semantifold 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +5 -2
  2. package/build/index.d.ts +12 -8
  3. package/build/index.d.ts.map +1 -1
  4. package/build/index.js +10 -7
  5. package/build/src/backends/android.d.ts +49 -0
  6. package/build/src/backends/android.d.ts.map +1 -0
  7. package/build/src/backends/android.js +1274 -0
  8. package/build/src/backends/identifiers.d.ts.map +1 -1
  9. package/build/src/backends/identifiers.js +7 -1
  10. package/build/src/backends/kotlin.d.ts +10 -0
  11. package/build/src/backends/kotlin.d.ts.map +1 -1
  12. package/build/src/backends/kotlin.js +11 -9
  13. package/build/src/backends/program.d.ts +6 -4
  14. package/build/src/backends/program.d.ts.map +1 -1
  15. package/build/src/backends/program.js +5 -4
  16. package/build/src/backends/shared.d.ts.map +1 -1
  17. package/build/src/backends/shared.js +17 -1
  18. package/build/src/backends/writer.d.ts +21 -1
  19. package/build/src/backends/writer.d.ts.map +1 -1
  20. package/build/src/backends/writer.js +25 -2
  21. package/build/src/language-registry.d.ts.map +1 -1
  22. package/build/src/language-registry.js +11 -1
  23. package/build/src/semantic/types.d.ts +182 -2
  24. package/build/src/semantic/types.d.ts.map +1 -1
  25. package/build/src/semantic/types.js +44 -2
  26. package/docs/android.md +79 -0
  27. package/docs/architecture.md +2 -0
  28. package/docs/ios.md +1 -1
  29. package/docs/language-support.md +8 -1
  30. package/docs/source-maps.md +2 -0
  31. package/docs/specification.md +5 -0
  32. package/docs/testing.md +15 -0
  33. package/index.js +9 -6
  34. package/package.json +1 -1
  35. package/src/backends/android.js +1370 -0
  36. package/src/backends/identifiers.js +6 -0
  37. package/src/backends/kotlin.js +11 -8
  38. package/src/backends/program.js +4 -3
  39. package/src/backends/shared.js +19 -0
  40. package/src/backends/writer.js +27 -2
  41. package/src/language-registry.js +10 -0
  42. package/src/semantic/types.js +46 -1
@@ -0,0 +1,1274 @@
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"
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 compile library is missing")
398
+ }
399
+ val semantifoldAcceptanceRoot = providers.environmentVariable("SEMANTIFOLD_ANDROID_ACCEPTANCE_ROOT").orNull
400
+ ?: throw GradleException("SEMANTIFOLD_ANDROID_INFRASTRUCTURE: SEMANTIFOLD_ANDROID_ACCEPTANCE_ROOT is required")
401
+ val semantifoldDebugKeystore = file("$semantifoldAcceptanceRoot/debug.keystore")
402
+ if (!semantifoldDebugKeystore.isFile) {
403
+ throw GradleException("SEMANTIFOLD_ANDROID_INFRASTRUCTURE: ephemeral debug keystore is missing")
404
+ }
405
+
406
+ android {
407
+ namespace = "`,
408
+ field("namespace", configuration.namespace), `"\n compileSdk = `, field("compileSdk", String(configuration.compileSdk)),
409
+ `\n buildToolsVersion = "`, field("buildToolsVersion", configuration.buildToolsVersion), `"\n\n defaultConfig {\n applicationId = "`,
410
+ field("applicationId", configuration.applicationId), `"\n minSdk = `, field("minimumSdk", String(configuration.minimumSdk)),
411
+ `\n targetSdk = `, field("targetSdk", String(configuration.targetSdk)), `\n versionCode = `,
412
+ field("versionCode", String(configuration.versionCode)), `\n versionName = "`, field("versionName", kotlinEscape(configuration.versionName)),
413
+ `"\n testApplicationId = "`, field("applicationId", configuration.applicationId),
414
+ `.test"\n testInstrumentationRunner = "`, field("packageName", configuration.packageName),
415
+ `.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`
416
+ ]);
417
+ }
418
+ /**
419
+ * Renders the allowlisted Android application manifest.
420
+ * @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
421
+ * @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
422
+ * @returns {string} Android application manifest.
423
+ */
424
+ function renderAndroidManifest(configuration, spans) {
425
+ const orientation = configuration.orientation == "unspecified" ? "" : ` android:screenOrientation="${configuration.orientation}"`;
426
+ return configured(`${projectRoot}/app/src/main/AndroidManifest.xml`, spans, [
427
+ `<?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="`,
428
+ field("packageName", configuration.packageName), `.`, field("activityClassName", configuration.activityClassName),
429
+ `"\n android:exported="true"`,
430
+ 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`
431
+ ]);
432
+ }
433
+ /**
434
+ * Renders explicit API 23-30 exclusions for every full-backup storage domain.
435
+ * @returns {string} Android full-backup rules XML.
436
+ */
437
+ function renderBackupRules() {
438
+ return `<?xml version="1.0" encoding="utf-8"?>
439
+ <full-backup-content>
440
+ <exclude domain="root" path="." />
441
+ <exclude domain="file" path="." />
442
+ <exclude domain="database" path="." />
443
+ <exclude domain="sharedpref" path="." />
444
+ <exclude domain="external" path="." />
445
+ <exclude domain="device_root" path="." />
446
+ <exclude domain="device_file" path="." />
447
+ <exclude domain="device_database" path="." />
448
+ <exclude domain="device_sharedpref" path="." />
449
+ </full-backup-content>
450
+ `;
451
+ }
452
+ /**
453
+ * Renders explicit Android 12+ exclusions for every cloud-backup and device-transfer storage domain.
454
+ * @returns {string} Android data extraction rules XML.
455
+ */
456
+ function renderDataExtractionRules() {
457
+ return `<?xml version="1.0" encoding="utf-8"?>
458
+ <data-extraction-rules>
459
+ <cloud-backup>
460
+ <exclude domain="root" path="." />
461
+ <exclude domain="file" path="." />
462
+ <exclude domain="database" path="." />
463
+ <exclude domain="sharedpref" path="." />
464
+ <exclude domain="external" path="." />
465
+ <exclude domain="device_root" path="." />
466
+ <exclude domain="device_file" path="." />
467
+ <exclude domain="device_database" path="." />
468
+ <exclude domain="device_sharedpref" path="." />
469
+ </cloud-backup>
470
+ <device-transfer>
471
+ <exclude domain="root" path="." />
472
+ <exclude domain="file" path="." />
473
+ <exclude domain="database" path="." />
474
+ <exclude domain="sharedpref" path="." />
475
+ <exclude domain="external" path="." />
476
+ <exclude domain="device_root" path="." />
477
+ <exclude domain="device_file" path="." />
478
+ <exclude domain="device_database" path="." />
479
+ <exclude domain="device_sharedpref" path="." />
480
+ </device-transfer>
481
+ </data-extraction-rules>
482
+ `;
483
+ }
484
+ /**
485
+ * Renders the platform-only instrumentation manifest.
486
+ * @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
487
+ * @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
488
+ * @returns {string} Android test manifest.
489
+ */
490
+ function renderAndroidTestManifest(configuration, spans) {
491
+ return configured(`${projectRoot}/app/src/androidTest/AndroidManifest.xml`, spans, [
492
+ `<?xml version="1.0" encoding="utf-8"?>\n<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n <instrumentation\n android:name="`,
493
+ field("packageName", configuration.packageName), `.SemantifoldUiInstrumentation"\n android:targetPackage="`,
494
+ field("applicationId", xmlEscape(configuration.applicationId)), `" />\n</manifest>\n`
495
+ ]);
496
+ }
497
+ /**
498
+ * Renders the synthetic launcher activity.
499
+ * @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
500
+ * @param {string} entryModule - Selected semantic entry module identity.
501
+ * @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
502
+ * @returns {string} Kotlin launcher activity source.
503
+ */
504
+ function renderActivity(configuration, entryModule, spans) {
505
+ const resourceImport = configuration.namespace == configuration.packageName
506
+ ? []
507
+ : ["import ", field("namespace", configuration.namespace), ".R\n"];
508
+ return configured(`${projectRoot}/app/src/main/kotlin/${configuration.packageName.replaceAll(".", "/")}/${configuration.activityClassName}.kt`, spans, [
509
+ "package ", field("packageName", configuration.packageName), `
510
+
511
+ import android.app.Activity
512
+ import android.annotation.SuppressLint
513
+ import android.os.Bundle
514
+ import android.widget.TextView
515
+ `, ...resourceImport, `import `, field("packageName", configuration.packageName),
516
+ `.semantic.SemantifoldModule${moduleName(entryModule)}
517
+
518
+ class `, field("activityClassName", configuration.activityClassName), ` : Activity() {
519
+ @SuppressLint("SetTextI18n")
520
+ override fun onCreate(savedInstanceState: Bundle?) {
521
+ super.onCreate(savedInstanceState)
522
+ setContentView(R.layout.activity_main)
523
+ val lines = SemantifoldModule${moduleName(entryModule)}.semantifoldEntry()
524
+ val output = java.lang.StringBuilder()
525
+ var index = 0
526
+ while (index < lines.size) {
527
+ if (index > 0) output.append('\\n')
528
+ output.append(lines[index])
529
+ index += 1
530
+ }
531
+ findViewById<TextView>(R.id.semantifold_output).text = output.toString()
532
+ }
533
+ }
534
+ `
535
+ ]);
536
+ }
537
+ /**
538
+ * Renders the single accessibility-important native text view.
539
+ * @returns {string} Android layout XML.
540
+ */
541
+ function renderLayout() {
542
+ return `<?xml version="1.0" encoding="utf-8"?>
543
+ <TextView xmlns:android="http://schemas.android.com/apk/res/android"
544
+ android:id="@+id/semantifold_output"
545
+ android:layout_width="match_parent"
546
+ android:layout_height="match_parent"
547
+ android:gravity="center"
548
+ android:importantForAccessibility="yes"
549
+ android:textIsSelectable="true" />
550
+ `;
551
+ }
552
+ /**
553
+ * Renders configuration-derived string resources.
554
+ * @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
555
+ * @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
556
+ * @returns {string} Android string resource XML.
557
+ */
558
+ function renderStrings(configuration, spans) {
559
+ return configured(`${projectRoot}/app/src/main/res/values/strings.xml`, spans, [
560
+ `<?xml version="1.0" encoding="utf-8"?>\n<resources>\n <string name="app_name">`,
561
+ field("displayName", xmlEscape(configuration.displayName)), `</string>\n</resources>\n`
562
+ ]);
563
+ }
564
+ /**
565
+ * Renders the fixed platform-native baseline theme.
566
+ * @returns {string} Android theme resource XML.
567
+ */
568
+ function renderTheme() {
569
+ return `<?xml version="1.0" encoding="utf-8"?>
570
+ <resources>
571
+ <style name="Theme.Semantifold" parent="android:style/Theme.Material.Light.NoActionBar">
572
+ <item name="android:fontFamily">sans</item>
573
+ <item name="android:windowActionModeOverlay">true</item>
574
+ </style>
575
+ </resources>
576
+ `;
577
+ }
578
+ /**
579
+ * Renders the sole JUnit test-scope semantic assertion.
580
+ * @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
581
+ * @param {string} entryModule - Selected semantic entry module identity.
582
+ * @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
583
+ * @returns {string} Kotlin unit test source.
584
+ */
585
+ function renderUnitTest(configuration, entryModule, spans) {
586
+ return configured(`${projectRoot}/app/src/test/kotlin/${configuration.packageName.replaceAll(".", "/")}/SemantifoldEntryTest.kt`, spans, [
587
+ "package ", field("packageName", configuration.packageName), `
588
+
589
+ import `, field("packageName", configuration.packageName), `.semantic.SemantifoldModule${moduleName(entryModule)}
590
+ import org.junit.Test
591
+
592
+ class SemantifoldEntryTest {
593
+ @Test
594
+ fun entryIsDeterministicAcrossFreshRuns() {
595
+ val firstOutput = SemantifoldModule${moduleName(entryModule)}.semantifoldEntry()
596
+ val secondOutput = SemantifoldModule${moduleName(entryModule)}.semantifoldEntry()
597
+ if (!firstOutput.equals(secondOutput)) {
598
+ throw AssertionError("Semantic entry output differs across fresh runs.")
599
+ }
600
+ }
601
+ }
602
+ `
603
+ ]);
604
+ }
605
+ /**
606
+ * Renders the framework-only instrumentation runner.
607
+ * @param {import("../semantic/types.js").AndroidApplicationConfiguration} configuration - Normalized configuration.
608
+ * @param {ConfigurationSpan[]} spans - Collected configuration provenance spans.
609
+ * @returns {string} Kotlin instrumentation source.
610
+ */
611
+ function renderInstrumentation(configuration, spans) {
612
+ const resourceImport = configuration.namespace == configuration.packageName
613
+ ? []
614
+ : ["import ", field("namespace", configuration.namespace), ".R\n"];
615
+ return configured(`${projectRoot}/app/src/androidTest/kotlin/${configuration.packageName.replaceAll(".", "/")}/SemantifoldUiInstrumentation.kt`, spans, [
616
+ "package ", field("packageName", configuration.packageName), `
617
+
618
+ import android.app.Activity
619
+ import android.app.Instrumentation
620
+ import android.content.Intent
621
+ import android.os.Bundle
622
+ import android.util.Base64
623
+ import android.view.View
624
+ import android.widget.TextView
625
+ import java.nio.charset.StandardCharsets
626
+ `, ...resourceImport, `
627
+ class SemantifoldUiInstrumentation : Instrumentation() {
628
+ private var inputArguments: Bundle? = null
629
+
630
+ override fun onCreate(arguments: Bundle?) {
631
+ inputArguments = arguments
632
+ start()
633
+ }
634
+
635
+ override fun onStart() {
636
+ try {
637
+ val providedArguments = inputArguments
638
+ ?: throw IllegalStateException("missing instrumentation arguments")
639
+ val encoded = providedArguments.getString("expected_output_base64")
640
+ ?: throw IllegalStateException("missing expected_output_base64 instrumentation argument")
641
+ val expected = String(Base64.decode(encoded, Base64.NO_WRAP), StandardCharsets.UTF_8)
642
+ val launch = targetContext.packageManager.getLaunchIntentForPackage(targetContext.packageName)
643
+ ?: throw IllegalStateException("generated application has no launcher intent")
644
+ launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
645
+ val activity = startActivitySync(launch) as `, field("activityClassName", configuration.activityClassName), `
646
+ assertOutput(activity, expected)
647
+ val monitor = addMonitor(`, field("activityClassName", configuration.activityClassName), `::class.java.name, null, false)
648
+ runOnMainSync { activity.recreate() }
649
+ waitForIdleSync()
650
+ val recreated = waitForMonitorWithTimeout(monitor, 10_000)
651
+ ?: throw IllegalStateException("activity was not recreated")
652
+ assertOutput(recreated, expected)
653
+ finish(Activity.RESULT_OK, Bundle())
654
+ } catch (error: Throwable) {
655
+ val result = Bundle()
656
+ result.putString("semantifold_failure", android.util.Log.getStackTraceString(error))
657
+ finish(Activity.RESULT_CANCELED, result)
658
+ }
659
+ }
660
+
661
+ private fun assertOutput(activity: Activity, expected: String) {
662
+ waitForIdleSync()
663
+ val actual = activity.findViewById<TextView>(R.id.semantifold_output)
664
+ ?: throw IllegalStateException("missing semantifold_output view")
665
+ if (actual.visibility != View.VISIBLE) throw IllegalStateException("output view is not visible")
666
+ if (actual.javaClass != TextView::class.java) throw IllegalStateException("output view is not a native TextView")
667
+ if (!actual.text.toString().equals(expected)) throw IllegalStateException("output text mismatch")
668
+ if (actual.contentDescription != null) throw IllegalStateException("output content description must stay absent")
669
+ if (actual.importantForAccessibility != View.IMPORTANT_FOR_ACCESSIBILITY_YES) {
670
+ throw IllegalStateException("output view is not accessibility-important")
671
+ }
672
+ }
673
+ }
674
+ `
675
+ ]);
676
+ }
677
+ /**
678
+ * Renders the ownership, toolchain, and provenance manifest.
679
+ * @param {ReturnType<typeof preflightAndroidApplication>} prepared - Prepared application.
680
+ * @param {import("../semantic/types.js").GeneratedSetArtifact[]} artifacts - Owned project artifacts.
681
+ * @param {string} manifestPath - Ownership manifest path.
682
+ * @param {ConfigurationSpan[]} spans - Configuration provenance spans.
683
+ * @returns {string} Canonical project manifest JSON.
684
+ */
685
+ function renderProjectManifest(prepared, artifacts, manifestPath, spans) {
686
+ const inputPaths = new Set([...prepared.resources, ...prepared.assets].map(({ fullPath }) => fullPath));
687
+ const semanticArtifacts = artifacts.filter(artifact => artifact.provenance.kind == "text");
688
+ const ownedPaths = [...artifacts.map(({ path }) => path), manifestPath];
689
+ return stringifyCanonicalJson({
690
+ configuration: prepared.configuration,
691
+ generator: { name: "semantifold", version: generatorVersion },
692
+ ownership: {
693
+ excludedPathPatterns,
694
+ ownedPaths,
695
+ ownedRoot: projectRoot,
696
+ sha256: artifacts.map(artifact => ({ path: artifact.path, sha256: hashContent(artifact.content) }))
697
+ },
698
+ provenance: {
699
+ configuration: Object.keys(prepared.configuration).sort().map(fieldName => ({
700
+ field: fieldName,
701
+ manifestPointer: `/configuration/${fieldName}`,
702
+ outputs: configurationOutputs(spans, fieldName)
703
+ })),
704
+ inputs: [...prepared.resources, ...prepared.assets].map(item => ({
705
+ contentKind: item.contentKind,
706
+ mediaType: item.mediaType,
707
+ path: item.fullPath,
708
+ sha256: item.sha256
709
+ })),
710
+ semanticSources: prepared.sources.map(source => ({
711
+ artifacts: semanticArtifacts.filter(artifact => artifact.provenance.kind == "text" &&
712
+ artifact.provenance.mapping.spans.some(({ origin }) => originReferencesFilename(origin, source.filename)))
713
+ .map(({ path }) => path),
714
+ filename: source.filename,
715
+ ...(source.language === undefined ? {} : { language: source.language }),
716
+ sha256: createHash("sha256").update(source.content).digest("hex")
717
+ })),
718
+ syntheticScaffolding: [...artifacts.filter(artifact => artifact.provenance.kind == "synthetic" &&
719
+ !inputPaths.has(artifact.path)).map(({ path }) => path), manifestPath]
720
+ },
721
+ schema: "SemantifoldAndroidProject",
722
+ semanticProgram: semanticProgramManifest(prepared),
723
+ target: "android",
724
+ toolchain,
725
+ version: 1
726
+ });
727
+ }
728
+ /**
729
+ * Renders semantic module and source identities for the project manifest.
730
+ * @param {ReturnType<typeof preflightAndroidApplication>} prepared - Prepared application.
731
+ * @returns {Record<string, unknown>} Semantic program manifest.
732
+ */
733
+ function semanticProgramManifest(prepared) {
734
+ const sourceContent = new Map(prepared.sources.map(source => [source.filename, source.content]));
735
+ const order = new Map(prepared.program.modules.map((module, index) => [module.id, index]));
736
+ const modules = prepared.program.modules.map(module => {
737
+ const source = prepared.program.sources.find(candidate => candidate.filename == module.sourceFilename);
738
+ const content = sourceContent.get(module.sourceFilename);
739
+ if (!source || content === undefined)
740
+ throw new TypeError(`Preflighted Android module '${module.id}' lost source ownership.`);
741
+ return {
742
+ dependencies: [...new Set(module.imports.map(({ moduleId }) => moduleId))]
743
+ .sort((left, right) => /** @type {number} */ (order.get(left)) - /** @type {number} */ (order.get(right))),
744
+ generatedArtifacts: [prepared.modulePaths.get(module.id)],
745
+ id: module.id,
746
+ namespace: `SemantifoldModule${moduleName(module.id)}`,
747
+ source: { filename: source.filename, id: source.id, sha256: createHash("sha256").update(content).digest("hex") }
748
+ };
749
+ });
750
+ const entryId = prepared.program.entryModule;
751
+ return {
752
+ entry: {
753
+ activityArtifact: `${projectRoot}/app/src/main/kotlin/${prepared.packagePath}/${prepared.configuration.activityClassName}.kt`,
754
+ generatedArtifact: prepared.modulePaths.get(entryId),
755
+ generatedFunctionIdentity: `SemantifoldModule${moduleName(entryId)}.semantifoldEntry`,
756
+ moduleId: entryId
757
+ },
758
+ modules,
759
+ schema: "SemantifoldAndroidSemanticProgram",
760
+ sources: prepared.program.sources.map(source => ({
761
+ filename: source.filename,
762
+ id: source.id,
763
+ language: source.language,
764
+ moduleIds: modules.filter(module => module.source.filename == source.filename).map(({ id }) => id),
765
+ ownership: source.ownership ?? "application",
766
+ sha256: createHash("sha256").update(/** @type {string} */ (sourceContent.get(source.filename))).digest("hex")
767
+ })),
768
+ version: 1
769
+ };
770
+ }
771
+ /**
772
+ * Validates and normalizes the closed Android configuration.
773
+ * @param {unknown} candidate - Candidate configuration.
774
+ * @returns {import("../semantic/types.js").AndroidApplicationConfiguration} Normalized configuration.
775
+ */
776
+ function normalizeConfiguration(candidate) {
777
+ if (candidate === undefined)
778
+ candidate = {};
779
+ if (!isPlainObject(candidate) || Object.keys(candidate).some(key => !configurationFields.has(key))) {
780
+ invalidConfiguration("Android application configuration must be a closed plain object.");
781
+ }
782
+ const configuration = /** @type {import("../semantic/types.js").AndroidApplicationConfigurationInput} */ (candidate);
783
+ const applicationId = configuration.applicationId ?? "dev.semantifold.generated";
784
+ const namespace = configuration.namespace ?? applicationId;
785
+ const packageName = configuration.packageName ?? namespace;
786
+ const activityClassName = configuration.activityClassName ?? "MainActivity";
787
+ const productName = configuration.productName ?? "Semantifold";
788
+ const displayName = configuration.displayName ?? "Semantifold";
789
+ const minimumSdk = configuration.minimumSdk ?? 23;
790
+ const targetSdk = configuration.targetSdk ?? toolchain.targetSdk;
791
+ const compileSdk = configuration.compileSdk ?? toolchain.compileSdk;
792
+ const buildToolsVersion = configuration.buildToolsVersion ?? toolchain.buildTools;
793
+ const versionCode = configuration.versionCode ?? 1;
794
+ const versionName = configuration.versionName ?? "1.0.0";
795
+ const orientation = configuration.orientation ?? "unspecified";
796
+ const theme = configuration.theme ?? "system";
797
+ for (const [label, value] of [["Application ID", applicationId], ["Namespace", namespace], ["Package name", packageName]]) {
798
+ if (typeof value != "string" || !isPackageName(value))
799
+ invalidConfiguration(`${label} must be a lowercase Java package identity.`);
800
+ }
801
+ if (typeof activityClassName != "string" || !/^[A-Z][A-Za-z0-9]*$/u.test(activityClassName) || kotlinKeywords.has(activityClassName)) {
802
+ invalidConfiguration("Activity class name must be an ASCII upper-camel Kotlin identifier.");
803
+ }
804
+ for (const [label, value] of [["Product name", productName], ["Display name", displayName]]) {
805
+ if (typeof value != "string" || value.length == 0 || value.trim() != value || [...value].length > 64 ||
806
+ !hasOnlyUnicodeScalars(value) || /[\p{Cc}\p{Zl}\p{Zp}\uFFFE\uFFFF]/u.test(value)) {
807
+ invalidConfiguration(`${label} must be a non-empty single-line Unicode scalar string of at most 64 characters.`);
808
+ }
809
+ }
810
+ if (/[\\/:<>"?*|]/u.test(productName)) {
811
+ invalidConfiguration("Product name contains a character forbidden by the Gradle project-name contract.");
812
+ }
813
+ if (minimumSdk !== 23 || targetSdk !== 35 || compileSdk !== 35 || minimumSdk > targetSdk || targetSdk > compileSdk) {
814
+ invalidConfiguration("SDK levels must use the qualified minimum 23, target 35, and compile 35 matrix.");
815
+ }
816
+ if (buildToolsVersion != toolchain.buildTools)
817
+ invalidConfiguration("Build Tools version must be exactly '35.0.0'.");
818
+ if (!Number.isSafeInteger(versionCode) || versionCode < 1 || versionCode > 2_100_000_000) {
819
+ invalidConfiguration("Version code must be a positive Android-safe integer.");
820
+ }
821
+ if (typeof versionName != "string" || !semanticVersionPattern.test(versionName)) {
822
+ invalidConfiguration("Version name must be a canonical non-empty semantic version string.");
823
+ }
824
+ if (orientation != "unspecified")
825
+ invalidConfiguration("The baseline orientation is exactly 'unspecified'.");
826
+ if (theme != "system")
827
+ invalidConfiguration("The baseline theme is exactly 'system'.");
828
+ if (configuration.permissions !== undefined &&
829
+ (!isDenseArray(configuration.permissions) || configuration.permissions.length != 0)) {
830
+ invalidConfiguration("The baseline Android permission set must be empty.");
831
+ }
832
+ return {
833
+ activityClassName,
834
+ applicationId,
835
+ buildToolsVersion,
836
+ compileSdk,
837
+ displayName,
838
+ minimumSdk,
839
+ namespace,
840
+ orientation,
841
+ packageName,
842
+ productName,
843
+ targetSdk,
844
+ theme,
845
+ versionCode,
846
+ versionName
847
+ };
848
+ }
849
+ /**
850
+ * Validates, snapshots, and orders caller-provided inputs.
851
+ * @param {unknown} candidate - Candidate resource or asset list.
852
+ * @param {"asset" | "resource"} kind - Android input kind.
853
+ * @returns {AndroidInputFile[]} Normalized inputs.
854
+ */
855
+ function normalizeInputFiles(candidate, kind) {
856
+ if (candidate === undefined)
857
+ return [];
858
+ if (!isDenseArray(candidate))
859
+ invalidResource(`Application ${kind}s must be a dense array.`);
860
+ /** @type {AndroidInputFile[]} */
861
+ const files = [];
862
+ for (let index = 0; index < candidate.length; index += 1) {
863
+ const item = candidate[index];
864
+ if (!isPlainObject(item) || Object.keys(item).length != resourceFields.size ||
865
+ Object.keys(item).some(key => !resourceFields.has(key)))
866
+ invalidResource(`${capitalize(kind)} ${index} must use the closed input schema.`);
867
+ const path = item.path;
868
+ const content = item.content;
869
+ const mediaType = item.mediaType;
870
+ const sha256 = item.sha256;
871
+ if (!isSafeArtifactPath(path) || kind == "resource" && !isAllowedResourcePath(path)) {
872
+ invalidResource(`${capitalize(kind)} ${index} has an unsafe or unsupported path.`);
873
+ }
874
+ if (typeof content != "string" && !(content instanceof Uint8Array) || typeof content == "string" &&
875
+ (content.length == 0 || !hasOnlyUnicodeScalars(content)) || content instanceof Uint8Array && content.byteLength == 0) {
876
+ invalidResource(`${capitalize(kind)} '${path}' requires non-empty exact content.`);
877
+ }
878
+ if (typeof mediaType != "string" || !mediaTypePattern.test(mediaType) || /[\r\n]/u.test(mediaType)) {
879
+ invalidResource(`${capitalize(kind)} '${path}' requires an explicit valid media type.`);
880
+ }
881
+ if (kind == "resource" && path.startsWith("drawable-") && !["image/png", "image/webp"].includes(mediaType)) {
882
+ invalidResource(`Drawable resource '${path}' must use PNG or WebP media type.`);
883
+ }
884
+ const snapshot = typeof content == "string" ? content : new Uint8Array(content);
885
+ const actualHash = createHash("sha256").update(snapshot).digest("hex");
886
+ if (typeof sha256 != "string" || !/^[0-9a-f]{64}$/u.test(sha256) || sha256 != actualHash) {
887
+ invalidResource(`${capitalize(kind)} '${path}' SHA-256 does not match its exact content.`);
888
+ }
889
+ const fullPath = `${projectRoot}/app/src/main/${kind == "resource" ? "res" : "assets"}/${path}`;
890
+ files.push({ content: snapshot, contentKind: typeof snapshot == "string" ? "text" : "binary", fullPath, mediaType, path, sha256 });
891
+ }
892
+ files.sort((left, right) => left.fullPath < right.fullPath ? -1 : left.fullPath > right.fullPath ? 1 : 0);
893
+ const conflict = findPortableArtifactPathConflict(files.map(({ fullPath }) => fullPath));
894
+ if (conflict)
895
+ invalidResource(`${capitalize(kind)} path '${conflict.path}' has a ${conflict.kind} conflict.`);
896
+ if (kind == "resource")
897
+ validateResourceIdentifiers(files);
898
+ return files;
899
+ }
900
+ /**
901
+ * Rejects two files that Android would compile to the same resource identifier in one configuration.
902
+ * @param {AndroidInputFile[]} files - Validated resource inputs.
903
+ */
904
+ function validateResourceIdentifiers(files) {
905
+ const identifiers = new Map();
906
+ for (const file of files) {
907
+ const separator = file.path.indexOf("/");
908
+ const directory = file.path.slice(0, separator);
909
+ const filename = file.path.slice(separator + 1);
910
+ const extension = filename.indexOf(".");
911
+ const name = extension == -1 ? filename : filename.slice(0, extension);
912
+ const resourceType = directory.split("-", 1)[0];
913
+ const key = `${directory}/${name}`;
914
+ const previous = identifiers.get(key);
915
+ if (previous) {
916
+ invalidResource(`Android resource identifier '${resourceType}/${name}' collides between '${previous}' and '${file.path}' in configuration '${directory}'.`);
917
+ }
918
+ identifiers.set(key, file.path);
919
+ }
920
+ }
921
+ /**
922
+ * Tests whether a caller resource uses the narrow allowlisted resource grammar.
923
+ * @param {string} value - Resource path relative to res.
924
+ * @returns {boolean} Whether the path is supported.
925
+ */
926
+ function isAllowedResourcePath(value) {
927
+ if (/^raw\/[a-z][a-z0-9_]*(?:\.[a-z0-9]+)?$/u.test(value))
928
+ return true;
929
+ return /^drawable-(?:mdpi|hdpi|xhdpi|xxhdpi|xxxhdpi)\/[a-z][a-z0-9_]*\.(?:png|webp)$/u.test(value);
930
+ }
931
+ /**
932
+ * Converts a validated input snapshot into an owned artifact.
933
+ * @param {AndroidInputFile} item - Validated caller input.
934
+ * @returns {import("../semantic/types.js").GeneratedSetArtifact} Owned input artifact.
935
+ */
936
+ function inputFileArtifact(item) {
937
+ const reason = `Exact caller-provided Android input (sha256:${item.sha256}).`;
938
+ if (typeof item.content == "string") {
939
+ return {
940
+ ...syntheticText(item.fullPath, "resource", item.content, reason),
941
+ mediaType: item.mediaType
942
+ };
943
+ }
944
+ const content = new Uint8Array(item.content);
945
+ return {
946
+ content,
947
+ contentKind: "binary",
948
+ mediaType: item.mediaType,
949
+ ownership: "generated",
950
+ path: item.fullPath,
951
+ provenance: { kind: "bytes", mapping: createByteMapping({
952
+ byteLength: content.byteLength,
953
+ path: item.fullPath,
954
+ ranges: [{ generated: { end: content.byteLength, start: 0 },
955
+ origin: { kind: "synthetic", reason, relatedOrigins: [] }, role: "resource" }]
956
+ }) },
957
+ role: "resource"
958
+ };
959
+ }
960
+ /**
961
+ * Creates a deterministic synthetic text artifact.
962
+ * @param {string} path - Artifact path.
963
+ * @param {import("../semantic/types.js").GeneratedArtifactRole} role - Artifact role.
964
+ * @param {string} content - UTF-8 artifact content.
965
+ * @param {string} reason - Synthetic provenance reason.
966
+ * @returns {import("../semantic/types.js").GeneratedSetArtifact} Text artifact.
967
+ */
968
+ function syntheticText(path, role, content, reason) {
969
+ return { content, contentKind: "text", mediaType: mediaTypeFor(path), ownership: "generated", path,
970
+ provenance: { kind: "synthetic", reason, relatedOrigins: [] }, role };
971
+ }
972
+ /**
973
+ * Creates a configuration-derived text artifact.
974
+ * @param {string} path - Artifact path.
975
+ * @param {import("../semantic/types.js").GeneratedArtifactRole} role - Artifact role.
976
+ * @param {string} content - UTF-8 artifact content.
977
+ * @param {string} reason - Synthetic provenance reason.
978
+ * @returns {import("../semantic/types.js").GeneratedSetArtifact} Text artifact.
979
+ */
980
+ function configuredText(path, role, content, reason) {
981
+ return syntheticText(path, role, content, reason);
982
+ }
983
+ /**
984
+ * Derives the media type for a generated text path.
985
+ * @param {string} path - Generated artifact path.
986
+ * @returns {string} Artifact media type.
987
+ */
988
+ function mediaTypeFor(path) {
989
+ if (path.endsWith(".json"))
990
+ return "application/json";
991
+ if (path.endsWith(".xml"))
992
+ return "application/xml";
993
+ if (path.endsWith(".kt") || path.endsWith(".kts"))
994
+ return "text/x-kotlin";
995
+ return "text/plain";
996
+ }
997
+ /**
998
+ * Marks one rendered value as configuration-derived.
999
+ * @param {string} fieldName - Configuration field name.
1000
+ * @param {string} value - Rendered field value.
1001
+ * @returns {{field: string, value: string}} Marked configuration value.
1002
+ */
1003
+ function field(fieldName, value) {
1004
+ return { field: fieldName, value };
1005
+ }
1006
+ /**
1007
+ * Joins rendered parts while recording configuration causality.
1008
+ * @param {string} path - Output artifact path.
1009
+ * @param {ConfigurationSpan[]} spans - Mutable provenance span collector.
1010
+ * @param {(string | {field: string, value: string})[]} parts - Synthetic and marked parts.
1011
+ * @returns {string} Rendered text.
1012
+ */
1013
+ function configured(path, spans, parts) {
1014
+ let content = "";
1015
+ for (const part of parts) {
1016
+ if (typeof part == "string")
1017
+ content += part;
1018
+ else {
1019
+ const start = content.length;
1020
+ content += part.value;
1021
+ spans.push({ end: content.length, field: part.field, path, start });
1022
+ }
1023
+ }
1024
+ return content;
1025
+ }
1026
+ /**
1027
+ * Groups configuration spans by artifact.
1028
+ * @param {ConfigurationSpan[]} spans - All rendered configuration spans.
1029
+ * @param {string} fieldName - Requested configuration field.
1030
+ * @returns {{path: string, ranges: {end: number, start: number}[]}[]} Output ranges.
1031
+ */
1032
+ function configurationOutputs(spans, fieldName) {
1033
+ const grouped = new Map();
1034
+ for (const span of spans) {
1035
+ if (span.field != fieldName)
1036
+ continue;
1037
+ const ranges = grouped.get(span.path) ?? [];
1038
+ ranges.push({ end: span.end, start: span.start });
1039
+ grouped.set(span.path, ranges);
1040
+ }
1041
+ return [...grouped].map(([path, ranges]) => ({ path, ranges }));
1042
+ }
1043
+ /**
1044
+ * Tests whether a mapping origin refers to one semantic source file.
1045
+ * @param {import("../semantic/types.js").SemanticOrigin} origin - Mapping origin.
1046
+ * @param {string} filename - Semantic source filename.
1047
+ * @returns {boolean} Whether the origin owns the filename.
1048
+ */
1049
+ function originReferencesFilename(origin, filename) {
1050
+ if (origin.kind == "source")
1051
+ return origin.location.filename == filename;
1052
+ if (origin.kind == "derived")
1053
+ return origin.origins.some(({ location }) => location.filename == filename);
1054
+ return origin.relatedOrigins.some(({ location }) => location.filename == filename);
1055
+ }
1056
+ /**
1057
+ * Hashes exact text or bytes for ownership records.
1058
+ * @param {string | Uint8Array} content - Exact artifact content.
1059
+ * @returns {string} Lowercase SHA-256 digest.
1060
+ */
1061
+ function hashContent(content) {
1062
+ return createHash("sha256").update(content).digest("hex");
1063
+ }
1064
+ /**
1065
+ * Serializes JSON with recursively stable object-key ordering.
1066
+ * @param {unknown} value - JSON-compatible value.
1067
+ * @returns {string} Canonical indented JSON with trailing newline.
1068
+ */
1069
+ function stringifyCanonicalJson(value) {
1070
+ return `${JSON.stringify(sortJson(value), null, 2)}\n`;
1071
+ }
1072
+ /**
1073
+ * Recursively sorts object keys without changing array order.
1074
+ * @param {unknown} value - JSON-compatible value.
1075
+ * @returns {unknown} Canonically ordered value.
1076
+ */
1077
+ function sortJson(value) {
1078
+ if (Array.isArray(value))
1079
+ return value.map(sortJson);
1080
+ if (!isPlainObject(value))
1081
+ return value;
1082
+ return Object.fromEntries(Object.keys(value).sort().map(key => [key, sortJson(value[key])]));
1083
+ }
1084
+ /**
1085
+ * Tests a lowercase Kotlin-compatible package identity.
1086
+ * @param {string} value - Candidate package name.
1087
+ * @returns {boolean} Whether the name is accepted.
1088
+ */
1089
+ function isPackageName(value) {
1090
+ const parts = value.split(".");
1091
+ return parts.length >= 2 && parts.every(part => /^[a-z][a-z0-9_]*$/u.test(part) && !kotlinKeywords.has(part));
1092
+ }
1093
+ /**
1094
+ * Rejects launcher names that shadow an unqualified symbol in generated same-package Kotlin.
1095
+ * @param {string} activityClassName - Validated launcher class name.
1096
+ * @param {string} entryModule - Selected semantic entry module.
1097
+ */
1098
+ function validateActivityClassName(activityClassName, entryModule) {
1099
+ const semanticEntrySymbol = `SemantifoldModule${moduleName(entryModule)}`;
1100
+ if (androidScaffoldSymbols.has(activityClassName) || activityClassName == semanticEntrySymbol) {
1101
+ invalidConfiguration(`Activity class name '${activityClassName}' collides with generated Kotlin symbol '${activityClassName}'.`);
1102
+ }
1103
+ }
1104
+ /**
1105
+ * Allocates one module-wide output sink that cannot shadow a source binding.
1106
+ * @param {import("../semantic/types.js").SemanticModule} module - Prepared semantic module.
1107
+ * @returns {string} Collision-safe Kotlin binding.
1108
+ */
1109
+ function outputSinkName(module) {
1110
+ const bindings = new Set(module.functions.flatMap(declaration => declaration.parameters.map(({ name }) => name)));
1111
+ for (const declaration of module.functions)
1112
+ collectBlockBindingNames(declaration.body, bindings);
1113
+ collectBlockBindingNames(module.entryPoint.body, bindings);
1114
+ let candidate = "semantifoldOutput";
1115
+ while (bindings.has(candidate))
1116
+ candidate += "_";
1117
+ return candidate;
1118
+ }
1119
+ /**
1120
+ * Collects local bindings recursively from the supported semantic block subset.
1121
+ * @param {import("../semantic/types.js").Block} block - Semantic block.
1122
+ * @param {Set<string>} bindings - Mutable binding-name set.
1123
+ */
1124
+ function collectBlockBindingNames(block, bindings) {
1125
+ for (const statement of block.statements) {
1126
+ if (statement.kind == "LocalDeclaration")
1127
+ bindings.add(statement.name);
1128
+ else if (statement.kind == "IfStatement") {
1129
+ collectBlockBindingNames(statement.consequent, bindings);
1130
+ if (statement.alternate)
1131
+ collectBlockBindingNames(statement.alternate, bindings);
1132
+ }
1133
+ }
1134
+ }
1135
+ /**
1136
+ * Maps a preflighted module identity to a stable Kotlin suffix.
1137
+ * @param {string} id - Semantic module identity.
1138
+ * @returns {string} Kotlin object-name suffix.
1139
+ */
1140
+ function moduleName(id) {
1141
+ return id.split(/[._-]+/u).map(part => `${part[0].toUpperCase()}${part.slice(1)}`).join("");
1142
+ }
1143
+ /**
1144
+ * Wraps legacy single-module input in the canonical program contract.
1145
+ * @param {import("../semantic/types.js").SemanticModule | undefined} candidate - Candidate semantic module.
1146
+ * @returns {import("../semantic/types.js").SemanticProgram} Canonical single-module program.
1147
+ */
1148
+ function normalizeSingleModule(candidate) {
1149
+ if (!isPlainObject(candidate))
1150
+ unsupportedCapability("android", "missing or invalid module", undefined);
1151
+ const module = structuredClone(candidate);
1152
+ const sources = module.provenance?.sources;
1153
+ if (!Array.isArray(sources) || sources.length != 1 || sources[0].content === null ||
1154
+ sources[0].filename != module.location?.filename || typeof sources[0].language != "string") {
1155
+ unsupportedCapability("android", "single-module source ownership", module.location);
1156
+ }
1157
+ rekeyModuleDeclarations(module, "main");
1158
+ const exports = [
1159
+ ...(module.records ?? []).map(declaration => applicationExport(declaration, "record")),
1160
+ ...(module.classes ?? []).map(declaration => applicationExport(declaration, "class")),
1161
+ ...(module.errors ?? []).map(declaration => applicationExport(declaration, "error")),
1162
+ ...module.functions.map(declaration => applicationExport(declaration, "function"))
1163
+ ];
1164
+ const programModule = { ...module, exports, id: "main", imports: [], sourceFilename: sources[0].filename };
1165
+ return { entryModule: "main", kind: "Program", modules: [programModule], sources: structuredClone(sources) };
1166
+ }
1167
+ /**
1168
+ * Creates an application-local export record for single-module compatibility.
1169
+ * @param {{id?: string, location: import("../semantic/types.js").SourceLocation, name: string}} declaration - Semantic declaration.
1170
+ * @param {import("../semantic/types.js").SemanticDeclarationKind} symbolKind - Declaration kind.
1171
+ * @returns {import("../semantic/types.js").SemanticExport} Semantic export.
1172
+ */
1173
+ function applicationExport(declaration, symbolKind) {
1174
+ return { declarationId: /** @type {string} */ (declaration.id), exportedName: declaration.name,
1175
+ kind: /** @type {const} */ ("Export"), location: declaration.location, symbolKind };
1176
+ }
1177
+ /**
1178
+ * Qualifies single-module declaration identities before program preflight.
1179
+ * @param {import("../semantic/types.js").SemanticModule} module - Cloned semantic module.
1180
+ * @param {string} moduleId - Canonical module identity.
1181
+ */
1182
+ function rekeyModuleDeclarations(module, moduleId) {
1183
+ const declarations = [...module.records ?? [], ...module.classes ?? [], ...module.errors ?? [], ...module.functions];
1184
+ const replacements = new Map(declarations.filter(declaration => typeof declaration.id == "string")
1185
+ .map(declaration => [declaration.id, `${moduleId}#${declaration.id}`]));
1186
+ for (const declaration of declarations)
1187
+ if (typeof declaration.id == "string")
1188
+ declaration.id = replacements.get(declaration.id);
1189
+ const seen = new Set();
1190
+ const identityFields = new Set(["classId", "declarationId", "field", "method", "parameterId"]);
1191
+ /**
1192
+ * Rewrites declaration references throughout one semantic value graph.
1193
+ * @param {unknown} value - Candidate nested semantic value.
1194
+ */
1195
+ const visit = value => {
1196
+ if (!value || typeof value != "object" || seen.has(value))
1197
+ return;
1198
+ seen.add(value);
1199
+ for (const [key, nested] of Object.entries(value)) {
1200
+ if (!Array.isArray(value) && identityFields.has(key) && typeof nested == "string" && replacements.has(nested)) {
1201
+ Reflect.set(value, key, replacements.get(nested));
1202
+ }
1203
+ else
1204
+ visit(nested);
1205
+ }
1206
+ };
1207
+ visit(module);
1208
+ }
1209
+ /**
1210
+ * Escapes a configuration value for XML text or attributes.
1211
+ * @param {string} value - Raw configuration value.
1212
+ * @returns {string} XML-safe value.
1213
+ */
1214
+ function xmlEscape(value) {
1215
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;")
1216
+ .replaceAll('"', "&quot;").replaceAll("'", "&apos;");
1217
+ }
1218
+ /**
1219
+ * Escapes a configuration value for a Kotlin string literal body.
1220
+ * @param {string} value - Raw configuration value.
1221
+ * @returns {string} Kotlin-safe value.
1222
+ */
1223
+ function kotlinEscape(value) {
1224
+ return value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("$", "\\$");
1225
+ }
1226
+ /**
1227
+ * Uppercases the initial ASCII character of a known non-empty word.
1228
+ * @param {string} value - Non-empty word.
1229
+ * @returns {string} Capitalized word.
1230
+ */
1231
+ function capitalize(value) {
1232
+ return `${value[0].toUpperCase()}${value.slice(1)}`;
1233
+ }
1234
+ /**
1235
+ * Tests whether a value is a plain data object.
1236
+ * @param {unknown} value - Candidate value.
1237
+ * @returns {value is Record<string, unknown>} Whether the value is a plain object.
1238
+ */
1239
+ function isPlainObject(value) {
1240
+ return Boolean(value) && typeof value == "object" && !Array.isArray(value) && Object.getPrototypeOf(value) == Object.prototype;
1241
+ }
1242
+ /**
1243
+ * Throws a stable invalid-request diagnostic.
1244
+ * @param {string} message - Diagnostic message.
1245
+ * @returns {never} Never returns.
1246
+ */
1247
+ function invalidInput(message) {
1248
+ throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_INPUT", language: "android", message });
1249
+ }
1250
+ /**
1251
+ * Throws a stable invalid-configuration diagnostic.
1252
+ * @param {string} message - Diagnostic message.
1253
+ * @returns {never} Never returns.
1254
+ */
1255
+ function invalidConfiguration(message) {
1256
+ throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_CONFIGURATION", language: "android", message });
1257
+ }
1258
+ /**
1259
+ * Throws a stable invalid-resource diagnostic.
1260
+ * @param {string} message - Diagnostic message.
1261
+ * @returns {never} Never returns.
1262
+ */
1263
+ function invalidResource(message) {
1264
+ throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_RESOURCE", language: "android", message });
1265
+ }
1266
+ /**
1267
+ * Throws a stable invalid-path diagnostic.
1268
+ * @param {string} message - Diagnostic message.
1269
+ * @returns {never} Never returns.
1270
+ */
1271
+ function invalidPath(message) {
1272
+ throw new SemantifoldDiagnostic({ code: "INVALID_APPLICATION_PATH", language: "android", message });
1273
+ }
1274
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5kcm9pZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZW5kcy9hbmRyb2lkLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sYUFBYSxDQUFBO0FBQ3RDLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxhQUFhLENBQUE7QUFDeEMsT0FBTyxFQUFDLGdDQUFnQyxFQUFFLGtCQUFrQixFQUFDLE1BQU0scUJBQXFCLENBQUE7QUFDeEYsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0sc0JBQXNCLENBQUE7QUFDdEQsT0FBTyxFQUFDLHFCQUFxQixFQUFFLHFCQUFxQixFQUFDLE1BQU0sa0JBQWtCLENBQUE7QUFDN0UsT0FBTyxFQUFDLGVBQWUsRUFBRSxhQUFhLEVBQUMsTUFBTSxlQUFlLENBQUE7QUFDNUQsT0FBTyxFQUFDLHFCQUFxQixFQUFDLE1BQU0sd0JBQXdCLENBQUE7QUFDNUQsT0FBTyxFQUFDLHdCQUF3QixFQUFDLE1BQU0sY0FBYyxDQUFBO0FBQ3JELE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSxjQUFjLENBQUE7QUFDM0MsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLHFCQUFxQixDQUFBO0FBQ2pELE9BQU8sRUFBQyxlQUFlLEVBQUMsTUFBTSxhQUFhLENBQUE7QUFDM0MsT0FBTyxFQUFDLFlBQVksRUFBQyxNQUFNLGFBQWEsQ0FBQTtBQUV4QyxNQUFNLFdBQVcsR0FBRyx1QkFBdUIsQ0FBQTtBQUMzQyxNQUFNLGdCQUFnQixHQUFHLE9BQU8sQ0FBQTtBQUNoQyw2RUFBNkU7QUFDN0UsTUFBTSxzQkFBc0IsR0FBRyxJQUFJLEdBQUcsQ0FBQztJQUNyQyxLQUFLLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsS0FB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SUFDMUIsT0FBTyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksT0FBTyxLQUFLLElBQUksUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUE7QUFDaEksQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxPQUFPO0lBQzNCLE1BQU0sSUFBSSxxQkFBcUIsQ0FBQyxFQUFDLElBQUksRUFBRSwyQkFBMkIsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBQyxDQUFDLENBQUE7QUFDcEcsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFTLG9CQUFvQixDQUFDLE9BQU87SUFDbkMsTUFBTSxJQUFJLHFCQUFxQixDQUFDLEVBQUMsSUFBSSxFQUFFLG1DQUFtQyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFDLENBQUMsQ0FBQTtBQUM1RyxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsZUFBZSxDQUFDLE9BQU87SUFDOUIsTUFBTSxJQUFJLHFCQUFxQixDQUFDLEVBQUMsSUFBSSxFQUFFLDhCQUE4QixFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFDLENBQUMsQ0FBQTtBQUN2RyxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsV0FBVyxDQUFDLE9BQU87SUFDMUIsTUFBTSxJQUFJLHFCQUFxQixDQUFDLEVBQUMsSUFBSSxFQUFFLDBCQUEwQixFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFDLENBQUMsQ0FBQTtBQUNuRyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCB7Y3JlYXRlSGFzaH0gZnJvbSBcIm5vZGU6Y3J5cHRvXCJcbmltcG9ydCB7aXNEZW5zZUFycmF5fSBmcm9tIFwiLi4vYXJyYXkuanNcIlxuaW1wb3J0IHtmaW5kUG9ydGFibGVBcnRpZmFjdFBhdGhDb25mbGljdCwgaXNTYWZlQXJ0aWZhY3RQYXRofSBmcm9tIFwiLi4vYXJ0aWZhY3QtcGF0aC5qc1wiXG5pbXBvcnQge2NyZWF0ZUJ5dGVNYXBwaW5nfSBmcm9tIFwiLi4vYmluYXJ5LW1hcHBpbmcuanNcIlxuaW1wb3J0IHtTZW1hbnRpZm9sZERpYWdub3N0aWMsIHVuc3VwcG9ydGVkQ2FwYWJpbGl0eX0gZnJvbSBcIi4uL2RpYWdub3N0aWMuanNcIlxuaW1wb3J0IHtmaW5hbGl6ZU1hcHBpbmcsIHRvU291cmNlTWFwVjN9IGZyb20gXCIuLi9tYXBwaW5nLmpzXCJcbmltcG9ydCB7aGFzT25seVVuaWNvZGVTY2FsYXJzfSBmcm9tIFwiLi4vc2VtYW50aWMvc2NhbGFycy5qc1wiXG5pbXBvcnQge3ByZWZsaWdodFNlbWFudGljUHJvZ3JhbX0gZnJvbSBcIi4vcHJvZ3JhbS5qc1wiXG5pbXBvcnQge2VtaXRTY2FsYXJUeXBlfSBmcm9tIFwiLi9zY2FsYXJzLmpzXCJcbmltcG9ydCB7a290bGluUnVudGltZX0gZnJvbSBcIi4va290bGluLXJ1bnRpbWUuanNcIlxuaW1wb3J0IHtlbWl0S290bGluQmxvY2t9IGZyb20gXCIuL2tvdGxpbi5qc1wiXG5pbXBvcnQge1NvdXJjZVdyaXRlcn0gZnJvbSBcIi4vd3JpdGVyLmpzXCJcblxuY29uc3QgcHJvamVjdFJvb3QgPSBcImdlbmVyYXRlZC9hbmRyb2lkLWFwcFwiXG5jb25zdCBnZW5lcmF0b3JWZXJzaW9uID0gXCIwLjQuMFwiXG4vKiogQHR5cGUge1JlYWRvbmx5PFNldDxpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY0xhbmd1YWdlPj59ICovXG5jb25zdCBhbmRyb2lkU291cmNlTGFuZ3VhZ2VzID0gbmV3IFNldChbXG4gIFwicGhwXCIsIFwicnVieVwiLCBcImphdmFzY3JpcHRcIiwgXCJ0eXBlc2NyaXB0XCIsIFwiamF2YVwiLCBcImtvdGxpblwiLCBcInB5dGhvblwiLCBcImNzaGFycFwiLCBcImdvXCIsIFwiY1wiLCBcImNwcFwiLCBcInJ1c3RcIiwgXCJzd2lmdFwiLCBcImRhcnRcIlxuXSlcbmNvbnN0IHJlcXVlc3RGaWVsZHMgPSBuZXcgU2V0KFtcImFzc2V0c1wiLCBcImNvbmZpZ3VyYXRpb25cIiwgXCJsYW5ndWFnZVwiLCBcIm1vZHVsZVwiLCBcInByb2dyYW1cIiwgXCJyZXNvdXJjZXNcIiwgXCJyb2xlXCJdKVxuY29uc3QgY29uZmlndXJhdGlvbkZpZWxkcyA9IG5ldyBTZXQoW1xuICBcImFjdGl2aXR5Q2xhc3NOYW1lXCIsIFwiYXBwbGljYXRpb25JZFwiLCBcImJ1aWxkVG9vbHNWZXJzaW9uXCIsIFwiY29tcGlsZVNka1wiLCBcImRpc3BsYXlOYW1lXCIsIFwibWluaW11bVNka1wiLCBcIm5hbWVzcGFjZVwiLFxuICBcIm9yaWVudGF0aW9uXCIsIFwicGFja2FnZU5hbWVcIiwgXCJwZXJtaXNzaW9uc1wiLCBcInByb2R1Y3ROYW1lXCIsIFwidGFyZ2V0U2RrXCIsIFwidGhlbWVcIiwgXCJ2ZXJzaW9uQ29kZVwiLCBcInZlcnNpb25OYW1lXCJcbl0pXG5jb25zdCByZXNvdXJjZUZpZWxkcyA9IG5ldyBTZXQoW1wiY29udGVudFwiLCBcIm1lZGlhVHlwZVwiLCBcInBhdGhcIiwgXCJzaGEyNTZcIl0pXG5jb25zdCBrb3RsaW5LZXl3b3JkcyA9IG5ldyBTZXQoW1xuICBcImFzXCIsIFwiYnJlYWtcIiwgXCJjbGFzc1wiLCBcImNvbnRpbnVlXCIsIFwiZG9cIiwgXCJlbHNlXCIsIFwiZmFsc2VcIiwgXCJmb3JcIiwgXCJmdW5cIiwgXCJpZlwiLCBcImluXCIsIFwiaW50ZXJmYWNlXCIsIFwiaXNcIiwgXCJudWxsXCIsXG4gIFwib2JqZWN0XCIsIFwicGFja2FnZVwiLCBcInJldHVyblwiLCBcInN1cGVyXCIsIFwidGhpc1wiLCBcInRocm93XCIsIFwidHJ1ZVwiLCBcInRyeVwiLCBcInR5cGVhbGlhc1wiLCBcInR5cGVvZlwiLCBcInZhbFwiLCBcInZhclwiLCBcIndoZW5cIiwgXCJ3aGlsZVwiXG5dKVxuY29uc3QgYW5kcm9pZFNjYWZmb2xkU3ltYm9scyA9IG5ldyBTZXQoW1xuICBcIkFjdGl2aXR5XCIsIFwiQmFzZTY0XCIsIFwiQnVuZGxlXCIsIFwiSWxsZWdhbFN0YXRlRXhjZXB0aW9uXCIsIFwiSW5zdHJ1bWVudGF0aW9uXCIsIFwiSW50ZW50XCIsIFwiUlwiLCBcIlNlbWFudGlmb2xkRW50cnlUZXN0XCIsXG4gIFwiU2VtYW50aWZvbGRVaUluc3RydW1lbnRhdGlvblwiLCBcIlN0YW5kYXJkQ2hhcnNldHNcIiwgXCJTdHJpbmdcIiwgXCJTdXBwcmVzc0xpbnRcIiwgXCJUZXN0XCIsIFwiVGV4dFZpZXdcIiwgXCJUaHJvd2FibGVcIiwgXCJWaWV3XCJcbl0pXG5jb25zdCBtZWRpYVR5cGVQYXR0ZXJuID0gL15bQS1aYS16MC05ISMkJl5fListXStcXC9bQS1aYS16MC05ISMkJl5fListXSsoPzo7W1xcdTAwMjAtXFx1MDA3ZV0rKT8kL3VcbmNvbnN0IHNlbWFudGljVmVyc2lvblBhdHRlcm4gPSAvXig/OjB8WzEtOV1bMC05XSopXFwuKD86MHxbMS05XVswLTldKilcXC4oPzowfFsxLTldWzAtOV0qKSg/Oi0oPzowfFsxLTldWzAtOV0qfFtBLVphLXotXVtBLVphLXowLTktXSopKD86XFwuKD86MHxbMS05XVswLTldKnxbQS1aYS16LV1bQS1aYS16MC05LV0qKSkqKT8oPzpcXCtbQS1aYS16MC05LV0rKD86XFwuW0EtWmEtejAtOS1dKykqKT8kL3VcbmNvbnN0IHRvb2xjaGFpbiA9IE9iamVjdC5mcmVlemUoe1xuICBhbmRyb2lkR3JhZGxlUGx1Z2luOiBcIjguMTEuMVwiLFxuICBhcmNoaXZlczoge1xuICAgIGJ1aWxkVG9vbHM6IHtcbiAgICAgIHJldmlzaW9uOiBcIjM1LjAuMFwiLFxuICAgICAgc2hhMjU2OiBcImJkM2E0OTY2OTEyZWI4YjMwZWQwZDAwYjBjZGE2YjY1NDNiOTQ5ZDVmZmUwMGJlYTU0YzA0YzgxZTE1NjFkODhcIixcbiAgICAgIHVybDogXCJodHRwczovL2RsLmdvb2dsZS5jb20vYW5kcm9pZC9yZXBvc2l0b3J5L2J1aWxkLXRvb2xzX3IzNV9saW51eC56aXBcIlxuICAgIH0sXG4gICAgY29tbWFuZExpbmVUb29sczoge1xuICAgICAgcmV2aXNpb246IFwiMTEwNzY3MDhcIixcbiAgICAgIHNoYTI1NjogXCIyZDJkNTA4NTdlNGViNTUzYWY1YTZkYzNhZDUwN2ExN2FkZjQzZDExNTI2NGIxYWZjMTE2Zjk1YzkyZTVlMjU4XCIsXG4gICAgICB1cmw6IFwiaHR0cHM6Ly9kbC5nb29nbGUuY29tL2FuZHJvaWQvcmVwb3NpdG9yeS9jb21tYW5kbGluZXRvb2xzLWxpbnV4LTExMDc2NzA4X2xhdGVzdC56aXBcIlxuICAgIH0sXG4gICAgZW11bGF0b3I6IHtcbiAgICAgIGJ1aWxkSWQ6IFwiMTM2MTA0MTJcIixcbiAgICAgIHJldmlzaW9uOiBcIjM1LjYuMTFcIixcbiAgICAgIHNoYTI1NjogXCIyZmUyYjU2ZmU5M2NlNzVlMWQ0NzhhNDAxNjIxMzEzODFkOTExYzM1NWVmZWFlZGI1NGRkMWUwZDA4OTdhNWNmXCIsXG4gICAgICB1cmw6IFwiaHR0cHM6Ly9lZGdlZGwubWUuZ3Z0MS5jb20vZWRnZWRsL2FuZHJvaWQvcmVwb3NpdG9yeS9lbXVsYXRvci1saW51eF94NjQtMTM2MTA0MTIuemlwXCJcbiAgICB9LFxuICAgIHBsYXRmb3JtOiB7XG4gICAgICByZXZpc2lvbjogXCIzNS1yMlwiLFxuICAgICAgc2hhMjU2OiBcIjA5ODhjYWNhZDAxYjM4YTE4YTQ3YmFjMTRhMDY5NWYyNDZiYzc2YzFiMDZjMGVlYjhlYjBkYzgyNWFiMGM4ZTBcIixcbiAgICAgIHVybDogXCJodHRwczovL2RsLmdvb2dsZS5jb20vYW5kcm9pZC9yZXBvc2l0b3J5L3BsYXRmb3JtLTM1X3IwMi56aXBcIlxuICAgIH0sXG4gICAgcGxhdGZvcm1Ub29sczoge1xuICAgICAgcmV2aXNpb246IFwiMzcuMC4xXCIsXG4gICAgICBzaGEyNTY6IFwiZDIzMGYxMzg0MmY2MGY3ODJhODY0NWY5YzgxM2Y4Zjg0NWJmMzYwODllYTcyODlmMjhjNDhmMTc5NzkzMTNmMVwiLFxuICAgICAgdXJsOiBcImh0dHBzOi8vZGwuZ29vZ2xlLmNvbS9hbmRyb2lkL3JlcG9zaXRvcnkvcGxhdGZvcm0tdG9vbHNfcjM3LjAuMS1saW51eC56aXBcIlxuICAgIH0sXG4gICAgc3lzdGVtSW1hZ2U6IHtcbiAgICAgIHJldmlzaW9uOiBcIjM1LWdvb2dsZV9hcGlzLXg4Nl82NC1yOVwiLFxuICAgICAgc2hhMjU2OiBcImM2N2I5YmEwZmY1YmMwZWI2ZDA0Njg3MWJmYTIyOGFmMTRkNGQ0N2IwMmYwY2RhZTk0ZjA0OGU1MTFiNzU2NmVcIixcbiAgICAgIHVybDogXCJodHRwczovL2RsLmdvb2dsZS5jb20vYW5kcm9pZC9yZXBvc2l0b3J5L3N5cy1pbWcvZ29vZ2xlX2FwaXMveDg2XzY0LTM1X3IwOS56aXBcIlxuICAgIH1cbiAgfSxcbiAgYnVpbGRUb29sczogXCIzNS4wLjBcIixcbiAgY29tbWFuZExpbmVUb29sczogXCIxMTA3NjcwOFwiLFxuICBjb21waWxlU2RrOiAzNSxcbiAgZW11bGF0b3I6IFwiMzUuNi4xMVwiLFxuICBncmFkbGU6IFwiOC4xM1wiLFxuICBqYXZhOiBcIjIxLjAuOFwiLFxuICBrb3RsaW46IFwiMi4yLjEwXCIsXG4gIGtvdGxpbkNvbXBpbGVyU2hhMjU2OiBcIjMwMmQxZDhlNjcxZTVjMzIwN2U2ZWQ2MmZmMTFmYjU1NTQ2MmE2MjhlMjJhMTE1ODI1NGRjYWFmN2U3Mzk0YmNcIixcbiAgc3lzdGVtSW1hZ2U6IFwic3lzdGVtLWltYWdlczthbmRyb2lkLTM1O2dvb2dsZV9hcGlzO3g4Nl82NFwiLFxuICB0YXJnZXRTZGs6IDM1XG59KVxuY29uc3QgZXhjbHVkZWRQYXRoUGF0dGVybnMgPSBPYmplY3QuZnJlZXplKFtcIi5ncmFkbGUvKipcIiwgXCIqKi9idWlsZC8qKlwiLCBcImxvY2FsLnByb3BlcnRpZXNcIl0pXG5jb25zdCBhbmRyb2lkS290bGluUnVudGltZSA9IGBAZmlsZTpTdXBwcmVzcyhcIlBMQVRGT1JNX0NMQVNTX01BUFBFRF9UT19LT1RMSU5cIilcblxucGFja2FnZSBfX1BBQ0tBR0VfXy5zZW1hbnRpY1xuXG4ke2tvdGxpblJ1bnRpbWUucmVwbGFjZUFsbChcInByaXZhdGUgXCIsIFwiaW50ZXJuYWwgXCIpfVxuaW50ZXJuYWwgY2xhc3MgU2VtYW50aWZvbGRPdXRwdXRTaW5rIHtcbiAgcHJpdmF0ZSB2YWwgdmFsdWVzOiBqYXZhLnV0aWwuQXJyYXlMaXN0PFN0cmluZz4gPSBqYXZhLnV0aWwuQXJyYXlMaXN0PFN0cmluZz4oKVxuXG4gIGZ1biByZXNldCgpIHtcbiAgICB2YWx1ZXMuY2xlYXIoKVxuICB9XG5cbiAgZnVuIHdyaXRlKHZhbHVlOiBMb25nKSB7XG4gICAgdmFsdWVzLmFkZCh2YWx1ZS50b1N0cmluZygpKVxuICB9XG5cbiAgZnVuIHdyaXRlKHZhbHVlOiBCb29sZWFuKSB7XG4gICAgdmFsdWVzLmFkZChpZiAodmFsdWUpIFwidHJ1ZVwiIGVsc2UgXCJmYWxzZVwiKVxuICB9XG5cbiAgZnVuIHdyaXRlKHZhbHVlOiBTdHJpbmcpIHtcbiAgICB2YWx1ZXMuYWRkKHZhbHVlKVxuICB9XG5cbiAgZnVuIHNuYXBzaG90KCk6IGphdmEudXRpbC5BcnJheUxpc3Q8U3RyaW5nPiA9IGphdmEudXRpbC5BcnJheUxpc3Q8U3RyaW5nPih2YWx1ZXMpXG59XG5gXG5cbi8qKiBAdHlwZWRlZiB7e2NvbnRlbnQ6IHN0cmluZyB8IFVpbnQ4QXJyYXksIGNvbnRlbnRLaW5kOiBcImJpbmFyeVwiIHwgXCJ0ZXh0XCIsIGZ1bGxQYXRoOiBzdHJpbmcsIG1lZGlhVHlwZTogc3RyaW5nLCBwYXRoOiBzdHJpbmcsIHNoYTI1Njogc3RyaW5nfX0gQW5kcm9pZElucHV0RmlsZSAqL1xuLyoqIEB0eXBlZGVmIHt7ZW5kOiBudW1iZXIsIGZpZWxkOiBzdHJpbmcsIHBhdGg6IHN0cmluZywgc3RhcnQ6IG51bWJlcn19IENvbmZpZ3VyYXRpb25TcGFuICovXG5cbi8qKlxuICogUHJlZmxpZ2h0cyBhIGNvbXBsZXRlIEFuZHJvaWQgYXBwbGljYXRpb24gcmVxdWVzdCBiZWZvcmUgYWxsb2NhdGluZyBhIHNvdXJjZSB3cml0ZXIuXG4gKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIHVua25vd24+fSBpbnB1dCAtIENhbmRpZGF0ZSBhcHBsaWNhdGlvbiByZXF1ZXN0LlxuICogQHJldHVybnMge3thc3NldHM6IEFuZHJvaWRJbnB1dEZpbGVbXSwgY29uZmlndXJhdGlvbjogaW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuQW5kcm9pZEFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbiwgbW9kdWxlUGF0aHM6IE1hcDxzdHJpbmcsIHN0cmluZz4sIG1vZHVsZXM6IGltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljTW9kdWxlW10sIHBhY2thZ2VQYXRoOiBzdHJpbmcsIHByb2dyYW06IGltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLlNlbWFudGljUHJvZ3JhbSwgcmVzb3VyY2VzOiBBbmRyb2lkSW5wdXRGaWxlW10sIHNvdXJjZXM6IHtjb250ZW50OiBzdHJpbmcsIGZpbGVuYW1lOiBzdHJpbmcsIGxhbmd1YWdlPzogaW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU2VtYW50aWNMYW5ndWFnZX1bXX19IFByZXBhcmVkIGFwcGxpY2F0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJlZmxpZ2h0QW5kcm9pZEFwcGxpY2F0aW9uKGlucHV0KSB7XG4gIGlmICghaXNQbGFpbk9iamVjdChpbnB1dCkgfHwgT2JqZWN0LmtleXMoaW5wdXQpLnNvbWUoa2V5ID0+ICFyZXF1ZXN0RmllbGRzLmhhcyhrZXkpKSB8fFxuICAgIEJvb2xlYW4oaW5wdXQubW9kdWxlKSA9PSBCb29sZWFuKGlucHV0LnByb2dyYW0pKSB7XG4gICAgaW52YWxpZElucHV0KFwiQW5kcm9pZCBhcHBsaWNhdGlvbiBnZW5lcmF0aW9uIHJlcXVpcmVzIGEgY2xvc2VkIHJlcXVlc3Qgd2l0aCBleGFjdGx5IG9uZSBzZW1hbnRpYyBtb2R1bGUgb3IgcHJvZ3JhbS5cIilcbiAgfVxuICBpZiAoaW5wdXQubGFuZ3VhZ2UgIT09IHVuZGVmaW5lZCAmJiBpbnB1dC5sYW5ndWFnZSAhPSBcImFuZHJvaWRcIiB8fCBpbnB1dC5yb2xlICE9PSB1bmRlZmluZWQgJiYgaW5wdXQucm9sZSAhPSBcImFwcGxpY2F0aW9uXCIpIHtcbiAgICBpbnZhbGlkSW5wdXQoXCJBbmRyb2lkIGFwcGxpY2F0aW9uIGdlbmVyYXRpb24gYWNjZXB0cyBvbmx5IHRoZSBBbmRyb2lkIGFwcGxpY2F0aW9uIHJvbGUuXCIpXG4gIH1cbiAgY29uc3QgY29uZmlndXJhdGlvbiA9IG5vcm1hbGl6ZUNvbmZpZ3VyYXRpb24oaW5wdXQuY29uZmlndXJhdGlvbilcbiAgY29uc3QgcHJvZ3JhbSA9IGlucHV0LnByb2dyYW0gPz8gbm9ybWFsaXplU2luZ2xlTW9kdWxlKFxuICAgIC8qKiBAdHlwZSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuU2VtYW50aWNNb2R1bGUgfCB1bmRlZmluZWR9ICovIChpbnB1dC5tb2R1bGUpKVxuICBjb25zdCBwcmVwYXJlZCA9IHByZWZsaWdodFNlbWFudGljUHJvZ3JhbSh7XG4gICAgYmFja2VuZExhbmd1YWdlOiBcImtvdGxpblwiLFxuICAgIGRpYWdub3N0aWNMYW5ndWFnZTogXCJhbmRyb2lkXCIsXG4gICAgcHJvZ3JhbTogLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY1Byb2dyYW19ICovIChwcm9ncmFtKSxcbiAgICBzb3VyY2VMYW5ndWFnZXM6IGFuZHJvaWRTb3VyY2VMYW5ndWFnZXNcbiAgfSlcbiAgdmFsaWRhdGVBY3Rpdml0eUNsYXNzTmFtZShjb25maWd1cmF0aW9uLmFjdGl2aXR5Q2xhc3NOYW1lLCBwcmVwYXJlZC5wcm9ncmFtLmVudHJ5TW9kdWxlKVxuICBjb25zdCBwYWNrYWdlUGF0aCA9IGNvbmZpZ3VyYXRpb24ucGFja2FnZU5hbWUucmVwbGFjZUFsbChcIi5cIiwgXCIvXCIpXG4gIGNvbnN0IHNlbWFudGljUm9vdCA9IGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4va290bGluLyR7cGFja2FnZVBhdGh9L3NlbWFudGljYFxuICBjb25zdCBtb2R1bGVQYXRocyA9IG5ldyBNYXAocHJlcGFyZWQubW9kdWxlcy5tYXAobW9kdWxlID0+IFtcbiAgICAvKiogQHR5cGUge3N0cmluZ30gKi8gKFJlZmxlY3QuZ2V0KG1vZHVsZSwgXCJpZFwiKSksXG4gICAgYCR7c2VtYW50aWNSb290fS8ke21vZHVsZU5hbWUoLyoqIEB0eXBlIHtzdHJpbmd9ICovIChSZWZsZWN0LmdldChtb2R1bGUsIFwiaWRcIikpKX0ua3RgXG4gIF0pKVxuICBjb25zdCByZXNvdXJjZXMgPSBub3JtYWxpemVJbnB1dEZpbGVzKGlucHV0LnJlc291cmNlcywgXCJyZXNvdXJjZVwiKVxuICBjb25zdCBhc3NldHMgPSBub3JtYWxpemVJbnB1dEZpbGVzKGlucHV0LmFzc2V0cywgXCJhc3NldFwiKVxuICBjb25zdCBmaXhlZFBhdGhzID0gYXBwbGljYXRpb25QYXRocyhjb25maWd1cmF0aW9uLCBtb2R1bGVQYXRocylcbiAgY29uc3QgY29tcGxldGVQYXRocyA9IFtcbiAgICAuLi5maXhlZFBhdGhzLFxuICAgIC4uLnJlc291cmNlcy5tYXAoKHtmdWxsUGF0aH0pID0+IGZ1bGxQYXRoKSxcbiAgICAuLi5hc3NldHMubWFwKCh7ZnVsbFBhdGh9KSA9PiBmdWxsUGF0aClcbiAgXVxuICBjb25zdCBjb25mbGljdCA9IGZpbmRQb3J0YWJsZUFydGlmYWN0UGF0aENvbmZsaWN0KGNvbXBsZXRlUGF0aHMpXG5cbiAgaWYgKGNvbmZsaWN0KSB7XG4gICAgaW52YWxpZFBhdGgoYEFwcGxpY2F0aW9uIGFydGlmYWN0IHBhdGggJyR7Y29uZmxpY3QucGF0aH0nIGhhcyBhICR7Y29uZmxpY3Qua2luZH0gY29uZmxpY3Qke2NvbmZsaWN0Lm90aGVyID8gYCB3aXRoICcke2NvbmZsaWN0Lm90aGVyfSdgIDogXCJcIn0uYClcbiAgfVxuXG4gIHJldHVybiB7Li4ucHJlcGFyZWQsIGFzc2V0cywgY29uZmlndXJhdGlvbiwgbW9kdWxlUGF0aHMsIHBhY2thZ2VQYXRoLCByZXNvdXJjZXN9XG59XG5cbi8qKlxuICogR2VuZXJhdGVzIG9uZSBjb21wbGV0ZSBkZXRlcm1pbmlzdGljIEFuZHJvaWQvS290bGluIHByb2plY3QuXG4gKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIHVua25vd24+fSBpbnB1dCAtIEFwcGxpY2F0aW9uIGdlbmVyYXRpb24gcmVxdWVzdC5cbiAqIEByZXR1cm5zIHt7YXJ0aWZhY3RzOiBpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0ZWRTZXRBcnRpZmFjdFtdLCBtZXRhZGF0YToge2FwcGxpY2F0aW9uTWFuaWZlc3Q6IHN0cmluZywgcGxhdGZvcm1RdWFsaWZpY2F0aW9uOiBzdHJpbmd9LCB0YXJnZXQ6IFwiYW5kcm9pZFwifX0gQ2FuZGlkYXRlIGFydGlmYWN0IHNldC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlQW5kcm9pZEFwcGxpY2F0aW9uKGlucHV0KSB7XG4gIGNvbnN0IHByZXBhcmVkID0gcHJlZmxpZ2h0QW5kcm9pZEFwcGxpY2F0aW9uKGlucHV0KVxuICBjb25zdCBjb25maWd1cmF0aW9uU3BhbnMgPSAvKiogQHR5cGUge0NvbmZpZ3VyYXRpb25TcGFuW119ICovIChbXSlcbiAgY29uc3QgY29uZmlndXJhdGlvbiA9IHByZXBhcmVkLmNvbmZpZ3VyYXRpb25cbiAgY29uc3QgcGFja2FnZVBhdGggPSBwcmVwYXJlZC5wYWNrYWdlUGF0aFxuICBjb25zdCBzZW1hbnRpY0FydGlmYWN0cyA9IHJlbmRlclNlbWFudGljQXJ0aWZhY3RzKHByZXBhcmVkKVxuICBjb25zdCBhcnRpZmFjdHMgPSAvKiogQHR5cGUge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRlZFNldEFydGlmYWN0W119ICovIChbXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2FwcC9idWlsZC5ncmFkbGUua3RzYCwgXCJtYW5pZmVzdFwiLCByZW5kZXJBcHBCdWlsZChjb25maWd1cmF0aW9uLCBjb25maWd1cmF0aW9uU3BhbnMpLFxuICAgICAgXCJQaW5uZWQgZGVwZW5kZW5jeS1taW5pbWFsIEFuZHJvaWQgYXBwbGljYXRpb24gYnVpbGQuXCIpLFxuICAgIGNvbmZpZ3VyZWRUZXh0KGAke3Byb2plY3RSb290fS9hcHAvc3JjL2FuZHJvaWRUZXN0L0FuZHJvaWRNYW5pZmVzdC54bWxgLCBcIm1hbmlmZXN0XCIsXG4gICAgICByZW5kZXJBbmRyb2lkVGVzdE1hbmlmZXN0KGNvbmZpZ3VyYXRpb24sIGNvbmZpZ3VyYXRpb25TcGFucyksIFwiUGxhdGZvcm0tb25seSBBbmRyb2lkIGluc3RydW1lbnRhdGlvbiBkZWNsYXJhdGlvbi5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvYW5kcm9pZFRlc3Qva290bGluLyR7cGFja2FnZVBhdGh9L1NlbWFudGlmb2xkVWlJbnN0cnVtZW50YXRpb24ua3RgLCBcInN1cHBvcnRcIixcbiAgICAgIHJlbmRlckluc3RydW1lbnRhdGlvbihjb25maWd1cmF0aW9uLCBjb25maWd1cmF0aW9uU3BhbnMpLCBcIlBsYXRmb3JtLW9ubHkgYWNjZXNzaWJpbGl0eSBhbmQgbGlmZWN5Y2xlIGFzc2VydGlvbi5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9BbmRyb2lkTWFuaWZlc3QueG1sYCwgXCJtYW5pZmVzdFwiLFxuICAgICAgcmVuZGVyQW5kcm9pZE1hbmlmZXN0KGNvbmZpZ3VyYXRpb24sIGNvbmZpZ3VyYXRpb25TcGFucyksIFwiQ2xvc2VkIGFsbG93bGlzdGVkIEFuZHJvaWQgYXBwbGljYXRpb24gbWFuaWZlc3QuXCIpLFxuICAgIGNvbmZpZ3VyZWRUZXh0KGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4va290bGluLyR7cGFja2FnZVBhdGh9LyR7Y29uZmlndXJhdGlvbi5hY3Rpdml0eUNsYXNzTmFtZX0ua3RgLCBcImVudHJ5XCIsXG4gICAgICByZW5kZXJBY3Rpdml0eShjb25maWd1cmF0aW9uLCBwcmVwYXJlZC5wcm9ncmFtLmVudHJ5TW9kdWxlLCBjb25maWd1cmF0aW9uU3BhbnMpLFxuICAgICAgXCJTeW50aGV0aWMgQW5kcm9pZCBhY3Rpdml0eSBsaWZlY3ljbGUgYW5kIG5hdGl2ZSBvdXRwdXQgdmlldyBiaW5kaW5nLlwiKSxcbiAgICAuLi5zZW1hbnRpY0FydGlmYWN0cyxcbiAgICBzeW50aGV0aWNUZXh0KGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4vcmVzL2xheW91dC9hY3Rpdml0eV9tYWluLnhtbGAsIFwicmVzb3VyY2VcIiwgcmVuZGVyTGF5b3V0KCksXG4gICAgICBcIlN5bnRoZXRpYyBvbmUtdmlldyBBbmRyb2lkIGxheW91dCBhbmQgYWNjZXNzaWJpbGl0eSBpZGVudGl0eS5cIiksXG4gICAgY29uZmlndXJlZFRleHQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9yZXMvdmFsdWVzL3N0cmluZ3MueG1sYCwgXCJyZXNvdXJjZVwiLFxuICAgICAgcmVuZGVyU3RyaW5ncyhjb25maWd1cmF0aW9uLCBjb25maWd1cmF0aW9uU3BhbnMpLCBcIkVzY2FwZWQgYXBwbGljYXRpb24gbGFiZWxzIGRlcml2ZWQgZnJvbSBjb25maWd1cmF0aW9uLlwiKSxcbiAgICBzeW50aGV0aWNUZXh0KGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4vcmVzL3ZhbHVlcy90aGVtZXMueG1sYCwgXCJyZXNvdXJjZVwiLCByZW5kZXJUaGVtZSgpLFxuICAgICAgXCJDbG9zZWQgcGxhdGZvcm0tbmF0aXZlIGFwcGxpY2F0aW9uIHRoZW1lLlwiKSxcbiAgICBzeW50aGV0aWNUZXh0KGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4vcmVzL3htbC9iYWNrdXBfcnVsZXMueG1sYCwgXCJyZXNvdXJjZVwiLCByZW5kZXJCYWNrdXBSdWxlcygpLFxuICAgICAgXCJDbG9zZWQgQVBJIDIzLTMwIGZ1bGwtYmFja3VwIGV4Y2x1c2lvbnMuXCIpLFxuICAgIHN5bnRoZXRpY1RleHQoYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9yZXMveG1sL2RhdGFfZXh0cmFjdGlvbl9ydWxlcy54bWxgLCBcInJlc291cmNlXCIsIHJlbmRlckRhdGFFeHRyYWN0aW9uUnVsZXMoKSxcbiAgICAgIFwiQ2xvc2VkIEFuZHJvaWQgMTIrIGNsb3VkLWJhY2t1cCBhbmQgZGV2aWNlLXRyYW5zZmVyIGV4Y2x1c2lvbnMuXCIpLFxuICAgIGNvbmZpZ3VyZWRUZXh0KGAke3Byb2plY3RSb290fS9hcHAvc3JjL3Rlc3Qva290bGluLyR7cGFja2FnZVBhdGh9L1NlbWFudGlmb2xkRW50cnlUZXN0Lmt0YCwgXCJzdXBwb3J0XCIsXG4gICAgICByZW5kZXJVbml0VGVzdChjb25maWd1cmF0aW9uLCBwcmVwYXJlZC5wcm9ncmFtLmVudHJ5TW9kdWxlLCBjb25maWd1cmF0aW9uU3BhbnMpLFxuICAgICAgXCJKVW5pdCB0ZXN0LXNjb3BlLW9ubHkgc2VtYW50aWMgZGV0ZXJtaW5pc20gYXNzZXJ0aW9uLlwiKSxcbiAgICBzeW50aGV0aWNUZXh0KGAke3Byb2plY3RSb290fS9idWlsZC5ncmFkbGUua3RzYCwgXCJtYW5pZmVzdFwiLCByZW5kZXJSb290QnVpbGQoKSxcbiAgICAgIFwiUGlubmVkIEFuZHJvaWQgYW5kIEtvdGxpbiBidWlsZCBwbHVnaW5zLlwiKSxcbiAgICBzeW50aGV0aWNUZXh0KGAke3Byb2plY3RSb290fS9ncmFkbGUucHJvcGVydGllc2AsIFwic3VwcG9ydFwiLCByZW5kZXJHcmFkbGVQcm9wZXJ0aWVzKCksXG4gICAgICBcIlBpbm5lZCBoZXJtZXRpYyBHcmFkbGUgcHJvY2VzcyBwcm9wZXJ0aWVzLlwiKSxcbiAgICBjb25maWd1cmVkVGV4dChgJHtwcm9qZWN0Um9vdH0vc2V0dGluZ3MuZ3JhZGxlLmt0c2AsIFwibWFuaWZlc3RcIiwgcmVuZGVyU2V0dGluZ3MoY29uZmlndXJhdGlvbiwgY29uZmlndXJhdGlvblNwYW5zKSxcbiAgICAgIFwiQ2xvc2VkIG9mZmljaWFsIEdyYWRsZSBwbHVnaW4gYW5kIGRlcGVuZGVuY3kgcmVwb3NpdG9yaWVzLlwiKSxcbiAgICAuLi5wcmVwYXJlZC5yZXNvdXJjZXMubWFwKGlucHV0RmlsZUFydGlmYWN0KSxcbiAgICAuLi5wcmVwYXJlZC5hc3NldHMubWFwKGlucHV0RmlsZUFydGlmYWN0KVxuICBdKVxuXG4gIGFydGlmYWN0cy5zb3J0KChsZWZ0LCByaWdodCkgPT4gbGVmdC5wYXRoIDwgcmlnaHQucGF0aCA/IC0xIDogbGVmdC5wYXRoID4gcmlnaHQucGF0aCA/IDEgOiAwKVxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBgJHtwcm9qZWN0Um9vdH0vc2VtYW50aWZvbGQtcHJvamVjdC5qc29uYFxuXG4gIGFydGlmYWN0cy5wdXNoKHN5bnRoZXRpY1RleHQobWFuaWZlc3RQYXRoLCBcIm1hbmlmZXN0XCIsXG4gICAgcmVuZGVyUHJvamVjdE1hbmlmZXN0KHByZXBhcmVkLCBhcnRpZmFjdHMsIG1hbmlmZXN0UGF0aCwgY29uZmlndXJhdGlvblNwYW5zKSxcbiAgICBcIlZlcnNpb25lZCBBbmRyb2lkIHByb2plY3Qgb3duZXJzaGlwLCB0b29sY2hhaW4sIGFuZCBwcm92ZW5hbmNlIG1hbmlmZXN0LlwiKSlcblxuICByZXR1cm4ge1xuICAgIGFydGlmYWN0cyxcbiAgICBtZXRhZGF0YToge2FwcGxpY2F0aW9uTWFuaWZlc3Q6IG1hbmlmZXN0UGF0aCwgcGxhdGZvcm1RdWFsaWZpY2F0aW9uOiBcInRlbnNvcmJ1enota3ZtXCJ9LFxuICAgIHRhcmdldDogXCJhbmRyb2lkXCJcbiAgfVxufVxuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG1hcHBlZCBzZW1hbnRpYyBLb3RsaW4gYXJ0aWZhY3RzIGZvciBldmVyeSBwcm9ncmFtIG1vZHVsZS5cbiAqIEBwYXJhbSB7UmV0dXJuVHlwZTx0eXBlb2YgcHJlZmxpZ2h0QW5kcm9pZEFwcGxpY2F0aW9uPn0gcHJlcGFyZWQgLSBQcmVwYXJlZCBhcHBsaWNhdGlvbi5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0ZWRTZXRBcnRpZmFjdFtdfSBTZW1hbnRpYyBLb3RsaW4gYXJ0aWZhY3RzLlxuICovXG5mdW5jdGlvbiByZW5kZXJTZW1hbnRpY0FydGlmYWN0cyhwcmVwYXJlZCkge1xuICBjb25zdCBzZW1hbnRpY1Jvb3QgPSBgJHtwcm9qZWN0Um9vdH0vYXBwL3NyYy9tYWluL2tvdGxpbi8ke3ByZXBhcmVkLnBhY2thZ2VQYXRofS9zZW1hbnRpY2BcbiAgLyoqIEB0eXBlIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0ZWRTZXRBcnRpZmFjdFtdfSAqL1xuICBjb25zdCBhcnRpZmFjdHMgPSBbc3ludGhldGljVGV4dChgJHtzZW1hbnRpY1Jvb3R9L1NlbWFudGlmb2xkUnVudGltZS5rdGAsIFwic3VwcG9ydFwiLFxuICAgIGFuZHJvaWRLb3RsaW5SdW50aW1lLnJlcGxhY2VBbGwoXCJfX1BBQ0tBR0VfX1wiLCBwcmVwYXJlZC5jb25maWd1cmF0aW9uLnBhY2thZ2VOYW1lKSxcbiAgICBcIlNoYXJlZCBBbmRyb2lkIGFwcGxpY2F0aW9uIG91dHB1dCBjYXB0dXJlIGFuZCBjaGVja2VkIEtvdGxpbiBzY2FsYXIgc3VwcG9ydC5cIildXG4gIGNvbnN0IGRlY2xhcmF0aW9ucyA9IG5ldyBNYXAoKVxuXG4gIGZvciAoY29uc3QgbW9kdWxlIG9mIHByZXBhcmVkLm1vZHVsZXMpIHtcbiAgICBmb3IgKGNvbnN0IGRlY2xhcmF0aW9uIG9mIG1vZHVsZS5mdW5jdGlvbnMpIGRlY2xhcmF0aW9ucy5zZXQoZGVjbGFyYXRpb24uaWQsIHtcbiAgICAgIGRlY2xhcmF0aW9uLFxuICAgICAgbW9kdWxlSWQ6IC8qKiBAdHlwZSB7c3RyaW5nfSAqLyAoUmVmbGVjdC5nZXQobW9kdWxlLCBcImlkXCIpKVxuICAgIH0pXG4gIH1cbiAgZm9yIChjb25zdCBtb2R1bGUgb2YgcHJlcGFyZWQubW9kdWxlcykge1xuICAgIGNvbnN0IG1vZHVsZUlkID0gLyoqIEB0eXBlIHtzdHJpbmd9ICovIChSZWZsZWN0LmdldChtb2R1bGUsIFwiaWRcIikpXG4gICAgY29uc3QgZmlsZW5hbWUgPSAvKiogQHR5cGUge3N0cmluZ30gKi8gKHByZXBhcmVkLm1vZHVsZVBhdGhzLmdldChtb2R1bGVJZCkpXG4gICAgY29uc3Qgc2lua05hbWUgPSBvdXRwdXRTaW5rTmFtZShtb2R1bGUpXG4gICAgY29uc3Qgd3JpdGVyID0gbmV3IFNvdXJjZVdyaXRlcih7XG4gICAgICBjYWxsQXJndW1lbnRTdWZmaXg6IHNpbmtOYW1lLFxuICAgICAgY2FsbE5hbWVSZXNvbHZlcjogZXhwcmVzc2lvbiA9PiB7XG4gICAgICAgIGNvbnN0IHJlc29sdmVkID0gZGVjbGFyYXRpb25zLmdldChleHByZXNzaW9uLnJlc29sdXRpb24/LmRlY2xhcmF0aW9uSWQpXG5cbiAgICAgICAgaWYgKCFyZXNvbHZlZCkgdGhyb3cgbmV3IFR5cGVFcnJvcihgVW5rbm93biB2YWxpZGF0ZWQgQW5kcm9pZCBmdW5jdGlvbiAnJHtleHByZXNzaW9uLnJlc29sdXRpb24/LmRlY2xhcmF0aW9uSWR9Jy5gKVxuXG4gICAgICAgIHJldHVybiBgU2VtYW50aWZvbGRNb2R1bGUke21vZHVsZU5hbWUocmVzb2x2ZWQubW9kdWxlSWQpfS4ke3Jlc29sdmVkLmRlY2xhcmF0aW9uLm5hbWV9YFxuICAgICAgfSxcbiAgICAgIGZpbGVuYW1lLFxuICAgICAgbGFuZ3VhZ2U6IFwia290bGluXCIsXG4gICAgICBtZXRob2RTdHJpbmdFcXVhbGl0eTogdHJ1ZSxcbiAgICAgIG1vZHVsZSxcbiAgICAgIHByb2dyYW06IHByZXBhcmVkLnByb2dyYW0sXG4gICAgICBwcm9ncmFtUGF0aHM6IHByZXBhcmVkLm1vZHVsZVBhdGhzLFxuICAgICAgc291cmNlczogcHJlcGFyZWQuc291cmNlc1xuICAgIH0pXG5cbiAgICB3cml0ZXIuc3ludGhldGljKGBAZmlsZTpTdXBwcmVzcyhcIlBMQVRGT1JNX0NMQVNTX01BUFBFRF9UT19LT1RMSU5cIilcXG5cXG5wYWNrYWdlICR7cHJlcGFyZWQuY29uZmlndXJhdGlvbi5wYWNrYWdlTmFtZX0uc2VtYW50aWNcXG5cXG5gLFxuICAgICAgXCJBbmRyb2lkIHNlbWFudGljIHBhY2thZ2UgbmFtZXNwYWNlXCIsIFttb2R1bGVdLCBbXCJcIl0pXG4gICAgZW1pdFNlbWFudGljTW9kdWxlKHdyaXRlciwgbW9kdWxlLCBtb2R1bGVJZCwgbW9kdWxlSWQgPT0gcHJlcGFyZWQucHJvZ3JhbS5lbnRyeU1vZHVsZSwgc2lua05hbWUpXG4gICAgY29uc3QgbWFwcGluZyA9IGZpbmFsaXplTWFwcGluZyh3cml0ZXIuZmluaXNoKCkpXG5cbiAgICBhcnRpZmFjdHMucHVzaCh7XG4gICAgICBjb250ZW50OiBtYXBwaW5nLmdlbmVyYXRlZC5jb250ZW50LFxuICAgICAgY29udGVudEtpbmQ6IFwidGV4dFwiLFxuICAgICAgbWVkaWFUeXBlOiBcInRleHQveC1rb3RsaW5cIixcbiAgICAgIG93bmVyc2hpcDogXCJnZW5lcmF0ZWRcIixcbiAgICAgIHBhdGg6IGZpbGVuYW1lLFxuICAgICAgcHJvdmVuYW5jZToge2tpbmQ6IFwidGV4dFwiLCBtYXBwaW5nLCBzb3VyY2VNYXA6IHRvU291cmNlTWFwVjMobWFwcGluZyksIHNvdXJjZU1hcEZpbGVuYW1lOiBgJHtmaWxlbmFtZX0ubWFwYH0sXG4gICAgICByb2xlOiBcInNvdXJjZVwiXG4gICAgfSlcbiAgfVxuXG4gIHJldHVybiBhcnRpZmFjdHNcbn1cblxuLyoqXG4gKiBFbWl0cyBvbmUgbmFtZXNwYWNlZCBzZW1hbnRpYyBtb2R1bGUgYW5kIGl0cyBlbnRyeSBicmlkZ2Ugd2hlbiBhcHBsaWNhYmxlLlxuICogQHBhcmFtIHtTb3VyY2VXcml0ZXJ9IHdyaXRlciAtIE1hcHBlZCBLb3RsaW4gd3JpdGVyLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5TZW1hbnRpY01vZHVsZX0gbW9kdWxlIC0gUHJlcGFyZWQgbW9kdWxlLlxuICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZUlkIC0gU3RhYmxlIG1vZHVsZSBpZGVudGl0eS5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZW50cnkgLSBXaGV0aGVyIHRoaXMgbW9kdWxlIG93bnMgdGhlIGVudHJ5IGJsb2NrLlxuICogQHBhcmFtIHtzdHJpbmd9IHNpbmtOYW1lIC0gQ29sbGlzaW9uLXNhZmUgb3V0cHV0IHNpbmsgYmluZGluZy5cbiAqL1xuZnVuY3Rpb24gZW1pdFNlbWFudGljTW9kdWxlKHdyaXRlciwgbW9kdWxlLCBtb2R1bGVJZCwgZW50cnksIHNpbmtOYW1lKSB7XG4gIHdyaXRlci5zeW50aGV0aWMoYGludGVybmFsIG9iamVjdCBTZW1hbnRpZm9sZE1vZHVsZSR7bW9kdWxlTmFtZShtb2R1bGVJZCl9IHtcXG5gLFxuICAgIFwiQW5kcm9pZCBzZW1hbnRpYyBtb2R1bGUgbmFtZXNwYWNlXCIsIFttb2R1bGVdLCBbXCJcIl0pXG4gIG1vZHVsZS5mdW5jdGlvbnMuZm9yRWFjaCgoZGVjbGFyYXRpb24sIGZ1bmN0aW9uSW5kZXgpID0+IHtcbiAgICBjb25zdCBwYXRoID0gYC9mdW5jdGlvbnMvJHtmdW5jdGlvbkluZGV4fWBcblxuICAgIHdyaXRlci5zeW50aGV0aWMoXCIgIFwiLCBcIkFuZHJvaWQgbmFtZXNwYWNlZCBmdW5jdGlvbiBpbmRlbnRhdGlvblwiLCBbZGVjbGFyYXRpb25dLCBbcGF0aF0pXG4gICAgd3JpdGVyLm1hcHBlZChcImZ1blwiLCB7bWFwcGluZ0tpbmQ6IFwiYW5jaG9yXCIsIG5vZGU6IGRlY2xhcmF0aW9uLCBwYXRofSlcbiAgICB3cml0ZXIuc3ludGhldGljKFwiIFwiLCBcImRlY2xhcmF0aW9uIHNwYWNpbmdcIiwgW2RlY2xhcmF0aW9uXSwgW3BhdGhdKVxuICAgIHdyaXRlci5tYXBwZWQoZGVjbGFyYXRpb24ubmFtZSwge21hcHBpbmdLaW5kOiBcImV4YWN0XCIsIG5vZGU6IGRlY2xhcmF0aW9uLCBwYXRoLCByb2xlOiBcIm5hbWVcIn0pXG4gICAgd3JpdGVyLnN5bnRoZXRpYyhcIihcIiwgXCJmdW5jdGlvbiBwYXJhbWV0ZXIgc2NhZmZvbGRcIiwgW2RlY2xhcmF0aW9uXSwgW3BhdGhdKVxuICAgIGRlY2xhcmF0aW9uLnBhcmFtZXRlcnMuZm9yRWFjaCgocGFyYW1ldGVyLCBwYXJhbWV0ZXJJbmRleCkgPT4ge1xuICAgICAgY29uc3QgcGFyYW1ldGVyUGF0aCA9IGAke3BhdGh9L3BhcmFtZXRlcnMvJHtwYXJhbWV0ZXJJbmRleH1gXG5cbiAgICAgIGlmIChwYXJhbWV0ZXJJbmRleCkgd3JpdGVyLnN5bnRoZXRpYyhcIiwgXCIsIFwicGFyYW1ldGVyIHNlcGFyYXRvclwiLCBbcGFyYW1ldGVyXSwgW3BhcmFtZXRlclBhdGhdKVxuICAgICAgd3JpdGVyLm1hcHBlZChwYXJhbWV0ZXIubmFtZSwge21hcHBpbmdLaW5kOiBcImV4YWN0XCIsIG5vZGU6IHBhcmFtZXRlciwgcGF0aDogcGFyYW1ldGVyUGF0aCwgcm9sZTogXCJuYW1lXCJ9KVxuICAgICAgd3JpdGVyLnN5bnRoZXRpYyhcIjogXCIsIFwicGFyYW1ldGVyIGFubm90YXRpb24gc2NhZmZvbGRcIiwgW3BhcmFtZXRlcl0sIFtwYXJhbWV0ZXJQYXRoXSlcbiAgICAgIHdyaXRlci5tYXBwZWQoZW1pdFNjYWxhclR5cGUoXCJrb3RsaW5cIiwgcGFyYW1ldGVyLnR5cGUpLCB7bWFwcGluZ0tpbmQ6IFwiZXhhY3RcIiwgbm9kZTogcGFyYW1ldGVyLnR5cGUsXG4gICAgICAgIHBhdGg6IGAke3BhcmFtZXRlclBhdGh9L3R5cGVgLCByb2xlOiBcInR5cGVcIn0pXG4gICAgfSlcbiAgICBpZiAoZGVjbGFyYXRpb24ucGFyYW1ldGVycy5sZW5ndGgpIHdyaXRlci5zeW50aGV0aWMoXCIsIFwiLCBcIm91dHB1dCBzaW5rIHBhcmFtZXRlciBzZXBhcmF0b3JcIiwgW2RlY2xhcmF0aW9uXSwgW3BhdGhdKVxuICAgIHdyaXRlci5zeW50aGV0aWMoYCR7c2lua05hbWV9OiBTZW1hbnRpZm9sZE91dHB1dFNpbmspOiBgLCBcInNoYXJlZCBBbmRyb2lkIG91dHB1dCBzaW5rIHBhcmFtZXRlclwiLCBbZGVjbGFyYXRpb25dLCBbcGF0aF0pXG4gICAgd3JpdGVyLm1hcHBlZChlbWl0U2NhbGFyVHlwZShcImtvdGxpblwiLCBkZWNsYXJhdGlvbi5yZXR1cm5UeXBlKSwge21hcHBpbmdLaW5kOiBcImV4YWN0XCIsIG5vZGU6IGRlY2xhcmF0aW9uLnJldHVyblR5cGUsXG4gICAgICBwYXRoOiBgJHtwYXRofS9yZXR1cm5UeXBlYCwgcm9sZTogXCJ0eXBlXCJ9KVxuICAgIHdyaXRlci5zeW50aGV0aWMoXCIge1xcblwiLCBcIktvdGxpbiBmdW5jdGlvbiBib2R5IHNjYWZmb2xkXCIsIFtkZWNsYXJhdGlvbl0sIFtwYXRoXSlcbiAgICBlbWl0S290bGluQmxvY2sod3JpdGVyLCBkZWNsYXJhdGlvbi5ib2R5LCBcIiAgICBcIiwgYCR7cGF0aH0vYm9keWAsIGAke3NpbmtOYW1lfS53cml0ZWApXG4gICAgd3JpdGVyLnN5bnRoZXRpYyhcIiAgfVxcblwiLCBcIktvdGxpbiBmdW5jdGlvbiBib2R5IHNjYWZmb2xkXCIsIFtkZWNsYXJhdGlvbl0sIFtwYXRoXSlcbiAgfSlcbiAgaWYgKGVudHJ5KSB7XG4gICAgd3JpdGVyLnN5bnRoZXRpYyhcIiAgZnVuIHNlbWFudGlmb2xkRW50cnkoKTogamF2YS51dGlsLkFycmF5TGlzdDxTdHJpbmc+IHtcXG5cIiwgXCJBbmRyb2lkIHNlbWFudGljIGVudHJ5IHNjYWZmb2xkXCIsIFttb2R1bGUuZW50cnlQb2ludF0sIFtcIi9lbnRyeVBvaW50XCJdKVxuICAgIHdyaXRlci5zeW50aGV0aWMoYCAgICB2YWwgJHtzaW5rTmFtZX0gPSBTZW1hbnRpZm9sZE91dHB1dFNpbmsoKVxcbmAsIFwiQW5kcm9pZCBvdXRwdXQgc2luayBhbGxvY2F0aW9uXCIsXG4gICAgICBbbW9kdWxlLmVudHJ5UG9pbnRdLCBbXCIvZW50cnlQb2ludFwiXSlcbiAgICB3cml0ZXIuc3ludGhldGljKGAgICAgJHtzaW5rTmFtZX0ucmVzZXQoKVxcbmAsIFwiQW5kcm9pZCBsaWZlY3ljbGUtc2FmZSBvdXRwdXQgcmVzZXRcIiwgW21vZHVsZS5lbnRyeVBvaW50XSwgW1wiL2VudHJ5UG9pbnRcIl0pXG4gICAgZW1pdEtvdGxpbkJsb2NrKHdyaXRlciwgbW9kdWxlLmVudHJ5UG9pbnQuYm9keSwgXCIgICAgXCIsIFwiL2VudHJ5UG9pbnQvYm9keVwiLCBgJHtzaW5rTmFtZX0ud3JpdGVgKVxuICAgIHdyaXRlci5zeW50aGV0aWMoYCAgICByZXR1cm4gJHtzaW5rTmFtZX0uc25hcHNob3QoKVxcbmAsIFwiQW5kcm9pZCBzZW1hbnRpYyBvdXRwdXQgcmV0dXJuXCIsXG4gICAgICBbbW9kdWxlLmVudHJ5UG9pbnRdLCBbXCIvZW50cnlQb2ludFwiXSlcbiAgICB3cml0ZXIuc3ludGhldGljKFwiICB9XFxuXCIsIFwiQW5kcm9pZCBzZW1hbnRpYyBlbnRyeSBzY2FmZm9sZFwiLCBbbW9kdWxlLmVudHJ5UG9pbnRdLCBbXCIvZW50cnlQb2ludFwiXSlcbiAgfVxuICB3cml0ZXIuc3ludGhldGljKFwifVxcblwiLCBcIkFuZHJvaWQgc2VtYW50aWMgbW9kdWxlIG5hbWVzcGFjZVwiLCBbbW9kdWxlXSwgW1wiXCJdKVxufVxuXG4vKipcbiAqIExpc3RzIGV2ZXJ5IGZpeGVkIGdlbmVyYXRlZCBwYXRoIGJlZm9yZSBhbnkgd3JpdGVyIGlzIGFsbG9jYXRlZC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuQW5kcm9pZEFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbn0gY29uZmlndXJhdGlvbiAtIE5vcm1hbGl6ZWQgYXBwbGljYXRpb24gY29uZmlndXJhdGlvbi5cbiAqIEBwYXJhbSB7TWFwPHN0cmluZywgc3RyaW5nPn0gbW9kdWxlUGF0aHMgLSBTZW1hbnRpYyBtb2R1bGUgb3V0cHV0IHBhdGhzLlxuICogQHJldHVybnMge3N0cmluZ1tdfSBGaXhlZCBvd25lZCBhcnRpZmFjdCBwYXRocy5cbiAqL1xuZnVuY3Rpb24gYXBwbGljYXRpb25QYXRocyhjb25maWd1cmF0aW9uLCBtb2R1bGVQYXRocykge1xuICBjb25zdCBwYWNrYWdlUGF0aCA9IGNvbmZpZ3VyYXRpb24ucGFja2FnZU5hbWUucmVwbGFjZUFsbChcIi5cIiwgXCIvXCIpXG5cbiAgcmV0dXJuIFtcbiAgICBgJHtwcm9qZWN0Um9vdH0vYXBwL2J1aWxkLmdyYWRsZS5rdHNgLFxuICAgIGAke3Byb2plY3RSb290fS9hcHAvc3JjL2FuZHJvaWRUZXN0L0FuZHJvaWRNYW5pZmVzdC54bWxgLFxuICAgIGAke3Byb2plY3RSb290fS9hcHAvc3JjL2FuZHJvaWRUZXN0L2tvdGxpbi8ke3BhY2thZ2VQYXRofS9TZW1hbnRpZm9sZFVpSW5zdHJ1bWVudGF0aW9uLmt0YCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vYXBwL3NyYy9tYWluL0FuZHJvaWRNYW5pZmVzdC54bWxgLFxuICAgIGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4va290bGluLyR7cGFja2FnZVBhdGh9LyR7Y29uZmlndXJhdGlvbi5hY3Rpdml0eUNsYXNzTmFtZX0ua3RgLFxuICAgIC4uLm1vZHVsZVBhdGhzLnZhbHVlcygpLFxuICAgIGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4va290bGluLyR7cGFja2FnZVBhdGh9L3NlbWFudGljL1NlbWFudGlmb2xkUnVudGltZS5rdGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9yZXMvbGF5b3V0L2FjdGl2aXR5X21haW4ueG1sYCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vYXBwL3NyYy9tYWluL3Jlcy92YWx1ZXMvc3RyaW5ncy54bWxgLFxuICAgIGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4vcmVzL3ZhbHVlcy90aGVtZXMueG1sYCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vYXBwL3NyYy9tYWluL3Jlcy94bWwvYmFja3VwX3J1bGVzLnhtbGAsXG4gICAgYCR7cHJvamVjdFJvb3R9L2FwcC9zcmMvbWFpbi9yZXMveG1sL2RhdGFfZXh0cmFjdGlvbl9ydWxlcy54bWxgLFxuICAgIGAke3Byb2plY3RSb290fS9hcHAvc3JjL3Rlc3Qva290bGluLyR7cGFja2FnZVBhdGh9L1NlbWFudGlmb2xkRW50cnlUZXN0Lmt0YCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vYnVpbGQuZ3JhZGxlLmt0c2AsXG4gICAgYCR7cHJvamVjdFJvb3R9L2dyYWRsZS5wcm9wZXJ0aWVzYCxcbiAgICBgJHtwcm9qZWN0Um9vdH0vc2V0dGluZ3MuZ3JhZGxlLmt0c2AsXG4gICAgYCR7cHJvamVjdFJvb3R9L3NlbWFudGlmb2xkLXByb2plY3QuanNvbmBcbiAgXVxufVxuXG4vKipcbiAqIFJlbmRlcnMgdGhlIHBpbm5lZCByb290IHBsdWdpbiBkZWNsYXJhdGlvbnMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBSb290IEdyYWRsZSBLb3RsaW4gc2NyaXB0LlxuICovXG5mdW5jdGlvbiByZW5kZXJSb290QnVpbGQoKSB7XG4gIHJldHVybiBgcGx1Z2lucyB7XG4gIGlkKFwiY29tLmFuZHJvaWQuYXBwbGljYXRpb25cIikgdmVyc2lvbiBcIiR7dG9vbGNoYWluLmFuZHJvaWRHcmFkbGVQbHVnaW59XCIgYXBwbHkgZmFsc2VcbiAgaWQoXCJvcmcuamV0YnJhaW5zLmtvdGxpbi5hbmRyb2lkXCIpIHZlcnNpb24gXCIke3Rvb2xjaGFpbi5rb3RsaW59XCIgYXBwbHkgZmFsc2Vcbn1cbmBcbn1cblxuLyoqXG4gKiBSZW5kZXJzIGNsb3NlZCBwcm9qZWN0IHNldHRpbmdzIGFuZCByZXBvc2l0b3JpZXMuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkFuZHJvaWRBcHBsaWNhdGlvbkNvbmZpZ3VyYXRpb259IGNvbmZpZ3VyYXRpb24gLSBOb3JtYWxpemVkIGNvbmZpZ3VyYXRpb24uXG4gKiBAcGFyYW0ge0NvbmZpZ3VyYXRpb25TcGFuW119IHNwYW5zIC0gQ29sbGVjdGVkIGNvbmZpZ3VyYXRpb24gcHJvdmVuYW5jZSBzcGFucy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IFNldHRpbmdzIEdyYWRsZSBLb3RsaW4gc2NyaXB0LlxuICovXG5mdW5jdGlvbiByZW5kZXJTZXR0aW5ncyhjb25maWd1cmF0aW9uLCBzcGFucykge1xuICByZXR1cm4gY29uZmlndXJlZChgJHtwcm9qZWN0Um9vdH0vc2V0dGluZ3MuZ3JhZGxlLmt0c2AsIHNwYW5zLCBbYHBsdWdpbk1hbmFnZW1lbnQge1xuICByZXBvc2l0b3JpZXMge1xuICAgIGdvb2dsZSgpXG4gICAgbWF2ZW5DZW50cmFsKClcbiAgICBncmFkbGVQbHVnaW5Qb3J0YWwoKVxuICB9XG59XG5cbmRlcGVuZGVuY3lSZXNvbHV0aW9uTWFuYWdlbWVudCB7XG4gIHJlcG9zaXRvcmllc01vZGUuc2V0KFJlcG9zaXRvcmllc01vZGUuRkFJTF9PTl9QUk9KRUNUX1JFUE9TKVxuICByZXBvc2l0b3JpZXMge1xuICAgIGdvb2dsZSgpXG4gICAgbWF2ZW5DZW50cmFsKClcbiAgfVxufVxuXG5yb290UHJvamVjdC5uYW1lID0gXCJgLCBmaWVsZChcInByb2R1Y3ROYW1lXCIsIGtvdGxpbkVzY2FwZShjb25maWd1cmF0aW9uLnByb2R1Y3ROYW1lKSksIGBcIlxuaW5jbHVkZShcIjphcHBcIilcbmBdKVxufVxuXG4vKipcbiAqIFJlbmRlcnMgZGV0ZXJtaW5pc3RpYyBHcmFkbGUgcHJvY2VzcyBwcm9wZXJ0aWVzLlxuICogQHJldHVybnMge3N0cmluZ30gR3JhZGxlIHByb3BlcnRpZXMgZmlsZS5cbiAqL1xuZnVuY3Rpb24gcmVuZGVyR3JhZGxlUHJvcGVydGllcygpIHtcbiAgcmV0dXJuIGBvcmcuZ3JhZGxlLmNhY2hpbmc9ZmFsc2Vcbm9yZy5ncmFkbGUuY29uZmlndXJhdGlvbi1jYWNoZT1mYWxzZVxub3JnLmdyYWRsZS5kYWVtb249ZmFsc2Vcbm9yZy5ncmFkbGUuanZtYXJncz0tWG14MjA0OG0gLURmaWxlLmVuY29kaW5nPVVURi04IC1EdXNlci5sYW5ndWFnZT1lbiAtRHVzZXIuY291bnRyeT1VUyAtRHVzZXIudGltZXpvbmU9VVRDXG5vcmcuZ3JhZGxlLnBhcmFsbGVsPWZhbHNlXG5rb3RsaW4uc3RkbGliLmRlZmF1bHQuZGVwZW5kZW5jeT1mYWxzZVxua290bGluLmNvZGUuc3R5bGU9b2ZmaWNpYWxcbmBcbn1cblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBhcHBsaWNhdGlvbiBtb2R1bGUgYnVpbGQgY29udHJhY3QuXG4gKiBAcGFyYW0ge2ltcG9ydChcIi4uL3NlbWFudGljL3R5cGVzLmpzXCIpLkFuZHJvaWRBcHBsaWNhdGlvbkNvbmZpZ3VyYXRpb259IGNvbmZpZ3VyYXRpb24gLSBOb3JtYWxpemVkIGNvbmZpZ3VyYXRpb24uXG4gKiBAcGFyYW0ge0NvbmZpZ3VyYXRpb25TcGFuW119IHNwYW5zIC0gQ29sbGVjdGVkIGNvbmZpZ3VyYXRpb24gcHJvdmVuYW5jZSBzcGFucy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IEFwcGxpY2F0aW9uIEdyYWRsZSBLb3RsaW4gc2NyaXB0LlxuICovXG5mdW5jdGlvbiByZW5kZXJBcHBCdWlsZChjb25maWd1cmF0aW9uLCBzcGFucykge1xuICByZXR1cm4gY29uZmlndXJlZChgJHtwcm9qZWN0Um9vdH0vYXBwL2J1aWxkLmdyYWRsZS5rdHNgLCBzcGFucywgW1xuICAgIGBpbXBvcnQgb3JnLmpldGJyYWlucy5rb3RsaW4uZ3JhZGxlLmRzbC5Kdm1UYXJnZXRcbmltcG9ydCBvcmcuamV0YnJhaW5zLmtvdGxpbi5ncmFkbGUudGFza3MuS290bGluSnZtQ29tcGlsZVxuXG5wbHVnaW5zIHtcbiAgaWQoXCJjb20uYW5kcm9pZC5hcHBsaWNhdGlvblwiKVxuICBpZChcIm9yZy5qZXRicmFpbnMua290bGluLmFuZHJvaWRcIilcbn1cblxuZGVwZW5kZW5jaWVzIHtcbiAgdGVzdFJ1bnRpbWVPbmx5KFwib3JnLmhhbWNyZXN0OmhhbWNyZXN0LWNvcmU6MS4zXCIpIHtcbiAgICBpc1RyYW5zaXRpdmUgPSBmYWxzZVxuICB9XG59XG5cbnZhbCBzZW1hbnRpZm9sZEtvdGxpbkhvbWUgPSBwcm92aWRlcnMuZW52aXJvbm1lbnRWYXJpYWJsZShcIlNFTUFOVElGT0xEX0tPVExJTl9IT01FXCIpLm9yTnVsbFxuICA/OiB0aHJvdyBHcmFkbGVFeGNlcHRpb24oXCJTRU1BTlRJRk9MRF9BTkRST0lEX0lORlJBU1RSVUNUVVJFOiBTRU1BTlRJRk9MRF9LT1RMSU5fSE9NRSBpcyByZXF1aXJlZFwiKVxudmFsIHNlbWFudGlmb2xkS290bGluU3RkbGliID0gZmlsZShcIiRzZW1hbnRpZm9sZEtvdGxpbkhvbWUvbGliL2tvdGxpbi1zdGRsaWIuamFyXCIpXG5pZiAoIXNlbWFudGlmb2xkS290bGluU3RkbGliLmlzRmlsZSkge1xuICB0aHJvdyBHcmFkbGVFeGNlcHRpb24oXCJTRU1BTlRJRk9MRF9BTkRST0lEX0lORlJBU1RSVUNUVVJFOiBwaW5uZWQgS290bGluIGNvbXBpbGUgbGlicmFyeSBpcyBtaXNzaW5nXCIpXG59XG52YWwgc2VtYW50aWZvbGRBY2NlcHRhbmNlUm9vdCA9IHByb3ZpZGVycy5lbnZpcm9ubWVudFZhcmlhYmxlKFwiU0VNQU5USUZPTERfQU5EUk9JRF9BQ0NFUFRBTkNFX1JPT1RcIikub3JOdWxsXG4gID86IHRocm93IEdyYWRsZUV4Y2VwdGlvbihcIlNFTUFOVElGT0xEX0FORFJPSURfSU5GUkFTVFJVQ1RVUkU6IFNFTUFOVElGT0xEX0FORFJPSURfQUNDRVBUQU5DRV9ST09UIGlzIHJlcXVpcmVkXCIpXG52YWwgc2VtYW50aWZvbGREZWJ1Z0tleXN0b3JlID0gZmlsZShcIiRzZW1hbnRpZm9sZEFjY2VwdGFuY2VSb290L2RlYnVnLmtleXN0b3JlXCIpXG5pZiAoIXNlbWFudGlmb2xkRGVidWdLZXlzdG9yZS5pc0ZpbGUpIHtcbiAgdGhyb3cgR3JhZGxlRXhjZXB0aW9uKFwiU0VNQU5USUZPTERfQU5EUk9JRF9JTkZSQVNUUlVDVFVSRTogZXBoZW1lcmFsIGRlYnVnIGtleXN0b3JlIGlzIG1pc3NpbmdcIilcbn1cblxuYW5kcm9pZCB7XG4gIG5hbWVzcGFjZSA9IFwiYCxcbiAgICBmaWVsZChcIm5hbWVzcGFjZVwiLCBjb25maWd1cmF0aW9uLm5hbWVzcGFjZSksIGBcIlxcbiAgY29tcGlsZVNkayA9IGAsIGZpZWxkKFwiY29tcGlsZVNka1wiLCBTdHJpbmcoY29uZmlndXJhdGlvbi5jb21waWxlU2RrKSksXG4gICAgYFxcbiAgYnVpbGRUb29sc1ZlcnNpb24gPSBcImAsIGZpZWxkKFwiYnVpbGRUb29sc1ZlcnNpb25cIiwgY29uZmlndXJhdGlvbi5idWlsZFRvb2xzVmVyc2lvbiksIGBcIlxcblxcbiAgZGVmYXVsdENvbmZpZyB7XFxuICAgIGFwcGxpY2F0aW9uSWQgPSBcImAsXG4gICAgZmllbGQoXCJhcHBsaWNhdGlvbklkXCIsIGNvbmZpZ3VyYXRpb24uYXBwbGljYXRpb25JZCksIGBcIlxcbiAgICBtaW5TZGsgPSBgLCBmaWVsZChcIm1pbmltdW1TZGtcIiwgU3RyaW5nKGNvbmZpZ3VyYXRpb24ubWluaW11bVNkaykpLFxuICAgIGBcXG4gICAgdGFyZ2V0U2RrID0gYCwgZmllbGQoXCJ0YXJnZXRTZGtcIiwgU3RyaW5nKGNvbmZpZ3VyYXRpb24udGFyZ2V0U2RrKSksIGBcXG4gICAgdmVyc2lvbkNvZGUgPSBgLFxuICAgIGZpZWxkKFwidmVyc2lvbkNvZGVcIiwgU3RyaW5nKGNvbmZpZ3VyYXRpb24udmVyc2lvbkNvZGUpKSwgYFxcbiAgICB2ZXJzaW9uTmFtZSA9IFwiYCwgZmllbGQoXCJ2ZXJzaW9uTmFtZVwiLCBrb3RsaW5Fc2NhcGUoY29uZmlndXJhdGlvbi52ZXJzaW9uTmFtZSkpLFxuICAgIGBcIlxcbiAgICB0ZXN0QXBwbGljYXRpb25JZCA9IFwiYCwgZmllbGQoXCJhcHBsaWNhdGlvbklkXCIsIGNvbmZpZ3VyYXRpb24uYXBwbGljYXRpb25JZCksXG4gICAgYC50ZXN0XCJcXG4gICAgdGVzdEluc3RydW1lbnRhdGlvblJ1bm5lciA9IFwiYCwgZmllbGQoXCJwYWNrYWdlTmFtZVwiLCBjb25maWd1cmF0aW9uLnBhY2thZ2VOYW1lKSxcbiAgICBgLlNlbWFudGlmb2xkVWlJbnN0cnVtZW50YXRpb25cIlxcbiAgfVxcblxcbiAgc2lnbmluZ0NvbmZpZ3Mge1xcbiAgICBnZXRCeU5hbWUoXCJkZWJ1Z1wiKSB7XFxuICAgICAgc3RvcmVGaWxlID0gc2VtYW50aWZvbGREZWJ1Z0tleXN0b3JlXFxuICAgICAgc3RvcmVQYXNzd29yZCA9IFwiYW5kcm9pZFwiXFxuICAgICAga2V5QWxpYXMgPSBcImFuZHJvaWRkZWJ1Z2tleVwiXFxuICAgICAga2V5UGFzc3dvcmQgPSBcImFuZHJvaWRcIlxcbiAgICB9XFxuICB9XFxuICBidWlsZFR5cGVzIHtcXG4gICAgZ2V0QnlOYW1lKFwiZGVidWdcIikge1xcbiAgICAgIHNpZ25pbmdDb25maWcgPSBzaWduaW5nQ29uZmlncy5nZXRCeU5hbWUoXCJkZWJ1Z1wiKVxcbiAgICB9XFxuICB9XFxuICBidWlsZEZlYXR1cmVzIHtcXG4gICAgYnVpbGRDb25maWcgPSBmYWxzZVxcbiAgfVxcbiAgY29tcGlsZU9wdGlvbnMge1xcbiAgICBzb3VyY2VDb21wYXRpYmlsaXR5ID0gSmF2YVZlcnNpb24uVkVSU0lPTl8yMVxcbiAgICB0YXJnZXRDb21wYXRpYmlsaXR5ID0gSmF2YVZlcnNpb24uVkVSU0lPTl8yMVxcbiAgfVxcbiAgbGludCB7XFxuICAgIGFib3J0T25FcnJvciA9IHRydWVcXG4gICAgY2hlY2tEZXBlbmRlbmNpZXMgPSB0cnVlXFxuICAgIGRpc2FibGUgKz0gXCJNaXNzaW5nQXBwbGljYXRpb25JY29uXCJcXG4gICAgZGlzYWJsZSArPSBcIk9sZFRhcmdldEFwaVwiXFxuICAgIGRpc2FibGUgKz0gXCJHcmFkbGVEZXBlbmRlbmN5XCJcXG4gICAgd2FybmluZ3NBc0Vycm9ycyA9IHRydWVcXG4gIH1cXG4gIHBhY2thZ2luZyB7XFxuICAgIHJlc291cmNlcy5leGNsdWRlcyArPSBzZXRPZihcIk1FVEEtSU5GL0xJQ0VOU0UqXCIsIFwiTUVUQS1JTkYvTk9USUNFKlwiKVxcbiAgfVxcbn1cXG5cXG50YXNrcy53aXRoVHlwZTxLb3RsaW5Kdm1Db21waWxlPigpLmNvbmZpZ3VyZUVhY2gge1xcbiAgbGlicmFyaWVzLmZyb20oZmlsZXMoc2VtYW50aWZvbGRLb3RsaW5TdGRsaWIpKVxcbiAgY29tcGlsZXJPcHRpb25zIHtcXG4gICAgYWxsV2FybmluZ3NBc0Vycm9ycy5zZXQodHJ1ZSlcXG4gICAgZnJlZUNvbXBpbGVyQXJncy5hZGRBbGwoXCItWG5vLWNhbGwtYXNzZXJ0aW9uc1wiLCBcIi1Ybm8tcGFyYW0tYXNzZXJ0aW9uc1wiLCBcIi1Ybm8tcmVjZWl2ZXItYXNzZXJ0aW9uc1wiKVxcbiAgICBqdm1UYXJnZXQuc2V0KEp2bVRhcmdldC5KVk1fMjEpXFxuICB9XFxufVxcblxcbmRlcGVuZGVuY2llcyB7XFxuICB0ZXN0SW1wbGVtZW50YXRpb24oXCJqdW5pdDpqdW5pdDo0LjEzLjJcIikge1xcbiAgICBpc1RyYW5zaXRpdmUgPSBmYWxzZVxcbiAgfVxcbn1cXG5gXG4gIF0pXG59XG5cbi8qKlxuICogUmVuZGVycyB0aGUgYWxsb3dsaXN0ZWQgQW5kcm9pZCBhcHBsaWNhdGlvbiBtYW5pZmVzdC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vc2VtYW50aWMvdHlwZXMuanNcIikuQW5kcm9pZEFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbn0gY29uZmlndXJhdGlvbiAtIE5vcm1hbGl6ZWQgY29uZmlndXJhdGlvbi5cbiAqIEBwYXJhbSB7Q29uZmlndXJhdGlvblNwYW5bXX0gc3BhbnMgLSBDb2xsZWN0ZWQgY29uZmlndXJhdGlvbiBwcm92ZW5hbmNlIHNwYW5zLlxuICogQHJldHVybnMge3N0cmluZ30gQW5kcm9pZCBhcHBsaWNhdGlvbiBtYW5pZmVzdC5cbiAqL1xuZnVuY3Rpb24gcmVuZGVyQW5kcm9pZE1hbmlmZXN0KGNvbmZpZ3VyYXRpb24sIHNwYW5zKSB7XG4gIGNvbnN0IG9yaWVudGF0aW9uID0gY29uZmlndXJhdGlvbi5vcmllbnRhdGlvbiA9PSBcInVuc3BlY2lmaWVkXCIgPyBcIlwiIDogYCBhbmRyb2lkOnNjcmVlbk9yaWVudGF0aW9uPVwiJHtjb25maWd1cmF0aW9uLm9yaWVudGF0aW9ufVwiYFxuXG4gIHJldHVybiBjb25maWd1cmVkKGAke3Byb2plY3RSb290fS9hcHAvc3JjL21haW4vQW5kcm9pZE1hbmlmZXN0LnhtbGAsIHNwYW5zLCBbXG4gICAgYDw/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=