semantifold 0.4.0 → 0.6.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 +13 -7
- package/build/index.d.ts +12 -8
- package/build/index.d.ts.map +1 -1
- package/build/index.js +10 -7
- package/build/src/backends/android.d.ts +49 -0
- package/build/src/backends/android.d.ts.map +1 -0
- package/build/src/backends/android.js +1278 -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 +30 -1
- package/build/src/backends/ios.js +2 -2
- package/build/src/backends/kotlin.d.ts +10 -0
- package/build/src/backends/kotlin.d.ts.map +1 -1
- package/build/src/backends/kotlin.js +11 -9
- 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 +6 -4
- package/build/src/backends/program.d.ts.map +1 -1
- package/build/src/backends/program.js +5 -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.map +1 -1
- package/build/src/backends/shared.js +20 -4
- package/build/src/backends/writer.d.ts +21 -1
- package/build/src/backends/writer.d.ts.map +1 -1
- package/build/src/backends/writer.js +25 -2
- 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 +184 -4
- package/build/src/semantic/types.d.ts.map +1 -1
- package/build/src/semantic/types.js +45 -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 +79 -0
- package/docs/architecture.md +13 -5
- package/docs/goals.md +1 -1
- package/docs/ios.md +1 -1
- package/docs/language-support.md +15 -4
- package/docs/parser-qualification.md +31 -1
- package/docs/source-maps.md +7 -3
- package/docs/specification.md +5 -0
- package/docs/testing.md +40 -3
- package/docs/zig.md +33 -0
- package/index.js +9 -6
- 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 +1374 -0
- package/src/backends/identifiers.js +30 -0
- package/src/backends/ios.js +1 -1
- package/src/backends/kotlin.js +11 -8
- package/src/backends/native-validation.js +1 -1
- package/src/backends/program.js +4 -3
- package/src/backends/scalars.js +1 -0
- package/src/backends/shared.js +22 -3
- package/src/backends/writer.js +27 -2
- 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 +47 -2
- package/src/semantic/validate.js +1 -1
- package/src/toolchains.js +1 -0
- package/src/zig-bindings.js +46 -0
|
@@ -0,0 +1,1278 @@
|
|
|
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 { preflightSemanticProgram } from "./program.js";
|
|
10
|
+
import { emitScalarType } from "./scalars.js";
|
|
11
|
+
import { kotlinRuntime } from "./kotlin-runtime.js";
|
|
12
|
+
import { emitKotlinBlock } from "./kotlin.js";
|
|
13
|
+
import { SourceWriter } from "./writer.js";
|
|
14
|
+
const projectRoot = "generated/android-app";
|
|
15
|
+
const generatorVersion = "0.4.0";
|
|
16
|
+
/** @type {Readonly<Set<import("../semantic/types.js").SemanticLanguage>>} */
|
|
17
|
+
const androidSourceLanguages = new Set([
|
|
18
|
+
"php", "ruby", "javascript", "typescript", "java", "kotlin", "python", "csharp", "go", "c", "cpp", "rust", "swift", "dart", "zig"
|
|
19
|
+
]);
|
|
20
|
+
const requestFields = new Set(["assets", "configuration", "language", "module", "program", "resources", "role"]);
|
|
21
|
+
const configurationFields = new Set([
|
|
22
|
+
"activityClassName", "applicationId", "buildToolsVersion", "compileSdk", "displayName", "minimumSdk", "namespace",
|
|
23
|
+
"orientation", "packageName", "permissions", "productName", "targetSdk", "theme", "versionCode", "versionName"
|
|
24
|
+
]);
|
|
25
|
+
const resourceFields = new Set(["content", "mediaType", "path", "sha256"]);
|
|
26
|
+
const kotlinKeywords = new Set([
|
|
27
|
+
"as", "break", "class", "continue", "do", "else", "false", "for", "fun", "if", "in", "interface", "is", "null",
|
|
28
|
+
"object", "package", "return", "super", "this", "throw", "true", "try", "typealias", "typeof", "val", "var", "when", "while"
|
|
29
|
+
]);
|
|
30
|
+
const androidScaffoldSymbols = new Set([
|
|
31
|
+
"Activity", "Base64", "Bundle", "IllegalStateException", "Instrumentation", "Intent", "R", "SemantifoldEntryTest",
|
|
32
|
+
"SemantifoldUiInstrumentation", "StandardCharsets", "String", "SuppressLint", "Test", "TextView", "Throwable", "View"
|
|
33
|
+
]);
|
|
34
|
+
const mediaTypePattern = /^[A-Za-z0-9!#$&^_.+-]+\/[A-Za-z0-9!#$&^_.+-]+(?:;[\u0020-\u007e]+)?$/u;
|
|
35
|
+
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;
|
|
36
|
+
const toolchain = Object.freeze({
|
|
37
|
+
androidGradlePlugin: "8.11.1",
|
|
38
|
+
archives: {
|
|
39
|
+
buildTools: {
|
|
40
|
+
revision: "35.0.0",
|
|
41
|
+
sha256: "bd3a4966912eb8b30ed0d00b0cda6b6543b949d5ffe00bea54c04c81e1561d88",
|
|
42
|
+
url: "https://dl.google.com/android/repository/build-tools_r35_linux.zip"
|
|
43
|
+
},
|
|
44
|
+
commandLineTools: {
|
|
45
|
+
revision: "11076708",
|
|
46
|
+
sha256: "2d2d50857e4eb553af5a6dc3ad507a17adf43d115264b1afc116f95c92e5e258",
|
|
47
|
+
url: "https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip"
|
|
48
|
+
},
|
|
49
|
+
emulator: {
|
|
50
|
+
buildId: "13610412",
|
|
51
|
+
revision: "35.6.11",
|
|
52
|
+
sha256: "2fe2b56fe93ce75e1d478a40162131381d911c355efeaedb54dd1e0d0897a5cf",
|
|
53
|
+
url: "https://edgedl.me.gvt1.com/edgedl/android/repository/emulator-linux_x64-13610412.zip"
|
|
54
|
+
},
|
|
55
|
+
platform: {
|
|
56
|
+
revision: "35-r2",
|
|
57
|
+
sha256: "0988cacad01b38a18a47bac14a0695f246bc76c1b06c0eeb8eb0dc825ab0c8e0",
|
|
58
|
+
url: "https://dl.google.com/android/repository/platform-35_r02.zip"
|
|
59
|
+
},
|
|
60
|
+
platformTools: {
|
|
61
|
+
revision: "37.0.1",
|
|
62
|
+
sha256: "d230f13842f60f782a8645f9c813f8f845bf36089ea7289f28c48f17979313f1",
|
|
63
|
+
url: "https://dl.google.com/android/repository/platform-tools_r37.0.1-linux.zip"
|
|
64
|
+
},
|
|
65
|
+
systemImage: {
|
|
66
|
+
revision: "35-google_apis-x86_64-r9",
|
|
67
|
+
sha256: "c67b9ba0ff5bc0eb6d046871bfa228af14d4d47b02f0cdae94f048e511b7566e",
|
|
68
|
+
url: "https://dl.google.com/android/repository/sys-img/google_apis/x86_64-35_r09.zip"
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
buildTools: "35.0.0",
|
|
72
|
+
commandLineTools: "11076708",
|
|
73
|
+
compileSdk: 35,
|
|
74
|
+
emulator: "35.6.11",
|
|
75
|
+
gradle: "8.13",
|
|
76
|
+
java: "21.0.8",
|
|
77
|
+
kotlin: "2.2.10",
|
|
78
|
+
kotlinCompilerSha256: "302d1d8e671e5c3207e6ed62ff11fb555462a628e22a1158254dcaaf7e7394bc",
|
|
79
|
+
systemImage: "system-images;android-35;google_apis;x86_64",
|
|
80
|
+
targetSdk: 35
|
|
81
|
+
});
|
|
82
|
+
const excludedPathPatterns = Object.freeze([".gradle/**", "**/build/**", "local.properties"]);
|
|
83
|
+
const androidKotlinRuntime = `@file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
|
|
84
|
+
|
|
85
|
+
package __PACKAGE__.semantic
|
|
86
|
+
|
|
87
|
+
${kotlinRuntime.replaceAll("private ", "internal ")}
|
|
88
|
+
internal class SemantifoldOutputSink {
|
|
89
|
+
private val values: java.util.ArrayList<String> = java.util.ArrayList<String>()
|
|
90
|
+
|
|
91
|
+
fun reset() {
|
|
92
|
+
values.clear()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fun write(value: Long) {
|
|
96
|
+
values.add(value.toString())
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fun write(value: Boolean) {
|
|
100
|
+
values.add(if (value) "true" else "false")
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fun write(value: String) {
|
|
104
|
+
values.add(value)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
fun snapshot(): java.util.ArrayList<String> = java.util.ArrayList<String>(values)
|
|
108
|
+
}
|
|
109
|
+
`;
|
|
110
|
+
/** @typedef {{content: string | Uint8Array, contentKind: "binary" | "text", fullPath: string, mediaType: string, path: string, sha256: string}} AndroidInputFile */
|
|
111
|
+
/** @typedef {{end: number, field: string, path: string, start: number}} ConfigurationSpan */
|
|
112
|
+
/**
|
|
113
|
+
* Preflights a complete Android application request before allocating a source writer.
|
|
114
|
+
* @param {Record<string, unknown>} input - Candidate application request.
|
|
115
|
+
* @returns {{assets: AndroidInputFile[], configuration: import("../semantic/types.js").AndroidApplicationConfiguration, modulePaths: Map<string, string>, modules: import("../semantic/types.js").SemanticModule[], packagePath: string, program: import("../semantic/types.js").SemanticProgram, resources: AndroidInputFile[], sources: {content: string, filename: string, language?: import("../semantic/types.js").SemanticLanguage}[]}} Prepared application.
|
|
116
|
+
*/
|
|
117
|
+
export function preflightAndroidApplication(input) {
|
|
118
|
+
if (!isPlainObject(input) || Object.keys(input).some(key => !requestFields.has(key)) ||
|
|
119
|
+
Boolean(input.module) == Boolean(input.program)) {
|
|
120
|
+
invalidInput("Android application generation requires a closed request with exactly one semantic module or program.");
|
|
121
|
+
}
|
|
122
|
+
if (input.language !== undefined && input.language != "android" || input.role !== undefined && input.role != "application") {
|
|
123
|
+
invalidInput("Android application generation accepts only the Android application role.");
|
|
124
|
+
}
|
|
125
|
+
const configuration = normalizeConfiguration(input.configuration);
|
|
126
|
+
const program = input.program ?? normalizeSingleModule(
|
|
127
|
+
/** @type {import("../semantic/types.js").SemanticModule | undefined} */ (input.module));
|
|
128
|
+
const prepared = preflightSemanticProgram({
|
|
129
|
+
backendLanguage: "kotlin",
|
|
130
|
+
diagnosticLanguage: "android",
|
|
131
|
+
program: /** @type {import("../semantic/types.js").SemanticProgram} */ (program),
|
|
132
|
+
sourceLanguages: androidSourceLanguages
|
|
133
|
+
});
|
|
134
|
+
validateActivityClassName(configuration.activityClassName, prepared.program.entryModule);
|
|
135
|
+
const packagePath = configuration.packageName.replaceAll(".", "/");
|
|
136
|
+
const semanticRoot = `${projectRoot}/app/src/main/kotlin/${packagePath}/semantic`;
|
|
137
|
+
const modulePaths = new Map(prepared.modules.map(module => [
|
|
138
|
+
/** @type {string} */ (Reflect.get(module, "id")),
|
|
139
|
+
`${semanticRoot}/${moduleName(/** @type {string} */ (Reflect.get(module, "id")))}.kt`
|
|
140
|
+
]));
|
|
141
|
+
const resources = normalizeInputFiles(input.resources, "resource");
|
|
142
|
+
const assets = normalizeInputFiles(input.assets, "asset");
|
|
143
|
+
const fixedPaths = applicationPaths(configuration, modulePaths);
|
|
144
|
+
const completePaths = [
|
|
145
|
+
...fixedPaths,
|
|
146
|
+
...resources.map(({ fullPath }) => fullPath),
|
|
147
|
+
...assets.map(({ fullPath }) => fullPath)
|
|
148
|
+
];
|
|
149
|
+
const conflict = findPortableArtifactPathConflict(completePaths);
|
|
150
|
+
if (conflict) {
|
|
151
|
+
invalidPath(`Application artifact path '${conflict.path}' has a ${conflict.kind} conflict${conflict.other ? ` with '${conflict.other}'` : ""}.`);
|
|
152
|
+
}
|
|
153
|
+
return { ...prepared, assets, configuration, modulePaths, packagePath, resources };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Generates one complete deterministic Android/Kotlin project.
|
|
157
|
+
* @param {Record<string, unknown>} input - Application generation request.
|
|
158
|
+
* @returns {{artifacts: import("../semantic/types.js").GeneratedSetArtifact[], metadata: {applicationManifest: string, platformQualification: string}, target: "android"}} Candidate artifact set.
|
|
159
|
+
*/
|
|
160
|
+
export function generateAndroidApplication(input) {
|
|
161
|
+
const prepared = preflightAndroidApplication(input);
|
|
162
|
+
const configurationSpans = /** @type {ConfigurationSpan[]} */ ([]);
|
|
163
|
+
const configuration = prepared.configuration;
|
|
164
|
+
const packagePath = prepared.packagePath;
|
|
165
|
+
const semanticArtifacts = renderSemanticArtifacts(prepared);
|
|
166
|
+
const artifacts = /** @type {import("../semantic/types.js").GeneratedSetArtifact[]} */ ([
|
|
167
|
+
configuredText(`${projectRoot}/app/build.gradle.kts`, "manifest", renderAppBuild(configuration, configurationSpans), "Pinned dependency-minimal Android application build."),
|
|
168
|
+
configuredText(`${projectRoot}/app/src/androidTest/AndroidManifest.xml`, "manifest", renderAndroidTestManifest(configuration, configurationSpans), "Platform-only Android instrumentation declaration."),
|
|
169
|
+
configuredText(`${projectRoot}/app/src/androidTest/kotlin/${packagePath}/SemantifoldUiInstrumentation.kt`, "support", renderInstrumentation(configuration, configurationSpans), "Platform-only accessibility and lifecycle assertion."),
|
|
170
|
+
configuredText(`${projectRoot}/app/src/main/AndroidManifest.xml`, "manifest", renderAndroidManifest(configuration, configurationSpans), "Closed allowlisted Android application manifest."),
|
|
171
|
+
configuredText(`${projectRoot}/app/src/main/kotlin/${packagePath}/${configuration.activityClassName}.kt`, "entry", renderActivity(configuration, prepared.program.entryModule, configurationSpans), "Synthetic Android activity lifecycle and native output view binding."),
|
|
172
|
+
...semanticArtifacts,
|
|
173
|
+
syntheticText(`${projectRoot}/app/src/main/res/layout/activity_main.xml`, "resource", renderLayout(), "Synthetic one-view Android layout and accessibility identity."),
|
|
174
|
+
configuredText(`${projectRoot}/app/src/main/res/values/strings.xml`, "resource", renderStrings(configuration, configurationSpans), "Escaped application labels derived from configuration."),
|
|
175
|
+
syntheticText(`${projectRoot}/app/src/main/res/values/themes.xml`, "resource", renderTheme(), "Closed platform-native application theme."),
|
|
176
|
+
syntheticText(`${projectRoot}/app/src/main/res/xml/backup_rules.xml`, "resource", renderBackupRules(), "Closed API 23-30 full-backup exclusions."),
|
|
177
|
+
syntheticText(`${projectRoot}/app/src/main/res/xml/data_extraction_rules.xml`, "resource", renderDataExtractionRules(), "Closed Android 12+ cloud-backup and device-transfer exclusions."),
|
|
178
|
+
configuredText(`${projectRoot}/app/src/test/kotlin/${packagePath}/SemantifoldEntryTest.kt`, "support", renderUnitTest(configuration, prepared.program.entryModule, configurationSpans), "JUnit test-scope-only semantic determinism assertion."),
|
|
179
|
+
syntheticText(`${projectRoot}/build.gradle.kts`, "manifest", renderRootBuild(), "Pinned Android and Kotlin build plugins."),
|
|
180
|
+
syntheticText(`${projectRoot}/gradle.properties`, "support", renderGradleProperties(), "Pinned hermetic Gradle process properties."),
|
|
181
|
+
configuredText(`${projectRoot}/settings.gradle.kts`, "manifest", renderSettings(configuration, configurationSpans), "Closed official Gradle plugin and dependency repositories."),
|
|
182
|
+
...prepared.resources.map(inputFileArtifact),
|
|
183
|
+
...prepared.assets.map(inputFileArtifact)
|
|
184
|
+
]);
|
|
185
|
+
artifacts.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
|
|
186
|
+
const manifestPath = `${projectRoot}/semantifold-project.json`;
|
|
187
|
+
artifacts.push(syntheticText(manifestPath, "manifest", renderProjectManifest(prepared, artifacts, manifestPath, configurationSpans), "Versioned Android project ownership, toolchain, and provenance manifest."));
|
|
188
|
+
return {
|
|
189
|
+
artifacts,
|
|
190
|
+
metadata: { applicationManifest: manifestPath, platformQualification: "tensorbuzz-kvm" },
|
|
191
|
+
target: "android"
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Renders the mapped semantic Kotlin artifacts for every program module.
|
|
196
|
+
* @param {ReturnType<typeof preflightAndroidApplication>} prepared - Prepared application.
|
|
197
|
+
* @returns {import("../semantic/types.js").GeneratedSetArtifact[]} Semantic Kotlin artifacts.
|
|
198
|
+
*/
|
|
199
|
+
function renderSemanticArtifacts(prepared) {
|
|
200
|
+
const semanticRoot = `${projectRoot}/app/src/main/kotlin/${prepared.packagePath}/semantic`;
|
|
201
|
+
/** @type {import("../semantic/types.js").GeneratedSetArtifact[]} */
|
|
202
|
+
const artifacts = [syntheticText(`${semanticRoot}/SemantifoldRuntime.kt`, "support", androidKotlinRuntime.replaceAll("__PACKAGE__", prepared.configuration.packageName), "Shared Android application output capture and checked Kotlin scalar support.")];
|
|
203
|
+
const declarations = new Map();
|
|
204
|
+
for (const module of prepared.modules) {
|
|
205
|
+
for (const declaration of module.functions)
|
|
206
|
+
declarations.set(declaration.id, {
|
|
207
|
+
declaration,
|
|
208
|
+
moduleId: /** @type {string} */ (Reflect.get(module, "id"))
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
for (const module of prepared.modules) {
|
|
212
|
+
const moduleId = /** @type {string} */ (Reflect.get(module, "id"));
|
|
213
|
+
const filename = /** @type {string} */ (prepared.modulePaths.get(moduleId));
|
|
214
|
+
const sinkName = outputSinkName(module);
|
|
215
|
+
const writer = new SourceWriter({
|
|
216
|
+
callArgumentSuffix: sinkName,
|
|
217
|
+
callNameResolver: expression => {
|
|
218
|
+
const resolved = declarations.get(expression.resolution?.declarationId);
|
|
219
|
+
if (!resolved)
|
|
220
|
+
throw new TypeError(`Unknown validated Android function '${expression.resolution?.declarationId}'.`);
|
|
221
|
+
return `SemantifoldModule${moduleName(resolved.moduleId)}.${resolved.declaration.name}`;
|
|
222
|
+
},
|
|
223
|
+
filename,
|
|
224
|
+
language: "kotlin",
|
|
225
|
+
methodStringEquality: true,
|
|
226
|
+
module,
|
|
227
|
+
program: prepared.program,
|
|
228
|
+
programPaths: prepared.modulePaths,
|
|
229
|
+
sources: prepared.sources
|
|
230
|
+
});
|
|
231
|
+
writer.synthetic(`@file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")\n\npackage ${prepared.configuration.packageName}.semantic\n\n`, "Android semantic package namespace", [module], [""]);
|
|
232
|
+
emitSemanticModule(writer, module, moduleId, moduleId == prepared.program.entryModule, sinkName);
|
|
233
|
+
const mapping = finalizeMapping(writer.finish());
|
|
234
|
+
artifacts.push({
|
|
235
|
+
content: mapping.generated.content,
|
|
236
|
+
contentKind: "text",
|
|
237
|
+
mediaType: "text/x-kotlin",
|
|
238
|
+
ownership: "generated",
|
|
239
|
+
path: filename,
|
|
240
|
+
provenance: { kind: "text", mapping, sourceMap: toSourceMapV3(mapping), sourceMapFilename: `${filename}.map` },
|
|
241
|
+
role: "source"
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return artifacts;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Emits one namespaced semantic module and its entry bridge when applicable.
|
|
248
|
+
* @param {SourceWriter} writer - Mapped Kotlin writer.
|
|
249
|
+
* @param {import("../semantic/types.js").SemanticModule} module - Prepared module.
|
|
250
|
+
* @param {string} moduleId - Stable module identity.
|
|
251
|
+
* @param {boolean} entry - Whether this module owns the entry block.
|
|
252
|
+
* @param {string} sinkName - Collision-safe output sink binding.
|
|
253
|
+
*/
|
|
254
|
+
function emitSemanticModule(writer, module, moduleId, entry, sinkName) {
|
|
255
|
+
writer.synthetic(`internal object SemantifoldModule${moduleName(moduleId)} {\n`, "Android semantic module namespace", [module], [""]);
|
|
256
|
+
module.functions.forEach((declaration, functionIndex) => {
|
|
257
|
+
const path = `/functions/${functionIndex}`;
|
|
258
|
+
writer.synthetic(" ", "Android namespaced function indentation", [declaration], [path]);
|
|
259
|
+
writer.mapped("fun", { mappingKind: "anchor", node: declaration, path });
|
|
260
|
+
writer.synthetic(" ", "declaration spacing", [declaration], [path]);
|
|
261
|
+
writer.mapped(declaration.name, { mappingKind: "exact", node: declaration, path, role: "name" });
|
|
262
|
+
writer.synthetic("(", "function parameter scaffold", [declaration], [path]);
|
|
263
|
+
declaration.parameters.forEach((parameter, parameterIndex) => {
|
|
264
|
+
const parameterPath = `${path}/parameters/${parameterIndex}`;
|
|
265
|
+
if (parameterIndex)
|
|
266
|
+
writer.synthetic(", ", "parameter separator", [parameter], [parameterPath]);
|
|
267
|
+
writer.mapped(parameter.name, { mappingKind: "exact", node: parameter, path: parameterPath, role: "name" });
|
|
268
|
+
writer.synthetic(": ", "parameter annotation scaffold", [parameter], [parameterPath]);
|
|
269
|
+
writer.mapped(emitScalarType("kotlin", parameter.type), { mappingKind: "exact", node: parameter.type,
|
|
270
|
+
path: `${parameterPath}/type`, role: "type" });
|
|
271
|
+
});
|
|
272
|
+
if (declaration.parameters.length)
|
|
273
|
+
writer.synthetic(", ", "output sink parameter separator", [declaration], [path]);
|
|
274
|
+
writer.synthetic(`${sinkName}: SemantifoldOutputSink): `, "shared Android output sink parameter", [declaration], [path]);
|
|
275
|
+
writer.mapped(emitScalarType("kotlin", declaration.returnType), { mappingKind: "exact", node: declaration.returnType,
|
|
276
|
+
path: `${path}/returnType`, role: "type" });
|
|
277
|
+
writer.synthetic(" {\n", "Kotlin function body scaffold", [declaration], [path]);
|
|
278
|
+
emitKotlinBlock(writer, declaration.body, " ", `${path}/body`, `${sinkName}.write`);
|
|
279
|
+
writer.synthetic(" }\n", "Kotlin function body scaffold", [declaration], [path]);
|
|
280
|
+
});
|
|
281
|
+
if (entry) {
|
|
282
|
+
writer.synthetic(" fun semantifoldEntry(): java.util.ArrayList<String> {\n", "Android semantic entry scaffold", [module.entryPoint], ["/entryPoint"]);
|
|
283
|
+
writer.synthetic(` val ${sinkName} = SemantifoldOutputSink()\n`, "Android output sink allocation", [module.entryPoint], ["/entryPoint"]);
|
|
284
|
+
writer.synthetic(` ${sinkName}.reset()\n`, "Android lifecycle-safe output reset", [module.entryPoint], ["/entryPoint"]);
|
|
285
|
+
emitKotlinBlock(writer, module.entryPoint.body, " ", "/entryPoint/body", `${sinkName}.write`);
|
|
286
|
+
writer.synthetic(` return ${sinkName}.snapshot()\n`, "Android semantic output return", [module.entryPoint], ["/entryPoint"]);
|
|
287
|
+
writer.synthetic(" }\n", "Android semantic entry scaffold", [module.entryPoint], ["/entryPoint"]);
|
|
288
|
+
}
|
|
289
|
+
writer.synthetic("}\n", "Android semantic module namespace", [module], [""]);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Lists every fixed generated path before any writer is allocated.
|
|
293
|
+
* @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized application configuration.
|
|
294
|
+
* @param {Map<string, string>} modulePaths - Semantic module output paths.
|
|
295
|
+
* @returns {string[]} Fixed owned artifact paths.
|
|
296
|
+
*/
|
|
297
|
+
function applicationPaths(configuration, modulePaths) {
|
|
298
|
+
const packagePath = configuration.packageName.replaceAll(".", "/");
|
|
299
|
+
return [
|
|
300
|
+
`${projectRoot}/app/build.gradle.kts`,
|
|
301
|
+
`${projectRoot}/app/src/androidTest/AndroidManifest.xml`,
|
|
302
|
+
`${projectRoot}/app/src/androidTest/kotlin/${packagePath}/SemantifoldUiInstrumentation.kt`,
|
|
303
|
+
`${projectRoot}/app/src/main/AndroidManifest.xml`,
|
|
304
|
+
`${projectRoot}/app/src/main/kotlin/${packagePath}/${configuration.activityClassName}.kt`,
|
|
305
|
+
...modulePaths.values(),
|
|
306
|
+
`${projectRoot}/app/src/main/kotlin/${packagePath}/semantic/SemantifoldRuntime.kt`,
|
|
307
|
+
`${projectRoot}/app/src/main/res/layout/activity_main.xml`,
|
|
308
|
+
`${projectRoot}/app/src/main/res/values/strings.xml`,
|
|
309
|
+
`${projectRoot}/app/src/main/res/values/themes.xml`,
|
|
310
|
+
`${projectRoot}/app/src/main/res/xml/backup_rules.xml`,
|
|
311
|
+
`${projectRoot}/app/src/main/res/xml/data_extraction_rules.xml`,
|
|
312
|
+
`${projectRoot}/app/src/test/kotlin/${packagePath}/SemantifoldEntryTest.kt`,
|
|
313
|
+
`${projectRoot}/build.gradle.kts`,
|
|
314
|
+
`${projectRoot}/gradle.properties`,
|
|
315
|
+
`${projectRoot}/settings.gradle.kts`,
|
|
316
|
+
`${projectRoot}/semantifold-project.json`
|
|
317
|
+
];
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Renders the pinned root plugin declarations.
|
|
321
|
+
* @returns {string} Root Gradle Kotlin script.
|
|
322
|
+
*/
|
|
323
|
+
function renderRootBuild() {
|
|
324
|
+
return `plugins {
|
|
325
|
+
id("com.android.application") version "${toolchain.androidGradlePlugin}" apply false
|
|
326
|
+
id("org.jetbrains.kotlin.android") version "${toolchain.kotlin}" apply false
|
|
327
|
+
}
|
|
328
|
+
`;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Renders closed project settings and repositories.
|
|
332
|
+
* @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
|
|
333
|
+
* @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
|
|
334
|
+
* @returns {string} Settings Gradle Kotlin script.
|
|
335
|
+
*/
|
|
336
|
+
function renderSettings(configuration, spans) {
|
|
337
|
+
return configured(`${projectRoot}/settings.gradle.kts`, spans, [`pluginManagement {
|
|
338
|
+
repositories {
|
|
339
|
+
google()
|
|
340
|
+
mavenCentral()
|
|
341
|
+
gradlePluginPortal()
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
dependencyResolutionManagement {
|
|
346
|
+
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
|
347
|
+
repositories {
|
|
348
|
+
google()
|
|
349
|
+
mavenCentral()
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
rootProject.name = "`, field("productName", kotlinEscape(configuration.productName)), `"
|
|
354
|
+
include(":app")
|
|
355
|
+
`]);
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Renders deterministic Gradle process properties.
|
|
359
|
+
* @returns {string} Gradle properties file.
|
|
360
|
+
*/
|
|
361
|
+
function renderGradleProperties() {
|
|
362
|
+
return `org.gradle.caching=false
|
|
363
|
+
org.gradle.configuration-cache=false
|
|
364
|
+
org.gradle.daemon=false
|
|
365
|
+
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -Duser.language=en -Duser.country=US -Duser.timezone=UTC
|
|
366
|
+
org.gradle.parallel=false
|
|
367
|
+
kotlin.stdlib.default.dependency=false
|
|
368
|
+
kotlin.code.style=official
|
|
369
|
+
`;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Renders the application module build contract.
|
|
373
|
+
* @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
|
|
374
|
+
* @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
|
|
375
|
+
* @returns {string} Application Gradle Kotlin script.
|
|
376
|
+
*/
|
|
377
|
+
function renderAppBuild(configuration, spans) {
|
|
378
|
+
return configured(`${projectRoot}/app/build.gradle.kts`, spans, [
|
|
379
|
+
`import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
380
|
+
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
|
|
381
|
+
|
|
382
|
+
plugins {
|
|
383
|
+
id("com.android.application")
|
|
384
|
+
id("org.jetbrains.kotlin.android")
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
dependencies {
|
|
388
|
+
testRuntimeOnly("org.hamcrest:hamcrest-core:1.3") {
|
|
389
|
+
isTransitive = false
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
val semantifoldKotlinHome = providers.environmentVariable("SEMANTIFOLD_KOTLIN_HOME").orNull
|
|
394
|
+
?: throw GradleException("SEMANTIFOLD_ANDROID_INFRASTRUCTURE: SEMANTIFOLD_KOTLIN_HOME is required")
|
|
395
|
+
val semantifoldKotlinStdlib = file("$semantifoldKotlinHome/lib/kotlin-stdlib.jar")
|
|
396
|
+
if (!semantifoldKotlinStdlib.isFile) {
|
|
397
|
+
throw GradleException("SEMANTIFOLD_ANDROID_INFRASTRUCTURE: pinned Kotlin stdlib is missing")
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
dependencies {
|
|
401
|
+
androidTestImplementation(files(semantifoldKotlinStdlib))
|
|
402
|
+
}
|
|
403
|
+
val semantifoldAcceptanceRoot = providers.environmentVariable("SEMANTIFOLD_ANDROID_ACCEPTANCE_ROOT").orNull
|
|
404
|
+
?: throw GradleException("SEMANTIFOLD_ANDROID_INFRASTRUCTURE: SEMANTIFOLD_ANDROID_ACCEPTANCE_ROOT is required")
|
|
405
|
+
val semantifoldDebugKeystore = file("$semantifoldAcceptanceRoot/debug.keystore")
|
|
406
|
+
if (!semantifoldDebugKeystore.isFile) {
|
|
407
|
+
throw GradleException("SEMANTIFOLD_ANDROID_INFRASTRUCTURE: ephemeral debug keystore is missing")
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
android {
|
|
411
|
+
namespace = "`,
|
|
412
|
+
field("namespace", configuration.namespace), `"\n compileSdk = `, field("compileSdk", String(configuration.compileSdk)),
|
|
413
|
+
`\n buildToolsVersion = "`, field("buildToolsVersion", configuration.buildToolsVersion), `"\n\n defaultConfig {\n applicationId = "`,
|
|
414
|
+
field("applicationId", configuration.applicationId), `"\n minSdk = `, field("minimumSdk", String(configuration.minimumSdk)),
|
|
415
|
+
`\n targetSdk = `, field("targetSdk", String(configuration.targetSdk)), `\n versionCode = `,
|
|
416
|
+
field("versionCode", String(configuration.versionCode)), `\n versionName = "`, field("versionName", kotlinEscape(configuration.versionName)),
|
|
417
|
+
`"\n testApplicationId = "`, field("applicationId", configuration.applicationId),
|
|
418
|
+
`.test"\n testInstrumentationRunner = "`, field("packageName", configuration.packageName),
|
|
419
|
+
`.SemantifoldUiInstrumentation"\n }\n\n signingConfigs {\n getByName("debug") {\n storeFile = semantifoldDebugKeystore\n storePassword = "android"\n keyAlias = "androiddebugkey"\n keyPassword = "android"\n }\n }\n buildTypes {\n getByName("debug") {\n signingConfig = signingConfigs.getByName("debug")\n }\n }\n buildFeatures {\n buildConfig = false\n }\n compileOptions {\n sourceCompatibility = JavaVersion.VERSION_21\n targetCompatibility = JavaVersion.VERSION_21\n }\n lint {\n abortOnError = true\n checkDependencies = true\n disable += "MissingApplicationIcon"\n disable += "OldTargetApi"\n disable += "GradleDependency"\n warningsAsErrors = true\n }\n packaging {\n resources.excludes += setOf("META-INF/LICENSE*", "META-INF/NOTICE*")\n }\n}\n\ntasks.withType<KotlinJvmCompile>().configureEach {\n libraries.from(files(semantifoldKotlinStdlib))\n compilerOptions {\n allWarningsAsErrors.set(true)\n freeCompilerArgs.addAll("-Xno-call-assertions", "-Xno-param-assertions", "-Xno-receiver-assertions")\n jvmTarget.set(JvmTarget.JVM_21)\n }\n}\n\ndependencies {\n testImplementation("junit:junit:4.13.2") {\n isTransitive = false\n }\n}\n`
|
|
420
|
+
]);
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Renders the allowlisted Android application manifest.
|
|
424
|
+
* @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
|
|
425
|
+
* @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
|
|
426
|
+
* @returns {string} Android application manifest.
|
|
427
|
+
*/
|
|
428
|
+
function renderAndroidManifest(configuration, spans) {
|
|
429
|
+
const orientation = configuration.orientation == "unspecified" ? "" : ` android:screenOrientation="${configuration.orientation}"`;
|
|
430
|
+
return configured(`${projectRoot}/app/src/main/AndroidManifest.xml`, spans, [
|
|
431
|
+
`<?xml version="1.0" encoding="utf-8"?>\n<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n <application\n android:allowBackup="false"\n android:dataExtractionRules="@xml/data_extraction_rules"\n android:fullBackupContent="@xml/backup_rules"\n android:label="@string/app_name"\n android:supportsRtl="true"\n android:theme="@style/Theme.Semantifold">\n <activity\n android:name="`,
|
|
432
|
+
field("packageName", configuration.packageName), `.`, field("activityClassName", configuration.activityClassName),
|
|
433
|
+
`"\n android:exported="true"`,
|
|
434
|
+
orientation ? field("orientation", orientation) : "", `>\n <intent-filter>\n <action android:name="android.intent.action.MAIN" />\n <category android:name="android.intent.category.LAUNCHER" />\n </intent-filter>\n </activity>\n </application>\n</manifest>\n`
|
|
435
|
+
]);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Renders explicit API 23-30 exclusions for every full-backup storage domain.
|
|
439
|
+
* @returns {string} Android full-backup rules XML.
|
|
440
|
+
*/
|
|
441
|
+
function renderBackupRules() {
|
|
442
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
443
|
+
<full-backup-content>
|
|
444
|
+
<exclude domain="root" path="." />
|
|
445
|
+
<exclude domain="file" path="." />
|
|
446
|
+
<exclude domain="database" path="." />
|
|
447
|
+
<exclude domain="sharedpref" path="." />
|
|
448
|
+
<exclude domain="external" path="." />
|
|
449
|
+
<exclude domain="device_root" path="." />
|
|
450
|
+
<exclude domain="device_file" path="." />
|
|
451
|
+
<exclude domain="device_database" path="." />
|
|
452
|
+
<exclude domain="device_sharedpref" path="." />
|
|
453
|
+
</full-backup-content>
|
|
454
|
+
`;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Renders explicit Android 12+ exclusions for every cloud-backup and device-transfer storage domain.
|
|
458
|
+
* @returns {string} Android data extraction rules XML.
|
|
459
|
+
*/
|
|
460
|
+
function renderDataExtractionRules() {
|
|
461
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
462
|
+
<data-extraction-rules>
|
|
463
|
+
<cloud-backup>
|
|
464
|
+
<exclude domain="root" path="." />
|
|
465
|
+
<exclude domain="file" path="." />
|
|
466
|
+
<exclude domain="database" path="." />
|
|
467
|
+
<exclude domain="sharedpref" path="." />
|
|
468
|
+
<exclude domain="external" path="." />
|
|
469
|
+
<exclude domain="device_root" path="." />
|
|
470
|
+
<exclude domain="device_file" path="." />
|
|
471
|
+
<exclude domain="device_database" path="." />
|
|
472
|
+
<exclude domain="device_sharedpref" path="." />
|
|
473
|
+
</cloud-backup>
|
|
474
|
+
<device-transfer>
|
|
475
|
+
<exclude domain="root" path="." />
|
|
476
|
+
<exclude domain="file" path="." />
|
|
477
|
+
<exclude domain="database" path="." />
|
|
478
|
+
<exclude domain="sharedpref" path="." />
|
|
479
|
+
<exclude domain="external" path="." />
|
|
480
|
+
<exclude domain="device_root" path="." />
|
|
481
|
+
<exclude domain="device_file" path="." />
|
|
482
|
+
<exclude domain="device_database" path="." />
|
|
483
|
+
<exclude domain="device_sharedpref" path="." />
|
|
484
|
+
</device-transfer>
|
|
485
|
+
</data-extraction-rules>
|
|
486
|
+
`;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Renders the platform-only instrumentation manifest.
|
|
490
|
+
* @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
|
|
491
|
+
* @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
|
|
492
|
+
* @returns {string} Android test manifest.
|
|
493
|
+
*/
|
|
494
|
+
function renderAndroidTestManifest(configuration, spans) {
|
|
495
|
+
return configured(`${projectRoot}/app/src/androidTest/AndroidManifest.xml`, spans, [
|
|
496
|
+
`<?xml version="1.0" encoding="utf-8"?>\n<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n <instrumentation\n android:name="`,
|
|
497
|
+
field("packageName", configuration.packageName), `.SemantifoldUiInstrumentation"\n android:targetPackage="`,
|
|
498
|
+
field("applicationId", xmlEscape(configuration.applicationId)), `" />\n</manifest>\n`
|
|
499
|
+
]);
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Renders the synthetic launcher activity.
|
|
503
|
+
* @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
|
|
504
|
+
* @param {string} entryModule - Selected semantic entry module identity.
|
|
505
|
+
* @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
|
|
506
|
+
* @returns {string} Kotlin launcher activity source.
|
|
507
|
+
*/
|
|
508
|
+
function renderActivity(configuration, entryModule, spans) {
|
|
509
|
+
const resourceImport = configuration.namespace == configuration.packageName
|
|
510
|
+
? []
|
|
511
|
+
: ["import ", field("namespace", configuration.namespace), ".R\n"];
|
|
512
|
+
return configured(`${projectRoot}/app/src/main/kotlin/${configuration.packageName.replaceAll(".", "/")}/${configuration.activityClassName}.kt`, spans, [
|
|
513
|
+
"package ", field("packageName", configuration.packageName), `
|
|
514
|
+
|
|
515
|
+
import android.app.Activity
|
|
516
|
+
import android.annotation.SuppressLint
|
|
517
|
+
import android.os.Bundle
|
|
518
|
+
import android.widget.TextView
|
|
519
|
+
`, ...resourceImport, `import `, field("packageName", configuration.packageName),
|
|
520
|
+
`.semantic.SemantifoldModule${moduleName(entryModule)}
|
|
521
|
+
|
|
522
|
+
class `, field("activityClassName", configuration.activityClassName), ` : Activity() {
|
|
523
|
+
@SuppressLint("SetTextI18n")
|
|
524
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
525
|
+
super.onCreate(savedInstanceState)
|
|
526
|
+
setContentView(R.layout.activity_main)
|
|
527
|
+
val lines = SemantifoldModule${moduleName(entryModule)}.semantifoldEntry()
|
|
528
|
+
val output = java.lang.StringBuilder()
|
|
529
|
+
var index = 0
|
|
530
|
+
while (index < lines.size) {
|
|
531
|
+
if (index > 0) output.append('\\n')
|
|
532
|
+
output.append(lines[index])
|
|
533
|
+
index += 1
|
|
534
|
+
}
|
|
535
|
+
findViewById<TextView>(R.id.semantifold_output).text = output.toString()
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
`
|
|
539
|
+
]);
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Renders the single accessibility-important native text view.
|
|
543
|
+
* @returns {string} Android layout XML.
|
|
544
|
+
*/
|
|
545
|
+
function renderLayout() {
|
|
546
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
547
|
+
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
548
|
+
android:id="@+id/semantifold_output"
|
|
549
|
+
android:layout_width="match_parent"
|
|
550
|
+
android:layout_height="match_parent"
|
|
551
|
+
android:gravity="center"
|
|
552
|
+
android:importantForAccessibility="yes"
|
|
553
|
+
android:textIsSelectable="true" />
|
|
554
|
+
`;
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Renders configuration-derived string resources.
|
|
558
|
+
* @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
|
|
559
|
+
* @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
|
|
560
|
+
* @returns {string} Android string resource XML.
|
|
561
|
+
*/
|
|
562
|
+
function renderStrings(configuration, spans) {
|
|
563
|
+
return configured(`${projectRoot}/app/src/main/res/values/strings.xml`, spans, [
|
|
564
|
+
`<?xml version="1.0" encoding="utf-8"?>\n<resources>\n <string name="app_name">`,
|
|
565
|
+
field("displayName", xmlEscape(configuration.displayName)), `</string>\n</resources>\n`
|
|
566
|
+
]);
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Renders the fixed platform-native baseline theme.
|
|
570
|
+
* @returns {string} Android theme resource XML.
|
|
571
|
+
*/
|
|
572
|
+
function renderTheme() {
|
|
573
|
+
return `<?xml version="1.0" encoding="utf-8"?>
|
|
574
|
+
<resources>
|
|
575
|
+
<style name="Theme.Semantifold" parent="android:style/Theme.Material.Light.NoActionBar">
|
|
576
|
+
<item name="android:fontFamily">sans</item>
|
|
577
|
+
<item name="android:windowActionModeOverlay">true</item>
|
|
578
|
+
</style>
|
|
579
|
+
</resources>
|
|
580
|
+
`;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Renders the sole JUnit test-scope semantic assertion.
|
|
584
|
+
* @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
|
|
585
|
+
* @param {string} entryModule - Selected semantic entry module identity.
|
|
586
|
+
* @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
|
|
587
|
+
* @returns {string} Kotlin unit test source.
|
|
588
|
+
*/
|
|
589
|
+
function renderUnitTest(configuration, entryModule, spans) {
|
|
590
|
+
return configured(`${projectRoot}/app/src/test/kotlin/${configuration.packageName.replaceAll(".", "/")}/SemantifoldEntryTest.kt`, spans, [
|
|
591
|
+
"package ", field("packageName", configuration.packageName), `
|
|
592
|
+
|
|
593
|
+
import `, field("packageName", configuration.packageName), `.semantic.SemantifoldModule${moduleName(entryModule)}
|
|
594
|
+
import org.junit.Test
|
|
595
|
+
|
|
596
|
+
class SemantifoldEntryTest {
|
|
597
|
+
@Test
|
|
598
|
+
fun entryIsDeterministicAcrossFreshRuns() {
|
|
599
|
+
val firstOutput = SemantifoldModule${moduleName(entryModule)}.semantifoldEntry()
|
|
600
|
+
val secondOutput = SemantifoldModule${moduleName(entryModule)}.semantifoldEntry()
|
|
601
|
+
if (!firstOutput.equals(secondOutput)) {
|
|
602
|
+
throw AssertionError("Semantic entry output differs across fresh runs.")
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
`
|
|
607
|
+
]);
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Renders the framework-only instrumentation runner.
|
|
611
|
+
* @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
|
|
612
|
+
* @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
|
|
613
|
+
* @returns {string} Kotlin instrumentation source.
|
|
614
|
+
*/
|
|
615
|
+
function renderInstrumentation(configuration, spans) {
|
|
616
|
+
const resourceImport = configuration.namespace == configuration.packageName
|
|
617
|
+
? []
|
|
618
|
+
: ["import ", field("namespace", configuration.namespace), ".R\n"];
|
|
619
|
+
return configured(`${projectRoot}/app/src/androidTest/kotlin/${configuration.packageName.replaceAll(".", "/")}/SemantifoldUiInstrumentation.kt`, spans, [
|
|
620
|
+
"package ", field("packageName", configuration.packageName), `
|
|
621
|
+
|
|
622
|
+
import android.app.Activity
|
|
623
|
+
import android.app.Instrumentation
|
|
624
|
+
import android.content.Intent
|
|
625
|
+
import android.os.Bundle
|
|
626
|
+
import android.util.Base64
|
|
627
|
+
import android.view.View
|
|
628
|
+
import android.widget.TextView
|
|
629
|
+
import java.nio.charset.StandardCharsets
|
|
630
|
+
`, ...resourceImport, `
|
|
631
|
+
class SemantifoldUiInstrumentation : Instrumentation() {
|
|
632
|
+
private var inputArguments: Bundle? = null
|
|
633
|
+
|
|
634
|
+
override fun onCreate(arguments: Bundle?) {
|
|
635
|
+
inputArguments = arguments
|
|
636
|
+
start()
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
override fun onStart() {
|
|
640
|
+
try {
|
|
641
|
+
val providedArguments = inputArguments
|
|
642
|
+
?: throw IllegalStateException("missing instrumentation arguments")
|
|
643
|
+
val encoded = providedArguments.getString("expected_output_base64")
|
|
644
|
+
?: throw IllegalStateException("missing expected_output_base64 instrumentation argument")
|
|
645
|
+
val expected = String(Base64.decode(encoded, Base64.NO_WRAP), StandardCharsets.UTF_8)
|
|
646
|
+
val launch = targetContext.packageManager.getLaunchIntentForPackage(targetContext.packageName)
|
|
647
|
+
?: throw IllegalStateException("generated application has no launcher intent")
|
|
648
|
+
launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
|
649
|
+
val activity = startActivitySync(launch) as `, field("activityClassName", configuration.activityClassName), `
|
|
650
|
+
assertOutput(activity, expected)
|
|
651
|
+
val monitor = addMonitor(`, field("activityClassName", configuration.activityClassName), `::class.java.name, null, false)
|
|
652
|
+
runOnMainSync { activity.recreate() }
|
|
653
|
+
waitForIdleSync()
|
|
654
|
+
val recreated = waitForMonitorWithTimeout(monitor, 10_000)
|
|
655
|
+
?: throw IllegalStateException("activity was not recreated")
|
|
656
|
+
assertOutput(recreated, expected)
|
|
657
|
+
finish(Activity.RESULT_OK, Bundle())
|
|
658
|
+
} catch (error: Throwable) {
|
|
659
|
+
val result = Bundle()
|
|
660
|
+
result.putString("semantifold_failure", android.util.Log.getStackTraceString(error))
|
|
661
|
+
finish(Activity.RESULT_CANCELED, result)
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
private fun assertOutput(activity: Activity, expected: String) {
|
|
666
|
+
waitForIdleSync()
|
|
667
|
+
val actual = activity.findViewById<TextView>(R.id.semantifold_output)
|
|
668
|
+
?: throw IllegalStateException("missing semantifold_output view")
|
|
669
|
+
if (actual.visibility != View.VISIBLE) throw IllegalStateException("output view is not visible")
|
|
670
|
+
if (actual.javaClass != TextView::class.java) throw IllegalStateException("output view is not a native TextView")
|
|
671
|
+
if (!actual.text.toString().equals(expected)) throw IllegalStateException("output text mismatch")
|
|
672
|
+
if (actual.contentDescription != null) throw IllegalStateException("output content description must stay absent")
|
|
673
|
+
if (actual.importantForAccessibility != View.IMPORTANT_FOR_ACCESSIBILITY_YES) {
|
|
674
|
+
throw IllegalStateException("output view is not accessibility-important")
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
`
|
|
679
|
+
]);
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Renders the ownership, toolchain, and provenance manifest.
|
|
683
|
+
* @param {ReturnType<typeof preflightAndroidApplication>} prepared - Prepared application.
|
|
684
|
+
* @param {import("../semantic/types.js").GeneratedSetArtifact[]} artifacts - Owned project artifacts.
|
|
685
|
+
* @param {string} manifestPath - Ownership manifest path.
|
|
686
|
+
* @param {ConfigurationSpan[]} spans - Configuration provenance spans.
|
|
687
|
+
* @returns {string} Canonical project manifest JSON.
|
|
688
|
+
*/
|
|
689
|
+
function renderProjectManifest(prepared, artifacts, manifestPath, spans) {
|
|
690
|
+
const inputPaths = new Set([...prepared.resources, ...prepared.assets].map(({ fullPath }) => fullPath));
|
|
691
|
+
const semanticArtifacts = artifacts.filter(artifact => artifact.provenance.kind == "text");
|
|
692
|
+
const ownedPaths = [...artifacts.map(({ path }) => path), manifestPath];
|
|
693
|
+
return stringifyCanonicalJson({
|
|
694
|
+
configuration: prepared.configuration,
|
|
695
|
+
generator: { name: "semantifold", version: generatorVersion },
|
|
696
|
+
ownership: {
|
|
697
|
+
excludedPathPatterns,
|
|
698
|
+
ownedPaths,
|
|
699
|
+
ownedRoot: projectRoot,
|
|
700
|
+
sha256: artifacts.map(artifact => ({ path: artifact.path, sha256: hashContent(artifact.content) }))
|
|
701
|
+
},
|
|
702
|
+
provenance: {
|
|
703
|
+
configuration: Object.keys(prepared.configuration).sort().map(fieldName => ({
|
|
704
|
+
field: fieldName,
|
|
705
|
+
manifestPointer: `/configuration/${fieldName}`,
|
|
706
|
+
outputs: configurationOutputs(spans, fieldName)
|
|
707
|
+
})),
|
|
708
|
+
inputs: [...prepared.resources, ...prepared.assets].map(item => ({
|
|
709
|
+
contentKind: item.contentKind,
|
|
710
|
+
mediaType: item.mediaType,
|
|
711
|
+
path: item.fullPath,
|
|
712
|
+
sha256: item.sha256
|
|
713
|
+
})),
|
|
714
|
+
semanticSources: prepared.sources.map(source => ({
|
|
715
|
+
artifacts: semanticArtifacts.filter(artifact => artifact.provenance.kind == "text" &&
|
|
716
|
+
artifact.provenance.mapping.spans.some(({ origin }) => originReferencesFilename(origin, source.filename)))
|
|
717
|
+
.map(({ path }) => path),
|
|
718
|
+
filename: source.filename,
|
|
719
|
+
...(source.language === undefined ? {} : { language: source.language }),
|
|
720
|
+
sha256: createHash("sha256").update(source.content).digest("hex")
|
|
721
|
+
})),
|
|
722
|
+
syntheticScaffolding: [...artifacts.filter(artifact => artifact.provenance.kind == "synthetic" &&
|
|
723
|
+
!inputPaths.has(artifact.path)).map(({ path }) => path), manifestPath]
|
|
724
|
+
},
|
|
725
|
+
schema: "SemantifoldAndroidProject",
|
|
726
|
+
semanticProgram: semanticProgramManifest(prepared),
|
|
727
|
+
target: "android",
|
|
728
|
+
toolchain,
|
|
729
|
+
version: 1
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Renders semantic module and source identities for the project manifest.
|
|
734
|
+
* @param {ReturnType<typeof preflightAndroidApplication>} prepared - Prepared application.
|
|
735
|
+
* @returns {Record<string, unknown>} Semantic program manifest.
|
|
736
|
+
*/
|
|
737
|
+
function semanticProgramManifest(prepared) {
|
|
738
|
+
const sourceContent = new Map(prepared.sources.map(source => [source.filename, source.content]));
|
|
739
|
+
const order = new Map(prepared.program.modules.map((module, index) => [module.id, index]));
|
|
740
|
+
const modules = prepared.program.modules.map(module => {
|
|
741
|
+
const source = prepared.program.sources.find(candidate => candidate.filename == module.sourceFilename);
|
|
742
|
+
const content = sourceContent.get(module.sourceFilename);
|
|
743
|
+
if (!source || content === undefined)
|
|
744
|
+
throw new TypeError(`Preflighted Android module '${module.id}' lost source ownership.`);
|
|
745
|
+
return {
|
|
746
|
+
dependencies: [...new Set(module.imports.map(({ moduleId }) => moduleId))]
|
|
747
|
+
.sort((left, right) => /** @type {number} */ (order.get(left)) - /** @type {number} */ (order.get(right))),
|
|
748
|
+
generatedArtifacts: [prepared.modulePaths.get(module.id)],
|
|
749
|
+
id: module.id,
|
|
750
|
+
namespace: `SemantifoldModule${moduleName(module.id)}`,
|
|
751
|
+
source: { filename: source.filename, id: source.id, sha256: createHash("sha256").update(content).digest("hex") }
|
|
752
|
+
};
|
|
753
|
+
});
|
|
754
|
+
const entryId = prepared.program.entryModule;
|
|
755
|
+
return {
|
|
756
|
+
entry: {
|
|
757
|
+
activityArtifact: `${projectRoot}/app/src/main/kotlin/${prepared.packagePath}/${prepared.configuration.activityClassName}.kt`,
|
|
758
|
+
generatedArtifact: prepared.modulePaths.get(entryId),
|
|
759
|
+
generatedFunctionIdentity: `SemantifoldModule${moduleName(entryId)}.semantifoldEntry`,
|
|
760
|
+
moduleId: entryId
|
|
761
|
+
},
|
|
762
|
+
modules,
|
|
763
|
+
schema: "SemantifoldAndroidSemanticProgram",
|
|
764
|
+
sources: prepared.program.sources.map(source => ({
|
|
765
|
+
filename: source.filename,
|
|
766
|
+
id: source.id,
|
|
767
|
+
language: source.language,
|
|
768
|
+
moduleIds: modules.filter(module => module.source.filename == source.filename).map(({ id }) => id),
|
|
769
|
+
ownership: source.ownership ?? "application",
|
|
770
|
+
sha256: createHash("sha256").update(/** @type {string} */ (sourceContent.get(source.filename))).digest("hex")
|
|
771
|
+
})),
|
|
772
|
+
version: 1
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Validates and normalizes the closed Android configuration.
|
|
777
|
+
* @param {unknown} candidate - Candidate configuration.
|
|
778
|
+
* @returns {import("../semantic/types.js").AndroidApplicationConfiguration} Normalized configuration.
|
|
779
|
+
*/
|
|
780
|
+
function normalizeConfiguration(candidate) {
|
|
781
|
+
if (candidate === undefined)
|
|
782
|
+
candidate = {};
|
|
783
|
+
if (!isPlainObject(candidate) || Object.keys(candidate).some(key => !configurationFields.has(key))) {
|
|
784
|
+
invalidConfiguration("Android application configuration must be a closed plain object.");
|
|
785
|
+
}
|
|
786
|
+
const configuration = /** @type {import("../semantic/types.js").AndroidApplicationConfigurationInput} */ (candidate);
|
|
787
|
+
const applicationId = configuration.applicationId ?? "dev.semantifold.generated";
|
|
788
|
+
const namespace = configuration.namespace ?? applicationId;
|
|
789
|
+
const packageName = configuration.packageName ?? namespace;
|
|
790
|
+
const activityClassName = configuration.activityClassName ?? "MainActivity";
|
|
791
|
+
const productName = configuration.productName ?? "Semantifold";
|
|
792
|
+
const displayName = configuration.displayName ?? "Semantifold";
|
|
793
|
+
const minimumSdk = configuration.minimumSdk ?? 23;
|
|
794
|
+
const targetSdk = configuration.targetSdk ?? toolchain.targetSdk;
|
|
795
|
+
const compileSdk = configuration.compileSdk ?? toolchain.compileSdk;
|
|
796
|
+
const buildToolsVersion = configuration.buildToolsVersion ?? toolchain.buildTools;
|
|
797
|
+
const versionCode = configuration.versionCode ?? 1;
|
|
798
|
+
const versionName = configuration.versionName ?? "1.0.0";
|
|
799
|
+
const orientation = configuration.orientation ?? "unspecified";
|
|
800
|
+
const theme = configuration.theme ?? "system";
|
|
801
|
+
for (const [label, value] of [["Application ID", applicationId], ["Namespace", namespace], ["Package name", packageName]]) {
|
|
802
|
+
if (typeof value != "string" || !isPackageName(value))
|
|
803
|
+
invalidConfiguration(`${label} must be a lowercase Java package identity.`);
|
|
804
|
+
}
|
|
805
|
+
if (typeof activityClassName != "string" || !/^[A-Z][A-Za-z0-9]*$/u.test(activityClassName) || kotlinKeywords.has(activityClassName)) {
|
|
806
|
+
invalidConfiguration("Activity class name must be an ASCII upper-camel Kotlin identifier.");
|
|
807
|
+
}
|
|
808
|
+
for (const [label, value] of [["Product name", productName], ["Display name", displayName]]) {
|
|
809
|
+
if (typeof value != "string" || value.length == 0 || value.trim() != value || [...value].length > 64 ||
|
|
810
|
+
!hasOnlyUnicodeScalars(value) || /[\p{Cc}\p{Zl}\p{Zp}\uFFFE\uFFFF]/u.test(value)) {
|
|
811
|
+
invalidConfiguration(`${label} must be a non-empty single-line Unicode scalar string of at most 64 characters.`);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if (/[\\/:<>"?*|]/u.test(productName)) {
|
|
815
|
+
invalidConfiguration("Product name contains a character forbidden by the Gradle project-name contract.");
|
|
816
|
+
}
|
|
817
|
+
if (minimumSdk !== 23 || targetSdk !== 35 || compileSdk !== 35 || minimumSdk > targetSdk || targetSdk > compileSdk) {
|
|
818
|
+
invalidConfiguration("SDK levels must use the qualified minimum 23, target 35, and compile 35 matrix.");
|
|
819
|
+
}
|
|
820
|
+
if (buildToolsVersion != toolchain.buildTools)
|
|
821
|
+
invalidConfiguration("Build Tools version must be exactly '35.0.0'.");
|
|
822
|
+
if (!Number.isSafeInteger(versionCode) || versionCode < 1 || versionCode > 2_100_000_000) {
|
|
823
|
+
invalidConfiguration("Version code must be a positive Android-safe integer.");
|
|
824
|
+
}
|
|
825
|
+
if (typeof versionName != "string" || !semanticVersionPattern.test(versionName)) {
|
|
826
|
+
invalidConfiguration("Version name must be a canonical non-empty semantic version string.");
|
|
827
|
+
}
|
|
828
|
+
if (orientation != "unspecified")
|
|
829
|
+
invalidConfiguration("The baseline orientation is exactly 'unspecified'.");
|
|
830
|
+
if (theme != "system")
|
|
831
|
+
invalidConfiguration("The baseline theme is exactly 'system'.");
|
|
832
|
+
if (configuration.permissions !== undefined &&
|
|
833
|
+
(!isDenseArray(configuration.permissions) || configuration.permissions.length != 0)) {
|
|
834
|
+
invalidConfiguration("The baseline Android permission set must be empty.");
|
|
835
|
+
}
|
|
836
|
+
return {
|
|
837
|
+
activityClassName,
|
|
838
|
+
applicationId,
|
|
839
|
+
buildToolsVersion,
|
|
840
|
+
compileSdk,
|
|
841
|
+
displayName,
|
|
842
|
+
minimumSdk,
|
|
843
|
+
namespace,
|
|
844
|
+
orientation,
|
|
845
|
+
packageName,
|
|
846
|
+
productName,
|
|
847
|
+
targetSdk,
|
|
848
|
+
theme,
|
|
849
|
+
versionCode,
|
|
850
|
+
versionName
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Validates, snapshots, and orders caller-provided inputs.
|
|
855
|
+
* @param {unknown} candidate - Candidate resource or asset list.
|
|
856
|
+
* @param {"asset" | "resource"} kind - Android input kind.
|
|
857
|
+
* @returns {AndroidInputFile[]} Normalized inputs.
|
|
858
|
+
*/
|
|
859
|
+
function normalizeInputFiles(candidate, kind) {
|
|
860
|
+
if (candidate === undefined)
|
|
861
|
+
return [];
|
|
862
|
+
if (!isDenseArray(candidate))
|
|
863
|
+
invalidResource(`Application ${kind}s must be a dense array.`);
|
|
864
|
+
/** @type {AndroidInputFile[]} */
|
|
865
|
+
const files = [];
|
|
866
|
+
for (let index = 0; index < candidate.length; index += 1) {
|
|
867
|
+
const item = candidate[index];
|
|
868
|
+
if (!isPlainObject(item) || Object.keys(item).length != resourceFields.size ||
|
|
869
|
+
Object.keys(item).some(key => !resourceFields.has(key)))
|
|
870
|
+
invalidResource(`${capitalize(kind)} ${index} must use the closed input schema.`);
|
|
871
|
+
const path = item.path;
|
|
872
|
+
const content = item.content;
|
|
873
|
+
const mediaType = item.mediaType;
|
|
874
|
+
const sha256 = item.sha256;
|
|
875
|
+
if (!isSafeArtifactPath(path) || kind == "resource" && !isAllowedResourcePath(path)) {
|
|
876
|
+
invalidResource(`${capitalize(kind)} ${index} has an unsafe or unsupported path.`);
|
|
877
|
+
}
|
|
878
|
+
if (typeof content != "string" && !(content instanceof Uint8Array) || typeof content == "string" &&
|
|
879
|
+
(content.length == 0 || !hasOnlyUnicodeScalars(content)) || content instanceof Uint8Array && content.byteLength == 0) {
|
|
880
|
+
invalidResource(`${capitalize(kind)} '${path}' requires non-empty exact content.`);
|
|
881
|
+
}
|
|
882
|
+
if (typeof mediaType != "string" || !mediaTypePattern.test(mediaType) || /[\r\n]/u.test(mediaType)) {
|
|
883
|
+
invalidResource(`${capitalize(kind)} '${path}' requires an explicit valid media type.`);
|
|
884
|
+
}
|
|
885
|
+
if (kind == "resource" && path.startsWith("drawable-") && !["image/png", "image/webp"].includes(mediaType)) {
|
|
886
|
+
invalidResource(`Drawable resource '${path}' must use PNG or WebP media type.`);
|
|
887
|
+
}
|
|
888
|
+
const snapshot = typeof content == "string" ? content : new Uint8Array(content);
|
|
889
|
+
const actualHash = createHash("sha256").update(snapshot).digest("hex");
|
|
890
|
+
if (typeof sha256 != "string" || !/^[0-9a-f]{64}$/u.test(sha256) || sha256 != actualHash) {
|
|
891
|
+
invalidResource(`${capitalize(kind)} '${path}' SHA-256 does not match its exact content.`);
|
|
892
|
+
}
|
|
893
|
+
const fullPath = `${projectRoot}/app/src/main/${kind == "resource" ? "res" : "assets"}/${path}`;
|
|
894
|
+
files.push({ content: snapshot, contentKind: typeof snapshot == "string" ? "text" : "binary", fullPath, mediaType, path, sha256 });
|
|
895
|
+
}
|
|
896
|
+
files.sort((left, right) => left.fullPath < right.fullPath ? -1 : left.fullPath > right.fullPath ? 1 : 0);
|
|
897
|
+
const conflict = findPortableArtifactPathConflict(files.map(({ fullPath }) => fullPath));
|
|
898
|
+
if (conflict)
|
|
899
|
+
invalidResource(`${capitalize(kind)} path '${conflict.path}' has a ${conflict.kind} conflict.`);
|
|
900
|
+
if (kind == "resource")
|
|
901
|
+
validateResourceIdentifiers(files);
|
|
902
|
+
return files;
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Rejects two files that Android would compile to the same resource identifier in one configuration.
|
|
906
|
+
* @param {AndroidInputFile[]} files - Validated resource inputs.
|
|
907
|
+
*/
|
|
908
|
+
function validateResourceIdentifiers(files) {
|
|
909
|
+
const identifiers = new Map();
|
|
910
|
+
for (const file of files) {
|
|
911
|
+
const separator = file.path.indexOf("/");
|
|
912
|
+
const directory = file.path.slice(0, separator);
|
|
913
|
+
const filename = file.path.slice(separator + 1);
|
|
914
|
+
const extension = filename.indexOf(".");
|
|
915
|
+
const name = extension == -1 ? filename : filename.slice(0, extension);
|
|
916
|
+
const resourceType = directory.split("-", 1)[0];
|
|
917
|
+
const key = `${directory}/${name}`;
|
|
918
|
+
const previous = identifiers.get(key);
|
|
919
|
+
if (previous) {
|
|
920
|
+
invalidResource(`Android resource identifier '${resourceType}/${name}' collides between '${previous}' and '${file.path}' in configuration '${directory}'.`);
|
|
921
|
+
}
|
|
922
|
+
identifiers.set(key, file.path);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* Tests whether a caller resource uses the narrow allowlisted resource grammar.
|
|
927
|
+
* @param {string} value - Resource path relative to res.
|
|
928
|
+
* @returns {boolean} Whether the path is supported.
|
|
929
|
+
*/
|
|
930
|
+
function isAllowedResourcePath(value) {
|
|
931
|
+
if (/^raw\/[a-z][a-z0-9_]*(?:\.[a-z0-9]+)?$/u.test(value))
|
|
932
|
+
return true;
|
|
933
|
+
return /^drawable-(?:mdpi|hdpi|xhdpi|xxhdpi|xxxhdpi)\/[a-z][a-z0-9_]*\.(?:png|webp)$/u.test(value);
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Converts a validated input snapshot into an owned artifact.
|
|
937
|
+
* @param {AndroidInputFile} item - Validated caller input.
|
|
938
|
+
* @returns {import("../semantic/types.js").GeneratedSetArtifact} Owned input artifact.
|
|
939
|
+
*/
|
|
940
|
+
function inputFileArtifact(item) {
|
|
941
|
+
const reason = `Exact caller-provided Android input (sha256:${item.sha256}).`;
|
|
942
|
+
if (typeof item.content == "string") {
|
|
943
|
+
return {
|
|
944
|
+
...syntheticText(item.fullPath, "resource", item.content, reason),
|
|
945
|
+
mediaType: item.mediaType
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
const content = new Uint8Array(item.content);
|
|
949
|
+
return {
|
|
950
|
+
content,
|
|
951
|
+
contentKind: "binary",
|
|
952
|
+
mediaType: item.mediaType,
|
|
953
|
+
ownership: "generated",
|
|
954
|
+
path: item.fullPath,
|
|
955
|
+
provenance: { kind: "bytes", mapping: createByteMapping({
|
|
956
|
+
byteLength: content.byteLength,
|
|
957
|
+
path: item.fullPath,
|
|
958
|
+
ranges: [{ generated: { end: content.byteLength, start: 0 },
|
|
959
|
+
origin: { kind: "synthetic", reason, relatedOrigins: [] }, role: "resource" }]
|
|
960
|
+
}) },
|
|
961
|
+
role: "resource"
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Creates a deterministic synthetic text artifact.
|
|
966
|
+
* @param {string} path - Artifact path.
|
|
967
|
+
* @param {import("../semantic/types.js").GeneratedArtifactRole} role - Artifact role.
|
|
968
|
+
* @param {string} content - UTF-8 artifact content.
|
|
969
|
+
* @param {string} reason - Synthetic provenance reason.
|
|
970
|
+
* @returns {import("../semantic/types.js").GeneratedSetArtifact} Text artifact.
|
|
971
|
+
*/
|
|
972
|
+
function syntheticText(path, role, content, reason) {
|
|
973
|
+
return { content, contentKind: "text", mediaType: mediaTypeFor(path), ownership: "generated", path,
|
|
974
|
+
provenance: { kind: "synthetic", reason, relatedOrigins: [] }, role };
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Creates a configuration-derived text artifact.
|
|
978
|
+
* @param {string} path - Artifact path.
|
|
979
|
+
* @param {import("../semantic/types.js").GeneratedArtifactRole} role - Artifact role.
|
|
980
|
+
* @param {string} content - UTF-8 artifact content.
|
|
981
|
+
* @param {string} reason - Synthetic provenance reason.
|
|
982
|
+
* @returns {import("../semantic/types.js").GeneratedSetArtifact} Text artifact.
|
|
983
|
+
*/
|
|
984
|
+
function configuredText(path, role, content, reason) {
|
|
985
|
+
return syntheticText(path, role, content, reason);
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Derives the media type for a generated text path.
|
|
989
|
+
* @param {string} path - Generated artifact path.
|
|
990
|
+
* @returns {string} Artifact media type.
|
|
991
|
+
*/
|
|
992
|
+
function mediaTypeFor(path) {
|
|
993
|
+
if (path.endsWith(".json"))
|
|
994
|
+
return "application/json";
|
|
995
|
+
if (path.endsWith(".xml"))
|
|
996
|
+
return "application/xml";
|
|
997
|
+
if (path.endsWith(".kt") || path.endsWith(".kts"))
|
|
998
|
+
return "text/x-kotlin";
|
|
999
|
+
return "text/plain";
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Marks one rendered value as configuration-derived.
|
|
1003
|
+
* @param {string} fieldName - Configuration field name.
|
|
1004
|
+
* @param {string} value - Rendered field value.
|
|
1005
|
+
* @returns {{field: string, value: string}} Marked configuration value.
|
|
1006
|
+
*/
|
|
1007
|
+
function field(fieldName, value) {
|
|
1008
|
+
return { field: fieldName, value };
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Joins rendered parts while recording configuration causality.
|
|
1012
|
+
* @param {string} path - Output artifact path.
|
|
1013
|
+
* @param {ConfigurationSpan[]} spans - Mutable provenance span collector.
|
|
1014
|
+
* @param {(string | {field: string, value: string})[]} parts - Synthetic and marked parts.
|
|
1015
|
+
* @returns {string} Rendered text.
|
|
1016
|
+
*/
|
|
1017
|
+
function configured(path, spans, parts) {
|
|
1018
|
+
let content = "";
|
|
1019
|
+
for (const part of parts) {
|
|
1020
|
+
if (typeof part == "string")
|
|
1021
|
+
content += part;
|
|
1022
|
+
else {
|
|
1023
|
+
const start = content.length;
|
|
1024
|
+
content += part.value;
|
|
1025
|
+
spans.push({ end: content.length, field: part.field, path, start });
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
return content;
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Groups configuration spans by artifact.
|
|
1032
|
+
* @param {ConfigurationSpan[]} spans - All rendered configuration spans.
|
|
1033
|
+
* @param {string} fieldName - Requested configuration field.
|
|
1034
|
+
* @returns {{path: string, ranges: {end: number, start: number}[]}[]} Output ranges.
|
|
1035
|
+
*/
|
|
1036
|
+
function configurationOutputs(spans, fieldName) {
|
|
1037
|
+
const grouped = new Map();
|
|
1038
|
+
for (const span of spans) {
|
|
1039
|
+
if (span.field != fieldName)
|
|
1040
|
+
continue;
|
|
1041
|
+
const ranges = grouped.get(span.path) ?? [];
|
|
1042
|
+
ranges.push({ end: span.end, start: span.start });
|
|
1043
|
+
grouped.set(span.path, ranges);
|
|
1044
|
+
}
|
|
1045
|
+
return [...grouped].map(([path, ranges]) => ({ path, ranges }));
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Tests whether a mapping origin refers to one semantic source file.
|
|
1049
|
+
* @param {import("../semantic/types.js").SemanticOrigin} origin - Mapping origin.
|
|
1050
|
+
* @param {string} filename - Semantic source filename.
|
|
1051
|
+
* @returns {boolean} Whether the origin owns the filename.
|
|
1052
|
+
*/
|
|
1053
|
+
function originReferencesFilename(origin, filename) {
|
|
1054
|
+
if (origin.kind == "source")
|
|
1055
|
+
return origin.location.filename == filename;
|
|
1056
|
+
if (origin.kind == "derived")
|
|
1057
|
+
return origin.origins.some(({ location }) => location.filename == filename);
|
|
1058
|
+
return origin.relatedOrigins.some(({ location }) => location.filename == filename);
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Hashes exact text or bytes for ownership records.
|
|
1062
|
+
* @param {string | Uint8Array} content - Exact artifact content.
|
|
1063
|
+
* @returns {string} Lowercase SHA-256 digest.
|
|
1064
|
+
*/
|
|
1065
|
+
function hashContent(content) {
|
|
1066
|
+
return createHash("sha256").update(content).digest("hex");
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Serializes JSON with recursively stable object-key ordering.
|
|
1070
|
+
* @param {unknown} value - JSON-compatible value.
|
|
1071
|
+
* @returns {string} Canonical indented JSON with trailing newline.
|
|
1072
|
+
*/
|
|
1073
|
+
function stringifyCanonicalJson(value) {
|
|
1074
|
+
return `${JSON.stringify(sortJson(value), null, 2)}\n`;
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Recursively sorts object keys without changing array order.
|
|
1078
|
+
* @param {unknown} value - JSON-compatible value.
|
|
1079
|
+
* @returns {unknown} Canonically ordered value.
|
|
1080
|
+
*/
|
|
1081
|
+
function sortJson(value) {
|
|
1082
|
+
if (Array.isArray(value))
|
|
1083
|
+
return value.map(sortJson);
|
|
1084
|
+
if (!isPlainObject(value))
|
|
1085
|
+
return value;
|
|
1086
|
+
return Object.fromEntries(Object.keys(value).sort().map(key => [key, sortJson(value[key])]));
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Tests a lowercase Kotlin-compatible package identity.
|
|
1090
|
+
* @param {string} value - Candidate package name.
|
|
1091
|
+
* @returns {boolean} Whether the name is accepted.
|
|
1092
|
+
*/
|
|
1093
|
+
function isPackageName(value) {
|
|
1094
|
+
const parts = value.split(".");
|
|
1095
|
+
return parts.length >= 2 && parts.every(part => /^[a-z][a-z0-9_]*$/u.test(part) && !kotlinKeywords.has(part));
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Rejects launcher names that shadow an unqualified symbol in generated same-package Kotlin.
|
|
1099
|
+
* @param {string} activityClassName - Validated launcher class name.
|
|
1100
|
+
* @param {string} entryModule - Selected semantic entry module.
|
|
1101
|
+
*/
|
|
1102
|
+
function validateActivityClassName(activityClassName, entryModule) {
|
|
1103
|
+
const semanticEntrySymbol = `SemantifoldModule${moduleName(entryModule)}`;
|
|
1104
|
+
if (androidScaffoldSymbols.has(activityClassName) || activityClassName == semanticEntrySymbol) {
|
|
1105
|
+
invalidConfiguration(`Activity class name '${activityClassName}' collides with generated Kotlin symbol '${activityClassName}'.`);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Allocates one module-wide output sink that cannot shadow a source binding.
|
|
1110
|
+
* @param {import("../semantic/types.js").SemanticModule} module - Prepared semantic module.
|
|
1111
|
+
* @returns {string} Collision-safe Kotlin binding.
|
|
1112
|
+
*/
|
|
1113
|
+
function outputSinkName(module) {
|
|
1114
|
+
const bindings = new Set(module.functions.flatMap(declaration => declaration.parameters.map(({ name }) => name)));
|
|
1115
|
+
for (const declaration of module.functions)
|
|
1116
|
+
collectBlockBindingNames(declaration.body, bindings);
|
|
1117
|
+
collectBlockBindingNames(module.entryPoint.body, bindings);
|
|
1118
|
+
let candidate = "semantifoldOutput";
|
|
1119
|
+
while (bindings.has(candidate))
|
|
1120
|
+
candidate += "_";
|
|
1121
|
+
return candidate;
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Collects local bindings recursively from the supported semantic block subset.
|
|
1125
|
+
* @param {import("../semantic/types.js").Block} block - Semantic block.
|
|
1126
|
+
* @param {Set<string>} bindings - Mutable binding-name set.
|
|
1127
|
+
*/
|
|
1128
|
+
function collectBlockBindingNames(block, bindings) {
|
|
1129
|
+
for (const statement of block.statements) {
|
|
1130
|
+
if (statement.kind == "LocalDeclaration")
|
|
1131
|
+
bindings.add(statement.name);
|
|
1132
|
+
else if (statement.kind == "IfStatement") {
|
|
1133
|
+
collectBlockBindingNames(statement.consequent, bindings);
|
|
1134
|
+
if (statement.alternate)
|
|
1135
|
+
collectBlockBindingNames(statement.alternate, bindings);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Maps a preflighted module identity to a stable Kotlin suffix.
|
|
1141
|
+
* @param {string} id - Semantic module identity.
|
|
1142
|
+
* @returns {string} Kotlin object-name suffix.
|
|
1143
|
+
*/
|
|
1144
|
+
function moduleName(id) {
|
|
1145
|
+
return id.split(/[._-]+/u).map(part => `${part[0].toUpperCase()}${part.slice(1)}`).join("");
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Wraps legacy single-module input in the canonical program contract.
|
|
1149
|
+
* @param {import("../semantic/types.js").SemanticModule | undefined} candidate - Candidate semantic module.
|
|
1150
|
+
* @returns {import("../semantic/types.js").SemanticProgram} Canonical single-module program.
|
|
1151
|
+
*/
|
|
1152
|
+
function normalizeSingleModule(candidate) {
|
|
1153
|
+
if (!isPlainObject(candidate))
|
|
1154
|
+
unsupportedCapability("android", "missing or invalid module", undefined);
|
|
1155
|
+
const module = structuredClone(candidate);
|
|
1156
|
+
const sources = module.provenance?.sources;
|
|
1157
|
+
if (!Array.isArray(sources) || sources.length != 1 || sources[0].content === null ||
|
|
1158
|
+
sources[0].filename != module.location?.filename || typeof sources[0].language != "string") {
|
|
1159
|
+
unsupportedCapability("android", "single-module source ownership", module.location);
|
|
1160
|
+
}
|
|
1161
|
+
rekeyModuleDeclarations(module, "main");
|
|
1162
|
+
const exports = [
|
|
1163
|
+
...(module.records ?? []).map(declaration => applicationExport(declaration, "record")),
|
|
1164
|
+
...(module.classes ?? []).map(declaration => applicationExport(declaration, "class")),
|
|
1165
|
+
...(module.errors ?? []).map(declaration => applicationExport(declaration, "error")),
|
|
1166
|
+
...module.functions.map(declaration => applicationExport(declaration, "function"))
|
|
1167
|
+
];
|
|
1168
|
+
const programModule = { ...module, exports, id: "main", imports: [], sourceFilename: sources[0].filename };
|
|
1169
|
+
return { entryModule: "main", kind: "Program", modules: [programModule], sources: structuredClone(sources) };
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Creates an application-local export record for single-module compatibility.
|
|
1173
|
+
* @param {{id?: string, location: import("../semantic/types.js").SourceLocation, name: string}} declaration - Semantic declaration.
|
|
1174
|
+
* @param {import("../semantic/types.js").SemanticDeclarationKind} symbolKind - Declaration kind.
|
|
1175
|
+
* @returns {import("../semantic/types.js").SemanticExport} Semantic export.
|
|
1176
|
+
*/
|
|
1177
|
+
function applicationExport(declaration, symbolKind) {
|
|
1178
|
+
return { declarationId: /** @type {string} */ (declaration.id), exportedName: declaration.name,
|
|
1179
|
+
kind: /** @type {const} */ ("Export"), location: declaration.location, symbolKind };
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Qualifies single-module declaration identities before program preflight.
|
|
1183
|
+
* @param {import("../semantic/types.js").SemanticModule} module - Cloned semantic module.
|
|
1184
|
+
* @param {string} moduleId - Canonical module identity.
|
|
1185
|
+
*/
|
|
1186
|
+
function rekeyModuleDeclarations(module, moduleId) {
|
|
1187
|
+
const declarations = [...module.records ?? [], ...module.classes ?? [], ...module.errors ?? [], ...module.functions];
|
|
1188
|
+
const replacements = new Map(declarations.filter(declaration => typeof declaration.id == "string")
|
|
1189
|
+
.map(declaration => [declaration.id, `${moduleId}#${declaration.id}`]));
|
|
1190
|
+
for (const declaration of declarations)
|
|
1191
|
+
if (typeof declaration.id == "string")
|
|
1192
|
+
declaration.id = replacements.get(declaration.id);
|
|
1193
|
+
const seen = new Set();
|
|
1194
|
+
const identityFields = new Set(["classId", "declarationId", "field", "method", "parameterId"]);
|
|
1195
|
+
/**
|
|
1196
|
+
* Rewrites declaration references throughout one semantic value graph.
|
|
1197
|
+
* @param {unknown} value - Candidate nested semantic value.
|
|
1198
|
+
*/
|
|
1199
|
+
const visit = value => {
|
|
1200
|
+
if (!value || typeof value != "object" || seen.has(value))
|
|
1201
|
+
return;
|
|
1202
|
+
seen.add(value);
|
|
1203
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
1204
|
+
if (!Array.isArray(value) && identityFields.has(key) && typeof nested == "string" && replacements.has(nested)) {
|
|
1205
|
+
Reflect.set(value, key, replacements.get(nested));
|
|
1206
|
+
}
|
|
1207
|
+
else
|
|
1208
|
+
visit(nested);
|
|
1209
|
+
}
|
|
1210
|
+
};
|
|
1211
|
+
visit(module);
|
|
1212
|
+
}
|
|
1213
|
+
/**
|
|
1214
|
+
* Escapes a configuration value for XML text or attributes.
|
|
1215
|
+
* @param {string} value - Raw configuration value.
|
|
1216
|
+
* @returns {string} XML-safe value.
|
|
1217
|
+
*/
|
|
1218
|
+
function xmlEscape(value) {
|
|
1219
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">")
|
|
1220
|
+
.replaceAll('"', """).replaceAll("'", "'");
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Escapes a configuration value for a Kotlin string literal body.
|
|
1224
|
+
* @param {string} value - Raw configuration value.
|
|
1225
|
+
* @returns {string} Kotlin-safe value.
|
|
1226
|
+
*/
|
|
1227
|
+
function kotlinEscape(value) {
|
|
1228
|
+
return value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("$", "\\$");
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Uppercases the initial ASCII character of a known non-empty word.
|
|
1232
|
+
* @param {string} value - Non-empty word.
|
|
1233
|
+
* @returns {string} Capitalized word.
|
|
1234
|
+
*/
|
|
1235
|
+
function capitalize(value) {
|
|
1236
|
+
return `${value[0].toUpperCase()}${value.slice(1)}`;
|
|
1237
|
+
}
|
|
1238
|
+
/**
|
|
1239
|
+
* Tests whether a value is a plain data object.
|
|
1240
|
+
* @param {unknown} value - Candidate value.
|
|
1241
|
+
* @returns {value is Record<string, unknown>} Whether the value is a plain object.
|
|
1242
|
+
*/
|
|
1243
|
+
function isPlainObject(value) {
|
|
1244
|
+
return Boolean(value) && typeof value == "object" && !Array.isArray(value) && Object.getPrototypeOf(value) == Object.prototype;
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Throws a stable invalid-request diagnostic.
|
|
1248
|
+
* @param {string} message - Diagnostic message.
|
|
1249
|
+
* @returns {never} Never returns.
|
|
1250
|
+
*/
|
|
1251
|
+
function invalidInput(message) {
|
|
1252
|
+
throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_INPUT", language: "android", message });
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Throws a stable invalid-configuration diagnostic.
|
|
1256
|
+
* @param {string} message - Diagnostic message.
|
|
1257
|
+
* @returns {never} Never returns.
|
|
1258
|
+
*/
|
|
1259
|
+
function invalidConfiguration(message) {
|
|
1260
|
+
throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_CONFIGURATION", language: "android", message });
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Throws a stable invalid-resource diagnostic.
|
|
1264
|
+
* @param {string} message - Diagnostic message.
|
|
1265
|
+
* @returns {never} Never returns.
|
|
1266
|
+
*/
|
|
1267
|
+
function invalidResource(message) {
|
|
1268
|
+
throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_RESOURCE", language: "android", message });
|
|
1269
|
+
}
|
|
1270
|
+
/**
|
|
1271
|
+
* Throws a stable invalid-path diagnostic.
|
|
1272
|
+
* @param {string} message - Diagnostic message.
|
|
1273
|
+
* @returns {never} Never returns.
|
|
1274
|
+
*/
|
|
1275
|
+
function invalidPath(message) {
|
|
1276
|
+
throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_PATH", language: "android", message });
|
|
1277
|
+
}
|
|
1278
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5kcm9pZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZW5kcy9hbmRyb2lkLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sYUFBYSxDQUFBO0FBQ3RDLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxhQUFhLENBQUE7QUFDeEMsT0FBTyxFQUFDLGdDQUFnQyxFQUFFLGtCQUFrQixFQUFDLE1BQU0scUJBQXFCLENBQUE7QUFDeEYsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0sc0JBQXNCLENBQUE7QUFDdEQsT0FBTyxFQUFDLHFCQUFxQixFQUFFLHFCQUFxQixFQUFDLE1BQU0sa0JBQWtCLENBQUE7QUFDN0UsT0FBTyxFQUFDLGVBQWUsRUFBRSxhQUFhLEVBQUMsTUFBTSxlQUFlLENBQUE7QUFDNUQsT0FBTyxFQUFDLHFCQUFxQixFQUFDLE1BQU0sd0JBQXdCLENBQUE7QUFDNUQsT0FBTyxFQUFDLHdCQUF3QixFQUFDLE1BQU0sY0FBYyxDQUFBO0FBQ3JELE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSxjQUFjLENBQUE7QUFDM0MsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLHFCQUFxQixDQUFBO0FBQ2pELE9BQU8sRUFBQyxlQUFlLEVBQUMsTUFBTSxhQUFhLENBQUE7QUFDM0MsT0FBTyxFQUFDLFlBQVksRUFBQyxNQUFNLGFBQWEsQ0FBQTtBQUV4QyxNQUFNLFdBQVcsR0FBRyx1QkFBdUIsQ0FBQTtBQUMzQyxNQUFNLGdCQUFnQixHQUFHLE9BQU8sQ0FBQTtBQUNoQyw2RUFBNkU7QUFDN0UsTUFBTSxzQkFBc0IsR0FBRyxJQUFJLEdBQUcsQ0FBQztJQUNyQyxLQUFLLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsS0FB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QUFhLENBQUMsS0FBSztJQUMxQixPQUFPLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxPQUFPLEtBQUssSUFBSSxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLFNBQVMsQ0FBQTtBQUNoSSxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsWUFBWSxDQUFDLE9BQU87SUFDM0IsTUFBTSxJQUFJLHFCQUFxQixDQUFDLEVBQUMsSUFBSSxFQUFFLDJCQUEyQixFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFDLENBQUMsQ0FBQTtBQUNwRyxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsb0JBQW9CLENBQUMsT0FBTztJQUNuQyxNQUFNLElBQUkscUJBQXFCLENBQUMsRUFBQyxJQUFJLEVBQUUsbUNBQW1DLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUMsQ0FBQyxDQUFBO0FBQzVHLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxlQUFlLENBQUMsT0FBTztJQUM5QixNQUFNLElBQUkscUJBQXFCLENBQUMsRUFBQyxJQUFJLEVBQUUsOEJBQThCLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUMsQ0FBQyxDQUFBO0FBQ3ZHLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxXQUFXLENBQUMsT0FBTztJQUMxQixNQUFNLElBQUkscUJBQXFCLENBQUMsRUFBQyxJQUFJLEVBQUUsMEJBQTBCLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUMsQ0FBQyxDQUFBO0FBQ25HLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IHtjcmVhdGVIYXNofSBmcm9tIFwibm9kZTpjcnlwdG9cIlxuaW1wb3J0IHtpc0RlbnNlQXJyYXl9IGZyb20gXCIuLi9hcnJheS5qc1wiXG5pbXBvcnQge2ZpbmRQb3J0YWJsZUFydGlmYWN0UGF0aENvbmZsaWN0LCBpc1NhZmVBcnRpZmFjdFBhdGh9IGZyb20gXCIuLi9hcnRpZmFjdC1wYXRoLmpzXCJcbmltcG9ydCB7Y3JlYXRlQnl0ZU1hcHBpbmd9IGZyb20gXCIuLi9iaW5hcnktbWFwcGluZy5qc1wiXG5pbXBvcnQge1NlbWFudGlmb2xkRGlhZ25vc3RpYywgdW5zdXBwb3J0ZWRDYXBhYmlsaXR5fSBmcm9tIFwiLi4vZGlhZ25vc3RpYy5qc1wiXG5pbXBvcnQge2ZpbmFsaXplTWFwcGluZywgdG9Tb3VyY2VNYXBWM30gZnJvbSBcIi4uL21hcHBpbmcuanNcIlxuaW1wb3J0IHtoYXNPbmx5VW5pY29kZVNjYWxhcnN9IGZyb20gXCIuLi9zZW1hbnRpYy9zY2FsYXJzLmpzXCJcbmltcG9ydCB7cHJlZmxpZ2h0U2VtYW50aWNQcm9ncmFtfSBmcm9tIFwiLi9wcm9ncmFtLmpzXCJcbmltcG9ydCB7ZW1pdFNjYWxhclR5cGV9IGZyb20gXCIuL3NjYWxhcnMuanNcIlxuaW1wb3J0IHtrb3RsaW5SdW50aW1lfSBmcm9tIFwiLi9rb3RsaW4tcnVudGltZS5qc1wiXG5pbXBvcnQge2VtaXRLb3RsaW5CbG9ja30gZnJvbSBcIi4va290bGluLmpzXCJcbmltcG9ydCB7U291cmNlV3JpdGVyfSBmcm9tIFwiLi93cml0ZXIuanNcIlxuXG5jb25zdCBwcm9qZWN0Um9vdCA9IFwiZ2VuZXJhdGVkL2FuZHJvaWQtYXBwXCJcbmNvbnN0IGdlbmVyYXRvclZlcnNpb24gPSBcIjAuNC4wXCJcbi8qKiBAdHlwZSB7UmVhZG9ubHk8U2V0PGltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljTGFuZ3VhZ2U+Pn0gKi9cbmNvbnN0IGFuZHJvaWRTb3VyY2VMYW5ndWFnZXMgPSBuZXcgU2V0KFtcbiAgXCJwaHBcIiwgXCJydWJ5XCIsIFwiamF2YXNjcmlwdFwiLCBcInR5cGVzY3JpcHRcIiwgXCJqYXZhXCIsIFwia290bGluXCIsIFwicHl0aG9uXCIsIFwiY3NoYXJwXCIsIFwiZ29cIiwgXCJjXCIsIFwiY3BwXCIsIFwicnVzdFwiLCBcInN3aWZ0XCIsIFwiZGFydFwiLCBcInppZ1wiXG5dKVxuY29uc3QgcmVxdWVzdEZpZWxkcyA9IG5ldyBTZXQoW1wiYXNzZXRzXCIsIFwiY29uZmlndXJhdGlvblwiLCBcImxhbmd1YWdlXCIsIFwibW9kdWxlXCIsIFwicHJvZ3JhbVwiLCBcInJlc291cmNlc1wiLCBcInJvbGVcIl0pXG5jb25zdCBjb25maWd1cmF0aW9uRmllbGRzID0gbmV3IFNldChbXG4gIFwiYWN0aXZpdHlDbGFzc05hbWVcIiwgXCJhcHBsaWNhdGlvbklkXCIsIFwiYnVpbGRUb29sc1ZlcnNpb25cIiwgXCJjb21waWxlU2RrXCIsIFwiZGlzcGxheU5hbWVcIiwgXCJtaW5pbXVtU2RrXCIsIFwibmFtZXNwYWNlXCIsXG4gIFwib3JpZW50YXRpb25cIiwgXCJwYWNrYWdlTmFtZVwiLCBcInBlcm1pc3Npb25zXCIsIFwicHJvZHVjdE5hbWVcIiwgXCJ0YXJnZXRTZGtcIiwgXCJ0aGVtZVwiLCBcInZlcnNpb25Db2RlXCIsIFwidmVyc2lvbk5hbWVcIlxuXSlcbmNvbnN0IHJlc291cmNlRmllbGRzID0gbmV3IFNldChbXCJjb250ZW50XCIsIFwibWVkaWFUeXBlXCIsIFwicGF0aFwiLCBcInNoYTI1NlwiXSlcbmNvbnN0IGtvdGxpbktleXdvcmRzID0gbmV3IFNldChbXG4gIFwiYXNcIiwgXCJicmVha1wiLCBcImNsYXNzXCIsIFwiY29udGludWVcIiwgXCJkb1wiLCBcImVsc2VcIiwgXCJmYWxzZVwiLCBcImZvclwiLCBcImZ1blwiLCBcImlmXCIsIFwiaW5cIiwgXCJpbnRlcmZhY2VcIiwgXCJpc1wiLCBcIm51bGxcIixcbiAgXCJvYmplY3RcIiwgXCJwYWNrYWdlXCIsIFwicmV0dXJuXCIsIFwic3VwZXJcIiwgXCJ0aGlzXCIsIFwidGhyb3dcIiwgXCJ0cnVlXCIsIFwidHJ5XCIsIFwidHlwZWFsaWFzXCIsIFwidHlwZW9mXCIsIFwidmFsXCIsIFwidmFyXCIsIFwid2hlblwiLCBcIndoaWxlXCJcbl0pXG5jb25zdCBhbmRyb2lkU2NhZmZvbGRTeW1ib2xzID0gbmV3IFNldChbXG4gIFwiQWN0aXZpdHlcIiwgXCJCYXNlNjRcIiwgXCJCdW5kbGVcIiwgXCJJbGxlZ2FsU3RhdGVFeGNlcHRpb25cIiwgXCJJbnN0cnVtZW50YXRpb25cIiwgXCJJbnRlbnRcIiwgXCJSXCIsIFwiU2VtYW50aWZvbGRFbnRyeVRlc3RcIixcbiAgXCJTZW1hbnRpZm9sZFVpSW5zdHJ1bWVudGF0aW9uXCIsIFwiU3RhbmRhcmRDaGFyc2V0c1wiLCBcIlN0cmluZ1wiLCBcIlN1cHByZXNzTGludFwiLCBcIlRlc3RcIiwgXCJUZXh0Vmlld1wiLCBcIlRocm93YWJsZVwiLCBcIlZpZXdcIlxuXSlcbmNvbnN0IG1lZGlhVHlwZVBhdHRlcm4gPSAvXltBLVphLXowLTkhIyQmXl8uKy1dK1xcL1tBLVphLXowLTkhIyQmXl8uKy1dKyg/OjtbXFx1MDAyMC1cXHUwMDdlXSspPyQvdVxuY29uc3Qgc2VtYW50aWNWZXJzaW9uUGF0dGVybiA9IC9eKD86MHxbMS05XVswLTldKilcXC4oPzowfFsxLTldWzAtOV0qKVxcLig/OjB8WzEtOV1bMC05XSopKD86LSg/OjB8WzEtOV1bMC05XSp8W0EtWmEtei1dW0EtWmEtejAtOS1dKikoPzpcXC4oPzowfFsxLTldWzAtOV0qfFtBLVphLXotXVtBLVphLXowLTktXSopKSopPyg/OlxcK1tBLVphLXowLTktXSsoPzpcXC5bQS1aYS16MC05LV0rKSopPyQvdVxuY29uc3QgdG9vbGNoYWluID0gT2JqZWN0LmZyZWV6ZSh7XG4gIGFuZHJvaWRHcmFkbGVQbHVnaW46IFwiOC4xMS4xXCIsXG4gIGFyY2hpdmVzOiB7XG4gICAgYnVpbGRUb29sczoge1xuICAgICAgcmV2aXNpb246IFwiMzUuMC4wXCIsXG4gICAgICBzaGEyNTY6IFwiYmQzYTQ5NjY5MTJlYjhiMzBlZDBkMDBiMGNkYTZiNjU0M2I5NDlkNWZmZTAwYmVhNTRjMDRjODFlMTU2MWQ4OFwiLFxuICAgICAgdXJsOiBcImh0dHBzOi8vZGwuZ29vZ2xlLmNvbS9hbmRyb2lkL3JlcG9zaXRvcnkvYnVpbGQtdG9vbHNfcjM1X2xpbnV4LnppcFwiXG4gICAgfSxcbiAgICBjb21tYW5kTGluZVRvb2xzOiB7XG4gICAgICByZXZpc2lvbjogXCIxMTA3NjcwOFwiLFxuICAgICAgc2hhMjU2OiBcIjJkMmQ1MDg1N2U0ZWI1NTNhZjVhNmRjM2FkNTA3YTE3YWRmNDNkMTE1MjY0YjFhZmMxMTZmOTVjOTJlNWUyNThcIixcbiAgICAgIHVybDogXCJodHRwczovL2RsLmdvb2dsZS5jb20vYW5kcm9pZC9yZXBvc2l0b3J5L2NvbW1hbmRsaW5ldG9vbHMtbGludXgtMTEwNzY3MDhfbGF0ZXN0LnppcFwiXG4gICAgfSxcbiAgICBlbXVsYXRvcjoge1xuICAgICAgYnVpbGRJZDogXCIxMzYxMDQxMlwiLFxuICAgICAgcmV2aXNpb246IFwiMzUuNi4xMVwiLFxuICAgICAgc2hhMjU2OiBcIjJmZTJiNTZmZTkzY2U3NWUxZDQ3OGE0MDE2MjEzMTM4MWQ5MTFjMzU1ZWZlYWVkYjU0ZGQxZTBkMDg5N2E1Y2ZcIixcbiAgICAgIHVybDogXCJodHRwczovL2VkZ2VkbC5tZS5ndnQxLmNvbS9lZGdlZGwvYW5kcm9pZC9yZXBvc2l0b3J5L2VtdWxhdG9yLWxpbnV4X3g2NC0xMzYxMDQxMi56aXBcIlxuICAgIH0sXG4gICAgcGxhdGZvcm06IHtcbiAgICAgIHJldmlzaW9uOiBcIjM1LXIyXCIsXG4gICAgICBzaGEyNTY6IFwiMDk4OGNhY2FkMDFiMzhhMThhNDdiYWMxNGEwNjk1ZjI0NmJjNzZjMWIwNmMwZWViOGViMGRjODI1YWIwYzhlMFwiLFxuICAgICAgdXJsOiBcImh0dHBzOi8vZGwuZ29vZ2xlLmNvbS9hbmRyb2lkL3JlcG9zaXRvcnkvcGxhdGZvcm0tMzVfcjAyLnppcFwiXG4gICAgfSxcbiAgICBwbGF0Zm9ybVRvb2xzOiB7XG4gICAgICByZXZpc2lvbjogXCIzNy4wLjFcIixcbiAgICAgIHNoYTI1NjogXCJkMjMwZjEzODQyZjYwZjc4MmE4NjQ1ZjljODEzZjhmODQ1YmYzNjA4OWVhNzI4OWYyOGM0OGYxNzk3OTMxM2YxXCIsXG4gICAgICB1cmw6IFwiaHR0cHM6Ly9kbC5nb29nbGUuY29tL2FuZHJvaWQvcmVwb3NpdG9yeS9wbGF0Zm9ybS10b29sc19yMzcuMC4xLWxpbnV4LnppcFwiXG4gICAgfSxcbiAgICBzeXN0ZW1JbWFnZToge1xuICAgICAgcmV2aXNpb246IFwiMzUtZ29vZ2xlX2FwaXMteDg2XzY0LXI5XCIsXG4gICAgICBzaGEyNTY6IFwiYzY3YjliYTBmZjViYzBlYjZkMDQ2ODcxYmZhMjI4YWYxNGQ0ZDQ3YjAyZjBjZGFlOTRmMDQ4ZTUxMWI3NTY2ZVwiLFxuICAgICAgdXJsOiBcImh0dHBzOi8vZGwuZ29vZ2xlLmNvbS9hbmRyb2lkL3JlcG9zaXRvcnkvc3lzLWltZy9nb29nbGVfYXBpcy94ODZfNjQtMzVfcjA5LnppcFwiXG4gICAgfVxuICB9LFxuICBidWlsZFRvb2xzOiBcIjM1LjAuMFwiLFxuICBjb21tYW5kTGluZVRvb2xzOiBcIjExMDc2NzA4XCIsXG4gIGNvbXBpbGVTZGs6IDM1LFxuICBlbXVsYXRvcjogXCIzNS42LjExXCIsXG4gIGdyYWRsZTogXCI4LjEzXCIsXG4gIGphdmE6IFwiMjEuMC44XCIsXG4gIGtvdGxpbjogXCIyLjIuMTBcIixcbiAga290bGluQ29tcGlsZXJTaGEyNTY6IFwiMzAyZDFkOGU2NzFlNWMzMjA3ZTZlZDYyZmYxMWZiNTU1NDYyYTYyOGUyMmExMTU4MjU0ZGNhYWY3ZTczOTRiY1wiLFxuICBzeXN0ZW1JbWFnZTogXCJzeXN0ZW0taW1hZ2VzO2FuZHJvaWQtMzU7Z29vZ2xlX2FwaXM7eDg2XzY0XCIsXG4gIHRhcmdldFNkazogMzVcbn0pXG5jb25zdCBleGNsdWRlZFBhdGhQYXR0ZXJucyA9IE9iamVjdC5mcmVlemUoW1wiLmdyYWRsZS8qKlwiLCBcIioqL2J1aWxkLyoqXCIsIFwibG9jYWwucHJvcGVydGllc1wiXSlcbmNvbnN0IGFuZHJvaWRLb3RsaW5SdW50aW1lID0gYEBmaWxlOlN1cHByZXNzKFwiUExBVEZPUk1fQ0xBU1NfTUFQUEVEX1RPX0tPVExJTlwiKVxuXG5wYWNrYWdlIF9fUEFDS0FHRV9fLnNlbWFudGljXG5cbiR7a290bGluUnVudGltZS5yZXBsYWNlQWxsKFwicHJpdmF0ZSBcIiwgXCJpbnRlcm5hbCBcIil9XG5pbnRlcm5hbCBjbGFzcyBTZW1hbnRpZm9sZE91dHB1dFNpbmsge1xuICBwcml2YXRlIHZhbCB2YWx1ZXM6IGphdmEudXRpbC5BcnJheUxpc3Q8U3RyaW5nPiA9IGphdmEudXRpbC5BcnJheUxpc3Q8U3RyaW5nPigpXG5cbiAgZnVuIHJlc2V0KCkge1xuICAgIHZhbHVlcy5jbGVhcigpXG4gIH1cblxuICBmdW4gd3JpdGUodmFsdWU6IExvbmcpIHtcbiAgICB2YWx1ZXMuYWRkKHZhbHVlLnRvU3RyaW5nKCkpXG4gIH1cblxuICBmdW4gd3JpdGUodmFsdWU6IEJvb2xlYW4pIHtcbiAgICB2YWx1ZXMuYWRkKGlmICh2YWx1ZSkgXCJ0cnVlXCIgZWxzZSBcImZhbHNlXCIpXG4gIH1cblxuICBmdW4gd3JpdGUodmFsdWU6IFN0cmluZykge1xuICAgIHZhbHVlcy5hZGQodmFsdWUpXG4gIH1cblxuICBmdW4gc25hcHNob3QoKTogamF2YS51dGlsLkFycmF5TGlzdDxTdHJpbmc+ID0gamF2YS51dGlsLkFycmF5TGlzdDxTdHJpbmc+KHZhbHVlcylcbn1cbmBcblxuLyoqIEB0eXBlZGVmIHt7Y29udGVudDogc3RyaW5nIHwgVWludDhBcnJheSwgY29udGVudEtpbmQ6IFwiYmluYXJ5XCIgfCBcInRleHRcIiwgZnVsbFBhdGg6IHN0cmluZywgbWVkaWFUeXBlOiBzdHJpbmcsIHBhdGg6IHN0cmluZywgc2hhMjU2OiBzdHJpbmd9fSBBbmRyb2lkSW5wdXRGaWxlICovXG4vKiogQHR5cGVkZWYge3tlbmQ6IG51bWJlciwgZmllbGQ6IHN0cmluZywgcGF0aDogc3RyaW5nLCBzdGFydDogbnVtYmVyfX0gQ29uZmlndXJhdGlvblNwYW4gKi9cblxuLyoqXG4gKiBQcmVmbGlnaHRzIGEgY29tcGxldGUgQW5kcm9pZCBhcHBsaWNhdGlvbiByZXF1ZXN0IGJlZm9yZSBhbGxvY2F0aW5nIGEgc291cmNlIHdyaXRlci5cbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgdW5rbm93bj59IGlucHV0IC0gQ2FuZGlkYXRlIGFwcGxpY2F0aW9uIHJlcXVlc3QuXG4gKiBAcmV0dXJucyB7e2Fzc2V0czogQW5kcm9pZElucHV0RmlsZVtdLCBjb25maWd1cmF0aW9uOiBpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5BbmRyb2lkQXBwbGljYXRpb25Db25maWd1cmF0aW9uLCBtb2R1bGVQYXRoczogTWFwPHN0cmluZywgc3RyaW5nPiwgbW9kdWxlczogaW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU2VtYW50aWNNb2R1bGVbXSwgcGFja2FnZVBhdGg6IHN0cmluZywgcHJvZ3JhbTogaW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU2VtYW50aWNQcm9ncmFtLCByZXNvdXJjZXM6IEFuZHJvaWRJbnB1dEZpbGVbXSwgc291cmNlczoge2NvbnRlbnQ6IHN0cmluZywgZmlsZW5hbWU6IHN0cmluZywgbGFuZ3VhZ2U/OiBpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY0xhbmd1YWdlfVtdfX0gUHJlcGFyZWQgYXBwbGljYXRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcmVmbGlnaHRBbmRyb2lkQXBwbGljYXRpb24oaW5wdXQpIHtcbiAgaWYgKCFpc1BsYWluT2JqZWN0KGlucHV0KSB8fCBPYmplY3Qua2V5cyhpbnB1dCkuc29tZShrZXkgPT4gIXJlcXVlc3RGaWVsZHMuaGFzKGtleSkpIHx8XG4gICAgQm9vbGVhbihpbnB1dC5tb2R1bGUpID09IEJvb2xlYW4oaW5wdXQucHJvZ3JhbSkpIHtcbiAgICBpbnZhbGlkSW5wdXQoXCJBbmRyb2lkIGFwcGxpY2F0aW9uIGdlbmVyYXRpb24gcmVxdWlyZXMgYSBjbG9zZWQgcmVxdWVzdCB3aXRoIGV4YWN0bHkgb25lIHNlbWFudGljIG1vZHVsZSBvciBwcm9ncmFtLlwiKVxuICB9XG4gIGlmIChpbnB1dC5sYW5ndWFnZSAhPT0gdW5kZWZpbmVkICYmIGlucHV0Lmxhbmd1YWdlICE9IFwiYW5kcm9pZFwiIHx8IGlucHV0LnJvbGUgIT09IHVuZGVmaW5lZCAmJiBpbnB1dC5yb2xlICE9IFwiYXBwbGljYXRpb25cIikge1xuICAgIGludmFsaWRJbnB1dChcIkFuZHJvaWQgYXBwbGljYXRpb24gZ2VuZXJhdGlvbiBhY2NlcHRzIG9ubHkgdGhlIEFuZHJvaWQgYXBwbGljYXRpb24gcm9sZS5cIilcbiAgfVxuICBjb25zdCBjb25maWd1cmF0aW9uID0gbm9ybWFsaXplQ29uZmlndXJhdGlvbihpbnB1dC5jb25maWd1cmF0aW9uKVxuICBjb25zdCBwcm9ncmFtID0gaW5wdXQucHJvZ3JhbSA/PyBub3JtYWxpemVTaW5nbGVNb2R1bGUoXG4gICAgLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY01vZHVsZSB8IHVuZGVmaW5lZH0gKi8gKGlucHV0Lm1vZHVsZSkpXG4gIGNvbnN0IHByZXBhcmVkID0gcHJlZmxpZ2h0U2VtYW50aWNQcm9ncmFtKHtcbiAgICBiYWNrZW5kTGFuZ3VhZ2U6IFwia290bGluXCIsXG4gICAgZGlhZ25vc3RpY0xhbmd1YWdlOiBcImFuZHJvaWRcIixcbiAgICBwcm9ncmFtOiAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljUHJvZ3JhbX0gKi8gKHByb2dyYW0pLFxuICAgIHNvdXJjZUxhbmd1YWdlczogYW5kcm9pZFNvdXJjZUxhbmd1YWdlc1xuICB9KVxuICB2YWxpZGF0ZUFjdGl2aXR5Q2xhc3NOYW1lKGNvbmZpZ3VyYXRpb24uYWN0aXZpdHlDbGFzc05hbWUsIHByZXBhcmVkLnByb2dyYW0uZW50cnlNb2R1bGUpXG4gIGNvbnN0IHBhY2thZ2VQYXRoID0gY29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZS5yZXBsYWNlQWxsKFwiLlwiLCBcIi9cIilcbiAgY29uc3Qgc2VtYW50aWNSb290ID0gYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9rb3RsaW4vJHtwYWNrYWdlUGF0aH0vc2VtYW50aWNgXG4gIGNvbnN0IG1vZHVsZVBhdGhzID0gbmV3IE1hcChwcmVwYXJlZC5tb2R1bGVzLm1hcChtb2R1bGUgPT4gW1xuICAgIC8qKiBAdHlwZSB7c3RyaW5nfSAqLyAoUmVmbGVjdC5nZXQobW9kdWxlLCBcImlkXCIpKSxcbiAgICBgJHtzZW1hbnRpY1Jvb3R9LyR7bW9kdWxlTmFtZSgvKiogQHR5cGUge3N0cmluZ30gKi8gKFJlZmxlY3QuZ2V0KG1vZHVsZSwgXCJpZFwiKSkpfS5rdGBcbiAgXSkpXG4gIGNvbnN0IHJlc291cmNlcyA9IG5vcm1hbGl6ZUlucHV0RmlsZXMoaW5wdXQucmVzb3VyY2VzLCBcInJlc291cmNlXCIpXG4gIGNvbnN0IGFzc2V0cyA9IG5vcm1hbGl6ZUlucHV0RmlsZXMoaW5wdXQuYXNzZXRzLCBcImFzc2V0XCIpXG4gIGNvbnN0IGZpeGVkUGF0aHMgPSBhcHBsaWNhdGlvblBhdGhzKGNvbmZpZ3VyYXRpb24sIG1vZHVsZVBhdGhzKVxuICBjb25zdCBjb21wbGV0ZVBhdGhzID0gW1xuICAgIC4uLmZpeGVkUGF0aHMsXG4gICAgLi4ucmVzb3VyY2VzLm1hcCgoe2Z1bGxQYXRofSkgPT4gZnVsbFBhdGgpLFxuICAgIC4uLmFzc2V0cy5tYXAoKHtmdWxsUGF0aH0pID0+IGZ1bGxQYXRoKVxuICBdXG4gIGNvbnN0IGNvbmZsaWN0ID0gZmluZFBvcnRhYmxlQXJ0aWZhY3RQYXRoQ29uZmxpY3QoY29tcGxldGVQYXRocylcblxuICBpZiAoY29uZmxpY3QpIHtcbiAgICBpbnZhbGlkUGF0aChgQXBwbGljYXRpb24gYXJ0aWZhY3QgcGF0aCAnJHtjb25mbGljdC5wYXRofScgaGFzIGEgJHtjb25mbGljdC5raW5kfSBjb25mbGljdCR7Y29uZmxpY3Qub3RoZXIgPyBgIHdpdGggJyR7Y29uZmxpY3Qub3RoZXJ9J2AgOiBcIlwifS5gKVxuICB9XG5cbiAgcmV0dXJuIHsuLi5wcmVwYXJlZCwgYXNzZXRzLCBjb25maWd1cmF0aW9uLCBtb2R1bGVQYXRocywgcGFja2FnZVBhdGgsIHJlc291cmNlc31cbn1cblxuLyoqXG4gKiBHZW5lcmF0ZXMgb25lIGNvbXBsZXRlIGRldGVybWluaXN0aWMgQW5kcm9pZC9Lb3RsaW4gcHJvamVjdC5cbiAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgdW5rbm93bj59IGlucHV0IC0gQXBwbGljYXRpb24gZ2VuZXJhdGlvbiByZXF1ZXN0LlxuICogQHJldHVybnMge3thcnRpZmFjdHM6IGltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZFNldEFydGlmYWN0W10sIG1ldGFkYXRhOiB7YXBwbGljYXRpb25NYW5pZmVzdDogc3RyaW5nLCBwbGF0Zm9ybVF1YWxpZmljYXRpb246IHN0cmluZ30sIHRhcmdldDogXCJhbmRyb2lkXCJ9fSBDYW5kaWRhdGUgYXJ0aWZhY3Qgc2V0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVBbmRyb2lkQXBwbGljYXRpb24oaW5wdXQpIHtcbiAgY29uc3QgcHJlcGFyZWQgPSBwcmVmbGlnaHRBbmRyb2lkQXBwbGljYXRpb24oaW5wdXQpXG4gIGNvbnN0IGNvbmZpZ3VyYXRpb25TcGFucyA9IC8qKiBAdHlwZSB7Q29uZmlndXJhdGlvblNwYW5bXX0gKi8gKFtdKVxuICBjb25zdCBjb25maWd1cmF0aW9uID0gcHJlcGFyZWQuY29uZmlndXJhdGlvblxuICBjb25zdCBwYWNrYWdlUGF0aCA9IHByZXBhcmVkLnBhY2thZ2VQYXRoXG4gIGNvbnN0IHNlbWFudGljQXJ0aWZhY3RzID0gcmVuZGVyU2VtYW50aWNBcnRpZmFjdHMocHJlcGFyZWQpXG4gIGNvbnN0IGFydGlmYWN0cyA9IC8qKiBAdHlwZSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuR2VuZXJhdGVkU2V0QXJ0aWZhY3RbXX0gKi8gKFtcbiAgICBjb25maWd1cmVkVGV4dChgJHtwcm9qZWN0Um9vdH0vYXBwL2J1aWxkLmdyYWRsZS5rdHNgLCBcIm1hbmlmZXN0XCIsIHJlbmRlckFwcEJ1aWxkKGNvbmZpZ3VyYXRpb24sIGNvbmZpZ3VyYXRpb25TcGFucyksXG4gICAgICBcIlBpbm5lZCBkZXBlbmRlbmN5LW1pbmltYWwgQW5kcm9pZCBhcHBsaWNhdGlvbiBidWlsZC5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvYW5kcm9pZFRlc3QvQW5kcm9pZE1hbmlmZXN0LnhtbGAsIFwibWFuaWZlc3RcIixcbiAgICAgIHJlbmRlckFuZHJvaWRUZXN0TWFuaWZlc3QoY29uZmlndXJhdGlvbiwgY29uZmlndXJhdGlvblNwYW5zKSwgXCJQbGF0Zm9ybS1vbmx5IEFuZHJvaWQgaW5zdHJ1bWVudGF0aW9uIGRlY2xhcmF0aW9uLlwiKSxcbiAgICBjb25maWd1cmVkVGV4dChgJHtwcm9qZWN0Um9vdH0vYXBwL3NyYy9hbmRyb2lkVGVzdC9rb3RsaW4vJHtwYWNrYWdlUGF0aH0vU2VtYW50aWZvbGRVaUluc3RydW1lbnRhdGlvbi5rdGAsIFwic3VwcG9ydFwiLFxuICAgICAgcmVuZGVySW5zdHJ1bWVudGF0aW9uKGNvbmZpZ3VyYXRpb24sIGNvbmZpZ3VyYXRpb25TcGFucyksIFwiUGxhdGZvcm0tb25seSBhY2Nlc3NpYmlsaXR5IGFuZCBsaWZlY3ljbGUgYXNzZXJ0aW9uLlwiKSxcbiAgICBjb25maWd1cmVkVGV4dChgJHtwcm9qZWN0Um9vdH0vYXBwL3NyYy9tYWluL0FuZHJvaWRNYW5pZmVzdC54bWxgLCBcIm1hbmlmZXN0XCIsXG4gICAgICByZW5kZXJBbmRyb2lkTWFuaWZlc3QoY29uZmlndXJhdGlvbiwgY29uZmlndXJhdGlvblNwYW5zKSwgXCJDbG9zZWQgYWxsb3dsaXN0ZWQgQW5kcm9pZCBhcHBsaWNhdGlvbiBtYW5pZmVzdC5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9rb3RsaW4vJHtwYWNrYWdlUGF0aH0vJHtjb25maWd1cmF0aW9uLmFjdGl2aXR5Q2xhc3NOYW1lfS5rdGAsIFwiZW50cnlcIixcbiAgICAgIHJlbmRlckFjdGl2aXR5KGNvbmZpZ3VyYXRpb24sIHByZXBhcmVkLnByb2dyYW0uZW50cnlNb2R1bGUsIGNvbmZpZ3VyYXRpb25TcGFucyksXG4gICAgICBcIlN5bnRoZXRpYyBBbmRyb2lkIGFjdGl2aXR5IGxpZmVjeWNsZSBhbmQgbmF0aXZlIG91dHB1dCB2aWV3IGJpbmRpbmcuXCIpLFxuICAgIC4uLnNlbWFudGljQXJ0aWZhY3RzLFxuICAgIHN5bnRoZXRpY1RleHQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9yZXMvbGF5b3V0L2FjdGl2aXR5X21haW4ueG1sYCwgXCJyZXNvdXJjZVwiLCByZW5kZXJMYXlvdXQoKSxcbiAgICAgIFwiU3ludGhldGljIG9uZS12aWV3IEFuZHJvaWQgbGF5b3V0IGFuZCBhY2Nlc3NpYmlsaXR5IGlkZW50aXR5LlwiKSxcbiAgICBjb25maWd1cmVkVGV4dChgJHtwcm9qZWN0Um9vdH0vYXBwL3NyYy9tYWluL3Jlcy92YWx1ZXMvc3RyaW5ncy54bWxgLCBcInJlc291cmNlXCIsXG4gICAgICByZW5kZXJTdHJpbmdzKGNvbmZpZ3VyYXRpb24sIGNvbmZpZ3VyYXRpb25TcGFucyksIFwiRXNjYXBlZCBhcHBsaWNhdGlvbiBsYWJlbHMgZGVyaXZlZCBmcm9tIGNvbmZpZ3VyYXRpb24uXCIpLFxuICAgIHN5bnRoZXRpY1RleHQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9yZXMvdmFsdWVzL3RoZW1lcy54bWxgLCBcInJlc291cmNlXCIsIHJlbmRlclRoZW1lKCksXG4gICAgICBcIkNsb3NlZCBwbGF0Zm9ybS1uYXRpdmUgYXBwbGljYXRpb24gdGhlbWUuXCIpLFxuICAgIHN5bnRoZXRpY1RleHQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9yZXMveG1sL2JhY2t1cF9ydWxlcy54bWxgLCBcInJlc291cmNlXCIsIHJlbmRlckJhY2t1cFJ1bGVzKCksXG4gICAgICBcIkNsb3NlZCBBUEkgMjMtMzAgZnVsbC1iYWNrdXAgZXhjbHVzaW9ucy5cIiksXG4gICAgc3ludGhldGljVGV4dChgJHtwcm9qZWN0Um9vdH0vYXBwL3NyYy9tYWluL3Jlcy94bWwvZGF0YV9leHRyYWN0aW9uX3J1bGVzLnhtbGAsIFwicmVzb3VyY2VcIiwgcmVuZGVyRGF0YUV4dHJhY3Rpb25SdWxlcygpLFxuICAgICAgXCJDbG9zZWQgQW5kcm9pZCAxMisgY2xvdWQtYmFja3VwIGFuZCBkZXZpY2UtdHJhbnNmZXIgZXhjbHVzaW9ucy5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvdGVzdC9rb3RsaW4vJHtwYWNrYWdlUGF0aH0vU2VtYW50aWZvbGRFbnRyeVRlc3Qua3RgLCBcInN1cHBvcnRcIixcbiAgICAgIHJlbmRlclVuaXRUZXN0KGNvbmZpZ3VyYXRpb24sIHByZXBhcmVkLnByb2dyYW0uZW50cnlNb2R1bGUsIGNvbmZpZ3VyYXRpb25TcGFucyksXG4gICAgICBcIkpVbml0IHRlc3Qtc2NvcGUtb25seSBzZW1hbnRpYyBkZXRlcm1pbmlzbSBhc3NlcnRpb24uXCIpLFxuICAgIHN5bnRoZXRpY1RleHQoYCR7cHJvamVjdFJvb3R9L2J1aWxkLmdyYWRsZS5rdHNgLCBcIm1hbmlmZXN0XCIsIHJlbmRlclJvb3RCdWlsZCgpLFxuICAgICAgXCJQaW5uZWQgQW5kcm9pZCBhbmQgS290bGluIGJ1aWxkIHBsdWdpbnMuXCIpLFxuICAgIHN5bnRoZXRpY1RleHQoYCR7cHJvamVjdFJvb3R9L2dyYWRsZS5wcm9wZXJ0aWVzYCwgXCJzdXBwb3J0XCIsIHJlbmRlckdyYWRsZVByb3BlcnRpZXMoKSxcbiAgICAgIFwiUGlubmVkIGhlcm1ldGljIEdyYWRsZSBwcm9jZXNzIHByb3BlcnRpZXMuXCIpLFxuICAgIGNvbmZpZ3VyZWRUZXh0KGAke3Byb2plY3RSb290fS9zZXR0aW5ncy5ncmFkbGUua3RzYCwgXCJtYW5pZmVzdFwiLCByZW5kZXJTZXR0aW5ncyhjb25maWd1cmF0aW9uLCBjb25maWd1cmF0aW9uU3BhbnMpLFxuICAgICAgXCJDbG9zZWQgb2ZmaWNpYWwgR3JhZGxlIHBsdWdpbiBhbmQgZGVwZW5kZW5jeSByZXBvc2l0b3JpZXMuXCIpLFxuICAgIC4uLnByZXBhcmVkLnJlc291cmNlcy5tYXAoaW5wdXRGaWxlQXJ0aWZhY3QpLFxuICAgIC4uLnByZXBhcmVkLmFzc2V0cy5tYXAoaW5wdXRGaWxlQXJ0aWZhY3QpXG4gIF0pXG5cbiAgYXJ0aWZhY3RzLnNvcnQoKGxlZnQsIHJpZ2h0KSA9PiBsZWZ0LnBhdGggPCByaWdodC5wYXRoID8gLTEgOiBsZWZ0LnBhdGggPiByaWdodC5wYXRoID8gMSA6IDApXG4gIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGAke3Byb2plY3RSb290fS9zZW1hbnRpZm9sZC1wcm9qZWN0Lmpzb25gXG5cbiAgYXJ0aWZhY3RzLnB1c2goc3ludGhldGljVGV4dChtYW5pZmVzdFBhdGgsIFwibWFuaWZlc3RcIixcbiAgICByZW5kZXJQcm9qZWN0TWFuaWZlc3QocHJlcGFyZWQsIGFydGlmYWN0cywgbWFuaWZlc3RQYXRoLCBjb25maWd1cmF0aW9uU3BhbnMpLFxuICAgIFwiVmVyc2lvbmVkIEFuZHJvaWQgcHJvamVjdCBvd25lcnNoaXAsIHRvb2xjaGFpbiwgYW5kIHByb3ZlbmFuY2UgbWFuaWZlc3QuXCIpKVxuXG4gIHJldHVybiB7XG4gICAgYXJ0aWZhY3RzLFxuICAgIG1ldGFkYXRhOiB7YXBwbGljYXRpb25NYW5pZmVzdDogbWFuaWZlc3RQYXRoLCBwbGF0Zm9ybVF1YWxpZmljYXRpb246IFwidGVuc29yYnV6ei1rdm1cIn0sXG4gICAgdGFyZ2V0OiBcImFuZHJvaWRcIlxuICB9XG59XG5cbi8qKlxuICogUmVuZGVycyB0aGUgbWFwcGVkIHNlbWFudGljIEtvdGxpbiBhcnRpZmFjdHMgZm9yIGV2ZXJ5IHByb2dyYW0gbW9kdWxlLlxuICogQHBhcmFtIHtSZXR1cm5UeXBlPHR5cGVvZiBwcmVmbGlnaHRBbmRyb2lkQXBwbGljYXRpb24+fSBwcmVwYXJlZCAtIFByZXBhcmVkIGFwcGxpY2F0aW9uLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZFNldEFydGlmYWN0W119IFNlbWFudGljIEtvdGxpbiBhcnRpZmFjdHMuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlclNlbWFudGljQXJ0aWZhY3RzKHByZXBhcmVkKSB7XG4gIGNvbnN0IHNlbWFudGljUm9vdCA9IGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4va290bGluLyR7cHJlcGFyZWQucGFja2FnZVBhdGh9L3NlbWFudGljYFxuICAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZFNldEFydGlmYWN0W119ICovXG4gIGNvbnN0IGFydGlmYWN0cyA9IFtzeW50aGV0aWNUZXh0KGAke3NlbWFudGljUm9vdH0vU2VtYW50aWZvbGRSdW50aW1lLmt0YCwgXCJzdXBwb3J0XCIsXG4gICAgYW5kcm9pZEtvdGxpblJ1bnRpbWUucmVwbGFjZUFsbChcIl9fUEFDS0FHRV9fXCIsIHByZXBhcmVkLmNvbmZpZ3VyYXRpb24ucGFja2FnZU5hbWUpLFxuICAgIFwiU2hhcmVkIEFuZHJvaWQgYXBwbGljYXRpb24gb3V0cHV0IGNhcHR1cmUgYW5kIGNoZWNrZWQgS290bGluIHNjYWxhciBzdXBwb3J0LlwiKV1cbiAgY29uc3QgZGVjbGFyYXRpb25zID0gbmV3IE1hcCgpXG5cbiAgZm9yIChjb25zdCBtb2R1bGUgb2YgcHJlcGFyZWQubW9kdWxlcykge1xuICAgIGZvciAoY29uc3QgZGVjbGFyYXRpb24gb2YgbW9kdWxlLmZ1bmN0aW9ucykgZGVjbGFyYXRpb25zLnNldChkZWNsYXJhdGlvbi5pZCwge1xuICAgICAgZGVjbGFyYXRpb24sXG4gICAgICBtb2R1bGVJZDogLyoqIEB0eXBlIHtzdHJpbmd9ICovIChSZWZsZWN0LmdldChtb2R1bGUsIFwiaWRcIikpXG4gICAgfSlcbiAgfVxuICBmb3IgKGNvbnN0IG1vZHVsZSBvZiBwcmVwYXJlZC5tb2R1bGVzKSB7XG4gICAgY29uc3QgbW9kdWxlSWQgPSAvKiogQHR5cGUge3N0cmluZ30gKi8gKFJlZmxlY3QuZ2V0KG1vZHVsZSwgXCJpZFwiKSlcbiAgICBjb25zdCBmaWxlbmFtZSA9IC8qKiBAdHlwZSB7c3RyaW5nfSAqLyAocHJlcGFyZWQubW9kdWxlUGF0aHMuZ2V0KG1vZHVsZUlkKSlcbiAgICBjb25zdCBzaW5rTmFtZSA9IG91dHB1dFNpbmtOYW1lKG1vZHVsZSlcbiAgICBjb25zdCB3cml0ZXIgPSBuZXcgU291cmNlV3JpdGVyKHtcbiAgICAgIGNhbGxBcmd1bWVudFN1ZmZpeDogc2lua05hbWUsXG4gICAgICBjYWxsTmFtZVJlc29sdmVyOiBleHByZXNzaW9uID0+IHtcbiAgICAgICAgY29uc3QgcmVzb2x2ZWQgPSBkZWNsYXJhdGlvbnMuZ2V0KGV4cHJlc3Npb24ucmVzb2x1dGlvbj8uZGVjbGFyYXRpb25JZClcblxuICAgICAgICBpZiAoIXJlc29sdmVkKSB0aHJvdyBuZXcgVHlwZUVycm9yKGBVbmtub3duIHZhbGlkYXRlZCBBbmRyb2lkIGZ1bmN0aW9uICcke2V4cHJlc3Npb24ucmVzb2x1dGlvbj8uZGVjbGFyYXRpb25JZH0nLmApXG5cbiAgICAgICAgcmV0dXJuIGBTZW1hbnRpZm9sZE1vZHVsZSR7bW9kdWxlTmFtZShyZXNvbHZlZC5tb2R1bGVJZCl9LiR7cmVzb2x2ZWQuZGVjbGFyYXRpb24ubmFtZX1gXG4gICAgICB9LFxuICAgICAgZmlsZW5hbWUsXG4gICAgICBsYW5ndWFnZTogXCJrb3RsaW5cIixcbiAgICAgIG1ldGhvZFN0cmluZ0VxdWFsaXR5OiB0cnVlLFxuICAgICAgbW9kdWxlLFxuICAgICAgcHJvZ3JhbTogcHJlcGFyZWQucHJvZ3JhbSxcbiAgICAgIHByb2dyYW1QYXRoczogcHJlcGFyZWQubW9kdWxlUGF0aHMsXG4gICAgICBzb3VyY2VzOiBwcmVwYXJlZC5zb3VyY2VzXG4gICAgfSlcblxuICAgIHdyaXRlci5zeW50aGV0aWMoYEBmaWxlOlN1cHByZXNzKFwiUExBVEZPUk1fQ0xBU1NfTUFQUEVEX1RPX0tPVExJTlwiKVxcblxcbnBhY2thZ2UgJHtwcmVwYXJlZC5jb25maWd1cmF0aW9uLnBhY2thZ2VOYW1lfS5zZW1hbnRpY1xcblxcbmAsXG4gICAgICBcIkFuZHJvaWQgc2VtYW50aWMgcGFja2FnZSBuYW1lc3BhY2VcIiwgW21vZHVsZV0sIFtcIlwiXSlcbiAgICBlbWl0U2VtYW50aWNNb2R1bGUod3JpdGVyLCBtb2R1bGUsIG1vZHVsZUlkLCBtb2R1bGVJZCA9PSBwcmVwYXJlZC5wcm9ncmFtLmVudHJ5TW9kdWxlLCBzaW5rTmFtZSlcbiAgICBjb25zdCBtYXBwaW5nID0gZmluYWxpemVNYXBwaW5nKHdyaXRlci5maW5pc2goKSlcblxuICAgIGFydGlmYWN0cy5wdXNoKHtcbiAgICAgIGNvbnRlbnQ6IG1hcHBpbmcuZ2VuZXJhdGVkLmNvbnRlbnQsXG4gICAgICBjb250ZW50S2luZDogXCJ0ZXh0XCIsXG4gICAgICBtZWRpYVR5cGU6IFwidGV4dC94LWtvdGxpblwiLFxuICAgICAgb3duZXJzaGlwOiBcImdlbmVyYXRlZFwiLFxuICAgICAgcGF0aDogZmlsZW5hbWUsXG4gICAgICBwcm92ZW5hbmNlOiB7a2luZDogXCJ0ZXh0XCIsIG1hcHBpbmcsIHNvdXJjZU1hcDogdG9Tb3VyY2VNYXBWMyhtYXBwaW5nKSwgc291cmNlTWFwRmlsZW5hbWU6IGAke2ZpbGVuYW1lfS5tYXBgfSxcbiAgICAgIHJvbGU6IFwic291cmNlXCJcbiAgICB9KVxuICB9XG5cbiAgcmV0dXJuIGFydGlmYWN0c1xufVxuXG4vKipcbiAqIEVtaXRzIG9uZSBuYW1lc3BhY2VkIHNlbWFudGljIG1vZHVsZSBhbmQgaXRzIGVudHJ5IGJyaWRnZSB3aGVuIGFwcGxpY2FibGUuXG4gKiBAcGFyYW0ge1NvdXJjZVdyaXRlcn0gd3JpdGVyIC0gTWFwcGVkIEtvdGxpbiB3cml0ZXIuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljTW9kdWxlfSBtb2R1bGUgLSBQcmVwYXJlZCBtb2R1bGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlSWQgLSBTdGFibGUgbW9kdWxlIGlkZW50aXR5LlxuICogQHBhcmFtIHtib29sZWFufSBlbnRyeSAtIFdoZXRoZXIgdGhpcyBtb2R1bGUgb3ducyB0aGUgZW50cnkgYmxvY2suXG4gKiBAcGFyYW0ge3N0cmluZ30gc2lua05hbWUgLSBDb2xsaXNpb24tc2FmZSBvdXRwdXQgc2luayBiaW5kaW5nLlxuICovXG5mdW5jdGlvbiBlbWl0U2VtYW50aWNNb2R1bGUod3JpdGVyLCBtb2R1bGUsIG1vZHVsZUlkLCBlbnRyeSwgc2lua05hbWUpIHtcbiAgd3JpdGVyLnN5bnRoZXRpYyhgaW50ZXJuYWwgb2JqZWN0IFNlbWFudGlmb2xkTW9kdWxlJHttb2R1bGVOYW1lKG1vZHVsZUlkKX0ge1xcbmAsXG4gICAgXCJBbmRyb2lkIHNlbWFudGljIG1vZHVsZSBuYW1lc3BhY2VcIiwgW21vZHVsZV0sIFtcIlwiXSlcbiAgbW9kdWxlLmZ1bmN0aW9ucy5mb3JFYWNoKChkZWNsYXJhdGlvbiwgZnVuY3Rpb25JbmRleCkgPT4ge1xuICAgIGNvbnN0IHBhdGggPSBgL2Z1bmN0aW9ucy8ke2Z1bmN0aW9uSW5kZXh9YFxuXG4gICAgd3JpdGVyLnN5bnRoZXRpYyhcIiAgXCIsIFwiQW5kcm9pZCBuYW1lc3BhY2VkIGZ1bmN0aW9uIGluZGVudGF0aW9uXCIsIFtkZWNsYXJhdGlvbl0sIFtwYXRoXSlcbiAgICB3cml0ZXIubWFwcGVkKFwiZnVuXCIsIHttYXBwaW5nS2luZDogXCJhbmNob3JcIiwgbm9kZTogZGVjbGFyYXRpb24sIHBhdGh9KVxuICAgIHdyaXRlci5zeW50aGV0aWMoXCIgXCIsIFwiZGVjbGFyYXRpb24gc3BhY2luZ1wiLCBbZGVjbGFyYXRpb25dLCBbcGF0aF0pXG4gICAgd3JpdGVyLm1hcHBlZChkZWNsYXJhdGlvbi5uYW1lLCB7bWFwcGluZ0tpbmQ6IFwiZXhhY3RcIiwgbm9kZTogZGVjbGFyYXRpb24sIHBhdGgsIHJvbGU6IFwibmFtZVwifSlcbiAgICB3cml0ZXIuc3ludGhldGljKFwiKFwiLCBcImZ1bmN0aW9uIHBhcmFtZXRlciBzY2FmZm9sZFwiLCBbZGVjbGFyYXRpb25dLCBbcGF0aF0pXG4gICAgZGVjbGFyYXRpb24ucGFyYW1ldGVycy5mb3JFYWNoKChwYXJhbWV0ZXIsIHBhcmFtZXRlckluZGV4KSA9PiB7XG4gICAgICBjb25zdCBwYXJhbWV0ZXJQYXRoID0gYCR7cGF0aH0vcGFyYW1ldGVycy8ke3BhcmFtZXRlckluZGV4fWBcblxuICAgICAgaWYgKHBhcmFtZXRlckluZGV4KSB3cml0ZXIuc3ludGhldGljKFwiLCBcIiwgXCJwYXJhbWV0ZXIgc2VwYXJhdG9yXCIsIFtwYXJhbWV0ZXJdLCBbcGFyYW1ldGVyUGF0aF0pXG4gICAgICB3cml0ZXIubWFwcGVkKHBhcmFtZXRlci5uYW1lLCB7bWFwcGluZ0tpbmQ6IFwiZXhhY3RcIiwgbm9kZTogcGFyYW1ldGVyLCBwYXRoOiBwYXJhbWV0ZXJQYXRoLCByb2xlOiBcIm5hbWVcIn0pXG4gICAgICB3cml0ZXIuc3ludGhldGljKFwiOiBcIiwgXCJwYXJhbWV0ZXIgYW5ub3RhdGlvbiBzY2FmZm9sZFwiLCBbcGFyYW1ldGVyXSwgW3BhcmFtZXRlclBhdGhdKVxuICAgICAgd3JpdGVyLm1hcHBlZChlbWl0U2NhbGFyVHlwZShcImtvdGxpblwiLCBwYXJhbWV0ZXIudHlwZSksIHttYXBwaW5nS2luZDogXCJleGFjdFwiLCBub2RlOiBwYXJhbWV0ZXIudHlwZSxcbiAgICAgICAgcGF0aDogYCR7cGFyYW1ldGVyUGF0aH0vdHlwZWAsIHJvbGU6IFwidHlwZVwifSlcbiAgICB9KVxuICAgIGlmIChkZWNsYXJhdGlvbi5wYXJhbWV0ZXJzLmxlbmd0aCkgd3JpdGVyLnN5bnRoZXRpYyhcIiwgXCIsIFwib3V0cHV0IHNpbmsgcGFyYW1ldGVyIHNlcGFyYXRvclwiLCBbZGVjbGFyYXRpb25dLCBbcGF0aF0pXG4gICAgd3JpdGVyLnN5bnRoZXRpYyhgJHtzaW5rTmFtZX06IFNlbWFudGlmb2xkT3V0cHV0U2luayk6IGAsIFwic2hhcmVkIEFuZHJvaWQgb3V0cHV0IHNpbmsgcGFyYW1ldGVyXCIsIFtkZWNsYXJhdGlvbl0sIFtwYXRoXSlcbiAgICB3cml0ZXIubWFwcGVkKGVtaXRTY2FsYXJUeXBlKFwia290bGluXCIsIGRlY2xhcmF0aW9uLnJldHVyblR5cGUpLCB7bWFwcGluZ0tpbmQ6IFwiZXhhY3RcIiwgbm9kZTogZGVjbGFyYXRpb24ucmV0dXJuVHlwZSxcbiAgICAgIHBhdGg6IGAke3BhdGh9L3JldHVyblR5cGVgLCByb2xlOiBcInR5cGVcIn0pXG4gICAgd3JpdGVyLnN5bnRoZXRpYyhcIiB7XFxuXCIsIFwiS290bGluIGZ1bmN0aW9uIGJvZHkgc2NhZmZvbGRcIiwgW2RlY2xhcmF0aW9uXSwgW3BhdGhdKVxuICAgIGVtaXRLb3RsaW5CbG9jayh3cml0ZXIsIGRlY2xhcmF0aW9uLmJvZHksIFwiICAgIFwiLCBgJHtwYXRofS9ib2R5YCwgYCR7c2lua05hbWV9LndyaXRlYClcbiAgICB3cml0ZXIuc3ludGhldGljKFwiICB9XFxuXCIsIFwiS290bGluIGZ1bmN0aW9uIGJvZHkgc2NhZmZvbGRcIiwgW2RlY2xhcmF0aW9uXSwgW3BhdGhdKVxuICB9KVxuICBpZiAoZW50cnkpIHtcbiAgICB3cml0ZXIuc3ludGhldGljKFwiICBmdW4gc2VtYW50aWZvbGRFbnRyeSgpOiBqYXZhLnV0aWwuQXJyYXlMaXN0PFN0cmluZz4ge1xcblwiLCBcIkFuZHJvaWQgc2VtYW50aWMgZW50cnkgc2NhZmZvbGRcIiwgW21vZHVsZS5lbnRyeVBvaW50XSwgW1wiL2VudHJ5UG9pbnRcIl0pXG4gICAgd3JpdGVyLnN5bnRoZXRpYyhgICAgIHZhbCAke3NpbmtOYW1lfSA9IFNlbWFudGlmb2xkT3V0cHV0U2luaygpXFxuYCwgXCJBbmRyb2lkIG91dHB1dCBzaW5rIGFsbG9jYXRpb25cIixcbiAgICAgIFttb2R1bGUuZW50cnlQb2ludF0sIFtcIi9lbnRyeVBvaW50XCJdKVxuICAgIHdyaXRlci5zeW50aGV0aWMoYCAgICAke3NpbmtOYW1lfS5yZXNldCgpXFxuYCwgXCJBbmRyb2lkIGxpZmVjeWNsZS1zYWZlIG91dHB1dCByZXNldFwiLCBbbW9kdWxlLmVudHJ5UG9pbnRdLCBbXCIvZW50cnlQb2ludFwiXSlcbiAgICBlbWl0S290bGluQmxvY2sod3JpdGVyLCBtb2R1bGUuZW50cnlQb2ludC5ib2R5LCBcIiAgICBcIiwgXCIvZW50cnlQb2ludC9ib2R5XCIsIGAke3NpbmtOYW1lfS53cml0ZWApXG4gICAgd3JpdGVyLnN5bnRoZXRpYyhgICAgIHJldHVybiAke3NpbmtOYW1lfS5zbmFwc2hvdCgpXFxuYCwgXCJBbmRyb2lkIHNlbWFudGljIG91dHB1dCByZXR1cm5cIixcbiAgICAgIFttb2R1bGUuZW50cnlQb2ludF0sIFtcIi9lbnRyeVBvaW50XCJdKVxuICAgIHdyaXRlci5zeW50aGV0aWMoXCIgIH1cXG5cIiwgXCJBbmRyb2lkIHNlbWFudGljIGVudHJ5IHNjYWZmb2xkXCIsIFttb2R1bGUuZW50cnlQb2ludF0sIFtcIi9lbnRyeVBvaW50XCJdKVxuICB9XG4gIHdyaXRlci5zeW50aGV0aWMoXCJ9XFxuXCIsIFwiQW5kcm9pZCBzZW1hbnRpYyBtb2R1bGUgbmFtZXNwYWNlXCIsIFttb2R1bGVdLCBbXCJcIl0pXG59XG5cbi8qKlxuICogTGlzdHMgZXZlcnkgZml4ZWQgZ2VuZXJhdGVkIHBhdGggYmVmb3JlIGFueSB3cml0ZXIgaXMgYWxsb2NhdGVkLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5BbmRyb2lkQXBwbGljYXRpb25Db25maWd1cmF0aW9ufSBjb25maWd1cmF0aW9uIC0gTm9ybWFsaXplZCBhcHBsaWNhdGlvbiBjb25maWd1cmF0aW9uLlxuICogQHBhcmFtIHtNYXA8c3RyaW5nLCBzdHJpbmc+fSBtb2R1bGVQYXRocyAtIFNlbWFudGljIG1vZHVsZSBvdXRwdXQgcGF0aHMuXG4gKiBAcmV0dXJucyB7c3RyaW5nW119IEZpeGVkIG93bmVkIGFydGlmYWN0IHBhdGhzLlxuICovXG5mdW5jdGlvbiBhcHBsaWNhdGlvblBhdGhzKGNvbmZpZ3VyYXRpb24sIG1vZHVsZVBhdGhzKSB7XG4gIGNvbnN0IHBhY2thZ2VQYXRoID0gY29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZS5yZXBsYWNlQWxsKFwiLlwiLCBcIi9cIilcblxuICByZXR1cm4gW1xuICAgIGAke3Byb2plY3RSb290fS9hcHAvYnVpbGQuZ3JhZGxlLmt0c2AsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvYW5kcm9pZFRlc3QvQW5kcm9pZE1hbmlmZXN0LnhtbGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvYW5kcm9pZFRlc3Qva290bGluLyR7cGFja2FnZVBhdGh9L1NlbWFudGlmb2xkVWlJbnN0cnVtZW50YXRpb24ua3RgLFxuICAgIGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4vQW5kcm9pZE1hbmlmZXN0LnhtbGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9rb3RsaW4vJHtwYWNrYWdlUGF0aH0vJHtjb25maWd1cmF0aW9uLmFjdGl2aXR5Q2xhc3NOYW1lfS5rdGAsXG4gICAgLi4ubW9kdWxlUGF0aHMudmFsdWVzKCksXG4gICAgYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9rb3RsaW4vJHtwYWNrYWdlUGF0aH0vc2VtYW50aWMvU2VtYW50aWZvbGRSdW50aW1lLmt0YCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vYXBwL3NyYy9tYWluL3Jlcy9sYXlvdXQvYWN0aXZpdHlfbWFpbi54bWxgLFxuICAgIGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4vcmVzL3ZhbHVlcy9zdHJpbmdzLnhtbGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9yZXMvdmFsdWVzL3RoZW1lcy54bWxgLFxuICAgIGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4vcmVzL3htbC9iYWNrdXBfcnVsZXMueG1sYCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vYXBwL3NyYy9tYWluL3Jlcy94bWwvZGF0YV9leHRyYWN0aW9uX3J1bGVzLnhtbGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvdGVzdC9rb3RsaW4vJHtwYWNrYWdlUGF0aH0vU2VtYW50aWZvbGRFbnRyeVRlc3Qua3RgLFxuICAgIGAke3Byb2plY3RSb290fS9idWlsZC5ncmFkbGUua3RzYCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vZ3JhZGxlLnByb3BlcnRpZXNgLFxuICAgIGAke3Byb2plY3RSb290fS9zZXR0aW5ncy5ncmFkbGUua3RzYCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vc2VtYW50aWZvbGQtcHJvamVjdC5qc29uYFxuICBdXG59XG5cbi8qKlxuICogUmVuZGVycyB0aGUgcGlubmVkIHJvb3QgcGx1Z2luIGRlY2xhcmF0aW9ucy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IFJvb3QgR3JhZGxlIEtvdGxpbiBzY3JpcHQuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlclJvb3RCdWlsZCgpIHtcbiAgcmV0dXJuIGBwbHVnaW5zIHtcbiAgaWQoXCJjb20uYW5kcm9pZC5hcHBsaWNhdGlvblwiKSB2ZXJzaW9uIFwiJHt0b29sY2hhaW4uYW5kcm9pZEdyYWRsZVBsdWdpbn1cIiBhcHBseSBmYWxzZVxuICBpZChcIm9yZy5qZXRicmFpbnMua290bGluLmFuZHJvaWRcIikgdmVyc2lvbiBcIiR7dG9vbGNoYWluLmtvdGxpbn1cIiBhcHBseSBmYWxzZVxufVxuYFxufVxuXG4vKipcbiAqIFJlbmRlcnMgY2xvc2VkIHByb2plY3Qgc2V0dGluZ3MgYW5kIHJlcG9zaXRvcmllcy5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuQW5kcm9pZEFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbn0gY29uZmlndXJhdGlvbiAtIE5vcm1hbGl6ZWQgY29uZmlndXJhdGlvbi5cbiAqIEBwYXJhbSB7Q29uZmlndXJhdGlvblNwYW5bXX0gc3BhbnMgLSBDb2xsZWN0ZWQgY29uZmlndXJhdGlvbiBwcm92ZW5hbmNlIHNwYW5zLlxuICogQHJldHVybnMge3N0cmluZ30gU2V0dGluZ3MgR3JhZGxlIEtvdGxpbiBzY3JpcHQuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlclNldHRpbmdzKGNvbmZpZ3VyYXRpb24sIHNwYW5zKSB7XG4gIHJldHVybiBjb25maWd1cmVkKGAke3Byb2plY3RSb290fS9zZXR0aW5ncy5ncmFkbGUua3RzYCwgc3BhbnMsIFtgcGx1Z2luTWFuYWdlbWVudCB7XG4gIHJlcG9zaXRvcmllcyB7XG4gICAgZ29vZ2xlKClcbiAgICBtYXZlbkNlbnRyYWwoKVxuICAgIGdyYWRsZVBsdWdpblBvcnRhbCgpXG4gIH1cbn1cblxuZGVwZW5kZW5jeVJlc29sdXRpb25NYW5hZ2VtZW50IHtcbiAgcmVwb3NpdG9yaWVzTW9kZS5zZXQoUmVwb3NpdG9yaWVzTW9kZS5GQUlMX09OX1BST0pFQ1RfUkVQT1MpXG4gIHJlcG9zaXRvcmllcyB7XG4gICAgZ29vZ2xlKClcbiAgICBtYXZlbkNlbnRyYWwoKVxuICB9XG59XG5cbnJvb3RQcm9qZWN0Lm5hbWUgPSBcImAsIGZpZWxkKFwicHJvZHVjdE5hbWVcIiwga290bGluRXNjYXBlKGNvbmZpZ3VyYXRpb24ucHJvZHVjdE5hbWUpKSwgYFwiXG5pbmNsdWRlKFwiOmFwcFwiKVxuYF0pXG59XG5cbi8qKlxuICogUmVuZGVycyBkZXRlcm1pbmlzdGljIEdyYWRsZSBwcm9jZXNzIHByb3BlcnRpZXMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBHcmFkbGUgcHJvcGVydGllcyBmaWxlLlxuICovXG5mdW5jdGlvbiByZW5kZXJHcmFkbGVQcm9wZXJ0aWVzKCkge1xuICByZXR1cm4gYG9yZy5ncmFkbGUuY2FjaGluZz1mYWxzZVxub3JnLmdyYWRsZS5jb25maWd1cmF0aW9uLWNhY2hlPWZhbHNlXG5vcmcuZ3JhZGxlLmRhZW1vbj1mYWxzZVxub3JnLmdyYWRsZS5qdm1hcmdzPS1YbXgyMDQ4bSAtRGZpbGUuZW5jb2Rpbmc9VVRGLTggLUR1c2VyLmxhbmd1YWdlPWVuIC1EdXNlci5jb3VudHJ5PVVTIC1EdXNlci50aW1lem9uZT1VVENcbm9yZy5ncmFkbGUucGFyYWxsZWw9ZmFsc2VcbmtvdGxpbi5zdGRsaWIuZGVmYXVsdC5kZXBlbmRlbmN5PWZhbHNlXG5rb3RsaW4uY29kZS5zdHlsZT1vZmZpY2lhbFxuYFxufVxuXG4vKipcbiAqIFJlbmRlcnMgdGhlIGFwcGxpY2F0aW9uIG1vZHVsZSBidWlsZCBjb250cmFjdC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuQW5kcm9pZEFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbn0gY29uZmlndXJhdGlvbiAtIE5vcm1hbGl6ZWQgY29uZmlndXJhdGlvbi5cbiAqIEBwYXJhbSB7Q29uZmlndXJhdGlvblNwYW5bXX0gc3BhbnMgLSBDb2xsZWN0ZWQgY29uZmlndXJhdGlvbiBwcm92ZW5hbmNlIHNwYW5zLlxuICogQHJldHVybnMge3N0cmluZ30gQXBwbGljYXRpb24gR3JhZGxlIEtvdGxpbiBzY3JpcHQuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlckFwcEJ1aWxkKGNvbmZpZ3VyYXRpb24sIHNwYW5zKSB7XG4gIHJldHVybiBjb25maWd1cmVkKGAke3Byb2plY3RSb290fS9hcHAvYnVpbGQuZ3JhZGxlLmt0c2AsIHNwYW5zLCBbXG4gICAgYGltcG9ydCBvcmcuamV0YnJhaW5zLmtvdGxpbi5ncmFkbGUuZHNsLkp2bVRhcmdldFxuaW1wb3J0IG9yZy5qZXRicmFpbnMua290bGluLmdyYWRsZS50YXNrcy5Lb3RsaW5Kdm1Db21waWxlXG5cbnBsdWdpbnMge1xuICBpZChcImNvbS5hbmRyb2lkLmFwcGxpY2F0aW9uXCIpXG4gIGlkKFwib3JnLmpldGJyYWlucy5rb3RsaW4uYW5kcm9pZFwiKVxufVxuXG5kZXBlbmRlbmNpZXMge1xuICB0ZXN0UnVudGltZU9ubHkoXCJvcmcuaGFtY3Jlc3Q6aGFtY3Jlc3QtY29yZToxLjNcIikge1xuICAgIGlzVHJhbnNpdGl2ZSA9IGZhbHNlXG4gIH1cbn1cblxudmFsIHNlbWFudGlmb2xkS290bGluSG9tZSA9IHByb3ZpZGVycy5lbnZpcm9ubWVudFZhcmlhYmxlKFwiU0VNQU5USUZPTERfS09UTElOX0hPTUVcIikub3JOdWxsXG4gID86IHRocm93IEdyYWRsZUV4Y2VwdGlvbihcIlNFTUFOVElGT0xEX0FORFJPSURfSU5GUkFTVFJVQ1RVUkU6IFNFTUFOVElGT0xEX0tPVExJTl9IT01FIGlzIHJlcXVpcmVkXCIpXG52YWwgc2VtYW50aWZvbGRLb3RsaW5TdGRsaWIgPSBmaWxlKFwiJHNlbWFudGlmb2xkS290bGluSG9tZS9saWIva290bGluLXN0ZGxpYi5qYXJcIilcbmlmICghc2VtYW50aWZvbGRLb3RsaW5TdGRsaWIuaXNGaWxlKSB7XG4gIHRocm93IEdyYWRsZUV4Y2VwdGlvbihcIlNFTUFOVElGT0xEX0FORFJPSURfSU5GUkFTVFJVQ1RVUkU6IHBpbm5lZCBLb3RsaW4gc3RkbGliIGlzIG1pc3NpbmdcIilcbn1cblxuZGVwZW5kZW5jaWVzIHtcbiAgYW5kcm9pZFRlc3RJbXBsZW1lbnRhdGlvbihmaWxlcyhzZW1hbnRpZm9sZEtvdGxpblN0ZGxpYikpXG59XG52YWwgc2VtYW50aWZvbGRBY2NlcHRhbmNlUm9vdCA9IHByb3ZpZGVycy5lbnZpcm9ubWVudFZhcmlhYmxlKFwiU0VNQU5USUZPTERfQU5EUk9JRF9BQ0NFUFRBTkNFX1JPT1RcIikub3JOdWxsXG4gID86IHRocm93IEdyYWRsZUV4Y2VwdGlvbihcIlNFTUFOVElGT0xEX0FORFJPSURfSU5GUkFTVFJVQ1RVUkU6IFNFTUFOVElGT0xEX0FORFJPSURfQUNDRVBUQU5DRV9ST09UIGlzIHJlcXVpcmVkXCIpXG52YWwgc2VtYW50aWZvbGREZWJ1Z0tleXN0b3JlID0gZmlsZShcIiRzZW1hbnRpZm9sZEFjY2VwdGFuY2VSb290L2RlYnVnLmtleXN0b3JlXCIpXG5pZiAoIXNlbWFudGlmb2xkRGVidWdLZXlzdG9yZS5pc0ZpbGUpIHtcbiAgdGhyb3cgR3JhZGxlRXhjZXB0aW9uKFwiU0VNQU5USUZPTERfQU5EUk9JRF9JTkZSQVNUUlVDVFVSRTogZXBoZW1lcmFsIGRlYnVnIGtleXN0b3JlIGlzIG1pc3NpbmdcIilcbn1cblxuYW5kcm9pZCB7XG4gIG5hbWVzcGFjZSA9IFwiYCxcbiAgICBmaWVsZChcIm5hbWVzcGFjZVwiLCBjb25maWd1cmF0aW9uLm5hbWVzcGFjZSksIGBcIlxcbiAgY29tcGlsZVNkayA9IGAsIGZpZWxkKFwiY29tcGlsZVNka1wiLCBTdHJpbmcoY29uZmlndXJhdGlvbi5jb21waWxlU2RrKSksXG4gICAgYFxcbiAgYnVpbGRUb29sc1ZlcnNpb24gPSBcImAsIGZpZWxkKFwiYnVpbGRUb29sc1ZlcnNpb25cIiwgY29uZmlndXJhdGlvbi5idWlsZFRvb2xzVmVyc2lvbiksIGBcIlxcblxcbiAgZGVmYXVsdENvbmZpZyB7XFxuICAgIGFwcGxpY2F0aW9uSWQgPSBcImAsXG4gICAgZmllbGQoXCJhcHBsaWNhdGlvbklkXCIsIGNvbmZpZ3VyYXRpb24uYXBwbGljYXRpb25JZCksIGBcIlxcbiAgICBtaW5TZGsgPSBgLCBmaWVsZChcIm1pbmltdW1TZGtcIiwgU3RyaW5nKGNvbmZpZ3VyYXRpb24ubWluaW11bVNkaykpLFxuICAgIGBcXG4gICAgdGFyZ2V0U2RrID0gYCwgZmllbGQoXCJ0YXJnZXRTZGtcIiwgU3RyaW5nKGNvbmZpZ3VyYXRpb24udGFyZ2V0U2RrKSksIGBcXG4gICAgdmVyc2lvbkNvZGUgPSBgLFxuICAgIGZpZWxkKFwidmVyc2lvbkNvZGVcIiwgU3RyaW5nKGNvbmZpZ3VyYXRpb24udmVyc2lvbkNvZGUpKSwgYFxcbiAgICB2ZXJzaW9uTmFtZSA9IFwiYCwgZmllbGQoXCJ2ZXJzaW9uTmFtZVwiLCBrb3RsaW5Fc2NhcGUoY29uZmlndXJhdGlvbi52ZXJzaW9uTmFtZSkpLFxuICAgIGBcIlxcbiAgICB0ZXN0QXBwbGljYXRpb25JZCA9IFwiYCwgZmllbGQoXCJhcHBsaWNhdGlvbklkXCIsIGNvbmZpZ3VyYXRpb24uYXBwbGljYXRpb25JZCksXG4gICAgYC50ZXN0XCJcXG4gICAgdGVzdEluc3RydW1lbnRhdGlvblJ1bm5lciA9IFwiYCwgZmllbGQoXCJwYWNrYWdlTmFtZVwiLCBjb25maWd1cmF0aW9uLnBhY2thZ2VOYW1lKSxcbiAgICBgLlNlbWFudGlmb2xkVWlJbnN0cnVtZW50YXRpb25cIlxcbiAgfVxcblxcbiAgc2lnbmluZ0NvbmZpZ3Mge1xcbiAgICBnZXRCeU5hbWUoXCJkZWJ1Z1wiKSB7XFxuICAgICAgc3RvcmVGaWxlID0gc2VtYW50aWZvbGREZWJ1Z0tleXN0b3JlXFxuICAgICAgc3RvcmVQYXNzd29yZCA9IFwiYW5kcm9pZFwiXFxuICAgICAga2V5QWxpYXMgPSBcImFuZHJvaWRkZWJ1Z2tleVwiXFxuICAgICAga2V5UGFzc3dvcmQgPSBcImFuZHJvaWRcIlxcbiAgICB9XFxuICB9XFxuICBidWlsZFR5cGVzIHtcXG4gICAgZ2V0QnlOYW1lKFwiZGVidWdcIikge1xcbiAgICAgIHNpZ25pbmdDb25maWcgPSBzaWduaW5nQ29uZmlncy5nZXRCeU5hbWUoXCJkZWJ1Z1wiKVxcbiAgICB9XFxuICB9XFxuICBidWlsZEZlYXR1cmVzIHtcXG4gICAgYnVpbGRDb25maWcgPSBmYWxzZVxcbiAgfVxcbiAgY29tcGlsZU9wdGlvbnMge1xcbiAgICBzb3VyY2VDb21wYXRpYmlsaXR5ID0gSmF2YVZlcnNpb24uVkVSU0lPTl8yMVxcbiAgICB0YXJnZXRDb21wYXRpYmlsaXR5ID0gSmF2YVZlcnNpb24uVkVSU0lPTl8yMVxcbiAgfVxcbiAgbGludCB7XFxuICAgIGFib3J0T25FcnJvciA9IHRydWVcXG4gICAgY2hlY2tEZXBlbmRlbmNpZXMgPSB0cnVlXFxuICAgIGRpc2FibGUgKz0gXCJNaXNzaW5nQXBwbGljYXRpb25JY29uXCJcXG4gICAgZGlzYWJsZSArPSBcIk9sZFRhcmdldEFwaVwiXFxuICAgIGRpc2FibGUgKz0gXCJHcmFkbGVEZXBlbmRlbmN5XCJcXG4gICAgd2FybmluZ3NBc0Vycm9ycyA9IHRydWVcXG4gIH1cXG4gIHBhY2thZ2luZyB7XFxuICAgIHJlc291cmNlcy5leGNsdWRlcyArPSBzZXRPZihcIk1FVEEtSU5GL0xJQ0VOU0UqXCIsIFwiTUVUQS1JTkYvTk9USUNFKlwiKVxcbiAgfVxcbn1cXG5cXG50YXNrcy53aXRoVHlwZTxLb3RsaW5Kdm1Db21waWxlPigpLmNvbmZpZ3VyZUVhY2gge1xcbiAgbGlicmFyaWVzLmZyb20oZmlsZXMoc2VtYW50aWZvbGRLb3RsaW5TdGRsaWIpKVxcbiAgY29tcGlsZXJPcHRpb25zIHtcXG4gICAgYWxsV2FybmluZ3NBc0Vycm9ycy5zZXQodHJ1ZSlcXG4gICAgZnJlZUNvbXBpbGVyQXJncy5hZGRBbGwoXCItWG5vLWNhbGwtYXNzZXJ0aW9uc1wiLCBcIi1Ybm8tcGFyYW0tYXNzZXJ0aW9uc1wiLCBcIi1Ybm8tcmVjZWl2ZXItYXNzZXJ0aW9uc1wiKVxcbiAgICBqdm1UYXJnZXQuc2V0KEp2bVRhcmdldC5KVk1fMjEpXFxuICB9XFxufVxcblxcbmRlcGVuZGVuY2llcyB7XFxuICB0ZXN0SW1wbGVtZW50YXRpb24oXCJqdW5pdDpqdW5pdDo0LjEzLjJcIikge1xcbiAgICBpc1RyYW5zaXRpdmUgPSBmYWxzZVxcbiAgfVxcbn1cXG5gXG4gIF0pXG59XG5cbi8qKlxuICogUmVuZGVycyB0aGUgYWxsb3dsaXN0ZWQgQW5kcm9pZCBhcHBsaWNhdGlvbiBtYW5pZmVzdC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuQW5kcm9pZEFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbn0gY29uZmlndXJhdGlvbiAtIE5vcm1hbGl6ZWQgY29uZmlndXJhdGlvbi5cbiAqIEBwYXJhbSB7Q29uZmlndXJhdGlvblNwYW5bXX0gc3BhbnMgLSBDb2xsZWN0ZWQgY29uZmlndXJhdGlvbiBwcm92ZW5hbmNlIHNwYW5zLlxuICogQHJldHVybnMge3N0cmluZ30gQW5kcm9pZCBhcHBsaWNhdGlvbiBtYW5pZmVzdC5cbiAqL1xuZnVuY3Rpb24gcmVuZGVyQW5kcm9pZE1hbmlmZXN0KGNvbmZpZ3VyYXRpb24sIHNwYW5zKSB7XG4gIGNvbnN0IG9yaWVudGF0aW9uID0gY29uZmlndXJhdGlvbi5vcmllbnRhdGlvbiA9PSBcInVuc3BlY2lmaWVkXCIgPyBcIlwiIDogYCBhbmRyb2lkOnNjcmVlbk9yaWVudGF0aW9uPVwiJHtjb25maWd1cmF0aW9uLm9yaWVudGF0aW9ufVwiYFxuXG4gIHJldHVybiBjb25maWd1cmVkKGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4vQW5kcm9pZE1hbmlmZXN0LnhtbGAsIHNwYW5zLCBbXG4gICAgYDw/eG1sIHZlcnNpb249XCIxLjBcIiBlbmNvZGluZz1cInV0Zi04XCI/PlxcbjxtYW5pZmVzdCB4bWxuczphbmRyb2lkPVwiaHR0cDovL3NjaGVtYXMuYW5kcm9pZC5jb20vYXBrL3Jlcy9hbmRyb2lkXCI+XFxuICA8YXBwbGljYXRpb25cXG4gICAgYW5kcm9pZDphbGxvd0JhY2t1cD1cImZhbHNlXCJcXG4gICAgYW5kcm9pZDpkYXRhRXh0cmFjdGlvblJ1bGVzPVwiQHhtbC9kYXRhX2V4dHJhY3Rpb25fcnVsZXNcIlxcbiAgICBhbmRyb2lkOmZ1bGxCYWNrdXBDb250ZW50PVwiQHhtbC9iYWNrdXBfcnVsZXNcIlxcbiAgICBhbmRyb2lkOmxhYmVsPVwiQHN0cmluZy9hcHBfbmFtZVwiXFxuICAgIGFuZHJvaWQ6c3VwcG9ydHNSdGw9XCJ0cnVlXCJcXG4gICAgYW5kcm9pZDp0aGVtZT1cIkBzdHlsZS9UaGVtZS5TZW1hbnRpZm9sZFwiPlxcbiAgICA8YWN0aXZpdHlcXG4gICAgICBhbmRyb2lkOm5hbWU9XCJgLFxuICAgIGZpZWxkKFwicGFja2FnZU5hbWVcIiwgY29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZSksIGAuYCwgZmllbGQoXCJhY3Rpdml0eUNsYXNzTmFtZVwiLCBjb25maWd1cmF0aW9uLmFjdGl2aXR5Q2xhc3NOYW1lKSxcbiAgICBgXCJcXG4gICAgICBhbmRyb2lkOmV4cG9ydGVkPVwidHJ1ZVwiYCxcbiAgICBvcmllbnRhdGlvbiA/IGZpZWxkKFwib3JpZW50YXRpb25cIiwgb3JpZW50YXRpb24pIDogXCJcIiwgYD5cXG4gICAgICA8aW50ZW50LWZpbHRlcj5cXG4gICAgICAgIDxhY3Rpb24gYW5kcm9pZDpuYW1lPVwiYW5kcm9pZC5pbnRlbnQuYWN0aW9uLk1BSU5cIiAvPlxcbiAgICAgICAgPGNhdGVnb3J5IGFuZHJvaWQ6bmFtZT1cImFuZHJvaWQuaW50ZW50LmNhdGVnb3J5LkxBVU5DSEVSXCIgLz5cXG4gICAgICA8L2ludGVudC1maWx0ZXI+XFxuICAgIDwvYWN0aXZpdHk+XFxuICA8L2FwcGxpY2F0aW9uPlxcbjwvbWFuaWZlc3Q+XFxuYFxuICBdKVxufVxuXG4vKipcbiAqIFJlbmRlcnMgZXhwbGljaXQgQVBJIDIzLTMwIGV4Y2x1c2lvbnMgZm9yIGV2ZXJ5IGZ1bGwtYmFja3VwIHN0b3JhZ2UgZG9tYWluLlxuICogQHJldHVybnMge3N0cmluZ30gQW5kcm9pZCBmdWxsLWJhY2t1cCBydWxlcyBYTUwuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlckJhY2t1cFJ1bGVzKCkge1xuICByZXR1cm4gYDw/eG1sIHZlcnNpb249XCIxLjBcIiBlbmNvZGluZz1cInV0Zi04XCI/PlxuPGZ1bGwtYmFja3VwLWNvbnRlbnQ+XG4gIDxleGNsdWRlIGRvbWFpbj1cInJvb3RcIiBwYXRoPVwiLlwiIC8+XG4gIDxleGNsdWRlIGRvbWFpbj1cImZpbGVcIiBwYXRoPVwiLlwiIC8+XG4gIDxleGNsdWRlIGRvbWFpbj1cImRhdGFiYXNlXCIgcGF0aD1cIi5cIiAvPlxuICA8ZXhjbHVkZSBkb21haW49XCJzaGFyZWRwcmVmXCIgcGF0aD1cIi5cIiAvPlxuICA8ZXhjbHVkZSBkb21haW49XCJleHRlcm5hbFwiIHBhdGg9XCIuXCIgLz5cbiAgPGV4Y2x1ZGUgZG9tYWluPVwiZGV2aWNlX3Jvb3RcIiBwYXRoPVwiLlwiIC8+XG4gIDxleGNsdWRlIGRvbWFpbj1cImRldmljZV9maWxlXCIgcGF0aD1cIi5cIiAvPlxuICA8ZXhjbHVkZSBkb21haW49XCJkZXZpY2VfZGF0YWJhc2VcIiBwYXRoPVwiLlwiIC8+XG4gIDxleGNsdWRlIGRvbWFpbj1cImRldmljZV9zaGFyZWRwcmVmXCIgcGF0aD1cIi5cIiAvPlxuPC9mdWxsLWJhY2t1cC1jb250ZW50PlxuYFxufVxuXG4vKipcbiAqIFJlbmRlcnMgZXhwbGljaXQgQW5kcm9pZCAxMisgZXhjbHVzaW9ucyBmb3IgZXZlcnkgY2xvdWQtYmFja3VwIGFuZCBkZXZpY2UtdHJhbnNmZXIgc3RvcmFnZSBkb21haW4uXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBBbmRyb2lkIGRhdGEgZXh0cmFjdGlvbiBydWxlcyBYTUwuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlckRhdGFFeHRyYWN0aW9uUnVsZXMoKSB7XG4gIHJldHVybiBgPD94bWwgdmVyc2lvbj1cIjEuMFwiIGVuY29kaW5nPVwidXRmLThcIj8+XG48ZGF0YS1leHRyYWN0aW9uLXJ1bGVzPlxuICA8Y2xvdWQtYmFja3VwPlxuICAgIDxleGNsdWRlIGRvbWFpbj1cInJvb3RcIiBwYXRoPVwiLlwiIC8+XG4gICAgPGV4Y2x1ZGUgZG9tYWluPVwiZmlsZVwiIHBhdGg9XCIuXCIgLz5cbiAgICA8ZXhjbHVkZSBkb21haW49XCJkYXRhYmFzZVwiIHBhdGg9XCIuXCIgLz5cbiAgICA8ZXhjbHVkZSBkb21haW49XCJzaGFyZWRwcmVmXCIgcGF0aD1cIi5cIiAvPlxuICAgIDxleGNsdWRlIGRvbWFpbj1cImV4dGVybmFsXCIgcGF0aD1cIi5cIiAvPlxuICAgIDxleGNsdWRlIGRvbWFpbj1cImRldmljZV9yb290XCIgcGF0aD1cIi5cIiAvPlxuICAgIDxleGNsdWRlIGRvbWFpbj1cImRldmljZV9maWxlXCIgcGF0aD1cIi5cIiAvPlxuICAgIDxleGNsdWRlIGRvbWFpbj1cImRldmljZV9kYXRhYmFzZVwiIHBhdGg9XCIuXCIgLz5cbiAgICA8ZXhjbHVkZSBkb21haW49XCJkZXZpY2Vfc2hhcmVkcHJlZlwiIHBhdGg9XCIuXCIgLz5cbiAgPC9jbG91ZC1iYWNrdXA+XG4gIDxkZXZpY2UtdHJhbnNmZXI+XG4gICAgPGV4Y2x1ZGUgZG9tYWluPVwicm9vdFwiIHBhdGg9XCIuXCIgLz5cbiAgICA8ZXhjbHVkZSBkb21haW49XCJmaWxlXCIgcGF0aD1cIi5cIiAvPlxuICAgIDxleGNsdWRlIGRvbWFpbj1cImRhdGFiYXNlXCIgcGF0aD1cIi5cIiAvPlxuICAgIDxleGNsdWRlIGRvbWFpbj1cInNoYXJlZHByZWZcIiBwYXRoPVwiLlwiIC8+XG4gICAgPGV4Y2x1ZGUgZG9tYWluPVwiZXh0ZXJuYWxcIiBwYXRoPVwiLlwiIC8+XG4gICAgPGV4Y2x1ZGUgZG9tYWluPVwiZGV2aWNlX3Jvb3RcIiBwYXRoPVwiLlwiIC8+XG4gICAgPGV4Y2x1ZGUgZG9tYWluPVwiZGV2aWNlX2ZpbGVcIiBwYXRoPVwiLlwiIC8+XG4gICAgPGV4Y2x1ZGUgZG9tYWluPVwiZGV2aWNlX2RhdGFiYXNlXCIgcGF0aD1cIi5cIiAvPlxuICAgIDxleGNsdWRlIGRvbWFpbj1cImRldmljZV9zaGFyZWRwcmVmXCIgcGF0aD1cIi5cIiAvPlxuICA8L2RldmljZS10cmFuc2Zlcj5cbjwvZGF0YS1leHRyYWN0aW9uLXJ1bGVzPlxuYFxufVxuXG4vKipcbiAqIFJlbmRlcnMgdGhlIHBsYXRmb3JtLW9ubHkgaW5zdHJ1bWVudGF0aW9uIG1hbmlmZXN0LlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5BbmRyb2lkQXBwbGljYXRpb25Db25maWd1cmF0aW9ufSBjb25maWd1cmF0aW9uIC0gTm9ybWFsaXplZCBjb25maWd1cmF0aW9uLlxuICogQHBhcmFtIHtDb25maWd1cmF0aW9uU3BhbltdfSBzcGFucyAtIENvbGxlY3RlZCBjb25maWd1cmF0aW9uIHByb3ZlbmFuY2Ugc3BhbnMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBBbmRyb2lkIHRlc3QgbWFuaWZlc3QuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlckFuZHJvaWRUZXN0TWFuaWZlc3QoY29uZmlndXJhdGlvbiwgc3BhbnMpIHtcbiAgcmV0dXJuIGNvbmZpZ3VyZWQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvYW5kcm9pZFRlc3QvQW5kcm9pZE1hbmlmZXN0LnhtbGAsIHNwYW5zLCBbXG4gICAgYDw/eG1sIHZlcnNpb249XCIxLjBcIiBlbmNvZGluZz1cInV0Zi04XCI/PlxcbjxtYW5pZmVzdCB4bWxuczphbmRyb2lkPVwiaHR0cDovL3NjaGVtYXMuYW5kcm9pZC5jb20vYXBrL3Jlcy9hbmRyb2lkXCI+XFxuICA8aW5zdHJ1bWVudGF0aW9uXFxuICAgIGFuZHJvaWQ6bmFtZT1cImAsXG4gICAgZmllbGQoXCJwYWNrYWdlTmFtZVwiLCBjb25maWd1cmF0aW9uLnBhY2thZ2VOYW1lKSwgYC5TZW1hbnRpZm9sZFVpSW5zdHJ1bWVudGF0aW9uXCJcXG4gICAgYW5kcm9pZDp0YXJnZXRQYWNrYWdlPVwiYCxcbiAgICBmaWVsZChcImFwcGxpY2F0aW9uSWRcIiwgeG1sRXNjYXBlKGNvbmZpZ3VyYXRpb24uYXBwbGljYXRpb25JZCkpLCBgXCIgLz5cXG48L21hbmlmZXN0PlxcbmBcbiAgXSlcbn1cblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBzeW50aGV0aWMgbGF1bmNoZXIgYWN0aXZpdHkuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkFuZHJvaWRBcHBsaWNhdGlvbkNvbmZpZ3VyYXRpb259IGNvbmZpZ3VyYXRpb24gLSBOb3JtYWxpemVkIGNvbmZpZ3VyYXRpb24uXG4gKiBAcGFyYW0ge3N0cmluZ30gZW50cnlNb2R1bGUgLSBTZWxlY3RlZCBzZW1hbnRpYyBlbnRyeSBtb2R1bGUgaWRlbnRpdHkuXG4gKiBAcGFyYW0ge0NvbmZpZ3VyYXRpb25TcGFuW119IHNwYW5zIC0gQ29sbGVjdGVkIGNvbmZpZ3VyYXRpb24gcHJvdmVuYW5jZSBzcGFucy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEtvdGxpbiBsYXVuY2hlciBhY3Rpdml0eSBzb3VyY2UuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlckFjdGl2aXR5KGNvbmZpZ3VyYXRpb24sIGVudHJ5TW9kdWxlLCBzcGFucykge1xuICBjb25zdCByZXNvdXJjZUltcG9ydCA9IGNvbmZpZ3VyYXRpb24ubmFtZXNwYWNlID09IGNvbmZpZ3VyYXRpb24ucGFja2FnZU5hbWVcbiAgICA/IFtdXG4gICAgOiBbXCJpbXBvcnQgXCIsIGZpZWxkKFwibmFtZXNwYWNlXCIsIGNvbmZpZ3VyYXRpb24ubmFtZXNwYWNlKSwgXCIuUlxcblwiXVxuXG4gIHJldHVybiBjb25maWd1cmVkKGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4va290bGluLyR7Y29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZS5yZXBsYWNlQWxsKFwiLlwiLCBcIi9cIil9LyR7Y29uZmlndXJhdGlvbi5hY3Rpdml0eUNsYXNzTmFtZX0ua3RgLCBzcGFucywgW1xuICAgIFwicGFja2FnZSBcIiwgZmllbGQoXCJwYWNrYWdlTmFtZVwiLCBjb25maWd1cmF0aW9uLnBhY2thZ2VOYW1lKSwgYFxuXG5pbXBvcnQgYW5kcm9pZC5hcHAuQWN0aXZpdHlcbmltcG9ydCBhbmRyb2lkLmFubm90YXRpb24uU3VwcHJlc3NMaW50XG5pbXBvcnQgYW5kcm9pZC5vcy5CdW5kbGVcbmltcG9ydCBhbmRyb2lkLndpZGdldC5UZXh0Vmlld1xuYCwgLi4ucmVzb3VyY2VJbXBvcnQsIGBpbXBvcnQgYCwgZmllbGQoXCJwYWNrYWdlTmFtZVwiLCBjb25maWd1cmF0aW9uLnBhY2thZ2VOYW1lKSxcbiAgICBgLnNlbWFudGljLlNlbWFudGlmb2xkTW9kdWxlJHttb2R1bGVOYW1lKGVudHJ5TW9kdWxlKX1cblxuY2xhc3MgYCwgZmllbGQoXCJhY3Rpdml0eUNsYXNzTmFtZVwiLCBjb25maWd1cmF0aW9uLmFjdGl2aXR5Q2xhc3NOYW1lKSwgYCA6IEFjdGl2aXR5KCkge1xuICBAU3VwcHJlc3NMaW50KFwiU2V0VGV4dEkxOG5cIilcbiAgb3ZlcnJpZGUgZnVuIG9uQ3JlYXRlKHNhdmVkSW5zdGFuY2VTdGF0ZTogQnVuZGxlPykge1xuICAgIHN1cGVyLm9uQ3JlYXRlKHNhdmVkSW5zdGFuY2VTdGF0ZSlcbiAgICBzZXRDb250ZW50VmlldyhSLmxheW91dC5hY3Rpdml0eV9tYWluKVxuICAgIHZhbCBsaW5lcyA9IFNlbWFudGlmb2xkTW9kdWxlJHttb2R1bGVOYW1lKGVudHJ5TW9kdWxlKX0uc2VtYW50aWZvbGRFbnRyeSgpXG4gICAgdmFsIG91dHB1dCA9IGphdmEubGFuZy5TdHJpbmdCdWlsZGVyKClcbiAgICB2YXIgaW5kZXggPSAwXG4gICAgd2hpbGUgKGluZGV4IDwgbGluZXMuc2l6ZSkge1xuICAgICAgaWYgKGluZGV4ID4gMCkgb3V0cHV0LmFwcGVuZCgnXFxcXG4nKVxuICAgICAgb3V0cHV0LmFwcGVuZChsaW5lc1tpbmRleF0pXG4gICAgICBpbmRleCArPSAxXG4gICAgfVxuICAgIGZpbmRWaWV3QnlJZDxUZXh0Vmlldz4oUi5pZC5zZW1hbnRpZm9sZF9vdXRwdXQpLnRleHQgPSBvdXRwdXQudG9TdHJpbmcoKVxuICB9XG59XG5gXG4gIF0pXG59XG5cbi8qKlxuICogUmVuZGVycyB0aGUgc2luZ2xlIGFjY2Vzc2liaWxpdHktaW1wb3J0YW50IG5hdGl2ZSB0ZXh0IHZpZXcuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBBbmRyb2lkIGxheW91dCBYTUwuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlckxheW91dCgpIHtcbiAgcmV0dXJuIGA8P3htbCB2ZXJzaW9uPVwiMS4wXCIgZW5jb2Rpbmc9XCJ1dGYtOFwiPz5cbjxUZXh0VmlldyB4bWxuczphbmRyb2lkPVwiaHR0cDovL3NjaGVtYXMuYW5kcm9pZC5jb20vYXBrL3Jlcy9hbmRyb2lkXCJcbiAgYW5kcm9pZDppZD1cIkAraWQvc2VtYW50aWZvbGRfb3V0cHV0XCJcbiAgYW5kcm9pZDpsYXlvdXRfd2lkdGg9XCJtYXRjaF9wYXJlbnRcIlxuICBhbmRyb2lkOmxheW91dF9oZWlnaHQ9XCJtYXRjaF9wYXJlbnRcIlxuICBhbmRyb2lkOmdyYXZpdHk9XCJjZW50ZXJcIlxuICBhbmRyb2lkOmltcG9ydGFudEZvckFjY2Vzc2liaWxpdHk9XCJ5ZXNcIlxuICBhbmRyb2lkOnRleHRJc1NlbGVjdGFibGU9XCJ0cnVlXCIgLz5cbmBcbn1cblxuLyoqXG4gKiBSZW5kZXJzIGNvbmZpZ3VyYXRpb24tZGVyaXZlZCBzdHJpbmcgcmVzb3VyY2VzLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5BbmRyb2lkQXBwbGljYXRpb25Db25maWd1cmF0aW9ufSBjb25maWd1cmF0aW9uIC0gTm9ybWFsaXplZCBjb25maWd1cmF0aW9uLlxuICogQHBhcmFtIHtDb25maWd1cmF0aW9uU3BhbltdfSBzcGFucyAtIENvbGxlY3RlZCBjb25maWd1cmF0aW9uIHByb3ZlbmFuY2Ugc3BhbnMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBBbmRyb2lkIHN0cmluZyByZXNvdXJjZSBYTUwuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlclN0cmluZ3MoY29uZmlndXJhdGlvbiwgc3BhbnMpIHtcbiAgcmV0dXJuIGNvbmZpZ3VyZWQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9yZXMvdmFsdWVzL3N0cmluZ3MueG1sYCwgc3BhbnMsIFtcbiAgICBgPD94bWwgdmVyc2lvbj1cIjEuMFwiIGVuY29kaW5nPVwidXRmLThcIj8+XFxuPHJlc291cmNlcz5cXG4gIDxzdHJpbmcgbmFtZT1cImFwcF9uYW1lXCI+YCxcbiAgICBmaWVsZChcImRpc3BsYXlOYW1lXCIsIHhtbEVzY2FwZShjb25maWd1cmF0aW9uLmRpc3BsYXlOYW1lKSksIGA8L3N0cmluZz5cXG48L3Jlc291cmNlcz5cXG5gXG4gIF0pXG59XG5cbi8qKlxuICogUmVuZGVycyB0aGUgZml4ZWQgcGxhdGZvcm0tbmF0aXZlIGJhc2VsaW5lIHRoZW1lLlxuICogQHJldHVybnMge3N0cmluZ30gQW5kcm9pZCB0aGVtZSByZXNvdXJjZSBYTUwuXG4gKi9cbmZ1bmN0aW9uIHJlbmRlclRoZW1lKCkge1xuICByZXR1cm4gYDw/eG1sIHZlcnNpb249XCIxLjBcIiBlbmNvZGluZz1cInV0Zi04XCI/PlxuPHJlc291cmNlcz5cbiAgPHN0eWxlIG5hbWU9XCJUaGVtZS5TZW1hbnRpZm9sZFwiIHBhcmVudD1cImFuZHJvaWQ6c3R5bGUvVGhlbWUuTWF0ZXJpYWwuTGlnaHQuTm9BY3Rpb25CYXJcIj5cbiAgICA8aXRlbSBuYW1lPVwiYW5kcm9pZDpmb250RmFtaWx5XCI+c2FuczwvaXRlbT5cbiAgICA8aXRlbSBuYW1lPVwiYW5kcm9pZDp3aW5kb3dBY3Rpb25Nb2RlT3ZlcmxheVwiPnRydWU8L2l0ZW0+XG4gIDwvc3R5bGU+XG48L3Jlc291cmNlcz5cbmBcbn1cblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBzb2xlIEpVbml0IHRlc3Qtc2NvcGUgc2VtYW50aWMgYXNzZXJ0aW9uLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5BbmRyb2lkQXBwbGljYXRpb25Db25maWd1cmF0aW9ufSBjb25maWd1cmF0aW9uIC0gTm9ybWFsaXplZCBjb25maWd1cmF0aW9uLlxuICogQHBhcmFtIHtzdHJpbmd9IGVudHJ5TW9kdWxlIC0gU2VsZWN0ZWQgc2VtYW50aWMgZW50cnkgbW9kdWxlIGlkZW50aXR5LlxuICogQHBhcmFtIHtDb25maWd1cmF0aW9uU3BhbltdfSBzcGFucyAtIENvbGxlY3RlZCBjb25maWd1cmF0aW9uIHByb3ZlbmFuY2Ugc3BhbnMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBLb3RsaW4gdW5pdCB0ZXN0IHNvdXJjZS5cbiAqL1xuZnVuY3Rpb24gcmVuZGVyVW5pdFRlc3QoY29uZmlndXJhdGlvbiwgZW50cnlNb2R1bGUsIHNwYW5zKSB7XG4gIHJldHVybiBjb25maWd1cmVkKGAke3Byb2plY3RSb290fS9hcHAvc3JjL3Rlc3Qva290bGluLyR7Y29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZS5yZXBsYWNlQWxsKFwiLlwiLCBcIi9cIil9L1NlbWFudGlmb2xkRW50cnlUZXN0Lmt0YCwgc3BhbnMsIFtcbiAgICBcInBhY2thZ2UgXCIsIGZpZWxkKFwicGFja2FnZU5hbWVcIiwgY29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZSksIGBcblxuaW1wb3J0IGAsIGZpZWxkKFwicGFja2FnZU5hbWVcIiwgY29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZSksIGAuc2VtYW50aWMuU2VtYW50aWZvbGRNb2R1bGUke21vZHVsZU5hbWUoZW50cnlNb2R1bGUpfVxuaW1wb3J0IG9yZy5qdW5pdC5UZXN0XG5cbmNsYXNzIFNlbWFudGlmb2xkRW50cnlUZXN0IHtcbiAgQFRlc3RcbiAgZnVuIGVudHJ5SXNEZXRlcm1pbmlzdGljQWNyb3NzRnJlc2hSdW5zKCkge1xuICAgIHZhbCBmaXJzdE91dHB1dCA9IFNlbWFudGlmb2xkTW9kdWxlJHttb2R1bGVOYW1lKGVudHJ5TW9kdWxlKX0uc2VtYW50aWZvbGRFbnRyeSgpXG4gICAgdmFsIHNlY29uZE91dHB1dCA9IFNlbWFudGlmb2xkTW9kdWxlJHttb2R1bGVOYW1lKGVudHJ5TW9kdWxlKX0uc2VtYW50aWZvbGRFbnRyeSgpXG4gICAgaWYgKCFmaXJzdE91dHB1dC5lcXVhbHMoc2Vjb25kT3V0cHV0KSkge1xuICAgICAgdGhyb3cgQXNzZXJ0aW9uRXJyb3IoXCJTZW1hbnRpYyBlbnRyeSBvdXRwdXQgZGlmZmVycyBhY3Jvc3MgZnJlc2ggcnVucy5cIilcbiAgICB9XG4gIH1cbn1cbmBcbiAgXSlcbn1cblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBmcmFtZXdvcmstb25seSBpbnN0cnVtZW50YXRpb24gcnVubmVyLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5BbmRyb2lkQXBwbGljYXRpb25Db25maWd1cmF0aW9ufSBjb25maWd1cmF0aW9uIC0gTm9ybWFsaXplZCBjb25maWd1cmF0aW9uLlxuICogQHBhcmFtIHtDb25maWd1cmF0aW9uU3BhbltdfSBzcGFucyAtIENvbGxlY3RlZCBjb25maWd1cmF0aW9uIHByb3ZlbmFuY2Ugc3BhbnMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBLb3RsaW4gaW5zdHJ1bWVudGF0aW9uIHNvdXJjZS5cbiAqL1xuZnVuY3Rpb24gcmVuZGVySW5zdHJ1bWVudGF0aW9uKGNvbmZpZ3VyYXRpb24sIHNwYW5zKSB7XG4gIGNvbnN0IHJlc291cmNlSW1wb3J0ID0gY29uZmlndXJhdGlvbi5uYW1lc3BhY2UgPT0gY29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZVxuICAgID8gW11cbiAgICA6IFtcImltcG9ydCBcIiwgZmllbGQoXCJuYW1lc3BhY2VcIiwgY29uZmlndXJhdGlvbi5uYW1lc3BhY2UpLCBcIi5SXFxuXCJdXG5cbiAgcmV0dXJuIGNvbmZpZ3VyZWQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvYW5kcm9pZFRlc3Qva290bGluLyR7Y29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZS5yZXBsYWNlQWxsKFwiLlwiLCBcIi9cIil9L1NlbWFudGlmb2xkVWlJbnN0cnVtZW50YXRpb24ua3RgLCBzcGFucywgW1xuICAgIFwicGFja2FnZSBcIiwgZmllbGQoXCJwYWNrYWdlTmFtZVwiLCBjb25maWd1cmF0aW9uLnBhY2thZ2VOYW1lKSwgYFxuXG5pbXBvcnQgYW5kcm9pZC5hcHAuQWN0aXZpdHlcbmltcG9ydCBhbmRyb2lkLmFwcC5JbnN0cnVtZW50YXRpb25cbmltcG9ydCBhbmRyb2lkLmNvbnRlbnQuSW50ZW50XG5pbXBvcnQgYW5kcm9pZC5vcy5CdW5kbGVcbmltcG9ydCBhbmRyb2lkLnV0aWwuQmFzZTY0XG5pbXBvcnQgYW5kcm9pZC52aWV3LlZpZXdcbmltcG9ydCBhbmRyb2lkLndpZGdldC5UZXh0Vmlld1xuaW1wb3J0IGphdmEubmlvLmNoYXJzZXQuU3RhbmRhcmRDaGFyc2V0c1xuYCwgLi4ucmVzb3VyY2VJbXBvcnQsIGBcbmNsYXNzIFNlbWFudGlmb2xkVWlJbnN0cnVtZW50YXRpb24gOiBJbnN0cnVtZW50YXRpb24oKSB7XG4gIHByaXZhdGUgdmFyIGlucHV0QXJndW1lbnRzOiBCdW5kbGU/ID0gbnVsbFxuXG4gIG92ZXJyaWRlIGZ1biBvbkNyZWF0ZShhcmd1bWVudHM6IEJ1bmRsZT8pIHtcbiAgICBpbnB1dEFyZ3VtZW50cyA9IGFyZ3VtZW50c1xuICAgIHN0YXJ0KClcbiAgfVxuXG4gIG92ZXJyaWRlIGZ1biBvblN0YXJ0KCkge1xuICAgIHRyeSB7XG4gICAgICB2YWwgcHJvdmlkZWRBcmd1bWVudHMgPSBpbnB1dEFyZ3VtZW50c1xuICAgICAgICA/OiB0aHJvdyBJbGxlZ2FsU3RhdGVFeGNlcHRpb24oXCJtaXNzaW5nIGluc3RydW1lbnRhdGlvbiBhcmd1bWVudHNcIilcbiAgICAgIHZhbCBlbmNvZGVkID0gcHJvdmlkZWRBcmd1bWVudHMuZ2V0U3RyaW5nKFwiZXhwZWN0ZWRfb3V0cHV0X2Jhc2U2NFwiKVxuICAgICAgICA/OiB0aHJvdyBJbGxlZ2FsU3RhdGVFeGNlcHRpb24oXCJtaXNzaW5nIGV4cGVjdGVkX291dHB1dF9iYXNlNjQgaW5zdHJ1bWVudGF0aW9uIGFyZ3VtZW50XCIpXG4gICAgICB2YWwgZXhwZWN0ZWQgPSBTdHJpbmcoQmFzZTY0LmRlY29kZShlbmNvZGVkLCBCYXNlNjQuTk9fV1JBUCksIFN0YW5kYXJkQ2hhcnNldHMuVVRGXzgpXG4gICAgICB2YWwgbGF1bmNoID0gdGFyZ2V0Q29udGV4dC5wYWNrYWdlTWFuYWdlci5nZXRMYXVuY2hJbnRlbnRGb3JQYWNrYWdlKHRhcmdldENvbnRleHQucGFja2FnZU5hbWUpXG4gICAgICAgID86IHRocm93IElsbGVnYWxTdGF0ZUV4Y2VwdGlvbihcImdlbmVyYXRlZCBhcHBsaWNhdGlvbiBoYXMgbm8gbGF1bmNoZXIgaW50ZW50XCIpXG4gICAgICBsYXVuY2guYWRkRmxhZ3MoSW50ZW50LkZMQUdfQUNUSVZJVFlfTkVXX1RBU0sgb3IgSW50ZW50LkZMQUdfQUNUSVZJVFlfQ0xFQVJfVEFTSylcbiAgICAgIHZhbCBhY3Rpdml0eSA9IHN0YXJ0QWN0aXZpdHlTeW5jKGxhdW5jaCkgYXMgYCwgZmllbGQoXCJhY3Rpdml0eUNsYXNzTmFtZVwiLCBjb25maWd1cmF0aW9uLmFjdGl2aXR5Q2xhc3NOYW1lKSwgYFxuICAgICAgYXNzZXJ0T3V0cHV0KGFjdGl2aXR5LCBleHBlY3RlZClcbiAgICAgIHZhbCBtb25pdG9yID0gYWRkTW9uaXRvcihgLCBmaWVsZChcImFjdGl2aXR5Q2xhc3NOYW1lXCIsIGNvbmZpZ3VyYXRpb24uYWN0aXZpdHlDbGFzc05hbWUpLCBgOjpjbGFzcy5qYXZhLm5hbWUsIG51bGwsIGZhbHNlKVxuICAgICAgcnVuT25NYWluU3luYyB7IGFjdGl2aXR5LnJlY3JlYXRlKCkgfVxuICAgICAgd2FpdEZvcklkbGVTeW5jKClcbiAgICAgIHZhbCByZWNyZWF0ZWQgPSB3YWl0Rm9yTW9uaXRvcldpdGhUaW1lb3V0KG1vbml0b3IsIDEwXzAwMClcbiAgICAgICAgPzogdGhyb3cgSWxsZWdhbFN0YXRlRXhjZXB0aW9uKFwiYWN0aXZpdHkgd2FzIG5vdCByZWNyZWF0ZWRcIilcbiAgICAgIGFzc2VydE91dHB1dChyZWNyZWF0ZWQsIGV4cGVjdGVkKVxuICAgICAgZmluaXNoKEFjdGl2aXR5LlJFU1VMVF9PSywgQnVuZGxlKCkpXG4gICAgfSBjYXRjaCAoZXJyb3I6IFRocm93YWJsZSkge1xuICAgICAgdmFsIHJlc3VsdCA9IEJ1bmRsZSgpXG4gICAgICByZXN1bHQucHV0U3RyaW5nKFwic2VtYW50aWZvbGRfZmFpbHVyZVwiLCBhbmRyb2lkLnV0aWwuTG9nLmdldFN0YWNrVHJhY2VTdHJpbmcoZXJyb3IpKVxuICAgICAgZmluaXNoKEFjdGl2aXR5LlJFU1VMVF9DQU5DRUxFRCwgcmVzdWx0KVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZnVuIGFzc2VydE91dHB1dChhY3Rpdml0eTogQWN0aXZpdHksIGV4cGVjdGVkOiBTdHJpbmcpIHtcbiAgICB3YWl0Rm9ySWRsZVN5bmMoKVxuICAgIHZhbCBhY3R1YWwgPSBhY3Rpdml0eS5maW5kVmlld0J5SWQ8VGV4dFZpZXc+KFIuaWQuc2VtYW50aWZvbGRfb3V0cHV0KVxuICAgICAgPzogdGhyb3cgSWxsZWdhbFN0YXRlRXhjZXB0aW9uKFwibWlzc2luZyBzZW1hbnRpZm9sZF9vdXRwdXQgdmlld1wiKVxuICAgIGlmIChhY3R1YWwudmlzaWJpbGl0eSAhPSBWaWV3LlZJU0lCTEUpIHRocm93IElsbGVnYWxTdGF0ZUV4Y2VwdGlvbihcIm91dHB1dCB2aWV3IGlzIG5vdCB2aXNpYmxlXCIpXG4gICAgaWYgKGFjdHVhbC5qYXZhQ2xhc3MgIT0gVGV4dFZpZXc6OmNsYXNzLmphdmEpIHRocm93IElsbGVnYWxTdGF0ZUV4Y2VwdGlvbihcIm91dHB1dCB2aWV3IGlzIG5vdCBhIG5hdGl2ZSBUZXh0Vmlld1wiKVxuICAgIGlmICghYWN0dWFsLnRleHQudG9TdHJpbmcoKS5lcXVhbHMoZXhwZWN0ZWQpKSB0aHJvdyBJbGxlZ2FsU3RhdGVFeGNlcHRpb24oXCJvdXRwdXQgdGV4dCBtaXNtYXRjaFwiKVxuICAgIGlmIChhY3R1YWwuY29udGVudERlc2NyaXB0aW9uICE9IG51bGwpIHRocm93IElsbGVnYWxTdGF0ZUV4Y2VwdGlvbihcIm91dHB1dCBjb250ZW50IGRlc2NyaXB0aW9uIG11c3Qgc3RheSBhYnNlbnRcIilcbiAgICBpZiAoYWN0dWFsLmltcG9ydGFudEZvckFjY2Vzc2liaWxpdHkgIT0gVmlldy5JTVBPUlRBTlRfRk9SX0FDQ0VTU0lCSUxJVFlfWUVTKSB7XG4gICAgICB0aHJvdyBJbGxlZ2FsU3RhdGVFeGNlcHRpb24oXCJvdXRwdXQgdmlldyBpcyBub3QgYWNjZXNzaWJpbGl0eS1pbXBvcnRhbnRcIilcbiAgICB9XG4gIH1cbn1cbmBcbiAgXSlcbn1cblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBvd25lcnNoaXAsIHRvb2xjaGFpbiwgYW5kIHByb3ZlbmFuY2UgbWFuaWZlc3QuXG4gKiBAcGFyYW0ge1JldHVyblR5cGU8dHlwZW9mIHByZWZsaWdodEFuZHJvaWRBcHBsaWNhdGlvbj59IHByZXBhcmVkIC0gUHJlcGFyZWQgYXBwbGljYXRpb24uXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZFNldEFydGlmYWN0W119IGFydGlmYWN0cyAtIE93bmVkIHByb2plY3QgYXJ0aWZhY3RzLlxuICogQHBhcmFtIHtzdHJpbmd9IG1hbmlmZXN0UGF0aCAtIE93bmVyc2hpcCBtYW5pZmVzdCBwYXRoLlxuICogQHBhcmFtIHtDb25maWd1cmF0aW9uU3BhbltdfSBzcGFucyAtIENvbmZpZ3VyYXRpb24gcHJvdmVuYW5jZSBzcGFucy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IENhbm9uaWNhbCBwcm9qZWN0IG1hbmlmZXN0IEpTT04uXG4gKi9cbmZ1bmN0aW9uIHJlbmRlclByb2plY3RNYW5pZmVzdChwcmVwYXJlZCwgYXJ0aWZhY3RzLCBtYW5pZmVzdFBhdGgsIHNwYW5zKSB7XG4gIGNvbnN0IGlucHV0UGF0aHMgPSBuZXcgU2V0KFsuLi5wcmVwYXJlZC5yZXNvdXJjZXMsIC4uLnByZXBhcmVkLmFzc2V0c10ubWFwKCh7ZnVsbFBhdGh9KSA9PiBmdWxsUGF0aCkpXG4gIGNvbnN0IHNlbWFudGljQXJ0aWZhY3RzID0gYXJ0aWZhY3RzLmZpbHRlcihhcnRpZmFjdCA9PiBhcnRpZmFjdC5wcm92ZW5hbmNlLmtpbmQgPT0gXCJ0ZXh0XCIpXG4gIGNvbnN0IG93bmVkUGF0aHMgPSBbLi4uYXJ0aWZhY3RzLm1hcCgoe3BhdGh9KSA9PiBwYXRoKSwgbWFuaWZlc3RQYXRoXVxuXG4gIHJldHVybiBzdHJpbmdpZnlDYW5vbmljYWxKc29uKHtcbiAgICBjb25maWd1cmF0aW9uOiBwcmVwYXJlZC5jb25maWd1cmF0aW9uLFxuICAgIGdlbmVyYXRvcjoge25hbWU6IFwic2VtYW50aWZvbGRcIiwgdmVyc2lvbjogZ2VuZXJhdG9yVmVyc2lvbn0sXG4gICAgb3duZXJzaGlwOiB7XG4gICAgICBleGNsdWRlZFBhdGhQYXR0ZXJucyxcbiAgICAgIG93bmVkUGF0aHMsXG4gICAgICBvd25lZFJvb3Q6IHByb2plY3RSb290LFxuICAgICAgc2hhMjU2OiBhcnRpZmFjdHMubWFwKGFydGlmYWN0ID0+ICh7cGF0aDogYXJ0aWZhY3QucGF0aCwgc2hhMjU2OiBoYXNoQ29udGVudChhcnRpZmFjdC5jb250ZW50KX0pKVxuICAgIH0sXG4gICAgcHJvdmVuYW5jZToge1xuICAgICAgY29uZmlndXJhdGlvbjogT2JqZWN0LmtleXMocHJlcGFyZWQuY29uZmlndXJhdGlvbikuc29ydCgpLm1hcChmaWVsZE5hbWUgPT4gKHtcbiAgICAgICAgZmllbGQ6IGZpZWxkTmFtZSxcbiAgICAgICAgbWFuaWZlc3RQb2ludGVyOiBgL2NvbmZpZ3VyYXRpb24vJHtmaWVsZE5hbWV9YCxcbiAgICAgICAgb3V0cHV0czogY29uZmlndXJhdGlvbk91dHB1dHMoc3BhbnMsIGZpZWxkTmFtZSlcbiAgICAgIH0pKSxcbiAgICAgIGlucHV0czogWy4uLnByZXBhcmVkLnJlc291cmNlcywgLi4ucHJlcGFyZWQuYXNzZXRzXS5tYXAoaXRlbSA9PiAoe1xuICAgICAgICBjb250ZW50S2luZDogaXRlbS5jb250ZW50S2luZCxcbiAgICAgICAgbWVkaWFUeXBlOiBpdGVtLm1lZGlhVHlwZSxcbiAgICAgICAgcGF0aDogaXRlbS5mdWxsUGF0aCxcbiAgICAgICAgc2hhMjU2OiBpdGVtLnNoYTI1NlxuICAgICAgfSkpLFxuICAgICAgc2VtYW50aWNTb3VyY2VzOiBwcmVwYXJlZC5zb3VyY2VzLm1hcChzb3VyY2UgPT4gKHtcbiAgICAgICAgYXJ0aWZhY3RzOiBzZW1hbnRpY0FydGlmYWN0cy5maWx0ZXIoYXJ0aWZhY3QgPT4gYXJ0aWZhY3QucHJvdmVuYW5jZS5raW5kID09IFwidGV4dFwiICYmXG4gICAgICAgICAgYXJ0aWZhY3QucHJvdmVuYW5jZS5tYXBwaW5nLnNwYW5zLnNvbWUoKHtvcmlnaW59KSA9PiBvcmlnaW5SZWZlcmVuY2VzRmlsZW5hbWUob3JpZ2luLCBzb3VyY2UuZmlsZW5hbWUpKSlcbiAgICAgICAgICAubWFwKCh7cGF0aH0pID0+IHBhdGgpLFxuICAgICAgICBmaWxlbmFtZTogc291cmNlLmZpbGVuYW1lLFxuICAgICAgICAuLi4oc291cmNlLmxhbmd1YWdlID09PSB1bmRlZmluZWQgPyB7fSA6IHtsYW5ndWFnZTogc291cmNlLmxhbmd1YWdlfSksXG4gICAgICAgIHNoYTI1NjogY3JlYXRlSGFzaChcInNoYTI1NlwiKS51cGRhdGUoc291cmNlLmNvbnRlbnQpLmRpZ2VzdChcImhleFwiKVxuICAgICAgfSkpLFxuICAgICAgc3ludGhldGljU2NhZmZvbGRpbmc6IFsuLi5hcnRpZmFjdHMuZmlsdGVyKGFydGlmYWN0ID0+IGFydGlmYWN0LnByb3ZlbmFuY2Uua2luZCA9PSBcInN5bnRoZXRpY1wiICYmXG4gICAgICAgICFpbnB1dFBhdGhzLmhhcyhhcnRpZmFjdC5wYXRoKSkubWFwKCh7cGF0aH0pID0+IHBhdGgpLCBtYW5pZmVzdFBhdGhdXG4gICAgfSxcbiAgICBzY2hlbWE6IFwiU2VtYW50aWZvbGRBbmRyb2lkUHJvamVjdFwiLFxuICAgIHNlbWFudGljUHJvZ3JhbTogc2VtYW50aWNQcm9ncmFtTWFuaWZlc3QocHJlcGFyZWQpLFxuICAgIHRhcmdldDogXCJhbmRyb2lkXCIsXG4gICAgdG9vbGNoYWluLFxuICAgIHZlcnNpb246IDFcbiAgfSlcbn1cblxuLyoqXG4gKiBSZW5kZXJzIHNlbWFudGljIG1vZHVsZSBhbmQgc291cmNlIGlkZW50aXRpZXMgZm9yIHRoZSBwcm9qZWN0IG1hbmlmZXN0LlxuICogQHBhcmFtIHtSZXR1cm5UeXBlPHR5cGVvZiBwcmVmbGlnaHRBbmRyb2lkQXBwbGljYXRpb24+fSBwcmVwYXJlZCAtIFByZXBhcmVkIGFwcGxpY2F0aW9uLlxuICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsIHVua25vd24+fSBTZW1hbnRpYyBwcm9ncmFtIG1hbmlmZXN0LlxuICovXG5mdW5jdGlvbiBzZW1hbnRpY1Byb2dyYW1NYW5pZmVzdChwcmVwYXJlZCkge1xuICBjb25zdCBzb3VyY2VDb250ZW50ID0gbmV3IE1hcChwcmVwYXJlZC5zb3VyY2VzLm1hcChzb3VyY2UgPT4gW3NvdXJjZS5maWxlbmFtZSwgc291cmNlLmNvbnRlbnRdKSlcbiAgY29uc3Qgb3JkZXIgPSBuZXcgTWFwKHByZXBhcmVkLnByb2dyYW0ubW9kdWxlcy5tYXAoKG1vZHVsZSwgaW5kZXgpID0+IFttb2R1bGUuaWQsIGluZGV4XSkpXG4gIGNvbnN0IG1vZHVsZXMgPSBwcmVwYXJlZC5wcm9ncmFtLm1vZHVsZXMubWFwKG1vZHVsZSA9PiB7XG4gICAgY29uc3Qgc291cmNlID0gcHJlcGFyZWQucHJvZ3JhbS5zb3VyY2VzLmZpbmQoY2FuZGlkYXRlID0+IGNhbmRpZGF0ZS5maWxlbmFtZSA9PSBtb2R1bGUuc291cmNlRmlsZW5hbWUpXG4gICAgY29uc3QgY29udGVudCA9IHNvdXJjZUNvbnRlbnQuZ2V0KG1vZHVsZS5zb3VyY2VGaWxlbmFtZSlcblxuICAgIGlmICghc291cmNlIHx8IGNvbnRlbnQgPT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IFR5cGVFcnJvcihgUHJlZmxpZ2h0ZWQgQW5kcm9pZCBtb2R1bGUgJyR7bW9kdWxlLmlkfScgbG9zdCBzb3VyY2Ugb3duZXJzaGlwLmApXG5cbiAgICByZXR1cm4ge1xuICAgICAgZGVwZW5kZW5jaWVzOiBbLi4ubmV3IFNldChtb2R1bGUuaW1wb3J0cy5tYXAoKHttb2R1bGVJZH0pID0+IG1vZHVsZUlkKSldXG4gICAgICAgIC5zb3J0KChsZWZ0LCByaWdodCkgPT4gLyoqIEB0eXBlIHtudW1iZXJ9ICovIChvcmRlci5nZXQobGVmdCkpIC0gLyoqIEB0eXBlIHtudW1iZXJ9ICovIChvcmRlci5nZXQocmlnaHQpKSksXG4gICAgICBnZW5lcmF0ZWRBcnRpZmFjdHM6IFtwcmVwYXJlZC5tb2R1bGVQYXRocy5nZXQobW9kdWxlLmlkKV0sXG4gICAgICBpZDogbW9kdWxlLmlkLFxuICAgICAgbmFtZXNwYWNlOiBgU2VtYW50aWZvbGRNb2R1bGUke21vZHVsZU5hbWUobW9kdWxlLmlkKX1gLFxuICAgICAgc291cmNlOiB7ZmlsZW5hbWU6IHNvdXJjZS5maWxlbmFtZSwgaWQ6IHNvdXJjZS5pZCwgc2hhMjU2OiBjcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShjb250ZW50KS5kaWdlc3QoXCJoZXhcIil9XG4gICAgfVxuICB9KVxuICBjb25zdCBlbnRyeUlkID0gcHJlcGFyZWQucHJvZ3JhbS5lbnRyeU1vZHVsZVxuXG4gIHJldHVybiB7XG4gICAgZW50cnk6IHtcbiAgICAgIGFjdGl2aXR5QXJ0aWZhY3Q6IGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4va290bGluLyR7cHJlcGFyZWQucGFja2FnZVBhdGh9LyR7cHJlcGFyZWQuY29uZmlndXJhdGlvbi5hY3Rpdml0eUNsYXNzTmFtZX0ua3RgLFxuICAgICAgZ2VuZXJhdGVkQXJ0aWZhY3Q6IHByZXBhcmVkLm1vZHVsZVBhdGhzLmdldChlbnRyeUlkKSxcbiAgICAgIGdlbmVyYXRlZEZ1bmN0aW9uSWRlbnRpdHk6IGBTZW1hbnRpZm9sZE1vZHVsZSR7bW9kdWxlTmFtZShlbnRyeUlkKX0uc2VtYW50aWZvbGRFbnRyeWAsXG4gICAgICBtb2R1bGVJZDogZW50cnlJZFxuICAgIH0sXG4gICAgbW9kdWxlcyxcbiAgICBzY2hlbWE6IFwiU2VtYW50aWZvbGRBbmRyb2lkU2VtYW50aWNQcm9ncmFtXCIsXG4gICAgc291cmNlczogcHJlcGFyZWQucHJvZ3JhbS5zb3VyY2VzLm1hcChzb3VyY2UgPT4gKHtcbiAgICAgIGZpbGVuYW1lOiBzb3VyY2UuZmlsZW5hbWUsXG4gICAgICBpZDogc291cmNlLmlkLFxuICAgICAgbGFuZ3VhZ2U6IHNvdXJjZS5sYW5ndWFnZSxcbiAgICAgIG1vZHVsZUlkczogbW9kdWxlcy5maWx0ZXIobW9kdWxlID0+IG1vZHVsZS5zb3VyY2UuZmlsZW5hbWUgPT0gc291cmNlLmZpbGVuYW1lKS5tYXAoKHtpZH0pID0+IGlkKSxcbiAgICAgIG93bmVyc2hpcDogc291cmNlLm93bmVyc2hpcCA/PyBcImFwcGxpY2F0aW9uXCIsXG4gICAgICBzaGEyNTY6IGNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKC8qKiBAdHlwZSB7c3RyaW5nfSAqLyAoc291cmNlQ29udGVudC5nZXQoc291cmNlLmZpbGVuYW1lKSkpLmRpZ2VzdChcImhleFwiKVxuICAgIH0pKSxcbiAgICB2ZXJzaW9uOiAxXG4gIH1cbn1cblxuLyoqXG4gKiBWYWxpZGF0ZXMgYW5kIG5vcm1hbGl6ZXMgdGhlIGNsb3NlZCBBbmRyb2lkIGNvbmZpZ3VyYXRpb24uXG4gKiBAcGFyYW0ge3Vua25vd259IGNhbmRpZGF0ZSAtIENhbmRpZGF0ZSBjb25maWd1cmF0aW9uLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkFuZHJvaWRBcHBsaWNhdGlvbkNvbmZpZ3VyYXRpb259IE5vcm1hbGl6ZWQgY29uZmlndXJhdGlvbi5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplQ29uZmlndXJhdGlvbihjYW5kaWRhdGUpIHtcbiAgaWYgKGNhbmRpZGF0ZSA9PT0gdW5kZWZpbmVkKSBjYW5kaWRhdGUgPSB7fVxuICBpZiAoIWlzUGxhaW5PYmplY3QoY2FuZGlkYXRlKSB8fCBPYmplY3Qua2V5cyhjYW5kaWRhdGUpLnNvbWUoa2V5ID0+ICFjb25maWd1cmF0aW9uRmllbGRzLmhhcyhrZXkpKSkge1xuICAgIGludmFsaWRDb25maWd1cmF0aW9uKFwiQW5kcm9pZCBhcHBsaWNhdGlvbiBjb25maWd1cmF0aW9uIG11c3QgYmUgYSBjbG9zZWQgcGxhaW4gb2JqZWN0LlwiKVxuICB9XG4gIGNvbnN0IGNvbmZpZ3VyYXRpb24gPSAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkFuZHJvaWRBcHBsaWNhdGlvbkNvbmZpZ3VyYXRpb25JbnB1dH0gKi8gKGNhbmRpZGF0ZSlcbiAgY29uc3QgYXBwbGljYXRpb25JZCA9IGNvbmZpZ3VyYXRpb24uYXBwbGljYXRpb25JZCA/PyBcImRldi5zZW1hbnRpZm9sZC5nZW5lcmF0ZWRcIlxuICBjb25zdCBuYW1lc3BhY2UgPSBjb25maWd1cmF0aW9uLm5hbWVzcGFjZSA/PyBhcHBsaWNhdGlvbklkXG4gIGNvbnN0IHBhY2thZ2VOYW1lID0gY29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZSA/PyBuYW1lc3BhY2VcbiAgY29uc3QgYWN0aXZpdHlDbGFzc05hbWUgPSBjb25maWd1cmF0aW9uLmFjdGl2aXR5Q2xhc3NOYW1lID8/IFwiTWFpbkFjdGl2aXR5XCJcbiAgY29uc3QgcHJvZHVjdE5hbWUgPSBjb25maWd1cmF0aW9uLnByb2R1Y3ROYW1lID8/IFwiU2VtYW50aWZvbGRcIlxuICBjb25zdCBkaXNwbGF5TmFtZSA9IGNvbmZpZ3VyYXRpb24uZGlzcGxheU5hbWUgPz8gXCJTZW1hbnRpZm9sZFwiXG4gIGNvbnN0IG1pbmltdW1TZGsgPSBjb25maWd1cmF0aW9uLm1pbmltdW1TZGsgPz8gMjNcbiAgY29uc3QgdGFyZ2V0U2RrID0gY29uZmlndXJhdGlvbi50YXJnZXRTZGsgPz8gdG9vbGNoYWluLnRhcmdldFNka1xuICBjb25zdCBjb21waWxlU2RrID0gY29uZmlndXJhdGlvbi5jb21waWxlU2RrID8/IHRvb2xjaGFpbi5jb21waWxlU2RrXG4gIGNvbnN0IGJ1aWxkVG9vbHNWZXJzaW9uID0gY29uZmlndXJhdGlvbi5idWlsZFRvb2xzVmVyc2lvbiA/PyB0b29sY2hhaW4uYnVpbGRUb29sc1xuICBjb25zdCB2ZXJzaW9uQ29kZSA9IGNvbmZpZ3VyYXRpb24udmVyc2lvbkNvZGUgPz8gMVxuICBjb25zdCB2ZXJzaW9uTmFtZSA9IGNvbmZpZ3VyYXRpb24udmVyc2lvbk5hbWUgPz8gXCIxLjAuMFwiXG4gIGNvbnN0IG9yaWVudGF0aW9uID0gY29uZmlndXJhdGlvbi5vcmllbnRhdGlvbiA/PyBcInVuc3BlY2lmaWVkXCJcbiAgY29uc3QgdGhlbWUgPSBjb25maWd1cmF0aW9uLnRoZW1lID8/IFwic3lzdGVtXCJcblxuICBmb3IgKGNvbnN0IFtsYWJlbCwgdmFsdWVdIG9mIFtbXCJBcHBsaWNhdGlvbiBJRFwiLCBhcHBsaWNhdGlvbklkXSwgW1wiTmFtZXNwYWNlXCIsIG5hbWVzcGFjZV0sIFtcIlBhY2thZ2UgbmFtZVwiLCBwYWNrYWdlTmFtZV1dKSB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSAhPSBcInN0cmluZ1wiIHx8ICFpc1BhY2thZ2VOYW1lKHZhbHVlKSkgaW52YWxpZENvbmZpZ3VyYXRpb24oYCR7bGFiZWx9IG11c3QgYmUgYSBsb3dlcmNhc2UgSmF2YSBwYWNrYWdlIGlkZW50aXR5LmApXG4gIH1cbiAgaWYgKHR5cGVvZiBhY3Rpdml0eUNsYXNzTmFtZSAhPSBcInN0cmluZ1wiIHx8ICEvXltBLVpdW0EtWmEtejAtOV0qJC91LnRlc3QoYWN0aXZpdHlDbGFzc05hbWUpIHx8IGtvdGxpbktleXdvcmRzLmhhcyhhY3Rpdml0eUNsYXNzTmFtZSkpIHtcbiAgICBpbnZhbGlkQ29uZmlndXJhdGlvbihcIkFjdGl2aXR5IGNsYXNzIG5hbWUgbXVzdCBiZSBhbiBBU0NJSSB1cHBlci1jYW1lbCBLb3RsaW4gaWRlbnRpZmllci5cIilcbiAgfVxuICBmb3IgKGNvbnN0IFtsYWJlbCwgdmFsdWVdIG9mIFtbXCJQcm9kdWN0IG5hbWVcIiwgcHJvZHVjdE5hbWVdLCBbXCJEaXNwbGF5IG5hbWVcIiwgZGlzcGxheU5hbWVdXSkge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgIT0gXCJzdHJpbmdcIiB8fCB2YWx1ZS5sZW5ndGggPT0gMCB8fCB2YWx1ZS50cmltKCkgIT0gdmFsdWUgfHwgWy4uLnZhbHVlXS5sZW5ndGggPiA2NCB8fFxuICAgICAgIWhhc09ubHlVbmljb2RlU2NhbGFycyh2YWx1ZSkgfHwgL1tcXHB7Q2N9XFxwe1psfVxccHtacH1cXHVGRkZFXFx1RkZGRl0vdS50ZXN0KHZhbHVlKSkge1xuICAgICAgaW52YWxpZENvbmZpZ3VyYXRpb24oYCR7bGFiZWx9IG11c3QgYmUgYSBub24tZW1wdHkgc2luZ2xlLWxpbmUgVW5pY29kZSBzY2FsYXIgc3RyaW5nIG9mIGF0IG1vc3QgNjQgY2hhcmFjdGVycy5gKVxuICAgIH1cbiAgfVxuICBpZiAoL1tcXFxcLzo8PlwiPyp8XS91LnRlc3QocHJvZHVjdE5hbWUpKSB7XG4gICAgaW52YWxpZENvbmZpZ3VyYXRpb24oXCJQcm9kdWN0IG5hbWUgY29udGFpbnMgYSBjaGFyYWN0ZXIgZm9yYmlkZGVuIGJ5IHRoZSBHcmFkbGUgcHJvamVjdC1uYW1lIGNvbnRyYWN0LlwiKVxuICB9XG4gIGlmIChtaW5pbXVtU2RrICE9PSAyMyB8fCB0YXJnZXRTZGsgIT09IDM1IHx8IGNvbXBpbGVTZGsgIT09IDM1IHx8IG1pbmltdW1TZGsgPiB0YXJnZXRTZGsgfHwgdGFyZ2V0U2RrID4gY29tcGlsZVNkaykge1xuICAgIGludmFsaWRDb25maWd1cmF0aW9uKFwiU0RLIGxldmVscyBtdXN0IHVzZSB0aGUgcXVhbGlmaWVkIG1pbmltdW0gMjMsIHRhcmdldCAzNSwgYW5kIGNvbXBpbGUgMzUgbWF0cml4LlwiKVxuICB9XG4gIGlmIChidWlsZFRvb2xzVmVyc2lvbiAhPSB0b29sY2hhaW4uYnVpbGRUb29scykgaW52YWxpZENvbmZpZ3VyYXRpb24oXCJCdWlsZCBUb29scyB2ZXJzaW9uIG11c3QgYmUgZXhhY3RseSAnMzUuMC4wJy5cIilcbiAgaWYgKCFOdW1iZXIuaXNTYWZlSW50ZWdlcih2ZXJzaW9uQ29kZSkgfHwgdmVyc2lvbkNvZGUgPCAxIHx8IHZlcnNpb25Db2RlID4gMl8xMDBfMDAwXzAwMCkge1xuICAgIGludmFsaWRDb25maWd1cmF0aW9uKFwiVmVyc2lvbiBjb2RlIG11c3QgYmUgYSBwb3NpdGl2ZSBBbmRyb2lkLXNhZmUgaW50ZWdlci5cIilcbiAgfVxuICBpZiAodHlwZW9mIHZlcnNpb25OYW1lICE9IFwic3RyaW5nXCIgfHwgIXNlbWFudGljVmVyc2lvblBhdHRlcm4udGVzdCh2ZXJzaW9uTmFtZSkpIHtcbiAgICBpbnZhbGlkQ29uZmlndXJhdGlvbihcIlZlcnNpb24gbmFtZSBtdXN0IGJlIGEgY2Fub25pY2FsIG5vbi1lbXB0eSBzZW1hbnRpYyB2ZXJzaW9uIHN0cmluZy5cIilcbiAgfVxuICBpZiAob3JpZW50YXRpb24gIT0gXCJ1bnNwZWNpZmllZFwiKSBpbnZhbGlkQ29uZmlndXJhdGlvbihcIlRoZSBiYXNlbGluZSBvcmllbnRhdGlvbiBpcyBleGFjdGx5ICd1bnNwZWNpZmllZCcuXCIpXG4gIGlmICh0aGVtZSAhPSBcInN5c3RlbVwiKSBpbnZhbGlkQ29uZmlndXJhdGlvbihcIlRoZSBiYXNlbGluZSB0aGVtZSBpcyBleGFjdGx5ICdzeXN0ZW0nLlwiKVxuICBpZiAoY29uZmlndXJhdGlvbi5wZXJtaXNzaW9ucyAhPT0gdW5kZWZpbmVkICYmXG4gICAgKCFpc0RlbnNlQXJyYXkoY29uZmlndXJhdGlvbi5wZXJtaXNzaW9ucykgfHwgY29uZmlndXJhdGlvbi5wZXJtaXNzaW9ucy5sZW5ndGggIT0gMCkpIHtcbiAgICBpbnZhbGlkQ29uZmlndXJhdGlvbihcIlRoZSBiYXNlbGluZSBBbmRyb2lkIHBlcm1pc3Npb24gc2V0IG11c3QgYmUgZW1wdHkuXCIpXG4gIH1cblxuICByZXR1cm4ge1xuICAgIGFjdGl2aXR5Q2xhc3NOYW1lLFxuICAgIGFwcGxpY2F0aW9uSWQsXG4gICAgYnVpbGRUb29sc1ZlcnNpb24sXG4gICAgY29tcGlsZVNkayxcbiAgICBkaXNwbGF5TmFtZSxcbiAgICBtaW5pbXVtU2RrLFxuICAgIG5hbWVzcGFjZSxcbiAgICBvcmllbnRhdGlvbixcbiAgICBwYWNrYWdlTmFtZSxcbiAgICBwcm9kdWN0TmFtZSxcbiAgICB0YXJnZXRTZGssXG4gICAgdGhlbWUsXG4gICAgdmVyc2lvbkNvZGUsXG4gICAgdmVyc2lvbk5hbWVcbiAgfVxufVxuXG4vKipcbiAqIFZhbGlkYXRlcywgc25hcHNob3RzLCBhbmQgb3JkZXJzIGNhbGxlci1wcm92aWRlZCBpbnB1dHMuXG4gKiBAcGFyYW0ge3Vua25vd259IGNhbmRpZGF0ZSAtIENhbmRpZGF0ZSByZXNvdXJjZSBvciBhc3NldCBsaXN0LlxuICogQHBhcmFtIHtcImFzc2V0XCIgfCBcInJlc291cmNlXCJ9IGtpbmQgLSBBbmRyb2lkIGlucHV0IGtpbmQuXG4gKiBAcmV0dXJucyB7QW5kcm9pZElucHV0RmlsZVtdfSBOb3JtYWxpemVkIGlucHV0cy5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplSW5wdXRGaWxlcyhjYW5kaWRhdGUsIGtpbmQpIHtcbiAgaWYgKGNhbmRpZGF0ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gW11cbiAgaWYgKCFpc0RlbnNlQXJyYXkoY2FuZGlkYXRlKSkgaW52YWxpZFJlc291cmNlKGBBcHBsaWNhdGlvbiAke2tpbmR9cyBtdXN0IGJlIGEgZGVuc2UgYXJyYXkuYClcbiAgLyoqIEB0eXBlIHtBbmRyb2lkSW5wdXRGaWxlW119ICovXG4gIGNvbnN0IGZpbGVzID0gW11cblxuICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgY2FuZGlkYXRlLmxlbmd0aDsgaW5kZXggKz0gMSkge1xuICAgIGNvbnN0IGl0ZW0gPSBjYW5kaWRhdGVbaW5kZXhdXG5cbiAgICBpZiAoIWlzUGxhaW5PYmplY3QoaXRlbSkgfHwgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoICE9IHJlc291cmNlRmllbGRzLnNpemUgfHxcbiAgICAgIE9iamVjdC5rZXlzKGl0ZW0pLnNvbWUoa2V5ID0+ICFyZXNvdXJjZUZpZWxkcy5oYXMoa2V5KSkpIGludmFsaWRSZXNvdXJjZShgJHtjYXBpdGFsaXplKGtpbmQpfSAke2luZGV4fSBtdXN0IHVzZSB0aGUgY2xvc2VkIGlucHV0IHNjaGVtYS5gKVxuICAgIGNvbnN0IHBhdGggPSBpdGVtLnBhdGhcbiAgICBjb25zdCBjb250ZW50ID0gaXRlbS5jb250ZW50XG4gICAgY29uc3QgbWVkaWFUeXBlID0gaXRlbS5tZWRpYVR5cGVcbiAgICBjb25zdCBzaGEyNTYgPSBpdGVtLnNoYTI1NlxuXG4gICAgaWYgKCFpc1NhZmVBcnRpZmFjdFBhdGgocGF0aCkgfHwga2luZCA9PSBcInJlc291cmNlXCIgJiYgIWlzQWxsb3dlZFJlc291cmNlUGF0aChwYXRoKSkge1xuICAgICAgaW52YWxpZFJlc291cmNlKGAke2NhcGl0YWxpemUoa2luZCl9ICR7aW5kZXh9IGhhcyBhbiB1bnNhZmUgb3IgdW5zdXBwb3J0ZWQgcGF0aC5gKVxuICAgIH1cbiAgICBpZiAodHlwZW9mIGNvbnRlbnQgIT0gXCJzdHJpbmdcIiAmJiAhKGNvbnRlbnQgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB8fCB0eXBlb2YgY29udGVudCA9PSBcInN0cmluZ1wiICYmXG4gICAgICAoY29udGVudC5sZW5ndGggPT0gMCB8fCAhaGFzT25seVVuaWNvZGVTY2FsYXJzKGNvbnRlbnQpKSB8fCBjb250ZW50IGluc3RhbmNlb2YgVWludDhBcnJheSAmJiBjb250ZW50LmJ5dGVMZW5ndGggPT0gMCkge1xuICAgICAgaW52YWxpZFJlc291cmNlKGAke2NhcGl0YWxpemUoa2luZCl9ICcke3BhdGh9JyByZXF1aXJlcyBub24tZW1wdHkgZXhhY3QgY29udGVudC5gKVxuICAgIH1cbiAgICBpZiAodHlwZW9mIG1lZGlhVHlwZSAhPSBcInN0cmluZ1wiIHx8ICFtZWRpYVR5cGVQYXR0ZXJuLnRlc3QobWVkaWFUeXBlKSB8fCAvW1xcclxcbl0vdS50ZXN0KG1lZGlhVHlwZSkpIHtcbiAgICAgIGludmFsaWRSZXNvdXJjZShgJHtjYXBpdGFsaXplKGtpbmQpfSAnJHtwYXRofScgcmVxdWlyZXMgYW4gZXhwbGljaXQgdmFsaWQgbWVkaWEgdHlwZS5gKVxuICAgIH1cbiAgICBpZiAoa2luZCA9PSBcInJlc291cmNlXCIgJiYgcGF0aC5zdGFydHNXaXRoKFwiZHJhd2FibGUtXCIpICYmICFbXCJpbWFnZS9wbmdcIiwgXCJpbWFnZS93ZWJwXCJdLmluY2x1ZGVzKG1lZGlhVHlwZSkpIHtcbiAgICAgIGludmFsaWRSZXNvdXJjZShgRHJhd2FibGUgcmVzb3VyY2UgJyR7cGF0aH0nIG11c3QgdXNlIFBORyBvciBXZWJQIG1lZGlhIHR5cGUuYClcbiAgICB9XG4gICAgY29uc3Qgc25hcHNob3QgPSB0eXBlb2YgY29udGVudCA9PSBcInN0cmluZ1wiID8gY29udGVudCA6IG5ldyBVaW50OEFycmF5KGNvbnRlbnQpXG4gICAgY29uc3QgYWN0dWFsSGFzaCA9IGNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKHNuYXBzaG90KS5kaWdlc3QoXCJoZXhcIilcblxuICAgIGlmICh0eXBlb2Ygc2hhMjU2ICE9IFwic3RyaW5nXCIgfHwgIS9eWzAtOWEtZl17NjR9JC91LnRlc3Qoc2hhMjU2KSB8fCBzaGEyNTYgIT0gYWN0dWFsSGFzaCkge1xuICAgICAgaW52YWxpZFJlc291cmNlKGAke2NhcGl0YWxpemUoa2luZCl9ICcke3BhdGh9JyBTSEEtMjU2IGRvZXMgbm90IG1hdGNoIGl0cyBleGFjdCBjb250ZW50LmApXG4gICAgfVxuICAgIGNvbnN0IGZ1bGxQYXRoID0gYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi8ke2tpbmQgPT0gXCJyZXNvdXJjZVwiID8gXCJyZXNcIiA6IFwiYXNzZXRzXCJ9LyR7cGF0aH1gXG5cbiAgICBmaWxlcy5wdXNoKHtjb250ZW50OiBzbmFwc2hvdCwgY29udGVudEtpbmQ6IHR5cGVvZiBzbmFwc2hvdCA9PSBcInN0cmluZ1wiID8gXCJ0ZXh0XCIgOiBcImJpbmFyeVwiLCBmdWxsUGF0aCwgbWVkaWFUeXBlLCBwYXRoLCBzaGEyNTZ9KVxuICB9XG4gIGZpbGVzLnNvcnQoKGxlZnQsIHJpZ2h0KSA9PiBsZWZ0LmZ1bGxQYXRoIDwgcmlnaHQuZnVsbFBhdGggPyAtMSA6IGxlZnQuZnVsbFBhdGggPiByaWdodC5mdWxsUGF0aCA/IDEgOiAwKVxuICBjb25zdCBjb25mbGljdCA9IGZpbmRQb3J0YWJsZUFydGlmYWN0UGF0aENvbmZsaWN0KGZpbGVzLm1hcCgoe2Z1bGxQYXRofSkgPT4gZnVsbFBhdGgpKVxuXG4gIGlmIChjb25mbGljdCkgaW52YWxpZFJlc291cmNlKGAke2NhcGl0YWxpemUoa2luZCl9IHBhdGggJyR7Y29uZmxpY3QucGF0aH0nIGhhcyBhICR7Y29uZmxpY3Qua2luZH0gY29uZmxpY3QuYClcbiAgaWYgKGtpbmQgPT0gXCJyZXNvdXJjZVwiKSB2YWxpZGF0ZVJlc291cmNlSWRlbnRpZmllcnMoZmlsZXMpXG5cbiAgcmV0dXJuIGZpbGVzXG59XG5cbi8qKlxuICogUmVqZWN0cyB0d28gZmlsZXMgdGhhdCBBbmRyb2lkIHdvdWxkIGNvbXBpbGUgdG8gdGhlIHNhbWUgcmVzb3VyY2UgaWRlbnRpZmllciBpbiBvbmUgY29uZmlndXJhdGlvbi5cbiAqIEBwYXJhbSB7QW5kcm9pZElucHV0RmlsZVtdfSBmaWxlcyAtIFZhbGlkYXRlZCByZXNvdXJjZSBpbnB1dHMuXG4gKi9cbmZ1bmN0aW9uIHZhbGlkYXRlUmVzb3VyY2VJZGVudGlmaWVycyhmaWxlcykge1xuICBjb25zdCBpZGVudGlmaWVycyA9IG5ldyBNYXAoKVxuXG4gIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgIGNvbnN0IHNlcGFyYXRvciA9IGZpbGUucGF0aC5pbmRleE9mKFwiL1wiKVxuICAgIGNvbnN0IGRpcmVjdG9yeSA9IGZpbGUucGF0aC5zbGljZSgwLCBzZXBhcmF0b3IpXG4gICAgY29uc3QgZmlsZW5hbWUgPSBmaWxlLnBhdGguc2xpY2Uoc2VwYXJhdG9yICsgMSlcbiAgICBjb25zdCBleHRlbnNpb24gPSBmaWxlbmFtZS5pbmRleE9mKFwiLlwiKVxuICAgIGNvbnN0IG5hbWUgPSBleHRlbnNpb24gPT0gLTEgPyBmaWxlbmFtZSA6IGZpbGVuYW1lLnNsaWNlKDAsIGV4dGVuc2lvbilcbiAgICBjb25zdCByZXNvdXJjZVR5cGUgPSBkaXJlY3Rvcnkuc3BsaXQoXCItXCIsIDEpWzBdXG4gICAgY29uc3Qga2V5ID0gYCR7ZGlyZWN0b3J5fS8ke25hbWV9YFxuICAgIGNvbnN0IHByZXZpb3VzID0gaWRlbnRpZmllcnMuZ2V0KGtleSlcblxuICAgIGlmIChwcmV2aW91cykge1xuICAgICAgaW52YWxpZFJlc291cmNlKGBBbmRyb2lkIHJlc291cmNlIGlkZW50aWZpZXIgJyR7cmVzb3VyY2VUeXBlfS8ke25hbWV9JyBjb2xsaWRlcyBiZXR3ZWVuICcke3ByZXZpb3VzfScgYW5kICcke2ZpbGUucGF0aH0nIGluIGNvbmZpZ3VyYXRpb24gJyR7ZGlyZWN0b3J5fScuYClcbiAgICB9XG4gICAgaWRlbnRpZmllcnMuc2V0KGtleSwgZmlsZS5wYXRoKVxuICB9XG59XG5cbi8qKlxuICogVGVzdHMgd2hldGhlciBhIGNhbGxlciByZXNvdXJjZSB1c2VzIHRoZSBuYXJyb3cgYWxsb3dsaXN0ZWQgcmVzb3VyY2UgZ3JhbW1hci5cbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFJlc291cmNlIHBhdGggcmVsYXRpdmUgdG8gcmVzLlxuICogQHJldHVybnMge2Jvb2xlYW59IFdoZXRoZXIgdGhlIHBhdGggaXMgc3VwcG9ydGVkLlxuICovXG5mdW5jdGlvbiBpc0FsbG93ZWRSZXNvdXJjZVBhdGgodmFsdWUpIHtcbiAgaWYgKC9ecmF3XFwvW2Etel1bYS16MC05X10qKD86XFwuW2EtejAtOV0rKT8kL3UudGVzdCh2YWx1ZSkpIHJldHVybiB0cnVlXG5cbiAgcmV0dXJuIC9eZHJhd2FibGUtKD86bWRwaXxoZHBpfHhoZHBpfHh4aGRwaXx4eHhoZHBpKVxcL1thLXpdW2EtejAtOV9dKlxcLig/OnBuZ3x3ZWJwKSQvdS50ZXN0KHZhbHVlKVxufVxuXG4vKipcbiAqIENvbnZlcnRzIGEgdmFsaWRhdGVkIGlucHV0IHNuYXBzaG90IGludG8gYW4gb3duZWQgYXJ0aWZhY3QuXG4gKiBAcGFyYW0ge0FuZHJvaWRJbnB1dEZpbGV9IGl0ZW0gLSBWYWxpZGF0ZWQgY2FsbGVyIGlucHV0LlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZFNldEFydGlmYWN0fSBPd25lZCBpbnB1dCBhcnRpZmFjdC5cbiAqL1xuZnVuY3Rpb24gaW5wdXRGaWxlQXJ0aWZhY3QoaXRlbSkge1xuICBjb25zdCByZWFzb24gPSBgRXhhY3QgY2FsbGVyLXByb3ZpZGVkIEFuZHJvaWQgaW5wdXQgKHNoYTI1Njoke2l0ZW0uc2hhMjU2fSkuYFxuXG4gIGlmICh0eXBlb2YgaXRlbS5jb250ZW50ID09IFwic3RyaW5nXCIpIHtcbiAgICByZXR1cm4ge1xuICAgICAgLi4uc3ludGhldGljVGV4dChpdGVtLmZ1bGxQYXRoLCBcInJlc291cmNlXCIsIGl0ZW0uY29udGVudCwgcmVhc29uKSxcbiAgICAgIG1lZGlhVHlwZTogaXRlbS5tZWRpYVR5cGVcbiAgICB9XG4gIH1cbiAgY29uc3QgY29udGVudCA9IG5ldyBVaW50OEFycmF5KGl0ZW0uY29udGVudClcblxuICByZXR1cm4ge1xuICAgIGNvbnRlbnQsXG4gICAgY29udGVudEtpbmQ6IFwiYmluYXJ5XCIsXG4gICAgbWVkaWFUeXBlOiBpdGVtLm1lZGlhVHlwZSxcbiAgICBvd25lcnNoaXA6IFwiZ2VuZXJhdGVkXCIsXG4gICAgcGF0aDogaXRlbS5mdWxsUGF0aCxcbiAgICBwcm92ZW5hbmNlOiB7a2luZDogXCJieXRlc1wiLCBtYXBwaW5nOiBjcmVhdGVCeXRlTWFwcGluZyh7XG4gICAgICBieXRlTGVuZ3RoOiBjb250ZW50LmJ5dGVMZW5ndGgsXG4gICAgICBwYXRoOiBpdGVtLmZ1bGxQYXRoLFxuICAgICAgcmFuZ2VzOiBbe2dlbmVyYXRlZDoge2VuZDogY29udGVudC5ieXRlTGVuZ3RoLCBzdGFydDogMH0sXG4gICAgICAgIG9yaWdpbjoge2tpbmQ6IFwic3ludGhldGljXCIsIHJlYXNvbiwgcmVsYXRlZE9yaWdpbnM6IFtdfSwgcm9sZTogXCJyZXNvdXJjZVwifV1cbiAgICB9KX0sXG4gICAgcm9sZTogXCJyZXNvdXJjZVwiXG4gIH1cbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgZGV0ZXJtaW5pc3RpYyBzeW50aGV0aWMgdGV4dCBhcnRpZmFjdC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gQXJ0aWZhY3QgcGF0aC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuR2VuZXJhdGVkQXJ0aWZhY3RSb2xlfSByb2xlIC0gQXJ0aWZhY3Qgcm9sZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBjb250ZW50IC0gVVRGLTggYXJ0aWZhY3QgY29udGVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSByZWFzb24gLSBTeW50aGV0aWMgcHJvdmVuYW5jZSByZWFzb24uXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuR2VuZXJhdGVkU2V0QXJ0aWZhY3R9IFRleHQgYXJ0aWZhY3QuXG4gKi9cbmZ1bmN0aW9uIHN5bnRoZXRpY1RleHQocGF0aCwgcm9sZSwgY29udGVudCwgcmVhc29uKSB7XG4gIHJldHVybiB7Y29udGVudCwgY29udGVudEtpbmQ6IFwidGV4dFwiLCBtZWRpYVR5cGU6IG1lZGlhVHlwZUZvcihwYXRoKSwgb3duZXJzaGlwOiBcImdlbmVyYXRlZFwiLCBwYXRoLFxuICAgIHByb3ZlbmFuY2U6IHtraW5kOiBcInN5bnRoZXRpY1wiLCByZWFzb24sIHJlbGF0ZWRPcmlnaW5zOiBbXX0sIHJvbGV9XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIGNvbmZpZ3VyYXRpb24tZGVyaXZlZCB0ZXh0IGFydGlmYWN0LlxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBBcnRpZmFjdCBwYXRoLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0ZWRBcnRpZmFjdFJvbGV9IHJvbGUgLSBBcnRpZmFjdCByb2xlLlxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnRlbnQgLSBVVEYtOCBhcnRpZmFjdCBjb250ZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IHJlYXNvbiAtIFN5bnRoZXRpYyBwcm92ZW5hbmNlIHJlYXNvbi5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0ZWRTZXRBcnRpZmFjdH0gVGV4dCBhcnRpZmFjdC5cbiAqL1xuZnVuY3Rpb24gY29uZmlndXJlZFRleHQocGF0aCwgcm9sZSwgY29udGVudCwgcmVhc29uKSB7XG4gIHJldHVybiBzeW50aGV0aWNUZXh0KHBhdGgsIHJvbGUsIGNvbnRlbnQsIHJlYXNvbilcbn1cblxuLyoqXG4gKiBEZXJpdmVzIHRoZSBtZWRpYSB0eXBlIGZvciBhIGdlbmVyYXRlZCB0ZXh0IHBhdGguXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIEdlbmVyYXRlZCBhcnRpZmFjdCBwYXRoLlxuICogQHJldHVybnMge3N0cmluZ30gQXJ0aWZhY3QgbWVkaWEgdHlwZS5cbiAqL1xuZnVuY3Rpb24gbWVkaWFUeXBlRm9yKHBhdGgpIHtcbiAgaWYgKHBhdGguZW5kc1dpdGgoXCIuanNvblwiKSkgcmV0dXJuIFwiYXBwbGljYXRpb24vanNvblwiXG4gIGlmIChwYXRoLmVuZHNXaXRoKFwiLnhtbFwiKSkgcmV0dXJuIFwiYXBwbGljYXRpb24veG1sXCJcbiAgaWYgKHBhdGguZW5kc1dpdGgoXCIua3RcIikgfHwgcGF0aC5lbmRzV2l0aChcIi5rdHNcIikpIHJldHVybiBcInRleHQveC1rb3RsaW5cIlxuXG4gIHJldHVybiBcInRleHQvcGxhaW5cIlxufVxuXG4vKipcbiAqIE1hcmtzIG9uZSByZW5kZXJlZCB2YWx1ZSBhcyBjb25maWd1cmF0aW9uLWRlcml2ZWQuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmllbGROYW1lIC0gQ29uZmlndXJhdGlvbiBmaWVsZCBuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlIC0gUmVuZGVyZWQgZmllbGQgdmFsdWUuXG4gKiBAcmV0dXJucyB7e2ZpZWxkOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmd9fSBNYXJrZWQgY29uZmlndXJhdGlvbiB2YWx1ZS5cbiAqL1xuZnVuY3Rpb24gZmllbGQoZmllbGROYW1lLCB2YWx1ZSkge1xuICByZXR1cm4ge2ZpZWxkOiBmaWVsZE5hbWUsIHZhbHVlfVxufVxuXG4vKipcbiAqIEpvaW5zIHJlbmRlcmVkIHBhcnRzIHdoaWxlIHJlY29yZGluZyBjb25maWd1cmF0aW9uIGNhdXNhbGl0eS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gT3V0cHV0IGFydGlmYWN0IHBhdGguXG4gKiBAcGFyYW0ge0NvbmZpZ3VyYXRpb25TcGFuW119IHNwYW5zIC0gTXV0YWJsZSBwcm92ZW5hbmNlIHNwYW4gY29sbGVjdG9yLlxuICogQHBhcmFtIHsoc3RyaW5nIHwge2ZpZWxkOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmd9KVtdfSBwYXJ0cyAtIFN5bnRoZXRpYyBhbmQgbWFya2VkIHBhcnRzLlxuICogQHJldHVybnMge3N0cmluZ30gUmVuZGVyZWQgdGV4dC5cbiAqL1xuZnVuY3Rpb24gY29uZmlndXJlZChwYXRoLCBzcGFucywgcGFydHMpIHtcbiAgbGV0IGNvbnRlbnQgPSBcIlwiXG5cbiAgZm9yIChjb25zdCBwYXJ0IG9mIHBhcnRzKSB7XG4gICAgaWYgKHR5cGVvZiBwYXJ0ID09IFwic3RyaW5nXCIpIGNvbnRlbnQgKz0gcGFydFxuICAgIGVsc2Uge1xuICAgICAgY29uc3Qgc3RhcnQgPSBjb250ZW50Lmxlbmd0aFxuXG4gICAgICBjb250ZW50ICs9IHBhcnQudmFsdWVcbiAgICAgIHNwYW5zLnB1c2goe2VuZDogY29udGVudC5sZW5ndGgsIGZpZWxkOiBwYXJ0LmZpZWxkLCBwYXRoLCBzdGFydH0pXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGNvbnRlbnRcbn1cblxuLyoqXG4gKiBHcm91cHMgY29uZmlndXJhdGlvbiBzcGFucyBieSBhcnRpZmFjdC5cbiAqIEBwYXJhbSB7Q29uZmlndXJhdGlvblNwYW5bXX0gc3BhbnMgLSBBbGwgcmVuZGVyZWQgY29uZmlndXJhdGlvbiBzcGFucy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWVsZE5hbWUgLSBSZXF1ZXN0ZWQgY29uZmlndXJhdGlvbiBmaWVsZC5cbiAqIEByZXR1cm5zIHt7cGF0aDogc3RyaW5nLCByYW5nZXM6IHtlbmQ6IG51bWJlciwgc3RhcnQ6IG51bWJlcn1bXX1bXX0gT3V0cHV0IHJhbmdlcy5cbiAqL1xuZnVuY3Rpb24gY29uZmlndXJhdGlvbk91dHB1dHMoc3BhbnMsIGZpZWxkTmFtZSkge1xuICBjb25zdCBncm91cGVkID0gbmV3IE1hcCgpXG5cbiAgZm9yIChjb25zdCBzcGFuIG9mIHNwYW5zKSB7XG4gICAgaWYgKHNwYW4uZmllbGQgIT0gZmllbGROYW1lKSBjb250aW51ZVxuICAgIGNvbnN0IHJhbmdlcyA9IGdyb3VwZWQuZ2V0KHNwYW4ucGF0aCkgPz8gW11cblxuICAgIHJhbmdlcy5wdXNoKHtlbmQ6IHNwYW4uZW5kLCBzdGFydDogc3Bhbi5zdGFydH0pXG4gICAgZ3JvdXBlZC5zZXQoc3Bhbi5wYXRoLCByYW5nZXMpXG4gIH1cblxuICByZXR1cm4gWy4uLmdyb3VwZWRdLm1hcCgoW3BhdGgsIHJhbmdlc10pID0+ICh7cGF0aCwgcmFuZ2VzfSkpXG59XG5cbi8qKlxuICogVGVzdHMgd2hldGhlciBhIG1hcHBpbmcgb3JpZ2luIHJlZmVycyB0byBvbmUgc2VtYW50aWMgc291cmNlIGZpbGUuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljT3JpZ2lufSBvcmlnaW4gLSBNYXBwaW5nIG9yaWdpbi5cbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAtIFNlbWFudGljIHNvdXJjZSBmaWxlbmFtZS5cbiAqIEByZXR1cm5zIHtib29sZWFufSBXaGV0aGVyIHRoZSBvcmlnaW4gb3ducyB0aGUgZmlsZW5hbWUuXG4gKi9cbmZ1bmN0aW9uIG9yaWdpblJlZmVyZW5jZXNGaWxlbmFtZShvcmlnaW4sIGZpbGVuYW1lKSB7XG4gIGlmIChvcmlnaW4ua2luZCA9PSBcInNvdXJjZVwiKSByZXR1cm4gb3JpZ2luLmxvY2F0aW9uLmZpbGVuYW1lID09IGZpbGVuYW1lXG4gIGlmIChvcmlnaW4ua2luZCA9PSBcImRlcml2ZWRcIikgcmV0dXJuIG9yaWdpbi5vcmlnaW5zLnNvbWUoKHtsb2NhdGlvbn0pID0+IGxvY2F0aW9uLmZpbGVuYW1lID09IGZpbGVuYW1lKVxuXG4gIHJldHVybiBvcmlnaW4ucmVsYXRlZE9yaWdpbnMuc29tZSgoe2xvY2F0aW9ufSkgPT4gbG9jYXRpb24uZmlsZW5hbWUgPT0gZmlsZW5hbWUpXG59XG5cbi8qKlxuICogSGFzaGVzIGV4YWN0IHRleHQgb3IgYnl0ZXMgZm9yIG93bmVyc2hpcCByZWNvcmRzLlxuICogQHBhcmFtIHtzdHJpbmcgfCBVaW50OEFycmF5fSBjb250ZW50IC0gRXhhY3QgYXJ0aWZhY3QgY29udGVudC5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IExvd2VyY2FzZSBTSEEtMjU2IGRpZ2VzdC5cbiAqL1xuZnVuY3Rpb24gaGFzaENvbnRlbnQoY29udGVudCkge1xuICByZXR1cm4gY3JlYXRlSGFzaChcInNoYTI1NlwiKS51cGRhdGUoY29udGVudCkuZGlnZXN0KFwiaGV4XCIpXG59XG5cbi8qKlxuICogU2VyaWFsaXplcyBKU09OIHdpdGggcmVjdXJzaXZlbHkgc3RhYmxlIG9iamVjdC1rZXkgb3JkZXJpbmcuXG4gKiBAcGFyYW0ge3Vua25vd259IHZhbHVlIC0gSlNPTi1jb21wYXRpYmxlIHZhbHVlLlxuICogQHJldHVybnMge3N0cmluZ30gQ2Fub25pY2FsIGluZGVudGVkIEpTT04gd2l0aCB0cmFpbGluZyBuZXdsaW5lLlxuICovXG5mdW5jdGlvbiBzdHJpbmdpZnlDYW5vbmljYWxKc29uKHZhbHVlKSB7XG4gIHJldHVybiBgJHtKU09OLnN0cmluZ2lmeShzb3J0SnNvbih2YWx1ZSksIG51bGwsIDIpfVxcbmBcbn1cblxuLyoqXG4gKiBSZWN1cnNpdmVseSBzb3J0cyBvYmplY3Qga2V5cyB3aXRob3V0IGNoYW5naW5nIGFycmF5IG9yZGVyLlxuICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIEpTT04tY29tcGF0aWJsZSB2YWx1ZS5cbiAqIEByZXR1cm5zIHt1bmtub3dufSBDYW5vbmljYWxseSBvcmRlcmVkIHZhbHVlLlxuICovXG5mdW5jdGlvbiBzb3J0SnNvbih2YWx1ZSkge1xuICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHJldHVybiB2YWx1ZS5tYXAoc29ydEpzb24pXG4gIGlmICghaXNQbGFpbk9iamVjdCh2YWx1ZSkpIHJldHVybiB2YWx1ZVxuXG4gIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmtleXModmFsdWUpLnNvcnQoKS5tYXAoa2V5ID0+IFtrZXksIHNvcnRKc29uKHZhbHVlW2tleV0pXSkpXG59XG5cbi8qKlxuICogVGVzdHMgYSBsb3dlcmNhc2UgS290bGluLWNvbXBhdGlibGUgcGFja2FnZSBpZGVudGl0eS5cbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIENhbmRpZGF0ZSBwYWNrYWdlIG5hbWUuXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gV2hldGhlciB0aGUgbmFtZSBpcyBhY2NlcHRlZC5cbiAqL1xuZnVuY3Rpb24gaXNQYWNrYWdlTmFtZSh2YWx1ZSkge1xuICBjb25zdCBwYXJ0cyA9IHZhbHVlLnNwbGl0KFwiLlwiKVxuXG4gIHJldHVybiBwYXJ0cy5sZW5ndGggPj0gMiAmJiBwYXJ0cy5ldmVyeShwYXJ0ID0+IC9eW2Etel1bYS16MC05X10qJC91LnRlc3QocGFydCkgJiYgIWtvdGxpbktleXdvcmRzLmhhcyhwYXJ0KSlcbn1cblxuLyoqXG4gKiBSZWplY3RzIGxhdW5jaGVyIG5hbWVzIHRoYXQgc2hhZG93IGFuIHVucXVhbGlmaWVkIHN5bWJvbCBpbiBnZW5lcmF0ZWQgc2FtZS1wYWNrYWdlIEtvdGxpbi5cbiAqIEBwYXJhbSB7c3RyaW5nfSBhY3Rpdml0eUNsYXNzTmFtZSAtIFZhbGlkYXRlZCBsYXVuY2hlciBjbGFzcyBuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IGVudHJ5TW9kdWxlIC0gU2VsZWN0ZWQgc2VtYW50aWMgZW50cnkgbW9kdWxlLlxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZUFjdGl2aXR5Q2xhc3NOYW1lKGFjdGl2aXR5Q2xhc3NOYW1lLCBlbnRyeU1vZHVsZSkge1xuICBjb25zdCBzZW1hbnRpY0VudHJ5U3ltYm9sID0gYFNlbWFudGlmb2xkTW9kdWxlJHttb2R1bGVOYW1lKGVudHJ5TW9kdWxlKX1gXG5cbiAgaWYgKGFuZHJvaWRTY2FmZm9sZFN5bWJvbHMuaGFzKGFjdGl2aXR5Q2xhc3NOYW1lKSB8fCBhY3Rpdml0eUNsYXNzTmFtZSA9PSBzZW1hbnRpY0VudHJ5U3ltYm9sKSB7XG4gICAgaW52YWxpZENvbmZpZ3VyYXRpb24oYEFjdGl2aXR5IGNsYXNzIG5hbWUgJyR7YWN0aXZpdHlDbGFzc05hbWV9JyBjb2xsaWRlcyB3aXRoIGdlbmVyYXRlZCBLb3RsaW4gc3ltYm9sICcke2FjdGl2aXR5Q2xhc3NOYW1lfScuYClcbiAgfVxufVxuXG4vKipcbiAqIEFsbG9jYXRlcyBvbmUgbW9kdWxlLXdpZGUgb3V0cHV0IHNpbmsgdGhhdCBjYW5ub3Qgc2hhZG93IGEgc291cmNlIGJpbmRpbmcuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljTW9kdWxlfSBtb2R1bGUgLSBQcmVwYXJlZCBzZW1hbnRpYyBtb2R1bGUuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBDb2xsaXNpb24tc2FmZSBLb3RsaW4gYmluZGluZy5cbiAqL1xuZnVuY3Rpb24gb3V0cHV0U2lua05hbWUobW9kdWxlKSB7XG4gIGNvbnN0IGJpbmRpbmdzID0gbmV3IFNldChtb2R1bGUuZnVuY3Rpb25zLmZsYXRNYXAoZGVjbGFyYXRpb24gPT4gZGVjbGFyYXRpb24ucGFyYW1ldGVycy5tYXAoKHtuYW1lfSkgPT4gbmFtZSkpKVxuXG4gIGZvciAoY29uc3QgZGVjbGFyYXRpb24gb2YgbW9kdWxlLmZ1bmN0aW9ucykgY29sbGVjdEJsb2NrQmluZGluZ05hbWVzKGRlY2xhcmF0aW9uLmJvZHksIGJpbmRpbmdzKVxuICBjb2xsZWN0QmxvY2tCaW5kaW5nTmFtZXMobW9kdWxlLmVudHJ5UG9pbnQuYm9keSwgYmluZGluZ3MpXG4gIGxldCBjYW5kaWRhdGUgPSBcInNlbWFudGlmb2xkT3V0cHV0XCJcblxuICB3aGlsZSAoYmluZGluZ3MuaGFzKGNhbmRpZGF0ZSkpIGNhbmRpZGF0ZSArPSBcIl9cIlxuXG4gIHJldHVybiBjYW5kaWRhdGVcbn1cblxuLyoqXG4gKiBDb2xsZWN0cyBsb2NhbCBiaW5kaW5ncyByZWN1cnNpdmVseSBmcm9tIHRoZSBzdXBwb3J0ZWQgc2VtYW50aWMgYmxvY2sgc3Vic2V0LlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5CbG9ja30gYmxvY2sgLSBTZW1hbnRpYyBibG9jay5cbiAqIEBwYXJhbSB7U2V0PHN0cmluZz59IGJpbmRpbmdzIC0gTXV0YWJsZSBiaW5kaW5nLW5hbWUgc2V0LlxuICovXG5mdW5jdGlvbiBjb2xsZWN0QmxvY2tCaW5kaW5nTmFtZXMoYmxvY2ssIGJpbmRpbmdzKSB7XG4gIGZvciAoY29uc3Qgc3RhdGVtZW50IG9mIGJsb2NrLnN0YXRlbWVudHMpIHtcbiAgICBpZiAoc3RhdGVtZW50LmtpbmQgPT0gXCJMb2NhbERlY2xhcmF0aW9uXCIpIGJpbmRpbmdzLmFkZChzdGF0ZW1lbnQubmFtZSlcbiAgICBlbHNlIGlmIChzdGF0ZW1lbnQua2luZCA9PSBcIklmU3RhdGVtZW50XCIpIHtcbiAgICAgIGNvbGxlY3RCbG9ja0JpbmRpbmdOYW1lcyhzdGF0ZW1lbnQuY29uc2VxdWVudCwgYmluZGluZ3MpXG4gICAgICBpZiAoc3RhdGVtZW50LmFsdGVybmF0ZSkgY29sbGVjdEJsb2NrQmluZGluZ05hbWVzKHN0YXRlbWVudC5hbHRlcm5hdGUsIGJpbmRpbmdzKVxuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIE1hcHMgYSBwcmVmbGlnaHRlZCBtb2R1bGUgaWRlbnRpdHkgdG8gYSBzdGFibGUgS290bGluIHN1ZmZpeC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBpZCAtIFNlbWFudGljIG1vZHVsZSBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEtvdGxpbiBvYmplY3QtbmFtZSBzdWZmaXguXG4gKi9cbmZ1bmN0aW9uIG1vZHVsZU5hbWUoaWQpIHtcbiAgcmV0dXJuIGlkLnNwbGl0KC9bLl8tXSsvdSkubWFwKHBhcnQgPT4gYCR7cGFydFswXS50b1VwcGVyQ2FzZSgpfSR7cGFydC5zbGljZSgxKX1gKS5qb2luKFwiXCIpXG59XG5cbi8qKlxuICogV3JhcHMgbGVnYWN5IHNpbmdsZS1tb2R1bGUgaW5wdXQgaW4gdGhlIGNhbm9uaWNhbCBwcm9ncmFtIGNvbnRyYWN0LlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY01vZHVsZSB8IHVuZGVmaW5lZH0gY2FuZGlkYXRlIC0gQ2FuZGlkYXRlIHNlbWFudGljIG1vZHVsZS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY1Byb2dyYW19IENhbm9uaWNhbCBzaW5nbGUtbW9kdWxlIHByb2dyYW0uXG4gKi9cbmZ1bmN0aW9uIG5vcm1hbGl6ZVNpbmdsZU1vZHVsZShjYW5kaWRhdGUpIHtcbiAgaWYgKCFpc1BsYWluT2JqZWN0KGNhbmRpZGF0ZSkpIHVuc3VwcG9ydGVkQ2FwYWJpbGl0eShcImFuZHJvaWRcIiwgXCJtaXNzaW5nIG9yIGludmFsaWQgbW9kdWxlXCIsIHVuZGVmaW5lZClcbiAgY29uc3QgbW9kdWxlID0gc3RydWN0dXJlZENsb25lKGNhbmRpZGF0ZSlcbiAgY29uc3Qgc291cmNlcyA9IG1vZHVsZS5wcm92ZW5hbmNlPy5zb3VyY2VzXG5cbiAgaWYgKCFBcnJheS5pc0FycmF5KHNvdXJjZXMpIHx8IHNvdXJjZXMubGVuZ3RoICE9IDEgfHwgc291cmNlc1swXS5jb250ZW50ID09PSBudWxsIHx8XG4gICAgc291cmNlc1swXS5maWxlbmFtZSAhPSBtb2R1bGUubG9jYXRpb24/LmZpbGVuYW1lIHx8IHR5cGVvZiBzb3VyY2VzWzBdLmxhbmd1YWdlICE9IFwic3RyaW5nXCIpIHtcbiAgICB1bnN1cHBvcnRlZENhcGFiaWxpdHkoXCJhbmRyb2lkXCIsIFwic2luZ2xlLW1vZHVsZSBzb3VyY2Ugb3duZXJzaGlwXCIsIG1vZHVsZS5sb2NhdGlvbilcbiAgfVxuICByZWtleU1vZHVsZURlY2xhcmF0aW9ucyhtb2R1bGUsIFwibWFpblwiKVxuICBjb25zdCBleHBvcnRzID0gW1xuICAgIC4uLihtb2R1bGUucmVjb3JkcyA/PyBbXSkubWFwKGRlY2xhcmF0aW9uID0+IGFwcGxpY2F0aW9uRXhwb3J0KGRlY2xhcmF0aW9uLCBcInJlY29yZFwiKSksXG4gICAgLi4uKG1vZHVsZS5jbGFzc2VzID8/IFtdKS5tYXAoZGVjbGFyYXRpb24gPT4gYXBwbGljYXRpb25FeHBvcnQoZGVjbGFyYXRpb24sIFwiY2xhc3NcIikpLFxuICAgIC4uLihtb2R1bGUuZXJyb3JzID8/IFtdKS5tYXAoZGVjbGFyYXRpb24gPT4gYXBwbGljYXRpb25FeHBvcnQoZGVjbGFyYXRpb24sIFwiZXJyb3JcIikpLFxuICAgIC4uLm1vZHVsZS5mdW5jdGlvbnMubWFwKGRlY2xhcmF0aW9uID0+IGFwcGxpY2F0aW9uRXhwb3J0KGRlY2xhcmF0aW9uLCBcImZ1bmN0aW9uXCIpKVxuICBdXG4gIGNvbnN0IHByb2dyYW1Nb2R1bGUgPSB7Li4ubW9kdWxlLCBleHBvcnRzLCBpZDogXCJtYWluXCIsIGltcG9ydHM6IFtdLCBzb3VyY2VGaWxlbmFtZTogc291cmNlc1swXS5maWxlbmFtZX1cblxuICByZXR1cm4ge2VudHJ5TW9kdWxlOiBcIm1haW5cIiwga2luZDogXCJQcm9ncmFtXCIsIG1vZHVsZXM6IFtwcm9ncmFtTW9kdWxlXSwgc291cmNlczogc3RydWN0dXJlZENsb25lKHNvdXJjZXMpfVxufVxuXG4vKipcbiAqIENyZWF0ZXMgYW4gYXBwbGljYXRpb24tbG9jYWwgZXhwb3J0IHJlY29yZCBmb3Igc2luZ2xlLW1vZHVsZSBjb21wYXRpYmlsaXR5LlxuICogQHBhcmFtIHt7aWQ/OiBzdHJpbmcsIGxvY2F0aW9uOiBpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5Tb3VyY2VMb2NhdGlvbiwgbmFtZTogc3RyaW5nfX0gZGVjbGFyYXRpb24gLSBTZW1hbnRpYyBkZWNsYXJhdGlvbi5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU2VtYW50aWNEZWNsYXJhdGlvbktpbmR9IHN5bWJvbEtpbmQgLSBEZWNsYXJhdGlvbiBraW5kLlxuICogQHJldHVybnMge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljRXhwb3J0fSBTZW1hbnRpYyBleHBvcnQuXG4gKi9cbmZ1bmN0aW9uIGFwcGxpY2F0aW9uRXhwb3J0KGRlY2xhcmF0aW9uLCBzeW1ib2xLaW5kKSB7XG4gIHJldHVybiB7ZGVjbGFyYXRpb25JZDogLyoqIEB0eXBlIHtzdHJpbmd9ICovIChkZWNsYXJhdGlvbi5pZCksIGV4cG9ydGVkTmFtZTogZGVjbGFyYXRpb24ubmFtZSxcbiAgICBraW5kOiAvKiogQHR5cGUge2NvbnN0fSAqLyAoXCJFeHBvcnRcIiksIGxvY2F0aW9uOiBkZWNsYXJhdGlvbi5sb2NhdGlvbiwgc3ltYm9sS2luZH1cbn1cblxuLyoqXG4gKiBRdWFsaWZpZXMgc2luZ2xlLW1vZHVsZSBkZWNsYXJhdGlvbiBpZGVudGl0aWVzIGJlZm9yZSBwcm9ncmFtIHByZWZsaWdodC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU2VtYW50aWNNb2R1bGV9IG1vZHVsZSAtIENsb25lZCBzZW1hbnRpYyBtb2R1bGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlSWQgLSBDYW5vbmljYWwgbW9kdWxlIGlkZW50aXR5LlxuICovXG5mdW5jdGlvbiByZWtleU1vZHVsZURlY2xhcmF0aW9ucyhtb2R1bGUsIG1vZHVsZUlkKSB7XG4gIGNvbnN0IGRlY2xhcmF0aW9ucyA9IFsuLi5tb2R1bGUucmVjb3JkcyA/PyBbXSwgLi4ubW9kdWxlLmNsYXNzZXMgPz8gW10sIC4uLm1vZHVsZS5lcnJvcnMgPz8gW10sIC4uLm1vZHVsZS5mdW5jdGlvbnNdXG4gIGNvbnN0IHJlcGxhY2VtZW50cyA9IG5ldyBNYXAoZGVjbGFyYXRpb25zLmZpbHRlcihkZWNsYXJhdGlvbiA9PiB0eXBlb2YgZGVjbGFyYXRpb24uaWQgPT0gXCJzdHJpbmdcIilcbiAgICAubWFwKGRlY2xhcmF0aW9uID0+IFtkZWNsYXJhdGlvbi5pZCwgYCR7bW9kdWxlSWR9IyR7ZGVjbGFyYXRpb24uaWR9YF0pKVxuXG4gIGZvciAoY29uc3QgZGVjbGFyYXRpb24gb2YgZGVjbGFyYXRpb25zKSBpZiAodHlwZW9mIGRlY2xhcmF0aW9uLmlkID09IFwic3RyaW5nXCIpIGRlY2xhcmF0aW9uLmlkID0gcmVwbGFjZW1lbnRzLmdldChkZWNsYXJhdGlvbi5pZClcbiAgY29uc3Qgc2VlbiA9IG5ldyBTZXQoKVxuICBjb25zdCBpZGVudGl0eUZpZWxkcyA9IG5ldyBTZXQoW1wiY2xhc3NJZFwiLCBcImRlY2xhcmF0aW9uSWRcIiwgXCJmaWVsZFwiLCBcIm1ldGhvZFwiLCBcInBhcmFtZXRlcklkXCJdKVxuICAvKipcbiAgICogUmV3cml0ZXMgZGVjbGFyYXRpb24gcmVmZXJlbmNlcyB0aHJvdWdob3V0IG9uZSBzZW1hbnRpYyB2YWx1ZSBncmFwaC5cbiAgICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIENhbmRpZGF0ZSBuZXN0ZWQgc2VtYW50aWMgdmFsdWUuXG4gICAqL1xuICBjb25zdCB2aXNpdCA9IHZhbHVlID0+IHtcbiAgICBpZiAoIXZhbHVlIHx8IHR5cGVvZiB2YWx1ZSAhPSBcIm9iamVjdFwiIHx8IHNlZW4uaGFzKHZhbHVlKSkgcmV0dXJuXG4gICAgc2Vlbi5hZGQodmFsdWUpXG4gICAgZm9yIChjb25zdCBba2V5LCBuZXN0ZWRdIG9mIE9iamVjdC5lbnRyaWVzKHZhbHVlKSkge1xuICAgICAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSAmJiBpZGVudGl0eUZpZWxkcy5oYXMoa2V5KSAmJiB0eXBlb2YgbmVzdGVkID09IFwic3RyaW5nXCIgJiYgcmVwbGFjZW1lbnRzLmhhcyhuZXN0ZWQpKSB7XG4gICAgICAgIFJlZmxlY3Quc2V0KHZhbHVlLCBrZXksIHJlcGxhY2VtZW50cy5nZXQobmVzdGVkKSlcbiAgICAgIH0gZWxzZSB2aXNpdChuZXN0ZWQpXG4gICAgfVxuICB9XG5cbiAgdmlzaXQobW9kdWxlKVxufVxuXG4vKipcbiAqIEVzY2FwZXMgYSBjb25maWd1cmF0aW9uIHZhbHVlIGZvciBYTUwgdGV4dCBvciBhdHRyaWJ1dGVzLlxuICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlIC0gUmF3IGNvbmZpZ3VyYXRpb24gdmFsdWUuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBYTUwtc2FmZSB2YWx1ZS5cbiAqL1xuZnVuY3Rpb24geG1sRXNjYXBlKHZhbHVlKSB7XG4gIHJldHVybiB2YWx1ZS5yZXBsYWNlQWxsKFwiJlwiLCBcIiZhbXA7XCIpLnJlcGxhY2VBbGwoXCI8XCIsIFwiJmx0O1wiKS5yZXBsYWNlQWxsKFwiPlwiLCBcIiZndDtcIilcbiAgICAucmVwbGFjZUFsbCgnXCInLCBcIiZxdW90O1wiKS5yZXBsYWNlQWxsKFwiJ1wiLCBcIiZhcG9zO1wiKVxufVxuXG4vKipcbiAqIEVzY2FwZXMgYSBjb25maWd1cmF0aW9uIHZhbHVlIGZvciBhIEtvdGxpbiBzdHJpbmcgbGl0ZXJhbCBib2R5LlxuICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlIC0gUmF3IGNvbmZpZ3VyYXRpb24gdmFsdWUuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBLb3RsaW4tc2FmZSB2YWx1ZS5cbiAqL1xuZnVuY3Rpb24ga290bGluRXNjYXBlKHZhbHVlKSB7XG4gIHJldHVybiB2YWx1ZS5yZXBsYWNlQWxsKFwiXFxcXFwiLCBcIlxcXFxcXFxcXCIpLnJlcGxhY2VBbGwoJ1wiJywgJ1xcXFxcIicpLnJlcGxhY2VBbGwoXCIkXCIsIFwiXFxcXCRcIilcbn1cblxuLyoqXG4gKiBVcHBlcmNhc2VzIHRoZSBpbml0aWFsIEFTQ0lJIGNoYXJhY3RlciBvZiBhIGtub3duIG5vbi1lbXB0eSB3b3JkLlxuICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlIC0gTm9uLWVtcHR5IHdvcmQuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBDYXBpdGFsaXplZCB3b3JkLlxuICovXG5mdW5jdGlvbiBjYXBpdGFsaXplKHZhbHVlKSB7XG4gIHJldHVybiBgJHt2YWx1ZVswXS50b1VwcGVyQ2FzZSgpfSR7dmFsdWUuc2xpY2UoMSl9YFxufVxuXG4vKipcbiAqIFRlc3RzIHdoZXRoZXIgYSB2YWx1ZSBpcyBhIHBsYWluIGRhdGEgb2JqZWN0LlxuICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIENhbmRpZGF0ZSB2YWx1ZS5cbiAqIEByZXR1cm5zIHt2YWx1ZSBpcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPn0gV2hldGhlciB0aGUgdmFsdWUgaXMgYSBwbGFpbiBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIGlzUGxhaW5PYmplY3QodmFsdWUpIHtcbiAgcmV0dXJuIEJvb2xlYW4odmFsdWUpICYmIHR5cGVvZiB2YWx1ZSA9PSBcIm9iamVjdFwiICYmICFBcnJheS5pc0FycmF5KHZhbHVlKSAmJiBPYmplY3QuZ2V0UHJvdG90eXBlT2YodmFsdWUpID09IE9iamVjdC5wcm90b3R5cGVcbn1cblxuLyoqXG4gKiBUaHJvd3MgYSBzdGFibGUgaW52YWxpZC1yZXF1ZXN0IGRpYWdub3N0aWMuXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIERpYWdub3N0aWMgbWVzc2FnZS5cbiAqIEByZXR1cm5zIHtuZXZlcn0gTmV2ZXIgcmV0dXJucy5cbiAqL1xuZnVuY3Rpb24gaW52YWxpZElucHV0KG1lc3NhZ2UpIHtcbiAgdGhyb3cgbmV3IFNlbWFudGlmb2xkRGlhZ25vc3RpYyh7Y29kZTogXCJJTlZBTElEX0FQUExJQ0FUSU9OX0lOUFVUXCIsIGxhbmd1YWdlOiBcImFuZHJvaWRcIiwgbWVzc2FnZX0pXG59XG5cbi8qKlxuICogVGhyb3dzIGEgc3RhYmxlIGludmFsaWQtY29uZmlndXJhdGlvbiBkaWFnbm9zdGljLlxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBEaWFnbm9zdGljIG1lc3NhZ2UuXG4gKiBAcmV0dXJucyB7bmV2ZXJ9IE5ldmVyIHJldHVybnMuXG4gKi9cbmZ1bmN0aW9uIGludmFsaWRDb25maWd1cmF0aW9uKG1lc3NhZ2UpIHtcbiAgdGhyb3cgbmV3IFNlbWFudGlmb2xkRGlhZ25vc3RpYyh7Y29kZTogXCJJTlZBTElEX0FQUExJQ0FUSU9OX0NPTkZJR1VSQVRJT05cIiwgbGFuZ3VhZ2U6IFwiYW5kcm9pZFwiLCBtZXNzYWdlfSlcbn1cblxuLyoqXG4gKiBUaHJvd3MgYSBzdGFibGUgaW52YWxpZC1yZXNvdXJjZSBkaWFnbm9zdGljLlxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBEaWFnbm9zdGljIG1lc3NhZ2UuXG4gKiBAcmV0dXJucyB7bmV2ZXJ9IE5ldmVyIHJldHVybnMuXG4gKi9cbmZ1bmN0aW9uIGludmFsaWRSZXNvdXJjZShtZXNzYWdlKSB7XG4gIHRocm93IG5ldyBTZW1hbnRpZm9sZERpYWdub3N0aWMoe2NvZGU6IFwiSU5WQUxJRF9BUFBMSUNBVElPTl9SRVNPVVJDRVwiLCBsYW5ndWFnZTogXCJhbmRyb2lkXCIsIG1lc3NhZ2V9KVxufVxuXG4vKipcbiAqIFRocm93cyBhIHN0YWJsZSBpbnZhbGlkLXBhdGggZGlhZ25vc3RpYy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gRGlhZ25vc3RpYyBtZXNzYWdlLlxuICogQHJldHVybnMge25ldmVyfSBOZXZlciByZXR1cm5zLlxuICovXG5mdW5jdGlvbiBpbnZhbGlkUGF0aChtZXNzYWdlKSB7XG4gIHRocm93IG5ldyBTZW1hbnRpZm9sZERpYWdub3N0aWMoe2NvZGU6IFwiSU5WQUxJRF9BUFBMSUNBVElPTl9QQVRIXCIsIGxhbmd1YWdlOiBcImFuZHJvaWRcIiwgbWVzc2FnZX0pXG59XG4iXX0=
|