From 177db92ff2165c1fc8d8e0458483566809540727 Mon Sep 17 00:00:00 2001 From: Patrick Brosset Date: Tue, 28 Nov 2023 16:17:06 +0100 Subject: [PATCH] Slow calendar in-progress demo --- slow-calendar/README.md | 24 + slow-calendar/package-lock.json | 1580 ++++ slow-calendar/package.json | 16 + slow-calendar/public/app.css | 251 + slow-calendar/public/bundle.js | 2 + slow-calendar/public/clock.png | Bin 0 -> 1097 bytes slow-calendar/public/data.json | 11446 ++++++++++++++++++++++++++ slow-calendar/public/index.html | 13 + slow-calendar/public/info.png | Bin 0 -> 1117 bytes slow-calendar/public/pin.png | Bin 0 -> 1193 bytes slow-calendar/src/AppUI.ts | 163 + slow-calendar/src/CalendarEvent.ts | 71 + slow-calendar/src/EventPopup.ts | 93 + slow-calendar/src/MonthGrid.ts | 117 + slow-calendar/src/Sidebar.ts | 41 + slow-calendar/src/Store.ts | 24 + slow-calendar/src/Toolbar.ts | 73 + slow-calendar/src/WeekGrid.ts | 93 + slow-calendar/src/app.ts | 35 + slow-calendar/src/events-factory.ts | 99 + slow-calendar/src/utils.ts | 33 + slow-calendar/tsconfig.json | 12 + slow-calendar/webpack.config.js | 22 + 23 files changed, 14208 insertions(+) create mode 100644 slow-calendar/README.md create mode 100644 slow-calendar/package-lock.json create mode 100644 slow-calendar/package.json create mode 100644 slow-calendar/public/app.css create mode 100644 slow-calendar/public/bundle.js create mode 100644 slow-calendar/public/clock.png create mode 100644 slow-calendar/public/data.json create mode 100644 slow-calendar/public/index.html create mode 100644 slow-calendar/public/info.png create mode 100644 slow-calendar/public/pin.png create mode 100644 slow-calendar/src/AppUI.ts create mode 100644 slow-calendar/src/CalendarEvent.ts create mode 100644 slow-calendar/src/EventPopup.ts create mode 100644 slow-calendar/src/MonthGrid.ts create mode 100644 slow-calendar/src/Sidebar.ts create mode 100644 slow-calendar/src/Store.ts create mode 100644 slow-calendar/src/Toolbar.ts create mode 100644 slow-calendar/src/WeekGrid.ts create mode 100644 slow-calendar/src/app.ts create mode 100644 slow-calendar/src/events-factory.ts create mode 100644 slow-calendar/src/utils.ts create mode 100644 slow-calendar/tsconfig.json create mode 100644 slow-calendar/webpack.config.js diff --git a/slow-calendar/README.md b/slow-calendar/README.md new file mode 100644 index 0000000..a4b63d6 --- /dev/null +++ b/slow-calendar/README.md @@ -0,0 +1,24 @@ +# Slow Calendar app + +**IN PROGRESS**: this demo app is still in progress and isn't ready for use yet. + +## Building + +To build the calendar app, you'll need to have [Node.js](https://nodejs.org/) installed. + +Then run: + +1. `cd slow-calendar` +1. `npm install` +1. `npm run build` + +The build app will be in the `public` directory. + +## Running + +To run the app locally, use a local web server like [http-server](https://www.npmjs.com/package/http-server): + +1. `npm install -g http-server` +1. `http-server public` + +Then open [http://localhost:8080](http://localhost:8080) in your browser. diff --git a/slow-calendar/package-lock.json b/slow-calendar/package-lock.json new file mode 100644 index 0000000..c85197b --- /dev/null +++ b/slow-calendar/package-lock.json @@ -0,0 +1,1580 @@ +{ + "name": "slow-calendar", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "slow-calendar", + "dependencies": { + "event-target-shim": "^6.0.2" + }, + "devDependencies": { + "ts-loader": "^9.5.1", + "typescript": "^5.3.2", + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@types/eslint": { + "version": "8.44.7", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.7.tgz", + "integrity": "sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.0.tgz", + "integrity": "sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/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, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/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 + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001565", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz", + "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/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 + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/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, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.594", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.594.tgz", + "integrity": "sha512-xT1HVAu5xFn7bDfkjGQi9dNpMqGchUkebwf1GL7cZN32NSwwlHRPMSDJ1KN6HkS0bWUtndbSQZqvpQftKG2uFQ==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", + "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/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, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/event-target-shim": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-6.0.2.tgz", + "integrity": "sha512-8q3LsZjRezbFZ2PN+uP+Q7pnHUMmAOziU2vA2OwoFaKIXxlxl38IylhSSgUorWu/rf4er67w0ikBqjBFk/pomA==", + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/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 + }, + "node_modules/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 + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/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, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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 + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/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, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/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 + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "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 + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", + "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/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, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/typescript": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", + "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } +} diff --git a/slow-calendar/package.json b/slow-calendar/package.json new file mode 100644 index 0000000..6549b18 --- /dev/null +++ b/slow-calendar/package.json @@ -0,0 +1,16 @@ +{ + "name": "slow-calendar", + "devDependencies": { + "ts-loader": "^9.5.1", + "typescript": "^5.3.2", + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4" + }, + "scripts": { + "build": "webpack --mode=production", + "start": "webpack serve --mode=development" + }, + "dependencies": { + "event-target-shim": "^6.0.2" + } +} diff --git a/slow-calendar/public/app.css b/slow-calendar/public/app.css new file mode 100644 index 0000000..84314be --- /dev/null +++ b/slow-calendar/public/app.css @@ -0,0 +1,251 @@ +:root { + --border-color: #bbb; + --background-color: aliceblue; + --accent-color: #f06; + --today-color: #feffed; +} + +html { + font-family: system-ui; + font-size: .8rem; +} + +html, body { + margin: 0; + padding: 0; + overflow: hidden; + height: 100%; +} + +button { + border: 1px solid var(--border-color); + background: #eee; + font-size: inherit; + font-family: inherit; + border-radius: .25rem; + padding: .5rem 1rem; +} + +button.primary { + background: var(--accent-color); + border-color: #0004; +} + +button:active { + filter: brightness(.9); +} + +#app { + height: calc(100% - 2rem); + padding: 1rem; + display: grid; + gap: 1rem; + grid-template-rows: max-content 1fr; + grid-template-columns: 1fr 200px; + background-color: var(--background-color); +} + +#toolbar { + padding: 1rem; + background: white; + border: 1px solid var(--border-color); + display: flex; + align-items: center; + gap: .5rem; + border-radius: .5rem; + grid-column: span 2; +} + +#toolbar #month-year { + margin: 0 auto; + font-weight: bold; +} + +#month-grid { + display: grid; + grid-template-columns: repeat(7, 1fr); + grid-auto-rows: 1fr; + gap: 1px; + border: 1px solid var(--border-color); + background: var(--border-color); + border-radius: .5rem; + overflow: hidden; +} + +#week-grid { + display: none; + grid-template-columns: repeat(7, 1fr); + grid-template-rows: 1fr; + gap: 1px; + border: 1px solid var(--border-color); + background: var(--border-color); + border-radius: .5rem; + overflow: hidden; +} + +#sidebar { + padding: 1rem; + background: white; + border: 1px solid var(--border-color); + border-radius: .5rem; + overflow-y: auto; +} + +#sidebar h2 { + margin: 0; + text-align: center; +} + +.day { + padding: .5rem; + overflow: hidden; + background-color: white; +} + +.day:hover { + background: #eee; +} + +.day.prev-month, .day.next-month { + opacity: .4; +} + +.day.today { + background: var(--today-color); + box-shadow: inset 0 0 0 1px #aaa; + background-image: linear-gradient(to bottom, + transparent 0 var(--now-marker), + red var(--now-marker) calc(var(--now-marker) + 2px), + transparent 0 + ); +} + +.events, .event { + margin: 0; + padding: 0; + list-style: none; +} + +.event { + background-color: var(--event-color); + border: 1px solid color-mix(in srgb, var(--event-color) 50%, black 50%); +} + +.day .header { + font-size: .8rem; + white-space: nowrap; +} + +.day.today .header { + font-weight: bold; +} + +.event { + margin-block-start: .25rem; + padding: .25rem; + border-radius: .25rem; + overflow: hidden; + cursor: default; +} + +.event * { + pointer-events: none; +} + +.event .time { + font-weight: bold; + font-size: .9em; +} + +.event.multi-day { + box-shadow: -1rem 0 0 0 var(--event-color), 1rem 0 0 0 var(--event-color); + border: 0; +} + +.event.unconfirmed { + border-style: dashed; +} + +.event:hover { + box-shadow: inset 0 0 0 2px #0005; +} + +.popup { + display: none; + position: absolute; + width: calc(100vw / 7 - 1rem - 3px); + background: white; + padding: .5rem; + border-radius: .25rem; + border: 1px solid #aaa; + margin: 0 .5rem; + background: var(--today-color); + box-shadow: 0 0 1rem 0 #0004; +} + +.popup.left { + translate: calc(-1.5rem - 2px); + margin: 0; +} + +.popup.visible { + display: block; +} + +.popup::before { + content: ""; + position: absolute; + width: 1rem; + height: 1rem; + background: var(--event-color); + border-radius: 50%; + top: 1rem; + right: 1rem; + border: 1px solid color-mix(in srgb, var(--event-color) 50%, black 50%); +} + +.popup.unconfirmed::before { + border-style: dashed; +} + +.popup h2 { + margin: 0; + padding-inline-end: 2rem; +} + +.popup p { + margin: 1rem 0 0 0; +} + +.when::before { + content: 'When: '; + font-weight: bold; + padding-inline-start: 1.25rem; + background: url(clock.png); + background-repeat: no-repeat; + background-size: 1rem; + background-position: 0 .25rem; + background-blend-mode: darken; +} + +.where::before { + content: 'Where: '; + font-weight: bold; + padding-inline-start: 1.25rem; + background: url(pin.png); + background-repeat: no-repeat; + background-size: 1rem; + background-position: 0 .2rem; + background-blend-mode: darken; +} + +.what::before { + content: 'What: '; + font-weight: bold; + padding-inline-start: 1.25rem; + background: url(info.png); + background-repeat: no-repeat; + background-size: 1rem; + background-position: 0 .2rem; + background-blend-mode: darken; +} \ No newline at end of file diff --git a/slow-calendar/public/bundle.js b/slow-calendar/public/bundle.js new file mode 100644 index 0000000..c2f4329 --- /dev/null +++ b/slow-calendar/public/bundle.js @@ -0,0 +1,2 @@ +(()=>{"use strict";function e(e,n,...s){if(!e)throw new TypeError(t(n,s))}function t(e,t){let s=0;return e.replace(/%[os]/gu,(()=>n(t[s++])))}function n(e){return"object"!=typeof e||null===e?String(e):Object.prototype.toString.call(e)}const s="undefined"!=typeof window?window:"undefined"!=typeof self?self:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:void 0;let i;class o{constructor(e,t){this.code=e,this.message=t}warn(...e){var t;try{i;const n=(null!==(t=(new Error).stack)&&void 0!==t?t:"").replace(/^(?:.+?\n){2}/gu,"\n");console.warn(this.message,...e,n)}catch(e){}}}const a=new o("W01","Unable to initialize event under dispatching."),r=new o("W02","Assigning any falsy value to 'cancelBubble' property has no effect."),l=new o("W03","Assigning any truthy value to 'returnValue' property has no effect."),c=new o("W04","Unable to preventDefault on non-cancelable events."),d=new o("W05","Unable to preventDefault inside passive event listener invocation."),h=new o("W06","An event listener wasn't added because it has been added already: %o, %o"),u=new o("W07","The %o option value was abandoned because the event listener wasn't added as duplicated."),p=new o("W08","The 'callback' argument must be a function or an object that has 'handleEvent' method: %o");new o("W09","Event attribute handler must be a function: %o");class g{static get NONE(){return v}static get CAPTURING_PHASE(){return m}static get AT_TARGET(){return E}static get BUBBLING_PHASE(){return y}constructor(e,t){Object.defineProperty(this,"isTrusted",{value:!1,enumerable:!0});const n=null!=t?t:{};f.set(this,{type:String(e),bubbles:Boolean(n.bubbles),cancelable:Boolean(n.cancelable),composed:Boolean(n.composed),target:null,currentTarget:null,stopPropagationFlag:!1,stopImmediatePropagationFlag:!1,canceledFlag:!1,inPassiveListenerFlag:!1,dispatchFlag:!1,timeStamp:Date.now()})}get type(){return b(this).type}get target(){return b(this).target}get srcElement(){return b(this).target}get currentTarget(){return b(this).currentTarget}composedPath(){const e=b(this).currentTarget;return e?[e]:[]}get NONE(){return v}get CAPTURING_PHASE(){return m}get AT_TARGET(){return E}get BUBBLING_PHASE(){return y}get eventPhase(){return b(this).dispatchFlag?2:0}stopPropagation(){b(this).stopPropagationFlag=!0}get cancelBubble(){return b(this).stopPropagationFlag}set cancelBubble(e){e?b(this).stopPropagationFlag=!0:r.warn()}stopImmediatePropagation(){const e=b(this);e.stopPropagationFlag=e.stopImmediatePropagationFlag=!0}get bubbles(){return b(this).bubbles}get cancelable(){return b(this).cancelable}get returnValue(){return!b(this).canceledFlag}set returnValue(e){e?l.warn():w(b(this))}preventDefault(){w(b(this))}get defaultPrevented(){return b(this).canceledFlag}get composed(){return b(this).composed}get isTrusted(){return!1}get timeStamp(){return b(this).timeStamp}initEvent(e,t=!1,n=!1){const s=b(this);s.dispatchFlag?a.warn():f.set(this,{...s,type:String(e),bubbles:Boolean(t),cancelable:Boolean(n),target:null,currentTarget:null,stopPropagationFlag:!1,stopImmediatePropagationFlag:!1,canceledFlag:!1})}}const v=0,m=1,E=2,y=3,f=new WeakMap;function b(t,n="this"){const s=f.get(t);return e(null!=s,"'%s' must be an object that Event constructor created, but got another one: %o",n,t),s}function w(e){e.inPassiveListenerFlag?d.warn():e.cancelable?e.canceledFlag=!0:c.warn()}Object.defineProperty(g,"NONE",{enumerable:!0}),Object.defineProperty(g,"CAPTURING_PHASE",{enumerable:!0}),Object.defineProperty(g,"AT_TARGET",{enumerable:!0}),Object.defineProperty(g,"BUBBLING_PHASE",{enumerable:!0});const D=Object.getOwnPropertyNames(g.prototype);for(let e=0;ei,configurable:!0,enumerable:!0})}}class P extends g{static wrap(e){return new(L(e))(e)}constructor(e){super(e.type,{bubbles:e.bubbles,cancelable:e.cancelable,composed:e.composed}),e.cancelBubble&&super.stopPropagation(),e.defaultPrevented&&super.preventDefault(),M.set(this,{original:e});const t=Object.keys(e);for(let n=0;nn!==t)),!1):(e.listeners.splice(t,1),!0)}R.set(Object.prototype,P),void 0!==s&&void 0!==s.Event&&R.set(s.Event.prototype,P);class G{constructor(){B.set(this,Object.create(null))}addEventListener(e,t,n){const s=H(this),{callback:i,capture:o,once:a,passive:r,signal:l,type:c}=function(e,t,n){var s;return W(t),"object"==typeof n&&null!==n?{type:String(e),callback:null!=t?t:void 0,capture:Boolean(n.capture),passive:Boolean(n.passive),once:Boolean(n.once),signal:null!==(s=n.signal)&&void 0!==s?s:void 0}:{type:String(e),callback:null!=t?t:void 0,capture:Boolean(n),passive:!1,once:!1,signal:void 0}}(e,t,n);if(null==i||(null==l?void 0:l.aborted))return;const d=function(e,t){var n;return null!==(n=e[t])&&void 0!==n?n:e[t]={attrCallback:void 0,attrListener:void 0,cow:!1,listeners:[]}}(s,c),p=j(d,i,o);-1===p?function(e,t,n,s,i,o){let a;o&&(a=x.bind(null,e,t,n),o.addEventListener("abort",a));const r=function(e,t,n,s,i,o){return{callback:e,flags:(t?1:0)|(n?2:0)|(s?4:0),signal:i,signalListener:o}}(t,n,s,i,o,a);e.cow?(e.cow=!1,e.listeners=[...e.listeners,r]):e.listeners.push(r)}(d,i,o,r,a,l):function(e,t,n,s){h.warn($(e)?"capture":"bubble",e.callback),I(e)!==t&&u.warn("passive"),F(e)!==n&&u.warn("once"),e.signal!==s&&u.warn("signal")}(d.listeners[p],r,a,l)}removeEventListener(e,t,n){const s=H(this),{callback:i,capture:o,type:a}=function(e,t,n){return W(t),"object"==typeof n&&null!==n?{type:String(e),callback:null!=t?t:void 0,capture:Boolean(n.capture)}:{type:String(e),callback:null!=t?t:void 0,capture:Boolean(n)}}(e,t,n),r=s[a];null!=i&&r&&x(r,i,o)}dispatchEvent(e){const t=H(this)[String(e.type)];if(null==t)return!0;const n=e instanceof g?e:P.wrap(e),i=b(n,"event");if(i.dispatchFlag)throw o="This event has been in dispatching.",s.DOMException?new s.DOMException(o,"InvalidStateError"):(null==_&&(_=class e extends Error{constructor(t){super(t),Error.captureStackTrace&&Error.captureStackTrace(this,e)}get code(){return 11}get name(){return"InvalidStateError"}},Object.defineProperties(_.prototype,{code:{enumerable:!0},name:{enumerable:!0}}),k(_),k(_.prototype)),new _(o));var o;if(i.dispatchFlag=!0,i.target=i.currentTarget=this,!i.stopPropagationFlag){const{cow:e,listeners:s}=t;t.cow=!0;for(let o=0;oe.date.getFullYear()===t.getFullYear()&&e.date.getMonth()===t.getMonth()&&e.date.getDate()===t.getDate())).sort(((e,t)=>!e.time&&t.time?-1:e.time&&!t.time?1:e.time||t.time?parseInt(e.time.replace(/^0/,"").replace(":",""))-parseInt(t.time.replace(/^0/,"").replace(":","")):0)).sort(((e,t)=>e.multiDays&&!t.multiDays?-1:!e.multiDays&&t.multiDays?1:void 0))}void 0!==s&&void 0!==s.EventTarget&&Object.setPrototypeOf(G.prototype,s.EventTarget.prototype);const V=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];class q extends G{constructor(e,t,n){super(),this.el=e,this._date=new Date,this.rootEl=e,this._date=t,this._events=n,this.render()}render(){this.rootEl.innerHTML="";const e=this._date.getMonth(),t=this._date.getFullYear(),n=new Date(t,e,1),s=new Date(t,e+1,0),i=n.getDay(),o=s.getDay(),a=s.getDate(),r=new Date(t,e,0).getDate(),l=[];let c=0;for(let n=r-i+1;n<=r;n++){const s=new Date(t,e-1,n);l.push({date:s,html:this.renderDay(s,n,c,"prev-month")}),c++}for(let n=1;n<=a;n++){const s=new Date(t,e,n);l.push({date:s,html:this.renderDay(s,n,c)}),c++}for(let n=1;n<=7-o-1;n++){const s=new Date(t,e+1,n);l.push({date:s,html:this.renderDay(s,n,c,"next-month")}),c++}for(const{date:e,html:t}of l)this.rootEl.insertAdjacentHTML("beforeend",t),this.rootEl.lastElementChild.addEventListener("click",(t=>{this.dispatchEvent(new CustomEvent("day-clicked",{detail:e}))}));this.updateNowMarker()}renderDay(e,t,n,s=""){const i=U(this._events,e);return`\n
\n
\n ${V[e.getDay()]}\n ${t}\n
\n
    \n ${i.map((e=>e.asOneLineHTML(n))).join("")}\n
\n
\n `}updateNowMarker(){const e=new Date,t=100*(100*e.getHours()+e.getMinutes())/2400,n=this.rootEl.querySelector(".day.today");if(n){const e=n.offsetHeight*t/100;this.rootEl.style.setProperty("--now-marker",`${e}px`)}setTimeout((()=>this.updateNowMarker()),1e3)}set date(e){this._date=e,this.render()}set events(e){this._events=e,this.render()}}const J=["January","February","March","April","May","June","July","August","September","October","November","December"];class X extends G{constructor(e,t,n){super(),this.el=e,this.selectedMode="month",this.rootEl=e,this._date=t,this.selectedMode=n,this.render()}formatMonthYear(){const e=this._date.getMonth(),t=this._date.getFullYear();return`${J[e]} ${t}`}render(){this.rootEl.innerHTML=`\n \n \n \n ${this.formatMonthYear()}\n \n \n \n \n `,this.rootEl.querySelector("#prev-month").addEventListener("click",(()=>{console.log(`Prev ${this.selectedMode} clicked`),this.dispatchEvent(new g("prev"))})),this.rootEl.querySelector("#next-month").addEventListener("click",(()=>{console.log(`Next ${this.selectedMode} clicked`),this.dispatchEvent(new g("next"))})),this.rootEl.querySelector("#today").addEventListener("click",(()=>{console.log("Today clicked"),this.dispatchEvent(new g("today"))})),this.rootEl.querySelector("#month-view").addEventListener("click",(()=>{console.log("Month view clicked"),this.dispatchEvent(new g("month-view")),this.selectedMode="month"})),this.rootEl.querySelector("#week-view").addEventListener("click",(()=>{console.log("Week view clicked"),this.dispatchEvent(new g("week-view")),this.selectedMode="week"}))}set date(e){this._date=e,this.render()}}class z{constructor(e,t,n){this.el=e,this._events=[],this._date=new Date,this.rootEl=e,this._date=t,this._events=n,this.render()}render(){if(this.rootEl.innerHTML="\n

Click a day to view events

\n ",!this._events.length)return;this.rootEl.innerHTML="";const e=document.createElement("ul");e.className="events",this.rootEl.appendChild(e);for(const t of this._events)e.innerHTML+=t.asFullHTML()}set events(e){this._events=e,this.render()}}const Q=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];class Z extends G{constructor(e,t,n){super(),this.el=e,this._date=new Date,this.rootEl=e,this._date=t,this._events=n,this.render()}render(){this.rootEl.innerHTML="";const e=this._date.getMonth(),t=this._date.getFullYear(),n=this._date.getDate(),s=this._date.getDay(),i=new Date(t,e,n-s);for(let n=0;n<7;n++){const s=new Date(t,e,i.getDate()+n);this.rootEl.insertAdjacentHTML("beforeend",this.renderDay(s,s.getDate())),this.rootEl.lastElementChild.addEventListener("click",(e=>{this.dispatchEvent(new CustomEvent("day-clicked",{detail:s}))}))}this.updateNowMarker()}renderDay(e,t,n=""){const s=U(this._events,e);return`\n
\n
\n ${Q[e.getDay()]}\n ${t}\n
\n
    \n ${s.map((e=>e.asMediumLengthHTML())).join("")}\n
\n
\n `}updateNowMarker(){const e=new Date,t=100*(100*e.getHours()+e.getMinutes())/2400,n=this.rootEl.querySelector(".day.today");if(n){const e=n.offsetHeight*t/100;this.rootEl.style.setProperty("--now-marker",`${e}px`)}setTimeout((()=>this.updateNowMarker()),1e3)}set date(e){this._date=e,this.render()}set events(e){this._events=e,this.render()}}class K extends G{constructor(e,t,n,s){super(),this.mode="month",this.rootEl=e,this._date=t,this._events=s,this.mode=n,this.render()}render(){this.rootEl.innerHTML="",this.toolbarEl=document.createElement("div"),this.toolbarEl.id="toolbar",this.rootEl.appendChild(this.toolbarEl),this.toolbar=new X(this.toolbarEl,this._date,this.mode),this.toolbar.addEventListener("prev",(()=>{const e="month"===this.mode?new Date(this._date.getFullYear(),this._date.getMonth()-1,1):new Date(this._date.getFullYear(),this._date.getMonth(),this._date.getDate()-7);this.date=e,this.dispatchEvent(new CustomEvent("date-changed",{detail:this._date}))})),this.toolbar.addEventListener("next",(()=>{const e="month"===this.mode?new Date(this._date.getFullYear(),this._date.getMonth()+1,1):new Date(this._date.getFullYear(),this._date.getMonth(),this._date.getDate()+7);this.date=e,this.dispatchEvent(new CustomEvent("date-changed",{detail:this._date}))})),this.toolbar.addEventListener("today",(()=>{this.date=new Date,this.dispatchEvent(new CustomEvent("date-changed",{detail:this._date}))})),this.toolbar.addEventListener("month-view",(()=>{this.mode="month",this.monthGridEl.style.display="grid",this.weekGridEl.style.display="none",this.dispatchEvent(new CustomEvent("mode-changed",{detail:this.mode}))})),this.toolbar.addEventListener("week-view",(()=>{this.mode="week",this.monthGridEl.style.display="none",this.weekGridEl.style.display="grid",this.dispatchEvent(new CustomEvent("mode-changed",{detail:this.mode}))})),this.monthGridEl=document.createElement("div"),this.monthGridEl.id="month-grid",this.rootEl.appendChild(this.monthGridEl),this.monthGrid=new q(this.monthGridEl,this._date,this._events),this.weekGridEl=document.createElement("div"),this.weekGridEl.id="week-grid",this.rootEl.appendChild(this.weekGridEl),this.weekGrid=new Z(this.weekGridEl,this._date,this._events),this.sidebarEl=document.createElement("div"),this.sidebarEl.id="sidebar",this.rootEl.appendChild(this.sidebarEl),this.sidebar=new z(this.sidebarEl,this._date,this._events),this.monthGrid.addEventListener("day-clicked",(e=>{const t=e.detail,n=U(this._events,t);this.sidebar.events=n})),this.weekGrid.addEventListener("day-clicked",(e=>{const t=e.detail,n=U(this._events,t);this.sidebar.events=n})),this.sidebar.events=U(this._events,new Date),"week"===this.mode?(this.monthGridEl.style.display="none",this.weekGridEl.style.display="grid"):(this.monthGridEl.style.display="grid",this.weekGridEl.style.display="none")}set date(e){console.log("Setting date to",e),this._date=e,this.monthGrid.date=e,this.weekGrid.date=e,this.toolbar.date=e,this.sidebar.events=U(this._events,this._date)}set events(e){this._events=e,this.monthGrid.events=e,this.weekGrid.events=e,this.sidebar.events=U(this._events,this._date)}}class ee{constructor(e,t,n){this.rsvp=!1,this.title=e,this.id=t,this.date=n}asOneLineHTML(e=void 0){const t=this.time?`${this.time}`:"";return`\n
  • \n
    ${t} ${this.title}
    \n
  • \n `}asMediumLengthHTML(){const e=this.time?`${this.time}`:"";return`\n
  • \n
    ${e}
    \n

    ${this.title}

    \n

    ${this.description}

    \n
  • \n `}asFullHTML(){let e="";return this.multiDays?e=`From ${this.multiDays.start.toDateString()} to ${this.multiDays.end.toDateString()}`:(e=this.date.toDateString(),this.time&&(e+=`, at ${this.time}`),this.repeat&&(e+=`, ${this.repeat}`),this.duration&&(e+=` (${this.duration} minutes)`)),`\n
  • \n
    \n

    ${this.title}

    \n

    ${e}

    \n ${this.location?`

    ${this.location}

    `:""}\n

    ${this.description}

    \n
    \n
  • \n `}}var te=function(e,t,n,s){return new(n||(n=Promise))((function(i,o){function a(e){try{l(s.next(e))}catch(e){o(e)}}function r(e){try{l(s.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,r)}l((s=s.apply(e,t||[])).next())}))};class ne{constructor(e){this.events=e}start(){this.popupEl||(this.popupEl=document.createElement("div"),this.popupEl.className="popup"),addEventListener("mousemove",(e=>{this.popupEl.classList.remove("visible"),this.popupEl.remove();const t=e.target.closest("#month-grid .event, #week-grid .event");if(!t)return;const n=t.id;if(!n||!n.startsWith("id-"))return;let s=n.replace("id-","");const i=this.events.find((e=>e.id===s));if(!i)return void console.log("No event found for id",s);const o=parseInt(t.dataset.indexInGrid);this.popupEl.style.setProperty("--event-color",i.color),this.popupEl.classList.toggle("visible",!0),this.popupEl.classList.toggle("unconfirmed",!i.rsvp);let a="";i.multiDays?a=`From ${i.multiDays.start.toDateString()} to ${i.multiDays.end.toDateString()}`:(a=i.date.toDateString(),i.time&&(a+=`, at ${i.time}`),i.repeat&&(a+=`, ${i.repeat}`),i.duration&&(a+=` (${i.duration} minutes)`)),this.popupEl.innerHTML=`\n

    ${i.title}

    \n

    ${a}

    \n ${i.location?`

    ${i.location}

    `:""}\n

    ${i.description}

    \n `,document.body.appendChild(this.popupEl);const r=t.getBoundingClientRect(),l=r.top,c=r.right,d=r.left,h=r.width;this.popupEl.style.top=o>=28?l-this.popupEl.clientHeight+"px":`${l}px`,6===o||13===o||20===o||27===o||34===o?(this.popupEl.style.left=d-h+"px",this.popupEl.classList.toggle("left",!0)):(this.popupEl.style.left=`${c}px`,this.popupEl.classList.toggle("left",!1))}))}}class se{getStoredPrefs(){return e=this,t=void 0,s=function*(){yield new Promise((e=>setTimeout(e,250*Math.random())));const e=localStorage.getItem("slow-cal-mode"),t=localStorage.getItem("slow-cal-initDate");return{mode:e,initDate:t?new Date(t):void 0}},new((n=void 0)||(n=Promise))((function(i,o){function a(e){try{l(s.next(e))}catch(e){o(e)}}function r(e){try{l(s.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,r)}l((s=s.apply(e,t||[])).next())}));var e,t,n,s}set mode(e){console.log("Storing mode prefs"),localStorage.setItem("slow-cal-mode",e)}set initDate(e){console.log("Storing date prefs"),localStorage.setItem("slow-cal-initDate",e.toISOString())}}addEventListener("DOMContentLoaded",(()=>{return e=void 0,t=void 0,s=function*(){const e=new se,t=yield e.getStoredPrefs(),n=t.initDate||new Date,s=t.mode||"month",i=document.getElementById("app"),o=new K(i,n,s,[]),a=yield function(){return te(this,void 0,void 0,(function*(){const e=yield function(){return te(this,void 0,void 0,(function*(){console.log("Fetching calendar data ..."),yield new Promise((e=>setTimeout(e,500*Math.random())));const e=yield fetch("./data.json");return yield e.json()}))}();return console.log("Processing events ..."),e.events.map((e=>function(e){const t=[new Date(e.startDate)];let n=null;if(e.repeat){const n=new Date(e.startDate),s=e.endDate?new Date(e.endDate):new Date(n.getTime()+15768e7);if("daily"===e.repeat){console.log("Expanding daily event ...");const e=(s.getTime()-n.getTime())/864e5;for(let s=1;s<=e;s++){const e=new Date(n.getTime()+24*s*60*60*1e3);0!==e.getDay()&&6!==e.getDay()&&t.push(e)}}else if("weekly"===e.repeat){console.log("Expanding weekly event ...");const e=(s.getTime()-n.getTime())/6048e5;for(let s=1;s<=e;s++){const e=new Date(n.getTime()+7*s*24*60*60*1e3);t.push(e)}}else if("monthly"===e.repeat){console.log("Expanding monthly event ...");const e=12*(s.getFullYear()-n.getFullYear())+(s.getMonth()-n.getMonth());for(let s=1;s<=e;s++){const e=new Date(n.getTime());e.setMonth(e.getMonth()+s),t.push(e)}}else if("yearly"===e.repeat){console.log("Expanding yearly event ...");const e=s.getFullYear()-n.getFullYear();for(let s=1;s<=e;s++){const e=new Date(n.getTime());e.setFullYear(e.getFullYear()+s),t.push(e)}}}else if(e.endDate){const s=new Date(e.startDate),i=new Date(e.endDate),o=(i.getTime()-s.getTime())/864e5;for(let e=1;e<=o;e++){const n=new Date(s.getTime()+24*e*60*60*1e3);t.push(n)}n={start:s,end:i}}return t.map(((t,s)=>{const i=e.id+(s>0?`-${s}`:""),o=new ee(e.title,i,t);return o.multiDays=n,o.color=e.color,o.time=e.startTime,o.duration=e.duration,o.repeat=e.repeat,o.location=e.location,o.description=e.description,o.rsvp=e.rsvp,o}))}(e))).flat()}))}();console.log("Refreshing calendar with events"),o.events=a,console.log("Initializing the popup util"),new ne(a).start(),o.addEventListener("mode-changed",(t=>{e.mode=t.detail})),o.addEventListener("date-changed",(t=>{e.initDate=t.detail}))},new((n=void 0)||(n=Promise))((function(i,o){function a(e){try{l(s.next(e))}catch(e){o(e)}}function r(e){try{l(s.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,r)}l((s=s.apply(e,t||[])).next())}));var e,t,n,s}))})(); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,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RUFBUSxFQUFJLElBQUlBLElBQVUsSUFDL0NoRixFQUFRLElBQUl5TSxHQUFjdEYsRUFBVXVGLE1BQU9YLEVBQUlyRSxHQVlyRCxPQVZBMUgsRUFBTW1JLFVBQVlBLEVBRWxCbkksRUFBTTRNLE1BQVF6RixFQUFVeUYsTUFDeEI1TSxFQUFNaUksS0FBT2QsRUFBVW1KLFVBQ3ZCdFEsRUFBTWtOLFNBQVcvRixFQUFVK0YsU0FDM0JsTixFQUFNaU4sT0FBUzlGLEVBQVU4RixPQUN6QmpOLEVBQU1tTixTQUFXaEcsRUFBVWdHLFNBQzNCbk4sRUFBTTZNLFlBQWMxRixFQUFVMEYsWUFDOUI3TSxFQUFNMk0sS0FBT3hGLEVBQVV3RixLQUVoQjNNLENBQUssR0FFaEIsQ0FPV3VRLENBQWtDdlEsS0FDeEN3USxNQUNMLEcsQ0RsRnVCQyxHQUVyQjdULFFBQVF1TyxJQUFJLG1DQUNacUUsRUFBTS9ILE9BQVNBLEVBRWY3SyxRQUFRdU8sSUFBSSwrQkFDRSxJQUFJaUMsR0FBVzNGLEdBQ3ZCc0YsUUFHTnlDLEVBQU0xSixpQkFBaUIsZ0JBQWlCb0IsSUFDdENpSSxFQUFNbkUsS0FBTzlELEVBQUUwQyxNQUFNLElBSXZCNEYsRUFBTTFKLGlCQUFpQixnQkFBaUJvQixJQUN0Q2lJLEVBQU1ILFNBQVc5SCxFQUFFMEMsTUFBTSxHQUU3QixFLFlBN0JpRCxLLDZRQTZCL0MsRyIsInNvdXJjZXMiOlsid2VicGFjazovL3Nsb3ctY2FsZW5kYXIvLi9ub2RlX21vZHVsZXMvZXZlbnQtdGFyZ2V0LXNoaW0vaW5kZXgubWpzIiwid2VicGFjazovL3Nsb3ctY2FsZW5kYXIvLi9zcmMvdXRpbHMudHMiLCJ3ZWJwYWNrOi8vc2xvdy1jYWxlbmRhci8uL3NyYy9Nb250aEdyaWQudHMiLCJ3ZWJwYWNrOi8vc2xvdy1jYWxlbmRhci8uL3NyYy9Ub29sYmFyLnRzIiwid2VicGFjazovL3Nsb3ctY2FsZW5kYXIvLi9zcmMvU2lkZWJhci50cyIsIndlYnBhY2s6Ly9zbG93LWNhbGVuZGFyLy4vc3JjL1dlZWtHcmlkLnRzIiwid2VicGFjazovL3Nsb3ctY2FsZW5kYXIvLi9zcmMvQXBwVUkudHMiLCJ3ZWJwYWNrOi8vc2xvdy1jYWxlbmRhci8uL3NyYy9DYWxlbmRhckV2ZW50LnRzIiwid2VicGFjazovL3Nsb3ctY2FsZW5kYXIvLi9zcmMvRXZlbnRQb3B1cC50cyIsIndlYnBhY2s6Ly9zbG93LWNhbGVuZGFyLy4vc3JjL1N0b3JlLnRzIiwid2VicGFjazovL3Nsb3ctY2FsZW5kYXIvLi9zcmMvYXBwLnRzIiwid2VicGFjazovL3Nsb3ctY2FsZW5kYXIvLi9zcmMvZXZlbnRzLWZhY3RvcnkudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBc3NlcnQgYSBjb25kaXRpb24uXG4gKiBAcGFyYW0gY29uZGl0aW9uIFRoZSBjb25kaXRpb24gdGhhdCBpdCBzaG91bGQgc2F0aXNmeS5cbiAqIEBwYXJhbSBtZXNzYWdlIFRoZSBlcnJvciBtZXNzYWdlLlxuICogQHBhcmFtIGFyZ3MgVGhlIGFyZ3VtZW50cyBmb3IgcmVwbGFjaW5nIHBsYWNlaG9sZGVycyBpbiB0aGUgbWVzc2FnZS5cbiAqL1xuZnVuY3Rpb24gYXNzZXJ0VHlwZShjb25kaXRpb24sIG1lc3NhZ2UsIC4uLmFyZ3MpIHtcbiAgICBpZiAoIWNvbmRpdGlvbikge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGZvcm1hdChtZXNzYWdlLCBhcmdzKSk7XG4gICAgfVxufVxuLyoqXG4gKiBDb252ZXJ0IGEgdGV4dCBhbmQgYXJndW1lbnRzIHRvIG9uZSBzdHJpbmcuXG4gKiBAcGFyYW0gbWVzc2FnZSBUaGUgZm9ybWF0aW5nIHRleHRcbiAqIEBwYXJhbSBhcmdzIFRoZSBhcmd1bWVudHMuXG4gKi9cbmZ1bmN0aW9uIGZvcm1hdChtZXNzYWdlLCBhcmdzKSB7XG4gICAgbGV0IGkgPSAwO1xuICAgIHJldHVybiBtZXNzYWdlLnJlcGxhY2UoLyVbb3NdL2d1LCAoKSA9PiBhbnlUb1N0cmluZyhhcmdzW2krK10pKTtcbn1cbi8qKlxuICogQ29udmVydCBhIHZhbHVlIHRvIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uLlxuICogQHBhcmFtIHggVGhlIHZhbHVlIHRvIGdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uLlxuICovXG5mdW5jdGlvbiBhbnlUb1N0cmluZyh4KSB7XG4gICAgaWYgKHR5cGVvZiB4ICE9PSBcIm9iamVjdFwiIHx8IHggPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIFN0cmluZyh4KTtcbiAgICB9XG4gICAgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh4KTtcbn1cblxubGV0IGN1cnJlbnRFcnJvckhhbmRsZXI7XG4vKipcbiAqIFNldCB0aGUgZXJyb3IgaGFuZGxlci5cbiAqIEBwYXJhbSB2YWx1ZSBUaGUgZXJyb3IgaGFuZGxlciB0byBzZXQuXG4gKi9cbmZ1bmN0aW9uIHNldEVycm9ySGFuZGxlcih2YWx1ZSkge1xuICAgIGFzc2VydFR5cGUodHlwZW9mIHZhbHVlID09PSBcImZ1bmN0aW9uXCIgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCwgXCJUaGUgZXJyb3IgaGFuZGxlciBtdXN0IGJlIGEgZnVuY3Rpb24gb3IgdW5kZWZpbmVkLCBidXQgZ290ICVvLlwiLCB2YWx1ZSk7XG4gICAgY3VycmVudEVycm9ySGFuZGxlciA9IHZhbHVlO1xufVxuLyoqXG4gKiBQcmludCBhIGVycm9yIG1lc3NhZ2UuXG4gKiBAcGFyYW0gbWF5YmVFcnJvciBUaGUgZXJyb3Igb2JqZWN0LlxuICovXG5mdW5jdGlvbiByZXBvcnRFcnJvcihtYXliZUVycm9yKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZXJyb3IgPSBtYXliZUVycm9yIGluc3RhbmNlb2YgRXJyb3JcbiAgICAgICAgICAgID8gbWF5YmVFcnJvclxuICAgICAgICAgICAgOiBuZXcgRXJyb3IoYW55VG9TdHJpbmcobWF5YmVFcnJvcikpO1xuICAgICAgICAvLyBDYWxsIHRoZSB1c2VyLWRlZmluZWQgZXJyb3IgaGFuZGxlciBpZiBleGlzdHMuXG4gICAgICAgIGlmIChjdXJyZW50RXJyb3JIYW5kbGVyKSB7XG4gICAgICAgICAgICBjdXJyZW50RXJyb3JIYW5kbGVyKGVycm9yKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICAvLyBEaXNwYXRjaCBhbiBgZXJyb3JgIGV2ZW50IGlmIHRoaXMgaXMgb24gYSBicm93c2VyLlxuICAgICAgICBpZiAodHlwZW9mIGRpc3BhdGNoRXZlbnQgPT09IFwiZnVuY3Rpb25cIiAmJlxuICAgICAgICAgICAgdHlwZW9mIEVycm9yRXZlbnQgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgZGlzcGF0Y2hFdmVudChuZXcgRXJyb3JFdmVudChcImVycm9yXCIsIHsgZXJyb3IsIG1lc3NhZ2U6IGVycm9yLm1lc3NhZ2UgfSkpO1xuICAgICAgICB9XG4gICAgICAgIC8vIEVtaXQgYW4gYHVuY2F1Z2h0RXhjZXB0aW9uYCBldmVudCBpZiB0aGlzIGlzIG9uIE5vZGUuanMuXG4gICAgICAgIC8vaXN0YW5idWwgaWdub3JlIGVsc2VcbiAgICAgICAgZWxzZSBpZiAodHlwZW9mIHByb2Nlc3MgIT09IFwidW5kZWZpbmVkXCIgJiZcbiAgICAgICAgICAgIHR5cGVvZiBwcm9jZXNzLmVtaXQgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgcHJvY2Vzcy5lbWl0KFwidW5jYXVnaHRFeGNlcHRpb25cIiwgZXJyb3IpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIE90aGVyd2lzZSwgcHJpbnQgdGhlIGVycm9yLlxuICAgICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICB9XG4gICAgY2F0Y2ggKF9hKSB7XG4gICAgICAgIC8vIGlnbm9yZS5cbiAgICB9XG59XG5cbi8qKlxuICogVGhlIGdsb2JhbCBvYmplY3QuXG4gKi9cbi8vaXN0YW5idWwgaWdub3JlIG5leHRcbmNvbnN0IEdsb2JhbCA9IHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCJcbiAgICA/IHdpbmRvd1xuICAgIDogdHlwZW9mIHNlbGYgIT09IFwidW5kZWZpbmVkXCJcbiAgICAgICAgPyBzZWxmXG4gICAgICAgIDogdHlwZW9mIGdsb2JhbCAhPT0gXCJ1bmRlZmluZWRcIlxuICAgICAgICAgICAgPyBnbG9iYWxcbiAgICAgICAgICAgIDogdHlwZW9mIGdsb2JhbFRoaXMgIT09IFwidW5kZWZpbmVkXCJcbiAgICAgICAgICAgICAgICA/IGdsb2JhbFRoaXNcbiAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZDtcblxubGV0IGN1cnJlbnRXYXJuSGFuZGxlcjtcbi8qKlxuICogU2V0IHRoZSB3YXJuaW5nIGhhbmRsZXIuXG4gKiBAcGFyYW0gdmFsdWUgVGhlIHdhcm5pbmcgaGFuZGxlciB0byBzZXQuXG4gKi9cbmZ1bmN0aW9uIHNldFdhcm5pbmdIYW5kbGVyKHZhbHVlKSB7XG4gICAgYXNzZXJ0VHlwZSh0eXBlb2YgdmFsdWUgPT09IFwiZnVuY3Rpb25cIiB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkLCBcIlRoZSB3YXJuaW5nIGhhbmRsZXIgbXVzdCBiZSBhIGZ1bmN0aW9uIG9yIHVuZGVmaW5lZCwgYnV0IGdvdCAlby5cIiwgdmFsdWUpO1xuICAgIGN1cnJlbnRXYXJuSGFuZGxlciA9IHZhbHVlO1xufVxuLyoqXG4gKiBUaGUgd2FybmluZyBpbmZvcm1hdGlvbi5cbiAqL1xuY2xhc3MgV2FybmluZyB7XG4gICAgY29uc3RydWN0b3IoY29kZSwgbWVzc2FnZSkge1xuICAgICAgICB0aGlzLmNvZGUgPSBjb2RlO1xuICAgICAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBSZXBvcnQgdGhpcyB3YXJuaW5nLlxuICAgICAqIEBwYXJhbSBhcmdzIFRoZSBhcmd1bWVudHMgb2YgdGhlIHdhcm5pbmcuXG4gICAgICovXG4gICAgd2FybiguLi5hcmdzKSB7XG4gICAgICAgIHZhciBfYTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIENhbGwgdGhlIHVzZXItZGVmaW5lZCB3YXJuaW5nIGhhbmRsZXIgaWYgZXhpc3RzLlxuICAgICAgICAgICAgaWYgKGN1cnJlbnRXYXJuSGFuZGxlcikge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRXYXJuSGFuZGxlcih7IC4uLnRoaXMsIGFyZ3MgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gT3RoZXJ3aXNlLCBwcmludCB0aGUgd2FybmluZy5cbiAgICAgICAgICAgIGNvbnN0IHN0YWNrID0gKChfYSA9IG5ldyBFcnJvcigpLnN0YWNrKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiBcIlwiKS5yZXBsYWNlKC9eKD86Lis/XFxuKXsyfS9ndSwgXCJcXG5cIik7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4odGhpcy5tZXNzYWdlLCAuLi5hcmdzLCBzdGFjayk7XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2ggKF9iKSB7XG4gICAgICAgICAgICAvLyBJZ25vcmUuXG4gICAgICAgIH1cbiAgICB9XG59XG5cbmNvbnN0IEluaXRFdmVudFdhc0NhbGxlZFdoaWxlRGlzcGF0Y2hpbmcgPSBuZXcgV2FybmluZyhcIlcwMVwiLCBcIlVuYWJsZSB0byBpbml0aWFsaXplIGV2ZW50IHVuZGVyIGRpc3BhdGNoaW5nLlwiKTtcbmNvbnN0IEZhbHN5V2FzQXNzaWduZWRUb0NhbmNlbEJ1YmJsZSA9IG5ldyBXYXJuaW5nKFwiVzAyXCIsIFwiQXNzaWduaW5nIGFueSBmYWxzeSB2YWx1ZSB0byAnY2FuY2VsQnViYmxlJyBwcm9wZXJ0eSBoYXMgbm8gZWZmZWN0LlwiKTtcbmNvbnN0IFRydXRoeVdhc0Fzc2lnbmVkVG9SZXR1cm5WYWx1ZSA9IG5ldyBXYXJuaW5nKFwiVzAzXCIsIFwiQXNzaWduaW5nIGFueSB0cnV0aHkgdmFsdWUgdG8gJ3JldHVyblZhbHVlJyBwcm9wZXJ0eSBoYXMgbm8gZWZmZWN0LlwiKTtcbmNvbnN0IE5vbkNhbmNlbGFibGVFdmVudFdhc0NhbmNlbGVkID0gbmV3IFdhcm5pbmcoXCJXMDRcIiwgXCJVbmFibGUgdG8gcHJldmVudERlZmF1bHQgb24gbm9uLWNhbmNlbGFibGUgZXZlbnRzLlwiKTtcbmNvbnN0IENhbmNlbGVkSW5QYXNzaXZlTGlzdGVuZXIgPSBuZXcgV2FybmluZyhcIlcwNVwiLCBcIlVuYWJsZSB0byBwcmV2ZW50RGVmYXVsdCBpbnNpZGUgcGFzc2l2ZSBldmVudCBsaXN0ZW5lciBpbnZvY2F0aW9uLlwiKTtcbmNvbnN0IEV2ZW50TGlzdGVuZXJXYXNEdXBsaWNhdGVkID0gbmV3IFdhcm5pbmcoXCJXMDZcIiwgXCJBbiBldmVudCBsaXN0ZW5lciB3YXNuJ3QgYWRkZWQgYmVjYXVzZSBpdCBoYXMgYmVlbiBhZGRlZCBhbHJlYWR5OiAlbywgJW9cIik7XG5jb25zdCBPcHRpb25XYXNJZ25vcmVkID0gbmV3IFdhcm5pbmcoXCJXMDdcIiwgXCJUaGUgJW8gb3B0aW9uIHZhbHVlIHdhcyBhYmFuZG9uZWQgYmVjYXVzZSB0aGUgZXZlbnQgbGlzdGVuZXIgd2Fzbid0IGFkZGVkIGFzIGR1cGxpY2F0ZWQuXCIpO1xuY29uc3QgSW52YWxpZEV2ZW50TGlzdGVuZXIgPSBuZXcgV2FybmluZyhcIlcwOFwiLCBcIlRoZSAnY2FsbGJhY2snIGFyZ3VtZW50IG11c3QgYmUgYSBmdW5jdGlvbiBvciBhbiBvYmplY3QgdGhhdCBoYXMgJ2hhbmRsZUV2ZW50JyBtZXRob2Q6ICVvXCIpO1xuY29uc3QgSW52YWxpZEF0dHJpYnV0ZUhhbmRsZXIgPSBuZXcgV2FybmluZyhcIlcwOVwiLCBcIkV2ZW50IGF0dHJpYnV0ZSBoYW5kbGVyIG11c3QgYmUgYSBmdW5jdGlvbjogJW9cIik7XG5cbi8qZXNsaW50LWRpc2FibGUgY2xhc3MtbWV0aG9kcy11c2UtdGhpcyAqL1xuLyoqXG4gKiBBbiBpbXBsZW1lbnRhdGlvbiBvZiBgRXZlbnRgIGludGVyZmFjZSwgdGhhdCB3cmFwcyBhIGdpdmVuIGV2ZW50IG9iamVjdC5cbiAqIGBFdmVudFRhcmdldGAgc2hpbSBjYW4gY29udHJvbCB0aGUgaW50ZXJuYWwgc3RhdGUgb2YgdGhpcyBgRXZlbnRgIG9iamVjdHMuXG4gKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZXZlbnRcbiAqL1xuY2xhc3MgRXZlbnQge1xuICAgIC8qKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNkb20tZXZlbnQtbm9uZVxuICAgICAqL1xuICAgIHN0YXRpYyBnZXQgTk9ORSgpIHtcbiAgICAgICAgcmV0dXJuIE5PTkU7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNkb20tZXZlbnQtY2FwdHVyaW5nX3BoYXNlXG4gICAgICovXG4gICAgc3RhdGljIGdldCBDQVBUVVJJTkdfUEhBU0UoKSB7XG4gICAgICAgIHJldHVybiBDQVBUVVJJTkdfUEhBU0U7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNkb20tZXZlbnQtYXRfdGFyZ2V0XG4gICAgICovXG4gICAgc3RhdGljIGdldCBBVF9UQVJHRVQoKSB7XG4gICAgICAgIHJldHVybiBBVF9UQVJHRVQ7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNkb20tZXZlbnQtYnViYmxpbmdfcGhhc2VcbiAgICAgKi9cbiAgICBzdGF0aWMgZ2V0IEJVQkJMSU5HX1BIQVNFKCkge1xuICAgICAgICByZXR1cm4gQlVCQkxJTkdfUEhBU0U7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemUgdGhpcyBldmVudCBpbnN0YW5jZS5cbiAgICAgKiBAcGFyYW0gdHlwZSBUaGUgdHlwZSBvZiB0aGlzIGV2ZW50LlxuICAgICAqIEBwYXJhbSBldmVudEluaXREaWN0IE9wdGlvbnMgdG8gaW5pdGlhbGl6ZS5cbiAgICAgKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWV2ZW50LWV2ZW50XG4gICAgICovXG4gICAgY29uc3RydWN0b3IodHlwZSwgZXZlbnRJbml0RGljdCkge1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgXCJpc1RydXN0ZWRcIiwge1xuICAgICAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IG9wdHMgPSBldmVudEluaXREaWN0ICE9PSBudWxsICYmIGV2ZW50SW5pdERpY3QgIT09IHZvaWQgMCA/IGV2ZW50SW5pdERpY3QgOiB7fTtcbiAgICAgICAgaW50ZXJuYWxEYXRhTWFwLnNldCh0aGlzLCB7XG4gICAgICAgICAgICB0eXBlOiBTdHJpbmcodHlwZSksXG4gICAgICAgICAgICBidWJibGVzOiBCb29sZWFuKG9wdHMuYnViYmxlcyksXG4gICAgICAgICAgICBjYW5jZWxhYmxlOiBCb29sZWFuKG9wdHMuY2FuY2VsYWJsZSksXG4gICAgICAgICAgICBjb21wb3NlZDogQm9vbGVhbihvcHRzLmNvbXBvc2VkKSxcbiAgICAgICAgICAgIHRhcmdldDogbnVsbCxcbiAgICAgICAgICAgIGN1cnJlbnRUYXJnZXQ6IG51bGwsXG4gICAgICAgICAgICBzdG9wUHJvcGFnYXRpb25GbGFnOiBmYWxzZSxcbiAgICAgICAgICAgIHN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbkZsYWc6IGZhbHNlLFxuICAgICAgICAgICAgY2FuY2VsZWRGbGFnOiBmYWxzZSxcbiAgICAgICAgICAgIGluUGFzc2l2ZUxpc3RlbmVyRmxhZzogZmFsc2UsXG4gICAgICAgICAgICBkaXNwYXRjaEZsYWc6IGZhbHNlLFxuICAgICAgICAgICAgdGltZVN0YW1wOiBEYXRlLm5vdygpLFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogVGhlIHR5cGUgb2YgdGhpcyBldmVudC5cbiAgICAgKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWV2ZW50LXR5cGVcbiAgICAgKi9cbiAgICBnZXQgdHlwZSgpIHtcbiAgICAgICAgcmV0dXJuICQodGhpcykudHlwZTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogVGhlIGV2ZW50IHRhcmdldCBvZiB0aGUgY3VycmVudCBkaXNwYXRjaGluZy5cbiAgICAgKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWV2ZW50LXRhcmdldFxuICAgICAqL1xuICAgIGdldCB0YXJnZXQoKSB7XG4gICAgICAgIHJldHVybiAkKHRoaXMpLnRhcmdldDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogVGhlIGV2ZW50IHRhcmdldCBvZiB0aGUgY3VycmVudCBkaXNwYXRjaGluZy5cbiAgICAgKiBAZGVwcmVjYXRlZCBVc2UgdGhlIGB0YXJnZXRgIHByb3BlcnR5IGluc3RlYWQuXG4gICAgICogQHNlZSBodHRwczovL2RvbS5zcGVjLndoYXR3Zy5vcmcvI2RvbS1ldmVudC1zcmNlbGVtZW50XG4gICAgICovXG4gICAgZ2V0IHNyY0VsZW1lbnQoKSB7XG4gICAgICAgIHJldHVybiAkKHRoaXMpLnRhcmdldDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogVGhlIGV2ZW50IHRhcmdldCBvZiB0aGUgY3VycmVudCBkaXNwYXRjaGluZy5cbiAgICAgKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWV2ZW50LWN1cnJlbnR0YXJnZXRcbiAgICAgKi9cbiAgICBnZXQgY3VycmVudFRhcmdldCgpIHtcbiAgICAgICAgcmV0dXJuICQodGhpcykuY3VycmVudFRhcmdldDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogVGhlIGV2ZW50IHRhcmdldCBvZiB0aGUgY3VycmVudCBkaXNwYXRjaGluZy5cbiAgICAgKiBUaGlzIGRvZXNuJ3Qgc3VwcG9ydCBub2RlIHRyZWUuXG4gICAgICogQHNlZSBodHRwczovL2RvbS5zcGVjLndoYXR3Zy5vcmcvI2RvbS1ldmVudC1jb21wb3NlZHBhdGhcbiAgICAgKi9cbiAgICBjb21wb3NlZFBhdGgoKSB7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRUYXJnZXQgPSAkKHRoaXMpLmN1cnJlbnRUYXJnZXQ7XG4gICAgICAgIGlmIChjdXJyZW50VGFyZ2V0KSB7XG4gICAgICAgICAgICByZXR1cm4gW2N1cnJlbnRUYXJnZXRdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQHNlZSBodHRwczovL2RvbS5zcGVjLndoYXR3Zy5vcmcvI2RvbS1ldmVudC1ub25lXG4gICAgICovXG4gICAgZ2V0IE5PTkUoKSB7XG4gICAgICAgIHJldHVybiBOT05FO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWV2ZW50LWNhcHR1cmluZ19waGFzZVxuICAgICAqL1xuICAgIGdldCBDQVBUVVJJTkdfUEhBU0UoKSB7XG4gICAgICAgIHJldHVybiBDQVBUVVJJTkdfUEhBU0U7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNkb20tZXZlbnQtYXRfdGFyZ2V0XG4gICAgICovXG4gICAgZ2V0IEFUX1RBUkdFVCgpIHtcbiAgICAgICAgcmV0dXJuIEFUX1RBUkdFVDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQHNlZSBodHRwczovL2RvbS5zcGVjLndoYXR3Zy5vcmcvI2RvbS1ldmVudC1idWJibGluZ19waGFzZVxuICAgICAqL1xuICAgIGdldCBCVUJCTElOR19QSEFTRSgpIHtcbiAgICAgICAgcmV0dXJuIEJVQkJMSU5HX1BIQVNFO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBUaGUgY3VycmVudCBldmVudCBwaGFzZS5cbiAgICAgKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWV2ZW50LWV2ZW50cGhhc2VcbiAgICAgKi9cbiAgICBnZXQgZXZlbnRQaGFzZSgpIHtcbiAgICAgICAgcmV0dXJuICQodGhpcykuZGlzcGF0Y2hGbGFnID8gMiA6IDA7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFN0b3AgZXZlbnQgYnViYmxpbmcuXG4gICAgICogQmVjYXVzZSB0aGlzIHNoaW0gZG9lc24ndCBzdXBwb3J0IG5vZGUgdHJlZSwgdGhpcyBtZXJlbHkgY2hhbmdlcyB0aGUgYGNhbmNlbEJ1YmJsZWAgcHJvcGVydHkgdmFsdWUuXG4gICAgICogQHNlZSBodHRwczovL2RvbS5zcGVjLndoYXR3Zy5vcmcvI2RvbS1ldmVudC1zdG9wcHJvcGFnYXRpb25cbiAgICAgKi9cbiAgICBzdG9wUHJvcGFnYXRpb24oKSB7XG4gICAgICAgICQodGhpcykuc3RvcFByb3BhZ2F0aW9uRmxhZyA9IHRydWU7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIGB0cnVlYCBpZiBldmVudCBidWJibGluZyB3YXMgc3RvcHBlZC5cbiAgICAgKiBAZGVwcmVjYXRlZFxuICAgICAqIEBzZWUgaHR0cHM6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNkb20tZXZlbnQtY2FuY2VsYnViYmxlXG4gICAgICovXG4gICAgZ2V0IGNhbmNlbEJ1YmJsZSgpIHtcbiAgICAgICAgcmV0dXJuICQodGhpcykuc3RvcFByb3BhZ2F0aW9uRmxhZztcbiAgICB9XG4gICAgLyoqXG4gICAgICogU3RvcCBldmVudCBidWJibGluZyBpZiBgdHJ1ZWAgaXMgc2V0LlxuICAgICAqIEBkZXByZWNhdGVkIFVzZSB0aGUgYHN0b3BQcm9wYWdhdGlvbigpYCBtZXRob2QgaW5zdGVhZC5cbiAgICAgKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWV2ZW50LWNhbmNlbGJ1YmJsZVxuICAgICAqL1xuICAgIHNldCBjYW5jZWxCdWJibGUodmFsdWUpIHtcbiAgICAgICAgaWYgKHZhbHVlKSB7XG4gICAgICAgICAgICAkKHRoaXMpLnN0b3BQcm9wYWdhdGlvbkZsYWcgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgRmFsc3lXYXNBc3NpZ25lZFRvQ2FuY2VsQnViYmxlLndhcm4oKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvKipcbiAgICAgKiBTdG9wIGV2ZW50IGJ1YmJsaW5nIGFuZCBzdWJzZXF1ZW50IGV2ZW50IGxpc3RlbmVyIGNhbGxpbmdzLlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNkb20tZXZlbnQtc3RvcGltbWVkaWF0ZXByb3BhZ2F0aW9uXG4gICAgICovXG4gICAgc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCkge1xuICAgICAgICBjb25zdCBkYXRhID0gJCh0aGlzKTtcbiAgICAgICAgZGF0YS5zdG9wUHJvcGFnYXRpb25GbGFnID0gZGF0YS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb25GbGFnID0gdHJ1ZTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogYHRydWVgIGlmIHRoaXMgZXZlbnQgd2lsbCBidWJibGUuXG4gICAgICogQHNlZSBodHRwczovL2RvbS5zcGVjLndoYXR3Zy5vcmcvI2RvbS1ldmVudC1idWJibGVzXG4gICAgICovXG4gICAgZ2V0IGJ1YmJsZXMoKSB7XG4gICAgICAgIHJldHVybiAkKHRoaXMpLmJ1YmJsZXM7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIGB0cnVlYCBpZiB0aGlzIGV2ZW50IGNhbiBiZSBjYW5jZWxlZCBieSB0aGUgYHByZXZlbnREZWZhdWx0KClgIG1ldGhvZC5cbiAgICAgKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWV2ZW50LWNhbmNlbGFibGVcbiAgICAgKi9cbiAgICBnZXQgY2FuY2VsYWJsZSgpIHtcbiAgICAgICAgcmV0dXJuICQodGhpcykuY2FuY2VsYWJsZTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogYHRydWVgIGlmIHRoZSBkZWZhdWx0IGJlaGF2aW9yIHdpbGwgYWN0LlxuICAgICAqIEBkZXByZWNhdGVkIFVzZSB0aGUgYGRlZmF1bHRQcmV2ZW50ZWRgIHByb2VwcnR5IGluc3RlYWQuXG4gICAgICogQHNlZSBodHRwczovL2RvbS5zcGVjLndoYXR3Zy5vcmcvI2RvbS1ldmVudC1yZXR1cm52YWx1ZVxuICAgICAqL1xuICAgIGdldCByZXR1cm5WYWx1ZSgpIHtcbiAgICAgICAgcmV0dXJuICEkKHRoaXMpLmNhbmNlbGVkRmxhZztcbiAgICB9XG4gICAgLyoqXG4gICAgICogQ2FuY2VsIHRoZSBkZWZhdWx0IGJlaGF2aW9yIGlmIGBmYWxzZWAgaXMgc2V0LlxuICAgICAqIEBkZXByZWNhdGVkIFVzZSB0aGUgYHByZXZlbnREZWZhdWx0KClgIG1ldGhvZCBpbnN0ZWFkLlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNkb20tZXZlbnQtcmV0dXJudmFsdWVcbiAgICAgKi9cbiAgICBzZXQgcmV0dXJuVmFsdWUodmFsdWUpIHtcbiAgICAgICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICAgICAgc2V0Q2FuY2VsRmxhZygkKHRoaXMpKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIFRydXRoeVdhc0Fzc2lnbmVkVG9SZXR1cm5WYWx1ZS53YXJuKCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLyoqXG4gICAgICogQ2FuY2VsIHRoZSBkZWZhdWx0IGJlaGF2aW9yLlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNkb20tZXZlbnQtcHJldmVudGRlZmF1bHRcbiAgICAgKi9cbiAgICBwcmV2ZW50RGVmYXVsdCgpIHtcbiAgICAgICAgc2V0Q2FuY2VsRmxhZygkKHRoaXMpKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogYHRydWVgIGlmIHRoZSBkZWZhdWx0IGJlaGF2aW9yIHdhcyBjYW5jZWxlZC5cbiAgICAgKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWV2ZW50LWRlZmF1bHRwcmV2ZW50ZWRcbiAgICAgKi9cbiAgICBnZXQgZGVmYXVsdFByZXZlbnRlZCgpIHtcbiAgICAgICAgcmV0dXJuICQodGhpcykuY2FuY2VsZWRGbGFnO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWV2ZW50LWNvbXBvc2VkXG4gICAgICovXG4gICAgZ2V0IGNvbXBvc2VkKCkge1xuICAgICAgICByZXR1cm4gJCh0aGlzKS5jb21wb3NlZDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQHNlZSBodHRwczovL2RvbS5zcGVjLndoYXR3Zy5vcmcvI2RvbS1ldmVudC1pc3RydXN0ZWRcbiAgICAgKi9cbiAgICAvL2lzdGFuYnVsIGlnbm9yZSBuZXh0XG4gICAgZ2V0IGlzVHJ1c3RlZCgpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBAc2VlIGh0dHBzOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWV2ZW50LXRpbWVzdGFtcFxuICAgICAqL1xuICAgIGdldCB0aW1lU3RhbXAoKSB7XG4gICAgICAgIHJldHVybiAkKHRoaXMpLnRpbWVTdGFtcDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQGRlcHJlY2F0ZWQgRG9uJ3QgdXNlIHRoaXMgbWV0aG9kLiBUaGUgY29uc3RydWN0b3IgZGlkIGluaXRpYWxpemF0aW9uLlxuICAgICAqL1xuICAgIGluaXRFdmVudCh0eXBlLCBidWJibGVzID0gZmFsc2UsIGNhbmNlbGFibGUgPSBmYWxzZSkge1xuICAgICAgICBjb25zdCBkYXRhID0gJCh0aGlzKTtcbiAgICAgICAgaWYgKGRhdGEuZGlzcGF0Y2hGbGFnKSB7XG4gICAgICAgICAgICBJbml0RXZlbnRXYXNDYWxsZWRXaGlsZURpc3BhdGNoaW5nLndhcm4oKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpbnRlcm5hbERhdGFNYXAuc2V0KHRoaXMsIHtcbiAgICAgICAgICAgIC4uLmRhdGEsXG4gICAgICAgICAgICB0eXBlOiBTdHJpbmcodHlwZSksXG4gICAgICAgICAgICBidWJibGVzOiBCb29sZWFuKGJ1YmJsZXMpLFxuICAgICAgICAgICAgY2FuY2VsYWJsZTogQm9vbGVhbihjYW5jZWxhYmxlKSxcbiAgICAgICAgICAgIHRhcmdldDogbnVsbCxcbiAgICAgICAgICAgIGN1cnJlbnRUYXJnZXQ6IG51bGwsXG4gICAgICAgICAgICBzdG9wUHJvcGFnYXRpb25GbGFnOiBmYWxzZSxcbiAgICAgICAgICAgIHN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbkZsYWc6IGZhbHNlLFxuICAgICAgICAgICAgY2FuY2VsZWRGbGFnOiBmYWxzZSxcbiAgICAgICAgfSk7XG4gICAgfVxufVxuLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEhlbHBlcnNcbi8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5jb25zdCBOT05FID0gMDtcbmNvbnN0IENBUFRVUklOR19QSEFTRSA9IDE7XG5jb25zdCBBVF9UQVJHRVQgPSAyO1xuY29uc3QgQlVCQkxJTkdfUEhBU0UgPSAzO1xuLyoqXG4gKiBQcml2YXRlIGRhdGEgZm9yIGV2ZW50IHdyYXBwZXJzLlxuICovXG5jb25zdCBpbnRlcm5hbERhdGFNYXAgPSBuZXcgV2Vha01hcCgpO1xuLyoqXG4gKiBHZXQgcHJpdmF0ZSBkYXRhLlxuICogQHBhcmFtIGV2ZW50IFRoZSBldmVudCBvYmplY3QgdG8gZ2V0IHByaXZhdGUgZGF0YS5cbiAqIEBwYXJhbSBuYW1lIFRoZSB2YXJpYWJsZSBuYW1lIHRvIHJlcG9ydC5cbiAqIEByZXR1cm5zIFRoZSBwcml2YXRlIGRhdGEgb2YgdGhlIGV2ZW50LlxuICovXG5mdW5jdGlvbiAkKGV2ZW50LCBuYW1lID0gXCJ0aGlzXCIpIHtcbiAgICBjb25zdCByZXR2ID0gaW50ZXJuYWxEYXRhTWFwLmdldChldmVudCk7XG4gICAgYXNzZXJ0VHlwZShyZXR2ICE9IG51bGwsIFwiJyVzJyBtdXN0IGJlIGFuIG9iamVjdCB0aGF0IEV2ZW50IGNvbnN0cnVjdG9yIGNyZWF0ZWQsIGJ1dCBnb3QgYW5vdGhlciBvbmU6ICVvXCIsIG5hbWUsIGV2ZW50KTtcbiAgICByZXR1cm4gcmV0djtcbn1cbi8qKlxuICogaHR0cHM6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNzZXQtdGhlLWNhbmNlbGVkLWZsYWdcbiAqIEBwYXJhbSBkYXRhIHByaXZhdGUgZGF0YS5cbiAqL1xuZnVuY3Rpb24gc2V0Q2FuY2VsRmxhZyhkYXRhKSB7XG4gICAgaWYgKGRhdGEuaW5QYXNzaXZlTGlzdGVuZXJGbGFnKSB7XG4gICAgICAgIENhbmNlbGVkSW5QYXNzaXZlTGlzdGVuZXIud2FybigpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghZGF0YS5jYW5jZWxhYmxlKSB7XG4gICAgICAgIE5vbkNhbmNlbGFibGVFdmVudFdhc0NhbmNlbGVkLndhcm4oKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBkYXRhLmNhbmNlbGVkRmxhZyA9IHRydWU7XG59XG4vLyBTZXQgZW51bWVyYWJsZVxuT2JqZWN0LmRlZmluZVByb3BlcnR5KEV2ZW50LCBcIk5PTkVcIiwgeyBlbnVtZXJhYmxlOiB0cnVlIH0pO1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KEV2ZW50LCBcIkNBUFRVUklOR19QSEFTRVwiLCB7IGVudW1lcmFibGU6IHRydWUgfSk7XG5PYmplY3QuZGVmaW5lUHJvcGVydHkoRXZlbnQsIFwiQVRfVEFSR0VUXCIsIHsgZW51bWVyYWJsZTogdHJ1ZSB9KTtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudCwgXCJCVUJCTElOR19QSEFTRVwiLCB7IGVudW1lcmFibGU6IHRydWUgfSk7XG5jb25zdCBrZXlzID0gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoRXZlbnQucHJvdG90eXBlKTtcbmZvciAobGV0IGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7ICsraSkge1xuICAgIGlmIChrZXlzW2ldID09PSBcImNvbnN0cnVjdG9yXCIpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgfVxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudC5wcm90b3R5cGUsIGtleXNbaV0sIHsgZW51bWVyYWJsZTogdHJ1ZSB9KTtcbn1cbi8vIEVuc3VyZSBgZXZlbnQgaW5zdGFuY2VvZiB3aW5kb3cuRXZlbnRgIGlzIGB0cnVlYC5cbmlmICh0eXBlb2YgR2xvYmFsICE9PSBcInVuZGVmaW5lZFwiICYmIHR5cGVvZiBHbG9iYWwuRXZlbnQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICBPYmplY3Quc2V0UHJvdG90eXBlT2YoRXZlbnQucHJvdG90eXBlLCBHbG9iYWwuRXZlbnQucHJvdG90eXBlKTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBuZXcgSW52YWxpZFN0YXRlRXJyb3IgaW5zdGFuY2UuXG4gKiBAcGFyYW0gbWVzc2FnZSBUaGUgZXJyb3IgbWVzc2FnZS5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlSW52YWxpZFN0YXRlRXJyb3IobWVzc2FnZSkge1xuICAgIGlmIChHbG9iYWwuRE9NRXhjZXB0aW9uKSB7XG4gICAgICAgIHJldHVybiBuZXcgR2xvYmFsLkRPTUV4Y2VwdGlvbihtZXNzYWdlLCBcIkludmFsaWRTdGF0ZUVycm9yXCIpO1xuICAgIH1cbiAgICBpZiAoRE9NRXhjZXB0aW9uID09IG51bGwpIHtcbiAgICAgICAgRE9NRXhjZXB0aW9uID0gY2xhc3MgRE9NRXhjZXB0aW9uIGV4dGVuZHMgRXJyb3Ige1xuICAgICAgICAgICAgY29uc3RydWN0b3IobXNnKSB7XG4gICAgICAgICAgICAgICAgc3VwZXIobXNnKTtcbiAgICAgICAgICAgICAgICBpZiAoRXJyb3IuY2FwdHVyZVN0YWNrVHJhY2UpIHtcbiAgICAgICAgICAgICAgICAgICAgRXJyb3IuY2FwdHVyZVN0YWNrVHJhY2UodGhpcywgRE9NRXhjZXB0aW9uKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY2xhc3MtbWV0aG9kcy11c2UtdGhpc1xuICAgICAgICAgICAgZ2V0IGNvZGUoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIDExO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNsYXNzLW1ldGhvZHMtdXNlLXRoaXNcbiAgICAgICAgICAgIGdldCBuYW1lKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBcIkludmFsaWRTdGF0ZUVycm9yXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKERPTUV4Y2VwdGlvbi5wcm90b3R5cGUsIHtcbiAgICAgICAgICAgIGNvZGU6IHsgZW51bWVyYWJsZTogdHJ1ZSB9LFxuICAgICAgICAgICAgbmFtZTogeyBlbnVtZXJhYmxlOiB0cnVlIH0sXG4gICAgICAgIH0pO1xuICAgICAgICBkZWZpbmVFcnJvckNvZGVQcm9wZXJ0aWVzKERPTUV4Y2VwdGlvbik7XG4gICAgICAgIGRlZmluZUVycm9yQ29kZVByb3BlcnRpZXMoRE9NRXhjZXB0aW9uLnByb3RvdHlwZSk7XG4gICAgfVxuICAgIHJldHVybiBuZXcgRE9NRXhjZXB0aW9uKG1lc3NhZ2UpO1xufVxuLy8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEhlbHBlcnNcbi8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5sZXQgRE9NRXhjZXB0aW9uO1xuY29uc3QgRXJyb3JDb2RlTWFwID0ge1xuICAgIElOREVYX1NJWkVfRVJSOiAxLFxuICAgIERPTVNUUklOR19TSVpFX0VSUjogMixcbiAgICBISUVSQVJDSFlfUkVRVUVTVF9FUlI6IDMsXG4gICAgV1JPTkdfRE9DVU1FTlRfRVJSOiA0LFxuICAgIElOVkFMSURfQ0hBUkFDVEVSX0VSUjogNSxcbiAgICBOT19EQVRBX0FMTE9XRURfRVJSOiA2LFxuICAgIE5PX01PRElGSUNBVElPTl9BTExPV0VEX0VSUjogNyxcbiAgICBOT1RfRk9VTkRfRVJSOiA4LFxuICAgIE5PVF9TVVBQT1JURURfRVJSOiA5LFxuICAgIElOVVNFX0FUVFJJQlVURV9FUlI6IDEwLFxuICAgIElOVkFMSURfU1RBVEVfRVJSOiAxMSxcbiAgICBTWU5UQVhfRVJSOiAxMixcbiAgICBJTlZBTElEX01PRElGSUNBVElPTl9FUlI6IDEzLFxuICAgIE5BTUVTUEFDRV9FUlI6IDE0LFxuICAgIElOVkFMSURfQUNDRVNTX0VSUjogMTUsXG4gICAgVkFMSURBVElPTl9FUlI6IDE2LFxuICAgIFRZUEVfTUlTTUFUQ0hfRVJSOiAxNyxcbiAgICBTRUNVUklUWV9FUlI6IDE4LFxuICAgIE5FVFdPUktfRVJSOiAxOSxcbiAgICBBQk9SVF9FUlI6IDIwLFxuICAgIFVSTF9NSVNNQVRDSF9FUlI6IDIxLFxuICAgIFFVT1RBX0VYQ0VFREVEX0VSUjogMjIsXG4gICAgVElNRU9VVF9FUlI6IDIzLFxuICAgIElOVkFMSURfTk9ERV9UWVBFX0VSUjogMjQsXG4gICAgREFUQV9DTE9ORV9FUlI6IDI1LFxufTtcbmZ1bmN0aW9uIGRlZmluZUVycm9yQ29kZVByb3BlcnRpZXMob2JqKSB7XG4gICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKEVycm9yQ29kZU1hcCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgIGNvbnN0IGtleSA9IGtleXNbaV07XG4gICAgICAgIGNvbnN0IHZhbHVlID0gRXJyb3JDb2RlTWFwW2tleV07XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmosIGtleSwge1xuICAgICAgICAgICAgZ2V0KCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICB9KTtcbiAgICB9XG59XG5cbi8qKlxuICogQW4gaW1wbGVtZW50YXRpb24gb2YgYEV2ZW50YCBpbnRlcmZhY2UsIHRoYXQgd3JhcHMgYSBnaXZlbiBldmVudCBvYmplY3QuXG4gKiBUaGlzIGNsYXNzIGNvbnRyb2xzIHRoZSBpbnRlcm5hbCBzdGF0ZSBvZiBgRXZlbnRgLlxuICogQHNlZSBodHRwczovL2RvbS5zcGVjLndoYXR3Zy5vcmcvI2ludGVyZmFjZS1ldmVudFxuICovXG5jbGFzcyBFdmVudFdyYXBwZXIgZXh0ZW5kcyBFdmVudCB7XG4gICAgLyoqXG4gICAgICogV3JhcCBhIGdpdmVuIGV2ZW50IG9iamVjdCB0byBjb250cm9sIHN0YXRlcy5cbiAgICAgKiBAcGFyYW0gZXZlbnQgVGhlIGV2ZW50LWxpa2Ugb2JqZWN0IHRvIHdyYXAuXG4gICAgICovXG4gICAgc3RhdGljIHdyYXAoZXZlbnQpIHtcbiAgICAgICAgcmV0dXJuIG5ldyAoZ2V0V3JhcHBlckNsYXNzT2YoZXZlbnQpKShldmVudCk7XG4gICAgfVxuICAgIGNvbnN0cnVjdG9yKGV2ZW50KSB7XG4gICAgICAgIHN1cGVyKGV2ZW50LnR5cGUsIHtcbiAgICAgICAgICAgIGJ1YmJsZXM6IGV2ZW50LmJ1YmJsZXMsXG4gICAgICAgICAgICBjYW5jZWxhYmxlOiBldmVudC5jYW5jZWxhYmxlLFxuICAgICAgICAgICAgY29tcG9zZWQ6IGV2ZW50LmNvbXBvc2VkLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGV2ZW50LmNhbmNlbEJ1YmJsZSkge1xuICAgICAgICAgICAgc3VwZXIuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2ZW50LmRlZmF1bHRQcmV2ZW50ZWQpIHtcbiAgICAgICAgICAgIHN1cGVyLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIH1cbiAgICAgICAgaW50ZXJuYWxEYXRhTWFwJDEuc2V0KHRoaXMsIHsgb3JpZ2luYWw6IGV2ZW50IH0pO1xuICAgICAgICAvLyBEZWZpbmUgYWNjZXNzb3JzXG4gICAgICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhldmVudCk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgY29uc3Qga2V5ID0ga2V5c1tpXTtcbiAgICAgICAgICAgIGlmICghKGtleSBpbiB0aGlzKSkge1xuICAgICAgICAgICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBrZXksIGRlZmluZVJlZGlyZWN0RGVzY3JpcHRvcihldmVudCwga2V5KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgc3RvcFByb3BhZ2F0aW9uKCkge1xuICAgICAgICBzdXBlci5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgY29uc3QgeyBvcmlnaW5hbCB9ID0gJCQxKHRoaXMpO1xuICAgICAgICBpZiAoXCJzdG9wUHJvcGFnYXRpb25cIiBpbiBvcmlnaW5hbCkge1xuICAgICAgICAgICAgb3JpZ2luYWwuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZ2V0IGNhbmNlbEJ1YmJsZSgpIHtcbiAgICAgICAgcmV0dXJuIHN1cGVyLmNhbmNlbEJ1YmJsZTtcbiAgICB9XG4gICAgc2V0IGNhbmNlbEJ1YmJsZSh2YWx1ZSkge1xuICAgICAgICBzdXBlci5jYW5jZWxCdWJibGUgPSB2YWx1ZTtcbiAgICAgICAgY29uc3QgeyBvcmlnaW5hbCB9ID0gJCQxKHRoaXMpO1xuICAgICAgICBpZiAoXCJjYW5jZWxCdWJibGVcIiBpbiBvcmlnaW5hbCkge1xuICAgICAgICAgICAgb3JpZ2luYWwuY2FuY2VsQnViYmxlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG4gICAgc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCkge1xuICAgICAgICBzdXBlci5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcbiAgICAgICAgY29uc3QgeyBvcmlnaW5hbCB9ID0gJCQxKHRoaXMpO1xuICAgICAgICBpZiAoXCJzdG9wSW1tZWRpYXRlUHJvcGFnYXRpb25cIiBpbiBvcmlnaW5hbCkge1xuICAgICAgICAgICAgb3JpZ2luYWwuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZ2V0IHJldHVyblZhbHVlKCkge1xuICAgICAgICByZXR1cm4gc3VwZXIucmV0dXJuVmFsdWU7XG4gICAgfVxuICAgIHNldCByZXR1cm5WYWx1ZSh2YWx1ZSkge1xuICAgICAgICBzdXBlci5yZXR1cm5WYWx1ZSA9IHZhbHVlO1xuICAgICAgICBjb25zdCB7IG9yaWdpbmFsIH0gPSAkJDEodGhpcyk7XG4gICAgICAgIGlmIChcInJldHVyblZhbHVlXCIgaW4gb3JpZ2luYWwpIHtcbiAgICAgICAgICAgIG9yaWdpbmFsLnJldHVyblZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcHJldmVudERlZmF1bHQoKSB7XG4gICAgICAgIHN1cGVyLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGNvbnN0IHsgb3JpZ2luYWwgfSA9ICQkMSh0aGlzKTtcbiAgICAgICAgaWYgKFwicHJldmVudERlZmF1bHRcIiBpbiBvcmlnaW5hbCkge1xuICAgICAgICAgICAgb3JpZ2luYWwucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBnZXQgdGltZVN0YW1wKCkge1xuICAgICAgICBjb25zdCB7IG9yaWdpbmFsIH0gPSAkJDEodGhpcyk7XG4gICAgICAgIGlmIChcInRpbWVTdGFtcFwiIGluIG9yaWdpbmFsKSB7XG4gICAgICAgICAgICByZXR1cm4gb3JpZ2luYWwudGltZVN0YW1wO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzdXBlci50aW1lU3RhbXA7XG4gICAgfVxufVxuLyoqXG4gKiBQcml2YXRlIGRhdGEgZm9yIGV2ZW50IHdyYXBwZXJzLlxuICovXG5jb25zdCBpbnRlcm5hbERhdGFNYXAkMSA9IG5ldyBXZWFrTWFwKCk7XG4vKipcbiAqIEdldCBwcml2YXRlIGRhdGEuXG4gKiBAcGFyYW0gZXZlbnQgVGhlIGV2ZW50IG9iamVjdCB0byBnZXQgcHJpdmF0ZSBkYXRhLlxuICogQHJldHVybnMgVGhlIHByaXZhdGUgZGF0YSBvZiB0aGUgZXZlbnQuXG4gKi9cbmZ1bmN0aW9uICQkMShldmVudCkge1xuICAgIGNvbnN0IHJldHYgPSBpbnRlcm5hbERhdGFNYXAkMS5nZXQoZXZlbnQpO1xuICAgIGFzc2VydFR5cGUocmV0diAhPSBudWxsLCBcIid0aGlzJyBpcyBleHBlY3RlZCBhbiBFdmVudCBvYmplY3QsIGJ1dCBnb3RcIiwgZXZlbnQpO1xuICAgIHJldHVybiByZXR2O1xufVxuLyoqXG4gKiBDYWNoZSBmb3Igd3JhcHBlciBjbGFzc2VzLlxuICogQHR5cGUge1dlYWtNYXA8T2JqZWN0LCBGdW5jdGlvbj59XG4gKiBAcHJpdmF0ZVxuICovXG5jb25zdCB3cmFwcGVyQ2xhc3NDYWNoZSA9IG5ldyBXZWFrTWFwKCk7XG4vLyBNYWtlIGFzc29jaWF0aW9uIGZvciB3cmFwcGVycy5cbndyYXBwZXJDbGFzc0NhY2hlLnNldChPYmplY3QucHJvdG90eXBlLCBFdmVudFdyYXBwZXIpO1xuaWYgKHR5cGVvZiBHbG9iYWwgIT09IFwidW5kZWZpbmVkXCIgJiYgdHlwZW9mIEdsb2JhbC5FdmVudCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgIHdyYXBwZXJDbGFzc0NhY2hlLnNldChHbG9iYWwuRXZlbnQucHJvdG90eXBlLCBFdmVudFdyYXBwZXIpO1xufVxuLyoqXG4gKiBHZXQgdGhlIHdyYXBwZXIgY2xhc3Mgb2YgYSBnaXZlbiBwcm90b3R5cGUuXG4gKiBAcGFyYW0gb3JpZ2luYWxFdmVudCBUaGUgZXZlbnQgb2JqZWN0IHRvIHdyYXAuXG4gKi9cbmZ1bmN0aW9uIGdldFdyYXBwZXJDbGFzc09mKG9yaWdpbmFsRXZlbnQpIHtcbiAgICBjb25zdCBwcm90b3R5cGUgPSBPYmplY3QuZ2V0UHJvdG90eXBlT2Yob3JpZ2luYWxFdmVudCk7XG4gICAgaWYgKHByb3RvdHlwZSA9PSBudWxsKSB7XG4gICAgICAgIHJldHVybiBFdmVudFdyYXBwZXI7XG4gICAgfVxuICAgIGxldCB3cmFwcGVyID0gd3JhcHBlckNsYXNzQ2FjaGUuZ2V0KHByb3RvdHlwZSk7XG4gICAgaWYgKHdyYXBwZXIgPT0gbnVsbCkge1xuICAgICAgICB3cmFwcGVyID0gZGVmaW5lV3JhcHBlcihnZXRXcmFwcGVyQ2xhc3NPZihwcm90b3R5cGUpLCBwcm90b3R5cGUpO1xuICAgICAgICB3cmFwcGVyQ2xhc3NDYWNoZS5zZXQocHJvdG90eXBlLCB3cmFwcGVyKTtcbiAgICB9XG4gICAgcmV0dXJuIHdyYXBwZXI7XG59XG4vKipcbiAqIERlZmluZSBuZXcgd3JhcHBlciBjbGFzcy5cbiAqIEBwYXJhbSBCYXNlRXZlbnRXcmFwcGVyIFRoZSBiYXNlIHdyYXBwZXIgY2xhc3MuXG4gKiBAcGFyYW0gb3JpZ2luYWxQcm90b3R5cGUgVGhlIHByb3RvdHlwZSBvZiB0aGUgb3JpZ2luYWwgZXZlbnQuXG4gKi9cbmZ1bmN0aW9uIGRlZmluZVdyYXBwZXIoQmFzZUV2ZW50V3JhcHBlciwgb3JpZ2luYWxQcm90b3R5cGUpIHtcbiAgICBjbGFzcyBDdXN0b21FdmVudFdyYXBwZXIgZXh0ZW5kcyBCYXNlRXZlbnRXcmFwcGVyIHtcbiAgICB9XG4gICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKG9yaWdpbmFsUHJvdG90eXBlKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEN1c3RvbUV2ZW50V3JhcHBlci5wcm90b3R5cGUsIGtleXNbaV0sIGRlZmluZVJlZGlyZWN0RGVzY3JpcHRvcihvcmlnaW5hbFByb3RvdHlwZSwga2V5c1tpXSkpO1xuICAgIH1cbiAgICByZXR1cm4gQ3VzdG9tRXZlbnRXcmFwcGVyO1xufVxuLyoqXG4gKiBHZXQgdGhlIHByb3BlcnR5IGRlc2NyaXB0b3IgdG8gcmVkaXJlY3QgYSBnaXZlbiBwcm9wZXJ0eS5cbiAqL1xuZnVuY3Rpb24gZGVmaW5lUmVkaXJlY3REZXNjcmlwdG9yKG9iaiwga2V5KSB7XG4gICAgY29uc3QgZCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3Iob2JqLCBrZXkpO1xuICAgIHJldHVybiB7XG4gICAgICAgIGdldCgpIHtcbiAgICAgICAgICAgIGNvbnN0IG9yaWdpbmFsID0gJCQxKHRoaXMpLm9yaWdpbmFsO1xuICAgICAgICAgICAgY29uc3QgdmFsdWUgPSBvcmlnaW5hbFtrZXldO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlLmJpbmQob3JpZ2luYWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQodmFsdWUpIHtcbiAgICAgICAgICAgIGNvbnN0IG9yaWdpbmFsID0gJCQxKHRoaXMpLm9yaWdpbmFsO1xuICAgICAgICAgICAgb3JpZ2luYWxba2V5XSA9IHZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBjb25maWd1cmFibGU6IGQuY29uZmlndXJhYmxlLFxuICAgICAgICBlbnVtZXJhYmxlOiBkLmVudW1lcmFibGUsXG4gICAgfTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBuZXcgbGlzdGVuZXIuXG4gKiBAcGFyYW0gY2FsbGJhY2sgVGhlIGNhbGxiYWNrIGZ1bmN0aW9uLlxuICogQHBhcmFtIGNhcHR1cmUgVGhlIGNhcHR1cmUgZmxhZy5cbiAqIEBwYXJhbSBwYXNzaXZlIFRoZSBwYXNzaXZlIGZsYWcuXG4gKiBAcGFyYW0gb25jZSBUaGUgb25jZSBmbGFnLlxuICogQHBhcmFtIHNpZ25hbCBUaGUgYWJvcnQgc2lnbmFsLlxuICogQHBhcmFtIHNpZ25hbExpc3RlbmVyIFRoZSBhYm9ydCBldmVudCBsaXN0ZW5lciBmb3IgdGhlIGFib3J0IHNpZ25hbC5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlTGlzdGVuZXIoY2FsbGJhY2ssIGNhcHR1cmUsIHBhc3NpdmUsIG9uY2UsIHNpZ25hbCwgc2lnbmFsTGlzdGVuZXIpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBjYWxsYmFjayxcbiAgICAgICAgZmxhZ3M6IChjYXB0dXJlID8gMSAvKiBDYXB0dXJlICovIDogMCkgfFxuICAgICAgICAgICAgKHBhc3NpdmUgPyAyIC8qIFBhc3NpdmUgKi8gOiAwKSB8XG4gICAgICAgICAgICAob25jZSA/IDQgLyogT25jZSAqLyA6IDApLFxuICAgICAgICBzaWduYWwsXG4gICAgICAgIHNpZ25hbExpc3RlbmVyLFxuICAgIH07XG59XG4vKipcbiAqIFNldCB0aGUgYHJlbW92ZWRgIGZsYWcgdG8gdGhlIGdpdmVuIGxpc3RlbmVyLlxuICogQHBhcmFtIGxpc3RlbmVyIFRoZSBsaXN0ZW5lciB0byBjaGVjay5cbiAqL1xuZnVuY3Rpb24gc2V0UmVtb3ZlZChsaXN0ZW5lcikge1xuICAgIGxpc3RlbmVyLmZsYWdzIHw9IDggLyogUmVtb3ZlZCAqLztcbn1cbi8qKlxuICogQ2hlY2sgaWYgdGhlIGdpdmVuIGxpc3RlbmVyIGhhcyB0aGUgYGNhcHR1cmVgIGZsYWcgb3Igbm90LlxuICogQHBhcmFtIGxpc3RlbmVyIFRoZSBsaXN0ZW5lciB0byBjaGVjay5cbiAqL1xuZnVuY3Rpb24gaXNDYXB0dXJlKGxpc3RlbmVyKSB7XG4gICAgcmV0dXJuIChsaXN0ZW5lci5mbGFncyAmIDEgLyogQ2FwdHVyZSAqLykgPT09IDEgLyogQ2FwdHVyZSAqLztcbn1cbi8qKlxuICogQ2hlY2sgaWYgdGhlIGdpdmVuIGxpc3RlbmVyIGhhcyB0aGUgYHBhc3NpdmVgIGZsYWcgb3Igbm90LlxuICogQHBhcmFtIGxpc3RlbmVyIFRoZSBsaXN0ZW5lciB0byBjaGVjay5cbiAqL1xuZnVuY3Rpb24gaXNQYXNzaXZlKGxpc3RlbmVyKSB7XG4gICAgcmV0dXJuIChsaXN0ZW5lci5mbGFncyAmIDIgLyogUGFzc2l2ZSAqLykgPT09IDIgLyogUGFzc2l2ZSAqLztcbn1cbi8qKlxuICogQ2hlY2sgaWYgdGhlIGdpdmVuIGxpc3RlbmVyIGhhcyB0aGUgYG9uY2VgIGZsYWcgb3Igbm90LlxuICogQHBhcmFtIGxpc3RlbmVyIFRoZSBsaXN0ZW5lciB0byBjaGVjay5cbiAqL1xuZnVuY3Rpb24gaXNPbmNlKGxpc3RlbmVyKSB7XG4gICAgcmV0dXJuIChsaXN0ZW5lci5mbGFncyAmIDQgLyogT25jZSAqLykgPT09IDQgLyogT25jZSAqLztcbn1cbi8qKlxuICogQ2hlY2sgaWYgdGhlIGdpdmVuIGxpc3RlbmVyIGhhcyB0aGUgYHJlbW92ZWRgIGZsYWcgb3Igbm90LlxuICogQHBhcmFtIGxpc3RlbmVyIFRoZSBsaXN0ZW5lciB0byBjaGVjay5cbiAqL1xuZnVuY3Rpb24gaXNSZW1vdmVkKGxpc3RlbmVyKSB7XG4gICAgcmV0dXJuIChsaXN0ZW5lci5mbGFncyAmIDggLyogUmVtb3ZlZCAqLykgPT09IDggLyogUmVtb3ZlZCAqLztcbn1cbi8qKlxuICogQ2FsbCBhbiBldmVudCBsaXN0ZW5lci5cbiAqIEBwYXJhbSBsaXN0ZW5lciBUaGUgbGlzdGVuZXIgdG8gY2FsbC5cbiAqIEBwYXJhbSB0YXJnZXQgVGhlIGV2ZW50IHRhcmdldCBvYmplY3QgZm9yIGB0aGlzQXJnYC5cbiAqIEBwYXJhbSBldmVudCBUaGUgZXZlbnQgb2JqZWN0IGZvciB0aGUgZmlyc3QgYXJndW1lbnQuXG4gKiBAcGFyYW0gYXR0cmlidXRlIGB0cnVlYCBpZiB0aGlzIGNhbGxiYWNrIGlzIGFuIGV2ZW50IGF0dHJpYnV0ZSBoYW5kbGVyLlxuICovXG5mdW5jdGlvbiBpbnZva2VDYWxsYmFjayh7IGNhbGxiYWNrIH0sIHRhcmdldCwgZXZlbnQpIHtcbiAgICB0cnkge1xuICAgICAgICBpZiAodHlwZW9mIGNhbGxiYWNrID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwodGFyZ2V0LCBldmVudCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodHlwZW9mIGNhbGxiYWNrLmhhbmRsZUV2ZW50ID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgIGNhbGxiYWNrLmhhbmRsZUV2ZW50KGV2ZW50KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBjYXRjaCAodGhyb3duRXJyb3IpIHtcbiAgICAgICAgcmVwb3J0RXJyb3IodGhyb3duRXJyb3IpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBGaW5kIHRoZSBpbmRleCBvZiBnaXZlbiBsaXN0ZW5lci5cbiAqIFRoaXMgcmV0dXJucyBgLTFgIGlmIG5vdCBmb3VuZC5cbiAqIEBwYXJhbSBsaXN0IFRoZSBsaXN0ZW5lciBsaXN0LlxuICogQHBhcmFtIGNhbGxiYWNrIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBmaW5kLlxuICogQHBhcmFtIGNhcHR1cmUgVGhlIGNhcHR1cmUgZmxhZyB0byBmaW5kLlxuICovXG5mdW5jdGlvbiBmaW5kSW5kZXhPZkxpc3RlbmVyKHsgbGlzdGVuZXJzIH0sIGNhbGxiYWNrLCBjYXB0dXJlKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaXN0ZW5lcnMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgaWYgKGxpc3RlbmVyc1tpXS5jYWxsYmFjayA9PT0gY2FsbGJhY2sgJiZcbiAgICAgICAgICAgIGlzQ2FwdHVyZShsaXN0ZW5lcnNbaV0pID09PSBjYXB0dXJlKSB7XG4gICAgICAgICAgICByZXR1cm4gaTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gLTE7XG59XG4vKipcbiAqIEFkZCB0aGUgZ2l2ZW4gbGlzdGVuZXIuXG4gKiBEb2VzIGNvcHktb24td3JpdGUgaWYgbmVlZGVkLlxuICogQHBhcmFtIGxpc3QgVGhlIGxpc3RlbmVyIGxpc3QuXG4gKiBAcGFyYW0gY2FsbGJhY2sgVGhlIGNhbGxiYWNrIGZ1bmN0aW9uLlxuICogQHBhcmFtIGNhcHR1cmUgVGhlIGNhcHR1cmUgZmxhZy5cbiAqIEBwYXJhbSBwYXNzaXZlIFRoZSBwYXNzaXZlIGZsYWcuXG4gKiBAcGFyYW0gb25jZSBUaGUgb25jZSBmbGFnLlxuICogQHBhcmFtIHNpZ25hbCBUaGUgYWJvcnQgc2lnbmFsLlxuICovXG5mdW5jdGlvbiBhZGRMaXN0ZW5lcihsaXN0LCBjYWxsYmFjaywgY2FwdHVyZSwgcGFzc2l2ZSwgb25jZSwgc2lnbmFsKSB7XG4gICAgbGV0IHNpZ25hbExpc3RlbmVyO1xuICAgIGlmIChzaWduYWwpIHtcbiAgICAgICAgc2lnbmFsTGlzdGVuZXIgPSByZW1vdmVMaXN0ZW5lci5iaW5kKG51bGwsIGxpc3QsIGNhbGxiYWNrLCBjYXB0dXJlKTtcbiAgICAgICAgc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBzaWduYWxMaXN0ZW5lcik7XG4gICAgfVxuICAgIGNvbnN0IGxpc3RlbmVyID0gY3JlYXRlTGlzdGVuZXIoY2FsbGJhY2ssIGNhcHR1cmUsIHBhc3NpdmUsIG9uY2UsIHNpZ25hbCwgc2lnbmFsTGlzdGVuZXIpO1xuICAgIGlmIChsaXN0LmNvdykge1xuICAgICAgICBsaXN0LmNvdyA9IGZhbHNlO1xuICAgICAgICBsaXN0Lmxpc3RlbmVycyA9IFsuLi5saXN0Lmxpc3RlbmVycywgbGlzdGVuZXJdO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgbGlzdC5saXN0ZW5lcnMucHVzaChsaXN0ZW5lcik7XG4gICAgfVxuICAgIHJldHVybiBsaXN0ZW5lcjtcbn1cbi8qKlxuICogUmVtb3ZlIGEgbGlzdGVuZXIuXG4gKiBAcGFyYW0gbGlzdCBUaGUgbGlzdGVuZXIgbGlzdC5cbiAqIEBwYXJhbSBjYWxsYmFjayBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gZmluZC5cbiAqIEBwYXJhbSBjYXB0dXJlIFRoZSBjYXB0dXJlIGZsYWcgdG8gZmluZC5cbiAqIEByZXR1cm5zIGB0cnVlYCBpZiBpdCBtdXRhdGVkIHRoZSBsaXN0IGRpcmVjdGx5LlxuICovXG5mdW5jdGlvbiByZW1vdmVMaXN0ZW5lcihsaXN0LCBjYWxsYmFjaywgY2FwdHVyZSkge1xuICAgIGNvbnN0IGluZGV4ID0gZmluZEluZGV4T2ZMaXN0ZW5lcihsaXN0LCBjYWxsYmFjaywgY2FwdHVyZSk7XG4gICAgaWYgKGluZGV4ICE9PSAtMSkge1xuICAgICAgICByZXR1cm4gcmVtb3ZlTGlzdGVuZXJBdChsaXN0LCBpbmRleCk7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cbi8qKlxuICogUmVtb3ZlIGEgbGlzdGVuZXIuXG4gKiBAcGFyYW0gbGlzdCBUaGUgbGlzdGVuZXIgbGlzdC5cbiAqIEBwYXJhbSBpbmRleCBUaGUgaW5kZXggb2YgdGhlIHRhcmdldCBsaXN0ZW5lci5cbiAqIEBwYXJhbSBkaXNhYmxlQ293IERpc2FibGUgY29weS1vbi13cml0ZSBpZiB0cnVlLlxuICogQHJldHVybnMgYHRydWVgIGlmIGl0IG11dGF0ZWQgdGhlIGBsaXN0ZW5lcnNgIGFycmF5IGRpcmVjdGx5LlxuICovXG5mdW5jdGlvbiByZW1vdmVMaXN0ZW5lckF0KGxpc3QsIGluZGV4LCBkaXNhYmxlQ293ID0gZmFsc2UpIHtcbiAgICBjb25zdCBsaXN0ZW5lciA9IGxpc3QubGlzdGVuZXJzW2luZGV4XTtcbiAgICAvLyBTZXQgdGhlIHJlbW92ZWQgZmxhZy5cbiAgICBzZXRSZW1vdmVkKGxpc3RlbmVyKTtcbiAgICAvLyBEaXNwb3NlIHRoZSBhYm9ydCBzaWduYWwgbGlzdGVuZXIgaWYgZXhpc3RzLlxuICAgIGlmIChsaXN0ZW5lci5zaWduYWwpIHtcbiAgICAgICAgbGlzdGVuZXIuc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBsaXN0ZW5lci5zaWduYWxMaXN0ZW5lcik7XG4gICAgfVxuICAgIC8vIFJlbW92ZSBpdCBmcm9tIHRoZSBhcnJheS5cbiAgICBpZiAobGlzdC5jb3cgJiYgIWRpc2FibGVDb3cpIHtcbiAgICAgICAgbGlzdC5jb3cgPSBmYWxzZTtcbiAgICAgICAgbGlzdC5saXN0ZW5lcnMgPSBsaXN0Lmxpc3RlbmVycy5maWx0ZXIoKF8sIGkpID0+IGkgIT09IGluZGV4KTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBsaXN0Lmxpc3RlbmVycy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgIHJldHVybiB0cnVlO1xufVxuXG4vKipcbiAqIENyZWF0ZSBhIG5ldyBgTGlzdGVuZXJMaXN0TWFwYCBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUxpc3RlbmVyTGlzdE1hcCgpIHtcbiAgICByZXR1cm4gT2JqZWN0LmNyZWF0ZShudWxsKTtcbn1cbi8qKlxuICogR2V0IHRoZSBsaXN0ZW5lciBsaXN0IG9mIHRoZSBnaXZlbiB0eXBlLlxuICogSWYgdGhlIGxpc3RlbmVyIGxpc3QgaGFzIG5vdCBiZWVuIGluaXRpYWxpemVkLCBpbml0aWFsaXplIGFuZCByZXR1cm4gaXQuXG4gKiBAcGFyYW0gbGlzdGVuZXJNYXAgVGhlIGxpc3RlbmVyIGxpc3QgbWFwLlxuICogQHBhcmFtIHR5cGUgVGhlIGV2ZW50IHR5cGUgdG8gZ2V0LlxuICovXG5mdW5jdGlvbiBlbnN1cmVMaXN0ZW5lckxpc3QobGlzdGVuZXJNYXAsIHR5cGUpIHtcbiAgICB2YXIgX2E7XG4gICAgcmV0dXJuICgoX2EgPSBsaXN0ZW5lck1hcFt0eXBlXSkgIT09IG51bGwgJiYgX2EgIT09IHZvaWQgMCA/IF9hIDogKGxpc3RlbmVyTWFwW3R5cGVdID0ge1xuICAgICAgICBhdHRyQ2FsbGJhY2s6IHVuZGVmaW5lZCxcbiAgICAgICAgYXR0ckxpc3RlbmVyOiB1bmRlZmluZWQsXG4gICAgICAgIGNvdzogZmFsc2UsXG4gICAgICAgIGxpc3RlbmVyczogW10sXG4gICAgfSkpO1xufVxuXG4vKipcbiAqIEFuIGltcGxlbWVudGF0aW9uIG9mIHRoZSBgRXZlbnRUYXJnZXRgIGludGVyZmFjZS5cbiAqIEBzZWUgaHR0cHM6Ly9kb20uc3BlYy53aGF0d2cub3JnLyNldmVudHRhcmdldFxuICovXG5jbGFzcyBFdmVudFRhcmdldCB7XG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZSB0aGlzIGluc3RhbmNlLlxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBpbnRlcm5hbERhdGFNYXAkMi5zZXQodGhpcywgY3JlYXRlTGlzdGVuZXJMaXN0TWFwKCkpO1xuICAgIH1cbiAgICAvLyBJbXBsZW1lbnRhdGlvblxuICAgIGFkZEV2ZW50TGlzdGVuZXIodHlwZTAsIGNhbGxiYWNrMCwgb3B0aW9uczApIHtcbiAgICAgICAgY29uc3QgbGlzdGVuZXJNYXAgPSAkJDIodGhpcyk7XG4gICAgICAgIGNvbnN0IHsgY2FsbGJhY2ssIGNhcHR1cmUsIG9uY2UsIHBhc3NpdmUsIHNpZ25hbCwgdHlwZSwgfSA9IG5vcm1hbGl6ZUFkZE9wdGlvbnModHlwZTAsIGNhbGxiYWNrMCwgb3B0aW9uczApO1xuICAgICAgICBpZiAoY2FsbGJhY2sgPT0gbnVsbCB8fCAoc2lnbmFsID09PSBudWxsIHx8IHNpZ25hbCA9PT0gdm9pZCAwID8gdm9pZCAwIDogc2lnbmFsLmFib3J0ZWQpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbGlzdCA9IGVuc3VyZUxpc3RlbmVyTGlzdChsaXN0ZW5lck1hcCwgdHlwZSk7XG4gICAgICAgIC8vIEZpbmQgZXhpc3RpbmcgbGlzdGVuZXIuXG4gICAgICAgIGNvbnN0IGkgPSBmaW5kSW5kZXhPZkxpc3RlbmVyKGxpc3QsIGNhbGxiYWNrLCBjYXB0dXJlKTtcbiAgICAgICAgaWYgKGkgIT09IC0xKSB7XG4gICAgICAgICAgICB3YXJuRHVwbGljYXRlKGxpc3QubGlzdGVuZXJzW2ldLCBwYXNzaXZlLCBvbmNlLCBzaWduYWwpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIEFkZCB0aGUgbmV3IGxpc3RlbmVyLlxuICAgICAgICBhZGRMaXN0ZW5lcihsaXN0LCBjYWxsYmFjaywgY2FwdHVyZSwgcGFzc2l2ZSwgb25jZSwgc2lnbmFsKTtcbiAgICB9XG4gICAgLy8gSW1wbGVtZW50YXRpb25cbiAgICByZW1vdmVFdmVudExpc3RlbmVyKHR5cGUwLCBjYWxsYmFjazAsIG9wdGlvbnMwKSB7XG4gICAgICAgIGNvbnN0IGxpc3RlbmVyTWFwID0gJCQyKHRoaXMpO1xuICAgICAgICBjb25zdCB7IGNhbGxiYWNrLCBjYXB0dXJlLCB0eXBlIH0gPSBub3JtYWxpemVPcHRpb25zKHR5cGUwLCBjYWxsYmFjazAsIG9wdGlvbnMwKTtcbiAgICAgICAgY29uc3QgbGlzdCA9IGxpc3RlbmVyTWFwW3R5cGVdO1xuICAgICAgICBpZiAoY2FsbGJhY2sgIT0gbnVsbCAmJiBsaXN0KSB7XG4gICAgICAgICAgICByZW1vdmVMaXN0ZW5lcihsaXN0LCBjYWxsYmFjaywgY2FwdHVyZSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gSW1wbGVtZW50YXRpb25cbiAgICBkaXNwYXRjaEV2ZW50KGUpIHtcbiAgICAgICAgY29uc3QgbGlzdCA9ICQkMih0aGlzKVtTdHJpbmcoZS50eXBlKV07XG4gICAgICAgIGlmIChsaXN0ID09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGV2ZW50ID0gZSBpbnN0YW5jZW9mIEV2ZW50ID8gZSA6IEV2ZW50V3JhcHBlci53cmFwKGUpO1xuICAgICAgICBjb25zdCBldmVudERhdGEgPSAkKGV2ZW50LCBcImV2ZW50XCIpO1xuICAgICAgICBpZiAoZXZlbnREYXRhLmRpc3BhdGNoRmxhZykge1xuICAgICAgICAgICAgdGhyb3cgY3JlYXRlSW52YWxpZFN0YXRlRXJyb3IoXCJUaGlzIGV2ZW50IGhhcyBiZWVuIGluIGRpc3BhdGNoaW5nLlwiKTtcbiAgICAgICAgfVxuICAgICAgICBldmVudERhdGEuZGlzcGF0Y2hGbGFnID0gdHJ1ZTtcbiAgICAgICAgZXZlbnREYXRhLnRhcmdldCA9IGV2ZW50RGF0YS5jdXJyZW50VGFyZ2V0ID0gdGhpcztcbiAgICAgICAgaWYgKCFldmVudERhdGEuc3RvcFByb3BhZ2F0aW9uRmxhZykge1xuICAgICAgICAgICAgY29uc3QgeyBjb3csIGxpc3RlbmVycyB9ID0gbGlzdDtcbiAgICAgICAgICAgIC8vIFNldCBjb3B5LW9uLXdyaXRlIGZsYWcuXG4gICAgICAgICAgICBsaXN0LmNvdyA9IHRydWU7XG4gICAgICAgICAgICAvLyBDYWxsIGxpc3RlbmVycy5cbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGlzdGVuZXJzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgbGlzdGVuZXIgPSBsaXN0ZW5lcnNbaV07XG4gICAgICAgICAgICAgICAgLy8gU2tpcCBpZiByZW1vdmVkLlxuICAgICAgICAgICAgICAgIGlmIChpc1JlbW92ZWQobGlzdGVuZXIpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBSZW1vdmUgdGhpcyBsaXN0ZW5lciBpZiBoYXMgdGhlIGBvbmNlYCBmbGFnLlxuICAgICAgICAgICAgICAgIGlmIChpc09uY2UobGlzdGVuZXIpICYmIHJlbW92ZUxpc3RlbmVyQXQobGlzdCwgaSwgIWNvdykpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQmVjYXVzZSB0aGlzIGxpc3RlbmVyIHdhcyByZW1vdmVkLCB0aGUgbmV4dCBpbmRleCBpcyB0aGVcbiAgICAgICAgICAgICAgICAgICAgLy8gc2FtZSBhcyB0aGUgY3VycmVudCB2YWx1ZS5cbiAgICAgICAgICAgICAgICAgICAgaSAtPSAxO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBDYWxsIHRoaXMgbGlzdGVuZXIgd2l0aCB0aGUgYHBhc3NpdmVgIGZsYWcuXG4gICAgICAgICAgICAgICAgZXZlbnREYXRhLmluUGFzc2l2ZUxpc3RlbmVyRmxhZyA9IGlzUGFzc2l2ZShsaXN0ZW5lcik7XG4gICAgICAgICAgICAgICAgaW52b2tlQ2FsbGJhY2sobGlzdGVuZXIsIHRoaXMsIGV2ZW50KTtcbiAgICAgICAgICAgICAgICBldmVudERhdGEuaW5QYXNzaXZlTGlzdGVuZXJGbGFnID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgLy8gU3RvcCBpZiB0aGUgYGV2ZW50LnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpYCBtZXRob2Qgd2FzIGNhbGxlZC5cbiAgICAgICAgICAgICAgICBpZiAoZXZlbnREYXRhLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbkZsYWcpIHtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gUmVzdG9yZSBjb3B5LW9uLXdyaXRlIGZsYWcuXG4gICAgICAgICAgICBpZiAoIWNvdykge1xuICAgICAgICAgICAgICAgIGxpc3QuY293ID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZXZlbnREYXRhLnRhcmdldCA9IG51bGw7XG4gICAgICAgIGV2ZW50RGF0YS5jdXJyZW50VGFyZ2V0ID0gbnVsbDtcbiAgICAgICAgZXZlbnREYXRhLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbkZsYWcgPSBmYWxzZTtcbiAgICAgICAgZXZlbnREYXRhLnN0b3BQcm9wYWdhdGlvbkZsYWcgPSBmYWxzZTtcbiAgICAgICAgZXZlbnREYXRhLmRpc3BhdGNoRmxhZyA9IGZhbHNlO1xuICAgICAgICByZXR1cm4gIWV2ZW50RGF0YS5jYW5jZWxlZEZsYWc7XG4gICAgfVxufVxuLyoqXG4gKiBJbnRlcm5hbCBkYXRhLlxuICovXG5jb25zdCBpbnRlcm5hbERhdGFNYXAkMiA9IG5ldyBXZWFrTWFwKCk7XG4vKipcbiAqIEdldCBwcml2YXRlIGRhdGEuXG4gKiBAcGFyYW0gdGFyZ2V0IFRoZSBldmVudCB0YXJnZXQgb2JqZWN0IHRvIGdldCBwcml2YXRlIGRhdGEuXG4gKiBAcGFyYW0gbmFtZSBUaGUgdmFyaWFibGUgbmFtZSB0byByZXBvcnQuXG4gKiBAcmV0dXJucyBUaGUgcHJpdmF0ZSBkYXRhIG9mIHRoZSBldmVudC5cbiAqL1xuZnVuY3Rpb24gJCQyKHRhcmdldCwgbmFtZSA9IFwidGhpc1wiKSB7XG4gICAgY29uc3QgcmV0diA9IGludGVybmFsRGF0YU1hcCQyLmdldCh0YXJnZXQpO1xuICAgIGFzc2VydFR5cGUocmV0diAhPSBudWxsLCBcIiclcycgbXVzdCBiZSBhbiBvYmplY3QgdGhhdCBFdmVudFRhcmdldCBjb25zdHJ1Y3RvciBjcmVhdGVkLCBidXQgZ290IGFub3RoZXIgb25lOiAlb1wiLCBuYW1lLCB0YXJnZXQpO1xuICAgIHJldHVybiByZXR2O1xufVxuLyoqXG4gKiBOb3JtYWxpemUgb3B0aW9ucy5cbiAqIEBwYXJhbSBvcHRpb25zIFRoZSBvcHRpb25zIHRvIG5vcm1hbGl6ZS5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplQWRkT3B0aW9ucyh0eXBlLCBjYWxsYmFjaywgb3B0aW9ucykge1xuICAgIHZhciBfYTtcbiAgICBhc3NlcnRDYWxsYmFjayhjYWxsYmFjayk7XG4gICAgaWYgKHR5cGVvZiBvcHRpb25zID09PSBcIm9iamVjdFwiICYmIG9wdGlvbnMgIT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHR5cGU6IFN0cmluZyh0eXBlKSxcbiAgICAgICAgICAgIGNhbGxiYWNrOiBjYWxsYmFjayAhPT0gbnVsbCAmJiBjYWxsYmFjayAhPT0gdm9pZCAwID8gY2FsbGJhY2sgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBjYXB0dXJlOiBCb29sZWFuKG9wdGlvbnMuY2FwdHVyZSksXG4gICAgICAgICAgICBwYXNzaXZlOiBCb29sZWFuKG9wdGlvbnMucGFzc2l2ZSksXG4gICAgICAgICAgICBvbmNlOiBCb29sZWFuKG9wdGlvbnMub25jZSksXG4gICAgICAgICAgICBzaWduYWw6IChfYSA9IG9wdGlvbnMuc2lnbmFsKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiB1bmRlZmluZWQsXG4gICAgICAgIH07XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIHR5cGU6IFN0cmluZyh0eXBlKSxcbiAgICAgICAgY2FsbGJhY2s6IGNhbGxiYWNrICE9PSBudWxsICYmIGNhbGxiYWNrICE9PSB2b2lkIDAgPyBjYWxsYmFjayA6IHVuZGVmaW5lZCxcbiAgICAgICAgY2FwdHVyZTogQm9vbGVhbihvcHRpb25zKSxcbiAgICAgICAgcGFzc2l2ZTogZmFsc2UsXG4gICAgICAgIG9uY2U6IGZhbHNlLFxuICAgICAgICBzaWduYWw6IHVuZGVmaW5lZCxcbiAgICB9O1xufVxuLyoqXG4gKiBOb3JtYWxpemUgb3B0aW9ucy5cbiAqIEBwYXJhbSBvcHRpb25zIFRoZSBvcHRpb25zIHRvIG5vcm1hbGl6ZS5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplT3B0aW9ucyh0eXBlLCBjYWxsYmFjaywgb3B0aW9ucykge1xuICAgIGFzc2VydENhbGxiYWNrKGNhbGxiYWNrKTtcbiAgICBpZiAodHlwZW9mIG9wdGlvbnMgPT09IFwib2JqZWN0XCIgJiYgb3B0aW9ucyAhPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgdHlwZTogU3RyaW5nKHR5cGUpLFxuICAgICAgICAgICAgY2FsbGJhY2s6IGNhbGxiYWNrICE9PSBudWxsICYmIGNhbGxiYWNrICE9PSB2b2lkIDAgPyBjYWxsYmFjayA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGNhcHR1cmU6IEJvb2xlYW4ob3B0aW9ucy5jYXB0dXJlKSxcbiAgICAgICAgfTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgICAgdHlwZTogU3RyaW5nKHR5cGUpLFxuICAgICAgICBjYWxsYmFjazogY2FsbGJhY2sgIT09IG51bGwgJiYgY2FsbGJhY2sgIT09IHZvaWQgMCA/IGNhbGxiYWNrIDogdW5kZWZpbmVkLFxuICAgICAgICBjYXB0dXJlOiBCb29sZWFuKG9wdGlvbnMpLFxuICAgIH07XG59XG4vKipcbiAqIEFzc2VydCB0aGUgdHlwZSBvZiAnY2FsbGJhY2snIGFyZ3VtZW50LlxuICogQHBhcmFtIGNhbGxiYWNrIFRoZSBjYWxsYmFjayB0byBjaGVjay5cbiAqL1xuZnVuY3Rpb24gYXNzZXJ0Q2FsbGJhY2soY2FsbGJhY2spIHtcbiAgICBpZiAodHlwZW9mIGNhbGxiYWNrID09PSBcImZ1bmN0aW9uXCIgfHxcbiAgICAgICAgKHR5cGVvZiBjYWxsYmFjayA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgICAgICAgY2FsbGJhY2sgIT09IG51bGwgJiZcbiAgICAgICAgICAgIHR5cGVvZiBjYWxsYmFjay5oYW5kbGVFdmVudCA9PT0gXCJmdW5jdGlvblwiKSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChjYWxsYmFjayA9PSBudWxsIHx8IHR5cGVvZiBjYWxsYmFjayA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICBJbnZhbGlkRXZlbnRMaXN0ZW5lci53YXJuKGNhbGxiYWNrKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGZvcm1hdChJbnZhbGlkRXZlbnRMaXN0ZW5lci5tZXNzYWdlLCBbY2FsbGJhY2tdKSk7XG59XG4vKipcbiAqIFByaW50IHdhcm5pbmcgZm9yIGR1cGxpY2F0ZWQuXG4gKiBAcGFyYW0gbGlzdGVuZXIgVGhlIGN1cnJlbnQgbGlzdGVuZXIgdGhhdCBpcyBkdXBsaWNhdGVkLlxuICogQHBhcmFtIHBhc3NpdmUgVGhlIHBhc3NpdmUgZmxhZyBvZiB0aGUgbmV3IGR1cGxpY2F0ZWQgbGlzdGVuZXIuXG4gKiBAcGFyYW0gb25jZSBUaGUgb25jZSBmbGFnIG9mIHRoZSBuZXcgZHVwbGljYXRlZCBsaXN0ZW5lci5cbiAqIEBwYXJhbSBzaWduYWwgVGhlIHNpZ25hbCBvYmplY3Qgb2YgdGhlIG5ldyBkdXBsaWNhdGVkIGxpc3RlbmVyLlxuICovXG5mdW5jdGlvbiB3YXJuRHVwbGljYXRlKGxpc3RlbmVyLCBwYXNzaXZlLCBvbmNlLCBzaWduYWwpIHtcbiAgICBFdmVudExpc3RlbmVyV2FzRHVwbGljYXRlZC53YXJuKGlzQ2FwdHVyZShsaXN0ZW5lcikgPyBcImNhcHR1cmVcIiA6IFwiYnViYmxlXCIsIGxpc3RlbmVyLmNhbGxiYWNrKTtcbiAgICBpZiAoaXNQYXNzaXZlKGxpc3RlbmVyKSAhPT0gcGFzc2l2ZSkge1xuICAgICAgICBPcHRpb25XYXNJZ25vcmVkLndhcm4oXCJwYXNzaXZlXCIpO1xuICAgIH1cbiAgICBpZiAoaXNPbmNlKGxpc3RlbmVyKSAhPT0gb25jZSkge1xuICAgICAgICBPcHRpb25XYXNJZ25vcmVkLndhcm4oXCJvbmNlXCIpO1xuICAgIH1cbiAgICBpZiAobGlzdGVuZXIuc2lnbmFsICE9PSBzaWduYWwpIHtcbiAgICAgICAgT3B0aW9uV2FzSWdub3JlZC53YXJuKFwic2lnbmFsXCIpO1xuICAgIH1cbn1cbi8vIFNldCBlbnVtZXJhYmxlXG5jb25zdCBrZXlzJDEgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhFdmVudFRhcmdldC5wcm90b3R5cGUpO1xuZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzJDEubGVuZ3RoOyArK2kpIHtcbiAgICBpZiAoa2V5cyQxW2ldID09PSBcImNvbnN0cnVjdG9yXCIpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgfVxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFdmVudFRhcmdldC5wcm90b3R5cGUsIGtleXMkMVtpXSwgeyBlbnVtZXJhYmxlOiB0cnVlIH0pO1xufVxuLy8gRW5zdXJlIGBldmVudFRhcmdldCBpbnN0YW5jZW9mIHdpbmRvdy5FdmVudFRhcmdldGAgaXMgYHRydWVgLlxuaWYgKHR5cGVvZiBHbG9iYWwgIT09IFwidW5kZWZpbmVkXCIgJiZcbiAgICB0eXBlb2YgR2xvYmFsLkV2ZW50VGFyZ2V0ICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgT2JqZWN0LnNldFByb3RvdHlwZU9mKEV2ZW50VGFyZ2V0LnByb3RvdHlwZSwgR2xvYmFsLkV2ZW50VGFyZ2V0LnByb3RvdHlwZSk7XG59XG5cbi8qKlxuICogR2V0IHRoZSBjdXJyZW50IHZhbHVlIG9mIGEgZ2l2ZW4gZXZlbnQgYXR0cmlidXRlLlxuICogQHBhcmFtIHRhcmdldCBUaGUgYEV2ZW50VGFyZ2V0YCBvYmplY3QgdG8gZ2V0LlxuICogQHBhcmFtIHR5cGUgVGhlIGV2ZW50IHR5cGUuXG4gKi9cbmZ1bmN0aW9uIGdldEV2ZW50QXR0cmlidXRlVmFsdWUodGFyZ2V0LCB0eXBlKSB7XG4gICAgdmFyIF9hLCBfYjtcbiAgICBjb25zdCBsaXN0TWFwID0gJCQyKHRhcmdldCwgXCJ0YXJnZXRcIik7XG4gICAgcmV0dXJuIChfYiA9IChfYSA9IGxpc3RNYXBbdHlwZV0pID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5hdHRyQ2FsbGJhY2spICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IG51bGw7XG59XG4vKipcbiAqIFNldCBhbiBldmVudCBsaXN0ZW5lciB0byBhIGdpdmVuIGV2ZW50IGF0dHJpYnV0ZS5cbiAqIEBwYXJhbSB0YXJnZXQgVGhlIGBFdmVudFRhcmdldGAgb2JqZWN0IHRvIHNldC5cbiAqIEBwYXJhbSB0eXBlIFRoZSBldmVudCB0eXBlLlxuICogQHBhcmFtIGNhbGxiYWNrIFRoZSBldmVudCBsaXN0ZW5lci5cbiAqL1xuZnVuY3Rpb24gc2V0RXZlbnRBdHRyaWJ1dGVWYWx1ZSh0YXJnZXQsIHR5cGUsIGNhbGxiYWNrKSB7XG4gICAgaWYgKGNhbGxiYWNrICE9IG51bGwgJiYgdHlwZW9mIGNhbGxiYWNrICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgSW52YWxpZEF0dHJpYnV0ZUhhbmRsZXIud2FybihjYWxsYmFjayk7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgY2FsbGJhY2sgPT09IFwiZnVuY3Rpb25cIiB8fFxuICAgICAgICAodHlwZW9mIGNhbGxiYWNrID09PSBcIm9iamVjdFwiICYmIGNhbGxiYWNrICE9PSBudWxsKSkge1xuICAgICAgICB1cHNlcnRFdmVudEF0dHJpYnV0ZUxpc3RlbmVyKHRhcmdldCwgdHlwZSwgY2FsbGJhY2spO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmVtb3ZlRXZlbnRBdHRyaWJ1dGVMaXN0ZW5lcih0YXJnZXQsIHR5cGUpO1xuICAgIH1cbn1cbi8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBIZWxwZXJzXG4vLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLyoqXG4gKiBVcGRhdGUgb3IgaW5zZXJ0IHRoZSBnaXZlbiBldmVudCBhdHRyaWJ1dGUgaGFuZGxlci5cbiAqIEBwYXJhbSB0YXJnZXQgVGhlIGBFdmVudFRhcmdldGAgb2JqZWN0IHRvIHNldC5cbiAqIEBwYXJhbSB0eXBlIFRoZSBldmVudCB0eXBlLlxuICogQHBhcmFtIGNhbGxiYWNrIFRoZSBldmVudCBsaXN0ZW5lci5cbiAqL1xuZnVuY3Rpb24gdXBzZXJ0RXZlbnRBdHRyaWJ1dGVMaXN0ZW5lcih0YXJnZXQsIHR5cGUsIGNhbGxiYWNrKSB7XG4gICAgY29uc3QgbGlzdCA9IGVuc3VyZUxpc3RlbmVyTGlzdCgkJDIodGFyZ2V0LCBcInRhcmdldFwiKSwgU3RyaW5nKHR5cGUpKTtcbiAgICBsaXN0LmF0dHJDYWxsYmFjayA9IGNhbGxiYWNrO1xuICAgIGlmIChsaXN0LmF0dHJMaXN0ZW5lciA9PSBudWxsKSB7XG4gICAgICAgIGxpc3QuYXR0ckxpc3RlbmVyID0gYWRkTGlzdGVuZXIobGlzdCwgZGVmaW5lRXZlbnRBdHRyaWJ1dGVDYWxsYmFjayhsaXN0KSwgZmFsc2UsIGZhbHNlLCBmYWxzZSwgdW5kZWZpbmVkKTtcbiAgICB9XG59XG4vKipcbiAqIFJlbW92ZSB0aGUgZ2l2ZW4gZXZlbnQgYXR0cmlidXRlIGhhbmRsZXIuXG4gKiBAcGFyYW0gdGFyZ2V0IFRoZSBgRXZlbnRUYXJnZXRgIG9iamVjdCB0byByZW1vdmUuXG4gKiBAcGFyYW0gdHlwZSBUaGUgZXZlbnQgdHlwZS5cbiAqIEBwYXJhbSBjYWxsYmFjayBUaGUgZXZlbnQgbGlzdGVuZXIuXG4gKi9cbmZ1bmN0aW9uIHJlbW92ZUV2ZW50QXR0cmlidXRlTGlzdGVuZXIodGFyZ2V0LCB0eXBlKSB7XG4gICAgY29uc3QgbGlzdE1hcCA9ICQkMih0YXJnZXQsIFwidGFyZ2V0XCIpO1xuICAgIGNvbnN0IGxpc3QgPSBsaXN0TWFwW1N0cmluZyh0eXBlKV07XG4gICAgaWYgKGxpc3QgJiYgbGlzdC5hdHRyTGlzdGVuZXIpIHtcbiAgICAgICAgcmVtb3ZlTGlzdGVuZXIobGlzdCwgbGlzdC5hdHRyTGlzdGVuZXIuY2FsbGJhY2ssIGZhbHNlKTtcbiAgICAgICAgbGlzdC5hdHRyQ2FsbGJhY2sgPSBsaXN0LmF0dHJMaXN0ZW5lciA9IHVuZGVmaW5lZDtcbiAgICB9XG59XG4vKipcbiAqIERlZmluZSB0aGUgY2FsbGJhY2sgZnVuY3Rpb24gZm9yIHRoZSBnaXZlbiBsaXN0ZW5lciBsaXN0IG9iamVjdC5cbiAqIEl0IGNhbGxzIGBhdHRyQ2FsbGJhY2tgIHByb3BlcnR5IGlmIHRoZSBwcm9wZXJ0eSB2YWx1ZSBpcyBhIGZ1bmN0aW9uLlxuICogQHBhcmFtIGxpc3QgVGhlIGBMaXN0ZW5lckxpc3RgIG9iamVjdC5cbiAqL1xuZnVuY3Rpb24gZGVmaW5lRXZlbnRBdHRyaWJ1dGVDYWxsYmFjayhsaXN0KSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICBjb25zdCBjYWxsYmFjayA9IGxpc3QuYXR0ckNhbGxiYWNrO1xuICAgICAgICBpZiAodHlwZW9mIGNhbGxiYWNrID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwodGhpcywgZXZlbnQpO1xuICAgICAgICB9XG4gICAgfTtcbn1cblxuLyoqXG4gKiBEZWZpbmUgYW4gYEV2ZW50VGFyZ2V0YCBjbGFzcyB0aGF0IGhhcyBldmVudCBhdHRpYnV0ZXMuXG4gKiBAcGFyYW0gdHlwZXMgVGhlIHR5cGVzIHRvIGRlZmluZSBldmVudCBhdHRyaWJ1dGVzLlxuICogQGRlcHJlY2F0ZWQgVXNlIGBnZXRFdmVudEF0dHJpYnV0ZVZhbHVlYC9gc2V0RXZlbnRBdHRyaWJ1dGVWYWx1ZWAgcGFpciBvbiB5b3VyIGRlcml2ZWQgY2xhc3MgaW5zdGVhZCBiZWNhdXNlIG9mIHN0YXRpYyBhbmFseXNpcyBmcmllbmRseS5cbiAqL1xuZnVuY3Rpb24gZGVmaW5lQ3VzdG9tRXZlbnRUYXJnZXQoLi4udHlwZXMpIHtcbiAgICBjbGFzcyBDdXN0b21FdmVudFRhcmdldCBleHRlbmRzIEV2ZW50VGFyZ2V0IHtcbiAgICB9XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0eXBlcy5sZW5ndGg7ICsraSkge1xuICAgICAgICBkZWZpbmVFdmVudEF0dHJpYnV0ZShDdXN0b21FdmVudFRhcmdldC5wcm90b3R5cGUsIHR5cGVzW2ldKTtcbiAgICB9XG4gICAgcmV0dXJuIEN1c3RvbUV2ZW50VGFyZ2V0O1xufVxuLyoqXG4gKiBEZWZpbmUgYW4gZXZlbnQgYXR0cmlidXRlLlxuICogQHBhcmFtIHRhcmdldCBUaGUgYEV2ZW50VGFyZ2V0YCBvYmplY3QgdG8gZGVmaW5lIGFuIGV2ZW50IGF0dHJpYnV0ZS5cbiAqIEBwYXJhbSB0eXBlIFRoZSBldmVudCB0eXBlIHRvIGRlZmluZS5cbiAqIEBwYXJhbSBfZXZlbnRDbGFzcyBVbnVzZWQsIGJ1dCB0byBpbmZlciBgRXZlbnRgIGNsYXNzIHR5cGUuXG4gKiBAZGVwcmVjYXRlZCBVc2UgYGdldEV2ZW50QXR0cmlidXRlVmFsdWVgL2BzZXRFdmVudEF0dHJpYnV0ZVZhbHVlYCBwYWlyIG9uIHlvdXIgZGVyaXZlZCBjbGFzcyBpbnN0ZWFkIGJlY2F1c2Ugb2Ygc3RhdGljIGFuYWx5c2lzIGZyaWVuZGx5LlxuICovXG5mdW5jdGlvbiBkZWZpbmVFdmVudEF0dHJpYnV0ZSh0YXJnZXQsIHR5cGUsIF9ldmVudENsYXNzKSB7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwgYG9uJHt0eXBlfWAsIHtcbiAgICAgICAgZ2V0KCkge1xuICAgICAgICAgICAgcmV0dXJuIGdldEV2ZW50QXR0cmlidXRlVmFsdWUodGhpcywgdHlwZSk7XG4gICAgICAgIH0sXG4gICAgICAgIHNldCh2YWx1ZSkge1xuICAgICAgICAgICAgc2V0RXZlbnRBdHRyaWJ1dGVWYWx1ZSh0aGlzLCB0eXBlLCB2YWx1ZSk7XG4gICAgICAgIH0sXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgRXZlbnRUYXJnZXQ7XG5leHBvcnQgeyBFdmVudCwgRXZlbnRUYXJnZXQsIGRlZmluZUN1c3RvbUV2ZW50VGFyZ2V0LCBkZWZpbmVFdmVudEF0dHJpYnV0ZSwgZ2V0RXZlbnRBdHRyaWJ1dGVWYWx1ZSwgc2V0RXJyb3JIYW5kbGVyLCBzZXRFdmVudEF0dHJpYnV0ZVZhbHVlLCBzZXRXYXJuaW5nSGFuZGxlciB9O1xuLy8jIHNvdXJjZU1hcHBpbmdVUkw9aW5kZXgubWpzLm1hcFxuIiwiaW1wb3J0IHsgQ2FsZW5kYXJFdmVudCB9IGZyb20gXCIuL0NhbGVuZGFyRXZlbnRcIjtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRFdmVudHNGb3JEYXkoZXZlbnRzOiBDYWxlbmRhckV2ZW50W10sIGRhdGU6IERhdGUpOiBDYWxlbmRhckV2ZW50W10ge1xyXG4gIHJldHVybiBldmVudHMuZmlsdGVyKGV2ZW50ID0+IHtcclxuICAgIHJldHVybiBldmVudC5kYXRlLmdldEZ1bGxZZWFyKCkgPT09IGRhdGUuZ2V0RnVsbFllYXIoKSAmJlxyXG4gICAgICBldmVudC5kYXRlLmdldE1vbnRoKCkgPT09IGRhdGUuZ2V0TW9udGgoKSAmJlxyXG4gICAgICBldmVudC5kYXRlLmdldERhdGUoKSA9PT0gZGF0ZS5nZXREYXRlKCk7XHJcbiAgfSkuc29ydCgoYSwgYikgPT4ge1xyXG4gICAgLy8gSWYgb25lIGhhcyBubyB0aW1lIHByb3BlcnR5LCBpdCBzaG91bGQgYmUgZmlyc3QuXHJcbiAgICAvLyBJZiBib3RoIGhhdmUgbm8gdGltZSwgbm8gc29ydGluZyBpcyBuZWVkZWQuXHJcbiAgICBpZiAoIWEudGltZSAmJiAhIWIudGltZSkge1xyXG4gICAgICByZXR1cm4gLTE7XHJcbiAgICB9IGVsc2UgaWYgKCEhYS50aW1lICYmICFiLnRpbWUpIHtcclxuICAgICAgcmV0dXJuIDE7XHJcbiAgICB9IGVsc2UgaWYgKCFhLnRpbWUgJiYgIWIudGltZSkge1xyXG4gICAgICByZXR1cm4gMDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTb3J0IHRoZSBldmVudHMgYnkgdGltZS4gVGltZXMgYXJlIHN0cmluZ3MgaW4gMjRcclxuICAgIC8vIGZvcm1hdHMsIHNvIGp1c3QgcmVtb3ZlIHRoZSBsZWFkaW5nIDAsIGlmIGFueSwgYW5kXHJcbiAgICAvLyB0aGUgY29sb24sIGFuZCBjb21wYXJlIHRoZSBudW1iZXJzLlxyXG4gICAgY29uc3QgYVRpbWUgPSBwYXJzZUludChhLnRpbWUucmVwbGFjZSgvXjAvLCAnJykucmVwbGFjZSgnOicsICcnKSk7XHJcbiAgICBjb25zdCBiVGltZSA9IHBhcnNlSW50KGIudGltZS5yZXBsYWNlKC9eMC8sICcnKS5yZXBsYWNlKCc6JywgJycpKTtcclxuICAgIHJldHVybiBhVGltZSAtIGJUaW1lO1xyXG4gIH0pLnNvcnQoKGEsIGIpID0+IHtcclxuICAgIC8vIFNvcnQgdGhlIGV2ZW50cyB0aGF0IGFyZSBtdWx0aS1kYXlzIGZpcnN0LlxyXG4gICAgaWYgKCEhYS5tdWx0aURheXMgJiYgIWIubXVsdGlEYXlzKSB7XHJcbiAgICAgIHJldHVybiAtMTtcclxuICAgIH0gZWxzZSBpZiAoIWEubXVsdGlEYXlzICYmICEhYi5tdWx0aURheXMpIHtcclxuICAgICAgcmV0dXJuIDE7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuIiwiaW1wb3J0IHsgRXZlbnRUYXJnZXQsIEV2ZW50IH0gZnJvbSBcImV2ZW50LXRhcmdldC1zaGltXCI7XHJcbmltcG9ydCB7IENhbGVuZGFyRXZlbnQgfSBmcm9tIFwiLi9DYWxlbmRhckV2ZW50XCI7XHJcbmltcG9ydCB7IGdldEV2ZW50c0ZvckRheSB9IGZyb20gXCIuL3V0aWxzXCI7XHJcblxyXG5jb25zdCBEQVlTID0gWydTdW5kYXknLCAnTW9uZGF5JywgJ1R1ZXNkYXknLCAnV2VkbmVzZGF5JywgJ1RodXJzZGF5JywgJ0ZyaWRheScsICdTYXR1cmRheSddO1xyXG5cclxuZXhwb3J0IGNsYXNzIE1vbnRoR3JpZCBleHRlbmRzIEV2ZW50VGFyZ2V0IHtcclxuICBwcml2YXRlIHJvb3RFbDogSFRNTEVsZW1lbnQ7XHJcbiAgcHJpdmF0ZSBfZGF0ZTogRGF0ZSA9IG5ldyBEYXRlKCk7XHJcbiAgcHJpdmF0ZSBfZXZlbnRzOiBDYWxlbmRhckV2ZW50W107XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgZWw6IEhUTUxFbGVtZW50LCBkYXRlOiBEYXRlLCBldmVudHM6IENhbGVuZGFyRXZlbnRbXSkge1xyXG4gICAgc3VwZXIoKTtcclxuXHJcbiAgICB0aGlzLnJvb3RFbCA9IGVsO1xyXG4gICAgdGhpcy5fZGF0ZSA9IGRhdGU7XHJcbiAgICB0aGlzLl9ldmVudHMgPSBldmVudHM7XHJcblxyXG4gICAgdGhpcy5yZW5kZXIoKTtcclxuICB9XHJcbiAgXHJcbiAgcmVuZGVyKCkge1xyXG4gICAgdGhpcy5yb290RWwuaW5uZXJIVE1MID0gJyc7XHJcblxyXG4gICAgY29uc3QgbW9udGggPSB0aGlzLl9kYXRlLmdldE1vbnRoKCk7XHJcbiAgICBjb25zdCB5ZWFyID0gdGhpcy5fZGF0ZS5nZXRGdWxsWWVhcigpO1xyXG4gIFxyXG4gICAgY29uc3QgZmlyc3REYXkgPSBuZXcgRGF0ZSh5ZWFyLCBtb250aCwgMSk7XHJcbiAgICBjb25zdCBsYXN0RGF5ID0gbmV3IERhdGUoeWVhciwgbW9udGggKyAxLCAwKTtcclxuICBcclxuICAgIGNvbnN0IGZpcnN0V2Vla2RheSA9IGZpcnN0RGF5LmdldERheSgpO1xyXG4gICAgY29uc3QgbGFzdFdlZWtkYXkgPSBsYXN0RGF5LmdldERheSgpO1xyXG4gICAgY29uc3QgZGF5c0luTW9udGggPSBsYXN0RGF5LmdldERhdGUoKTtcclxuICAgIGNvbnN0IGRheXNJbkxhc3RNb250aCA9IG5ldyBEYXRlKHllYXIsIG1vbnRoLCAwKS5nZXREYXRlKCk7XHJcbiAgICBjb25zdCBkYXlzOiB7ZGF0ZTogRGF0ZSwgaHRtbDogc3RyaW5nfVtdID0gW107XHJcbiAgXHJcbiAgICBsZXQgaW5kZXhJbkdyaWQgPSAwO1xyXG5cclxuICAgIC8vIERheXMgZnJvbSBsYXN0IG1vbnRoXHJcbiAgICBmb3IgKGxldCBpID0gZGF5c0luTGFzdE1vbnRoIC0gZmlyc3RXZWVrZGF5ICsgMTsgaSA8PSBkYXlzSW5MYXN0TW9udGg7IGkrKykge1xyXG4gICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoeWVhciwgbW9udGggLSAxLCBpKTtcclxuICAgICAgZGF5cy5wdXNoKHtkYXRlLCBodG1sOiB0aGlzLnJlbmRlckRheShkYXRlLCBpLCBpbmRleEluR3JpZCwgJ3ByZXYtbW9udGgnKX0pO1xyXG4gICAgICBpbmRleEluR3JpZCsrO1xyXG4gICAgfVxyXG4gIFxyXG4gICAgLy8gRGF5cyBmcm9tIHRoaXMgbW9udGhcclxuICAgIGZvciAobGV0IGkgPSAxOyBpIDw9IGRheXNJbk1vbnRoOyBpKyspIHtcclxuICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKHllYXIsIG1vbnRoLCBpKTtcclxuICAgICAgZGF5cy5wdXNoKHtkYXRlLCBodG1sOiB0aGlzLnJlbmRlckRheShkYXRlLCBpLCBpbmRleEluR3JpZCl9KTtcclxuICAgICAgaW5kZXhJbkdyaWQrKztcclxuICAgIH1cclxuICBcclxuICAgIC8vIERheXMgZnJvbSBuZXh0IG1vbnRoXHJcbiAgICBmb3IgKGxldCBpID0gMTsgaSA8PSA3IC0gbGFzdFdlZWtkYXkgLSAxOyBpKyspIHtcclxuICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKHllYXIsIG1vbnRoICsgMSwgaSk7XHJcbiAgICAgIGRheXMucHVzaCh7ZGF0ZSwgaHRtbDogdGhpcy5yZW5kZXJEYXkoZGF0ZSwgaSwgaW5kZXhJbkdyaWQsICduZXh0LW1vbnRoJyl9KTtcclxuICAgICAgaW5kZXhJbkdyaWQrKztcclxuICAgIH1cclxuXHJcbiAgICBmb3IgKGNvbnN0IHtkYXRlLCBodG1sfSBvZiBkYXlzKSB7XHJcbiAgICAgIHRoaXMucm9vdEVsLmluc2VydEFkamFjZW50SFRNTCgnYmVmb3JlZW5kJywgaHRtbCk7XHJcbiAgICAgIGNvbnN0IGRheUVsID0gdGhpcy5yb290RWwubGFzdEVsZW1lbnRDaGlsZCBhcyBIVE1MRWxlbWVudDtcclxuXHJcbiAgICAgIGRheUVsLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKGU6IE1vdXNlRXZlbnQpID0+IHtcclxuICAgICAgICAvLyBAdHMtaWdub3JlXHJcbiAgICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudCgnZGF5LWNsaWNrZWQnLCB7ZGV0YWlsOiBkYXRlfSkpO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnVwZGF0ZU5vd01hcmtlcigpO1xyXG4gIH1cclxuXHJcbiAgcmVuZGVyRGF5KGRhdGU6IERhdGUsIGRheU51bWJlcjogbnVtYmVyLCBpbmRleEluR3JpZDogbnVtYmVyLCBjbGFzc05hbWU6IHN0cmluZyA9ICcnKTogc3RyaW5nIHtcclxuICAgIGNvbnN0IGV2ZW50cyA9IGdldEV2ZW50c0ZvckRheSh0aGlzLl9ldmVudHMsIGRhdGUpO1xyXG4gICAgY29uc3QgaXNUb2RheSA9IGRhdGUudG9EYXRlU3RyaW5nKCkgPT09IG5ldyBEYXRlKCkudG9EYXRlU3RyaW5nKCk7XHJcblxyXG4gICAgcmV0dXJuIGBcclxuICAgICAgPGRpdiBjbGFzcz1cImRheSAke2lzVG9kYXkgPyAndG9kYXknIDogJyd9ICR7Y2xhc3NOYW1lfVwiPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJoZWFkZXJcIj5cclxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZGF5LW5hbWVcIj4ke0RBWVNbZGF0ZS5nZXREYXkoKV19PC9zcGFuPlxyXG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJkYXktbnVtYmVyXCI+JHtkYXlOdW1iZXJ9PC9zcGFuPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDx1bCBjbGFzcz1cImV2ZW50c1wiPlxyXG4gICAgICAgICAgJHtldmVudHMubWFwKGV2ZW50ID0+IGV2ZW50LmFzT25lTGluZUhUTUwoaW5kZXhJbkdyaWQpKS5qb2luKCcnKX1cclxuICAgICAgICA8L3VsPlxyXG4gICAgICA8L2Rpdj5cclxuICAgIGA7XHJcbiAgfVxyXG5cclxuICB1cGRhdGVOb3dNYXJrZXIoKSB7XHJcbiAgICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpO1xyXG4gICAgY29uc3QgdGltZSA9IG5vdy5nZXRIb3VycygpICogMTAwICsgbm93LmdldE1pbnV0ZXMoKTtcclxuICAgIGNvbnN0IHJhdGlvID0gdGltZSAqIDEwMCAvIDI0MDA7XHJcblxyXG4gICAgLy8gRm9yY2luZyBhIHN5bmMgcmVmbG93IGhlcmUgYnkgcXVlcnlpbmcgdGhlIG9mZnNldEhlaWdodCBvZiB0aGUgZGF5IGNlbGwuXHJcbiAgICAvLyBDb3VsZCBqdXN0IHNldCB0aGUgJSB2YWx1ZSBkaXJlY3RseSBpbnN0ZWFkLlxyXG4gICAgY29uc3QgZGF5RWwgPSB0aGlzLnJvb3RFbC5xdWVyeVNlbGVjdG9yKCcuZGF5LnRvZGF5JykgYXMgSFRNTEVsZW1lbnQ7XHJcbiAgICBpZiAoZGF5RWwpIHtcclxuICAgICAgY29uc3QgcHhIZWlnaHQgPSBkYXlFbC5vZmZzZXRIZWlnaHQ7XHJcbiAgICAgIGNvbnN0IG1hcmtlckhlaWdodCA9IHB4SGVpZ2h0ICogcmF0aW8gLyAxMDA7XHJcblxyXG4gICAgICB0aGlzLnJvb3RFbC5zdHlsZS5zZXRQcm9wZXJ0eSgnLS1ub3ctbWFya2VyJywgYCR7bWFya2VySGVpZ2h0fXB4YCk7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnVwZGF0ZU5vd01hcmtlcigpLCAxMDAwKTtcclxuICB9XHJcblxyXG4gIHNldCBkYXRlKGRhdGU6IERhdGUpIHtcclxuICAgIHRoaXMuX2RhdGUgPSBkYXRlO1xyXG4gICAgdGhpcy5yZW5kZXIoKTtcclxuICB9XHJcblxyXG4gIHNldCBldmVudHMoZXZlbnRzOiBDYWxlbmRhckV2ZW50W10pIHtcclxuICAgIHRoaXMuX2V2ZW50cyA9IGV2ZW50cztcclxuICAgIHRoaXMucmVuZGVyKCk7XHJcbiAgfVxyXG59XHJcbiIsImltcG9ydCB7IEV2ZW50VGFyZ2V0LCBFdmVudCB9IGZyb20gXCJldmVudC10YXJnZXQtc2hpbVwiO1xyXG5cclxuY29uc3QgTU9OVEhTID0gW1xyXG4gICdKYW51YXJ5JywgJ0ZlYnJ1YXJ5JywgJ01hcmNoJywgJ0FwcmlsJywgJ01heScsICdKdW5lJywgJ0p1bHknLCAnQXVndXN0JyxcclxuICAnU2VwdGVtYmVyJywgJ09jdG9iZXInLCAnTm92ZW1iZXInLCdEZWNlbWJlcidcclxuXTtcclxuXHJcbmV4cG9ydCBjbGFzcyBUb29sYmFyIGV4dGVuZHMgRXZlbnRUYXJnZXQge1xyXG4gIHByaXZhdGUgcm9vdEVsOiBIVE1MRWxlbWVudDtcclxuICBwcml2YXRlIF9kYXRlOiBEYXRlO1xyXG4gIHByaXZhdGUgc2VsZWN0ZWRNb2RlOiBzdHJpbmcgPSBcIm1vbnRoXCI7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgZWw6IEhUTUxFbGVtZW50LCBkYXRlOiBEYXRlLCBtb2RlOiBzdHJpbmcpIHtcclxuICAgIHN1cGVyKCk7XHJcblxyXG4gICAgdGhpcy5yb290RWwgPSBlbDtcclxuICAgIHRoaXMuX2RhdGUgPSBkYXRlO1xyXG4gICAgdGhpcy5zZWxlY3RlZE1vZGUgPSBtb2RlO1xyXG5cclxuICAgIHRoaXMucmVuZGVyKCk7XHJcbiAgfVxyXG5cclxuICBmb3JtYXRNb250aFllYXIoKSB7XHJcbiAgICBjb25zdCBtb250aCA9IHRoaXMuX2RhdGUuZ2V0TW9udGgoKTtcclxuICAgIGNvbnN0IHllYXIgPSB0aGlzLl9kYXRlLmdldEZ1bGxZZWFyKCk7XHJcbiAgICByZXR1cm4gYCR7TU9OVEhTW21vbnRoXX0gJHt5ZWFyfWA7XHJcbiAgfVxyXG4gIFxyXG4gIHJlbmRlcigpIHtcclxuICAgIHRoaXMucm9vdEVsLmlubmVySFRNTCA9IGBcclxuICAgICAgPGJ1dHRvbiBpZD1cInByZXYtbW9udGhcIj5QcmV2PC9idXR0b24+XHJcbiAgICAgIDxidXR0b24gaWQ9XCJ0b2RheVwiIGNsYXNzPVwicHJpbWFyeVwiPlRvZGF5PC9idXR0b24+XHJcbiAgICAgIDxidXR0b24gaWQ9XCJuZXh0LW1vbnRoXCI+TmV4dDwvYnV0dG9uPlxyXG4gICAgICA8c3BhbiBpZD1cIm1vbnRoLXllYXJcIj4ke3RoaXMuZm9ybWF0TW9udGhZZWFyKCl9PC9zcGFuPlxyXG4gICAgICA8aW5wdXQgdHlwZT1cInJhZGlvXCIgbmFtZT1cInZpZXdcIiBpZD1cIm1vbnRoLXZpZXdcIiAke3RoaXMuc2VsZWN0ZWRNb2RlID09PSBcIm1vbnRoXCIgPyBcImNoZWNrZWRcIiA6IFwiXCJ9PlxyXG4gICAgICA8bGFiZWwgZm9yPVwibW9udGgtdmlld1wiPk1vbnRoPC9sYWJlbD5cclxuICAgICAgPGlucHV0IHR5cGU9XCJyYWRpb1wiIG5hbWU9XCJ2aWV3XCIgaWQ9XCJ3ZWVrLXZpZXdcIiAke3RoaXMuc2VsZWN0ZWRNb2RlID09PSBcIndlZWtcIiA/IFwiY2hlY2tlZFwiIDogXCJcIn0+XHJcbiAgICAgIDxsYWJlbCBmb3I9XCJ3ZWVrLXZpZXdcIj5XZWVrPC9sYWJlbD4gICAgICBcclxuICAgIGA7XHJcblxyXG4gICAgdGhpcy5yb290RWwucXVlcnlTZWxlY3RvcignI3ByZXYtbW9udGgnKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsICgpID0+IHtcclxuICAgICAgY29uc29sZS5sb2coYFByZXYgJHt0aGlzLnNlbGVjdGVkTW9kZX0gY2xpY2tlZGApO1xyXG4gICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KCdwcmV2JykpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgdGhpcy5yb290RWwucXVlcnlTZWxlY3RvcignI25leHQtbW9udGgnKS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsICgpID0+IHtcclxuICAgICAgY29uc29sZS5sb2coYE5leHQgJHt0aGlzLnNlbGVjdGVkTW9kZX0gY2xpY2tlZGApO1xyXG4gICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KCduZXh0JykpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgdGhpcy5yb290RWwucXVlcnlTZWxlY3RvcignI3RvZGF5JykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoKSA9PiB7XHJcbiAgICAgIGNvbnNvbGUubG9nKFwiVG9kYXkgY2xpY2tlZFwiKTtcclxuICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgndG9kYXknKSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICB0aGlzLnJvb3RFbC5xdWVyeVNlbGVjdG9yKCcjbW9udGgtdmlldycpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4ge1xyXG4gICAgICBjb25zb2xlLmxvZyhcIk1vbnRoIHZpZXcgY2xpY2tlZFwiKTtcclxuICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgnbW9udGgtdmlldycpKTtcclxuICAgICAgdGhpcy5zZWxlY3RlZE1vZGUgPSBcIm1vbnRoXCI7XHJcbiAgICB9KTtcclxuICAgIFxyXG4gICAgdGhpcy5yb290RWwucXVlcnlTZWxlY3RvcignI3dlZWstdmlldycpLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4ge1xyXG4gICAgICBjb25zb2xlLmxvZyhcIldlZWsgdmlldyBjbGlja2VkXCIpO1xyXG4gICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KCd3ZWVrLXZpZXcnKSk7XHJcbiAgICAgIHRoaXMuc2VsZWN0ZWRNb2RlID0gXCJ3ZWVrXCI7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHNldCBkYXRlKGRhdGU6IERhdGUpIHtcclxuICAgIHRoaXMuX2RhdGUgPSBkYXRlO1xyXG4gICAgdGhpcy5yZW5kZXIoKTtcclxuICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgQ2FsZW5kYXJFdmVudCB9IGZyb20gXCIuL0NhbGVuZGFyRXZlbnRcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBTaWRlYmFyIHtcclxuICBwcml2YXRlIHJvb3RFbDogSFRNTEVsZW1lbnQ7XHJcbiAgcHJpdmF0ZSBfZXZlbnRzOiBDYWxlbmRhckV2ZW50W10gPSBbXTtcclxuICBwcml2YXRlIF9kYXRlOiBEYXRlID0gbmV3IERhdGUoKTtcclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBlbDogSFRNTEVsZW1lbnQsIGRhdGU6IERhdGUsIGV2ZW50czogQ2FsZW5kYXJFdmVudFtdKSB7XHJcbiAgICB0aGlzLnJvb3RFbCA9IGVsO1xyXG4gICAgdGhpcy5fZGF0ZSA9IGRhdGU7XHJcbiAgICB0aGlzLl9ldmVudHMgPSBldmVudHM7XHJcblxyXG4gICAgdGhpcy5yZW5kZXIoKTtcclxuICB9XHJcbiAgXHJcbiAgcmVuZGVyKCkge1xyXG4gICAgdGhpcy5yb290RWwuaW5uZXJIVE1MID0gYFxyXG4gICAgICA8aDI+Q2xpY2sgYSBkYXkgdG8gdmlldyBldmVudHM8L2gyPlxyXG4gICAgYDtcclxuXHJcbiAgICBpZiAoIXRoaXMuX2V2ZW50cy5sZW5ndGgpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMucm9vdEVsLmlubmVySFRNTCA9ICcnO1xyXG5cclxuICAgIGNvbnN0IHVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndWwnKTtcclxuICAgIHVsLmNsYXNzTmFtZSA9ICdldmVudHMnO1xyXG4gICAgdGhpcy5yb290RWwuYXBwZW5kQ2hpbGQodWwpO1xyXG5cclxuICAgIGZvciAoY29uc3QgZXZlbnQgb2YgdGhpcy5fZXZlbnRzKSB7XHJcbiAgICAgIHVsLmlubmVySFRNTCArPSBldmVudC5hc0Z1bGxIVE1MKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBzZXQgZXZlbnRzKGV2ZW50czogQ2FsZW5kYXJFdmVudFtdKSB7XHJcbiAgICB0aGlzLl9ldmVudHMgPSBldmVudHM7XHJcbiAgICB0aGlzLnJlbmRlcigpO1xyXG4gIH1cclxufVxyXG5gYCIsImltcG9ydCB7IEV2ZW50VGFyZ2V0LCBFdmVudCB9IGZyb20gXCJldmVudC10YXJnZXQtc2hpbVwiO1xyXG5pbXBvcnQgeyBDYWxlbmRhckV2ZW50IH0gZnJvbSBcIi4vQ2FsZW5kYXJFdmVudFwiO1xyXG5pbXBvcnQgeyBnZXRFdmVudHNGb3JEYXkgfSBmcm9tIFwiLi91dGlsc1wiO1xyXG5cclxuY29uc3QgREFZUyA9IFsnU3VuZGF5JywgJ01vbmRheScsICdUdWVzZGF5JywgJ1dlZG5lc2RheScsICdUaHVyc2RheScsICdGcmlkYXknLCAnU2F0dXJkYXknXTtcclxuXHJcbmV4cG9ydCBjbGFzcyBXZWVrR3JpZCBleHRlbmRzIEV2ZW50VGFyZ2V0IHtcclxuICBwcml2YXRlIHJvb3RFbDogSFRNTEVsZW1lbnQ7XHJcbiAgcHJpdmF0ZSBfZGF0ZTogRGF0ZSA9IG5ldyBEYXRlKCk7XHJcbiAgcHJpdmF0ZSBfZXZlbnRzOiBDYWxlbmRhckV2ZW50W107XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgZWw6IEhUTUxFbGVtZW50LCBkYXRlOiBEYXRlLCBldmVudHM6IENhbGVuZGFyRXZlbnRbXSkge1xyXG4gICAgc3VwZXIoKTtcclxuXHJcbiAgICB0aGlzLnJvb3RFbCA9IGVsO1xyXG4gICAgdGhpcy5fZGF0ZSA9IGRhdGU7XHJcbiAgICB0aGlzLl9ldmVudHMgPSBldmVudHM7XHJcblxyXG4gICAgdGhpcy5yZW5kZXIoKTtcclxuICB9XHJcbiAgXHJcbiAgcmVuZGVyKCkge1xyXG4gICAgdGhpcy5yb290RWwuaW5uZXJIVE1MID0gJyc7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgZGF0ZXMgdGhhdCBtYWtlIHRoZSB3ZWVrIGFyb3VuZCB0aGlzLl9kYXRlLlxyXG4gICAgY29uc3QgbW9udGggPSB0aGlzLl9kYXRlLmdldE1vbnRoKCk7XHJcbiAgICBjb25zdCB5ZWFyID0gdGhpcy5fZGF0ZS5nZXRGdWxsWWVhcigpO1xyXG4gICAgY29uc3QgZGF0ZSA9IHRoaXMuX2RhdGUuZ2V0RGF0ZSgpO1xyXG4gICAgY29uc3QgZGF5ID0gdGhpcy5fZGF0ZS5nZXREYXkoKTtcclxuXHJcbiAgICBjb25zdCBmaXJzdERheSA9IG5ldyBEYXRlKHllYXIsIG1vbnRoLCBkYXRlIC0gZGF5KTtcclxuXHJcbiAgICAvLyBJdGVyYXRlIG92ZXIgdGhlIGRhdGVzIGFuZCByZW5kZXIgdGhlIGRheXMuXHJcbiAgICBjb25zdCBkYXlzOiB7ZGF0ZTogRGF0ZSwgaHRtbDogc3RyaW5nfVtdID0gW107XHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IDc7IGkrKykge1xyXG4gICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoeWVhciwgbW9udGgsIGZpcnN0RGF5LmdldERhdGUoKSArIGkpO1xyXG4gICAgICB0aGlzLnJvb3RFbC5pbnNlcnRBZGphY2VudEhUTUwoJ2JlZm9yZWVuZCcsIHRoaXMucmVuZGVyRGF5KGRhdGUsIGRhdGUuZ2V0RGF0ZSgpKSk7XHJcblxyXG4gICAgICBjb25zdCBkYXlFbCA9IHRoaXMucm9vdEVsLmxhc3RFbGVtZW50Q2hpbGQgYXMgSFRNTEVsZW1lbnQ7XHJcbiAgICAgIGRheUVsLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKGU6IE1vdXNlRXZlbnQpID0+IHtcclxuICAgICAgICAvLyBAdHMtaWdub3JlXHJcbiAgICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudCgnZGF5LWNsaWNrZWQnLCB7ZGV0YWlsOiBkYXRlfSkpO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnVwZGF0ZU5vd01hcmtlcigpO1xyXG4gIH1cclxuXHJcbiAgcmVuZGVyRGF5KGRhdGU6IERhdGUsIGRheU51bWJlcjogbnVtYmVyLCBjbGFzc05hbWU6IHN0cmluZyA9ICcnKTogc3RyaW5nIHtcclxuICAgIGNvbnN0IGV2ZW50cyA9IGdldEV2ZW50c0ZvckRheSh0aGlzLl9ldmVudHMsIGRhdGUpO1xyXG4gICAgY29uc3QgaXNUb2RheSA9IGRhdGUudG9EYXRlU3RyaW5nKCkgPT09IG5ldyBEYXRlKCkudG9EYXRlU3RyaW5nKCk7XHJcblxyXG4gICAgcmV0dXJuIGBcclxuICAgICAgPGRpdiBjbGFzcz1cImRheSAke2lzVG9kYXkgPyAndG9kYXknIDogJyd9ICR7Y2xhc3NOYW1lfVwiPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJoZWFkZXJcIj5cclxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZGF5LW5hbWVcIj4ke0RBWVNbZGF0ZS5nZXREYXkoKV19PC9zcGFuPlxyXG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJkYXktbnVtYmVyXCI+JHtkYXlOdW1iZXJ9PC9zcGFuPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDx1bCBjbGFzcz1cImV2ZW50c1wiPlxyXG4gICAgICAgICAgJHtldmVudHMubWFwKGV2ZW50ID0+IGV2ZW50LmFzTWVkaXVtTGVuZ3RoSFRNTCgpKS5qb2luKCcnKX1cclxuICAgICAgICA8L3VsPlxyXG4gICAgICA8L2Rpdj5cclxuICAgIGA7XHJcbiAgfVxyXG5cclxuICB1cGRhdGVOb3dNYXJrZXIoKSB7XHJcbiAgICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpO1xyXG4gICAgY29uc3QgdGltZSA9IG5vdy5nZXRIb3VycygpICogMTAwICsgbm93LmdldE1pbnV0ZXMoKTtcclxuICAgIGNvbnN0IHJhdGlvID0gdGltZSAqIDEwMCAvIDI0MDA7XHJcblxyXG4gICAgLy8gRm9yY2luZyBhIHN5bmMgcmVmbG93IGhlcmUgYnkgcXVlcnlpbmcgdGhlIG9mZnNldEhlaWdodCBvZiB0aGUgZGF5IGNlbGwuXHJcbiAgICAvLyBDb3VsZCBqdXN0IHNldCB0aGUgJSB2YWx1ZSBkaXJlY3RseSBpbnN0ZWFkLlxyXG4gICAgY29uc3QgZGF5RWwgPSB0aGlzLnJvb3RFbC5xdWVyeVNlbGVjdG9yKCcuZGF5LnRvZGF5JykgYXMgSFRNTEVsZW1lbnQ7XHJcbiAgICBpZiAoZGF5RWwpIHtcclxuICAgICAgY29uc3QgcHhIZWlnaHQgPSBkYXlFbC5vZmZzZXRIZWlnaHQ7XHJcbiAgICAgIGNvbnN0IG1hcmtlckhlaWdodCA9IHB4SGVpZ2h0ICogcmF0aW8gLyAxMDA7XHJcblxyXG4gICAgICB0aGlzLnJvb3RFbC5zdHlsZS5zZXRQcm9wZXJ0eSgnLS1ub3ctbWFya2VyJywgYCR7bWFya2VySGVpZ2h0fXB4YCk7XHJcbiAgICB9XHJcblxyXG4gICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnVwZGF0ZU5vd01hcmtlcigpLCAxMDAwKTtcclxuICB9XHJcblxyXG4gIHNldCBkYXRlKGRhdGU6IERhdGUpIHtcclxuICAgIHRoaXMuX2RhdGUgPSBkYXRlO1xyXG4gICAgdGhpcy5yZW5kZXIoKTtcclxuICB9XHJcblxyXG4gIHNldCBldmVudHMoZXZlbnRzOiBDYWxlbmRhckV2ZW50W10pIHtcclxuICAgIHRoaXMuX2V2ZW50cyA9IGV2ZW50cztcclxuICAgIHRoaXMucmVuZGVyKCk7XHJcbiAgfVxyXG59XHJcbiIsImltcG9ydCB7IEV2ZW50VGFyZ2V0LCBFdmVudCB9IGZyb20gXCJldmVudC10YXJnZXQtc2hpbVwiO1xyXG5pbXBvcnQgeyBDYWxlbmRhckV2ZW50IH0gZnJvbSBcIi4vQ2FsZW5kYXJFdmVudFwiO1xyXG5pbXBvcnQgeyBNb250aEdyaWQgfSBmcm9tIFwiLi9Nb250aEdyaWRcIjtcclxuaW1wb3J0IHsgVG9vbGJhciB9IGZyb20gXCIuL1Rvb2xiYXJcIjtcclxuaW1wb3J0IHsgU2lkZWJhciB9IGZyb20gXCIuL1NpZGViYXJcIjtcclxuaW1wb3J0IHsgZ2V0RXZlbnRzRm9yRGF5IH0gZnJvbSBcIi4vdXRpbHNcIjtcclxuaW1wb3J0IHsgV2Vla0dyaWQgfSBmcm9tIFwiLi9XZWVrR3JpZFwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIEFwcFVJIGV4dGVuZHMgRXZlbnRUYXJnZXQge1xyXG4gIHByaXZhdGUgcm9vdEVsOiBIVE1MRWxlbWVudDtcclxuXHJcbiAgcHJpdmF0ZSBtb250aEdyaWRFbDogSFRNTEVsZW1lbnQ7XHJcbiAgcHVibGljIG1vbnRoR3JpZDogTW9udGhHcmlkO1xyXG5cclxuICBwcml2YXRlIHdlZWtHcmlkRWw6IEhUTUxFbGVtZW50O1xyXG4gIHB1YmxpYyB3ZWVrR3JpZDogV2Vla0dyaWQ7XHJcblxyXG4gIHByaXZhdGUgdG9vbGJhckVsOiBIVE1MRWxlbWVudDtcclxuICBwcml2YXRlIHRvb2xiYXI6IFRvb2xiYXI7XHJcblxyXG4gIHByaXZhdGUgc2lkZWJhckVsOiBIVE1MRWxlbWVudDtcclxuICBwcml2YXRlIHNpZGViYXI6IFNpZGViYXI7XHJcblxyXG4gIHByaXZhdGUgX2RhdGU6IERhdGU7XHJcbiAgcHJpdmF0ZSBfZXZlbnRzOiBDYWxlbmRhckV2ZW50W107XHJcblxyXG4gIHByaXZhdGUgbW9kZTogc3RyaW5nID0gXCJtb250aFwiO1xyXG5cclxuICBjb25zdHJ1Y3RvcihlbDogSFRNTEVsZW1lbnQsIGRhdGU6IERhdGUsIG1vZGU6IHN0cmluZywgZXZlbnRzOiBDYWxlbmRhckV2ZW50W10pIHtcclxuICAgIHN1cGVyKCk7XHJcblxyXG4gICAgdGhpcy5yb290RWwgPSBlbDtcclxuICAgIHRoaXMuX2RhdGUgPSBkYXRlO1xyXG4gICAgdGhpcy5fZXZlbnRzID0gZXZlbnRzO1xyXG4gICAgdGhpcy5tb2RlID0gbW9kZTtcclxuXHJcbiAgICB0aGlzLnJlbmRlcigpO1xyXG4gIH1cclxuXHJcbiAgcmVuZGVyKCkge1xyXG4gICAgdGhpcy5yb290RWwuaW5uZXJIVE1MID0gJyc7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGFuIGVsZW1lbnQgZm9yIHRoZSB0b29sYmFyLlxyXG4gICAgdGhpcy50b29sYmFyRWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuICAgIHRoaXMudG9vbGJhckVsLmlkID0gJ3Rvb2xiYXInO1xyXG4gICAgdGhpcy5yb290RWwuYXBwZW5kQ2hpbGQodGhpcy50b29sYmFyRWwpO1xyXG5cclxuICAgIC8vIEluaXQgdGhlIHRvb2xiYXIgY29tcG9uZW50IGluIGl0LlxyXG4gICAgdGhpcy50b29sYmFyID0gbmV3IFRvb2xiYXIodGhpcy50b29sYmFyRWwsIHRoaXMuX2RhdGUsIHRoaXMubW9kZSk7XHJcblxyXG4gICAgdGhpcy50b29sYmFyLmFkZEV2ZW50TGlzdGVuZXIoJ3ByZXYnLCAoKSA9PiB7XHJcbiAgICAgIGNvbnN0IG5ld0RhdGUgPSB0aGlzLm1vZGUgPT09IFwibW9udGhcIlxyXG4gICAgICAgID8gbmV3IERhdGUodGhpcy5fZGF0ZS5nZXRGdWxsWWVhcigpLCB0aGlzLl9kYXRlLmdldE1vbnRoKCkgLSAxLCAxKVxyXG4gICAgICAgIDogbmV3IERhdGUodGhpcy5fZGF0ZS5nZXRGdWxsWWVhcigpLCB0aGlzLl9kYXRlLmdldE1vbnRoKCksIHRoaXMuX2RhdGUuZ2V0RGF0ZSgpIC0gNyk7XHJcbiAgICAgIHRoaXMuZGF0ZSA9IG5ld0RhdGU7XHJcblxyXG4gICAgICAvLyBAdHMtaWdub3JlXHJcbiAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoJ2RhdGUtY2hhbmdlZCcsIHtkZXRhaWw6IHRoaXMuX2RhdGV9KSk7XHJcbiAgICB9KTtcclxuICAgIFxyXG4gICAgdGhpcy50b29sYmFyLmFkZEV2ZW50TGlzdGVuZXIoJ25leHQnLCAoKSA9PiB7XHJcbiAgICAgIGNvbnN0IG5ld0RhdGUgPSB0aGlzLm1vZGUgPT09IFwibW9udGhcIlxyXG4gICAgICAgID8gbmV3IERhdGUodGhpcy5fZGF0ZS5nZXRGdWxsWWVhcigpLCB0aGlzLl9kYXRlLmdldE1vbnRoKCkgKyAxLCAxKVxyXG4gICAgICAgIDogbmV3IERhdGUodGhpcy5fZGF0ZS5nZXRGdWxsWWVhcigpLCB0aGlzLl9kYXRlLmdldE1vbnRoKCksIHRoaXMuX2RhdGUuZ2V0RGF0ZSgpICsgNyk7XHJcbiAgICAgIHRoaXMuZGF0ZSA9IG5ld0RhdGU7XHJcblxyXG4gICAgICAvLyBAdHMtaWdub3JlXHJcbiAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChuZXcgQ3VzdG9tRXZlbnQoJ2RhdGUtY2hhbmdlZCcsIHtkZXRhaWw6IHRoaXMuX2RhdGV9KSk7XHJcbiAgICB9KTtcclxuICAgIFxyXG4gICAgdGhpcy50b29sYmFyLmFkZEV2ZW50TGlzdGVuZXIoJ3RvZGF5JywgKCkgPT4ge1xyXG4gICAgICB0aGlzLmRhdGUgPSBuZXcgRGF0ZSgpO1xyXG4gICAgICBcclxuICAgICAgLy8gQHRzLWlnbm9yZVxyXG4gICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KCdkYXRlLWNoYW5nZWQnLCB7ZGV0YWlsOiB0aGlzLl9kYXRlfSkpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgdGhpcy50b29sYmFyLmFkZEV2ZW50TGlzdGVuZXIoJ21vbnRoLXZpZXcnLCAoKSA9PiB7XHJcbiAgICAgIHRoaXMubW9kZSA9IFwibW9udGhcIjtcclxuICAgICAgdGhpcy5tb250aEdyaWRFbC5zdHlsZS5kaXNwbGF5ID0gJ2dyaWQnO1xyXG4gICAgICB0aGlzLndlZWtHcmlkRWwuc3R5bGUuZGlzcGxheSA9ICdub25lJztcclxuXHJcbiAgICAgIC8vIEB0cy1pZ25vcmVcclxuICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudCgnbW9kZS1jaGFuZ2VkJywge2RldGFpbDogdGhpcy5tb2RlfSkpO1xyXG4gICAgfSk7XHJcbiAgICBcclxuICAgIHRoaXMudG9vbGJhci5hZGRFdmVudExpc3RlbmVyKCd3ZWVrLXZpZXcnLCAoKSA9PiB7XHJcbiAgICAgIHRoaXMubW9kZSA9IFwid2Vla1wiO1xyXG4gICAgICB0aGlzLm1vbnRoR3JpZEVsLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICAgIHRoaXMud2Vla0dyaWRFbC5zdHlsZS5kaXNwbGF5ID0gJ2dyaWQnO1xyXG5cclxuICAgICAgLy8gQHRzLWlnbm9yZVxyXG4gICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IEN1c3RvbUV2ZW50KCdtb2RlLWNoYW5nZWQnLCB7ZGV0YWlsOiB0aGlzLm1vZGV9KSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYW4gZWxlbWVudCBmb3IgdGhlIG1vbnRoIGdyaWQuXHJcbiAgICB0aGlzLm1vbnRoR3JpZEVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XHJcbiAgICB0aGlzLm1vbnRoR3JpZEVsLmlkID0gJ21vbnRoLWdyaWQnO1xyXG4gICAgdGhpcy5yb290RWwuYXBwZW5kQ2hpbGQodGhpcy5tb250aEdyaWRFbCk7XHJcblxyXG4gICAgLy8gSW5pdCB0aGUgbW9udGggZ3JpZCBjb21wb25lbnQgaW4gaXQuXHJcbiAgICB0aGlzLm1vbnRoR3JpZCA9IG5ldyBNb250aEdyaWQodGhpcy5tb250aEdyaWRFbCwgdGhpcy5fZGF0ZSwgdGhpcy5fZXZlbnRzKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYW4gZWxlbWVudCBmb3IgdGhlIHdlZWsgZ3JpZC5cclxuICAgIHRoaXMud2Vla0dyaWRFbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgdGhpcy53ZWVrR3JpZEVsLmlkID0gJ3dlZWstZ3JpZCc7XHJcbiAgICB0aGlzLnJvb3RFbC5hcHBlbmRDaGlsZCh0aGlzLndlZWtHcmlkRWwpO1xyXG5cclxuICAgIC8vIEluaXQgdGhlIHdlZWsgZ3JpZCBjb21wb25lbnQgaW4gaXQuXHJcbiAgICB0aGlzLndlZWtHcmlkID0gbmV3IFdlZWtHcmlkKHRoaXMud2Vla0dyaWRFbCwgdGhpcy5fZGF0ZSwgdGhpcy5fZXZlbnRzKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYW4gZWxlbWVudCBmb3IgdGhlIHNpZGViYXIuXHJcbiAgICB0aGlzLnNpZGViYXJFbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgdGhpcy5zaWRlYmFyRWwuaWQgPSAnc2lkZWJhcic7XHJcbiAgICB0aGlzLnJvb3RFbC5hcHBlbmRDaGlsZCh0aGlzLnNpZGViYXJFbCk7XHJcblxyXG4gICAgLy8gSW5pdCB0aGUgc2lkZWJhciBjb21wb25lbnQgaW4gaXQuXHJcbiAgICB0aGlzLnNpZGViYXIgPSBuZXcgU2lkZWJhcih0aGlzLnNpZGViYXJFbCwgdGhpcy5fZGF0ZSwgdGhpcy5fZXZlbnRzKTtcclxuXHJcbiAgICAvLyBMaXN0ZW4gZm9yIGRheS1jbGlja2VkIGV2ZW50cyBmcm9tIHRoZSBtb250aCBhbmQgd2VlayBncmlkcyB0byBzaG93IHRoZSBmdWxsXHJcbiAgICAvLyBsaXN0IGluIHRoZSBzaWRlYmFyLlxyXG4gICAgLy8gQHRzLWlnbm9yZVxyXG4gICAgdGhpcy5tb250aEdyaWQuYWRkRXZlbnRMaXN0ZW5lcignZGF5LWNsaWNrZWQnLCAoZTogQ3VzdG9tRXZlbnQpID0+IHtcclxuICAgICAgY29uc3QgZGF0ZSA9IGUuZGV0YWlsO1xyXG4gICAgICBjb25zdCBldmVudHMgPSBnZXRFdmVudHNGb3JEYXkodGhpcy5fZXZlbnRzLCBkYXRlKTtcclxuICAgICAgdGhpcy5zaWRlYmFyLmV2ZW50cyA9IGV2ZW50cztcclxuICAgIH0pO1xyXG4gICAgLy8gQHRzLWlnbm9yZVxyXG4gICAgdGhpcy53ZWVrR3JpZC5hZGRFdmVudExpc3RlbmVyKCdkYXktY2xpY2tlZCcsIChlOiBDdXN0b21FdmVudCkgPT4ge1xyXG4gICAgICBjb25zdCBkYXRlID0gZS5kZXRhaWw7XHJcbiAgICAgIGNvbnN0IGV2ZW50cyA9IGdldEV2ZW50c0ZvckRheSh0aGlzLl9ldmVudHMsIGRhdGUpO1xyXG4gICAgICB0aGlzLnNpZGViYXIuZXZlbnRzID0gZXZlbnRzO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU3RhcnQgd2l0aCB0b2RheS5cclxuICAgIHRoaXMuc2lkZWJhci5ldmVudHMgPSBnZXRFdmVudHNGb3JEYXkodGhpcy5fZXZlbnRzLCBuZXcgRGF0ZSgpKTtcclxuXHJcbiAgICAvLyBTaG93L2hpZGUgdGhlIHJpZ2h0IG1vZGVcclxuICAgIGlmICh0aGlzLm1vZGUgPT09IFwid2Vla1wiKSB7XHJcbiAgICAgIHRoaXMubW9udGhHcmlkRWwuc3R5bGUuZGlzcGxheSA9ICdub25lJztcclxuICAgICAgdGhpcy53ZWVrR3JpZEVsLnN0eWxlLmRpc3BsYXkgPSAnZ3JpZCc7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLm1vbnRoR3JpZEVsLnN0eWxlLmRpc3BsYXkgPSAnZ3JpZCc7XHJcbiAgICAgIHRoaXMud2Vla0dyaWRFbC5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgc2V0IGRhdGUoZGF0ZTogRGF0ZSkge1xyXG4gICAgY29uc29sZS5sb2coXCJTZXR0aW5nIGRhdGUgdG9cIiwgZGF0ZSk7XHJcbiAgICB0aGlzLl9kYXRlID0gZGF0ZTtcclxuICAgIHRoaXMubW9udGhHcmlkLmRhdGUgPSBkYXRlO1xyXG4gICAgdGhpcy53ZWVrR3JpZC5kYXRlID0gZGF0ZTtcclxuICAgIHRoaXMudG9vbGJhci5kYXRlID0gZGF0ZTtcclxuICAgIHRoaXMuc2lkZWJhci5ldmVudHMgPSBnZXRFdmVudHNGb3JEYXkodGhpcy5fZXZlbnRzLCB0aGlzLl9kYXRlKTtcclxuICB9XHJcblxyXG4gIHNldCBldmVudHMoZXZlbnRzOiBDYWxlbmRhckV2ZW50W10pIHtcclxuICAgIHRoaXMuX2V2ZW50cyA9IGV2ZW50cztcclxuICAgIHRoaXMubW9udGhHcmlkLmV2ZW50cyA9IGV2ZW50cztcclxuICAgIHRoaXMud2Vla0dyaWQuZXZlbnRzID0gZXZlbnRzO1xyXG4gICAgdGhpcy5zaWRlYmFyLmV2ZW50cyA9IGdldEV2ZW50c0ZvckRheSh0aGlzLl9ldmVudHMsIHRoaXMuX2RhdGUpO1xyXG4gIH1cclxufVxyXG4iLCJleHBvcnQgY2xhc3MgQ2FsZW5kYXJFdmVudCB7XHJcbiAgdGl0bGU6IHN0cmluZztcclxuICBpZDogc3RyaW5nO1xyXG4gIGRhdGU6IERhdGU7XHJcbiAgdGltZTogc3RyaW5nfHVuZGVmaW5lZDtcclxuICBkdXJhdGlvbjogbnVtYmVyfHVuZGVmaW5lZDtcclxuICByZXBlYXQ6IHN0cmluZ3x1bmRlZmluZWQ7XHJcbiAgZGVzY3JpcHRpb246IHN0cmluZ3x1bmRlZmluZWQ7XHJcbiAgY29sb3I6IHN0cmluZ3x1bmRlZmluZWQ7XHJcbiAgbG9jYXRpb246IHN0cmluZ3x1bmRlZmluZWQ7XHJcbiAgbXVsdGlEYXlzOiB7c3RhcnQ6IERhdGUsIGVuZDogRGF0ZX18bnVsbDtcclxuICByc3ZwOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHRpdGxlOiBzdHJpbmcsIGlkOiBzdHJpbmcsIGRhdGU6IERhdGUpIHtcclxuICAgIHRoaXMudGl0bGUgPSB0aXRsZTtcclxuICAgIHRoaXMuaWQgPSBpZDtcclxuICAgIHRoaXMuZGF0ZSA9IGRhdGU7XHJcbiAgfVxyXG5cclxuICBhc09uZUxpbmVIVE1MKGluZGV4SW5HcmlkOiBudW1iZXJ8dW5kZWZpbmVkID0gdW5kZWZpbmVkKTogc3RyaW5nIHtcclxuICAgIGNvbnN0IHRpbWUgPSB0aGlzLnRpbWUgPyBgPHNwYW4gY2xhc3M9XCJ0aW1lXCI+JHt0aGlzLnRpbWV9PC9zcGFuPmAgOiAnJztcclxuXHJcbiAgICByZXR1cm4gYFxyXG4gICAgICA8bGkgaWQ9XCJpZC0ke3RoaXMuaWR9XCIgZGF0YS1pbmRleC1pbi1ncmlkPVwiJHtpbmRleEluR3JpZH1cIiBjbGFzcz1cImV2ZW50JHshIXRoaXMubXVsdGlEYXlzID8gXCIgbXVsdGktZGF5XCIgOiBcIlwifSR7dGhpcy5yc3ZwID8gXCJcIiA6IFwiIHVuY29uZmlybWVkXCJ9XCIgc3R5bGU9XCItLWV2ZW50LWNvbG9yOiAke3RoaXMuY29sb3J9O1wiPlxyXG4gICAgICAgIDxkaXY+JHt0aW1lfSA8c3BhbiBjbGFzcz1cInRpdGxlXCI+JHt0aGlzLnRpdGxlfTwvc3Bhbj48L2Rpdj5cclxuICAgICAgPC9saT5cclxuICAgIGA7XHJcbiAgfVxyXG5cclxuICBhc01lZGl1bUxlbmd0aEhUTUwoKTogc3RyaW5nIHtcclxuICAgIGNvbnN0IHRpbWUgPSB0aGlzLnRpbWUgPyBgPHNwYW4gY2xhc3M9XCJ0aW1lXCI+JHt0aGlzLnRpbWV9PC9zcGFuPmAgOiAnJztcclxuXHJcbiAgICByZXR1cm4gYFxyXG4gICAgICA8bGkgaWQ9XCJpZC0ke3RoaXMuaWR9XCIgY2xhc3M9XCJldmVudCR7ISF0aGlzLm11bHRpRGF5cyA/IFwiIG11bHRpLWRheVwiIDogXCJcIn0ke3RoaXMucnN2cCA/IFwiXCIgOiBcIiB1bmNvbmZpcm1lZFwifVwiIHN0eWxlPVwiLS1ldmVudC1jb2xvcjogJHt0aGlzLmNvbG9yfTtcIj5cclxuICAgICAgICA8ZGl2PiR7dGltZX08L2Rpdj5cclxuICAgICAgICA8cCBjbGFzcz1cInRpdGxlXCI+JHt0aGlzLnRpdGxlfTwvcD5cclxuICAgICAgICA8cD4ke3RoaXMuZGVzY3JpcHRpb259PC9wPlxyXG4gICAgICA8L2xpPlxyXG4gICAgYDtcclxuICB9XHJcblxyXG4gIGFzRnVsbEhUTUwoKTogc3RyaW5nIHtcclxuICAgIGxldCB3aGVuID0gXCJcIjtcclxuICAgICAgXHJcbiAgICBpZiAoIXRoaXMubXVsdGlEYXlzKSB7XHJcbiAgICAgIHdoZW4gPSB0aGlzLmRhdGUudG9EYXRlU3RyaW5nKCk7XHJcbiAgICAgIGlmICh0aGlzLnRpbWUpIHtcclxuICAgICAgICB3aGVuICs9IGAsIGF0ICR7dGhpcy50aW1lfWA7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKHRoaXMucmVwZWF0KSB7XHJcbiAgICAgICAgd2hlbiArPSBgLCAke3RoaXMucmVwZWF0fWA7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKHRoaXMuZHVyYXRpb24pIHtcclxuICAgICAgICB3aGVuICs9IGAgKCR7dGhpcy5kdXJhdGlvbn0gbWludXRlcylgO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB3aGVuID0gYEZyb20gJHt0aGlzLm11bHRpRGF5cy5zdGFydC50b0RhdGVTdHJpbmcoKX0gdG8gJHt0aGlzLm11bHRpRGF5cy5lbmQudG9EYXRlU3RyaW5nKCl9YDtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gYFxyXG4gICAgICA8bGkgY2xhc3M9XCJldmVudCR7dGhpcy5yc3ZwID8gXCJcIiA6IFwiIHVuY29uZmlybWVkXCJ9XCIgc3R5bGU9XCItLWV2ZW50LWNvbG9yOiAke3RoaXMuY29sb3J9O1wiPlxyXG4gICAgICAgIDxkaXY+XHJcbiAgICAgICAgICA8aDI+JHt0aGlzLnRpdGxlfTwvaDI+XHJcbiAgICAgICAgICA8cCBjbGFzcz1cIndoZW5cIj4ke3doZW59PC9wPlxyXG4gICAgICAgICAgJHt0aGlzLmxvY2F0aW9uID8gYDxwIGNsYXNzPVwid2hlcmVcIj4ke3RoaXMubG9jYXRpb259PC9wPmAgOiBcIlwifVxyXG4gICAgICAgICAgPHAgY2xhc3M9XCJ3aGF0XCI+JHt0aGlzLmRlc2NyaXB0aW9ufTwvcD5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgPC9saT5cclxuICAgIGA7XHJcbiAgfVxyXG59XHJcbiIsImltcG9ydCB7IENhbGVuZGFyRXZlbnQgfSBmcm9tIFwiLi9DYWxlbmRhckV2ZW50XCI7XHJcblxyXG5leHBvcnQgY2xhc3MgRXZlbnRQb3B1cCB7XHJcbiAgcHJpdmF0ZSBwb3B1cEVsOiBIVE1MRWxlbWVudHx1bmRlZmluZWQ7XHJcblxyXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgZXZlbnRzOiBDYWxlbmRhckV2ZW50W10pIHt9XHJcblxyXG4gIHN0YXJ0KCkge1xyXG4gICAgaWYgKCF0aGlzLnBvcHVwRWwpIHtcclxuICAgICAgdGhpcy5wb3B1cEVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcclxuICAgICAgdGhpcy5wb3B1cEVsLmNsYXNzTmFtZSA9IFwicG9wdXBcIjtcclxuICAgIH1cclxuICAgIFxyXG4gICAgYWRkRXZlbnRMaXN0ZW5lcihcIm1vdXNlbW92ZVwiLCAoZTogTW91c2VFdmVudCkgPT4ge1xyXG4gICAgICB0aGlzLnBvcHVwRWwuY2xhc3NMaXN0LnJlbW92ZShcInZpc2libGVcIik7XHJcbiAgICAgIHRoaXMucG9wdXBFbC5yZW1vdmUoKTtcclxuXHJcbiAgICAgIGNvbnN0IGV2ZW50RWwgPSAoZS50YXJnZXQgYXMgSFRNTEVsZW1lbnQpLmNsb3Nlc3QoXCIjbW9udGgtZ3JpZCAuZXZlbnQsICN3ZWVrLWdyaWQgLmV2ZW50XCIpIGFzIEhUTUxFbGVtZW50O1xyXG4gICAgICBpZiAoIWV2ZW50RWwpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGNvbnN0IGlkID0gZXZlbnRFbC5pZDtcclxuXHJcbiAgICAgIGlmICghaWQgfHwgIWlkLnN0YXJ0c1dpdGgoXCJpZC1cIikpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGxldCBldmVudElkID0gaWQucmVwbGFjZShcImlkLVwiLCBcIlwiKTtcclxuXHJcbiAgICAgIGNvbnN0IGV2ZW50ID0gdGhpcy5ldmVudHMuZmluZChldmVudCA9PiBldmVudC5pZCA9PT0gZXZlbnRJZCk7ICAgICAgXHJcbiAgICAgIGlmICghZXZlbnQpIHtcclxuICAgICAgICBjb25zb2xlLmxvZyhcIk5vIGV2ZW50IGZvdW5kIGZvciBpZFwiLCBldmVudElkKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGNvbnN0IGV2ZW50SW5kZXhJbkdyaWQgPSBwYXJzZUludChldmVudEVsLmRhdGFzZXQuaW5kZXhJbkdyaWQhKTtcclxuXHJcbiAgICAgIHRoaXMucG9wdXBFbC5zdHlsZS5zZXRQcm9wZXJ0eShcIi0tZXZlbnQtY29sb3JcIiwgZXZlbnQuY29sb3IpO1xyXG4gICAgICB0aGlzLnBvcHVwRWwuY2xhc3NMaXN0LnRvZ2dsZShcInZpc2libGVcIiwgdHJ1ZSk7XHJcbiAgICAgIHRoaXMucG9wdXBFbC5jbGFzc0xpc3QudG9nZ2xlKFwidW5jb25maXJtZWRcIiwgIWV2ZW50LnJzdnApO1xyXG5cclxuICAgICAgbGV0IHdoZW4gPSBcIlwiO1xyXG4gICAgICBcclxuICAgICAgaWYgKCFldmVudC5tdWx0aURheXMpIHtcclxuICAgICAgICB3aGVuID0gZXZlbnQuZGF0ZS50b0RhdGVTdHJpbmcoKTtcclxuICAgICAgICBpZiAoZXZlbnQudGltZSkge1xyXG4gICAgICAgICAgd2hlbiArPSBgLCBhdCAke2V2ZW50LnRpbWV9YDtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGV2ZW50LnJlcGVhdCkge1xyXG4gICAgICAgICAgd2hlbiArPSBgLCAke2V2ZW50LnJlcGVhdH1gO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoZXZlbnQuZHVyYXRpb24pIHtcclxuICAgICAgICAgIHdoZW4gKz0gYCAoJHtldmVudC5kdXJhdGlvbn0gbWludXRlcylgO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB3aGVuID0gYEZyb20gJHtldmVudC5tdWx0aURheXMuc3RhcnQudG9EYXRlU3RyaW5nKCl9IHRvICR7ZXZlbnQubXVsdGlEYXlzLmVuZC50b0RhdGVTdHJpbmcoKX1gO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aGlzLnBvcHVwRWwuaW5uZXJIVE1MID0gYFxyXG4gICAgICAgIDxoMj4ke2V2ZW50LnRpdGxlfTwvaDI+XHJcbiAgICAgICAgPHAgY2xhc3M9XCJ3aGVuXCI+JHt3aGVufTwvcD5cclxuICAgICAgICAke2V2ZW50LmxvY2F0aW9uID8gYDxwIGNsYXNzPVwid2hlcmVcIj4ke2V2ZW50LmxvY2F0aW9ufTwvcD5gIDogXCJcIn1cclxuICAgICAgICA8cCBjbGFzcz1cIndoYXRcIj4ke2V2ZW50LmRlc2NyaXB0aW9ufTwvcD5cclxuICAgICAgYDtcclxuXHJcbiAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQodGhpcy5wb3B1cEVsKTtcclxuXHJcbiAgICAgIC8vIEdldCB0aGUgY29vcmRpbmF0ZXMgb2YgdGhlIGV2ZW50IGVsZW1lbnQuXHJcbiAgICAgIGNvbnN0IHJlY3QgPSBldmVudEVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgICBjb25zdCB0b3AgPSByZWN0LnRvcDtcclxuICAgICAgY29uc3QgcmlnaHQgPSByZWN0LnJpZ2h0O1xyXG4gICAgICBjb25zdCBsZWZ0ID0gcmVjdC5sZWZ0O1xyXG4gICAgICBjb25zdCB3aWR0aCA9IHJlY3Qud2lkdGg7XHJcblxyXG4gICAgICBpZiAoZXZlbnRJbmRleEluR3JpZCA+PSAyOCkge1xyXG4gICAgICAgIC8vIFRoZSBldmVudCBpcyBpbiB0aGUgbGFzdCAyIHJvd3MuIFNob3cgdGhlIHBvcHVwIGFib3ZlIGl0LlxyXG4gICAgICAgIHRoaXMucG9wdXBFbC5zdHlsZS50b3AgPSBgJHt0b3AgLSB0aGlzLnBvcHVwRWwuY2xpZW50SGVpZ2h0fXB4YDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLnBvcHVwRWwuc3R5bGUudG9wID0gYCR7dG9wfXB4YDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGV2ZW50SW5kZXhJbkdyaWQgPT09IDYgfHwgZXZlbnRJbmRleEluR3JpZCA9PT0gMTMgfHwgZXZlbnRJbmRleEluR3JpZCA9PT0gMjAgfHwgZXZlbnRJbmRleEluR3JpZCA9PT0gMjcgfHwgZXZlbnRJbmRleEluR3JpZCA9PT0gMzQpIHtcclxuICAgICAgICAvLyBUaGUgZXZlbnQgaXMgbGFzdCBpbiBhIHJvdywgc28gd2Ugd2FudCB0byBzaG93IHRoZSBwb3B1cCB0byB0aGUgbGVmdCBvZiBpdC5cclxuICAgICAgICB0aGlzLnBvcHVwRWwuc3R5bGUubGVmdCA9IGAke2xlZnQgLSB3aWR0aH1weGA7XHJcbiAgICAgICAgdGhpcy5wb3B1cEVsLmNsYXNzTGlzdC50b2dnbGUoXCJsZWZ0XCIsIHRydWUpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRoaXMucG9wdXBFbC5zdHlsZS5sZWZ0ID0gYCR7cmlnaHR9cHhgO1xyXG4gICAgICAgIHRoaXMucG9wdXBFbC5jbGFzc0xpc3QudG9nZ2xlKFwibGVmdFwiLCBmYWxzZSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxufVxyXG4iLCJleHBvcnQgY2xhc3MgU3RvcmUge1xyXG4gIGFzeW5jIGdldFN0b3JlZFByZWZzKCk6IFByb21pc2U8e21vZGU6IHN0cmluZywgaW5pdERhdGU6IERhdGV8dW5kZWZpbmVkfT4ge1xyXG4gICAgLy8gRmFrZSBzb21lIHJhbmRvbSB0aW1lICh1cCB0byAyNTBtcykgdG8gc2ltdWxhdGUgYW4gQVBJIGNhbGwuXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgTWF0aC5yYW5kb20oKSAqIDI1MCkpO1xyXG5cclxuICAgIGNvbnN0IG1vZGUgPSBsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnc2xvdy1jYWwtbW9kZScpO1xyXG4gICAgY29uc3QgaW5pdERhdGUgPSBsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnc2xvdy1jYWwtaW5pdERhdGUnKTtcclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBtb2RlLFxyXG4gICAgICBpbml0RGF0ZTogaW5pdERhdGUgPyBuZXcgRGF0ZShpbml0RGF0ZSkgOiB1bmRlZmluZWRcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBzZXQgbW9kZShtb2RlOiBzdHJpbmcpIHtcclxuICAgIGNvbnNvbGUubG9nKFwiU3RvcmluZyBtb2RlIHByZWZzXCIpO1xyXG4gICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oJ3Nsb3ctY2FsLW1vZGUnLCBtb2RlKTtcclxuICB9XHJcblxyXG4gIHNldCBpbml0RGF0ZShkYXRlOiBEYXRlKSB7XHJcbiAgICBjb25zb2xlLmxvZyhcIlN0b3JpbmcgZGF0ZSBwcmVmc1wiKTtcclxuICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKCdzbG93LWNhbC1pbml0RGF0ZScsIGRhdGUudG9JU09TdHJpbmcoKSk7XHJcbiAgfVxyXG59XHJcbiIsImltcG9ydCB7IEFwcFVJIH0gZnJvbSBcIi4vQXBwVUlcIjtcclxuaW1wb3J0IHsgZ2V0QWxsRXZlbnRzIH0gZnJvbSBcIi4vZXZlbnRzLWZhY3RvcnlcIjtcclxuaW1wb3J0IHsgRXZlbnRQb3B1cCB9IGZyb20gXCIuL0V2ZW50UG9wdXBcIjtcclxuaW1wb3J0IHsgU3RvcmUgfSBmcm9tIFwiLi9TdG9yZVwiO1xyXG5cclxuYWRkRXZlbnRMaXN0ZW5lcihcIkRPTUNvbnRlbnRMb2FkZWRcIiwgYXN5bmMgKCkgPT4ge1xyXG4gIGNvbnN0IHN0b3JlID0gbmV3IFN0b3JlKCk7XHJcbiAgY29uc3QgcHJlZnMgPSBhd2FpdCBzdG9yZS5nZXRTdG9yZWRQcmVmcygpO1xyXG5cclxuICAvLyBUaGlzIGlzIHdoYXQgdGhlIGNhbGVuZGFyIHdpbGwgYmUgY2VudGVyZWQgYXJvdW5kIG9uIGxvYWQuXHJcbiAgY29uc3QgaW5pdERhdGUgPSBwcmVmcy5pbml0RGF0ZSB8fCBuZXcgRGF0ZSgpO1xyXG4gIGNvbnN0IGluaXRNb2RlID0gcHJlZnMubW9kZSB8fCBcIm1vbnRoXCI7XHJcblxyXG4gIGNvbnN0IGFwcEVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2FwcCcpO1xyXG4gIGNvbnN0IGFwcFVJID0gbmV3IEFwcFVJKGFwcEVsISwgaW5pdERhdGUsIGluaXRNb2RlLCBbXSk7XHJcblxyXG4gIGNvbnN0IGV2ZW50cyA9IGF3YWl0IGdldEFsbEV2ZW50cygpXHJcblxyXG4gIGNvbnNvbGUubG9nKFwiUmVmcmVzaGluZyBjYWxlbmRhciB3aXRoIGV2ZW50c1wiKTtcclxuICBhcHBVSS5ldmVudHMgPSBldmVudHM7XHJcblxyXG4gIGNvbnNvbGUubG9nKFwiSW5pdGlhbGl6aW5nIHRoZSBwb3B1cCB1dGlsXCIpO1xyXG4gIGNvbnN0IHBvcHVwID0gbmV3IEV2ZW50UG9wdXAoZXZlbnRzKTtcclxuICBwb3B1cC5zdGFydCgpO1xyXG5cclxuICAvLyBAdHMtaWdub3JlXHJcbiAgYXBwVUkuYWRkRXZlbnRMaXN0ZW5lcihcIm1vZGUtY2hhbmdlZFwiLCAoZTogQ3VzdG9tRXZlbnQpID0+IHtcclxuICAgIHN0b3JlLm1vZGUgPSBlLmRldGFpbDtcclxuICB9KTtcclxuXHJcbiAgLy8gQHRzLWlnbm9yZVxyXG4gIGFwcFVJLmFkZEV2ZW50TGlzdGVuZXIoXCJkYXRlLWNoYW5nZWRcIiwgKGU6IEN1c3RvbUV2ZW50KSA9PiB7XHJcbiAgICBzdG9yZS5pbml0RGF0ZSA9IGUuZGV0YWlsO1xyXG4gIH0pO1xyXG59KTtcclxuIiwiaW1wb3J0IHsgQ2FsZW5kYXJFdmVudCB9IGZyb20gXCIuL0NhbGVuZGFyRXZlbnRcIjtcclxuXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoRGF0YSgpIHtcclxuICAvLyBTaW11bGF0ZSBhIHNsb3dlciBBUEkgZW5kcG9pbnQgY2FsbC5cclxuICBjb25zb2xlLmxvZyhcIkZldGNoaW5nIGNhbGVuZGFyIGRhdGEgLi4uXCIpO1xyXG4gIGF3YWl0IG5ldyBQcm9taXNlKHJlc29sdmUgPT4gc2V0VGltZW91dChyZXNvbHZlLCBNYXRoLnJhbmRvbSgpICogNTAwKSk7XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCgnLi9kYXRhLmpzb24nKTtcclxuICByZXR1cm4gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xyXG59XHJcblxyXG5mdW5jdGlvbiBjcmVhdGVPbmVPck11bHRpcGxlRXZlbnRzRnJvbURhdGEoZXZlbnREYXRhOiBhbnkpOiBDYWxlbmRhckV2ZW50W10geyAgXHJcbiAgY29uc3QgZGF0ZXM6IERhdGVbXSA9IFtuZXcgRGF0ZShldmVudERhdGEuc3RhcnREYXRlKV07XHJcbiAgbGV0IG11bHRpRGF5czoge3N0YXJ0OiBEYXRlLCBlbmQ6IERhdGV9fG51bGwgPSBudWxsO1xyXG5cclxuICBpZiAoZXZlbnREYXRhLnJlcGVhdCkge1xyXG4gICAgY29uc3Qgc3RhcnREYXRlID0gbmV3IERhdGUoZXZlbnREYXRhLnN0YXJ0RGF0ZSk7XHJcblxyXG4gICAgLy8gSWYgdGhpcyBldmVudCBpcyByZXBlYXRlZCwgaXQgbXVzdCBoYXZlIGFuIGVuZCBkYXRlLlxyXG4gICAgY29uc3QgZW5kRGF0ZSA9IGV2ZW50RGF0YS5lbmREYXRlXHJcbiAgICAgIC8vIEVpdGhlciB0aGUgZW5kIGRhdGUgaXMgc3BlY2lmaWVkLlxyXG4gICAgICA/IG5ldyBEYXRlKGV2ZW50RGF0YS5lbmREYXRlKVxyXG4gICAgICAvLyBPciBpdCdzIDUgeWVhciBhZnRlciB0aGUgc3RhcnQgZGF0ZS5cclxuICAgICAgOiBuZXcgRGF0ZShzdGFydERhdGUuZ2V0VGltZSgpICsgNSAqIDM2NSAqIDI0ICogNjAgKiA2MCAqIDEwMDApO1xyXG5cclxuICAgIGlmIChldmVudERhdGEucmVwZWF0ID09PSBcImRhaWx5XCIpIHtcclxuICAgICAgY29uc29sZS5sb2coXCJFeHBhbmRpbmcgZGFpbHkgZXZlbnQgLi4uXCIpO1xyXG4gICAgICBjb25zdCBkYXlzID0gKGVuZERhdGUuZ2V0VGltZSgpIC0gc3RhcnREYXRlLmdldFRpbWUoKSkgLyAoMTAwMCAqIDYwICogNjAgKiAyNCk7XHJcbiAgICAgIGZvciAobGV0IGkgPSAxOyBpIDw9IGRheXM7IGkrKykge1xyXG4gICAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShzdGFydERhdGUuZ2V0VGltZSgpICsgaSAqIDI0ICogNjAgKiA2MCAqIDEwMDApO1xyXG4gICAgICAgIC8vIElmIGRhdGUgaXMgb24gYSB3ZWVrIGVuZCwgc2tpcCBpdC5cclxuICAgICAgICBpZiAoZGF0ZS5nZXREYXkoKSA9PT0gMCB8fCBkYXRlLmdldERheSgpID09PSA2KSB7XHJcbiAgICAgICAgICBjb250aW51ZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGRhdGVzLnB1c2goZGF0ZSk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSBpZiAoZXZlbnREYXRhLnJlcGVhdCA9PT0gXCJ3ZWVrbHlcIikge1xyXG4gICAgICBjb25zb2xlLmxvZyhcIkV4cGFuZGluZyB3ZWVrbHkgZXZlbnQgLi4uXCIpO1xyXG4gICAgICBjb25zdCB3ZWVrcyA9IChlbmREYXRlLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZS5nZXRUaW1lKCkpIC8gKDEwMDAgKiA2MCAqIDYwICogMjQgKiA3KTtcclxuICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPD0gd2Vla3M7IGkrKykge1xyXG4gICAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShzdGFydERhdGUuZ2V0VGltZSgpICsgaSAqIDcgKiAyNCAqIDYwICogNjAgKiAxMDAwKTtcclxuICAgICAgICBkYXRlcy5wdXNoKGRhdGUpO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2UgaWYgKGV2ZW50RGF0YS5yZXBlYXQgPT09IFwibW9udGhseVwiKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKFwiRXhwYW5kaW5nIG1vbnRobHkgZXZlbnQgLi4uXCIpO1xyXG4gICAgICBjb25zdCBtb250aHMgPSAoZW5kRGF0ZS5nZXRGdWxsWWVhcigpIC0gc3RhcnREYXRlLmdldEZ1bGxZZWFyKCkpICogMTIgKyAoZW5kRGF0ZS5nZXRNb250aCgpIC0gc3RhcnREYXRlLmdldE1vbnRoKCkpO1xyXG4gICAgICBmb3IgKGxldCBpID0gMTsgaSA8PSBtb250aHM7IGkrKykge1xyXG4gICAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShzdGFydERhdGUuZ2V0VGltZSgpKTtcclxuICAgICAgICBkYXRlLnNldE1vbnRoKGRhdGUuZ2V0TW9udGgoKSArIGkpO1xyXG4gICAgICAgIGRhdGVzLnB1c2goZGF0ZSk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSBpZiAoZXZlbnREYXRhLnJlcGVhdCA9PT0gXCJ5ZWFybHlcIikge1xyXG4gICAgICBjb25zb2xlLmxvZyhcIkV4cGFuZGluZyB5ZWFybHkgZXZlbnQgLi4uXCIpO1xyXG4gICAgICBjb25zdCB5ZWFycyA9IGVuZERhdGUuZ2V0RnVsbFllYXIoKSAtIHN0YXJ0RGF0ZS5nZXRGdWxsWWVhcigpO1xyXG4gICAgICBmb3IgKGxldCBpID0gMTsgaSA8PSB5ZWFyczsgaSsrKSB7XHJcbiAgICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKHN0YXJ0RGF0ZS5nZXRUaW1lKCkpO1xyXG4gICAgICAgIGRhdGUuc2V0RnVsbFllYXIoZGF0ZS5nZXRGdWxsWWVhcigpICsgaSk7XHJcbiAgICAgICAgZGF0ZXMucHVzaChkYXRlKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0gZWxzZSBpZiAoZXZlbnREYXRhLmVuZERhdGUpIHtcclxuICAgIC8vIElmIHRoaXMgZXZlbnQgaGFzIGEgc3RhcnQgYW5kIGVuZCBkYXRlLCBidXQgaXNuJ3QgcmVwZWF0ZWQuXHJcbiAgICBjb25zdCBzdGFydERhdGUgPSBuZXcgRGF0ZShldmVudERhdGEuc3RhcnREYXRlKTtcclxuICAgIGNvbnN0IGVuZERhdGUgPSBuZXcgRGF0ZShldmVudERhdGEuZW5kRGF0ZSk7XHJcbiAgICBjb25zdCBkYXlzID0gKGVuZERhdGUuZ2V0VGltZSgpIC0gc3RhcnREYXRlLmdldFRpbWUoKSkgLyAoMTAwMCAqIDYwICogNjAgKiAyNCk7XHJcbiAgICBmb3IgKGxldCBpID0gMTsgaSA8PSBkYXlzOyBpKyspIHtcclxuICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKHN0YXJ0RGF0ZS5nZXRUaW1lKCkgKyBpICogMjQgKiA2MCAqIDYwICogMTAwMCk7XHJcbiAgICAgIGRhdGVzLnB1c2goZGF0ZSk7XHJcbiAgICB9XHJcbiAgICBtdWx0aURheXMgPSB7c3RhcnQ6IHN0YXJ0RGF0ZSwgZW5kOiBlbmREYXRlfTtcclxuICB9XHJcblxyXG5cclxuICByZXR1cm4gZGF0ZXMubWFwKChkYXRlLCBpbmRleCkgPT4ge1xyXG4gICAgY29uc3QgaWQgPSBldmVudERhdGEuaWQgKyAoaW5kZXggPiAwID8gYC0ke2luZGV4fWAgOiBcIlwiKTtcclxuICAgIGNvbnN0IGV2ZW50ID0gbmV3IENhbGVuZGFyRXZlbnQoZXZlbnREYXRhLnRpdGxlLCBpZCwgZGF0ZSk7XHJcblxyXG4gICAgZXZlbnQubXVsdGlEYXlzID0gbXVsdGlEYXlzO1xyXG5cclxuICAgIGV2ZW50LmNvbG9yID0gZXZlbnREYXRhLmNvbG9yO1xyXG4gICAgZXZlbnQudGltZSA9IGV2ZW50RGF0YS5zdGFydFRpbWU7XHJcbiAgICBldmVudC5kdXJhdGlvbiA9IGV2ZW50RGF0YS5kdXJhdGlvbjtcclxuICAgIGV2ZW50LnJlcGVhdCA9IGV2ZW50RGF0YS5yZXBlYXQ7XHJcbiAgICBldmVudC5sb2NhdGlvbiA9IGV2ZW50RGF0YS5sb2NhdGlvbjtcclxuICAgIGV2ZW50LmRlc2NyaXB0aW9uID0gZXZlbnREYXRhLmRlc2NyaXB0aW9uO1xyXG4gICAgZXZlbnQucnN2cCA9IGV2ZW50RGF0YS5yc3ZwO1xyXG5cclxuICAgIHJldHVybiBldmVudDtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldEFsbEV2ZW50cygpOiBQcm9taXNlPENhbGVuZGFyRXZlbnRbXT4ge1xyXG4gIGNvbnN0IGRhdGEgPSBhd2FpdCBmZXRjaERhdGEoKTtcclxuXHJcbiAgY29uc29sZS5sb2coXCJQcm9jZXNzaW5nIGV2ZW50cyAuLi5cIik7XHJcbiAgcmV0dXJuIGRhdGEuZXZlbnRzLm1hcCgoZXZlbnQ6IGFueSkgPT4ge1xyXG4gICAgcmV0dXJuIGNyZWF0ZU9uZU9yTXVsdGlwbGVFdmVudHNGcm9tRGF0YShldmVudCk7XHJcbiAgfSkuZmxhdCgpO1xyXG59XHJcbiJdLCJuYW1lcyI6WyJhc3NlcnRUeXBlIiwiY29uZGl0aW9uIiwibWVzc2FnZSIsImFyZ3MiLCJUeXBlRXJyb3IiLCJmb3JtYXQiLCJpIiwicmVwbGFjZSIsImFueVRvU3RyaW5nIiwieCIsIlN0cmluZyIsIk9iamVjdCIsInByb3RvdHlwZSIsInRvU3RyaW5nIiwiY2FsbCIsIkdsb2JhbCIsIndpbmRvdyIsInNlbGYiLCJnbG9iYWwiLCJnbG9iYWxUaGlzIiwidW5kZWZpbmVkIiwiY3VycmVudFdhcm5IYW5kbGVyIiwiV2FybmluZyIsImNvbnN0cnVjdG9yIiwiY29kZSIsInRoaXMiLCJ3YXJuIiwiX2EiLCJzdGFjayIsIkVycm9yIiwiY29uc29sZSIsIl9iIiwiSW5pdEV2ZW50V2FzQ2FsbGVkV2hpbGVEaXNwYXRjaGluZyIsIkZhbHN5V2FzQXNzaWduZWRUb0NhbmNlbEJ1YmJsZSIsIlRydXRoeVdhc0Fzc2lnbmVkVG9SZXR1cm5WYWx1ZSIsIk5vbkNhbmNlbGFibGVFdmVudFdhc0NhbmNlbGVkIiwiQ2FuY2VsZWRJblBhc3NpdmVMaXN0ZW5lciIsIkV2ZW50TGlzdGVuZXJXYXNEdXBsaWNhdGVkIiwiT3B0aW9uV2FzSWdub3JlZCIsIkludmFsaWRFdmVudExpc3RlbmVyIiwiRXZlbnQiLCJOT05FIiwiQ0FQVFVSSU5HX1BIQVNFIiwiQVRfVEFSR0VUIiwiQlVCQkxJTkdfUEhBU0UiLCJ0eXBlIiwiZXZlbnRJbml0RGljdCIsImRlZmluZVByb3BlcnR5IiwidmFsdWUiLCJlbnVtZXJhYmxlIiwib3B0cyIsImludGVybmFsRGF0YU1hcCIsInNldCIsImJ1YmJsZXMiLCJCb29sZWFuIiwiY2FuY2VsYWJsZSIsImNvbXBvc2VkIiwidGFyZ2V0IiwiY3VycmVudFRhcmdldCIsInN0b3BQcm9wYWdhdGlvbkZsYWciLCJzdG9wSW1tZWRpYXRlUHJvcGFnYXRpb25GbGFnIiwiY2FuY2VsZWRGbGFnIiwiaW5QYXNzaXZlTGlzdGVuZXJGbGFnIiwiZGlzcGF0Y2hGbGFnIiwidGltZVN0YW1wIiwiRGF0ZSIsIm5vdyIsIiQiLCJzcmNFbGVtZW50IiwiY29tcG9zZWRQYXRoIiwiZXZlbnRQaGFzZSIsInN0b3BQcm9wYWdhdGlvbiIsImNhbmNlbEJ1YmJsZSIsInN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbiIsImRhdGEiLCJyZXR1cm5WYWx1ZSIsInNldENhbmNlbEZsYWciLCJwcmV2ZW50RGVmYXVsdCIsImRlZmF1bHRQcmV2ZW50ZWQiLCJpc1RydXN0ZWQiLCJpbml0RXZlbnQiLCJXZWFrTWFwIiwiZXZlbnQiLCJuYW1lIiwicmV0diIsImdldCIsImtleXMiLCJnZXRPd25Qcm9wZXJ0eU5hbWVzIiwibGVuZ3RoIiwiRE9NRXhjZXB0aW9uIiwic2V0UHJvdG90eXBlT2YiLCJFcnJvckNvZGVNYXAiLCJJTkRFWF9TSVpFX0VSUiIsIkRPTVNUUklOR19TSVpFX0VSUiIsIkhJRVJBUkNIWV9SRVFVRVNUX0VSUiIsIldST05HX0RPQ1VNRU5UX0VSUiIsIklOVkFMSURfQ0hBUkFDVEVSX0VSUiIsIk5PX0RBVEFfQUxMT1dFRF9FUlIiLCJOT19NT0RJRklDQVRJT05fQUxMT1dFRF9FUlIiLCJOT1RfRk9VTkRfRVJSIiwiTk9UX1NVUFBPUlRFRF9FUlIiLCJJTlVTRV9BVFRSSUJVVEVfRVJSIiwiSU5WQUxJRF9TVEFURV9FUlIiLCJTWU5UQVhfRVJSIiwiSU5WQUxJRF9NT0RJRklDQVRJT05fRVJSIiwiTkFNRVNQQUNFX0VSUiIsIklOVkFMSURfQUNDRVNTX0VSUiIsIlZBTElEQVRJT05fRVJSIiwiVFlQRV9NSVNNQVRDSF9FUlIiLCJTRUNVUklUWV9FUlIiLCJORVRXT1JLX0VSUiIsIkFCT1JUX0VSUiIsIlVSTF9NSVNNQVRDSF9FUlIiLCJRVU9UQV9FWENFRURFRF9FUlIiLCJUSU1FT1VUX0VSUiIsIklOVkFMSURfTk9ERV9UWVBFX0VSUiIsIkRBVEFfQ0xPTkVfRVJSIiwiZGVmaW5lRXJyb3JDb2RlUHJvcGVydGllcyIsIm9iaiIsImtleSIsImNvbmZpZ3VyYWJsZSIsIkV2ZW50V3JhcHBlciIsIndyYXAiLCJnZXRXcmFwcGVyQ2xhc3NPZiIsInN1cGVyIiwiaW50ZXJuYWxEYXRhTWFwJDEiLCJvcmlnaW5hbCIsImRlZmluZVJlZGlyZWN0RGVzY3JpcHRvciIsIiQkMSIsIndyYXBwZXJDbGFzc0NhY2hlIiwib3JpZ2luYWxFdmVudCIsImdldFByb3RvdHlwZU9mIiwid3JhcHBlciIsIkJhc2VFdmVudFdyYXBwZXIiLCJvcmlnaW5hbFByb3RvdHlwZSIsIkN1c3RvbUV2ZW50V3JhcHBlciIsImRlZmluZVdyYXBwZXIiLCJkIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwiYmluZCIsImlzQ2FwdHVyZSIsImxpc3RlbmVyIiwiZmxhZ3MiLCJpc1Bhc3NpdmUiLCJpc09uY2UiLCJpc1JlbW92ZWQiLCJpbnZva2VDYWxsYmFjayIsImNhbGxiYWNrIiwiaGFuZGxlRXZlbnQiLCJ0aHJvd25FcnJvciIsIm1heWJlRXJyb3IiLCJlcnJvciIsImRpc3BhdGNoRXZlbnQiLCJFcnJvckV2ZW50IiwicHJvY2VzcyIsImVtaXQiLCJyZXBvcnRFcnJvciIsImZpbmRJbmRleE9mTGlzdGVuZXIiLCJsaXN0ZW5lcnMiLCJjYXB0dXJlIiwicmVtb3ZlTGlzdGVuZXIiLCJsaXN0IiwiaW5kZXgiLCJyZW1vdmVMaXN0ZW5lckF0IiwiZGlzYWJsZUNvdyIsInNldFJlbW92ZWQiLCJzaWduYWwiLCJyZW1vdmVFdmVudExpc3RlbmVyIiwic2lnbmFsTGlzdGVuZXIiLCJjb3ciLCJmaWx0ZXIiLCJfIiwic3BsaWNlIiwiRXZlbnRUYXJnZXQiLCJpbnRlcm5hbERhdGFNYXAkMiIsImNyZWF0ZSIsImFkZEV2ZW50TGlzdGVuZXIiLCJ0eXBlMCIsImNhbGxiYWNrMCIsIm9wdGlvbnMwIiwibGlzdGVuZXJNYXAiLCIkJDIiLCJvbmNlIiwicGFzc2l2ZSIsIm9wdGlvbnMiLCJhc3NlcnRDYWxsYmFjayIsIm5vcm1hbGl6ZUFkZE9wdGlvbnMiLCJhYm9ydGVkIiwiYXR0ckNhbGxiYWNrIiwiYXR0ckxpc3RlbmVyIiwiZW5zdXJlTGlzdGVuZXJMaXN0IiwiY3JlYXRlTGlzdGVuZXIiLCJwdXNoIiwiYWRkTGlzdGVuZXIiLCJ3YXJuRHVwbGljYXRlIiwibm9ybWFsaXplT3B0aW9ucyIsImUiLCJldmVudERhdGEiLCJtc2ciLCJjYXB0dXJlU3RhY2tUcmFjZSIsImRlZmluZVByb3BlcnRpZXMiLCJrZXlzJDEiLCJnZXRFdmVudHNGb3JEYXkiLCJldmVudHMiLCJkYXRlIiwiZ2V0RnVsbFllYXIiLCJnZXRNb250aCIsImdldERhdGUiLCJzb3J0IiwiYSIsImIiLCJ0aW1lIiwicGFyc2VJbnQiLCJtdWx0aURheXMiLCJEQVlTIiwiTW9udGhHcmlkIiwiZWwiLCJfZGF0ZSIsInJvb3RFbCIsIl9ldmVudHMiLCJyZW5kZXIiLCJpbm5lckhUTUwiLCJtb250aCIsInllYXIiLCJmaXJzdERheSIsImxhc3REYXkiLCJmaXJzdFdlZWtkYXkiLCJnZXREYXkiLCJsYXN0V2Vla2RheSIsImRheXNJbk1vbnRoIiwiZGF5c0luTGFzdE1vbnRoIiwiZGF5cyIsImluZGV4SW5HcmlkIiwiaHRtbCIsInJlbmRlckRheSIsImluc2VydEFkamFjZW50SFRNTCIsImxhc3RFbGVtZW50Q2hpbGQiLCJDdXN0b21FdmVudCIsImRldGFpbCIsInVwZGF0ZU5vd01hcmtlciIsImRheU51bWJlciIsImNsYXNzTmFtZSIsInRvRGF0ZVN0cmluZyIsIm1hcCIsImFzT25lTGluZUhUTUwiLCJqb2luIiwicmF0aW8iLCJnZXRIb3VycyIsImdldE1pbnV0ZXMiLCJkYXlFbCIsInF1ZXJ5U2VsZWN0b3IiLCJtYXJrZXJIZWlnaHQiLCJvZmZzZXRIZWlnaHQiLCJzdHlsZSIsInNldFByb3BlcnR5Iiwic2V0VGltZW91dCIsIk1PTlRIUyIsIlRvb2xiYXIiLCJtb2RlIiwic2VsZWN0ZWRNb2RlIiwiZm9ybWF0TW9udGhZZWFyIiwibG9nIiwiU2lkZWJhciIsInVsIiwiZG9jdW1lbnQiLCJjcmVhdGVFbGVtZW50IiwiYXBwZW5kQ2hpbGQiLCJhc0Z1bGxIVE1MIiwiV2Vla0dyaWQiLCJkYXkiLCJhc01lZGl1bUxlbmd0aEhUTUwiLCJBcHBVSSIsInRvb2xiYXJFbCIsImlkIiwidG9vbGJhciIsIm5ld0RhdGUiLCJtb250aEdyaWRFbCIsImRpc3BsYXkiLCJ3ZWVrR3JpZEVsIiwibW9udGhHcmlkIiwid2Vla0dyaWQiLCJzaWRlYmFyRWwiLCJzaWRlYmFyIiwiQ2FsZW5kYXJFdmVudCIsInRpdGxlIiwicnN2cCIsImNvbG9yIiwiZGVzY3JpcHRpb24iLCJ3aGVuIiwic3RhcnQiLCJlbmQiLCJyZXBlYXQiLCJkdXJhdGlvbiIsImxvY2F0aW9uIiwiRXZlbnRQb3B1cCIsInBvcHVwRWwiLCJjbGFzc0xpc3QiLCJyZW1vdmUiLCJldmVudEVsIiwiY2xvc2VzdCIsInN0YXJ0c1dpdGgiLCJldmVudElkIiwiZmluZCIsImV2ZW50SW5kZXhJbkdyaWQiLCJkYXRhc2V0IiwidG9nZ2xlIiwiYm9keSIsInJlY3QiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0b3AiLCJyaWdodCIsImxlZnQiLCJ3aWR0aCIsImNsaWVudEhlaWdodCIsIlN0b3JlIiwiZ2V0U3RvcmVkUHJlZnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsIk1hdGgiLCJyYW5kb20iLCJsb2NhbFN0b3JhZ2UiLCJnZXRJdGVtIiwiaW5pdERhdGUiLCJzZXRJdGVtIiwidG9JU09TdHJpbmciLCJzdG9yZSIsInByZWZzIiwiaW5pdE1vZGUiLCJhcHBFbCIsImdldEVsZW1lbnRCeUlkIiwiYXBwVUkiLCJyZXNwb25zZSIsImZldGNoIiwianNvbiIsImZldGNoRGF0YSIsImRhdGVzIiwic3RhcnREYXRlIiwiZW5kRGF0ZSIsImdldFRpbWUiLCJ3ZWVrcyIsIm1vbnRocyIsInNldE1vbnRoIiwieWVhcnMiLCJzZXRGdWxsWWVhciIsInN0YXJ0VGltZSIsImNyZWF0ZU9uZU9yTXVsdGlwbGVFdmVudHNGcm9tRGF0YSIsImZsYXQiLCJnZXRBbGxFdmVudHMiXSwic291cmNlUm9vdCI6IiJ9 \ No newline at end of file diff --git a/slow-calendar/public/clock.png b/slow-calendar/public/clock.png new file mode 100644 index 0000000000000000000000000000000000000000..b3ecbcd505a646c94715259fd0e0778579facf3e GIT binary patch literal 1097 zcmV-P1h)H$P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGxhX4Q_hXIe}@nrx21KvqQK~zXfomERr zRA&^vY;1s`;S~trKtc!u3mOPZSqKT?(abO|Y+^TR6N|t?stF6bk~Bi)RcTCZfZAwc zE#PBepc1>Vv4S-<-B@v_U{r@@VeD|LJobziN z8$SFOx3)r1;QH08MJz1*h2`bde|MwsdN;TEDsB_-czoF042Yx4<;Kv^SJ=P57FMej z+1c61%F04+ZZ0Y+K0rrD2WDsI#5NLv?&~$gA`JpGpkXi=!kIJO$jHb*Nl6JhJ3qt3 z#3bhCe#7I(f8frY8T9q_qqepVsi~=GXlTIGr}H8dACHU)FgUTe=t6aMHS+TEaP8WU z2!+D3PlQ5|*w-mMdGaS5ju!0M^B%5V{XzD&2{1SVx!tez!1<`FtHb*G-(u|Z`Nc4z zf7V;4#&xufWO!=EP%gD^k)SK`jG^Qm#zX0Ro69&UX62rq^OO-er4m3A^sIwVOO-(p? z@|2{OU&VMVZL75qw{K5D;~xbD1$tABOAxc*WFWAmck45pKK(h4A8$i@d%MmKw6(QM zSNr_|gTUUsR!mJzGetmoc{%#~2X+)-WyKG_L?}DjxLmK1o}P|JkA9CH^1*{2!Rd4w z4F4~QyLW$v#gc}Vm9?k437PqJ2N zHe5KIq7-pD59k9c1!vFp==bl6IG7=<-$gSsGcx9La&mC*-Y>GRVj2X<_*%bw`3j1Q zi}l0LMoUYJ6acI3`t=*Qc=20lHk+*sX=(4HwY3#XOUvSySRe)gMRp{?uDp5k77iai zBB?7XDw4~;tgKAVi?iwF%LTFJi + + + + Slow Calendar + + + + +
    + + + \ No newline at end of file diff --git a/slow-calendar/public/info.png b/slow-calendar/public/info.png new file mode 100644 index 0000000000000000000000000000000000000000..3f51295c17f5793ab8f8efda91a2c27b0259cbd6 GIT binary patch literal 1117 zcmV-j1fu(iP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGxhX4Q_hXIe}@nrx21M*2kK~zXfl~qkl zlxGm0UG~pi8oCz_1Qtt?;<6mJ2Z)4_*n>@=;UXMtIM{@1J=w&bAh9;GtqCWUl1Oc0 zsT$pal#tk)@n_XWixSO7pd3W}SQEp-{_jrTdDwT|rK_<|@@Br7dFT1&{h4`9o0~DF zx4>jF(XL$%CG&9& zx$S{iJ{ugCSAhVrFrP6%y;w7%D^AuLGu@Qw`bAo(p zD~^D}hrhx^l_f7P{{ve*p2Bj~;XzL%O7#~n*0{aB9dQQ__Q9sk;0?Jz_E=}Uyu1RN z-b0ye7!mC6>gpO+BX;o%UcNNAzP=vulas%}2673^X0yC+Uk9A$&P~8sd^m!!v7g{S zd2$50_URv7xe|om=kuv8PGMz~&F1*QgTLX}z563%B}>=AGDHuDpYhPpFh6>=_aVP`Z#&-W^+B4|DN{#BhuTLw&CSix+M0py{{z{!*RMBd zYHA8U@9OGO-IB?iOeV?WsiVHWessM+V1z6dSx{+)sZeDZ{I;h7DGCpWT+dRjAO^Xg-}8Rf43J70f+x&gTN@(^pt jgRjm($!y+I4n+R~TVT(HCW$G|00000NkvXXu0mjf+&m!X literal 0 HcmV?d00001 diff --git a/slow-calendar/public/pin.png b/slow-calendar/public/pin.png new file mode 100644 index 0000000000000000000000000000000000000000..4e72af1cee372dfb4d40ad51b13a9352bd51adba GIT binary patch literal 1193 zcmV;a1XlZrP)X1^@s6-qmI800001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGxhX4Q_hXIe}@nrx21U^YbK~zXfeN|gb z(^nWjv=m0$QEs7xfHDFLagUA=h+~onju+g6W0JT)vzA%~I6yflSh{a;b=p>kw#per>bRfp%%fnP!TFQgHQc6nRBCGXVip7XlS7S0h z03IZ%e!}4h#p6U>U0rK|EiEl{_3BULaLmx7M{_haHBH0AKTvaX^O{dnQxkbS-VMYc z4Fp2Su(LBkxN~O-jgS8U9fJppM&)N6rlJbpY+27>{zwDgb6I7)&Iyx>gO*473`9xWP;k<+|6a#@E?cV(^^n3QaM;42P_U)@jzr4Jh zT&`t`L=vZEa`G1Rd-v91Flc64-tl&>sfWaMX(Q-e*3tPOPO(g5trudnYb*v_2! z0)4?*J$?ENS;?iKxw!?5t^zoV)2Ba|SMy^!apDx&?NiY626L=B}AtINcEL^gwC)YazMaoo|P9q6+Sq+FeRKEFJFZ^L15aA?h8J5jS39sLFV za?|Mf^M8>!+d-;s1{V=_;$`5CVXQA{>wRZt?o&=q4*W+(Mxj%_AXUP+aN!#`$|EHM zXQ5Nhig0mpiOR~#;MddB1064i;@Lo|D$>c5rx3t5?e5*bp<_E^VZlii6&0`_InoZD zs$5Dokg~7?qr1Bsf$|BVv9aHvyM22~mc|{>x3;!o6Zx8M=Ga2YqMntrXTJmi%Yg$Q zlDsYWKX&X>*qLzinzL+6%AztJ7#KvMU^0WjNaxQd%3I>ZY#;l|Cz_#N)+bM%38&L3 z3JVKGNy!fRvPMKao+v!q;kBd+X=!Ofr_;)JK91t?dI<49e7_;TPqO`a00000NkvXX Hu0mjfbz4SQ literal 0 HcmV?d00001 diff --git a/slow-calendar/src/AppUI.ts b/slow-calendar/src/AppUI.ts new file mode 100644 index 0000000..9eb83f9 --- /dev/null +++ b/slow-calendar/src/AppUI.ts @@ -0,0 +1,163 @@ +import { EventTarget, Event } from "event-target-shim"; +import { CalendarEvent } from "./CalendarEvent"; +import { MonthGrid } from "./MonthGrid"; +import { Toolbar } from "./Toolbar"; +import { Sidebar } from "./Sidebar"; +import { getEventsForDay } from "./utils"; +import { WeekGrid } from "./WeekGrid"; + +export class AppUI extends EventTarget { + private rootEl: HTMLElement; + + private monthGridEl: HTMLElement; + public monthGrid: MonthGrid; + + private weekGridEl: HTMLElement; + public weekGrid: WeekGrid; + + private toolbarEl: HTMLElement; + private toolbar: Toolbar; + + private sidebarEl: HTMLElement; + private sidebar: Sidebar; + + private _date: Date; + private _events: CalendarEvent[]; + + private mode: string = "month"; + + constructor(el: HTMLElement, date: Date, mode: string, events: CalendarEvent[]) { + super(); + + this.rootEl = el; + this._date = date; + this._events = events; + this.mode = mode; + + this.render(); + } + + render() { + this.rootEl.innerHTML = ''; + + // Create an element for the toolbar. + this.toolbarEl = document.createElement('div'); + this.toolbarEl.id = 'toolbar'; + this.rootEl.appendChild(this.toolbarEl); + + // Init the toolbar component in it. + this.toolbar = new Toolbar(this.toolbarEl, this._date, this.mode); + + this.toolbar.addEventListener('prev', () => { + const newDate = this.mode === "month" + ? new Date(this._date.getFullYear(), this._date.getMonth() - 1, 1) + : new Date(this._date.getFullYear(), this._date.getMonth(), this._date.getDate() - 7); + this.date = newDate; + + // @ts-ignore + this.dispatchEvent(new CustomEvent('date-changed', {detail: this._date})); + }); + + this.toolbar.addEventListener('next', () => { + const newDate = this.mode === "month" + ? new Date(this._date.getFullYear(), this._date.getMonth() + 1, 1) + : new Date(this._date.getFullYear(), this._date.getMonth(), this._date.getDate() + 7); + this.date = newDate; + + // @ts-ignore + this.dispatchEvent(new CustomEvent('date-changed', {detail: this._date})); + }); + + this.toolbar.addEventListener('today', () => { + this.date = new Date(); + + // @ts-ignore + this.dispatchEvent(new CustomEvent('date-changed', {detail: this._date})); + }); + + this.toolbar.addEventListener('month-view', () => { + this.mode = "month"; + this.monthGridEl.style.display = 'grid'; + this.weekGridEl.style.display = 'none'; + + // @ts-ignore + this.dispatchEvent(new CustomEvent('mode-changed', {detail: this.mode})); + }); + + this.toolbar.addEventListener('week-view', () => { + this.mode = "week"; + this.monthGridEl.style.display = 'none'; + this.weekGridEl.style.display = 'grid'; + + // @ts-ignore + this.dispatchEvent(new CustomEvent('mode-changed', {detail: this.mode})); + }); + + // Create an element for the month grid. + this.monthGridEl = document.createElement('div'); + this.monthGridEl.id = 'month-grid'; + this.rootEl.appendChild(this.monthGridEl); + + // Init the month grid component in it. + this.monthGrid = new MonthGrid(this.monthGridEl, this._date, this._events); + + // Create an element for the week grid. + this.weekGridEl = document.createElement('div'); + this.weekGridEl.id = 'week-grid'; + this.rootEl.appendChild(this.weekGridEl); + + // Init the week grid component in it. + this.weekGrid = new WeekGrid(this.weekGridEl, this._date, this._events); + + // Create an element for the sidebar. + this.sidebarEl = document.createElement('div'); + this.sidebarEl.id = 'sidebar'; + this.rootEl.appendChild(this.sidebarEl); + + // Init the sidebar component in it. + this.sidebar = new Sidebar(this.sidebarEl, this._date, this._events); + + // Listen for day-clicked events from the month and week grids to show the full + // list in the sidebar. + // @ts-ignore + this.monthGrid.addEventListener('day-clicked', (e: CustomEvent) => { + const date = e.detail; + const events = getEventsForDay(this._events, date); + this.sidebar.events = events; + }); + // @ts-ignore + this.weekGrid.addEventListener('day-clicked', (e: CustomEvent) => { + const date = e.detail; + const events = getEventsForDay(this._events, date); + this.sidebar.events = events; + }); + + // Start with today. + this.sidebar.events = getEventsForDay(this._events, new Date()); + + // Show/hide the right mode + if (this.mode === "week") { + this.monthGridEl.style.display = 'none'; + this.weekGridEl.style.display = 'grid'; + } else { + this.monthGridEl.style.display = 'grid'; + this.weekGridEl.style.display = 'none'; + } + } + + set date(date: Date) { + console.log("Setting date to", date); + this._date = date; + this.monthGrid.date = date; + this.weekGrid.date = date; + this.toolbar.date = date; + this.sidebar.events = getEventsForDay(this._events, this._date); + } + + set events(events: CalendarEvent[]) { + this._events = events; + this.monthGrid.events = events; + this.weekGrid.events = events; + this.sidebar.events = getEventsForDay(this._events, this._date); + } +} diff --git a/slow-calendar/src/CalendarEvent.ts b/slow-calendar/src/CalendarEvent.ts new file mode 100644 index 0000000..0b66fb5 --- /dev/null +++ b/slow-calendar/src/CalendarEvent.ts @@ -0,0 +1,71 @@ +export class CalendarEvent { + title: string; + id: string; + date: Date; + time: string|undefined; + duration: number|undefined; + repeat: string|undefined; + description: string|undefined; + color: string|undefined; + location: string|undefined; + multiDays: {start: Date, end: Date}|null; + rsvp: boolean = false; + + constructor(title: string, id: string, date: Date) { + this.title = title; + this.id = id; + this.date = date; + } + + asOneLineHTML(indexInGrid: number|undefined = undefined): string { + const time = this.time ? `${this.time}` : ''; + + return ` +
  • +
    ${time} ${this.title}
    +
  • + `; + } + + asMediumLengthHTML(): string { + const time = this.time ? `${this.time}` : ''; + + return ` +
  • +
    ${time}
    +

    ${this.title}

    +

    ${this.description}

    +
  • + `; + } + + asFullHTML(): string { + let when = ""; + + if (!this.multiDays) { + when = this.date.toDateString(); + if (this.time) { + when += `, at ${this.time}`; + } + if (this.repeat) { + when += `, ${this.repeat}`; + } + if (this.duration) { + when += ` (${this.duration} minutes)`; + } + } else { + when = `From ${this.multiDays.start.toDateString()} to ${this.multiDays.end.toDateString()}`; + } + + return ` +
  • +
    +

    ${this.title}

    +

    ${when}

    + ${this.location ? `

    ${this.location}

    ` : ""} +

    ${this.description}

    +
    +
  • + `; + } +} diff --git a/slow-calendar/src/EventPopup.ts b/slow-calendar/src/EventPopup.ts new file mode 100644 index 0000000..1e4b60c --- /dev/null +++ b/slow-calendar/src/EventPopup.ts @@ -0,0 +1,93 @@ +import { CalendarEvent } from "./CalendarEvent"; + +export class EventPopup { + private popupEl: HTMLElement|undefined; + + constructor(private events: CalendarEvent[]) {} + + start() { + if (!this.popupEl) { + this.popupEl = document.createElement("div"); + this.popupEl.className = "popup"; + } + + addEventListener("mousemove", (e: MouseEvent) => { + this.popupEl.classList.remove("visible"); + this.popupEl.remove(); + + const eventEl = (e.target as HTMLElement).closest("#month-grid .event, #week-grid .event") as HTMLElement; + if (!eventEl) { + return; + } + + const id = eventEl.id; + + if (!id || !id.startsWith("id-")) { + return; + } + + let eventId = id.replace("id-", ""); + + const event = this.events.find(event => event.id === eventId); + if (!event) { + console.log("No event found for id", eventId); + return; + } + + const eventIndexInGrid = parseInt(eventEl.dataset.indexInGrid!); + + this.popupEl.style.setProperty("--event-color", event.color); + this.popupEl.classList.toggle("visible", true); + this.popupEl.classList.toggle("unconfirmed", !event.rsvp); + + let when = ""; + + if (!event.multiDays) { + when = event.date.toDateString(); + if (event.time) { + when += `, at ${event.time}`; + } + if (event.repeat) { + when += `, ${event.repeat}`; + } + if (event.duration) { + when += ` (${event.duration} minutes)`; + } + } else { + when = `From ${event.multiDays.start.toDateString()} to ${event.multiDays.end.toDateString()}`; + } + + this.popupEl.innerHTML = ` +

    ${event.title}

    +

    ${when}

    + ${event.location ? `

    ${event.location}

    ` : ""} +

    ${event.description}

    + `; + + document.body.appendChild(this.popupEl); + + // Get the coordinates of the event element. + const rect = eventEl.getBoundingClientRect(); + const top = rect.top; + const right = rect.right; + const left = rect.left; + const width = rect.width; + + if (eventIndexInGrid >= 28) { + // The event is in the last 2 rows. Show the popup above it. + this.popupEl.style.top = `${top - this.popupEl.clientHeight}px`; + } else { + this.popupEl.style.top = `${top}px`; + } + + if (eventIndexInGrid === 6 || eventIndexInGrid === 13 || eventIndexInGrid === 20 || eventIndexInGrid === 27 || eventIndexInGrid === 34) { + // The event is last in a row, so we want to show the popup to the left of it. + this.popupEl.style.left = `${left - width}px`; + this.popupEl.classList.toggle("left", true); + } else { + this.popupEl.style.left = `${right}px`; + this.popupEl.classList.toggle("left", false); + } + }); + } +} diff --git a/slow-calendar/src/MonthGrid.ts b/slow-calendar/src/MonthGrid.ts new file mode 100644 index 0000000..e118a8a --- /dev/null +++ b/slow-calendar/src/MonthGrid.ts @@ -0,0 +1,117 @@ +import { EventTarget, Event } from "event-target-shim"; +import { CalendarEvent } from "./CalendarEvent"; +import { getEventsForDay } from "./utils"; + +const DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + +export class MonthGrid extends EventTarget { + private rootEl: HTMLElement; + private _date: Date = new Date(); + private _events: CalendarEvent[]; + + constructor(private el: HTMLElement, date: Date, events: CalendarEvent[]) { + super(); + + this.rootEl = el; + this._date = date; + this._events = events; + + this.render(); + } + + render() { + this.rootEl.innerHTML = ''; + + const month = this._date.getMonth(); + const year = this._date.getFullYear(); + + const firstDay = new Date(year, month, 1); + const lastDay = new Date(year, month + 1, 0); + + const firstWeekday = firstDay.getDay(); + const lastWeekday = lastDay.getDay(); + const daysInMonth = lastDay.getDate(); + const daysInLastMonth = new Date(year, month, 0).getDate(); + const days: {date: Date, html: string}[] = []; + + let indexInGrid = 0; + + // Days from last month + for (let i = daysInLastMonth - firstWeekday + 1; i <= daysInLastMonth; i++) { + const date = new Date(year, month - 1, i); + days.push({date, html: this.renderDay(date, i, indexInGrid, 'prev-month')}); + indexInGrid++; + } + + // Days from this month + for (let i = 1; i <= daysInMonth; i++) { + const date = new Date(year, month, i); + days.push({date, html: this.renderDay(date, i, indexInGrid)}); + indexInGrid++; + } + + // Days from next month + for (let i = 1; i <= 7 - lastWeekday - 1; i++) { + const date = new Date(year, month + 1, i); + days.push({date, html: this.renderDay(date, i, indexInGrid, 'next-month')}); + indexInGrid++; + } + + for (const {date, html} of days) { + this.rootEl.insertAdjacentHTML('beforeend', html); + const dayEl = this.rootEl.lastElementChild as HTMLElement; + + dayEl.addEventListener('click', (e: MouseEvent) => { + // @ts-ignore + this.dispatchEvent(new CustomEvent('day-clicked', {detail: date})); + }); + } + + this.updateNowMarker(); + } + + renderDay(date: Date, dayNumber: number, indexInGrid: number, className: string = ''): string { + const events = getEventsForDay(this._events, date); + const isToday = date.toDateString() === new Date().toDateString(); + + return ` +
    +
    + ${DAYS[date.getDay()]} + ${dayNumber} +
    +
      + ${events.map(event => event.asOneLineHTML(indexInGrid)).join('')} +
    +
    + `; + } + + updateNowMarker() { + const now = new Date(); + const time = now.getHours() * 100 + now.getMinutes(); + const ratio = time * 100 / 2400; + + // Forcing a sync reflow here by querying the offsetHeight of the day cell. + // Could just set the % value directly instead. + const dayEl = this.rootEl.querySelector('.day.today') as HTMLElement; + if (dayEl) { + const pxHeight = dayEl.offsetHeight; + const markerHeight = pxHeight * ratio / 100; + + this.rootEl.style.setProperty('--now-marker', `${markerHeight}px`); + } + + setTimeout(() => this.updateNowMarker(), 1000); + } + + set date(date: Date) { + this._date = date; + this.render(); + } + + set events(events: CalendarEvent[]) { + this._events = events; + this.render(); + } +} diff --git a/slow-calendar/src/Sidebar.ts b/slow-calendar/src/Sidebar.ts new file mode 100644 index 0000000..b33a5e6 --- /dev/null +++ b/slow-calendar/src/Sidebar.ts @@ -0,0 +1,41 @@ +import { CalendarEvent } from "./CalendarEvent"; + +export class Sidebar { + private rootEl: HTMLElement; + private _events: CalendarEvent[] = []; + private _date: Date = new Date(); + + constructor(private el: HTMLElement, date: Date, events: CalendarEvent[]) { + this.rootEl = el; + this._date = date; + this._events = events; + + this.render(); + } + + render() { + this.rootEl.innerHTML = ` +

    Click a day to view events

    + `; + + if (!this._events.length) { + return; + } + + this.rootEl.innerHTML = ''; + + const ul = document.createElement('ul'); + ul.className = 'events'; + this.rootEl.appendChild(ul); + + for (const event of this._events) { + ul.innerHTML += event.asFullHTML(); + } + } + + set events(events: CalendarEvent[]) { + this._events = events; + this.render(); + } +} +`` \ No newline at end of file diff --git a/slow-calendar/src/Store.ts b/slow-calendar/src/Store.ts new file mode 100644 index 0000000..155a1cd --- /dev/null +++ b/slow-calendar/src/Store.ts @@ -0,0 +1,24 @@ +export class Store { + async getStoredPrefs(): Promise<{mode: string, initDate: Date|undefined}> { + // Fake some random time (up to 250ms) to simulate an API call. + await new Promise(resolve => setTimeout(resolve, Math.random() * 250)); + + const mode = localStorage.getItem('slow-cal-mode'); + const initDate = localStorage.getItem('slow-cal-initDate'); + + return { + mode, + initDate: initDate ? new Date(initDate) : undefined + }; + } + + set mode(mode: string) { + console.log("Storing mode prefs"); + localStorage.setItem('slow-cal-mode', mode); + } + + set initDate(date: Date) { + console.log("Storing date prefs"); + localStorage.setItem('slow-cal-initDate', date.toISOString()); + } +} diff --git a/slow-calendar/src/Toolbar.ts b/slow-calendar/src/Toolbar.ts new file mode 100644 index 0000000..191f134 --- /dev/null +++ b/slow-calendar/src/Toolbar.ts @@ -0,0 +1,73 @@ +import { EventTarget, Event } from "event-target-shim"; + +const MONTHS = [ + 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', + 'September', 'October', 'November','December' +]; + +export class Toolbar extends EventTarget { + private rootEl: HTMLElement; + private _date: Date; + private selectedMode: string = "month"; + + constructor(private el: HTMLElement, date: Date, mode: string) { + super(); + + this.rootEl = el; + this._date = date; + this.selectedMode = mode; + + this.render(); + } + + formatMonthYear() { + const month = this._date.getMonth(); + const year = this._date.getFullYear(); + return `${MONTHS[month]} ${year}`; + } + + render() { + this.rootEl.innerHTML = ` + + + + ${this.formatMonthYear()} + + + + + `; + + this.rootEl.querySelector('#prev-month').addEventListener('click', () => { + console.log(`Prev ${this.selectedMode} clicked`); + this.dispatchEvent(new Event('prev')); + }); + + this.rootEl.querySelector('#next-month').addEventListener('click', () => { + console.log(`Next ${this.selectedMode} clicked`); + this.dispatchEvent(new Event('next')); + }); + + this.rootEl.querySelector('#today').addEventListener('click', () => { + console.log("Today clicked"); + this.dispatchEvent(new Event('today')); + }); + + this.rootEl.querySelector('#month-view').addEventListener('click', () => { + console.log("Month view clicked"); + this.dispatchEvent(new Event('month-view')); + this.selectedMode = "month"; + }); + + this.rootEl.querySelector('#week-view').addEventListener('click', () => { + console.log("Week view clicked"); + this.dispatchEvent(new Event('week-view')); + this.selectedMode = "week"; + }); + } + + set date(date: Date) { + this._date = date; + this.render(); + } +} diff --git a/slow-calendar/src/WeekGrid.ts b/slow-calendar/src/WeekGrid.ts new file mode 100644 index 0000000..9838c83 --- /dev/null +++ b/slow-calendar/src/WeekGrid.ts @@ -0,0 +1,93 @@ +import { EventTarget, Event } from "event-target-shim"; +import { CalendarEvent } from "./CalendarEvent"; +import { getEventsForDay } from "./utils"; + +const DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + +export class WeekGrid extends EventTarget { + private rootEl: HTMLElement; + private _date: Date = new Date(); + private _events: CalendarEvent[]; + + constructor(private el: HTMLElement, date: Date, events: CalendarEvent[]) { + super(); + + this.rootEl = el; + this._date = date; + this._events = events; + + this.render(); + } + + render() { + this.rootEl.innerHTML = ''; + + // Find the dates that make the week around this._date. + const month = this._date.getMonth(); + const year = this._date.getFullYear(); + const date = this._date.getDate(); + const day = this._date.getDay(); + + const firstDay = new Date(year, month, date - day); + + // Iterate over the dates and render the days. + const days: {date: Date, html: string}[] = []; + for (let i = 0; i < 7; i++) { + const date = new Date(year, month, firstDay.getDate() + i); + this.rootEl.insertAdjacentHTML('beforeend', this.renderDay(date, date.getDate())); + + const dayEl = this.rootEl.lastElementChild as HTMLElement; + dayEl.addEventListener('click', (e: MouseEvent) => { + // @ts-ignore + this.dispatchEvent(new CustomEvent('day-clicked', {detail: date})); + }); + } + + this.updateNowMarker(); + } + + renderDay(date: Date, dayNumber: number, className: string = ''): string { + const events = getEventsForDay(this._events, date); + const isToday = date.toDateString() === new Date().toDateString(); + + return ` +
    +
    + ${DAYS[date.getDay()]} + ${dayNumber} +
    +
      + ${events.map(event => event.asMediumLengthHTML()).join('')} +
    +
    + `; + } + + updateNowMarker() { + const now = new Date(); + const time = now.getHours() * 100 + now.getMinutes(); + const ratio = time * 100 / 2400; + + // Forcing a sync reflow here by querying the offsetHeight of the day cell. + // Could just set the % value directly instead. + const dayEl = this.rootEl.querySelector('.day.today') as HTMLElement; + if (dayEl) { + const pxHeight = dayEl.offsetHeight; + const markerHeight = pxHeight * ratio / 100; + + this.rootEl.style.setProperty('--now-marker', `${markerHeight}px`); + } + + setTimeout(() => this.updateNowMarker(), 1000); + } + + set date(date: Date) { + this._date = date; + this.render(); + } + + set events(events: CalendarEvent[]) { + this._events = events; + this.render(); + } +} diff --git a/slow-calendar/src/app.ts b/slow-calendar/src/app.ts new file mode 100644 index 0000000..8ced173 --- /dev/null +++ b/slow-calendar/src/app.ts @@ -0,0 +1,35 @@ +import { AppUI } from "./AppUI"; +import { getAllEvents } from "./events-factory"; +import { EventPopup } from "./EventPopup"; +import { Store } from "./Store"; + +addEventListener("DOMContentLoaded", async () => { + const store = new Store(); + const prefs = await store.getStoredPrefs(); + + // This is what the calendar will be centered around on load. + const initDate = prefs.initDate || new Date(); + const initMode = prefs.mode || "month"; + + const appEl = document.getElementById('app'); + const appUI = new AppUI(appEl!, initDate, initMode, []); + + const events = await getAllEvents() + + console.log("Refreshing calendar with events"); + appUI.events = events; + + console.log("Initializing the popup util"); + const popup = new EventPopup(events); + popup.start(); + + // @ts-ignore + appUI.addEventListener("mode-changed", (e: CustomEvent) => { + store.mode = e.detail; + }); + + // @ts-ignore + appUI.addEventListener("date-changed", (e: CustomEvent) => { + store.initDate = e.detail; + }); +}); diff --git a/slow-calendar/src/events-factory.ts b/slow-calendar/src/events-factory.ts new file mode 100644 index 0000000..24f2b9f --- /dev/null +++ b/slow-calendar/src/events-factory.ts @@ -0,0 +1,99 @@ +import { CalendarEvent } from "./CalendarEvent"; + +async function fetchData() { + // Simulate a slower API endpoint call. + console.log("Fetching calendar data ..."); + await new Promise(resolve => setTimeout(resolve, Math.random() * 500)); + const response = await fetch('./data.json'); + return await response.json(); +} + +function createOneOrMultipleEventsFromData(eventData: any): CalendarEvent[] { + const dates: Date[] = [new Date(eventData.startDate)]; + let multiDays: {start: Date, end: Date}|null = null; + + if (eventData.repeat) { + const startDate = new Date(eventData.startDate); + + // If this event is repeated, it must have an end date. + const endDate = eventData.endDate + // Either the end date is specified. + ? new Date(eventData.endDate) + // Or it's 5 year after the start date. + : new Date(startDate.getTime() + 5 * 365 * 24 * 60 * 60 * 1000); + + if (eventData.repeat === "daily") { + console.log("Expanding daily event ..."); + const days = (endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24); + for (let i = 1; i <= days; i++) { + const date = new Date(startDate.getTime() + i * 24 * 60 * 60 * 1000); + // If date is on a week end, skip it. + if (date.getDay() === 0 || date.getDay() === 6) { + continue; + } + + dates.push(date); + } + } else if (eventData.repeat === "weekly") { + console.log("Expanding weekly event ..."); + const weeks = (endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24 * 7); + for (let i = 1; i <= weeks; i++) { + const date = new Date(startDate.getTime() + i * 7 * 24 * 60 * 60 * 1000); + dates.push(date); + } + } else if (eventData.repeat === "monthly") { + console.log("Expanding monthly event ..."); + const months = (endDate.getFullYear() - startDate.getFullYear()) * 12 + (endDate.getMonth() - startDate.getMonth()); + for (let i = 1; i <= months; i++) { + const date = new Date(startDate.getTime()); + date.setMonth(date.getMonth() + i); + dates.push(date); + } + } else if (eventData.repeat === "yearly") { + console.log("Expanding yearly event ..."); + const years = endDate.getFullYear() - startDate.getFullYear(); + for (let i = 1; i <= years; i++) { + const date = new Date(startDate.getTime()); + date.setFullYear(date.getFullYear() + i); + dates.push(date); + } + } + } else if (eventData.endDate) { + // If this event has a start and end date, but isn't repeated. + const startDate = new Date(eventData.startDate); + const endDate = new Date(eventData.endDate); + const days = (endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24); + for (let i = 1; i <= days; i++) { + const date = new Date(startDate.getTime() + i * 24 * 60 * 60 * 1000); + dates.push(date); + } + multiDays = {start: startDate, end: endDate}; + } + + + return dates.map((date, index) => { + const id = eventData.id + (index > 0 ? `-${index}` : ""); + const event = new CalendarEvent(eventData.title, id, date); + + event.multiDays = multiDays; + + event.color = eventData.color; + event.time = eventData.startTime; + event.duration = eventData.duration; + event.repeat = eventData.repeat; + event.location = eventData.location; + event.description = eventData.description; + event.rsvp = eventData.rsvp; + + return event; + }); +} + +export async function getAllEvents(): Promise { + const data = await fetchData(); + + console.log("Processing events ..."); + return data.events.map((event: any) => { + return createOneOrMultipleEventsFromData(event); + }).flat(); +} diff --git a/slow-calendar/src/utils.ts b/slow-calendar/src/utils.ts new file mode 100644 index 0000000..7718807 --- /dev/null +++ b/slow-calendar/src/utils.ts @@ -0,0 +1,33 @@ +import { CalendarEvent } from "./CalendarEvent"; + +export function getEventsForDay(events: CalendarEvent[], date: Date): CalendarEvent[] { + return events.filter(event => { + return event.date.getFullYear() === date.getFullYear() && + event.date.getMonth() === date.getMonth() && + event.date.getDate() === date.getDate(); + }).sort((a, b) => { + // If one has no time property, it should be first. + // If both have no time, no sorting is needed. + if (!a.time && !!b.time) { + return -1; + } else if (!!a.time && !b.time) { + return 1; + } else if (!a.time && !b.time) { + return 0; + } + + // Sort the events by time. Times are strings in 24 + // formats, so just remove the leading 0, if any, and + // the colon, and compare the numbers. + const aTime = parseInt(a.time.replace(/^0/, '').replace(':', '')); + const bTime = parseInt(b.time.replace(/^0/, '').replace(':', '')); + return aTime - bTime; + }).sort((a, b) => { + // Sort the events that are multi-days first. + if (!!a.multiDays && !b.multiDays) { + return -1; + } else if (!a.multiDays && !!b.multiDays) { + return 1; + } + }); +} diff --git a/slow-calendar/tsconfig.json b/slow-calendar/tsconfig.json new file mode 100644 index 0000000..658c4c2 --- /dev/null +++ b/slow-calendar/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "outDir": "./dist/", + "sourceMap": true, + "noImplicitAny": true, + "module": "es6", + "target": "es6", + "jsx": "react", + "allowJs": true, + "moduleResolution": "node" + } +} \ No newline at end of file diff --git a/slow-calendar/webpack.config.js b/slow-calendar/webpack.config.js new file mode 100644 index 0000000..93adeb2 --- /dev/null +++ b/slow-calendar/webpack.config.js @@ -0,0 +1,22 @@ +const path = require('path'); + +module.exports = { + entry: './src/app.ts', + devtool: 'inline-source-map', + module: { + rules: [ + { + test: /\.tsx?$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + ], + }, + resolve: { + extensions: ['.tsx', '.ts', '.js'], + }, + output: { + filename: 'bundle.js', + path: path.resolve(__dirname, 'public'), + }, +};