@macedon-technologies/batman 1.34.0 → 1.35.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.
- package/.jsii +248 -28
- package/API.md +212 -0
- package/README.md +26 -0
- package/factory/work-item-sources.md +24 -4
- package/lib/BatmanProject.d.ts +11 -0
- package/lib/BatmanProject.js +5 -2
- package/lib/BootcampProject.js +5 -2
- package/lib/CodeOwnersFile.js +1 -1
- package/lib/PrAutoMergeWorkflow.js +1 -1
- package/lib/ProductionDeployWorkflow.js +1 -1
- package/lib/SoftwareFactoryBootstrap.d.ts +14 -3
- package/lib/SoftwareFactoryBootstrap.js +99 -15
- package/lib/SoftwareFactoryFiles.d.ts +13 -0
- package/lib/SoftwareFactoryFiles.js +22 -4
- package/lib/SoftwareFactoryJiraExtension.d.ts +14 -0
- package/lib/SoftwareFactoryJiraExtension.js +58 -0
- package/lib/SoftwareFactoryModels.d.ts +10 -0
- package/lib/SoftwareFactoryModels.js +26 -7
- package/lib/SoftwareFactoryWorkItemSources.d.ts +20 -3
- package/lib/SoftwareFactoryWorkItemSources.js +98 -9
- package/lib/StagingDeployWorkflow.js +1 -1
- package/lib/WorkItemSource.d.ts +67 -0
- package/lib/WorkItemSource.js +45 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -1
- package/lib/utils.js +36 -3
- package/package.json +3 -2
- package/swamp-bootstrap/pull-extensions.ts +79 -10
- package/swamp-bootstrap/required-extensions.json +4 -0
- package/templates/app/swamp-bootstrap/pull-extensions.ts +79 -10
- package/templates/app/swamp-bootstrap/required-extensions.json +4 -0
- package/templates/jira/extensions/models/jira.ts +191 -0
package/lib/utils.js
CHANGED
|
@@ -191,7 +191,7 @@ function readmeContents(projectName, e2eTesting = true, packageManager = javascr
|
|
|
191
191
|
'| `architecture-rules/check.ts`, `tsconfig.json`, `README.md` | Architecture rule engine |',
|
|
192
192
|
'| `attestation/manifest.ts`, `verify.ts`, `tsconfig.json` | PR attestation mechanism |',
|
|
193
193
|
'| `openspec-gates/check-tasks-complete.ts`, `tsconfig.json` | OpenSpec task-completion gate |',
|
|
194
|
-
'| `swamp-bootstrap/pull-extensions.ts`, `tsconfig.json` | Pulls swamp extensions at their pinned versions |',
|
|
194
|
+
'| `swamp-bootstrap/pull-extensions.ts`, `required-extensions.json`, `tsconfig.json` | Pulls swamp extensions at their pinned versions, and at least the versions the enabled work-item sources need |',
|
|
195
195
|
'| `workflows/workflow-*.yaml` | Swamp workflows the software factory runs |',
|
|
196
196
|
'| `factory/work-item-sources.md` | How the software factory resolves a work-item ID to its tracker |',
|
|
197
197
|
'',
|
|
@@ -201,7 +201,7 @@ function readmeContents(projectName, e2eTesting = true, packageManager = javascr
|
|
|
201
201
|
'',
|
|
202
202
|
'Batman also seeds a [swamp](https://github.com/swamp-club/swamp) software',
|
|
203
203
|
'factory — a `@swamp/software-factory` state machine that drives a work item',
|
|
204
|
-
'(a GitHub issue number
|
|
204
|
+
'(a GitHub issue number, or a Jira key when the Jira source is enabled) through intake, OpenSpec planning,',
|
|
205
205
|
'implementation, pre-PR verification, and an opened PR. Intake resolves the',
|
|
206
206
|
'work item through the managed `factory/work-item-sources.md`. The seed',
|
|
207
207
|
'files under `models/**/*.yaml` and `architecture-rules/rules.json` are',
|
|
@@ -239,6 +239,39 @@ function readmeContents(projectName, e2eTesting = true, packageManager = javascr
|
|
|
239
239
|
'swamp vault put <repo>-secrets GITHUB_TOKEN --refresh-from "gh auth token"',
|
|
240
240
|
'```',
|
|
241
241
|
'',
|
|
242
|
+
'#### Taking work items from Jira',
|
|
243
|
+
'',
|
|
244
|
+
'Set `workItemSources: { github: {}, jira: { projectKeys, siteHost } }` in',
|
|
245
|
+
'`.projenrc.ts`, or leave out `github` to take work items from Jira alone.',
|
|
246
|
+
'`projectKeys` lists the Jira projects intake may read, and `siteHost` is the',
|
|
247
|
+
'site\'s hostname, such as `acme.atlassian.net`. Then run `npx projen`, which',
|
|
248
|
+
'writes the managed',
|
|
249
|
+
'`extensions/models/jira.ts` and the seed `models/@batman/jira/<repo>-jira.yaml`,',
|
|
250
|
+
'and commit both.',
|
|
251
|
+
'',
|
|
252
|
+
'Intake reads Jira through Atlassian\'s `acli`, with each developer\'s own',
|
|
253
|
+
'sign-in, as it reads GitHub through `gh`. The extension only reads; it never',
|
|
254
|
+
'writes to Jira. Each developer installs `acli`',
|
|
255
|
+
'(https://developer.atlassian.com/cloud/acli/guides/install-acli/) and signs in',
|
|
256
|
+
'once:',
|
|
257
|
+
'',
|
|
258
|
+
'```bash',
|
|
259
|
+
'# Sign in through the browser',
|
|
260
|
+
'acli jira auth login --web',
|
|
261
|
+
'',
|
|
262
|
+
'# Or, where there is no browser, sign in with an API token read from a file',
|
|
263
|
+
'acli jira auth login --site <siteHost> --email <you@example.com> --token < token.txt',
|
|
264
|
+
'# The same in PowerShell',
|
|
265
|
+
'Get-Content token.txt | acli jira auth login --site <siteHost> --email <you@example.com> --token',
|
|
266
|
+
'',
|
|
267
|
+
'# The status must show Site: <siteHost>; if it shows another site, switch',
|
|
268
|
+
'acli jira auth status',
|
|
269
|
+
'acli jira auth switch --site <siteHost>',
|
|
270
|
+
'```',
|
|
271
|
+
'',
|
|
272
|
+
'If a fetch says `acli` is not signed in, sign in again. Either sign-in can do',
|
|
273
|
+
'anything your Atlassian account can, so treat it like your `gh` sign-in.',
|
|
274
|
+
'',
|
|
242
275
|
'---',
|
|
243
276
|
'',
|
|
244
277
|
'## Where to Start',
|
|
@@ -292,4 +325,4 @@ function readmeContents(projectName, e2eTesting = true, packageManager = javascr
|
|
|
292
325
|
'This updates all managed files to the latest Batman standards. Your editable sample files are never touched.',
|
|
293
326
|
].join('\n');
|
|
294
327
|
}
|
|
295
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFLQSw0Q0FZQztBQU1ELHdDQVdDO0FBV0QsNERBT0M7QUFVRCxzREFFQztBQU9ELDREQUVDO0FBRUQsa0NBZ0JDO0FBRUQsd0NBeU1DO0FBdFNELHNEQUEyRDtBQUUzRDs7R0FFRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLGNBQWtDLEVBQUUsTUFBYztJQUNqRixRQUFRLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLEtBQUssK0JBQWtCLENBQUMsR0FBRztZQUN6QixPQUFPLFdBQVcsTUFBTSxFQUFFLENBQUM7UUFDN0IsS0FBSywrQkFBa0IsQ0FBQyxHQUFHO1lBQ3pCLE9BQU8sV0FBVyxNQUFNLEVBQUUsQ0FBQztRQUM3QixLQUFLLCtCQUFrQixDQUFDLElBQUk7WUFDMUIsT0FBTyxRQUFRLE1BQU0sRUFBRSxDQUFDO1FBQzFCO1lBQ0Usb0ZBQW9GO1lBQ3BGLE9BQU8sUUFBUSxNQUFNLEVBQUUsQ0FBQztJQUM1QixDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLGNBQWMsQ0FBQyxjQUFrQztJQUMvRCxRQUFRLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLEtBQUssK0JBQWtCLENBQUMsR0FBRztZQUN6QixPQUFPLFFBQVEsQ0FBQztRQUNsQixLQUFLLCtCQUFrQixDQUFDLEdBQUc7WUFDekIsT0FBTywrQkFBK0IsQ0FBQztRQUN6QyxLQUFLLCtCQUFrQixDQUFDLElBQUk7WUFDMUIsT0FBTyxnQ0FBZ0MsQ0FBQztRQUMxQztZQUNFLE9BQU8sZ0NBQWdDLENBQUM7SUFDNUMsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILFNBQWdCLHdCQUF3QjtJQUN0QyxPQUFPO1FBQ0wsbUdBQW1HO1FBQ25HLG9EQUFvRDtRQUNwRCwrQ0FBK0M7UUFDL0MsSUFBSTtLQUNMLENBQUM7QUFDSixDQUFDO0FB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S0FBSztRQUNMLEVBQUU7UUFDRixnQkFBZ0I7UUFDaEIsZ0ZBQWdGO1FBQ2hGLG9FQUFvRTtRQUNwRSxFQUFFO1FBQ0YsS0FBSztRQUNMLEVBQUU7UUFDRixxQkFBcUI7UUFDckIsRUFBRTtRQUNGLFNBQVM7UUFDVCw4Q0FBOEM7UUFDOUMsWUFBWTtRQUNaLEtBQUs7UUFDTCxFQUFFO1FBQ0YsOEdBQThHO0tBQy9HLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ2YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5vZGVQYWNrYWdlTWFuYWdlciB9IGZyb20gJ3Byb2plbi9saWIvamF2YXNjcmlwdCc7XG5cbi8qKlxuICogUmVuZGVycyB0aGUgY29tbWFuZCB1c2VkIHRvIHJ1biBhIHBhY2thZ2UuanNvbiBzY3JpcHQgZm9yIHRoZSBnaXZlbiBwYWNrYWdlIG1hbmFnZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBydW5TY3JpcHRDb21tYW5kKHBhY2thZ2VNYW5hZ2VyOiBOb2RlUGFja2FnZU1hbmFnZXIsIHNjcmlwdDogc3RyaW5nKTogc3RyaW5nIHtcbiAgc3dpdGNoIChwYWNrYWdlTWFuYWdlcikge1xuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLk5QTTpcbiAgICAgIHJldHVybiBgbnBtIHJ1biAke3NjcmlwdH1gO1xuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLkJVTjpcbiAgICAgIHJldHVybiBgYnVuIHJ1biAke3NjcmlwdH1gO1xuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLlBOUE06XG4gICAgICByZXR1cm4gYHBucG0gJHtzY3JpcHR9YDtcbiAgICBkZWZhdWx0OlxuICAgICAgLy8gYWxsIHlhcm4gdmFyaWFudHMgKHlhcm4sIHlhcm4yLCB5YXJuX2NsYXNzaWMsIHlhcm5fYmVycnkpIHNoYXJlIHRoZSBgeWFybmAgYmluYXJ5XG4gICAgICByZXR1cm4gYHlhcm4gJHtzY3JpcHR9YDtcbiAgfVxufVxuXG4vKipcbiAqIFJlbmRlcnMgdGhlIGNvbW1hbmQgdXNlZCB0byBkbyBhIGNsZWFuLCByZXByb2R1Y2libGUgZGVwZW5kZW5jeSBpbnN0YWxsIChlLmcuIGZvciBDSSlcbiAqIGZvciB0aGUgZ2l2ZW4gcGFja2FnZSBtYW5hZ2VyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaW5zdGFsbENvbW1hbmQocGFja2FnZU1hbmFnZXI6IE5vZGVQYWNrYWdlTWFuYWdlcik6IHN0cmluZyB7XG4gIHN3aXRjaCAocGFja2FnZU1hbmFnZXIpIHtcbiAgICBjYXNlIE5vZGVQYWNrYWdlTWFuYWdlci5OUE06XG4gICAgICByZXR1cm4gJ25wbSBjaSc7XG4gICAgY2FzZSBOb2RlUGFja2FnZU1hbmFnZXIuQlVOOlxuICAgICAgcmV0dXJuICdidW4gaW5zdGFsbCAtLWZyb3plbi1sb2NrZmlsZSc7XG4gICAgY2FzZSBOb2RlUGFja2FnZU1hbmFnZXIuUE5QTTpcbiAgICAgIHJldHVybiAncG5wbSBpbnN0YWxsIC0tZnJvemVuLWxvY2tmaWxlJztcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuICd5YXJuIGluc3RhbGwgLS1mcm96ZW4tbG9ja2ZpbGUnO1xuICB9XG59XG5cbi8qKlxuICogQmFzaCBsaW5lcyB0aGF0IHNhbml0aXplIGEgYENMRUFOX0JSQU5DSF9OQU1FYCB2YXJpYWJsZSAoYWxyZWFkeSBzdHJpcHBlZCBvZiBhbnlcbiAqIGNvbnZlbnRpb25hbC1jb21taXQgcHJlZml4KSBpbnRvIGEgdmFsdWUgc2FmZSB0byB1c2UgYXMgYSBDbG91ZEZvcm1hdGlvbiBzdGFjay1uYW1lXG4gKiBmcmFnbWVudDogY29sbGFwc2VzIHJ1bnMgb2Ygbm9uLWFscGhhbnVtZXJpYyBjaGFyYWN0ZXJzIHRvIGAtYCwgdHJpbXMgbGVhZGluZy90cmFpbGluZ1xuICogYC1gLCBhbmQgcHJlZml4ZXMgd2l0aCBgcHItYCBpZiB0aGUgcmVzdWx0IHdvdWxkIG5vdCBzdGFydCB3aXRoIGEgbGV0dGVyIChvciBpcyBlbXB0eSkuXG4gKlxuICogU2hhcmVkIGJ5IFByRGVwbG95V29ya2Zsb3cgYW5kIFByQ2xlYW51cFdvcmtmbG93IHNvIGJvdGggZGVyaXZlIHRoZSBpZGVudGljYWwgc3RhY2tcbiAqIG5hbWUgZm9yIGEgZ2l2ZW4gYnJhbmNoLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemVCcmFuY2hOYW1lU2NyaXB0KCk6IHN0cmluZ1tdIHtcbiAgcmV0dXJuIFtcbiAgICAnQ0xFQU5fQlJBTkNIX05BTUU9JChlY2hvIFwiJENMRUFOX0JSQU5DSF9OQU1FXCIgfCBzZWQgLUUgXFwncy9bXkEtWmEtejAtOV0rLy0vZzsgcy9eLSsvLzsgcy8tKyQvL1xcJyknLFxuICAgICdpZiBbWyAhIFwiJENMRUFOX0JSQU5DSF9OQU1FXCIgPX4gXltBLVphLXpdIF1dOyB0aGVuJyxcbiAgICAnICBDTEVBTl9CUkFOQ0hfTkFNRT1cInByLSR7Q0xFQU5fQlJBTkNIX05BTUV9XCInLFxuICAgICdmaScsXG4gIF07XG59XG5cbi8qKlxuICogSm9pbnMgY29tbWFuZHMgd2l0aCBgO2AgaW5zdGVhZCBvZiBgJiZgL2B8fGAgc28gdGhlIHJlc3VsdCBpcyB2YWxpZCBmb3IgYSBzd2FtcFxuICogY29tbWFuZC9zaGVsbCBtb2RlbCdzIGBydW46YCB2YWx1ZSBvbiBib3RoIFBPU0lYIHNoZWxscyBhbmQgV2luZG93cyBQb3dlclNoZWxsIDUuMVxuICogKHdoaWNoIGhhcyBubyBgJiZgL2B8fGAgY2hhaW4gb3BlcmF0b3JzIGJlZm9yZSBwd3NoIDcpLiBVbmxpa2UgYCYmYCwgYDtgIGRvZXMgbm90XG4gKiBzaG9ydC1jaXJjdWl0IG9uIGZhaWx1cmUg4oCUIGNhbGxlcnMgdGhhdCBuZWVkIGZhaWx1cmUgdG8gc3RvcCB0aGUgc2VxdWVuY2Ugc2hvdWxkIHNwbGl0XG4gKiBpbnRvIHNlcGFyYXRlIHdvcmtmbG93IHN0ZXBzIHdpdGggdGhlaXIgb3duIGBhc3NlcnRgIGdhdGVzIGluc3RlYWQgb2YgcmVseWluZyBvbiB0aGlzXG4gKiBmb3IgY29udHJvbCBmbG93LlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2hlbGxQb3J0YWJsZVNlcXVlbmNlKC4uLmNvbW1hbmRzOiBzdHJpbmdbXSk6IHN0cmluZyB7XG4gIHJldHVybiBjb21tYW5kcy5qb2luKCc7ICcpO1xufVxuXG4vKipcbiAqIFJlbmRlcnMgYSBwb3J0YWJsZSBmb3JjZS1kZWxldGUgZm9yIGEgc2luZ2xlIGZpbGUsIGZvciB1c2UgaW4gYSBzd2FtcCBjb21tYW5kL3NoZWxsXG4gKiBtb2RlbCdzIGBydW46YCB2YWx1ZSBpbiBwbGFjZSBvZiBgcm0gLWYgPHBhdGg+YCAoYW1iaWd1b3VzIHdpdGggUG93ZXJTaGVsbCA1LjEnc1xuICogYFJlbW92ZS1JdGVtIC1GaWx0ZXJgIGFsaWFzKS4gTWF0Y2hlcyB0aGUgZml4IGFscmVhZHkgdmFsaWRhdGVkIGluIGV4bWFuIzEzNi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNoZWxsUG9ydGFibGVGb3JjZURlbGV0ZShwYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gYG5vZGUgLWUgXCJyZXF1aXJlKCdmcycpLnJtU3luYygnJHtwYXRofScsIHsgZm9yY2U6IHRydWUgfSlcImA7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXJpYWxpemVUcyh2YWx1ZTogYW55LCBkZXB0aCA9IDEpOiBzdHJpbmcge1xuICBjb25zdCBwYWQgPSAnICAnLnJlcGVhdChkZXB0aCk7XG4gIGNvbnN0IGlubmVyUGFkID0gJyAgJy5yZXBlYXQoZGVwdGggKyAxKTtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHJldHVybiBgJyR7dmFsdWV9J2A7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nKSByZXR1cm4gU3RyaW5nKHZhbHVlKTtcbiAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgY29uc3QgaXRlbXMgPSB2YWx1ZS5tYXAodiA9PiBgJHtpbm5lclBhZH0ke3NlcmlhbGl6ZVRzKHYsIGRlcHRoICsgMSl9YCkuam9pbignLFxcbicpO1xuICAgIHJldHVybiBgW1xcbiR7aXRlbXN9LFxcbiR7cGFkfV1gO1xuICB9XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlICE9PSBudWxsKSB7XG4gICAgY29uc3QgZW50cmllcyA9IE9iamVjdC5lbnRyaWVzKHZhbHVlKVxuICAgICAgLm1hcCgoW2ssIHZdKSA9PiBgJHtpbm5lclBhZH0ke2t9OiAke3NlcmlhbGl6ZVRzKHYsIGRlcHRoICsgMSl9YClcbiAgICAgIC5qb2luKCcsXFxuJyk7XG4gICAgcmV0dXJuIGB7XFxuJHtlbnRyaWVzfSxcXG4ke3BhZH19YDtcbiAgfVxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVhZG1lQ29udGVudHMoXG4gIHByb2plY3ROYW1lOiBzdHJpbmcsXG4gIGUyZVRlc3RpbmcgPSB0cnVlLFxuICBwYWNrYWdlTWFuYWdlcjogTm9kZVBhY2thZ2VNYW5hZ2VyID0gTm9kZVBhY2thZ2VNYW5hZ2VyLllBUk5fQ0xBU1NJQyxcbiAgcHJBdXRvTWVyZ2UgPSBmYWxzZSxcbikge1xuICBjb25zdCB0ZXN0RTJlQ29tbWFuZCA9IHJ1blNjcmlwdENvbW1hbmQocGFja2FnZU1hbmFnZXIsICd0ZXN0OmUyZScpO1xuICByZXR1cm4gW1xuICAgIGAjICR7cHJvamVjdE5hbWV9YCxcbiAgICAnJyxcbiAgICAnVGhpcyBwcm9qZWN0IHdhcyBib290c3RyYXBwZWQgd2l0aCBbQmF0bWFuXShodHRwczovL2dpdGh1Yi5jb20vbWFjZWRvbi10ZWNobm9sb2dpZXMvcGxhdGZvcm0tY29tbW9uKS4nLFxuICAgICcnLFxuICAgICcjIyBXaGF0IEJhdG1hbiBDcmVhdGVkJyxcbiAgICAnJyxcbiAgICAnIyMjIENESyBJbmZyYXN0cnVjdHVyZSAoYHNyYy9gKScsXG4gICAgJycsXG4gICAgJ3wgRmlsZSB8IERlc2NyaXB0aW9uIHwnLFxuICAgICd8LS0tLS0tfC0tLS0tLS0tLS0tLS18JyxcbiAgICAnfCBgc3JjL21haW4udHNgIHwgQ0RLIGFwcCBlbnRyeSBwb2ludCDigJQgaW5zdGFudGlhdGVzIGRldiwgc3RhZ2luZywgYW5kIHByb2QgYEFwcGxpY2F0aW9uU3RhY2tgcyB8JyxcbiAgICAnfCBgc3JjL0xvY2FsRGV2QXBwLnRzYCB8IExvY2FsIGRldmVsb3BtZW50IENESyBhcHAg4oCUIHVzZWQgYnkgYHlhcm4gY2RrOmRldmAgLSBkZXBsb3lzIHRvIEFXUyBmb3Igc2xvd2VyIGJ1dCBtb3JlIHRob3JvdWdoIHRlc3RpbmcgfCcsXG4gICAgJ3wgYHNyYy9HaXRIdWJSb2xlcy50c2AgfCBDREsgYXBwIGZvciBkZXBsb3lpbmcgdGhlIEdpdEh1YiBPSURDIElBTSByb2xlIChvbmUtdGltZSBib290c3RyYXApIHwnLFxuICAgICd8IGBzcmMvc3RhY2tzL0FwcGxpY2F0aW9uU3RhY2sudHNgIHwgWW91ciBwcmltYXJ5IHN0YWNrIOKAlCBleHRlbmQgaXQgdG8gYWRkIHJlc291cmNlcyB8JyxcbiAgICAnfCBgc3JjL3N0YWNrcy9CYXNlQXBwbGljYXRpb25TdGFjay50c2AgfCBCYXNlIHN0YWNrIHdpdGggQVBJLCBzdGF0aWMgd2Vic2l0ZSwgRGF0YWRvZywgYW5kIFJvdXRlIDUzIHdpcmVkIHVwIHwnLFxuICAgICd8IGBzcmMvc3RhY2tzL0dpdEh1YlJvbGVzU3RhY2sudHNgIHwgSUFNIHJvbGUgc3RhY2sgZm9yIEdpdEh1YiBBY3Rpb25zIE9JREMgYXV0aGVudGljYXRpb24gfCcsXG4gICAgJ3wgYHNyYy9jb25zdHJ1Y3RzL0FwaS50c2AgfCBBUEkgR2F0ZXdheSArIExhbWJkYSBjb25zdHJ1Y3Qgd2l0aCBDbGVyayBKV1QgYXV0aG9yaXplciB8JyxcbiAgICAnfCBgc3JjL2NvbnN0cnVjdHMvU3RhdGljV2Vic2l0ZS50c2AgfCBDbG91ZEZyb250ICsgUzMgKyBBQ00gKyBSb3V0ZSA1MyBjb25zdHJ1Y3QgfCcsXG4gICAgJ3wgYHNyYy9jb25zdHJ1Y3RzL2hhbmRsZXIvQXBpLkZ1bmN0aW9uLnRzYCB8IExhbWJkYSBoYW5kbGVyIGVudHJ5IHBvaW50LCBiYXNpYyB3cmFwcGVyIGFyb3VuZCBFeHByZXNzLWNvbXBhdGlibGUgYXBwIGNvZGUgfCcsXG4gICAgJ3wgYHNyYy9hc3BlY3RzL0RhdGFEb2dBc3BlY3QudHNgIHwgQ0RLIGFzcGVjdCB0aGF0IHdpcmVzIGFsbCBMYW1iZGEgZnVuY3Rpb25zIHRvIERhdGFkb2cgfCcsXG4gICAgJycsXG4gICAgJyMjIyBGcm9udGVuZCAoYHdlYi9gKScsXG4gICAgJycsXG4gICAgJ3wgRmlsZSB8IERlc2NyaXB0aW9uIHwnLFxuICAgICd8LS0tLS0tfC0tLS0tLS0tLS0tLS18JyxcbiAgICAnfCBgd2ViL3NyYy9tYWluLnRzeGAgfCBSZWFjdCBhcHAgZW50cnkgcG9pbnQgd2l0aCBDbGVyayBhbmQgUmVhY3QgUXVlcnkgcHJvdmlkZXJzIHwnLFxuICAgICd8IGB3ZWIvc3JjL0FwcC50c3hgIHwgUm9vdCBhcHBsaWNhdGlvbiBjb21wb25lbnQgfCcsXG4gICAgJ3wgYHdlYi9zcmMvQXBwLmNzc2AgLyBgd2ViL3NyYy9pbmRleC5jc3NgIHwgQmFzZSBzdHlsZXNoZWV0cyAoVGFpbHdpbmQgQ1NTIHY0KSB8JyxcbiAgICAnfCBgd2ViL3NyYy9jb25maWcudHNgIHwgYHVzZUNvbmZpZygpYCBob29rIOKAlCBsb2FkcyBydW50aW1lIGNvbmZpZyBmcm9tIGBjb25maWcuanNvbmAgfCcsXG4gICAgJ3wgYHdlYi9zcmMvc2VydmljZXMvQXBpU2VydmljZS50c2AgfCBgdXNlQXBpUXVlcnkoKWAgLyBgdXNlQXBpTXV0YXRpb24oKWAg4oCUIGF1dGhlbnRpY2F0ZWQgQVBJIGhvb2tzLCBjYWNoZWQgcGVyIHBhdGggfCcsXG4gICAgJ3wgYHdlYi9zcmMvaGVscGVycy9gIHwgYHJlcXVlc3RzLnRzYCwgYEh0dHBFcnJvci50c2AsIGBlcnJvcnMudHNgLCBgcmV0cnkudHNgIOKAlCB0aGUgcmVxdWVzdCBhbmQgZXJyb3IgaGVscGVycyBgQXBpU2VydmljZWAgaXMgYnVpbHQgb24gfCcsXG4gICAgJ3wgYHdlYi9wdWJsaWMvY29uZmlnLmpzb25gIHwgUnVudGltZSBjb25maWcgKEFQSSBiYXNlIFVSTCwgQ2xlcmsgcHVibGlzaGFibGUga2V5KSB8JyxcbiAgICAuLi4oZTJlVGVzdGluZyA/IFtcbiAgICAgICd8IGB3ZWIvcGxheXdyaWdodC5jb25maWcudHNgIHwgUGxheXdyaWdodCBlMmUgY29uZmlnIOKAlCBzZWUgYHdlYi9lMmUvUkVBRE1FLm1kYCB8JyxcbiAgICAgIGB8IFxcYHdlYi9lMmUvXFxgIHwgUGxheXdyaWdodCBlMmUgc3VpdGUgKFxcYCR7dGVzdEUyZUNvbW1hbmR9XFxgKTsgYWxzbyBydW4gaW4gQ0kgYWdhaW5zdCBlYWNoIFBSJ3MgZGVwbG95ZWQgVVJMIHxgLFxuICAgIF0gOiBbXSksXG4gICAgJycsXG4gICAgJyMjIyBHaXRIdWIgQWN0aW9ucyBXb3JrZmxvd3MgKGAuZ2l0aHViL3dvcmtmbG93cy9gKScsXG4gICAgJycsXG4gICAgJ3wgRmlsZSB8IFRyaWdnZXIgfCcsXG4gICAgJ3wtLS0tLS18LS0tLS0tLS0tfCcsXG4gICAgJ3wgYHByLWRlcGxveS55bWxgIHwgT24gcHVsbCByZXF1ZXN0IG9wZW4vdXBkYXRlIOKAlCBkZXBsb3lzIGEgcGVyLVBSIGRldiBzdGFjayB8JyxcbiAgICAnfCBgcHItY2xlYW51cC55bWxgIHwgT24gcHVsbCByZXF1ZXN0IGNsb3NlIOKAlCB0ZWFycyBkb3duIHRoZSBwZXItUFIgZGV2IHN0YWNrIHwnLFxuICAgICd8IGBzdGFnaW5nLWRlcGxveS55bWxgIHwgT24gcHVzaCB0byBgbWFpbmAsIG9yIG1hbnVhbGx5IHRyaWdnZXJlZCDigJQgZGVwbG95cyB0byBzdGFnaW5nIHwnLFxuICAgIC4uLihwckF1dG9NZXJnZSA/IFtcbiAgICAgICd8IGBwci1hdXRvLW1lcmdlLnltbGAgfCBPbiBwdWxsIHJlcXVlc3Qgb3Blbi9yZW9wZW4vcmVhZHkgZm9yIHJldmlldyDigJQgdHVybnMgb24gc3F1YXNoIGF1dG8tbWVyZ2Ugd2l0aCBhIEdpdEh1YiBBcHAgdG9rZW4gfCcsXG4gICAgXSA6IFtdKSxcbiAgICAnfCBgcHJvZHVjdGlvbi1kZXBsb3kueW1sYCB8IE1hbnVhbGx5IHRyaWdnZXJlZCDigJQgZGVwbG95cyB0byBwcm9kdWN0aW9uIHwnLFxuICAgICcnLFxuICAgICctLS0nLFxuICAgICcnLFxuICAgICcjIyBGaWxlcyBZb3UgQ2FuIEVkaXQnLFxuICAgICcnLFxuICAgICdUaGVzZSBmaWxlcyBhcmUgZ2VuZXJhdGVkIG9uY2UgYW5kIG5ldmVyIG92ZXJ3cml0dGVuIGJ5IEJhdG1hbi4gTW9kaWZ5IHRoZW0gZnJlZWx5LicsXG4gICAgJycsXG4gICAgJ3wgRmlsZSB8IFdoYXQgdG8gZG8gd2l0aCBpdCB8JyxcbiAgICAnfC0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLXwnLFxuICAgICd8IGAucHJvamVucmMudHMgfCBUaGUgbWFpbiBQcm9qZW4gY29uZmlndXJhdGlvbiBmaWxlLiBBZGRpdGlvbmFsIGRlcGVuZGVuY2llcyBmb3IgZWl0aGVyIHRoZSBBUEkgb3IgdGhlIFdlYiBmcm9udGVuZCBuZWVkIHRvIGJlIGFkZGVkIGhlcmUgfCcsXG4gICAgJ3wgYHNyYy9zdGFja3MvQXBwbGljYXRpb25TdGFjay50c2AgfCAqKlN0YXJ0IGhlcmUuKiogQWRkIENESyBjb25zdHJ1Y3RzIHRvIGJ1aWxkIHlvdXIgaW5mcmFzdHJ1Y3R1cmUgfCcsXG4gICAgJ3wgYHNyYy9hcGkvYXBwLnRzIHwgVGhlIG1haW4gbW9ub2xpdGhpYyBBUEkgUkVTVCBzZXJ2ZXIgZmlsZS4gTWFpbiBmaWxlIHlvdSBzaG91bGQgYmUgbW9kaWZ5aW5nIHwnLFxuICAgICd8IGB3ZWIvc3JjL0FwcC50c3hgIHwgQnVpbGQgeW91ciBVSSBoZXJlIHwnLFxuICAgICd8IGB3ZWIvc3JjL0FwcC5jc3NgIC8gYHdlYi9zcmMvaW5kZXguY3NzYCB8IFN0eWxlIHlvdXIgYXBwbGljYXRpb24gfCcsXG4gICAgJ3wgYHdlYi9zcmMvbWFpbi50c3hgIHwgQWRqdXN0IHRvcC1sZXZlbCBwcm92aWRlcnMgb3Igcm91dGluZyB8JyxcbiAgICAnfCBgd2ViL3NyYy9zZXJ2aWNlcy9BcGlTZXJ2aWNlLnRzYCAvIGB3ZWIvc3JjL2hlbHBlcnMvYCB8IEFkZCBBUEkgc2VydmljZSBob29rcyBhbG9uZ3NpZGUgYEFwaVNlcnZpY2UudHNgLCBvciBhZGp1c3QgdGhlIHJlcXVlc3QgaGVscGVycyB8JyxcbiAgICAnfCBgd2ViL3B1YmxpYy9jb25maWcuanNvbmAgfCBVcGRhdGUgZm9yIGxvY2FsIGRldmVsb3BtZW50IChBUEkgVVJMLCBDbGVyayBrZXkpIHwnLFxuICAgIC4uLihlMmVUZXN0aW5nID8gW1xuICAgICAgJ3wgYHdlYi9wbGF5d3JpZ2h0LmNvbmZpZy50c2AgLyBgd2ViL2UyZS9gIHwgUGxheXdyaWdodCBlMmUgc3VpdGUg4oCUIGV4dGVuZCBpdCB3aXRoIHJlYWwgZmxvd3M7IHNlZSBgd2ViL2UyZS9SRUFETUUubWRgIHwnLFxuICAgIF0gOiBbXSksXG4gICAgJycsXG4gICAgJyMjIEZpbGVzIFlvdSBDYW5ub3QgRWRpdCcsXG4gICAgJycsXG4gICAgJ1RoZXNlIGZpbGVzIGFyZSAqKm1hbmFnZWQgYnkgQmF0bWFuKiogYW5kIHdpbGwgYmUgb3ZlcndyaXR0ZW4gZXZlcnkgdGltZSBgbnB4IHByb2plbmAgcnVucy4gRG8gbm90IGVkaXQgdGhlbSBkaXJlY3RseSDigJQgbWFrZSBjaGFuZ2VzIGluIGAucHJvamVucmMudHNgIGluc3RlYWQuJyxcbiAgICAnJyxcbiAgICAnPiBbIUlNUE9SVEFOVF0nLFxuICAgICc+IElmIHlvdSBoYXZlIEFOWSBjaGFuZ2VzIHlvdSB3YW50IHRvIG1ha2UgdG8gdGhlc2UgZmlsZXMsIG5vdGlmeSAjdGVhbS1iYXRtYW4gb24gU2xhY2suICcsXG4gICAgJz4gV2UgbWFpbnRhaW4gdGhlc2UgZmlsZXMgYXMgcGFydCBvZiB0aGUgY29yZSBCYXRtYW4gZXhwZXJpZW5jZSwgYW5kIHlvdXIgZmVlZGJhY2sgaXMgY3J1Y2lhbCB0byBlbnN1cmUgdGhleSBtZWV0IHlvdXIgbmVlZHMuJyxcbiAgICAnJyxcbiAgICAnfCBGaWxlIHwgV2h5IGl0XFwncyBtYW5hZ2VkIHwnLFxuICAgICd8LS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tfCcsXG4gICAgJ3wgYHNyYy9zdGFja3MvQmFzZUFwcGxpY2F0aW9uU3RhY2sudHNgIHwgQ29yZSBzdGFjayB3aXJpbmcg4oCUIHVwZGF0ZWQgd2l0aCBCYXRtYW4gcmVsZWFzZXMgfCcsXG4gICAgJ3wgYHNyYy9hc3BlY3RzL0RhdGFEb2dBc3BlY3QudHNgIHwgRGF0YWRvZyBDREsgYXNwZWN0IHwnLFxuICAgICd8IGB3ZWIvdml0ZS5jb25maWcudHNgIHwgVml0ZSBjb25maWd1cmF0aW9uIHwnLFxuICAgICd8IGB3ZWIvZXNsaW50LmNvbmZpZy5qc2AgfCBFU0xpbnQgY29uZmlndXJhdGlvbiB8JyxcbiAgICAnfCBgd2ViL3Bvc3Rjc3MuY29uZmlnLmpzYCB8IFBvc3RDU1MgLyBUYWlsd2luZCBjb25maWd1cmF0aW9uIHwnLFxuICAgICd8IGB3ZWIvaW5kZXguaHRtbGAgfCBIVE1MIGVudHJ5IHBvaW50IHwnLFxuICAgICd8IGB3ZWIvdHNjb25maWcuanNvbmAgLyBgd2ViL3RzY29uZmlnLmFwcC5qc29uYCAvIGB3ZWIvdHNjb25maWcubm9kZS5qc29uYCB8IFR5cGVTY3JpcHQgY29uZmlndXJhdGlvbiB8JyxcbiAgICAnfCBgd2ViL3NyYy92aXRlLWVudi5kLnRzYCB8IFZpdGUgdHlwZSBkZWNsYXJhdGlvbnMgfCcsXG4gICAgJ3wgYHdlYi9zcmMvY29uZmlnLnRzYCB8IFJ1bnRpbWUgY29uZmlnIGhvb2sg4oCUIHNoYXBlIGRyaXZlbiBieSBgLnByb2plbnJjLnRzYCB8JyxcbiAgICAnfCBgLmdpdGh1Yi9DT0RFT1dORVJTYCB8IENvZGUgb3duZXJzaGlwIHBvbGljeSB8JyxcbiAgICAnfCBgLmdpdGh1Yi93b3JrZmxvd3MvKi55bWxgIHwgQWxsIENJL0NEIHdvcmtmbG93cyB8JyxcbiAgICAnfCBgYXJjaGl0ZWN0dXJlLXJ1bGVzL2NoZWNrLnRzYCwgYHRzY29uZmlnLmpzb25gLCBgUkVBRE1FLm1kYCB8IEFyY2hpdGVjdHVyZSBydWxlIGVuZ2luZSB8JyxcbiAgICAnfCBgYXR0ZXN0YXRpb24vbWFuaWZlc3QudHNgLCBgdmVyaWZ5LnRzYCwgYHRzY29uZmlnLmpzb25gIHwgUFIgYXR0ZXN0YXRpb24gbWVjaGFuaXNtIHwnLFxuICAgICd8IGBvcGVuc3BlYy1nYXRlcy9jaGVjay10YXNrcy1jb21wbGV0ZS50c2AsIGB0c2NvbmZpZy5qc29uYCB8IE9wZW5TcGVjIHRhc2stY29tcGxldGlvbiBnYXRlIHwnLFxuICAgICd8IGBzd2FtcC1ib290c3RyYXAvcHVsbC1leHRlbnNpb25zLnRzYCwgYHRzY29uZmlnLmpzb25gIHwgUHVsbHMgc3dhbXAgZXh0ZW5zaW9ucyBhdCB0aGVpciBwaW5uZWQgdmVyc2lvbnMgfCcsXG4gICAgJ3wgYHdvcmtmbG93cy93b3JrZmxvdy0qLnlhbWxgIHwgU3dhbXAgd29ya2Zsb3dzIHRoZSBzb2Z0d2FyZSBmYWN0b3J5IHJ1bnMgfCcsXG4gICAgJ3wgYGZhY3Rvcnkvd29yay1pdGVtLXNvdXJjZXMubWRgIHwgSG93IHRoZSBzb2Z0d2FyZSBmYWN0b3J5IHJlc29sdmVzIGEgd29yay1pdGVtIElEIHRvIGl0cyB0cmFja2VyIHwnLFxuICAgICcnLFxuICAgICc+ICoqVGlwOioqIEZpbGVzIHdpdGggYSBgfn4gR2VuZXJhdGVkIGJ5IHByb2plbi4gVG8gbW9kaWZ5LCBlZGl0IC5wcm9qZW5yYy50cyBhbmQgcnVuIFwibnB4IHByb2plblwiLiB+fmAgaGVhZGVyIGFyZSBtYW5hZ2VkIGZpbGVzLicsXG4gICAgJycsXG4gICAgJyMjIyBTb2Z0d2FyZSBGYWN0b3J5IChgbW9kZWxzL2AsIGBhcmNoaXRlY3R1cmUtcnVsZXMvcnVsZXMuanNvbmApJyxcbiAgICAnJyxcbiAgICAnQmF0bWFuIGFsc28gc2VlZHMgYSBbc3dhbXBdKGh0dHBzOi8vZ2l0aHViLmNvbS9zd2FtcC1jbHViL3N3YW1wKSBzb2Z0d2FyZScsXG4gICAgJ2ZhY3Rvcnkg4oCUIGEgYEBzd2FtcC9zb2Z0d2FyZS1mYWN0b3J5YCBzdGF0ZSBtYWNoaW5lIHRoYXQgZHJpdmVzIGEgd29yayBpdGVtJyxcbiAgICAnKGEgR2l0SHViIGlzc3VlIG51bWJlciB0b2RheSkgdGhyb3VnaCBpbnRha2UsIE9wZW5TcGVjIHBsYW5uaW5nLCcsXG4gICAgJ2ltcGxlbWVudGF0aW9uLCBwcmUtUFIgdmVyaWZpY2F0aW9uLCBhbmQgYW4gb3BlbmVkIFBSLiBJbnRha2UgcmVzb2x2ZXMgdGhlJyxcbiAgICAnd29yayBpdGVtIHRocm91Z2ggdGhlIG1hbmFnZWQgYGZhY3Rvcnkvd29yay1pdGVtLXNvdXJjZXMubWRgLiBUaGUgc2VlZCcsXG4gICAgJ2ZpbGVzIHVuZGVyIGBtb2RlbHMvKiovKi55YW1sYCBhbmQgYGFyY2hpdGVjdHVyZS1ydWxlcy9ydWxlcy5qc29uYCBhcmUnLFxuICAgICdnZW5lcmF0ZWQgb25jZSAobGlrZSB0aGUgZmlsZXMgaW4nLFxuICAgICdcIkZpbGVzIFlvdSBDYW4gRWRpdFwiIGFib3ZlKSDigJQgdHVuZSB0aGUgZmFjdG9yeVxcJ3Mgc3RhZ2VzL2dhdGVzIG9yIGFkZCB5b3VyJyxcbiAgICAnb3duIGFyY2hpdGVjdHVyZSBydWxlcyBkaXJlY3RseSBpbiB0aG9zZSBmaWxlcy4nLFxuICAgICcnLFxuICAgICdgc3dhbXAgaW5pdGAgcnVucyBhdXRvbWF0aWNhbGx5IGFzIHBhcnQgb2YgYGluc3RhbGxgL2BpbnN0YWxsOmNpYCAoYSBzaWxlbnQnLFxuICAgICduby1vcCBpZiBgc3dhbXBgIGlzblxcJ3Qgb24gUEFUSCwgZS5nLiBpbiBDSSksIHNvIHRoZSByZXBvIHN0YXlzIGluaXRpYWxpemVkJyxcbiAgICAnd2l0aG91dCBhIHNlcGFyYXRlIHN0ZXAuJyxcbiAgICAnJyxcbiAgICAnYHN3YW1wVmVyc2lvbmAgaW4gYC5zd2FtcC55YW1sYCBpcyB0aGUgbWluaW11bSBzd2FtcCBDTEkgdGhlIHJlcG8gbmVlZHM6IHRoZScsXG4gICAgJ3ZlcnNpb24gaXQgd2FzIGxhc3QgdXBncmFkZWQgd2l0aC4gc3dhbXAgZG9lc25cXCd0IGtlZXAgb2xkIGJ1aWxkcywgc28gaW5zdGFsbCcsXG4gICAgJ3RoZSBjdXJyZW50IGBzdGFibGVgIHJlbGVhc2UgcmF0aGVyIHRoYW4gdGhhdCBleGFjdCB2ZXJzaW9uOicsXG4gICAgJycsXG4gICAgJ2BgYGJhc2gnLFxuICAgICcjIG1hY09TIC8gTGludXgnLFxuICAgICdjdXJsIC1mc1NMIGh0dHBzOi8vc3dhbXAuY2x1Yi9pbnN0YWxsLnNoIHwgc2gnLFxuICAgICcnLFxuICAgICcjIFdpbmRvd3MgKFBvd2VyU2hlbGwpJyxcbiAgICAnaXJtIGh0dHBzOi8vc3dhbXAuY2x1Yi9pbnN0YWxsLnBzMSB8IGlleCcsXG4gICAgJ2BgYCcsXG4gICAgJycsXG4gICAgJ09uZS10aW1lIHNldHVwIGJleW9uZCB0aGF0LCBhZnRlciB5b3VyIGZpcnN0IGBucHggcHJvamVuYDonLFxuICAgICcnLFxuICAgICdgYGBiYXNoJyxcbiAgICAnIyBQdWxscyBlYWNoIGV4dGVuc2lvbiBhdCB0aGUgdmVyc2lvbiBwaW5uZWQgaW4nLFxuICAgICcjIGV4dGVuc2lvbnMvbW9kZWxzL3Vwc3RyZWFtX2V4dGVuc2lvbnMuanNvbiAob3IgdGhlIGxhdGVzdCcsXG4gICAgJyMgc29mdHdhcmUtZmFjdG9yeS9naXRodWIgZXh0ZW5zaW9ucyBpbiBhIHJlcG8gd2l0aCBubyBsb2NrZmlsZSB5ZXQpLCcsXG4gICAgJyMgcmVzdG9yZXMgdGhlIGxvY2tmaWxlIGFuZCBjb21taXR0ZWQgc2tpbGwgZmlsZXMgZnJvbSBnaXQsIGFuZCBjcmVhdGVzIHRoZScsXG4gICAgJyMgcmVwb1xcJ3Mgc2VjcmV0cyB2YXVsdCcsXG4gICAgJ25weCBwcm9qZW4gc3dhbXA6Ym9vdHN0cmFwJyxcbiAgICAnJyxcbiAgICAnIyBUaGVuIHN0b3JlIGEgR2l0SHViIHRva2VuIHRoZSBmYWN0b3J5IGNhbiBvcGVuIFBScyB3aXRoJyxcbiAgICAnc3dhbXAgdmF1bHQgcHV0IDxyZXBvPi1zZWNyZXRzIEdJVEhVQl9UT0tFTiAtLXJlZnJlc2gtZnJvbSBcImdoIGF1dGggdG9rZW5cIicsXG4gICAgJ2BgYCcsXG4gICAgJycsXG4gICAgJy0tLScsXG4gICAgJycsXG4gICAgJyMjIFdoZXJlIHRvIFN0YXJ0JyxcbiAgICAnJyxcbiAgICAnMS4gKipgc3JjL3N0YWNrcy9BcHBsaWNhdGlvblN0YWNrLnRzYCoqIOKAlCBBZGQgeW91ciBDREsgY29uc3RydWN0cyBoZXJlLiBUaGUgYmFzZSBzdGFjayBhbHJlYWR5IHByb3ZpZGVzIGB0aGlzLmFwaWAsIGB0aGlzLmhvc3RlZFpvbmVgLCBgdGhpcy5kYXRhZG9nYCwgYW5kICh3aGVuIHRoZSBzdGFjayBjcmVhdGVzIG9uZSkgYHRoaXMudnBjYCBhcyBwcm90ZWN0ZWQgcHJvcGVydGllcy4nLFxuICAgICcnLFxuICAgICcyLiAqKmB3ZWIvYCoqIOKAlCBCdWlsZCB5b3VyIGZyb250ZW5kLiBTdGFydCB3aXRoIGB3ZWIvc3JjL0FwcC50c3hgIGFuZCBhZGQgc2VydmljZXMgYWxvbmdzaWRlIGB3ZWIvc3JjL3NlcnZpY2VzL0FwaVNlcnZpY2UudHNgLicsXG4gICAgJycsXG4gICAgJzMuICoqYHNyYy9hcGkvYXBwLnRzYCoqIOKAlCBJbXBsZW1lbnQgeW91ciBiYWNrZW5kIExhbWJkYSBoYW5kbGVyIGxvZ2ljIGhlcmUuJyxcbiAgICAnJyxcbiAgICAnNC4gKipgLnByb2plbnJjLnRzYCoqIC0gTWFuYWdlcyBwcm9qZWN0IGRlcGVuZGVuY2llcyBhbmQgY29uZmlndXJhdGlvbi4gUnVuIGBucHggcHJvamVuYCBhZnRlciBtYWtpbmcgYW55IGNoYW5nZXMgdG8gdGhpcyBmaWxlLicsXG4gICAgJy0tLScsXG4gICAgJycsXG4gICAgJyMjIERldmVsb3BtZW50IFdvcmtmbG93JyxcbiAgICAnJyxcbiAgICAnYGBgYmFzaCcsXG4gICAgJyMgSW5zdGFsbCBkZXBlbmRlbmNpZXMnLFxuICAgICd5YXJuIGluc3RhbGwnLFxuICAgICcnLFxuICAgICcjIFN0YXJ0IGxvY2FsIGRldiBzZXJ2ZXIgKGJhY2tlbmQgTGFtYmRhICsgVml0ZSBmcm9udGVuZCBpbiBwYXJhbGxlbCknLFxuICAgICd5YXJuIGRldicsXG4gICAgJycsXG4gICAgJyMgRGVwbG95IGEgcGVyc29uYWwgZGV2IHN0YWNrIHRvIEFXUyBhcyBhbiBhbHRlcm5hdGl2ZSB0byBsb2NhbCBkZXZlbG9wbWVudCwgcHJvdmlkZXMgbW9yZSB0aG9yb3VnaCBlbmQtdG8tZW5kIHRlc3RpbmcnLFxuICAgICd5YXJuIGNkazpkZXYgLS1jb250ZXh0IGxvY2FsLWRldi1wcmVmaXg9eW91ci1oYW5kbGUgZGVwbG95JyxcbiAgICAnJyxcbiAgICAnIyBSZWRlcGxveSB5b3VyIHBlcnNvbmFsIGRldiBzdGFjayBmYXN0OiBhZnRlciB0aGUgZmlyc3QgZGVwbG95IGFib3ZlLCBrZWVwJyxcbiAgICBcIiMgcmV1c2luZyB0aGUgc2FtZSBzdGFjayAoZG9uJ3QgZGVsZXRlIGl0IGJldHdlZW4gYnJhbmNoZXMpIGFuZCBpdGVyYXRlIHdpdGhcIixcbiAgICAnIyBob3Rzd2FwLWZhbGxiYWNrIGluc3RlYWQgb2YgYSBmdWxsIENsb3VkRm9ybWF0aW9uIGRlcGxveW1lbnQnLFxuICAgICd5YXJuIGNkazpkZXY6aG90c3dhcCAtLWNvbnRleHQgbG9jYWwtZGV2LXByZWZpeD15b3VyLWhhbmRsZScsXG4gICAgJycsXG4gICAgJyMgUnVuIHRlc3RzJyxcbiAgICAneWFybiB0ZXN0JyxcbiAgICAnJyxcbiAgICAnIyBSZS1zeW50aGVzaXplIHByb2plY3QgZmlsZXMgYWZ0ZXIgZWRpdGluZyAucHJvamVucmMudHMnLFxuICAgICducHggcHJvamVuJyxcbiAgICAnYGBgJyxcbiAgICAnJyxcbiAgICAnPiBbIUlNUE9SVEFOVF0nLFxuICAgICc+IGAtLWhvdHN3YXAtZmFsbGJhY2tgICh1c2VkIGJ5IGBjZGs6ZGV2OmhvdHN3YXBgIGFuZCB0aGUgYHdhdGNoYCB0YXNrKSBpcyBmb3InLFxuICAgICc+IHBlcnNvbmFsIGRldiBzdGFja3Mgb25seSDigJQgbmV2ZXIgcnVuIGl0IGFnYWluc3Qgc3RhZ2luZyBvciBwcm9kLicsXG4gICAgJycsXG4gICAgJy0tLScsXG4gICAgJycsXG4gICAgJyMjIFVwZ3JhZGluZyBCYXRtYW4nLFxuICAgICcnLFxuICAgICdgYGBiYXNoJyxcbiAgICAneWFybiBhZGQgQG1hY2Vkb24tdGVjaG5vbG9naWVzL2JhdG1hbkBsYXRlc3QnLFxuICAgICducHggcHJvamVuJyxcbiAgICAnYGBgJyxcbiAgICAnJyxcbiAgICAnVGhpcyB1cGRhdGVzIGFsbCBtYW5hZ2VkIGZpbGVzIHRvIHRoZSBsYXRlc3QgQmF0bWFuIHN0YW5kYXJkcy4gWW91ciBlZGl0YWJsZSBzYW1wbGUgZmlsZXMgYXJlIG5ldmVyIHRvdWNoZWQuJyxcbiAgXS5qb2luKCdcXG4nKTtcbn1cbiJdfQ==
|
|
328
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFLQSw0Q0FZQztBQU1ELHdDQVdDO0FBV0QsNERBT0M7QUFVRCxzREFFQztBQU9ELDREQUVDO0FBRUQsa0NBZ0JDO0FBRUQsd0NBME9DO0FBdlVELHNEQUEyRDtBQUUzRDs7R0FFRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLGNBQWtDLEVBQUUsTUFBYztJQUNqRixRQUFRLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLEtBQUssK0JBQWtCLENBQUMsR0FBRztZQUN6QixPQUFPLFdBQVcsTUFBTSxFQUFFLENBQUM7UUFDN0IsS0FBSywrQkFBa0IsQ0FBQyxHQUFHO1lBQ3pCLE9BQU8sV0FBVyxNQUFNLEVBQUUsQ0FBQztRQUM3QixLQUFLLCtCQUFrQixDQUFDLElBQUk7WUFDMUIsT0FBTyxRQUFRLE1BQU0sRUFBRSxDQUFDO1FBQzFCO1lBQ0Usb0ZBQW9GO1lBQ3BGLE9BQU8sUUFBUSxNQUFNLEVBQUUsQ0FBQztJQUM1QixDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLGNBQWMsQ0FBQyxjQUFrQztJQUMvRCxRQUFRLGNBQWMsRUFBRSxDQUFDO1FBQ3ZCLEtBQUssK0JBQWtCLENBQUMsR0FBRztZQUN6QixPQUFPLFFBQVEsQ0FBQztRQUNsQixLQUFLLCtCQUFrQixDQUFDLEdBQUc7WUFDekIsT0FBTywrQkFBK0IsQ0FBQztRQUN6QyxLQUFLLCtCQUFrQixDQUFDLElBQUk7WUFDMUIsT0FBTyxnQ0FBZ0MsQ0FBQztRQUMxQztZQUNFLE9BQU8sZ0NBQWdDLENBQUM7SUFDNUMsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILFNBQWdCLHdCQUF3QjtJQUN0QyxPQUFPO1FBQ0wsbUdBQW1HO1FBQ25HLG9EQUFvRDtRQUNwRCwrQ0FBK0M7UUFDL0MsSUFBSTtLQUNMLENBQUM7QUFDSixDQUFDO0FB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QUNGLEtBQUs7UUFDTCxFQUFFO1FBQ0YsbUJBQW1CO1FBQ25CLEVBQUU7UUFDRiw2TkFBNk47UUFDN04sRUFBRTtRQUNGLGdJQUFnSTtRQUNoSSxFQUFFO1FBQ0YsNkVBQTZFO1FBQzdFLEVBQUU7UUFDRixpSUFBaUk7UUFDakksS0FBSztRQUNMLEVBQUU7UUFDRix5QkFBeUI7UUFDekIsRUFBRTtRQUNGLFNBQVM7UUFDVCx3QkFBd0I7UUFDeEIsY0FBYztRQUNkLEVBQUU7UUFDRix1RUFBdUU7UUFDdkUsVUFBVTtRQUNWLEVBQUU7UUFDRix3SEFBd0g7UUFDeEgsNERBQTREO1FBQzVELEVBQUU7UUFDRiw2RUFBNkU7UUFDN0UsOEVBQThFO1FBQzlFLGdFQUFnRTtRQUNoRSw2REFBNkQ7UUFDN0QsRUFBRTtRQUNGLGFBQWE7UUFDYixXQUFXO1FBQ1gsRUFBRTtRQUNGLDBEQUEwRDtRQUMxRCxZQUFZO1FBQ1osS0FBSztRQUNMLEVBQUU7UUFDRixnQkFBZ0I7UUFDaEIsZ0ZBQWdGO1FBQ2hGLG9FQUFvRTtRQUNwRSxFQUFFO1FBQ0YsS0FBSztRQUNMLEVBQUU7UUFDRixxQkFBcUI7UUFDckIsRUFBRTtRQUNGLFNBQVM7UUFDVCw4Q0FBOEM7UUFDOUMsWUFBWTtRQUNaLEtBQUs7UUFDTCxFQUFFO1FBQ0YsOEdBQThHO0tBQy9HLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ2YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5vZGVQYWNrYWdlTWFuYWdlciB9IGZyb20gJ3Byb2plbi9saWIvamF2YXNjcmlwdCc7XG5cbi8qKlxuICogUmVuZGVycyB0aGUgY29tbWFuZCB1c2VkIHRvIHJ1biBhIHBhY2thZ2UuanNvbiBzY3JpcHQgZm9yIHRoZSBnaXZlbiBwYWNrYWdlIG1hbmFnZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBydW5TY3JpcHRDb21tYW5kKHBhY2thZ2VNYW5hZ2VyOiBOb2RlUGFja2FnZU1hbmFnZXIsIHNjcmlwdDogc3RyaW5nKTogc3RyaW5nIHtcbiAgc3dpdGNoIChwYWNrYWdlTWFuYWdlcikge1xuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLk5QTTpcbiAgICAgIHJldHVybiBgbnBtIHJ1biAke3NjcmlwdH1gO1xuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLkJVTjpcbiAgICAgIHJldHVybiBgYnVuIHJ1biAke3NjcmlwdH1gO1xuICAgIGNhc2UgTm9kZVBhY2thZ2VNYW5hZ2VyLlBOUE06XG4gICAgICByZXR1cm4gYHBucG0gJHtzY3JpcHR9YDtcbiAgICBkZWZhdWx0OlxuICAgICAgLy8gYWxsIHlhcm4gdmFyaWFudHMgKHlhcm4sIHlhcm4yLCB5YXJuX2NsYXNzaWMsIHlhcm5fYmVycnkpIHNoYXJlIHRoZSBgeWFybmAgYmluYXJ5XG4gICAgICByZXR1cm4gYHlhcm4gJHtzY3JpcHR9YDtcbiAgfVxufVxuXG4vKipcbiAqIFJlbmRlcnMgdGhlIGNvbW1hbmQgdXNlZCB0byBkbyBhIGNsZWFuLCByZXByb2R1Y2libGUgZGVwZW5kZW5jeSBpbnN0YWxsIChlLmcuIGZvciBDSSlcbiAqIGZvciB0aGUgZ2l2ZW4gcGFja2FnZSBtYW5hZ2VyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaW5zdGFsbENvbW1hbmQocGFja2FnZU1hbmFnZXI6IE5vZGVQYWNrYWdlTWFuYWdlcik6IHN0cmluZyB7XG4gIHN3aXRjaCAocGFja2FnZU1hbmFnZXIpIHtcbiAgICBjYXNlIE5vZGVQYWNrYWdlTWFuYWdlci5OUE06XG4gICAgICByZXR1cm4gJ25wbSBjaSc7XG4gICAgY2FzZSBOb2RlUGFja2FnZU1hbmFnZXIuQlVOOlxuICAgICAgcmV0dXJuICdidW4gaW5zdGFsbCAtLWZyb3plbi1sb2NrZmlsZSc7XG4gICAgY2FzZSBOb2RlUGFja2FnZU1hbmFnZXIuUE5QTTpcbiAgICAgIHJldHVybiAncG5wbSBpbnN0YWxsIC0tZnJvemVuLWxvY2tmaWxlJztcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuICd5YXJuIGluc3RhbGwgLS1mcm96ZW4tbG9ja2ZpbGUnO1xuICB9XG59XG5cbi8qKlxuICogQmFzaCBsaW5lcyB0aGF0IHNhbml0aXplIGEgYENMRUFOX0JSQU5DSF9OQU1FYCB2YXJpYWJsZSAoYWxyZWFkeSBzdHJpcHBlZCBvZiBhbnlcbiAqIGNvbnZlbnRpb25hbC1jb21taXQgcHJlZml4KSBpbnRvIGEgdmFsdWUgc2FmZSB0byB1c2UgYXMgYSBDbG91ZEZvcm1hdGlvbiBzdGFjay1uYW1lXG4gKiBmcmFnbWVudDogY29sbGFwc2VzIHJ1bnMgb2Ygbm9uLWFscGhhbnVtZXJpYyBjaGFyYWN0ZXJzIHRvIGAtYCwgdHJpbXMgbGVhZGluZy90cmFpbGluZ1xuICogYC1gLCBhbmQgcHJlZml4ZXMgd2l0aCBgcHItYCBpZiB0aGUgcmVzdWx0IHdvdWxkIG5vdCBzdGFydCB3aXRoIGEgbGV0dGVyIChvciBpcyBlbXB0eSkuXG4gKlxuICogU2hhcmVkIGJ5IFByRGVwbG95V29ya2Zsb3cgYW5kIFByQ2xlYW51cFdvcmtmbG93IHNvIGJvdGggZGVyaXZlIHRoZSBpZGVudGljYWwgc3RhY2tcbiAqIG5hbWUgZm9yIGEgZ2l2ZW4gYnJhbmNoLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemVCcmFuY2hOYW1lU2NyaXB0KCk6IHN0cmluZ1tdIHtcbiAgcmV0dXJuIFtcbiAgICAnQ0xFQU5fQlJBTkNIX05BTUU9JChlY2hvIFwiJENMRUFOX0JSQU5DSF9OQU1FXCIgfCBzZWQgLUUgXFwncy9bXkEtWmEtejAtOV0rLy0vZzsgcy9eLSsvLzsgcy8tKyQvL1xcJyknLFxuICAgICdpZiBbWyAhIFwiJENMRUFOX0JSQU5DSF9OQU1FXCIgPX4gXltBLVphLXpdIF1dOyB0aGVuJyxcbiAgICAnICBDTEVBTl9CUkFOQ0hfTkFNRT1cInByLSR7Q0xFQU5fQlJBTkNIX05BTUV9XCInLFxuICAgICdmaScsXG4gIF07XG59XG5cbi8qKlxuICogSm9pbnMgY29tbWFuZHMgd2l0aCBgO2AgaW5zdGVhZCBvZiBgJiZgL2B8fGAgc28gdGhlIHJlc3VsdCBpcyB2YWxpZCBmb3IgYSBzd2FtcFxuICogY29tbWFuZC9zaGVsbCBtb2RlbCdzIGBydW46YCB2YWx1ZSBvbiBib3RoIFBPU0lYIHNoZWxscyBhbmQgV2luZG93cyBQb3dlclNoZWxsIDUuMVxuICogKHdoaWNoIGhhcyBubyBgJiZgL2B8fGAgY2hhaW4gb3BlcmF0b3JzIGJlZm9yZSBwd3NoIDcpLiBVbmxpa2UgYCYmYCwgYDtgIGRvZXMgbm90XG4gKiBzaG9ydC1jaXJjdWl0IG9uIGZhaWx1cmUg4oCUIGNhbGxlcnMgdGhhdCBuZWVkIGZhaWx1cmUgdG8gc3RvcCB0aGUgc2VxdWVuY2Ugc2hvdWxkIHNwbGl0XG4gKiBpbnRvIHNlcGFyYXRlIHdvcmtmbG93IHN0ZXBzIHdpdGggdGhlaXIgb3duIGBhc3NlcnRgIGdhdGVzIGluc3RlYWQgb2YgcmVseWluZyBvbiB0aGlzXG4gKiBmb3IgY29udHJvbCBmbG93LlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2hlbGxQb3J0YWJsZVNlcXVlbmNlKC4uLmNvbW1hbmRzOiBzdHJpbmdbXSk6IHN0cmluZyB7XG4gIHJldHVybiBjb21tYW5kcy5qb2luKCc7ICcpO1xufVxuXG4vKipcbiAqIFJlbmRlcnMgYSBwb3J0YWJsZSBmb3JjZS1kZWxldGUgZm9yIGEgc2luZ2xlIGZpbGUsIGZvciB1c2UgaW4gYSBzd2FtcCBjb21tYW5kL3NoZWxsXG4gKiBtb2RlbCdzIGBydW46YCB2YWx1ZSBpbiBwbGFjZSBvZiBgcm0gLWYgPHBhdGg+YCAoYW1iaWd1b3VzIHdpdGggUG93ZXJTaGVsbCA1LjEnc1xuICogYFJlbW92ZS1JdGVtIC1GaWx0ZXJgIGFsaWFzKS4gTWF0Y2hlcyB0aGUgZml4IGFscmVhZHkgdmFsaWRhdGVkIGluIGV4bWFuIzEzNi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNoZWxsUG9ydGFibGVGb3JjZURlbGV0ZShwYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gYG5vZGUgLWUgXCJyZXF1aXJlKCdmcycpLnJtU3luYygnJHtwYXRofScsIHsgZm9yY2U6IHRydWUgfSlcImA7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXJpYWxpemVUcyh2YWx1ZTogYW55LCBkZXB0aCA9IDEpOiBzdHJpbmcge1xuICBjb25zdCBwYWQgPSAnICAnLnJlcGVhdChkZXB0aCk7XG4gIGNvbnN0IGlubmVyUGFkID0gJyAgJy5yZXBlYXQoZGVwdGggKyAxKTtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHJldHVybiBgJyR7dmFsdWV9J2A7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nKSByZXR1cm4gU3RyaW5nKHZhbHVlKTtcbiAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgY29uc3QgaXRlbXMgPSB2YWx1ZS5tYXAodiA9PiBgJHtpbm5lclBhZH0ke3NlcmlhbGl6ZVRzKHYsIGRlcHRoICsgMSl9YCkuam9pbignLFxcbicpO1xuICAgIHJldHVybiBgW1xcbiR7aXRlbXN9LFxcbiR7cGFkfV1gO1xuICB9XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlICE9PSBudWxsKSB7XG4gICAgY29uc3QgZW50cmllcyA9IE9iamVjdC5lbnRyaWVzKHZhbHVlKVxuICAgICAgLm1hcCgoW2ssIHZdKSA9PiBgJHtpbm5lclBhZH0ke2t9OiAke3NlcmlhbGl6ZVRzKHYsIGRlcHRoICsgMSl9YClcbiAgICAgIC5qb2luKCcsXFxuJyk7XG4gICAgcmV0dXJuIGB7XFxuJHtlbnRyaWVzfSxcXG4ke3BhZH19YDtcbiAgfVxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVhZG1lQ29udGVudHMoXG4gIHByb2plY3ROYW1lOiBzdHJpbmcsXG4gIGUyZVRlc3RpbmcgPSB0cnVlLFxuICBwYWNrYWdlTWFuYWdlcjogTm9kZVBhY2thZ2VNYW5hZ2VyID0gTm9kZVBhY2thZ2VNYW5hZ2VyLllBUk5fQ0xBU1NJQyxcbiAgcHJBdXRvTWVyZ2UgPSBmYWxzZSxcbikge1xuICBjb25zdCB0ZXN0RTJlQ29tbWFuZCA9IHJ1blNjcmlwdENvbW1hbmQocGFja2FnZU1hbmFnZXIsICd0ZXN0OmUyZScpO1xuICByZXR1cm4gW1xuICAgIGAjICR7cHJvamVjdE5hbWV9YCxcbiAgICAnJyxcbiAgICAnVGhpcyBwcm9qZWN0IHdhcyBib290c3RyYXBwZWQgd2l0aCBbQmF0bWFuXShodHRwczovL2dpdGh1Yi5jb20vbWFjZWRvbi10ZWNobm9sb2dpZXMvcGxhdGZvcm0tY29tbW9uKS4nLFxuICAgICcnLFxuICAgICcjIyBXaGF0IEJhdG1hbiBDcmVhdGVkJyxcbiAgICAnJyxcbiAgICAnIyMjIENESyBJbmZyYXN0cnVjdHVyZSAoYHNyYy9gKScsXG4gICAgJycsXG4gICAgJ3wgRmlsZSB8IERlc2NyaXB0aW9uIHwnLFxuICAgICd8LS0tLS0tfC0tLS0tLS0tLS0tLS18JyxcbiAgICAnfCBgc3JjL21haW4udHNgIHwgQ0RLIGFwcCBlbnRyeSBwb2ludCDigJQgaW5zdGFudGlhdGVzIGRldiwgc3RhZ2luZywgYW5kIHByb2QgYEFwcGxpY2F0aW9uU3RhY2tgcyB8JyxcbiAgICAnfCBgc3JjL0xvY2FsRGV2QXBwLnRzYCB8IExvY2FsIGRldmVsb3BtZW50IENESyBhcHAg4oCUIHVzZWQgYnkgYHlhcm4gY2RrOmRldmAgLSBkZXBsb3lzIHRvIEFXUyBmb3Igc2xvd2VyIGJ1dCBtb3JlIHRob3JvdWdoIHRlc3RpbmcgfCcsXG4gICAgJ3wgYHNyYy9HaXRIdWJSb2xlcy50c2AgfCBDREsgYXBwIGZvciBkZXBsb3lpbmcgdGhlIEdpdEh1YiBPSURDIElBTSByb2xlIChvbmUtdGltZSBib290c3RyYXApIHwnLFxuICAgICd8IGBzcmMvc3RhY2tzL0FwcGxpY2F0aW9uU3RhY2sudHNgIHwgWW91ciBwcmltYXJ5IHN0YWNrIOKAlCBleHRlbmQgaXQgdG8gYWRkIHJlc291cmNlcyB8JyxcbiAgICAnfCBgc3JjL3N0YWNrcy9CYXNlQXBwbGljYXRpb25TdGFjay50c2AgfCBCYXNlIHN0YWNrIHdpdGggQVBJLCBzdGF0aWMgd2Vic2l0ZSwgRGF0YWRvZywgYW5kIFJvdXRlIDUzIHdpcmVkIHVwIHwnLFxuICAgICd8IGBzcmMvc3RhY2tzL0dpdEh1YlJvbGVzU3RhY2sudHNgIHwgSUFNIHJvbGUgc3RhY2sgZm9yIEdpdEh1YiBBY3Rpb25zIE9JREMgYXV0aGVudGljYXRpb24gfCcsXG4gICAgJ3wgYHNyYy9jb25zdHJ1Y3RzL0FwaS50c2AgfCBBUEkgR2F0ZXdheSArIExhbWJkYSBjb25zdHJ1Y3Qgd2l0aCBDbGVyayBKV1QgYXV0aG9yaXplciB8JyxcbiAgICAnfCBgc3JjL2NvbnN0cnVjdHMvU3RhdGljV2Vic2l0ZS50c2AgfCBDbG91ZEZyb250ICsgUzMgKyBBQ00gKyBSb3V0ZSA1MyBjb25zdHJ1Y3QgfCcsXG4gICAgJ3wgYHNyYy9jb25zdHJ1Y3RzL2hhbmRsZXIvQXBpLkZ1bmN0aW9uLnRzYCB8IExhbWJkYSBoYW5kbGVyIGVudHJ5IHBvaW50LCBiYXNpYyB3cmFwcGVyIGFyb3VuZCBFeHByZXNzLWNvbXBhdGlibGUgYXBwIGNvZGUgfCcsXG4gICAgJ3wgYHNyYy9hc3BlY3RzL0RhdGFEb2dBc3BlY3QudHNgIHwgQ0RLIGFzcGVjdCB0aGF0IHdpcmVzIGFsbCBMYW1iZGEgZnVuY3Rpb25zIHRvIERhdGFkb2cgfCcsXG4gICAgJycsXG4gICAgJyMjIyBGcm9udGVuZCAoYHdlYi9gKScsXG4gICAgJycsXG4gICAgJ3wgRmlsZSB8IERlc2NyaXB0aW9uIHwnLFxuICAgICd8LS0tLS0tfC0tLS0tLS0tLS0tLS18JyxcbiAgICAnfCBgd2ViL3NyYy9tYWluLnRzeGAgfCBSZWFjdCBhcHAgZW50cnkgcG9pbnQgd2l0aCBDbGVyayBhbmQgUmVhY3QgUXVlcnkgcHJvdmlkZXJzIHwnLFxuICAgICd8IGB3ZWIvc3JjL0FwcC50c3hgIHwgUm9vdCBhcHBsaWNhdGlvbiBjb21wb25lbnQgfCcsXG4gICAgJ3wgYHdlYi9zcmMvQXBwLmNzc2AgLyBgd2ViL3NyYy9pbmRleC5jc3NgIHwgQmFzZSBzdHlsZXNoZWV0cyAoVGFpbHdpbmQgQ1NTIHY0KSB8JyxcbiAgICAnfCBgd2ViL3NyYy9jb25maWcudHNgIHwgYHVzZUNvbmZpZygpYCBob29rIOKAlCBsb2FkcyBydW50aW1lIGNvbmZpZyBmcm9tIGBjb25maWcuanNvbmAgfCcsXG4gICAgJ3wgYHdlYi9zcmMvc2VydmljZXMvQXBpU2VydmljZS50c2AgfCBgdXNlQXBpUXVlcnkoKWAgLyBgdXNlQXBpTXV0YXRpb24oKWAg4oCUIGF1dGhlbnRpY2F0ZWQgQVBJIGhvb2tzLCBjYWNoZWQgcGVyIHBhdGggfCcsXG4gICAgJ3wgYHdlYi9zcmMvaGVscGVycy9gIHwgYHJlcXVlc3RzLnRzYCwgYEh0dHBFcnJvci50c2AsIGBlcnJvcnMudHNgLCBgcmV0cnkudHNgIOKAlCB0aGUgcmVxdWVzdCBhbmQgZXJyb3IgaGVscGVycyBgQXBpU2VydmljZWAgaXMgYnVpbHQgb24gfCcsXG4gICAgJ3wgYHdlYi9wdWJsaWMvY29uZmlnLmpzb25gIHwgUnVudGltZSBjb25maWcgKEFQSSBiYXNlIFVSTCwgQ2xlcmsgcHVibGlzaGFibGUga2V5KSB8JyxcbiAgICAuLi4oZTJlVGVzdGluZyA/IFtcbiAgICAgICd8IGB3ZWIvcGxheXdyaWdodC5jb25maWcudHNgIHwgUGxheXdyaWdodCBlMmUgY29uZmlnIOKAlCBzZWUgYHdlYi9lMmUvUkVBRE1FLm1kYCB8JyxcbiAgICAgIGB8IFxcYHdlYi9lMmUvXFxgIHwgUGxheXdyaWdodCBlMmUgc3VpdGUgKFxcYCR7dGVzdEUyZUNvbW1hbmR9XFxgKTsgYWxzbyBydW4gaW4gQ0kgYWdhaW5zdCBlYWNoIFBSJ3MgZGVwbG95ZWQgVVJMIHxgLFxuICAgIF0gOiBbXSksXG4gICAgJycsXG4gICAgJyMjIyBHaXRIdWIgQWN0aW9ucyBXb3JrZmxvd3MgKGAuZ2l0aHViL3dvcmtmbG93cy9gKScsXG4gICAgJycsXG4gICAgJ3wgRmlsZSB8IFRyaWdnZXIgfCcsXG4gICAgJ3wtLS0tLS18LS0tLS0tLS0tfCcsXG4gICAgJ3wgYHByLWRlcGxveS55bWxgIHwgT24gcHVsbCByZXF1ZXN0IG9wZW4vdXBkYXRlIOKAlCBkZXBsb3lzIGEgcGVyLVBSIGRldiBzdGFjayB8JyxcbiAgICAnfCBgcHItY2xlYW51cC55bWxgIHwgT24gcHVsbCByZXF1ZXN0IGNsb3NlIOKAlCB0ZWFycyBkb3duIHRoZSBwZXItUFIgZGV2IHN0YWNrIHwnLFxuICAgICd8IGBzdGFnaW5nLWRlcGxveS55bWxgIHwgT24gcHVzaCB0byBgbWFpbmAsIG9yIG1hbnVhbGx5IHRyaWdnZXJlZCDigJQgZGVwbG95cyB0byBzdGFnaW5nIHwnLFxuICAgIC4uLihwckF1dG9NZXJnZSA/IFtcbiAgICAgICd8IGBwci1hdXRvLW1lcmdlLnltbGAgfCBPbiBwdWxsIHJlcXVlc3Qgb3Blbi9yZW9wZW4vcmVhZHkgZm9yIHJldmlldyDigJQgdHVybnMgb24gc3F1YXNoIGF1dG8tbWVyZ2Ugd2l0aCBhIEdpdEh1YiBBcHAgdG9rZW4gfCcsXG4gICAgXSA6IFtdKSxcbiAgICAnfCBgcHJvZHVjdGlvbi1kZXBsb3kueW1sYCB8IE1hbnVhbGx5IHRyaWdnZXJlZCDigJQgZGVwbG95cyB0byBwcm9kdWN0aW9uIHwnLFxuICAgICcnLFxuICAgICctLS0nLFxuICAgICcnLFxuICAgICcjIyBGaWxlcyBZb3UgQ2FuIEVkaXQnLFxuICAgICcnLFxuICAgICdUaGVzZSBmaWxlcyBhcmUgZ2VuZXJhdGVkIG9uY2UgYW5kIG5ldmVyIG92ZXJ3cml0dGVuIGJ5IEJhdG1hbi4gTW9kaWZ5IHRoZW0gZnJlZWx5LicsXG4gICAgJycsXG4gICAgJ3wgRmlsZSB8IFdoYXQgdG8gZG8gd2l0aCBpdCB8JyxcbiAgICAnfC0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLXwnLFxuICAgICd8IGAucHJvamVucmMudHMgfCBUaGUgbWFpbiBQcm9qZW4gY29uZmlndXJhdGlvbiBmaWxlLiBBZGRpdGlvbmFsIGRlcGVuZGVuY2llcyBmb3IgZWl0aGVyIHRoZSBBUEkgb3IgdGhlIFdlYiBmcm9udGVuZCBuZWVkIHRvIGJlIGFkZGVkIGhlcmUgfCcsXG4gICAgJ3wgYHNyYy9zdGFja3MvQXBwbGljYXRpb25TdGFjay50c2AgfCAqKlN0YXJ0IGhlcmUuKiogQWRkIENESyBjb25zdHJ1Y3RzIHRvIGJ1aWxkIHlvdXIgaW5mcmFzdHJ1Y3R1cmUgfCcsXG4gICAgJ3wgYHNyYy9hcGkvYXBwLnRzIHwgVGhlIG1haW4gbW9ub2xpdGhpYyBBUEkgUkVTVCBzZXJ2ZXIgZmlsZS4gTWFpbiBmaWxlIHlvdSBzaG91bGQgYmUgbW9kaWZ5aW5nIHwnLFxuICAgICd8IGB3ZWIvc3JjL0FwcC50c3hgIHwgQnVpbGQgeW91ciBVSSBoZXJlIHwnLFxuICAgICd8IGB3ZWIvc3JjL0FwcC5jc3NgIC8gYHdlYi9zcmMvaW5kZXguY3NzYCB8IFN0eWxlIHlvdXIgYXBwbGljYXRpb24gfCcsXG4gICAgJ3wgYHdlYi9zcmMvbWFpbi50c3hgIHwgQWRqdXN0IHRvcC1sZXZlbCBwcm92aWRlcnMgb3Igcm91dGluZyB8JyxcbiAgICAnfCBgd2ViL3NyYy9zZXJ2aWNlcy9BcGlTZXJ2aWNlLnRzYCAvIGB3ZWIvc3JjL2hlbHBlcnMvYCB8IEFkZCBBUEkgc2VydmljZSBob29rcyBhbG9uZ3NpZGUgYEFwaVNlcnZpY2UudHNgLCBvciBhZGp1c3QgdGhlIHJlcXVlc3QgaGVscGVycyB8JyxcbiAgICAnfCBgd2ViL3B1YmxpYy9jb25maWcuanNvbmAgfCBVcGRhdGUgZm9yIGxvY2FsIGRldmVsb3BtZW50IChBUEkgVVJMLCBDbGVyayBrZXkpIHwnLFxuICAgIC4uLihlMmVUZXN0aW5nID8gW1xuICAgICAgJ3wgYHdlYi9wbGF5d3JpZ2h0LmNvbmZpZy50c2AgLyBgd2ViL2UyZS9gIHwgUGxheXdyaWdodCBlMmUgc3VpdGUg4oCUIGV4dGVuZCBpdCB3aXRoIHJlYWwgZmxvd3M7IHNlZSBgd2ViL2UyZS9SRUFETUUubWRgIHwnLFxuICAgIF0gOiBbXSksXG4gICAgJycsXG4gICAgJyMjIEZpbGVzIFlvdSBDYW5ub3QgRWRpdCcsXG4gICAgJycsXG4gICAgJ1RoZXNlIGZpbGVzIGFyZSAqKm1hbmFnZWQgYnkgQmF0bWFuKiogYW5kIHdpbGwgYmUgb3ZlcndyaXR0ZW4gZXZlcnkgdGltZSBgbnB4IHByb2plbmAgcnVucy4gRG8gbm90IGVkaXQgdGhlbSBkaXJlY3RseSDigJQgbWFrZSBjaGFuZ2VzIGluIGAucHJvamVucmMudHNgIGluc3RlYWQuJyxcbiAgICAnJyxcbiAgICAnPiBbIUlNUE9SVEFOVF0nLFxuICAgICc+IElmIHlvdSBoYXZlIEFOWSBjaGFuZ2VzIHlvdSB3YW50IHRvIG1ha2UgdG8gdGhlc2UgZmlsZXMsIG5vdGlmeSAjdGVhbS1iYXRtYW4gb24gU2xhY2suICcsXG4gICAgJz4gV2UgbWFpbnRhaW4gdGhlc2UgZmlsZXMgYXMgcGFydCBvZiB0aGUgY29yZSBCYXRtYW4gZXhwZXJpZW5jZSwgYW5kIHlvdXIgZmVlZGJhY2sgaXMgY3J1Y2lhbCB0byBlbnN1cmUgdGhleSBtZWV0IHlvdXIgbmVlZHMuJyxcbiAgICAnJyxcbiAgICAnfCBGaWxlIHwgV2h5IGl0XFwncyBtYW5hZ2VkIHwnLFxuICAgICd8LS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tfCcsXG4gICAgJ3wgYHNyYy9zdGFja3MvQmFzZUFwcGxpY2F0aW9uU3RhY2sudHNgIHwgQ29yZSBzdGFjayB3aXJpbmcg4oCUIHVwZGF0ZWQgd2l0aCBCYXRtYW4gcmVsZWFzZXMgfCcsXG4gICAgJ3wgYHNyYy9hc3BlY3RzL0RhdGFEb2dBc3BlY3QudHNgIHwgRGF0YWRvZyBDREsgYXNwZWN0IHwnLFxuICAgICd8IGB3ZWIvdml0ZS5jb25maWcudHNgIHwgVml0ZSBjb25maWd1cmF0aW9uIHwnLFxuICAgICd8IGB3ZWIvZXNsaW50LmNvbmZpZy5qc2AgfCBFU0xpbnQgY29uZmlndXJhdGlvbiB8JyxcbiAgICAnfCBgd2ViL3Bvc3Rjc3MuY29uZmlnLmpzYCB8IFBvc3RDU1MgLyBUYWlsd2luZCBjb25maWd1cmF0aW9uIHwnLFxuICAgICd8IGB3ZWIvaW5kZXguaHRtbGAgfCBIVE1MIGVudHJ5IHBvaW50IHwnLFxuICAgICd8IGB3ZWIvdHNjb25maWcuanNvbmAgLyBgd2ViL3RzY29uZmlnLmFwcC5qc29uYCAvIGB3ZWIvdHNjb25maWcubm9kZS5qc29uYCB8IFR5cGVTY3JpcHQgY29uZmlndXJhdGlvbiB8JyxcbiAgICAnfCBgd2ViL3NyYy92aXRlLWVudi5kLnRzYCB8IFZpdGUgdHlwZSBkZWNsYXJhdGlvbnMgfCcsXG4gICAgJ3wgYHdlYi9zcmMvY29uZmlnLnRzYCB8IFJ1bnRpbWUgY29uZmlnIGhvb2sg4oCUIHNoYXBlIGRyaXZlbiBieSBgLnByb2plbnJjLnRzYCB8JyxcbiAgICAnfCBgLmdpdGh1Yi9DT0RFT1dORVJTYCB8IENvZGUgb3duZXJzaGlwIHBvbGljeSB8JyxcbiAgICAnfCBgLmdpdGh1Yi93b3JrZmxvd3MvKi55bWxgIHwgQWxsIENJL0NEIHdvcmtmbG93cyB8JyxcbiAgICAnfCBgYXJjaGl0ZWN0dXJlLXJ1bGVzL2NoZWNrLnRzYCwgYHRzY29uZmlnLmpzb25gLCBgUkVBRE1FLm1kYCB8IEFyY2hpdGVjdHVyZSBydWxlIGVuZ2luZSB8JyxcbiAgICAnfCBgYXR0ZXN0YXRpb24vbWFuaWZlc3QudHNgLCBgdmVyaWZ5LnRzYCwgYHRzY29uZmlnLmpzb25gIHwgUFIgYXR0ZXN0YXRpb24gbWVjaGFuaXNtIHwnLFxuICAgICd8IGBvcGVuc3BlYy1nYXRlcy9jaGVjay10YXNrcy1jb21wbGV0ZS50c2AsIGB0c2NvbmZpZy5qc29uYCB8IE9wZW5TcGVjIHRhc2stY29tcGxldGlvbiBnYXRlIHwnLFxuICAgICd8IGBzd2FtcC1ib290c3RyYXAvcHVsbC1leHRlbnNpb25zLnRzYCwgYHJlcXVpcmVkLWV4dGVuc2lvbnMuanNvbmAsIGB0c2NvbmZpZy5qc29uYCB8IFB1bGxzIHN3YW1wIGV4dGVuc2lvbnMgYXQgdGhlaXIgcGlubmVkIHZlcnNpb25zLCBhbmQgYXQgbGVhc3QgdGhlIHZlcnNpb25zIHRoZSBlbmFibGVkIHdvcmstaXRlbSBzb3VyY2VzIG5lZWQgfCcsXG4gICAgJ3wgYHdvcmtmbG93cy93b3JrZmxvdy0qLnlhbWxgIHwgU3dhbXAgd29ya2Zsb3dzIHRoZSBzb2Z0d2FyZSBmYWN0b3J5IHJ1bnMgfCcsXG4gICAgJ3wgYGZhY3Rvcnkvd29yay1pdGVtLXNvdXJjZXMubWRgIHwgSG93IHRoZSBzb2Z0d2FyZSBmYWN0b3J5IHJlc29sdmVzIGEgd29yay1pdGVtIElEIHRvIGl0cyB0cmFja2VyIHwnLFxuICAgICcnLFxuICAgICc+ICoqVGlwOioqIEZpbGVzIHdpdGggYSBgfn4gR2VuZXJhdGVkIGJ5IHByb2plbi4gVG8gbW9kaWZ5LCBlZGl0IC5wcm9qZW5yYy50cyBhbmQgcnVuIFwibnB4IHByb2plblwiLiB+fmAgaGVhZGVyIGFyZSBtYW5hZ2VkIGZpbGVzLicsXG4gICAgJycsXG4gICAgJyMjIyBTb2Z0d2FyZSBGYWN0b3J5IChgbW9kZWxzL2AsIGBhcmNoaXRlY3R1cmUtcnVsZXMvcnVsZXMuanNvbmApJyxcbiAgICAnJyxcbiAgICAnQmF0bWFuIGFsc28gc2VlZHMgYSBbc3dhbXBdKGh0dHBzOi8vZ2l0aHViLmNvbS9zd2FtcC1jbHViL3N3YW1wKSBzb2Z0d2FyZScsXG4gICAgJ2ZhY3Rvcnkg4oCUIGEgYEBzd2FtcC9zb2Z0d2FyZS1mYWN0b3J5YCBzdGF0ZSBtYWNoaW5lIHRoYXQgZHJpdmVzIGEgd29yayBpdGVtJyxcbiAgICAnKGEgR2l0SHViIGlzc3VlIG51bWJlciwgb3IgYSBKaXJhIGtleSB3aGVuIHRoZSBKaXJhIHNvdXJjZSBpcyBlbmFibGVkKSB0aHJvdWdoIGludGFrZSwgT3BlblNwZWMgcGxhbm5pbmcsJyxcbiAgICAnaW1wbGVtZW50YXRpb24sIHByZS1QUiB2ZXJpZmljYXRpb24sIGFuZCBhbiBvcGVuZWQgUFIuIEludGFrZSByZXNvbHZlcyB0aGUnLFxuICAgICd3b3JrIGl0ZW0gdGhyb3VnaCB0aGUgbWFuYWdlZCBgZmFjdG9yeS93b3JrLWl0ZW0tc291cmNlcy5tZGAuIFRoZSBzZWVkJyxcbiAgICAnZmlsZXMgdW5kZXIgYG1vZGVscy8qKi8qLnlhbWxgIGFuZCBgYXJjaGl0ZWN0dXJlLXJ1bGVzL3J1bGVzLmpzb25gIGFyZScsXG4gICAgJ2dlbmVyYXRlZCBvbmNlIChsaWtlIHRoZSBmaWxlcyBpbicsXG4gICAgJ1wiRmlsZXMgWW91IENhbiBFZGl0XCIgYWJvdmUpIOKAlCB0dW5lIHRoZSBmYWN0b3J5XFwncyBzdGFnZXMvZ2F0ZXMgb3IgYWRkIHlvdXInLFxuICAgICdvd24gYXJjaGl0ZWN0dXJlIHJ1bGVzIGRpcmVjdGx5IGluIHRob3NlIGZpbGVzLicsXG4gICAgJycsXG4gICAgJ2Bzd2FtcCBpbml0YCBydW5zIGF1dG9tYXRpY2FsbHkgYXMgcGFydCBvZiBgaW5zdGFsbGAvYGluc3RhbGw6Y2lgIChhIHNpbGVudCcsXG4gICAgJ25vLW9wIGlmIGBzd2FtcGAgaXNuXFwndCBvbiBQQVRILCBlLmcuIGluIENJKSwgc28gdGhlIHJlcG8gc3RheXMgaW5pdGlhbGl6ZWQnLFxuICAgICd3aXRob3V0IGEgc2VwYXJhdGUgc3RlcC4nLFxuICAgICcnLFxuICAgICdgc3dhbXBWZXJzaW9uYCBpbiBgLnN3YW1wLnlhbWxgIGlzIHRoZSBtaW5pbXVtIHN3YW1wIENMSSB0aGUgcmVwbyBuZWVkczogdGhlJyxcbiAgICAndmVyc2lvbiBpdCB3YXMgbGFzdCB1cGdyYWRlZCB3aXRoLiBzd2FtcCBkb2VzblxcJ3Qga2VlcCBvbGQgYnVpbGRzLCBzbyBpbnN0YWxsJyxcbiAgICAndGhlIGN1cnJlbnQgYHN0YWJsZWAgcmVsZWFzZSByYXRoZXIgdGhhbiB0aGF0IGV4YWN0IHZlcnNpb246JyxcbiAgICAnJyxcbiAgICAnYGBgYmFzaCcsXG4gICAgJyMgbWFjT1MgLyBMaW51eCcsXG4gICAgJ2N1cmwgLWZzU0wgaHR0cHM6Ly9zd2FtcC5jbHViL2luc3RhbGwuc2ggfCBzaCcsXG4gICAgJycsXG4gICAgJyMgV2luZG93cyAoUG93ZXJTaGVsbCknLFxuICAgICdpcm0gaHR0cHM6Ly9zd2FtcC5jbHViL2luc3RhbGwucHMxIHwgaWV4JyxcbiAgICAnYGBgJyxcbiAgICAnJyxcbiAgICAnT25lLXRpbWUgc2V0dXAgYmV5b25kIHRoYXQsIGFmdGVyIHlvdXIgZmlyc3QgYG5weCBwcm9qZW5gOicsXG4gICAgJycsXG4gICAgJ2BgYGJhc2gnLFxuICAgICcjIFB1bGxzIGVhY2ggZXh0ZW5zaW9uIGF0IHRoZSB2ZXJzaW9uIHBpbm5lZCBpbicsXG4gICAgJyMgZXh0ZW5zaW9ucy9tb2RlbHMvdXBzdHJlYW1fZXh0ZW5zaW9ucy5qc29uIChvciB0aGUgbGF0ZXN0JyxcbiAgICAnIyBzb2Z0d2FyZS1mYWN0b3J5L2dpdGh1YiBleHRlbnNpb25zIGluIGEgcmVwbyB3aXRoIG5vIGxvY2tmaWxlIHlldCksJyxcbiAgICAnIyByZXN0b3JlcyB0aGUgbG9ja2ZpbGUgYW5kIGNvbW1pdHRlZCBza2lsbCBmaWxlcyBmcm9tIGdpdCwgYW5kIGNyZWF0ZXMgdGhlJyxcbiAgICAnIyByZXBvXFwncyBzZWNyZXRzIHZhdWx0JyxcbiAgICAnbnB4IHByb2plbiBzd2FtcDpib290c3RyYXAnLFxuICAgICcnLFxuICAgICcjIFRoZW4gc3RvcmUgYSBHaXRIdWIgdG9rZW4gdGhlIGZhY3RvcnkgY2FuIG9wZW4gUFJzIHdpdGgnLFxuICAgICdzd2FtcCB2YXVsdCBwdXQgPHJlcG8+LXNlY3JldHMgR0lUSFVCX1RPS0VOIC0tcmVmcmVzaC1mcm9tIFwiZ2ggYXV0aCB0b2tlblwiJyxcbiAgICAnYGBgJyxcbiAgICAnJyxcbiAgICAnIyMjIyBUYWtpbmcgd29yayBpdGVtcyBmcm9tIEppcmEnLFxuICAgICcnLFxuICAgICdTZXQgYHdvcmtJdGVtU291cmNlczogeyBnaXRodWI6IHt9LCBqaXJhOiB7IHByb2plY3RLZXlzLCBzaXRlSG9zdCB9IH1gIGluJyxcbiAgICAnYC5wcm9qZW5yYy50c2AsIG9yIGxlYXZlIG91dCBgZ2l0aHViYCB0byB0YWtlIHdvcmsgaXRlbXMgZnJvbSBKaXJhIGFsb25lLicsXG4gICAgJ2Bwcm9qZWN0S2V5c2AgbGlzdHMgdGhlIEppcmEgcHJvamVjdHMgaW50YWtlIG1heSByZWFkLCBhbmQgYHNpdGVIb3N0YCBpcyB0aGUnLFxuICAgICdzaXRlXFwncyBob3N0bmFtZSwgc3VjaCBhcyBgYWNtZS5hdGxhc3NpYW4ubmV0YC4gVGhlbiBydW4gYG5weCBwcm9qZW5gLCB3aGljaCcsXG4gICAgJ3dyaXRlcyB0aGUgbWFuYWdlZCcsXG4gICAgJ2BleHRlbnNpb25zL21vZGVscy9qaXJhLnRzYCBhbmQgdGhlIHNlZWQgYG1vZGVscy9AYmF0bWFuL2ppcmEvPHJlcG8+LWppcmEueWFtbGAsJyxcbiAgICAnYW5kIGNvbW1pdCBib3RoLicsXG4gICAgJycsXG4gICAgJ0ludGFrZSByZWFkcyBKaXJhIHRocm91Z2ggQXRsYXNzaWFuXFwncyBgYWNsaWAsIHdpdGggZWFjaCBkZXZlbG9wZXJcXCdzIG93bicsXG4gICAgJ3NpZ24taW4sIGFzIGl0IHJlYWRzIEdpdEh1YiB0aHJvdWdoIGBnaGAuIFRoZSBleHRlbnNpb24gb25seSByZWFkczsgaXQgbmV2ZXInLFxuICAgICd3cml0ZXMgdG8gSmlyYS4gRWFjaCBkZXZlbG9wZXIgaW5zdGFsbHMgYGFjbGlgJyxcbiAgICAnKGh0dHBzOi8vZGV2ZWxvcGVyLmF0bGFzc2lhbi5jb20vY2xvdWQvYWNsaS9ndWlkZXMvaW5zdGFsbC1hY2xpLykgYW5kIHNpZ25zIGluJyxcbiAgICAnb25jZTonLFxuICAgICcnLFxuICAgICdgYGBiYXNoJyxcbiAgICAnIyBTaWduIGluIHRocm91Z2ggdGhlIGJyb3dzZXInLFxuICAgICdhY2xpIGppcmEgYXV0aCBsb2dpbiAtLXdlYicsXG4gICAgJycsXG4gICAgJyMgT3IsIHdoZXJlIHRoZXJlIGlzIG5vIGJyb3dzZXIsIHNpZ24gaW4gd2l0aCBhbiBBUEkgdG9rZW4gcmVhZCBmcm9tIGEgZmlsZScsXG4gICAgJ2FjbGkgamlyYSBhdXRoIGxvZ2luIC0tc2l0ZSA8c2l0ZUhvc3Q+IC0tZW1haWwgPHlvdUBleGFtcGxlLmNvbT4gLS10b2tlbiA8IHRva2VuLnR4dCcsXG4gICAgJyMgVGhlIHNhbWUgaW4gUG93ZXJTaGVsbCcsXG4gICAgJ0dldC1Db250ZW50IHRva2VuLnR4dCB8IGFjbGkgamlyYSBhdXRoIGxvZ2luIC0tc2l0ZSA8c2l0ZUhvc3Q+IC0tZW1haWwgPHlvdUBleGFtcGxlLmNvbT4gLS10b2tlbicsXG4gICAgJycsXG4gICAgJyMgVGhlIHN0YXR1cyBtdXN0IHNob3cgU2l0ZTogPHNpdGVIb3N0PjsgaWYgaXQgc2hvd3MgYW5vdGhlciBzaXRlLCBzd2l0Y2gnLFxuICAgICdhY2xpIGppcmEgYXV0aCBzdGF0dXMnLFxuICAgICdhY2xpIGppcmEgYXV0aCBzd2l0Y2ggLS1zaXRlIDxzaXRlSG9zdD4nLFxuICAgICdgYGAnLFxuICAgICcnLFxuICAgICdJZiBhIGZldGNoIHNheXMgYGFjbGlgIGlzIG5vdCBzaWduZWQgaW4sIHNpZ24gaW4gYWdhaW4uIEVpdGhlciBzaWduLWluIGNhbiBkbycsXG4gICAgJ2FueXRoaW5nIHlvdXIgQXRsYXNzaWFuIGFjY291bnQgY2FuLCBzbyB0cmVhdCBpdCBsaWtlIHlvdXIgYGdoYCBzaWduLWluLicsXG4gICAgJycsXG4gICAgJy0tLScsXG4gICAgJycsXG4gICAgJyMjIFdoZXJlIHRvIFN0YXJ0JyxcbiAgICAnJyxcbiAgICAnMS4gKipgc3JjL3N0YWNrcy9BcHBsaWNhdGlvblN0YWNrLnRzYCoqIOKAlCBBZGQgeW91ciBDREsgY29uc3RydWN0cyBoZXJlLiBUaGUgYmFzZSBzdGFjayBhbHJlYWR5IHByb3ZpZGVzIGB0aGlzLmFwaWAsIGB0aGlzLmhvc3RlZFpvbmVgLCBgdGhpcy5kYXRhZG9nYCwgYW5kICh3aGVuIHRoZSBzdGFjayBjcmVhdGVzIG9uZSkgYHRoaXMudnBjYCBhcyBwcm90ZWN0ZWQgcHJvcGVydGllcy4nLFxuICAgICcnLFxuICAgICcyLiAqKmB3ZWIvYCoqIOKAlCBCdWlsZCB5b3VyIGZyb250ZW5kLiBTdGFydCB3aXRoIGB3ZWIvc3JjL0FwcC50c3hgIGFuZCBhZGQgc2VydmljZXMgYWxvbmdzaWRlIGB3ZWIvc3JjL3NlcnZpY2VzL0FwaVNlcnZpY2UudHNgLicsXG4gICAgJycsXG4gICAgJzMuICoqYHNyYy9hcGkvYXBwLnRzYCoqIOKAlCBJbXBsZW1lbnQgeW91ciBiYWNrZW5kIExhbWJkYSBoYW5kbGVyIGxvZ2ljIGhlcmUuJyxcbiAgICAnJyxcbiAgICAnNC4gKipgLnByb2plbnJjLnRzYCoqIC0gTWFuYWdlcyBwcm9qZWN0IGRlcGVuZGVuY2llcyBhbmQgY29uZmlndXJhdGlvbi4gUnVuIGBucHggcHJvamVuYCBhZnRlciBtYWtpbmcgYW55IGNoYW5nZXMgdG8gdGhpcyBmaWxlLicsXG4gICAgJy0tLScsXG4gICAgJycsXG4gICAgJyMjIERldmVsb3BtZW50IFdvcmtmbG93JyxcbiAgICAnJyxcbiAgICAnYGBgYmFzaCcsXG4gICAgJyMgSW5zdGFsbCBkZXBlbmRlbmNpZXMnLFxuICAgICd5YXJuIGluc3RhbGwnLFxuICAgICcnLFxuICAgICcjIFN0YXJ0IGxvY2FsIGRldiBzZXJ2ZXIgKGJhY2tlbmQgTGFtYmRhICsgVml0ZSBmcm9udGVuZCBpbiBwYXJhbGxlbCknLFxuICAgICd5YXJuIGRldicsXG4gICAgJycsXG4gICAgJyMgRGVwbG95IGEgcGVyc29uYWwgZGV2IHN0YWNrIHRvIEFXUyBhcyBhbiBhbHRlcm5hdGl2ZSB0byBsb2NhbCBkZXZlbG9wbWVudCwgcHJvdmlkZXMgbW9yZSB0aG9yb3VnaCBlbmQtdG8tZW5kIHRlc3RpbmcnLFxuICAgICd5YXJuIGNkazpkZXYgLS1jb250ZXh0IGxvY2FsLWRldi1wcmVmaXg9eW91ci1oYW5kbGUgZGVwbG95JyxcbiAgICAnJyxcbiAgICAnIyBSZWRlcGxveSB5b3VyIHBlcnNvbmFsIGRldiBzdGFjayBmYXN0OiBhZnRlciB0aGUgZmlyc3QgZGVwbG95IGFib3ZlLCBrZWVwJyxcbiAgICBcIiMgcmV1c2luZyB0aGUgc2FtZSBzdGFjayAoZG9uJ3QgZGVsZXRlIGl0IGJldHdlZW4gYnJhbmNoZXMpIGFuZCBpdGVyYXRlIHdpdGhcIixcbiAgICAnIyBob3Rzd2FwLWZhbGxiYWNrIGluc3RlYWQgb2YgYSBmdWxsIENsb3VkRm9ybWF0aW9uIGRlcGxveW1lbnQnLFxuICAgICd5YXJuIGNkazpkZXY6aG90c3dhcCAtLWNvbnRleHQgbG9jYWwtZGV2LXByZWZpeD15b3VyLWhhbmRsZScsXG4gICAgJycsXG4gICAgJyMgUnVuIHRlc3RzJyxcbiAgICAneWFybiB0ZXN0JyxcbiAgICAnJyxcbiAgICAnIyBSZS1zeW50aGVzaXplIHByb2plY3QgZmlsZXMgYWZ0ZXIgZWRpdGluZyAucHJvamVucmMudHMnLFxuICAgICducHggcHJvamVuJyxcbiAgICAnYGBgJyxcbiAgICAnJyxcbiAgICAnPiBbIUlNUE9SVEFOVF0nLFxuICAgICc+IGAtLWhvdHN3YXAtZmFsbGJhY2tgICh1c2VkIGJ5IGBjZGs6ZGV2OmhvdHN3YXBgIGFuZCB0aGUgYHdhdGNoYCB0YXNrKSBpcyBmb3InLFxuICAgICc+IHBlcnNvbmFsIGRldiBzdGFja3Mgb25seSDigJQgbmV2ZXIgcnVuIGl0IGFnYWluc3Qgc3RhZ2luZyBvciBwcm9kLicsXG4gICAgJycsXG4gICAgJy0tLScsXG4gICAgJycsXG4gICAgJyMjIFVwZ3JhZGluZyBCYXRtYW4nLFxuICAgICcnLFxuICAgICdgYGBiYXNoJyxcbiAgICAneWFybiBhZGQgQG1hY2Vkb24tdGVjaG5vbG9naWVzL2JhdG1hbkBsYXRlc3QnLFxuICAgICducHggcHJvamVuJyxcbiAgICAnYGBgJyxcbiAgICAnJyxcbiAgICAnVGhpcyB1cGRhdGVzIGFsbCBtYW5hZ2VkIGZpbGVzIHRvIHRoZSBsYXRlc3QgQmF0bWFuIHN0YW5kYXJkcy4gWW91ciBlZGl0YWJsZSBzYW1wbGUgZmlsZXMgYXJlIG5ldmVyIHRvdWNoZWQuJyxcbiAgXS5qb2luKCdcXG4nKTtcbn1cbiJdfQ==
|
package/package.json
CHANGED
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"projen": "0.103.1",
|
|
31
31
|
"ts-jest": "^29.4.5",
|
|
32
32
|
"ts-node": "^10.9.2",
|
|
33
|
-
"typescript": "^5.9.3"
|
|
33
|
+
"typescript": "^5.9.3",
|
|
34
|
+
"zod": "4.3.6"
|
|
34
35
|
},
|
|
35
36
|
"peerDependencies": {
|
|
36
37
|
"constructs": "10.5.0",
|
|
@@ -49,7 +50,7 @@
|
|
|
49
50
|
"main": "lib/index.js",
|
|
50
51
|
"license": "Apache-2.0",
|
|
51
52
|
"stability": "stable",
|
|
52
|
-
"version": "1.
|
|
53
|
+
"version": "1.35.0",
|
|
53
54
|
"jest": {
|
|
54
55
|
"coverageProvider": "v8",
|
|
55
56
|
"testMatch": [
|
|
@@ -9,11 +9,18 @@
|
|
|
9
9
|
* it writes backslash paths and deletes the committed files it tracks (e.g.
|
|
10
10
|
* .claude/skills/software-factory/). So afterwards the lockfile and every
|
|
11
11
|
* git-tracked file it lists are restored from git.
|
|
12
|
+
*
|
|
13
|
+
* Then each extension in swamp-bootstrap/required-extensions.json that the
|
|
14
|
+
* lockfile lacks, or pins below the listed minimum, is pulled at that
|
|
15
|
+
* minimum. The tracked files it lists are restored again, except the
|
|
16
|
+
* lockfile, whose paths are normalized to forward slashes so it is the only
|
|
17
|
+
* change left to commit.
|
|
12
18
|
*/
|
|
13
19
|
import { execFileSync } from 'node:child_process';
|
|
14
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
20
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
15
21
|
|
|
16
22
|
const LOCKFILE = 'extensions/models/upstream_extensions.json';
|
|
23
|
+
const REQUIRED_EXTENSIONS = 'swamp-bootstrap/required-extensions.json';
|
|
17
24
|
const DEFAULT_EXTENSIONS = ['@swamp/software-factory', '@webframp/github', '@goodcraft/github'];
|
|
18
25
|
|
|
19
26
|
interface LockfileEntry {
|
|
@@ -37,12 +44,45 @@ function pull(extension: string): void {
|
|
|
37
44
|
execFileSync('swamp', ['extension', 'pull', extension, '--force'], { stdio: 'inherit' });
|
|
38
45
|
}
|
|
39
46
|
|
|
40
|
-
function
|
|
47
|
+
function readRequiredExtensions(): Record<string, string> {
|
|
48
|
+
if (!existsSync(REQUIRED_EXTENSIONS)) {
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
const required = JSON.parse(readFileSync(REQUIRED_EXTENSIONS, 'utf8')) as Record<string, string>;
|
|
52
|
+
return Object.fromEntries(Object.entries(required).filter(([name]) => name.startsWith('@')));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function isOlder(version: string | undefined, minimum: string): boolean {
|
|
56
|
+
for (const value of [version, minimum]) {
|
|
57
|
+
if (typeof value !== 'string' || !/^\d+(\.\d+)*$/.test(value)) {
|
|
58
|
+
throw new Error(`Cannot compare extension version ${JSON.stringify(value)}: expected digits separated by dots`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const have = version!.split('.').map(Number);
|
|
62
|
+
const want = minimum.split('.').map(Number);
|
|
63
|
+
for (let i = 0; i < Math.max(have.length, want.length); i++) {
|
|
64
|
+
const difference = (have[i] ?? 0) - (want[i] ?? 0);
|
|
65
|
+
if (difference !== 0) {
|
|
66
|
+
return difference < 0;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function toPosix(file: string): string {
|
|
73
|
+
return file.replace(/\\/g, '/');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function restoreTrackedFiles(lockfile: Record<string, LockfileEntry>, includeLockfile = true): void {
|
|
41
77
|
const listed = Object.values(lockfile)
|
|
42
78
|
.flatMap((entry) => entry.files ?? [])
|
|
43
|
-
.map(
|
|
79
|
+
.map(toPosix)
|
|
44
80
|
.filter((file) => !file.startsWith('.swamp/'));
|
|
45
|
-
const
|
|
81
|
+
const paths = [...(includeLockfile ? [LOCKFILE] : []), ...listed];
|
|
82
|
+
if (paths.length === 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const tracked = run('git', ['ls-files', '-z', '--', ...paths])
|
|
46
86
|
.split('\0')
|
|
47
87
|
.filter(Boolean);
|
|
48
88
|
if (tracked.length > 0) {
|
|
@@ -51,18 +91,47 @@ function restoreTrackedFiles(lockfile: Record<string, LockfileEntry>): void {
|
|
|
51
91
|
}
|
|
52
92
|
}
|
|
53
93
|
|
|
94
|
+
function normalizeLockfile(lockfile: Record<string, LockfileEntry>): void {
|
|
95
|
+
for (const entry of Object.values(lockfile)) {
|
|
96
|
+
if (entry.files) {
|
|
97
|
+
entry.files = entry.files.map(toPosix);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
writeFileSync(LOCKFILE, `${JSON.stringify(lockfile, null, 2)}\n`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function pullRequiredExtensions(): void {
|
|
104
|
+
const lockfile = readLockfile() ?? {};
|
|
105
|
+
const needed = Object.entries(readRequiredExtensions())
|
|
106
|
+
.filter(([name, minimum]) => !lockfile[name] || isOlder(lockfile[name].version, minimum));
|
|
107
|
+
if (needed.length === 0) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
for (const [name, minimum] of needed) {
|
|
111
|
+
pull(`${name}@${minimum}`);
|
|
112
|
+
}
|
|
113
|
+
const updated = readLockfile();
|
|
114
|
+
if (updated) {
|
|
115
|
+
const pulled = new Set(needed.map(([name]) => name));
|
|
116
|
+
restoreTrackedFiles(Object.fromEntries(Object.entries(updated).filter(([name]) => !pulled.has(name))), false);
|
|
117
|
+
normalizeLockfile(updated);
|
|
118
|
+
}
|
|
119
|
+
const pinned = needed.map(([name, minimum]) => `${name}@${minimum}`).join(', ');
|
|
120
|
+
console.log(`Commit ${LOCKFILE}: it now pins ${pinned}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
54
123
|
function main(): void {
|
|
55
124
|
const lockfile = readLockfile();
|
|
56
125
|
if (!lockfile) {
|
|
57
126
|
console.log(`No ${LOCKFILE} yet: pulling the latest stable software-factory extensions`);
|
|
58
127
|
DEFAULT_EXTENSIONS.forEach(pull);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
128
|
+
} else {
|
|
129
|
+
for (const [name, entry] of Object.entries(lockfile)) {
|
|
130
|
+
pull(`${name}@${entry.version}`);
|
|
131
|
+
}
|
|
132
|
+
restoreTrackedFiles(lockfile);
|
|
64
133
|
}
|
|
65
|
-
|
|
134
|
+
pullRequiredExtensions();
|
|
66
135
|
}
|
|
67
136
|
|
|
68
137
|
main();
|
|
@@ -9,11 +9,18 @@
|
|
|
9
9
|
* it writes backslash paths and deletes the committed files it tracks (e.g.
|
|
10
10
|
* .claude/skills/software-factory/). So afterwards the lockfile and every
|
|
11
11
|
* git-tracked file it lists are restored from git.
|
|
12
|
+
*
|
|
13
|
+
* Then each extension in swamp-bootstrap/required-extensions.json that the
|
|
14
|
+
* lockfile lacks, or pins below the listed minimum, is pulled at that
|
|
15
|
+
* minimum. The tracked files it lists are restored again, except the
|
|
16
|
+
* lockfile, whose paths are normalized to forward slashes so it is the only
|
|
17
|
+
* change left to commit.
|
|
12
18
|
*/
|
|
13
19
|
import { execFileSync } from 'node:child_process';
|
|
14
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
20
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
15
21
|
|
|
16
22
|
const LOCKFILE = 'extensions/models/upstream_extensions.json';
|
|
23
|
+
const REQUIRED_EXTENSIONS = 'swamp-bootstrap/required-extensions.json';
|
|
17
24
|
const DEFAULT_EXTENSIONS = ['@swamp/software-factory', '@webframp/github', '@goodcraft/github'];
|
|
18
25
|
|
|
19
26
|
interface LockfileEntry {
|
|
@@ -37,12 +44,45 @@ function pull(extension: string): void {
|
|
|
37
44
|
execFileSync('swamp', ['extension', 'pull', extension, '--force'], { stdio: 'inherit' });
|
|
38
45
|
}
|
|
39
46
|
|
|
40
|
-
function
|
|
47
|
+
function readRequiredExtensions(): Record<string, string> {
|
|
48
|
+
if (!existsSync(REQUIRED_EXTENSIONS)) {
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
const required = JSON.parse(readFileSync(REQUIRED_EXTENSIONS, 'utf8')) as Record<string, string>;
|
|
52
|
+
return Object.fromEntries(Object.entries(required).filter(([name]) => name.startsWith('@')));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function isOlder(version: string | undefined, minimum: string): boolean {
|
|
56
|
+
for (const value of [version, minimum]) {
|
|
57
|
+
if (typeof value !== 'string' || !/^\d+(\.\d+)*$/.test(value)) {
|
|
58
|
+
throw new Error(`Cannot compare extension version ${JSON.stringify(value)}: expected digits separated by dots`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const have = version!.split('.').map(Number);
|
|
62
|
+
const want = minimum.split('.').map(Number);
|
|
63
|
+
for (let i = 0; i < Math.max(have.length, want.length); i++) {
|
|
64
|
+
const difference = (have[i] ?? 0) - (want[i] ?? 0);
|
|
65
|
+
if (difference !== 0) {
|
|
66
|
+
return difference < 0;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function toPosix(file: string): string {
|
|
73
|
+
return file.replace(/\\/g, '/');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function restoreTrackedFiles(lockfile: Record<string, LockfileEntry>, includeLockfile = true): void {
|
|
41
77
|
const listed = Object.values(lockfile)
|
|
42
78
|
.flatMap((entry) => entry.files ?? [])
|
|
43
|
-
.map(
|
|
79
|
+
.map(toPosix)
|
|
44
80
|
.filter((file) => !file.startsWith('.swamp/'));
|
|
45
|
-
const
|
|
81
|
+
const paths = [...(includeLockfile ? [LOCKFILE] : []), ...listed];
|
|
82
|
+
if (paths.length === 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const tracked = run('git', ['ls-files', '-z', '--', ...paths])
|
|
46
86
|
.split('\0')
|
|
47
87
|
.filter(Boolean);
|
|
48
88
|
if (tracked.length > 0) {
|
|
@@ -51,18 +91,47 @@ function restoreTrackedFiles(lockfile: Record<string, LockfileEntry>): void {
|
|
|
51
91
|
}
|
|
52
92
|
}
|
|
53
93
|
|
|
94
|
+
function normalizeLockfile(lockfile: Record<string, LockfileEntry>): void {
|
|
95
|
+
for (const entry of Object.values(lockfile)) {
|
|
96
|
+
if (entry.files) {
|
|
97
|
+
entry.files = entry.files.map(toPosix);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
writeFileSync(LOCKFILE, `${JSON.stringify(lockfile, null, 2)}\n`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function pullRequiredExtensions(): void {
|
|
104
|
+
const lockfile = readLockfile() ?? {};
|
|
105
|
+
const needed = Object.entries(readRequiredExtensions())
|
|
106
|
+
.filter(([name, minimum]) => !lockfile[name] || isOlder(lockfile[name].version, minimum));
|
|
107
|
+
if (needed.length === 0) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
for (const [name, minimum] of needed) {
|
|
111
|
+
pull(`${name}@${minimum}`);
|
|
112
|
+
}
|
|
113
|
+
const updated = readLockfile();
|
|
114
|
+
if (updated) {
|
|
115
|
+
const pulled = new Set(needed.map(([name]) => name));
|
|
116
|
+
restoreTrackedFiles(Object.fromEntries(Object.entries(updated).filter(([name]) => !pulled.has(name))), false);
|
|
117
|
+
normalizeLockfile(updated);
|
|
118
|
+
}
|
|
119
|
+
const pinned = needed.map(([name, minimum]) => `${name}@${minimum}`).join(', ');
|
|
120
|
+
console.log(`Commit ${LOCKFILE}: it now pins ${pinned}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
54
123
|
function main(): void {
|
|
55
124
|
const lockfile = readLockfile();
|
|
56
125
|
if (!lockfile) {
|
|
57
126
|
console.log(`No ${LOCKFILE} yet: pulling the latest stable software-factory extensions`);
|
|
58
127
|
DEFAULT_EXTENSIONS.forEach(pull);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
128
|
+
} else {
|
|
129
|
+
for (const [name, entry] of Object.entries(lockfile)) {
|
|
130
|
+
pull(`${name}@${entry.version}`);
|
|
131
|
+
}
|
|
132
|
+
restoreTrackedFiles(lockfile);
|
|
64
133
|
}
|
|
65
|
-
|
|
134
|
+
pullRequiredExtensions();
|
|
66
135
|
}
|
|
67
136
|
|
|
68
137
|
main();
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads one Jira work item through Atlassian's acli, with the developer's own
|
|
3
|
+
* acli sign-in. It only reads: it runs `acli jira auth status` and
|
|
4
|
+
* `acli jira workitem view`, and nothing else.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { z } from "npm:zod@4.3.6";
|
|
9
|
+
|
|
10
|
+
const KEY = /^[A-Z][A-Z0-9_]+-[1-9][0-9]*$/;
|
|
11
|
+
const SITE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i;
|
|
12
|
+
const ANSI_ESCAPE = /\u001b\[[0-9;]*[A-Za-z]/g;
|
|
13
|
+
const VIEW_FIELDS = "summary,description,status,priority,labels,comment,issuetype";
|
|
14
|
+
const NOT_FOUND = "Issue does not exist or you do not have permission to see it";
|
|
15
|
+
const INSTALL_GUIDE = "https://developer.atlassian.com/cloud/acli/guides/install-acli/";
|
|
16
|
+
const SIGN_IN = "Run: acli jira auth login --web (or sign in with an API token where there's no browser)";
|
|
17
|
+
const MAX_COMMENTS = 20;
|
|
18
|
+
|
|
19
|
+
const GlobalArgsSchema = z.object({
|
|
20
|
+
site: z.string().regex(SITE).describe("The Jira Cloud site's hostname, such as acme.atlassian.net"),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const FetchArgsSchema = z.object({
|
|
24
|
+
key: z.string().regex(KEY).describe("The work item's key, such as AI-123"),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const IssueSchema = z.object({
|
|
28
|
+
key: z.string(),
|
|
29
|
+
site: z.string(),
|
|
30
|
+
url: z.string(),
|
|
31
|
+
summary: z.string().nullable(),
|
|
32
|
+
description: z.unknown(),
|
|
33
|
+
status: z.string().nullable(),
|
|
34
|
+
priority: z.string().nullable(),
|
|
35
|
+
issueType: z.string().nullable(),
|
|
36
|
+
labels: z.array(z.string()),
|
|
37
|
+
comments: z.array(z.object({
|
|
38
|
+
author: z.string().nullable(),
|
|
39
|
+
created: z.string().nullable(),
|
|
40
|
+
body: z.unknown(),
|
|
41
|
+
})),
|
|
42
|
+
fetchedAt: z.string(),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
interface AcliResult {
|
|
46
|
+
code: number;
|
|
47
|
+
stdout: string;
|
|
48
|
+
output: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface AcliComment {
|
|
52
|
+
author?: { displayName?: string } | null;
|
|
53
|
+
created?: string | null;
|
|
54
|
+
body?: unknown;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface AcliIssue {
|
|
58
|
+
key?: unknown;
|
|
59
|
+
fields?: {
|
|
60
|
+
summary?: string | null;
|
|
61
|
+
description?: unknown;
|
|
62
|
+
status?: { name?: string } | null;
|
|
63
|
+
priority?: { name?: string } | null;
|
|
64
|
+
issuetype?: { name?: string } | null;
|
|
65
|
+
labels?: unknown;
|
|
66
|
+
comment?: { comments?: AcliComment[] } | null;
|
|
67
|
+
} | null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function projectOf(key: string): string {
|
|
71
|
+
return key.slice(0, key.lastIndexOf("-"));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function runAcli(args: string[]): Promise<AcliResult> {
|
|
75
|
+
let result: Deno.CommandOutput;
|
|
76
|
+
try {
|
|
77
|
+
result = await new Deno.Command("acli", { args, stdout: "piped", stderr: "piped" }).output();
|
|
78
|
+
} catch (error) {
|
|
79
|
+
if (error instanceof Deno.errors.NotFound) {
|
|
80
|
+
throw new Error(`acli is not installed. Install it from ${INSTALL_GUIDE}, then run: acli jira auth login --web`);
|
|
81
|
+
}
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
const decoder = new TextDecoder();
|
|
85
|
+
const stdout = decoder.decode(result.stdout);
|
|
86
|
+
const output = `${stdout}\n${decoder.decode(result.stderr)}`.replace(ANSI_ESCAPE, "");
|
|
87
|
+
return { code: result.code, stdout, output };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function checkSignedInSite(site: string): Promise<void> {
|
|
91
|
+
const status = await runAcli(["jira", "auth", "status"]);
|
|
92
|
+
if (status.code !== 0) {
|
|
93
|
+
throw new Error(`acli is not signed in to Jira. ${SIGN_IN}`);
|
|
94
|
+
}
|
|
95
|
+
const siteLine = status.output.split(/\r?\n/).map((line) => /^\s*Site:\s*(\S+)\s*$/.exec(line)).find((match) => match);
|
|
96
|
+
if (!siteLine) {
|
|
97
|
+
throw new Error(`acli jira auth status did not name a site: ${status.output.trim()}. ${SIGN_IN}`);
|
|
98
|
+
}
|
|
99
|
+
const current = siteLine[1].replace(/^https?:\/\//i, "").replace(/\/+$/, "");
|
|
100
|
+
if (current.toLowerCase() !== site.toLowerCase()) {
|
|
101
|
+
throw new Error(`acli is signed in to ${current}, not ${site}. Run: acli jira auth switch --site ${site}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function viewIssue(key: string): Promise<AcliIssue & { key: string }> {
|
|
106
|
+
const view = await runAcli(["jira", "workitem", "view", key, "--json", "--fields", VIEW_FIELDS]);
|
|
107
|
+
if (view.code !== 0) {
|
|
108
|
+
if (view.output.includes(NOT_FOUND)) {
|
|
109
|
+
throw new Error(`Jira work item not found: ${key}. It doesn't exist, or the account acli is signed in as can't see it.`);
|
|
110
|
+
}
|
|
111
|
+
if (/unauthori[sz]ed/i.test(view.output)) {
|
|
112
|
+
throw new Error(`acli is not signed in to Jira, or its session has expired. ${SIGN_IN}`);
|
|
113
|
+
}
|
|
114
|
+
throw new Error(`acli jira workitem view ${key} failed: ${view.output.trim()}`);
|
|
115
|
+
}
|
|
116
|
+
let issue: AcliIssue;
|
|
117
|
+
try {
|
|
118
|
+
issue = JSON.parse(view.stdout);
|
|
119
|
+
} catch {
|
|
120
|
+
throw new Error(`acli jira workitem view ${key} failed: it did not print JSON: ${view.stdout.trim().slice(0, 200)}`);
|
|
121
|
+
}
|
|
122
|
+
if (typeof issue?.key !== "string" || !KEY.test(issue.key)) {
|
|
123
|
+
throw new Error(`acli jira workitem view ${key} failed: it returned no work item key`);
|
|
124
|
+
}
|
|
125
|
+
if (projectOf(issue.key) !== projectOf(key)) {
|
|
126
|
+
throw new Error(`Jira work item not found: ${key} (moved to ${issue.key})`);
|
|
127
|
+
}
|
|
128
|
+
return issue as AcliIssue & { key: string };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Reads Jira work items through acli. */
|
|
132
|
+
export const model = {
|
|
133
|
+
type: "@batman/jira",
|
|
134
|
+
version: "2026.11.09.1",
|
|
135
|
+
globalArguments: GlobalArgsSchema,
|
|
136
|
+
resources: {
|
|
137
|
+
issue: {
|
|
138
|
+
description: "One Jira work item as acli returned it, with a browse URL and the time it was fetched",
|
|
139
|
+
schema: IssueSchema,
|
|
140
|
+
lifetime: "infinite",
|
|
141
|
+
garbageCollection: 10,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
methods: {
|
|
145
|
+
fetch: {
|
|
146
|
+
description: "Fetch one work item by key and write it as the record issue-<key>",
|
|
147
|
+
arguments: FetchArgsSchema,
|
|
148
|
+
execute: async (
|
|
149
|
+
args: z.infer<typeof FetchArgsSchema>,
|
|
150
|
+
context: {
|
|
151
|
+
globalArgs: z.infer<typeof GlobalArgsSchema>;
|
|
152
|
+
writeResource: (specName: string, name: string, data: Record<string, unknown>) => Promise<{ name: string }>;
|
|
153
|
+
},
|
|
154
|
+
) => {
|
|
155
|
+
const { key } = args;
|
|
156
|
+
const { site } = context.globalArgs;
|
|
157
|
+
if (!KEY.test(key)) {
|
|
158
|
+
throw new Error(`Not a Jira work item key: ${key}`);
|
|
159
|
+
}
|
|
160
|
+
if (!SITE.test(site)) {
|
|
161
|
+
throw new Error(`Not a Jira site hostname: ${site}`);
|
|
162
|
+
}
|
|
163
|
+
await checkSignedInSite(site);
|
|
164
|
+
const issue = await viewIssue(key);
|
|
165
|
+
const fields = issue.fields ?? {};
|
|
166
|
+
const comments = (fields.comment?.comments ?? []).slice(-MAX_COMMENTS).map((comment) => ({
|
|
167
|
+
author: comment.author?.displayName ?? null,
|
|
168
|
+
created: comment.created ?? null,
|
|
169
|
+
body: comment.body ?? null,
|
|
170
|
+
}));
|
|
171
|
+
const labels = Array.isArray(fields.labels)
|
|
172
|
+
? fields.labels.filter((label): label is string => typeof label === "string")
|
|
173
|
+
: [];
|
|
174
|
+
const handle = await context.writeResource("issue", `issue-${key}`, {
|
|
175
|
+
key: issue.key,
|
|
176
|
+
site,
|
|
177
|
+
url: `https://${site}/browse/${issue.key}`,
|
|
178
|
+
summary: fields.summary ?? null,
|
|
179
|
+
description: fields.description ?? null,
|
|
180
|
+
status: fields.status?.name ?? null,
|
|
181
|
+
priority: fields.priority?.name ?? null,
|
|
182
|
+
issueType: fields.issuetype?.name ?? null,
|
|
183
|
+
labels,
|
|
184
|
+
comments,
|
|
185
|
+
fetchedAt: new Date().toISOString(),
|
|
186
|
+
});
|
|
187
|
+
return { dataHandles: [handle] };
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
};
|