diff --git a/.eslintrc b/.eslintrc index a44d175d..94782cad 100644 --- a/.eslintrc +++ b/.eslintrc @@ -15,7 +15,6 @@ "globals": { // global TS types - "Response": "readonly", "EventSource": "readonly", // @TODO remove. Configure as a type declaration "MessageEvent": "readonly", // @TODO remove. Configure as a type declaration "Event": "readonly", // @TODO remove. Configure as a type declaration @@ -66,7 +65,21 @@ "plugin:compat/recommended" ], "rules": { - "no-restricted-syntax": ["error", "ForOfStatement", "ForInStatement", "ArrayPattern"], + "no-restricted-syntax": [ + "error", + { + "selector": "ForOfStatement", + "message": "Avoid for-of syntax in favor of a smaller transpiled code" + }, + { + "selector": "ForInStatement", + "message": "Don't use for-in syntax in libraries, because it iterates over members inherited from the prototype chain" + }, + { + "selector": "TSEnumDeclaration[const=true]", + "message": "Don't declare const enum, because it is not supported by Babel used for building RN SDK" + } + ], "compat/compat": ["error", "defaults, not ie < 10, not node < 6"], "no-throw-literal": "error" }, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..1fac0178 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,39 @@ +name: ci +on: + push: + branches: + - '*' + pull_request: + branches: + - '*' + +jobs: + build: + name: Build + runs-on: ubuntu-latest + services: + redis: + image: redis + ports: + - 6379:6379 + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up nodejs + uses: actions/setup-node@v2 + with: + node-version: 'lts/*' + cache: 'npm' + + - name: npm CI + run: npm ci + + - name: npm Check + run: npm run check + + - name: npm Test + run: npm run test + + - name: npm Build + run: npm run build diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5ab3da26..00000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: node_js - -node_js: - - "lts/*" - -cache: npm - -services: - - redis-server - -git: - depth: false - -before_script: - - npm install - -script: - - npm run check - - npm run test - - npm run build diff --git a/CHANGES.txt b/CHANGES.txt index 2500c73a..429ad003 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,12 @@ +1.0.0 (October 20, 2021) +- BREAKING CHANGE on multiple modules due to general polishing, improvements and bug fixes. In most cases the change is to use named exports. This affected mostly modules related with synchronization and storages. + - Updated streaming logic to use the newest version of our streaming service, including: + - Integration with Auth service V2, connecting to the new channels and applying the received connection delay. + - Implemented handling of the new MySegmentsV2 notification types (SegmentRemoval, KeyList, Bounded and Unbounded) + - New control notification for environment scoped streaming reset. +- Updated localhost mode to emit SDK_READY_FROM_CACHE event in Browser when using localStorage (Related to issue https://github.com/splitio/react-client/issues/34). +- Updated dependencies for vulnerability fixes. + 0.1.0 (March 30, 2021) - Initial public release. It includes common modules to be consumed by the different Split implementations written in JavaScript. Based on the original JS SDK in the `javascript-client` repository. - It's designed with a modular approach, with the following goals in mind: diff --git a/README.md b/README.md index 37b4e232..51caf41d 100644 --- a/README.md +++ b/README.md @@ -24,16 +24,18 @@ To learn more about Split, contact hello@split.io, or get started with feature f Split has built and maintains SDKs for: -* .NET [Github](https://github.com/splitio/.net-core-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK) +* .NET [Github](https://github.com/splitio/dotnet-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK) * Android [Github](https://github.com/splitio/android-client) [Docs](https://help.split.io/hc/en-us/articles/360020343291-Android-SDK) * GO [Github](https://github.com/splitio/go-client) [Docs](https://help.split.io/hc/en-us/articles/360020093652-Go-SDK) * iOS [Github](https://github.com/splitio/ios-client) [Docs](https://help.split.io/hc/en-us/articles/360020401491-iOS-SDK) * Java [Github](https://github.com/splitio/java-client) [Docs](https://help.split.io/hc/en-us/articles/360020405151-Java-SDK) * Javascript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK) * Node [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK) +* Javascript for Browser [Github](https://github.com/splitio/javascript-browser-client) [Docs](https://help.split.io/hc/en-us/articles/360058730852-Browser-SDK) * PHP [Github](https://github.com/splitio/php-client) [Docs](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK) * Python [Github](https://github.com/splitio/python-client) [Docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK) * React [Github](https://github.com/splitio/react-client) [Docs](https://help.split.io/hc/en-us/articles/360038825091-React-SDK) +* React Native [Github](https://github.com/splitio/react-native-client) [Docs](https://help.split.io/hc/en-us/articles/4406066357901-React-Native-SDK) * Redux [Github](https://github.com/splitio/redux-client) [Docs](https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK) * Ruby [Github](https://github.com/splitio/ruby-client) [Docs](https://help.split.io/hc/en-us/articles/360020673251-Ruby-SDK) diff --git a/package-lock.json b/package-lock.json index dd8b235b..f32024b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,39 +1,58 @@ { "name": "@splitsoftware/splitio-commons", - "version": "0.1.0", + "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", "dev": true, "requires": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.14.5" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + } } }, "@babel/compat-data": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.12.tgz", - "integrity": "sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", + "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", "dev": true }, "@babel/core": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.14.tgz", - "integrity": "sha512-wZso/vyF4ki0l0znlgM4inxbdrUvCb+cVz8grxDq+6C9k6qbqoIJteQOKicaKjCipU3ISV+XedCqpL2RJJVehA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.9", - "@babel/helper-compilation-targets": "^7.13.13", - "@babel/helper-module-transforms": "^7.13.14", - "@babel/helpers": "^7.13.10", - "@babel/parser": "^7.13.13", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.13", - "@babel/types": "^7.13.14", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", + "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.15.8", + "@babel/generator": "^7.15.8", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.8", + "@babel/helpers": "^7.15.4", + "@babel/parser": "^7.15.8", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -42,32 +61,6 @@ "source-map": "^0.5.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -77,12 +70,12 @@ } }, "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", + "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", "dev": true, "requires": { - "@babel/types": "^7.13.0", + "@babel/types": "^7.15.6", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -96,161 +89,131 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz", - "integrity": "sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", + "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.13.12", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", + "@babel/compat-data": "^7.15.0", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", "semver": "^6.3.0" - }, - "dependencies": { - "browserslist": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.3.tgz", - "integrity": "sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001181", - "colorette": "^1.2.1", - "electron-to-chromium": "^1.3.649", - "escalade": "^3.1.1", - "node-releases": "^1.1.70" - } - }, - "caniuse-lite": { - "version": "1.0.30001204", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001204.tgz", - "integrity": "sha512-JUdjWpcxfJ9IPamy2f5JaRDCaqJOxDzOSKtbdx4rH9VivMd1vIzoPumsJa9LoMIi4Fx2BV2KZOxWhNkBjaYivQ==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.702", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.702.tgz", - "integrity": "sha512-qJVUKFWQnF6wP7MmTngDkmm8/KPzaiTXNFOAg5j7DSa6J7kPou7mTBqC8jpUOxauQWwHR3pn4dMRdV8IE1xdtA==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "node-releases": { - "version": "1.1.71", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", - "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", - "dev": true - } } }, "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", + "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-get-function-arity": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", + "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.15.4" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", + "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "dev": true, + "requires": { + "@babel/types": "^7.15.4" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", - "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", + "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.15.4" } }, "@babel/helper-module-imports": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", - "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", + "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.15.4" } }, "@babel/helper-module-transforms": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz", - "integrity": "sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-replace-supers": "^7.13.12", - "@babel/helper-simple-access": "^7.13.12", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.12.11", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.13", - "@babel/types": "^7.13.14" + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", + "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.15.4", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/helper-validator-identifier": "^7.15.7", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6" }, "dependencies": { "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "dev": true } } }, "@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", - "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", + "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.15.4" } }, "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", "dev": true }, "@babel/helper-replace-supers": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", - "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", + "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.13.12", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" + "@babel/helper-member-expression-to-functions": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/helper-simple-access": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", - "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", + "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.15.4" } }, "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", + "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.15.4" } }, "@babel/helper-validator-identifier": { @@ -260,20 +223,20 @@ "dev": true }, "@babel/helper-validator-option": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", - "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", "dev": true }, "@babel/helpers": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz", - "integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", + "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", "dev": true, "requires": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/highlight": { @@ -288,9 +251,9 @@ } }, "@babel/parser": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.13.tgz", - "integrity": "sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", + "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -393,112 +356,65 @@ } }, "@babel/plugin-syntax-top-level-await": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz", - "integrity": "sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, - "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "@babel/plugin-syntax-typescript": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - } + "@babel/helper-plugin-utils": "^7.14.5" } }, - "@babel/traverse": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.13.tgz", - "integrity": "sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==", + "@babel/template": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", + "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.9", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.13", - "@babel/types": "^7.13.13", + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4" + } + }, + "@babel/traverse": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", + "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4", "debug": "^4.1.0", "globals": "^11.1.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.12.13" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - } } }, "@babel/types": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz", - "integrity": "sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==", + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", + "@babel/helper-validator-identifier": "^7.14.9", "to-fast-properties": "^2.0.0" }, "dependencies": { "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "dev": true } } @@ -509,50 +425,30 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, "@eslint/eslintrc": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", - "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.1.1", "espree": "^7.3.0", - "globals": "^12.1.0", + "globals": "^13.9.0", "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", - "lodash": "^4.17.19", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "dependencies": { - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" } }, "ignore": { @@ -561,14 +457,31 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true } } }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -589,32 +502,19 @@ "dev": true }, "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.2.4.tgz", + "integrity": "sha512-94znCKynPZpDpYHQ6esRJSc11AmONrVkBOBZiD7S+bSubHhrUfbS95EY5HIOxhm4PQO7cnvZkL3oJcY0oMA+Wg==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", + "jest-message-util": "^27.2.4", + "jest-util": "^27.2.4", "slash": "^3.0.0" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -625,9 +525,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -655,20 +555,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -681,54 +567,41 @@ } }, "@jest/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.2.4.tgz", + "integrity": "sha512-UNQLyy+rXoojNm2MGlapgzWhZD1CT1zcHZQYeiD0xE7MtJfC19Q6J5D/Lm2l7i4V97T30usKDoEtjI8vKwWcLg==", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.2.4", + "@jest/reporters": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", + "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", + "jest-changed-files": "^27.2.4", + "jest-config": "^27.2.4", + "jest-haste-map": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.2.4", + "jest-resolve-dependencies": "^27.2.4", + "jest-runner": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", + "jest-watcher": "^27.2.4", + "micromatch": "^4.0.4", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -739,9 +612,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -769,20 +642,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -795,30 +654,74 @@ } }, "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.2.4.tgz", + "integrity": "sha512-wkuui5yr3SSQW0XD0Qm3TATUbL/WE3LDEM3ulC+RCQhMf2yxhci8x7svGkZ4ivJ6Pc94oOzpZ6cdHBAMSYd1ew==", + "dev": true, + "requires": { + "@jest/fake-timers": "^27.2.4", + "@jest/types": "^27.2.4", + "@types/node": "*", + "jest-mock": "^27.2.4" + } + }, + "@jest/fake-timers": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.2.4.tgz", + "integrity": "sha512-cs/TzvwWUM7kAA6Qm/890SK6JJ2pD5RfDNM3SSEom6BmdyV6OiWP1qf/pqo6ts6xwpcM36oN0wSEzcZWc6/B6w==", "dev": true, "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/types": "^27.2.4", + "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-mock": "^26.6.2" + "jest-message-util": "^27.2.4", + "jest-mock": "^27.2.4", + "jest-util": "^27.2.4" + } + }, + "@jest/globals": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.2.4.tgz", + "integrity": "sha512-DRsRs5dh0i+fA9mGHylTU19+8fhzNJoEzrgsu+zgJoZth3x8/0juCQ8nVVdW1er4Cqifb/ET7/hACYVPD0dBEA==", + "dev": true, + "requires": { + "@jest/environment": "^27.2.4", + "@jest/types": "^27.2.4", + "expect": "^27.2.4" + } + }, + "@jest/reporters": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.2.4.tgz", + "integrity": "sha512-LHeSdDnDZkDnJ8kvnjcqV8P1Yv/32yL4d4XfR5gBiy3xGO0onwll1QEbvtW96fIwhx2nejug0GTaEdNDoyr3fQ==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^27.2.4", + "jest-resolve": "^27.2.4", + "jest-util": "^27.2.4", + "jest-worker": "^27.2.4", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -829,9 +732,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -870,33 +773,64 @@ } } }, - "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "@jest/source-map": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", + "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.2.4.tgz", + "integrity": "sha512-eU+PRo0+lIS01b0dTmMdVZ0TtcRSxEaYquZTRFMQz6CvsehGhx9bRzi9Zdw6VROviJyv7rstU+qAMX5pNBmnfQ==", + "dev": true, + "requires": { + "@jest/console": "^27.2.4", + "@jest/types": "^27.2.4", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.2.4.tgz", + "integrity": "sha512-fpk5eknU3/DXE2QCCG1wv/a468+cfPo3Asu6d6yUtM9LOPh709ubZqrhuUOYfM8hXMrIpIdrv1CdCrWWabX0rQ==", + "dev": true, + "requires": { + "@jest/test-result": "^27.2.4", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.2.4", + "jest-runtime": "^27.2.4" + } + }, + "@jest/transform": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.2.4.tgz", + "integrity": "sha512-n5FlX2TH0oQGwyVDKPxdJ5nI2sO7TJBFe3u3KaAtt7TOiV4yL+Y+rSFDl+Ic5MpbiA/eqXmLAQxjnBmWgS2rEA==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.2.4", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.2.4", + "jest-regex-util": "^27.0.6", + "jest-util": "^27.2.4", + "micromatch": "^4.0.4", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -907,9 +841,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -937,20 +871,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -962,30 +882,19 @@ } } }, - "@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "@jest/types": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.4.tgz", + "integrity": "sha512-IDO2ezTxeMvQAHxzG/ZvEyA47q0aVfzT95rGFl7bZs/Go0aIucvfDbS2rmnoEdXxlLQhcolmoG/wvL/uKx4tKA==", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -996,9 +905,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -1037,568 +946,600 @@ } } }, - "@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", "dev": true, "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "node-notifier": "^8.0.0", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.0.1.tgz", + "integrity": "sha512-AU7kwFxreVd6OAXcAFlKSmZquiRUU0FvYm44k1Y1QbK7Co4m0aqfGMhjykIeQp/H6rcl+nFmj0zfdUcGVs9Dew==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", + "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", + "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/google.analytics": { + "version": "0.0.40", + "resolved": "https://registry.npmjs.org/@types/google.analytics/-/google.analytics-0.0.40.tgz", + "integrity": "sha512-R3HpnLkqmKxhUAf8kIVvDVGJqPtaaZlW4yowNwjOZUTmYUQEgHh8Nh5wkSXKMroNAuQM8gbXJHmNbbgA8tdb7Q==", + "dev": true + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/ioredis": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.17.4.tgz", + "integrity": "sha512-kb5+thmQJ7HHyOAnCOeqRJlF2fyvadHghnLLLKZzCNyShStJeIQtNGGDjA30gWqj6UFSDAWBfGEMKrFDrGfvzQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.2.tgz", + "integrity": "sha512-4dRxkS/AFX0c5XW6IPMNOydLn2tEhNhJV7DnYK+0bjoJZ+QTmfucBlihX7aoEsh/ocYtkLC73UbnBXBXIxsULA==", + "dev": true, + "requires": { + "jest-diff": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, + "@types/lodash": { + "version": "4.14.162", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.162.tgz", + "integrity": "sha512-alvcho1kRUnnD1Gcl4J+hK0eencvzq9rmzvFPRmP5rPHx9VVsJj6bKLTATPVf9ktgv4ujzh7T+XWKp+jhuODig==", + "dev": true + }, + "@types/node": { + "version": "14.14.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.7.tgz", + "integrity": "sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg==", + "dev": true + }, + "@types/object-assign": { + "version": "4.0.30", + "resolved": "https://registry.npmjs.org/@types/object-assign/-/object-assign-4.0.30.tgz", + "integrity": "sha1-iUk3HVqZ9Dge4PHfCpt6GH4H5lI=", + "dev": true + }, + "@types/prettier": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.2.0.tgz", + "integrity": "sha512-zBNRkzvLSwo6y5TG0DVcmshZIYBHKtmzD4N+LYnfTFpzc4bc79o8jNRSb728WV7A4Cegbs+MV5IRAj8BKBgOVQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.2.0", + "@typescript-eslint/scope-manager": "4.2.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "@typescript-eslint/scope-manager": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.2.0.tgz", + "integrity": "sha512-Tb402cxxObSxWIVT+PnBp5ruT2V/36yj6gG4C9AjkgRlZpxrLAzWDk3neen6ToMBGeGdxtnfFLoJRUecGz9mYQ==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "@typescript-eslint/types": "4.2.0", + "@typescript-eslint/visitor-keys": "4.2.0" } }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } + "@typescript-eslint/types": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.2.0.tgz", + "integrity": "sha512-xkv5nIsxfI/Di9eVwN+G9reWl7Me9R5jpzmZUch58uQ7g0/hHVuGUbbn4NcxcM5y/R4wuJIIEPKPDb5l4Fdmwg==", + "dev": true }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "@typescript-eslint/visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.2.0.tgz", + "integrity": "sha512-WIf4BNOlFOH2W+YqGWa6YKLcK/EB3gEj2apCrqLw6mme1RzBy0jtJ9ewJgnrZDB640zfnv8L+/gwGH5sYp/rGw==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@typescript-eslint/types": "4.2.0", + "eslint-visitor-keys": "^2.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "dev": true, "requires": { - "color-name": "~1.1.4" + "ms": "2.1.2" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, - "@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "@typescript-eslint/experimental-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.2.0.tgz", + "integrity": "sha512-5BBj6BjgHEndBaQQpUVzRIPERz03LBc0MCQkHwUaH044FJFL08SwWv/sQftk7gf0ShZ2xZysz0LTwCwNt4Xu3w==", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.2.0", + "@typescript-eslint/types": "4.2.0", + "@typescript-eslint/typescript-estree": "4.2.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "@typescript-eslint/scope-manager": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.2.0.tgz", + "integrity": "sha512-Tb402cxxObSxWIVT+PnBp5ruT2V/36yj6gG4C9AjkgRlZpxrLAzWDk3neen6ToMBGeGdxtnfFLoJRUecGz9mYQ==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "@typescript-eslint/types": "4.2.0", + "@typescript-eslint/visitor-keys": "4.2.0" } }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "@typescript-eslint/types": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.2.0.tgz", + "integrity": "sha512-xkv5nIsxfI/Di9eVwN+G9reWl7Me9R5jpzmZUch58uQ7g0/hHVuGUbbn4NcxcM5y/R4wuJIIEPKPDb5l4Fdmwg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.2.0.tgz", + "integrity": "sha512-iWDLCB7z4MGkLipduF6EOotdHNtgxuNKnYD54nMS/oitFnsk4S3S/TE/UYXQTra550lHtlv9eGmp+dvN9pUDtA==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "@typescript-eslint/types": "4.2.0", + "@typescript-eslint/visitor-keys": "4.2.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" } }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "@typescript-eslint/visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.2.0.tgz", + "integrity": "sha512-WIf4BNOlFOH2W+YqGWa6YKLcK/EB3gEj2apCrqLw6mme1RzBy0jtJ9ewJgnrZDB640zfnv8L+/gwGH5sYp/rGw==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@typescript-eslint/types": "4.2.0", + "eslint-visitor-keys": "^2.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "dev": true, "requires": { - "color-name": "~1.1.4" + "ms": "2.1.2" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, - "@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", - "dev": true, - "requires": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" - } - }, - "@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "@typescript-eslint/parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.2.0.tgz", + "integrity": "sha512-54jJ6MwkOtowpE48C0QJF9iTz2/NZxfKVJzv1ha5imigzHbNSLN9yvbxFFH1KdlRPQrlR8qxqyOvLHHxd397VA==", "dev": true, "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "@typescript-eslint/scope-manager": "4.2.0", + "@typescript-eslint/types": "4.2.0", + "@typescript-eslint/typescript-estree": "4.2.0", + "debug": "^4.1.1" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "dev": true, "requires": { - "color-name": "~1.1.4" + "ms": "2.1.2" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, - "@jest/types": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz", - "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==", + "@typescript-eslint/scope-manager": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.2.0.tgz", + "integrity": "sha512-Tb402cxxObSxWIVT+PnBp5ruT2V/36yj6gG4C9AjkgRlZpxrLAzWDk3neen6ToMBGeGdxtnfFLoJRUecGz9mYQ==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "@typescript-eslint/types": "4.2.0", + "@typescript-eslint/visitor-keys": "4.2.0" + } + }, + "@typescript-eslint/types": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.2.0.tgz", + "integrity": "sha512-xkv5nIsxfI/Di9eVwN+G9reWl7Me9R5jpzmZUch58uQ7g0/hHVuGUbbn4NcxcM5y/R4wuJIIEPKPDb5l4Fdmwg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.2.0.tgz", + "integrity": "sha512-iWDLCB7z4MGkLipduF6EOotdHNtgxuNKnYD54nMS/oitFnsk4S3S/TE/UYXQTra550lHtlv9eGmp+dvN9pUDtA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.2.0", + "@typescript-eslint/visitor-keys": "4.2.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" }, "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "dev": true, "requires": { - "color-name": "~1.1.4" + "ms": "2.1.2" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, - "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "@typescript-eslint/visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.2.0.tgz", + "integrity": "sha512-WIf4BNOlFOH2W+YqGWa6YKLcK/EB3gEj2apCrqLw6mme1RzBy0jtJ9ewJgnrZDB640zfnv8L+/gwGH5sYp/rGw==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" + "@typescript-eslint/types": "4.2.0", + "eslint-visitor-keys": "^2.0.0" } }, - "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", "dev": true }, - "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "acorn": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", + "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "dev": true + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" } }, - "@sinonjs/commons": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", - "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==", + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, "requires": { - "type-detect": "4.0.8" + "debug": "4" } }, - "@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "ajv": { + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, - "@types/babel__core": { - "version": "7.1.14", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", - "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "type-fest": "^0.21.3" } }, - "@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "color-convert": "^1.9.0" } }, - "@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, - "@types/babel__traverse": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", - "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "@babel/types": "^7.3.0" + "sprintf-js": "~1.0.2" } }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, - "@types/google.analytics": { - "version": "0.0.40", - "resolved": "https://registry.npmjs.org/@types/google.analytics/-/google.analytics-0.0.40.tgz", - "integrity": "sha512-R3HpnLkqmKxhUAf8kIVvDVGJqPtaaZlW4yowNwjOZUTmYUQEgHh8Nh5wkSXKMroNAuQM8gbXJHmNbbgA8tdb7Q==", + "ast-metadata-inferer": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.2.0.tgz", + "integrity": "sha512-6yPph2NeCHNxoI/ZmjklYaLOSZDAx+0L0+wsXnF56FxmjxvUlYZSWcj1KXtXO8IufruQTzVFOjg1+IzdDazSPg==", "dev": true }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/ioredis": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.17.4.tgz", - "integrity": "sha512-kb5+thmQJ7HHyOAnCOeqRJlF2fyvadHghnLLLKZzCNyShStJeIQtNGGDjA30gWqj6UFSDAWBfGEMKrFDrGfvzQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true }, - "@types/jest": { - "version": "26.0.10", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.10.tgz", - "integrity": "sha512-i2m0oyh8w/Lum7wWK/YOZJakYF8Mx08UaKA1CtbmFeDquVhAEdA7znacsVSf2hJ1OQ/OfVMGN90pw/AtzF8s/Q==", + "babel-jest": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.2.4.tgz", + "integrity": "sha512-f24OmxyWymk5jfgLdlCMu4fTs4ldxFBIdn5sJdhvGC1m08rSkJ5hYbWkNmfBSvE/DjhCVNSHXepxsI6THGfGsg==", "dev": true, "requires": { - "jest-diff": "^25.2.1", - "pretty-format": "^25.2.1" + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^27.2.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" }, "dependencies": { - "@jest/types": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz", - "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" - } - }, - "@types/istanbul-reports": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", - "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" - } - }, "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -1620,48 +1561,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "diff-sequences": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", - "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==", - "dev": true - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-diff": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.5.0.tgz", - "integrity": "sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==", - "dev": true, - "requires": { - "chalk": "^3.0.0", - "diff-sequences": "^25.2.6", - "jest-get-type": "^25.2.6", - "pretty-format": "^25.5.0" - } - }, - "jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", - "dev": true - }, - "pretty-format": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz", - "integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==", - "dev": true, - "requires": { - "@jest/types": "^25.5.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -1673,517 +1578,562 @@ } } }, - "@types/json-schema": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", - "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", - "dev": true - }, - "@types/lodash": { - "version": "4.14.162", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.162.tgz", - "integrity": "sha512-alvcho1kRUnnD1Gcl4J+hK0eencvzq9rmzvFPRmP5rPHx9VVsJj6bKLTATPVf9ktgv4ujzh7T+XWKp+jhuODig==", - "dev": true - }, - "@types/node": { - "version": "14.14.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.7.tgz", - "integrity": "sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "@types/object-assign": { - "version": "4.0.30", - "resolved": "https://registry.npmjs.org/@types/object-assign/-/object-assign-4.0.30.tgz", - "integrity": "sha1-iUk3HVqZ9Dge4PHfCpt6GH4H5lI=", - "dev": true - }, - "@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", - "dev": true - }, - "@types/yargs": { - "version": "15.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz", - "integrity": "sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w==", + "babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", "dev": true, "requires": { - "@types/yargs-parser": "*" + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" } }, - "@types/yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", - "dev": true + "babel-plugin-jest-hoist": { + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz", + "integrity": "sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } }, - "@typescript-eslint/eslint-plugin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.2.0.tgz", - "integrity": "sha512-zBNRkzvLSwo6y5TG0DVcmshZIYBHKtmzD4N+LYnfTFpzc4bc79o8jNRSb728WV7A4Cegbs+MV5IRAj8BKBgOVQ==", + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.2.0", - "@typescript-eslint/scope-manager": "4.2.0", - "debug": "^4.1.1", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "dependencies": { - "@typescript-eslint/scope-manager": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.2.0.tgz", - "integrity": "sha512-Tb402cxxObSxWIVT+PnBp5ruT2V/36yj6gG4C9AjkgRlZpxrLAzWDk3neen6ToMBGeGdxtnfFLoJRUecGz9mYQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.2.0", - "@typescript-eslint/visitor-keys": "4.2.0" - } - }, - "@typescript-eslint/types": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.2.0.tgz", - "integrity": "sha512-xkv5nIsxfI/Di9eVwN+G9reWl7Me9R5jpzmZUch58uQ7g0/hHVuGUbbn4NcxcM5y/R4wuJIIEPKPDb5l4Fdmwg==", - "dev": true - }, - "@typescript-eslint/visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.2.0.tgz", - "integrity": "sha512-WIf4BNOlFOH2W+YqGWa6YKLcK/EB3gEj2apCrqLw6mme1RzBy0jtJ9ewJgnrZDB640zfnv8L+/gwGH5sYp/rGw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.2.0", - "eslint-visitor-keys": "^2.0.0" - } - }, - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - } + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" } }, - "@typescript-eslint/experimental-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.2.0.tgz", - "integrity": "sha512-5BBj6BjgHEndBaQQpUVzRIPERz03LBc0MCQkHwUaH044FJFL08SwWv/sQftk7gf0ShZ2xZysz0LTwCwNt4Xu3w==", + "babel-preset-jest": { + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz", + "integrity": "sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg==", "dev": true, "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.2.0", - "@typescript-eslint/types": "4.2.0", - "@typescript-eslint/typescript-estree": "4.2.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" + "babel-plugin-jest-hoist": "^27.2.0", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" }, "dependencies": { - "@typescript-eslint/scope-manager": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.2.0.tgz", - "integrity": "sha512-Tb402cxxObSxWIVT+PnBp5ruT2V/36yj6gG4C9AjkgRlZpxrLAzWDk3neen6ToMBGeGdxtnfFLoJRUecGz9mYQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.2.0", - "@typescript-eslint/visitor-keys": "4.2.0" - } - }, - "@typescript-eslint/types": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.2.0.tgz", - "integrity": "sha512-xkv5nIsxfI/Di9eVwN+G9reWl7Me9R5jpzmZUch58uQ7g0/hHVuGUbbn4NcxcM5y/R4wuJIIEPKPDb5l4Fdmwg==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.2.0.tgz", - "integrity": "sha512-iWDLCB7z4MGkLipduF6EOotdHNtgxuNKnYD54nMS/oitFnsk4S3S/TE/UYXQTra550lHtlv9eGmp+dvN9pUDtA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.2.0", - "@typescript-eslint/visitor-keys": "4.2.0", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.2.0.tgz", - "integrity": "sha512-WIf4BNOlFOH2W+YqGWa6YKLcK/EB3gEj2apCrqLw6mme1RzBy0jtJ9ewJgnrZDB640zfnv8L+/gwGH5sYp/rGw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.2.0", - "eslint-visitor-keys": "^2.0.0" - } - }, - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", "dev": true }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true } } }, - "@typescript-eslint/parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.2.0.tgz", - "integrity": "sha512-54jJ6MwkOtowpE48C0QJF9iTz2/NZxfKVJzv1ha5imigzHbNSLN9yvbxFFH1KdlRPQrlR8qxqyOvLHHxd397VA==", + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.2.0", - "@typescript-eslint/types": "4.2.0", - "@typescript-eslint/typescript-estree": "4.2.0", - "debug": "^4.1.1" - }, - "dependencies": { - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "@typescript-eslint/scope-manager": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.2.0.tgz", - "integrity": "sha512-Tb402cxxObSxWIVT+PnBp5ruT2V/36yj6gG4C9AjkgRlZpxrLAzWDk3neen6ToMBGeGdxtnfFLoJRUecGz9mYQ==", + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { - "@typescript-eslint/types": "4.2.0", - "@typescript-eslint/visitor-keys": "4.2.0" + "fill-range": "^7.0.1" } }, - "@typescript-eslint/types": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.2.0.tgz", - "integrity": "sha512-xkv5nIsxfI/Di9eVwN+G9reWl7Me9R5jpzmZUch58uQ7g0/hHVuGUbbn4NcxcM5y/R4wuJIIEPKPDb5l4Fdmwg==", + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, - "@typescript-eslint/typescript-estree": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.2.0.tgz", - "integrity": "sha512-iWDLCB7z4MGkLipduF6EOotdHNtgxuNKnYD54nMS/oitFnsk4S3S/TE/UYXQTra550lHtlv9eGmp+dvN9pUDtA==", + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", "dev": true, "requires": { - "@typescript-eslint/types": "4.2.0", - "@typescript-eslint/visitor-keys": "4.2.0", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "dependencies": { - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - } + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" } }, - "@typescript-eslint/visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.2.0.tgz", - "integrity": "sha512-WIf4BNOlFOH2W+YqGWa6YKLcK/EB3gEj2apCrqLw6mme1RzBy0jtJ9ewJgnrZDB640zfnv8L+/gwGH5sYp/rGw==", + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, "requires": { - "@typescript-eslint/types": "4.2.0", - "eslint-visitor-keys": "^2.0.0" + "fast-json-stable-stringify": "2.x" } }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "acorn": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", - "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "node-int64": "^0.4.0" } }, - "acorn-jsx": { + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "caniuse-db": { + "version": "1.0.30001120", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001120.tgz", + "integrity": "sha512-DvFSRBZYuPj2976yroUk/vqu45nvbf70+qJLH7q+q3S9IOXY4Wl/q7nWOJX8mq6SjWQzCWbz0J0Q6UjsuYwd2A==", "dev": true }, - "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "caniuse-lite": { + "version": "1.0.30001247", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001247.tgz", + "integrity": "sha512-4rS7co+7+AoOSPRPOPUt5/GdaqZc0EsUpWk66ofE3HJTAajUK2Ss2VwoNzVN69ghg8lYYlh0an0Iy4LIHHo9UQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", "dev": true }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-name": "1.1.3" } }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "delayed-stream": "~1.0.0" } }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "dev": true, "requires": { - "sprintf-js": "~1.0.2" + "safe-buffer": "~5.1.1" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "core-js": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", + "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", "dev": true }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true + "cross-env": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz", + "integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", "dev": true }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, "requires": { - "safer-buffer": "~2.1.0" + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true + "csv-streamify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/csv-streamify/-/csv-streamify-4.0.0.tgz", + "integrity": "sha512-d+QZf8WaKwn/8/dJDyN0TFkmSH0fHBFJSyz+ujC2a5sGvXgxEj3zBwqx/mLoPMJ+YbI9H7n3h5YL4uAHUj731w==", + "dev": true, + "requires": { + "through2": "2.0.3" + } }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } }, - "ast-metadata-inferer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.2.0.tgz", - "integrity": "sha512-6yPph2NeCHNxoI/ZmjklYaLOSZDAx+0L0+wsXnF56FxmjxvUlYZSWcj1KXtXO8IufruQTzVFOjg1+IzdDazSPg==", - "dev": true + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "dev": true }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", "dev": true }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, - "babel-jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "denque": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", + "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==", + "dev": true + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff-sequences": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", + "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "requires": { - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.6.2", + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, + "electron-to-chromium": { + "version": "1.3.788", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.788.tgz", + "integrity": "sha512-dbMIpX4E4/Gk4gzOh1GYS7ls1vGsByWKpIqLviJi1mSmSt5BvrWLLtSqpFE5BaC7Ef4NnI0GMaiddNX2Brw6zA==", + "dev": true + }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" + "@babel/highlight": "^7.10.4" } }, "ansi-styles": { @@ -2196,9 +2146,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -2220,12 +2170,72 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2234,2603 +2244,789 @@ "requires": { "has-flag": "^4.0.0" } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true } } }, - "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "eslint-plugin-compat": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-3.7.0.tgz", + "integrity": "sha512-A3uzSYqUjNj6rMyaBuU3l8wSCadZjeZRZ7WF3eU9vUT0JItiqRysjmYELkHHCpH8l7wRprUu4MZPr37lFCw7iA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", - "test-exclude": "^6.0.0" + "ast-metadata-inferer": "^0.2.0-0", + "browserslist": "^4.12.0", + "caniuse-db": "^1.0.30001059", + "core-js": "^3.6.5", + "lodash.memoize": "4.1.2", + "mdn-browser-compat-data": "^1.0.21", + "semver": "7.3.2" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + } } }, - "babel-plugin-jest-hoist": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" } }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, - "babel-preset-jest": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^26.6.2", - "babel-preset-current-node-syntax": "^1.0.0" + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "estraverse": "^5.1.0" }, "dependencies": { - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "dev": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "dev": true } } }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "expect": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.2.4.tgz", + "integrity": "sha512-gOtuonQ8TCnbNNCSw2fhVzRf8EFYDII4nB5NmG4IEV0rbUnW1I5zXvoTntU4iicB/Uh0oZr20NGlOLdJiwsOZA==", "dev": true, "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "@jest/types": "^27.2.4", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.0.6", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-regex-util": "^27.0.6" }, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { - "is-descriptor": "^1.0.0" + "fill-range": "^7.0.1" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "to-regex-range": "^5.0.1" } }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", "dev": true, "requires": { - "kind-of": "^6.0.0" + "braces": "^3.0.1", + "picomatch": "^2.0.5" } }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-number": "^7.0.0" } } } }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, - "browserslist": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.0.tgz", - "integrity": "sha512-pUsXKAF2lVwhmtpeA3LJrZ76jXuusrNyhduuQs7CDFf9foT4Y38aQOserd2lMe5DSSrjf3fx34oHwryuvxAUgQ==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001111", - "electron-to-chromium": "^1.3.523", - "escalade": "^3.0.2", - "node-releases": "^1.1.60" - } + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", "dev": true, "requires": { - "fast-json-stable-stringify": "2.x" + "reusify": "^1.0.4" } }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", "dev": true, "requires": { - "node-int64": "^0.4.0" + "bser": "2.1.1" } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "fetch-mock": { + "version": "9.10.7", + "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-9.10.7.tgz", + "integrity": "sha512-YkiMHSL8CQ0vlWYpqGvlaZjViFk0Kar9jonPjSvaWoztkeHH6DENqUzBIsffzjVKhwchPI74SZRLRpIsEyNcZQ==", "dev": true, "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-db": { - "version": "1.0.30001120", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001120.tgz", - "integrity": "sha512-DvFSRBZYuPj2976yroUk/vqu45nvbf70+qJLH7q+q3S9IOXY4Wl/q7nWOJX8mq6SjWQzCWbz0J0Q6UjsuYwd2A==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001118", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001118.tgz", - "integrity": "sha512-RNKPLojZo74a0cP7jFMidQI7nvLER40HgNfgKQEJ2PFm225L0ectUungNQoK3Xk3StQcFbpBPNEvoWD59436Hg==", - "dev": true + "babel-runtime": "^6.26.0", + "core-js": "^3.0.0", + "debug": "^4.1.1", + "glob-to-regexp": "^0.4.0", + "is-subset": "^0.1.1", + "lodash.isequal": "^4.5.0", + "path-to-regexp": "^2.2.1", + "querystring": "^0.2.0", + "whatwg-url": "^6.5.0" + }, + "dependencies": { + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { - "rsvp": "^4.8.4" + "flat-cache": "^3.0.4" } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "to-regex-range": "^5.0.1" } }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", - "dev": true + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "flatted": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "dev": true + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", "dev": true, "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" } }, - "cluster-key-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", - "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "collect-v8-coverage": { + "functional-red-black-tree": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { - "color-name": "1.1.3" + "is-glob": "^4.0.1" } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "globby": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", + "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", "dev": true, "requires": { - "delayed-stream": "~1.0.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } } }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", "dev": true, "requires": { - "safe-buffer": "~5.1.1" + "whatwg-encoding": "^1.0.5" } }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "core-js": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", - "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cross-env": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz", - "integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==", + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "dev": true, "requires": { - "cross-spawn": "^7.0.1" + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" } }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", "dev": true, "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "agent-base": "6", + "debug": "4" } }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "csv-streamify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/csv-streamify/-/csv-streamify-4.0.0.tgz", - "integrity": "sha512-d+QZf8WaKwn/8/dJDyN0TFkmSH0fHBFJSyz+ujC2a5sGvXgxEj3zBwqx/mLoPMJ+YbI9H7n3h5YL4uAHUj731w==", + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { - "through2": "2.0.3" + "safer-buffer": ">= 2.1.2 < 3" } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } } }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "import-local": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", + "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", "dev": true, "requires": { - "ms": "2.1.2" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } + "once": "^1.3.0", + "wrappy": "1" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "denque": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", - "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "ioredis": { + "version": "4.27.2", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.27.2.tgz", + "integrity": "sha512-7OpYymIthonkC2Jne5uGWXswdhlua1S1rWGAERaotn0hGJWTSURvxdHA9G6wNbT/qKCloCja/FHsfKXW8lpTmg==", "dev": true, "requires": { - "path-type": "^4.0.0" + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "p-map": "^2.1.0", + "redis-commands": "1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" } }, - "doctrine": { + "is-ci": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", "dev": true, "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } + "ci-info": "^3.1.1" } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "is-core-module": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.7.0.tgz", + "integrity": "sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ==", "dev": true, "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "has": "^1.0.3" } }, - "electron-to-chromium": { - "version": "1.3.550", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.550.tgz", - "integrity": "sha512-MWDHoJsSieBaJ6mObvi3V0eKZufR1iMJl56VIGdXCgFHyCUbVDGm2IMXUNjDxgbGbKa3tA5+zJmHuBQqRxGiLA==", + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, - "emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "once": "^1.4.0" + "is-extglob": "^2.1.1" } }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true }, - "escalade": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz", - "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==", + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "is-subset": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", + "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", "dev": true }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "eslint": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.9.0.tgz", - "integrity": "sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.1.3", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "eslint-scope": "^5.1.0", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^1.3.0", - "espree": "^7.3.0", - "esquery": "^1.2.0", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash": "^4.17.19", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - } - } - }, - "eslint-plugin-compat": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-3.7.0.tgz", - "integrity": "sha512-A3uzSYqUjNj6rMyaBuU3l8wSCadZjeZRZ7WF3eU9vUT0JItiqRysjmYELkHHCpH8l7wRprUu4MZPr37lFCw7iA==", - "dev": true, - "requires": { - "ast-metadata-inferer": "^0.2.0-0", - "browserslist": "^4.12.0", - "caniuse-db": "^1.0.30001059", - "core-js": "^3.6.5", - "lodash.memoize": "4.1.2", - "mdn-browser-compat-data": "^1.0.21", - "semver": "7.3.2" - }, - "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", - "dev": true - }, - "espree": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", - "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "exec-sh": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", - "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "fetch-mock": { - "version": "9.10.7", - "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-9.10.7.tgz", - "integrity": "sha512-YkiMHSL8CQ0vlWYpqGvlaZjViFk0Kar9jonPjSvaWoztkeHH6DENqUzBIsffzjVKhwchPI74SZRLRpIsEyNcZQ==", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "core-js": "^3.0.0", - "debug": "^4.1.1", - "glob-to-regexp": "^0.4.0", - "is-subset": "^0.1.1", - "lodash.isequal": "^4.5.0", - "path-to-regexp": "^2.2.1", - "querystring": "^0.2.0", - "whatwg-url": "^6.5.0" - }, - "dependencies": { - "debug": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", - "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "dependencies": { - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - } - } - }, - "import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ioredis": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.18.0.tgz", - "integrity": "sha512-wXlB60wD+ayJxbD7t+RFBanXinhHyYpfKUxTEEXNOpd0wb+nC8GLH2r7SaZ6sSBOxr8x6jDfBiuMaiK3bPYABw==", - "dev": true, - "requires": { - "cluster-key-slot": "^1.1.0", - "debug": "^4.1.1", - "denque": "^1.1.0", - "lodash.defaults": "^4.2.0", - "lodash.flatten": "^4.4.0", - "redis-commands": "1.6.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0", - "standard-as-callback": "^2.0.1" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-docker": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", - "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", - "dev": true, - "optional": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-potential-custom-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", - "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-subset": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", - "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "optional": true, - "requires": { - "is-docker": "^2.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", - "dev": true, - "requires": { - "@jest/core": "^26.6.3", - "import-local": "^3.0.2", - "jest-cli": "^26.6.3" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", - "dev": true, - "requires": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "prompts": "^2.0.1", - "yargs": "^15.4.1" - } - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-changed-files": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" } }, - "jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "dev": true, "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -4848,134 +3044,38 @@ } } }, - "jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", "dev": true, "requires": { - "detect-newline": "^3.0.0" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" } }, - "jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "istanbul-reports": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.3.tgz", + "integrity": "sha512-0i77ZFLsb9U3DHi22WzmIngVzfoyxxbQcZRqlF3KoKmCJGq9nhFHoGi8FqBztN2rE8w6hURnZghetn0xpkVb6A==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" - }, - "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" } }, - "jest-environment-jsdom": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", - "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "jest": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.2.4.tgz", + "integrity": "sha512-h4uqb1EQLfPulWyUFFWv9e9Nn8sCqsJ/j3wk/KCY0p4s4s0ICCfP3iMf6hRf5hEhsDyvyrCgKiZXma63gMz16A==", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2", - "jsdom": "^16.4.0" + "@jest/core": "^27.2.4", + "import-local": "^3.0.2", + "jest-cli": "^27.2.4" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -4986,9 +3086,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5016,18 +3116,24 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "jest-cli": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.2.4.tgz", + "integrity": "sha512-4kpQQkg74HYLaXo3nzwtg4PYxSLgL7puz1LXHj5Tu85KmlIpxQFjRkXlx4V47CYFFIDoyl3rHA/cXOxUWyMpNg==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", + "@jest/core": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", "chalk": "^4.0.0", + "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" + "import-local": "^3.0.2", + "jest-config": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", + "prompts": "^2.0.1", + "yargs": "^16.2.0" } }, "supports-color": { @@ -5041,33 +3147,44 @@ } } }, - "jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "jest-changed-files": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.2.4.tgz", + "integrity": "sha512-eeO1C1u4ex7pdTroYXezr+rbr957myyVoKGjcY4R1TJi3A+9v+4fu1Iv9J4eLq1bgFyT3O3iRWU9lZsEE7J72Q==", + "dev": true, + "requires": { + "@jest/types": "^27.2.4", + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "jest-circus": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.2.4.tgz", + "integrity": "sha512-TtheheTElrGjlsY9VxkzUU1qwIx05ItIusMVKnvNkMt4o/PeegLRcjq3Db2Jz0GGdBalJdbzLZBgeulZAJxJWA==", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/environment": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.2.4", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.2.4", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "pretty-format": "^27.2.4", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5078,9 +3195,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5108,20 +3225,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5133,47 +3236,35 @@ } } }, - "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true - }, - "jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "jest-config": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.2.4.tgz", + "integrity": "sha512-tWy0UxhdzqiKyp4l5Vq4HxLyD+gH5td+GCF3c22/DJ0bYAOsMo+qi2XtbJI6oYMH5JOJQs9nLW/r34nvFCehjA==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.2.4", + "@jest/types": "^27.2.4", + "babel-jest": "^27.2.4", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7" + "is-ci": "^3.0.0", + "jest-circus": "^27.2.4", + "jest-environment-jsdom": "^27.2.4", + "jest-environment-node": "^27.2.4", + "jest-get-type": "^27.0.6", + "jest-jasmine2": "^27.2.4", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.2.4", + "jest-runner": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", + "micromatch": "^4.0.4", + "pretty-format": "^27.2.4" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5184,9 +3275,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5214,20 +3305,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5239,45 +3316,18 @@ } } }, - "jest-jasmine2": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", - "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "jest-diff": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.2.4.tgz", + "integrity": "sha512-bLAVlDSCR3gqUPGv+4nzVpEXGsHh98HjUL7Vb2hVyyuBDoQmja8eJb0imUABsuxBeUVmf47taJSAd9nDrwWKEg==", "dev": true, "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^26.6.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2", - "throat": "^5.0.0" + "diff-sequences": "^27.0.6", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.2.4" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5288,9 +3338,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5318,20 +3368,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5343,32 +3379,26 @@ } } }, - "jest-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", + "jest-docblock": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", + "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", "dev": true, "requires": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "detect-newline": "^3.0.0" } }, - "jest-localstorage-mock": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/jest-localstorage-mock/-/jest-localstorage-mock-2.4.3.tgz", - "integrity": "sha512-UgifkHKoWVRUoSqO4Z4Z+Hl1NbiYBVDlmkmulFFeRRneGECWAlAdGWJdyz+2NisjOZnnQoxQl0s5dQ7ch62Jxw==", - "dev": true - }, - "jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "jest-each": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.2.4.tgz", + "integrity": "sha512-w9XVc+0EDBUTJS4xBNJ7N2JCcWItFd006lFjz77OarAQcQ10eFDBMrfDv2GBJMKlXe9aq0HrIIF51AXcZrRJyg==", "dev": true, "requires": { + "@jest/types": "^27.2.4", "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "jest-get-type": "^27.0.6", + "jest-util": "^27.2.4", + "pretty-format": "^27.2.4" }, "dependencies": { "ansi-styles": { @@ -5381,9 +3411,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5422,36 +3452,88 @@ } } }, - "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "jest-environment-jsdom": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.2.4.tgz", + "integrity": "sha512-X70pTXFSypD7AIzKT1mLnDi5hP9w9mdTRcOGOmoDoBrNyNEg4rYm6d4LQWFLc9ps1VnMuDOkFSG0wjSNYGjkng==", + "dev": true, + "requires": { + "@jest/environment": "^27.2.4", + "@jest/fake-timers": "^27.2.4", + "@jest/types": "^27.2.4", + "@types/node": "*", + "jest-mock": "^27.2.4", + "jest-util": "^27.2.4", + "jsdom": "^16.6.0" + } + }, + "jest-environment-node": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.2.4.tgz", + "integrity": "sha512-ZbVbFSnbzTvhLOIkqh5lcLuGCCFvtG4xTXIRPK99rV2KzQT3kNg16KZwfTnLNlIiWCE8do960eToeDfcqmpSAw==", + "dev": true, + "requires": { + "@jest/environment": "^27.2.4", + "@jest/fake-timers": "^27.2.4", + "@jest/types": "^27.2.4", + "@types/node": "*", + "jest-mock": "^27.2.4", + "jest-util": "^27.2.4" + } + }, + "jest-get-type": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", + "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", + "dev": true + }, + "jest-haste-map": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.2.4.tgz", + "integrity": "sha512-bkJ4bT00T2K+1NZXbRcyKnbJ42I6QBvoDNMTAQQDBhaGNnZreiQKUNqax0e6hLTx7E75pKDeltVu3V1HAdu+YA==", + "dev": true, + "requires": { + "@jest/types": "^27.2.4", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^27.0.6", + "jest-serializer": "^27.0.6", + "jest-util": "^27.2.4", + "jest-worker": "^27.2.4", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.2.4.tgz", + "integrity": "sha512-fcffjO/xLWLVnW2ct3No4EksxM5RyPwHDYu9QU+90cC+/eSMLkFAxS55vkqsxexOO5zSsZ3foVpMQcg/amSeIQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", + "@babel/traverse": "^7.1.0", + "@jest/environment": "^27.2.4", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", + "@types/node": "*", "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" + "co": "^4.6.0", + "expect": "^27.2.4", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.2.4", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "pretty-format": "^27.2.4", + "throat": "^6.0.1" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5462,9 +3544,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5503,29 +3585,34 @@ } } }, - "jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "jest-leak-detector": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.2.4.tgz", + "integrity": "sha512-SrcHWbe0EHg/bw2uBjVoHacTo5xosl068x2Q0aWsjr2yYuW2XwqrSkZV4lurUop0jhv1709ymG4or+8E4sH27Q==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*" + "jest-get-type": "^27.0.6", + "pretty-format": "^27.2.4" + } + }, + "jest-localstorage-mock": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/jest-localstorage-mock/-/jest-localstorage-mock-2.4.3.tgz", + "integrity": "sha512-UgifkHKoWVRUoSqO4Z4Z+Hl1NbiYBVDlmkmulFFeRRneGECWAlAdGWJdyz+2NisjOZnnQoxQl0s5dQ7ch62Jxw==", + "dev": true + }, + "jest-matcher-utils": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.2.4.tgz", + "integrity": "sha512-nQeLfFAIPPkyhkDfifAPfP/U5wm1x0fLtAzqXZSSKckXDNuk2aaOfQiDYv1Mgf5GY6yOsxfUnvNm3dDjXM+BXw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.2.4", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.2.4" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5536,9 +3623,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5577,47 +3664,23 @@ } } }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true - }, - "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", - "dev": true - }, - "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "jest-message-util": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.2.4.tgz", + "integrity": "sha512-wbKT/BNGnBVB9nzi+IoaLkXt6fbSvqUxx+IYY66YFh96J3goY33BAaNG3uPqaw/Sh/FR9YpXGVDfd5DJdbh4nA==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.2.4", + "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" + "micromatch": "^4.0.4", + "pretty-format": "^27.2.4", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5628,9 +3691,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5658,20 +3721,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5683,30 +3732,46 @@ } } }, - "jest-resolve-dependencies": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", + "jest-mock": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.2.4.tgz", + "integrity": "sha512-iVRU905rutaAoUcrt5Tm1JoHHWi24YabqEGXjPJI4tAyA6wZ7mzDi3GrZ+M7ebgWBqUkZE93GAx1STk7yCMIQA==", + "dev": true, + "requires": { + "@jest/types": "^27.2.4", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true + }, + "jest-regex-util": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", + "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", + "dev": true + }, + "jest-resolve": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.2.4.tgz", + "integrity": "sha512-IsAO/3+3BZnKjI2I4f3835TBK/90dxR7Otgufn3mnrDFTByOSXclDi3G2XJsawGV4/18IMLARJ+V7Wm7t+J89Q==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.6.2" + "@jest/types": "^27.2.4", + "chalk": "^4.0.0", + "escalade": "^3.1.1", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", + "resolve": "^1.20.0", + "slash": "^3.0.0" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5717,9 +3782,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5758,47 +3823,47 @@ } } }, + "jest-resolve-dependencies": { + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.4.tgz", + "integrity": "sha512-i5s7Uh9B3Q6uwxLpMhNKlgBf6pcemvWaORxsW1zNF/YCY3jd5EftvnGBI+fxVwJ1CBxkVfxqCvm1lpZkbaoGmg==", + "dev": true, + "requires": { + "@jest/types": "^27.2.4", + "jest-regex-util": "^27.0.6", + "jest-snapshot": "^27.2.4" + } + }, "jest-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.2.4.tgz", + "integrity": "sha512-hIo5PPuNUyVDidZS8EetntuuJbQ+4IHWxmHgYZz9FIDbG2wcZjrP6b52uMDjAEQiHAn8yn8ynNe+TL8UuGFYKg==", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.2.4", + "@jest/environment": "^27.2.4", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.7.1", + "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", + "jest-docblock": "^27.0.6", + "jest-environment-jsdom": "^27.2.4", + "jest-environment-node": "^27.2.4", + "jest-haste-map": "^27.2.4", + "jest-leak-detector": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-resolve": "^27.2.4", + "jest-runtime": "^27.2.4", + "jest-util": "^27.2.4", + "jest-worker": "^27.2.4", "source-map-support": "^0.5.6", - "throat": "^5.0.0" + "throat": "^6.0.1" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5809,9 +3874,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5839,20 +3904,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5865,53 +3916,40 @@ } }, "jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.2.4.tgz", + "integrity": "sha512-ICKzzYdjIi70P17MZsLLIgIQFCQmIjMFf+xYww3aUySiUA/QBPUTdUqo5B2eg4HOn9/KkUsV0z6GVgaqAPBJvg==", + "dev": true, + "requires": { + "@jest/console": "^27.2.4", + "@jest/environment": "^27.2.4", + "@jest/fake-timers": "^27.2.4", + "@jest/globals": "^27.2.4", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.2.4", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", + "@types/yargs": "^16.0.0", "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", + "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", "exit": "^0.1.2", "glob": "^7.1.3", "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", + "jest-haste-map": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-mock": "^27.2.4", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.2.4", + "jest-snapshot": "^27.2.4", + "jest-util": "^27.2.4", + "jest-validate": "^27.2.4", "slash": "^3.0.0", "strip-bom": "^4.0.0", - "yargs": "^15.4.1" + "yargs": "^16.2.0" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5922,9 +3960,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5952,20 +3990,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5978,9 +4002,9 @@ } }, "jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", + "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", "dev": true, "requires": { "@types/node": "*", @@ -5988,42 +4012,37 @@ } }, "jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.2.4.tgz", + "integrity": "sha512-5DFxK31rYS8X8C6WXsFx8XxrxW3PGa6+9IrUcZdTLg1aEyXDGIeiBh4jbwvh655bg/9vTETbEj/njfZicHTZZw==", "dev": true, "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", + "@jest/transform": "^27.2.4", + "@jest/types": "^27.2.4", "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^26.6.2", + "expect": "^27.2.4", "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", + "jest-diff": "^27.2.4", + "jest-get-type": "^27.0.6", + "jest-haste-map": "^27.2.4", + "jest-matcher-utils": "^27.2.4", + "jest-message-util": "^27.2.4", + "jest-resolve": "^27.2.4", + "jest-util": "^27.2.4", "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", + "pretty-format": "^27.2.4", "semver": "^7.3.2" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6034,9 +4053,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6085,42 +4104,32 @@ } }, "jest-util": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.3.0.tgz", - "integrity": "sha512-4zpn6bwV0+AMFN0IYhH/wnzIQzRaYVrz1A8sYnRnj4UXDXbOVtWmlaZkO9mipFqZ13okIfN87aDoJWB7VH6hcw==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.2.4.tgz", + "integrity": "sha512-mW++4u+fSvAt3YBWm5IpbmRAceUqa2B++JlUZTiuEt2AmNYn0Yw5oay4cP17TGsMINRNPSGiJ2zNnX60g+VbFg==", "dev": true, "requires": { - "@jest/types": "^26.3.0", + "@jest/types": "^27.2.4", "@types/node": "*", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" }, "dependencies": { "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6142,37 +4151,18 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6181,45 +4171,23 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, "jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.2.4.tgz", + "integrity": "sha512-VMtbxbkd7LHnIH7PChdDtrluCFRJ4b1YV2YJzNwwsASMWftq/HgqiqjvptBOWyWOtevgO3f14wPxkPcLlVBRog==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", + "@jest/types": "^27.2.4", + "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", + "jest-get-type": "^27.0.6", "leven": "^3.1.0", - "pretty-format": "^26.6.2" + "pretty-format": "^27.2.4" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6236,9 +4204,9 @@ "dev": true }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6278,33 +4246,20 @@ } }, "jest-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.2.4.tgz", + "integrity": "sha512-LXC/0+dKxhK7cfF7reflRYlzDIaQE+fL4ynhKhzg8IMILNMuI4xcjXXfUJady7OR4/TZeMg7X8eHx8uan9vqaQ==", "dev": true, "requires": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/test-result": "^27.2.4", + "@jest/types": "^27.2.4", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^26.6.2", + "jest-util": "^27.2.4", "string-length": "^4.0.1" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -6315,9 +4270,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6345,20 +4300,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", - "dev": true, - "requires": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6371,14 +4312,14 @@ } }, "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.4.tgz", + "integrity": "sha512-Zq9A2Pw59KkVjBBKD1i3iE2e22oSjXhUKKuAK1HGX8flGwkm6NMozyEYzKd41hXc64dbd/0eWFeEEuxqXyhM+g==", "dev": true, "requires": { "@types/node": "*", "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "supports-color": "^8.0.0" }, "dependencies": { "has-flag": { @@ -6388,9 +4329,9 @@ "dev": true }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -6414,20 +4355,14 @@ "esprima": "^4.0.0" } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, "jsdom": { - "version": "16.5.2", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.2.tgz", - "integrity": "sha512-JxNtPt9C1ut85boCbJmffaQ06NBnzkQY/MWO3YxPW8IWS38A26z+B1oBvA9LwKrytewdfymnhi4UNH3/RAgZrg==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, "requires": { "abab": "^2.0.5", - "acorn": "^8.1.0", + "acorn": "^8.2.4", "acorn-globals": "^6.0.0", "cssom": "^0.4.4", "cssstyle": "^2.3.0", @@ -6435,12 +4370,13 @@ "decimal.js": "^10.2.1", "domexception": "^2.0.1", "escodegen": "^2.0.0", + "form-data": "^3.0.0", "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.0", "parse5": "6.0.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.9", "saxes": "^5.0.1", "symbol-tree": "^3.2.4", "tough-cookie": "^4.0.0", @@ -6450,14 +4386,14 @@ "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.5.0", - "ws": "^7.4.4", + "ws": "^7.4.6", "xml-name-validator": "^3.0.0" }, "dependencies": { "acorn": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", - "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", "dev": true } } @@ -6468,18 +4404,6 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -6492,39 +4416,15 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "requires": { "minimist": "^1.2.5" } }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, "kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -6547,12 +4447,6 @@ "type-check": "~0.3.2" } }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -6563,9 +4457,15 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "dev": true }, "lodash.defaults": { @@ -6592,12 +4492,24 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -6631,21 +4543,6 @@ "tmpl": "1.0.x" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, "mdn-browser-compat-data": { "version": "1.0.35", "resolved": "https://registry.npmjs.org/mdn-browser-compat-data/-/mdn-browser-compat-data-1.0.35.tgz", @@ -6668,28 +4565,36 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" + }, + "dependencies": { + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + } } }, "mime-db": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", - "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", + "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", "dev": true }, "mime-types": { - "version": "2.1.29", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", - "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", + "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", "dev": true, "requires": { - "mime-db": "1.46.0" + "mime-db": "1.50.0" } }, "mimic-fn": { @@ -6713,70 +4618,18 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "node-fetch": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", @@ -6789,65 +4642,18 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-notifier": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", - "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", - "dev": true, - "optional": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "optional": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true }, "node-releases": { - "version": "1.1.60", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz", - "integrity": "sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==", + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", "dev": true }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -6855,20 +4661,12 @@ "dev": true }, "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { - "path-key": "^2.0.0" - }, - "dependencies": { - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - } + "path-key": "^3.0.0" } }, "nwsapi": { @@ -6877,66 +4675,11 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -6969,18 +4712,6 @@ "word-wrap": "~1.2.3" } }, - "p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -6999,6 +4730,12 @@ "p-limit": "^2.2.0" } }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -7014,30 +4751,12 @@ "callsites": "^3.0.0" } }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, "parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -7057,9 +4776,9 @@ "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-to-regexp": { @@ -7074,12 +4793,6 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", @@ -7104,12 +4817,6 @@ "find-up": "^4.0.0" } }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -7117,84 +4824,22 @@ "dev": true }, "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "version": "27.2.4", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.2.4.tgz", + "integrity": "sha512-NUjw22WJHldzxyps2YjLZkUj6q1HvjqFezkB9Y2cklN8NtVZN/kZEXGZdFw4uny3oENzV5EEMESrkI0YDUH8vg==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", + "@jest/types": "^27.2.4", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", "react-is": "^17.0.1" }, "dependencies": { - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, @@ -7217,9 +4862,9 @@ "dev": true }, "prompts": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", - "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", + "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", "dev": true, "requires": { "kleur": "^3.0.3", @@ -7232,28 +4877,12 @@ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -7261,42 +4890,11 @@ "dev": true }, "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - } - }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -7313,9 +4911,9 @@ } }, "redis-commands": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.6.0.tgz", - "integrity": "sha512-2jnZ0IkjZxvguITjFTrGiLyzQZcTvaw8DAaCXxZq/dsHXz7KfMQ3OUJy7Tz9vnRtZRVz6VRCPDvruvU8Ts44wQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", + "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==", "dev": true }, "redis-errors": { @@ -7342,128 +4940,22 @@ "promise-queue": "^2.2.5" } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, "regexpp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", "dev": true }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - } - } - }, - "request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "requires": { - "lodash": "^4.17.19" - } - }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "dev": true, - "requires": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, "resolve": { @@ -7491,18 +4983,6 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -7518,12 +4998,6 @@ "glob": "^7.1.3" } }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, "run-parallel": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", @@ -7536,162 +5010,12 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, "saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -7701,40 +5025,11 @@ "xmlchars": "^2.2.0" } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true }, "shebang-command": { "version": "2.0.0", @@ -7751,17 +5046,10 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true - }, "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", "dev": true }, "sisteransi": { @@ -7777,255 +5065,68 @@ "dev": true }, "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "is-descriptor": "^0.1.0" + "color-convert": "^2.0.1" } }, - "extend-shallow": { + "color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "is-extendable": "^0.1.0" + "color-name": "~1.1.4" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true } } }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "requires": { "escape-string-regexp": "^2.0.0" @@ -8040,36 +5141,9 @@ } }, "standard-as-callback": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.0.1.tgz", - "integrity": "sha512-NQOxSeB8gOI5WjSaxjBgog2QFw55FV8TkS6Y07BiB3VJ8xNTvUYm0wl0s8ObgQ5NhdpnNfigMIKjgPESzgr4tg==", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", "dev": true }, "string-length": { @@ -8083,14 +5157,25 @@ } }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } } }, "string_decoder": { @@ -8117,12 +5202,6 @@ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, "strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -8145,9 +5224,9 @@ } }, "supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", "dev": true, "requires": { "has-flag": "^4.0.0", @@ -8178,53 +5257,55 @@ "dev": true }, "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", + "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true + "ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } } } @@ -8257,9 +5338,9 @@ "dev": true }, "throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", "dev": true }, "through2": { @@ -8273,9 +5354,9 @@ } }, "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, "to-fast-properties": { @@ -8284,38 +5365,6 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -8337,38 +5386,38 @@ } }, "tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", "dev": true, "requires": { "punycode": "^2.1.1" } }, "ts-jest": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.3.0.tgz", - "integrity": "sha512-Jq2uKfx6bPd9+JDpZNMBJMdMQUC3sJ08acISj8NXlVgR2d5OqslEHOR2KHMgwymu8h50+lKIm0m0xj/ioYdW2Q==", + "version": "27.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.5.tgz", + "integrity": "sha512-lIJApzfTaSSbtlksfFNHkWOzLJuuSm4faFAfo5kvzOiRAuoN4/eKxVJ2zEAho8aecE04qX6K1pAzfH5QHL1/8w==", "dev": true, "requires": { - "@types/jest": "26.x", "bs-logger": "0.x", - "buffer-from": "1.x", "fast-json-stable-stringify": "2.x", - "jest-util": "26.x", + "jest-util": "^27.0.0", "json5": "2.x", - "lodash.memoize": "4.x", + "lodash": "4.x", "make-error": "1.x", - "mkdirp": "1.x", "semver": "7.x", - "yargs-parser": "18.x" + "yargs-parser": "20.x" }, "dependencies": { "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, @@ -8394,21 +5443,6 @@ } } }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -8425,9 +5459,9 @@ "dev": true }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true }, "typedarray-to-buffer": { @@ -8445,64 +5479,12 @@ "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==", "dev": true }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, "uri-js": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", @@ -8512,41 +5494,22 @@ "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "optional": true - }, "v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", - "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, "v8-to-istanbul": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.1.tgz", - "integrity": "sha512-p0BB09E5FRjx0ELN6RgusIPsSPhtgexSRcKETybEs6IGOTXJSZqfwxp7r//55nnu0f1AxltY5VvdVqy2vZf9AA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", + "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -8562,27 +5525,6 @@ } } }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -8632,13 +5574,13 @@ "dev": true }, "whatwg-url": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz", - "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", "dev": true, "requires": { "lodash": "^4.7.0", - "tr46": "^2.0.2", + "tr46": "^2.1.0", "webidl-conversions": "^6.1.0" } }, @@ -8651,12 +5593,6 @@ "isexe": "^2.0.0" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -8664,9 +5600,9 @@ "dev": true }, "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { "ansi-styles": "^4.0.0", @@ -8706,26 +5642,6 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - } - } - }, "write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", @@ -8739,9 +5655,9 @@ } }, "ws": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", - "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", + "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", "dev": true }, "xml-name-validator": { @@ -8763,9 +5679,9 @@ "dev": true }, "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yallist": { @@ -8775,33 +5691,25 @@ "dev": true }, "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } }, "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true } } } diff --git a/package.json b/package.json index c981c1b2..01e594a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-commons", - "version": "0.1.0", + "version": "1.0.0", "description": "Split Javascript SDK common components", "main": "cjs/index.js", "module": "esm/index.js", @@ -50,7 +50,7 @@ "devDependencies": { "@types/google.analytics": "0.0.40", "@types/ioredis": "^4.14.1", - "@types/jest": "^26.0.10", + "@types/jest": "^27.0.0", "@types/lodash": "^4.14.162", "@types/node": "^14.14.7", "@types/object-assign": "^4.0.30", @@ -58,18 +58,18 @@ "@typescript-eslint/parser": "^4.2.0", "cross-env": "^7.0.2", "csv-streamify": "^4.0.0", - "eslint": "^7.9.0", + "eslint": "^7.32.0", "eslint-plugin-compat": "3.7.0", "fetch-mock": "^9.10.7", - "ioredis": "4.18.0", - "jest": "^26.6.3", + "ioredis": "^4.26.0", + "jest": "^27.2.3", "jest-localstorage-mock": "^2.4.3", "js-yaml": "^3.14.0", - "lodash": "^4.17.20", + "lodash": "^4.17.21", "node-fetch": "^2.6.1", "redis-server": "1.2.2", "rimraf": "^3.0.2", - "ts-jest": "^26.3.0", + "ts-jest": "^27.0.5", "typescript": "^4.0.2" }, "sideEffects": false diff --git a/src/__tests__/mocks/message.STREAMING_RESET.json b/src/__tests__/mocks/message.STREAMING_RESET.json new file mode 100644 index 00000000..791d9ded --- /dev/null +++ b/src/__tests__/mocks/message.STREAMING_RESET.json @@ -0,0 +1,4 @@ +{ + "type": "message", + "data": "{\"timestamp\":1457552660000,\"data\":\"{\\\"type\\\":\\\"CONTROL\\\",\\\"controlType\\\":\\\"STREAMING_RESET\\\"}\"}" +} \ No newline at end of file diff --git a/src/__tests__/mocks/message.V2.BOUNDED.GZIP.1457552651000.json b/src/__tests__/mocks/message.V2.BOUNDED.GZIP.1457552651000.json new file mode 100644 index 00000000..97c2a73c --- /dev/null +++ b/src/__tests__/mocks/message.V2.BOUNDED.GZIP.1457552651000.json @@ -0,0 +1,4 @@ +{ + "type": "message", + "data": "{\"data\":\"{\\\"type\\\":\\\"MY_SEGMENTS_UPDATE_V2\\\",\\\"changeNumber\\\":1457552651000,\\\"segmentName\\\":\\\"\\\",\\\"c\\\": 1,\\\"u\\\": 1,\\\"d\\\":\\\"H4sIAAAAAAAA/2JABxzYeIxQLguYFIBLN8Bl4EABjc+EzOnAsA4QAAD//8YBvWeAAAAA\\\"}\"}" +} \ No newline at end of file diff --git a/src/__tests__/mocks/message.V2.KEYLIST.GZIP.1457552652000.json b/src/__tests__/mocks/message.V2.KEYLIST.GZIP.1457552652000.json new file mode 100644 index 00000000..c44ee3ac --- /dev/null +++ b/src/__tests__/mocks/message.V2.KEYLIST.GZIP.1457552652000.json @@ -0,0 +1,4 @@ +{ + "type": "message", + "data": "{\"data\":\"{\\\"type\\\":\\\"MY_SEGMENTS_UPDATE_V2\\\",\\\"changeNumber\\\":1457552652000,\\\"segmentName\\\":\\\"splitters\\\",\\\"c\\\": 1,\\\"u\\\": 2,\\\"d\\\":\\\"H4sIAAAAAAAA/wTAsRHDUAgD0F2ofwEIkPAqPhdZIW0uu/v97GPXHU004ULuMGrYR6XUbIjlXULPPse+dt1yhJibBODjrTmj3GJ4emduuDDP/w0AAP//18WLsl0AAAA=\\\"}\"}" +} \ No newline at end of file diff --git a/src/__tests__/mocks/message.V2.SEGMENT_REMOVAL.1457552653000.json b/src/__tests__/mocks/message.V2.SEGMENT_REMOVAL.1457552653000.json new file mode 100644 index 00000000..aaf1a3f3 --- /dev/null +++ b/src/__tests__/mocks/message.V2.SEGMENT_REMOVAL.1457552653000.json @@ -0,0 +1,4 @@ +{ + "type": "message", + "data": "{\"data\":\"{\\\"type\\\":\\\"MY_SEGMENTS_UPDATE_V2\\\",\\\"changeNumber\\\":1457552653000,\\\"segmentName\\\":\\\"splitters\\\",\\\"c\\\": 0,\\\"u\\\": 3,\\\"d\\\":\\\"\\\"}\"}" +} \ No newline at end of file diff --git a/src/__tests__/mocks/message.V2.UNBOUNDED.1457552650000.json b/src/__tests__/mocks/message.V2.UNBOUNDED.1457552650000.json new file mode 100644 index 00000000..a7a2e793 --- /dev/null +++ b/src/__tests__/mocks/message.V2.UNBOUNDED.1457552650000.json @@ -0,0 +1,4 @@ +{ + "type": "message", + "data": "{\"data\":\"{\\\"type\\\":\\\"MY_SEGMENTS_UPDATE_V2\\\",\\\"changeNumber\\\":1457552650000,\\\"segmentName\\\":\\\"\\\",\\\"c\\\": 0,\\\"u\\\": 0,\\\"d\\\":\\\"\\\"}\"}" +} \ No newline at end of file diff --git a/src/__tests__/testUtils/eventSourceMock.ts b/src/__tests__/testUtils/eventSourceMock.ts index 87369bc0..281421b3 100644 --- a/src/__tests__/testUtils/eventSourceMock.ts +++ b/src/__tests__/testUtils/eventSourceMock.ts @@ -47,7 +47,8 @@ export default class EventSource { static readonly CLOSED: ReadyStateType = 2; private readonly __emitter: IEventEmitter; - onerror?: (evt: MessageEvent) => any;; + private readonly __eventSourceInitDict: EventSourceInitDict; + onerror?: (evt: MessageEvent) => any; onmessage?: (evt: MessageEvent) => any; onopen?: (evt?: MessageEvent) => any; readyState: ReadyStateType; @@ -56,13 +57,14 @@ export default class EventSource { constructor( url: string, - configuration: EventSourceInitDict = defaultOptions + eventSourceInitDict: EventSourceInitDict = defaultOptions ) { this.url = url; - this.withCredentials = configuration.withCredentials; + this.withCredentials = eventSourceInitDict.withCredentials; this.readyState = 0; // @ts-ignore this.__emitter = new EventEmitter(); + this.__eventSourceInitDict = arguments[1]; sources[url] = this; if (__listener) setTimeout(__listener, 0, this); } @@ -81,24 +83,28 @@ export default class EventSource { emit(eventName: string, messageEvent?: MessageEvent) { this.__emitter.emit(eventName, messageEvent); + + let listener: ((evt: any) => any) | undefined; + switch (eventName) { + case 'error': listener = this.onerror; break; + case 'open': listener = this.onopen; break; + case 'message': listener = this.onmessage; break; + } + if (typeof listener === 'function') { + listener(messageEvent); + } } emitError(error: MessageEvent) { - if (typeof this.onerror === 'function') { - this.onerror(error); - } + this.emit('error', error); } emitOpen() { this.readyState = 1; - if (typeof this.onopen === 'function') { - this.onopen(); - } + this.emit('open'); } emitMessage(message: MessageEvent) { - if (typeof this.onmessage === 'function') { - this.onmessage(message); - } + this.emit('message', message); } } diff --git a/src/dtos/types.ts b/src/dtos/types.ts index 1351dc8f..a61e3777 100644 --- a/src/dtos/types.ts +++ b/src/dtos/types.ts @@ -194,18 +194,15 @@ export interface IMySegmentsResponse { mySegments: IMySegmentsResponseItem[] } -/** Metadata internal types */ +/** Metadata internal type for storages */ export interface IMetadata { - version: string // SDK version - ip: string | false // host IP - hostname: string | false // host name -} - -export interface IRedisMetadata { - s: string // SDK version - i: string // host IP - n: string // host name + /** SDK version */ + s: string + /** host IP */ + i: string + /** host name */ + n: string } export type ISplitFiltersValidation = { diff --git a/src/evaluator/index.ts b/src/evaluator/index.ts index 8dd5aa14..3c12c9b3 100644 --- a/src/evaluator/index.ts +++ b/src/evaluator/index.ts @@ -15,6 +15,14 @@ const treatmentException = { config: null }; +function treatmentsException(splitNames: string[]) { + const evaluations: Record = {}; + splitNames.forEach(splitName => { + evaluations[splitName] = treatmentException; + }); + return evaluations; +} + export function evaluateFeature( log: ILogger, key: SplitIO.SplitKey, @@ -27,10 +35,8 @@ export function evaluateFeature( try { stringifiedSplit = storage.splits.getSplit(splitName); } catch (e) { - // the only scenario where getSplit can throw an error is when the storage - // is redis and there is a connection issue and we can't retrieve the split - // to be evaluated - return Promise.resolve(treatmentException); + // Exception on sync `getSplit` storage. Not possible ATM with InMemory and InLocal storages. + return treatmentException; } if (thenable(stringifiedSplit)) { @@ -40,7 +46,11 @@ export function evaluateFeature( key, attributes, storage, - )); + )).catch( + // Exception on async `getSplit` storage. For example, when the storage is redis or + // pluggable and there is a connection issue and we can't retrieve the split to be evaluated + () => treatmentException + ); } return getEvaluation( @@ -60,22 +70,21 @@ export function evaluateFeatures( storage: IStorageSync | IStorageAsync, ): MaybeThenable> { let stringifiedSplits; - const evaluations: Record = {}; try { stringifiedSplits = storage.splits.getSplits(splitNames); } catch (e) { - // the only scenario where `getSplits` can throw an error is when the storage - // is redis and there is a connection issue and we can't retrieve the split - // to be evaluated - splitNames.forEach(splitName => { - evaluations[splitName] = treatmentException; - }); - return Promise.resolve(evaluations); + // Exception on sync `getSplits` storage. Not possible ATM with InMemory and InLocal storages. + return treatmentsException(splitNames); } return (thenable(stringifiedSplits)) ? - stringifiedSplits.then(splits => getEvaluations(log, splitNames, splits, key, attributes, storage)) : + stringifiedSplits.then(splits => getEvaluations(log, splitNames, splits, key, attributes, storage)) + .catch(() => { + // Exception on async `getSplits` storage. For example, when the storage is redis or + // pluggable and there is a connection issue and we can't retrieve the split to be evaluated + return treatmentsException(splitNames); + }) : getEvaluations(log, splitNames, stringifiedSplits, key, attributes, storage); } diff --git a/src/evaluator/matchers/matcherTypes.ts b/src/evaluator/matchers/matcherTypes.ts index 76ed1192..786db547 100644 --- a/src/evaluator/matchers/matcherTypes.ts +++ b/src/evaluator/matchers/matcherTypes.ts @@ -19,7 +19,7 @@ export const matcherTypes: Record = { MATCHES_STRING: 17 }; -export const dataTypes = { +export const matcherDataTypes = { BOOLEAN: 'BOOLEAN', STRING: 'STRING', NUMBER: 'NUMBER', @@ -28,7 +28,7 @@ export const dataTypes = { NOT_SPECIFIED: 'NOT_SPECIFIED' }; -export function mapper(matcherType: string) { +export function matcherTypesMapper(matcherType: string) { const type = matcherTypes[matcherType]; if (type) return type; else return matcherTypes.UNDEFINED; diff --git a/src/evaluator/matchersTransform/index.ts b/src/evaluator/matchersTransform/index.ts index 7a4f6241..abb1c8b0 100644 --- a/src/evaluator/matchersTransform/index.ts +++ b/src/evaluator/matchersTransform/index.ts @@ -1,5 +1,5 @@ import { findIndex } from '../../utils/lang'; -import { matcherTypes, mapper, dataTypes } from '../matchers/matcherTypes'; +import { matcherTypes, matcherTypesMapper, matcherDataTypes } from '../matchers/matcherTypes'; import segmentTransform from './segment'; import whitelistTransform from './whitelist'; import setTransform from './set'; @@ -28,9 +28,9 @@ export default function matchersTransform(matchers: ISplitMatcher[]): IMatcherDt } = matcher; let attribute = keySelector && keySelector.attribute; - let type = mapper(matcherType); + let type = matcherTypesMapper(matcherType); // As default input data type we use string (even for ALL_KEYS) - let dataType = dataTypes.STRING; + let dataType = matcherDataTypes.STRING; let value = undefined; if (type === matcherTypes.IN_SEGMENT) { @@ -39,29 +39,29 @@ export default function matchersTransform(matchers: ISplitMatcher[]): IMatcherDt value = whitelistTransform(whitelistObject as IWhitelistMatcherData); } else if (type === matcherTypes.EQUAL_TO) { value = numericTransform(unaryNumericObject as IUnaryNumericMatcherData); - dataType = dataTypes.NUMBER; + dataType = matcherDataTypes.NUMBER; if ((unaryNumericObject as IUnaryNumericMatcherData).dataType === 'DATETIME') { value = zeroSinceHH(value); - dataType = dataTypes.DATETIME; + dataType = matcherDataTypes.DATETIME; } } else if (type === matcherTypes.GREATER_THAN_OR_EQUAL_TO || type === matcherTypes.LESS_THAN_OR_EQUAL_TO) { value = numericTransform(unaryNumericObject as IUnaryNumericMatcherData); - dataType = dataTypes.NUMBER; + dataType = matcherDataTypes.NUMBER; if ((unaryNumericObject as IUnaryNumericMatcherData).dataType === 'DATETIME') { value = zeroSinceSS(value); - dataType = dataTypes.DATETIME; + dataType = matcherDataTypes.DATETIME; } } else if (type === matcherTypes.BETWEEN) { value = betweenObject as IBetweenMatcherData; - dataType = dataTypes.NUMBER; + dataType = matcherDataTypes.NUMBER; if (value.dataType === 'DATETIME') { value.start = zeroSinceSS(value.start); value.end = zeroSinceSS(value.end); - dataType = dataTypes.DATETIME; + dataType = matcherDataTypes.DATETIME; } } else if ( type === matcherTypes.EQUAL_TO_SET || @@ -70,7 +70,7 @@ export default function matchersTransform(matchers: ISplitMatcher[]): IMatcherDt type === matcherTypes.PART_OF_SET ) { value = setTransform(whitelistObject as IWhitelistMatcherData); - dataType = dataTypes.SET; + dataType = matcherDataTypes.SET; } else if ( type === matcherTypes.STARTS_WITH || type === matcherTypes.ENDS_WITH || @@ -79,9 +79,9 @@ export default function matchersTransform(matchers: ISplitMatcher[]): IMatcherDt value = setTransform(whitelistObject as IWhitelistMatcherData); } else if (type === matcherTypes.IN_SPLIT_TREATMENT) { value = dependencyObject; - dataType = dataTypes.NOT_SPECIFIED; + dataType = matcherDataTypes.NOT_SPECIFIED; } else if (type === matcherTypes.EQUAL_TO_BOOLEAN) { - dataType = dataTypes.BOOLEAN; + dataType = matcherDataTypes.BOOLEAN; value = booleanMatcherData; } else if (type === matcherTypes.MATCHES_STRING) { value = stringMatcherData; diff --git a/src/evaluator/value/sanitize.ts b/src/evaluator/value/sanitize.ts index 46cae859..7ca7b5cd 100644 --- a/src/evaluator/value/sanitize.ts +++ b/src/evaluator/value/sanitize.ts @@ -3,7 +3,7 @@ import { IDependencyMatcherValue } from '../types'; import { ILogger } from '../../logger/types'; import { isObject, uniq, toString, toNumber } from '../../utils/lang'; import { zeroSinceHH, zeroSinceSS } from '../convertions'; -import { matcherTypes, dataTypes } from '../matchers/matcherTypes'; +import { matcherTypes, matcherDataTypes } from '../matchers/matcherTypes'; import { ENGINE_SANITIZE } from '../../logger/constants'; function sanitizeNumber(val: any): number | undefined { @@ -23,7 +23,7 @@ function sanitizeString(val: any): string | undefined { return str ? str : undefined; } -function sanitizeArray(val: any): number[] | string[] | undefined { +function sanitizeArray(val: any): string[] | undefined { const arr = Array.isArray(val) ? uniq(val.map(e => e + '')) : []; return arr.length ? arr : undefined; } @@ -74,20 +74,20 @@ export default function sanitize(log: ILogger, matcherTypeID: number, value: str let sanitizedValue: string | number | boolean | Array | IDependencyMatcherValue | undefined; switch (dataType) { - case dataTypes.NUMBER: - case dataTypes.DATETIME: + case matcherDataTypes.NUMBER: + case matcherDataTypes.DATETIME: sanitizedValue = sanitizeNumber(value); break; - case dataTypes.STRING: + case matcherDataTypes.STRING: sanitizedValue = sanitizeString(value); break; - case dataTypes.SET: + case matcherDataTypes.SET: sanitizedValue = sanitizeArray(value); break; - case dataTypes.BOOLEAN: + case matcherDataTypes.BOOLEAN: sanitizedValue = sanitizeBoolean(value); break; - case dataTypes.NOT_SPECIFIED: + case matcherDataTypes.NOT_SPECIFIED: sanitizedValue = value; break; default: diff --git a/src/index.ts b/src/index.ts index 7abf494f..33f4217a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,24 +1,14 @@ // InMemory storage factory for standalone server-side SplitFactory export { InMemoryStorageFactory } from './storages/inMemory/InMemoryStorage'; + // InMemory storage factory for standalone client-side SplitFactory export { InMemoryStorageCSFactory } from './storages/inMemory/InMemoryStorageCS'; -// InMemory caches, reused to implement new storages -export { default as SplitsCacheInMemory } from './storages/inMemory/SplitsCacheInMemory'; -export { default as MySegmentsCacheInMemory } from './storages/inMemory/MySegmentsCacheInMemory'; -export { default as SegmentsCacheInMemory } from './storages/inMemory/SegmentsCacheInMemory'; -export { default as EventsCacheInMemory } from './storages/inMemory/EventsCacheInMemory'; -export { default as ImpressionsCacheInMemory } from './storages/inMemory/ImpressionsCacheInMemory'; -export { default as LatenciesCacheInMemory } from './storages/inMemory/LatenciesCacheInMemory'; -export { default as CountsCacheInMemory } from './storages/inMemory/CountsCacheInMemory'; - -// Utils for implementing new storages for standalone SplitFactory -export { default as AbstractSplitsCacheSync, usesSegments } from './storages/AbstractSplitsCacheSync'; -export { default as AbstractSegmentsCacheSync } from './storages/AbstractSegmentsCacheSync'; +// InLocalStorage factory for standalone client-side SplitFactory in Web browsers +export { InLocalStorage } from './storages/inLocalStorage'; -// Evaluator: -export { evaluateFeature, evaluateFeatures } from './evaluator'; +// Pluggable storage factory for consumer/producer mode +export { PluggableStorage } from './storages/pluggable'; -// Utils: -export { hash128 } from './utils/murmur3/murmur3_128'; -export { hash } from './utils/murmur3/murmur3'; +// Pluggable storage factory for consumer/producer mode +export { InRedisStorage } from './storages/inRedis'; diff --git a/src/integrations/__tests__/browser.spec.ts b/src/integrations/__tests__/browser.spec.ts index 9bab3e99..1b79d8bb 100644 --- a/src/integrations/__tests__/browser.spec.ts +++ b/src/integrations/__tests__/browser.spec.ts @@ -6,9 +6,9 @@ import { loggerMock } from '../../logger/__tests__/sdkLogger.mock'; // Mock integration modules (GaToSplit and SplitToGa). jest.mock('../ga/GaToSplit'); -import GaToSplitMock from '../ga/GaToSplit'; +import { GaToSplit as GaToSplitMock } from '../ga/GaToSplit'; jest.mock('../ga/SplitToGa'); -import SplitToGaMock from '../ga/SplitToGa'; +import { SplitToGa as SplitToGaMock } from '../ga/SplitToGa'; const SplitToGaQueueMethod = jest.fn(); (SplitToGaMock as unknown as jest.Mock).mockImplementation(() => { diff --git a/src/integrations/browser.ts b/src/integrations/browser.ts index f9cb8927..f3a17713 100644 --- a/src/integrations/browser.ts +++ b/src/integrations/browser.ts @@ -2,8 +2,8 @@ import { GOOGLE_ANALYTICS_TO_SPLIT, SPLIT_TO_GOOGLE_ANALYTICS } from '../utils/c import { IIntegration, IIntegrationManager, IIntegrationFactoryParams } from './types'; import { BrowserIntegration } from './ga/types'; import pluggableIntegrationsManagerFactory from './pluggable'; -import GaToSplitPlugin from './ga/GaToSplitPlugin'; -import SplitToGaPlugin from './ga/SplitToGaPlugin'; +import { GoogleAnalyticsToSplit } from './ga/GoogleAnalyticsToSplit'; +import { SplitToGoogleAnalytics } from './ga/SplitToGoogleAnalytics'; /** * IntegrationsManager factory for the browser variant of the isomorphic JS SDK. @@ -23,8 +23,8 @@ export default function integrationsManagerFactory( const integrationFactories: Array<(params: IIntegrationFactoryParams) => IIntegration | void> = integrations .map(integrationOptions => { switch (integrationOptions.type) { - case GOOGLE_ANALYTICS_TO_SPLIT: return GaToSplitPlugin(integrationOptions); - case SPLIT_TO_GOOGLE_ANALYTICS: return SplitToGaPlugin(integrationOptions); + case GOOGLE_ANALYTICS_TO_SPLIT: return GoogleAnalyticsToSplit(integrationOptions); + case SPLIT_TO_GOOGLE_ANALYTICS: return SplitToGoogleAnalytics(integrationOptions); } }) .filter(integrationFactory => { diff --git a/src/integrations/ga/GaToSplit.ts b/src/integrations/ga/GaToSplit.ts index befa31f1..360c93a1 100644 --- a/src/integrations/ga/GaToSplit.ts +++ b/src/integrations/ga/GaToSplit.ts @@ -182,7 +182,7 @@ export function fixEventTypeId(log: ILogger, eventTypeId: any) { * @param {object} coreSettings core settings used to define an identity if no one provided as SDK or plugin options * @param {object} log factory logger */ -export default function GaToSplit(sdkOptions: GoogleAnalyticsToSplitOptions, params: IIntegrationFactoryParams) { +export function GaToSplit(sdkOptions: GoogleAnalyticsToSplitOptions, params: IIntegrationFactoryParams) { const { storage, settings: { core: coreSettings, log } } = params; diff --git a/src/integrations/ga/GaToSplitPlugin.ts b/src/integrations/ga/GoogleAnalyticsToSplit.ts similarity index 66% rename from src/integrations/ga/GaToSplitPlugin.ts rename to src/integrations/ga/GoogleAnalyticsToSplit.ts index 04a16905..940447aa 100644 --- a/src/integrations/ga/GaToSplitPlugin.ts +++ b/src/integrations/ga/GoogleAnalyticsToSplit.ts @@ -1,8 +1,8 @@ import { IIntegrationFactoryParams } from '../types'; -import GaToSplit from './GaToSplit'; +import { GaToSplit } from './GaToSplit'; import { GoogleAnalyticsToSplitOptions } from './types'; -export default function GaToSplitPlugin(options: GoogleAnalyticsToSplitOptions) { +export function GoogleAnalyticsToSplit(options: GoogleAnalyticsToSplitOptions) { // GaToSplit integration factory return (params: IIntegrationFactoryParams) => { diff --git a/src/integrations/ga/SplitToGa.ts b/src/integrations/ga/SplitToGa.ts index df933c21..dd469676 100644 --- a/src/integrations/ga/SplitToGa.ts +++ b/src/integrations/ga/SplitToGa.ts @@ -10,7 +10,7 @@ const logPrefix = 'split-to-ga: '; const noGaWarning = '`ga` command queue not found.'; const noHit = 'No hit was sent.'; -export default class SplitToGa implements IIntegration { +export class SplitToGa implements IIntegration { // A falsy object represents the default tracker static defaultTrackerNames = ['']; diff --git a/src/integrations/ga/SplitToGaPlugin.ts b/src/integrations/ga/SplitToGoogleAnalytics.ts similarity index 67% rename from src/integrations/ga/SplitToGaPlugin.ts rename to src/integrations/ga/SplitToGoogleAnalytics.ts index 9001c180..4ec71177 100644 --- a/src/integrations/ga/SplitToGaPlugin.ts +++ b/src/integrations/ga/SplitToGoogleAnalytics.ts @@ -1,8 +1,8 @@ import { IIntegrationFactoryParams } from '../types'; -import SplitToGa from './SplitToGa'; +import { SplitToGa } from './SplitToGa'; import { SplitToGoogleAnalyticsOptions } from './types'; -export default function SplitToGaPlugin(options: SplitToGoogleAnalyticsOptions = {}) { +export function SplitToGoogleAnalytics(options: SplitToGoogleAnalyticsOptions = {}) { // SplitToGa integration factory return (params: IIntegrationFactoryParams) => { diff --git a/src/integrations/ga/__tests__/GaToSplit.spec.ts b/src/integrations/ga/__tests__/GaToSplit.spec.ts index 21c4a1ef..3296fe86 100644 --- a/src/integrations/ga/__tests__/GaToSplit.spec.ts +++ b/src/integrations/ga/__tests__/GaToSplit.spec.ts @@ -1,7 +1,7 @@ /* eslint-disable no-undef */ import { IEventsCacheSync } from '../../../storages/types'; import { SplitIO, ISettings } from '../../../types'; -import GaToSplit, { validateIdentities, defaultPrefix, defaultMapper, validateEventData, fixEventTypeId } from '../GaToSplit'; +import { GaToSplit, validateIdentities, defaultPrefix, defaultMapper, validateEventData, fixEventTypeId } from '../GaToSplit'; import { gaMock, gaRemove, modelMock } from './gaMock'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; @@ -122,6 +122,7 @@ function customMapper(model: UniversalAnalytics.Model, defaultEvent: SplitIO.Eve } // Updates defaultEvent function customMapper2(model: UniversalAnalytics.Model, defaultEvent: SplitIO.EventData) { + // @ts-ignore. The defaultEvent has a property value, that might be empty depending on the hitType defaultEvent.properties['someProp2'] = 'someProp2'; return defaultEvent; } diff --git a/src/integrations/ga/__tests__/SplitToGa.spec.ts b/src/integrations/ga/__tests__/SplitToGa.spec.ts index 849350ca..d05e4bab 100644 --- a/src/integrations/ga/__tests__/SplitToGa.spec.ts +++ b/src/integrations/ga/__tests__/SplitToGa.spec.ts @@ -6,7 +6,7 @@ import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; import { gaMock, gaRemove } from './gaMock'; // Test target -import SplitToGa from '../SplitToGa'; +import { SplitToGa } from '../SplitToGa'; const fakeImpressionPayload: SplitIO.ImpressionData = { impression: { diff --git a/src/listeners/__tests__/browser.spec.ts b/src/listeners/__tests__/browser.spec.ts index 32c69f59..3bd83169 100644 --- a/src/listeners/__tests__/browser.spec.ts +++ b/src/listeners/__tests__/browser.spec.ts @@ -105,7 +105,7 @@ function triggerUnloadEvent() { /* Mocks end */ -test('Browser JS listener / Impressions optimized mode', (done) => { +test('Browser JS listener / Impressions optimized mode', () => { const listener = new BrowserSignalListener(undefined, fullSettings, fakeStorageOptimized as IStorageSync, fakeSplitApi); @@ -116,63 +116,64 @@ test('Browser JS listener / Impressions optimized mode', (done) => { triggerUnloadEvent(); - setTimeout(() => { - // Unload event was triggered. Thus sendBeacon method should have been called three times. - expect(global.window.navigator.sendBeacon).toBeCalledTimes(3); + // Unload event was triggered. Thus sendBeacon method should have been called three times. + expect(global.window.navigator.sendBeacon).toBeCalledTimes(3); - // Http post services should have not been called - expect(fakeSplitApi.postTestImpressionsBulk).not.toBeCalled(); - expect(fakeSplitApi.postEventsBulk).not.toBeCalled(); - expect(fakeSplitApi.postTestImpressionsCount).not.toBeCalled(); + // Http post services should have not been called + expect(fakeSplitApi.postTestImpressionsBulk).not.toBeCalled(); + expect(fakeSplitApi.postEventsBulk).not.toBeCalled(); + expect(fakeSplitApi.postTestImpressionsCount).not.toBeCalled(); - // pre-check and call stop - expect(global.window.removeEventListener).not.toBeCalled(); - listener.stop(); + // pre-check and call stop + expect(global.window.removeEventListener).not.toBeCalled(); + listener.stop(); - // removed correct listener from correct signal on stop. - expect((global.window.removeEventListener as jest.Mock).mock.calls).toEqual([[UNLOAD_DOM_EVENT, listener.flushData]]); - - done(); - }, 0); + // removed correct listener from correct signal on stop. + expect((global.window.removeEventListener as jest.Mock).mock.calls).toEqual([[UNLOAD_DOM_EVENT, listener.flushData]]); }); -test('Browser JS listener / Impressions debug mode', (done) => { +test('Browser JS listener / Impressions debug mode', () => { + const syncManagerMockWithPushManager = { pushManager: { stop: jest.fn() } }; - const listener = new BrowserSignalListener(undefined, fullSettings, fakeStorageDebug as IStorageSync, fakeSplitApi); + // @ts-expect-error + const listener = new BrowserSignalListener(syncManagerMockWithPushManager, fullSettings, fakeStorageDebug as IStorageSync, fakeSplitApi); listener.start(); // Assigned right function to right signal. expect((global.window.addEventListener as jest.Mock).mock.calls).toEqual([[UNLOAD_DOM_EVENT, listener.flushData]]); + expect(syncManagerMockWithPushManager.pushManager.stop).not.toBeCalled(); + triggerUnloadEvent(); - setTimeout(() => { - // Unload event was triggered. Thus sendBeacon method should have been called twice. - expect(global.window.navigator.sendBeacon).toBeCalledTimes(2); + // Unload event was triggered. Thus sendBeacon method should have been called twice. + expect(global.window.navigator.sendBeacon).toBeCalledTimes(2); - // Http post services should have not been called - expect(fakeSplitApi.postTestImpressionsBulk).not.toBeCalled(); - expect(fakeSplitApi.postEventsBulk).not.toBeCalled(); - expect(fakeSplitApi.postTestImpressionsCount).not.toBeCalled(); + // And since we passed a syncManager with a pushManager, its stop method should have been called. + expect(syncManagerMockWithPushManager.pushManager.stop).toBeCalledTimes(1); - // pre-check and call stop - expect(global.window.removeEventListener).not.toBeCalled(); - listener.stop(); + // Http post services should have not been called + expect(fakeSplitApi.postTestImpressionsBulk).not.toBeCalled(); + expect(fakeSplitApi.postEventsBulk).not.toBeCalled(); + expect(fakeSplitApi.postTestImpressionsCount).not.toBeCalled(); - // removed correct listener from correct signal on stop. - expect((global.window.removeEventListener as jest.Mock).mock.calls).toEqual([[UNLOAD_DOM_EVENT, listener.flushData]]); + // pre-check and call stop + expect(global.window.removeEventListener).not.toBeCalled(); + listener.stop(); - done(); - }, 0); + // removed correct listener from correct signal on stop. + expect((global.window.removeEventListener as jest.Mock).mock.calls).toEqual([[UNLOAD_DOM_EVENT, listener.flushData]]); }); -test('Browser JS listener / Impressions debug mode without sendBeacon API', (done) => { +test('Browser JS listener / Impressions debug mode without sendBeacon API', () => { // remove sendBeacon API const sendBeacon = global.navigator.sendBeacon; // @ts-expect-error global.navigator.sendBeacon = undefined; + const syncManagerMockWithoutPushManager = {}; - const listener = new BrowserSignalListener(undefined, fullSettings, fakeStorageDebug as IStorageSync, fakeSplitApi); + // @ts-expect-error + const listener = new BrowserSignalListener(syncManagerMockWithoutPushManager, fullSettings, fakeStorageDebug as IStorageSync, fakeSplitApi); listener.start(); @@ -181,25 +182,21 @@ test('Browser JS listener / Impressions debug mode without sendBeacon API', (don triggerUnloadEvent(); - setTimeout(() => { - // Unload event was triggered. Thus sendBeacon method should have been called twice. - expect(sendBeacon).not.toBeCalled(); - - // Http post services should have not been called - expect(fakeSplitApi.postTestImpressionsBulk).toBeCalledTimes(1); - expect(fakeSplitApi.postEventsBulk).toBeCalledTimes(1); - expect(fakeSplitApi.postTestImpressionsCount).not.toBeCalled(); + // Unload event was triggered. Thus sendBeacon method should have been called twice. + expect(sendBeacon).not.toBeCalled(); - // pre-check and call stop - expect(global.window.removeEventListener).not.toBeCalled(); - listener.stop(); + // Http post services should have not been called + expect(fakeSplitApi.postTestImpressionsBulk).toBeCalledTimes(1); + expect(fakeSplitApi.postEventsBulk).toBeCalledTimes(1); + expect(fakeSplitApi.postTestImpressionsCount).not.toBeCalled(); - // removed correct listener from correct signal on stop. - expect((global.window.removeEventListener as jest.Mock).mock.calls).toEqual([[UNLOAD_DOM_EVENT, listener.flushData]]); + // pre-check and call stop + expect(global.window.removeEventListener).not.toBeCalled(); + listener.stop(); - // restore sendBeacon API - global.navigator.sendBeacon = sendBeacon; + // removed correct listener from correct signal on stop. + expect((global.window.removeEventListener as jest.Mock).mock.calls).toEqual([[UNLOAD_DOM_EVENT, listener.flushData]]); - done(); - }, 0); + // restore sendBeacon API + global.navigator.sendBeacon = sendBeacon; }); diff --git a/src/listeners/__tests__/node.spec.ts b/src/listeners/__tests__/node.spec.ts index cf5794ed..1755fa7d 100644 --- a/src/listeners/__tests__/node.spec.ts +++ b/src/listeners/__tests__/node.spec.ts @@ -7,8 +7,8 @@ const processKillSpy = jest.spyOn(process, 'kill').mockImplementation(() => true test('Node JS listener / Signal Listener class methods and start/stop functionality', () => { - const handlerMock = jest.fn(); - const listener = new NodeSignalListener(handlerMock, fullSettings); + const syncManagerMock = { flush: jest.fn() }; // @ts-expect-error + const listener = new NodeSignalListener(syncManagerMock, fullSettings); listener.start(); @@ -27,8 +27,8 @@ test('Node JS listener / Signal Listener class methods and start/stop functional test('Node JS listener / Signal Listener SIGTERM callback with sync handler', () => { - const handlerMock = jest.fn(); - const listener = new NodeSignalListener(handlerMock, fullSettings); + const syncManagerMock = { flush: jest.fn() }; // @ts-expect-error + const listener = new NodeSignalListener(syncManagerMock, fullSettings); listener.start(); // Stub stop function since we don't want side effects on test. @@ -36,7 +36,7 @@ test('Node JS listener / Signal Listener SIGTERM callback with sync handler', () // Control asserts. expect(listener.stop).not.toBeCalled(); - expect(handlerMock).not.toBeCalled(); + expect(syncManagerMock.flush).not.toBeCalled(); expect(processKillSpy).not.toBeCalled(); // Call function @@ -44,7 +44,7 @@ test('Node JS listener / Signal Listener SIGTERM callback with sync handler', () listener._sigtermHandler(); // Handler was properly called. - expect(handlerMock).toBeCalledTimes(1); + expect(syncManagerMock.flush).toBeCalledTimes(1); // Clean up is called. expect(listener.stop).toBeCalledTimes(1); @@ -56,8 +56,8 @@ test('Node JS listener / Signal Listener SIGTERM callback with sync handler', () }); test('Node JS listener / Signal Listener SIGTERM callback with sync handler that throws an error', () => { - const handlerMock = jest.fn(() => { throw 'some error'; }); - const listener = new NodeSignalListener(handlerMock, fullSettings); + const syncManagerMock = { flush: jest.fn(() => { throw 'some error'; }) }; // @ts-expect-error + const listener = new NodeSignalListener(syncManagerMock, fullSettings); listener.start(); // Stub stop function since we don't want side effects on test. @@ -65,7 +65,7 @@ test('Node JS listener / Signal Listener SIGTERM callback with sync handler that // Control asserts. expect(listener.stop).not.toBeCalled(); - expect(handlerMock).not.toBeCalled(); + expect(syncManagerMock.flush).not.toBeCalled(); expect(processKillSpy).not.toBeCalled(); // Call function. @@ -73,7 +73,7 @@ test('Node JS listener / Signal Listener SIGTERM callback with sync handler that listener._sigtermHandler(); // Handler was properly called. - expect(handlerMock).toBeCalledTimes(1); + expect(syncManagerMock.flush).toBeCalledTimes(1); // Even if the handler throws, clean up is called. expect(listener.stop).toBeCalledTimes(1); @@ -85,16 +85,16 @@ test('Node JS listener / Signal Listener SIGTERM callback with sync handler that processKillSpy.mockClear(); }); -test('Node JS listener / Signal Listener SIGTERM callback with async handler', async (done) => { +test('Node JS listener / Signal Listener SIGTERM callback with async handler', async () => { const fakePromise = new Promise(res => { setTimeout(() => { res(); }, 0); }); - const handlerMock = jest.fn(() => fakePromise); - - const listener = new NodeSignalListener(handlerMock, fullSettings); + const syncManagerMock = { flush: jest.fn(() => fakePromise) }; + // @ts-expect-error + const listener = new NodeSignalListener(syncManagerMock, fullSettings); // Stub stop function since we don't want side effects on test. jest.spyOn(listener, 'stop'); @@ -107,13 +107,13 @@ test('Node JS listener / Signal Listener SIGTERM callback with async handler', a listener._sigtermHandler(); // Handler was properly called. - expect(handlerMock).toBeCalledTimes(1); + expect(syncManagerMock.flush).toBeCalledTimes(1); // Check that the wrap up is waiting for the promise to be resolved. expect(listener.stop).not.toBeCalled(); expect(processKillSpy).not.toBeCalled(); - fakePromise.then(() => { + await fakePromise.then(() => { // Clean up is called even if there is an error. expect(listener.stop).toBeCalledTimes(1); // It called for kill again, so the shutdown keeps going. @@ -122,23 +122,19 @@ test('Node JS listener / Signal Listener SIGTERM callback with async handler', a // Reset the kill spy since it's used on other tests. processKillSpy.mockClear(); - - done(); }); - - return fakePromise; }); -test('Node JS listener / Signal Listener SIGTERM callback with async handler that throws an error', async (done) => { +test('Node JS listener / Signal Listener SIGTERM callback with async handler that throws an error', async () => { const fakePromise = new Promise((res, rej) => { setTimeout(() => { rej(); }, 0); }); - const handlerMock = jest.fn(() => fakePromise); - - const listener = new NodeSignalListener(handlerMock, fullSettings); + const syncManagerMock = { flush: jest.fn(() => fakePromise) }; + // @ts-expect-error + const listener = new NodeSignalListener(syncManagerMock, fullSettings); // Stub stop function since we don't want side effects on test. jest.spyOn(listener, 'stop'); @@ -148,17 +144,17 @@ test('Node JS listener / Signal Listener SIGTERM callback with async handler tha // Call function // @ts-expect-error - const handlerPromise = listener._sigtermHandler(); + const handlerPromise: Promise = listener._sigtermHandler(); // Handler was properly called. - expect(handlerMock).toBeCalledTimes(1); + expect(syncManagerMock.flush).toBeCalledTimes(1); // Check that the wrap up is waiting for the promise to be resolved. expect(listener.stop).not.toBeCalled(); expect(processKillSpy).not.toBeCalled(); // Calling .then since the wrapUp handler does not throw. - (handlerPromise as Promise).then(() => { + await handlerPromise.then(() => { // Clean up is called. expect(listener.stop).toBeCalledTimes(1); // It called for kill again, so the shutdown keeps going. @@ -169,9 +165,5 @@ test('Node JS listener / Signal Listener SIGTERM callback with async handler tha processOnSpy.mockRestore(); processRemoveListenerSpy.mockRestore(); processKillSpy.mockRestore(); - - done(); }); - - return handlerPromise; }); diff --git a/src/listeners/browser.ts b/src/listeners/browser.ts index d937448e..c5c4fdfd 100644 --- a/src/listeners/browser.ts +++ b/src/listeners/browser.ts @@ -1,16 +1,16 @@ /* eslint-disable no-undef */ // @TODO eventually migrate to JS-Browser-SDK package. import { ISignalListener } from './types'; -import { IRecorderCacheConsumerSync, IStorageSync } from '../storages/types'; +import { IRecorderCacheProducerSync, IStorageSync } from '../storages/types'; import { fromImpressionsCollector } from '../sync/submitters/impressionsSyncTask'; import { fromImpressionCountsCollector } from '../sync/submitters/impressionCountsSyncTask'; -import { ISplitApi } from '../services/types'; +import { IResponse, ISplitApi } from '../services/types'; import { ImpressionDTO, ISettings } from '../types'; import { ImpressionsPayload } from '../sync/submitters/types'; -import { MaybeThenable } from '../dtos/types'; import { OPTIMIZED, DEBUG } from '../utils/constants'; import objectAssign from 'object-assign'; import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants'; +import { ISyncManager } from '../sync/types'; // 'unload' event is used instead of 'beforeunload', since 'unload' is not a cancelable event, so no other listeners can stop the event from occurring. const UNLOAD_DOM_EVENT = 'unload'; @@ -24,7 +24,7 @@ export default class BrowserSignalListener implements ISignalListener { private fromImpressionsCollector: (data: ImpressionDTO[]) => ImpressionsPayload; constructor( - handler: (() => MaybeThenable) | undefined, // Not used, but passed by sdkFactory for NodeSignalListener + private syncManager: ISyncManager | undefined, private settings: ISettings, private storage: IStorageSync, private serviceApi: ISplitApi, @@ -72,9 +72,12 @@ export default class BrowserSignalListener implements ISignalListener { this._flushData(eventsUrl + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata); this._flushData(eventsUrl + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk); if (this.storage.impressionCounts) this._flushData(eventsUrl + '/testImpressions/count/beacon', this.storage.impressionCounts, this.serviceApi.postTestImpressionsCount, fromImpressionCountsCollector); + + // Close streaming connection + if (this.syncManager && this.syncManager.pushManager) this.syncManager.pushManager.stop(); } - private _flushData(url: string, cache: IRecorderCacheConsumerSync, postService: (body: string) => Promise, fromCacheToPayload?: (cacheData: TState) => any, extraMetadata?: {}) { + private _flushData(url: string, cache: IRecorderCacheProducerSync, postService: (body: string) => Promise, fromCacheToPayload?: (cacheData: TState) => any, extraMetadata?: {}) { // if there is data in cache, send it to backend if (!cache.isEmpty()) { const dataPayload = fromCacheToPayload ? fromCacheToPayload(cache.state()) : cache.state(); diff --git a/src/listeners/node.ts b/src/listeners/node.ts index 18b01519..9d8a22e9 100644 --- a/src/listeners/node.ts +++ b/src/listeners/node.ts @@ -3,7 +3,8 @@ import { ISignalListener } from './types'; import thenable from '../utils/promise/thenable'; import { MaybeThenable } from '../dtos/types'; import { ISettings } from '../types'; -import { logPrefixCleanup, CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants'; +import { LOG_PREFIX_CLEANUP, CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants'; +import { ISyncManager } from '../sync/types'; const SIGTERM = 'SIGTERM'; const EVENT_NAME = 'for SIGTERM signal.'; @@ -17,10 +18,21 @@ const EVENT_NAME = 'for SIGTERM signal.'; */ export default class NodeSignalListener implements ISignalListener { + private handler: () => MaybeThenable; + private settings: ISettings; + constructor( - private handler: () => MaybeThenable, - private settings: ISettings + syncManager: ISyncManager | undefined, // private handler: () => MaybeThenable, + settings: ISettings ) { + // @TODO review handler logic when implementing Node SDK + this.handler = function () { + if (syncManager) { + // syncManager.stop(); + return syncManager.flush(); + } + }; + this.settings = settings; this._sigtermHandler = this._sigtermHandler.bind(this); } @@ -49,14 +61,14 @@ export default class NodeSignalListener implements ISignalListener { process.kill(process.pid, SIGTERM); }; - this.settings.log.debug(logPrefixCleanup + 'Split SDK graceful shutdown after SIGTERM.'); + this.settings.log.debug(`${LOG_PREFIX_CLEANUP}Split SDK graceful shutdown after SIGTERM.`); let handlerResult = null; try { handlerResult = this.handler(); } catch (err) { - this.settings.log.error(logPrefixCleanup + `Error with Split SDK graceful shutdown: ${err}`); + this.settings.log.error(`${LOG_PREFIX_CLEANUP}Error with Split SDK graceful shutdown: ${err}`); } if (thenable(handlerResult)) { diff --git a/src/logger/constants.ts b/src/logger/constants.ts index 46cac217..5ca7317c 100644 --- a/src/logger/constants.ts +++ b/src/logger/constants.ts @@ -93,6 +93,7 @@ export const WARN_SPLITS_FILTER_INVALID = 220; export const WARN_SPLITS_FILTER_EMPTY = 221; export const WARN_STORAGE_INVALID = 222; export const WARN_API_KEY = 223; +export const STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2 = 224; export const ERROR_ENGINE_COMBINER_IFELSEIF = 300; export const ERROR_LOGLEVEL_INVALID = 301; @@ -117,23 +118,24 @@ export const ERROR_EMPTY = 319; export const ERROR_EMPTY_ARRAY = 320; export const ERROR_INVALID_IMPRESSIONS_MODE = 321; export const ERROR_HTTP = 322; +export const ERROR_LOCALHOST_MODULE_REQUIRED = 323; // Log prefixes (a.k.a. tags or categories) -export const logPrefixSettings = 'settings'; -export const logPrefixInstantiation = 'Factory instantiation'; -export const logPrefixEngine = 'engine'; -export const logPrefixEngineCombiner = logPrefixEngine + ':combiner: '; -export const logPrefixEngineMatcher = logPrefixEngine + ':matcher: '; -export const logPrefixEngineValue = logPrefixEngine + ':value: '; -export const logPrefixSync = 'sync'; -export const logPrefixSyncManager = logPrefixSync + ':sync-manager: '; -export const logPrefixSyncOffline = logPrefixSync + ':offline: '; -export const logPrefixSyncStreaming = logPrefixSync + ':streaming: '; -export const logPrefixSyncSplits = logPrefixSync + ':split-changes: '; -export const logPrefixSyncSegments = logPrefixSync + ':segment-changes: '; -export const logPrefixSyncMysegments = logPrefixSync + ':my-segments: '; -export const logPrefixSyncPolling = logPrefixSync + ':polling-manager: '; -export const logPrefixSyncSubmitters = logPrefixSync + ':submitter: '; -export const logPrefixImpressionsTracker = 'impressions-tracker: '; -export const logPrefixEventsTracker = 'events-tracker: '; -export const logPrefixCleanup = 'cleanup: '; +export const LOG_PREFIX_SETTINGS = 'settings'; +export const LOG_PREFIX_INSTANTIATION = 'Factory instantiation'; +export const LOG_PREFIX_ENGINE = 'engine'; +export const LOG_PREFIX_ENGINE_COMBINER = LOG_PREFIX_ENGINE + ':combiner: '; +export const LOG_PREFIX_ENGINE_MATCHER = LOG_PREFIX_ENGINE + ':matcher: '; +export const LOG_PREFIX_ENGINE_VALUE = LOG_PREFIX_ENGINE + ':value: '; +export const LOG_PREFIX_SYNC = 'sync'; +export const LOG_PREFIX_SYNC_MANAGER = LOG_PREFIX_SYNC + ':sync-manager: '; +export const LOG_PREFIX_SYNC_OFFLINE = LOG_PREFIX_SYNC + ':offline: '; +export const LOG_PREFIX_SYNC_STREAMING = LOG_PREFIX_SYNC + ':streaming: '; +export const LOG_PREFIX_SYNC_SPLITS = LOG_PREFIX_SYNC + ':split-changes: '; +export const LOG_PREFIX_SYNC_SEGMENTS = LOG_PREFIX_SYNC + ':segment-changes: '; +export const LOG_PREFIX_SYNC_MYSEGMENTS = LOG_PREFIX_SYNC + ':my-segments: '; +export const LOG_PREFIX_SYNC_POLLING = LOG_PREFIX_SYNC + ':polling-manager: '; +export const LOG_PREFIX_SYNC_SUBMITTERS = LOG_PREFIX_SYNC + ':submitter: '; +export const LOG_PREFIX_IMPRESSIONS_TRACKER = 'impressions-tracker: '; +export const LOG_PREFIX_EVENTS_TRACKER = 'events-tracker: '; +export const LOG_PREFIX_CLEANUP = 'cleanup: '; diff --git a/src/logger/index.ts b/src/logger/index.ts index 4738e191..ed2e5032 100644 --- a/src/logger/index.ts +++ b/src/logger/index.ts @@ -12,7 +12,7 @@ export const LogLevels: { [level: string]: LogLevel } = { NONE: 'NONE' }; -const LogLevelRanks = { +const LogLevelIndexes = { DEBUG: 1, INFO: 2, WARN: 3, @@ -47,28 +47,28 @@ export class Logger implements ILogger { constructor(options?: ILoggerOptions, codes?: IMap) { this.options = objectAssign({}, defaultOptions, options); this.codes = codes || new _Map(); - this.logLevel = LogLevelRanks[this.options.logLevel]; + this.logLevel = LogLevelIndexes[this.options.logLevel]; } setLogLevel(logLevel: LogLevel) { this.options.logLevel = logLevel; - this.logLevel = LogLevelRanks[logLevel]; + this.logLevel = LogLevelIndexes[logLevel]; } debug(msg: string | number, args?: any[]) { - if (this._shouldLog(LogLevelRanks.DEBUG)) this._log(LogLevels.DEBUG, msg, args); + if (this._shouldLog(LogLevelIndexes.DEBUG)) this._log(LogLevels.DEBUG, msg, args); } info(msg: string | number, args?: any[]) { - if (this._shouldLog(LogLevelRanks.INFO)) this._log(LogLevels.INFO, msg, args); + if (this._shouldLog(LogLevelIndexes.INFO)) this._log(LogLevels.INFO, msg, args); } warn(msg: string | number, args?: any[]) { - if (this._shouldLog(LogLevelRanks.WARN)) this._log(LogLevels.WARN, msg, args); + if (this._shouldLog(LogLevelIndexes.WARN)) this._log(LogLevels.WARN, msg, args); } error(msg: string | number, args?: any[]) { - if (this._shouldLog(LogLevelRanks.ERROR)) this._log(LogLevels.ERROR, msg, args); + if (this._shouldLog(LogLevelIndexes.ERROR)) this._log(LogLevels.ERROR, msg, args); } private _log(level: LogLevel, msg: string | number, args?: any[]) { diff --git a/src/logger/messages/debug.ts b/src/logger/messages/debug.ts index 4f1444bc..ed8281ed 100644 --- a/src/logger/messages/debug.ts +++ b/src/logger/messages/debug.ts @@ -3,47 +3,47 @@ import { codesInfo } from './info'; export const codesDebug: [number, string][] = codesInfo.concat([ // evaluator - [c.ENGINE_COMBINER_AND, c.logPrefixEngineCombiner + '[andCombiner] evaluates to %s'], - [c.ENGINE_COMBINER_IFELSEIF, c.logPrefixEngineCombiner + 'Treatment found: %s'], - [c.ENGINE_COMBINER_IFELSEIF_NO_TREATMENT, c.logPrefixEngineCombiner + 'All predicates evaluated, no treatment found.'], - [c.ENGINE_BUCKET, c.logPrefixEngine + ': using algo "murmur" bucket %s for key %s using seed %s - treatment %s'], - [c.ENGINE_MATCHER_ALL, c.logPrefixEngineMatcher + '[allMatcher] is always true'], - [c.ENGINE_MATCHER_BETWEEN, c.logPrefixEngineMatcher + '[betweenMatcher] is %s between %s and %s? %s'], - [c.ENGINE_MATCHER_BOOLEAN, c.logPrefixEngineMatcher + '[booleanMatcher] %s === %s'], - [c.ENGINE_MATCHER_CONTAINS_ALL, c.logPrefixEngineMatcher + '[containsAllMatcher] %s contains all elements of %s? %s'], - [c.ENGINE_MATCHER_CONTAINS_ANY, c.logPrefixEngineMatcher + '[containsAnyMatcher] %s contains at least an element of %s? %s'], - [c.ENGINE_MATCHER_CONTAINS_STRING, c.logPrefixEngineMatcher + '[containsStringMatcher] %s contains %s? %s'], - [c.ENGINE_MATCHER_DEPENDENCY, c.logPrefixEngineMatcher + '[dependencyMatcher] parent split "%s" evaluated to "%s" with label "%s". %s evaluated treatment is part of [%s] ? %s.'], - [c.ENGINE_MATCHER_DEPENDENCY_PRE, c.logPrefixEngineMatcher + '[dependencyMatcher] will evaluate parent split: "%s" with key: %s %s'], - [c.ENGINE_MATCHER_EQUAL, c.logPrefixEngineMatcher + '[equalToMatcher] is %s equal to %s? %s'], - [c.ENGINE_MATCHER_EQUAL_TO_SET, c.logPrefixEngineMatcher + '[equalToSetMatcher] is %s equal to set %s? %s'], - [c.ENGINE_MATCHER_ENDS_WITH, c.logPrefixEngineMatcher + '[endsWithMatcher] %s ends with %s? %s'], - [c.ENGINE_MATCHER_GREATER, c.logPrefixEngineMatcher + '[greaterThanEqualMatcher] is %s greater than %s? %s'], - [c.ENGINE_MATCHER_LESS, c.logPrefixEngineMatcher + '[lessThanEqualMatcher] is %s less than %s? %s'], - [c.ENGINE_MATCHER_PART_OF, c.logPrefixEngineMatcher + '[partOfMatcher] %s is part of %s? %s'], - [c.ENGINE_MATCHER_SEGMENT, c.logPrefixEngineMatcher + '[segmentMatcher] evaluated %s / %s => %s'], - [c.ENGINE_MATCHER_STRING, c.logPrefixEngineMatcher + '[stringMatcher] does %s matches with %s? %s'], - [c.ENGINE_MATCHER_STRING_INVALID, c.logPrefixEngineMatcher + '[stringMatcher] %s is an invalid regex'], - [c.ENGINE_MATCHER_STARTS_WITH, c.logPrefixEngineMatcher + '[startsWithMatcher] %s starts with %s? %s'], - [c.ENGINE_MATCHER_WHITELIST, c.logPrefixEngineMatcher + '[whitelistMatcher] evaluated %s in [%s] => %s'], - [c.ENGINE_VALUE, c.logPrefixEngineValue + 'Extracted attribute [%s], [%s] will be used for matching.'], - [c.ENGINE_SANITIZE, c.logPrefixEngine + ':sanitize: Attempted to sanitize [%s] which should be of type [%s]. Sanitized and processed value => [%s]'], + [c.ENGINE_COMBINER_AND, c.LOG_PREFIX_ENGINE_COMBINER + '[andCombiner] evaluates to %s'], + [c.ENGINE_COMBINER_IFELSEIF, c.LOG_PREFIX_ENGINE_COMBINER + 'Treatment found: %s'], + [c.ENGINE_COMBINER_IFELSEIF_NO_TREATMENT, c.LOG_PREFIX_ENGINE_COMBINER + 'All predicates evaluated, no treatment found.'], + [c.ENGINE_BUCKET, c.LOG_PREFIX_ENGINE + ': using algo "murmur" bucket %s for key %s using seed %s - treatment %s'], + [c.ENGINE_MATCHER_ALL, c.LOG_PREFIX_ENGINE_MATCHER + '[allMatcher] is always true'], + [c.ENGINE_MATCHER_BETWEEN, c.LOG_PREFIX_ENGINE_MATCHER + '[betweenMatcher] is %s between %s and %s? %s'], + [c.ENGINE_MATCHER_BOOLEAN, c.LOG_PREFIX_ENGINE_MATCHER + '[booleanMatcher] %s === %s'], + [c.ENGINE_MATCHER_CONTAINS_ALL, c.LOG_PREFIX_ENGINE_MATCHER + '[containsAllMatcher] %s contains all elements of %s? %s'], + [c.ENGINE_MATCHER_CONTAINS_ANY, c.LOG_PREFIX_ENGINE_MATCHER + '[containsAnyMatcher] %s contains at least an element of %s? %s'], + [c.ENGINE_MATCHER_CONTAINS_STRING, c.LOG_PREFIX_ENGINE_MATCHER + '[containsStringMatcher] %s contains %s? %s'], + [c.ENGINE_MATCHER_DEPENDENCY, c.LOG_PREFIX_ENGINE_MATCHER + '[dependencyMatcher] parent split "%s" evaluated to "%s" with label "%s". %s evaluated treatment is part of [%s] ? %s.'], + [c.ENGINE_MATCHER_DEPENDENCY_PRE, c.LOG_PREFIX_ENGINE_MATCHER + '[dependencyMatcher] will evaluate parent split: "%s" with key: %s %s'], + [c.ENGINE_MATCHER_EQUAL, c.LOG_PREFIX_ENGINE_MATCHER + '[equalToMatcher] is %s equal to %s? %s'], + [c.ENGINE_MATCHER_EQUAL_TO_SET, c.LOG_PREFIX_ENGINE_MATCHER + '[equalToSetMatcher] is %s equal to set %s? %s'], + [c.ENGINE_MATCHER_ENDS_WITH, c.LOG_PREFIX_ENGINE_MATCHER + '[endsWithMatcher] %s ends with %s? %s'], + [c.ENGINE_MATCHER_GREATER, c.LOG_PREFIX_ENGINE_MATCHER + '[greaterThanEqualMatcher] is %s greater than %s? %s'], + [c.ENGINE_MATCHER_LESS, c.LOG_PREFIX_ENGINE_MATCHER + '[lessThanEqualMatcher] is %s less than %s? %s'], + [c.ENGINE_MATCHER_PART_OF, c.LOG_PREFIX_ENGINE_MATCHER + '[partOfMatcher] %s is part of %s? %s'], + [c.ENGINE_MATCHER_SEGMENT, c.LOG_PREFIX_ENGINE_MATCHER + '[segmentMatcher] evaluated %s / %s => %s'], + [c.ENGINE_MATCHER_STRING, c.LOG_PREFIX_ENGINE_MATCHER + '[stringMatcher] does %s matches with %s? %s'], + [c.ENGINE_MATCHER_STRING_INVALID, c.LOG_PREFIX_ENGINE_MATCHER + '[stringMatcher] %s is an invalid regex'], + [c.ENGINE_MATCHER_STARTS_WITH, c.LOG_PREFIX_ENGINE_MATCHER + '[startsWithMatcher] %s starts with %s? %s'], + [c.ENGINE_MATCHER_WHITELIST, c.LOG_PREFIX_ENGINE_MATCHER + '[whitelistMatcher] evaluated %s in [%s] => %s'], + [c.ENGINE_VALUE, c.LOG_PREFIX_ENGINE_VALUE + 'Extracted attribute [%s], [%s] will be used for matching.'], + [c.ENGINE_SANITIZE, c.LOG_PREFIX_ENGINE + ':sanitize: Attempted to sanitize [%s] which should be of type [%s]. Sanitized and processed value => [%s]'], // SDK - [c.CLEANUP_REGISTERING, c.logPrefixCleanup + 'Registering cleanup handler %s'], - [c.CLEANUP_DEREGISTERING, c.logPrefixCleanup + 'Deregistering cleanup handler %s'], + [c.CLEANUP_REGISTERING, c.LOG_PREFIX_CLEANUP + 'Registering cleanup handler %s'], + [c.CLEANUP_DEREGISTERING, c.LOG_PREFIX_CLEANUP + 'Deregistering cleanup handler %s'], [c.RETRIEVE_CLIENT_DEFAULT, ' Retrieving default SDK client.'], [c.RETRIEVE_CLIENT_EXISTING, ' Retrieving existing SDK client.'], [c.RETRIEVE_MANAGER, ' Retrieving manager instance.'], // synchronizer - [c.SYNC_OFFLINE_DATA, c.logPrefixSyncOffline + 'Splits data: \n%s'], - [c.SYNC_SPLITS_FETCH, c.logPrefixSyncSplits + 'Spin up split update using since = %s'], - [c.SYNC_SPLITS_NEW, c.logPrefixSyncSplits + 'New splits %s'], - [c.SYNC_SPLITS_REMOVED, c.logPrefixSyncSplits + 'Removed splits %s'], - [c.SYNC_SPLITS_SEGMENTS, c.logPrefixSyncSplits + 'Segment names collected %s'], - [c.STREAMING_NEW_MESSAGE, c.logPrefixSyncStreaming + 'New SSE message received, with data: %s.'], - [c.SYNC_TASK_START, c.logPrefixSync + ': Starting %s. Running each %s millis'], - [c.SYNC_TASK_EXECUTE, c.logPrefixSync + ': Running %s'], - [c.SYNC_TASK_STOP, c.logPrefixSync + ': Stopping %s'], + [c.SYNC_OFFLINE_DATA, c.LOG_PREFIX_SYNC_OFFLINE + 'Splits data: \n%s'], + [c.SYNC_SPLITS_FETCH, c.LOG_PREFIX_SYNC_SPLITS + 'Spin up split update using since = %s'], + [c.SYNC_SPLITS_NEW, c.LOG_PREFIX_SYNC_SPLITS + 'New splits %s'], + [c.SYNC_SPLITS_REMOVED, c.LOG_PREFIX_SYNC_SPLITS + 'Removed splits %s'], + [c.SYNC_SPLITS_SEGMENTS, c.LOG_PREFIX_SYNC_SPLITS + 'Segment names collected %s'], + [c.STREAMING_NEW_MESSAGE, c.LOG_PREFIX_SYNC_STREAMING + 'New SSE message received, with data: %s.'], + [c.SYNC_TASK_START, c.LOG_PREFIX_SYNC + ': Starting %s. Running each %s millis'], + [c.SYNC_TASK_EXECUTE, c.LOG_PREFIX_SYNC + ': Running %s'], + [c.SYNC_TASK_STOP, c.LOG_PREFIX_SYNC + ': Stopping %s'], // initialization / settings validation - [c.SETTINGS_SPLITS_FILTER, c.logPrefixSettings + ': splits filtering criteria is "%s".'] + [c.SETTINGS_SPLITS_FILTER, c.LOG_PREFIX_SETTINGS + ': splits filtering criteria is "%s".'] ]); diff --git a/src/logger/messages/error.ts b/src/logger/messages/error.ts index 0eea8c02..75269bc9 100644 --- a/src/logger/messages/error.ts +++ b/src/logger/messages/error.ts @@ -2,17 +2,17 @@ import * as c from '../constants'; export const codesError: [number, string][] = [ // evaluator - [c.ERROR_ENGINE_COMBINER_IFELSEIF, c.logPrefixEngineCombiner + 'Invalid Split, no valid rules found'], + [c.ERROR_ENGINE_COMBINER_IFELSEIF, c.LOG_PREFIX_ENGINE_COMBINER + 'Invalid Split, no valid rules found'], // SDK [c.ERROR_LOGLEVEL_INVALID, 'logger: Invalid Log Level - No changes to the logs will be applied.'], [c.ERROR_CLIENT_CANNOT_GET_READY, ' The SDK will not get ready. Reason: %s'], - [c.ERROR_IMPRESSIONS_TRACKER, c.logPrefixImpressionsTracker + 'Could not store impressions bulk with %s impression(s). Error: %s'], - [c.ERROR_IMPRESSIONS_LISTENER, c.logPrefixImpressionsTracker + 'Impression listener logImpression method threw: %s.'], - [c.ERROR_EVENTS_TRACKER, c.logPrefixEventsTracker + 'Failed to queue %s'], + [c.ERROR_IMPRESSIONS_TRACKER, c.LOG_PREFIX_IMPRESSIONS_TRACKER + 'Could not store impressions bulk with %s impression(s). Error: %s'], + [c.ERROR_IMPRESSIONS_LISTENER, c.LOG_PREFIX_IMPRESSIONS_TRACKER + 'Impression listener logImpression method threw: %s.'], + [c.ERROR_EVENTS_TRACKER, c.LOG_PREFIX_EVENTS_TRACKER + 'Failed to queue %s'], // synchronizer - [c.ERROR_SYNC_OFFLINE_LOADING, c.logPrefixSyncOffline + 'There was an issue loading the mock Splits data, no changes will be applied to the current cache. %s'], - [c.ERROR_STREAMING_SSE, c.logPrefixSyncStreaming + 'Fail to connect to streaming, with error message: %s'], - [c.ERROR_STREAMING_AUTH, c.logPrefixSyncStreaming + 'Failed to authenticate for streaming. Error: "%s".'], + [c.ERROR_SYNC_OFFLINE_LOADING, c.LOG_PREFIX_SYNC_OFFLINE + 'There was an issue loading the mock Splits data, no changes will be applied to the current cache. %s'], + [c.ERROR_STREAMING_SSE, c.LOG_PREFIX_SYNC_STREAMING + 'Failed to connect or error on streaming connection, with error message: %s'], + [c.ERROR_STREAMING_AUTH, c.LOG_PREFIX_SYNC_STREAMING + 'Failed to authenticate for streaming. Error: %s.'], [c.ERROR_HTTP, ' Response status is not OK. Status: %s. URL: %s. Message: %s'], // client status [c.ERROR_CLIENT_LISTENER, 'A listener was added for %s on the SDK, which has already fired and won\'t be emitted again. The callback won\'t be executed.'], @@ -29,5 +29,6 @@ export const codesError: [number, string][] = [ [c.ERROR_EMPTY, '%s: you passed an empty %s. It must be a non-empty string.'], [c.ERROR_EMPTY_ARRAY, '%s: %s must be a non-empty array.'], // initialization / settings validation - [c.ERROR_INVALID_IMPRESSIONS_MODE, c.logPrefixSettings + ': you passed an invalid "impressionsMode". It should be one of the following values: %s. Defaulting to "%s" mode.'], + [c.ERROR_INVALID_IMPRESSIONS_MODE, c.LOG_PREFIX_SETTINGS + ': you passed an invalid "impressionsMode". It should be one of the following values: %s. Defaulting to "%s" mode.'], + [c.ERROR_LOCALHOST_MODULE_REQUIRED, c.LOG_PREFIX_SETTINGS + ': an invalid value was received for "sync.localhostMode" config. A valid entity should be provided for localhost mode.'] ]; diff --git a/src/logger/messages/info.ts b/src/logger/messages/info.ts index 2877a9d8..22083bf6 100644 --- a/src/logger/messages/info.ts +++ b/src/logger/messages/info.ts @@ -8,26 +8,26 @@ export const codesInfo: [number, string][] = codesWarn.concat([ [c.CLIENT_READY_FROM_CACHE, READY_MSG + ' from cache'], [c.CLIENT_READY, READY_MSG], // SDK - [c.IMPRESSION, c.logPrefixImpressionsTracker +'Split: %s. Key: %s. Evaluation: %s. Label: %s'], - [c.IMPRESSION_QUEUEING, c.logPrefixImpressionsTracker +'Queueing corresponding impression.'], + [c.IMPRESSION, c.LOG_PREFIX_IMPRESSIONS_TRACKER +'Split: %s. Key: %s. Evaluation: %s. Label: %s'], + [c.IMPRESSION_QUEUEING, c.LOG_PREFIX_IMPRESSIONS_TRACKER +'Queueing corresponding impression.'], [c.NEW_SHARED_CLIENT, ' New shared client instance created.'], [c.NEW_FACTORY, ' New Split SDK instance created.'], - [c.EVENTS_TRACKER_SUCCESS, c.logPrefixEventsTracker + 'Successfully qeued %s'], - [c.IMPRESSIONS_TRACKER_SUCCESS, c.logPrefixImpressionsTracker + 'Successfully stored %s impression(s).'], + [c.EVENTS_TRACKER_SUCCESS, c.LOG_PREFIX_EVENTS_TRACKER + 'Successfully queued %s'], + [c.IMPRESSIONS_TRACKER_SUCCESS, c.LOG_PREFIX_IMPRESSIONS_TRACKER + 'Successfully stored %s impression(s).'], // synchronizer - [c.POLLING_SMART_PAUSING, c.logPrefixSyncPolling + 'Turning segments data polling %s.'], - [c.POLLING_START, c.logPrefixSyncPolling + 'Starting polling'], - [c.POLLING_STOP, c.logPrefixSyncPolling + 'Stopping polling'], - [c.SYNC_SPLITS_FETCH_RETRY, c.logPrefixSyncSplits + 'Retrying download of splits #%s. Reason: %s'], - [c.SUBMITTERS_PUSH_FULL_EVENTS_QUEUE, c.logPrefixSyncSubmitters + 'Flushing full events queue and reseting timer.'], - [c.SUBMITTERS_PUSH, c.logPrefixSyncSubmitters + 'Pushing %s %s.'], - [c.STREAMING_REFRESH_TOKEN, c.logPrefixSyncStreaming + 'Refreshing streaming token in %s seconds.'], - [c.STREAMING_RECONNECT, c.logPrefixSyncStreaming + 'Attempting to reconnect in %s seconds.'], - [c.STREAMING_CONNECTING, c.logPrefixSyncStreaming + 'Connecting to streaming.'], - [c.STREAMING_DISABLED, c.logPrefixSyncStreaming + 'Streaming is disabled for given Api key. Switching to polling mode.'], - [c.STREAMING_DISCONNECTING, c.logPrefixSyncStreaming + 'Disconnecting from streaming.'], - [c.SYNC_START_POLLING, c.logPrefixSyncManager + 'Streaming not available. Starting polling.'], - [c.SYNC_CONTINUE_POLLING, c.logPrefixSyncManager + 'Streaming couldn\'t connect. Continue polling.'], - [c.SYNC_STOP_POLLING, c.logPrefixSyncManager + 'Streaming (re)connected. Syncing and stopping polling.'], + [c.POLLING_SMART_PAUSING, c.LOG_PREFIX_SYNC_POLLING + 'Turning segments data polling %s.'], + [c.POLLING_START, c.LOG_PREFIX_SYNC_POLLING + 'Starting polling'], + [c.POLLING_STOP, c.LOG_PREFIX_SYNC_POLLING + 'Stopping polling'], + [c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying download of splits #%s. Reason: %s'], + [c.SUBMITTERS_PUSH_FULL_EVENTS_QUEUE, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing full events queue and reseting timer.'], + [c.SUBMITTERS_PUSH, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Pushing %s %s.'], + [c.STREAMING_REFRESH_TOKEN, c.LOG_PREFIX_SYNC_STREAMING + 'Refreshing streaming token in %s seconds, and connecting streaming in %s seconds.'], + [c.STREAMING_RECONNECT, c.LOG_PREFIX_SYNC_STREAMING + 'Attempting to reconnect in %s seconds.'], + [c.STREAMING_CONNECTING, c.LOG_PREFIX_SYNC_STREAMING + '%sConnecting to streaming.'], + [c.STREAMING_DISABLED, c.LOG_PREFIX_SYNC_STREAMING + 'Streaming is disabled for given Api key. Switching to polling mode.'], + [c.STREAMING_DISCONNECTING, c.LOG_PREFIX_SYNC_STREAMING + 'Disconnecting from streaming.'], + [c.SYNC_START_POLLING, c.LOG_PREFIX_SYNC_MANAGER + 'Streaming not available. Starting polling.'], + [c.SYNC_CONTINUE_POLLING, c.LOG_PREFIX_SYNC_MANAGER + 'Streaming couldn\'t connect. Continue polling.'], + [c.SYNC_STOP_POLLING, c.LOG_PREFIX_SYNC_MANAGER + 'Streaming (re)connected. Syncing and stopping polling.'], ]); diff --git a/src/logger/messages/warn.ts b/src/logger/messages/warn.ts index e10da2f5..350eeb43 100644 --- a/src/logger/messages/warn.ts +++ b/src/logger/messages/warn.ts @@ -3,16 +3,16 @@ import { codesError } from './error'; export const codesWarn: [number, string][] = codesError.concat([ // evaluator - [c.ENGINE_VALUE_INVALID, c.logPrefixEngineValue + 'Value %s doesn\'t match with expected type.'], - [c.ENGINE_VALUE_NO_ATTRIBUTES, c.logPrefixEngineValue + 'Defined attribute [%s], no attributes received.'], + [c.ENGINE_VALUE_INVALID, c.LOG_PREFIX_ENGINE_VALUE + 'Value %s doesn\'t match with expected type.'], + [c.ENGINE_VALUE_NO_ATTRIBUTES, c.LOG_PREFIX_ENGINE_VALUE + 'Defined attribute [%s], no attributes received.'], // synchronizer - [c.SYNC_MYSEGMENTS_FETCH_RETRY, c.logPrefixSyncMysegments + 'Retrying download of segments #%s. Reason: %s'], - [c.SYNC_SPLITS_FETCH_FAILS, c.logPrefixSyncSplits + 'Error while doing fetch of Splits. %s'], - [c.STREAMING_PARSING_ERROR_FAILS, c.logPrefixSyncStreaming + 'Error parsing SSE error notification: %s'], - [c.STREAMING_PARSING_MESSAGE_FAILS, c.logPrefixSyncStreaming + 'Error parsing SSE message notification: %s'], - [c.STREAMING_FALLBACK, c.logPrefixSyncStreaming + 'Falling back to polling mode. Reason: %s'], - [c.SUBMITTERS_PUSH_FAILS, c.logPrefixSyncSubmitters + 'Droping %s %s after retry. Reason: %s.'], - [c.SUBMITTERS_PUSH_RETRY, c.logPrefixSyncSubmitters + 'Failed to push %s %s, keeping data to retry on next iteration. Reason: %s.'], + [c.SYNC_MYSEGMENTS_FETCH_RETRY, c.LOG_PREFIX_SYNC_MYSEGMENTS + 'Retrying download of segments #%s. Reason: %s'], + [c.SYNC_SPLITS_FETCH_FAILS, c.LOG_PREFIX_SYNC_SPLITS + 'Error while doing fetch of Splits. %s'], + [c.STREAMING_PARSING_ERROR_FAILS, c.LOG_PREFIX_SYNC_STREAMING + 'Error parsing SSE error notification: %s'], + [c.STREAMING_PARSING_MESSAGE_FAILS, c.LOG_PREFIX_SYNC_STREAMING + 'Error parsing SSE message notification: %s'], + [c.STREAMING_FALLBACK, c.LOG_PREFIX_SYNC_STREAMING + 'Falling back to polling mode. Reason: %s'], + [c.SUBMITTERS_PUSH_FAILS, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Droping %s %s after retry. Reason: %s.'], + [c.SUBMITTERS_PUSH_RETRY, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Failed to push %s %s, keeping data to retry on next iteration. Reason: %s.'], // client status [c.CLIENT_NOT_READY, '%s: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method.'], [c.CLIENT_NO_LISTENER, 'No listeners for SDK Readiness detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet ready.'], @@ -25,10 +25,12 @@ export const codesWarn: [number, string][] = codesError.concat([ [c.WARN_LOWERCASE_TRAFFIC_TYPE, '%s: traffic_type_name should be all lowercase - converting string to lowercase.'], [c.WARN_NOT_EXISTENT_TT, '%s: traffic type "%s" does not have any corresponding split in this environment, make sure you\'re tracking your events to a valid traffic type defined in the web console.'], // initialization / settings validation - [c.WARN_INTEGRATION_INVALID, c.logPrefixSettings+': %s integration %s at settings %s invalid. %s'], - [c.WARN_SPLITS_FILTER_IGNORED, c.logPrefixSettings+': split filters have been configured but will have no effect if mode is not "%s", since synchronization is being deferred to an external tool.'], - [c.WARN_SPLITS_FILTER_INVALID, c.logPrefixSettings+': split filter at position %s is invalid. It must be an object with a valid filter type ("byName" or "byPrefix") and a list of "values".'], - [c.WARN_SPLITS_FILTER_EMPTY, c.logPrefixSettings+': splitFilters configuration must be a non-empty array of filter objects.'], - [c.WARN_STORAGE_INVALID, c.logPrefixSettings+': The provided storage is invalid. Fallbacking into default MEMORY storage'], - [c.WARN_API_KEY, c.logPrefixSettings+': You already have %s. We recommend keeping only one instance of the factory at all times (Singleton pattern) and reusing it throughout your application'] + [c.WARN_INTEGRATION_INVALID, c.LOG_PREFIX_SETTINGS+': %s integration item(s) at settings is invalid. %s'], + [c.WARN_SPLITS_FILTER_IGNORED, c.LOG_PREFIX_SETTINGS+': split filters have been configured but will have no effect if mode is not "%s", since synchronization is being deferred to an external tool.'], + [c.WARN_SPLITS_FILTER_INVALID, c.LOG_PREFIX_SETTINGS+': split filter at position %s is invalid. It must be an object with a valid filter type ("byName" or "byPrefix") and a list of "values".'], + [c.WARN_SPLITS_FILTER_EMPTY, c.LOG_PREFIX_SETTINGS+': splitFilters configuration must be a non-empty array of filter objects.'], + [c.WARN_STORAGE_INVALID, c.LOG_PREFIX_SETTINGS+': The provided storage is invalid. Fallbacking into default MEMORY storage'], + [c.WARN_API_KEY, c.LOG_PREFIX_SETTINGS+': You already have %s. We recommend keeping only one instance of the factory at all times (Singleton pattern) and reusing it throughout your application'], + + [c.STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, c.LOG_PREFIX_SYNC_STREAMING + 'Fetching MySegments due to an error processing %s notification: %s'], ]); diff --git a/src/readiness/__tests__/sdkReadinessManager.spec.ts b/src/readiness/__tests__/sdkReadinessManager.spec.ts index 3cc3c765..5bfda13e 100644 --- a/src/readiness/__tests__/sdkReadinessManager.spec.ts +++ b/src/readiness/__tests__/sdkReadinessManager.spec.ts @@ -195,7 +195,7 @@ describe('SDK Readiness Manager - Event emitter', () => { describe('SDK Readiness Manager - Ready promise', () => { - test('.ready() promise behaviour for clients', async (done) => { + test('.ready() promise behaviour for clients', async () => { const sdkReadinessManager = sdkReadinessManagerFactory(loggerMock, EventEmitterMock); const ready = sdkReadinessManager.sdkStatus.ready(); @@ -258,7 +258,6 @@ describe('SDK Readiness Manager - Ready promise', () => { loggerMock.mockClear(); testPassedCount++; expect(testPassedCount).toBe(5); - done(); }, () => { throw new Error('It should be resolved on ready event, not rejected.'); } ); diff --git a/src/readiness/constants.ts b/src/readiness/constants.ts index 90b926de..061bbd67 100644 --- a/src/readiness/constants.ts +++ b/src/readiness/constants.ts @@ -1,9 +1,9 @@ // Splits events: -export const SDK_SPLITS_ARRIVED = 'SDK_SPLITS_ARRIVED'; -export const SDK_SPLITS_CACHE_LOADED = 'SDK_SPLITS_CACHE_LOADED'; +export const SDK_SPLITS_ARRIVED = 'state::splits-arrived'; +export const SDK_SPLITS_CACHE_LOADED = 'state::splits-cache-loaded'; // Segments events: -export const SDK_SEGMENTS_ARRIVED = 'SDK_SEGMENTS_ARRIVED'; +export const SDK_SEGMENTS_ARRIVED = 'state::segments-arrived'; // Readiness events: export const SDK_READY_TIMED_OUT = 'init::timeout'; diff --git a/src/readiness/readinessManager.ts b/src/readiness/readinessManager.ts index 91ab79ff..394ba056 100644 --- a/src/readiness/readinessManager.ts +++ b/src/readiness/readinessManager.ts @@ -41,7 +41,7 @@ export function readinessManagerFactory( // emit SDK_READY_FROM_CACHE let isReadyFromCache = false; - if (splits.splitsCacheLoaded) setTimeout(checkIsReadyFromCache, 0); // don't check status inmediately, to allow attach listeners + if (splits.splitsCacheLoaded) isReadyFromCache = true; // ready from cache, but doesn't emit SDK_READY_FROM_CACHE else splits.once(SDK_SPLITS_CACHE_LOADED, checkIsReadyFromCache); // emit SDK_READY_TIMED_OUT @@ -62,20 +62,36 @@ export function readinessManagerFactory( let isDestroyed = false; function checkIsReadyFromCache() { - if (!isReadyFromCache && splits.splitsCacheLoaded) { - isReadyFromCache = true; - gate.emit(SDK_READY_FROM_CACHE); + isReadyFromCache = true; + // Don't emit SDK_READY_FROM_CACHE if SDK_READY has been emitted + if (!isReady) { + try { + gate.emit(SDK_READY_FROM_CACHE); + } catch (e) { + // throws user callback exceptions in next tick + setTimeout(() => { throw e; }, 0); + } } } function checkIsReadyOrUpdate(diff: any) { if (isReady) { - gate.emit(SDK_UPDATE, diff); + try { + gate.emit(SDK_UPDATE, diff); + } catch (e) { + // throws user callback exceptions in next tick + setTimeout(() => { throw e; }, 0); + } } else { if (splits.splitsArrived && segments.segmentsArrived) { clearTimeout(readyTimeoutId); isReady = true; - gate.emit(SDK_READY); + try { + gate.emit(SDK_READY); + } catch (e) { + // throws user callback exceptions in next tick + setTimeout(() => { throw e; }, 0); + } } } } diff --git a/src/readiness/types.ts b/src/readiness/types.ts index 062daf4e..288a2717 100644 --- a/src/readiness/types.ts +++ b/src/readiness/types.ts @@ -2,8 +2,8 @@ import { IEventEmitter, IStatusInterface } from '../types'; /** Splits data emitter */ -type SDK_SPLITS_ARRIVED = 'SDK_SPLITS_ARRIVED' -type SDK_SPLITS_CACHE_LOADED = 'SDK_SPLITS_CACHE_LOADED' +type SDK_SPLITS_ARRIVED = 'state::splits-arrived' +type SDK_SPLITS_CACHE_LOADED = 'state::splits-cache-loaded' type ISplitsEvent = SDK_SPLITS_ARRIVED | SDK_SPLITS_CACHE_LOADED export interface ISplitsEventEmitter extends IEventEmitter { @@ -16,7 +16,7 @@ export interface ISplitsEventEmitter extends IEventEmitter { /** Segments data emitter */ -type SDK_SEGMENTS_ARRIVED = 'SDK_SEGMENTS_ARRIVED' +type SDK_SEGMENTS_ARRIVED = 'state::segments-arrived' type ISegmentsEvent = SDK_SEGMENTS_ARRIVED export interface ISegmentsEventEmitter extends IEventEmitter { diff --git a/src/sdkClient/client.ts b/src/sdkClient/client.ts index e9f178d8..c6889678 100644 --- a/src/sdkClient/client.ts +++ b/src/sdkClient/client.ts @@ -103,7 +103,7 @@ export default function clientFactory(params: IClientFactoryParams): SplitIO.ICl function track(key: SplitIO.SplitKey, trafficTypeName: string, eventTypeId: string, value?: number, properties?: SplitIO.Properties, size = 1024) { const matchingKey = getMatching(key); const timestamp = Date.now(); - const eventData = { + const eventData: SplitIO.EventData = { eventTypeId, trafficTypeName, value, @@ -115,7 +115,7 @@ export default function clientFactory(params: IClientFactoryParams): SplitIO.ICl // This may be async but we only warn, we don't actually care if it is valid or not in terms of queueing the event. validateTrafficTypeExistance(log, readinessManager, storage.splits, mode, trafficTypeName, 'track'); - return eventTracker.track(eventData as SplitIO.EventData, size); + return eventTracker.track(eventData, size); } return { diff --git a/src/sdkClient/sdkClientMethodCS.ts b/src/sdkClient/sdkClientMethodCS.ts index 80089705..aeb29720 100644 --- a/src/sdkClient/sdkClientMethodCS.ts +++ b/src/sdkClient/sdkClientMethodCS.ts @@ -59,7 +59,7 @@ export function sdkClientMethodCSFactory(params: ISdkClientFactoryParams): (key? const sharedSdkReadiness = sdkReadinessManager.shared(readyTimeout); const sharedStorage = (storage as IStorageSyncCS).shared(matchingKey); - const sharedSyncManager = (syncManager as ISyncManagerCS).shared(matchingKey, sharedSdkReadiness.readinessManager, sharedStorage); + const sharedSyncManager = syncManager && (syncManager as ISyncManagerCS).shared(matchingKey, sharedSdkReadiness.readinessManager, sharedStorage); // As shared clients reuse all the storage information, we don't need to check here if we // will use offline or online mode. We should stick with the original decision. @@ -74,7 +74,7 @@ export function sdkClientMethodCSFactory(params: ISdkClientFactoryParams): (key? validKey ); - sharedSyncManager.start(); + sharedSyncManager && sharedSyncManager.start(); log.info(NEW_SHARED_CLIENT); } else { diff --git a/src/sdkFactory/index.ts b/src/sdkFactory/index.ts index 2fd3e67c..0f89f516 100644 --- a/src/sdkFactory/index.ts +++ b/src/sdkFactory/index.ts @@ -1,9 +1,8 @@ import { ISdkFactoryParams } from './types'; import sdkReadinessManagerFactory from '../readiness/sdkReadinessManager'; -import buildMetadata from '../utils/settingsValidation/buildMetadata'; import impressionsTrackerFactory from '../trackers/impressionsTracker'; import eventTrackerFactory from '../trackers/eventTracker'; -import { IStorageSync } from '../storages/types'; +import { IStorageFactoryParams, IStorageSync } from '../storages/types'; import { SplitIO } from '../types'; import { ISplitApi } from '../services/types'; import { getMatching } from '../utils/key'; @@ -11,6 +10,8 @@ import { shouldBeOptimized } from '../trackers/impressionObserver/utils'; import { validateAndTrackApiKey } from '../utils/inputValidation/apiKey'; import { createLoggerAPI } from '../logger/sdkLogger'; import { NEW_FACTORY, RETRIEVE_MANAGER } from '../logger/constants'; +import { metadataBuilder } from '../storages/metadataBuilder'; +import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../readiness/constants'; /** * Modular SDK factory @@ -26,29 +27,31 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO. // We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle. validateAndTrackApiKey(log, settings.core.authorizationKey); - const metadata = buildMetadata(settings); - // @TODO handle non-recoverable error, such as, `fetch` api not available, invalid API Key, etc. const sdkReadinessManager = sdkReadinessManagerFactory(log, platform.EventEmitter, settings.startup.readyTimeout); + const readinessManager = sdkReadinessManager.readinessManager; - const storageFactoryParams = { + // @TODO consider passing the settings object, so that each storage access only what it needs + const storageFactoryParams: IStorageFactoryParams = { eventsQueueSize: settings.scheduler.eventsQueueSize, - // @TODO consider removing next prop and creating impressionsCounts cache somewhere else to simplify custom storages optimize: shouldBeOptimized(settings), - // @TODO add support for dataloader. consider calling outside the storageFactory to simplify custom storages - dataLoader: undefined, // ATM, only used by InLocalStorage matchingKey: getMatching(settings.core.key), splitFiltersValidation: settings.sync.__splitFiltersValidation, - // ATM, only used by InRedisStorage. @TODO pass a callback to simplify custom storages. - readinessManager: sdkReadinessManager.readinessManager, - metadata, + // Callback used in consumer mode (`syncManagerFactory` is undefined) to emit SDK_READY + onReadyCb: !syncManagerFactory ? (error) => { + if (error) return; // don't emit SDK_READY if storage failed to connect. + readinessManager.splits.emit(SDK_SPLITS_ARRIVED); + readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED); + } : undefined, + metadata: metadataBuilder(settings), log }; const storage = storageFactory(storageFactoryParams); + // @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);` // splitApi is used by SyncManager and Browser signal listener const splitApi = splitApiFactory && splitApiFactory(settings, platform); @@ -65,11 +68,11 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO. // trackers const observer = impressionsObserverFactory && impressionsObserverFactory(); - const impressionsTracker = impressionsTrackerFactory(log, storage.impressions, metadata, impressionListener, integrationsManager, observer, storage.impressionCounts); + const impressionsTracker = impressionsTrackerFactory(log, storage.impressions, settings, impressionListener, integrationsManager, observer, storage.impressionCounts); const eventTracker = eventTrackerFactory(log, storage.events, integrationsManager); // signal listener - const signalListener = SignalListener && new SignalListener(syncManager && syncManager.flush, settings, storage, splitApi); + const signalListener = SignalListener && new SignalListener(syncManager, settings, storage, splitApi); // Sdk client and manager const clientMethod = sdkClientMethodFactory({ eventTracker, impressionsTracker, sdkReadinessManager, settings, storage, syncManager, signalListener }); diff --git a/src/sdkFactory/types.ts b/src/sdkFactory/types.ts index dcd6c0d2..b0d87343 100644 --- a/src/sdkFactory/types.ts +++ b/src/sdkFactory/types.ts @@ -1,4 +1,3 @@ -import { MaybeThenable } from '../dtos/types'; import { IIntegrationManager, IIntegrationFactoryParams } from '../integrations/types'; import { ISignalListener } from '../listeners/types'; import { ILogger } from '../logger/types'; @@ -9,10 +8,10 @@ import { IStorageAsync, IStorageSync, ISplitsCacheSync, ISplitsCacheAsync, IStor import { ISyncManager, ISyncManagerFactoryParams } from '../sync/types'; import { IImpressionObserver } from '../trackers/impressionObserver/types'; import { SplitIO, ISettings, IEventEmitter } from '../types'; -import { ISettingsInternal } from '../utils/settingsValidation/types'; /** - * Environment related dependencies + * Environment related dependencies. + * These getters are called a fixed number of times per factory instantiation. */ export interface IPlatform { getOptions?: () => object @@ -27,7 +26,7 @@ export interface IPlatform { export interface ISdkFactoryParams { // The settings must be already validated - settings: ISettingsInternal, + settings: ISettings, // Platform dependencies platform: IPlatform, @@ -41,7 +40,7 @@ export interface ISdkFactoryParams { splitApiFactory?: (settings: ISettings, platform: IPlatform) => ISplitApi, // SyncManager factory. - // It is not required when providing an asynchronous storage. + // Not required when providing an asynchronous storage (consumer mode), but required in standalone mode to avoid SDK timeout. // It can create an offline or online sync manager, with or without streaming support. syncManagerFactory?: (params: ISyncManagerFactoryParams) => ISyncManager, @@ -56,9 +55,10 @@ export interface ISdkFactoryParams { // It Allows to distinguish SDK clients with the client-side API (`ICsSDK`) or server-side API (`ISDK` or `IAsyncSDK`). sdkClientMethodFactory: (params: ISdkClientFactoryParams) => ({ (): SplitIO.ICsClient; (key: SplitIO.SplitKey, trafficType?: string | undefined): SplitIO.ICsClient; } | (() => SplitIO.IClient) | (() => SplitIO.IAsyncClient)) - // Signal listener constructor. Used to handle special app states, like shutdown, app paused or resumed. + // Optional signal listener constructor. Used to handle special app states, like shutdown, app paused or resumed. + // Pass only if `syncManager` (used by Node listener) and `splitApi` (used by Browser listener) are passed. SignalListener?: new ( - handler: (() => MaybeThenable) | undefined, // Used by NodeSignalListener + syncManager: ISyncManager | undefined, // Used by NodeSignalListener to flush data, and by BrowserSignalListener to close streaming connection. settings: ISettings, // Used by BrowserSignalListener storage: IStorageSync | IStorageAsync, // Used by BrowserSignalListener serviceApi: ISplitApi | undefined) => ISignalListener, // Used by BrowserSignalListener diff --git a/src/sdkManager/__tests__/index.asyncCache.spec.ts b/src/sdkManager/__tests__/index.asyncCache.spec.ts index 46cffb11..9829f9e2 100644 --- a/src/sdkManager/__tests__/index.asyncCache.spec.ts +++ b/src/sdkManager/__tests__/index.asyncCache.spec.ts @@ -3,6 +3,8 @@ import splitObject from './mocks/input.json'; import splitView from './mocks/output.json'; import { sdkManagerFactory } from '../index'; import SplitsCacheInRedis from '../../storages/inRedis/SplitsCacheInRedis'; +import { SplitsCachePluggable } from '../../storages/pluggable/SplitsCachePluggable'; +import { wrapperAdapter } from '../../storages/pluggable/wrapperAdapter'; import KeyBuilderSS from '../../storages/KeyBuilderSS'; import { ISdkReadinessManager } from '../../readiness/types'; import { loggerMock } from '../../logger/__tests__/sdkLogger.mock'; @@ -16,48 +18,72 @@ const sdkReadinessManagerMock = { sdkStatus: jest.fn() } as ISdkReadinessManager; -test('MANAGER API / Async cache (In Redis)', async () => { +// @ts-expect-error +const keys = new KeyBuilderSS(); + +describe('MANAGER API', () => { + + afterEach(() => { loggerMock.mockClear(); }); + + test('Async cache (In Redis)', async () => { + + /** Setup: create manager */ + const connection = new Redis({}); + const cache = new SplitsCacheInRedis(loggerMock, keys, connection); + const manager = sdkManagerFactory(loggerMock, cache, sdkReadinessManagerMock); + await cache.clear(); + await cache.addSplit(splitObject.name, JSON.stringify(splitObject)); + + /** List all splits */ + const views = await manager.splits(); + expect(views[0]).toEqual(splitView); + + /** Read only one split by name */ + + const split = await manager.split(splitObject.name); + expect(split).toEqual(splitView); + + + /** List all the split names */ - /** Setup: create manager */ - const connection = new Redis({}); // @ts-expect-error - const keys = new KeyBuilderSS(); - const cache = new SplitsCacheInRedis(loggerMock, keys, connection); - const manager = sdkManagerFactory(loggerMock, cache, sdkReadinessManagerMock); - await cache.clear(); - await cache.addSplit(splitObject.name, JSON.stringify(splitObject)); + const names = await manager.names(); + expect(names.indexOf(splitObject.name) !== -1).toBe(true); - /** List all splits */ - const views = await manager.splits(); - expect(views[0]).toEqual(splitView); + /** Input Validation */ - /** Read only one split by name */ + // control assertions to verify that the manager is connected with that cache. + expect((await manager.split(splitObject.name)) != null).toBe(true); // control assertion for split. + expect((await manager.splits()).length > 0).toBe(true); // control assertion for splits. + expect((await manager.names()).length > 0).toBe(true); // control assertion for names. - const split = await manager.split(splitObject.name); - expect(split).toEqual(splitView); + // @ts-expect-error + expect(await manager.split(undefined)).toBe(null); // If the split name is invalid, `manager.split(invalidName)` returns null. + // This is kind of tied to the implementation of the isOperational validator. + (sdkReadinessManagerMock.readinessManager.isDestroyed as jest.Mock).mockImplementation(() => true); - /** List all the split names */ + expect(await manager.split(splitObject.name)).toBe(null); // If the factory/client is destroyed, `manager.split(validName)` will return null either way since the storage is not valid. + expect(await manager.splits()).toEqual([]); // If the factory/client is destroyed, `manager.splits()` will return empty array either way since the storage is not valid. + expect(await manager.names()).toEqual([]); // If the factory/client is destroyed, `manager.names()` will return empty array either way since the storage is not valid. - const names = await manager.names(); - expect(names.indexOf(splitObject.name) !== -1).toBe(true); - /** Input Validation */ - // control assertions to verify that the manager is connected with that cache. - expect((await manager.split(splitObject.name)) != null).toBe(true); // control assertion for split. - expect((await manager.splits()).length > 0).toBe(true); // control assertion for splits. - expect((await manager.names()).length > 0).toBe(true); // control assertion for names. + /** Teardown */ + await cache.removeSplit(splitObject.name); + await connection.quit(); + }); - // @ts-expect-error - expect(await manager.split(undefined)).toBe(null); // If the split name is invalid, `manager.split(invalidName)` returns null. + test('Async cache with error', async () => { + // passing an empty object as wrapper, to make method calls of splits cache fail returning a rejected promise. + // @ts-expect-error + const cache = new SplitsCachePluggable(loggerMock, keys, wrapperAdapter(loggerMock, {})); + const manager = sdkManagerFactory(loggerMock, cache, sdkReadinessManagerMock); - // This is kind of tied to the implementation of the isOperational validator. - (sdkReadinessManagerMock.readinessManager.isDestroyed as jest.Mock).mockImplementation(() => true); + expect(await manager.split('some_spplit')).toEqual(null); + expect(await manager.splits()).toEqual([]); + expect(await manager.names()).toEqual([]); - expect(await manager.split(splitObject.name)).toBe(null); // If the factory/client is destroyed, `manager.split(validName)` will return null either way since the storage is not valid. - expect(await manager.splits()).toEqual([]); // If the factory/client is destroyed, `manager.splits()` will return empty array either way since the storage is not valid. - expect(await manager.names()).toEqual([]); // If the factory/client is destroyed, `manager.names()` will return empty array either way since the storage is not valid. + expect(loggerMock.error).toBeCalledTimes(3); // 3 error logs, one for each attempt to call a wrapper method + }); - /** Teardown */ - await connection.quit(); }); diff --git a/src/sdkManager/index.ts b/src/sdkManager/index.ts index a929d082..2536f121 100644 --- a/src/sdkManager/index.ts +++ b/src/sdkManager/index.ts @@ -74,7 +74,7 @@ export function sdkManagerFactory { + return split.catch(() => null).then(result => { // handle possible rejections when using pluggable storage validateSplitExistance(log, readinessManager, splitName, result, SPLIT_FN_LABEL); return objectToView(result); }); @@ -93,8 +93,9 @@ export function sdkManagerFactory []).then(objectsToViews) : // handle possible rejections when using pluggable storage + objectsToViews(currentSplits); }, /** * Get the Split names present on the factory storage @@ -103,7 +104,11 @@ export function sdkManagerFactory []) : // handle possible rejections when using pluggable storage + splitNames; } } ); diff --git a/src/services/__tests__/splitApi.spec.ts b/src/services/__tests__/splitApi.spec.ts index 265f52e3..c014e678 100644 --- a/src/services/__tests__/splitApi.spec.ts +++ b/src/services/__tests__/splitApi.spec.ts @@ -2,12 +2,9 @@ import { splitApiFactory } from '../splitApi'; import { ISettings } from '../../types'; import { settingsSplitApi } from '../../utils/settingsValidation/__tests__/settings.mocks'; -import { SplitError } from '../../utils/lang/errors'; const settingsWithRuntime = { ...settingsSplitApi, runtime: { ip: 'ip', hostname: 'hostname' } } as ISettings; -const fetchMock = jest.fn(() => Promise.resolve({ ok: true })); - function assertHeaders(settings: ISettings, headers: Record) { expect(headers['Accept']).toBe('application/json'); expect(headers['Content-Type']).toBe('application/json'); @@ -22,6 +19,7 @@ describe('splitApi', () => { test.each([settingsSplitApi, settingsWithRuntime])('performs requests with expected headers', (settings) => { + const fetchMock = jest.fn(() => Promise.resolve({ ok: true })); const splitApi = splitApiFactory(settings, { getFetch: () => fetchMock }); splitApi.fetchAuth(); @@ -39,33 +37,63 @@ describe('splitApi', () => { splitApi.postEventsBulk('fake-body'); assertHeaders(settings, fetchMock.mock.calls[4][1].headers); - splitApi.postMetricsCounters('fake-body'); + splitApi.postTestImpressionsBulk('fake-body'); assertHeaders(settings, fetchMock.mock.calls[5][1].headers); + expect(fetchMock.mock.calls[5][1].headers['SplitSDKImpressionsMode']).toBe(settings.sync.impressionsMode); - splitApi.postMetricsTimes('fake-body'); + splitApi.postTestImpressionsCount('fake-body'); assertHeaders(settings, fetchMock.mock.calls[6][1].headers); - splitApi.postTestImpressionsBulk('fake-body'); + // Deprecated + splitApi.postMetricsCounters('fake-body'); assertHeaders(settings, fetchMock.mock.calls[7][1].headers); - expect(fetchMock.mock.calls[7][1].headers['SplitSDKImpressionsMode']).toBe(settings.sync.impressionsMode); - - splitApi.postTestImpressionsCount('fake-body'); + splitApi.postMetricsTimes('fake-body'); assertHeaders(settings, fetchMock.mock.calls[8][1].headers); fetchMock.mockClear(); }); - test('reject requests if fetch Api is not provided', (done) => { + test('rejects requests if fetch Api is not provided', (done) => { const splitApi = splitApiFactory(settingsSplitApi, { getFetch: () => undefined }); // Invoking any Service method, returns a rejected promise with Split error splitApi.fetchAuth().catch(error => { - expect(error).toBeInstanceOf(SplitError); + expect(error).toBeInstanceOf(Error); expect(error.message).toBe('Global fetch API is not available.'); done(); }); }); + test('performs requests with overwritten headers', () => { + const fetchMock = jest.fn(() => Promise.resolve({ ok: true })); + const splitApi = splitApiFactory(settingsWithRuntime, { getFetch: () => fetchMock }); + + const newHeaders = { SplitSDKVersion: 'newVersion', SplitSDKMachineIP: 'newIp', SplitSDKMachineName: 'newHostname' }; + const expectedHeaders = { ...settingsWithRuntime, version: newHeaders.SplitSDKVersion, runtime: { ip: newHeaders.SplitSDKMachineIP, hostname: newHeaders.SplitSDKMachineName } }; + + splitApi.postEventsBulk('fake-body', newHeaders); + assertHeaders(expectedHeaders, fetchMock.mock.calls[0][1].headers); + + splitApi.postTestImpressionsBulk('fake-body', newHeaders); + assertHeaders(expectedHeaders, fetchMock.mock.calls[1][1].headers); + expect(fetchMock.mock.calls[1][1].headers['SplitSDKImpressionsMode']).toBe(settingsWithRuntime.sync.impressionsMode); + }); + + test('performs APIs health service check', (done) => { + const fetchMock = jest.fn(() => Promise.resolve({ ok: true })); + const splitApi = splitApiFactory(settingsWithRuntime, { getFetch: () => fetchMock }); + + splitApi.getSdkAPIHealthCheck().then((res) => { + expect(res).toEqual(true); + }); + expect(fetchMock.mock.calls[0][0]).toMatch('sdk/version'); + + splitApi.getEventsAPIHealthCheck().then((res) => { + expect(res).toEqual(true); + done(); + }); + expect(fetchMock.mock.calls[1][0]).toMatch('events/version'); + }); }); diff --git a/src/services/splitApi.ts b/src/services/splitApi.ts index 9501f297..a080be33 100644 --- a/src/services/splitApi.ts +++ b/src/services/splitApi.ts @@ -1,9 +1,8 @@ import { IPlatform } from '../sdkFactory/types'; -import buildMetadata from '../utils/settingsValidation/buildMetadata'; import { ISettings } from '../types'; import { splitHttpClientFactory } from './splitHttpClient'; import { ISplitApi } from './types'; -import { ISettingsInternal } from '../utils/settingsValidation/types'; +import objectAssign from 'object-assign'; const noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } }; @@ -15,19 +14,28 @@ function userKeyToQueryParam(userKey: string) { * Factory of SplitApi objects, which group the collection of Split HTTP endpoints used by the SDK * * @param settings validated settings object - * @param platform environment-specific dependencies + * @param platform object containing environment-specific `getFetch` and `getOptions` dependencies */ -export function splitApiFactory(settings: ISettings, platform: IPlatform): ISplitApi { +export function splitApiFactory(settings: ISettings, platform: Pick): ISplitApi { const urls = settings.urls; - const filterQueryString = (settings as ISettingsInternal).sync.__splitFiltersValidation && (settings as ISettingsInternal).sync.__splitFiltersValidation.queryString; - const metadata = buildMetadata(settings); + const filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString; const SplitSDKImpressionsMode = settings.sync.impressionsMode; - const splitHttpClient = splitHttpClientFactory(settings.log, settings.core.authorizationKey, metadata, platform.getFetch, platform.getOptions); + const splitHttpClient = splitHttpClientFactory(settings, platform.getFetch, platform.getOptions); return { + getSdkAPIHealthCheck() { + const url = `${urls.sdk}/version`; + return splitHttpClient(url).then(() => true).catch(() => false); + }, + + getEventsAPIHealthCheck() { + const url = `${urls.events}/version`; + return splitHttpClient(url).then(() => true).catch(() => false); + }, + fetchAuth(userMatchingKeys?: string[]) { - let url = `${urls.auth}/auth`; + let url = `${urls.auth}/v2/auth`; if (userMatchingKeys) { // accounting the possibility that `userMatchingKeys` is undefined (server-side API) const queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&'); if (queryParams) // accounting the possibility that `userKeys` and thus `queryParams` are empty @@ -57,22 +65,40 @@ export function splitApiFactory(settings: ISettings, platform: IPlatform): ISpli return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined); }, - postEventsBulk(body: string) { + /** + * Post events. + * + * @param body Events bulk payload + * @param headers Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers. + */ + postEventsBulk(body: string, headers?: Record) { const url = `${urls.events}/events/bulk`; - return splitHttpClient(url, { method: 'POST', body }); + return splitHttpClient(url, { method: 'POST', body, headers }); }, - postTestImpressionsBulk(body: string) { + /** + * Post impressions. + * + * @param body Impressions bulk payload + * @param headers Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers. + */ + postTestImpressionsBulk(body: string, headers?: Record) { const url = `${urls.events}/testImpressions/bulk`; return splitHttpClient(url, { // Adding extra headers to send impressions in OPTIMIZED or DEBUG modes. - method: 'POST', body, headers: { SplitSDKImpressionsMode } + method: 'POST', body, headers: objectAssign({ SplitSDKImpressionsMode }, headers) }); }, - postTestImpressionsCount(body: string) { + /** + * Post impressions counts. + * + * @param body Impressions counts payload + * @param headers Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers. + */ + postTestImpressionsCount(body: string, headers?: Record) { const url = `${urls.events}/testImpressions/count`; - return splitHttpClient(url, { method: 'POST', body }); + return splitHttpClient(url, { method: 'POST', body, headers }); }, postMetricsCounters(body: string) { diff --git a/src/services/splitHttpClient.ts b/src/services/splitHttpClient.ts index d19beb9c..8f413f5e 100644 --- a/src/services/splitHttpClient.ts +++ b/src/services/splitHttpClient.ts @@ -1,22 +1,20 @@ -import { IFetch, IRequestOptions, ISplitHttpClient } from './types'; -import { SplitError, SplitNetworkError } from '../utils/lang/errors'; +import { IFetch, IRequestOptions, IResponse, ISplitHttpClient } from './types'; import objectAssign from 'object-assign'; -import { IMetadata } from '../dtos/types'; -import { ILogger } from '../logger/types'; import { ERROR_HTTP, ERROR_CLIENT_CANNOT_GET_READY } from '../logger/constants'; +import { ISettings } from '../types'; const messageNoFetch = 'Global fetch API is not available.'; /** * Factory of Split HTTP clients, which are HTTP clients with predefined headers for Split endpoints. * - * @param apikey api key to set Authorization header - * @param metadata data to set additional headers + * @param settings SDK settings, used to access authorizationKey, logger instance and metadata (SDK version, ip and hostname) to set additional headers * @param options global request options * @param fetch optional http client to use instead of the global Fetch (for environments where Fetch API is not available such as Node) */ -export function splitHttpClientFactory(log: ILogger, apikey: string, metadata: IMetadata, getFetch?: () => (IFetch | undefined), getOptions?: () => object): ISplitHttpClient { +export function splitHttpClientFactory(settings: Pick, getFetch?: () => (IFetch | undefined), getOptions?: () => object): ISplitHttpClient { + const { log, core: { authorizationKey }, version, runtime: { ip, hostname } } = settings; const options = getOptions && getOptions(); const fetch = getFetch && getFetch(); @@ -26,14 +24,14 @@ export function splitHttpClientFactory(log: ILogger, apikey: string, metadata: I const headers: Record = { 'Accept': 'application/json', 'Content-Type': 'application/json', - 'Authorization': `Bearer ${apikey}`, - 'SplitSDKVersion': metadata.version + 'Authorization': `Bearer ${authorizationKey}`, + 'SplitSDKVersion': version }; - if (metadata.ip) headers['SplitSDKMachineIP'] = metadata.ip; - if (metadata.hostname) headers['SplitSDKMachineName'] = metadata.hostname; + if (ip) headers['SplitSDKMachineIP'] = ip; + if (hostname) headers['SplitSDKMachineName'] = hostname; - return function httpClient(url: string, reqOpts: IRequestOptions = {}, logErrorsAsInfo: boolean = false): Promise { + return function httpClient(url: string, reqOpts: IRequestOptions = {}, logErrorsAsInfo: boolean = false): Promise { const request = objectAssign({ headers: reqOpts.headers ? objectAssign({}, headers, reqOpts.headers) : headers, @@ -45,8 +43,8 @@ export function splitHttpClientFactory(log: ILogger, apikey: string, metadata: I return fetch ? fetch(url, request) // https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful .then(response => { - if (!response.ok) { // eslint-disable-next-line no-throw-literal - throw { response }; + if (!response.ok) { + return response.text().then(message => Promise.reject({ response, message })); } return response; }) @@ -58,19 +56,22 @@ export function splitHttpClientFactory(log: ILogger, apikey: string, metadata: I switch (resp.status) { case 404: msg = 'Invalid API key or resource not found.'; break; - default: msg = resp.statusText; + // Don't use resp.statusText since reason phrase is removed in HTTP/2 + default: msg = error.message; break; } } else { // Something else, either an error making the request or a Network error. - msg = error.message; + msg = error.message || 'Network Error'; } if (!resp || resp.status !== 403) { // 403's log we'll be handled somewhere else. log[logErrorsAsInfo ? 'info' : 'error'](ERROR_HTTP, [resp ? resp.status : 'NO_STATUS', url, msg]); } + const networkError: Error & { statusCode?: number } = new Error(msg); // passes `undefined` as statusCode if not an HTTP error (resp === undefined) - throw new SplitNetworkError(msg, resp && resp.status); - }) : Promise.reject(new SplitError(messageNoFetch)); + networkError.statusCode = resp && resp.status; + throw networkError; + }) : Promise.reject(new Error(messageNoFetch)); }; } diff --git a/src/services/types.ts b/src/services/types.ts index 7e45c9df..b1bdf954 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -1,40 +1,64 @@ export type IRequestOptions = { - method?: string, - headers?: Record, - body?: string + method?: string, + headers?: Record, + body?: string }; +export type IResponse = { + ok: boolean, + status: number, + json: () => Promise, // Used to parse OK response body. Promise rejects if body cannot be parsed + text: () => Promise, // Used to read Not OK response body. Promise never rejects + + /** Other available properties when using Unfetch */ + // statusText: string, // `undefined` in Web fetch since HTTP/2 doesn't have reason phrases anymore. `node-fetch` overwrites it depending on the status code + // url: string, + // blob: () => Promise, + // clone: () => IResponse, + // headers: { + // keys: () => string[], + // entries: () => Array<[string, string]>, + // get: (key: string) => string | undefined, + // has: (key: string) => boolean, + // } +} + // Reduced version of Fetch API -export type IFetch = (url: string, options?: IRequestOptions) => Promise +export type IFetch = (url: string, options?: IRequestOptions) => Promise + +// IFetch specialization +export type IHealthCheckAPI = () => Promise -export type ISplitHttpClient = (url: string, options?: IRequestOptions, logErrorsAsInfo?: boolean) => Promise +export type ISplitHttpClient = (url: string, options?: IRequestOptions, logErrorsAsInfo?: boolean) => Promise -export type IFetchAuth = (userKeys?: string[]) => Promise +export type IFetchAuth = (userKeys?: string[]) => Promise -export type IFetchSplitChanges = (since: number, noCache?: boolean) => Promise +export type IFetchSplitChanges = (since: number, noCache?: boolean) => Promise -export type IFetchSegmentChanges = (since: number, segmentName: string, noCache?: boolean) => Promise +export type IFetchSegmentChanges = (since: number, segmentName: string, noCache?: boolean) => Promise -export type IFetchMySegments = (userMatchingKey: string, noCache?: boolean) => Promise +export type IFetchMySegments = (userMatchingKey: string, noCache?: boolean) => Promise -export type IPostEventsBulk = (body: string) => Promise +export type IPostEventsBulk = (body: string, headers?: Record) => Promise -export type IPostTestImpressionsBulk = (body: string) => Promise +export type IPostTestImpressionsBulk = (body: string, headers?: Record) => Promise -export type IPostTestImpressionsCount = (body: string) => Promise +export type IPostTestImpressionsCount = (body: string, headers?: Record) => Promise -export type IPostMetricsCounters = (body: string) => Promise +export type IPostMetricsCounters = (body: string) => Promise -export type IPostMetricsTimes = (body: string) => Promise +export type IPostMetricsTimes = (body: string) => Promise export interface ISplitApi { - fetchAuth: IFetchAuth - fetchSplitChanges: IFetchSplitChanges - fetchSegmentChanges: IFetchSegmentChanges - fetchMySegments: IFetchMySegments - postEventsBulk: IPostEventsBulk - postTestImpressionsBulk: IPostTestImpressionsBulk - postTestImpressionsCount: IPostTestImpressionsCount - postMetricsCounters: IPostMetricsCounters - postMetricsTimes: IPostMetricsTimes + getSdkAPIHealthCheck: IHealthCheckAPI + getEventsAPIHealthCheck: IHealthCheckAPI + fetchAuth: IFetchAuth + fetchSplitChanges: IFetchSplitChanges + fetchSegmentChanges: IFetchSegmentChanges + fetchMySegments: IFetchMySegments + postEventsBulk: IPostEventsBulk + postTestImpressionsBulk: IPostTestImpressionsBulk + postTestImpressionsCount: IPostTestImpressionsCount + postMetricsCounters: IPostMetricsCounters + postMetricsTimes: IPostMetricsTimes } diff --git a/src/storages/AbstractSplitsCacheAsync.ts b/src/storages/AbstractSplitsCacheAsync.ts new file mode 100644 index 00000000..e213b9a3 --- /dev/null +++ b/src/storages/AbstractSplitsCacheAsync.ts @@ -0,0 +1,65 @@ +import { ISplitsCacheAsync } from './types'; +import { ISplit } from '../dtos/types'; + +/** + * This class provides a skeletal implementation of the ISplitsCacheAsync interface + * to minimize the effort required to implement this interface. + */ +export default abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync { + + abstract addSplit(name: string, split: string): Promise + abstract addSplits(entries: [string, string][]): Promise + abstract removeSplits(names: string[]): Promise + abstract getSplit(name: string): Promise + abstract getSplits(names: string[]): Promise> + abstract setChangeNumber(changeNumber: number): Promise + abstract getChangeNumber(): Promise + abstract getAll(): Promise + abstract getSplitNames(): Promise + abstract trafficTypeExists(trafficType: string): Promise + abstract clear(): Promise + + // @TODO revisit segment-related methods ('usesSegments', 'getRegisteredSegments', 'registerSegments') + // noop, just keeping the interface. This is used by standalone client-side API only, and so only implemented by InMemory and InLocalStorage. + usesSegments(): Promise { + return Promise.resolve(true); + } + + /** + * Check if the splits information is already stored in cache. + * Noop, just keeping the interface. This is used by client-side implementations only. + */ + checkCache(): Promise { + return Promise.resolve(false); + } + + /** + * Kill `name` split and set `defaultTreatment` and `changeNumber`. + * Used for SPLIT_KILL push notifications. + * + * @param {string} name + * @param {string} defaultTreatment + * @param {number} changeNumber + * @returns {Promise} a promise that is resolved once the split kill operation is performed. The fulfillment value is a boolean: `true` if the kill success updating the split or `false` if no split is updated, + * for instance, if the `changeNumber` is old, or if the split is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update. + * The promise will never be rejected. + */ + killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise { + return this.getSplit(name).then(split => { + + if (split) { + const parsedSplit: ISplit = JSON.parse(split); + if (!parsedSplit.changeNumber || parsedSplit.changeNumber < changeNumber) { + parsedSplit.killed = true; + parsedSplit.defaultTreatment = defaultTreatment; + parsedSplit.changeNumber = changeNumber; + const newSplit = JSON.stringify(parsedSplit); + + return this.addSplit(name, newSplit); + } + } + return false; + }).catch(() => false); + } + +} diff --git a/src/storages/AbstractSplitsCacheSync.ts b/src/storages/AbstractSplitsCacheSync.ts index 36eef20d..9bc31467 100644 --- a/src/storages/AbstractSplitsCacheSync.ts +++ b/src/storages/AbstractSplitsCacheSync.ts @@ -10,26 +10,13 @@ export default abstract class AbstractSplitsCacheSync implements ISplitsCacheSyn abstract addSplit(name: string, split: string): boolean; addSplits(entries: [string, string][]): boolean[] { - const results: boolean[] = []; - - entries.forEach(keyValuePair => { - results.push(this.addSplit(keyValuePair[0], keyValuePair[1])); - }); - - return results; + return entries.map(keyValuePair => this.addSplit(keyValuePair[0], keyValuePair[1])); } - abstract removeSplit(name: string): number - - removeSplits(names: string[]): number { - let len = names.length; - let counter = 0; + abstract removeSplit(name: string): boolean - for (let i = 0; i < len; i++) { - counter += this.removeSplit(names[i]); - } - - return counter; + removeSplits(names: string[]): boolean[] { + return names.map(name => this.removeSplit(name)); } abstract getSplit(name: string): string | null @@ -63,7 +50,7 @@ export default abstract class AbstractSplitsCacheSync implements ISplitsCacheSyn * It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE. */ checkCache(): boolean { - return this.getChangeNumber() > -1; + return false; } /** diff --git a/src/storages/KeyBuilder.ts b/src/storages/KeyBuilder.ts index 36e4badc..b761b7dd 100644 --- a/src/storages/KeyBuilder.ts +++ b/src/storages/KeyBuilder.ts @@ -1,14 +1,22 @@ -import { startsWith } from '../utils/lang'; +import { endsWith, startsWith } from '../utils/lang'; const everythingAtTheEnd = /[^.]+$/; -export default class KeyBuilder { +const DEFAULT_PREFIX = 'SPLITIO'; + +export function validatePrefix(prefix: unknown) { + return prefix && typeof prefix === 'string' ? + endsWith(prefix, '.' + DEFAULT_PREFIX) ? + prefix : // suffix already appended + prefix + '.' + DEFAULT_PREFIX : // append suffix + DEFAULT_PREFIX; // use default prefix if none is provided +} - static DEFAULT_PREFIX = 'SPLITIO'; +export default class KeyBuilder { protected readonly prefix: string; - constructor(prefix: string = KeyBuilder.DEFAULT_PREFIX) { + constructor(prefix: string = DEFAULT_PREFIX) { this.prefix = prefix; } @@ -33,6 +41,15 @@ export default class KeyBuilder { return startsWith(key, `${this.prefix}.split.`); } + buildSplitKeyPrefix() { + return `${this.prefix}.split.`; + } + + // Only used by InLocalStorage. + buildSplitsWithSegmentCountKey() { + return `${this.prefix}.splits.usingSegments`; + } + buildSegmentNameKey(segmentName: string) { return `${this.prefix}.segment.${segmentName}`; } diff --git a/src/storages/KeyBuilderCS.ts b/src/storages/KeyBuilderCS.ts index 7d2c1312..6bfe7adf 100644 --- a/src/storages/KeyBuilderCS.ts +++ b/src/storages/KeyBuilderCS.ts @@ -26,10 +26,6 @@ export default class KeyBuilderCS extends KeyBuilder { return builtSegmentKeyName.substr(prefix.length); } - buildSplitsWithSegmentCountKey() { - return `${this.prefix}.splits.usingSegments`; - } - buildLastUpdatedKey() { return `${this.prefix}.splits.lastUpdated`; } diff --git a/src/storages/KeyBuilderSS.ts b/src/storages/KeyBuilderSS.ts index 903a0c73..8944eecb 100644 --- a/src/storages/KeyBuilderSS.ts +++ b/src/storages/KeyBuilderSS.ts @@ -7,9 +7,9 @@ import { IMetadata } from '../dtos/types'; export default class KeyBuilderSS extends KeyBuilder { - protected readonly metadata: Required; + protected readonly metadata: IMetadata; - constructor(prefix: string, metadata: Required) { + constructor(prefix: string, metadata: IMetadata) { super(prefix); this.metadata = metadata; } @@ -19,7 +19,7 @@ export default class KeyBuilderSS extends KeyBuilder { } private buildVersionablePrefix() { - return `${this.prefix}/${this.metadata.version}/${this.metadata.ip}`; + return `${this.prefix}/${this.metadata.s}/${this.metadata.i}`; } buildImpressionsKey() { @@ -53,7 +53,7 @@ export default class KeyBuilderSS extends KeyBuilder { // } searchPatternForSplitKeys() { - return `${this.prefix}.split.*`; + return `${this.buildSplitKeyPrefix()}*`; } // NOT USED diff --git a/src/storages/__tests__/KeyBuilder.spec.ts b/src/storages/__tests__/KeyBuilder.spec.ts index b3e77dac..6016d169 100644 --- a/src/storages/__tests__/KeyBuilder.spec.ts +++ b/src/storages/__tests__/KeyBuilder.spec.ts @@ -67,7 +67,7 @@ test('KEYS / traffic type keys', () => { test('KEYS / impressions', () => { const prefix = 'SPLITIO'; - const metadata = { version: 'js-1234', ip: '10-10-10-10', hostname: 'UNKNOWN' }; + const metadata = { s: 'js-1234', i: '10-10-10-10', n: 'UNKNOWN' }; const builder = new KeyBuilderSS(prefix, metadata); const expectedImpressionKey = `${prefix}.impressions`; @@ -92,13 +92,13 @@ test('KEYS / events', () => { test('KEYS / latency keys', () => { const prefix = 'SPLITIO'; - const metadata = { version: 'js-1234', ip: '10-10-10-10', hostname: 'UNKNOWN' }; + const metadata = { s: 'js-1234', i: '10-10-10-10', n: 'UNKNOWN' }; const builder = new KeyBuilderSS(prefix, metadata); const metricName = 'unit testing metric name'; const bucketNumber = '10'; - const expectedLatencyKey = `${prefix}/${metadata.version}/${metadata.ip}/latency.${metricName}.bucket.${bucketNumber}`; + const expectedLatencyKey = `${prefix}/${metadata.s}/${metadata.i}/latency.${metricName}.bucket.${bucketNumber}`; expect(builder.buildLatencyKey(metricName, bucketNumber) === expectedLatencyKey).toBe(true); diff --git a/src/storages/__tests__/metadataBuilder.spec.ts b/src/storages/__tests__/metadataBuilder.spec.ts new file mode 100644 index 00000000..c3365308 --- /dev/null +++ b/src/storages/__tests__/metadataBuilder.spec.ts @@ -0,0 +1,34 @@ +import { metadataBuilder } from '../metadataBuilder'; +import { UNKNOWN } from '../../utils/constants'; + +describe('metadataBuilder', () => { + + test('metadata object creation', () => { + const settings = { + version: 'test.version', + runtime: { + ip: 'test.ip', + hostname: 'test.hostname' + } + }; + let meta = metadataBuilder(settings); + + expect(meta.s).toBe(settings.version); // SDK Version should be returned as the "s" property. + expect(meta.i).toBe(settings.runtime.ip); // SDK runtime IP should be returned as the "i" property. + expect(meta.n).toBe(settings.runtime.hostname); // SDK runtime hostname should be returned as the "n" property. + + expect(meta !== metadataBuilder(settings)).toBe(true); // Should return a new object each time we call it. + }); + + test('creation with undefined properties', () => { + const fakeSettings = { + version: 'test.version', runtime: { ip: false as false, hostname: false as false } + }; + let meta = metadataBuilder(fakeSettings); + + expect(meta.s).toBe(fakeSettings.version); // SDK Version should be returned as the "s" property. + expect(meta.i).toBe(UNKNOWN); // The "i" property should be 'UNKNOWN' if IP value is undefined. + expect(meta.n).toBe(UNKNOWN); // The "n" property should be 'UNKNOWN' if hostname value is undefined. + }); + +}); diff --git a/src/storages/__tests__/testUtils.ts b/src/storages/__tests__/testUtils.ts new file mode 100644 index 00000000..b09e9c1b --- /dev/null +++ b/src/storages/__tests__/testUtils.ts @@ -0,0 +1,21 @@ +import { IStorageSync, IStorageAsync } from '../types'; + +// Assert that instances created by storage factories have the expected interface +export function assertStorageInterface(storage: IStorageSync | IStorageAsync) { + expect(typeof storage.destroy).toBe('function'); + expect(typeof storage.splits).toBe('object'); + expect(typeof storage.segments).toBe('object'); + expect(typeof storage.impressions).toBe('object'); + expect(typeof storage.events).toBe('object'); + expect(!storage.latencies || typeof storage.latencies === 'object').toBeTruthy; + expect(!storage.counts || typeof storage.counts === 'object').toBeTruthy; + expect(!storage.impressionCounts || typeof storage.impressionCounts === 'object').toBeTruthy; +} + +// Split mocks + +export const splitWithUserTT = '{ "trafficTypeName": "user_tt", "conditions": [] }'; + +export const splitWithAccountTT = '{ "trafficTypeName": "account_tt", "conditions": [] }'; + +export const splitWithAccountTTAndUsesSegments = '{ "trafficTypeName": "account_tt", "conditions": [{ "matcherGroup": { "matchers": [{ "matcherType": "IN_SEGMENT", "userDefinedSegmentMatcherData": { "segmentName": "employees" } }]}}] }'; diff --git a/src/storages/dataLoader.ts b/src/storages/dataLoader.ts index 97ae6b3b..26e0090d 100644 --- a/src/storages/dataLoader.ts +++ b/src/storages/dataLoader.ts @@ -39,9 +39,7 @@ export function dataLoaderFactory(preloadedData: SplitIO.PreloadedData): DataLoa storage.splits.setChangeNumber(since); // splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data - Object.keys(splitsData).forEach(splitName => { - storage.splits.addSplit(splitName, splitsData[splitName]); - }); + storage.splits.addSplits(Object.keys(splitsData).map(splitName => [splitName, splitsData[splitName]])); // add mySegments data let mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userId]; diff --git a/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts b/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts index 020f823a..12289470 100644 --- a/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +++ b/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts @@ -1,7 +1,7 @@ import { ILogger } from '../../logger/types'; import AbstractSegmentsCacheSync from '../AbstractSegmentsCacheSync'; import KeyBuilderCS from '../KeyBuilderCS'; -import { logPrefix, DEFINED } from './constants'; +import { LOG_PREFIX, DEFINED } from './constants'; export default class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync { @@ -20,7 +20,7 @@ export default class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync { * @NOTE this method is not being used at the moment. */ clear() { - this.log.info(logPrefix + 'Flushing MySegments data from localStorage'); + this.log.info(LOG_PREFIX + 'Flushing MySegments data from localStorage'); // We cannot simply call `localStorage.clear()` since that implies removing user items from the storage // We could optimize next sentence, since it implies iterating over all localStorage items @@ -34,7 +34,7 @@ export default class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync { localStorage.setItem(segmentKey, DEFINED); return true; } catch (e) { - this.log.error(logPrefix + e); + this.log.error(LOG_PREFIX + e); return false; } } @@ -46,7 +46,7 @@ export default class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync { localStorage.removeItem(segmentKey); return true; } catch (e) { - this.log.error(logPrefix + e); + this.log.error(LOG_PREFIX + e); return false; } } diff --git a/src/storages/inLocalStorage/SplitsCacheInLocal.ts b/src/storages/inLocalStorage/SplitsCacheInLocal.ts index 58d5ba09..68565b55 100644 --- a/src/storages/inLocalStorage/SplitsCacheInLocal.ts +++ b/src/storages/inLocalStorage/SplitsCacheInLocal.ts @@ -3,7 +3,7 @@ import AbstractSplitsCacheSync, { usesSegments } from '../AbstractSplitsCacheSyn import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang'; import KeyBuilderCS from '../KeyBuilderCS'; import { ILogger } from '../../logger/types'; -import { logPrefix } from './constants'; +import { LOG_PREFIX } from './constants'; /** * ISplitsCacheSync implementation that stores split definitions in browser LocalStorage. @@ -52,7 +52,7 @@ export default class SplitsCacheInLocal extends AbstractSplitsCacheSync { } } } catch (e) { - this.log.error(logPrefix + e); + this.log.error(LOG_PREFIX + e); } } @@ -72,7 +72,7 @@ export default class SplitsCacheInLocal extends AbstractSplitsCacheSync { } } } catch (e) { - this.log.error(logPrefix + e); + this.log.error(LOG_PREFIX + e); } } @@ -82,7 +82,7 @@ export default class SplitsCacheInLocal extends AbstractSplitsCacheSync { * We cannot simply call `localStorage.clear()` since that implies removing user items from the storage. */ clear() { - this.log.info(logPrefix + 'Flushing Splits data from localStorage'); + this.log.info(LOG_PREFIX + 'Flushing Splits data from localStorage'); // collect item keys const len = localStorage.length; @@ -114,12 +114,12 @@ export default class SplitsCacheInLocal extends AbstractSplitsCacheSync { return true; } catch (e) { - this.log.error(logPrefix + e); + this.log.error(LOG_PREFIX + e); return false; } } - removeSplit(name: string): number { + removeSplit(name: string): boolean { try { const split = this.getSplit(name); localStorage.removeItem(this.keys.buildSplitKey(name)); @@ -127,10 +127,10 @@ export default class SplitsCacheInLocal extends AbstractSplitsCacheSync { const parsedSplit = JSON.parse(split as string); this._decrementCounts(parsedSplit); - return 1; + return true; } catch (e) { - this.log.error(logPrefix + e); - return 0; + this.log.error(LOG_PREFIX + e); + return false; } } @@ -147,14 +147,14 @@ export default class SplitsCacheInLocal extends AbstractSplitsCacheSync { // when using a new split query, we must update it at the store if (this.updateNewFilter) { - this.log.info(logPrefix + 'Split filter query was modified. Updating cache.'); + this.log.info(LOG_PREFIX + 'Split filter query was modified. Updating cache.'); const queryKey = this.keys.buildSplitsFilterQueryKey(); const queryString = this.splitFiltersValidation.queryString; try { if (queryString) localStorage.setItem(queryKey, queryString); else localStorage.removeItem(queryKey); } catch (e) { - this.log.error(logPrefix + e); + this.log.error(LOG_PREFIX + e); } this.updateNewFilter = false; } @@ -166,7 +166,7 @@ export default class SplitsCacheInLocal extends AbstractSplitsCacheSync { this.hasSync = true; return true; } catch (e) { - this.log.error(logPrefix + e); + this.log.error(LOG_PREFIX + e); return false; } } @@ -273,7 +273,7 @@ export default class SplitsCacheInLocal extends AbstractSplitsCacheSync { }); } } catch (e) { - this.log.error(logPrefix + e); + this.log.error(LOG_PREFIX + e); } } // if the filter didn't change, nothing is done diff --git a/src/storages/inLocalStorage/__tests__/SplitsCacheInLocal.spec.ts b/src/storages/inLocalStorage/__tests__/SplitsCacheInLocal.spec.ts index 4430afe7..0f3172f7 100644 --- a/src/storages/inLocalStorage/__tests__/SplitsCacheInLocal.spec.ts +++ b/src/storages/inLocalStorage/__tests__/SplitsCacheInLocal.spec.ts @@ -1,6 +1,7 @@ import SplitsCacheInLocal from '../SplitsCacheInLocal'; import KeyBuilderCS from '../../KeyBuilderCS'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import { splitWithUserTT, splitWithAccountTT, splitWithAccountTTAndUsesSegments } from '../../__tests__/testUtils'; test('SPLIT CACHE / LocalStorage', () => { const cache = new SplitsCacheInLocal(loggerMock, new KeyBuilderCS('SPLITIO', 'user')); @@ -73,12 +74,12 @@ test('SPLIT CACHE / LocalStorage / trafficTypeExists and ttcache tests', () => { const cache = new SplitsCacheInLocal(loggerMock, new KeyBuilderCS('SPLITIO', 'user')); cache.addSplits([ // loop of addSplit - ['split1', '{ "trafficTypeName": "user_tt" }'], - ['split2', '{ "trafficTypeName": "account_tt" }'], - ['split3', '{ "trafficTypeName": "user_tt" }'], + ['split1', splitWithUserTT], + ['split2', splitWithAccountTT], + ['split3', splitWithUserTT], ['malformed', '{}'] ]); - cache.addSplit('split4', '{ "trafficTypeName": "user_tt" }'); + cache.addSplit('split4', splitWithUserTT); expect(cache.trafficTypeExists('user_tt')).toBe(true); expect(cache.trafficTypeExists('account_tt')).toBe(true); @@ -99,10 +100,10 @@ test('SPLIT CACHE / LocalStorage / trafficTypeExists and ttcache tests', () => { expect(cache.trafficTypeExists('user_tt')).toBe(false); expect(cache.trafficTypeExists('account_tt')).toBe(false); - cache.addSplit('split1', '{ "trafficTypeName": "user_tt" }'); + cache.addSplit('split1', splitWithUserTT); expect(cache.trafficTypeExists('user_tt')).toBe(true); - cache.addSplit('split1', '{ "trafficTypeName": "account_tt" }'); + cache.addSplit('split1', splitWithAccountTT); expect(cache.trafficTypeExists('account_tt')).toBe(true); expect(cache.trafficTypeExists('user_tt')).toBe(false); @@ -139,3 +140,25 @@ test('SPLIT CACHE / LocalStorage / killLocally', () => { expect(lol1Split.defaultTreatment).not.toBe('some_treatment_2'); // existing split is not updated if given changeNumber is older }); + +test('SPLIT CACHE / LocalStorage / usesSegments', () => { + const cache = new SplitsCacheInLocal(loggerMock, new KeyBuilderCS('SPLITIO', 'user')); + + expect(cache.usesSegments()).toBe(true); // true initially, until data is synchronized + cache.setChangeNumber(1); // to indicate that data has been synced. + + cache.addSplits([['split1', splitWithUserTT], ['split2', splitWithAccountTT],]); + expect(cache.usesSegments()).toBe(false); // 0 splits using segments + + cache.addSplit('split3', splitWithAccountTTAndUsesSegments); + expect(cache.usesSegments()).toBe(true); // 1 split using segments + + cache.addSplit('split4', splitWithAccountTTAndUsesSegments); + expect(cache.usesSegments()).toBe(true); // 2 splits using segments + + cache.removeSplit('split3'); + expect(cache.usesSegments()).toBe(true); // 1 split using segments + + cache.removeSplit('split4'); + expect(cache.usesSegments()).toBe(false); // 0 splits using segments +}); diff --git a/src/storages/inLocalStorage/__tests__/index.spec.ts b/src/storages/inLocalStorage/__tests__/index.spec.ts index 131f2eff..417c8727 100644 --- a/src/storages/inLocalStorage/__tests__/index.spec.ts +++ b/src/storages/inLocalStorage/__tests__/index.spec.ts @@ -1,6 +1,7 @@ // Mocks import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; import { IStorageFactoryParams } from '../../types'; +import { assertStorageInterface } from '../../__tests__/testUtils'; const fakeInMemoryStorage = 'fakeStorage'; const fakeInMemoryStorageFactory = jest.fn(() => fakeInMemoryStorage); jest.mock('../../inMemory/InMemoryStorageCS', () => { @@ -41,7 +42,7 @@ describe('IN LOCAL STORAGE', () => { const storageFactory = InLocalStorage({ prefix: 'prefix' }); const storage = storageFactory(internalSdkParams); - expect(typeof storage).toBe('object'); + assertStorageInterface(storage); // the instance must implement the storage interface expect(fakeInMemoryStorageFactory).not.toBeCalled(); // doesn't call InMemoryStorage factory }); diff --git a/src/storages/inLocalStorage/constants.ts b/src/storages/inLocalStorage/constants.ts index 74624310..8dcb6c3e 100644 --- a/src/storages/inLocalStorage/constants.ts +++ b/src/storages/inLocalStorage/constants.ts @@ -1,2 +1,2 @@ -export const logPrefix = 'storage:localstorage: '; +export const LOG_PREFIX = 'storage:localstorage: '; export const DEFINED = '1'; diff --git a/src/storages/inLocalStorage/index.ts b/src/storages/inLocalStorage/index.ts index 226d771c..6587208b 100644 --- a/src/storages/inLocalStorage/index.ts +++ b/src/storages/inLocalStorage/index.ts @@ -1,7 +1,8 @@ import ImpressionsCacheInMemory from '../inMemory/ImpressionsCacheInMemory'; import ImpressionCountsCacheInMemory from '../inMemory/ImpressionCountsCacheInMemory'; import EventsCacheInMemory from '../inMemory/EventsCacheInMemory'; -import { IStorageFactoryParams, IStorageSyncCS } from '../types'; +import { IStorageFactoryParams, IStorageSyncCS, IStorageSyncFactory } from '../types'; +import { validatePrefix } from '../KeyBuilder'; import KeyBuilderCS from '../KeyBuilderCS'; import { isLocalStorageAvailable } from '../../utils/env/isLocalStorageAvailable'; import SplitsCacheInLocal from './SplitsCacheInLocal'; @@ -10,7 +11,8 @@ import MySegmentsCacheInMemory from '../inMemory/MySegmentsCacheInMemory'; import SplitsCacheInMemory from '../inMemory/SplitsCacheInMemory'; import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../../utils/constants/browser'; import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS'; -import { logPrefix } from './constants'; +import { LOG_PREFIX } from './constants'; +import { STORAGE_LOCALSTORAGE } from '../../utils/constants'; export interface InLocalStorageOptions { prefix?: string @@ -19,15 +21,15 @@ export interface InLocalStorageOptions { /** * InLocal storage factory for standalone client-side SplitFactory */ -export function InLocalStorage(options: InLocalStorageOptions = {}) { +export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyncFactory { - const prefix = options.prefix ? options.prefix + '.SPLITIO' : 'SPLITIO'; + const prefix = validatePrefix(options.prefix); - return function InLocalStorageCSFactory(params: IStorageFactoryParams): IStorageSyncCS { + function InLocalStorageCSFactory(params: IStorageFactoryParams): IStorageSyncCS { // Fallback to InMemoryStorage if LocalStorage API is not available if (!isLocalStorageAvailable()) { - params.log.warn(logPrefix + 'LocalStorage API is unavailable. Fallbacking into default MEMORY storage'); + params.log.warn(LOG_PREFIX + 'LocalStorage API is unavailable. Fallbacking into default MEMORY storage'); return InMemoryStorageCSFactory(params); } @@ -68,5 +70,8 @@ export function InLocalStorage(options: InLocalStorageOptions = {}) { }; }, }; - }; + } + + InLocalStorageCSFactory.type = STORAGE_LOCALSTORAGE; + return InLocalStorageCSFactory; } diff --git a/src/storages/inMemory/EventsCacheInMemory.ts b/src/storages/inMemory/EventsCacheInMemory.ts index 2b92419b..e60d00d6 100644 --- a/src/storages/inMemory/EventsCacheInMemory.ts +++ b/src/storages/inMemory/EventsCacheInMemory.ts @@ -10,7 +10,12 @@ export default class EventsCacheInMemory implements IEventsCacheSync { private queue: SplitIO.EventData[]; private queueByteSize: number; - constructor(eventsQueueSize: number) { + /** + * + * @param eventsQueueSize number of queued events to call onFullQueueCb. + * Default value is 0, that means no maximum value, in case we want to avoid this being triggered. + */ + constructor(eventsQueueSize: number = 0) { this.maxQueue = eventsQueueSize; this.queue = []; this.queueByteSize = 0; diff --git a/src/storages/inMemory/ImpressionsCacheInMemory.ts b/src/storages/inMemory/ImpressionsCacheInMemory.ts index 2e4b0b53..9b9e3faa 100644 --- a/src/storages/inMemory/ImpressionsCacheInMemory.ts +++ b/src/storages/inMemory/ImpressionsCacheInMemory.ts @@ -10,7 +10,6 @@ export default class ImpressionsCacheInMemory implements IImpressionsCacheSync { */ track(data: ImpressionDTO[]) { this.queue.push(...data); - return true; } /** diff --git a/src/storages/inMemory/InMemoryStorage.ts b/src/storages/inMemory/InMemoryStorage.ts index 9cdaa4d1..349ac6e1 100644 --- a/src/storages/inMemory/InMemoryStorage.ts +++ b/src/storages/inMemory/InMemoryStorage.ts @@ -4,6 +4,7 @@ import ImpressionsCacheInMemory from './ImpressionsCacheInMemory'; import EventsCacheInMemory from './EventsCacheInMemory'; import { IStorageFactoryParams, IStorageSync } from '../types'; import ImpressionCountsCacheInMemory from './ImpressionCountsCacheInMemory'; +import { STORAGE_MEMORY } from '../../utils/constants'; /** * InMemory storage factory for standalone server-side SplitFactory @@ -12,6 +13,9 @@ import ImpressionCountsCacheInMemory from './ImpressionCountsCacheInMemory'; */ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageSync { + // InMemory storage is always ready + if (params.onReadyCb) setTimeout(params.onReadyCb); + return { splits: new SplitsCacheInMemory(), segments: new SegmentsCacheInMemory(), @@ -29,3 +33,5 @@ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageS } }; } + +InMemoryStorageFactory.type = STORAGE_MEMORY; diff --git a/src/storages/inMemory/InMemoryStorageCS.ts b/src/storages/inMemory/InMemoryStorageCS.ts index 1ef25283..d59e4c04 100644 --- a/src/storages/inMemory/InMemoryStorageCS.ts +++ b/src/storages/inMemory/InMemoryStorageCS.ts @@ -4,6 +4,7 @@ import ImpressionsCacheInMemory from './ImpressionsCacheInMemory'; import EventsCacheInMemory from './EventsCacheInMemory'; import { IStorageSyncCS, IStorageFactoryParams } from '../types'; import ImpressionCountsCacheInMemory from './ImpressionCountsCacheInMemory'; +import { STORAGE_MEMORY } from '../../utils/constants'; /** * InMemory storage factory for standalone client-side SplitFactory @@ -46,3 +47,5 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag }, }; } + +InMemoryStorageCSFactory.type = STORAGE_MEMORY; diff --git a/src/storages/inMemory/SplitsCacheInMemory.ts b/src/storages/inMemory/SplitsCacheInMemory.ts index 5388d2a4..39eefdcf 100644 --- a/src/storages/inMemory/SplitsCacheInMemory.ts +++ b/src/storages/inMemory/SplitsCacheInMemory.ts @@ -57,7 +57,7 @@ export default class SplitsCacheInMemory extends AbstractSplitsCacheSync { } } - removeSplit(name: string): number { + removeSplit(name: string): boolean { const split = this.getSplit(name); if (split) { // Delete the Split @@ -74,9 +74,9 @@ export default class SplitsCacheInMemory extends AbstractSplitsCacheSync { // Update the segments count. if (usesSegments(parsedSplit)) this.splitsWithSegmentsCount--; - return 1; + return true; } else { - return 0; + return false; } } diff --git a/src/storages/inMemory/__tests__/SegmentsCacheInMemory.spec.ts b/src/storages/inMemory/__tests__/SegmentsCacheInMemory.spec.ts index c332c912..70ca6b12 100644 --- a/src/storages/inMemory/__tests__/SegmentsCacheInMemory.spec.ts +++ b/src/storages/inMemory/__tests__/SegmentsCacheInMemory.spec.ts @@ -1,33 +1,43 @@ import SegmentsCache from '../SegmentsCacheInMemory'; -test('SEGMENTS CACHE / in memory', () => { - const cache = new SegmentsCache(); +describe('SEGMENTS CACHE IN MEMORY', () => { - cache.addToSegment('mocked-segment', [ - 'a', 'b', 'c' - ]); + test('isInSegment, set/getChangeNumber, add/removeFromSegment', () => { + const cache = new SegmentsCache(); - cache.setChangeNumber('mocked-segment', 1); + cache.addToSegment('mocked-segment', [ + 'a', 'b', 'c' + ]); - cache.removeFromSegment('mocked-segment', [ - 'd' - ]); + cache.setChangeNumber('mocked-segment', 1); - expect(cache.getChangeNumber('mocked-segment') === 1).toBe(true); + cache.removeFromSegment('mocked-segment', ['d']); - cache.addToSegment('mocked-segment', [ - 'd', 'e' - ]); + expect(cache.getChangeNumber('mocked-segment') === 1).toBe(true); - cache.removeFromSegment('mocked-segment', [ - 'a', 'c' - ]); + cache.addToSegment('mocked-segment', ['d', 'e']); - expect(cache.getChangeNumber('mocked-segment') === 1).toBe(true); + cache.removeFromSegment('mocked-segment', ['a', 'c']); + + expect(cache.getChangeNumber('mocked-segment') === 1).toBe(true); + + expect(cache.isInSegment('mocked-segment', 'a')).toBe(false); + expect(cache.isInSegment('mocked-segment', 'b')).toBe(true); // b + expect(cache.isInSegment('mocked-segment', 'c')).toBe(false); // c + expect(cache.isInSegment('mocked-segment', 'd')).toBe(true); // d + expect(cache.isInSegment('mocked-segment', 'e')).toBe(true); // e + }); + + test('registerSegment / getRegisteredSegments', async () => { + const cache = new SegmentsCache(); + + await cache.registerSegments(['s1']); + await cache.registerSegments(['s2']); + await cache.registerSegments(['s2', 's3', 's4']); + + const segments = cache.getRegisteredSegments(); + + ['s1', 's2', 's3', 's4'].forEach(s => expect(segments.indexOf(s) !== -1).toBe(true)); + }); - expect(cache.isInSegment('mocked-segment', 'a')).toBe(false); - expect(cache.isInSegment('mocked-segment', 'b')).toBe(true); // b - expect(cache.isInSegment('mocked-segment', 'c')).toBe(false); // c - expect(cache.isInSegment('mocked-segment', 'd')).toBe(true); // d - expect(cache.isInSegment('mocked-segment', 'e')).toBe(true); // e }); diff --git a/src/storages/inRedis/EventsCacheInRedis.ts b/src/storages/inRedis/EventsCacheInRedis.ts index 5a8caab5..f4bc133b 100644 --- a/src/storages/inRedis/EventsCacheInRedis.ts +++ b/src/storages/inRedis/EventsCacheInRedis.ts @@ -1,39 +1,38 @@ import { IEventsCacheAsync } from '../types'; -import { IRedisMetadata } from '../../dtos/types'; -import KeyBuilderSS from '../KeyBuilderSS'; +import { IMetadata } from '../../dtos/types'; import { Redis } from 'ioredis'; import { SplitIO } from '../../types'; import { ILogger } from '../../logger/types'; - -const logPrefix = 'storage:redis: '; +import { LOG_PREFIX } from './constants'; +import { StoredEventWithMetadata } from '../../sync/submitters/types'; export default class EventsCacheInRedis implements IEventsCacheAsync { + private readonly log: ILogger; + private readonly key: string; private readonly redis: Redis; - private readonly keys: KeyBuilderSS; - private readonly metadata: IRedisMetadata; - private readonly eventsKey: string; + private readonly metadata: IMetadata; - constructor(private readonly log: ILogger, keys: KeyBuilderSS, redis: Redis, metadata: IRedisMetadata) { - this.keys = keys; + constructor(log: ILogger, key: string, redis: Redis, metadata: IMetadata) { + this.log = log; + this.key = key; this.redis = redis; this.metadata = metadata; - - this.eventsKey = keys.buildEventsKey(); } /** * Add a new event object into the queue. + * Unlike `impressions::track`, result promise is never rejected. */ track(eventData: SplitIO.EventData): Promise { return this.redis.rpush( - this.eventsKey, + this.key, this._toJSON(eventData) ) // We use boolean values to signal successful queueing .then(() => true) .catch(err => { - this.log.error(logPrefix + `Error adding event to queue: ${err}.`); + this.log.error(`${LOG_PREFIX}Error adding event to queue: ${err}.`); return false; }); } @@ -45,6 +44,31 @@ export default class EventsCacheInRedis implements IEventsCacheAsync { return JSON.stringify({ m: this.metadata, e: eventData + } as StoredEventWithMetadata); + } + + count(): Promise { + return this.redis.llen(this.key).catch(() => 0); + } + + drop(count?: number): Promise { + if (!count) return this.redis.del(this.key); + + return this.redis.ltrim(this.key, count, -1); + } + + /** + * Pop the given number of events from the storage. + * The returned promise rejects if the wrapper operation fails. + * + * NOTE: this method doesn't take into account MAX_EVENT_SIZE or MAX_QUEUE_BYTE_SIZE limits. + * It is the submitter responsability to handle that. + */ + popNWithMetadata(count: number): Promise { + return this.redis.lrange(this.key, 0, count - 1).then(items => { + return this.redis.ltrim(this.key, items.length, -1).then(() => { + return items.map(item => JSON.parse(item) as StoredEventWithMetadata); + }); }); } diff --git a/src/storages/inRedis/ImpressionsCacheInRedis.ts b/src/storages/inRedis/ImpressionsCacheInRedis.ts index 9fdfdf81..7f399e64 100644 --- a/src/storages/inRedis/ImpressionsCacheInRedis.ts +++ b/src/storages/inRedis/ImpressionsCacheInRedis.ts @@ -1,31 +1,35 @@ import { IImpressionsCacheAsync } from '../types'; -import { IRedisMetadata } from '../../dtos/types'; +import { IMetadata } from '../../dtos/types'; import { ImpressionDTO } from '../../types'; -import KeyBuilderSS from '../KeyBuilderSS'; import { Redis } from 'ioredis'; +import { StoredImpressionWithMetadata } from '../../sync/submitters/types'; +import { ILogger } from '../../logger/types'; + +const IMPRESSIONS_TTL_REFRESH = 3600; // 1 hr export default class ImpressionsCacheInRedis implements IImpressionsCacheAsync { + private readonly log: ILogger; + private readonly key: string; private readonly redis: Redis; - private readonly keys: KeyBuilderSS; - private readonly metadata: IRedisMetadata; + private readonly metadata: IMetadata; - constructor(keys: KeyBuilderSS, redis: Redis, metadata: IRedisMetadata) { - this.keys = keys; + constructor(log: ILogger, key: string, redis: Redis, metadata: IMetadata) { + this.log = log; + this.key = key; this.redis = redis; this.metadata = metadata; } - track(impressions: ImpressionDTO[]): Promise { + track(impressions: ImpressionDTO[]): Promise { // @ts-ignore return this.redis.rpush( - this.keys.buildImpressionsKey(), + this.key, this._toJSON(impressions) ).then(queuedCount => { // If this is the creation of the key on Redis, set the expiration for it in 1hr. if (queuedCount === impressions.length) { - return this.redis.expire(this.keys.buildImpressionsKey(), 3600).then(result => result === 1); // 1 if the timeout was set. 0 if key does not exist. + return this.redis.expire(this.key, IMPRESSIONS_TTL_REFRESH); } - return true; }); } @@ -50,4 +54,28 @@ export default class ImpressionsCacheInRedis implements IImpressionsCacheAsync { }); } + count(): Promise { + return this.redis.llen(this.key).catch(() => 0); + } + + drop(count?: number): Promise { + if (!count) return this.redis.del(this.key); + + return this.redis.ltrim(this.key, count, -1); + } + + popNWithMetadata(count: number): Promise { + return this.redis.lrange(this.key, 0, count - 1).then(items => { + return this.redis.ltrim(this.key, items.length, -1).then(() => { + // This operation will simply do nothing if the key no longer exists (queue is empty) + // It's only done in the "successful" exit path so that the TTL is not overriden if impressons weren't + // popped correctly. This will result in impressions getting lost but will prevent the queue from taking + // a huge amount of memory. + this.redis.expire(this.key, IMPRESSIONS_TTL_REFRESH).catch(() => { }); // noop catch handler + + return items.map(item => JSON.parse(item) as StoredImpressionWithMetadata); + }); + }); + } + } diff --git a/src/storages/inRedis/RedisAdapter.ts b/src/storages/inRedis/RedisAdapter.ts index 7d0636bc..99dccd45 100644 --- a/src/storages/inRedis/RedisAdapter.ts +++ b/src/storages/inRedis/RedisAdapter.ts @@ -5,10 +5,10 @@ import { _Set, setToArray, ISet } from '../../utils/lang/sets'; import thenable from '../../utils/promise/thenable'; import timeout from '../../utils/promise/timeout'; -const logPrefix = 'storage:redis-adapter: '; +const LOG_PREFIX = 'storage:redis-adapter: '; // If we ever decide to fully wrap every method, there's a Commander.getBuiltinCommands from ioredis. -const METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'pipeline', 'expire', 'mget']; +const METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'pipeline', 'expire', 'mget', 'lrange', 'ltrim']; // Not part of the settings since it'll vary on each storage. We should be removing storage specific logic from elsewhere. const DEFAULT_OPTIONS = { @@ -55,16 +55,16 @@ export default class RedisAdapter extends ioredis { _listenToEvents() { this.once('ready', () => { const commandsCount = this._notReadyCommandsQueue ? this._notReadyCommandsQueue.length : 0; - this.log.info(logPrefix + `Redis connection established. Queued commands: ${commandsCount}.`); + this.log.info(LOG_PREFIX + `Redis connection established. Queued commands: ${commandsCount}.`); this._notReadyCommandsQueue && this._notReadyCommandsQueue.forEach(queued => { - this.log.info(logPrefix + `Executing queued ${queued.name} command.`); + this.log.info(LOG_PREFIX + `Executing queued ${queued.name} command.`); queued.command().then(queued.resolve).catch(queued.reject); }); // After the SDK is ready for the first time we'll stop queueing commands. This is just so we can keep handling BUR for them. this._notReadyCommandsQueue = undefined; }); this.once('close', () => { - this.log.info(logPrefix + 'Redis connection closed.'); + this.log.info(LOG_PREFIX + 'Redis connection closed.'); }); } @@ -78,7 +78,7 @@ export default class RedisAdapter extends ioredis { const params = arguments; function commandWrapper() { - instance.log.debug(logPrefix + `Executing ${method}.`); + instance.log.debug(LOG_PREFIX + `Executing ${method}.`); // Return original method const result = originalMethod.apply(instance, params); @@ -93,7 +93,7 @@ export default class RedisAdapter extends ioredis { result.then(cleanUpRunningCommandsCb, cleanUpRunningCommandsCb); return timeout(instance._options.operationTimeout, result).catch(err => { - instance.log.error(logPrefix + `${method} operation threw an error or exceeded configured timeout of ${instance._options.operationTimeout}ms. Message: ${err}`); + instance.log.error(LOG_PREFIX + `${method} operation threw an error or exceeded configured timeout of ${instance._options.operationTimeout}ms. Message: ${err}`); // Handling is not the adapter responsibility. throw err; }); @@ -126,19 +126,19 @@ export default class RedisAdapter extends ioredis { setTimeout(function deferedDisconnect() { if (instance._runningCommands.size > 0) { - instance.log.info(logPrefix + `Attempting to disconnect but there are ${instance._runningCommands.size} commands still waiting for resolution. Defering disconnection until those finish.`); + instance.log.info(LOG_PREFIX + `Attempting to disconnect but there are ${instance._runningCommands.size} commands still waiting for resolution. Defering disconnection until those finish.`); Promise.all(setToArray(instance._runningCommands)) .then(() => { - instance.log.debug(logPrefix + 'Pending commands finished successfully, disconnecting.'); + instance.log.debug(LOG_PREFIX + 'Pending commands finished successfully, disconnecting.'); originalMethod.apply(instance, params); }) .catch(e => { - instance.log.warn(logPrefix + `Pending commands finished with error: ${e}. Proceeding with disconnection.`); + instance.log.warn(LOG_PREFIX + `Pending commands finished with error: ${e}. Proceeding with disconnection.`); originalMethod.apply(instance, params); }); } else { - instance.log.debug(logPrefix + 'No commands pending execution, disconnect.'); + instance.log.debug(LOG_PREFIX + 'No commands pending execution, disconnect.'); // Nothing pending, just proceed. originalMethod.apply(instance, params); } diff --git a/src/storages/inRedis/SegmentsCacheInRedis.ts b/src/storages/inRedis/SegmentsCacheInRedis.ts index e4b23ccd..daee13a5 100644 --- a/src/storages/inRedis/SegmentsCacheInRedis.ts +++ b/src/storages/inRedis/SegmentsCacheInRedis.ts @@ -1,14 +1,18 @@ import { Redis } from 'ioredis'; +import { ILogger } from '../../logger/types'; import { isNaNNumber } from '../../utils/lang'; +import { LOG_PREFIX } from '../inLocalStorage/constants'; import KeyBuilderSS from '../KeyBuilderSS'; import { ISegmentsCacheAsync } from '../types'; export default class SegmentsCacheInRedis implements ISegmentsCacheAsync { + private readonly log: ILogger; private readonly redis: Redis; private readonly keys: KeyBuilderSS; - constructor(keys: KeyBuilderSS, redis: Redis) { + constructor(log: ILogger, keys: KeyBuilderSS, redis: Redis) { + this.log = log; this.redis = redis; this.keys = keys; } @@ -50,13 +54,12 @@ export default class SegmentsCacheInRedis implements ISegmentsCacheAsync { const i = parseInt(value as string, 10); return isNaNNumber(i) ? -1 : i; + }).catch((e) => { + this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e); + return -1; }); } - registerSegment(segment: string) { - return this.registerSegments([segment]); - } - registerSegments(segments: string[]) { if (segments.length) { return this.redis.sadd(this.keys.buildRegisteredSegmentsKey(), segments).then(() => true); @@ -69,6 +72,7 @@ export default class SegmentsCacheInRedis implements ISegmentsCacheAsync { return this.redis.smembers(this.keys.buildRegisteredSegmentsKey()); } + // @TODO remove/review. It is not being used. clear() { return this.redis.flushdb().then(status => status === 'OK'); } diff --git a/src/storages/inRedis/SplitsCacheInRedis.ts b/src/storages/inRedis/SplitsCacheInRedis.ts index c601b549..92e5c09c 100644 --- a/src/storages/inRedis/SplitsCacheInRedis.ts +++ b/src/storages/inRedis/SplitsCacheInRedis.ts @@ -1,10 +1,10 @@ import { isFiniteNumber, isNaNNumber } from '../../utils/lang'; import KeyBuilderSS from '../KeyBuilderSS'; -import { ISplitsCacheAsync } from '../types'; import { Redis } from 'ioredis'; import { ILogger } from '../../logger/types'; - -const logPrefix = 'storage:redis: '; +import { LOG_PREFIX } from './constants'; +import { ISplit } from '../../dtos/types'; +import AbstractSplitsCacheAsync from '../AbstractSplitsCacheAsync'; /** * Discard errors for an answer of multiple operations. @@ -17,19 +17,24 @@ function processPipelineAnswer(results: Array<[Error | null, string]>): string[] } /** - * Default ISplitsCacheSync implementation that stores split definitions in memory. - * Supported by all JS runtimes. + * ISplitsCacheAsync implementation that stores split definitions in Redis. + * Supported by Node. */ -export default class SplitsCacheInRedis implements ISplitsCacheAsync { +export default class SplitsCacheInRedis extends AbstractSplitsCacheAsync { + private readonly log: ILogger; private readonly redis: Redis; private readonly keys: KeyBuilderSS; private redisError?: string; - constructor(private readonly log: ILogger, keys: KeyBuilderSS, redis: Redis) { + constructor(log: ILogger, keys: KeyBuilderSS, redis: Redis) { + super(); + this.log = log; this.redis = redis; this.keys = keys; + // There is no need to listen for redis 'error' event, because in that case ioredis calls will be rejected and handled by redis storage adapters. + // But it is done just to avoid getting the ioredis message `Unhandled error event`. this.redis.on('error', (e) => { this.redisError = e; }); @@ -39,53 +44,91 @@ export default class SplitsCacheInRedis implements ISplitsCacheAsync { }); } + private _decrementCounts(split: ISplit) { + if (split.trafficTypeName) { + const ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName); + return this.redis.decr(ttKey).then(count => { + if (count === 0) return this.redis.del(ttKey); + }); + } + } + + private _incrementCounts(split: ISplit) { + if (split.trafficTypeName) { + const ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName); + return this.redis.incr(ttKey); + } + } + + /** + * Add a given split. + * The returned promise is resolved when the operation success + * or rejected if it fails (e.g., redis operation fails) + */ addSplit(name: string, split: string): Promise { - return this.redis.set( - this.keys.buildSplitKey(name), split - ).then( - status => status === 'OK' - ); + const splitKey = this.keys.buildSplitKey(name); + return this.redis.get(splitKey).then(splitFromStorage => { + + // handling parsing errors + let parsedPreviousSplit, parsedSplit; + try { + parsedPreviousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : undefined; + parsedSplit = JSON.parse(split); + } catch (e) { + throw new Error('Error parsing split definition: ' + e); + } + + return Promise.all([ + this.redis.set(splitKey, split), + this._incrementCounts(parsedSplit), + // If it's an update, we decrement the traffic type of the existing split, + parsedPreviousSplit && this._decrementCounts(parsedPreviousSplit) + ]); + }).then(([status]) => status === 'OK'); } + /** + * Add a list of splits. + * The returned promise is resolved when the operation success + * or rejected if it fails (e.g., redis operation fails) + */ addSplits(entries: [string, string][]): Promise { - if (entries.length) { - const cmds = entries.map(keyValuePair => ['set', this.keys.buildSplitKey(keyValuePair[0]), keyValuePair[1]]); - - return this.redis.pipeline(cmds) - .exec() - .then(processPipelineAnswer) - .then(answers => answers.map((status: string) => status === 'OK')); - } else { - return Promise.resolve([true]); - } + return Promise.all(entries.map(keyValuePair => this.addSplit(keyValuePair[0], keyValuePair[1]))); } /** - * Remove a given split from Redis. Returns the number of deleted keys. + * Remove a given split. + * The returned promise is resolved when the operation success, with 1 or 0 indicating if the split existed or not. + * or rejected if it fails (e.g., redis operation fails). */ removeSplit(name: string): Promise { - return this.redis.del(this.keys.buildSplitKey(name)); + return this.getSplit(name).then((split) => { + if (split) { + const parsedSplit = JSON.parse(split); + this._decrementCounts(parsedSplit); + } + return this.redis.del(this.keys.buildSplitKey(name)); + }); } /** - * Bulk delete of splits from Redis. Returns the number of deleted keys. + * Remove a list of splits. + * The returned promise is resolved when the operation success, + * or rejected if it fails (e.g., redis operation fails). */ - removeSplits(names: string[]): Promise { - if (names.length) { - return this.redis.del(names.map(n => this.keys.buildSplitKey(n))); - } else { - return Promise.resolve(0); - } + removeSplits(names: string[]): Promise { + return Promise.all(names.map(name => this.removeSplit(name))); } /** * Get split definition or null if it's not defined. + * Returned promise is rejected if redis operation fails. */ getSplit(name: string): Promise { if (this.redisError) { - this.log.error(logPrefix + this.redisError); + this.log.error(LOG_PREFIX + this.redisError); - throw this.redisError; + return Promise.reject(this.redisError); } return this.redis.get(this.keys.buildSplitKey(name)); @@ -93,8 +136,8 @@ export default class SplitsCacheInRedis implements ISplitsCacheAsync { /** * Set till number. - * - * @TODO pending error handling + * The returned promise is resolved when the operation success, + * or rejected if it fails. */ setChangeNumber(changeNumber: number): Promise { return this.redis.set(this.keys.buildSplitsTillKey(), changeNumber + '').then( @@ -103,19 +146,26 @@ export default class SplitsCacheInRedis implements ISplitsCacheAsync { } /** - * Get till number or null if it's not defined. - * - * @TODO pending error handling + * Get till number or -1 if it's not defined. + * The returned promise is resolved with the changeNumber or -1 if it doesn't exist or a redis operation fails. + * The promise will never be rejected. */ getChangeNumber(): Promise { return this.redis.get(this.keys.buildSplitsTillKey()).then((value: string | null) => { const i = parseInt(value as string, 10); return isNaNNumber(i) ? -1 : i; + }).catch((e) => { + this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from storage. Error: ' + e); + return -1; }); } /** + * Get list of all split definitions. + * The returned promise is resolved with the list of split definitions, + * or rejected if redis operation fails. + * * @TODO we need to benchmark which is the maximun number of commands we could * pipeline without kill redis performance. */ @@ -125,54 +175,64 @@ export default class SplitsCacheInRedis implements ISplitsCacheAsync { ).then(processPipelineAnswer); } + /** + * Get list of split names. + * The returned promise is resolved with the list of split names, + * or rejected if redis operation fails. + */ getSplitNames(): Promise { return this.redis.keys(this.keys.searchPatternForSplitKeys()).then( (listOfKeys) => listOfKeys.map(this.keys.extractKey) ); } + /** + * Check traffic type existence. + * The returned promise is resolved with a boolean indicating whether the TT exist or not. + * In case of redis operation failure, the promise resolves with a true value, assuming that the TT might exist. + * It will never be rejected. + */ trafficTypeExists(trafficType: string): Promise { // If there is a number there should be > 0, otherwise the TT is considered as not existent. return this.redis.get(this.keys.buildTrafficTypeKey(trafficType)) .then((ttCount: string | null | number) => { + if (ttCount === null) return false; // if entry doesn't exist, means that TT doesn't exist + ttCount = parseInt(ttCount as string, 10); if (!isFiniteNumber(ttCount) || ttCount < 0) { - this.log.info(logPrefix + `Could not validate traffic type existance of ${trafficType} due to data corruption of some sorts.`); + this.log.info(LOG_PREFIX + `Could not validate traffic type existance of ${trafficType} due to data corruption of some sorts.`); return false; } return ttCount > 0; }) .catch(e => { - this.log.error(logPrefix + `Could not validate traffic type existance of ${trafficType} due to an error: ${e}.`); + this.log.error(LOG_PREFIX + `Could not validate traffic type existance of ${trafficType} due to an error: ${e}.`); // If there is an error, bypass the validation so the event can get tracked. return true; }); } - // noop, just keeping the interface. This is used by client-side implementations only. - usesSegments(): Promise { - return Promise.resolve(true); - } - /** * Delete everything in the current database. * * @NOTE documentation says it never fails. */ - clear(): Promise { + clear() { return this.redis.flushdb().then(status => status === 'OK'); } /** * Fetches multiple splits definitions. + * Returned promise is rejected if redis operation fails. */ getSplits(names: string[]): Promise> { if (this.redisError) { - this.log.error(logPrefix + this.redisError); + this.log.error(LOG_PREFIX + this.redisError); - throw this.redisError; + return Promise.reject(this.redisError); } + const splits: Record = {}; const keys = names.map(name => this.keys.buildSplitKey(name)); return this.redis.mget(...keys) @@ -183,16 +243,9 @@ export default class SplitsCacheInRedis implements ISplitsCacheAsync { return Promise.resolve(splits); }) .catch(e => { - this.log.error(logPrefix + `Could not grab splits due to an error: ${e}.`); + this.log.error(LOG_PREFIX + `Could not grab splits due to an error: ${e}.`); return Promise.reject(e); }); } - /** - * Check if the splits information is already stored in cache. Redis would actually be the cache. - * Noop, just keeping the interface. This is used by client-side implementations only. - */ - checkCache(): Promise { - return Promise.resolve(true); - } } diff --git a/src/storages/inRedis/__tests__/CountsCacheInRedis.spec.ts b/src/storages/inRedis/__tests__/CountsCacheInRedis.spec.ts index 3d1d4cbd..8220a3ce 100644 --- a/src/storages/inRedis/__tests__/CountsCacheInRedis.spec.ts +++ b/src/storages/inRedis/__tests__/CountsCacheInRedis.spec.ts @@ -3,7 +3,7 @@ import KeyBuilderSS from '../../KeyBuilderSS'; import CountsCacheInRedis from '../CountsCacheInRedis'; const prefix = 'counts_cache_ut'; -const metadata = { version: 'v', ip: 'i', hostname: 'n' }; +const metadata = { s: 'version', i: 'ip', n: 'hostname' }; test('COUNTS CACHE IN REDIS / cover basic behavior', async () => { const connection = new Redis({}); diff --git a/src/storages/inRedis/__tests__/EventsCacheInRedis.spec.ts b/src/storages/inRedis/__tests__/EventsCacheInRedis.spec.ts index c4384726..2ed55687 100644 --- a/src/storages/inRedis/__tests__/EventsCacheInRedis.spec.ts +++ b/src/storages/inRedis/__tests__/EventsCacheInRedis.spec.ts @@ -1,76 +1,58 @@ import Redis from 'ioredis'; -import find from 'lodash/find'; -import isEqual from 'lodash/isEqual'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; -import KeyBuilderSS from '../../KeyBuilderSS'; import EventsCacheInRedis from '../EventsCacheInRedis'; -import { metadataBuilder } from '../index'; +import { fakeMetadata, fakeEvent1, fakeEvent1stored, fakeEvent2, fakeEvent2stored, fakeEvent3, fakeEvent3stored } from '../../pluggable/__tests__/EventsCachePluggable.spec'; const prefix = 'events_cache_ut'; -const metadata = { version: 'js_someversion', ip: 'some_ip', hostname: 'some_hostname' }; +const eventsKey = `${prefix}.events`; +const nonListKey = 'non-list-key'; -test('EVENTS CACHE IN REDIS / should incrementally store values in redis', async () => { +test('EVENTS CACHE IN REDIS / `track`, `count`, `popNWithMetadata` and `drop` methods', async () => { const connection = new Redis(); - // This piece is being tested elsewhere. - const keys = new KeyBuilderSS(prefix, metadata); - const key = keys.buildEventsKey(); - - const fakeRedisMetadata = metadataBuilder(metadata); - const fakeEvent1 = { event: 1 }; - const fakeEvent2 = { event: '2' }; - const fakeEvent3 = { event: null }; // Clean up in case there are still keys there. - await connection.del(key); + await connection.del(eventsKey); - let redisValues = await connection.lrange(key, 0, -1); + let redisValues = await connection.lrange(eventsKey, 0, -1); expect(redisValues.length).toBe(0); // control assertion, there are no events previously queued. - const cache = new EventsCacheInRedis(loggerMock, keys, connection, fakeRedisMetadata); + const cache = new EventsCacheInRedis(loggerMock, eventsKey, connection, fakeMetadata); // I'll use a "bad" instance so I can force an issue with the rpush command. I'll store an integer and will make the cache try to use rpush there. - await connection.set('non-list-key', 10); - // @ts-expect-error - const faultyCache = new EventsCacheInRedis(loggerMock, { - buildEventsKey: () => 'non-list-key' - }, connection, fakeRedisMetadata); + await connection.set(nonListKey, 10); + + const faultyCache = new EventsCacheInRedis(loggerMock, nonListKey, connection, fakeMetadata); - // @ts-expect-error expect(await cache.track(fakeEvent1)).toBe(true); // If the queueing operation was successful, it should resolve the returned promise with "true" - // @ts-expect-error expect(await cache.track(fakeEvent2)).toBe(true); // If the queueing operation was successful, it should resolve the returned promise with "true" - // @ts-expect-error expect(await cache.track(fakeEvent3)).toBe(true); // If the queueing operation was successful, it should resolve the returned promise with "true" - // @ts-expect-error expect(await faultyCache.track(fakeEvent1)).toBe(false); // If the queueing operation was NOT successful, it should resolve the returned promise with "false" instead of rejecting it. - // @ts-expect-error expect(await faultyCache.track(fakeEvent2)).toBe(false); // If the queueing operation was NOT successful, it should resolve the returned promise with "false" instead of rejecting it. - // @ts-expect-error expect(await faultyCache.track(fakeEvent3)).toBe(false); // If the queueing operation was NOT successful, it should resolve the returned promise with "false" instead of rejecting it. - redisValues = await connection.lrange(key, 0, -1); - + // Events should be in redis + redisValues = await connection.lrange(eventsKey, 0, -1); expect(redisValues.length).toBe(3); // After pushing we should have on Redis as many events as we have stored. expect(typeof redisValues[0]).toBe('string'); // All elements should be strings since those are stringified JSONs. expect(typeof redisValues[1]).toBe('string'); // All elements should be strings since those are stringified JSONs. expect(typeof redisValues[2]).toBe('string'); // All elements should be strings since those are stringified JSONs. - const findMatchingElem = (event: any) => { - return find(redisValues, elem => { - const parsedElem = JSON.parse(elem); - return isEqual(parsedElem.e, event) && isEqual(parsedElem.m, fakeRedisMetadata); - }); - }; + // Testing popNWithMetadata + expect(await cache.popNWithMetadata(2)).toEqual([fakeEvent1stored, fakeEvent2stored]); // events are removed in FIFO order + expect(await cache.count()).toBe(1); + + expect(await cache.popNWithMetadata(1)).toEqual([fakeEvent3stored]); + expect(await cache.count()).toBe(0); + + expect(await cache.popNWithMetadata(100)).toEqual([]); // no more events - /* If the elements are found, then the values are correct. */ - const foundEv1 = findMatchingElem(fakeEvent1); - const foundEv2 = findMatchingElem(fakeEvent2); - const foundEv3 = findMatchingElem(fakeEvent3); - expect(foundEv1).not.toBe(undefined); // Events stored on redis matched the values we are expecting. - expect(foundEv2).not.toBe(undefined); // Events stored on redis matched the values we are expecting. - expect(foundEv3).not.toBe(undefined); // Events stored on redis matched the values we are expecting. + // Testing drop method + await Promise.all([cache.track(fakeEvent1), cache.track(fakeEvent2), cache.track(fakeEvent3)]); + expect(await cache.count()).toBe(3); + await cache.drop(); + expect(await cache.count()).toBe(0); // storage should be empty after droping it // Clean up then end. - await connection.del(key); + await connection.del(eventsKey, nonListKey); await connection.quit(); }); diff --git a/src/storages/inRedis/__tests__/ImpressionsCacheInRedis.spec.ts b/src/storages/inRedis/__tests__/ImpressionsCacheInRedis.spec.ts index 36892885..0701bd7b 100644 --- a/src/storages/inRedis/__tests__/ImpressionsCacheInRedis.spec.ts +++ b/src/storages/inRedis/__tests__/ImpressionsCacheInRedis.spec.ts @@ -1,110 +1,92 @@ import Redis from '../RedisAdapter'; -import KeyBuilderSS from '../../KeyBuilderSS'; import ImpressionsCacheInRedis from '../ImpressionsCacheInRedis'; import IORedis, { BooleanResponse } from 'ioredis'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import { fakeMetadata, o1, o2, o3, o1stored, o2stored, o3stored } from '../../pluggable/__tests__/ImpressionsCachePluggable.spec'; -test('IMPRESSIONS CACHE IN REDIS / should incrementally store values', async () => { - const prefix = 'impr_cache_ut'; - const impressionsKey = `${prefix}.impressions`; - const testMeta = { thisIsTheMeta: true }; - const connection = new Redis(loggerMock, {}); - // @ts-expect-error - const keys = new KeyBuilderSS(prefix); // @ts-expect-error - const c = new ImpressionsCacheInRedis(keys, connection, testMeta); - - const o1 = { - feature: 'test1', - keyName: 'facundo@split.io', - treatment: 'on', - time: Date.now(), - changeNumber: 1 - }; - - const o2 = { - feature: 'test2', - keyName: 'pepep@split.io', - treatment: 'A', - time: Date.now(), - bucketingKey: '1234-5678', - label: 'is in segment', - changeNumber: 1 - }; - - const o3 = { - feature: 'test3', - keyName: 'pipiip@split.io', - treatment: 'B', - time: Date.now(), - changeNumber: 1 - }; - - // cleanup - await connection.del(impressionsKey); - - // @ts-expect-error - await c.track([o1]); // @ts-expect-error - await c.track([o2, o3]); - const state = await connection.lrange(impressionsKey, 0, -1); - // This is testing both the track and the toJSON method. - expect(state[0]).toBe(JSON.stringify({ - m: testMeta, - i: { k: o1.keyName, f: o1.feature, t: o1.treatment, c: o1.changeNumber, m: o1.time } - })); - expect(state[1]).toBe(JSON.stringify({ - m: testMeta, - i: { k: o2.keyName, b: o2.bucketingKey, f: o2.feature, t: o2.treatment, r: o2.label, c: o2.changeNumber, m: o2.time } - })); - expect(state[2]).toBe(JSON.stringify({ - m: testMeta, - i: { k: o3.keyName, f: o3.feature, t: o3.treatment, c: o3.changeNumber, m: o3.time } - })); - - await connection.del(impressionsKey); - await connection.quit(); -}); +describe('IMPRESSIONS CACHE IN REDIS', () => { + + test('`track`, `count`, `popNWithMetadata` and `drop` methods', async () => { + const connection = new Redis(loggerMock, {}); + const impressionsKey = 'impr_cache_ut.impressions'; + + const c = new ImpressionsCacheInRedis(loggerMock, impressionsKey, connection, fakeMetadata); + + // cleanup + await connection.del(impressionsKey); + + // Testing track and count methods. + await c.track([o1]); + expect(await c.count()).toBe(1); // count should return stored items + + await c.track([o2, o3]); + expect(await c.count()).toBe(3); // count should return stored items + + // Impressions should be in redis + const state = await connection.lrange(impressionsKey, 0, -1); + expect(state.length).toBe(3); // After pushing we should have on Redis as many impressions as we have stored. + expect(state[0]).toBe(JSON.stringify(o1stored)); + expect(state[1]).toBe(JSON.stringify(o2stored)); + expect(state[2]).toBe(JSON.stringify(o3stored)); + + // Testing popNWithMetadata and private toJSON methods. + expect(await c.popNWithMetadata(2)).toEqual([o1stored, o2stored]); // impressions are removed in FIFO order + expect(await c.count()).toBe(1); + + expect(await c.popNWithMetadata(1)).toEqual([o3stored]); + expect(await c.count()).toBe(0); + expect(await c.popNWithMetadata(100)).toEqual([]); // no more impressions + + // Testing drop method + await c.track([o1, o2, o3]); + expect(await c.count()).toBe(3); + await c.drop(); + expect(await c.count()).toBe(0); // storage should be empty after droping it -test('IMPRESSIONS CACHE IN REDIS / should not resolve track before calling expire', async (done) => { - const prefix = 'impr_cache_ut_2'; - const impressionsKey = `${prefix}.impressions`; - const testMeta = { thisIsTheMeta: true }; - const connection = new Redis(loggerMock, {}); - // @ts-expect-error - const keys = new KeyBuilderSS(prefix); // @ts-expect-error - const c = new ImpressionsCacheInRedis(keys, connection, testMeta); - - const i1 = { feature: 'test4', keyName: 'nicolas@split.io', treatment: 'off', time: Date.now(), changeNumber: 1 }; - const i2 = { feature: 'test5', keyName: 'matias@split.io', treatment: 'on', time: Date.now(), changeNumber: 2 }; - - const spy1 = jest.spyOn(connection, 'rpush'); - const spy2 = jest.spyOn(connection, 'expire'); - - // Crap so we can reproduce the latency as we would have on a remote server. - const originalExpire = connection.expire; - - connection.expire = function patchedForTestRedisExpire(...args: [key: IORedis.KeyType, seconds: number]) { - return new Promise((res, rej) => { - setTimeout(() => { - originalExpire.apply(connection, args).then(res).catch(rej); - }, 150); // 150ms of delay on the expire + await connection.del(impressionsKey); + await connection.quit(); + }); + + test('`track` should not resolve before calling expire', async () => { + const impressionsKey = 'impr_cache_ut_2.impressions'; + const connection = new Redis(loggerMock, {}); + + const c = new ImpressionsCacheInRedis(loggerMock, impressionsKey, connection, fakeMetadata); + + const i1 = { feature: 'test4', keyName: 'nicolas@split.io', treatment: 'off', time: Date.now(), changeNumber: 1 }; + const i2 = { feature: 'test5', keyName: 'matias@split.io', treatment: 'on', time: Date.now(), changeNumber: 2 }; + + const spy1 = jest.spyOn(connection, 'rpush'); + const spy2 = jest.spyOn(connection, 'expire'); + + // Crap so we can reproduce the latency as we would have on a remote server. + const originalExpire = connection.expire; + + connection.expire = function patchedForTestRedisExpire(...args: [key: IORedis.KeyType, seconds: number]) { + return new Promise((res, rej) => { + setTimeout(() => { + originalExpire.apply(connection, args).then(res).catch(rej); + }, 150); // 150ms of delay on the expire + }); + }; + + // cleanup prior to test. + await connection.del(impressionsKey); + + // @ts-expect-error + await c.track([i1, i2]).then(() => { + connection.del(impressionsKey); + connection.quit(); // Try to disconnect right away. + expect(spy1).toBeCalled(); // Redis rpush was called once before executing external callback. + // Following assertion fails if the expire takes place after disconnected and throws unhandledPromiseRejection + expect(spy2).toBeCalled(); // Redis expire was called once before executing external callback. + }).catch(e => { + throw new Error(`An error was generated from the redis expire tests: ${e}`); + }).then(() => { + // Finally clean up and wrap up. + spy1.mockRestore(); + spy2.mockRestore(); }); - }; - - // cleanup prior to test. - await connection.del(impressionsKey); - - // @ts-expect-error - c.track([i1, i2]).then(() => { - connection.quit(); // Try to disconnect right away. - expect(spy1).toBeCalled(); // Redis rpush was called once before executing external callback. - // Following assertion fails if the expire takes place after disconnected and throws unhandledPromiseRejection - expect(spy2).toBeCalled(); // Redis expire was called once before executing external callback. - }).catch(e => { - throw new Error(`An error was generated from the redis expire tests: ${e}`); - }).then(() => { - // Finally clean up and wrap up. - spy1.mockRestore(); - spy2.mockRestore(); - done(); }); + }); diff --git a/src/storages/inRedis/__tests__/LatenciesCacheInRedis.spec.ts b/src/storages/inRedis/__tests__/LatenciesCacheInRedis.spec.ts index 0e672adb..e592bdd9 100644 --- a/src/storages/inRedis/__tests__/LatenciesCacheInRedis.spec.ts +++ b/src/storages/inRedis/__tests__/LatenciesCacheInRedis.spec.ts @@ -3,7 +3,7 @@ import KeyBuilderSS from '../../KeyBuilderSS'; import LatenciesCacheInRedis from '../LatenciesCacheInRedis'; const prefix = 'latencies_cache_UT'; -const metadata = { version: 'js_someversion', ip: 'some_ip', hostname: 'some_hostname' }; +const metadata = { s: 'js_someversion', i: 'some_ip', n: 'some_hostname' }; test('METRICS (LATENCIES) CACHE IN REDIS / should count based on ranges', async () => { const connection = new Redis(); diff --git a/src/storages/inRedis/__tests__/RedisAdapter.spec.ts b/src/storages/inRedis/__tests__/RedisAdapter.spec.ts index ba369d8c..9557162d 100644 --- a/src/storages/inRedis/__tests__/RedisAdapter.spec.ts +++ b/src/storages/inRedis/__tests__/RedisAdapter.spec.ts @@ -6,7 +6,7 @@ import { _Set, setToArray } from '../../../utils/lang/sets'; // Mocking sdkLogger import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; -const logPrefix = 'storage:redis-adapter: '; +const LOG_PREFIX = 'storage:redis-adapter: '; // Mocking ioredis @@ -188,7 +188,7 @@ describe('STORAGE Redis Adapter', () => { secondCallArgs[1](); // Execute the callback for "close" expect(loggerMock.info).toBeCalledTimes(1); // The callback for the "close" event will only log info to the user about what is going on. - expect(loggerMock.info.mock.calls[0]).toEqual([logPrefix + 'Redis connection closed.']); // The callback for the "close" event will only log info to the user about what is going on. + expect(loggerMock.info.mock.calls[0]).toEqual([LOG_PREFIX + 'Redis connection closed.']); // The callback for the "close" event will only log info to the user about what is going on. loggerMock.info.mockClear(); expect(loggerMock.info).not.toBeCalled(); // Control assertion @@ -198,7 +198,7 @@ describe('STORAGE Redis Adapter', () => { firstCallArgs[1](); expect(loggerMock.info).toBeCalledTimes(1); // The callback for the "ready" event will inform the user about the trigger. - expect(loggerMock.info).toBeCalledWith(logPrefix + 'Redis connection established. Queued commands: 0.'); // The callback for the "ready" event will inform the user about the trigger. + expect(loggerMock.info).toBeCalledWith(LOG_PREFIX + 'Redis connection established. Queued commands: 0.'); // The callback for the "ready" event will inform the user about the trigger. expect(instance._notReadyCommandsQueue).toBe(undefined); // After the DB is ready, it will clean up the offline commands queue so we do not queue commands anymore. // Don't do this at home @@ -222,9 +222,9 @@ describe('STORAGE Redis Adapter', () => { expect(loggerMock.info).toBeCalledTimes(3); // If we had queued commands, it will log the event (1 call) as well as each executed command (n calls). expect(loggerMock.info.mock.calls).toEqual([ - [logPrefix + 'Redis connection established. Queued commands: 2.'], // The callback for the "ready" event will inform the user about the trigger and the amount of queued commands. - [logPrefix + 'Executing queued GET command.'], // If we had queued, it will log the event as well as each executed command. - [logPrefix + 'Executing queued SET command.'] // If we had queued commands, it will log the event as well as each executed command. + [LOG_PREFIX + 'Redis connection established. Queued commands: 2.'], // The callback for the "ready" event will inform the user about the trigger and the amount of queued commands. + [LOG_PREFIX + 'Executing queued GET command.'], // If we had queued, it will log the event as well as each executed command. + [LOG_PREFIX + 'Executing queued SET command.'] // If we had queued commands, it will log the event as well as each executed command. ]); expect(queuedGetCommand.command).toBeCalledTimes(1); // It will execute each queued command. @@ -287,7 +287,7 @@ describe('STORAGE Redis Adapter', () => { commandTimeoutResolver.rej('test'); setTimeout(() => { // Allow the promises to tick. expect(instance._runningCommands.has(commandTimeoutResolver.originalPromise)).toBe(false); // After a command finishes with error, it's promise is removed from the instance._runningCommands queue. - expect(loggerMock.error.mock.calls[index]).toEqual([`${logPrefix}${methodName} operation threw an error or exceeded configured timeout of 5000ms. Message: test`]); // The log error method should be called with the corresponding messages, depending on the method, error and operationTimeout. + expect(loggerMock.error.mock.calls[index]).toEqual([`${LOG_PREFIX}${methodName} operation threw an error or exceeded configured timeout of 5000ms. Message: test`]); // The log error method should be called with the corresponding messages, depending on the method, error and operationTimeout. }, 0); }); @@ -334,7 +334,7 @@ describe('STORAGE Redis Adapter', () => { expect(ioredisMock.disconnect).not.toBeCalled(); // Original method should not be called right away. setTimeout(() => { // o queued commands timeout wrapper. - expect(loggerMock.debug.mock.calls).toEqual([[logPrefix + 'No commands pending execution, disconnect.']]); + expect(loggerMock.debug.mock.calls).toEqual([[LOG_PREFIX + 'No commands pending execution, disconnect.']]); expect(ioredisMock.disconnect).toBeCalledTimes(1); // Original method should have been called once, asynchronously loggerMock.debug.mockClear(); ioredisMock.disconnect.mockClear(); @@ -347,11 +347,11 @@ describe('STORAGE Redis Adapter', () => { rejectedPromise.catch(() => { }); // Swallow the unhandled to avoid unhandledRejection warns setTimeout(() => { // queued with rejection timeout wrapper - expect(loggerMock.info.mock.calls).toEqual([[logPrefix + 'Attempting to disconnect but there are 2 commands still waiting for resolution. Defering disconnection until those finish.']]); + expect(loggerMock.info.mock.calls).toEqual([[LOG_PREFIX + 'Attempting to disconnect but there are 2 commands still waiting for resolution. Defering disconnection until those finish.']]); Promise.all(setToArray(instance._runningCommands)).catch(e => { setImmediate(() => { // Allow the callback to execute before checking. - expect(loggerMock.warn.mock.calls[0]).toEqual([`${logPrefix}Pending commands finished with error: ${e}. Proceeding with disconnection.`]); // Should warn about the error but tell user that will disconnect anyways. + expect(loggerMock.warn.mock.calls[0]).toEqual([`${LOG_PREFIX}Pending commands finished with error: ${e}. Proceeding with disconnection.`]); // Should warn about the error but tell user that will disconnect anyways. expect(ioredisMock.disconnect).toBeCalledTimes(1); // Original method should have been called once, asynchronously loggerMock.info.mockClear(); @@ -367,11 +367,11 @@ describe('STORAGE Redis Adapter', () => { instance._runningCommands.add(Promise.resolve()); setTimeout(() => { - expect(loggerMock.info.mock.calls).toEqual([[logPrefix + 'Attempting to disconnect but there are 4 commands still waiting for resolution. Defering disconnection until those finish.']]); + expect(loggerMock.info.mock.calls).toEqual([[LOG_PREFIX + 'Attempting to disconnect but there are 4 commands still waiting for resolution. Defering disconnection until those finish.']]); Promise.all(setToArray(instance._runningCommands)).then(() => { // This one will go through success path setImmediate(() => { - expect(loggerMock.debug.mock.calls).toEqual([[logPrefix + 'Pending commands finished successfully, disconnecting.']]); + expect(loggerMock.debug.mock.calls).toEqual([[LOG_PREFIX + 'Pending commands finished successfully, disconnecting.']]); expect(ioredisMock.disconnect).toBeCalledTimes(1); // Original method should have been called once, asynchronously }); }); diff --git a/src/storages/inRedis/__tests__/SegmentsCacheInRedis.spec.ts b/src/storages/inRedis/__tests__/SegmentsCacheInRedis.spec.ts index 57f490e4..dc3ea4b8 100644 --- a/src/storages/inRedis/__tests__/SegmentsCacheInRedis.spec.ts +++ b/src/storages/inRedis/__tests__/SegmentsCacheInRedis.spec.ts @@ -1,54 +1,59 @@ import Redis from 'ioredis'; import SegmentsCacheInRedis from '../SegmentsCacheInRedis'; import KeyBuilderSS from '../../KeyBuilderSS'; +import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; -test('SEGMENTS CACHE IN Redis / suite', async () => { - const connection = new Redis(); - // @ts-expect-error - const keys = new KeyBuilderSS(); - const cache = new SegmentsCacheInRedis(keys, connection); +// @ts-expect-error. Doesn't require metadata +const keys = new KeyBuilderSS(); - await cache.clear(); +describe('SEGMENTS CACHE IN REDIS', () => { - await cache.addToSegment('mocked-segment', ['a', 'b', 'c']); + test('isInSegment, set/getChangeNumber, add/removeFromSegment', async () => { + const connection = new Redis(); + const cache = new SegmentsCacheInRedis(loggerMock, keys, connection); - await cache.setChangeNumber('mocked-segment', 1); + await cache.clear(); - await cache.removeFromSegment('mocked-segment', ['d']); + await cache.addToSegment('mocked-segment', ['a', 'b', 'c']); - expect(await cache.getChangeNumber('mocked-segment') === 1).toBe(true); + await cache.setChangeNumber('mocked-segment', 1); - await cache.addToSegment('mocked-segment', ['d', 'e']); + await cache.removeFromSegment('mocked-segment', ['d']); - await cache.removeFromSegment('mocked-segment', ['a', 'c']); + expect(await cache.getChangeNumber('mocked-segment') === 1).toBe(true); - expect(await cache.getChangeNumber('mocked-segment') === 1).toBe(true); + expect(await cache.getChangeNumber('inexistent-segment')).toBe(-1); // -1 if the segment doesn't exist - expect(await cache.isInSegment('mocked-segment', 'a')).toBe(false); - expect(await cache.isInSegment('mocked-segment', 'b')).toBe(true); - expect(await cache.isInSegment('mocked-segment', 'c')).toBe(false); - expect(await cache.isInSegment('mocked-segment', 'd')).toBe(true); - expect(await cache.isInSegment('mocked-segment', 'e')).toBe(true); + await cache.addToSegment('mocked-segment', ['d', 'e']); - await connection.quit(); -}); + await cache.removeFromSegment('mocked-segment', ['a', 'c']); + + expect(await cache.getChangeNumber('mocked-segment') === 1).toBe(true); + + expect(await cache.isInSegment('mocked-segment', 'a')).toBe(false); + expect(await cache.isInSegment('mocked-segment', 'b')).toBe(true); + expect(await cache.isInSegment('mocked-segment', 'c')).toBe(false); + expect(await cache.isInSegment('mocked-segment', 'd')).toBe(true); + expect(await cache.isInSegment('mocked-segment', 'e')).toBe(true); + + await connection.quit(); + }); -test('SEGMENTS CACHE IN Redis / register segments', async () => { - const connection = new Redis(); - // @ts-expect-error - const keys = new KeyBuilderSS(); + test('registerSegment / getRegisteredSegments', async () => { + const connection = new Redis(); + const cache = new SegmentsCacheInRedis(loggerMock, keys, connection); - const cache = new SegmentsCacheInRedis(keys, connection); + await cache.clear(); - await cache.clear(); + await cache.registerSegments(['s1']); + await cache.registerSegments(['s2']); + await cache.registerSegments(['s2', 's3', 's4']); - await cache.registerSegment('s1'); - await cache.registerSegment('s2'); - await cache.registerSegments(['s2', 's3', 's4']); + const segments = await cache.getRegisteredSegments(); - const segments = await cache.getRegisteredSegments(); + ['s1', 's2', 's3', 's4'].forEach(s => expect(segments.indexOf(s) !== -1).toBe(true)); - ['s1', 's2', 's3', 's4'].forEach(s => expect(segments.indexOf(s) !== -1).toBe(true)); + await connection.quit(); + }); - await connection.quit(); }); diff --git a/src/storages/inRedis/__tests__/SplitsCacheInRedis.spec.ts b/src/storages/inRedis/__tests__/SplitsCacheInRedis.spec.ts index 1c03268e..7ab8384b 100644 --- a/src/storages/inRedis/__tests__/SplitsCacheInRedis.spec.ts +++ b/src/storages/inRedis/__tests__/SplitsCacheInRedis.spec.ts @@ -2,83 +2,157 @@ import Redis from 'ioredis'; import SplitsCacheInRedis from '../SplitsCacheInRedis'; import KeyBuilderSS from '../../KeyBuilderSS'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import { splitWithUserTT, splitWithAccountTT } from '../../__tests__/testUtils'; -test('SPLITS CACHE / Redis', async () => { - const connection = new Redis(); - // @ts-expect-error - const keys = new KeyBuilderSS(); - const cache = new SplitsCacheInRedis(loggerMock, keys, connection); +const prefix = 'splits_cache_ut'; - await cache.clear(); +describe('SPLITS CACHE REDIS', () => { - await cache.addSplits([ - ['lol1', 'something'], - ['lol2', 'something else'] - ]); + test('add/remove/get splits & set/get change number', async () => { + const connection = new Redis(); + // @ts-expect-error + const keysBuilder = new KeyBuilderSS(prefix); + const cache = new SplitsCacheInRedis(loggerMock, keysBuilder, connection); - let values = await cache.getAll(); + await cache.clear(); - expect(values.indexOf('something') !== -1).toBe(true); - expect(values.indexOf('something else') !== -1).toBe(true); + await cache.addSplits([ + ['lol1', splitWithUserTT], + ['lol2', splitWithAccountTT] + ]); - let splitNames = await cache.getSplitNames(); + let values = await cache.getAll(); - expect(splitNames.indexOf('lol1') !== -1).toBe(true); - expect(splitNames.indexOf('lol2') !== -1).toBe(true); + expect(values.indexOf(splitWithUserTT) !== -1).toBe(true); + expect(values.indexOf(splitWithAccountTT) !== -1).toBe(true); - await cache.removeSplit('lol1'); + let splitNames = await cache.getSplitNames(); - values = await cache.getAll(); + expect(splitNames.indexOf('lol1') !== -1).toBe(true); + expect(splitNames.indexOf('lol2') !== -1).toBe(true); - expect(values.indexOf('something') === -1).toBe(true); - expect(values.indexOf('something else') !== -1).toBe(true); + await cache.removeSplit('lol1'); - expect(await cache.getSplit('lol1') == null).toBe(true); - expect(await cache.getSplit('lol2') === 'something else').toBe(true); + values = await cache.getAll(); - await cache.setChangeNumber(123); - expect(await cache.getChangeNumber() === 123).toBe(true); + expect(values.indexOf(splitWithUserTT) === -1).toBe(true); + expect(values.indexOf(splitWithAccountTT) !== -1).toBe(true); - splitNames = await cache.getSplitNames(); + expect(await cache.getSplit('lol1') == null).toBe(true); + expect(await cache.getSplit('lol2') === splitWithAccountTT).toBe(true); - expect(splitNames.indexOf('lol1') === -1).toBe(true); - expect(splitNames.indexOf('lol2') !== -1).toBe(true); + await cache.setChangeNumber(123); + expect(await cache.getChangeNumber() === 123).toBe(true); - const splits = await cache.getSplits(['lol1', 'lol2']); - expect(splits['lol1'] === null).toBe(true); - expect(splits['lol2'] === 'something else').toBe(true); + splitNames = await cache.getSplitNames(); - await connection.quit(); -}); + expect(splitNames.indexOf('lol1') === -1).toBe(true); + expect(splitNames.indexOf('lol2') !== -1).toBe(true); + + const splits = await cache.getSplits(['lol1', 'lol2']); + expect(splits['lol1'] === null).toBe(true); + expect(splits['lol2'] === splitWithAccountTT).toBe(true); + + await connection.del(keysBuilder.buildTrafficTypeKey('account_tt')); + await connection.del(keysBuilder.buildSplitKey('lol2')); + await connection.del(keysBuilder.buildSplitsTillKey()); + await connection.quit(); + }); + + test('trafficTypeExists', async () => { + const prefix = 'splits_cache_ut'; + const connection = new Redis(); + // @ts-expect-error + const keysBuilder = new KeyBuilderSS(prefix); + const cache = new SplitsCacheInRedis(loggerMock, keysBuilder, connection); + + await cache.addSplits([ + ['split1', splitWithUserTT], + ['split2', splitWithAccountTT], + ['split3', splitWithUserTT], + ['malformed', '{}'] + ]); + await cache.addSplit('split4', splitWithUserTT); + await cache.addSplit('split4', splitWithUserTT); // trying to add the same definition for an already added split will not have effect + + expect(await cache.trafficTypeExists('user_tt')).toBe(true); + expect(await cache.trafficTypeExists('account_tt')).toBe(true); + expect(await cache.trafficTypeExists('not_existent_tt')).toBe(false); + + await cache.removeSplit('split4'); + + expect(await cache.trafficTypeExists('user_tt')).toBe(true); + expect(await cache.trafficTypeExists('account_tt')).toBe(true); + + expect(await connection.get(keysBuilder.buildTrafficTypeKey('account_tt'))).toBe('1'); + + await cache.removeSplits(['split3', 'split2']); // it'll invoke a loop of removeSplit + + expect(await cache.trafficTypeExists('user_tt')).toBe(true); + expect(await cache.trafficTypeExists('account_tt')).toBe(false); + + expect(await connection.get(keysBuilder.buildTrafficTypeKey('account_tt'))).toBe(null); // TT entry should be removed in the wrapper + + await cache.removeSplit('split1'); + + expect(await cache.trafficTypeExists('user_tt')).toBe(false); + expect(await cache.trafficTypeExists('account_tt')).toBe(false); + + await cache.addSplit('split1', splitWithUserTT); + expect(await cache.trafficTypeExists('user_tt')).toBe(true); + + await cache.addSplit('split1', splitWithAccountTT); + expect(await cache.trafficTypeExists('account_tt')).toBe(true); + expect(await cache.trafficTypeExists('user_tt')).toBe(false); + + await connection.del(keysBuilder.buildTrafficTypeKey('account_tt')); + await connection.del(keysBuilder.buildSplitKey('malformed')); + await connection.del(keysBuilder.buildSplitKey('split1')); + await connection.quit(); + + }); + + test('killLocally', async () => { + const connection = new Redis(); + // @ts-expect-error + const keys = new KeyBuilderSS(prefix); + const cache = new SplitsCacheInRedis(loggerMock, keys, connection); + + await cache.addSplit('lol1', splitWithUserTT); + await cache.addSplit('lol2', splitWithAccountTT); + const initialChangeNumber = await cache.getChangeNumber(); + + // kill an non-existent split + let updated = await cache.killLocally('nonexistent_split', 'other_treatment', 101); + const nonexistentSplit = await cache.getSplit('nonexistent_split'); + + expect(updated).toBe(false); // killLocally resolves without update if split doesn't exist + expect(nonexistentSplit).toBe(null); // non-existent split keeps being non-existent -test('SPLITS CACHE / Redis / trafficTypeExists tests', async () => { - const prefix = 'splits_cache_ut'; - const connection = new Redis(); - // @ts-expect-error - const keys = new KeyBuilderSS(prefix); - const cache = new SplitsCacheInRedis(loggerMock, keys, connection); + // kill an existent split + updated = await cache.killLocally('lol1', 'some_treatment', 100); + let lol1Split = JSON.parse(await cache.getSplit('lol1') as string); - const testTTName = 'tt_test_name'; - const testTTNameNoCount = 'tt_test_name_2'; - const testTTNameInvalid = 'tt_test_name_3'; - const ttKey = keys.buildTrafficTypeKey(testTTName); - const ttKeyNoCount = keys.buildTrafficTypeKey(testTTNameNoCount); - const ttKeyInvalid = keys.buildTrafficTypeKey(testTTNameInvalid); + expect(updated).toBe(true); // killLocally resolves with update if split is changed + expect(lol1Split.killed).toBe(true); // existing split must be killed + expect(lol1Split.defaultTreatment).toBe('some_treatment'); // existing split must have new default treatment + expect(lol1Split.changeNumber).toBe(100); // existing split must have the given change number + expect(await cache.getChangeNumber()).toBe(initialChangeNumber); // cache changeNumber is not changed - await cache.clear(); + // not update if changeNumber is old + updated = await cache.killLocally('lol1', 'some_treatment_2', 90); + lol1Split = JSON.parse(await cache.getSplit('lol1') as string); - await connection.set(ttKey, 3); - await connection.set(ttKeyNoCount, 0); - await connection.set(ttKeyInvalid, 'NaN'); + expect(updated).toBe(false); // killLocally resolves without update if changeNumber is old + expect(lol1Split.defaultTreatment).not.toBe('some_treatment_2'); // existing split is not updated if given changeNumber is older - expect(await cache.trafficTypeExists(testTTName)).toBe(true); - expect(await cache.trafficTypeExists(testTTNameNoCount)).toBe(false); - expect(await cache.trafficTypeExists(ttKeyInvalid)).toBe(false); - expect(await cache.trafficTypeExists('not_existent_tt')).toBe(false); + // Delete splits and TT keys + await cache.removeSplits(['lol1', 'lol2']); + await connection.del(keys.buildTrafficTypeKey('account_tt')); + await connection.del(keys.buildTrafficTypeKey('user_tt')); + expect(await connection.keys(`${prefix}*`)).toHaveLength(0); - await connection.del(ttKey); - await connection.del(ttKeyNoCount); - await connection.del(ttKeyInvalid); + await connection.quit(); + }); - await connection.quit(); }); diff --git a/src/storages/inRedis/__tests__/index.spec.ts b/src/storages/inRedis/__tests__/index.spec.ts deleted file mode 100644 index fa62acf3..00000000 --- a/src/storages/inRedis/__tests__/index.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { metadataBuilder } from '../index'; -import { UNKNOWN } from '../../../utils/constants'; -import { IMetadata } from '../../../dtos/types'; - -describe('metadataBuilder', () => { - - test('metadata object creation', () => { - const metadata = { - version: 'test.version', - ip: 'test.ip', - hostname: 'test.hostname' - }; - let meta = metadataBuilder(metadata); - - expect(meta.s).toBe(metadata.version); // SDK Version should be returned as the "s" property. - expect(meta.i).toBe(metadata.ip); // SDK runtime IP should be returned as the "i" property. - expect(meta.n).toBe(metadata.hostname); // SDK runtime hostname should be returned as the "n" property. - - expect(meta !== metadataBuilder(metadata)).toBe(true); // Should return a new object each time we call it. - }); - - test('creation with undefined properties', () => { - const metadata: IMetadata = { - version: 'test.version', ip: false, hostname: false - }; - let meta = metadataBuilder(metadata); - - expect(meta.s).toBe(metadata.version); // SDK Version should be returned as the "s" property. - expect(meta.i).toBe(UNKNOWN); // The "i" property should be 'UNKNOWN' if IP value is undefined. - expect(meta.n).toBe(UNKNOWN); // The "n" property should be 'UNKNOWN' if hostname value is undefined. - }); - -}); diff --git a/src/storages/inRedis/constants.ts b/src/storages/inRedis/constants.ts new file mode 100644 index 00000000..a3856844 --- /dev/null +++ b/src/storages/inRedis/constants.ts @@ -0,0 +1 @@ +export const LOG_PREFIX = 'storage:redis: '; diff --git a/src/storages/inRedis/index.ts b/src/storages/inRedis/index.ts index 52093236..b13413ee 100644 --- a/src/storages/inRedis/index.ts +++ b/src/storages/inRedis/index.ts @@ -1,6 +1,6 @@ import RedisAdapter from './RedisAdapter'; -import { IStorageAsync, IStorageFactoryParams } from '../types'; -import { IMetadata, IRedisMetadata } from '../../dtos/types'; +import { IStorageAsync, IStorageAsyncFactory, IStorageFactoryParams } from '../types'; +import { validatePrefix } from '../KeyBuilder'; import KeyBuilderSS from '../KeyBuilderSS'; import SplitsCacheInRedis from './SplitsCacheInRedis'; import SegmentsCacheInRedis from './SegmentsCacheInRedis'; @@ -8,50 +8,36 @@ import ImpressionsCacheInRedis from './ImpressionsCacheInRedis'; import EventsCacheInRedis from './EventsCacheInRedis'; import LatenciesCacheInRedis from './LatenciesCacheInRedis'; import CountsCacheInRedis from './CountsCacheInRedis'; -import { UNKNOWN } from '../../utils/constants'; -import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../../readiness/constants'; +import { STORAGE_REDIS } from '../../utils/constants'; export interface InRedisStorageOptions { prefix?: string options?: Record } -// exported for testing purposes -export function metadataBuilder(metadata: IMetadata): IRedisMetadata { - return { - s: metadata.version, - i: metadata.ip || UNKNOWN, - n: metadata.hostname || UNKNOWN, - }; -} - /** * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node. * @see {@link https://www.npmjs.com/package/ioredis} */ -export function InRedisStorage(options: InRedisStorageOptions = {}) { +export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsyncFactory { - const prefix = options.prefix ? options.prefix + '.SPLITIO' : 'SPLITIO'; + const prefix = validatePrefix(options.prefix); - return function InRedisStorageFactory(params: IStorageFactoryParams): IStorageAsync { + function InRedisStorageFactory({ log, metadata, onReadyCb }: IStorageFactoryParams): IStorageAsync { - const log = params.log; - const metadata = metadataBuilder(params.metadata); - const keys = new KeyBuilderSS(prefix, { version: metadata.s, ip: metadata.i, hostname: metadata.n }); + const keys = new KeyBuilderSS(prefix, metadata); const redisClient = new RedisAdapter(log, options.options || {}); - // subscription to Redis connect event in order to emit SDK_READY event - // @TODO pass a callback to simplify custom storages + // subscription to Redis connect event in order to emit SDK_READY event on consumer mode redisClient.on('connect', () => { - params.readinessManager.splits.emit(SDK_SPLITS_ARRIVED); - params.readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED); + if (onReadyCb) onReadyCb(); }); return { splits: new SplitsCacheInRedis(log, keys, redisClient), - segments: new SegmentsCacheInRedis(keys, redisClient), - impressions: new ImpressionsCacheInRedis(keys, redisClient, metadata), - events: new EventsCacheInRedis(log, keys, redisClient, metadata), + segments: new SegmentsCacheInRedis(log, keys, redisClient), + impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata), + events: new EventsCacheInRedis(log, keys.buildEventsKey(), redisClient, metadata), latencies: new LatenciesCacheInRedis(keys, redisClient), counts: new CountsCacheInRedis(keys, redisClient), @@ -62,5 +48,8 @@ export function InRedisStorage(options: InRedisStorageOptions = {}) { // @TODO check that caches works as expected when redisClient is disconnected } }; - }; + } + + InRedisStorageFactory.type = STORAGE_REDIS; + return InRedisStorageFactory; } diff --git a/src/storages/metadataBuilder.ts b/src/storages/metadataBuilder.ts new file mode 100644 index 00000000..2cfd9d2d --- /dev/null +++ b/src/storages/metadataBuilder.ts @@ -0,0 +1,11 @@ +import { IMetadata } from '../dtos/types'; +import { ISettings } from '../types'; +import { UNKNOWN } from '../utils/constants'; + +export function metadataBuilder(settings: Pick): IMetadata { + return { + s: settings.version, + i: settings.runtime.ip || UNKNOWN, + n: settings.runtime.hostname || UNKNOWN, + }; +} diff --git a/src/storages/pluggable/EventsCachePluggable.ts b/src/storages/pluggable/EventsCachePluggable.ts new file mode 100644 index 00000000..ff0b19dc --- /dev/null +++ b/src/storages/pluggable/EventsCachePluggable.ts @@ -0,0 +1,79 @@ +import { ICustomStorageWrapper, IEventsCacheAsync } from '../types'; +import { IMetadata } from '../../dtos/types'; +import { SplitIO } from '../../types'; +import { ILogger } from '../../logger/types'; +import { LOG_PREFIX } from './constants'; +import { StoredEventWithMetadata } from '../../sync/submitters/types'; + +export class EventsCachePluggable implements IEventsCacheAsync { + + private readonly log: ILogger; + private readonly wrapper: ICustomStorageWrapper; + private readonly key: string; + private readonly metadata: IMetadata; + + constructor(log: ILogger, key: string, wrapper: ICustomStorageWrapper, metadata: IMetadata) { + this.log = log; + this.key = key; + this.wrapper = wrapper; + this.metadata = metadata; + } + + /** + * Push given event to the storage. + * @param eventData Event item to push. + * @returns A promise that is resolved with a boolean value indicating if the push operation succeeded or failed. + * Unlike `impressions::track`, The promise will never be rejected. + */ + track(eventData: SplitIO.EventData): Promise { + return this.wrapper.pushItems( + this.key, + [this._toJSON(eventData)] + ) + // We use boolean values to signal successful queueing + .then(() => true) + .catch(e => { + this.log.error(`${LOG_PREFIX}Error adding event to queue: ${e}.`); + return false; + }); + } + + private _toJSON(eventData: SplitIO.EventData): string { + return JSON.stringify({ + m: this.metadata, + e: eventData + } as StoredEventWithMetadata); + } + + /** + * Returns a promise that resolves with the count of stored events, or 0 if there was some error. + * The promise will never be rejected. + */ + count(): Promise { + return this.wrapper.getItemsCount(this.key).catch(() => 0); + } + + /** + * Removes the given number of events from the store. If a number is not provided, it deletes all items. + * The returned promise rejects if the wrapper operation fails. + */ + drop(count?: number): Promise { + if (!count) return this.wrapper.del(this.key); + + return this.wrapper.popItems(this.key, count).then(() => { }); + } + + /** + * Pop the given number of events from the storage. + * The returned promise rejects if the wrapper operation fails. + * + * NOTE: this method doesn't take into account MAX_EVENT_SIZE or MAX_QUEUE_BYTE_SIZE limits. + * It is the submitter responsability to handle that. + */ + popNWithMetadata(count: number): Promise { + return this.wrapper.popItems(this.key, count).then((items) => { + return items.map(item => JSON.parse(item) as StoredEventWithMetadata); + }); + } + +} diff --git a/src/storages/pluggable/ImpressionsCachePluggable.ts b/src/storages/pluggable/ImpressionsCachePluggable.ts new file mode 100644 index 00000000..debe30ed --- /dev/null +++ b/src/storages/pluggable/ImpressionsCachePluggable.ts @@ -0,0 +1,83 @@ +import { ICustomStorageWrapper, IImpressionsCacheAsync } from '../types'; +import { IMetadata } from '../../dtos/types'; +import { ImpressionDTO } from '../../types'; +import { ILogger } from '../../logger/types'; +import { StoredImpressionWithMetadata } from '../../sync/submitters/types'; + +export class ImpressionsCachePluggable implements IImpressionsCacheAsync { + + private readonly log: ILogger; + private readonly key: string; + private readonly wrapper: ICustomStorageWrapper; + private readonly metadata: IMetadata; + + constructor(log: ILogger, key: string, wrapper: ICustomStorageWrapper, metadata: IMetadata) { + this.log = log; + this.key = key; + this.wrapper = wrapper; + this.metadata = metadata; + } + + /** + * Push given impressions to the storage. + * @param impressions List of impresions to push. + * @returns A promise that is resolved if the push operation succeeded + * or rejected if the wrapper operation fails. + */ + track(impressions: ImpressionDTO[]): Promise { + return this.wrapper.pushItems( + this.key, + this._toJSON(impressions) + ); + } + + private _toJSON(impressions: ImpressionDTO[]): string[] { + return impressions.map(impression => { + const { + keyName, bucketingKey, feature, treatment, label, time, changeNumber + } = impression; + + return JSON.stringify({ + m: this.metadata, + i: { + k: keyName, + b: bucketingKey, + f: feature, + t: treatment, + r: label, + c: changeNumber, + m: time + } + } as StoredImpressionWithMetadata); + }); + } + + /** + * Returns a promise that resolves with the count of stored impressions, or 0 if there was some error. + * The promise will never be rejected. + */ + count(): Promise { + return this.wrapper.getItemsCount(this.key).catch(() => 0); + } + + /** + * Removes the given number of impressions from the store. If a number is not provided, it deletes all items. + * The returned promise rejects if the wrapper operation fails. + */ + drop(count?: number): Promise { // @ts-ignore + if (!count) return this.wrapper.del(this.key); + + return this.wrapper.popItems(this.key, count).then(() => { }); + } + + /** + * Pop the given number of impressions from the store. + * The returned promise rejects if the wrapper operation fails. + */ + popNWithMetadata(count: number): Promise { + return this.wrapper.popItems(this.key, count).then((items) => { + return items.map(item => JSON.parse(item) as StoredImpressionWithMetadata); + }); + } + +} diff --git a/src/storages/pluggable/SegmentsCachePluggable.ts b/src/storages/pluggable/SegmentsCachePluggable.ts new file mode 100644 index 00000000..ec4c3fc3 --- /dev/null +++ b/src/storages/pluggable/SegmentsCachePluggable.ts @@ -0,0 +1,115 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable no-unused-vars */ +import { isNaNNumber } from '../../utils/lang'; +import KeyBuilderSS from '../KeyBuilderSS'; +import { ICustomStorageWrapper, ISegmentsCacheAsync } from '../types'; +import { ILogger } from '../../logger/types'; +import { LOG_PREFIX } from './constants'; +import { _Set } from '../../utils/lang/sets'; + +/** + * ISegmentsCacheAsync implementation for pluggable storages. + */ +export class SegmentsCachePluggable implements ISegmentsCacheAsync { + + private readonly log: ILogger; + private readonly keys: KeyBuilderSS; + private readonly wrapper: ICustomStorageWrapper; + + constructor(log: ILogger, keys: KeyBuilderSS, wrapper: ICustomStorageWrapper) { + this.log = log; + this.keys = keys; + this.wrapper = wrapper; + } + + /** + * Add a list of `segmentKeys` to the given segment `name`. + * The returned promise is resolved when the operation success + * or rejected if wrapper operation fails. + */ + addToSegment(name: string, segmentKeys: string[]) { + const segmentKey = this.keys.buildSegmentNameKey(name); + + if (segmentKeys.length) { + return this.wrapper.addItems(segmentKey, segmentKeys); + } else { + return Promise.resolve(); + } + } + + /** + * Remove a list of `segmentKeys` from the given segment `name`. + * The returned promise is resolved when the operation success + * or rejected if wrapper operation fails. + */ + removeFromSegment(name: string, segmentKeys: string[]) { + const segmentKey = this.keys.buildSegmentNameKey(name); + + if (segmentKeys.length) { + return this.wrapper.removeItems(segmentKey, segmentKeys); + } else { + return Promise.resolve(); + } + } + + /** + * Returns a promise that resolves with a boolean value indicating if `key` is part of `name` segment. + * Promise can be rejected if wrapper operation fails. + */ + isInSegment(name: string, key: string) { + return this.wrapper.itemContains(this.keys.buildSegmentNameKey(name), key); + } + + /** + * Set till number for the given segment `name`. + * The returned promise is resolved when the operation success, + * or rejected if it fails (e.g., wrapper operation fails). + */ + setChangeNumber(name: string, changeNumber: number) { + return this.wrapper.set( + this.keys.buildSegmentTillKey(name), changeNumber + '' + ); + } + + /** + * Get till number or -1 if it's not defined. + * The returned promise is resolved with the changeNumber or -1 if it doesn't exist or a wrapper operation fails. + * The promise will never be rejected. + */ + getChangeNumber(name: string) { + return this.wrapper.get(this.keys.buildSegmentTillKey(name)).then((value: string | null) => { + const i = parseInt(value as string, 10); + + return isNaNNumber(i) ? -1 : i; + }).catch((e) => { + this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e); + return -1; + }); + } + + /** + * Add the given segment names to the set of registered segments. + * The returned promise is resolved when the operation success, + * or rejected if it fails (e.g., wrapper operation fails). + */ + registerSegments(segments: string[]) { + if (segments.length) { + return this.wrapper.addItems(this.keys.buildRegisteredSegmentsKey(), segments); + } else { + return Promise.resolve(); + } + } + + /** + * Returns a promise that resolves with the set of registered segments in a list, + * or rejected if it fails (e.g., wrapper operation fails). + */ + getRegisteredSegments() { + return this.wrapper.getItems(this.keys.buildRegisteredSegmentsKey()); + } + + /** @TODO implement if required by DataLoader or Producer mode */ + clear(): Promise { + return Promise.resolve(true); + } +} diff --git a/src/storages/pluggable/SplitsCachePluggable.ts b/src/storages/pluggable/SplitsCachePluggable.ts new file mode 100644 index 00000000..e4e29ce4 --- /dev/null +++ b/src/storages/pluggable/SplitsCachePluggable.ts @@ -0,0 +1,211 @@ +import { isFiniteNumber, isNaNNumber } from '../../utils/lang'; +import KeyBuilder from '../KeyBuilder'; +import { ICustomStorageWrapper } from '../types'; +import { ILogger } from '../../logger/types'; +import { ISplit } from '../../dtos/types'; +import { LOG_PREFIX } from './constants'; +import AbstractSplitsCacheAsync from '../AbstractSplitsCacheAsync'; + +/** + * ISplitsCacheAsync implementation for pluggable storages. + */ +export class SplitsCachePluggable extends AbstractSplitsCacheAsync { + + private readonly log: ILogger; + private readonly keys: KeyBuilder; + private readonly wrapper: ICustomStorageWrapper; + + /** + * Create a SplitsCache that uses a custom storage wrapper. + * @param log Logger instance. + * @param keys Key builder. + * @param wrapper Adapted wrapper storage. + */ + constructor(log: ILogger, keys: KeyBuilder, wrapper: ICustomStorageWrapper) { + super(); + this.log = log; + this.keys = keys; + this.wrapper = wrapper; + } + + private _decrementCounts(split: ISplit) { + if (split.trafficTypeName) { + const ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName); + return this.wrapper.decr(ttKey).then(count => { + if (count === 0) return this.wrapper.del(ttKey); + }); + } + } + + private _incrementCounts(split: ISplit) { + if (split.trafficTypeName) { + const ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName); + return this.wrapper.incr(ttKey); + } + } + + /** + * Add a given split. + * The returned promise is resolved when the operation success + * or rejected if it fails (e.g., wrapper operation fails) + */ + addSplit(name: string, split: string): Promise { + const splitKey = this.keys.buildSplitKey(name); + return this.wrapper.get(splitKey).then(splitFromStorage => { + + // handling parsing error + let parsedPreviousSplit, parsedSplit; + try { + parsedPreviousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : undefined; + parsedSplit = JSON.parse(split); + } catch (e) { + throw new Error('Error parsing split definition: ' + e); + } + + return Promise.all([ + this.wrapper.set(splitKey, split), + this._incrementCounts(parsedSplit), + // If it's an update, we decrement the traffic type and segment count of the existing split, + parsedPreviousSplit && this._decrementCounts(parsedPreviousSplit) + ]); + }).then(() => true); + } + + /** + * Add a list of splits. + * The returned promise is resolved when the operation success + * or rejected if it fails (e.g., wrapper operation fails) + */ + addSplits(entries: [string, string][]): Promise { + return Promise.all(entries.map(keyValuePair => this.addSplit(keyValuePair[0], keyValuePair[1]))); + } + + /** + * Remove a given split. + * The returned promise is resolved when the operation success, with a boolean indicating if the split existed or not. + * or rejected if it fails (e.g., wrapper operation fails). + */ + removeSplit(name: string) { + return this.getSplit(name).then((split) => { + if (split) { + const parsedSplit = JSON.parse(split); + this._decrementCounts(parsedSplit); + } + return this.wrapper.del(this.keys.buildSplitKey(name)); + }); + } + + /** + * Remove a list of splits. + * The returned promise is resolved when the operation success, with a boolean array indicating if the splits existed or not. + * or rejected if it fails (e.g., wrapper operation fails). + */ + removeSplits(names: string[]): Promise { // @ts-ignore + return Promise.all(names.map(name => this.removeSplit(name))); + } + + /** + * Get split. + * The returned promise is resolved with the split definition or null if it's not defined, + * or rejected if wrapper operation fails. + */ + getSplit(name: string): Promise { + return this.wrapper.get(this.keys.buildSplitKey(name)); + } + + /** + * Get list of splits. + * The returned promise is resolved with a map of split names to their split definition or null if it's not defined, + * or rejected if wrapper operation fails. + */ + getSplits(names: string[]): Promise> { + const keys = names.map(name => this.keys.buildSplitKey(name)); + + return this.wrapper.getMany(keys).then(splitDefinitions => { + const splits: Record = {}; + names.forEach((name, idx) => { + splits[name] = splitDefinitions[idx]; + }); + return Promise.resolve(splits); + }); + } + + /** + * Get list of all split definitions. + * The returned promise is resolved with the list of split definitions, + * or rejected if wrapper operation fails. + */ + getAll(): Promise { + return this.wrapper.getKeysByPrefix(this.keys.buildSplitKeyPrefix()).then( + (listOfKeys) => Promise.all(listOfKeys.map(this.wrapper.get) as Promise[]) + ); + } + + /** + * Get list of split names. + * The returned promise is resolved with the list of split names, + * or rejected if wrapper operation fails. + */ + getSplitNames(): Promise { + return this.wrapper.getKeysByPrefix(this.keys.buildSplitKeyPrefix()).then( + (listOfKeys) => listOfKeys.map(this.keys.extractKey) + ); + } + + /** + * Check traffic type existence. + * The returned promise is resolved with a boolean indicating whether the TT exist or not. + * In case of wrapper operation failures, the promise resolves with a true value, assuming that the TT might exist. + * It will never be rejected. + */ + trafficTypeExists(trafficType: string): Promise { + // If there is a number there should be > 0, otherwise the TT is considered as not existent. + return this.wrapper.get(this.keys.buildTrafficTypeKey(trafficType)) + .then((ttCount: string | null | number) => { + if (ttCount === null) return false; // if entry doesn't exist, means that TT doesn't exist + + ttCount = parseInt(ttCount as string, 10); + if (!isFiniteNumber(ttCount) || ttCount < 0) { + this.log.info(LOG_PREFIX + `Could not validate traffic type existence of ${trafficType} due to data corruption of some sorts.`); + return false; + } + + return ttCount > 0; + }).catch(e => { + this.log.error(LOG_PREFIX + `Could not validate traffic type existence of ${trafficType} due to an error: ${e}.`); + // If there is an error, bypass the validation so the event can get tracked. + return true; + }); + } + + /** + * Set till number. + * The returned promise is resolved when the operation success, + * or rejected if it fails (e.g., wrapper operation fails). + */ + setChangeNumber(changeNumber: number) { + return this.wrapper.set(this.keys.buildSplitsTillKey(), changeNumber + ''); + } + + /** + * Get till number or -1 if it's not defined. + * The returned promise is resolved with the changeNumber or -1 if it doesn't exist or a wrapper operation fails. + * The promise will never be rejected. + */ + getChangeNumber(): Promise { + return this.wrapper.get(this.keys.buildSplitsTillKey()).then((value) => { + const i = parseInt(value as string, 10); + + return isNaNNumber(i) ? -1 : i; + }).catch((e) => { + this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from storage. Error: ' + e); + return -1; + }); + } + + // @TODO implement if required by DataLoader or producer mode + clear() { + return Promise.resolve(true); + } + +} diff --git a/src/storages/pluggable/__tests__/EventsCachePluggable.spec.ts b/src/storages/pluggable/__tests__/EventsCachePluggable.spec.ts new file mode 100644 index 00000000..09d8c84a --- /dev/null +++ b/src/storages/pluggable/__tests__/EventsCachePluggable.spec.ts @@ -0,0 +1,69 @@ +import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import { EventsCachePluggable } from '../EventsCachePluggable'; +import { wrapperMockFactory } from './wrapper.mock'; +import { wrapperAdapter } from '../wrapperAdapter'; + +const prefix = 'events_cache_ut'; +const eventsKey = `${prefix}.events`; +const fakeMetadata = { s: 'js_someversion', i: 'some_ip', n: 'some_hostname' }; + +const fakeEvent1 = { eventTypeId: '1', timestamp: 111 }; +const fakeEvent1stored = { m: fakeMetadata, e: fakeEvent1 }; + +const fakeEvent2 = { eventTypeId: '2', timestamp: 222 }; +const fakeEvent2stored = { m: fakeMetadata, e: fakeEvent2 }; + +const fakeEvent3 = { eventTypeId: '3', timestamp: 333 }; +const fakeEvent3stored = { m: fakeMetadata, e: fakeEvent3 }; + +export { fakeMetadata, fakeEvent1, fakeEvent1stored, fakeEvent2, fakeEvent2stored, fakeEvent3, fakeEvent3stored }; + +describe('PLUGGABLE EVENTS CACHE', () => { + + test('`track`, `count`, `popNWithMetadata` and `drop` methods', async () => { + const wrapperMock = wrapperMockFactory(); + const cache = new EventsCachePluggable(loggerMock, eventsKey, wrapperMock, fakeMetadata); + + // Testing track and count methods. + expect(await cache.track(fakeEvent1)).toBe(true); // If the queueing operation was successful, it should resolve the returned promise with "true" + expect(await cache.count()).toBe(1); // count should return stored items + expect(await cache.track(fakeEvent2)).toBe(true); // If the queueing operation was successful, it should resolve the returned promise with "true" + expect(await cache.track(fakeEvent3)).toBe(true); // If the queueing operation was successful, it should resolve the returned promise with "true" + expect(await cache.count()).toBe(3); // count should return stored items + + const values = wrapperMock._cache[eventsKey] as string[]; + expect(values.length).toBe(3); // After pushing we should have events in the wrapper. + + // Testing popNWithMetadata + expect(await cache.popNWithMetadata(2)).toEqual([fakeEvent1stored, fakeEvent2stored]); // events are removed in FIFO order + expect(await cache.count()).toBe(1); + + expect(await cache.popNWithMetadata(1)).toEqual([fakeEvent3stored]); + expect(await cache.count()).toBe(0); + + expect(await cache.popNWithMetadata(100)).toEqual([]); // no more events + + // Testing drop method + await Promise.all([cache.track(fakeEvent1), cache.track(fakeEvent2), cache.track(fakeEvent3)]); + expect(await cache.count()).toBe(3); + await cache.drop(); + expect(await cache.count()).toBe(0); // storage should be empty after droping it + + wrapperMock.mockClear(); + }); + + test('`track` method result should not reject if wrapper operation fails', async () => { + const wrapperMock = wrapperMockFactory(); + // @ts-ignore. I'll use a "bad" queue to force an exception with the pushItems wrapper operation. + wrapperMock._cache['non-list-key'] = 10; + // wrapperMock is adapted this time to properly handle unexpected exceptions + const faultyCache = new EventsCachePluggable(loggerMock, 'non-list-key', wrapperAdapter(loggerMock, wrapperMock), fakeMetadata); + + expect(await faultyCache.track(fakeEvent1)).toBe(false); // If the queueing operation was NOT successful, it should resolve the returned promise with "false" instead of rejecting it. + expect(await faultyCache.track(fakeEvent2)).toBe(false); // If the queueing operation was NOT successful, it should resolve the returned promise with "false" instead of rejecting it. + expect(await faultyCache.track(fakeEvent3)).toBe(false); // If the queueing operation was NOT successful, it should resolve the returned promise with "false" instead of rejecting it. + + wrapperMock.mockClear(); + }); + +}); diff --git a/src/storages/pluggable/__tests__/ImpressionsCachePluggable.spec.ts b/src/storages/pluggable/__tests__/ImpressionsCachePluggable.spec.ts new file mode 100644 index 00000000..d978be1b --- /dev/null +++ b/src/storages/pluggable/__tests__/ImpressionsCachePluggable.spec.ts @@ -0,0 +1,101 @@ +import { ImpressionsCachePluggable } from '../ImpressionsCachePluggable'; +import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import { wrapperMock } from './wrapper.mock'; +import { IMetadata } from '../../../dtos/types'; + +const prefix = 'impr_cache_ut'; +const impressionsKey = `${prefix}.impressions`; + +const fakeMetadata: IMetadata = { s: 'js_someversion', i: 'some_ip', n: 'some_hostname' }; + +const o1 = { + feature: 'test1', + keyName: 'facundo@split.io', + treatment: 'on', + time: Date.now(), + label: 'default rule', + changeNumber: 1 +}; + +const o1stored = { + m: fakeMetadata, + i: { k: o1.keyName, f: o1.feature, t: o1.treatment, r: o1.label, c: o1.changeNumber, m: o1.time } +}; + +const o2 = { + feature: 'test2', + keyName: 'pepep@split.io', + treatment: 'A', + time: Date.now(), + bucketingKey: '1234-5678', + label: 'is in segment', + changeNumber: 1 +}; + +const o2stored = { + m: fakeMetadata, + i: { k: o2.keyName, b: o2.bucketingKey, f: o2.feature, t: o2.treatment, r: o2.label, c: o2.changeNumber, m: o2.time } +}; + +const o3 = { + feature: 'test3', + keyName: 'pipiip@split.io', + treatment: 'B', + time: Date.now(), + label: 'default rule', + changeNumber: 1 +}; + +const o3stored = { + m: fakeMetadata, + i: { k: o3.keyName, f: o3.feature, t: o3.treatment, r: o3.label, c: o3.changeNumber, m: o3.time } +}; + +export { fakeMetadata, o1, o2, o3, o1stored, o2stored, o3stored }; + +describe('PLUGGABLE IMPRESSIONS CACHE', () => { + + afterEach(() => { + loggerMock.mockClear(); + wrapperMock.mockClear(); + }); + + test('`track`, `count`, `popNWithMetadata` and `drop` methods', async () => { + const cache = new ImpressionsCachePluggable(loggerMock, impressionsKey, wrapperMock, fakeMetadata); + + // Testing track and count methods. + await cache.track([o1]); + let state = wrapperMock._cache[impressionsKey] as string[]; + expect(state.length).toBe(1); // impression should be stored + expect(await cache.count()).toBe(1); // count should return stored items + + await cache.track([o2, o3]); + state = wrapperMock._cache[impressionsKey] as string[]; + expect(state.length).toBe(3); + expect(await cache.count()).toBe(3); // count should return stored items + + // Testing popNWithMetadata and private toJSON methods. + expect(await cache.popNWithMetadata(2)).toEqual([o1stored, o2stored]); // impressions are removed in FIFO order + expect(await cache.count()).toBe(1); + + expect(await cache.popNWithMetadata(1)).toEqual([o3stored]); + expect(await cache.count()).toBe(0); + expect(await cache.popNWithMetadata(100)).toEqual([]); // no more impressions + + // Testing drop method + await cache.track([o1, o2, o3]); + expect(await cache.count()).toBe(3); + await cache.drop(); + expect(await cache.count()).toBe(0); // storage should be empty after droping it + + }); + + test('`track` method rejects if wrapper operation fails', (done) => { + // make wrapper operation fail + wrapperMock.pushItems.mockImplementation(() => Promise.reject()); + const cache = new ImpressionsCachePluggable(loggerMock, impressionsKey, wrapperMock, fakeMetadata); + + cache.track([o1]).catch(done); // result should rejects + }); + +}); diff --git a/src/storages/pluggable/__tests__/SegmentsCachePluggable.spec.ts b/src/storages/pluggable/__tests__/SegmentsCachePluggable.spec.ts new file mode 100644 index 00000000..d0ec3a56 --- /dev/null +++ b/src/storages/pluggable/__tests__/SegmentsCachePluggable.spec.ts @@ -0,0 +1,56 @@ +import { SegmentsCachePluggable } from '../SegmentsCachePluggable'; +import KeyBuilderSS from '../../KeyBuilderSS'; +import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import { wrapperMock } from './wrapper.mock'; + +// @ts-ignore. Doesn't require metadata +const keyBuilder = new KeyBuilderSS(); + +describe('SEGMENTS CACHE PLUGGABLE', () => { + + afterEach(() => { + loggerMock.mockClear(); + wrapperMock.mockClear(); + }); + + test('isInSegment, set/getChangeNumber, add/removeFromSegment', async () => { + const cache = new SegmentsCachePluggable(loggerMock, keyBuilder, wrapperMock); + + await cache.addToSegment('mocked-segment', ['a', 'b', 'c']); + + await cache.setChangeNumber('mocked-segment', 1); + + await cache.removeFromSegment('mocked-segment', ['d']); + + expect(await cache.getChangeNumber('mocked-segment') === 1).toBe(true); + + expect(await cache.getChangeNumber('inexistent-segment')).toBe(-1); // -1 if the segment doesn't exist + + await cache.addToSegment('mocked-segment', ['d', 'e']); + + await cache.removeFromSegment('mocked-segment', ['a', 'c']); + + expect(await cache.getChangeNumber('mocked-segment') === 1).toBe(true); + + expect(await cache.isInSegment('mocked-segment', 'a')).toBe(false); + expect(await cache.isInSegment('mocked-segment', 'b')).toBe(true); + expect(await cache.isInSegment('mocked-segment', 'c')).toBe(false); + expect(await cache.isInSegment('mocked-segment', 'd')).toBe(true); + expect(await cache.isInSegment('mocked-segment', 'e')).toBe(true); + + expect(await cache.isInSegment('inexistent-segment', 'a')).toBe(false); + }); + + test('registerSegment / getRegisteredSegments', async () => { + const cache = new SegmentsCachePluggable(loggerMock, keyBuilder, wrapperMock); + + await cache.registerSegments(['s1']); + await cache.registerSegments(['s2']); + await cache.registerSegments(['s2', 's3', 's4']); + + const segments = await cache.getRegisteredSegments(); + + ['s1', 's2', 's3', 's4'].forEach(s => expect(segments.indexOf(s) !== -1).toBe(true)); + }); + +}); diff --git a/src/storages/pluggable/__tests__/SplitsCachePluggable.spec.ts b/src/storages/pluggable/__tests__/SplitsCachePluggable.spec.ts new file mode 100644 index 00000000..99069585 --- /dev/null +++ b/src/storages/pluggable/__tests__/SplitsCachePluggable.spec.ts @@ -0,0 +1,159 @@ +import { SplitsCachePluggable } from '../SplitsCachePluggable'; +import KeyBuilder from '../../KeyBuilder'; +import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import { wrapperMockFactory } from './wrapper.mock'; +import { splitWithUserTT, splitWithAccountTT } from '../../__tests__/testUtils'; + +const keysBuilder = new KeyBuilder(); + +describe('SPLITS CACHE PLUGGABLE', () => { + + test('add/remove/get splits', async () => { + const cache = new SplitsCachePluggable(loggerMock, keysBuilder, wrapperMockFactory()); + + // Assert addSplit and addSplits + await cache.addSplits([ + ['lol1', splitWithUserTT], + ['lol2', splitWithAccountTT] + ]); + await cache.addSplit('lol3', splitWithAccountTT); + + // adding malformed or existing splits with the same definitions will not have effects + await expect(cache.addSplits([ + ['lol1', splitWithUserTT], + ['lol2', '{ /'] + ])).rejects.toBeTruthy(); + await expect(cache.addSplit('lol3', '{ /')).rejects.toBeTruthy(); + + // Assert getAll + let values = await cache.getAll(); + + expect(values.length).toBe(3); + expect(values.indexOf(splitWithUserTT) !== -1).toBe(true); + expect(values.indexOf(splitWithAccountTT) !== -1).toBe(true); + + // Assert getSplits + let valuesObj = await cache.getSplits(['lol2', 'lol3']); + + expect(Object.keys(valuesObj).length).toBe(2); + expect(valuesObj.lol2).toBe(splitWithAccountTT); + expect(valuesObj.lol3).toBe(splitWithAccountTT); + + // Assert getSplitNames + let splitNames = await cache.getSplitNames(); + + expect(splitNames.length).toBe(3); + expect(splitNames.indexOf('lol1') !== -1).toBe(true); + expect(splitNames.indexOf('lol2') !== -1).toBe(true); + expect(splitNames.indexOf('lol3') !== -1).toBe(true); + + // Assert removeSplit + await cache.removeSplit('lol1'); + + values = await cache.getAll(); + expect(values.length).toBe(2); + expect(await cache.getSplit('lol1')).toBe(null); + expect(await cache.getSplit('lol2')).toBe(splitWithAccountTT); + + // Assert removeSplits + await cache.addSplit('lol1', splitWithUserTT); + await cache.removeSplits(['lol1', 'lol3']); + + values = await cache.getAll(); + expect(values.length).toBe(1); + splitNames = await cache.getSplitNames(); + expect(splitNames.length).toBe(1); + expect(await cache.getSplit('lol1')).toBe(null); + expect(await cache.getSplit('lol2')).toBe(splitWithAccountTT); + + }); + + test('set/get change number', async () => { + const cache = new SplitsCachePluggable(loggerMock, keysBuilder, wrapperMockFactory()); + + expect(await cache.getChangeNumber()).toBe(-1); // if not set yet, changeNumber is -1 + await cache.setChangeNumber(123); + expect(await cache.getChangeNumber()).toBe(123); + + }); + + test('trafficTypeExists', async () => { + const wrapper = wrapperMockFactory(); + const cache = new SplitsCachePluggable(loggerMock, keysBuilder, wrapper); + + await cache.addSplits([ + ['split1', splitWithUserTT], + ['split2', splitWithAccountTT], + ['split3', splitWithUserTT], + ['malformed', '{}'] + ]); + await cache.addSplit('split4', splitWithUserTT); + await cache.addSplit('split4', splitWithUserTT); // trying to add the same definition for an already added split will not have effect + + expect(await cache.trafficTypeExists('user_tt')).toBe(true); + expect(await cache.trafficTypeExists('account_tt')).toBe(true); + expect(await cache.trafficTypeExists('not_existent_tt')).toBe(false); + + await cache.removeSplit('split4'); + + expect(await cache.trafficTypeExists('user_tt')).toBe(true); + expect(await cache.trafficTypeExists('account_tt')).toBe(true); + + expect(await wrapper.get(keysBuilder.buildTrafficTypeKey('account_tt'))).toBe('1'); + + await cache.removeSplits(['split3', 'split2']); // it'll invoke a loop of removeSplit + + expect(await cache.trafficTypeExists('user_tt')).toBe(true); + expect(await cache.trafficTypeExists('account_tt')).toBe(false); + + expect(await wrapper.get(keysBuilder.buildTrafficTypeKey('account_tt'))).toBe(null); // TT entry should be removed in the wrapper + + await cache.removeSplit('split1'); + + expect(await cache.trafficTypeExists('user_tt')).toBe(false); + expect(await cache.trafficTypeExists('account_tt')).toBe(false); + + await cache.addSplit('split1', splitWithUserTT); + expect(await cache.trafficTypeExists('user_tt')).toBe(true); + + await cache.addSplit('split1', splitWithAccountTT); + expect(await cache.trafficTypeExists('account_tt')).toBe(true); + expect(await cache.trafficTypeExists('user_tt')).toBe(false); + + }); + + test('killLocally', async () => { + const cache = new SplitsCachePluggable(loggerMock, keysBuilder, wrapperMockFactory()); + + await cache.addSplit('lol1', splitWithUserTT); + await cache.addSplit('lol2', splitWithAccountTT); + const initialChangeNumber = await cache.getChangeNumber(); + + // kill an non-existent split + let updated = await cache.killLocally('nonexistent_split', 'other_treatment', 101); + const nonexistentSplit = await cache.getSplit('nonexistent_split'); + + expect(updated).toBe(false); // killLocally resolves without update if split doesn't exist + expect(nonexistentSplit).toBe(null); // non-existent split keeps being non-existent + + // kill an existent split + updated = await cache.killLocally('lol1', 'some_treatment', 100); + let lol1Split = JSON.parse(await cache.getSplit('lol1') as string); + + expect(updated).toBe(true); // killLocally resolves with update if split is changed + expect(lol1Split.killed).toBe(true); // existing split must be killed + expect(lol1Split.defaultTreatment).toBe('some_treatment'); // existing split must have new default treatment + expect(lol1Split.changeNumber).toBe(100); // existing split must have the given change number + expect(await cache.getChangeNumber()).toBe(initialChangeNumber); // cache changeNumber is not changed + + // not update if changeNumber is old + updated = await cache.killLocally('lol1', 'some_treatment_2', 90); + lol1Split = JSON.parse(await cache.getSplit('lol1') as string); + + expect(updated).toBe(false); // killLocally resolves without update if changeNumber is old + expect(lol1Split.defaultTreatment).not.toBe('some_treatment_2'); // existing split is not updated if given changeNumber is older + + }); + +}); + diff --git a/src/storages/pluggable/__tests__/index.spec.ts b/src/storages/pluggable/__tests__/index.spec.ts new file mode 100644 index 00000000..8356a3ad --- /dev/null +++ b/src/storages/pluggable/__tests__/index.spec.ts @@ -0,0 +1,62 @@ +// @ts-nocheck + +// Mocks +import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import { IStorageFactoryParams } from '../../types'; +import { wrapperMock, wrapperMockFactory } from './wrapper.mock'; + +const metadata = { s: 'version', i: 'ip', n: 'hostname' }; +const prefix = 'some_prefix'; + +// Test target +import { PluggableStorage } from '../index'; +import { assertStorageInterface } from '../../__tests__/testUtils'; + +describe('PLUGGABLE STORAGE', () => { + + const internalSdkParams: IStorageFactoryParams = { + log: loggerMock, + metadata, + onReadyCb: jest.fn() + }; + + afterEach(() => { + wrapperMock.mockClear(); + }); + + test('creates a storage instance', async () => { + const storageFactory = PluggableStorage({ prefix, wrapper: wrapperMock }); + const storage = storageFactory(internalSdkParams); + + assertStorageInterface(storage); // the instance must implement the storage interface + expect(wrapperMock.connect).toBeCalledTimes(1); // wrapper connect method should be called once when storage is created + + expect(await storage.splits.getSplit('some_split')).toBe(null); + expect(wrapperMock.get).toBeCalledWith(`${prefix}.SPLITIO.split.some_split`); // keys prefix should be the provided one + + await storage.destroy(); + expect(wrapperMock.close).toBeCalledTimes(1); // wrapper close method should be called once when storage is destroyed + + expect(internalSdkParams.onReadyCb).toBeCalledTimes(1); // onReady callback should be called when the wrapper connect resolved with true + }); + + test('throws an exception if wrapper doesn\'t implement the expected interface', async () => { + + expect(() => PluggableStorage({ wrapper: wrapperMock })).not.toThrow(); // not prefix but valid wrapper is OK + + // Throws exception if no object is passed as wrapper + const errorNoValidWrapper = 'Expecting custom storage `wrapper` in options, but no valid wrapper instance was provided.'; + expect(() => PluggableStorage()).toThrow(errorNoValidWrapper); + expect(() => PluggableStorage({ wrapper: undefined })).toThrow(errorNoValidWrapper); + expect(() => PluggableStorage({ wrapper: 'invalid wrapper' })).toThrow(errorNoValidWrapper); + + // Throws exception if the given object is not a valid wrapper, informing which methods are missing + const invalidWrapper = wrapperMockFactory(); + invalidWrapper.connect = undefined; + invalidWrapper.close = 'invalid function'; + const errorNoValidWrapperInterface = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.'; + expect(() => PluggableStorage({ wrapper: invalidWrapper })).toThrow(errorNoValidWrapperInterface); + expect(() => PluggableStorage({ wrapper: {} })).toThrow(errorNoValidWrapperInterface); + }); + +}); diff --git a/src/storages/pluggable/__tests__/wrapper.mock.ts b/src/storages/pluggable/__tests__/wrapper.mock.ts new file mode 100644 index 00000000..da4b2122 --- /dev/null +++ b/src/storages/pluggable/__tests__/wrapper.mock.ts @@ -0,0 +1,133 @@ +import { startsWith, toNumber } from '../../../utils/lang'; + +// Creates an in memory ICustomStorageWrapper implementation with Jest mocks +export function wrapperMockFactory() { + + /** Holds items and list of items */ + let _cache: Record> = {}; + + return { + _cache, + + get: jest.fn((key => { + return Promise.resolve(key in _cache ? _cache[key] as string : null); + })), + set: jest.fn((key: string, value: string) => { + const result = key in _cache; + _cache[key] = value; + return Promise.resolve(result); + }), + getAndSet: jest.fn((key: string, value: string) => { + const result = key in _cache ? _cache[key] as string : null; + _cache[key] = value; + return Promise.resolve(result); + }), + del: jest.fn((key: string) => { + const result = key in _cache; + delete _cache[key]; + return Promise.resolve(result); + }), + getKeysByPrefix: jest.fn((prefix: string) => { + return Promise.resolve(Object.keys(_cache).filter(key => startsWith(key, prefix))); + }), + incr: jest.fn((key: string) => { + if (key in _cache) { + const count = toNumber(_cache[key]) + 1; + if (isNaN(count)) return Promise.reject('Given key is not a number'); + _cache[key] = count + ''; + return Promise.resolve(count); + } else { + _cache[key] = '1'; + return Promise.resolve(1); + } + }), + decr: jest.fn((key: string) => { + if (key in _cache) { + const count = toNumber(_cache[key]) - 1; + if (isNaN(count)) return Promise.reject('Given key is not a number'); + _cache[key] = count + ''; + return Promise.resolve(count); + } else { + _cache[key] = '-1'; + return Promise.resolve(-1); + } + }), + getMany: jest.fn((keys: string[]) => { + return Promise.resolve(keys.map(key => _cache[key] ? _cache[key] as string : null)); + }), + pushItems: jest.fn((key: string, items: string[]) => { // @ts-ignore + if (!(key in _cache)) _cache[key] = []; + const list = _cache[key]; + if (Array.isArray(list)) { + list.push(...items); + return Promise.resolve(); + } + return Promise.reject('key is not a list'); + }), + popItems: jest.fn((key: string, count: number) => { + const list = _cache[key]; + return Promise.resolve(Array.isArray(list) ? list.splice(0, count) : []); + }), + getItemsCount: jest.fn((key: string) => { + const list = _cache[key]; + return Promise.resolve(Array.isArray(list) ? list.length : 0); + }), + itemContains: jest.fn((key: string, item: string) => { + const set = _cache[key]; + if (!set) return Promise.resolve(false); + if (set instanceof Set) return Promise.resolve(set.has(item)); + return Promise.reject('key is not a set'); + }), + addItems: jest.fn((key: string, items: string[]) => { + if (!(key in _cache)) _cache[key] = new Set(); + const set = _cache[key]; + if (set instanceof Set) { + items.forEach(item => set.add(item)); + return Promise.resolve(); + } + return Promise.reject('key is not a set'); + }), + removeItems: jest.fn((key: string, items: string[]) => { + if (!(key in _cache)) _cache[key] = new Set(); + const set = _cache[key]; + if (set instanceof Set) { + items.forEach(item => set.delete(item)); + return Promise.resolve(); + } + return Promise.reject('key is not a set'); + }), + getItems: jest.fn((key: string) => { + const set = _cache[key]; + if (!set) return Promise.resolve([]); + if (set instanceof Set) return Promise.resolve(Array.from(set)); + return Promise.reject('key is not a set'); + }), + + // always connects and close + connect: jest.fn(() => Promise.resolve()), + close: jest.fn(() => Promise.resolve()), + + mockClear() { + this._cache = {}; + this.get.mockClear(); + this.set.mockClear(); + this.del.mockClear(); + this.getKeysByPrefix.mockClear(); + this.incr.mockClear(); + this.decr.mockClear(); + this.getMany.mockClear(); + this.connect.mockClear(); + this.close.mockClear(); + this.getAndSet.mockClear(); + this.pushItems.mockClear(); + this.popItems.mockClear(); + this.getItemsCount.mockClear(); + this.itemContains.mockClear(); + this.addItems.mockClear(); + this.removeItems.mockClear(); + this.getItems.mockClear(); + } + }; +} + +export const wrapperMock = wrapperMockFactory(); diff --git a/src/storages/pluggable/__tests__/wrapperAdapter.spec.ts b/src/storages/pluggable/__tests__/wrapperAdapter.spec.ts new file mode 100644 index 00000000..dd081b6f --- /dev/null +++ b/src/storages/pluggable/__tests__/wrapperAdapter.spec.ts @@ -0,0 +1,109 @@ +// @ts-nocheck +import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import thenable from '../../../utils/promise/thenable'; +import { LOG_PREFIX } from '../constants'; + +/** Mocks */ + +import { wrapperMock } from './wrapper.mock'; + +function throwsException() { + throw new Error('some error'); +} + +function rejectedPromise() { + return Promise.reject('some error'); +} + +function invalidThenable() { + return { then() { } }; +} + +export const wrapperWithIssues = { + get: undefined, + set: 'invalid value', + del: throwsException, + getKeysByPrefix: rejectedPromise, + incr: invalidThenable, + decr: 'invalid value', + getMany: throwsException, + connect: rejectedPromise, + close: invalidThenable, + getAndSet: 'invalid value', + pushItems: rejectedPromise, + popItems: invalidThenable, + getItemsCount: 'invalid value', + itemContains: throwsException, + addItems: { then: 10 }, + removeItems: invalidThenable, + getItems: { then: () => { throw new Error(); } } +}; + +const VALID_METHOD_CALLS = { + 'get': ['some_key'], + 'set': ['some_key', 'some_value'], + 'del': ['some_key'], + 'getKeysByPrefix': ['some_prefix'], + 'incr': ['some_key'], + 'decr': ['some_key'], + 'getMany': [['some_key_1', 'some_key_2']], + 'connect': [], + 'close': [], + 'getAndSet': ['some_key', 'some_value'], + 'pushItems': ['some_key_list', ['item1', 'item2']], + 'popItems': ['some_key_list'], + 'getItemsCount': ['some_key_list'], + 'itemContains': ['some_key_set', 'some_value'], + 'addItems': ['some_key_set', ['item1', 'item2']], + 'removeItems': ['some_key_set', ['item1', 'item2']], + 'getItems': ['some_key_set'], +}; + +// Test target +import { wrapperAdapter } from '../wrapperAdapter'; + +describe('Wrapper Adapter', () => { + + afterEach(() => { + loggerMock.mockClear(); + wrapperMock.mockClear(); + }); + + test('calls original wrapper methods', async () => { + const instance = wrapperAdapter(loggerMock, wrapperMock); + const methods = Object.keys(VALID_METHOD_CALLS); + + for (let i = 0; i < methods.length; i++) { + const method = methods[i]; + const result = instance[method](...VALID_METHOD_CALLS[method]); + expect(wrapperMock[method]).toBeCalledTimes(1); + expect(wrapperMock[method]).toBeCalledWith(...VALID_METHOD_CALLS[method]); + expect(wrapperMock[method]).toHaveReturnedWith(result); + await result; + } + + // no logs if there isn't issues + expect(loggerMock.error).not.toBeCalled(); + expect(loggerMock.warn).not.toBeCalled(); + }); + + test('handle wrapper call exceptions', async () => { + const instance = wrapperAdapter(loggerMock, wrapperWithIssues); + const methods = Object.keys(VALID_METHOD_CALLS); + + for (let i = 0; i < methods.length; i++) { + const method = methods[i]; + const result = instance[method](...VALID_METHOD_CALLS[method]); + expect(thenable(result)).toBe(true); + try { + await result; + expect(true).toBe(false); // promise shouldn't be resolved + } catch (e) { + expect(loggerMock.error).toHaveBeenCalledWith(`${LOG_PREFIX} Wrapper '${method}' operation threw an error. Message: ${e}`); + } + } + + expect(loggerMock.error).toBeCalledTimes(methods.length); + }); + +}); diff --git a/src/storages/pluggable/constants.ts b/src/storages/pluggable/constants.ts new file mode 100644 index 00000000..1f845f45 --- /dev/null +++ b/src/storages/pluggable/constants.ts @@ -0,0 +1 @@ +export const LOG_PREFIX = 'storage:pluggable:'; diff --git a/src/storages/pluggable/inMemoryWrapper.ts b/src/storages/pluggable/inMemoryWrapper.ts new file mode 100644 index 00000000..efb2c6db --- /dev/null +++ b/src/storages/pluggable/inMemoryWrapper.ts @@ -0,0 +1,116 @@ +import { ICustomStorageWrapper } from '../types'; +import { startsWith, toNumber } from '../../utils/lang'; +import { ISet, setToArray, _Set } from '../../utils/lang/sets'; + +/** + * Creates a ICustomStorageWrapper implementation that stores items in memory. + * The `_cache` property is the object were items are stored. + * Intended for testing purposes. + */ +export function inMemoryWrapperFactory(): ICustomStorageWrapper & { _cache: Record> } { + + let _cache: Record> = {}; + + return { + /** Holds items (for key-value operations), list of items (for list operations) and set of items (for set operations) */ + _cache, + + get(key) { + return Promise.resolve(key in _cache ? _cache[key] as string : null); + }, + set(key: string, value: string) { + const result = key in _cache; + _cache[key] = value; + return Promise.resolve(result); + }, + getAndSet(key: string, value: string) { + const result = key in _cache ? _cache[key] as string : null; + _cache[key] = value; + return Promise.resolve(result); + }, + del(key: string) { + const result = key in _cache; + delete _cache[key]; + return Promise.resolve(result); + }, + getKeysByPrefix(prefix: string) { + return Promise.resolve(Object.keys(_cache).filter(key => startsWith(key, prefix))); + }, + incr(key: string) { + if (key in _cache) { + const count = toNumber(_cache[key]) + 1; + if (isNaN(count)) return Promise.reject('Given key is not a number'); + _cache[key] = count + ''; + return Promise.resolve(count); + } else { + _cache[key] = '1'; + return Promise.resolve(1); + } + }, + decr(key: string) { + if (key in _cache) { + const count = toNumber(_cache[key]) - 1; + if (isNaN(count)) return Promise.reject('Given key is not a number'); + _cache[key] = count + ''; + return Promise.resolve(count); + } else { + _cache[key] = '-1'; + return Promise.resolve(-1); + } + }, + getMany(keys: string[]) { + return Promise.resolve(keys.map(key => _cache[key] ? _cache[key] as string : null)); + }, + pushItems(key: string, items: string[]) { // @ts-ignore + if (!(key in _cache)) _cache[key] = []; + const list = _cache[key]; + if (Array.isArray(list)) { + list.push(...items); + return Promise.resolve(); + } + return Promise.reject('key is not a list'); + }, + popItems(key: string, count: number) { + const list = _cache[key]; + return Promise.resolve(Array.isArray(list) ? list.splice(0, count) : []); + }, + getItemsCount(key: string) { + const list = _cache[key]; + return Promise.resolve(Array.isArray(list) ? list.length : 0); + }, + itemContains(key: string, item: string) { + const set = _cache[key]; + if (!set) return Promise.resolve(false); + if (set instanceof _Set) return Promise.resolve(set.has(item)); + return Promise.reject('key is not a set'); + }, + addItems(key: string, items: string[]) { + if (!(key in _cache)) _cache[key] = new _Set(); + const set = _cache[key]; + if (set instanceof _Set) { + items.forEach(item => set.add(item)); + return Promise.resolve(); + } + return Promise.reject('key is not a set'); + }, + removeItems(key: string, items: string[]) { + if (!(key in _cache)) _cache[key] = new _Set(); + const set = _cache[key]; + if (set instanceof _Set) { + items.forEach(item => set.delete(item)); + return Promise.resolve(); + } + return Promise.reject('key is not a set'); + }, + getItems(key: string) { + const set = _cache[key]; + if (!set) return Promise.resolve([]); + if (set instanceof _Set) return Promise.resolve(setToArray(set)); + return Promise.reject('key is not a set'); + }, + + // always connects and close + connect() { return Promise.resolve(); }, + close() { return Promise.resolve(); }, + }; +} diff --git a/src/storages/pluggable/index.ts b/src/storages/pluggable/index.ts new file mode 100644 index 00000000..2afb1bf4 --- /dev/null +++ b/src/storages/pluggable/index.ts @@ -0,0 +1,71 @@ +import { ICustomStorageWrapper, IStorageAsync, IStorageAsyncFactory, IStorageFactoryParams } from '../types'; + +import KeyBuilderSS from '../KeyBuilderSS'; +import { SplitsCachePluggable } from './SplitsCachePluggable'; +import { SegmentsCachePluggable } from './SegmentsCachePluggable'; +import { ImpressionsCachePluggable } from './ImpressionsCachePluggable'; +import { EventsCachePluggable } from './EventsCachePluggable'; +import { wrapperAdapter, METHODS_TO_PROMISE_WRAP } from './wrapperAdapter'; +import { isObject } from '../../utils/lang'; +import { validatePrefix } from '../KeyBuilder'; +import { STORAGE_CUSTOM } from '../../utils/constants'; + +const NO_VALID_WRAPPER = 'Expecting custom storage `wrapper` in options, but no valid wrapper instance was provided.'; +const NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.'; + +export interface PluggableStorageOptions { + prefix?: string + wrapper: ICustomStorageWrapper +} + +/** + * Validate pluggable storage factory options. + * + * @param options user options + * @throws Will throw an error if the options are invalid. Example: wrapper is not provided or doesn't have some methods. + */ +function validatePluggableStorageOptions(options: any) { + if (!isObject(options) || !isObject(options.wrapper)) throw new Error(NO_VALID_WRAPPER); + + const wrapper = options.wrapper; + const missingMethods = METHODS_TO_PROMISE_WRAP.filter(method => typeof wrapper[method] !== 'function'); + if (missingMethods.length) throw new Error(`${NO_VALID_WRAPPER_INTERFACE} The following methods are missing or invalid: ${missingMethods}`); +} + +/** + * Pluggable storage factory for consumer server-side & client-side SplitFactory. + */ +export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyncFactory { + + validatePluggableStorageOptions(options); + + const prefix = validatePrefix(options.prefix); + + function PluggableStorageFactory({ log, metadata, onReadyCb }: IStorageFactoryParams): IStorageAsync { + const keys = new KeyBuilderSS(prefix, metadata); + const wrapper = wrapperAdapter(log, options.wrapper); + + // subscription to Wrapper connect event in order to emit SDK_READY event + wrapper.connect().then(() => { + if (onReadyCb) onReadyCb(); + }).catch((e) => { + if (onReadyCb) onReadyCb(e || new Error('Error connecting wrapper')); + }); + + return { + splits: new SplitsCachePluggable(log, keys, wrapper), + segments: new SegmentsCachePluggable(log, keys, wrapper), + impressions: new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata), + events: new EventsCachePluggable(log, keys.buildEventsKey(), wrapper, metadata), + // @TODO add telemetry cache when required + + // Disconnect the underlying storage, to release its resources (such as open files, database connections, etc). + destroy() { + return wrapper.close(); + } + }; + } + + PluggableStorageFactory.type = STORAGE_CUSTOM; + return PluggableStorageFactory; +} diff --git a/src/storages/pluggable/wrapperAdapter.ts b/src/storages/pluggable/wrapperAdapter.ts new file mode 100644 index 00000000..0b93f494 --- /dev/null +++ b/src/storages/pluggable/wrapperAdapter.ts @@ -0,0 +1,58 @@ +import { ILogger } from '../../logger/types'; +import { ICustomStorageWrapper } from '../types'; +import { LOG_PREFIX } from './constants'; + +export const METHODS_TO_PROMISE_WRAP: string[] = [ + 'get', + 'set', + 'getAndSet', + 'del', + 'getKeysByPrefix', + 'incr', + 'decr', + 'getMany', + 'pushItems', + 'popItems', + 'getItemsCount', + 'itemContains', + 'addItems', + 'removeItems', + 'getItems', + 'connect', + 'close' +]; + +/** + * Adapter of the Custom Storage Wrapper. + * Used to handle exceptions as rejected promises, in order to simplify the error handling on storages. + * + * @param log logger instance + * @param wrapper custom storage wrapper to adapt + * @returns an adapted version of the given storage wrapper + */ +export function wrapperAdapter(log: ILogger, wrapper: ICustomStorageWrapper): ICustomStorageWrapper { + + const wrapperAdapter: Record = {}; + + METHODS_TO_PROMISE_WRAP.forEach((method) => { + + // Logs error and wraps it into a rejected promise. + function handleError(e: any) { + log.error(`${LOG_PREFIX} Wrapper '${method}' operation threw an error. Message: ${e}`); + return Promise.reject(e); + } + + wrapperAdapter[method] = function () { + try { + // @ts-ignore + return wrapper[method].apply(wrapper, arguments).then(value => value).catch(handleError); + } catch (e) { + return handleError(e); + } + }; + + }); + + // @ts-ignore + return wrapperAdapter; +} diff --git a/src/storages/types.ts b/src/storages/types.ts index c4b94ad2..288e1fea 100644 --- a/src/storages/types.ts +++ b/src/storages/types.ts @@ -1,79 +1,264 @@ import { MaybeThenable, IMetadata, ISplitFiltersValidation } from '../dtos/types'; import { ILogger } from '../logger/types'; -import { IReadinessManager } from '../readiness/types'; +import { StoredEventWithMetadata, StoredImpressionWithMetadata } from '../sync/submitters/types'; import { SplitIO, ImpressionDTO } from '../types'; +/** + * Interface of a custom wrapper storage. + */ +export interface ICustomStorageWrapper { + + /** Key-Value operations */ + + /** + * Get the value of given `key`. + * + * @function get + * @param {string} key Item to retrieve + * @returns {Promise} A promise that resolves with the element value associated with the specified `key`, + * or null if the key does not exist. The promise rejects if the operation fails. + */ + get: (key: string) => Promise + /** + * Add or update an item with a specified `key` and `value`. + * + * @function set + * @param {string} key Item to update + * @param {string} value Value to set + * @returns {Promise} A promise that resolves if the operation success, whether the key was added or updated. + * The promise rejects if the operation fails. + */ + set: (key: string, value: string) => Promise + /** + * Add or update an item with a specified `key` and `value`. + * + * @function getAndSet + * @param {string} key Item to update + * @param {string} value Value to set + * @returns {Promise} A promise that resolves with the previous value associated to the given `key`, or null if not set. + * The promise rejects if the operation fails. + */ + getAndSet: (key: string, value: string) => Promise + /** + * Removes the specified item by `key`. + * + * @function del + * @param {string} key Item to delete + * @returns {Promise} A promise that resolves if the operation success, whether the key existed and was removed or it didn't exist. + * The promise rejects if the operation fails, for example, if there is a connection error. + */ + del: (key: string) => Promise + /** + * Returns all keys matching the given prefix. + * + * @function getKeysByPrefix + * @param {string} prefix String prefix to match + * @returns {Promise} A promise that resolves with the list of keys that match the given `prefix`. + * The promise rejects if the operation fails. + */ + getKeysByPrefix: (prefix: string) => Promise + /** + * Returns the values of all given `keys`. + * + * @function getMany + * @param {string[]} keys List of keys to retrieve + * @returns {Promise<(string | null)[]>} A promise that resolves with the list of items associated with the specified list of `keys`. + * For every key that does not hold a string value or does not exist, null is returned. The promise rejects if the operation fails. + */ + getMany: (keys: string[]) => Promise<(string | null)[]> + + /** Integer operations */ + + /** + * Increments in 1 the given `key` value or set it in 1 if the value doesn't exist. + * + * @function incr + * @param {string} key Key to increment + * @returns {Promise} A promise that resolves with the value of key after the increment. The promise rejects if the operation fails, + * for example, if there is a connection error or the key contains a string that can not be represented as integer. + */ + incr: (key: string) => Promise + /** + * Decrements in 1 the given `key` value or set it in -1 if the value doesn't exist. + * + * @function decr + * @param {string} key Key to decrement + * @returns {Promise} A promise that resolves with the value of key after the decrement. The promise rejects if the operation fails, + * for example, if there is a connection error or the key contains a string that can not be represented as integer. + */ + decr: (key: string) => Promise + + /** Queue operations */ + + /** + * Inserts given items at the tail of `key` list. If `key` does not exist, an empty list is created before pushing the items. + * + * @function pushItems + * @param {string} key List key + * @param {string[]} items List of items to push + * @returns {Promise} A promise that resolves if the operation success. + * The promise rejects if the operation fails, for example, if there is a connection error or the key holds a value that is not a list. + */ + pushItems: (key: string, items: string[]) => Promise + /** + * Removes and returns the first `count` items from a list. If `key` does not exist, an empty list is items is returned. + * + * @function popItems + * @param {string} key List key + * @param {number} count Number of items to pop + * @returns {Promise} A promise that resolves with the list of removed items from the list, or an empty array when key does not exist. + * The promise rejects if the operation fails, for example, if there is a connection error or the key holds a value that is not a list. + */ + popItems: (key: string, count: number) => Promise + /** + * Returns the count of items in a list, or 0 if `key` does not exist. + * + * @function getItemsCount + * @param {string} key List key + * @returns {Promise} A promise that resolves with the number of items at the `key` list, or 0 when `key` does not exist. + * The promise rejects if the operation fails, for example, if there is a connection error or the key holds a value that is not a list. + */ + getItemsCount: (key: string) => Promise + + /** Set operations */ + + /** + * Returns if item is a member of a set. + * + * @function itemContains + * @param {string} key Set key + * @param {string} item Item value + * @returns {Promise} A promise that resolves with true boolean value if `item` is a member of the set stored at `key`, + * or false if it is not a member or `key` set does not exist. The promise rejects if the operation fails, for example, + * if there is a connection error or the key holds a value that is not a set. + */ + itemContains: (key: string, item: string) => Promise + /** + * Add the specified `items` to the set stored at `key`. Those items that are already part of the set are ignored. + * If key does not exist, an empty set is created before adding the items. + * + * @function addItems + * @param {string} key Set key + * @param {string} items Items to add + * @returns {Promise} A promise that resolves if the operation success. + * The promise rejects if the operation fails, for example, if there is a connection error or the key holds a value that is not a set. + */ + addItems: (key: string, items: string[]) => Promise + /** + * Remove the specified `items` from the set stored at `key`. Those items that are not part of the set are ignored. + * + * @function removeItems + * @param {string} key Set key + * @param {string} items Items to remove + * @returns {Promise} A promise that resolves if the operation success. If key does not exist, the promise also resolves. + * The promise rejects if the operation fails, for example, if there is a connection error or the key holds a value that is not a set. + */ + removeItems: (key: string, items: string[]) => Promise + /** + * Returns all the items of the `key` set. + * + * @function getItems + * @param {string} key Set key + * @returns {Promise} A promise that resolves with the list of items. If key does not exist, the result is an empty list. + * The promise rejects if the operation fails, for example, if there is a connection error or the key holds a value that is not a set. + */ + getItems: (key: string) => Promise + + /** Control operations */ + + /** + * Connects to the underlying storage. + * It is meant for storages that requires to be connected to some database or server. Otherwise it can just return a resolved promise. + * Note: will be called once on SplitFactory instantiation. + * + * @function connect + * @returns {Promise} A promise that resolves when the wrapper successfully connect to the underlying storage. + * The promise rejects with the corresponding error if the wrapper fails to connect. + */ + connect: () => Promise + /** + * Disconnects the underlying storage. + * It is meant for storages that requires to be closed, in order to release resources. Otherwise it can just return a resolved promise. + * Note: will be called once on SplitFactory client destroy. + * + * @function close + * @returns {Promise} A promise that resolves when the operation ends. + * The promise never rejects. + */ + close: () => Promise +} + /** Splits cache */ export interface ISplitsCacheBase { - addSplit(name: string, split: string): MaybeThenable, - addSplits(entries: [string, string][]): MaybeThenable, - removeSplit(name: string): MaybeThenable, - removeSplits(names: string[]): MaybeThenable, + addSplits(entries: [string, string][]): MaybeThenable, + removeSplits(names: string[]): MaybeThenable, getSplit(name: string): MaybeThenable, getSplits(names: string[]): MaybeThenable>, // `fetchMany` in spec - setChangeNumber(changeNumber: number): MaybeThenable, + setChangeNumber(changeNumber: number): MaybeThenable, + // should never reject or throw an exception. Instead return -1 by default, assuming no splits are present in the storage. getChangeNumber(): MaybeThenable, getAll(): MaybeThenable, getSplitNames(): MaybeThenable, + // should never reject or throw an exception. Instead return true by default, asssuming the TT might exist. trafficTypeExists(trafficType: string): MaybeThenable, + // only for Client-Side usesSegments(): MaybeThenable, - clear(): MaybeThenable, + clear(): MaybeThenable, + // should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE. checkCache(): MaybeThenable, + killLocally(name: string, defaultTreatment: string, changeNumber: number): MaybeThenable } export interface ISplitsCacheSync extends ISplitsCacheBase { - addSplit(name: string, split: string): boolean, - addSplits(entries: [string, string][]): boolean[] - removeSplit(name: string): number - removeSplits(names: string[]): number - getSplit(name: string): string | null - getSplits(names: string[]): Record - setChangeNumber(changeNumber: number): boolean - getChangeNumber(): number - getAll(): string[] - getSplitNames(): string[] - trafficTypeExists(trafficType: string): boolean - usesSegments(): boolean - clear(): void - checkCache(): boolean + addSplits(entries: [string, string][]): boolean[], + removeSplits(names: string[]): boolean[], + getSplit(name: string): string | null, + getSplits(names: string[]): Record, + setChangeNumber(changeNumber: number): boolean, + getChangeNumber(): number, + getAll(): string[], + getSplitNames(): string[], + trafficTypeExists(trafficType: string): boolean, + usesSegments(): boolean, + clear(): void, + checkCache(): boolean, killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean } export interface ISplitsCacheAsync extends ISplitsCacheBase { - addSplit(name: string, split: string): Promise, - addSplits(entries: [string, string][]): Promise, - removeSplit(name: string): Promise, - removeSplits(names: string[]): Promise, + addSplits(entries: [string, string][]): Promise, + removeSplits(names: string[]): Promise, getSplit(name: string): Promise, getSplits(names: string[]): Promise>, - setChangeNumber(changeNumber: number): Promise, + setChangeNumber(changeNumber: number): Promise, getChangeNumber(): Promise, getAll(): Promise, getSplitNames(): Promise, trafficTypeExists(trafficType: string): Promise, usesSegments(): Promise, - clear(): Promise, + clear(): Promise, checkCache(): Promise, + killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise } /** Segments cache */ export interface ISegmentsCacheBase { - addToSegment(name: string, segmentKeys: string[]): MaybeThenable // different signature on Server and Client-Side - removeFromSegment(name: string, segmentKeys: string[]): MaybeThenable // different signature on Server and Client-Side + addToSegment(name: string, segmentKeys: string[]): MaybeThenable // different signature on Server and Client-Side + removeFromSegment(name: string, segmentKeys: string[]): MaybeThenable // different signature on Server and Client-Side isInSegment(name: string, key?: string): MaybeThenable // different signature on Server and Client-Side - registerSegments(names: string[]): MaybeThenable // only for Server-Side + registerSegments(names: string[]): MaybeThenable // only for Server-Side getRegisteredSegments(): MaybeThenable // only for Server-Side - setChangeNumber(name: string, changeNumber: number): MaybeThenable // only for Server-Side + setChangeNumber(name: string, changeNumber: number): MaybeThenable // only for Server-Side getChangeNumber(name: string): MaybeThenable // only for Server-Side - clear(): MaybeThenable + clear(): MaybeThenable } // Same API for both variants: SegmentsCache and MySegmentsCache (client-side API) export interface ISegmentsCacheSync extends ISegmentsCacheBase { - addToSegment(name: string, segmentKeys: string[]): boolean - removeFromSegment(name: string, segmentKeys: string[]): boolean + addToSegment(name: string, segmentKeys?: string[]): boolean + removeFromSegment(name: string, segmentKeys?: string[]): boolean isInSegment(name: string, key?: string): boolean registerSegments(names: string[]): boolean getRegisteredSegments(): string[] @@ -84,104 +269,110 @@ export interface ISegmentsCacheSync extends ISegmentsCacheBase { } export interface ISegmentsCacheAsync extends ISegmentsCacheBase { - addToSegment(name: string, segmentKeys: string[]): Promise - removeFromSegment(name: string, segmentKeys: string[]): Promise + addToSegment(name: string, segmentKeys: string[]): Promise + removeFromSegment(name: string, segmentKeys: string[]): Promise isInSegment(name: string, key?: string): Promise - registerSegments(names: string[]): Promise + registerSegments(names: string[]): Promise getRegisteredSegments(): Promise - setChangeNumber(name: string, changeNumber: number): Promise + setChangeNumber(name: string, changeNumber: number): Promise getChangeNumber(name: string): Promise - clear(): Promise + clear(): Promise } -/** - * Producer API of Recorder caches (Impressions, Events and Metrics cache), used by recorders to push data. - */ -export interface IRecorderCacheProducerBase { - track(...args: TArgs): MaybeThenable -} +/** Recorder storages (impressions, events and telemetry) */ -/** - * Consumer API of Recorder caches, used by submitters to pop data and post it to Split BE. - */ -export interface IRecorderCacheConsumerSync { - isEmpty(): boolean // check if cache is empty. Return true if the cache was just created or cleared. - clear(): void // clear cache data - state(): TState // get cache data -} - -export interface IRecorderCacheSync extends IRecorderCacheProducerBase, IRecorderCacheConsumerSync { - track(...args: TArgs): boolean | void +export interface IImpressionsCacheBase { + // Consumer API method, used by impressions tracker, in standalone and consumer modes, to push impressions into the storage. + track(data: ImpressionDTO[]): MaybeThenable } -export interface IRecorderCacheAsync extends IRecorderCacheProducerBase { - track(...args: TArgs): Promise +export interface IEventsCacheBase { + // Consumer API method, used by events tracker, in standalone and consumer modes, to push events into the storage. + track(data: SplitIO.EventData, size?: number): MaybeThenable } -/** Impressions cache */ +/** Impressions and events cache for standalone mode (sync) */ -export interface IImpressionsCacheBase extends IRecorderCacheProducerBase<[ImpressionDTO[]]> { - track(data: ImpressionDTO[]): MaybeThenable +// Producer API methods for sync recorder storages, used by submitters in standalone mode to pop data and post it to Split BE. +export interface IRecorderCacheProducerSync { + // @TODO names are inconsistent with spec + /* Checks if cache is empty. Returns true if the cache was just created or cleared */ + isEmpty(): boolean + /* clears cache data */ + clear(): void + /* Gets cache data */ + state(): T } -export interface IImpressionsCacheSync extends IImpressionsCacheBase, IRecorderCacheSync<[ImpressionDTO[]], ImpressionDTO[]> { - track(data: ImpressionDTO[]): boolean -} -export interface IImpressionsCacheAsync extends IImpressionsCacheBase, IRecorderCacheAsync<[ImpressionDTO[]]> { - track(data: ImpressionDTO[]): Promise +export interface IImpressionsCacheSync extends IImpressionsCacheBase, IRecorderCacheProducerSync { + track(data: ImpressionDTO[]): void } -/** Impression counts cache */ - -export interface IImpressionCountsCacheBase extends IRecorderCacheProducerBase<[string, number, number]> { - track(featureName: string, timeFrame: number, amount: number): MaybeThenable +export interface IEventsCacheSync extends IEventsCacheBase, IRecorderCacheProducerSync { + track(data: SplitIO.EventData, size?: number): boolean + setOnFullQueueCb(cb: () => void): void } -export interface IImpressionCountsCacheSync extends IImpressionCountsCacheBase, IRecorderCacheSync<[string, number, number], Record> { - track(featureName: string, timeFrame: number, amount: number): void -} +/** Impressions and events cache for consumer and producer mode (async) */ -export interface IImpressionCountsCacheAsync extends IImpressionCountsCacheBase, IRecorderCacheAsync<[string, number, number]> { - track(featureName: string, timeFrame: number, amount: number): Promise +// Producer API methods for async recorder storages, used by submitters in producer mode to pop data and post it to Split BE. +export interface IRecorderCacheProducerAsync { + /* returns the number of stored items */ + count(): Promise + /* removes the given number of items from the store. If not provided, it deletes all items */ + drop(count?: number): Promise + /* pops the given number of items from the store */ + popNWithMetadata(count: number): Promise } -/** Events cache */ - -export interface IEventsCacheBase extends IRecorderCacheProducerBase<[SplitIO.EventData, number | undefined]> { - track(data: SplitIO.EventData, size?: number): MaybeThenable +export interface IImpressionsCacheAsync extends IImpressionsCacheBase, IRecorderCacheProducerAsync { + // Consumer API method, used by impressions tracker (in standalone and consumer modes) to push data into. + track(data: ImpressionDTO[]): Promise } -export interface IEventsCacheSync extends IEventsCacheBase, IRecorderCacheSync<[SplitIO.EventData, number | undefined], SplitIO.EventData[]> { - track(data: SplitIO.EventData, size?: number): boolean, - setOnFullQueueCb(cb: () => void): void +export interface IEventsCacheAsync extends IEventsCacheBase, IRecorderCacheProducerAsync { + // Consumer API method, used by events tracker (in standalone and consumer modes) to push data into. + track(data: SplitIO.EventData, size?: number): Promise } -export interface IEventsCacheAsync extends IEventsCacheBase, IRecorderCacheAsync<[SplitIO.EventData, number | undefined]> { - track(data: SplitIO.EventData, size?: number): Promise +/** + * Impression counts cache for impressions dedup in standalone and producer mode. + * Only in memory. Named `ImpressionsCounter` in spec. + */ +export interface IImpressionCountsCacheSync extends IRecorderCacheProducerSync> { + // Used by impressions tracker + track(featureName: string, timeFrame: number, amount: number): void + + // Used by impressions count submitter in standalone and producer mode + isEmpty(): boolean // check if cache is empty. Return true if the cache was just created or cleared. + clear(): void // clear cache data + state(): Record // get cache data } -/** Latencies cache */ -export interface ILatenciesCacheBase extends IRecorderCacheProducerBase<[string, number]> { } +/** Latencies and metric counts cache */ +// @TODO remove. They are deprecated. -export interface ILatenciesCacheSync extends ILatenciesCacheBase, IRecorderCacheSync<[string, number], Record> { +export interface ILatenciesCacheSync extends IRecorderCacheProducerSync> { track(metricName: string, latency: number): boolean + isEmpty(): boolean + clear(): void + state(): Record } -export interface ILatenciesCacheAsync extends ILatenciesCacheBase, IRecorderCacheAsync<[string, number]> { +export interface ILatenciesCacheAsync { track(metricName: string, latency: number): Promise } -/** Counts cache */ - -export interface ICountsCacheBase extends IRecorderCacheProducerBase<[string]> { } - -export interface ICountsCacheSync extends ICountsCacheBase, IRecorderCacheSync<[string], Record> { +export interface ICountsCacheSync extends IRecorderCacheProducerSync> { track(metricName: string): boolean + isEmpty(): boolean + clear(): void + state(): Record } -export interface ICountsCacheAsync extends ICountsCacheBase, IRecorderCacheAsync<[string]> { +export interface ICountsCacheAsync { track(metricName: string): Promise } @@ -193,15 +384,14 @@ export interface IStorageBase< TSplitsCache extends ISplitsCacheBase, TSegmentsCache extends ISegmentsCacheBase, TImpressionsCache extends IImpressionsCacheBase, - TImpressionCountsCache extends IImpressionCountsCacheBase, TEventsCache extends IEventsCacheBase, - TLatenciesCache extends ILatenciesCacheBase, - TCountsCache extends ICountsCacheBase, + TLatenciesCache extends ILatenciesCacheSync | ILatenciesCacheAsync, + TCountsCache extends ICountsCacheSync | ICountsCacheAsync, > { splits: TSplitsCache, segments: TSegmentsCache, impressions: TImpressionsCache, - impressionCounts?: TImpressionCountsCache, + impressionCounts?: IImpressionCountsCacheSync, events: TEventsCache, latencies?: TLatenciesCache, counts?: TCountsCache, @@ -212,7 +402,6 @@ export type IStorageSync = IStorageBase< ISplitsCacheSync, ISegmentsCacheSync, IImpressionsCacheSync, - IImpressionCountsCacheSync, IEventsCacheSync, ILatenciesCacheSync, ICountsCacheSync @@ -226,7 +415,6 @@ export type IStorageAsync = IStorageBase< ISplitsCacheAsync, ISegmentsCacheAsync, IImpressionsCacheAsync, - IImpressionCountsCacheAsync, IEventsCacheAsync, ILatenciesCacheAsync, ICountsCacheAsync @@ -238,15 +426,28 @@ export type DataLoader = (storage: IStorageSync, matchingKey: string) => void export interface IStorageFactoryParams { log: ILogger, - eventsQueueSize: number, - optimize: boolean /* whether create the `impressionCounts` cache (OPTIMIZED impression mode) or not (DEBUG impression mode) */, - dataLoader?: DataLoader, + eventsQueueSize?: number, + optimize?: boolean /* whether create the `impressionCounts` cache (OPTIMIZED impression mode) or not (DEBUG impression mode) */, // ATM, only used by InLocalStorage matchingKey?: string, /* undefined on server-side SDKs */ - splitFiltersValidation: ISplitFiltersValidation, + splitFiltersValidation?: ISplitFiltersValidation, - // ATM, only used by InRedisStorage. @TODO pass a callback to simplify custom storages. - readinessManager: IReadinessManager, + // This callback is invoked when the storage is ready to be used. Error-first callback style: if an error is passed, + // it means that the storge fail to connect and shouldn't be used. + // It is meant for emitting SDK_READY event in consumer mode, and for synchronizer to wait before using the storage. + onReadyCb?: (error?: any) => void, metadata: IMetadata, } + +export type StorageType = 'MEMORY' | 'LOCALSTORAGE' | 'REDIS' | 'CUSTOM'; + +export type IStorageSyncFactory = { + type: StorageType, + (params: IStorageFactoryParams): IStorageSync +} + +export type IStorageAsyncFactory = { + type: StorageType, + (params: IStorageFactoryParams): IStorageAsync +} diff --git a/src/sync/__tests__/syncTask.spec.ts b/src/sync/__tests__/syncTask.spec.ts new file mode 100644 index 00000000..b947e0a3 --- /dev/null +++ b/src/sync/__tests__/syncTask.spec.ts @@ -0,0 +1,84 @@ +import syncTaskFactory from '../syncTask'; +import { loggerMock } from '../../logger/__tests__/sdkLogger.mock'; + +const period = 30; +const taskResult = 'taskResult'; +const asyncTask = jest.fn(() => Promise.resolve(taskResult)); + +test('syncTaskFactory', (done) => { + + const syncTask = syncTaskFactory(loggerMock, asyncTask, period); + + // The initial state of the syncTask is not "running" periodically neither "executing" + expect(syncTask.isExecuting()).toBe(false); + expect(syncTask.isRunning()).toBe(false); + + // Calling `start` periodically executes the given task and returns its result + const startArgs = [1, 2]; // @ts-ignore + syncTask.start(...startArgs).then(async (result) => { + expect(syncTask.isRunning()).toBe(true); // Running periodically + expect(syncTask.isExecuting()).toBe(false); // Already executed + expect(result).toBe(taskResult); + expect(asyncTask).toBeCalledWith(...startArgs); + + // Calling `start` again has not effect + expect(syncTask.start(...startArgs)).toBe(undefined); + + // Calling `execute` inmediatelly executes the given task and returns its result + result = await syncTask.execute(3, 4); + expect(result).toBe(taskResult); + expect(asyncTask).toHaveBeenLastCalledWith(3, 4); + expect(syncTask.isExecuting()).toBe(false); // Already executed + + // Calling `execute` again result in a new execution of the given task + result = await syncTask.execute(5, 6); + expect(result).toBe(taskResult); + expect(asyncTask).toHaveBeenLastCalledWith(5, 6); + expect(syncTask.isExecuting()).toBe(false); // Already executed + + }); + + expect(syncTask.isExecuting()).toBe(true); // Executing + + setTimeout(() => { + expect(asyncTask).toHaveBeenLastCalledWith(...startArgs); // Periodic call should be done with the initial `start` arguments + expect(asyncTask).toBeCalledTimes(4); // The task was executed 4 times: twice due to periodic execution and twice due to execute call + + setTimeout(() => { + expect(asyncTask).toHaveBeenLastCalledWith(...startArgs); // Periodic call should be done with the initial `start` arguments + expect(asyncTask).toBeCalledTimes(5); // The task was executed 5 times: 3 due to periodic execution and twice due to execute call + + // Calling `stop` stops the periodic execution of the given task + expect(syncTask.isRunning()).toBe(true); // Running periodically + syncTask.stop(); + expect(syncTask.isRunning()).toBe(false); // Stop running periodically + + setTimeout(() => { + expect(asyncTask).toBeCalledTimes(5); // Stopped task should not be called again + + // Stopping and starting + syncTask.stop(); + syncTask.start(); // Inmediatelly call task + syncTask.stop(); + syncTask.start(); // Inmediatelly call task + syncTask.stop(); + expect(asyncTask).toBeCalledTimes(7); + + // // Resume periodic execution + syncTask.start(); // Inmediatelly call task + syncTask.start(); // No effect + expect(asyncTask).toBeCalledTimes(8); + + setTimeout(() => { + expect(asyncTask).toBeCalledTimes(9); // Stopped task should not be called again + expect(syncTask.isRunning()).toBe(true); // Running periodically + syncTask.stop(); // Finally stop to finish the test + expect(syncTask.isRunning()).toBe(false); // Stop running periodically + + done(); + }, period + 10); + }, period + 10); + }, period + 10); + }, period + 10); + +}); diff --git a/src/sync/offline/LocalhostFromFile.ts b/src/sync/offline/LocalhostFromFile.ts new file mode 100644 index 00000000..33e6c121 --- /dev/null +++ b/src/sync/offline/LocalhostFromFile.ts @@ -0,0 +1,12 @@ +import { splitsParserFromFileFactory } from './splitsParser/splitsParserFromFile'; +import { syncManagerOfflineFactory } from './syncManagerOffline'; +import { SplitIO } from '../../types'; + +// Singleton instance of the factory function for offline SyncManager from YAML file (a.k.a. localhostFromFile) +// Requires Node 'fs' and 'path' APIs. +const localhostFromFile = syncManagerOfflineFactory(splitsParserFromFileFactory) as SplitIO.LocalhostFactory; +localhostFromFile.type = 'LocalhostFromFile'; + +export function LocalhostFromFile(): SplitIO.LocalhostFactory { + return localhostFromFile; +} diff --git a/src/sync/offline/LocalhostFromObject.ts b/src/sync/offline/LocalhostFromObject.ts new file mode 100644 index 00000000..b823e7ee --- /dev/null +++ b/src/sync/offline/LocalhostFromObject.ts @@ -0,0 +1,12 @@ +import { splitsParserFromSettingsFactory } from './splitsParser/splitsParserFromSettings'; +import { syncManagerOfflineFactory } from './syncManagerOffline'; +import { SplitIO } from '../../types'; + +// Singleton instance of the factory function for offline SyncManager from object (a.k.a. localhostFromObject) +// SDK instances instantiate their SyncManagers with the same factory +const localhostFromObject = syncManagerOfflineFactory(splitsParserFromSettingsFactory) as SplitIO.LocalhostFactory; +localhostFromObject.type = 'LocalhostFromObject'; + +export function LocalhostFromObject(): SplitIO.LocalhostFactory { + return localhostFromObject; +} diff --git a/src/sync/offline/splitsParser/splitsParserFromFile.ts b/src/sync/offline/splitsParser/splitsParserFromFile.ts index b56052c6..95ea8d14 100644 --- a/src/sync/offline/splitsParser/splitsParserFromFile.ts +++ b/src/sync/offline/splitsParser/splitsParserFromFile.ts @@ -7,8 +7,9 @@ import yaml from 'js-yaml'; import { isString, endsWith, find, forOwn, uniq, } from '../../../utils/lang'; import parseCondition, { IMockSplitEntry } from './parseCondition'; import { ISplitPartial } from '../../../dtos/types'; -import { SplitIO } from '../../../types'; +import { ISettings, SplitIO } from '../../../types'; import { ILogger } from '../../../logger/types'; +import { ISplitsParser } from './types'; const logPrefix = 'sync:offline:splits-fetcher: '; @@ -16,8 +17,6 @@ type IYamlSplitEntry = Record const DEFAULT_FILENAME = '.split'; -let previousMock = 'NO_MOCK_LOADED'; - function configFilesPath(configFilePath?: SplitIO.MockedFeaturesFilePath): SplitIO.MockedFeaturesFilePath { if (configFilePath === DEFAULT_FILENAME || !isString(configFilePath)) { let root = process.env.HOME; @@ -39,96 +38,6 @@ function configFilesPath(configFilePath?: SplitIO.MockedFeaturesFilePath): Split return configFilePath as SplitIO.MockedFeaturesFilePath; } -// Parse `.split` configuration file and return a map of "Split Objects" -function readSplitConfigFile(log: ILogger, filePath: SplitIO.MockedFeaturesFilePath): false | Record { - const SPLIT_POSITION = 0; - const TREATMENT_POSITION = 1; - let data; - - try { - data = fs.readFileSync(filePath, 'utf-8'); - } catch (e) { - log.error(e.message); - - return {}; - } - - if (data === previousMock) return false; - previousMock = data; - - const splitObjects = data.split(/\r?\n/).reduce((accum, line, index) => { - let tuple: string | string[] = line.trim(); - - if (tuple === '' || tuple.charAt(0) === '#') { - log.debug(logPrefix + `Ignoring empty line or comment at #${index}`); - } else { - tuple = tuple.split(/\s+/); - - if (tuple.length !== 2) { - log.debug(logPrefix + `Ignoring line since it does not have exactly two columns #${index}`); - } else { - const splitName = tuple[SPLIT_POSITION]; - const condition = parseCondition({ treatment: tuple[TREATMENT_POSITION] }); - accum[splitName] = { conditions: [condition], configurations: {}, trafficTypeName: 'localhost' }; - } - } - - return accum; - }, {} as Record); - - return splitObjects; -} - -// Parse `.yml` or `.yaml` configuration files and return a map of "Split Objects" -function readYAMLConfigFile(log: ILogger, filePath: SplitIO.MockedFeaturesFilePath): false | Record { - let data = ''; - let yamldoc = null; - - try { - data = fs.readFileSync(filePath, 'utf8'); - - if (data === previousMock) return false; - previousMock = data; - - yamldoc = yaml.safeLoad(data); - } catch (e) { - log.error(e); - - return {}; - } - - // Each entry will be mapped to a condition, but we'll also keep the configurations map. - const mocksData = (yamldoc as IYamlSplitEntry[]).reduce((accum, splitEntry) => { - const splitName = Object.keys(splitEntry)[0]; - - if (!splitName || !isString(splitEntry[splitName].treatment)) - log.error(logPrefix + 'Ignoring entry on YAML since the format is incorrect.'); - - const mockData = splitEntry[splitName]; - - // "Template" for each split accumulated data - if (!accum[splitName]) { - accum[splitName] = { - configurations: {}, conditions: [], treatments: [], trafficTypeName: 'localhost' - }; - } - - // Assign the config if there is one on the mock - if (mockData.config) accum[splitName].configurations[mockData.treatment] = mockData.config; - // Parse the condition from the entry. - const condition = parseCondition(mockData); - accum[splitName].conditions[condition.conditionType === 'ROLLOUT' ? 'push' : 'unshift'](condition); - // Also keep track of the treatments, will be useful for manager functionality. - accum[splitName].treatments.push(mockData.treatment); - - return accum; - }, {} as Record & { treatments: string[] }>); - - arrangeConditions(mocksData); - - return mocksData; -} - // This function is not pure nor meant to be. Here we apply modifications to cover // for behaviour that's ensured by the BE. function arrangeConditions(mocksData: Record & { treatments: string[] }>) { @@ -160,18 +69,114 @@ function arrangeConditions(mocksData: Record & { }); } -// Load the content of a configuration file into an Object -export default function splitsParserFromFile({ features, log }: { features?: SplitIO.MockedFeaturesFilePath, log: ILogger }): false | Record { - const filePath = configFilesPath(features); - let mockData: false | Record; - - // If we have a filePath, it means the extension is correct, choose the parser. - if (endsWith(filePath, '.split')) { - log.warn(logPrefix + '.split mocks will be deprecated soon in favor of YAML files, which provide more targeting power. Take a look in our documentation.'); - mockData = readSplitConfigFile(log, filePath); - } else { - mockData = readYAMLConfigFile(log, filePath); +export function splitsParserFromFileFactory(): ISplitsParser { + + let previousMock = 'NO_MOCK_LOADED'; + + // Parse `.split` configuration file and return a map of "Split Objects" + function readSplitConfigFile(log: ILogger, filePath: SplitIO.MockedFeaturesFilePath): false | Record { + const SPLIT_POSITION = 0; + const TREATMENT_POSITION = 1; + let data; + + try { + data = fs.readFileSync(filePath, 'utf-8'); + } catch (e) { + log.error(e.message); + + return {}; + } + + if (data === previousMock) return false; + previousMock = data; + + const splitObjects = data.split(/\r?\n/).reduce((accum, line, index) => { + let tuple: string | string[] = line.trim(); + + if (tuple === '' || tuple.charAt(0) === '#') { + log.debug(logPrefix + `Ignoring empty line or comment at #${index}`); + } else { + tuple = tuple.split(/\s+/); + + if (tuple.length !== 2) { + log.debug(logPrefix + `Ignoring line since it does not have exactly two columns #${index}`); + } else { + const splitName = tuple[SPLIT_POSITION]; + const condition = parseCondition({ treatment: tuple[TREATMENT_POSITION] }); + accum[splitName] = { conditions: [condition], configurations: {}, trafficTypeName: 'localhost' }; + } + } + + return accum; + }, {} as Record); + + return splitObjects; + } + + // Parse `.yml` or `.yaml` configuration files and return a map of "Split Objects" + function readYAMLConfigFile(log: ILogger, filePath: SplitIO.MockedFeaturesFilePath): false | Record { + let data = ''; + let yamldoc = null; + + try { + data = fs.readFileSync(filePath, 'utf8'); + + if (data === previousMock) return false; + previousMock = data; + + yamldoc = yaml.safeLoad(data); + } catch (e) { + log.error(e); + + return {}; + } + + // Each entry will be mapped to a condition, but we'll also keep the configurations map. + const mocksData = (yamldoc as IYamlSplitEntry[]).reduce((accum, splitEntry) => { + const splitName = Object.keys(splitEntry)[0]; + + if (!splitName || !isString(splitEntry[splitName].treatment)) + log.error(logPrefix + 'Ignoring entry on YAML since the format is incorrect.'); + + const mockData = splitEntry[splitName]; + + // "Template" for each split accumulated data + if (!accum[splitName]) { + accum[splitName] = { + configurations: {}, conditions: [], treatments: [], trafficTypeName: 'localhost' + }; + } + + // Assign the config if there is one on the mock + if (mockData.config) accum[splitName].configurations[mockData.treatment] = mockData.config; + // Parse the condition from the entry. + const condition = parseCondition(mockData); + accum[splitName].conditions[condition.conditionType === 'ROLLOUT' ? 'push' : 'unshift'](condition); + // Also keep track of the treatments, will be useful for manager functionality. + accum[splitName].treatments.push(mockData.treatment); + + return accum; + }, {} as Record & { treatments: string[] }>); + + arrangeConditions(mocksData); + + return mocksData; } - return mockData; + // Load the content of a configuration file into an Object + return function splitsParserFromFile({ features, log }: ISettings): false | Record { + const filePath = configFilesPath(features as string); + let mockData: false | Record; + + // If we have a filePath, it means the extension is correct, choose the parser. + if (endsWith(filePath, '.split')) { + log.warn(logPrefix + '.split mocks will be deprecated soon in favor of YAML files, which provide more targeting power. Take a look in our documentation.'); + mockData = readSplitConfigFile(log, filePath); + } else { + mockData = readYAMLConfigFile(log, filePath); + } + + return mockData; + }; + } diff --git a/src/sync/offline/splitsParser/splitsParserFromSettings.ts b/src/sync/offline/splitsParser/splitsParserFromSettings.ts index 14b9a059..f9cf9175 100644 --- a/src/sync/offline/splitsParser/splitsParserFromSettings.ts +++ b/src/sync/offline/splitsParser/splitsParserFromSettings.ts @@ -3,8 +3,6 @@ import { ISettings, SplitIO } from '../../../types'; import { isObject, forOwn } from '../../../utils/lang'; import parseCondition from './parseCondition'; -let previousMock: SplitIO.MockedFeaturesMap = { 'emptyMock': '1' }; - function hasTreatmentChanged(prev: string | SplitIO.TreatmentWithConfig, curr: string | SplitIO.TreatmentWithConfig) { if (typeof prev !== typeof curr) return true; @@ -15,54 +13,60 @@ function hasTreatmentChanged(prev: string | SplitIO.TreatmentWithConfig, curr: s } } -function mockUpdated(currentData: SplitIO.MockedFeaturesMap) { - const names = Object.keys(currentData); +export function splitsParserFromSettingsFactory() { - // Different amount of items - if (names.length !== Object.keys(previousMock).length) { - previousMock = currentData; - return true; - } + let previousMock: SplitIO.MockedFeaturesMap = { 'emptyMock': '1' }; - return names.some(name => { - const newSplit = !previousMock[name]; - const newTreatment = hasTreatmentChanged(previousMock[name], currentData[name]); - const changed = newSplit || newTreatment; + function mockUpdated(currentData: SplitIO.MockedFeaturesMap) { + const names = Object.keys(currentData); - if (changed) previousMock = currentData; + // Different amount of items + if (names.length !== Object.keys(previousMock).length) { + previousMock = currentData; + return true; + } - return changed; - }); -} + return names.some(name => { + const newSplit = !previousMock[name]; + const newTreatment = hasTreatmentChanged(previousMock[name], currentData[name]); + const changed = newSplit || newTreatment; -/** - * - * @param features validated object with mocked features mapping. - */ -export default function splitsParserFromSettings(settings: ISettings): false | Record { - const features = settings.features as SplitIO.MockedFeaturesMap || {}; + if (changed) previousMock = currentData; - if (!mockUpdated(features)) return false; + return changed; + }); + } - const splitObjects: Record = {}; + /** + * + * @param settings validated object with mocked features mapping. + */ + return function splitsParserFromSettings(settings: ISettings): false | Record { + const features = settings.features as SplitIO.MockedFeaturesMap || {}; - forOwn(features, (data, splitName) => { - let treatment = data; - let config = null; + if (!mockUpdated(features)) return false; - if (isObject(data)) { - treatment = (data as SplitIO.TreatmentWithConfig).treatment; - config = (data as SplitIO.TreatmentWithConfig).config || config; - } - const configurations: Record = {}; - if (config !== null) configurations[treatment as string] = config; + const splitObjects: Record = {}; + + forOwn(features, (data, splitName) => { + let treatment = data; + let config = null; + + if (isObject(data)) { + treatment = (data as SplitIO.TreatmentWithConfig).treatment; + config = (data as SplitIO.TreatmentWithConfig).config || config; + } + const configurations: Record = {}; + if (config !== null) configurations[treatment as string] = config; + + splitObjects[splitName] = { + trafficTypeName: 'localhost', + conditions: [parseCondition({ treatment: treatment as string })], + configurations + }; + }); - splitObjects[splitName] = { - trafficTypeName: 'localhost', - conditions: [parseCondition({ treatment: treatment as string })], - configurations - }; - }); + return splitObjects; + }; - return splitObjects; } diff --git a/src/sync/syncManagerOffline.ts b/src/sync/offline/syncManagerOffline.ts similarity index 76% rename from src/sync/syncManagerOffline.ts rename to src/sync/offline/syncManagerOffline.ts index 20a9b074..58a75b6f 100644 --- a/src/sync/syncManagerOffline.ts +++ b/src/sync/offline/syncManagerOffline.ts @@ -1,9 +1,9 @@ -import { ISyncManager, ISyncManagerCS, ISyncManagerFactoryParams } from './types'; -import fromObjectSyncTaskFactory from './offline/syncTasks/fromObjectSyncTask'; +import { ISyncManager, ISyncManagerCS, ISyncManagerFactoryParams } from '../types'; +import fromObjectSyncTaskFactory from './syncTasks/fromObjectSyncTask'; import objectAssign from 'object-assign'; -import { ISplitsParser } from './offline/splitsParser/types'; -import { IReadinessManager } from '../readiness/types'; -import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants'; +import { ISplitsParser } from './splitsParser/types'; +import { IReadinessManager } from '../../readiness/types'; +import { SDK_SEGMENTS_ARRIVED } from '../../readiness/constants'; function flush() { return Promise.resolve(); @@ -16,7 +16,7 @@ function flush() { * @param splitsParser e.g., `splitsParserFromFile`, `splitsParserFromSettings`. */ export function syncManagerOfflineFactory( - splitsParser: ISplitsParser + splitsParserFactory: () => ISplitsParser ): (params: ISyncManagerFactoryParams) => ISyncManagerCS { /** @@ -29,7 +29,7 @@ export function syncManagerOfflineFactory( }: ISyncManagerFactoryParams): ISyncManagerCS { return objectAssign( - fromObjectSyncTaskFactory(splitsParser, storage, readiness, settings), + fromObjectSyncTaskFactory(splitsParserFactory(), storage, readiness, settings), { // fake flush, that resolves immediately flush, @@ -38,7 +38,7 @@ export function syncManagerOfflineFactory( shared(matchingKey: string, readinessManager: IReadinessManager): ISyncManager { return { start() { - // In LOCALHOST mode, shared clients are ready in the next event cycle than created + // In LOCALHOST mode, shared clients are ready in the next event-loop cycle than created // SDK_READY cannot be emitted directly because this will not update the readiness status setTimeout(() => { readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED); // SDK_SPLITS_ARRIVED emitted by main SyncManager diff --git a/src/sync/offline/syncTasks/fromObjectSyncTask.ts b/src/sync/offline/syncTasks/fromObjectSyncTask.ts index 66c51db1..2eccc27c 100644 --- a/src/sync/offline/syncTasks/fromObjectSyncTask.ts +++ b/src/sync/offline/syncTasks/fromObjectSyncTask.ts @@ -7,7 +7,7 @@ import syncTaskFactory from '../../syncTask'; import { ISyncTask } from '../../types'; import { ISettings } from '../../../types'; import { CONTROL } from '../../../utils/constants'; -import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants'; +import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants'; import { SYNC_OFFLINE_DATA, ERROR_SYNC_OFFLINE_LOADING } from '../../../logger/constants'; /** @@ -20,7 +20,8 @@ export function fromObjectUpdaterFactory( settings: ISettings, ): () => Promise { - const log = settings.log; + const log = settings.log, splitsCache = storage.splits; + let startingUp = true; return function objectUpdater() { const splits: [string, string][] = []; @@ -53,11 +54,20 @@ export function fromObjectUpdaterFactory( }); return Promise.all([ - storage.splits.clear(), - storage.splits.addSplits(splits) + splitsCache.clear(), // required to sync removed splits from mock + splitsCache.addSplits(splits) ]).then(() => { readiness.splits.emit(SDK_SPLITS_ARRIVED); - readiness.segments.emit(SDK_SEGMENTS_ARRIVED); + + if (startingUp) { + startingUp = false; + Promise.resolve(splitsCache.checkCache()).then(cacheReady => { + // Emits SDK_READY_FROM_CACHE + if (cacheReady) readiness.splits.emit(SDK_SPLITS_CACHE_LOADED); + // Emits SDK_READY + readiness.segments.emit(SDK_SEGMENTS_ARRIVED); + }); + } return true; }); } else { diff --git a/src/sync/polling/fetchers/mySegmentsFetcher.ts b/src/sync/polling/fetchers/mySegmentsFetcher.ts index 2ba6b7b5..298ef558 100644 --- a/src/sync/polling/fetchers/mySegmentsFetcher.ts +++ b/src/sync/polling/fetchers/mySegmentsFetcher.ts @@ -1,5 +1,4 @@ -import { SplitError } from '../../../utils/lang/errors'; -import { IFetchMySegments } from '../../../services/types'; +import { IFetchMySegments, IResponse } from '../../../services/types'; import { IMySegmentsResponseItem } from '../../../dtos/types'; import { IMySegmentsFetcher } from './types'; @@ -12,7 +11,7 @@ export default function mySegmentsFetcherFactory(fetchMySegments: IFetchMySegmen return function mySegmentsFetcher( noCache?: boolean, // Optional decorator for `fetchMySegments` promise, such as timeout or time tracker - decorator?: (promise: Promise) => Promise + decorator?: (promise: Promise) => Promise ): Promise { let mySegmentsPromise = fetchMySegments(userMatchingKey, noCache); @@ -20,8 +19,7 @@ export default function mySegmentsFetcherFactory(fetchMySegments: IFetchMySegmen // Extract segment names return mySegmentsPromise - // JSON parsing errors are handled as SplitErrors, to distinguish from user callback errors - .then(resp => resp.json().catch(error => { throw new SplitError(error.message); })) + .then(resp => resp.json()) .then(json => json.mySegments.map((segment: IMySegmentsResponseItem) => segment.name)); }; diff --git a/src/sync/polling/fetchers/segmentChangesFetcher.ts b/src/sync/polling/fetchers/segmentChangesFetcher.ts index db7d6c38..0bf14400 100644 --- a/src/sync/polling/fetchers/segmentChangesFetcher.ts +++ b/src/sync/polling/fetchers/segmentChangesFetcher.ts @@ -4,7 +4,6 @@ import { ISegmentChangesFetcher } from './types'; function greedyFetch(fetchSegmentChanges: IFetchSegmentChanges, since: number, segmentName: string, noCache?: boolean): Promise { return fetchSegmentChanges(since, segmentName, noCache) - // no need to handle json parsing errors as SplitError, since errors are handled differently for segments .then(resp => resp.json()) .then((json: ISegmentChangesResponse) => { let { since, till } = json; @@ -15,13 +14,6 @@ function greedyFetch(fetchSegmentChanges: IFetchSegmentChanges, since: number, s return [flatMe[0], ...flatMe[1]]; }); } - }) - .catch(err => { - // If the operation is forbidden it may be due to permissions, don't recover and propagate the error. - if (err.statusCode === 403) throw err; - // if something goes wrong with the request to the server, we are going to - // stop requesting information till the next round of downloading - return []; }); } diff --git a/src/sync/polling/fetchers/splitChangesFetcher.ts b/src/sync/polling/fetchers/splitChangesFetcher.ts index d8679c31..47de07ea 100644 --- a/src/sync/polling/fetchers/splitChangesFetcher.ts +++ b/src/sync/polling/fetchers/splitChangesFetcher.ts @@ -1,5 +1,4 @@ -import { SplitError } from '../../../utils/lang/errors'; -import { IFetchSplitChanges } from '../../../services/types'; +import { IFetchSplitChanges, IResponse } from '../../../services/types'; import { ISplitChangesFetcher } from './types'; /** @@ -12,15 +11,13 @@ export default function splitChangesFetcherFactory(fetchSplitChanges: IFetchSpli since: number, noCache?: boolean, // Optional decorator for `fetchSplitChanges` promise, such as timeout or time tracker - decorator?: (promise: Promise) => Promise + decorator?: (promise: Promise) => Promise ) { let splitsPromise = fetchSplitChanges(since, noCache); if (decorator) splitsPromise = decorator(splitsPromise); - return splitsPromise - // JSON parsing errors are handled as SplitErrors, to distinguish from user callback errors - .then(resp => resp.json().catch(error => { throw new SplitError(error.message); })); + return splitsPromise.then(resp => resp.json()); }; } diff --git a/src/sync/polling/fetchers/types.ts b/src/sync/polling/fetchers/types.ts index e39cb85a..4d1272f0 100644 --- a/src/sync/polling/fetchers/types.ts +++ b/src/sync/polling/fetchers/types.ts @@ -1,9 +1,10 @@ import { ISplitChangesResponse, ISegmentChangesResponse } from '../../../dtos/types'; +import { IResponse } from '../../../services/types'; export type ISplitChangesFetcher = ( since: number, noCache?: boolean, - decorator?: (promise: Promise) => Promise + decorator?: (promise: Promise) => Promise ) => Promise export type ISegmentChangesFetcher = ( @@ -15,5 +16,5 @@ export type ISegmentChangesFetcher = ( export type IMySegmentsFetcher = ( noCache?: boolean, - decorator?: (promise: Promise) => Promise + decorator?: (promise: Promise) => Promise ) => Promise diff --git a/src/sync/polling/pollingManagerSS.ts b/src/sync/polling/pollingManagerSS.ts index 24b27600..773da265 100644 --- a/src/sync/polling/pollingManagerSS.ts +++ b/src/sync/polling/pollingManagerSS.ts @@ -6,7 +6,7 @@ import { ISplitApi } from '../../services/types'; import { ISettings } from '../../types'; import { IPollingManager, ISegmentsSyncTask, ISplitsSyncTask } from './types'; import thenable from '../../utils/promise/thenable'; -import { POLLING_START, POLLING_STOP, logPrefixSyncPolling } from '../../logger/constants'; +import { POLLING_START, POLLING_STOP, LOG_PREFIX_SYNC_POLLING } from '../../logger/constants'; /** * Expose start / stop mechanism for pulling data from services. @@ -30,8 +30,8 @@ export default function pollingManagerSSFactory( // Start periodic fetching (polling) start() { log.info(POLLING_START); - log.debug(logPrefixSyncPolling + `Splits will be refreshed each ${settings.scheduler.featuresRefreshRate} millis`); - log.debug(logPrefixSyncPolling + `Segments will be refreshed each ${settings.scheduler.segmentsRefreshRate} millis`); + log.debug(LOG_PREFIX_SYNC_POLLING + `Splits will be refreshed each ${settings.scheduler.featuresRefreshRate} millis`); + log.debug(LOG_PREFIX_SYNC_POLLING + `Segments will be refreshed each ${settings.scheduler.segmentsRefreshRate} millis`); const startingUp = splitsSyncTask.start(); if (thenable(startingUp)) { diff --git a/src/sync/polling/syncTasks/mySegmentsSyncTask.ts b/src/sync/polling/syncTasks/mySegmentsSyncTask.ts index 6b19166d..6547c3c6 100644 --- a/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +++ b/src/sync/polling/syncTasks/mySegmentsSyncTask.ts @@ -1,101 +1,15 @@ -import { IMySegmentsFetcher } from '../fetchers/types'; -import { ISegmentsCacheSync, ISplitsCacheSync, IStorageSync } from '../../../storages/types'; -import { IReadinessManager, ISegmentsEventEmitter } from '../../../readiness/types'; -import { SplitError } from '../../../utils/lang/errors'; -import timeout from '../../../utils/promise/timeout'; +import { IStorageSync } from '../../../storages/types'; +import { IReadinessManager } from '../../../readiness/types'; import syncTaskFactory from '../../syncTask'; import { ISegmentsSyncTask } from '../types'; import { IFetchMySegments } from '../../../services/types'; import mySegmentsFetcherFactory from '../fetchers/mySegmentsFetcher'; import { ISettings } from '../../../types'; -import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants'; -import { ILogger } from '../../../logger/types'; -import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants'; - -type IMySegmentsUpdater = (segmentList?: string[], noCache?: boolean) => Promise +import { mySegmentsUpdaterFactory } from '../updaters/mySegmentsUpdater'; /** - * factory of MySegments updater (a.k.a, SegmentsSyncTask), a task that: - * - fetches mySegments using `mySegmentsFetcher` - * - updates `mySegmentsCache` - * - uses `segmentsEventEmitter` to emit events related to segments data updates + * Creates a sync task that periodically executes a `mySegmentsUpdater` task */ -function mySegmentsUpdaterFactory( - log: ILogger, - mySegmentsFetcher: IMySegmentsFetcher, - splitsCache: ISplitsCacheSync, - mySegmentsCache: ISegmentsCacheSync, - segmentsEventEmitter: ISegmentsEventEmitter, - requestTimeoutBeforeReady: number, - retriesOnFailureBeforeReady: number, -): IMySegmentsUpdater { - - let readyOnAlreadyExistentState = true; - let startingUp = true; - - /** timeout and telemetry decorator for `splitChangesFetcher` promise */ - function _promiseDecorator(promise: Promise) { - if (startingUp) promise = timeout(requestTimeoutBeforeReady, promise); - return promise; - - // @TODO telemetry - // NOTE: We only collect metrics on startup. - // mySegmentsPromise = tracker.start(tracker.TaskNames.MY_SEGMENTS_FETCH, startingUp ? metricCollectors : false, mySegmentsPromise); - } - - // @TODO if allowing custom storages, handle async execution and wrap errors as SplitErrors to distinguish from user callback errors - function updateSegments(segments: string[]) { - // Update the list of segment names available - const shouldNotifyUpdate = mySegmentsCache.resetSegments(segments); - - // Notify update if required - if (splitsCache.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) { - readyOnAlreadyExistentState = false; - segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED); - } - } - - function _mySegmentsUpdater(retry: number, segmentList?: string[], noCache?: boolean): Promise { - const updaterPromise: Promise = segmentList ? - // If segmentList is provided, there is no need to fetch mySegments - new Promise((res) => { updateSegments(segmentList); res(true); }) : - // If not provided, fetch mySegments - mySegmentsFetcher(noCache, _promiseDecorator).then(segments => { - // Only when we have downloaded segments completely, we should not keep retrying anymore - startingUp = false; - - updateSegments(segments); - return true; - }); - - return updaterPromise.catch(error => { - // handle user callback errors - if (!(error instanceof SplitError)) setTimeout(() => { throw error; }, 0); - - if (startingUp && retriesOnFailureBeforeReady > retry) { - retry += 1; - log.warn(SYNC_MYSEGMENTS_FETCH_RETRY, [retry, error]); - return _mySegmentsUpdater(retry); // no need to forward `segmentList` and `noCache` params - } else { - startingUp = false; - } - - return false; - }); - } - - /** - * MySegments updater returns a promise that resolves with a `false` boolean value if it fails to fetch mySegments or synchronize them with the storage. - * - * @param {string[] | undefined} segmentList list of mySegments names to sync in the storage. If the list is `undefined`, it fetches them before syncing in the storage. - * @param {boolean | undefined} noCache true to revalidate data to fetch - */ - return function mySegmentsUpdater(segmentList?: string[], noCache?: boolean) { - return _mySegmentsUpdater(0, segmentList, noCache); - }; - -} - export default function mySegmentsSyncTaskFactory( fetchMySegments: IFetchMySegments, storage: IStorageSync, diff --git a/src/sync/polling/syncTasks/segmentsSyncTask.ts b/src/sync/polling/syncTasks/segmentsSyncTask.ts index 4d0d400b..69cda5a3 100644 --- a/src/sync/polling/syncTasks/segmentsSyncTask.ts +++ b/src/sync/polling/syncTasks/segmentsSyncTask.ts @@ -1,111 +1,15 @@ -import { ISegmentChangesFetcher } from '../fetchers/types'; -import { ISegmentsCacheSync, IStorageSync } from '../../../storages/types'; +import { IStorageSync } from '../../../storages/types'; import { IReadinessManager } from '../../../readiness/types'; -import { ISegmentChangesResponse } from '../../../dtos/types'; -import { findIndex } from '../../../utils/lang'; -import { SplitError } from '../../../utils/lang/errors'; import syncTaskFactory from '../../syncTask'; import { ISegmentsSyncTask } from '../types'; import segmentChangesFetcherFactory from '../fetchers/segmentChangesFetcher'; import { IFetchSegmentChanges } from '../../../services/types'; import { ISettings } from '../../../types'; -import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants'; -import { ILogger } from '../../../logger/types'; -import { logPrefixInstantiation, logPrefixSyncSegments } from '../../../logger/constants'; - -type ISegmentChangesUpdater = (segmentNames?: string[], noCache?: boolean, fetchOnlyNew?: boolean) => Promise +import { segmentChangesUpdaterFactory } from '../updaters/segmentChangesUpdater'; /** - * factory of SegmentChanges updater (a.k.a, SegmentsSyncTask), a task that: - * - fetches segment changes using `segmentChangesFetcher` - * - updates `segmentsCache` - * - uses `segmentsEventEmitter` to emit events related to segments data updates + * Creates a sync task that periodically executes a `segmentChangesUpdater` task */ -function segmentChangesUpdaterFactory( - log: ILogger, - segmentChangesFetcher: ISegmentChangesFetcher, - segmentsCache: ISegmentsCacheSync, - readiness: IReadinessManager, -): ISegmentChangesUpdater { - - let readyOnAlreadyExistentState = true; - - /** telemetry decorator for `segmentChangesFetcher` promise */ - function _promiseDecorator(promise: Promise) { - return promise; - // @TODO handle telemetry? - // const collectMetrics = startingUp || isNode; // If we are on the browser, only collect this metric for first fetch. On node do it always. - // splitsPromise = tracker.start(tracker.TaskNames.SPLITS_FETCH, collectMetrics ? metricCollectors : false, splitsPromise); - } - - /** - * Segments updater returns a promise that resolves with a `false` boolean value if it fails at least to fetch a segment or synchronize it with the storage. - * Thus, a false result doesn't imply that SDK_SEGMENTS_ARRIVED was not emitted. - * - * @param {string[] | undefined} segmentNames list of segment names to fetch. By passing `undefined` it fetches the list of segments registered at the storage - * @param {boolean | undefined} noCache true to revalidate data to fetch on a SEGMENT_UPDATE notifications. - * @param {boolean | undefined} fetchOnlyNew if true, only fetch the segments that not exists, i.e., which `changeNumber` is equal to -1. - * This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE notifications. - */ - return function segmentChangesUpdater(segmentNames?: string[], noCache?: boolean, fetchOnlyNew?: boolean) { - log.debug(logPrefixSyncSegments + 'Started segments update'); - - // If not a segment name provided, read list of available segments names to be updated. - let segments = segmentNames ? segmentNames : segmentsCache.getRegisteredSegments(); - if (fetchOnlyNew) segments = segments.filter(segmentName => segmentsCache.getChangeNumber(segmentName) === -1); - - // Async fetchers are collected here. - const updaters: Promise[] = []; - - for (let index = 0; index < segments.length; index++) { - const segmentName = segments[index]; - const since = segmentsCache.getChangeNumber(segmentName); - - log.debug(logPrefixSyncSegments + `Processing segment ${segmentName}`); - - updaters.push(segmentChangesFetcher(since, segmentName, noCache, _promiseDecorator).then(function (changes) { - let changeNumber = -1; - changes.forEach(x => { - if (x.added.length > 0) segmentsCache.addToSegment(segmentName, x.added); - if (x.removed.length > 0) segmentsCache.removeFromSegment(segmentName, x.removed); - if (x.added.length > 0 || x.removed.length > 0) { - segmentsCache.setChangeNumber(segmentName, x.till); - changeNumber = x.till; - } - - log.debug(logPrefixSyncSegments + `Processed ${segmentName} with till = ${x.till}. Added: ${x.added.length}. Removed: ${x.removed.length}`); - }); - - return changeNumber; - })); - - } - - return Promise.all(updaters).then(shouldUpdateFlags => { - // if at least one segment fetch successes, mark segments ready - if (findIndex(shouldUpdateFlags, v => v !== -1) !== -1 || readyOnAlreadyExistentState) { - readyOnAlreadyExistentState = false; - readiness.segments.emit(SDK_SEGMENTS_ARRIVED); - } - // if at least one segment fetch fails, return false to indicate that there was some error (e.g., invalid json, HTTP error, etc) - if (shouldUpdateFlags.indexOf(-1) !== -1) return false; - return true; - }).catch(error => { - // handle user callback errors - if (!(error instanceof SplitError)) setTimeout(() => { throw error; }, 0); - - if (error.statusCode === 403) { - // @TODO although factory status is destroyed, synchronization is not stopped - readiness.destroy(); - log.error(logPrefixInstantiation + ': you passed a client-side type authorizationKey, please grab an Api Key from the Split web console that is of type Server-side.'); - } - - return false; - }); - }; - -} - export default function segmentsSyncTaskFactory( fetchSegmentChanges: IFetchSegmentChanges, storage: IStorageSync, diff --git a/src/sync/polling/syncTasks/splitsSyncTask.ts b/src/sync/polling/syncTasks/splitsSyncTask.ts index a69e579a..04544c02 100644 --- a/src/sync/polling/syncTasks/splitsSyncTask.ts +++ b/src/sync/polling/syncTasks/splitsSyncTask.ts @@ -1,182 +1,15 @@ -import { SplitError } from '../../../utils/lang/errors'; -import { _Set, setToArray, ISet } from '../../../utils/lang/sets'; -import { ISegmentsCacheSync, ISplitsCacheSync, IStorageSync } from '../../../storages/types'; -import { ISplitChangesFetcher } from '../fetchers/types'; -import { ISplit, ISplitChangesResponse } from '../../../dtos/types'; -import { IReadinessManager, ISplitsEventEmitter } from '../../../readiness/types'; -import timeout from '../../../utils/promise/timeout'; +import { IStorageSync } from '../../../storages/types'; +import { IReadinessManager } from '../../../readiness/types'; import syncTaskFactory from '../../syncTask'; import { ISplitsSyncTask } from '../types'; import splitChangesFetcherFactory from '../fetchers/splitChangesFetcher'; import { IFetchSplitChanges } from '../../../services/types'; -import thenable from '../../../utils/promise/thenable'; import { ISettings } from '../../../types'; -import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants'; -import { ILogger } from '../../../logger/types'; -import { SYNC_SPLITS_FETCH, SYNC_SPLITS_NEW, SYNC_SPLITS_REMOVED, SYNC_SPLITS_SEGMENTS, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants'; - -type ISplitChangesUpdater = (noCache?: boolean) => Promise - -// Checks that all registered segments have been fetched (changeNumber !== -1). -// @TODO review together with Segments and MySegments storage APIs -function checkAllSegmentsExist(segmentsStorage: ISegmentsCacheSync) { - return segmentsStorage.getRegisteredSegments().every(segmentName => segmentsStorage.getChangeNumber(segmentName) !== -1); -} +import { splitChangesUpdaterFactory } from '../updaters/splitChangesUpdater'; /** - * Collect segments from a raw split definition. - * Exported for testing purposes. + * Creates a sync task that periodically executes a `splitChangesUpdater` task */ -export function parseSegments({ conditions }: ISplit): ISet { - - let segments = new _Set(); - - for (let i = 0; i < conditions.length; i++) { - const matchers = conditions[i].matcherGroup.matchers; - - matchers.forEach(matcher => { - if (matcher.matcherType === 'IN_SEGMENT') segments.add(matcher.userDefinedSegmentMatcherData.segmentName); - }); - } - - return segments; -} - -interface ISplitMutations { - added: [string, string][], - removed: string[], - segments: string[] -} - -/** - * Given the list of splits from /splitChanges endpoint, it returns the mutations, - * i.e., an object with added splits, removed splits and used segments. - * Exported for testing purposes. - */ -export function computeSplitsMutation(entries: ISplit[]): ISplitMutations { - const segments = new _Set(); - const computed = entries.reduce((accum, split) => { - if (split.status === 'ACTIVE') { - accum.added.push([split.name, JSON.stringify(split)]); - - parseSegments(split).forEach((segmentName: string) => { - segments.add(segmentName); - }); - } else { - accum.removed.push(split.name); - } - - return accum; - }, { added: [], removed: [], segments: [] } as ISplitMutations); - - computed.segments = setToArray(segments); - - return computed; -} - -/** - * factory of SplitChanges updater (a.k.a, SplitsSyncTask), a task that: - * - fetches split changes using `splitChangesFetcher` - * - updates `splitsCache` - * - uses `splitsEventEmitter` to emit events related to split data updates - * Exported for testing purposes. - */ -export function splitChangesUpdaterFactory( - log: ILogger, - splitChangesFetcher: ISplitChangesFetcher, - splitsCache: ISplitsCacheSync, - segmentsCache: ISegmentsCacheSync, - splitsEventEmitter: ISplitsEventEmitter, - requestTimeoutBeforeReady: number, - retriesOnFailureBeforeReady: number, -): ISplitChangesUpdater { - - let startingUp = true; - let readyOnAlreadyExistentState = true; - - /** timeout and telemetry decorator for `splitChangesFetcher` promise */ - function _promiseDecorator(promise: Promise) { - if (startingUp && requestTimeoutBeforeReady) promise = timeout(requestTimeoutBeforeReady, promise); - return promise; - - // @TODO telemetry - // const collectMetrics = startingUp || isNode; // If we are on the browser, only collect this metric for first fetch. On node do it always. - // splitsPromise = tracker.start(tracker.TaskNames.SPLITS_FETCH, collectMetrics ? metricCollectors : false, splitsPromise); - } - - /** - * SplitChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch splits or synchronize them with the storage. - * - * @param {boolean | undefined} noCache true to revalidate data to fetch - */ - return function splitChangesUpdater(noCache?: boolean) { - - /** - * @param {number} since current changeNumber at splitsCache - * @param {number} retry current number of retry attemps - */ - function _splitChangesUpdater(since: number, retry = 0): Promise { - log.debug(SYNC_SPLITS_FETCH, [since]); - - const fetcherPromise = splitChangesFetcher(since, noCache, _promiseDecorator) - .then((splitChanges: ISplitChangesResponse) => { - startingUp = false; - - const mutation = computeSplitsMutation(splitChanges.splits); - - log.debug(SYNC_SPLITS_NEW, [mutation.added.length]); - log.debug(SYNC_SPLITS_REMOVED, [mutation.removed.length]); - log.debug(SYNC_SPLITS_SEGMENTS, [mutation.segments.length]); - - // Write into storage - // @TODO if allowing custom storages, wrap errors as SplitErrors to distinguish from user callback errors - return Promise.all([ - // calling first `setChangenumber` method, to perform cache flush if split filter queryString changed - splitsCache.setChangeNumber(splitChanges.till), - splitsCache.addSplits(mutation.added), - splitsCache.removeSplits(mutation.removed), - segmentsCache.registerSegments(mutation.segments) - ]).then(() => { - // For server-side SDK, we must check that all registered segments have been fetched - if (readyOnAlreadyExistentState || (since !== splitChanges.till && checkAllSegmentsExist(segmentsCache))) { - readyOnAlreadyExistentState = false; - splitsEventEmitter.emit(SDK_SPLITS_ARRIVED); - } - return true; - }); - }) - .catch(error => { - // handle user callback errors - if (!(error instanceof SplitError)) { - setTimeout(() => { throw error; }, 0); - startingUp = false; // Stop retrying. - } - - log.warn(SYNC_SPLITS_FETCH_FAILS, [error]); - - if (startingUp && retriesOnFailureBeforeReady > retry) { - retry += 1; - log.info(SYNC_SPLITS_FETCH_RETRY, [retry, error]); - return _splitChangesUpdater(since, retry); - } else { - startingUp = false; - } - return false; - }); - - // After triggering the requests, if we have cached splits information let's notify that. - if (startingUp && splitsCache.checkCache()) splitsEventEmitter.emit(SDK_SPLITS_CACHE_LOADED); - - return fetcherPromise; - } - - const since = splitsCache.getChangeNumber(); - // Adding an extra promise to keep the fetch call asynchronous - const sincePromise: Promise = thenable(since) ? since : Promise.resolve(since); - return sincePromise.then(_splitChangesUpdater); - }; -} - export default function splitsSyncTaskFactory( fetchSplitChanges: IFetchSplitChanges, storage: IStorageSync, diff --git a/src/sync/polling/types.ts b/src/sync/polling/types.ts index dd56fbcf..f3cf3639 100644 --- a/src/sync/polling/types.ts +++ b/src/sync/polling/types.ts @@ -2,11 +2,12 @@ import { IReadinessManager } from '../../readiness/types'; import { ISplitApi } from '../../services/types'; import { IStorageSync } from '../../storages/types'; import { ISettings } from '../../types'; +import { SegmentsData } from '../streaming/SSEHandler/types'; import { ITask, ISyncTask } from '../types'; export interface ISplitsSyncTask extends ISyncTask<[noCache?: boolean], boolean> { } -export interface ISegmentsSyncTask extends ISyncTask<[segmentNames?: string[], noCache?: boolean, fetchOnlyNew?: boolean], boolean> { } +export interface ISegmentsSyncTask extends ISyncTask<[segmentNames?: SegmentsData, noCache?: boolean, fetchOnlyNew?: boolean], boolean> { } export interface IPollingManager extends ITask { syncAll(): Promise diff --git a/src/sync/polling/syncTasks/__tests__/splitChangesUpdater.spec.ts b/src/sync/polling/updaters/__tests__/splitChangesUpdater.spec.ts similarity index 96% rename from src/sync/polling/syncTasks/__tests__/splitChangesUpdater.spec.ts rename to src/sync/polling/updaters/__tests__/splitChangesUpdater.spec.ts index 9fb8ab89..cfe8dac6 100644 --- a/src/sync/polling/syncTasks/__tests__/splitChangesUpdater.spec.ts +++ b/src/sync/polling/updaters/__tests__/splitChangesUpdater.spec.ts @@ -4,7 +4,7 @@ import { splitApiFactory } from '../../../../services/splitApi'; import SegmentsCacheInMemory from '../../../../storages/inMemory/SegmentsCacheInMemory'; import SplitsCacheInMemory from '../../../../storages/inMemory/SplitsCacheInMemory'; import splitChangesFetcherFactory from '../../fetchers/splitChangesFetcher'; -import { splitChangesUpdaterFactory, parseSegments, computeSplitsMutation } from '../splitsSyncTask'; +import { splitChangesUpdaterFactory, parseSegments, computeSplitsMutation } from '../splitChangesUpdater'; import splitChangesMock1 from '../../../../__tests__/mocks/splitchanges.since.-1.json'; import fetchMock from '../../../../__tests__/testUtils/fetchMock'; import { settingsSplitApi } from '../../../../utils/settingsValidation/__tests__/settings.mocks'; @@ -80,7 +80,7 @@ test('splitChangesUpdater / factory', (done) => { expect(removeSplits).toBeCalledTimes(1); expect(removeSplits).lastCalledWith([]); expect(registerSegments).toBeCalledTimes(1); - expect(splitsEmitSpy).toBeCalledWith('SDK_SPLITS_ARRIVED'); + expect(splitsEmitSpy).toBeCalledWith('state::splits-arrived'); expect(result).toBe(true); done(); }); diff --git a/src/sync/polling/updaters/mySegmentsUpdater.ts b/src/sync/polling/updaters/mySegmentsUpdater.ts new file mode 100644 index 00000000..4ceb4ab3 --- /dev/null +++ b/src/sync/polling/updaters/mySegmentsUpdater.ts @@ -0,0 +1,107 @@ +import { IMySegmentsFetcher } from '../fetchers/types'; +import { ISegmentsCacheSync, ISplitsCacheSync } from '../../../storages/types'; +import { ISegmentsEventEmitter } from '../../../readiness/types'; +import timeout from '../../../utils/promise/timeout'; +import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants'; +import { ILogger } from '../../../logger/types'; +import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants'; +import { SegmentsData } from '../../streaming/SSEHandler/types'; + +type IMySegmentsUpdater = (segmentList?: string[], noCache?: boolean) => Promise + +/** + * factory of MySegments updater, a task that: + * - fetches mySegments using `mySegmentsFetcher` + * - updates `mySegmentsCache` + * - uses `segmentsEventEmitter` to emit events related to segments data updates + */ +export function mySegmentsUpdaterFactory( + log: ILogger, + mySegmentsFetcher: IMySegmentsFetcher, + splitsCache: ISplitsCacheSync, + mySegmentsCache: ISegmentsCacheSync, + segmentsEventEmitter: ISegmentsEventEmitter, + requestTimeoutBeforeReady: number, + retriesOnFailureBeforeReady: number, +): IMySegmentsUpdater { + + let readyOnAlreadyExistentState = true; + let startingUp = true; + + /** timeout and telemetry decorator for `splitChangesFetcher` promise */ + function _promiseDecorator(promise: Promise) { + if (startingUp) promise = timeout(requestTimeoutBeforeReady, promise); + return promise; + + // @TODO telemetry + // NOTE: We only collect metrics on startup. + // mySegmentsPromise = tracker.start(tracker.TaskNames.MY_SEGMENTS_FETCH, startingUp ? metricCollectors : false, mySegmentsPromise); + } + + // @TODO if allowing custom storages, handle async execution + function updateSegments(segmentsData: SegmentsData) { + + let shouldNotifyUpdate; + if (Array.isArray(segmentsData)) { + // Update the list of segment names available + shouldNotifyUpdate = mySegmentsCache.resetSegments(segmentsData); + } else { + // Add/Delete the segment + const { name, add } = segmentsData; + if (mySegmentsCache.isInSegment(name) !== add) { + shouldNotifyUpdate = true; + if (add) mySegmentsCache.addToSegment(name); + else mySegmentsCache.removeFromSegment(name); + } else { + shouldNotifyUpdate = false; + } + } + + // Notify update if required + if (splitsCache.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) { + readyOnAlreadyExistentState = false; + segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED); + } + } + + function _mySegmentsUpdater(retry: number, segmentsData?: SegmentsData, noCache?: boolean): Promise { + const updaterPromise: Promise = segmentsData ? + // If segmentsData is provided, there is no need to fetch mySegments + new Promise((res) => { updateSegments(segmentsData); res(true); }) : + // If not provided, fetch mySegments + mySegmentsFetcher(noCache, _promiseDecorator).then(segments => { + // Only when we have downloaded segments completely, we should not keep retrying anymore + startingUp = false; + + updateSegments(segments); + return true; + }); + + return updaterPromise.catch(error => { + if (startingUp && retriesOnFailureBeforeReady > retry) { + retry += 1; + log.warn(SYNC_MYSEGMENTS_FETCH_RETRY, [retry, error]); + return _mySegmentsUpdater(retry); // no need to forward `segmentList` and `noCache` params + } else { + startingUp = false; + } + + return false; + }); + } + + /** + * MySegments updater returns a promise that resolves with a `false` boolean value if it fails to fetch mySegments or synchronize them with the storage. + * Returned promise will not be rejected. + * + * @param {SegmentsData | undefined} segmentsData it can be: + * (1) the list of mySegments names to sync in the storage, + * (2) an object with a segment name and action (true: add, or false: delete) to update the storage, + * (3) or `undefined`, for which the updater will fetch mySegments in order to sync the storage. + * @param {boolean | undefined} noCache true to revalidate data to fetch + */ + return function mySegmentsUpdater(segmentsData?: SegmentsData, noCache?: boolean) { + return _mySegmentsUpdater(0, segmentsData, noCache); + }; + +} diff --git a/src/sync/polling/updaters/segmentChangesUpdater.ts b/src/sync/polling/updaters/segmentChangesUpdater.ts new file mode 100644 index 00000000..eefedf88 --- /dev/null +++ b/src/sync/polling/updaters/segmentChangesUpdater.ts @@ -0,0 +1,115 @@ +import { ISegmentChangesFetcher } from '../fetchers/types'; +import { ISegmentsCacheBase } from '../../../storages/types'; +import { IReadinessManager } from '../../../readiness/types'; +import { ISegmentChangesResponse, MaybeThenable } from '../../../dtos/types'; +import { findIndex } from '../../../utils/lang'; +import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants'; +import { ILogger } from '../../../logger/types'; +import { LOG_PREFIX_INSTANTIATION, LOG_PREFIX_SYNC_SEGMENTS } from '../../../logger/constants'; +import thenable from '../../../utils/promise/thenable'; + +type ISegmentChangesUpdater = (segmentNames?: string[], noCache?: boolean, fetchOnlyNew?: boolean) => Promise + +/** + * Factory of SegmentChanges updater, a task that: + * - fetches segment changes using `segmentChangesFetcher` + * - updates `segmentsCache` + * - uses `segmentsEventEmitter` to emit events related to segments data updates + * + * @param log logger instance + * @param segmentChangesFetcher fetcher of `/segmentChanges` + * @param segments segments storage, with sync or async methods + * @param readiness optional readiness manager. Not required for synchronizer or producer mode. + */ +export function segmentChangesUpdaterFactory( + log: ILogger, + segmentChangesFetcher: ISegmentChangesFetcher, + segments: ISegmentsCacheBase, + readiness?: IReadinessManager, +): ISegmentChangesUpdater { + + let readyOnAlreadyExistentState = true; + + /** telemetry decorator for `segmentChangesFetcher` promise */ + function _promiseDecorator(promise: Promise) { + return promise; + // @TODO handle telemetry? + // const collectMetrics = startingUp || isNode; // If we are on the browser, only collect this metric for first fetch. On node do it always. + // splitsPromise = tracker.start(tracker.TaskNames.SPLITS_FETCH, collectMetrics ? metricCollectors : false, splitsPromise); + } + + /** + * Segments updater returns a promise that resolves with a `false` boolean value if it fails at least to fetch a segment or synchronize it with the storage. + * Thus, a false result doesn't imply that SDK_SEGMENTS_ARRIVED was not emitted. + * Returned promise will not be rejected. + * + * @param {string[] | undefined} segmentNames list of segment names to fetch. By passing `undefined` it fetches the list of segments registered at the storage + * @param {boolean | undefined} noCache true to revalidate data to fetch on a SEGMENT_UPDATE notifications. + * @param {boolean | undefined} fetchOnlyNew if true, only fetch the segments that not exists, i.e., which `changeNumber` is equal to -1. + * This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE notifications. + */ + return function segmentChangesUpdater(segmentNames?: string[], noCache?: boolean, fetchOnlyNew?: boolean) { + log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Started segments update`); + + // If not a segment name provided, read list of available segments names to be updated. + let segmentsPromise = Promise.resolve(segmentNames ? segmentNames : segments.getRegisteredSegments()); + + return segmentsPromise.then(segmentNames => { + // Async fetchers are collected here. + const updaters: Promise[] = []; + + for (let index = 0; index < segmentNames.length; index++) { + const segmentName = segmentNames[index]; + log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Processing segment ${segmentName}`); + let sincePromise = Promise.resolve(segments.getChangeNumber(segmentName)); + + updaters.push(sincePromise.then(since => { + // if fetchOnlyNew flag, avoid processing already fetched segments + if (fetchOnlyNew && since !== -1) return -1; + + return segmentChangesFetcher(since, segmentName, noCache, _promiseDecorator).then(function (changes) { + let changeNumber = -1; + const results: MaybeThenable[] = []; + changes.forEach(x => { + if (x.added.length > 0) results.push(segments.addToSegment(segmentName, x.added)); + if (x.removed.length > 0) results.push(segments.removeFromSegment(segmentName, x.removed)); + if (x.added.length > 0 || x.removed.length > 0) { + results.push(segments.setChangeNumber(segmentName, x.till)); + changeNumber = x.till; + } + + log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Processed ${segmentName} with till = ${x.till}. Added: ${x.added.length}. Removed: ${x.removed.length}`); + }); + // If at least one storage operation result is a promise, join all in a single promise. + if (results.some(result => thenable(result))) return Promise.all(results).then(() => changeNumber); + return changeNumber; + }); + })); + + } + + return Promise.all(updaters).then(shouldUpdateFlags => { + // if at least one segment fetch succeeded, mark segments ready + if (findIndex(shouldUpdateFlags, v => v !== -1) !== -1 || readyOnAlreadyExistentState) { + readyOnAlreadyExistentState = false; + if (readiness) readiness.segments.emit(SDK_SEGMENTS_ARRIVED); + } + return true; + }); + }) + // Handles rejected promises at `segmentChangesFetcher`, `segments.getRegisteredSegments` and other segment storage operations. + .catch(error => { + if (error && error.statusCode === 403) { + // If the operation is forbidden, it may be due to permissions. Destroy the SDK instance. + // @TODO although factory status is destroyed, synchronization is not stopped + if (readiness) readiness.destroy(); + log.error(`${LOG_PREFIX_INSTANTIATION}: you passed a client-side type authorizationKey, please grab an Api Key from the Split web console that is of type Server-side.`); + } else { + log.warn(`${LOG_PREFIX_SYNC_SEGMENTS}Error while doing fetch of segments. ${error}`); + } + + return false; + }); + }; + +} diff --git a/src/sync/polling/updaters/splitChangesUpdater.ts b/src/sync/polling/updaters/splitChangesUpdater.ts new file mode 100644 index 00000000..ce490771 --- /dev/null +++ b/src/sync/polling/updaters/splitChangesUpdater.ts @@ -0,0 +1,181 @@ +import { _Set, setToArray, ISet } from '../../../utils/lang/sets'; +import { ISegmentsCacheBase, ISplitsCacheBase } from '../../../storages/types'; +import { ISplitChangesFetcher } from '../fetchers/types'; +import { ISplit, ISplitChangesResponse } from '../../../dtos/types'; +import { ISplitsEventEmitter } from '../../../readiness/types'; +import timeout from '../../../utils/promise/timeout'; +import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants'; +import { ILogger } from '../../../logger/types'; +import { SYNC_SPLITS_FETCH, SYNC_SPLITS_NEW, SYNC_SPLITS_REMOVED, SYNC_SPLITS_SEGMENTS, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants'; + +type ISplitChangesUpdater = (noCache?: boolean) => Promise + +// Checks that all registered segments have been fetched (changeNumber !== -1 for every segment). +// Returns a promise that could be rejected. +// @TODO review together with Segments and MySegments storage APIs +function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise { + let registeredSegments = Promise.resolve(segments.getRegisteredSegments()); + return registeredSegments.then(segmentNames => { + return Promise.all(segmentNames.map(segmentName => segments.getChangeNumber(segmentName))) + .then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !== -1)); + }); +} + +/** + * Collect segments from a raw split definition. + * Exported for testing purposes. + */ +export function parseSegments({ conditions }: ISplit): ISet { + let segments = new _Set(); + + for (let i = 0; i < conditions.length; i++) { + const matchers = conditions[i].matcherGroup.matchers; + + matchers.forEach(matcher => { + if (matcher.matcherType === 'IN_SEGMENT') segments.add(matcher.userDefinedSegmentMatcherData.segmentName); + }); + } + + return segments; +} + +interface ISplitMutations { + added: [string, string][], + removed: string[], + segments: string[] +} + +/** + * Given the list of splits from /splitChanges endpoint, it returns the mutations, + * i.e., an object with added splits, removed splits and used segments. + * Exported for testing purposes. + */ +export function computeSplitsMutation(entries: ISplit[]): ISplitMutations { + const segments = new _Set(); + const computed = entries.reduce((accum, split) => { + if (split.status === 'ACTIVE') { + accum.added.push([split.name, JSON.stringify(split)]); + + parseSegments(split).forEach((segmentName: string) => { + segments.add(segmentName); + }); + } else { + accum.removed.push(split.name); + } + + return accum; + }, { added: [], removed: [], segments: [] } as ISplitMutations); + + computed.segments = setToArray(segments); + + return computed; +} + +/** + * factory of SplitChanges updater, a task that: + * - fetches split changes using `splitChangesFetcher` + * - updates `splitsCache` + * - uses `splitsEventEmitter` to emit events related to split data updates + * + * @param log Logger instance + * @param splitChangesFetcher Fetcher of `/splitChanges` + * @param splits Splits storage, with sync or async methods + * @param segments Segments storage, with sync or async methods + * @param splitsEventEmitter Optional readiness manager. Not required for synchronizer or producer mode. + * @param requestTimeoutBeforeReady How long the updater will wait for the request to timeout. Default 0, i.e., never timeout. + * @param retriesOnFailureBeforeReady How many retries on `/splitChanges` we the updater do in case of failure or timeout. Default 0, i.e., no retries. + */ +export function splitChangesUpdaterFactory( + log: ILogger, + splitChangesFetcher: ISplitChangesFetcher, + splits: ISplitsCacheBase, + segments: ISegmentsCacheBase, + splitsEventEmitter?: ISplitsEventEmitter, + requestTimeoutBeforeReady: number = 0, + retriesOnFailureBeforeReady: number = 0, +): ISplitChangesUpdater { + + let startingUp = true; + + /** timeout and telemetry decorator for `splitChangesFetcher` promise */ + function _promiseDecorator(promise: Promise) { + if (startingUp && requestTimeoutBeforeReady) promise = timeout(requestTimeoutBeforeReady, promise); + return promise; + + // @TODO telemetry + // const collectMetrics = startingUp || isNode; // If we are on the browser, only collect this metric for first fetch. On node do it always. + // splitsPromise = tracker.start(tracker.TaskNames.SPLITS_FETCH, collectMetrics ? metricCollectors : false, splitsPromise); + } + + /** + * SplitChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch splits or synchronize them with the storage. + * Returned promise will not be rejected. + * + * @param {boolean | undefined} noCache true to revalidate data to fetch + */ + return function splitChangesUpdater(noCache?: boolean) { + + /** + * @param {number} since current changeNumber at splitsCache + * @param {number} retry current number of retry attemps + */ + function _splitChangesUpdater(since: number, retry = 0): Promise { + log.debug(SYNC_SPLITS_FETCH, [since]); + + const fetcherPromise = splitChangesFetcher(since, noCache, _promiseDecorator) + .then((splitChanges: ISplitChangesResponse) => { + startingUp = false; + + const mutation = computeSplitsMutation(splitChanges.splits); + + log.debug(SYNC_SPLITS_NEW, [mutation.added.length]); + log.debug(SYNC_SPLITS_REMOVED, [mutation.removed.length]); + log.debug(SYNC_SPLITS_SEGMENTS, [mutation.segments.length]); + + // Write into storage + // @TODO call `setChangeNumber` only if the other storage operations have succeeded, in order to keep storage consistency + return Promise.all([ + // calling first `setChangenumber` method, to perform cache flush if split filter queryString changed + splits.setChangeNumber(splitChanges.till), + splits.addSplits(mutation.added), + splits.removeSplits(mutation.removed), + segments.registerSegments(mutation.segments) + ]).then(() => { + + if (splitsEventEmitter) { + // To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched + return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && checkAllSegmentsExist(segments))) + .catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */) + .then(emitSplitsArrivedEvent => { + // emit SDK events + if (emitSplitsArrivedEvent) splitsEventEmitter.emit(SDK_SPLITS_ARRIVED); + return true; + }); + } + return true; + }); + }) + .catch(error => { + log.warn(SYNC_SPLITS_FETCH_FAILS, [error]); + + if (startingUp && retriesOnFailureBeforeReady > retry) { + retry += 1; + log.info(SYNC_SPLITS_FETCH_RETRY, [retry, error]); + return _splitChangesUpdater(since, retry); + } else { + startingUp = false; + } + return false; + }); + + // After triggering the requests, if we have cached splits information let's notify that. + if (splitsEventEmitter && startingUp) { + Promise.resolve(splits.checkCache()).then(cacheReady => { if (cacheReady) splitsEventEmitter.emit(SDK_SPLITS_CACHE_LOADED); }); + } + return fetcherPromise; + } + + let sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error + return sincePromise.then(_splitChangesUpdater); + }; +} diff --git a/src/sync/streaming/AuthClient/__tests__/dataMocks.ts b/src/sync/streaming/AuthClient/__tests__/dataMocks.ts deleted file mode 100644 index 3e354c8e..00000000 --- a/src/sync/streaming/AuthClient/__tests__/dataMocks.ts +++ /dev/null @@ -1,46 +0,0 @@ -export const jwtSample = 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleUlkIiwidHlwIjoiSldUIn0.eyJvcmdJZCI6IjEyMTM4YWMxLTA5MmYtMzJlNy1iYTc4LTEyMzk1ZDRhOTYzNCIsImVudklkIjoiODZiMGQzYTAtNWY1NC0zMmU3LTIyZjktMDExNTBmYTlmYTNhIiwieC1hYmx5LWNhcGFiaWxpdHkiOiJ7XCJOek0yTURJNU16YzBfTXpReU9EVTRORFV5Tmc9PV9zZWdtZW50c1wiOltcInN1YnNjcmliZVwiXSxcIk56TTJNREk1TXpjMF9NelF5T0RVNE5EVXlOZz09X3NwbGl0c1wiOltcInN1YnNjcmliZVwiXSxcImNvbnRyb2xcIjpbXCJzdWJzY3JpYmVcIl19IiwieC1hYmx5LWNsaWVudElkIjoiY2xpZW50SWQiLCJleHAiOjE1ODM3ODcxMjQsImlhdCI6MTU4Mzc4MzUyNH0.f3I0ADc3kzQ4RfFywEukBM8bw91AUnJcGH3nwYUjEg0'; -export const jwtSampleInvalid = 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleUlkIiwidHlwIjoiSldUIn0.aaavcmdJZCI6IjEyMTM4YWMxLTA5MmYtMzJlNy1iYTc4LTEyMzk1ZDRhOTYzNCIsImVudklkIjoiODZiMGQzYTAtNWY1NC0zMmU3LTIyZjktMDExNTBmYTlmYTNhIiwieC1hYmx5LWNhcGFiaWxpdHkiOiJ7XCJOek0yTURJNU16YzBfTXpReU9EVTRORFV5Tmc9PV9zZWdtZW50c1wiOltcInN1YnNjcmliZVwiXSxcIk56TTJNREk1TXpjMF9NelF5T0RVNE5EVXlOZz09X3NwbGl0c1wiOltcInN1YnNjcmliZVwiXSxcImNvbnRyb2xcIjpbXCJzdWJzY3JpYmVcIl19IiwieC1hYmx5LWNsaWVudElkIjoiY2xpZW50SWQiLCJleHAiOjE1ODM3ODcxMjQsImlhdCI6MTU4Mzc4MzUyNH0.f3I0ADc3kzQ4RfFywEukBM8bw91AUnJcGH3nwYUjEg0'; -export const jwtSampleNoChannels = 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleUlkIiwidHlwIjoiSldUIn0.eyJvcmdJZCI6IjEyMTM4YWMxLTA5MmYtMzJlNy1iYTc4LTEyMzk1ZDRhOTYzNCIsImVudklkIjoiODZiMGQzYTAtNWY1NC0zMmU3LTIyZjktMDExNTBmYTlmYTNhIiwieC1hYmx5LWNsaWVudElkIjoiY2xpZW50SWQiLCJleHAiOjE1ODM3ODcxMjQsImlhdCI6MTU4Mzc4MzUyNH0.aiuUdeBAZaFMtgaH9y9cwxPG3LyiJCGpX54jd1V4Z54'; -export const jwtSampleNoIat = 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleUlkIiwidHlwIjoiSldUIn0.eyJvcmdJZCI6IjEyMTM4YWMxLTA5MmYtMzJlNy1iYTc4LTEyMzk1ZDRhOTYzNCIsImVudklkIjoiODZiMGQzYTAtNWY1NC0zMmU3LTIyZjktMDExNTBmYTlmYTNhIiwieC1hYmx5LWNhcGFiaWxpdHkiOiJ7XCJOek0yTURJNU16YzBfTXpReU9EVTRORFV5Tmc9PV9zZWdtZW50c1wiOltcInN1YnNjcmliZVwiXSxcIk56TTJNREk1TXpjMF9NelF5T0RVNE5EVXlOZz09X3NwbGl0c1wiOltcInN1YnNjcmliZVwiXSxcImNvbnRyb2xcIjpbXCJzdWJzY3JpYmVcIl19IiwieC1hYmx5LWNsaWVudElkIjoiY2xpZW50SWQiLCJleHAiOjE1ODM3ODcxMjQsImlhdCI6IjE1ODM3ODM1MjQifQ'; - -export const decodedJwtPayloadSample = { - orgId: '12138ac1-092f-32e7-ba78-12395d4a9634', - envId: '86b0d3a0-5f54-32e7-22f9-01150fa9fa3a', - ['x-ably-capability']: '{"NzM2MDI5Mzc0_MzQyODU4NDUyNg==_segments":["subscribe"],"NzM2MDI5Mzc0_MzQyODU4NDUyNg==_splits":["subscribe"],"control":["subscribe"]}', - ['x-ably-clientId']: 'clientId', - exp: 1583787124, - iat: 1583783524, -}; - -export const decodedJwtHeadersSample = { - alg: 'HS256', - kid: 'keyId', - typ: 'JWT', -}; - -export const parsedChannelsSample = { - 'NzM2MDI5Mzc0_MzQyODU4NDUyNg==_segments': ['subscribe'], - 'NzM2MDI5Mzc0_MzQyODU4NDUyNg==_splits': ['subscribe'], - 'control': ['subscribe'] -}; - -export const base64sample = 'ZW1pQHNwbGl0Lmlv'; - -export const decodedBase64sample = 'emi@split.io'; - -export const authDataResponseSample = { - pushEnabled: true, - token: jwtSample, -}; - -export const authDataSample = { - ...authDataResponseSample, - decodedToken: decodedJwtPayloadSample, - channels: parsedChannelsSample, -}; - -export const userKeySample = 'emi@split.io'; - -export const userKeyBase64HashSample = 'MjAxNjU2NDU5Mw=='; - -export const channelsQueryParamSample = 'NzM2MDI5Mzc0_MzQyODU4NDUyNg%3D%3D_segments,NzM2MDI5Mzc0_MzQyODU4NDUyNg%3D%3D_splits,control'; diff --git a/src/sync/streaming/AuthClient/__tests__/index.spec.ts b/src/sync/streaming/AuthClient/__tests__/index.spec.ts index 98182a59..afaf5f73 100644 --- a/src/sync/streaming/AuthClient/__tests__/index.spec.ts +++ b/src/sync/streaming/AuthClient/__tests__/index.spec.ts @@ -1,6 +1,6 @@ // mocks and dependencies import { splitApiFactory } from '../../../../services/splitApi'; -import { authDataResponseSample, authDataSample, jwtSampleInvalid, jwtSampleNoChannels, jwtSampleNoIat, userKeySample, userKeyBase64HashSample } from './dataMocks'; +import { authDataResponseSample, authDataSample, jwtSampleInvalid, jwtSampleNoChannels, jwtSampleNoIat, userKeySample, userKeyBase64HashSample } from '../../__tests__/dataMocks'; import fetchMock from '../../../../__tests__/testUtils/fetchMock'; import { settingsSplitApi } from '../../../../utils/settingsValidation/__tests__/settings.mocks'; import EventEmitter from '../../../../utils/MinEvents'; @@ -21,7 +21,7 @@ test('hashUserKey', () => { test('authenticate / success in node (200)', done => { - fetchMock.getOnce(authUrl + '/auth', (url, opts) => { + fetchMock.getOnce(authUrl + '/v2/auth', (url, opts) => { // @ts-ignore expect(opts.headers['Authorization']).toBe(`Bearer ${authorizationKey}`); // auth request must contain Authorization header with config authorizationKey return { status: 200, body: authDataResponseSample }; @@ -40,7 +40,7 @@ test('authenticate / success in browser (200)', done => { const userKeys = ['emi@split.io', 'maldo@split.io']; - fetchMock.getOnce(authUrl + '/auth?users=emi%40split.io&users=maldo%40split.io', (url, opts) => { + fetchMock.getOnce(authUrl + '/v2/auth?users=emi%40split.io&users=maldo%40split.io', (url, opts) => { // @ts-ignore expect(opts.headers['Authorization']).toBe(`Bearer ${authorizationKey}`); // auth request must contain Authorization header with config authorizationKey return { status: 200, body: authDataResponseSample }; @@ -57,7 +57,7 @@ test('authenticate / success in browser (200)', done => { test('authenticate / bad request in browser due to no user keys (400)', done => { - fetchMock.getOnce(authUrl + '/auth', { status: 400, body: '"no user specified"' }); + fetchMock.getOnce(authUrl + '/v2/auth', { status: 400, body: '"no user specified"' }); authenticate([]).then(() => { throw new Error('if bad request, promise is rejected'); @@ -70,7 +70,7 @@ test('authenticate / bad request in browser due to no user keys (400)', done => test('authenticate / Invalid credentials (401)', done => { - fetchMock.getOnce(authUrl + '/auth', { status: 401, body: '"Invalid credentials"' }); + fetchMock.getOnce(authUrl + '/v2/auth', { status: 401, body: '"Invalid credentials"' }); authenticate([]).then(() => { throw new Error('if invalid credential, promise should be rejected'); @@ -85,7 +85,7 @@ test('authenticate / HTTP error (other than 401)', done => { const NOT_OK_STATUS_CODE = 500; - fetchMock.getOnce(authUrl + '/auth', { status: NOT_OK_STATUS_CODE, body: 'some error message' }); + fetchMock.getOnce(authUrl + '/v2/auth', { status: NOT_OK_STATUS_CODE, body: 'some error message' }); authenticate([]).then(() => { throw new Error('if an HTTP error, promise is rejected'); @@ -98,7 +98,7 @@ test('authenticate / HTTP error (other than 401)', done => { test('authenticate / Network error (e.g., timeout)', done => { - fetchMock.getOnce(authUrl + '/auth', { throws: new TypeError('Network error') }); + fetchMock.getOnce(authUrl + '/v2/auth', { throws: new TypeError('Network error') }); authenticate([]).then(() => { throw new Error('if network error, promise is rejected'); @@ -111,9 +111,9 @@ test('authenticate / Network error (e.g., timeout)', done => { test('authenticate / Error parsing token', done => { - fetchMock.getOnce(authUrl + '/auth', { status: 200, body: { pushEnabled: true, token: jwtSampleInvalid } }); - fetchMock.getOnce(authUrl + '/auth', { status: 200, body: { pushEnabled: true, token: jwtSampleNoChannels } }); - fetchMock.getOnce(authUrl + '/auth', { status: 200, body: { pushEnabled: true, token: jwtSampleNoIat } }); + fetchMock.getOnce(authUrl + '/v2/auth', { status: 200, body: { pushEnabled: true, token: jwtSampleInvalid } }); + fetchMock.getOnce(authUrl + '/v2/auth', { status: 200, body: { pushEnabled: true, token: jwtSampleNoChannels } }); + fetchMock.getOnce(authUrl + '/v2/auth', { status: 200, body: { pushEnabled: true, token: jwtSampleNoIat } }); authenticate().then(() => { throw new Error('if invalid token, promise is rejected'); diff --git a/src/sync/streaming/AuthClient/index.ts b/src/sync/streaming/AuthClient/index.ts index 1f0192a9..8f19c34e 100644 --- a/src/sync/streaming/AuthClient/index.ts +++ b/src/sync/streaming/AuthClient/index.ts @@ -19,7 +19,6 @@ export function authenticateFactory(fetchAuth: IFetchAuth): IAuthenticate { return function authenticate(userKeys?: string[]): Promise { let authPromise = fetchAuth(userKeys); // errors handled by fetchAuth service return authPromise - // no need to handle json parsing errors as SplitError, since no user callbacks are executed after this promise is resolved .then(resp => resp.json()) .then(json => { if (json.token) { // empty token when `"pushEnabled": false` diff --git a/src/sync/streaming/AuthClient/types.ts b/src/sync/streaming/AuthClient/types.ts index cf8f78f3..53bc2b03 100644 --- a/src/sync/streaming/AuthClient/types.ts +++ b/src/sync/streaming/AuthClient/types.ts @@ -5,6 +5,7 @@ export interface IAuthTokenPushEnabled { token: string decodedToken: IDecodedJWTToken channels: { [channel: string]: string[] } + connDelay?: number } export interface IAuthTokenPushDisabled { @@ -15,3 +16,5 @@ export interface IAuthTokenPushDisabled { export type IAuthToken = IAuthTokenPushDisabled | IAuthTokenPushEnabled export type IAuthenticate = (userKeys?: string[]) => Promise + +export type IAuthenticateV2 = (isClientSide?: boolean) => Promise diff --git a/src/sync/streaming/SSEClient/__tests__/index.spec.ts b/src/sync/streaming/SSEClient/__tests__/index.spec.ts index c660ad09..6155224b 100644 --- a/src/sync/streaming/SSEClient/__tests__/index.spec.ts +++ b/src/sync/streaming/SSEClient/__tests__/index.spec.ts @@ -1,18 +1,28 @@ // @ts-nocheck import EventSourceMock from '../../../../__tests__/testUtils/eventSourceMock'; -import { authDataSample, channelsQueryParamSample } from '../../AuthClient/__tests__/dataMocks'; +import { authDataSample, channelsQueryParamSample } from '../../__tests__/dataMocks'; +import { fullSettings as settings } from '../../../../utils/settingsValidation/__tests__/settings.mocks'; +import { url } from '../../../../utils/settingsValidation/url'; import SSClient from '../index'; -const URL = 'someurl'; +const EXPECTED_URL = url(settings, '/sse') + + '?channels=' + channelsQueryParamSample + + '&accessToken=' + authDataSample.token + + '&v=1.1&heartbeats=true'; + +const EXPECTED_HEADERS = { + SplitSDKClientKey: '1234', + SplitSDKVersion: settings.version +}; test('SSClient / instance creation throws error if EventSource is not provided', () => { - expect(() => { new SSClient(URL); }).toThrow(Error); - expect(() => { new SSClient(URL, () => undefined); }).toThrow(Error); + expect(() => { new SSClient(settings); }).toThrow(Error); + expect(() => { new SSClient(settings, false, () => undefined); }).toThrow(Error); }); test('SSClient / instance creation success if EventSource is provided', () => { - const instance = new SSClient(URL, () => EventSourceMock); + const instance = new SSClient(settings, false, () => EventSourceMock); expect(instance.eventSource).toBe(EventSourceMock); }); @@ -25,12 +35,9 @@ test('SSClient / setEventHandler, open and close methods', () => { }; // instance SSEClient - const instance = new SSClient(URL, () => EventSourceMock); + const instance = new SSClient(settings, false, () => EventSourceMock); instance.setEventHandler(handler); - // error on first open without authToken - expect(instance.reopen).toThrow(Error); // throw error if reopen is invoked without a previous open call - // open connection instance.open(authDataSample); let esconnection = instance.connection; // instance of EventSource used to mock events @@ -63,12 +70,6 @@ test('SSClient / setEventHandler, open and close methods', () => { instance.connection.emitOpen(); expect(handler.handleOpen).toBeCalledTimes(1); // handleOpen called when connection is open - // reopen the connection - handler.handleOpen.mockClear(); - instance.reopen(); - instance.connection.emitOpen(); - expect(handler.handleOpen).toBeCalledTimes(1); // handleOpen called if connection is reopen - // remove event handler before opening a new connection handler.handleOpen.mockClear(); instance.setEventHandler(undefined); @@ -78,16 +79,44 @@ test('SSClient / setEventHandler, open and close methods', () => { }); -test('SSClient / open method: URL', () => { +test('SSClient / open method: URL with metadata query params', () => { - const instance = new SSClient(URL, () => EventSourceMock); + const instance = new SSClient(settings, false, () => EventSourceMock); instance.open(authDataSample); - const EXPECTED_URL = URL + '/sse' + - '?channels=' + channelsQueryParamSample + - '&accessToken=' + authDataSample.token + - '&v=1.1&heartbeats=true'; + const EXPECTED_BROWSER_URL = EXPECTED_URL + `&SplitSDKVersion=${settings.version}&SplitSDKClientKey=${EXPECTED_HEADERS.SplitSDKClientKey}`; + + expect(instance.connection.url).toBe(EXPECTED_BROWSER_URL); // URL is properly set for streaming connection + expect(instance.connection.__eventSourceInitDict).toBe(undefined); // No headers are passed for streaming connection +}); + +test('SSClient / open method: URL and metadata headers with IP and Hostname', () => { + + const settingsWithRuntime = { + ...settings, + runtime: { + ip: 'some ip', + hostname: 'some hostname' + } + }; + const instance = new SSClient(settingsWithRuntime, true, () => EventSourceMock); + instance.open(authDataSample); expect(instance.connection.url).toBe(EXPECTED_URL); // URL is properly set for streaming connection + expect(instance.connection.__eventSourceInitDict).toEqual({ + headers: { + ...EXPECTED_HEADERS, + SplitSDKMachineIP: settingsWithRuntime.runtime.ip, + SplitSDKMachineName: settingsWithRuntime.runtime.hostname + } + }); // Headers are properly set for streaming connection +}); +test('SSClient / open method: URL and metadata headers without IP and Hostname', () => { + + const instance = new SSClient(settings, true, () => EventSourceMock); + instance.open(authDataSample); + + expect(instance.connection.url).toBe(EXPECTED_URL); // URL is properly set for streaming connection + expect(instance.connection.__eventSourceInitDict).toEqual({ headers: EXPECTED_HEADERS }); // Headers are properly set for streaming connection }); diff --git a/src/sync/streaming/SSEClient/index.ts b/src/sync/streaming/SSEClient/index.ts index 8f75a514..7e3cc4bb 100644 --- a/src/sync/streaming/SSEClient/index.ts +++ b/src/sync/streaming/SSEClient/index.ts @@ -1,3 +1,4 @@ +import { ISettings } from '../../../types'; import { IAuthTokenPushEnabled } from '../AuthClient/types'; import { ISSEClient, ISseEventHandler } from './types'; @@ -5,6 +6,26 @@ const VERSION = '1.1'; const CONTROL_CHANNEL_REGEX = /^control_/; +/** + * Build metadata headers for SSE connection. + * + * @param {ISettings} settings Validated settings. + * @returns {Record} Headers object + */ +function buildSSEHeaders(settings: ISettings) { + const headers: Record = { + SplitSDKClientKey: settings.core.authorizationKey.slice(-4), + SplitSDKVersion: settings.version, + }; + + // ip and hostname are false if IPAddressesEnabled is false + const { ip, hostname } = settings.runtime; + if (ip) headers['SplitSDKMachineIP'] = ip; + if (hostname) headers['SplitSDKMachineName'] = hostname; + + return headers; +} + /** * Handles streaming connections with EventSource API */ @@ -14,23 +35,27 @@ export default class SSEClient implements ISSEClient { streamingUrl: string; connection?: InstanceType; handler?: ISseEventHandler; - authToken?: IAuthTokenPushEnabled; + useHeaders?: boolean; + headers: Record; /** * SSEClient constructor. * - * @param streamingUrl URL - * @param eventSource optional EventSource constructor to use instead of the global one - * @throws 'EventSource API is not available. ' if EventSource is not passed and global one is not available + * @param settings Validated settings. + * @param useHeaders True to send metadata as headers or false to send as query params. If `true`, the provided EventSource must support headers. + * @param getEventSource Function to get the EventSource constructor. + * @throws 'EventSource API is not available. ' if EventSource is not available. */ - constructor(streamingUrl: string, getEventSource?: () => typeof EventSource | undefined) { + constructor(settings: ISettings, useHeaders?: boolean, getEventSource?: () => (typeof EventSource | undefined)) { // @ts-expect-error this.eventSource = getEventSource && getEventSource(); // if eventSource is not available, throw an exception if (!this.eventSource) throw new Error('EventSource API is not available. '); - this.streamingUrl = streamingUrl + '/sse'; - this.reopen = this.reopen.bind(this); + this.streamingUrl = settings.urls.streaming + '/sse'; + // @TODO get `useHeaders` flag from `getEventSource`, to use EventSource headers on client-side SDKs when possible. + this.useHeaders = useHeaders; + this.headers = buildSSEHeaders(settings); } setEventHandler(handler: ISseEventHandler) { @@ -41,13 +66,11 @@ export default class SSEClient implements ISSEClient { * Open the connection with a given authToken * * @param {IAuthTokenPushEnabled} authToken - * @throws {TypeError} if `authToken` is undefined + * @throws {TypeError} Will throw an error if `authToken` is undefined */ open(authToken: IAuthTokenPushEnabled) { this.close(); // it closes connection if previously opened - this.authToken = authToken; - const channelsQueryParam = Object.keys(authToken.channels).map( function (channel) { const params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : ''; @@ -56,12 +79,18 @@ export default class SSEClient implements ISSEClient { ).join(','); const url = `${this.streamingUrl}?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${VERSION}&heartbeats=true`; // same results using `&heartbeats=false` - this.connection = new this.eventSource(url); + this.connection = new this.eventSource( + // For client-side SDKs, SplitSDKClientKey and SplitSDKClientKey metadata is passed as query params, + // because native EventSource implementations for browser doesn't support headers. + this.useHeaders ? url : url + `&SplitSDKVersion=${this.headers.SplitSDKVersion}&SplitSDKClientKey=${this.headers.SplitSDKClientKey}`, + // @ts-ignore. For server-side SDKs, metadata is passed via headers. EventSource must support headers, like 'eventsource' package for Node. + this.useHeaders ? { headers: this.headers } : undefined + ); if (this.handler) { // no need to check if SSEClient is used only by PushManager - this.connection.onopen = this.handler.handleOpen; - this.connection.onmessage = this.handler.handleMessage; - this.connection.onerror = this.handler.handleError; + this.connection.addEventListener('open', this.handler.handleOpen); + this.connection.addEventListener('message', this.handler.handleMessage); + this.connection.addEventListener('error', this.handler.handleError); } } @@ -69,13 +98,4 @@ export default class SSEClient implements ISSEClient { close() { if (this.connection) this.connection.close(); } - - /** - * Re-open the connection with the last given authToken. - * - * @throws {TypeError} if `open` has not been previously called with an authToken - */ - reopen() { - this.open(this.authToken as IAuthTokenPushEnabled); - } } diff --git a/src/sync/streaming/SSEClient/types.ts b/src/sync/streaming/SSEClient/types.ts index aba3c03f..3d614080 100644 --- a/src/sync/streaming/SSEClient/types.ts +++ b/src/sync/streaming/SSEClient/types.ts @@ -8,7 +8,6 @@ export interface ISseEventHandler { export interface ISSEClient { open(authToken: IAuthTokenPushEnabled): void, - reopen(): void, close(): void, setEventHandler(handler: ISseEventHandler): void } diff --git a/src/sync/streaming/SSEHandler/NotificationKeeper.ts b/src/sync/streaming/SSEHandler/NotificationKeeper.ts index ce2ba8f1..1df88250 100644 --- a/src/sync/streaming/SSEHandler/NotificationKeeper.ts +++ b/src/sync/streaming/SSEHandler/NotificationKeeper.ts @@ -62,6 +62,14 @@ export default function notificationKeeperFactory(pushEmitter: IPushEventEmitter }, handleControlEvent(controlType: ControlType, channel: string, timestamp: number) { + /* STREAMING_RESET control event is handled by PushManager directly since it doesn't require + * tracking timestamp and state like OCCUPANCY or CONTROL. It also ignores previous + * OCCUPANCY and CONTROL notifications, and whether PUSH_SUBSYSTEM_DOWN has been emitted or not */ + if (controlType === ControlType.STREAMING_RESET) { + pushEmitter.emit(controlType); + return; + } + for (let i = 0; i < channels.length; i++) { const c = channels[i]; if (c.regex.test(channel)) { diff --git a/src/sync/streaming/SSEHandler/NotificationParser.ts b/src/sync/streaming/SSEHandler/NotificationParser.ts index a7403a0e..749fc332 100644 --- a/src/sync/streaming/SSEHandler/NotificationParser.ts +++ b/src/sync/streaming/SSEHandler/NotificationParser.ts @@ -22,10 +22,12 @@ export function errorParser(error: Event): INotificationError { * Also assigns the type OCCUPANCY, if it corresponds, so that all supported messages (e.g., SPLIT_UPDATE, CONTROL) have a type. * * @param message - * @returns parsed notification message + * @returns parsed notification message or undefined if the given event data is falsy (e.g, '' or undefined). + * For example, the EventSource implementation of React-Native for iOS emits a message event with empty data for Ably keepalive comments. * @throws {SyntaxError} if `message.data` or `JSON.parse(message.data).data` are invalid JSON strings */ -export function messageParser(message: MessageEvent): INotificationMessage { +export function messageParser(message: MessageEvent): INotificationMessage | undefined { + if (!message.data) return; const messageData = JSON.parse(message.data); messageData.parsedData = JSON.parse(messageData.data); diff --git a/src/sync/streaming/SSEHandler/__tests__/index.spec.ts b/src/sync/streaming/SSEHandler/__tests__/index.spec.ts index 52473d0d..79f8c573 100644 --- a/src/sync/streaming/SSEHandler/__tests__/index.spec.ts +++ b/src/sync/streaming/SSEHandler/__tests__/index.spec.ts @@ -1,6 +1,6 @@ // @ts-nocheck import SSEHandlerFactory from '..'; -import { PUSH_SUBSYSTEM_UP, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, PUSH_RETRYABLE_ERROR, MY_SEGMENTS_UPDATE, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE } from '../../constants'; +import { PUSH_SUBSYSTEM_UP, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, PUSH_RETRYABLE_ERROR, MY_SEGMENTS_UPDATE, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MY_SEGMENTS_UPDATE_V2, ControlType } from '../../constants'; import { loggerMock } from '../../../../logger/__tests__/sdkLogger.mock'; // update messages @@ -9,21 +9,31 @@ import splitKillMessage from '../../../../__tests__/mocks/message.SPLIT_KILL.145 import segmentUpdateMessage from '../../../../__tests__/mocks/message.SEGMENT_UPDATE.1457552640000.json'; import mySegmentsUpdateMessage from '../../../../__tests__/mocks/message.MY_SEGMENTS_UPDATE.nicolas@split.io.1457552640000.json'; +// update messages MY_SEGMENTS_UPDATE_V2 +import unboundedMessage from '../../../../__tests__/mocks/message.V2.UNBOUNDED.1457552650000.json'; +import boundedGzipMessage from '../../../../__tests__/mocks/message.V2.BOUNDED.GZIP.1457552651000.json'; +import keylistGzipMessage from '../../../../__tests__/mocks/message.V2.KEYLIST.GZIP.1457552652000.json'; +import segmentRemovalMessage from '../../../../__tests__/mocks/message.V2.SEGMENT_REMOVAL.1457552653000.json'; +import { keylists, bitmaps } from '../../__tests__/dataMocks'; + // occupancy messages import occupancy1ControlPri from '../../../../__tests__/mocks/message.OCCUPANCY.1.control_pri.1586987434450.json'; import occupancy0ControlPri from '../../../../__tests__/mocks/message.OCCUPANCY.0.control_pri.1586987434550.json'; import occupancy2ControlPri from '../../../../__tests__/mocks/message.OCCUPANCY.2.control_pri.1586987434650.json'; -const occupancy1ControlSec = {...occupancy1ControlPri, data: occupancy1ControlPri.data.replace('control_pri', 'control_sec')}; -const occupancy0ControlSec = {...occupancy0ControlPri, data: occupancy0ControlPri.data.replace('control_pri', 'control_sec')}; -const occupancy2ControlSec = {...occupancy2ControlPri, data: occupancy2ControlPri.data.replace('control_pri', 'control_sec')}; +const occupancy1ControlSec = { ...occupancy1ControlPri, data: occupancy1ControlPri.data.replace('control_pri', 'control_sec') }; +const occupancy0ControlSec = { ...occupancy0ControlPri, data: occupancy0ControlPri.data.replace('control_pri', 'control_sec') }; +const occupancy2ControlSec = { ...occupancy2ControlPri, data: occupancy2ControlPri.data.replace('control_pri', 'control_sec') }; // control messages import controlStreamingPaused from '../../../../__tests__/mocks/message.CONTROL.STREAMING_PAUSED.control_pri.1586987434750.json'; import controlStreamingResumed from '../../../../__tests__/mocks/message.CONTROL.STREAMING_RESUMED.control_pri.1586987434850.json'; import controlStreamingDisabled from '../../../../__tests__/mocks/message.CONTROL.STREAMING_DISABLED.control_pri.1586987434950.json'; -const controlStreamingPausedSec = {...controlStreamingPaused, data: controlStreamingPaused.data.replace('control_pri', 'control_sec')}; -const controlStreamingResumedSec = {...controlStreamingResumed, data: controlStreamingResumed.data.replace('control_pri', 'control_sec')}; -const controlStreamingDisabledSec = {...controlStreamingDisabled, data: controlStreamingDisabled.data.replace('control_pri', 'control_sec')}; +const controlStreamingPausedSec = { ...controlStreamingPaused, data: controlStreamingPaused.data.replace('control_pri', 'control_sec') }; +const controlStreamingResumedSec = { ...controlStreamingResumed, data: controlStreamingResumed.data.replace('control_pri', 'control_sec') }; +const controlStreamingDisabledSec = { ...controlStreamingDisabled, data: controlStreamingDisabled.data.replace('control_pri', 'control_sec') }; + +// streaming reset message, from `{orgHash}_{envHash}_control` channel +import streamingReset from '../../../../__tests__/mocks/message.STREAMING_RESET.json'; const pushEmitter = { emit: jest.fn() }; @@ -37,7 +47,7 @@ test('`handleOpen` and `handlerMessage` for OCCUPANCY notifications (Notificatio expect(pushEmitter.emit.mock.calls[0][0]).toBe(PUSH_SUBSYSTEM_UP); // must emit PUSH_SUBSYSTEM_UP sseHandler.handleMessage({ data: '{ "data": "{\\"type\\":\\"SPLIT_UPDATE\\",\\"changeNumber\\":1457552620999 }" }' }); - expect(pushEmitter.emit).toHaveBeenLastCalledWith(SPLIT_UPDATE, 1457552620999); // must handle update massage if streaming on + expect(pushEmitter.emit).toHaveBeenLastCalledWith(SPLIT_UPDATE, { type: 'SPLIT_UPDATE', changeNumber: 1457552620999 }); // must handle update message if streaming on // OCCUPANCY messages @@ -49,25 +59,29 @@ test('`handleOpen` and `handlerMessage` for OCCUPANCY notifications (Notificatio expect(pushEmitter.emit).toHaveBeenLastCalledWith(PUSH_SUBSYSTEM_DOWN); // must emit PUSH_SUBSYSTEM_DOWN if streaming on and OCCUPANCY 0 in both control channels sseHandler.handleMessage({ data: '{ "data": "{\\"type\\":\\"SPLIT_UPDATE\\",\\"changeNumber\\":1457552620999 }" }' }); - expect(pushEmitter.emit).toBeCalledTimes(3); // must not handle update massage if streaming off after an OCCUPANCY message + expect(pushEmitter.emit).toBeCalledTimes(3); // must not handle update message if streaming off after an OCCUPANCY message + + sseHandler.handleMessage(streamingReset); + expect(pushEmitter.emit).toBeCalledTimes(4); // but must handle streaming reset message sseHandler.handleMessage(occupancy0ControlPri); sseHandler.handleMessage(occupancy0ControlSec); - expect(pushEmitter.emit).toBeCalledTimes(3); // must not emit PUSH_SUBSYSTEM_DOWN if streaming off + expect(pushEmitter.emit).toBeCalledTimes(4); // must not emit PUSH_SUBSYSTEM_DOWN if streaming off sseHandler.handleMessage(occupancy1ControlPri); sseHandler.handleMessage(occupancy1ControlSec); - expect(pushEmitter.emit).toBeCalledTimes(3); // must ignore OCCUPANCY message if its timestamp is older + expect(pushEmitter.emit).toBeCalledTimes(4); // must ignore OCCUPANCY message if its timestamp is older sseHandler.handleMessage(occupancy2ControlSec); expect(pushEmitter.emit).toHaveBeenLastCalledWith(PUSH_SUBSYSTEM_UP); // must emit PUSH_SUBSYSTEM_UP if streaming off and OCCUPANCY mayor than 0 in at least one channel sseHandler.handleMessage({ data: '{ "data": "{\\"type\\":\\"SPLIT_UPDATE\\",\\"changeNumber\\":1457552620999 }" }' }); sseHandler.handleMessage(occupancy2ControlPri); // must not emit PUSH_SUBSYSTEM_UP, since streaming is already on - expect(pushEmitter.emit).toHaveBeenLastCalledWith(SPLIT_UPDATE, 1457552620999); // must handle update massage if streaming on after an OCCUPANCY event - - expect(pushEmitter.emit).toBeCalledTimes(5); // must not emit PUSH_SUBSYSTEM_UP if streaming is already on and another channel has publishers + expect(pushEmitter.emit).toHaveBeenLastCalledWith(SPLIT_UPDATE, { type: 'SPLIT_UPDATE', changeNumber: 1457552620999 }); // must handle update message if streaming on after an OCCUPANCY event + sseHandler.handleMessage(streamingReset); + expect(pushEmitter.emit).toHaveBeenLastCalledWith(ControlType.STREAMING_RESET); // must handle streaming reset + expect(pushEmitter.emit).toBeCalledTimes(7); // must not emit PUSH_SUBSYSTEM_UP if streaming is already on and another channel has publishers }); test('`handlerMessage` for CONTROL notifications (NotificationKeeper)', () => { @@ -81,21 +95,26 @@ test('`handlerMessage` for CONTROL notifications (NotificationKeeper)', () => { expect(pushEmitter.emit).toHaveBeenLastCalledWith(PUSH_SUBSYSTEM_DOWN); // must emit PUSH_SUBSYSTEM_DOWN if streaming on and received a STREAMING_PAUSED control message sseHandler.handleMessage({ data: '{ "data": "{\\"type\\":\\"SPLIT_UPDATE\\",\\"changeNumber\\":1457552620999 }" }' }); - expect(pushEmitter.emit).toBeCalledTimes(2); // must not handle update massage if streaming off after a CONTROL message + expect(pushEmitter.emit).toBeCalledTimes(2); // must not handle update message if streaming off after a CONTROL message + + sseHandler.handleMessage(streamingReset); + expect(pushEmitter.emit).toBeCalledTimes(3); // but must handle streaming reset message sseHandler.handleMessage(controlStreamingPaused); sseHandler.handleMessage(controlStreamingPausedSec); - expect(pushEmitter.emit).toBeCalledTimes(2); // must not emit PUSH_SUBSYSTEM_DOWN if streaming off + expect(pushEmitter.emit).toBeCalledTimes(3); // must not emit PUSH_SUBSYSTEM_DOWN if streaming off sseHandler.handleMessage(controlStreamingResumedSec); // testing STREAMING_RESUMED with second region expect(pushEmitter.emit).toHaveBeenLastCalledWith(PUSH_SUBSYSTEM_UP); // must emit PUSH_SUBSYSTEM_UP if streaming off and received a STREAMING_RESUMED control message'); sseHandler.handleMessage(controlStreamingResumed); sseHandler.handleMessage(controlStreamingResumedSec); - expect(pushEmitter.emit).toBeCalledTimes(3); // must not emit PUSH_SUBSYSTEM_UP if streaming on + expect(pushEmitter.emit).toBeCalledTimes(4); // must not emit PUSH_SUBSYSTEM_UP if streaming on sseHandler.handleMessage({ data: '{ "data": "{\\"type\\":\\"SPLIT_UPDATE\\",\\"changeNumber\\":1457552620999 }" }' }); - expect(pushEmitter.emit).toHaveBeenLastCalledWith(SPLIT_UPDATE, 1457552620999); // must handle update massage if streaming on after a CONTROL event + expect(pushEmitter.emit).toHaveBeenLastCalledWith(SPLIT_UPDATE, { type: 'SPLIT_UPDATE', changeNumber: 1457552620999 }); // must handle update message if streaming on after a CONTROL event + sseHandler.handleMessage(streamingReset); + expect(pushEmitter.emit).toHaveBeenLastCalledWith(ControlType.STREAMING_RESET); // must handle streaming reset sseHandler.handleMessage(controlStreamingDisabledSec); // testing STREAMING_DISABLED with second region expect(pushEmitter.emit).toHaveBeenLastCalledWith(PUSH_NONRETRYABLE_ERROR); // must emit PUSH_NONRETRYABLE_ERROR if received a STREAMING_DISABLED control message @@ -111,20 +130,20 @@ test('`handlerMessage` for CONTROL notifications (NotificationKeeper)', () => { }); -test('`handlerMessage` for update notifications (NotificationProcessor)', () => { +test('`handlerMessage` for update notifications (NotificationProcessor) and streaming reset', () => { const sseHandler = SSEHandlerFactory(loggerMock, pushEmitter); sseHandler.handleOpen(); pushEmitter.emit.mockClear(); - let expectedParams = [1457552620999]; + let expectedParams = [{ type: 'SPLIT_UPDATE', changeNumber: 1457552620999 }]; sseHandler.handleMessage(splitUpdateMessage); expect(pushEmitter.emit).toHaveBeenLastCalledWith(SPLIT_UPDATE, ...expectedParams); // must emit SPLIT_UPDATE with the message change number - expectedParams = [1457552650000, 'whitelist', 'not_allowed']; + expectedParams = [{ type: 'SPLIT_KILL', changeNumber: 1457552650000, splitName: 'whitelist', defaultTreatment: 'not_allowed' }]; sseHandler.handleMessage(splitKillMessage); expect(pushEmitter.emit).toHaveBeenLastCalledWith(SPLIT_KILL, ...expectedParams); // must emit SPLIT_KILL with the message change number, split name and default treatment - expectedParams = [1457552640000, 'splitters']; + expectedParams = [{ type: 'SEGMENT_UPDATE', changeNumber: 1457552640000, segmentName: 'splitters' }]; sseHandler.handleMessage(segmentUpdateMessage); expect(pushEmitter.emit).toHaveBeenLastCalledWith(SEGMENT_UPDATE, ...expectedParams); // must emit SEGMENT_UPDATE with the message change number and segment name @@ -132,6 +151,25 @@ test('`handlerMessage` for update notifications (NotificationProcessor)', () => sseHandler.handleMessage(mySegmentsUpdateMessage); expect(pushEmitter.emit).toHaveBeenLastCalledWith(MY_SEGMENTS_UPDATE, ...expectedParams); // must emit MY_SEGMENTS_UPDATE with the message parsed data and channel + expectedParams = [{ type: 'MY_SEGMENTS_UPDATE_V2', changeNumber: 1457552650000, c: 0, d: '', u: 0, segmentName: '' }]; + sseHandler.handleMessage(unboundedMessage); + expect(pushEmitter.emit).toHaveBeenLastCalledWith(MY_SEGMENTS_UPDATE_V2, ...expectedParams); // must emit MY_SEGMENTS_UPDATE_V2 with the message parsed data + + expectedParams = [{ type: 'MY_SEGMENTS_UPDATE_V2', changeNumber: 1457552651000, c: 1, d: bitmaps[0].bitmapDataCompressed, u: 1, segmentName: '' }]; + sseHandler.handleMessage(boundedGzipMessage); + expect(pushEmitter.emit).toHaveBeenLastCalledWith(MY_SEGMENTS_UPDATE_V2, ...expectedParams); // must emit MY_SEGMENTS_UPDATE_V2 with the message parsed data + + expectedParams = [{ type: 'MY_SEGMENTS_UPDATE_V2', changeNumber: 1457552652000, c: 1, d: keylists[0].keyListDataCompressed, u: 2, segmentName: 'splitters' }]; + sseHandler.handleMessage(keylistGzipMessage); + expect(pushEmitter.emit).toHaveBeenLastCalledWith(MY_SEGMENTS_UPDATE_V2, ...expectedParams); // must emit MY_SEGMENTS_UPDATE_V2 with the message parsed data + + expectedParams = [{ type: 'MY_SEGMENTS_UPDATE_V2', changeNumber: 1457552653000, c: 0, d: '', u: 3, segmentName: 'splitters' }]; + sseHandler.handleMessage(segmentRemovalMessage); + expect(pushEmitter.emit).toHaveBeenLastCalledWith(MY_SEGMENTS_UPDATE_V2, ...expectedParams); // must emit MY_SEGMENTS_UPDATE_V2 with the message parsed data + + sseHandler.handleMessage(streamingReset); + expect(pushEmitter.emit).toHaveBeenLastCalledWith(ControlType.STREAMING_RESET); // must emit STREAMING_RESET + }); test('handleError', () => { @@ -172,12 +210,12 @@ test('handlerMessage: ignore invalid events', () => { sseHandler.handleMessage('invalid message'); sseHandler.handleMessage({ data: '{ data: %invalid json\'\'}' }); - expect(pushEmitter.emit).toBeCalledTimes(0); // must ignore massage if invalid + expect(pushEmitter.emit).toBeCalledTimes(0); // must ignore message if invalid sseHandler.handleMessage({ data: '{ "data": "{\\"type\\":\\"UNSUPPORTED_TYPE\\",\\"changeNumber\\":1457552620999 }" }' }); - expect(pushEmitter.emit).toBeCalledTimes(0); // must ignore massage if it has an invalid type + expect(pushEmitter.emit).toBeCalledTimes(0); // must ignore message if it has an invalid type sseHandler.handleMessage({ data: '{ "data": "{\\"type\\":\\"SPLIT_UPDATE\\",\\"changeNumber\\":1457552620999 }" }' }); - expect(pushEmitter.emit).toBeCalledTimes(1); // must handle massage if valid + expect(pushEmitter.emit).toBeCalledTimes(1); // must handle message if valid }); diff --git a/src/sync/streaming/SSEHandler/index.ts b/src/sync/streaming/SSEHandler/index.ts index 716564d8..b0cd7069 100644 --- a/src/sync/streaming/SSEHandler/index.ts +++ b/src/sync/streaming/SSEHandler/index.ts @@ -1,9 +1,9 @@ import { errorParser, messageParser } from './NotificationParser'; import notificationKeeperFactory from './NotificationKeeper'; -import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, MY_SEGMENTS_UPDATE, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE } from '../constants'; +import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE } from '../constants'; import { IPushEventEmitter } from '../types'; import { ISseEventHandler } from '../SSEClient/types'; -import { INotificationError } from './types'; +import { INotificationError, INotificationMessage } from './types'; import { ILogger } from '../../../logger/types'; import { STREAMING_PARSING_ERROR_FAILS, ERROR_STREAMING_SSE, STREAMING_PARSING_MESSAGE_FAILS, STREAMING_NEW_MESSAGE } from '../../../logger/constants'; @@ -43,7 +43,7 @@ export default function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventE log.warn(STREAMING_PARSING_ERROR_FAILS, [err]); } - let errorMessage = errorWithParsedData.parsedData && errorWithParsedData.parsedData.message; + let errorMessage = (errorWithParsedData.parsedData && errorWithParsedData.parsedData.message) || errorWithParsedData.message; log.error(ERROR_STREAMING_SSE, [errorMessage]); if (isRetryableError(errorWithParsedData)) { @@ -55,9 +55,10 @@ export default function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventE /* NotificationProcessor */ handleMessage(message) { - let messageWithParsedData; + let messageWithParsedData: INotificationMessage | undefined; try { messageWithParsedData = messageParser(message); + if (!messageWithParsedData) return; // Messages with empty data are ignored } catch (err) { log.warn(STREAMING_PARSING_MESSAGE_FAILS, [err]); return; @@ -67,30 +68,19 @@ export default function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventE log.debug(STREAMING_NEW_MESSAGE, [data]); // we only handle update events if streaming is up. - if (!notificationKeeper.isStreamingUp() && parsedData.type !== OCCUPANCY && parsedData.type !== CONTROL) + if (!notificationKeeper.isStreamingUp() && [OCCUPANCY, CONTROL].indexOf(parsedData.type) === -1) return; switch (parsedData.type) { /* update events */ case SPLIT_UPDATE: - pushEmitter.emit(SPLIT_UPDATE, - parsedData.changeNumber); - break; case SEGMENT_UPDATE: - pushEmitter.emit(SEGMENT_UPDATE, - parsedData.changeNumber, - parsedData.segmentName); + case MY_SEGMENTS_UPDATE_V2: + case SPLIT_KILL: + pushEmitter.emit(parsedData.type, parsedData); break; case MY_SEGMENTS_UPDATE: - pushEmitter.emit(MY_SEGMENTS_UPDATE, - parsedData, - channel); - break; - case SPLIT_KILL: - pushEmitter.emit(SPLIT_KILL, - parsedData.changeNumber, - parsedData.splitName, - parsedData.defaultTreatment); + pushEmitter.emit(parsedData.type, parsedData, channel); break; /* occupancy & control events, handled by NotificationManagerKeeper */ @@ -100,6 +90,7 @@ export default function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventE case CONTROL: notificationKeeper.handleControlEvent(parsedData.controlType, channel, timestamp); break; + default: break; } diff --git a/src/sync/streaming/SSEHandler/types.ts b/src/sync/streaming/SSEHandler/types.ts index 039c1675..293689ab 100644 --- a/src/sync/streaming/SSEHandler/types.ts +++ b/src/sync/streaming/SSEHandler/types.ts @@ -1,5 +1,5 @@ import { ControlType } from '../constants'; -import { MY_SEGMENTS_UPDATE, SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY } from '../types'; +import { MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY } from '../types'; export interface IMySegmentsUpdateData { type: MY_SEGMENTS_UPDATE, @@ -8,6 +8,33 @@ export interface IMySegmentsUpdateData { segmentList?: string[] } +export enum Compression { + None = 0, + Gzip = 1, + Zlib = 2 +} + +export enum UpdateStrategy { + UnboundedFetchRequest = 0, + BoundedFetchRequest = 1, + KeyList = 2, + SegmentRemoval = 3 +} + +export interface KeyList { + a?: string[], // decimal hash64 of user keys + r?: string[], // decimal hash64 of user keys +} + +export interface IMySegmentsUpdateV2Data { + type: MY_SEGMENTS_UPDATE_V2, + changeNumber: number, + segmentName: string, + c: Compression, + d: string, + u: UpdateStrategy, +} + export interface ISegmentUpdateData { type: SEGMENT_UPDATE, changeNumber: number, @@ -38,6 +65,13 @@ export interface IOccupancyData { } } -export type INotificationData = IMySegmentsUpdateData | ISegmentUpdateData | ISplitUpdateData | ISplitKillData | IControlData | IOccupancyData +export type INotificationData = IMySegmentsUpdateData | IMySegmentsUpdateV2Data | ISegmentUpdateData | ISplitUpdateData | ISplitKillData | IControlData | IOccupancyData export type INotificationMessage = { parsedData: INotificationData, channel: string, timestamp: number, data: string } -export type INotificationError = Event & { parsedData?: any } +export type INotificationError = Event & { parsedData?: any, message?: string } + +export type SegmentsData = string[] | { + /* segment name */ + name: string, + /* action: `true` for add, and `false` for delete */ + add: boolean +} diff --git a/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts b/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts index fb52b403..192e81fa 100644 --- a/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +++ b/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts @@ -1,6 +1,7 @@ import { ISegmentsSyncTask } from '../../polling/types'; import Backoff from '../../../utils/Backoff'; import { IUpdateWorker } from './types'; +import { SegmentsData } from '../SSEHandler/types'; /** * MySegmentsUpdateWorker class @@ -10,7 +11,7 @@ export default class MySegmentsUpdateWorker implements IUpdateWorker { private readonly mySegmentsSyncTask: ISegmentsSyncTask; private maxChangeNumber: number; private handleNewEvent: boolean; - private segmentList?: string[]; + private segmentsData?: SegmentsData; private currentChangeNumber: number; readonly backoff: Backoff; @@ -21,7 +22,7 @@ export default class MySegmentsUpdateWorker implements IUpdateWorker { this.mySegmentsSyncTask = mySegmentsSyncTask; this.maxChangeNumber = 0; // keeps the maximum changeNumber among queued events this.handleNewEvent = false; - this.segmentList = undefined; // keeps the segmentList (if included in payload) from the queued event with maximum changeNumber + this.segmentsData = undefined; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber this.currentChangeNumber = -1; // @TODO: remove once `/mySegments` endpoint provides the changeNumber this.put = this.put.bind(this); this.__handleMySegmentsUpdateCall = this.__handleMySegmentsUpdateCall.bind(this); @@ -36,7 +37,7 @@ export default class MySegmentsUpdateWorker implements IUpdateWorker { const currentMaxChangeNumber = this.maxChangeNumber; // fetch mySegments revalidating data if cached - this.mySegmentsSyncTask.execute(this.segmentList, true).then((result) => { + this.mySegmentsSyncTask.execute(this.segmentsData, true).then((result) => { if (result !== false) // Unlike `Splits|SegmentsUpdateWorker`, we cannot use `mySegmentsCache.getChangeNumber` since `/mySegments` endpoint doesn't provide this value. this.currentChangeNumber = Math.max(this.currentChangeNumber, currentMaxChangeNumber); // use `currentMaxChangeNumber`, in case that `this.maxChangeNumber` was updated during fetch. if (this.handleNewEvent) { @@ -52,15 +53,15 @@ export default class MySegmentsUpdateWorker implements IUpdateWorker { * Invoked by NotificationProcessor on MY_SEGMENTS_UPDATE event * * @param {number} changeNumber change number of the MY_SEGMENTS_UPDATE notification - * @param {string[] | undefined} segmentList might be undefined + * @param {SegmentsData | undefined} segmentsData might be undefined */ - put(changeNumber: number, segmentList?: string[]) { + put(changeNumber: number, segmentsData?: SegmentsData) { if (changeNumber <= this.currentChangeNumber || changeNumber <= this.maxChangeNumber) return; this.maxChangeNumber = changeNumber; this.handleNewEvent = true; this.backoff.reset(); - this.segmentList = segmentList; + this.segmentsData = segmentsData; if (this.mySegmentsSyncTask.isExecuting()) return; diff --git a/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts b/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts index aa900e9d..3a299024 100644 --- a/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +++ b/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts @@ -1,6 +1,7 @@ import { ISegmentsCacheSync } from '../../../storages/types'; import Backoff from '../../../utils/Backoff'; import { ISegmentsSyncTask } from '../../polling/types'; +import { ISegmentUpdateData } from '../SSEHandler/types'; import { IUpdateWorker } from './types'; /** @@ -66,7 +67,7 @@ export default class SegmentsUpdateWorker implements IUpdateWorker { * @param {number} changeNumber change number of the SEGMENT_UPDATE notification * @param {string} segmentName segment name of the SEGMENT_UPDATE notification */ - put(changeNumber: number, segmentName: string) { + put({ changeNumber, segmentName }: ISegmentUpdateData) { const currentChangeNumber = this.segmentsCache.getChangeNumber(segmentName); if (changeNumber <= currentChangeNumber || changeNumber <= this.maxChangeNumbers[segmentName]) return; diff --git a/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts b/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts index 7c93b476..944d5776 100644 --- a/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +++ b/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts @@ -3,6 +3,7 @@ import { ISplitsEventEmitter } from '../../../readiness/types'; import { ISplitsCacheSync } from '../../../storages/types'; import Backoff from '../../../utils/Backoff'; import { ISegmentsSyncTask, ISplitsSyncTask } from '../../polling/types'; +import { ISplitKillData, ISplitUpdateData } from '../SSEHandler/types'; import { IUpdateWorker } from './types'; /** @@ -60,7 +61,7 @@ export default class SplitsUpdateWorker implements IUpdateWorker { * * @param {number} changeNumber change number of the SPLIT_UPDATE notification */ - put(changeNumber: number) { + put({ changeNumber }: Pick) { const currentChangeNumber = this.splitsCache.getChangeNumber(); if (changeNumber <= currentChangeNumber || changeNumber <= this.maxChangeNumber) return; @@ -81,14 +82,14 @@ export default class SplitsUpdateWorker implements IUpdateWorker { * @param {string} splitName name of split to kill * @param {string} defaultTreatment default treatment value */ - killSplit(changeNumber: number, splitName: string, defaultTreatment: string) { + killSplit({ changeNumber, splitName, defaultTreatment }: ISplitKillData) { // @TODO handle retry due to errors in storage, once we allow the definition of custom async storages if (this.splitsCache.killLocally(splitName, defaultTreatment, changeNumber)) { // trigger an SDK_UPDATE if Split was killed locally this.splitsEventEmitter.emit(SDK_SPLITS_ARRIVED, true); } // queues the SplitChanges fetch (only if changeNumber is newer) - this.put(changeNumber); + this.put({ changeNumber }); } } diff --git a/src/sync/streaming/UpdateWorkers/__tests__/SegmentsUpdateWorker.spec.ts b/src/sync/streaming/UpdateWorkers/__tests__/SegmentsUpdateWorker.spec.ts index 50eddd88..5e6acb6a 100644 --- a/src/sync/streaming/UpdateWorkers/__tests__/SegmentsUpdateWorker.spec.ts +++ b/src/sync/streaming/UpdateWorkers/__tests__/SegmentsUpdateWorker.spec.ts @@ -54,18 +54,18 @@ describe('SegmentsUpdateWorker ', () => { // assert calling `segmentsSyncTask.execute` if `isExecuting` is false expect(segmentsSyncTask.isExecuting()).toBe(false); - segmentsUpdateWorker.put(100, 'mocked_segment_1'); + segmentsUpdateWorker.put({ changeNumber: 100, segmentName: 'mocked_segment_1' }); expect(segmentsUpdateWorker.maxChangeNumbers).toEqual({ 'mocked_segment_1': 100 }); // queues events (changeNumbers) if they are mayor than storage changeNumbers and maxChangeNumbers expect(segmentsSyncTask.execute).toBeCalledTimes(1); // synchronizes segment if `isExecuting` is false expect(segmentsSyncTask.execute.mock.calls).toEqual([[['mocked_segment_1'], true]]); // synchronizes segment with given name // assert queueing items if `isExecuting` is true expect(segmentsSyncTask.isExecuting()).toBe(true); - segmentsUpdateWorker.put(95, 'mocked_segment_1'); - segmentsUpdateWorker.put(100, 'mocked_segment_2'); - segmentsUpdateWorker.put(105, 'mocked_segment_1'); - segmentsUpdateWorker.put(94, 'mocked_segment_1'); - segmentsUpdateWorker.put(94, 'mocked_segment_3'); + segmentsUpdateWorker.put({ changeNumber: 95, segmentName: 'mocked_segment_1' }); + segmentsUpdateWorker.put({ changeNumber: 100, segmentName: 'mocked_segment_2' }); + segmentsUpdateWorker.put({ changeNumber: 105, segmentName: 'mocked_segment_1' }); + segmentsUpdateWorker.put({ changeNumber: 94, segmentName: 'mocked_segment_1' }); + segmentsUpdateWorker.put({ changeNumber: 94, segmentName: 'mocked_segment_3' }); expect(segmentsUpdateWorker.maxChangeNumbers).toEqual({ 'mocked_segment_1': 105, 'mocked_segment_2': 100, 'mocked_segment_3': 94 }); // queues events expect(segmentsSyncTask.execute).toBeCalledTimes(1); // doesn't synchronize segment if `isExecuting` is true @@ -80,7 +80,7 @@ describe('SegmentsUpdateWorker ', () => { // assert not rescheduling synchronization if some changeNumber is not updated as expected, // but rescheduling if a new item was queued with a greater changeNumber while the fetch was pending. - segmentsUpdateWorker.put(110, 'mocked_segment_1'); + segmentsUpdateWorker.put({ changeNumber: 110, segmentName: 'mocked_segment_1' }); segmentsSyncTask.__resolveSegmentsUpdaterCall(1, { 'mocked_segment_1': 100, 'mocked_segment_2': 100, 'mocked_segment_3': 94 }); setTimeout(() => { expect(segmentsSyncTask.execute).toBeCalledTimes(3); // re-synchronizes segment if a new item was queued with a greater changeNumber while the fetch was pending @@ -94,7 +94,7 @@ describe('SegmentsUpdateWorker ', () => { expect(segmentsUpdateWorker.maxChangeNumbers).toEqual({ 'mocked_segment_1': -1, 'mocked_segment_2': -1, 'mocked_segment_3': -1 }); // maxChangeNumbers were cleaned // assert restarting retries, when a newer event is queued - segmentsUpdateWorker.put(110, 'mocked_segment_1'); // queued + segmentsUpdateWorker.put({ changeNumber: 110, segmentName: 'mocked_segment_1' }); // queued expect(segmentsUpdateWorker.backoff.attempts).toBe(0); // backoff scheduler for retries is reset if a new event is queued done(); diff --git a/src/sync/streaming/UpdateWorkers/__tests__/SplitsUpdateWorker.spec.ts b/src/sync/streaming/UpdateWorkers/__tests__/SplitsUpdateWorker.spec.ts index 43aec4e1..bf28fa2e 100644 --- a/src/sync/streaming/UpdateWorkers/__tests__/SplitsUpdateWorker.spec.ts +++ b/src/sync/streaming/UpdateWorkers/__tests__/SplitsUpdateWorker.spec.ts @@ -62,16 +62,16 @@ describe('SplitsUpdateWorker', () => { // assert calling `splitsSyncTask.execute` if `isExecuting` is false expect(splitsSyncTask.isExecuting()).toBe(false); - splitUpdateWorker.put(100); // queued + splitUpdateWorker.put({ changeNumber: 100 }); // queued expect(splitUpdateWorker.maxChangeNumber).toBe(100); // queues changeNumber if it is mayor than storage changeNumber and maxChangeNumber expect(splitsSyncTask.execute).toBeCalledTimes(1); // synchronizes splits if `isExecuting` is false // assert queueing changeNumber if `isExecuting` is true expect(splitsSyncTask.isExecuting()).toBe(true); - splitUpdateWorker.put(105); // queued - splitUpdateWorker.put(104); // not queued - splitUpdateWorker.put(106); // queued - splitUpdateWorker.put(103); // not queued + splitUpdateWorker.put({ changeNumber: 105 }); // queued + splitUpdateWorker.put({ changeNumber: 104 }); // not queued + splitUpdateWorker.put({ changeNumber: 106 }); // queued + splitUpdateWorker.put({ changeNumber: 103 }); // not queued expect(splitsSyncTask.execute).toBeCalledTimes(1); // doesn't synchronize splits while `isExecuting` is true expect(splitUpdateWorker.maxChangeNumber).toBe(106); // queues changeNumber if it is mayor than currently maxChangeNumber and storage changeNumber @@ -96,7 +96,7 @@ describe('SplitsUpdateWorker', () => { expect(splitUpdateWorker.maxChangeNumber).toBe(106); // maxChangeNumber // assert restarting retries, when a newer event is queued - splitUpdateWorker.put(107); // queued + splitUpdateWorker.put({ changeNumber: 107 }); // queued expect(splitUpdateWorker.backoff.attempts).toBe(0); // backoff scheduler for retries is reset if a new event is queued done(); @@ -116,7 +116,7 @@ describe('SplitsUpdateWorker', () => { const splitUpdateWorker = new SplitsUpdateWorker(cache, splitsSyncTask, splitsEventEmitterMock); // assert killing split locally, emitting SDK_SPLITS_ARRIVED event, and synchronizing splits if changeNumber is new - splitUpdateWorker.killSplit(100, 'lol1', 'off'); // splitsCache.killLocally is synchronous + splitUpdateWorker.killSplit({ changeNumber: 100, splitName: 'lol1', defaultTreatment: 'off' }); // splitsCache.killLocally is synchronous expect(splitUpdateWorker.maxChangeNumber).toBe(100); // queues changeNumber if split kill resolves with update expect(splitsSyncTask.execute).toBeCalledTimes(1); // synchronizes splits if `isExecuting` is false expect(splitsEventEmitterMock.emit.mock.calls).toEqual([[SDK_SPLITS_ARRIVED, true]]); // emits `SDK_SPLITS_ARRIVED` with `isSplitKill` flag in true, if split kill resolves with update @@ -127,7 +127,7 @@ describe('SplitsUpdateWorker', () => { setTimeout(() => { splitsSyncTask.execute.mockClear(); splitsEventEmitterMock.emit.mockClear(); - splitUpdateWorker.killSplit(90, 'lol1', 'on'); + splitUpdateWorker.killSplit({ changeNumber: 90, splitName: 'lol1', defaultTreatment: 'on' }); setTimeout(() => { expect(splitUpdateWorker.maxChangeNumber).toBe(100); // doesn't queues changeNumber if killLocally resolved without update (its changeNumber was minor than the split changeNumber diff --git a/src/sync/streaming/UpdateWorkers/types.ts b/src/sync/streaming/UpdateWorkers/types.ts index e8d6762e..ea91a154 100644 --- a/src/sync/streaming/UpdateWorkers/types.ts +++ b/src/sync/streaming/UpdateWorkers/types.ts @@ -2,5 +2,5 @@ import Backoff from '../../../utils/Backoff'; export interface IUpdateWorker { readonly backoff: Backoff, - put(changeNumber: number, ...args: any[]): void + put(...args: any[]): void } diff --git a/src/sync/streaming/__tests__/dataMocks.ts b/src/sync/streaming/__tests__/dataMocks.ts new file mode 100644 index 00000000..7d7ea334 --- /dev/null +++ b/src/sync/streaming/__tests__/dataMocks.ts @@ -0,0 +1,251 @@ +export const jwtSample = 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleUlkIiwidHlwIjoiSldUIn0.eyJvcmdJZCI6IjEyMTM4YWMxLTA5MmYtMzJlNy1iYTc4LTEyMzk1ZDRhOTYzNCIsImVudklkIjoiODZiMGQzYTAtNWY1NC0zMmU3LTIyZjktMDExNTBmYTlmYTNhIiwieC1hYmx5LWNhcGFiaWxpdHkiOiJ7XCJOek0yTURJNU16YzBfTXpReU9EVTRORFV5Tmc9PV9zZWdtZW50c1wiOltcInN1YnNjcmliZVwiXSxcIk56TTJNREk1TXpjMF9NelF5T0RVNE5EVXlOZz09X3NwbGl0c1wiOltcInN1YnNjcmliZVwiXSxcImNvbnRyb2xcIjpbXCJzdWJzY3JpYmVcIl19IiwieC1hYmx5LWNsaWVudElkIjoiY2xpZW50SWQiLCJleHAiOjE1ODM3ODcxMjQsImlhdCI6MTU4Mzc4MzUyNH0.f3I0ADc3kzQ4RfFywEukBM8bw91AUnJcGH3nwYUjEg0'; +export const jwtSampleInvalid = 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleUlkIiwidHlwIjoiSldUIn0.aaavcmdJZCI6IjEyMTM4YWMxLTA5MmYtMzJlNy1iYTc4LTEyMzk1ZDRhOTYzNCIsImVudklkIjoiODZiMGQzYTAtNWY1NC0zMmU3LTIyZjktMDExNTBmYTlmYTNhIiwieC1hYmx5LWNhcGFiaWxpdHkiOiJ7XCJOek0yTURJNU16YzBfTXpReU9EVTRORFV5Tmc9PV9zZWdtZW50c1wiOltcInN1YnNjcmliZVwiXSxcIk56TTJNREk1TXpjMF9NelF5T0RVNE5EVXlOZz09X3NwbGl0c1wiOltcInN1YnNjcmliZVwiXSxcImNvbnRyb2xcIjpbXCJzdWJzY3JpYmVcIl19IiwieC1hYmx5LWNsaWVudElkIjoiY2xpZW50SWQiLCJleHAiOjE1ODM3ODcxMjQsImlhdCI6MTU4Mzc4MzUyNH0.f3I0ADc3kzQ4RfFywEukBM8bw91AUnJcGH3nwYUjEg0'; +export const jwtSampleNoChannels = 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleUlkIiwidHlwIjoiSldUIn0.eyJvcmdJZCI6IjEyMTM4YWMxLTA5MmYtMzJlNy1iYTc4LTEyMzk1ZDRhOTYzNCIsImVudklkIjoiODZiMGQzYTAtNWY1NC0zMmU3LTIyZjktMDExNTBmYTlmYTNhIiwieC1hYmx5LWNsaWVudElkIjoiY2xpZW50SWQiLCJleHAiOjE1ODM3ODcxMjQsImlhdCI6MTU4Mzc4MzUyNH0.aiuUdeBAZaFMtgaH9y9cwxPG3LyiJCGpX54jd1V4Z54'; +export const jwtSampleNoIat = 'eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleUlkIiwidHlwIjoiSldUIn0.eyJvcmdJZCI6IjEyMTM4YWMxLTA5MmYtMzJlNy1iYTc4LTEyMzk1ZDRhOTYzNCIsImVudklkIjoiODZiMGQzYTAtNWY1NC0zMmU3LTIyZjktMDExNTBmYTlmYTNhIiwieC1hYmx5LWNhcGFiaWxpdHkiOiJ7XCJOek0yTURJNU16YzBfTXpReU9EVTRORFV5Tmc9PV9zZWdtZW50c1wiOltcInN1YnNjcmliZVwiXSxcIk56TTJNREk1TXpjMF9NelF5T0RVNE5EVXlOZz09X3NwbGl0c1wiOltcInN1YnNjcmliZVwiXSxcImNvbnRyb2xcIjpbXCJzdWJzY3JpYmVcIl19IiwieC1hYmx5LWNsaWVudElkIjoiY2xpZW50SWQiLCJleHAiOjE1ODM3ODcxMjQsImlhdCI6IjE1ODM3ODM1MjQifQ'; + +export const decodedJwtPayloadSample = { + orgId: '12138ac1-092f-32e7-ba78-12395d4a9634', + envId: '86b0d3a0-5f54-32e7-22f9-01150fa9fa3a', + ['x-ably-capability']: '{"NzM2MDI5Mzc0_MzQyODU4NDUyNg==_segments":["subscribe"],"NzM2MDI5Mzc0_MzQyODU4NDUyNg==_splits":["subscribe"],"control":["subscribe"]}', + ['x-ably-clientId']: 'clientId', + exp: 1583787124, + iat: 1583783524, +}; + +export const decodedJwtHeadersSample = { + alg: 'HS256', + kid: 'keyId', + typ: 'JWT', +}; + +export const parsedChannelsSample = { + 'NzM2MDI5Mzc0_MzQyODU4NDUyNg==_segments': ['subscribe'], + 'NzM2MDI5Mzc0_MzQyODU4NDUyNg==_splits': ['subscribe'], + 'control': ['subscribe'] +}; + +export const base64sample = 'ZW1pQHNwbGl0Lmlv'; + +export const decodedBase64sample = 'emi@split.io'; + +export const authDataResponseSample = { + pushEnabled: true, + token: jwtSample, +}; + +export const authDataSample = { + ...authDataResponseSample, + decodedToken: decodedJwtPayloadSample, + channels: parsedChannelsSample, +}; + +export const userKeySample = 'emi@split.io'; + +export const userKeyBase64HashSample = 'MjAxNjU2NDU5Mw=='; + +export const channelsQueryParamSample = 'NzM2MDI5Mzc0_MzQyODU4NDUyNg%3D%3D_segments,NzM2MDI5Mzc0_MzQyODU4NDUyNg%3D%3D_splits,control'; + +export const keylists = [ + { + compression: 1, // GZIP + keyListDataCompressed: 'H4sIAAAAAAAA/wTAsRHDUAgD0F2ofwEIkPAqPhdZIW0uu/v97GPXHU004ULuMGrYR6XUbIjlXULPPse+dt1yhJibBODjrTmj3GJ4emduuDDP/w0AAP//18WLsl0AAAA=', + keyListData: { a: ['1573573083296714675', '8482869187405483569'], r: ['8031872927333060586', '6829471020522910836'] }, + addedUserKeys: ['key1', 'key2'], + removedUserKeys: ['key3', 'key4'], + otherUserKeys: ['key5', 'key6'] + } +]; + +export const bitmaps = [ + { + compression: 1, // GZIP + bitmapDataCompressed: 'H4sIAAAAAAAA/2JABxzYeIxQLguYFIBLN8Bl4EABjc+EzOnAsA4QAAD//8YBvWeAAAAA', + bitmapData: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + trueUserKeys: [ + '88f8b33b-f858-4aea-bea2-a5f066bab3ce', + '603516ce-1243-400b-b919-0dce5d8aecfd', + '4588c4f6-3d18-452a-bc4a-47d7abfd23df', + '42bcfe02-d268-472f-8ed5-e6341c33b4f7', + '4b0b0467-3fe1-43d1-a3d5-937c0a5473b1', + '2a7cae0e-85a2-443e-9d7c-7157b7c5960a', + '18c936ad-0cd2-490d-8663-03eaa23a5ef1', + '09025e90-d396-433a-9292-acef23cf0ad1', + 'bfd4a824-0cde-4f11-9700-2b4c5ad6f719', + '2b79d5df-b65a-d25d-75d7-05877f69d976', + '375903c8-6f62-4272-88f1-f8bcd304c7ae' + ], + falseUserKeys: [ + '88f8b33b-f858-4aea-bea2-a5f066bab3c0', + '603516ce-1243-400b-b919-0dce5d8aecf0', + '4588c4f6-3d18-452a-bc4a-47d7abfd23d0', + '42bcfe02-d268-472f-8ed5-e6341c33b4fc', + '4b0b0467-3fe1-43d1-a3d5-937c0a5473b5', + '2a7cae0e-85a2-443e-9d7c-7157b7c59606', + '18c936ad-0cd2-490d-8663-03eaa23a5ef0', + '09025e90-d396-433a-9292-acef23cf0ad0', + 'bfd4a824-0cde-4f11-9700-2b4c5ad6f710', + '2b79d5df-b65a-d25d-75d7-05877f69d970', + '375903c8-6f62-4272-88f1-f8bcd304c7a1' + ] + }, { + compression: 2, // ZLIB + bitmapDataCompressed: 'eJxiGAX4AMdAO2AU4AeMA+2AAQACA+0AuoORGMvDBDANtAPoDBQG2gGDGQz16pRloB0wCkbBKBgFo4As0EBYyZCqoojwDwEACAAA//+W/QFR', + trueUserKeys: [ + '88f8b33b-f858-4aea-bea2-a5f066bab3ce', + '603516ce-1243-400b-b919-0dce5d8aecfd', + '4588c4f6-3d18-452a-bc4a-47d7abfd23df', + '42bcfe02-d268-472f-8ed5-e6341c33b4f7', + '4b0b0467-3fe1-43d1-a3d5-937c0a5473b1', + '2a7cae0e-85a2-443e-9d7c-7157b7c5960a', + '18c936ad-0cd2-490d-8663-03eaa23a5ef1', + '09025e90-d396-433a-9292-acef23cf0ad1', + 'bfd4a824-0cde-4f11-9700-2b4c5ad6f719', + '2b79d5df-b65a-d25d-75d7-05877f69d976', + '375903c8-6f62-4272-88f1-f8bcd304c7ae' + ], + falseUserKeys: [ + '88f8b33b-f858-4aea-bea2-a5f066bab3c1', + '603516ce-1243-400b-b919-0dce5d8aecf2', + '4588c4f6-3d18-452a-bc4a-47d7abfd23d3', + '42bcfe02-d268-472f-8ed5-e6341c33b4f4', + '4b0b0467-3fe1-43d1-a3d5-937c0a5473b5', + '2a7cae0e-85a2-443e-9d7c-7157b7c59606', + '18c936ad-0cd2-490d-8663-03eaa23a5ef7', + '09025e90-d396-433a-9292-acef23cf0ad8', + 'bfd4a824-0cde-4f11-9700-2b4c5ad6f710', + '2b79d5df-b65a-d25d-75d7-05877f69d97a', + '375903c8-6f62-4272-88f1-f8bcd304c7ab' + ] + }, { + compression: 2, // ZLIB + bitmapDataCompressed: 'eJzMVk3OhDAIVdNFl9/22zVzEo8yR5mjT6LGsRTKg2LiW8yPUnjQB+2kIwM2ThTIKtVU1oknFcRzufz+YGYM/phnHW8sdPvs9EzXW2I+HFzhNyTNgCD/PpW9xpGiHD0Bw1U5HLSS644FbGZgoPovmjpmX5wAzhIxJyN7IAnFQWX1htj+LUl6ZQRV3umMqYG1LCrOJGLPV8+IidBQZFt6sOUA6CqsX5iEFY2gqufs2mfqRtsVWytRnO+iYMN7xIBqJhDqAydV+HidkGOGEJYvk4fhe/8iIukphG/XfFcfVxnMVcALCOF77qL/EU7ODepxlLST6qxFLYRdOyW8EBY4BqVjObnm3V5ZMkZIKf++8+hM7zM1Kd3aFqVZeSHzDQAA//+QUQ3a', + trueUserKeys: [ + 'user1', + 'user2', + 'user3', + 'user4', + 'user5', + 'user6', + 'user7', + 'user8', + 'user9', + 'user10', + 'user11', + 'user12', + 'user13', + 'user14', + 'user15', + 'user16', + 'user17', + 'user18', + 'user19', + 'user20', + 'user21', + 'user22', + 'user23', + 'user24', + 'user25', + 'user26', + 'user27', + 'user28', + 'user29', + 'user30', + 'user31', + 'user32', + 'user33', + 'user34', + 'user35', + 'user36', + 'user37', + 'user38', + 'user39', + 'user40', + 'user41', + 'user42', + 'user43', + 'user44', + 'user45', + 'user46', + 'user47', + 'user48', + 'user49', + 'user50', + 'user51', + 'user52', + 'user53', + 'user54', + 'user55', + 'user56', + 'user57', + 'user58', + 'user59', + 'user60', + 'user61', + 'user62', + 'user63', + 'user64', + 'user65', + 'user66', + 'user67', + 'user68', + 'user69', + 'user70', + 'user71', + 'user72', + 'user73', + 'user74', + 'user75', + 'user76', + 'user77', + 'user78', + 'user79', + 'user80', + 'user81', + 'user82', + 'user83', + 'user84', + 'user85', + 'user86', + 'user87', + 'user88', + 'user89', + 'user90', + 'user91', + 'user92', + 'user93', + 'user94', + 'user95', + 'user96', + 'user97', + 'user98', + 'user99', + 'user100', + 'user101', + 'user102', + 'user103', + 'user104', + 'user105', + 'user106', + 'user107', + 'user108', + 'user109', + 'user110', + 'user111', + 'user112', + 'user113', + 'user114', + 'user115', + 'user116', + 'user117', + 'user118', + 'user119', + 'user120', + ], + falseUserKeys: [ + 'user', + 'user0', + 'user121', + 'user122', + ] + } +]; diff --git a/src/sync/streaming/__tests__/mySegmentsV2utils.spec.ts b/src/sync/streaming/__tests__/mySegmentsV2utils.spec.ts new file mode 100644 index 00000000..b2826848 --- /dev/null +++ b/src/sync/streaming/__tests__/mySegmentsV2utils.spec.ts @@ -0,0 +1,53 @@ +import { hash64 } from '../../../utils/murmur3/murmur3_64'; +import { keylists, bitmaps } from './dataMocks'; + +import { parseKeyList, parseBitmap, isInBitmap } from '../mySegmentsV2utils'; +import { _Set } from '../../../utils/lang/sets'; + +test('parseKeyList', () => { + keylists.forEach(keylist => { + const { compression, keyListData, keyListDataCompressed, addedUserKeys, removedUserKeys, otherUserKeys } = keylist; + + expect(parseKeyList(keyListDataCompressed, compression)).toEqual(keyListData); // decompress KeyList + + const added = new _Set(keyListData.a); + const removed = new _Set(keyListData.r); + + addedUserKeys.forEach(userKey => { + const hash = hash64(userKey); + expect(added.has(hash.dec)).toBe(true); // key hash belongs to added list + expect(removed.has(hash.dec)).toBe(false); // t belong to removed list + }); + + removedUserKeys.forEach(userKey => { + const hash = hash64(userKey); + expect(added.has(hash.dec)).toBe(false); // t belong to added list + expect(removed.has(hash.dec)).toBe(true); // key hash belongs to removed list + }); + + otherUserKeys.forEach(userKey => { + const hash = hash64(userKey); + expect(added.has(hash.dec)).toBe(false); // t belong to added list + expect(removed.has(hash.dec)).toBe(false); // t belong to removed list + }); + }); +}); + +test('parseBitmap & isInBitmap', () => { + bitmaps.forEach(bitmap => { + const { compression, bitmapData, bitmapDataCompressed, trueUserKeys, falseUserKeys } = bitmap; + + const actualBitmap = parseBitmap(bitmapDataCompressed, compression); + if (bitmapData) expect(actualBitmap).toEqual(bitmapData); // decompress Bitmap + + trueUserKeys.forEach(userKey => { + const hash = hash64(userKey); + expect(isInBitmap(actualBitmap, hash.hex)).toBe(true); // key hash belongs to Bitmap + }); + + falseUserKeys.forEach(userKey => { + const hash = hash64(userKey); + expect(isInBitmap(actualBitmap, hash.hex)).toBe(false); // t belong to Bitmap + }); + }); +}); diff --git a/src/sync/streaming/__tests__/pushManager.spec.ts b/src/sync/streaming/__tests__/pushManager.spec.ts new file mode 100644 index 00000000..9b6fb784 --- /dev/null +++ b/src/sync/streaming/__tests__/pushManager.spec.ts @@ -0,0 +1,36 @@ +import pushManagerFactory from '../pushManager'; +import EventEmitter from '../../../utils/MinEvents'; +import { fullSettings } from '../../../utils/settingsValidation/__tests__/settings.mocks'; +import { IPushManagerCS } from '../types'; + +const platformMock = { + getEventSource: jest.fn(() => { return () => { }; }), + EventEmitter +}; + +test('pushManagerFactory returns undefined if EventSource is not available', () => { + // @ts-ignore + const pushManager = pushManagerFactory({}, {}, {}, () => { }, { + getEventSource: () => undefined, + EventEmitter + }, fullSettings); + + expect(pushManager).toBe(undefined); +}); + +test('pushManager does not connect to streaming if it is stopped inmediatelly after being started', (done) => { + const fetchAuthMock = jest.fn(); + + // @ts-ignore + const pushManager = pushManagerFactory({}, {}, {}, fetchAuthMock, platformMock, fullSettings) as IPushManagerCS; + + pushManager.start(); + pushManager.start(); + pushManager.stop(); + pushManager.stop(); + + setTimeout(() => { + expect(fetchAuthMock).not.toBeCalled(); + done(); + }); +}); diff --git a/src/sync/streaming/constants.ts b/src/sync/streaming/constants.ts index 8b69840d..8afb41a6 100644 --- a/src/sync/streaming/constants.ts +++ b/src/sync/streaming/constants.ts @@ -26,6 +26,7 @@ export const PUSH_SUBSYSTEM_DOWN = 'PUSH_SUBSYSTEM_DOWN'; // Update-type push notifications, handled by NotificationProcessor export const MY_SEGMENTS_UPDATE = 'MY_SEGMENTS_UPDATE'; +export const MY_SEGMENTS_UPDATE_V2 = 'MY_SEGMENTS_UPDATE_V2'; export const SEGMENT_UPDATE = 'SEGMENT_UPDATE'; export const SPLIT_KILL = 'SPLIT_KILL'; export const SPLIT_UPDATE = 'SPLIT_UPDATE'; @@ -38,4 +39,5 @@ export enum ControlType { STREAMING_DISABLED = 'STREAMING_DISABLED', STREAMING_PAUSED = 'STREAMING_PAUSED', STREAMING_RESUMED = 'STREAMING_RESUMED', + STREAMING_RESET = 'STREAMING_RESET', } diff --git a/src/sync/streaming/mySegmentsV2utils.ts b/src/sync/streaming/mySegmentsV2utils.ts new file mode 100644 index 00000000..df3adff6 --- /dev/null +++ b/src/sync/streaming/mySegmentsV2utils.ts @@ -0,0 +1,77 @@ +import { algorithms } from '../../utils/decompress'; +import { decodeFromBase64 } from '../../utils/base64'; +import { Compression, KeyList } from './SSEHandler/types'; + +const GZIP = 1; +const ZLIB = 2; + +function Uint8ArrayToString(myUint8Arr: Uint8Array) { // @ts-ignore + return String.fromCharCode.apply(null, myUint8Arr); +} + +function StringToUint8Array(myString: string) { + const charCodes = myString.split('').map((e) => e.charCodeAt(0)); + return new Uint8Array(charCodes); +} + +/** + * Decode and decompress 'data' with 'compression' algorithm + * + * @param {string} data + * @param {number} compression 1 GZIP, 2 ZLIB + * @returns {Uint8Array} + * @throws if data string cannot be decoded, decompressed or the provided compression value is invalid (not 1 or 2) + */ +function decompress(data: string, compression: Compression) { + let compressData = decodeFromBase64(data); + const binData = StringToUint8Array(compressData); + + if (typeof algorithms === 'string') throw new Error(algorithms); + if (compression === GZIP) return algorithms.gunzipSync(binData); + if (compression === ZLIB) return algorithms.unzlibSync(binData); + throw new Error(`Invalid compression algorithm #${compression}`); +} + +/** + * Decode, decompress and parse the provided 'data' into a KeyList object + * + * @param {string} data + * @param {number} compression + * @returns {{a?: string[], r?: string[] }} + * @throws if data string cannot be decoded, decompressed or parsed + */ +export function parseKeyList(data: string, compression: Compression): KeyList { + const binKeyList = decompress(data, compression); + const strKeyList = Uint8ArrayToString(binKeyList); + + // replace numbers to strings, to avoid losing precision + return JSON.parse(strKeyList.replace(/\d+/g, '"$&"')); +} + +/** + * Decode, decompress and parse the provided 'data' into a Bitmap object + * + * @param {string} data + * @param {number} compression + * @returns {Uint8Array} + * @throws if data string cannot be decoded or decompressed + */ +export function parseBitmap(data: string, compression: Compression) { + return decompress(data, compression); +} + +/** + * Check if the 'bitmap' bit at 'hash64hex' position is 1 + * + * @param {Uint8Array} bitmap + * @param {string} hash64hex 16-chars string, representing a number in hexa + * @returns {boolean} + */ +export function isInBitmap(bitmap: Uint8Array, hash64hex: string) { + // using the lowest 32 bits as index, to avoid losing precision when converting to number + const index = parseInt(hash64hex.slice(8), 16) % (bitmap.length * 8); + + const internal = Math.floor(index / 8); + const offset = index % 8; + return (bitmap[internal] & 1 << offset) > 0; +} diff --git a/src/sync/streaming/pushManager.ts b/src/sync/streaming/pushManager.ts index 0e7f1559..e7b7caac 100644 --- a/src/sync/streaming/pushManager.ts +++ b/src/sync/streaming/pushManager.ts @@ -3,7 +3,6 @@ import { ISSEClient } from './SSEClient/types'; import { IStorageSync } from '../../storages/types'; import { IReadinessManager } from '../../readiness/types'; import { ISegmentsSyncTask, IPollingManager } from '../polling/types'; -import { IUpdateWorker } from './UpdateWorkers/types'; import objectAssign from 'object-assign'; import Backoff from '../../utils/Backoff'; import SSEHandlerFactory from './SSEHandler'; @@ -16,9 +15,14 @@ import SSEClient from './SSEClient'; import { IFetchAuth } from '../../services/types'; import { ISettings } from '../../types'; import { getMatching } from '../../utils/key'; -import { MY_SEGMENTS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP } from './constants'; +import { MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType } from './constants'; import { IPlatform } from '../../sdkFactory/types'; -import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT } from '../../logger/constants'; +import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2 } from '../../logger/constants'; +import { KeyList, UpdateStrategy } from './SSEHandler/types'; +import { isInBitmap, parseBitmap, parseKeyList } from './mySegmentsV2utils'; +import { ISet, _Set } from '../../utils/lang/sets'; +import { Hash64, hash64 } from '../../utils/murmur3/murmur3_64'; +import { IAuthTokenPushEnabled } from './AuthClient/types'; /** * PushManager factory: @@ -34,11 +38,15 @@ export default function pushManagerFactory( settings: ISettings, ): IPushManagerCS | undefined { + // `userKey` is the matching key of main client in client-side SDK. + // It can be used to check if running on client-side or server-side SDK. + const userKey = settings.core.key ? getMatching(settings.core.key) : undefined; // const log = settings.log; let sseClient: ISSEClient; try { - sseClient = new SSEClient(settings.urls.streaming, platform.getEventSource); + // `useHeaders` false for client-side, even if the platform EventSource supports headers (e.g., React Native). + sseClient = new SSEClient(settings, userKey ? false : true, platform.getEventSource); } catch (e) { log.warn(STREAMING_FALLBACK, [e]); return; @@ -50,54 +58,67 @@ export default function pushManagerFactory( const sseHandler = SSEHandlerFactory(log, pushEmitter); sseClient.setEventHandler(sseHandler); + // init workers + const segmentsUpdateWorker = userKey ? new MySegmentsUpdateWorker(pollingManager.segmentsSyncTask) : new SegmentsUpdateWorker(storage.segments, pollingManager.segmentsSyncTask); + // For server-side we pass the segmentsSyncTask, used by SplitsUpdateWorker to fetch new segments + const splitsUpdateWorker = new SplitsUpdateWorker(storage.splits, pollingManager.splitsSyncTask, readiness.splits, userKey ? undefined : pollingManager.segmentsSyncTask); + // [Only for client-side] map of hashes to user keys, to dispatch MY_SEGMENTS_UPDATE events to the corresponding MySegmentsUpdateWorker const userKeyHashes: Record = {}; - const userKey = settings.core.key ? getMatching(settings.core.key) : undefined; // matching key of main client + // [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers. + // Hash64 is used to process MY_SEGMENTS_UPDATE_V2 events and dispatch actions to the corresponding MySegmentsUpdateWorker. + const clients: Record = {}; if (userKey) { const hash = hashUserKey(userKey); userKeyHashes[hash] = userKey; + clients[userKey] = { hash64: hash64(userKey), worker: segmentsUpdateWorker as MySegmentsUpdateWorker }; } - // [Only for client-side] map of user keys to their corresponding MySegmentsUpdateWorkers. It has a two-fold intention: - // - stop workers all together when push is disconnected - // - keep the current list of user keys to authenticate - const workers: Record = {}; - - // init workers - const segmentsUpdateWorker = userKey ? new MySegmentsUpdateWorker(pollingManager.segmentsSyncTask) : new SegmentsUpdateWorker(storage.segments, pollingManager.segmentsSyncTask); - if (userKey) workers[userKey] = segmentsUpdateWorker; - const splitsUpdateWorker = new SplitsUpdateWorker(storage.splits, pollingManager.splitsSyncTask, readiness.splits); - // [Only for client-side] variable to flag that a new client was added. It is needed to reconnect streaming. let connectForNewClient = false; - // flag that indicates if `disconnectPush` was called, either by the SyncManager (when the client is destroyed) or by a PUSH_NONRETRYABLE_ERROR error. + // flag that indicates if `stop/disconnectPush` was called, either by the SyncManager, when the client is destroyed, or due to a PUSH_NONRETRYABLE_ERROR error. // It is used to halt the `connectPush` process if it was in progress. let disconnected: boolean | undefined; + // flag that indicates a PUSH_NONRETRYABLE_ERROR, condition with which starting pushManager again is ignored. + let disabled: boolean | undefined; // `disabled` implies `disconnected === true` /** PushManager functions related to initialization */ const connectPushRetryBackoff = new Backoff(connectPush, settings.scheduler.pushRetryBackoffBase); - let timeoutId: ReturnType; + let timeoutIdTokenRefresh: ReturnType; + let timeoutIdSseOpen: ReturnType; - function scheduleTokenRefresh(issuedAt: number, expirationTime: number) { - // clear scheduled token refresh if exists (needed when resuming PUSH) - if (timeoutId) clearTimeout(timeoutId); + function scheduleTokenRefreshAndSse(authData: IAuthTokenPushEnabled) { + // clear scheduled tasks if exist + if (timeoutIdTokenRefresh) clearTimeout(timeoutIdTokenRefresh); + if (timeoutIdSseOpen) clearTimeout(timeoutIdSseOpen); - // Set token refresh 10 minutes before expirationTime - const delayInSeconds = expirationTime - issuedAt - SECONDS_BEFORE_EXPIRATION; + // Set token refresh 10 minutes before `expirationTime - issuedAt` + const decodedToken = authData.decodedToken; + const refreshTokenDelay = decodedToken.exp - decodedToken.iat - SECONDS_BEFORE_EXPIRATION; + // Default connDelay of 60 secs + const connDelay = typeof authData.connDelay === 'number' && authData.connDelay >= 0 ? authData.connDelay : 60; - log.info(STREAMING_REFRESH_TOKEN, [delayInSeconds]); + log.info(STREAMING_REFRESH_TOKEN, [refreshTokenDelay, connDelay]); - timeoutId = setTimeout(connectPush, delayInSeconds * 1000); + timeoutIdTokenRefresh = setTimeout(connectPush, refreshTokenDelay * 1000); + + timeoutIdSseOpen = setTimeout(() => { + // halt if disconnected + if (disconnected) return; + sseClient.open(authData); + }, connDelay * 1000); } function connectPush() { + // Guard condition in case `stop/disconnectPush` has been called (e.g., calling SDK destroy, or app signal close/background) + if (disconnected) return; + log.info(STREAMING_CONNECTING, [disconnected === undefined ? '' : 'Re-']); disconnected = false; - log.info(STREAMING_CONNECTING); - const userKeys = userKey ? Object.keys(workers) : undefined; + const userKeys = userKey ? Object.keys(clients) : undefined; authenticate(userKeys).then( function (authData) { if (disconnected) return; @@ -111,12 +132,10 @@ export default function pushManagerFactory( } // [Only for client-side] don't open SSE connection if a new shared client was added, since it means that a new authentication is taking place - if (userKeys && userKeys.length < Object.keys(workers).length) return; + if (userKeys && userKeys.length < Object.keys(clients).length) return; - // Connect to SSE and schedule refresh token - const decodedToken = authData.decodedToken; - sseClient.open(authData); - scheduleTokenRefresh(decodedToken.iat, decodedToken.exp); + // Schedule SSE connection and refresh token + scheduleTokenRefreshAndSse(authData); } ).catch( function (error) { @@ -138,11 +157,15 @@ export default function pushManagerFactory( // close SSE connection and cancel scheduled tasks function disconnectPush() { + // Halt disconnecting, just to avoid redundant logs if called multiple times + if (disconnected) return; disconnected = true; - log.info(STREAMING_DISCONNECTING); + sseClient.close(); + log.info(STREAMING_DISCONNECTING); - if (timeoutId) clearTimeout(timeoutId); + if (timeoutIdTokenRefresh) clearTimeout(timeoutIdTokenRefresh); + if (timeoutIdSseOpen) clearTimeout(timeoutIdSseOpen); connectPushRetryBackoff.reset(); stopWorkers(); @@ -151,18 +174,23 @@ export default function pushManagerFactory( // cancel scheduled fetch retries of Splits, Segments, and MySegments Update Workers function stopWorkers() { splitsUpdateWorker.backoff.reset(); - if (userKey) forOwn(workers, worker => worker.backoff.reset()); + if (userKey) forOwn(clients, ({ worker }) => worker.backoff.reset()); else segmentsUpdateWorker.backoff.reset(); } pushEmitter.on(PUSH_SUBSYSTEM_DOWN, stopWorkers); - // restart backoff retry counter once push is connected - pushEmitter.on(PUSH_SUBSYSTEM_UP, () => { connectPushRetryBackoff.reset(); }); + // Only required when streaming connects after a PUSH_RETRYABLE_ERROR. + // Otherwise it is unnecessary (e.g, STREAMING_RESUMED). + pushEmitter.on(PUSH_SUBSYSTEM_UP, () => { + connectPushRetryBackoff.reset(); + stopWorkers(); + }); /** Fallbacking without retry due to: STREAMING_DISABLED control event, or 'pushEnabled: false', or non-recoverable SSE and Authentication errors */ pushEmitter.on(PUSH_NONRETRYABLE_ERROR, function handleNonRetryableError() { + disabled = true; // Note: `stopWorkers` is been called twice, but it is not harmful disconnectPush(); pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already @@ -182,21 +210,93 @@ export default function pushManagerFactory( pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already }); + /** STREAMING_RESET notification. Unlike a PUSH_RETRYABLE_ERROR, it doesn't emit PUSH_SUBSYSTEM_DOWN to fallback polling */ + + pushEmitter.on(ControlType.STREAMING_RESET, function handleStreamingReset() { + if (disconnected) return; // should never happen + + // Minimum required clean-up. + // `disconnectPush` cannot be called because it sets `disconnected` and thus `connectPush` will not execute + if (timeoutIdTokenRefresh) clearTimeout(timeoutIdTokenRefresh); + + connectPush(); + }); + /** Functions related to synchronization (Queues and Workers in the spec) */ pushEmitter.on(SPLIT_KILL, splitsUpdateWorker.killSplit); pushEmitter.on(SPLIT_UPDATE, splitsUpdateWorker.put); + if (userKey) { pushEmitter.on(MY_SEGMENTS_UPDATE, function handleMySegmentsUpdate(parsedData, channel) { const userKeyHash = channel.split('_')[2]; const userKey = userKeyHashes[userKeyHash]; - if (userKey && workers[userKey]) { // check context since it can be undefined if client has been destroyed - const mySegmentsUpdateWorker = workers[userKey]; - mySegmentsUpdateWorker.put( + if (userKey && clients[userKey]) { // check existence since it can be undefined if client has been destroyed + clients[userKey].worker.put( parsedData.changeNumber, parsedData.includesPayload ? parsedData.segmentList ? parsedData.segmentList : [] : undefined); } }); + pushEmitter.on(MY_SEGMENTS_UPDATE_V2, function handleMySegmentsUpdate(parsedData) { + switch (parsedData.u) { + case UpdateStrategy.BoundedFetchRequest: { + let bitmap: Uint8Array; + try { + bitmap = parseBitmap(parsedData.d, parsedData.c); + } catch (e) { + log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['BoundedFetchRequest', e]); + break; + } + + forOwn(clients, ({ hash64, worker }) => { + if (isInBitmap(bitmap, hash64.hex)) { + worker.put(parsedData.changeNumber); // fetch mySegments + } + }); + return; + } + case UpdateStrategy.KeyList: { + let keyList: KeyList, added: ISet, removed: ISet; + try { + keyList = parseKeyList(parsedData.d, parsedData.c); + added = new _Set(keyList.a); + removed = new _Set(keyList.r); + } catch (e) { + log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['KeyList', e]); + break; + } + + forOwn(clients, ({ hash64, worker }) => { + const add = added.has(hash64.dec) ? true : removed.has(hash64.dec) ? false : undefined; + if (add !== undefined) { + worker.put(parsedData.changeNumber, { + name: parsedData.segmentName, + add + }); + } + }); + return; + } + case UpdateStrategy.SegmentRemoval: + if (!parsedData.segmentName) { + log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['SegmentRemoval', 'No segment name was provided']); + break; + } + + forOwn(clients, ({ worker }) => + worker.put(parsedData.changeNumber, { + name: parsedData.segmentName, + add: false + }) + ); + return; + } + + // `UpdateStrategy.UnboundedFetchRequest` and fallbacks of other cases + forOwn(clients, ({ worker }) => { + worker.put(parsedData.changeNumber); + }); + }); } else { pushEmitter.on(SEGMENT_UPDATE, (segmentsUpdateWorker as SegmentsUpdateWorker).put); } @@ -206,17 +306,19 @@ export default function pushManagerFactory( Object.create(pushEmitter), { // Expose functionality for starting and stoping push mode: - stop: disconnectPush, // `handleNonRetryableError` cannot be used as `stop`, because it emits PUSH_SUBSYSTEM_DOWN event, which start polling. + stop: disconnectPush, // `handleNonRetryableError` cannot be used as `stop`, because it emits PUSH_SUBSYSTEM_DOWN event, which starts polling. start() { + // Guard condition to avoid calling `connectPush` again if the `start` method is called multiple times or if push has been disabled. + if (disabled || disconnected === false) return; + disconnected = false; // Run in next event-loop cycle for optimization on client-side: if multiple clients are created in the same cycle than the factory, only one authentication is performed. setTimeout(connectPush); }, // [Only for client-side] add(userKey: string, mySegmentsSyncTask: ISegmentsSyncTask) { - const mySegmentsUpdateWorker = new MySegmentsUpdateWorker(mySegmentsSyncTask); - workers[userKey] = mySegmentsUpdateWorker; + clients[userKey] = { hash64: hash64(userKey), worker: new MySegmentsUpdateWorker(mySegmentsSyncTask) }; const hash = hashUserKey(userKey); @@ -239,6 +341,7 @@ export default function pushManagerFactory( remove(userKey: string) { const hash = hashUserKey(userKey); delete userKeyHashes[hash]; + delete clients[userKey]; } } ); diff --git a/src/sync/streaming/pushManagerCS.ts b/src/sync/streaming/pushManagerCS.ts deleted file mode 100644 index 5611eaa0..00000000 --- a/src/sync/streaming/pushManagerCS.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { IPushEventEmitter, IPushManagerCS } from './types'; -import { ISSEClient } from './SSEClient/types'; -import { IStorageSync } from '../../storages/types'; -import { IReadinessManager } from '../../readiness/types'; -import { ISegmentsSyncTask, IPollingManager } from '../polling/types'; -import { IUpdateWorker } from './UpdateWorkers/types'; -import objectAssign from 'object-assign'; -import { MY_SEGMENTS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP } from './constants'; -import Backoff from '../../utils/Backoff'; -import SSEHandlerFactory from './SSEHandler'; -import MySegmentsUpdateWorker from './UpdateWorkers/MySegmentsUpdateWorker'; -import SplitsUpdateWorker from './UpdateWorkers/SplitsUpdateWorker'; -import { authenticateFactory, hashUserKey } from './AuthClient'; -import { forOwn } from '../../utils/lang'; -import SSEClient from './SSEClient'; -import { IFetchAuth } from '../../services/types'; -import { ISettings } from '../../types'; -import { getMatching } from '../../utils/key'; -import { IPlatform } from '../../sdkFactory/types'; -import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT } from '../../logger/constants'; - -/** - * PushManager factory for client-side, with support for multiple clients. - * It assumes settings contains a key. - */ -export default function pushManagerCSFactory( - pollingManager: IPollingManager, - storage: IStorageSync, - readiness: IReadinessManager, - fetchAuth: IFetchAuth, - platform: IPlatform, - settings: ISettings -): IPushManagerCS | undefined { - - const log = settings.log; - - let sseClient: ISSEClient; - try { - sseClient = new SSEClient(settings.urls.streaming, platform.getEventSource); - } catch (e) { - log.warn(STREAMING_FALLBACK, [e]); - return; - } - const authenticate = authenticateFactory(fetchAuth); - - // init feedback loop - const pushEmitter = new platform.EventEmitter() as IPushEventEmitter; - const sseHandler = SSEHandlerFactory(log, pushEmitter); - sseClient.setEventHandler(sseHandler); - - // [Only for client-side] map of hashes to user keys, to dispatch MY_SEGMENTS_UPDATE events to the corresponding MySegmentsUpdateWorker - const userKeyHashes: Record = {}; - const userKey = getMatching(settings.core.key); // matching key of main client - const hash = hashUserKey(userKey); - userKeyHashes[hash] = userKey; - - // [Only for client-side] map of user keys to their corresponding MySegmentsUpdateWorkers. It has a two-fold intention: - // - stop workers all together when push is disconnected - // - keep the current list of user keys to authenticate - const workers: Record = {}; - - // init workers - const mySegmentsUpdateWorker = new MySegmentsUpdateWorker(pollingManager.segmentsSyncTask); - workers[userKey] = mySegmentsUpdateWorker; - const splitsUpdateWorker = new SplitsUpdateWorker(storage.splits, pollingManager.splitsSyncTask, readiness.splits); - - // [Only for client-side] variable to flag that a new client was added. It is needed to reconnect streaming. - let connectForNewClient = false; - - // flag that indicates if `disconnectPush` was called, either by the SyncManager (when the client is destroyed) or by a PUSH_NONRETRYABLE_ERROR error. - // It is used to halt the `connectPush` process if it was in progress. - let disconnected: boolean | undefined; - - /** PushManager functions related to initialization */ - - const connectPushRetryBackoff = new Backoff(connectPush, settings.scheduler.pushRetryBackoffBase); - - let timeoutId: ReturnType; - - function scheduleTokenRefresh(issuedAt: number, expirationTime: number) { - // clear scheduled token refresh if exists (needed when resuming PUSH) - if (timeoutId) clearTimeout(timeoutId); - - // Set token refresh 10 minutes before expirationTime - const delayInSeconds = expirationTime - issuedAt - SECONDS_BEFORE_EXPIRATION; - - log.info(STREAMING_REFRESH_TOKEN, [delayInSeconds]); - - timeoutId = setTimeout(connectPush, delayInSeconds * 1000); - } - - function connectPush() { - disconnected = false; - log.info(STREAMING_CONNECTING); - - const userKeys = Object.keys(workers); // [Only for client-side] - authenticate(userKeys).then( - function (authData) { - if (disconnected) return; - - // 'pushEnabled: false' is handled as a PUSH_NONRETRYABLE_ERROR instead of PUSH_SUBSYSTEM_DOWN, in order to - // close the sseClient in case the org has been bloqued while the instance was connected to streaming - if (!authData.pushEnabled) { - log.info(STREAMING_DISABLED); - pushEmitter.emit(PUSH_NONRETRYABLE_ERROR); - return; - } - - // [Only for client-side] don't open SSE connection if a new shared client was added, since it means that a new authentication is taking place - if (userKeys && userKeys.length < Object.keys(workers).length) return; - - // Connect to SSE and schedule refresh token - const decodedToken = authData.decodedToken; - sseClient.open(authData); - scheduleTokenRefresh(decodedToken.iat, decodedToken.exp); - } - ).catch( - function (error) { - if (disconnected) return; - - log.error(ERROR_STREAMING_AUTH, [error.message]); - - // Handle 4XX HTTP errors: 401 (invalid API Key) or 400 (using incorrect API Key, i.e., client-side API Key on server-side) - if (error.statusCode >= 400 && error.statusCode < 500) { - pushEmitter.emit(PUSH_NONRETRYABLE_ERROR); - return; - } - - // Handle other HTTP and network errors as recoverable errors - pushEmitter.emit(PUSH_RETRYABLE_ERROR); - } - ); - } - - // close SSE connection and cancel scheduled tasks - function disconnectPush() { - disconnected = true; - log.info(STREAMING_DISCONNECTING); - sseClient.close(); - - if (timeoutId) clearTimeout(timeoutId); - connectPushRetryBackoff.reset(); - - stopWorkers(); - } - - // cancel scheduled fetch retries of Splits, Segments, and MySegments Update Workers - function stopWorkers() { - splitsUpdateWorker.backoff.reset(); - forOwn(workers, worker => worker.backoff.reset()); - } - - pushEmitter.on(PUSH_SUBSYSTEM_DOWN, stopWorkers); - - // restart backoff retry counter once push is connected - pushEmitter.on(PUSH_SUBSYSTEM_UP, () => { connectPushRetryBackoff.reset(); }); - - /** Fallbacking without retry due to: STREAMING_DISABLED control event, or 'pushEnabled: false', or non-recoverable SSE and Authentication errors */ - - pushEmitter.on(PUSH_NONRETRYABLE_ERROR, function handleNonRetryableError() { - // Note: `stopWorkers` is been called twice, but it is not harmful - disconnectPush(); - pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already - }); - - /** Fallbacking with retry due to recoverable SSE and Authentication errors */ - - pushEmitter.on(PUSH_RETRYABLE_ERROR, function handleRetryableError() { // HTTP or network error in SSE connection - // SSE connection is closed to avoid repeated errors due to retries - sseClient.close(); - - // retry streaming reconnect with backoff algorithm - let delayInMillis = connectPushRetryBackoff.scheduleCall(); - - log.info(STREAMING_RECONNECT, [delayInMillis / 1000]); - - pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already - }); - - /** Functions related to synchronization (Queues and Workers in the spec) */ - - pushEmitter.on(SPLIT_KILL, splitsUpdateWorker.killSplit); - pushEmitter.on(SPLIT_UPDATE, splitsUpdateWorker.put); - // [Only for client-side] - pushEmitter.on(MY_SEGMENTS_UPDATE, function handleMySegmentsUpdate(parsedData, channel) { - const userKeyHash = channel.split('_')[2]; - const userKey = userKeyHashes[userKeyHash]; - if (userKey && workers[userKey]) { // check context since it can be undefined if client has been destroyed - const mySegmentsUpdateWorker = workers[userKey]; - mySegmentsUpdateWorker.put( - parsedData.changeNumber, - parsedData.includesPayload ? parsedData.segmentList ? parsedData.segmentList : [] : undefined); - } - }); - - return objectAssign( - // Expose Event Emitter functionality and Event constants - Object.create(pushEmitter), - { - // Expose functionality for starting and stoping push mode: - stop: disconnectPush, // `handleNonRetryableError` cannot be used as `stop`, because it emits PUSH_SUBSYSTEM_DOWN event, which start polling. - - start() { - // Run in next event-loop cycle for optimization: if multiple clients are created in the same cycle than the factory, only one authentication is performed. - setTimeout(connectPush); - }, - - // [Only for client-side] - add(userKey: string, mySegmentsSyncTask: ISegmentsSyncTask) { - const mySegmentsUpdateWorker = new MySegmentsUpdateWorker(mySegmentsSyncTask); - workers[userKey] = mySegmentsUpdateWorker; - - const hash = hashUserKey(userKey); - - if (!userKeyHashes[hash]) { - userKeyHashes[hash] = userKey; - connectForNewClient = true; // we must reconnect on start, to listen the channel for the new user key - } - - // Reconnects in case of a new client. - // Run in next event-loop cycle to save authentication calls - // in case the user is creating several clients in the current cycle. - setTimeout(function checkForReconnect() { - if (connectForNewClient) { - connectForNewClient = false; - connectPush(); - } - }, 0); - }, - // [Only for client-side] - remove(userKey: string) { - const hash = hashUserKey(userKey); - delete userKeyHashes[hash]; - } - } - ); -} diff --git a/src/sync/streaming/pushManagerSS.ts b/src/sync/streaming/pushManagerSS.ts deleted file mode 100644 index 37de7fce..00000000 --- a/src/sync/streaming/pushManagerSS.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { IPushEventEmitter, IPushManager } from './types'; -import { ISSEClient } from './SSEClient/types'; -import { IStorageSync } from '../../storages/types'; -import { IPollingManager } from '../polling/types'; -import { IReadinessManager } from '../../readiness/types'; -import objectAssign from 'object-assign'; -import { PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP } from './constants'; -import Backoff from '../../utils/Backoff'; -import SSEHandlerFactory from './SSEHandler'; -import SegmentsUpdateWorker from './UpdateWorkers/SegmentsUpdateWorker'; -import SplitsUpdateWorker from './UpdateWorkers/SplitsUpdateWorker'; -import { IFetchAuth } from '../../services/types'; -import { authenticateFactory } from './AuthClient'; -import SSEClient from './SSEClient'; -import { ISettings } from '../../types'; -import { IPlatform } from '../../sdkFactory/types'; -import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT } from '../../logger/constants'; - -/** - * PushManager factory for server-side - */ -export default function pushManagerSSFactory( - pollingManager: IPollingManager, - storage: IStorageSync, - readiness: IReadinessManager, - fetchAuth: IFetchAuth, - platform: IPlatform, - settings: ISettings -): IPushManager | undefined { - - const log = settings.log; - - let sseClient: ISSEClient; - try { - sseClient = new SSEClient(settings.urls.streaming, platform.getEventSource); - } catch (e) { - log.warn(STREAMING_FALLBACK, [e]); - return; - } - const authenticate = authenticateFactory(fetchAuth); - - // init feedback loop (pushEmitter) - const pushEmitter = new platform.EventEmitter() as IPushEventEmitter; - const sseHandler = SSEHandlerFactory(log, pushEmitter); - sseClient.setEventHandler(sseHandler); - - // init workers - const splitsUpdateWorker = new SplitsUpdateWorker(storage.splits, pollingManager.splitsSyncTask, readiness.splits); - const segmentsUpdateWorker = new SegmentsUpdateWorker(storage.segments, pollingManager.segmentsSyncTask); - - // flag that indicates if `disconnectPush` was called, either by the SyncManager (when the client is destroyed) or by a PUSH_NONRETRYABLE_ERROR error. - // It is used to halt the `connectPush` process if it was in progress. - let disconnected: boolean | undefined; - - /** PushManager functions related to initialization */ - - const connectPushRetryBackoff = new Backoff(connectPush, settings.scheduler.pushRetryBackoffBase); - - let timeoutId: ReturnType; - - function scheduleTokenRefresh(issuedAt: number, expirationTime: number) { - // clear scheduled token refresh if exists (needed when resuming PUSH) - if (timeoutId) clearTimeout(timeoutId); - - // Set token refresh 10 minutes before expirationTime - const delayInSeconds = expirationTime - issuedAt - SECONDS_BEFORE_EXPIRATION; - - log.info(STREAMING_REFRESH_TOKEN, [delayInSeconds]); - - timeoutId = setTimeout(connectPush, delayInSeconds * 1000); - } - - function connectPush() { - disconnected = false; - log.info(STREAMING_CONNECTING); - - authenticate().then( - function (authData) { - if (disconnected) return; - - // 'pushEnabled: false' is handled as a PUSH_NONRETRYABLE_ERROR instead of PUSH_SUBSYSTEM_DOWN, in order to - // close the sseClient in case the org has been bloqued while the instance was connected to streaming - if (!authData.pushEnabled) { - log.info(STREAMING_DISABLED); - pushEmitter.emit(PUSH_NONRETRYABLE_ERROR); - return; - } - - // Connect to SSE and schedule refresh token - const decodedToken = authData.decodedToken; - sseClient.open(authData); - scheduleTokenRefresh(decodedToken.iat, decodedToken.exp); - } - ).catch( - function (error) { - if (disconnected) return; - - log.error(ERROR_STREAMING_AUTH, [error.message]); - - // Handle 4XX HTTP errors: 401 (invalid API Key) or 400 (using incorrect API Key, i.e., client-side API Key on server-side) - if (error.statusCode >= 400 && error.statusCode < 500) { - pushEmitter.emit(PUSH_NONRETRYABLE_ERROR); - return; - } - - // Handle other HTTP and network errors as recoverable errors - pushEmitter.emit(PUSH_RETRYABLE_ERROR); - } - ); - } - - // close SSE connection and cancel scheduled tasks - function disconnectPush() { - disconnected = true; - log.info(STREAMING_DISCONNECTING); - sseClient.close(); - - if (timeoutId) clearTimeout(timeoutId); - connectPushRetryBackoff.reset(); - - stopWorkers(); - } - - // cancel scheduled fetch retries of Splits, Segments, and MySegments Update Workers - function stopWorkers() { - splitsUpdateWorker.backoff.reset(); - segmentsUpdateWorker.backoff.reset(); - } - - pushEmitter.on(PUSH_SUBSYSTEM_DOWN, stopWorkers); - - // restart backoff retry counter once push is connected - pushEmitter.on(PUSH_SUBSYSTEM_UP, () => { connectPushRetryBackoff.reset(); }); - - /** Fallbacking without retry due to: STREAMING_DISABLED control event, or 'pushEnabled: false', or non-recoverable SSE and Authentication errors */ - - pushEmitter.on(PUSH_NONRETRYABLE_ERROR, function handleNonRetryableError() { - // Note: `stopWorkers` is been called twice, but it is not harmful - disconnectPush(); - pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already - }); - - /** Fallbacking with retry due to recoverable SSE and Authentication errors */ - - pushEmitter.on(PUSH_RETRYABLE_ERROR, function handleRetryableError() { // HTTP or network error in SSE connection - // SSE connection is closed to avoid repeated errors due to retries - sseClient.close(); - - // retry streaming reconnect with backoff algorithm - let delayInMillis = connectPushRetryBackoff.scheduleCall(); - - log.info(STREAMING_RECONNECT, [delayInMillis / 1000]); - - pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already - }); - - /** Functions related to synchronization (Queues and Workers in the spec) */ - - pushEmitter.on(SPLIT_KILL, splitsUpdateWorker.killSplit); - pushEmitter.on(SPLIT_UPDATE, splitsUpdateWorker.put); - // [Only for server-side] - pushEmitter.on(SEGMENT_UPDATE, segmentsUpdateWorker.put); - - return objectAssign( - // Expose Event Emitter functionality and Event constants - Object.create(pushEmitter), - { - // Expose functionality for starting and stoping push mode: - stop: disconnectPush, // `handleNonRetryableError` cannot be used as `stop`, because it emits PUSH_SUBSYSTEM_DOWN event, which start polling. - - start() { - // Run in next event-loop cycle as in browser - setTimeout(connectPush); - } - } - ); -} diff --git a/src/sync/streaming/types.ts b/src/sync/streaming/types.ts index df348f70..6832a335 100644 --- a/src/sync/streaming/types.ts +++ b/src/sync/streaming/types.ts @@ -1,4 +1,4 @@ -import { IMySegmentsUpdateData } from './SSEHandler/types'; +import { IMySegmentsUpdateData, IMySegmentsUpdateV2Data, ISegmentUpdateData, ISplitUpdateData, ISplitKillData } from './SSEHandler/types'; import { ITask } from '../types'; import { IPollingManager, ISegmentsSyncTask } from '../polling/types'; import { IReadinessManager } from '../../readiness/types'; @@ -6,6 +6,7 @@ import { IFetchAuth } from '../../services/types'; import { IStorageSync } from '../../storages/types'; import { IEventEmitter, ISettings } from '../../types'; import { IPlatform } from '../../sdkFactory/types'; +import { ControlType } from './constants'; // Internal SDK events, subscribed by SyncManager and PushManager export type PUSH_SUBSYSTEM_UP = 'PUSH_SUBSYSTEM_UP' @@ -15,6 +16,7 @@ export type PUSH_RETRYABLE_ERROR = 'PUSH_RETRYABLE_ERROR' // Update-type push notifications, handled by NotificationProcessor export type MY_SEGMENTS_UPDATE = 'MY_SEGMENTS_UPDATE'; +export type MY_SEGMENTS_UPDATE_V2 = 'MY_SEGMENTS_UPDATE_V2'; export type SEGMENT_UPDATE = 'SEGMENT_UPDATE'; export type SPLIT_KILL = 'SPLIT_KILL'; export type SPLIT_UPDATE = 'SPLIT_UPDATE'; @@ -23,33 +25,23 @@ export type SPLIT_UPDATE = 'SPLIT_UPDATE'; export type CONTROL = 'CONTROL'; export type OCCUPANCY = 'OCCUPANCY'; -export type IPushEvent = PUSH_SUBSYSTEM_UP | PUSH_SUBSYSTEM_DOWN | PUSH_NONRETRYABLE_ERROR | PUSH_RETRYABLE_ERROR | MY_SEGMENTS_UPDATE | SEGMENT_UPDATE | SPLIT_UPDATE | SPLIT_KILL +export type IPushEvent = PUSH_SUBSYSTEM_UP | PUSH_SUBSYSTEM_DOWN | PUSH_NONRETRYABLE_ERROR | PUSH_RETRYABLE_ERROR | MY_SEGMENTS_UPDATE | MY_SEGMENTS_UPDATE_V2 | SEGMENT_UPDATE | SPLIT_UPDATE | SPLIT_KILL | ControlType.STREAMING_RESET + +type IParsedData = + T extends MY_SEGMENTS_UPDATE ? IMySegmentsUpdateData : + T extends MY_SEGMENTS_UPDATE_V2 ? IMySegmentsUpdateV2Data : + T extends SEGMENT_UPDATE ? ISegmentUpdateData : + T extends SPLIT_UPDATE ? ISplitUpdateData : + T extends SPLIT_KILL ? ISplitKillData : undefined; /** * EventEmitter used as Feedback Loop between the SyncManager and PushManager, * where the latter pushes messages and the former consumes it */ export interface IPushEventEmitter extends IEventEmitter { - once(event: T, listener: (...args: - T extends MY_SEGMENTS_UPDATE ? [parsedData: IMySegmentsUpdateData, channel: string] : - T extends SEGMENT_UPDATE ? [changeNumber: number, segmentName: string] : - T extends SPLIT_UPDATE ? [changeNumber: number] : - T extends SPLIT_KILL ? [changeNumber: number, splitName: string, defaultTreatment: string] : - any[]) => void): this; - - on(event: T, listener: (...args: - T extends MY_SEGMENTS_UPDATE ? [parsedData: IMySegmentsUpdateData, channel: string] : - T extends SEGMENT_UPDATE ? [changeNumber: number, segmentName: string] : - T extends SPLIT_UPDATE ? [changeNumber: number] : - T extends SPLIT_KILL ? [changeNumber: number, splitName: string, defaultTreatment: string] : - any[]) => void): this; - - emit(event: T, ...args: - T extends MY_SEGMENTS_UPDATE ? [parsedData: IMySegmentsUpdateData, channel: string] : - T extends SEGMENT_UPDATE ? [changeNumber: number, segmentName: string] : - T extends SPLIT_UPDATE ? [changeNumber: number] : - T extends SPLIT_KILL ? [changeNumber: number, splitName: string, defaultTreatment: string] : - any[]): boolean; + once(event: T, listener: (parsedData: IParsedData, channel: T extends MY_SEGMENTS_UPDATE ? string : undefined) => void): this; + on(event: T, listener: (parsedData: IParsedData, channel: T extends MY_SEGMENTS_UPDATE ? string : undefined) => void): this; + emit(event: T, parsedData?: IParsedData, channel?: T extends MY_SEGMENTS_UPDATE ? string : undefined): boolean; } /** diff --git a/src/sync/submitters/impressionsSyncTask.ts b/src/sync/submitters/impressionsSyncTask.ts index c5ff1d02..cf6b6068 100644 --- a/src/sync/submitters/impressionsSyncTask.ts +++ b/src/sync/submitters/impressionsSyncTask.ts @@ -12,7 +12,7 @@ import { ILogger } from '../../logger/types'; */ export function fromImpressionsCollector(sendLabels: boolean, data: ImpressionDTO[]): ImpressionsPayload { let groupedByFeature = groupBy(data, 'feature'); - let dto: any[] = []; + let dto: ImpressionsPayload = []; // using forOwn instead of for...in since the last also iterates over prototype enumerables forOwn(groupedByFeature, (value, name) => { diff --git a/src/sync/submitters/metricsSyncTask.ts b/src/sync/submitters/metricsSyncTask.ts index 2f743884..a5264b14 100644 --- a/src/sync/submitters/metricsSyncTask.ts +++ b/src/sync/submitters/metricsSyncTask.ts @@ -45,5 +45,5 @@ export function latenciesSyncTaskFactory( ): ISyncTask { // don't retry metrics. - return submitterSyncTaskFactory(log, postMetricsLatencies, latenciesCache, metricsRefreshRate, 'latency metrics', latencyTracker, fromCache('latencies')); + return submitterSyncTaskFactory(log, postMetricsLatencies, latenciesCache, metricsRefreshRate, 'latency metrics', latencyTracker, fromCache('latencies'), 0, true); } diff --git a/src/sync/submitters/submitterSyncTask.ts b/src/sync/submitters/submitterSyncTask.ts index cbee1913..bf92b2e9 100644 --- a/src/sync/submitters/submitterSyncTask.ts +++ b/src/sync/submitters/submitterSyncTask.ts @@ -1,22 +1,24 @@ import syncTaskFactory from '../syncTask'; import { ISyncTask, ITimeTracker } from '../types'; -import { IRecorderCacheConsumerSync } from '../../storages/types'; +import { IRecorderCacheProducerSync } from '../../storages/types'; import { ILogger } from '../../logger/types'; import { SUBMITTERS_PUSH, SUBMITTERS_PUSH_FAILS, SUBMITTERS_PUSH_RETRY } from '../../logger/constants'; +import { IResponse } from '../../services/types'; /** * Base function to create submitter sync tasks, such as ImpressionsSyncTask and EventsSyncTask */ export function submitterSyncTaskFactory( log: ILogger, - postClient: (body: string) => Promise, - sourceCache: IRecorderCacheConsumerSync, + postClient: (body: string) => Promise, + sourceCache: IRecorderCacheProducerSync, postRate: number, dataName: string, latencyTracker?: ITimeTracker, fromCacheToPayload?: (cacheData: TState) => any, maxRetries: number = 0, -): ISyncTask { + debugLogs?: boolean +): ISyncTask<[], void> { let retries = 0; @@ -26,7 +28,7 @@ export function submitterSyncTaskFactory( const data = sourceCache.state(); const dataCount: number | '' = typeof data.length === 'number' ? data.length : ''; - log.info(SUBMITTERS_PUSH, [dataCount, dataName]); + log[debugLogs ? 'debug' : 'info'](SUBMITTERS_PUSH, [dataCount, dataName]); const latencyTrackerStop = latencyTracker && latencyTracker.start(); const jsonPayload = JSON.stringify(fromCacheToPayload ? fromCacheToPayload(data) : data); diff --git a/src/sync/submitters/types.ts b/src/sync/submitters/types.ts index 368f486e..6ab697c1 100644 --- a/src/sync/submitters/types.ts +++ b/src/sync/submitters/types.ts @@ -1,20 +1,64 @@ +import { IMetadata } from '../../dtos/types'; +import { SplitIO } from '../../types'; + export type ImpressionsPayload = { - f: string, // Split name - i: { // Key Impressions - k: string; // Key - t: string; // Treatment - m: number; // Timestamp - c: number; // ChangeNumber - r?: string; // Rule label - b?: string; // Bucketing Key - pt?: number; // Previous time + /** Split name */ + f: string, + /** Key Impressions */ + i: { + /** Key */ + k: string; + /** Treatment */ + t: string; + /** Timestamp */ + m: number; + /** ChangeNumber */ + c: number; + /** Rule label */ + r?: string; + /** Bucketing Key */ + b?: string; + /** Previous time */ + pt?: number; }[] }[] export type ImpressionCountsPayload = { pf: { - f: string // Split name - m: number // Time Frame - rc: number // Count + /** Split name */ + f: string + /** Time Frame */ + m: number + /** Count */ + rc: number }[] } + +export type StoredImpressionWithMetadata = { + /** Metadata */ + m: IMetadata, + /** Stored impression */ + i: { + /** keyName */ + k: string, + /** bucketingKey */ + b?: string, + /** Split name */ + f: string, + /** treatment */ + t: string, + /** label */ + r: string, + /** changeNumber */ + c: number, + /** time */ + m: number + } +} + +export type StoredEventWithMetadata = { + /** Metadata */ + m: IMetadata, + /** Stored event */ + e: SplitIO.EventData +} diff --git a/src/sync/syncManagerOnline.ts b/src/sync/syncManagerOnline.ts index 04a0c98f..b0199a9c 100644 --- a/src/sync/syncManagerOnline.ts +++ b/src/sync/syncManagerOnline.ts @@ -75,17 +75,28 @@ export function syncManagerOnlineFactory( pollingManager.syncAll(); } - let running = false; + if (pushManager) { + pushManager.on(PUSH_SUBSYSTEM_UP, stopPollingAndSyncAll); + pushManager.on(PUSH_SUBSYSTEM_DOWN, startPolling); + } + + let running = false; // flag that indicates whether the syncManager has been started (true) or stopped (false) + let startFirstTime = true; // flag to distinguish calling the `start` method for the first time, to support pausing and resuming the synchronization return { + pushManager, + /** + * Method used to start the syncManager for the first time, or resume it after being stopped. + */ start() { // start syncing splits and segments if (pushManager) { - pollingManager.syncAll(); - pushManager.on(PUSH_SUBSYSTEM_UP, stopPollingAndSyncAll); - pushManager.on(PUSH_SUBSYSTEM_DOWN, startPolling); - // Run in next event-loop cycle as in client-side SyncManager + // Doesn't call `syncAll` when the syncManager is resuming + if (startFirstTime) { + pollingManager.syncAll(); + startFirstTime = false; + } pushManager.start(); } else { pollingManager.start(); @@ -96,6 +107,9 @@ export function syncManagerOnlineFactory( running = true; }, + /** + * Method used to stop/pause the syncManager. + */ stop() { // stop syncing if (pushManager) pushManager.stop(); diff --git a/src/sync/syncTask.ts b/src/sync/syncTask.ts index 321ea99e..d86cb9f4 100644 --- a/src/sync/syncTask.ts +++ b/src/sync/syncTask.ts @@ -3,28 +3,50 @@ import { ILogger } from '../logger/types'; import { ISyncTask } from './types'; /** - * factory of sync tasks + * Creates a syncTask that handles the periodic execution of a given task ("start" and "stop" methods). + * The task can be executed once calling the "execute" method. + * NOTE: Multiple calls to "execute" are not queued. Use "isExecuting" method to handle synchronization. + * + * @param log Logger instance. + * @param task Task to execute that returns a promise that NEVER REJECTS. Otherwise, periodic execution can result in Unhandled Promise Rejections. + * @param period Period in milliseconds to execute the task. + * @param taskName Optional task name for logging. + * @returns A sync task that wraps the given task. */ -export default function syncTaskFactory(log: ILogger, task: (...args: Input) => Promise, period: number, taskName = 'task'): ISyncTask { +export default function syncTaskFactory(log: ILogger, task: (...args: Input) => Promise, period: number, taskName = 'task'): ISyncTask { - // flag that indicates if the task is being executed + // Flag that indicates if the task is being executed let executing = false; - - // flag that indicates if the task periodic execution has been started/stopped. We cannot use timeoutID because it is set after the first execution of the task. + // flag that indicates if the task periodic execution has been started/stopped. let running = false; - let timeoutID: number | undefined; + // Auxiliar counter used to avoid race condition when calling `start` & `stop` intermittently + let runningId = 0; + // Params passed to `task` when called periodically + let runningArgs: Input; + // Id of the periodic call timeout + let timeoutID: any; function execute(...args: Input) { executing = true; log.debug(SYNC_TASK_EXECUTE, [taskName]); return task(...args).then(result => { executing = false; - if (running) timeoutID = setTimeout(execute, period, ...args); + return result; + }); + // No need to handle promise rejection because it is a pre-condition that provided task never rejects. + } + + function periodicExecute(currentRunningId: number) { + return execute(...runningArgs).then((result) => { + // Call `setTimeout` if periodic execution was started and `currentRunningId === runningId` + // to avoid a race condition when calling `start`, `stop` and `start` again + if (running && currentRunningId === runningId) timeoutID = setTimeout(periodicExecute, period, currentRunningId); return result; }); } return { + // @TODO check if we need to queued `execute` calls, to avoid possible race conditions on submitters and updaters with streaming. execute, isExecuting() { @@ -34,8 +56,10 @@ export default function syncTaskFactory(log: ILogge start(...args: Input) { if (!running) { running = true; + runningId++; + runningArgs = args; log.debug(SYNC_TASK_START, [taskName, period]); - return execute(...args); + return periodicExecute(runningId); } }, diff --git a/src/sync/types.ts b/src/sync/types.ts index 4af95e62..55566ef1 100644 --- a/src/sync/types.ts +++ b/src/sync/types.ts @@ -3,6 +3,7 @@ import { IPlatform } from '../sdkFactory/types'; import { ISplitApi } from '../services/types'; import { IStorageSync } from '../storages/types'; import { ISettings } from '../types'; +import { IPushManager } from './streaming/types'; export interface ITask { /** @@ -41,7 +42,8 @@ export interface ITimeTracker { /** SyncManager */ export interface ISyncManager extends ITask { - flush(): Promise + flush(): Promise, + pushManager?: IPushManager } export interface ISyncManagerCS extends ISyncManager { diff --git a/src/trackers/__tests__/impressionsTracker.spec.ts b/src/trackers/__tests__/impressionsTracker.spec.ts index 9a89a61d..b85135f1 100644 --- a/src/trackers/__tests__/impressionsTracker.spec.ts +++ b/src/trackers/__tests__/impressionsTracker.spec.ts @@ -2,7 +2,6 @@ import impressionsTrackerFactory from '../impressionsTracker'; import ImpressionCountsCacheInMemory from '../../storages/inMemory/ImpressionCountsCacheInMemory'; import { impressionObserverSSFactory } from '../impressionObserver/impressionObserverSS'; import { impressionObserverCSFactory } from '../impressionObserver/impressionObserverCS'; -import { IMetadata } from '../../dtos/types'; import { ImpressionDTO } from '../../types'; import { loggerMock } from '../../logger/__tests__/sdkLogger.mock'; @@ -12,9 +11,11 @@ function generateMocks() { const fakeImpressionsCache = { track: jest.fn() }; - const fakeMetadata: IMetadata = { - hostname: 'fake-hostname', - ip: 'fake-ip', + const fakeSettings = { + runtime: { + hostname: 'fake-hostname', + ip: 'fake-ip' + }, version: 'jest-test', }; const fakeListener = { @@ -25,7 +26,7 @@ function generateMocks() { }; return { - fakeImpressionsCache, fakeMetadata, fakeListener, fakeIntegrationsManager + fakeImpressionsCache, fakeSettings, fakeListener, fakeIntegrationsManager }; } @@ -36,14 +37,14 @@ describe('Impressions Tracker', () => { test('Tracker API', () => { expect(typeof impressionsTrackerFactory).toBe('function'); // The module should return a function which acts as a factory. - const { fakeImpressionsCache, fakeMetadata } = generateMocks(); - const instance = impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeMetadata); + const { fakeImpressionsCache, fakeSettings } = generateMocks(); + const instance = impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeSettings); expect(typeof instance.track).toBe('function'); // The instance should implement the track method which will actually track queued impressions. }); test('Should be able to track impressions (in DEBUG mode without Previous Time).', () => { - const { fakeImpressionsCache, fakeMetadata } = generateMocks(); - const tracker = impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeMetadata); + const { fakeImpressionsCache, fakeSettings } = generateMocks(); + const tracker = impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeSettings); const imp1 = { feature: '10', @@ -63,8 +64,8 @@ describe('Impressions Tracker', () => { }); test('Tracked impressions should be sent to impression listener and integration manager when we invoke .track()', (done) => { - const { fakeImpressionsCache, fakeMetadata, fakeListener, fakeIntegrationsManager } = generateMocks(); - const tracker = impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeMetadata, fakeListener, fakeIntegrationsManager); + const { fakeImpressionsCache, fakeSettings, fakeListener, fakeIntegrationsManager } = generateMocks(); + const tracker = impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeSettings, fakeListener, fakeIntegrationsManager); const fakeImpression = { feature: 'impression' @@ -91,8 +92,8 @@ describe('Impressions Tracker', () => { expect(fakeListener.logImpression).toBeCalledTimes(2); // The listener should be executed after the timeout wrapping make it to the queue stack, once per each tracked impression. expect(fakeIntegrationsManager.handleImpression).toBeCalledTimes(2); // The integrations manager handleImpression method should be executed after the timeout wrapping make it to the queue stack, once per each tracked impression. - const impressionData1 = { impression: fakeImpression, attributes: fakeAttributes, sdkLanguageVersion: fakeMetadata.version, ip: fakeMetadata.ip, hostname: fakeMetadata.hostname }; - const impressionData2 = { impression: fakeImpression2, attributes: fakeAttributes, sdkLanguageVersion: fakeMetadata.version, ip: fakeMetadata.ip, hostname: fakeMetadata.hostname }; + const impressionData1 = { impression: fakeImpression, attributes: fakeAttributes, sdkLanguageVersion: fakeSettings.version, ip: fakeSettings.runtime.ip, hostname: fakeSettings.runtime.hostname }; + const impressionData2 = { impression: fakeImpression2, attributes: fakeAttributes, sdkLanguageVersion: fakeSettings.version, ip: fakeSettings.runtime.ip, hostname: fakeSettings.runtime.hostname }; expect(fakeListener.logImpression.mock.calls[0][0]).toEqual(impressionData1); // The listener should be executed with the corresponding map for each of the impressions. expect(fakeListener.logImpression.mock.calls[1][0]).toEqual(impressionData2); // The listener should be executed with the corresponding map for each of the impressions. @@ -134,13 +135,13 @@ describe('Impressions Tracker', () => { } as ImpressionDTO; test('Should track 3 impressions with Previous Time.', () => { - const { fakeImpressionsCache, fakeMetadata } = generateMocks(); + const { fakeImpressionsCache, fakeSettings } = generateMocks(); impression.time = impression2.time = 123456789; impression3.time = 1234567891; const trackers = [ - impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeMetadata, undefined, undefined, impressionObserverSSFactory()), - impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeMetadata, undefined, undefined, impressionObserverCSFactory()) + impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeSettings, undefined, undefined, impressionObserverSSFactory()), + impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeSettings, undefined, undefined, impressionObserverCSFactory()) ]; expect(fakeImpressionsCache.track).not.toBeCalled(); // storage method should not be called until impressions are tracked. @@ -162,13 +163,13 @@ describe('Impressions Tracker', () => { }); test('Should track 2 impressions in OPTIMIZED mode (providing ImpressionCountsCache).', () => { - const { fakeImpressionsCache, fakeMetadata } = generateMocks(); + const { fakeImpressionsCache, fakeSettings } = generateMocks(); impression.time = Date.now(); impression2.time = Date.now(); impression3.time = Date.now(); const impressionCountsCache = new ImpressionCountsCacheInMemory(); - const tracker = impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeMetadata, undefined, undefined, impressionObserverCSFactory(), impressionCountsCache); + const tracker = impressionsTrackerFactory(loggerMock, fakeImpressionsCache, fakeSettings, undefined, undefined, impressionObserverCSFactory(), impressionCountsCache); expect(fakeImpressionsCache.track).not.toBeCalled(); // cache method should not be called by just creating a tracker diff --git a/src/trackers/impressionObserver/ImpressionObserver.ts b/src/trackers/impressionObserver/ImpressionObserver.ts index 887c73a7..666fa463 100644 --- a/src/trackers/impressionObserver/ImpressionObserver.ts +++ b/src/trackers/impressionObserver/ImpressionObserver.ts @@ -2,18 +2,16 @@ import { ImpressionDTO } from '../../types'; import LRUCache from '../../utils/LRUCache'; import { IImpressionObserver } from './types'; -export default class ImpressionObserver implements IImpressionObserver { - private cache: LRUCache; - private hasher: (impression: ImpressionDTO) => string | null; +export default class ImpressionObserver implements IImpressionObserver { + private cache: LRUCache; + private hasher: (impression: ImpressionDTO) => K; - constructor(size: number, hasher: (impression: ImpressionDTO) => string | null) { + constructor(size: number, hasher: (impression: ImpressionDTO) => K) { this.cache = new LRUCache(size); this.hasher = hasher; } testAndSet(impression: ImpressionDTO) { - if (!impression) return; - const hash = this.hasher(impression); const previous = this.cache.get(hash); this.cache.set(hash, impression.time); diff --git a/src/trackers/impressionObserver/__tests__/buildKey.spec.ts b/src/trackers/impressionObserver/__tests__/buildKey.spec.ts new file mode 100644 index 00000000..4217c109 --- /dev/null +++ b/src/trackers/impressionObserver/__tests__/buildKey.spec.ts @@ -0,0 +1,9 @@ +import { buildKey } from '../buildKey'; +import { generateImpressions } from './testUtils'; + +test('buildKey', () => { // @ts-ignore + expect(buildKey({})).toBe('undefined:undefined:undefined:undefined:undefined'); + + const imp = generateImpressions(1)[0]; + expect(buildKey(imp)).toBe('key_0:feature_0:someTreatment:in segment all:0'); +}); diff --git a/src/trackers/impressionObserver/__tests__/clientSideObserver.spec.ts b/src/trackers/impressionObserver/__tests__/clientSideObserver.spec.ts index 37a177be..c4740a8a 100644 --- a/src/trackers/impressionObserver/__tests__/clientSideObserver.spec.ts +++ b/src/trackers/impressionObserver/__tests__/clientSideObserver.spec.ts @@ -72,9 +72,6 @@ test('Hasher 32 / Impression Hasher Does Not Crash', () => { // @ts-ignore imp1.treatment = null; expect(hashImpression32(imp1)).not.toBe(null); - - // @ts-ignore - expect(hashImpression32(null)).toBe(null); }); test('Client-side (Browser JS) / Impression Observer Basic Functionality', () => { diff --git a/src/trackers/impressionObserver/__tests__/serverSideObserver.spec.ts b/src/trackers/impressionObserver/__tests__/serverSideObserver.spec.ts index 7f6c026b..7f14cfe8 100644 --- a/src/trackers/impressionObserver/__tests__/serverSideObserver.spec.ts +++ b/src/trackers/impressionObserver/__tests__/serverSideObserver.spec.ts @@ -72,9 +72,6 @@ test('Hasher 128 / Impression Hasher Does Not Crash', () => { // @ts-ignore imp1.treatment = null; expect(hashImpression128(imp1)).not.toBe(null); - - // @ts-ignore - expect(hashImpression128(null)).toBe(null); }); test('Server-side (Node JS) / Impression Observer Basic Functionality', () => { diff --git a/src/trackers/impressionObserver/buildKey.ts b/src/trackers/impressionObserver/buildKey.ts index 4267ce0b..8adedb82 100644 --- a/src/trackers/impressionObserver/buildKey.ts +++ b/src/trackers/impressionObserver/buildKey.ts @@ -1,19 +1,5 @@ import { ImpressionDTO } from '../../types'; -const UNKNOWN = 'UNKNOWN'; - -function _unknownIfNull(s: any) { - return s ? s : UNKNOWN; -} - -function _zeroIfNull(l: any) { - return l ? l : 0; -} - -export default function buildKey(impression: ImpressionDTO) { - return `${_unknownIfNull(impression.keyName)} - :${_unknownIfNull(impression.feature)} - :${_unknownIfNull(impression.treatment)} - :${_unknownIfNull(impression.label)} - :${_zeroIfNull(impression.changeNumber)}`; +export function buildKey(impression: ImpressionDTO) { + return `${impression.keyName}:${impression.feature}:${impression.treatment}:${impression.label}:${impression.changeNumber}`; } diff --git a/src/trackers/impressionObserver/impressionObserverCS.ts b/src/trackers/impressionObserver/impressionObserverCS.ts index 168195f9..bf86409e 100644 --- a/src/trackers/impressionObserver/impressionObserverCS.ts +++ b/src/trackers/impressionObserver/impressionObserverCS.ts @@ -1,10 +1,10 @@ import ImpressionObserver from './ImpressionObserver'; import { hash } from '../../utils/murmur3/murmur3'; -import buildKey from './buildKey'; +import { buildKey } from './buildKey'; import { ImpressionDTO } from '../../types'; export function hashImpression32(impression: ImpressionDTO) { - return impression ? hash(buildKey(impression)).toString() : null; + return hash(buildKey(impression)); } const LAST_SEEN_CACHE_SIZE = 500; // cache up to 500 impression hashes diff --git a/src/trackers/impressionObserver/impressionObserverSS.ts b/src/trackers/impressionObserver/impressionObserverSS.ts index 89ecf4c6..828cfc21 100644 --- a/src/trackers/impressionObserver/impressionObserverSS.ts +++ b/src/trackers/impressionObserver/impressionObserverSS.ts @@ -1,10 +1,10 @@ import ImpressionObserver from './ImpressionObserver'; -import { hash128 } from '../../utils/murmur3/murmur3_128'; -import buildKey from './buildKey'; +import { hash128 } from '../../utils/murmur3/murmur3_128_x86'; +import { buildKey } from './buildKey'; import { ImpressionDTO } from '../../types'; export function hashImpression128(impression: ImpressionDTO) { - return impression ? hash128(buildKey(impression)).toString() : null; + return hash128(buildKey(impression)); } const LAST_SEEN_CACHE_SIZE = 500000; // cache up to 500k impression hashes diff --git a/src/trackers/impressionsTracker.ts b/src/trackers/impressionsTracker.ts index 5d227892..1c43f7fb 100644 --- a/src/trackers/impressionsTracker.ts +++ b/src/trackers/impressionsTracker.ts @@ -1,10 +1,9 @@ import objectAssign from 'object-assign'; import thenable from '../utils/promise/thenable'; import { truncateTimeFrame } from '../utils/time'; -import { IImpressionCountsCacheBase, IImpressionsCacheBase } from '../storages/types'; +import { IImpressionCountsCacheSync, IImpressionsCacheBase } from '../storages/types'; import { IImpressionsHandler, IImpressionsTracker } from './types'; -import { IMetadata } from '../dtos/types'; -import { SplitIO, ImpressionDTO } from '../types'; +import { SplitIO, ImpressionDTO, ISettings } from '../types'; import { IImpressionObserver } from './impressionObserver/types'; import { ILogger } from '../logger/types'; import { IMPRESSIONS_TRACKER_SUCCESS, ERROR_IMPRESSIONS_TRACKER, ERROR_IMPRESSIONS_LISTENER } from '../logger/constants'; @@ -24,14 +23,14 @@ export default function impressionsTrackerFactory( impressionsCache: IImpressionsCacheBase, // @TODO consider passing only an optional integrationsManager to handle impressions - { ip, hostname, version }: IMetadata, + { runtime: { ip, hostname }, version }: Pick, impressionListener?: SplitIO.IImpressionListener, integrationsManager?: IImpressionsHandler, // if observer is provided, it implies `shouldAddPreviousTime` flag (i.e., if impressions previous time should be added or not) observer?: IImpressionObserver, // if countsCache is provided, it implies `isOptimized` flag (i.e., if impressions should be deduped or not) - countsCache?: IImpressionCountsCacheBase + countsCache?: IImpressionCountsCacheSync ): IImpressionsTracker { return { diff --git a/src/types.ts b/src/types.ts index a7473280..691c5beb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,8 +1,10 @@ +import { ISplitFiltersValidation } from './dtos/types'; import { IIntegration, IIntegrationFactoryParams } from './integrations/types'; import { ILogger } from './logger/types'; /* eslint-disable no-use-before-define */ -import { IStorageFactoryParams, IStorageSyncCS, IStorageSync, IStorageAsync } from './storages/types'; +import { IStorageFactoryParams, IStorageSyncCS, IStorageSync, IStorageAsync, IStorageSyncFactory } from './storages/types'; +import { ISyncManagerFactoryParams, ISyncManagerCS } from './sync/types'; /** * EventEmitter interface with the minimal methods used by the SDK @@ -55,6 +57,8 @@ export type SDKMode = 'standalone' | 'consumer' | 'localhost'; * Settings interface. This is a representation of the settings the SDK expose, that's why * most of it's props are readonly. Only features should be rewritten when localhost mode is active. * @interface ISettings + * + * NOTE: same ISettings interface from public type declarations extended with private properties. */ export interface ISettings { readonly core: { @@ -81,7 +85,7 @@ export interface ISettings { retriesOnFailureBeforeReady: number, eventsFirstPushWindow: number }, - readonly storage: (params: IStorageFactoryParams) => IStorageSyncCS, + readonly storage: IStorageSyncFactory, readonly integrations?: Array<(params: IIntegrationFactoryParams) => IIntegration | void>, readonly urls: { events: string, @@ -96,12 +100,15 @@ export interface ISettings { readonly sync: { splitFilters: SplitIO.SplitFilter[], impressionsMode: SplitIO.ImpressionsMode, + __splitFiltersValidation: ISplitFiltersValidation, + localhostMode?: SplitIO.LocalhostFactory }, readonly runtime: { ip: string | false hostname: string | false }, readonly log: ILogger + readonly impressionListener?: unknown } /** * Log levels. @@ -576,6 +583,13 @@ export namespace SplitIO { * @typedef {Promise} SplitNamesAsync */ export type SplitNamesAsync = Promise; + /** + * Localhost mode factory. + */ + export type LocalhostFactory = { + type: 'LocalhostFromObject' | 'LocalhostFromFile' + (params: ISyncManagerFactoryParams): ISyncManagerCS + } /** * Impression listener interface. This is the interface that needs to be implemented * by the element you provide to the SDK as impression listener. @@ -592,7 +606,7 @@ export namespace SplitIO { export type EventData = { eventTypeId: string; value?: number; - properties: Properties; + properties?: Properties; trafficTypeName?: string; key?: string; // matching user key timestamp: number; diff --git a/src/utils/base64/__tests__/index.spec.ts b/src/utils/base64/__tests__/index.spec.ts index 8eff2bdc..3af8571e 100644 --- a/src/utils/base64/__tests__/index.spec.ts +++ b/src/utils/base64/__tests__/index.spec.ts @@ -1,4 +1,4 @@ -import { base64sample, decodedBase64sample } from '../../../sync/streaming/AuthClient/__tests__/dataMocks'; +import { base64sample, decodedBase64sample } from '../../../sync/streaming/__tests__/dataMocks'; import { encodeToBase64, decodeFromBase64 } from '../index'; diff --git a/src/utils/constants/index.ts b/src/utils/constants/index.ts index cfcd245b..51bcafca 100644 --- a/src/utils/constants/index.ts +++ b/src/utils/constants/index.ts @@ -1,3 +1,5 @@ +import { StorageType } from '../../storages/types'; + // Special treatments export const CONTROL = 'control'; export const CONTROL_WITH_CONFIG = { @@ -24,4 +26,7 @@ export const PRODUCER_MODE = 'producer'; export const CONSUMER_MODE = 'consumer'; // Storage types -export const STORAGE_MEMORY = 'MEMORY'; +export const STORAGE_MEMORY: StorageType = 'MEMORY'; +export const STORAGE_LOCALSTORAGE: StorageType = 'LOCALSTORAGE'; +export const STORAGE_REDIS: StorageType = 'REDIS'; +export const STORAGE_CUSTOM: StorageType = 'CUSTOM'; diff --git a/src/utils/decompress/index.ts b/src/utils/decompress/index.ts new file mode 100644 index 00000000..e0f5c2cd --- /dev/null +++ b/src/utils/decompress/index.ts @@ -0,0 +1,429 @@ +/* +Trimmed version of "fflate" library (https://www.npmjs.com/package/fflate/v/0.7.1) +used for GZIP/Zlib decompression in JavaScript, with the minimal modules used by the SDK. + +MIT License + +Copyright (c) 2020 Arjun Barrett + +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. +*/ +/* eslint-disable */ +// @ts-nocheck + +export const algorithms = (function iifeDecompress() { + + // Handle runtimes without typed arrays + if ([typeof Uint8Array, typeof Uint16Array, typeof Uint32Array].some(v => v != 'function')) { + return 'global Uint8Array object is not available for gzip/zlib decompression'; + } + + // DEFLATE is a complex format; to read this code, you should probably check the RFC first: + + // aliases for shorter compressed code (most minifers don't do this) + var u8 = Uint8Array, u16 = Uint16Array, u32 = Uint32Array; + // fixed length extra bits + var fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, /* unused */ 0, 0, /* impossible */ 0]); + // fixed distance extra bits + // see fleb note + var fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* unused */ 0, 0]); + // code length index map + var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]); + // get base, reverse index map from extra bits + var freb = function (eb, start) { + var b = new u16(31); + for (var i = 0; i < 31; ++i) { + b[i] = start += 1 << eb[i - 1]; + } + // numbers here are at max 18 bits + var r = new u32(b[30]); + for (var i = 1; i < 30; ++i) { + for (var j = b[i]; j < b[i + 1]; ++j) { + r[j] = ((j - b[i]) << 5) | i; + } + } + return [b, r]; + }; + var _a = freb(fleb, 2), fl = _a[0], revfl = _a[1]; + // we can ignore the fact that the other numbers are wrong; they never happen anyway + fl[28] = 258, revfl[258] = 28; + var _b = freb(fdeb, 0), fd = _b[0]; + // map of value to reverse (assuming 16 bits) + var rev = new u16(32768); + for (var i = 0; i < 32768; ++i) { + // reverse table algorithm from SO + var x = ((i & 0xAAAA) >>> 1) | ((i & 0x5555) << 1); + x = ((x & 0xCCCC) >>> 2) | ((x & 0x3333) << 2); + x = ((x & 0xF0F0) >>> 4) | ((x & 0x0F0F) << 4); + rev[i] = (((x & 0xFF00) >>> 8) | ((x & 0x00FF) << 8)) >>> 1; + } + // create huffman tree from u8 "map": index -> code length for code index + // mb (max bits) must be at most 15 + // TODO: optimize/split up? + var hMap = (function (cd, mb, r) { + var s = cd.length; + // index + var i = 0; + // u16 "map": index -> # of codes with bit length = index + var l = new u16(mb); + // length of cd must be 288 (total # of codes) + for (; i < s; ++i) + ++l[cd[i] - 1]; + // u16 "map": index -> minimum code for bit length = index + var le = new u16(mb); + for (i = 0; i < mb; ++i) { + le[i] = (le[i - 1] + l[i - 1]) << 1; + } + var co; + if (r) { + // u16 "map": index -> number of actual bits, symbol for code + co = new u16(1 << mb); + // bits to remove for reverser + var rvb = 15 - mb; + for (i = 0; i < s; ++i) { + // ignore 0 lengths + if (cd[i]) { + // num encoding both symbol and bits read + var sv = (i << 4) | cd[i]; + // free bits + var r_1 = mb - cd[i]; + // start value + var v = le[cd[i] - 1]++ << r_1; + // m is end value + for (var m = v | ((1 << r_1) - 1); v <= m; ++v) { + // every 16 bit value starting with the code yields the same result + co[rev[v] >>> rvb] = sv; + } + } + } + } + else { + co = new u16(s); + for (i = 0; i < s; ++i) { + if (cd[i]) { + co[i] = rev[le[cd[i] - 1]++] >>> (15 - cd[i]); + } + } + } + return co; + }); + // fixed length tree + var flt = new u8(288); + for (var i = 0; i < 144; ++i) + flt[i] = 8; + for (var i = 144; i < 256; ++i) + flt[i] = 9; + for (var i = 256; i < 280; ++i) + flt[i] = 7; + for (var i = 280; i < 288; ++i) + flt[i] = 8; + // fixed distance tree + var fdt = new u8(32); + for (var i = 0; i < 32; ++i) + fdt[i] = 5; + // fixed length map + var flrm = /*#__PURE__*/ hMap(flt, 9, 1); + // fixed distance map + var fdrm = /*#__PURE__*/ hMap(fdt, 5, 1); + // find max of array + var max = function (a) { + var m = a[0]; + for (var i = 1; i < a.length; ++i) { + if (a[i] > m) + m = a[i]; + } + return m; + }; + // read d, starting at bit p and mask with m + var bits = function (d, p, m) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8)) >> (p & 7)) & m; + }; + // read d, starting at bit p continuing for at least 16 bits + var bits16 = function (d, p) { + var o = (p / 8) | 0; + return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16)) >> (p & 7)); + }; + // get end of byte + var shft = function (p) { return ((p + 7) / 8) | 0; }; + // typed array slice - allows garbage collector to free original reference, + // while being more compatible than .slice + var slc = function (v, s, e) { + if (s == null || s < 0) + s = 0; + if (e == null || e > v.length) + e = v.length; + // can't use .constructor in case user-supplied + var n = new (v instanceof u16 ? u16 : v instanceof u32 ? u32 : u8)(e - s); + n.set(v.subarray(s, e)); + return n; + }; + // error codes + var ec = [ + 'unexpected EOF', + 'invalid block type', + 'invalid length/literal', + 'invalid distance', + 'stream finished', + 'no stream handler', + , + 'no callback', + 'invalid UTF-8 data', + 'extra field too long', + 'date not in range 1980-2099', + 'filename too long', + 'stream finishing', + 'invalid zip data' + // determined by unknown compression method + ]; + var err = function (ind, msg, nt) { + var e = new Error(msg || ec[ind]); + e.code = ind; + if (Error.captureStackTrace) + Error.captureStackTrace(e, err); + if (!nt) + throw e; + return e; + }; + // expands raw DEFLATE data + var inflt = function (dat, buf, st) { + // source length + var sl = dat.length; + if (!sl || (st && st.f && !st.l)) + return buf || new u8(0); + // have to estimate size + var noBuf = !buf || st; + // no state + var noSt = !st || st.i; + if (!st) + st = {}; + // Assumes roughly 33% compression ratio average + if (!buf) + buf = new u8(sl * 3); + // ensure buffer can fit at least l elements + var cbuf = function (l) { + var bl = buf.length; + // need to increase size to fit + if (l > bl) { + // Double or set to necessary, whichever is greater + var nbuf = new u8(Math.max(bl * 2, l)); + nbuf.set(buf); + buf = nbuf; + } + }; + // last chunk bitpos bytes + var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n; + // total bits + var tbts = sl * 8; + do { + if (!lm) { + // BFINAL - this is only 1 when last chunk is next + final = bits(dat, pos, 1); + // type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman + var type = bits(dat, pos + 1, 3); + pos += 3; + if (!type) { + // go to end of byte boundary + var s = shft(pos) + 4, l = dat[s - 4] | (dat[s - 3] << 8), t = s + l; + if (t > sl) { + if (noSt) + err(0); + break; + } + // ensure size + if (noBuf) + cbuf(bt + l); + // Copy over uncompressed data + buf.set(dat.subarray(s, t), bt); + // Get new bitpos, update byte count + st.b = bt += l, st.p = pos = t * 8, st.f = final; + continue; + } + else if (type == 1) + lm = flrm, dm = fdrm, lbt = 9, dbt = 5; + else if (type == 2) { + // literal lengths + var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4; + var tl = hLit + bits(dat, pos + 5, 31) + 1; + pos += 14; + // length+distance tree + var ldt = new u8(tl); + // code length tree + var clt = new u8(19); + for (var i = 0; i < hcLen; ++i) { + // use index map to get real code + clt[clim[i]] = bits(dat, pos + i * 3, 7); + } + pos += hcLen * 3; + // code lengths bits + var clb = max(clt), clbmsk = (1 << clb) - 1; + // code lengths map + var clm = hMap(clt, clb, 1); + for (var i = 0; i < tl;) { + var r = clm[bits(dat, pos, clbmsk)]; + // bits read + pos += r & 15; + // symbol + var s = r >>> 4; + // code length to copy + if (s < 16) { + ldt[i++] = s; + } + else { + // copy count + var c = 0, n = 0; + if (s == 16) + n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1]; + else if (s == 17) + n = 3 + bits(dat, pos, 7), pos += 3; + else if (s == 18) + n = 11 + bits(dat, pos, 127), pos += 7; + while (n--) + ldt[i++] = c; + } + } + // length tree distance tree + var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit); + // max length bits + lbt = max(lt); + // max dist bits + dbt = max(dt); + lm = hMap(lt, lbt, 1); + dm = hMap(dt, dbt, 1); + } + else + err(1); + if (pos > tbts) { + if (noSt) + err(0); + break; + } + } + // Make sure the buffer can hold this + the largest possible addition + // Maximum chunk size (practically, theoretically infinite) is 2^17; + if (noBuf) + cbuf(bt + 131072); + var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1; + var lpos = pos; + for (; ; lpos = pos) { + // bits read, code + var c = lm[bits16(dat, pos) & lms], sym = c >>> 4; + pos += c & 15; + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (!c) + err(2); + if (sym < 256) + buf[bt++] = sym; + else if (sym == 256) { + lpos = pos, lm = null; + break; + } + else { + var add = sym - 254; + // no extra bits needed if less + if (sym > 264) { + // index + var i = sym - 257, b = fleb[i]; + add = bits(dat, pos, (1 << b) - 1) + fl[i]; + pos += b; + } + // dist + var d = dm[bits16(dat, pos) & dms], dsym = d >>> 4; + if (!d) + err(3); + pos += d & 15; + var dt = fd[dsym]; + if (dsym > 3) { + var b = fdeb[dsym]; + dt += bits16(dat, pos) & ((1 << b) - 1), pos += b; + } + if (pos > tbts) { + if (noSt) + err(0); + break; + } + if (noBuf) + cbuf(bt + 131072); + var end = bt + add; + for (; bt < end; bt += 4) { + buf[bt] = buf[bt - dt]; + buf[bt + 1] = buf[bt + 1 - dt]; + buf[bt + 2] = buf[bt + 2 - dt]; + buf[bt + 3] = buf[bt + 3 - dt]; + } + bt = end; + } + } + st.l = lm, st.p = lpos, st.b = bt, st.f = final; + if (lm) + final = 1, st.m = lbt, st.d = dm, st.n = dbt; + } while (!final); + return bt == buf.length ? buf : slc(buf, 0, bt); + }; + // gzip footer: -8 to -4 = CRC, -4 to -0 is length + // gzip start + var gzs = function (d) { + if (d[0] != 31 || d[1] != 139 || d[2] != 8) + err(6, 'invalid gzip data'); + var flg = d[3]; + var st = 10; + if (flg & 4) + st += d[10] | (d[11] << 8) + 2; + for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++]) + ; + return st + (flg & 2); + }; + // gzip length + var gzl = function (d) { + var l = d.length; + return ((d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16) | (d[l - 1] << 24)) >>> 0; + }; + // zlib valid + var zlv = function (d) { + if ((d[0] & 15) != 8 || (d[0] >>> 4) > 7 || ((d[0] << 8 | d[1]) % 31)) + err(6, 'invalid zlib data'); + if (d[1] & 32) + err(6, 'invalid zlib data: preset dictionaries not supported'); + }; + + return { + /** + * Expands GZIP data + * @param data The data to decompress + * @param out Where to write the data. GZIP already encodes the output size, so providing this doesn't save memory. + * @returns The decompressed version of the data + */ + gunzipSync(data: Uint8Array, out?: Uint8Array): Uint8Array { + return inflt(data.subarray(gzs(data), -8), out || new u8(gzl(data))); + }, + /** + * Expands Zlib data + * @param data The data to decompress + * @param out Where to write the data. Saves memory if you know the decompressed size and provide an output buffer of that length. + * @returns The decompressed version of the data + */ + unzlibSync(data: Uint8Array, out?: Uint8Array): Uint8Array { + return inflt((zlv(data), data.subarray(2, -4)), out); + } + } +})(); diff --git a/src/utils/inputValidation/__tests__/apiKey.spec.ts b/src/utils/inputValidation/__tests__/apiKey.spec.ts index c1cbb25d..76d18f1f 100644 --- a/src/utils/inputValidation/__tests__/apiKey.spec.ts +++ b/src/utils/inputValidation/__tests__/apiKey.spec.ts @@ -86,9 +86,9 @@ describe('validateAndTrackApiKey', () => { expect(validateAndTrackApiKey(loggerMock, validApiKey)).toBe(validApiKey); expect(loggerMock.warn.mock.calls).toEqual([ - [WARN_API_KEY, ['1 factory with this API Key']], - [WARN_API_KEY, ['2 factories with this API Key']], - [WARN_API_KEY, ['3 factories with this API Key']] + [WARN_API_KEY, ['1 factory/ies with this API Key']], + [WARN_API_KEY, ['2 factory/ies with this API Key']], + [WARN_API_KEY, ['3 factory/ies with this API Key']] ]); // We get a warning each time we register the same api key, with the number of instances we have. // We will release the used api key leaving only 1 "use" on the cache. @@ -100,7 +100,7 @@ describe('validateAndTrackApiKey', () => { // So we get the warning again. expect(validateAndTrackApiKey(loggerMock, validApiKey)).toBe(validApiKey); - expect(loggerMock.warn).toBeCalledWith(WARN_API_KEY, ['1 factory with this API Key']); + expect(loggerMock.warn).toBeCalledWith(WARN_API_KEY, ['1 factory/ies with this API Key']); // Leave it with 0 releaseApiKey(validApiKey); diff --git a/src/utils/inputValidation/__tests__/event.spec.ts b/src/utils/inputValidation/__tests__/event.spec.ts index 2e54136b..ce7e2cff 100644 --- a/src/utils/inputValidation/__tests__/event.spec.ts +++ b/src/utils/inputValidation/__tests__/event.spec.ts @@ -47,7 +47,7 @@ describe('INPUT VALIDATION for Event types', () => { const expectedLog = invalidEvents[i]['msg']; expect(validateEvent(loggerMock, invalidValue, 'test_method')).toBe(false); // Invalid event types should always return false. - expect(loggerMock.error).toBeCalledWith(expectedLog, expectedLog === ERROR_EVENT_TYPE_FORMAT ? ['test_method', invalidValue] : ['test_method']); // Should log the error for the invalid event type. + expect(loggerMock.error).toBeCalledWith(expectedLog, expectedLog === ERROR_EVENT_TYPE_FORMAT ? ['test_method', invalidValue] : ['test_method', 'event_type']); // Should log the error for the invalid event type. loggerMock.error.mockClear(); } diff --git a/src/utils/inputValidation/__tests__/splitExistance.spec.ts b/src/utils/inputValidation/__tests__/splitExistance.spec.ts index 4bc2b8e8..7d0d7b39 100644 --- a/src/utils/inputValidation/__tests__/splitExistance.spec.ts +++ b/src/utils/inputValidation/__tests__/splitExistance.spec.ts @@ -7,7 +7,7 @@ import { validateSplitExistance } from '../splitExistance'; import { IReadinessManager } from '../../../readiness/types'; import { WARN_NOT_EXISTENT_SPLIT } from '../../../logger/constants'; -describe('Split existance (special case)', () => { +describe('Split existence (special case)', () => { afterEach(() => { loggerMock.mockClear(); }); diff --git a/src/utils/inputValidation/__tests__/trafficType.spec.ts b/src/utils/inputValidation/__tests__/trafficType.spec.ts index bbea3d23..7a3b6bb3 100644 --- a/src/utils/inputValidation/__tests__/trafficType.spec.ts +++ b/src/utils/inputValidation/__tests__/trafficType.spec.ts @@ -59,7 +59,7 @@ describe('INPUT VALIDATION for Traffic Types', () => { const expectedLog = invalidTrafficTypes[i]['msg']; expect(validateTrafficType(loggerMock, invalidValue, 'test_method')).toBe(false); // Invalid traffic types should always return false. - expect(loggerMock.error.mock.calls[i]).toEqual([expectedLog, ['test_method']]); // Should log the error for the invalid traffic type. + expect(loggerMock.error.mock.calls[i]).toEqual([expectedLog, ['test_method', 'traffic_type']]); // Should log the error for the invalid traffic type. } expect(loggerMock.warn).not.toBeCalled(); // It should have not logged any warnings. diff --git a/src/utils/inputValidation/__tests__/trafficTypeExistance.spec.ts b/src/utils/inputValidation/__tests__/trafficTypeExistance.spec.ts index ba2f1666..293ccb84 100644 --- a/src/utils/inputValidation/__tests__/trafficTypeExistance.spec.ts +++ b/src/utils/inputValidation/__tests__/trafficTypeExistance.spec.ts @@ -57,7 +57,7 @@ describe('validateTrafficTypeExistance', () => { readinessManagerMock.isReady.mockImplementation(() => true); expect(validateTrafficTypeExistance(loggerMock, readinessManagerMock, splitsCacheMock, STANDALONE_MODE, TEST_EXISTENT_TT, 'test_method')).toBe(true); // If the SDK is in condition to validate but the TT exists, it will return true. - expect(splitsCacheMock.trafficTypeExists.mock.calls).toEqual([[TEST_EXISTENT_TT]]); // If the SDK is in condition to validate, it checks that TT existance with the storage. + expect(splitsCacheMock.trafficTypeExists.mock.calls).toEqual([[TEST_EXISTENT_TT]]); // If the SDK is in condition to validate, it checks that TT existence with the storage. expect(loggerMock.warn).not.toBeCalled(); // If the SDK is in condition to validate but the TT exists, it will not log any warnings. expect(loggerMock.error).not.toBeCalled(); // If the SDK is in condition to validate but the TT exists, it will not log any errors. }); @@ -65,7 +65,7 @@ describe('validateTrafficTypeExistance', () => { test('Should return false and log warning if SDK Ready, not localhost mode and the traffic type does NOT exist in the storage', () => { // Ready, standalone, and the TT not exists in the storage. expect(validateTrafficTypeExistance(loggerMock, readinessManagerMock, splitsCacheMock, STANDALONE_MODE, TEST_NOT_EXISTENT_TT, 'test_method_y')).toBe(false); // If the SDK is in condition to validate but the TT does not exist in the storage, it will return false. - expect(splitsCacheMock.trafficTypeExists.mock.calls).toEqual([[TEST_NOT_EXISTENT_TT]]); // If the SDK is in condition to validate, it checks that TT existance with the storage. + expect(splitsCacheMock.trafficTypeExists.mock.calls).toEqual([[TEST_NOT_EXISTENT_TT]]); // If the SDK is in condition to validate, it checks that TT existence with the storage. expect(loggerMock.warn).toBeCalledWith(WARN_NOT_EXISTENT_TT, ['test_method_y', TEST_NOT_EXISTENT_TT]); // If the SDK is in condition to validate but the TT does not exist in the storage, it will log the expected warning. expect(loggerMock.error).not.toBeCalled(); // It logged a warning so no errors should be logged. }); @@ -75,7 +75,7 @@ describe('validateTrafficTypeExistance', () => { const validationPromise = validateTrafficTypeExistance(loggerMock, readinessManagerMock, splitsCacheMock, STANDALONE_MODE, TEST_EXISTENT_ASYNC_TT, 'test_method_z'); expect(thenable(validationPromise)).toBe(true); // If the storage is async, it should also return a promise. - expect(splitsCacheMock.trafficTypeExists.mock.calls).toEqual([[TEST_EXISTENT_ASYNC_TT]]); // If the SDK is in condition to validate, it checks that TT existance with the async storage. + expect(splitsCacheMock.trafficTypeExists.mock.calls).toEqual([[TEST_EXISTENT_ASYNC_TT]]); // If the SDK is in condition to validate, it checks that TT existence with the async storage. expect(loggerMock.warn).not.toBeCalled(); // We are still fetching the data from the storage, no logs yet. expect(loggerMock.error).not.toBeCalled(); // We are still fetching the data from the storage, no logs yet. @@ -90,7 +90,7 @@ describe('validateTrafficTypeExistance', () => { const validationPromise2 = validateTrafficTypeExistance(loggerMock, readinessManagerMock, splitsCacheMock, STANDALONE_MODE, TEST_NOT_EXISTENT_ASYNC_TT, 'test_method_z'); expect(thenable(validationPromise2)).toBe(true); // If the storage is async, it should also return a promise. - expect(splitsCacheMock.trafficTypeExists.mock.calls).toEqual([[TEST_NOT_EXISTENT_ASYNC_TT]]); // If the SDK is in condition to validate, it checks that TT existance with the async storage. + expect(splitsCacheMock.trafficTypeExists.mock.calls).toEqual([[TEST_NOT_EXISTENT_ASYNC_TT]]); // If the SDK is in condition to validate, it checks that TT existence with the async storage. expect(loggerMock.warn).not.toBeCalled(); // We are still fetching the data from the storage, no logs yet. expect(loggerMock.error).not.toBeCalled(); // We are still fetching the data from the storage, no logs yet. diff --git a/src/utils/inputValidation/apiKey.ts b/src/utils/inputValidation/apiKey.ts index 0b891abf..86175189 100644 --- a/src/utils/inputValidation/apiKey.ts +++ b/src/utils/inputValidation/apiKey.ts @@ -1,4 +1,4 @@ -import { ERROR_NULL, ERROR_EMPTY, ERROR_INVALID, WARN_API_KEY, logPrefixInstantiation } from '../../logger/constants'; +import { ERROR_NULL, ERROR_EMPTY, ERROR_INVALID, WARN_API_KEY, LOG_PREFIX_INSTANTIATION } from '../../logger/constants'; import { ILogger } from '../../logger/types'; import { isString } from '../lang'; @@ -8,14 +8,14 @@ const item = 'api_key'; export function validateApiKey(log: ILogger, maybeApiKey: any): string | false { let apiKey: string | false = false; if (maybeApiKey == undefined) { // eslint-disable-line eqeqeq - log.error(ERROR_NULL, [logPrefixInstantiation, item]); + log.error(ERROR_NULL, [LOG_PREFIX_INSTANTIATION, item]); } else if (isString(maybeApiKey)) { if (maybeApiKey.length > 0) apiKey = maybeApiKey; else - log.error(ERROR_EMPTY, [logPrefixInstantiation, item]); + log.error(ERROR_EMPTY, [LOG_PREFIX_INSTANTIATION, item]); } else { - log.error(ERROR_INVALID, [logPrefixInstantiation, item]); + log.error(ERROR_INVALID, [LOG_PREFIX_INSTANTIATION, item]); } return apiKey; @@ -36,7 +36,7 @@ export function validateAndTrackApiKey(log: ILogger, maybeApiKey: any): string | log.warn(WARN_API_KEY, ['an instance of the Split factory']); } } else { - log.warn(WARN_API_KEY, [`${usedKeysMap[apiKey]} ${usedKeysMap[apiKey] === 1 ? 'factory' : 'factories'} with this API Key`]); + log.warn(WARN_API_KEY, [`${usedKeysMap[apiKey]} factory/ies with this API Key`]); usedKeysMap[apiKey]++; } } diff --git a/src/utils/inputValidation/event.ts b/src/utils/inputValidation/event.ts index 03e79c9e..98311224 100644 --- a/src/utils/inputValidation/event.ts +++ b/src/utils/inputValidation/event.ts @@ -3,15 +3,16 @@ import { ILogger } from '../../logger/types'; import { isString } from '../lang'; const EVENT_TYPE_REGEX = /^[a-zA-Z0-9][-_.:a-zA-Z0-9]{0,79}$/; +const item = 'event_type'; export function validateEvent(log: ILogger, maybeEvent: any, method: string): string | false { if (maybeEvent == undefined) { // eslint-disable-line eqeqeq - log.error(ERROR_NULL, [method]); + log.error(ERROR_NULL, [method, item]); } else if (!isString(maybeEvent)) { - log.error(ERROR_INVALID, [method]); + log.error(ERROR_INVALID, [method, item]); } else { // It is a string. if (maybeEvent.length === 0) { - log.error(ERROR_EMPTY, [method]); + log.error(ERROR_EMPTY, [method, item]); } else if (!EVENT_TYPE_REGEX.test(maybeEvent)) { log.error(ERROR_EVENT_TYPE_FORMAT, [method, maybeEvent]); } else { diff --git a/src/utils/inputValidation/eventProperties.ts b/src/utils/inputValidation/eventProperties.ts index 8a599a97..b2bf20e6 100644 --- a/src/utils/inputValidation/eventProperties.ts +++ b/src/utils/inputValidation/eventProperties.ts @@ -10,7 +10,7 @@ const ECMA_SIZES = { NUMBER: 8 }; const MAX_PROPERTIES_AMOUNT = 300; -const MAX_PROPERTIES_SIZE = 1024 * 32; +const MAX_EVENT_SIZE = 1024 * 32; const BASE_EVENT_SIZE = 1024; // We assume 1kb events without properties (avg measured) export function validateEventProperties(log: ILogger, maybeProperties: any, method: string): { properties: SplitIO.Properties | null | false, size: number } { @@ -55,7 +55,7 @@ export function validateEventProperties(log: ILogger, maybeProperties: any, meth else if (isBoolVal) output.size += ECMA_SIZES.BOOLEAN; else if (isStringVal) output.size += val.length * ECMA_SIZES.STRING; - if (output.size > MAX_PROPERTIES_SIZE) { + if (output.size > MAX_EVENT_SIZE) { log.error(ERROR_SIZE_EXCEEDED, [method]); output.properties = false; break; diff --git a/src/utils/inputValidation/trafficType.ts b/src/utils/inputValidation/trafficType.ts index 79f1eb02..01c64dbd 100644 --- a/src/utils/inputValidation/trafficType.ts +++ b/src/utils/inputValidation/trafficType.ts @@ -3,15 +3,16 @@ import { ILogger } from '../../logger/types'; import { isString } from '../lang'; const CAPITAL_LETTERS_REGEX = /[A-Z]/; +const item = 'traffic_type'; export function validateTrafficType(log: ILogger, maybeTT: any, method: string): string | false { if (maybeTT == undefined) { // eslint-disable-line eqeqeq - log.error(ERROR_NULL, [method]); + log.error(ERROR_NULL, [method, item]); } else if (!isString(maybeTT)) { - log.error(ERROR_INVALID, [method]); + log.error(ERROR_INVALID, [method, item]); } else { if (maybeTT.length === 0) { - log.error(ERROR_EMPTY, [method]); + log.error(ERROR_EMPTY, [method, item]); } else { if (CAPITAL_LETTERS_REGEX.test(maybeTT)) { log.warn(WARN_LOWERCASE_TRAFFIC_TYPE, [method]); diff --git a/src/utils/inputValidation/trafficTypeExistance.ts b/src/utils/inputValidation/trafficTypeExistance.ts index eb64c0d3..99d9f705 100644 --- a/src/utils/inputValidation/trafficTypeExistance.ts +++ b/src/utils/inputValidation/trafficTypeExistance.ts @@ -19,17 +19,15 @@ export function validateTrafficTypeExistance(log: ILogger, readinessManager: IRe // If not ready or in localhost mode, we won't run the validation if (!readinessManager.isReady() || mode === LOCALHOST_MODE) return true; - const res = splitsCache.trafficTypeExists(maybeTT); + const res = splitsCache.trafficTypeExists(maybeTT); // never rejects or throws error if (thenable(res)) { - res.then(function (isValid) { + return res.then(function (isValid) { if (!isValid) logTTExistanceWarning(log, maybeTT, method); - return isValid; // propagate result }); } else { if (!res) logTTExistanceWarning(log, maybeTT, method); + return res; } - - return res; } diff --git a/src/utils/jwt/__tests__/index.spec.ts b/src/utils/jwt/__tests__/index.spec.ts index 35d27390..7073739b 100644 --- a/src/utils/jwt/__tests__/index.spec.ts +++ b/src/utils/jwt/__tests__/index.spec.ts @@ -1,4 +1,4 @@ -import { jwtSample, decodedJwtPayloadSample } from '../../../sync/streaming/AuthClient/__tests__/dataMocks'; +import { jwtSample, decodedJwtPayloadSample } from '../../../sync/streaming/__tests__/dataMocks'; import { decodeJWTtoken } from '..'; test('decodeJWTtoken', () => { diff --git a/src/utils/lang/__tests__/errors.spec.ts b/src/utils/lang/__tests__/errors.spec.ts deleted file mode 100644 index a4a383e1..00000000 --- a/src/utils/lang/__tests__/errors.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { SplitError, SplitNetworkError, SplitTimeoutError } from '../errors'; - -test('LANG UTILS / errors', () => { - const splitErrorInst = new SplitError(); // This one should not be used directly, so only testing default message - let splitNetErrorInst = new SplitNetworkError(); - let splitTimeErrorInst = new SplitTimeoutError(); - - expect(splitErrorInst.message).toBe('Split Error'); // The errors should have a default message. - expect(splitNetErrorInst.message).toBe('Split Network Error'); // The errors should have a default message. - expect(splitTimeErrorInst.message).toBe('Split Timeout Error'); // The errors should have a default message. - - splitNetErrorInst = new SplitNetworkError('NETWORK_ERR', 341); - - expect(splitNetErrorInst.message).toBe('NETWORK_ERR'); // Split Network Error should store params (message) correctly - expect(splitNetErrorInst.statusCode).toBe(341); // Split Network Error should store params (status code) correctly - expect(splitNetErrorInst instanceof SplitNetworkError).toBeTruthy(); - expect(splitNetErrorInst instanceof SplitError).toBeTruthy(); // All custom errors should extend from the root one - expect(splitNetErrorInst instanceof Error).toBeTruthy(); // All custom errors should extend from the native one. - - splitTimeErrorInst = new SplitTimeoutError('TIMEOUT_ERR'); - - expect(splitTimeErrorInst.message).toBe('TIMEOUT_ERR'); // Split Network Error should store params (message) correctly - expect(splitTimeErrorInst instanceof SplitTimeoutError).toBeTruthy(); - expect(splitTimeErrorInst instanceof SplitError).toBeTruthy(); // All custom errors should extend from the root one. - expect(splitTimeErrorInst instanceof Error).toBeTruthy(); // All custom errors should extend from the native one. - -}); diff --git a/src/utils/lang/__tests__/index.spec.ts b/src/utils/lang/__tests__/index.spec.ts index 51a62ccc..613ad573 100644 --- a/src/utils/lang/__tests__/index.spec.ts +++ b/src/utils/lang/__tests__/index.spec.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { startsWith, endsWith, @@ -32,7 +33,6 @@ test('LANG UTILS / startsWith', () => { expect(startsWith('myStr', ' yS')).toBe(false); expect(startsWith('myStr', null)).toBe(false); expect(startsWith(false, null)).toBe(false); - // @ts-ignore expect(startsWith()).toBe(false); expect(startsWith(null, 'ys')).toBe(false); @@ -55,7 +55,6 @@ test('LANG UTILS / endsWith', () => { expect(endsWith('myStr', 'str', false)).toBe(false); expect(endsWith('myStr', null)).toBe(false); expect(endsWith(false, null)).toBe(false); - // @ts-ignore expect(endsWith()).toBe(false); expect(endsWith(null, 'ys')).toBe(false); @@ -93,12 +92,10 @@ test('LANG UTILS / get', () => { test('LANG UTILS / getGlobal', () => { // positive expect(getGlobal('console')).toBe(console); // If the global property exists, return it. - // @ts-ignore global.something = 'something'; expect(getGlobal('something')).toBe('something'); // If the global property exists, return it. // negative - // @ts-ignore expect(getGlobal()).toBe(undefined); expect(getGlobal(null)).toBe(undefined); // If the passed value is an invalid key type (neither a number or a string), return undefined. expect(getGlobal('non-existent-property')).toBe(undefined); // If the global property doesn't exist, return undefined. @@ -107,13 +104,9 @@ test('LANG UTILS / getGlobal', () => { test('LANG UTILS / findIndex', () => { const arr = [1, 2, 3, 4, 3]; - // @ts-ignore expect(findIndex()).toBe(-1); // If the parameters for findIndex are wrong it returns -1. - // @ts-ignore expect(findIndex(null, () => { })).toBe(-1); // If the parameters for findIndex are wrong it returns -1. - // @ts-ignore expect(findIndex({}, () => { })).toBe(-1); // If the parameters for findIndex are wrong it returns -1. - // @ts-ignore expect(findIndex({}, false)).toBe(-1); // If the parameters for findIndex are wrong it returns -1. expect(findIndex(arr, () => false)).toBe(-1); // If no element causes iteratee to return truthy, it returns -1. @@ -128,7 +121,6 @@ test('LANG UTILS / findIndex', () => { }); test('LANG UTILS / find', () => { - // @ts-ignore expect(find()).toBe(undefined); // We cant find the element if the collection is wrong type, so we return undefined. expect(find(null, () => true)).toBe(undefined); // We cant find the element if the collection is wrong type, so we return undefined. @@ -157,11 +149,12 @@ test('LANG UTILS / find', () => { }); test('LANG UTILS / isString', () => { + // positive expect(isString('')).toBe(true); // Should return true for strings. expect(isString('asd')).toBe(true); // Should return true for strings. expect(isString(new String('asdf'))).toBe(true); // Should return true for strings. - // @ts-ignore + // negative expect(isString()).toBe(false); // Should return false for non-strings. expect(isString(null)).toBe(false); // Should return false for non-strings. expect(isString([])).toBe(false); // Should return false for non-strings. @@ -171,12 +164,13 @@ test('LANG UTILS / isString', () => { }); test('LANG UTILS / isFiniteNumber', () => { + // positive expect(isFiniteNumber(1)).toBe(true); // Should return true for finite numbers. expect(isFiniteNumber(-0.5)).toBe(true); // Should return true for finite numbers. expect(isFiniteNumber(Number(0.5))).toBe(true); // Should return true for finite numbers. expect(isFiniteNumber(new Number(4))).toBe(true); // Should return true for finite numbers. - // @ts-ignore + // negative expect(isFiniteNumber()).toBe(false); // Should return false for anything that is not a finite number. expect(isFiniteNumber(Infinity)).toBe(false); // Should return false for anything that is not a finite number. expect(isFiniteNumber(-Infinity)).toBe(false); // Should return false for anything that is not a finite number. @@ -192,11 +186,12 @@ test('LANG UTILS / isFiniteNumber', () => { }); test('LANG UTILS / isNaNNumber', () => { + // positive expect(isNaNNumber(NaN)).toBe(true); // Should return true for NaN numbers of "number" type. expect(isNaNNumber(Number(NaN))).toBe(true); // Should return true for NaN numbers of "number" type. expect(isNaNNumber(new Number(NaN))).toBe(true); // Should return true for NaN Number objects. - // @ts-ignore + // negative expect(isNaNNumber()).toBe(false); // Should return false for anything that is not a NaN number. expect(isNaNNumber(Infinity)).toBe(false); // Should return false for anything that is not a NaN number. expect(isNaNNumber(-Infinity)).toBe(false); // Should return false for anything that is not a NaN number. @@ -211,12 +206,13 @@ test('LANG UTILS / isNaNNumber', () => { }); test('LANG UTILS / isIntegerNumber', () => { + // positive expect(isIntegerNumber(1)).toBe(true); // Should return true for integer numbers of "number" type. expect(isIntegerNumber(Number.MIN_SAFE_INTEGER)).toBe(true); // Should return true for integer numbers of "number" type. expect(isIntegerNumber(Number(4))).toBe(true); // Should return true for integer numbers of "number" type. expect(isIntegerNumber(new Number(4))).toBe(true); // Should return true for integer Number objects. - // @ts-ignore + // negative expect(isIntegerNumber()).toBe(false); // Should return false for anything that is not an integer numbers. expect(isIntegerNumber(Infinity)).toBe(false); // Should return false for anything that is not an integer numbers. expect(isIntegerNumber(-Infinity)).toBe(false); // Should return false for anything that is not an integer numbers. @@ -234,12 +230,14 @@ test('LANG UTILS / isIntegerNumber', () => { }); test('LANG UTILS / isObject', () => { + // positive expect(isObject({})).toBe(true); // Should return true for map objects. expect(isObject({ a: true })).toBe(true); // Should return true for map objects. expect(isObject(new Object())).toBe(true); // Should return true for map objects. expect(isObject(Object.create({}))).toBe(true); // Should return true for map objects. expect(isObject(Object.create(Object.prototype))).toBe(true); // Should return true for map objects. + // negative expect(isObject([])).toBe(false); // Should return false for anything that is not a map object. expect(isObject(() => { })).toBe(false); // Should return false for anything that is not a map object. expect(isObject(true)).toBe(false); // Should return false for anything that is not a map object. @@ -435,20 +433,17 @@ test('LANG UTILS / uniqAsStrings', () => { const stringifier = (value: any) => { return Object.keys(value).sort().join(','); }; // returns a string with the ordered keys of the passed object expect(uniqAsStrings([{ a: '3' }, { a: '3', b: '2' }, { a: '3' }, { b: '2', a: '3' }], stringifier)).toEqual([{ a: '3' }, { a: '3', b: '2' }]); // uniqAsStrings should remove all duplicate values from array. - // @ts-ignore expect(() => { uniqAsStrings({}); }).toThrow(); // uniqAsStrings should be called with an array. }); test('LANG UTILS / toString', () => { - // @ts-ignore expect(typeof toString()).toBe('string'); // It should ALWAYS return a string. expect(typeof toString(null)).toBe('string'); // It should ALWAYS return a string. expect(typeof toString(250)).toBe('string'); // It should ALWAYS return a string. expect(typeof toString('asdad')).toBe('string'); // It should ALWAYS return a string. expect(typeof toString(/regex/)).toBe('string'); // It should ALWAYS return a string. - // @ts-ignore expect(toString()).toBe(''); // And the returned string should be correct expect(toString('it is just me')).toBe('it is just me'); // And the returned string should be correct expect(toString(5)).toBe('5'); // And the returned string should be correct @@ -466,7 +461,6 @@ test('LANG UTILS / toNumber', () => { expect(typeof toNumber('asdad')).toBe('number'); // It should ALWAYS return a number. expect(typeof toNumber(/regex/)).toBe('number'); // It should ALWAYS return a number. - // @ts-ignore expect(Number.isNaN(toNumber())).toBe(true); // The returned number should be NaN for values that cannot be converted expect(Number.isNaN(toNumber(/regex/))).toBe(true); // The returned number should be NaN for values that cannot be converted expect(Number.isNaN(toNumber({}))).toBe(true); // The returned number should be NaN for values that cannot be converted @@ -522,9 +516,7 @@ test('LANG UTILS / groupBy', () => { expect(groupBy(true, 'team')).toEqual({}); // If the input is empty or wrong type, it will return an empty object. expect(groupBy('string', 'team')).toEqual({}); // If the input is empty or wrong type, it will return an empty object. expect(groupBy({}, 'team')).toEqual({}); // If the input is empty or wrong type, it will return an empty object. - // @ts-ignore expect(groupBy({ something: 1 }, null)).toEqual({}); // If the input is empty or wrong type, it will return an empty object. - // @ts-ignore expect(groupBy({ something: 1 })).toEqual({}); // If the input is empty or wrong type, it will return an empty object. }); diff --git a/src/utils/lang/errors.ts b/src/utils/lang/errors.ts deleted file mode 100644 index 75cf7ad8..00000000 --- a/src/utils/lang/errors.ts +++ /dev/null @@ -1,32 +0,0 @@ -// Simplified version of https://github.com/wesleytodd/setprototypeof/blob/master/index.js -const setPrototypeOf = Object.setPrototypeOf || function (obj, proto) { obj.__proto__ = proto; return obj; }; - -export class SplitError extends Error { - constructor(msg = 'Split Error') { - super(msg); - this.message = msg; - - // Required when extending a native constructor and transpiling to ES5 - // See https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work - setPrototypeOf(this, SplitError.prototype); - } -} - -export class SplitTimeoutError extends SplitError { - constructor(msg?: string) { - super(msg || 'Split Timeout Error'); - setPrototypeOf(this, SplitTimeoutError.prototype); - } -} - -export class SplitNetworkError extends SplitError { - - // HTTP error status code, or undefined if it is not an HTTP error - statusCode?: number; - - constructor(msg?: string, code?: number) { - super(msg || 'Split Network Error'); - this.statusCode = code; - setPrototypeOf(this, SplitNetworkError.prototype); - } -} diff --git a/src/utils/lang/index.ts b/src/utils/lang/index.ts index 6074a1c1..340d3ccc 100644 --- a/src/utils/lang/index.ts +++ b/src/utils/lang/index.ts @@ -89,7 +89,7 @@ export function get(obj: any, prop: any, val: any): any { /** * Parses an array into a map of different arrays, grouping by the specified prop value. */ -export function groupBy(source: any, prop: string): Record { +export function groupBy >(source: T[], prop: string): Record { const map: Record = {}; if (Array.isArray(source) && isString(prop)) { diff --git a/src/utils/lang/sets.ts b/src/utils/lang/sets.ts index bcdd022c..6ecb157d 100644 --- a/src/utils/lang/sets.ts +++ b/src/utils/lang/sets.ts @@ -104,7 +104,7 @@ interface ISetConstructor { */ export function __getSetConstructor(): ISetConstructor { // eslint-disable-next-line compat/compat - if (Array.from && typeof Set === 'function' && Set.prototype && Set.prototype.values) { + if (typeof Array.from === 'function' && typeof Set === 'function' && Set.prototype && Set.prototype.values) { return Set; } return SetPoly; diff --git a/src/utils/murmur3/__tests__/mocks/murmur3_86_uuids.csv b/src/utils/murmur3/__tests__/mocks/murmur3_86_uuids.csv new file mode 100644 index 00000000..287abf27 --- /dev/null +++ b/src/utils/murmur3/__tests__/mocks/murmur3_86_uuids.csv @@ -0,0 +1,10000 @@ +d4a54f9e-f21c-0988-bcc8-e89da126ff2d,572008525,6110769680312780039 +d37fc58c-1037-7431-3cee-03426979dd8e,4164581979,11951443564137380472 +92bd9de9-3e9d-6756-6020-c304eec1105b,834179676,6521191437051114291 +04242919-7259-c375-415a-819dc78f069b,1281492683,11624151202307826664 +7effb24e-cc24-94c3-9c02-b229d6fe5912,1654206287,17515355730787830281 +903420ab-41fb-700f-9b80-630be9ae6fab,2539827769,4748916454346960012 +73a48474-ad55-432c-e814-72e7138e92fb,3711496963,4158959184796757093 +650d17a7-13a8-1dc4-5207-b037155d7ddd,3881768690,16078635943815928471 +002da80f-2874-4c3a-3123-9d299857be0a,3695857284,14421021020809728893 +2db99d28-0151-2cdc-32bd-89ba863ac96f,131324347,13610619508425419599 +b60b9a0e-d1b2-1fa1-5c1b-bd33cded8086,4232273712,1735637088762833411 +aa27d5df-83ea-10cd-a4ac-103e701fe984,2659416369,10075660319729239292 +8b8c06cb-b964-8fa0-cf6a-87cfabe5063a,3170763384,12019499630719827728 +d6c28c78-429f-3fe0-5298-e31253017d77,3307510501,7536749457398765968 +ce68fe0a-f737-788d-d02d-b6135a3bad45,2224726756,16385898734448800912 +59e21f39-e338-c87d-d409-38aa95d197f7,2358482912,17338517665879570430 +a0e2d55c-7105-2e25-8f6f-bd2caa15ed61,2947432973,16864144094594945306 +ad271ab2-a5b9-7914-f14e-12ba0b9aead8,2872868023,13183944309034098153 +95ad42e9-a82b-2497-9f64-c2ef8ca6f7d1,2092831961,13791114210372761095 +2dd5e9f1-c438-22c7-ab52-e6b63ba96de4,243472212,8325961748031818171 +d2b85cde-0e06-04bb-bbe3-0b455b8a70f2,1556243367,3740769227826616178 +9fbdb977-22ac-8545-fcac-a393f13cd391,2964441184,9026286771441902056 +0c90c03e-a7b9-2354-1cc4-03455d55064f,664473457,16616431203056497209 +3a25073d-8acd-fd0c-77ca-cabe9bbf2ee2,451046140,15026085476621529029 +7cab66eb-3900-6c5e-ef65-48fb72177738,1419494605,14007620125094865074 +0e6a5de5-62d1-4469-3e4b-bfbee623e422,2527770838,6437992571180654186 +b93c6f2a-97ab-b6dd-9516-627dd2e6584d,3640358391,8968042437174876802 +fabea4c3-946a-b7b9-f734-5a161ca00f9d,25651457,15778762564457029284 +3e78935a-da64-f52c-07a4-9b590ebd9997,231127444,1477103003870813632 +13b7a26b-5b38-1411-a753-271f1373311c,219052932,15585597177397388509 +58c345c5-0dc7-145f-b998-af41f9d05c5f,3282203814,13938294911937099893 +23e1e994-db6c-dc7c-453b-81470aacb410,1313424997,8827652388504993981 +f6574ef4-eefa-01aa-f849-9423f77b0fd6,1920720379,15135750343001570779 +25256927-52e1-46ab-e485-7c5ecfcbd962,2861211123,7228689118696639643 +6cd3053f-53ff-d3a6-0a0b-81a3a2bd9d95,891573851,14095614401064479831 +6af221f6-c14e-08f1-0011-81a1fda7ad75,3389906649,12895569853495670094 +4494c47f-c79e-3a94-ea73-247f827985a4,2114124684,3593790374077401577 +981e5700-24f3-623a-250b-a7e31592519d,3538730704,18434329787190665237 +6d04c277-4b50-7fef-3ec3-eb7b6b55e285,3277413154,10664477280267924328 +0ebf2849-fcfd-291b-5a4b-30553a239a61,3449525661,11531115310881941062 +1fca4498-443d-e6cc-1411-515a0023f176,735702659,5603065018432516928 +5f83f43e-82ad-fbbb-5a9b-9d07151ba58c,3723386557,951073065887448214 +4535653f-fdf5-c963-4c9e-53f6231237a1,805478918,13834191545195498866 +f81044c4-f05a-bdb9-e7a9-38c49f74ea45,1587765005,2012955415412816891 +9bc85c35-2c70-6193-7327-4a8c7cc6e8bb,534096939,14814165426867102771 +40269280-7cb3-75a6-1117-c76784ffba0c,4146278695,13032939822837403572 +431fc362-21be-f205-9953-76e68dc25241,2174155412,6800609813657331379 +fc7cda4f-de9e-7e7f-62a0-f782b26493e7,2704683504,1836509424651348083 +3526d4bf-e658-c701-45d4-d8023f5cd8d3,4010876178,18053895776109965919 +7127a7bd-b884-86b8-15e6-1f24b172166a,4034492745,6639238365325412744 +fce3bd25-a196-c641-26b2-ef685cdcc389,850328618,2850557489867056504 +a6c98eb8-4467-a5e2-660d-591168bac82c,1747579497,2603632599240934080 +f71ed75e-b76f-c6cc-fa24-c7f5b789d802,3471539634,15426031105526821351 +a0f290bb-bbb1-6417-675c-e51ab5530c6f,4260160582,16318365611039628900 +f33994a7-27f0-d41e-e0bb-64a8db92f4cf,789982897,5627716230030979071 +997af189-a491-31dd-96d9-4c3323b2836a,4222325228,2718006380727985819 +ced335bc-e50c-2c7b-d8c4-0689e24217c4,1382900212,2963258459539661954 +5aff02da-5366-b993-dcd1-3048b5a6c758,2834638765,14157408770736027667 +3e261b4c-577a-d7d6-1142-bfc9a4c14b9c,797859111,9083544606452081763 +d5798960-5abf-5d59-5776-7709b8b5a143,1938299602,15864725264242373257 +11792af1-4e45-1e05-dbd0-68f74396c4fd,953335631,12937609759299565176 +e8de0af1-e528-dd4e-0a0a-315e1bbb47cb,1477102656,6803047079640003590 +93e24216-ed73-d891-ac52-1d0fae7a81fe,745787363,16250825406789648589 +ee7e030a-8a27-9a4c-d29d-20475e1884e1,471291089,13896594461305347796 +b3b9609a-9ee5-5200-0923-e90623408ae9,2547125905,9491865599752642657 +9ff6b679-14e4-24c8-a52b-ccb5691148c7,2474740247,15024398727503542865 +dbfa7d42-e484-4845-aecb-2289ef21fd01,243912091,1372274219717515911 +1d1d1e7f-6efd-a6df-d344-0ca409625499,2982631495,12846036845666019944 +47f4b325-41fa-f1d6-9fc4-7972ac945358,3169714675,17269890794755951979 +270b793b-85ec-973d-740a-d6ac39780031,1328548839,10425194033778738297 +415be986-f35b-7beb-d94b-2b5484b4ddd2,205794869,10031360501332530022 +9b31da17-65e0-3f0a-2b84-3f5869c0e634,3903596548,8135959220925945448 +0b4834b1-f7c6-9beb-0dae-35e377a5310d,3632987778,7703596245154917347 +12c55fc1-61db-9203-070c-cada3b532734,923009852,12568970089567305631 +506b80f7-d52b-91c9-7744-6320cd897514,2250696931,10222982395374936548 +13829fe5-cd35-c29f-6754-ab39b270b9bc,89461565,3780642068297662899 +2b1727cd-5651-9e05-2cd9-7f5ff4290e25,2813252572,9351764614575524523 +c1ab6eb6-bc14-aa31-2579-66256f8b2036,1221532356,8587576694411269605 +3e3bb83e-fe4c-5dbb-5ccf-2fff8037c810,2529305952,9535016289104292122 +d4117ce3-bb07-f63f-8337-e7bb8aabac7f,2409227254,10603682998588707688 +b49fd9b9-efaf-122a-6bdd-359a51c1e6ce,2745223350,4720702529687986254 +c9808773-52e9-31b9-2828-59f8a87b94c8,1034857454,1082393566351213171 +1f4984fa-0800-076c-cd14-98ec35590ebf,925687488,5795072768010566870 +61e3a2b9-6e72-57e7-abb3-b6642e04e18a,174168821,2212146776777814906 +92af2d05-448e-02a8-2956-65a4b97a04bb,27292304,1507919516693427818 +051e65eb-8ffa-afc2-8cbf-c51eb7e84046,2958359173,6234228223196626897 +a1097b5b-fa72-8290-a5e5-4e3f7b85edbf,2398851142,11217177613832380574 +84b1c94b-8588-18c3-7c7a-a9a0e2cdd6be,723475327,14410651180552238409 +9ddd0dda-941c-2da6-dc75-4d75e3efba4f,1916974770,7975517106874244439 +e3ee6dfc-beb0-1153-61fd-c4a1c173ac95,3779654817,4429028600606595783 +dfa84446-f880-3465-60c4-d6c4774fdaa0,4239550761,16224168269144047830 +3bc7decc-8298-4d33-5b43-c489fbd936ad,192788597,9079703930021675129 +0286afd9-3ec6-9b45-f019-2ea9734be8fd,2782252641,12311044188492560886 +f8b6b965-bc06-826d-318d-cba9026a5a1d,1968842709,13188615772528556694 +962d08e5-0e72-f478-cb64-4fdcbde2f259,3774521966,8872090316205972053 +c5cc7a19-f441-a629-1b42-577b1ead7131,4140728323,15128037282167073728 +bc8497df-50d5-6cba-d1a4-9fa8daa2a174,4173310189,3536453024399711317 +b28831dd-7dac-aa12-dfee-4c93245841b5,6439639,8079967594791246923 +d2049679-b0dd-5630-690c-168f774d392e,89198147,13410621222603863127 +2729e1eb-9aff-73eb-25c3-0dcf6f445b35,1512562349,6657516799837946038 +f1af56a1-a355-3696-d715-2592050d0428,1781886991,292701526608530807 +3a273ecf-d86c-781f-46a4-1a61dc62a074,2948452345,1814994012980786948 +22fb0253-9a6c-f4ff-f730-79c722a2b152,103186744,17743885859573385090 +dd0e1b3e-e7f2-6e00-0e93-784745c804a8,2549537664,3485107529088992904 +398bb6de-66f5-b56a-db36-581262ca4f6a,1213951991,2686258663298480477 +d8918a56-68cb-812a-90ca-5f16e6407481,4248919027,10943170681903136659 +e7118548-d66f-8a9a-bcde-1adc602c5d0f,1369328405,9014527485617625905 +3510b94c-6715-29ce-a3ef-795e045dcece,3180769216,9403334992504306610 +0de5124a-563d-cc42-eacc-ef3583fee605,756062226,13734442449303511586 +01b6e2b8-e32f-dcec-8757-85bf093b2a2e,2562323741,9426024825518264087 +d0a88675-f7eb-bcb1-bbe3-c4a6bbeb22ba,2186868918,9753610423884826181 +5218337d-7dd5-39e1-cf2c-7d613e506145,2994650164,14187635336348946445 +1fd94a88-e975-da9f-b4e8-d357f98f3665,2608613472,13278152499682684526 +15881f75-4e42-d9ca-78a0-77cca15d9dd3,720488490,954848535188394438 +a6e44f12-910a-a6f5-0979-0c55ac87a01a,441032980,5834761742826089216 +b9cae979-016b-5559-b734-9ffc97e5cb4c,1294203818,6160021562930596171 +ddb8df76-e3e3-1629-f411-90bba2ab6b2d,562493824,8754882671493246036 +2a2d1510-e627-2b52-e06a-a92ab9f7e48b,2255125327,5634188235137559440 +27c43443-a4cd-0ebf-76a7-6fed96a40d09,4225263772,3720085863578308976 +c0b946a5-c90c-1605-5c7e-f8971fe6f70f,3777505029,16036995156229967249 +44b2f4d0-98b6-f34e-1ef7-22f010d2b627,3850338653,11637511597807476061 +c5c4aee3-702b-481a-97ee-0781517e980a,89181772,16570302944786701195 +70f44c08-9f7d-db78-70b7-d731ffeed493,3665497153,3159218070692154597 +48556661-2fe0-7557-559f-56ac46675e7a,1141224319,4886068688429608008 +1cc74dca-a6f3-3e16-f0d6-aa2a3b4b6002,2406926676,90106159773718615 +43b312b3-1f7b-be9d-adff-68053911fe80,3412830058,10460575761238287449 +3df19c3f-0859-e6a9-775b-1703cbdb7492,3413323537,2572647050174715384 +65364246-03a1-403a-983a-24d96469d330,3176406699,7918014503628737138 +4df5a8cd-f2f9-76bf-a61e-c745f06254df,3128995098,2237848883135832258 +98d069c8-7983-a606-0d2d-e0316e164307,2671651659,14065439130604171443 +fb1bdf12-79c9-0533-2019-4906a2c69262,945778795,4507776024720458247 +70d337c4-e692-985c-d724-aa00f86c9cab,3152974945,6381140575419600190 +e4f21110-7123-7526-0233-dc114b19e076,1863319659,12215870986886901064 +caeb293f-869f-750a-39f7-1b029453daa5,720644639,14036664169219113709 +8a61225e-bbfe-2739-1eb4-2c90698dc9ae,3290998422,18054586122416800064 +beb2eb5c-88e6-d208-2679-0d7e3af9e6d8,952469850,4238065208086612103 +b0a62188-1417-0cdb-7eb4-0ad81e931958,467987846,3386278304718196359 +23c0f104-1a67-0747-d572-be3801efd1ba,2412172023,4303450617369245532 +f28a37a7-6f51-1562-d58d-52ac7dbb75af,3758681382,8655377841190135733 +ffad8bd3-5ec9-d9da-6c64-5f6cc66fd291,4131480030,15897669890218010730 +91d92931-3283-fc71-8887-01e665c1470c,691892354,17583334213471329586 +4c96fc05-8ea5-e745-60f3-701c7b81fa08,1576913519,16500572831432450878 +07f312a8-9f3a-97d2-5c0e-c636fbafc535,2922255229,15858246961302994344 +23971cc7-1bd0-1a70-eae9-d157ab2183bc,879506936,5951046717783431528 +664a373a-ba45-fcd6-5909-9622b4c27ad0,1413751368,5206701727331705809 +1fc1c19a-93c2-d789-04a4-aae7575c6393,1309015557,2957335615855777231 +62953524-09bd-a853-d02b-1174b834427d,4290586552,18434871909940703716 +19bf581c-6e21-8d62-c21f-1f8244026137,684206723,11316388959895161025 +041c0877-28e7-69a4-bbbc-c6c192806ee5,1050869753,919188375348944608 +f09e433d-0f50-07e9-e8fd-0100c8c0f9a4,3512326689,2177480390508745280 +c5184cac-a122-5830-af33-0b8eb61d3fc5,1351280051,6067887123618139194 +ce2da986-d5ee-6133-5b65-a9bf307f9517,2114379210,11456761596372511389 +dc00a6d5-fd78-af84-a729-3e82683b4e59,2650431095,12430072767625227248 +619193eb-7096-8810-8a52-fd3c870ea23c,216799690,4120066397623368263 +462d7332-f419-3710-700d-931ff4940274,1928597509,17655492965161092740 +9cde9ab0-1bb9-5e90-1f9a-24af4ddbdd54,534403519,12880495304150899193 +743fbd36-18d3-fc8c-22e2-51c99b4b80b8,555160233,7328132803344035186 +109f32e1-d852-64d9-4b39-c5dcdfc4ef53,1364679224,2819661580276117815 +4ce115b3-ce71-98ef-cc0c-e6997f2c1a14,1700041510,17744609210287439046 +3bcf62d6-d448-3344-e795-f6b506b56c3e,4073752286,10589516690185181220 +4827e151-4076-1f70-739f-d69e6c5c225f,3083768274,16808088896448163775 +0c418115-7a3d-b8d8-bb4e-09ae507448c0,3826760116,13249138125785352920 +0c13eb2c-9b6a-a053-5b3f-5d0ba33fb089,4142962976,13425872843717176114 +e94a77ae-cfae-fc24-f301-ecff215cac76,1776181759,6637995112133226199 +1479d56f-cfba-8d64-a3cd-ea2d3df68f19,3910166530,2429771408042063591 +8747301f-3628-d148-5a92-bafce4aef464,4019454994,12039001515258931788 +93924d79-5c11-4bc6-f5b0-42e7eacda890,3139801433,3791033996064640991 +482e4f3d-05c4-8ab8-ed0a-3ab0e6c7b891,2116653219,4052679207738689668 +417c7553-0bdb-040f-46c1-9361717c3ff1,1102696967,11103786694474178846 +1e86c322-de7b-5f76-3702-6e43e6dceb14,1116770907,18334982877397743861 +dc96cc73-cbba-c43f-2ac1-9d64c03de1cd,451956168,17950656278775831188 +3c938e61-e69f-985f-8fda-25ad72df5271,2368382577,3281276154185916162 +163bd192-4274-9516-32f9-f144f37ccbbc,856438549,11013114143940515259 +58bd2c93-f84e-35d0-be60-67f8ae1da82d,2057076398,8538622891164271423 +22308932-2cba-e2d0-5758-42e39b5c21c1,401984817,17463164966459199896 +55b7955b-dbf9-408d-f583-96b505bedd51,4020992489,7819335307121915491 +9e464499-80d7-ebe2-629a-510cdd8d93a1,1270104604,7713906659295428800 +6a368ab5-0814-103c-5551-82a90b138bde,2086314513,12667969944839565034 +21c30657-bb11-a1a1-f8db-196a0a0b4023,4090464420,346555091295075514 +8e56e57d-ca1c-fe61-7dec-8dfd6939eb10,3629609864,2744065420635778813 +d9d275d7-55da-310b-0412-a0c0e10e5375,2901541198,12915684799710766868 +8c1e0680-892c-1f01-5948-3a65490b4c0b,4286368509,16417910253385495330 +182123de-98c6-621c-a43c-c1eee54c0804,3867453479,14113173817697533630 +b624bfc8-60a5-6afd-3dc0-6afe1cccb06c,829663147,4268409706304552379 +d1f401d7-99e5-be1a-fa7f-0d822e19f336,2956005646,5776991213273461395 +ce14d0cb-0d6a-a075-02c3-3fa14ed4fbc2,179472691,1950494332928133536 +8c38b355-bcc1-db71-7854-0ccfb8ec7ac8,502975054,5966856830155413332 +9337f099-efd6-fd96-64c8-5b1ecba8bdc9,3010948339,13174891068890261794 +0b03f9ae-462e-f6e8-e7b7-7ea7eee21383,2489590048,4250461178231264192 +4f63e6fc-c3dc-c25a-a8dc-0b45512f657b,1980785694,16160583630332969507 +f2e8c38c-de01-49ab-5e5e-ee6079250e34,531765430,944637152283898459 +0321b281-e228-24cb-9968-6414b6c1ba41,2446892502,5922221363832021707 +f252f271-a07a-2604-0a3e-8f89055882de,32491960,15673596569924026692 +48f11a44-5672-b3f7-7839-4c54427e8c21,1883573966,2730652851970183657 +990f3dc9-448c-53b1-761a-5ea4a8199b22,33844643,10941452030525597268 +dfc42596-93af-3146-9985-bdf37b65357a,1107823758,5798762438472465801 +7dc4fe6c-b240-5c07-4d16-48d3e10b6430,3627262043,10725258450875420981 +ea3eac99-dcec-0338-af94-24a9c8fdbb86,732580087,4877700428070589489 +ed7b61ea-a86a-d567-1fd5-3c8d6f873ab6,640620677,10410241668943597061 +fed81881-f072-0f1e-9d00-508fd03be941,358113503,946683631627302856 +0e26de7d-be51-6428-ce43-ba97c6842782,879695982,17221902682568325146 +60fd032a-999f-b2d5-cb2b-8327db4ba39a,487199974,365993903571137853 +d03a2603-5901-cb91-f14d-25ff3e218b4c,2308855488,6650477266754928191 +6943bb0d-c7b6-d9d9-4b0b-750a86120e7f,1984901117,15494156324269941918 +800095e6-694e-e80c-e6de-feec59a81b72,91765828,16909047312674667088 +44b178fd-2f3c-33b1-0749-9d90e742ddb1,527857131,11625309250986666250 +db5ed6cb-4b4d-fa15-a1a9-0bda17d6cbe8,157523174,5192415953969085303 +5928b73c-35fb-b146-f22f-949f33ba990e,2268534374,14560739439232394232 +4fd2ddb1-e726-0ed5-14b3-0018446e2010,730374345,12689355252548468980 +6e51e313-f24e-71af-08ef-1cc144944bf8,529542717,4323779605872218641 +a7588826-9702-ecf1-109e-cf00f23be1fc,2373680561,2972808440489596325 +43b9a8c3-f837-986b-41fd-c3460458e8f4,3121673605,7529094438978813366 +f7c1ee32-11b4-5f66-6df9-c441a9b59a1e,2556719246,16533044252066423899 +fcd04980-7574-ebc4-5e6f-4804e5ffd29e,2355444259,15658610855163211664 +26d702f6-5453-d641-6684-b23a2649d183,2148428378,14313682128640151183 +1c3a1feb-f29a-dce3-1af2-43746f8b5b5d,2063858552,16487246672197108603 +8edc0a50-a487-09bf-c58e-21bfe54f9254,3755951150,8961939897505868108 +437d3488-41dc-a7a0-5adf-496054c11c02,3382468144,4056566192701380255 +a19c606d-c02b-55f3-4e5d-fb6ba314aa58,1092683941,14523574739891144403 +a373dab0-b04d-93d5-48ba-9ba9ef37ece0,2919707057,13009977604870230198 +80d110af-903e-f5fa-4da8-a21d296f0797,3899275820,16747667324468828978 +9fb0faba-64e2-2c0d-7502-d12a67756c33,3490725466,6710897035481747644 +34a7d6f3-eb32-ed35-2b45-67a74391a390,890052642,12102076273626593672 +888a2b14-90cf-f74a-f277-35412f7cdaf8,3155511299,14857479144482717175 +35651bca-7f6e-5366-6499-2c846a35e86d,2807227788,16295424738605426318 +a7d4e3ba-d93a-e469-0a78-d97e1852dadc,1992856746,10340303194145211518 +d16c4046-52a3-52ec-a7e5-3b28a27faebd,3141387216,17521794828801753342 +bce247e7-ba94-c414-ec43-1bcd78f16c51,851419647,5455159217453134408 +d3bfd901-875d-2bdb-c0f3-27fde3343796,1486836166,9522551440412319920 +21367653-ff66-1d28-08da-b4f1208b443e,2948200431,7541843900963058873 +423f7b33-cefe-7f8a-2813-9d96b854ba72,2851616403,4459702195995418619 +693a9307-6172-a5ae-8d39-aa9ad71fa2ce,1217853943,877211537043809290 +6959ca14-75e1-8d87-06a6-05c8b2c087f9,3147456247,13955060182229066855 +2a4d02b4-ee2e-eb2a-12a7-7a71ca0bec90,25489033,1768856034570690724 +ab0559fb-2a7b-0d14-6222-63dd0d0aec1e,3494407740,6530420593279327462 +fb911e1f-d101-a7fb-c8c4-a22e8ae0259f,633742139,12890540183354571626 +d367b5dc-95b1-d819-be4d-ea8ec3f16549,1418266213,17832133322462779561 +d32617c9-ac1e-4d84-7590-4f05645e758c,3171226376,12576618327653340410 +8964876c-eecf-3d3b-16c0-f4ea92bd0ae0,2246724032,17637874404503558147 +6f9a0079-131e-5715-ab9b-7e332892e2c1,1608214626,15221134278216616296 +86a9ef08-dadb-548d-0961-c94753ba98ca,4283916676,11764497927937076810 +d16409e4-6885-643f-4d1b-49e4756e9914,4230232866,12273035963030737086 +c1208397-8504-ff22-d5b8-e6d71e81c41d,3664575202,11342204022681508510 +fafa0edc-3e02-f52c-796a-7dea996bc75c,769080413,16010600358873084866 +c768db02-65ab-24b4-49e4-48ec853764be,3786088631,4128979119842835135 +909a9272-72e9-a5cb-317c-bf6c9bdb30fd,253682818,17746337297791776649 +b7b1942d-5a93-c77f-510d-ae1e9b998b95,3248526080,1412315441127631335 +637689c8-75d1-bf05-06af-8ce6b659b3a5,1120900525,14178228944742021707 +f6647e4c-ccaf-321d-aa35-dcd22649d3f7,945836475,1648935656316505381 +80c88fb1-d69b-094a-d8dc-64ce1f961c04,3906844210,7751304670967604433 +db8185a1-4f17-5f15-8c3e-b2ac05477475,2553775034,4951096580533107206 +dc5544ad-926c-1855-8cb5-5fd6248b1a63,2199045680,9472966568721349855 +a34b6285-f327-1bae-ab83-8ab556024726,1611026869,2086508303287668239 +8eeea235-bd60-79d1-7a75-57f5b90caa61,1316287896,11059287492777601825 +16f84667-76fa-4ee8-9fc8-425f473f0730,1784882232,16070050884652302459 +fa397c0d-de1e-240d-fa06-e406e34d1eaf,3765162387,6769831424173793911 +5c44809c-bd0e-817f-e74e-c3e85bed034a,2500696715,13289144198673191010 +1881dfe9-af11-b70a-e961-c86d9d33f4ab,1452413292,12734473925166345114 +bc6cef40-f628-99bc-dc11-6ce4c97a4702,434800746,16327735750860741876 +fe7fb22d-98c4-37ff-c5c7-2ae789cba600,3574269502,5584968253943637482 +31c3872b-0a28-6a36-fe19-e4c891901834,843118953,18101442064896491755 +997dad76-0efd-7307-11ea-41c4e20be23e,3193194967,11378118040402348414 +55a3d0c9-4b85-8085-aa43-0173ba1f339c,1862810739,3837346098708020439 +e8a68068-cd55-3eb5-b4b4-b5a01bcf7908,2283008128,3635736879629924377 +f274c11f-3b2f-b601-c02e-08f4ff209a04,3410873074,5270345052918928555 +5bb19bf9-ac6f-5c43-e391-7ce4fa9c0242,157563567,8044427042245553841 +2d40efaa-59b6-5bf7-e001-a2e0d416db4c,379462020,13992444273662256950 +6c15d908-77ec-33ab-9219-105290c7aa7c,1527554343,7877276370267055900 +2ca62549-0e8d-b748-98b2-246247ebc3eb,728714507,7650091793439326013 +37c1b444-3d19-5ded-8557-18a3cc2fd97f,2729800016,12481582903455065180 +b0cdfe7d-d473-3afb-98b6-229766b67e76,470927667,149039178628671385 +0578a906-37ad-befc-17af-9fdaa5aa3b8c,2862893176,10198571710922574465 +de3ef95f-8e0e-65a1-59ce-b5b780d2b502,103595257,5247955359676774411 +2d7319ab-8a52-e4b8-d4d4-fa0a08f5a415,3439228850,15488082730295804379 +58533c8e-5b41-79bc-e4b2-70ce2d43ae18,2512172595,14081704220328661932 +5349a6dd-cba0-3bbd-389d-e54406ca85ca,797163897,14863257189436601866 +ba946ebd-e10b-8df7-0fd9-66b880a04cae,3702101452,10139813324377018220 +cdc0bf27-c7f0-4dfc-3dde-55832703fb78,2293319841,4169487441481585267 +c7d09073-c01a-8afd-c910-780c58cc6975,2183147982,4008190465375491904 +4b6060a0-c3c1-16ac-e55f-1cd1468641ca,2200856403,10820007333630475568 +60f22ad7-f2d9-3e6e-e47f-e61d07143960,1776992985,16794868476802909477 +c60d1b23-39f6-b976-d487-08a8037a1023,3063572118,6657575858549871674 +5dff90e6-ecba-66a9-0e52-8b5d9a4255a8,1691257277,6608897636340523836 +bf7cd390-3f9a-deef-af99-a3ff62291b5d,2657443663,13233115718268950643 +8cfd3461-d55f-cb34-0aaf-99c97ccb5f17,1707587348,17842480757410497094 +778e6789-e58c-7aee-7ca0-3ed3d42d62d8,355909679,14628491228208771009 +d5666501-b083-2c2f-dd56-22d0b0d3a783,3088488423,6278110012806646546 +dd6f8e8d-d3a7-debb-f835-1fbb95d154b4,1398748743,11219526757526721738 +6551a97f-ad95-16dd-a06d-361f7379fb51,4277210743,16265086254047935265 +c2abe62a-1d84-1168-1b61-c22ed2dbdac2,2116807189,15242742528450472618 +21df6362-265e-d8ca-9242-6219f220e2f2,1495225050,4540550769758984726 +0c8ecdac-4ccc-3540-e8a0-8eae7c70f898,4253954124,5815564460961879444 +03c0249a-e587-4fc6-385e-f280c40f4bd6,2510604512,12289082359371089310 +79203a69-3de7-a608-7485-e85ff754531f,2275103313,11127765226978401298 +1c71a7b2-614b-9f39-d49e-8d24cddc00b7,1859074737,8530338645624872292 +7cca40e2-3b0e-00bb-3617-4d964de8b937,2121512458,16987125273256244873 +fd9aca80-2f18-ad61-9853-4bbbb4e5514d,1965157103,12062893699155268604 +5f9fae67-ced9-a1bb-da28-02cfd491d4be,608739094,13314089645780679499 +61712c55-d55f-1d63-3c3c-0a19f31706e0,1598174242,10040159795570423993 +acb8e784-d647-3439-af8d-f8b057b3aaae,2664999062,17668356151836993406 +5704c967-423a-e9e7-d761-799c735b1c43,3598327798,7368594376496832076 +835f2cc4-20bc-09f5-9140-21055f7c9cc4,1385230145,8251777299358491298 +d5b06077-0f64-3fc3-cdeb-73012607a3aa,2703745384,15256173712401526629 +60730afe-f6a4-4b91-8e36-8ddb6d717161,3429391303,9184059812210538849 +78d6c2f1-56ff-bc63-f422-6c1a7bc1dbd0,2881563375,17654368789573762996 +ac853153-e264-3c34-77ad-1d547be27c33,1454166887,7039890773402574132 +ff2777b6-2c03-f4a9-57f3-fd3cabd3ad6d,1042169800,16151584288334653533 +375a4a4f-9d62-1769-9484-5b4e299f9001,1475589142,13445623916039203948 +d31b75f7-baf8-c274-4371-9cc44b77ead7,3480937103,15298442421452224312 +81b10a6e-49e7-d96f-bdb3-38ebc1478d80,1319548130,15806543194565603133 +8d2db95a-063b-0c21-8840-df9ab26c7792,2445167749,908619466686045118 +1fd31138-fcf4-40cb-b70c-54053c5d5904,2667373563,11179255574791825384 +b7426fbb-da2f-706b-489e-d18192012714,21198745,14029673649919349153 +b6db19a1-591e-f61c-ca71-3b09b00fcc16,571629739,9032464346971813806 +e5d2051a-fa04-8929-5304-45397806853d,2223071551,10837298891127495195 +f19c9163-3b74-1642-136f-59fab4e3e31b,3991754071,15166631966965357201 +a38deb3a-c114-d5d9-8293-42badb5edc86,303342925,17277990033470978550 +a4e68f1a-f05f-351e-a7e8-1bb21503bea6,3556383468,13706276968742307768 +a6e7daa9-a2b6-0c0f-7eb5-caffd41ca5d8,1141326138,3296504536164016471 +754a257b-9791-f7ef-11da-04df64f22e8b,1186766584,12701109701102924631 +cee02025-3b0a-538c-c929-8f5dc44f12f5,2094758775,18364060881751443939 +42ca49a6-8255-1737-054c-0fe5898d300b,1771373498,3920054963305283105 +4879f663-0e0f-53b8-4426-632d2bf3b23e,3070766583,13849536153789702303 +d2bd370b-8fce-9031-01d5-9804cfbdfbde,2648766713,13955872398101244425 +467f3c63-92c5-725b-9e47-1d3b2a953d82,2670845461,6834628771855197839 +820210fd-6412-af03-64e3-7b89560c48b1,1675329957,10985946494853209951 +e509f355-6f88-075c-ad7d-bcb20ec278b5,403852786,3451666310005102522 +14876f28-c623-eb1b-d9cb-ab8e4e57b56f,2283014747,5341497805349515935 +26ac052f-3e15-27e5-fdb4-2d2856fbb5e7,1156220917,13598234639601230706 +d81689d1-4add-13e5-110a-0c1acf35d258,103432445,13198416573092308069 +9c2a457b-d530-0fc0-4df9-d34ca0c36a8b,2752322856,8242298562398441176 +65305928-4846-e908-6c5c-6d611f4a9276,1289007219,3534469783748969152 +cb1b8945-3d95-3afc-d13c-a4e9ac6d068d,2873455084,5271506106538754948 +3e709dfb-120f-1978-21a7-e361f5392111,1722155089,9304458487368319475 +561a65b4-09e0-28ad-649c-7b91ac6f4eca,939212201,8344871028813037469 +9d8d6ffb-12b2-26e9-2d34-6aa11e749b9d,3731431352,3110316502475937925 +ebb5edfa-c354-7c16-5c77-da01f6558891,3316003676,6617977627464078058 +7991ce78-386a-52e2-3dfc-3bd8a5c1a4a9,1697351597,8955744597665223251 +d943978b-b582-df30-5592-427b77ab06f1,1488578907,18061482807442226255 +7a73d2f8-a4ac-d838-0e37-c290be5250c2,3078590344,14339909022322477902 +789af39f-f4b8-f438-182e-0969b5a59a50,3744341502,12271073986957311130 +394c9ab8-1c70-eddf-c23a-bf7bd6259a87,1045624941,8222642569691257299 +1eb05243-9afb-d105-3f9e-27c4674f0cdd,2759881480,9216257894282204180 +fe098ec8-ade9-858d-d841-d4deec6bf7ad,894240934,11271156459640207371 +bc593aed-01a3-9f7c-a589-40e99c27e4d0,1831845137,789454573716083659 +b1e40b62-a89f-b110-15f3-a88313a0b96e,813066856,8242089863563647466 +c5be083e-207a-949d-e219-bd8b45c7aabf,2841588777,3837639926481395819 +b8059ab9-6276-7437-c5b7-2e53d53c85f5,344126786,1914005098573518710 +a9544d51-9342-a7c4-3f90-96401990cebe,3763322028,10570444681663094300 +89c3ff86-9dbe-bbcb-8696-5728ba7b6d45,2850478947,11680355016146192153 +df9c6b67-a0cf-f676-c058-d818cbb3beca,2619707906,2831742950843509267 +e47d8a0a-0272-82d1-ddd7-f507421da676,4135871003,11022850600574037956 +f06ba7e7-c09d-b161-320f-3deff353f000,2807771089,4044964083901386404 +a1cecda5-fd2a-8e79-227c-3d2668b8a26a,724046311,4990378361166777881 +7320399a-b30e-d104-3d69-6217c782e2ff,1652102711,2524680174842240952 +3573e802-3d10-2687-d61e-a71e77669ad2,3709964644,16363011283873863712 +f11011f0-5c49-efbc-03b3-00b70d88b32d,2718416102,15689088743845650989 +5c0c77a4-e33f-1d60-b18b-79a9d4084ca8,3835427677,17480193710234419501 +0272d096-be38-47d2-5379-5e8eb35706d1,19151882,7637814291358338141 +af8fa93c-4682-b13d-f229-5ebb2ff49510,2339864586,8464980854213399753 +f71dae5e-ce34-b454-afe6-0fcdaf14a0bd,2676841801,10033294133905797959 +3b0b2208-5f3e-0deb-2a7a-9cc2e206be7f,1781340681,13666464489919092672 +3ea51bdb-2241-94c9-e3e9-a1a9dd480507,4233377168,3881900066739128624 +a6da2b49-8e1b-5c64-7924-17a1ac6a5faa,1219885971,4044571242628127701 +63ed4fd0-1ec9-9a4e-b469-8552defcae08,2721025015,4795883151058861158 +db1ce85e-6dcc-f0a8-37d6-7e2d017af126,1005502633,10131205265341356721 +f9f18f3f-9b06-7606-b854-e7f542ff7d65,965897513,4001756101970204970 +26aa6c84-a884-2005-e9e2-6f0ae3990836,1438568078,11181278417183080613 +3308af73-ce5b-2a3e-4193-8087b900939c,209758221,3364260157809732759 +da46be6d-8362-1038-239c-160ec6523d54,1415611729,5810442948935320135 +9a0537b3-3ebb-cc56-779b-40d60a845b23,813605883,12111903614705196427 +e1adaf01-71c4-6c2a-e1bb-963a78b89ab8,283687676,3150609645499400341 +797c2516-c74a-4d77-ee78-6e1c708fc89d,2203550876,7559083223518893058 +4f0bd552-0c49-bc5c-a3f4-a084d40b8957,1047986637,13890047268614723080 +7adfa722-bc26-76f2-d26e-60e8e0c441b5,1908671297,2633570272141194636 +40ac8375-2efb-6e9a-9a1d-95d72edee50c,4099456839,2617279691993730704 +d3f488a4-7306-06c3-6f12-45854332a4c1,3417086189,8963476406330929732 +c0ced953-f467-2e34-50c8-ff8d6ba282fc,2160558324,13818411729104827044 +99ad3fe5-95cd-5b93-8eea-ab9f492d43a4,1116156309,15955712020686889090 +56ed119f-1c36-6adc-b451-529c2c262757,1492864953,4094186269410392716 +5dec8556-21e1-6cf6-527e-28444a8f94a2,3182825156,9966290117899751360 +142709fa-613c-836b-3f8e-640833bc3e7b,2542398398,10634817095176967814 +a6368a01-6623-4938-c41a-7aebe6c0d3f3,238300496,1366490166666691607 +af87719a-2cc7-3747-766d-704d5b95d6e6,82696409,789047520560307896 +0b2897b1-48d1-09da-cd2f-08cd6c68d8ef,3907029371,11491659472447141209 +1a4d4504-177c-8468-64ed-b790d0eadd9d,2450513841,11727840507287700144 +21a9e1bd-1262-ced3-6eac-449e95ef6130,843507835,17298054457391677132 +741c823a-030f-de7f-a0f0-b96ad25bc125,2630336275,2223951914485031152 +93c8755b-b563-55da-4c34-c48bc504a93e,511628769,16187834362248247274 +f7d2ef93-4354-78c3-bcb2-88c23a7f51b2,1584411289,14630496559702402385 +bbb4e100-ebf1-811c-be49-cc4aca1fdb20,181311591,9995661992182545331 +f93ae6d4-851b-dafd-939d-ed7eb9c2b005,3301852069,5259033673889624108 +4c30ed81-c09c-9499-ac46-cb5f808d6393,3173023565,3897562648667230048 +dbc77442-11e1-f3b0-7e34-e0d47b65afce,1322645932,11146003656279617497 +d9df8d2f-0002-627b-cf73-f20ca2f5f4f4,959876464,14706352538742566044 +c2d1a06e-0314-fdf8-b579-be74e0b41af0,3632256514,4069160393175128017 +7cc45ba7-36cb-f019-68a1-24f838bed3ed,1304089471,15618737157494247356 +d9203ad9-63bd-24ca-32e2-94a5b171e79a,1236469886,4554790953756998105 +889762c4-3548-b233-c7ea-84e179bd7ebc,154295810,14127742580271623534 +42fc9646-b927-e42b-9f74-2233393854e5,4161955786,8178376176581763986 +d287bd80-c197-765e-9840-1bb4891c24cb,3951083882,82050965750778866 +5891579f-068f-894e-3606-8a9e1885db7b,1069520941,8361860414828825969 +77261354-2218-97b8-4ae3-32dac4362e7c,1462029506,17717648081796268032 +7bbe11c5-d1a4-baf9-66f1-7f171588e5b6,3723994083,1300420702281823775 +87c9377c-3ed8-9489-8892-6ad87d7b52b6,4111778018,5294973814255866257 +4b75a09b-dfd1-a13a-b511-b4ebbaeff78b,947453226,10436742206425899091 +07a0233b-58b3-4e4e-e3d2-462a8ec0ba49,924815743,17198673801956018277 +6e4427f7-b723-6b80-257c-708d4ea9bb58,431118995,11840860314823485264 +7d135ee2-cee7-edb2-e476-f5b234217c8b,1904623089,8864125099157606603 +63cf8c93-0767-919a-83b4-0a1d6d13a5a5,846797755,876612770489181690 +b090ec7c-122b-d407-69fd-4a5139c1835d,100829232,1199936786943701069 +21986f22-c9fa-adf5-7ca0-c8c075b1ad29,2167945362,1088800630319331049 +f846bd49-4d27-7ca0-52f1-27d990a2b62f,1634962202,11440476926426630169 +4c1c9648-a399-f76d-d4af-4021a2c34eea,497257919,4006836792061887976 +f22c0c5c-d848-b356-a9ae-dd540404b8a1,4249264042,8443102330247617324 +26064cc8-914d-c87e-b57b-e0e53f99977f,451070607,10399282191082677908 +56b4dd25-e487-6a7b-482b-89e1ba4b9afa,3227691270,13582406502942859787 +b62750b2-86b8-d79a-1f9b-c51d81bfb5fa,1778466769,14236495932189588262 +75d96b82-e808-f8d5-5028-9ef23d09f427,3962661315,10366660335017317775 +6e85d956-dfae-4b8f-c233-18cf1481dc2c,3819795736,4911029135798318337 +733c2227-a6ce-6c4b-01d4-0f7fdae83ef9,3657132747,9655421091760293063 +7b0477c0-b0e2-3580-d82f-c8b2c9b81667,665522252,7069965112679035632 +0504213a-3988-8fa7-0177-a09277a59b54,980744146,5401533627093880036 +b08d9e93-2c0b-9bda-eeeb-e14350a9fe40,2973939429,13218324674493076614 +77247d6e-ce3a-05d2-6b44-5402b7b450f8,2297509777,13027698902991741793 +2ed47bf2-46a2-26b8-d3b9-52c8f8969fef,4247661410,16397240263696504541 +3b30ca49-81e9-d158-bdc1-b882d51522c9,1603746269,10516624489785767286 +390bbc64-ec1f-bcd8-6cc0-e6cee49e0aed,3287508451,14356753781721055517 +9f7fdb7c-9dfd-37c1-b055-7cec66077dbd,1872431856,16385288025380849996 +1d8068ce-076b-3f84-24c2-225ae481fda9,2808574739,1781127494789523875 +feca704f-b620-f020-d6dd-48cf86c41542,1874347735,16474656845204663390 +e9974aa8-c2e4-0e2b-0a68-5e9ff77aa949,2317267875,9763829021493148694 +fb66fad3-62ca-50d4-e0e9-f09d56450af8,2117267421,4218134599820041201 +363002fe-2960-75a7-7464-5a7f0267567a,799623805,6614036197086215733 +9ee01ac5-65fe-e770-eaa3-8f039e573bd3,3526868861,6537412199230557651 +f319348c-0c09-7fa3-dc70-939e599c8782,3684057206,1197414170744832720 +b3d4389c-6736-2263-b380-70dc18272f81,1135210651,9352225956336729872 +302977fa-1636-3541-5bd3-176c7999a4c6,1205834246,6050684418038268048 +9f8f2214-a4b7-817d-2fab-32884742c8c3,4214489884,5816148174992244499 +1c116e2e-cd8a-9b43-803c-9d16e4215362,364922943,7743186406011328835 +dee5dc4f-2c98-3a38-2ce7-2d26ae537b32,3289652136,16297776126997995448 +b358d026-bec0-0fc9-2bfb-2024a73a2162,3831594005,1393765027577394722 +2a853108-f59c-f8d2-0ba3-f5f972617114,1702489423,14130407598420242142 +9dcfbbfc-8dc9-3bd5-3196-0f49c1835363,3425510247,6832517343839852299 +0e3f9f42-8c0a-73a8-a183-df825fbdffa4,2041937812,17584430001268222761 +cfc16e73-4264-3c8e-3871-d69a1cb5df11,2491754567,9855749419164985227 +fca809a9-00f6-37ba-16e6-6879e803df5d,3348019410,10932609666008150350 +f6ad4918-d2f1-ceaf-3746-35e8da321306,2793249674,6919050281438967742 +52cc9754-5209-f0dd-65a1-8043c72fa64e,929423510,8541706042240180909 +65458f6f-9785-bd02-b34a-cefaa15c7885,3005460942,4676256492092739990 +9bdc2185-1b10-1852-67ea-487e0c07e895,1092348917,6766238953220894166 +81b096fc-bbaa-c4c8-0e50-308a74adf4ba,1109319578,16313608061255688563 +b562caa2-5b81-63bd-1174-c8813b024f61,577699399,606568513503579674 +f454258b-7950-138e-8f68-d5452bf4b7f8,2745354122,469121490798004748 +2f869fbd-da49-d333-530f-9984e4d9edb3,2349974125,13850342595151795426 +069421cf-6f52-4ab8-6592-5656d58ee3e5,1771084189,7245592176306951277 +317b6a28-142e-eba3-a3b6-bec9157202fb,3523523360,10581095484020211454 +23353b7f-be23-e526-4c66-0bb95b86e4d2,2551606565,6806084738295130909 +5d0f5437-6e6c-6eeb-5ceb-d49d7de9bf11,2195014001,13816973142874807877 +0765a348-e2be-1c80-9e3e-3fd3d7335330,1455876871,9004654132110376826 +1e036081-aea0-4367-82f2-e0a33b7026fb,1510936193,6134668059483707111 +edd928e6-8a23-368d-45b4-a637581e3894,55181197,2284666583290973091 +761f7cfe-acc5-9dba-8a95-fd2449cac497,2411470318,1181461905372779068 +ad9f473e-5647-c558-1db9-42c6522176ad,116415088,15967126638111853748 +a0deefc7-56c4-5690-bd01-88e3a6ebaf35,839890574,16738564994480725412 +0678d722-b052-c0b1-03a4-d82a39ec5760,3344435798,5939605618437226302 +1e141572-b630-c3b9-e4be-8b5f9325dbf1,2825695057,3701768902124489000 +fe066957-065a-cd4e-f18c-638f37dce943,2660303414,13505642109613696681 +b74003fe-e3c4-15b4-5d91-c654279aedb3,3506261166,8316279284394457871 +3e3f8e32-0090-250f-f85e-a76a0555d2b7,1123107978,12928627409440359471 +ed65677c-aca5-a35f-66cf-ed1095766abf,972237251,9956801931800076716 +1f12f9a1-2793-38f9-19a2-d8cf0f57e1e1,1300625925,10267814575711254043 +aa7ba6a1-071f-5a5d-bdea-85b3a248193a,4217737436,4180413737941583962 +ed1f3ae7-f894-11a9-f475-0c091fad3dee,3207532395,9520328214612080639 +26b73f41-772c-6043-4795-ee64e1d0b9fe,2129471038,5822940843090864091 +f5fbd457-59ea-9900-d318-283e7ae2c7e2,1213201396,16028591017475154002 +0ac301d6-8985-e963-6934-f4da715e26b8,2454226522,18411310275037584108 +56506835-c350-195e-1e97-7ea3aa5339eb,934462319,18439500282864643274 +09427bb2-4057-5f5e-c2ea-06dcc5979024,3318028832,8546979992509714866 +0b9e84fd-84ad-db66-6635-bf31c5b32287,80230072,5056374490634154729 +72d84954-cb26-dbac-eea8-2eca4905842b,3947991084,7787449688883222762 +6ef22b4a-519c-9d72-1fac-2c305edbdbb8,3616439232,339195943547673812 +30cc9995-add7-0d3c-e0ae-d3732136ab69,2954998773,2560971025047044239 +461bc132-3bb4-1d36-ae50-107aaac23ece,2159766764,1994627373827680838 +4ae52599-dbee-2d80-c3e7-627a06184e69,2769404079,10350242199875694427 +478efd96-cb4a-258f-7523-72650a10e9a6,4258280765,4543944805894254844 +701bc2e8-9e60-ec55-c05b-ae3bb5630079,3204055847,5424864930298268448 +d85b58e0-9263-5747-c326-53856362650c,1883985202,5105995190632770781 +8dae398e-2210-bc98-31c3-6c694e4bef8f,2842003014,12008705018218306183 +422c53e3-92bd-53d6-0a98-da6e779f3db8,4047371964,6649290144982750980 +386620a2-a2d9-2ea7-7757-44710ecee94a,3135613369,5359285846779012179 +bdd77a4a-3871-5c9b-5319-21125a483cdd,3352343689,5168779343278608362 +7d5a4805-db73-b5ac-72c6-907fa2308f3b,2807363494,2978650875363791518 +c1869f2e-87cd-52a7-21b9-33ffd7ee2c24,4247646437,6980645364608486076 +225f43c9-586b-509a-c360-1f9b8f76e4c1,2448963607,4281531176716791118 +7e6f110c-fcc4-5165-aa34-6bc51c51d0e1,2919173837,9049814211574351591 +7425d243-aaf9-35d8-e9e3-192ffd1e1be6,3315461975,12188601156595589796 +221725b8-d83f-aaab-065b-02ccb6930fda,1760564738,12096629887155868778 +b78d3907-0a8e-8266-d0ff-b7074c399800,131272475,237628085016679016 +97840ad6-645d-653f-f268-ea0e2d99b69a,79215374,2153828977228670066 +b21bf902-3d50-2438-8c18-b906c2e274c8,301069638,5168409810733733214 +9d5ceb26-9221-78d1-54c1-7a44fc572a53,2805171156,12200204692130100589 +296ed9b4-5262-acd3-f18e-694f252432e1,4249978169,7766067352433625639 +fadad2c2-e4f0-9258-e5ff-4b9e55a8afeb,1683793333,16668173180553915748 +70240e83-cacd-f81b-9388-36416e506e52,1073382735,14914646808153794506 +96d44ae7-4c03-ce88-7adb-82aedf5f18de,953244412,14453102857473981978 +bff8eb77-b7a1-b266-0bc7-f6bc112b350c,2106027916,17837071774915675315 +81aca18e-aad7-9411-1f3f-c33dd347448d,3512720559,17666807165782477515 +0923f553-a110-2d7f-4964-cb5131bdf791,105510336,2727148570088798010 +267975ef-c07c-0c7f-dc36-7bf9365b3bf2,2886352536,10223053536005168362 +a2729a3f-d24a-97ff-357e-2d3cbf94ecce,3018548651,5389388424760704072 +8aa2ecac-5355-4879-80ac-d8579c619989,3243415374,4077587864806207596 +934e3eca-bb6e-ae3a-0ec1-036effbeec9f,2268195226,6579690459964403802 +3de53e5e-d533-25e5-6ca4-af8892b9d9d4,2245376452,8795120388647209220 +7a80f95a-1621-cc88-4bad-1053717f63ca,3573467029,5003566919419731662 +c00f7e35-2e95-d414-0c3a-025fa0758dd2,82433306,16997044690964056245 +bbb7c699-bf72-440e-73b3-e3e91c6aaec5,1768848753,16589859488234506600 +79e3e538-934f-e94d-54bf-f29c53e6ec47,2501831997,14247019659320044641 +b8577e71-c21c-90d6-71a3-b89a625ff975,1180361848,351544953510602046 +5c03d155-cf53-30d9-4fc6-c2b82eb78701,2145035309,18260807137526334400 +f7a333f3-62f1-a327-2a76-feaf9b2e9051,1575662342,6246067980741763008 +66cc10b5-9758-1b3d-272f-31c1a130990f,4142566576,9062729475150814534 +38fa5151-dd94-29fa-2494-f11c198a8fa2,4279928751,8316923438707637376 +b7aa568c-a30c-8408-1c61-192da05a78c0,4269652650,587873603018319893 +11cbf9ee-6fdb-2628-d0ee-60afa3bbb405,1458777692,12748992685523146331 +730f2f44-9727-7e26-9d31-b3201ff00b38,1051584767,18259272777879399489 +6290175e-9ceb-c975-a46a-6494d0737e68,3662283383,9253275220227849017 +641fb32a-c9c1-61c7-0db1-8eaf4eeb7d08,1398900168,10443799607328646761 +f7c88956-60e6-eebb-4655-358589ced648,1073697604,964928264303866914 +1fc090d1-9fee-568b-01b6-3edeef7277a5,3868204791,14514744167326086616 +c69af76a-704d-e6ea-08a8-df717fc08471,144864096,7522125938887299279 +4b1b4e9d-0b07-3592-3df2-3098dbff2837,1333529033,5483905156136181979 +6e10d3e6-969c-0e4b-01ce-a6a5377accba,1763589928,8966727878074496597 +4df58e74-3033-e461-2520-c1788b45d332,3754062098,4619804150614556931 +4fe3a0c3-1afa-0c8c-a05d-45ae5ce57262,3939573695,17626161258731747050 +3adb4239-63a4-9d2f-2240-7ea1e41363a8,2901512339,7398706004047712977 +c7ebd82d-b8f1-58a1-3a0e-4c48a026abf4,1182235120,14029544889607774883 +03e158d3-98a4-e643-b961-63697821e0ed,3378892497,13781933243701947564 +3a0ff8a7-7196-230c-c8be-636a2695ca35,3296233641,10615379189893247434 +ffcbbfd4-60f6-c539-d825-07781558c7eb,3325090601,14182603568818944277 +3813299a-3792-2340-cb20-162d0a03e35d,3188579465,2957061087424732475 +1318d804-5750-13bf-fd90-140dc1c6470a,2447077835,361169147017428554 +13dc7947-a9a5-eae0-9962-992822d29ad8,2101126325,13093653631422592693 +9d28d49d-dac1-b3bd-a8b5-4eba4a1acd6a,4072732094,3748442279507306988 +e4675892-76b9-49f8-cf0a-8f7d3f403d37,3408775585,11466502139416822594 +08baaf6c-d0a8-87e8-5634-160b15406a3a,3699538427,5154056110472570640 +65c04092-7a55-bd22-9173-dfec2bc98071,3422274465,396602370476164099 +9f191172-b1ce-e99e-0189-81c841504e40,2757484842,5375077820736999970 +30ebe79b-7b88-fcaa-5771-acfa5e61b237,69856742,7074424934852161186 +acdd11ff-2826-a034-ebf5-84fba19e314b,3586498671,8577367293589351339 +3f9773cf-30e9-fe87-93ff-939b1a729207,1003585779,10610860378354034943 +4cda6c80-7861-42ae-7930-5fc13631dfdd,2330049517,5401885671948665310 +a3616745-21cc-1af5-89c5-68e19058a5fc,3911701814,9586118099009771780 +d8a871c2-87af-d8a7-e159-1701968b8f78,2248232298,11648598258361479644 +403e569b-6d54-83da-6110-98c11a1619d6,2393210284,13351328899255353765 +b4bf0c56-3ef9-38e8-9b5e-9c1f64d12221,707393471,6471459309563224210 +11793ff0-8ec1-cbac-9ad8-cfcb59acb7c9,3988177599,9788814001735818382 +1efcfe0d-a550-2537-cc38-4ed8a9c0669c,3283064096,9911848482365371249 +7bfeb53c-baa2-6f58-ac4a-6622071c3764,2090395515,13155593809483398566 +030f0879-57af-802a-dd12-0a5df88be62e,4009890327,15049026718615006863 +bf3ece0d-b7d9-3450-dd15-40df97cde2aa,1023877489,329206331649932846 +7fddd37c-5c8f-14fb-bc14-170a2ae81cc7,2205809453,9661009271082812589 +93babe78-7849-4430-26e7-a86a5558ef33,392459937,11691105692790113154 +f13ca7a1-b7e3-51fe-1263-f8030fa9d350,963522151,13576278722594416105 +ac159362-9135-d217-2e89-240993eac3a6,1215928320,5413865809803322390 +5047b3a4-d6a5-b0a0-2474-e997d7e22c8d,3279454548,9457737166113217275 +604f1d23-788f-279f-75a5-167c9d23f5d6,3370861764,10975753228297610312 +2fb300d1-9b8e-05f9-8e02-65f925850683,906460590,10112505245496038928 +4ee96e78-f060-5b36-3d58-ba301651d2ec,1421506419,11621787054224287370 +af6d0ae0-da4e-2241-23b6-abade46ba992,4015744505,11479628845314972096 +90474e31-0e65-b989-d009-3f50063d0a3b,3506907593,9985705310395570493 +ebc65828-575b-e1bb-6d9e-85a0d3b4229b,2663147761,13030684558394285509 +bde1b0b5-bb6b-a921-d9d5-5daa918fb94b,2733952388,4262187406354787361 +813875ad-1a62-fc26-144e-7ffab41f0262,4202321285,4454781001926136681 +561edd0b-fc5f-4ecb-eae6-794ea4b68cdd,3916326534,13959203891465141807 +5c92e194-54b3-3348-1ed1-5c7e9bc9d7f2,4109009797,13142469268575591768 +5449158a-1940-0bbc-d9d4-415b68e49098,2646283967,121333823809027155 +d4da915c-6804-4d87-36de-972a5cc4dc6f,66958982,9774371840516216755 +153df00b-90b1-f332-8c26-7c94e06ed051,909614476,6941047653083804445 +e57d68bf-1b58-9fa5-bd24-bd241d633cdf,2862643104,12940608818704836770 +bb2c2329-526d-7509-c60b-1f15513948d2,2591775329,7796159289628021421 +fc153b50-6063-43e6-58ce-74dc46d7d923,2885788223,16346981798169518959 +9ef7fe92-53ab-2c99-89ed-bb5295c6b4d6,3892218268,1824858428032058218 +c970e457-c519-f9a9-2d9a-7d0c3ed9458c,2003486155,9493220696718839294 +c049847b-a00f-6147-547d-678a1169a363,195725084,7140696083363059145 +df85d5c8-c756-f222-533c-7973c326585a,3730858253,12642220693501992154 +fe351086-b5be-7a1c-8327-bbbfdf0491ac,1073577430,3138878851873825906 +e9d3fcc5-33d5-24d2-39e5-8cb1dbd878c6,3639329829,18222468304744875253 +aae3406c-3d7c-715f-193b-0cb01e0ddf4d,380074568,6081504230003960809 +57c42971-0ff4-abca-c941-f6150ded673d,856460848,3294424631854147629 +f4cf75f0-7ac3-4cd3-666d-4461fb5686dd,658670861,11081459653357114606 +8feb514e-9b55-c5e4-997b-a94029975d3b,265211947,17120040918032000245 +3c28c05c-33e9-9479-6dce-e917edb22c56,1672142770,9394838752418319823 +62bfd257-8882-9719-b3f0-0c3d221b8e9b,2349579973,4286007236292584559 +ded62829-9bf4-b051-fe58-2b290bd04ed6,2576617251,11265524869330342544 +3f775c63-00b7-9b35-58ed-53e5d143c6c2,1454871261,14703941120872161761 +43658d9a-5de1-85a5-341e-76192921c068,786305558,7416829407777382303 +4c9df405-7806-0de5-d61a-b749310090cd,3019217356,10158455853646644929 +57e76601-ac11-865c-1385-6d404ebd3518,2073021407,10044280580716425139 +342cab3f-e07f-7fb0-9991-0fd90870f0de,605764362,1955962026916572341 +05ce876a-b588-9fa5-a0a3-8078ab7774e8,2618257112,4313234241383923900 +6fc474c8-8db5-aef4-6fe9-6f6a1e9813c0,2034620868,5387245085303711544 +0d019abc-ec81-6c79-207f-d82ffcd3fb1d,1677400647,15021498180968562002 +c85b05bd-91d6-cccb-654d-5999477138e4,1233692773,15771977049052272302 +95af7884-24d3-9c75-6db4-ae4f2dd092a0,3718473116,1206228306099630703 +e17b01d4-cc24-b796-4e46-c91148ba4d38,2823072040,1070020169186615586 +a71869d0-a3af-a5b2-2e09-fb6b12071ad5,2848821136,1990460228226730272 +28cf4eb4-dfe9-e313-36b6-555ed1e7c9c1,3647492720,11954166564937686020 +389f790e-a4a1-0531-bb78-f2916177d590,3657662712,9482733756199899244 +d5f7a796-5fd1-e12a-1811-007565fc2b35,3881564344,16059894135952418637 +dc75eeb6-9a73-a52a-817b-9af23bd13104,1756086480,3062204564819010697 +d83f866d-236b-2c26-0503-5c8a52d9acba,1487408336,13490884169195027702 +d325b114-6469-9a71-5eb7-32c56ebb6995,187067632,8522873454615947096 +7eaeca90-36e1-1165-6cf5-3e2add10dfb8,716677072,8656046031427634002 +3e4cbfe6-b2bb-63fb-95a7-1868c87f52c8,2368030435,10857951102986827049 +0e8950d3-b972-b636-0db7-4d801cd39b4d,1616199209,3491933228374422908 +1f49c988-e66b-4d55-d73b-b7bf11cd3e9b,272605213,13588211500311334612 +221a2597-5c6d-4aca-9cfa-6f0498f80c4f,1729190579,17472552323671653021 +21c82f09-f7ed-a1f0-beb3-9301504e52c3,3089178565,515274060885885431 +f4e8a95c-6b49-08b5-c8b1-e7ac8105fe5a,1963530597,13058151951109129687 +20536604-e729-bb80-9b99-03df49fcb88f,500143105,9949220945551133537 +2e6dd7dd-ad42-987b-7003-fe49dbeb5aa5,3287429607,10572292122228065503 +1d1b2deb-56bd-5a4f-8aee-6fe338295aad,3075976250,3522897622694920659 +8189432e-82f3-9fc3-8aa5-87f421824241,3192877128,12793060789679751834 +86de9082-589d-2f25-3417-c2fd27f18385,1238609964,15469198938388645570 +2ffc7617-c1c8-8d00-75da-dec3d78f191c,2388265527,16785510456014156387 +98cc8b6b-0242-fdb7-5505-ae3f5c6b792a,2348675436,7316972692687942242 +963b2ead-3ecd-96cc-5072-72de91454087,32624930,13445197617595817665 +00820fc4-4332-fbce-28ec-28c357719671,3133131426,9023814727389640326 +752937b2-5bd3-0e8d-5dce-89790df33a18,234910796,1400347872406936057 +9ea4b50c-47fe-f2b0-dbce-f929839cf82f,566892560,1279866767368202207 +5a21cf75-b596-98a4-7fbe-183aaf0971d6,2254043500,18013510081930570181 +980f4fc3-818c-41f4-0452-f83a941be0b8,141542564,17976445370431073485 +ad7c8bab-2064-e0da-55e7-53ffcf7c9c6f,4181849949,1276927068321884944 +0d00a0ff-16b7-986d-5079-5efa8ed9b578,446438997,6451364100597684455 +b904034d-e3fd-040a-eb2f-a64e59107747,928090964,8776222548580578130 +7c4c207d-7d2d-16c4-fe06-8e98d803ac54,3784402549,5201356987765223222 +294086f3-e2de-ee99-e5ea-c008e0788f1d,3064492518,5342698474551751343 +433faa14-e1c1-6332-6023-1fe1d46c4894,2072436418,11035870410886441942 +35a789c2-d6dd-8642-e894-0af0ea12119b,4242127797,12089740345222841472 +317827ef-8a67-2eaa-b519-23002028bab9,1792873089,6515248701818971495 +b74a82ce-1c02-4488-467f-f9cd663e4977,495841149,6898624813050559992 +11a91085-676f-c45f-8a74-8fbb739cf5cc,683969218,7033969783778351996 +85114c9b-ed3f-5e9d-c9b8-ba0cce536a6d,1708042977,10848534094578539077 +f9327d7b-8827-74af-6600-bcd43aaa5541,161617912,17950310295467133343 +0bbe5581-8dcf-90f4-119b-9f3a0236dcda,1932960811,2135593775723866546 +77f130c2-14ae-a879-3315-a6e110c47a98,1498519743,9550727866249871093 +5d7fe707-4733-7b3e-fb8f-7461f1cf610a,3391487452,3765637437114162464 +43c33cd6-1171-3dae-3906-aef2ede9dece,2671820970,4641991594213230389 +6e9d6dba-f427-116b-4a4d-76d744b0451a,3764380603,11818550109350619806 +c149d072-2110-12a6-3946-fff97f31ac8d,1815325689,976861375562512126 +1b0f0259-d762-8fb3-5961-e7fe169033ab,3703863638,5752624618843596003 +d0dfff41-0bca-4df2-d589-d8a410c13d53,3043313727,10730282924699396220 +dc0e17dc-83d7-7b76-d608-cea5a0b285bb,3132332975,10716207008828296657 +59663a3c-48f8-9e75-47af-62d33af70a18,3612205940,2338696905670157345 +86313a43-6239-2f7a-5697-22eafed53ef9,1088119252,280723916563749323 +2cf2d570-7b4e-c5b5-23f2-8efc6efb0cf1,2295922606,12462752643168881909 +03405631-3daf-bb6f-79e7-3afe0821e377,642953578,4086770776086244403 +955ab4e9-6033-89de-fc6e-0c2c7be40ffb,3433339107,3620367849991679161 +8adc0fe7-d211-8131-ed69-727e4229c58f,2701673753,3335940478590585500 +aaece148-baec-29e4-360a-0004a4ab0aea,2862768373,13089335567774071544 +545f1ced-3c12-600b-7aaf-75a857c0a5ce,1408225687,15018400892789274043 +980449cf-3b33-9bda-3c7b-b8cf7cc518ce,806614010,2718757152055574356 +46b85681-56e1-397c-8cf9-2ca797fa1bb9,1164548112,12963120278944528209 +e82d2e26-538c-f30d-f2b9-3ab9680e9d34,3626415182,9650866189577270228 +0477ba08-e1ae-51ae-e13f-5887d790ef9a,3203952062,18054214771284808741 +cd3f9a28-79ed-97ce-e686-a19323b1edd9,2981313302,14152428740094106837 +6d3c25b4-5e55-1ccd-052e-fd6a185b1cc4,3410409293,5791965148495189184 +9160ffa3-a5a7-b033-b44e-480b2ab34415,321210954,80085906944033477 +1457f9a6-5c14-d303-0f96-9e8ecb5f50a1,3210403110,18193163596531585478 +961ed8e2-3f55-f510-38f9-6b5c884b5658,2785368155,13293883231704105632 +ad2323be-5ac2-a051-935c-cbdd2e7d9b26,1839478323,12343747264692723458 +39331138-4df5-3fba-8582-208f12cdbd98,655399054,12603630759159084292 +da4667ea-2147-04a8-1994-09b113d264b8,2426365591,10956153361108734379 +cecb6212-7bce-1721-9085-063e3527f6e5,620287047,7757261334348121168 +9d24fd23-9144-923f-93ff-dcd1cf490f8a,2958707791,17992499138179265349 +7489bd0c-0be7-318c-21e0-f6424b5e8f47,2279377080,3734479072392265879 +1755c697-9e8f-69f0-b7d8-3d0919d2ebe3,3379847963,16609426162114974341 +184c07ac-7018-0392-c50d-8f3d879ae5b4,924021698,14456221377900576422 +1e240ce7-0e4f-d490-9154-bdb49e0d5695,3297542641,501403012070758669 +88cf1d04-b6b5-b68a-69c2-1b1fe3f7ef6c,2713483248,7507961066653003970 +1ad1d78c-8b6e-225e-0f12-e694b2e2be89,2879957166,18157486152076401217 +7b39c222-cd70-46ef-a32e-eefb5a97f0d9,1927171241,5477727841471327985 +ae1606a2-a4d9-769b-d52d-c29f4428de77,1550914382,7410752178785142072 +6834c60a-6b09-6042-cce4-e99d834fccf2,1152147408,8620622089717204815 +71a7e5ae-6a22-9438-03e0-d6cb876e8a14,1231718288,13979265758757969426 +77a2ed71-1445-5be1-18b4-e7b91794205a,2756990848,687104652142624383 +27691544-d405-5e4e-29ef-ac4e34125be8,1696267080,11299704773331007952 +44c809dc-6636-991c-bd24-097d5429ce08,1900600067,3092888626369677577 +3d36b9e5-ff90-af10-9730-6b0e6ebc1a46,2707080193,10829146758987359641 +70de5e35-da5d-8548-8f83-c54780edacb6,862852490,8076352847662437832 +cb5dfce2-e1c4-6366-d11d-76763327fa8d,1162976035,15807615282166805185 +15f49c2d-09c3-d22b-0fe4-7740dc10e2b6,1559344741,7348534598639132878 +06d64786-9323-84b4-74d6-d392dd8d45a5,1502564208,3400962094675248555 +bf3c1149-6d2f-4c6c-20ee-007eb2ece908,4015937538,584948361715144919 +c7b06027-0dad-0985-e6fa-4ffbc70bdad4,1804828473,11269728630732431067 +43ed059b-0c69-6c74-7202-4e8415ab4854,919340182,12025388373391024817 +12d10dcc-02bc-ba3e-5e0f-ee1e201a3b40,759894431,12181851402766771139 +bc067474-ccdd-2f84-5c4d-f6ca16c60b1e,1398968712,4396911206676369195 +d06b10ac-8ecf-e776-a93c-a8ed9293e1d3,1317645603,2596001306511960652 +d80bd7cc-d340-60e2-f938-d2f3bef2d45f,3790843053,12427848364991285209 +69a3b275-b96c-2ea2-da87-3f39ca8bf06b,740687688,10525435867311336808 +f43155a9-5e2f-ae2c-7360-6117fdb63633,3706171993,8857286192575887142 +889d8ef8-2f1b-8dd2-33c1-78362762d2de,2130924691,791470032843891489 +d73d57c1-222b-ede0-9d7f-c80c2c021e54,1305667971,15866508340234197423 +59ba2e88-fc89-f0d8-0627-c5ee0fe35ce4,166768230,15278586162764603518 +bcf67daa-40bb-2943-5d3a-b5c47289bc33,2520050604,3663361409808258305 +e61379fc-9820-467f-1cc1-15cfedf87595,1403771243,15911566119453340602 +e32cb729-ce70-cd2b-1365-1846ed72f960,967377353,955303826436163081 +48c8ee55-1747-8597-da82-63d63b305500,1866378843,8001394950076421088 +a7c1f444-5dba-41c9-f4b7-1b4912bb34c7,960348910,14313833699790553787 +98d00da7-4399-69c1-a0a7-829a7fb4c98f,1106201965,17206380809660574549 +e0a101e9-7aa7-9d2e-42ce-e09030dbd9b4,2458769557,13126446433527817866 +99faa9fe-c971-cd88-0eda-9daf0821c68e,4125979928,9152632853965964866 +a27008e7-c22c-3791-22ad-96556101a499,1247770545,2783179201033716425 +4c1d4fd3-b86e-2dc8-c957-26c7ac7f8655,1835897165,7000807557551121584 +a4cfc8d9-d895-a4f8-6461-e8f23ef5e2be,1745669140,14261407393498779891 +7f26351b-aee9-e326-bf06-f5d76caad197,2448479928,8596563464355606542 +c14c4950-89de-a584-373a-86b926dd2b77,4027805115,17137609135638639423 +2e6e3ca9-2169-aa51-b255-04cf074ac88c,3693088229,14415310196209422995 +7d3ea34e-8fe7-023c-3cc2-14d88fcd84ef,3623954094,6605235624308826173 +0c6236f1-c6d2-93ff-54f6-b4d1c535b1ee,4016530959,8219980233748315393 +5843dae2-e113-9c94-fe2d-a0ff769a7d8c,87012011,15178717071801001604 +42bf6a74-8f7f-d8c9-3196-cb24cb0f2dde,4156738129,11032965440259701275 +253b1206-b943-8d09-e224-952c68d62127,1584045659,5788251226795881165 +feff5c11-a898-7f2f-13a9-8d3b1e7e5e7d,989234353,8600399166530432247 +942afd6d-29ad-5029-d34e-7a7e0829ada7,893721904,3904179669632097270 +b9bd2ebf-7988-e064-eb16-f2c65deae6a9,2649498040,7054282133929989466 +798daede-e51a-9675-fc22-bc05b0adb514,1841368022,13442257744084105790 +85dcff38-7897-5fb1-b6d9-ccf5c44a6676,1510724394,9222947825212529968 +695382bf-bc63-7550-dd20-5977faa0207e,1893088017,11080258828660827338 +6b61eaad-1974-18bd-ef27-ffba57560a66,3921567591,462203539037289254 +a96d07a6-afcc-f6a9-72c4-6d8e9e6f1772,3240688373,13978416778684225914 +bddc6da8-2165-0f40-9192-f23eded708d4,2865451396,13432270646412475138 +7c008281-0aa6-6530-923a-9805f2887bf1,2712267792,8470594172477007203 +d94eb9c1-7e60-80b8-9e9b-668397a39eef,3337790433,1312575134627920389 +4a0f4f0e-e0d2-1b25-e29d-1869c13a6aab,2281697739,9213392866757069161 +47ed0f61-2709-e6bb-e47c-f609668c3adb,2414028027,3296310680946616956 +6551e2a3-46b4-7955-edce-1afdfcc41db8,461160655,15009933306103340900 +b2105dae-4514-1be5-3ef4-bc0a7d330bee,685901512,12742452894637093621 +ad227277-6db2-daff-c9b4-c8e2a3fc4f14,306560321,5399436738263089811 +8bcb1098-6108-bcef-2bcb-58bcd074df92,1097305818,2970115726421350454 +d5ba3e1d-7b7e-7e85-65a8-b429059d3775,2270653381,15811605371355573932 +fa56d8ed-4764-b0df-5f1d-b4e411bf6126,3197272636,3907977662624430536 +25c20e25-da16-0eba-d0dd-525f74929acd,3211698021,9245776021275989497 +3bf5e6a3-99dd-bbe1-7158-9bd882353ebb,1410778639,12965074775845520483 +434fb7fc-b203-550a-a2df-eb4505e50b94,1036651666,5843654047190839884 +91a3de18-fdb4-0520-376b-8db2ef6d6032,3191874705,5330959724757032994 +465a7de0-e751-ea4f-b96a-90bc90381ae0,2645894061,435780935792582716 +d50375af-cf0e-bc9f-f49b-b1adaf3016b6,2845152512,2688320651101596784 +262fb81c-3db0-d485-efc9-595e785cb430,523169284,13926169994866720138 +3a6ad291-aec6-701e-c60e-dbfdafd7660b,1073360251,2926447966331174453 +b35c4c53-871e-da3c-ed3d-1fe3e03d81a3,1165760373,10233589379073763195 +d03c987f-30a3-4779-6c93-717af54f7eeb,4015336673,78841696316771617 +5816702d-0346-09b3-6b70-a6c36e4ec84b,3340516346,1104992083169752981 +fce8d1f8-c45a-3ee6-7f1f-417a0f8ebf15,917342161,17980174953774690300 +9eb8b271-5c45-dee5-ec43-3bd3dbd3b81b,2251907894,17777891550197883514 +e5ee18cd-54fd-838f-9fbc-9b3020bd00e7,3052933887,7617333681344224037 +6c23dfc9-2f8d-16db-0aed-a06ac883e75c,2653488960,1287460953432691945 +8ecb039f-382b-e340-3fd1-61a673aded06,2369961813,998880254561296343 +7a008a72-0c0b-ee49-fb95-48141f52c66a,489834060,2808121954320079050 +ef81dfd8-3409-3913-2c4f-95ccba7dd050,480729209,5182798988176571350 +3c098140-8bc8-6232-d68b-4b5eba7d8ce1,1591252106,6244779092962965572 +ff511abc-456f-65d2-dfa1-86921cc433b5,4219170287,7253322935061061923 +6af2950d-9285-ea0d-626c-8fd03cdf4da0,2304587949,17498813741879054540 +f90f60dd-6316-a59e-bbc6-f69a3c1c57a9,509666043,17590669723515139651 +50ee48ee-1953-4d9b-ae7c-710dfe2a5fb5,2835788868,17291089505264322831 +6a05d723-8410-67ac-5d73-0c38d736a9a9,4011025871,3335546662697139089 +b6cdff64-baf7-8b4b-4495-f6fc9ddd7b62,1571462174,8909301856731178495 +3aedb34f-1f6f-7b8c-1a12-5ab62fea2686,339389605,1540806752642200853 +4c8ea222-a224-beee-6f4b-19b4e6e3644f,660283726,17404165944314100660 +1053a6db-78c9-1391-5a87-33fa133893a0,1762698784,18390588636548223668 +13bb46e8-78c9-a844-644a-70f81fc56756,2751334870,669203345395879977 +42eb13be-0c4d-99ab-111d-7c49f3b8e37b,664631575,4203430549625984582 +8d3746c2-845b-babf-128c-0bb6844a2902,2402580453,5237215515227451306 +378c9736-0451-46bc-f581-2d178fc90a4a,1151684370,9516947076276032114 +34036d55-498e-eb4a-d47f-94c2a2892763,4281470612,10601167801468956478 +e49da451-e293-dde6-72ff-ba0d826eeddf,3654287937,11268218737012628195 +cba1acb1-d7c2-d970-ddb5-938fa217a0ee,4069403727,5780913496396682145 +84f9ff26-46b3-b23a-f4ce-80ff1a8a66b2,1986559400,12966226350574629294 +3e0230bd-fbd9-1ab7-574a-ecb0f53a2fab,142593162,4140950042168061250 +bfe1d805-8ab7-11cb-e8c1-c137f36c54c7,1414612121,10096994776538479954 +09c71019-970f-75ac-3b3d-8fcbd34d4f0d,81019490,14307067048820090786 +c2e1ade1-f154-f1c5-66c3-ab7225791216,2677381688,2062557446211395361 +001764d9-75c3-1e90-91a2-8ec2934a48a9,852783668,8898572620691947818 +396907c5-d7ea-8c3f-4a2f-94fe2bfe10f7,3193386482,10705514251871701109 +4807c921-27c5-0ccb-b2f9-432cdc9cff4d,1096553024,2796481429219030346 +b86f66ec-14af-3cb2-b920-0f9b702220ac,3696551263,2089398260887823317 +ff46e4c3-3c29-5b25-5b9e-54c391297f90,2370471289,967887986272497471 +0b99bd66-38ce-f09f-487c-198b67e96f53,2159772748,15045716872722293605 +c0abad8a-7ca1-c2c6-9666-45f0bfe0c21e,2337348791,16342189219980885947 +5532244e-9081-5888-d630-414f4f9d92a4,1812416013,4741313867375049631 +3d4aaacb-9efa-b88b-8512-e848da79eda0,4105006793,17477797535121263533 +3c0af812-d5e1-5db0-03ba-1bbe9fd442d6,3913925049,6287701971290800968 +719a7466-4398-44c8-e406-e6f762967547,3682101225,10801877599194117923 +75f9931e-e7fb-9e7e-7b60-fc7749e22a6b,2577656122,2444966316168216572 +21c0af91-922a-acc8-e38a-0ed82914b1d4,3524876347,9327401359660625347 +9be96c28-eede-debe-82df-a0a73e282ced,4091774050,9714634586579594461 +a32ac560-61b1-56aa-4e97-c389210509f8,595893039,17114871780834967868 +ef6ec5ad-1931-e249-9bd5-e8fa02f7b593,2122528458,13114162413425379370 +92b12283-e216-cc1e-ddb4-cf1456cd7d05,228693441,15048037808017963199 +b33d5ccb-70af-76a2-41e0-d4ffb63fb99a,129001216,6245568056390508193 +f8f981bc-40f3-457b-a6fa-7a9401b9bc96,3160585016,8442769168393909326 +6d7ad80b-942a-ae25-9b8e-6bc35586dbbe,1058046314,12521055757468915035 +a12e48cd-160e-107f-2001-0688a97c1238,1186847007,7982448319012715167 +f39f789e-b2e1-c0d8-9760-34056d04af6b,3077129986,4289646553068615627 +f39666b2-2c99-5e9d-0826-d4d2a8ab7b35,1142083053,17050836346723674663 +4bfd5a91-dc23-3ac1-d114-e221356e3aa3,4207488301,5358438949935508074 +14860d4e-c978-077a-e453-3d7e5530e9fc,569909059,3151476151971078217 +d4655434-4682-3500-9d78-a27c3c719cc7,2115253155,10446786097948705237 +e22642db-8eb1-337b-a9c9-6ddfa1ae6d5d,1012506995,18289277028535778468 +65507ab7-e4e3-3c66-cd13-82e55f68d49d,4251076233,6769808875711809207 +ace2350c-0e04-df8f-7f81-06e86744a8da,3954426899,5488585161342175696 +713b8a6f-36bb-e5b2-57fc-e544591e8ec4,1514818237,781346815907698620 +558cc3e5-5250-a092-655b-117ec91d141e,1603841100,17248151102222018692 +cdee1071-910c-3f79-58f3-4975e03fdb41,1023645691,6657325226702333757 +dcb74ef8-7299-b135-d582-f38537c999eb,818280213,14678630656958162557 +821c1455-50a1-5d4a-e40a-186939bac74f,2744164163,12468285055725317239 +a5aa6d58-804d-940b-b359-23950c4c2550,929081185,12955418607573037694 +c9d80bd1-8810-1be4-31af-53471db434cc,4231474193,7762681428323700083 +69f2bf6b-d21b-78b6-53e0-67972abb9520,3138972708,3364232507230282123 +14549714-5fe7-7006-d866-7ffdb6eba15e,2445686266,11828918806078401460 +0cebc116-6ab2-22ae-8bd3-5cfb800fa544,1605237439,4921913168172428036 +f033d4c9-3fa9-31db-10d0-c4e5b8b99cd8,4153499085,1492495192482068028 +a6007c10-3293-e24e-5371-2d95f1815a26,2045107860,18000151336330399368 +d94b2d20-50f9-98c7-3f80-4119d39cf2cd,3148249449,1864448502505778334 +4f23aaf2-e25c-b7ff-1527-e469d7582a1f,2204969824,8727534704700155797 +e513b313-82ec-359a-9fc5-53b6bec12de6,4015810681,14008624999020379816 +bc09b29e-4511-fc3b-a710-698553a851da,1728833406,1275790306620176811 +5a4b3308-db87-be2d-9805-65dfb70a493f,3150278854,2773184740820985451 +c1d16b97-d990-854b-c99f-7de2d7a74d32,2380693930,10681996885758493534 +66b556c4-0842-d4eb-c0c0-22c98682638f,466686742,9824972474116734457 +43a43fc5-a848-dfa6-4418-1bcc00afbdad,4149799477,3294150183392480940 +2a6f832a-4c7c-98d6-a929-4b8839ba0ac4,2001244790,7175588869560788674 +d9bbc4f4-9dd5-5e08-a5a3-67238d13bc98,1273505746,6980768961350470245 +b22c1ceb-63a8-dd5a-7c9c-14153d32af0e,4031690025,5102325387561854626 +2adc9749-c6cc-0073-bf4d-6ed182f95dc6,3161326290,8516145522355670209 +f938f7bc-1b86-37b7-a175-abb1f6d79e70,2100597483,1867343364754706281 +c17b6a3b-4fc9-c804-78f6-fe605333f906,702411384,12004094937338189490 +fa6e39c8-34f9-9806-788b-0718c4a1b4ca,1894446415,2937476504803766618 +db2c6908-f454-e595-38c4-6a22e610fb89,1560490602,13857443446352355850 +4a400951-2f9e-3309-6afa-1c7065b6c570,1664996922,228396202861701181 +52ef0d9b-dfea-6832-a756-d6657ee5344f,4014141996,6984242884387822210 +90322c66-7c61-737f-a034-3a19bca701db,1909486621,11410261750026571599 +37abd2e0-795a-7202-db2b-f687405e9c10,3532103719,10659641029217667188 +4ffc9025-2630-2b1f-d5b5-2ca0b7f63f70,3293864307,13963072407841417829 +7122dc7b-d7dc-0d11-ea9a-4744dd5e9135,227816988,7660681283455902464 +f410b5b5-4214-0920-adbd-944fe8e868e1,1057194606,5928633519340170956 +62d2cd62-250a-27ee-fa15-a41aa93343c8,1048188529,10906416238739768684 +eec8a29f-df77-3c38-92c0-c7a17c9162bc,1119604513,3555449176746929676 +cced08be-6d94-b6bd-ab79-e06b807e8ff6,1065648588,14586219975085650905 +ae57f485-e70e-d3eb-3160-3a3abb2b5bae,315574171,13474258063676967844 +67d60dce-c115-32f0-0283-0671944d0d31,1476540427,16614181491425133515 +b8c5dc86-4a85-e1ae-e511-d23631be9e3a,3629206922,17245558133573965394 +4fadbe82-cded-bc56-df2a-33d4fa7d1d1b,651427598,14421273679959382681 +b43979a9-778a-7a56-299a-84bba213065d,1086945602,445296042707428141 +630eeebe-877c-aff2-19a9-530ac3ff284c,3683231411,18435946434131366238 +5eaf95b3-6222-d37e-9808-a4c4be344752,1171633421,10604027930721569439 +e55a97e2-6b79-5ce9-88d4-8c339345ba1b,2445553364,780655032538295874 +2396764f-192e-1c15-0f4a-bbaf109dc155,930039687,1841373320649318911 +be72577f-bd65-3c46-c86a-0fb63be8cf2c,123383722,7132935644420210602 +7c01c64e-cf3d-fe01-2613-17fa63d8735a,4258784124,5376555237707454226 +261fc826-fbd2-e3d3-d8d2-532cbe6a2578,4284461076,11915585623533141357 +cc8fc888-eed4-b87f-abf0-0c66aeed89cf,1695958908,16403069083610928310 +68cdb9fc-ab56-ddbc-321e-ce7bc8e3ebf9,3578622891,17346236264910739729 +3b0686d5-9fcd-e5e2-a5a4-d239980b3be1,1319708611,7141516775620921353 +bd37274b-b43a-4b0f-7871-e024a77762aa,757350555,16952816539661620787 +4ca358b3-b995-feb4-344a-769c001e8f0e,2249142844,858306619176559642 +597f5688-ccaf-f775-f70b-34d039886b24,10813023,13369719723819762625 +0431e6aa-b165-3863-d169-667bded9e08c,1114849501,13648366233612873539 +340b8c3b-413c-bf41-15f0-78cc3bb3962c,3104494780,5948773684488497579 +dd50d1e9-ea4c-e1e4-9968-eedbfb6088ec,3603676666,10821939055805262364 +350f9ea4-e99f-67b8-526e-186cbb921cc2,1138893616,11495882814988514718 +39e10198-d669-5e4f-9d92-123b9276d445,2887285509,6076848433993151369 +e3261a9e-3ad4-cb11-2515-c508e420a237,1637426803,5802022256880919234 +8e83658b-3918-c9ff-514b-0447450d7af4,1892160843,8523522262861518344 +da555be0-e351-3415-7afc-03adc0c7ec1d,3967103917,11748877079108675706 +8f72c8fa-7b1b-ab64-de7d-04d59304ef1b,1237713057,17686609822826221176 +04f6ca64-94ee-b878-47ac-1530d6a1c361,1711025871,10479002818200582586 +78f653bb-e606-dc9e-45a1-a7e6f50eeaf5,2286026632,11533930684673597495 +e69d0539-467a-b810-78f5-4519ccfad9a4,1294459824,2208301532433215379 +f3540fbc-672c-18f7-cf7a-4485921ebaa0,11027254,14197627363285319260 +7a138a8b-2168-9df7-a583-5d444ba1433e,2561290887,2013843250332435752 +ec8c8fa1-a0d3-c54b-2170-66eef58035ae,3223814141,2840113124700542376 +e2a04467-c9dd-7ed2-16eb-d5db24a18407,3562749897,15478418984224454796 +75df2e17-054d-a72e-8937-a240bff5b44a,1999784897,15506447548692959454 +ffbdb6f7-a5d5-18be-ed1d-a9c220a5f5a2,3785823861,8987905354922137339 +bac4a812-b3f4-04e2-66d2-15c28744c7e7,1148286083,7007292934008427386 +f66bfc3b-224c-0ce2-ddb7-748a3ff281f8,1871647984,2087587187704780933 +4b3fd74c-0975-ed99-fad0-3dfa02b18437,1261812168,9858521580276575422 +75826bbd-ff5b-ce87-e3b5-93010ba18198,1821632896,17566288583022706948 +22d1c69e-c7f6-46ef-7ac7-b8d08efedc7b,4160856216,8984460817582958168 +ebeb26e5-20b0-5f48-781e-03df389ed47a,2058444582,17211455541328974014 +51d665f6-9bc5-3e0c-26fa-34ab6e73b03a,1906734213,4335405414405736455 +74677d51-9234-714c-4ecf-43044956d31a,383997123,14900044904973804983 +64c67191-b2d9-134e-43b7-13feeb80742f,1922931425,11347935138801671936 +765b4979-0555-f22b-7dec-664373a25878,1098308971,13691158380825841025 +471e4c0d-7bea-ac4e-235a-bba86c8ca824,3630459162,1656152097060130216 +e2a73f29-dc50-7650-69e9-84a1df081c98,3049804254,15358132639706466217 +0c5584ba-0294-490b-4b66-3ae378769396,2338840480,8759894572664161141 +c368da29-eb61-5ffc-75df-6ac87494b1fa,4041039438,16904896159976190742 +1eb79234-97c1-e2d2-6707-578cfafaa80a,3258528882,2190043195058874108 +19283874-9eaa-7ccf-76eb-880488a44348,1018148015,366763332126995400 +a17dfdb3-5334-57d4-e258-8c99f7ad6934,1240649368,6396221595191583387 +14c38c85-de99-b0a2-afc1-9b1c830740f8,844130382,16243426534026326664 +28c7eee7-617f-8025-c112-ffbd0ee6b8e6,1422196152,1860455850753523754 +3492a891-d0df-d8c4-5e8c-5f171f86017a,3274225707,16728912637029580247 +8e01659e-93cb-c481-9de7-b947478a14a8,1001335200,6409355840435794782 +74636bd2-d614-61dd-a880-a3b278418407,3415921838,10919874034065952344 +558bfb19-c028-0bb6-e2e7-b8a79670183c,3463086547,16864601109833740955 +b56d0837-3b00-3193-5c58-acb550773eec,2733497252,11434213844449834417 +196e9056-0473-735e-9c9d-48498efbba8c,1465997098,5385690495996360387 +6b3ff59e-75eb-5933-e46b-9b5fba2927dd,656514026,7510518488479384800 +eb452cf4-d573-d21f-4a84-387f44f2be9b,4112437355,11165893660954230572 +98657ec4-bbeb-1379-e268-f1c56153ae06,599031540,8894161594767878704 +7cdcd19b-909b-a71a-3954-e602ec7a4fbb,448018278,11515757140803363532 +fc90cf1d-7ad3-44b3-608d-aae61e3d2721,1561371055,13677814718352259815 +31600473-7961-e447-1b23-5551c03cfb8e,2773641376,8260261998893158488 +ca63433a-57f1-7cb4-2c5c-d72ae876d2e5,4120740700,14418197501115369234 +46008f7b-996f-d23d-f7e6-cf98d612c4a9,2242598104,12680881789353357156 +a5f5de52-4bb4-ff10-c377-ebcb039534f2,4185599418,16011083381852725207 +facbcee1-0e50-6e05-4c7f-61f8950a7249,719670461,15395903616198031297 +03a64c4f-5cd9-ed83-f844-4176e8e76832,74551458,1228807473426859295 +73d4e620-1c12-a062-9775-0d65e2bc19df,1940055933,13863417818511879593 +97783c59-156e-0abd-4606-f81cc8d68c96,2893529208,4086924721177821548 +e1488c88-efb6-f488-cd08-fd3fef357e20,474743555,10461838270113231471 +c97533ea-c98e-c011-a804-0d2e93da06b3,2086706842,621909463380902798 +b091629a-e1bd-d098-089e-d855440c3443,2555931905,10221352739767822653 +c482f23f-3576-beec-75c9-2d9041d3ab83,3685137682,17459984923779025143 +264ce9fe-e42c-0ecd-25c9-c34038a593e9,3262808214,18178432116023259346 +bd14ef16-dd48-6cd1-3b3c-86a3fd813108,4059506222,1718144124906875895 +9b17e070-5fb1-a9cd-e9e1-dce96c9c50d5,1455741943,2833066319222601052 +a701293b-a91c-e9d3-e0a9-016218df4f35,4181156662,2588364445767063567 +ec4ec4c6-6e0a-105c-1cf5-d59eba69db25,3815658306,7685541555486216469 +48de491e-c3ad-a7a6-fffd-fb604a2081ce,595304747,17423239564865792330 +0f9437a8-9522-bdad-9ca8-c749d853776e,2126203923,5374362840507147998 +42ced42e-a26d-d594-0858-146ec5f3fdcc,2459384746,14704785973176664245 +0e3f7440-a847-9869-ab66-a21d99c9f68c,1109158639,11290215915245937921 +97c8071e-ff37-aff0-78f5-adac26f3e403,3038154386,6454699607509018169 +a296f3b6-1cf6-bcc2-400d-779ee3e05094,3682570183,14295291843665277647 +6f49e4f0-d076-c38b-8ae1-02749cf46a28,3242363039,18302389147646033722 +34bfeff5-9ae1-eef7-9db0-e834c742d6c0,3642164724,5889236261912271066 +c26d61ec-88d8-d7a2-afcd-2c3192574338,154505107,766454946673323672 +7fcfb187-4cfd-cbe3-86b2-77e10bfb2b89,3055176861,17175149320475802206 +11a44721-bf80-9cba-0058-bde7e8011f53,1659441355,1785390546843389270 +f9b4ebad-eec4-abdd-809b-07b43d9fb105,791802017,9668577569206012073 +dc6085c1-e3af-dbae-911e-26072b20adca,1376874951,9402603887520129553 +db113261-418a-fc12-4f44-e051b269b890,91348781,12447518382805263200 +150dacab-b969-9e96-99ea-1ea120b193b2,1003698621,5917700538677130083 +9cd79f6e-073e-d6e1-451f-8189752efb21,2784552753,13842575741475870042 +39b95641-fbad-d550-c6cb-5ce05bbd8ca2,445507233,2477818658080237554 +d9bc3af9-16cc-846b-7057-ed47fd42136f,2372236521,10375462599386460193 +c95da8e2-34d1-c92d-b50c-2c29f829f4b1,4225168645,5775206234636504366 +15a88ee1-863c-8fb9-f5c3-8d713d951faa,2759564659,18222557088253912938 +be5f99bb-92dc-c03f-207c-970bc3bdb356,3806016463,9375706137615481460 +d0ed8b61-c683-0644-0515-b86616abeb5c,486729299,9628151073403871836 +4f3501a4-fcce-3682-576e-9a20c7eae2f8,1914313489,5066234261755915185 +5ba99005-6955-937e-cc84-f2dd2c00bec9,625568635,4685576988772020018 +aaba0d0f-c15b-2bca-a73f-88e8f0611be2,3721983754,12200965509119282420 +ec0aa8ae-6f55-ebf8-b350-3db9ba228e86,2341520373,11772485552675692029 +ff9891e6-64c7-0f2f-de8a-9f1eb50a20f4,622719184,17838699040964948131 +aa416188-360b-5cdb-8699-e8e504ee3cf8,1318067694,8210680897822747203 +bec600ed-632c-3496-e0bf-5ffa055325ca,4001017847,10341595665029293259 +e9f17a78-7db2-19bd-8c71-f9b10ff6f750,3251480288,17261012497208913687 +72b0ff31-ff0f-c564-c273-831cbb3c13b6,3532060550,12383623252284816342 +7a23644b-72d3-4d94-de32-a06138145e57,3949633263,15993727098792635633 +de741e7c-d8fd-3f2c-8794-af25ee7064e6,2379889465,13607533049263292921 +56d6dd48-eb5c-93c8-8ec2-77bdb60d86d6,661608797,4186886879031666587 +e2b92e6e-b263-c2d3-1b80-9c0818662f8c,745280385,11680116736811715377 +402f95dd-a607-7684-9a06-4f49f36698a7,1895384823,1899798490312090068 +b1e18838-ca94-ac0b-edaa-f8f2decad071,745298403,17286182024636032558 +d86bf927-02e2-0593-1e1f-fbe5afbe9df2,515445274,4599455761924755717 +dde3b463-7f23-1595-1d5f-e90166ae84d7,1758749590,1076105136604705021 +0b57691e-2c23-8f6a-efdb-32c453925692,3256840889,17951565521172629510 +d4ff0a40-d20a-6aa5-26f5-bd4dbe6919c4,481851502,14404864469370403724 +a2d2842e-383d-4aa0-3cd7-231567252bad,936116712,781095813566384599 +f6675873-2371-aebf-bf79-944ae192a29b,1382507889,4634895052997176333 +dd4ad259-1f3d-d66f-7beb-69c926795b89,168053980,2967649072234195414 +b1ca21d8-6d3f-9121-6015-797847ba5e9f,3596023532,16788678207235554866 +54f8968a-8e28-b43f-ad9c-b2feaad45859,3104639138,4347440775883462163 +9acfc029-c898-a0f8-91a1-28109d6309f0,932955737,16010977888453005917 +3b9f1e05-d4e6-bce5-fe08-8e981d53b5dc,3213658393,15186206064841884464 +b8507701-28b1-74a0-7d96-c159bc4973fa,2325723098,12852890449199659120 +5141c53d-92b7-3754-e343-710630184448,1968228070,3413048814640167092 +57e4bc82-2b47-fc97-e6c5-adaf0ce74b17,156598488,6665487678851722780 +7bfedabe-7b17-434a-d6f4-fddaaabea2ad,1250111628,12564767669251561825 +e56bc757-774f-c241-8373-bd7c63b9638c,2071903914,5285157281186397803 +be2df334-a6a5-fa48-d3e4-1cfa7e35a7fa,3211829815,3290585749482428256 +fb270d47-e600-6128-1a8f-6dbffde9ccdd,3193725333,11700039566922552925 +4be934ff-63ad-d140-55f8-b853bcd00078,730701770,7705853728712356103 +71607043-0208-9bc1-0d30-84241b2ba5e4,716677825,13791197901517025263 +c15969f4-fe6c-7b76-ee25-be8b8449de2b,1658767312,16520736355308408436 +d391850b-cba4-0901-6e3d-b51930a27bd4,502729506,15757686817459641532 +50dcdaab-7a54-a0e3-6274-c677e3da5389,1614156923,14870295549563779098 +6e8cbe14-50d1-1b9f-dbec-f1ae27bdad82,650929484,12757792437153956759 +caccc358-5694-2ca7-6082-53062d867849,3777401742,15128979162420875684 +cfd5b5e0-04df-391a-4f48-500a8d945043,2432965479,8033424765123059786 +f43f5f0a-ab80-9589-5678-a9be1cf2e370,3704128010,14108409665250994161 +5606acb0-2653-bce6-5eba-017576ebbade,989956051,13660755800417201910 +ec3fc417-4168-4c4b-f310-ce236ebd71d3,788296101,6555296799648261585 +576a7834-1fd5-84cd-f047-a6ef551ec8ed,2653257099,2939746776211188135 +dc71f88f-47b0-8cf9-7bd0-f149cd990546,3429794116,4672054563428322308 +acb903ac-7dd4-87c9-abde-076ace052e21,504330895,7196165543448135506 +65d5011a-b85a-7a3d-8864-6e70f5ac5a1b,190515274,2203927845037150738 +45993268-ed5e-4d0f-0876-69a70b3ae875,3208820722,8937345106794258390 +80f352c0-76cd-9922-ef87-963dae78982f,1725733715,1334021053067229452 +57a10354-3d2f-694b-c0a3-7c1b7ee9e281,1331647234,16757282962408979658 +d6f28788-9ba4-1550-ba64-252fbc1653d8,1099978582,1953763341949901403 +64312846-b8a9-aa59-5537-0d5a270135f5,2421016771,13974053400689746812 +1675c569-601b-c018-4882-bc9ff875b521,1759886678,12675654022181226214 +641124dc-8369-1b2b-4970-f4360fd341a8,832634343,3209789650770382953 +c0089f5c-4e04-ce1a-de3a-d0e8eba9ac46,2608997113,10115669576457606619 +e1ab915e-5680-f3cf-d2dc-77dfe74318c0,2450732227,8459886503971939320 +3e09969f-5a5d-053a-1c26-dc76d49d9152,3885884887,14240842627550862069 +d69175d7-7645-6c54-7d5d-7254d65adcca,2723111570,9607206295221941762 +43b44864-1018-2deb-558c-4c56155ec865,4217011991,7294049108688350812 +aa675253-fe90-58d2-a2a3-e533de6a4fc5,598688338,12669540210297318172 +376681b4-e15b-6986-253f-b41c221f16cc,2137840729,2117658901581814530 +3356145b-3af8-5ae1-096e-60aa16cee297,519874845,18290177823216012343 +a162105b-1ba6-3e8e-c57e-67eaf875c3df,857707724,16466679863680433886 +8849aa40-8680-be75-fae2-7de05b628d97,2126867380,9630819224777562771 +5c4ce0f2-33dd-db67-fd1e-b0df1412f7da,1379039985,10341214671926507085 +fa1fc0bc-95e2-72ac-070d-69f28b9118cc,709352624,12700400333594409318 +3461af33-72df-984a-f03f-a49bd9433c8e,2565675728,1051550088873030986 +43d1e33c-3ed6-78aa-38fe-55871e2d6604,1684015492,15939538983172708366 +39c888a0-cddb-86f7-b4e5-f1ae596cf355,3557389874,17803861361200663636 +69213561-f48b-da09-1ceb-6cedae362bc3,361513384,4453020379410832894 +1cbc5eb8-dbb3-b07d-42bc-6bc27aa3afb2,918619256,8450573606123893720 +5fb9fddd-dcd2-0e59-3dd9-ad9bb0ec69fd,3373620429,7246654161474570880 +1c646de0-0228-06f6-68b0-e29273857651,42287174,16837256522568770575 +575f4b16-f2a1-b2be-2489-18f409ed53f1,2037678143,7249914796532071981 +06c43b53-8215-4372-30a8-02cb5c82f92e,602470673,6269494818449052419 +4bb7ee64-25c4-35f3-7594-6b1f5c788346,2226799563,3208396073960483800 +5c1acfa3-5d34-4e99-b429-fe02188ddcc1,2151795428,6343152856724935240 +dc59099e-b3c2-36c7-e173-7e76448e30a7,2181787259,1516213099614131358 +33372158-4fc6-c1a0-c57c-408ab9477392,3718930508,5674191826173986204 +7d438b23-7b6f-730a-a748-2bd55cf1a154,1245493777,13822131997721452826 +5901f4ce-830e-f151-9440-e4d6789db705,2959051454,2736924563156034962 +27988c05-8946-2635-5083-97cbdecf9a86,215035345,15630677337885207038 +e6e695d4-b6ae-74d3-2d1e-18ab15263ba1,1823348342,2522316691581645489 +3635b698-c3b1-bd13-350a-89aca790f777,1248888312,6280895763692335424 +6e93fddd-c959-c264-2893-f0bf7b42b05b,3771259047,785991026334107282 +5c07086e-fa5b-799f-d3ad-951ec267c8ce,1689127702,11152980911823988033 +97aa0432-6525-553f-6794-82756076e6d2,2355096470,6260194729080556505 +60e2f648-ddbb-b013-3dd2-dcd029550120,2034476068,2807770520034784869 +e41550c0-764e-2a55-a7f1-2d62f1f59f33,3895219289,2305604346005793649 +4cffcf30-aa0d-7603-836c-fc8b474ca8d0,3557034470,12874449407947416426 +c35d52e8-c447-afeb-c41c-29c1259e631c,66029233,15989321382921263973 +fcb4403b-994f-8faa-c1e1-f712c4a8859e,67523944,369356558146714786 +b99ec4a4-f012-0ae2-01dd-6e15eb7f1cfb,895658341,3464737488862474759 +459fedc0-b0f8-d1b6-43a7-d827a3206d96,3126021946,3830600341550295125 +ba04b258-d0a1-9396-63bc-3a2bc64ffc4a,1982157856,3930904595629867693 +d951d85b-cc40-2eda-2ec9-cf0ef1de4fa0,661534414,2831871628661497717 +46c53726-f3bd-a144-8ae0-418b1f148699,3322037380,12644882623825892309 +232dd141-084e-86dd-ee35-436d29573fc7,1280755096,15205718649727485096 +a87a4c3c-09db-a79f-51d7-e976f4db747d,2259222135,228146686762045581 +2eec6cdd-cbde-2ff0-b1c1-1df790d9499c,3160367126,13029266464995853834 +284b2f2c-3a84-444d-d278-7f6aed2ca879,2473874875,14012748473004012060 +5244a1fc-347e-78fe-02ea-c977264fc798,834331620,3251059986775129979 +cd0efcb8-e101-21cf-0066-46ccbb696df7,1041758737,10880901376066884646 +8645f87e-362d-3675-223b-4f54386acdef,2864829231,12725136443388127184 +c36de2d7-807d-f98e-048d-29848e028982,436557618,9136360026724058136 +4e7d1f05-5ba4-864b-57dc-d17c12abac05,2451519041,5487392679099953893 +cf9ddcaa-ee6a-b367-7a64-94039d97d458,996003804,14677163778517696817 +3141f315-c1bb-27c7-f7e7-97a44354eb95,1082393575,2986276591691964926 +1d44b1ee-f8ce-2b31-24bc-94398ad93365,4085077234,12350144594580408918 +666ace67-a497-1190-4a21-297b3123fdaa,127622308,5409133233733125186 +5295aa31-e02c-0532-9601-47d267745a47,2726442800,17605592133495188625 +85515447-960a-1618-e07f-1ab5aef7f5bb,80193031,15009692588655509968 +2a35db99-b90c-b5b4-7c67-c8a005574229,3825829539,2880578748535895972 +868dba88-f1fd-4dfd-a517-bc672201c558,4056047340,1838386010681110589 +648df9b3-c29c-b8d6-027e-b0340d329e3a,1288453311,2985388868261976458 +184d6bb2-1a7e-5fa5-70e5-4ca0abfe4b5f,3471884749,3074268021514098219 +582ef254-1643-ce36-8212-0fa454b127dc,1146142974,12755420050458609411 +31170533-eb2d-66d1-8c2a-89a005200974,1130873948,9329703565593235439 +9e0c62d9-43dd-a824-cfa0-5488df0b2d58,2185428005,2134904869932293284 +c3cb9ee2-8487-e5c2-46d1-750cabd4617d,1765895138,1038507121380384677 +fbf778f3-6c43-b5d2-df91-0f1ba7fbc102,2247186963,7164370345698511954 +b646f38a-9fda-d598-23e2-dedfe24b83f9,3350315694,4179829338800365888 +895ad1a7-6229-0359-e13f-1c330d3cf7ff,3710957519,7095955175366849470 +fed98218-903b-9968-73ea-eb37f8f4a342,2175830253,903311604392252061 +c58ac953-48c3-2694-98e8-8ce485e0cb4a,2926640862,14644044085948252466 +cb8fdcdb-3bba-3e18-89ba-4f9151a13f0e,1644460852,10982188846996173598 +edf38114-cffd-1e94-eae7-54b996981d54,1716240170,9302102768244458169 +0e527602-cb86-526e-e0e9-5de9eb77406d,1668575801,9715973916146193352 +3c2f5782-1a8f-04e6-2bc4-c8f2a9e06ec6,2871499116,723433402433022091 +1d7b0f8e-7c44-bcdb-ec7c-c2a37472acf2,2105754092,6641592767218195895 +b4a7f74b-9b5a-22d3-6054-58139bfe93c1,3359145390,12834962082243212735 +51caf624-bd4b-59b2-8fd8-8b7293401d1a,2568767518,5274271904411418152 +4f70858d-fabe-1c85-c138-fa00a472998d,3939227187,12298792930901941008 +8264ebc0-c11e-116c-ca22-c4d69d8a770b,2213544505,4399439117888399726 +13dfc9f9-433b-b16d-5723-cb4ba69c687e,2589782431,6316020717673501099 +5da1681a-14e5-486b-f193-55a4383e32bb,1358884873,10759862724646985170 +ec9373ec-f971-1adb-47b0-a7ff31d5a35f,4031282422,13562313597198165935 +2ff43bd1-a07f-3ca5-391e-850c7ad09d2d,2909534809,16334433160525617817 +d399350b-2347-c8a2-4339-b9a5b72a4f29,1208012051,16719742172119033987 +3aa21883-12b3-705f-23d4-a423e1a94806,3500734653,4464026629811390525 +ff18bf2b-4843-0da2-0218-34afb4502a0e,801654406,17470242237658225493 +7b990c27-c589-4304-de9e-22ef49b3a753,2426614039,12231667486555003643 +44607e74-82ec-a4eb-b206-6ae57879386a,2537112371,11094539413400957191 +e4ab02cc-cb1f-e417-dd75-80400f2395db,1368052328,12922026364288794532 +896ad187-319e-5e8d-6a02-d02bb8a6ebf2,4139576546,17980666004375451990 +ae0a8b35-437f-92ac-9817-0108929c1294,918489996,13902877140038034038 +a48f595d-461a-9dcc-c856-717cb2b35cbb,3949644386,255591583854270294 +38c182a4-3692-eeff-b537-38b21a270230,1060720616,13573544755577543431 +1c9faffc-55e5-7464-6db6-d9d93365b03c,3594764570,1794790274481311729 +e6ffb323-3742-49db-a655-b8d58964e2d5,2938738797,15058631483691308439 +9d05cfa8-e2a1-4cef-6cb3-630b46e24677,643054678,6622242240517565488 +e85f70b1-6165-8daa-2b45-920a940cfa58,2516036761,1835226520298143071 +1b6a13b4-b29b-3897-c8f1-2459307c4a65,2520376002,11480739725907680043 +07526b1c-8660-a92d-488f-84101eb0fbd9,2924761437,11678011332172185382 +bcbfa9bf-ed48-0fdf-4eb7-441b629eddde,1030100541,13275669125129127242 +f50874e6-cd49-f10c-fda7-fdb0242cb30e,524834748,15154239729794119113 +bbd9bbfe-43dc-859a-1ae8-b552d55d991a,2334838428,17155281464320509708 +ed5cf7f2-297c-966e-575c-c5856a57424a,312114658,582454906116093611 +bc55e932-f2d8-ece4-e208-ddc58b5fc343,1722926850,2953895663839795458 +7c72b839-1d6c-52d6-d454-162d50d84f1c,207391648,2906255736597079738 +4c918143-4a29-1c25-fe31-583f8440d38a,1315123858,12741761200928074731 +ad46b7b7-9ea3-104d-18bc-3bb5bc02940d,2431143959,11575489642330505325 +ada64a89-0756-15bd-6932-b34b93416b1d,4014376391,15881428268827236628 +b2e9a5f2-c93b-b94b-6f94-0957dbc3b0cb,4174194088,14726862978041830985 +88bfbbc6-1115-9ac9-b614-27e6ea2fe2aa,3391807475,9402609789529157288 +af536720-cbf7-2bcc-a681-fd1fca002db4,2575618855,11573277485922006133 +7d2c7f71-278d-7512-eb8d-82d52db62731,3197977215,9771508277518641306 +3125ddfa-a2b9-3fd0-ec2b-fb02b0e6dd3d,292780638,1032834568697906986 +0d4cd940-d3ed-70f8-2137-a57eae4b1cfc,1122324108,17720384951598737251 +12765cc2-fc01-f6e3-801a-53ba8b978242,2344492821,1836211769315371408 +0666ab05-e748-d921-e88a-d9f008edc856,1076191041,7358194773009178463 +bc37e0c8-79ab-a24c-cdfe-21bc4827c159,1765657234,15678921601342179224 +bd1fb293-d4f7-64b6-e087-8043ecb2d159,515867770,4177511411511897284 +f430e26c-6cd3-f7af-ad26-da0af4e53eba,1682589793,11215366758354549946 +a0cc2c28-b4f2-8b7e-3da4-7ee95e9f8e73,2919650713,3193381568892478074 +b25645e4-d5b4-b5e1-0ea0-7bddd1e81de9,2751437421,14620804379032642276 +d515ebdd-73e2-e0a2-e583-bdcf479aebd0,2629447285,15850253855587631062 +2723f56d-35d1-e5be-dc28-37fb214c0bb4,1521090915,11646235184934757002 +809f0d56-d9f5-3246-47c6-d76f57ac141c,2163383453,2984189673969848456 +0e880e1e-32b9-abda-b92e-94d3c029f286,1870083462,15613458431865266814 +ced3ca56-5db0-3014-1e1d-6bc408eda6e6,4058736203,5237117889960216341 +3d69a1ba-f84d-8c69-5204-00a9731c3d2d,778489314,8069686385842331462 +82271cba-6000-2eac-a650-3abd1c0404d1,1165282549,14842535136406994180 +f780b45b-9779-e190-6d38-b8110c4d57b7,987532280,5302014267328361975 +3b38ef8c-1083-9582-1e86-38e0e3b5effb,2411762153,14055638483399223743 +339a56a2-0230-20b8-3d87-aa790613bb00,3525467539,6888741540765341573 +9b8877c9-a291-d6d2-a5ce-d7593d63d215,539553771,14148479917806336867 +993c9523-a640-80fb-9bca-9b3cd508223f,4290534129,8633108454857951372 +4dcfe7d6-3d80-2e0e-d86e-67b0ca747b7b,285714745,9941989909408507171 +c5e3d20a-2a13-fb24-ef74-8b2d2317d2ca,984855275,1243790015781328536 +3929f73a-09ae-f1de-036a-f683ab944c07,1480564422,5398809072344897550 +9441fe90-5e92-721c-37ea-9b8ee5e75fb3,2278727632,12997172108455519282 +0511ac78-64c7-de73-83c8-630c62392ce1,4255284786,1769921808199506592 +3a5512fd-b3e0-67c1-2981-8df46c03c8d3,2009578142,12861709221470609626 +06081c7f-a670-ddd0-b38e-92881b5c2259,1262125806,4028698053938046033 +30486bce-2ad8-fe3c-38d7-556ff03b41ed,1022645347,940024340244689196 +bc219a35-dda2-4f26-c984-c86b83062e9a,2865894291,18027469558452241145 +d385c0dd-ab85-bee5-bd87-2a6a477ea8f0,4289183864,12428519418113048993 +338f2301-bca8-7796-02f4-c481f72fab63,3721324473,5608081281098045780 +f56d9731-b3d0-563d-a6d8-2c399f918832,2169128636,12901092923030642134 +6d843194-ae8c-a6c0-46da-739ea63f66cf,349281259,12199012958916967067 +3d2b74ac-940d-949a-1b4f-7cc7df43874e,1701860665,14746245212649963972 +6dc1c18f-32bb-370c-e662-694defab11c6,1272120274,3818915705426917467 +65bd20f2-6033-4453-568d-143e9fa18d1a,1401117812,2691207500136644812 +d412333b-3218-9c1f-d707-b5b5f057261a,2023917077,17656479568291865542 +e2b90fed-3063-b9d7-3d80-37c4d486a76e,2539409403,17530102237168329682 +2a5f0f7a-d898-8001-ca78-460358371446,1933981859,15244709744100634220 +35521447-3170-e35b-a29f-886ab95c28ed,1473655967,238982674405550501 +d82139a3-c4ed-316d-dd82-eda407320196,1873029135,8846544104439474165 +2ebfa993-bfc8-0aa6-38aa-bebc5cf7fc3e,1086294246,10897199979459473565 +c6085c3b-4131-cb34-17b1-53e1ba82692c,2060311386,2437233825146067023 +71de2d79-38b7-93b4-d85d-15dc90cdb63a,1641351018,2274097281079411678 +91f049e8-ad16-d9d9-5183-a8b6074aa5ee,3423480126,11146416619639028826 +09fa4644-6db5-8b4a-fcde-70685c9ce6f1,1646668484,18088125110588434512 +f8976594-079d-29c0-f336-c8391791b1b0,763553110,5744275910382808898 +84b1cf9f-efde-e97b-5672-26eb1105c182,3410999361,10014655030750822917 +3beea4d7-a032-a4fc-fa1b-113ed28a12ca,1404478119,7705513453652398056 +96eaba83-4ce7-49e5-8a4c-1731195a4bd0,389371089,8774308016331427475 +d55ceccb-7e07-8497-9b80-e5d0110ee869,2399231161,17130666656886037406 +bd6c6329-7a58-49e0-b37f-1efe0449a6ce,3581204762,16179148386086836125 +1baa69f0-3bd2-36eb-5ec6-cd82ff6c4862,3250073025,13343328639422434730 +59bac1a6-6fc0-c4d0-4d42-0ce240941d76,2542706239,3734620686751611430 +31dbdd3e-a398-beb3-56cb-83116b922daa,1443535925,2516077724376448695 +a903902f-cf61-2176-a3d1-5683920e28da,2190381089,14331764599669753369 +ceb1a279-0635-940d-8956-120ae40fa78c,3052336398,3354045988197194206 +32c4d45d-e0d8-ec4c-aedb-ed94094177b1,1998780831,16940182972721593533 +0fcccb85-76e3-38e1-2279-81d319bab878,3207663826,2472844207621769707 +3f4004ac-1214-95e4-e6ce-c57387f64be9,1120283920,16162089080878438349 +449896a4-022f-d2fc-301a-c976acde2130,131435604,7123819063628759433 +ba860f66-ab29-2fe0-7670-672796d401bc,3629682,12345805551181702723 +3ea65a02-ac49-d37e-7806-95c6c10ad4cd,1471062852,10491047226696160561 +2af8b3d0-66e9-66ef-b0c2-2dcb64bc61e0,243149640,794019070661294957 +5a2f89e8-32ff-6439-644e-066d26f35dfa,560247998,15684737959508549993 +a196bde3-135b-79aa-b6bd-1b468ed98fda,63668026,6358681690007580465 +baad6976-4873-d5b9-6bd3-b5201cf4999d,1137008677,1261954653015926466 +1973ebea-155b-9323-a1a8-ee9b818dd1db,659774516,2934147480236251883 +81761deb-edf9-f43c-af60-570905b5d30c,3527039088,4559995180464540507 +50c6bf2b-278a-48a5-f1b8-3755a1e79a11,4049573309,18255479468926939231 +48a039ad-2046-ad6c-bd38-b6a76b5d1a03,2580711566,17424524451111602000 +70ea3dd5-d881-9159-80f7-c32bcb82a375,229401822,17386120206579522782 +a34a4e08-5b49-8cbf-95a4-1273a8680c5b,3763108633,8685492421920876140 +68670410-407e-2a42-2940-e710f3d72287,1789724234,5240676376047689461 +adde7530-3576-809f-fc43-2229fdefe2ad,2892224091,10846523442211997795 +a87cf232-c27a-a572-6f5f-40012f9d2775,205701746,12852850845235249021 +f044d7fc-9333-61c4-9ebf-fb97e8947296,912442632,6575517040074098866 +c67b63a5-d9f1-29e3-0f59-45ef7df58b2d,449418455,305218403594131858 +4a340427-7ccd-134d-1e4f-99cafd7fc4a0,4111400099,4135481452311556099 +ed7cfa12-f303-5f51-8d1a-31b0ebbe31af,3375532392,8328662955767437789 +37783e53-caab-c662-e451-4cf5ab43c87c,1347270154,17376614137864914011 +a9d2ec35-c24c-011a-54c3-6a36cd67b1f8,2335733303,8987295217881182979 +9e0dd55d-cab2-f1ac-b1d7-3ef3d9f9f53c,4239132844,15907579251064616060 +2a814488-fbc1-0ffa-ad9c-e521093758f2,2952444996,10195562924149403761 +72a83177-ea27-111e-1a80-2d3b43e2c1e3,3179962346,11975131312300950392 +e59cf91e-e92b-1bde-87a8-b91fcd1a8049,2263362750,17487081337330857305 +f6063dea-5c49-b84b-d0a8-177ef5a88797,454889999,9144508567958096078 +f8e808dc-4e74-2181-7fcb-a062d0309f80,4142231606,15639631104211130478 +03a501ea-1da1-14d0-78d1-aef4a18415a2,515598399,2904296157503854389 +9f591722-fdfa-23d9-23cc-49a08c6d09e1,3520736115,7981581412552992809 +ca0d2a25-7de0-0d0a-cd8a-62669e606e02,1498631520,16705147430095990998 +d57f054c-7068-130c-51ea-a688a92ac3c4,997538257,14590737835201519789 +61e4864c-9c7d-eb0d-aac3-3f5edac7ded6,4143097133,9761081369217306688 +a663159b-7bce-cf70-cc10-a1eb96884ca8,3817947289,11439188283789082808 +f229a59f-39d3-343d-d4bb-3f8368fedf8f,2488091732,228510843349878024 +c07e934d-8173-68ff-278b-4fbbe70a6008,135447767,5070929659873314070 +43cea722-485d-1168-4d16-93c6555b6d7d,228471210,6358604037896974272 +80130dfc-c251-d3a7-3c1d-1dbac368f8ce,3076350838,4494494218981634823 +cc1213ec-4cde-a99a-8582-4f7049b03a7a,1602967865,7142146055647960368 +0d68974c-f267-a627-1c3e-e6a1a10b73af,2136674640,8760765699158222420 +3dd980f4-e032-a226-3a89-d27ba761fe3b,2132262679,8383918288704614390 +3c9e218f-7c76-edd2-486c-95a9e494a3fb,4273593278,8788974500206929389 +bee46457-a711-83f2-d521-111a8bab2e9e,48172765,2469062138415159282 +675868e3-c8bd-d887-e3ef-c8a56d219f79,1475653011,8532389182930157671 +a24bfdfb-a9e7-047d-64aa-5c167db094b6,603976667,2993267924140313849 +54ff9856-eb9d-2351-ab31-c025490dc66b,580916907,13540568355489380923 +15ee7d79-7da2-9055-7b0b-a47b7f4156ac,3212946735,16244739924139572131 +defc9fc2-41bd-f212-5cb5-6c5fd1a89944,1566576861,1789645542339476209 +091f825c-cee1-c70f-3007-3defde42d994,215540817,12431155347084532732 +ada278c0-b64b-f694-3f4c-5c681a8e8239,2359769059,10131091827997599922 +f3306db0-f121-f8fd-9a07-8e5c774e78f3,2360455183,18043482688602442059 +c7d62330-7018-7941-1c35-18456d77e669,2495497983,2820762462429620371 +c8d775bd-a736-1a60-42f2-4f2701646fc1,781754906,5791619155897904440 +e878447e-4c96-f30d-21c8-8fb58e6455de,3856289479,3948619495388745392 +4c93952e-2577-8516-3339-2483138c1999,2560969597,12059130984227297450 +521855bc-4427-3da5-947a-f604db49cef0,3460718720,14524487059024256719 +db30f827-0230-721c-1493-0e01bf5162f2,2667361243,7499320966717913124 +d4fff62f-f373-6c34-4ed9-56c5d9ac0dbb,3537125289,15986568083913369143 +f8e0a34f-35ff-f408-3538-66d90a947712,2608292531,16197034821925193587 +1e0175fe-a094-14a2-33b2-54a03e9888a3,569115196,14676325738975803956 +c0127e83-b5ab-b0d3-ac4d-624581855f91,817019971,7118394934027455978 +395fdc14-34c2-f67f-18ba-97ddc0a817be,2129982839,690223695262389850 +e8558153-f444-fe32-1693-1db0cb2a3f17,3298373935,10287576968797942288 +b5a59c3a-3634-5f8a-4c3c-81fd61f9ad9e,802313099,16380535685073309019 +678f8912-6baa-7267-175b-88abd4daa38e,2762106214,5073359673765760529 +1d711716-194e-110a-3972-b4c0b4f06628,4112716861,16095470520370905415 +db4204bd-1ea3-34dc-df98-53ed17734ef1,1099202178,16420175374956172949 +ad2e57aa-208c-d733-f953-daf3cd7d1d7f,1713555960,1194058002938719948 +23d58ceb-af53-cfdd-87a7-9c15abd86ed0,2276358243,7464410620379861951 +b2ad5caf-a423-1d30-8b76-7a194367890b,609514926,16609390150993270994 +03421c37-80e2-a7ed-4ae5-e5775b08150c,1444929003,17731737388672232382 +2053d054-3710-6a88-889d-b0bba85ce4f5,4163770354,131739875816145996 +00f3a0dc-47a4-d35f-5bb5-0cfa4685fd20,98545566,10965307720029995546 +383bf024-b058-caf7-56e2-813e2916516f,2746969156,4204892842101914831 +07b37f33-220d-8baf-0475-0422f8579a0c,2531122936,2183165602093120977 +7ff2da62-3528-d6b4-bc5a-2b71a954a8ce,3843123382,6957795209198772094 +7e7a4857-e02a-6551-1e0b-23a2cd4a9e70,1001594053,16818028937635704397 +f03056bc-6103-6b7d-4761-f0a6dc90a68d,2789490403,12612461268872766402 +bd4d986c-135d-2cfc-3af9-01fc33c16a9b,3247316501,9865561689932329659 +2e96b5a7-4b13-56bf-ae79-a20b6f7fd656,613588,1798561643463495705 +435a407b-d2c8-3797-f02d-2a3836c53ebb,3986093161,17403110084149172328 +761a918a-8a6e-1da1-4a8d-9c47c492768b,2885819528,12892917964415936545 +953f6c7b-ba83-9fac-f0d9-b3de6fbced8d,2512676423,16624092879530241459 +0d29756b-54a7-c047-bcf1-1fb19d50e929,1630934561,8794851438061311482 +7faa597b-89d0-c227-9c63-54c0dd68a574,2875585681,3825465403430445139 +f01e7733-98f7-8811-a074-a23362144f0d,2538736944,12957946451367695331 +1d4d2919-d809-ea82-8a1f-deec216f54ba,1141174693,9315215340656900232 +129bdbb5-a0b8-cb18-e266-be7ee01a06a5,3365889285,16901873702812774936 +8cc57406-584a-d64a-5bb4-1a1943ed092e,2867307686,6180726834114095590 +ea333e9f-ed95-938d-4838-64007a6507cb,1068665187,15742752638960768680 +92112fab-6e0f-4dc3-fd40-ca8e2406f168,2358732163,3280246747474846677 +93ba3ed9-61ce-068c-30f0-c623d9dee931,753499908,7777625335836779989 +a61debe2-497e-fa57-5e0d-29f2890441a5,131369583,10836936511448689354 +c5651b39-46ca-2cb7-dc67-e59fcf84d47f,2336018754,5188482341061439720 +a1816555-40c3-8bfb-4941-fa4e261dbd03,1845715649,213327633266665933 +cb36b96a-e011-bec8-7135-f4589f4decf7,222271234,11542515232117846153 +77aa67d9-564a-4566-fcc1-4e1906ced110,3318203241,3318010066664698858 +ebd70556-42c7-c508-6c1b-0f81de73656f,688027576,16112587827415991682 +3f4b0a96-7a66-ce43-4434-deec31a75ccf,3967696422,10071116095819732340 +45d41741-bbde-07db-38f6-a65d91619ad1,753212771,3315246018403359600 +fa2032c6-68c2-6625-2c43-e7848474632b,2201854992,3224170313924227260 +8006d0bb-d0df-26ef-ae0e-f2a266e09ecb,1099879549,16789845010280878367 +bf3830b3-a9b8-f05a-71ec-2a9cd888e59b,3288665551,15727107053790475881 +4065c21c-d377-93cd-f354-b07bcf81f820,532184905,14667739792828925022 +0a9d102d-c049-283e-2e70-1d438c120379,2864618113,15319511259157340775 +228803ae-057b-f7b1-d52c-b1f5b6798d44,2262873521,4094681392424670075 +66b7da86-6d6e-68dc-686b-903552e27585,2570107355,9321833771339935649 +b876cb2a-b1a8-3fc8-fc39-6891372e2754,4286346106,8791721100354914557 +dd3462a7-e979-5a30-3107-156af667e559,3009266752,14675437198166744575 +1d5cacb4-b8d9-2f15-ab9d-e4a024408f0e,342677495,1734928595564663513 +55562c22-10cd-d84b-6ec8-3ca836bf2fe0,3880772524,2993093165910986902 +8a3c7b6b-aef6-e0a2-9dce-e9ac904bfb60,1048630498,4364060788831502525 +9e9d0814-861d-3ddf-8113-66628e726c5d,1211507713,12162935294198236537 +0b4c5f65-e7df-34b9-96ee-d9619098bb90,2081885286,4547500124525479762 +dcddab7e-1381-dca4-671f-1c78508bb0ee,4205345307,3965745151238998963 +ce94a42c-372b-2a48-eb7b-73c7ded87202,3984404263,10259278952699337752 +448a47df-58a0-4d58-ce7b-52576a522cf5,807519177,14941104968528581894 +f9691f94-5df8-bba7-9072-bb7f3c98a055,1457944742,16143594021932094747 +094009c1-4ddd-5cee-48d6-2c3e2d7ec3d8,728045277,2409380005181360082 +e8bc7978-8d84-1019-1394-4f3af797a34c,288575941,5049452500478778810 +d222881a-2501-bc02-78ca-bbba014953d8,3429712012,5331974907475273614 +36485aa0-5d41-ecb4-cc91-3dfbf7c629ad,2181776777,8618019329346174300 +ee6c042b-02a0-8113-1f08-2ff61edb3a51,176868940,12662799673956140042 +b7e5ffe0-3afd-acbc-41e4-32062b721f32,1792226537,14735269744922870922 +849d1b33-7002-e26b-1e12-8ef5eef32be0,4229651209,11021030440489827489 +aaa9d2b0-663f-68cb-076a-5bccdb65f083,1553348388,10789733927806709821 +f3c33e7e-723a-21ea-3873-0333016048f4,820140482,3318037629610002673 +24ba55a2-6349-c93d-5b9b-4160b6b09603,2481438219,13801009845221159521 +8668fc67-e08a-2edc-ea28-3d5f9c90070f,452513215,4282743535343137355 +99ee5599-3cda-85f0-0263-c057d5e5d240,2995555554,12368786267559934727 +f38d1721-d1ad-fe7b-7d4e-9644272da6fa,3026977471,5092140499775169760 +e76cfd33-a7f7-1b6b-cb27-c9a797a9b689,416165341,3033089453075309980 +8c30da45-5141-b140-d9f5-9e82f8e5f369,3226727714,15143563202381988546 +1dda3c6a-1694-8be1-25a1-323a3b560140,4095873471,1154323224770308499 +9a468036-ed09-d69c-a39f-39e6d6675b04,3034708846,12680235777421406047 +7805a2e4-9233-e17b-d71e-d34e6a873fdf,851585422,4261356969147596502 +de5dcf00-004e-faca-564c-3a33ea23e10b,1043441037,11757115836089987232 +c82aabfb-30d4-68d1-e99e-34c76de51bd9,1019039854,980566075527365826 +25e29b8d-78fc-f60d-9fa6-a9aaec0432fc,2111258921,9795315706144186914 +45c5d4d7-9581-85fc-3bec-ed83bc4259fb,3767171272,6749881005441319717 +70b6cf14-8e54-d7e8-2302-7f35eb087b2b,2586025908,7711090021896135329 +cdc0465a-65cd-4a65-bb00-149bc3c9a704,1402861905,8135025864685028282 +d1957e8f-4424-7dd1-39b7-2e77e58e1e9e,260108572,10557534456168936746 +63816e6f-d3cd-1b1f-f96d-00cfc65f5e20,3626065944,13837690530371626221 +03a1f43a-4ffb-4d94-6661-ab5d8bcc6852,2792056302,16276743065899357402 +773a34c6-687d-d08f-e6d5-6ce6ae9a1979,1045336908,7314310212491136751 +9885a472-f66b-16d9-2596-ae6f28584f8c,2010884444,18178202291003258083 +70b3610d-0d9f-6389-044f-3e5d494df271,3031475683,16035378778809747531 +aabfd27e-bb3c-1efa-d0e9-99ff164b0566,3714040159,9984231203495354887 +711c3fa6-27ca-b495-2c22-590bfd251a35,2412058989,4779659630619118740 +922d0112-3766-6414-202d-b6d2081968fb,2448264209,12890693625584074483 +c759ff2f-1d5c-9cb3-2015-8ef84692e7a3,661716982,9943805201422599111 +03fa7c57-9c3d-ab54-dca6-0f5d9a016e4a,4267302669,1078560440289546793 +e8503eb3-782d-e623-cd36-7a7fac808b7c,917268028,5238680438673461045 +e7e9f5ae-50d8-c748-564b-0e65c149b7dd,2628582182,15706272719787206711 +b2818889-dd79-0760-f2b2-85def3e1702b,3004533545,2367281911010400774 +983a67ce-d526-53a1-0dc4-c0dadcbb8272,1782676756,18383515091484493080 +6b2145a6-8114-e2ae-74bf-6c13f72607e2,1008856982,3329091399671583173 +90a14c87-ad72-d77b-fccd-3f897c874257,2085887299,3594476761194135063 +62fe23d7-3b17-cd3f-c762-62c4e1860b27,762999585,5768352431368583302 +1814db2d-7eea-e3f8-a971-99d954fa7541,890776099,6017211997568956091 +22c4b618-3ab5-eec1-1348-7313ce0851a2,2435731871,14674139197762786113 +042588fc-dfdd-5d43-de6b-95e09b2f0436,2714063358,16141064327985423000 +52cd23fd-b6e0-5524-93a6-3eaf9ce965df,2487060911,5305381709945790978 +0ac8b2b2-f594-6891-8595-054b219912f9,637202225,15696244242052156250 +a2d2d30f-9fbc-d089-9f3a-f2229802921f,1566364618,17287379793339928446 +9ac13dcf-f852-3b02-eb40-e1148bb4efdf,2322171194,3805623828674578672 +ef7b1b7b-c396-7bbc-0133-76a48a45e4c4,841912311,14360001796422584809 +9f18c2d2-f4cc-da51-5daf-f72e7ea5ae03,841553351,789123014046048530 +08e06676-3e67-d49c-0ac4-7dbc3936cff5,1913317762,9832215437235088865 +5dc1c74b-593e-6dfa-8fa5-a21d35154ecc,2994592196,2499909343900315188 +e3680669-c5fb-56a5-2ae3-1ebcc45cc358,3361128125,7715541641336461070 +ee4ed56d-216d-4eb0-8794-585ef9e15568,3740082738,13809264829114476605 +af8e2096-b4e9-a6cc-d471-8f0bac4812dc,384843329,14038122749893578519 +8593510c-96e8-6796-7194-4a5dbcb6b030,1218805724,7883133136995833111 +ba6e8dc0-c69d-a2e6-cfde-2e0490bc5392,1141970683,6321608356847970119 +5f2a3084-cb5d-6fea-235f-57e1e105441a,213216029,7316928160795470026 +db3e8deb-dd3b-8efb-e56b-9815739ca934,4039139495,90757144372350485 +40d812d9-6e1d-5863-7df9-a8f1067d0348,3111632144,14884062502669617045 +070d430e-d96f-dfdc-6ef9-0a8d8e4fbeb6,2157611681,8691764278755742849 +dba6f7e9-c102-d303-71db-9f9b64d89b34,416811657,14040091154559127960 +5407e699-da9d-52a1-cc8f-37275df6ffd5,4222170111,686118057164921794 +defcde1f-fee5-704d-a40d-cd9eb081a146,2984625907,7838321804833825460 +6f3c2c0c-f48f-8bc7-1437-e77b7b04dc53,23809530,17551091399266448101 +1e18d07b-dfd9-4966-aedd-cc8fc2419759,1976420149,12069329388860288423 +79407197-79f7-c5b7-4b45-fa9506f09596,3150759002,17742000901382301285 +569ca5f9-dfa3-268b-afb5-09942981160c,3908014279,3373079669788198571 +d4edcfa7-36ec-09f8-3a7c-3de050bde65f,3045491889,7611348813759364244 +a7738f22-8af5-0cdf-8725-7972c85b0238,1148120182,2336428814610249883 +b0e9cc70-4800-e928-483e-06e9b257ae7c,3089844732,17786630550839174397 +30b11894-0595-004a-1e4a-29bdfc36c9d4,343266782,8051645919000794927 +754788ad-cc20-37bb-5ce1-f65e852aa8d7,3189915970,7704122489154723454 +0450d117-678e-7e25-6de3-caec9eba3e61,3491468928,10197605431506661133 +10e3d826-17d4-4745-34e9-18edc41e8da8,315600282,10208704600211465275 +783f0548-f46f-85d4-f425-3ebe48bf5365,2132548500,7049120426092892668 +ce40fc3e-5450-cd60-a839-e333a9553dc1,3838629699,11522467431201585597 +5521234d-1911-a1ee-4498-b645e49b0799,1620920302,5505184599062392567 +c49b9b61-421a-ac46-8abf-9d71fbb089a2,45277219,17454399096648631007 +da54e822-24c1-4d89-329e-b4ef604bee78,2817878523,2437175061660427459 +14e72bba-5705-cac5-3f41-354b2a93d95f,1706620634,15572875940314285147 +4297a903-7df4-ef55-e2af-93e3c8842278,954843431,2600193723907654118 +9783dc81-47bf-018c-d37b-2855afae1e00,1244429586,5319312970865838771 +a2143bec-1856-36fd-0c0f-0015ac5daf1e,3775160829,4938657213239413271 +31e604df-018f-ad7c-b957-189db65ea1e5,2821621368,14514337959707125104 +8dbf8516-a6c5-be76-e374-07f87141afc7,227662548,13593503409339356015 +66945d71-4f75-6d14-c8ff-f2647b831dc2,1217939559,9861775926425696475 +725abc33-dec5-44eb-3dec-71fe354554e0,2650002387,14420603299584411088 +bff71092-d654-b5f9-06bb-256c3a238563,669278920,173459528424420329 +7e6937b3-055c-d712-44ea-2970ab6e9d4f,2924064935,13485005373108185378 +2fcbbc00-d9c4-c709-163b-65b7505ea10e,2753958875,11073156453178972436 +27a4d590-6000-ffcf-acdf-a9ae985b3a61,2061095690,9874957862984609071 +475afa35-871c-fc0e-f3e7-7996c362c61d,1352703454,14879734127245222409 +37365832-8486-0ff3-b4c7-a9a6745589d0,508607992,18371501460937493623 +edf29ba8-edd5-5d3c-092a-2aebdc67248a,2047365487,15737239072463380643 +b6065cf9-ed8a-32ca-df5e-33498c8768e4,3568798358,784816012098036588 +6adbeb34-31f3-2a31-b2ad-6cae221d0a5b,1952599952,10328300353979891330 +2c56404d-0357-cf6e-82c4-35488a8fefd2,370971445,337130790757487644 +3cab0788-13d5-909a-7b61-f6a86d5edce5,1912922829,10982820623229068835 +28502ee6-a15c-3f36-1078-827af25d207d,1832364037,11948530997664375528 +2488df3a-4ad2-dc38-80be-45479df8c6ba,195438167,3358913585226403208 +d64e3ed0-066f-8879-6075-9a1b10027aca,3406402445,856455943637636206 +fcb2425b-72c7-069f-a395-a997342b1d48,4194237068,12290421894110547785 +ca935074-8e44-fdc1-4cc1-8688d36031ac,914531909,5127440653348204775 +d63f5ab9-1fa6-5023-ee14-55a28ac1c4cd,1055266678,11513258472152733155 +63e268c1-3328-fef4-af79-e0f060c2c822,195699273,15079464801458723721 +b6f01af1-76e6-d641-301a-bb03f58c6a54,764760177,2277699038114705486 +231cb8d2-1c29-9e95-937a-2d192aadcb6d,821661698,43464723893545867 +92f5b5d5-5dbb-d3ad-51c8-2a8cb02cf13f,700093622,9706838906224728882 +edd7f085-1c2e-7cff-e5a6-0570d126e86c,3879203803,15046363600876662186 +474b8045-1335-a8a7-fc14-f4dc9e23d7aa,468712998,6170946745177826498 +c5137184-c04e-ef6a-34a1-b5cf5457e02f,3634806342,15854167012376569786 +01932ae3-48c8-3ba9-28b2-4c305005d1ca,2551263442,13639208471615966777 +d11332f7-f851-7557-9ad8-d37edb6742f7,4130461247,13247004547308896750 +45abc8b5-c25b-29c5-923e-f43f74e961f7,337781932,326924961933501364 +89e8fe1c-ba0b-a552-ab12-52f3c3a16ae7,3969707407,8205226541259343497 +8e8ec8d2-c46b-a0e4-bda8-9d95025e8801,561670620,11489290532045853128 +4ffd1a10-33c0-e7f2-49ce-f8a5275e0a98,3371441277,17224192110987832169 +bdbdcb1a-6fa3-638a-d29e-db9b3261ec97,1527000959,16920411262754194659 +d310aa17-6837-b208-259f-33271a2f8710,502170808,14750842353971867061 +923e7c3a-a976-9667-8ff3-154c7e0fbe16,1296740572,906684946704109938 +757a5fcf-94d5-0891-5fd6-3a6be9643738,2840270634,10653867248399340403 +e78d40ef-61e0-f71e-8d19-2d3fa571129d,852244281,791764189950590755 +e8991cca-d2cd-b454-63dc-ff648497db0a,3045985990,819648634652674135 +5a36ada9-ebde-e979-91ba-3c93e0c510b0,3002405702,399111645638398845 +2bf4e83a-3f60-cbe2-a25e-6c53cd50cf26,1822856210,943502903379081863 +4fc1de6d-1906-f1bd-74a5-9b64628a022b,1041784848,12828989952400229118 +b39e3655-9058-a0ae-333e-9291b7462ead,2325420123,2716606385905854843 +6c95c3eb-6c20-a437-14e4-6f7fdcb6689e,2508071697,11545350694682895896 +bfa3d3e0-6e8c-cec0-6967-76774b4af9d7,1622519162,15970665825418138527 +99e30bf8-f8f1-e898-3fde-bd1570419ddf,2616056669,9904639160479051132 +ebbe65ed-3f3e-0ff8-a938-ac112073c6d3,2098427835,15049525820412063107 +3e294a7d-c26f-d430-5131-f684a0786178,1071705325,12621025071139630085 +8da5e358-fa55-05dc-6c0f-d2ac5f724dd1,221398034,7330124900344784969 +95ee8818-41bf-d43f-2288-4bc22acd0ef9,2908453475,4020227126865405720 +355f6c59-9216-89a3-e530-6974e8c578fe,1600036863,12016663885168200173 +216c86ae-8779-ed06-b9ca-d1f8485b69e3,486924456,10309634595010114824 +b3a0ade8-3a87-368f-32d9-c44b401cd324,3162260795,14981933936489458367 +45574bb3-350c-3099-80c3-caf48f3fb499,4293316807,1293367749224266936 +247a0165-65cc-55d3-9dbb-269d207d5f4f,1565649939,16852981127950179261 +e021b389-21df-4519-55c0-bda9a7d24307,474819689,18131407955148896608 +a9f5fad9-ade2-e2af-5fb2-338f9a74f4e6,2320304956,14157579431048776534 +694d9184-5f81-9d30-259d-32117b2360e6,1813415509,3214880215707081913 +dba65b39-0396-464d-d64b-90de17600b62,796993521,17764723980005467963 +68664327-c8eb-cb08-fea0-8c6dc1edd464,2642212214,17522296260995309039 +5c6171df-e04a-8a3d-58a8-ce91e4f34904,2625435071,3740305809071267656 +45f01c42-fcb7-85d0-666a-678c63eabaa7,2791753447,10145077460839801241 +a2a314eb-28fa-fd79-9014-3cbc0aa7dc28,2275847310,3362483332302078970 +0bc00dbd-2b4f-e490-9557-1d5944e70a63,3342725817,7802458953259271994 +e7384733-abea-f6b0-e251-dd1e1ee75460,2358293082,11212477401957095906 +044688a3-fb18-e2c7-e4ff-91603a4bd54a,630084577,11167065905216462227 +cfa90113-7825-1ada-fe03-7e34caa9ba5a,3829661689,17254924787688109602 +3b955cd0-5167-c6cc-e813-ade32f9118cf,1880769157,14385682068817003528 +037e9e7f-84f3-51a1-86ce-76919a547501,276017197,16308863988419223553 +aafa7274-cfeb-a15a-e047-221e2b80966e,676637944,12349564895422523560 +57b7a0b9-716d-5b58-bfcf-d2d4ccc390fc,4252996604,14402944071636927833 +1099c0d9-285d-fffb-5678-6a3947dd19e4,3855441292,12288261565795243169 +cd0db79f-b129-6c43-b7e5-8c25d2d2d27e,1441172656,9108555698051986982 +dccc8906-936e-9e49-77d3-9f94e8ee6edc,2613720279,8800913220739539558 +d1d3098b-f040-8516-1383-7eecbfcb0467,2938756925,5813827631140334560 +bf6a8488-15bc-2c96-ff3d-d9b073899ee7,2331414257,496503549038977467 +c9086040-2f08-3d20-5f83-443bf08a55cf,2035685160,18382574042285519295 +bdf72320-6d89-7402-1bac-75f02782379d,2843632897,10761981210061283427 +bd19f3d0-f9ea-96d2-56a0-26216804d065,1407058059,16251625823617586357 +ae71e7f6-4a5f-d54e-19a6-19bd8772f955,40915819,451341636909178713 +54de10f5-8448-7da8-5533-3460e9f7b00b,2143710281,5702355891425914861 +0035fdbc-d3fc-5d5e-446c-e3dad4cc4ce5,1220051360,13804333695123061902 +ab4193e3-5f5b-4957-6897-d0c33e452925,3936128513,6517702191420753118 +52b414c0-fbd4-20d0-6263-ee7e7949e3cc,2809673643,14800820857775958387 +34f44b0e-5def-e9fb-2c5a-a2d4ffa393b5,1101056022,18273020515013935393 +e4c73dce-b0a1-9cb0-3d97-0873e367f390,1095847935,13002113560248953151 +f4234d85-5f6a-d328-6784-2adbdf9cb2f1,3264365421,5773961608533551735 +23f917a1-1e3a-e930-d00c-024b254406aa,1025772138,5116783962653214437 +b2034907-ef32-c689-1033-9178d6310430,83695345,11377081629099652112 +a2a902d2-c364-a653-c508-0dffebcdf46a,3519487452,14141919507118445893 +8b378c3a-e9c3-eee5-1da0-0acd8f72e8c8,3611780993,11308796609526348527 +c429109b-d6a6-b228-0046-310da3e7c50f,1585917845,7746016428111669682 +9d1facf5-bec9-cd9b-b4e2-9b7b26e80434,1704495471,3592338688739945309 +3a7d7f8c-0adf-920d-3432-f2b4c6286d94,1679391319,6326368551693626371 +cfecd2dc-596d-5292-28a9-2ec7e91a8e4d,2934827592,13467410375411080926 +6fc2b242-bc38-70d3-60bf-2b99ca88e79b,1548256453,594327928639346130 +71a23358-8585-be54-e91c-9840847eb8c6,1823659460,14252358449565958199 +d538f7bc-df16-d70d-6472-07ed42bc94c0,1545910535,12257547679556736391 +5dc8a26e-4397-e3ba-6b49-ccfbe7c9318b,3750018629,8971324210355921970 +ed648c5a-35cc-3ff0-3df7-eb5f285824fe,3349407130,6926625911671086546 +a97a1f11-6ddd-e82b-c431-d92266a7d327,4100013503,11825925003702684723 +b9e118ef-cb04-5199-8e2d-56d0acd40fbf,1342586358,7651636107771876433 +426cba2f-0fdc-77a1-fdcd-5aee33439262,2704139290,13188417851479556759 +36f246c9-7c97-146b-7e2e-870bc784c0a2,390592854,9376766600943023268 +f570bcf7-9a14-3744-9f39-ea59c7f44694,248461920,1683346409384519678 +89ffc882-e74e-21fb-44b2-76641ac1d628,3391845351,7517783214737213924 +6a7ee09c-3866-e661-b2a2-7771c1e85b45,1401451307,3964513626167640275 +0d4ef38b-0c3d-90e7-27dc-1f4f27e0b741,4148269045,598481458183195995 +79b29e62-fa54-0fb8-814d-c78786ad2a66,3806939188,561323279935067325 +1f7df6bf-755c-84c5-640f-02384ab118e6,1716185928,1264654701288452931 +53b2f73d-9e53-591d-f57c-e892ba013664,2939884173,1866578006728580473 +28aea129-7400-6126-9957-3da3ffe0738e,3562305406,15753933380451691640 +70862a61-2f24-8f91-e0fb-70f9bc34372c,803624184,11347886426516022369 +87faaf53-d52a-4639-f9fe-e48dbcaa4fda,1248067113,14872975192219562291 +cbdda8bb-07e6-c447-0d84-d3c9fb2e8607,3185417246,9502410886751841780 +8875b0af-4a3b-1e47-aef4-e1c9fe9d6fcc,1361616602,16842627238767762240 +e03dce8c-6a71-f208-5c3f-f0d95ff6d19f,2484882654,16609333021339737339 +cdf93998-5afe-df07-cef0-1be30413bd9b,1331106545,16293889202444786828 +5f375c97-5d64-f647-eb93-1d90f5f2cfca,1769025552,14707184327445549107 +563fd61f-16b6-7925-e55b-7970270c37c5,1109307850,8585884241566350813 +ca0a1183-bbe1-5058-416d-ff32cb5d52cf,2254165532,7177818244974052718 +8e02e370-ace3-f39f-b46b-5e47e4f38dd0,629414553,16408442659828209363 +2102c0bc-4d84-fa66-a71b-108d18f0706f,3305007827,17133160644978918161 +57fc68f9-5a58-87fa-f2ec-df3e0b515ee8,3615855420,5386002768128572124 +310bc72c-d116-ecac-d246-93b47b29e9d1,461157672,17367568240033667324 +94eb4140-d768-5ddc-fc40-feaa0a39bc52,870240274,14999463633949990743 +b616ccd0-3e84-f67b-1faf-74fa0e0fcd2d,1666104435,1089092096233473687 +ed202f42-0ef6-851e-a846-11044e38ccda,3067177119,16438559739696601044 +5722d82b-16f2-10ed-580e-42e69c42cb91,864068307,613677785941292586 +7611afad-8384-b26d-c70d-3a16bf381639,1581709317,864058588014691831 +cf861cd1-e772-9e86-f5ed-ba9d72c43d08,2901772702,123330897565825554 +0a3a244d-4314-9f43-486d-7563b8a38704,891958590,16157277284313403334 +d34072c2-d437-1c0b-13e3-d95f4235189e,2572156971,9566879961592993683 +6ec87dcd-fd7f-5d1a-25f1-e9e7aafb0490,604050023,9853870654331380790 +eaf9a63f-21ba-5781-77a7-b8c7a70b578e,1123262249,17671878115521221405 +573f8bec-e818-6358-3777-be9f5480dec5,2598451712,6174692210697508370 +8fe5146f-992e-551d-2528-e50f1ba51f08,14087597,3368516284542481035 +01d52280-9245-0511-4cf2-b9e32dd74025,9726157,13372498442735582538 +6f439920-caa9-b497-a636-6c06a4a8be62,325191909,12462107379417611967 +2d463267-b250-45e3-948f-6b4cfcc7774a,3437307313,18307116236535916645 +ed68c303-f3fc-cb8b-9daf-4d45efa68057,3945614823,9178966394684886840 +1ab9da0b-9a26-db1b-13f2-1a9c7201609f,1055155613,6857125535637214246 +16d87d56-f6e6-6e5c-01b4-247fecf5faf8,1792403135,17640488111120383772 +6f80c5fb-c0a7-39db-9e96-f885d2284cb9,4102380140,3377047220387582147 +020d3a1c-78d6-9c92-acd9-cf23b5da0dfd,2350963553,5819805064859905751 +cf16797d-4db9-70e9-a05f-700b85b98009,3082936179,8518788274086809937 +d6dd2898-d654-4efe-5788-e7f772d2e629,797773535,1027386444238913844 +f48e417c-6502-2630-c484-df27136231cc,3756174429,14466234854843316899 +a656dfdf-4611-9323-8ad3-926745e82c66,3169459183,16834658754041252547 +0b809d8e-9427-e286-f4e0-4451c961eb45,3394936043,4712608164475321308 +d7c29916-2dbc-1a30-ca77-90a77d73cacd,3680168601,9814545783867813922 +8646271e-32f6-f909-b8bb-8984512b1a27,653032360,12931410289279273052 +23d3edd6-caee-26d1-8db6-0b87358348a0,563106469,9218257725176487473 +aa8e4686-03dc-7f4c-934a-b1a704b1a1e9,3836749868,3536075258048401516 +6bd3763e-f2e3-b4b8-af5d-00680de7e7ba,3481323546,9991015740533001385 +29a81c43-4c9c-df09-2422-8ced0edba902,3988180706,12782696349926427167 +a1b95373-ebbd-ab7d-5427-1d0722507843,3645418482,10170981467795299040 +68d7d9e9-8de6-2033-428c-f8afa1b32e44,3618213983,8168253040883481723 +2c04820d-8156-de24-4d3d-7881f7756f83,3633895708,5439200362639061194 +e0586b02-082e-6e10-24e0-3a15ba872775,3092411365,13360939534326697308 +2201b217-342e-b6f7-ff26-b34459c365d9,3765412774,1454932167329246297 +e7f49841-df5e-9d84-282d-fd1e0e3999a9,686199518,14252147631846938751 +0d231b73-a56c-940f-526d-e2aaaca4a998,2665980255,1171612999721891992 +1c458aba-0687-bcc5-8fdf-69804fff85a3,1272928595,11490989824527209411 +9c5cbec5-93e3-48b3-673c-3b81c350eeb8,2117448856,18238900298206545950 +209d7e93-07c8-04c2-a218-5be7ca7f2c92,1013179115,4938021781979063615 +9f9fa633-879b-95eb-2756-2808ca439010,3232235587,18222122797736835986 +fee457e3-c3b0-9e96-0526-993bf7bc6cf5,701715472,1060720900334940284 +dd93fa6d-a6a5-54bc-35b6-8821f1d7a803,4263518777,17825557455655465023 +beb04b3c-de40-2086-197b-4256fbe353b8,707554886,198555019440227527 +858cd4b7-7b26-dd1f-8f8c-c0a193416e98,2758535129,1247096307193065320 +f7ad56c2-2877-60d0-d4a7-5fd555b68086,624232462,9583157847003765727 +a0053a0e-f117-b659-66a0-26812a99d46c,2374069271,4954058012138703329 +cfcc1da5-116a-ceef-7a49-d0f27e0ffea6,3747809381,8521890634641934508 +a5d5fd3c-b1c2-8371-9dc2-9bcfc38377af,17125012,14233821284939727252 +3d1158f1-bcc0-5f96-4c37-b3c8b8f1a088,4149774068,6003694229337107040 +39f8bbb4-347e-b575-a2f7-f86e9b9e8b90,630122351,17579686243098424176 +91a02123-2865-abf4-bf4b-26ac08044643,3113299600,1767342297587013998 +277f424b-83e0-b0d9-6a71-d4eace0f3631,1263862987,15890356283169733507 +4832d9c5-cb56-4177-2d25-cfc9dc417d95,1000844874,12189879811138830137 +d5130acc-56c2-bb12-291c-aa578af1abb9,2832438748,5573986065576169027 +3fd00fa0-0562-8ac2-2b35-f1678ff0d1e9,1476145546,8684770218678014199 +9cfcb48a-ec74-1824-643e-f8ff31fe99b7,1608257058,5754882453387438169 +f1395dfb-a6de-59d0-5737-1fc9a54fcf74,1374103382,10910127711369504580 +6ddd61d9-1a79-2c8b-ab90-104f351e05f4,3808050733,16622353592199268116 +c05077fb-d596-9da7-3353-238f5430095e,397314723,10465713743122207916 +a2edc92a-1f89-7e5f-72b4-ea39966143f9,3523007300,15143226963864327950 +95fcff93-4a30-f29d-3972-89240fce575c,109820837,11562079764909819655 +4e4a7672-6f66-004e-fc61-040f375f5493,3409067061,14638058431157366057 +eabcd7e5-90e1-f89f-a29d-0baf074cad3a,1153780846,17138829911121777435 +c02ed5d5-21e5-5554-3336-83f335309e29,4049413243,8082638475869104257 +ccc1de15-5212-111a-c31a-52ebd62251a9,1543909833,8359778692392138243 +a46eca7a-17bf-bc33-044a-f306cc4ea318,3740233204,10828332100578732847 +7811dde0-2e82-61f3-07df-a72edfe4f158,2344604217,12308257302548756038 +87b01089-790e-bcb8-e4a1-8a9e29267814,295243821,16362310941427377212 +a932fe92-e645-7451-c65c-18944d542457,2832653201,4351512897717818367 +14780895-e722-0b4f-0d4e-80bed75051f2,2897653161,3753598121468468120 +18e868a1-3b7c-470b-8d8b-ea9dd6e23d8e,4093657445,351232862172522441 +ba34b0b1-03a5-eb14-5bf1-49a2c3e4e38a,3453203600,12203575999969009507 +0f660b75-f052-0530-6b58-c0201e9d0e02,2712736061,7659359272820489211 +7a07f6b3-db43-80bb-98f4-4a0b11adbd47,1739249312,9950090211789639811 +d675c517-9017-1b0e-dc22-b02ba8c051b4,186733492,12576859861004506431 +186a2fe2-71fc-669c-cd3b-72ffee9dcfeb,3641618842,798075123699467696 +9e38225e-549e-4eaa-bd3e-66bfdac4a9f6,4288172529,17012707348061797455 +0e6628a7-1e94-4c87-7c38-b217547828c7,3424815663,8154717034083722825 +aa23a159-d574-7775-8af6-c41b9427beed,3888101094,17774180385151980209 +d2d8dbdf-441f-2d14-2602-58acbf683546,380689290,7453840831175116086 +4786c752-7784-dbbe-0ad8-c61ce385dedb,2053184810,15655476117094053770 +379cbf57-60d7-b48a-b91c-6a4abc11eec9,314024227,5554889977472844835 +abdfebea-1e7d-826b-3a53-2a5505807871,1694841605,1155918843361607974 +26f944d2-3d1b-b114-fa37-4ae4cb655dab,2336522820,5948564595848025179 +e14d18d1-e22b-89e2-bb86-db6e4055b1ff,2939555482,14117200290002091906 +b9a9a99d-e59b-e010-fcfb-b7b8b7eb7c10,1630331004,10569406327290565307 +5d75d76d-317b-b888-bedb-c924935045e4,1091311608,10558693941485453401 +3bdc9747-03b0-671c-dc68-35cc5d82001f,4235597030,17379835432380765212 +60fc2791-4ace-24bf-033d-8a4ccaf6fa46,2409374316,12669610668173404213 +00a8a770-a69e-a52a-6971-b7b20b575313,3548990257,11805948237611447488 +d6d8d59a-c9c4-6362-64a5-5d193788aabf,40432344,16927265615571027928 +5033ad12-794d-7f13-487f-776ee08b17a6,3522379663,14550781800826858256 +56dcf2e5-2c3b-1869-eb94-1f124648c227,1594259938,1121029841563018795 +e39122e3-e4c7-5af8-56d6-820e23be7c83,3670939886,8668706983447016121 +15ee311a-ebb6-bc59-6ec1-70191b3baf48,1226028067,7446153898364923438 +419dab1c-6935-6bd8-4078-cb49e70755bb,1726354107,15541913319689061233 +502c8e61-e434-a4f0-fd22-ddca4e9f82e9,2002797941,15472006221601434729 +11726c4c-ec85-7107-8e23-260eccfe7577,21261040,7943274320602474183 +fe03c0c3-e3af-9460-93f4-dbd35ae682fb,3239833533,4290448515264378887 +061a471e-a59d-c541-509a-19de995b8abc,2573736747,3301426548517563251 +b981cf8b-9c64-4ff2-b15c-ccca168559d3,2063169925,2159057318972886279 +4dea43e6-2280-f34b-2b6b-4da938ff3e2f,3534186121,18301222661491960701 +c3a3fd54-a654-19aa-1fb0-fd3784ac425d,262525405,2008725642500492801 +d6bc7d57-60db-d01a-b3b7-4aceb682392f,2012017125,10722020641752707101 +54df6204-ba50-cf5d-1aec-c0e640485753,634291445,10382521844854772667 +62b607b1-efb3-6ca2-44c3-2961000dacd5,2937421275,1148607792855134785 +8feaa0c9-b4d7-f4b9-1f49-958d8f521bac,3208677672,14320682459364477458 +cf969be1-05d9-de19-869c-792fe2b0bd5a,665299984,3086694623466527096 +aa952a6f-74c6-c54c-d396-aba086ac2b22,1164557180,9960557724015035133 +7f831a80-47c0-12c3-4baa-60b2745538b0,3095164773,9363732045929728242 +a32b4ead-8d27-694d-1cba-f9b46cb5b2c2,161521995,2489625591590431024 +06a25329-d5ba-b8cb-db1c-9da2c22740b2,1700557364,11337394957944718884 +c635c8f8-2483-e1ad-3117-aa6cd46277b6,2838273731,14751988848697183115 +ab5768a1-dcc8-49a2-8efa-52e5f1d8923f,3356543192,16473851939849847907 +6bde48ec-3506-0bbe-f8ab-d3379c56d311,1600719140,12400277439887592723 +8a77da2d-eca4-12d4-4169-9a798ac3888f,3190749624,8714120852658543303 +15d09b5d-da27-6b95-c31b-017043ab19d7,3905235835,5809832847318355284 +2c35570a-eb4e-6116-f510-17167259e24c,2461075488,12768019314553884773 +a160140e-b852-d3f5-a48d-c65b7eb8810b,3451434929,17761052152763764757 +4ab7faaa-82b8-28a2-fe91-51e3852d0fa3,2055317788,833384006111537848 +20c5e946-5ad4-3922-ddac-741d0183ace1,730107015,4321321086189331064 +903031ef-0f61-0c76-9be6-c0775e3d7613,458283120,8975924781448826147 +a3afefaf-79d1-6cad-99c4-337812b57b19,4179824727,2255559361551277955 +0cdd46e3-0406-a90a-1cdd-771c67e59cfc,2961996713,3466327234234407503 +d6cd1e72-735d-df0f-922b-5dec5127a807,1036532579,7174894445249157586 +8445553f-e207-891f-b19c-19e4c14702eb,4113109298,6595899421473519526 +f7c31216-c07a-051e-d4a8-ee49ae0e7242,2966539413,371090941194221892 +d8303f98-5099-6843-0b49-3f153fed3f56,1544907652,1795063565355168095 +3acaaf0f-159f-3f56-cd2f-b44033957a54,2244121509,4035398851213591890 +e082270f-a977-70ff-3d90-7565c0d40b3c,666200909,5088809693056746958 +c0afbebc-95e3-f1b5-7273-10b8041fdf8a,1896809856,14834596597695085118 +ecf3b8e4-f687-5af1-3163-db66694785a2,3635440687,1400529200328971214 +a95c1d1c-0f13-4f54-9626-10792b99f0d9,916304406,1361023166415140280 +f8bf8cf6-be75-9337-a3f0-37c862826c6d,863284459,10977178643263811665 +349b475a-1eac-4d0a-d580-167fccc4df4d,1623251692,5866113429045879752 +f2bffc84-d9fb-5512-34c2-c02d79364235,2584372910,5746752605331815766 +4cfd334a-6ed9-d39b-7330-2554e7d536a0,3341009713,13680689713706472415 +10b51f8b-fe85-262d-cdbc-79f469e3b0da,1077311185,9323248747048372167 +22adb79f-cd81-8d00-0c8d-b9c214d6a176,1311920043,13797532336434358688 +3f8b2769-772e-6518-3997-6fe76db7ddff,2730946017,10426987209261876751 +7a80c320-120f-cdbc-88e0-158f7b09fab0,394114972,4689400081027701477 +054fa2b0-f770-9597-4aa7-56d3f3292910,1108227236,7236382167774631761 +36e2bd38-5273-3e97-687c-dc1ea047c7ee,3342525584,5164600158174196315 +b5800a43-cfb9-aadd-8c24-a84403245225,830409715,10164138226418953156 +f11fd788-d733-c6b1-9616-d43a155079e6,371961314,11504432632631008819 +223742bf-6716-7bf7-b031-c53e18c89b0a,2709057021,5072091380248116203 +dbee9194-225c-c4ef-52db-b4251bae3727,1481662001,9715911446942000423 +008d33ad-7d12-a804-c356-2906b46c3dc2,429275227,11077965686771427563 +b2c88522-6257-2804-f59e-52e769654bb2,2147515094,6353627817433512695 +36868c1e-e479-8f93-60bb-e5ba553e4620,1875995175,7919428340158379837 +563758ff-a403-20c6-9c99-0e40806b6b10,1455521030,16955743178020547778 +19291523-ca0a-7376-7ead-2fa2fa824d19,1651205336,12265666119589862465 +71e9377e-11bd-3517-741c-f7873a85df30,1096641499,14006680591240016649 +f49f4dd7-963e-90e3-d71f-b6c804b4618e,1615805140,12512606476873475791 +5d5047b3-12a8-9910-2cae-6ed12670ae55,4030777832,5626463051578120295 +cd207c51-b6d7-18f4-194b-9812fcf1b94d,2175717864,10929757941580196198 +c174219d-0d41-2bdb-44ba-18a2bae7ae89,2918732924,15181244008038141786 +a5a5dae9-fa27-6c97-09c1-17af05891dc6,3634650469,12473412182931591726 +de29d963-a042-e4b1-8e45-3d41e8d89b47,3493565901,17984477817741878165 +946414b0-6220-f001-0e5c-2af3410eb01c,3351971436,17256573115025035972 +4b9eb431-6746-376b-a075-d3112c58c497,345962011,9057636870904001515 +fe0b6cba-24bb-5502-4675-2530c61af63c,3455538967,15072519823660873712 +5eafa20d-4f16-d3ec-35fe-d0a0c19bd407,3706587808,17412483279465163986 +5e31237a-7fb8-74a6-9642-e841fc64b505,2904836390,1090910248572042385 +a82a9e9c-75cb-623b-8075-d2e5e9e8154a,2089786601,15093551167145111305 +5c5f2eb1-709c-7d04-0647-174bbd2fbb4f,783424519,3578841751306193166 +722a6508-049a-f221-31bb-d207678fe566,2597893961,6981217792590753897 +d6e5ac43-5e63-b6ff-84cc-ad4a9c6d9075,2717334675,4714526559146123674 +1dd0ffcc-969d-d178-119b-ffd6203d5e0a,3762049652,2860090360373591014 +bf19304a-ed99-8860-3a7f-d828ead16050,1673065419,10733782988389049399 +09c5b740-9667-e100-64e5-0bebe32ce77a,2529026314,15847039323996832638 +250cb746-35c7-cbb0-20f7-01d4cfd10547,4290604299,14596356213843522833 +e9d74ebd-31d9-4209-4886-0fade749b43d,233516342,10418993460076328074 +fe379c76-bffc-b927-7031-80b1bcbdebcd,99127590,9089623643021911858 +b56252f9-df69-2edb-465a-a5548e341178,586809139,14729741310371523586 +8f846066-bde7-2f3f-40c6-d1f45345e7f3,1985121312,15049984159943653807 +0da63bb6-692f-3b7f-d8e6-032b453a3183,4194354197,2521716492847683830 +efced049-6d65-2f09-2b70-0b9d64a4e9cf,337931557,1705832158542891783 +b30f6374-a100-0aa7-7b93-aa93595a26d5,3278713151,1063350213738123094 +38325a06-70ad-388f-12df-b2e8c51c6671,1942982306,18431311567001550776 +1ac679aa-3ea2-9f5e-a217-8ed68614780c,4167157595,10383332985107680152 +4a3be992-4bc0-076c-1ed9-7d5a8b5ca551,4045088297,7130157703036524425 +f0a24fe7-106d-834e-b6a7-42c7898df0ba,1821301478,15533571899151069640 +22f25efe-8608-26d4-61a4-845a4416b0fd,3470338782,9675752657459323592 +e5b6a153-9776-8140-0953-55c985a6e767,3888603559,13484777773596567403 +6162c83a-78f6-8bfd-9808-55a1daaf4313,2190491106,12535691388752788539 +93acbcd5-755f-9f06-8e4f-a649521c5a22,577662347,14046354717652905192 +751460d9-833f-2378-71d6-d7979d3d2c13,1345513610,16952213559649137585 +158ec213-fda5-d1ea-79e6-91d53a1942a0,1694880854,4150788549447913260 +5f4514b5-d6e0-ddf8-3912-b10dc58553df,3600829120,4890231476497155329 +187af573-0dab-fb08-c8a4-4b1a57eaffc7,2253585345,4225889593944036666 +4d85761a-edb6-65d5-11fc-69853100c23d,2037657191,9017940963000510773 +bc4d5ad2-66e5-3529-3193-d8f575626a74,1028519569,3876915054712703171 +1fa615ec-5363-d058-f02e-b9525ac38846,3222725319,8092629336544883510 +3f3d8744-10d4-834a-dae5-032acbb7f70c,2678454185,3853286212227022333 +8ddfa2e5-d121-515a-2756-03379659593c,1030369410,16633979696154523036 +a1a2f7aa-ad08-480d-ab8c-0c350c37a4f7,2092390723,613467872252864032 +1c820a8d-ccbf-9e7d-e27a-eac32f5c2722,650227872,671811741348539481 +75058359-8cbf-5146-26b9-9b93a8d99d35,1935262649,13233506953170830124 +e0720dac-07e3-2ac0-de4d-b91316f58c27,428191556,565687415831157497 +48579f00-31ed-5f8d-3738-de13f7127f35,4167150366,12372562181102086993 +67d8a820-2b09-0c2e-83ac-ecf6011dedab,3507642120,18282184758008120447 +bc97063c-a459-724e-d970-79517391dd63,3617625084,2599953992828706027 +591a2bbe-8064-8993-ee33-255f018c77c1,2304021850,15863066019238147434 +29eacd4e-9315-b282-21ac-69051100d9c4,1261845936,16535747695039622136 +79d6333f-318a-dc5a-26ae-f764fade53a8,2856758891,5963024195775970317 +596461b2-2794-f308-fb7e-3992cb9a117b,4064006390,39194609520456286 +13591cf7-d7ac-ec7c-21cd-641227e4c6e3,591852671,12071198560654732087 +e5e79b18-429c-6d15-eab6-e5215d9b0cf2,1467928809,15110331886258623495 +ad175f57-25f4-117a-4bf0-ad651b7d9474,366041593,4564791929298039099 +ce6d54ec-890c-f9f2-8d6b-28c3aa6948b0,188101094,17339461901654988308 +c49fa032-8f79-865c-6445-55ea83bc4965,1382889821,7534177490721177023 +1f33ce5c-5b56-c78e-8bd1-4119e3fa60b3,492061952,9936843666445082058 +b56e163e-7f4a-c381-26bf-a814d5e8c321,930765025,1365725238176228030 +7ceec985-9962-8b6e-fbbe-792b1689f6c9,2544182331,16056103710726486635 +bfc9ca49-0b34-763e-e1d2-cf9bea0eec58,2414651110,944464975296312967 +12dbe397-a21d-5863-90d5-ee4b40c826c5,3725312189,2024225058124800803 +8535d1b1-7c2e-2a5c-c11b-c258b358c020,719680660,7640899612469597515 +fa089e50-7ec9-9701-c876-d87f8c5311d9,443981056,17611137152184742574 +e35dc296-d13f-99e8-b625-0c354e5c98e3,3322639453,7863514129683090295 +a4367729-ea1f-cfb6-ff95-e373352ad498,1066516523,571176994116042607 +5d466431-777e-9061-de98-68fe9943ef11,4153000209,9965403610154323557 +76307992-aa7b-76ba-b6f7-a17d72f45e93,2873607212,13589475465145842210 +6c371426-2d84-32c0-121b-a9099d780898,1019617893,8994546444070345983 +b32a2f89-55a9-b12e-70e4-6f3f2b414dbd,2139247823,1693116066589101355 +e46f570b-91a7-3bdf-8fa1-9d89b50a81f7,4252532186,16414243102804913232 +4717d86b-fdd4-c525-ee32-16255f6fc8f2,2838720602,3466803248177244582 +113fc77d-24cc-1f47-305f-b63088f4cbc4,3324382516,4531272233999546788 +362dab07-3553-7e59-5b0d-547a541337b7,1089094424,11117902927623788269 +0ef81c13-c76c-ce10-5588-fe5f01c17273,159410593,12066192624013959639 +866bdee7-cecd-faca-49ec-dde53fec9fe7,1974814154,3376804740548890207 +4a59a001-0f94-0d09-cef4-55c30154ce60,965294058,2510981621563801535 +f1d8d0ef-69f7-d43a-3292-ba0f1d459286,2502786662,8645712205697527485 +fb2433c4-9e95-15ff-4e8b-3238364d6070,3466424031,17177159953915608445 +d56d75ac-c8c8-9e24-5234-9a1bfceea834,285721847,2243154023196256602 +dd4a8892-2e44-a026-cf73-d8386e283801,3382497179,4207473876837961486 +826aea0b-750f-b0c2-e3e8-06682e485885,35349074,7028415244382842748 +d01b851f-d652-dfda-e2f3-959d8382bcd9,1236688578,3289756284199834182 +6c607fca-3092-df86-35a5-27335df2bae6,823656955,11938207692918659349 +79fae4eb-da16-da16-8322-ef3ae5c9b7f4,510259776,4937984776872426201 +25dd1ded-09eb-ed6c-a5d8-ecf58839e2e9,1340349695,14009600786432039358 +57aba3cb-b84e-369b-30d4-e42b7bed6207,56088314,9851202082986427644 +ca07fea1-8d3a-3234-f541-9e8ad5a3acda,328694133,11351261037136643753 +51809fe7-dce4-fd01-81c5-bd52e58173ec,2925902786,16146079593472441856 +4a4ef45f-a925-ea55-2347-56e63b877972,600102789,10543796526539242197 +2ecf9926-32c2-dffb-12d4-6002de11f90f,3244129376,6725311458271792370 +26eb116a-fcb4-1c6e-3e03-c444aab1f2b4,354688241,2271831174002115081 +345d216a-5dcd-d68c-d083-0cb9c374b5b9,1934640664,457354023910304247 +4160f72d-52ea-4ae9-015b-2e5e74838fdb,3883022451,7637687543046633743 +1535528a-646c-4b35-30b5-426ab2440a67,1859918921,9653734449130146576 +a22e7977-65d1-9d3e-3b0c-fae13b2bb9af,1527505915,16792141549285571915 +e2d398f7-5779-7369-0700-bf120f0067cf,183154043,10168866089555017264 +b9cd3ca3-4c24-d5bc-bcbc-43c0f6906c20,1070829020,8470117031320277746 +5eda46ac-0410-312f-3079-6daa121a7550,2041669502,1000258147585774828 +ca0e68c7-59e0-a7a1-568d-047e153647bd,2293517107,802003609688233096 +ec4c66a8-45cc-127e-e091-af2eb80ddfa4,775121666,3554609993723862040 +e7387e7e-8feb-9c64-9eaf-457d96698980,3300171374,13777882581471116739 +d0c21c28-0ca0-93a0-b30a-5c8d2bd13290,2862120279,12992629274660224830 +178a3dfc-3c67-4b54-9acb-c95575b98e5b,3792500296,4900626136441218905 +027ffec6-5d57-3b32-637e-06b0b1d333ed,1402861436,12677926296668156866 +51b87bd3-969a-fe1d-bad1-7ba88bf0918d,3548316005,2643806475567805930 +436718e8-abb9-b438-45f0-c16b866d2781,3228486663,4786884850124826862 +3f29f0e4-2bed-3d06-3bde-b2f38384e457,352849822,3918274597720301209 +fe148707-5571-f325-c1d2-76f79f2d1adb,2225232319,5296832229332217955 +aa6a7799-3864-9944-f369-ce55752ba4b6,2805918694,16701679237066489150 +759d1381-d26f-1967-192e-860e14f4feef,2927384441,183000941703607471 +db8a62d0-59c4-c9f3-b764-ee36dfde6a2d,2907933596,11256504532884602238 +6b498edb-10d5-c99f-c85b-a342bc538799,246262273,16344593691565644358 +a2e6dabe-b5a6-6911-0373-3ea3e501e97f,595249649,10221451693898073831 +003104ac-92d8-706e-ca9f-d8230d8f4215,2941689476,15611947835098123315 +d0dfc9d4-62e2-558d-5e0c-30458288ca0d,101481657,12490115048588549182 +f71b93f4-cf2f-533f-eacf-6d333c38e91a,1714159960,12793247624198357284 +cb308d50-296d-fc16-76e9-4ea1a825d557,3518595641,3199977881480499609 +f5cfaa70-ae22-382e-ac36-31ed7f26c16f,1324907015,14332732126183253594 +3cb82be0-d909-6963-71be-2cf8c5e5493d,3834518174,4303138041370944375 +88e414b2-4be7-8601-8c19-1bbbc815a381,2303712155,5710427617991528924 +f6dd552a-f211-4bba-7fce-f62cf08008d1,1573058207,12005658638806883539 +e659de70-7197-82ed-ad0e-b2264aca771e,2249372371,8222077397486285088 +091cbdd4-e84a-44e4-80a8-adbad72339d8,1897889398,7036013505168007549 +9eefdc2e-ddfe-1224-6088-264d3f4e42d1,2009055819,9835270854546018047 +d45ef96a-1aac-e3f3-9ccb-49ec8ad29b93,1023001178,3299746990097143204 +adeb26c5-12c8-b178-6164-844d92dbe72e,2009257795,1520220140763502996 +8976490c-7bcd-341d-5638-5443bc82540f,3100597533,7707943049049133133 +cf6100bf-1684-475e-db2a-d00656c9811a,53336076,8851274906742924426 +2945026a-4e68-16a4-9a14-6c8e563b982e,574340249,16356241213993036132 +c2558127-bc1a-fa00-28c5-fdec5a88c3ac,1710597616,10838727631084191064 +e9ae0343-2296-8935-232a-698c419fd138,868101478,13735012742479466263 +d9d78035-aea8-79fe-b0f7-a06784eaa455,1114204971,10312303878703810629 +7310fa5a-2cd7-4ea4-749d-5163e98ee869,1067892885,6713760222717272700 +796acc5b-4694-0b53-fc19-1da842458032,1994705785,13153676040968765359 +81b33600-9961-4ce1-2a60-8bab0db4784e,3155257722,2099892819359953548 +507dfcc6-d2ee-a136-5926-286fd8ae492b,260541677,14351192028352481232 +74e072ae-8349-abe9-c0ab-8334e80ecc82,310033699,8274812413845068475 +1b820547-47b5-de42-27bd-0c2fb1752f90,2787246736,16679983939237563289 +f505ef66-56ea-9c11-92b6-910d75dfa580,3927841441,14822879667310497860 +d46b8f7a-9bba-6645-e716-ea958c5c0eb8,701913410,18098434657243385681 +395666c3-6e3e-90ad-6b31-aaf64313360e,1755766348,13114248603907535987 +03947ad4-24b4-a2eb-31ad-4cc69e05e870,2416807817,9745732061236408136 +8f0654b2-0462-a724-075e-e0d9691aa1ee,230427668,720597571671511456 +c07edae4-ef64-fefb-ac36-2215fb822953,1199583258,878166315864538281 +14245c1b-38f7-8b85-8cc6-62196b366dad,1424421366,5704587271461541473 +271d029d-cc9d-d212-8f1b-9edae32d7179,1043599542,2637845064792666474 +6ace4e3e-8181-362f-b8a6-361138fbe883,2193188187,12676804323153240890 +2faf541c-6890-0e5b-c06d-52c6d0951b8b,3021786484,3716031894445840709 +cf25cb70-69ba-9d6a-56a0-db3b11ae389d,327158637,11230723223499097884 +ade625e7-eaa7-4ab9-0bd2-5047b577dc90,2705400406,10555563700535950681 +f8616cf3-bad2-3efb-85ef-b3c3a46d21f9,2363367614,7681773705863561576 +0c968067-9528-a031-2274-2ea28444fe5a,3773538874,10436439425318196631 +e827118f-ab9f-de38-53b1-55a849398af2,1636062697,9931141189880989373 +ee947fae-b17f-fd96-cb26-d504178f36d8,1278072961,1755812388822394620 +1d3334f1-a5fe-23fb-bfa3-afd2653e69aa,3773350894,16142896797508317116 +ef61a0fc-d802-030a-21af-f9d0a8a0fa9d,712368374,17955960341051926459 +caf1a7b0-27c1-8ae1-7bbc-aae2327c34d3,2438029646,18225684449405969981 +db8c3d3a-a122-7373-c368-8a9e89acec73,2268715148,5028273045986551723 +d32c2b13-0336-e56c-d9e4-4e8dd76e8878,3837441199,7627690489346291105 +1e708f3c-c32a-04f9-464b-9b2e540ab4d0,3949450633,6362996050197072050 +0944a899-fde3-e51a-49aa-175a0fe33ab3,282430450,15138280439278535702 +f4e38b54-84a9-5be2-8418-e8300ed91f5e,2547389289,18035380325060719252 +b8d16942-14f5-9bb7-62c6-1510659fa0b3,3084777773,11682387184039828665 +decdbd6a-2f58-9853-5d11-1489c51efaf4,1083271020,7944745183038324376 +4cad7b31-4de0-fc6c-cf3f-2f9d6d9c21f9,2774893743,18093950776522762042 +7bf6a002-cd4d-988c-d27b-b8e66c63ddf0,2057542707,9303927425681775321 +0c0a882c-350d-8b3f-265b-eed7562c6d7d,3908394377,13575425780104434116 +48143fa2-0045-6a17-5d1a-6c2123792baa,3939567024,16410095220012065789 +0c315c8f-e6ab-8054-e018-b1bd857b0603,1208674655,17552866057611006967 +d23fa70d-c69a-59b5-6609-c8f771f74e1c,3705859527,10828719965736840308 +ad92061d-de9c-82fd-cc10-2ba0f39890dc,1480033877,933997836719415589 +f8738342-7d86-c052-a3f1-c92157e53a65,2434815674,4254558342317159663 +6b68152e-ceb2-1b80-2411-a691a41a11bf,527894703,4591510583374954457 +dc4ee56a-9fc2-df50-706c-11092b64366c,1496112743,16819890346258327164 +2f1a23b1-491b-b1a3-1371-9bba8bdbfe59,4224994697,14833156595515404892 +a5913c8b-12bd-4af6-b945-436a9e481487,3740584683,15626015589622519606 +ecf87aa9-7295-367b-9724-5f6e632c15ee,757832756,4029961164447207395 +50ddc6e1-afe4-74d8-b0db-2df7a8a7ca5f,3566374057,4572429063316855169 +7a91315a-93d4-f3b2-2abd-b0aff1f0152c,2559307257,4996025529202402056 +3212f2f6-67f0-3eaf-a95b-9e9a6fb94369,1253770007,6551028238528245041 +0ae75e6e-09eb-64f8-2cc7-7bb97253c2e2,484422482,13999554099631044471 +485d6bed-bcba-78ac-92dc-6651bf26e135,1450415724,14026979253437003711 +41a304cb-4660-3480-6ff8-f8bf7a4ebf1f,4238818636,10499103186815533916 +f73a15ef-c0c3-5189-42e2-97981f8eaabe,1156577122,4098256755728168912 +0176a931-03e2-205d-d713-65b09f111395,2056351254,15979640900588607460 +ef522937-b896-5354-228a-5c324a456af4,177669533,1673877157405623975 +93ca410a-36e2-0980-bab5-bf249cb0dc92,2042111806,12080707883884570601 +8c0153e9-1d00-70a9-ca30-8438547d6c88,1952441205,17637306619318147617 +284bd817-121e-b0a1-94ff-c705b470ac23,2362373181,5121238231232282917 +06d2da34-8664-de3b-1bf0-cc59d0f4d757,1565604906,14211424518201898326 +573392d2-06d4-a9e9-72fb-e2dd0b25a3c1,1067902547,12901673392320741144 +49cbbdc0-2e7a-a7a1-c55a-bb46eeb902a8,699808680,15494127518868781001 +18690629-905e-1c5f-a744-4e3322bfe3a2,2730338544,7554645075039401535 +a660c510-2625-e5c5-14e6-191918253152,172775399,14113495119665976575 +ce529b21-0b4f-716c-4b85-86551581d829,2480445819,16542350762339786625 +6dc5d20d-e117-d96b-9c26-b8583d5bcea5,3930392117,6496401041030816099 +b65512b7-70b6-79a7-4397-6e058cda033f,3393114097,12851164390438498567 +59c336c4-eaab-d93e-1180-d546d0c966f6,2145688538,14105228100530059086 +36dc00e3-cad4-fae5-5692-a0003405880c,2257352410,13411738600457515264 +656b5d97-f214-cd35-058a-3ac82e3174a5,2105472698,2237311162365976054 +3b602304-c0e9-09ed-a842-9c407796488d,2954981913,13305566361321239972 +deeac54a-c904-a43b-64b5-e2c4337958d2,2843982225,16078967943089791680 +b3ebb363-e767-64ca-b5e0-22a0f67ff866,2875640626,6071738893125488780 +1f472d57-b767-6d1b-65a0-48b6acbdf8f8,4220999016,3926780384877629990 +506b9f1e-a88b-9978-1fed-3f52b8c37a61,2939218985,10232536975065990734 +8458e2c5-6ece-61af-afcd-0af1bdd88322,2222814787,6859421070713214464 +2c2bc890-8c26-8805-1221-01e8c0afc59c,1809163963,2505544207994461533 +9f909151-383e-6012-74cd-543513387668,6287418,4323128188800414768 +a0355980-1174-cc10-9208-646890465b8b,461134231,4230868344843890066 +6545d23f-319a-02fb-d4ab-a7a92cc5a24d,4019961529,12425558947904808842 +831b8354-9e5a-c471-715b-163b7b1965ae,1022484229,9540280126756362570 +8b0fe794-9d94-8836-6409-afdbcda80ecf,3673435455,12713336498383471425 +6699c06f-eee3-7238-94f9-9da93638b85a,3496641366,3152234823759092831 +906e5feb-135f-8610-3135-c303853e4d9d,3462220697,14251165878481243028 +2e599ffd-5da4-edf9-1e40-0cc24da00fde,2172695050,5924917924961540603 +ce9fec08-1b2b-53d1-31d7-d0b68ca5eb6a,1600198478,3900934388237998379 +60d30ea2-4a4b-a77c-eaea-45654209a980,3325936590,14349779265769144774 +9b38d067-7be2-d8ac-fe95-4acfb8fc77de,3690252707,7863234621849534574 +55a4176e-dd3c-4e45-352d-6cdebcb84368,3708098690,5045397172991552292 +ce3de73e-9aa1-f609-fb0b-875df6e1b8eb,2900082487,16834997174820855320 +48037c35-6e21-de8a-02c0-c93614552802,3205622719,5345219316307419139 +e6e46d92-a0e8-d84a-16ac-c8667303b254,357786535,13817860732088760095 +d2f7dc93-a9b5-3b38-199c-287ddfa58584,1765018776,15861423395888118469 +d549a042-11ca-961d-279b-29ff063ce0ec,1484741192,1829682330195559050 +3857a879-bc1f-08fd-8ca7-c5dcc12fb459,96560634,17743619444536168824 +f4468aba-f26b-3d5e-2931-94e17fe45aab,2233212625,3576971693623466764 +a75c7982-2fdb-7f52-6c36-76053a2f0154,36348288,11953369458704328874 +fa10e196-1c7d-41e5-0478-8492ebcb2a47,1527434043,10780180774807667276 +43f2df66-73ea-45b9-6876-96651433aea7,1440819381,15413417236816038956 +9b35b8c7-08fa-8f8c-af8a-03927a3c1dd4,3104459470,2750739450699841490 +eedf027b-cc02-901d-2310-49b7849b726a,2023469719,3446275737470214462 +e8c174ed-a6f0-122d-33b1-bfe3c1b67341,2542932654,9924636090569562793 +cbed6da9-31b3-863f-1639-8525d01a9bb0,198765850,13126132270174868018 +7a786036-2bfc-3a74-5a0d-997d51bff257,209306032,9319678662885936443 +2801e408-4015-1f16-1f1d-15b28410389d,2000021174,2929265369626222079 +f91c5201-fa9d-f76f-0178-42c0dc186757,2959436582,5813217913243571580 +1ad2c362-bb58-783a-3da5-878b635d2ba3,286015625,16871217975358041455 +6e9bfed9-7cd3-ffdf-3d7d-0062abe30711,858941259,2721438742313930700 +163c5f9f-913c-16ff-63e2-7862a949b1a0,2316663935,13842632528507827056 +2319c6d2-e0c8-4d13-4408-eb74144609ed,2563297843,3891462435154660002 +6da89432-a1ec-9ad0-5ab4-9bc1fd050314,2824771552,16823776246511067832 +4c31fae9-040e-96f6-84fb-e8274b8c33e8,3241419403,12532688633823718892 +4f34b901-748b-d409-a4ff-e28c0bdff747,1922503600,16997710151951584377 +be30fdb7-a79d-5223-2268-a3b0ed52c01f,3810687524,1687997652244092424 +ffc71acb-9666-7c42-a8f7-c550e033ce15,473068887,4337311515220657347 +7d1814ba-14ad-79b7-3b72-9cd4a7d352b5,1061848652,12504342005181460137 +c19037e4-fc7d-6b60-b09e-da1b6e2656e0,1353484796,6097238882694162609 +49b2058a-e8d8-0b00-d8b5-14592b5a075a,3495901338,10952909932788109498 +2ad379c2-7412-9193-9cb7-30973d79adfe,1472371266,2613238114304729481 +96f5c8ea-ad22-1efc-ba44-961b5e3b619a,2524789468,4384631613690247246 +24e33678-13e9-1287-de97-ce9776733599,402218536,13388340058492048405 +b377c784-3730-fe77-6de1-22b3793c4075,3482557812,7288639828990839629 +3190463c-d4aa-ac33-f882-20e6d491461d,1001298540,11490824074426862065 +490cfd67-0e5c-6d36-8c28-282c3ef2c9e9,2583258651,10132155857990342506 +7044101a-d1cf-557e-1443-5cdd74c3af81,1131789388,14106883895069951037 +0375494e-c555-6ecb-d531-85ea9d5a040b,3444696683,17360709994987117808 +56feb329-e9bc-5f0a-cb8f-0dab5f10bdbb,1745281657,5954704613510332336 +2a0038fa-3cdf-0fc0-8775-6363239be525,1752878311,16467483388108960995 +23c534a2-9dfb-84fc-b1f2-38951b227936,737651934,16643850464680667363 +eaadd346-037d-5e9f-e63f-f6c990d5d68d,872395958,12820663969096065992 +898f8285-a790-4080-7755-21b603afc92e,2969817388,1927925050925769832 +903dc417-f0b5-4c11-9f21-ed40e1af148c,248336631,11383448459230838749 +42ec764b-f48d-7f2e-b62e-57ff2340df17,832225132,12277022917744356788 +4c48449f-03a3-2f86-cbe8-66729460d38d,2642406716,5419240648089506874 +91bdb18e-51e3-69d5-bbd7-1d8231438cef,1140998305,6721512167371395038 +df347f43-181f-542b-1271-f559a8eafa86,2403820877,2264902790028070702 +9c188990-c96a-7972-6a6b-5ea0ae401ec1,1292356842,17031794565426863770 +787a63ef-5978-0bf1-c1a1-2cfdff534773,2862807491,5861966997055719555 +9a8f9412-d4b6-6f80-fa02-fafe48e8340d,646559980,15202375185368773414 +5dcdadb3-7135-9242-b62e-c2238ab0f0a7,2316431536,3752877606996447353 +60342d8d-4a55-7a59-92a6-0eb9f8c81a0f,3033489573,12598109915472572617 +a1b61e86-c841-f766-4c02-f11d477c5c7a,2150065100,16483936133404277616 +2752078d-e185-c645-99a5-f32f1c540c43,3459546264,15992255796905668498 +968ed703-e7e2-cd03-0d62-d32c1d3fdeb2,2293080746,15510612262716442280 +89777bb3-7f1b-2c1f-95c0-e8375b6fdf1c,3725735759,16416420882882913822 +ab29fa02-2412-8e8f-4373-ed2c8fe11ddd,2444506979,5240950991282647014 +e402bc01-9f51-ac62-7cb0-5b2b2ddfad22,1532708984,5273077157656099219 +50c28f27-6088-1582-ffd8-58d911514587,2481054176,9993609612686600695 +851945be-b107-c305-d20c-2a67692c72a0,2524639753,12912563177399411034 +64880079-eb20-00a9-85d6-912ca3ccc3b0,3425445360,11591672076453056492 +fde9ddba-b51f-2fd8-05ad-7e3e612e96cc,1575259242,5216304358616235437 +33134501-b5a2-b114-ac90-1dac3da31140,3093236360,10469471982679528290 +96144a0e-d7ec-4f09-a51c-4e35abca9100,2023957513,261265319820693936 +1d523641-6d02-3df3-ead8-6d0cdab66d38,1195497072,2259830004386973413 +b5e633bb-546e-7357-509a-aa555c76dc72,3335474920,16816510854584552593 +aa6c419f-451c-a320-12b3-2ea9533a65de,3955102359,8393930485214192702 +67ede717-fd48-808d-48f4-53305837785a,322898284,7362130774160288249 +0a3cf494-c966-ecb0-252a-78f72ae76421,616863969,15358003013753843674 +e5ee657e-3621-594c-faee-71002b7df7f5,97880849,9899565961411829565 +0c89f90d-9689-51aa-e45a-13f0d620e600,1811622928,12493331783555452784 +02beb57e-aedb-ce30-f91e-6bc4a586881f,3426948360,408271550182806814 +dc86956a-0f48-17ce-afe8-20c5f5fa7ab3,248655272,16443925598490310359 +3e43abff-f747-bc92-2655-96cd4f9d2610,1194610933,6382236176486524452 +a561f4ee-1f55-84d6-4c77-85c88fb43ea4,2554866749,6249709904110169965 +07b560cb-0463-57d0-8d23-0d0750830302,2830236831,13086631917243381198 +0a53bd75-db2c-6482-713c-64494fcf9ec1,2835919604,18300909283131164702 +652c7bf7-fcbe-499c-3976-f717ae8b1069,3460828569,15604584868313982761 +d16c1f07-a3af-643c-9d58-c9647ee4597d,4048150596,11005264006242080802 +96fda0b6-fa59-e99d-d151-e1b1dfddb41e,2783135191,9242682020064362550 +2ef9d1ec-e347-9bbe-22d5-19404d1d3a7f,1697625662,343044442189594408 +e4c73aa6-049e-a0fe-7f03-a2a7fcb9cc17,275231280,10891713464719950544 +c7d50691-b28e-92e1-b1b3-14065e8ef61b,111317116,14850148159515939754 +5483c795-f5da-f090-a069-9de897bce3d4,2484210053,15764988135941902119 +613e39ae-751a-1ac2-331c-2a43e78029fa,710784148,76490807272815464 +55e29787-0c25-477e-0994-392d6fa72b2f,4217340414,7376488360968467602 +6bc0e1db-0487-ecee-fc51-ef03c2c57564,1339438342,16766089032788860370 +246ede85-1c8d-c992-15b2-e922f7fdba8e,271942497,5969256490107084312 +8faf9944-6dc7-7da6-51b5-d93298b22f42,2780796732,4558398215160044834 +f232794f-2616-ae26-b5b3-3175c910a267,3694558594,16006888634886739681 +cfbea136-9872-b73a-7e8d-e2c6c3aec845,1484815591,15617190294554833455 +3e3bfe67-e03f-5614-5671-3703af76344d,3744374030,3427031809773710902 +36914c49-34a9-64bf-6707-11b5c27818c8,2344117924,6046327905133700253 +3cf862a0-97c6-78ee-c256-b5edcd17258b,3148079563,11018155825840568207 +83304ecb-7eee-62f0-61c3-13dfcccfb4ce,614156761,16752386904791287517 +a3c07e0e-cec1-c3f0-4fc2-9015f77e3b33,2828782240,14411032490053733808 +12ebf0c7-611d-ea5b-e276-d3fe6cd34748,719165505,16003040397172394690 +29f3e07e-fc01-04e1-3c69-846b54fcac9a,763838505,13669182366990244718 +1b772886-1ae3-7829-e638-a4bd0a71906a,4111137007,14722113669630231565 +8b2f2f6f-5494-c067-89d8-0ac2d1c04feb,1814945679,3975192763625517634 +c8a9c1b1-c8ec-4562-062b-f8336a5fdc2f,4277620519,4411806392570356644 +1cf24031-0c3f-1b45-f624-e8cc6d5befad,3205614155,12753102781866775463 +479851d8-f592-48c2-6e47-381465624d57,1312481521,4404464144550183725 +c30e5b27-84ee-f49c-bccf-df72956cba50,1441574044,8289595981157323809 +e4b11fb6-f05c-b6bd-695f-5ddf10eb69ea,2148876849,9784645160259881991 +1b48e200-19aa-45d3-3391-6e3edda596f3,109652863,7091452710604039351 +cf76a874-f026-5e4a-585a-4ed1edd650a9,3182814213,10250151638991418416 +01e3bc8b-6520-0902-1e71-0fef75cc61c8,3307221545,3483004818973048535 +9b63f3e5-04ef-b71e-0fa7-70643edea46d,85607028,11414056414059429812 +06ad7c4d-b12d-c488-9eb0-ea05ad440465,237159980,2951302576198421030 +b16b7cd2-6aa3-6d3e-15df-cc9847e770c0,2963977619,5657467161453307152 +47471998-2fbc-3a52-2885-885cf7ea508b,3959501074,17707750418147610762 +dc4529f7-35b3-1171-db57-e26122cd2a58,2863305478,11572772650160655046 +7ef1028b-8e09-8087-5eaf-faf650b04009,2606124170,1091511688345676135 +67831188-a42f-8d36-da83-e26c3c59714b,610979628,6443186476319623218 +a267c999-6bc8-c9c1-c574-5cd0c87d1813,4224232700,16298518619950243437 +b3d897de-92fd-fe85-f074-655db2e5211f,2796365134,12661123870241948610 +f8573e17-6060-c197-2101-595c8b3e2d03,1743467377,11645726236106046502 +db040542-bd36-c112-7993-501ce696b063,2828161268,2524847611665541354 +518536fa-3a22-1ffe-d930-2279bf47c145,1383477809,9146907425894164578 +f2e2e4d0-1bd3-dc0d-f891-ab548e509247,3223849610,38848494696350514 +c983bbe1-bed8-dc69-4d21-35a8f3f93421,1564649264,2468414691914835061 +ea8365be-cb19-d6ea-e156-7b02972123e3,252628959,15106642172838635961 +c160de57-5119-bbcf-bef5-0065c95f15ec,2832604207,9719415081026787022 +901c5031-eea5-277c-916b-e173b7d5b66a,3054209189,3186650176342119223 +20de0d80-c389-029a-a4d3-01cc828f6513,2768696818,622658363037053603 +c4530505-10d0-ca7a-64eb-f19dc48bfaf7,746642052,2207726976253941588 +1aac4485-8a41-9a96-6fc3-3b2e0f2d548e,2872818026,8277938490693728748 +0bda1256-5931-f39b-4f3e-0a02050e84f1,2628086715,4616331840820881643 +97129eeb-dda9-9bcf-7152-e40dbd5ab414,146582282,13508873933993185992 +2b55372b-d08f-8cf9-d8b8-540a42389340,2987998952,832225457203934354 +f1247cbd-a5b0-8b33-88ad-c439265f20d6,2014645019,9771664352657192848 +a225d9ae-2037-25cf-bd1f-653613f4aabb,1273237676,6341097323613776348 +5df6891b-a2a7-9144-e7fc-45496d2e3970,1240700889,4523279943234762645 +457a9a6d-01ff-b7b0-8965-cf5f58c32445,2042908725,12814321331613351368 +56bc4598-bd78-8286-6fcb-894a9ca4a994,1984714797,9920356699931220693 +7e362a1d-90ba-6aae-b79b-378ea289860b,2178750966,4234281726846872894 +b86d353d-4c07-01e9-aa55-332334ebb1c0,931776260,15638421925282872830 +f25c6877-aa86-7535-fc84-89b7e76ad01e,200503641,12112331055955808268 +8321087b-31c8-02d6-b1b9-0b5f54fd773d,4055326929,8968302270074269564 +2d0dcb4f-ed08-ae5e-ddc4-f1550c937a47,2448996681,12472232728485411194 +c08d79a0-2969-0d15-3670-4023e7029779,440372585,4974675776301344077 +2cbc67f7-3df0-ca7b-81e9-7d281c615543,3073084554,431645599245637340 +eed50dea-dac5-8640-b643-19b272926672,706286603,15653083028667052697 +3572dd71-e156-6fca-27ba-b02365ff4487,1957043419,5429602992831333792 +874a3d26-dffe-cb11-37a5-5ee5b79a7cda,2213822368,7882932249588366842 +11e05568-c53b-e446-08e6-039b61c1e6d2,2938453456,7428772942429824501 +54aa7f9f-9e93-e7e7-0ba7-49efc0e2d95d,3076081761,949147167363825400 +61b48a35-5aa5-413a-5d21-a2ebcbd5253e,1624746683,12402096158154442328 +d02dc824-fcbd-460d-1d19-85aceef1e972,597449761,10269884058017947337 +e33c88dd-91dd-0afe-68ed-eb018fd77498,154529580,10477042183700903940 +ab42b529-79e2-9d15-2195-0422a1b7a8ee,2365390126,4777715963217570662 +5e5dc111-2175-282f-d8e6-c5c419892f0c,3759634257,14038675884219763643 +ce917f8a-1614-fe18-ff63-1ce1375be725,191507001,9998541349229702736 +5038bab7-469c-3897-711d-32736549c3f2,2170806641,17050333104832326613 +e9707c00-df98-cf52-f90f-aa41a05c822b,432405975,12887485203299845536 +2acc2cf0-534f-bbad-c975-29331a003591,2592943801,8987579680000198760 +b02ff3a4-539f-776f-7165-f908d4100140,3857179786,1951750579467324317 +66e94546-7f92-3f5b-b0f0-5ed10fadfeaf,2714827554,6419407335867994346 +3c0acd4f-7442-0461-3d82-444aec18460b,2939646572,15356748659053920208 +19bdba87-66f6-20b6-d5df-b2f045609c6f,597605349,4219696535515382931 +0dc180d1-b2c3-a862-829c-fdec52bfe298,2125363889,8261623833588463677 +76b8e711-cf96-8d9b-b7f2-2c69c73c6724,3916880983,9053860729102465443 +441b999c-93d7-97f8-2e1c-d4e74a987a1f,726033079,2552240795572189619 +571da80b-7d2d-4762-1977-c1a904ab3a5a,814165306,8081854518888880787 +5766cb18-062a-2a15-dea0-c3d5cffe1508,3263342600,16340580810378177201 +1fc0aee4-0174-f0ea-be12-6e2b3355f1c4,2571408957,5975048320420677223 +84894e07-f5a2-ec58-031e-4facf563c415,2766988641,16566369372711317081 +22903828-c58e-b5fa-30d4-9c07c0c75e54,3922784397,2212635799526141208 +9bd4816a-6077-19a5-f223-a0a6d8b39218,2568872026,4000895613869544557 +f68e346f-8f98-8c4c-0393-a81bd256569d,1802865762,683341517508285243 +d263bc31-e427-a49d-3f1f-674461fab515,3830515192,2320546830644472566 +2d3212e3-0d70-9067-6244-e1b33369efa0,3294639490,11530497639676372878 +9917379a-389c-01a4-bb15-8b8e743edbdc,1361698738,16648194595296981483 +3f6db31b-a221-0f14-97b2-a1082b4946d1,2824333032,2381152160328830485 +71beb55c-7b71-db35-1daf-b6843907ed2d,326799092,17456992603341077106 +1778d6c3-d62a-cc21-96c3-f504658e8397,696040483,15534200438504106513 +72df3566-24ee-1997-a914-a5d20c7924cc,3373275316,2368880392260222777 +21b7a2f7-9c6a-b934-53dc-183cf5fbecee,3920590999,7447360535438262373 +bf99898b-d07c-9841-ffcc-ee1db026a74d,887963785,5031527696999184635 +a23da45a-7454-1737-36cf-28f20ad1f81d,23347215,7142268869596279141 +12918e22-9bd4-102b-1395-c1543df9304a,2675044086,1482112606093684779 +1d66cf12-8c7f-695c-a62b-daaa5d999f17,2863005953,3468085715104302351 +dd2bbf55-c624-a320-7918-a8e0651276c2,453245158,4378080615904962803 +bc6b4b84-2308-b38b-7625-96cf12516f5a,3254703322,1192504237963676680 +098fd628-6596-c5e7-31a9-b18fa8f3f792,199949565,15440321123645731964 +f802696c-2c76-aa4d-a715-6937ca064ba4,942836349,2598741085774515278 +be7588b7-665f-fc92-7644-9b1b2a88cd08,1320771342,13286354251915459181 +284eb58f-75ed-d6e7-a826-366b2c82e6dc,340708716,6120743255362331330 +e798ada9-2bc4-9a5e-b64b-beeafb4bdf3a,3978964888,4159210564954825924 +d46064c1-d547-0f04-9c1e-c32c9af6a661,4194680101,6627820269147034632 +1fd10620-885d-1fb0-7e75-c8ffe7e14e1b,1661143111,22815056127933215 +4e7fa6b3-5a8c-442c-aa1b-f0d084e6567c,3109192772,6128008380558590289 +61d9cc01-ebc9-e3c6-48b8-f938641dc206,1020022717,2043041351011853867 +51927ece-6cc7-24a8-abdb-5d9ba49bcf21,3113935126,892555446721760866 +a77d1c74-fa1e-53fc-930f-be0bc50a8cd7,1391860172,18155807985700541665 +039a063e-1eed-d2fb-0bb3-990a1770fcf3,132158735,4382551107948846034 +94ce9d68-b13f-0bed-e781-958665e5995e,729536226,11133031076951624665 +41b64fd9-d0fb-f0a5-c184-cb45ac6948cc,424159425,10161771803248576757 +f665eb63-80e5-bbba-4273-b1a053dd8a3e,618615355,8940550087380822618 +7741db3a-31bb-7de5-3192-a15a45f182ff,1413653343,2548739687236139769 +23695158-8d90-3eb1-c45e-e2e117e68000,2342650772,15205210372273481332 +1536093e-077d-b5d8-7c77-9147e911f982,98938165,10361279076874869971 +dfa1e542-c40d-4d2d-1218-894e09fcae0f,3684079208,13139524080355935967 +a3f27241-0502-364a-c43a-7456a1c8ab63,3990315760,17563438366335579323 +82f90b26-298e-b240-0388-58d2d8f4c3bc,1055922135,17731350469178206706 +830d2937-abc6-8ccd-74c8-2c692ce86d96,3538899086,11510777569048808373 +84f08bad-fe7f-5744-1f81-710d1d56ee36,679032387,9720569854700432408 +664d15ae-7a9a-9d36-2580-6d5fffd393b9,602002705,6058303651397104104 +cf82042e-d69a-fcc7-3bf4-aa9ddeacdb00,3944977924,17081545187278263688 +21e2c6c3-33d2-74ef-d686-ff8363f23549,268495010,12122732834152797557 +18f1a123-1b7f-80f8-2c0d-dc20bd5093b3,3459372556,10284986373087532814 +3c5cfebc-5093-8886-90f0-3417afeb15cf,635839492,14250642598596801427 +c96a80bd-6e42-8034-f3b0-c62d7bf84b72,3456584832,838471030330820266 +5f508f5b-439e-3bc6-7e2b-2e476401cf27,3813258027,4346845191190759314 +f14699a4-045b-2f7f-63d3-c46504e4bf55,3084046037,8303145163586741765 +10510544-5178-7335-2b56-0c2ac8f38102,2573475079,11737779032704993953 +5c038c52-26ee-eb2c-dec2-3e0cca1a9328,1893164438,10950381697937344966 +84e0448f-a9ca-d401-086b-123cebc57269,1252341191,8267008448907812456 +e88ed511-4286-1b91-ebf6-162741b67436,17889735,2548801757011239920 +37ddf4d6-78e6-1d25-b929-0246eb36b03b,343119101,1647101915256751969 +c67b8167-e153-0d96-908f-2539f24b94ce,4094798211,15830294923303700633 +6cf23ca1-8d0d-ae0d-87ae-1bfb2a291d6d,897000873,5824169293641865859 +d1951b31-888d-9246-7118-460b6e803aea,1065323086,3147921706954198694 +fb89a51c-be09-a7e7-6910-b07b313b5671,381636883,9329583654319522127 +6fc08c65-5415-1ea4-3fde-fb1813963c9e,1277870021,4282189229579541992 +0d617673-7244-15d5-d505-6353f16cd84b,1795543001,12386675893605303832 +fce1c3e1-db9a-802f-333c-4d192dca141b,1358111465,5018007212810505859 +c82e76e5-b165-2f35-2e7d-7ae340947f48,4123611354,16588631501918818739 +d36caa89-e301-7515-ea22-a5478de68635,1057137568,6637264399280608228 +e9e0a595-d316-0724-be9b-3e1870dd4502,356771094,5703956968802021901 +e724b5d0-7e53-c9e8-0cb8-a6c5d84fa456,3315746509,10688550686494121864 +557c6b66-0328-79aa-0ce3-018e7e895c71,3555796729,7025557397821318803 +c2e2772f-283b-cdd8-ef21-b3b13429d1bc,3159720233,18381501916229329462 +bca7e377-3feb-5309-1a72-86eb9929b3b9,49624479,16567264835151046143 +77176b72-071a-6e2f-d7ab-7202222d8c65,3963036920,14607108840909141140 +be3893e8-d2d8-1dd3-bf1d-e4890b5e7db3,2890975426,11085315097862851124 +f6185c97-b396-da58-73ab-9c7dffe857cc,2013957316,4660110559498857526 +c5a734c7-f6a1-83c7-60d4-909043e54142,3047441556,17350787658601977401 +f6b8f0a6-f6be-75f6-5c5e-19065057b0dc,3731189800,1067386733895407236 +e72b4099-ee65-2aaf-c6df-94c32d7e8b31,3745622616,17770087947806318875 +fdb940d3-528d-b29f-f058-4fa5bee9ab41,3838592757,329780298088490870 +402c10d7-6149-1358-22da-78ddc6a4289b,1099805822,15496610877780535193 +d3003f0f-09a4-0896-dafe-639443e9efd9,3417777675,13400030818967650076 +a56741f0-d7ea-8ad7-33e6-7e64fca489a0,1348311691,11696592269518092946 +fca84270-f15a-0203-0e28-90cea63d70b5,810684869,17787356603738152125 +fbc30d5d-158e-a893-ac70-12908b9e9fd8,2480965665,14968455022609884671 +072997b6-da0f-bbd1-8a19-701d578c35e6,1723883943,15257277219275168728 +ddd06ddd-152b-3123-dc51-1f5d23a738a1,141003234,16521244375438511005 +118618c4-a85e-e3bd-2846-e5441857524f,3029624368,14707779721887390918 +de091f7d-523d-94e8-4453-42cb575434f2,3336823002,9914188368670499659 +1e3f60c7-1c39-7c51-3e8d-9c3a40793435,1385627916,14859386212715172874 +362480e1-b86c-d540-b03d-4c8495a2ae84,341050269,16245151902263288426 +bba16240-e1b7-8002-a966-11158f2d07f6,1125045739,1711311863624454382 +5025e055-3e21-df36-b596-a2f2ffcee090,979746399,8265987674588897374 +69eee7e5-6d92-39e4-4496-987abf182b11,1859971780,16943108397947806472 +9da7ce15-16ef-b433-e19a-3d62c3c1ab4e,1225055435,9229878981999298295 +d8009577-edf1-cdd5-51da-54bfbd7711b2,2400509631,7839131865478604785 +bac413ad-9499-1e51-4ef7-37bcf2d39e80,1038222873,17261162847589289224 +686f0fa9-8961-0101-cb94-c651be5abaee,552625673,6935237533973999745 +0f4350b0-9df4-43a4-e61b-866fa4e355fd,3475702756,246798945844616590 +6dee1106-0f53-179a-f277-f49fc9c935ac,4136768019,4463135117552462616 +756cf6b0-0599-c550-ab24-039e5e6518db,1892268349,18390698086351352415 +596b2616-c2ec-66a3-a648-55afa755522d,861028897,7099767649141842876 +9019f2e2-f988-fc91-a61a-30dcdfe24145,914094927,2416465774276540448 +08f82183-c868-6055-2b2b-cbd4aec58357,712451988,13659862740748842451 +d820330b-02ad-07bf-cef6-bc0b17c85792,2593188358,5888801292487516606 +58836630-272a-52a4-a81b-10bdd9704751,1991769267,6546544608569611432 +4b6f5ce5-7daf-590a-4b72-be86ced9aeea,2798850144,12710129591016454328 +be62f6ee-9bd2-4e26-5c14-b853b9df2eeb,333616943,5809288483640332675 +1ada1ca8-68a2-a233-992d-0741df69d0cd,3873318225,8859908242451345062 +ecdbb91d-a4b9-aaea-836c-f9dc3dadf33e,4209962742,14077908402388641690 +e5a17d74-e809-8542-d5df-b262286ff193,2165874896,3886985543311891711 +dd269357-e863-2a0a-0bb4-500fe5b2d618,149320264,15219603065454456396 +bd08db0f-f83b-cb58-a895-6ac1a80c8608,1114077294,10606855016142212693 +af7f71e7-9ce4-6c26-fe41-62b84a8d5908,2416616661,11158644164605450619 +2b49cf71-46a3-b970-7703-4932b4621bcb,4043057640,11499824857158965240 +284930f8-16d3-5b4c-790a-06fdc902599d,1127423842,10510581712921997104 +6ccc9b66-26e1-b4af-bf07-bf45e914d463,2586246539,15931795294751736988 +c1b9b954-21b2-af90-4af0-ff825e680232,1833306886,1628586192663298856 +c01e8eef-d62b-1a82-0be1-929ae4db404c,2753101762,13176697260560133240 +f0554dd6-b7df-208f-1343-1598e840c811,2813708161,14507782639480830199 +87e18439-f26c-14b6-d76c-3fd8f368878c,1903343678,14797428677234026357 +53ba9354-7c34-5855-c1fe-54190bff64fb,1415933164,13429131603111428217 +0835929a-f862-40c8-8bfa-ca9b17920422,1038419355,5474048625499747284 +944f2019-ac77-f9be-5fd5-414b0e24a16f,3264848043,11720116826528942640 +a6dccaf0-17aa-8777-d4c7-248b3cd204fb,4013280857,14429825636526034568 +44af698c-0127-0aec-6929-f53ce18a1d13,2994253132,6871936729797659629 +88966d8d-6ded-1c45-5583-0ce965ab92f9,2615477812,11888449423945581584 +0d875ac9-9eb7-e08a-87d4-f6930bfc6acc,505491511,8055376778789923710 +2c874e91-3e3e-4bf1-3ab5-276fa89cf02d,42047543,16963749636564283749 +5c23eb9f-ec41-52f3-ea1a-8ca92b3a8942,2624553406,2043255993759113534 +1e9b089a-ba55-4455-c53b-f2ed24a7e2bb,1601710601,5324196682410433121 +844a0a00-78c3-85c7-81ed-5d6d0b0916b0,1703009570,17480759315426986633 +fb45bedd-4507-26c0-dafa-406fa07b584a,3730092457,12199806310405954075 +9492196f-2ecd-5dd2-5304-476975a35b28,138235062,7320240688920644710 +54030d23-dc33-ad18-6d57-dfafd2a9850f,697379673,7125275669439077862 +569ac00d-4110-72a8-c52e-2de7ced92040,1092230198,12466566021509949791 +b1d87e02-30bb-df1b-3adb-5bc24c2ba0cd,1678823120,1071093158771912463 +2cb5f820-268d-855f-84be-b1c824794224,2138720604,14405092195771412022 +5d26e8fb-1ad9-2320-1eab-345cada22361,1048155787,8415037062396320885 +6b05986e-274b-f3e8-229f-8255f73f0f95,712086732,12693533752972197270 +132c456a-cf26-3dc3-8aef-f46e72b4dca3,3549389458,6542589442861898535 +8a1b4a5c-725a-7d6a-2ed3-2205ea3148b9,3420311500,13913984671027397037 +26aa191c-5f36-909f-b3b0-2b2ac578370d,2368370921,17211041888213229940 +f85e258f-02b2-5d34-b821-7225f1241858,1456042610,2379000339718834952 +f6f6dc72-bb89-2777-3a8a-0e7c8058d93d,1313811693,9970082381382640856 +fbab0e80-3b9b-dfec-cc6d-744060dc54a7,2370875713,11801984767133072514 +cfa10d71-6056-8354-72a0-c8cea1a7cf08,3284744643,13259272291965488890 +fc9ad20c-713b-2c5f-7600-10ef9bf845b9,3938026525,15667437461625037083 +f38d76f2-0c2b-0864-3662-9ab84049fdea,1991865388,7627494550849620761 +0ad8cbf3-5eb5-c4f5-d670-c8789d40465a,921252193,1189146903374821812 +853e46eb-9540-5181-7e4c-b76a7180f313,1314759415,1239629262183010911 +982bf479-4852-4f97-e5f5-50f1003aeebb,1026736452,1790333156194170586 +b533dd90-97c7-7f2d-22c2-0108f192919a,3683366952,4625016734585703521 +05455480-fd69-3695-da91-3622e42d4430,4192395261,6074733539598723695 +7679cf8c-ed4b-e897-bc43-e37864b3997f,1619435953,6452989343927253701 +47fcc872-e33d-b1fd-fb44-ade1e413b9a7,2246188377,5642823944777143202 +42d111d1-48f9-f7ec-fb25-81013b7c5a24,1771825349,7359725992837518019 +55b3bdca-13a6-3d7f-23ca-bd8092b4355a,3865279746,11305891845050424804 +34d34c44-3561-d708-d9a9-16d9281fbb9b,3216307578,4834992728217093241 +8fa5137c-c2ef-8034-e377-be5031cec0cf,2225354569,1313298603763250521 +1bc3d128-a1f4-5d40-0029-c24442cbc9ab,269459829,11707609948918194922 +7fe2b9b0-4b2d-1193-01f9-3830dfe57ce7,4068098165,2718138927677243220 +609dafe2-242b-5fc6-da96-d34ceb1c863d,3984145645,5965077139760051498 +9de3cb0b-e61c-5ac1-ce5c-3ed6dbcd2d28,1340910574,6825583927213181882 +1b939c12-445f-eb9f-d9e5-532383c6fbc0,3702054893,5055601954046328897 +71405c6d-a917-c78f-71f9-106fda382e8a,4214709216,3927618758990023360 +095ecfd7-8601-4345-129a-94a5533e894f,1898544684,6882175043364725732 +1f88328c-e456-7661-e343-15683c20b307,288049854,14982458092682654049 +5cebcc82-139a-bb1b-b958-1538162ec705,893435042,10156963068163961586 +26cea074-01a1-9ca1-9668-7667b34e2fec,3643939158,1959918118129352558 +d48b3ac7-f0e2-376e-4e89-e3d9345fc66e,4152741632,15594388940363993198 +68f16213-5b11-7221-a908-377dd9a0f068,688000513,4648950393191736130 +0325a0ae-ac7e-d825-3d7e-f0e10ff86e85,2681961765,17618247199441254321 +82e6cb82-3ccd-7a87-5307-92d68cd4377d,1614485049,7830720969112708906 +f694f90f-1305-7f2d-0bd6-0209e97c8c80,1683623453,5268003761356436262 +73251424-116b-08fb-0e2d-f9535bd86bc0,3599946941,8393853763448143512 +624604d5-b2f2-e27c-9a9b-ac41f737cb9a,3208595765,11671078843282478394 +a0349c8d-7a4c-7f78-7ec4-ab6abd5267e5,2601219930,6358624553699642462 +9890aa62-cd36-8a5c-b84c-6970e7ae539d,648868150,3673242233155772106 +ae5936e6-adab-7845-73de-6edadea643c4,2911218493,7823982698212319966 +a6ee16dc-e45c-bad1-e7a0-991a8885f35a,4148687701,340994090137038037 +8e20d411-f501-551a-fd25-b5ae6e24c3d6,2783636005,781275068716856012 +051c1ae1-c224-27ab-b0c1-18fe8c03b684,3330299543,5891574103436072959 +6f0868f1-36f9-efc8-a419-255daa56b920,4223340690,18326073180332817275 +ee4b9c09-eeca-f6e7-58f2-1cc2da9f43a0,1280449545,16207605644548935080 +6e4e4a96-c8a6-ca50-6389-ce6a80794409,1020310338,458209947260756232 +a3a619d9-c280-e6fc-9414-ebd848deb063,2979811151,13501284321946815843 +5c812f64-524f-eaff-cf43-264e306d31b2,3627810454,3382008135590842813 +346c0cd0-7d7c-83e0-8a47-851ffa853641,2906768506,11153377593563442831 +3e022160-9130-4ba1-6316-95a4cf3f1f32,286139685,1143377431902693861 +b2c95739-9505-00bb-3171-522703be8a62,1189924794,13597175526889560311 +3b9c8307-801f-326c-1896-09cab3cb4349,558346707,8304616792980513540 +290776ff-d870-d532-076f-d3d1b3d8b354,517692258,14856549531848254551 +f34c9623-c3e1-914d-c0ff-be0979667f01,3773811410,14125061334911171693 +ac94c93c-8acd-05f2-2182-bd4f8543fdba,654988361,3704323448320643682 +ae0794e7-e509-8ef8-7873-f64e41405a3d,2061085068,4085022553115462428 +1dc52c2c-bd95-f817-2108-7d7d22c6f46d,62245221,2230348464883320560 +97d3b40f-2144-fc42-d3d2-c88bfb4fa9f9,533871048,13136661582389628023 +a1c1ec14-ae1e-ad62-739b-defca2726374,2469640382,13266596723133589374 +e87c3fbc-abe8-0861-3d78-35f36bfd4739,336731154,18029686593179997297 +833a1c2c-d7d1-3696-67e6-06a1e52f92f1,3629725017,12028666552651215594 +19c03051-7199-602e-e7c7-0747f9d3dbb4,3291553659,4745786660931617644 +43830732-2f00-7708-5713-26687d348c4c,1314981615,4092711058454764020 +36720d77-5c6b-ab9a-ba85-0609f011a6d4,3462800679,1819927655147044207 +5823010d-e6f7-fc28-8dcf-96f5abb42d72,4025982816,18211140543826413769 +750de76b-5e5c-d436-5225-bd17dbbbdd1c,3183684352,1855567960809811259 +ee325c29-9e9a-c43b-c9fc-d87d4a51a0f1,723007312,12296522638695696555 +9c10f849-b012-553f-594b-463cfea7a302,2157506063,14588090133179681204 +2a1f7512-f5a9-0e5f-e946-e421b3bc9b58,328563933,5182023623011484605 +8cf820a4-ef85-6762-875b-b566da294f7f,3877442037,2840095054653553721 +ec815871-8a5e-eba9-2966-5ac4df706828,378872948,1318943716568381798 +8b537f84-86fa-cb2c-d28d-a7ebf1b36567,950649796,14135340513520706530 +1ffee795-0b9a-925b-060d-9400eac215a7,1401944871,15938931826955870975 +3e71a83f-d88c-2ad8-c740-0cce470c671e,4238245925,14818243395001682635 +cdfa907c-e731-774a-1b42-88769d17e618,3640746774,15271042014120110775 +1567afd0-39ad-ac3d-a05f-db0f85afdba9,3705359272,3755904479548849347 +b31856d2-efa7-db38-fa9b-406152a40d9a,1258814594,4429603773051871628 +7b19a3b1-8fea-cad6-9ad1-819bdec1c865,3466069115,15406784878141980178 +6539206a-2b7b-8e54-ae75-a6c6ba4303b1,4189735354,5990831529687863203 +8c412cb5-b30d-b944-a1fa-998bd3b7fe60,2956671095,15312487523412238726 +10442734-11a1-1798-53a0-6551fbbbd070,2596468060,1066189952937913171 +245345ce-97fa-e01f-5cdd-f1c622004e9d,3202152796,15217492838813616274 +16861777-3e1c-30e4-19b0-97bc8ed14ec5,1155490989,17477182265035486867 +fa4b0db9-384a-d25b-14f9-d9c6703fd8aa,2061430317,11286082105396100285 +140ec904-5270-b3d6-6135-cad4250f4103,558101830,4021572313449285723 +4b0fd889-5e8d-f320-5d71-ffc6c5fed81f,3819929461,3464504945397589021 +7dcb39d0-bafb-7e61-0109-cf45767bae95,2084965463,9500616677926062309 +e7eb1920-c501-d7dd-30a7-dd10b375b343,1181679572,18135771317146183789 +ef0fbc21-e939-73af-1837-6d4bb75eb0a4,1338194057,4674559943039660451 +43067e13-3d10-98a9-0c45-92a64125c706,3796548986,4311651789733818853 +74a63034-26df-bf8c-821d-d9837a4dd8c7,1880797258,7564999985367032687 +cf6090a4-70d2-e1cd-98ea-4dfee7a671e9,3848541403,8300262782975127465 +a55a12ec-d89d-8d74-99b5-f37798521bc2,532617538,1355579226442101046 +c2c4148c-b6b7-9dc3-f397-4b45af40b39b,1464133175,16787580766393055151 +54cc8a90-d8a7-62f1-8b69-871208b47763,2425274825,14233316980595212770 +84224dc3-ffa0-3354-7a73-61d03ef02237,171317442,6465736539932178209 +3ec026bf-0c33-6953-0bc2-23ed43e9c684,3977215845,2566820501695186860 +de38f557-6526-2c96-2592-10c1d85129fd,3073641006,15634927564013655622 +2b092928-41c6-f599-5712-440a28e69846,1467105169,6723129269430594005 +a8a75dc5-47a3-10b9-7f45-56c32b09ef94,2788367024,5179893921001132255 +f087c7a5-4d12-2a87-2bfc-ad3af2d13ff5,3663135428,3839625638730504094 +3ba10ae2-3f5b-ac36-495f-ffdd578f6365,138456791,13340302967495904040 +246152b4-aa22-c1c7-b09c-0af82f79534a,2876551181,7163705922421162336 +bf11544a-2c81-125b-fd19-eda82755957f,197764010,5783869793889404141 +a55f721d-bc81-ec8d-4f02-1ffafbe71f74,4095103782,4211944951951496213 +c28ca4de-a760-206b-4276-f3fc8ace6aff,3348744858,6561827648297198456 +cebe0869-461c-d105-a774-a2a80df8e378,309549243,6730429263866435235 +8b0b7a4c-41f0-ec7c-137a-762615ecb3af,3041887364,13795699895976294727 +aa56c577-8ea8-e5a4-8668-28dd1616ec92,1543080296,13986296288724889820 +64fe6cb7-f6a3-e005-2782-c69a5aa7c487,1270293324,8096110917717550642 +7096c8f8-9e22-702e-f81d-fcf1b0875586,912051566,16495697281517197809 +f1238245-b20d-949d-0a8a-e41ecf9314d2,1642289889,14373938257921876330 +4dd04cf5-38bd-37c4-1f94-24e3ba181ca2,1741032790,11218643495787039264 +a151ca67-7a3f-6c30-ce04-aa73936e3bdc,2623966205,14083265505471510887 +d4e35929-4904-9847-f5e7-4deb36cf31ef,1202432561,9086352422919112022 +3cb5be85-a08a-1c96-b142-f1ceab30e6c8,569910874,6613402864413060238 +63445964-2182-d60f-1931-c379373837a8,1910434763,18227019356737041234 +e8dd63ca-ba5b-8af8-788c-c6dee0bdcd29,1618185208,14374996398521634779 +bb96b615-fb81-1dca-3914-504ef52dacd5,3089604964,10663923817043869170 +b837aa3f-bd63-4495-2344-717c965d1927,983315520,12877952638571575869 +dc21cfd1-4263-f931-cbc9-9549631a6e36,989724906,1856311543781061611 +5a2a6711-413b-747b-9d19-9cd95ffaebf2,2288981085,1005644440760276842 +bf394695-9b9e-6bb1-e315-4ebd6b998a35,162407569,12185583794262820827 +693fb8db-a1d2-2973-11cc-c37fb198adc4,1385276362,4631342495039090150 +3cd9a1dc-c3dc-50df-71dc-6db3f35566e0,3075917150,11757677791723463394 +225da96a-9415-2d73-25b2-7de2a46855c2,2516032219,13892388057137549634 +e3d8c049-df66-17ab-d1ca-b427857232fe,716306382,14571466078720462981 +e66f670d-2568-f533-01cf-9be5c0e15f98,2953042795,15476751340636884832 +79564b81-26b1-68d3-0ae7-cfcc16df19cd,1921528193,10780006190780267815 +787ff13d-f367-c9fa-7e71-ab513a6ddc85,2744381704,17508101443707810539 +88e51491-ea81-98c7-a4a0-7889963597af,30196210,12613743769472750676 +9805d4ce-a522-426f-ffd7-743ca7f53cbb,2549276778,1450913729778167332 +9b389e76-9d93-8f39-a80b-3b3e9a6cd630,556109022,8957711457003968934 +e311b705-148a-824e-28d6-594c35619b06,1693065366,4696393042740640012 +36439ef8-497f-cc34-244a-4c54a2086e9b,1789851875,412958396587637148 +cfa3c276-13d7-3159-a82e-0a457aa05dd6,2309823675,13722232821615033397 +11b8390b-611c-c8c8-eba6-44b76ea128de,1245795476,8998323247808798476 +6234430f-b225-2884-0592-f4db813be2ed,1865087282,15013870550330807946 +0bc99c69-186c-84cb-8165-c7989b79c0e4,4217340861,10525430975356133377 +a3104425-919c-aafb-983b-a3d867a50961,4275693104,15385668982845643182 +03b720e2-a745-a909-9d44-685e72d345a2,2307704149,9973007328872344295 +fe76cb72-b7ac-5d41-f5b5-48d72a1bac18,2490073711,7693503292849299595 +f690f926-98be-6d6a-91bf-0e1c88b9605d,2598981383,6377103854393576581 +7c7cafc4-f7b4-19ae-cc4e-9527e07ed3a5,3312047033,14666733225370270872 +488613c3-ee66-3a20-5d05-32e399237d49,2850140717,5096426048245491246 +c33efcdf-9d9f-463e-921f-e056fe2c8afa,2509240099,14788177804586494263 +f23cb5aa-2e22-e026-ff6b-5178141b142d,1283300007,15700815428623875772 +3f11dabe-8a54-0f3b-2a28-d67c1a091374,2436409774,9106136142329602488 +9a8f1e8a-2718-124e-6b29-7f0e0c26942c,557145755,1754308856398149889 +e760e20f-8408-fb8a-9b1a-51fe2a7a498d,3371053649,4825372385551832211 +621aed5d-62dc-8d59-8b3e-212f5e49f21b,2774466092,8066397839673137588 +8eee2fa0-b264-14c5-f24b-c490603410c8,2534666175,1540857083248625364 +bf9b331a-c432-a403-0c6c-90f96c858fa8,2609897046,9169827555676275648 +4bc9ca85-97b7-96a4-ceec-337779158a26,2688674375,10727130869144029781 +415a0a51-66de-e04b-1fc0-53e6a031e0b4,2888460580,1313430909043028442 +c72c36d2-ec89-f4dd-da7e-7f85b5d8b25c,366680588,10346542689377623910 +f396d4d5-f232-70c2-9551-86f4e5c1795b,751540806,3579495599669795848 +d605b5e9-b505-0dbe-bd7f-4095fddf8296,463836500,12059701148053215323 +53a7f8b4-8c7e-11ab-4695-42a18f7099a2,1410676678,4485849894549506281 +966b54fe-4b57-f85c-a295-c7bfeba31da9,753104206,17685910532508363222 +79ebdc83-58d6-bac9-c4b8-39dfa835fb06,4293452638,4844239011864102461 +d1c3b056-991c-2a3b-5b29-cc233057ade7,2508505370,475041537334361082 +cbf34f5c-e1ee-d101-f9e6-9b6d73b1a579,2546397547,3858727886214628628 +a00b4604-b380-3df5-1ddc-0406cb821d1e,3153711089,215160824104618122 +3105dc35-4beb-ba3d-db3d-2498190391cf,724638691,9679832943317875838 +e0a3bccb-0784-aaa5-14f1-168e4d67e9ec,913538158,13375551107844324769 +87670d8d-adf5-cc16-2359-429fd941fdac,1645819045,12531729486155732096 +1bbc484e-f886-9e75-6b62-db131af2439e,833279377,1592567870744731079 +629d4235-c009-2f32-4c22-d8a3781fc836,1954054960,15762015255491717320 +cce2f199-8a56-ceea-96e0-b25250d66614,2742616184,1677846208952870429 +1a4bcb1e-9643-1880-72cb-334b2624524f,4150616081,3624425722619992462 +fee0477b-3c76-849e-ebbd-91bace511720,3629335323,15557381932525420524 +8e145d27-4a45-5590-b469-d4df131e620c,1278587191,2609088454936923604 +e0079367-00af-2920-8f11-fa80cfbb11af,2979069917,12261212268868039039 +bc099852-7ab6-23ce-cd7f-a3250e94678a,4012465246,17700561555647500121 +869add5a-12d8-5dd7-fc31-8fc5cea76684,3601354204,14902911966553412883 +b7931dd8-3c6b-e8f9-078b-563e4c191025,2285933299,7809329509939352323 +0f771dce-80fe-6447-8093-66ae800d8b21,1108256169,13160083945779751466 +20632f42-fe08-94ab-f1a8-817af08db490,1693894919,1512201181877000282 +0f73da82-323b-4252-c989-42e45ef649d9,1280863244,1207365220319040196 +cc98ad54-a6ad-aa94-8580-a689d5cf57f5,1282892151,8041560870981110739 +d39a5fc0-51e0-15fc-00da-e7f515d28fd9,2366044011,8048903540739444971 +669badbb-6dd8-f4d7-0478-a09d385ec2cc,3532864978,4420613784126523018 +2bf8148c-0b36-8899-d013-c522ae0d8b93,313548835,3505453016751859721 +206c7b7f-af65-a2eb-e393-4e70c0875711,3234587984,9212423651454707089 +48700c08-de8c-86e7-8004-665ec3c33c84,510283216,4561717439523100004 +cb8d33e6-7b1b-007e-3efa-9320cf30d0c2,4115093631,5634010544841244947 +4b3ea52d-f7c7-64c8-6871-852c746f7190,3192169283,10343192774946404519 +64c862d9-c821-eec0-327f-cb6afae07f5f,806512730,9624684654713116278 +0a814a0a-7bb6-bdc9-a376-17f39d77caaa,2884072772,11837123728295914578 +584cb85d-bc51-24d2-0ab9-35ad73dcec60,4199700674,11681535469518730042 +aadc38b3-d7b0-8bf6-a390-d4e4f36022de,3828068289,14834719414157567744 +54c0bf51-8c50-256d-086c-c41aca87b66d,826765935,17388053439445730776 +906f2dea-073e-8522-e1f0-cc6b2bb05dc6,1787821543,17227609286409119231 +358c2bb1-120d-7784-240e-53ba79966647,1580658477,8038583583842064661 +342ecdb6-8924-fc52-1437-775887c5f801,1021841168,3070865679432973732 +f85c50e1-e72b-7d15-3a8f-d2f1281fadaa,3108993730,9413113025398955071 +310e0cfb-2876-7cde-5ffa-6e4887b42c92,901050251,2019322656643335837 +3780e4f4-f7e9-ee61-b329-f8c5cd650b0c,117508406,7781341410949899197 +43ce6666-5328-9d11-cc91-0cd8bc57e190,556260734,5405542428319827577 +43273d31-d004-060c-dd9c-473fea96e298,2895318164,15943309838555484120 +7f003917-35e5-14f0-9252-9f14164195cb,1526710363,15997031524883722721 +232bb564-a4c8-70c2-b50d-424029c9dad3,3736608607,14484700472872918745 +dfc69547-5bd2-ea95-0df4-aafa96b78120,1013519258,10182314547970662875 +66dc9f95-f8c8-7010-f8fa-b7aa3ab55465,1312739999,14613081893302103638 +fc517dcb-af23-1720-a16f-260d6a59163a,2023190527,10043746689306686993 +7c6dece6-7246-772e-6e07-22bec3c36922,3715561451,1161125237607745607 +4ed98519-1e88-8454-6ca0-391649faebc6,2833570757,6779331662092628227 +70996730-4e51-0e75-fe85-7297c7bb4750,2732112851,15543497768344028085 +4561c3b8-3317-12fd-35f3-56e9ad857281,1164210897,16713583709404071876 +78779fc7-bae3-5a21-60aa-bb4a41018651,2044620959,15222899095108665795 +126e9054-2156-29d5-4bb4-c57f3109d1f8,4003870514,16032842944747068161 +2bab5f30-35f6-4f30-c627-5381910c082f,1321566410,522044954534120386 +cbb792c5-0bb8-c167-da84-86999925f8cd,2798339643,510603485023200980 +ec89f956-f14d-9888-ef52-88a331723564,3112853758,12679771200410201995 +18552369-6e78-d0e4-1275-9bddbe5f3782,137912589,1969176041890670425 +70cadd52-2089-d7d1-f857-977ceb44ad51,2891363248,3201087282174774918 +da9a1c87-3179-6acc-7e19-c689c01c97aa,2618905586,7598527713632684133 +7596e66d-0654-ca4e-4b12-94ec6a44ae17,3296884174,10451050244510913822 +e39f24e7-ec19-094d-9ee8-29a18a233ca2,980414283,9827871731900419714 +73f8835f-6d42-2a13-4be3-8903e34a4107,2925937838,16258945627342961972 +bdd27ae8-6b54-22dd-1604-bd889a6747de,684690578,6974608895526619811 +1b6d5ba2-c5f5-5bf8-e1d6-d21c926b2519,1856336905,16271059109329273464 +1795528d-e31d-77f7-8619-c307a5ed2a36,3262637017,5600455642021126491 +48dd6f48-37e2-965f-6609-c244f3ac8b6e,3879491695,14061079269536970123 +af9ee2c0-e271-9123-1062-7401a838aec2,2926119047,13975915230578567418 +f248752d-025f-1b4b-6f58-cd5e3d0ea4ba,1117646542,1719813106966567722 +d26aa213-7829-4b5b-c3a3-5bc9fba5b088,1920768912,8955489524307522051 +6f497a8a-65c4-98e0-ea21-a8820d990e48,2712066982,3852104464648898351 +06270646-afb9-bbb8-0f7f-688002122a0a,1453114860,1365138860121689838 +018f1533-aec3-865c-2f35-7438e6415225,1648321252,208291872237606512 +f873e65e-930d-ad4d-5379-6ed0b75277e6,281488993,6042101401633158082 +29c58d3b-86e4-84ab-a590-0a4837304a59,626747305,13149490102441492993 +ae1b2436-76b2-8abe-1fa8-e7443345a5a3,2843272390,4939596825361400790 +bda6e1dd-ede5-084a-790d-06fac017a7aa,1500073115,728862937819754423 +a64b2eaa-e5f6-f9a6-6c4c-2c068af4c72d,327265583,1246588290582278745 +85ac6201-f24f-7f9b-6bec-093bb18d281a,2719440571,12522329184960256907 +9777723a-08e2-9edf-7ce9-3b806fac76bc,2593079028,11244108801292320493 +4d6dfa5a-ad1d-b3f9-ec56-e0cc01fe77ce,2279751470,1846800331399395096 +c5a6130d-3680-3972-f84c-086e1248180e,1050967099,13625399764612230564 +3fd54412-df02-3b4d-dd02-a80ae1a41803,2844808498,8981811504087766249 +369bfd43-5cc7-db40-4758-f35e5d7a772b,1162638585,6794452243594838016 +c19b52f1-83a2-5739-23f8-8bf67b8f31cb,2884814509,11315855357654731632 +2e12cdd9-ba20-4179-f277-2beb7fb0a55a,1515874666,17965452909469885563 +5db42ee1-0df9-aab2-db7d-77de9b0c0ae7,548470744,4218223188432428873 +b9b8cbbd-e677-fed3-9869-1c46e76c3b1f,1302773039,3789512891671707099 +468be492-b70d-c6db-34a4-8eb7463dd5d6,2444452985,14959838390905492579 +8da67862-156f-cfae-6122-26f63bc97895,417670648,17424732800818167187 +443d8bd1-e1b3-b766-7bee-c03391cabf52,3192552806,1886593660219796704 +845dba9b-2ba8-c631-b9ef-8855721ad5ac,1070132567,5363400325890486747 +31789f1e-674f-bfea-0470-65aa4f019509,2603483781,7796965899042898325 +3e09a388-44c3-a5ef-9c46-e551ff1e31aa,216523042,4059876673381567404 +ad4bcf1d-14bd-dd17-cf5f-c707a1ab3695,1139272775,8748215523433067141 +511148bb-affd-2f06-f12f-30812933a42b,886016061,17652580849762844393 +933fd401-033f-a208-9ec1-4a3a8d0d18af,4091511222,7289234495245957981 +22ef7928-3304-137e-5d95-f191b6cdc2ba,2852255963,3001027170413449106 +7460283d-d179-1ff3-612f-6a4c5ebfa7d0,3919732936,9163211259562518060 +dd5c0f7f-4395-6625-d476-06a71487389e,4144863219,8073293150133438441 +9deb4d93-eec3-dd88-e966-9cca5f0fa94a,2638480260,3534672104743390146 +019ceef8-0297-8a08-dfd2-4955727f5930,3698337077,6346986143144215441 +332ddc27-595e-e0e6-5be6-23f42dceb401,503481093,9231095850371299595 +c1fa9378-5a3a-9b1b-1153-5dc5e6a256c1,3835545725,3375672802041265090 +e347e84e-6f89-c1c7-faa3-586c1500944d,3974476110,717523154698047503 +7a0385cc-bd72-dc48-9157-91b6900db43b,1272133635,6766729898500655280 +acade086-1b76-6641-5bf4-2dc024b904e6,3693805918,3387832744792875901 +dc48e3b0-fc7c-ac14-df25-7765d7bf5032,3823868297,6364563008291380043 +017c2dcf-f6ec-dfd7-5e50-10b73172d056,1987212304,2681251192441328214 +408bd9ec-eba5-7909-ca86-fc97a310d84a,1760772463,12134417260580846538 +7e652fbf-f1b0-f430-ab18-bc4fbc67e056,2577651510,3332616022372850645 +720c64c4-3e32-fa36-e7fe-1b584e68ef81,3798267017,17238674026308964686 +98153b36-7040-7428-6c1a-1ca2e6abb158,2795041727,1976191072135164866 +9b3419fd-9d1f-ca7d-bfab-ea2875480914,2215024170,16811221779857124168 +1ce8eccb-e549-2b11-c634-fb781bb91114,238609262,15731315510587247726 +09eadc39-3680-9fbb-ba81-a5797a23909c,4154316391,14388893827503359828 +880331ec-50e5-a46c-5a69-af67f25c7183,2306065672,17567337241663467936 +4f14bf34-ca4a-c0f6-8fb1-9697576382d0,3976547312,14114295417602137274 +a449cfa7-7dca-116d-2e25-8a86fa2f7d79,2642115589,15492986642205345953 +cd39bf43-6983-8539-33a9-f6883da9af2c,791327949,14407101512154995233 +bf16c36b-872d-ce02-d3a3-860b9e776811,3772322959,6347360606268912448 +96311d97-b942-d5e8-fa88-ffbb5e07e989,4107664764,5536735990313999235 +5b401864-e747-f8c1-7e43-fd7b7fee693c,4141460204,3355453478964255719 +d76786e9-6956-6293-ba8d-a2a15d44e20c,3989724478,16129098207627004232 +190f2a7d-305f-7310-3bc0-91dfcbab890a,4126872892,13102259907843568962 +44ed0204-90fa-0643-c97f-d0040fd099fb,2654288009,2508567166672262786 +3fbd641e-6be4-9f12-f15d-8e617dfa4a9d,1661192427,211609670268511604 +caf41f95-092d-139f-1dcb-e15e0e031612,666355209,16675381050717445218 +476030a5-d063-a252-dac5-5a7512e64a4a,1043780023,5337666532466152265 +3de73a0f-aaa1-8019-6328-55e87236aa1f,1317999763,2209234046952068004 +f235b48b-7002-36ac-d95e-5cdf45747c0b,789565806,7023339036306000269 +e8472379-574c-f13a-d673-e93b21d7aca9,137309151,18159085788199189355 +78a7ec40-c968-b0f8-a181-8d94bb1dcbff,2702867996,16244920913025101106 +d4d34ab7-0d6b-7579-c1a7-9fc0f79d04a1,2785970913,3610597777779920258 +43666bd2-fbc7-5abf-f9dd-8884feadab88,1495037583,2799856830733023546 +6c51f24d-752e-af9c-49e4-2bee2f1e2c84,223221035,16466638136739591849 +6ce15da5-e90b-56cc-8a99-7cd06fe067dd,3732880450,15575511401370853239 +5f1e0c63-2acd-d2de-d8e4-5cb368b5388f,1835744980,13167180099844930924 +8430a30e-7cde-bf77-f244-44558adc50ef,117717360,11369967582411225671 +56a36576-faa4-4f13-6053-53646e3e076b,3454177227,13481942802748119874 +fde6c9b9-b777-7105-7ecd-c7abd6cf5773,1680408753,3486487062285298584 +eb53c5eb-0e65-3c5f-bdc3-f8c57f65e186,2821807670,5527073690146441771 +26cd3425-4e63-298f-c36b-285438e0694b,3187445400,12968711647324162178 +8a859773-be59-dd37-5e02-2107051bc0ff,1524532294,8757329493117480531 +752614f9-4bb4-f9a5-0b29-689ac52bc9fa,2232825993,3698782829106858131 +9ec9ac8d-5dad-f0c6-ab26-4abfe26a3747,3344113611,6264479684650348651 +e3eda39d-1d91-75e2-1065-70a0bed2fddc,573244908,15933132810752256128 +4d2196bd-3507-4f6c-d6d9-26c59666b3c0,2687934351,890633742010285933 +77615ca1-6fb9-e951-5e8b-cddf2ff0e54c,3576398348,6502975659104762914 +42e9c268-e392-6320-e326-97b691305b3f,825522842,17068601356359757038 +8263ac69-ae83-7e9e-cb6e-674ad6024a7c,261240956,6365383976774621720 +9b020e32-9c37-5ecd-d66e-0432726a204f,3460555071,10444545106675172538 +a429dad1-6bc7-26a8-9cd0-fdf206c91f25,3702145320,15515168082587663325 +7391b0c9-1e9b-5d55-2380-edaf454af42d,409444298,17361645319420347468 +dfb5f6b5-2b39-6679-aede-5278dc8a72c5,2856596538,7548128512860398498 +a2ea5dd6-bfa3-603c-87f0-e3245caa6309,2266819084,7912338706304133150 +a1d4e860-be1f-1303-84f4-8bd748a7ce8a,509006221,12388398693029686583 +a382e854-5c91-2136-0f00-680514493fc4,2284390106,10948238250549200545 +0d1d9db3-8a87-d653-c9b0-c1026a049d74,2310313865,9020053091297308211 +a4d4bad9-1c53-d52a-d747-e3b332b35d78,4138014369,7014946825176138215 +07cea1af-38b5-a627-f354-42064cbb6758,81327103,6661538402045947820 +01934a00-c4a8-dd10-3ecd-e80ddf28a0eb,3103215474,10072653254630657973 +f4668f33-8636-6cd4-40df-70c4b4b30236,606757062,10800811823893674653 +fc1467ed-5ddc-e5fa-afd1-5042af47795f,3160316156,7362848328226417339 +a2266980-228d-d36e-b304-88360d7667e3,3608010199,11238433029865358309 +900f2c90-83d4-8c13-db32-cdb66e433ea4,4053062056,9762167777580046215 +cd5cada6-16f3-c00b-d570-eb04a906c207,3654313951,18310815005129602184 +d33053f7-0b42-d968-6e95-8c4632e012d9,2263581889,9022143092178042785 +dd642519-103b-b39d-aeb1-607bf7d02f18,706752842,11996344289315814609 +62188454-3cb8-dd65-2281-214c370271e4,1799230962,8291757153978231100 +ed66807c-2527-c477-02b2-d0a6a5deb9e2,908869221,9931781375033378765 +f00e57d7-64f2-2466-a089-889c4cec7c00,3134054634,16997746702604744484 +2c753b50-e831-08e4-dd72-fe2de979ca99,238713446,7850187609404482896 +9b08ff37-355d-5469-3759-c19da651afcd,2182878559,5714643146062243379 +4456cbeb-23eb-f0cb-ddad-0ad86866f7b2,4093017101,6873058906676463383 +d7058ba5-4730-00f4-c0bf-88941dd6f6c8,1357585346,14555357828522110297 +2b11096d-c9ac-67c8-72e4-a0bee816ec92,4095849009,12715050167001155077 +b4d25544-7271-38b3-e14b-dd0885a595bc,932217346,14074319590934021256 +187766de-2758-7caf-c528-74c2e92b4604,1619597366,15764247941021205681 +b6f41b19-67ed-25a7-935a-de1a3c7b1c40,1515041433,1921503078259070527 +81a47fd2-5a4b-4c60-c09f-90316c4a6a46,4226913677,14133594206603452501 +8c93f783-34cc-418f-70bf-2348a3894d74,3109933541,1505566779788102692 +de2be234-0a43-ccab-a5f1-73d670d20f26,207408244,15140714870398116453 +00b04d5c-4cc2-4f77-a874-7fcd477991c6,1718739027,14388956631169183976 +7a847b77-85e7-378f-9477-e0dc1c7ecb21,3197330467,18177714934380401120 +f126d33b-c5bb-5a65-d91f-5a71897ab3b0,1390380700,3668384330653632207 +05a5cd5d-3f70-742e-0e06-b43ab9124c78,3142806887,5461179161826303307 +c2f36527-972b-bfe5-ed0e-d52ffa3262bf,3267416786,16029506713511296214 +4de2caad-dc55-fc85-b2fe-a5c91334ba1f,539976099,2185643907278616338 +ec470985-8023-c799-ee30-4714c28d4109,1311441664,8827940504921444720 +2c1d9e42-ccd4-a8eb-97e0-4a947bf93f68,2889284507,3304609670358973291 +cb149035-5f89-3972-0bb5-b9bdaed8a446,3004487602,13969930310026579022 +1e38ed6c-aaac-91cb-f7e3-0ff61067238a,175593947,9535734730407474774 +44c35601-a3e4-f2e1-921f-b2b040b585fc,3779150225,17651441681766377037 +f0c5d591-7915-33e1-c94d-7c5a15700d7c,341439646,17107280064636979221 +a481b3de-3be1-8d8a-8be5-2557fe5749f4,3580479330,4919609136445118591 +a998fd87-b66f-a51d-2411-ae1e919e7d8f,3170399167,12378955433350447982 +7a680ed6-af80-4799-4ab2-bd4589281814,2617377954,6898480774876701205 +8d492d7b-7b0f-fb2a-0ea6-d17fa9d5819c,342657115,5664947935796234934 +7d00e2d6-eb65-24c8-8f70-d9b7eabec169,1210315166,8327137274736195210 +88ceac63-c6af-c04b-9a33-f6bb5fd4e86f,436531561,7569563634393733718 +c78db4b3-3c9f-2946-f251-f21104d9032f,3611302985,6289218558472970903 +0b9c0b41-5176-8ac3-3aa9-4023db30fbf3,1315280586,6116820604566461385 +4281ba04-d1b4-d374-9730-84c176cbc498,4173741520,18417010670147902145 +9aff55c6-24fc-26f1-ffa3-f081e8182b13,1927311485,9014477899896563187 +8dccfd95-d9aa-fe60-ed28-e08f1217bd3f,1459362969,10997454165672817501 +14362c3d-baa4-1201-8b6f-514eaceb59f3,1976230313,8715725017126099108 +addbb3c4-8391-8892-dcd0-8b94756a06c2,4045656713,1714618865410551502 +6d67eee3-eb25-3319-24f2-9c90bfd4bdd4,3137019583,14482251762672918906 +81663252-570d-6794-bfd8-b67ec1dd895f,3713641495,3550496078051401915 +9946e606-0937-62ef-3d95-1e56483c224b,2809969454,2078011230085425478 +984b2755-e35a-90b7-b848-7743b22d41d6,1000875649,6002015000384019849 +25eec7cc-ec8f-a127-6b63-23e6f48bddd0,3367697871,668841401149061967 +6714ec4c-8e9d-2bcf-db6d-15f94ae36597,3208352422,17705127659925831444 +1b8c751d-7da6-285e-5424-a5d45e40bbfb,857239131,15812804258223431153 +6d694213-9d04-3aad-e0ee-6a777495c895,1439624400,15717708325047198650 +2410a75f-d2d2-91df-eb70-cf8c126b68a5,2663365806,1487526138061286326 +198f132c-2368-a9b0-a22e-60b43dd2bcd9,1292422175,4424299899234945001 +49d34ce7-2fa5-1c5a-4884-10bd341e3201,3530835305,9419009535339892871 +a4e47f72-299e-4ce1-c971-11805ceb5daa,2824233386,3265644464308853760 +c7281281-116e-091b-a936-5aea1966bbd6,638475635,14019054422774230347 +ca02f92f-cc78-6b88-fba3-15e47a783530,4247075801,15346358610086193839 +78155933-2eb0-57f9-7a31-1cdec18ae43e,3369085899,6741433931618477412 +338f634a-b4d1-94ca-d4be-5d168590caa6,2346216374,4578954480540493852 +38cfcb19-12e2-f677-9561-d7aff0121416,160097285,5445737863421135755 +b092f52e-18df-d618-00b2-d8bd9dfe87fc,1288255477,5901168629695458994 +73378385-c4f6-c5d5-5751-e90905bd43c7,875436243,9863335071498050383 +417af79c-d728-0902-0b4e-b4e892238f4c,1173753113,2066881959158620430 +880db50e-6fa5-16f5-7556-991186892814,2942617556,17527002514148533019 +9842e495-a2da-0e88-f7c9-797c6abb15fd,2306442635,3884737667751856064 +34cce1a7-5d0d-4edb-da2c-e7864922005b,35482644,6627536081875956594 +12de6995-4fa8-4d31-9645-929cda228b07,685024437,17229649358876501401 +680c5bbf-ed71-7c7b-a06a-baf7a99227b4,214434349,12655020296629633555 +47c3b577-4b94-ce0b-e6cd-e7f2a0a21f1f,685362074,2171395186595634207 +fa0c58b6-1d23-979b-4b91-ab8388cc5583,1239265757,15786245230530825895 +b4b13846-12e0-52e6-c5af-5ead0f2bfd68,3962284966,12613103628724382218 +28965c09-cb7a-3f62-4132-108d9b5dfee7,1185510728,7478852599318647023 +61f22023-6c4c-d32c-1024-07975f34ba78,1530938504,15308295134210129145 +05f4f366-e8a1-125f-ae0b-b126f377ff9a,2034427732,2813879305002372659 +2f925a57-74f6-0bec-d910-2e7c522c32a7,1137074070,9220965785585027467 +ae445cce-3380-20f9-6b4b-45ab1cd05aec,1711123347,4166870366533240482 +63847a17-55ef-3772-f545-cf65d1793033,3532711950,9331939466270917570 +06afb0c2-c313-1628-1700-20901f4cb8f9,2866080629,4488455626952316726 +0ee08033-d590-0666-1e2c-92607663ca3f,2391830498,17013557871696337206 +687ce50b-074d-1c96-05b1-450e6341613f,3115097713,13031996425709214584 +ce8fc3ed-06fd-6b3f-d97e-18c4a45ded42,3989291408,3866310837633078633 +f79cd2f2-07df-33ad-37fe-bfc883c28c64,4053281394,17745840291709330261 +9af665a0-0090-8c2c-0247-af32dfa9fac6,2175721499,3440464917684769995 +df1faea0-06f1-5da5-4959-5a913bb94b0c,3872133476,17065461805153976555 +b163725c-a5c9-970b-6e29-eb00a65be27d,992320941,10626185913943839840 +cd3621af-a4d1-26a7-967e-74d79c860fb8,3767140770,3396407876976900238 +49f98550-71e7-a0c4-8808-26f0eb3729f0,4196946983,16436667613982947287 +908c7839-b06b-4ae0-c1e4-e1127facde7d,322440504,2038780540823423729 +76ecae0a-f915-5d8e-9f53-1df332d882af,1773979716,1924961608317425604 +bbc619df-4e48-3365-3ebb-2eab67f62ace,2846343051,2600404595341662505 +6b995065-a669-65a4-01f0-1ec529ec6067,807829525,9932474657375510757 +21b5f18f-aab0-2aa5-dbf2-068cf33b2d34,2685252035,9091789925926517632 +b439ebbf-b03a-393f-53fa-971ea1ff4c10,1817692669,13841014523935667350 +916e3998-2577-1cd9-ec37-c671b14f2c3a,3814744188,11116635033828130533 +c6263780-b49e-bcb9-796a-118cbc0b7a3e,3259618058,8442648514533661857 +910e9cb3-637b-b84d-fd2f-e4c029d83143,309019199,17440141150469589536 +079c4f48-f986-e6d5-5d71-bae0f4633637,3244707364,17381996405934143902 +26e27449-aedc-5d0c-5021-ef45b6ffe78e,2407382332,15498760246315926308 +f8c3f652-a489-532c-a78e-cc62cfed2a0d,592535212,6011205942082945436 +930279f3-8585-12f0-079b-65689afb1906,52089778,6807491831740339492 +c33e17b5-76af-1467-8b42-ed98d64d6dd5,462805792,5325473794377896117 +ae45a901-213d-73ec-442c-e9dec3dd8c01,3525807516,8824497594256284493 +c14baec2-1a5b-4157-b63b-2c4af19b601b,3663035716,13269075636559524338 +2cd0b901-79e7-c356-fbae-7877c909a643,1396674866,3926533485811156612 +dd0f6f4a-b838-a04a-8ed9-ac032d191a3d,502578764,15202643941952295720 +3082ee18-9260-4286-b635-b703c63ad42a,3744333899,8456985014368593274 +4ee5ef1a-13d1-74ca-87ed-0dbe238e10cd,1632896971,3274254686274794995 +098aa39e-41bc-9987-0d2b-aa38ea064b0f,566531268,6298761586365903483 +71ee3ed4-7aa7-d5ee-2d1b-9875fb323fec,1164211659,527874733332077195 +bfeae4a3-b103-0ea7-6877-799af62bbe3c,3600306787,9265643208465683495 +f59606d1-6dad-7c54-64f4-243bb48978f2,1150785509,12558884826479375319 +7c2ba3bf-4408-43d0-4e23-195b375b073d,343475971,4585594246448916160 +6c6049b5-d783-3f0d-5ac3-9d8d1909163e,3655205920,9848848637389579295 +2cb36549-dcdb-3dbe-9229-f9876d50f5c8,3208911966,9525575334371614714 +6a97bd97-3f8e-cda5-f525-925a4f9ab81a,3866671998,15142600204059914519 +e4002743-593d-c394-a3f1-010ec9e34e3f,4243504783,12831186551338893289 +6626b058-4a24-4ba0-7adc-8ca7d8a1d0d2,2970387196,8225442259046612434 +eb308909-4ea5-88ed-fa17-2ee70bdea1bf,1652099165,9602931364957167868 +b673859a-b097-f84b-7a20-87c1b88479b6,2870702751,17696224428216587024 +212c9ec9-5142-8d44-5b63-0af462968190,3123669381,13907088062362137944 +6f7014fa-b05e-563e-71ba-9c34f2cff1cd,1894272551,5113494720940663138 +05492a31-a661-1821-60f0-4c9fa84e3825,3162154345,10728674908455162539 +90a6c58f-3680-1b9b-32a7-aebbf5da5e00,4042651846,810142759726376869 +f7d48651-4b75-0d6f-d80a-bab4b3e4ba8d,1422507644,4444289758788740262 +005188e1-a1d1-707d-90df-44756a01acdb,2968227173,6972996801100196328 +209358f7-e968-12db-56ba-2609da649363,2184836713,12139436370180292942 +afb87660-9479-0d8f-5e04-5eca37e66a75,4158602170,5423356714792169150 +dd995b98-0b99-843a-6650-786064e3b185,71564355,15591449647340503480 +0abe2961-23c2-0849-046a-6df99455429f,2821686732,13342912352697107893 +7d89b9d6-cfaa-8a56-e537-e11895cbcc97,342162686,7926794207743896390 +6b5d36ee-d215-4bbc-c589-46acddfb84a1,3361649813,6880345546262965940 +b5e93cfa-b67c-5256-2df6-c7db764809f7,229763953,14316605058536215889 +4ca9f171-0991-20a2-249a-e82f7d49063f,1389178931,14211632024553101640 +b60b0184-f5b7-0acd-12ab-9a0695671277,2167822856,9257712212446350479 +eae86c75-24c9-5f37-b020-cb9cd3d33dfc,2165066767,17143606971777177706 +a3c610f5-2c54-a516-92d8-f81c7355da6e,1907774778,10411805621803723370 +9c6306d1-a978-0918-fd62-e39162d44b08,2196136727,9480800268546712532 +74ccef9c-1ed8-c61c-ee35-2adf73869a5c,3810561382,18160109141091956324 +0ca08472-cda6-476d-57a5-6d6672e35710,1069373056,2871402142739623837 +b467fcb9-9e21-ca0e-da25-05fff17a34f0,4073911664,13975475910055812085 +97ecf0a1-80a0-658e-3c97-a4170988f009,1345364230,4982784354780347837 +59606e8f-4c65-8134-7df7-ac779eb95367,1109966975,6084416427332595425 +c0c1f2b1-600a-342c-e648-83414069e4cb,1908336010,14495419196942259235 +9ba6ece9-5a42-e630-e685-566e187fa892,3122244448,1848646216952192657 +47f91792-5a2f-0f79-3a7c-fb6140034fb1,72101486,7822638078548539997 +bf2fb8d2-c792-4308-448d-7a08b9e79a5d,2354449769,13982693763456437522 +3aee70db-00b6-d904-d545-7463996440ea,1672801981,10857413657025301265 +4e634c78-8bc4-277e-ca9e-261ae40de8a4,2259390796,12495105232022113324 +f55ff794-6570-5d5d-baec-5e9b69c665e6,4041015300,1014413498939230254 +6d521413-c419-f5e9-98b5-0ddf24974920,2227543615,9964097057255024558 +2c98ec3d-404d-2691-8966-e78c16cc3ec4,2656887750,6874952506881710296 +16e268e4-b6cd-9f57-00e1-4a3a2a02bab5,872652151,12633161437783858865 +993d2124-1a9c-2790-3278-54536555f274,1165786328,16303648499695824561 +58442654-12dc-8d57-937e-3cd218f52f3e,3031739070,6530410593934149689 +e99fc8b3-2654-0b63-eb6a-56b6fdab2da4,1544009222,2014909510979795970 +277c4e38-469e-d01e-f746-53b06ca750a5,3785827766,11555499574522140912 +499b3c0b-5374-1335-6a6c-0da1a1134dcd,107937575,16452775797764240905 +256c560c-35f4-7f24-de53-4c0f21da698d,809706824,12239560067070268596 +6d9ae067-6f64-f82e-72ef-546166a03e86,20310959,13425457696765853655 +577cce5f-9d68-1439-7c0c-576212e9358c,4005386402,620284251110928379 +e24e3915-e020-3bd2-a32c-7b46d56a4b54,391482449,11327196425265401120 +843cdc67-b3e4-eafb-6bb9-d6ffc666b19c,3694826678,15017143447569424730 +2a602618-da8d-7ce3-ead4-cf4b062de1e4,2221592309,2620146761746058370 +d79f52e0-afee-6382-3a9b-41325c15b3a4,129539186,4464988786533960498 +255b91a3-c223-26df-3bc4-6fe0ce5af720,3184713486,16131883340612434107 +dfa6ac7d-6baa-eaa3-c3de-88769f16cce5,2102900228,14813465524077300994 +49abb1a4-d1d2-677b-1268-59f3e290c054,4094042092,17627049264546790621 +d3627f6e-27a0-f647-3968-378af72cafec,802822522,1209217971557619544 +b04a6f09-ecbe-828b-74ad-694295f63396,816514977,6291801542859298646 +9018ec32-bb00-63f5-bcd2-f8aef819dee4,2085167954,4536826087160532795 +76b941bc-5199-2f11-3562-0021943d849f,2817746183,13660638614769632984 +5a502ec3-7bdc-30d1-e28e-6e3b7898e200,876172069,485545074326914984 +ea82e93a-087b-906e-3fb6-74d4e980abfb,4038376697,6638230193333866472 +3c366577-c079-abe2-b3d2-9ba8b4f5d82f,3117118032,9397043914641040954 +a8fa9bcb-1730-6c47-22c0-8a2d89a664a0,3011114562,6309260670441818831 +4acbb81c-7ad8-131a-5614-59d52c2cf91e,2670437786,10396809891702287664 +f4a08359-42cb-91c3-9e0d-80dd82965618,2993209539,9840766886001542688 +0245e19c-d088-cc13-e8e2-7a3d264a2e94,737600060,18323926703569556239 +e525ef29-b443-e2d0-9992-1019b8bf8e41,2919393148,11806978850103672400 +49d18986-af93-4aff-ae1e-073aee7cba83,2506567930,2646181604809590813 +6645a949-56dd-4e46-b577-42d33c8823a6,1777066746,16873592068656234593 +64a40560-bfc3-e3a7-50db-a3c39cf6c30b,2378654284,71459500169794438 +72bed3c9-d8a7-dc8c-2f08-fdb501e94894,112050909,12138460593780200271 +97c3a500-e0c4-c24a-5aa6-0e1d42505988,2185743530,5017444936110409663 +e8c62196-feea-0935-399b-2f128816d770,1252663023,9968564238497565441 +df2cb19e-73d5-d3ca-10d9-56949371276d,228829721,12668306255061467950 +beeddc65-6254-ad69-7bbf-764d15e9b841,1927153157,5824436826563733689 +32c60073-1aa9-e359-3e93-9f90c23aeba7,2299814377,13583451679414633561 +55049130-ee60-f4da-fefd-be2900605d9b,1406326403,412995768625655084 +f038e1c0-c131-928b-e82d-7ac60f623b27,913245406,17684338511237104360 +be191f31-bd29-dbcb-3f1c-9d749842800b,2562768237,18327233669670425177 +670531ff-5ce0-56ca-8a8e-834935028612,826968439,10566515936683299550 +6e0773b2-388e-66a9-94a8-516fc3b8776d,2640166771,5529255540465358919 +00685bee-8e11-9f89-5059-f4c601a8b8db,1448526705,14111005538049050804 +7f99374a-b4e0-9230-fc2c-2a40692af2f2,880947795,5305125988215390433 +59e50ccc-3b63-e9b8-fe7e-7e671ad05723,50221086,8928422397615598253 +1c8f39b2-f57c-8dbb-d935-f7cdc1206bc8,3639169686,4994858049764023741 +a0eaafb7-7b59-828c-eb69-76a7026f830c,2514338113,3815092592659507515 +f3561422-e57d-b468-0750-c8802c49cdc5,3917250325,3440134893020180617 +0f7dc9d5-634d-587a-be50-ebddb96c28df,291442512,2650783492068126477 +1aa61cf6-1a41-3e3d-88f6-fab7b94c6266,2335306427,3932579897675625 +9541904b-b53e-2763-e85c-7f2665142a7e,3608896407,338257872109636384 +abef3483-977c-5569-9363-2a181adbe6ea,1317527951,9222305216742285013 +b9109f28-84c4-a147-b04f-013124c67cdd,330696490,9415732981607461212 +f2e3fe45-e9af-ab4b-7a72-f04ef85e2f3c,1113130519,15785986300915153633 +42b6bfb4-64fa-eb59-336b-d8cffca641f5,1554066278,5339090436038317284 +b0c82365-2773-2e79-2687-ddea34332b21,507070858,18126639162463391459 +2a6527af-1edf-009a-aa7c-fb2c3b9a18ca,763316477,8576285962322375399 +ff8c3889-c519-e272-174e-6f7831cd08af,2938259577,17104605209992281863 +fce0f22e-4b04-bd13-6750-a44e0786840a,3330377828,13820885368225350589 +c23ddd38-7009-8996-6f80-f4b71c0cf179,3648011591,17781644212951765218 +b9b72d30-9784-6a42-725e-8764d0fa4f4b,1978114702,12618370121554338674 +0575b62b-2072-6b4c-8454-231a6729c5c8,1908650793,10191884418329526201 +9351879f-070b-4200-9874-427dfa8f69e0,4058781008,11305300374658059428 +69657583-54a0-ca36-ecaf-9142a7ef02a2,2710604997,18027679255515195972 +7ede2918-674e-b07e-9b59-7ec7384ca8ec,2366509757,10065433815729335225 +8cc7c615-c104-919c-5e26-dbaba25f5aac,465566108,2604080744418810032 +d3343840-cfdd-2aed-5130-440104fb5f98,3016064490,8677983247274326532 +fe5a82a1-b514-ec36-2867-fd4c72f1e9ab,395484533,2014659297119638286 +989090df-d2a1-f185-6d31-bd06a7771c84,2806481920,5526458470686816407 +5fae0b87-ced5-102f-1a80-8ad9f4fa6783,3858744514,17139528934003266148 +cd4ab346-32cd-8bbb-4621-aecfeb9be186,671183120,10441844607957248356 +d775588e-59c9-9cff-056d-bce1d95b071a,2039425535,4163400725519742424 +783705ad-c8bd-eeac-8a53-56e0c2251937,3905621770,13432095399609988137 +c10d0c3d-75ef-dc62-6983-f5b42dbf5350,315496227,7066141508980964411 +3c811855-e9ef-516e-303c-aee783cdae6b,3615108706,5817944648308515538 +cc2450af-4819-8a72-14aa-4d3d7b1569a5,1677684969,13116613702929820232 +0594b391-181d-cd89-7800-092cb20214ec,441131406,17466093575922789923 +9bdf4378-ce47-d8d0-3238-03b9a5596835,2451020882,10978373766447334998 +27d6233a-8497-e4ad-986f-6142a8fc58fe,4153912507,4438813867223617649 +eb50c61c-164d-cdd6-2a71-5e38a12ae613,45296972,8996450494148750691 +de1aee67-519c-1410-ab59-5b902b45479d,3235406096,1497593197460448720 +0aa8ba36-cfb2-3d97-e8ad-cbb5451e0a26,4281273695,8055057895754747185 +8f54ed83-f965-3064-cf0b-ce1fdb87b6f0,1208877385,9476386506616989254 +28e25822-9ee0-2cc1-3caf-691eaf3c3928,3590432554,10093556970165090239 +15f45dcb-1795-2824-f513-04cc5dd25072,3300694571,6205740015015445969 +580b120c-19dd-5e30-fe14-a72a04c2d9d6,362525362,9262248029382684790 +ea638c44-d2d5-f666-6637-1843e30d9557,1409313112,13702532528678625379 +49f9f7bb-4357-f30e-719b-1dc0abfd1010,3426396285,9287113720950438062 +6ddce07f-d161-92fc-38be-2c4919f7bdae,3709909325,5388149057073086381 +ee48254f-3635-5de7-56d7-a8063224a52f,2220555456,12262930699794613149 +2868a8d3-10ba-6ec5-597f-858e6bb74434,888382745,17005330675678884208 +cb51a019-7f18-5b92-d4be-8b764cee34b0,230902817,4234091354852517510 +56286d23-d1e3-c5aa-9d05-49b56b5de3c6,2853092757,13422300946352051514 +453c61d5-1ef1-9a14-4f79-dde67fcc88aa,3444785185,10867771232019823389 +904d44b1-988e-bab2-4483-b19147c4edaa,4155513040,14332724571069884969 +d7def96c-bbe9-5bc3-47e7-5bc1d35a7099,1333364368,16818267026494788928 +b686de84-96d1-e351-2cbd-b367a0064dc0,1007878610,16920773638792963198 +c2347ea0-e83e-ed07-8623-2d7e3181f438,69918147,13975465860855287967 +13f6ef64-1f4a-1b14-06fc-0d9c0de0b343,1528084876,2910757367131736945 +703b0371-e877-dfdc-fd52-53df9e8273be,3346719589,1852152632351716172 +8e28f9af-ca94-786e-c536-b3106f83fc60,4217755443,2105246026351715978 +97f08217-776f-a4b6-27b5-f031b70a4f2d,1043248692,1299803272403419880 +2d8bcc94-ab20-5ff6-906e-5e29cb95da87,2493795743,18179509326786104123 +78ea3941-b030-4ffb-cf51-7a8da1fb18ed,1271696759,9780749784246049210 +f374a96c-a0e3-af1d-1f65-3f7c22c31548,1750393877,9235275246668340710 +7c8d3e5d-bc9e-8b15-3448-6de19914b3ee,1363813024,9760997969939887949 +92818359-1ee5-18c0-c371-aaa2d9c564b5,1118111075,17957601197383392783 +f6b0c000-0892-2adb-aff9-4af46b66b80b,3984324163,6485932622517129684 +3e3e2db1-e97c-5266-8046-f9f07132be0a,1169985952,4892530655889170532 +47883686-fa40-1eab-2193-38b754a23b83,1910823819,12839253040549572036 +944cece6-7a21-368a-74d8-fb651c67805a,3435201945,507453859261454732 +1bf4164f-db8f-e12e-995a-38b7b54a635b,136396740,1015876883643831770 +93d5e2a8-e95b-488b-8007-0cfb7f4f10a5,471451839,14955476975742888978 +a06ea51a-3b2d-ad59-c6b4-330e65af8303,1010412381,219373823328957821 +462d7c3a-b5c3-c685-b4d2-b93ec0e9d37a,1220393695,17439176180989365670 +46b9098a-5240-1bc7-6b43-7d22e09766bc,3054922094,15896308686014428829 +f54c338e-a534-0516-8277-adf705fb2087,646278864,16885144688938350336 +06e608ed-e685-adca-3b3c-eca2dcc7198b,3183302911,12572569840653250974 +340bffe7-8ee1-29c0-8459-7b125108fd22,1748266454,13675570478217805251 +8c9d137d-b95c-b877-a377-9dec7413ae5c,3034596498,12783539958768776502 +30f0885f-9845-8609-53a8-cc0572e1a789,1112901113,14375218638103833891 +0d99ffc4-2187-1183-e34d-da6e8499bbe7,2988522175,11973795633591666728 +2d5d2e66-a9bc-6892-622c-da611ff0f081,2536410850,7985699200305506868 +4ba3003c-a97f-a370-491f-9457cc8c6004,1993613393,17597352555779026703 +172d79cc-deb8-d4b8-5dd1-879f0a580df7,3380357481,6155063304681176466 +6045c1b5-5a34-5536-cf8b-ffc725b57a5f,3527537380,7008011507583793160 +0e798f57-cebd-e5b1-1ec1-7819d09241ea,552190371,11635857732953868244 +e85b9c55-43d6-b105-63f5-5c3fe38590dd,1581765789,11523019850369382877 +a7f8a9cf-dad4-92c6-dd73-0818051f91f3,689115667,13598435220691676648 +7535e81c-1d93-79ea-5da7-626c54288e43,3171336222,13367035156453272729 +5c364dd6-5325-c89a-3a48-f5903893d60e,2807275982,3317107409391401395 +cee0f8a7-0b37-47d0-3186-319084ccfc05,904314443,13291097411285481338 +719486f8-2b0a-6912-6e02-a32b43d69406,3927506392,16472435723884082358 +b99701c4-91bd-7ccd-fe90-db749a98bdfd,351372925,11024275193001084714 +17d0fec9-9212-48ba-c623-5844c73a447b,1298150681,2920328964526209807 +f059f335-fd97-2999-aa50-68b0798b4557,335024921,3470750173940750087 +cbaba429-85d5-d2eb-64d2-a00045244446,2101132354,13734535807805241005 +08fa9ede-7312-1918-6c4e-7c673c55851a,3611194239,5525519064977418341 +22da4b55-957a-d918-d36e-27abe2524794,1216660668,8777572550604125399 +aba20801-ddba-8873-6863-2f0c4a430d37,3715795324,15054429530675590485 +2943f21b-48b9-b6b9-5055-a8f8c61fb394,3035165716,9821542549367773193 +efe6e9bb-e2ff-51cf-0610-01e93fec607d,873710397,5015451686520306540 +7a3218ff-60b3-3d68-a8c2-db04a7c51618,1921882958,9548354612934384141 +7c3c1a0f-162d-2abb-058f-f70de6885b3a,571482123,16865469961276882395 +098c0d13-2b53-96e5-0f10-f8030948c835,3451915896,1029639841142716594 +7bce9a1f-1472-cee2-5937-91da6056ada1,807689380,9675674554040486205 +2e45ca34-664d-4441-73f7-f1fb62a5096a,2379631361,9043525946375434388 +ff35b806-a61b-9f91-9b25-3ca03adba935,4165107462,13751690815886672365 +391c9170-ba91-0b2d-ec16-8db7f1e6b191,2874109978,6800117320167361051 +71fdedaf-a0f9-11c2-3126-0f8bf2fa065f,2487675387,5281577408321223564 +fc406a5d-2f26-be94-bf23-ce0c8d339f74,105353592,15007024084112360426 +cf0a1853-af21-925f-cd56-b4c0d50697c2,2029645771,5448239496081327643 +ac0fc7d3-c773-2a54-c55d-50c156ef4e32,981268628,3180040762617069860 +ff9adf96-b205-9990-5dc3-fec038b69616,3873445740,11775886672809154500 +d87e0162-fa7c-8e03-ab00-4676e06fcc65,3231758332,13886650104977485710 +14dd4c4c-a689-136b-59c7-06efadb09016,524181194,14867326225767451213 +2e02c715-c629-8b6e-f8aa-a138b85a30aa,264733244,17750233963963780614 +df42f078-7463-a5cd-2838-977b1a681d42,2941792668,10654738024618715070 +b9fddf03-4d43-7861-3dbb-a44a9903f5cb,897305967,1806866727355277815 +629112e4-4986-6382-fe5f-ec79c87c2f64,3285503818,14777528568652201736 +915c0396-11c5-c8ef-99bc-81db1fe79140,4091078239,18143227640120282098 +052ed015-22ee-fd8b-fbca-ac7ad54f910a,3929401801,7005001378582359852 +ed8089a1-78fa-781b-e47e-3f43ae10bbd8,14333266,5030497463516779518 +a235ceb3-4653-6bf7-0609-9eb259c4276b,3859969929,12079301018678641615 +e2dccacc-b4c1-edb0-d71f-b1c6520c09fd,2515086458,4732633058237338206 +0f407dbf-5879-a392-a70b-28f836018a1b,2356351800,17562633511005659056 +90e27c82-6601-57aa-3a41-00b49a7220e2,1225467902,9799588085825711171 +df35e7f6-c0ac-f497-b77f-687138cce167,2485160648,16544752407953661642 +9f094b06-2e4c-f12c-e296-53f7bbdbab4d,2042298590,6671075500519606982 +aa103b56-97e4-dfcc-40dc-ad64c5b30a8e,4069170192,2826607138816115524 +3a03fff0-70f7-e79a-c726-d7f4274a76ca,4226979590,17661209019336716265 +46ef8aa6-5085-63f0-cf9f-baae0e7788bd,212597413,5683744569707520013 +5ab25e6c-6251-70f9-7141-52579c6df978,2891693241,6851198599442350694 +b7cc4c49-c29c-2cd7-74cb-ffdde0a7929c,853146,2600150917173301712 +452f3540-2b61-1db7-2e9b-f4efaeced521,2898901353,1949127518588523595 +518f1c94-c066-4636-953f-9ffccd7eecbb,541754885,11517169129179668461 +577b243e-9555-9c3a-70d8-02e0a99cc661,2302461002,12360012632774311402 +baa49c10-f6ac-8ae0-a0e6-305dae8f8ab9,3035648770,13632893994055632912 +37c562d5-9f1f-1cc7-32fd-ad658b7a7a04,1384731886,5212583308630781669 +6479069a-31e5-f986-c8b1-ca4d195f23f6,4278966709,5627785718207240850 +1869e91f-b5e0-adce-f52e-21f154cf281a,1882076775,6966178983685336167 +62c4db2f-be3e-855a-8b91-94f20e6c6049,1637359248,14897450964164579532 +75ab2a1d-62ba-00a2-0d8b-172f5ab6160b,2420484466,7650281882495446941 +9ecd18d2-cc33-b913-8449-a964f380594c,3582120223,1235991600278404879 +885195cd-1f8a-c977-7db8-c4f86b8f2fba,2810929881,6999779426502065249 +ed2337a2-e2f1-db10-f8a1-97e8f30b290d,3851823029,15388574796283971859 +0a504578-3d47-8116-f318-acc5db3f7533,4251999729,18205005850789420360 +a752523d-5966-0e57-61a5-953b09a5714e,1137379591,12742306289039317426 +e9c1470d-d6a4-99a2-d4d0-658abd311cbb,3972620910,14455926069418560669 +35c22851-b7bc-8207-9b5d-f0e339ab8782,1909453205,15431334687956466126 +f89c794f-ef01-e8cb-03e9-e1a3ddfa7e3e,2504823047,16604312681887283733 +cfa70e2c-aa46-7842-8f75-ce7e123dbb44,546155688,17829069730455484399 +120c6df1-ccbc-dc24-e938-6bc0fc3e1bf3,1265397380,13359772750044190309 +a0de70a5-3e16-96dc-a71a-a3adf4968a35,3759324721,16196398922620658894 +43a3aba6-fbcf-63a6-f5b4-621bf359670c,1018237376,1039897970498851722 +4ceac2e4-8d72-0102-ecbf-481f4dadf8c5,1519847273,5459772321718802846 +da514642-f448-b9fa-4ff1-0e7dcd091bff,2316176040,6367074348864267064 +2aa0481c-f7cd-2a16-3d2c-7c3bd22b4706,723362392,10050227017176527668 +fae8218c-9369-11f9-4536-d26d7ae6572e,1968368602,12624065617602358933 +adb1edea-b850-e376-1775-9880734eb55c,3205551042,17614999840605266795 +dd08c8c6-19a2-cf8d-c90e-57e9fbd78eeb,1118916999,14494438296999192115 +8e266e86-e341-bf4e-6d1d-6d2a54dfb002,3209508257,5595236174657683366 +120e845e-51de-e997-afc7-07d41a2237bf,1404842331,3457643232976879941 +ee4c0e24-9b81-5caa-2558-bcda2a0452e4,1122907290,17606211489367049800 +8a568ad3-839a-b2b5-627a-8c552951fdc5,2205079939,11337931531174896947 +73def876-f752-bd7e-fee6-08cf92ea0bf9,1712104989,3511413043066970526 +02b6026c-8952-435d-1b82-5f35115d8711,384938164,14808222568672019635 +e9c09435-578b-d534-da5d-29feee985745,947587506,17801622268839362691 +ad0cc4b8-f93f-3e58-aed5-0017c6ad5625,1777745599,17489214497546075903 +f8f00049-d6d4-2083-7523-92157718f89a,104371523,2363792353822368371 +21a14ad6-0daf-afe9-788b-62d42ed7c4df,3508280099,10704130986436751193 +9599c034-0122-10a2-b579-8ec10778cdf3,3100987133,13248679016013043823 +7a5af1e5-43cc-a23f-1dfc-bac54a964627,2161562599,14860127499714926223 +537d16c0-fe73-3608-61b1-900ac390a799,1591260484,13842530203984875412 +1ef21688-efc7-984e-5dc9-e0a851c844d2,1251155960,3675156260487123287 +0ea3a7d1-f987-f4da-accc-a730212edaf8,4157351067,17178715508709798277 +4cec7909-893b-8626-cf0a-41f96ab409ea,1173240988,15314796885536588758 +e53d2bd6-7659-97b5-04fc-ce6ad23eed60,1622549987,13477023595968533971 +b987f572-f556-ad54-aa71-d7c77848e8e1,3267805809,10600720557435221599 +7502da2b-b631-cab1-341b-64290e6685ea,3613306805,12639492880706309778 +d4d84088-513d-b5d9-c0a7-dd674a287dc1,3257089013,3524054441191036426 +292e09c5-ec9b-e134-7cd4-26858e79490b,3998210386,16607139293905638957 +67c7707b-2fb4-cecc-c5a7-77c8a5980801,1742456296,10905244996672594029 +610526e9-8afd-fbe2-6784-02c48bfa0612,1331995051,8794328614409274481 +ab189b1d-8fe6-d9ce-2e0d-ec1a71828a08,1386676965,13315077167130396533 +377b0acc-c63a-d6fb-1e72-6dbd94e2fb89,2989246697,18006063127472958239 +a409f711-2e9f-274d-37a2-c20421b8227f,82245576,16367452641268370523 +2477bbd4-da78-034b-dde8-7e8974da6b42,2086958478,10719628136055447095 +5bb9fd51-1b3c-ea0e-4ce3-b60b48231aa8,1034203234,6188895882946009978 +7e78a397-1e4e-7de2-d294-567fc4a756b1,2600926916,6612693570304958794 +13a7a9fa-23c2-a1b9-d7a5-b7dbf20ed061,4085181863,81960493336484159 +1d0974fd-f8b9-35b3-282c-2f2024605a41,2920417748,747145312343632393 +50d61fc4-5ef3-cee1-b29d-59e31bd9e5fc,1210900545,12354298894882645153 +e5c55edb-6adf-5a05-375d-4c6464549af8,1407408870,15501950290346269759 +6396183d-4346-054d-b161-d946fb8e15f3,1940207291,16607021751579300258 +29d825bf-4562-fe6f-a843-757f7a166f5b,699025516,1290145143115497432 +2f17b068-536c-63da-c1a1-db018c7a9ca2,3293904181,3147045893111335233 +d90f68b4-0e5f-93bd-640c-c85ca225f9d9,556667824,6334661075620201304 +f2f1e329-5065-030c-0cf6-6f835a3f4b03,3438419640,3485829572955624060 +72ad8080-608a-476d-d80a-2f4b52e7c853,2473502153,16808278371879825056 +ea24f90c-ed05-b1b1-b897-bd0eff497a5f,3304539658,17464783977136926165 +a1a9777e-8d12-3a62-71b8-6f3eaff223cd,4186225493,6252031165800376581 +b073984b-2f3a-c93d-f9cb-4662a2f7e2b9,463056627,6805994010285790257 +73b385d1-419f-8184-6735-b07d15d559d2,2717358309,2460242560818714790 +708fa066-2431-310a-4811-bbeb4dbf0967,3374257002,10406692865684101943 +4e2fd256-af51-729d-3b19-ef76e2b15daa,1498057943,6293550953484484823 +2e58b2df-79f7-c937-9162-ca158819332b,1603202155,7058502771029880279 +564d0e1f-a6dc-fed2-4758-9a33fa77709f,1165400214,6938627602294270318 +5f4227b8-923d-f06c-2d47-e1fe83dcf49f,2170744836,6412416829423412817 +cff1aee9-1802-fdad-a4a1-8ae63a69307e,3347200996,6076244311230099295 +a90874f2-a4c7-4bc4-d681-684111d9c835,646806876,8838001239948318771 +c9b1646c-6cbc-dec9-2bdc-30ebafcd4c6b,3496271788,5247938560435379255 +0d1d6ebe-f80f-f651-563c-caec60b63859,483067536,3741792692369407052 +f1db6af2-3d86-58cc-f325-07457628b905,1621242246,6679307963450174016 +e8ff4c89-f757-95aa-11a4-217531796137,1355261208,10004077064377481799 +6d5cc4ba-c83d-16ec-3e10-17de3dca0b06,3794346344,14829617232989847163 +d0599a83-a42c-0ec2-0924-f640baee9ccc,2558326707,6830039468687304457 +efb3b442-7df1-e777-318e-17ea4981061c,2500524260,8376773997467700812 +3b9452c0-7c96-0f86-7b35-70c5546cd1ea,2933739053,5992623142782409037 +e22d88d3-b3d2-438d-b828-2c45d4526fb8,1390336993,13055414110370516627 +a68bb911-6ea0-d5d8-5606-d47451c35b98,1541326293,7259049373451775971 +e0f87dd6-d5bc-d684-5738-5864040fe79e,3903416035,9042562902628957119 +39ce00f3-ffb6-8aa4-1077-54b1486ad6a1,2188499872,18339465280545437035 +4af29cfd-3cb3-5402-1289-0e44f4ebe757,2524828738,4611358379705646831 +192e5d48-bf25-fef0-2e1a-407f5e86d073,151681883,144959780371734738 +3c22bd80-cbd9-8416-d8d9-2ee554fe8a05,1326066255,8386723836005322806 +36e7bbb6-da3c-c6f0-6ea8-0ecb265e865d,3227407245,3889811519474857841 +9df675ca-027e-09a0-2994-57dbbfb46039,4245787721,16525993244601570203 +843aeb7a-f2a6-2689-34ae-2cde5145f9a8,2981112900,806885038795987039 +511cb1a5-2eb5-f564-4bf1-d052edd61ef8,2848282054,17483354444934043732 +85564748-f1a9-afd1-f823-2b19298d3319,621313143,6516405028381492577 +421ba78f-8dc3-407c-ac7a-9c8e43e1f2f1,1256028470,10598400416968408635 +c234a022-d7d6-60b7-97d8-e02690b40f20,4201413116,3957679989206280839 +0bec0ddb-5de3-2731-0256-f0189257f768,2686555227,2301880026058083296 +d8706356-5f9c-8dd1-0b6f-299168953ef0,2395333951,11471254055441843102 +f815be50-fb10-e3f5-0f4a-8a6e26cff32a,4293190703,5402837363436633749 +9f62185e-4206-06da-eee5-a25c0b8c4b30,1226202224,13485215557563802041 +54186172-625c-102c-0a27-f908a03684ae,151668573,17801267284859802150 +9e1d5f39-12dc-d54e-6915-581979bbb8fa,1757263626,5409821660525959234 +1bb3be17-0fdd-6a9f-5b10-3faedddf48b9,374342573,17799965765300910888 +d8463e19-a1c6-1f35-b061-6e79450f8c68,3420426445,11029905119081063558 +01fc6172-128f-e208-19dd-26d0f1592449,1299662858,3574924160330210955 +cc8470a0-6068-b925-8cfd-c815da5a7525,3325519033,177212846832562825 +da7c3bb0-89e1-de97-94b6-82568422ec24,632223371,14390728500088589958 +e1476d23-7f81-8d32-edd7-3fd3fcefec71,3062200030,14456371118168913412 +be222a51-7ebb-8f6c-6230-e6facd8a7d41,4219554348,7502719822466774564 +40fc0272-8b26-7316-a4ca-81ae3db979f9,1202938900,3945788810429061765 +ed9e1c9d-19e4-1300-7014-374df56ed15f,2919314061,3568063788868806333 +df152ab1-f891-f408-2a97-b45d6cb34de5,1885271982,14964701602784157210 +9a57bfa7-23bc-b469-6d7f-5f74ad32faeb,647235243,11765238867268498109 +60c8c689-092d-d6b0-bfdf-0c37323ce898,2979421930,13790410858125863220 +bc1788a9-26a4-44dc-3053-5d7d1b4a2b58,4094677379,16958902578996035563 +034f368d-8e46-189b-cb18-984be10be4d3,738217865,9950192898041164659 +0e822d67-2e1b-ada5-fb38-ea4b171dbbe7,1515292150,10774454477101790535 +347dcd9c-0b7c-fddd-d8d2-d7ad13935a5a,2707665914,18172976785899152545 +961fd46e-3381-508f-b632-f392e1207b5c,387273707,26019596371692515 +6146c991-6381-df9d-998b-a3e387a2aedc,1886678941,11564427889081516475 +4e1038a9-e32f-9644-13fe-d427784c34ce,1735594714,10066118508728761765 +9dc94f07-1e55-6e69-4740-11b5dfec0184,2522380106,3255722108880625844 +1c2eda4f-2b53-6fbe-8c81-d67cb3b0adb2,3310262202,9837663417646724932 +0733d0ca-623c-db8c-3874-a0151aede870,807072872,2742344891529183949 +1c822267-1d6f-5265-a1fe-1ecb9e353a03,1649926686,13114864968415063406 +9d113e00-1e87-8b6b-e358-d2b510cfe8a4,3903769069,2950589578469666215 +f5d15768-5ae0-6124-5694-c31048663e5b,514648685,4559846854488709224 +7b01f905-be42-bf43-54a2-403641e38c01,11610813,12006639463539492963 +4274d4d2-105f-5400-3e7b-7c29ea1c586f,1131967581,11948800390343606933 +d8ca6454-d16b-574e-d691-51d0a540a5ab,1895763853,1954768231262129742 +1002c568-7635-fdb6-cad3-b886c015a684,3293715233,11336270757145236405 +3c1fb398-505e-c238-c596-b0430bca73ae,3868724594,6932166609189931214 +90c9f3ca-79dc-5ab1-9712-36d01d9c6212,1707386957,5576369530667255161 +53ee9f4b-b66f-a16f-a5f6-135345cec5d6,1209587149,14259239678034987690 +034754f9-dfb9-31ab-5f11-b09957e15990,244628510,10202377006602256113 +e6641d28-ca98-39f2-2418-46c7963d2a5a,1264746684,9667411479387354138 +4ae998b2-9860-48a9-9a27-ba10e072a002,3285034478,1620311719996794029 +381d0c3f-e6eb-4b34-ed46-ca4abd240812,1244709771,1772399155463665091 +9b4d9bdd-ef1a-34bb-09ee-57bc05c8482b,1958780818,14222237982771917747 +bc49d439-9c97-033b-ba3b-7441222f274e,3098818716,13763293278541678343 +5975bbd8-8b79-cc96-2437-708a945a33be,2406578733,2577680825945336129 +8e7940d0-e166-4850-4745-f12496f4f7ff,3297677540,11963859725644104649 +48c20edb-5199-1f0f-a40e-ef3a1c568b61,527038797,14980396088576012388 +92a76bf5-9187-d3cc-75cc-b587e25d7bb6,893088922,4293651532058296532 +28826002-29b0-6efc-8c64-8c19ed863af4,2865014908,10310393926765813378 +34f01f3f-3632-4314-00da-e01ca7b843d5,46789204,17556709362499141429 +ba7a7fda-412a-f6dc-a68d-a4eda6f059cc,1245740114,18423240259111323500 +67b4cb57-9486-7203-3c34-0d8bd827363d,1393561036,4176812379194869638 +9993e29a-05ab-cc68-3b5e-662ec55dff6c,3839873011,4293625373901496268 +dfadb854-3ede-3d7c-a780-74a9a60f467c,709189771,13608696878400905754 +0ee9151d-d1c8-89c5-7988-6f63091c0800,3174452833,2091244698754056268 +b75d9f2c-e50e-f6ce-a791-432ca643d779,1106724715,13404818263217289284 +b3705432-68f6-2b07-55b1-199dc76267e2,4260289614,16674196089474276865 +bc7e3a40-2ecd-6c0f-37c4-30268cfe2e15,795245284,14276906749840078090 +a80b7bc6-5223-a5c7-2471-06f417354f20,1595312634,6789592962187029062 +4e8af3ab-c363-ab13-bb93-0e6ee45ab2ec,209097507,11600871057533252890 +62b57391-072d-f331-ea3e-73dd2cdea009,323538805,1764526358144974 +37e841d4-fa78-6b0e-c3be-08641b67ea2f,2920929108,2978117888448635073 +f8a2d265-7a8c-e2c3-8de1-9c099003e890,2628049392,11568944921344968581 +1b844e6d-53a0-8d6e-31bb-ac9af3927d00,588478145,17382185429284341207 +dda25312-a5a8-2478-e870-528a7d1069fb,650900899,10701458909380379830 +46825ac1-9b5f-fc94-f23b-875c939793cb,2682006482,14493731014378109471 +8abfe306-ecce-b283-b845-ad8a93697d6e,2250356551,14602533730102743331 +579bc8b9-8847-f34a-b18d-7d26f0e25c40,1204419125,9958364144726198178 +3a582287-baed-c249-0ef4-0c148730e08e,3469855965,13297008448778590281 +679cd738-dde7-cfa5-fc1d-a7175173f594,1139027039,12036578894694757106 +038c992c-64d8-9912-bd49-236d33b2b7bb,1945383152,13407409183014719372 +20f8bd28-87b2-0371-d7e2-0984eb7ba25b,2212496170,2946042807138997803 +bf2fc870-7de6-124a-5c13-61dcfba908b2,1513779844,3474048718270085035 +97f1c21d-46b8-95ed-d78d-0397a7493356,987873179,2797800127548030072 +cd549f8c-21e8-32d0-0fce-a833e96f9af8,1880311641,18401343267843107898 +110bf55d-c048-de24-bba4-4fafb3ce36d0,4084323781,18194301982192359689 +5109db8d-af39-5d4e-2240-2d835d13ce52,3989807842,6947848726749124015 +477dd2a2-497a-f715-20ac-3eaae3b102e4,965784651,13033603291111686339 +ac4e8465-4549-95be-c786-5e91789cecd0,311957186,3695307588530009550 +8aefc12e-ff8f-11cf-7f43-bd4e6ddda51b,582655033,17875263969607924334 +ecd581e4-3206-8bab-d650-31a0b6e5211e,684327399,9233075325004814897 +103efdad-3064-9f5c-9fa2-63ec8e1a80de,1230230114,2511195435098654811 +a64868fa-a496-b5dc-2f18-fea3c9ad563e,3606344497,15129888192635725085 +ee5dcc71-2146-0493-2443-3b274ca06291,2171804279,11611885166470685308 +445c5703-4b81-9609-5f47-d7f0f94e8794,4181923362,18121942309932617915 +b77af3ec-b380-3ab5-5622-9d0582911377,1439964312,14130888676262853242 +d268e990-50cf-f84c-73bb-da8a2778593b,3438062945,2050702544470251514 +10503709-3309-d4e1-9494-a52e1628d94b,2174596120,16971107517926760171 +add896dd-bb28-1906-cb76-f5b54e5ff201,2767968584,7041372677808631295 +efe7786a-7e79-b657-fa4f-e2c5e15d17f3,125974634,14596073058866436029 +93580d58-4213-dd24-8e4f-a652260bd8e5,3695606873,11320769403694829838 +badbdd92-7f84-c083-8ef7-bebee73e4b71,382049613,17718670239310667551 +22f2f99f-6010-bdb3-0e0d-b0ed3adb9725,2879174572,2163503595880709473 +25672540-1de3-30b2-40c1-5453320eea72,1287567984,10955159910571474637 +8766496f-cb7c-7acc-db08-2cc21e7cd35d,3794245370,1577545559559967840 +75c25d53-eb76-1f7b-85b7-fdb1c4bf8317,655852952,14911642371790484233 +bfbd8490-2bf2-e710-a387-8d2c262430fa,2455656839,3623341905164307255 +4c52317a-93c2-1484-7f5f-2cab2e3ea5f9,3218898311,15307752128002215327 +90951e46-cd2d-0bf8-14ba-fecaef97292e,2115661552,12755230297582056243 +79e51edb-16df-3a9e-dd2b-46392b5548c2,3228479610,4471552603139519565 +6981daa4-c9ed-3465-8e54-9700bff105d6,4027783525,9916844204487664260 +205addad-f795-d614-3fe6-6045c024a1e1,2096831231,7475396545727048411 +7a55ccda-ca85-14ac-6949-936381539b80,273975777,7472539465251825110 +2d3d3555-6360-d3ab-6cc6-d7d5c01a5aa7,1746241584,2976492577314786372 +3e0ab801-2e8c-0ced-d1d4-252b6224142f,1309015213,3506115323411606666 +637fea71-2aad-a127-bd68-45579fb6bbe0,2325714224,15642190984823207910 +64e234e7-cc3b-afa4-fe3c-1b4e8c4e5080,4159926219,14642994282519064799 +237415b0-03c9-ec57-3bf8-18db3b300e2d,2824370943,4155165231133572009 +242edb9c-1bd2-85c1-80e9-ed52a9726258,3237176061,247712835544409186 +c03a0cb0-dcc7-0440-b4dc-382b18349e14,204195902,6817749706497327220 +9c2b88d1-0d74-f486-d528-f3688ab2d334,118108653,6932133060205036161 +a72c2dc7-963e-488b-2e1f-15ffc27579d7,2360991577,11390192838309751389 +fcf8ff04-4e1a-6ba5-f81c-d90c56845c23,2345750618,7123442890771946705 +d9ce4302-b371-d44e-74c0-5d8c49419416,2946081560,2330136029488561855 +08afac2d-7954-f4e8-50b0-46525fdeedb2,841421834,10159212834148974280 +39be6972-14b7-4e47-a796-1cbbc90d9754,1196013337,147113461399249857 +49dfd1ae-83f4-5965-74db-ed5ddc9d47bd,2547501121,9520692605697848082 +ed725a80-f596-a1ec-53a9-81c67d1d2f54,1315398363,17919772207697505479 +806e10d0-7c3f-a5c8-e21e-c9559f45864a,807043505,13715399819102948279 +53cfe53a-63c1-247c-2d75-c174325700f7,896215001,10637214173599516320 +b18adc6e-4fc3-bc42-84b3-bc51f4593239,2266021338,17975934980144805921 +3168d43c-ec04-6acc-a1b8-04c74d5f3eb7,589143381,14732696471650396232 +3f16f520-3bee-954b-9b7f-49d9fbac0e2b,864471901,2960145437855172771 +242ee4a2-3627-0d69-8bfe-93b9a3cb70a0,1433917544,2874369268938234358 +c9534e4e-068f-9979-e646-f7dfafe72449,1398907060,5448620750984917942 +60620a3b-52a1-5768-ff18-0042525d7e70,4241692817,16359353957271629535 +37c4fb02-0bae-5fcc-4260-941639726725,1512083751,14629116100190964647 +a603fd07-74ad-c612-642a-543eeb6b61d8,2012917599,9871035739066630255 +ea4cc845-7583-6783-31ca-0b5b88e99a14,1523884216,18028134309348577288 +c1f3cc65-c39d-81a2-0b3d-a64a831d1767,1175591542,3719923735507695455 +c06f61b3-478f-3752-70af-bdd42741f49f,396100938,11828400800041849297 +a76b99ee-e79f-3427-03c7-2cbb1afe3136,2458694102,15140727255582088535 +32ac6211-7ad4-32df-8f77-d96251a38c1d,2244395134,108254753865588825 +4e200a90-2d0a-71f3-00cd-358b5da76385,3310211761,2804591009387416427 +8b670b5f-57cc-4527-dc3d-aa770eaed9d8,1526289125,9818355880392596505 +1a7202c6-47b6-d0f6-7538-ec0f93f15ef6,2183711319,4942343140431755697 +30a61678-67de-0c76-e38d-a1749f691d36,616758517,14897209549883160495 +b540e954-973d-94e7-86d1-7a4db1f0ffbc,3280445267,10089945750157769755 +32ae7372-bb32-1373-3dd6-3e66c51f0d17,3771902643,17334583779702700332 +bca03fa3-300d-43c7-c656-3890a0786adf,3058945413,865108280995478589 +a2bbd5da-606b-a099-e759-bc4d28410418,3088434388,1738580098754818044 +679016a5-02ad-88b5-ed4a-4acc8db76af0,4130304862,13423061674964423877 +b9ceef68-84c1-3d9a-82a2-e20d273d6927,449283063,6336658083931552754 +9f89b69f-ae58-700a-d779-de1ec8d39dbd,3875016725,13733482014321648692 +6b3a46ba-f62c-09d2-6928-56292aa2f144,1866785127,14368680473929370055 +f1587749-6560-da98-e918-6b33e9a003a0,2307199480,16641584463426310413 +86b826e6-4673-c001-717c-6f40e1c06c6d,354491566,11631490701851414508 +4fc3fe9b-68d3-9231-8269-51e7c9584ab1,3775300916,8202429676360404632 +7bd08cdb-e3ef-b7f3-2f72-561c2de5aa37,3309991745,12937271438602345632 +919a537b-1b60-5e89-35d7-1a90951a8c55,75566845,7793107450785955554 +fbb0807e-60c7-d95a-bfee-355dd861f8de,3082257535,13969015763047895200 +5a4f4633-9196-85e9-8803-cebd665506f8,3104183261,9921822588938810677 +a16a5cfe-3b8f-3bc7-3603-b002d9d72127,2015379010,16503281620783327299 +16443eb4-f947-150b-d6f4-303f0cdaf7ab,2673635808,7468178522519870857 +00b6967b-acf4-6258-2d65-0b32d2ed6338,738057368,941432642927301400 +9ac5c4f0-7a79-913d-85f2-8bfd53c63d49,2545172580,16780950558872195436 +855b8834-3b3b-c677-1ec0-afc48a343313,3908325354,17835029126399744970 +2db9e6fc-aeb9-c653-e521-c35c202d83de,3357478652,4224319442547310083 +0e5fab58-7212-210f-b2d0-a31c3df9665e,3083277861,4403058666614723203 +4839e5de-028a-0c65-e6df-180242bb38ed,651161474,5291110531623375038 +792da6bd-1935-5d48-0ecb-62b3a38be57d,1411499289,5583267652136695669 +783ec5ef-6fa6-0444-6a58-26abfa2d5681,4012572697,6104822226219344757 +5e9a65cc-b598-0ea4-1951-69cd42254a99,387740079,202466464979965038 +8bfb6237-270c-cea0-fb35-b55324884706,3881440197,11247838072603503734 +13f962af-a504-b14a-c2fb-1ba97e41b88d,3822052726,577959065012668975 +70b936de-a93f-e324-e244-76a51260eb2c,1789209847,492605675276202178 +3f1a5321-6691-a13d-8397-0e8ce6f357b8,688074797,5184723486184448608 +caef40d0-4544-7589-6901-e1b0de68a80c,1308399137,9468732851240070916 +116ded7e-57a0-45d7-4ec3-b543e3322c92,4281041164,17723793967040519846 +bfd4cd4d-62dd-a462-fd3c-8e3386f05181,3363572572,11654205706979290123 +bc8315d2-b525-004c-7f18-1048332f6587,192949368,9226212354181564852 +fa0542f0-adad-91b5-5b9e-bdc88696516d,1680651412,867868975206224745 +253e8a18-283e-a2b8-d572-ba817d1d4995,31399630,4107416397718906762 +1e75cf9b-2016-6021-937f-97823142b34b,3390780762,11302948529988330329 +8e4ba0f6-fcbf-3b73-0782-bae56663fab3,1153056046,14246769622346938421 +889868bb-b999-bf6e-ed8f-809bbd9b8a5c,832787158,4692315962918689166 +351603fd-a988-553c-313f-944181e17400,2356264903,718238084178830865 +adfc3686-d7cb-d622-acc7-fa40c6ec9103,1545389898,15680979425010310914 +2631d802-a6b1-c369-e89d-94e6e1a8c7be,3805786951,5126728372669312218 +9889f726-5f27-be5f-1c64-08dbe6a05a26,341095677,1902647976561222909 +9a8501ae-a8c3-2c78-8e7b-bd71f5bc3f2c,2647024307,6047868772370588894 +7b22c722-d7b0-26d7-f342-42fea09ff0f8,3862060867,172839894996364442 +4f459ab8-eb94-625d-5377-5152ce30d13e,455101233,5785979561615740054 +c0042cc7-a9d9-9885-b62f-68009d4d8133,1392623322,9380222560178231267 +c05187ca-d279-5981-073d-bfcf4aa001f3,1357737443,17786442354264560476 +a2a74d74-f4ac-038a-ec6f-3c1fc7245432,2571967826,11591496187019172654 +11b80625-c76e-80c4-32ea-eae51bb1add8,4114499095,16582932870255119189 +57243193-bb3e-86b1-656f-ea7e3d4c3614,2777258648,10796948709558658400 +b81732ac-aac2-19fe-787e-ffd298cc504f,1424915126,11113403741496155237 +0b9c8d51-8eeb-2dba-68e7-ca91f95d0420,2285416455,14904149457597727249 +9bde324c-c216-d511-db1e-7209a2fbd06f,4105438806,7867784007021146994 +ef63b722-87d1-c7cf-2548-948ccb75d66a,2280756856,4034946072150900428 +4cc869ab-978c-abee-d6ef-1dd29e8ac0f7,560105071,15532298126586098909 +b4732e3f-4bc5-027f-2265-4467ab01c654,3669525377,10306855237119999078 +cc7d5204-f2b5-f88d-5164-f083592dae1c,383775120,4305172286368386131 +31d4bb96-e687-0d64-baa5-11c2f6b54a10,3635856908,4055047810231250477 +260035bc-ee9d-f046-0d04-41dd1aaf69de,3339716371,11316128304392634409 +de95d5e1-f76d-416d-1c0f-28b0397acc36,2004494460,11091367855827522231 +586ac97e-caf5-1240-aa8c-3e3128a921e5,3128996674,17035667559018221122 +7d88b37e-c2af-4f6c-f9f4-b4d0cee3eae3,1632155067,7356340303427678754 +5657f2ae-2c52-fc65-da9d-425dc37bcad9,2674978162,15762306712514795101 +4714ee58-2832-d030-db87-988f59c19be2,3824110047,3727355645944219720 +0765cbc2-bdd1-a409-e791-7aea3922619c,2020033933,18201246656393879413 +fc8c7429-f445-b343-1264-f0d6c0247102,4052513391,5908947988107456483 +e47f2030-1414-0930-d6e4-9b7c61fef1e9,4294367948,12098919801326367351 +dd818dd7-5c91-7df6-065b-306a53a12428,3387064724,7127333986729980576 +5f9814f6-8fff-fef2-ed60-9e6a3180e4f4,3020466288,793717465487048389 +ca120e8f-043f-1901-23ef-214a2c845952,134502160,8769832189134489547 +704d4a70-a78d-2b0f-6310-5570696dc1ab,1063008957,13190103223664598007 +339bc169-a011-6ae5-282b-481470b0399a,1867856682,14899352896970554672 +0f3f8d74-f125-8425-aece-ad5311db583a,3747534660,2979200398790804287 +2a5b04a3-07e3-5dc4-9123-408f1178a10d,807373796,8830596332919938394 +bfd3f2e2-b458-c074-bc81-69bc535c6c3a,1966144318,6657349165762876210 +46260ecc-db29-0bb3-1fee-03ef3d270d03,3552281496,5267344669963557686 +edf4c55f-844d-ba5c-64f6-6cf9d2f50f70,3536624962,12889236262868968962 +e235e51b-c52d-e412-32c3-2e2416f4d4b6,694865206,14131022575220572150 +236d68ea-9dc6-c67d-a514-9f27b73189ff,2904397042,165986283059980242 +5088ce14-d2bd-c42e-8c58-338619fa1af0,2958093192,8692380400596257559 +198dbd5b-3dba-8043-fcc1-8d3c29269a5e,1886650386,2031331771445024366 +6a7f96d5-aa92-ad79-2783-130ae84990ed,1548541117,15912443775781177952 +796ca30f-0f25-c29c-3aa6-0d6b35d0ffda,3503324737,7629018937489297393 +94a4f0ef-e1dd-1754-aded-2ec832d81c25,4090299481,12299579533066521305 +0b01d1c5-810a-12be-ad10-4d3adbedb76e,2842846056,4511661276547802121 +c81b685d-f386-dc7d-9328-82bdf272f659,3992943665,12878411285386471719 +737b4d47-2f5e-28ad-dae5-22ffa9e86168,242479292,14282296458648550377 +989aa12e-4832-34ce-2a6a-dd7cbee61e54,3428291976,6060496008867015048 +828d361f-49b2-8096-7afa-8422f47a8db4,1115252525,7224417684321265159 +52e18b51-ac1d-2b22-94f7-8d1c5e731b36,568177765,1830229294393085908 +a2fd5ca8-e05d-587b-6a65-ee512424b374,1658343563,18093160018384555562 +02129371-38d2-4671-d90f-2dbb13c4182b,1921216642,10642207683215127750 +e84a6d83-ebed-edc0-e676-ce58a1a631a4,640597575,2964884589189683309 +375bb201-6c35-17b5-9640-c852e8d8e8d9,265804074,15107241925013818201 +041a29bc-f061-5b7c-c5a5-a3b1d799d181,2762763280,5119166057494922197 +4993d76e-f110-69d3-1bca-0ae528bcf33e,4213558318,14449684647434717702 +24fd9f97-3012-bc20-226f-ced53e2ac921,3457924257,16046278349631564770 +f2ad874b-83e6-700f-1d1b-10e69030d647,1230940099,5454209681371957588 +7027964a-a340-ff96-2ccb-a9deb12b7229,4079336997,12390209556755555043 +7189cd85-c286-2e58-0de6-7d980ad845c9,431847626,15490076178137896333 +ad21c0b8-95c0-bcdd-62be-ea4d631e8cbe,3602569361,17758242481027502881 +8b42adaf-31c3-f8f7-d5ce-4ad5eb55f128,2107917665,6824129620781085821 +53289370-ffbc-e025-0976-eb59a4230724,1326029303,12600760965673159918 +da15ec48-cdaf-8af3-7682-07cb335e0158,2888504165,7425997644831784685 +83a264f2-9a73-90f2-fc1c-71bdea491c5c,3275298061,15916493700071366491 +8c2b6cf5-3f83-03cf-df96-a233aac1b035,3345861302,18336465491789176398 +60aef869-f8e5-434e-9fa9-68c9f1331dc5,3579351161,5070757079060796771 +c3febfaa-e7dd-f905-c1a7-247d6e2967ae,151485441,4105213592642827170 +4c7fac62-66cf-8ba7-c4f0-b20c76b08f4d,1157548631,10007252514190527414 +aa64dbb4-2d52-2b84-8482-f18c8803ff90,1157320890,5831468515475634904 +e3db60c4-e0d6-09b8-0a7a-53ea99e4cd36,2207545947,14374066239717693715 +73a12d1f-085b-9aec-d7c5-60d1391a4c24,3167990227,9644307448672174921 +b227c0c5-df90-e038-67b3-00ed9a30605e,2315426784,9391725879349597362 +353f7341-ea45-d74f-2ad9-d2e4187fe9cd,2777874714,5876464835024615345 +d87adb1d-2829-1c0b-089c-10eb33ca26e6,2576276506,9650513288798439130 +0249c91c-ba20-474b-b6b7-c3694a8699c1,2126470507,13923435549294134855 +f36e6e21-1899-b299-be3f-2ba5322fc49e,2403721422,13944081086250239693 +4a0de442-81f8-ebcd-f720-6aef71803819,694226396,10822835089562780603 +59165a35-c102-c1b0-ca0c-0aa18ff44d66,404244820,12543499727597687801 +0c95ba50-f304-6755-fc7d-4e1381b111f4,2269936988,14833913475416872650 +5edf6a05-ec3d-1da2-5277-d15d9d47047e,1000192517,14677855950179070129 +6def4740-8a94-3771-54e4-f7b7ba94e562,2877486732,3039331226456898538 +2f384179-e4d1-eb33-f74d-e074459bf94c,660686795,12384088080462820712 +f6a43e12-f0b3-985d-a538-be8dbc7a0c89,2396624990,13386055115036397076 +ecc01a4e-75c3-5921-a17c-3d119a4d3575,1612806439,11326245943813160985 +e87fe836-b65a-1cd3-1a1d-a36defb84464,234130906,4721603092341094962 +d788b533-8c9a-404e-e8bd-8ef9e1c64483,4052635666,13645780913611609687 +2cc40bd1-1a36-cd41-a61b-825c4a422165,1748810122,12665472610537889401 +a694d506-bf21-235d-503f-af529f14b3a5,1137798812,7590506675382412193 +9fa5007a-7101-505c-7df3-a61fefa1f632,2203879739,9562947020689561334 +cea59d7e-ccfe-8455-ce52-cdd5024b5d7a,2525816900,11615474510854415274 +6d5b7a2d-ebf5-32de-6346-04bb491c1813,1683032133,4076855338495377631 +725336c3-9f1b-e992-e96e-792aaa2b80b8,198557715,11764709786256573051 +56ae2781-e929-a46d-4264-f0eb65c6465d,3392421013,1736560844837919718 +8cc3d56a-a2c7-f665-b6f4-d0ba3494b086,3711256636,4955678978643611850 +e93ceb00-ef0d-2f1b-63e5-52701f982558,1044325792,429408730078226445 +0450ca2e-5fb2-dffb-badf-9c520859947e,1143071533,5575715418956560810 +322dc943-c84f-bc8c-09df-8866e24c76f9,3182111974,1251366424812277363 +556e01e5-620d-c9f3-e478-832fa5b27b33,2758529535,17523784780099838414 +0f3efa94-632c-f357-71d5-18d032a7baef,1649962958,8947865487750812541 +5f641179-5c12-2d89-f6b3-3f99b04630fc,2569129283,6402737044770722451 +850ffc12-757f-d068-401d-f86f55d7494a,3264588418,10225507271314812712 +401fdda0-b954-8939-d690-58acb3675bba,647364138,16127011812234959888 +2fe998cc-3c10-3594-e3e2-54d8ba3b0373,1998579638,870121464926362167 +8137031e-1a8e-7820-936a-7323f0299b9d,80454870,17617750543915872059 +e8a31550-86ba-03a7-abc3-3e301c875e07,3459640327,11087136753398017501 +5959898e-a285-d542-a03e-c79bd287bb26,3349664035,17775513834142700109 +663648ab-476a-e17b-2ab8-8b2fe2b99044,2056671828,9843990765155814376 +f48336f6-bd8b-1514-2e2d-22adfed25aac,4159764290,15562717349039066263 +532766c8-e5eb-474a-2a21-99e586640ed0,3643496609,16588296355245688885 +67667522-072a-3719-5238-a04a30683436,871685720,13084607152426476890 +961ea65a-04a0-6f23-d536-d3536461db9c,4020052271,14896940035997212054 +fdf5e610-b38f-db11-1870-128f707a0436,509723692,4092403659078103034 +bca0a7c8-086f-9a2c-0029-eac94993cb68,3136695194,7869348257096332627 +71ff41c6-cbf0-af78-50fd-a8c308970413,924580535,10129401502118518982 +82726c7a-6c67-3049-493e-fb83f8b82492,3654024388,14293527523463752285 +9723612f-de66-1d07-f8fe-7deb742302b3,3377478374,9769347357641793060 +3da9e705-b5c3-3677-0c11-804951631371,3449665508,15962071104638035962 +bfafc52a-6721-1a4f-1478-93889d3a3666,2299796708,11916459875372767897 +dbd7da27-dd9d-f0bd-5d56-b805bbe472e6,1706067556,16337220829555324350 +008ae6f8-fd54-c615-0ecc-d8575fc85310,119096363,8169877391331111197 +f4e98c5a-4b18-05ff-1013-c7fc5ed56b81,2884440311,1711242975638514697 +e9693d3e-c5c4-44bc-3dc7-979758b1682b,1051058143,15548930903694802687 +48610b4d-1088-8456-ee47-6f85f08d9d3a,2250324310,4930373112039367005 +9fe91577-06ac-a935-760d-d4d9e9a771b9,3795201196,12570077241584422502 +a0a7f9c8-756b-20ef-2ec8-659ef87d921e,801966540,14515457828550730380 +b1845bb0-dff3-61ba-b7eb-3bcde9f5fed2,2733576035,4847152210417150294 +0f065239-d056-02ad-8e62-9588a7c05e57,3022614822,16843312831334713317 +cbd4134d-dbe3-455e-9248-24d9ba135c77,1493114798,2410828826763800701 +f1ce5732-f5bc-243c-f6eb-98204cfabd52,23688005,9931657257798821098 +e697d8d0-1da3-e42d-ad93-77f80284df3b,3346014815,7606484448763574424 +23a1ca44-c0a0-72c6-159a-c00c1ab7b674,4268680520,10341207353631104041 +5098dfe5-8f7a-b8e1-80e0-1aa667285dff,1907684550,12232632245532218265 +6a32d4a5-e41e-6f09-b46d-2be45d6cd9cf,2062345429,17616847243358998505 +5175fb9b-7fc9-0312-94e2-3ac1a15ab0c1,2440969693,16399484082186010592 +dbc261a2-e33b-8de9-e5d8-7b9b9d65e4cc,3450787747,4302808172781058389 +43de3613-78f6-f695-6fa3-12f2c1ce72ff,2379746139,13766787887832458781 +37aed6e7-f035-62bb-81ee-9c11ee0493b8,1964531331,4958422505167714344 +db752995-ded8-cd37-23b1-7ec7d1cbe5ed,2842345336,18194485762023662086 +e6c5ac87-3bbc-f5cd-4214-c4ed6efffe92,1647283159,11611854016726153411 +5296348b-3636-c552-f182-ff6ff002ebc7,613562724,12764051255847460696 +2fade837-0727-7f70-4bb5-d034272fd54b,907660365,5160074293410538923 +2779a566-822d-f045-72ba-865305be7198,457411738,15417826907604312365 +7ad9e393-ab95-e79b-bc5e-4af4eacd7c43,1524236520,13033236109038400573 +2e0903d9-b54a-8510-82c1-941d9823018d,2835017257,11833579822491521950 +7ebb4b13-f03f-1712-ee6f-c91d8c8848e8,1602631169,3230071854599903870 +87734ffb-2ccd-0bb9-a9ce-88bbe871e498,889887350,6046683990778948650 +e426c7f3-117c-6a3d-b459-88293afba5cc,3430492455,8736237614028949056 +9d4edc18-d341-6ac4-0101-29d208d6c3d8,1181956241,8757030034059719890 +053080e2-d956-7c5e-cf30-a4354ee43152,1413894780,7007865312373997888 +31686c18-a271-57bb-76af-e9097d8fbaf4,1880763434,35296113507287199 +f1fd8561-ac57-6bf8-75cd-905ac0da2ad5,2011919275,3517350737765874948 +8b666e72-2a3e-0e0d-83d5-c653867c526a,3058571685,16268654287098947175 +031ab923-ddff-7944-e3c6-fa6d480a8c6a,4128039572,1680979768644032283 +81b1f656-d817-81da-2372-1a3db9b4ae0a,228048771,11457086497263956786 +79d31360-02ec-13c8-f443-c395a8a56679,4073196678,4870613130025685885 +2bf9e240-f399-2fd6-13da-13ee4626355d,2640616424,4570776542752381317 +0d4a5034-5585-3f25-23a3-381054340039,4208213552,18422405262582059973 +c777f591-3d87-6050-87ef-8063650694b3,1028829755,17981423194030288567 +c94216e9-8fbd-9b84-68fd-e17642f35cc8,334875183,15352637607167538475 +dd5c928f-8e80-8b9f-84b3-2d8fbae464e7,3666575673,15251980808124120385 +98ff8d28-7ccc-c1ed-2b77-bbdadf986181,1378469686,8041414009108652347 +34be9c4f-0445-ea52-4349-8d10a942f355,439981602,450802501745981091 +09be8355-63ab-97f7-da27-1c0aa9535c56,648082748,7234374251780423960 +c0ac2e9b-4bb9-054f-a600-54914fa00b08,351403632,11353129453679980224 +6c2f694c-def1-7b38-20ba-b074a4a2bdab,1782279614,7432774249408507531 +76f66ba4-322a-9fed-7a82-afbbaed956d2,796937536,13322095829478707332 +6dab85f2-7e11-462e-6da4-1ffca644b699,2758330722,1554926198540601251 +02e333f2-613f-f113-6092-e01579e682e9,929590548,9822163795117652519 +6ca7073c-0a9a-9c2e-fd27-942f36c0732a,488161006,17689553743883808454 +6233362f-d2d7-2b55-644e-ee2b2ea54656,379505417,12953371787825148541 +4b6e2d2c-933d-9238-a6ab-376b591efa63,437804816,12744621750228447271 +f7332870-a7b9-8f23-34e8-32e6cc09d228,2734924632,15364647737915264302 +49bae6d6-7ed1-6f55-33c7-d6fddf617aff,2738833155,7429726993671989848 +1632fbb6-23bd-b113-669e-9cb4f6e8eb57,7011992,7246459006421049378 +fe4f0878-dfa3-ddcf-cc00-d8ca70651676,2215241744,9624862202958136529 +e55ce452-78da-4629-4d4c-c61d691b22ef,1315977853,9336683483542849501 +b36ce1e7-688b-5593-e5f1-380f986848e0,2231965289,15541138150425171044 +5934ecfc-d96c-128b-979f-d480863c86e5,454883878,15186123987807921281 +c52861cd-df40-d42a-7fa3-73ad925a506c,2642805361,10522013186684200506 +191f1145-0f7b-1d2d-508f-f9550ec37d2e,4050972728,8181092827949106223 +2dd6f54d-40f3-4522-a5e6-0cbb6b1a37cb,2888434188,12209966606759115452 +cc95372b-47b7-ac2c-5a93-88a1ca07f686,70297432,14522679475120052766 +0d556628-cfcc-2875-af93-f734d32abf07,4260270356,15617297271906217721 +b0b0e1af-a9b5-0955-9510-35bb22ef1907,3340627610,14037261076143042506 +5890247d-752b-5e40-6a59-870f0bc828a6,3714738508,8856459563610878158 +053bda15-af18-e585-a61a-110617b936e1,3930700462,14213121668489468420 +11ea87ff-d29c-7537-dae5-5e1e7067a319,3177215869,9981094627018066755 +55bfbcd9-8161-5f21-4977-b72f391cdee7,3510309365,12305144542703813160 +0aea44d5-9b3a-2b7c-8e7d-4032cff1e76a,119772121,11343624970656532651 +f51e105f-6d1f-602e-e926-0084b11654b6,3093336515,11097507009376647643 +35c186d1-6912-9ada-bb3c-675a8ada370e,1465832308,2987225501377349107 +d767987a-dc91-4c96-bf69-4a3f8c6d769a,2649623691,9201710784276167820 +29eaa6f7-a12b-ac78-47ef-150ec2cdea41,53340064,10041419866769438756 +af90f8d9-8bf6-1b86-490b-ca92736d688b,2038935004,7055938866689090794 +d343732b-a0a9-795d-eabf-65f6817f3d9c,985621716,1461548753786672366 +4282098c-b2c4-b632-8122-655bf93f53a2,2938473259,12002393618809009165 +f439ed64-07d0-7f9f-a653-23e70aa0a584,3511227352,3329495038986086828 +f73f9546-3747-df2d-8866-ecce26f8df9c,1486541781,5451561008519753492 +cec94d7f-cee9-4648-da1f-930db32115e4,1812844265,11460779716712587551 +d7720f7e-0ba1-efdf-2dbe-f93aa269a1ca,2774549093,7601571192490830590 +90fcaf69-e2f4-c5bf-e0bd-d8c147df96b4,2672477842,10630914882990835716 +984bab00-e1b1-02d3-7486-7afc600dc3e8,1672662106,2428023914595432719 +c37e71c4-a916-26dc-24d7-4df586dedcfc,3487370311,10974515421018978793 +f9da817f-2cf2-7852-a617-7ccb6877b741,423446756,16286914567851210105 +fc89ebaa-30d8-ed2a-779e-96682b1d55e4,226930635,16201473478455598201 +91330d56-25a6-6e1c-6994-190063e89ade,1993759811,6234530194273715508 +9272401f-d2e3-8bf7-d929-d897b7ab6f0e,3021908956,13218949778662440609 +81a4782c-9c86-e1b0-1a17-4d906da5fe3d,1000411001,15755941827672527994 +45e3789c-ded5-ac41-6c34-326026618145,2739928422,9608878868036698539 +20c6cdf4-cc54-943a-8307-40a4563172ff,3780537515,40698510313629337 +b016e05a-1c94-bf16-6b4d-30a3123f26df,4283691322,17141092583146828500 +132c7af9-e3cb-a365-2215-1bbd7c2ed484,3626307260,9110265340615122811 +1ac5611b-58cc-61ff-731f-31aeecdfe197,1560647795,17440696041363965889 +d1edacca-dfdc-3631-8e07-11f05b8578c5,1842173815,7586424061462479106 +c9cae4a8-f0d2-8b8f-544e-927cba986f13,1850946212,17159753837162182540 +30906130-66c2-3aef-6027-1d0e758f4b08,1758898972,17127697097602597404 +b0cd21b5-41f3-e652-03be-705d123d4856,1631962248,13552729529200101849 +50aa87f7-f82e-5d32-f5a0-3088683b2666,4060849142,12853934127273480863 +6fb65067-8913-8015-7c28-792d28283da6,2405901013,3507972796233048204 +a6294c14-43d9-705d-4aba-45b2582ea5cf,2011088096,5422480772918822110 +5f1f4090-e4a7-29f2-b20d-4bc271ef7a4b,3690964675,508762749278821120 +f8908cdc-d914-7fc6-ed50-21a5e1a94357,3132626803,2492045195610268384 +77c02781-14e6-84ff-b6c4-3f067fa6e265,3329692675,6666744450319048738 +e1a7da8c-6bb0-925f-28c3-7e6f69949713,462840308,189671860385704733 +7f2e68fc-ed1a-26e7-9315-17377b4ac2e6,3575267996,8818329988519774647 +c5fa4645-e23c-aa3a-2daf-df548178a215,1419924369,15734474961744037783 +f4f75c15-a201-b746-e64a-37953d7a5155,2622302462,7682414992392875817 +c120e4ef-ce58-2f4b-9880-bcd24057b148,1831845873,7354724443098161068 +2ec05d52-99ac-1a57-de96-8d5affb1f382,1191527950,14116763808160150834 +c975e7ea-165c-3476-9aeb-8cf9ec2c2a16,745207253,560240094123066495 +784f0dbf-2e28-0a45-33fe-afcbe1b9d622,2470243849,9925622452635930061 +f4e962da-458d-9970-5222-cde17c73006e,2178703107,6607201205127453348 +86b17801-e9df-c738-6521-2add7b99c028,2998593267,13496849934222466711 +b2ad129a-cd3c-115f-c0e2-216560d4d429,2634819073,13561801746613330339 +ea97c86d-3958-1f4a-196a-59ea0d6116d5,3020056727,4028697636190918770 +67834403-1193-906b-d60d-af5cbd6cd738,3292563783,4723530892051785636 +6f8d4583-5fbd-222a-82c2-09fec7b291dd,2569855754,1394874975882411421 +d2551ec9-8558-df06-9fc4-ff7662c8d942,1637681135,12224466467978579600 +6051d201-79de-8d96-ef8c-f660c0494254,580218293,5564701676912129530 +25669db4-dfff-7dd2-d295-4ae72e62793b,3758439956,7631246757374140065 +39f1962b-0dc6-0dbb-b270-dd00b896df6d,1625553518,1744558618795140950 +f6a37682-8f5a-b8f3-eb6b-4c8976799e8a,4275890977,6514165271663337951 +f8979897-fcc0-ae3d-c38e-72115f670ec5,3149933538,2932168736782566165 +5e25ea95-3944-b96c-704d-bd529d6f1485,684146085,16813135846375097465 +33145879-6947-937e-3c77-9d5a68928778,714002888,15095551055220277945 +a93cb202-38a9-04d6-8925-8417b43029ac,1660215710,14111755147790378511 +e1aa10d7-48c5-5197-3485-bc7f21b97270,2548498923,9140603484314916390 +fa442623-b142-9724-db31-742724c352bb,1596810234,2912791429147121086 +edaf4150-b2c1-5131-e36d-f83a6503d8ea,2044253333,3385610499343494127 +561e818f-93a1-f669-4814-66fe49bc41a9,1607164640,9697151178279408849 +178ce306-c8c6-3663-5afe-31a7b0d6141d,2088268702,14951639325710399705 +af91e318-996d-5fa9-e0c1-cc5255bdaa89,2239229551,8586526681535101444 +43ed5451-ed34-208f-86d6-c6e8fb74ef9f,1957192777,9607397702256195791 +660123b4-22c9-ce06-ecd2-d962b08cf077,98882788,9502649901693656425 +3e802d11-95b6-7372-288c-dc6efaeca912,3449698203,3180086024204310805 +cd7468ff-b2f9-7d0c-d7e6-67c320454f3d,186257158,2094100201969701448 +3a804272-2a78-99bf-7588-800184f9b09f,1094089608,12567031328339822224 +41673fb7-60ce-86c9-6b47-d68e6c0719f4,2493959082,2391742975408579434 +788e452e-fad8-f852-df4a-feecdff4cff5,4131988463,6626647403159588852 +d20a9e1f-84dc-a5be-d95c-47832c86f6ea,3883923188,16231706084258198672 +93b5ddc6-f59d-d37a-37aa-9cb6c5265e69,2457926473,5299505708893309098 +5de4c97c-c906-0e7f-002a-11c8d036580e,3276630877,15869199412422801059 +b808aa47-772e-5ac9-6f50-fea621cfb483,1500157621,4123546108304794041 +acf3d7cf-8e3f-b172-0266-c95523c5467d,3137195586,6684372288304222497 +123e033f-c897-0e6d-a82b-6631687b3886,79390606,15290312892614702169 +56fc21b4-8b69-8042-3266-14a5fbac5859,1268338596,10753594433643182902 +04ac67f7-8fdf-0ac3-5a73-4af305206557,1529043744,4837501164847042650 +fa4137a1-a6f0-1c77-60ca-fd1b46467d5f,1827083470,5220308390636641229 +b7f437f9-8c8d-30d5-ab2d-2d16220a45fc,2654783380,18211728468331081097 +bc131060-a66c-e0d2-edf5-51c0d95fee84,3617129209,8001924991936543737 +e6170aac-67cc-3707-a5f2-8eaf9eca8aff,1602942615,11508782978038034114 +aea2aa5d-638c-6534-d7ea-8048251b8797,4004074366,14616387747321084716 +1e1de084-b2c5-12f8-cdff-949675a4dbef,1604636378,7220634861470915577 +4baed0bc-ae1a-38b0-7b9f-b8f04be6c516,112552367,11529706314356245037 +e80d7014-1636-673a-e4e1-129ff92930e8,818881390,3561886815098595331 +f66edacb-2c22-4c29-b5c3-5eeac3ad02e6,3777305507,7865890343313881417 +09dd5bdd-5dba-3f11-c34e-d713a62a45a9,2273864413,1725944510520704032 +85d744e4-7847-18ea-e490-b137ff6b9f94,1045059243,10125830122172542669 +69b484d1-a14e-5979-8916-a361f5550321,2775370997,9806265532095697272 +7fbdf9c0-7dd5-01d7-08ba-873a66336a10,3953868745,15097114934970348386 +3d3059c1-8d51-2883-afec-1312d9385383,3578685587,4211585765976843687 +d90a9159-ac90-abf8-72ef-9e5dce8dae31,2946351639,5647563700426700575 +1f39ce6b-ac34-ea04-2f4d-c4793d479843,3386895623,451145408164605795 +d46d6d61-2c86-2058-4b2e-ccd7ab8def8f,3699918982,4776133956084785051 +5f837d4e-3116-3e6b-c41c-17bd6acd1f7f,3084442626,4052470550639100783 +51d82f0a-d2ff-be5c-ef64-46788118da2b,3656513245,4863526335056844172 +48e6ccfc-a02d-0b3c-e225-04e86c4d7948,2994793812,4893378555801801462 +5c84191b-205c-a26a-0d15-85695dd6cb36,3604644217,8842531671088529237 +9d7993b6-4ac6-e639-9005-11bdfa40068b,1262956590,11348695313231875781 +739f69c9-53f7-1db7-3a21-235a7d489f68,1197670779,13651890094682996341 +3d1b8f95-0228-dfbe-fc5a-cd3cbdbd01b7,3556545285,15823411801261966947 +9e9bcf5b-6e35-1c71-fd75-25393d996861,148778962,3788907587908190477 +02075095-9503-cd89-4563-54cd6ede265b,3843932845,6804961573098157931 +4d845e90-b30b-b0c4-9176-6c869ac2a34e,3729332786,697227779157683898 +3ea86695-81a4-9ce7-99f0-f76616fbaade,2806153735,15252151401961638801 +484b3dd1-305f-9057-4c0a-6fafbe711a7a,1944550000,17080418553947775635 +a0a667dc-9018-d752-c4c2-d15279143c2f,593469279,12634900889836657765 +d8e1a281-3f88-e4d4-46d9-59bf649bdd2f,189659499,11055901171089439986 +e4755919-de9e-4e00-c0b6-e5ecd7dfe61e,335627082,11693948967085519548 +cd158fb2-fe0b-6ed1-b61d-ebb109782cfe,1409836018,2603280930387965317 +0da9473e-6527-a00f-6647-2f21d9bc8ccc,623763046,14117937447687160274 +8503e6b4-3938-89c7-361d-8ba2727d90cd,1590901356,15750059468921433594 +15876747-096b-d162-a8b8-33ae05cb9158,1278794573,17056318597002813231 +2d5cf653-ee73-e159-d5cd-f4a10993f4fe,1862881593,16734983963570029865 +d2512dca-c8c8-49f9-ba28-b1e0aea1d2c1,4044375172,12072138970786720247 +451b4193-cebf-2da2-c0bf-220f63bad125,2683695500,14242947635852076393 +0c8e36ed-202d-b405-e6ab-e20e41b926b5,769975555,18325252549190610771 +de7928bf-b90e-a8e8-3ac5-90c7d2ee6a18,2758126778,16384026004242406490 +758106ad-afab-7a89-6cdc-856359335c4c,567238848,13010088996574409417 +deceb4ca-ceec-2c82-c2eb-f756fbd68834,513193895,17125283007760931983 +0ae834ea-9f60-6d6d-e5ca-8ce5e5038bc7,460171490,1809952033866360922 +4a3dcb68-5662-2719-bf29-62078a480380,3756995948,4800699628012720221 +0837dd7f-686c-47d0-228f-fd8e3df37c3c,3374564390,646215740637473120 +36499571-1af7-cc39-c89c-321c2bcd3328,2587714575,13560770173988810041 +7f2d1c6d-cd86-5441-0588-30d2879221f2,3450869453,4535349977338850307 +a91bb9b3-906d-0dd1-1ce3-6b4213bcb769,838842717,14387188644509074572 +b43d437b-4b8a-bd76-1dec-c1620f9fd096,2896414651,14186374466611141718 +a251ddce-4b27-4ec4-9db8-0dad8a4339a1,3680900308,12735463828433425398 +ca278eec-ef84-c215-4c04-eda1d5b10eec,1205495629,4857137308634537712 +237af4a1-7ef1-41c7-9c38-5ef30d6b3cc3,983637013,8730588592527490510 +1994bd12-aa0d-1e6c-5efc-098c326c898a,3561908239,4243394259466394265 +99342aeb-8d7a-77bc-bbde-922f73e616c6,1490195182,10434217704042998962 +a9d79dab-83e4-1fd4-ff8b-22e2d4402cfb,4058915373,17091004705683692226 +32cd0626-f080-dc4d-5e99-565adee11f4b,4272383094,9285302104843452351 +f5cb6b2c-9496-e821-81dd-ef8f6e5691a3,890948521,1276638982384232121 +b164b80b-a264-af84-4dd6-33cfa4d11e9f,2323010783,5570132327955225524 +949ee294-8521-b1b9-fed5-06d435194295,479964587,13079521586306593325 +61738187-ee50-3b66-8ae0-f03e2d1b29a9,1350625563,15514059723167010652 +1f73316a-f392-5d1f-5c5a-fb470002512e,3693789973,13894715172520497466 +ad570774-beb6-2f5c-d670-46c486fddaf6,4221080552,2644492159866932474 +2f987c83-bcc9-291c-150e-a0a06adf5f5f,3710595811,5366849407832838423 +5e40936d-521c-4768-6d6a-c98befa26778,2790736868,731099953072711953 +bc211bf6-d884-e776-b992-52641fe6e4bc,3739399667,18314351697220480195 +7f6d58f0-8c43-96cf-5570-3114b5867d9b,1402729779,5728253514726760620 +6d436ecb-3ad8-03dc-d339-f0a1ce4a3238,3478074634,10330423735675728972 +a78b0ada-405e-26e0-7a1e-670de25d32e4,2670225825,12104946864909634437 +4bb3f069-4939-43ad-27dd-f3feb1116909,1423120230,6642619456913849707 +d78fd5c2-b95b-63f0-d031-fb40d59e4d5d,1857337709,10547029827763761540 +a5f2e524-fca7-a6a2-76f5-467beeff7dfd,162391873,14848744011877002375 +603ec37c-dfa9-3d11-ac1c-e74e031e3ca1,3475954472,4285043560195074747 +09ccd27a-7380-aafc-8181-4068775c19b8,44871919,1816130664424623020 +5d0862eb-084f-31e7-b756-60669199fa03,1184539784,8138086702173421823 +062adaf6-42ee-f18a-cf0d-68b5e3c0be0a,3270114860,5426214436256007469 +06ac3990-6533-3d79-a26a-0a73fe0f4aab,1288833765,8457782192123193328 +45511b5d-d0ab-3695-e692-4d02ca64a6e1,1247811210,6391305522056674254 +4e72c2ff-fa18-e0a1-3691-a98a144fa31e,1379759749,11281946837964946354 +39c2f4c6-4456-1cc5-719c-b01f2c6fe7b1,4113583232,7223205211518138091 +ffcf4197-a517-8691-4941-83784f002650,2005506583,8047171379334695957 +cced1e1a-c7c7-cf58-124f-c4fa74208822,2579735721,3472571976385475029 +0c351114-9df0-aabc-7549-db8b67097806,1260439880,15541370932397182783 +cf0d24df-285a-28b8-acb8-a4dca43ca38c,741236215,6638763449777641771 +a9f8ba66-c0ae-962b-d1c4-60d7303ff903,3138266507,4316251700455049594 +903fa3d7-8114-2b26-e0b0-120d2c009fd9,3686064128,5418889079923252944 +788fb05c-fafe-8bd7-e1e2-99d0197608bb,2709611472,16545721815143945698 +863d6d5e-1b81-1aba-db0d-c464c95f5cef,611688017,8643535846908943364 +25b24a2b-74d0-8192-f5a0-e124fa277999,2738427317,5245567572319804739 +949cfcac-7b66-304a-eff1-cd928e7840fa,1368870145,7877864472054835483 +d1bfb8f9-082f-48c6-2f73-d4e21dc2be85,2869553676,5469242732134049836 +7f03d5fe-0b31-f513-a17e-a50b07a0582d,1373941506,7668406378876477417 +92f10e44-6c14-05be-234a-0882a8b0fc39,896076548,7842329007235080979 +7309d384-d2e5-63d9-b997-d4676756eba1,4085047633,1755456728071421169 +37fd99d3-6e3d-6f14-ba39-3d1ac9b38161,4101420087,17718974940762897893 +bed00245-c849-b5a7-1af3-5f9d5376ecff,1757535430,16437328270325860213 +84036899-a746-5cbb-5f96-5796d5009feb,3171528824,3793463172641068705 +7eb4b78e-1bf3-e6da-ad85-8afae8e18d03,2860244337,7984684869628541278 +47cc0a45-13ac-6a7b-f342-39eab86c66eb,211349701,16292904221109726153 +9452d944-2efa-46b0-fa41-14c363dcc520,1805387390,10027185008598330165 +eb184cdf-bc51-609b-c510-8f2aca1d86a1,3150892644,6228434617729964153 +d2a6014e-15a2-9518-4a84-3770d29e3245,2829546727,3805935597378451934 +a6d1352e-cb08-cd1b-7af8-63cab58b80d4,224770690,7535002276536046505 +de255f87-996f-8842-465f-249dd1ff310e,2500577283,10675542567137983666 +bf9b97df-b996-cd41-7273-d5084e935587,3647498338,11484974529323776007 +16952184-9c0b-4c78-62db-1dd0ec4e4186,458719070,12726496104394845834 +ce0770ed-d643-590b-857b-a594caea070e,1891359269,18431714146706810504 +8cf78378-416a-7184-a2b1-36552b0bb3ee,1641118636,17240113294726021406 +53d5c986-b07e-3aba-976c-090a736cf9f5,987008071,2007434351989943151 +5ddf5557-c9c7-cc15-b2a2-420b515f8d57,1077700730,8577304704182793769 +e4771bca-ad17-e8a6-1ab9-c1126d321550,4100635137,10162015994751955754 +71c2973c-682e-eeaa-4502-0be78064df8e,809444015,17392880316288093189 +06cab020-84c6-07c5-91e0-acca1923ad9f,1144807910,14763847040920554997 +c54fa3d7-b705-21b1-462c-00e5a4be62f6,1840838838,10389740357419612295 +87f5c4d8-7815-d20d-2cb2-a20cfc17cae1,1191495192,8285231636397749869 +0e7d0972-ad45-03d7-c575-ab9599b6c5ec,2755687866,13317272165878336557 +601a4234-af44-38bf-d5a5-d1d5486b89b5,423550732,8559699174046571251 +78383147-15de-d6f6-a210-5c82f70f796f,3932021226,10789541556251781489 +2b3acb6e-9ea6-0539-3bf6-ba59d3d752cd,1007548483,6865616539218172308 +bab78878-38ca-fae0-7ed1-c2a64354fc73,4239643222,11389592892153216665 +e4d18cd7-285e-1d0b-b59c-e6359f33d2ec,4006909670,140128853801427719 +0d61c5bc-7896-6e31-fec7-eb996d5e8435,2541652283,16454057324170150687 +8c2eb705-5b03-8501-6701-69b2298012ad,2910891987,4734934338521386904 +33e76bc9-f100-60d5-1953-1be03218a76f,3161140750,2382159928829452964 +31eaecfa-7175-5915-3430-ce1cc48d9509,2006636944,6321300953939850289 +8d50bb95-8d56-335a-5bd1-f09ba7687405,1478381019,582332242283144062 +76731b6a-3b0f-74d2-86d4-27508e1abbc9,1119205573,996799157380305443 +72a6a1e6-3d18-4950-389f-96f470512855,2106718575,15184641045594862402 +b5623ec7-ff86-b76b-0204-b2c1b77e5a81,1168866655,13458630811193247442 +1cba45ca-217c-14ab-bc84-53daef0ec6bf,387970660,10954858047139823529 +2dd11016-a748-909e-51fa-06ccb4655f95,1512634796,5470963067536843207 +b0dcd414-2f61-3a8d-5c2d-e466ec39d37d,121987819,1507455193969063644 +12535598-d2af-ce0d-f997-66e99481ffbb,1432711990,10573232359041048517 +fab56be1-7e14-9021-434f-5c995c52c66d,3329208060,17280238154371448174 +2364d09a-7dfc-2c0a-414d-b6df8fda4da2,3073441640,7252071768116928748 +c4dba06e-17d9-7349-2027-2ec71f2e1293,4065772867,16405335275854477218 +23ffce74-c41d-d3d1-28cd-4b393cf14d1f,3991580224,2471483500453852064 +ac29513d-ea86-db47-336b-3e31536d3b54,1549727105,9942147080020263965 +761b889f-cfc5-2bf5-ac16-b2a0c0e03c91,397267882,18190210627038764788 +501fc1f0-9317-50f5-c162-910d0cba6f02,789165998,3299584981185478158 +60c3a3fc-4e0c-aaac-9285-a8b6f94a9bf7,2238985803,9249457259331190296 +9b2e3dbc-796c-f92d-4602-96f92ced2541,1102189098,952603060515363305 +e9a57b06-8201-73ad-39c4-428251779325,3343427537,6013252402670008251 +770e35de-e9bf-050f-7c09-8d1fb8ba756f,648180355,8080495487874160104 +2777898d-19ae-7fe3-fca8-171fc6ba7ed6,4086013313,5877345794681620525 +59c28516-fbe2-ced0-e9fc-3deb755fe878,120554564,12000249252248654954 +73af8ff1-2102-05cd-c78d-7e2af3def056,1755502292,15091011242055525964 +5e538447-8e24-d1d4-4ca3-e51b20795ae9,4079478279,11542213918239667594 +667a8185-f96a-a11f-95b1-e5cf3de0c5c9,4270601267,4094387671435525932 +7444518f-d30e-47e9-7e02-59299b4d791c,3044303611,4875592081558142865 +77a3c9be-9b95-6f86-1d27-d701d5d5d9d1,1508084672,13510014788624323157 +26537f38-abcb-4d4b-d635-c34b1250af43,1074375873,14046696542948629316 +09ba56ca-e592-600e-cd3d-1dce004985c9,284662360,17607508682709016554 +a1b73120-0e8e-2d3d-d03c-81238c88ca24,1436956112,11046593468047370737 +958a8851-9f63-f7ce-34d8-da42ed9abf81,658823935,16096195925658570666 +da576fb3-fa1f-5f38-51ee-c184d94568da,3896982712,1136264825654107292 +872bd0a1-1103-fee1-ab46-443524088d78,1829116623,3457836711831610546 +3bfaf287-f357-3321-6561-eda86e7519a9,2203528884,16502899399569634050 +7ef8701b-9a60-cc73-9fc7-3208db7929f5,145826331,6546526630651565407 +35175371-70d1-78be-a782-23841b7c2f95,1891674413,7799947810856142965 +9a2a5487-cf49-2773-1997-08bca8657611,3684664919,13801292646176985169 +516e756d-3c3f-ef52-b36c-7fdfa9e3b82d,346707570,2766378128100899374 +9d4156e3-6906-ce23-f228-848e915eb5c2,63746721,3709326593967190059 +78062bb1-83ac-3c84-d88e-e2f90b8ede55,2655625681,119663466776325268 +b11c5df3-b312-ea03-8ac7-d5e6b4e661b2,1191771133,13431771896434640946 +23c64d52-e53b-cae5-f937-b0c03c7927db,1734309961,10031483117405599710 +9ce1b274-143a-0d31-081a-f1da6bd6c3fa,1672229930,196312548757556111 +0dbec091-2a7c-ec02-d133-d3d2e438119a,1520146323,15756593411333793208 +4540c334-76e6-2b05-fa5e-71773437b6bd,1216959254,15301787810506279235 +3d875422-49cc-aff0-1d47-f8a0e2fe853d,1429962614,9866562298994796357 +08255190-4e41-e317-4994-00f8945fd859,559790979,8522814760025912388 +ed8e8648-3609-1bd9-de3c-6a58bd4c1095,1461322308,2509601520792062228 +446cf2d6-a81a-579c-9a1d-19ae6eea829b,83621593,7700254049072706288 +c523ab41-cc17-e5a1-ecda-95afd3db79c0,1688164900,7460749488279537972 +bd282c88-3dec-a0b7-c0e7-35532c4fb00b,3560514792,14235110977186493095 +a9ebdf0d-7de7-d7e1-7cb0-1947b4c63afb,516986678,12449899223331842872 +91091afb-1083-103e-62c6-4a22180741fc,3463155079,14771646953495185429 +014dd89a-8ab1-f6f2-476b-8c8039a457e5,4105074575,5346868331376623577 +a0e18ca0-44b4-546f-1eb5-4d438ec7db8f,3759258732,2306324708857167824 +e3a6d83f-19fd-32e6-44f7-a6ca2a7fbeba,2140157762,18422555628199709535 +8cdf023f-8421-cdfe-dea1-2010c8338f68,3549567440,18311845271912194871 +dc274d63-01d2-d6f4-b768-494f7475f2c8,711911707,11521726957670697898 +96340d78-6f5d-7821-6a13-61a545a90d22,1013654861,236431767422683553 +8975083f-78ad-85b4-173e-878114b10057,1340367075,494913795866861303 +88711a0a-d952-b1eb-2511-0db6270f04c9,3208172571,13056832012211159896 +3f15e9c8-575c-4c11-c581-104f8805f620,3504070926,8928602757309959981 +b1260cc3-3f9e-a90a-f392-2eb188b7afa0,1612087316,2962355803200632438 +e3cd851a-bc8a-444e-aa67-de6fbc0eec36,2817265434,1306433966172163890 +f841a98a-ce83-d52c-01b4-4252f122908e,437823549,15234533166164053955 +d6a9cdbe-3b0b-cadd-9609-13ecae52bde4,2790892606,2255437000684473814 +227dc0c0-0c36-87b1-525a-7a6b696f1925,1849872774,7638576899391872656 +52ebce09-5839-1940-7b95-6e14e851f893,2715662915,12043489519252313559 +9d714936-0498-2483-6da9-8c35be022f85,1904696382,3246196236201238438 +57f579a9-2011-8112-28b2-2466f59e04de,914728044,8429801697151174143 +3cb2d6bc-bffb-771e-bda8-188ceef05a3b,586597616,3072826417239885158 +093bac83-c4e0-ab12-6335-3d911e7dfa57,4135782545,5078009631611870850 +5b795e11-3b61-8206-191c-c3d4f3613112,3123125126,13441580611244451745 +c4c6f035-6fe1-8d67-6aa3-1529d6deade9,4171498682,7438178668646976437 +22ef6e4c-a662-5567-7058-18bedd51c171,1505558915,16021139695234023295 +836a83ee-2ce3-80f2-0b02-9a316df39ba7,1537648082,9139864461050315339 +9cac6c69-fa41-0b02-1b4d-5621312e1eea,4151792563,15836007187147420456 +995d26fe-f4de-668d-b4fc-cb87bc33dc18,3768315034,696053969490768655 +ede691b2-039e-9b2f-fc0b-e2a234cb96e6,838085147,12112173422929452705 +02cc775c-bd2e-d679-d419-ef769c690cb6,2678781780,10651171576503222037 +e1c2f220-d609-037d-6313-ad325b40ce83,476873662,1859794021430530058 +a5b3e565-9638-029f-bcdb-db61a35f469c,3813594671,9982158366857787329 +c84822c9-2b13-bee8-f661-f6a16ce6b06d,377222900,17888907427018388813 +f3099925-101d-e784-2f7a-c9326de824a0,3592719820,432120219642220361 +6efba57b-9dd2-79ba-335e-732277bede30,1616713774,1474179620858318508 +a8588c6b-e475-b08c-db8e-4abb0b6a7940,318218064,8443738628760323282 +eaf63e97-e70b-be37-6e74-0052b05e22dd,76862923,17206325835443655634 +ac76de60-09ce-6cd1-f408-ea22cb99c1fa,446712749,4741785209127566748 +37015be2-65ee-3221-c6a2-f3c6eddb7dca,2335164933,14326550864633135743 +cf4b47f7-f632-b102-ed12-a2955e44ae29,4102927305,13240408819577461988 +ac96755b-61cf-b3d3-30d2-d09a6646f232,2353472703,17723165139598632506 +f675d3d8-8b01-4bd8-3eb7-105df4177ea1,1879300993,13947646376663623007 +8d1037fd-adc2-2b9f-20e1-511a6bc88f9e,887266327,17231309366454049185 +5d29d581-98e7-b8f5-80e7-e8cecce68a1d,2772268602,4170224255056433992 +2a2fa14b-d789-5024-175e-bd0beb1c7c3f,2892030523,13046066357197343457 +328dd367-2a19-f7f9-7d43-d89bba768ee6,2783917914,13083581270682071772 +e80e02a6-3ff3-6962-af3f-188d0b969d46,1299227486,8996721156209321472 +98b5126f-45d0-2a71-6ffc-c215ca2de4c4,1757105350,17814809791293243691 +d8191f21-dbf7-1983-697b-b650514c4d2b,413274073,8807513227652086477 +aeb752c9-bad6-854e-edd2-a5782e1c45e9,1092797225,18125913817883022779 +862c1cce-53f4-edfe-1b31-644300322841,3106446734,18216231402033322987 +cae20ee4-a9b9-ead0-6d56-821ceb013151,1705379069,11454269953585835639 +5c172c76-d050-6cc1-ce04-293cc8c70175,513578137,16337690309366946572 +c66380e7-afd9-2053-8b93-ebba14a1cbb0,4113005115,15103356574836627718 +8460171b-cf0e-5e0c-751a-33313601c5cd,3103509298,13890505005270414944 +0103705b-e136-07a1-48c5-12f35d940b3e,3279409781,8411095234925944248 +a301c90b-1f7f-4769-99c9-7baa02bede55,525083674,14716289687204926321 +4de74fa2-9aed-018e-a31d-c1b7684ccfd8,3070019707,16695085061572361907 +f6f849c5-46b7-b251-1a63-17028897df4e,2538034949,492005983800430696 +6db5031d-cf2f-681b-cc7d-1e72c1e7a88f,1293535236,3004329206225976214 +eb8a153f-7e55-3637-18d1-93180412d204,366728513,10469562982228779071 +b841ddc9-427a-f819-b1ee-dccf2a517e22,192961901,16360265129467594570 +b3e9dd51-523b-44e5-38b3-a9edd2089b6b,2768708972,17780912489282652695 +fe992418-5396-8c76-a463-55fa9d423637,2346826295,13265063573904055204 +9517d7bf-ea36-0148-40fc-e76193ecca7c,2744204173,1303427608863252515 +c3dfc3a0-2c87-2253-ce10-b44e8477edb0,1828931337,10763003830373306258 +92e0cafc-296a-8232-3c1e-cd552a5c3e51,3360694087,6694053428738160780 +f7cbc048-9212-0541-fbe3-6964a1b8812a,929196102,106309320778521413 +7bf8d59c-4259-b887-afa5-573d608ff6a4,4229257814,14917591908878602213 +6eb4f417-f07f-6443-76f6-bb0c6f093f10,3543183152,12079465958823511172 +1bf9aa43-d692-69c7-b57b-d6b87d0965b5,3529526754,15125512804080962565 +89b68c1e-7843-9a67-9bfd-396946d4a880,2740798105,3253728135626455163 +952253fc-949f-d298-6c57-c1fcb4c4345c,2539259285,11013074984987342823 +efb9caed-d0ba-5ca9-e42f-b68f490fc0cb,1289062328,13018395087895995069 +a2ff2f8a-c71a-e2ef-1f2f-ac5d474dc0c1,3970115037,7660811963949132226 +e571dac1-f916-d591-2153-1ec0da03dd2a,1204030730,11552661074667341799 +d39cb44b-d683-a5e6-e306-98fcf472f08c,2438295119,7166220075633416857 +c96ec882-0838-2178-cfa8-a37a4349962a,1178746231,15308640637337628544 +435163e4-6927-b535-67c5-0cfd935f95a6,4068097986,11017420439285529588 +7ae5f4b7-1c17-dcb0-0e31-1af50fa9ea6c,3564582412,3461095727371548015 +fd10f973-67c9-5826-a8a7-9c7d6242ec49,592515625,6014526945941379461 +9ba2566a-30cd-852d-5a3d-432c57aed501,1187385106,4531155868745026689 +da93d377-b0b1-9a80-a4f7-d4f9d868134d,3619230833,16721204388920312565 +f9acac41-5aab-5852-4bb2-c5782c4b1040,2782418867,4779146415707791162 +de4566e7-5bff-fb86-34fc-de2178bb15c4,473322067,9121186752871435664 +65511ed9-23d1-31ce-fb85-ed549996a5d7,4158147555,13679624854148779978 +681334c7-c958-af32-4671-45bb02006c46,1882039724,5409146214550345039 +385358c0-a621-2012-fce8-d5c96a0bf748,387608613,3759229431660413264 +df5f700d-9ee2-c225-7052-7be1062ad539,2836465745,7837669792171995067 +3cbe4a1d-e4a1-b135-2e1e-d59d69b37584,305711616,11517958788744579790 +c5abf95d-3b16-422c-7fa8-905eda2598ff,1757920392,2718006317697608056 +1472806a-2542-339a-df86-95e2773ff127,1190394158,15856645267633555152 +f097796e-0eb9-65b3-e959-ca45f19e38bf,2321962856,1362982575650576768 +961d6c31-4ed3-0e4c-3725-60f824937880,3504810593,1980512543580437621 +ce55fb14-a3f3-e4be-2eaa-0140c212b1bd,1659510570,12593070101784148359 +6359d388-1b68-8cf5-4645-c78e121f1b31,3936473849,14575629019669326421 +30510abb-464d-5fae-8809-3265032a364f,3836333946,7769573617517455531 +a7b27ab7-8074-b981-3757-b9baf4bb6f21,673649959,14507294973245157662 +30a005a5-3216-af34-c981-d6999508f47c,1955573744,6462101000851618604 +8041230d-8b17-d507-bac7-f32d8fab54fb,1159640144,3557443052423413279 +04d1e44c-4757-7306-b080-251b3593098c,3712046183,16606623444504480142 +1d424ead-245c-1b1b-7962-fd6ca21bb62c,585937133,7412292593976163493 +d48c8ea4-5158-0db8-3c73-52b93aadef54,2014906903,5952709090895361494 +493740a1-fd4e-20b5-4cbe-a50872a56324,2441006142,3330305775649057533 +ba63dddb-2964-3759-69a6-082105e85963,2095734068,3187822807420639548 +24347384-37cd-ca19-aa7e-21e7326da040,1027011340,8321308512661167351 +6cdac713-5ef5-f2fc-f4c7-8a02d6d2e25f,2436637323,11509938349640747056 +e6a88ed7-1625-a6c5-058b-f064f92549e0,1385843958,10419588667572822408 +2bd2e96f-c2c5-2b90-1187-cb288c15d07b,4052538970,3031389480472524624 +13631625-6f1d-4bdf-7353-20ec89f0c136,2552857044,13099064562423436659 +5ba5c777-465b-d598-c4d6-31a109d16ce5,4276181741,17573115695785611084 +fabd0eef-a08f-e36b-11e3-831e5b461884,997159660,1660625929039097584 +75a6652f-3fa8-072f-38eb-52e04dfedae2,2706014376,4014281857229386508 +b988e901-3108-d5bd-423b-7cc0623d3ddc,3915944486,14867455528708303785 +c394097d-04c6-c0c9-1543-89451bee1f54,1369450428,16556231307799579568 +7ba18ee0-5af5-fd4e-56b7-293d59d4adc2,2053218692,6317452685218676739 +7a34e4f6-6253-ca10-c614-4ee927689782,3989400181,1814855496649948059 +ef9b7551-de3f-ba6c-ca8d-59a125ea6274,2106378717,3357432176335253094 +bb4b3cf9-6b03-f443-ff47-25893c227dc3,3486721695,11547045584979502450 +b2150c10-07e5-b64c-4c6d-3d1ed19fac7c,453382132,16704466311382194815 +f5b01403-25a3-f7ae-c4e0-29e6d810bb84,320403985,2077111685262712064 +cbef31f7-f559-72f9-274f-8388f8b1e592,740715031,9150707843251141278 +fad866ca-3577-3ca0-d68b-7a35a527fe00,3212710971,5907447231547943221 +ee209081-9c86-14f5-392b-c53dd4ee5387,3367390726,1447053056928231371 +3c4d57d3-9809-51dc-6931-ae821c17168f,2850966819,1431121418041650245 +b4c778f4-e87e-e0cf-bb22-1ab3a03e8dec,3889612233,11207649291640110391 +39a92eb9-5ba4-6fd4-7149-6443705568b4,3923487482,18178076983124213938 +bdb52234-a15b-c1b3-130b-18a5eb777f9a,4136233779,14815049915387536467 +8df9d4bb-c20a-4bc4-b17d-f29e00b14da3,3994568117,6830434500725260897 +0d4feabe-d243-5bef-8c0a-42980f2fee86,4095383657,2545736101591083119 +0449dcc8-1f05-22a0-b007-37c1cffcfbdc,1744328376,18184629081003071760 +c47f1d93-14f5-00c6-c64c-daf6d11acf98,3157358767,834057497796429776 +94428ac2-9aeb-1729-c5cc-dd32b37e37f7,1859991311,18304079616149880795 +edf95e0a-4666-cc49-cac6-464cda2a57a3,3002392512,16648434816494496174 +2c2fd482-bf76-6513-ffde-cf4f7fc0a3cc,174590554,4628702886149402181 +8b5d6538-2d03-a532-2ef7-3539cd57fdae,3832284570,10935725072275375273 +92313d02-4652-a9c3-5cd4-5a9045a08465,1622893272,10965469407606452485 +a6742aae-f528-3b96-7dcb-2c0290a21f29,3479984992,115744853610989484 +29f54d7e-0554-dba7-ad9f-b55253a50e25,265931980,13818195262337672192 +16a8c1e0-1ca4-7eb8-51c3-77bff8becbe7,1350781448,12146260722026793380 +5baa4215-1b95-52f4-95fd-cbeab073e068,2805899863,5279376161624664119 +a9b51861-de20-0f3a-68d2-015518555dae,587636724,17018964194067109267 +9c39f7a7-8201-b42b-2593-780b93a99942,160965806,8991392506430937674 +39672a7d-2276-dafd-f701-bc34796004a1,566452110,3435439428736641776 +d64e076f-04ca-e3c5-633d-e47cf92c9ca2,763692964,2653548204827097441 +1bd98454-1e28-5aed-70c5-13c923697f1c,3421007135,17707038314775596525 +135d2420-782b-47fa-d610-3158b327496e,2084015763,4182601905475541518 +d55fc9af-e290-9891-d52e-42b61025c604,3142075106,798726477600177593 +1cf9246d-5041-539c-199d-84822f552af7,3575360417,2669828664265846960 +5eaa416d-82d0-f326-95d3-c54653e161b1,1625808150,530969064603599338 +d230099d-1ae1-6159-157e-37b562dc5662,3640719877,5479572792946376097 +a041b5da-975a-44e4-2c41-c37f6c20200f,573430640,6150434954303108403 +d900227f-cd87-6af4-d30c-e4f11bce427c,3678153212,13992525768878925319 +1c89adb7-dc9b-dfcd-4e78-ed5b8c6fc370,797460672,7041441014888505573 +dc41b1d6-3d7c-9f8b-f17f-24e6a0d85e07,277376048,6206018626916067237 +3f0e82af-6c06-a5c6-bd8b-5f0a793c4b0d,2575576509,1565083443357470904 +d014d82a-7458-9aa3-ee96-1b637813bb63,1132511899,12463928444516846927 +96ae78a3-50be-8cb7-ad3d-32dea3e0c695,3862515810,18026891371203897502 +f849c1b5-8413-c04c-db1d-f17454a8e131,2930248217,3045442943291387781 +d2dd7762-ba4b-bc8c-c56a-ec860b800ac2,3997218902,13104043699639415317 +2f8c2eba-2149-3d20-9a88-abcbf1869c43,2787512750,1022572994729648673 +51679566-a4c6-468f-f0d1-b01725b67d60,352085153,5026491802902368677 +6d23b743-48cf-00c5-cf70-ff0d3cfc1e9f,1940689774,15627793543835986853 +7240717b-2b68-01fd-1306-3c55990bdb21,344641897,1099942704510726283 +d15f0952-9d1c-4499-96f7-4e6a6db63895,544874064,3714975342597984778 +3702d0b0-badb-648d-2693-f5060a15ba19,2392349818,4262978700765156082 +0841bccc-7792-ae5e-7b3d-8f28e0f8048e,3818692757,490035857625788396 +36ee24b9-5385-5ed8-ae8b-7aa8efcd002c,3684025431,15373709006242478881 +32e4140a-ad72-0faa-5c2c-29af80c70c80,1531999756,13888377873942986300 +5905574b-32b2-9b1b-0bcb-acf533fd61d3,2645901509,50293901003701975 +0babaa66-78de-a2d7-8c7f-298f555846b3,1690819595,448241137001175802 +95900a41-4c43-b0cd-acfc-e6e78f3d993c,451893659,11211236032475463252 +b62e1d79-dead-702b-ddc5-213ca441c2f4,1087578950,15625813097720782146 +2e117818-d9a6-09cf-a1ed-416ab5306bfd,3714599108,4045005021276198007 +4a487aff-68d3-2a77-b61e-24317e936a49,2848355907,6781426660816684008 +a0e60e6d-7875-13b0-dad3-a865ef8a683e,1200594350,7380382934270800493 +ad443776-7db0-7778-821a-5cacfad7ca5d,4013597107,4721459924052976397 +59c44c88-bf87-aa21-4e52-0dc4f6ace9d3,2418653482,6373538417219975768 +eea47734-a72c-0449-3bad-c4b348844f72,1406547525,3616466280108810318 +b30bc40a-4252-47b4-b88b-76143939520e,293980049,1395960052301750719 +2e04a30b-d86a-ac99-297f-ff396c20fa13,1059523607,7904717181377910913 +3cc76f5c-d13d-ccb1-ead0-5384c989a588,1105498217,17451674520600221533 +b63c61a5-d64d-c3a1-af1d-a5127e70cd5a,145748700,3416696093611268723 +daff50fc-885a-35f5-e8a8-821ce92a70f0,657805033,6592527219978994754 +6cd6bf22-fbaa-df30-4553-2ed345d2c50c,3524883382,12896602109657512523 +ee48c82a-ba0c-7277-17ed-073bd22c8311,3276462634,12852631796545921417 +b2529ff9-001d-62a4-365d-9f5ee42553d5,848771068,2264402668480791333 +6e2a887f-0235-9e00-d524-eb883f7a8293,3221622688,13841690670688837974 +c6d4529b-e452-5cd8-20a0-82aa308ef977,1311617071,15149012939246690356 +e05a38fd-81c7-1c02-e6d0-4cd77194a25e,2745801398,10885869171558129425 +44154de6-ecca-3247-e5bc-16fb65e907ad,2815140204,1954886134318592927 +c0287b95-26f1-24c9-5f13-fd1b003d8d0f,957709986,1012097184843360885 +1261a8ec-8bda-95fb-86f4-c240a126f11c,1177869844,6653569253294559101 +fbb0e16e-c120-0bef-e08c-0ee710cfab83,2090885380,5801194450646835038 +9f57a750-fa15-fa85-6ea4-7dac3b78b505,2441214588,4756919466472588703 +b9efe29a-121d-2c0b-311c-ed9f446cba4b,2642148859,10173191278060704612 +07cfd24b-4617-9dd7-86d4-a9297a5c5574,3309674815,1799444312052789683 +1e71271f-bdf0-ac38-72b6-a057060616e7,26008626,2578917755571268098 +1a9c7077-dc23-08ad-8d7a-cb3b2a2073ec,1531591466,11208490319125964845 +db87028a-5614-829c-7b7a-1b84165feeb9,601796727,4941010163211336764 +c29f14ae-c507-c797-1d8b-535481d2772c,863484124,17847624323272748128 +62345d44-ef1a-8afb-e4f4-07cf79ae72cb,1786549049,2072820438016030260 +5093251a-74eb-b332-5fad-c3e8bdf2bbfd,1832743274,15200332295985943462 +cbce5984-a291-76de-4441-c47ab43531f1,1320493061,8415520275011974043 +a3d7a4c3-9501-aef7-0f99-6c289ed680a8,547821136,12678998742667579090 +2ac22de4-88dd-ff5a-e9c2-bcd4b3fc34f3,2786443836,16463284719165936712 +ec2a7d4a-55d5-c5e5-4558-dead13ed3e49,3506914325,3269404172471875181 +85a0df29-5fb3-6c80-daf9-1063e7423d35,1995652351,12525154059858362517 +d47212d8-8df4-3d19-5347-16f2ee199864,1028596050,10144393145635955702 +dc906fde-3e4e-643c-f77f-de9bc38d783b,2775095715,16311003026803193346 +5fe4fe23-e156-7d71-3203-f909128ca93d,4189295418,10810073186401283497 +9b8f2343-89a8-9e81-879a-90832fa51b40,3118337468,3344269856753407186 +4d2b1b55-1cc1-21a4-5795-7efb873d6ed5,2848652774,8072788520600863586 +83bf2978-f59c-01a4-3c1e-468686d9a78f,2147553075,10599890877250946008 +4a9fc75d-1dbf-48a9-e1c2-828332bd4ff8,1625461931,16540921092544570357 +2fbe141c-62ba-ad86-248c-ebf6d5ecb866,1786868252,321860767599457982 +5170ae5e-9399-b77b-a4a3-707ede18179a,693638030,14327012970356403206 +f7c680b7-c67e-012e-f727-b48da109c9cb,1795765448,11356623688065728323 +5a423eb5-752c-5076-bec3-53bc3550fad8,2091142622,6053596779067461256 +f8d15bc1-95bc-557f-becc-72e4bff16013,355539042,1173000530378484179 +d7553840-5a38-28bb-107f-a1a7f3c87b93,1242638591,3474158056796944878 +54cd15c7-ec0c-36da-133e-b66d4c15cf5f,2732632732,18434648178831408549 +dd68ca16-74d8-88f8-25ea-c0a7feecc72a,951741346,1915868220654147253 +2eda86c2-ae74-8daa-ec68-bf5214501659,2981795443,843849336487849819 +441ab8e0-9e21-c531-31ef-f0eb81b3d768,1953159234,13992041500415974700 +3abbbf73-7cbf-287d-3dd5-3cce54a71e3b,4136248106,16158444938841462169 +812e0fff-60e9-1b43-ad6f-cf248134b8d5,3010104629,6384628531737170109 +a75bde76-2036-4d69-38f3-d9625182c15e,290480424,4123685898223927002 +c3a014c3-c546-8d3a-8a67-23b9dead0f84,1871361453,1746742567959140551 +9f8e59b1-bf55-2b52-0f2a-a36849758835,1976022877,12577613027857110296 +05c85090-a094-d205-f876-dc6ba369bf44,4022731888,5339977541893426345 +dcde2484-9f16-a439-67b0-7ab6414f22bc,1989447436,8077395261529726566 +9c51c9aa-8d41-19f2-dd20-0392bfb74e1f,387364384,1843843736242045636 +cf03fd3d-73a7-bd8a-da83-8dc12d341cd3,2530844140,6624076999745792401 +bbeeee52-301b-5b3d-2b62-5ad467adf4de,418710774,6664905778978261887 +2b8d4b00-fcd9-54b7-b383-9dc41046b91f,238376550,11752214353842450789 +190cb6e0-ebad-8ed1-469e-e20846e95520,1670670564,6183672461975889540 +12465a65-7953-add6-470f-38a889d82103,3977563285,17589962709398111049 +c1525a1a-3e4c-b7fb-ed4c-40aa0b8811fc,2174957207,12481300849902917423 +9339710b-5a07-d75f-3927-c0115ebd8e5c,2165225426,9041116832873252178 +689fa65e-a550-6513-603a-a6c9b9a245b7,1447513038,8945491351499385814 +548ae6c7-c823-ef71-4abe-170bfc941f6f,4083484783,14927480316327237820 +6a121636-3838-989b-d044-7762d5b222e8,1955403773,7039001369205646700 +e82ce118-5c93-caf9-9628-0d9d40cc69ad,4101317638,10222848617923057886 +50d74e51-24f6-9691-74e7-02c11b39e152,3430416844,465641853301403907 +bdca95fa-c0cb-4af3-cb4b-d362c75c355c,48266532,4484448611207632484 +3449f19d-2dc4-5b23-f50b-bffaf04eff31,1606474871,16380129783698716403 +e14ee642-9c93-d671-cdaf-60de10e9487c,2538169878,4259901011416178255 +9378a3f6-9ecb-9e14-ec8c-f7455a88bef3,4186747829,18002421809109582908 +69e95c8d-24de-80e7-d6ea-dbe4aac9fead,107756482,8201719311138974131 +aeec2371-807a-f7d5-a025-29a3c23f0a87,2146542079,7369262563939360057 +f3fd73bd-231a-a835-79a4-3edc7036ef92,4156942859,12990963866642026955 +4b7c71bd-19da-64d9-b4e3-b328b1ff9356,171857641,9674360754609867665 +5ab71bd4-0240-2f00-170c-877bae7fac60,2030122220,7352763152150985173 +f6ededfd-3638-01b0-96d0-2afe1537bb54,941542290,1031965731488980901 +a85d0beb-d16c-fc9e-b830-8d5bbdee97fd,637950734,9486495033298769581 +bfe7c8a5-d9ba-cea5-6289-9cd4f84775cd,972666063,6185481425376562707 +7642332c-bbe9-d9ea-680f-be83f5e6f13a,2924464297,9368876548657158481 +8fa660bd-9865-184d-0689-baa95a1f32a3,4070156962,12234334214212091289 +596c00b2-6692-d3b2-e958-41051b00341c,3577513964,2164119115023887648 +3c534e33-3fd7-c836-8ff9-c43e2cec6087,2821838370,2788013851099618076 +6a295a13-4c89-485f-91ea-a5dea95a3fef,2183431643,14920171453048122344 +2f89ad13-8915-8d6d-0178-3623281d4a1e,182942494,1753359870430955972 +18956d2b-359b-e75c-5434-2631d8084a45,775124771,7351606719881400487 +ef57c7a3-83d1-83f7-ea01-2932220ac45d,2990466440,1255349360668732274 +0e7bfbb8-6c41-3a1a-7a6e-0d76a554fba1,3582539109,17722974274099559410 +0f99187f-b6d6-156e-d330-fc542b0cf51e,614250933,4649132368198774615 +466cb8ac-552f-25cc-530c-5d1a3fb6d9aa,1893765103,6053714044142102992 +bc82c953-f9be-3afb-4703-8987f9e83c72,2569484303,3584403580020040489 +ab25124c-3318-9ae2-f55c-0f8265643ca8,3441960541,190797775802631484 +efcf82f2-0cb6-416c-efc6-104951407ff3,3827839371,10766569877588960951 +8a3c1167-64fb-4bb1-12ca-acf85f02ae0f,3195178872,2677061972353128442 +b258b829-7f1b-7cc7-0f4b-c9e12b15f5c9,1759559099,16984130020151896858 +0f0dfdfd-9810-9550-ae45-6038138f95b0,554734872,13559748598917091219 +1b992ba5-f970-9c4c-a1fb-3c85a5a74190,223562747,4017260406516346721 +05ad2265-22c9-aaf0-54d1-26f23683bce0,2795917685,13565364863607538154 +4ec660da-12a4-f79c-e47e-ed595b958778,547138348,7669043344891663323 +13f24b0d-dd1e-0f7c-34ed-9aacba062668,1716933194,7076439571261216560 +69abf7c4-3fba-5cd5-7b37-26df33e7c670,2153580643,16965493907328522828 +8e688861-8922-1a8a-2452-9cc2f542a449,3338669841,5893521605528382033 +0bd8eb70-41e3-2f1b-cd08-60c65fe1e277,213567150,16721561378547156884 +65b608b3-15bb-c6f0-56d6-30542c76a506,2144542775,5632658777485935398 +cea70d1e-a7fe-5201-369d-66dfa0e36c72,3386576584,9159277077064033541 +2f9ac081-ad49-2eab-aeab-38577cf909a9,870963335,4240670832942636211 +78f4aa9f-984e-7542-a149-a78352d5066e,1279053041,3275239845480347610 +bb01ff50-0962-8944-d3c1-fe79544608a5,3451054613,3903365748834231774 +1809c08c-aa47-8538-a3aa-6eb94db69b63,414583798,10596404070561399542 +604b9652-768b-9d49-6b4c-9583445871cd,366805407,13021361997404575150 +8cb0a345-e30c-81a6-865c-d3f21dd90b88,3748359094,2043762411134069342 +a6b0c740-ab37-d62b-2670-69f1cc2d9299,4209220884,3933456384854627133 +d62415a7-8a33-5142-6c1d-3a3ca168d93a,493941320,2599795777149375596 +443a2069-d0b2-ed0a-77d2-36bf2d2c049c,3974756315,7777550774679175282 +2a9869c0-71e2-9a04-1303-a9b657d8e8be,179831028,4965719848856631399 +56d78023-4267-6cf6-d33d-df546adf540e,2103326529,11468183347845541832 +5ba83697-4f88-aea0-7282-7a05d6f6c829,1943583971,5810053955676223748 +6a7170ff-f8e8-5d8c-7d62-475b2c5d001e,3314014389,10408330392665934161 +bba1e636-f76e-adcf-5d60-503bae48c137,1330214179,4429239327784321405 +6a04df92-d234-a080-976b-2a744fdf83a3,1702509010,13361073336842792718 +ad437d34-f314-ec8e-2d78-7453c9a849b2,2003790499,611027445606133936 +3114af09-c127-a819-3a88-df3f8d2df7e8,584372088,4196105011070294003 +51eb045d-5068-458f-3b1a-e00cb77e2a89,3691068154,4864344358827147997 +9a0526e6-b629-cc5e-18f3-7b4054af6455,2808789797,7331930163370767981 +3abb7506-0ef7-024a-d63f-e51ec2dddad6,1747415065,16661429384341644511 +b34e9001-330d-fb74-e530-ab8d7ef4aa54,1265484962,11129808054864896813 +2a174557-d8fd-6076-0fab-1249db4b31a1,2163019483,10850437818796910271 +c9d5e85c-d0b0-5e41-d717-17cfd21af14f,3808741085,10849790697033504271 +c34c16db-d013-2589-1aa5-433fc9bcb466,1882477977,212967417520299133 +887dc507-ac88-f2e6-bb27-7230298b7e5d,2985998964,13630374418395425291 +7537ac8d-679b-9eb3-0927-ba7f7bf59234,49376887,530216796811814979 +248f723c-d4af-a7ee-dd9c-857e1c39c8a3,2718351706,16111660361873732830 +da937980-9817-fca5-6ff9-5cf7f418b304,1341735189,16906864655474790267 +a4966814-cb07-fa36-0ed8-63cdf4542a5a,2713886460,16117751473549629449 +1c4799c9-bc78-8c65-1e82-926212b7ea11,4228049991,12675881094633072243 +2e6504fc-4fa6-d0a6-77b8-a0c9181d78ec,1746536943,17672452409594499311 +c6515b50-a0f6-a481-22c6-1c4753c8d4b9,3802099984,18199090598161494846 +658100a5-ebc5-39e4-6f04-3eda9ec95b26,1200844905,13745073237804407192 +3890fcb3-eb69-af12-8321-21804560f9ac,1909584295,5523738196012765429 +1ef6c5a9-8812-0587-c371-8d85d4fbdd9b,2169345231,17650613396745143728 +413d06cd-3370-b03d-c89d-ff70caa4a3b5,3905225741,8210530549339504345 +5bb8e833-9ff1-0f3e-f44f-93cb4fb27d24,1094393209,4220847562970267547 +5884533c-e87c-8c23-2660-334a6f9d0d13,3446943241,17235297328879506845 +17841e9e-efe1-6473-617e-372c37325dc3,1314700159,9075710323865470041 +97d586a2-b33c-9a19-3b83-01c5648c1d63,754718309,9019908390009302030 +05bec7b9-3d01-8c93-fe65-f7ec5d4ba3ca,2114805122,9024674443953901225 +883a7f52-1607-7e3b-202c-c5b8bd3b0332,1707598344,2588880421341329530 +13e52eb8-88d5-b0ed-1988-6b15630e8118,1077161682,2630130877119553937 +df873476-7736-8c2c-80a1-0d5425c9723a,547047320,7601914469048631251 +671c5fd5-4d6d-ed5d-fde5-ccbf2774cd17,3824517814,8825506109858427758 +1bb679e2-d082-72c4-f518-7cfd88e19a6d,514504566,10382608819955323013 +58232af1-ba63-3388-d597-a3b103b1f12d,4181782225,10442422334263980781 +9ef8a06b-0a48-9ef4-ec96-f105b827a9b3,167844121,12719232375808560035 +fac5c519-c2df-7ed1-3191-ee8a009dd17f,3925169218,8981360705696010847 +c0ca24e5-540d-6514-5d6e-f18ea4ddfd11,3022243961,1787136159963545198 +dc0b5581-30d6-aebb-c008-d9d13b2a3a65,2218769163,437289441612139750 +8f1fc654-c9db-742e-9088-a5d333afe119,2832196952,13190355561591026827 +f002854f-c42c-79e1-bcc8-c429f68e04f5,1262425250,17807166057623252021 +cdc5973d-98f5-887a-3b5d-ab6d0f831550,3712285876,6192253127741899097 +dce9dacd-f7aa-ba9a-4962-f11f3e84cb0b,2534747341,4861033700246293791 +fadd295d-bb5a-6d7d-b91f-480af76690fa,1264198082,16047006160105292708 +58042df3-99ba-3e69-958b-e6a0079fe7a4,589340352,17454177067197590949 +a35cc039-53b3-2490-9b4a-3a1a673ec500,2824704839,1839800612081845550 +0f1fb3b5-fbf8-7009-9ed2-b9e450dbb01d,307952227,14869098729135471894 +43215efc-b0b2-35fe-b5fd-d6b0d5e4d319,2206763641,11916407625660197026 +8aced883-2e59-7988-c15d-ae9688315246,1191526968,10311523557711844980 +5a31e522-98b5-fa2b-58bf-5abdf4b610b3,3354167950,2109861198018416573 +667c7332-40cb-1e4d-87ff-f7773f437b74,1816719869,16293287098201872737 +1ab4fbde-13ad-6aa6-4f07-d5cdb8109105,3042280090,14768493999406242104 +65e76c79-1324-2f83-8b69-745920327409,1592686390,15383031201769347875 +9aa4c046-8308-dbfe-fbd7-414c2a8d3b68,1338020579,16816471553752398168 +5f941768-b5af-bee6-1188-2d7fa02f2106,3975869997,1075923179478703044 +dfbe3af1-48c0-860c-3caa-f7562fbf4ea2,1793414539,16452643609766056841 +9fba7e19-0b39-4fcc-e6e4-777c44ab5ea1,1072746922,2375375491166426632 +18dbf112-bc75-92ff-31a7-66962b58c435,3403696549,3450475063871082557 +68ed9dfa-c8e1-b588-ff36-a083efd0027a,2074087081,15007188789005559670 +2b88647d-ad9d-6137-c9b7-1ce264a5fe76,2340867751,2868586807178801751 +9d21c58c-7252-1fdc-c569-c8ae353afdb6,808763011,16848639166202305293 +f8975299-05e1-90d0-e7d6-c893e8d65cac,3834813148,16634042673272038528 +2c6e8a60-f117-2118-a56f-9049a8905bfa,3057787229,566857477288793227 +b2320e3b-7742-7c25-1930-c3ed76cd2f26,723603226,11884993160939588824 +1bb392da-5bc6-c489-e1c8-404cb449dd9b,981765070,5371035514268540934 +069dafce-bb69-b10d-66bf-b2d7ba57f06c,2633764104,16549636626241510882 +9a1bbc65-e7e8-15a6-8594-079bd9e268b3,1261073785,2541577726616775398 +e2ceb0dd-e06d-7b53-f7b2-ba9b0eca0ba2,2618056959,7033174577492889861 +a452bd1a-d3c5-3abd-ea80-2a8ed4a680da,1113954968,3679492257421505267 +dde546d9-31e9-ff24-4051-8e1b85c27b8a,917851510,17014272118323581297 +db8e3238-6204-a079-8099-8918025c54e9,345530579,4704753439591793061 +9a338510-5990-0e59-8227-1691d9695b6d,744430681,201090654810041628 +762b978c-3031-0947-47fd-f163765b63a1,586871331,13349106697270988271 +837f3e38-23a7-d9b9-594a-0ba66109a777,2475338286,4126836852669306607 +5bf0ccbd-d6ba-34c6-04d7-caba6b89ff71,769066816,1314775384940515991 +a6d21aff-3706-11ea-eb55-66130b89254c,1189578248,13979651295566070626 +1fe19bab-cb3f-823e-0d4f-8bf59b039ab6,2588865236,11128230033381065277 +3e2261cc-3fc3-5070-061b-f47cc5f1fb56,2752099976,10914577857139065415 +26344e75-1674-022e-ad1d-4cc618a2aaef,3839013012,14372541074558642032 +186eeb75-7eb2-b22e-fa32-9107b6afa38c,2229282677,16584443969832806126 +a111d230-5cd8-e317-1b8d-c70d57afb5c6,2748461001,16824141647945028768 +728385fb-fdbd-4d1a-f22a-c7ff4d326a3a,1471125959,2028857149147418636 +a73038e9-d68d-536c-e3cd-ff2163030edd,1288563281,4735117446776548560 +335fbeee-71e0-3f46-5b46-584169de31cc,3374744805,1431341277122908860 +740574da-fcbb-91f6-94f6-8fbef4737b19,3112120873,16059721890274321250 +bc19a467-4c4a-768c-628d-bf4a16b3557b,850900057,10672841651214370305 +0f1d1e98-a0f3-45c3-2f1d-f0005569f920,4073698091,3935117856334973665 +6e35fd76-a504-a1e2-d1a0-373f533957ef,1560667697,8494877916207713738 +7dd4bfb3-401d-f3b0-3a7b-b62f82b312ed,2576878092,8627407632521410072 +506d0c4b-2fed-a64f-cbef-acce989670bd,611547627,17637654430447928704 +428ff3d2-d8e3-de32-19ab-2c033b585ba9,3607331468,16607604340907246140 +91a9873b-2912-9b82-2d2f-25645798f0a6,748575681,2076731796338232742 +b34e8aa3-f36b-f091-9e7a-427fb884adef,275637775,14007101476358530793 +efc8ae14-0f69-267d-6bed-41086d48266e,192566162,12925738181658022547 +32ba026c-9c0a-29a9-caa8-ff5fc62f8a5b,3603662924,17419345846544131520 +098c6d9c-d13e-98b6-57ad-27898802e0ed,1583886242,12834899393687326054 +974f1303-0748-60a0-32af-386894089d0b,3347579122,5715893856383352167 +2f707dae-e464-0fb5-2e5c-20e8c399c216,2170706624,143782392265055304 +b5dda923-6b57-323f-82ff-2d0cd291f201,1273851871,16683111534750353785 +10438216-a943-2b91-c91a-e96fce18cfda,3900714271,4261452314276233014 +141f2320-fae0-2614-8cd3-f57a8d655e7e,1390409232,5107106568150460311 +fd474e61-8594-5fdb-d6bd-1b7a35a38d59,2303803822,1790554001825464848 +e3580151-3d79-8ebd-7e3f-df5763afab39,1849640580,3052271401301548861 +34cba179-0b76-242f-d7a4-6e7f78d87f47,1802947856,8898823708708300610 +cd7ca694-fc94-a030-64a9-089f16e49117,1988432847,14974630856641121162 +5fcac71b-bea3-ae2c-7c5a-13e0171612cd,81520404,7697496884948583746 +750c289e-83ac-a2a1-1363-b5e43b1faad2,2144479520,13921101353716073125 +a300f33d-2cd2-cb32-1549-6d58353eadbb,1593229574,17239746681822979138 +d6978ef8-3f52-e2e3-cfd7-b036a37c8520,3972083699,777411419370873330 +e1afd279-a897-8d89-6989-79d0a337a8a3,1584893637,13005006539886288921 +c8c5161d-b867-9406-e65e-3c71d97867f1,1367471465,5227834651658960582 +0f7b257f-c5d8-089e-b6d7-8be93adcbe92,1659701442,15626518544976168560 +71477604-366d-1e63-3f24-c38c6881570d,3400950317,11604201852502313442 +a803a0f4-63f8-4483-67df-f35382caf406,3950478757,6907806068674018498 +08b60c9c-e344-babe-85c8-987e7fb76a74,3085407711,12211373260660565415 +1c11e19f-7baf-e871-ca83-1d7f7b8cb2a9,717777446,13284700351786048030 +00ac4315-05d7-8bf6-7ea0-d9673c9d0e53,662773936,6966882813440798633 +c757acf3-2f89-a364-57cd-49c83b220b37,677578341,7742437405125681554 +f7cf686b-c20b-6bbe-f29d-5157bd5165a6,2456541581,8501870991622081175 +0a5aa67a-961d-6fb2-7701-cf6ceb8cde9d,1599064497,3169179236640739016 +1d7788f1-a1c8-db60-d2a1-31079e30956e,493434407,2697928983082261658 +6b16bcb5-45c9-94f8-5967-535f9224dc4f,1434995339,11848747822711532433 +9c335204-17b7-4c70-81e5-fa44cc7768fb,1539253354,15148897179124516093 +8ad489c1-350f-a1c9-96c2-dd8a283f9b80,993629137,14120683775589475281 +183dc5b8-42a2-bbbd-7270-c6754219d206,2336653583,2658564046181862819 +d9cd80bc-71d5-df9c-0d23-d07117910d6a,1134705372,16799335698761668639 +60cce724-9dff-84b7-af53-09be3dc2b6be,2635746994,10592255423842214557 +9edbe0e0-d42d-d2fc-ddc5-6fddd2e5a350,3016347217,5813870943363065221 +70d912b9-1ba8-4a66-0626-a270e6760dd4,1734067219,13811642363568765085 +c563cdb0-3c93-a83c-c304-5f5d2db6a42a,533891756,807653224432100352 +e21e070e-9830-dc0c-2592-76208cd7750d,2513169905,18061899841254571720 +7490c9f6-b836-02a0-97a5-3783941df32d,3556751917,3364474321522565683 +b11a1040-58c8-921e-c292-cc2372e3794d,1593041836,8834138574458642948 +7aac4855-7987-8834-2ddc-74e887f25875,3575585737,15888379631172748716 +640ebedd-64c5-b42e-15c9-1acffadf939f,1281386037,11747730499362268339 +bc3ad140-ed21-8c94-af9c-11a314a26f16,3609747391,18016791061908436164 +0ba608d9-a620-26bc-b45a-84cef9c37ce6,2959154403,17400135356735034543 +c14c4eb9-5b8f-798a-6ed7-b06d0ff10e1d,234504964,12921588165617121469 +84eed63e-68e4-d59a-3999-c912acff92ff,2140158130,17837202638561707166 +06932dfb-9f88-a831-906d-b7a0d116abe8,2972465990,15690634286567221016 +f02e0c48-6e24-94fa-7a0e-36faf46bcd1d,1115589019,18173177394265645530 +cd060c5b-25d7-0c9f-41c9-6a52bef684a1,3999416803,15523415202525442606 +b1a81be3-4924-1715-34e3-29366e7ca962,3792401103,785210625949958387 +3dae30f1-c29f-5cdf-00d2-1edbd8c63ac3,956444375,1630882771160504746 +35ef4386-a422-2a29-760a-4bc9f8d37e89,1983263128,17384532455663327638 +1e0c39d1-46fb-461e-4b23-eb41bb6e20c1,2956859041,3362677932822490527 +fe34c34d-f471-bf87-31b5-fde30330411e,2968832923,11978302592659061897 +f160eff8-c953-875e-d4d1-5efea0f26d23,3068877236,3061671032600403509 +230518ba-6255-314c-57ec-0f01dcc5cd4c,2662141355,16653544069482507836 +91085d77-162c-0cd0-25b8-dd1fb0c53037,3795777922,4620527265369346606 +ecfb0df5-85b9-ba87-fa08-51f5d0e5a2a4,2514435307,14962165032394683125 +b63d6574-f44f-2c3d-ac41-47ac2993d57a,355179850,7390993801337529470 +23630346-6595-3a8b-ab8c-5fd5cc34bd3d,2581304408,4029690913857449293 +fd92af35-26f1-6b4f-330b-ef5a461e1f5d,3844434640,15238372553067134926 +4655aeeb-f358-9157-e28c-ae4e71d0a402,454230234,12478901303743213740 +625629a7-8d74-c0e6-5ec1-e9ded3ced89b,2532201606,7527377289996062858 +22b2904b-0112-ab75-5a1b-ac123c5e91c0,2847475134,13842461139070821471 +b1613352-7fb7-a29d-dcb1-fb23cf7f3d78,669781934,5547809245532580743 +3f3d4edb-3fe7-84e3-f730-600bcd5e1215,793391238,4807814312987848257 +21a280f9-8dff-47dc-1ce4-6cf7c3b1d5e9,2006932123,7586879053976939032 +0bcbbe94-bca8-3864-e45e-01a2d800cc0d,1924330192,15173001306156472485 +9cb2d0d8-940e-d307-a5ff-159cc202fd8e,3471877017,769702583321727764 +a2e42f63-f835-95d8-627e-2f6372976cd6,158334331,17116779380889605190 +3ca50540-f3fc-ff9b-ca19-3520617674c9,862360073,8335486163951974999 +44401dd2-9aee-85d6-ee87-c09f80000bab,3304823024,14510939711457081055 +851f8792-daa9-ff5b-bb08-0973e8739b05,2881447059,584855998825222307 +01f371ae-3e44-f882-0976-6d96a0e0bc1a,2150171880,750358728879877545 +784567b5-e963-f78b-3b82-b8a93a5cba80,541004861,5850046684662939769 +1e40a5ac-0efa-8ae1-fc76-b2078f9fe1a0,2504464478,17122835905056778079 +7211f2be-0dc7-9eb5-dde1-c73d031bf29f,645142600,12500509742166209723 +d5211972-40c5-7c20-696a-5bcfe92da8d6,1285754771,10080685564673362366 +5a5dbca4-ff1e-204c-c9af-5b71de7f8df9,74493374,13298545065100235880 +f635844b-a403-b624-cdc9-cea0c98d4824,2268908096,17020142442960387851 +396c5c61-e3cc-a2d0-56ae-a0acbc6d6a8f,1045248587,4242327917418344064 +0870236e-a6c6-04bd-4e49-9aa1a59bdc0d,763555314,14156638075644641003 +5a2175ba-af50-9c44-48d8-f7845ec9cdf4,464956753,575868973838987430 +38f30dcd-014f-e8e0-996d-014a32948f40,2410524097,8763985268687032827 +b98996af-b91a-5c53-c25c-6e0704be1731,2600814388,7423028080267915581 +a64f700f-eed2-daaf-51a4-8abac7f76bd7,102781851,5297616880202102215 +0d5fd96a-2285-b70e-e3e8-47c0680eb6c1,4185041704,2794634361231054936 +1fc381ac-50ae-929b-c3ab-b87c2fed9bfa,1032819986,8812555837877489157 +bf486ad1-4e5f-85d9-dc5e-ca451d061880,2469034967,12330841006031838834 +da84bbac-c2f6-5c71-91ca-43438b92cf3c,620972973,12472526443394686168 +38dcfcf6-27d6-ce4b-53a4-b2fd8e2a1c0f,3347549006,9784879548969704508 +29bebeee-2221-fb75-91a0-97e793ae42f2,1271879368,17514490929826277559 +1696dd3e-a618-37f8-ec81-0ed940e8fd9f,3495469203,3445946031747272596 +69ee7d7d-29fb-f4a7-c295-3455fac19755,1242408861,9993679831049897834 +ebde319c-8e20-7787-6ba1-3f8ec4d7585b,4256158818,16785556566312067994 +74a1c4b9-a89b-f1b8-09ca-5320048b6b10,3267310223,7505634958608623113 +e7c198b3-cc2e-eb68-b08a-af8445823bb5,2501368937,9504961238203486581 +6e4cc8cd-d819-690b-923e-9bb6cf54b587,1360478144,17105882354274947549 +4803feb6-35d0-6d79-46fd-6bd876f50949,3971836961,2161202127342767133 +abd09834-63ba-169a-f613-d371a523b0a4,845675884,1362456096345782865 +1339a221-b3f7-1663-cf87-02ec190f9c1a,2446398731,6169431766355756300 +ad523844-6431-6fdc-d39e-b1eab5adf9fb,2064967339,7101946859818427521 +4fa1424e-f63d-7662-7290-66a73c5f94a4,1441968781,10951510606371073939 +ca68ba80-73c4-549e-de38-9f846b8bc663,1664740571,9292586206394913035 +a65bb6e7-7af0-4e56-a2ff-669056bf05a6,811192785,14208264568468355470 +21ae59c5-9e09-8f54-e4c3-8885c0eb2232,1602626831,17985137047163129808 +35842363-13cf-ced9-1b0b-c699948782fd,1404455203,4326090337696670778 +fbeae81a-227b-2f45-b5f2-4f4cdacf1452,1144346247,887025118072348541 +c3042964-9101-06cd-5328-d86f80011544,949101066,2665207589057965052 +2db6dc0c-ff41-08f0-1c04-0a83bf0768aa,1044807935,3274446559307223658 +7a4d7a6a-ae75-1ae0-f854-518a498eeaba,1747244700,11240702204765229683 +2ab9b15b-203d-d5bf-7d61-3bfb7bc06162,610465462,8715327060418175066 +d99a26e5-07c3-c5d8-d4bc-f06b88898a18,1926859021,9872855821597069055 +dd7fb2e9-0145-a9f1-ca1c-e05753a2ab33,3584434077,16710509953772836374 +e3e2e05c-15ee-8cd9-c310-60667fa7009d,995747038,2303922384458388617 +59ac32a9-f65e-8a7f-9ece-b1543f90ed8e,3936548097,17658908326336064892 +9f59e9d6-909a-f314-4937-93f0603bb05a,2752614703,12485667594005690770 +66e1cd7b-074f-50a8-444b-6fab55ebaa41,1282008494,2994560561989693798 +61485fa5-5314-7f22-fd2d-b2ab5788b14e,2782853926,1312096495261716189 +91e757cf-e0c7-d2e9-f61e-fa26511cf618,2245683442,16883569438363047633 +e0169dea-0b05-2fc7-8cfb-6a056747ae0f,2114408900,9273870247917207185 +07a69fa2-de21-9a5b-bec0-03bf3cbf7178,160313412,17794883055465248923 +f6ad2eb2-436b-578a-a2d2-76cc1096b517,2814120404,868697581800562952 +754d0500-0ce4-5a13-afef-f2d8b1a53dfe,1744293555,17106560014375176571 +e83ba2d4-abec-e6f5-a5fd-9604200199d1,3664030101,2347883549735845337 +41ae511c-e23a-7f84-26f3-10d35796d4c2,3843815341,14446493081608251506 +57e2c730-0bf6-fe2c-1877-0db807ac758e,4119461380,9590116982785621107 +a9d9c9da-ce3a-1947-9f54-f89e57effeaf,573880092,3019461846105989826 +08bedf78-5d76-b3c9-9e1d-98640aa717d8,1819018873,1543684411238731168 +93d648c5-708d-b898-cc4b-43c2617533d4,3984828016,12842573310412354265 +20ee927b-05ed-8153-108e-b31e00ab6a28,3953661822,301514335926934437 +c8ddbc1d-512d-43e0-deaf-a1fc7c9fec0b,3212411126,18395282687180035843 +e7be542e-9498-33ed-6742-cb54e06ae75e,104428667,14291909541868730255 +7d09c45c-2f90-8dd7-ec86-bbb8a47470c0,1574425969,6814162139876242024 +06a199f0-a1d5-6171-d967-8b093749487e,376776600,15628477924345396327 +21084f5d-9624-fe0f-0d10-6d8bc56d2b38,3165348894,13285367119624002942 +d1f529a5-de95-c5a4-9c8a-1423fd5840af,1658195699,13513830596763615719 +f962daac-6dfc-1935-f74b-dfad2c0364fc,1270176826,12481680964004608925 +048d92b5-3893-2477-d0fc-3dc4be2abac9,3916777516,8371253848097099931 +9fc27bc9-b206-bf25-a5c0-1dd5bf8f9595,2729629615,11435672032735241773 +c433a91b-247d-c191-4e20-94067aa8bdda,791966522,11815818300561110821 +2679bd27-642c-ff31-6057-8433fde37d61,162866674,3422440426042373892 +e792e1b6-e4a8-4eb4-d901-97f555d05c6b,792790565,19317336994826135 +054d74ed-ad39-7072-0bb1-cfc6489e1e5e,1251788961,6961767406978027100 +55212110-22d3-2286-d0b7-3b2d934a4396,1374929047,12528425963347021596 +871e9082-7e4e-2be5-5468-84d70f4806f2,4252429527,15765278164502356360 +b11d05bf-ca99-f47a-6d8a-9e917d2dcb74,1757453283,7002494470340171363 +0fd7e999-63bd-e36e-a08e-13aaacda6434,1656093406,11291531060129038799 +a95e00c1-e5e3-bfe5-b924-c6b69597fb06,2295136384,17175306065813575427 +d6a1c5e9-b500-37ba-07fd-b39bdcf15c82,837031123,15555418167123465451 +1ba60585-9f4a-2bf3-2fa4-8fccbe460cd0,2080525089,9596839209090261266 +a56de306-59c6-cd06-5734-3af7aef75952,1287648379,16397487276403987969 +e8bb59c0-a090-2147-a0db-55b11503d6b8,2241620734,11578183399310527752 +b566db8e-2102-1f17-1dc9-4dabed7e97c6,1529971128,1965680709139994717 +4ba1afd6-9156-ec33-d66f-2d23637aabb5,1382278408,1509341712254885698 +5aa97e5b-3a3e-c6cc-5492-10a45e667b06,851622382,1258249684031767867 +7ec0c759-310f-cd74-4b5b-b786fb7fd3f3,762511077,16849076884968578357 +9e4ec9e9-9b84-84ad-ba62-d6e239ff44f8,1167645011,17205623002755375660 +fe16b503-f40d-bf0c-d44e-617ee4f66441,3210711059,2959626174098399603 +8be08510-ffc5-0bf4-4c8f-528c528f2ec1,3995961162,4292524598275108573 +9cf635f0-7f35-0a56-d7ff-09db501f8fe0,3884983737,4411221890811051418 +167c5980-5927-9a6b-b201-59a713ac1b41,200585539,5124942065262568103 +d1a3a68c-d9b1-1787-b898-763fddd3c620,3000754554,15189013489761295629 +7ab007bb-e1ff-5117-d266-f8165b20681d,3797014246,2364450273797435431 +cebb04d6-5ef6-614d-6f62-51c90dabaa3d,3036790761,16564356947005097064 +fe1f8854-d375-eb55-26d3-86ab0d98f3c9,2751125333,865338203778008999 +b84bae15-1e12-7efb-fb4a-dedcb8de265d,1000497223,14810022081014385093 +26e34ee5-0e9a-2836-d5e7-984686efe366,3293142471,11418293606775521666 +3eb34eb5-433a-58a0-fcc4-45148b268c0c,298285919,16116445947545370530 +2730eafe-91aa-2181-c11c-a0321841479d,842929961,17351706661833956083 +a3a5e349-a3c7-7e4d-fb37-0c8439e56546,3301976715,18068405568208046560 +e7e4291e-8d8b-cc5c-dff8-98f780b85307,3747149964,14800819828992383997 +bc4cda52-4087-2585-edf4-7c68c9f307bd,2870730955,13159880256486894667 +0f194fe9-aef8-77b0-3ecb-dbf315362763,3028028594,10207888294437366250 +efd7406c-cc41-74f3-6d9b-7516851873d2,1265472037,17466741699421491080 +9094caf6-9ff7-0917-d170-3a9b2ef4423b,2247461836,12511787690875690849 +cfec864e-d034-61f5-38e5-e2e59035942a,2235447738,11646820720098662914 +4adce007-feff-c475-dc67-1067477b8ec4,2321268908,7925040134118488643 +d988fbe3-2eb0-2a90-2491-4cf5e5935b74,1456663625,13115951101399279972 +d289fd92-b79e-2aad-7ee3-98bb31e02c33,3578896435,5177896600209473354 +665e19c7-e8e7-a182-b2c9-95fc862f436d,1902527196,12514373458109717660 +afa1c52a-14d6-3818-1bb4-d2160c174aff,2753615387,5952937356025745243 +8d101291-78fd-54fb-56fd-f5ea5eb921a0,4006045935,9994138440080809047 +7d3ede6b-4672-5274-95c3-8a05d0fdc5b9,2308357908,13842022622989285515 +816c2f36-0f3e-e867-a861-f94615a321f6,694246312,2824491822806503475 +ab16f6c2-3449-e3f7-27fa-b1baff75ac4b,899927396,6342444297120362010 +2aa127c0-4e53-2b87-f5ff-a858b1cdde9f,110333238,12800527146473051367 +fedbc8b6-6c0b-ed36-c75c-78020d72572d,1410508199,10926932290150822252 +c89416aa-8b4c-c0bd-8bdf-d3eef4a43a08,4158870177,5319272498642777357 +423a02a7-02bd-2f3b-329d-a5ce0b3c3f45,366026388,16398296654288890088 +573a818e-14e1-fdc5-c7ee-25fb8002f8c8,2853269411,15387698900658240374 +ddc377da-feaf-9e58-02b9-b5d8dccb7b27,3838616796,5355505023284597457 +ff92cf12-88fa-7c82-7ebe-da11dc6dbe83,815780781,15023358287447042804 +6abfbc23-129a-e8c9-b7f3-3df119461a2b,1160158626,4549917742774309834 +528eab77-85f7-bef6-57b8-fb794afb0535,3149636814,3028921038333849919 +242dd0d1-b3cf-ea6a-30a5-c405cba0bdc3,3156031995,10326974783738008936 +ba5b4253-88d4-4e4a-64fb-9ca4eec811c9,3498905579,1081665383866783059 +68f4ff5a-a67c-7ff7-517e-cc3469ae0f0f,4184306894,18017987388474006072 +aa02489b-2152-5f68-ae7e-e5506625bc27,704190543,6362133328953052310 +03a44306-c4d4-fd29-969b-22446d6df008,392143350,10794548663487424195 +beb77357-e4ed-826c-c69b-a8e6c8fe69d0,443963275,9230827350698653050 +a1ea5f2d-d0bd-7a60-4ee4-b4215e060f5a,1929037939,1692606125920400265 +6a02b1df-ad7e-9bfd-a0a7-c25d7a0ce5d6,3660632395,3668392881219338209 +1f558512-398a-3c25-842d-c4450b374b81,3047571271,9572405880164928973 +bca9f47a-dfb4-d847-81d0-9a12b6ec00ca,3732738513,7947197098969825657 +e92fa874-0a34-987c-5706-77e01aaa3d83,166499827,7956812068237374221 +2fbbd6a6-3a11-291c-7260-8ad66ece7e9c,3797344872,2446075633575910909 +b63891fd-1d1c-3f84-dbf8-6f8e5aa741a3,3901078554,10314989605374193640 +802757d9-4a63-49de-4b6f-d59fd091bff4,4139408207,2240008264589131023 +1a71da6b-7ef2-c808-96fd-a6fa2de265cc,2973329143,16200293976218626619 +fbd0198f-c694-b75b-464c-c3db07c0b8a2,2729341250,12019078145662328501 +b819019c-790a-234a-2882-cd65eb795412,54513900,6276529672299818526 +10b91fd1-feac-0205-5118-ae75b7c5ec01,2415316396,17188185971440788717 +c6cedf38-c85c-127c-baa4-4d7ba1359cdb,2103442407,6949401549591297225 +7e1f250a-91fe-04d8-0d08-690734436200,1958623535,3166359760139099102 +8fcdea36-10b0-903c-702a-8bd306a86085,4036263459,13346563732558267214 +79af04e3-55a8-9132-b155-5b9a7e1ad51e,4022754110,12032931811751994493 +0cabca73-76a6-a7ca-ceb8-7d7dbea30553,2526653286,13355794107797304597 +59b067db-5210-0473-dfe6-9425c010b826,2374790220,3048749213356400097 +3ee51ce5-f019-289c-308a-50e819280e8c,2812245942,859191942548110187 +1c68096e-9c9e-981d-513b-f7d031564919,1065581890,12932536581199059199 +98809c31-23b9-5d4e-7725-bb927715ec79,3646931563,1965815421581551414 +df1c5838-ca3f-1420-cb5c-cb30f2180982,2495781891,3450810696945119793 +cadbe52f-84da-1542-999c-e6f78b718c4b,3642400482,4937650656022072045 +900a341a-278a-90ad-3de0-27dd25f9b724,1629244301,4625673185069459702 +b9bff808-0183-60fa-890f-d39fd26cddc1,3516601382,9796672737761530026 +b543ae52-8393-48b1-5577-7bd27f86aeba,97932105,5527240556329805233 +8f3eeb9d-c53b-f4af-5570-33686d719c52,2309712193,14568145881290698419 +92a0011c-b78b-d007-1768-418da5083e79,134790565,5000020863991002027 +764ad874-e3ae-7795-512f-bb4e60992918,3936247053,9362004812844169734 +29eecd0d-c4d8-b8bb-2de9-853f2c870f59,1114561073,9840870808982259222 +e5ab4fb6-f13d-198d-4931-93869ba9caf1,1052943203,4391636753540242541 +1defc04d-9768-f671-8a14-61b57db86692,2661951468,4346900052772244217 +d44ec569-62bc-6b70-1505-a8dd7da2ca63,2914610161,14941689917393312155 +28a25b55-6511-b85e-b807-09692db963cd,367609937,8191180834527273058 +47ca8e35-a792-660b-803d-69efa680a7d1,1314155477,5889141576939179696 +8779266a-2f50-bfc2-2c51-abba559c8f6f,134380272,12674978118593955841 +355bb868-72bb-34b2-ac74-8f50821272b6,983699113,16933368317205816246 +cf7259c2-b913-2ebd-30c4-bd78bb3e973b,880133262,9392748397266666390 +fb3fca6c-4935-6211-88d2-2a67f08fbd2c,3223990312,1171483095173653357 +8de8ac6d-eb62-08ca-b395-c44954d47571,523121498,4292061148720004607 +18ebfc4b-8926-1e65-7be1-6504339f1990,3362807890,16967636498413679333 +fda95f54-1113-a40f-816f-f99d43ca0824,4271162382,5050669600783318192 +dcd9f8ce-2a82-6d93-148d-c69a12db2ce7,1552221200,11840160116437710 +ad464bda-3d5f-5a9f-4077-ee29c15e85af,216145414,5863283255276435753 +947d0cf5-8ba8-0f68-2e3f-4296051a18d9,2958342101,8527206541035866296 +c5fd9e5e-5591-d703-6b04-404388fe87af,653950443,14689639531249348787 +3d8d58c3-1753-f9fc-3912-6accc29667da,1641807078,14253506048285127293 +d68506a3-492a-d71f-37e8-9f93c9ef0f32,1365458993,14052716124784292450 +58324ba0-6315-c55e-16f1-384ebaa88f5a,576618388,7001675749935040070 +837336de-8b6b-4d9b-8293-4bb2624a0a83,3800947154,5695277229983548419 +71bde793-7c27-e9c4-0532-3778013b25a7,2842216435,9428802767329742253 +16c82364-4d53-e58c-c094-530580bf2a75,857341698,17673764232120367155 +ffccbd06-e38d-5eef-99bd-cfcc18b2f77b,2801479017,10870356961040198191 +b8f1e26d-f237-7aa1-bbda-60283f03aba4,3973361214,6075055912485051693 +dbd9ff40-e92a-a883-5a5f-d03886620813,2201540381,17654207605882547819 +a8cdfc73-9424-54d4-b801-f2244159af4e,3534824912,13395497584673490994 +34c433a9-85a4-6963-bfff-b4405f5e2e7c,2471114518,647932309980540316 +70b7ecfc-9837-ad05-6d20-4465803d5327,3792687187,12190066184922013575 +bbd443d2-112f-460e-7728-06be7c8f47cf,1441321667,3383807203587189767 +e5a1351c-0f2b-719c-0cd4-e82ac3b5a411,3862779073,6383407495723524406 +26b1e3fa-addd-4702-bdfc-8300531733c8,4047280261,16169737326563717198 +e283a0ab-0ebc-392c-8869-89ef0905cb52,2465804292,12180298512669899623 +b3c9a6a0-bb7c-d926-56c9-7c5daeb00465,2129594648,11447295533465771005 +17b8349b-5e5c-dc24-5a42-4059c6646719,23723862,12350324433996974074 +11339007-0db8-155a-03cf-3d8d06597669,924803264,16582210085533953338 +f6ff9e39-be8f-a3db-72c0-2a9d5dab1f7c,2888551508,15448878287961722464 +4110fdcc-82be-7cd4-e231-d93459e19682,2535265030,7563870632538878130 +503c4e09-1522-56cb-36c8-0c5c6482da4e,287239838,3557645920085338931 +6352f5c8-1d4a-de82-74fa-b44e3710acad,2233307459,7102971732631285987 +a4d64776-bc61-bfa2-74ee-651785917bf8,2405097298,17020192691170390125 +f7554252-f76e-594e-923b-94be569e9974,3259735640,17805160403595380575 +b68c674b-6f15-25f9-266d-42276c863081,3002411218,8654498028321310310 +14931162-fb4e-61e2-f24b-eb13b81c7890,3611080635,10917607697301622243 +9cddf34f-37a3-9e1b-a69e-e20c8e17f1c1,3035965965,10688576619206098812 +147b94d2-5fc4-502d-f622-c81b07415c36,1792557086,11702597920919668591 +b325f64b-2386-274f-71b0-32cf2d3f4efa,555292069,17153914361631847949 +9a7c95d7-2841-9b04-b040-d137029eada2,4213711498,15549341159797444070 +0622d9f0-42f3-6e3c-bd29-0d4b99832473,3756810818,6949123854934103519 +35fc1ffc-be96-22fe-c1b3-3afc735ba350,1725836491,8473680075096562136 +53541d55-eb37-2759-e0e7-aed15ccd3667,1460697707,2787325042851680983 +62ebb0eb-fe5e-e27a-10b1-bcae38ac0eab,2289807650,1833097691242615003 +4e6168c6-a1c0-af18-2bc6-06f2b91247be,3750906688,4296068139963602654 +b813ecad-c237-5919-36ea-5b1292b222d0,3934887016,1268043412466099940 +6feb17d1-a3c1-aafd-b954-422ca35da7ab,2520416048,15554775520608893495 +d9e3b0ac-eaf3-b3f2-28a8-9b4934b170bb,252605232,12653157007121009187 +4408f2c6-3732-7b6a-c765-275c54f10d86,1784468703,9921833803056655604 +601462a2-f56c-93da-3843-ef699288f8f5,2246542767,7210071769245601470 +0d23c19a-53e0-46ab-e4f4-409e5a349123,789923417,13998156378088509627 +1f2fdf55-740c-73fc-5cac-187ec39073c1,3846887016,7346631416995090574 +da48f883-8224-2e5f-aadb-f61d290dc3a8,3433062224,15091908610749431594 +1e92a6d9-c817-326e-f2df-47c6f0e9dabc,235655976,17602840420679634809 +b09a57f1-926c-c986-34d0-c1c655356bba,3471058332,14859992256174410455 +858d7437-6b0b-f863-b89b-2142fb5360c6,1621887128,2674802529880995306 +bf025159-d479-a290-a3b5-f59ad23f4d03,1959589800,5357381893308353969 +0485dd3e-dd14-d15a-dadd-f72c94bed366,390054199,4156811748113237938 +152b9588-aab4-411c-4504-eb06a0fb3d55,1861925873,897120055361864451 +ebc3d9f1-40b3-1a69-0c04-0e62afbb03f6,3226614407,11615467966619521637 +7129ea3c-e8e3-3770-c967-5fe30fe500ed,3586754648,3625458819317190580 +2df94c28-3e88-7c61-68ae-892fa1a6b9a4,1179477767,13283512518220115301 +ce05ef46-6571-ea26-7159-25592c9ce379,240182643,10920602645789964755 +307f08cd-94f1-b368-988f-1a5577e60367,2352290694,16972074748517092278 +8a9f42bf-f331-c4e2-a1ad-ef5de9f19781,190874937,14634705424550335717 +a92555c0-49f0-c333-c1c7-0eaca7e62a5d,224459114,9788602448379339507 +00499a56-3d2c-ec77-9cd7-fd816c3f0182,3443402297,8515956472539802538 +0a28fcbb-c777-4cd0-ffd1-9053b3399a30,627893371,7135311549493449890 +892764c1-b5a4-d645-89b0-f5e2eaed518e,56198025,3468489444716603169 +d73ac5ab-9676-b25d-06bf-ca42fd624141,2062632522,9066440079779573339 +32e223e7-f26e-09da-b54d-516c7cd9d4a4,384752432,1657153746380402977 +0a34d9b8-f0b6-b3ad-afe1-ef2d31beaac5,448548969,4346502800086844722 +f6134b36-af08-35a6-548f-63c10a220e78,2046382790,8637943349243570370 +ace63bae-2cfb-a0bc-0662-70027923182b,2060900992,15850206441718948370 +2693c8f8-26b0-d447-0f36-275e549bed90,3089589268,2804474456429620812 +71aed1b0-be75-5602-1fdc-5190b19f86ee,2616916619,2684129550447532937 +b8086e64-986a-6c29-23a0-9db2eb10c443,3753748736,11491078966667826549 +36eddb7d-f380-8531-b3dd-5770baa5424d,1307413993,4038098054330890611 +f4ed534e-255b-cc4b-5208-c5dc6cbd1f3e,3754454500,4218659466205859840 +47e91f2c-48e1-f028-68f2-69b012b422e7,4069146773,10147377378816771482 +86f6123a-1467-e675-d4c3-64f6129281d4,855131238,13415156737163959748 +baf73d5c-2917-3e3a-3362-4f52f6895937,4154586281,4440372984944071145 +419f2b57-83b5-d31a-26aa-5df72f91ce4c,2067698304,9324391960662419949 +b511e943-4f8b-5e9d-e73f-2f50d93227af,2017297098,12445030965255166320 +dbdac162-ebcc-c42c-5381-36774e263485,3395140418,14468030818798630962 +24269bcb-4ca3-a92b-eedd-f40ef2069dc4,779500811,5721892734946547973 +e3156fd5-a664-63c0-e3e2-d54522f16a9d,3793302831,9189019528858677153 +1bde2952-41a4-4cbf-1159-5b6077f1f7e2,2752481650,15376028099129349511 +2c1cbaf4-d160-a690-dc37-152fb3529e2a,3942443502,3723289297669113305 +e15bb376-075f-f0c8-5b72-22b5795fc2b5,3463154093,895962686954908636 +4ffc3c57-72ce-8953-f4b2-02474c1aabcf,846169120,4494094594370965168 +b990b99f-22de-223b-2a58-bf5b12374d7a,3852236890,13442304322380163661 +3ba391ad-8eef-d180-62bf-a7c4db4526a2,2352440586,2012032434479302443 +b40e32f0-74ec-1e0e-666f-22896e374fc7,890747033,10584410546082028913 +1d464bb7-75fc-37ae-94ca-d6ceabc6255e,2196882147,9591623630746742813 +92b65bd9-ce29-5f82-c3d9-3f1657ea28c1,1717179597,605230012429166435 +885208f0-4445-3c80-5b43-b00aeccd0ce4,881258268,13500300512902305137 +5d1d78ee-30af-7a82-3758-1ec601755a3c,2482531172,1511603078682392662 +8e495b90-49e5-2264-9e5e-11099b8411bf,1245362217,12700595246941624394 +71142367-d099-7ac1-2875-835abd5cc885,297771693,16327484088931060154 +62bdf6db-1507-e826-5853-923a6f3c7a87,894159818,16741901929772904922 +42e3a11b-7982-6b19-bb25-4061f7f6d597,2818912247,16965017306486896857 +6b474710-4b21-5051-5682-7b8dee0c49f5,94864237,5708951085648182904 +7bf440f4-1913-8c74-52d2-ebdeb9c1e8da,1896171629,3510550284153956034 +f3db1c06-35ff-ed19-fed9-a1c25b48ee0c,217380218,14848360633277128562 +18572ca8-495f-efae-0979-0a73ec39afdf,784795245,2823754444937797572 +a05e6004-e6ef-3856-ddb2-8f4aa0477858,4098491491,16929754696246808097 +1f1d1a34-31a7-d1f5-87f1-cbd467484e6f,2712493114,17375378064897624531 +0fc2843d-014e-781e-49e5-d4f3703d2560,380838334,12656228608887388950 +ca55a21e-e19f-5951-0c72-3bf6d4ebe531,1111078323,9189465501440993952 +cbb9aad6-6e84-0d46-c508-aa07291ef010,1654138132,12795284904920654339 +532405f8-dacf-1ac4-00b1-46ec744a13bf,1490124566,11672267435402604814 +abb1c630-f939-6094-db41-67216b8ea768,2294634594,17127701064646202792 +73f4fdc2-5e02-3227-88a0-01c3269b97b3,1472635548,11745709082825491232 +779a6659-9687-792c-2964-b1737ecf5d91,4206999458,4111156790311502469 +f9a17b4f-93f0-5532-ca20-7c4ff2a07553,3958424609,696583450842137428 +f22a5cc3-e3d1-a1f7-ac07-de3abb726791,444180589,16024194098494442628 +2de6b534-5253-3a80-50d5-f1b09570e670,2277489612,5112199997510803334 +e1801fe0-d130-273f-1f17-51ae91f38269,1288521125,7172423459392525383 +fcec36c1-9548-e150-d7a1-46a5677346ac,1702927385,6851147849144841230 +b23da4c2-de7c-a133-82e2-235dc235400a,2794046282,1318655045496862812 +c6a69e4c-fe95-a71a-875b-4baca0f3c73f,4087956762,3271061164284103442 +e1411de1-514d-82bd-2ca7-3d8451c73bb4,1473131981,12508933951658267041 +7a1e8150-689f-45ac-c7ea-bf5643dca5ab,690400481,8546439874213467025 +303ee89e-794d-99c7-70ce-1b96aacfb6d2,712120495,4878171985670300441 +1b2cd7cb-c9a3-cb0b-e735-f10aec76d459,2820635952,8229390526918946880 +9b435526-927e-ddbf-2657-f379f0bf9402,1165972642,12565247350472865387 +801f4e80-6ccf-2f0c-a887-a47b39da48e5,651082694,2223416289164120439 +8d13239d-228a-11c9-bdce-8d6d611a09df,3317026556,18189924042086944782 +e71bc275-e831-5c9e-d40d-f50b38a9abae,3876331908,6050557502428336151 +9fb60502-632b-7cb3-4995-ca30ae5ec205,3336463009,11042822322469751016 +6cbb5840-1f1a-8653-423e-ba49d0e83066,1148705112,17490292004677664620 +47579317-a07d-86ed-649c-61a5618d2192,2680965106,1742808653213159244 +a8c449e6-86c3-22d2-a5a1-62e20774aa93,1735056547,8958707453436306070 +9e594a0a-8eb8-023d-3c4d-9dbed2453d91,2560238740,7398839212076010207 +e05da46d-1552-cc06-4163-f64306bf9b66,1936408148,9239678418789001996 +e624c8ce-bcf0-5bd2-716a-18d81844cd24,4195394135,12567757164932091419 +cce9fc59-d4a8-5528-6a10-706c6197aab1,587947991,12053838532360114019 +1aad98e8-d5a6-152a-fb82-42e120025607,4092225311,13012623115650560527 +53a53910-3518-f866-2050-c2a07b855e34,1843306351,3657150133258919442 +51a4127a-9c1d-9d88-5796-d40bd17e77fa,3136438185,1126823757501573081 +a2149396-5c65-8dad-c5f2-f646479efd9f,2588444808,17880993548086419200 +c9d6af63-c777-ee04-d238-d1c7d3c2c7fc,699575941,5810899055582685535 +ac3d473e-524f-f8f9-e882-3db491b6770a,1449367160,15001883829676410929 +9b8cb968-9b11-28fb-80eb-2ff9e5902d2a,2442701476,9531964826605934587 +05ea8a07-a74b-032e-b335-1091e293d330,2616945424,1556076986705196197 +be7b3b2c-fabb-1b58-bbd7-0fb45430399d,2901264439,5381387601839165846 +00f96955-0078-3a2b-999f-f2c1d181e236,2159968362,7971338577859142563 +a18b6ca1-f758-664e-dc90-6d850fcde742,869646397,15159726607254919025 +fa70b9b1-fa1c-4811-939f-7ab135a6cd7e,130688264,4319035173818610785 +88691cd3-ceac-ceea-705c-e4ebb6b92621,1916915645,16636838868393692751 +024f17ab-5cdc-3b12-48ce-1c36bc63f528,1953698150,15841665304584251401 +b350f425-f5d8-cee9-b689-641fb27ba457,3616063925,14232625641841925997 +b11907a4-9e5d-7742-7ec1-1dd91bcbcead,2088483102,14742499887140383175 +017aa462-d7f9-1022-10d8-e55fcfdfe288,2885210963,18050199542131536862 +6efe9c66-a710-f5f1-5a47-d3fc1397b077,3518072463,7461132277142073908 +0ff44694-7afb-e529-f094-3088e1a9e5c5,473303695,5040657547320356398 +d49d123e-1be3-5f06-281a-5cd098bdc71b,3328040062,4759197263595686144 +45de99af-cffd-3a30-54cf-0988afae6634,3629505262,1464216259490938143 +e41f874c-1ddf-d57a-b756-2cea3ce544cf,1539854331,8430619442443468421 +dbdef0d3-2933-2c6f-0739-c79593413d34,3911801798,10157125666754539357 +fc126ea0-d853-1882-b4b0-c486996737fe,2958457241,13933780112430763998 +248d7ec4-217a-26e9-b524-44658ee27b67,562435542,15992937331893420361 +d7aec1fc-9a25-f7ab-cd11-945458f5b15e,3981681810,15779745273240820518 +b810c0c6-de69-103c-54df-3b993da924fc,1683660398,6363118720058410107 +39c327e6-6b47-0d85-f23e-4beab1a67b41,1383730043,11346385243124556518 +8ea579ac-3ba7-57f9-813e-092c22e1cab0,1061415010,1658388679393895236 +a1ab1fde-639e-8b7e-e8b7-a403d78b6a1c,1863475810,7765552519041168261 +38f64566-a283-09b7-e6a1-69633c0a0040,2515128308,8538293486270786218 +7878ba08-96e6-ddbe-5cb4-f82307962835,4193365108,9203515475995442075 +0de93020-974b-b596-a829-cbf3cb430d45,662709821,1499759623051019333 +6458a322-f314-5416-28fa-083def6116f1,2576942434,10291657073165739352 +7caf15d0-5452-87c7-70e4-9c972ac82eb3,364116562,14760669629797881278 +784d5a39-6c59-0592-3a00-4d4ffe7dd0e8,2476598424,14286572919593103715 +9f06e741-9aac-3136-dd7e-e22b561e7297,706238108,15215398062714851891 +209367f6-9d1f-d554-0ba4-01c9e4ebdbb1,683143946,4612877375559988490 +75e847d8-9e88-3ccc-11f2-5cf0f02df081,2286400585,14683378805831512301 +01ddeaaa-dc73-24fd-5e9d-824144a8f160,2842099504,12113399366237481747 +f4865e91-f7d6-4ef6-231f-45a62d441a54,738436727,7725501050974869192 +243282c0-05dd-9622-0fa0-8ba552517ee0,3965542599,12699724812070217730 +433c146d-5db8-f955-3a15-97dc5478c8c1,1866779148,10457777940401260027 +a36e8126-b11e-87b3-9de2-bb3e947a29c4,1690085317,17751657751864631223 +52e510bd-f319-5202-a04e-9240aa96bbe7,1984212011,9340355969662068803 +a6d6b7b4-6eba-ab8b-9933-f7b955f7b140,1190925601,13452213949107960686 +649d370e-f11b-ae0b-931a-9731384473dc,2514188144,13380937690923887698 +c952d814-1170-473e-809f-4a7f5e4b54ba,4264881378,12249497091229352841 +7c97a773-b259-2911-7b78-27a4eadfe4c2,3560829178,2634002642720257324 +0fdd253f-b9a6-6527-c1d6-6d5a1bfd85f3,876695111,16760496171748601481 +f2aae59c-b470-3851-a2bb-cc15d2f8b679,1054384845,3250103559849778514 +6c043396-7a26-9d51-5d1f-c186817b2172,2890579216,14947284439090987143 +bed31717-6b6e-94d9-d3a3-d24fac622fe8,1164921065,5791794642071434524 +5c716ccb-2f76-4553-33c5-d00ee135afd6,2846997614,18103152153748685551 +93dae8f4-733d-d107-72a1-6ad2d381bf49,2874922471,10574217101732150934 +2c6ef95b-471b-7915-d0f9-7b1e8ce9d9a4,3711197677,12952313234590768019 +f88334d3-6a7c-899e-2813-ab8a08dea837,3842834607,10198187340028819630 +77460bbd-d635-6c3b-0ad2-2da0f0f4efcb,2318644267,9250209962833483529 +7156bdc7-3d56-6165-7c58-2fdcd05707fe,2322484178,17761027822932455526 +dac4b44e-1001-569c-041c-495c8f80dbc6,1838626291,13903619191516655661 +ba628159-fc65-01c5-776f-0cf78d7ba10e,1467059386,2776399533509533858 +aa5079d1-04c4-c079-e177-108ba6a985fa,2659538307,9792799495555342540 +99fa0a7c-c90c-2eca-4c30-1788e94699d9,278036275,7965214007016184829 +73ccafd9-4b85-3994-919c-a945b679dff3,4214363133,1200550463794102963 +b9a76ee5-f61b-af39-9065-0d1df5d14a39,546677479,16819668201178808530 +cd1f0003-9818-55f9-4072-b570e56e233e,469302434,5853934233692148359 +2d2bb302-a9c2-39f8-6e43-1273b34d6384,706937261,13968633763862091629 +fa274559-e067-b662-4571-d2b891af21b4,2698449226,11174042147340237479 +5bc67e4e-9af6-9a95-28b0-c90b713a1525,2992451719,7560200648510642059 +88fa309b-253e-0a88-9a20-fedf80c04c77,926334792,11906257588827590434 +79a35cac-6af6-8fdd-8044-6d8ff1443066,2752093296,819608595411096717 +b92541a0-8c32-c0b5-f6a8-ccff26ab668b,2307743979,9522260091424097895 +313fb43f-cf9d-bb7d-b9b4-fbaa8f80d1a1,794593271,8970827290756949820 +360e3d40-0d05-035e-0567-02f602c8b68b,3559112298,5164994796717210957 +0976bc3d-25ea-6011-fb35-94d6f19d8a02,1840911682,5477281599182787431 +3fad61a4-3ca5-fca2-b8ea-21e9e0ace5a1,370070123,7944600577927199489 +277f3e24-4bc6-5e18-e95b-8387455cf41a,1846871503,8883213113845195168 +e70f746c-82b9-3ea6-9746-f4f261b078ab,4037803438,15054850560483227497 +b248075d-1932-e859-85d2-fd8e607ad31c,454894710,9139575422201996649 +4e830edc-c125-acdd-c7bc-0e57482c2c74,1970856080,975655765711043562 +b20ca0fc-d779-013c-c4dc-deb22e40d103,2280765181,7400096347339088291 +a1fd769c-3292-b75a-b98f-fd0cd4368a23,1249188474,8904971016247301166 +c90d4194-3342-b3b2-bc06-baee17862952,3461077242,4874221243306052543 +13d4a684-d488-eb16-9e75-7c9f7e64a21f,4034851952,8720123256691043037 +ccb089dd-b0ec-8ac5-d003-8369aae10043,1815344030,11822752476117518328 +89bdfb2c-bb22-ca3b-6afe-6d00a0fc4347,153443599,6335110927573607040 +a73b43da-3303-a4d5-ba32-eedfe745cb6a,4155563871,6181112949205094112 +d801fea8-0d7f-ffc1-3e17-a3eabf86db2f,345363529,1469192913466768506 +2d1f6361-6f23-0165-66e0-d406893cc8f5,4235243272,13553580411101707172 +27788c04-3b14-d1bc-9aa9-beffee30bea2,4068446953,9926713379390913156 +7d26501d-7e7e-7310-9b93-e36a08353336,1143852293,15055824104708143028 +791f74c1-3832-6caf-a328-e8313516d47b,2143847805,2574578305853435019 +97d653e1-d540-4fa4-28ec-6f552745e5c0,213632222,3409630376917929301 +81f7ca21-c304-2ea6-67ea-f53be7c007a8,3129589643,14913619655369438165 +e1953b4f-2c65-3429-9ca8-a49de64b2289,3152425906,9076018844228204785 +25ab9b53-f1ec-ff64-4bb6-4a52012f193a,472590657,9018602285472765594 +8ea4a259-1281-777c-e46c-5ca0b56c23e3,2573393795,11921935059633622040 +419a3550-38e1-2e1e-91d8-c00413d17134,3730966366,6730224909163886036 +42e86351-9e32-ffd8-8c5e-3fae1e3e9ddf,58837669,17108041764986891213 +d4e29e30-9d86-1cb0-a17c-e2247cbacd25,534932528,1903811656613611778 +7f0602e3-31ce-6a2d-2b25-0339a06fcb99,148449060,495880484166813297 +19363657-46b8-bf0a-13a6-38eac9df1f48,1310658685,7286324743722849118 +2c08cb69-5657-f99f-578c-176ce40ed95f,3248550653,9181737648624789696 +6c5f582f-f366-9edf-5781-50c60f3add63,2055747396,9997672543954181852 +9ac69c14-51da-bd2f-600f-9536f4881b4a,331553192,5390395143950144637 +0112d7e3-ebc8-68d4-d77d-b5132219d45c,757133418,11658059940341990426 +70068275-467c-5617-7ace-dd4c8e6ba77e,51557635,3331171986896162535 +db0a7158-d9dd-7506-6c00-3f612fd25cae,4075164235,6216295192539173268 +d04b436e-44fd-7716-1042-b198d414235f,2045809165,17108582525745267970 +df00f132-2e8f-f65e-d6d0-8f04a7aed80c,3334033317,3117875670156796268 +f3d9bf73-d74f-99be-83d5-d0ab305b897a,1619028153,5643895700339472245 +b8c9e706-acaf-a5c6-3fc1-91bc93d68472,2643852494,2827265992875762638 +221fa066-0134-91e6-dbe4-5e6d7b6df8ca,2612063215,1772352696721591569 +7ea246b3-a2eb-af2f-1f1f-838785740843,534034365,11992840964686892871 +6540bfde-e592-82a0-572b-a5c3c525f25a,918256113,4247743741730050148 +380ec1db-ee67-b327-beb3-7d720abfb76f,829232556,11117812710008201412 +e57ff00a-b0ba-10ad-1a97-026a3b276f4d,2308117729,12075423757072592672 +9074990a-2ae0-9c6c-0a80-3fb92dc63654,4020886288,7058224807736060338 +7e2eb166-b20b-1779-5db8-e90ab7680a7b,3108359360,8800470811049980904 +e2a80019-eba5-88cd-9cd0-b94f84b40333,3560785410,11285073981901164784 +9dbf4854-e19b-da20-1d29-634bfdeb04cf,1967415814,17077752077352857772 +f573c6ce-3c6b-2898-7d86-935360c783b2,3554692032,5927122509040515974 +19b75ff0-3605-18ab-a76c-e0c4a2fe2193,1026514587,4611716600408226237 +44866ff6-c2f5-e1be-43f9-a9b8ae9c44d7,2123102588,5320913895952075713 +c89fb0fe-ed6b-5a40-3ca0-446268df54f6,42941870,4196005133142446745 +df90630e-3d71-5f83-05e6-8d8ee3363178,1130058250,16696195787699053503 +d57b7fc6-b9e9-cdab-8cdf-fd9114376ec3,4196815152,11096817415248688687 +597dbee5-04f3-214f-71ce-821af26e3366,3146843681,13316390647325580649 +d6ae6583-d727-05b8-d52f-31fcb9430682,3726036363,1866822341770134471 +1769a648-af30-6cd8-e223-e864814f8aa9,372139023,5190740224653516744 +8c783c7c-c8d4-eb27-f5c1-d192c44b180b,3480604541,6516232607130152220 +27d0bc7e-a559-4a9e-1a9d-5ca2172e1833,1515853417,15920670126800451792 +30c0ea85-9297-a1fc-a84b-52487dbe0cf3,3092203807,15640320281112699281 +4e9e113e-6716-8ed0-bac5-7c726bb5736a,2252737194,15454941038093821129 +e41a323c-36cd-aa0f-f7dc-8e1877bee828,2342301369,18137501618482440572 +e8d5e82f-8638-a543-972a-9ad938763538,2076820439,5156270750763644606 +4b566765-cd0e-41c7-6b1f-422047fe82f6,539012128,11124315629736261562 +bdddbfe4-d6ac-c6a2-3694-a33ef6296fe9,3764101548,4787197122698754494 +40a7e298-b8cc-fd34-c347-a4d89aad6df2,575854094,15277122039942284188 +5942e92b-833a-2b66-16a8-9d62d7893132,1348443455,13588884985195028971 +38b83bcb-f8b6-c9ce-833b-7e9069aed814,1488126723,5345778587687022995 +fb4a84dd-76fa-d0b6-bb4c-1f6cd6993281,450998399,13787820768418875148 +c7f75cc4-f63e-8584-e7af-98b7f19f6138,612495145,5405400839072622022 +db614345-0a59-98b7-d3ee-8584e6bd13b8,2242913313,12293838389512769146 +af76b45e-1927-022e-4280-fb23c85c2544,2391954498,13350755046664100497 +c8a275c8-0055-f97c-b483-31f823345546,3585382918,11830831656613196445 +ddbce020-64b7-2a64-2198-f7e5e52891e9,502495455,8020238919611690160 +64a41be7-e4f5-ae70-0407-437c45dd4808,3720934792,7625228628779532026 +f0745667-64c2-09ae-53fd-48db2db5cddd,2288367821,15136261920876912615 +d3c97c49-def5-0f29-9704-6c7ee2cd93d8,3884088605,10263582793340421862 +21e3ea85-54dc-5406-0f50-9df0da1f08f5,3413800236,15306510433402149271 +070d36a1-1315-21f8-8ae3-363e3a1659f0,2906196549,12240161365762167469 +f2094523-655c-38e0-b6d6-20147765a8f1,2881536300,11571774143349389075 +1175a9c0-ae90-1e74-3079-988911764ab0,2630123176,11596715644997993752 +f3a82311-a984-bbfc-b6b9-9acf503c5ac6,1360554358,13289994204893850714 +f7385743-1ad0-6600-0729-60079eae7750,1733192228,12629489611509819949 +1d872072-1c06-a5f6-960d-1ae148202485,1209957176,1090665920840329796 +f55295ba-7e45-c0a4-89ae-76ee0b7b6db0,2904363351,528230510409494231 +44771ba5-4687-969e-dddb-be0968e503ba,2186351370,17963821289088221814 +3bdaddaa-4672-b3b3-1aff-b0c6c96f7348,1106012458,6315510561192235667 +a398f163-eae7-c30d-d099-4081ed5bb3e3,1800706605,12519363814463808597 +f75072b2-9450-caa2-6080-3b238ec36ae1,520219815,8406557695624130471 +1537aea8-1b25-b451-42a7-0dd6b75ceca7,4099779723,7775131688678944184 +332af8cb-7a73-80cd-7939-de5a0d40dbd9,850143195,17001506421605869706 +1b12b868-a548-d9cc-190c-b400c6368139,2376803008,8605688143992882837 +8a4b8e24-6fe7-4fb8-ea6d-a028c355b0c4,3314779745,3156822286411769735 +6f33f448-65e1-441c-5f57-fe6ef2a2daf6,2457395736,10160582041237854719 +8b0e6e5f-e05f-bb15-4673-c3a9966f220d,3858422366,7928081511894081986 +24353d08-9f14-bdf8-f612-5e0e5410609b,4059038663,6331597223820828875 +85224361-a057-f761-9566-5a19b68f63a9,1242933303,2566353979900150337 +258e6ed1-12b0-e0e0-f0e5-fdc134353a8f,124423989,16800018201884901473 +a8b628d4-d311-aee1-dbe7-d29481d7b6f7,2475920610,13379167966559798857 +547771fb-05f4-9ff5-1715-52727e94a6b0,3966467240,14283691103547629698 +7896202d-f69f-2696-0653-3032dce8a436,3455130989,16824133106805135355 +0b05edfc-d102-63ba-fdca-c944b8e2d09a,819637919,8300813209144338952 +6991cc26-6ede-39b4-95a8-f4f6b61ea902,2283899276,9351862213868816325 +4cb45ae6-1dbb-563b-d417-ba5cc54d30dd,3353290089,7356815160215645277 +3f9b16a5-93e2-a9ef-0289-18696988d495,2451390468,11561403724373011101 +6e69b051-4ebb-48cb-1db7-c4c8e8bbaf26,2233783234,4311843099213944151 +f50a0c1a-cab1-2fc2-f600-7870e2cd9b40,3993107585,10427846556304324237 +2e267e16-c007-8ba0-0eac-5ffb4c4f4b78,3002835036,5341501929015873824 +e9963d9b-d7da-d4f0-e3bf-5d6effe0f784,3457586883,1990211602030309078 +87e97936-1287-77dd-0900-d22649a6ef99,1561686738,15860105426353904086 +a599572d-2e37-ec4b-3936-164edd8cbca6,3019731202,15688410697866054027 +d87fb249-c8ec-eb62-3dbb-db2f83eb6ea5,1966390781,14179384029118328830 +a87b48e2-89f0-28d8-3598-4d41a6a6e970,2733532269,6115805343769010126 +ca16c7d7-17fa-2d1f-0509-76a59f55cf47,2765594866,17123834108598956961 +2cc80295-c7b6-5dcc-7173-f86dc4c567cf,3825965203,11272936786905149715 +a6d5c8fe-f1be-7949-c7e9-82494a9ed3bc,4053465265,7118844567282496559 +8b023e48-e8b7-6d41-e636-e59ae53e8fa1,2445108811,382422931118375937 +47b4f124-649a-2bf6-4d9b-8b85c1817d6a,1760512351,1150843787064465381 +d69d8e38-7f3e-1d84-f6f7-d53af1cf24af,3403057741,13640761809550131599 +daad85c1-d6df-7efb-7a00-537f86700f60,3340756349,2113511398923066084 +30a82799-73b0-81bd-e097-1e3f7d4117b2,1900442786,8486332784889704941 +dc0a2aba-fde0-9254-e676-d58d7409356c,2243465671,7370017137629984697 +7a055995-3969-be07-9a4b-9b9332beaa0a,1735938767,12212655608751167615 +08e5fdf7-d0c2-f0eb-e499-0c20a26b53c2,3124406556,15360948354719304943 +7470aa9f-ab90-abb5-6d4c-1351cc45aeec,2371050192,1047730807591970098 +f3e15903-4e83-f6a2-1960-ded7e4cb9444,825259891,14186072816299030022 +0120329a-aab1-0dc9-f252-e0518c189873,2260851579,17146033852023956403 +eccc10ab-525a-787c-d6ea-353c470fb41e,2841130820,2150001534882067114 +7c0a49e3-a104-32e0-1c73-1dfe3877336c,4045755884,13394190314355456009 +a61f7906-3d82-ea63-6dcb-f122594e1d95,2911385473,303193566925501914 +64daa5e5-b0ef-e1f5-0cd2-40fbc6b19266,1432149647,7339191663048905747 +89c56ea8-29df-545b-28a1-0b5e1e6b1fb3,2537117165,15955906213019007107 +e75f0cf1-8c30-c027-5fe2-a53dca02a92a,2235101520,7514568230509408844 +63941f6d-906e-39b2-c8ae-46cbfd4617d0,2623966161,3568452633401579744 +86f9df85-a53c-c8f6-685a-3d88c451bd28,2416990776,17398278096673680742 +8073ac70-15c1-a6e7-a455-8ed4d98bf964,4228381113,8349510932895507195 +bbe81461-138f-88e5-1090-faaddf056150,3051400880,1773889055799378002 +e0abd0d5-b35b-baac-3641-36a2e6092a00,3273068533,12921923959078476176 +3a9afc8d-c979-b016-3f14-b607e8b5c2a7,740525652,7771653964024254297 +3eef0e7b-0cc9-3bad-bbae-68201fdee50f,4132954074,9415378873216740280 +e886b600-0be1-76bc-3799-a9b7122c02f5,1888918921,2737649433520982264 +4ed7806d-9e66-3e00-67ee-f06ff7c62348,3932667215,14434432951640415487 +5ef1ccc2-322b-e2d6-1b7a-555bf7e4c7f9,505787860,2228082737646035678 +3a4f8185-0116-8444-0052-7da25066c8b1,1098127692,3754245322608756992 +137306cc-a866-eb86-a359-13e813aff661,3870051641,4980335037762276803 +1ea1fd2a-f456-eb1b-6f5f-89cf8b78d2b3,1362103032,5718850504246128881 +671b816c-f630-c76c-f8c9-f68aa8489d9f,1247323096,8808552728564234470 +eefd52bb-70d8-a26b-3a2d-a06c3716d081,486834359,17052652502622108993 +e81ecf5a-487a-edd9-0c0e-84f1ca079666,1865201736,4095683903379454961 +1fdfdc0d-02c1-2961-73d3-be6eea09e5f5,2790353401,7974412100132540224 +189a799f-b528-883b-22be-543aead74825,3318907253,2693626192464980454 +07ebdff3-a395-4e7e-bda4-c6553b54ea00,1958761615,14881621682119600137 +b061ee34-864c-a2d2-a667-2e11b4a78441,1682772315,4840519656575968689 +00145d0d-33ac-6509-eb27-b6ba3875fa5a,141580905,16272628841765068693 +62a4cb3a-fc47-27c6-eb74-2d22393543ea,3197199305,11332480612621315845 +09197e8a-2647-4c99-4c74-174fbc344e8f,3707355854,8353026222357455990 +f186ad5c-b254-f001-013c-0e27d2c9e2da,1972603519,16540125843091255429 +ea8ae388-f187-3a8f-33c0-f49313fda70f,2112999751,3995903972350721651 +84094b50-3736-c421-ba12-a19352e7a32a,2753231077,16977034012790219083 +3d673ae2-10b9-b39e-669f-d9ed37115367,1887260415,12098160444503217115 +193a4f3e-0c60-b433-407c-dd28d4a39a6b,1641292758,9325459538117481753 +cfa5fcda-f12e-0eba-005a-835bf18028cc,3682563853,7123764066327132264 +d2e3f376-f384-51e9-6735-36f985653e07,1977534660,2590696323926776125 +8f88d803-4cfa-2ad8-30ad-0a27fdeb4fad,2778612044,7553992646487529018 +5b705d36-37a5-f58a-2e7e-a1e99e414eec,4187106560,3916191432741650991 +76c90766-a258-e0ff-b631-c2e0869af296,1023256310,6599562768535341379 +bdf2f409-bf52-ad85-5d27-c12c495ed78f,3809045293,11795939771645497897 +e20e2396-702a-6828-a26f-1f66d05004cd,3187292835,342304369293675671 +dcb915e4-49c1-f28f-cf34-5125ad183f0b,4000758374,2954057142254130184 +ef80d2cd-fd72-f288-3044-24783a6a2c0b,3020872092,17977729187243563821 +aeb030c1-c5ed-e3e6-bdac-ebab8ef74ef7,2430090359,2542918408189772095 +a79b295c-5319-be0a-13c8-19615848de51,3711752285,10599042723864341256 +7f283b03-5d7e-7e0e-b033-ac47bb3ff4f7,1438220209,4969440367714133836 +14129e65-a8e5-93fa-2312-9a753c9ab906,2926109318,17489566395248286743 +d21dc91c-a627-23a7-232b-e6a16280710a,3193024817,17329803937066387720 +291f69f9-0ef6-2f9b-dce7-cc88db5287cf,926497746,7441001641381063936 +125c77a1-9f50-e8cd-65bf-6ca2f72d833f,1563872625,12456439796513512775 +aba306fa-e19a-a8d2-d09f-8776c2623468,600262319,17424308978696533289 +1aca201d-dc4d-ee4c-d522-f6ed0c8cacc1,2375532298,5332783181414732683 +269acf0a-451d-5b77-696c-19ef27390e6b,1119439576,5495688243707925158 +d8cfd726-b0ca-a0e0-8b33-936ee5609def,5817649,1291094591167198851 +8363b876-2cd3-09d0-8070-659573ee85ae,1440923259,5390729855199986948 +2b86ad61-a6a7-44d7-0799-c1fc18f86355,3812747203,12377328151069614627 +476d6c77-3490-5fd2-73ef-c1d06f7716df,4276951902,665729927970215741 +6581f5c3-4907-23d6-0823-5336669641a9,1927502894,7809874913163674327 +44d419cd-bd51-6f80-4bdd-2a911a6c081a,1105061805,7955222004799800803 +61681b85-195f-aaaa-a861-0baecc56cfa5,1997515422,14317662060794091447 +794c49f8-9e9b-abe2-3edb-0fa4e02bdca8,4202917203,7372016264039357486 +c8a26f5e-dcd3-9236-b69e-9d3ce33f0da2,873628676,15414902694344123968 +c763467f-0f8e-885b-cfa6-860ed3610ffd,2550722685,16527880883541157722 +1ee5160f-9c3b-a3a7-5a4a-e0d4f2753db9,513140069,8738884455300086485 +339b4a21-8956-d6a2-7479-bef5624b59fd,2194904354,11274208396762034476 +95b25489-dab9-ece5-3c34-caea0251304e,1664446787,926609895815227658 +29446994-18dd-b416-0415-453efb554550,1296909170,10371567955286248020 +87f478e6-c196-2971-fd7e-707fcc2798e4,3562647334,6506167115698873804 +52cfba09-b9ee-7b31-1e15-1dcfcf9fd84a,1376459367,15099059967583117987 +7cd1b3b7-80ee-ae9d-d9d5-488864ddfbad,557492672,6567767864431734127 +31e285a2-835f-5757-a92f-13f2e369cf7d,3437218409,12959298057114198776 +30b3f654-1668-26ea-73e2-849a9a4b54f9,2817199735,12989355578633338076 +03afd550-e7a9-4aac-bdd6-e34084b81173,1774263633,1737821196357429497 +ebaaeb6c-42c5-bf8a-4340-dc98fa5fd553,907438981,3558034592090709843 +27bf757b-394b-bf49-4dce-d9bdcd772f59,3590846913,12386517477305272705 +cea1c39d-9e98-ed78-3a77-0587fc62ca93,2460872219,2697323452875449057 +dbf9c102-1267-16ae-cfbd-0e7f66fce770,3635141203,15608825396730822017 +44c88255-3d29-804d-d957-c1bc942bce5f,1078975902,7953143362951680404 +8f91773f-7a25-9c2c-175e-8c4e840cb617,1618582738,11667493864334854774 +edd98c15-f38c-1eb6-4666-b598820d73a4,115864781,14862967663253885882 +e2b14000-fdf2-1098-57b6-6c8313ab3bdf,602837016,8926065201582170360 +71d2aa4c-c23a-93af-a364-3bd698dd8a78,3578095186,14121760951463685883 +3568a1b6-3d1f-89ba-da0b-ca79b44d74ea,4044071962,2591628661123058315 +173e04c5-200a-106b-67c0-d06b35617635,2674506817,9009836035735899657 +973a2762-b1a0-c3c2-b6e7-addbec16568e,1755091830,4526660965274611878 +40147ba7-b290-cf97-bf68-f78d740695eb,171189123,16174196333681083561 +86ae935a-7bc7-a9e9-d97a-2db70e817104,2303986065,651597335703204376 +4305a396-8191-f304-4449-9c3ba20ff049,1220786907,7977113563388368660 +796ec2c3-40f6-792f-492b-8d3d2c68826c,710787487,6693854741609554405 +fade7b9f-142a-0502-97ae-9b1b251739b1,2953589057,8048015447756948067 +fbeb53ed-2cdf-d67d-0a80-6533d048e97c,1776087767,17733915719378256968 +3943bcb3-92f9-4193-9788-e4dd6a058d63,3210416593,7932923436980022084 +b8413314-ffab-7314-5b2f-376995b05a92,4084071457,6045280741250355322 +8f9676b8-1fa9-3168-7a00-1c833d311f30,2944649450,16794289099459762022 +3448ab40-a9b8-a14d-ec7c-e09b041c7d80,2325551676,12570190801642734909 +0e6a2f22-de7b-f272-323c-fee1726edc82,989989300,10302281455372869301 +1e1fcf6e-eb71-33ec-828e-72236c558992,650983156,13074408543145346450 +74610c98-cbeb-dce9-fa9c-d3c47fed8f26,4097366283,6848170429998023445 +c6dc6115-1f7c-13cc-6e91-d91e8f9b6820,440402120,15395814858809095678 +725e3c54-0852-9dd4-3f1b-152c6057d59e,2535863964,15387448624429632458 +90497290-58f6-6edc-7f53-163b22831859,4100364046,17567653486742374407 +6c53fe99-e87a-e61c-65bb-9ece3cf54387,1470302421,11256728259571986225 +89823e0e-0f4a-9329-1df0-9f541dd055f8,3600157582,8899791554218334511 +bf52a5a9-034c-854e-d835-a3fc6a0e2526,1196570713,18118572541329409332 +e605a1f1-2b09-4be0-8b75-a7b03cb0a0d8,2636785459,13353096668234622771 +8ac57e44-9dca-1f90-e750-a92f32be0e04,3784876280,3547675168653663842 +eac46283-486a-44d9-5a7d-f9b1bf141dc7,3620241071,17918991522802307609 +7b277986-52f4-de60-35c2-0f955d9df6cb,4199636700,12479788642382809291 +a6ed47e2-eb55-acdb-b822-e82a4137972b,2236935272,11096699853512246566 +25b286e9-36d1-5067-7001-b6e1deddb076,2508486438,921228408002104894 +3ea15cd1-6fb4-89b2-9476-df0bed84b55b,2843765539,16783429817205598064 +8833846d-1316-d13a-6d25-bff9a0ea2ad2,3332396864,8155153152072232521 +227e08ee-0bcc-cbf3-c400-7b9222d032c9,2483734103,8450480455682047742 +90003dc1-a79a-4d14-4bcb-42b7533e6f0f,3869418703,10333156687449770366 +c0a667bb-fa71-f5c5-1bdb-4fd826865ecf,2298506406,5254223609422966085 +eb968816-f2e9-d4ad-5f4b-91e2bbf78a03,1124191355,11544068821240878930 +55e19fae-ac20-12af-ab15-4d905431516f,459319414,13534086621319503860 +eaf46d7b-b0de-a19e-ce66-c660be45a60f,1107782320,4264805178379701382 +cc5bf236-7b9f-d810-0558-579520687aea,1040189911,7446430042183687826 +ea74e337-9024-89e0-b06f-66b51e2d114d,2312858186,3369317377193624007 +2194ea81-bea4-dba5-ba78-9521fd622854,266601934,375744318052655572 +98ee8a91-4d76-df4f-b007-0ba56da67422,3360901352,6970132757313378604 +d894fe02-b36c-06e5-84ef-8e91d373d91c,2357694993,1141080433834787204 +fac2cc9e-9b71-e70e-db1c-0d68cdf16a2d,774071960,7102002875976478982 +bf072d44-1742-0a57-02b7-83e273d793c2,1455707452,17571929291872492519 +f1bd9d27-bba2-3cd6-3e31-362e5bfad7b9,362932062,12351588062119272555 +a4276239-d28f-4897-5c0e-d40bfe3dcc50,713663053,1937716960349748742 +885ce645-ecdf-89b1-b3f4-ff0095aad682,4130337648,4142653881325970615 +3e25d9a2-29e7-8dc1-941c-b3ea715d5ae9,827917336,16727197516211035173 +9a5cf7d3-3a4a-8c85-9f79-8ae261e3e840,4050600092,13028252510313365314 +b08ca274-9fc4-966d-3e3e-932919e4cd9b,1539489970,58057889135406883 +f0bd385e-48b6-4b15-e99c-c42a5dcc0d91,79286976,12045575868697339114 +4c56cfff-fa23-ce6b-9b7c-65ee9433596e,2027118961,7166699305615514166 +71f2f8c8-43a0-2088-6d53-0f6ade794a04,1165490011,15386713880104458283 +84163235-3830-668d-87f2-feda0ace6a44,1436712316,10780433622048329327 +33fd952a-a467-e003-221d-c950992392d8,40227735,11026896802688327292 +99f5b3d1-e301-5469-0eba-8acf15e478da,3297588490,7721864881109405339 +d233f4e5-3f9b-5172-c190-2fe37aed0579,1508983575,10050835349077403962 +f70c4d0c-4ca1-d14b-95dc-860519f402a2,3095520776,14445128840002065234 +d40a10d2-f78d-ec6e-027b-656b990e122a,500212480,6555882515805660302 +e49fad4e-e544-90de-3c24-eea3cb3081eb,3552922676,7538653153732281046 +27018b81-b0ef-1422-55df-844a5443fafb,4008349270,6889893024283826699 +30f37d69-bc47-3611-1798-dccfb8202ec5,2517264298,5352121667593000997 +2c9437f1-5d32-d04e-7c31-9577a9fa4a28,2606189020,15804774866976632496 +7807f6e6-9244-96e5-bc4f-83d61d905180,57574043,1263705000203081763 +17316a72-1299-cd7b-5429-f5a6dc9b09ed,2483105379,1412966064681004116 +2877fcbd-d373-a634-bad1-849934a5153a,1533816141,15688895212002437496 +1727df4e-326d-00f1-d177-9960dbdfa1d6,2092044605,16102943223819142161 +c8279be8-ab16-c2a4-954b-7ccd1b19611a,3546768574,13772256514506393268 +4e77bdd4-c167-2488-dc48-2b7c26ac356f,2037160459,13622967833191384172 +53cefee7-14dc-4e99-d410-1fbca18f2f7d,2291834215,11378476282446655279 +7af8fada-0bc2-aac8-13b2-ed5315c7da69,1298661518,4931948916532720830 +7149fac6-56c5-58b6-d72f-b6867fa9c504,2688952151,684542332919833432 +9ff55345-5422-d19d-5719-7415cc58a89c,2268061378,10944909416906376760 +a09ab586-3ade-177f-b76a-4dd9d7e469e1,2205001448,17201766874093525672 +7d04428b-402c-89f8-3302-92510c301f71,890551698,8049909626947077017 +c0d1552d-6c42-3f11-ba9f-311f1a132a44,529274188,16346966205436970082 +dace30dc-cb9c-835f-b5f6-610557401990,3017553379,17887106983466178582 +9b341c1b-1d9a-cb8f-d27b-ebfa4be192af,601714732,2707816592869477582 +fb171ce0-b046-2dc4-eec1-9c1352a73217,877732308,196781053167805559 +7e90c5a0-c061-0e84-1e4d-d669bb12fbe2,3403506673,6614446753619354857 +490703d2-f172-9a72-7407-15435d399e9d,3114889370,9632815671750998203 +1431bb4f-29d3-d198-fd4b-16ddbca20fea,1931573054,3829750350570397542 +01064246-215f-f5ad-e5be-64f3be5e7e51,577316760,9494487506126211948 +451ee0a7-4436-9ca8-5534-8f814a7f49ef,1223504045,10832084031656092661 +577ff03f-f813-434f-3678-358fd8b8bcda,125957332,10459462654538235777 +3ef198d1-f30e-cc2f-6737-0d5f6e58dec0,103583069,17166834431002413306 +ae40f6ef-318c-6398-eabe-5e328c37e6a3,2502883077,249721321184689541 +b59e2c01-e82f-4250-5c7b-9ad5875cae2e,1968032111,4795393011247798426 +eb174293-d4b2-4f5f-8414-b668a7fb33f4,478002472,12098150670583715764 +94f72bda-6d14-9e27-f1ff-2f6ad2f6264b,115217621,15941211114935659250 +3f050682-fbd7-f5f3-9b69-c5d500a16c5d,1590160934,10210748590691393774 +8d937b72-687a-c2e1-b53f-c34bd1c9d757,2513539277,9250582798991495898 +7f27788f-47e1-d197-81aa-ec04fb79610c,3726766730,12927968308044872816 +193dbc69-545c-1e14-b892-615d9d16d08e,1535305725,1903519723301670525 +d1b7e9f1-5865-8894-379d-38db17b61142,3301277285,5746179810258036042 +e97aa9b4-cd57-dafa-955b-09456dfc86a1,2432787133,6606543554673685128 +314480ab-a415-2f05-4ca0-57eaad67eb94,1047444791,12629047682465616399 +553082cd-78f3-a050-5de5-b941d5a8e696,37608044,899704401978337783 +1f594cfc-d5db-8c19-43b0-dc40fba2d243,1592580096,9839232327481752059 +85cc35bd-1b46-c9fe-4afb-42a78a74e82c,3516274055,2647983786793548165 +6041da99-4184-11f8-d260-4bfcc87ebc60,1176213860,10504959035706121344 +3f4bbdb3-43e9-df96-bb98-f9ddad699c3b,2350072867,10619929305779031419 +5c7ae858-69d3-b45a-a8aa-9799c176674f,350859034,13302021347011434677 +72ae6421-2081-7a5a-4665-2a29649a0089,2238899018,12355634593695214600 +6783ddce-bdde-ee34-4e30-b72f6a785e9b,553166364,15831209627622698073 +a8e41bc9-2f9e-6946-2096-82f67331e240,2043995545,16783243497663202766 +d37fc62b-2172-48bd-bc37-6c98830e3ab1,3679788508,10265211695968020487 +f7ad0fac-88cc-7861-e285-950a35031259,1521182693,8135063525351848581 +cc810e0c-2472-36b2-725a-dcada66f581d,1632525023,11547867210183855829 +a0920693-e459-7a1d-8816-96882581e0ba,1044876289,2390478184080892768 +f6b31118-84ea-0666-add0-937577523c91,416537962,17963575185267193258 +da3eb32a-49bc-08ad-361a-b576c1e97309,3136579944,16725900925129313239 +ba78f93b-998b-cbd6-a32d-328f23e92205,4082970816,10395092267283020323 +6fb1f5b0-88d9-8f60-adab-4ad21537b1a2,884057768,1848575488021520276 +ef7f158f-a63d-15c2-3f2f-191da0876f5a,57755824,1627809813220773429 +bf83f6ba-f58c-5c1f-1ee9-070486780962,3407581536,5963136129063644699 +bb89eed0-10e0-409d-e75a-ca43291af981,3705615974,11600625514960695009 +4b28c87d-f175-b5cd-a0f2-ce4760afd111,2307317161,12146136092295462384 +73b61940-a029-6709-2e41-b33ab21bbe83,433935206,411514738005326951 +72dc2c8c-8c4c-56b8-9b71-c485f5214c19,969638842,17390321930017559559 +1ca40d8a-a2f0-9508-774a-4392825a579f,1343077800,2800954887059569194 +507270e7-2c66-987d-1b0e-0b682025575c,168842644,611228894689796611 +e9d3d199-3f23-e6de-b567-3e03b2554a90,1059686459,7382742174797735995 +d300f990-c6a2-0b39-1f4b-aa9ff4702020,2149815436,15185071268677878870 +2f3bc8c9-2a62-8914-e65c-90acb72596ca,1955231029,6561870689261551470 +a7cc8569-00e0-5b84-78b7-a70f9eb02695,287349972,5432051880569660079 +90fe8294-5117-a1b8-cf65-8927dfd7466e,186343729,7688709628525734526 +f8e3a03b-4dfc-5d71-5941-3160a4add3ea,3701711849,5255090292602727848 +6fe66afb-a6ce-c5e0-370a-799ceda71290,1451116622,4937645648369409543 +88e5e365-1bbc-52ac-63c2-080e54ac3da2,4067924974,6159934244476871946 +f1a6aecc-768a-d280-9d83-7dfa70899615,2338167821,17935039025698975201 +331278d7-d821-6dba-40d5-e4352387e5b4,1285304092,14266099323560310261 +fb0fd935-c5f2-4fa2-16a5-946ff87f6e05,1854915001,13599200155831147149 +56a2eecb-2c16-b36d-83aa-cc356d33fd83,3761922772,9255198854623046741 +98d7d12b-5c17-366e-c04d-1476044d143a,1462782117,12176819573181628315 +20a3d17f-1866-f587-bc0c-ac1ae1dd85ba,65006963,14970034093343383097 +93ba7005-5543-c175-a59d-ee877eb2acc0,859786197,14763720506551762446 +6275bd4c-f541-b41f-a8b5-b1702dcef7cf,2476603504,6110678465155737985 +5454a447-b516-edbd-6705-44842204beb6,4265644404,8200404006621872165 +acbc3792-b30a-56df-541f-507136cf38eb,3407307839,12966122568509026734 +8afc796b-a657-ac45-a95b-7a5ae2af96ef,2927612530,12126229425352627413 +c0a0d9bc-dba9-8273-aa0b-97ab71a1b5e8,1668418852,3710690357679607217 +a0afdb62-c4b4-55e4-f4b7-39e5731df8e6,980476313,299032528191436065 +7f5ddbbc-86a0-3fc4-28fb-ac437739e51b,573781626,11061356139144318093 +2091250f-7b7a-0876-8378-34aa7a79fb6b,3232195379,5646809212683250822 +10a01c98-2a07-fb99-257f-15d572b738a5,1197312904,6639189231347628880 +889c141e-5a67-3257-3d4e-5a639b13bf63,2662030125,3274829901813881868 +9e0c23d7-b6a7-084e-d11b-3c76efb68689,372248204,14823465497996232928 +3d1c56f7-e1c0-ede5-30e1-5314d411e995,828953390,5846448711351730664 +b68da106-aeca-198e-833d-55aa59274402,3870371764,10287485079822233332 +9599fa80-3383-3b8a-43a9-0f3004843c44,707544370,7674995129892462527 +50ee55f7-ed26-08b3-1ef5-a477ff6becc8,1568741497,1033261433056792333 +17e3ac05-2049-4abb-72c1-d174c5dfbdd4,3613441147,11746708761564786486 +0f001607-14af-b73d-f225-3750e47bd619,3163894492,6171388972989809316 +e6b3c39f-4112-c0e0-d6c2-ddcdbdc99ad9,3832339404,13458064359150984689 +8587bb5b-af2b-dce6-b73a-10dbc3263ed1,1741664691,14187304876985923115 +b6a082c2-e6de-fec1-bc38-53c1e6675cad,3478393843,2048847945493637065 +41b3bec6-1ddf-4ed9-c83c-985b30ba2c71,3621489846,3719577826361088374 +74eaaa55-75e8-6102-003a-37831f6c1c58,2013695512,16587274199018567659 +0767aa01-dd8d-92c3-084e-05f14a944435,2926178144,6014332123069986415 +c8738673-c068-a7fb-7f77-338a5be4307b,3823121463,14647275916487602355 +45558f9d-5132-d583-5546-b04bc15d4c3f,1689339836,6625522409615056205 +130293b5-c6ef-15ae-3a1c-177e14a8118b,1651123584,662795455825280507 +379e23d4-459b-0a06-4ab8-ecba9629de53,1213797878,952668957096362870 +f869dff5-4530-f832-5bcf-610c6fd534fe,4242168477,8940851830056007830 +6d1eac32-0452-7529-d680-2398f5ece1ca,1793514227,1314658482252237802 +3a38b65d-bb84-d0f1-d28f-8fe746438fd1,2701276085,4318346751168741248 +cf3b6aa4-25a8-fae0-9fc9-65e78d72da7e,2467859519,6347886633585280057 +77fe55ed-22b0-c624-cd3e-16372691550e,3332832744,2302141231513353230 +d471bb27-1cff-63ab-f71c-e64748dba08a,1906063490,3848440904363376862 +100ad85c-30ad-4c4f-6bc6-33f1bbf1d848,1869682233,6725465995283685069 +2a828320-61c3-f677-22ab-f12351e00365,2462354161,7489919852718670935 +9ef39033-d019-ed2a-a7e7-3def78d0a558,381740032,10249099967372083088 +21029cc5-b90c-c448-6a39-ec728c93809d,276848590,5670416171902990881 +4743021c-75d9-3fcb-03f1-e09635c0cbb2,195904695,12110900027097978460 +8a9670ca-b285-3017-6ab8-f1880e9ed60c,3591401440,9214432819318922296 +310efd28-6f31-cde0-4356-395c7fbf3ce8,3166231993,2154599549548480058 +1cbe0a57-f76f-8765-b6f8-e6fcb7e26fb1,2346732609,9838676799736894130 +6aee44c2-4e6e-f379-faea-0d8f9da12f0b,938370554,1176639741787539112 +8bcabd5e-64ac-b0c2-08fe-894e999a306a,321436991,14623418078776984463 +9d3f3ce8-d56d-c548-6804-4635769ab9f4,49222568,6075050626613126574 +1a7295bf-203c-ffe1-1b18-cb8f3acd4d10,1974101997,18070731871030356508 +a41d201e-e4a0-a913-eeb7-fa8b7447565d,1668901996,5883081835358886554 +37b8a204-2666-2a10-f5eb-4348816b7f25,1503710746,11173166522370657083 +76cbd797-567f-cbea-506c-00ca226d8e5e,2920927776,3760147711320745699 +e144b338-e02a-c14d-8c07-4bb37afc5621,4111306282,15869182352067459566 +66ee31f1-2528-0c67-b891-dd22e8ffd509,3207346022,11071884461107887876 +ffec6ce8-fd92-b170-3645-89d9afd66d51,602145083,15574599384798223835 +23fb5f7c-0a35-d9be-6134-f8b176144f36,659904527,15617363428006126409 +0a5cfbc7-8e02-02c9-2248-85a5d65087c5,1667271366,2975132331295372070 +0f3c9c68-d595-884e-6d87-952e6899a1f4,3590124560,17517633291135713671 +222c2689-ad5c-9f7d-02a6-1bec0a3d1bf1,602188025,15569415383878683574 +403572fd-7aca-bfde-2407-481f048d7383,719105889,1889229751191988327 +6da8987f-6d23-0635-e316-56416f168ed4,2736211505,6851638421691986916 +472e0fa5-67d1-f780-0124-bf2a5acb19bf,3503127736,5445976873390321681 +430145e8-cd30-7f5c-5a98-6117d7364952,530674204,12132036341279420392 +1825a474-88ce-cf7f-af7e-f1e355a6b0f5,3826722727,703341594951729451 +71552a56-8de0-227e-a241-390ce87d1494,318923276,17793996872917494494 +7f4f5c11-c1a6-8943-fff9-b69b93f5b90d,1858049463,8832430649644492187 +ca4da15d-ad70-2e90-7f61-4739aa13279a,1807194796,2575703675668873489 +e026861a-6b23-40c4-1551-da4c1e1574e0,3385676345,15564416119583128074 +ec434f5e-7d68-6b39-2a37-00d528fd76d5,2875937281,8017121173540549652 +ec068373-9672-f44b-d130-81b152232451,2490376575,15545245930070732213 +bc5906e7-2130-05f2-4cdb-0c7086947441,390987927,14868147592306255261 +acca0f80-786b-638d-72b0-93bfc63199d1,669909526,8402021734212153360 +563df0da-b97e-2207-ef3d-0b13f76b08fb,2361813405,6815935344395458472 +5addd32a-31d2-4bcf-dd97-7bec45bc123e,3026450923,16496398967293756542 +4a02c224-bdaf-73ed-b2ff-f5974178533b,1923977229,11904308258530864906 +2080ff94-8aed-580e-04c6-a62d1c397bd1,2438192043,17557144433919613528 +b6a0779b-b09f-4408-c357-b050eb44d502,3413525857,4436354130443421469 +4164ca62-56ac-489b-f1f1-cc684b8cdbc3,828098603,10609400455045029005 +cc8b683f-f4c6-7a9b-6446-9e68da0a1351,3597760289,12008690087284985100 +a0d48241-8d17-9343-454f-6ecae718e720,4133900692,14798530219510149077 +3b0a0253-2236-2a6f-34a8-f8db680d9fcf,1128096946,7170384070495908259 +7565d8f0-bf24-5b0a-b28d-f832e3304418,3810245258,8784571754222603516 +929b7bfa-88bc-b530-88f9-687a4e394429,3133613848,5759951304057837941 +f76d7f6b-da73-ac95-088f-f769f781101b,1312298410,10898717896078028479 +914d9851-97af-5828-4543-dcdbbf55723d,3847579815,6877308104620290536 +0cc7541c-3724-41e3-7b4b-aef0f09950a6,1305404734,11082319813828031764 +8e5ef6d2-dca7-3483-271f-cd7cc8b42faf,3078127069,8434388065935369254 +56f696b0-08ee-5627-2c14-617e1009f5f1,1578933862,7427646094947329685 +f8f1caf8-7e72-6455-75c3-16f2b03a380b,1031757112,9126419370355753871 +0e0b1f80-5bb5-4638-b33b-66da6865d91a,2336521373,9174003172186316611 +c9a474b9-f33e-b1e2-2dd4-ef064e0391e3,2778045909,6885619544501043837 +aad80ce5-1ce4-e92b-13a4-19085c19d764,2720216523,1072408045806508209 +c4658e21-7951-1717-efde-9f5bf5ba20f5,1298734876,15726281144351087749 +ff0cd4b0-55cc-64ee-886d-e7cfc2cdd045,3963076043,6280338609818433528 +f74d44f8-0864-497b-06ee-ce763d4e6f24,3990111261,14334841441225293257 +9518cfc2-7b80-dd06-7596-45a16c3c1143,409299420,5155442761844120265 +920ad598-bb1d-f524-6dcf-0d2c90963f9b,4101003267,6438038516426764853 +4668316c-e7b1-167e-8360-dc413ce44639,400561708,290023327639119269 +3222efc6-ccfb-cc46-268b-6d609111dd24,4223677163,5226313930249306624 +bda05fa8-84d1-8a40-be26-5e3edcfc803e,2690763296,7437255116204313525 +2603e10a-a24a-862e-1a05-7aaceb414782,1563937170,12498707562364415551 +6f99c407-c0ed-1698-15b3-2aedea5d94fa,826874845,14695876149045586332 +f440077e-bf7a-6402-7c0d-99ddc3a3be5c,768716292,5714990547888971805 +90c8d703-4afd-31c2-3302-b50154cebff0,4024554389,13539780371761570691 +96823a4f-aee1-dfc8-1d8f-89179ea8926a,2319926822,13691789458887515000 +b2d0be34-6a13-28b0-7267-164ec54175ba,2820541979,12618800807664521409 +6eed23df-0027-4055-06eb-ebac082ef015,546788775,17912504980906198334 +56d233bf-ca9f-3240-ee87-69e46d11e47d,2321955584,3503591114258602409 +85454b1b-2b84-1ef7-5d46-271ad48e701c,1223223497,4226826683712750175 +4bcbbe6c-9da8-55a2-0889-4531a4847bc2,1718042486,14084191592749266858 +fa5782cb-8eae-bb03-51d0-ecc13e7f4025,124396252,12535121635226750439 +19d3b7da-9923-0da9-7174-09af5d74a54c,604178336,15577447010190316577 +60913774-c75b-fce5-d515-107783c7426f,203547021,17074231369269825921 +4b50c3ae-fd23-379a-397f-0de7f9faf697,2784672256,17836698881542240462 +c87de0c5-3f1a-31d4-a4b8-23bab7f720d3,1902112154,12921123865907346137 +a2dbc5ed-577f-8d50-fdf4-38891dd69c3f,118310429,6746387465248199967 +39024ce2-b9a7-1d7e-d7c3-891fdccdf9e7,441478759,15854568768371840110 +931ec8b5-c2dc-1e8a-8d7c-7f9103172dbc,1363918881,12308266736124489902 +4d594399-7249-ad7b-3c20-522138bf14fd,3226302188,9942940881581053871 +1bdbbd05-cb69-14f8-1d05-43cc2d10fadb,2472975161,11308734361237804699 +4e827c4c-ab35-1252-e533-c7a0a3df861d,2788131008,5617540880238894052 +006c67da-5655-b523-0d11-8aea6671f2b5,3163356879,17182075204897657583 +001e87c4-5818-f915-37f2-14d4690a333c,1322121496,7460815163094246292 +c2234288-3bef-21a4-5862-f48d845b50a8,2035336604,15016741451301585296 +2c475497-e13f-634b-31a0-3fe9ad02dee3,3145002051,17030568635869060981 +85c41e06-7690-fb60-6089-0fbc67ad5a38,3381611618,15623247809296755291 +478d15be-d72d-f59e-e0fd-00e66dca04e2,1729788316,6134716389492946597 +a01a1f2f-6f1d-7c8f-14d2-1cc496ce1614,2148910771,5968410247238216878 +6045d3a8-8b3e-a297-a9ba-424ceb6c05e7,589502750,12628968085060403823 +84f7b704-8181-66f6-c80f-a6e3152da394,1282524665,13313902707779028653 +2b7e72de-b748-d312-2be0-40fd5b1d0820,3163310698,4910995421331336627 +2cb37219-4483-e7ca-15db-724528e030af,2347639552,3869276482528506449 +9534d93c-5e49-0fb9-11c8-fd3332db559e,240274706,15342755021048766991 +e0758cdc-ecff-8e64-9c5a-401e6b8594b3,762223613,9685088496349697340 +0cb0b4d2-c01a-8136-9911-464aacf38df9,429913650,11082335047553560056 +6fa3a12f-57c5-a756-9976-f0f4718b24d9,608386844,17858225263211598366 +19aef310-c285-5d01-0aed-bf3738b40370,2234902781,1835348316426518878 +d52f183e-d9d1-2321-e385-6f04341af968,257457190,10008009035438216900 +55bcafd7-7017-6333-0bfb-9d6e8f914fc1,1547283030,14542114141891721756 +1bf151b5-d0e8-c1e6-5072-0df5c507ea10,3936650167,10812985116390830544 +0ab9285e-3bda-ed47-64c9-e0e03aa44661,3292117206,12082755114948104161 +a50718b8-4c62-4dd5-0518-71e5d31dab4f,2789247364,12594365641637159305 +fce81632-6de1-e226-00d7-4109856bce10,666729818,17314643373060011289 +142b2548-2a05-1495-d571-6027da09fbf0,3691775408,16318871290100633758 +bbfedbcf-5560-13cb-6ee6-1cd466ca77ae,4101635396,11266851288381466927 +2ee461de-2889-ca88-4c29-84cce6d9db49,2648514361,8303772131782622512 +3f41cee9-9d68-9d2d-0456-246157aa1723,1591132055,4066807692198983874 +32a1532c-5b05-884f-bb63-85b9f41b8cfb,824266910,16483403182881158954 +5f8d5176-46bf-4685-8280-5187fd850922,2420893184,4140161716236109938 +68ba7cd8-5737-ecd8-27e6-857c50423443,3829131492,11735024110741527074 +da1f459b-8870-b6e1-e434-065c316756e0,2439624249,10740896704965473383 +55182e86-3fe5-fdee-c5a2-39f90c689d2b,175768405,1808603716392226043 +d4ca085f-2b65-aaad-0e22-c4e44d55313f,3992528933,13415464681090666634 +07a7f5d2-73be-15b7-f7ce-0c156fe5ba56,667045274,17185109046568999148 +c0b276df-8cd9-6515-7a91-d08d995ac900,83353270,13693348881910680691 +165c6ef3-4a1c-abae-fc89-050dbef0da6f,2245529573,6752760424671732124 +1da0d346-45d3-7d91-c43a-e34ffa5f0f62,923328342,11096739580755650174 +5f29a109-cbe6-b503-e3ad-1e69f0a57f4b,3823156447,16362466181207661317 +65f6227d-e027-354e-964e-00fe4704b598,1941330057,7735775675237609571 +573ad961-2cc5-5e6e-6375-fc61490a9d03,3999098250,10346796583583730775 +02b7d109-a30e-58ab-3eb6-631d007fd8e1,136622987,8999379895407354101 +5647c9da-b23c-c3f5-a717-4fa84f6c67e0,521258248,983732213200170216 +fd7156cf-6c52-af77-87c3-da50980d6989,2703752230,17443408985528788701 +0b7925b2-faa4-ab92-edaf-88004c1f51b8,1783123202,12595186796179968336 +0218982d-d688-fd2a-c36c-34b00e471179,3467189016,5652130590275411708 +14d53f0e-918c-eb2e-893a-91b75e4882cf,2630309398,6836685915894116480 +a554adb6-7cc6-9c1a-f3a8-288ea1dfe18d,1294041760,1273284438588241672 +02e8b3c9-d4e6-5ca7-f415-e914ba7d8adb,1280858595,6560341070347102603 +19ec17a6-40e8-6eb5-8331-8fdd6e906c2a,431615147,9573099067453495417 +7ec955f1-acef-ed07-8f25-fa02a0e44017,3935796219,4658528989683846249 +fbaf8d80-7cee-76e9-07a5-6b23801fe213,4293639284,15020833014128753776 +cfb7c462-fa14-d702-97fb-098fb67ed80f,4281344791,3708621942729530733 +b97ab02b-d939-8144-bbbb-0354faf330f0,453113769,8569250229195559206 +c4e28ae5-e174-04d5-f9c2-62e29662fce3,3426832210,6266225940775161685 +c0f6417f-932e-f30f-8ccc-81ad030d81ed,1974125818,15836244327407413218 +6ce949fb-d4ff-19e7-46e1-99f214d4d6f7,4128540173,7105288249933333362 +6e5d91d1-1700-fddb-bd4e-5c4f33818185,339204050,10172098960570566832 +e7c6869e-7888-acb5-7b2d-68d15bd765f5,2582627463,3068465205056682401 +1ac88a6c-a06a-ebd3-a74a-caad6674f3bf,2308516853,270520757525754985 +b831290e-7a70-7ce9-2412-515d5fea6909,2282187817,11195838507804742165 +11164d2e-e63d-c797-32f1-5b5a745386de,2952612702,2121262382190865189 +2fb34537-f943-5148-3373-36a05aebf24c,1500531131,17448380373430892068 +cdcb36e9-3271-4897-cffb-b3f8cc8e7ddd,3773134768,1820244656923321037 +71408e9f-d089-f3c5-3837-e7182e781a5c,1525133635,3276875169669133491 +ff98ba27-d8cb-9954-2a68-378bd1a9e0b7,3773718946,10522341197145839110 +50893849-ee63-1861-20b6-16d7d2b9d504,1513696103,17365753869329092742 +22914a88-c684-e24f-fad8-d3a4ca3f782a,3530923228,7578702740626547837 +2b1301ea-f003-19ba-6228-baa1e98d3c3b,981800860,12241446606441315932 +ae8ef993-d610-f99f-6a17-eb4a270413ad,2229227594,8672209262290249347 +a2d157f1-85fe-4936-e906-52967bf5edec,2920691020,18007468172361006661 +f0f48a27-9f2c-a457-45d4-d3a3ae16fa35,3674777622,3203248289188990197 +e81f345e-a372-7e8f-7adf-1914c1f32c4a,2417098125,14015086615765471250 +7e549b48-685a-16a5-c2a4-4c3ac28a8fc4,788131542,14983636817372591736 +6c761f4c-a63d-569f-984f-69d849432bcc,2564212824,3632586268401177333 +11831439-867d-c919-0983-76c534d0c485,401998653,5800804689584940331 +347f2869-e1fb-8a2e-3d99-03461d1243ec,1019972928,12103649160708757846 +c85a50a1-e148-d020-eec9-407803a2edc5,2053391879,15556045974974603898 +48fa01eb-4d5a-145a-fd3e-5ee35cacb4a0,2348864495,15014301867678169251 +4f73a2b6-d37d-a7e1-b3f4-ceac13e23554,505069887,5314111046999080184 +a1a072d4-0d48-a882-593b-dbfca2d3bd27,4254180773,9171061581505685839 +bcd6155d-ac9d-aa56-8d23-50df159a9c6d,1070943357,5974801039323364077 +07b60c83-ce2f-9130-90f6-23783686b39a,1075287480,17741638830208381977 +daa2a3a6-0244-44fc-7421-cd10e6ed4cad,2663841562,5979557058127746873 +607052c4-48e6-2fd2-a241-c76d58e4b7c0,4079193625,1596365289736313782 +cd6be4eb-b478-2b23-7177-556875d4a404,2904963375,12079810307391139236 +f3ee34f6-ae0a-f503-8e59-f44dfbb439c1,100480926,12799517094224027168 +66684725-9f9b-0af7-2679-4d8cc052c773,609989797,15968405307782005739 +244509bd-d11a-f054-450d-2f1b93bd971d,3725380540,9156852334601789111 +e8f7cbeb-f3c1-6a6b-fce2-7fc485c48d98,13707637,16750924976775183851 +a496c3b9-672b-2418-62f9-b08c05716ec4,2025634080,11001298980309605793 +bf35d946-6fec-928b-3389-393b2de35fc2,2628543744,11638670265925817223 +bd9e8a1e-ec6f-2906-06d1-0c1c276b6f2e,79873979,10567276683928450999 +f008505d-4409-f691-dbd4-9d7f069a658b,1780986180,2939841204633474076 +c0943bb5-5247-40f2-6461-5a98b71b503c,1155126223,9358194787365128950 +914b819d-a1e1-e231-0cc9-fa36463bb347,1741373781,12771532961070539481 +fd727830-f8cb-9399-9a73-fac360e73872,511797769,12494554181000968766 +486b2e77-a6d7-5c15-394a-7bebeb601cad,175674056,6619709243310736002 +38493661-fc33-78a1-fccb-375677a9a0f1,4199583732,18010953548893091970 +c2b82a18-5abf-6260-4c7a-a74c447b7556,2679468992,14258196414326926428 +96c0212d-d4ae-c014-4a35-f0b4fcc70223,2594218488,2638183710664542707 +ebf01f88-7b48-ce46-f3c6-151deeb507fc,879449162,7622946365890623408 +80496009-e424-bcb6-d3e3-e33d9d12e5b5,1263989954,6206123860672921438 +7afd8fa7-aa77-6c24-a3b5-0640fb9249ee,2140346112,4278243130270461993 +c3823cb9-c09a-5f5d-1401-9c423815f44f,706775586,6398256552255408986 +4793c6ac-4754-6061-d7b7-11f7c032d25f,3456690431,18102542766986915015 +019710b1-9a4e-d8c4-17cf-9ed5e47731c5,3619296719,18072353062830257851 +3a02e398-617b-9de9-a5da-0e227f1dde04,323778885,10582812331975918682 +ab5fb7cb-af0b-5a17-4e97-01d4789387c6,248823432,17560932964076984296 +8c05b899-142f-f456-b16f-76d998d720b1,3138461062,16039911032315089755 +40b9f619-400e-f000-1a98-eee5f62fed96,2719723943,6140976584405688621 +2e0f8067-1bac-ff91-7c07-5c9e1884709e,2824132737,12004587176975526378 +05d98f26-3778-569c-7c74-ff66173711d0,3389853254,16591812322842837462 +3610a3da-709a-e593-10b2-fdf748643528,2838619028,5526036643589617124 +67e5ecd5-5e7b-f849-e3da-077de32b12d3,1071347694,12541216149987567244 +245b508a-68ef-e1c2-36b5-0774f289c8dc,2546908194,11677949969650610208 +66362270-d8e5-d7ee-53bd-014e332c5cc0,84221738,16916624194897456791 +bea86926-de88-60de-fb5f-926f4b92b98b,467516481,2060659002560325744 +b80d4c64-118c-da6b-a674-bb8048d7f19c,96563005,6035806128919336281 +b96a3275-8ffb-cbeb-74b3-17e271683e51,612355110,15309239508278881429 +d1e7252b-1e94-3a8d-7253-25bd5c04418e,2736744880,7413180055195712489 +e2d7619a-6446-7862-8f94-2fb95ae561a0,3281975737,16800520340339946867 +67c51fe4-be01-59d8-b386-06baead3ec4c,379468379,5966865769545535978 +3f54604c-f496-0966-2957-39bd0795384a,1633815697,18007893160704839367 +600da826-9126-55a4-e38a-b9cf0d5e5e66,2443251373,14587092866260028826 +5b92a459-4bed-5d0d-b2ff-5fc1f1740d9e,467759410,14675800102250992489 +1e7d4808-8955-8879-39ea-7c1771c733d5,1547423684,17430692621048698498 +8dff87e3-fd53-e79c-2161-e31dbf8d5e10,862951301,3737608867810325436 +e1c8acc1-df34-a295-5fd9-a7d60223a2aa,4189985593,17321398195973400191 +75e2b557-7ac7-d435-504a-987ae73762ab,2178693903,11020110536231760021 +0c64ca95-e79c-406e-5081-470123c306c4,164149790,1458020435044294726 +114b27c7-03f9-0367-55b8-75e78696898d,1011630831,14097314746154929632 +03560e66-c011-8217-1f19-0e7c0647b837,3204202755,9812178220620948208 +a0a2ddc3-a536-9ef3-edfd-6a48f36a4788,736957004,1730508914335421990 +0902276e-94b6-e9d7-e08f-f7d898f55cc0,1536404087,8336183590917334386 +ee750403-2bb5-f077-fc99-b6c3aded838d,3021675701,5834445520533434709 +0996243d-c692-c859-24c0-c85c27cb60a2,1130392373,14107608929792058028 +59a73359-2f9f-cbe1-3a2e-19f65fdacc77,2346815295,8567291214929898128 +efc9ca2a-e407-51fd-55bf-c996be357583,3141239482,9236266806461878502 +a2c708c0-f5af-37e3-9170-07ea23f94edc,3542939632,8352991248670592511 +a21bf78f-91b5-bfb3-91cd-6eda849b1862,1761964311,3052214385171461697 +aa4eeddd-1ece-8698-cfea-6969a05c7fcb,524890873,11446454789970977576 +58b14a77-c95d-8c09-1679-9ae069c694ea,3220258996,8951386824597475257 +e3251c89-36a5-e8ac-6379-d0226174779c,2834932068,18334668973260009937 +e07c452b-210f-21a0-bd38-7887ff60cf14,1526668913,4525184991221316828 +3a4b1238-6bbc-ce0a-17cd-4d10fcd5a0e5,2604341982,12009760487066684701 +a898b10f-8c88-c38b-9530-9b39aed993c6,1589183106,4774013588000806951 +8310c32f-4d99-ad31-ef80-7a2530e0a334,2840064731,9722475998685122256 +038eefc9-62a1-91a2-0bb2-a7f823d9fd84,364903194,7922143242472049197 +7e471828-492b-6aa2-354c-fbccd89c38e2,862741031,11319347594280264532 +46cf958f-9d45-684a-0766-2c05763e68c1,2270394834,4255197251569241951 +ced97e29-dedd-818b-83aa-4927123c5564,4051777568,3334371108092912245 +7e2f0a8f-7d7b-fe9d-c436-fb23a7201186,776837960,8268117366264285802 +e2a9f6f5-707f-04bc-ce11-1a1ba6cc613e,2460212180,7471415335717932683 +0061ed78-0c49-2e4e-9548-2937a8528e78,189143620,525632787588025272 +1e88648e-9d22-963c-8130-10fd607bcf10,1790469007,2489636997929587855 +4d240c1e-bcfb-0983-7802-15c7ff508084,3224781763,17670654688755281584 +7f955b53-2e9e-71f6-c1af-baf2fc9f865a,1179426952,17024966869806700922 +0df9d25f-48ae-4a6f-64d7-3e2012e0d9b8,2863866364,9800911513938829310 +1ad8ef21-e57f-d9f3-775c-a31c4801a44f,1364829812,2115595148639892363 +a8da75da-ec50-1e5b-2517-359e984ae8e5,1792101082,2220367467230433397 +7c5a2d26-9cbd-e1d9-65ea-6b1156b3ad6a,3447668302,12280345781654741399 +83637223-0c46-6538-b9df-d7ae3d16439c,3785629501,15382086269012093645 +8d3f9f15-423e-5b89-e5cb-a795c167b473,1517062674,13450086666664550490 +46cb0a68-fff3-e119-bc1d-7c57e78e81e7,4235527483,5334804458247915705 +5ea025ea-6046-bd28-6ff3-9e65c91af688,4234146700,3977420768360400913 +a4656f23-2506-e5dc-3c19-946c076b5179,3798229771,11420835041828953584 +2a51ee31-c082-8994-6acf-17aae839c715,2210419276,11528471591098715467 +0d313d3f-fa22-e10b-8593-ea2bc097aae5,1502004215,6445927810071515005 +94c59c8d-d915-8623-e310-5752936a246a,1126714632,11295528811437405033 +87c5751c-e299-5ab5-d2a0-9cf147e8271b,3243502306,7094552128495033064 +a08f67bb-8645-cef6-0423-6b6e6c7606a9,306368491,15445584756112381395 +1bc95834-f10d-2d28-4be0-3c5a29387f7a,693745629,15194633707097522506 +6486df96-0028-c5d4-951c-d681e7e7220c,1282760401,11176471916110803669 +2f908815-41b4-8b06-45f1-df9d6e76b184,4078047260,9931281142231372515 +06e17f5a-9c6f-6644-b356-4e459a8d0dde,1791475726,6183146728212875179 +9b01c425-fb85-4d21-b60b-f9087cd137f6,1437056929,17308345172930619321 +736b47bb-e120-df2d-3ea9-90b7b16a36e6,2137856979,17824770170256436801 +24ee0a88-d9df-c24a-7d02-027cecf97270,1072894734,3281307734879611456 +de5004f8-f003-9701-bc25-9a180fecabf7,2813265085,13602311008238392625 +5217ce66-367f-49a5-e13e-952a64ced8cd,3230195285,14265974568834241019 +bd62daec-63f8-9552-503b-7a7f928a1538,1739751267,8515503744313625278 +60ea5997-30ed-a751-5012-bd3257c65b28,4168471784,16540046368478625363 +6baa2777-b8e3-112a-093a-fef0819aed62,4135797538,12652151439464210005 +dc0e488a-4583-3620-50d8-ae39241120ac,3513110505,11468742996765362120 +e3c92a19-3b9d-7cf8-f411-868f1762ed6d,3609183535,11285666337689977349 +1844c2da-2029-26d5-56db-7438d6102d9f,1098589576,3782624750085357306 +94112b3c-4664-387c-3356-c6b7246d17f1,1269621648,13069684619675736316 +3a1c5afa-f6da-c91f-f6dc-08e037d6d461,1270452823,11390221717469596882 +254c9be1-a096-9cd2-cb61-d93f00f340e2,2367355842,7467360413096594884 +6a85d0e1-db86-33d5-a917-6d14ce1f2f14,1656226197,6679404534732388759 +8d3841f7-cf13-fccf-70fd-47af51d878be,3694836437,3123843092347190309 +2fccb8f8-a9ed-a3d9-d7a8-caf36d24397f,3982850584,5757679690857787471 +be31a38b-d6af-3c3c-80b0-d2187484baab,2969392749,4228641156146851597 +46eaa426-e6da-7f78-cf51-c02c68ab25b4,300101426,3761993009694535456 +d9739a77-aa9e-4267-96a7-096842491268,1378162294,5098034527989321205 +24e78878-27ed-924f-5ffb-f9d044d87d3b,3563492507,3907226824063345791 +f1175e46-6fd6-2214-278e-6c649c9d1e4a,2389074587,9322844137870497539 +b5e60bf9-b270-81bd-34c1-e9065c396231,2835275588,8054674398623140289 +f535a62e-9669-51bc-be5b-32dc35ca97a3,3504034599,5145699965716082452 +beb14212-198b-392c-1142-5690e26f0e15,1747217960,3071197185538743606 +9e6af016-c3f4-7b99-b5e5-6eb8dad23638,3653816781,3827662545489627342 +c40dd6e7-7d12-9ecd-8872-ac32f3a0f262,3550227204,15386585875835205929 +7db5dd10-b0cb-8b06-cb0f-cfcb25da0afe,2752417758,10704128765986033687 +2bdd2e2c-96fa-c998-b932-664877a22f59,3616330811,8772432239383195599 +05f454d0-aca0-8af5-3481-0d18f395f05e,3157285649,16369231416382854861 +1302cc15-ced4-fdc1-3f87-90f4aeefa7d3,931003856,15772787931493914959 +8eeee125-ad0b-5206-442c-47d2e7cf05a5,3105275406,10946493326963693976 +b6b23546-4001-8171-86ec-52d8b03de97c,2408201653,14112033771721132707 +cb77984e-d1be-ad32-7a39-488295aabb5f,3636216834,5681088205438034067 +ffa20b20-75ae-914d-6daa-b80d6295b185,2615753324,2293544819938648098 +32f6313e-5fe9-6aa5-4e80-b37554d1590d,807541821,8570002532022029383 +977f5a0c-e9a5-ef0b-89ce-5689529423d2,1949417810,5723951063323333727 +3008e3c7-3524-590e-63a7-7fa4b58ab033,3785538161,15773011181832282085 +f5648669-9884-006d-6d51-842c3133cdf8,2336976038,8829328254495363626 +bffabdcf-3166-9571-681b-fe181774eed4,915177034,7523971248211280615 +aa4c3b17-4797-e01c-8741-f579963f585e,827250134,3617625869548458509 +95506a9d-67d4-3142-4a60-2a49f9115471,3306452216,14492511408411707374 +ea6c6bed-34de-de4c-3f93-668806aef5cd,746640131,11746797774564173991 +0fc34af0-2903-5920-fba5-8d0cf4e38c9f,1724504446,14650061821212950253 +babfe8b4-3dc7-caea-8e8e-4e8eb0a5c91b,4228801824,13361656844728764332 +0eaf594e-ce2f-b84b-23d5-5d8668210586,2498260737,9973560251793986370 +4235e3b0-05ae-bfe7-02e1-c88a58de6f8a,3380493332,5207730314628315040 +e2bf0fcd-66e5-75d7-be79-3e6f5d6e6204,3772560061,13055676262478764328 +fefdaca0-e07c-e0f3-714f-73225daff796,917479550,3093001870530920780 +a16f3be0-d61f-0604-2b43-13a6e6d33285,2506838335,6163231318171136767 +6f720cf1-9160-b014-07bf-604297269e2e,3494090948,8771593585803313985 +70eb00fc-0785-32d0-40ed-cddda30df529,927290457,9989166740887677466 +ad4bf6a3-4e81-946e-5228-226e4175ce9b,2452844989,17770540629948304272 +3e55c6c0-c284-d1d3-cb20-01aa2cfb31b8,1867614565,7899329606978293581 +b7c54eaf-a82f-c52e-24c5-8067d70ba302,952040290,14270253113675011612 +e11ef916-df84-0e11-bc06-1f0857224521,2661784127,288816500858819916 +3a5622ae-b734-943a-90a9-6ee70f9f48a7,3968818358,7013950990811168015 +82690874-398f-994c-9882-ff60ea8326a6,2608244201,4332900202600455572 +62d22ad1-bbcc-0e15-947d-5cb39bb70c9e,1733205797,4088328146951726821 +9c1d68f5-947c-90f0-83b1-7852c1712fee,2946647382,2316748158051616169 +ef9059dd-64d2-b5f0-b551-5c6914de6912,3706628508,15277037731462693050 +337b9476-a92d-1c9c-78a3-dd096926b343,1173759180,11098669640885193257 +2c1019e3-6b03-99fb-32fb-5c166e512886,2476616553,15717162108815558975 +eda55a6f-f5a4-93e1-c128-44d7030e47d6,2562705399,14182706453560125685 +702157a9-f934-6a72-551e-b51e40564701,1917925973,6983417643692848176 +34fc2bc2-a853-2178-cf45-cb95bfdd52ab,1595520321,8403312353663004968 +547935eb-0e73-816f-8897-f542dc9a22ff,2470454120,17267733178638585613 +0fac68d2-c4f4-f8e3-16c3-d606c412eeb7,2711522139,16225647242752005508 +7dab3e0e-504a-94f2-792f-3b19c85115d1,356106376,9310344845430082359 +63f643fd-0919-0c40-c7b7-9311ebfd2476,197595957,6539202332769120782 +0b017b90-7c52-c3f3-5e4e-266c7f0afe41,192419780,12166128461165410294 +06936c12-aaa6-d17c-d1c2-7548423e4ba0,4012322861,6299466707680009207 +f21fad9a-ff7e-afc8-bcf3-5680c7fee929,3471926250,5585809422755687539 +a34468c5-5333-e9bd-e18a-a97d8b4ed2a9,981482828,16808063838844345497 +ce1ca179-e034-8ee6-bea2-a4b21dfa39ca,3349184488,8097376935061060070 +4a7fbe7f-8a07-0196-40a8-f89fd6a0c930,902619219,16609634589220254345 +c8e96bf7-1a30-1dea-92d2-898b78954bed,3553076390,501198906879215497 +ed868942-08c2-0e84-7fcf-312a894e33b8,3996079845,13492998673855274521 +2837c341-7792-ea01-c264-5c83c820fe63,1670515278,11820114289560210732 +a951d3bf-31cc-3999-f0bf-17451f406358,3990608292,4728333828632595390 +465edde5-a67b-be20-a4d7-91099da9d3dc,3335752981,11212669256733346259 +59a2b2f8-481e-a18a-ee52-f04e596c2bc7,485055589,18238214172728281629 +d4152549-958f-a231-ea5b-df26eede56b7,1263114815,13966176223591803678 +9c1cce06-aeec-3523-b69b-58078354a0ef,2665238446,18084365441677341917 +d680a4ca-906d-1729-b4d6-c086e1ee5b08,4088640635,3679919665946557136 +07e9ec59-8f37-3f07-e19d-845c578f7b45,440451955,5104452355874722287 +9a791072-b056-c33c-1ac1-602e3a4b26bb,3554296039,5783788200293725989 +e9d74ee3-266d-00e1-1f7e-5bdfb1ddd7e9,3223857680,1340105393094971638 +1ead288a-c9d0-1ee4-a919-88087ee317d2,696363156,15500741950133104143 +117520ff-533f-19f4-dbf6-933311892726,3798552359,10413443488201274718 +f38b3b6e-e3e4-77a4-0e4b-7e947137459c,1969006921,14171610303279691387 +8858e7fc-a05b-e48a-f132-dd4032c652cb,3769438332,2831075391620413355 +4a7ed396-99e9-ae1d-21df-a65c07345ade,1372759783,16596161816623981369 +b930d175-4019-a77b-b88b-2b68c5c7bfcb,937208829,2456329402770485051 +46ef049f-8622-7c41-3dde-6d82dfbe5304,3272825930,15868918125050512579 +98ad11e7-5a46-29a2-4487-f70e6bdb8003,3270702742,16912282548971170644 +8ed06096-d91b-cb98-2102-16d23a43d71a,954936260,4725401991101267704 +7edaf0f9-2d12-1383-22b9-5ce60ac9e50c,508674635,11319908035016583354 +a653745c-ea53-aba9-39c4-7b538cc3f9ee,3719704463,4251177405514379144 +d855d3cc-38f2-5397-2c8c-98d0cb8efee9,60469670,2790110733782282317 +4ca42a67-81ce-1d81-e98c-6645e4840e2f,1932567684,16548173363977854568 +7180362c-5355-d722-7aec-ac6bbb6970f8,415501031,8360665672533711192 +dfee6183-bbd8-1a34-92e8-05bfc7d4ee49,95681973,7708426992681754105 +2884c63b-3733-859b-ba29-c28c77014087,1646655566,1439615752412680018 +1d30211e-c4fa-29e2-45c3-e323cc0dad3b,758904472,7009496733046404182 +070a12ad-2746-4bf3-f487-9379c583f27e,624005725,6647219612166493610 +982f1c0c-0618-5ae1-ff5d-0ca41de9369e,917202463,441830285391234403 +3480b54c-4628-3b64-ab34-c10fb44859b6,3780254559,10326398133710466457 +53473be6-0d9f-db37-9d6f-b99deb9c5b48,1703214457,18393446980438942938 +8ef32405-7057-d3e8-6b33-8948af0f6d76,3044021988,297095244814985621 +15e49020-d609-ad35-72e6-efdeb6377f48,2656062450,1844209168761988205 +4a83b687-8029-7f15-839d-7ddf534648d8,3779631649,1410137851189879828 +f51027ed-98b6-7eaf-e799-d33c9a3170fa,1802329910,13582308146738893722 +b83ee779-9a45-921c-35a1-fb655acf0ef3,3895114903,14830387306978554953 +7965d093-386c-d5a5-2f1d-f74e85fa67da,3074134614,12072877854858221438 +cbe4349c-3b07-7457-726a-221717626581,609881108,16514774591695298232 +2fad4b14-91fe-cc76-fb41-33331395a4d0,1580940919,9498049874913931388 +7267f715-90ce-f370-1f06-261cb53c9259,2993162563,15972869508971172508 +f4c3239a-a28b-c67b-86dc-1d9ff557afb2,2806351426,9030211035216200301 +43d78287-b727-659a-3155-7d0d7035267b,2789989565,10214518830179014397 +2f49566c-49d5-f95d-9fa8-edd328bf5f19,193247264,346576716949764542 +59b55ae1-e5de-cdb4-a4cf-c3dcb5557d41,3503306352,11157030632473462168 +29c53dec-2bd4-a758-b870-d544bb19728d,3335463011,13940920581324002494 +6a3ee1ff-2f78-162c-256f-0c46b84eac76,1087651452,329074544024498241 +1cab6dc4-3f88-bd21-2b0d-6c0087b82baf,1977333681,2653651765820094834 +6c737bc3-e758-77ba-5e39-fe6575cdcc27,2203277309,2154704557673353560 +42473508-e887-7bb9-0a55-f129d4b841a1,3399633568,2207241019568141454 +e56feedf-2e1e-c723-89c5-92e377df1f55,4075216455,15631093949278064026 +99515b8e-cc15-dcce-c09b-50d6743b1a50,2525332233,920985985920146350 +bb6a3415-262c-fba8-31bf-efbd2e28c351,4009378459,11170005909413534955 +ea0220a0-7e7a-5312-77c0-5e7773d63878,967524248,3971251299401859498 +0b31fec0-4a1b-8970-8da2-20aae509a0c8,3072232620,6913347579666086192 +06517f3a-f541-5745-fcec-12f1134e5e23,3470608782,2179964334143434080 +e02528af-6d06-dde7-0742-ef774b16e514,3183042830,5888779609948714868 +35d4d253-8702-92a5-6d24-90e849131ba5,2185848817,17759511354597944523 +e54dcf81-e64e-d4a8-ebc5-e8e077bb7302,679253903,15505461311842951020 +2dcc6455-fa9a-d77c-b6ab-cca85cbef9c9,3282344495,6701556288234554915 +1c6d839c-9d07-c364-92eb-b3f71d0c8f4b,76576286,16313377438141676912 +b70e6664-b070-53fb-4b5c-7965d4228f36,889315420,16793936559227178218 +f33e52fd-d05d-950b-40a8-475f09450a08,3668259872,12190503099640099408 +c28bbfba-2571-663f-5682-34072d27ae9a,474263566,13443166111674950249 +360f72d4-a7dd-4535-29a7-e0ce4011f041,3724404309,13451218834438566015 +4ef9dc2f-3930-1fb7-6803-8ab257d0bc1f,588143111,2549811083528082612 +088c9c91-fdaa-0444-c1e6-be27f46f53cf,440039254,1372566882971526730 +fed6309e-2659-860b-d9bf-f3614f0c2c32,3269054203,13792646611151611675 +e41366a9-8f5a-a4ac-f454-4340017b6801,1755856107,345279654831109397 +81ecba60-f21f-ffa0-5de8-4bc9e966092d,3298871371,2081060943914427343 +2458a5e4-de6c-56f3-b55e-021478ee0489,129140462,2334127328488283594 +f4f4f040-1b89-0be6-c636-20aef7546ade,422187846,16629674019299927994 +bb08be4c-1c4e-0e40-2934-b1077cd8a127,2559192282,733398902966512060 +afa34c09-342d-d43a-2587-737659b6020d,2917566347,9533887367641234492 +a8a6c964-89da-e102-411c-1028eb321aba,362565401,9460662121199206749 +665a0592-bfad-9f2e-d185-ab68f5954cf2,1456553382,16250890468197352337 +de4257ef-9dea-f1ba-4509-d248dfc43f30,932368760,6149604674689163508 +9d1e9879-547b-7f15-21e4-9ec6455e2f0d,676951120,16634038420956232374 +20f051f7-214d-8e61-e1d0-184a70e85392,3169824832,10374574547447483321 +faf42cc4-b531-2642-1d6c-e0eb10cf0cd2,2233467263,10370307825280657810 +560cad06-5f39-e105-ba8a-8435937167d0,3837591235,11941769229855530771 +fbb8c487-7b15-8eec-3ea6-94854c531a19,46599283,5157216063903533150 +661dafc4-c339-5161-3d23-b826bbf8c4ef,3209243726,18068085817453262913 +96841489-4935-9e0a-6b0e-b583ae890dc9,1507680126,12224629264350377656 +c45bd545-1805-1a88-2e4c-3726e999548e,591274051,18119088685662776208 +854963bb-b79c-08e8-a945-07eb7e19e408,2553573381,11365004851028715388 +b87b4338-cb93-59ae-66c6-af17b2fd44a2,3875222652,4166001842019740284 +aaa31628-1197-be4e-a993-bf442fa6e906,1405546654,3946132383138748155 +0ded65ea-e8dc-0da8-3122-09e42908ee4a,3860846947,12882872179451171924 +c1c54243-a03d-7802-5560-c490a88030b3,3851859487,3703177235117187217 +ae343977-06c6-9c98-7193-2bdf4d72d097,3558552316,7925710307650122149 +8f4668c6-445e-c90c-d0d4-3785d8bd1f44,2305506965,3518831167622440831 +0624550c-f204-71a6-89c4-c144c119bed2,3923600149,3206234691009221671 +22119e23-39dc-0994-2418-9ac79125b1c3,3209359786,14512431156293070801 +ed4a439e-1fd6-fbec-ab9a-8daa9080ccac,2102956754,18119533780787041843 +3d70e32d-0adc-7db6-a959-47e2209be33f,2048367386,13315574113503084978 +68dea157-d81c-8066-11cb-ed822e341ff9,3524488777,447514004979315134 +f60de2d6-0dc3-b98d-a4b3-a8a331fbdd53,1048276491,11958414006968628233 +245efdde-6be5-c88e-a4db-30f13fa43cf7,2797083123,16940104879787099478 +e11451d8-6efe-e0af-adbf-1473fe99ad93,238686274,12839505417647796341 +0b6fa25b-9a0f-7cdd-b9d7-4eee48033134,317881032,15659523883042809757 +e8065404-4b5a-8bf1-98fa-90df9119acb5,46497506,651576060820383968 +5fa63960-8ec0-2f69-cd1f-8984aaf7b848,4173985830,14045782487612401547 +e6138ccf-1f80-6ec2-5f22-cce17df76d07,2991831225,650181999825516330 +ce161e47-8194-ffd3-57e7-fcc95c64f40f,2897048827,7154256244951732601 +6eb2e11f-251f-a1ae-0cdf-3ef425c7fe26,1612340097,12622371344161963898 +1534b131-7926-757f-7216-111e51e9799c,355930575,7312059631120440231 +bc6d9255-c307-b90d-8b57-fd5bff9c775d,1998033529,13238721423112498039 +e782f20e-2908-4c6b-dca9-7379cc4fa6c9,769832433,11662911892209571385 +3748d067-a065-34db-7f43-74b411849d01,1789806061,4366552006650987386 +317635d6-a719-340c-f8e2-45d0bd8fb3ed,1466116755,11468681434339409062 +08fe56b1-bea2-f2d7-b13f-faed3f655b07,1541916899,4239125852789785475 +069be756-9c40-235f-541e-b990945d98fc,3834770554,16489362111781544743 +d9f6ebc5-737c-8cf3-9c92-453533cdcf71,439437948,5289633216350958628 +1c4f04f7-71cb-67d1-e1aa-9c3828765416,1496801193,6399277298088041439 +1da08b54-744c-c916-6904-44a3d0d177f0,4160929128,13984869954037561254 +a550dc83-2881-c989-557b-3c3692ce9f2f,3137038578,2153656013313316273 +88c18511-0941-605b-e857-a47873cf3169,2138595631,16102117511504084097 +c2477273-2235-97da-2b13-cef09e590461,1636870011,11147461615308528080 +748a2a9c-f96f-ddfc-7379-502c337d923c,3697808900,13274261401119486031 +aaa94825-a3a6-8f1f-4664-bac159a02866,2666674902,10520368467797196910 +be3efeb6-8ed5-4b21-4c3c-989853439a7f,271177293,7507644236818966317 +f40a8917-77c5-b8b3-194a-6a486d4c8312,1190764391,12698255241199321579 +a6b6ad45-d610-b68f-7aba-d861159261d4,4082492032,3866550373102946170 +59d69f61-1c7a-6999-53da-5aa1513f1d94,4186287469,14041808903608756309 +dbb7aecc-e69c-fa78-a6ad-0cd5ad2be8e2,2165101353,11550588973774338115 +f7c22ec6-4d5c-1943-4937-a71e05a6f5c4,3768443231,6438370052189498858 +ef083833-8dd5-e41e-c936-b128393ae0da,2882933189,7699451373308720311 +4c8fce18-7867-7d8a-e684-677cd5633f68,1823133722,14050139339710557599 +b9bcdc77-8bd1-b073-42c8-29411bd76d28,563887233,14130877342587237375 +0c176529-918b-9a20-b143-e44d8073e4cc,391235531,15601801147933885753 +7916b6ec-ff39-1f41-26f0-9a8862833243,2911044649,7392715689097633094 +ab51f646-2e26-3fdb-f50d-3a04e0b6c882,1573593367,2560855777354549578 +c7ac1fd8-763b-a994-f47b-c58f6e113ca4,2095809144,11355105434343518741 +e02e97be-d123-8ac4-fe97-d0e55bb4bec0,162949734,14620959582640554452 +c71e78dc-6b3e-c25a-936c-ff42741ebf8c,897579126,18422777793661487706 +91c8ecca-ec1a-15b9-e88c-a74cb7729397,94054068,15740905232404840179 +d242d78d-aa8c-c2be-d9ca-0b27fea996d2,566314727,2508786417694541376 +a8164bf1-199b-5b46-bd95-c67e16c96837,3304026052,3481591161972368853 +dd41ab91-abd9-4b6e-a2a4-e6606976c6fd,698675420,13771478622408088219 +990a5784-0b2d-2f28-9883-f4bd1a0a806c,2431625824,12119861002504465607 +15642687-e8a3-a658-b86e-842303144a93,3543727839,10694389627131014334 +9a85650b-4265-51b8-0c7a-fe9deb8619d5,3080659806,3673984479063100041 +13b5ec11-b679-6711-ab98-adeaeda18e0a,473503777,18289570344881845479 +fa6f5940-7fd1-745f-1bd0-eb7f72eff7e4,2657171086,11609844024139153492 +5484a5b7-623f-1ced-c409-7ade39368f01,2835767883,5759320787506965120 +eb51c123-971f-acb6-9d5a-70d7f98dfd3a,2685191467,8870130075937657576 +3839d75a-2cba-c879-3f20-803d9d77e9a7,3814292744,16561492563344799406 +426f489c-4adb-e2d6-8607-faebe2a4fed2,316284642,15173276939461466830 +fdabeecc-0d0f-4384-e95c-5220b593068c,2865769807,8150407812676683801 +535564ff-223b-82cb-86be-79ce5c7e3068,2591930242,9573218138216232361 +6e31e57c-2e16-14d1-ffad-127e821a14f4,781799053,2831596607800698389 +803dd7cd-f987-b189-d4f6-7cecbd73f916,3492507925,5926272020704683458 +3cc8aa6e-9a32-1e31-fa94-2fdfc62e81e4,4071855650,4558286160954532754 +ab44e00d-0d08-6f6b-8ff3-a800817d9e63,2587575023,13280804970537582190 +ea7f788a-e471-547f-2617-937f265d997d,3101932756,9708534002322992491 +93582587-999e-cf3a-81d5-c2a6b50736ef,400404764,651698952575432048 +1472d08e-3e30-a6e7-7637-6b1faaa8da75,456728505,13033971794668334750 +511cbf07-aeea-3d1e-cddc-2405cbdc8e94,1064330269,15208379524657075910 +4672469a-4eec-a6e9-2799-002f3e0d4527,1396899148,8781158456550623667 +beaac90a-6d3e-c225-6079-50432c1c4355,3216370903,1275421121117350819 +c2221cd7-7ccc-3bf4-f2e9-b462d7d17ffa,2134973009,9086341643443743272 +3da3adb2-9b01-3ba8-e570-d91d65cb00ef,3592907919,2954119502129642282 +3bf9f479-d078-1daa-6695-b2d1e2bc4158,1359917456,1600696786035549526 +064f48dd-e19b-a879-08d6-533556746cec,2617957888,12733027495940881697 +ad6029a3-655c-9480-432e-54a354e180c4,3389408253,15071583223171988990 +014be490-30b0-3e47-26ff-23d27a0d1ea9,530807620,9654477152621530993 +628cc0ec-2a27-2367-4dfd-abca717656df,42287910,11652836734351027560 +f3d7fd65-7651-50e3-9693-668e83fe1b49,82631246,11498495147020255874 +69d6e21a-1225-2942-d5ab-05b7ff463044,1627983298,17029491026363290406 +280fe16f-1904-c687-2493-c292cac98e71,3943433608,15432624651686670120 +5860a65f-46d6-427b-c121-aa8e562a5a7a,1670417345,11485949231655402220 +24cde20c-a361-de44-cb60-18e747e6a56d,1692690869,5735469752366936184 +c7069763-4fad-ba25-5b35-7959d138f3af,476025547,10918162594836869125 +ac3032ab-f8f3-43f2-fbf5-00582db5a782,3635928366,14363182429065825067 +d746e773-70d4-041a-ca54-ca725034ee90,3647469821,9913496640755989098 +5115374c-5d55-a641-381f-41b230429c92,3923328709,13832612162584078969 +5fb39e4e-2937-338b-03bc-4f0bd1168feb,1703224976,1345462520357016611 +57c7cbc5-e2b1-e30c-c65b-1f652999858b,4186737561,4732871566794987168 +3d5ecd3a-daef-d245-deec-8dc2aafb14f9,3296501519,16665295178023155772 +662e360a-2ff6-d365-cff9-f876dc4f74a9,3116938527,17207416318085681040 +6efb197b-ddba-a74d-9d16-29e1fc6b1274,2097041942,4959444453457991224 +d47cd9ae-6adb-ed87-4e3f-2e2f05e56474,3385647762,5940143416233440559 +e0722f00-5e14-1d3b-5a2d-7873d64e5943,3843159099,7672363305264919984 +9638e31b-afb3-8869-39d8-3a0fb36db56c,1165095927,11229182071524277280 +d10c01f0-b80a-0e37-4c58-c60177e31a7b,1007743157,7356836015029801111 +c5283cba-2b29-ac3d-096d-80a5efc12442,1320578739,11756292715570110112 +6ee494e3-f1f4-9701-5c7d-566e6176f18e,587098792,8931575237363374044 +ddb0471c-19e6-43ea-63ee-b301c976753f,1945471,9516894265026161247 +08c021c0-4742-20ba-3a32-9e6ccc272cee,2696303980,10622711687942522393 +33c40565-646b-ca5d-4aca-3de83e689bcb,2678333168,14923977391959516727 +d3d927bf-5671-71f0-22b8-b0207a787687,3799814887,10685077523926487063 +17c9c263-8b07-034d-f40a-a1d17b677030,79308011,8733691289002548502 +d429a1f8-3fdd-b5e3-d12c-53e08849e273,3341236155,13426731260635196370 +2af2889d-a8ae-7b1c-d083-cb6b64388eac,755380767,26405658769487765 +d94f3504-cf49-900a-6057-0cba88618540,3257159926,7633673170130371775 +cc877afe-043b-1983-484d-d0b96bbd38da,4279533654,13868420641572433529 +0fdccd96-f465-688d-f184-3806bc7b517c,3350313194,12180335557734552814 +e0220667-0edf-6f7f-2326-d50e228a965f,3519981408,337250361921589973 +4a553b2f-618c-aff9-c43a-5dbe9b314cba,3182762141,17825072689466159390 +55cb182f-b094-c1c2-8404-34dec515ea2e,1366167982,8913645195125347103 +561d72f8-1abb-f442-cd66-57b53d28cbf3,511499111,17336481828453339272 +ed566c23-81ec-f2c0-395d-47df990825f8,4246777925,440250585162694643 +8614d610-b0cb-3768-c20f-fe9b4ba877ff,1282350682,291389389991965950 +8872dcc0-41e1-9ad9-7c46-3f411461bcbf,1793663081,7662351661056205020 +685971b8-fc02-0510-eeda-62e053200e84,900056892,13825777933644151483 +3e7b0e42-05f0-87c2-1705-4233233dae53,2850147563,3915646603800278537 +25c10bfa-b259-2edc-2765-69f6d4554938,1608282784,13248443265392416669 +ea24b390-3af5-0776-cfc5-3fad953113c7,2613771458,11518173224527725586 +f37e0ca4-1ed2-8a21-a615-172be306a189,2056724905,1385664972932257629 +a0371e66-cb43-d365-d5f8-816cea3f08ef,2235167099,12945294612600988316 +d73b9907-cbd4-b9ba-eebc-e59df4406def,3032965956,5438241206822914985 +03e86f70-400d-11f7-0e75-b1d962330c03,3777066594,13921215524515888076 +cadd7334-5228-e146-200c-aab82787bb36,3561420359,10532234434022253208 +096d2494-6d3b-68bd-cae3-4730eb556153,565027543,16405813630750364646 +6dff36d6-d552-15f4-61f4-967a781a6cfd,1326495692,14268393039243439189 +301c13a4-bb66-5c74-d0f9-c7b122c0af2e,1079798653,3177752801300883363 +34e932a7-d54a-792b-955e-bbaf941c6d6d,4230541693,18030147449325799958 +f1303294-544b-3665-2ded-8dd85dbebf3c,3347922054,11357465419750530265 +9ea06255-8000-81f2-9f87-9340f7a1053a,3109340865,9581467550240664547 +ea27c94f-f36d-ce85-f693-f0777b5fb6cf,265861584,10602382909899403110 +70ebc1be-0ab7-2445-4d35-54b71164be4a,837908442,3640980016181479388 +0b3f4bbe-37de-3054-267e-aef2331f9436,896929608,13083086549346688461 +0852b105-c12c-3421-e24d-b2a36b7c089d,3211519230,15201937205267861233 +ed0665bc-d94a-995e-a44e-46f4d6c8ad2f,3984664707,5213416057386546430 +37a6a618-2f4f-025a-e20f-7dfbdff9a911,2359629421,14535208851702484381 +781a49cc-b929-ef94-acbb-4d99ef1009cd,1081559360,7862462026015068081 +c3a0b017-c31d-a3b5-3fdb-5c998065cc05,3873197207,16404158989518317966 +fb420bf6-471a-6450-59dc-789cc07207d1,3643289676,6095560284311491643 +c583b51f-3791-4746-d3d4-dea382312f50,3115738151,5310918034430552475 +e25815f9-508c-2486-a176-68718d9e1bbc,2271812311,12250606139027144070 +3d1d7950-bb51-6e2e-fc45-51e78b86afe5,4230358307,13121620805472820761 +8a04d7f9-b234-286c-56fc-d4e641f5d819,301681172,8694754410056227477 +80573010-1e3d-f39e-30ba-cb84fed8e560,4179282124,15685829692495706457 +5963d554-7c5d-6618-a25d-37ec4585bf71,3898577493,9086348615723148911 +6b572378-e0af-60a2-1fa2-0a76d140460f,2936852971,7442842091894520483 +ea136de8-f360-1325-6dbd-6c5ea0030f46,2512749433,7700599607392325670 +0a62a9ec-59c1-ea38-b3b4-e55be0e020ba,2865672573,13505572601170957899 +5aabd396-0a6f-5e41-7124-222870d0e6bc,518250412,18016355825646024900 +8d44f7fc-199a-2751-f2df-317e0bf94d52,41714252,8856689919916637312 +b374ed6e-5f41-964d-71c7-1c2a4f677db9,3430211771,4602057422146373394 +ec3b24ec-b7f2-97dc-244f-6921db4d675c,3442700607,16492755950002494160 +e4a1f5b9-0a3a-c89f-1cd1-8f9e650a8175,838961623,10359918259681515556 +083f37b9-300b-ebbd-b3cf-56a1ef8f0f4f,2882566089,3190269009344708142 +6b60f9c4-0027-5f63-1e6c-3ace35a2b500,2967102791,2300426150033059070 +fbfd52db-df75-204b-8409-9128d3f4153f,4171686519,9949135067091721186 +cc5bd7bc-2aae-8f6b-4278-852db255d70c,3082952873,12026811356594283237 +6a08e199-e6a6-b463-7888-323eb51fd6a2,1923466928,17589954708642952453 +c2341fc1-5d4d-3eaf-2b4b-4c981b356fee,2976609823,264668412311942211 +8ef34bb4-f774-93e4-054d-556d18244382,2173357983,4166238258046287371 +da30d425-eaf7-586c-7cf3-a0f88ceb4fc2,133190974,1726391514596159703 +322d98c8-4484-8d08-7702-89e75ecbb4e1,3315068508,4347933555221082082 +a5fd4cfc-5ecb-5a57-69ab-6c5a658ff3ea,3086733040,5587479769638415797 +df9b37bc-42f1-0d68-d1ab-5ba1cb169c7c,2188834858,7449242642682440586 +314266ec-6925-e7d3-8865-3935c7ad750d,4122523286,7377744373470900143 +6e28cfc4-d2ba-b2b8-6437-fafa19d35f08,1617199625,10267770547443653548 +eb6e7b0c-f3af-17b6-5e73-73b4a38d903b,596287340,1884576952026073666 +eeaa94c7-48f1-bf71-fbf2-4e23d70353ba,863972359,2214270446454769821 +db53ba2e-5720-c8cb-7c0d-ac402b067126,194791352,6428448887848629998 +c6889b52-adeb-b397-1728-fd789fc3dd50,4184168918,4568697079123264586 +301307fd-8b11-ff41-ed58-9fbda61e8d91,3510264174,12694917068022890702 +769fe420-4c84-4717-c278-efdfee9fe7f6,1883713861,4975383598675738943 +01b38056-4e03-1e7a-c405-7b9d480d08a7,62101950,16457712797457900011 +0dbba043-916f-a9d2-9ffb-5eaea16d235e,1208167100,4218070446918923973 +e10feafc-e47e-593b-b489-09a0ef2bd92f,324924825,6185249562718502254 +55e353a5-ff5f-f6e8-63c2-1dd31a1f5a74,2119136191,13628509989445125752 +804079e4-1463-a176-9f18-2daed7557db8,3151453031,16866877898672163109 +4beaafe1-39cb-7b6e-a0a8-c9982bfdd73d,1640505198,5744309926858329678 +ded0f234-00a8-d2a0-8515-d8d21d893b5e,2799157467,13685972059418998518 +6952bdcd-7b62-ca2e-4c3c-cfe0eae19415,805622624,6696853287681129788 +d346e35d-d3f0-9db2-731b-dc61f8b19e69,2841569945,12624961971618524993 +9983ec53-d1fc-d0f7-8c42-a1cb37803cfd,227420717,9023168825939916420 +ced1dedc-7bc2-5f84-1e1d-2c008d81f1c6,2197657308,17855953180937034765 +e6357c9b-9f1e-20e2-f533-2988ce3b9fc6,899528691,5399169404653378618 +1b6e0b95-80dc-19ce-25a3-8c367d411863,4227988954,13846631520330695311 +b1fe5ba7-d7cb-5096-c859-067c62045d10,2274227397,2125314144570083396 +7ce2f3aa-5dbd-34aa-212e-b0b0dbf6cbbb,806269887,8064407197161626390 +11507d33-6d77-1c89-72bf-d44e57d9a2c1,3185569339,12608045285608846712 +9ff15f5c-e284-4b04-15a0-6069aa4649bc,1469582181,5687903752893159835 +33c78e6a-0054-c3c4-872a-823eb814f9e1,764405222,16836578837365415127 +dd047e73-c28c-9888-ac8d-0e5c3e9f0301,884473021,4959291474442011835 +b4b2fb45-88ed-b903-6857-8dee5aa50735,2635836155,7751973116171320409 +a622aab9-1969-cbd4-d823-76d1f25b6bfa,848017596,5565868282707450710 +3a5c326b-b4c6-2139-ab91-db6f14e614be,3050289711,7725404260001142386 +232e903c-a8a9-288e-fc67-e3a8bf4d2384,198554050,15414759746142073248 +1092df67-be7f-030b-3df5-0ebfbb38dbb4,3782245522,4962418425322967146 +766e98f2-e36e-3444-3c5b-caebd363c2e0,2258903349,2148882255200805424 +f6bfb901-432c-15b5-8b0d-2bc07c50e664,4195395381,3817312007317167689 +8e9a50c6-ef6c-5bc5-acf4-3854fe3e17ca,3720033839,7536047927030584788 +f744b950-4c48-b6fb-07dd-50b1059d2965,1645320287,15993985055776088635 +0eac0c58-96c9-7a9c-85cb-b716e1d77da6,1470811388,610938688655430826 +1b5a8a96-0f16-246f-eab0-3935a0460f97,1634472097,7491099757749367358 +60b3af08-c5a3-f5ef-2a3d-f3bd3b95e65d,599646504,15914005561865607443 +6eb7421d-b882-6369-cfa3-2ce9bb2f75de,3816525548,1703000110560894282 +6a5140d4-2180-ca2a-051c-0387a360b5e3,3918049470,16910513642549845919 +db2286e5-8495-ad08-61e0-ea7a554172c7,3838329957,17048922320863165966 +c51c2dea-3696-eb24-1839-8be95292299b,31334352,2237209101001407509 +c0a3bd17-be9a-8747-19c9-782cd59e8caf,1496316773,12223401054705037641 +0268981f-655b-bf87-6a81-6b13e871ad1b,3959575817,13467368519329174735 +6a6901d3-5b0d-605e-f7f4-2113d62690c8,3804578524,1516381534467788327 +eb61dee4-0d60-bb58-e1e6-4f448112e48d,3819591794,4679460331111309559 +36a39625-e84c-fb7e-8fe6-cdaf5f33928f,3957899387,3559087521483901796 +ed3ed3dd-1155-016d-3e0c-8833409c7b39,588068921,8998717180311620147 +664b0aca-03db-764a-15e4-f3974f6ae14b,2021797882,2090839502763675374 +5a50a04f-c4b6-947d-b06f-68cf006a42cb,1569175963,2942867243385431363 +3f81cf6a-2f13-ee3c-1d84-f31b26370ade,1845298902,5749189535841549180 +b7addd71-55bf-5216-c26e-8096cee8bc80,2736931578,2245955151210080877 +5c885202-258e-31ba-73c6-14802991ddc3,978181002,12021078624260475716 +0e37d09c-5030-4739-df93-1ae613cb7556,988435024,17400065524640726330 +591fadec-b55a-c7cf-48ec-86c0b9b8467e,3130916981,17495348207825347721 +6f2fdff3-ea47-995d-9dc5-3aceca75b719,4183166940,4143127527255230808 +c7bf3f04-db3d-7a5f-02da-89ef5c8855a0,982321756,8526483098806340806 +cc5c821d-8f45-d5d2-ffa2-ffd2e23f74ad,1869337172,8600769896562562718 +781dbce4-91e8-dc90-6b11-4593266b2a56,396430820,11387989139236649857 +55a842bb-5638-f21f-676a-cfe5db667c7c,1728152741,15912755380345885913 +e02af4cd-a4ce-de8d-f6e7-fab45a28017c,3271584143,10576304326893777620 +7d8d5801-9f0b-2b76-dfeb-69aeb0ec7232,3931352904,2294606801624380706 +19e675b5-334e-e064-5e5c-84d23dee8105,4109842730,14815356459061871945 +d4d52235-4e60-c98c-8ec3-a1e3f282e37f,241695540,17287857669954568985 +5ab970a2-f67e-29e7-5429-0b40ce45880f,1050186140,827914099093832712 +4dc8f4cb-c074-9cb1-ee78-3e991cb9d683,21276352,12695038379090579749 +67c00b31-567a-b45a-284a-28e0f713a155,4067670647,9667348756521084253 +e2f1bc88-ead5-46de-09e2-ec6becb33fe3,3557132064,3782636161797250030 +9d8e6b71-7822-cf9f-9674-27589f970a13,1687381356,877853088054847185 +6602185d-71cd-bbd7-1b70-5edda576b7bd,436447021,15882687904199128986 +aaf6f559-f1e4-1cc9-0834-e7100ce50486,1136630654,1870979047681291828 +dab7ae40-1b2a-f132-772e-11cbd6c824cd,52372492,12245221550125219989 +3cd7f614-8611-ae4e-2841-924e2867cb13,2290047441,13244549622138132541 +98ca5f7a-4742-d202-98f9-84a218382b17,3044303871,1711031836726127741 +5744811d-42ce-2173-659a-d78804d4a3c6,77450795,17489435622023331898 +4b67a321-eaec-832b-2646-3b9cbf97bfff,1324315130,988708071061329372 +3dceba64-3734-4641-917e-437a5feb91e0,3265635259,13150920591033324383 +84e0ec9c-65b5-037c-9724-3ee707392071,2538970643,13127569053318809766 +8b58d078-6104-3387-da82-419dc97f0ff1,2839439778,4740874136156353272 +1f6efced-0e7c-9ec1-c02a-d7bb5dd04bc8,839775743,2151333522630486157 +5b20638d-9c47-67cf-aecf-d1e535f7e9e5,4161404706,6483629860748266006 +fc006946-a193-f870-d92d-e7be0d5eb86f,145688589,14694442175462557461 +33113781-467a-28b3-0dd6-78b5ef806a09,523385505,13154530428628940308 +5e9d8f99-546f-b4e1-6a2f-9e98b9842732,2503800261,15834848149941080842 +3c896204-d040-4a48-4dbc-372b638ec151,158039568,16121522166629611333 +ea8f0022-12f1-6cf7-37b2-10432d5c5352,1968362918,13186263663725537175 +218c9dab-5bce-4102-983e-288a1751fb42,3640092093,11049979229018456115 +0e4f205f-205d-91b3-4450-9a068049efac,561205945,2594655132239984099 +0b56b516-9731-ae5f-9ab2-998ca6c3b40f,688696088,5064835052636133947 +314b75b7-f3e5-8ec4-330f-f6ec78b6333e,361746242,14349409895205998393 +e5329eba-d045-8fb6-3fa9-8e0a8c22bd54,524376400,4983747142020025966 +5bfc7cad-1653-8f3a-792f-0a9a0676e6b9,3360083628,3989065864990996474 +7c138155-e8d9-45d4-c82c-2232a930d7e0,1865489905,13851157127849535244 +64590790-1488-7635-e2f1-879968868eff,1949160636,6808176729900284289 +1f132357-4a27-4fed-6f42-dd9e65ac6cff,2549575459,18090889491691019093 +51cb320b-cf8a-bcc2-b14f-b4d9f528e9f0,2327280770,16708676087281951394 +61936bb0-6c25-f124-e848-44bffe97176b,4098458341,6740682791834735850 +0d545c59-263f-590e-ac07-261000e0d3c3,2102831451,3946397474377126075 +f0e6b7f6-0b43-8510-c938-58ee4bbe28dd,1947311220,16276053266002120789 +6539020e-9ff4-901b-0197-d3f802dce595,857305758,4096719841000979337 +0de2a7f3-1106-2b4b-f481-0c01fe6a4f04,3687895486,8506610480511363753 +ca2a8b03-17e7-7f00-dffa-cf15a5d072a9,3165717987,13017517901722197538 +685d2a3a-5712-5032-4d86-c8bff136ccf7,3975867729,3982513639684630167 +5a2e288a-c6cd-725c-bf8a-50595488b8cc,2140182489,13284003993712718316 +3ee6ba58-f165-f36b-3091-e4c029bc576a,3938303118,6357411081474611024 +f4c1cd19-b4f9-1ace-bede-7acfdeda2e5d,3925316098,11540617493650880449 +4c2e1bd3-d6fe-73fc-ae26-1bb73d0fca89,3163316134,16036981266558891789 +50ac3707-be74-6632-294a-a66e0b1e14f2,1266038046,2074544214082544909 +1f88c15c-dfd8-29f7-8d63-53238829a072,2606876746,1354850301630777289 +6d1bebe7-1142-08f8-c270-ceb51a64f48a,3420514640,16367987648987834357 +a0b83d99-311e-3165-00b5-406dacada0b0,1379555064,16013245340794976178 +189877cb-38fe-a920-068e-62a31c77db70,1645866015,4263958849323196966 +a4458487-daf0-1a57-047e-7c14c0ae744b,3227686789,8328919640761480195 +8e69d557-0ffc-f195-d715-564e7c942d7a,1221764661,13929660849179862857 +50fac4f8-aa22-6c5a-ee2c-356f36b0dd17,1359077677,16503428658086680184 +9716d63c-599c-f228-7ac8-90b2c7409a6e,1479189629,7577194457251727306 +9523b0f9-702d-dab4-d757-09564dd09f21,4040068325,17048071631276876479 +98248ff2-53b1-e104-3043-daabbc2a9b9e,827305445,4427711442150769429 +5f6846c0-40ed-d5ba-dbd7-de896dbabd2b,1141762181,4443253389765348902 +59edaf9c-c8b6-abd8-e122-1a5973fca1fc,306377396,10288686187314073449 +cc1caa0f-ba88-1d4c-8b2a-0d1699a223f5,1073111899,9825009482329105079 +1b9a431f-1a6b-5bae-0430-f7fa9fb5db83,3059683415,13568850272396894965 +e2f95c2f-aa86-bd66-14de-e5027568cf26,1981056106,6939577865393797855 +00d271d6-fd72-710f-ab80-a7ffe9bf2d51,606072779,15632124896290023075 +4fb8b1d4-357a-e1e5-5eb5-07b4d8465792,1719289527,894645452091305504 +ab1a7492-769f-7ca6-b5a1-f2b1fb828d33,4123035904,14383474107623845173 +bc4db8ee-a798-b76d-2817-068bae19da31,2897888123,13667828469289987268 +ee8799a1-9cd0-cfc2-9265-6a98c7811bf5,1112676407,14535399224609214005 +256fd603-0b73-f36c-b877-6bbb82b236ab,150807332,8344888492917187465 +b496a852-db19-27bd-4fd3-8a42398b1ef1,2611785539,3169138230413151713 +f1b1da92-e2c2-94e6-2138-4728df4e3647,3231738780,14773029531338634027 +4f1237b8-d851-18b7-6703-ea6723658b12,2793147749,3435994309806928517 +b3abcfd0-5194-c9f1-43d9-0d1733d44140,2093206517,9695123992743178267 +6571796e-9b09-a6ff-5993-3083e1ab9608,776141188,9172068966669528233 +20bc7dba-5e43-790a-b37d-fa1054d4aaec,3424803892,7216068322328270365 +a8798735-6d12-7823-29f1-f99a1b431bb2,686862226,7325177843914742771 +8a2d6955-db2d-f02c-9261-04445c304d22,4095740701,16551394635686374956 +18483ba5-da48-cbc9-4c12-ae8596ebeaab,1017956463,5337370381261011165 +e49b1d32-2888-0944-29e6-cefcea15fd05,928689127,9193735787633573816 +9e634dff-c865-2598-3612-202254eced11,2855689926,3908713715319673205 +4180b85d-85e0-7089-f3c1-4374cbc3d60b,668246404,8988870293971595931 +f4b20755-ce69-4aa2-b11c-21ce030cfbc6,1648870350,4676652126515320514 +90cebb43-162c-2973-c757-7ecac76498d7,993084396,16582356257367661965 +55b2d683-3f33-5989-5fac-439540d881c2,2459148047,4958449784721815483 +1a445b93-0660-0493-17ef-2b36258caf68,1189120308,3095100890240434448 +eff5553e-8d77-7173-4bc4-3b2edd3e9ef8,1227099042,15975789034368382666 +eb448e8b-5491-6322-7884-f2ea612a7401,3552208801,10341146048799364009 +63b3fff7-9543-f549-8a00-a2b5fe0a3523,1767090943,6473823895381487893 +8dbebbf2-f3fd-59c4-3a82-aa4087fb929e,2260410793,13280913210253035494 +b4cb7242-8619-bf43-a71b-b32d668f98b2,3783131263,9776701122306222574 +b9b4b331-0a3c-6203-4aba-4b85c87909dd,3229755385,445792091291314623 +7f2382ac-91cf-8aec-d757-6a99120c69c7,3391917286,7609947516773518426 +84fb8b54-f9bc-e0e0-ebe0-c452303e1030,2510518986,17190397541311915381 +cd0402ac-d9ec-9d11-623c-d4e27db80b82,272648794,3433945648840082619 +9298b38e-1403-5e03-ca18-3c3c407b26ea,3075590510,14265934992401734082 +0a360937-478a-e85e-f4ed-b0d2e451eeb3,4016628023,10540083925472509987 +bafec908-595e-baae-8a27-fb5c75bb4e9b,1319048125,4890679751409177988 +e392834a-fe80-0f9c-1cfe-8a6718757e0a,3947700708,1999732844726705596 +ecce9a01-dc99-d12f-3bd5-510484469730,1843956409,8641862315973937413 +12adc32f-3439-adbc-6aaf-ff6202469a45,2531632857,13792644558499912465 +b7c6a2d2-4f51-1c98-5c26-38d55c1fa71c,1464554870,6838215304175608687 +ca76d56a-b28d-e293-1720-30800f4b28fd,219276766,6606549425133489104 +b0fbe506-acb8-e9ed-0ec9-3ef40e2de818,3098026022,14013849488822795815 +89bf4fa9-9948-524b-3360-92782af9d99a,992691603,974087525770063339 +5768ff43-ebcb-9a9f-6073-7a28ad9a1f43,2287438620,1300059668085859031 +367583fb-ef29-1646-3c0d-30fbfc207ba8,3935102453,900405303938434377 +ca74f08f-0db7-7791-1453-2d9ddeb58da9,1788786600,15211974510666475698 +a946856e-65df-2a60-9df7-3ecaafe3aed0,1077041058,714012160477940298 +4683e444-cfed-46c1-7052-36427dd4117c,2139054450,13309872596916522365 +324c04ac-6d0d-1d3f-22ed-1a1c980538e3,903340135,7201199262694694211 +514f42dc-80bc-4734-1342-e5c8e5aecdec,3985901698,17871656171660634317 +8be4210c-2078-412f-56ff-1b95b54e3865,38142899,11071838546988130245 +99a6b153-cbb4-98e4-ceb0-d034e1ceeac0,2148868984,16837372379694086148 +2811d159-a719-130a-9326-177428f8e228,203059745,1995736065113432774 +17c48bcc-57f0-8657-5d92-ee58db80de8e,3530676906,3971247669108097582 +8251667b-08bd-59cb-dd94-2985dd18d930,1722818886,12617553321956753889 +327e68bf-186c-33fc-0ad1-741a2fb9efe4,3534921022,11173114297911733352 +1b3150c9-ab9a-d7cc-697a-e16e0eb907b4,4130888624,13660536649174545444 +365b5908-a6d9-3757-3b1f-42e7c270980e,682940869,18146324615081642610 +8e014f82-c291-abfd-b7b9-d4fd98a2b16c,3853624627,257269290716187159 +2d287013-cd3e-0e77-20ed-90b2354a127f,3384192549,1434876614230270804 +1c03deea-1367-4898-d239-f863bfec7404,3763956236,14323900581725800271 +848835c6-fcc1-0ca0-dbc7-5a698e09caa1,1485053220,2051417984717784970 +e6c94909-4dc2-72de-e6c6-b12621852819,776547748,16769088799204828894 +b2a2ee04-c2e9-3cea-9f00-733032bbb302,1272454224,4690631111837829998 +1f36d5e1-1297-5ff0-659f-c95ceca6fce6,3649949192,8502147809610691949 +e5623923-933d-7700-23b8-0e768b154f04,812330303,5716263641993822210 +1da8d21f-c58c-321a-4947-76e2de9c2e84,3477371606,16391740824235283680 +b35a9758-bff7-782f-46ea-4a0c6daa01f2,1876240576,16066340258566616439 +47148caf-4846-9d3d-8cd1-320eed04f21b,2015052246,6704979729250171083 +3e297e12-6a18-69a7-c0df-8dcc6f401a30,690123492,10723055132463521534 +b38210a6-171a-8c14-3f62-044f94707c6c,1206858320,18383549045593119232 +c879298a-2500-29e4-02b4-d63f3161416a,2366592526,14944691973692444422 +60ecad29-8593-f04c-8b46-4ce6b5527c82,1924331755,4372434608670698980 +1e531751-b3dd-9ac3-3336-3cae26b390df,1645305342,15340278018942537130 +01b02ef7-af53-a741-80e5-d9bd74928e41,2205569115,8208548908701258460 +442351f1-20e5-789a-a592-a558548f9faf,2074003154,11190916084517211664 +b82f1dcc-5b83-e6c7-0eea-fdaac2108cc4,2791361627,10835551753948538845 +f5e92d6a-5650-4644-1bb9-3e69cfb96905,3569320187,5211995410265524100 +90df7dc2-28c2-12b3-2b69-89d7ca5bab69,1886753276,4303606595707304199 +b1725d51-e4f4-b793-b10b-88519c326e94,3785639284,8224829340880172897 +0bba98c9-c828-44c8-1a92-4a0dd699a1a8,3614408762,11581958058802552938 +d8280463-5f48-c46e-b834-069887954e27,3319860150,13047767027625738512 +112ea25f-24cf-0c79-e5e7-dd031b8586b4,3950032056,15392719607380968755 +578c46b2-f3e5-91b9-2cc2-fa23b5ab7755,4260962374,17658021650837086765 +c4d0f286-ca84-8625-4276-511387052ab6,1577864057,17969025976387311515 +a7f3e9ed-d682-f4b9-5975-027fc648b370,906323353,14606308148086212495 +d38a55ea-83b0-197c-cd9a-228ef95319d9,2974173210,7684591856636538980 +21cb3dd1-5b47-22c7-a5e6-5a45eecc87be,3289580467,14619481798216818160 +b8815dc2-7e1b-3b7c-6636-85e30dabcb71,2919975838,10395565910206441060 +9283077e-a511-91fe-7194-3c01e01c618d,3198708843,13306221075635190103 +695375f3-f79b-b99f-7c5c-a558a5d6f581,3424617433,593212673041348251 +57c8b686-1bd2-7989-561d-3d07abc486ac,320222450,977820211892084190 +13fcb2ac-bfae-a181-f16d-181e8fde1bbe,957129546,4104189794929239638 +09c451c2-86a5-0222-97e9-5a40ad22d82f,610202490,10374766826533122230 +4b95d8c1-16cd-0cf1-1450-335f69083cc3,4116724915,16920359312560655125 +d7b0c374-400f-4c76-246b-076f95e296a7,2034580068,2735151393562326118 +682d272b-a59e-e796-85b9-82523047f382,710187678,11547053330868903922 +50b1d925-3dc2-0411-5ae1-e547eae271b6,660900255,12807048955726600488 +b8f4c22f-b300-1850-d6fe-4fe03a3f9d3d,38916509,12424368617041336012 +84f4d2e3-9f81-26e6-4011-dba29a629045,2593064195,8963566111195837164 +d0d62c29-c87e-4929-f647-ffc3a75a3ce8,3301340215,10178572985518002368 +7c1a6d8c-59fe-6ea3-3113-e5e5dc885141,392578905,8382982996225980584 +bf02fcd7-60ad-20b9-b83c-01395fad44e6,210209695,15230364303069364391 +29a7e6dd-fcb2-1157-3769-37ec6bb4be10,3903648974,3120891803851825841 +ad8ecc83-b08c-a9c3-93de-087d64d0a0ca,1075436534,6200412561703908870 +e0b4fbe7-8262-0f60-a38d-462f10992d01,1284506386,13323130648138268334 +2b595357-2980-5f09-a5e0-094fb93d1a68,334195243,11389288716949142205 +58840448-26b3-8e64-3749-00926b80f6f7,2634080746,2364903191371846628 +63a7bef7-9ec5-d78a-85c6-6a54113c22b4,1128088247,1177242720791227310 +f944d3b0-1140-8415-f79b-652b4d358aec,4130823837,4935415248998388042 +4ff51730-fe8f-ea4d-c5b5-c4e6430fe12a,1025925126,1981400058248159141 +32851a98-440f-b4a7-a278-ff93ee84fd96,776209488,10714431459927910546 +370c4c13-d9f7-346a-c082-9d3dc92cb28a,1961551512,7696204310570536686 +f01981ee-076e-6778-8935-4a08afd06e90,417271452,6593102558166201632 +4f775860-03f7-9133-2d3e-1064cab4df6b,1877089494,2901775435605433185 +2e8f72ef-d12a-b9b8-c6c6-fbe7f6096357,2067958194,73248027505028482 +e060ec02-e702-232f-2552-76ce75d96f59,775848189,4467302794255039536 +ccf0a7bd-3839-0739-540e-254053640511,3457741404,4337185641088993139 +71d58db6-6f19-0181-fada-d866075c321d,690026061,16885489290584549727 +020d3c2b-c905-46a7-0b57-9999e137b72f,587691426,17714054622116429713 +393941da-3fce-f1f4-04fc-fbc3915baaef,1903946957,12061570730208150184 +4624f5ec-25c5-c107-e4c9-407cbdb3cb1a,3347596296,1872998377151731476 +e548882c-22bd-23b1-843f-6bbb288fdbc1,442590929,10904455545840041804 +7d7baf0b-2205-8536-f318-70fc183074fc,1748564107,10703543212928762855 +13b1790b-bafe-d5cc-166a-ca92fa42471c,2056620007,11705325787579992797 +7fceb9c1-8e3d-0f7f-30c9-c62ac51c793d,1405893543,1896328233953776353 +689a3e2c-0a9a-60db-6c1a-535e450a9947,2288342700,4105190056769134603 +89bf2f35-8f94-53ae-e4f9-59c2993519a5,1739809868,6643095196933696523 +11322d03-0fb0-9f10-f987-3c6df43430a4,985814784,12177113845202275246 +a5968be9-3e42-85da-e284-90ad342905ac,327065065,14385131694193892828 +83ba1d6e-9fb7-9e3f-7404-3dabb0a4b592,735356081,16199610838070161134 +f10e417c-bcbb-b736-6b2f-dab830735169,1796120577,365267034471256086 +33996eb6-94b9-3edc-c3fb-564620533505,2105212266,12093306192754823030 +ce1d2b8d-249c-70aa-7555-3de5cf549408,4232683414,7085547816940544383 +18eed44f-9423-a7fa-6df8-3ab395421c17,157301919,17064691841639698553 +61f3b3ea-e41e-65e8-cb6c-c06a1fcdbd90,2177082194,5387971449259074904 +69f7e647-7743-f93d-b834-509c65deadb4,2472081491,6189993665064577689 +e1dbd67f-5268-9577-96cb-985c3100f29e,4228541756,14586905950985883988 +11986a61-c83b-1b6e-42cd-e69ce45026a1,1237020806,6488741107528089435 +18dca29f-a8e1-d02a-d1a3-6cb64c497c64,1745081144,765971334840016807 +3f0d9e25-22fe-6741-5ad3-3955a5366f79,2108633674,8070749516170021009 +98305318-04ca-e69b-aaf1-a81a8cc3734e,2588150801,12439538593593327861 +77788d90-9245-6101-b5ac-2c97a06712a4,4086066135,13803837452375375645 +e4efdfe7-71af-1e4d-f8a3-ada2cc37629c,2556077696,2562445833657799647 +517f1225-9a8d-8779-ea5a-1ac4868ccd44,1224634241,18441048977592590061 +5ad1b099-94d3-3df2-e2cd-e747d04f301e,2397344037,18220116713790971583 +81e16aa6-999c-73fb-0e6f-d9ecf6d663f6,2777393661,11420769926199295390 +c06898a6-a042-3f44-168d-0467f1b6dfac,3628393018,11518009348113261715 +6d7c9936-9738-50f0-2cc5-33517ee2e4e6,2654541842,5020391222196580699 +b771f2ff-b11e-52b5-2ded-e0854a675fae,3568774293,11416725501689032747 +8bd03939-f7a7-e06d-041a-377753446be0,1846211216,2113063460775992894 +ef7d204e-0a60-dbc2-5670-cd48b15c7ce4,2028199817,9326269845576889750 +3e1c02cb-2c85-3f54-ef3a-1ccb9b9785ef,2365544305,16262234934051505075 +4aaff930-955a-3b44-f32e-0407f2888ce3,1571868890,17082015913760124719 +a9090ba2-d9ee-9328-edcf-410025bf5336,2925290980,240657407285629902 +cdc84a62-df9d-65c7-150c-82d5a441dc06,517101877,15509802537451505859 +8cdd476b-e755-6167-b4e8-3ed78ae4ce6e,363036603,12771070146783048222 +a0977ea3-7d4c-a223-706e-a4fba8fe7ee9,1715065173,8010350824442488158 +7aef07f3-3f86-4509-e9af-43b8df1b407f,1178464785,10143908207847712901 +820f6d92-6a64-c81b-bd24-1e276cf50a79,4269740939,835024563730555726 +49fd785e-9f0f-7f67-43f3-a0c338762065,3885735205,5192402334313022287 +466659b1-58e3-4f60-94eb-9051db4c814c,75366105,9923812499701032005 +68a796b1-09f8-93d9-c96a-5a12a9732fc2,793717858,15053169081076668445 +9714e08f-b18c-00cc-32d4-7a925519cfb5,2430593852,17573648792211363742 +75ea5fd8-afd6-3531-c0fa-ebaa577e241e,2190948831,720760156405388203 +320da18e-4ca4-9011-4d00-6407ff7fe92d,1061139900,988251180903250084 +2f03dfdc-c765-0c74-b137-bc45d446c72b,605772415,11846255836793368341 +f42ec6c1-ccb1-0ad2-3180-98b1a50a3fe2,608200126,18183631463345288337 +e4cab2de-3b0b-0c99-e827-a15773ebcf23,3352652781,12909481271209613262 +f65f0913-aa5e-c9e4-d169-2ba52123b8ce,969930401,9553854565334362126 +4a488933-5c02-8d15-5724-308fde793207,1712624057,823548441782954889 +3f92aaba-e8ae-c947-cd3d-d6fafecdfcf4,1018594381,7534165187092143764 +07aec73e-328f-a316-f829-297915d2eae8,4211772659,13928101777222803550 +3568d786-eecd-4c51-9c2c-96fad30f2a6c,1709374267,9325703626986464221 +18b1b0e0-b3e9-108a-7df5-a90eaa98847d,589065529,4422852032371751645 +8f4d71b8-8580-0d4e-6e8f-0aaaa65036df,4012321672,14829061165024088926 +fb71e76f-3c14-e44e-625e-9256cfcc0c08,4145606570,5277481830067850617 +8121d8da-778e-3220-5c54-80c31cabe7a7,1495383439,18269333225996307693 +47537d1b-681e-4424-5949-afce242c9f39,496154014,17660814414125460336 +4af98e5b-a4c0-d79b-5bee-8574c9ab3f6d,1510694392,16569209489948709231 +798b56ae-59b9-963b-0199-384428d6b5d0,204993764,7378863667078407644 +97e2bf62-114f-49db-e306-34f57280fb7a,396224075,16568721632123050175 +15064f63-b2f4-421b-6522-8de5f13101a2,341691691,2262032991398715093 +955f861e-964a-a338-cd95-988ecb8c8897,3922038828,8493145193298415504 +407342c6-f2c5-f84b-b955-f03581b1c00d,3490018700,1704037834187399164 +8043a9ec-e34c-27a2-374e-c5c0f185cbbc,2318001274,909335705918864265 +0bed56c0-0fd1-2f92-d2ec-6163097418b8,1422017914,17969162494337973614 +7b7520ed-c915-d8c0-fab1-d2f1aa085b06,771659323,126694317943419381 +9979fcc3-9536-4bf0-03bc-96d658556d87,4158673910,9080911840838530898 +5e155fcf-c5cb-d060-ea69-0ac105d7099c,87052126,8647519910780286306 +cbf1be15-744c-8d0e-651a-0c4c2ed8cee4,2825407017,17199139906710054542 +999a3047-d6b5-f3a4-f841-8c8278a546b6,2418523304,4494926282804073513 +d5fcd09e-fc07-dea9-a772-4c287446df46,2097562128,17206655320266502041 +1878cb93-2563-a1e3-0e79-7685100139e5,3739364158,7012592738525893097 +f4b8b738-1412-6a13-d422-748ab096751f,1888401896,8589737770756328641 +d5502787-d1f5-8c4b-3b83-d41efa6fdd00,2759371975,2459511002525191040 +2e8da3bf-bd5e-906f-1b44-2597a9647489,1630714375,14217967612030036011 +cf9ba717-52d3-2b37-8337-062560d7f64e,1986391285,12434673831001747300 +c7463aef-34e0-af67-5ccd-80a8a549d4f4,974739463,13543816833097550250 +d9cb7a7d-6f52-7efb-3f7e-15fe62a668f2,2643423209,1120123612070036124 +e7b2bd47-dc24-80cd-36e7-4d0f427f713d,3405381437,4394778977513026398 +4ac15d2b-65e7-6676-8c31-be68bf1a2d9e,3249292113,8015319577700633523 +704a8229-972c-1e60-c96e-cf9cef730656,1091186885,9735411339978452796 +8bf2da57-e0d2-981c-9262-fc3a4d6ef98f,1632546862,4034167320678782002 +f737c336-b8a2-a238-9bce-1c059dfd5107,342185324,15133814131265474244 +9a828262-9082-b43a-f648-f4db38962a9a,3939828966,17320928241482552075 +74ab97c5-900a-bc1e-9e80-be740e36e144,3397267362,17723862450140897921 +f82d94e7-0309-9dd5-9c84-fa2e493e00af,3656602272,14072090948428356224 +181ff660-02dd-a959-f2a9-9b33aba07988,2897672016,42860807357063660 +f616f9b4-8915-deae-85de-e08525700bfe,4185519204,14110062409073624804 +a25a48f7-644f-16c3-6975-f99cafb8671f,1912873048,16641260481952716468 +73826ea1-17a2-7213-aa19-0c2ca0d45e3d,2210335756,4863480123286147756 +9622dbae-2648-fa64-d7e5-aecb850c9584,3500026362,10634833747402462405 +03512f8e-4c4f-fbb8-2fb4-cdccd7984722,1962898404,17640114180839757407 +0069171a-58c7-dd1a-76e5-09b65235e802,586941691,4071710622372131759 +cf8d7a09-a6f5-a6e9-d8fb-acf254df17c2,1484106758,17910315748447622088 +089d98bd-83b3-1a69-1532-6bda73c5c010,2445858110,15606740093337121938 +e6083fc7-3eb2-bfd9-a393-a9fad03273cb,4096450385,10886714413616133884 +53fe4d80-72af-b978-90e9-b0d7eb6926b5,908042003,5958299878598699517 +d01cb21d-909b-c7f3-9bb0-888ed8c500c3,918870631,1074301847795278755 +ec67cf46-2cb7-f319-e0c5-4b9dc824b430,1205847738,2852474728451418594 +9e8b3f79-78aa-0771-2c31-fb5cda701fa2,1577862594,17713608968901862943 +90534b83-898e-a993-b9db-d9f9a9fe04e3,996774127,1983273657672572195 +3d864301-fb82-cb3a-1163-5b0295a3b923,4001832237,2135102156937929213 +6f481085-56ca-6c33-ebc6-81ed8168bf0d,2930257881,9819096603578512294 +1321fe25-85cc-124e-3410-1d915fac9e4a,1314417898,594488595275569484 +63986a01-6fe1-6d82-312b-e58b4c0de177,3828105138,7642357454850435149 +3b24d686-caaf-cbb6-5949-98fbd136bc48,3755542763,10678686950378603242 +738c500f-7b50-e061-9317-25db2a5df6a6,1044281867,921606430863303847 +cdb16059-3bf5-b6e6-ad71-bd3d11c266a9,2638807043,11750733685768359921 +df720aba-a8d4-a2a1-e3c3-f9072b19d0cb,417941094,16323743047572613933 +f8d2ee73-11d4-baec-868c-3eef4d9b1216,2196337623,9142065862097913480 +2da03717-e2ba-4e1b-ec85-c245af115da1,195947460,6001120996815808729 +209067ed-5c31-0ae9-1bed-17fc4991d0f7,826032510,979292545737422618 +c0ddda67-1d3a-6f5b-1a13-7cbd455db79c,3789486883,16993785642244832305 +a809fa7a-489f-b7dc-3ce6-6c3c34646c57,697508967,11876648342438339194 +c087bebd-b5b1-a5f0-668e-1af9e591c0c4,2689707067,14182905961163934070 +ecd4f096-e290-0133-a030-b9c088656f22,3146346459,2477173099296765772 +a79c0b33-7d24-f752-5373-10d4e07a7d4c,1070367618,16947742868382350027 +4ff20f48-8c44-8518-3bbe-72998268197c,2869528997,16052719802129115301 +0588a9fe-9a86-60bd-cf42-a63f94a3123c,4167926034,17311247550488054726 +655b96e7-5396-c03f-0baf-075bf2d87c5b,3860737698,18438126049444514944 +a631a545-dbe5-181b-428f-10738a0a1ffb,2621792055,9653120232414180562 +1d03058c-b00f-48aa-0b09-2944c3dee1df,1666343991,3163658173934099649 +8bac7607-2a27-6073-147b-bf6da2fbbccf,2558301636,10546278945086860866 +429e5eba-5694-bedb-b5dc-f671f64a0118,833799501,13352164678133698684 +46207886-69b9-d7df-13fa-12c9f41ab15a,927869763,7408930308972012649 +8f088b5b-cc31-50f9-41ea-e35bdbbf34c2,1884635261,16287434556568905905 +f8a3b581-9acd-fbef-e13c-0e0cf13d4920,2216700002,13207439268701823715 +d0f93b89-0107-3db1-82d5-2fd64425d0a6,3809502845,1866800225580325540 +ed45792a-4838-9a7f-9a9b-fb6a7db4e74a,892210096,12122411191184785037 +e8e4c2b0-0f60-42a3-4370-3602eb56e786,4089367725,18341883307783073778 +b579d06d-7771-9fdd-6cb8-7a4f16cd3706,2955938771,4387907770482053993 +52283730-782f-914d-31d9-48dfd6f013a0,1313786647,8601152661429479979 +2a2a5dc9-87c2-e8e7-3c76-17f18bdc8a38,2332327708,11681260072750590393 +c8097914-7753-efdb-daec-d1e5bd911651,3878716809,11052601631377346904 +a7d0f11f-a5e4-2032-d427-edd03037d977,1141475843,6787906801738645691 +83f0a3bb-ef54-3cc6-2efa-1d0d123e0c6c,3716901592,629069982053091132 +c8d1b35b-d201-9d60-f517-7f236756d7f4,334998930,3157936085276243063 +9f5a7522-2fd4-dbc6-2404-6cdf21b9a1be,750321186,12917534701172620854 +4a827d6b-a729-3a5d-4dfe-ef5922d3c812,1419155840,14219201706884106567 +e2be0030-3191-52c3-1240-79f8483a1488,558969581,11532045361276037480 +751f89fc-7b57-46a2-ced2-d805b675cb81,990535272,13972673961224043263 +4f9ad848-efe0-5e0a-6acd-313f0b5dcb46,2213874636,18407143016217994505 +73f50f20-883a-93cb-f7a2-108c435e6667,894172311,13238726747857174608 +36b9f97e-60bc-5ab3-ddf4-8f90a131e778,2784527056,7142081686070768186 +710e55de-d16b-9fec-9e97-9066d9c088ae,4221883032,710987388746549092 +ee9c8c2f-35e2-fd96-33fe-18598c4df71f,1137948864,16397310632549877919 +529b85d4-02fd-1444-8e05-b93b396a2a4d,1509081077,12018629139155754898 +39dfe3cb-f5ee-bdb3-ac58-9805cfe395a9,422056332,13497195256643364784 +54ef3aa8-34b4-915a-92be-9f2934b061fc,1877034195,4518903528946119334 +ff1bb59f-9eed-9474-4262-a237cf5370f7,1287739178,8156424893359771103 +cfcaae96-a083-83ff-1cb8-4bc139e57bc3,4216436476,9927059072807249563 +f5b1fd1f-a771-b6f5-d22e-253a268e5ca5,1242241764,3077942084018571178 +5407d1f4-c264-87b8-c145-a5414cd389f6,3091038296,3880101400366782562 +d0d2743c-1257-8921-0149-01eb63dda40f,2557678155,9117357281101983326 +42cfc902-0481-853b-3788-543ab6e89c3f,1128045912,8000401814902020262 +4f565ffb-ec80-0d06-b28d-8f86bc348f1e,2834642795,11564584634133541166 +3743a8fc-7edd-8adc-0f04-aff71c7c5df7,415351860,3657301779193354854 +8b40c9af-2431-1fce-b6d0-fdadcfa60e94,3459393687,4452114123140182089 +be367031-7ed4-1192-15f6-e34c1b00b0b5,2442939689,1849677629628070352 +5b5f86be-5cca-2f98-56c5-6be47bc98cb7,1573381330,1494014562392659925 +1e686236-533b-5f66-be31-a4b561b541ed,983481686,14142040023565896071 +63fa6ad8-e012-46d1-622c-8d91a53890cb,325535077,13835558181724024751 +8f206546-56c4-139f-8435-a26159c4990f,1224409676,2369035442877831030 +fd972623-a69a-fe63-acf9-2862cacf3d52,3166439018,9060666692446784339 +74e4eb43-7f88-4fe1-72ad-9dd20b18cad5,3395609459,6904949299524507103 +e3150676-c88a-0b08-2f4e-4503e12d378a,2971551630,718586230052125368 +867eadf4-1855-3ddc-1ee5-40b5333748ad,1975708311,11129353892262549724 +cfc8780a-9b17-9654-59b7-7e04ce1338ec,1426196895,10601809980685952461 +ba6f3422-36b6-4f7d-f782-bd900c0b9139,1870399034,11568025741288009540 +b0a6c025-1e04-ea8f-92c4-d5554c64a9bb,453413790,10439968642257032494 +7c00a9cd-f233-4ec1-d224-5a86e59c6909,2701320159,15056655841844381440 +f50813eb-b13c-fd67-cab8-84b69c410338,2255127598,9345902081749719969 +0f477395-511e-2e02-39c1-6990a619ed83,819360421,6055774149569986778 +10754cf7-10c4-0ffa-5d14-90b6d22d4993,163940561,12698658272446039035 +17fcad5f-ac44-77b8-0bb3-1d2e2ebbb426,3514798429,12732444131692776500 +08daf2d4-a079-7764-e0a8-8bb8817204cd,1226140351,15241015396534278711 +7b2ef9b9-0f19-7c30-98a0-a4ddbaff2d66,372245225,171377328786965935 +899c5130-f0e4-0891-18c7-1d7dea4c3be8,1092659941,2218055960023307052 +c46020c7-ff2e-959a-a640-a35129adfe7f,3182056010,17188163344577677233 +9cc79e4d-d9ab-3955-7a28-29ab2bacf010,2896195701,17032254608752482967 +89cedc52-6a63-7c63-3bd6-43505afe89e3,441960393,7996175564853340962 +a8b5e007-4397-b138-2366-4b877073618a,2566843014,8716448685396908303 +ca6b9864-e1c6-ccb4-bf5b-aba1c9dee3ac,57306266,4582362744492129825 +94ac1650-0002-3137-bc02-02fd632809b5,3609479176,15102613052599763452 +c7e22f23-d567-fbb7-9657-1486c3a3006f,2518546319,15533550019968854877 +dd62b084-42e3-4541-b859-39bcf2a0b31c,4278743642,9896513585251145779 +7d0c8d1f-b0aa-8b9a-1233-8ceac927f7bb,174651472,2698660282634958270 +b8654e51-54bb-ba1e-9ee7-168831f0c286,1389378473,11159168916972525705 +b1537d32-ada8-32ec-6d22-84c47e0264cb,2916197516,16726277178378180162 +44785679-ee6b-d5d8-b50e-8109c4892207,3750059113,16625507686145305273 +5a12d5a5-3755-0f29-f36d-8860a7228b7c,782783970,1860702722155954467 +4e7d7b1e-6964-ae4d-172d-36c6d98b8aae,1873521263,9024205535617862772 +7774ca34-3835-3c57-4430-1d951f9ca7aa,2290828619,6329994011604973348 +94191426-d494-be6a-ba4d-97bed434aa0f,1356336990,5571735759414800229 +de3ead2e-ca03-f88a-523f-46742a3ad554,2274975736,975310911189053711 +2539a8a4-1093-c330-329b-545d4fdd277f,2199213211,16224652879070078113 +ff160d61-222b-1c20-468a-508b4b517336,2451893400,2575237486372643207 +4a67ed18-ebff-7d17-859d-bfdb5b2bf94e,2031010627,5255961419362539233 +1fdf5cc0-b562-6695-7c10-650075724115,2106347564,13234428157462826822 +8f3ea7d9-2e8e-dc94-af62-c2b6586be91d,1543161435,2978466483548850380 +5a168497-af10-fba5-fcd0-93aba27ca685,2360042794,624613120626194473 +0bbfb27d-8f12-ea2c-a597-5686b29f1738,1989652511,12323210945923774169 +d8d44874-7ae7-d8a5-2bbe-03cfda76dd44,2264273561,3307686914720604091 +5c7c282d-109b-f3cd-f27a-b4f69ced3a0e,4293619719,1159295114849602644 +78c04453-7e14-5841-211c-cfa550ee56a3,3030086301,8472261729444505745 +029b08f8-5ec4-8f8f-4ff1-085aeb53a750,2001563344,10329486083652355918 +0f6445cb-a7ed-d44c-dac3-44a767d343a0,2385124501,1782282360554830469 +0c17e421-1c8d-6760-e7f7-186d052851f9,4251585766,6129621939065287344 +1e817c67-1f51-69a0-5bd3-b863e1b81c4c,2711794458,12409675282858712128 +5b8c2e74-bc1c-a341-83f4-30ebe3202267,797961272,10960403513410349587 +953dfe81-e278-dbd1-2613-ebb25798069e,1665268163,16039354066608183185 +9c79210d-a634-a92b-c289-d60583e2625d,1930360614,5787802462607724625 +9912e32c-598a-1942-8d62-e796ba05d1a9,4127067725,10360619107782192067 +d39b7ca1-79f7-c77c-55e4-69744c9f2742,308301437,7270127215930141462 +a47e7db4-7f83-03f5-702e-b621a9cdce4e,332392019,6663957196838982727 +b2695be4-0e20-69b7-5b24-1c743566d51f,1011092149,16739440550762514065 +30660ab5-d589-a548-031b-a31504c2b31e,3861273930,3964936797351683054 +921762fa-5306-09bd-c57e-7c79e1ac7896,4205166526,1226655986366420714 +c201c8a5-a704-4629-df43-7f7434c23780,489264250,14157084771531314671 +bc5cd9bf-51b4-e6e7-2b3e-d2067f3ac0c6,1681522739,6715220500557149485 +ccc1b869-7037-4602-1d7e-f6be371a5ba1,1079735557,8196353886315964224 +8565b592-1b41-ac5e-6221-ec98b417117c,2307562968,1231407458282877839 +157cfd7b-79ed-b4e5-7f43-4b6bfee39713,1120697790,12867302223802482572 +868f0b71-5fe3-7c5c-f538-342ddde372ce,2463965245,11120792545402458430 +572387bc-adae-ddf9-89fe-c4ff0c54494f,3837739380,5243702470950579312 +6796052e-5cd1-048b-e8e0-764375dc5e66,3970409127,11090282391698284071 +b7c35f15-efe8-17b1-4a0f-e5f77a12ddbd,2372723381,16254942567610091218 +499b5054-1a65-fb84-0b5f-1c0f2316f549,634034050,13383542621928845011 +2a14e42c-1017-6a90-b906-1e0fa471181f,833287006,7018165780218668522 +c1eb1cf4-984b-bb2a-89fd-c96642e76442,3099957223,9146281215453831881 +a1fa3bc1-210e-3ee0-a705-bc6e408241e1,4074630110,6188851829727156976 +fc7be3b2-3355-b42e-2c32-3eb433b3fa87,2713766988,2810393811292725172 +2a21c219-f2ad-bdee-4d2e-4b1c11907310,4009888719,15331305988802908140 +07145a5d-379b-12df-8e3d-f9ddcb62e866,1102160905,2035790234627141918 +8361c297-1ebf-1416-dbb2-640a011569b4,3850744503,7225170828523535042 +d182e1c8-e363-9fb9-0615-c6e21e8c7d07,2092945611,11588523409051919044 +ce7ef5eb-1b98-c6e6-087f-70a723b9b68a,3295730355,1902725998658277889 +68d52114-c12c-59e4-d620-fad42ed2ad0b,4287426599,11044120543266428830 +cf6c4975-2083-0444-298b-61bea33b0052,2387364936,12365644347424610518 +260c7497-f376-2256-1d8a-21156d12e06d,2854262767,13481108316338105446 +933d763e-ee0b-def8-b652-391cbbe92301,4112805369,10312690427606842971 +36b6409d-b2a3-e89d-2279-e4589386448c,434896053,2305480675946130247 +4e2e7b64-9e3f-0cbe-804f-85ef13a094a5,1010004096,14429331466443227986 +d97535ba-67ac-9c58-c54a-c770c2788539,611486636,12449969850220897866 +9913e113-1067-0cb6-9e4b-595dd395097f,3606349889,117346384788047015 +d8a0f78e-901f-14ca-db5f-b2aa6bd92b25,1790322190,13717069469537132624 +9791b0e1-1f00-3ab7-20b2-b143fbc379be,1290545733,6617881531450174523 +791608c8-6144-146e-67c6-d93bda915b0b,1117275935,14774413871815851091 +256096e9-3b77-9bb8-b6b1-930c5eb8deaa,3408878459,8762256080915468400 +64126e1a-e80c-c603-c101-4a73e1ca5893,2409893155,1938099711295885549 +5d4e5de4-fa53-9d8c-2e29-962a56bfbf21,1904770178,15236571851736592347 +55ff8b6b-98c4-fbcb-798b-4c120fe7e471,2418983904,11356470982400722771 +3dc111c8-45a0-da0b-6b8a-830509aca812,2425140973,926110880299831459 +92e37770-bac9-f74d-caa6-c331c9619bd3,2449422602,2632818142172985450 +851d20b3-7b5a-9097-479b-e0621988aa27,2124537552,18235481699319906488 +7f0baba0-8085-7eff-42b8-fc5a5cd8644c,3646233358,10272473552845753392 +6b90550b-b2d4-c7af-ace5-1e9832920ea1,292635050,3643493640968641601 +779b7038-49ee-e47e-c2e9-18d57f79b3b5,700053641,11548013574240404535 +435d16c7-de9d-aef2-c4dd-1b213e9a986e,2204692191,17840271529224175394 +7077540a-0966-961b-36f3-f5b6add76a00,1509821912,3665883959456337468 +d8230ed5-eb18-f9a0-92d7-47b70be5640f,2167787711,18130529898545593404 +6a1d1a24-27cd-8b31-e4ff-4e77c368a173,579102729,7718999372375291181 +c9e106a1-8f23-6071-4d2d-41942f00fe00,3275311948,6817078637802680294 +3f3708fd-03a0-2eba-037a-7d8acec21ab4,3550993247,15156754999238560371 +4f82f7b7-6af5-81d3-ccb6-3a50cd18aa1c,1932325860,17162554544459315521 +868f74ac-3994-abe4-c1ce-b11594ffef73,1379981906,10126421696149912409 +cd24f67e-f5c6-46c1-b6fa-75732587a436,1854610655,10614279075567076052 +d8a7e657-bd1f-b678-b005-11504cef965c,2920383149,10618873732834932287 +be7a9099-d875-72aa-1573-6cb051e94ab9,2133508504,11253200464871308929 +a75b0700-6815-e139-b47b-ce7dcd0f9862,3830133619,15143404502787474839 +36b51c1a-74cf-e986-1ba8-710e9978921b,1915673244,13672605108331482137 +755ef426-fe40-7cff-9c21-583eedeba1d4,4012264959,4355832169635951806 +f1345afc-b287-6c9a-dbfb-19a9b93fc789,593848166,15702933995181868509 +5625f475-04b4-4f93-7baf-25931b6cae4a,3744865425,16088517524982615264 +2821018a-e638-a856-a7bd-e6022225155f,2299021262,15731406418986070093 +d5aa71b4-b03a-7104-6a9e-e581cb294651,2020031855,10615675828757957258 +695d25d9-3bf5-43e6-6904-07fe271411c6,978715645,6571771512476624157 +6d88b9ea-9ef9-b7d4-5029-5c0acfa776e7,1123074031,765144726696410338 +155b1e8f-25c1-ac42-b81d-97ddcff99eac,3664692236,10745163287650254441 +169b7957-5c6c-85dc-07ce-00acc0206a53,3227096742,107044451166926607 +8e0483e1-622c-a751-c0d8-60f4abd51de9,792430514,17045755483167345488 +44fedb31-e843-f17e-b28e-9d57c52c2911,2076828499,12610967691109875401 +b7ca62cc-314e-7e32-99b2-ed7e66931b87,1018473201,7253068115607696215 +db537cee-c714-e2de-8a3a-952d77f27c49,1472787843,9664660258291467449 +1d54f881-3abd-a4e8-408c-b94f9f17aace,15852583,10196836027531533355 +9e026c16-2022-5fee-f7c5-16bd5e498c39,3381391369,12390111119837301483 +ed393610-ca4d-b381-4246-2be1cd7eecd4,2281478392,5344379920218987447 +edb61619-5679-bae3-6e77-4c24d3dedaa8,3103374152,2006536625094998192 +9f097adb-e46f-187e-7d7d-d07c9bd40266,139540890,1660545526161594223 +8623bea1-bf9e-8a8d-b055-b6a67aae81d9,453235035,11504900155067406782 +d6c7a830-895b-bce6-fc16-145ce6079b2b,173643573,7799186770213165151 +43332686-5c54-98a7-0c13-965ef0629cac,2544705125,10048452856254910578 +78a5abc6-ca62-9d9f-54fd-6f6275fce817,3130718313,1621540396735798439 +8ee8c059-cba7-05d5-b946-682b462c92b3,1138055084,2876110955218836571 +b457e8b6-233c-322b-9c28-4e0c39b8215a,793163346,12493570388389032306 +0e009f30-916a-cf2c-2fc2-3adbfac26030,3046770189,6772994533272217807 +23cf2693-0e97-4aa5-0a9e-f1484273f5f8,1582016021,1710952347762847040 +90d3ed61-41e4-569a-ed1f-06c35b0ea50c,1149851663,12913025927112543093 +0ec41962-a50a-433b-52b8-4f2187023728,3699764353,17765199311778869458 +1117a3a7-1f66-794a-631b-196cc25f50eb,762741550,1023246260146887551 +09570ca6-3429-f3ba-fcc5-2fdb264311d0,746447503,13884162886965007831 +eafda463-d22f-8af2-1e55-8230854f39da,1430847753,3884402759793520656 +9aa26aa0-1b05-78ed-8fbe-8eb066ca5b2a,1966952583,17618945195867775366 +7f791d57-a5a4-71be-1ebb-e6725122d548,3478917132,14804186590257451418 +954e852f-ed66-d5d0-f5eb-e70ec883d3b5,2135621960,16736683370673333797 +683d6f2c-ab8d-41b7-9210-179dc8e8d547,1643972448,11117550355243986150 +7cdf6bc0-b79d-4e1f-ab2d-807de024fba2,2204852279,12166813695126066319 +cf3106e2-0387-3a11-bf83-5a53696709f8,74421968,4539510415111621388 +e0112ff4-68ed-bb6a-01aa-f706ab8034b5,1597542512,12388208463726689826 +a1981e48-9401-b878-3fad-6896d0783895,1512254140,15588784190112253191 +9899281b-57d2-d280-1cbf-050f549a2b81,787344524,6495007346463468957 +75fc0763-ed18-2d17-a754-fb7fef2da5d4,918151716,10143488124716776396 +8a0a5ff5-cc20-6975-2294-a4713d735d6d,2411664885,5997504636840658448 +e5c3babe-e0c9-f681-2b41-f9328f24c038,3231530427,3994307007018731844 +e5d73324-4a16-a4c9-1af2-eef2a31e21bd,1632268608,10932883104252593775 +3a644034-0577-6b40-49ed-d93576fa4fc8,1957956138,3306619912731061474 +26a1d93e-3657-0005-cb69-e34a08a9be67,2017906827,7212443028575160060 +cb823207-3528-90df-a947-dba24feacd86,1016433740,12119306648765369534 +1da0c5b1-f521-8d51-3e25-6d903c462f9a,2601115843,9297090807621058308 +b6395d26-e821-7f4f-53c0-42c33ca1f198,3784440908,9985220930012222826 +b96a74cb-efcf-cb52-9de3-d2c47865ad62,3917131222,15286093149036214393 +dada9b69-993b-1445-9a68-914c121ab29e,499231900,10465979094343020519 +7fa8edea-4a5b-62ce-1ec5-51c4084a96b3,3893304549,10107368591403178930 +12df80f9-22bf-6bb0-1c4b-5935a1fdc6ef,950111617,15126090545727790956 +f1df4ae3-3dec-c94f-9425-4126ae747202,78803402,11143780729216516399 +ba7dcb5d-c427-6f54-ba68-1ef5b1d0a6cb,3048723701,15276591729024264910 +c18914c3-251b-9b78-a4b6-49a4afa189e0,614042263,14751238825297763604 +632956f2-1c1d-a654-8756-27d2602a55d5,133955936,10221276221076318772 +17e2fba6-5863-95fd-7b4d-7d3d91bcf90b,435410938,4411417134863247365 +85ec233b-8680-eed4-980c-8e0f72cfaf63,1640606635,10280627328994113133 +57afd52d-b705-fea8-b854-4728a2a93d67,2360115290,11619486988750253664 +0bfe8ed7-6d33-b2f3-a753-3bf647ca1524,2203976923,7092525471937395521 +eeda14f7-735f-7082-591b-585d4a465391,2706411466,4893623614054671834 +aa7d9819-257a-d5b7-c400-7397637526a3,22547585,9737448923054774962 +580f2612-8ff9-a01e-2788-3595894cf829,2114363323,13685748409701674114 +a46adaee-4875-1530-7156-1aa307d30f2b,3139898672,11403117047917244589 +59f4a944-578e-89ac-47f9-a1c0049fdb59,2668080731,1666972434682113491 +73aa41d3-5ba5-d0e3-d8b0-f6cdbd07f429,1983851495,8135439958839555761 +517d53ef-032b-9598-e063-0f3617ef3681,981027203,10290259746489324086 +79f3f3ef-ef0e-e084-dadc-c3b6ffc27d7a,2372427040,13735060346963123578 +b68d3b7e-ce32-d5f0-a9ae-1b5fe39d7361,2351702601,9137659352007022444 +a53dd349-40a6-65e2-dccc-1719fce69434,3606011965,16157773381847607433 +8bc5b994-364c-8823-6b0a-104f56bf0722,1679383597,2326974089544333445 +f26b6ae4-e059-7670-476e-24240b25a642,893087754,15165294139979694483 +64ea3aae-1e9e-a929-c086-15e275fbc7df,3711558129,6082996562312978159 +b62ee50a-05b2-9796-3228-1c845f849e9a,951520357,10067202335047884734 +c47d3197-78d9-caad-0383-54856b105e8f,774616133,12470552923980011946 +3fa7afbe-8d1e-d527-cd4f-f634580e6c30,577031702,15670202197694717180 +15845dba-58d0-1062-ce2e-eccfb2327ee1,2089664324,11010169162956823094 +f3e50e53-d84f-bc05-dba4-8683363a18f6,133331537,14703368428318678132 +ddd4dae6-f6aa-5708-993a-dec009fabb2c,3273086416,18064339089440988257 +7ed964b5-c168-7fa6-e8d0-105dfb6f3887,1316843003,5204556157761179021 +ac885a33-ccf2-c2fd-f632-3091bfc2eee9,1104071943,3847581477126266002 +ce5f5907-3568-b842-f8b3-8c5434f51116,412719961,8804305256722979282 +713db9ab-c075-fe2c-3ac9-507e03415b8f,2963607582,9874843753097371051 +5255bd5f-9e0b-a26a-0a69-9e121396c07d,1280727529,9585411715965052008 +f61be2fa-f4ad-4a84-25b3-1f9052dc07fe,1527512085,9382833022378624092 +7002e2a8-c58f-f4ad-87f3-c3081c9102d9,3460985336,15013021183169486142 +22487bb6-9b24-b2d5-6feb-a9ceb57ec1d4,244469997,8502944395563067333 +82a72572-9a7e-7477-58f3-ac2a93d0162d,2727094510,11751446716133166560 +826019f6-66b6-5f5c-0961-2e281d15d167,524530451,14784697604908006457 +0b422938-a229-3578-8a20-6dc5feec66aa,721446903,199895434361684978 +e0c71985-2648-30f5-b9a9-eba81e776df2,875085556,16605703068022501497 +a385445b-7ca7-fb4c-3568-861243c6a754,826538117,2234264813489251222 +cede4878-54d2-858b-4106-25cfc3bb8b51,4176103373,10420480012124987541 +5eff5f2d-372f-b71b-e203-d92a79f639dd,3879257706,11895480935844003181 +69d2ae70-d4cb-6a46-024e-058cc750f09a,3486497301,15781075825600262614 +7efec1c2-6d03-6964-2d74-b1afa1071fe5,3546517019,6337598934957749141 +12f0763b-df10-c8bd-6711-7351fbf21dd2,3330230048,15945371640134224748 +36000a3f-0f73-dd9e-fcea-e1ead63937c5,2281400433,7974397493824322236 +7f3c6548-fae9-ee35-873b-767c814eebdb,2698306767,3190215202327017256 +a66eccb1-c2e9-2428-0906-c2bf3fb83727,4246720730,15043404573628881746 +78e62b0c-4231-e733-14c2-13750a82b396,1860516384,3717320434552424261 +e320f842-5aae-a68f-3a2c-6dae6517f55a,2509447828,7668132430037382920 +e73b3f2d-82af-68dd-aceb-3d753408af15,2939234610,9123090612970173731 +3b491f0c-2583-a119-50d2-32e9626b1143,3800105277,18187096800124983312 +42ea6585-3d5c-b797-a84f-531ba3537ee3,547478171,16917546028251031464 +dbe0aa43-dbca-f410-7ff0-cd2236237ab0,2385042766,5709491381889851142 +6e6702ea-f858-407a-eac6-67a0634951a9,2707276745,16745359070584359793 +3d4d6a5a-55ce-4474-66a5-1f1824487342,2937706434,2349148463053891286 +27630db3-8497-5304-9489-7f9e2274e44d,745607483,4632716251476564948 +a9f4a906-ed8c-9ca4-b0d0-c91c87db3c5f,4180415757,12959546520072625528 +1445fb4c-67c1-526c-7e28-4b24c4ee4065,1886120815,8613830488269025160 +88f52b00-bc9c-5b2d-15fc-f396dd2a2fdd,1476393618,5274810601223669257 +4bada792-22fe-42fa-5cce-ca6444539783,2885869247,13077044223544232556 +a36def8f-cc52-6fcc-2d80-39286c23b981,2971801611,4976625132049526799 +433e64eb-79c3-d772-f7a7-194c46abf513,2206199030,14647272065132493871 +6d86a57a-cc1b-1362-821e-99c2e03e8026,1014163585,11072923316265542989 +7082f4d1-f646-f365-ec19-b4f99973bdc1,2577704048,782628753288945158 +91054f65-d300-3b48-5085-7a1ab6ee5128,1011640484,12055826248036052549 +bcc167a8-3860-2734-2e62-57b73b766ed5,3866752776,5693617751817925379 +12d17539-cc7c-efdb-fdad-44e952f98ea0,3208750460,6169364511764583958 +b68bb87b-5890-dc13-18d5-292a57470624,3173885528,5371879680903082207 +bd5fdf57-5a66-79cd-48cf-d4b437eccb68,323481638,14983067207483553021 +34ee961f-ae2f-0ebe-d022-d1b7d8b3853d,4139371014,16851306912311267098 +4dc3309c-3ee3-bad0-046c-95803e6aa8aa,2393128117,16888723572640703143 +bdebf839-5a42-ce64-0b2e-2bf6302216f0,3594884622,9973163834702364243 +6cea0621-356b-6fd7-f875-6e04508a31e5,228824264,10115802825035948570 +5f888134-8fad-b2c8-6337-e7dd6482f2f4,1703643370,11066973118804090817 +666285a4-76f4-0f85-e487-05ea329ed888,3017319883,3520811434753256165 +f6a60253-0321-7190-cb7e-02f55bbbe958,2944583169,12193065669687687690 +dd4f1bc7-cb07-2c72-fcf4-8d4f124fa980,559083534,10108095518136584350 +6cc929d6-78c2-7e17-176a-2e9d30d989bb,3240537949,16869525805045493994 +0fbf2929-bf42-b70f-4bf6-5444c228644f,3951658925,11587665100537912722 +d9738523-6f4d-2cde-775c-1d1183bc71fa,539069731,11877137756389542819 +b28fef64-84da-4123-a33f-26536ebe7afe,719837594,12382908107260710816 +e430c938-d7ad-c452-1e8e-d0322ce12c77,4217174157,8499872473423656855 +ab0f4e2b-f344-0cbb-8213-a8fd3b4d8d23,3714604397,15409062405920235456 +f3daf14e-93d8-9fe0-b98c-c55ac8bcf199,1134452050,9745435449996024010 +bff60f87-4483-8d8d-2a99-e5ddbda16bd0,408506551,2509944774171645744 +71f2eb19-10c7-b13c-1363-7dd81fe49a55,2234780242,842796073187582104 +1e350560-b4d2-bc44-b326-fe5c69190a0e,1702220217,16636939473715089505 +7b92039d-0c5e-0f2a-9bd8-445aa9172698,3612382605,11026797765030563494 +57c83438-af2d-5f50-3def-9a70f1ca2eba,1776231146,12193481800224796062 +22db1b11-85af-606a-f1b1-90b59acaa41b,611859338,9300425082331652267 +b72f4806-d195-b1b6-5c1f-510b67f78cdf,3882305928,9988059841698950620 +c4e9d3c6-81cf-d52d-ec97-e60ca2a5b5df,3934191538,10531711983387058378 +d790a432-1555-ddf5-7d32-252c8e43d6b6,337337651,17724638390982292906 +b84bcd66-e992-310a-7ba1-18d8a221d2d6,4222651899,333033909535025023 +9d3005a8-45a9-ef3d-e83b-392329d971db,2572639960,9402478450673773222 +1206ce92-6397-d56d-5ccf-d77ea4ba2fc2,3951714488,13759919353784911894 +8d6bc2d7-71fa-e833-bf8b-e50d41ad3425,3238623036,1678087165341342803 +87a13564-e388-a6ab-f3c7-96811d4e2fc9,2102022686,16048636336559492770 +91fdbaec-6a76-9e4c-0027-00e348973226,3210956474,349807899185259954 +64e3ac56-0661-e692-5404-6017bfab6d28,3296418170,11532558025557196076 +a896f264-935c-4f58-c799-cc859c59cb9c,2672666815,12227235065636364697 +e4742e50-253b-62de-a8f6-29baf08a3c62,959884467,12970582461442452651 +2f607768-08f2-d503-17dd-9fae338b286b,2319793633,3193574055694579270 +6a645d4d-70a5-74fd-803a-256f9db7762f,3792005681,11601004830782003909 +f603867c-f40c-a1e2-6083-251371f22bb0,84559254,3704500354733845332 +c2a2877b-0c35-2a3b-8feb-eb0a5b938c4c,2027787644,11753780299562803484 +aac165ae-7c81-5e6e-5edb-d0daa00819b0,3594172330,2492709680709327467 +b75a3690-f553-dd99-1026-5907d6bd1cd3,2495555571,6625603264035433785 +f8277517-0f7b-f01e-282b-1c31302596aa,3428830627,7755760718603840086 +d501aa0b-2d30-93b7-7b38-8b06da014991,2869312543,10709489273141133575 +37c4874d-fdf2-185a-78d1-dc6f9b8621af,504693733,15180167181759356947 +c5285a10-7584-bd19-43e2-1463dfa3eaf3,1467750425,10034710479541463606 +792c1af8-6807-e2c0-0d9b-0117f3bb2936,227111233,7635471815320371298 +490f24d1-57be-bfa1-6b8a-ae988200a45b,1009943943,9009405052927942840 +597b8386-bfe4-fd64-579c-6818f3fc6e14,2281554202,2635696355686559983 +0da97b08-f814-994c-8d08-109df0698363,3018350882,13542735333471842190 +79d12219-e0f2-ad56-849b-6f62a0696a43,2238780079,15992027127112262768 +9daaadcd-1cd7-98b7-8a6d-aa1e4fbb2cad,4262344400,103489088420995469 +cb406e81-0fa3-6497-716c-9601fafe2090,662261196,6332210328372860889 +e2fc17e8-c3d8-1826-35e0-9c0c3ba947ee,2141486752,4361407851168516426 +fa1c8ef5-30a5-fdc3-73a0-0df90f46786c,3085786120,5477101083322340328 +974ec16a-76f9-c51a-3083-f8de769c99e8,1597115219,15279430018453599916 +0a548291-2c8a-7828-3b14-4af93b02fef0,3148099550,4426580745232336462 +9f3f8fff-967e-0ac3-1c63-ef6f33a6102e,1790455322,13101426956710032092 +f1019100-27fc-dd19-9f1d-6980bae5ccae,3219889018,3860349725961513057 +76dbd980-ffac-806f-ae18-871aae271f5d,2824430767,14592634570220363544 +cb8e1841-4619-ef4a-3dcc-479b643088f3,2805252016,16759185058777092199 +7473eee3-efd2-0a64-00b5-3a20ee784fbd,3605567894,8242072822743467901 +637cfd01-3944-5bec-f1f3-a8dcc666f329,1183958918,13989527476787458373 +0bbc73b9-289b-6216-b0b5-4f696d68eedf,4248337627,3883036896919719191 +e0f03076-bebd-a8de-09c6-5b38a71c4b53,2543487413,6371118279189710559 +7c031d27-19f6-bcfb-91d9-aa4c78ae6799,2150097710,17746267694972938259 +ada3872a-f96c-3300-7b0c-f9b6825c0f90,3667400001,10828302587908649350 +2b5f75ba-48a1-c171-797e-c11622205916,737261372,16595202234488448382 +91294591-cdd3-56c7-46a5-275da38c0e18,2742685870,12723816393927065440 +0d2c94b8-d2c8-a590-dfd7-da201e374de2,627777159,18243112116251639780 +e6e511ac-d6f7-731d-5576-df19c6824fcd,2249921850,959130383119275961 +2fcbecea-e52c-4b34-5b2b-8d322cb8a924,2869125094,5077400123312601129 +fb0a27f1-a6c9-be30-8e1e-7c6e55830c5d,1259239839,9924771791275217278 +061072b8-8068-ddb0-4194-8a5546c741c7,187696702,17146147857869230269 +8b841f2b-a233-05b5-7b8a-21f847620a5e,2713405354,10864209546312669500 +576045e6-7a09-50cb-3cc2-286076ddadc5,2539453400,18313168232000897584 +5b028a2d-ae24-bf3c-64cf-50b37559b154,1535166152,17805137041792589391 +776e0b15-79ec-688d-1cf3-060cb2761851,3905477498,13204327250285078991 +1dc34a46-1592-a3ac-f765-e951053ac84e,523375717,811531637393986476 +fd88c8b7-8b44-1c6d-ae1e-8c582790406b,3072253763,1961215464317784339 +a4fb80c1-a958-a1db-e629-3f294615d500,2440522849,4153487518037114980 +e01bd875-d196-b867-b22b-fdc8eee45c97,12697688,17219577917455875401 +2036599c-aaea-2e6d-eab8-f02036c1aa91,1773341906,1948537903576250263 +82ebdf90-8f20-aea0-631a-d84fe14cddd9,3810116841,18254761517610114932 +1d4405f6-af82-dc02-50a8-d1b41d18bfd9,1117153236,17626899589253669899 +72337599-b970-6b16-e0f3-96fed815dac4,2285042019,6303560957011361411 +d8f585f7-e7d3-70dc-f3c5-85f16b1375d4,1892610419,5170736361618199994 +dcfb4dcf-13f3-232f-83b9-b48abb245a83,318429607,17047636811838819889 +c8367777-4260-9a94-ced4-45a76cf3c1bd,2818639894,4681893234629493919 +2090bedf-c1e1-bd34-5d43-d30b7fb1e42f,2004108967,2105305920137415932 +79345ef2-f924-6d11-7b7f-f18ef789e12c,1413354866,930743516459764622 +2d0a42b7-2fd5-9e81-810e-23a7b1c005aa,3494247361,15996356150483191018 +5d737bc1-ee44-77ca-14b0-fea2c216fbf1,2229745889,16243625138800914509 +13c4980f-186f-4d5f-37b5-27871120e3e5,966090297,11104204339737730500 +a37aabdf-c168-a0c2-e8c3-e7ace336d6bc,4098659367,2555075224708050226 +522d28d8-df4f-8e42-b25c-ed235ea7c7e0,4271031513,12745000709131428925 +e9768b53-2f9e-5601-6ca2-cc1e1555a0c5,804944290,18408155936007202052 +4a4c59de-d861-25ac-3d08-4f301be68484,3977385903,1217095877089294475 +9c5bb417-eaa0-d138-81f4-bfd0a157e2bc,2734448594,11675563615913633567 +a0c1e969-4fd5-3562-53e8-2df6582b6d27,1523738764,17767839411761276016 +d471a387-2c27-73f4-b879-58de90d47f03,4230141760,17652225386222382988 +79570ebc-c2b9-fb72-89b0-555a0648fb0d,2341378959,14998038507864862785 +e7b09263-ad2a-314c-9c35-cf03abbc594b,2971787476,5079984941189379776 +adfdfc90-1df5-b183-e7f3-6a8706ef53e4,3032193233,251510141763423032 +a439084e-8fc6-13f5-30a4-9fa6de7561a2,2755634510,10582396570149953357 +632cc560-bc21-d588-9fe9-92d955ed5f16,1142769047,5514569818060385696 +5236b5fb-c158-dd79-e3e8-2a1ca4f18ff1,2459805712,3254022041756245991 +bb5870d2-deb9-7dff-0e08-5e3ef710af3b,3902641887,3421770952207927676 +90286e26-4ca4-0916-bd6d-a4f4422db52f,2158167192,3959674955330726919 +e569cdbf-1d65-2e8a-c966-3dd61d8b63d9,3092797121,11199404986769658616 +70d0ba6a-0341-0c76-6985-a64a2a0cc93d,1807755503,3445115644017476227 +59a95fee-860b-8285-7aa2-4d714829dda4,2474797301,17233227771020308121 +05914d79-41d6-8ffd-3323-7c6dc3fde581,1224712281,7963857379034353430 +ca65f77e-dc1f-96cb-0a06-aca1b392a3a5,1456690587,713847753539896939 +41091afe-2817-2cfd-e8f1-9100cf6a8884,1513268543,6224248002391718410 +e4148a99-98bb-c6a5-1bc7-f733b0612177,350267099,3945826823853607871 +6f376482-2120-c8c5-35b2-f18be45b0f10,4256229249,15134317540379907898 +fcf27581-7159-767e-b30a-f6caa73e4b69,989182948,7492790488979041910 +30e3d1ce-d114-ca8d-b89d-2704251f6e1c,3022713967,12869659531544115065 +f038f36f-3b16-41bb-db8c-c56d9be198e3,3670050285,2789021543118863675 +d4bfb4d2-1345-a385-ae3b-8d87bfc3abde,507093519,15655548601070085636 +07bc7ad7-e4ed-25ed-9273-d4512df34353,4016361836,13021350511799685598 +07fadcb9-42a3-bea2-e0b4-0c906c9008f0,3303282693,7870931461360474796 +e162cd6b-30e0-5daf-15db-a08e21a48848,2769516650,5582772955378937339 +f2133415-f8da-c13d-6a7a-0f2d8f2a87e8,3558286708,8428724705878833037 +4ab744c4-fc11-054e-82bb-b68b9ca2a812,4246400992,4546408512924554535 +d2f7dd1e-3f92-35ca-5311-4893ad137f15,2263613730,382598167442081549 +c2d990a7-da59-c2c6-d179-2e768d532a71,1717567693,970443880362410600 +92d424d1-d3fe-421e-ebda-189dd0a03d1a,3803676563,5095926865815837168 +e94f765b-f9d3-1d2e-e28f-723430ec589e,2815882153,4176977291417151340 +587d1965-1b87-42c4-0a56-dba021bf1520,3612913641,10131822835589928948 +35d16633-5f06-6513-a475-96582c59e315,1547052070,14943851060141341244 +819b82be-b9e3-ae32-5ed8-fa41d715dc65,2515724651,10691980807450805604 +ecff0d93-930a-42d2-1727-cfdf1341c2bd,1046693798,15692870152242871602 +4088b4cf-407c-4b56-4620-856947aceb63,3480313253,8573955299667134581 +c40b4066-9e9c-9cba-a326-b69431279d49,1793783074,7435231811276168516 +ef432a17-70e3-9983-332e-df9f911d4d43,203311905,14564026785675356346 +1fd56e95-336a-ac81-a5c3-5afa60db6fa9,3976739382,8556608814480507312 +a13dc6e4-0e64-5059-4585-2fd26e57dfb2,446115276,3123295273426618260 +de3be4d9-471c-c597-a5d1-1cdb9d0bc382,867099860,539468251559389504 +80efef19-f1ad-de17-38a0-7b18920b53a0,1979962517,5614003161846978034 +625ecf01-980e-4d5f-aee3-729d3ac549ed,2304390700,15585382390965372971 +30a6ed25-22dd-082c-c5bc-e77dba1f1aaf,4275438010,4489405432939483575 +046058f1-dc5d-7c21-0191-33d6d3c52776,820368413,15619635452160863731 +75d1bf42-a668-7904-8ca7-5ee8ee0a839d,64709085,8156873343765074112 +bb0d1d90-09a1-b47e-3e5c-7018ca488d81,333561029,2927605832729325923 +7c4d2e1d-65d8-4f81-c2fc-c7052b4d9003,845288895,14942348899429415613 +6bcdc239-f1c9-1987-7739-3e281962b907,2890497969,6016033106782317158 +4a868d09-2f50-4416-3dcb-f59118655f86,3144641897,770002338573588141 +b9e0e6f1-1644-fcd7-b394-1ace1af7f8a9,2399106393,7230266195771411986 +f7d28fff-c1c4-8fa4-79e9-8737d90a4c74,3978064814,14557725892833216651 +f3ca7925-c272-ddc4-0c08-e0ec530cfd81,3651314378,13472926204074388409 +b021d134-1627-d728-9691-cd21e25e18fd,3716811692,11486259457346181592 +67610a4e-8f97-1e6e-d054-f371ce4429bc,902214169,222530660929415988 +d1d38f1b-2e9a-6a46-0b90-e728fedede1e,1741786844,11458031836263753692 +29f7894e-6495-d54d-d9f9-7f428e413343,2220654114,18072976672111689544 +f1d85471-5938-f21b-84a0-4ef846c71aba,2212166239,12456368508196825314 +e2dc39ae-a977-82a6-4a6f-28dc2c09eaaa,3105751824,13336341822930610936 +c99a1306-a575-43e7-dd56-6e656ede999e,125373151,9408874414275269978 +44fc496e-3b8a-c546-7a9d-dc275b59fb93,562865591,1599773564232797284 +feeddbde-13cf-ecd6-c147-f2feacbe06f1,977378062,2340303635292700477 +c0ff17d6-0ab8-2c11-284f-4197b3ae974e,4069617587,15684965877670388234 +eaa41df3-c120-7a39-ea25-7764f8c509f8,3758540817,1211422013411393792 +9d0dc66c-18a9-6d7c-457a-6bc893f619c3,2878642821,16170169883248266811 +ac978c36-d917-b495-6f43-d691e61e3948,1444899094,16413665214233059551 +5d04bb2d-180c-3e08-e19d-25160b75a823,4197355996,1970199545283321818 +5d4a8e47-3e07-098c-4397-5bdf8d9af300,4290947357,10523122503010402598 +6b54272c-f857-1aa1-f0bd-d193340d3fdf,3896238606,8339738179085740709 +712b44e6-f694-0ac4-3520-8410bd187d12,1818410467,803614189749595638 +fa573cab-bb2c-d1f1-8b88-c6773b1762c0,3935444051,14814155843019591012 +2050537e-6a69-c5a9-f9a9-c0986f428225,2940868964,1176844902698712177 +54fc89e2-d712-a8f2-f260-b11a1021efba,2599191735,6963767442473008555 +1349091d-58da-df70-566e-02f92815ab12,2430396028,7392528513012229155 +e2be5f5c-ec76-fbfe-89c2-1d9f174e7c6f,1261471187,1889557179161374061 +ee48d9c4-2126-b7ee-d47f-fbeb420202af,1747131266,3858740201675478831 +b30c79d5-ec76-99d8-4273-a0876d888d2b,1648368477,10546673773074518432 +3525a42e-b8cb-3e31-a90a-13e3ef99c6df,607912098,5751961549904025030 +e5cd751a-61bc-2633-8d3d-19f8f8843d90,3055996986,18088094511271271134 +a731ee91-4753-55d3-e679-a74bf8f5be0d,4234679234,18256956381164950420 +861dcdc0-aa6c-312f-9016-d2da9346c71c,1673859477,14581036556910729910 +31feefc7-8839-b382-fd8e-27c7dddd5ed1,2512192148,6624427782433373821 +ec06a191-9ff8-a78b-a37d-f2f5c7bc5570,2844515131,908579988679020025 +9629416a-8d0f-70b5-e740-84ef5c275500,2911800303,10594188352627990244 +f48277ba-0cc7-e6f0-280f-790455ed865f,2707138650,17542718000310208213 +5fa8eb01-6e85-39d6-aa7b-a52f3aac99ee,1455578134,11979937446588506674 +9a1f78b6-21e6-558e-40b3-9d248ed52a54,848520761,6682722605006011897 +492ffdab-7463-1175-b4de-d7ded07a0262,1993431713,2442445952397158907 +fdf5ff88-97d8-7ab7-5c9a-440b8c13aad9,668653841,15675110374105250708 +c8d4531e-35fe-5070-7c34-0fe30bdfbdf2,4044949060,6374918795176415807 +88e5bd05-791b-692a-cd5f-4c0883cc0dc2,3200543995,10297019605692592076 +e6b7a2c7-c73b-e4aa-592f-0ef50e3e74c0,2733456231,8664027346371238061 +b495d0f5-baba-ae7e-76a6-318f4dce2c5f,1828284830,5986237375001074658 +68270dec-791c-94be-47d2-5554463c1d4f,2592177203,11896796605724572212 +046ffab2-562b-cfa7-5ee2-286f965d0e9d,2185059495,11237329329268779502 +d8da246f-67a0-0b2a-cb5c-31d3ad3abb54,1779445019,10572503008899766179 +896b6bc3-1c19-7a72-9a33-d6f646ae114c,3888114468,4882916018140618159 +52c1a564-c2a3-5d88-7761-52036c79fb85,3601107566,2247010999899724615 +67ff22bd-d5f4-2b0a-9de1-077886db74d1,3028484770,18299381621503318107 +243e93ef-d75d-f362-322e-6da0e6cc60f6,1866590893,12477036188404546395 +6f24555d-28f3-b22f-ac39-2def69e42b4b,511205768,13066417791280739183 +402c8b64-3f1f-b6d4-38d9-ddb5a12df9a7,344724378,16180044176536023633 +94dadbe8-b70b-0069-a369-58a0e66643a4,3186327292,7816167938986324110 +978726e7-ebd0-7b7d-ec32-96203bc4d3cb,2410012367,12352785926851522770 +19198553-f1aa-c330-7ae5-07c66a021f96,2104651268,8340928624501682199 +042006ec-1476-a290-7199-44f4a173fb4c,2369793982,12090203013770897508 +9e65f768-0abb-13ef-3abe-49f381aee737,4056198506,3188168333279704651 +3ed969fd-1a8b-ac83-f084-c5e8d5a3a002,2420425580,6933962411201336440 +872b11a7-ffda-7239-e17a-5a37acd24468,2338035539,14921758159271347686 +67a2de1d-4ebd-0d41-56c2-81ff9425b955,963567692,245538864796539767 +3eb7a712-ff5f-2654-cda2-e71467973525,1638119557,5327341078007699283 +c66bfd29-28d3-3203-890f-c4a70d7732cd,639412994,7595299608516275958 +50b65390-1e05-7c3a-ec1e-96c627eb4c28,1984219281,6463999981861525271 +c651518c-58cb-423e-a9ef-2b4d9bbf3b45,1664838396,9447739746315777426 +0edb78c6-365e-7fe0-f681-152cd626a394,562736276,5722935279807058060 +56ddda6d-004c-e555-7bcb-8914d0675ef1,2760269139,2834150991393211998 +7b495ab5-f77c-1435-a993-6d59f91979ea,325314074,15125312603206352031 +1b01bb71-c58a-0b41-46ec-d7b29c5788fc,2734874007,14393740994658565010 +23954a29-5012-a60e-a920-bd38fdabd281,3783426659,13689877784873393366 +b437d387-9b1d-e3b7-6970-c999d717e4fa,785778349,7531209091012617798 +d84adbc3-f559-7830-2880-9615a3c48cb7,44188668,1873544488984285923 +89fb82d0-5d77-6408-8224-f8dbd9be2e74,4217062005,5570133100876061610 +059e0de5-38a4-368b-fb9d-6fbff00f4fd9,2488457902,11844180706058373822 +eaf314e1-b576-8f54-3532-142c4a651357,2354449105,5901831444145348039 +2b1491cf-7b5d-acc2-b5cb-45d1b3d6a5fc,2835539787,1112564792408668661 +7beed271-2522-0327-886a-3b5d9b75b726,3080901642,5450997876783857199 +791df19d-37fd-9cdc-271e-b03f3d6b2dad,708837686,12555698959260463380 +469c9557-5ee5-6bd2-3e0b-c8c17c2d95e8,2370962654,14144848118359582965 +3846f2a6-47a5-92c8-8dd6-c5dddc056cda,3196552506,13421825458793599850 +dacff4db-fbdd-40e0-38d1-218414bccf4a,3009679324,15950436925784569847 +ad31215e-866e-c6ea-d099-58e2e8a80b42,2595120539,11193853920298287234 +0838452c-c26f-1ff3-be89-44418d1a12d4,3274746822,11968448306274305326 +2f922204-64aa-3158-f539-8ae506583b23,3590982143,15703812649269597619 +0728192f-b8f0-9305-805a-1164af085187,2865226604,5090244064483432193 +f5077422-a19e-5bf5-8f2e-60c45cda2b42,3981562367,11367929635543808140 +22df644c-e357-86a9-27a1-e0d006ae720c,2034405870,1118392691865850151 +c662bb07-56bc-188f-7bf9-48fcef210bd3,1286552253,17532911103035790699 +89f0164e-131e-d919-d385-fcc97a374c75,3026618179,1028996983559618330 +aca5dacf-2fc9-a7a6-8959-5c7a6d2535b6,943297245,13233606692218257245 +3afe0b22-3032-1292-74b2-1a5a7c83618d,3877657602,12741578380958842660 +69a51c17-f665-ca9a-b453-1c70fba08404,3708964575,7296590910960879557 +70169cd6-0870-488e-1379-cb1604575f3d,2048361631,2141840030117331323 +15e885d5-44d1-dd51-3710-fe2e3e1762de,2268595452,998999503232598874 +b7687904-3600-dff0-6863-99de76bf0722,3970859820,9355543869936429393 +272c1cae-609f-7226-e984-32559cc84f82,1332202658,9137607005305900541 +c2144cf2-4c4e-b0e9-2c24-a26748fe4607,225858895,7411324465640311769 +9fe36b8c-2395-ebba-4a13-7dd2fa1d3ee9,2372775323,1219528717428170843 +cec44c53-ce56-a8b1-99f6-52aa396cd1cd,2007760665,5436932538414968290 +d3e63de8-f4f4-2a66-2e07-261735d7732a,596907497,9028214352818499804 +99daffe2-fc71-4779-3592-631985716276,2773562827,17474594785290110327 +65d6ff88-21e9-0915-d109-eab1254c96f5,1937387119,12850550152520469951 +d8c7bdaf-94d7-81b9-66c9-901b83dca456,1595909048,4828038542927300988 +16eae262-fa0a-b426-8b61-e3c635d7e43d,4068576885,13910182670859835166 +e5cde3fd-ccc0-6c5c-b099-567853872a4b,3784622729,9838343960771448545 +499eda84-0654-3511-d0ea-2bd29edd7317,2803454194,5278618698380195355 +a48a7a3a-e7cc-6659-7764-feb6f65f8ec1,1036541765,14599001013931787839 +c83050fa-9281-07a2-d342-0d599c69323f,3234446633,2311735997945572154 +aa895d23-bc35-2d9a-0a93-3cdec560ecbe,139462940,10974240409828414814 +877bfd7c-7808-8639-5dce-b3876767f49b,472705024,8784656759451016662 +98bb787e-dfae-8bd4-e328-0b410c9c95eb,2499741446,1789074688996809461 +823120a6-cbfc-d655-c04b-dd87d9f9327f,368766783,3379065973632660265 +1530bde8-8ae0-ce89-af6a-6bb5d3fbd0e5,57906882,5166314301711548041 +e390dc10-7aa9-4c45-81fd-bb061916d3c8,1483152325,14674455592417475738 +07e979f4-8c0d-f408-584d-6f5897b7d414,384556035,14205588566391625000 +8bf2cba9-00c8-4417-7cf4-b0bb26dc06c7,1371131666,9733343334089071300 +189da913-8ce6-c69c-a67f-8f1a2c167f4a,3988699147,7655761845119284434 +fe2cac9b-44c4-e50e-e01e-663a6612f3ba,2363187508,17354835647820146560 +f59a84a5-b08e-1bf8-eb23-bf9bbeaa74dd,3913788801,11304430161248979100 +338ea7d5-1a81-f60f-6a02-a2830b7ce673,2353778057,8035807210971142648 +a5f51c23-2839-340e-ea6a-3c07178c7e11,490248589,8168404192717302003 +2b473c86-1a7a-5c10-47fe-47e946b0c5dd,1877888325,125086302844152523 +8ac68063-18d9-19a2-d44c-9e7723239f14,3464412890,7102297556900562537 +a2509170-2c15-4158-10f7-f65f3de4d7a6,2879355700,7789967431530740729 +513d7106-bcf5-da16-8cad-09dcc1736b67,2706001507,5846018646123190123 +3a24926c-3885-9ec7-7008-e8eabe0c24ff,2974906591,1133808368450084018 +40ecd2fe-aa80-7d10-281e-9ceac171e192,1509808547,9489714968704550848 +8c4f5bcf-14ca-5aaa-28f1-5ddadbb3187a,2012018526,14042176672422353505 +c69ae0d1-4d5b-5e36-3c72-1cedc2ebd663,1406532869,4806293843542195765 +67cb1708-ff0d-fed6-3b2b-d46c4fc0e368,2701072175,1281571611357524037 +d9c32932-67ac-a4fd-13a5-52bd61fbd44b,1263969368,14688187230107211748 +f80e0809-e1f4-b587-89a6-e8c7c4d05c94,1031241403,14607601170801820756 +ec71b9e2-3b13-434e-3977-d00d7ee7c36c,3958217675,1562671108733866503 +48f6c036-6e61-c587-d312-8ee80faf5644,659451036,17042619831726708533 +0fe13e01-2be0-0df1-1b6b-fc00f7ab4b30,4036162720,7087536895081260271 +582a6ee8-9170-b87c-ffe8-61cac8e38c23,1498815906,3183602628707126077 +c672d52c-9cd1-f8dd-5f09-a6d0d9d4d783,2382749317,738121017471062948 +9a40144f-bf82-6496-7ffd-9ab8ac84d29f,4134684912,17551361378728514574 +e31b5da1-b754-bb1b-a3f8-30b0d3e389f8,2403809966,9199431109742662648 +328dc211-3cd4-cb4f-9f8d-6587140c368c,2125667738,510800279725089289 +16b953a6-5f65-e7de-ab89-a6b692be7043,2992865769,11600931738670332784 +c0c302f8-2769-1c61-2136-7ff5f3baf352,2182355595,10088954907517814709 +1de48e90-6f4c-3266-05c2-d258d6ce7f67,1783850074,6894737714472756455 +ca51db57-168b-3a29-a0dc-03c0f57e50cf,2372266818,3777138240753943117 +b545e3c1-9508-c62e-6bc6-33b58821fcdd,4031632799,271216681662922614 +afb2efbe-a981-e923-8c78-7adfeade0222,1212739797,7095977872335051915 +c6a9bf09-6ac0-5186-3d23-d053b6341edc,1060609680,13407122405008924678 +96aa4a01-5ea0-39eb-11df-da556eb84c45,4017544507,10232643416351431622 +7793b33e-ce94-99b6-ced3-2b4cb76afe2c,1734705562,8763612787063478375 +e1f31523-40e3-ba68-72d0-ce530fffab76,1841717565,283220918549801196 +e7888461-6070-8002-d7a7-5a28e0375281,712687107,987063885184631950 +2409ffe1-0951-942e-41a8-a55ab063dca6,2821729711,6507491171218331550 +03ec21fb-bf8b-c861-423a-c41f851fbf42,1502320134,880612972263667269 +2bb25369-5e09-5304-3316-80cfc72f29ce,3867838339,3459789581236070252 +c1bab8ab-ad29-4c7d-2e00-2c4febe718c1,3524542960,9518458900357321134 +cd1accf9-6fd6-b334-f050-c966c5178013,2347415932,15174049795442722223 +535a0125-c58f-a11c-e16b-4c22e09fd38b,2567937386,10740164069226888116 +87533fed-08a4-9218-be23-9fc9349ad8b5,3678415456,18357691789256462979 +4dcec3d7-99c0-1a58-4640-764f993332a6,672856289,14678770427466124313 +8bad1025-5007-74ef-6c56-ae793692384e,1807854280,10032567152220196290 +205bd190-de16-4045-350e-262138b78b2a,1233819886,2710086290606280892 +8a96d471-6412-be88-eaeb-4b3a3740b67a,1616069586,14124893585026140023 +c34cd9a4-de74-a19e-a2d2-4707f2ae8503,2476095,5128182446259256466 +01273d4d-69a5-5447-3c58-aaa06913b690,3825591503,9093771459160945247 +a1e04289-9bf7-a9e3-3786-0203c3b20d0c,747517866,8713012190946676498 +68372250-acca-1f70-a49a-bf10f7878e0d,1815817712,3198241334754227451 +79f1661b-83b5-42e7-185e-230ddcfb5189,3324071124,16378309544766916963 +bcae92b5-a4f8-6577-e696-4f735f7831a6,1789589989,5412057645134858436 +6f10a9eb-596f-b3b3-8f1f-1437e5ccae6c,1641783343,2246622386190283536 +f20bcc68-39d7-ab1d-951c-6c816e6e1cb1,3480668053,903688538681052517 +d5ccd30d-0e0f-7cc3-80a7-200e67e222df,2332501522,4504267049628789073 +86a4a8d0-f21d-2700-ec35-b7cbd51738be,2013723167,10701465968992908770 +e6610040-2bd6-1e64-bc39-9327254afb23,3724363195,8517993670554010700 +a6e4fbca-a652-2573-21ad-871508bd3442,1101639551,9659878538400252972 +fde59457-618d-5ed7-e285-580af4061bc8,1151106717,6859632054529215006 +a90f3dea-6f1f-8031-ad26-400990916a52,1177834313,1443188066670131313 +f7e29f5e-338f-f633-35ca-459672f54aa0,3437218925,14815551811781357927 +8de7f42f-1c3b-0558-fb96-bbddcba26578,239436745,7013717764501476773 +a876ba30-f242-f04b-fc24-00693e08cd6c,2804867111,585074174919017469 +68805f2e-3ee4-4251-da26-da4239f4a02e,3109824090,1811004731253332332 +5d10ab91-0862-9996-e63e-e778fbf720ed,559779698,9630401812017776232 +26203d18-0d11-9f96-6c09-49e01ea63d3f,2977249963,3924055361517226366 +a332901c-ea92-e217-978d-24251285e03b,1463636013,15108547854071363485 +326bdc28-484a-77d3-673a-541ab88bc254,121500798,12908080837165648812 +7c9339ee-facb-e593-69a0-d141442f021f,4070513826,9344515569141106406 +1acce19f-1f46-9d6f-e70f-ad7f6f6f6110,816718168,1476891212176477910 +2a4a809c-6b50-d0f7-83a9-bce6535dc72e,345912215,11055591292292852375 +b5330077-942f-745d-c93e-dc0415156271,2800925645,8990290862195820833 +c67361ee-93d0-c7fe-a4f8-b0f548a833af,2778443213,9611432400467500166 +7760434a-60d1-8fef-478d-2f182b17da9b,1996184333,3999298910908421686 +9974fa67-d10e-9d5b-dad9-12944d42ec32,1100328377,15629102401727342469 +4f4c0d27-fcae-1813-daaa-b2d859c1534e,184032462,11754828737162671632 +d040ca39-582d-df51-0b07-28d0d345876b,4083321565,1621681529250476715 +dc304b1d-1332-364d-c3a7-a8eba6a02493,3529814777,14675781054000567340 +ad6525db-05ac-53f3-daa1-20b57514fbcc,3600693764,7254467605351784580 +3948f270-e1ed-57a1-643b-de07653940d2,2184778026,9568141779493661075 +aa91597a-6692-9ed5-4674-eb3ee10cc567,2408904008,6085805608242797779 +ab967d9f-a9c9-ab1f-05db-827d841da954,3410338903,18376045682364185653 +3bd378a9-47ba-be67-7042-1ff0030bb139,3563225527,2737082107226411346 +a8b004d6-5079-2c6e-a784-6d4862d68c30,4202381895,4967130472815185441 +9323e61f-c9f9-d4d4-5b1f-c9cd1c14183f,1789954102,11941212457352733362 +96163452-21f0-c99b-7090-e7af66a8608b,2638538171,2079245087267297750 +13c07cac-ed97-1482-72ae-ae013110011b,3651292962,191746288655408434 +61f16794-99c6-52fe-5175-ef400ef91cad,3229254549,15624452282268238893 +dc3c00cf-f285-9e1a-5c04-7ed1f084c6f2,3495748523,13045508489137250334 +fc712f6d-f634-b7cb-87d4-f8033fabd154,2294742349,14199616138738101597 +3dcc2011-e647-cbeb-c3b6-8f18d502c77d,610102167,102286605706752909 +47cbdbf6-7005-e0d4-a10e-24a63a870111,429369734,6199081335350860865 +e0bfa4ca-a1e7-f600-e707-107d0c5dee19,3394367863,15922688428372619550 +4ef81649-7f4c-db76-f8d8-94ad2c199ad6,1975909819,8889696241103927310 +0e8f9db4-9103-224a-99a3-7e869dc336e1,4241748296,2927982722217535079 +317f7dcf-c341-35fc-ddc6-e28f51b79fc6,1941986691,8424597246279970932 +6cea1018-782b-b837-a9fc-e646e1db79c7,1313462453,10533052041955470415 +77758658-f33e-e5d8-2e27-aa89093011c1,2631601255,15396996747032662030 +41102a8d-2587-2860-0a30-d641ee313bb5,1979468604,1858536480693315916 +2bfb0030-0ccb-3924-8edf-ab6738447ab2,674792343,13695694107950652136 +38433899-669e-3aa8-394a-56554ea56d64,2010174940,15953095760385620400 +9d83f82c-d2c2-3670-e236-928233ffd211,1505819743,7188305886236993694 +027bcebe-820c-c902-e678-ea1963c9dc99,1639745915,12245312066092754991 +5e9c7703-8598-3970-2a4a-5cfa68f87507,164222181,15338373270546847247 +31ffa66f-1229-ce82-3e62-7ff757caaf6e,1706511505,11932590951283015475 +b61e552d-1041-5337-6cae-bab82e1c79db,4053325525,391209514494126893 +2c746786-79eb-471f-80d5-b5efb30f1c40,1589698827,8669068451633552073 +9a540acd-7275-8700-cbf9-b4da7c3d8e1a,1432714354,8637631158717452480 +9f493f91-a9c0-d10a-8705-e0aa6239642c,1637081385,18161278560579187629 +e3eeecc5-612e-ff76-81b4-9d2cd0a4a816,726791323,167314368704772759 +a21a12d6-a172-a5df-50a9-449d57a3aaab,861578568,15904794733315260558 +d00c476a-6bb4-8742-3854-0a11496b244f,2047991209,4213378472086993434 +353c760d-f38e-d926-50cd-7fc49bf5a13e,3800629476,2027395599473290535 +810f272f-b556-374f-3d9f-ad1d9cdc2468,4153707520,10858234254972988066 +b6be6725-9945-d6db-5aed-5bfc7ab32982,728562987,16940899350181681489 +27ff9a7c-56af-c579-fe24-d8d3d5f85ea2,2551815567,3828126065098592952 +66d78709-f051-e209-94e4-b1d852693bfe,2117994024,9190717871468608162 +8dee1966-c87d-b9c3-6e82-a4a36e354db2,4017975457,4161278758034283487 +f8282adf-6ca1-967e-fdf5-630a8d43d8cc,2866994958,16490594203740167341 +5b07358d-57c1-73cf-5946-23afdfe341b7,2797845651,16958461687724764471 +87c349cf-f753-995d-81f3-ceb4c0c3b0d1,1152936683,10634033916366888701 +591ddd48-85c5-75b9-dada-30a91bf4d785,1832680158,7491448954472642076 +049bf6f6-1886-838d-3a42-8a43eba840f7,3241546248,8156292523106709804 +46da7962-0149-48ba-ef68-c3f806fa7cd0,2265088136,17504442769460568100 +d0eb3f46-a923-ea1b-1a8e-3ad89fea060e,3634194291,5887462033707187992 +035f3db7-09d5-8376-558c-9fa9c3860da6,1309121506,18332662226647668984 +dad0ad59-e87b-342c-f565-f472f3284971,3667513894,18091943567921298447 +c07b5d86-04b9-cf46-82c2-42d2b63f7ccd,745602470,5271961330513500939 +80687cda-8d7b-f0da-0cf0-32983fa476eb,2741440039,2288985938711113615 +30cd9218-da9e-447d-eddf-8372972a5e52,426017893,5991546175837860595 +eb2ff29e-f618-6d7b-29a9-5443c2dd8bb6,4252220981,1674196773723504737 +e094f011-c785-c11e-75e4-4a552f75dd49,3928675393,5174922423484694593 +e96f4c6a-5cb4-9560-2d6c-6878544f2952,1030072816,8665508803856090962 +ca3d1862-b572-3e54-fe7e-e4bb8995283e,945160855,5738295777492388532 +4532e953-06ee-8214-7eda-ce15aaedd344,3195447504,10694322029879734830 +46798107-a783-fd43-0baa-e4e96a597d71,1354914631,13134142372269353488 +e2463f84-af62-c3e2-117e-b0cfa4f22c13,3496852676,16241001377040132408 +34ce2bd7-e06b-48cb-7856-1a1ae67c385e,1607028000,12115872335023244961 +315ffa50-7bed-c093-32aa-192d638d67bc,943572157,14664547449968567422 +7a92927b-3a65-578c-8720-a5ab87625f44,2174809427,14832831655045705545 +48dc3cd4-1fcd-5f26-be64-59d5f08c7c8e,3646665511,3227662569902877617 +2e61d176-7b46-79c4-f3cb-1edff7aacf38,3034081656,8059404715103614077 +a873c790-27b1-ac9b-df28-3a525eba9709,3084750695,11591042451437949762 +2330516c-73b0-9ba2-80d2-cfb0ac2d812c,3389249167,3311930384398892118 +e9338aed-b8a7-d5c1-522b-a64a3f4bf82a,1458487306,9517380045165266323 +7923a804-ba83-1866-0c3a-dc653f1a0be4,3823079160,15773779184087006601 +9e303e2a-a4a2-3c01-08bf-c20b47c33310,2501130214,7304494232404462912 +58052c2d-0965-db19-3f49-1b169d7693dd,186197528,3491374678534036963 +847743d2-e6c9-57e1-ea9b-c42fe0ccdb87,3115323478,13243945204399756448 +1afc47d3-0c9b-4044-5818-c3e3e5111942,2731472211,16813586291383055886 +d31786de-242c-7072-f4be-9668bfbd72e4,4058966515,6324558981310684490 +1f2d7bc8-c937-f96e-7a04-76dbd06eebe2,3640125627,10833911800301038422 +f17c96aa-5c50-88f2-26bb-e7ef4a383c5c,3642091256,1640954828398410765 +d9184d45-b328-9be0-d9d2-1d5d42fa0d82,4054230475,11508981894694668184 +073ff893-4076-5917-689e-0afd0f8344e7,1156132109,9908327093191579625 +df8d9cb4-46bf-929c-42b0-e034c15677d3,857862874,15257878738583854407 +6ce9ac5a-f230-ce9b-61b0-3698571e6e62,2943619474,5776907404128028349 +7aaa0c9a-0958-4b7e-f99f-3e43500dc6da,966947020,3667994070887567454 +5f8494ea-cf17-d5d1-2e9a-98d525377cb6,2604483877,10046264658251767314 +f2eeb212-d3c6-85e0-4808-d060c58c6c98,3819621000,3553844420616404992 +99e75c94-a5c5-3ec1-514f-44ea63d7fb48,234243939,5058363557320783477 +f3ee8896-8148-ddac-4707-c4aedea3bdc4,102789649,13190584822921028899 +5d149998-b644-c412-6af7-07904920b70e,633119015,12754305411004011403 +fa041c2e-1ad1-9c8d-4ed5-cca13b81e211,2243261839,2732580916512674039 +90042ff2-0149-9882-30df-053ebceeeaed,3351535623,1426065637989631475 +ac8e9097-3c04-64f9-c148-b9d8818de0a2,3546732785,7923115935502543240 +66abb7ae-beaa-4f80-b871-5bd7e81d72a1,1059792021,4738121773370525303 +84667f88-4bf6-d585-499e-721becd25c8d,338153336,12973401162617442537 +7d83d82c-4152-c184-a430-1d4b37ec48aa,2215743443,18351149253590019420 +ad585d50-4ef6-bbc2-fbbf-15a72bc9ceb0,3252953570,14109267931253726919 +82a82c1e-37c7-a847-024b-1164d7aae51d,874634234,2216438395015763876 +f725faa2-bb08-8ec6-3d8b-1c521acee0d1,482375779,9260922082162690743 +a9ac1ad5-a14b-7ce0-8d2f-dea96ad30f67,2573454737,39937758197033138 +5a32dc3d-f09f-d74d-2cf8-98be35e38af1,3510805045,7265079034611263058 +3ff491b0-8e1e-7031-131d-302e1b256226,3028574967,18193098385929066302 +22247847-8867-f77a-08e8-29a6bb660d0c,1648878578,15388347826243890265 +20a17b63-8a2d-ff8c-4bdf-8a8d5f9ecef7,3588177661,11729397672985073737 +ac9bc1f5-00fc-a6d8-4386-4337ee70ee42,2741771906,17978471185442476788 +f57c5120-4fd3-0484-fa3f-d187f63691c1,2856990323,17046310299746158694 +90c82b53-8a0b-7743-07f4-2843d708bed3,4040330342,4705693987567164229 +be78b246-2529-aa71-9be3-5371c4f221be,894801894,16084405961813516107 +c5e39cd9-20b3-388b-ad2b-de66e33e06e0,488571039,7976816193690985574 +8600f7d5-508a-ddbb-34e8-f851c8281081,2991423890,6545262245829078315 +1ee96a44-557b-4b12-657a-218cb61e72e3,2969039715,446398656582621225 +4cd8a2f2-93e2-8e98-1008-098c8ef74bf4,909073547,15939162904228034814 +91667143-3009-f7e3-95dd-881b6a83e595,2529084259,13507411750400169777 +4013af56-88e4-4874-c114-ebf07bde34c8,3029017967,13935678036391780214 +9a0c688f-701a-d88b-0c80-3db5e7810088,1443422304,512042085136669284 +2e28c623-e726-1204-a94e-b412ae019f94,1083577820,12411031181595494083 +02e6319d-fcbf-e491-8512-2cf7c7ea032c,2185569511,5082282061918679435 +d42a47d0-9002-ac37-403d-f91be4aaf4ab,3990177635,5560571335865716352 +e57d1783-0425-eec6-687f-87a3165a7f8e,1536087527,9760645819712344781 +fc535ddf-7bc7-3161-2a54-e4e8a85d7079,1814738789,7441504958123455429 +0849fbd7-414e-1783-b717-5718b42bd1d4,1585082263,4021671690709980622 +bb7a629d-86f1-d6d6-9b87-38b13a86d66a,2621974618,14467471835460841932 +f900806f-b2dd-fa8b-c91b-efaf71750175,2928411187,3459192266120152779 +4bb8c8fe-475c-bce3-45a7-90f7301e14fd,522454951,9060364519331320045 +4b8761b2-3c9a-12be-55bc-59d43f2829aa,1141438669,16849274735426347050 +ddcfe32f-5e5a-118d-1222-cb510ce937cc,3459314748,7544030831190176511 +8d7244df-0f31-a775-361a-d23c845f5d36,2110131903,6418383780396872144 +7acb743f-6225-ba16-2116-965ba14eb49b,419786319,11273762156824529873 +fd6223bb-fc2e-3df0-60fc-894ccb5c18ac,3538702230,5823477719062328524 +abcaddfa-f654-04be-9031-7fc3eadaf93a,3441031267,12220418953260977034 +2f413fd7-0e2a-aec9-a7a7-4a3b5d796ea3,3690357173,15930078324782960982 +a8ddbe7c-cf0c-d094-12dc-84cc5d3a0ba2,526807022,8078889257507631930 +6ae31758-240b-0112-e78e-79f3ef12dfc7,903750638,18329912958884641862 +ed76f7d3-5f3d-4865-5a1b-8cff0038101e,1857237767,14644869485483882072 +adaa80e4-a176-fcbe-61f7-2ea02698ac42,4164669420,17720859667854736905 +1a9eb798-ba47-675a-9920-ad5b4a64aa19,2137813560,11334914915176973038 +4700531e-378f-be8f-ca12-1d1111bf5898,2877044639,16936203728430129684 +378f2fd0-9132-8867-f3bb-e87d998ba07d,3338558357,12723573779671256466 +5a029abd-a875-eae4-660e-c15d01f00527,4243556755,12106854212380288860 +9d07ef17-9b0c-9900-b6be-004e3c799f11,2735744658,5980113119917882609 +4ce4021c-b530-6c23-6800-3a452c7c82ed,2908002645,14438516880162100789 +2c440a8b-e3dc-16de-17ac-c3eabf8c8a3f,4112035282,13353959752400837407 +088b8d31-5381-4fb2-9ebc-e4d3b57d9647,2316163321,2498968420222747750 +b1ea29cb-bb35-7aad-93f2-42ad89f43b08,769626582,4157362151718669208 +9d6e6838-546c-8443-b419-1abe1ebd46d2,297125308,5144124516056810922 +e59def4e-500f-a729-f80f-2af07cc82648,3565529409,13521597315154119746 +da0769d2-9d88-2265-c194-17ec0e74f5dd,1347719759,14107927385007851500 +8ebed742-2fdd-79f1-6240-700fe9cc0f61,3830828535,1047528256489207810 +c2d5acba-0e21-1772-93bd-651749749a72,3455526447,9493208964467339248 +1b5dbb98-a2eb-34cd-48f5-476083b4924b,198889348,15014520338180909520 +9869b30b-6aed-176c-2a71-09a7f0eee33c,2460063544,15072717128893914699 +b396263d-c643-0fd4-dc88-99bd9e742bcf,3799909996,8239428404143648294 +e5a05d78-15b7-49cb-5e2e-c5425bd66d2d,2118811966,11041452587615822381 +4fef71dd-7ac8-96c1-a5cf-54f5595a7fdb,3198087234,7479177758576855698 +cbf0b938-dfa5-04d2-01fb-d04e62fb5ab2,518000846,12772222740333229394 +24241d37-a6d0-59a1-c6e9-40bafe3006a6,3622696131,4568515114734817725 +cd6af56c-c009-9c79-5383-77aca4ceac23,3883350665,4952773441516503606 +0a0a0be7-b986-1109-d92f-00dce9ad7904,2505988828,8210578897337130196 +2539f914-90c9-7874-1e44-45427fc3a4a0,3193881748,1155263964306982611 +bc79de3e-32c7-5404-b866-d6792fd107b7,3244593349,908283315388877223 +4895a838-fc4a-e00f-ee3d-21e3f97c277c,3554157202,3308806492689142903 +510514fb-cf5c-0c83-5eb7-4af4cc6514ae,3104973362,9802993814735329713 +d5563076-618f-24aa-674c-45e31902855f,673520358,18433793961053346375 +4fdbff13-4104-73d5-9d44-1bdf7493024e,530598035,21387802677930696 +f4b48379-1c67-45f6-4a8f-0f2e8b86a055,2510028886,16711885211871200999 +e9f238cf-8929-681e-7dc6-dd7e8fcc6cd0,107853103,16134590438557410910 +80f9c125-3655-3da2-6dca-bb0b1809c8e9,3858472296,13394131438647782093 +98556ca5-90ed-306b-728d-4c2aa0fb8ccc,3039786003,5236729746247292677 +169ba1c6-102a-e8f9-8e16-402d67c6d5f4,139930734,11046371683299654073 +7742d3fa-4465-5e3b-81d5-3a1287003af8,2441055588,5486105977709569718 +75c4e28f-67a0-1960-11fe-a36f82edeb61,2080023173,15970903315275085381 +85b76078-b9b7-56df-be17-5bf3c2483f93,1298227443,234451133159100806 +6eefebf7-fac7-1bc5-6e3e-efe3b4df6cfc,3776813560,3995767448481407376 +1222daa8-946f-15fe-940c-50c0b4000833,2213532837,17327770829681877471 +72150aa8-11ab-f02d-b50d-6a07d0591a98,3333569536,17107928505567410728 +aac81d2e-d5cf-867c-2cdb-6be4ad105558,2427359352,3037554613835830157 +bba68468-7a7c-4a0a-915b-ca8a26f44b12,288681534,13624613424594575812 +a2b8584e-37e3-f07b-b4f8-4d3ca4afbb8b,1058903756,5636309419640704346 +40550ea4-be2f-9d45-27c6-2d40fc4b4bf6,1275543864,17894789989893803198 +fb8941d3-ff11-de17-f7b0-51f61b6ffb27,4289205741,303433103333306926 +2ab57999-2564-1068-4e60-89d40c4e33b7,2367742849,3465698146452937125 +84deeee9-f303-44b7-acb7-39887efeb8b8,499424998,4845992892035290272 +d201f820-573d-cfdc-a51a-634e69fb0c7c,219078060,9409054943079415609 +3ec7f95b-4241-c7bd-4041-6eb503e8ebaa,2514916997,11290755307238904927 +f4a4d27b-9540-74f1-15cc-9d2c852de732,1820408119,681571863246306172 +22130c69-5599-f214-fe4b-1512ed4399b1,3610651415,5815407531036841595 +d486102b-82f0-f79a-b533-848f37eff1c2,117818922,3188435737840861370 +843c2f0b-31eb-96ee-022b-bf35d4ecd5a2,3930204493,14026250407851538696 +2e9598ea-de8b-0eeb-0d11-28ab463177c7,2028374269,7683569289419080478 +5a424c14-1b15-cded-8a11-9c28941bd4c1,3189338734,10770847471910265165 +e166b7d0-6a90-881c-bea3-42e674b9cc07,4242395985,14552717151963233600 +74052c3a-30e0-4d31-f0fe-a58b18f284eb,145044497,2526117631988852856 +7a8fd8ff-9f28-a405-e790-be52f05a6df8,3789814531,6990416034778148500 +acf8527e-d901-0522-155b-c1381f8d6ee2,1318911560,3073944139248608770 +5d3198ee-5f7b-b686-9042-f2fee7162751,2498781096,17479933008479630833 +7368a4d7-56e7-34ed-954b-bbd500bfb1ba,2936080705,344119205245701989 +92764a27-9ff8-4442-c110-cd2336684fdd,2251818274,11909671592087373793 +5682574e-d099-8c41-82bd-d48c26cf0ca5,4018610727,9626968597725792053 +dbb344d7-4bd9-74d1-67c8-0159f5a81e1c,4128664348,11300029531865061146 +59f3671c-4b50-5535-e513-dfe295865946,1862673606,2374469619498832523 +6cdaf6b8-22eb-4b2d-b59a-f076093085b2,3990863840,11352032481594212382 +bd4b5fc4-9bc7-ec9c-ab6a-fe2f0c954eba,2639987653,5002543004105028834 +78a375de-1bc2-9490-9ee2-e2a4e5a24a5f,854017809,5499142295064426828 +9616d99d-b3a3-da57-6542-b9388d5d07f1,2208902540,12563885229658759334 +e0f9e97b-bd3a-5393-7167-a1e6121716f2,2123459134,358345155603599420 +d340a49a-1c2d-ee7a-9b2a-47af4987f923,3070184284,9446036238264625621 +1f389220-942c-4416-c354-d79705215020,2052205863,16986724747617023162 +64f9dbce-24f9-82cb-63a3-247ffeb0adeb,127276153,6582737940915960066 +3a65d35a-e555-2c68-3202-63e5bbdfae50,2543400459,6137463970903617253 +408b0db6-6028-d639-d376-069e83435e8a,875407544,6055316960309822783 +e261d7e2-1ddc-6ad7-45f5-373a6cdc7862,2656098772,10710323422540228475 +5c8e178c-78fd-729b-e5df-cc6a96cc6640,3395755924,14024754881813984895 +979c9ee6-065c-d161-78ce-2a00f722065b,361095099,11896564567938857395 +d009be10-bb9d-400e-d1c7-0e8a52d24bb6,2496306940,14514469560775265962 +9fd7ee71-1572-96e9-31e0-a204e5f8382a,1956705545,1666042571082228628 +55c8840e-2fc1-f438-0af2-0cdda7f8a45f,1954030724,6803960933214968901 +cd53db71-0acc-8511-3d96-62266c0973f7,918993956,16063373864347369198 +0e8e618b-9a45-9922-f260-b1144635703e,2511858089,7065946929815838559 +3fc2f96b-127b-f17f-b038-d3f69bdf17bc,20633132,8104260017241404245 +a875dd3a-b28f-6928-3da9-081bafcc43ab,1969506729,14484120469376990768 +3403a150-8fec-cb4d-7a76-b1a66459927d,3274293961,17031721526814705961 +8e3ed625-0542-abd9-c3a2-d79d45ab70a0,2142926546,7786647255385094195 +c926ad08-50ce-9d16-7026-ea12cfeacd58,1953941529,14526511730526957689 +198e3351-898b-474d-4753-4444b1a6cd2a,3884253569,5968514943741716519 +153c256c-e458-49c1-9813-c26847a9781e,742561056,3292600689470428413 +c70f0bd8-0701-8489-5c80-f800b261817a,2156067627,935027214059213517 +6cbc24cf-0c25-6ac4-f00f-5f9909bd4dd8,371898940,2941855140685497360 +610ee1f9-8e97-51b5-4c57-deb1c2d54303,1205660062,6316685594480117336 +b32b74aa-b94e-68f4-e407-4dfaad66f25d,2138388736,3077255592070651598 +99b83b0e-424b-659a-a1f3-7d326815f1ba,2125052419,12121938246977252392 +76f629e0-bb3a-a952-2202-84277f97193e,846845437,7434021503853883413 +b01009b7-5634-26c7-a5b6-e05560f6e432,721696924,6087168073922287198 +78199410-eeb6-3680-06c2-61c119f9de2a,152561711,2397726949436112536 +77e78be2-bec1-d221-0910-d29c69c408e1,607172145,8414814297437677591 +c19d2442-e487-c923-81d3-8a5a8a76ddbc,3922920043,3969323578516614376 +100984f9-de52-691d-102e-d421d26bfaff,3554287677,5375336978089926314 +70e4f167-b779-2fb0-dae9-67f34c9473de,3634945484,12456536686629701895 +70d11663-79d4-882f-65ca-1f595ca5540c,2625392271,6898357219409760689 +4c39d34c-85bb-5b41-cb2e-fb705d3938b0,85175301,17473261425103451086 +da54971b-597a-5c7b-7a31-28509cd4f3c2,2277415373,1354350939816016349 +f9a35cce-9f1c-5b51-3651-47350a863d31,235518357,8030623915332045156 +332e8c82-dc9b-9d2c-475b-ca5ffe667166,1391697984,2846595066802484655 +e23ee6ff-2129-4fa9-9adc-4ea7a0a114fb,2906086727,16721043232763151134 +b2286c1d-3d04-657d-af43-b9f050527737,407927006,18431764948244661971 +5f1d2c06-6e96-5ece-5892-7b6385f40d0d,1594123456,810076932751875424 +c3b133b7-e75c-ac73-c0bf-d8350966cfc8,2149248796,10383685744523837438 +c782b4ae-e289-29cd-2201-485da22242ed,1255007533,2607237239295101810 +1f028bf1-d250-99b0-1bea-a2ac631f2e76,2677907854,2577902301997810873 +c9810e37-be8e-b540-2574-538609751058,1075022747,17081097000595052435 +a0650c5d-5f58-08b6-5673-714b5ab6d959,1485538318,17080463047996245455 +86b87856-7033-f43d-4082-7bd41d54b7d0,480225699,3198316805981740529 +b33cc40f-1e41-e273-fec8-a6b5cd657d39,2728364299,2076765569813523555 +7b8299e3-2737-c648-c5e3-24674d769377,3052935748,15352263352767151296 +3e3ee11f-7ea5-874e-ce8b-6af8e2e41040,3317099483,11534575892929271079 +dea4a416-9317-a9df-aadf-61e8c1df6e06,615556751,17631403722389407512 +e3309cba-bbcf-1834-3343-62ca826ffa6d,1637167050,89810687630887054 +44442ba7-8d87-986a-9b28-f51201d8eae3,2793040261,15760959310378697058 +9d5c0865-8884-364e-2770-05a3087cd877,744935471,14587311426865396442 +bd94b8f3-d89b-358f-33a4-2b91a808bfb4,3744728792,4442456691509591019 +ae0be405-5297-0588-2e5a-72f4cc29327d,846062753,5682163680008444609 +13ee1293-493b-22b6-b9e5-8ce81630cdae,2881206001,13307194201458749889 +1c5b6bfe-40e4-ca9b-0dda-0d2ab6a3a769,1284461056,5236415035641516790 +95a8c2a2-ed0c-616a-9b26-32cf1c1f31b6,751000805,3873730167828462438 +48c42df6-880d-4a03-d96a-a6d6d5fb995d,57443836,3375430914690652430 +22e8be9f-e283-809b-4b30-b8d402672ac3,2862569593,2577115416274673794 +8e154f9d-52bf-2beb-b1f6-03792e64dff6,2828887852,1629233493503305690 +644f5023-5776-46f8-ab45-6b3bb2ee6fd1,1739857427,7239685353896250207 +718a128f-7b94-2e29-59e5-fd8b08641c73,4237365385,10093901311838697755 +42f0a8df-e806-4d19-bbb0-1f7a1604f352,1454087315,2218939624279547933 +b95ff48b-3d32-19e2-a556-a0060f800d51,2481846304,4306793027933993602 +a494a151-17ac-1c57-674f-7b63575c1230,3344649039,18367151783247201664 +7ce36890-605d-7039-a1e9-0a7064964c14,1704840962,1457501425644146766 +732ce19e-568d-5048-08f2-d7d9643f2100,458311203,541598719633967463 +ac2b25a0-e1b9-cde3-e6d8-ab2e72e58b8a,2397413428,11319567270593727749 +a9e379d8-b4a8-4933-8803-2efcc5216ac9,2400250343,8812983474255233683 +9b7609b2-807f-0aab-c15c-4f0b06702e27,3197322901,14229207016070312598 +5981d997-f3d8-a8e3-1f45-3408a37aa855,2437409088,243431959045180943 +e941887e-2e72-e274-d7ac-010ed2f58015,33480568,7474287257661451397 +498025ec-4e8f-7649-ee56-fd36480bd65c,2917541670,9501975062663146784 +d4f3616e-a84d-9412-7066-de72e068627d,3692782149,6693556505278604554 +4719ef6f-07f3-9b3c-9e8d-5c1a94e9891d,4200787553,640022244285358406 +da73f399-de6c-907c-f804-115cb3cd6e5f,2743498782,7940053994042843227 +f319d2ba-babf-b42e-8b4d-4af7b29f7868,3146280668,12255744798505388259 +4f27d0bf-0a88-7863-147f-ab0ac39f9b88,737034585,13189303027062912440 +c302a806-cf95-f47d-5cb7-5c5c3607c61c,1038301301,16873631166616457569 +d087af24-a08e-ca5b-615c-b5538b35c837,1287723010,1060432583439441004 +b4a2ac9a-d19c-c6e2-9e9b-bedcd77f72dc,1462340718,10766215373139456347 +bc5b67fe-102c-8757-6149-c366056c79f4,2520790837,15446795227311893237 +a50400aa-c539-8cd7-f0e9-64b6fb1a9268,1017892196,7115923304307812263 +e281464e-1d20-98ec-9588-31cbcfd265b2,516419567,4343038109013567752 +42054a02-b710-c54d-5b9d-c8bc58ceea5b,219628579,2991217152784098587 +708b5150-dc20-e8fe-313b-11258b7e7cf7,261820619,17886077694279035891 +ea7a07c0-9378-f4e4-3f2f-777ba8f34831,3725432661,18013180689380792312 +143e9abf-f52d-904b-7672-f722d1b67c01,612850603,8051890373183911810 +cda4781e-dee2-0255-f8d3-2b12fbb9ef42,409939169,14541209367750528835 +6690b2b2-47e5-28cf-d5ea-4a58c9c61f46,423636313,11562227637473846178 +655b0e6b-eafc-2858-dc50-eaf51de25584,992616475,2813929612857605093 +db184f72-3756-010c-766a-644b95f0b577,11808306,5711489541450196541 +81e12403-8ac4-73ca-d4b9-67d5f0fd516f,4058142866,11697750481498665038 +821cfaa2-8275-3675-3f9f-36b6162dcc7c,2497388351,1767054518735301276 +36d00065-01ee-af44-d3bc-b5d7c43f95f3,2268477079,1415327675832720664 +b9722168-f1b7-2521-0d0b-75e6da83ac75,1274863344,15376310811639018761 +fb897530-7689-ba52-c412-3294aacb10ff,1990638910,2737886719755547662 +6929043d-2f2f-9b1b-90c7-1d2bb8bf5e80,1095525907,9654288801942198327 +3774966a-0248-3e61-c49f-0217b5ea0e52,3214268414,9468860962951657132 +c659ba6f-a277-bfe5-b513-46b71599139f,3749718526,18225343028310533364 +50bf9b5a-34f1-54d3-7616-d537d6d41760,2593370173,11043883325594572442 +80adc60e-90f5-2aa6-eb3f-72ee0befbb6c,4020178256,2204295526890577073 +48a6e18f-5911-93fb-a681-4bf10fa585e4,109256960,1937414264338298707 +e75338d2-da60-f3f6-4e43-3f07f5bbb45d,3894903238,15769645711424392866 +42b2d55e-eb14-cbc6-675a-f958fd23c5ff,3361848714,12284871821040607000 +8b007cc2-cad4-216a-c3ef-97cc9c90d59c,326200307,8189363693866407470 +bc37b932-2d66-14f8-107c-5a229251ff04,1802916953,1368641946312099016 +c2cdb86d-f00e-e937-d871-983e774acd01,2243108020,1661530804586901817 +b012f254-c9ec-2e48-4fa7-97c997584f6b,135397621,298884046591541945 +a821601f-9d94-7e85-0db6-135c784baaaf,3526530009,8892862290387689471 +d14a875b-dbab-6823-e331-d2066650a444,2164626002,17366567552366286578 +702a9dd4-c0ba-0626-d76a-ef7be94abbbc,3269141788,12176193240532751227 +03989fc7-4de6-e2c6-07f0-605419486db5,2068534867,7103146558188573369 +d4d44f2d-a266-4525-b350-c1bec30638c4,1975278013,6643241273551039101 +d5e88aad-c7d1-2890-09a2-d3e850308cdc,1243758307,12214936257507123668 +7e915440-fd2b-bd9f-c2d6-9b6cb8db91f4,469310299,9651941318128454915 +d7952ba4-848b-8f8b-7e70-dc3019698c8b,3625456867,4238844398288944063 +45152cc1-83e7-54aa-6d3f-8b9d6bdc4d7c,3147858145,12547235422574406567 +844e3ae6-4518-2cfd-4094-a64387f0e438,280524701,3320665434967616824 +97eacc26-3d3f-51b4-547f-832fb615efc5,1612337544,8564110622265771965 +11821482-3da3-1a8f-29a4-51939627cdd1,2720723857,8215103517402354155 +6517fc45-b05a-ed04-42cc-6bbc6a2d3294,2784365723,17547806906509726991 +47ee9105-6680-5296-2f35-329c0b144834,2537794090,12259551569189205948 +ef0198dd-2b04-872d-8a73-4722bce9deaa,3805406211,10983016382992841858 +6c9e9bfa-a41e-fa0f-6a7d-996251b74fb5,79000078,1895648981625910360 +751f99a8-57eb-ddc3-87ad-c0c365e456e5,3958579300,2064978441535415956 +763d2d02-973a-efd2-5431-aab84fb6dd8c,641698119,9892621655978496214 +2b41795a-3344-21ec-510a-8628fb770bd6,2498196526,7626405195696660901 +a3f8b186-9b67-ad17-666d-3f42072166df,3669012165,11430980860939020057 +0b18911a-7737-f45b-d9ad-f32a7f7d0778,3945965454,1459389038732961678 +05932ecf-e06c-6791-8e96-f3b5ee4114ee,1718752351,13788168436623875984 +4b8bfecb-4f9e-c94d-2d05-7b747f4d9c46,3596313483,6339000813724870053 +25705a54-a94e-d435-6126-43d4c3effee7,3623044679,17335698646969585823 +398dd7b6-9422-3bd3-8733-f407648a2eb2,1570266234,17656594544106283976 +15b1e8ff-7883-0c1e-d8de-309d964b903a,3098107651,12019525291625995305 +9968d5ae-1e8c-bde5-a70a-05c13298e767,1573379185,12710145086138359090 +a498cec5-42d0-4e08-c257-832c10af2323,4224160895,9667125666330743791 +c0792745-6e01-39b3-5d74-51e700bbe389,552010732,9064901638903474860 +1aefb99d-a45d-c622-eee8-6387e52a7993,3479786982,15422642143113582829 +66bae2fd-887f-2c51-218b-14b8fb6c4c2f,3303007687,15977385238182423090 +a69357d6-c15c-8eaf-69b6-de13a69fba48,1601199687,3503428098804883691 +102b1e67-8967-9f88-d29d-dc815598d230,3904980880,10647023567227767920 +8e2e0226-2c26-63e8-d030-3e3c04765ddd,2569094405,13118101082852135598 +03afabc7-c92d-d3e9-172f-b290d0006a29,2592556110,14520402423601332287 +5fb66e6e-2675-ffdc-4621-bc9addfad5b8,2505936137,3738277509241615171 +65d2a054-7a30-8ff1-466f-7838dc1bd368,2857534958,1515302834882531260 +d027d268-a95b-aed1-480b-b495246b3812,1590031008,15691614342571071367 +06f4c8cd-b4ca-76a3-4649-3c6d89c097ba,901704370,7019326316925566642 +5a3c22d3-9d43-8b58-6aac-cafaebd13920,1084749154,16847644189112604673 +8c12fe87-a2c8-c0d0-32fd-49eaf66a0754,1145616685,9146052820022583478 +b1329dd8-783a-1a96-55c8-64896fa08aaa,3245911787,4790645216481325837 +cf47f4ac-dedb-0fe5-7e73-d55d743bbe6e,4283381045,17478317662516573324 +c048be0c-74df-65b9-5412-680df700a0f1,348542651,11181460358127220444 +93224f74-bc83-56e5-e758-74b37467fe8b,4101512509,16540398726589456449 +3304b8c2-d63b-0c48-41a7-a2417871606c,433552862,3314241429182345030 +2294056c-47d3-e989-26df-f4d94b3656ab,2995289907,4621355630112983476 +93a548f6-404f-c7d9-a6db-a0fb23b60b07,2947759724,9844286343641201186 +36f91d31-cdcf-3c61-b004-359a009d1f55,3329267431,910516986564500810 +23ddd6f4-01b3-747d-5e40-5cc3a2645659,2515232511,3106855020240066160 +baa0e179-3d76-b79a-03c2-29a175457296,452443654,452671485653161553 +b3d41477-24c1-0198-7a94-fa6b207f3857,130024090,5101168328329578135 +ffb1023f-5e4e-0883-cb89-d6c4f1550ca6,146287730,4710526778724405296 +9f0130ab-76ed-5672-dde4-e7c1fbddab0e,4187486565,8628305742749236300 +f2fc2845-793f-0bff-39ec-c157b4671fc0,375547711,13621362527150629229 +0c12721f-b7d3-fa79-aecd-8fb76e6a926e,1438254053,7352077105359824377 +050e1679-96cf-a3b4-3865-fb34d2b54a10,1920290714,10055522789794612928 +d652a897-ae19-bd47-f62b-f5237dcb8a98,286002697,1515285967469162203 +4f1c6ed0-690e-9f8a-3eeb-7ad8accfd58d,2039096307,3080753655342575801 +58cd47e9-6bcc-7a15-ff17-2e116f2075f5,528831952,11766853537080232797 +5777e2c0-146b-226d-9e22-074a4d243ef6,3787489658,17094022024531842211 +0817903b-0ad7-d1e9-f694-a1026df076c8,3814356479,5545172350330245498 +bc3f8576-f3c9-fb11-173d-1b5514b92d33,129069667,13564711253065999796 +655df14b-05d6-8b0f-6251-d3b5f6f92da8,1457305262,9403746929003670644 +78defa83-cb81-513c-c1f3-c031ad42ac7a,3562868437,1784065776411232391 +61481e9a-2185-8955-88cf-cd78bb007455,3530926572,8497477870887057633 +ce38e3ef-b5bf-e6b6-d202-7bf2c1ae4184,752402241,12722299005849476050 +f5970710-ba3e-ec79-6c73-48a6900b4a5d,2702257746,11861011469976252976 +d138a47c-9706-faf7-6c71-650deaad2fc8,2406337591,13244395059708832863 +5bc7ddda-2812-2368-c9ce-634d9c601534,3057541233,2031542263020478891 +8c5ccf16-02ce-4559-4355-4cbdac74f2a8,1938977077,9690744432008632315 +af6470dd-4b40-c25e-5e26-6c3b63e21cd8,1969007003,14789319765117669293 +c1843452-6e2a-9392-bfd9-65c80cd12063,2588123866,15113592479561617127 +b0bbbc2e-a1c3-7a83-7214-4b01486fcaf8,2252069527,17499792666941058932 +36fd6ad9-90e3-b91e-d3a2-eb704ffa834d,4178605928,8191682312693775335 +4f985229-f547-46cf-fd20-a9a76f348244,3367872288,5231304917264827269 +4a309e90-542a-07e7-5c90-7fd20e02b99f,2754151235,11838969642276510854 +e09f1d0a-a03c-c73e-2d25-0dafbbc29001,2620988088,10786735583676388104 +17b99c01-d423-2911-59b7-4ff0ef22c2bf,942725429,3972902385191996065 +f73a0f87-dd35-7a49-8a66-f8300f88f0ce,3988760842,17647974180397709758 +dc180831-641e-2ec6-4221-1ff926234200,1161050636,3915500613745684257 +36b46238-f6a5-328f-ebd1-d03f16af5290,617691396,10819685176869701783 +b0cc978d-b371-1192-7937-7bae8004a2c2,4144411154,17330619605846854110 +9a51d379-792a-9a39-442c-c8bef40bb22e,2593480650,7948469726207702952 +71e2ab76-b7e9-64f1-7808-8b8799aedad5,1786140400,13701122858290559828 +e2d960f9-66f5-bff8-47a8-a1dcb2b28be0,819195609,15978674517500951939 +c3a4bf26-99c2-3c5b-432b-238946c12368,2519367547,1271651773962997178 +89b0bfd2-ff69-4c8b-72f3-a276fb46bd6d,3758725289,6943271650874888336 +c116422c-d029-3914-3178-be7a4a975bba,521507472,11737912729912065503 +e926ad2d-a002-5d0d-3668-bea3d1fc9a0b,171353156,11271317037325845036 +83d2c5c3-afd3-b50a-2ef0-1a4e165b19ea,2548535734,2244793820108382775 +e1b4138e-75cf-ce25-f1ab-9ca713cdba64,2870550018,16849812966901490263 +bdd2be54-34fc-1d27-f6fa-fc50e45a9d91,2660328910,89099183174926551 +6dec85f2-6f88-f35e-2f48-f76594b55f0e,2748343983,4439577448010290898 +49773ac9-3765-1f3d-2775-03e475179ce9,1865851921,3782116724637133967 +4a4d8687-02dc-4127-db5c-11e59da1511a,1418932223,3328098958631974646 +dc5c66d1-25b9-0b0f-dd00-8d53efa57372,118754345,13093108421174691184 +43d0aed5-a972-780d-b460-4622ad06b3b6,393865600,18310531209786207930 +c1de30d7-69d1-35a3-b4dd-004842207610,917126391,17832353346524391624 +ea1227b9-a175-84f2-648d-72d8ddfac16c,269108323,17992083232496388328 +f275b7cb-c2d9-1e31-eacd-8db4558d2c3e,2044859131,11476723808616971489 +034cd1e7-b7fc-a2b3-b661-be0885975834,925921403,13149740789567518262 +3b184d70-4d41-4d9e-32e1-d092e14dacda,351166358,13572811141497024626 +1f25d2f8-7324-b2bd-7d7f-3ead391fd63f,818668656,5678815895009690296 +74049bd7-f17f-90a2-3596-d2b674c14712,2655231206,10801399592782601970 +be113ca6-9874-57bc-1e95-d27d006297e1,3941218363,3587841103038312241 +8e30fa78-0903-ee2b-4c75-727764e15d53,1534191646,9869417519430314082 +4803151f-b15a-c236-8802-b75b0aba0dcc,3293296529,8097765117151332088 +f9578f7b-b97b-ca90-a1b7-3b540c3c918f,2440920812,8682508414807587449 +aeeb3826-aa59-835b-c260-986902811e3f,1391033813,2550096658378500160 +41411aba-a004-5efd-0adc-e959ad9e3ad5,3354660599,12072958607931327786 +4ae7a537-77bd-84ee-fa1f-ff21491057bc,1241288965,5758092501567433907 +a6406419-5f3f-5e1d-dd09-c41270753403,2593529969,15676094658606134290 +70979cb9-64fa-5fe0-ab50-756d91eb1a9f,1705841910,8141541339081848439 +38527f60-9709-aae2-bbde-0fa016089c49,991917812,2393477860647785782 +d29bd033-c3bf-2a73-c025-42ea372b4e66,3181195927,16196295975524943800 +c7eb20f2-5e50-1d3e-c7f3-3421f53fa5d2,3596163743,14778374942991949129 +f83ce79a-a0df-7ad7-e5ba-4c185e835bba,1357885056,154451555369725136 +8be50b58-5746-0395-2bac-c5d136068a58,842584957,6341091995592555391 +e6b88948-a03b-fc9b-594a-68e7e1c24d00,1140158234,16532426286148972273 +cc65ec6b-5115-d755-89b9-7643613ea6fe,1243061531,5359209281983140393 +d011774e-e181-5515-588a-811bca6a3419,1340657229,738013679497643861 +42754b01-3a99-775b-a984-f3b4d3291561,1646793082,12391749519801922385 +8030767e-a226-a5dc-f16e-de87e0557cb0,213210192,15735529924244587046 +a4ff30c6-bf1b-0cde-f1ec-569cdd489585,560807862,10112753510697837291 +49160a24-b220-27c6-c827-1aa319e9c220,1616181510,15947491393909126346 +85c6d8e3-c5a7-6589-19d8-2ba16e88c04e,4252583326,5308810816455127229 +8561cc84-2b74-245f-5626-293d34fc02b9,3705048171,9833487817493814474 +58787d92-7d28-0683-18fb-45e4ff619bc5,2235714292,7600829596020930507 +89a62f96-2fd1-066c-c5ac-7f0f6ddd3cb6,158263423,13694480627855538491 +065c5f2d-bde6-73f0-9c14-1d6e9ff950c1,881190259,3299335958520533017 +526ac6dd-2d44-f1c7-2c93-f8e387c2d822,2496113570,9699197843769366778 +39470697-d452-4bdb-6f28-b7fe463aa4db,3522508047,364946882243838119 +7dca39be-4503-a56d-e25a-1fef617352d4,1558748128,4629051836567415040 +97b00ccf-7fb6-528e-70ca-36efe4fcf920,65969955,8282102570069646027 +c6022cb3-952c-88a6-2e40-8d8bae381b10,3109142590,16942772687261096932 +81cb278c-5d1c-1ae1-55e2-3ead3140eadc,1962984016,14830856425631905380 +28ea4f60-3f1c-a433-3804-03dc5be06f57,3171515187,1889646871428705886 +30aa74fa-a45a-5af5-ec56-98d2e8391d0e,3276974401,17087888423455894647 +a573c857-2503-0766-e060-06d67e2452c3,1339463021,13800309235145981034 +a373418d-3b0c-91e1-0202-1a6c209c3999,3614665407,9448452327249184684 +d66d7dd4-0078-fd26-103c-2b1fed661bc4,698746971,10766128431680279699 +f3f9fd07-edce-ea30-709e-6d42de7292f2,1265524745,12738329023962770334 +0c2a68db-3219-8849-0861-a13795c2f9e2,1614170183,1396326218503596437 +ac384709-77b5-bbf3-3855-a87bb6f19450,1296973687,15473490744113234627 +3823f678-75d3-d3e1-d775-989b56c58cc4,1884109752,396606291400874593 +7e0051f1-ae2f-5bc6-fb0f-6a867030389a,641959967,15745756214997471824 +5e73edd7-4603-7d26-55fc-1a8c7f5e1d13,905565077,5815352035475260250 +56434ef0-99a8-b905-b3df-fb445125a6ba,2102328526,4439982914807017974 +8fd086ab-cdd9-bf77-cbc1-689e7dce3157,1789414120,7727335505127684143 +8099ef74-06b4-2c5f-913a-329579c55125,2870473071,18275832997964810716 +e1a56c85-1af6-bb47-b820-336d9512d09b,400872315,18249673368283884288 +f509a460-a786-de59-c438-b92dbcf43564,4254595429,4832318907367542342 +4fc802e0-d732-cb32-9f04-01e1c8f17a69,544842034,6291142971082734163 +8690daa1-e4fe-9711-6160-411b599b4ed5,1318514142,13751928124804490988 +4bda2961-ded0-fb69-6ba3-a89065c45eab,386528474,3300402579494035829 +9c2949ad-d356-06e0-126a-7fc18184cd0d,4053598488,597814042918456667 +e4eb6a75-66cb-3c84-a6e5-44d5945dcb96,53516570,11263087716169549001 +f979bc2c-635a-c8cf-0eef-f9e9494e858f,2746620290,9374919319112327471 +ce9592fa-9c2d-b157-f6ac-a227aa946dac,1819809728,1045764137565344179 +6cf1bb85-fa2c-e96d-28ad-dd3ed64ecdd3,1231114388,13626478013001532548 +99ca99f7-d124-0c7b-9aee-68f3385735ce,1439044757,3422443730477518254 +7f4ebabe-bf1b-a9eb-6ac6-eee9aa71f40a,3574814140,11288953912758461728 +4d486a8b-3b4b-1d54-b2f3-312512003c92,2774639604,10264985919960853911 +390cf7a2-239d-dd93-a7bc-692f9fea2bfc,1128890493,3730674122298261233 +d7f6467c-2a82-18c5-b99e-87178ac51d97,1206703198,18238599525408725501 +bbe45340-95d5-6c27-e2b1-5d367de8e1bf,64916038,15617797235598805732 +f245823d-33d4-337f-bd64-a0913d7c8df3,3447210362,3043909131542066226 +5baad6ad-8ba4-5344-6896-b765ba9379bc,1220626370,7352983546095086872 +a6443c7e-7226-0c19-adc6-1bfad1e1bee1,494136100,8793468634783367562 +49cca39a-1070-a46c-c78b-4e0285bf9c79,2037742427,16302066590309680607 +d87cc803-576b-ef8a-ac17-b2b176f7181d,508251857,17855126756512369621 +84dbf35d-aa86-d047-034a-065ca1fcf51d,3515438706,12886369148857071937 +8c81a0b5-40a9-b182-aba3-f4b9597a29a4,331842550,12246755622052586285 +e067b8bc-5c53-2985-b053-b77db37b832f,3219040013,4163147556846746209 +9f3fbc8d-47a6-2764-88d5-f6b62019913d,2430871682,17542607912999316807 +4a06d38e-ca02-6a92-0bdb-a8bf3f02c5d2,4113098003,7433374380419256338 +3dc79c15-e210-a65f-f4d8-c35750422dcc,1578170847,9093645060917070330 +a8eaeb7b-eb62-01e1-7747-c4a734910283,3594647869,9826868460046794074 +c7bf6ac4-ae4c-31f9-c8d4-106f4525215e,2933339988,386323351976856217 +0fcf1e30-6ae7-593b-970e-526d277f2dd3,3210014096,8322524433105480359 +df6a3894-e315-770c-3314-6c3a86b54712,728408705,5461523288931091450 +6aa126fe-dc57-147c-8b34-af710a7a2a86,3000514921,16298244916433728871 +33d8938b-e04a-bf6f-b3c5-41161ab5312d,735205755,4923804847265489673 +19864806-213c-3ea9-315a-6782a322abd3,2061736172,11515129067339631693 +2d6bf6f7-42a0-042d-a5ba-82cd9dd1fed1,4244254612,7491741891752365276 +f356e278-bac1-9ece-501c-325209dd3b51,1067866483,6165636427836171481 +bd3fbe13-19d5-123d-bb81-334a155ca87c,3177252941,16222143633986082864 +62ba80f7-71ff-1bfd-e5fb-72931ef7c762,27441506,13881232090356074947 +9e559b4a-aca3-6107-49d2-67a46ab7ca65,3121359764,8345402789582051224 +3f48e062-e769-9e9f-5929-08cdf2b3f97c,1733698358,9248598515100737590 +6249ff52-0ed4-ed40-689a-01d829e40171,2181895776,5603846889635604852 +b040963f-9c74-ead1-4fbc-952dad4e1fdf,897980928,2802966150764556485 +3b96fcfe-9fa4-68c6-9661-1e4a1fd2e3a2,3625709633,4675908909884244621 +c533b06b-6268-40cc-301b-b002aea97302,2793642224,9392237270706894873 +266786e5-1b22-1b03-3a2d-79cd7cdc0e41,2323445553,17328775306822626161 +74632dab-d2a7-0774-6967-c5a3e37f2050,2096041037,3416687175270558898 +d78148f5-0dae-d497-52aa-f0971f6ec159,1938741502,15912257512613589936 +74af1c1e-5eb3-cd44-4148-8686452500f8,2329027054,11720618529412484611 +a9959786-8c2a-3724-40b4-1b9e3fd82b71,4294032564,90909060003164688 +bcde5f2a-c8a8-1bd2-dde4-0f47c8eb0015,2518374064,8385352443910747122 +fb68d411-b2d0-2092-637f-381c085b1369,1475068732,3666502904034920722 +afaf0751-d4e3-0fb6-d0fd-48b3d993ca61,2078932007,16841047714881610782 +5ba185e3-d52a-bb12-5601-58bf1ee5cdaa,740581830,6217185404790570807 +3b4f1022-2b91-4466-0965-c27024b0ae21,791787870,17518805785674808274 +822bbae5-7817-dfdb-640c-9780e8d122c9,3336713488,16775308023972249359 +19542d78-dd3e-d172-4892-a745a8075a1c,3939682808,18100802694180164136 +ddec2b09-0e2f-7fe9-2652-d69ec9285de4,2810614436,12410272956999391763 +39bae92a-a7fb-9023-9df1-ed676667d916,348085268,11435919627148493061 +6a20f8b9-0baa-7409-9cd3-5d377e8c4b0d,3012447225,12557690726436256508 +9e54bfc2-f3ff-9352-e908-932a72a3c648,1702143135,14577295809012441016 +a42bbbb7-d1ee-03e8-9823-6a56e826494c,981659936,7669607401508484154 +6d57e8f6-a884-e3b2-d862-2f8053ce6158,788306782,17821418496761766004 +a88a46e5-f7b8-313b-b9a5-e183cec1b700,442177709,10473235438521642194 +e2736d4c-a425-dda5-a101-77bbb783c660,2661631871,695511342834569751 +e04a04ca-9bc9-8cc5-5694-967a7476dc87,2009088284,7437734272644989069 +c30f1c52-eed4-48a2-018e-4088bfdf1ab2,2378076598,16466851541520948070 +a87a21cb-8c09-b4fb-dd07-f5eb1bf87811,4260514101,6768858332962955345 +b4c78f75-cb1a-ad4d-3964-efdab237c65c,3723738716,4220211680728279925 +32f43e6c-8df1-4e23-35d4-5841ee703d9e,4258572643,12108880556887640264 +33e536bb-7892-7e70-5f03-d86ceb14122f,1168098460,9876773911205462844 +7dcfc0c7-22de-6bd9-99af-917464c850e8,3099566972,14827017111095831733 +a6904e05-78a3-dc00-2f7d-2659ad1efe21,907114266,16727094054131797115 +f4a51dfb-96e7-2a0e-161c-6111a26006c5,4250831119,1681429259259682364 +4bdc37e1-f7e3-2f76-86e7-42d7bb43129d,4007635529,11599981764100337384 +fc56b276-8e33-f2cf-6fa4-fc64ebdf0f37,4162969719,12186437077132714867 +a6c4ec52-e970-49ba-38bc-3c9be767f39b,2814279376,1681686809907096599 +a3f57b7b-f71c-8d31-339f-48dd394158b7,496600202,4309505222556099967 +83b600a0-7498-4a2d-3338-841dbe085dc0,2360927719,1110585161115234958 +dd146696-f39b-e945-5496-a8526325f1eb,1953910796,7938330202839522729 +206beeea-abc0-beed-d36b-ea52c8dddadc,2156635535,5389112796555606984 +ceb6c4b5-84c5-85dd-e8c2-57b706afa629,1022852044,12014038387709998457 +b4c6ea0b-da12-3f76-8b91-218dfff98869,2900317745,14508250541625327964 +eb602830-21d2-849b-8b3f-d7e90385adce,2485892025,5072067343886222473 +9875049e-2623-554a-11fa-da0d1fb126b1,2751309091,4734015429983797507 +616c7742-4dc1-cfd4-df03-5646e9f6def6,3831627764,8039983172081337694 +e80cc3e2-2543-1397-9b6b-31bc6a9b67cc,2116642828,16037241963640593015 +d933b064-fce5-03d7-2a6d-36b51559b57e,639357943,18086812611371068577 +3ab74d68-1f34-d918-16f5-c0404922a964,831517367,13842673981368544592 +84cd97db-7606-3e6a-8ff2-d4cdb0258bd7,2505711886,1381594624749005346 +2a2ee481-cae2-03e5-aac0-775299c78bd9,753672896,6640302152645843106 +5b0c8d09-1720-2c18-cd5f-ac203ba95e98,281958400,15628208079545495465 +a90aca18-0f0b-11f5-c077-89a8e0756ec1,835029271,16272489700038825212 +437c43a8-4769-25ae-4281-fa21fbf8dc37,3057718943,1128132999198122593 +c0553bd9-7f91-d6ae-8ff2-a56c757153e4,1995273501,7865026754329126869 +14060ade-3f46-ca96-2712-5bf20fba0eba,2945026912,14472012925208475993 +f9a5e3f5-d043-6630-d318-51b0872e161f,3993482953,2357915871825385270 +990f7751-4689-d623-6b89-ca3e176f7b2b,3175650613,176926220376103505 +3fb8db52-56aa-5386-657e-d21b73c89950,765471683,9463430872617354407 +e983f671-affa-799f-5823-0402d6970163,1143101531,7601632639489949652 +9a3a82ac-e133-cd8a-d690-234221a1aa01,2186613804,14637199917816906612 +e5fcca60-85aa-3ca7-9b94-94ffbea11ce1,2537697256,2609198146710960487 +f6c8c019-fa66-090f-9478-5c0c6d0ddc6c,4101877258,3622583367967497747 +1b990f9d-3975-fa94-5e89-24ef16a21294,951492395,1170524597983690330 +ba52f002-1dc7-9da9-2233-bd9192aedd8d,1310899595,4734582135654099812 +782028aa-e0ae-9157-f792-6bcaf1d830ea,130529091,7791365974489011568 +f3ae7c07-e287-9e1d-2772-3131e92bb767,19752584,10755448164588366216 +80e0a51f-9c3c-e509-05da-5912ab8864c7,760566054,5468892163715362 +c533fcca-c9d8-cddd-b145-8f0324170594,1911096103,9952399371668269618 +f28e9131-fae4-928b-2550-440001aa3cc2,1746066284,7349627842903883735 +3bb7e831-49dc-e47f-7ff8-b6df0ae2450f,2484479624,766127978316165435 +f7a310ee-4ccf-d8ac-fd55-4c45a81a4971,3917345387,11174766629394852507 +c90f7490-6eab-bf57-766a-bc498c586149,3323755380,8960472388279468949 +48930168-c945-fc3a-59da-2aa21a7e0a57,2902786066,1578780090609935585 +a691a407-7231-65b5-0864-6afec348e348,615916722,16051095365150967839 +a2233d6a-9a85-0335-d718-4c0d235f5e77,3733848237,9173930902378934502 +a5798d6d-5803-5f85-4ff7-d880936e44a7,1314252550,2882314844379664282 +e0d36e2d-35af-ac2b-1aea-babcf5493263,3239231189,17409428984139090950 +2a89d1a9-72f5-a54b-87fc-437e3028594f,959070827,6103241388654213489 +ca583b9f-97bb-1b6d-9e17-61702b6b5217,806816486,13537206377016078263 +42664d2d-aa27-779c-68cf-b86f4bdd75ec,719946335,10840959530143093722 +400c42f4-4303-28e1-fdd3-326fbbf4880b,1385753169,1589879976249603427 +67e814be-ac75-97b4-1849-26d09d8d26c8,2956158611,16004772894325976914 +63256fda-2060-18c6-745a-ff931540d25a,2760379210,4991607861474672492 +d114781d-ba71-9030-b31e-e62402523936,825686387,11432877302720779583 +04603d28-819d-739f-03e0-0aa5ecd31972,2403843673,3315231562974462536 +5045ff1f-7144-f2af-c84f-7cf457de8723,1874744022,9722254845532089573 +e820cf01-f6a4-679e-2f84-a2412c805023,2313650161,12945122597167513585 +ccf661f2-3c7f-ef94-5610-634ef2cebab9,519900054,9966087496526892145 +8a22a8f9-7049-df8b-3d91-3a85fe8cd966,2052123084,10712935516522612595 +d3ec941b-d9f9-1026-988a-5e5d08fc2f42,475886219,11404582177552156633 +c5479d99-7e0c-6a89-ef4f-b9cbffdc88b1,2666300506,12898475423351291373 +51f35656-815d-e876-1ce2-8b10e3007529,313910932,8869947828443431063 +700280dc-d282-55bc-00de-a90528b6a2d1,4148206425,15580186123206239406 +d326181b-14fe-e632-634f-fffd00b25dfc,83552687,1834196777068441887 +e74a04a2-9094-96ad-441e-d89d2943e348,3142301657,819821420982409159 +7146ba62-0389-53f5-24d3-e60ebc989e22,371210365,4474501080918373948 +29dac9a4-0f83-9f5a-acd9-1a6277c8ef76,4020843267,4816367834421386824 +36f818ae-4941-0589-4b75-41354d823215,2497282635,2100332995657681901 +faeea99f-b843-ae42-4de1-6107e75698af,119417050,17146038091781977439 +e4d3d52b-ffb0-888d-0fd0-2d0657f3827a,841612042,11862216144443287118 +ecfa9b4a-4320-24f4-63e2-041e2f657793,1845163537,2635256301330115210 +f9ea7487-90dd-6373-f36b-3d3b9c4ce7fa,2384862086,14121430985611972123 +38bb6b79-ff02-10cb-518e-d4980f34b1fe,3394514946,16679949764077280818 +e3112a6f-879b-573f-8ad8-8b9283d95e81,3333643512,4146417761804223599 +f258f156-ee75-3e5e-8da7-0b5244b63738,2865841352,9584295919177811639 +fda8c8fa-55f0-1b64-c350-5e4133fb413c,836596324,12793535732452371549 +8b6065f3-625a-ee35-3e3d-a8b4bd36b07f,3952700495,9330272143336662536 +58f22af4-61ee-1c61-c172-f300c5276a77,2038934578,15489746612224335181 +90f69a45-175f-8f18-cb0a-ff1649368dc9,3723163469,7104329846434330463 +e196dfc5-ee7b-2939-cfeb-cb1d59273148,1485544376,15813800981988392858 +4d173c0a-d625-8222-95ca-74354c565da9,438787685,14919593583867460663 +59fe02ab-f72d-7ac2-2a93-7b2a7385a8b6,1188326771,16940496920579576510 +f07b16bc-cae1-fefa-dd54-89bb84c46930,1988162013,4231846693661416223 +542c7614-37c9-669c-e20d-ca9d4a383115,3670863924,16027268809997350286 +e3c8cbb1-ed4b-e67f-e33e-c9c118e09dbd,2862948211,2642373169135376801 +7f02d8a6-6111-b089-3484-217e38f98140,1472903765,12968667377296532884 +4f12dea6-7eba-3eef-9f69-ec4c5e8a2b86,1496800171,13917505738680328030 +2ca7eb53-6c6e-1080-0c35-b81f174cdc7b,442949449,15207927254775606171 +09eb4a73-ff32-5545-9659-cae5b5e7856e,2135678511,11325371192444445296 +59df0ffd-b886-0b6a-11d8-99fe02033d71,4037762060,2761141899920630539 +24435ead-bd9d-6123-3589-2c02dbb416ad,1184117652,8228431336126813511 +e4649a80-08e7-00b0-1b16-6baa45db5e84,5112510,15812696446667726603 +59aefef5-710f-0a88-96af-b880e5f300cf,1228970465,16413252657512676245 +14511665-3abe-3484-5bc2-e44b9ff68644,724293242,5373557443406725483 +124cebb6-020e-0afe-4edd-296920c06462,2256393910,8484197378209151173 +a3ebd881-b46e-6edd-8f44-f9a2ca104dcd,3595040777,1676121585520305256 +6114a5f4-9bc9-fac3-095a-df11614f44cf,2462944063,883773341437477095 +a6e3d762-184c-38ae-25ed-19c1303f9cd0,890895018,14527561310084984064 +629b5dd5-08ab-ca33-ba94-0d1f68b65064,2790087323,539892126203449167 +a93d3a19-051f-e0b2-b873-bf848b2bbf04,2758448366,11010047657271940627 +5c0280b8-12bb-de49-586a-56858e9c720e,3227994138,10972791850838204097 +b79bcb35-47b0-48b1-8a52-d509afcf3418,122550075,18405104011391758209 +f88c95ca-50c3-5921-3914-ed7d5687b190,3006997639,3928857658416796484 +ac534583-2708-de61-21d9-2af424355313,1331541592,5354596743623205287 +561429ee-ddf5-7265-e586-aee7bd0b20ed,2103741189,13170395554400524932 +b69dc5f5-a057-1258-f0b6-4c6b0aa6665b,4268406133,14346793526539894109 +e835e5ea-df09-9f11-7b13-65cb3a9e51b8,2556631699,9548115679338327136 +73c8ba3d-9153-84e6-601d-dadef952453f,1539194885,10528408513163407150 +2f10c7b4-20fe-4bbb-ee85-bdb7aed9b599,2004985076,13537635421473266777 +2cf0cc81-b550-3b40-b2a6-ebc6b7b741ad,4094451943,8478076562671964313 +75fb1e3d-ec73-9985-6dbc-de3347a03aae,268282742,9014006767685494491 +9eb6f5e7-dd08-cc30-598e-fb936e3b49a6,1166920538,13190217964204037034 +cab62dd1-4de5-2414-8007-5f0611b8bb35,2607281569,7880659711665588503 +e3744cc9-efd7-3e55-e68a-6e691c802ea7,2409846198,13253285962944833553 +738980a5-8a78-e6f6-24f7-7fdf8270e5f2,3346771248,10578504312986598716 +05c0ec9c-0ac2-7cca-4133-d3bc1be91ea1,3617816013,11741077845332350577 +84e0a49f-56e8-be28-7e4a-02a4850fee99,808611266,4530087048055884951 +e90f8616-071d-db69-4277-f81df4cb3d8f,1239905393,17882896080333456627 +071200f5-9f51-509d-570b-26fc1bdb6877,3332785131,2397300449165641563 +96d86283-93b1-bf93-ac9b-7fc13e9e2bb9,110112992,4146297884968693577 +046fb44c-967a-93e2-a1e6-f6ea4ee89818,1148535776,1668255164187741848 +a29788f8-3905-17b1-ffef-d531e3e87777,4048563734,3081076916175341135 +3d4e42e6-1060-3f18-e12c-197ff94cfcea,335721437,10954698032670841890 +0b2fecde-8ac7-92d8-8e4e-3e2aebe25be3,1115539892,15515446966879644567 +6caac761-bc70-44f5-5be1-22267547966c,658035281,12797734855116947395 +2fa58944-57ef-8440-5d1a-38237e97a6a5,3509027420,5746651555517587524 +d597d643-4dcb-fd9c-99f3-7f93f8ff4572,735885845,2378938517500301882 +dfe81285-31b8-e0da-c195-aaea1ed6d1aa,410883327,9777192624843599476 +2cfec755-9d79-fa17-e04c-4b4b6556d499,3748891677,2803613835689445226 +3bf4f88b-79e5-a8c0-86a1-b66996bb47ab,3658804106,7690990796026123033 +c8541ed8-747f-7829-7532-a99d7698029d,2762535844,12118581558137864351 +f6da4477-9a22-7eac-49e9-013834d704be,3397586364,14579784555662029599 +3571a9c8-0d1a-e727-a4f3-4b3182200a55,1429555560,10341183026958480208 +28f0b774-6661-b434-7ff5-d4b2be6278ad,459508155,13714009126863750065 +b3de6923-3f8f-b852-9294-60c8a359b919,1544033076,309553099841654210 +32a45f3d-befd-338a-0257-a8d55c648df7,1859764901,13018682543691080270 +f35e9c9a-04bb-4d0a-fa93-4d5090f98ff9,754838925,812222411909639685 +567d329c-8e78-3f67-3ddd-1cc8d12b51d0,826292334,3358585541417514192 +316dc042-0558-fe96-285d-fbcacf82e481,4181820785,13182926984526578966 +4d7cc8c7-78ee-190c-e872-f31cc2adb54a,3331889490,16752351486211051980 +fcc14a5d-2d68-5de9-ac3a-a589cb18eb36,3837596564,13458461084962600294 +01e17702-d0f4-ca59-9323-588cecb691a3,1440216412,16703961634897100231 +ad508ab0-3351-ce98-b6f4-a71603d9b2c3,443851586,17162152063047458241 +5b5bf73e-3c8b-3616-990a-366d328cc54f,1082485365,8182712492922906674 +f363a099-a37b-589d-4d48-e738cedc19df,4134345060,14273311860960770609 +bd869542-b1b7-c27c-ea8e-b9afbca7fc48,2404752401,7028258351218425044 +821dd42a-363f-8892-8b95-3c22a16dbf4a,83863687,6539791897596949788 +1c2ddc01-bcea-dfc2-715d-1ef03eddaa1e,2340793571,6571090625147304543 +fc0c7d2b-106e-ee62-99df-0067a56e3083,2387878361,11063523462416597203 +2ce75923-957d-3969-55b5-78aa4d6922b5,2984778596,13445501355515935078 +aa4eec60-deec-f0b4-a3b8-c1aba9816445,4109874583,17780655549424440658 +52d7ee5b-9b6a-2acb-f090-4cc04e84024a,3986403350,13341085611648965121 +3f72f373-54f7-3cfb-d322-63b0dfdce346,68643749,4514110038621212360 +13785fd0-1364-fc99-6657-4639b9b3c542,3746708860,10935236206747151639 +d9b34775-550e-4f64-d092-6c13a8c96db7,4191476506,9818382895804353655 +81a0f8fd-ad46-3452-125c-d8df5c7bed39,1922085563,4722272889315933704 +4f735f56-eccf-2973-257e-7cbb468ace3b,438722728,4557177859341470982 +822aa22a-8b6c-d409-48bc-fb24ae18d427,282763662,2182415984663557407 +a96b9a5f-59e8-6920-02d1-a73623b181c2,187102171,14367859710850521503 +03dc15ac-7b2b-d1d9-b544-2e0f536c8e45,1507853089,9605495761360869427 +dff65824-96f6-90c0-7ab4-8be7b5eda02b,3073149694,2570600073560666086 +00230cc4-51f9-c7d5-30ad-d781f8e36334,3389719448,6086737706434543243 +04e25367-cda1-95df-c3c4-fe2bf4908547,3427864734,7812242993191952479 +49f97b79-0e36-83d4-80d1-4a6e5ff6f24f,1905734633,8219704157768598837 +8ad7c580-9c57-4a61-3cca-bb1856c7e45f,921067967,1786996235712705069 +afc1a071-f3d3-38b6-560c-b553779d1c1e,3146669066,6127499046974591866 +9af914fd-7c25-42a4-e5d9-1bdf401b4dc0,482583512,13932694605039961962 +629b7e23-81ad-9504-c65a-f2ea9af4e9ff,2160867184,6357039640348621988 +3833903d-f980-2d88-d73f-8429a221751c,2430661468,516053590466948844 +a825dacf-a53a-6583-fb81-86fd8748fdd4,2979533968,11961411827356072369 +102029d2-3fde-804d-5449-15b099f8550f,1434011725,6349017709027774665 +1053b8b5-331a-f72f-a099-eb83e3df70d6,1732870001,1138329632120497912 +18d82fec-a51b-2b6e-4849-33f751a84f10,301446369,4623007077911438562 +0b1183cb-5e37-1738-f640-1301948bfb63,4115018196,5370854598650333658 +e5e875d3-5943-09ff-5dbd-f78be19d2c68,141427428,13801419370574167265 +05c8fc10-4082-05d8-9c35-e526fe264a0a,1971183194,10044360898882696308 +83ef9af8-72d8-c94f-7986-d4e2ea4d0f93,3024763256,1486269575837971972 +aea1889e-ffd3-9538-5ac7-256eb3e5f633,2599731312,6072034272702081293 +ba6929c5-0be2-cc9b-c93f-337884d66674,1669419638,10333080463822820570 +b2116277-c8a7-aba2-a0a3-231d430cfa1a,2824549933,3501817223332957278 +cf0df513-ae01-5a34-c438-adf948c293a7,3594322085,12695311603434859275 +f9565f3a-f056-ebc2-620a-dcd773817354,205581477,3318447217095366144 +80243a14-a8cb-9eb1-4407-68fea68f2a96,302047696,9350137612241942022 +e2dbb67e-c494-a15e-e08c-d1c021ab161d,3565905706,196219681836302729 +dcb707ce-448a-daac-3fad-c2755f709bfc,1903431223,12990805802995521648 +a9c9da0e-c99a-1949-4c98-d5d81d35e371,3235665063,1611410610984804432 +2af929b5-9d59-409b-a67c-cd337aaf1e4d,1359485080,5588082288799741568 +57552db9-6508-22e1-b644-1bda726d9c87,188751296,6251327540066801499 +bf18bae4-0ebb-fef8-fbe6-479116582749,3645249203,15505257735988138760 +d904f45a-e51f-1aae-0970-207f1776b426,1502989205,10078866796042500824 +32490f20-0c6c-62ff-0027-3d181b8422f7,7203696,13330338362243508839 +e10ecdc6-7ce3-f0fc-b03f-01996aec00f6,1502034707,7069547428642746495 +e1250d68-3be8-f11c-71b0-2803a5aa5a65,1754465710,8671048316053678367 +f412cc58-8a78-87f5-fb7c-192621ead9cc,129325586,4613057845133678024 +027b64f5-2a5b-b4c8-a3f8-3a13262c7eee,2526192967,11759111639503129091 +37172bdb-1ea1-268e-176a-a145674b1f4b,2341241358,857407870712923221 +452ecef7-0047-9dfe-9201-f4a5332a75f5,2704673730,16980215895148496048 +e70d8602-45d2-842c-5305-55f676f22ce2,2333110110,6125128055674851106 +7ea1e4ca-24e8-86b3-9083-89983c4cc608,2376119921,13687641152476505160 +d246dc6d-c0b8-60e7-8d6f-7c12f2fcc6bf,3450381028,6283050424859102061 +ac19a620-7976-8733-7e77-e99bb5045d46,1955485694,9488842354091815579 +3d42c8e1-4339-20ae-bd9b-a8dbe02d0377,2876360774,5056152892172272506 +8ee63469-b409-f702-cdfd-557ed6f0fdba,525175382,9374248060755568873 +877b9bda-81bd-2eea-67c4-83eacc095d9a,1689521799,9243131868433116277 +262ca251-e0ce-2688-4356-d3dbbb98471a,2817822237,16303849554836295741 +0d949521-f300-ce4c-e052-e69453050a41,528843380,6920018946656700516 +1b845b36-4a01-524a-64d1-44b83e375e11,2516054521,13312657960422846916 +e7a80441-a859-1f46-24c8-622201e6bc6e,2506218151,14635083781748969604 +17bba10d-58c1-1a6c-8869-f7bea1b0f175,1445915120,3468867168800337589 +6c361f21-e276-9800-d39d-d0d6d6b1ad8e,1959498458,17027321185773800431 +fe5ac3ad-816b-36cf-1abf-1a9a53c912ff,272576173,8333615831323247907 +386c4395-d393-0a0c-e680-eeeef4db4658,3415745708,3437165813268337984 +c88693f1-013f-27a4-20aa-5de8e225c4ff,280732386,3300808437231739071 +17336d85-7250-6c21-0afc-4255f5c1a13b,826154302,9404489818069107115 +c16f019e-73b4-cbcf-0ac6-01c4e734086f,774098703,18218103210807346244 +0a24a1ac-3cf1-8cb1-8baa-eb4f35f8b984,3234127315,10381475819408678002 +c10c6fbe-da4e-6fb5-6deb-35d777b8c793,2457037549,3052384122440065804 +fefa2756-fd94-15c3-3bcc-881bb3ee4b59,99059407,14226021013083053196 +ec892c11-9aec-b76a-d777-30247e106875,689370278,4065190929593588447 +0e47fe76-a900-a0fb-8a6c-01d00a27ce67,910152134,6905635718014189337 +970e9f09-f9ee-ca61-3314-d850a40fcab0,4096585477,16036174847495391790 +497e43de-1488-5b11-6b85-ce92771f4e75,302398790,10582935017164571176 +637feb9e-75b3-dc70-5ab3-120f0ec32183,4165568954,16883508305758280774 +e4e145de-ad2f-92ee-ea0b-188f9fab76f0,1462650861,5861158835576539195 +785d4794-32b7-8971-ce81-1b131eb86075,3165801583,17639006044243976235 +b7750ffa-f731-0654-9ad8-3b93623d86c6,2713375973,9765444584878933249 +1f349cc6-2733-e0c6-1dbe-ac65b7c2013f,129827271,3271857323644219184 +f07a02be-765a-7b91-84a4-f981d4dd46d3,2268908332,14840242830230252653 +b56dde01-36c2-f78e-27a1-df21e8f93966,2175734027,7137046498916688013 +77555d90-5b62-e793-b11c-a3fa792a002c,1840715875,17128976116454646163 +046ddbd3-baa7-6d7e-2fbc-71b739dbbedd,1927645133,2628060200861631602 +dcd2eace-168a-c5ee-f0ac-cf5525e240fb,4280352087,12878473231948965452 +febaba11-2a8c-9756-b6b0-b873e4fb37e6,1583917508,264892763459666171 +8745a337-d475-2a4c-0d81-0c7021f66f72,2840838037,17867931771661460799 +61510543-7071-fb84-e9c7-e3c7aba29411,471110014,9773053685308628243 +6b716235-55bf-ab4b-7a2f-17ecd6cd0cb9,2899976377,4702767879390822297 +1b1f7c7a-e932-5515-9524-a2dd2a2d1ce4,3053893173,16600797643356253402 +dd1116eb-f462-330e-bcfe-6a18a2ad6f2b,585948557,3041676816586247464 +a3c599a6-ea20-c98a-b635-3d34a057e1db,1759499265,4360490877301209076 +ad7fe0a3-133a-eb6e-831a-01624f75af59,2788737069,312547031839072798 +47576845-2c58-3a04-df56-83f7851824d6,1226316364,15968673578705484659 +d4c2a947-ceb2-202e-fda8-0184fc7c5c5c,791586662,10552869288100346436 +9f5cd4e0-7790-8987-b173-17bcde1b9fc3,2233331494,13681107479094179463 +94ec72c2-37a0-5dd6-8457-56c798c9e5b1,3084197205,1338788569558559210 +cd980308-b393-90a0-00ea-b6a9cbbe7cbd,4192880835,15622214520593498021 +ece7d60a-8a1d-3640-7301-ac859ead0863,1088743620,14000195307544822755 +15138113-4a8f-c52b-3901-a34e5d9b19e6,2137012118,3462970605662525546 +a257d7cd-fcec-e35c-9273-cc2486b1b815,1425937113,11099512680279379239 +fa6aabdb-e97d-4e46-88ab-713c828e7d44,2239277245,15122612297826467969 +0516aff0-18ad-9f11-47da-d1f6c37490c6,147476489,4753477244681129493 +a04b306d-32b8-953e-17e5-0dc0eeb096d8,3748037097,14380722049264543373 +4447cb6c-48f2-6a2a-daa4-05e9762ca8b6,2072747417,2656338783545138948 +041558a6-4fd5-64d7-8a3c-372517a0266b,620856107,10916612162072466965 +49a0a447-b096-a6ff-69a7-c44b643c845f,2217891090,1785188541115603481 +0a6c1305-b97e-38f6-683f-cf8301f5fe78,83065955,14480749048282088528 +5d00f86b-ef8f-65c9-07c8-36ba2b1a2b3a,568034937,1426185078802013 +4aae6634-e941-157e-66ef-d73d463ecd63,2184821438,7508710348668725789 +45609a1b-4d8a-3d75-1a39-6c9412a96ddb,3393997478,1497612731575737732 +a19307eb-06ce-4754-168a-1a0327bd5edc,2296383417,6514854260681287928 +d767450d-a0f9-0218-fb67-35907ac11683,2268751492,17037389575714377443 +ae5fae4d-478f-968d-a9a5-f6770118d856,446908990,17903514990270309810 +ce25caf2-68d6-15ec-6b12-5154ef788ade,3915046037,8713963623829692554 +ff10f909-7069-905e-7ce2-6049006cf750,1835017727,2463473693898461942 +49abc3d0-824d-8f38-2374-7aeba1fae855,282565499,6224290438272231703 +9ecf4b10-6ee0-1552-dee6-b71703c9108e,1146893873,1500754613932309860 +b8bbbb22-bd58-a0c1-23ab-422845a60544,2149363686,10350648104447540159 +0817b02f-f68d-598a-b2c4-07bab8ac60a7,12480476,6910227135631551247 +beaf4d52-74f8-a829-c7a9-f59f6d96226a,2929880587,12226941560457407183 +5813139f-6e74-6b65-01ee-72ef37e10f02,575051492,6268780402569429436 +b9981498-bae0-54a1-ecfb-35fe7332ea64,2789353652,16413286033989428703 +88163e9b-0cb9-a7dc-7468-b23ee6aa4ec2,1822554972,11489223089681130104 +19fae37d-b7e4-ed72-828f-11a274f18ece,206157595,7085884781519887042 +c0b61b8d-0286-6918-e0e5-caf39b82ad46,1084427695,15316601429435252795 +9fbcc8c5-ef35-062f-675a-040c9f542c85,46701866,7634855689599319069 +0a991a0e-7dcc-3a32-0267-372e2ed876ad,3569920841,1257481670354630521 +eb0fc069-94c2-2659-9539-29612e49c754,2224977689,1280785425795976850 +063af257-4e74-d4da-3cb0-68a3bfd285b0,1232734055,6939194193223815178 +d5dc6faf-8eb1-6cd5-4801-8f492b33425e,2210148053,16327353617707983703 +a862dcf0-a872-0b1a-e722-ae69c7bfd86f,3577402838,12613252618514165982 +21177e57-5ac7-76a7-59d8-b75a68859ee9,1533118377,3707916630961735886 +0f7fadba-2edb-4368-5ff5-283d0d1f8a84,1458577723,3285544301934283874 +d1e1a431-f829-fd00-a846-73cfdb44c455,2355838058,5985765567372272960 +e41706aa-5060-1f73-05e5-2b13f2f9ca14,1196539740,17331510362093004216 +79c5b08f-213f-238f-e702-e9ffe513300f,800978561,17895812459124249504 +358768ef-c807-bc8a-6b5a-8ddd4731ac74,3884687561,6087375654430287437 +a8cad8db-1e7f-6b61-a832-e71337ed9225,76392388,7684061442251623830 +dad88a1a-48aa-4b48-e29b-435825b723a6,2463337546,14311371130201722807 +881330c2-b6a5-cb30-150f-717fbaf1a1b7,579484700,4001414482586089647 +34b615a6-6fa3-7095-e4d2-08b104cac39a,2767061965,158450464134687597 +2de07028-29c3-e81c-92f1-4718fe18d7dd,3151091126,2151105968249498611 +785eb196-35e6-21f0-6ade-13754c58239f,1547546524,9395460216352989264 +2406707d-2b00-d3a7-33de-32f31a6da2d4,3561014301,17462003861110426019 +a648991c-8abe-d84e-1b4f-d407d4ec84a5,3854381306,1043893708833814430 +c330922e-efc9-29d6-eace-e787d729dbcc,118046950,12632089643756258308 +b8ade7d9-4d88-07cd-026a-8dc2e23c7228,2555286692,16766695682618928407 +bf41de73-dcbb-2491-32e5-df041279bd3a,3750773765,13803652794378025802 +92e7dc69-2fb9-9bbe-5ecc-23dbe6241a47,971587828,10971536436264014740 +122248d7-77c0-82de-28ca-0868a00d836a,533522935,17850789286029920623 +d0fff8b5-3feb-6ed6-a561-a3c6a1eb69e2,1621625111,6422087293373800883 +c30e5f40-c32a-5eb4-dcd2-f1469c223e40,1640702469,11484401204122517532 +59438c37-97fd-b225-5d49-d76ff5f52da0,1900971560,2691402190985754806 +86a2e06a-2a52-9a83-bf28-8df021802d10,4025199009,13527924376519985448 +84039776-0377-5bcb-7094-1fc443265567,1706126469,14110791412060020065 +e5cd1f93-cdc3-453b-6e17-cb37208fcd2d,929157889,16633575641564064926 +98245d14-818f-a8df-a43a-cbd46bc6598f,88005627,14462065618188174208 +a86ba28a-3085-5cb0-c17b-458a1af39a29,2123304248,17798750657209093107 +7b148fd1-eaa5-a1e9-6503-f5933456ac6f,1674493459,8967995294314688328 +7b00de14-b78f-483e-5bdd-a3a60adaf3bc,2423717274,2512969379994270276 +69cc20c8-9e6b-7f0a-2802-d7eabed969f1,513090335,389438055014196156 +ce4c46db-ddd7-d0da-ade1-e52746104d73,359841073,2566842150364632733 +8a26001c-3b0d-85ee-7305-7212bc845bee,2537665890,9159620834724626359 +5c48c233-56d1-f2c7-d9da-e061ff8b1e17,2475552964,10333589397221921993 +e4e829ce-dabb-401e-9156-6e737c02d6d3,4203102020,5716839087821359829 +d447020e-0908-4482-12e3-c3e531fbcdbe,3536010800,16146596337671419111 +698fa012-0ffd-1b13-0094-9c0e63466023,732111783,17854176149588719609 +217400f1-e500-f2c9-ba68-6b65bcd3300e,3344973723,2603753196894358115 +c348a341-fbe6-ba69-04da-4bd854f64252,58795245,13006543261949065597 +a9992f36-f3dd-d4aa-3590-a15254af276a,1969411802,6954682699794322461 +977953d3-be07-44d9-11a0-281efe51dc4b,1552432992,2269283922368443990 +299093b9-0d2d-5279-5b83-130ef45a3fa4,3877472859,5706828474000345964 +589cff89-fed2-43a0-6d68-e6178985d76f,1290432548,11691135678208525655 +f5a519ec-f2ac-0e9a-9d1e-d7d7751599f8,530584209,362267762497320171 +c2fb893a-7524-fcc7-d5a7-5a06022ac1f8,1274226979,13047571849822022918 +20639beb-4990-746a-c639-841b3ef617a2,718358725,15635397296955693581 +16ca29aa-8c9d-c021-8e2e-b32d0d2dff6c,3759948046,14908062734089370725 +b55ec45d-7243-87d3-920b-4bda6122d929,3988361132,5950230053485967030 +c6a9b840-4ad3-d671-9eb6-1801eff124ea,3059533676,17579455724912495350 +f9639461-1248-f648-3c27-1a96f7128749,993848062,15770698551350515952 +c3415f0d-e5b2-0bcf-59df-7104fd60b7da,113405195,1498705155140328945 +0acf5b8c-de0d-bb22-c8ee-56c35fa17e8a,3665622585,12494432218009257506 +d47329f0-0666-a5e9-1b65-23816fac1268,2661089231,6128086147967734536 +c51ea757-1423-a303-d369-94c53a0c4c5b,923203513,14040774167126455479 +32e15ab1-034c-ffc7-326c-4a0927cc6834,3500266732,6062824875629512039 +4440b64a-161d-7436-03f7-298d4228b6e9,2724803395,10368340774459703952 +d3de3f35-e56b-b612-54a3-746f6da3bd4b,180462172,8284788873688396161 +630a9743-5a8d-f58c-2863-141136157eb8,2845711324,10717259504500886553 +72a7e1b5-e267-2a7f-e9c1-f48fcad28763,300008274,11691430727736832951 +e94b60ef-f42f-fa30-da5c-62d3c73430e1,359061564,1791480261935150207 +95ef15c5-091d-e0f2-ea55-4312a37dde38,2835518835,6995014055414377647 +31efc555-e566-ed31-5f45-43d2026b5019,3773722345,16592979689944188071 +f611d4af-be82-70f2-f28a-e1aca97f2bcb,16963352,17892281284851084615 +f1f74004-0029-ddda-7892-5c34f7914b69,2972926582,16464132574959685369 +e2d9b4b9-c73a-3947-af15-9f030bbcffad,2132844753,18186112207922174773 +3d8cccb6-5e06-00aa-2620-6a1479fd5f2f,2208922296,1507080275835209989 +10030645-08d9-d78f-99c6-d576c8d126ce,2178854797,15047518074556291708 +249c442a-69fe-911a-caa0-8f0ad69108d2,242921204,8355935905734279811 +2e8c9357-38c2-0543-d4c2-ef2291ed1c29,1201630801,61367399288514602 +87902f44-f67c-e72f-8fdd-7ef3f87526ae,1651551862,12089782392868283292 +0ad45540-a3dc-a8d0-be2e-1ef25bffa832,897920800,4678750092740670633 +9a93c60d-88cd-d33a-da4d-dadf7fa14472,3074840026,10788223689599478971 +a3902fe8-e51b-5be3-dd49-0eca0c845890,2114282729,17331027284306548800 +26237b14-eafa-d8db-40ee-5399375a5a23,2429361040,16070880542694322613 +5b63e735-a68b-b941-ee3f-9b95636ec0b5,3526132614,2927156788978463163 +a567a142-fc4c-8ebe-db14-34fa363b9534,1307340268,10111469647044855095 +5d6ba0d1-4f45-6977-0e54-73a36a201a7c,3251521985,7501141904292319154 +493e5273-8175-d91c-b666-c89dca2b9566,3238437149,1553505268628358921 +003c8103-2dd9-25f9-8117-955bb9e72ba4,1714100778,10419358777202316723 +268f3c12-b7eb-8639-6bd0-29bdab31f669,688252195,1585984784168558494 +875e5a70-2771-916f-6099-c2bf3ff8dce9,2937388839,3657144758442884815 +aafa2187-a7a0-d0cf-1da4-36d997e5558e,1909633704,11126668267875668566 +aa6d6977-1374-7a47-6da8-2c11dc12e4bd,725434967,3696847395053937264 +0bedbd12-d145-6104-d7f3-5935e5dc6376,3494147486,7962550204713169543 +8bcddda5-5d9c-bb9a-3205-dba69eceac68,3635277460,12424562856465642893 +f1bd671c-89d1-6448-c9e9-69f0173f7ff9,2405298742,15144491784725257588 +f2404a84-6633-5b5d-0279-f1bb5cd83a3d,3618684757,6886875444327291395 +f2321d1a-5ff4-6b44-ab47-10ce3d30496f,2188737045,9096959876050426096 +ea4c4ac0-4602-9c58-3f74-c4a5ee2a72b3,2703905891,18132268402620908419 +50fef38b-c47d-faf1-14a5-54995754dbbd,1991976111,9358314976386794448 +047fb583-75d5-4861-944c-a07bcdeed0e9,2436851654,12060208851083859944 +2fddda66-32ec-0c46-d59c-01ba0747aa3d,865205600,6923982127476098905 +dd7bed3a-3baf-f527-879f-2bb42463499a,3332691934,1611411916093733753 +cc2f3943-7bdf-fc0d-6f04-c0a65e4f60ec,2565023286,11111792932874262176 +709cc093-6f53-dfb8-a331-29bdc606cc13,510090688,16502517724473617888 +a1926e64-6a8b-a41f-a992-422aeba16820,3075585112,5340192929330352814 +13e70afa-61ae-7cc9-7e89-a6f2018685fa,3230324343,11209371842481668014 +cdb37435-0be3-f6a1-c458-dfb05c1819e6,1842530089,3145268406786080522 +565a396b-12c8-cfef-4bb0-a7b80a433972,3996910777,10318380345111288126 +c4740176-5fb0-150b-b841-c52660c43474,1210377212,943656710152526723 +b7f8adc1-2a8c-3baf-6a4c-ab0d8461b7ae,2423583567,10673294498576574421 +a3b1f0a8-707e-9f0f-2183-67bb3b020e32,748026559,4957953328362442128 +5a8745ae-a54d-c9f1-f3cb-cd26e0af52ae,1363673635,17186454663352926591 +e506a591-a534-5e00-0f08-06f2620a4724,3239223947,5510138751588571385 +9a5e92f1-a065-fbb6-e136-661fb9fbaac6,2418579171,8541608579281466555 +23543006-e23e-14d3-5d47-996cb8e2e86b,4017536931,2968225264110740459 +bae5e14d-834f-f0d9-5e54-d2390eaa2c84,2851019087,15012668414562126477 +cff64ca2-9459-6307-9ad0-b67c065aed7f,1333164297,8883329139211594441 +526220aa-8443-03ff-658e-c58affe8c154,2881224642,5880688652616655676 +76d8e641-d3eb-3c01-b6ea-496dd9b6cdd3,2953318773,5353961194994050727 +0d63531d-c42e-e616-905e-a68e3eb27b37,759426047,16898244388043183275 +b4793a04-c066-0cb3-30d9-bdde5174bbbd,4190234794,13261406605239040843 +095b3afd-9f70-cb89-c3a5-2d3321434955,2586478858,2468303497175885992 +fba3fd40-7707-3fb2-865b-b9bce33c2f08,2015470438,5187066080853586166 +07e9fd97-cbc8-d231-31ab-c792c4bdff3a,619931061,13720470298649807719 +e7bb0c49-dffd-b18f-1032-c39e29e4e9cd,1588133677,1685220978895562270 +e0a1cb16-365e-703c-d519-4352d1c94227,3074497577,13173002613430960072 +073b1eff-4f62-8509-7895-04f9d55ec4d8,3025690433,12754043418580745738 +7d583dc5-f401-1e69-c54f-173e2f191bf4,2256862851,14912416631159864866 +19ff3735-b499-aaf9-3a41-62dc361bede4,1108689677,10047672387725738310 +1c1caabc-c11c-636b-284c-36935d116422,2489620530,10069525320980040098 +a6d0fe19-4c42-e217-b875-5a681d073f0d,184598848,11363169523610559317 +f6d1bba6-1e43-77ef-c439-8221a26b89da,4112778926,3020568441805229598 +28dfb72e-cc4c-1b36-ec05-5e1f1cf0a3d7,1668836760,4802270042028699932 +2215f673-3b9e-a4a1-8b25-9491da2f7cf1,2123497507,11549021451499807101 +8ff75ad7-c2e4-d155-9155-dc8cf9619e5f,474417821,4988226063642626082 +b55f621d-6075-dd7e-b684-21043e12e45a,3744439486,15742792355871453355 +2bd4ad1e-7613-cecd-cbae-ec1415c1fe7b,1781794988,3869404338004511047 +79bf10ab-19a8-7599-128a-7e9cebe3f1ae,2237894069,2729912252403950234 +6654a350-7496-9152-1576-391fd3efb6ee,3965784469,7687466220256665220 +63bd4c52-fa26-6163-c2c1-e02b25a5edda,2894366328,16862078404844242383 +a6735833-762c-1ea5-2687-7db5441f2439,3556689665,1667111283259459970 +64f6155c-ebf0-ee2f-5bd1-dc885c438ed6,2444948549,17366018675746631629 +ea76bce3-ff78-a3cd-b2b0-22b7ee93ab6c,577881007,13834579944939966666 +7821ed1d-a3c8-73d9-152f-61b2060d014a,3294516897,12703642315598823709 +1e744485-0828-971d-3706-7e308919699b,4010867980,8161355005827611055 +835390de-4164-96be-f2f2-8d89a7814188,3988851705,14816691547453048035 +de271b20-dd37-8c88-1dd7-e5da4c049abb,375149452,1376181912238318648 +cea4b34d-8a7e-c729-2fa9-9fc674f812ea,713255802,9611152538354955086 +089bae35-83b2-4ed2-ac36-8bf455e6e312,843016096,12979347268752908120 +f6a54544-0eba-8f27-3d38-f5e440ce358c,2493047236,5459646168697720460 +6f7f7b05-ec91-1427-76ad-b75f840301af,2743459974,5776924768378945206 +3d8f6910-bd8d-d94d-2366-e8acbfa8a1d6,2256120203,12658295051274755100 +5ba00901-fa8e-672a-5926-8c85d641ec50,2004153297,1439025835018422552 +0152bca3-48ba-7ade-5610-2e07ab6e2478,3222006771,862059780202836791 +e0a2192a-40ba-3372-7071-452e616d8cb9,3990837037,9967290298896638480 +8521ff31-6f68-ff99-c517-17d54eaeeced,158974789,17327080194593380107 +60fe4d25-7937-311f-5cdb-9ab29ecdc432,847203228,9023569611644809472 +12206694-f8e6-24b7-b4b8-a6d70dc24db9,3462327591,2890918797678142697 +1e31baa5-cbf8-a313-7051-c6e6718f8dfb,2686841141,7266176433452091522 +7d624f38-84dc-384e-4d45-2bee97a30243,1609593403,2599099036661909315 +317c91df-404c-1abc-0543-ff3a7e825833,2124249505,716771314889291996 +b561d795-8de5-fe36-d237-35fb66c1f28d,3031694774,3878453565145982768 +9110901b-f98f-aedc-0122-1868efc4e426,551687055,9392119324438780543 +094a47b7-f785-186c-d029-63ba40486f74,4194090986,11568075665849854024 +d440a444-68dd-9935-7d77-d1c86eadfe75,2764439127,9949830173691462480 +74767cea-75dc-5f77-0598-4982c7cb053e,908561496,8487992061026713682 +e75e75d4-5070-40aa-8363-32315fee192c,2466975741,3498602671236392024 +0b71c3dc-0997-6405-68ab-391472a71dd4,3191773018,1784454353624691213 +f1dea62a-2ec7-9730-7175-8237d0b28475,4155499382,7104450628875899148 +f8068224-f702-aee8-be76-7c0c29f26aec,3075183983,15168106851175171718 +c10e4963-64de-1f36-a9d2-8b23deb7e881,3555418556,6498865381434129150 +f9106ef9-e703-d806-b522-7cca25c81828,3192517058,10465331095780942892 +8f91c055-6b8b-dc3e-43f4-e2a8a3f9a887,2584687299,12691644596326764997 +9c527418-b313-357c-b307-aaf55fede4c8,1082611897,964420230494665534 +99e2c90b-66e0-1c24-5f78-f1cf986c1892,2593277538,7550886057054107962 +7463f12c-d748-d5ad-8da3-9cfb91da8d37,2621289617,4714959209222257397 +f98c52ee-b96f-cdea-962e-d9d941c133c9,1557269578,6573493581374948226 +a6e96439-c246-1379-444b-b150f61e519d,143958886,7389169186175578219 +cda55fef-2445-8784-0cf9-aa9646cffa03,1999720827,15849674240839869962 +ff9342c1-19b5-d3ec-3098-fa238f287d73,2204194357,18380923503067505748 +07a61378-c21e-3f4d-f860-b87b9e3cd748,2863803453,5104116852097621288 +7eef1faa-75d5-e1d2-85ef-45b30382c6eb,3766948095,1056232514853765359 +2ebdc646-6ff3-4883-c992-2bcf336c9439,4150232770,4414627474872470658 +6faf81f6-c56f-85a2-6a1a-ca46d1d61fe7,2443383340,10758643478392360701 +1dac049a-5e78-71a7-ca5e-e6ebc56eb52e,1788911630,4115636219151899238 +68db9e6d-a82f-51dd-0a80-63bb5fef0bfa,1007055859,3092519059961815710 +97022347-a51a-14de-0e37-006d62787ab3,3178116542,18000002083474674261 +337e0801-37c2-4d0f-c6db-abe53ae6f86c,2510166240,8875163071390969238 +4b1a2634-e1f8-736c-2cba-9f565208bf7c,2156484712,8828258946378839947 +90201e0f-c4b0-0e3e-2f2e-ca539cf4411d,3410128550,217298918731735209 +709b2a20-0e72-47aa-3d4a-f116f2ed0a93,64114199,16973082720020268641 +edab75c1-f72a-9d27-18bc-81d4288bd6dc,4278766713,7504601026521795340 +e81904f1-6e21-7d53-c7ae-2f12adf8618f,1636536697,2097225226140944272 +466fa2e2-fac6-f96e-7bad-64fb60dfb101,4112314927,3909710835143224553 +cba5d54b-72bb-77da-5ce6-f23487d71cf8,3347903223,2203480499011007263 +d01a38e5-917d-8d09-7275-28a80debc2dc,3840314293,1080112532102562124 +791068db-249f-36d3-ffe2-45c719045c35,1985535586,12207251722981029301 +399d7990-40b8-d417-4f0b-89362aa6bb3a,95771147,14519993097352290291 +3f52f39d-db7c-6883-5114-17fbe5ef3859,583614516,3717030991943354554 +09c9ea15-d2e4-6986-4a6d-3f76d4f3cc16,3517606534,3655363704712745029 +62d116f1-6428-fade-4e18-14ecc678dd2e,1685435193,3742221459747113843 +ca9e0759-edb2-82d8-cf22-7997481f55bc,1819221761,11097103318562836039 +9eaa01f7-fee4-6ef5-f4dc-d58a23983c4b,3311567671,1549458141190815373 +e821ec75-d75a-d4b7-e7cd-3f9d809f129a,2370669425,15308231924419430940 +9ed411f2-30d7-fa3f-c63c-2a175eeb9ccb,370449596,659584561764918447 +71094712-b074-d428-3901-9a236b9b11ce,3443662831,16560622513058446462 +e284c83d-56b2-ab7a-3217-673ca91826a3,980666592,2945617826540914462 +0acf670d-2e08-775a-71fe-7078abef7c81,61003142,17149451028352684338 +60aa5b49-73fa-a56c-2f8b-1ee284c05092,344835243,15424460145249850194 +b7496c6a-c969-bcb5-1739-afbf14782e12,703060003,17505291004624901880 +fe4f7990-9caa-e756-2abe-e2e15da28e85,1912864858,1369096618103869125 +73505862-648d-ad0f-a3d2-27dc5c9afb96,644765962,4307971107218034991 +d236cdb7-c7be-4159-0ddf-d4268af182bf,2864135906,10297700418152351655 +0ad25301-94d3-19d1-d361-11428e3247c5,802199655,11984236121660213820 +ad64b819-d9ed-54c5-2f39-3e46ef9f83c1,4007200666,6640137951829131343 +ae739947-54f3-f98f-3cbf-df75c5319144,1064535766,13827687589060240626 +00128e40-1999-ae85-b6cc-3f7c4bd5e766,429580465,15711565379283032072 +d9f95503-a4d6-5492-93eb-8dab3f144728,3297048268,11783237279692975335 +f67cc326-7245-29da-099e-a0b083a233f5,3523624488,4705641748059777542 +2fa73977-beec-057f-ec21-2543ee88465b,1705744808,8807717696709118900 +b06047cb-eb3c-c6eb-1ebd-c242177b80a9,3371176460,3182473970426153624 +03844202-9ec1-b153-effb-e61b5a4ad498,43170936,2799429086768291886 +c3221882-b3f1-189e-6ce0-a15ef38366c0,2489353177,11616359555048498255 +421d9ee9-b1a9-f570-90bc-290b74c3239d,3640494442,941266362484402172 +84f67dea-cc13-b35d-9855-4a461b752e5d,3402092941,3428207355091419200 +4105862f-8d9d-82df-6df0-46a3ef77b975,1229846202,18333332763611039263 +71f60cb7-8cd1-a24d-ad6a-94f7d5395fbc,1178819972,1597150117237407714 +e7e741af-1014-db36-86b9-32ed0e9f73d3,879426389,14170324737476031779 +7afb4016-ea04-a0c2-7170-4ac67cd682e9,2575837242,13566498398073036144 +ac412dbe-306d-a64e-6755-b20673d41e0f,1620532140,16356123158319079341 +449bfe63-1173-7f3b-e59a-387e28bec827,1456439985,193026073313765080 +5a33bdbc-14c1-dfe8-a3a8-6143eb716393,2166205195,10707954834362819684 +f6b7c491-e0ec-44db-cf5c-07afc4e44d78,2425626654,11820464814106015841 +5a33ad26-3d8b-fd3e-61bb-fe4d3739b970,1449914829,13462978930976812380 +8b243c1d-8830-0216-ac77-c229ad67495b,144860493,3641257944501598496 +7d76e03f-cca5-cfc3-9e6d-75eb53f95aea,1138965246,3079948719625405857 +7edf3c2c-db72-55e9-ca72-126f862fcd6e,2969530790,5524854851385715688 +9da2762e-b123-ecc3-f091-d734108c3a75,3127472011,17677463381981632048 +89cc52ae-b383-6b6e-1df8-f69352e47e78,2689729171,1626119558766528696 +b0c68d31-0e23-10e0-3d9c-fab0d24559cd,2307841886,14460991243215187375 +627269cc-07c8-bb96-0231-288848984142,1629357385,14324816840145381022 +98a59d37-9c67-4af2-cf7b-9f770579f3a1,4170634948,3507346625547610737 +36011608-a7f1-3965-2880-a4032f41a4a2,3329614769,4622432961792904757 +24695cf8-cef7-7c79-07c1-2c460b2a148a,261749767,3144736898934427605 +408646e8-e2cd-9831-b58f-5799fac7e24e,3516201815,7741558980700556674 +8862fe5e-a421-f980-2c45-a074c7c443fc,992452612,5990745087535943202 +a233a4cb-5670-7919-6d42-55e21882c551,2254867818,14946731137974277957 +881091c9-c6d7-de7c-9fc0-c4d138989df3,771352139,16689713935869930345 +f8978662-4aef-054b-3a54-f74ed552e270,3507585666,3422355849700624353 +b8f7f8be-27ae-5079-7f8b-43097b82f1d1,3260483628,7126993604729735175 +d4aae69e-d435-6e62-1b6e-effe97a94bb1,1935672043,13403568660277801964 +bc090596-5189-9722-5785-d8a7e0e03466,1384596130,8105325427509438478 +c8e47ddd-c0a2-6c07-7b0e-179c3dd1b666,3336198738,562329169694166400 +a67b2ef8-0e08-a3e8-71dd-421bab0a0191,3833486075,3637616209598905362 +dce2238e-1ab4-b19b-0852-13532abb4357,3813238197,10727985609704243515 +1e1bf847-0811-1aec-d91a-ff8d7160e7ae,1565999696,16460024825476143553 +b81a1d84-541a-ed63-e480-74dc3dc48ca1,3326333273,3810020892707009859 +85d1d51e-6ed7-a2e5-88a0-01d5399aa992,504016735,1108060325826747237 +9791cd5e-6c34-228e-34fb-20d95ff86229,3659128627,8988022275834972705 +009ee582-d618-fdf3-9c16-b573c553aec7,1086450741,3780870476970939947 +8f8419b1-bd38-6582-7fee-408bba36399b,3469021863,11591012114874938156 +8b9df9c7-25e1-dd82-7984-0efcda32fcf1,1472469214,15201900727766499718 +9101e0f4-2695-a46d-aaf9-d981c420bbd2,3106517258,13249399934879594223 +49d6a077-5550-45a3-cd84-d4ff1b8a35f1,1526082005,17151082470220394231 +e824c2ff-6f1f-7f97-7c95-410f0dd8101e,158949161,8565123733905425454 +1bad501b-dcae-99a6-aeda-44e6547556eb,53941132,2910959929606964364 +1ff0d842-3c1e-0dbb-0a29-5ad127645feb,3152241619,8911059649043312203 +a86f43e9-8004-af76-198a-eac5615bc2cc,1007420585,17635214340364324652 +255f02af-d77f-69e9-462a-8a528f003046,3424167274,6261165982669475993 +c1057f82-a5c4-8725-cb2d-4c72da236c3a,873238149,1914009869498223225 +e5df2e81-f040-5dd1-520e-1e4a075dad23,3487247887,14863182726763888111 +cec4a2f6-e393-7c5a-a98d-d8448b736ad9,3487005497,5213164118942716758 +59916883-526e-9ce3-d4a6-f1197ef29a1f,2626638656,14403469155649573423 +09fa30c1-ef5e-1f24-ca67-4f4a20a856ef,4184424646,2826499667849142030 +66a75c81-2d24-511c-852e-4df95af71854,2425530362,55132027562305420 +755d81b2-ec2d-9b95-81ae-b03d235bc6df,1644868929,3238830687373132275 +f0df873d-326b-8175-7052-74996eab508b,1411453877,5049118996526127097 +e760b0e7-9ad8-106b-78d8-37e5ab71d62c,2632183850,890232667454844790 +bab4229b-0794-2bc6-9986-b0a6d9747a45,3125993518,13776442063182155161 +040047d8-5e7a-197f-6986-6645b7d7c3f7,3102907944,2653440687812910194 +f4466d06-f2f5-d344-0d5d-630871bf3707,3210805460,14380423803169391972 +ca5df9aa-baf9-9ff7-51b0-bff0dda2b76b,1599044919,2356644685510862888 +1fdd075e-a737-f500-a0d4-e12b6d2e9641,1918458217,6749314431782950328 +b18e774a-6a17-8efc-e365-7896af6dc545,3284364304,15353053736071182603 +fa4a234d-a8f3-8c5f-fa73-987616506a93,2498915953,10543060131449964682 +536e4a09-c27b-6452-9d85-9ef465f39076,3494056636,18155647440179106666 +6321bde2-b4fe-2486-11e1-44dcf5a80845,3582202986,10929899634431728121 +40fd4d08-be03-cf11-7763-ff1c35d39cf3,3025403131,793770325850707213 +3e648111-a330-e05c-dfe3-e1d0d3add39d,3060244643,6069655314122879666 +129c66c5-195f-52f2-9e59-4d9de79f54f8,3744839163,1234804558881417728 +2280f361-a433-157c-4477-2ccc3eb6aabb,1826115330,1101455873462969190 +e913c0e8-42bc-dea8-ccbb-ef43bd40f334,473081743,11752008793613624604 +a2077ea1-9533-f2d7-65fa-d990231da279,2616653657,7205976432711009709 +ae41dce9-170f-c74e-bdeb-e397e151c3e1,397698150,10145862011890265677 +c2c3057f-b8c6-9d6a-627b-2e70f4ab559a,2700122201,13510174420647205363 +c1d20d59-0b91-53ca-9583-ad2d7c9b08cf,224968462,15329270839151647835 +677e7f2b-8aa0-23ad-9ad6-74d93823fc82,3103861670,184538232608587042 +a879186c-2eee-4da2-8cff-281c53538692,4183465754,2635936208863001055 +a4cfdd1f-67e5-f95a-95dd-9e3e7124ef20,2781160522,4726564156711827238 +bf417f60-5724-294b-9e25-37161b023b23,1545719333,2687722065610460484 +7aa0423e-7a2d-df07-5ea4-18d9868790f9,4120819848,17434162811485113237 +dc774f31-6275-ecb0-54b0-28ec65c8cc90,885212348,16386089035015301802 +4df12cc9-feb6-6ada-ed4d-1bf1af5f0b36,2689301938,7781170555577441725 +46689602-be97-7a45-ab53-33c6b94b0cac,4164395278,17024222499145599694 +35b498c5-fd07-2581-d2ea-477b62ef86c7,1455659610,12151074270451127422 +c6f44e26-f153-cf6f-b567-9351435673b2,3273520193,13649823910146622207 +0ce07f18-2393-f029-6aca-1c94204b0866,3658957104,8343155080245521948 +c7424846-8d48-5efd-84a8-fe119d230ce0,3155461545,8956821812317511430 +e864fa98-c459-47d4-e1cd-3fe5c743ad7d,4292375077,4687793495698748724 +340ad911-2345-5dcd-cb9f-5cbc3cb5a3de,1482373833,8898865296319992394 +bd85c509-8d29-305a-1829-0111e46dba6a,2853878530,9799546528396423473 +5c7d6e1b-330f-ffd6-ede4-5b30987643e6,2434479615,2851206976834601997 +e212b436-9636-8fca-f98e-8091790ac7d4,3674309184,2806467082826107988 +030c1300-643d-e28a-5fc7-686f863f03d2,1515727402,10922962103203590400 +30ff3b08-1ce9-0eef-3308-b08e4a18719e,3649814611,14425340555417123607 +5a5b63e6-c176-6989-60da-03b46d37447c,1950602984,15641831923978449651 +03a98a1a-d456-ad5f-080c-188cc2aa00fb,209521430,814795053825946877 +18506814-9c76-2b20-57fd-1e6b4a15c0fa,2469939339,8396624057633540533 +cad76ba4-e52d-885f-4798-d2c432ad5dc5,464621347,12065446847335453099 +4f1727e1-58cd-50f4-fe11-0b5ad38b6bb6,2396105313,18220588195611477703 +89ae9bee-12f0-937e-2a87-6b8239cc267e,280741789,13524112486399747668 +9573eb18-024e-f645-7d8a-7633da2022fc,1773819657,11420565302713276065 +aceb0f1e-f4a0-5caf-923d-73152dc433ec,1436044498,15032999593972496127 +da9fb1af-18ff-2fd5-dd9d-efb37e441578,3450778648,3524653648009903631 +10b0d2be-4202-8242-64fe-653ec2e57955,1830927628,13713996915760028431 +bc643f87-c709-f733-fab1-7cd748b446bd,730184124,1347413792212389333 +76f3cf26-1b95-2090-2153-530b75101926,3382323934,12256598008290836475 +21cbe4ac-39fb-af61-0f03-4cd0caf1007e,3817741278,11336782605944941377 +4315dfc5-6499-6ee5-a0fb-0c91e4046662,1990416026,12793654624343103232 +e3e5acb5-1cc8-ef0b-e39b-c06322ad93d2,2221763135,7375231567385402240 +350db7de-6d6b-22b1-4fe6-515dc6f0c77c,1979341311,4441643597509921631 +cb5c4b5f-37d2-177b-d9a2-52f81b9a67b1,3265328492,9927620649708357351 +dc46706d-244c-5be2-6b8f-50e6863f89a8,1833712575,428185464103213599 +25bfad17-26bc-c5ff-c2ce-3674e9590766,2850160706,12731250065961268925 +d0e68d16-e1aa-254f-77d3-9f51e12d51a1,1151927103,10932978211569862064 +ce194b6e-34e6-bb8a-ba5e-62459e12baf2,1395571504,15261426652389059236 +5548956c-8c9e-f927-a394-a22f05fd8a93,2153141591,17104102983962313480 +371fe22b-4a91-7c48-8b06-3817c017208f,3845544299,10940269024989707884 +6ff1ab48-b125-5e9f-846d-4c07018dd640,2707083180,11623220289507585174 +95fdc695-bd36-c7d5-e527-1073498f6eb1,1037455247,3944829015958298751 +134af459-e9f4-b645-18df-be98bfc24f0c,2850635240,8819443328483070922 +ef9c4e2a-4767-b464-320b-569f3400ff41,375371959,12120823009489514308 +be8e5b5e-7bed-ce55-6ba2-5b3a8b08f47c,1888760830,1303132941346309814 +3af5383e-bc60-d725-a6f8-69bdd914b6a9,361251563,10356885399580792764 +00e0fb42-d6af-d533-31de-abe6bb3e6e7a,3512159229,933803314595144417 +969ae40c-3e08-b83c-5b97-5273db0aec14,1313648161,11389258490632533073 +e4b32002-ada6-dc41-af6a-59a9765799ab,1805234138,2432519129972351049 +16a74b89-c60f-a0ba-c591-1e0237c1c12f,3253634273,7557934846192163225 +4d79576f-cea2-594e-83a6-bd8b228fce35,2912893876,6717565859466252608 +2d99dbfd-b652-76a0-8bb7-695e5b413115,1778945600,2866332013672683627 +3db4bba4-61c4-3ac9-5fdf-3b22615c13c5,2599058192,15229360321804657339 +5b4a9246-8b1b-a124-2814-03174d7fc041,145866626,6880596433441283691 +cc0e50f3-4146-1bd4-9233-ec36ee5b1d34,1119057367,15462534050356757214 +e9e72d5d-4bf6-3b0e-700e-6ba212b1cd49,993767433,15541592533330439464 +ae4d3cba-b1f9-fa30-83bb-abee4c026178,3891569941,6553176116934044189 +3248203a-aa68-45e0-c2f9-7fa3492a74db,3724622262,1395743230420506626 +f3e8b497-5ac4-0cdf-69f7-8517e9ed3b70,730747469,3890671848059371303 +03f21172-43f7-a592-1020-fac57be87392,821645839,7380110057886477041 +a9105b88-87db-f784-1f92-1f92cb1ec4ee,1033738678,1424519326209516513 +a278e43c-2afd-a5b3-cfab-2dcfbd13ea3b,174940669,16870422721434556582 +998f4d4b-944d-0d91-a915-9c3c33ef8b51,1483599662,8459943866482797572 +4a11d38a-648d-3bc6-4d3a-0433d25bfe1e,4279550697,1463788456140201965 +63913eaf-50c1-c939-7b40-ed06c873d978,2638844500,958001614613833278 +e40288ba-420f-3eca-ea65-747e283c5805,2723465340,17431971594695024061 +2ffb745c-a246-a885-0abb-3fe9c9bb44d7,3009028382,8458639321225032604 +d84c5055-51a0-5fc3-1882-0ec82e330bd1,1109248636,10094794096948450091 +01f2ac70-ad09-c6ce-7b53-2b3203a2ad0d,1852814102,17239809207646262261 +15b87474-787a-903c-cb96-976353bfd3a5,106158967,7849436950795647673 +b8ecb84f-b45a-dd9e-a6e8-2dfc33a81a4a,2817474282,9268325811079695860 +5d9d33bb-9b0f-a8ba-3da6-14a11323aee4,3738997524,16444581571118829640 +3f015fa8-7a42-d8d3-cab2-c92aa51c90a1,690276500,4185692562891025811 +bca75c11-680d-9273-62d4-c7be092da743,1682013639,11110732240860110162 +6bd5e12e-8079-a06e-ff8f-852c1f114e02,3753039167,14491553518912800413 +a358504a-e4af-a5c2-1a96-f9993fe86280,3204647840,10278693056139699233 +14376f07-a36a-565f-a8d1-4431df321b5d,3847240466,10125972825174633258 +664f6cf0-6553-028e-765e-0d76165c6daf,3819097917,6940193890925812504 +012b5ddb-57b1-a727-ec6a-3f0ee94fc304,1429234806,11399571889044843553 +4aa79fa3-7204-487d-4fff-ebf24f73ecc4,3776935181,3517415554842478545 +3ab0a68f-9a61-d496-e708-dede0bdb1555,4125535701,6548163573781624518 +8b4cb7bd-7913-3e5f-6fee-53d3d285f9a0,3396142561,17435599089737460822 +617d9bbc-7db3-9a76-9799-38fdb6946f4f,3136519114,3096151183532879179 +7b54cd44-790c-688c-f53b-bc0c27d9cc1f,2057355420,16142800722880256418 +4248da47-5f75-6719-37c6-98ebd8e19635,4059589177,11562071919755625116 +f952ac62-fb66-ecd5-209f-8f530f9e9bad,1932309537,6032918044720650924 +f31337d2-c882-afb8-d143-366a2e9da34d,575953812,14397462403033143056 +26d1edc6-136b-915e-56cb-f9ec4777ca25,3812041996,10918129730523250590 +b532e3d3-7508-010c-63e3-19000638ed14,912126139,12233641943375076383 +976299ec-59d8-6527-fc14-059d46a8859f,3942371531,15978867716684747494 +b3f7410a-d648-4536-928f-851c69f9ac02,678817640,14156897124741510308 +28a4fbd8-1025-5646-5ac8-74b74f98446c,1602411147,5145018501280881874 +aa9af9b1-5a70-ee3d-9d5b-99b81dc931bd,944161675,12025922404250227161 +75fc93cc-a111-6fbd-ceff-fcac1335e0fa,1060818265,725064747705708150 +56ea2719-6509-0aa4-d402-c149a793cdef,2269996401,7736033015185792291 +0bc3a642-027c-d551-b1cf-a9cc72dbcedd,3961230970,11754359792284216450 +7d99e36d-c007-94d3-dbf5-2301fe7d2bb5,3941972233,4427798406053023009 +38121c35-6fd2-e77e-95de-293195d04605,741493959,8488763986428687488 +78ac5fbf-80bc-603f-64d6-39558592585d,3131828210,15540351012893019670 +92f56728-3f8f-60fb-2fe8-fe8f1ba17d6f,947653937,11412939054294790519 +0c89418e-2179-7d9f-41f5-4da615e7491d,38742437,8820541958584726050 +97151af3-18dd-7633-c07d-6f8b20e2dc85,1068865241,15268189237978315215 +17e6d07f-6956-3092-9253-ace70047770c,3681396101,17879684305897669179 +223d4f18-ec5e-ce31-8abb-83c3c5357bbd,1701248044,11459347313979827718 +d5f00bc1-eb8d-8555-f2dc-7872d65d3099,286102102,11787346730395216651 +f918abdc-97a9-4230-6b83-82d079d3896a,436437449,17513862906311128790 +52255c63-6823-a7a9-43f3-072836fd3910,859808030,11745734543815932627 +0a70ece1-843c-f3da-169d-fde15e4c485f,3666882070,5433290514821774600 +1f614e98-38b2-1733-ba66-d22368229dc0,2131024278,6691487331719563922 +6c016c28-1330-d986-bda6-93736894a251,1303404265,18384854309424412773 +f5ee4946-0be6-a5d6-2cca-deb494d83bba,1947799319,13169053594402647824 +1b021fa2-8b05-c8fa-0227-97e040dac17c,4188366084,9096706431042362583 +d88e896a-a248-1eeb-e9b0-4ac0b75c04bc,15158010,4200921020133347889 +dc25b74e-5129-0aec-31a9-74c1e063e060,1867045419,3493506843761944118 +6aa8bd2f-39cf-96e1-2fa2-f826eec6c89f,4246899456,14368691828846865750 +296ec5d5-6de3-3f94-eda6-025a51055a06,950772279,8885131243269469997 +3dd3b640-7874-8bd3-5bf0-b53b2b8762f7,38803789,14419294447373381352 +f405f2c4-d9e8-b1e8-f707-81ffdf20f9ad,800404424,7014104904229693745 +eef645d8-a036-a337-b753-7746b9150e63,894636517,132347617555533793 +e51d9120-3f56-ab6f-848b-9e042ba9be24,92255131,15981518861233389918 +ac92c86e-d0c0-b9f4-e1f5-1f8a3a6f091b,274031172,9000137286661223182 +53ee0e0e-fd8f-300d-4f22-6129f2507c7b,3510153229,14833945511369458982 +f21da7d6-9897-e382-9dab-312a74bca830,611101556,920136717987279975 +b481ccd9-6738-38af-c340-e1b94c5a5eae,2714483081,18422121301976733849 +95bcaad9-1268-36d1-f65c-d024a8cce9ec,3817953966,759722222533656468 +232f5bfd-ae2f-b1c3-df1d-3f6f1df5527b,3359877268,5090776812297702926 +13e0f38a-b7f7-9b4e-81bf-ee1c9624d6eb,1056895358,8472003850873447661 +b9897a5f-638e-eee2-0139-cd20269a810f,1564829365,308657606487147506 +f277cf74-5679-b6ac-233b-ddaea24292b3,218911832,11330572785563292467 +4c139998-ee46-6def-6fd9-d6b2f5bc6015,2034083153,17947788755292007853 +932d9e09-9f1d-61da-9997-b2d608d5bb94,1435515982,12886600847008110712 +594ba070-0a3f-871d-307f-fc644e3af3fe,2346635948,17388576265406960898 +0891ce45-b768-4a82-0526-ddae4361a1bc,1408598279,9229391376289070507 +1e6f84eb-2a7d-1a83-1a57-407f755d6c10,3874578679,16936456230531673551 +398ad8b9-6f62-db84-07bd-2a59e0b513bd,668843454,15120772138357662278 +c2ad0769-5837-80d4-018d-40eb03867c91,1584683505,17546836052033448746 +f8a84a3d-2e11-509a-f466-15238b8d19d4,1305293335,8325770835790717679 +c28cba4d-33f8-0bcf-bc63-0915220c5919,3409231045,8526365213056442856 +41cc53be-174b-71d2-f955-6c939586577e,1609289580,5775025551999642547 +e6b9b661-9627-e589-bd36-30fb2e056174,2714487191,2769421942089448022 +02749222-b285-f476-b86a-1ded35b31fd3,2213931564,931980824644077218 +2e250893-8a09-ec47-f128-fd846959816f,1336756706,3461839371317658176 +75197028-bab0-c1a7-b4f9-13b5ac228a82,1992543679,11276663472016814547 +0b2e4be2-0de9-a1f8-da21-a45ec70e4033,773522010,930711159473643301 +2f1e4fdb-91a9-08ff-eb7e-31a126e75b63,1146341746,9537179397913427404 +ec7c66f8-28d2-f674-8b99-7200ede9500d,3730409339,3325305319743798916 +e5a31a0f-57a5-552e-b5bc-7ffcd2cf71e4,2667539477,5024139610660894066 +fedf0979-8073-b761-689e-f7c61319f56b,1083984018,10538776132616351225 +f44fc9eb-b59b-1843-6d4d-51def24ed899,120536282,7359687351025634596 +27878c06-7266-15d6-0bd6-990615b944e3,4039144032,6805817469292964724 +4fa1ed4e-9508-b80e-e53a-0d2a7e7072f8,3425035803,6726729613534373188 +dd8594a7-bd2b-a39e-9564-968e12d347fa,765676370,1853042178817230240 +18759e92-d588-a1c2-9421-86c60382cfe9,2856630798,10435789719960946106 +6e5a5d38-1789-0c97-b6da-f2c4d4f54161,2347730357,8742467445199548285 +85334b84-ca65-2b6f-00aa-05ea3559c0c7,223037550,7221890505705111945 +abd0b5cc-77eb-811b-f38b-83a358fed08d,168385834,6979229511104190833 +aaadae23-1778-96f3-37a2-b9c397436299,439527029,3573428836896273279 +c7a6a2d4-e3b4-ca6e-cf90-7142e9e7077a,4156099507,12465836350074912513 +ea7114a8-2407-ceb9-265a-688ba31a3d84,855494088,10751992702676826451 +8771b8f4-63f6-edb2-f587-0fc04e9efcef,2824213166,12075679629798155371 +dac2f385-4c8c-642c-eb90-3efc900f4f80,742074246,18221303695194972760 +2b2de270-c693-d4a1-2763-5a4ab23a9f39,2710391103,13778257781847993257 +f2c20073-c1a0-190d-d9b9-be94b2c58b63,434232861,2812143274527742575 +382d8626-ca85-b9d5-5647-d08562952096,3101629803,3574302650244215242 +edfecd5a-6abb-5679-c3e5-23861f8800be,3998665839,8714975094337796269 +9e870e95-bfa7-abd4-2be0-06c4722f4293,3697098630,14727511847843646541 +be7f12c1-7e42-b181-98ad-038ed0034b4a,1674079702,12331857989474974273 +2b27626e-70d0-e13a-5542-8d78cc10cfa3,1736445835,16504785692306696984 +a9911e12-920b-d536-2074-89e469a88448,1886277304,6332893869055281631 +8f0d23dc-d69f-a32d-e39a-9de7e322dd7e,1085600410,11698332991227836115 +5fe78725-0ea3-10b3-a515-b6f6d118572c,2140510340,6738533017807652436 +aa9b54e3-cf5a-b7b9-60b1-5338e4ad5e39,3288863219,11423858663081848932 +116c7c76-0529-7202-e2a4-1f7cc3528150,1406282731,14783364500943691336 +87ec317e-e57a-08e8-2566-2061e35b4560,1337289336,9206717088051620960 +3338d20f-c425-1917-0144-4817c6e66a9a,3720612328,3864495478518003073 +d28f925e-2ed6-f74f-88d4-c7eacd4514a9,1303764152,12581804834983670625 +6ae28899-ed64-aa99-bc79-5c834f15a86f,4015104409,16796322089633974416 +82fcf455-7ade-1a58-6d8f-981741c39478,2661411760,5024599740489834490 +727adfe9-8f41-b1c2-6ddd-719174f9d0fd,3496238258,5855930566063655345 +90ce8c3e-87fd-be3f-474b-7edf427b659c,2114440406,10897491375023507395 +456c3e36-3598-f8c1-678c-554cdae9284a,1914459469,5396414357812739769 +ba386409-6d62-3683-70b6-790747de00c8,3825179115,2058297591586459083 +ac9c7733-9609-7a77-e3e8-400703412365,1736133990,691812420592433581 +7e06a39b-8bc0-1df6-3df8-cf79a458fe4a,3672297030,17699661904931054611 +4186b127-36f2-3e5a-321e-93ac7b848770,3627056145,16219763813131688557 +609b20c0-7e21-e672-10c3-cedef83431dd,3636687085,15019491963191053307 +9d3581ab-add7-b44b-c224-63faed299b5d,893297573,15285194029757722489 +f1667757-90fb-f197-1747-5f2ffb181f3b,3146259287,14166697143623523557 +111880c2-1e77-d393-cba6-09f00ba33585,2295101013,188129558239327689 +ee17aa26-cf19-f6ea-3da1-2a36876466b0,1140307474,1577784275784011123 +e88b77f2-4a7f-ef4a-cc91-7b7bc7f44bbe,2700548745,9924403691966059722 +0844152c-0a47-4406-1475-f7671a85f7e0,957297153,8551232005250675088 +86459034-81dc-9ac9-0d94-85028b4c0b8e,1746455992,7589580214792598249 +90d95c7b-f803-3f6e-330e-19fa7b688f10,3645307111,15774441038869487472 +dcfa3e22-9c86-43f4-8f42-0a6c880f0b46,1405590711,1894232030217030917 +be402a56-4e7b-2d1e-6bf6-24d0fa51b687,764741579,3806384122355149101 +78f34978-e938-ca7f-ca0a-c19154aa9039,204729122,7421108332092029040 +0156c724-e065-23ef-fc36-542d6271ec20,807570208,15696098764744238796 +6eb4870d-ee4b-9a7c-a89c-ef24da7fda37,2241484859,5453931635431119217 +34de1fd6-b124-9d60-6576-05562ec96c1e,2196131840,14931766493503802513 +d4d3a791-d545-ef1f-37b6-a2d36d7579aa,2209019700,9373393965209121655 +2080bc77-dfad-e387-7c1e-58c52818f236,500767155,16012864425157306928 +3d835334-e175-19dc-0394-08e210d65f0d,3968536570,15060954935064613497 +e93ab39b-c5c6-7dd7-8da9-c9e3ec79b4f9,3142642103,11344716804023041511 +b210ef66-2040-51b8-f288-016c63107d43,161405562,11146674318132447217 +1707795b-90a7-c768-7e57-187631def87a,379503145,1283050992554604134 +3491b8cd-967a-26e6-a52c-5ceaf88c0654,2851870839,12752157977207921340 +986c98f9-b62b-beb5-564e-fd8da0e043ea,3985954956,11023580560190042661 +20564150-7476-2fa8-194a-faa7820b69e8,3389012758,5815275338871851796 +d79833b7-3e91-f916-d89f-b70df6c93a2d,1853722226,11789712496936340609 +e018ecb5-79cd-afac-fdc3-a87e1422b8af,2725090328,16363409315690472957 +232c352e-b680-3e08-cac1-e7ae6dc4b7e6,379729144,9873043167208829163 +73045216-d82d-eae3-9dc1-b450581c5820,1234125242,2770687925515306281 +61d82fbb-03f8-258b-ad55-ccd69a8e643d,3468294714,13647241353060342608 +6af93d66-9f61-7858-2753-dd877a995136,1776014368,6904938807707805033 +0061e0bd-249d-3bb8-d39d-e051a88255cf,1579914694,6056550262750088658 +a9ce86f8-f51f-23af-e2e2-7d280850abb6,2824940656,2972941913340014780 +3b151284-dea3-288a-a1be-8783f88a4425,3475842710,10732832076719751598 +06acd548-54ad-833c-6660-1c2e524396b1,870415615,18306101414301946661 +fa16fd9e-4757-544f-d3af-bdd21b03de40,845443283,13705926744482952751 +c75e7980-b974-7817-eb47-20b90cdc9098,4201257145,13027228100503345195 +c9acda30-386c-59a3-5bd1-83fca085e7fd,3693457726,644221217494037086 +d960a62f-3367-2f44-f2d1-f74c08c7763f,3739250832,11885537686094933400 +4d82d738-228d-30b0-4e4c-0d8d9ae0689e,3415506986,10528154486635510151 +ae07b038-d21b-ac53-4f0b-df185df1eed1,365796366,7301359801562431434 +87e836cd-bba3-4809-747c-dd103320a7e0,392620382,2025385338492103706 +55aebbfc-0699-75c8-d53e-5118fa353eb0,456276037,17574422680240349658 +86015482-db44-a9c2-d2ef-940bd766df38,3364645918,14573013657410832506 +a4f2709a-950d-3659-b1dd-2af03562b481,483426356,5420081283077793850 +5a6a788e-f337-bae4-df95-4fa6e764e830,385349526,4214551394913009528 +d31ab75a-723e-0a14-9971-ea4512d75f73,51766107,17988551999872932882 +68b942e1-b8a2-15d6-2d60-26d9b50ee8a0,2569525672,3028733955748948525 +d8015d2e-7a12-9e45-e39b-ffdd9d4e222b,1656853339,14668616929565325700 +a72aef5f-11ab-b176-a99e-41c02437a153,299901285,6187614847178968085 +abad9a17-5638-c0b1-3d27-ca8eb7c35be4,2722978516,9715378083584794205 +b0b7118f-e4c2-9186-bc14-68bafc6c0756,2267188483,4856617486755762714 +127060db-2771-a006-f2f1-ce7ba47f6614,3856378065,13950922339705332492 +a3e95698-de91-0fee-6370-9c6316ba4b97,167020262,870935579042230355 +b153a5c7-2a39-2b63-9316-3c29d21b72af,2111068489,8064898457532835967 +02a7de2b-d03c-7931-01a2-1a50f1d337df,4059331619,5847101610638165384 +e6f6a92a-2562-361f-ab1c-cab96d5db05b,1690548571,9888734499062577982 +31b11311-f0c9-bed0-8f66-adfc74006e08,957161712,9374800910324760694 +b461ac2d-4bc7-4e85-d111-874395314367,1583435102,14736949406118669229 +140ae276-e684-a212-1cae-923fc7127767,659027254,3624348005702920622 +73588242-1d43-60a7-3952-3c137b31f38e,3369584419,1570931921778732927 +d3c0c356-43bb-081e-6813-091eb10fd4d8,2712415452,4480279891650075621 +5c8449a3-fcef-6f91-3258-d5c71520d37e,3657104927,7339562039217857585 +0e36e595-9386-60ab-3c68-e39d2bd85005,3678130520,13531542845950217173 +ddb173e8-6ec0-0c95-208f-522aff353db1,3125692093,1098427452298468220 +2a65ab9e-7223-160d-0926-f1d3a909e173,818125161,4024614496838609828 +4bb99aa9-2640-247c-1cb5-043d579b8f7c,2745461079,13704478207812862410 +ba0cee22-080c-c3da-3f71-e8b5ebf0e33f,4112874287,9949813229055806299 +caee0f0f-acd7-5b6e-4d67-29f38dd8bc17,2227924736,13624020932465769823 +a88fb0e0-dc21-fa6f-80a3-a0b0a0ae5a88,1422343473,12348553753772177617 +b29972d6-bbc5-9dd5-efa2-650d242954e7,4156848872,334215187267111234 +03c2cb4f-b97b-8d37-f00d-30d56911bcfe,3739546364,7922519345903615828 +084320b7-c62f-e68a-848b-8f0c5e337614,2749449506,10472799866978375801 +a1490b72-bca5-409f-d9bd-3601190588ff,3266103912,8094795926430947565 +76ee53af-c0ff-ef2f-4bc7-8fcec2af7b11,1108154729,17514630686061304207 +67fe21b3-1be5-b2fd-dcc2-6bdba56e1cc6,4222423165,9780352863318645733 +e8c7fd53-6e8b-57b3-e136-d824d710ce52,476670031,15872004695726123448 +ed05616f-e706-4854-dda2-24ceb3a53255,267759139,1921579470330492157 +ffbe723e-896f-5ca3-3c02-81f3db4e3ff1,1382308493,8039438505694973400 +3a2bb960-7d81-2fb2-3415-b2f851ef235a,1756500620,5566437370509890868 +d6ca3786-1078-2da7-0c7f-d6bef691f6a6,3977766051,18039067934697588693 +e90bae57-7252-3cef-a9a5-492c7efa0581,2416133995,14829100285354020250 +82d6b483-71cc-f7cc-5197-365e78c6e7ab,2768702102,13364079932388710706 +323ac3a7-000b-cf92-2bc1-86b8f0e970c4,3425535740,7633045036844695373 +5b1e5d60-f472-e787-2995-d0a8865a862f,3175639449,12260377664437052566 +a4383333-f51e-1186-cd8c-cf8de1163dfc,2154328556,6839161782790987018 +b3b3f5c0-5f98-9061-b98a-92ea3de7d651,3776588203,4969051260656149745 +e57f4272-1d92-6af5-6170-16a0b1ba4742,4261281202,9743163314343660434 +70774805-fd6d-1713-12e1-e43d6cab308b,2881556482,12382393072678014443 +0527bf57-7831-e54f-d46a-b746519911bf,2806388479,3016905067439994053 +42628eab-1de4-e581-fc68-c85f37c18b0b,2205691939,17336177853995018536 +a0676b04-464f-def8-d55d-c9e5cecbfb64,3477131063,8650046348123730203 +9c1bf4d1-1d66-9721-73f7-7cdfd8fc0611,113650412,6357036629533752245 +489c1721-680d-a5b0-4c9f-0b7d48d7152d,1774885155,7135469457593732095 +b3935d0a-36bd-e30d-2282-bc4e03f0343c,3433266336,391812421596007411 +4c26b7bb-ae02-4eaa-6c46-827088fea47c,2220122072,462147139740005741 +f3169c6d-d155-1fe1-8772-6e6dd97c7051,1261676747,14938871935395447814 +6df5ef5a-aa15-a35a-7ebf-642f0d900197,4023417802,10234213386866311446 +118a18cb-5928-ba44-409b-3be63659d316,1382732681,7080073099444400373 +f7ab3b74-3527-ba84-fe94-52222e4cf945,2380131244,13252502334582721169 +e3cd1ef6-5840-9877-d0d8-1e87e9fc857f,252278434,6803187350263872672 +2046f380-aa25-0844-246b-419f3fdc0c91,383817809,8698033087457151099 +8d3a2944-d134-a366-a121-5060d9825deb,442653443,6653806389056870323 +2f9c8a13-6419-ae54-eb83-4d18ac695b71,3781790513,12038904346539997932 +baf4e9e5-b138-4dbf-a1ac-a1729e6b5992,2851512277,7974754882517933130 +809cdc63-83eb-16dc-1b35-c89847ee6e41,2149192073,13296904944613810914 +438db9cd-3d8a-b51c-9a13-70c9a79ddb9c,1810772228,1872391856267407075 +a00b2aef-541b-e327-c2c3-413eb17a0384,3621868574,13334273904481383486 +12144b5f-4ed2-a95b-67b5-b3ed1811eecf,1255557198,4328628153905407752 +6fd0667f-5ef9-70e2-4b48-ff90efa25818,2849607869,9659706499751308155 +975763db-7157-6c33-cada-5f76aefec41f,1441016749,14933665568586372485 +c2664d67-00b6-a97c-35de-ce3f8e64874b,144559624,4002418836008844745 +c58848fb-29a0-e759-f3ab-3b8f9300506a,3347479713,11619878019189727901 +2d3a4ebd-b9c7-fa02-7d31-101ac037e21a,3902714262,1447136482313539936 +1af8e34d-57bb-145b-3e3f-d529efc5c48f,4107750315,16186876339803131118 +2a0363e0-2bd1-3936-ec32-b77f15225ff4,4193737124,6439362271627938389 +eff9b0ae-b329-7fc1-6018-89dd239538d5,1639484630,16355991047142669078 +4f32d8d9-050c-fe7b-3da1-1fd275d3034c,266160079,11373090793005416059 +358f475d-0ee2-c1c3-fea3-001eba1b9ea1,1982441347,1730698880426609400 +211d5b9e-5033-bb12-8596-1d32f0e04775,2094601242,3694745007456927382 +9354ab19-e53a-4405-e676-fc356f88c041,319290853,275784940022434239 +ce85ddb8-feef-64d1-0acc-b57c51847a78,1029996292,11244692298842349178 +18eb8b5c-bae4-4e2b-7be1-9f133ef62ba5,920718878,4103942603730879386 +7b240d3d-d418-c8de-65d8-1ca992288b32,1332349839,1133974504561707846 +8265fb5e-b941-da20-1957-4da85f4d17fb,52034351,5401801592043490298 +d605412a-c023-437b-d469-d9136306a774,1940461029,3394608342004163685 +69bd5805-d0c5-29da-a8ca-5c27f0e2f94b,2595986031,1801460603231132290 +e4c68341-f016-0b26-1572-c7590948f2e3,668997237,13749307046152286845 +5f905e48-e6f7-9dd2-0a21-ded05abd8ed0,4096405508,13279813812022454358 +5cd7a095-6ebf-b73a-da3b-fa683075bac6,2105210595,526080090740035553 +9961f17b-07d8-4009-3977-50156ae43df3,2999458877,11579877051951439341 +5d63aefd-a4c0-c7ea-6d02-3c6cfd607b4e,2628814659,5834862844001997897 +6b57c1cc-7bb8-d0f0-2de3-d912c2003179,3201658715,17193224522725331028 +2b574264-c62e-3da8-c659-b4f27a1a1e18,901803126,12580295249774550945 +aeb2a1b9-6365-373c-72d9-d954e5ba6bf5,4000675839,5366088685709620157 +2037b857-9877-5e98-76a4-fc738efb6dea,2104424776,16481453698383873915 +b59695e0-819b-97d9-d476-ab274cbada1e,681140010,12353715187318451198 +555e1d02-b0ef-c8cc-4966-eedcbf6721eb,52085234,3144061184987881087 +e542425d-672d-b3c9-ac8e-9ea18044c9e7,2656697539,15500475674272365037 +acb805bb-7b5f-fdb3-3793-bd07f927b957,165604693,12203046280955016945 +9f6a5b8c-4869-fd31-e4ad-46cbf63f7af1,2179122494,10890414033788910168 +0e0e245a-6ee4-1858-4bb2-b44d9f12ccbd,3460161182,1332384691771230381 +632019a6-dbe1-2bed-b5a5-d2a3e65c4210,3225514410,11901323458138938098 +a1849c50-7fc7-85f6-7189-06e70c8f58b4,1015486313,16620295138577735516 +a9634793-da6b-c6d8-3226-fe690325446d,1535331173,722237665754911367 +e289e375-ae64-49ad-e77a-0833025da3a1,838539427,10697933257962309996 +137115be-a626-9e91-6dad-8f12dab951b8,1336901307,2671340924497647533 +f4a70973-b6ae-4533-842a-d611811d01d8,71506733,12010879987821193805 +abb6105a-cc9a-e0d4-4d31-c4f633968764,1831503922,16036442847406278745 +6b7a5b62-8f4c-7037-acb6-7f35fd77018f,3042043029,3266170341306124168 +fa2dcb9d-d47b-af92-afe0-be0fa347afe8,3737895739,1861371723074016701 +44c5e3f6-8f92-f675-fd49-4cd6403c0d83,2494584391,896096604193810523 +806f12a4-363a-ac88-b148-eb0aaabb2f08,660764395,16985045547848902156 +3af39677-7a3a-68c6-6b01-ea92a1872a25,1909610952,1324317922222569951 +92790221-19e1-6557-2d1e-9d492a6d25da,3239287407,10056431828088990889 +4910acd6-fda0-ed43-d090-dec448893bbf,941831404,1466338339360880404 +b5781e38-af72-9a4b-ebbe-a182f7b432ff,891295249,315626317278570704 +13ab40f2-f79b-21af-d8e8-70af355efb0b,3701395631,2456972414968524283 +efeeae83-bae8-335d-0da4-e64203c41b71,1548733497,9210570712128503685 +0aee4a88-31bd-2a3b-c8b4-92a8fd864dd5,4074657083,3090637287880582856 +54db9fca-8e86-138e-7363-d544b613c064,3369782154,11208821903573638058 +2a209ee8-319f-1a97-dd05-f9501a951e83,4130876947,15413452378218496234 +eefe862f-24dd-32f7-d8ae-5feb2a206eae,3569296583,18208224028783915118 +42f1a79e-4661-79b4-d2cd-acdc0b52145c,903179567,4023254594214721876 +33fd3ce1-5633-20ea-6b96-49e4f54b98ae,2982398158,13580064043766071167 +378ff402-94ce-8343-6069-53b19569f987,1126714807,6907777395174710719 +355a6488-c462-59ef-672c-cfc505ea4a05,4059997957,3659472531547891981 +32c097e0-9dce-3809-0584-573bce828b16,2872605978,14871179772688910291 +c176da10-4fe0-259f-9160-f31fa3a3db2a,3070013146,2255471456028878755 +932a532d-a014-0af3-ba53-68e221652705,2321292635,13923400909985262691 +b979e79e-f3cb-74a0-ab1b-fbd3413b22de,2075342052,4717577168769724982 +33f8b3f7-7a0c-346e-5089-98e65b8a6548,2629738334,9217036001829094120 +2ebbf99e-e9f8-f619-d9d7-3f0ee1d6a928,1352110316,2776059506171211113 +e7ecf0f5-e5a6-1534-a7b3-d49e4693efff,3269262687,11293919452714602674 +38d45130-c10e-a339-0ceb-b4bdea6d22e8,2810894188,7968190863951708798 +7ecf64d3-2f04-5b95-5979-e6b1587c710f,1083171788,7553281965868905945 +5692df97-7d24-8691-b66f-955970832c2d,21849877,15604088746673013743 +034a8652-096f-3ad0-d428-6f533d91646a,3434523097,9133215392001374424 +cbf0cc0f-74b4-4abc-aeff-2e3b75607bb4,2471940108,3950674594256718642 +e2c81079-7144-5601-39b5-ab37f2006fae,942262696,16246689503925161880 +6be171a3-5237-795f-74b6-e7ce5867d892,3713787000,17124377098466663045 +02284406-774e-ceb5-9776-d15bb919d9f9,2563774517,11841047845553376730 +3951d6f9-7db2-f670-84d6-d14385140ab9,2435211446,15047764364941311658 +58858766-5ca5-674d-7296-96d9c5573b5f,1502364519,9217281433207163862 +3bec0fb6-9bad-0b1d-bf0a-d5d4b71e14d9,2688808266,10172798970106028247 +31729aa1-bc80-cb8b-2956-2c60c34f7f1b,3969173992,13017318368232108068 +c1ab19db-c24d-89bd-8e8f-45696b90278d,1792649346,6566091084025890041 +17ae7f02-a991-8a83-2218-23d6286898ca,2273968526,3840686320607407380 +60827e0a-df8c-8334-3ba1-1311e8848b38,86461659,14876729407641033578 +04906082-5deb-dd7e-6fea-e22499348569,3921666946,17467141431947529576 +50120a3c-ae0e-6525-7887-80fb6efa7367,3895367974,17541973409151781611 +a11d6b3b-678b-d481-896f-59b98e27e6f4,1251120794,13250437347762154140 +b3abe6e0-ede2-311b-997b-6706efabbc35,3924926083,14977333789348888773 +c764a20d-f69f-e7c0-36fc-eb8df5a765a1,2519931883,721015383498752575 +701b34d9-a833-73b8-ba19-9c3849a9e111,1290445505,5028298712027692817 +f266029f-f067-3f83-0f6a-0bfe3eb1bed9,4146026313,9567983901306501137 +65625685-01f6-daf9-2365-1f9d840e99ab,3403826024,12141807750813595079 +4b1760f7-2cac-a8d6-e264-b7de5922bef6,1723366272,1752427847081867564 +6f50e496-1887-c5b8-46c7-8e34455f2dc4,3353948020,12111330008699465829 +5bd799b6-9daa-2691-050d-5a231379f7a7,2434177461,11057061372174117868 +ad6d58a7-cdc5-4e8a-99fa-26d176ceba24,1668810847,8415972880402296722 +ec619082-75f9-4721-520d-a971c5575d1d,1046625663,15135386720889647801 +a2bcbea8-51da-a13c-6e40-e5d6b0e5e4b5,4056956805,3303063292971468445 +550b5d94-39bc-200c-3dcd-c520b4f4297a,3515720807,12922360206786475582 +4b093ac9-aa3d-8ea7-e7bd-c4d02a9327b0,264224974,11554527423683669980 +0d2bf380-7159-2238-c7fd-6478363c28c5,3040144879,5760798221653993682 +99ebce54-d398-0c7b-d338-b5042bae2d15,1167746616,7767748475808663005 +05ea0375-311e-8066-f461-01861651997e,2977169726,9013478161164644110 +2be6d614-7c67-b29f-c229-da6fcd5a4a86,123739138,14006891992244435668 +3e951b71-a128-43f2-c90a-e94722514c04,3906367966,10609531538109842561 +7da30dd9-153e-f317-c521-c07b2b9a1f3a,2883140915,12664426923689950672 +97e849b2-48a7-0a1c-10fd-a40b69f828ae,3964810771,16273161734316159210 +d32ac014-24e6-a83a-7f43-36e86163ed93,405975585,5396156363540265074 +a62d49bf-a753-8a61-68fe-1befeefb7be6,2581749937,12968533410951189776 +719445dc-86cb-a129-175a-2ce7bd0c0ee2,4293387345,16319649287873247154 +ff9d0e64-ab67-dbd8-28d1-1e813977ff7d,1865791707,9505484353587239042 +016b3125-315e-0f6b-75fa-2ca0fde9a8bf,805089427,16907193905288956081 +7149d15a-a95e-575f-f984-9559632cbfcb,259470200,16127663187276903073 +c179b321-752b-fecb-d200-42b81eaeee28,2738284298,7928962708190419582 +9a429077-f861-ff4a-c804-559f37f1a4b7,1433560575,4898412124854149231 +ae2c0219-5a5e-2258-7c65-91461c7e86e2,3869639661,8278764490786428359 +2bab3935-262d-c6db-acb8-9fc11fc14745,3353135448,6062911793678804590 +67519d35-beb9-5601-b19a-5559fe5525a4,3275870114,8477526922373589210 +efc82133-3350-325c-7ad1-dba034e622fb,2199875553,2906575561431178500 +f0493278-dabd-98fe-9016-9e3e7b7336ee,3097979716,17704405734003857982 +1cad38f2-62a2-3488-2810-4af811e637d3,562887088,17010539096694566361 +3534ac57-69ee-203b-8289-277407f78977,1205575672,16647994406481456089 +3ff882d9-e845-053a-f633-ea2271b2f76e,1197021473,16262917214652799994 +e1bdce13-24cf-4680-b155-75922278b844,1343755123,5617354549894273990 +ae42531a-9d4e-0ba2-4dca-248a1feff81d,1180398527,9943098151868405493 +f648643d-c6fc-a463-81ec-fb482b7a07c3,2784087650,12589423579904943946 +18fc1eeb-45d6-f380-a3fe-af9551ae633c,2427040930,16746953500607429982 +c6a06e33-f8e0-e6c3-2604-6d5e8c65a4b6,369761707,8227893667187214939 +2d977e94-5a57-097c-ecb5-e194e6c7c335,1378349257,17424990643176208614 +0f81fb7e-450c-df21-2c25-f4d75e107662,1020358686,7355140934943684534 +2112f14d-fb24-9946-5065-fa4b564f0c42,1407012826,4906804691207812653 +8a538fc9-236f-9cc9-6200-ab3bedaf76e1,3551461354,58776466940477847 +3956933c-0574-4e83-e23a-af1fc9d9d1a6,1508979386,10528360708753347337 +8c45f8a0-767e-7498-bfe6-4fdeb07ef55e,3370551113,8393775921647418553 +9c638c52-1da9-ea5a-20db-62d857ff1580,2094472763,7489840643233894158 +1d3dd09d-089e-79b7-a313-c2aabd253ad6,1709928369,14237657399944585337 +b51e9d4f-f962-3b3f-4e86-47f513ff0bed,2618099634,12736344537032652694 +aee9a45f-b81e-2afc-2bb8-3549c9282c01,1347328371,7134059685551454451 +d750578b-01bc-dbb3-361a-d1623a5a638e,2737436661,14519469556699406868 +9d29cbc2-b397-b41d-829c-3d86601258f0,2114358801,8122629931934517627 +4d5e082f-8734-9d81-e172-5b6fa6a5f0aa,2648340148,8269046407228477085 +b0002bcb-f431-46eb-1f0c-dbb7849a286f,1274827688,2594243812447437881 +bfa9a335-0088-0522-ec1e-cdbb19a63d8d,1762549419,8668627237889561609 +92cf50a1-88af-4501-31b0-aac9aedad040,1495600844,13742528641328639202 +73970847-02e9-759e-6eff-8429489d185f,2917897650,1761310319286514764 +f8ce8df3-2aba-eb8a-1182-24132b1fc7dc,628080697,8959918925672930537 +257713ef-7d9d-6137-668f-3207f2c90e36,924358083,6630089946775463630 +0e2f2f6d-1fc3-e023-5287-5a278428c1c3,2156808733,7446184452509705716 +28668788-7f6e-048b-34c4-9751e4c2172a,900308499,8578102163857031720 +4c5e4ca4-1c47-9c5e-bca2-172dfff8a80c,109062743,7023601023602487006 +e5e3b7af-4076-4317-e632-6f7a1fa43618,2223918050,17611134928321079152 +8bf5270f-f73c-49d0-8f94-3f9ae4971781,1444653030,176469504608623446 +88c622c9-3033-f7fb-21cf-d437283b8f71,1324253260,11073935626003438102 +434c0316-8106-fd3d-778f-f7d3af8b2248,1080424017,6818099810142337258 +e129da96-85e7-ffae-6ebd-6fa663a25bfb,3196507792,8208421376161829211 +779edc46-172e-5845-a52f-7c8b29fd3a82,1225935231,9632589310180820665 +d7009ef4-51fc-8bd4-fc4a-2db3e4d84dcd,1894788269,7304829854771003408 +35f3e28c-6729-92fc-e5a2-a9c5396d3809,1362313757,12098639102376506771 +ffdb0a07-89aa-e846-9432-5e8d3a327a3b,64839473,953158252143803645 +96ac16c6-0f35-2513-79bc-c6b5cfd2c5a9,98618757,9406735278724124466 +63523b52-f7c8-a06d-20aa-79bb663a41d4,728732751,8007597226774818507 +60da5b87-9a6a-28d8-4908-bb58b76a31c6,1188243158,3056384792346573928 +c74c6163-d464-c104-9eac-4447b6f3f565,85468370,455562036221366097 +7b206f5d-7544-2024-1615-20a709eec78a,422779298,217871030773846645 +b9995ac9-d38a-aec4-b9b4-c388417df6d8,2061947465,248222250887494672 +460fb1d7-9862-cd8c-1b48-7e2fd51fc8a5,2390359600,3791180880581803802 +c3897ed5-765b-e8e4-b903-35e7455c2f0d,2000563166,12907491100788470068 +60b46c24-08eb-924b-b5a5-d7c9a2fb74f0,3296108426,17838656273788063529 +e832a3df-b453-8fd6-f9a3-33815a4a864a,3946983060,2052580787176578893 +3821d2a2-e122-12d7-3578-c4d9eca51426,1858308881,16072236246096653668 +c9f0879e-45ba-be10-94a5-653be8859e1a,2379692677,12912944750199774169 +56741171-2810-e3b1-8ed3-03be4ed820d4,1981049469,9851199797478365665 +de5edfaa-f36b-7de9-22cc-05d81fe2a8b0,3472553935,6852966562876110568 +6acb640b-b4ee-a9e9-a338-da0ab217d959,2560491472,3581830591717666914 +3754f396-d08a-807c-91c1-ba79015268db,3439851598,7863477191493437064 +1109e64b-87de-28d8-aac9-cc1b0ba0505f,4117563709,4877164943835653385 +ac55768d-046f-1d93-52a7-80abf9fc0461,4203361237,3022824157048853908 +a9e3b526-ea41-d43c-ff74-e826a9b9bad1,1651328445,11256246407209786776 +95bc5d3c-2556-0e08-7018-c49d97d28ef4,708583793,9583793174806845343 +0eb421b6-2d77-e96f-a882-7172cf7736cd,952906829,15436596820424821965 +c26982c2-e075-e0d4-2703-49b5c74e5c7a,4138289274,9623240881340616856 +ec13a8ea-b853-0e5c-7a8e-86e3aca368c1,4182281324,11351733437592790876 +f71302bd-6d98-91bf-a9e1-799a6b1023f3,4274429602,804279574539080346 +fef24cb6-ac87-6d8f-bf9d-dbfa1035ebd9,3197250498,4987769578373073842 +b9be9179-b388-fafb-5d8a-83a091f99aa4,2479021166,9756832846367439469 +6b0de737-4e3d-816f-2675-b4767e125791,2542179815,3027807876721574183 +ae137c6b-dcde-0dee-a298-b22e812198d8,3757722744,4658056808604031025 +423f2ecd-dfa2-29a7-7834-d2a2837bc9d8,2015940587,18118044226309351935 +7e95a5c5-e0ac-4f16-51a6-8e7cfd378c4b,1387370171,14867971348173710359 +5c5b21c6-b993-247e-d046-1337d1013085,2992418580,8614093999941786147 +c879f42f-7fb4-acd7-9bad-90df78e09b7c,787994978,10644773544310010249 +b0d2c2bf-7e13-3952-7729-d6d521fb2f54,4098810568,12770785394662734531 +3a37cd35-f5ee-96b4-7f4e-8eb9dc7c6942,3379846049,10926393280217153222 +01332ecf-1362-c004-22cd-dd2ea3367f6e,3981462830,5586326246676453512 +aa61f596-4796-5576-4533-b855613db0ad,971390006,3492474373669876878 +ce575798-f77b-a673-b864-750be72d61bc,769233930,13613432546449433009 +307fee5d-51e5-478c-0aa0-c2d692ddccf2,3354909433,9115427512131173762 +02d097df-d0ec-851e-cc91-d04f5a767db2,2538799656,7765443436148752545 +ef3770dd-03a0-630a-ceea-b32ec805d128,3111951189,16946616385435003069 +8efedb9d-a4db-e784-b24f-b694ea2fb58d,2821103060,3399099985256014710 +a80fcfd6-ebc0-3a39-065e-c4ffe6a5dab9,2407451036,1775540002752673843 +11ede758-99b1-9d0b-daee-803654858a10,3413767924,5503388123586374543 +728c49f1-ed05-9e52-c754-b825fbf19bb4,781488843,11275152981850282856 +b1927956-8032-22f9-4e8c-ce3fd04219c2,218815793,109055839303954459 +6610d3b8-3745-d27b-3ac6-f8c1aca615a7,1515161062,1337528712062641411 +b6609b53-2a79-cd1a-94cb-ab8d20a8f362,3706208782,5336005727778009737 +2acadfdf-dc1e-602c-ce35-e4478ba7774f,745086849,13489480730193150101 +46d37b48-1a92-91e3-5694-e5b2bb350b92,2486572458,1694390320371201021 +63a96409-04de-ea47-ed4d-c6683f962075,1485994929,11021981220150164121 +723d6d51-836b-435f-3627-03f663e33088,4000095953,5815855344762285505 +9b154d65-283d-7e67-871c-1abca83828a5,1904553692,12806890925457315808 +3b69d211-14f8-fbe5-8568-9d56717838d9,1462025144,4267315464261147038 +a72772e7-b44e-76f5-07b6-862440130562,2053477753,8797803326978920628 +f45e30e8-14ab-1562-2827-ecd6d72be3c1,1215223703,3842557552009489809 +698ba624-9629-3da4-bea6-ad50127c406d,2005232059,4344596044044519877 +538e924a-2ce2-1dd9-691a-303090f33e3c,3449837018,11687492260017386991 +0b423518-ed4b-34dc-419f-9e9f6e52811f,1198933660,9390631037744382325 +b9e1b677-617f-53d0-19f6-956509a50d89,1903680435,15709051115584403379 +539ad353-9959-377a-1453-386c333b3699,3338094897,12456032457863500718 +708de8eb-fcdc-e15f-ca40-7953af7f3fa4,3512834176,11943918861764124149 +e2e817b9-b160-f005-dbc6-a82dcf4ef2e8,2159125859,7167435298199602433 +fc70d8b5-0990-d026-07f7-e3b46df18ba6,1288663937,14476152772238360993 +72e8167d-fe6b-c1d8-bc15-bc5438aeb74a,4288882469,17136592751915094133 +e3bac37b-3b9b-6ed7-1f92-ad7e564e29ad,4103606990,9087854392961527723 +7fad0257-1cd5-519b-e97a-44b6d485d7c6,3053020341,717952062112590802 +8f3bd927-e36c-506c-3797-3545222b45c8,2023812857,5010553209567155300 +59e8c4e6-24b6-214b-be2e-ecc1d017d27c,3965450065,9097571281044686750 +49abe813-7422-7878-620d-296ecbbc8f57,4103353897,12932943711558458377 +916537ab-4aa9-d234-46e5-fe2b11c6d428,2140390619,6451267175740343778 +40598c97-b8fb-c16b-3d74-5f1ab1a32ebd,4136397363,17603123411659882660 +85aa9aef-c2fb-0dff-1db6-63609d82d204,817810087,8895055745783084594 +10e25d60-13ce-a8a6-1627-953c741e3433,548646103,13652166547703999063 +b685a6d1-ca03-902b-535b-ae8108e4068d,2828809939,3284815292366954364 +6a1c0b8e-f3c2-77e6-79f9-65422f6ab39a,1204922839,4058717006083771814 +b4d41a47-210f-0ac9-a23a-4395c7ec34ca,1931824717,323277156965564224 +093fa737-ec2e-0fc0-8dd2-1560e91358d5,645221824,14433317043749452177 +a0330ac1-e157-922d-0953-933076a8ab8b,2427196153,6793711969291471722 +9d0875bc-e3bf-9977-2901-6f867c8d99ae,59243597,2081814338603424417 +37f47645-4357-d7d0-8d5b-76ebeaf7c685,623611464,14381221669269006547 +72b011b3-76da-e728-3076-7125c3d0092e,1780068288,8620649820378197963 +c1ea9373-e55e-e6c4-07f4-872e5465e12f,2417293969,8935355608776141002 +7c0a887b-73a8-ca05-592f-2d16acabb43f,1933426256,10369074623332874305 +ee42a073-ad13-a908-7bc1-0389d738b7ab,1413061138,1582476258511668558 +33c7b28d-bae5-46f3-d572-66639f18ff5c,3731395682,13903804180361930716 +f75081c8-e686-58b0-9288-c1869f2069ff,4182818178,3806341046405205132 +8e8d7633-3ec1-ec36-5d6f-c3c767ab48b4,2967890029,10018722961041868351 +6850f6b0-f3b2-f86c-129b-0b3901158d4e,2658487240,13303406125124696773 +e9abd14b-8ca4-c2bf-10f7-f9ac9fd85041,2767090812,6134944157133900529 +71f80f18-1a47-40d6-ae02-54df99dfc270,1874377725,4857833811272927113 +68543cd6-0dd1-c3da-bb42-69c80473d99c,2268913307,14042083525615236214 +96333a07-9f31-f207-a299-59c41cd88993,929793599,17768162037555302611 +688edd60-64b4-26e6-2224-8846b7cb4aba,3463584904,13589918029367522057 +bfbd97b8-4206-ca15-e77d-321e163a69fc,2125739205,16645552329333220778 +fa1b7884-2b00-e232-3d69-0076ca5da229,3747096324,1157866952828406719 +c683561f-229b-1900-5a0c-ab4ec8a2f261,4195896530,7327756810027637178 +25cc305b-8ff9-6f55-abc2-66667a3b07c6,1172173505,10082632735801687632 +ec02875f-3d74-cf2b-1fba-07f91dcedc07,2165397521,14572368382524747414 +ed2be026-f681-3a76-5757-9b8cdeb7388f,2304348029,18262581545578585435 +f2f4489d-aadb-97c6-d820-6305747c2bcc,3938513260,15559147601072634027 +9e1ca3e6-8a64-0715-4417-4227e2b5c59c,856206679,8028945156134803863 +b6451fd7-0ebb-474b-144e-451ed2c5dbf8,4069114893,14765710111962199574 +bf1dc46c-c789-0cbb-a9cf-849aefaceeff,171416553,994195618051158401 +ce73c27e-349a-07c7-8cf9-4cacad657372,4168479350,4524808483244166629 +e46a4f7f-90c4-02f1-e79e-b1ad20065d79,394382509,16016149908493739245 +ce22050d-db02-412c-b945-1589d88f2bf9,4076926850,29693038812818674 +980489f3-672d-2f51-6330-406e8bae75b6,3363889819,9908888344514138172 +73d25e46-6a19-b7a7-b991-1208ca88753d,495351823,12795919097827121763 +eb61129a-bddf-6afe-efe3-1174a1d004b3,2675596820,15675565922074735082 +7f9df22a-d4fa-02e9-bb77-c00010e97ea8,1901016524,9943241994145429889 +c8e1faf5-ec42-a3f2-d2a5-c58578fabebc,1068250529,2283021478788537282 +756f887f-4bf0-a9d4-8e2d-f6a3d71c876c,651679294,1053265337349201189 +48b054fa-6902-deae-b7f6-453a1fe8ca6a,1932137188,6682754856997046300 +39885fe3-2d4f-f5b2-928a-80a3dfaf42cb,2891332312,5687108756558896259 +5faa9e8e-9f61-7bb7-9d49-6a36cc99333c,616700358,9539421197333300538 +fe7456ae-add9-31ce-3b6a-550fbf01502c,2369400160,5703324600292644530 +baa66749-92e6-c27b-73cc-e92499085c5c,2364761618,7252994988416468421 +e78a3058-a58b-9afe-4daa-794c4a41d956,3282996134,13012800995213230277 +09c0f114-da44-8769-57a1-4e3c2afd5d61,4163222529,16694203677393368262 +a2b23b3a-ce69-de98-ad65-df90c17def4d,1227848634,4822344326598171338 +27d18011-c64f-15b8-bb54-799ddcf54491,2594306423,16937237619166914939 +1ef75e1f-edf1-516f-8c66-a3cd5447684e,266897094,6050342557109532034 +3f79162a-1e01-81c6-8e19-ae6824d8f14e,2946248789,584370940749581409 +152cd77e-40f9-fb5c-1846-40ce0667cd20,1558968499,9172671376230615308 +47025876-57b0-e653-cb28-9414409978db,319863651,9127061434704216770 +babf5d49-1d19-994c-2f97-7f3c50a4bc01,2569203795,14177990140016824759 +cc00d6ac-b75d-a60c-4181-819f08137502,3585841477,13442541984377302980 +133434f3-5540-c4a6-362b-1af66bdc9566,2210242398,15612518426375722213 +13dd0624-0c35-909a-0c76-2ef39229b51d,437717980,11780678974797989472 +e50abee5-f9da-a9da-c174-b590973d9005,1995262154,15777729888550085891 +633672c5-315a-7223-d169-247e4990ae3a,4105905755,3021326152093226123 +98481fbf-d743-9d27-04b3-678f0425faf1,3403547715,11484780862486009403 +67fd6bb8-86b0-6f0e-6546-aa1c49b2bffa,992138934,1227586519335205233 +0f592359-2615-039d-213e-250a0b9dbf84,4165834615,13215139541928406884 +ebedd116-1e70-981c-bfcc-8e7903380163,1907595263,1030554903263218341 +e89e88e6-5665-6eea-64e4-db534c45d8a5,3374502843,6822174493051414890 +961377e7-f972-0164-bb20-ff0548165833,1390348711,14044145922394261137 +8de786fb-5eb7-a648-e89f-88c06c881b1e,2944518420,26962571673901703 +5ee57217-e6fc-f3b5-153d-6dc448b0d28a,2597292733,14858734844252954795 +c11cb288-f249-9d4d-5ef1-111ec83b49f3,3901868085,14422889673380428137 +29102ab7-1c98-885e-cf4c-8e1424fa154c,3450705168,6760073870547895247 +dc9f10c2-294b-bf00-c6e7-c5eca1b2aa49,3098738117,4115246034717257362 +2f7eae68-af43-74f7-fa41-633950f64e08,1196337344,8587271014032595425 +735fc85e-61f0-fbf2-64c7-f09d0aeb87b5,277147833,4929339041800124202 +ea67b245-0a40-3148-78bb-feee9593a366,152115914,10990307563490132966 +8db6246c-81e2-6517-0c49-990c62b5388f,1436545537,6298910967850206027 +6ffe7934-ed02-4981-0c8f-d201335772cd,2988983521,5436721558717744070 +322fddd3-7794-84ee-f07a-a95b31999c86,1943520256,9761435722798406247 +2c93b809-049f-977b-12af-1d279c1e1caa,3149876504,17536852414661240138 +38c08f77-3e56-1b53-276a-56fc100fa243,3068951202,5671285118205906083 +2b09bf01-8409-f2b2-8904-d413e2505e63,2136581047,3110729371086974861 +d4e1a650-4a11-90cc-7b65-c30ce20e29f2,2273251860,10140874725592227683 +55790c31-7a9b-29aa-6758-af0ab2790a65,447667298,5409845352256595766 +650b0d8f-a9c3-40dd-c7b4-a273d2e8397e,3480623151,8429147931375215669 +7766da0f-0a27-e6b4-8c9e-50065c098fcb,3081309993,3810722771719214889 +c5086a02-5170-ae30-c2f3-27c7af7f8ef3,349227848,11076458714133957450 +ccb300c3-da67-8da5-9faa-724fb95f7eac,3887061684,13511731742288874594 +ddaed765-5140-9551-0ced-cc6a315b18e4,2685155503,7286953995759544891 +48936a28-63e4-7645-02fe-9f203f3392a7,415557555,14854477429318951038 +b86a1b85-46b9-25ca-e027-77807dedb47c,1457818511,15179846020486331355 +3c58f3a1-0162-4575-28c3-4e9863f39514,1183065751,18417401904527792071 +05e99c22-1f2f-e4d9-141b-38f8bbc48506,1270105684,6077805107120672677 +365c3a17-52c6-4c4e-f336-49d0e7a294ce,3893653339,4419561178287110365 +420cf154-d95c-579e-1a54-29b272ccffd1,864036821,3668040571678766437 +8f7750bc-b28a-2de7-f5f4-40fd3d95390c,2673225108,6260224182194759760 +f61a61e2-8167-860f-0359-4be66224372e,3330263528,280374323012190817 +0b5b3a0b-490f-11f2-3162-4088a15988c1,545157140,13066609753329579439 +3f47bac0-f796-88ea-d331-207ceb004b5d,2372548855,4009499103544463854 +640ff9c7-a31b-233b-ac92-8031d7104273,4261186266,4963442806063666696 +7acfeea9-1305-612a-15ca-24d0397a2140,4124905723,16455000579368780441 +e565b078-aaf0-3a87-28fb-64bc52a6923c,2631835833,14172866943784738770 +b8018319-dac6-c09b-23e2-13402b45d009,900445396,3191415947544822789 +6f5718d7-c955-08f0-cabf-7ba34e53e2e9,2684737794,12134456939627248440 +8f6677b5-e50b-671c-0b55-d867008ea108,1494842517,2113685420954817274 +910dd72d-7577-1af1-effa-24753274e7a0,1791023472,11426048898105191611 +62c19e86-9211-1b03-47eb-b657d4cc7bc4,2316151368,4000308454203948386 +498a1a8c-1894-b6d7-8d2c-8a50e771c1c9,1101420587,4152713806598574481 +e5f1a677-6b99-4c84-3897-5cfc164229b2,4117713450,3458171168930510736 +0e2cab1d-7fde-ad84-3d2f-9dd57e2c8dfa,2492157934,12425186696751098621 +6329d5de-ba1a-9992-b57b-3cf34dfd81ff,3184865566,3731840637813994096 +c16d240f-431f-fbba-466d-267d00192807,2672384309,2749134206961574376 +33c4995d-624b-1c98-b843-bdc3f34c859f,1818752900,3852116591928332540 +dca70097-eaaa-3304-0aad-765a75a55fa6,1051445243,6567431649852149773 +9110b2cc-77b4-58f4-6ab3-10a58792b79e,85167994,8005301258431518845 +abaaa497-8aca-e2e1-58ae-0b5826a895bd,2441452702,14655558418478888304 +f3b2dee4-7c84-9ded-ecfb-f69a6beea872,291390517,8562341190146906258 +463236dc-7247-19e0-17af-f52d0dc6f87d,1621534976,286429468190818848 +63f0b3b8-5bda-cf1b-61c6-be4fb4726442,4269273342,6126026575821057948 +7dde12eb-567d-d30c-840a-a98b7ef6b09d,973056194,13397857934287510593 +896989fc-b050-e465-fd3f-942c6f1e129f,861348167,2594216014595839869 +802cde2d-f4d5-f059-8d40-8a2c7cb05eab,1979924172,5977466994797053724 +145eaade-ed48-024d-cff7-0f270353bbe8,1199067830,4570351272937397287 +3f77c3f2-005d-13c7-ac07-6c4db015e4d9,2197214547,7563598610190777216 +32dadf9f-ca96-22e3-e4a0-6959db5f8ba2,2241314642,4109486234729848633 +f870422f-3e68-89b1-dadd-fc705271671b,251412181,8276676222836245426 +abae28b3-68a2-b909-fb34-b56faa49ff83,1812512996,6574801936362622813 +5ceaff1f-9d12-bf20-c995-1f4e6bf4d45a,2201977967,2583925201199764142 +2761722a-0948-1cb2-9d25-74af92a61ee4,1815489515,7025505870372424697 +a4db2ac5-1968-5f5a-d904-6685ca043697,3643839798,11570372040379206905 +fccbbc8b-8f5b-31d2-2e43-b17b9148545b,3549698346,3852490623437366585 +fe8b89cd-2f1c-fcc4-efaa-03e72efd7b3b,2998792548,13322824595089207675 +bc87e085-814c-1482-8bf7-0dffd0553ab3,455057994,9238395347188920627 +67fa7fff-4f02-9163-aa2b-bdf96526cf76,1558798225,18427433096371040935 +bc07e8b2-0a1a-d318-bef1-c2f29ff9dcf5,718532738,4388217020689332412 +12a6729a-86e6-7215-cb76-425083509cb8,513394306,10479372218125792053 +a2ba48a6-290b-6a7a-f653-5c919ef76cbb,3277347803,8962382517285974113 +6fbfc719-e2c8-5d6f-3189-76d9b42712c5,1548208192,6649815404315131451 +87bc9ef1-ba0e-788f-792d-81bbbe30a78b,3479428937,16885731705113336113 +59217e7a-3358-b8dd-7be4-de3f8472ab2c,3261094858,2857985078182690216 +e7c5952d-3790-9f8a-7892-8abe81af54aa,1065321220,11160801689078597273 +94992cfc-700a-6c9a-25c2-fb041e641766,4148500784,16593256259746709288 +ef6b17b7-edac-c861-4fea-4d29ce3f96da,3959384475,14464901050551254740 +e7e1e048-59f5-d38b-c37a-239b4af8dfad,4236040450,11442477037594940055 +5d54ef5f-9583-d8da-a729-0cd38944ac4a,148923375,11020916628500083452 +74041b6e-b475-3b12-63f7-f2edefe5b8b1,2794181305,9019762722120709744 +7a633779-011b-2102-349e-0265289f5b01,2196911354,14623969531607109438 +bf88c24a-1069-335e-ec0b-7ce0969d1b1b,2145927818,7706996373887256838 +5c1c949a-32c6-2da1-9e7f-c9a3d5950a34,3620584077,5189955383033623791 +86b3f3f9-0e7c-1c8a-8da3-8befe3e88895,3831721560,13000513321795083189 +87fc5ce2-1f42-c137-6da9-af2a79ffa6a9,2930065226,16633380941811302927 +8f5f6973-3e55-b0bd-b16e-8d20b37fa4e5,1830693979,12191736168791193775 +a6fb9f01-7c57-6b9c-5d74-1aaee531f53e,673220222,5852327605625462233 +cbf9634e-aeb9-d721-0797-adf703916505,1167509889,5329891367018771254 +c038908e-fd4a-0c6d-91f8-bce08304743f,1377527338,6469917094948554761 +7ccccee1-1c08-8195-9e83-196cb15ce3a6,1716385359,1070812019276392051 +e2a6e82d-3b8b-ae80-ed58-f19fbd68d585,3281973498,15837278178184115451 +2c82a86b-4b28-0784-bc0c-d044e5e6b055,3938725019,9953688639343418729 +488887ac-cef9-d299-5b54-be02b722b442,783247663,1752789280399552048 +24b33772-5fe4-6b3b-c71c-cf7e5ea0dd7c,506850615,2171756962813033546 +3921cae8-1a39-eb27-e832-0633e1fdf406,3397263644,15885471777378255947 +bad439fa-4b0b-0400-181f-fce5e5c6fe93,3481726402,1459710949895493179 +dde3ec29-f7df-e55d-13c2-5fcb160c54d2,511332068,6101306906300561549 +3daf01a2-111b-354f-2cb2-4ee48acbc108,1977746431,11860210770300395674 +92df4d3c-64bd-e652-7e25-60fbc8afe047,3384129330,15083545531572978883 +c284471c-5966-6853-4ccf-39d71cb4cf3d,2290207146,13660105245649088016 +b0cad6ce-7037-1683-8d41-81d9d81659e3,2072970891,1485681390596397842 +e8611b6a-f835-8420-51c7-c47583a53c4f,1869236074,14670479064383654544 +63fee61d-0d39-b7de-7d38-0a261b814e27,1871301428,14286521040502755401 +a450da7c-eb4c-a0ff-1a2f-0c3737e5bfe0,3393194832,11890946904361589322 +ae4a5246-0b58-39a9-3b65-d91842ab1d46,2109518354,7232734512615667624 +4c71bf20-8af1-5522-25bc-256ff61b831f,1590062774,16759663660613570539 +aacd0734-6ab6-e3f5-11a9-7f2966348c08,1883478069,11877558420451354680 +ae190e32-87d6-9cad-2bd0-f31f894ea13c,3656156656,4762812740585646205 +868463dd-7130-a075-38ac-75caf8402d9e,816703769,15654324567962989274 +440782a8-ce08-0ade-61c4-18d409ffed3a,3481692290,14427662325301473060 +cb88dac7-454e-5db4-b92f-fd1baa0b3e5d,1863616317,5729653175301309080 +864db60e-f355-9b81-4540-6d895eec33d7,3654821150,12662787143728104140 +4f248e35-4894-66f5-309b-379c1b39ca0d,3891906627,15815939178141640502 +499771e9-9b5a-e0da-c560-84d76e7bfb2c,195624715,11016336810658532982 +47ee7999-8083-e833-8dff-7a1ec27e9ae9,523599146,9999836536315904569 +49e7fe0b-0bc4-08dd-f751-e4c5bb12c133,1129499674,7090710817677993671 +a113eaad-7985-9bde-9094-5048d5dc71c4,1800021156,3587422417911325958 +95e13a8a-7ca5-2d79-628d-b920c610793e,4211882458,2241247252946156487 +3c78653a-0670-7adc-6986-ca60143ab4a4,3460492489,6143916557644888045 +3a2edc82-582a-47c3-9fe6-11e1c2e382ad,724118463,17341798161794486396 +57332472-9e5a-d47b-c2e3-163b51739caa,1751948184,3975087380471020864 +dea2a700-a9d8-174e-6dd7-95387090df38,3136562410,647231668556377192 +850dc0ee-238f-d980-39b2-c6cb73092a72,3529097527,688795322261496230 +4052354f-1d45-6922-32e5-0f76f6670d5f,1758920896,842125571964540319 +e70c8cd5-17e2-81d8-e5f6-dc4d147cf48b,494870105,2999856128797829735 +53162f6b-5fa7-e7e5-da6b-4d444b28fe4c,4152028020,5741462610174408510 +37b4c64b-93d0-f9e2-3b83-19d46246b3c9,2921974391,17280899526856410455 +2712e61d-a7a2-f5a0-489e-2efb3420b1cb,1943595534,7537094107508427704 +d569e832-2f90-db20-3974-c3c49f4c9105,3191386481,3834690253398430986 +b0496710-46fe-8506-025c-7045ed07e7d7,3862710319,11876647423556687223 +a5ed4d44-3650-b8e0-0ca0-e895eec71c75,860845957,777185019677358501 +b6c4d06d-fb12-57b4-4085-926daaf014bc,2087220395,14319193836249960889 +a239e7da-2e98-8c3a-9bb2-241dcb7dbc7e,2521135073,14148677409657077874 +953af078-c2b4-bf5c-1dee-b857e7512579,3435002596,9721087550252165038 +09e21463-5760-6c57-525f-b6bc50dadc48,927461056,1274193349055342287 +50aea60f-cfcf-0bf4-5ca9-dc7dc6940d96,708690767,16496867831498629572 +aebdea61-a613-ee5c-dfd0-017d683b9567,2217555056,3736569697352726741 +6910b84a-18a4-da42-996c-e9a300596544,3231059404,1492904260587424442 +09daef25-0aac-9bc5-0afb-5f21f9f8f900,892271031,17713697639322968209 +b2f05ed6-53b5-b500-8a09-56cbac563bd3,2723215170,16751862059226683647 +4f6ec3cc-0fb2-025c-4c27-87768fcfa695,1530894244,1978832669351703012 +29c306fc-9e10-89c9-5fea-e60e41171a91,744462029,11648711882032120915 +911ea3c0-ef5d-78f2-1314-9e8b0f5769ed,3013322268,6977934630497971609 +c2c6f344-5231-716c-f116-6bb1b388c125,548290282,2079049550494025437 +b7479624-5e81-b1c2-2b22-343ef41a63d5,3122735642,9962499371967506701 +34b75f4f-f28c-a716-3fe5-3864ba3cb56e,1934002675,8203743449681783273 +13ef9ae8-9ae4-f421-9e87-45887c6647ea,4037555401,15393725950834323037 +bbf6d1b2-e06f-10cb-64b1-45640e933987,1288600979,6700512781798970074 +c218aed1-6846-2a98-cd47-563db77eeec5,1642873397,9779324317419798919 +0a42fcb3-37a1-722d-80d7-4979255ebc1b,1073745512,10418007531506438953 +c96a9436-71a2-b629-2bd1-11ac75532742,1964329750,3298748434864056267 +ffd733f6-adf4-e612-e4cd-6280070918fd,251898263,15037577617175628387 +98a3b860-37d5-5117-fd9d-3154e8d3b2a2,2193299010,15397908680072179454 +3f6a4701-e3c2-b710-65b0-2dc43de22b2d,1388495752,13823603633493145050 +8a72ac2e-6400-28b1-f573-70f2386f6851,2143530258,4065675186322103706 +0a5ef500-298a-41b8-cc0a-11feea784339,2863555045,11122622863264646388 +964b93dc-43d3-7887-0e5d-31ad77c281da,2298220785,9373279289810028292 +e6e23a39-7c20-abd2-8382-ff63791e02ed,3975400988,8834539903197506755 +0e2c8c31-cae8-ed32-2966-30941b2fbe6e,1165530281,9106941470728169962 +b1335164-9c19-a903-750b-cc03a585013e,882077830,8950214127188347265 +0f829dd3-adbe-b33c-d195-191ec8237982,254102960,2676357090020882100 +70190121-546c-fd4c-d732-316f037f9970,3094184180,14503130236342100714 +fed54420-76a6-c22f-fef8-b781dd42af8c,3153207075,8586305843660301454 +bed7922c-6b4b-45ce-13fe-ba94c07bfec4,3970902501,15226093048443872679 +e382d888-9938-8b2e-ed2c-5b46d2dd383d,636136826,801164559133166736 +018a1bad-7c70-5fac-0ec5-1a73fe06b0d1,973333046,6440808337004652228 +574124c8-7145-481f-5b74-1a6d47289f86,2370615035,643358004676128490 +710988b7-c33b-9bf5-8ab9-d0ec015bebf3,2305550722,3255165349264385876 +41588741-9e19-7d90-2e42-c9fbd220c8fb,4273307825,7118095485101116935 +cd7626c0-9875-36e6-03a2-70950b155fe4,495730900,4859693178440329721 +21e3bae3-0975-266e-4810-f0b41ebd3b79,2435841559,6325626008599444242 +59c2d2ed-2bdc-4734-7522-e7cbca4b92ce,2695214009,5555918485297116772 +d06a6e72-b0d8-17c5-b9d0-4a92665f1131,389488932,14520236010273926372 +08649cde-a1ec-9aab-be64-82c2ce46453e,4174910751,13382287289056555985 +6f481537-7604-2c6f-4ca0-ca55d0bf8f71,2523820647,4507080672524851200 +2e28e90f-6871-e2a0-6812-639191e751ab,2499465342,5363818403224066540 +0f08b2bc-bceb-d4a5-64bd-aa40b60fab65,1517059652,10171474156888381322 +71f53788-4e63-bfed-860a-ec885416c305,1070235508,5730737969017652739 +818f7b89-4111-a92d-9961-e402c65f2117,560718620,10416744877379493228 +4fcd69a4-fe17-41dd-bcf9-e3e5f5e2db99,3048841680,16698197345778490252 +a6bb3abb-a395-6168-6d78-13f7f8de5fcf,3662902249,2903348135862577233 +aa440c8a-696f-0e6a-7a7a-f2e2fe4712e3,254679766,17586089752026244087 +07c5aa76-4734-b822-67a4-bdd94278e647,3401798259,6207399620734431820 +a4ef7e03-1626-c0ca-9787-95060d82f893,2067558209,11680209966722488742 +e3d758e9-ad78-a8ba-0827-6299d4d3c840,3913972589,9234372960934936831 +772df8bf-6341-3e9b-6611-1367b0497c20,134220513,3531972531242664373 +efa4a4f1-4e3b-0ffc-91a8-01d05cfbcb1d,2365698826,11407541934802985076 +2b14577c-3dc4-a7d6-5e63-e5654f926ddc,2041645276,6258963600747495034 +cb98a971-593d-699b-e2e8-dbeeaa383f56,1019326986,9153146389812305920 +98a08c33-a1f6-3b98-0af4-d23ffb12b6ec,2846150539,12377694792641266147 +9e186046-e5ee-8189-c624-159e6415a75c,432904088,18168881349013678123 +b374ae3a-5713-8cc1-0dab-30cdcceb7338,2971826090,7513964665208342030 +a8f6ed9e-8901-40f0-19d4-ca26602242f7,1060428891,835233186904536747 +42adabfe-f64f-5d43-9778-3d15db360eb8,1119358734,7548503269888657012 +a6ee1289-3258-e299-9540-72f8fcfb3337,1300582648,2050522369337051100 +580289d3-dea8-e8eb-40e0-32c72fd47db1,2203129959,6255071965161471269 +2cd6ccd2-93d9-c531-8ab0-0da0be399862,3299463804,18380694226051476116 +8a407e37-db9e-a1da-2d0b-b7cdb38fa0eb,1882186001,5705965947824220809 +1eada94b-c485-1fb2-d4e5-31d44a6a728b,3898305778,15393643326533219686 +a2c07e31-8cb3-8951-c890-8dd911ace0fd,146597181,5926602824038868632 +4b4b5304-e869-af87-453c-830dd6f40583,1956799085,11780315159481850039 +c755f402-a0c2-1374-1d96-6a5a61651486,2510209495,6716713485004592228 +6aab8f87-904e-f91c-bf2d-9894be94100e,3981592670,2518534684018066853 +148b6fa5-8a00-7af1-3c60-d0838904932c,3974976528,12497305765170272274 +da8f8571-104a-3b47-a624-1b414fff7511,2437601250,9466691894288444495 +2dcf55c3-7be0-6fb6-478c-3ec321e7de05,257494148,16573948551992927798 +333df2c9-575b-10b9-5691-aa4b84b70d50,2886108776,9402851689883580864 +08643643-cba0-9f95-233a-a50057fc1454,3269598481,2021011741448701735 +ab9ba674-7c3d-6147-ad94-05e78665c10a,4031452482,7295039509239033480 +cbdaefbf-e2d5-d689-e8e3-e7b2085aecb8,2710099499,10427846853255503009 +1a7a8058-1a7e-3426-4373-0afb6df3df4b,3159476540,2947564834247340700 +55416ff9-b56c-7189-e7ac-cc060fff242e,227042182,9687052826747661825 +185fe3dc-e223-3401-676d-aa9b83b6f0c3,1122552790,7997165498895010030 +27a833bd-3b39-e643-292e-988a62189d4d,1559358124,9866232842581201473 +63cd4843-0c9f-a261-b3e1-99a7707d94c3,54726525,10907269926430570755 +34a5c4fb-47b0-c216-df03-8a9325f310c9,3767976143,14109318629254844936 +7b051484-e7f9-4074-53f2-1e04991c00c7,3318038902,1331851596992128819 +4718c539-03c3-1c9c-89b9-cade5fb3f1a1,4166745041,4761652387865975138 +f0ab8a6e-e147-eebc-1c71-1d9399df7b9f,1027283626,8582294052581992880 +282db209-f236-6091-02fc-ddd093b323e1,697333978,5920849487145826657 +196a89fe-22fb-1766-a4ac-9ba2813fa090,3371355931,5454547155145894221 +47a65677-31fe-e72c-48ef-ffc4023b8f4d,4125735806,16033962192616835941 +4297c2aa-ab14-d8d4-0e62-c2c0dda4bcdc,2822216143,6944256568732982740 +825d35a5-51ed-0b4b-beb5-f9e8b0f160e6,2098236140,11852566640747139669 +a5cc4913-5464-e984-28bf-d12459a30ecc,2778755812,17715255718779812917 +dcca481c-c0a7-78f6-b4a7-47501c8e21a8,2696746647,9257859967955117974 +d384cf0d-8d1c-b7ea-08d5-5723b5cc815a,2271885603,5963850683184323331 +aa5fd9de-0a8c-411f-4853-8b842e5eb433,3018997405,4630590395609651549 +e0fb4168-7cf0-2b78-bdfb-f9352338393d,1599759973,14230664893301564021 +86e4e1c6-4ebe-65ad-f3b6-62138c2813f0,4220278707,14694083235297362573 +91d0f3c4-b844-066e-e155-8f8c2ff79485,3671866944,13522470735637702432 +b0a002af-158f-9b56-93a9-6c1ff5293175,1072680753,10787055889221296697 +ab273038-6d8e-7c5b-90e2-ed830e58ef52,4231081706,17777455479170595514 +a1153a51-f2ae-395a-a0fd-ba83199d70ce,3179115163,7095913076647609681 +52722a73-94ee-b385-d165-661b82b1a30f,893901926,1513881173354771804 +a2ceda8f-5f97-00f6-5397-b19e5b28cabd,943116751,2997659983031304731 +1c051e32-16e8-b720-c931-8f3dd303bb40,3012473761,17132642150012398576 +6a33a6ec-70f6-f049-ee7b-42cb435856d2,271842010,15313305985599140136 +5b42ce8f-68f9-5e1f-e687-2689a312b879,2682186879,7356584208930223505 +1f549199-3d60-04bf-9026-371d7ed71640,4192349784,366404172746130578 +1f776aa6-122c-7017-5372-914915182196,293871275,17275331283448410122 +f444fbac-a03b-9c21-f328-1f2aafbf916f,3128958830,14515199508350046398 +2990996f-6ded-9dfb-3776-3a5ee09e1857,3228510738,4991209602095545114 +f3edaaa2-b945-b80f-dc7f-c185380e9543,2838999606,4923365682559201556 +1a1d06b5-91ba-29dc-5f79-4a743bd9c724,341789721,16725940927831768593 +0a9fc252-6626-a692-4de7-7b8a7d585e28,2680751050,996093813953049983 +d77e6a73-d60a-b127-338d-c22a4dc4288b,1005169484,795030009395204568 +d4408cc5-52d2-d378-eed9-b07a1dac8b3d,2395762891,18245147582103514954 +8be56655-f2fb-2890-750c-b639e543c13b,1508512102,445006646555616558 +6563fda8-ad32-eca8-6040-5bebaa4994b4,85398755,4927647241074596026 +64b2ab00-88d1-d4db-e837-8a5ff2fac503,1872470303,15340240752477214360 +c4c1b46c-54be-3811-29d1-54bf86a9e92c,1828907283,6173896290623007506 +d94a7e2e-1758-3847-ce60-26da4c2a3c47,3714533402,13537668731085036478 +3dd4673f-c0c5-76b7-98d7-d5d9c5854acf,1203880324,12804686156679975278 +dbe4780a-feef-6833-3154-911a3b46cba5,802920026,12025201042785846089 +868534e6-fd40-3cae-4b0a-7f3dc2df0c3c,522343854,17823667154356226083 +dc13e4a8-af3c-597e-f99d-ea3d1827f901,2957120262,4381297306347073808 +fa208626-2e36-834b-2c85-96126641c903,2372166386,5740669408101299905 +a1e8882a-9036-528e-a3f4-cf60baca110c,1857305831,16544339845329502061 +e77e0ce6-31f2-d286-6258-f4bd26183fc6,3172479139,3058055452435125983 +a06cd472-5ac3-df27-5130-f8005c153b4a,2656407018,7927133599190808780 +01a1adf9-fa8c-e801-123c-3db819659241,2378151545,9473790112964726679 +7891ca06-41e8-2468-12db-3559ec28898e,3476431632,15847405810632114857 +97ddfd8c-65a1-3634-bc4f-0b677c2de6be,3515686818,10942702140722774750 +5920e62a-8f4a-db9b-cf10-b0021ecaace3,1714344754,12699136976130874794 +ec2ab9f0-bf30-e5a2-fa40-2d8997964894,1245636748,14537733416910282068 +e9685784-3202-c52c-7459-9836c62dfccd,2309732016,7216548422824290615 +2e4c6ab7-ba82-358a-a0c5-719e1df76697,4223238087,7265787842125385125 +29607e05-efc9-2953-e3e5-36bf07d6a3e7,2243651704,10154379818493842722 +15fb2f1f-b765-63b8-4239-0c2cff8108ce,3033874076,13752510526306888373 +b1a86e02-15c2-0e27-1877-2eb98613ca9f,3812648343,9397570646889765691 +e1113465-b449-1a31-b853-d1942c123d32,3507814962,6569553449566976010 +1225a684-3e53-9e18-479f-207dc831f7ec,3441625765,12631868130222972340 +40a005c2-3ce4-06f4-713f-99882e337328,404052511,9105604583279574617 +7eed4bbc-6948-7353-2a6f-0c13be106693,2260862891,3796050397350590027 +79bbcab8-248b-75bc-a4a0-7f683674a632,1438846424,6903398713652341382 +60f45444-1863-3aa2-656f-11b23e237e29,813241560,4293687325049354098 +011f08e4-3ce9-f5c1-40fa-18b2a24e4908,3955416614,822990825760256046 +ef1911dc-aa01-af14-6112-abe1098f513f,3383272002,2379023198591492126 +47fddf00-0953-2602-f414-084cb9ea1329,3608672793,2774787401328034137 +f9edeb60-91b8-6e34-278c-f3f13f44a3cc,1222928301,1190095281624297546 +8dd25eed-0ddc-93e5-acf8-7e15d6848392,1510723759,17132257134400683793 +def5e4e5-c4d4-0639-e428-81e1cd3ed90b,4213616256,1511297844014493272 +79957da3-7f0c-add9-3242-74365ae686d1,3923809036,4753323734649602466 +add78d02-911d-3ed5-b14b-20513dbc81af,2116160534,331596539888831817 +3eae0384-363a-bfc4-6ee2-219bbc9810c1,2545247242,1621848032735191052 +615ae8c0-5f59-1255-92eb-fa4e73704333,3921909242,10269793803443573761 +9448a19d-d4b1-9ff8-fd2d-e39e30efa04d,2124799217,17397521323586926708 +4974dd0f-1329-f64b-8f48-93d8ca985b30,4052920134,6191583628948265360 +fff4f6c3-e56b-dbbb-bfb3-2e6ede047671,3525285231,10058857747120359386 +90a6357a-4f57-8791-f925-34f42b78cf62,1822052295,12944440674621261541 +49aed2e6-2a95-1347-d460-9e9a02e42ec0,1965595420,12063809230935011342 +f5c30e0b-ecab-404f-51c5-b2130912eebc,3607104754,1363617857805960353 +4c032d15-6878-7a3a-084d-003ae0bba450,2552502929,13985867444685177283 +48322ac7-1592-3c0b-4d6c-ab2f8386f09c,2086287457,1489706322293457796 +b21e0b0e-60ed-4939-d1f1-681c31d48164,2537732745,2994846130100619094 +264517d9-a835-b1f4-805d-6ad1d506dd2c,2178077418,18056714896362423072 +2998f77e-e334-fdfc-b6a1-e07047c4c28f,2688808981,5610372411106914279 +dd609398-c7c6-a672-8fa1-cee855c31f03,126967906,15433895577159433075 +9bf81166-8984-6a5e-44a5-eab04faedba9,2584202887,13342645404224178051 +9e33dce7-07c3-b463-053e-5af57ff5066a,269711925,13227159149315397922 +36951276-f90b-8482-af16-5cb5d63c3ddf,4105330224,12799651952296520583 +426f610f-7a3a-e31d-7f3e-71a61b024005,490782320,2014959581465334101 +06984942-2608-48cd-e842-69ebc7b82579,2043674636,12564147936133197026 +832e2c00-4c46-c28d-23a9-b57c8f08c6b9,3662295352,11972721053766493614 +621bf36a-7cd4-bddf-c688-82441c7d7a87,315848524,14915243874774003032 +50339d7a-672a-3e0e-34c6-e04632bd00cc,2744424716,16530541793447932674 +78243170-a46a-a85f-e6f8-963115a2296f,3651734775,5887535568651952128 +10817d15-49d8-cda9-9bdc-c7b103a8d0e5,3226582722,7669040167811637956 +19a84b97-fcd5-211a-5edf-70852596d031,580463283,740910569117677575 +471620a5-9ed9-435a-7fa1-4072b920b00a,3943644588,1850860452592736634 +a34f84d1-3c48-e93e-2841-8eb3b6a6cf4a,3338401820,6575133059961371042 +fb382210-a01c-53eb-6f07-ea6289a994b9,2079766259,3247526723005471179 +7f9e9a16-c1ef-01c3-f1c9-eb303a2d9d58,2761414360,10817572029029402319 +756ce2ce-3a46-c161-4e95-2685c85326bb,2296597416,12024993261827233208 +1b0ee098-085e-c57d-7e62-3794de27622e,903963355,10199262123155366164 +b70bd993-f53c-d3c3-5cc7-0f61e8451e82,1154922453,8551469857737738860 +63c39e2c-4a70-9319-a763-347627b2b9e2,2477495608,9036521242022277024 +670b941a-038b-7f4c-15a8-9c48157cd1b1,1629509446,10944721119627989413 +ee68b0dd-d3de-2d40-c11f-e1eb1dc7a264,475069189,2317050228358352007 +0e2feda0-65dd-ef80-b4b4-53ba301974e6,3831797766,14285531051405606605 +3322be41-6d2a-24f4-1df9-037d2642a0df,255322359,9113897513090088645 +f37e092d-dc6d-de01-62eb-591443edcb6f,1774411042,2155499389486234127 +4d3c8f07-b29e-5ae7-d3b7-350348755f64,3614835111,7880525311243819308 +578cdf2b-ba01-2449-99db-3852a67c51e8,746234585,129372648859799615 +ec430b83-3316-5a4d-8dbd-bad41a7825b1,2478359454,14955193885860389915 +267aad50-d615-60b4-e052-078d53e39498,1394791948,1620894722061988571 +7c8ecedd-be17-d0d8-cbc7-9bf95e65cd01,748461845,7152720073723526992 +1d097454-378f-e453-f37f-140d1de47123,2307206270,1945412601619676954 +55a1f197-4bdb-c840-a2e2-bf020933e791,165266340,3596881322044976755 +1c097c5b-3625-f4db-d2d9-12b0242a51fa,3245005981,17575155693655514452 +08c54da9-8a79-60ed-5b9f-e2bd43b1ab61,1042647888,7261179356890557630 +5db2603f-19aa-d5fa-5c21-e93ab5f39a18,470606670,5541808738129772760 +09182624-96f0-7452-e231-3abafb59f5bc,2742699736,3813853871806094463 +cc87261d-88c9-bd4d-40d0-3c61667a42c2,1013386,15972757954044279747 +cc7ea211-ca7e-6692-f9c2-47764de00bdf,3669073985,16310142826600201726 +5e7c3b35-d9ef-6a9a-2d7b-5a2e15d13f52,3497080122,4257601795161330807 +30df10fd-d374-07d0-aa4a-c4593089468d,1833211699,4419736224613214516 +0b068893-0fb0-3b06-1c69-18bfc6c35d87,2976402040,2897208232986192 +bd3f66af-b9a1-0b84-b43a-bfda9f5220e9,420879873,991894041866522290 +cb7a7ede-3e4f-39ef-9121-4d32630b064d,1375059012,15539309183790030225 +dab1880a-4754-d768-52cd-51659b532aa9,1830134185,1223083819496581404 +6bc0cd8d-6a0c-7b38-e93c-c5f43936fb50,3309267279,11762547318998816331 +de59c2d2-a53d-ead8-0ffd-8376107d4a6f,3121389713,8458927347267866582 +bce11899-75c4-792e-3d88-caee05431704,4211959944,16682794538570103062 +20d2d8c3-ac01-d38f-1cd5-2c16224d2a46,2989198526,7678394067371535444 +116afa80-962b-77cf-5d94-1c6dda8608ec,4169481813,11117741341135022478 +e9d9b7ac-49c3-5bdb-8964-0e7026d2e0bd,2956930006,5844631709839401919 +f6621fca-ea20-ce5f-e9eb-25badc29846d,3350118330,3947764027495036525 +34dc68d7-caf8-358c-b0cd-07a0380872c8,2740109682,6891005848745568464 +48fb11c9-dcba-0537-27f3-a07877a8af25,1854953025,13762069858029106169 +84da13cf-619a-d853-aeaa-6ebc1abf9ed1,3189312280,6369971483581259427 +2cda3361-95bb-bdc4-68f7-34a9789f410f,3501239986,2693211966282406687 +174fe635-ceb0-fd62-7209-5cb302f3e560,2179414095,16608506242747016683 +9ca2426c-3d12-60e7-993a-78f540ff490e,3300348909,12345805466614174620 +bd18921e-25c9-8352-b6f6-a7ca01dabfc7,761347698,11677143362366447909 +4d507d37-4ef5-2ccf-a82e-bd5c544b1b37,3727673616,5372676260443567749 +c341caf5-39b0-f724-a056-b792f5795981,2023065195,4549191946041810299 +952110cd-c1ab-c01e-1f45-405e2b7944e2,1613246030,1553105035395441651 +9259e906-fca5-3b1e-9e4f-479bfc5e3efe,2880745767,4670717067736572819 +f13c2a03-fefb-cf13-8bca-a1391d99fb4f,1285498357,9377862316658877422 +3531b608-a64a-8a47-c19c-48392c1d0100,2085326262,18187904753467212065 +30461031-df08-7b26-40a0-875835fcdf16,4118339845,17900595568370633642 +83f59ca4-c92f-d823-530b-80322964a9c4,454930014,3228412022051921708 +fbdd025a-fe0b-4582-17dd-933643d9dd64,2313050362,5921505349938093995 +5601a765-97a0-961a-e787-b8a9f6bd534c,3295375987,13048916246221282662 +053a13e1-653e-75b4-6d76-ea6954dd7e04,1083050583,14691485873912501870 +ec969004-74e1-ad61-230a-8fdfd53e785c,2149240322,13021463511639646258 +178f2cc7-18c0-6da4-d537-d9c112083db2,2596836241,7975280202610258016 +adfead2d-7b15-4c2d-a2e0-25f7b92c7970,1916219103,5783562915285263228 +49e40d8a-baa4-cbdb-b716-d69d273a186e,747881871,4791285508538089260 +ca586a3c-501f-c78c-9b06-541226de492c,1780546234,8434159410945122090 +1c39632d-0bb1-e3f1-3191-b047f2c7721d,3085566197,8401314294463496273 +6dadd14b-a6bf-9f40-35bd-b936776e73d7,3747562856,6670908483890222565 +f9cb7f33-5640-af60-e871-469045115456,2073005626,1006649829471660770 +47a94e54-b419-9bc9-a072-f3eb8a5b04e4,548437580,13342100202176974474 +2e91c4ec-e234-351f-cf7a-d8e8805ceb45,2218672172,8409368678122592659 +65decb64-3583-0b52-dcca-1bc62eada3a1,2288152786,7886674456159160048 +1909ae42-200a-2607-96f4-0d62191bfd50,2478558880,13599025851019905153 +e673eb23-0255-d131-3b14-548c48b9c105,3856480803,17771810441075790151 +7edb528f-66ee-a60e-6d40-a56417a5756f,1193174849,4447018581253340972 +76871d00-a1ab-64f0-0b9d-b52eb1f0d2af,4083530820,13049710725323205076 +1905c122-4587-7905-7793-eac5acaae327,126043603,10355173651272142624 +6ae045a2-973d-8a5b-9e01-bb907479dfd4,2369721222,17244684345483976358 +00d8ecf0-5f1c-bb94-8fb0-c8611b2a93ba,1538692220,14628589762342761605 +d7a44b9d-9928-738c-c899-af3e42436451,2738585999,10838395338387417465 +c7dffd01-e1af-300c-5026-cd2663622292,744828498,7783949008092602522 +1aa48f7c-3718-60a5-52f1-eb56511051f3,1804270860,14976881531990006350 +db8699b7-cf87-2a56-119b-7451a5a68d75,4023313346,1001011473045324323 +981ea1a7-d188-e9bb-9ef5-be2d9497c743,668872255,9859531677797774908 +7b5fcc50-fc4d-1d6c-3c24-442cb29e4acb,3523203659,9832728834416583557 +8c714186-89c6-a198-eab6-25b3bfefe04b,1828929149,13564439311041624666 +7532872d-b037-b6b9-4894-cd5ea6d28d6e,1417521877,6403065888849016856 +05c98546-5067-1735-77e1-9ef2d979cf64,3047268342,5196936573480315957 +5cd61c5f-4572-8898-50a4-0891b38ec7d8,3937118411,15785394899360081748 +2bc8771a-6763-ecae-0a58-143ba00aa73e,2225251514,8371436840734151202 +63416f6e-ea7b-8810-cad3-c08bf813ea26,3504557449,3211694863462127737 +1520ba61-543e-5fe2-29d1-5a9827689484,4247520213,17847977884770960815 +3cd41dde-d784-f957-0ceb-29b82b821537,2111949322,17728205083962428305 +8ec31427-6d21-4874-5550-3ad4f0e113b9,585072721,1289029504497910554 +3f847d2c-43d2-1385-9f30-cead39a79340,2840257943,9017899100065314588 +3bd59985-a611-5f5d-5893-1a267c33fa50,2429114671,14573735793792005443 +2ce2f75b-2e9b-824a-280e-2f96ad5a36e2,1541023664,15755243348707601165 +526c4220-7f47-c9bc-2e27-82d732ef465a,913924949,17948342154050979064 +be611e63-4519-17f7-f693-46cc38cfccba,1874380777,4912452417305178643 +28ea01a4-469b-c291-fad8-238bdda6797b,1296705416,4027042255602052840 +43e293ac-13c2-2499-7d6c-a7976bf6beb5,599359689,2170906296829851873 +c4976e19-ce65-84c9-acef-627d89bc1e93,3861499772,18320247268702027726 +d3871d72-ea7c-22c4-3f9c-d245bac9ec83,1864558247,13159473387334574253 +8bec9335-88d3-1676-7d40-33674bfd48f3,3745316572,4167059829612213071 +8ffe2c71-545a-783a-0cd1-861403300058,3762306327,6069249990544495048 +af6d22a3-ccd4-dc2c-0adc-f2e0f7d9987b,2877423352,12274990933431424840 +ab027373-c294-b31a-cf48-e9f4b05fa7d0,3332817312,8006111219579804874 +c475cda3-2d09-96e1-8d88-3d33efafe0cd,2795374210,15242838729151237310 +e6c52402-a2d4-17ee-9861-d96ea59aa297,2765836085,16440476230842771841 +548dccff-59a1-81b7-a676-ca67d3edc686,2525329335,17178389328318871368 +946d1f09-8042-b43d-5b95-6d9619e79713,3420500934,1041985937153497200 +067ffbd7-97fd-ac74-db3b-1dbad0d93fee,2013455568,9995403304469314383 +0e208a4e-e48a-c523-10e0-ae88d4478539,1563127611,6521767020831593817 +cf40ccd7-3237-5871-c259-f25c7b5dfecf,2698303774,446750653535855690 +9153f7b6-fd05-1293-61bd-9837834f8142,2694923570,7970003588652063727 +f1951bed-6fcd-f48a-4e7e-86adeddc15cb,1195557344,8391204129041061648 +9796564f-a4c7-7b12-1381-fc263663335d,2909342351,16942930284090514092 +896eb464-8c94-60fd-04a5-0ecc2a7ba1f8,2074638602,16068709752369482688 +c37e4e12-9829-8866-b489-89271b4c9d5f,3419679711,5992133618134041630 +b94b8cc9-63af-5317-202c-643e630d1f41,2290774768,1913102590064673609 +4c0ba471-4c8b-6259-8eb9-977ac574d7b1,898026083,4868256868460019396 +7278db88-f5b2-12a3-021f-3af02757b80b,3778040064,6151918477099412832 +781b409a-c53a-1569-82dd-1464e99d5f4c,905690960,7516331065961505926 +99796598-2473-7e2c-a421-82438e5d2755,2590608510,2111821344797504812 +ba7071c9-cee5-10ce-32ec-4120aa12b9a9,523629610,6364839464559953026 +59d823fe-3380-0504-154f-20ebd7ecbadd,1118405972,11273633606695085075 +1d2bf8ac-93ed-837a-09ca-40c7de3655f0,852928848,12189882926240024158 +eb4497ac-ea0d-49ba-af40-5d033f4eb9fa,3235794869,11167143388924757782 +32d5786a-c18b-2f13-c0da-8f826e18e0e3,4276030559,3270438348923981233 +a05561ef-1991-1af9-c9a9-11ec087a4421,2065085921,12152371944883308454 +c3a4a84c-9581-40c7-dc41-3fa829a47477,3583255249,191274882363603237 +07b7f79f-c371-5130-fa64-210edf3840a9,3320680097,15474414069841846111 +c223b650-05f5-bccd-5af4-7cf78aea1720,2471786472,10201212484590933462 +8aa1b261-b7f7-57c0-de3b-b2455bc80e46,3268870353,15974736586764921403 +af6f9837-05fb-e231-80c7-ef7b7c064b54,2657119121,11887130902274703243 +6ef3d7da-16a3-aed0-a6f8-76494caaf1a1,55521506,17937060597150824086 +96db9c78-ee9e-5d47-0efe-d74241ef05fd,544238531,17486260357540824095 +26e8326c-79c4-839c-04dc-dbe6abd2e11b,3359061141,2082710214508898932 +f0ef3287-9137-341f-6ad6-6644eaaae5e6,873706789,16619016487902940366 +30ef32c6-ad01-6c48-a0c4-24db89355721,469422495,2362982996640343548 +b1278fc4-725b-8271-a8ca-954138a597d8,2297905301,7128787530083133538 +5fb367a4-e1dc-d4d7-69a8-8a4e9847f357,419400701,15591411176256357588 +36d9aafb-ae8e-ab49-af7b-bb8c18f35b17,4153832629,4991254392764555097 +8cae0ff5-dfef-2975-060a-3f13764b2180,1006800160,16807802810167161498 +98c1423f-34bf-de6d-03b6-d99db4a341ab,617920594,12962342422136052825 +4aacc21c-3e95-e036-780f-4cd9422034dd,4192244554,14762268346752682792 +922aed50-3404-5f95-e05f-746dcc973929,1227868603,15289261772909278853 +2d7267c4-a1a2-5ec8-996a-7a30a5816827,791582918,16654884109599676419 +2a878d0b-5869-8833-398e-2f348952b670,356589445,7027593889249066802 +ec788fe5-ce2f-d48c-8520-e6f7c526ea9a,924392906,7936607001706232212 +a0fac6a0-cb92-4fed-24d5-608354e6b4b8,1693156093,16854449191026286632 +f864be45-6a4e-86a6-4239-4b5845f57146,1008590771,8780640172190379348 +f38bb600-df1c-ae2a-4185-3d187680e788,2308311795,9859115866129102130 +fa389fd3-3ea0-c25c-b854-a4cd461fdf0d,448434809,15594604558349279417 +d0bf8024-53e2-76e0-e553-1d92d11d0302,882320615,11422671215485796924 +6ba52f4f-bff3-c8c3-efd8-6b45ee365db7,1674115602,13517454417305307417 +53a2324d-dfd9-39b2-5d72-616057613e4e,3927835476,10410007205600270133 +0a715055-c248-ce45-a626-21975fa43e4d,3041771394,10099902380725611909 +6902284e-3fd7-c206-8ddd-6890cdde6294,3582865344,5705560271052990775 +73915b84-0132-f74f-ab9c-fc9ccfe619b5,1026525133,9571328743583686189 +1da1660b-9c42-0dc4-828d-848f5782db2d,4054991503,12564437286086955494 +29fd0379-eed9-8494-3d14-9211836b6f08,303084840,4449958216761978290 +ea74f011-6472-e973-0f46-becc8f1c8b2b,1365891233,2138406035308163135 +35a927ab-025c-2d59-3dfa-d23774a73375,1199016293,10419220605114314489 +29549822-6e26-ec65-193e-c94e96e8ee25,1464010493,17618449724920230906 +3a77d1e2-2412-d3e6-4eb1-932030dce1d4,878460063,157447625523801565 +458341fd-0a25-dcb4-7eac-9b823d08c08d,3167202894,14626472144422738830 +4e113e8f-acef-5ce2-9b1d-7792998b633b,3770051330,11253777969159368539 +f642f975-e63f-4f9f-9137-2a0dd062f85f,1678527073,303136115949769063 +f67d9cb2-41ce-d831-de57-0d87f017d854,2815802993,1686098111992898424 +d62ce96e-cb82-742f-7c7e-6a049b471ccb,2094846784,5446267986041652252 +4d322866-cd26-08ce-2bd1-e2c5171bbf26,3596076386,9536640660515333808 +51affba2-313f-5671-41fd-d40f75710dcb,3290918332,2253446225576056026 +4bba18fb-bbc2-1e38-d459-29b5d2ab3e7c,75384091,17156718415112141859 +81fd795e-921f-e5c1-c1bc-954735709665,2223255834,2552643116144878420 +7f38b600-1a1a-075f-551a-cb782e81c7ad,3161004696,6939370429672612399 +ebe52b07-bd51-9b8b-b0ef-04283a58f327,2622065309,10485039724840098952 +e12aaeb7-370a-167b-3fa0-382581c5637c,2983901114,7948274383025775330 +b4e3dc1a-8db1-ddeb-9992-f9b153282bd6,369123702,8231141666962906572 +60023db4-ba6b-7b37-87f7-e4c4b349ba91,917138879,5409585884070464503 +8557302d-8439-1f62-7b20-ef0188e259ed,1124083897,7244747029465664579 +ca3cc0f8-49ce-e683-4902-dc0d6425f6ca,771896142,975966677409713304 +c8cb23e0-67bf-a861-0f6b-ca351f031510,1815694901,7437115403084881833 +08407c89-1394-9f1c-6b9c-40428a245dae,427498229,631249069072722137 +1b6aa21d-af0f-03fb-bac9-c0d0452bb523,169396900,10794614006584942620 +09a8b5fb-e771-7ed9-4dc9-89db8670e298,3730906116,3860821121702322104 +1e86beff-071a-060e-1e0a-2d08ef77276a,2409561655,11600833306259915723 +40445b0c-2c1a-9eef-eeae-4899ea0add0d,1779369713,3801582601712261088 +bc12d3e1-bd44-f695-a1dc-e8e228872bbd,631831440,4099892287047474061 +7b39ad47-2ac4-e27a-b1a1-c9779b200391,544295141,12030379335838607505 +18a2e411-8e54-b645-0793-a20441c0d762,1844965534,11408524497545933793 +0b440747-fa0b-606e-dda5-5fb3d8199294,2014615539,11804785214989830672 +01777ef2-313e-408c-fcbe-81fd62e117cf,1004685798,2895059686668556779 +eaf96f5f-e89b-3a2b-76a9-a2f1d1d2141f,3982302077,8035814730384670760 +5a00d7ab-31d2-27a9-ea1a-d9bcd27635eb,2074330213,2916685088193867935 +85f38d4a-bf8e-fed8-c39b-205bd751ccb3,3337854313,16604265752219050151 +fdf9fb5b-2eeb-177b-1dfd-36be33af06b8,2324819224,15146583379379205591 +3e2575b3-8b55-b685-1f43-8be979e30c4b,2598336883,1566116281061926972 +9fe757cb-feaf-9318-4cc8-daba2fad12d4,2291898961,4048393036300703621 +8bce947a-7477-2ef7-9a6b-abdced74fb47,1483234184,9448928890699185075 +549e5241-5bca-20dd-dac6-e797057a433d,688984875,2329612230321926206 +8eb8a7e9-196a-60d0-d059-ad7340cf2e8a,2731970827,2025659771262070908 +2be58c97-e9ec-d83d-2249-f25633bb983f,2441470066,5414306568029234073 +5a64d947-7f96-12c6-4a54-1ae0f5f8a5a2,2890449883,17986387861951029955 +a23ecd22-068d-9090-7962-25aafd1d2003,3553082988,2364999809266111904 +7578b628-d61b-5747-c7cf-7ec76dd8b9b9,115913680,15062542760774678150 +8e6c065e-a7f6-19a1-833f-fcb05112fdff,4051062250,4291497030419032208 +1e428648-c76e-8f93-ca42-567dbb2cef26,647119720,10423845068576144862 +de80b8d0-aceb-6bab-85d4-67f0ae5da87f,576168996,9037234023286176463 +c2495558-d52e-7e94-1ade-fe2424f8bb79,2448699089,12229427965916351773 +0d03646f-0b56-f23e-2cc4-a7fa94b55120,1924966156,7773947371994185108 +f4036b9b-7dab-07cc-ce50-a9f058e96fae,82431214,7870866931639009089 +753766bc-63ee-54e4-a57b-20b473730b30,2451491126,1089719117728266043 +7e57bef4-86d7-e8eb-809b-76b47a3b2dd6,3321238064,17409292651136331286 +72db6066-7a73-f83f-cac5-cf949bd4f6a3,3408554480,13635787108022838963 +66423f61-87ea-e71f-90c5-633f5e19b37e,2554920211,5096793107627319575 +b115aed2-f9f7-1168-5c94-9a53aedecbbd,3907892526,13507834148336217008 +7c48cb8a-0cd6-301e-1811-52b58a29b666,3109965767,961736385684220577 +8892d8e1-87c4-ce26-17c1-d528395bdae4,1471989001,2127182582631633493 +3cac3bac-1f81-63ff-6922-5e2e4fb55ae7,1993461991,14566098004610603415 +7f39d7ff-a36a-e284-c365-87c36e16c01d,3365030457,2796454016066279434 +2d6de24a-4f68-0300-4c00-16cd711bc313,3261141713,17042940019398230164 +694af77a-0a82-2531-955a-def8ce69a7ce,839172988,11990670677225024251 +7b2e9f40-ac0c-fe8d-5133-0912b7819407,2120029161,16803096649162885377 +bf111ea6-173c-e004-6363-cacd3ba1b0e4,2287095260,17639450565810076856 +e428fb92-cc68-fd44-703c-78e14601d8eb,2503637378,3883315212081204680 +756b9974-afbb-8b48-8eaf-538954cabaa5,3491569184,1690080893003714025 +4d6140da-7b4d-119b-c034-07339987a052,1455837894,4986977136168522775 +aae1200b-4dbf-9114-8987-af2d1e1fb400,4206366612,9895377078688151560 +8939ba75-deb5-bf1d-ba88-f339df786339,632423052,13022761571142111409 +cdf97b82-cc96-1baa-2f0b-f3d417a33f03,171014153,7595053806651722613 +4bb4d140-b9a6-0137-1392-1db7038ece60,1298645875,16945465670205413597 +1bb07c09-2740-aa2f-ef17-c6b4fa29c09f,2114508966,9193330734935618056 +de666636-7918-9375-8565-fbefedec18f7,2399587547,16775547124527487320 +d83558f1-604c-028c-c2b1-5bfa774f9ef6,757331889,9149507608089890907 +51ff293b-3de9-3c09-c510-8f2c5be60d65,1466993342,17065613850258209441 +b09d1d0d-686d-04fd-62ac-7ece290160d9,1477327185,681953690015762124 +a870073a-a599-976c-76ab-00286831375d,3218374302,14079718650768240960 +d99bffc0-074c-a7f8-8197-76ce65ba52da,895677447,15812010688916877709 +466c2d42-b02a-7087-a08a-d32b30779517,3837108764,2873576582010543164 +686a20a7-8138-fd15-5e77-d6f262527435,1640039790,7594614905707734507 +a66840cf-be2f-6683-b186-4ea44db54323,3987035001,16545858645601795602 +f15b2c84-79ca-e55c-e313-6f5ff50a9cbf,2280140723,14693644427002977840 +bd6570eb-cd19-b83a-6f70-8b989c5493c6,3522263849,6618468050593456135 +6a6c24ff-886e-d280-bef3-86e1ef1b542a,1568698315,8792406380317446816 +19ac12c9-c98d-8ccd-80c0-420f1eeb17de,1102329430,8315768133941241920 +f0dc7da0-3caf-7618-2185-4d36c2e9cd1b,1895045170,7336088335853921392 +0cfb217f-f4b9-fa3b-5398-8d5b96377cb0,2697280285,15134014102864984869 +5f652a07-69a8-0168-0403-304914713b82,243181996,11995421062714107174 +d994928b-2e4f-ebb2-0d9b-0b87180d5c77,441106914,17373011931327149774 +9990ab10-2733-6cf3-45cd-aa6c2c572f09,2799462091,6806248026839654309 +a63cc503-0c7e-9a52-f9db-942f998d6415,1984277854,13125006299556999184 +a4fc2fd4-2f60-1884-001c-892b2a4981b7,3780233172,12731234365948868818 +03bc9fcb-3777-de6b-8cda-06cd12c61a10,4162296180,3442709374581805853 +9263516d-faf8-c648-a8f6-00366ce88b0c,1720509514,7209027179673936454 +54b3bd09-6396-2745-f0f5-cdfbacbb975a,3548990231,138680712776837301 +a87d15f3-0591-9b70-a200-7b135908d063,138930829,17752078915442129673 +106685a8-12ea-a78b-6d10-47d9c1afdaad,296518364,15221366344968332013 +9914de1d-f60b-7b6a-0704-29126161f1b2,3575406553,10965143144054199137 +9bd0cb2f-cffb-9e53-ccca-3f118f0d03b9,3286666969,11824867314185791145 +acfb4110-13bc-a34f-7510-562f36c21ef4,4231702863,6549013836517174228 +99336443-f165-b03f-1b6e-6105d714989b,1179394446,10069832914627389822 +d10db139-9595-c85a-867d-782485d2cf6c,2292198212,7917481824086973844 +fc7f6e07-7155-90e1-bb8c-2f07bdcda36d,2587369483,9090150002976597723 +d4da9801-d497-59a6-88c9-1c16bb5eca6a,395695149,425009235129772218 +d6d69e75-af92-8e79-5023-eb2b55804e78,2087714853,18300666636656623188 +7f0479d4-a819-af22-a66d-3f6e76dd9ee7,1227080633,6064848972681008421 +3dfbb226-6176-4fc9-fc0e-adff42b6a7ab,53539550,15910381044367165620 +4ef8ff33-c378-5fc7-2b2c-4268b315c275,982227106,1196679896700423514 +521e7845-f512-3752-01eb-8109d1a543b0,2808364484,12948025203608228292 +b5537136-568a-5dde-624e-ecbec644a2a4,2850379475,7874931389050476504 +ebf48d61-2136-bfbe-2341-5a6e316bb2ae,4196208438,3441462985420826835 +7efdc56a-6e5f-d2e9-9d3d-0491b698caf8,832839296,3776286137506846861 +626ab25d-7ea6-9a09-abba-1612e0f363a7,2162141783,13511279961772167750 +0af5783f-27a4-8690-ba6b-250435364952,291006638,4171025844137197025 +c66f4418-2957-02aa-bd32-2cc5c64e9123,3994217854,8711575249818805512 +ea5548cc-b8ab-5567-0943-98c435bcb232,2553363786,7445454274117105470 +6a19b45f-dbc1-f582-0eeb-fbdae15240b9,953002143,15500221479748401564 +61035dcb-2046-73a6-a5a9-11be5f3f2007,2085382841,18131441035127778957 +7707d1de-ba51-a778-8912-d293fe3c7c89,3903724255,3539838951129854161 +3da783e7-d031-1b96-0ee9-3518ae5f7f43,736931243,14285395223699032423 +bef37849-aae6-493d-4895-903c7f0c0fbb,534765527,5388707143324063758 +f88259e6-95ba-f749-bd2e-fcfd67d212ad,2050974558,530690936517820058 +e1883958-74a7-d6f8-3231-dd27dbfc28d9,1227514363,12673940762642876149 +59d3e434-6285-f015-d8ea-98bef33f6fbd,1741246126,17942364292652040455 +19184a43-4b3e-7260-a2ee-ae90196e2d1f,4165377616,2498020163358831619 +14a41b43-c7a2-eaa9-d604-7dd5b314d82a,1936401747,9364704187233596553 +43d6adf4-ec26-6860-f2ee-9a115d000521,2613481976,12122673562479605614 +ddfdf076-15ff-5396-69cf-4dac97b00af0,3505432312,6848087996446108183 +c8f6e178-6953-caf4-2942-9a5e4b561b59,3041498493,2441873521533196409 +60e9a706-7ba5-a209-7b06-37f19db0bc77,3026588295,5629504402000127754 +db37daab-fdc5-bca6-de42-4db403234c29,804461661,2543645305959953687 +7bcecdcb-a4e9-0202-ce8c-dde950f637ed,4035675501,8789908641771079931 +8c783393-bd0e-e92e-1f48-118ffa2d3d75,1828316054,4362821144507529950 +435a5f92-2864-15a3-a9ec-fbad698aad05,2539311144,2069690793910178535 +8df52c58-ea29-c57c-fbf5-bd1dbc4c3241,3616404770,1792145188188229282 +2409d8ea-d917-f6dc-5806-b40610ee694b,2611541047,15047560989521097029 +4edb3c1a-e31b-1615-2a03-7bf00bc3191b,3724805114,14043901610288331075 +6230df59-1ce4-9497-f0f1-025614901c5f,2419609513,4518153236369433166 +6b9cb40a-1bac-d10a-0a3c-60a9eb85fd52,2373550051,11182131475115008519 +76444845-71b1-872c-35d8-033d75961076,257190821,15484882431647402562 +190ee926-f2ea-60f0-03c6-309ad7cb4a1c,3203321810,4306098938063255662 +77d96b0d-aa06-4f12-ade7-457bacf70e3f,3190099724,3683858845988348664 +b01988ba-e121-5f97-c194-a0c52d7d929d,2403841538,13818738898637437991 +a6ece93a-4633-0127-e67b-5d473cedeb79,3222696317,12067871058796892086 +af671bd7-cf79-24ce-48ea-e153abaaa694,681440426,12727734571712712082 +6992483c-8f0b-0007-c03c-9065c172128b,3624019251,2371513886804967677 +ae8ea9bc-d093-97da-a708-d9ea93c2d53a,2735470124,16717062171305286958 +c39d915c-4b72-9b12-7d2f-f73000d2c1a3,1059542637,7064957943080931179 +353a6a6f-c895-a32e-88c6-cfbc5b87e227,4107698952,16030860826772920748 +56095cdb-07de-1909-db79-33f5d10686c4,2527223401,14239127694606794222 +6eb965ef-4dc0-3bf3-5b30-2e3a4ad0566e,963258289,4437115097619496766 +117cedf2-19a0-5ec7-f01f-18168ad3da6f,1799567448,2237869767938126249 +8456e939-6622-6208-4e2a-82c7776642ec,579221684,13701718073649236576 +c28a451c-7bd9-4aa1-3bf8-c37ca6179e8e,1481453316,6575417742071118545 +3f8eeaa2-e65f-feda-b528-178a868319bc,466829390,8213336260982899575 +75a49e70-93ca-e69a-1fde-61b2e746c3c3,140171137,2115806116379109822 +e316d938-d58b-540e-0664-7c3911f4de10,1024642305,12189943319357451303 +a44d4be2-7d30-8807-dc76-d239e308f56a,2586402799,1166251746584905561 +8236bdcc-ea19-e032-989b-2302a84ffe74,604971283,17967102167483535641 +3f421431-9576-584f-91eb-1c5a1f057c26,3070921946,1910898221454510146 +8c8c597b-61a9-3dd3-c111-8c4d2936859a,3730892045,2410295358681391198 +140365e1-d5e0-10cc-32b6-52e884130012,3911379638,9778999228719043881 +f773ad65-2099-28b0-d7dc-fe3ac86ea7f7,1934370890,9455433919042388144 +d252931d-8a20-caf8-5eac-4769ae99c6b6,443481414,7284931976953807505 +4bd3b5e6-37a5-4dc6-3148-a18ca3c5deea,1828525394,3854789052168772831 +15fdc0ff-ad5c-e5b2-0932-a7c42a7c5994,2324360570,10325651231271066295 +ab6ee2d9-6beb-cbeb-adb1-a4f0eb9e6b2e,3145477296,16432480176543556865 +9ca5b3dc-ef6d-1d15-34e6-af6f520caa71,2864597065,5715781195717647754 +486c8010-3ac6-e167-ddc0-ce1bc117093b,4271399084,16025108817616395401 +07815150-8268-96b9-0de0-82939005ad39,190330259,15196168059165507766 +0e96c488-e7ba-4afc-6f15-f85b784e65ca,2357272327,17979805648095756931 +e7d2c27b-7aa0-d018-03d4-52fab7a616b8,1719738411,15010615553380529291 +7053edbc-6fdf-7e02-5dc8-928f93f41d7d,1131189606,3028267587168232826 +f4816c87-8f6f-093e-c1d6-6c17099ee25d,2274709979,15934712721652888278 +ede65b27-acbe-657b-c02a-64e0c7d40aae,1080077664,12189459487121025075 +68b65948-7516-e307-f084-c327f86baefe,2686684166,13384579644370006038 +99cb29a2-54a9-a356-5741-2661c54f4fe2,3004626382,12030337297768880892 +b7db2cc5-2d02-f04f-0d07-0efd008e1272,2396577253,8420506614005437667 +59f49660-518f-ab57-3c81-3b054d79fe7d,3582834772,10841043798286925378 +c19697cf-d0a6-4b57-f941-ccdb4cf7b887,1386311613,14405498235931505338 +4a59f458-c9a4-86e8-babd-33909c36fe64,1753882765,6640534698265419425 +9deae0a2-dbdf-5c6a-b80b-0a9fd69122fe,2051984607,14475112317885771603 +85e2c1eb-ab7e-6209-7fe5-8768abf82c08,817115630,8376217056803447699 +b7e71441-f99e-84b4-18dd-d7d958f0d5fa,680427446,12149755568896490017 +91d2724e-61f8-6612-deff-81d8d14bb2dc,2636359495,12677548758714935589 +957db568-75d7-9225-33ce-cf62a3e18b4a,820087538,17868364267019579260 +60582922-3798-24a7-9431-b078ad3bd659,1011099521,2592122366169910277 +e4f47686-7314-851f-6e53-aab60491155f,1576707719,14658725989628289530 +7717fde3-25c8-a14a-9644-d372f28d0329,232219465,690994796242993047 +3f4041d4-361f-2271-27d3-736ecb8d9e30,3243625421,16945545151750410975 +1f17bc77-1264-ae49-4e6a-f0e8337851a7,1196301703,10495754226119180961 +56feccc9-ff25-4458-dc12-37098f57b146,3970103888,13495401858443394751 +17065cd9-0f70-10d7-c5a6-0c5448538916,2004615612,14604711185639375338 +b971fbb3-b08d-672a-821a-2297f062a26d,2545556422,8675944270215523068 +a0c98f28-b81c-0ed3-9710-8fbbc424cb9c,3022770566,3585992044546222660 +c97a80bc-17cf-3849-44ea-e78bbf4f4bec,4150179840,12622778051267315393 +a8c73cd1-4557-61ab-3947-e18030cba798,2096678566,10790459263406151673 +1cbc0186-8d00-f76e-f4bd-a81f67452f7b,1901562414,17227454738994112469 +9c84dcae-eecb-614a-a079-bd59dfd8d784,535034230,11705432572612873167 +50f67042-510f-ebb1-7509-bb835e26cabb,1642216864,14049947881152373049 +6696b858-2701-8634-8458-8841a659b8db,3455601075,17704065262092875651 +b8d007e8-e406-bdeb-37cc-bd319ba95302,681184857,10152211422964171239 +26bc4a77-d339-1d28-bd82-bb707c406dc9,638749210,6849116073641552260 +1033a80b-f060-09b0-76c6-6570cf0c7b41,4257207490,7796518453622074055 +ff7e9a49-cf6e-ca17-1c13-f1b08e9330ac,4022450041,5154185640595269225 +74c1b638-253d-5135-1866-3038ba9f7011,2076792594,574879069129720480 +888811a8-65b4-03b4-32a8-70fae886c616,3694301825,9485440389507924982 +fbca3390-10da-f050-03ae-f104be6ace5c,1658985152,7345873728366147126 +86c88cdd-224a-c093-c1b2-1eebe2f409c6,3282238250,14054991300485281946 +da7a16ca-7cd7-9b22-0dfa-8f21f9ac8025,3418594667,1932628717549317601 +ce453ab8-da6a-62ac-aadf-7d3a3d967340,3477838496,4169697602643500141 +98f39d59-40d1-d8db-94ff-1d4606a9d880,4207979718,4225225658746920220 +814d2fe5-f186-94b3-dc00-9a8ba484f68f,3219831085,16973329252422089482 +de124b2d-880f-5fba-1427-f15d75030035,2878504436,2754993923712528533 +cfdc9c9b-a91a-3dc2-4a36-18f85d76d58e,1967154662,7399177061768321070 +df586865-69d8-6ade-a5d8-b129e4e46327,1039110537,5916809055171645993 +b59551f9-2824-cbe3-bcfa-b68cd2a2168b,1511963298,3930283414455322613 +e205dfb7-93de-71f3-7264-1e0c0ba7702f,3854010911,9932655349910819856 +bfd90d52-09af-aedb-dfab-fb7fe7faba92,1052635748,4388161182256326687 +bb89f6de-5ea0-82f2-3667-606b8816a0d9,1150372432,1616944799619117778 +48d6f5d1-fb90-4662-08db-34664b7e1a41,2799101605,13256926717047093174 +94b37dce-f549-0aa1-1407-29e8faa82c98,3520543925,374270036683540212 +b4ed5b51-1e3d-38d5-2f45-4ee1ccf202b5,2398767848,863162687761146630 +8162cfb2-e317-2870-e189-3b9abcaded1b,1500691670,2081483388595298638 +819993ba-ef56-ce1b-1133-f668614d2df0,1347567467,5297690524204147025 +0ee588ae-784b-24ea-fbac-bd56b76b6d3e,4272651353,3089826234619985444 +bbb38cf1-7eb2-93a0-9caf-4531520ad68a,1850200438,5681424668702121690 +6147c032-def2-385b-2af5-9cca2aa00e30,2201121492,3878847315838349199 +a901b9fd-a3ba-e2a1-8444-be8c78a41cb4,3519122893,13880919150093076831 +070a8a2a-7767-69e7-f536-07eba7af3549,2768968818,12380523631322903841 +ca94716a-eea5-f564-50e8-a8ed1ef9236f,359808159,7267713808151647105 +740b5781-cb97-838d-c27b-68af22400dd2,3457069022,1659021869771241933 +e9dabaca-8e53-d3bf-7316-7dca64cd63ba,2512954573,6927782260724078627 +0f9671de-be39-85bc-0184-f7e6c8f50ac4,2183113732,5082727165245061816 +0195c03e-b4e0-b4aa-5800-5d77d7c5b51d,3098002651,1825351553079544719 +de85083f-5787-e902-57bd-037f99b20674,1417930154,16856641000298658060 +47591d41-8845-1a8f-65e3-a9037b256492,57602053,3224038039534546250 +485175ea-7e47-6d2b-0dcc-ee69012a5a02,852311542,8511046771075616140 +35e1e388-eeae-5f58-fd70-9d270f2dda23,488709196,8320869748888761050 +e147be86-94d9-db7f-a15c-72c701192e92,118489456,5681725699651214945 +0ea4dcb9-fe6d-de43-d9cf-059ec082e55f,1194846514,2348392721699218064 +b0247b44-d16d-1f13-6e4c-5a57d3268f84,1609938029,2956029385667631998 +54691bb6-1299-331d-9b51-494a3d4295d3,3175132728,5859855844120100609 +c09ed204-fe25-ced3-84c7-59edf9fc95c5,2602722842,1838661458159211811 +9b5bf18e-be8b-e010-5080-b83aede15bcb,934368011,3255097848521824494 +6f46c338-e363-32a4-89f7-9581da4c1d6a,3795280933,18076216163391129731 +e8ef550d-860f-4bab-bbd7-09b87a71d95c,4065598654,4426586675733731596 +41cd7d3b-729d-b7cc-be4e-b90b4aed5fc8,388299207,1808896481471083738 +f95ba67a-e61a-0d9a-a0d4-2041f3f65136,391755252,18083420704031757118 +d6be9415-7cd5-dd2c-0c08-007694baf1cd,1194574144,16216288721036828146 +2edd542d-dc3e-a37e-3ca9-f6ec45ab8815,1002668481,17030094338445354014 +52199bc3-115e-064f-22f0-789eddaa2f27,485679676,14780033244741931847 +ec4f6db9-72d5-22fe-4bd4-fbf1cbd399e8,2458709478,11598853455418148112 +4947d9af-d2c9-b6df-ed06-ce7ce8c72825,1703779423,17482957184559412267 +fa376811-bce5-4c60-6174-d61e7cf2ef93,1423549040,9336837604874264930 +06c82d9e-3955-6eca-58e0-d2be43d354d4,4202908265,8195696778116686811 +9c2c2081-6c37-00b0-5a65-6c2a7d69d3b6,1584706761,17000056025347283001 +08b8f220-8036-66b3-2f0b-8f47ebf4b625,907571566,4457888013555301197 +b36d1630-3b86-b167-d095-d9b4893351a0,89011874,16650084409419160877 +a5d9129d-6fa3-bfb8-886d-8a2f824c459c,2209458290,5166422292822024138 +eee65100-a4ca-7a6c-da9b-3e5e32a6c8ea,4275601027,16562270468471561156 +875e5b63-5ab2-140c-1305-16b5aa5084cf,1676566072,17089605393567924991 +9ddfef9f-e9a8-da56-f579-37dbbf741a37,2657360351,12123227938259213497 +6608b9d8-c5a8-4228-8caf-62eb289bcfba,3378902938,1656296166578500469 +fae46119-8166-ebab-3c75-ac93012e69e0,491437828,7816061792010390619 +7fba4890-8a66-28aa-b950-5f5e45a5b1d7,2308724258,11294559838923796877 +07befa49-0777-d4ad-c6a7-464f285c390a,3152898526,8043983596187879508 +d848ea64-29f2-c8e5-ea12-0247ed03faec,4173898001,7113363079860384794 +3fc0d271-c4e8-73a3-364c-9ea77110405b,2317404786,2401593520256823539 +d8788c49-1e8c-1148-2498-f1ed2f7dc334,2788345335,13210833452313447696 +5b80d039-2628-0b54-c8a7-25356fea620f,975978754,10885734085594137693 +d7ed0592-e2cf-079c-3f65-2df1c46bfba5,369580483,18288879639795562093 +d8c0b6c8-bacc-c4a7-b2ca-fe507957401d,3163382190,17565204783337410964 +03ff3fb2-732e-e845-f248-6af6a5b92762,241265058,10504406340801642064 +144a6101-07c6-f9b5-e7dc-07c47514baf2,2719018264,11099943518613906832 +aff7bd2c-6f35-8383-6774-f07cadb810a3,2936809996,8602128627446739390 +6f103df7-4ed6-3421-4479-7be0cfa483d8,2323621704,11597818227972803516 +1988fc45-e263-bc51-7836-af7cd96064cd,1564774979,18044115204548538897 +93d7d174-97d5-2c29-1cce-5f8c82c0f5fc,3437398754,18440558502821519824 +b02a74aa-61c5-dc7b-12fe-5951dd49c295,783930996,876840078906914339 +9fc2bd67-cd42-b88a-8af7-db8bb478e37c,2144888929,3870303328387187050 +3229d04d-4f24-c5a8-e25d-1e9bde4b762c,870009582,2847801716282754384 +e197a767-0343-bad7-5d22-0ba6dfa79bd0,4083506423,3252334974581103927 +911fdfae-4102-4b26-dc6d-8f95262f3cf5,934451267,14294520983400116206 +123e0632-319f-b89d-866c-d9bad949e4b0,2170962679,2341129675616529736 +8fed2811-11eb-ba10-2ff0-f62d3d86ded9,914700440,14225316374185470926 +219aa60a-b4a9-d4c6-d436-de647c13c93a,2947081249,17878789851739801321 +dee8ccf8-38c9-7d18-400a-f2e22a37baee,2616425330,7667963297696318832 +31ad1a98-8625-36f1-25cf-187d65fbcc9c,4040954094,3046948537060079903 +3c305ca8-5a6a-2260-675d-9300ae936c79,406208614,14337694819872076171 +e84d37d6-e6f1-47e4-b4e7-48c390c0ac68,1475780569,1250693179030894672 +2ca9a6c5-6686-112d-b238-656f9e35245b,286071471,1586745283892910816 +e6671cf0-75ae-eee3-684b-d8ace87bedeb,4042171145,12747756609357383749 +0db59205-3c3e-341c-cb1c-a87f1fc528d5,3299406046,2676512952193381781 +96d7983c-92ae-694c-3e72-86426171ce45,3882308473,7907077085485154358 +b5ceadee-dc68-a2ca-2cc1-879f2830510d,3150158720,11347116104985306621 +6a5cc629-f6f9-0c4e-c2be-a811c0e72aa2,918245639,6477903076380710307 +153f44f6-0510-7ed6-1d15-d57b3e883989,2599011752,17028341601741487551 +1d9bdbe8-5b01-1d36-1e27-936232e46c26,2529583513,18134936280516530221 +27b41423-2840-7ab1-866f-a3bd0ea38d35,1150123425,18133778821007256769 +5a475be8-e9ce-260f-35e7-e6f844680cdd,4276975162,12493612164616885951 +a76ecf53-1f9a-993e-d213-25a32314adb7,952431572,15499007756361729693 +6288cc58-8c93-c92d-1330-a6ccfe9d3d8c,20870559,14056560535166858081 +af217563-66e2-bd55-2c22-6ef3ccb36030,961154095,818948847555832436 +472a9122-7a13-08fa-6ea9-617c39bbf241,2728149184,17430190196940579305 +4a8f4ff0-1a6f-c145-289a-c318c147384a,2914778215,7806965865287312377 +10ff3068-bf16-5fc3-a6a6-ae133e15e3c1,1341325406,8761786621629230351 +bfb9646b-1f63-20ef-68e8-ac1f205c661d,2438166317,2308842746109759849 +d2ebe7e0-650d-c3ab-567d-b650bb99987a,908545845,13593642029043197366 +31111294-1918-74d3-d94d-d3eda6e4b956,3653180968,73961352331998445 +fa881486-b2c7-d713-fce7-b667d72949a3,1985520820,6691036271337001983 +3f02e798-02bf-3c92-ccff-cf0d85f2d36d,1663231761,8894539814418835419 +eee5f047-70c3-0abc-7ce4-850aeaf65f9a,3156025784,7553748095328253259 +2aebb3b9-08fb-4118-4ad7-2563e92c4b7c,3942291044,10484734625939192454 +f183b286-5ae9-e0d6-c7e1-dd5ff57aaea7,553602908,1637381444732825849 +f84a5d62-8ebd-7656-4b8e-4faec6af6f3a,3528304346,7720563044347159725 +7dd8b8d8-a778-db17-4b30-966aa7eaf132,1819709270,15917320153633905490 +43516538-d897-3224-fe4c-adab728723d0,4136484641,18276379265569517262 +34722c3c-9ce9-93db-d64a-a08c4e159a35,4182132178,6084663270304157267 +fcab0d84-78db-cc0e-2e15-522b885ab81a,264370268,8084052167922937952 +3e04c213-43da-6b82-f582-ea94a202aef2,467147780,15619134123602313063 +6c4b2efd-c332-92cd-6f4f-c363f4284029,150769186,6031769454432033319 +ab127a81-e334-8501-786e-1978c88a8957,1945760569,6917364268022994560 +1269d2bb-f7d9-3460-922b-bb76c9684b87,3874422712,3299661392399938561 +8350eff4-15fa-5a30-1167-930bfe3766a4,2368627327,15031961168268488029 +11afe6ab-6b50-7cb1-2cf1-b777809e3517,1951022204,957745298275504867 +f55253e7-bf3b-b173-59f2-7f9aae2cbc5c,709504496,14477560571414678422 +4f3fb7dd-e685-712c-ff40-72c5ff98955a,3479589101,144095994971228459 +802e4b1b-c131-a2d7-528c-8baabb802a89,212028519,15153652632826046582 +7350da9e-d77c-f82d-b25a-ab8fec97b9bb,76323198,14629340084423162006 +eba4ecd8-3f43-8474-ced6-5c1338ab947b,744185866,9292544847729256842 +f939cc34-518d-6afb-51e4-8f6b76016b65,4085919167,2386228949142055350 +51a90ac9-466b-9702-f3ea-8f2de7df7926,1558823140,8954438317115210367 +4a91cc46-eb0d-a830-6ec7-e612c104e0f7,3832414116,12194489608338592187 +b94e0d08-0f51-28c2-7eeb-75324c1ac0b8,4125140473,5585988105757663215 +50f373e4-59dd-95f5-0863-c86e543a089d,2108211609,6036203033812209679 +a3ab6ae6-4db9-fe24-be80-5fe1fed647e0,456506482,13977309138442026434 +ebd21e5a-2cb5-3a48-fa1d-b7c5e549db2d,2733980124,15468018553303393758 +1ae3d8ff-90ed-3c00-2d96-f21c63d4f8a9,150379123,3885716454310042612 +a3438f42-5037-1463-14e4-7a566a22780e,1263128589,3210776728620349209 +a47272cb-b34c-22e5-37c2-47268def6f34,3294626883,6704224085171359567 +762bd4db-936e-653f-6e02-d768984a3b10,3032195503,14840388990327719018 +6e0542a3-33de-5611-d786-b2339787f004,3952704710,15423844807571517486 +31d6b432-ffa4-86f0-2523-30fab426a5f3,3299835500,571480209020519339 +f6ec45ee-8a5f-ceb1-05a9-1a3a5921e95f,831695139,547302177820570385 +92150270-53d2-6e0b-4c3d-d9e5ba8359c5,3179047772,7591662849969594342 +baa1626f-dd5f-df7e-a608-fde8963329be,560096884,11568616418680527660 +687a28eb-fcd6-cdee-1805-b5ca4df32937,592140535,17592475791078250562 +c4d43b8a-4a2d-7b64-f7d0-57e7f871f4b1,693952288,14678884018192427984 +47699fa4-9f58-34e5-367e-0e8416a64551,1106629354,7890291715238023369 +48951719-d9a3-d664-7094-bed6116080ec,2044793771,4413492905610389514 +0d464ad5-d729-9c57-4193-09fa38ab05bd,228540638,14400949181270234211 +5a8d96c8-bd7f-f7f4-1c0c-653850e25152,3780561807,17479532353012671095 +05e7180f-de1b-33bc-6033-208bdef6823c,4177404728,9378080100660562351 +ff9c7e73-9ef4-6110-be2a-b7c867fe2e25,3166489905,12318650358289501866 +ca64c35c-b40e-1839-ec43-c5738c7d4880,4005614700,16280695556787247102 +72d005c7-e72f-8307-f265-ed40114000fe,2096484588,13412325492576968145 +9e16c790-af27-8d59-6c80-95d3f5d6863b,1301785507,15577606092825402634 +533d55c5-4218-0b4c-fc95-3c9c7244103b,2956371356,5369962221260579373 +5569a151-0d6e-f38a-a8b1-c775b7ac913d,1405588618,16178911124643162481 +866e5a2f-4354-e450-37f9-15d03bf23ec4,1063755446,2754284402685399524 +a94ee800-76e6-9d7d-dd85-1d4683ad4986,1592932488,714535952981896724 +d8006f03-dccb-7563-b982-22f0585d89c1,209264559,7166711541592416862 +c87efe45-7c77-78f2-8c33-a2cb0124fee8,3564910016,8987784579327171922 +b46f4bba-83a1-451d-3cb4-e3553b7bf76b,150961895,6720478471336345089 +d1ea3509-4aa9-ca62-bca4-e20aecee07a1,214164423,12149702832527656760 +0f851a20-317f-2b07-545c-b832b43d3181,619285506,16205883800885042653 +11cc87d6-56e8-c148-8836-245269c4da98,3533347294,6701932998991202852 +a2abf696-45df-9d28-0733-6850c6994bc2,4185207149,3781031075853341129 +dec0ded5-2fec-c9f4-05d6-482d68f23c39,3969943956,209887130447469771 +f6cdf885-0ef8-f334-b287-2a6b318a0056,2023069547,1460598720489473953 +f9ecff13-c807-9dee-99da-44924102152f,3146888958,11658025441465910931 +b3f4bc38-5e7c-737d-2e0d-cd0669061e8f,2338154933,15828082918115964077 +6325493a-4791-1067-7793-860eb80576ca,3443373206,7688503130481645333 +75478a8d-cc2a-9f07-1ab7-85e8bfea565d,1843031136,14930148610314560315 +a6466c71-af75-6ca2-a1fb-e5fec892c613,2361797269,3429542495763004807 +af52e54b-1d66-7c3c-8121-f7d2eab33eb5,2927278124,9306114784565748526 +2419f62f-34d9-37b8-3249-fe57364faa82,1168748889,609079878641278438 +0b3f247e-3ac5-de25-84bb-961824074e16,220280075,376239536740140566 +7a6758e7-2a54-afd9-ccb7-e38def302d43,3287338618,5048788019870328569 +21acfb68-1c40-ffaa-797b-d775b1bb3000,2478557085,14693596443047194526 +318f0795-63eb-6e7b-3050-a8d880feecb9,864136389,794756159134217412 +da35c6b4-d24b-80c1-0db6-e12c0c1726e3,1213594164,3935617906374091490 +31d3257d-d49b-926e-7ca5-9777e00ead53,1356704941,1790909392448673420 +e684a8dc-8ac5-43af-db39-522ca7db1234,585384076,16775865145443808995 +54dbf682-f161-8002-464b-75c595c2f330,1092424174,11835808376388141918 +abd9cf23-98f7-b2a0-24d7-4c4c5e3d0cf1,3384925184,14297000047307379482 +918f0c62-c788-664f-832c-c86409fd88fa,3742752120,33500082919542003 +d9b022f9-7c2d-11e7-77a5-576e2f2466a2,32393635,3200348674603879736 +1520be7e-f033-8f41-2bec-f1f7afda7320,280116747,12480451676335428441 +ec8d4a72-4485-c85f-ce44-c9a5f3875078,890867479,15424418440578086132 +7cbd43b4-7582-7cb8-93d9-8e88e8b70a10,2295637054,10589984314971232189 +3ed1dc84-ff81-9b3d-8604-cbf670e067f4,2989522364,13879385549494944047 +0faf99b5-7f17-0d25-b18b-ee42d152bee4,775700733,1547551162664573120 +2c9eb9a4-db23-9633-de06-8e9f34a4258a,1656235871,11327200942077833986 +17b60913-c609-f1bb-8fcf-f700e8822d86,3684250741,13266115202879907682 +8c58f6c1-1e95-dc4e-0753-32312d396403,2075650865,17107861961479427629 +66fbf6d9-e70f-0a8f-0ab8-83219554a0e3,1596656496,2726330179350492764 +f5fae419-d76c-5c44-b439-a6f82f31f626,56426702,9649392195041366426 +048af170-8631-f37a-e8ed-346fb0b87d52,2003572876,4483080746572408063 +4d6bc127-2e1c-a3bc-68ba-739b6ec4fa79,1083487759,834332577099071267 +758ec3e2-7036-2e44-09a7-f76111fb3b04,1373156711,316432407411174008 +4b2479bc-55d9-49eb-2437-a03a41b7a4a2,1795295950,6657254228410927134 +6e7eb974-b2e6-4606-540a-76c98d788073,4254892802,15696093140688994737 +d85a5e89-d41a-e68c-a53b-c5b08823dae4,495870287,2872871781435093936 +cfaa78b5-8165-2617-8c0c-107fc3bf12ee,3014075158,14327955441849321823 +07beccdd-d069-42d8-a9c8-0e365bdfb895,1057600163,10359505044999825314 +43af0f2b-bd42-fb34-b35f-1b963fb496fc,3064058529,14408797678466453421 +088c1c90-3b6f-8030-123d-25f98d4d4760,4207515092,3321950927087562382 +22ed1a3c-40c4-66ba-2f03-bc4cd0c048f6,1147866379,10025179654525832826 +33852e5b-c83a-9c38-b73b-ca8726ef14d4,2972347288,14650936146943648909 +38983383-79c8-fff8-92a0-9b3ce3de60e9,3287318237,12298665284314482648 +484761ff-2a69-020d-dc79-b3c4d1ae35d1,204128883,1775026179686694098 +3ac67ffb-e4c5-fb31-1eb9-2d738ddf9a1f,2132780375,15842398745205315339 +27abb472-7b0d-36aa-55d5-953686bb2fda,4022236714,3349469576122934290 +f141bf63-bb7e-0b9c-25bd-97184f331262,1150322012,12604260049406674951 +0c2b4d5b-741c-abc2-66d7-1f1a49dbca2b,1942138406,18006771957379392100 +9ef550fc-3471-01be-69b0-becb46ac89df,1342833791,16125210316085547808 +ac7bc6b3-360d-19f3-be94-34ee9294e63e,134092387,11140548735045303878 +bdf866d3-a3ce-15ae-7eab-5e8be0f1e0fd,261332126,4275485236798369895 +015c64b4-94e4-4652-a81d-0b4aaaaa974b,2896096633,4406022740601717505 +51cd5584-fab5-3643-9df8-478981a4deac,3835221234,17235690107930528236 +2d6b9fb6-96d8-3f49-ed31-9019786f1f3d,1400863741,9692444144592951733 +c087f99d-b1fc-e93b-ca61-fb1644537868,4089505291,3079176321063297865 +7fee5996-6713-fc97-1b6e-fd37284e153a,3792754107,7025805870576132181 +bf4df1e0-22b2-80d9-0c4c-2da21de9e8b1,1276872863,976368878321971257 +eac2981a-77fc-263b-40a7-4bf769aa4741,1843343917,3425709292968605477 +6e3bd150-a946-ab82-e5b7-e5eb7850bae2,1608853938,10039417248502713998 +fc16c405-5536-e603-fdfe-f4245d4fc819,4021704323,14091864268485755447 +d84e409e-ebaf-562b-554b-adbf3413631c,3996870964,1121663768754230377 +c076df4a-911c-b8d4-eb2e-f477d0c2beff,4018001027,2976621816582404359 +6d00833d-5879-f06b-344c-74ba61007b0c,2032976615,9611041534804292673 +70a808c5-d486-5470-5a77-e1c5bd1a37c8,3947919029,5611377447996477387 +ad758535-f15d-a891-5d6d-2136f725a3b9,1436709014,8201183654451810818 +e70214d7-4be6-12ba-0e25-429df6ad5f3d,337918740,8877312395108018057 +088c13b5-5e1e-3e62-dc96-02c0edff7ce9,933206203,15529478547878752255 +3efad7b4-a747-7c93-b1fb-376f587f0424,3726719156,17276865231148666439 +153bf202-5c35-6aa3-303b-65662b48f65d,186323232,6428064161438093002 +b913c28e-fe1e-6d97-777b-4f4d4758f63b,1334637992,8877481243127198759 +21e07bbf-9650-facd-59d6-a0bdc70746ed,2050103054,12076732075967246767 +6ad35838-f642-ddf1-8773-9b14eedae483,3182294437,7351528307567094723 +e99a72ba-3902-5500-b9e3-a2c8dd1ac373,4059279883,16656100031064568473 +eff8e346-e4b2-02d7-fb4c-57720674b835,97980176,1726682665094769221 +51c40bd1-1c54-dc12-5e4c-8b506a512953,2370593929,4765471985069230096 +794c7936-2ef8-625f-36a2-e9746fa7090e,3421516787,3830590780043136929 +a9658f47-ee1a-4cb5-affd-dc000e93faa1,947540131,13596463512669887655 +c5620726-d249-33c8-3ec7-4f3e130ef741,1830311184,4449028363783480033 +1795319c-a842-5eca-7a85-5e453d3fe34f,3687239475,12172819887755837859 +d8d8ffbd-b04a-fccf-16b5-92ddf3774e9c,2245916844,16434083860439416903 +f43ebe6d-b8e5-02ac-8212-7ed8c8a5e7e2,3085220945,4262929070615828321 +4ec3a2a6-627e-5245-441b-931d12c884a4,973147445,16159740109796805830 +a2f7cffa-2ab1-8fee-b931-b6a562c85bc0,3773812310,3236979321557961838 +de206838-7fd6-4879-8b83-c122f625d2d6,2308287071,5589682046474775751 +5b8d3393-f301-7a5d-9279-afbb623bfc85,2623638845,13367964418326297480 +24676d13-b094-0221-a30a-52b575f35fde,3387890531,4244740476897137385 +73441d27-60fd-3815-04e0-16726e2f9d7d,2730346682,7542935074468713719 +8e50b662-e5b5-8245-e324-775fa77b3e59,3906815728,10446178309826660095 +eac9330c-b8fa-8610-614d-c88d2843573a,3091821349,2080649993858503943 +c93714bc-72d6-e01a-dd44-f015da92dff8,1339442194,2338138610701258712 +4506330b-484e-fb08-3f31-1a543132d4d0,811394131,3962200618286839100 +4a83a105-2c3b-e366-c92c-7a4a3a9bb6b4,882174971,15340299380738413607 +d505677f-0d24-7d09-c8f3-d57f45ea15ec,1329638634,13566332401213695350 +6283ba6a-2b0e-b31b-1010-da6d48ce504d,68074206,2518562265367808236 +1e611ac0-f242-3805-64f2-7258395ed1e7,2134925113,13975787925557860362 +2474473d-2ff6-3ac1-e6aa-80f60aa0b6e4,4095079685,14535511339393742276 +eb691dc8-8dea-33c9-928c-cd27e8801708,1941913578,4721911964830495647 +cbb01950-a57e-2665-aaba-782d594c6a4e,3956016049,4022177763818436762 +72725514-98f8-791b-4d46-ae903bb285d2,4269822400,13712315199893484618 +90de486e-b082-344a-8228-5268e29948ed,3218533151,12948191072910032084 +561900b7-d358-c69a-7017-012e71a8f9f3,1130171886,2775764602662848242 +d1d0d105-ec21-0483-bd34-026926e4a918,469732068,10645279082017687657 +8b79b367-cb4f-8c38-dfa3-44bbd59af9e6,185379409,9786435745176830684 +9ef0d7b5-302c-91c9-02dd-e4cfb109445e,3261270344,14872447780018059708 +6410823f-c90f-0f47-dc93-be7829921fc4,1401199843,2317939934319003272 +696b32a4-7edf-1026-af4b-0b336ac78dc6,2470715398,5514811105777917212 +ffa2bcf8-5fc0-84e8-bc28-33826367b7c0,2558063963,13450110707540366957 +09ea5e04-51ec-99f4-5a1a-cd956a72372c,246367120,3589333554561259581 +762d34c5-4498-3fa3-0bfb-baac6be0ff62,1821136000,16630074183753168780 +9bf9d8da-8d11-9dc0-34ea-6103e5946439,3864169945,13079669723458155466 +506d15b0-93fb-2bc7-7ab2-958be4968d92,1562529394,8190564061487185623 +3c8e5ba1-2dc0-df2a-b6ec-dc82dce6f78f,2977043444,5897732515117517682 +2a87a328-e768-f68e-e5cb-93a2d9e66d01,3319401731,4846135622968666947 +8444b1b7-1f9e-20c6-b7dd-3e3e5ac351ee,1332844248,11070823575071421489 +7414b075-4e68-898b-e097-a7db2ea02126,1314902150,15276714395986297106 +5ec0be94-dd4d-4c4b-b5d4-09a2d745f6ab,170153600,8926640198643584214 +c44f14af-3ebe-c6d7-e198-a7d035691e9f,456854977,6428122798356150777 +9864d4c4-4131-7b95-fa0c-b9ad79488d65,735025095,3296191288614732907 +86a7169e-d006-b97b-07ea-e342b78f95e0,725053128,3592101304085356133 +f690ac4d-9648-c62d-5fe6-70aff1dbd17b,1470453323,14110972740010878716 +328f6d11-53d9-52a0-92aa-f0429e219f10,1269198324,15610478976665759112 +e2e094c9-8004-708d-39f9-05a708bbbacf,2770552279,16295358261522317050 +be65a93e-68b0-3ad4-a89f-c40c8e7a56aa,2705726642,13453581816917988578 +0a10e381-48ac-4362-4ac4-7a621005426b,1321506009,2048484270539550347 +03b6e723-0a8b-b053-e645-704786631e54,3991323773,15317327114744315750 +abea0cbf-1659-8558-ff79-4b4c895af30d,1713365518,12792009997762748573 +d8a4bf1d-b20f-3350-b67b-829ba461ebb2,3239397389,10800164626989541291 +afd74afb-0ad5-6a17-b4f8-ea8ec1a0688a,858391517,10555482168175147442 +d9fa0d85-6da0-b934-9c05-e87818e25517,4185041154,16512070285935252617 +0b2f2385-e036-ada6-858a-64a3803b2c4d,2714841059,2170975731635573142 +045571d9-03c5-ecb9-2b92-8d29017b1cfa,1062996105,17905151032069681521 +2c3567c0-97e5-aab0-fa81-f256f62c5506,2116168114,560692755616890660 +47344e4c-7af2-1daa-fc90-2293cc694ac3,3526096826,12650176867710444691 +45f5fc4d-c12b-fee6-2387-87110fb25f95,2695595727,6149257971793220180 +777f249a-1078-9da0-bd4d-0193dbd31269,3491469348,11512807106120548517 +abfa3ba4-9f13-eda2-ae45-43161704444d,842351657,5511101539331650271 +d218718b-0eea-e0fb-f1e0-19872dd99d1b,2385704475,9789466181871407405 +7586dc52-4435-aedd-614a-59966d203d11,3406357959,14574122608747056621 +b0e92150-672a-3e81-8b96-d616bbaa1c95,1104572376,4044301184522775889 +fbd47685-c5eb-38dd-1d51-5cffe4a3319c,3843803726,1211906891762888858 +cceba919-8793-5a11-a4fc-7f5e18167bb6,951253533,12379186776137100755 +49e3b8b8-9c52-7eb2-857c-7297b75c9a2d,3383385193,17716129523800369127 +d6fdb711-be52-7897-fc72-5f6daada3a3f,2926116678,6005170627322262036 +342c07e7-968e-04f4-df7e-dd628c2693f8,4134838487,16273403213587900570 +2e2dea2f-87b2-d1f5-6e0b-dee54bd0849b,4276527763,4121317951778366789 +1597f924-dd0c-d9e3-4cb2-71e332d5600f,2681241229,11222959369285409523 +228af789-7a8e-2d8a-7aa8-17234de75a0d,3443150832,6383857818992880133 +46fea6ed-640b-4301-0a31-dbe8666eb64c,1934747328,12610953437141635217 +5c4b02f1-f37e-7b9c-ec34-6d281de3d389,206557406,11730848975780178253 +20a7cee9-28fc-3295-1fed-231d6e1bd94f,1576965396,7314258657651973171 +4165783a-bec1-9c93-5037-d797466dd724,3308842125,13938802429062622415 +da919cdc-1eee-a670-9e86-1554c83b33bf,2676656075,16789804784239059792 +78464061-7e57-c391-d3d4-519e62854da5,762504104,14570375607141041501 +6d4c3c28-6667-fe8c-9d36-bde00c31676e,3503675364,9390441701255256778 +2b86fee3-d0c2-7d5e-5fc2-c9bcc230ee4d,769728212,17692017900964278843 +01fe53d0-4f89-82e9-5973-bc2dba4e4860,2459572406,15164865961271057986 +a202cfe6-489c-2646-ba53-c238df781ef7,3985559754,3487499492154928085 +f63bae78-6663-45c3-7445-58351844f938,3710063328,1924919039884217442 +fd3ec9f2-cee3-a32a-f59f-bbb1be1f0588,195526297,3533521240458867217 +2eacf6c5-e190-c37c-6713-094692d51dae,1622958534,9315065227243558650 +c6a70918-043c-0ddf-2744-33a856e506f0,501756234,11968952582001311719 +9e04834d-8133-1dbc-8962-e416073e4f99,204088844,1986946100095698147 +2a4ae3f6-52f9-4615-3a17-50565c3655f9,3292907586,5719489375642916400 +3d6a465d-f07e-daee-66ac-df8c348dbee0,985651369,11984407859887306970 +5ae22651-6dd8-89ef-b039-3a638c94953d,2241438165,1043619913065620052 +d90b11a5-bc31-f8d4-2b64-cf67681980db,964160163,1241099970604618580 +5e3db0f0-3a36-d117-631c-9c89d42cb31a,2074785512,15751889971575361260 +44890263-9a84-50e4-822a-f0af4caed0a3,1320704943,13165631398825800796 +c1b14163-8120-9377-2554-9e9ad274852e,436499291,15540417810408935938 +8a4c594b-9bfa-2c03-f5ba-70c56b9ac28d,794714445,12495438368501827101 +c019916c-c5ad-0f57-e3c0-332b5e30ebdc,3439556028,11647968418882135481 +07037a57-48d2-98ee-8d43-5f71f4c2e10e,1140507949,660372254181418925 +4c179a09-79c8-9bc7-812c-a46fbb208e60,2401583174,18410369850766387739 +b6d3362b-445e-159f-803d-e723ef6ceb16,2348912814,9923331583023444947 +cb666238-5e69-cf88-43d7-ded0d46db7e4,240142303,9232139742800266843 +e2b3a61b-6fb5-1f5a-58ac-e0cf62166274,1625707386,10575265962325597113 +6259bc17-a835-03ba-f3fa-645e8c11d086,1999610239,4234864029405450296 +ef0278da-3249-3c84-43ee-442f835f902f,4011823466,15998632365704089942 +81d047d0-2d1c-d235-c3c2-41e0eb0be571,1314614721,16707308783553212880 +29b854fd-667e-d39a-3c39-5856b6ddc7fd,2310863255,15270894357972955427 +8f01bce5-9c23-be60-b260-cc1f0c5eab6b,3916845056,9549744864894256889 +e03c7fb9-155a-a70e-e991-9e61c93cbc8e,1379742170,6218277080580461837 +49c43d84-a0be-d222-aca8-78a7ad5c21e4,2125430880,15232275626959555789 +82f4738e-33dc-a209-630a-1eb766276e30,3580558694,13488213406691571211 +bf53480b-fc42-99dc-4709-5902b9d4a0fe,4118514861,1620976098837228212 +c7cfd5d9-64b0-d7cf-3cb2-02af9cfb329b,1954074888,9167810982443025451 +0b15fe6b-aae2-f212-aebb-479878bf209a,1610362498,8537751612014216200 +5b4ce476-1aa5-e703-9b61-d72871c5a553,1213252407,11488496009248520537 +bfe252e8-07b7-6c70-41c8-854de3759d3d,3825124915,13823997681947296034 +237adea1-5a9d-3760-bbb1-c63ca130b870,1325283547,8592877174862524151 +5eb989c8-a75f-8075-2e3a-ca76f417bffe,3203392005,1135844844971779914 +b1de8a05-96c0-3684-8797-f6c853e40e9b,2427074862,10799304912401962476 +a843bab5-e7dd-19d5-b673-e83d160e7996,1657600997,2366461951952235060 +6b126c1a-ebaf-7a06-5c8f-692298dbd17d,687967934,2948274850822584579 +890d206b-b943-75d2-dd61-06db1f874033,416639622,3632763199743339000 +24144507-6963-f14e-abeb-fd185c929123,2428096332,14173249756583688373 +8cc5f8ce-b63b-3bd1-0465-67473fd200d1,4162717704,9974228007837265711 +30cd7f89-6c6a-7723-95b1-37a2a3978cd1,849072660,12633513708533293315 +29671f64-9ca4-27d5-01eb-3fcd14aa6af9,3957514418,15418354948846593482 +f614f86b-e51d-9f5f-59ee-8e0d08d788ab,3048169651,15305584914530601860 +43190588-4210-6081-bfdf-21a2ebd08be7,1439163294,1035936020888168032 +b6281c7f-60b5-d34c-3340-3afcb3dc8056,4049265063,15343473629787508677 +1da84f2c-f10b-33de-143f-a8b3653a03c4,338315778,4626529876601605697 +4265cf54-2e4b-7c62-6b30-b53fed751b8a,1482412574,7634694972064594158 +9e15bd65-b6c7-9c98-cad2-972ec144db77,768424579,396308993114075477 +8d54b5bd-6115-1cd0-fc84-df8588c18fb1,394458429,13600820769903217502 +90b323df-efed-9f7c-db6d-83282ab82648,2649978018,2309269758359064132 +72b44e00-4e93-5cc6-7cda-ebb555a9ba95,3216110057,17092910818420599897 +b2b63415-cbfb-2043-b7be-84c7ace4aeca,1673502344,10854044383800993336 +757d17be-396d-55c4-6568-388a8fd8ddb1,4251960615,14356520408782853067 +31890cad-cef8-5d6e-bec3-1502e13d51fc,815761502,17373024123573337167 +44844925-f356-3123-b5bd-30a78e202a61,121158312,5750295064068700143 +d6f4d1d0-89c3-d043-4f42-102691389013,763297496,12015411370161842831 +18e91033-a3a9-d6e8-7096-d37faedfea6f,3605095320,16125919664789550583 +8a56c5ec-9a83-1baf-e356-2b3fcd34db88,2387048976,1500675933126457794 +82117bf7-8e16-ad72-b786-e310fc36647d,3102811092,2827922744027370792 +3494354d-f3ba-8712-f939-33238b9dc0c8,384544902,13423647082930181446 +26c9dcc8-c081-3bec-bd1f-f21f5be8b53a,374311224,10507914771273881495 +b125c1a6-1f2f-ef28-fa97-5afb355ba08b,2526620609,4300100411012294617 +4ef86046-673b-790d-905b-64af4e78f5d7,556428713,6353331941523782883 +a9ebee2b-f347-f393-1295-7f95ff5bcf03,1085320561,12542151708189299725 +560091e0-4264-b6b3-e15f-fb37c8ccb370,1420945847,10861885441718980300 +cc93aff1-b19b-54a3-69dd-9d6c53bcb33a,1604128992,10080346746652350461 +a33a8b34-8f0c-28aa-de40-357eba748c12,1555434607,1345321603063312113 +f4c73d42-cd69-2968-b3f6-bfe447d7199f,1700061774,5756910159554195815 +5ff65a7a-38ab-db5b-8c80-4060ff9e9731,3623119304,16311830278922086345 +a09cdc7d-68d4-c858-655f-512e07b37de8,2260827257,5815988089335444764 +a300f272-5324-2d20-725a-679f94bb7fd3,2942781864,10963172915709068984 +364095a3-5982-2a6d-95b5-f3d84846989b,3577840285,14775563359646201772 +3dc1b287-ae43-535d-2fb1-240e9e5dca45,1387988191,12308260804922428020 +b697950c-4fed-aabb-6308-cc528c97d840,2282554349,11139829723646929174 +222bbc58-2a88-4d1b-19fe-9df397b483e3,541660645,14472504403486078767 +13d54351-5381-1894-b6e9-a1e32c18c530,3921063889,15069430163555436980 +995d464c-3459-5878-b0cc-6786ab9addd8,1149065318,4429575435240496151 +4e046065-7cae-5471-cbfd-fea22ea624c1,90544653,12124300526551597006 +144388c1-934b-fb45-7e3f-5d92dc0f9cb0,850417299,6432390457469029600 +20132528-2996-7779-914c-830204df1be7,328457355,13630505096896510961 +289769e0-f2cd-bf14-34c3-b66f4756b3d9,3474881172,3973500434086902703 +1e8d0c38-49bc-3367-666c-549f60e8d9a0,1663878659,7964304034738220848 +f6d941ed-d798-86b1-e459-d5ba336848e2,1392025721,2142864776744620862 +b8cf128e-e941-cc8f-91e9-8586c0736371,2402214155,12785573363457168554 +cfd6ed5b-fa90-7b4a-a0c2-d5295fd55669,238430499,11576573690365166590 +beeb2bcb-345c-a8b9-f526-34759153a9b2,2982357573,16112099961510748240 +c1119465-523f-7576-5022-c68870119257,880349629,578766049375106056 +93635903-3bc8-1007-19ac-5c0d3f56d031,2403248946,13952378896322111183 +f733c912-cd6d-713d-0367-985b631930a0,2827679711,1057218020722495920 +9109742b-74dd-0a46-ba22-c5165ee5ee54,546869687,8641713947542393860 +a0684365-e1f6-0844-17b8-4f086c62b9be,2137015427,316980558388294035 +8c0098c8-b473-775f-3ada-5e7d0fb95e8c,2123618205,9237384317544181317 +9c7dc142-a58c-d316-7a2f-be123a8a10e7,84936676,153296650314355056 +a680c9bc-b770-37d8-f364-61cfed5d6b24,3318229932,9052188663950534630 +c5dbd1ae-ffd8-9b20-4ff0-8e4474341267,793879817,17595131705114912980 +9a521c19-cd21-de74-f64b-e0c6305c300a,2782949450,5478036614989199260 +968650a3-f9cd-f299-c6bc-30397d28a55c,3207877534,12186868013723543415 +3df16891-a2a1-b268-83a2-d63a8b05966c,54789323,4887020405404379025 +48142156-801f-0389-03cd-b660142924fe,2287130832,14623124515382498207 +186d99c6-902b-cee0-71c6-aeee1447fddd,2678374723,3177494053127293949 +6049be86-61db-704e-778b-168a6e3efc8f,3136674077,1334940361529438271 +1cbfc47b-3622-a67b-fc44-ef14a7c79771,2930962004,1053345259090950070 +4689e652-3a93-8b20-729b-91f530c9179d,2257180221,9735734940983752665 +89e26022-d0ae-1498-42dd-a6f33ee8370a,388539162,10000863913539381147 +0445f665-f7ff-955c-4572-d1ed353ac147,22054949,8628625890525774612 +56a6948f-04f7-74f3-dcb8-e18ca7956576,4097916098,3867605573091987690 +1e9dcf3f-dd94-87e7-9a68-3938b29c54e2,1138992095,287999700678192909 +15ba060e-edc7-aa0d-325d-a0e8af4092a7,2683579572,15550706895286083741 +5425a1a3-ad38-bfe4-7aaf-a03b55932935,3255306552,17199030675059589110 +383a6182-23ed-66a6-f5d8-21cfafe21336,2996245698,15776240770517389852 +c97467f1-ae02-d74b-3d68-f311e246fc5a,2667732319,18146060584303216647 +cc9caa19-18cc-1ebf-9cbd-88018284709a,945221566,6409535489693803159 +070ef2b2-fbd6-57bc-23c9-12e4edfa51d7,1375444060,17773468614046460246 +56c0803e-1a0b-b09b-b365-37a2b2dfa667,474483234,8332705747913843979 +f47cdee8-e9e6-f26e-a518-173a62e447a0,2407353251,10921647625892057608 +082a12e1-453b-70b9-9aae-d675418d6b33,2819702273,7731916191177597813 +8c3bced9-11ac-135f-f865-2db79dcca2d1,1419503500,7670872649829343164 +bde4faae-c596-18d0-4435-a6b824a59758,1781175718,6313280678079843050 +5da4cc96-9666-6a3d-e7e6-0dfd84301580,1204914195,7769443666166848375 +833c2b61-d1f4-e75c-ed51-41bcbe3f0642,3941964947,4107822900901205281 +50945871-dc6b-babf-6a04-a23a90f770a0,1397657045,6327084510132160635 +f6c79b9c-732f-14fd-c04e-e818156e85aa,749830489,6585995412342049816 +f9435ced-afd5-f8ec-39bd-69e474e55e12,660057385,10850815090194363870 +eeea8484-0d12-b701-50ad-274287eef5b9,3176880072,2701157620814774666 +1b7c05a2-f6fa-0ceb-2beb-a8013a7ca0f4,3152237683,8145269232172110760 +ce92276a-2b42-6b26-31bf-bd3185ca0eba,1053397130,4207538119580107965 +42c16714-063d-f8e1-4db0-6fa359381a4b,1265251676,16861518737119370362 +5935884a-577b-4387-c6fc-39afd2476013,609377746,11346294264568200052 +64b2535a-dff2-62dc-1f0f-607d5d75cca3,2389927617,6956728350157984540 +23d123be-e14c-e3c7-887f-8099e6b752e4,220146562,14826700000580846431 +069d9407-5946-ffaf-0934-0adecfd0f919,1856383717,14542725624096574131 +6a5f8824-8219-53c0-ba29-f0825c9e7ce8,1995133228,11823169476526604557 +c1e5520d-0857-231e-94d0-d531d20da42f,1050335315,16236895969685073425 +e30d5310-e266-00ee-c1e1-7b56477d8b95,1472602863,8841895852795284547 +22e9296d-de71-fe1c-1273-53432f3486a6,3339050274,9430287607158716367 +02331937-efc4-bfe9-0d17-a63d79e89888,382127012,953149667179678634 +41a485b6-ce77-a75b-87fa-9fbe446b7ee8,2639585914,18347059260318115736 +b87628e4-8cf3-7852-c397-816a270dc836,1660615450,6846921331202342490 +f2278bbc-1349-1691-5d87-0a9309103031,673133712,16170316764804071883 +e8dc1614-3da2-ce89-63eb-86d3db973fe0,2102702819,5071328445786881828 +187579eb-7d32-b126-dea4-78b35b75c65e,2307409980,5114731442560772851 +9b7ab1f1-7067-525e-cd74-044c284f1fcd,84197213,2347685103758036178 +d5ba7540-9bd1-abe6-5382-fb4b5da57f1e,3573364264,3978292652991892084 +db9ff797-90c1-ead4-be95-c201488cfbb8,3665632101,12026397028003802075 +c46310e1-987c-98b4-08c6-5b9fd3476807,389524867,17604034491110235444 +c7827968-c9cc-5d0c-5e45-3760962f072c,1981848391,2190207524038729014 +6b941db7-b1d2-5865-1cb9-81ad1a900dd6,1470433018,3881735392693141880 +3dd38b15-7355-dfb4-1228-b79a4cbed816,1968730606,16529302313426813049 +8e44e05f-3ba3-d24a-1367-5ead28adaadd,654212117,18267351463475089489 +d611a126-be2a-56f9-7685-d27383b8880e,1939357006,9608532345802667401 +1ed0a30d-ce9f-f131-4459-9f3c9b8640ac,1022522992,420259526426235931 +f80c7ace-e988-2727-39e5-2c3a9db8fb75,3425457330,3908178519244892172 +6f86097b-76d9-db3d-8d14-7804ff91d24f,3944718653,1314755402150300547 +f2f633f6-708f-3268-ad9c-100064eb1182,496198004,942016199868043763 +5e5a2f30-62c5-0860-de8d-4aac1918b65d,534626728,10430617165774597528 +4767b4ed-f3df-a1d5-0a25-a1fbcfa20745,3519733827,5676160276786389330 +aebe9a6f-65ca-2e5d-b277-20a353621f45,2891402380,5761639423131277075 +950e5f7e-5fe5-3dcf-fcf6-323b5ea3f8f0,2503906623,13534654422314710626 +d4674011-905c-099d-3688-19033b33a753,2758705409,10620242396272212362 +e4fea9c6-dd47-1e9c-82de-7b089cb1af8e,844262179,11296773262444451557 +f2ad811a-4165-f789-283b-6b73219edc39,1891443875,8813622879994528020 +56a8a295-76e0-f816-e656-d7103a43b9c7,2183620347,13106260335337258730 +31392358-ee70-dabd-8e1c-58779b400ab0,3831899554,12837326112045685978 +5adfa074-80dd-e5b8-3279-1ca0d8f3b24b,713097218,2178327098575155074 +cd825d62-4059-de51-8662-924ca312c54f,2082817665,10246421095253552246 +60d08b89-6ade-e444-7a63-227e1fe35340,4066726290,7616129597366075619 +01d3383d-55a3-bc10-135b-913a3ecd39e7,2277436606,3291456208568747435 +1b7f71a1-0639-79d0-400b-d7b4bba117b5,3451304392,11519292232346074177 +09dfdfea-8acd-49d3-a380-06d760c8cd56,181406302,11435930547053273209 +08cd1f49-82b1-27cf-1494-531c5e4ac6da,3430233235,17847869946986141524 +b8b71274-f481-8afe-5804-17ac734541d7,1233352935,1636559146289071388 +a1beafd7-425f-d017-383a-1cbecf01a763,1387584013,6895239346574283197 +bb75c20a-f433-e22a-81cc-de8179e6fad6,112938743,9888717401885249667 +434b753e-f5f4-f7f4-9f57-4bf570d339a0,2685543104,1753598292356322683 +7af74c98-f1c8-c33b-f016-c318a6a7069e,4147897340,11375454624921625676 +7977025d-442a-1828-c0d4-ccffd8ebbf21,3330943190,6545268157414587657 +38c24618-8e99-9dfa-180a-a491b07b53e1,3724542302,10784832123182095287 +8d20f38c-5690-de18-62de-c6f79b97e3d1,1122321461,14835743736508423130 +4d0ff2ad-0866-0898-acb0-329fcb9cd1dc,381735005,10743964522040793533 +7e14d4cb-ebb6-efa1-3bda-a8cf816eaf1b,25498220,16440423844598641174 +5687823b-c17b-714e-785e-739cbeb88010,146317594,5862180931531758871 +f638cc10-0482-c256-62fe-ca548c3a6321,319945286,5143717715673941783 +58b993fa-7ced-f6fd-d2eb-975a9c419425,2260778647,15479708225091861949 +09122642-97ad-688d-1d61-2801ae6e4ae7,2805607741,1350458971538524029 +940c34d4-3766-530a-128e-b58fb8360aa8,3726305834,9316888124131919743 +6341ed74-0d68-f634-9b44-549ec6ea9440,2245589127,7728703717237553723 +71bc16cd-9c7a-2dd0-4432-f0781fba4731,1929889327,18039709588753494540 +dd288ea9-1349-8d8b-390c-e43301157e3a,3958138623,9736159016380187786 +6b8e3420-a092-6165-db05-da37580c199d,2647437992,11667248752183853042 +4ecb0c0e-c3bf-8357-6a1a-8b716b9e4b8b,1552828253,12260363200689871586 +deff9a6e-779c-1d06-ef0a-bd356e859398,876551328,7959013948825320053 +a9be5d48-7310-3221-2b24-22e9dd1c0af2,2761636215,3928682102906076829 +9bae9f9d-abac-07ff-fd55-6324defa9c84,1401604035,14818334302777051779 +f3c6ec79-ed01-5b0f-a93f-adbf36080a04,2280040630,1411177574487035349 +5297d5ec-631c-7def-27a5-9211075c9ea4,2121974662,4225518224292141423 +d1cfac59-d0cc-cb49-172f-daeba38d63fc,1097100256,17618198558726172872 +c1533895-7183-3983-a6b8-4c71b633d607,3696594416,14972371291105234870 +e4e90406-86d0-ceb0-a2fe-b62b69a76524,315452515,2248630477196245623 +cbda3ae3-4ddc-e73e-aef0-191bca53b8fb,1521358240,13997315980138570411 +e9d8922a-f90c-e7e2-d0db-f5c02f7f5f39,2337879201,14834117596792194720 +46b28d22-a5cd-396b-3f4f-a9e0fd4d5d9b,3979979678,17051734827437330085 +8c30f563-de4e-bcce-96cd-5880f890f242,1962850178,5570773595409196372 +4f71ff3b-54e4-176c-8df4-2f9ff98a56f3,317625169,6268671175512660484 +421573bf-66a7-431b-d6be-c100bb2458b0,2396096396,13058491152843462352 +3337eeeb-3437-b075-2961-a6d84bbf74c9,4239563456,12477243740996385067 +9007d330-c6de-546f-5509-39e0026d7bb0,851452412,5955538106081874921 +42ee79cf-5783-7a92-5104-477bc8eead88,2385402293,14629940620781248760 +9b47461e-a5e0-4d58-c7f6-9831538a5d7c,452930150,18120220266540257666 +b601d74c-d685-2f90-608d-1628313ab6ac,3566319140,11270226182286847851 +7e4862a4-bacf-985d-8444-671857b3b533,3582603774,16848077578185961463 +f2397cc9-dcf0-dcab-802d-d51cdb63c923,1530309902,15180166622974222791 +409386a2-9116-f37f-6c19-d7e6418152ac,1750242102,6275508759703188285 +ae2e865f-5a47-3d44-cf7a-583980c7562e,3030695665,1905979234056547092 +541845d5-67d0-7a5d-a1b4-fe09db29bbae,4043855466,5740363932113179562 +9a0a432c-7e62-5c79-db04-d57bdd399f7a,2373737092,5716386740859043303 +6a544499-ba44-f8ef-b423-ab7f2521e901,372857711,5585003483200438326 +0d703565-1c22-38a2-8c14-36c89a848616,16247217,3770757908277627813 +80a00f6c-4ba3-2304-cd0b-1368e56d4491,4016422781,10258184371342895696 +38216e40-09af-c3f1-85cd-7909275a3767,832696899,2777274673040965447 +2beaaccf-762b-9ab7-5e62-7e8b1c3f5d7f,2555348873,15435909768673506583 +57c59b01-de46-5399-692a-01e4667ba740,271375469,7541905111609478503 +5904cc3b-e640-3ca8-31c6-1598d81c846b,11983193,5346239133301459488 +81e35eea-4374-0403-c875-6edbd34ceb23,3144721900,10135494381232026156 +ac4ea577-a94b-612b-0000-029c1e7791b1,1251151748,9387313803200194691 +0bfaea96-b7ed-47fe-765c-59ef6a0f17e5,2042401352,6559205354270619638 +649575f4-c8a3-8f71-53d2-b98797320a35,3898060529,5140642534064537436 +6085771d-9144-b9ac-2be8-9c216a7f1903,1913951781,17743648335035781396 +b49d9873-63b0-1911-1a78-8083f391561d,3915460642,8755592041702837322 +8e8786e6-1de3-cd66-8bf3-42f7a0d55334,2146932105,12079157304796232189 +f7dbc930-11e3-697b-b087-4f57b8765699,1829349848,5509471908660321062 +c5b83f03-4e23-1c1a-7bce-5d21a5507466,573182935,2743832367496207858 +74b51530-1bfc-9de4-580e-07dd78699a2f,3075063221,2804329395568501343 +c25c1dbc-d423-3a4c-370c-badce94eea8b,771462251,16876024799769572262 +30caf6ea-6f5b-c630-1b38-6c3c3b76a98d,2089112534,9142636221334704136 +5ddcef2c-ac7c-ca06-1eca-9e27f7e37d69,413688156,9990630683252621655 +9caec7a5-181d-17b9-8f6a-f2c12c44d1ef,1930314130,615320072676085176 +d568b7bb-dd95-f26d-363f-b50e1fed28e1,420114256,18205588782028309525 +c9d70c58-6c12-3083-d0c3-f288bd68ec98,2774659521,3917888100256231696 +44ff1d81-0e12-624e-e1dd-7fb2c63f409e,53415269,18124066958862198192 +ca336895-c6cf-90e0-c9d0-87064a11f882,1007181978,5191363040640001305 +280d2f0c-8204-586b-d3c7-fdcf279eb22f,352893768,3625295992774960027 +681bc639-1b4c-1ad0-6a33-bb159f75367a,3958171622,4449391356213167240 +fb2e8770-31f6-86c5-ae83-6c498f62c271,1279914271,11039952063183893164 +401cb57f-fe80-e150-fcab-b1dce9ca8e0e,1327773148,9185779378284318336 +5c8cad83-11c2-0604-d649-9f555395dae6,392629503,15421694556878403523 +7d76aeea-2611-15cd-0c6e-540ddb381361,3372098675,12743586714357424141 +fe4093af-1cc9-efe1-4585-e3d31eb78359,3585122771,1700538386311768497 +15e02f89-ea16-d421-750b-29c109f57cf8,2782980818,17749484437647285134 +c213fc43-d33f-b07f-f4ab-b664ee3e3ea1,1400412668,11152756947724418835 +8fc33cb9-5d43-9ed6-5b7f-39fd8e733c63,465487104,6065838825091847120 +33889184-3abc-1789-b85a-0092ee6caa35,1408385448,2235604240873536872 +d857b787-0951-435d-c9d7-03ee5db090f0,4033409753,11616726338646892462 +2ea7244b-94fd-257e-cf73-31824cfe954b,559789608,18385317110422273937 +f516f799-9f86-a3cb-3e42-3b87f17b83f9,3935342432,5100457965665690530 +e4e0e43f-a10a-2a4c-e081-b1a92e568ad6,730569116,11059699774962900737 +dfb7928e-c2c3-0295-ec43-f11ba694fcba,1329890051,11005205464049301546 +e37a79ef-ce9c-8ba0-fb15-a5454cb67505,2948322915,13789513051544569835 +f74066b9-7823-d8f1-b8d9-f70988e96a09,4136718486,4220502851848506875 +7bc0b011-3028-1a3f-d8c7-d59fa0f0f1b4,62315921,16920247833208278894 +24b91caa-9cab-cfc3-351d-6c3beb84a0d6,2100809152,17410126682163059545 +259d42fd-35b2-31de-83c8-40d017e46e1a,4255442378,14639720301784779929 +64fed1f2-2ab7-1942-0e22-4b95239cbb72,190151303,6356706626613964696 +025b6211-2ab6-decf-47e6-979135ab6eef,2911507319,16310535090767465312 +4c5ee2c2-bfd3-27de-c477-dacb130ac3b6,1061341670,15489476381954045848 +8ab6a73f-1a50-8dd0-99b2-360392813891,3963980397,7009710097312933532 +a68a7b2b-7902-1439-7914-967c9d0d96aa,441984657,11320608088661648836 +744d47b4-c03d-500c-8e9f-f3f50d629809,21327009,3607295298307774447 +e6b0c7aa-da4f-031f-f6a2-039da2b6e5eb,93625713,11499756748642832359 +580c4284-8532-f1be-1b7e-5e492cae35c7,918815041,5424769536814456002 +68dfd9bf-cc83-3b42-4f03-a681bcbf8f1c,95180102,7941759509383320169 +1fa5c22a-8ae9-9638-dfac-a2ac452fea69,1918229186,121248472953568468 +416ccf46-121e-35c8-33d4-27812c7ead0e,4099241533,5048528925622026549 +710167ec-7049-2469-a395-00bcf5ba9938,42881579,16087847715341555275 +f850e196-887d-c575-cafb-5a25d88c64df,413499610,6981976805889109850 +0f95e981-1581-77dd-878b-e9655a6755f7,607713954,5833567573695700961 +fcc975a8-def9-52c4-35fb-ad4e6df6a33b,3353740034,12604813104414248270 +6dfbbb6a-631b-646b-edd2-a7cc7a9245de,244009678,6346629518904929669 +552a0aa9-1ff5-475f-2325-030e313e9655,4235359295,16205362518792344550 +84c70ae0-5347-cea7-08fc-018aece7b927,2676675360,5379993932079626152 +09989da7-f987-5ba8-edad-4e5dcfdd4c12,2661180299,803045837946037319 +67c25fab-d2d4-62ee-cd7a-8af5c7cfc672,2840877563,11642040171115282017 +f7aa9629-463b-ca74-f1eb-47815af3cc9b,1148907962,8787717178257902386 +4bd035f5-def0-8bfa-186a-3b8a12560803,2679910375,5936171715221639820 +8fa556f0-1ce6-2191-3d29-8551a9e3d8c0,4141329990,10202390621058477747 +d523b65f-aaf5-6e1b-76fa-6b581d0d3214,108645678,9447657324850693693 +e0e88074-45c6-95c3-1759-c0af69ae7033,752702324,12694356590727428103 +457088a6-2a69-005c-3584-dacf0dc16026,338627262,17068458443728313103 +e1792422-4f6b-3deb-a292-debd540689e3,2906039603,17033114598471686162 +9f7b1959-4df8-c099-5679-aa58d3767e86,2153257689,9348463565226347658 +d879f815-83da-2fa2-0394-3699cbeedb49,3793718247,12644508090280196257 +d1727713-6d4d-1ab5-b373-7ab80848c484,1620784365,3776381520118527951 +3ced616e-8945-690f-0f2a-e2a270f9dd0c,1029849982,450759552977987246 +3d5c0dcf-c170-4ee0-046b-5ecd8653a983,1123167007,378293191870071813 +f3a70bd8-7568-efe6-9066-a16af11a1a82,3394951660,18389503973953640537 +acc02e60-77bd-4ee4-1bb6-71fc827a7e8a,1299301771,13937656057436940166 +3b2a4b9d-06d2-7338-c773-93e5c2926b2d,775595925,10089796802151061704 +cdd6dcbb-2f17-3b7a-9996-02399f086957,3748666162,11531840052172203238 +4cf0f8d1-7476-865c-c303-8014549e3ddc,1480978711,4023126361940901178 +5bce0f82-cf92-5521-f549-9e4985c3d4c7,3433155147,6009927074548173401 +7c48f5b5-c76c-bb53-275c-7a98f08e8e1d,1255939016,11386363594183581977 +5ea9e501-d0ee-bb67-ed06-81b837b01152,698080161,6331422324565874478 +10a6f05a-d21a-7e60-7f43-14ecbd696e7b,3129892553,17183667603568923413 +be772495-e036-d88c-18cb-0dc2d96197ce,3494214644,7815193288770633266 +df3c496c-ee34-5f4c-a879-4c99f4fc82fd,366622248,705829098848537112 +2675f8ce-2efe-a0d8-efd9-833556cf178b,535242815,16682910346474866321 +04ca90b1-4de0-f153-d9a3-c1662cc410de,891627947,14292739520026621934 +a7a757b3-9b78-dc84-e887-3965bddc4b88,1964439959,3568147238276545990 +5a441b56-b934-2c00-9bc3-a45210c67c1b,297718721,17794744187610986180 +ca9b4d03-388c-1bfc-5cc7-3c05c7ec2caa,3214991021,4315439531222432006 +f33112f6-bdb6-93fd-4927-6273b84b4b76,1122792774,6546543230198469282 +96faafe0-6b82-18f2-b0e6-def3d1fb3091,3299623735,7057670875834819068 +b3ce6250-5a37-aff5-9ba2-ac2f352baba3,1083791824,10283054268432565291 +77ae25bc-1c3b-4410-bfd3-c2363ed8243f,1924832903,5802579879452329699 +94508436-4c30-5604-4236-fd33f795b1d0,2255471780,12376877803832492541 +7e2dde8c-1a86-7aa2-ca58-1881ff164f36,1236464239,3079710732405379019 +f57fa5a7-41ca-37d0-1836-14452a7241d3,1230440207,14919039548698261847 +9a110644-d9fe-3b5c-3ecd-a3b55f97fa47,743968529,18389209488173754821 +32840f8c-7dc9-471c-eb5b-0976af91a04b,3786330213,4424289723054799386 +8ef93bb3-b3cc-9f94-0d5d-5f74ff75f25b,723244913,8067413782501512004 +767d413d-82c8-599d-56b0-9993e75a3c87,110266354,14337092671978812792 +fdd696ac-fc97-24f4-8542-d87138946fa6,1119459824,1284623128202603480 +556f1965-d1e4-14ec-712d-80b6a485943d,623361087,7386988775159634801 +013c2d76-5a02-1b50-aaff-54277b504a19,3083368844,15863347249554558480 +aac91ec2-b251-2f6b-b7f3-6d81dad7c879,3403724169,7156080445182683511 +532a8a1d-d39b-866b-b157-572bd2ab2131,2495482386,5886985496189934070 +1af33813-9493-e5a2-4f6e-5af2f262779d,2678825578,5237924920075973404 +ad557168-a02f-6bdf-1f19-7f7f6732e64a,2897080442,1201045901508575556 +1436f5d4-1815-06d1-ee69-1a4a299f2857,148322982,17491581168174916458 +67517bf1-0de7-cf36-3274-a1bfb059f73c,1518339429,3933328580260943868 +ea484566-dc5d-60ff-a9af-72283469268e,374148259,17912728504088334099 +75b61078-fe71-33bd-4137-b03b40c1a77d,902308262,6292014585853436208 +adbd8284-e781-ac5d-1d23-c19eab8d35d3,372224886,14450607909370228137 +84b68de5-a82f-bf74-f75c-cc23d0583ffd,1502227634,7055277349007972343 +3206fefb-abba-2da3-cdfa-665fa4509fb1,1281369487,12223872308701068154 +de9f1820-d5d2-b142-c8d7-f8d59766e4f4,2431504690,2518552193916630891 +7a518653-fa8e-a526-5b80-21029625b8a4,1626866817,3587797272527493612 +e0ca4205-0070-dfc8-3ca1-7282179f3164,4185219031,12297216966200645330 +78a6954e-51d8-4257-e9d8-520b326c5fce,1298244696,11261353541197794230 +3675ceac-e5d8-3293-ea2b-9720c5cb646f,4090984184,12220444472479005563 +51e7e546-465a-bb76-e53a-db348c61d331,3679999081,14291288790628007324 +3b297504-8c17-273d-ed0d-4f9f2786b849,2789123759,1073904439173401183 +71a1b370-af23-4281-588c-a7b87cb2fbc7,3438714603,16714078222664098487 +9bd6946d-ff51-a055-6004-3911185ea5f7,1089630502,4775136394297757016 +24c28172-620a-cc81-a012-28525fb1b6f3,1844023943,6264823123589319730 +e0d6d4d8-fbba-3b93-0b78-6983959a5822,505641792,3894366589265047972 +28c19cce-d8a2-aad9-1f8f-cfd87d22c4e7,2343065615,16799285165589118608 +ceaea335-d4c0-53f8-1f1a-d2e2fed21d28,2493607632,16410423129122934972 +17230d76-d2d8-6b64-c10f-a75bcdbf7232,4048817643,4871991116533831868 +5edfc95d-ec0b-ea36-0802-3fe7d5a6b41d,2265700981,3801365321080369590 +3e6ced92-0bdb-4c6f-65fc-ff60328267a1,2602022533,16396685920363614398 +9e01950a-39d7-d6c2-6f4e-98ff4f45f4b0,3484405169,3748552435464507549 +35d0d964-2145-fbfe-09df-5ac0d62e6259,2293436411,11401543604359368588 +4d52db47-d866-afd5-7633-72b831adff44,1802996990,11880029633575460772 +c2ed673f-c4d6-9922-dcf1-1ff552183bc6,2378705508,13487575594619432926 +738c3d9f-c942-37d3-147d-1b1d6a1f0923,1880288632,13706569859816532782 +cce456db-1aa3-d1ab-7b6a-19d71d7260cd,859159417,14006779392132879171 +c0e084be-689f-69ef-4bf0-2fd0ec1ad052,1007995375,13807076772557707863 +6941f9c3-df30-4acf-e3d9-8f9f987810ef,1517512925,10838462978003356315 +1d8bf81b-8b2f-e7fc-689b-8e803881e6c0,4211298402,12985797220885010198 +6b4d7c28-d609-e650-a520-8f5a0817d7ba,3578743462,2847043226473020460 +f0a96465-7cf6-ddce-41c6-2b9a15efa11c,3044624199,5542397395063337613 +9366acd7-2997-5867-4606-11c8f11107df,1527828991,14719000210445272776 +ad374b04-1ae6-120c-35d5-1dbe67d192b3,3627288375,7572994368238914390 +64112cb0-7178-e5b6-5d82-4c79b1d25b0a,946978538,2900197881684247291 +4f69678c-8672-366c-fdbb-dcbc125f843c,3737887662,4863594361099761220 +37c8cf20-2ff2-6eb5-4460-224d1cca1757,4107944883,12841037426352018718 +90be8d88-8818-a269-0b6a-67576e07ead6,77843720,12052707864243472457 +04bd7e35-bcb0-b957-dc12-d436d6b36d64,1361073050,17484151809258338546 +edfa50ed-aab5-fcee-774e-88baa97d7c02,3882164814,8225186369091883418 +86434056-7772-74a8-f99f-87a2ab60e356,3458537391,4790008474350703103 +0cb3bfe6-368c-086c-eab1-32986f3526bb,86204726,1663374340009910149 +5b28b7c6-5052-b5af-c2db-65199546d910,3296066805,659291874932832001 +abbc8fb0-1bf4-adb2-e338-737417b6081b,1172010367,15558011303420429781 +f6fb60fb-1727-e247-e528-77db2478b3cd,3967708050,6791603836014395353 +c6eac5ce-f582-74f3-1ae2-4f78484edace,3422742053,2246435208389284239 +f08bb226-f429-6534-e153-ed5c904b5040,1633586369,1542546043877202658 +52cd120c-a64d-2079-ba78-c73af0a3f249,4278019464,17157321754411640193 +b5736af7-4ff7-3e7b-399d-028e5af4f4e9,2058212056,1969109020295523640 +edea66c7-480b-e735-ed05-0955e597b227,1732109156,2766625260784812264 +bfcc15da-f5d8-e01d-9bb6-b7eca0971d40,323581720,2203174208611362281 +3f9accbe-245a-a150-be5c-a8684e3588d3,282298805,5090494557899525138 +3be4ae7d-ea14-3b8f-c40b-4b53184effde,2386186521,2405029183158448228 +961c2cde-47f0-9142-d292-ea09f5b03a2c,1744721085,14718681138114487835 +1b06399b-35bd-e49a-d5c7-9ebb68beac24,3991205983,12378514687890016116 +0a2a47d0-e291-3f2a-233b-88f0898df7d5,255567264,15802634167718585790 +a6f141ec-4177-28cb-b489-28150f8f09f4,1253129429,7685386873748893555 +8e836faf-472e-4dba-363f-ba9b40eb2635,3537630084,8684289068276865226 +e3357cac-6824-6937-70c7-51776e5391b2,4049681931,1387128101255636142 +64e9914c-8f1d-c6b0-163d-c2bbd943ef23,3704449201,7613733090294519457 +9bbde6e4-8ecc-9aa1-c91d-bdc87f781003,1269786578,10339000422230737034 +55a97d23-a17d-561e-c8f9-a99928469fe3,23722666,9552321896411393217 +2ebba34c-537d-1211-0f95-e57072c4d191,2731485029,2070074356298131803 +4e4c2f17-65f3-d4c8-ebba-c01fc588e130,479867961,5240801851241315439 +22f92e31-0bf5-68cd-dee1-52d6e37e2669,1662097420,2653760832873324030 +27f7ed89-06c2-eb8d-b7d3-3b1b9136ea31,3083875158,13749416859674278685 +343790f0-0def-4d73-92e5-b967bbe9afc0,4123069910,6028907805608558147 +b7341418-4d61-f92c-3880-8a9685bd5f47,1473916590,18202618482709360823 +cbebba0a-c817-7c11-3355-eef0f75726cd,2327761852,12067583967931502103 +a7b8edc9-a692-af9d-92dc-d639bf2712fa,2191637012,9941845415880719663 +06cd47aa-17b7-31a2-2a41-ec21f4c41eef,247451758,17611188176865967397 +bbcaed67-eb69-69ed-8bdf-e6070e63d3c6,3889913445,15721510418023183015 +16f95bcd-ec2d-bdcc-5bf9-ee3b3ba9eefc,670346562,13111944265683191920 +730df4ce-b927-0384-bf6c-f55c0a7cbd0e,37566371,16776293157413731151 +fdaf1b8b-45fe-60cb-392d-ebb893ac4a37,1511258570,14554956458952348213 +35cc6aed-a097-294a-f6b2-15b119d014cc,1171129613,16477287277262375907 +5ef55b86-89ee-a4d8-da8d-1f0be8f672e5,1746307058,1806408554700825467 +776a64c6-5467-9a92-fd96-72351053cdfc,2108610361,15582336791454147584 +08dc5b55-d65e-bbf4-5996-f3e8e6dcbe4b,1309099013,6671597471063174568 +9134c861-9bfb-4f3e-99ae-8394170668e4,2556870516,4073933831402419866 +1189d4ab-c195-ccb6-c1b4-211dc2119afe,3020067508,14545701465463855636 +94d15096-f686-edb2-915e-9a276f24be8a,3442397993,7529683992052710562 +976aa577-9e95-49c4-036f-0e8d12eaac57,3550573215,548636338138447625 +1335eda1-9bdd-b32d-264c-16a28ddcec62,3410970353,4388615592063466214 +e145c586-a9fa-b6a3-3d0e-6c4e8fbc2a6f,3308634063,1932531810519517446 +c4bfc631-aebb-a0ac-8699-5e0cd939070b,370599843,12691927408069551470 +3ed94fa7-cc26-17f9-0ed8-db4b017b26e7,1918085227,15943477193801765963 +b5d0aea6-7333-657d-3c51-a088ab47d97d,3532402164,9713096021212152736 +a4e4d09e-6775-6e63-2865-7aca6fd06e8b,3083873413,13354131618156757942 +2916e71f-0736-3718-2724-94bd75cee2bb,2344492988,12382508110029920490 +c01350bc-eb62-ed71-8d0b-5ed4210807a2,1874462719,4611664751427257384 +826d852d-d488-0562-9721-95ec349239f1,2087059770,482410516492690652 +052926fe-ba1a-5b53-8132-f8e7a2562ac9,2261065027,11388113835731576920 +9bbc065f-b250-126d-4cc9-55c867f9ce30,495233597,10298064077252853412 +0dcd4c74-0451-ff07-db63-9cd29611f1ec,2094616054,9950910879131375584 +25424285-5ddf-6b7d-efed-d12894941f3b,4212697754,13303311281790728650 +1bad1eb2-fb9b-80fb-3c4b-62c1a97d3725,3156092873,9131185838819983180 +993ffe1d-056e-2555-b7e7-7b8a83389a8c,3624233639,17279428357113340204 +8432eda6-5ddc-f192-22be-2ad7a7a6040d,1751354627,16528347363202889027 +8dba9772-1f0d-bb7a-ad0c-3d097ca1eb7b,1720467955,5201810084487966698 +5a0fb643-f923-c402-f9ef-0043b91e7f92,2862938539,8039041701086748204 +0cdb8eb6-bde9-3df3-bffd-a4943d93697f,726580673,9074782919874768118 +40b51d38-f9dd-8f91-57e9-e024987f8d95,1229206735,13294666502306102104 +dea733c3-a7ba-2ff2-e2c6-0459c71a87c6,689217524,13685336074513389342 +9a336cf1-b8b9-b616-1bfd-9890474e82a4,1687607912,19473735009198589 +23931346-a5e9-d67f-c984-eece7356bd21,1956666666,9982745695134143323 +ede66f7a-20d7-0b1e-efc6-a5397496e454,984066322,8522899017646219360 +d2a5ec7f-4353-158e-36e7-fa42b075ed84,2771044761,14969322338906593531 +601ebba1-9bb6-555d-cd7b-5d45615ca1b4,3753714885,14284204260667030329 +f5ada59a-d406-af35-6fd5-983f8704740b,2619915399,11066093766903609005 +c48a781f-8cd0-06d5-d689-3cfc0b223041,958807249,12978025556322420472 +ed4fbe80-6a81-6db0-68bb-1bd40b91a9d1,3347361584,414947662351788171 +dc5da8d1-4229-c185-93b3-13472e093260,4006954378,5693647417708167081 +724e998f-e7fe-be73-4a78-99d63f0d35d6,2332320418,377407375379524801 +ca373437-ca53-6300-2d13-b1c1a776f97f,2048566061,2119200496760611651 +e90a7cc8-262e-305b-3dc2-d97cef54f144,1425659632,18338221310929880616 +001795e0-9777-9c10-995a-87c5a035ce50,56187791,3084088978665572949 +4815dda1-c649-aa4f-7beb-741febbdd7a9,4104447810,10266692640357101535 +17c9b110-86ae-b663-3a62-abd1591901ec,747513429,15081875705018573854 +a08cc533-9325-b1b0-5174-fd2e01b03b14,3651552166,9222904541659426869 +de0fb00c-7296-f356-7ecc-fabc37605a0a,3643521964,6982833818300663383 +f6f8670c-f90d-e749-7ec4-43d81ffe5e5f,3406647068,1149207882190552974 +e87c7e4b-3308-90f6-8a4a-362c7883b254,161668790,16322362847878075172 +32061ac2-e6d4-5043-6440-b709f9fefa53,2811618773,8110903463274528695 +d9451f35-d83e-692d-0a41-0405ae6d1c96,775598319,16735788747137180500 +a33da8e8-c2b9-8c2e-ccb1-105c4a9fd81a,3493908020,11840059698807290339 +5c6937c0-6edd-c069-bade-ebd5ff80de49,3078376152,17948052714388737247 +bbf15227-6a6e-85ae-9e48-108c7f38c523,1450013069,12409891302426173040 +3e98a2bf-7fd9-f578-7b8f-27ec38211148,1705002451,3311137434932433226 +296c2ed4-87a4-8235-fa91-326a0ae6d971,1550199037,17250527299182422481 +1712bda7-5332-52be-d3b9-d7c11dff2b78,1240118504,4330361716699240817 +31abb4e3-08c2-2d81-483e-9828431b769a,2207683491,8185015215168310036 +d6b6c151-b73e-2dc5-0c5a-33475ff2b943,4014225465,4347779997515374132 +cee0fce6-19e9-4c8c-6cfa-52f1fd550ed1,818967351,10387390611379796870 +7d577eab-88df-9712-4ca6-2c8b71445329,7135271,1573012009895416957 +d7531b45-0786-e044-02ac-32ca402d9c17,962886919,2568241723374213969 +e1fd260c-4d57-5597-03d8-9145a08f60e8,2488693704,18230471577799645841 +d58fcbc7-41f4-e6a5-1830-5d759a07fb15,3989172021,14351320574193875923 +e5e8c8df-434b-d7b2-1159-d9addf49cb6b,3771506197,7726186778948982405 +7ed50a84-3a46-3411-46eb-0b9f1e989a4d,3970097968,13399760627389440235 +5666dace-efc1-a1c1-dbfa-28f409428ad2,276668662,224710258032863281 +57f8638c-9fb2-6a0e-df80-4f551983f663,4192025423,449321327060813073 +0ddec4b7-0ed4-0904-8883-b9a438e4c4e5,1269438220,10409136222538537299 +c3ca0e01-6bad-b72b-c318-9a4b6f57132d,2189215704,3172321609552189651 +406c6265-6aa9-a25a-ca30-702f95fa1328,985111055,3623307821041370609 +15613dcd-39e8-3b02-a1ff-eaf6c5f1b1c9,1209166976,4137810008586018615 +e68e7a5e-9e1e-4d4f-682e-3f8c4e7dd635,128367686,6048457201350349195 +742f6cef-6ec4-ce89-9bd2-56c4b7a5e01b,1361937467,11375099311999855247 +81e9bd40-55df-fb3d-4ddd-1a2aa95a10f6,902479020,4241805773854839582 +8a5f39e6-0230-e5b1-4dde-92d8ee43fdf4,573249217,5331848876000638083 +08a85dcb-aa84-d3e7-44af-bbd63f381a7f,728291115,16756309803950694549 +c780a6fe-07af-c7aa-dba2-73e0dfe0d0cb,692009296,2686148350851593014 +63b301ee-4daf-248c-f5df-c30027a67924,1301730885,3461589241293203024 +c1910303-62a1-6071-c606-2d71656a42ae,1684676089,10833735231700372530 +12dc0eaf-cd6a-d2a1-e0fc-047b5b52374f,2804807884,9360475475717212445 +8dc03c1a-0f15-ffd5-ef53-e7b2dc7cb52b,1952914329,15160808293278463092 +682ab6f3-5719-2b7d-89c2-ccf8209eb535,2091127593,10918773622517821152 +1ff65993-e013-7508-c8bd-d70cdf9a71f2,5355993,1681560000710903287 +0688dbfd-4493-b21d-6aad-9208e2849dd3,1980588613,11904832752675381191 +251b0fd2-2755-cb49-1fad-2ffafbef0fbb,263878352,11131388999223795694 +4ceb45f9-6e5b-4ebc-ff01-f4322b45310e,2069677221,17059044069128895357 +ef045808-a4c6-611c-09df-8b967570855f,1392334658,4424011924062698092 +af7e0e14-7007-4e64-0f10-6708169ff563,3638343350,3450532313587171546 +0833f795-0062-88b7-6b47-31efc4c86f6f,651118292,10884699703737825389 +426b2521-5708-4491-ea4f-aac04bd13e35,1465677215,15344371242800048279 +e5a4cd3d-e1c4-448d-4ca4-aa1e49528d7d,3734685017,617716002533225537 +aa9513ae-cbcd-3ead-83d2-c5de4af143dd,3284400325,1806401196123344752 +858a8b8b-b3ee-6ed2-41de-64055f3a4009,2658072111,1197654999873422877 +aab90caf-bdef-9983-4df2-4d4e3dc94909,1721409755,13624677813225697909 +f972487c-97a0-c846-b472-b394b1944b08,544852907,1492779243932587810 +f7336af2-ba0f-d944-5ede-b118bf37548c,4163154267,2943717620429978939 +f0734550-d43e-85c6-f455-d0e2eb903a43,774213828,10886729809427949991 +08021669-ed75-e7fb-d676-3d2a16e131e6,2292685827,4896783400995902516 +6306f787-f852-06b8-f200-b963411c7e4b,1014191179,11131837673575752600 +471c1fdf-25be-8350-5454-1251eea9f0d1,3103224388,18064809593270245664 +1c5c677c-d480-1c0f-4d95-d9675b121418,706470157,15070690153033291672 +59a549d2-5d6f-9003-bb4a-0e75d3f37d56,995297647,13749570842440331837 +4afbcb45-e473-07eb-a04b-52368a7b3292,2900347359,11136670879372185123 +7d2257f8-5f22-e279-54c2-4a222c22b979,835450066,12707247230975875667 +26aecb06-abc9-3efe-c110-bc067894c4f6,916169814,7540875326851460621 +04f9faab-0eec-ffea-1ea7-0657adb79554,648023767,7999178332642554632 +9d1fe657-eaca-5a2f-7b1d-059e0a4417bc,249966975,5151000455218854923 +0aeb7d1c-6734-f446-174f-decc585b93fc,1913854420,17800745045088671551 +5d6e2a82-d00d-5b9a-41d5-49c50578a833,1452574280,2271538896946929197 +76d33605-8bdc-1381-62f4-174a84686280,2310549351,10746580647783950381 +6f9183be-d7b8-110e-43b2-ce033b83734d,2349339035,1846945431590818084 +26c27482-7632-6e78-c14d-6f75553d20e9,552415484,8562383636253067962 +68baec53-5f5f-b110-4d18-fae30d7a5ecc,2336863129,8472711748690374248 +7ee6ebfc-8589-2ace-b73e-8f5dead51082,4118646917,3177240985261171544 +184c94eb-7781-1286-6cba-53185f3dc3b7,2087626653,6826961717913350900 +fb892663-763e-4f90-d47d-15608e56433f,379572683,13230827205788902083 +bab0286e-4513-53ed-808f-e50455352daf,1591785778,2746940953128949003 +f183fb7e-f4fd-8581-a815-91eed30b323a,555138219,17903262622272916871 +50209c7e-2cf0-4c50-77e0-c51ac5de1e31,663672430,10849025845828068504 +407bc21b-deca-b8de-5336-c74f23377760,2167585836,10112140032671037988 +cd5f9b50-2020-0b15-9218-4a6ad9d35b47,596978669,12712639103447393161 +1d5a79f8-fd73-b6cb-64b6-d92de4640017,3590966825,7244008903689349233 +1c091054-be29-71c1-289d-879282b3c80d,1101108583,759771486190255840 +26cd0d6a-7f7c-313e-d67d-b5453cffc9b2,1826770619,7819098431512334723 +95e6621c-1026-1297-d036-afd61ee6970d,2761651645,16161602224444204473 +d195fffb-870e-a459-904e-c1e68921f513,3385170225,11497182853324215267 +7dad54b1-68c0-48a2-e061-bd0bc94f7ebe,4171457460,5784851947377192939 +23d592a1-d9b0-6a33-0312-655f3511bd08,1211140007,10969950349614800616 +939c04bc-270f-94ef-83b0-3d09e510ef08,1712458672,17541657681304082947 +a85a8f34-4247-f587-fffb-c32c2bf11203,3917637329,17585125042211887920 +f8a2e594-4342-20ce-8d17-ac04b939db63,2323817426,14516086266176378972 +2255e1e3-9869-e0bb-472f-9eef57f4fad0,176605679,6922170166269050543 +2e6fc77e-fd27-de14-cdf1-b4b705f7a73a,13582291,9915118524717149905 +0cc6d4f4-e927-68d2-d63f-2c2a05d12ac1,2709179699,11847284907685196912 +378cea1a-f0c9-b6c3-f61c-c8fbd1b3e445,297915082,2340050854759641321 +22c50ff0-4939-0aa5-4081-53a6067e1b10,1732260374,6702671232758620106 +eb339922-3061-937d-fede-043c957bed5e,109228589,14358054547091128053 +c5392891-fca9-c330-5c65-e019e329da83,2340659350,949982718972516173 +e271bc3d-1401-07b5-f42d-7be7ab68f2dc,1819636374,99430926496317538 +9ed1efcb-4619-c3ad-6d03-347b080b5516,3154222505,5818928591294642483 +028cad1a-7089-d9a4-e63a-f687fb23f068,3215572135,15127142134609204040 +81ffd2a8-97d7-14b2-c096-b1e2337b96a6,3199311193,14734249376909855411 +0b0018b7-23f6-4ba5-5398-8608c3a1968a,1692376356,5063791479210171913 +bbd88ed6-f33a-9ba7-ef0a-155efa602c5f,905812250,16296902313551846941 +3438a4b4-902b-f89e-56db-89e06ad0468a,740764047,2042757931307212428 +5ff5e502-8813-d2d5-2f92-b3c24f245e06,2037245994,10961056926382908668 +e818ca55-07e0-ab3b-9236-d062d9aaa21b,2829617621,9305464151704205684 +82ee4d4d-14ae-18ab-b66b-5be42706c3ca,443054335,12510607845436994536 +4705aa17-8e64-02f2-7d09-484d5ff004be,1275129959,7571276205610077715 +39642033-e080-5084-8be2-340a9be046a3,3891670948,5034991376004046340 +8943a91b-0ae9-6d9b-807c-c0074155f26f,649820063,4292906489068969046 +b31f89e8-e42d-5017-8673-887531736a70,3021764734,16286550578455981749 +1d760008-91dd-0a56-1525-b83050089383,3400988747,10774179850134297114 +820671a5-f77d-b883-4a75-00a9efee320f,356587737,11005148146564176838 +f25fba0a-a586-5986-29af-c10ef1b36ea9,305093604,4790146617123804124 +4dd5c57c-a8d8-c213-55c2-669397073cc0,2913976520,13818032066416930771 +dd11a88a-86c9-d212-8f9a-5c69d8014d78,350267357,4075259408672124000 +ecf0aa4b-25f3-8055-0200-e2ed179c8e79,3061371213,5767107044299654097 +ab01da73-a265-6326-d64b-9b334415a39f,2828681227,3411914797686888646 +626f0164-ab2e-8910-4101-a8fc71f5a41e,905667090,11084825918578579893 +8d14b321-4365-2d75-b89e-f8cb2ae76d2b,1986344440,5462726278157003581 +25a24fde-6d1b-077f-8ba4-9000c84c9a9e,1107034187,7572442872756704880 +baf65c1e-5805-1011-e463-e10e8b579f29,3426757899,11722737448548879530 +9a24e1cc-ac81-5e73-bf77-63c9b03aa6e2,221179228,2607163431951900754 +15d1d86c-dc29-1bfc-675b-65cfaabc3aef,2676359298,5250468145227516543 +4254ffd4-4006-c04e-26e6-75a28a530051,3766675164,3980564112403759824 +8f655d6f-aac6-7f26-ac32-266a56d83f33,3744927845,11407936281893779601 +b2659c5e-6b26-4f0a-ac59-ff7262e8db0d,2495413070,4291352343131410920 +f9f62584-6a35-9d28-55ac-7db7b942ecf8,1935205715,6444718887818881270 +68869870-9923-c4d1-2039-5b3b67de51a3,1630305460,14919670489062929228 +7e4095c2-124a-1253-b017-afebc000e711,491874489,9900142262676715803 +d8b9b138-5ff0-bbe7-ee7d-823793317779,3531165455,16093672180989298983 +a3304e30-f16f-8bf8-f2f1-a549566bad59,1605387438,7196636061774460888 +04fd64d2-d4a8-cc0b-8d81-c00b8de070a4,2992102506,7753986195261487107 +a15f0ef0-839e-c8ea-3375-60ea2198033f,623395369,2743822358698824465 +a06098d2-288c-a859-2b43-cdbe88061fd9,1360110029,4166535100693357509 +bf44c482-8ee1-e166-0034-52e9862e746a,1101684874,6268470677370976752 +9c008ce3-0c6d-3107-37ef-6141b42fedf6,289557191,634489412844545617 +b169c73a-55f0-4bde-e230-bc20484700b0,1318259169,5708137278760801211 +c9bff708-47dd-c9f1-963c-d43a8964a024,2448603235,6042655540801336554 +aba09e5d-888d-7667-4873-2eb45d402b56,1316256389,4826061489939284341 +3146e1fe-a58a-1074-cde4-a4fff7ac790e,1927766981,8174175550417216877 +16d86ccc-3bd2-ae0b-a6ae-b9f200508903,3571096299,4844892706660845751 +3a5f87c6-6da7-8103-d2a1-a51e64ef15e0,1184146412,9504631046610309078 +2c24222c-8dc8-f7e3-0e80-83bf1724851e,2467885093,12558018248309248888 +ef65e1f8-a512-3cdd-5964-c5ca00783f80,1351531975,11266615042674972357 +c67030c3-57a8-43a1-cf1f-198c1fa8cc1f,554746817,8838191175543963649 +5d1e1369-9259-01dc-750d-583008458122,3715550120,14173131708892224471 +63fefc87-9bb6-776c-9dc6-5f5a9c6801b0,266218795,8664453070405798211 +3ded6d19-678f-9abe-f51f-ddda55e7bb13,3214874259,12337744500014320200 +5040f33f-ccea-399c-d2ab-882b1f2f4c27,4017731872,12535772431248188581 +3806d815-420e-8d86-d304-71de69664390,2129896069,15840157030573061072 +6b64b6f0-201a-2601-e783-960590bdb593,266160915,4857692812988289078 +0fd386f9-5002-8b4a-746b-26185679541e,2041756714,933858166955598864 +69b598c7-b117-b204-b74a-ea8753d0cd68,2597424058,12975304190008731540 +4e2f8b60-5dd2-0c51-47d5-c79423268f05,996189427,15773345481512578385 +b186fc94-1b85-5a65-b16a-fef39a21d743,287006995,15111670251435782818 +9e608683-ccbd-90ca-58a3-610e6c236d1e,4288323276,13931107885929661242 +e8a65d46-c1eb-b677-809c-800ecdbc730a,1719981983,17286366238580549479 +038d30a8-82a3-2ff1-3ab7-3099a9ed6838,3062731853,17477805259960348269 +a69fefdf-b7d4-ebeb-ba62-720804d4d1af,874844150,12559838828690523839 +d67555f8-5507-5236-f60b-9a6c02c6c2d2,1581805714,1065910951195598877 +702c4491-1c2f-8de7-c313-5a571cbb54dd,1796402189,284075440892792208 +82e1115c-8f1b-a418-d486-caafd286582f,2010990470,5983941795046198513 +c97b9cac-2a28-3427-a210-e1f2ce1fb9ff,2736329311,9188582447047306997 +61f8f668-3735-78d3-1e33-bfb6b5065d9c,631000866,145476087751844878 +8928aebd-6ef6-d95a-4c33-6461b147cbff,2939917153,2268673458093622559 +95612503-8580-d1ed-8ef7-21561e892175,2813612686,543328678658452312 +e28f91c2-1120-2e86-0733-94ba3f754811,1288640275,10043488410647746685 +a02965d2-0828-b5dd-e413-03e85c4483b0,3960305652,13222431697166634636 +8ea8f605-a091-93cc-0a98-38063da97a4c,835359217,9647455789975692937 +9c65ffd7-fbf3-9da5-5833-92eb7f08231c,2492719474,15468964456523074197 +86a3d609-fda1-690d-66a6-a53a0fb7d6f1,1336168647,13680456649337414699 +b2076d92-1ac9-7f52-25c6-b520b9d06412,1924618581,704692911184888624 +884a8c5b-cdf0-a267-a51a-2cd3e41a55bb,3158682260,605611028786259467 +b6e9544c-6d8c-49ed-96ec-2971989971ee,4007260985,9099394830507892710 +c5756264-fc19-644a-93b4-d76aefdba0eb,3446993698,6792515823608644028 +bb57e23f-e0d6-2b9a-5a31-01a739bcd4c4,3544305243,15982769508533679558 +56f3c4c8-19c5-c1ff-d9dd-2d19b6af0ab8,2307782825,14742128910363287922 +8481e9e5-4fa4-8d7d-e9e7-a92601fe5162,976013404,10294231277422089452 +b1bf4b24-d8e5-b612-f824-afc76c564099,199555110,3707124369718464060 +73d4ccb5-a71c-4978-a170-29467c6c4bd4,3371539703,14248600021510796168 +1a3620e7-e7ba-ec78-83c8-d62c352d5e1c,2621988773,5040720709367840808 +b5eeb1b0-24ee-4a4d-5c00-f65c4af2a0a2,1376062214,6288957812666035302 +5a4276a4-9a4c-59e2-a433-cc350a8f683b,1960534020,4548140189888192722 +fa594eed-1e93-e930-5159-a395fc927a9c,3430005786,366513627655065035 +afadb1a1-b6b7-9748-b44f-96925943b1b5,682477770,12407361966144930454 +863a9ed3-d246-deac-f70d-67f816441597,890964568,2545692170620664732 +9bfe0ada-23ca-dfe5-eb7e-3cc23aebc83a,1756324899,12264498506078290283 +1ad42799-1d00-d54e-ecb3-e0f7aaa1dc64,1479802306,4875596086702704087 +a9439a3c-87f7-ef03-1b27-2124bd9e0dea,1028821630,15725505610154069930 +e2904eeb-d6bc-191c-eb86-608b046414ce,1507103721,12566709449765285976 +1e58def5-c596-ff9b-8637-0540a4445f57,2560215139,6510907842728959936 +ad77c8ef-2b32-d49d-2274-ed082298ebda,3224285618,17887187248831070392 +7295bf31-1d0f-6341-3d45-f11dcbb60bc5,2338971574,11376297933254568064 +21d575bb-c955-bd86-b7ed-7cd5f7f6bc39,778302342,5761481438252532298 +c7dc9247-aeec-ac03-3b54-c05bec98995d,3824013256,9486479625704327925 +173c5805-2a5b-8bc9-a8e6-9a8eee52a65e,2217303623,11304603913618560198 +4fe8462c-6691-ff69-b7a3-55c044970769,2862820048,776268941950842774 +f3354d7a-c213-0d1c-9ef8-a28ba8315246,1010099818,10749717330049307356 +8babfb4c-7eb6-7f16-b43d-68a50fa710e1,3726694981,8692842207129678688 +e508aff3-e4b8-e93e-1e89-2e36f922b675,30060823,2893584069472498262 +127edcc6-97b2-f4ad-80a4-b51273d834e2,3965857866,3303407906573452504 +a9e6ba6c-2f0f-f27f-1c22-64636a0ed2c1,712350190,11091652010142857417 +9d930974-d193-2b4f-26e9-36126e570cad,2743665693,7996493039011664261 +57a30535-f911-6568-8fb0-b4a5d23c3e7d,2952356951,13912746008324326332 +f000bc34-165c-47d2-e064-a46cd6f559c6,1722278421,13681153333018939504 +bdad1bf2-ed21-e9df-9a65-8fca2770e1b4,1453109919,16141705393050606563 +031cf112-0f06-73d4-8f33-68de4c9d4dcb,2146175916,1522203534658638910 +1d7d2db5-b6fb-da19-02ea-640c3b94fd42,698116376,2020579787443434948 +bd907008-2561-891c-5fb0-1adc1241d274,215959483,11698641466155536293 +35d7d66e-59b9-f319-20d5-fe33bcd86a86,3293573545,14429181985396851127 +ee352215-18c4-3a7f-e167-b077c653d9ca,1581477006,1158611192890202794 +4abedb36-79e8-7236-f02f-74adaba30c35,1780586641,3473842205235062539 +33b10f1f-7832-2e25-14ce-32c4e9b0380e,1911887352,3505513971820536187 +b8607604-a686-49ca-7795-8637ed7b1e09,3958364140,3563736961821766251 +9d762e77-4ae9-d850-a0ba-70722c09bfe4,3066411837,18256064374050970053 +977db6ce-26f6-a2b3-8e28-d3e1237924f2,1846919556,10563916700975740779 +e9dc2aa7-67b6-8fef-550c-43d9ed3b6bf0,336841953,1449100298818957430 +82a41f7f-aa06-e811-4882-71ee41404acc,3410445559,11239957036040988222 +5e1a0c99-e3de-51a4-9414-bf8a49704402,1305842920,1528660020574647564 +2c4a30e2-6ae4-0383-69d3-dcdb7f31e699,3967550878,2897085361830377172 +dbe0a691-029e-8149-310f-4f0c1fe1603c,1353131565,1103005315519594773 +6f0cf28c-3547-7897-f3dd-17dfd83c43e8,3883361625,10968216249125028337 +51dd6a5f-0ccc-a518-b3a2-0d525d26135e,796376985,16457042553719302842 +939e3edc-7a6a-511c-3832-e975ed42a495,714260257,3810099941218859357 +9836cb14-da53-848e-73bf-5e57d67516dd,1538103023,7509897936482511213 +cd85db6d-d2d1-b31a-6465-838e6cd7bd9a,3513632407,12258432749541286498 +cebdf8dc-f8d8-1033-d127-a814f143d9d7,4247936921,16154715062122779365 +264c04dd-3ffe-219e-1d64-8b47bdcb87c9,3577749920,13604893658158753971 +f1b79ec5-6929-5d42-4d0c-9508277ee71f,2541576408,4485417603491762263 +d795d325-8f46-2dcc-18aa-c60f630391f1,3891383526,10313868429981247554 +c752f158-99f7-d913-733f-781801a2a10b,3304215314,6331518380991223765 +ad3a9450-eb0c-9e57-4871-de81d2d3b5a3,3586180632,5717975580842709053 +13716cdf-76b4-3d54-a628-d7fc57636395,2627715854,1271122351039361163 +9e0acb28-18e2-09d6-e7b2-492bf9333d63,1693561689,8115129786729929703 +93e64116-e762-4039-6d7e-efd900648636,3864224291,5846732751453673442 +320a8a36-c911-5cef-512c-997d53522100,3513106303,1708717293129574394 +50d3a837-d0c7-4c0b-7936-14918061730f,104811598,1918809163759727642 +6e845ba2-16b1-addc-6d36-1b17e535b81d,3994232222,11487415410845278365 +e056be78-ad91-83ea-35c2-dabc42d2d45c,2833606475,8153089149128914220 +84aebc84-981f-f931-3cfd-0354d3d3aab3,2510674754,16002588499654689165 +c3a6fedb-fc4b-0130-0a25-e7c8ccdd1865,636973361,5398450804722398284 +55356324-bf7d-d093-1c97-bc1dfcc5b017,3532607270,12557018929704705861 +16518b13-90f0-fb2e-5d08-b9aaaebed87a,964357088,6351029100523077013 +1b36510d-226d-b07e-ef36-d08a65641a82,2448158478,12331715113814990169 +aad1831a-f0c2-4dc8-d659-d7b576bb559a,1981276588,5819254760140330449 +082bd394-45d1-f97b-bf20-ba9f40b4a6da,655591672,4849394986707086400 +75f4d805-a1d8-9e9c-a65c-9af10857deb1,124026739,15238672304858989591 +66b198ee-1d45-117b-db09-07ced20ada4b,934355506,7007997711145860746 +4b2d727a-a34e-849c-2ea1-a9ccff0f6fc1,248132491,12716914288299656293 +c2d701be-7450-1cba-8d89-39bb0a06196a,502169357,3333581825933563534 +2024ef8c-5e84-992d-96ec-6d756c1d2e04,3101858739,16635981273308100738 +0e606674-1f05-efee-6921-681eab07d9de,2926083836,15637728152057517136 +b8077117-a764-151a-2b0b-65208f8445fb,3822524246,1590777611486629988 +ec4b3495-a385-ad68-26d6-362a6e8fd6f4,924751151,3235248477685793806 +c1eef4bb-8416-c119-2cf7-2070d1245aee,316347302,14591092852491906548 +4b57b989-6b50-4257-7d6d-2708ff6fc9a0,4259639854,12120229635357722789 +020cbd74-ea6d-f9df-f8ae-8a9fcf66f13d,239877381,4539061929005576491 +6fc727c1-6361-2a2d-0e43-df5e0d931f38,1895790374,4532762157339733507 +42b7281a-2d54-5912-37dd-d30ccc2f7509,2924824433,3180367774390315309 +9217c014-0b9d-77b1-5693-efe4e5408425,2505917289,18002980046013170924 +532c4648-ca12-f549-9ce0-c1b91e0eeebb,850831035,5268411552414283925 +808e1378-233f-e449-b6c7-05a293a970cb,1334213158,17787314938512117794 +bb843443-7396-6a0b-e445-364a63416ae9,1234813747,13334645511988070524 +bd62bedc-2525-0c44-811f-6301acae9213,3548730759,2137447094526693508 +8c161932-13b0-71ac-5dba-b3ba38293a1d,4273528473,981022990979728496 +227b3c10-0059-e8f3-3982-67cc011fca7e,3763676823,1954611682039014419 +4ac499fb-2652-b4db-dc83-87622de9d91e,1951833773,11142775676704188481 +8ab452e9-1830-86d2-8833-fa19717abf76,724612649,4509572489633907675 +9e0d7d85-d5c5-7c8b-2877-f9d5d08b51d0,1735025769,10559667658506324052 +86355b68-62a1-e2bc-0cf5-7914161a4858,3857230461,14126234269306939758 +51b06fc1-2371-fbd0-553a-a8c4ef77150d,1435143665,9206472187098323985 +5333cc50-2df6-7f54-af9a-0d09bc67ae2e,4065283694,17425042472532816650 +0f07e97d-2c3a-390b-f2f5-fa07f1c763de,542621673,6663228719587920992 +4ba35aa8-369f-47cb-4751-d24fb1c31fc3,539350851,17808094542001672848 +b105ccb4-5240-e611-616e-4c0a0f9391ad,1535159514,6396847103677979684 +7e6b575b-8ec7-aee8-617c-aecf9a6ea3b8,944919279,4704324521629611192 +2da449ca-55b5-7a2f-5fae-22ad30f71346,2340588668,7574350189375369578 +2be51966-3af5-8a5f-664a-02aadbc4d312,698779305,17926904602556698763 +6c52df25-36e2-3c6d-f802-3f97ea533078,22632160,8023236906104396408 +7d15f7a7-3f36-5c30-8cbb-aaef73b71a7d,2185387833,16639628983225384131 +53f87932-cf9d-6d08-bce5-c05945320de0,2559496965,37085232371956196 +54327979-dd9a-ca08-1c8e-05a466d463d6,112700925,10716240658318128134 +cf39144f-c42f-34c4-8a6c-c40da02f8d53,2977984274,14031084184999026743 +66c7282f-e2ed-036b-b7dd-9cf705ec7642,2386033099,16129456340005144615 +e326ef6e-bc51-9cc5-1aa8-26e647c62910,4001028436,7532937277342912280 +25ee700e-2fe1-9dfc-6976-d86aac473e16,1611812599,4149638964875036439 +336b86a3-c20d-d544-7f21-84fd46063425,4081179494,7564342882197617593 +7806018a-d4f5-a8e2-b0e8-b4b633c3cc7c,3919152402,18187653996512438650 +3a406bd5-ecc4-91b6-a414-084b9c55f8fb,3496632350,5359194697341522930 +28239dce-92a4-d26a-f2e7-efa0b30378ab,1045085343,3428374290126759919 +fed42651-de0b-a1a9-8cee-b09fccdcdaf8,3105408370,12143913979253477078 +efc5b9a2-d67b-cf1e-8db9-1c6a45575f6f,4058149159,14545950582312341631 +29e84b85-0450-95f2-8cfc-6cc864fd486c,1761221833,15016040339677793120 +5cf4c2b4-fc04-8574-5592-a9f05623eec8,3816964254,7467178300239653720 +f2e08e15-b1b4-46b1-1f71-fe4b0ed6a799,3361038694,12583755778303130134 +70beb142-14cc-c0e2-e39f-a75573a6735e,606772441,12009620598347378779 +e92a8385-91d6-2352-45ac-3ba1f210d16d,813569776,8036709251925149863 +fc3213ec-903b-66bd-7a64-db4488ae9f43,3641216778,13563336444723940279 +e9261b96-9e15-6e88-c3a2-df21aad97456,2690416909,3059301478858072032 +9418daae-7d43-4513-9bc5-3faccb7c51f7,1753150460,13878205338360553847 +d6998bd6-37a8-94b5-337d-d72767a07cb5,774886426,14658936529946056931 +c9516019-bf89-5c0e-39f0-e78b24eaa57a,283112054,13297668414140010451 +97fc3038-eb20-b4b6-6718-f07200b3ef65,2233506401,11992312023396398769 +d6fcbc4f-a941-a0d9-c7b6-60406961abb8,2627203632,15576781298725859715 +06624701-8e27-f5fe-d45f-b5904cdeeab3,2765105982,11242403206202804273 +6b26ec09-41d2-b176-5c1e-bc2aba76d7d3,744860863,1416029971348574371 +d79528ed-141c-1b5d-8e06-2658c71d0b5a,2419683650,17761391170417428767 +ce40df3a-2939-0417-5682-bc4a9ab7dc0b,1383712991,6776383371205444294 +f962b326-c9b2-29bf-0670-79ea0c63502c,476490557,8408568751595796319 +0144c2fb-5091-d36d-4287-f201ddb4b8f7,1837594739,14493714240678770005 +01ceb334-41c1-d999-4847-36031f0bed7b,2006972002,16462397162037390909 +985043f0-770f-9d73-94b4-2cea7305d266,779506969,14579920604933005303 +4d4b634b-6e22-ea14-cb5e-0a62aa509948,2276286424,8468721787061419597 +62060744-840a-2cc0-b679-c6c6f0ea03f0,3278231923,14504958982255651156 +a708e3a2-e62a-be69-b886-1675c0782971,125960025,3204206268012943549 +884e9095-0d97-3613-a4df-96647071fee3,1695218137,18371303945553255426 +c73e0586-0ccc-e9cf-7f81-5782997e2a08,2716885512,12955774384624090306 +ade25deb-5b76-07ca-7bdf-ebfeddbdd6a3,2589606474,3343782538934576587 +f5a6c792-5692-43bb-85cd-bfb79e383340,2001708641,3883866854866413176 +c209ba94-fb68-f837-2956-1c6178dce016,903912689,14126288368351921637 +466b6994-4daf-7908-36ac-687ef13b2a9e,2091819507,9786378647549441586 +8f8a01df-0955-df37-b258-634167fa5552,1288007764,5975083168745411788 +fac2e01d-be8a-fa62-e3f9-619b048a4d81,3047719142,3647517507155771498 +ddf4ade6-5709-dbd6-49c5-aba065a498ec,1787883213,18202916652944481680 +a1e8ac60-1699-4059-7400-062e3da71ef2,2675418434,16075067874760211340 +12c14114-88a2-ca59-6272-c8d6ee866f3a,1802729047,17410426337654410752 +b9797a96-b6c4-500a-a2ed-28cd3163aa7a,2854635130,15959945064322538730 +8ce4fe62-949c-538b-157c-6ce3cda67210,4089788353,1076147889953991479 +9fba6717-3ec4-4f28-d3a1-47a1dc3b8283,1014786306,6168840644410785247 +accef49c-91c2-0363-6045-ffb943d0f979,2391767172,6281534313073039856 +daebf4bf-ec6f-c07a-6690-843d2c225db9,3128026737,7384460424563586961 +6e041699-6366-d490-dc50-7b42ce92fdd7,2432639019,13169971689110264960 +04d79572-659a-225b-addb-6f34b16c2b7d,2234394608,10897412864879047213 +4cff267c-f857-1a25-38b0-09f77644d67c,3227606985,8224452207787443242 +56e270df-ac37-7884-c45f-ac525abda21f,853141812,16311515096384120594 +62d344c6-bedf-2cc4-d47b-57d9e2173535,2555601334,11164982087020247804 +0bc31591-67f3-9ec4-e130-f1abf7a2ae33,665707652,9515490903604369565 +48029146-4888-1989-ca03-4c9c39f4aad3,3462768187,17170728828288960783 +997b43fd-7e8b-9d25-91bc-c6b334c2f780,1952033007,4559844032131399243 +dc8b275d-ffc1-2271-f17f-1a3b116fe7fe,3356931327,3980527080019802706 +d5fe0cbc-6adb-24ba-0c96-9ad352b4344e,2343057767,738297616513678267 +5a15bde8-74ef-dca1-642a-c71012121bd1,4124539206,10296573416445938226 +881bc4b6-6b00-6660-017e-7cb6ed2c602b,818290922,9793833476889164886 +8736b03f-bba4-a236-5ead-8f660fd18b4c,3437445009,14305509169500794936 +4bf77e1e-8997-bcfd-d59e-f50729fde874,3974459951,6271441678140341636 +76b10a6e-58ee-aa51-82f9-5c19a03934f3,2299080898,13098630710590733803 +f5187a75-e98f-4210-f128-52b21c71c661,716983109,15468462449682698138 +92230cd1-2571-4a42-72df-8e8e90ab56d8,3293859516,4942669004457168055 +b33daed2-412e-7a81-a57a-f642a6d76747,1495704312,5122921257206022130 +723577da-1164-b0ed-ed5d-9298af6543d6,1020721836,6995737665962667043 +d2cd9bb1-8af2-46f3-eeef-4bb195e199e1,3737276821,12475816969651597283 +f2fb1b8e-ec94-684e-c4c1-7792c959c193,2042707852,12806334944574239290 +be1e8e97-1dcd-e11f-f8e6-c1a8988c9414,3677708679,9508253525797427253 +70c8289b-5934-6af0-5a6f-bee002d2d23a,1821485577,15127205086789275732 +3b2cdeee-37c5-7eba-7bfa-1cb66a9cfe8c,1203777786,17332968574617884339 +2f2c9884-edb8-960e-6e5a-703c1fe52986,2429076763,1084116428456990855 +aa03af93-6ed9-bd87-7f54-01ea483e7367,3265771215,6698179830991644105 +7f0f26df-6ada-cb32-0fb9-d90bd709fbe4,2156672817,10784826599966585691 +e7ec02e8-a624-60a1-9932-35ec6d86a9db,2599090588,4989970721235576222 +67a2dc23-e06f-b0e2-0a02-a947ac3601d2,2017655082,10827725013398746235 +2cf35e70-4338-ea3a-b056-90c23f75979c,3412960176,10375500911534489223 +4d4c7a18-d332-714b-1ba7-2f1c3fda4076,3089818889,9890220434706375410 +f4bbfd36-f530-58d2-efd2-bb1ba9c9b693,3392121122,3074381759250006720 +72454e9c-b93f-90ae-b94e-4bc68b62fe3a,3018925962,10720682330538248840 +7a3e9f83-9663-ab48-8949-ade4e20b20fa,3650799417,12074631217778032848 +1f8285b7-b60c-099c-ae87-366e2191a214,3017311430,2658628648916806388 +ca0cb282-67e0-54c3-f76e-17cb680c89c8,2717402078,14344551304665320413 +c4a0224a-fc8e-9325-99d6-c75b6d8fd3a1,3267985314,10303353948826610647 +e17c4dc5-4529-6c04-5a31-ef1e6ffd4a94,4263128468,15739070454583871000 +35813756-c517-d785-275b-e8a35d208e6e,3559546358,10711579670735178745 +3ece27f9-8a43-051e-a17b-e9cf567e1186,2722390963,9947968816075741061 +e739a6db-2c1e-7098-21a7-dc96a678c4b5,3582117754,11148089583147633310 +248e13d1-b63c-5bc6-f5a4-1fca8fdc0f69,1871356910,8994984287153637435 +be3e4c59-b668-0061-e9eb-89e2eb43d041,2111161905,2439230810160737822 +e8765038-0859-1006-1500-e1772cf770a4,2350632281,1084636107338386647 +3b4cd52d-d444-b5e9-7041-fc6a14b29bb0,2539454927,2717997358583360032 +d08c816e-14a0-13c6-7f44-707f0ab4d4bd,616289789,17992816679070595633 +175add23-597c-f2a8-c1f4-e7b722403b68,2235291968,15892675119228201482 +6a9137f4-3722-d5f0-bd5b-cf4503a2c396,2219305803,6324015831320110264 +3a918109-ecb6-c9d5-d8c4-74101ea481f2,4183103443,9129444753260888288 +c7056c77-582e-c62c-51be-cc4d1766fa0b,224935463,13126639800379678558 +0639f08a-72d5-eb01-7130-499bbbc46baa,3517385631,10875045179371601037 +30bde76d-0c4b-77a8-786b-a6ff274e99ba,3879757307,15702723306740421306 +56d127ba-7cfa-ef9a-a8d7-037e5f236be0,2184386616,9688524248826220679 +9ee5708d-d24f-22e1-ef59-c5ddd6248adc,1073830284,2067104529503803140 +9bee324c-f5b8-8161-5c83-ff684d3c25fc,2105293321,15000283575250191651 +aab11165-76c0-a5a6-6bc9-81d9767d7d85,2874621227,6815850552781354643 +ccf774f7-0b6d-a0f7-379d-db5bb7d6edb0,3179461831,16093004135819972184 +cda45a21-245b-d187-8f41-1f8ef51ff87d,4274848947,11363707484997361536 +28022011-24b1-c483-347e-4eb75a7a65ae,3114607449,12383581765525280342 +f48ea874-6843-5d90-5f2d-a0ea3c07a556,2682858021,3519772489181019453 +061349ea-3aa8-7574-447d-172e05deddf0,784535434,1530230925259926151 +6a6e8cd6-1728-7f16-d3b2-83d90c60f281,1059204261,11448204614717958604 +2c70d118-88e3-703a-fcf9-769e036ecf4c,2022159494,15933148735977939416 +91b03d46-13c5-24b1-bc0e-7c3521a4f429,274729388,14782259943119777689 +b2ee1974-7f94-f65d-6ea6-24efa9e860e5,1166954334,8830646660159619314 +b881510e-bc37-4711-6716-09cf8d50b7d9,350914667,9084889811140510827 +6bb12646-7927-af87-78ac-cecd4bb8f6a4,1645350176,7628245432648436030 +e7bb7aed-ec38-b83e-ce1e-3e7021703647,680144842,2797389187275945584 +7a98658c-9d34-be6e-6b70-7a6c00d3d844,644581955,9270015707359491726 +79cc238e-0312-6daf-2030-89e0bb9e652f,1148329404,6886484418841844862 +a29fdd06-fa21-7c94-4fb2-a43870b2f5c8,2393328868,3901279577320298119 +3192d5d3-91c5-c1de-70e0-d151614edf8f,3827148489,1540726778688349631 +9a4f852d-49af-ce1b-fd7e-fa39886e70c2,963139314,777992985651313300 +e009f1fb-895e-cca2-def3-f34400bdb185,1601394593,12062803266588501742 +2074b77d-9511-2253-ca8b-316921d02938,944179273,10251380740720954995 +874bdbaf-0bca-be0b-aba8-341616ad2d63,738841958,1486099851940458369 +ca1b2b67-d63f-471a-9035-926e104d7f7b,4027021584,7425252084363772208 +c016c7a2-6325-593f-a248-9366503a70f2,1889362205,12244490078637944537 +7bb64328-d227-c1a3-9768-d08df70f0be4,1058400807,15742601716963836627 +6c2bd690-8d50-54f5-6aeb-428917c2aefc,2636049162,18439893653971696281 +06c45ba4-67e1-0ed5-0595-791b18279fde,933741894,9457973365751210017 +e2d00e2e-4a1e-0f4c-6b5d-048d93b062ee,472938716,2564252054714309440 +30b7fb71-19ec-454c-7d6b-805a9fbc16c3,1708667176,17528335108417047455 +0bf389ea-9985-7010-9e6c-7d98089bc94d,252673321,615424884354843975 +196f6e33-7162-6113-c5ea-9872d1219f93,770708953,13846392994622500743 +21ffc9e2-d903-fce1-a863-e2eae0d3775c,3093326244,5579929906717137638 +f1f7359b-15cd-1f4b-95ce-12452fa2d27a,375840143,4755303172402994922 +c6883654-0bd3-f250-4224-6b9fc0de8bbc,3870847027,13842359387041756714 +f711cc39-73c5-2915-60f5-ffda48572c63,1297131983,5413576743108418592 +75585cf0-5529-0eab-95a5-59f46a898e9c,2790494775,16742151740087170504 +a20dc470-777e-be35-7108-014c0b779800,3741300996,15723284745150877280 +1d945207-fadb-e630-956d-41f079b86e9e,4071617874,5329755014149525492 +8c783aaf-336a-9034-0a20-b36dcfd87ef3,4139538104,9747287738986699761 +24c13429-2dce-f062-5a23-c3f97e684a95,3576289414,993310855788411418 +cf5fc72b-bdbd-f791-5e27-e62e79ad2e31,636868136,9982674194143109027 +c9e0d559-84cd-d377-7095-5bfdf7acac2c,4084049483,842585440731674585 +96c6659d-f2c2-bc4f-1975-7a96043b264b,3819187656,15817708173869191943 +f043cfa2-9ee6-0fcf-d21f-a703b0b49419,1701103699,6648674761204277693 +7b51af6a-d113-081a-185c-46b8e906f950,2266321473,2448117403494498856 +80db6476-a357-7b62-8191-127b5d0a35ff,651999881,12065482993704083385 +7fadaa39-943a-b8d0-8827-c383d1e41a6d,4172002985,14322181466456878945 +14370aea-1d1a-8c6a-f973-64645e6af06a,463486812,12182639765577960118 +3b1e02ca-6f4e-c259-2480-419341847d77,3320292813,15704602139585948851 +6822b43c-1303-f5ab-3d3a-26f475eee768,1276062185,8159711004817238994 +0080591b-9a36-e4be-a5c4-b672d4acafb7,1984735495,9454838365639927813 +4e76e25e-e456-5982-2a28-9aae022497a8,2815974096,9715401631568169086 +69107627-ac31-ff1e-6802-3381349f37eb,3381111064,4907348930521345207 +614237b1-03af-e0d3-ea9b-9f9b0124fc8e,2916885699,15569059264950236771 +044ccfff-7ed0-1593-8c03-013004e75915,785571226,14010114435070049721 +9a89abaa-ed9d-88b2-18ee-737e3b31c22b,1469610683,5850027495884508011 +f3204a19-9ce9-daa3-11dc-5ac42647b518,2360335029,10264333636407996487 +a1be69ce-ad78-beec-d98d-2d6cdeb7afbe,991690080,7986167140094496768 +8d1ea0c9-652d-7be9-a4ae-855ea0901944,2126935052,629272982724036533 +14068c92-03a2-01a5-1ff5-0b1ca3889845,2193725078,126009354263885536 +8314d3d5-ddba-1545-b894-e9d43088f224,2334134,9042891819209151766 +b8f54681-b6ba-9e20-8cca-340679d94b64,2566604428,8853613598203450565 +a5d0e175-98f5-9aeb-6f48-359ac19d01fc,2475544605,13612769365419403789 +395efa74-1cd4-2427-9529-fbfa9cb23b66,4292508656,10201912669050181692 +b22ab636-fc9c-7ba0-8845-b269786c1fce,232461120,10220095186715790753 +365a711e-a4ca-2434-7dca-184fbe2369d7,1048478457,9971996529711137806 +6bf966d4-2b59-25d1-0599-76e313c75de9,1739998644,16636957318038088782 +617249b0-b064-4e0f-14b1-8f12a4fc59ab,2700433787,335530846059132651 +e7d3ee80-bc27-523c-e6f0-fe384de94bf3,1829412233,3551650817535438747 +2c285e0d-ed3c-686a-310e-5d9ae8239b32,880974,8509688931257151967 +39defcf7-a73e-2c1f-cb4d-3c435de724cf,3125869857,10216008095289768839 +595ffb52-84a1-e6f2-d0b9-a2e811d0323e,2934993522,18013510281129621393 +5595d308-fc6c-2952-3b21-7bbeb407b19e,1038380832,6717966821827441726 +85c6c9ab-ad6e-1f11-d253-f62ef2959bcb,4047330296,12545928142420340283 +caba4a6e-c080-d83b-1c21-de2056c07adc,3377614995,14069469015421488310 +acd3568b-061c-950c-a2f6-dec22f752743,1406997137,15863128614460253878 +fb3b2aa7-afb6-33e4-782e-3c475a6b2be1,1399337108,7095186875253019371 +a014b3ee-86fe-2cbf-4913-536c815683c7,2200857928,9349093538758023643 +ada013e3-27f5-a5d9-34e2-c8bf4347f9f6,4151694086,2492706430505939534 +7f516a7d-4ed5-2143-4962-ce61b2c2cc1b,878670581,6141828318815426102 +3e5326ae-dca0-4335-d63a-15a2cbb1719f,3839287036,5005965360802615010 +a7e9017a-5c1b-e201-f93c-15c6852728b6,1105108985,4243146656378005509 +3c8ff244-d066-eb0e-c293-9eddcef713bb,891406796,4329257715161424622 +209b2b1f-4baa-ab70-a27a-f36eb179b2aa,3552376828,3262698835911147365 +14d80660-27f2-d86f-78b3-c297420fce70,1569371653,16760862595663606627 +348d57ff-f7fb-86f0-f566-08d48ddfd31a,3186255788,17015585907449719817 +ddcc7b91-c167-5259-1059-43b505b60dc2,3210102609,14792287226365902989 +b98e7e13-87c8-788a-c89d-235d3d4e8231,373694529,18120240371665619446 +876149d8-3a15-2d7c-6ff2-2792978f09d2,3548675550,18184006412186500180 +f9bd9a52-d8b6-b1a8-cf9a-b5133c66540b,4106592053,3343412138853842926 +a489d90c-4ba8-808f-e56b-32d622273307,3277582381,12379815772571092429 +10374211-f43e-0e9e-840e-07d38cc94381,3094262208,8303251583916038001 +b5a41c6c-4cd5-dc84-c23c-1fc836d9ffe9,2810915269,6769984576435654991 +a8ba46c7-44e8-367e-f774-728519918cc0,3635886840,12751868982062489646 +fbdb1b4b-6a8c-4b6b-5af5-a1d5740678eb,3905260164,15872787286282777100 +b8a473fd-20ed-d567-7631-24934feca6ee,3320390884,3330674374834724687 +5ec2e1d2-4bae-3856-78fa-4959fe6132c6,1729274572,13891194348088750832 +793da42f-17ab-ec6a-b05d-21b61491b928,1115766243,987730652366770939 +f476dbcd-6bd2-6b7f-785d-bd9dc426e97a,1314790471,7298299925007835965 +e7451d22-f500-31d0-bfe3-e959c2bd111e,3978328463,12848987777254899857 +fa2e1148-9a50-1ad7-7ae4-3cf2a9bcc1c0,3466198488,16518370341181139107 +74bb4f56-336d-8795-22b9-d7f5d54ac880,3768997639,4103115817127505030 +e65b1c04-3259-88bb-ffc7-71176cbcd6da,1858089179,3157877795226076575 +2d142b3f-2470-ef45-5ca8-a983cf9cc14e,2335220351,10699700520544641160 +85118c55-d897-9df0-d705-161f214b2267,4126672204,12103803096954905851 +3e749bdc-34a0-901e-1555-7ee7ce9fba89,3961252566,16247276214707640926 +76f4658c-bf8b-673a-b9ce-56e0d6d10895,482234233,8220442989470862527 +b96c47ed-2cdc-352b-d493-cefb88a44d30,3758847578,16118446647972406760 +90fe8e3e-06ad-788b-4df1-47dad41697f2,1763468790,17079996962672367164 +601b47cf-ba35-b5ec-88a7-215b7ee14a93,1278436280,15060273520144697558 +d6fafdbb-6063-c068-2ca9-8a8189b1c4d8,1974195847,6120346604011854919 +d5241ef6-6102-b4e1-0d6b-a14974484009,3659032147,14515976548943068344 +3cf55a31-788a-4728-4ec5-707796c4da2d,1936744076,18079430317039268056 +56ea5acd-9f2f-8c7b-4c44-8c42fb0e4001,499611274,17385657600823680441 +b0d9a9a2-80b7-f169-bebb-8b81231850e4,2998867058,10118168048896507541 +7eea90b8-1331-bfa3-1934-65b7834041c9,1299292874,14447611595277188504 +07728fe4-07a1-12e2-5023-08faa384dde2,2144200252,15350269030537814981 +b603b54e-2b21-afd4-2c55-43bb52cb5109,940683333,17449570312818517696 +f7116901-8e4a-33bd-64d8-489beea38d77,2700691956,3372688301104017843 +c690ed4e-db91-e2d5-258b-34ef88cd3ef8,3388377037,15027212647658382773 +988ef68e-1f53-4e9f-6f3e-8c5a5d8a370c,2217667961,6770447100450212039 +17e8199b-e348-5ffe-6556-0cb92601503c,28596841,1870006961411727820 +fb7d6d15-f156-c0a8-bd19-1163d0fa6992,931330117,7043939858994242101 +a5c0d568-90ef-345a-c288-33d869289312,817666752,14808040926764325968 +98fe559b-705b-dfa1-4f2e-56637d6d3ba6,3970529875,1715824210714730230 +e2e5ce19-07d6-5227-1f81-39af25ca16fe,867929685,14715786986142247244 +80af3b36-f6c5-159f-9c5d-44991645b2fd,4045215010,16480073200930346277 +f7c440aa-3d18-e4be-5725-ae9616c31591,249488826,5768010562868445838 +5c8b4851-7121-f360-9ae1-1848641622a2,2428198386,12280765021781666548 +d271f76d-4cd2-872b-6d80-88429b60ed29,3202506778,4187901301328674792 +c950e8ec-41ff-02de-5b67-df199f37630e,2615048735,15181156579559740236 +227ff481-ec4e-52ca-a409-98308bd5c2e5,1820414882,410090942649767883 +b33a60ef-48a8-c776-1869-6ac1794435fb,2034219663,11869243037976111356 +a0e2b142-4941-ce41-a179-87830446ee12,2666999589,4750868503658157558 +d50a1dc1-abfa-03f5-6812-16db0af284c4,3692243512,11855589696440993438 +2507c6bd-77d9-2460-a55e-6b05d11dad69,3376418354,17573794480351706509 +9be13da6-143e-e4db-952a-fceb4e8d6a77,2736003450,16026210933360912674 +09d60c98-83db-2170-00e2-668bb640f534,923076746,10789467866923175879 +85d1e882-16e4-05ff-6cad-788238fd14ca,462148659,12106134642559129080 +ff92ef0c-139d-f5a4-8c12-28b0e52b2e48,2879114165,10279517488304018464 +c6d02b94-3efd-452b-a0ae-0a0fec16b869,1401421537,10980300573058539465 +3b426c7d-d1c4-8d16-9209-4c4f33a4ceba,403443415,9181380260439684750 +12b7c11f-5b44-65fe-8fdb-458b118708fc,918202423,1764600184576359082 +beb886cc-8f07-c854-e382-db8e9629c8b8,328513993,7192893763586643611 +8097cd28-8e49-b2a5-8893-0a2e1a601f27,660038238,7859023191735182735 +703e6e30-334c-01d8-080e-c244fe67653c,1698274406,4936370077472915993 +f2a5d606-139c-21db-8b86-17650d6728bb,3682955234,9144007866246471937 +be001730-1ade-8cbe-dab4-39ab54983ea1,1665702936,11767442386745305050 +3c4de722-79b2-6556-bdca-7f76279cc7eb,628780731,16103238694043484205 +08835f48-240a-6a5d-a897-780bd895eb62,2601204975,11592286269088812614 +fb3fa9f0-da3b-b0c4-8ed3-2e7d9f940291,4077118238,9171791095214677756 +867c4a87-f146-07bf-c64c-823c24dd3079,3094456126,4971549481928415588 +516627fc-4e5e-fcba-7dc1-834d1d727035,1441460550,4370197136600931237 +e457d6b4-df5f-6dba-8ae1-f6ace8a9128a,2295299468,271234660468641933 diff --git a/src/utils/murmur3/__tests__/murmur3.spec.ts b/src/utils/murmur3/__tests__/murmur3.spec.ts index 2246b450..0f3c8eb6 100644 --- a/src/utils/murmur3/__tests__/murmur3.spec.ts +++ b/src/utils/murmur3/__tests__/murmur3.spec.ts @@ -1,6 +1,9 @@ import fs from 'fs'; import rl from 'readline'; import * as murmur3 from '../murmur3'; +import { hash128 as hash128x64 } from '../murmur3_128'; +import { hash128 as hash128x86 } from '../murmur3_128_x86'; +import { hash64 } from '../murmur3_64'; [ 'murmur3-sample-v4.csv', @@ -35,3 +38,64 @@ import * as murmur3 from '../murmur3'; }, 30000); // timeout of 30 seconds, since this test can take more time when reporting test coverage }); + +function dec2hex(str: any) { + let sum = []; + const dec = str.toString().split(''); + const hex = []; + while (dec.length) { + let s = 1 * dec.shift(); + for (let i = 0; s || i < sum.length; i++) { + s += (sum[i] || 0) * 10; + sum[i] = s % 16; + s = (s - sum[i]) / 16; + } + } + while (sum.length) { + hex.push((sum.pop() as any).toString(16)); + } + return hex.join(''); +} + +[ + { filename: 'murmur3_86_uuids.csv', hash128: hash128x86 }, + { filename: 'murmur3_64_uuids.csv', hash128: hash128x64 } +].forEach(({ filename, hash128 }) => { + + test('MURMUR3 128 / validate hashing behavior using sample data', (done) => { + const parser = rl.createInterface({ + terminal: false, + input: fs.createReadStream(require.resolve(`./mocks/${filename}`)) + }); + + parser + .on('line', line => { + const parts = line.split(','); + + if (parts.length === 3) { + let key = parts[0]; + let seed = parseInt(parts[1], 10); + let hash = parts[2]; + const result = hash128(key, seed); + + expect(result.substring(0, 16)).toBe(dec2hex(hash).padStart(16, '0')); + } + }) + .on('close', done); + }, 30000); // timeout of 30 seconds, since this test can take more time when reporting test coverage +}); + +test('MURMUR3 128 higher 64 bits', () => { + + [ + ['key1', { hex: '15d67461d2044fb3', dec: '1573573083296714675' }], + ['key2', { hex: '75b93494ef690e31', dec: '8482869187405483569' }], + ['key3', { hex: '6f76f1df6ac38fea', dec: '8031872927333060586' }], + ['key4', { hex: '5ec727b58617b474', dec: '6829471020522910836' }], + ['key5', { hex: 'b07087d10f0143b8', dec: '12713811080036565944' }], + ['key6', { hex: 'ddcd11333e54c85c', dec: '15982449564394506332' }], + ['', { hex: '0000000000000000', dec: '0' }], + ].forEach(([key, hash]) => { + expect(hash64(key as string)).toEqual(hash); + }); +}); diff --git a/src/utils/murmur3/__tests__/murmur3_128.spec.ts b/src/utils/murmur3/__tests__/murmur3_128.spec.ts deleted file mode 100644 index dc8bed45..00000000 --- a/src/utils/murmur3/__tests__/murmur3_128.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import fs from 'fs'; -import rl from 'readline'; -import { hash128 } from '../murmur3_128'; - -function dec2hex(str: any) { - let sum = []; - const dec = str.toString().split(''); - const hex = []; - while (dec.length) { - let s = 1 * dec.shift(); - for (let i = 0; s || i < sum.length; i++) { - s += (sum[i] || 0) * 10; - sum[i] = s % 16; - s = (s - sum[i]) / 16; - } - } - while (sum.length) { - hex.push((sum.pop() as any).toString(16)); - } - return hex.join(''); -} - -[ - 'murmur3_64_uuids.csv', -].forEach(filename => { - - test('MURMUR3 128 / validate hashing behavior using sample data', (done) => { - const parser = rl.createInterface({ - terminal: false, - input: fs.createReadStream(require.resolve(`./mocks/${filename}`)) - }); - - parser - .on('line', line => { - const parts = line.split(','); - - if (parts.length === 3) { - let key = parts[0]; - let seed = parseInt(parts[1], 10); - let hash = parts[2]; - const result = hash128(key, seed); - - expect(result.substring(0, 16)).toBe(dec2hex(hash).padStart(16, '0')); - } - }) - .on('close', done); - }, 30000); // timeout of 30 seconds, since this test can take more time when reporting test coverage -}); diff --git a/src/utils/murmur3/commons.ts b/src/utils/murmur3/common.ts similarity index 89% rename from src/utils/murmur3/commons.ts rename to src/utils/murmur3/common.ts index 2b733301..03a4363b 100644 --- a/src/utils/murmur3/commons.ts +++ b/src/utils/murmur3/common.ts @@ -1,8 +1,4 @@ -import utfx from './utfx'; - -const stringSource = utfx.stringSource; -const stringDestination = utfx.stringDestination; -const encodeUTF16toUTF8 = utfx.encodeUTF16toUTF8; +import { stringSource, stringDestination, encodeUTF16toUTF8 } from './utfx'; export function UTF16ToUTF8(key: string) { let sd; diff --git a/src/utils/murmur3/murmur3.ts b/src/utils/murmur3/murmur3.ts index 434fcbd3..ea6ed6fd 100644 --- a/src/utils/murmur3/murmur3.ts +++ b/src/utils/murmur3/murmur3.ts @@ -1,5 +1,5 @@ /* eslint-disable no-fallthrough */ -import { UTF16ToUTF8, x86Fmix, x86Multiply, x86Rotl } from './commons'; +import { UTF16ToUTF8, x86Fmix, x86Multiply, x86Rotl } from './common'; /* * +----------------------------------------------------------------------------------+ @@ -65,11 +65,11 @@ function hash32(key?: string, seed?: number) { return h1 >>> 0; } -export function hash(str?: string, seed?: number): number { - // @ts-ignore - return hash32(UTF16ToUTF8(str), seed >>> 0); +export function hash(str: string, seed?: number): number { + + return hash32(UTF16ToUTF8(str), seed as number >>> 0); } -export function bucket(str?: string, seed?: number): number { +export function bucket(str: string, seed?: number): number { return Math.abs(hash(str, seed) % 100) + 1; } diff --git a/src/utils/murmur3/murmur3_128.ts b/src/utils/murmur3/murmur3_128.ts index 18140e29..a9929324 100644 --- a/src/utils/murmur3/murmur3_128.ts +++ b/src/utils/murmur3/murmur3_128.ts @@ -1,10 +1,5 @@ /* eslint-disable no-fallthrough */ -import { UTF16ToUTF8, x86Fmix, x86Multiply, x86Rotl } from './commons'; - -const X64 = 'x64'; -const X86 = 'x86'; -const X64_ARCHS = ['arm64', 'ppc64', 'x64', 's390x', 'mipsel']; -const isX64 = getArchType() === X64; +import { UTF16ToUTF8 } from './common'; /* * +----------------------------------------------------------------------------------+ @@ -149,171 +144,6 @@ function _x64Fmix(h: number[]): number[] { // PUBLIC FUNCTIONS // ---------------- -function hash128x86(key?: string, seed?: number) { - // - // Given a string and an optional seed as an int, returns a 128 bit - // hash using the x86 flavor of MurmurHash3, as an unsigned hex. - // - - key = key || ''; - seed = seed || 0; - - var remainder = key.length % 16; - var bytes = key.length - remainder; - - var h1 = seed; - var h2 = seed; - var h3 = seed; - var h4 = seed; - - var k1 = 0; - var k2 = 0; - var k3 = 0; - var k4 = 0; - - var c1 = 0x239b961b; - var c2 = 0xab0e9789; - var c3 = 0x38b34ae5; - var c4 = 0xa1e38b93; - - for (var i = 0; i < bytes; i = i + 16) { - k1 = ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(i + 1) & 0xff) << 8) | ((key.charCodeAt(i + 2) & 0xff) << 16) | ((key.charCodeAt(i + 3) & 0xff) << 24); - k2 = ((key.charCodeAt(i + 4) & 0xff)) | ((key.charCodeAt(i + 5) & 0xff) << 8) | ((key.charCodeAt(i + 6) & 0xff) << 16) | ((key.charCodeAt(i + 7) & 0xff) << 24); - k3 = ((key.charCodeAt(i + 8) & 0xff)) | ((key.charCodeAt(i + 9) & 0xff) << 8) | ((key.charCodeAt(i + 10) & 0xff) << 16) | ((key.charCodeAt(i + 11) & 0xff) << 24); - k4 = ((key.charCodeAt(i + 12) & 0xff)) | ((key.charCodeAt(i + 13) & 0xff) << 8) | ((key.charCodeAt(i + 14) & 0xff) << 16) | ((key.charCodeAt(i + 15) & 0xff) << 24); - - k1 = x86Multiply(k1, c1); - k1 = x86Rotl(k1, 15); - k1 = x86Multiply(k1, c2); - h1 ^= k1; - - h1 = x86Rotl(h1, 19); - h1 += h2; - h1 = x86Multiply(h1, 5) + 0x561ccd1b; - - k2 = x86Multiply(k2, c2); - k2 = x86Rotl(k2, 16); - k2 = x86Multiply(k2, c3); - h2 ^= k2; - - h2 = x86Rotl(h2, 17); - h2 += h3; - h2 = x86Multiply(h2, 5) + 0x0bcaa747; - - k3 = x86Multiply(k3, c3); - k3 = x86Rotl(k3, 17); - k3 = x86Multiply(k3, c4); - h3 ^= k3; - - h3 = x86Rotl(h3, 15); - h3 += h4; - h3 = x86Multiply(h3, 5) + 0x96cd1c35; - - k4 = x86Multiply(k4, c4); - k4 = x86Rotl(k4, 18); - k4 = x86Multiply(k4, c1); - h4 ^= k4; - - h4 = x86Rotl(h4, 13); - h4 += h1; - h4 = x86Multiply(h4, 5) + 0x32ac3b17; - } - - k1 = 0; - k2 = 0; - k3 = 0; - k4 = 0; - - switch (remainder) { - case 15: - k4 ^= key.charCodeAt(i + 14) << 16; - - case 14: - k4 ^= key.charCodeAt(i + 13) << 8; - - case 13: - k4 ^= key.charCodeAt(i + 12); - k4 = x86Multiply(k4, c4); - k4 = x86Rotl(k4, 18); - k4 = x86Multiply(k4, c1); - h4 ^= k4; - - case 12: - k3 ^= key.charCodeAt(i + 11) << 24; - - case 11: - k3 ^= key.charCodeAt(i + 10) << 16; - - case 10: - k3 ^= key.charCodeAt(i + 9) << 8; - - case 9: - k3 ^= key.charCodeAt(i + 8); - k3 = x86Multiply(k3, c3); - k3 = x86Rotl(k3, 17); - k3 = x86Multiply(k3, c4); - h3 ^= k3; - - case 8: - k2 ^= key.charCodeAt(i + 7) << 24; - - case 7: - k2 ^= key.charCodeAt(i + 6) << 16; - - case 6: - k2 ^= key.charCodeAt(i + 5) << 8; - - case 5: - k2 ^= key.charCodeAt(i + 4); - k2 = x86Multiply(k2, c2); - k2 = x86Rotl(k2, 16); - k2 = x86Multiply(k2, c3); - h2 ^= k2; - - case 4: - k1 ^= key.charCodeAt(i + 3) << 24; - - case 3: - k1 ^= key.charCodeAt(i + 2) << 16; - - case 2: - k1 ^= key.charCodeAt(i + 1) << 8; - - case 1: - k1 ^= key.charCodeAt(i); - k1 = x86Multiply(k1, c1); - k1 = x86Rotl(k1, 15); - k1 = x86Multiply(k1, c2); - h1 ^= k1; - } - - h1 ^= key.length; - h2 ^= key.length; - h3 ^= key.length; - h4 ^= key.length; - - h1 += h2; - h1 += h3; - h1 += h4; - h2 += h1; - h3 += h1; - h4 += h1; - - h1 = x86Fmix(h1); - h2 = x86Fmix(h2); - h3 = x86Fmix(h3); - h4 = x86Fmix(h4); - - h1 += h2; - h1 += h3; - h1 += h4; - h2 += h1; - h3 += h1; - h4 += h1; - - return ('00000000' + (h1 >>> 0).toString(16)).slice(-8) + ('00000000' + (h2 >>> 0).toString(16)).slice(-8) + ('00000000' + (h3 >>> 0).toString(16)).slice(-8) + ('00000000' + (h4 >>> 0).toString(16)).slice(-8); -} - function hash128x64(key?: string, seed?: number) { // // Given a string and an optional seed as an int, returns a 128 bit @@ -433,14 +263,11 @@ function hash128x64(key?: string, seed?: number) { return ('00000000' + (h1[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h1[1] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[1] >>> 0).toString(16)).slice(-8); } -function getArchType() { - // Values listed from https://nodejs.org/api/process.html#process_process_arch - // @TODO Review when supporting alternatives of Node - // eslint-disable-next-line no-undef - const arch = typeof process !== 'undefined' && process.arch ? process.arch : X86; - return (X64_ARCHS.indexOf(arch) > -1) ? X64 : X86; -} - +/** + * x64 version of Murmur3 for 128bits. + * + * @param {string} str + */ export function hash128(str: string, seed?: number): string { - return isX64 ? hash128x64(UTF16ToUTF8(str), (seed as number) >>> 0) : hash128x86(UTF16ToUTF8(str), (seed as number) >>> 0); + return hash128x64(UTF16ToUTF8(str), (seed as number) >>> 0); } diff --git a/src/utils/murmur3/murmur3_128_x86.ts b/src/utils/murmur3/murmur3_128_x86.ts new file mode 100644 index 00000000..a05ad3dc --- /dev/null +++ b/src/utils/murmur3/murmur3_128_x86.ts @@ -0,0 +1,188 @@ +/* eslint-disable no-fallthrough */ +import { UTF16ToUTF8, x86Fmix, x86Multiply, x86Rotl } from './common'; + +/*! + * +----------------------------------------------------------------------------------+ + * | murmurHash3.js v3.0.0 (https://github.com/karanlyons/murmurHash3.js) | + * | A TypeScript/JavaScript implementation of MurmurHash3's hashing algorithms. | + * |----------------------------------------------------------------------------------| + * | Copyright (c) 2012-2020 Karan Lyons. Freely distributable under the MIT license. | + * +----------------------------------------------------------------------------------+ + */ + +// PUBLIC FUNCTIONS +// ---------------- +function hash128x86(key?: string, seed?: number): string { + // + // Given a string and an optional seed as an int, returns a 128 bit + // hash using the x86 flavor of MurmurHash3, as an unsigned hex. + // + + key = key || ''; + seed = seed || 0; + + var remainder = key.length % 16; + var bytes = key.length - remainder; + + var h1 = seed; + var h2 = seed; + var h3 = seed; + var h4 = seed; + + var k1 = 0; + var k2 = 0; + var k3 = 0; + var k4 = 0; + + var c1 = 0x239b961b; + var c2 = 0xab0e9789; + var c3 = 0x38b34ae5; + var c4 = 0xa1e38b93; + + for (var i = 0; i < bytes; i = i + 16) { + k1 = ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(i + 1) & 0xff) << 8) | ((key.charCodeAt(i + 2) & 0xff) << 16) | ((key.charCodeAt(i + 3) & 0xff) << 24); + k2 = ((key.charCodeAt(i + 4) & 0xff)) | ((key.charCodeAt(i + 5) & 0xff) << 8) | ((key.charCodeAt(i + 6) & 0xff) << 16) | ((key.charCodeAt(i + 7) & 0xff) << 24); + k3 = ((key.charCodeAt(i + 8) & 0xff)) | ((key.charCodeAt(i + 9) & 0xff) << 8) | ((key.charCodeAt(i + 10) & 0xff) << 16) | ((key.charCodeAt(i + 11) & 0xff) << 24); + k4 = ((key.charCodeAt(i + 12) & 0xff)) | ((key.charCodeAt(i + 13) & 0xff) << 8) | ((key.charCodeAt(i + 14) & 0xff) << 16) | ((key.charCodeAt(i + 15) & 0xff) << 24); + + k1 = x86Multiply(k1, c1); + k1 = x86Rotl(k1, 15); + k1 = x86Multiply(k1, c2); + h1 ^= k1; + + h1 = x86Rotl(h1, 19); + h1 += h2; + h1 = x86Multiply(h1, 5) + 0x561ccd1b; + + k2 = x86Multiply(k2, c2); + k2 = x86Rotl(k2, 16); + k2 = x86Multiply(k2, c3); + h2 ^= k2; + + h2 = x86Rotl(h2, 17); + h2 += h3; + h2 = x86Multiply(h2, 5) + 0x0bcaa747; + + k3 = x86Multiply(k3, c3); + k3 = x86Rotl(k3, 17); + k3 = x86Multiply(k3, c4); + h3 ^= k3; + + h3 = x86Rotl(h3, 15); + h3 += h4; + h3 = x86Multiply(h3, 5) + 0x96cd1c35; + + k4 = x86Multiply(k4, c4); + k4 = x86Rotl(k4, 18); + k4 = x86Multiply(k4, c1); + h4 ^= k4; + + h4 = x86Rotl(h4, 13); + h4 += h1; + h4 = x86Multiply(h4, 5) + 0x32ac3b17; + } + + k1 = 0; + k2 = 0; + k3 = 0; + k4 = 0; + + switch (remainder) { + case 15: + k4 ^= key.charCodeAt(i + 14) << 16; + + case 14: + k4 ^= key.charCodeAt(i + 13) << 8; + + case 13: + k4 ^= key.charCodeAt(i + 12); + k4 = x86Multiply(k4, c4); + k4 = x86Rotl(k4, 18); + k4 = x86Multiply(k4, c1); + h4 ^= k4; + + case 12: + k3 ^= key.charCodeAt(i + 11) << 24; + + case 11: + k3 ^= key.charCodeAt(i + 10) << 16; + + case 10: + k3 ^= key.charCodeAt(i + 9) << 8; + + case 9: + k3 ^= key.charCodeAt(i + 8); + k3 = x86Multiply(k3, c3); + k3 = x86Rotl(k3, 17); + k3 = x86Multiply(k3, c4); + h3 ^= k3; + + case 8: + k2 ^= key.charCodeAt(i + 7) << 24; + + case 7: + k2 ^= key.charCodeAt(i + 6) << 16; + + case 6: + k2 ^= key.charCodeAt(i + 5) << 8; + + case 5: + k2 ^= key.charCodeAt(i + 4); + k2 = x86Multiply(k2, c2); + k2 = x86Rotl(k2, 16); + k2 = x86Multiply(k2, c3); + h2 ^= k2; + + case 4: + k1 ^= key.charCodeAt(i + 3) << 24; + + case 3: + k1 ^= key.charCodeAt(i + 2) << 16; + + case 2: + k1 ^= key.charCodeAt(i + 1) << 8; + + case 1: + k1 ^= key.charCodeAt(i); + k1 = x86Multiply(k1, c1); + k1 = x86Rotl(k1, 15); + k1 = x86Multiply(k1, c2); + h1 ^= k1; + } + + h1 ^= key.length; + h2 ^= key.length; + h3 ^= key.length; + h4 ^= key.length; + + h1 += h2; + h1 += h3; + h1 += h4; + h2 += h1; + h3 += h1; + h4 += h1; + + h1 = x86Fmix(h1); + h2 = x86Fmix(h2); + h3 = x86Fmix(h3); + h4 = x86Fmix(h4); + + h1 += h2; + h1 += h3; + h1 += h4; + h2 += h1; + h3 += h1; + h4 += h1; + + return ('00000000' + (h1 >>> 0).toString(16)).slice(-8) + ('00000000' + (h2 >>> 0).toString(16)).slice(-8) + ('00000000' + (h3 >>> 0).toString(16)).slice(-8) + ('00000000' + (h4 >>> 0).toString(16)).slice(-8); +} + +/** + * x86 version of Murmur3 for 128bits. + * Used by hashImpression128 because in JS it is more efficient than the x64 version, no matter the underlying OS/CPU arch. + * + * @param {string} str + */ +export function hash128(str: string, seed?: number): string { + return hash128x86(UTF16ToUTF8(str), (seed as number) >>> 0); +} diff --git a/src/utils/murmur3/murmur3_64.ts b/src/utils/murmur3/murmur3_64.ts new file mode 100644 index 00000000..aba873c7 --- /dev/null +++ b/src/utils/murmur3/murmur3_64.ts @@ -0,0 +1,36 @@ +import { hash128 } from './murmur3_128'; + +export type Hash64 = { hex: string, dec: string }; + +/** + * Use instead of parseInt, to not lose precision when converting big integers (greater than 2^53 - 1) + */ +function hex2dec(s: string): string { + let i, j, digits = [0], carry; + for (i = 0; i < s.length; i += 1) { + carry = parseInt(s.charAt(i), 16); + for (j = digits.length - 1; j >= 0; j -= 1) { + digits[j] = digits[j] * 16 + carry; + carry = digits[j] / 10 | 0; + digits[j] %= 10; + } + while (carry > 0) { + digits.unshift(carry % 10); + carry = carry / 10 | 0; + } + } + return digits.join(''); +} + +/** + * Gets the higher 64 bits of the x64 version of Murmur3 for 128bits, as decimal and hexadecimal number strings. + * Used for MySegments channel V2 notifications. + * @param {string} str + */ +export function hash64(str: string): Hash64 { + const hex = hash128(str).slice(0, 16); + return { + hex, // BoundedFetchRequest notification + dec: hex2dec(hex) // KeyList notification + }; +} diff --git a/src/utils/murmur3/utfx.ts b/src/utils/murmur3/utfx.ts index 81a60c21..9bc44270 100644 --- a/src/utils/murmur3/utfx.ts +++ b/src/utils/murmur3/utfx.ts @@ -8,128 +8,110 @@ */ export interface utfx { - stringSource(key: string): () => number | null, - stringDestination(): (...args: number[]) => string | undefined, encodeUTF16toUTF8(src: () => number | null, dst: (...args: number[]) => string | undefined): void, - // Internal use - UTF16toUTF8(src: () => number | null, dst: (cp: number) => void): void, - encodeUTF8(src: (() => number | null) | number, dst: (cp: number) => void): void } -export default (function () { - /** - * utfx namespace. - * @exports utfx - * @type {!Object.} - */ - // @ts-ignore - var utfx: utfx = {}; - - /** - * Encodes UTF8 code points to UTF8 bytes. - * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point - * respectively `null` if there are no more code points left or a single numeric code point. - * @param {!function(number)} dst Bytes destination as a function successively called with the next byte - * @expose - */ - utfx.encodeUTF8 = function (src, dst) { - var cp = null; - if (typeof src === 'number') - cp = src, src = function () { return null; }; - while (cp !== null || (cp = src()) !== null) { - if (cp < 0x80) - dst(cp & 0x7F); - else if (cp < 0x800) - dst(((cp >> 6) & 0x1F) | 0xC0), dst((cp & 0x3F) | 0x80); - else if (cp < 0x10000) - dst(((cp >> 12) & 0x0F) | 0xE0), dst(((cp >> 6) & 0x3F) | 0x80), dst((cp & 0x3F) | 0x80); - else - dst(((cp >> 18) & 0x07) | 0xF0), dst(((cp >> 12) & 0x3F) | 0x80), dst(((cp >> 6) & 0x3F) | 0x80), dst((cp & 0x3F) | 0x80); - cp = null; - } - }; +/** + * Encodes UTF8 code points to UTF8 bytes. + * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point + * respectively `null` if there are no more code points left or a single numeric code point. + * @param {!function(number)} dst Bytes destination as a function successively called with the next byte + * @expose + */ +function encodeUTF8(src: (() => number | null) | number, dst: (cp: number) => void): void { + var cp = null; + if (typeof src === 'number') + cp = src, src = function () { return null; }; + while (cp !== null || (cp = src()) !== null) { + if (cp < 0x80) + dst(cp & 0x7F); + else if (cp < 0x800) + dst(((cp >> 6) & 0x1F) | 0xC0), dst((cp & 0x3F) | 0x80); + else if (cp < 0x10000) + dst(((cp >> 12) & 0x0F) | 0xE0), dst(((cp >> 6) & 0x3F) | 0x80), dst((cp & 0x3F) | 0x80); + else + dst(((cp >> 18) & 0x07) | 0xF0), dst(((cp >> 12) & 0x3F) | 0x80), dst(((cp >> 6) & 0x3F) | 0x80), dst((cp & 0x3F) | 0x80); + cp = null; + } +} - /** - * Converts UTF16 characters to UTF8 code points. - * @param {!function():number|null} src Characters source as a function returning the next char code respectively - * `null` if there are no more characters left. - * @param {!function(number)} dst Code points destination as a function successively called with each converted code - * point. - * @expose - */ - utfx.UTF16toUTF8 = function (src, dst) { - var c1, c2 = null; - // eslint-disable-next-line no-constant-condition - while (true) { - if ((c1 = c2 !== null ? c2 : src()) === null) - break; - if (c1 >= 0xD800 && c1 <= 0xDFFF) { - if ((c2 = src()) !== null) { - if (c2 >= 0xDC00 && c2 <= 0xDFFF) { - dst((c1 - 0xD800) * 0x400 + c2 - 0xDC00 + 0x10000); - c2 = null; continue; - } +/** + * Converts UTF16 characters to UTF8 code points. + * @param {!function():number|null} src Characters source as a function returning the next char code respectively + * `null` if there are no more characters left. + * @param {!function(number)} dst Code points destination as a function successively called with each converted code + * point. + * @expose + */ +function UTF16toUTF8(src: () => number | null, dst: (cp: number) => void): void { + var c1, c2 = null; + // eslint-disable-next-line no-constant-condition + while (true) { + if ((c1 = c2 !== null ? c2 : src()) === null) + break; + if (c1 >= 0xD800 && c1 <= 0xDFFF) { + if ((c2 = src()) !== null) { + if (c2 >= 0xDC00 && c2 <= 0xDFFF) { + dst((c1 - 0xD800) * 0x400 + c2 - 0xDC00 + 0x10000); + c2 = null; continue; } } - dst(c1); } - if (c2 !== null) dst(c2); - }; + dst(c1); + } + if (c2 !== null) dst(c2); +} - /** - * Converts and encodes UTF16 characters to UTF8 bytes. - * @param {!function():number|null} src Characters source as a function returning the next char code respectively `null` - * if there are no more characters left. - * @param {!function(number)} dst Bytes destination as a function successively called with the next byte. - * @expose - */ - utfx.encodeUTF16toUTF8 = function (src, dst) { - utfx.UTF16toUTF8(src, function (cp) { - utfx.encodeUTF8(cp, dst); - }); - }; +/** + * Converts and encodes UTF16 characters to UTF8 bytes. + * @param {!function():number|null} src Characters source as a function returning the next char code respectively `null` + * if there are no more characters left. + * @param {!function(number)} dst Bytes destination as a function successively called with the next byte. + * @expose + */ +export function encodeUTF16toUTF8(src: () => number | null, dst: (...args: number[]) => string | undefined): void { + UTF16toUTF8(src, function (cp) { + encodeUTF8(cp, dst); + }); +} - /** - * String.fromCharCode reference for compile time renaming. - * @type {!function(...[number]):string} - * @inner - */ - var stringFromCharCode = String.fromCharCode; +/** + * String.fromCharCode reference for compile time renaming. + * @type {!function(...[number]):string} + * @inner + */ +var stringFromCharCode = String.fromCharCode; - /** - * Creates a source function for a string. - * @param {string} s String to read from - * @returns {!function():number|null} Source function returning the next char code respectively `null` if there are - * no more characters left. - * @throws {TypeError} If the argument is invalid - * @expose - */ - utfx.stringSource = function (s) { - if (typeof s !== 'string') - throw TypeError('Illegal argument: ' + (typeof s)); - var i = 0; return function () { - return i >= s.length ? null : s.charCodeAt(i++); - }; +/** + * Creates a source function for a string. + * @param {string} s String to read from + * @returns {!function():number|null} Source function returning the next char code respectively `null` if there are + * no more characters left. + * @throws {TypeError} If the argument is invalid + * @expose + */ +export function stringSource(s: string): () => number | null { + if (typeof s !== 'string') + throw TypeError('Illegal argument: ' + (typeof s)); + var i = 0; return function () { + return i >= s.length ? null : s.charCodeAt(i++); }; +} - /** - * Creates a destination function for a string. - * @returns {function(number=):undefined|string} Destination function successively called with the next char code. - * Returns the final string when called without arguments. - * @expose - */ - utfx.stringDestination = function () { - const cs: number[] = [], ps: string[] = []; return function () { - if (arguments.length === 0) - return ps.join('') + stringFromCharCode.apply(String, cs); - if (cs.length + arguments.length > 1024) - ps.push(stringFromCharCode.apply(String, cs)), cs.length = 0; // @ts-ignore - Array.prototype.push.apply(cs, arguments); - }; +/** + * Creates a destination function for a string. + * @returns {function(number=):undefined|string} Destination function successively called with the next char code. + * Returns the final string when called without arguments. + * @expose + */ +export function stringDestination(): (...args: number[]) => string | undefined { + const cs: number[] = [], ps: string[] = []; return function () { + if (arguments.length === 0) + return ps.join('') + stringFromCharCode.apply(String, cs); + if (cs.length + arguments.length > 1024) + ps.push(stringFromCharCode.apply(String, cs)), cs.length = 0; // @ts-ignore + Array.prototype.push.apply(cs, arguments); }; - - return utfx; - -})(); +} diff --git a/src/utils/promise/timeout.ts b/src/utils/promise/timeout.ts index 9a049bec..3ca70b8c 100644 --- a/src/utils/promise/timeout.ts +++ b/src/utils/promise/timeout.ts @@ -1,11 +1,9 @@ -import { SplitTimeoutError } from '../lang/errors'; - export default function timeout(ms: number, promise: Promise): Promise { if (ms < 1) return promise; return new Promise((resolve, reject) => { const tid = setTimeout(() => { - reject(new SplitTimeoutError(`Operation timed out because it exceeded the configured time limit of ${ms}ms.`)); + reject(new Error(`Operation timed out because it exceeded the configured time limit of ${ms}ms.`)); }, ms); promise.then((res) => { diff --git a/src/utils/promise/wrapper.ts b/src/utils/promise/wrapper.ts index 266c083f..7c7779ec 100644 --- a/src/utils/promise/wrapper.ts +++ b/src/utils/promise/wrapper.ts @@ -37,16 +37,19 @@ export default function promiseWrapper(customPromise: Promise, defaultOnRe const originalThen = newPromise.then; - newPromise.then = function (onfulfilled, onrejected) { - const result: Promise = originalThen.call(newPromise, onfulfilled, onrejected); - if (typeof onfulfilled === 'function') hasOnFulfilled = true; - if (typeof onrejected === 'function') { - hasOnRejected = true; - return result; - } else { - return chain(result); + // Using `defineProperty` in case Promise.prototype.then property is not writable + Object.defineProperty(newPromise, 'then', { + value: function (onfulfilled: any, onrejected: any) { + const result: Promise = originalThen.call(newPromise, onfulfilled, onrejected); + if (typeof onfulfilled === 'function') hasOnFulfilled = true; + if (typeof onrejected === 'function') { + hasOnRejected = true; + return result; + } else { + return chain(result); + } } - }; + }); return newPromise; } diff --git a/src/utils/settingsValidation/__tests__/settings.mocks.ts b/src/utils/settingsValidation/__tests__/settings.mocks.ts index 23b8dfee..80aacabf 100644 --- a/src/utils/settingsValidation/__tests__/settings.mocks.ts +++ b/src/utils/settingsValidation/__tests__/settings.mocks.ts @@ -1,6 +1,7 @@ import { InMemoryStorageCSFactory } from '../../../storages/inMemory/InMemoryStorageCS'; import { ISettings } from '../../../types'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import { LocalhostFromObject } from '../../../sync/offline/LocalhostFromObject'; export const settingsWithKey = { core: { @@ -38,7 +39,7 @@ export const settingsWithKeyObject = { export const fullSettings: ISettings = { core: { - authorizationKey: 'asd', + authorizationKey: 'aaaabbbbcccc1234', key: 'some_key', labelsEnabled: false, IPAddressesEnabled: false @@ -61,13 +62,19 @@ export const fullSettings: ISettings = { }, features: 'path/to/file', storage: InMemoryStorageCSFactory, - integrations: [()=>{}], // A no-op integration + integrations: [() => { }], // A no-op integration mode: 'standalone', debug: false, streamingEnabled: false, sync: { splitFilters: [], - impressionsMode: 'OPTIMIZED' + impressionsMode: 'OPTIMIZED', + localhostMode: LocalhostFromObject(), + __splitFiltersValidation: { + validFilters: [], + queryString: null, + groupedFilters: { byName: [], byPrefix: [] } + } }, version: 'jest', runtime: { @@ -97,5 +104,9 @@ export const settingsSplitApi = { sync: { impressionsMode: 'DEBUG' }, + runtime: { + ip: false, + hostname: false + }, log: loggerMock }; diff --git a/src/utils/settingsValidation/__tests__/splitFilters.spec.ts b/src/utils/settingsValidation/__tests__/splitFilters.spec.ts index 3aa994dd..1e23b752 100644 --- a/src/utils/settingsValidation/__tests__/splitFilters.spec.ts +++ b/src/utils/settingsValidation/__tests__/splitFilters.spec.ts @@ -11,7 +11,7 @@ import { SETTINGS_SPLITS_FILTER, ERROR_INVALID, ERROR_EMPTY_ARRAY, WARN_SPLITS_F describe('validateSplitFilters', () => { - let defaultOutput = { + const defaultOutput = { validFilters: [], queryString: null, groupedFilters: { byName: [], byPrefix: [] } @@ -38,11 +38,11 @@ describe('validateSplitFilters', () => { test('Returns object with null queryString, if `splitFilters` contains invalid filters or contains filters with no values or invalid values', () => { - let splitFilters: any[] = [ + const splitFilters: any[] = [ { type: 'byName', values: [] }, { type: 'byName', values: [] }, { type: 'byPrefix', values: [] }]; - let output = { + const output = { validFilters: [...splitFilters], queryString: null, groupedFilters: { byName: [], byPrefix: [] } diff --git a/src/utils/settingsValidation/buildMetadata.ts b/src/utils/settingsValidation/buildMetadata.ts deleted file mode 100644 index 52642f63..00000000 --- a/src/utils/settingsValidation/buildMetadata.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { IMetadata } from '../../dtos/types'; -import { ISettings } from '../../types'; - -export default function buildMetadata(settings: ISettings): IMetadata { - const { version, runtime } = settings; - return { - version, - ip: runtime && runtime.ip, - hostname: runtime && runtime.hostname, - }; -} diff --git a/src/utils/settingsValidation/index.ts b/src/utils/settingsValidation/index.ts index 0f07c330..1840fdb5 100644 --- a/src/utils/settingsValidation/index.ts +++ b/src/utils/settingsValidation/index.ts @@ -3,7 +3,8 @@ import mode from './mode'; import { validateSplitFilters } from './splitFilters'; import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE } from '../constants'; import validImpressionsMode from './impressionsMode'; -import { ISettingsInternal, ISettingsValidationParams } from './types'; +import { ISettingsValidationParams } from './types'; +import { ISettings } from '../../types'; const base = { // Define which kind of object you want to retrieve from SplitFactory @@ -73,7 +74,13 @@ const base = { sync: { splitFilters: undefined, // impressions collection mode - impressionsMode: OPTIMIZED + impressionsMode: OPTIMIZED, + localhostMode: undefined + }, + + runtime: { + ip: false, + hostname: false }, // Logger @@ -86,16 +93,17 @@ function fromSecondsToMillis(n: number) { /** * Validates the given config and use it to build a settings object. + * NOTE: it doesn't validate the Api Key. Call `validateApikey` or `validateAndTrackApiKey` for that after settings validation. * * @param config user defined configuration * @param validationParams defaults and fields validators used to validate and creates a settings object from a given config */ export function settingsValidation(config: unknown, validationParams: ISettingsValidationParams) { - const { defaults, runtime, storage, integrations, logger } = validationParams; + const { defaults, runtime, storage, integrations, logger, localhost } = validationParams; // creates a settings object merging base, defaults and config objects. - const withDefaults = merge({}, base, defaults, config) as ISettingsInternal; + const withDefaults = merge({}, base, defaults, config) as ISettings; // ensure a valid logger. // First thing to validate, since other validators might use the logger. @@ -103,17 +111,18 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV withDefaults.log = log; // Scheduler periods - withDefaults.scheduler.featuresRefreshRate = fromSecondsToMillis(withDefaults.scheduler.featuresRefreshRate); - withDefaults.scheduler.segmentsRefreshRate = fromSecondsToMillis(withDefaults.scheduler.segmentsRefreshRate); - withDefaults.scheduler.metricsRefreshRate = fromSecondsToMillis(withDefaults.scheduler.metricsRefreshRate); - withDefaults.scheduler.impressionsRefreshRate = fromSecondsToMillis(withDefaults.scheduler.impressionsRefreshRate); - withDefaults.scheduler.offlineRefreshRate = fromSecondsToMillis(withDefaults.scheduler.offlineRefreshRate); - withDefaults.scheduler.eventsPushRate = fromSecondsToMillis(withDefaults.scheduler.eventsPushRate); + const { scheduler, startup } = withDefaults; + scheduler.featuresRefreshRate = fromSecondsToMillis(scheduler.featuresRefreshRate); + scheduler.segmentsRefreshRate = fromSecondsToMillis(scheduler.segmentsRefreshRate); + scheduler.metricsRefreshRate = fromSecondsToMillis(scheduler.metricsRefreshRate); + scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate); + scheduler.offlineRefreshRate = fromSecondsToMillis(scheduler.offlineRefreshRate); + scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate); // Startup periods - withDefaults.startup.requestTimeoutBeforeReady = fromSecondsToMillis(withDefaults.startup.requestTimeoutBeforeReady); - withDefaults.startup.readyTimeout = fromSecondsToMillis(withDefaults.startup.readyTimeout); - withDefaults.startup.eventsFirstPushWindow = fromSecondsToMillis(withDefaults.startup.eventsFirstPushWindow); + startup.requestTimeoutBeforeReady = fromSecondsToMillis(startup.requestTimeoutBeforeReady); + startup.readyTimeout = fromSecondsToMillis(startup.readyTimeout); + startup.eventsFirstPushWindow = fromSecondsToMillis(withDefaults.startup.eventsFirstPushWindow); // ensure a valid SDK mode // @ts-ignore, modify readonly prop @@ -130,19 +139,21 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV // Current ip/hostname information // @ts-ignore, modify readonly prop - withDefaults.runtime = runtime(withDefaults); + if (runtime) withDefaults.runtime = runtime(withDefaults); // ensure a valid list of integrations. // `integrations` returns an array of valid integration items. // @ts-ignore, modify readonly prop if (integrations) withDefaults.integrations = integrations(withDefaults); + if (localhost) withDefaults.sync.localhostMode = localhost(withDefaults); + // validate push options if (withDefaults.streamingEnabled !== false) { // @ts-ignore, modify readonly prop withDefaults.streamingEnabled = true; // Backoff bases. // We are not checking if bases are positive numbers. Thus, we might be reauthenticating immediately (`setTimeout` with NaN or negative number) - withDefaults.scheduler.pushRetryBackoffBase = fromSecondsToMillis(withDefaults.scheduler.pushRetryBackoffBase); + scheduler.pushRetryBackoffBase = fromSecondsToMillis(scheduler.pushRetryBackoffBase); } // validate the `splitFilters` settings and parse splits query diff --git a/src/utils/settingsValidation/integrations/common.ts b/src/utils/settingsValidation/integrations/common.ts index 95fa1cd4..5ead4509 100644 --- a/src/utils/settingsValidation/integrations/common.ts +++ b/src/utils/settingsValidation/integrations/common.ts @@ -21,7 +21,7 @@ export function validateIntegrations(settings: { log: ILogger, integrations?: an // Log a warning if at least one item is invalid const invalids = integrations.length - validIntegrations.length; - if (invalids) log.warn(WARN_INTEGRATION_INVALID, [invalids, invalids === 1 ? 'item' : 'items', invalids === 1 ? 'is' : 'are', extraWarning || '']); + if (invalids) log.warn(WARN_INTEGRATION_INVALID, [invalids, extraWarning || '']); return validIntegrations; } diff --git a/src/utils/settingsValidation/localhost/__tests__/index.spec.ts b/src/utils/settingsValidation/localhost/__tests__/index.spec.ts new file mode 100644 index 00000000..663530dc --- /dev/null +++ b/src/utils/settingsValidation/localhost/__tests__/index.spec.ts @@ -0,0 +1,62 @@ +import { validateLocalhost } from '../pluggable'; +import { validateLocalhostWithDefault } from '../builtin'; +import { LocalhostFromObject } from '../../../../sync/offline/LocalhostFromObject'; +import { loggerMock as log } from '../../../../logger/__tests__/sdkLogger.mock'; + +const localhostModeObject = LocalhostFromObject(); + +describe('validateLocalhost, for slim SplitFactory', () => { + + afterEach(() => { + log.error.mockClear(); + }); + + test('if mode is LOCALHOST_MODE and localhostMode object is invalid or not provided, returns undefined and logs an error', () => { + expect(validateLocalhost({ log, sync: {}, mode: 'localhost' })).toBe(undefined); + expect(validateLocalhost({ log, sync: { localhostMode: null }, mode: 'localhost' })).toBe(undefined); + expect(validateLocalhost({ log, sync: { localhostMode: () => { } }, mode: 'localhost' })).toBe(undefined); + expect(log.error).toBeCalledTimes(3); // logs error if provided object is invalid + }); + + test('if mode is LOCALHOST_MODE and localhostMode object is valid, returns the provided object', () => { + expect(validateLocalhost({ log, sync: { localhostMode: localhostModeObject }, mode: 'localhost' })).toBe(localhostModeObject); + expect(log.error).not.toBeCalled(); + }); + + test('if mode is not LOCALHOST_MODE, returns the provided object (it is not validated)', () => { + expect(validateLocalhost({ log, sync: {}, mode: 'standalone' })).toBe(undefined); + expect(validateLocalhost({ log, sync: { localhostMode: 'INVALID_BUT_IGNORED' }, mode: 'standalone' })).toBe('INVALID_BUT_IGNORED'); + expect(log.error).not.toBeCalled(); + }); + +}); + +describe('validateLocalhostWithDefault, for full SplitFactory', () => { + + afterEach(() => { + log.error.mockClear(); + }); + + test('if mode is LOCALHOST_MODE and localhostMode object is not provided, returns default without logging an error', () => { + expect(validateLocalhostWithDefault({ log, sync: {}, mode: 'localhost' })).toBe(localhostModeObject); + expect(validateLocalhostWithDefault({ log, sync: { localhostMode: null }, mode: 'localhost' })).toBe(localhostModeObject); + expect(log.error).not.toBeCalled(); + }); + + test('if mode is LOCALHOST_MODE and localhostMode object is invalid, returns default and logs an error', () => { + expect(validateLocalhostWithDefault({ log, sync: { localhostMode: () => { } }, mode: 'localhost' })).toBe(localhostModeObject); + expect(log.error).toBeCalledTimes(1); // logs error if provided object is invalid + }); + + test('if mode is LOCALHOST_MODE and localhostMode object is valid, returns the provided object', () => { + expect(validateLocalhostWithDefault({ log, sync: { localhostMode: localhostModeObject }, mode: 'localhost' })).toBe(localhostModeObject); + expect(log.error).not.toBeCalled(); + }); + + test('if mode is not LOCALHOST_MODE, returns the provided object or the default one. Provided object is not validated and so no errors are logged', () => { + expect(validateLocalhostWithDefault({ log, sync: {}, mode: 'standalone' })).toBe(localhostModeObject); + expect(validateLocalhostWithDefault({ log, sync: { localhostMode: 'INVALID_BUT_IGNORED' }, mode: 'standalone' })).toBe('INVALID_BUT_IGNORED'); + expect(log.error).not.toBeCalled(); + }); + +}); diff --git a/src/utils/settingsValidation/localhost/builtin.ts b/src/utils/settingsValidation/localhost/builtin.ts new file mode 100644 index 00000000..35a30145 --- /dev/null +++ b/src/utils/settingsValidation/localhost/builtin.ts @@ -0,0 +1,16 @@ +import { ILogger } from '../../../logger/types'; +import { SDKMode, } from '../../../types'; +import { LocalhostFromObject } from '../../../sync/offline/LocalhostFromObject'; +import { validateLocalhost } from './pluggable'; + +/** + * This function validates `settings.sync.localhostMode` object + * + * @param {any} settings config object provided by the user to initialize the sdk + * + * @returns {Object} provided localhost mode module at `settings.sync.localhostMode` if valid, or a default LocalhostFromObject instance if not provided or invalid + */ +export function validateLocalhostWithDefault(settings: { log: ILogger, sync: { localhostMode?: any }, mode: SDKMode }) { + if (!settings.sync.localhostMode) return LocalhostFromObject(); + return validateLocalhost(settings) || LocalhostFromObject(); +} diff --git a/src/utils/settingsValidation/localhost/pluggable.ts b/src/utils/settingsValidation/localhost/pluggable.ts new file mode 100644 index 00000000..3231e612 --- /dev/null +++ b/src/utils/settingsValidation/localhost/pluggable.ts @@ -0,0 +1,22 @@ +import { ERROR_LOCALHOST_MODULE_REQUIRED } from '../../../logger/constants'; +import { ILogger } from '../../../logger/types'; +import { SDKMode, } from '../../../types'; +import { LOCALHOST_MODE } from '../../constants'; + +/** + * This function validates `settings.sync.localhostMode` object + * + * @param {any} settings config object provided by the user to initialize the sdk + * + * @returns {Object | undefined} provided localhost mode module at `settings.sync.localhostMode`, or undefined if it is not provided or invalid + */ +export function validateLocalhost(settings: { log: ILogger, sync: { localhostMode?: any}, mode: SDKMode }) { + const localhostMode = settings.sync.localhostMode; + + // localhostMode.type is used for internal validation. Not considered part of the public API, and might be updated eventually. + if (settings.mode === LOCALHOST_MODE && (typeof localhostMode !== 'function' || localhostMode.type !== 'LocalhostFromObject')) { + settings.log.error(ERROR_LOCALHOST_MODULE_REQUIRED); + return undefined; + } + return localhostMode; +} diff --git a/src/utils/settingsValidation/splitFilters.ts b/src/utils/settingsValidation/splitFilters.ts index 7c474952..eb7b0371 100644 --- a/src/utils/settingsValidation/splitFilters.ts +++ b/src/utils/settingsValidation/splitFilters.ts @@ -3,7 +3,7 @@ import { validateSplits } from '../inputValidation/splits'; import { ISplitFiltersValidation } from '../../dtos/types'; import { SplitIO } from '../../types'; import { ILogger } from '../../logger/types'; -import { WARN_SPLITS_FILTER_IGNORED, WARN_SPLITS_FILTER_EMPTY, WARN_SPLITS_FILTER_INVALID, SETTINGS_SPLITS_FILTER, logPrefixSettings } from '../../logger/constants'; +import { WARN_SPLITS_FILTER_IGNORED, WARN_SPLITS_FILTER_EMPTY, WARN_SPLITS_FILTER_INVALID, SETTINGS_SPLITS_FILTER, LOG_PREFIX_SETTINGS } from '../../logger/constants'; // Split filters metadata. // Ordered according to their precedency when forming the filter query string: `&names=&prefixes=` @@ -39,7 +39,7 @@ function validateFilterType(maybeFilterType: any): maybeFilterType is SplitIO.Sp */ function validateSplitFilter(log: ILogger, type: SplitIO.SplitFilterType, values: string[], maxLength: number) { // validate and remove invalid and duplicated values - let result = validateSplits(log, values, logPrefixSettings, `${type} filter`, `${type} filter value`); + let result = validateSplits(log, values, LOG_PREFIX_SETTINGS, `${type} filter`, `${type} filter value`); if (result) { // check max length @@ -107,7 +107,6 @@ export function validateSplitFilters(log: ILogger, maybeSplitFilters: any, mode: } // Validate filters and group their values by filter type inside `groupedFilters` object - // Assign the valid filters to the output of the validator by using filter function res.validFilters = maybeSplitFilters.filter((filter, index) => { if (filter && validateFilterType(filter.type) && Array.isArray(filter.values)) { res.groupedFilters[filter.type as SplitIO.SplitFilterType] = res.groupedFilters[filter.type as SplitIO.SplitFilterType].concat(filter.values); diff --git a/src/utils/settingsValidation/storage/__tests__/storageCS.spec.ts b/src/utils/settingsValidation/storage/__tests__/storageCS.spec.ts index 8e1f1484..72456b1f 100644 --- a/src/utils/settingsValidation/storage/__tests__/storageCS.spec.ts +++ b/src/utils/settingsValidation/storage/__tests__/storageCS.spec.ts @@ -1,21 +1,37 @@ -import { validateStorageCS } from '../storageCS'; +import { validateStorageCS, __InLocalStorageMockFactory } from '../storageCS'; import { InMemoryStorageCSFactory } from '../../../../storages/inMemory/InMemoryStorageCS'; import { loggerMock as log } from '../../../../logger/__tests__/sdkLogger.mock'; +const mockInLocalStorageFactory = () => { }; +mockInLocalStorageFactory.type = 'LOCALSTORAGE'; describe('storage validator for pluggable storage (client-side)', () => { + afterEach(() => { + log.warn.mockClear(); + }); + // Check different types, since `storage` param is defined by the user test('fallbacks to default InMemory storage if the storage is invalid or not provided', () => { expect(validateStorageCS({ log })).toBe(InMemoryStorageCSFactory); expect(validateStorageCS({ log, storage: undefined })).toBe(InMemoryStorageCSFactory); + expect(log.warn).not.toBeCalled(); + expect(validateStorageCS({ log, storage: {} })).toBe(InMemoryStorageCSFactory); expect(validateStorageCS({ log, storage: 'invalid storage' })).toBe(InMemoryStorageCSFactory); + expect(validateStorageCS({ log, storage: () => { } })).toBe(InMemoryStorageCSFactory); + expect(validateStorageCS({ log, storage: () => { }, mode: 'localhost' })).toBe(InMemoryStorageCSFactory); + expect(log.warn).toBeCalledTimes(4); }); test('returns the provided storage factory if it is valid', () => { - const mockStorageFactory = () => { }; - expect(validateStorageCS({ log, storage: mockStorageFactory })).toBe(mockStorageFactory); + expect(validateStorageCS({ log, storage: mockInLocalStorageFactory })).toBe(mockInLocalStorageFactory); + expect(log.warn).not.toBeCalled(); + }); + + test('fallbacks to mock InLocalStorage storage if the storage is InLocalStorage and the mode localhost', () => { + expect(validateStorageCS({ log, storage: mockInLocalStorageFactory, mode: 'localhost' })).toBe(__InLocalStorageMockFactory); + expect(log.warn).not.toBeCalled(); }); }); diff --git a/src/utils/settingsValidation/storage/storageCS.ts b/src/utils/settingsValidation/storage/storageCS.ts index d8d1406c..9cb762e2 100644 --- a/src/utils/settingsValidation/storage/storageCS.ts +++ b/src/utils/settingsValidation/storage/storageCS.ts @@ -1,7 +1,16 @@ import { InMemoryStorageCSFactory } from '../../../storages/inMemory/InMemoryStorageCS'; -import { ISettings } from '../../../types'; +import { ISettings, SDKMode } from '../../../types'; import { ILogger } from '../../../logger/types'; import { WARN_STORAGE_INVALID } from '../../../logger/constants'; +import { LOCALHOST_MODE, STORAGE_LOCALSTORAGE, STORAGE_MEMORY } from '../../../utils/constants'; +import { IStorageFactoryParams, IStorageSyncCS } from '../../../storages/types'; + +export function __InLocalStorageMockFactory(params: IStorageFactoryParams): IStorageSyncCS { + const result = InMemoryStorageCSFactory(params); + result.splits.checkCache = () => true; // to emit SDK_READY_FROM_CACHE + return result; +} +__InLocalStorageMockFactory.type = STORAGE_MEMORY; /** * This function validates `settings.storage` object @@ -10,16 +19,20 @@ import { WARN_STORAGE_INVALID } from '../../../logger/constants'; * * @returns {Object} valid storage factory. It might be the default `InMemoryStorageCSFactory` if the provided storage is invalid. */ -export function validateStorageCS(settings: { log: ILogger, storage?: any }): ISettings['storage'] { - const { storage, log } = settings; +export function validateStorageCS(settings: { log: ILogger, storage?: any, mode?: SDKMode }): ISettings['storage'] { + let { storage = InMemoryStorageCSFactory, log, mode } = settings; - // validate storage - // @TODO validate its API (Splits cache, MySegments cache, etc) when supporting custom storages - if (storage) { - if (typeof storage === 'function') return storage; + // If an invalid storage is provided, fallback into MEMORY + if (typeof storage !== 'function' || storage.type !== STORAGE_MEMORY && storage.type !== STORAGE_LOCALSTORAGE) { + storage = InMemoryStorageCSFactory; log.warn(WARN_STORAGE_INVALID); } + // In localhost mode with InLocalStorage, fallback to a mock InLocalStorage to emit SDK_READY_FROM_CACHE + if (mode === LOCALHOST_MODE && storage.type === STORAGE_LOCALSTORAGE) { + return __InLocalStorageMockFactory; + } + // return default InMemory storage if provided one is not valid - return InMemoryStorageCSFactory; + return storage; } diff --git a/src/utils/settingsValidation/types.ts b/src/utils/settingsValidation/types.ts index 5a07379d..db801b12 100644 --- a/src/utils/settingsValidation/types.ts +++ b/src/utils/settingsValidation/types.ts @@ -1,4 +1,3 @@ -import { ISplitFiltersValidation } from '../../dtos/types'; import { ISettings } from '../../types'; /** @@ -7,24 +6,18 @@ import { ISettings } from '../../types'; */ export interface ISettingsValidationParams { /** + * Object of values to overwrite default settings. * Version and startup properties are mandatory, because these values are not part of the base setting. */ defaults: Partial & { version: string } & { startup: ISettings['startup'] }, - runtime: (settings: ISettings) => ISettings['runtime'], + /** Function to overwrite runtime values (ip and hostname) which are false by default */ + runtime?: (settings: ISettings) => ISettings['runtime'], /** Storage validator */ storage?: (settings: ISettings) => ISettings['storage'], /** Integrations validator */ integrations?: (settings: ISettings) => ISettings['integrations'], - /** Logger validator */ + /** Logger validator (`settings.debug`) */ logger: (settings: ISettings) => ISettings['log'], -} - -/** - * Settings interface extended with private properties used for internal purposes. - */ -export interface ISettingsInternal extends ISettings { - readonly sync: ISettings['sync'] & { - __splitFiltersValidation: ISplitFiltersValidation - } - readonly impressionListener?: unknown + /** Localhost mode validator (`settings.sync.localhostMode`) */ + localhost?: (settings: ISettings) => ISettings['sync']['localhostMode'], } diff --git a/src/utils/settingsValidation/url.ts b/src/utils/settingsValidation/url.ts index 0be606b8..796f5423 100644 --- a/src/utils/settingsValidation/url.ts +++ b/src/utils/settingsValidation/url.ts @@ -1,7 +1,7 @@ import { ISettings } from '../../types'; const eventsEndpointMatcher = /^\/(testImpressions|metrics|events)/; -const authEndpointMatcher = /^\/auth/; +const authEndpointMatcher = /^\/v2\/auth/; const streamingEndpointMatcher = /^\/(sse|event-stream)/; /** diff --git a/src/utils/timeTracker/__tests__/index.spec.ts b/src/utils/timeTracker/__tests__/index.spec.ts index d9348e27..e95def88 100644 --- a/src/utils/timeTracker/__tests__/index.spec.ts +++ b/src/utils/timeTracker/__tests__/index.spec.ts @@ -1,6 +1,7 @@ import timer from '../timer'; import tracker from '../index'; import { loggerMock } from '../../../logger/__tests__/sdkLogger.mock'; +import { IResponse } from '../../../services/types'; test('TIMER / should count the time between two tasks', (done) => { const timerDuration = Math.floor(Math.random() * 1000); // In millis @@ -24,18 +25,19 @@ describe('TIME TRACKER', () => { }); test('start() / should return the correct type', () => { - const promise = new Promise(res => { + const promise = new Promise(res => { setTimeout(res, 1000); }); const startNormal = tracker.start(loggerMock, tracker.TaskNames.SDK_READY); const startNormalFake = tracker.start(loggerMock, 'fakeTask3'); - const startWithPromise = tracker.start(loggerMock, 'fakeTask4', undefined, promise) as Promise; + const startWithPromise = tracker.start(loggerMock, 'fakeTask4', undefined, promise); expect(typeof startNormal).toBe('function'); // If we call start without a promise, it will return the stop function, // @ts-expect-error expect(typeof startNormal.setCollectorForTask).toBe('function'); // that has a function as well for setting the collector at a defered time, because it has a registered cb but no collector received. // @ts-expect-error expect(typeof startNormalFake.setCollectorForTask).toBe('undefined'); // If no callback is registered for the task, no collectors setup function is attached to returned one. + // @ts-expect-error expect(typeof startWithPromise.then).toBe('function'); // But if we pass a promise, we will get a promise back, with the necessary callbacks already handled. }); diff --git a/src/utils/timeTracker/index.ts b/src/utils/timeTracker/index.ts index 27dd3896..c6899659 100644 --- a/src/utils/timeTracker/index.ts +++ b/src/utils/timeTracker/index.ts @@ -2,6 +2,7 @@ import { uniqueId } from '../lang'; import timer from './timer'; import thenable from '../promise/thenable'; import { ILogger } from '../../logger/types'; +import { IResponse } from '../../services/types'; // Based on ProducerMetricsCollector and ClientCollector classes interface MetricsCollector { @@ -120,7 +121,7 @@ const TrackerAPI = { * @param {string} task - The name of the task. * @param {number | string} modifier - (optional) The modifier for the task, if any. */ - __attachToPromise(log: ILogger, promise: Promise, task: string, collector: false | MetricsCollector, modifier?: number | string) { + __attachToPromise(log: ILogger, promise: Promise, task: string, collector: false | MetricsCollector, modifier?: number | string) { return promise.then(resp => { this.stop(log, task, modifier); @@ -146,7 +147,7 @@ const TrackerAPI = { * @param {Promise} promise - (optional) The promise we are tracking. * @return {Function | Promise} The stop function for this specific task or the promise received with the callbacks registered. */ - start(log: ILogger, task: string, collectors?: Record, promise?: Promise, now?: () => number): Promise | (() => number) { + start(log: ILogger, task: string, collectors?: Record, promise?: Promise, now?: () => number): Promise | (() => number) { const taskUniqueId = uniqueId(); const taskCollector = getCollectorForTask(task, collectors); let result;