@nlabs/lex 1.59.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/.storybook/main.ts +3 -47
  2. package/README.md +13 -19
  3. package/__mocks__/build.js +3 -3
  4. package/config.json +3 -1
  5. package/examples/lex.config.js +3 -7
  6. package/lib/LexConfig.d.ts +2 -6
  7. package/lib/LexConfig.js +2 -2
  8. package/lib/commands/ai/ai.js +3 -3
  9. package/lib/commands/build/build.d.ts +5 -3
  10. package/lib/commands/build/build.js +66 -156
  11. package/lib/commands/config/config.js +9 -7
  12. package/lib/commands/dev/dev.d.ts +0 -2
  13. package/lib/commands/dev/dev.js +24 -115
  14. package/lib/commands/init/init.js +4 -9
  15. package/lib/commands/migrate/migrate.js +2 -2
  16. package/lib/commands/serverless-dev/serverless-dev.js +2 -2
  17. package/lib/commands/versions/versions.d.ts +1 -1
  18. package/lib/commands/versions/versions.js +4 -4
  19. package/lib/lex.js +10 -11
  20. package/lib/types.d.ts +1 -1
  21. package/lib/types.js +1 -1
  22. package/lib/utils/app.d.ts +0 -2
  23. package/lib/utils/app.js +2 -29
  24. package/lib/utils/{webpack/LexSvgSpritemapPlugin.d.ts → assets/LexSvgSpritemap.d.ts} +6 -8
  25. package/lib/utils/assets/LexSvgSpritemap.js +219 -0
  26. package/lib/utils/file.d.ts +0 -4
  27. package/lib/utils/file.js +4 -100
  28. package/lib/utils/staticSite.d.ts +15 -0
  29. package/lib/utils/staticSite.js +80 -0
  30. package/lib/utils/vite/assets.d.ts +19 -0
  31. package/lib/utils/vite/assets.js +249 -0
  32. package/lib/utils/vite/config.d.ts +12 -0
  33. package/lib/utils/vite/config.js +279 -0
  34. package/package.json +27 -45
  35. package/postcss.config.js +1 -2
  36. package/tsconfig.lint.json +0 -1
  37. package/tsconfig.test.json +0 -1
  38. package/lib/utils/webpack/LexSvgSpritemapPlugin.js +0 -255
  39. package/scripts/test-webpack.js +0 -453
  40. package/webpack.config.d.ts +0 -2
  41. package/webpack.config.js +0 -960
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nlabs/lex",
3
- "version": "1.59.4",
3
+ "version": "2.0.0",
4
4
  "description": "Lex",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -30,7 +30,7 @@
30
30
  "arkhamjs",
31
31
  "lex",
32
32
  "nitrogenlabs",
33
- "webpack"
33
+ "vite"
34
34
  ],
35
35
  "author": {
36
36
  "name": "Giraldo Rosales",
@@ -72,7 +72,6 @@
72
72
  "test:commands": "NODE_ENV=test && npm run test:cli && npm run test:integration",
73
73
  "test:coverage": "NODE_ENV=test && npx vitest run --coverage",
74
74
  "test:coverage:upload": "codecov",
75
- "test:webpack": "node scripts/test-webpack.js",
76
75
  "type-check": "tsc --noEmit --project tsconfig.lint.json",
77
76
  "type-check:build": "tsc --noEmit --project tsconfig.build.json",
78
77
  "type-check:test": "tsc --noEmit --project tsconfig.test.json",
@@ -85,19 +84,16 @@
85
84
  "watch": "NODE_ENV=development rm -rf lib && npx swc src --out-dir ./lib --source-maps inline --strip-leading-paths --extensions .ts,.tsx --ignore '**/*.test.ts' --ignore '**/*.test.tsx' --ignore '**/*.spec.ts' --ignore '**/*.spec.tsx' --ignore '**/*.integration.ts' --ignore '**/*.integration.tsx' --ignore '**/*.e2e.ts' --ignore '**/*.e2e.tsx' --watch"
86
85
  },
87
86
  "dependencies": {
88
- "@mdx-js/loader": "^3.1.1",
89
- "@nlabs/webpack-plugin-static-site": "*",
90
87
  "@playwright/test": "^1.62.1",
88
+ "@rollup/plugin-inject": "^5.0.5",
91
89
  "@storybook/addon-docs": "^10.5.8",
92
90
  "@storybook/addon-links": "^10.5.8",
93
- "@storybook/addon-styling-webpack": "^3.0.2",
94
91
  "@storybook/addon-themes": "^10.5.8",
95
- "@storybook/cli": "^10.5.8",
96
92
  "@storybook/react": "^10.5.8",
97
- "@storybook/react-webpack5": "^10.5.8",
93
+ "@storybook/react-vite": "^10.5.8",
98
94
  "@swc/cli": "^0.8.1",
99
- "@swc/core": "^1.15.47",
100
- "@swc/react-compiler": "^1.15.47",
95
+ "@swc/core": "^1.16.0",
96
+ "@swc/react-compiler": "^1.16.0",
101
97
  "@tailwindcss/forms": "^0.5.11",
102
98
  "@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
103
99
  "@tailwindcss/postcss": "4.3.3",
@@ -112,41 +108,31 @@
112
108
  "chalk": "^6.0.0",
113
109
  "commander": "^15.0.0",
114
110
  "compare-versions": "^6.1.1",
115
- "compression-webpack-plugin": "^12.0.0",
116
- "copy-webpack-plugin": "^14.0.0",
117
111
  "core-js": "^3.50.0",
118
- "crypto-js": "^4.2.0",
119
- "css-loader": "^7.1.4",
120
- "css-minimizer-webpack-plugin": "^8.0.0",
121
- "cssnano": "^8.0.5",
122
- "dotenv-webpack": "^9.0.0",
123
- "download-npm-package": "^3.1.12",
112
+ "cssnano": "^8.0.6",
124
113
  "esbuild": "^0.28.2",
125
114
  "eslint": "^10.8.1",
126
- "eslint-config-styleguidejs": "^5.0.4",
115
+ "eslint-config-styleguidejs": "^5.0.7",
127
116
  "execa": "10.0.1",
128
117
  "expect": "^30.4.1",
129
118
  "express": "^5.2.1",
130
- "favicons-webpack-plugin": "^6.0.1",
119
+ "favicons": "^7.3.1",
131
120
  "find-file-up": "^2.0.1",
132
121
  "glob": "^13.0.6",
133
122
  "global": "^4.4.0",
134
123
  "graphql": "^17.0.2",
135
124
  "graphql-tag": "^2.12.7",
136
- "html-loader": "^5.1.0",
137
- "html-webpack-plugin": "^5.6.8",
138
125
  "https-browserify": "^1.0.0",
139
- "image-minimizer-webpack-plugin": "^5.0.0",
140
126
  "jsdom": "^30.0.1",
141
127
  "latest-version": "9.0.0",
142
128
  "lodash": "^4.18.1",
143
129
  "luxon": "^3.7.2",
144
130
  "math-expression-evaluator": "^2.0.7",
145
- "mini-css-extract-plugin": "^2.10.2",
146
131
  "npm-check-updates": "^23.0.2",
147
132
  "openai": "^7.4.0",
148
133
  "ora": "9.4.1",
149
134
  "os-browserify": "^0.3.0",
135
+ "pacote": "^21.5.1",
150
136
  "path-browserify": "^1.0.1",
151
137
  "postcss": "^8.5.26",
152
138
  "postcss-browser-reporter": "^0.7.0",
@@ -155,11 +141,10 @@
155
141
  "postcss-flexbugs-fixes": "^5.0.2",
156
142
  "postcss-hash": "^3.0.0",
157
143
  "postcss-import": "16.2.0",
158
- "postcss-loader": "^8.2.1",
159
144
  "postcss-nesting": "^14.0.1",
160
- "postcss-preset-env": "^11.3.2",
145
+ "postcss-preset-env": "^11.4.0",
161
146
  "postcss-simple-vars": "^7.0.1",
162
- "postcss-svgo": "8.0.4",
147
+ "postcss-svgo": "8.0.5",
163
148
  "postcss-url": "10.1.4",
164
149
  "postcss-value-parser": "^4.2.0",
165
150
  "process": "^0.11.10",
@@ -171,52 +156,49 @@
171
156
  "rimraf": "^6.1.3",
172
157
  "semver": "^7.8.5",
173
158
  "sharp": "^0.35.3",
174
- "source-map-loader": "^5.0.0",
175
159
  "storybook": "^10.5.8",
176
160
  "stream-browserify": "^3.0.0",
177
161
  "stream-http": "^3.2.0",
178
- "style-loader": "^4.0.0",
179
162
  "svgo": "4.0.2",
180
- "swc-loader": "^0.2.7",
181
163
  "tailwindcss": "^4.3.3",
182
164
  "ts-node": "^10.9.2",
183
- "tsconfig-paths-webpack-plugin": "^4.2.0",
184
165
  "typescript": "^7.0.2",
185
166
  "util": "^0.12.5",
167
+ "vite": "^8.2.1",
168
+ "vite-plugin-node-polyfills": "^0.28.0",
186
169
  "vitest": "^4.1.10",
187
170
  "vm-browserify": "^1.1.2",
188
- "webpack": "5.109.2",
189
- "webpack-bundle-analyzer": "^5.3.1",
190
- "webpack-cli": "^7.2.2",
191
- "webpack-merge": "^6.0.1",
192
- "webpack-plugin-serve": "^1.6.0",
193
171
  "ws": "^8.21.3"
194
172
  },
195
173
  "devDependencies": {
196
174
  "@types/express": "^5.0.6",
197
175
  "@types/luxon": "^3.7.4",
198
176
  "@types/node": "^26.2.0",
199
- "@types/ora": "^3.2.0",
200
177
  "@types/react": "^19.2.18",
201
- "@types/webpack": "^5.28.5"
178
+ "@types/semver": "^7.7.1"
202
179
  },
203
180
  "overrides": {
204
181
  "@babel/core": "^7.29.7",
205
182
  "@xhmikosr/decompress": "^11.1.3",
206
- "brace-expansion": "^5.0.7",
183
+ "body-parser": "^2.3.0",
184
+ "brace-expansion": "^5.0.9",
207
185
  "cross-spawn": "^7.0.6",
186
+ "encoding-sniffer": "^1.0.2",
208
187
  "fast-xml-parser": "^5.8.0",
188
+ "fast-uri": "^4.1.2",
189
+ "favicons": {
190
+ "sharp": "^0.35.3"
191
+ },
192
+ "glob": "^13.0.6",
209
193
  "got": "^14.6.6",
210
194
  "http-proxy-middleware": "^3.0.7",
211
- "js-yaml": "^4.3.0",
195
+ "js-yaml": "^5.3.0",
196
+ "pacote": "^21.5.1",
212
197
  "piscina": "^4.9.3",
213
198
  "qs": "^6.15.3",
199
+ "rimraf": "^6.1.3",
214
200
  "semver-regex": "^4.0.5",
215
- "tmp": "^0.2.7",
216
- "undici": "^7.28.0",
217
- "webpack-plugin-serve": {
218
- "ws": "^7.5.11"
219
- }
201
+ "undici": "^8.10.0"
220
202
  },
221
203
  "gitHead": "0f5fb22fc0f0ab1abab5adf62afed24c7c87e4a8"
222
204
  }
package/postcss.config.js CHANGED
@@ -16,14 +16,13 @@ import postcssPresetEnv from 'postcss-preset-env';
16
16
  import postcssSimpleVars from 'postcss-simple-vars';
17
17
  import postcssSvgo from 'postcss-svgo';
18
18
  import postcssUrl from 'postcss-url';
19
- import {default as webpack} from 'webpack';
20
19
 
21
20
  import postcssFor from './lib/utils/postcss/postcss-for.js';
22
21
  import postcssPercentage from './lib/utils/postcss/postcss-percentage.js';
23
22
 
24
23
  const config = {
25
24
  plugins: [
26
- postcssImport({addDependencyTo: webpack}),
25
+ postcssImport(),
27
26
  postcssUrl(),
28
27
  postcssFor(),
29
28
  postcssPercentage({
@@ -3,7 +3,6 @@
3
3
  "compilerOptions": {
4
4
  "allowJs": true,
5
5
  "allowSyntheticDefaultImports": true,
6
- "baseUrl": "./src",
7
6
  "declaration": true,
8
7
  "emitDeclarationOnly": true,
9
8
  "esModuleInterop": true,
@@ -2,7 +2,6 @@
2
2
  "compilerOptions": {
3
3
  "allowJs": true,
4
4
  "allowSyntheticDefaultImports": true,
5
- "baseUrl": "./src",
6
5
  "declaration": true,
7
6
  "emitDeclarationOnly": true,
8
7
  "esModuleInterop": true,
@@ -1,255 +0,0 @@
1
- function _define_property(obj, key, value) {
2
- if (key in obj) {
3
- Object.defineProperty(obj, key, {
4
- value: value,
5
- enumerable: true,
6
- configurable: true,
7
- writable: true
8
- });
9
- } else obj[key] = value;
10
- return obj;
11
- }
12
- /**
13
- * Copyright (c) 2018-Present, Nitrogen Labs, Inc.
14
- * Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
15
- */ import { readFileSync } from 'fs';
16
- import { sync as globSync } from 'glob';
17
- import { basename as pathBasename, dirname as pathDirname, extname as pathExtname, resolve as pathResolve } from 'path';
18
- import { optimize } from 'svgo';
19
- import webpack from 'webpack';
20
- const DEFAULT_FILENAME = 'icons/icons.svg';
21
- const PLUGIN_NAME = 'LexSvgSpritemapPlugin';
22
- const ROOT_EXCLUDED_ATTRIBUTES = new Set([
23
- 'height',
24
- 'id',
25
- 'version',
26
- 'viewBox',
27
- 'width',
28
- 'xmlns'
29
- ]);
30
- const escapeAttribute = (value)=>{
31
- return value.replaceAll('&', '&amp;').replaceAll('"', '&quot;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
32
- };
33
- const normalizeAssetFilename = (filename)=>{
34
- return filename.replace(/^[./]+/, '');
35
- };
36
- const parseAttributes = (input)=>{
37
- const attributes = {};
38
- const attributeRegex = /([:@\w-]+)\s*=\s*("([^"]*)"|'([^']*)')/g;
39
- let match = attributeRegex.exec(input);
40
- while(match){
41
- attributes[match[1]] = match[3] ?? match[4] ?? '';
42
- match = attributeRegex.exec(input);
43
- }
44
- return attributes;
45
- };
46
- const parseSvg = (source)=>{
47
- const svgMatch = source.replace(/<\?xml[\s\S]*?\?>/ig, '').replace(/<!doctype[\s\S]*?>/ig, '').match(/<svg\b([^>]*)>([\s\S]*?)<\/svg>/i);
48
- if (!svgMatch) {
49
- return null;
50
- }
51
- return {
52
- attributes: parseAttributes(svgMatch[1] || ''),
53
- content: svgMatch[2]?.trim() || ''
54
- };
55
- };
56
- const buildAttributeString = (attributes)=>{
57
- return Object.entries(attributes).map(([name, value])=>`${name}="${escapeAttribute(value)}"`).join(' ');
58
- };
59
- const sanitizeIdentifier = (value)=>{
60
- const sanitizedValue = value.trim().replaceAll(/\s+/g, '-').replaceAll(/[^A-Za-z0-9_-]/g, '-').replaceAll(/-{2,}/g, '-').replaceAll(/^[-_]+|[-_]+$/g, '');
61
- const safeValue = sanitizedValue || 'icon';
62
- return /^[A-Za-z_]/.test(safeValue) ? safeValue : `icon-${safeValue}`;
63
- };
64
- const getPrefix = (filePath, prefix)=>{
65
- if (prefix === false) {
66
- return '';
67
- }
68
- if (typeof prefix === 'function') {
69
- return prefix(filePath);
70
- }
71
- return prefix || '';
72
- };
73
- const optimizeSvg = (content, enabled)=>{
74
- if (!enabled) {
75
- return content;
76
- }
77
- return optimize(content, {
78
- multipass: true,
79
- plugins: [
80
- {
81
- name: 'preset-default',
82
- params: {
83
- overrides: {
84
- cleanupIds: false
85
- }
86
- }
87
- }
88
- ]
89
- }).data;
90
- };
91
- const createSpriteSymbol = (filePath, usedIdentifiers, prefix, warnings)=>{
92
- const source = readFileSync(filePath, 'utf8');
93
- const parsedSvg = parseSvg(source);
94
- if (!parsedSvg) {
95
- warnings.push(new webpack.WebpackError(`Invalid SVG icon: ${filePath}`));
96
- return null;
97
- }
98
- if (!parsedSvg.content) {
99
- warnings.push(new webpack.WebpackError(`SVG icon is empty: ${filePath}`));
100
- return null;
101
- }
102
- const rawIdentifier = `${getPrefix(filePath, prefix)}${pathBasename(filePath, pathExtname(filePath))}`;
103
- const baseIdentifier = sanitizeIdentifier(rawIdentifier);
104
- let identifier = baseIdentifier;
105
- let duplicateIndex = 1;
106
- while(usedIdentifiers.has(identifier)){
107
- duplicateIndex += 1;
108
- identifier = `${baseIdentifier}-${duplicateIndex}`;
109
- }
110
- if (identifier !== baseIdentifier) {
111
- warnings.push(new webpack.WebpackError(`Duplicate SVG icon id "${baseIdentifier}" detected, using "${identifier}" for ${filePath}`));
112
- }
113
- usedIdentifiers.add(identifier);
114
- const namespaceAttributes = Object.entries(parsedSvg.attributes).reduce((result, [name, value])=>{
115
- if (name.toLowerCase().startsWith('xmlns:')) {
116
- result[name] = value;
117
- }
118
- return result;
119
- }, {});
120
- const symbolAttributes = Object.entries(parsedSvg.attributes).reduce((result, [name, value])=>{
121
- if (ROOT_EXCLUDED_ATTRIBUTES.has(name)) {
122
- return result;
123
- }
124
- if (name.toLowerCase().startsWith('xmlns:')) {
125
- return result;
126
- }
127
- result[name] = value;
128
- return result;
129
- }, {
130
- id: identifier
131
- });
132
- if (parsedSvg.attributes.viewBox) {
133
- symbolAttributes.viewBox = parsedSvg.attributes.viewBox;
134
- } else {
135
- const width = Number.parseFloat(parsedSvg.attributes.width || '');
136
- const height = Number.parseFloat(parsedSvg.attributes.height || '');
137
- if (Number.isFinite(width) && Number.isFinite(height)) {
138
- symbolAttributes.viewBox = `0 0 ${width} ${height}`;
139
- } else {
140
- warnings.push(new webpack.WebpackError(`SVG icon is missing a viewBox and readable width/height: ${filePath}`));
141
- return null;
142
- }
143
- }
144
- return {
145
- filePath,
146
- namespaceAttributes,
147
- symbol: `<symbol ${buildAttributeString(symbolAttributes)}>${parsedSvg.content}</symbol>`
148
- };
149
- };
150
- const collectFiles = (patterns, allowDuplicates)=>{
151
- const files = patterns.flatMap((pattern)=>{
152
- return globSync(pattern, {
153
- absolute: true,
154
- dot: false,
155
- nodir: true
156
- });
157
- }).map((filePath)=>pathResolve(filePath));
158
- if (allowDuplicates) {
159
- return files;
160
- }
161
- return [
162
- ...new Set(files)
163
- ];
164
- };
165
- export class LexSvgSpritemapPlugin {
166
- buildSpritemap() {
167
- const warnings = [];
168
- const filePaths = collectFiles(this.patterns, this.options.allowDuplicates);
169
- if (filePaths.length === 0) {
170
- return {
171
- content: null,
172
- filePaths,
173
- warnings
174
- };
175
- }
176
- const namespaceAttributes = {};
177
- const usedIdentifiers = new Set();
178
- const symbols = filePaths.map((filePath)=>{
179
- return createSpriteSymbol(filePath, usedIdentifiers, this.options.prefix, warnings);
180
- }).filter((entry)=>entry !== null);
181
- if (symbols.length === 0) {
182
- return {
183
- content: null,
184
- filePaths,
185
- warnings
186
- };
187
- }
188
- for (const symbol of symbols){
189
- for (const [name, value] of Object.entries(symbol.namespaceAttributes)){
190
- namespaceAttributes[name] = value;
191
- }
192
- }
193
- const rootAttributes = buildAttributeString({
194
- xmlns: 'http://www.w3.org/2000/svg',
195
- ...namespaceAttributes
196
- });
197
- const spriteContent = `<svg ${rootAttributes}>${symbols.map((symbol)=>symbol.symbol).join('')}</svg>`;
198
- return {
199
- content: optimizeSvg(spriteContent, this.options.optimize),
200
- filePaths,
201
- warnings
202
- };
203
- }
204
- apply(compiler) {
205
- compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation)=>{
206
- const directories = new Set();
207
- const spritemap = this.buildSpritemap();
208
- for (const filePath of spritemap.filePaths){
209
- compilation.fileDependencies.add(filePath);
210
- directories.add(pathDirname(filePath));
211
- }
212
- for (const pattern of this.patterns){
213
- const baseDirectory = pathResolve(pattern.replace(/\*.*$/, ''));
214
- directories.add(baseDirectory);
215
- }
216
- for (const directory of directories){
217
- compilation.contextDependencies.add(directory);
218
- }
219
- if (spritemap.warnings.length > 0) {
220
- compilation.warnings.push(...spritemap.warnings);
221
- }
222
- compilation.hooks.processAssets.tap({
223
- name: PLUGIN_NAME,
224
- stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
225
- }, ()=>{
226
- if (!spritemap.content) {
227
- return;
228
- }
229
- const assetName = this.options.filename;
230
- const source = new webpack.sources.RawSource(spritemap.content);
231
- if (compilation.getAsset(assetName)) {
232
- compilation.updateAsset(assetName, source);
233
- return;
234
- }
235
- compilation.emitAsset(assetName, source);
236
- });
237
- });
238
- }
239
- constructor(patterns, options = {}){
240
- _define_property(this, "patterns", void 0);
241
- _define_property(this, "options", void 0);
242
- this.patterns = Array.isArray(patterns) ? patterns : [
243
- patterns
244
- ];
245
- this.options = {
246
- allowDuplicates: options.allowDuplicates ?? false,
247
- filename: normalizeAssetFilename(options.filename || DEFAULT_FILENAME),
248
- optimize: options.optimize ?? true,
249
- prefix: options.prefix ?? false
250
- };
251
- }
252
- }
253
- export default LexSvgSpritemapPlugin;
254
-
255
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy91dGlscy93ZWJwYWNrL0xleFN2Z1Nwcml0ZW1hcFBsdWdpbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcHlyaWdodCAoYykgMjAxOC1QcmVzZW50LCBOaXRyb2dlbiBMYWJzLCBJbmMuXG4gKiBDb3B5cmlnaHRzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIHRoZSBhY2NvbXBhbnlpbmcgTElDRU5TRSBmaWxlIGZvciB0ZXJtcy5cbiAqL1xuaW1wb3J0IHtyZWFkRmlsZVN5bmN9IGZyb20gJ2ZzJztcbmltcG9ydCB7c3luYyBhcyBnbG9iU3luY30gZnJvbSAnZ2xvYic7XG5pbXBvcnQge2Jhc2VuYW1lIGFzIHBhdGhCYXNlbmFtZSwgZGlybmFtZSBhcyBwYXRoRGlybmFtZSwgZXh0bmFtZSBhcyBwYXRoRXh0bmFtZSwgcmVzb2x2ZSBhcyBwYXRoUmVzb2x2ZX0gZnJvbSAncGF0aCc7XG5pbXBvcnQge29wdGltaXplfSBmcm9tICdzdmdvJztcbmltcG9ydCB3ZWJwYWNrIGZyb20gJ3dlYnBhY2snO1xuXG50eXBlIElkZW50aWZpZXJQcmVmaXggPSBmYWxzZSB8IHN0cmluZyB8ICgoZmlsZVBhdGg6IHN0cmluZykgPT4gc3RyaW5nKTtcblxuZXhwb3J0IGludGVyZmFjZSBMZXhTdmdTcHJpdGVtYXBQbHVnaW5PcHRpb25zIHtcbiAgcmVhZG9ubHkgYWxsb3dEdXBsaWNhdGVzPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgZmlsZW5hbWU/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IG9wdGltaXplPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgcHJlZml4PzogSWRlbnRpZmllclByZWZpeDtcbn1cblxuaW50ZXJmYWNlIFBhcnNlZFN2ZyB7XG4gIHJlYWRvbmx5IGF0dHJpYnV0ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIHJlYWRvbmx5IGNvbnRlbnQ6IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIFNwcml0ZVN5bWJvbCB7XG4gIHJlYWRvbmx5IGZpbGVQYXRoOiBzdHJpbmc7XG4gIHJlYWRvbmx5IG5hbWVzcGFjZUF0dHJpYnV0ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIHJlYWRvbmx5IHN5bWJvbDogc3RyaW5nO1xufVxuXG5jb25zdCBERUZBVUxUX0ZJTEVOQU1FID0gJ2ljb25zL2ljb25zLnN2Zyc7XG5jb25zdCBQTFVHSU5fTkFNRSA9ICdMZXhTdmdTcHJpdGVtYXBQbHVnaW4nO1xuY29uc3QgUk9PVF9FWENMVURFRF9BVFRSSUJVVEVTID0gbmV3IFNldChbXG4gICdoZWlnaHQnLFxuICAnaWQnLFxuICAndmVyc2lvbicsXG4gICd2aWV3Qm94JyxcbiAgJ3dpZHRoJyxcbiAgJ3htbG5zJ1xuXSk7XG5cbmNvbnN0IGVzY2FwZUF0dHJpYnV0ZSA9ICh2YWx1ZTogc3RyaW5nKTogc3RyaW5nID0+IHtcbiAgcmV0dXJuIHZhbHVlXG4gICAgLnJlcGxhY2VBbGwoJyYnLCAnJmFtcDsnKVxuICAgIC5yZXBsYWNlQWxsKCdcIicsICcmcXVvdDsnKVxuICAgIC5yZXBsYWNlQWxsKCc8JywgJyZsdDsnKVxuICAgIC5yZXBsYWNlQWxsKCc+JywgJyZndDsnKTtcbn07XG5cbmNvbnN0IG5vcm1hbGl6ZUFzc2V0RmlsZW5hbWUgPSAoZmlsZW5hbWU6IHN0cmluZyk6IHN0cmluZyA9PiB7XG4gIHJldHVybiBmaWxlbmFtZS5yZXBsYWNlKC9eWy4vXSsvLCAnJyk7XG59O1xuXG5jb25zdCBwYXJzZUF0dHJpYnV0ZXMgPSAoaW5wdXQ6IHN0cmluZyk6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPT4ge1xuICBjb25zdCBhdHRyaWJ1dGVzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gIGNvbnN0IGF0dHJpYnV0ZVJlZ2V4ID0gLyhbOkBcXHctXSspXFxzKj1cXHMqKFwiKFteXCJdKilcInwnKFteJ10qKScpL2c7XG5cbiAgbGV0IG1hdGNoOiBSZWdFeHBFeGVjQXJyYXkgfCBudWxsID0gYXR0cmlidXRlUmVnZXguZXhlYyhpbnB1dCk7XG4gIHdoaWxlKG1hdGNoKSB7XG4gICAgYXR0cmlidXRlc1ttYXRjaFsxXV0gPSBtYXRjaFszXSA/PyBtYXRjaFs0XSA/PyAnJztcbiAgICBtYXRjaCA9IGF0dHJpYnV0ZVJlZ2V4LmV4ZWMoaW5wdXQpO1xuICB9XG5cbiAgcmV0dXJuIGF0dHJpYnV0ZXM7XG59O1xuXG5jb25zdCBwYXJzZVN2ZyA9IChzb3VyY2U6IHN0cmluZyk6IFBhcnNlZFN2ZyB8IG51bGwgPT4ge1xuICBjb25zdCBzdmdNYXRjaCA9IHNvdXJjZVxuICAgIC5yZXBsYWNlKC88XFw/eG1sW1xcc1xcU10qP1xcPz4vaWcsICcnKVxuICAgIC5yZXBsYWNlKC88IWRvY3R5cGVbXFxzXFxTXSo/Pi9pZywgJycpXG4gICAgLm1hdGNoKC88c3ZnXFxiKFtePl0qKT4oW1xcc1xcU10qPyk8XFwvc3ZnPi9pKTtcblxuICBpZighc3ZnTWF0Y2gpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgYXR0cmlidXRlczogcGFyc2VBdHRyaWJ1dGVzKHN2Z01hdGNoWzFdIHx8ICcnKSxcbiAgICBjb250ZW50OiBzdmdNYXRjaFsyXT8udHJpbSgpIHx8ICcnXG4gIH07XG59O1xuXG5jb25zdCBidWlsZEF0dHJpYnV0ZVN0cmluZyA9IChhdHRyaWJ1dGVzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+KTogc3RyaW5nID0+IHtcbiAgcmV0dXJuIE9iamVjdC5lbnRyaWVzKGF0dHJpYnV0ZXMpXG4gICAgLm1hcCgoW25hbWUsIHZhbHVlXSkgPT4gYCR7bmFtZX09XCIke2VzY2FwZUF0dHJpYnV0ZSh2YWx1ZSl9XCJgKVxuICAgIC5qb2luKCcgJyk7XG59O1xuXG5jb25zdCBzYW5pdGl6ZUlkZW50aWZpZXIgPSAodmFsdWU6IHN0cmluZyk6IHN0cmluZyA9PiB7XG4gIGNvbnN0IHNhbml0aXplZFZhbHVlID0gdmFsdWVcbiAgICAudHJpbSgpXG4gICAgLnJlcGxhY2VBbGwoL1xccysvZywgJy0nKVxuICAgIC5yZXBsYWNlQWxsKC9bXkEtWmEtejAtOV8tXS9nLCAnLScpXG4gICAgLnJlcGxhY2VBbGwoLy17Mix9L2csICctJylcbiAgICAucmVwbGFjZUFsbCgvXlstX10rfFstX10rJC9nLCAnJyk7XG5cbiAgY29uc3Qgc2FmZVZhbHVlID0gc2FuaXRpemVkVmFsdWUgfHwgJ2ljb24nO1xuXG4gIHJldHVybiAvXltBLVphLXpfXS8udGVzdChzYWZlVmFsdWUpID8gc2FmZVZhbHVlIDogYGljb24tJHtzYWZlVmFsdWV9YDtcbn07XG5cbmNvbnN0IGdldFByZWZpeCA9IChmaWxlUGF0aDogc3RyaW5nLCBwcmVmaXg6IElkZW50aWZpZXJQcmVmaXgpOiBzdHJpbmcgPT4ge1xuICBpZihwcmVmaXggPT09IGZhbHNlKSB7XG4gICAgcmV0dXJuICcnO1xuICB9XG5cbiAgaWYodHlwZW9mIHByZWZpeCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgIHJldHVybiBwcmVmaXgoZmlsZVBhdGgpO1xuICB9XG5cbiAgcmV0dXJuIHByZWZpeCB8fCAnJztcbn07XG5cbmNvbnN0IG9wdGltaXplU3ZnID0gKGNvbnRlbnQ6IHN0cmluZywgZW5hYmxlZDogYm9vbGVhbik6IHN0cmluZyA9PiB7XG4gIGlmKCFlbmFibGVkKSB7XG4gICAgcmV0dXJuIGNvbnRlbnQ7XG4gIH1cblxuICByZXR1cm4gb3B0aW1pemUoY29udGVudCwge1xuICAgIG11bHRpcGFzczogdHJ1ZSxcbiAgICBwbHVnaW5zOiBbe1xuICAgICAgbmFtZTogJ3ByZXNldC1kZWZhdWx0JyxcbiAgICAgIHBhcmFtczoge1xuICAgICAgICBvdmVycmlkZXM6IHtcbiAgICAgICAgICBjbGVhbnVwSWRzOiBmYWxzZVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfV1cbiAgfSkuZGF0YTtcbn07XG5cbmNvbnN0IGNyZWF0ZVNwcml0ZVN5bWJvbCA9IChcbiAgZmlsZVBhdGg6IHN0cmluZyxcbiAgdXNlZElkZW50aWZpZXJzOiBTZXQ8c3RyaW5nPixcbiAgcHJlZml4OiBJZGVudGlmaWVyUHJlZml4LFxuICB3YXJuaW5nczogd2VicGFjay5XZWJwYWNrRXJyb3JbXVxuKTogU3ByaXRlU3ltYm9sIHwgbnVsbCA9PiB7XG4gIGNvbnN0IHNvdXJjZSA9IHJlYWRGaWxlU3luYyhmaWxlUGF0aCwgJ3V0ZjgnKTtcbiAgY29uc3QgcGFyc2VkU3ZnID0gcGFyc2VTdmcoc291cmNlKTtcblxuICBpZighcGFyc2VkU3ZnKSB7XG4gICAgd2FybmluZ3MucHVzaChuZXcgd2VicGFjay5XZWJwYWNrRXJyb3IoYEludmFsaWQgU1ZHIGljb246ICR7ZmlsZVBhdGh9YCkpO1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgaWYoIXBhcnNlZFN2Zy5jb250ZW50KSB7XG4gICAgd2FybmluZ3MucHVzaChuZXcgd2VicGFjay5XZWJwYWNrRXJyb3IoYFNWRyBpY29uIGlzIGVtcHR5OiAke2ZpbGVQYXRofWApKTtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IHJhd0lkZW50aWZpZXIgPSBgJHtnZXRQcmVmaXgoZmlsZVBhdGgsIHByZWZpeCl9JHtwYXRoQmFzZW5hbWUoZmlsZVBhdGgsIHBhdGhFeHRuYW1lKGZpbGVQYXRoKSl9YDtcbiAgY29uc3QgYmFzZUlkZW50aWZpZXIgPSBzYW5pdGl6ZUlkZW50aWZpZXIocmF3SWRlbnRpZmllcik7XG5cbiAgbGV0IGlkZW50aWZpZXIgPSBiYXNlSWRlbnRpZmllcjtcbiAgbGV0IGR1cGxpY2F0ZUluZGV4ID0gMTtcblxuICB3aGlsZSh1c2VkSWRlbnRpZmllcnMuaGFzKGlkZW50aWZpZXIpKSB7XG4gICAgZHVwbGljYXRlSW5kZXggKz0gMTtcbiAgICBpZGVudGlmaWVyID0gYCR7YmFzZUlkZW50aWZpZXJ9LSR7ZHVwbGljYXRlSW5kZXh9YDtcbiAgfVxuXG4gIGlmKGlkZW50aWZpZXIgIT09IGJhc2VJZGVudGlmaWVyKSB7XG4gICAgd2FybmluZ3MucHVzaChuZXcgd2VicGFjay5XZWJwYWNrRXJyb3IoYER1cGxpY2F0ZSBTVkcgaWNvbiBpZCBcIiR7YmFzZUlkZW50aWZpZXJ9XCIgZGV0ZWN0ZWQsIHVzaW5nIFwiJHtpZGVudGlmaWVyfVwiIGZvciAke2ZpbGVQYXRofWApKTtcbiAgfVxuXG4gIHVzZWRJZGVudGlmaWVycy5hZGQoaWRlbnRpZmllcik7XG5cbiAgY29uc3QgbmFtZXNwYWNlQXR0cmlidXRlcyA9IE9iamVjdC5lbnRyaWVzKHBhcnNlZFN2Zy5hdHRyaWJ1dGVzKS5yZWR1Y2U8UmVjb3JkPHN0cmluZywgc3RyaW5nPj4oKHJlc3VsdCwgW25hbWUsIHZhbHVlXSkgPT4ge1xuICAgIGlmKG5hbWUudG9Mb3dlckNhc2UoKS5zdGFydHNXaXRoKCd4bWxuczonKSkge1xuICAgICAgcmVzdWx0W25hbWVdID0gdmFsdWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSwge30pO1xuXG4gIGNvbnN0IHN5bWJvbEF0dHJpYnV0ZXMgPSBPYmplY3QuZW50cmllcyhwYXJzZWRTdmcuYXR0cmlidXRlcykucmVkdWNlPFJlY29yZDxzdHJpbmcsIHN0cmluZz4+KChyZXN1bHQsIFtuYW1lLCB2YWx1ZV0pID0+IHtcbiAgICBpZihST09UX0VYQ0xVREVEX0FUVFJJQlVURVMuaGFzKG5hbWUpKSB7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIGlmKG5hbWUudG9Mb3dlckNhc2UoKS5zdGFydHNXaXRoKCd4bWxuczonKSkge1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICByZXN1bHRbbmFtZV0gPSB2YWx1ZTtcblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH0sIHtcbiAgICBpZDogaWRlbnRpZmllclxuICB9KTtcblxuICBpZihwYXJzZWRTdmcuYXR0cmlidXRlcy52aWV3Qm94KSB7XG4gICAgc3ltYm9sQXR0cmlidXRlcy52aWV3Qm94ID0gcGFyc2VkU3ZnLmF0dHJpYnV0ZXMudmlld0JveDtcbiAgfSBlbHNlIHtcbiAgICBjb25zdCB3aWR0aCA9IE51bWJlci5wYXJzZUZsb2F0KHBhcnNlZFN2Zy5hdHRyaWJ1dGVzLndpZHRoIHx8ICcnKTtcbiAgICBjb25zdCBoZWlnaHQgPSBOdW1iZXIucGFyc2VGbG9hdChwYXJzZWRTdmcuYXR0cmlidXRlcy5oZWlnaHQgfHwgJycpO1xuXG4gICAgaWYoTnVtYmVyLmlzRmluaXRlKHdpZHRoKSAmJiBOdW1iZXIuaXNGaW5pdGUoaGVpZ2h0KSkge1xuICAgICAgc3ltYm9sQXR0cmlidXRlcy52aWV3Qm94ID0gYDAgMCAke3dpZHRofSAke2hlaWdodH1gO1xuICAgIH0gZWxzZSB7XG4gICAgICB3YXJuaW5ncy5wdXNoKG5ldyB3ZWJwYWNrLldlYnBhY2tFcnJvcihgU1ZHIGljb24gaXMgbWlzc2luZyBhIHZpZXdCb3ggYW5kIHJlYWRhYmxlIHdpZHRoL2hlaWdodDogJHtmaWxlUGF0aH1gKSk7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIGZpbGVQYXRoLFxuICAgIG5hbWVzcGFjZUF0dHJpYnV0ZXMsXG4gICAgc3ltYm9sOiBgPHN5bWJvbCAke2J1aWxkQXR0cmlidXRlU3RyaW5nKHN5bWJvbEF0dHJpYnV0ZXMpfT4ke3BhcnNlZFN2Zy5jb250ZW50fTwvc3ltYm9sPmBcbiAgfTtcbn07XG5cbmNvbnN0IGNvbGxlY3RGaWxlcyA9IChwYXR0ZXJuczogcmVhZG9ubHkgc3RyaW5nW10sIGFsbG93RHVwbGljYXRlczogYm9vbGVhbik6IHN0cmluZ1tdID0+IHtcbiAgY29uc3QgZmlsZXMgPSBwYXR0ZXJucy5mbGF0TWFwKChwYXR0ZXJuKSA9PiB7XG4gICAgcmV0dXJuIGdsb2JTeW5jKHBhdHRlcm4sIHtcbiAgICAgIGFic29sdXRlOiB0cnVlLFxuICAgICAgZG90OiBmYWxzZSxcbiAgICAgIG5vZGlyOiB0cnVlXG4gICAgfSkgYXMgc3RyaW5nW107XG4gIH0pLm1hcCgoZmlsZVBhdGgpID0+IHBhdGhSZXNvbHZlKGZpbGVQYXRoKSk7XG5cbiAgaWYoYWxsb3dEdXBsaWNhdGVzKSB7XG4gICAgcmV0dXJuIGZpbGVzO1xuICB9XG5cbiAgcmV0dXJuIFsuLi5uZXcgU2V0KGZpbGVzKV07XG59O1xuXG5leHBvcnQgY2xhc3MgTGV4U3ZnU3ByaXRlbWFwUGx1Z2luIHtcbiAgcmVhZG9ubHkgcGF0dGVybnM6IHN0cmluZ1tdO1xuICByZWFkb25seSBvcHRpb25zOiBSZXF1aXJlZDxMZXhTdmdTcHJpdGVtYXBQbHVnaW5PcHRpb25zPjtcblxuICBjb25zdHJ1Y3RvcihwYXR0ZXJuczogc3RyaW5nIHwgc3RyaW5nW10sIG9wdGlvbnM6IExleFN2Z1Nwcml0ZW1hcFBsdWdpbk9wdGlvbnMgPSB7fSkge1xuICAgIHRoaXMucGF0dGVybnMgPSBBcnJheS5pc0FycmF5KHBhdHRlcm5zKSA/IHBhdHRlcm5zIDogW3BhdHRlcm5zXTtcbiAgICB0aGlzLm9wdGlvbnMgPSB7XG4gICAgICBhbGxvd0R1cGxpY2F0ZXM6IG9wdGlvbnMuYWxsb3dEdXBsaWNhdGVzID8/IGZhbHNlLFxuICAgICAgZmlsZW5hbWU6IG5vcm1hbGl6ZUFzc2V0RmlsZW5hbWUob3B0aW9ucy5maWxlbmFtZSB8fCBERUZBVUxUX0ZJTEVOQU1FKSxcbiAgICAgIG9wdGltaXplOiBvcHRpb25zLm9wdGltaXplID8/IHRydWUsXG4gICAgICBwcmVmaXg6IG9wdGlvbnMucHJlZml4ID8/IGZhbHNlXG4gICAgfTtcbiAgfVxuXG4gIGJ1aWxkU3ByaXRlbWFwKCk6IHtjb250ZW50OiBzdHJpbmcgfCBudWxsOyBmaWxlUGF0aHM6IHN0cmluZ1tdOyB3YXJuaW5nczogd2VicGFjay5XZWJwYWNrRXJyb3JbXX0ge1xuICAgIGNvbnN0IHdhcm5pbmdzOiB3ZWJwYWNrLldlYnBhY2tFcnJvcltdID0gW107XG4gICAgY29uc3QgZmlsZVBhdGhzID0gY29sbGVjdEZpbGVzKHRoaXMucGF0dGVybnMsIHRoaXMub3B0aW9ucy5hbGxvd0R1cGxpY2F0ZXMpO1xuXG4gICAgaWYoZmlsZVBhdGhzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgY29udGVudDogbnVsbCxcbiAgICAgICAgZmlsZVBhdGhzLFxuICAgICAgICB3YXJuaW5nc1xuICAgICAgfTtcbiAgICB9XG5cbiAgICBjb25zdCBuYW1lc3BhY2VBdHRyaWJ1dGVzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gICAgY29uc3QgdXNlZElkZW50aWZpZXJzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgY29uc3Qgc3ltYm9scyA9IGZpbGVQYXRocy5tYXAoKGZpbGVQYXRoKSA9PiB7XG4gICAgICByZXR1cm4gY3JlYXRlU3ByaXRlU3ltYm9sKGZpbGVQYXRoLCB1c2VkSWRlbnRpZmllcnMsIHRoaXMub3B0aW9ucy5wcmVmaXgsIHdhcm5pbmdzKTtcbiAgICB9KS5maWx0ZXIoKGVudHJ5KTogZW50cnkgaXMgU3ByaXRlU3ltYm9sID0+IGVudHJ5ICE9PSBudWxsKTtcblxuICAgIGlmKHN5bWJvbHMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBjb250ZW50OiBudWxsLFxuICAgICAgICBmaWxlUGF0aHMsXG4gICAgICAgIHdhcm5pbmdzXG4gICAgICB9O1xuICAgIH1cblxuICAgIGZvcihjb25zdCBzeW1ib2wgb2Ygc3ltYm9scykge1xuICAgICAgZm9yKGNvbnN0IFtuYW1lLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc3ltYm9sLm5hbWVzcGFjZUF0dHJpYnV0ZXMpKSB7XG4gICAgICAgIG5hbWVzcGFjZUF0dHJpYnV0ZXNbbmFtZV0gPSB2YWx1ZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCByb290QXR0cmlidXRlcyA9IGJ1aWxkQXR0cmlidXRlU3RyaW5nKHtcbiAgICAgIHhtbG5zOiAnaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnLFxuICAgICAgLi4ubmFtZXNwYWNlQXR0cmlidXRlc1xuICAgIH0pO1xuICAgIGNvbnN0IHNwcml0ZUNvbnRlbnQgPSBgPHN2ZyAke3Jvb3RBdHRyaWJ1dGVzfT4ke3N5bWJvbHMubWFwKChzeW1ib2wpID0+IHN5bWJvbC5zeW1ib2wpLmpvaW4oJycpfTwvc3ZnPmA7XG5cbiAgICByZXR1cm4ge1xuICAgICAgY29udGVudDogb3B0aW1pemVTdmcoc3ByaXRlQ29udGVudCwgdGhpcy5vcHRpb25zLm9wdGltaXplKSxcbiAgICAgIGZpbGVQYXRocyxcbiAgICAgIHdhcm5pbmdzXG4gICAgfTtcbiAgfVxuXG4gIGFwcGx5KGNvbXBpbGVyOiB3ZWJwYWNrLkNvbXBpbGVyKTogdm9pZCB7XG4gICAgY29tcGlsZXIuaG9va3MudGhpc0NvbXBpbGF0aW9uLnRhcChQTFVHSU5fTkFNRSwgKGNvbXBpbGF0aW9uKSA9PiB7XG4gICAgICBjb25zdCBkaXJlY3RvcmllcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgICAgY29uc3Qgc3ByaXRlbWFwID0gdGhpcy5idWlsZFNwcml0ZW1hcCgpO1xuXG4gICAgICBmb3IoY29uc3QgZmlsZVBhdGggb2Ygc3ByaXRlbWFwLmZpbGVQYXRocykge1xuICAgICAgICBjb21waWxhdGlvbi5maWxlRGVwZW5kZW5jaWVzLmFkZChmaWxlUGF0aCk7XG4gICAgICAgIGRpcmVjdG9yaWVzLmFkZChwYXRoRGlybmFtZShmaWxlUGF0aCkpO1xuICAgICAgfVxuXG4gICAgICBmb3IoY29uc3QgcGF0dGVybiBvZiB0aGlzLnBhdHRlcm5zKSB7XG4gICAgICAgIGNvbnN0IGJhc2VEaXJlY3RvcnkgPSBwYXRoUmVzb2x2ZShwYXR0ZXJuLnJlcGxhY2UoL1xcKi4qJC8sICcnKSk7XG4gICAgICAgIGRpcmVjdG9yaWVzLmFkZChiYXNlRGlyZWN0b3J5KTtcbiAgICAgIH1cblxuICAgICAgZm9yKGNvbnN0IGRpcmVjdG9yeSBvZiBkaXJlY3Rvcmllcykge1xuICAgICAgICBjb21waWxhdGlvbi5jb250ZXh0RGVwZW5kZW5jaWVzLmFkZChkaXJlY3RvcnkpO1xuICAgICAgfVxuXG4gICAgICBpZihzcHJpdGVtYXAud2FybmluZ3MubGVuZ3RoID4gMCkge1xuICAgICAgICBjb21waWxhdGlvbi53YXJuaW5ncy5wdXNoKC4uLnNwcml0ZW1hcC53YXJuaW5ncyk7XG4gICAgICB9XG5cbiAgICAgIGNvbXBpbGF0aW9uLmhvb2tzLnByb2Nlc3NBc3NldHMudGFwKHtcbiAgICAgICAgbmFtZTogUExVR0lOX05BTUUsXG4gICAgICAgIHN0YWdlOiB3ZWJwYWNrLkNvbXBpbGF0aW9uLlBST0NFU1NfQVNTRVRTX1NUQUdFX0FERElUSU9OQUxcbiAgICAgIH0sICgpID0+IHtcbiAgICAgICAgaWYoIXNwcml0ZW1hcC5jb250ZW50KSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgYXNzZXROYW1lID0gdGhpcy5vcHRpb25zLmZpbGVuYW1lO1xuICAgICAgICBjb25zdCBzb3VyY2UgPSBuZXcgd2VicGFjay5zb3VyY2VzLlJhd1NvdXJjZShzcHJpdGVtYXAuY29udGVudCk7XG5cbiAgICAgICAgaWYoY29tcGlsYXRpb24uZ2V0QXNzZXQoYXNzZXROYW1lKSkge1xuICAgICAgICAgIGNvbXBpbGF0aW9uLnVwZGF0ZUFzc2V0KGFzc2V0TmFtZSwgc291cmNlKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb21waWxhdGlvbi5lbWl0QXNzZXQoYXNzZXROYW1lLCBzb3VyY2UpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgTGV4U3ZnU3ByaXRlbWFwUGx1Z2luO1xuIl0sIm5hbWVzIjpbInJlYWRGaWxlU3luYyIsInN5bmMiLCJnbG9iU3luYyIsImJhc2VuYW1lIiwicGF0aEJhc2VuYW1lIiwiZGlybmFtZSIsInBhdGhEaXJuYW1lIiwiZXh0bmFtZSIsInBhdGhFeHRuYW1lIiwicmVzb2x2ZSIsInBhdGhSZXNvbHZlIiwib3B0aW1pemUiLCJ3ZWJwYWNrIiwiREVGQVVMVF9GSUxFTkFNRSIsIlBMVUdJTl9OQU1FIiwiUk9PVF9FWENMVURFRF9BVFRSSUJVVEVTIiwiU2V0IiwiZXNjYXBlQXR0cmlidXRlIiwidmFsdWUiLCJyZXBsYWNlQWxsIiwibm9ybWFsaXplQXNzZXRGaWxlbmFtZSIsImZpbGVuYW1lIiwicmVwbGFjZSIsInBhcnNlQXR0cmlidXRlcyIsImlucHV0IiwiYXR0cmlidXRlcyIsImF0dHJpYnV0ZVJlZ2V4IiwibWF0Y2giLCJleGVjIiwicGFyc2VTdmciLCJzb3VyY2UiLCJzdmdNYXRjaCIsImNvbnRlbnQiLCJ0cmltIiwiYnVpbGRBdHRyaWJ1dGVTdHJpbmciLCJPYmplY3QiLCJlbnRyaWVzIiwibWFwIiwibmFtZSIsImpvaW4iLCJzYW5pdGl6ZUlkZW50aWZpZXIiLCJzYW5pdGl6ZWRWYWx1ZSIsInNhZmVWYWx1ZSIsInRlc3QiLCJnZXRQcmVmaXgiLCJmaWxlUGF0aCIsInByZWZpeCIsIm9wdGltaXplU3ZnIiwiZW5hYmxlZCIsIm11bHRpcGFzcyIsInBsdWdpbnMiLCJwYXJhbXMiLCJvdmVycmlkZXMiLCJjbGVhbnVwSWRzIiwiZGF0YSIsImNyZWF0ZVNwcml0ZVN5bWJvbCIsInVzZWRJZGVudGlmaWVycyIsIndhcm5pbmdzIiwicGFyc2VkU3ZnIiwicHVzaCIsIldlYnBhY2tFcnJvciIsInJhd0lkZW50aWZpZXIiLCJiYXNlSWRlbnRpZmllciIsImlkZW50aWZpZXIiLCJkdXBsaWNhdGVJbmRleCIsImhhcyIsImFkZCIsIm5hbWVzcGFjZUF0dHJpYnV0ZXMiLCJyZWR1Y2UiLCJyZXN1bHQiLCJ0b0xvd2VyQ2FzZSIsInN0YXJ0c1dpdGgiLCJzeW1ib2xBdHRyaWJ1dGVzIiwiaWQiLCJ2aWV3Qm94Iiwid2lkdGgiLCJOdW1iZXIiLCJwYXJzZUZsb2F0IiwiaGVpZ2h0IiwiaXNGaW5pdGUiLCJzeW1ib2wiLCJjb2xsZWN0RmlsZXMiLCJwYXR0ZXJucyIsImFsbG93RHVwbGljYXRlcyIsImZpbGVzIiwiZmxhdE1hcCIsInBhdHRlcm4iLCJhYnNvbHV0ZSIsImRvdCIsIm5vZGlyIiwiTGV4U3ZnU3ByaXRlbWFwUGx1Z2luIiwiYnVpbGRTcHJpdGVtYXAiLCJmaWxlUGF0aHMiLCJvcHRpb25zIiwibGVuZ3RoIiwic3ltYm9scyIsImZpbHRlciIsImVudHJ5Iiwicm9vdEF0dHJpYnV0ZXMiLCJ4bWxucyIsInNwcml0ZUNvbnRlbnQiLCJhcHBseSIsImNvbXBpbGVyIiwiaG9va3MiLCJ0aGlzQ29tcGlsYXRpb24iLCJ0YXAiLCJjb21waWxhdGlvbiIsImRpcmVjdG9yaWVzIiwic3ByaXRlbWFwIiwiZmlsZURlcGVuZGVuY2llcyIsImJhc2VEaXJlY3RvcnkiLCJkaXJlY3RvcnkiLCJjb250ZXh0RGVwZW5kZW5jaWVzIiwicHJvY2Vzc0Fzc2V0cyIsInN0YWdlIiwiQ29tcGlsYXRpb24iLCJQUk9DRVNTX0FTU0VUU19TVEFHRV9BRERJVElPTkFMIiwiYXNzZXROYW1lIiwic291cmNlcyIsIlJhd1NvdXJjZSIsImdldEFzc2V0IiwidXBkYXRlQXNzZXQiLCJlbWl0QXNzZXQiLCJBcnJheSIsImlzQXJyYXkiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQUE7OztDQUdDLEdBQ0QsU0FBUUEsWUFBWSxRQUFPLEtBQUs7QUFDaEMsU0FBUUMsUUFBUUMsUUFBUSxRQUFPLE9BQU87QUFDdEMsU0FBUUMsWUFBWUMsWUFBWSxFQUFFQyxXQUFXQyxXQUFXLEVBQUVDLFdBQVdDLFdBQVcsRUFBRUMsV0FBV0MsV0FBVyxRQUFPLE9BQU87QUFDdEgsU0FBUUMsUUFBUSxRQUFPLE9BQU87QUFDOUIsT0FBT0MsYUFBYSxVQUFVO0FBc0I5QixNQUFNQyxtQkFBbUI7QUFDekIsTUFBTUMsY0FBYztBQUNwQixNQUFNQywyQkFBMkIsSUFBSUMsSUFBSTtJQUN2QztJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7Q0FDRDtBQUVELE1BQU1DLGtCQUFrQixDQUFDQztJQUN2QixPQUFPQSxNQUNKQyxVQUFVLENBQUMsS0FBSyxTQUNoQkEsVUFBVSxDQUFDLEtBQUssVUFDaEJBLFVBQVUsQ0FBQyxLQUFLLFFBQ2hCQSxVQUFVLENBQUMsS0FBSztBQUNyQjtBQUVBLE1BQU1DLHlCQUF5QixDQUFDQztJQUM5QixP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