semantifold 0.5.0 → 0.7.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/README.md +15 -9
- package/build/index.d.ts +8 -8
- package/build/index.d.ts.map +1 -1
- package/build/index.js +6 -6
- package/build/src/backends/android.js +8 -4
- package/build/src/backends/dart.d.ts +19 -0
- package/build/src/backends/dart.d.ts.map +1 -1
- package/build/src/backends/dart.js +28 -16
- package/build/src/backends/flutter.d.ts +51 -0
- package/build/src/backends/flutter.d.ts.map +1 -0
- package/build/src/backends/flutter.js +1362 -0
- package/build/src/backends/identifiers.d.ts +6 -0
- package/build/src/backends/identifiers.d.ts.map +1 -1
- package/build/src/backends/identifiers.js +28 -5
- package/build/src/backends/ios.js +2 -2
- package/build/src/backends/native-validation.d.ts +2 -2
- package/build/src/backends/native-validation.d.ts.map +1 -1
- package/build/src/backends/native-validation.js +2 -2
- package/build/src/backends/program.d.ts +4 -4
- package/build/src/backends/program.d.ts.map +1 -1
- package/build/src/backends/program.js +4 -4
- package/build/src/backends/scalars.d.ts.map +1 -1
- package/build/src/backends/scalars.js +2 -1
- package/build/src/backends/shared.d.ts +7 -0
- package/build/src/backends/shared.d.ts.map +1 -1
- package/build/src/backends/shared.js +14 -9
- package/build/src/backends/zig-runtime.d.ts +5 -0
- package/build/src/backends/zig-runtime.d.ts.map +1 -0
- package/build/src/backends/zig-runtime.js +92 -0
- package/build/src/backends/zig-validation.d.ts +9 -0
- package/build/src/backends/zig-validation.d.ts.map +1 -0
- package/build/src/backends/zig-validation.js +73 -0
- package/build/src/backends/zig.d.ts +42 -0
- package/build/src/backends/zig.d.ts.map +1 -0
- package/build/src/backends/zig.js +584 -0
- package/build/src/frontends/scalars.d.ts.map +1 -1
- package/build/src/frontends/scalars.js +2 -1
- package/build/src/frontends/zig-parser.d.ts +31 -0
- package/build/src/frontends/zig-parser.d.ts.map +1 -0
- package/build/src/frontends/zig-parser.js +17 -0
- package/build/src/frontends/zig.d.ts +14 -0
- package/build/src/frontends/zig.d.ts.map +1 -0
- package/build/src/frontends/zig.js +970 -0
- package/build/src/language-registry.d.ts.map +1 -1
- package/build/src/language-registry.js +40 -1
- package/build/src/mapping.js +2 -2
- package/build/src/semantic/provenance.js +3 -3
- package/build/src/semantic/types.d.ts +154 -4
- package/build/src/semantic/types.d.ts.map +1 -1
- package/build/src/semantic/types.js +39 -3
- package/build/src/semantic/validate.js +2 -2
- package/build/src/toolchains.d.ts +6 -0
- package/build/src/toolchains.d.ts.map +1 -1
- package/build/src/toolchains.js +2 -1
- package/build/src/zig-bindings.d.ts +10 -0
- package/build/src/zig-bindings.d.ts.map +1 -0
- package/build/src/zig-bindings.js +54 -0
- package/docs/android.md +7 -3
- package/docs/architecture.md +13 -5
- package/docs/flutter.md +47 -0
- package/docs/goals.md +1 -1
- package/docs/language-support.md +16 -5
- package/docs/parser-qualification.md +31 -1
- package/docs/source-maps.md +7 -3
- package/docs/testing.md +47 -4
- package/docs/zig.md +33 -0
- package/index.js +5 -5
- package/node_modules/semantifold-tree-sitter-zig-internal/LICENSE +15 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/README.md +5 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/LICENSE +21 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/README.md +21 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/binding.gyp +29 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/bindings/node/binding.cc +20 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/bindings/node/binding_test.js +9 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/bindings/node/index.d.ts +28 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/bindings/node/index.js +11 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/grammar.js +900 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/package.json +57 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/prebuilds/darwin-arm64/@tree-sitter-grammars+tree-sitter-zig.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/prebuilds/darwin-x64/@tree-sitter-grammars+tree-sitter-zig.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/prebuilds/linux-arm64/@tree-sitter-grammars+tree-sitter-zig.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/prebuilds/linux-x64/@tree-sitter-grammars+tree-sitter-zig.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/prebuilds/win32-arm64/@tree-sitter-grammars+tree-sitter-zig.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/prebuilds/win32-x64/@tree-sitter-grammars+tree-sitter-zig.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/queries/folds.scm +23 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/queries/highlights.scm +291 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/queries/indents.scm +22 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/queries/injections.scm +10 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/src/grammar.json +6570 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/src/node-types.json +3178 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/src/parser.c +169829 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/src/tree_sitter/alloc.h +54 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/src/tree_sitter/array.h +291 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/src/tree_sitter/parser.h +266 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/tree-sitter-zig.wasm +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/@tree-sitter-grammars/tree-sitter-zig/tree-sitter.json +38 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/LICENSE +21 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/README.md +128 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/binding.gyp +80 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/index.js +916 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/package.json +76 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/prebuilds/darwin-arm64/tree-sitter.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/prebuilds/darwin-x64/tree-sitter.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/prebuilds/linux-arm64/tree-sitter.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/prebuilds/linux-x64/tree-sitter.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/prebuilds/win32-arm64/tree-sitter.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/prebuilds/win32-x64/tree-sitter.node +0 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/addon_data.h +47 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/binding.cc +35 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/conversions.cc +140 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/conversions.h +22 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/language.cc +106 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/language.h +17 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/logger.cc +70 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/logger.h +19 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/lookaheaditerator.cc +122 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/lookaheaditerator.h +33 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/node.cc +1088 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/node.h +30 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/parser.cc +306 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/parser.h +35 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/query.cc +397 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/query.h +40 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/tree.cc +316 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/tree.h +45 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/tree_cursor.cc +213 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/src/tree_cursor.h +52 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/tree-sitter.d.ts +1042 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/include/tree_sitter/api.h +1318 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/alloc.c +48 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/alloc.h +41 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/array.h +291 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/atomic.h +68 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/clock.h +146 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/error_costs.h +11 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/get_changed_ranges.c +501 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/get_changed_ranges.h +36 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/host.h +21 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/language.c +223 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/language.h +297 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/length.h +52 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lexer.c +435 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lexer.h +49 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lib.c +12 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/node.c +920 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/parser.c +2165 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/parser.h +266 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/point.h +62 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/portable/endian.h +206 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/query.c +4187 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/reduce_action.h +34 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/reusable_node.h +95 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/stack.c +899 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/stack.h +130 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/subtree.c +1066 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/subtree.h +399 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree.c +170 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree.h +31 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree_cursor.c +712 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree_cursor.h +48 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/ts_assert.h +11 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/ICU_SHA +1 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/LICENSE +414 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/README.md +29 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/ptypes.h +1 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/umachine.h +448 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/urename.h +1 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf.h +1 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf16.h +733 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf8.h +881 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode.h +83 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/stdlib-symbols.txt +24 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/stdlib.c +109 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/wasm-stdlib.h +1302 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm_store.c +1859 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm_store.h +31 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/package.json +21 -0
- package/node_modules/semantifold-tree-sitter-zig-internal/src/zig.js +134 -0
- package/package.json +11 -6
- package/src/backends/android.js +7 -3
- package/src/backends/dart.js +28 -15
- package/src/backends/flutter.js +1465 -0
- package/src/backends/identifiers.js +28 -4
- package/src/backends/ios.js +1 -1
- package/src/backends/native-validation.js +1 -1
- package/src/backends/program.js +3 -3
- package/src/backends/scalars.js +1 -0
- package/src/backends/shared.js +15 -11
- package/src/backends/zig-runtime.js +93 -0
- package/src/backends/zig-validation.js +68 -0
- package/src/backends/zig.js +579 -0
- package/src/frontends/scalars.js +1 -0
- package/src/frontends/zig-parser.js +20 -0
- package/src/frontends/zig.js +994 -0
- package/src/language-registry.js +40 -0
- package/src/mapping.js +1 -1
- package/src/semantic/provenance.js +2 -2
- package/src/semantic/types.js +41 -2
- package/src/semantic/validate.js +1 -1
- package/src/toolchains.js +1 -0
- package/src/zig-bindings.js +46 -0
|
@@ -0,0 +1,1362 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { isDenseArray } from "../array.js";
|
|
4
|
+
import { findPortableArtifactPathConflict, isSafeArtifactPath } from "../artifact-path.js";
|
|
5
|
+
import { createByteMapping } from "../binary-mapping.js";
|
|
6
|
+
import { SemantifoldDiagnostic, unsupportedCapability } from "../diagnostic.js";
|
|
7
|
+
import { finalizeMapping, toSourceMapV3 } from "../mapping.js";
|
|
8
|
+
import { hasOnlyUnicodeScalars } from "../semantic/scalars.js";
|
|
9
|
+
import { dartRuntime } from "./dart-runtime.js";
|
|
10
|
+
import { emitDartBlock, findUnreadDartLocals } from "./dart.js";
|
|
11
|
+
import { preflightSemanticProgram } from "./program.js";
|
|
12
|
+
import { emitScalarType } from "./scalars.js";
|
|
13
|
+
import { SourceWriter } from "./writer.js";
|
|
14
|
+
const projectRoot = "generated/flutter-app";
|
|
15
|
+
const generatorVersion = "0.6.0";
|
|
16
|
+
const flutterToolchain = Object.freeze({
|
|
17
|
+
archive: "flutter_linux_3.47.4-stable.tar.xz",
|
|
18
|
+
archiveSha256: "5b45f0ceda99b9bebdc873e7e69f6450aeb4c30f454b505e2e62fc9255a907d3",
|
|
19
|
+
dart: "3.13.3",
|
|
20
|
+
revision: "9584c6713b324636289d067944a46fd6b49df14b",
|
|
21
|
+
version: "3.47.4"
|
|
22
|
+
});
|
|
23
|
+
const androidToolchain = Object.freeze({
|
|
24
|
+
androidGradlePlugin: "8.11.1",
|
|
25
|
+
buildTools: "35.0.0",
|
|
26
|
+
cmake: "3.22.1",
|
|
27
|
+
compileSdk: 35,
|
|
28
|
+
gradle: "8.14",
|
|
29
|
+
java: "21.0.8",
|
|
30
|
+
kotlinGradlePlugin: "2.2.20",
|
|
31
|
+
minimumSdk: 23,
|
|
32
|
+
ndk: "27.0.12077973",
|
|
33
|
+
targetSdk: 35
|
|
34
|
+
});
|
|
35
|
+
/** @type {readonly (readonly [string, string, string])[]} */
|
|
36
|
+
const flutterLockedHostedPackages = Object.freeze([
|
|
37
|
+
["async", "2.13.1", "e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37"],
|
|
38
|
+
["boolean_selector", "2.1.2", "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"],
|
|
39
|
+
["characters", "1.4.1", "faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b"],
|
|
40
|
+
["clock", "1.1.3", "e51d50bca3217c9a9fa2b41a30e4a38971133f5f9ec7a3d57bae095007f1d28e"],
|
|
41
|
+
["collection", "1.19.1", "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"],
|
|
42
|
+
["fake_async", "1.3.3", "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"],
|
|
43
|
+
["leak_tracker", "11.0.2", "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"],
|
|
44
|
+
["leak_tracker_flutter_testing", "3.0.10", "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"],
|
|
45
|
+
["leak_tracker_testing", "3.0.2", "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"],
|
|
46
|
+
["matcher", "0.12.20", "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd"],
|
|
47
|
+
["material_color_utilities", "0.13.0", "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"],
|
|
48
|
+
["meta", "1.19.0", "307249ce4ff29d58a18e97f6345f539382eb9c9c29ecda628900f31de0443dd9"],
|
|
49
|
+
["path", "1.9.1", "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"],
|
|
50
|
+
["source_span", "1.10.2", "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"],
|
|
51
|
+
["stack_trace", "1.12.2", "277654b3034d17ac6f9f1cb5595db011b1d5d41e8806866db28e0abaa101c490"],
|
|
52
|
+
["stream_channel", "2.1.4", "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"],
|
|
53
|
+
["string_scanner", "1.4.1", "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"],
|
|
54
|
+
["term_glyph", "1.2.2", "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"],
|
|
55
|
+
["test_api", "0.7.12", "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11"],
|
|
56
|
+
["vector_math", "2.4.2", "f36f9f3be64c6198714492bb455c11056e33e2f85d9a0b676a48301e44fdcf47"],
|
|
57
|
+
["vm_service", "15.3.0", "5f37239c4851efcef929cea7824e76df7f2f0970aef85d66bbc430afa40e72f0"]
|
|
58
|
+
]);
|
|
59
|
+
/** @type {readonly (readonly [string, "direct main" | "direct dev" | "transitive"])[]} */
|
|
60
|
+
const flutterLockedSdkPackages = Object.freeze([
|
|
61
|
+
["flutter", "direct main"],
|
|
62
|
+
["flutter_test", "direct dev"],
|
|
63
|
+
["sky_engine", "transitive"]
|
|
64
|
+
]);
|
|
65
|
+
/** @type {Readonly<Set<import("../semantic/types.js").SemanticLanguage>>} */
|
|
66
|
+
const flutterSourceLanguages = new Set([
|
|
67
|
+
"php", "ruby", "javascript", "typescript", "java", "kotlin", "python", "csharp", "go", "c", "cpp", "rust", "swift", "dart", "zig"
|
|
68
|
+
]);
|
|
69
|
+
const requestFields = new Set(["assets", "configuration", "language", "module", "program", "role"]);
|
|
70
|
+
const configurationFields = new Set([
|
|
71
|
+
"activityClassName", "applicationId", "buildToolsVersion", "compileSdk", "displayName", "minimumSdk", "organization",
|
|
72
|
+
"packageName", "permissions", "targetSdk", "versionCode", "versionName"
|
|
73
|
+
]);
|
|
74
|
+
const assetFields = new Set(["content", "mediaType", "path", "sha256"]);
|
|
75
|
+
const dartKeywords = new Set([
|
|
76
|
+
"abstract", "as", "assert", "async", "await", "base", "break", "case", "catch", "class", "const", "continue",
|
|
77
|
+
"covariant", "default", "deferred", "do", "dynamic", "else", "enum", "export", "extends", "extension", "external",
|
|
78
|
+
"factory", "false", "final", "finally", "for", "Function", "get", "hide", "if", "implements", "import", "in",
|
|
79
|
+
"interface", "is", "late", "library", "mixin", "new", "null", "of", "on", "operator", "part", "required",
|
|
80
|
+
"rethrow", "return", "sealed", "set", "show", "static", "super", "switch", "sync", "this", "throw", "true",
|
|
81
|
+
"try", "typedef", "var", "void", "when", "while", "with", "yield"
|
|
82
|
+
]);
|
|
83
|
+
const javaKeywords = new Set([
|
|
84
|
+
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default",
|
|
85
|
+
"do", "double", "else", "enum", "extends", "final", "finally", "float", "for", "goto", "if", "implements",
|
|
86
|
+
"import", "instanceof", "int", "interface", "long", "native", "new", "package", "private", "protected", "public",
|
|
87
|
+
"return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient",
|
|
88
|
+
"try", "void", "volatile", "while"
|
|
89
|
+
]);
|
|
90
|
+
const forbiddenPackageNames = new Set([
|
|
91
|
+
...flutterLockedHostedPackages.map(([name]) => name),
|
|
92
|
+
...flutterLockedSdkPackages.map(([name]) => name),
|
|
93
|
+
"integration_test",
|
|
94
|
+
"semantifold"
|
|
95
|
+
]);
|
|
96
|
+
const androidRunnerBaseClassNames = new Set(["FlutterActivity"]);
|
|
97
|
+
const semanticVersionPattern = /^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-(?:0|[1-9][0-9]*|[A-Za-z-][A-Za-z0-9-]*)(?:\.(?:0|[1-9][0-9]*|[A-Za-z-][A-Za-z0-9-]*))*)?(?:\+[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*)?$/u;
|
|
98
|
+
const mediaTypePattern = /^[A-Za-z0-9!#$&^_.+-]+\/[A-Za-z0-9!#$&^_.+-]+(?:[\u0020-\u007e]+)?$/u;
|
|
99
|
+
const excludedPathPatterns = Object.freeze([
|
|
100
|
+
".dart_tool/**", ".flutter-plugins", ".flutter-plugins-dependencies", "android/.gradle/**", "android/app/build/**",
|
|
101
|
+
"android/local.properties", "build/**"
|
|
102
|
+
]);
|
|
103
|
+
const outputSinkRuntime = `
|
|
104
|
+
final class _SemantifoldOutputSink {
|
|
105
|
+
final List<String> _values = <String>[];
|
|
106
|
+
|
|
107
|
+
void write(Object value) {
|
|
108
|
+
if (value is! int && value is! bool && value is! String) {
|
|
109
|
+
throw StateError('Unsupported Semantifold output value');
|
|
110
|
+
}
|
|
111
|
+
_values.add(value.toString());
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
List<String> snapshot() => List<String>.unmodifiable(_values);
|
|
115
|
+
}
|
|
116
|
+
`;
|
|
117
|
+
/** @typedef {{content: string | Uint8Array, contentKind: "binary" | "text", fullPath: string, mediaType: string, path: string, sha256: string}} FlutterAsset */
|
|
118
|
+
/** @typedef {{end: number, field: string, path: string, start: number}} ConfigurationSpan */
|
|
119
|
+
/**
|
|
120
|
+
* Preflights a complete Flutter application request before rendering any artifact.
|
|
121
|
+
* @param {Record<string, unknown>} input - Candidate application request.
|
|
122
|
+
* @returns {{assets: FlutterAsset[], configuration: import("../semantic/types.js").FlutterApplicationConfiguration, modulePaths: Map<string, string>, modules: import("../semantic/types.js").SemanticModule[], packagePath: string, program: import("../semantic/types.js").SemanticProgram, sources: {content: string, filename: string, language?: import("../semantic/types.js").SemanticLanguage}[]}} Prepared application.
|
|
123
|
+
*/
|
|
124
|
+
export function preflightFlutterApplication(input) {
|
|
125
|
+
if (!isPlainObject(input) || Object.keys(input).some(key => !requestFields.has(key)) ||
|
|
126
|
+
Boolean(input.module) == Boolean(input.program)) {
|
|
127
|
+
invalidInput("Flutter application generation requires a closed request with exactly one semantic module or program.");
|
|
128
|
+
}
|
|
129
|
+
if (input.language !== undefined && input.language != "flutter" || input.role !== undefined && input.role != "application") {
|
|
130
|
+
invalidInput("Flutter application generation accepts only the Flutter application role.");
|
|
131
|
+
}
|
|
132
|
+
const configuration = normalizeConfiguration(input.configuration);
|
|
133
|
+
const program = input.program ?? normalizeSingleModule(
|
|
134
|
+
/** @type {import("../semantic/types.js").SemanticModule | undefined} */ (input.module));
|
|
135
|
+
const prepared = preflightSemanticProgram({
|
|
136
|
+
backendLanguage: "dart",
|
|
137
|
+
diagnosticLanguage: "flutter",
|
|
138
|
+
program: /** @type {import("../semantic/types.js").SemanticProgram} */ (program),
|
|
139
|
+
sourceLanguages: flutterSourceLanguages
|
|
140
|
+
});
|
|
141
|
+
const entryModule = prepared.modules.find(module => Reflect.get(module, "id") == prepared.program.entryModule);
|
|
142
|
+
const entryCollision = entryModule?.functions.find(({ name }) => name == "semantifoldEntry");
|
|
143
|
+
if (entryCollision)
|
|
144
|
+
unsupportedCapability("flutter", "reserved generated semantic entry function 'semantifoldEntry'", entryCollision.location);
|
|
145
|
+
const packagePath = configuration.applicationId.replaceAll(".", "/");
|
|
146
|
+
const modulePaths = new Map(prepared.modules.map(module => {
|
|
147
|
+
const moduleId = /** @type {string} */ (Reflect.get(module, "id"));
|
|
148
|
+
return [moduleId, `${projectRoot}/lib/src/semantic/${moduleFileName(moduleId)}.dart`];
|
|
149
|
+
}));
|
|
150
|
+
const assets = normalizeAssets(input.assets);
|
|
151
|
+
const completePaths = [...applicationPaths(configuration, modulePaths), ...assets.map(({ fullPath }) => fullPath)];
|
|
152
|
+
const conflict = findPortableArtifactPathConflict(completePaths);
|
|
153
|
+
if (conflict) {
|
|
154
|
+
invalidPath(`Application artifact path '${conflict.path}' has a ${conflict.kind} conflict${conflict.other ? ` with '${conflict.other}'` : ""}.`);
|
|
155
|
+
}
|
|
156
|
+
const semanticNames = new Map();
|
|
157
|
+
for (const module of prepared.modules) {
|
|
158
|
+
const moduleId = /** @type {string} */ (Reflect.get(module, "id"));
|
|
159
|
+
const name = moduleName(moduleId);
|
|
160
|
+
const previous = semanticNames.get(name);
|
|
161
|
+
if (previous)
|
|
162
|
+
invalidPath(`Semantic modules '${previous}' and '${moduleId}' collide at generated Dart class '${name}'.`);
|
|
163
|
+
semanticNames.set(name, moduleId);
|
|
164
|
+
}
|
|
165
|
+
return { ...prepared, assets, configuration, modulePaths, packagePath };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Generates one deterministic SDK-only Flutter project for the qualified Android lane.
|
|
169
|
+
* @param {Record<string, unknown>} input - Application generation request.
|
|
170
|
+
* @returns {{artifacts: import("../semantic/types.js").GeneratedSetArtifact[], metadata: {applicationManifest: string, platformQualification: {android: string, ios: string}}, target: "flutter"}} Candidate artifact set.
|
|
171
|
+
*/
|
|
172
|
+
export function generateFlutterApplication(input) {
|
|
173
|
+
const prepared = preflightFlutterApplication(input);
|
|
174
|
+
const configurationSpans = /** @type {ConfigurationSpan[]} */ ([]);
|
|
175
|
+
const configuration = prepared.configuration;
|
|
176
|
+
const semanticArtifacts = renderSemanticArtifacts(prepared);
|
|
177
|
+
const artifacts = /** @type {import("../semantic/types.js").GeneratedSetArtifact[]} */ ([
|
|
178
|
+
syntheticText(`${projectRoot}/.metadata`, "manifest", renderMetadata(), "Exact Flutter 3.47.4 project-template identity; generated migration is disabled."),
|
|
179
|
+
syntheticText(`${projectRoot}/analysis_options.yaml`, "support", renderAnalysisOptions(), "Closed analyzer configuration without external lint packages."),
|
|
180
|
+
configuredText(`${projectRoot}/android/app/build.gradle.kts`, "manifest", renderAndroidAppBuild(configuration, configurationSpans), "Task 028-compatible Android build and isolated debug-signing configuration."),
|
|
181
|
+
configuredText(`${projectRoot}/android/app/src/main/AndroidManifest.xml`, "manifest", renderAndroidManifest(configuration, configurationSpans), "Closed permission-free Flutter Android application manifest."),
|
|
182
|
+
configuredText(`${projectRoot}/android/app/src/main/java/${prepared.packagePath}/${configuration.activityClassName}.java`, "support", renderAndroidActivity(configuration, configurationSpans), "Synthetic Flutter Android embedding launcher."),
|
|
183
|
+
syntheticText(`${projectRoot}/android/app/src/main/res/drawable/launch_background.xml`, "resource", renderLaunchBackground(), "Synthetic minimum-SDK-qualified Flutter launch background."),
|
|
184
|
+
syntheticText(`${projectRoot}/android/app/src/main/res/values-night/styles.xml`, "resource", renderAndroidStyles(true), "Synthetic dark platform launch and Flutter host themes."),
|
|
185
|
+
syntheticText(`${projectRoot}/android/app/src/main/res/values/styles.xml`, "resource", renderAndroidStyles(false), "Synthetic light platform launch and Flutter host themes."),
|
|
186
|
+
syntheticText(`${projectRoot}/android/app/src/main/res/xml/backup_rules.xml`, "resource", renderBackupRules(), "Closed API 23-30 full-backup exclusions reused from the Android safety contract."),
|
|
187
|
+
syntheticText(`${projectRoot}/android/app/src/main/res/xml/data_extraction_rules.xml`, "resource", renderDataExtractionRules(), "Closed Android 12+ backup and transfer exclusions reused from the Android safety contract."),
|
|
188
|
+
syntheticText(`${projectRoot}/android/build.gradle.kts`, "manifest", renderAndroidRootBuild(), "Task 028-compatible deterministic Android root build."),
|
|
189
|
+
syntheticText(`${projectRoot}/android/gradle.properties`, "support", renderAndroidGradleProperties(), "Pinned isolated Gradle properties for the qualified Android lane."),
|
|
190
|
+
configuredText(`${projectRoot}/android/settings.gradle.kts`, "manifest", renderAndroidSettings(configuration, configurationSpans), "Exact Flutter Gradle plugin loader with the pinned Task 028 Android plugin matrix."),
|
|
191
|
+
configuredText(`${projectRoot}/lib/main.dart`, "entry", renderWidgetApplication(prepared, configurationSpans), "Synthetic stateless Material application and labelled output widget."),
|
|
192
|
+
...semanticArtifacts,
|
|
193
|
+
syntheticText(`${projectRoot}/pubspec.lock`, "manifest", renderPubspecLock(), "Exact Flutter 3.47.4 SDK dependency resolution; no caller package resolution."),
|
|
194
|
+
configuredText(`${projectRoot}/pubspec.yaml`, "manifest", renderPubspec(prepared, configurationSpans), "Closed SDK-only Flutter package and asset manifest."),
|
|
195
|
+
configuredText(`${projectRoot}/test/semantic_logic_test.dart`, "support", renderLogicTest(prepared, configurationSpans), "SDK-owned Flutter test for fresh deterministic semantic entry execution."),
|
|
196
|
+
configuredText(`${projectRoot}/test/widget_test.dart`, "support", renderWidgetTest(prepared, configurationSpans), "SDK-owned Flutter widget test for exact text, key, and semantics label."),
|
|
197
|
+
...prepared.assets.map(assetArtifact)
|
|
198
|
+
]);
|
|
199
|
+
artifacts.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
|
|
200
|
+
const manifestPath = `${projectRoot}/semantifold-project.json`;
|
|
201
|
+
artifacts.push(syntheticText(manifestPath, "manifest", renderProjectManifest(prepared, artifacts, manifestPath, configurationSpans), "Versioned Flutter project ownership, toolchain, provenance, and platform-status manifest."));
|
|
202
|
+
return {
|
|
203
|
+
artifacts,
|
|
204
|
+
metadata: {
|
|
205
|
+
applicationManifest: manifestPath,
|
|
206
|
+
platformQualification: { android: "tensorbuzz-kvm", ios: "deferred-owner-direction" }
|
|
207
|
+
},
|
|
208
|
+
target: "flutter"
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Emits mapped application-owned Dart semantic modules.
|
|
213
|
+
* @param {ReturnType<typeof preflightFlutterApplication>} prepared - Prepared application.
|
|
214
|
+
* @returns {import("../semantic/types.js").GeneratedSetArtifact[]} Semantic Dart artifacts.
|
|
215
|
+
*/
|
|
216
|
+
function renderSemanticArtifacts(prepared) {
|
|
217
|
+
const declarations = new Map();
|
|
218
|
+
for (const module of prepared.modules) {
|
|
219
|
+
for (const declaration of module.functions)
|
|
220
|
+
declarations.set(declaration.id, {
|
|
221
|
+
declaration,
|
|
222
|
+
moduleId: /** @type {string} */ (Reflect.get(module, "id"))
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/** @type {import("../semantic/types.js").GeneratedSetArtifact[]} */
|
|
226
|
+
const artifacts = [syntheticText(`${projectRoot}/lib/src/semantic/semantifold.dart`, "support", renderSemanticLibrary(prepared), "Shared checked Dart scalar/output runtime and deterministic part ownership.")];
|
|
227
|
+
for (const module of prepared.modules) {
|
|
228
|
+
const moduleId = /** @type {string} */ (Reflect.get(module, "id"));
|
|
229
|
+
const filename = /** @type {string} */ (prepared.modulePaths.get(moduleId));
|
|
230
|
+
const sinkName = outputSinkName(module);
|
|
231
|
+
const writer = new SourceWriter({
|
|
232
|
+
callArgumentSuffix: sinkName,
|
|
233
|
+
callNameResolver: expression => {
|
|
234
|
+
const resolved = declarations.get(expression.resolution?.declarationId);
|
|
235
|
+
if (!resolved)
|
|
236
|
+
throw new TypeError(`Unknown validated Flutter function '${expression.resolution?.declarationId}'.`);
|
|
237
|
+
return `SemantifoldModule${moduleName(resolved.moduleId)}.${resolved.declaration.name}`;
|
|
238
|
+
},
|
|
239
|
+
filename,
|
|
240
|
+
language: "dart",
|
|
241
|
+
module,
|
|
242
|
+
program: prepared.program,
|
|
243
|
+
programPaths: prepared.modulePaths,
|
|
244
|
+
sources: prepared.sources
|
|
245
|
+
});
|
|
246
|
+
writer.synthetic("part of 'semantifold.dart';\n\n", "Flutter semantic library part directive", [module], [""]);
|
|
247
|
+
emitSemanticModule(writer, module, moduleId, moduleId == prepared.program.entryModule, sinkName);
|
|
248
|
+
const mapping = finalizeMapping(writer.finish());
|
|
249
|
+
artifacts.push({
|
|
250
|
+
content: mapping.generated.content,
|
|
251
|
+
contentKind: "text",
|
|
252
|
+
mediaType: "text/x-dart",
|
|
253
|
+
ownership: "generated",
|
|
254
|
+
path: filename,
|
|
255
|
+
provenance: { kind: "text", mapping, sourceMap: toSourceMapV3(mapping), sourceMapFilename: `${filename}.map` },
|
|
256
|
+
role: "source"
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
return artifacts;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Emits one namespaced semantic Dart part.
|
|
263
|
+
* @param {SourceWriter} writer - Mapped source writer.
|
|
264
|
+
* @param {import("../semantic/types.js").SemanticModule} module - Prepared semantic module.
|
|
265
|
+
* @param {string} moduleId - Stable semantic module identity.
|
|
266
|
+
* @param {boolean} entry - Whether this module owns the application entry.
|
|
267
|
+
* @param {string} sinkName - Collision-safe output sink binding.
|
|
268
|
+
*/
|
|
269
|
+
function emitSemanticModule(writer, module, moduleId, entry, sinkName) {
|
|
270
|
+
const unreadLocals = findUnreadDartLocals(module);
|
|
271
|
+
writer.synthetic(`abstract final class SemantifoldModule${moduleName(moduleId)} {\n`, "Flutter semantic module namespace", [module], [""]);
|
|
272
|
+
module.functions.forEach((declaration, functionIndex) => {
|
|
273
|
+
const path = `/functions/${functionIndex}`;
|
|
274
|
+
writer.synthetic(" static ", "Flutter namespaced function scaffold", [declaration], [path]);
|
|
275
|
+
writer.mapped(emitScalarType("dart", declaration.returnType), {
|
|
276
|
+
mappingKind: "exact", node: declaration.returnType, path: `${path}/returnType`, role: "type"
|
|
277
|
+
});
|
|
278
|
+
writer.synthetic(" ", "declaration spacing", [declaration], [path]);
|
|
279
|
+
writer.mapped(declaration.name, { mappingKind: "exact", node: declaration, path, role: "name" });
|
|
280
|
+
const parameterTexts = declaration.parameters.map(parameter => `${emitScalarType("dart", parameter.type)} ${parameter.name}`);
|
|
281
|
+
parameterTexts.push(`_SemantifoldOutputSink ${sinkName}`);
|
|
282
|
+
const multiline = writer.column - 1 + `(${parameterTexts.join(", ")}) {`.length > 80;
|
|
283
|
+
writer.mapped("(", { mappingKind: "anchor", node: declaration, path });
|
|
284
|
+
declaration.parameters.forEach((parameter, parameterIndex) => {
|
|
285
|
+
const parameterPath = `${path}/parameters/${parameterIndex}`;
|
|
286
|
+
if (multiline)
|
|
287
|
+
writer.synthetic(`${parameterIndex ? "" : "\n"} `, "Dart application parameter indentation", [parameter], [parameterPath]);
|
|
288
|
+
else if (parameterIndex)
|
|
289
|
+
writer.synthetic(", ", "parameter separator", [parameter], [parameterPath]);
|
|
290
|
+
writer.mapped(emitScalarType("dart", parameter.type), {
|
|
291
|
+
mappingKind: "exact", node: parameter.type, path: `${parameterPath}/type`, role: "type"
|
|
292
|
+
});
|
|
293
|
+
writer.synthetic(" ", "parameter spacing", [parameter], [parameterPath]);
|
|
294
|
+
writer.mapped(parameter.name, { mappingKind: "exact", node: parameter, path: parameterPath, role: "name" });
|
|
295
|
+
if (multiline)
|
|
296
|
+
writer.synthetic(",\n", "Dart formatter parameter separator", [parameter], [parameterPath]);
|
|
297
|
+
});
|
|
298
|
+
if (multiline)
|
|
299
|
+
writer.synthetic(`${declaration.parameters.length ? "" : "\n"} _SemantifoldOutputSink ${sinkName},\n `, "Flutter output sink parameter", [declaration], [path]);
|
|
300
|
+
else
|
|
301
|
+
writer.synthetic(`${declaration.parameters.length ? ", " : ""}_SemantifoldOutputSink ${sinkName}`, "Flutter output sink parameter", [declaration], [path]);
|
|
302
|
+
writer.mapped(")", { mappingKind: "anchor", node: declaration, path });
|
|
303
|
+
writer.synthetic(" {\n", "Dart function body scaffold", [declaration], [path]);
|
|
304
|
+
emitDartBlock(writer, declaration.body, " ", `${path}/body`, unreadLocals, `${sinkName}.write`, true);
|
|
305
|
+
writer.synthetic(" }\n", "Dart function body scaffold", [declaration], [path]);
|
|
306
|
+
if (functionIndex + 1 < module.functions.length || entry) {
|
|
307
|
+
writer.synthetic("\n", "Dart formatter declaration separator", [declaration], [path]);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
if (entry) {
|
|
311
|
+
writer.synthetic(" static List<String> semantifoldEntry() {\n", "Flutter semantic entry scaffold", [module.entryPoint], ["/entryPoint"]);
|
|
312
|
+
writer.synthetic(` final _SemantifoldOutputSink ${sinkName} = _SemantifoldOutputSink();\n`, "Flutter output sink allocation", [module.entryPoint], ["/entryPoint"]);
|
|
313
|
+
emitDartBlock(writer, module.entryPoint.body, " ", "/entryPoint/body", unreadLocals, `${sinkName}.write`, true);
|
|
314
|
+
writer.synthetic(` return ${sinkName}.snapshot();\n`, "Flutter semantic output return", [module.entryPoint], ["/entryPoint"]);
|
|
315
|
+
writer.synthetic(" }\n", "Flutter semantic entry scaffold", [module.entryPoint], ["/entryPoint"]);
|
|
316
|
+
}
|
|
317
|
+
writer.synthetic("}\n", "Flutter semantic module namespace", [module], [""]);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Renders the shared semantic Dart library.
|
|
321
|
+
* @param {ReturnType<typeof preflightFlutterApplication>} prepared - Prepared project.
|
|
322
|
+
* @returns {string} Dart library source.
|
|
323
|
+
*/
|
|
324
|
+
function renderSemanticLibrary(prepared) {
|
|
325
|
+
const parts = prepared.modules.map(module => `part '${moduleFileName(/** @type {string} */ (Reflect.get(module, "id")))}.dart';`).join("\n");
|
|
326
|
+
return `${parts}\n\n${dartRuntime}${outputSinkRuntime}`;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Renders exact Flutter template identity metadata.
|
|
330
|
+
* @returns {string} Metadata YAML.
|
|
331
|
+
*/
|
|
332
|
+
function renderMetadata() {
|
|
333
|
+
return `# This file tracks properties of this Semantifold-owned Flutter project.
|
|
334
|
+
version:
|
|
335
|
+
revision: ${flutterToolchain.revision}
|
|
336
|
+
channel: stable
|
|
337
|
+
project_type: app
|
|
338
|
+
`;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Renders the closed analyzer configuration.
|
|
342
|
+
* @returns {string} Analyzer YAML.
|
|
343
|
+
*/
|
|
344
|
+
function renderAnalysisOptions() {
|
|
345
|
+
return `analyzer:
|
|
346
|
+
language:
|
|
347
|
+
strict-casts: true
|
|
348
|
+
strict-raw-types: true
|
|
349
|
+
`;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Renders the SDK-only package manifest.
|
|
353
|
+
* @param {ReturnType<typeof preflightFlutterApplication>} prepared - Prepared project.
|
|
354
|
+
* @param {ConfigurationSpan[]} spans - Configuration provenance sink.
|
|
355
|
+
* @returns {string} Pubspec YAML.
|
|
356
|
+
*/
|
|
357
|
+
function renderPubspec(prepared, spans) {
|
|
358
|
+
const configuration = prepared.configuration;
|
|
359
|
+
const assetLines = prepared.assets.length == 0 ? "" : `\n assets:\n${prepared.assets.map(({ path }) => ` - ${path}`).join("\n")}\n`;
|
|
360
|
+
return configured(`${projectRoot}/pubspec.yaml`, spans, [
|
|
361
|
+
"name: ", field("packageName", configuration.packageName), "\npublish_to: none\nversion: ",
|
|
362
|
+
field("versionName", configuration.versionName), "+", field("versionCode", String(configuration.versionCode)),
|
|
363
|
+
"\nenvironment:\n sdk: 3.13.3\n flutter: 3.47.4\ndependencies:\n flutter:\n sdk: flutter\ndev_dependencies:\n flutter_test:\n sdk: flutter\nflutter:\n uses-material-design: true\n",
|
|
364
|
+
assetLines
|
|
365
|
+
]);
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Renders the exact Flutter SDK dependency lock.
|
|
369
|
+
* @returns {string} Pub lock YAML.
|
|
370
|
+
*/
|
|
371
|
+
function renderPubspecLock() {
|
|
372
|
+
const hosted = new Map(flutterLockedHostedPackages.map(package_ => [package_[0], package_]));
|
|
373
|
+
const sdk = new Map(flutterLockedSdkPackages);
|
|
374
|
+
const packageNames = [...hosted.keys(), ...sdk.keys()].sort();
|
|
375
|
+
const packages = packageNames.map(name => {
|
|
376
|
+
const sdkDependency = sdk.get(name);
|
|
377
|
+
if (sdkDependency)
|
|
378
|
+
return ` ${name}:
|
|
379
|
+
dependency: ${sdkDependency == "transitive" ? sdkDependency : `"${sdkDependency}"`}
|
|
380
|
+
description: flutter
|
|
381
|
+
source: sdk
|
|
382
|
+
version: "0.0.0"`;
|
|
383
|
+
const locked = hosted.get(name);
|
|
384
|
+
if (!locked)
|
|
385
|
+
throw new TypeError(`Missing validated Flutter lock entry '${name}'.`);
|
|
386
|
+
const [, version, sha256] = locked;
|
|
387
|
+
const renderedHash = /^[0-9]/u.test(sha256) ? `"${sha256}"` : sha256;
|
|
388
|
+
return ` ${name}:
|
|
389
|
+
dependency: transitive
|
|
390
|
+
description:
|
|
391
|
+
name: ${name}
|
|
392
|
+
sha256: ${renderedHash}
|
|
393
|
+
url: "https://pub.dev"
|
|
394
|
+
source: hosted
|
|
395
|
+
version: "${version}"`;
|
|
396
|
+
}).join("\n");
|
|
397
|
+
return `# Generated by pub
|
|
398
|
+
# See https://dart.dev/tools/pub/glossary#lockfile
|
|
399
|
+
packages:
|
|
400
|
+
${packages}
|
|
401
|
+
sdks:
|
|
402
|
+
dart: "3.13.3"
|
|
403
|
+
flutter: "3.47.4"
|
|
404
|
+
`;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Renders the synthetic Material widget shell.
|
|
408
|
+
* @param {ReturnType<typeof preflightFlutterApplication>} prepared - Prepared project.
|
|
409
|
+
* @param {ConfigurationSpan[]} spans - Configuration provenance sink.
|
|
410
|
+
* @returns {string} Flutter entry source.
|
|
411
|
+
*/
|
|
412
|
+
function renderWidgetApplication(prepared, spans) {
|
|
413
|
+
const entryClass = `SemantifoldModule${moduleName(prepared.program.entryModule)}`;
|
|
414
|
+
return configured(`${projectRoot}/lib/main.dart`, spans, [
|
|
415
|
+
`import 'package:flutter/material.dart';
|
|
416
|
+
|
|
417
|
+
import 'src/semantic/semantifold.dart';
|
|
418
|
+
|
|
419
|
+
void main() {
|
|
420
|
+
runApp(const SemantifoldApplication());
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
class SemantifoldApplication extends StatelessWidget {
|
|
424
|
+
const SemantifoldApplication({super.key});
|
|
425
|
+
|
|
426
|
+
@override
|
|
427
|
+
Widget build(BuildContext context) {
|
|
428
|
+
final List<String> lines = ${entryClass}.semantifoldEntry();
|
|
429
|
+
|
|
430
|
+
return MaterialApp(
|
|
431
|
+
debugShowCheckedModeBanner: false,
|
|
432
|
+
title: '`, field("displayName", dartEscape(prepared.configuration.displayName)), `',
|
|
433
|
+
home: Scaffold(
|
|
434
|
+
body: Center(
|
|
435
|
+
child: Semantics(
|
|
436
|
+
key: const Key('semantifold-output'),
|
|
437
|
+
container: true,
|
|
438
|
+
explicitChildNodes: true,
|
|
439
|
+
label: 'semantifold-output',
|
|
440
|
+
child: Text(lines.join('\\n')),
|
|
441
|
+
),
|
|
442
|
+
),
|
|
443
|
+
),
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
`
|
|
448
|
+
]);
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Renders the semantic-entry determinism test.
|
|
452
|
+
* @param {ReturnType<typeof preflightFlutterApplication>} prepared - Prepared project.
|
|
453
|
+
* @param {ConfigurationSpan[]} spans - Configuration provenance sink.
|
|
454
|
+
* @returns {string} Flutter test source.
|
|
455
|
+
*/
|
|
456
|
+
function renderLogicTest(prepared, spans) {
|
|
457
|
+
const entryClass = `SemantifoldModule${moduleName(prepared.program.entryModule)}`;
|
|
458
|
+
return configured(`${projectRoot}/test/semantic_logic_test.dart`, spans, [
|
|
459
|
+
"import 'package:flutter_test/flutter_test.dart';\nimport 'package:", field("packageName", prepared.configuration.packageName),
|
|
460
|
+
`/src/semantic/semantifold.dart';
|
|
461
|
+
|
|
462
|
+
void main() {
|
|
463
|
+
test('semantic entry is deterministic across fresh runs', () {
|
|
464
|
+
expect(
|
|
465
|
+
${entryClass}.semantifoldEntry(),
|
|
466
|
+
${entryClass}.semantifoldEntry(),
|
|
467
|
+
);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
`
|
|
471
|
+
]);
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Renders the exact labelled widget test.
|
|
475
|
+
* @param {ReturnType<typeof preflightFlutterApplication>} prepared - Prepared project.
|
|
476
|
+
* @param {ConfigurationSpan[]} spans - Configuration provenance sink.
|
|
477
|
+
* @returns {string} Flutter widget test source.
|
|
478
|
+
*/
|
|
479
|
+
function renderWidgetTest(prepared, spans) {
|
|
480
|
+
const entryClass = `SemantifoldModule${moduleName(prepared.program.entryModule)}`;
|
|
481
|
+
return configured(`${projectRoot}/test/widget_test.dart`, spans, [
|
|
482
|
+
"import 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\nimport 'package:",
|
|
483
|
+
field("packageName", prepared.configuration.packageName), `/main.dart';
|
|
484
|
+
import 'package:`, field("packageName", prepared.configuration.packageName), `/src/semantic/semantifold.dart';
|
|
485
|
+
|
|
486
|
+
void main() {
|
|
487
|
+
testWidgets('renders exact labelled semantic output', (
|
|
488
|
+
WidgetTester tester,
|
|
489
|
+
) async {
|
|
490
|
+
final String expected = ${entryClass}.semantifoldEntry().join('\\n');
|
|
491
|
+
|
|
492
|
+
await tester.pumpWidget(const SemantifoldApplication());
|
|
493
|
+
final Finder output = find.byKey(const Key('semantifold-output'));
|
|
494
|
+
|
|
495
|
+
expect(output, findsOneWidget);
|
|
496
|
+
expect(
|
|
497
|
+
tester.widget<Semantics>(output).properties.label,
|
|
498
|
+
'semantifold-output',
|
|
499
|
+
);
|
|
500
|
+
expect(
|
|
501
|
+
find.descendant(of: output, matching: find.text(expected)),
|
|
502
|
+
findsOneWidget,
|
|
503
|
+
);
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
`
|
|
507
|
+
]);
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Renders the shared Android root build.
|
|
511
|
+
* @returns {string} Gradle Kotlin source.
|
|
512
|
+
*/
|
|
513
|
+
function renderAndroidRootBuild() {
|
|
514
|
+
return `allprojects {
|
|
515
|
+
repositories {
|
|
516
|
+
google()
|
|
517
|
+
mavenCentral()
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get()
|
|
522
|
+
rootProject.layout.buildDirectory.value(newBuildDir)
|
|
523
|
+
|
|
524
|
+
subprojects {
|
|
525
|
+
project.layout.buildDirectory.value(newBuildDir.dir(project.name))
|
|
526
|
+
project.evaluationDependsOn(":app")
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
tasks.register<Delete>("clean") {
|
|
530
|
+
delete(rootProject.layout.buildDirectory)
|
|
531
|
+
}
|
|
532
|
+
`;
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Renders Flutter plugin and Android plugin ownership.
|
|
536
|
+
* @param {import("../semantic/types.js").FlutterApplicationConfiguration} configuration - Normalized configuration.
|
|
537
|
+
* @param {ConfigurationSpan[]} spans - Configuration provenance sink.
|
|
538
|
+
* @returns {string} Gradle settings source.
|
|
539
|
+
*/
|
|
540
|
+
function renderAndroidSettings(configuration, spans) {
|
|
541
|
+
return configured(`${projectRoot}/android/settings.gradle.kts`, spans, [`pluginManagement {
|
|
542
|
+
val flutterSdkPath = run {
|
|
543
|
+
val properties = java.util.Properties()
|
|
544
|
+
file("local.properties").inputStream().use { properties.load(it) }
|
|
545
|
+
requireNotNull(properties.getProperty("flutter.sdk")) { "flutter.sdk not set in local.properties" }
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
|
549
|
+
|
|
550
|
+
repositories {
|
|
551
|
+
google()
|
|
552
|
+
mavenCentral()
|
|
553
|
+
gradlePluginPortal()
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
plugins {
|
|
558
|
+
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
|
559
|
+
id("com.android.application") version "${androidToolchain.androidGradlePlugin}" apply false
|
|
560
|
+
id("org.jetbrains.kotlin.android") version "${androidToolchain.kotlinGradlePlugin}" apply false
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
rootProject.name = "`, field("packageName", configuration.packageName), `"
|
|
564
|
+
include(":app")
|
|
565
|
+
`]);
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Renders deterministic Android Gradle properties.
|
|
569
|
+
* @returns {string} Gradle properties.
|
|
570
|
+
*/
|
|
571
|
+
function renderAndroidGradleProperties() {
|
|
572
|
+
return `android.builtInKotlin=false
|
|
573
|
+
android.newDsl=false
|
|
574
|
+
android.useAndroidX=true
|
|
575
|
+
kotlin.stdlib.default.dependency=false
|
|
576
|
+
org.gradle.caching=false
|
|
577
|
+
org.gradle.configuration-cache=false
|
|
578
|
+
org.gradle.daemon=false
|
|
579
|
+
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -Duser.language=en -Duser.country=US -Duser.timezone=UTC
|
|
580
|
+
org.gradle.parallel=false
|
|
581
|
+
`;
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Renders the Flutter Android application build.
|
|
585
|
+
* @param {import("../semantic/types.js").FlutterApplicationConfiguration} configuration - Normalized configuration.
|
|
586
|
+
* @param {ConfigurationSpan[]} spans - Configuration provenance sink.
|
|
587
|
+
* @returns {string} Application Gradle source.
|
|
588
|
+
*/
|
|
589
|
+
function renderAndroidAppBuild(configuration, spans) {
|
|
590
|
+
return configured(`${projectRoot}/android/app/build.gradle.kts`, spans, [`plugins {
|
|
591
|
+
id("com.android.application")
|
|
592
|
+
id("org.jetbrains.kotlin.android")
|
|
593
|
+
id("dev.flutter.flutter-gradle-plugin")
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
val semantifoldAcceptanceRoot = providers.environmentVariable("SEMANTIFOLD_FLUTTER_ACCEPTANCE_ROOT").orNull
|
|
597
|
+
?: throw GradleException("SEMANTIFOLD_FLUTTER_INFRASTRUCTURE: SEMANTIFOLD_FLUTTER_ACCEPTANCE_ROOT is required")
|
|
598
|
+
val semantifoldDebugKeystore = file("$semantifoldAcceptanceRoot/debug.keystore")
|
|
599
|
+
if (!semantifoldDebugKeystore.isFile) {
|
|
600
|
+
throw GradleException("SEMANTIFOLD_FLUTTER_INFRASTRUCTURE: ephemeral debug keystore is missing")
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
configurations.configureEach {
|
|
604
|
+
exclude(group = "androidx.profileinstaller", module = "profileinstaller")
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
android {
|
|
608
|
+
namespace = "`, field("applicationId", configuration.applicationId), `"
|
|
609
|
+
compileSdk = `, field("compileSdk", String(configuration.compileSdk)), `
|
|
610
|
+
buildToolsVersion = "`, field("buildToolsVersion", configuration.buildToolsVersion), `"
|
|
611
|
+
ndkVersion = "${androidToolchain.ndk}"
|
|
612
|
+
|
|
613
|
+
defaultConfig {
|
|
614
|
+
applicationId = "`, field("applicationId", configuration.applicationId), `"
|
|
615
|
+
minSdk = `, field("minimumSdk", String(configuration.minimumSdk)), `
|
|
616
|
+
targetSdk = `, field("targetSdk", String(configuration.targetSdk)), `
|
|
617
|
+
versionCode = `, field("versionCode", String(configuration.versionCode)), `
|
|
618
|
+
versionName = "`, field("versionName", configuration.versionName), `"
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
signingConfigs {
|
|
622
|
+
getByName("debug") {
|
|
623
|
+
storeFile = semantifoldDebugKeystore
|
|
624
|
+
storePassword = "android"
|
|
625
|
+
keyAlias = "androiddebugkey"
|
|
626
|
+
keyPassword = "android"
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
buildTypes {
|
|
631
|
+
getByName("debug") {
|
|
632
|
+
signingConfig = signingConfigs.getByName("debug")
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
buildFeatures {
|
|
637
|
+
buildConfig = false
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
compileOptions {
|
|
641
|
+
sourceCompatibility = JavaVersion.VERSION_17
|
|
642
|
+
targetCompatibility = JavaVersion.VERSION_17
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
lint {
|
|
646
|
+
abortOnError = true
|
|
647
|
+
checkDependencies = true
|
|
648
|
+
disable += "MissingApplicationIcon"
|
|
649
|
+
disable += "OldTargetApi"
|
|
650
|
+
disable += "GradleDependency"
|
|
651
|
+
warningsAsErrors = true
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
flutter {
|
|
656
|
+
source = "../.."
|
|
657
|
+
}
|
|
658
|
+
`]);
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Renders the permission-free Android manifest.
|
|
662
|
+
* @param {import("../semantic/types.js").FlutterApplicationConfiguration} configuration - Normalized configuration.
|
|
663
|
+
* @param {ConfigurationSpan[]} spans - Configuration provenance sink.
|
|
664
|
+
* @returns {string} Android manifest XML.
|
|
665
|
+
*/
|
|
666
|
+
function renderAndroidManifest(configuration, spans) {
|
|
667
|
+
return configured(`${projectRoot}/android/app/src/main/AndroidManifest.xml`, spans, [
|
|
668
|
+
`<manifest
|
|
669
|
+
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
670
|
+
xmlns:tools="http://schemas.android.com/tools">
|
|
671
|
+
<permission tools:node="removeAll" />
|
|
672
|
+
<uses-permission tools:node="removeAll" />
|
|
673
|
+
<application
|
|
674
|
+
android:allowBackup="false"
|
|
675
|
+
android:dataExtractionRules="@xml/data_extraction_rules"
|
|
676
|
+
android:fullBackupContent="@xml/backup_rules"
|
|
677
|
+
android:label="`, field("displayName", xmlEscape(configuration.displayName)), `"
|
|
678
|
+
android:name="\${applicationName}"
|
|
679
|
+
android:supportsRtl="true">
|
|
680
|
+
<activity
|
|
681
|
+
android:name=".`, field("activityClassName", configuration.activityClassName), `"
|
|
682
|
+
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
|
683
|
+
android:exported="true"
|
|
684
|
+
android:hardwareAccelerated="true"
|
|
685
|
+
android:launchMode="singleTop"
|
|
686
|
+
android:taskAffinity=""
|
|
687
|
+
android:theme="@style/LaunchTheme"
|
|
688
|
+
android:windowSoftInputMode="adjustResize">
|
|
689
|
+
<meta-data
|
|
690
|
+
android:name="io.flutter.embedding.android.NormalTheme"
|
|
691
|
+
android:resource="@style/NormalTheme" />
|
|
692
|
+
<intent-filter>
|
|
693
|
+
<action android:name="android.intent.action.MAIN" />
|
|
694
|
+
<category android:name="android.intent.category.LAUNCHER" />
|
|
695
|
+
</intent-filter>
|
|
696
|
+
</activity>
|
|
697
|
+
<meta-data android:name="flutterEmbedding" android:value="2" />
|
|
698
|
+
<provider android:name="androidx.startup.InitializationProvider" tools:node="remove" />
|
|
699
|
+
</application>
|
|
700
|
+
</manifest>
|
|
701
|
+
`
|
|
702
|
+
]);
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Renders the Java Flutter activity launcher.
|
|
706
|
+
* @param {import("../semantic/types.js").FlutterApplicationConfiguration} configuration - Normalized configuration.
|
|
707
|
+
* @param {ConfigurationSpan[]} spans - Configuration provenance sink.
|
|
708
|
+
* @returns {string} Java source.
|
|
709
|
+
*/
|
|
710
|
+
function renderAndroidActivity(configuration, spans) {
|
|
711
|
+
return configured(`${projectRoot}/android/app/src/main/java/${configuration.applicationId.replaceAll(".", "/")}/${configuration.activityClassName}.java`, spans, [
|
|
712
|
+
"package ", field("applicationId", configuration.applicationId), `;
|
|
713
|
+
|
|
714
|
+
import io.flutter.embedding.android.FlutterActivity;
|
|
715
|
+
|
|
716
|
+
public final class `, field("activityClassName", configuration.activityClassName), ` extends FlutterActivity {
|
|
717
|
+
}
|
|
718
|
+
`
|
|
719
|
+
]);
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Renders platform launch and host styles.
|
|
723
|
+
* @param {boolean} night - Whether to render the night theme.
|
|
724
|
+
* @returns {string} Android resource XML.
|
|
725
|
+
*/
|
|
726
|
+
function renderAndroidStyles(night) {
|
|
727
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
728
|
+
<resources>
|
|
729
|
+
<style name="LaunchTheme" parent="@android:style/Theme.${night ? "Black" : "Light"}.NoTitleBar">
|
|
730
|
+
<item name="android:windowBackground">@drawable/launch_background</item>
|
|
731
|
+
</style>
|
|
732
|
+
<style name="NormalTheme" parent="@android:style/Theme.${night ? "Black" : "Light"}.NoTitleBar">
|
|
733
|
+
<item name="android:windowBackground">?android:colorBackground</item>
|
|
734
|
+
</style>
|
|
735
|
+
</resources>
|
|
736
|
+
`;
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Renders a platform launch background.
|
|
740
|
+
* @returns {string} Android resource XML.
|
|
741
|
+
*/
|
|
742
|
+
function renderLaunchBackground() {
|
|
743
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
744
|
+
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
|
745
|
+
<item android:drawable="?android:colorBackground" />
|
|
746
|
+
</layer-list>
|
|
747
|
+
`;
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Renders complete legacy backup exclusions.
|
|
751
|
+
* @returns {string} Android resource XML.
|
|
752
|
+
*/
|
|
753
|
+
function renderBackupRules() {
|
|
754
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
755
|
+
<full-backup-content>
|
|
756
|
+
<exclude domain="root" path="." />
|
|
757
|
+
<exclude domain="file" path="." />
|
|
758
|
+
<exclude domain="database" path="." />
|
|
759
|
+
<exclude domain="sharedpref" path="." />
|
|
760
|
+
<exclude domain="external" path="." />
|
|
761
|
+
<exclude domain="device_root" path="." />
|
|
762
|
+
<exclude domain="device_file" path="." />
|
|
763
|
+
<exclude domain="device_database" path="." />
|
|
764
|
+
<exclude domain="device_sharedpref" path="." />
|
|
765
|
+
</full-backup-content>
|
|
766
|
+
`;
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Renders complete Android 12+ backup exclusions.
|
|
770
|
+
* @returns {string} Android resource XML.
|
|
771
|
+
*/
|
|
772
|
+
function renderDataExtractionRules() {
|
|
773
|
+
const exclusions = ["root", "file", "database", "sharedpref", "external", "device_root", "device_file", "device_database", "device_sharedpref"]
|
|
774
|
+
.map(domain => ` <exclude domain="${domain}" path="." />`).join("\n");
|
|
775
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
776
|
+
<data-extraction-rules>
|
|
777
|
+
<cloud-backup>
|
|
778
|
+
${exclusions}
|
|
779
|
+
</cloud-backup>
|
|
780
|
+
<device-transfer>
|
|
781
|
+
${exclusions}
|
|
782
|
+
</device-transfer>
|
|
783
|
+
</data-extraction-rules>
|
|
784
|
+
`;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Renders the ownership, toolchain, provenance, and platform-status manifest.
|
|
788
|
+
* @param {ReturnType<typeof preflightFlutterApplication>} prepared - Prepared application.
|
|
789
|
+
* @param {import("../semantic/types.js").GeneratedSetArtifact[]} artifacts - Owned artifacts except this manifest.
|
|
790
|
+
* @param {string} manifestPath - Manifest artifact path.
|
|
791
|
+
* @param {ConfigurationSpan[]} spans - Configuration provenance spans.
|
|
792
|
+
* @returns {string} Canonical manifest JSON.
|
|
793
|
+
*/
|
|
794
|
+
function renderProjectManifest(prepared, artifacts, manifestPath, spans) {
|
|
795
|
+
const inputPaths = new Set(prepared.assets.map(({ fullPath }) => fullPath));
|
|
796
|
+
const semanticArtifacts = artifacts.filter(artifact => artifact.provenance.kind == "text");
|
|
797
|
+
return stringifyCanonicalJson({
|
|
798
|
+
configuration: prepared.configuration,
|
|
799
|
+
generator: { name: "semantifold", version: generatorVersion },
|
|
800
|
+
ownership: {
|
|
801
|
+
excludedPathPatterns,
|
|
802
|
+
ownedPaths: [...artifacts.map(({ path }) => path), manifestPath],
|
|
803
|
+
ownedRoot: projectRoot,
|
|
804
|
+
sha256: artifacts.map(artifact => ({ path: artifact.path, sha256: hashContent(artifact.content) }))
|
|
805
|
+
},
|
|
806
|
+
platforms: {
|
|
807
|
+
android: { acceptance: "tensorbuzz-kvm", artifacts: "generated" },
|
|
808
|
+
ios: {
|
|
809
|
+
acceptance: "deferred",
|
|
810
|
+
artifacts: "omitted",
|
|
811
|
+
reason: "Owner direction defers macOS, Xcode, Apple SDK, signing, and iOS Simulator qualification."
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
provenance: {
|
|
815
|
+
configuration: Object.keys(prepared.configuration).sort().map(fieldName => ({
|
|
816
|
+
field: fieldName,
|
|
817
|
+
manifestPointer: `/configuration/${fieldName}`,
|
|
818
|
+
outputs: configurationOutputs(spans, fieldName)
|
|
819
|
+
})),
|
|
820
|
+
inputs: prepared.assets.map(asset => ({
|
|
821
|
+
contentKind: asset.contentKind,
|
|
822
|
+
mediaType: asset.mediaType,
|
|
823
|
+
path: asset.fullPath,
|
|
824
|
+
sha256: asset.sha256
|
|
825
|
+
})),
|
|
826
|
+
semanticSources: prepared.sources.map(source => ({
|
|
827
|
+
artifacts: semanticArtifacts.filter(artifact => artifact.provenance.kind == "text" &&
|
|
828
|
+
artifact.provenance.mapping.spans.some(({ origin }) => originReferencesFilename(origin, source.filename)))
|
|
829
|
+
.map(({ path }) => path),
|
|
830
|
+
filename: source.filename,
|
|
831
|
+
...(source.language === undefined ? {} : { language: source.language }),
|
|
832
|
+
sha256: createHash("sha256").update(source.content).digest("hex")
|
|
833
|
+
})),
|
|
834
|
+
syntheticScaffolding: [...artifacts.filter(artifact => artifact.provenance.kind == "synthetic" &&
|
|
835
|
+
!inputPaths.has(artifact.path)).map(({ path }) => path), manifestPath]
|
|
836
|
+
},
|
|
837
|
+
schema: "SemantifoldFlutterProject",
|
|
838
|
+
semanticProgram: semanticProgramManifest(prepared),
|
|
839
|
+
target: "flutter",
|
|
840
|
+
toolchain: { android: androidToolchain, flutter: flutterToolchain },
|
|
841
|
+
version: 1
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Describes the complete semantic program inside the application manifest.
|
|
846
|
+
* @param {ReturnType<typeof preflightFlutterApplication>} prepared - Prepared project.
|
|
847
|
+
* @returns {Record<string, unknown>} Semantic program manifest.
|
|
848
|
+
*/
|
|
849
|
+
function semanticProgramManifest(prepared) {
|
|
850
|
+
const sourceContent = new Map(prepared.sources.map(source => [source.filename, source.content]));
|
|
851
|
+
const order = new Map(prepared.program.modules.map((module, index) => [module.id, index]));
|
|
852
|
+
const modules = prepared.program.modules.map(module => {
|
|
853
|
+
const source = prepared.program.sources.find(candidate => candidate.filename == module.sourceFilename);
|
|
854
|
+
const content = sourceContent.get(module.sourceFilename);
|
|
855
|
+
if (!source || content === undefined)
|
|
856
|
+
throw new TypeError(`Preflighted Flutter module '${module.id}' lost source ownership.`);
|
|
857
|
+
return {
|
|
858
|
+
dependencies: [...new Set(module.imports.map(({ moduleId }) => moduleId))]
|
|
859
|
+
.sort((left, right) => /** @type {number} */ (order.get(left)) - /** @type {number} */ (order.get(right))),
|
|
860
|
+
generatedArtifacts: [prepared.modulePaths.get(module.id)],
|
|
861
|
+
id: module.id,
|
|
862
|
+
namespace: `SemantifoldModule${moduleName(module.id)}`,
|
|
863
|
+
source: { filename: source.filename, id: source.id, sha256: createHash("sha256").update(content).digest("hex") }
|
|
864
|
+
};
|
|
865
|
+
});
|
|
866
|
+
const entryId = prepared.program.entryModule;
|
|
867
|
+
return {
|
|
868
|
+
entry: {
|
|
869
|
+
generatedArtifact: prepared.modulePaths.get(entryId),
|
|
870
|
+
generatedFunctionIdentity: `SemantifoldModule${moduleName(entryId)}.semantifoldEntry`,
|
|
871
|
+
moduleId: entryId,
|
|
872
|
+
widgetArtifact: `${projectRoot}/lib/main.dart`
|
|
873
|
+
},
|
|
874
|
+
modules,
|
|
875
|
+
schema: "SemantifoldFlutterSemanticProgram",
|
|
876
|
+
sources: prepared.program.sources.map(source => ({
|
|
877
|
+
filename: source.filename,
|
|
878
|
+
id: source.id,
|
|
879
|
+
language: source.language,
|
|
880
|
+
moduleIds: modules.filter(module => module.source.filename == source.filename).map(({ id }) => id),
|
|
881
|
+
ownership: source.ownership ?? "application",
|
|
882
|
+
sha256: createHash("sha256").update(/** @type {string} */ (sourceContent.get(source.filename))).digest("hex")
|
|
883
|
+
})),
|
|
884
|
+
version: 1
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Normalizes and validates the closed application configuration.
|
|
889
|
+
* @param {unknown} candidate - Candidate configuration.
|
|
890
|
+
* @returns {import("../semantic/types.js").FlutterApplicationConfiguration} Normalized configuration.
|
|
891
|
+
*/
|
|
892
|
+
function normalizeConfiguration(candidate) {
|
|
893
|
+
if (candidate === undefined)
|
|
894
|
+
candidate = {};
|
|
895
|
+
if (!isPlainObject(candidate) || Object.keys(candidate).some(key => !configurationFields.has(key))) {
|
|
896
|
+
invalidConfiguration("Flutter application configuration must be a closed plain object.");
|
|
897
|
+
}
|
|
898
|
+
const configuration = /** @type {import("../semantic/types.js").FlutterApplicationConfigurationInput} */ (candidate);
|
|
899
|
+
const packageName = configuration.packageName ?? "semantifold_generated";
|
|
900
|
+
const organization = configuration.organization ?? "dev.semantifold";
|
|
901
|
+
const applicationId = configuration.applicationId ?? `${organization}.generated`;
|
|
902
|
+
const activityClassName = configuration.activityClassName ?? "MainActivity";
|
|
903
|
+
const displayName = configuration.displayName ?? "Semantifold";
|
|
904
|
+
const minimumSdk = configuration.minimumSdk ?? 23;
|
|
905
|
+
const targetSdk = configuration.targetSdk ?? 35;
|
|
906
|
+
const compileSdk = configuration.compileSdk ?? 35;
|
|
907
|
+
const buildToolsVersion = configuration.buildToolsVersion ?? "35.0.0";
|
|
908
|
+
const versionCode = configuration.versionCode ?? 1;
|
|
909
|
+
const versionName = configuration.versionName ?? "1.0.0";
|
|
910
|
+
if (typeof packageName != "string" || !/^[a-z][a-z0-9_]*$/u.test(packageName) || dartKeywords.has(packageName) ||
|
|
911
|
+
forbiddenPackageNames.has(packageName))
|
|
912
|
+
invalidConfiguration("Dart package name must be a non-reserved lowercase underscore identifier.");
|
|
913
|
+
if (typeof organization != "string" || !isReverseDns(organization, 2)) {
|
|
914
|
+
invalidConfiguration("Organization must be a lowercase reverse-DNS identity with at least two segments.");
|
|
915
|
+
}
|
|
916
|
+
if (typeof applicationId != "string" || !isReverseDns(applicationId, 3) || !applicationId.startsWith(`${organization}.`)) {
|
|
917
|
+
invalidConfiguration("Application ID must extend the exact organization as lowercase reverse DNS.");
|
|
918
|
+
}
|
|
919
|
+
if (typeof activityClassName != "string" || !/^[A-Z][A-Za-z0-9]*$/u.test(activityClassName) ||
|
|
920
|
+
javaKeywords.has(activityClassName))
|
|
921
|
+
invalidConfiguration("Activity class name must be an ASCII upper-camel Java identifier.");
|
|
922
|
+
if (androidRunnerBaseClassNames.has(activityClassName)) {
|
|
923
|
+
invalidConfiguration("Activity class name must not collide with the imported Flutter launcher base class.");
|
|
924
|
+
}
|
|
925
|
+
if (typeof displayName != "string" || displayName.length == 0 || displayName.trim() != displayName ||
|
|
926
|
+
[...displayName].length > 64 || !hasOnlyUnicodeScalars(displayName) || /[\p{Cc}\p{Zl}\p{Zp}\uFFFE\uFFFF]/u.test(displayName)) {
|
|
927
|
+
invalidConfiguration("Display name must be a non-empty single-line Unicode scalar string of at most 64 characters.");
|
|
928
|
+
}
|
|
929
|
+
if (minimumSdk !== 23 || targetSdk !== 35 || compileSdk !== 35) {
|
|
930
|
+
invalidConfiguration("SDK levels must reuse the qualified minimum 23, target 35, and compile 35 Android matrix.");
|
|
931
|
+
}
|
|
932
|
+
if (buildToolsVersion != "35.0.0")
|
|
933
|
+
invalidConfiguration("Build Tools version must be exactly '35.0.0'.");
|
|
934
|
+
if (!Number.isSafeInteger(versionCode) || versionCode < 1 || versionCode > 2_100_000_000) {
|
|
935
|
+
invalidConfiguration("Version code must be a positive Android-safe integer.");
|
|
936
|
+
}
|
|
937
|
+
if (typeof versionName != "string" || !semanticVersionPattern.test(versionName) || versionName.includes("+")) {
|
|
938
|
+
invalidConfiguration("Version name must be a canonical semantic version without build metadata.");
|
|
939
|
+
}
|
|
940
|
+
if (configuration.permissions !== undefined &&
|
|
941
|
+
(!isDenseArray(configuration.permissions) || configuration.permissions.length != 0)) {
|
|
942
|
+
invalidConfiguration("The baseline Flutter permission set must be empty.");
|
|
943
|
+
}
|
|
944
|
+
return { activityClassName, applicationId, buildToolsVersion, compileSdk, displayName, minimumSdk, organization,
|
|
945
|
+
packageName, targetSdk, versionCode, versionName };
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* Snapshots and validates exact caller assets.
|
|
949
|
+
* @param {unknown} candidate - Candidate asset collection.
|
|
950
|
+
* @returns {FlutterAsset[]} Normalized assets.
|
|
951
|
+
*/
|
|
952
|
+
function normalizeAssets(candidate) {
|
|
953
|
+
if (candidate === undefined)
|
|
954
|
+
return [];
|
|
955
|
+
if (!isDenseArray(candidate))
|
|
956
|
+
invalidAsset("Flutter assets must be a dense array.");
|
|
957
|
+
/** @type {FlutterAsset[]} */
|
|
958
|
+
const assets = [];
|
|
959
|
+
for (let index = 0; index < candidate.length; index += 1) {
|
|
960
|
+
const item = candidate[index];
|
|
961
|
+
if (!isPlainObject(item) || Object.keys(item).length != assetFields.size ||
|
|
962
|
+
Object.keys(item).some(key => !assetFields.has(key)))
|
|
963
|
+
invalidAsset(`Asset ${index} must use the closed input schema.`);
|
|
964
|
+
const path = item.path;
|
|
965
|
+
const content = item.content;
|
|
966
|
+
const mediaType = item.mediaType;
|
|
967
|
+
const sha256 = item.sha256;
|
|
968
|
+
if (!isSafeArtifactPath(path) || !String(path).startsWith("assets/")) {
|
|
969
|
+
invalidAsset(`Asset ${index} requires a safe portable path below 'assets'.`);
|
|
970
|
+
}
|
|
971
|
+
if (typeof content != "string" && !(content instanceof Uint8Array) || typeof content == "string" &&
|
|
972
|
+
(content.length == 0 || !hasOnlyUnicodeScalars(content)) || content instanceof Uint8Array && content.byteLength == 0) {
|
|
973
|
+
invalidAsset(`Asset '${path}' requires non-empty exact content.`);
|
|
974
|
+
}
|
|
975
|
+
if (typeof mediaType != "string" || !mediaTypePattern.test(mediaType) || /[\r\n]/u.test(mediaType)) {
|
|
976
|
+
invalidAsset(`Asset '${path}' requires an explicit valid media type.`);
|
|
977
|
+
}
|
|
978
|
+
const snapshot = typeof content == "string" ? content : new Uint8Array(content);
|
|
979
|
+
const actualHash = createHash("sha256").update(snapshot).digest("hex");
|
|
980
|
+
if (typeof sha256 != "string" || !/^[0-9a-f]{64}$/u.test(sha256) || sha256 != actualHash) {
|
|
981
|
+
invalidAsset(`Asset '${path}' SHA-256 does not match its exact content.`);
|
|
982
|
+
}
|
|
983
|
+
assets.push({ content: snapshot, contentKind: typeof snapshot == "string" ? "text" : "binary",
|
|
984
|
+
fullPath: `${projectRoot}/${path}`, mediaType, path, sha256 });
|
|
985
|
+
}
|
|
986
|
+
assets.sort((left, right) => left.fullPath < right.fullPath ? -1 : left.fullPath > right.fullPath ? 1 : 0);
|
|
987
|
+
const conflict = findPortableArtifactPathConflict(assets.map(({ fullPath }) => fullPath));
|
|
988
|
+
if (conflict)
|
|
989
|
+
invalidAsset(`Asset path '${conflict.path}' has a ${conflict.kind} conflict.`);
|
|
990
|
+
return assets;
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Enumerates every generator-owned application path.
|
|
994
|
+
* @param {import("../semantic/types.js").FlutterApplicationConfiguration} configuration - Normalized configuration.
|
|
995
|
+
* @param {Map<string, string>} modulePaths - Semantic module paths.
|
|
996
|
+
* @returns {string[]} Complete paths.
|
|
997
|
+
*/
|
|
998
|
+
function applicationPaths(configuration, modulePaths) {
|
|
999
|
+
const packagePath = configuration.applicationId.replaceAll(".", "/");
|
|
1000
|
+
return [
|
|
1001
|
+
`${projectRoot}/.metadata`,
|
|
1002
|
+
`${projectRoot}/analysis_options.yaml`,
|
|
1003
|
+
`${projectRoot}/android/app/build.gradle.kts`,
|
|
1004
|
+
`${projectRoot}/android/app/src/main/AndroidManifest.xml`,
|
|
1005
|
+
`${projectRoot}/android/app/src/main/java/${packagePath}/${configuration.activityClassName}.java`,
|
|
1006
|
+
`${projectRoot}/android/app/src/main/res/drawable/launch_background.xml`,
|
|
1007
|
+
`${projectRoot}/android/app/src/main/res/values-night/styles.xml`,
|
|
1008
|
+
`${projectRoot}/android/app/src/main/res/values/styles.xml`,
|
|
1009
|
+
`${projectRoot}/android/app/src/main/res/xml/backup_rules.xml`,
|
|
1010
|
+
`${projectRoot}/android/app/src/main/res/xml/data_extraction_rules.xml`,
|
|
1011
|
+
`${projectRoot}/android/build.gradle.kts`,
|
|
1012
|
+
`${projectRoot}/android/gradle.properties`,
|
|
1013
|
+
`${projectRoot}/android/settings.gradle.kts`,
|
|
1014
|
+
`${projectRoot}/lib/main.dart`,
|
|
1015
|
+
...modulePaths.values(),
|
|
1016
|
+
`${projectRoot}/lib/src/semantic/semantifold.dart`,
|
|
1017
|
+
`${projectRoot}/pubspec.lock`,
|
|
1018
|
+
`${projectRoot}/pubspec.yaml`,
|
|
1019
|
+
`${projectRoot}/test/semantic_logic_test.dart`,
|
|
1020
|
+
`${projectRoot}/test/widget_test.dart`,
|
|
1021
|
+
`${projectRoot}/semantifold-project.json`
|
|
1022
|
+
];
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Converts one normalized asset to an owned artifact.
|
|
1026
|
+
* @param {FlutterAsset} asset - Normalized asset.
|
|
1027
|
+
* @returns {import("../semantic/types.js").GeneratedSetArtifact} Generated asset.
|
|
1028
|
+
*/
|
|
1029
|
+
function assetArtifact(asset) {
|
|
1030
|
+
const reason = `Exact caller-provided Flutter asset (sha256:${asset.sha256}).`;
|
|
1031
|
+
if (typeof asset.content == "string")
|
|
1032
|
+
return { ...syntheticText(asset.fullPath, "resource", asset.content, reason), mediaType: asset.mediaType };
|
|
1033
|
+
const content = new Uint8Array(asset.content);
|
|
1034
|
+
return {
|
|
1035
|
+
content,
|
|
1036
|
+
contentKind: "binary",
|
|
1037
|
+
mediaType: asset.mediaType,
|
|
1038
|
+
ownership: "generated",
|
|
1039
|
+
path: asset.fullPath,
|
|
1040
|
+
provenance: { kind: "bytes", mapping: createByteMapping({
|
|
1041
|
+
byteLength: content.byteLength,
|
|
1042
|
+
path: asset.fullPath,
|
|
1043
|
+
ranges: [{ generated: { end: content.byteLength, start: 0 },
|
|
1044
|
+
origin: { kind: "synthetic", reason, relatedOrigins: [] }, role: "asset" }]
|
|
1045
|
+
}) },
|
|
1046
|
+
role: "resource"
|
|
1047
|
+
};
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Creates a synthetic text artifact.
|
|
1051
|
+
* @param {string} path - Artifact path.
|
|
1052
|
+
* @param {import("../semantic/types.js").GeneratedArtifactRole} role - Artifact role.
|
|
1053
|
+
* @param {string} content - Exact content.
|
|
1054
|
+
* @param {string} reason - Synthetic provenance reason.
|
|
1055
|
+
* @returns {import("../semantic/types.js").GeneratedSetArtifact} Generated artifact.
|
|
1056
|
+
*/
|
|
1057
|
+
function syntheticText(path, role, content, reason) {
|
|
1058
|
+
return { content, contentKind: "text", mediaType: mediaTypeFor(path), ownership: "generated", path,
|
|
1059
|
+
provenance: { kind: "synthetic", reason, relatedOrigins: [] }, role };
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Creates text whose configuration spans are recorded separately.
|
|
1063
|
+
* @param {string} path - Artifact path.
|
|
1064
|
+
* @param {import("../semantic/types.js").GeneratedArtifactRole} role - Artifact role.
|
|
1065
|
+
* @param {string} content - Exact content.
|
|
1066
|
+
* @param {string} reason - Synthetic provenance reason.
|
|
1067
|
+
* @returns {import("../semantic/types.js").GeneratedSetArtifact} Generated artifact.
|
|
1068
|
+
*/
|
|
1069
|
+
function configuredText(path, role, content, reason) {
|
|
1070
|
+
return syntheticText(path, role, content, reason);
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Selects an exact media type from an owned path.
|
|
1074
|
+
* @param {string} path - Artifact path.
|
|
1075
|
+
* @returns {string} Media type.
|
|
1076
|
+
*/
|
|
1077
|
+
function mediaTypeFor(path) {
|
|
1078
|
+
if (path.endsWith(".dart"))
|
|
1079
|
+
return "text/x-dart";
|
|
1080
|
+
if (path.endsWith(".json"))
|
|
1081
|
+
return "application/json";
|
|
1082
|
+
if (path.endsWith(".yaml") || path.endsWith(".lock"))
|
|
1083
|
+
return "application/yaml";
|
|
1084
|
+
if (path.endsWith(".xml"))
|
|
1085
|
+
return "application/xml";
|
|
1086
|
+
if (path.endsWith(".java"))
|
|
1087
|
+
return "text/x-java-source";
|
|
1088
|
+
if (path.endsWith(".kts"))
|
|
1089
|
+
return "text/x-kotlin";
|
|
1090
|
+
return "text/plain";
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Marks one rendered value as configuration-derived.
|
|
1094
|
+
* @param {string} fieldName - Configuration field.
|
|
1095
|
+
* @param {string} value - Rendered value.
|
|
1096
|
+
* @returns {{field: string, value: string}} Marked value.
|
|
1097
|
+
*/
|
|
1098
|
+
function field(fieldName, value) {
|
|
1099
|
+
return { field: fieldName, value };
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Joins configured parts while recording exact output spans.
|
|
1103
|
+
* @param {string} path - Artifact path.
|
|
1104
|
+
* @param {ConfigurationSpan[]} spans - Configuration provenance sink.
|
|
1105
|
+
* @param {(string | {field: string, value: string})[]} parts - Literal and configured parts.
|
|
1106
|
+
* @returns {string} Rendered content.
|
|
1107
|
+
*/
|
|
1108
|
+
function configured(path, spans, parts) {
|
|
1109
|
+
let content = "";
|
|
1110
|
+
for (const part of parts) {
|
|
1111
|
+
if (typeof part == "string")
|
|
1112
|
+
content += part;
|
|
1113
|
+
else {
|
|
1114
|
+
const start = content.length;
|
|
1115
|
+
content += part.value;
|
|
1116
|
+
spans.push({ end: content.length, field: part.field, path, start });
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
return content;
|
|
1120
|
+
}
|
|
1121
|
+
/**
|
|
1122
|
+
* Groups exact generated ranges for one configuration field.
|
|
1123
|
+
* @param {ConfigurationSpan[]} spans - Recorded spans.
|
|
1124
|
+
* @param {string} fieldName - Configuration field.
|
|
1125
|
+
* @returns {{path: string, ranges: {end: number, start: number}[]}[]} Grouped output ranges.
|
|
1126
|
+
*/
|
|
1127
|
+
function configurationOutputs(spans, fieldName) {
|
|
1128
|
+
const grouped = new Map();
|
|
1129
|
+
for (const span of spans) {
|
|
1130
|
+
if (span.field != fieldName)
|
|
1131
|
+
continue;
|
|
1132
|
+
const ranges = grouped.get(span.path) ?? [];
|
|
1133
|
+
ranges.push({ end: span.end, start: span.start });
|
|
1134
|
+
grouped.set(span.path, ranges);
|
|
1135
|
+
}
|
|
1136
|
+
return [...grouped].map(([path, ranges]) => ({ path, ranges }));
|
|
1137
|
+
}
|
|
1138
|
+
/**
|
|
1139
|
+
* Checks whether provenance refers to one source file.
|
|
1140
|
+
* @param {import("../semantic/types.js").SemanticOrigin} origin - Semantic origin.
|
|
1141
|
+
* @param {string} filename - Source filename.
|
|
1142
|
+
* @returns {boolean} Whether the origin references the source.
|
|
1143
|
+
*/
|
|
1144
|
+
function originReferencesFilename(origin, filename) {
|
|
1145
|
+
if (origin.kind == "source")
|
|
1146
|
+
return origin.location.filename == filename;
|
|
1147
|
+
if (origin.kind == "derived")
|
|
1148
|
+
return origin.origins.some(({ location }) => location.filename == filename);
|
|
1149
|
+
return origin.relatedOrigins.some(({ location }) => location.filename == filename);
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Hashes exact artifact content.
|
|
1153
|
+
* @param {string | Uint8Array} content - Artifact content.
|
|
1154
|
+
* @returns {string} Lowercase SHA-256.
|
|
1155
|
+
*/
|
|
1156
|
+
function hashContent(content) {
|
|
1157
|
+
return createHash("sha256").update(content).digest("hex");
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Serializes a recursively sorted JSON value.
|
|
1161
|
+
* @param {unknown} value - JSON-compatible value.
|
|
1162
|
+
* @returns {string} Canonical indented JSON.
|
|
1163
|
+
*/
|
|
1164
|
+
function stringifyCanonicalJson(value) {
|
|
1165
|
+
return `${JSON.stringify(sortJson(value), null, 2)}\n`;
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
* Recursively sorts object keys without reordering arrays.
|
|
1169
|
+
* @param {unknown} value - JSON-compatible value.
|
|
1170
|
+
* @returns {unknown} Sorted value.
|
|
1171
|
+
*/
|
|
1172
|
+
function sortJson(value) {
|
|
1173
|
+
if (Array.isArray(value))
|
|
1174
|
+
return value.map(sortJson);
|
|
1175
|
+
if (!isPlainObject(value))
|
|
1176
|
+
return value;
|
|
1177
|
+
return Object.fromEntries(Object.keys(value).sort().map(key => [key, sortJson(value[key])]));
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Validates a lowercase reverse-DNS identity.
|
|
1181
|
+
* @param {string} value - Candidate identity.
|
|
1182
|
+
* @param {number} segments - Required minimum segment count.
|
|
1183
|
+
* @returns {boolean} Whether the identity is valid.
|
|
1184
|
+
*/
|
|
1185
|
+
function isReverseDns(value, segments) {
|
|
1186
|
+
const parts = value.split(".");
|
|
1187
|
+
return parts.length >= segments && parts.every(part => /^[a-z][a-z0-9_]*$/u.test(part) && !javaKeywords.has(part));
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Derives one stable Dart class suffix.
|
|
1191
|
+
* @param {string} id - Semantic module identity.
|
|
1192
|
+
* @returns {string} Dart class suffix.
|
|
1193
|
+
*/
|
|
1194
|
+
function moduleName(id) {
|
|
1195
|
+
return id.split(/[._-]+/u).map(part => `${part[0].toUpperCase()}${part.slice(1)}`).join("");
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Derives one stable semantic part filename.
|
|
1199
|
+
* @param {string} id - Semantic module identity.
|
|
1200
|
+
* @returns {string} Dart filename.
|
|
1201
|
+
*/
|
|
1202
|
+
function moduleFileName(id) {
|
|
1203
|
+
return id.replaceAll(/[.-]/gu, "_");
|
|
1204
|
+
}
|
|
1205
|
+
/**
|
|
1206
|
+
* Allocates a collision-free private output sink binding.
|
|
1207
|
+
* @param {import("../semantic/types.js").SemanticModule} module - Semantic module.
|
|
1208
|
+
* @returns {string} Dart binding name.
|
|
1209
|
+
*/
|
|
1210
|
+
function outputSinkName(module) {
|
|
1211
|
+
const bindings = new Set(module.functions.flatMap(declaration => declaration.parameters.map(({ name }) => name)));
|
|
1212
|
+
for (const declaration of module.functions)
|
|
1213
|
+
collectBlockBindingNames(declaration.body, bindings);
|
|
1214
|
+
collectBlockBindingNames(module.entryPoint.body, bindings);
|
|
1215
|
+
let candidate = "semantifoldOutput";
|
|
1216
|
+
while (bindings.has(candidate))
|
|
1217
|
+
candidate += "_";
|
|
1218
|
+
return candidate;
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Collects every block-owned binding name.
|
|
1222
|
+
* @param {import("../semantic/types.js").Block} block - Semantic block.
|
|
1223
|
+
* @param {Set<string>} bindings - Mutable name set.
|
|
1224
|
+
* @returns {void}
|
|
1225
|
+
*/
|
|
1226
|
+
function collectBlockBindingNames(block, bindings) {
|
|
1227
|
+
for (const statement of block.statements) {
|
|
1228
|
+
if (statement.kind == "LocalDeclaration")
|
|
1229
|
+
bindings.add(statement.name);
|
|
1230
|
+
else if (statement.kind == "IfStatement") {
|
|
1231
|
+
collectBlockBindingNames(statement.consequent, bindings);
|
|
1232
|
+
if (statement.alternate)
|
|
1233
|
+
collectBlockBindingNames(statement.alternate, bindings);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
/**
|
|
1238
|
+
* Wraps one module in an explicit semantic project.
|
|
1239
|
+
* @param {import("../semantic/types.js").SemanticModule | undefined} candidate - Candidate module.
|
|
1240
|
+
* @returns {import("../semantic/types.js").SemanticProgram} Normalized project.
|
|
1241
|
+
*/
|
|
1242
|
+
function normalizeSingleModule(candidate) {
|
|
1243
|
+
if (!isPlainObject(candidate))
|
|
1244
|
+
unsupportedCapability("flutter", "missing or invalid module", undefined);
|
|
1245
|
+
const module = structuredClone(candidate);
|
|
1246
|
+
const sources = module.provenance?.sources;
|
|
1247
|
+
if (!Array.isArray(sources) || sources.length != 1 || sources[0].content === null ||
|
|
1248
|
+
sources[0].filename != module.location?.filename || typeof sources[0].language != "string") {
|
|
1249
|
+
unsupportedCapability("flutter", "single-module source ownership", module.location);
|
|
1250
|
+
}
|
|
1251
|
+
rekeyModuleDeclarations(module, "main");
|
|
1252
|
+
const exports = [
|
|
1253
|
+
...(module.records ?? []).map(declaration => applicationExport(declaration, "record")),
|
|
1254
|
+
...(module.classes ?? []).map(declaration => applicationExport(declaration, "class")),
|
|
1255
|
+
...(module.errors ?? []).map(declaration => applicationExport(declaration, "error")),
|
|
1256
|
+
...module.functions.map(declaration => applicationExport(declaration, "function"))
|
|
1257
|
+
];
|
|
1258
|
+
const programModule = { ...module, exports, id: "main", imports: [], sourceFilename: sources[0].filename };
|
|
1259
|
+
return { entryModule: "main", kind: "Program", modules: [programModule], sources: structuredClone(sources) };
|
|
1260
|
+
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Converts one module declaration to an explicit application export.
|
|
1263
|
+
* @param {{id?: string, location: import("../semantic/types.js").SourceLocation, name: string}} declaration - Declaration.
|
|
1264
|
+
* @param {import("../semantic/types.js").SemanticDeclarationKind} symbolKind - Declaration kind.
|
|
1265
|
+
* @returns {import("../semantic/types.js").SemanticExport} Semantic export.
|
|
1266
|
+
*/
|
|
1267
|
+
function applicationExport(declaration, symbolKind) {
|
|
1268
|
+
return { declarationId: /** @type {string} */ (declaration.id), exportedName: declaration.name,
|
|
1269
|
+
kind: "Export", location: declaration.location, symbolKind };
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Re-keys one standalone module for application-project ownership.
|
|
1273
|
+
* @param {import("../semantic/types.js").SemanticModule} module - Standalone module.
|
|
1274
|
+
* @param {string} moduleId - Stable application module identity.
|
|
1275
|
+
* @returns {void}
|
|
1276
|
+
*/
|
|
1277
|
+
function rekeyModuleDeclarations(module, moduleId) {
|
|
1278
|
+
const declarations = [...module.records ?? [], ...module.classes ?? [], ...module.errors ?? [], ...module.functions];
|
|
1279
|
+
const replacements = new Map(declarations.filter(declaration => typeof declaration.id == "string")
|
|
1280
|
+
.map(declaration => [declaration.id, `${moduleId}#${declaration.id}`]));
|
|
1281
|
+
for (const declaration of declarations)
|
|
1282
|
+
if (typeof declaration.id == "string")
|
|
1283
|
+
declaration.id = replacements.get(declaration.id);
|
|
1284
|
+
const seen = new Set();
|
|
1285
|
+
const identityFields = new Set(["classId", "declarationId", "field", "method", "parameterId"]);
|
|
1286
|
+
/**
|
|
1287
|
+
* Rewrites semantic declaration identities recursively.
|
|
1288
|
+
* @param {unknown} value - Candidate semantic value.
|
|
1289
|
+
* @returns {void}
|
|
1290
|
+
*/
|
|
1291
|
+
const visit = value => {
|
|
1292
|
+
if (!value || typeof value != "object" || seen.has(value))
|
|
1293
|
+
return;
|
|
1294
|
+
seen.add(value);
|
|
1295
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
1296
|
+
if (!Array.isArray(value) && identityFields.has(key) && typeof nested == "string" && replacements.has(nested)) {
|
|
1297
|
+
Reflect.set(value, key, replacements.get(nested));
|
|
1298
|
+
}
|
|
1299
|
+
else
|
|
1300
|
+
visit(nested);
|
|
1301
|
+
}
|
|
1302
|
+
};
|
|
1303
|
+
visit(module);
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* Escapes an XML attribute value.
|
|
1307
|
+
* @param {string} value - Raw value.
|
|
1308
|
+
* @returns {string} Escaped value.
|
|
1309
|
+
*/
|
|
1310
|
+
function xmlEscape(value) {
|
|
1311
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">")
|
|
1312
|
+
.replaceAll('"', """).replaceAll("'", "'");
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Escapes a single-quoted Dart literal body.
|
|
1316
|
+
* @param {string} value - Raw value.
|
|
1317
|
+
* @returns {string} Escaped value.
|
|
1318
|
+
*/
|
|
1319
|
+
function dartEscape(value) {
|
|
1320
|
+
return value.replaceAll("\\", "\\\\").replaceAll("'", "\\'").replaceAll("$", "\\$");
|
|
1321
|
+
}
|
|
1322
|
+
/**
|
|
1323
|
+
* Checks for a plain string-keyed object.
|
|
1324
|
+
* @param {unknown} value - Candidate value.
|
|
1325
|
+
* @returns {value is Record<string, unknown>} Whether the value is plain.
|
|
1326
|
+
*/
|
|
1327
|
+
function isPlainObject(value) {
|
|
1328
|
+
return Boolean(value) && typeof value == "object" && !Array.isArray(value) && Object.getPrototypeOf(value) == Object.prototype;
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* Throws a stable invalid-input diagnostic.
|
|
1332
|
+
* @param {string} message - Diagnostic detail.
|
|
1333
|
+
* @returns {never} Never returns.
|
|
1334
|
+
*/
|
|
1335
|
+
function invalidInput(message) {
|
|
1336
|
+
throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_INPUT", language: "flutter", message });
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Throws a stable invalid-configuration diagnostic.
|
|
1340
|
+
* @param {string} message - Diagnostic detail.
|
|
1341
|
+
* @returns {never} Never returns.
|
|
1342
|
+
*/
|
|
1343
|
+
function invalidConfiguration(message) {
|
|
1344
|
+
throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_CONFIGURATION", language: "flutter", message });
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* Throws a stable invalid-asset diagnostic.
|
|
1348
|
+
* @param {string} message - Diagnostic detail.
|
|
1349
|
+
* @returns {never} Never returns.
|
|
1350
|
+
*/
|
|
1351
|
+
function invalidAsset(message) {
|
|
1352
|
+
throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_ASSET", language: "flutter", message });
|
|
1353
|
+
}
|
|
1354
|
+
/**
|
|
1355
|
+
* Throws a stable invalid-path diagnostic.
|
|
1356
|
+
* @param {string} message - Diagnostic detail.
|
|
1357
|
+
* @returns {never} Never returns.
|
|
1358
|
+
*/
|
|
1359
|
+
function invalidPath(message) {
|
|
1360
|
+
throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_PATH", language: "flutter", message });
|
|
1361
|
+
}
|
|
1362
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmx1dHRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZW5kcy9mbHV0dGVyLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sYUFBYSxDQUFBO0FBQ3RDLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxhQUFhLENBQUE7QUFDeEMsT0FBTyxFQUFDLGdDQUFnQyxFQUFFLGtCQUFrQixFQUFDLE1BQU0scUJBQXFCLENBQUE7QUFDeEYsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0sc0JBQXNCLENBQUE7QUFDdEQsT0FBTyxFQUFDLHFCQUFxQixFQUFFLHFCQUFxQixFQUFDLE1BQU0sa0JBQWtCLENBQUE7QUFDN0UsT0FBTyxFQUFDLGVBQWUsRUFBRSxhQUFhLEVBQUMsTUFBTSxlQUFlLENBQUE7QUFDNUQsT0FBTyxFQUFDLHFCQUFxQixFQUFDLE1BQU0sd0JBQXdCLENBQUE7QUFDNUQsT0FBTyxFQUFDLFdBQVcsRUFBQyxNQUFNLG1CQUFtQixDQUFBO0FBQzdDLE9BQU8sRUFBQyxhQUFhLEVBQUUsb0JBQW9CLEVBQUMsTUFBTSxXQUFXLENBQUE7QUFDN0QsT0FBTyxFQUFDLHdCQUF3QixFQUFDLE1BQU0sY0FBYyxDQUFBO0FBQ3JELE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSxjQUFjLENBQUE7QUFDM0MsT0FBTyxFQUFDLFlBQVksRUFBQyxNQUFNLGFBQWEsQ0FBQTtBQUV4QyxNQUFNLFdBQVcsR0FBRyx1QkFBdUIsQ0FBQTtBQUMzQyxNQUFNLGdCQUFnQixHQUFHLE9BQU8sQ0FBQTtBQUNoQyxNQUFNLGdCQUFnQixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDckMsT0FBTyxFQUFFLG9DQUFvQztJQUM3QyxhQUFhLEVBQUUsa0VBQWtFO0lBQ2pGLElBQUksRUFBRSxRQUFRO0lBQ2QsUUFBUSxFQUFFLDBDQUEwQztJQUNwRCxPQUFPLEVBQUUs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QUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxZQUFZLENBQUMsT0FBTztJQUMzQixNQUFNLElBQUkscUJBQXFCLENBQUMsRUFBQyxJQUFJLEVBQUUsMkJBQTJCLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUMsQ0FBQyxDQUFBO0FBQ3BHLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxvQkFBb0IsQ0FBQyxPQUFPO0lBQ25DLE1BQU0sSUFBSSxxQkFBcUIsQ0FBQyxFQUFDLElBQUksRUFBRSxtQ0FBbUMsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBQyxDQUFDLENBQUE7QUFDNUcsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxPQUFPO0lBQzNCLE1BQU0sSUFBSSxxQkFBcUIsQ0FBQyxFQUFDLElBQUksRUFBRSwyQkFBMkIsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBQyxDQUFDLENBQUE7QUFDcEcsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFTLFdBQVcsQ0FBQyxPQUFPO0lBQzFCLE1BQU0sSUFBSSxxQkFBcUIsQ0FBQyxFQUFDLElBQUksRUFBRSwwQkFBMEIsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBQyxDQUFDLENBQUE7QUFDbkcsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQge2NyZWF0ZUhhc2h9IGZyb20gXCJub2RlOmNyeXB0b1wiXG5pbXBvcnQge2lzRGVuc2VBcnJheX0gZnJvbSBcIi4uL2FycmF5LmpzXCJcbmltcG9ydCB7ZmluZFBvcnRhYmxlQXJ0aWZhY3RQYXRoQ29uZmxpY3QsIGlzU2FmZUFydGlmYWN0UGF0aH0gZnJvbSBcIi4uL2FydGlmYWN0LXBhdGguanNcIlxuaW1wb3J0IHtjcmVhdGVCeXRlTWFwcGluZ30gZnJvbSBcIi4uL2JpbmFyeS1tYXBwaW5nLmpzXCJcbmltcG9ydCB7U2VtYW50aWZvbGREaWFnbm9zdGljLCB1bnN1cHBvcnRlZENhcGFiaWxpdHl9IGZyb20gXCIuLi9kaWFnbm9zdGljLmpzXCJcbmltcG9ydCB7ZmluYWxpemVNYXBwaW5nLCB0b1NvdXJjZU1hcFYzfSBmcm9tIFwiLi4vbWFwcGluZy5qc1wiXG5pbXBvcnQge2hhc09ubHlVbmljb2RlU2NhbGFyc30gZnJvbSBcIi4uL3NlbWFudGljL3NjYWxhcnMuanNcIlxuaW1wb3J0IHtkYXJ0UnVudGltZX0gZnJvbSBcIi4vZGFydC1ydW50aW1lLmpzXCJcbmltcG9ydCB7ZW1pdERhcnRCbG9jaywgZmluZFVucmVhZERhcnRMb2NhbHN9IGZyb20gXCIuL2RhcnQuanNcIlxuaW1wb3J0IHtwcmVmbGlnaHRTZW1hbnRpY1Byb2dyYW19IGZyb20gXCIuL3Byb2dyYW0uanNcIlxuaW1wb3J0IHtlbWl0U2NhbGFyVHlwZX0gZnJvbSBcIi4vc2NhbGFycy5qc1wiXG5pbXBvcnQge1NvdXJjZVdyaXRlcn0gZnJvbSBcIi4vd3JpdGVyLmpzXCJcblxuY29uc3QgcHJvamVjdFJvb3QgPSBcImdlbmVyYXRlZC9mbHV0dGVyLWFwcFwiXG5jb25zdCBnZW5lcmF0b3JWZXJzaW9uID0gXCIwLjYuMFwiXG5jb25zdCBmbHV0dGVyVG9vbGNoYWluID0gT2JqZWN0LmZyZWV6ZSh7XG4gIGFyY2hpdmU6IFwiZmx1dHRlcl9saW51eF8zLjQ3LjQtc3RhYmxlLnRhci54elwiLFxuICBhcmNoaXZlU2hhMjU2OiBcIjViNDVmMGNlZGE5OWI5YmViZGM4NzNlN2U2OWY2NDUwYWViNGMzMGY0NTRiNTA1ZTJlNjJmYzkyNTVhOTA3ZDNcIixcbiAgZGFydDogXCIzLjEzLjNcIixcbiAgcmV2aXNpb246IFwiOTU4NGM2NzEzYjMyNDYzNjI4OWQwNjc5NDRhNDZmZDZiNDlkZjE0YlwiLFxuICB2ZXJzaW9uOiBcIjMuNDcuNFwiXG59KVxuY29uc3QgYW5kcm9pZFRvb2xjaGFpbiA9IE9iamVjdC5mcmVlemUoe1xuICBhbmRyb2lkR3JhZGxlUGx1Z2luOiBcIjguMTEuMVwiLFxuICBidWlsZFRvb2xzOiBcIjM1LjAuMFwiLFxuICBjbWFrZTogXCIzLjIyLjFcIixcbiAgY29tcGlsZVNkazogMzUsXG4gIGdyYWRsZTogXCI4LjE0XCIsXG4gIGphdmE6IFwiMjEuMC44XCIsXG4gIGtvdGxpbkdyYWRsZVBsdWdpbjogXCIyLjIuMjBcIixcbiAgbWluaW11bVNkazogMjMsXG4gIG5kazogXCIyNy4wLjEyMDc3OTczXCIsXG4gIHRhcmdldFNkazogMzVcbn0pXG4vKiogQHR5cGUge3JlYWRvbmx5IChyZWFkb25seSBbc3RyaW5nLCBzdHJpbmcsIHN0cmluZ10pW119ICovXG5jb25zdCBmbHV0dGVyTG9ja2VkSG9zdGVkUGFja2FnZXMgPSBPYmplY3QuZnJlZXplKFtcbiAgW1wiYXN5bmNcIiwgXCIyLjEzLjFcIiwgXCJlMmViMDQ5MWJhNWRkYjYxNzc3NDJkMmRhMjM5MDQ1NzQwODIxMzliMDdjMWUzM2I4NTAzYjlmNDZmM2UxYTM3XCJdLFxuICBbXCJib29sZWFuX3NlbGVjdG9yXCIsIFwiMi4xLjJcIiwgXCI4YWFiMTc3MWUxMjQzYTUwNjNiOGIwZmY2ODA0MmQ2NzMzNGUzZmVhYjllOTViOTQ5MGY5YTZlYmY3M2I0MmVhXCJdLFxuICBbXCJjaGFyYWN0ZXJzXCIsIFwiMS40LjFcIiwgXCJmYWYzODQ5N2JkYTVlYWQyYThjNzYxNWY0Zjc5MzlkZjA0MzMzNDc4YmYzMmU0MTczZmNiMDZkNDI4YjU3MTZiXCJdLFxuICBbXCJjbG9ja1wiLCBcIjEuMS4zXCIsIFwiZTUxZDUwYmNhMzIxN2M5YTlmYTJiNDFhMzBlNGEzODk3MTEzM2Y1ZjllYzdhM2Q1N2JhZTA5NTAwN2YxZDI4ZVwiXSxcbiAgW1wiY29sbGVjdGlvblwiLCBcIjEuMTkuMVwiLCBcIjJmNTcwOWFlNGQzZDU5ZGQ4ZjdjZDMwOWI0ZTAyMzA0NmI1N2Q4YTZjODIxMzA3ODVkMmIwZTU4NjgwODRlNzZcIl0sXG4gIFtcImZha2VfYXN5bmNcIiwgXCIxLjMuM1wiLCBcIjUzNjhmMjI0YTc0NTIzZThkMmU3Mzk5ZWExNjM4YjM3YWVjZmNhODI0YTNjYzRkZmRmNzdiZjFmYTkwNWFjNDRcIl0sXG4gIFtcImxlYWtfdHJhY2tlclwiLCBcIjExLjAuMlwiLCBcIjMzZTJlMjZiZGQ4NWEwMTEyZWMxNTQwMGM4Y2JmZmVhNzBkMGY5YzM0MDc0OTFmNjcyYTJmYWQ0NzkxNWUyZGVcIl0sXG4gIFtcImxlYWtfdHJhY2tlcl9mbHV0dGVyX3Rlc3RpbmdcIiwgXCIzLjAuMTBcIiwgXCIxZGJjMTQwYmI1YTIzYzc1ZWE5YzQ4MTEyMjI3NTYxMDRmYmNkMWEyNzE3M2YwYzM0Y2EwMWUxNmJlYTQ3M2MxXCJdLFxuICBbXCJsZWFrX3RyYWNrZXJfdGVzdGluZ1wiLCBcIjMuMC4yXCIsIFwiOGQ1YTJkNDlmNGE2NmI0OTc0NGIyM2IwMTg4NDg0MDBkMjNlNTRjYWY5NDYzZjRlYjIwZGYzZWI4YWNiMmViMVwiXSxcbiAgW1wibWF0Y2hlclwiLCBcIjAuMTIuMjBcIiwgXCIzMWJkMDk5YjQ3YzEwY2QxYWViNTUxNDZhMmQ0NmNlMDI3NzYzMGVjZWYzZjdkYWU1NGFkNzg3M2YzNjY5NmNkXCJdLFxuICBbXCJtYXRlcmlhbF9jb2xvcl91dGlsaXRpZXNcIiwgXCIwLjEzLjBcIiwgXCI5YzMzNzAwN2U4MmIxODg5MTQ5YzgyZWQyNDJlZDFjYjI0YTY2MDQ0ZTMwOTc5YzQ0OTEyMzgxZTliZTRjNDhiXCJdLFxuICBbXCJtZXRhXCIsIFwiMS4xOS4wXCIsIFwiMzA3MjQ5Y2U0ZmYyOWQ1OGExOGU5N2Y2MzQ1ZjUzOTM4MmViOWM5YzI5ZWNkYTYyODkwMGYzMWRlMDQ0M2RkOVwiXSxcbiAgW1wicGF0aFwiLCBcIjEuOS4xXCIsIFwiNzVjY2E2OWQxNDkwOTY1YmU5OGM3M2NlYWVhMTE3ZThhMDRkZDIxMjE3YjM3YjI5MmM5ZGRiZWMwZDk1NWJjNVwiXSxcbiAgW1wic291cmNlX3NwYW5cIiwgXCIxLjEwLjJcIiwgXCI1NmEwMmYxZjRjZDFhMmQ5NjMwM2MwMTQ0YzkzYmQ2ZDkwOWVlYTZiZWU2YmY1YTBlMGI2ODVlZGJkNGM0N2FiXCJdLFxuICBbXCJzdGFja190cmFjZVwiLCBcIjEuMTIuMlwiLCBcIjI3NzY1NGIzMDM0ZDE3YWM2ZjlmMWNiNTU5NWRiMDExYjFkNWQ0MWU4ODA2ODY2ZGIyOGUwYWJhYTEwMWM0OTBcIl0sXG4gIFtcInN0cmVhbV9jaGFubmVsXCIsIFwiMi4xLjRcIiwgXCI5NjllMDRjODBiOGJjZGY4MjZmOGYxNjU3OWM3YjE0ZDc4MDQ1OGJkOTdmNTZkMTA3ZDM5NTBmZGJlZWYwNTlkXCJdLFxuICBbXCJzdHJpbmdfc2Nhbm5lclwiLCBcIjEuNC4xXCIsIFwiOTIxY2QzMTcyNWI3MmZlMTgxOTA2YzZhOTRkOTg3Yzc4ZTNiOThjMmUyMDViMzk3ZWEzOTlkNDA1NDg3MmI0M1wiXSxcbiAgW1widGVybV9nbHlwaFwiLCBcIjEuMi4yXCIsIFwiN2Y1NTQ3OTg2MjVlYTc2OGE3NTE4MzEzZTU4ZjgzODkxYzdmNTAyNGY4OGU0NmU3MTgyYTQ1NTg4NTBhNGI4ZVwiXSxcbiAgW1widGVzdF9hcGlcIiwgXCIwLjcuMTJcIiwgXCIyYTEyMmNiZTA1OWY4YjYxMGQzYTU0MTVmNDJlMjU1YjZjMTdiMWYyMWVlZTFkOTYwZjMxMDgwMjM3ZmI0ZjExXCJdLFxuICBbXCJ2ZWN0b3JfbWF0aFwiLCBcIjIuNC4yXCIsIFwiZjM2ZjlmM2JlNjRjNjE5ODcxNDQ5MmJiNDU1YzExMDU2ZTMzZTJmODVkOWEwYjY3NmE0ODMwMWU0NGZkY2Y0N1wiXSxcbiAgW1widm1fc2VydmljZVwiLCBcIjE1LjMuMFwiLCBcIjVmMzcyMzljNDg1MWVmY2VmOTI5Y2VhNzgyNGU3NmRmN2YyZjA5NzBhZWY4NWQ2NmJiYzQzMGFmYTQwZTcyZjBcIl1cbl0pXG4vKiogQHR5cGUge3JlYWRvbmx5IChyZWFkb25seSBbc3RyaW5nLCBcImRpcmVjdCBtYWluXCIgfCBcImRpcmVjdCBkZXZcIiB8IFwidHJhbnNpdGl2ZVwiXSlbXX0gKi9cbmNvbnN0IGZsdXR0ZXJMb2NrZWRTZGtQYWNrYWdlcyA9IE9iamVjdC5mcmVlemUoW1xuICBbXCJmbHV0dGVyXCIsIFwiZGlyZWN0IG1haW5cIl0sXG4gIFtcImZsdXR0ZXJfdGVzdFwiLCBcImRpcmVjdCBkZXZcIl0sXG4gIFtcInNreV9lbmdpbmVcIiwgXCJ0cmFuc2l0aXZlXCJdXG5dKVxuLyoqIEB0eXBlIHtSZWFkb25seTxTZXQ8aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU2VtYW50aWNMYW5ndWFnZT4+fSAqL1xuY29uc3QgZmx1dHRlclNvdXJjZUxhbmd1YWdlcyA9IG5ldyBTZXQoW1xuICBcInBocFwiLCBcInJ1YnlcIiwgXCJqYXZhc2NyaXB0XCIsIFwidHlwZXNjcmlwdFwiLCBcImphdmFcIiwgXCJrb3RsaW5cIiwgXCJweXRob25cIiwgXCJjc2hhcnBcIiwgXCJnb1wiLCBcImNcIiwgXCJjcHBcIiwgXCJydXN0XCIsIFwic3dpZnRcIiwgXCJkYXJ0XCIsIFwiemlnXCJcbl0pXG5jb25zdCByZXF1ZXN0RmllbGRzID0gbmV3IFNldChbXCJhc3NldHNcIiwgXCJjb25maWd1cmF0aW9uXCIsIFwibGFuZ3VhZ2VcIiwgXCJtb2R1bGVcIiwgXCJwcm9ncmFtXCIsIFwicm9sZVwiXSlcbmNvbnN0IGNvbmZpZ3VyYXRpb25GaWVsZHMgPSBuZXcgU2V0KFtcbiAgXCJhY3Rpdml0eUNsYXNzTmFtZVwiLCBcImFwcGxpY2F0aW9uSWRcIiwgXCJidWlsZFRvb2xzVmVyc2lvblwiLCBcImNvbXBpbGVTZGtcIiwgXCJkaXNwbGF5TmFtZVwiLCBcIm1pbmltdW1TZGtcIiwgXCJvcmdhbml6YXRpb25cIixcbiAgXCJwYWNrYWdlTmFtZVwiLCBcInBlcm1pc3Npb25zXCIsIFwidGFyZ2V0U2RrXCIsIFwidmVyc2lvbkNvZGVcIiwgXCJ2ZXJzaW9uTmFtZVwiXG5dKVxuY29uc3QgYXNzZXRGaWVsZHMgPSBuZXcgU2V0KFtcImNvbnRlbnRcIiwgXCJtZWRpYVR5cGVcIiwgXCJwYXRoXCIsIFwic2hhMjU2XCJdKVxuY29uc3QgZGFydEtleXdvcmRzID0gbmV3IFNldChbXG4gIFwiYWJzdHJhY3RcIiwgXCJhc1wiLCBcImFzc2VydFwiLCBcImFzeW5jXCIsIFwiYXdhaXRcIiwgXCJiYXNlXCIsIFwiYnJlYWtcIiwgXCJjYXNlXCIsIFwiY2F0Y2hcIiwgXCJjbGFzc1wiLCBcImNvbnN0XCIsIFwiY29udGludWVcIixcbiAgXCJjb3ZhcmlhbnRcIiwgXCJkZWZhdWx0XCIsIFwiZGVmZXJyZWRcIiwgXCJkb1wiLCBcImR5bmFtaWNcIiwgXCJlbHNlXCIsIFwiZW51bVwiLCBcImV4cG9ydFwiLCBcImV4dGVuZHNcIiwgXCJleHRlbnNpb25cIiwgXCJleHRlcm5hbFwiLFxuICBcImZhY3RvcnlcIiwgXCJmYWxzZVwiLCBcImZpbmFsXCIsIFwiZmluYWxseVwiLCBcImZvclwiLCBcIkZ1bmN0aW9uXCIsIFwiZ2V0XCIsIFwiaGlkZVwiLCBcImlmXCIsIFwiaW1wbGVtZW50c1wiLCBcImltcG9ydFwiLCBcImluXCIsXG4gIFwiaW50ZXJmYWNlXCIsIFwiaXNcIiwgXCJsYXRlXCIsIFwibGlicmFyeVwiLCBcIm1peGluXCIsIFwibmV3XCIsIFwibnVsbFwiLCBcIm9mXCIsIFwib25cIiwgXCJvcGVyYXRvclwiLCBcInBhcnRcIiwgXCJyZXF1aXJlZFwiLFxuICBcInJldGhyb3dcIiwgXCJyZXR1cm5cIiwgXCJzZWFsZWRcIiwgXCJzZXRcIiwgXCJzaG93XCIsIFwic3RhdGljXCIsIFwic3VwZXJcIiwgXCJzd2l0Y2hcIiwgXCJzeW5jXCIsIFwidGhpc1wiLCBcInRocm93XCIsIFwidHJ1ZVwiLFxuICBcInRyeVwiLCBcInR5cGVkZWZcIiwgXCJ2YXJcIiwgXCJ2b2lkXCIsIFwid2hlblwiLCBcIndoaWxlXCIsIFwid2l0aFwiLCBcInlpZWxkXCJcbl0pXG5jb25zdCBqYXZhS2V5d29yZHMgPSBuZXcgU2V0KFtcbiAgXCJhYnN0cmFjdFwiLCBcImFzc2VydFwiLCBcImJvb2xlYW5cIiwgXCJicmVha1wiLCBcImJ5dGVcIiwgXCJjYXNlXCIsIFwiY2F0Y2hcIiwgXCJjaGFyXCIsIFwiY2xhc3NcIiwgXCJjb25zdFwiLCBcImNvbnRpbnVlXCIsIFwiZGVmYXVsdFwiLFxuICBcImRvXCIsIFwiZG91YmxlXCIsIFwiZWxzZVwiLCBcImVudW1cIiwgXCJleHRlbmRzXCIsIFwiZmluYWxcIiwgXCJmaW5hbGx5XCIsIFwiZmxvYXRcIiwgXCJmb3JcIiwgXCJnb3RvXCIsIFwiaWZcIiwgXCJpbXBsZW1lbnRzXCIsXG4gIFwiaW1wb3J0XCIsIFwiaW5zdGFuY2VvZlwiLCBcImludFwiLCBcImludGVyZmFjZVwiLCBcImxvbmdcIiwgXCJuYXRpdmVcIiwgXCJuZXdcIiwgXCJwYWNrYWdlXCIsIFwicHJpdmF0ZVwiLCBcInByb3RlY3RlZFwiLCBcInB1YmxpY1wiLFxuICBcInJldHVyblwiLCBcInNob3J0XCIsIFwic3RhdGljXCIsIFwic3RyaWN0ZnBcIiwgXCJzdXBlclwiLCBcInN3aXRjaFwiLCBcInN5bmNocm9uaXplZFwiLCBcInRoaXNcIiwgXCJ0aHJvd1wiLCBcInRocm93c1wiLCBcInRyYW5zaWVudFwiLFxuICBcInRyeVwiLCBcInZvaWRcIiwgXCJ2b2xhdGlsZVwiLCBcIndoaWxlXCJcbl0pXG5jb25zdCBmb3JiaWRkZW5QYWNrYWdlTmFtZXMgPSBuZXcgU2V0KFtcbiAgLi4uZmx1dHRlckxvY2tlZEhvc3RlZFBhY2thZ2VzLm1hcCgoW25hbWVdKSA9PiBuYW1lKSxcbiAgLi4uZmx1dHRlckxvY2tlZFNka1BhY2thZ2VzLm1hcCgoW25hbWVdKSA9PiBuYW1lKSxcbiAgXCJpbnRlZ3JhdGlvbl90ZXN0XCIsXG4gIFwic2VtYW50aWZvbGRcIlxuXSlcbmNvbnN0IGFuZHJvaWRSdW5uZXJCYXNlQ2xhc3NOYW1lcyA9IG5ldyBTZXQoW1wiRmx1dHRlckFjdGl2aXR5XCJdKVxuY29uc3Qgc2VtYW50aWNWZXJzaW9uUGF0dGVybiA9IC9eKD86MHxbMS05XVswLTldKilcXC4oPzowfFsxLTldWzAtOV0qKVxcLig/OjB8WzEtOV1bMC05XSopKD86LSg/OjB8WzEtOV1bMC05XSp8W0EtWmEtei1dW0EtWmEtejAtOS1dKikoPzpcXC4oPzowfFsxLTldWzAtOV0qfFtBLVphLXotXVtBLVphLXowLTktXSopKSopPyg/OlxcK1tBLVphLXowLTktXSsoPzpcXC5bQS1aYS16MC05LV0rKSopPyQvdVxuY29uc3QgbWVkaWFUeXBlUGF0dGVybiA9IC9eW0EtWmEtejAtOSEjJCZeXy4rLV0rXFwvW0EtWmEtejAtOSEjJCZeXy4rLV0rKD86W1xcdTAwMjAtXFx1MDA3ZV0rKT8kL3VcbmNvbnN0IGV4Y2x1ZGVkUGF0aFBhdHRlcm5zID0gT2JqZWN0LmZyZWV6ZShbXG4gIFwiLmRhcnRfdG9vbC8qKlwiLCBcIi5mbHV0dGVyLXBsdWdpbnNcIiwgXCIuZmx1dHRlci1wbHVnaW5zLWRlcGVuZGVuY2llc1wiLCBcImFuZHJvaWQvLmdyYWRsZS8qKlwiLCBcImFuZHJvaWQvYXBwL2J1aWxkLyoqXCIsXG4gIFwiYW5kcm9pZC9sb2NhbC5wcm9wZXJ0aWVzXCIsIFwiYnVpbGQvKipcIlxuXSlcbmNvbnN0IG91dHB1dFNpbmtSdW50aW1lID0gYFxuZmluYWwgY2xhc3MgX1NlbWFudGlmb2xkT3V0cHV0U2luayB7XG4gIGZpbmFsIExpc3Q8U3RyaW5nPiBfdmFsdWVzID0gPFN0cmluZz5bXTtcblxuICB2b2lkIHdyaXRlKE9iamVjdCB2YWx1ZSkge1xuICAgIGlmICh2YWx1ZSBpcyEgaW50ICYmIHZhbHVlIGlzISBib29sICYmIHZhbHVlIGlzISBTdHJpbmcpIHtcbiAgICAgIHRocm93IFN0YXRlRXJyb3IoJ1Vuc3VwcG9ydGVkIFNlbWFudGlmb2xkIG91dHB1dCB2YWx1ZScpO1xuICAgIH1cbiAgICBfdmFsdWVzLmFkZCh2YWx1ZS50b1N0cmluZygpKTtcbiAgfVxuXG4gIExpc3Q8U3RyaW5nPiBzbmFwc2hvdCgpID0+IExpc3Q8U3RyaW5nPi51bm1vZGlmaWFibGUoX3ZhbHVlcyk7XG59XG5gXG5cbi8qKiBAdHlwZWRlZiB7e2NvbnRlbnQ6IHN0cmluZyB8IFVpbnQ4QXJyYXksIGNvbnRlbnRLaW5kOiBcImJpbmFyeVwiIHwgXCJ0ZXh0XCIsIGZ1bGxQYXRoOiBzdHJpbmcsIG1lZGlhVHlwZTogc3RyaW5nLCBwYXRoOiBzdHJpbmcsIHNoYTI1Njogc3RyaW5nfX0gRmx1dHRlckFzc2V0ICovXG4vKiogQHR5cGVkZWYge3tlbmQ6IG51bWJlciwgZmllbGQ6IHN0cmluZywgcGF0aDogc3RyaW5nLCBzdGFydDogbnVtYmVyfX0gQ29uZmlndXJhdGlvblNwYW4gKi9cblxuLyoqXG4gKiBQcmVmbGlnaHRzIGEgY29tcGxldGUgRmx1dHRlciBhcHBsaWNhdGlvbiByZXF1ZXN0IGJlZm9yZSByZW5kZXJpbmcgYW55IGFydGlmYWN0LlxuICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCB1bmtub3duPn0gaW5wdXQgLSBDYW5kaWRhdGUgYXBwbGljYXRpb24gcmVxdWVzdC5cbiAqIEByZXR1cm5zIHt7YXNzZXRzOiBGbHV0dGVyQXNzZXRbXSwgY29uZmlndXJhdGlvbjogaW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuRmx1dHRlckFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbiwgbW9kdWxlUGF0aHM6IE1hcDxzdHJpbmcsIHN0cmluZz4sIG1vZHVsZXM6IGltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljTW9kdWxlW10sIHBhY2thZ2VQYXRoOiBzdHJpbmcsIHByb2dyYW06IGltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljUHJvZ3JhbSwgc291cmNlczoge2NvbnRlbnQ6IHN0cmluZywgZmlsZW5hbWU6IHN0cmluZywgbGFuZ3VhZ2U/OiBpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY0xhbmd1YWdlfVtdfX0gUHJlcGFyZWQgYXBwbGljYXRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcmVmbGlnaHRGbHV0dGVyQXBwbGljYXRpb24oaW5wdXQpIHtcbiAgaWYgKCFpc1BsYWluT2JqZWN0KGlucHV0KSB8fCBPYmplY3Qua2V5cyhpbnB1dCkuc29tZShrZXkgPT4gIXJlcXVlc3RGaWVsZHMuaGFzKGtleSkpIHx8XG4gICAgQm9vbGVhbihpbnB1dC5tb2R1bGUpID09IEJvb2xlYW4oaW5wdXQucHJvZ3JhbSkpIHtcbiAgICBpbnZhbGlkSW5wdXQoXCJGbHV0dGVyIGFwcGxpY2F0aW9uIGdlbmVyYXRpb24gcmVxdWlyZXMgYSBjbG9zZWQgcmVxdWVzdCB3aXRoIGV4YWN0bHkgb25lIHNlbWFudGljIG1vZHVsZSBvciBwcm9ncmFtLlwiKVxuICB9XG4gIGlmIChpbnB1dC5sYW5ndWFnZSAhPT0gdW5kZWZpbmVkICYmIGlucHV0Lmxhbmd1YWdlICE9IFwiZmx1dHRlclwiIHx8IGlucHV0LnJvbGUgIT09IHVuZGVmaW5lZCAmJiBpbnB1dC5yb2xlICE9IFwiYXBwbGljYXRpb25cIikge1xuICAgIGludmFsaWRJbnB1dChcIkZsdXR0ZXIgYXBwbGljYXRpb24gZ2VuZXJhdGlvbiBhY2NlcHRzIG9ubHkgdGhlIEZsdXR0ZXIgYXBwbGljYXRpb24gcm9sZS5cIilcbiAgfVxuICBjb25zdCBjb25maWd1cmF0aW9uID0gbm9ybWFsaXplQ29uZmlndXJhdGlvbihpbnB1dC5jb25maWd1cmF0aW9uKVxuICBjb25zdCBwcm9ncmFtID0gaW5wdXQucHJvZ3JhbSA/PyBub3JtYWxpemVTaW5nbGVNb2R1bGUoXG4gICAgLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY01vZHVsZSB8IHVuZGVmaW5lZH0gKi8gKGlucHV0Lm1vZHVsZSkpXG4gIGNvbnN0IHByZXBhcmVkID0gcHJlZmxpZ2h0U2VtYW50aWNQcm9ncmFtKHtcbiAgICBiYWNrZW5kTGFuZ3VhZ2U6IFwiZGFydFwiLFxuICAgIGRpYWdub3N0aWNMYW5ndWFnZTogXCJmbHV0dGVyXCIsXG4gICAgcHJvZ3JhbTogLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY1Byb2dyYW19ICovIChwcm9ncmFtKSxcbiAgICBzb3VyY2VMYW5ndWFnZXM6IGZsdXR0ZXJTb3VyY2VMYW5ndWFnZXNcbiAgfSlcbiAgY29uc3QgZW50cnlNb2R1bGUgPSBwcmVwYXJlZC5tb2R1bGVzLmZpbmQobW9kdWxlID0+IFJlZmxlY3QuZ2V0KG1vZHVsZSwgXCJpZFwiKSA9PSBwcmVwYXJlZC5wcm9ncmFtLmVudHJ5TW9kdWxlKVxuICBjb25zdCBlbnRyeUNvbGxpc2lvbiA9IGVudHJ5TW9kdWxlPy5mdW5jdGlvbnMuZmluZCgoe25hbWV9KSA9PiBuYW1lID09IFwic2VtYW50aWZvbGRFbnRyeVwiKVxuXG4gIGlmIChlbnRyeUNvbGxpc2lvbikgdW5zdXBwb3J0ZWRDYXBhYmlsaXR5KFwiZmx1dHRlclwiLCBcInJlc2VydmVkIGdlbmVyYXRlZCBzZW1hbnRpYyBlbnRyeSBmdW5jdGlvbiAnc2VtYW50aWZvbGRFbnRyeSdcIiwgZW50cnlDb2xsaXNpb24ubG9jYXRpb24pXG4gIGNvbnN0IHBhY2thZ2VQYXRoID0gY29uZmlndXJhdGlvbi5hcHBsaWNhdGlvbklkLnJlcGxhY2VBbGwoXCIuXCIsIFwiL1wiKVxuICBjb25zdCBtb2R1bGVQYXRocyA9IG5ldyBNYXAocHJlcGFyZWQubW9kdWxlcy5tYXAobW9kdWxlID0+IHtcbiAgICBjb25zdCBtb2R1bGVJZCA9IC8qKiBAdHlwZSB7c3RyaW5nfSAqLyAoUmVmbGVjdC5nZXQobW9kdWxlLCBcImlkXCIpKVxuXG4gICAgcmV0dXJuIFttb2R1bGVJZCwgYCR7cHJvamVjdFJvb3R9L2xpYi9zcmMvc2VtYW50aWMvJHttb2R1bGVGaWxlTmFtZShtb2R1bGVJZCl9LmRhcnRgXVxuICB9KSlcbiAgY29uc3QgYXNzZXRzID0gbm9ybWFsaXplQXNzZXRzKGlucHV0LmFzc2V0cylcbiAgY29uc3QgY29tcGxldGVQYXRocyA9IFsuLi5hcHBsaWNhdGlvblBhdGhzKGNvbmZpZ3VyYXRpb24sIG1vZHVsZVBhdGhzKSwgLi4uYXNzZXRzLm1hcCgoe2Z1bGxQYXRofSkgPT4gZnVsbFBhdGgpXVxuICBjb25zdCBjb25mbGljdCA9IGZpbmRQb3J0YWJsZUFydGlmYWN0UGF0aENvbmZsaWN0KGNvbXBsZXRlUGF0aHMpXG5cbiAgaWYgKGNvbmZsaWN0KSB7XG4gICAgaW52YWxpZFBhdGgoYEFwcGxpY2F0aW9uIGFydGlmYWN0IHBhdGggJyR7Y29uZmxpY3QucGF0aH0nIGhhcyBhICR7Y29uZmxpY3Qua2luZH0gY29uZmxpY3Qke2NvbmZsaWN0Lm90aGVyID8gYCB3aXRoICcke2NvbmZsaWN0Lm90aGVyfSdgIDogXCJcIn0uYClcbiAgfVxuICBjb25zdCBzZW1hbnRpY05hbWVzID0gbmV3IE1hcCgpXG5cbiAgZm9yIChjb25zdCBtb2R1bGUgb2YgcHJlcGFyZWQubW9kdWxlcykge1xuICAgIGNvbnN0IG1vZHVsZUlkID0gLyoqIEB0eXBlIHtzdHJpbmd9ICovIChSZWZsZWN0LmdldChtb2R1bGUsIFwiaWRcIikpXG4gICAgY29uc3QgbmFtZSA9IG1vZHVsZU5hbWUobW9kdWxlSWQpXG4gICAgY29uc3QgcHJldmlvdXMgPSBzZW1hbnRpY05hbWVzLmdldChuYW1lKVxuXG4gICAgaWYgKHByZXZpb3VzKSBpbnZhbGlkUGF0aChgU2VtYW50aWMgbW9kdWxlcyAnJHtwcmV2aW91c30nIGFuZCAnJHttb2R1bGVJZH0nIGNvbGxpZGUgYXQgZ2VuZXJhdGVkIERhcnQgY2xhc3MgJyR7bmFtZX0nLmApXG4gICAgc2VtYW50aWNOYW1lcy5zZXQobmFtZSwgbW9kdWxlSWQpXG4gIH1cblxuICByZXR1cm4gey4uLnByZXBhcmVkLCBhc3NldHMsIGNvbmZpZ3VyYXRpb24sIG1vZHVsZVBhdGhzLCBwYWNrYWdlUGF0aH1cbn1cblxuLyoqXG4gKiBHZW5lcmF0ZXMgb25lIGRldGVybWluaXN0aWMgU0RLLW9ubHkgRmx1dHRlciBwcm9qZWN0IGZvciB0aGUgcXVhbGlmaWVkIEFuZHJvaWQgbGFuZS5cbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgdW5rbm93bj59IGlucHV0IC0gQXBwbGljYXRpb24gZ2VuZXJhdGlvbiByZXF1ZXN0LlxuICogQHJldHVybnMge3thcnRpZmFjdHM6IGltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZFNldEFydGlmYWN0W10sIG1ldGFkYXRhOiB7YXBwbGljYXRpb25NYW5pZmVzdDogc3RyaW5nLCBwbGF0Zm9ybVF1YWxpZmljYXRpb246IHthbmRyb2lkOiBzdHJpbmcsIGlvczogc3RyaW5nfX0sIHRhcmdldDogXCJmbHV0dGVyXCJ9fSBDYW5kaWRhdGUgYXJ0aWZhY3Qgc2V0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVGbHV0dGVyQXBwbGljYXRpb24oaW5wdXQpIHtcbiAgY29uc3QgcHJlcGFyZWQgPSBwcmVmbGlnaHRGbHV0dGVyQXBwbGljYXRpb24oaW5wdXQpXG4gIGNvbnN0IGNvbmZpZ3VyYXRpb25TcGFucyA9IC8qKiBAdHlwZSB7Q29uZmlndXJhdGlvblNwYW5bXX0gKi8gKFtdKVxuICBjb25zdCBjb25maWd1cmF0aW9uID0gcHJlcGFyZWQuY29uZmlndXJhdGlvblxuICBjb25zdCBzZW1hbnRpY0FydGlmYWN0cyA9IHJlbmRlclNlbWFudGljQXJ0aWZhY3RzKHByZXBhcmVkKVxuICBjb25zdCBhcnRpZmFjdHMgPSAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZFNldEFydGlmYWN0W119ICovIChbXG4gICAgc3ludGhldGljVGV4dChgJHtwcm9qZWN0Um9vdH0vLm1ldGFkYXRhYCwgXCJtYW5pZmVzdFwiLCByZW5kZXJNZXRhZGF0YSgpLFxuICAgICAgXCJFeGFjdCBGbHV0dGVyIDMuNDcuNCBwcm9qZWN0LXRlbXBsYXRlIGlkZW50aXR5OyBnZW5lcmF0ZWQgbWlncmF0aW9uIGlzIGRpc2FibGVkLlwiKSxcbiAgICBzeW50aGV0aWNUZXh0KGAke3Byb2plY3RSb290fS9hbmFseXNpc19vcHRpb25zLnlhbWxgLCBcInN1cHBvcnRcIiwgcmVuZGVyQW5hbHlzaXNPcHRpb25zKCksXG4gICAgICBcIkNsb3NlZCBhbmFseXplciBjb25maWd1cmF0aW9uIHdpdGhvdXQgZXh0ZXJuYWwgbGludCBwYWNrYWdlcy5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYXBwL2J1aWxkLmdyYWRsZS5rdHNgLCBcIm1hbmlmZXN0XCIsIHJlbmRlckFuZHJvaWRBcHBCdWlsZChjb25maWd1cmF0aW9uLCBjb25maWd1cmF0aW9uU3BhbnMpLFxuICAgICAgXCJUYXNrIDAyOC1jb21wYXRpYmxlIEFuZHJvaWQgYnVpbGQgYW5kIGlzb2xhdGVkIGRlYnVnLXNpZ25pbmcgY29uZmlndXJhdGlvbi5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYXBwL3NyYy9tYWluL0FuZHJvaWRNYW5pZmVzdC54bWxgLCBcIm1hbmlmZXN0XCIsXG4gICAgICByZW5kZXJBbmRyb2lkTWFuaWZlc3QoY29uZmlndXJhdGlvbiwgY29uZmlndXJhdGlvblNwYW5zKSwgXCJDbG9zZWQgcGVybWlzc2lvbi1mcmVlIEZsdXR0ZXIgQW5kcm9pZCBhcHBsaWNhdGlvbiBtYW5pZmVzdC5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYXBwL3NyYy9tYWluL2phdmEvJHtwcmVwYXJlZC5wYWNrYWdlUGF0aH0vJHtjb25maWd1cmF0aW9uLmFjdGl2aXR5Q2xhc3NOYW1lfS5qYXZhYCwgXCJzdXBwb3J0XCIsXG4gICAgICByZW5kZXJBbmRyb2lkQWN0aXZpdHkoY29uZmlndXJhdGlvbiwgY29uZmlndXJhdGlvblNwYW5zKSwgXCJTeW50aGV0aWMgRmx1dHRlciBBbmRyb2lkIGVtYmVkZGluZyBsYXVuY2hlci5cIiksXG4gICAgc3ludGhldGljVGV4dChgJHtwcm9qZWN0Um9vdH0vYW5kcm9pZC9hcHAvc3JjL21haW4vcmVzL2RyYXdhYmxlL2xhdW5jaF9iYWNrZ3JvdW5kLnhtbGAsIFwicmVzb3VyY2VcIiwgcmVuZGVyTGF1bmNoQmFja2dyb3VuZCgpLFxuICAgICAgXCJTeW50aGV0aWMgbWluaW11bS1TREstcXVhbGlmaWVkIEZsdXR0ZXIgbGF1bmNoIGJhY2tncm91bmQuXCIpLFxuICAgIHN5bnRoZXRpY1RleHQoYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYXBwL3NyYy9tYWluL3Jlcy92YWx1ZXMtbmlnaHQvc3R5bGVzLnhtbGAsIFwicmVzb3VyY2VcIiwgcmVuZGVyQW5kcm9pZFN0eWxlcyh0cnVlKSxcbiAgICAgIFwiU3ludGhldGljIGRhcmsgcGxhdGZvcm0gbGF1bmNoIGFuZCBGbHV0dGVyIGhvc3QgdGhlbWVzLlwiKSxcbiAgICBzeW50aGV0aWNUZXh0KGAke3Byb2plY3RSb290fS9hbmRyb2lkL2FwcC9zcmMvbWFpbi9yZXMvdmFsdWVzL3N0eWxlcy54bWxgLCBcInJlc291cmNlXCIsIHJlbmRlckFuZHJvaWRTdHlsZXMoZmFsc2UpLFxuICAgICAgXCJTeW50aGV0aWMgbGlnaHQgcGxhdGZvcm0gbGF1bmNoIGFuZCBGbHV0dGVyIGhvc3QgdGhlbWVzLlwiKSxcbiAgICBzeW50aGV0aWNUZXh0KGAke3Byb2plY3RSb290fS9hbmRyb2lkL2FwcC9zcmMvbWFpbi9yZXMveG1sL2JhY2t1cF9ydWxlcy54bWxgLCBcInJlc291cmNlXCIsIHJlbmRlckJhY2t1cFJ1bGVzKCksXG4gICAgICBcIkNsb3NlZCBBUEkgMjMtMzAgZnVsbC1iYWNrdXAgZXhjbHVzaW9ucyByZXVzZWQgZnJvbSB0aGUgQW5kcm9pZCBzYWZldHkgY29udHJhY3QuXCIpLFxuICAgIHN5bnRoZXRpY1RleHQoYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYXBwL3NyYy9tYWluL3Jlcy94bWwvZGF0YV9leHRyYWN0aW9uX3J1bGVzLnhtbGAsIFwicmVzb3VyY2VcIiwgcmVuZGVyRGF0YUV4dHJhY3Rpb25SdWxlcygpLFxuICAgICAgXCJDbG9zZWQgQW5kcm9pZCAxMisgYmFja3VwIGFuZCB0cmFuc2ZlciBleGNsdXNpb25zIHJldXNlZCBmcm9tIHRoZSBBbmRyb2lkIHNhZmV0eSBjb250cmFjdC5cIiksXG4gICAgc3ludGhldGljVGV4dChgJHtwcm9qZWN0Um9vdH0vYW5kcm9pZC9idWlsZC5ncmFkbGUua3RzYCwgXCJtYW5pZmVzdFwiLCByZW5kZXJBbmRyb2lkUm9vdEJ1aWxkKCksXG4gICAgICBcIlRhc2sgMDI4LWNvbXBhdGlibGUgZGV0ZXJtaW5pc3RpYyBBbmRyb2lkIHJvb3QgYnVpbGQuXCIpLFxuICAgIHN5bnRoZXRpY1RleHQoYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvZ3JhZGxlLnByb3BlcnRpZXNgLCBcInN1cHBvcnRcIiwgcmVuZGVyQW5kcm9pZEdyYWRsZVByb3BlcnRpZXMoKSxcbiAgICAgIFwiUGlubmVkIGlzb2xhdGVkIEdyYWRsZSBwcm9wZXJ0aWVzIGZvciB0aGUgcXVhbGlmaWVkIEFuZHJvaWQgbGFuZS5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvc2V0dGluZ3MuZ3JhZGxlLmt0c2AsIFwibWFuaWZlc3RcIiwgcmVuZGVyQW5kcm9pZFNldHRpbmdzKGNvbmZpZ3VyYXRpb24sIGNvbmZpZ3VyYXRpb25TcGFucyksXG4gICAgICBcIkV4YWN0IEZsdXR0ZXIgR3JhZGxlIHBsdWdpbiBsb2FkZXIgd2l0aCB0aGUgcGlubmVkIFRhc2sgMDI4IEFuZHJvaWQgcGx1Z2luIG1hdHJpeC5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2xpYi9tYWluLmRhcnRgLCBcImVudHJ5XCIsIHJlbmRlcldpZGdldEFwcGxpY2F0aW9uKHByZXBhcmVkLCBjb25maWd1cmF0aW9uU3BhbnMpLFxuICAgICAgXCJTeW50aGV0aWMgc3RhdGVsZXNzIE1hdGVyaWFsIGFwcGxpY2F0aW9uIGFuZCBsYWJlbGxlZCBvdXRwdXQgd2lkZ2V0LlwiKSxcbiAgICAuLi5zZW1hbnRpY0FydGlmYWN0cyxcbiAgICBzeW50aGV0aWNUZXh0KGAke3Byb2plY3RSb290fS9wdWJzcGVjLmxvY2tgLCBcIm1hbmlmZXN0XCIsIHJlbmRlclB1YnNwZWNMb2NrKCksXG4gICAgICBcIkV4YWN0IEZsdXR0ZXIgMy40Ny40IFNESyBkZXBlbmRlbmN5IHJlc29sdXRpb247IG5vIGNhbGxlciBwYWNrYWdlIHJlc29sdXRpb24uXCIpLFxuICAgIGNvbmZpZ3VyZWRUZXh0KGAke3Byb2plY3RSb290fS9wdWJzcGVjLnlhbWxgLCBcIm1hbmlmZXN0XCIsIHJlbmRlclB1YnNwZWMocHJlcGFyZWQsIGNvbmZpZ3VyYXRpb25TcGFucyksXG4gICAgICBcIkNsb3NlZCBTREstb25seSBGbHV0dGVyIHBhY2thZ2UgYW5kIGFzc2V0IG1hbmlmZXN0LlwiKSxcbiAgICBjb25maWd1cmVkVGV4dChgJHtwcm9qZWN0Um9vdH0vdGVzdC9zZW1hbnRpY19sb2dpY190ZXN0LmRhcnRgLCBcInN1cHBvcnRcIiwgcmVuZGVyTG9naWNUZXN0KHByZXBhcmVkLCBjb25maWd1cmF0aW9uU3BhbnMpLFxuICAgICAgXCJTREstb3duZWQgRmx1dHRlciB0ZXN0IGZvciBmcmVzaCBkZXRlcm1pbmlzdGljIHNlbWFudGljIGVudHJ5IGV4ZWN1dGlvbi5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L3Rlc3Qvd2lkZ2V0X3Rlc3QuZGFydGAsIFwic3VwcG9ydFwiLCByZW5kZXJXaWRnZXRUZXN0KHByZXBhcmVkLCBjb25maWd1cmF0aW9uU3BhbnMpLFxuICAgICAgXCJTREstb3duZWQgRmx1dHRlciB3aWRnZXQgdGVzdCBmb3IgZXhhY3QgdGV4dCwga2V5LCBhbmQgc2VtYW50aWNzIGxhYmVsLlwiKSxcbiAgICAuLi5wcmVwYXJlZC5hc3NldHMubWFwKGFzc2V0QXJ0aWZhY3QpXG4gIF0pXG5cbiAgYXJ0aWZhY3RzLnNvcnQoKGxlZnQsIHJpZ2h0KSA9PiBsZWZ0LnBhdGggPCByaWdodC5wYXRoID8gLTEgOiBsZWZ0LnBhdGggPiByaWdodC5wYXRoID8gMSA6IDApXG4gIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGAke3Byb2plY3RSb290fS9zZW1hbnRpZm9sZC1wcm9qZWN0Lmpzb25gXG5cbiAgYXJ0aWZhY3RzLnB1c2goc3ludGhldGljVGV4dChtYW5pZmVzdFBhdGgsIFwibWFuaWZlc3RcIixcbiAgICByZW5kZXJQcm9qZWN0TWFuaWZlc3QocHJlcGFyZWQsIGFydGlmYWN0cywgbWFuaWZlc3RQYXRoLCBjb25maWd1cmF0aW9uU3BhbnMpLFxuICAgIFwiVmVyc2lvbmVkIEZsdXR0ZXIgcHJvamVjdCBvd25lcnNoaXAsIHRvb2xjaGFpbiwgcHJvdmVuYW5jZSwgYW5kIHBsYXRmb3JtLXN0YXR1cyBtYW5pZmVzdC5cIikpXG5cbiAgcmV0dXJuIHtcbiAgICBhcnRpZmFjdHMsXG4gICAgbWV0YWRhdGE6IHtcbiAgICAgIGFwcGxpY2F0aW9uTWFuaWZlc3Q6IG1hbmlmZXN0UGF0aCxcbiAgICAgIHBsYXRmb3JtUXVhbGlmaWNhdGlvbjoge2FuZHJvaWQ6IFwidGVuc29yYnV6ei1rdm1cIiwgaW9zOiBcImRlZmVycmVkLW93bmVyLWRpcmVjdGlvblwifVxuICAgIH0sXG4gICAgdGFyZ2V0OiBcImZsdXR0ZXJcIlxuICB9XG59XG5cbi8qKlxuICogRW1pdHMgbWFwcGVkIGFwcGxpY2F0aW9uLW93bmVkIERhcnQgc2VtYW50aWMgbW9kdWxlcy5cbiAqIEBwYXJhbSB7UmV0dXJuVHlwZTx0eXBlb2YgcHJlZmxpZ2h0Rmx1dHRlckFwcGxpY2F0aW9uPn0gcHJlcGFyZWQgLSBQcmVwYXJlZCBhcHBsaWNhdGlvbi5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0ZWRTZXRBcnRpZmFjdFtdfSBTZW1hbnRpYyBEYXJ0IGFydGlmYWN0cy5cbiAqL1xuZnVuY3Rpb24gcmVuZGVyU2VtYW50aWNBcnRpZmFjdHMocHJlcGFyZWQpIHtcbiAgY29uc3QgZGVjbGFyYXRpb25zID0gbmV3IE1hcCgpXG5cbiAgZm9yIChjb25zdCBtb2R1bGUgb2YgcHJlcGFyZWQubW9kdWxlcykge1xuICAgIGZvciAoY29uc3QgZGVjbGFyYXRpb24gb2YgbW9kdWxlLmZ1bmN0aW9ucykgZGVjbGFyYXRpb25zLnNldChkZWNsYXJhdGlvbi5pZCwge1xuICAgICAgZGVjbGFyYXRpb24sXG4gICAgICBtb2R1bGVJZDogLyoqIEB0eXBlIHtzdHJpbmd9ICovIChSZWZsZWN0LmdldChtb2R1bGUsIFwiaWRcIikpXG4gICAgfSlcbiAgfVxuICAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZFNldEFydGlmYWN0W119ICovXG4gIGNvbnN0IGFydGlmYWN0cyA9IFtzeW50aGV0aWNUZXh0KGAke3Byb2plY3RSb290fS9saWIvc3JjL3NlbWFudGljL3NlbWFudGlmb2xkLmRhcnRgLCBcInN1cHBvcnRcIixcbiAgICByZW5kZXJTZW1hbnRpY0xpYnJhcnkocHJlcGFyZWQpLCBcIlNoYXJlZCBjaGVja2VkIERhcnQgc2NhbGFyL291dHB1dCBydW50aW1lIGFuZCBkZXRlcm1pbmlzdGljIHBhcnQgb3duZXJzaGlwLlwiKV1cblxuICBmb3IgKGNvbnN0IG1vZHVsZSBvZiBwcmVwYXJlZC5tb2R1bGVzKSB7XG4gICAgY29uc3QgbW9kdWxlSWQgPSAvKiogQHR5cGUge3N0cmluZ30gKi8gKFJlZmxlY3QuZ2V0KG1vZHVsZSwgXCJpZFwiKSlcbiAgICBjb25zdCBmaWxlbmFtZSA9IC8qKiBAdHlwZSB7c3RyaW5nfSAqLyAocHJlcGFyZWQubW9kdWxlUGF0aHMuZ2V0KG1vZHVsZUlkKSlcbiAgICBjb25zdCBzaW5rTmFtZSA9IG91dHB1dFNpbmtOYW1lKG1vZHVsZSlcbiAgICBjb25zdCB3cml0ZXIgPSBuZXcgU291cmNlV3JpdGVyKHtcbiAgICAgIGNhbGxBcmd1bWVudFN1ZmZpeDogc2lua05hbWUsXG4gICAgICBjYWxsTmFtZVJlc29sdmVyOiBleHByZXNzaW9uID0+IHtcbiAgICAgICAgY29uc3QgcmVzb2x2ZWQgPSBkZWNsYXJhdGlvbnMuZ2V0KGV4cHJlc3Npb24ucmVzb2x1dGlvbj8uZGVjbGFyYXRpb25JZClcblxuICAgICAgICBpZiAoIXJlc29sdmVkKSB0aHJvdyBuZXcgVHlwZUVycm9yKGBVbmtub3duIHZhbGlkYXRlZCBGbHV0dGVyIGZ1bmN0aW9uICcke2V4cHJlc3Npb24ucmVzb2x1dGlvbj8uZGVjbGFyYXRpb25JZH0nLmApXG5cbiAgICAgICAgcmV0dXJuIGBTZW1hbnRpZm9sZE1vZHVsZSR7bW9kdWxlTmFtZShyZXNvbHZlZC5tb2R1bGVJZCl9LiR7cmVzb2x2ZWQuZGVjbGFyYXRpb24ubmFtZX1gXG4gICAgICB9LFxuICAgICAgZmlsZW5hbWUsXG4gICAgICBsYW5ndWFnZTogXCJkYXJ0XCIsXG4gICAgICBtb2R1bGUsXG4gICAgICBwcm9ncmFtOiBwcmVwYXJlZC5wcm9ncmFtLFxuICAgICAgcHJvZ3JhbVBhdGhzOiBwcmVwYXJlZC5tb2R1bGVQYXRocyxcbiAgICAgIHNvdXJjZXM6IHByZXBhcmVkLnNvdXJjZXNcbiAgICB9KVxuXG4gICAgd3JpdGVyLnN5bnRoZXRpYyhcInBhcnQgb2YgJ3NlbWFudGlmb2xkLmRhcnQnO1xcblxcblwiLCBcIkZsdXR0ZXIgc2VtYW50aWMgbGlicmFyeSBwYXJ0IGRpcmVjdGl2ZVwiLCBbbW9kdWxlXSwgW1wiXCJdKVxuICAgIGVtaXRTZW1hbnRpY01vZHVsZSh3cml0ZXIsIG1vZHVsZSwgbW9kdWxlSWQsIG1vZHVsZUlkID09IHByZXBhcmVkLnByb2dyYW0uZW50cnlNb2R1bGUsIHNpbmtOYW1lKVxuICAgIGNvbnN0IG1hcHBpbmcgPSBmaW5hbGl6ZU1hcHBpbmcod3JpdGVyLmZpbmlzaCgpKVxuXG4gICAgYXJ0aWZhY3RzLnB1c2goe1xuICAgICAgY29udGVudDogbWFwcGluZy5nZW5lcmF0ZWQuY29udGVudCxcbiAgICAgIGNvbnRlbnRLaW5kOiBcInRleHRcIixcbiAgICAgIG1lZGlhVHlwZTogXCJ0ZXh0L3gtZGFydFwiLFxuICAgICAgb3duZXJzaGlwOiBcImdlbmVyYXRlZFwiLFxuICAgICAgcGF0aDogZmlsZW5hbWUsXG4gICAgICBwcm92ZW5hbmNlOiB7a2luZDogXCJ0ZXh0XCIsIG1hcHBpbmcsIHNvdXJjZU1hcDogdG9Tb3VyY2VNYXBWMyhtYXBwaW5nKSwgc291cmNlTWFwRmlsZW5hbWU6IGAke2ZpbGVuYW1lfS5tYXBgfSxcbiAgICAgIHJvbGU6IFwic291cmNlXCJcbiAgICB9KVxuICB9XG5cbiAgcmV0dXJuIGFydGlmYWN0c1xufVxuXG4vKipcbiAqIEVtaXRzIG9uZSBuYW1lc3BhY2VkIHNlbWFudGljIERhcnQgcGFydC5cbiAqIEBwYXJhbSB7U291cmNlV3JpdGVyfSB3cml0ZXIgLSBNYXBwZWQgc291cmNlIHdyaXRlci5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU2VtYW50aWNNb2R1bGV9IG1vZHVsZSAtIFByZXBhcmVkIHNlbWFudGljIG1vZHVsZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBtb2R1bGVJZCAtIFN0YWJsZSBzZW1hbnRpYyBtb2R1bGUgaWRlbnRpdHkuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGVudHJ5IC0gV2hldGhlciB0aGlzIG1vZHVsZSBvd25zIHRoZSBhcHBsaWNhdGlvbiBlbnRyeS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzaW5rTmFtZSAtIENvbGxpc2lvbi1zYWZlIG91dHB1dCBzaW5rIGJpbmRpbmcuXG4gKi9cbmZ1bmN0aW9uIGVtaXRTZW1hbnRpY01vZHVsZSh3cml0ZXIsIG1vZHVsZSwgbW9kdWxlSWQsIGVudHJ5LCBzaW5rTmFtZSkge1xuICBjb25zdCB1bnJlYWRMb2NhbHMgPSBmaW5kVW5yZWFkRGFydExvY2Fscyhtb2R1bGUpXG5cbiAgd3JpdGVyLnN5bnRoZXRpYyhgYWJzdHJhY3QgZmluYWwgY2xhc3MgU2VtYW50aWZvbGRNb2R1bGUke21vZHVsZU5hbWUobW9kdWxlSWQpfSB7XFxuYCxcbiAgICBcIkZsdXR0ZXIgc2VtYW50aWMgbW9kdWxlIG5hbWVzcGFjZVwiLCBbbW9kdWxlXSwgW1wiXCJdKVxuICBtb2R1bGUuZnVuY3Rpb25zLmZvckVhY2goKGRlY2xhcmF0aW9uLCBmdW5jdGlvbkluZGV4KSA9PiB7XG4gICAgY29uc3QgcGF0aCA9IGAvZnVuY3Rpb25zLyR7ZnVuY3Rpb25JbmRleH1gXG5cbiAgICB3cml0ZXIuc3ludGhldGljKFwiICBzdGF0aWMgXCIsIFwiRmx1dHRlciBuYW1lc3BhY2VkIGZ1bmN0aW9uIHNjYWZmb2xkXCIsIFtkZWNsYXJhdGlvbl0sIFtwYXRoXSlcbiAgICB3cml0ZXIubWFwcGVkKGVtaXRTY2FsYXJUeXBlKFwiZGFydFwiLCBkZWNsYXJhdGlvbi5yZXR1cm5UeXBlKSwge1xuICAgICAgbWFwcGluZ0tpbmQ6IFwiZXhhY3RcIiwgbm9kZTogZGVjbGFyYXRpb24ucmV0dXJuVHlwZSwgcGF0aDogYCR7cGF0aH0vcmV0dXJuVHlwZWAsIHJvbGU6IFwidHlwZVwiXG4gICAgfSlcbiAgICB3cml0ZXIuc3ludGhldGljKFwiIFwiLCBcImRlY2xhcmF0aW9uIHNwYWNpbmdcIiwgW2RlY2xhcmF0aW9uXSwgW3BhdGhdKVxuICAgIHdyaXRlci5tYXBwZWQoZGVjbGFyYXRpb24ubmFtZSwge21hcHBpbmdLaW5kOiBcImV4YWN0XCIsIG5vZGU6IGRlY2xhcmF0aW9uLCBwYXRoLCByb2xlOiBcIm5hbWVcIn0pXG4gICAgY29uc3QgcGFyYW1ldGVyVGV4dHMgPSBkZWNsYXJhdGlvbi5wYXJhbWV0ZXJzLm1hcChwYXJhbWV0ZXIgPT4gYCR7ZW1pdFNjYWxhclR5cGUoXCJkYXJ0XCIsIHBhcmFtZXRlci50eXBlKX0gJHtwYXJhbWV0ZXIubmFtZX1gKVxuXG4gICAgcGFyYW1ldGVyVGV4dHMucHVzaChgX1NlbWFudGlmb2xkT3V0cHV0U2luayAke3NpbmtOYW1lfWApXG4gICAgY29uc3QgbXVsdGlsaW5lID0gd3JpdGVyLmNvbHVtbiAtIDEgKyBgKCR7cGFyYW1ldGVyVGV4dHMuam9pbihcIiwgXCIpfSkge2AubGVuZ3RoID4gODBcblxuICAgIHdyaXRlci5tYXBwZWQoXCIoXCIsIHttYXBwaW5nS2luZDogXCJhbmNob3JcIiwgbm9kZTogZGVjbGFyYXRpb24sIHBhdGh9KVxuICAgIGRlY2xhcmF0aW9uLnBhcmFtZXRlcnMuZm9yRWFjaCgocGFyYW1ldGVyLCBwYXJhbWV0ZXJJbmRleCkgPT4ge1xuICAgICAgY29uc3QgcGFyYW1ldGVyUGF0aCA9IGAke3BhdGh9L3BhcmFtZXRlcnMvJHtwYXJhbWV0ZXJJbmRleH1gXG5cbiAgICAgIGlmIChtdWx0aWxpbmUpIHdyaXRlci5zeW50aGV0aWMoYCR7cGFyYW1ldGVySW5kZXggPyBcIlwiIDogXCJcXG5cIn0gICAgYCxcbiAgICAgICAgXCJEYXJ0IGFwcGxpY2F0aW9uIHBhcmFtZXRlciBpbmRlbnRhdGlvblwiLCBbcGFyYW1ldGVyXSwgW3BhcmFtZXRlclBhdGhdKVxuICAgICAgZWxzZSBpZiAocGFyYW1ldGVySW5kZXgpIHdyaXRlci5zeW50aGV0aWMoXCIsIFwiLCBcInBhcmFtZXRlciBzZXBhcmF0b3JcIiwgW3BhcmFtZXRlcl0sIFtwYXJhbWV0ZXJQYXRoXSlcbiAgICAgIHdyaXRlci5tYXBwZWQoZW1pdFNjYWxhclR5cGUoXCJkYXJ0XCIsIHBhcmFtZXRlci50eXBlKSwge1xuICAgICAgICBtYXBwaW5nS2luZDogXCJleGFjdFwiLCBub2RlOiBwYXJhbWV0ZXIudHlwZSwgcGF0aDogYCR7cGFyYW1ldGVyUGF0aH0vdHlwZWAsIHJvbGU6IFwidHlwZVwiXG4gICAgICB9KVxuICAgICAgd3JpdGVyLnN5bnRoZXRpYyhcIiBcIiwgXCJwYXJhbWV0ZXIgc3BhY2luZ1wiLCBbcGFyYW1ldGVyXSwgW3BhcmFtZXRlclBhdGhdKVxuICAgICAgd3JpdGVyLm1hcHBlZChwYXJhbWV0ZXIubmFtZSwge21hcHBpbmdLaW5kOiBcImV4YWN0XCIsIG5vZGU6IHBhcmFtZXRlciwgcGF0aDogcGFyYW1ldGVyUGF0aCwgcm9sZTogXCJuYW1lXCJ9KVxuICAgICAgaWYgKG11bHRpbGluZSkgd3JpdGVyLnN5bnRoZXRpYyhcIixcXG5cIiwgXCJEYXJ0IGZvcm1hdHRlciBwYXJhbWV0ZXIgc2VwYXJhdG9yXCIsIFtwYXJhbWV0ZXJdLCBbcGFyYW1ldGVyUGF0aF0pXG4gICAgfSlcbiAgICBpZiAobXVsdGlsaW5lKSB3cml0ZXIuc3ludGhldGljKGAke2RlY2xhcmF0aW9uLnBhcmFtZXRlcnMubGVuZ3RoID8gXCJcIiA6IFwiXFxuXCJ9ICAgIF9TZW1hbnRpZm9sZE91dHB1dFNpbmsgJHtzaW5rTmFtZX0sXFxuICBgLFxuICAgICAgXCJGbHV0dGVyIG91dHB1dCBzaW5rIHBhcmFtZXRlclwiLCBbZGVjbGFyYXRpb25dLCBbcGF0aF0pXG4gICAgZWxzZSB3cml0ZXIuc3ludGhldGljKGAke2RlY2xhcmF0aW9uLnBhcmFtZXRlcnMubGVuZ3RoID8gXCIsIFwiIDogXCJcIn1fU2VtYW50aWZvbGRPdXRwdXRTaW5rICR7c2lua05hbWV9YCxcbiAgICAgIFwiRmx1dHRlciBvdXRwdXQgc2luayBwYXJhbWV0ZXJcIiwgW2RlY2xhcmF0aW9uXSwgW3BhdGhdKVxuICAgIHdyaXRlci5tYXBwZWQoXCIpXCIsIHttYXBwaW5nS2luZDogXCJhbmNob3JcIiwgbm9kZTogZGVjbGFyYXRpb24sIHBhdGh9KVxuICAgIHdyaXRlci5zeW50aGV0aWMoXCIge1xcblwiLCBcIkRhcnQgZnVuY3Rpb24gYm9keSBzY2FmZm9sZFwiLCBbZGVjbGFyYXRpb25dLCBbcGF0aF0pXG4gICAgZW1pdERhcnRCbG9jayh3cml0ZXIsIGRlY2xhcmF0aW9uLmJvZHksIFwiICAgIFwiLCBgJHtwYXRofS9ib2R5YCwgdW5yZWFkTG9jYWxzLCBgJHtzaW5rTmFtZX0ud3JpdGVgLCB0cnVlKVxuICAgIHdyaXRlci5zeW50aGV0aWMoXCIgIH1cXG5cIiwgXCJEYXJ0IGZ1bmN0aW9uIGJvZHkgc2NhZmZvbGRcIiwgW2RlY2xhcmF0aW9uXSwgW3BhdGhdKVxuICAgIGlmIChmdW5jdGlvbkluZGV4ICsgMSA8IG1vZHVsZS5mdW5jdGlvbnMubGVuZ3RoIHx8IGVudHJ5KSB7XG4gICAgICB3cml0ZXIuc3ludGhldGljKFwiXFxuXCIsIFwiRGFydCBmb3JtYXR0ZXIgZGVjbGFyYXRpb24gc2VwYXJhdG9yXCIsIFtkZWNsYXJhdGlvbl0sIFtwYXRoXSlcbiAgICB9XG4gIH0pXG4gIGlmIChlbnRyeSkge1xuICAgIHdyaXRlci5zeW50aGV0aWMoXCIgIHN0YXRpYyBMaXN0PFN0cmluZz4gc2VtYW50aWZvbGRFbnRyeSgpIHtcXG5cIiwgXCJGbHV0dGVyIHNlbWFudGljIGVudHJ5IHNjYWZmb2xkXCIsXG4gICAgICBbbW9kdWxlLmVudHJ5UG9pbnRdLCBbXCIvZW50cnlQb2ludFwiXSlcbiAgICB3cml0ZXIuc3ludGhldGljKGAgICAgZmluYWwgX1NlbWFudGlmb2xkT3V0cHV0U2luayAke3NpbmtOYW1lfSA9IF9TZW1hbnRpZm9sZE91dHB1dFNpbmsoKTtcXG5gLFxuICAgICAgXCJGbHV0dGVyIG91dHB1dCBzaW5rIGFsbG9jYXRpb25cIiwgW21vZHVsZS5lbnRyeVBvaW50XSwgW1wiL2VudHJ5UG9pbnRcIl0pXG4gICAgZW1pdERhcnRCbG9jayh3cml0ZXIsIG1vZHVsZS5lbnRyeVBvaW50LmJvZHksIFwiICAgIFwiLCBcIi9lbnRyeVBvaW50L2JvZHlcIiwgdW5yZWFkTG9jYWxzLCBgJHtzaW5rTmFtZX0ud3JpdGVgLCB0cnVlKVxuICAgIHdyaXRlci5zeW50aGV0aWMoYCAgICByZXR1cm4gJHtzaW5rTmFtZX0uc25hcHNob3QoKTtcXG5gLCBcIkZsdXR0ZXIgc2VtYW50aWMgb3V0cHV0IHJldHVyblwiLFxuICAgICAgW21vZHVsZS5lbnRyeVBvaW50XSwgW1wiL2VudHJ5UG9pbnRcIl0pXG4gICAgd3JpdGVyLnN5bnRoZXRpYyhcIiAgfVxcblwiLCBcIkZsdXR0ZXIgc2VtYW50aWMgZW50cnkgc2NhZmZvbGRcIiwgW21vZHVsZS5lbnRyeVBvaW50XSwgW1wiL2VudHJ5UG9pbnRcIl0pXG4gIH1cbiAgd3JpdGVyLnN5bnRoZXRpYyhcIn1cXG5cIiwgXCJGbHV0dGVyIHNlbWFudGljIG1vZHVsZSBuYW1lc3BhY2VcIiwgW21vZHVsZV0sIFtcIlwiXSlcbn1cblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBzaGFyZWQgc2VtYW50aWMgRGFydCBsaWJyYXJ5LlxuICogQHBhcmFtIHtSZXR1cm5UeXBlPHR5cGVvZiBwcmVmbGlnaHRGbHV0dGVyQXBwbGljYXRpb24+fSBwcmVwYXJlZCAtIFByZXBhcmVkIHByb2plY3QuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBEYXJ0IGxpYnJhcnkgc291cmNlLlxuICovXG5mdW5jdGlvbiByZW5kZXJTZW1hbnRpY0xpYnJhcnkocHJlcGFyZWQpIHtcbiAgY29uc3QgcGFydHMgPSBwcmVwYXJlZC5tb2R1bGVzLm1hcChtb2R1bGUgPT4gYHBhcnQgJyR7bW9kdWxlRmlsZU5hbWUoLyoqIEB0eXBlIHtzdHJpbmd9ICovIChSZWZsZWN0LmdldChtb2R1bGUsIFwiaWRcIikpKX0uZGFydCc7YCkuam9pbihcIlxcblwiKVxuXG4gIHJldHVybiBgJHtwYXJ0c31cXG5cXG4ke2RhcnRSdW50aW1lfSR7b3V0cHV0U2lua1J1bnRpbWV9YFxufVxuXG4vKipcbiAqIFJlbmRlcnMgZXhhY3QgRmx1dHRlciB0ZW1wbGF0ZSBpZGVudGl0eSBtZXRhZGF0YS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IE1ldGFkYXRhIFlBTUwuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlck1ldGFkYXRhKCkge1xuICByZXR1cm4gYCMgVGhpcyBmaWxlIHRyYWNrcyBwcm9wZXJ0aWVzIG9mIHRoaXMgU2VtYW50aWZvbGQtb3duZWQgRmx1dHRlciBwcm9qZWN0LlxudmVyc2lvbjpcbiAgcmV2aXNpb246ICR7Zmx1dHRlclRvb2xjaGFpbi5yZXZpc2lvbn1cbiAgY2hhbm5lbDogc3RhYmxlXG5wcm9qZWN0X3R5cGU6IGFwcFxuYFxufVxuXG4vKipcbiAqIFJlbmRlcnMgdGhlIGNsb3NlZCBhbmFseXplciBjb25maWd1cmF0aW9uLlxuICogQHJldHVybnMge3N0cmluZ30gQW5hbHl6ZXIgWUFNTC5cbiAqL1xuZnVuY3Rpb24gcmVuZGVyQW5hbHlzaXNPcHRpb25zKCkge1xuICByZXR1cm4gYGFuYWx5emVyOlxuICBsYW5ndWFnZTpcbiAgICBzdHJpY3QtY2FzdHM6IHRydWVcbiAgICBzdHJpY3QtcmF3LXR5cGVzOiB0cnVlXG5gXG59XG5cbi8qKlxuICogUmVuZGVycyB0aGUgU0RLLW9ubHkgcGFja2FnZSBtYW5pZmVzdC5cbiAqIEBwYXJhbSB7UmV0dXJuVHlwZTx0eXBlb2YgcHJlZmxpZ2h0Rmx1dHRlckFwcGxpY2F0aW9uPn0gcHJlcGFyZWQgLSBQcmVwYXJlZCBwcm9qZWN0LlxuICogQHBhcmFtIHtDb25maWd1cmF0aW9uU3BhbltdfSBzcGFucyAtIENvbmZpZ3VyYXRpb24gcHJvdmVuYW5jZSBzaW5rLlxuICogQHJldHVybnMge3N0cmluZ30gUHVic3BlYyBZQU1MLlxuICovXG5mdW5jdGlvbiByZW5kZXJQdWJzcGVjKHByZXBhcmVkLCBzcGFucykge1xuICBjb25zdCBjb25maWd1cmF0aW9uID0gcHJlcGFyZWQuY29uZmlndXJhdGlvblxuICBjb25zdCBhc3NldExpbmVzID0gcHJlcGFyZWQuYXNzZXRzLmxlbmd0aCA9PSAwID8gXCJcIiA6IGBcXG4gIGFzc2V0czpcXG4ke3ByZXBhcmVkLmFzc2V0cy5tYXAoKHtwYXRofSkgPT4gYCAgICAtICR7cGF0aH1gKS5qb2luKFwiXFxuXCIpfVxcbmBcblxuICByZXR1cm4gY29uZmlndXJlZChgJHtwcm9qZWN0Um9vdH0vcHVic3BlYy55YW1sYCwgc3BhbnMsIFtcbiAgICBcIm5hbWU6IFwiLCBmaWVsZChcInBhY2thZ2VOYW1lXCIsIGNvbmZpZ3VyYXRpb24ucGFja2FnZU5hbWUpLCBcIlxcbnB1Ymxpc2hfdG86IG5vbmVcXG52ZXJzaW9uOiBcIixcbiAgICBmaWVsZChcInZlcnNpb25OYW1lXCIsIGNvbmZpZ3VyYXRpb24udmVyc2lvbk5hbWUpLCBcIitcIiwgZmllbGQoXCJ2ZXJzaW9uQ29kZVwiLCBTdHJpbmcoY29uZmlndXJhdGlvbi52ZXJzaW9uQ29kZSkpLFxuICAgIFwiXFxuZW52aXJvbm1lbnQ6XFxuICBzZGs6IDMuMTMuM1xcbiAgZmx1dHRlcjogMy40Ny40XFxuZGVwZW5kZW5jaWVzOlxcbiAgZmx1dHRlcjpcXG4gICAgc2RrOiBmbHV0dGVyXFxuZGV2X2RlcGVuZGVuY2llczpcXG4gIGZsdXR0ZXJfdGVzdDpcXG4gICAgc2RrOiBmbHV0dGVyXFxuZmx1dHRlcjpcXG4gIHVzZXMtbWF0ZXJpYWwtZGVzaWduOiB0cnVlXFxuXCIsXG4gICAgYXNzZXRMaW5lc1xuICBdKVxufVxuXG4vKipcbiAqIFJlbmRlcnMgdGhlIGV4YWN0IEZsdXR0ZXIgU0RLIGRlcGVuZGVuY3kgbG9jay5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IFB1YiBsb2NrIFlBTUwuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlclB1YnNwZWNMb2NrKCkge1xuICBjb25zdCBob3N0ZWQgPSBuZXcgTWFwKGZsdXR0ZXJMb2NrZWRIb3N0ZWRQYWNrYWdlcy5tYXAocGFja2FnZV8gPT4gW3BhY2thZ2VfWzBdLCBwYWNrYWdlX10pKVxuICBjb25zdCBzZGsgPSBuZXcgTWFwKGZsdXR0ZXJMb2NrZWRTZGtQYWNrYWdlcylcbiAgY29uc3QgcGFja2FnZU5hbWVzID0gWy4uLmhvc3RlZC5rZXlzKCksIC4uLnNkay5rZXlzKCldLnNvcnQoKVxuICBjb25zdCBwYWNrYWdlcyA9IHBhY2thZ2VOYW1lcy5tYXAobmFtZSA9PiB7XG4gICAgY29uc3Qgc2RrRGVwZW5kZW5jeSA9IHNkay5nZXQobmFtZSlcblxuICAgIGlmIChzZGtEZXBlbmRlbmN5KSByZXR1cm4gYCAgJHtuYW1lfTpcbiAgICBkZXBlbmRlbmN5OiAke3Nka0RlcGVuZGVuY3kgPT0gXCJ0cmFuc2l0aXZlXCIgPyBzZGtEZXBlbmRlbmN5IDogYFwiJHtzZGtEZXBlbmRlbmN5fVwiYH1cbiAgICBkZXNjcmlwdGlvbjogZmx1dHRlclxuICAgIHNvdXJjZTogc2RrXG4gICAgdmVyc2lvbjogXCIwLjAuMFwiYFxuICAgIGNvbnN0IGxvY2tlZCA9IGhvc3RlZC5nZXQobmFtZSlcblxuICAgIGlmICghbG9ja2VkKSB0aHJvdyBuZXcgVHlwZUVycm9yKGBNaXNzaW5nIHZhbGlkYXRlZCBGbHV0dGVyIGxvY2sgZW50cnkgJyR7bmFtZX0nLmApXG4gICAgY29uc3QgWywgdmVyc2lvbiwgc2hhMjU2XSA9IGxvY2tlZFxuICAgIGNvbnN0IHJlbmRlcmVkSGFzaCA9IC9eWzAtOV0vdS50ZXN0KHNoYTI1NikgPyBgXCIke3NoYTI1Nn1cImAgOiBzaGEyNTZcblxuICAgIHJldHVybiBgICAke25hbWV9OlxuICAgIGRlcGVuZGVuY3k6IHRyYW5zaXRpdmVcbiAgICBkZXNjcmlwdGlvbjpcbiAgICAgIG5hbWU6ICR7bmFtZX1cbiAgICAgIHNoYTI1NjogJHtyZW5kZXJlZEhhc2h9XG4gICAgICB1cmw6IFwiaHR0cHM6Ly9wdWIuZGV2XCJcbiAgICBzb3VyY2U6IGhvc3RlZFxuICAgIHZlcnNpb246IFwiJHt2ZXJzaW9ufVwiYFxuICB9KS5qb2luKFwiXFxuXCIpXG5cbiAgcmV0dXJuIGAjIEdlbmVyYXRlZCBieSBwdWJcbiMgU2VlIGh0dHBzOi8vZGFydC5kZXYvdG9vbHMvcHViL2dsb3NzYXJ5I2xvY2tmaWxlXG5wYWNrYWdlczpcbiR7cGFja2FnZXN9XG5zZGtzOlxuICBkYXJ0OiBcIjMuMTMuM1wiXG4gIGZsdXR0ZXI6IFwiMy40Ny40XCJcbmBcbn1cblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBzeW50aGV0aWMgTWF0ZXJpYWwgd2lkZ2V0IHNoZWxsLlxuICogQHBhcmFtIHtSZXR1cm5UeXBlPHR5cGVvZiBwcmVmbGlnaHRGbHV0dGVyQXBwbGljYXRpb24+fSBwcmVwYXJlZCAtIFByZXBhcmVkIHByb2plY3QuXG4gKiBAcGFyYW0ge0NvbmZpZ3VyYXRpb25TcGFuW119IHNwYW5zIC0gQ29uZmlndXJhdGlvbiBwcm92ZW5hbmNlIHNpbmsuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBGbHV0dGVyIGVudHJ5IHNvdXJjZS5cbiAqL1xuZnVuY3Rpb24gcmVuZGVyV2lkZ2V0QXBwbGljYXRpb24ocHJlcGFyZWQsIHNwYW5zKSB7XG4gIGNvbnN0IGVudHJ5Q2xhc3MgPSBgU2VtYW50aWZvbGRNb2R1bGUke21vZHVsZU5hbWUocHJlcGFyZWQucHJvZ3JhbS5lbnRyeU1vZHVsZSl9YFxuXG4gIHJldHVybiBjb25maWd1cmVkKGAke3Byb2plY3RSb290fS9saWIvbWFpbi5kYXJ0YCwgc3BhbnMsIFtcbiAgICBgaW1wb3J0ICdwYWNrYWdlOmZsdXR0ZXIvbWF0ZXJpYWwuZGFydCc7XG5cbmltcG9ydCAnc3JjL3NlbWFudGljL3NlbWFudGlmb2xkLmRhcnQnO1xuXG52b2lkIG1haW4oKSB7XG4gIHJ1bkFwcChjb25zdCBTZW1hbnRpZm9sZEFwcGxpY2F0aW9uKCkpO1xufVxuXG5jbGFzcyBTZW1hbnRpZm9sZEFwcGxpY2F0aW9uIGV4dGVuZHMgU3RhdGVsZXNzV2lkZ2V0IHtcbiAgY29uc3QgU2VtYW50aWZvbGRBcHBsaWNhdGlvbih7c3VwZXIua2V5fSk7XG5cbiAgQG92ZXJyaWRlXG4gIFdpZGdldCBidWlsZChCdWlsZENvbnRleHQgY29udGV4dCkge1xuICAgIGZpbmFsIExpc3Q8U3RyaW5nPiBsaW5lcyA9ICR7ZW50cnlDbGFzc30uc2VtYW50aWZvbGRFbnRyeSgpO1xuXG4gICAgcmV0dXJuIE1hdGVyaWFsQXBwKFxuICAgICAgZGVidWdTaG93Q2hlY2tlZE1vZGVCYW5uZXI6IGZhbHNlLFxuICAgICAgdGl0bGU6ICdgLCBmaWVsZChcImRpc3BsYXlOYW1lXCIsIGRhcnRFc2NhcGUocHJlcGFyZWQuY29uZmlndXJhdGlvbi5kaXNwbGF5TmFtZSkpLCBgJyxcbiAgICAgIGhvbWU6IFNjYWZmb2xkKFxuICAgICAgICBib2R5OiBDZW50ZXIoXG4gICAgICAgICAgY2hpbGQ6IFNlbWFudGljcyhcbiAgICAgICAgICAgIGtleTogY29uc3QgS2V5KCdzZW1hbnRpZm9sZC1vdXRwdXQnKSxcbiAgICAgICAgICAgIGNvbnRhaW5lcjogdHJ1ZSxcbiAgICAgICAgICAgIGV4cGxpY2l0Q2hpbGROb2RlczogdHJ1ZSxcbiAgICAgICAgICAgIGxhYmVsOiAnc2VtYW50aWZvbGQtb3V0cHV0JyxcbiAgICAgICAgICAgIGNoaWxkOiBUZXh0KGxpbmVzLmpvaW4oJ1xcXFxuJykpLFxuICAgICAgICAgICksXG4gICAgICAgICksXG4gICAgICApLFxuICAgICk7XG4gIH1cbn1cbmBcbiAgXSlcbn1cblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBzZW1hbnRpYy1lbnRyeSBkZXRlcm1pbmlzbSB0ZXN0LlxuICogQHBhcmFtIHtSZXR1cm5UeXBlPHR5cGVvZiBwcmVmbGlnaHRGbHV0dGVyQXBwbGljYXRpb24+fSBwcmVwYXJlZCAtIFByZXBhcmVkIHByb2plY3QuXG4gKiBAcGFyYW0ge0NvbmZpZ3VyYXRpb25TcGFuW119IHNwYW5zIC0gQ29uZmlndXJhdGlvbiBwcm92ZW5hbmNlIHNpbmsuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBGbHV0dGVyIHRlc3Qgc291cmNlLlxuICovXG5mdW5jdGlvbiByZW5kZXJMb2dpY1Rlc3QocHJlcGFyZWQsIHNwYW5zKSB7XG4gIGNvbnN0IGVudHJ5Q2xhc3MgPSBgU2VtYW50aWZvbGRNb2R1bGUke21vZHVsZU5hbWUocHJlcGFyZWQucHJvZ3JhbS5lbnRyeU1vZHVsZSl9YFxuXG4gIHJldHVybiBjb25maWd1cmVkKGAke3Byb2plY3RSb290fS90ZXN0L3NlbWFudGljX2xvZ2ljX3Rlc3QuZGFydGAsIHNwYW5zLCBbXG4gICAgXCJpbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JztcXG5pbXBvcnQgJ3BhY2thZ2U6XCIsIGZpZWxkKFwicGFja2FnZU5hbWVcIiwgcHJlcGFyZWQuY29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZSksXG4gICAgYC9zcmMvc2VtYW50aWMvc2VtYW50aWZvbGQuZGFydCc7XG5cbnZvaWQgbWFpbigpIHtcbiAgdGVzdCgnc2VtYW50aWMgZW50cnkgaXMgZGV0ZXJtaW5pc3RpYyBhY3Jvc3MgZnJlc2ggcnVucycsICgpIHtcbiAgICBleHBlY3QoXG4gICAgICAke2VudHJ5Q2xhc3N9LnNlbWFudGlmb2xkRW50cnkoKSxcbiAgICAgICR7ZW50cnlDbGFzc30uc2VtYW50aWZvbGRFbnRyeSgpLFxuICAgICk7XG4gIH0pO1xufVxuYFxuICBdKVxufVxuXG4vKipcbiAqIFJlbmRlcnMgdGhlIGV4YWN0IGxhYmVsbGVkIHdpZGdldCB0ZXN0LlxuICogQHBhcmFtIHtSZXR1cm5UeXBlPHR5cGVvZiBwcmVmbGlnaHRGbHV0dGVyQXBwbGljYXRpb24+fSBwcmVwYXJlZCAtIFByZXBhcmVkIHByb2plY3QuXG4gKiBAcGFyYW0ge0NvbmZpZ3VyYXRpb25TcGFuW119IHNwYW5zIC0gQ29uZmlndXJhdGlvbiBwcm92ZW5hbmNlIHNpbmsuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBGbHV0dGVyIHdpZGdldCB0ZXN0IHNvdXJjZS5cbiAqL1xuZnVuY3Rpb24gcmVuZGVyV2lkZ2V0VGVzdChwcmVwYXJlZCwgc3BhbnMpIHtcbiAgY29uc3QgZW50cnlDbGFzcyA9IGBTZW1hbnRpZm9sZE1vZHVsZSR7bW9kdWxlTmFtZShwcmVwYXJlZC5wcm9ncmFtLmVudHJ5TW9kdWxlKX1gXG5cbiAgcmV0dXJuIGNvbmZpZ3VyZWQoYCR7cHJvamVjdFJvb3R9L3Rlc3Qvd2lkZ2V0X3Rlc3QuZGFydGAsIHNwYW5zLCBbXG4gICAgXCJpbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlci9tYXRlcmlhbC5kYXJ0JztcXG5pbXBvcnQgJ3BhY2thZ2U6Zmx1dHRlcl90ZXN0L2ZsdXR0ZXJfdGVzdC5kYXJ0JztcXG5pbXBvcnQgJ3BhY2thZ2U6XCIsXG4gICAgZmllbGQoXCJwYWNrYWdlTmFtZVwiLCBwcmVwYXJlZC5jb25maWd1cmF0aW9uLnBhY2thZ2VOYW1lKSwgYC9tYWluLmRhcnQnO1xuaW1wb3J0ICdwYWNrYWdlOmAsIGZpZWxkKFwicGFja2FnZU5hbWVcIiwgcHJlcGFyZWQuY29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZSksIGAvc3JjL3NlbWFudGljL3NlbWFudGlmb2xkLmRhcnQnO1xuXG52b2lkIG1haW4oKSB7XG4gIHRlc3RXaWRnZXRzKCdyZW5kZXJzIGV4YWN0IGxhYmVsbGVkIHNlbWFudGljIG91dHB1dCcsIChcbiAgICBXaWRnZXRUZXN0ZXIgdGVzdGVyLFxuICApIGFzeW5jIHtcbiAgICBmaW5hbCBTdHJpbmcgZXhwZWN0ZWQgPSAke2VudHJ5Q2xhc3N9LnNlbWFudGlmb2xkRW50cnkoKS5qb2luKCdcXFxcbicpO1xuXG4gICAgYXdhaXQgdGVzdGVyLnB1bXBXaWRnZXQoY29uc3QgU2VtYW50aWZvbGRBcHBsaWNhdGlvbigpKTtcbiAgICBmaW5hbCBGaW5kZXIgb3V0cHV0ID0gZmluZC5ieUtleShjb25zdCBLZXkoJ3NlbWFudGlmb2xkLW91dHB1dCcpKTtcblxuICAgIGV4cGVjdChvdXRwdXQsIGZpbmRzT25lV2lkZ2V0KTtcbiAgICBleHBlY3QoXG4gICAgICB0ZXN0ZXIud2lkZ2V0PFNlbWFudGljcz4ob3V0cHV0KS5wcm9wZXJ0aWVzLmxhYmVsLFxuICAgICAgJ3NlbWFudGlmb2xkLW91dHB1dCcsXG4gICAgKTtcbiAgICBleHBlY3QoXG4gICAgICBmaW5kLmRlc2NlbmRhbnQob2Y6IG91dHB1dCwgbWF0Y2hpbmc6IGZpbmQudGV4dChleHBlY3RlZCkpLFxuICAgICAgZmluZHNPbmVXaWRnZXQsXG4gICAgKTtcbiAgfSk7XG59XG5gXG4gIF0pXG59XG5cbi8qKlxuICogUmVuZGVycyB0aGUgc2hhcmVkIEFuZHJvaWQgcm9vdCBidWlsZC5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEdyYWRsZSBLb3RsaW4gc291cmNlLlxuICovXG5mdW5jdGlvbiByZW5kZXJBbmRyb2lkUm9vdEJ1aWxkKCkge1xuICByZXR1cm4gYGFsbHByb2plY3RzIHtcbiAgcmVwb3NpdG9yaWVzIHtcbiAgICBnb29nbGUoKVxuICAgIG1hdmVuQ2VudHJhbCgpXG4gIH1cbn1cblxudmFsIG5ld0J1aWxkRGlyOiBEaXJlY3RvcnkgPSByb290UHJvamVjdC5sYXlvdXQuYnVpbGREaXJlY3RvcnkuZGlyKFwiLi4vLi4vYnVpbGRcIikuZ2V0KClcbnJvb3RQcm9qZWN0LmxheW91dC5idWlsZERpcmVjdG9yeS52YWx1ZShuZXdCdWlsZERpcilcblxuc3VicHJvamVjdHMge1xuICBwcm9qZWN0LmxheW91dC5idWlsZERpcmVjdG9yeS52YWx1ZShuZXdCdWlsZERpci5kaXIocHJvamVjdC5uYW1lKSlcbiAgcHJvamVjdC5ldmFsdWF0aW9uRGVwZW5kc09uKFwiOmFwcFwiKVxufVxuXG50YXNrcy5yZWdpc3RlcjxEZWxldGU+KFwiY2xlYW5cIikge1xuICBkZWxldGUocm9vdFByb2plY3QubGF5b3V0LmJ1aWxkRGlyZWN0b3J5KVxufVxuYFxufVxuXG4vKipcbiAqIFJlbmRlcnMgRmx1dHRlciBwbHVnaW4gYW5kIEFuZHJvaWQgcGx1Z2luIG93bmVyc2hpcC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuRmx1dHRlckFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbn0gY29uZmlndXJhdGlvbiAtIE5vcm1hbGl6ZWQgY29uZmlndXJhdGlvbi5cbiAqIEBwYXJhbSB7Q29uZmlndXJhdGlvblNwYW5bXX0gc3BhbnMgLSBDb25maWd1cmF0aW9uIHByb3ZlbmFuY2Ugc2luay5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEdyYWRsZSBzZXR0aW5ncyBzb3VyY2UuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlckFuZHJvaWRTZXR0aW5ncyhjb25maWd1cmF0aW9uLCBzcGFucykge1xuICByZXR1cm4gY29uZmlndXJlZChgJHtwcm9qZWN0Um9vdH0vYW5kcm9pZC9zZXR0aW5ncy5ncmFkbGUua3RzYCwgc3BhbnMsIFtgcGx1Z2luTWFuYWdlbWVudCB7XG4gIHZhbCBmbHV0dGVyU2RrUGF0aCA9IHJ1biB7XG4gICAgdmFsIHByb3BlcnRpZXMgPSBqYXZhLnV0aWwuUHJvcGVydGllcygpXG4gICAgZmlsZShcImxvY2FsLnByb3BlcnRpZXNcIikuaW5wdXRTdHJlYW0oKS51c2UgeyBwcm9wZXJ0aWVzLmxvYWQoaXQpIH1cbiAgICByZXF1aXJlTm90TnVsbChwcm9wZXJ0aWVzLmdldFByb3BlcnR5KFwiZmx1dHRlci5zZGtcIikpIHsgXCJmbHV0dGVyLnNkayBub3Qgc2V0IGluIGxvY2FsLnByb3BlcnRpZXNcIiB9XG4gIH1cblxuICBpbmNsdWRlQnVpbGQoXCIkZmx1dHRlclNka1BhdGgvcGFja2FnZXMvZmx1dHRlcl90b29scy9ncmFkbGVcIilcblxuICByZXBvc2l0b3JpZXMge1xuICAgIGdvb2dsZSgpXG4gICAgbWF2ZW5DZW50cmFsKClcbiAgICBncmFkbGVQbHVnaW5Qb3J0YWwoKVxuICB9XG59XG5cbnBsdWdpbnMge1xuICBpZChcImRldi5mbHV0dGVyLmZsdXR0ZXItcGx1Z2luLWxvYWRlclwiKSB2ZXJzaW9uIFwiMS4wLjBcIlxuICBpZChcImNvbS5hbmRyb2lkLmFwcGxpY2F0aW9uXCIpIHZlcnNpb24gXCIke2FuZHJvaWRUb29sY2hhaW4uYW5kcm9pZEdyYWRsZVBsdWdpbn1cIiBhcHBseSBmYWxzZVxuICBpZChcIm9yZy5qZXRicmFpbnMua290bGluLmFuZHJvaWRcIikgdmVyc2lvbiBcIiR7YW5kcm9pZFRvb2xjaGFpbi5rb3RsaW5HcmFkbGVQbHVnaW59XCIgYXBwbHkgZmFsc2Vcbn1cblxucm9vdFByb2plY3QubmFtZSA9IFwiYCwgZmllbGQoXCJwYWNrYWdlTmFtZVwiLCBjb25maWd1cmF0aW9uLnBhY2thZ2VOYW1lKSwgYFwiXG5pbmNsdWRlKFwiOmFwcFwiKVxuYF0pXG59XG5cbi8qKlxuICogUmVuZGVycyBkZXRlcm1pbmlzdGljIEFuZHJvaWQgR3JhZGxlIHByb3BlcnRpZXMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBHcmFkbGUgcHJvcGVydGllcy5cbiAqL1xuZnVuY3Rpb24gcmVuZGVyQW5kcm9pZEdyYWRsZVByb3BlcnRpZXMoKSB7XG4gIHJldHVybiBgYW5kcm9pZC5idWlsdEluS290bGluPWZhbHNlXG5hbmRyb2lkLm5ld0RzbD1mYWxzZVxuYW5kcm9pZC51c2VBbmRyb2lkWD10cnVlXG5rb3RsaW4uc3RkbGliLmRlZmF1bHQuZGVwZW5kZW5jeT1mYWxzZVxub3JnLmdyYWRsZS5jYWNoaW5nPWZhbHNlXG5vcmcuZ3JhZGxlLmNvbmZpZ3VyYXRpb24tY2FjaGU9ZmFsc2Vcbm9yZy5ncmFkbGUuZGFlbW9uPWZhbHNlXG5vcmcuZ3JhZGxlLmp2bWFyZ3M9LVhteDIwNDhtIC1EZmlsZS5lbmNvZGluZz1VVEYtOCAtRHVzZXIubGFuZ3VhZ2U9ZW4gLUR1c2VyLmNvdW50cnk9VVMgLUR1c2VyLnRpbWV6b25lPVVUQ1xub3JnLmdyYWRsZS5wYXJhbGxlbD1mYWxzZVxuYFxufVxuXG4vKipcbiAqIFJlbmRlcnMgdGhlIEZsdXR0ZXIgQW5kcm9pZCBhcHBsaWNhdGlvbiBidWlsZC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuRmx1dHRlckFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbn0gY29uZmlndXJhdGlvbiAtIE5vcm1hbGl6ZWQgY29uZmlndXJhdGlvbi5cbiAqIEBwYXJhbSB7Q29uZmlndXJhdGlvblNwYW5bXX0gc3BhbnMgLSBDb25maWd1cmF0aW9uIHByb3ZlbmFuY2Ugc2luay5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEFwcGxpY2F0aW9uIEdyYWRsZSBzb3VyY2UuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlckFuZHJvaWRBcHBCdWlsZChjb25maWd1cmF0aW9uLCBzcGFucykge1xuICByZXR1cm4gY29uZmlndXJlZChgJHtwcm9qZWN0Um9vdH0vYW5kcm9pZC9hcHAvYnVpbGQuZ3JhZGxlLmt0c2AsIHNwYW5zLCBbYHBsdWdpbnMge1xuICBpZChcImNvbS5hbmRyb2lkLmFwcGxpY2F0aW9uXCIpXG4gIGlkKFwib3JnLmpldGJyYWlucy5rb3RsaW4uYW5kcm9pZFwiKVxuICBpZChcImRldi5mbHV0dGVyLmZsdXR0ZXItZ3JhZGxlLXBsdWdpblwiKVxufVxuXG52YWwgc2VtYW50aWZvbGRBY2NlcHRhbmNlUm9vdCA9IHByb3ZpZGVycy5lbnZpcm9ubWVudFZhcmlhYmxlKFwiU0VNQU5USUZPTERfRkxVVFRFUl9BQ0NFUFRBTkNFX1JPT1RcIikub3JOdWxsXG4gID86IHRocm93IEdyYWRsZUV4Y2VwdGlvbihcIlNFTUFOVElGT0xEX0ZMVVRURVJfSU5GUkFTVFJVQ1RVUkU6IFNFTUFOVElGT0xEX0ZMVVRURVJfQUNDRVBUQU5DRV9ST09UIGlzIHJlcXVpcmVkXCIpXG52YWwgc2VtYW50aWZvbGREZWJ1Z0tleXN0b3JlID0gZmlsZShcIiRzZW1hbnRpZm9sZEFjY2VwdGFuY2VSb290L2RlYnVnLmtleXN0b3JlXCIpXG5pZiAoIXNlbWFudGlmb2xkRGVidWdLZXlzdG9yZS5pc0ZpbGUpIHtcbiAgdGhyb3cgR3JhZGxlRXhjZXB0aW9uKFwiU0VNQU5USUZPTERfRkxVVFRFUl9JTkZSQVNUUlVDVFVSRTogZXBoZW1lcmFsIGRlYnVnIGtleXN0b3JlIGlzIG1pc3NpbmdcIilcbn1cblxuY29uZmlndXJhdGlvbnMuY29uZmlndXJlRWFjaCB7XG4gIGV4Y2x1ZGUoZ3JvdXAgPSBcImFuZHJvaWR4LnByb2ZpbGVpbnN0YWxsZXJcIiwgbW9kdWxlID0gXCJwcm9maWxlaW5zdGFsbGVyXCIpXG59XG5cbmFuZHJvaWQge1xuICBuYW1lc3BhY2UgPSBcImAsIGZpZWxkKFwiYXBwbGljYXRpb25JZFwiLCBjb25maWd1cmF0aW9uLmFwcGxpY2F0aW9uSWQpLCBgXCJcbiAgY29tcGlsZVNkayA9IGAsIGZpZWxkKFwiY29tcGlsZVNka1wiLCBTdHJpbmcoY29uZmlndXJhdGlvbi5jb21waWxlU2RrKSksIGBcbiAgYnVpbGRUb29sc1ZlcnNpb24gPSBcImAsIGZpZWxkKFwiYnVpbGRUb29sc1ZlcnNpb25cIiwgY29uZmlndXJhdGlvbi5idWlsZFRvb2xzVmVyc2lvbiksIGBcIlxuICBuZGtWZXJzaW9uID0gXCIke2FuZHJvaWRUb29sY2hhaW4ubmRrfVwiXG5cbiAgZGVmYXVsdENvbmZpZyB7XG4gICAgYXBwbGljYXRpb25JZCA9IFwiYCwgZmllbGQoXCJhcHBsaWNhdGlvbklkXCIsIGNvbmZpZ3VyYXRpb24uYXBwbGljYXRpb25JZCksIGBcIlxuICAgIG1pblNkayA9IGAsIGZpZWxkKFwibWluaW11bVNka1wiLCBTdHJpbmcoY29uZmlndXJhdGlvbi5taW5pbXVtU2RrKSksIGBcbiAgICB0YXJnZXRTZGsgPSBgLCBmaWVsZChcInRhcmdldFNka1wiLCBTdHJpbmcoY29uZmlndXJhdGlvbi50YXJnZXRTZGspKSwgYFxuICAgIHZlcnNpb25Db2RlID0gYCwgZmllbGQoXCJ2ZXJzaW9uQ29kZVwiLCBTdHJpbmcoY29uZmlndXJhdGlvbi52ZXJzaW9uQ29kZSkpLCBgXG4gICAgdmVyc2lvbk5hbWUgPSBcImAsIGZpZWxkKFwidmVyc2lvbk5hbWVcIiwgY29uZmlndXJhdGlvbi52ZXJzaW9uTmFtZSksIGBcIlxuICB9XG5cbiAgc2lnbmluZ0NvbmZpZ3Mge1xuICAgIGdldEJ5TmFtZShcImRlYnVnXCIpIHtcbiAgICAgIHN0b3JlRmlsZSA9IHNlbWFudGlmb2xkRGVidWdLZXlzdG9yZVxuICAgICAgc3RvcmVQYXNzd29yZCA9IFwiYW5kcm9pZFwiXG4gICAgICBrZXlBbGlhcyA9IFwiYW5kcm9pZGRlYnVna2V5XCJcbiAgICAgIGtleVBhc3N3b3JkID0gXCJhbmRyb2lkXCJcbiAgICB9XG4gIH1cblxuICBidWlsZFR5cGVzIHtcbiAgICBnZXRCeU5hbWUoXCJkZWJ1Z1wiKSB7XG4gICAgICBzaWduaW5nQ29uZmlnID0gc2lnbmluZ0NvbmZpZ3MuZ2V0QnlOYW1lKFwiZGVidWdcIilcbiAgICB9XG4gIH1cblxuICBidWlsZEZlYXR1cmVzIHtcbiAgICBidWlsZENvbmZpZyA9IGZhbHNlXG4gIH1cblxuICBjb21waWxlT3B0aW9ucyB7XG4gICAgc291cmNlQ29tcGF0aWJpbGl0eSA9IEphdmFWZXJzaW9uLlZFUlNJT05fMTdcbiAgICB0YXJnZXRDb21wYXRpYmlsaXR5ID0gSmF2YVZlcnNpb24uVkVSU0lPTl8xN1xuICB9XG5cbiAgbGludCB7XG4gICAgYWJvcnRPbkVycm9yID0gdHJ1ZVxuICAgIGNoZWNrRGVwZW5kZW5jaWVzID0gdHJ1ZVxuICAgIGRpc2FibGUgKz0gXCJNaXNzaW5nQXBwbGljYXRpb25JY29uXCJcbiAgICBkaXNhYmxlICs9IFwiT2xkVGFyZ2V0QXBpXCJcbiAgICBkaXNhYmxlICs9IFwiR3JhZGxlRGVwZW5kZW5jeVwiXG4gICAgd2FybmluZ3NBc0Vycm9ycyA9IHRydWVcbiAgfVxufVxuXG5mbHV0dGVyIHtcbiAgc291cmNlID0gXCIuLi8uLlwiXG59XG5gXSlcbn1cblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBwZXJtaXNzaW9uLWZyZWUgQW5kcm9pZCBtYW5pZmVzdC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuRmx1dHRlckFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbn0gY29uZmlndXJhdGlvbiAtIE5vcm1hbGl6ZWQgY29uZmlndXJhdGlvbi5cbiAqIEBwYXJhbSB7Q29uZmlndXJhdGlvblNwYW5bXX0gc3BhbnMgLSBDb25maWd1cmF0aW9uIHByb3ZlbmFuY2Ugc2luay5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEFuZHJvaWQgbWFuaWZlc3QgWE1MLlxuICovXG5mdW5jdGlvbiByZW5kZXJBbmRyb2lkTWFuaWZlc3QoY29uZmlndXJhdGlvbiwgc3BhbnMpIHtcbiAgcmV0dXJuIGNvbmZpZ3VyZWQoYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYXBwL3NyYy9tYWluL0FuZHJvaWRNYW5pZmVzdC54bWxgLCBzcGFucywgW1xuICAgIGA8bWFuaWZlc3RcbiAgeG1sbnM6YW5kcm9pZD1cImh0dHA6Ly9zY2hlbWFzLmFuZHJvaWQuY29tL2Fway9yZXMvYW5kcm9pZFwiXG4gIHhtbG5zOnRvb2xzPVwiaHR0cDovL3NjaGVtYXMuYW5kcm9pZC5jb20vdG9vbHNcIj5cbiAgPHBlcm1pc3Npb24gdG9vbHM6bm9kZT1cInJlbW92ZUFsbFwiIC8+XG4gIDx1c2VzLXBlcm1pc3Npb24gdG9vbHM6bm9kZT1cInJlbW92ZUFsbFwiIC8+XG4gIDxhcHBsaWNhdGlvblxuICAgIGFuZHJvaWQ6YWxsb3dCYWNrdXA9XCJmYWxzZVwiXG4gICAgYW5kcm9pZDpkYXRhRXh0cmFjdGlvblJ1bGVzPVwiQHhtbC9kYXRhX2V4dHJhY3Rpb25fcnVsZXNcIlxuICAgIGFuZHJvaWQ6ZnVsbEJhY2t1cENvbnRlbnQ9XCJAeG1sL2JhY2t1cF9ydWxlc1wiXG4gICAgYW5kcm9pZDpsYWJlbD1cImAsIGZpZWxkKFwiZGlzcGxheU5hbWVcIiwgeG1sRXNjYXBlKGNvbmZpZ3VyYXRpb24uZGlzcGxheU5hbWUpKSwgYFwiXG4gICAgYW5kcm9pZDpuYW1lPVwiXFwke2FwcGxpY2F0aW9uTmFtZX1cIlxuICAgIGFuZHJvaWQ6c3VwcG9ydHNSdGw9XCJ0cnVlXCI+XG4gICAgPGFjdGl2aXR5XG4gICAgICBhbmRyb2lkOm5hbWU9XCIuYCwgZmllbGQoXCJhY3Rpdml0eUNsYXNzTmFtZVwiLCBjb25maWd1cmF0aW9uLmFjdGl2aXR5Q2xhc3NOYW1lKSwgYFwiXG4gICAgICBhbmRyb2lkOmNvbmZpZ0NoYW5nZXM9XCJvcmllbnRhdGlvbnxrZXlib2FyZEhpZGRlbnxrZXlib2FyZHxzY3JlZW5TaXplfHNtYWxsZXN0U2NyZWVuU2l6ZXxsb2NhbGV8bGF5b3V0RGlyZWN0aW9ufGZvbnRTY2FsZXxzY3JlZW5MYXlvdXR8ZGVuc2l0eXx1aU1vZGVcIlxuICAgICAgYW5kcm9pZDpleHBvcnRlZD1cInRydWVcIlxuICAgICAgYW5kcm9pZDpoYXJkd2FyZUFjY2VsZXJhdGVkPVwidHJ1ZVwiXG4gICAgICBhbmRyb2lkOmxhdW5jaE1vZGU9XCJzaW5nbGVUb3BcIlxuICAgICAgYW5kcm9pZDp0YXNrQWZmaW5pdHk9XCJcIlxuICAgICAgYW5kcm9pZDp0aGVtZT1cIkBzdHlsZS9MYXVuY2hUaGVtZVwiXG4gICAgICBhbmRyb2lkOndpbmRvd1NvZnRJbnB1dE1vZGU9XCJhZGp1c3RSZXNpemVcIj5cbiAgICAgIDxtZXRhLWRhdGFcbiAgICAgICAgYW5kcm9pZDpuYW1lPVwiaW8uZmx1dHRlci5lbWJlZGRpbmcuYW5kcm9pZC5Ob3JtYWxUaGVtZVwiXG4gICAgICAgIGFuZHJvaWQ6cmVzb3VyY2U9XCJAc3R5bGUvTm9ybWFsVGhlbWVcIiAvPlxuICAgICAgPGludGVudC1maWx0ZXI+XG4gICAgICAgIDxhY3Rpb24gYW5kcm9pZDpuYW1lPVwiYW5kcm9pZC5pbnRlbnQuYWN0aW9uLk1BSU5cIiAvPlxuICAgICAgICA8Y2F0ZWdvcnkgYW5kcm9pZDpuYW1lPVwiYW5kcm9pZC5pbnRlbnQuY2F0ZWdvcnkuTEFVTkNIRVJcIiAvPlxuICAgICAgPC9pbnRlbnQtZmlsdGVyPlxuICAgIDwvYWN0aXZpdHk+XG4gICAgPG1ldGEtZGF0YSBhbmRyb2lkOm5hbWU9XCJmbHV0dGVyRW1iZWRkaW5nXCIgYW5kcm9pZDp2YWx1ZT1cIjJcIiAvPlxuICAgIDxwcm92aWRlciBhbmRyb2lkOm5hbWU9XCJhbmRyb2lkeC5zdGFydHVwLkluaXRpYWxpemF0aW9uUHJvdmlkZXJcIiB0b29sczpub2RlPVwicmVtb3ZlXCIgLz5cbiAgPC9hcHBsaWNhdGlvbj5cbjwvbWFuaWZlc3Q+XG5gXG4gIF0pXG59XG5cbi8qKlxuICogUmVuZGVycyB0aGUgSmF2YSBGbHV0dGVyIGFjdGl2aXR5IGxhdW5jaGVyLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5GbHV0dGVyQXBwbGljYXRpb25Db25maWd1cmF0aW9ufSBjb25maWd1cmF0aW9uIC0gTm9ybWFsaXplZCBjb25maWd1cmF0aW9uLlxuICogQHBhcmFtIHtDb25maWd1cmF0aW9uU3BhbltdfSBzcGFucyAtIENvbmZpZ3VyYXRpb24gcHJvdmVuYW5jZSBzaW5rLlxuICogQHJldHVybnMge3N0cmluZ30gSmF2YSBzb3VyY2UuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlckFuZHJvaWRBY3Rpdml0eShjb25maWd1cmF0aW9uLCBzcGFucykge1xuICByZXR1cm4gY29uZmlndXJlZChgJHtwcm9qZWN0Um9vdH0vYW5kcm9pZC9hcHAvc3JjL21haW4vamF2YS8ke2NvbmZpZ3VyYXRpb24uYXBwbGljYXRpb25JZC5yZXBsYWNlQWxsKFwiLlwiLCBcIi9cIil9LyR7Y29uZmlndXJhdGlvbi5hY3Rpdml0eUNsYXNzTmFtZX0uamF2YWAsIHNwYW5zLCBbXG4gICAgXCJwYWNrYWdlIFwiLCBmaWVsZChcImFwcGxpY2F0aW9uSWRcIiwgY29uZmlndXJhdGlvbi5hcHBsaWNhdGlvbklkKSwgYDtcblxuaW1wb3J0IGlvLmZsdXR0ZXIuZW1iZWRkaW5nLmFuZHJvaWQuRmx1dHRlckFjdGl2aXR5O1xuXG5wdWJsaWMgZmluYWwgY2xhc3MgYCwgZmllbGQoXCJhY3Rpdml0eUNsYXNzTmFtZVwiLCBjb25maWd1cmF0aW9uLmFjdGl2aXR5Q2xhc3NOYW1lKSwgYCBleHRlbmRzIEZsdXR0ZXJBY3Rpdml0eSB7XG59XG5gXG4gIF0pXG59XG5cbi8qKlxuICogUmVuZGVycyBwbGF0Zm9ybSBsYXVuY2ggYW5kIGhvc3Qgc3R5bGVzLlxuICogQHBhcmFtIHtib29sZWFufSBuaWdodCAtIFdoZXRoZXIgdG8gcmVuZGVyIHRoZSBuaWdodCB0aGVtZS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEFuZHJvaWQgcmVzb3VyY2UgWE1MLlxuICovXG5mdW5jdGlvbiByZW5kZXJBbmRyb2lkU3R5bGVzKG5pZ2h0KSB7XG4gIHJldHVybiBgPD94bWwgdmVyc2lvbj1cIjEuMFwiIGVuY29kaW5nPVwidXRmLThcIj8+XG48cmVzb3VyY2VzPlxuICA8c3R5bGUgbmFtZT1cIkxhdW5jaFRoZW1lXCIgcGFyZW50PVwiQGFuZHJvaWQ6c3R5bGUvVGhlbWUuJHtuaWdodCA/IFwiQmxhY2tcIiA6IFwiTGlnaHRcIn0uTm9UaXRsZUJhclwiPlxuICAgIDxpdGVtIG5hbWU9XCJhbmRyb2lkOndpbmRvd0JhY2tncm91bmRcIj5AZHJhd2FibGUvbGF1bmNoX2JhY2tncm91bmQ8L2l0ZW0+XG4gIDwvc3R5bGU+XG4gIDxzdHlsZSBuYW1lPVwiTm9ybWFsVGhlbWVcIiBwYXJlbnQ9XCJAYW5kcm9pZDpzdHlsZS9UaGVtZS4ke25pZ2h0ID8gXCJCbGFja1wiIDogXCJMaWdodFwifS5Ob1RpdGxlQmFyXCI+XG4gICAgPGl0ZW0gbmFtZT1cImFuZHJvaWQ6d2luZG93QmFja2dyb3VuZFwiPj9hbmRyb2lkOmNvbG9yQmFja2dyb3VuZDwvaXRlbT5cbiAgPC9zdHlsZT5cbjwvcmVzb3VyY2VzPlxuYFxufVxuXG4vKipcbiAqIFJlbmRlcnMgYSBwbGF0Zm9ybSBsYXVuY2ggYmFja2dyb3VuZC5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEFuZHJvaWQgcmVzb3VyY2UgWE1MLlxuICovXG5mdW5jdGlvbiByZW5kZXJMYXVuY2hCYWNrZ3JvdW5kKCkge1xuICByZXR1cm4gYDw/eG1sIHZlcnNpb249XCIxLjBcIiBlbmNvZGluZz1cInV0Zi04XCI/PlxuPGxheWVyLWxpc3QgeG1sbnM6YW5kcm9pZD1cImh0dHA6Ly9zY2hlbWFzLmFuZHJvaWQuY29tL2Fway9yZXMvYW5kcm9pZFwiPlxuICA8aXRlbSBhbmRyb2lkOmRyYXdhYmxlPVwiP2FuZHJvaWQ6Y29sb3JCYWNrZ3JvdW5kXCIgLz5cbjwvbGF5ZXItbGlzdD5cbmBcbn1cblxuLyoqXG4gKiBSZW5kZXJzIGNvbXBsZXRlIGxlZ2FjeSBiYWNrdXAgZXhjbHVzaW9ucy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEFuZHJvaWQgcmVzb3VyY2UgWE1MLlxuICovXG5mdW5jdGlvbiByZW5kZXJCYWNrdXBSdWxlcygpIHtcbiAgcmV0dXJuIGA8P3htbCB2ZXJzaW9uPVwiMS4wXCIgZW5jb2Rpbmc9XCJ1dGYtOFwiPz5cbjxmdWxsLWJhY2t1cC1jb250ZW50PlxuICA8ZXhjbHVkZSBkb21haW49XCJyb290XCIgcGF0aD1cIi5cIiAvPlxuICA8ZXhjbHVkZSBkb21haW49XCJmaWxlXCIgcGF0aD1cIi5cIiAvPlxuICA8ZXhjbHVkZSBkb21haW49XCJkYXRhYmFzZVwiIHBhdGg9XCIuXCIgLz5cbiAgPGV4Y2x1ZGUgZG9tYWluPVwic2hhcmVkcHJlZlwiIHBhdGg9XCIuXCIgLz5cbiAgPGV4Y2x1ZGUgZG9tYWluPVwiZXh0ZXJuYWxcIiBwYXRoPVwiLlwiIC8+XG4gIDxleGNsdWRlIGRvbWFpbj1cImRldmljZV9yb290XCIgcGF0aD1cIi5cIiAvPlxuICA8ZXhjbHVkZSBkb21haW49XCJkZXZpY2VfZmlsZVwiIHBhdGg9XCIuXCIgLz5cbiAgPGV4Y2x1ZGUgZG9tYWluPVwiZGV2aWNlX2RhdGFiYXNlXCIgcGF0aD1cIi5cIiAvPlxuICA8ZXhjbHVkZSBkb21haW49XCJkZXZpY2Vfc2hhcmVkcHJlZlwiIHBhdGg9XCIuXCIgLz5cbjwvZnVsbC1iYWNrdXAtY29udGVudD5cbmBcbn1cblxuLyoqXG4gKiBSZW5kZXJzIGNvbXBsZXRlIEFuZHJvaWQgMTIrIGJhY2t1cCBleGNsdXNpb25zLlxuICogQHJldHVybnMge3N0cmluZ30gQW5kcm9pZCByZXNvdXJjZSBYTUwuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlckRhdGFFeHRyYWN0aW9uUnVsZXMoKSB7XG4gIGNvbnN0IGV4Y2x1c2lvbnMgPSBbXCJyb290XCIsIFwiZmlsZVwiLCBcImRhdGFiYXNlXCIsIFwic2hhcmVkcHJlZlwiLCBcImV4dGVybmFsXCIsIFwiZGV2aWNlX3Jvb3RcIiwgXCJkZXZpY2VfZmlsZVwiLCBcImRldmljZV9kYXRhYmFzZVwiLCBcImRldmljZV9zaGFyZWRwcmVmXCJdXG4gICAgLm1hcChkb21haW4gPT4gYCAgICA8ZXhjbHVkZSBkb21haW49XCIke2RvbWFpbn1cIiBwYXRoPVwiLlwiIC8+YCkuam9pbihcIlxcblwiKVxuXG4gIHJldHVybiBgPD94bWwgdmVyc2lvbj1cIjEuMFwiIGVuY29kaW5nPVwidXRmLThcIj8+XG48ZGF0YS1leHRyYWN0aW9uLXJ1bGVzPlxuICA8Y2xvdWQtYmFja3VwPlxuJHtleGNsdXNpb25zfVxuICA8L2Nsb3VkLWJhY2t1cD5cbiAgPGRldmljZS10cmFuc2Zlcj5cbiR7ZXhjbHVzaW9uc31cbiAgPC9kZXZpY2UtdHJhbnNmZXI+XG48L2RhdGEtZXh0cmFjdGlvbi1ydWxlcz5cbmBcbn1cblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBvd25lcnNoaXAsIHRvb2xjaGFpbiwgcHJvdmVuYW5jZSwgYW5kIHBsYXRmb3JtLXN0YXR1cyBtYW5pZmVzdC5cbiAqIEBwYXJhbSB7UmV0dXJuVHlwZTx0eXBlb2YgcHJlZmxpZ2h0Rmx1dHRlckFwcGxpY2F0aW9uPn0gcHJlcGFyZWQgLSBQcmVwYXJlZCBhcHBsaWNhdGlvbi5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuR2VuZXJhdGVkU2V0QXJ0aWZhY3RbXX0gYXJ0aWZhY3RzIC0gT3duZWQgYXJ0aWZhY3RzIGV4Y2VwdCB0aGlzIG1hbmlmZXN0LlxuICogQHBhcmFtIHtzdHJpbmd9IG1hbmlmZXN0UGF0aCAtIE1hbmlmZXN0IGFydGlmYWN0IHBhdGguXG4gKiBAcGFyYW0ge0NvbmZpZ3VyYXRpb25TcGFuW119IHNwYW5zIC0gQ29uZmlndXJhdGlvbiBwcm92ZW5hbmNlIHNwYW5zLlxuICogQHJldHVybnMge3N0cmluZ30gQ2Fub25pY2FsIG1hbmlmZXN0IEpTT04uXG4gKi9cbmZ1bmN0aW9uIHJlbmRlclByb2plY3RNYW5pZmVzdChwcmVwYXJlZCwgYXJ0aWZhY3RzLCBtYW5pZmVzdFBhdGgsIHNwYW5zKSB7XG4gIGNvbnN0IGlucHV0UGF0aHMgPSBuZXcgU2V0KHByZXBhcmVkLmFzc2V0cy5tYXAoKHtmdWxsUGF0aH0pID0+IGZ1bGxQYXRoKSlcbiAgY29uc3Qgc2VtYW50aWNBcnRpZmFjdHMgPSBhcnRpZmFjdHMuZmlsdGVyKGFydGlmYWN0ID0+IGFydGlmYWN0LnByb3ZlbmFuY2Uua2luZCA9PSBcInRleHRcIilcblxuICByZXR1cm4gc3RyaW5naWZ5Q2Fub25pY2FsSnNvbih7XG4gICAgY29uZmlndXJhdGlvbjogcHJlcGFyZWQuY29uZmlndXJhdGlvbixcbiAgICBnZW5lcmF0b3I6IHtuYW1lOiBcInNlbWFudGlmb2xkXCIsIHZlcnNpb246IGdlbmVyYXRvclZlcnNpb259LFxuICAgIG93bmVyc2hpcDoge1xuICAgICAgZXhjbHVkZWRQYXRoUGF0dGVybnMsXG4gICAgICBvd25lZFBhdGhzOiBbLi4uYXJ0aWZhY3RzLm1hcCgoe3BhdGh9KSA9PiBwYXRoKSwgbWFuaWZlc3RQYXRoXSxcbiAgICAgIG93bmVkUm9vdDogcHJvamVjdFJvb3QsXG4gICAgICBzaGEyNTY6IGFydGlmYWN0cy5tYXAoYXJ0aWZhY3QgPT4gKHtwYXRoOiBhcnRpZmFjdC5wYXRoLCBzaGEyNTY6IGhhc2hDb250ZW50KGFydGlmYWN0LmNvbnRlbnQpfSkpXG4gICAgfSxcbiAgICBwbGF0Zm9ybXM6IHtcbiAgICAgIGFuZHJvaWQ6IHthY2NlcHRhbmNlOiBcInRlbnNvcmJ1enota3ZtXCIsIGFydGlmYWN0czogXCJnZW5lcmF0ZWRcIn0sXG4gICAgICBpb3M6IHtcbiAgICAgICAgYWNjZXB0YW5jZTogXCJkZWZlcnJlZFwiLFxuICAgICAgICBhcnRpZmFjdHM6IFwib21pdHRlZFwiLFxuICAgICAgICByZWFzb246IFwiT3duZXIgZGlyZWN0aW9uIGRlZmVycyBtYWNPUywgWGNvZGUsIEFwcGxlIFNESywgc2lnbmluZywgYW5kIGlPUyBTaW11bGF0b3IgcXVhbGlmaWNhdGlvbi5cIlxuICAgICAgfVxuICAgIH0sXG4gICAgcHJvdmVuYW5jZToge1xuICAgICAgY29uZmlndXJhdGlvbjogT2JqZWN0LmtleXMocHJlcGFyZWQuY29uZmlndXJhdGlvbikuc29ydCgpLm1hcChmaWVsZE5hbWUgPT4gKHtcbiAgICAgICAgZmllbGQ6IGZpZWxkTmFtZSxcbiAgICAgICAgbWFuaWZlc3RQb2ludGVyOiBgL2NvbmZpZ3VyYXRpb24vJHtmaWVsZE5hbWV9YCxcbiAgICAgICAgb3V0cHV0czogY29uZmlndXJhdGlvbk91dHB1dHMoc3BhbnMsIGZpZWxkTmFtZSlcbiAgICAgIH0pKSxcbiAgICAgIGlucHV0czogcHJlcGFyZWQuYXNzZXRzLm1hcChhc3NldCA9PiAoe1xuICAgICAgICBjb250ZW50S2luZDogYXNzZXQuY29udGVudEtpbmQsXG4gICAgICAgIG1lZGlhVHlwZTogYXNzZXQubWVkaWFUeXBlLFxuICAgICAgICBwYXRoOiBhc3NldC5mdWxsUGF0aCxcbiAgICAgICAgc2hhMjU2OiBhc3NldC5zaGEyNTZcbiAgICAgIH0pKSxcbiAgICAgIHNlbWFudGljU291cmNlczogcHJlcGFyZWQuc291cmNlcy5tYXAoc291cmNlID0+ICh7XG4gICAgICAgIGFydGlmYWN0czogc2VtYW50aWNBcnRpZmFjdHMuZmlsdGVyKGFydGlmYWN0ID0+IGFydGlmYWN0LnByb3ZlbmFuY2Uua2luZCA9PSBcInRleHRcIiAmJlxuICAgICAgICAgIGFydGlmYWN0LnByb3ZlbmFuY2UubWFwcGluZy5zcGFucy5zb21lKCh7b3JpZ2lufSkgPT4gb3JpZ2luUmVmZXJlbmNlc0ZpbGVuYW1lKG9yaWdpbiwgc291cmNlLmZpbGVuYW1lKSkpXG4gICAgICAgICAgLm1hcCgoe3BhdGh9KSA9PiBwYXRoKSxcbiAgICAgICAgZmlsZW5hbWU6IHNvdXJjZS5maWxlbmFtZSxcbiAgICAgICAgLi4uKHNvdXJjZS5sYW5ndWFnZSA9PT0gdW5kZWZpbmVkID8ge30gOiB7bGFuZ3VhZ2U6IHNvdXJjZS5sYW5ndWFnZX0pLFxuICAgICAgICBzaGEyNTY6IGNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKHNvdXJjZS5jb250ZW50KS5kaWdlc3QoXCJoZXhcIilcbiAgICAgIH0pKSxcbiAgICAgIHN5bnRoZXRpY1NjYWZmb2xkaW5nOiBbLi4uYXJ0aWZhY3RzLmZpbHRlcihhcnRpZmFjdCA9PiBhcnRpZmFjdC5wcm92ZW5hbmNlLmtpbmQgPT0gXCJzeW50aGV0aWNcIiAmJlxuICAgICAgICAhaW5wdXRQYXRocy5oYXMoYXJ0aWZhY3QucGF0aCkpLm1hcCgoe3BhdGh9KSA9PiBwYXRoKSwgbWFuaWZlc3RQYXRoXVxuICAgIH0sXG4gICAgc2NoZW1hOiBcIlNlbWFudGlmb2xkRmx1dHRlclByb2plY3RcIixcbiAgICBzZW1hbnRpY1Byb2dyYW06IHNlbWFudGljUHJvZ3JhbU1hbmlmZXN0KHByZXBhcmVkKSxcbiAgICB0YXJnZXQ6IFwiZmx1dHRlclwiLFxuICAgIHRvb2xjaGFpbjoge2FuZHJvaWQ6IGFuZHJvaWRUb29sY2hhaW4sIGZsdXR0ZXI6IGZsdXR0ZXJUb29sY2hhaW59LFxuICAgIHZlcnNpb246IDFcbiAgfSlcbn1cblxuLyoqXG4gKiBEZXNjcmliZXMgdGhlIGNvbXBsZXRlIHNlbWFudGljIHByb2dyYW0gaW5zaWRlIHRoZSBhcHBsaWNhdGlvbiBtYW5pZmVzdC5cbiAqIEBwYXJhbSB7UmV0dXJuVHlwZTx0eXBlb2YgcHJlZmxpZ2h0Rmx1dHRlckFwcGxpY2F0aW9uPn0gcHJlcGFyZWQgLSBQcmVwYXJlZCBwcm9qZWN0LlxuICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsIHVua25vd24+fSBTZW1hbnRpYyBwcm9ncmFtIG1hbmlmZXN0LlxuICovXG5mdW5jdGlvbiBzZW1hbnRpY1Byb2dyYW1NYW5pZmVzdChwcmVwYXJlZCkge1xuICBjb25zdCBzb3VyY2VDb250ZW50ID0gbmV3IE1hcChwcmVwYXJlZC5zb3VyY2VzLm1hcChzb3VyY2UgPT4gW3NvdXJjZS5maWxlbmFtZSwgc291cmNlLmNvbnRlbnRdKSlcbiAgY29uc3Qgb3JkZXIgPSBuZXcgTWFwKHByZXBhcmVkLnByb2dyYW0ubW9kdWxlcy5tYXAoKG1vZHVsZSwgaW5kZXgpID0+IFttb2R1bGUuaWQsIGluZGV4XSkpXG4gIGNvbnN0IG1vZHVsZXMgPSBwcmVwYXJlZC5wcm9ncmFtLm1vZHVsZXMubWFwKG1vZHVsZSA9PiB7XG4gICAgY29uc3Qgc291cmNlID0gcHJlcGFyZWQucHJvZ3JhbS5zb3VyY2VzLmZpbmQoY2FuZGlkYXRlID0+IGNhbmRpZGF0ZS5maWxlbmFtZSA9PSBtb2R1bGUuc291cmNlRmlsZW5hbWUpXG4gICAgY29uc3QgY29udGVudCA9IHNvdXJjZUNvbnRlbnQuZ2V0KG1vZHVsZS5zb3VyY2VGaWxlbmFtZSlcblxuICAgIGlmICghc291cmNlIHx8IGNvbnRlbnQgPT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IFR5cGVFcnJvcihgUHJlZmxpZ2h0ZWQgRmx1dHRlciBtb2R1bGUgJyR7bW9kdWxlLmlkfScgbG9zdCBzb3VyY2Ugb3duZXJzaGlwLmApXG5cbiAgICByZXR1cm4ge1xuICAgICAgZGVwZW5kZW5jaWVzOiBbLi4ubmV3IFNldChtb2R1bGUuaW1wb3J0cy5tYXAoKHttb2R1bGVJZH0pID0+IG1vZHVsZUlkKSldXG4gICAgICAgIC5zb3J0KChsZWZ0LCByaWdodCkgPT4gLyoqIEB0eXBlIHtudW1iZXJ9ICovIChvcmRlci5nZXQobGVmdCkpIC0gLyoqIEB0eXBlIHtudW1iZXJ9ICovIChvcmRlci5nZXQocmlnaHQpKSksXG4gICAgICBnZW5lcmF0ZWRBcnRpZmFjdHM6IFtwcmVwYXJlZC5tb2R1bGVQYXRocy5nZXQobW9kdWxlLmlkKV0sXG4gICAgICBpZDogbW9kdWxlLmlkLFxuICAgICAgbmFtZXNwYWNlOiBgU2VtYW50aWZvbGRNb2R1bGUke21vZHVsZU5hbWUobW9kdWxlLmlkKX1gLFxuICAgICAgc291cmNlOiB7ZmlsZW5hbWU6IHNvdXJjZS5maWxlbmFtZSwgaWQ6IHNvdXJjZS5pZCwgc2hhMjU2OiBjcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShjb250ZW50KS5kaWdlc3QoXCJoZXhcIil9XG4gICAgfVxuICB9KVxuICBjb25zdCBlbnRyeUlkID0gcHJlcGFyZWQucHJvZ3JhbS5lbnRyeU1vZHVsZVxuXG4gIHJldHVybiB7XG4gICAgZW50cnk6IHtcbiAgICAgIGdlbmVyYXRlZEFydGlmYWN0OiBwcmVwYXJlZC5tb2R1bGVQYXRocy5nZXQoZW50cnlJZCksXG4gICAgICBnZW5lcmF0ZWRGdW5jdGlvbklkZW50aXR5OiBgU2VtYW50aWZvbGRNb2R1bGUke21vZHVsZU5hbWUoZW50cnlJZCl9LnNlbWFudGlmb2xkRW50cnlgLFxuICAgICAgbW9kdWxlSWQ6IGVudHJ5SWQsXG4gICAgICB3aWRnZXRBcnRpZmFjdDogYCR7cHJvamVjdFJvb3R9L2xpYi9tYWluLmRhcnRgXG4gICAgfSxcbiAgICBtb2R1bGVzLFxuICAgIHNjaGVtYTogXCJTZW1hbnRpZm9sZEZsdXR0ZXJTZW1hbnRpY1Byb2dyYW1cIixcbiAgICBzb3VyY2VzOiBwcmVwYXJlZC5wcm9ncmFtLnNvdXJjZXMubWFwKHNvdXJjZSA9PiAoe1xuICAgICAgZmlsZW5hbWU6IHNvdXJjZS5maWxlbmFtZSxcbiAgICAgIGlkOiBzb3VyY2UuaWQsXG4gICAgICBsYW5ndWFnZTogc291cmNlLmxhbmd1YWdlLFxuICAgICAgbW9kdWxlSWRzOiBtb2R1bGVzLmZpbHRlcihtb2R1bGUgPT4gbW9kdWxlLnNvdXJjZS5maWxlbmFtZSA9PSBzb3VyY2UuZmlsZW5hbWUpLm1hcCgoe2lkfSkgPT4gaWQpLFxuICAgICAgb3duZXJzaGlwOiBzb3VyY2Uub3duZXJzaGlwID8/IFwiYXBwbGljYXRpb25cIixcbiAgICAgIHNoYTI1NjogY3JlYXRlSGFzaChcInNoYTI1NlwiKS51cGRhdGUoLyoqIEB0eXBlIHtzdHJpbmd9ICovIChzb3VyY2VDb250ZW50LmdldChzb3VyY2UuZmlsZW5hbWUpKSkuZGlnZXN0KFwiaGV4XCIpXG4gICAgfSkpLFxuICAgIHZlcnNpb246IDFcbiAgfVxufVxuXG4vKipcbiAqIE5vcm1hbGl6ZXMgYW5kIHZhbGlkYXRlcyB0aGUgY2xvc2VkIGFwcGxpY2F0aW9uIGNvbmZpZ3VyYXRpb24uXG4gKiBAcGFyYW0ge3Vua25vd259IGNhbmRpZGF0ZSAtIENhbmRpZGF0ZSBjb25maWd1cmF0aW9uLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkZsdXR0ZXJBcHBsaWNhdGlvbkNvbmZpZ3VyYXRpb259IE5vcm1hbGl6ZWQgY29uZmlndXJhdGlvbi5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplQ29uZmlndXJhdGlvbihjYW5kaWRhdGUpIHtcbiAgaWYgKGNhbmRpZGF0ZSA9PT0gdW5kZWZpbmVkKSBjYW5kaWRhdGUgPSB7fVxuICBpZiAoIWlzUGxhaW5PYmplY3QoY2FuZGlkYXRlKSB8fCBPYmplY3Qua2V5cyhjYW5kaWRhdGUpLnNvbWUoa2V5ID0+ICFjb25maWd1cmF0aW9uRmllbGRzLmhhcyhrZXkpKSkge1xuICAgIGludmFsaWRDb25maWd1cmF0aW9uKFwiRmx1dHRlciBhcHBsaWNhdGlvbiBjb25maWd1cmF0aW9uIG11c3QgYmUgYSBjbG9zZWQgcGxhaW4gb2JqZWN0LlwiKVxuICB9XG4gIGNvbnN0IGNvbmZpZ3VyYXRpb24gPSAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkZsdXR0ZXJBcHBsaWNhdGlvbkNvbmZpZ3VyYXRpb25JbnB1dH0gKi8gKGNhbmRpZGF0ZSlcbiAgY29uc3QgcGFja2FnZU5hbWUgPSBjb25maWd1cmF0aW9uLnBhY2thZ2VOYW1lID8/IFwic2VtYW50aWZvbGRfZ2VuZXJhdGVkXCJcbiAgY29uc3Qgb3JnYW5pemF0aW9uID0gY29uZmlndXJhdGlvbi5vcmdhbml6YXRpb24gPz8gXCJkZXYuc2VtYW50aWZvbGRcIlxuICBjb25zdCBhcHBsaWNhdGlvbklkID0gY29uZmlndXJhdGlvbi5hcHBsaWNhdGlvbklkID8/IGAke29yZ2FuaXphdGlvbn0uZ2VuZXJhdGVkYFxuICBjb25zdCBhY3Rpdml0eUNsYXNzTmFtZSA9IGNvbmZpZ3VyYXRpb24uYWN0aXZpdHlDbGFzc05hbWUgPz8gXCJNYWluQWN0aXZpdHlcIlxuICBjb25zdCBkaXNwbGF5TmFtZSA9IGNvbmZpZ3VyYXRpb24uZGlzcGxheU5hbWUgPz8gXCJTZW1hbnRpZm9sZFwiXG4gIGNvbnN0IG1pbmltdW1TZGsgPSBjb25maWd1cmF0aW9uLm1pbmltdW1TZGsgPz8gMjNcbiAgY29uc3QgdGFyZ2V0U2RrID0gY29uZmlndXJhdGlvbi50YXJnZXRTZGsgPz8gMzVcbiAgY29uc3QgY29tcGlsZVNkayA9IGNvbmZpZ3VyYXRpb24uY29tcGlsZVNkayA/PyAzNVxuICBjb25zdCBidWlsZFRvb2xzVmVyc2lvbiA9IGNvbmZpZ3VyYXRpb24uYnVpbGRUb29sc1ZlcnNpb24gPz8gXCIzNS4wLjBcIlxuICBjb25zdCB2ZXJzaW9uQ29kZSA9IGNvbmZpZ3VyYXRpb24udmVyc2lvbkNvZGUgPz8gMVxuICBjb25zdCB2ZXJzaW9uTmFtZSA9IGNvbmZpZ3VyYXRpb24udmVyc2lvbk5hbWUgPz8gXCIxLjAuMFwiXG5cbiAgaWYgKHR5cGVvZiBwYWNrYWdlTmFtZSAhPSBcInN0cmluZ1wiIHx8ICEvXlthLXpdW2EtejAtOV9dKiQvdS50ZXN0KHBhY2thZ2VOYW1lKSB8fCBkYXJ0S2V5d29yZHMuaGFzKHBhY2thZ2VOYW1lKSB8fFxuICAgIGZvcmJpZGRlblBhY2thZ2VOYW1lcy5oYXMocGFja2FnZU5hbWUpKSBpbnZhbGlkQ29uZmlndXJhdGlvbihcIkRhcnQgcGFja2FnZSBuYW1lIG11c3QgYmUgYSBub24tcmVzZXJ2ZWQgbG93ZXJjYXNlIHVuZGVyc2NvcmUgaWRlbnRpZmllci5cIilcbiAgaWYgKHR5cGVvZiBvcmdhbml6YXRpb24gIT0gXCJzdHJpbmdcIiB8fCAhaXNSZXZlcnNlRG5zKG9yZ2FuaXphdGlvbiwgMikpIHtcbiAgICBpbnZhbGlkQ29uZmlndXJhdGlvbihcIk9yZ2FuaXphdGlvbiBtdXN0IGJlIGEgbG93ZXJjYXNlIHJldmVyc2UtRE5TIGlkZW50aXR5IHdpdGggYXQgbGVhc3QgdHdvIHNlZ21lbnRzLlwiKVxuICB9XG4gIGlmICh0eXBlb2YgYXBwbGljYXRpb25JZCAhPSBcInN0cmluZ1wiIHx8ICFpc1JldmVyc2VEbnMoYXBwbGljYXRpb25JZCwgMykgfHwgIWFwcGxpY2F0aW9uSWQuc3RhcnRzV2l0aChgJHtvcmdhbml6YXRpb259LmApKSB7XG4gICAgaW52YWxpZENvbmZpZ3VyYXRpb24oXCJBcHBsaWNhdGlvbiBJRCBtdXN0IGV4dGVuZCB0aGUgZXhhY3Qgb3JnYW5pemF0aW9uIGFzIGxvd2VyY2FzZSByZXZlcnNlIEROUy5cIilcbiAgfVxuICBpZiAodHlwZW9mIGFjdGl2aXR5Q2xhc3NOYW1lICE9IFwic3RyaW5nXCIgfHwgIS9eW0EtWl1bQS1aYS16MC05XSokL3UudGVzdChhY3Rpdml0eUNsYXNzTmFtZSkgfHxcbiAgICBqYXZhS2V5d29yZHMuaGFzKGFjdGl2aXR5Q2xhc3NOYW1lKSkgaW52YWxpZENvbmZpZ3VyYXRpb24oXCJBY3Rpdml0eSBjbGFzcyBuYW1lIG11c3QgYmUgYW4gQVNDSUkgdXBwZXItY2FtZWwgSmF2YSBpZGVudGlmaWVyLlwiKVxuICBpZiAoYW5kcm9pZFJ1bm5lckJhc2VDbGFzc05hbWVzLmhhcyhhY3Rpdml0eUNsYXNzTmFtZSkpIHtcbiAgICBpbnZhbGlkQ29uZmlndXJhdGlvbihcIkFjdGl2aXR5IGNsYXNzIG5hbWUgbXVzdCBub3QgY29sbGlkZSB3aXRoIHRoZSBpbXBvcnRlZCBGbHV0dGVyIGxhdW5jaGVyIGJhc2UgY2xhc3MuXCIpXG4gIH1cbiAgaWYgKHR5cGVvZiBkaXNwbGF5TmFtZSAhPSBcInN0cmluZ1wiIHx8IGRpc3BsYXlOYW1lLmxlbmd0aCA9PSAwIHx8IGRpc3BsYXlOYW1lLnRyaW0oKSAhPSBkaXNwbGF5TmFtZSB8fFxuICAgIFsuLi5kaXNwbGF5TmFtZV0ubGVuZ3RoID4gNjQgfHwgIWhhc09ubHlVbmljb2RlU2NhbGFycyhkaXNwbGF5TmFtZSkgfHwgL1tcXHB7Q2N9XFxwe1psfVxccHtacH1cXHVGRkZFXFx1RkZGRl0vdS50ZXN0KGRpc3BsYXlOYW1lKSkge1xuICAgIGludmFsaWRDb25maWd1cmF0aW9uKFwiRGlzcGxheSBuYW1lIG11c3QgYmUgYSBub24tZW1wdHkgc2luZ2xlLWxpbmUgVW5pY29kZSBzY2FsYXIgc3RyaW5nIG9mIGF0IG1vc3QgNjQgY2hhcmFjdGVycy5cIilcbiAgfVxuICBpZiAobWluaW11bVNkayAhPT0gMjMgfHwgdGFyZ2V0U2RrICE9PSAzNSB8fCBjb21waWxlU2RrICE9PSAzNSkge1xuICAgIGludmFsaWRDb25maWd1cmF0aW9uKFwiU0RLIGxldmVscyBtdXN0IHJldXNlIHRoZSBxdWFsaWZpZWQgbWluaW11bSAyMywgdGFyZ2V0IDM1LCBhbmQgY29tcGlsZSAzNSBBbmRyb2lkIG1hdHJpeC5cIilcbiAgfVxuICBpZiAoYnVpbGRUb29sc1ZlcnNpb24gIT0gXCIzNS4wLjBcIikgaW52YWxpZENvbmZpZ3VyYXRpb24oXCJCdWlsZCBUb29scyB2ZXJzaW9uIG11c3QgYmUgZXhhY3RseSAnMzUuMC4wJy5cIilcbiAgaWYgKCFOdW1iZXIuaXNTYWZlSW50ZWdlcih2ZXJzaW9uQ29kZSkgfHwgdmVyc2lvbkNvZGUgPCAxIHx8IHZlcnNpb25Db2RlID4gMl8xMDBfMDAwXzAwMCkge1xuICAgIGludmFsaWRDb25maWd1cmF0aW9uKFwiVmVyc2lvbiBjb2RlIG11c3QgYmUgYSBwb3NpdGl2ZSBBbmRyb2lkLXNhZmUgaW50ZWdlci5cIilcbiAgfVxuICBpZiAodHlwZW9mIHZlcnNpb25OYW1lICE9IFwic3RyaW5nXCIgfHwgIXNlbWFudGljVmVyc2lvblBhdHRlcm4udGVzdCh2ZXJzaW9uTmFtZSkgfHwgdmVyc2lvbk5hbWUuaW5jbHVkZXMoXCIrXCIpKSB7XG4gICAgaW52YWxpZENvbmZpZ3VyYXRpb24oXCJWZXJzaW9uIG5hbWUgbXVzdCBiZSBhIGNhbm9uaWNhbCBzZW1hbnRpYyB2ZXJzaW9uIHdpdGhvdXQgYnVpbGQgbWV0YWRhdGEuXCIpXG4gIH1cbiAgaWYgKGNvbmZpZ3VyYXRpb24ucGVybWlzc2lvbnMgIT09IHVuZGVmaW5lZCAmJlxuICAgICghaXNEZW5zZUFycmF5KGNvbmZpZ3VyYXRpb24ucGVybWlzc2lvbnMpIHx8IGNvbmZpZ3VyYXRpb24ucGVybWlzc2lvbnMubGVuZ3RoICE9IDApKSB7XG4gICAgaW52YWxpZENvbmZpZ3VyYXRpb24oXCJUaGUgYmFzZWxpbmUgRmx1dHRlciBwZXJtaXNzaW9uIHNldCBtdXN0IGJlIGVtcHR5LlwiKVxuICB9XG5cbiAgcmV0dXJuIHthY3Rpdml0eUNsYXNzTmFtZSwgYXBwbGljYXRpb25JZCwgYnVpbGRUb29sc1ZlcnNpb24sIGNvbXBpbGVTZGssIGRpc3BsYXlOYW1lLCBtaW5pbXVtU2RrLCBvcmdhbml6YXRpb24sXG4gICAgcGFja2FnZU5hbWUsIHRhcmdldFNkaywgdmVyc2lvbkNvZGUsIHZlcnNpb25OYW1lfVxufVxuXG4vKipcbiAqIFNuYXBzaG90cyBhbmQgdmFsaWRhdGVzIGV4YWN0IGNhbGxlciBhc3NldHMuXG4gKiBAcGFyYW0ge3Vua25vd259IGNhbmRpZGF0ZSAtIENhbmRpZGF0ZSBhc3NldCBjb2xsZWN0aW9uLlxuICogQHJldHVybnMge0ZsdXR0ZXJBc3NldFtdfSBOb3JtYWxpemVkIGFzc2V0cy5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplQXNzZXRzKGNhbmRpZGF0ZSkge1xuICBpZiAoY2FuZGlkYXRlID09PSB1bmRlZmluZWQpIHJldHVybiBbXVxuICBpZiAoIWlzRGVuc2VBcnJheShjYW5kaWRhdGUpKSBpbnZhbGlkQXNzZXQoXCJGbHV0dGVyIGFzc2V0cyBtdXN0IGJlIGEgZGVuc2UgYXJyYXkuXCIpXG4gIC8qKiBAdHlwZSB7Rmx1dHRlckFzc2V0W119ICovXG4gIGNvbnN0IGFzc2V0cyA9IFtdXG5cbiAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IGNhbmRpZGF0ZS5sZW5ndGg7IGluZGV4ICs9IDEpIHtcbiAgICBjb25zdCBpdGVtID0gY2FuZGlkYXRlW2luZGV4XVxuXG4gICAgaWYgKCFpc1BsYWluT2JqZWN0KGl0ZW0pIHx8IE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCAhPSBhc3NldEZpZWxkcy5zaXplIHx8XG4gICAgICBPYmplY3Qua2V5cyhpdGVtKS5zb21lKGtleSA9PiAhYXNzZXRGaWVsZHMuaGFzKGtleSkpKSBpbnZhbGlkQXNzZXQoYEFzc2V0ICR7aW5kZXh9IG11c3QgdXNlIHRoZSBjbG9zZWQgaW5wdXQgc2NoZW1hLmApXG4gICAgY29uc3QgcGF0aCA9IGl0ZW0ucGF0aFxuICAgIGNvbnN0IGNvbnRlbnQgPSBpdGVtLmNvbnRlbnRcbiAgICBjb25zdCBtZWRpYVR5cGUgPSBpdGVtLm1lZGlhVHlwZVxuICAgIGNvbnN0IHNoYTI1NiA9IGl0ZW0uc2hhMjU2XG5cbiAgICBpZiAoIWlzU2FmZUFydGlmYWN0UGF0aChwYXRoKSB8fCAhU3RyaW5nKHBhdGgpLnN0YXJ0c1dpdGgoXCJhc3NldHMvXCIpKSB7XG4gICAgICBpbnZhbGlkQXNzZXQoYEFzc2V0ICR7aW5kZXh9IHJlcXVpcmVzIGEgc2FmZSBwb3J0YWJsZSBwYXRoIGJlbG93ICdhc3NldHMnLmApXG4gICAgfVxuICAgIGlmICh0eXBlb2YgY29udGVudCAhPSBcInN0cmluZ1wiICYmICEoY29udGVudCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHx8IHR5cGVvZiBjb250ZW50ID09IFwic3RyaW5nXCIgJiZcbiAgICAgIChjb250ZW50Lmxlbmd0aCA9PSAwIHx8ICFoYXNPbmx5VW5pY29kZVNjYWxhcnMoY29udGVudCkpIHx8IGNvbnRlbnQgaW5zdGFuY2VvZiBVaW50OEFycmF5ICYmIGNvbnRlbnQuYnl0ZUxlbmd0aCA9PSAwKSB7XG4gICAgICBpbnZhbGlkQXNzZXQoYEFzc2V0ICcke3BhdGh9JyByZXF1aXJlcyBub24tZW1wdHkgZXhhY3QgY29udGVudC5gKVxuICAgIH1cbiAgICBpZiAodHlwZW9mIG1lZGlhVHlwZSAhPSBcInN0cmluZ1wiIHx8ICFtZWRpYVR5cGVQYXR0ZXJuLnRlc3QobWVkaWFUeXBlKSB8fCAvW1xcclxcbl0vdS50ZXN0KG1lZGlhVHlwZSkpIHtcbiAgICAgIGludmFsaWRBc3NldChgQXNzZXQgJyR7cGF0aH0nIHJlcXVpcmVzIGFuIGV4cGxpY2l0IHZhbGlkIG1lZGlhIHR5cGUuYClcbiAgICB9XG4gICAgY29uc3Qgc25hcHNob3QgPSB0eXBlb2YgY29udGVudCA9PSBcInN0cmluZ1wiID8gY29udGVudCA6IG5ldyBVaW50OEFycmF5KGNvbnRlbnQpXG4gICAgY29uc3QgYWN0dWFsSGFzaCA9IGNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKHNuYXBzaG90KS5kaWdlc3QoXCJoZXhcIilcblxuICAgIGlmICh0eXBlb2Ygc2hhMjU2ICE9IFwic3RyaW5nXCIgfHwgIS9eWzAtOWEtZl17NjR9JC91LnRlc3Qoc2hhMjU2KSB8fCBzaGEyNTYgIT0gYWN0dWFsSGFzaCkge1xuICAgICAgaW52YWxpZEFzc2V0KGBBc3NldCAnJHtwYXRofScgU0hBLTI1NiBkb2VzIG5vdCBtYXRjaCBpdHMgZXhhY3QgY29udGVudC5gKVxuICAgIH1cbiAgICBhc3NldHMucHVzaCh7Y29udGVudDogc25hcHNob3QsIGNvbnRlbnRLaW5kOiB0eXBlb2Ygc25hcHNob3QgPT0gXCJzdHJpbmdcIiA/IFwidGV4dFwiIDogXCJiaW5hcnlcIixcbiAgICAgIGZ1bGxQYXRoOiBgJHtwcm9qZWN0Um9vdH0vJHtwYXRofWAsIG1lZGlhVHlwZSwgcGF0aCwgc2hhMjU2fSlcbiAgfVxuICBhc3NldHMuc29ydCgobGVmdCwgcmlnaHQpID0+IGxlZnQuZnVsbFBhdGggPCByaWdodC5mdWxsUGF0aCA/IC0xIDogbGVmdC5mdWxsUGF0aCA+IHJpZ2h0LmZ1bGxQYXRoID8gMSA6IDApXG4gIGNvbnN0IGNvbmZsaWN0ID0gZmluZFBvcnRhYmxlQXJ0aWZhY3RQYXRoQ29uZmxpY3QoYXNzZXRzLm1hcCgoe2Z1bGxQYXRofSkgPT4gZnVsbFBhdGgpKVxuXG4gIGlmIChjb25mbGljdCkgaW52YWxpZEFzc2V0KGBBc3NldCBwYXRoICcke2NvbmZsaWN0LnBhdGh9JyBoYXMgYSAke2NvbmZsaWN0LmtpbmR9IGNvbmZsaWN0LmApXG5cbiAgcmV0dXJuIGFzc2V0c1xufVxuXG4vKipcbiAqIEVudW1lcmF0ZXMgZXZlcnkgZ2VuZXJhdG9yLW93bmVkIGFwcGxpY2F0aW9uIHBhdGguXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkZsdXR0ZXJBcHBsaWNhdGlvbkNvbmZpZ3VyYXRpb259IGNvbmZpZ3VyYXRpb24gLSBOb3JtYWxpemVkIGNvbmZpZ3VyYXRpb24uXG4gKiBAcGFyYW0ge01hcDxzdHJpbmcsIHN0cmluZz59IG1vZHVsZVBhdGhzIC0gU2VtYW50aWMgbW9kdWxlIHBhdGhzLlxuICogQHJldHVybnMge3N0cmluZ1tdfSBDb21wbGV0ZSBwYXRocy5cbiAqL1xuZnVuY3Rpb24gYXBwbGljYXRpb25QYXRocyhjb25maWd1cmF0aW9uLCBtb2R1bGVQYXRocykge1xuICBjb25zdCBwYWNrYWdlUGF0aCA9IGNvbmZpZ3VyYXRpb24uYXBwbGljYXRpb25JZC5yZXBsYWNlQWxsKFwiLlwiLCBcIi9cIilcblxuICByZXR1cm4gW1xuICAgIGAke3Byb2plY3RSb290fS8ubWV0YWRhdGFgLFxuICAgIGAke3Byb2plY3RSb290fS9hbmFseXNpc19vcHRpb25zLnlhbWxgLFxuICAgIGAke3Byb2plY3RSb290fS9hbmRyb2lkL2FwcC9idWlsZC5ncmFkbGUua3RzYCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vYW5kcm9pZC9hcHAvc3JjL21haW4vQW5kcm9pZE1hbmlmZXN0LnhtbGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYXBwL3NyYy9tYWluL2phdmEvJHtwYWNrYWdlUGF0aH0vJHtjb25maWd1cmF0aW9uLmFjdGl2aXR5Q2xhc3NOYW1lfS5qYXZhYCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vYW5kcm9pZC9hcHAvc3JjL21haW4vcmVzL2RyYXdhYmxlL2xhdW5jaF9iYWNrZ3JvdW5kLnhtbGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYXBwL3NyYy9tYWluL3Jlcy92YWx1ZXMtbmlnaHQvc3R5bGVzLnhtbGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYXBwL3NyYy9tYWluL3Jlcy92YWx1ZXMvc3R5bGVzLnhtbGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYXBwL3NyYy9tYWluL3Jlcy94bWwvYmFja3VwX3J1bGVzLnhtbGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYXBwL3NyYy9tYWluL3Jlcy94bWwvZGF0YV9leHRyYWN0aW9uX3J1bGVzLnhtbGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvYnVpbGQuZ3JhZGxlLmt0c2AsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FuZHJvaWQvZ3JhZGxlLnByb3BlcnRpZXNgLFxuICAgIGAke3Byb2plY3RSb290fS9hbmRyb2lkL3NldHRpbmdzLmdyYWRsZS5rdHNgLFxuICAgIGAke3Byb2plY3RSb290fS9saWIvbWFpbi5kYXJ0YCxcbiAgICAuLi5tb2R1bGVQYXRocy52YWx1ZXMoKSxcbiAgICBgJHtwcm9qZWN0Um9vdH0vbGliL3NyYy9zZW1hbnRpYy9zZW1hbnRpZm9sZC5kYXJ0YCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vcHVic3BlYy5sb2NrYCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vcHVic3BlYy55YW1sYCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vdGVzdC9zZW1hbnRpY19sb2dpY190ZXN0LmRhcnRgLFxuICAgIGAke3Byb2plY3RSb290fS90ZXN0L3dpZGdldF90ZXN0LmRhcnRgLFxuICAgIGAke3Byb2plY3RSb290fS9zZW1hbnRpZm9sZC1wcm9qZWN0Lmpzb25gXG4gIF1cbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBvbmUgbm9ybWFsaXplZCBhc3NldCB0byBhbiBvd25lZCBhcnRpZmFjdC5cbiAqIEBwYXJhbSB7Rmx1dHRlckFzc2V0fSBhc3NldCAtIE5vcm1hbGl6ZWQgYXNzZXQuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuR2VuZXJhdGVkU2V0QXJ0aWZhY3R9IEdlbmVyYXRlZCBhc3NldC5cbiAqL1xuZnVuY3Rpb24gYXNzZXRBcnRpZmFjdChhc3NldCkge1xuICBjb25zdCByZWFzb24gPSBgRXhhY3QgY2FsbGVyLXByb3ZpZGVkIEZsdXR0ZXIgYXNzZXQgKHNoYTI1Njoke2Fzc2V0LnNoYTI1Nn0pLmBcblxuICBpZiAodHlwZW9mIGFzc2V0LmNvbnRlbnQgPT0gXCJzdHJpbmdcIikgcmV0dXJuIHsuLi5zeW50aGV0aWNUZXh0KGFzc2V0LmZ1bGxQYXRoLCBcInJlc291cmNlXCIsIGFzc2V0LmNvbnRlbnQsIHJlYXNvbiksIG1lZGlhVHlwZTogYXNzZXQubWVkaWFUeXBlfVxuICBjb25zdCBjb250ZW50ID0gbmV3IFVpbnQ4QXJyYXkoYXNzZXQuY29udGVudClcblxuICByZXR1cm4ge1xuICAgIGNvbnRlbnQsXG4gICAgY29udGVudEtpbmQ6IFwiYmluYXJ5XCIsXG4gICAgbWVkaWFUeXBlOiBhc3NldC5tZWRpYVR5cGUsXG4gICAgb3duZXJzaGlwOiBcImdlbmVyYXRlZFwiLFxuICAgIHBhdGg6IGFzc2V0LmZ1bGxQYXRoLFxuICAgIHByb3ZlbmFuY2U6IHtraW5kOiBcImJ5dGVzXCIsIG1hcHBpbmc6IGNyZWF0ZUJ5dGVNYXBwaW5nKHtcbiAgICAgIGJ5dGVMZW5ndGg6IGNvbnRlbnQuYnl0ZUxlbmd0aCxcbiAgICAgIHBhdGg6IGFzc2V0LmZ1bGxQYXRoLFxuICAgICAgcmFuZ2VzOiBbe2dlbmVyYXRlZDoge2VuZDogY29udGVudC5ieXRlTGVuZ3RoLCBzdGFydDogMH0sXG4gICAgICAgIG9yaWdpbjoge2tpbmQ6IFwic3ludGhldGljXCIsIHJlYXNvbiwgcmVsYXRlZE9yaWdpbnM6IFtdfSwgcm9sZTogXCJhc3NldFwifV1cbiAgICB9KX0sXG4gICAgcm9sZTogXCJyZXNvdXJjZVwiXG4gIH1cbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgc3ludGhldGljIHRleHQgYXJ0aWZhY3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIEFydGlmYWN0IHBhdGguXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZEFydGlmYWN0Um9sZX0gcm9sZSAtIEFydGlmYWN0IHJvbGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gY29udGVudCAtIEV4YWN0IGNvbnRlbnQuXG4gKiBAcGFyYW0ge3N0cmluZ30gcmVhc29uIC0gU3ludGhldGljIHByb3ZlbmFuY2UgcmVhc29uLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZFNldEFydGlmYWN0fSBHZW5lcmF0ZWQgYXJ0aWZhY3QuXG4gKi9cbmZ1bmN0aW9uIHN5bnRoZXRpY1RleHQocGF0aCwgcm9sZSwgY29udGVudCwgcmVhc29uKSB7XG4gIHJldHVybiB7Y29udGVudCwgY29udGVudEtpbmQ6IFwidGV4dFwiLCBtZWRpYVR5cGU6IG1lZGlhVHlwZUZvcihwYXRoKSwgb3duZXJzaGlwOiBcImdlbmVyYXRlZFwiLCBwYXRoLFxuICAgIHByb3ZlbmFuY2U6IHtraW5kOiBcInN5bnRoZXRpY1wiLCByZWFzb24sIHJlbGF0ZWRPcmlnaW5zOiBbXX0sIHJvbGV9XG59XG5cbi8qKlxuICogQ3JlYXRlcyB0ZXh0IHdob3NlIGNvbmZpZ3VyYXRpb24gc3BhbnMgYXJlIHJlY29yZGVkIHNlcGFyYXRlbHkuXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIEFydGlmYWN0IHBhdGguXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZEFydGlmYWN0Um9sZX0gcm9sZSAtIEFydGlmYWN0IHJvbGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gY29udGVudCAtIEV4YWN0IGNvbnRlbnQuXG4gKiBAcGFyYW0ge3N0cmluZ30gcmVhc29uIC0gU3ludGhldGljIHByb3ZlbmFuY2UgcmVhc29uLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZFNldEFydGlmYWN0fSBHZW5lcmF0ZWQgYXJ0aWZhY3QuXG4gKi9cbmZ1bmN0aW9uIGNvbmZpZ3VyZWRUZXh0KHBhdGgsIHJvbGUsIGNvbnRlbnQsIHJlYXNvbikge1xuICByZXR1cm4gc3ludGhldGljVGV4dChwYXRoLCByb2xlLCBjb250ZW50LCByZWFzb24pXG59XG5cbi8qKlxuICogU2VsZWN0cyBhbiBleGFjdCBtZWRpYSB0eXBlIGZyb20gYW4gb3duZWQgcGF0aC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gQXJ0aWZhY3QgcGF0aC5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IE1lZGlhIHR5cGUuXG4gKi9cbmZ1bmN0aW9uIG1lZGlhVHlwZUZvcihwYXRoKSB7XG4gIGlmIChwYXRoLmVuZHNXaXRoKFwiLmRhcnRcIikpIHJldHVybiBcInRleHQveC1kYXJ0XCJcbiAgaWYgKHBhdGguZW5kc1dpdGgoXCIuanNvblwiKSkgcmV0dXJuIFwiYXBwbGljYXRpb24vanNvblwiXG4gIGlmIChwYXRoLmVuZHNXaXRoKFwiLnlhbWxcIikgfHwgcGF0aC5lbmRzV2l0aChcIi5sb2NrXCIpKSByZXR1cm4gXCJhcHBsaWNhdGlvbi95YW1sXCJcbiAgaWYgKHBhdGguZW5kc1dpdGgoXCIueG1sXCIpKSByZXR1cm4gXCJhcHBsaWNhdGlvbi94bWxcIlxuICBpZiAocGF0aC5lbmRzV2l0aChcIi5qYXZhXCIpKSByZXR1cm4gXCJ0ZXh0L3gtamF2YS1zb3VyY2VcIlxuICBpZiAocGF0aC5lbmRzV2l0aChcIi5rdHNcIikpIHJldHVybiBcInRleHQveC1rb3RsaW5cIlxuXG4gIHJldHVybiBcInRleHQvcGxhaW5cIlxufVxuXG4vKipcbiAqIE1hcmtzIG9uZSByZW5kZXJlZCB2YWx1ZSBhcyBjb25maWd1cmF0aW9uLWRlcml2ZWQuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmllbGROYW1lIC0gQ29uZmlndXJhdGlvbiBmaWVsZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFJlbmRlcmVkIHZhbHVlLlxuICogQHJldHVybnMge3tmaWVsZDogc3RyaW5nLCB2YWx1ZTogc3RyaW5nfX0gTWFya2VkIHZhbHVlLlxuICovXG5mdW5jdGlvbiBmaWVsZChmaWVsZE5hbWUsIHZhbHVlKSB7XG4gIHJldHVybiB7ZmllbGQ6IGZpZWxkTmFtZSwgdmFsdWV9XG59XG5cbi8qKlxuICogSm9pbnMgY29uZmlndXJlZCBwYXJ0cyB3aGlsZSByZWNvcmRpbmcgZXhhY3Qgb3V0cHV0IHNwYW5zLlxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBBcnRpZmFjdCBwYXRoLlxuICogQHBhcmFtIHtDb25maWd1cmF0aW9uU3BhbltdfSBzcGFucyAtIENvbmZpZ3VyYXRpb24gcHJvdmVuYW5jZSBzaW5rLlxuICogQHBhcmFtIHsoc3RyaW5nIHwge2ZpZWxkOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmd9KVtdfSBwYXJ0cyAtIExpdGVyYWwgYW5kIGNvbmZpZ3VyZWQgcGFydHMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBSZW5kZXJlZCBjb250ZW50LlxuICovXG5mdW5jdGlvbiBjb25maWd1cmVkKHBhdGgsIHNwYW5zLCBwYXJ0cykge1xuICBsZXQgY29udGVudCA9IFwiXCJcblxuICBmb3IgKGNvbnN0IHBhcnQgb2YgcGFydHMpIHtcbiAgICBpZiAodHlwZW9mIHBhcnQgPT0gXCJzdHJpbmdcIikgY29udGVudCArPSBwYXJ0XG4gICAgZWxzZSB7XG4gICAgICBjb25zdCBzdGFydCA9IGNvbnRlbnQubGVuZ3RoXG5cbiAgICAgIGNvbnRlbnQgKz0gcGFydC52YWx1ZVxuICAgICAgc3BhbnMucHVzaCh7ZW5kOiBjb250ZW50Lmxlbmd0aCwgZmllbGQ6IHBhcnQuZmllbGQsIHBhdGgsIHN0YXJ0fSlcbiAgICB9XG4gIH1cblxuICByZXR1cm4gY29udGVudFxufVxuXG4vKipcbiAqIEdyb3VwcyBleGFjdCBnZW5lcmF0ZWQgcmFuZ2VzIGZvciBvbmUgY29uZmlndXJhdGlvbiBmaWVsZC5cbiAqIEBwYXJhbSB7Q29uZmlndXJhdGlvblNwYW5bXX0gc3BhbnMgLSBSZWNvcmRlZCBzcGFucy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWVsZE5hbWUgLSBDb25maWd1cmF0aW9uIGZpZWxkLlxuICogQHJldHVybnMge3twYXRoOiBzdHJpbmcsIHJhbmdlczoge2VuZDogbnVtYmVyLCBzdGFydDogbnVtYmVyfVtdfVtdfSBHcm91cGVkIG91dHB1dCByYW5nZXMuXG4gKi9cbmZ1bmN0aW9uIGNvbmZpZ3VyYXRpb25PdXRwdXRzKHNwYW5zLCBmaWVsZE5hbWUpIHtcbiAgY29uc3QgZ3JvdXBlZCA9IG5ldyBNYXAoKVxuXG4gIGZvciAoY29uc3Qgc3BhbiBvZiBzcGFucykge1xuICAgIGlmIChzcGFuLmZpZWxkICE9IGZpZWxkTmFtZSkgY29udGludWVcbiAgICBjb25zdCByYW5nZXMgPSBncm91cGVkLmdldChzcGFuLnBhdGgpID8/IFtdXG5cbiAgICByYW5nZXMucHVzaCh7ZW5kOiBzcGFuLmVuZCwgc3RhcnQ6IHNwYW4uc3RhcnR9KVxuICAgIGdyb3VwZWQuc2V0KHNwYW4ucGF0aCwgcmFuZ2VzKVxuICB9XG5cbiAgcmV0dXJuIFsuLi5ncm91cGVkXS5tYXAoKFtwYXRoLCByYW5nZXNdKSA9PiAoe3BhdGgsIHJhbmdlc30pKVxufVxuXG4vKipcbiAqIENoZWNrcyB3aGV0aGVyIHByb3ZlbmFuY2UgcmVmZXJzIHRvIG9uZSBzb3VyY2UgZmlsZS5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU2VtYW50aWNPcmlnaW59IG9yaWdpbiAtIFNlbWFudGljIG9yaWdpbi5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNvdXJjZSBmaWxlbmFtZS5cbiAqIEByZXR1cm5zIHtib29sZWFufSBXaGV0aGVyIHRoZSBvcmlnaW4gcmVmZXJlbmNlcyB0aGUgc291cmNlLlxuICovXG5mdW5jdGlvbiBvcmlnaW5SZWZlcmVuY2VzRmlsZW5hbWUob3JpZ2luLCBmaWxlbmFtZSkge1xuICBpZiAob3JpZ2luLmtpbmQgPT0gXCJzb3VyY2VcIikgcmV0dXJuIG9yaWdpbi5sb2NhdGlvbi5maWxlbmFtZSA9PSBmaWxlbmFtZVxuICBpZiAob3JpZ2luLmtpbmQgPT0gXCJkZXJpdmVkXCIpIHJldHVybiBvcmlnaW4ub3JpZ2lucy5zb21lKCh7bG9jYXRpb259KSA9PiBsb2NhdGlvbi5maWxlbmFtZSA9PSBmaWxlbmFtZSlcblxuICByZXR1cm4gb3JpZ2luLnJlbGF0ZWRPcmlnaW5zLnNvbWUoKHtsb2NhdGlvbn0pID0+IGxvY2F0aW9uLmZpbGVuYW1lID09IGZpbGVuYW1lKVxufVxuXG4vKipcbiAqIEhhc2hlcyBleGFjdCBhcnRpZmFjdCBjb250ZW50LlxuICogQHBhcmFtIHtzdHJpbmcgfCBVaW50OEFycmF5fSBjb250ZW50IC0gQXJ0aWZhY3QgY29udGVudC5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IExvd2VyY2FzZSBTSEEtMjU2LlxuICovXG5mdW5jdGlvbiBoYXNoQ29udGVudChjb250ZW50KSB7XG4gIHJldHVybiBjcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShjb250ZW50KS5kaWdlc3QoXCJoZXhcIilcbn1cblxuLyoqXG4gKiBTZXJpYWxpemVzIGEgcmVjdXJzaXZlbHkgc29ydGVkIEpTT04gdmFsdWUuXG4gKiBAcGFyYW0ge3Vua25vd259IHZhbHVlIC0gSlNPTi1jb21wYXRpYmxlIHZhbHVlLlxuICogQHJldHVybnMge3N0cmluZ30gQ2Fub25pY2FsIGluZGVudGVkIEpTT04uXG4gKi9cbmZ1bmN0aW9uIHN0cmluZ2lmeUNhbm9uaWNhbEpzb24odmFsdWUpIHtcbiAgcmV0dXJuIGAke0pTT04uc3RyaW5naWZ5KHNvcnRKc29uKHZhbHVlKSwgbnVsbCwgMil9XFxuYFxufVxuXG4vKipcbiAqIFJlY3Vyc2l2ZWx5IHNvcnRzIG9iamVjdCBrZXlzIHdpdGhvdXQgcmVvcmRlcmluZyBhcnJheXMuXG4gKiBAcGFyYW0ge3Vua25vd259IHZhbHVlIC0gSlNPTi1jb21wYXRpYmxlIHZhbHVlLlxuICogQHJldHVybnMge3Vua25vd259IFNvcnRlZCB2YWx1ZS5cbiAqL1xuZnVuY3Rpb24gc29ydEpzb24odmFsdWUpIHtcbiAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSByZXR1cm4gdmFsdWUubWFwKHNvcnRKc29uKVxuICBpZiAoIWlzUGxhaW5PYmplY3QodmFsdWUpKSByZXR1cm4gdmFsdWVcblxuICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC5rZXlzKHZhbHVlKS5zb3J0KCkubWFwKGtleSA9PiBba2V5LCBzb3J0SnNvbih2YWx1ZVtrZXldKV0pKVxufVxuXG4vKipcbiAqIFZhbGlkYXRlcyBhIGxvd2VyY2FzZSByZXZlcnNlLUROUyBpZGVudGl0eS5cbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIENhbmRpZGF0ZSBpZGVudGl0eS5cbiAqIEBwYXJhbSB7bnVtYmVyfSBzZWdtZW50cyAtIFJlcXVpcmVkIG1pbmltdW0gc2VnbWVudCBjb3VudC5cbiAqIEByZXR1cm5zIHtib29sZWFufSBXaGV0aGVyIHRoZSBpZGVudGl0eSBpcyB2YWxpZC5cbiAqL1xuZnVuY3Rpb24gaXNSZXZlcnNlRG5zKHZhbHVlLCBzZWdtZW50cykge1xuICBjb25zdCBwYXJ0cyA9IHZhbHVlLnNwbGl0KFwiLlwiKVxuXG4gIHJldHVybiBwYXJ0cy5sZW5ndGggPj0gc2VnbWVudHMgJiYgcGFydHMuZXZlcnkocGFydCA9PiAvXlthLXpdW2EtejAtOV9dKiQvdS50ZXN0KHBhcnQpICYmICFqYXZhS2V5d29yZHMuaGFzKHBhcnQpKVxufVxuXG4vKipcbiAqIERlcml2ZXMgb25lIHN0YWJsZSBEYXJ0IGNsYXNzIHN1ZmZpeC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBpZCAtIFNlbWFudGljIG1vZHVsZSBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IERhcnQgY2xhc3Mgc3VmZml4LlxuICovXG5mdW5jdGlvbiBtb2R1bGVOYW1lKGlkKSB7XG4gIHJldHVybiBpZC5zcGxpdCgvWy5fLV0rL3UpLm1hcChwYXJ0ID0+IGAke3BhcnRbMF0udG9VcHBlckNhc2UoKX0ke3BhcnQuc2xpY2UoMSl9YCkuam9pbihcIlwiKVxufVxuXG4vKipcbiAqIERlcml2ZXMgb25lIHN0YWJsZSBzZW1hbnRpYyBwYXJ0IGZpbGVuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IGlkIC0gU2VtYW50aWMgbW9kdWxlIGlkZW50aXR5LlxuICogQHJldHVybnMge3N0cmluZ30gRGFydCBmaWxlbmFtZS5cbiAqL1xuZnVuY3Rpb24gbW9kdWxlRmlsZU5hbWUoaWQpIHtcbiAgcmV0dXJuIGlkLnJlcGxhY2VBbGwoL1suLV0vZ3UsIFwiX1wiKVxufVxuXG4vKipcbiAqIEFsbG9jYXRlcyBhIGNvbGxpc2lvbi1mcmVlIHByaXZhdGUgb3V0cHV0IHNpbmsgYmluZGluZy5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU2VtYW50aWNNb2R1bGV9IG1vZHVsZSAtIFNlbWFudGljIG1vZHVsZS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IERhcnQgYmluZGluZyBuYW1lLlxuICovXG5mdW5jdGlvbiBvdXRwdXRTaW5rTmFtZShtb2R1bGUpIHtcbiAgY29uc3QgYmluZGluZ3MgPSBuZXcgU2V0KG1vZHVsZS5mdW5jdGlvbnMuZmxhdE1hcChkZWNsYXJhdGlvbiA9PiBkZWNsYXJhdGlvbi5wYXJhbWV0ZXJzLm1hcCgoe25hbWV9KSA9PiBuYW1lKSkpXG5cbiAgZm9yIChjb25zdCBkZWNsYXJhdGlvbiBvZiBtb2R1bGUuZnVuY3Rpb25zKSBjb2xsZWN0QmxvY2tCaW5kaW5nTmFtZXMoZGVjbGFyYXRpb24uYm9keSwgYmluZGluZ3MpXG4gIGNvbGxlY3RCbG9ja0JpbmRpbmdOYW1lcyhtb2R1bGUuZW50cnlQb2ludC5ib2R5LCBiaW5kaW5ncylcbiAgbGV0IGNhbmRpZGF0ZSA9IFwic2VtYW50aWZvbGRPdXRwdXRcIlxuXG4gIHdoaWxlIChiaW5kaW5ncy5oYXMoY2FuZGlkYXRlKSkgY2FuZGlkYXRlICs9IFwiX1wiXG5cbiAgcmV0dXJuIGNhbmRpZGF0ZVxufVxuXG4vKipcbiAqIENvbGxlY3RzIGV2ZXJ5IGJsb2NrLW93bmVkIGJpbmRpbmcgbmFtZS5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuQmxvY2t9IGJsb2NrIC0gU2VtYW50aWMgYmxvY2suXG4gKiBAcGFyYW0ge1NldDxzdHJpbmc+fSBiaW5kaW5ncyAtIE11dGFibGUgbmFtZSBzZXQuXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZnVuY3Rpb24gY29sbGVjdEJsb2NrQmluZGluZ05hbWVzKGJsb2NrLCBiaW5kaW5ncykge1xuICBmb3IgKGNvbnN0IHN0YXRlbWVudCBvZiBibG9jay5zdGF0ZW1lbnRzKSB7XG4gICAgaWYgKHN0YXRlbWVudC5raW5kID09IFwiTG9jYWxEZWNsYXJhdGlvblwiKSBiaW5kaW5ncy5hZGQoc3RhdGVtZW50Lm5hbWUpXG4gICAgZWxzZSBpZiAoc3RhdGVtZW50LmtpbmQgPT0gXCJJZlN0YXRlbWVudFwiKSB7XG4gICAgICBjb2xsZWN0QmxvY2tCaW5kaW5nTmFtZXMoc3RhdGVtZW50LmNvbnNlcXVlbnQsIGJpbmRpbmdzKVxuICAgICAgaWYgKHN0YXRlbWVudC5hbHRlcm5hdGUpIGNvbGxlY3RCbG9ja0JpbmRpbmdOYW1lcyhzdGF0ZW1lbnQuYWx0ZXJuYXRlLCBiaW5kaW5ncylcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBXcmFwcyBvbmUgbW9kdWxlIGluIGFuIGV4cGxpY2l0IHNlbWFudGljIHByb2plY3QuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljTW9kdWxlIHwgdW5kZWZpbmVkfSBjYW5kaWRhdGUgLSBDYW5kaWRhdGUgbW9kdWxlLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljUHJvZ3JhbX0gTm9ybWFsaXplZCBwcm9qZWN0LlxuICovXG5mdW5jdGlvbiBub3JtYWxpemVTaW5nbGVNb2R1bGUoY2FuZGlkYXRlKSB7XG4gIGlmICghaXNQbGFpbk9iamVjdChjYW5kaWRhdGUpKSB1bnN1cHBvcnRlZENhcGFiaWxpdHkoXCJmbHV0dGVyXCIsIFwibWlzc2luZyBvciBpbnZhbGlkIG1vZHVsZVwiLCB1bmRlZmluZWQpXG4gIGNvbnN0IG1vZHVsZSA9IHN0cnVjdHVyZWRDbG9uZShjYW5kaWRhdGUpXG4gIGNvbnN0IHNvdXJjZXMgPSBtb2R1bGUucHJvdmVuYW5jZT8uc291cmNlc1xuXG4gIGlmICghQXJyYXkuaXNBcnJheShzb3VyY2VzKSB8fCBzb3VyY2VzLmxlbmd0aCAhPSAxIHx8IHNvdXJjZXNbMF0uY29udGVudCA9PT0gbnVsbCB8fFxuICAgIHNvdXJjZXNbMF0uZmlsZW5hbWUgIT0gbW9kdWxlLmxvY2F0aW9uPy5maWxlbmFtZSB8fCB0eXBlb2Ygc291cmNlc1swXS5sYW5ndWFnZSAhPSBcInN0cmluZ1wiKSB7XG4gICAgdW5zdXBwb3J0ZWRDYXBhYmlsaXR5KFwiZmx1dHRlclwiLCBcInNpbmdsZS1tb2R1bGUgc291cmNlIG93bmVyc2hpcFwiLCBtb2R1bGUubG9jYXRpb24pXG4gIH1cbiAgcmVrZXlNb2R1bGVEZWNsYXJhdGlvbnMobW9kdWxlLCBcIm1haW5cIilcbiAgY29uc3QgZXhwb3J0cyA9IFtcbiAgICAuLi4obW9kdWxlLnJlY29yZHMgPz8gW10pLm1hcChkZWNsYXJhdGlvbiA9PiBhcHBsaWNhdGlvbkV4cG9ydChkZWNsYXJhdGlvbiwgXCJyZWNvcmRcIikpLFxuICAgIC4uLihtb2R1bGUuY2xhc3NlcyA/PyBbXSkubWFwKGRlY2xhcmF0aW9uID0+IGFwcGxpY2F0aW9uRXhwb3J0KGRlY2xhcmF0aW9uLCBcImNsYXNzXCIpKSxcbiAgICAuLi4obW9kdWxlLmVycm9ycyA/PyBbXSkubWFwKGRlY2xhcmF0aW9uID0+IGFwcGxpY2F0aW9uRXhwb3J0KGRlY2xhcmF0aW9uLCBcImVycm9yXCIpKSxcbiAgICAuLi5tb2R1bGUuZnVuY3Rpb25zLm1hcChkZWNsYXJhdGlvbiA9PiBhcHBsaWNhdGlvbkV4cG9ydChkZWNsYXJhdGlvbiwgXCJmdW5jdGlvblwiKSlcbiAgXVxuICBjb25zdCBwcm9ncmFtTW9kdWxlID0gey4uLm1vZHVsZSwgZXhwb3J0cywgaWQ6IFwibWFpblwiLCBpbXBvcnRzOiBbXSwgc291cmNlRmlsZW5hbWU6IHNvdXJjZXNbMF0uZmlsZW5hbWV9XG5cbiAgcmV0dXJuIHtlbnRyeU1vZHVsZTogXCJtYWluXCIsIGtpbmQ6IFwiUHJvZ3JhbVwiLCBtb2R1bGVzOiBbcHJvZ3JhbU1vZHVsZV0sIHNvdXJjZXM6IHN0cnVjdHVyZWRDbG9uZShzb3VyY2VzKX1cbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBvbmUgbW9kdWxlIGRlY2xhcmF0aW9uIHRvIGFuIGV4cGxpY2l0IGFwcGxpY2F0aW9uIGV4cG9ydC5cbiAqIEBwYXJhbSB7e2lkPzogc3RyaW5nLCBsb2NhdGlvbjogaW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU291cmNlTG9jYXRpb24sIG5hbWU6IHN0cmluZ319IGRlY2xhcmF0aW9uIC0gRGVjbGFyYXRpb24uXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljRGVjbGFyYXRpb25LaW5kfSBzeW1ib2xLaW5kIC0gRGVjbGFyYXRpb24ga2luZC5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY0V4cG9ydH0gU2VtYW50aWMgZXhwb3J0LlxuICovXG5mdW5jdGlvbiBhcHBsaWNhdGlvbkV4cG9ydChkZWNsYXJhdGlvbiwgc3ltYm9sS2luZCkge1xuICByZXR1cm4ge2RlY2xhcmF0aW9uSWQ6IC8qKiBAdHlwZSB7c3RyaW5nfSAqLyAoZGVjbGFyYXRpb24uaWQpLCBleHBvcnRlZE5hbWU6IGRlY2xhcmF0aW9uLm5hbWUsXG4gICAga2luZDogXCJFeHBvcnRcIiwgbG9jYXRpb246IGRlY2xhcmF0aW9uLmxvY2F0aW9uLCBzeW1ib2xLaW5kfVxufVxuXG4vKipcbiAqIFJlLWtleXMgb25lIHN0YW5kYWxvbmUgbW9kdWxlIGZvciBhcHBsaWNhdGlvbi1wcm9qZWN0IG93bmVyc2hpcC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU2VtYW50aWNNb2R1bGV9IG1vZHVsZSAtIFN0YW5kYWxvbmUgbW9kdWxlLlxuICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZUlkIC0gU3RhYmxlIGFwcGxpY2F0aW9uIG1vZHVsZSBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5mdW5jdGlvbiByZWtleU1vZHVsZURlY2xhcmF0aW9ucyhtb2R1bGUsIG1vZHVsZUlkKSB7XG4gIGNvbnN0IGRlY2xhcmF0aW9ucyA9IFsuLi5tb2R1bGUucmVjb3JkcyA/PyBbXSwgLi4ubW9kdWxlLmNsYXNzZXMgPz8gW10sIC4uLm1vZHVsZS5lcnJvcnMgPz8gW10sIC4uLm1vZHVsZS5mdW5jdGlvbnNdXG4gIGNvbnN0IHJlcGxhY2VtZW50cyA9IG5ldyBNYXAoZGVjbGFyYXRpb25zLmZpbHRlcihkZWNsYXJhdGlvbiA9PiB0eXBlb2YgZGVjbGFyYXRpb24uaWQgPT0gXCJzdHJpbmdcIilcbiAgICAubWFwKGRlY2xhcmF0aW9uID0+IFtkZWNsYXJhdGlvbi5pZCwgYCR7bW9kdWxlSWR9IyR7ZGVjbGFyYXRpb24uaWR9YF0pKVxuXG4gIGZvciAoY29uc3QgZGVjbGFyYXRpb24gb2YgZGVjbGFyYXRpb25zKSBpZiAodHlwZW9mIGRlY2xhcmF0aW9uLmlkID09IFwic3RyaW5nXCIpIGRlY2xhcmF0aW9uLmlkID0gcmVwbGFjZW1lbnRzLmdldChkZWNsYXJhdGlvbi5pZClcbiAgY29uc3Qgc2VlbiA9IG5ldyBTZXQoKVxuICBjb25zdCBpZGVudGl0eUZpZWxkcyA9IG5ldyBTZXQoW1wiY2xhc3NJZFwiLCBcImRlY2xhcmF0aW9uSWRcIiwgXCJmaWVsZFwiLCBcIm1ldGhvZFwiLCBcInBhcmFtZXRlcklkXCJdKVxuICAvKipcbiAgICogUmV3cml0ZXMgc2VtYW50aWMgZGVjbGFyYXRpb24gaWRlbnRpdGllcyByZWN1cnNpdmVseS5cbiAgICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIENhbmRpZGF0ZSBzZW1hbnRpYyB2YWx1ZS5cbiAgICogQHJldHVybnMge3ZvaWR9XG4gICAqL1xuICBjb25zdCB2aXNpdCA9IHZhbHVlID0+IHtcbiAgICBpZiAoIXZhbHVlIHx8IHR5cGVvZiB2YWx1ZSAhPSBcIm9iamVjdFwiIHx8IHNlZW4uaGFzKHZhbHVlKSkgcmV0dXJuXG4gICAgc2Vlbi5hZGQodmFsdWUpXG4gICAgZm9yIChjb25zdCBba2V5LCBuZXN0ZWRdIG9mIE9iamVjdC5lbnRyaWVzKHZhbHVlKSkge1xuICAgICAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSAmJiBpZGVudGl0eUZpZWxkcy5oYXMoa2V5KSAmJiB0eXBlb2YgbmVzdGVkID09IFwic3RyaW5nXCIgJiYgcmVwbGFjZW1lbnRzLmhhcyhuZXN0ZWQpKSB7XG4gICAgICAgIFJlZmxlY3Quc2V0KHZhbHVlLCBrZXksIHJlcGxhY2VtZW50cy5nZXQobmVzdGVkKSlcbiAgICAgIH0gZWxzZSB2aXNpdChuZXN0ZWQpXG4gICAgfVxuICB9XG5cbiAgdmlzaXQobW9kdWxlKVxufVxuXG4vKipcbiAqIEVzY2FwZXMgYW4gWE1MIGF0dHJpYnV0ZSB2YWx1ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFJhdyB2YWx1ZS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEVzY2FwZWQgdmFsdWUuXG4gKi9cbmZ1bmN0aW9uIHhtbEVzY2FwZSh2YWx1ZSkge1xuICByZXR1cm4gdmFsdWUucmVwbGFjZUFsbChcIiZcIiwgXCImYW1wO1wiKS5yZXBsYWNlQWxsKFwiPFwiLCBcIiZsdDtcIikucmVwbGFjZUFsbChcIj5cIiwgXCImZ3Q7XCIpXG4gICAgLnJlcGxhY2VBbGwoJ1wiJywgXCImcXVvdDtcIikucmVwbGFjZUFsbChcIidcIiwgXCImYXBvcztcIilcbn1cblxuLyoqXG4gKiBFc2NhcGVzIGEgc2luZ2xlLXF1b3RlZCBEYXJ0IGxpdGVyYWwgYm9keS5cbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFJhdyB2YWx1ZS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEVzY2FwZWQgdmFsdWUuXG4gKi9cbmZ1bmN0aW9uIGRhcnRFc2NhcGUodmFsdWUpIHtcbiAgcmV0dXJuIHZhbHVlLnJlcGxhY2VBbGwoXCJcXFxcXCIsIFwiXFxcXFxcXFxcIikucmVwbGFjZUFsbChcIidcIiwgXCJcXFxcJ1wiKS5yZXBsYWNlQWxsKFwiJFwiLCBcIlxcXFwkXCIpXG59XG5cbi8qKlxuICogQ2hlY2tzIGZvciBhIHBsYWluIHN0cmluZy1rZXllZCBvYmplY3QuXG4gKiBAcGFyYW0ge3Vua25vd259IHZhbHVlIC0gQ2FuZGlkYXRlIHZhbHVlLlxuICogQHJldHVybnMge3ZhbHVlIGlzIFJlY29yZDxzdHJpbmcsIHVua25vd24+fSBXaGV0aGVyIHRoZSB2YWx1ZSBpcyBwbGFpbi5cbiAqL1xuZnVuY3Rpb24gaXNQbGFpbk9iamVjdCh2YWx1ZSkge1xuICByZXR1cm4gQm9vbGVhbih2YWx1ZSkgJiYgdHlwZW9mIHZhbHVlID09IFwib2JqZWN0XCIgJiYgIUFycmF5LmlzQXJyYXkodmFsdWUpICYmIE9iamVjdC5nZXRQcm90b3R5cGVPZih2YWx1ZSkgPT0gT2JqZWN0LnByb3RvdHlwZVxufVxuXG4vKipcbiAqIFRocm93cyBhIHN0YWJsZSBpbnZhbGlkLWlucHV0IGRpYWdub3N0aWMuXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIERpYWdub3N0aWMgZGV0YWlsLlxuICogQHJldHVybnMge25ldmVyfSBOZXZlciByZXR1cm5zLlxuICovXG5mdW5jdGlvbiBpbnZhbGlkSW5wdXQobWVzc2FnZSkge1xuICB0aHJvdyBuZXcgU2VtYW50aWZvbGREaWFnbm9zdGljKHtjb2RlOiBcIklOVkFMSURfQVBQTElDQVRJT05fSU5QVVRcIiwgbGFuZ3VhZ2U6IFwiZmx1dHRlclwiLCBtZXNzYWdlfSlcbn1cblxuLyoqXG4gKiBUaHJvd3MgYSBzdGFibGUgaW52YWxpZC1jb25maWd1cmF0aW9uIGRpYWdub3N0aWMuXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIERpYWdub3N0aWMgZGV0YWlsLlxuICogQHJldHVybnMge25ldmVyfSBOZXZlciByZXR1cm5zLlxuICovXG5mdW5jdGlvbiBpbnZhbGlkQ29uZmlndXJhdGlvbihtZXNzYWdlKSB7XG4gIHRocm93IG5ldyBTZW1hbnRpZm9sZERpYWdub3N0aWMoe2NvZGU6IFwiSU5WQUxJRF9BUFBMSUNBVElPTl9DT05GSUdVUkFUSU9OXCIsIGxhbmd1YWdlOiBcImZsdXR0ZXJcIiwgbWVzc2FnZX0pXG59XG5cbi8qKlxuICogVGhyb3dzIGEgc3RhYmxlIGludmFsaWQtYXNzZXQgZGlhZ25vc3RpYy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gRGlhZ25vc3RpYyBkZXRhaWwuXG4gKiBAcmV0dXJucyB7bmV2ZXJ9IE5ldmVyIHJldHVybnMuXG4gKi9cbmZ1bmN0aW9uIGludmFsaWRBc3NldChtZXNzYWdlKSB7XG4gIHRocm93IG5ldyBTZW1hbnRpZm9sZERpYWdub3N0aWMoe2NvZGU6IFwiSU5WQUxJRF9BUFBMSUNBVElPTl9BU1NFVFwiLCBsYW5ndWFnZTogXCJmbHV0dGVyXCIsIG1lc3NhZ2V9KVxufVxuXG4vKipcbiAqIFRocm93cyBhIHN0YWJsZSBpbnZhbGlkLXBhdGggZGlhZ25vc3RpYy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gRGlhZ25vc3RpYyBkZXRhaWwuXG4gKiBAcmV0dXJucyB7bmV2ZXJ9IE5ldmVyIHJldHVybnMuXG4gKi9cbmZ1bmN0aW9uIGludmFsaWRQYXRoKG1lc3NhZ2UpIHtcbiAgdGhyb3cgbmV3IFNlbWFudGlmb2xkRGlhZ25vc3RpYyh7Y29kZTogXCJJTlZBTElEX0FQUExJQ0FUSU9OX1BBVEhcIiwgbGFuZ3VhZ2U6IFwiZmx1dHRlclwiLCBtZXNzYWdlfSlcbn1cbiJdfQ==
|