obsidian-integration-testing 12.0.0 → 12.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/cjs/adb-device-list.cjs +54 -0
- package/dist/lib/cjs/adb-device-list.d.cts +72 -0
- package/dist/lib/cjs/android-sdk.cjs +52 -0
- package/dist/lib/cjs/android-sdk.d.cts +29 -0
- package/dist/lib/cjs/app-startup-progress.cjs +87 -0
- package/dist/lib/cjs/app-startup-progress.d.cts +128 -0
- package/dist/lib/cjs/appium-server-marker.cjs +29 -32
- package/dist/lib/cjs/appium-server-marker.d.cts +22 -0
- package/dist/lib/cjs/avd-probe-verdict.cjs +90 -0
- package/dist/lib/cjs/avd-probe-verdict.d.cts +175 -0
- package/dist/lib/cjs/community-plugin-registry.cjs +1 -1
- package/dist/lib/cjs/community-plugin-registry.d.cts +1 -1
- package/dist/lib/cjs/config-directory-fallback-error.cjs +57 -0
- package/dist/lib/cjs/config-directory-fallback-error.d.cts +64 -0
- package/dist/lib/cjs/config-directory.cjs +46 -0
- package/dist/lib/cjs/config-directory.d.cts +45 -0
- package/dist/lib/cjs/connect-to-cdp.cjs +13 -7
- package/dist/lib/cjs/connect-to-cdp.d.cts +19 -0
- package/dist/lib/cjs/demo-vault-bootstrap.cjs +1 -1
- package/dist/lib/cjs/demo-vault-bootstrap.d.cts +3 -2
- package/dist/lib/cjs/demo-vault-populate.cjs +3 -2
- package/dist/lib/cjs/device-readiness.cjs +38 -3
- package/dist/lib/cjs/device-readiness.d.cts +83 -9
- package/dist/lib/cjs/emulator-arguments.cjs +6 -2
- package/dist/lib/cjs/emulator-arguments.d.cts +26 -0
- package/dist/lib/cjs/emulator-backend.cjs +71 -0
- package/dist/lib/cjs/emulator-backend.d.cts +76 -0
- package/dist/lib/cjs/emulator-liveness.cjs +72 -0
- package/dist/lib/cjs/emulator-liveness.d.cts +158 -0
- package/dist/lib/cjs/emulator-snapshot.cjs +57 -0
- package/dist/lib/cjs/emulator-snapshot.d.cts +68 -0
- package/dist/lib/cjs/global-setup-core.cjs +30 -30
- package/dist/lib/cjs/global-setup-core.d.cts +27 -2
- package/dist/lib/cjs/headless-vault-config.cjs +51 -0
- package/dist/lib/cjs/headless-vault-config.d.cts +67 -0
- package/dist/lib/cjs/index.cjs +12 -1
- package/dist/lib/cjs/index.d.cts +6 -1
- package/dist/lib/cjs/library.cjs +1 -1
- package/dist/lib/cjs/mobile-input.cjs +14 -2
- package/dist/lib/cjs/mobile-input.d.cts +5 -9
- package/dist/lib/cjs/namespace-bootstrap.cjs +1 -1
- package/dist/lib/cjs/obsidian-instance.cjs +52 -3
- package/dist/lib/cjs/obsidian-instance.d.cts +12 -0
- package/dist/lib/cjs/open-obsidian-settings-tab.cjs +1 -1
- package/dist/lib/cjs/open-obsidian-settings-tab.d.cts +3 -2
- package/dist/lib/cjs/owned-instance-exit-marker.cjs +99 -0
- package/dist/lib/cjs/owned-instance-exit-marker.d.cts +106 -0
- package/dist/lib/cjs/owned-instance-exited-error.cjs +106 -0
- package/dist/lib/cjs/owned-instance-exited-error.d.cts +98 -0
- package/dist/lib/cjs/owned-vault-seed.cjs +9 -5
- package/dist/lib/cjs/owned-vault-seed.d.cts +24 -3
- package/dist/lib/cjs/parent-liveness.cjs +42 -5
- package/dist/lib/cjs/parent-liveness.d.cts +37 -5
- package/dist/lib/cjs/port-owner.cjs +61 -0
- package/dist/lib/cjs/port-owner.d.cts +47 -0
- package/dist/lib/cjs/process-capture.cjs +62 -0
- package/dist/lib/cjs/process-capture.d.cts +83 -0
- package/dist/lib/cjs/process-exit-message.cjs +14 -8
- package/dist/lib/cjs/process-exit-message.d.cts +37 -3
- package/dist/lib/cjs/process-liveness.cjs +51 -0
- package/dist/lib/cjs/process-liveness.d.cts +18 -0
- package/dist/lib/cjs/run-version-matrix.cjs +1 -1
- package/dist/lib/cjs/run-version-matrix.d.cts +1 -1
- package/dist/lib/cjs/teardown-verdict.cjs +53 -0
- package/dist/lib/cjs/teardown-verdict.d.cts +69 -0
- package/dist/lib/cjs/temporary-vault.cjs +43 -8
- package/dist/lib/cjs/temporary-vault.d.cts +47 -5
- package/dist/lib/cjs/transport-appium.cjs +102 -17
- package/dist/lib/cjs/transport-appium.d.cts +53 -3
- package/dist/lib/cjs/transport-desktop-cdp.cjs +195 -6
- package/dist/lib/cjs/transport-desktop-cdp.d.cts +99 -0
- package/dist/lib/cjs/transport-factory.cjs +951 -133
- package/dist/lib/cjs/transport-options.cjs +11 -3
- package/dist/lib/cjs/transport-options.d.cts +131 -12
- package/dist/lib/cjs/transport.cjs +1 -1
- package/dist/lib/cjs/transport.d.cts +7 -1
- package/dist/lib/cjs/vault-plugin-install.cjs +40 -0
- package/dist/lib/cjs/vault-plugin-install.d.cts +64 -0
- package/dist/lib/cjs/vault-teardown-verdict.cjs +42 -0
- package/dist/lib/cjs/vault-teardown-verdict.d.cts +57 -0
- package/dist/lib/cjs/version-matrix.cjs +1 -1
- package/dist/lib/cjs/version-matrix.d.cts +2 -2
- package/dist/lib/cjs/webview-cdp.cjs +6 -7
- package/dist/lib/cjs/webview-cdp.d.cts +5 -1
- package/dist/lib/esm/adb-device-list.d.mts +72 -0
- package/dist/lib/esm/adb-device-list.mjs +28 -0
- package/dist/lib/esm/android-sdk.d.mts +29 -0
- package/dist/lib/esm/android-sdk.mjs +18 -0
- package/dist/lib/esm/app-startup-progress.d.mts +128 -0
- package/dist/lib/esm/app-startup-progress.mjs +59 -0
- package/dist/lib/esm/appium-server-marker.d.mts +22 -0
- package/dist/lib/esm/appium-server-marker.mjs +28 -22
- package/dist/lib/esm/avd-probe-verdict.d.mts +175 -0
- package/dist/lib/esm/avd-probe-verdict.mjs +62 -0
- package/dist/lib/esm/community-plugin-registry.d.mts +1 -1
- package/dist/lib/esm/community-plugin-registry.mjs +1 -1
- package/dist/lib/esm/config-directory-fallback-error.d.mts +64 -0
- package/dist/lib/esm/config-directory-fallback-error.mjs +33 -0
- package/dist/lib/esm/config-directory.d.mts +45 -0
- package/dist/lib/esm/config-directory.mjs +21 -0
- package/dist/lib/esm/connect-to-cdp.d.mts +19 -0
- package/dist/lib/esm/connect-to-cdp.mjs +13 -7
- package/dist/lib/esm/demo-vault-bootstrap.d.mts +3 -2
- package/dist/lib/esm/demo-vault-bootstrap.mjs +1 -1
- package/dist/lib/esm/demo-vault-populate.mjs +3 -2
- package/dist/lib/esm/device-readiness.d.mts +83 -9
- package/dist/lib/esm/device-readiness.mjs +34 -2
- package/dist/lib/esm/emulator-arguments.d.mts +26 -0
- package/dist/lib/esm/emulator-arguments.mjs +6 -2
- package/dist/lib/esm/emulator-backend.d.mts +76 -0
- package/dist/lib/esm/emulator-backend.mjs +45 -0
- package/dist/lib/esm/emulator-liveness.d.mts +158 -0
- package/dist/lib/esm/emulator-liveness.mjs +47 -0
- package/dist/lib/esm/emulator-snapshot.d.mts +68 -0
- package/dist/lib/esm/emulator-snapshot.mjs +32 -0
- package/dist/lib/esm/global-setup-core.d.mts +27 -2
- package/dist/lib/esm/global-setup-core.mjs +34 -35
- package/dist/lib/esm/headless-vault-config.d.mts +67 -0
- package/dist/lib/esm/headless-vault-config.mjs +31 -0
- package/dist/lib/esm/index.d.mts +6 -1
- package/dist/lib/esm/index.mjs +11 -1
- package/dist/lib/esm/library.mjs +1 -1
- package/dist/lib/esm/mobile-input.d.mts +5 -9
- package/dist/lib/esm/mobile-input.mjs +14 -2
- package/dist/lib/esm/namespace-bootstrap.mjs +1 -1
- package/dist/lib/esm/obsidian-instance.d.mts +12 -0
- package/dist/lib/esm/obsidian-instance.mjs +55 -3
- package/dist/lib/esm/open-obsidian-settings-tab.d.mts +3 -2
- package/dist/lib/esm/open-obsidian-settings-tab.mjs +1 -1
- package/dist/lib/esm/owned-instance-exit-marker.d.mts +106 -0
- package/dist/lib/esm/owned-instance-exit-marker.mjs +78 -0
- package/dist/lib/esm/owned-instance-exited-error.d.mts +98 -0
- package/dist/lib/esm/owned-instance-exited-error.mjs +81 -0
- package/dist/lib/esm/owned-vault-seed.d.mts +24 -3
- package/dist/lib/esm/owned-vault-seed.mjs +9 -5
- package/dist/lib/esm/parent-liveness.d.mts +37 -5
- package/dist/lib/esm/parent-liveness.mjs +42 -5
- package/dist/lib/esm/port-owner.d.mts +47 -0
- package/dist/lib/esm/port-owner.mjs +36 -0
- package/dist/lib/esm/process-capture.d.mts +83 -0
- package/dist/lib/esm/process-capture.mjs +38 -0
- package/dist/lib/esm/process-exit-message.d.mts +37 -3
- package/dist/lib/esm/process-exit-message.mjs +13 -8
- package/dist/lib/esm/process-liveness.d.mts +18 -0
- package/dist/lib/esm/process-liveness.mjs +17 -0
- package/dist/lib/esm/run-version-matrix.d.mts +1 -1
- package/dist/lib/esm/run-version-matrix.mjs +1 -1
- package/dist/lib/esm/teardown-verdict.d.mts +69 -0
- package/dist/lib/esm/teardown-verdict.mjs +28 -0
- package/dist/lib/esm/temporary-vault.d.mts +47 -5
- package/dist/lib/esm/temporary-vault.mjs +43 -8
- package/dist/lib/esm/transport-appium.d.mts +53 -3
- package/dist/lib/esm/transport-appium.mjs +108 -17
- package/dist/lib/esm/transport-desktop-cdp.d.mts +99 -0
- package/dist/lib/esm/transport-desktop-cdp.mjs +202 -7
- package/dist/lib/esm/transport-factory.mjs +995 -138
- package/dist/lib/esm/transport-options.d.mts +131 -12
- package/dist/lib/esm/transport-options.mjs +9 -2
- package/dist/lib/esm/transport.d.mts +7 -1
- package/dist/lib/esm/vault-plugin-install.d.mts +64 -0
- package/dist/lib/esm/vault-plugin-install.mjs +20 -0
- package/dist/lib/esm/vault-teardown-verdict.d.mts +57 -0
- package/dist/lib/esm/vault-teardown-verdict.mjs +18 -0
- package/dist/lib/esm/version-matrix.d.mts +2 -2
- package/dist/lib/esm/version-matrix.mjs +1 -1
- package/dist/lib/esm/webview-cdp.d.mts +5 -1
- package/dist/lib/esm/webview-cdp.mjs +6 -7
- package/package.json +24 -23
- package/dist/lib/cjs/native-dialog-monitor.cjs +0 -192
- package/dist/lib/cjs/native-dialog-monitor.d.cts +0 -66
- package/dist/lib/cjs/obsidian-namespace.cjs +0 -17
- package/dist/lib/cjs/obsidian-namespace.d.cts +0 -128
- package/dist/lib/esm/native-dialog-monitor.d.mts +0 -66
- package/dist/lib/esm/native-dialog-monitor.mjs +0 -158
- package/dist/lib/esm/obsidian-namespace.d.mts +0 -128
- package/dist/lib/esm/obsidian-namespace.mjs +0 -1
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
2
|
execFile,
|
|
3
|
+
execFileSync,
|
|
3
4
|
spawn
|
|
4
5
|
} from "node:child_process";
|
|
5
6
|
import {
|
|
6
7
|
mkdirSync,
|
|
7
|
-
mkdtempSync
|
|
8
|
+
mkdtempSync,
|
|
9
|
+
statSync
|
|
8
10
|
} from "node:fs";
|
|
9
11
|
import http from "node:http";
|
|
10
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
homedir,
|
|
14
|
+
tmpdir
|
|
15
|
+
} from "node:os";
|
|
11
16
|
import { join } from "node:path";
|
|
12
17
|
import process from "node:process";
|
|
18
|
+
import {
|
|
19
|
+
checkIsDeviceListed,
|
|
20
|
+
listOnlineDeviceIds
|
|
21
|
+
} from "./adb-device-list.mjs";
|
|
22
|
+
import { resolveEmulatorBinaryPath } from "./android-sdk.mjs";
|
|
13
23
|
import {
|
|
14
24
|
checkIsAppiumDriverInstalled,
|
|
15
25
|
UIAUTOMATOR2_DRIVER_NAME,
|
|
@@ -19,6 +29,7 @@ import {
|
|
|
19
29
|
checkIsHarnessOwnedAppiumServer,
|
|
20
30
|
clearAppiumServerMarker,
|
|
21
31
|
readAppiumServerMarker,
|
|
32
|
+
recordAppiumServerStopAttempt,
|
|
22
33
|
writeAppiumServerMarker
|
|
23
34
|
} from "./appium-server-marker.mjs";
|
|
24
35
|
import {
|
|
@@ -29,18 +40,41 @@ import {
|
|
|
29
40
|
checkAvdExists,
|
|
30
41
|
listAvailableAvds
|
|
31
42
|
} from "./avd-list.mjs";
|
|
43
|
+
import {
|
|
44
|
+
buildAvdProbeSummary,
|
|
45
|
+
buildUnreadableDevicesMessage,
|
|
46
|
+
checkIsEmulatorDeviceId,
|
|
47
|
+
classifyAvdProbe,
|
|
48
|
+
resolveAvdProbeVerdict
|
|
49
|
+
} from "./avd-probe-verdict.mjs";
|
|
32
50
|
import {
|
|
33
51
|
resolveInstallerCompatibilityAction,
|
|
34
52
|
willThrowOnIncompatibleInstaller,
|
|
35
53
|
willThrowOnSilentAsarFallback,
|
|
36
54
|
willWarnOnCompatibilityIssues
|
|
37
55
|
} from "./compatibility-options.mjs";
|
|
56
|
+
import { assertValidConfigDirectory } from "./config-directory.mjs";
|
|
38
57
|
import { getSetupError } from "./context-provider.mjs";
|
|
39
58
|
import {
|
|
40
59
|
checkDeviceIdle,
|
|
41
|
-
|
|
60
|
+
checkNetworkValidated,
|
|
61
|
+
resolveDeviceIdleTimeoutInMilliseconds,
|
|
62
|
+
resolveNetworkReadyTimeoutInMilliseconds
|
|
42
63
|
} from "./device-readiness.mjs";
|
|
43
64
|
import { buildEmulatorArguments } from "./emulator-arguments.mjs";
|
|
65
|
+
import {
|
|
66
|
+
parsePosixProcessList,
|
|
67
|
+
parseWindowsTaskList,
|
|
68
|
+
selectEmulatorBackendPids
|
|
69
|
+
} from "./emulator-backend.mjs";
|
|
70
|
+
import {
|
|
71
|
+
buildEmulatorLivenessMessage,
|
|
72
|
+
resolveEmulatorLivenessVerdict
|
|
73
|
+
} from "./emulator-liveness.mjs";
|
|
74
|
+
import {
|
|
75
|
+
buildAvdSnapshotDirectoryCandidates,
|
|
76
|
+
buildSnapshotAgeMessage
|
|
77
|
+
} from "./emulator-snapshot.mjs";
|
|
44
78
|
import { exec } from "./exec.mjs";
|
|
45
79
|
import { IncompatibleInstallerVersionError } from "./incompatible-installer-version-error.mjs";
|
|
46
80
|
import { resolveInstallerCompatibility } from "./installer-compatibility.mjs";
|
|
@@ -70,18 +104,35 @@ import {
|
|
|
70
104
|
resolveConcreteVersion
|
|
71
105
|
} from "./obsidian-version-switch.mjs";
|
|
72
106
|
import { compareVersions } from "./obsidian-version.mjs";
|
|
73
|
-
import {
|
|
107
|
+
import { readOwnedInstanceExitMarker } from "./owned-instance-exit-marker.mjs";
|
|
108
|
+
import { buildOwnedInstanceExitedErrorFromMarker } from "./owned-instance-exited-error.mjs";
|
|
109
|
+
import {
|
|
110
|
+
parsePosixLsofPids,
|
|
111
|
+
parseWindowsNetstatPids
|
|
112
|
+
} from "./port-owner.mjs";
|
|
113
|
+
import {
|
|
114
|
+
appendProcessOutputTail,
|
|
115
|
+
buildProcessExitMessage
|
|
116
|
+
} from "./process-exit-message.mjs";
|
|
117
|
+
import { checkIsProcessAlive } from "./process-liveness.mjs";
|
|
74
118
|
import { resolveDeadBootGraceInMilliseconds } from "./renderer-boot-detection.mjs";
|
|
75
119
|
import {
|
|
76
120
|
resolveAppiumSpawnFlags,
|
|
77
121
|
resolveEmulatorSpawnFlags
|
|
78
122
|
} from "./spawn-options.mjs";
|
|
123
|
+
import {
|
|
124
|
+
buildTeardownMessage,
|
|
125
|
+
resolveTeardownOutcome
|
|
126
|
+
} from "./teardown-verdict.mjs";
|
|
79
127
|
import {
|
|
80
128
|
AppiumTransport,
|
|
81
129
|
DEFAULT_ANDROID_VAULT_BASE_PATH
|
|
82
130
|
} from "./transport-appium.mjs";
|
|
83
131
|
import { DesktopCdpTransport } from "./transport-desktop-cdp.mjs";
|
|
84
|
-
import {
|
|
132
|
+
import {
|
|
133
|
+
assertNever,
|
|
134
|
+
ensureNonNullable
|
|
135
|
+
} from "./type-guards.mjs";
|
|
85
136
|
import {
|
|
86
137
|
shouldHideAppiumConsole,
|
|
87
138
|
shouldHideEmulatorWindow
|
|
@@ -94,7 +145,11 @@ import {
|
|
|
94
145
|
const APP_PACKAGE = "md.obsidian";
|
|
95
146
|
const APP_ACTIVITY = `${APP_PACKAGE}.MainActivity`;
|
|
96
147
|
const ADB_DEVICE_CHECK_TIMEOUT_IN_MILLISECONDS = 5e3;
|
|
148
|
+
const AVD_PROBE_ATTEMPT_COUNT = 2;
|
|
149
|
+
const ADB_DUMPSYS_MAX_BUFFER_IN_BYTES = 8388608;
|
|
150
|
+
const ADB_DUMPSYS_TIMEOUT_IN_MILLISECONDS = 3e4;
|
|
97
151
|
const APPIUM_CONNECTION_RETRY_COUNT = 3;
|
|
152
|
+
const APPIUM_ESCALATED_STOP_TIMEOUT_IN_MILLISECONDS = 5e3;
|
|
98
153
|
const APPIUM_OUTPUT_TAIL_MAX_LENGTH = 8e3;
|
|
99
154
|
const APPIUM_PREFLIGHT_TIMEOUT_IN_MILLISECONDS = 5e3;
|
|
100
155
|
const APPIUM_START_POLL_INTERVAL_IN_MILLISECONDS = 500;
|
|
@@ -104,17 +159,26 @@ const CHROMEDRIVER_AUTODOWNLOAD_FEATURE = "uiautomator2:chromedriver_autodownloa
|
|
|
104
159
|
const COMMAND_TIMEOUT_IN_MILLISECONDS = 300;
|
|
105
160
|
const DEFAULT_TRANSPORT_TYPE = "obsidian-cdp";
|
|
106
161
|
const DEVICE_IDLE_POLL_INTERVAL_IN_MILLISECONDS = 2e3;
|
|
162
|
+
const DEVICE_LIVENESS_TIMEOUT_IN_MILLISECONDS = 15e3;
|
|
163
|
+
const DEVICE_LIVENESS_ATTEMPT_COUNT = 2;
|
|
164
|
+
const EMULATOR_BOOT_ATTEMPT_COUNT = 2;
|
|
107
165
|
const EMULATOR_BOOT_POLL_INTERVAL_IN_MILLISECONDS = 2e3;
|
|
108
166
|
const EMULATOR_BOOT_TIMEOUT_IN_MILLISECONDS = 12e4;
|
|
167
|
+
const EMULATOR_ESCALATED_STOP_TIMEOUT_IN_MILLISECONDS = 5e3;
|
|
109
168
|
const EMULATOR_LIST_TIMEOUT_IN_MILLISECONDS = 1e4;
|
|
110
169
|
const EMULATOR_OUTPUT_TAIL_MAX_LENGTH = 8e3;
|
|
170
|
+
const EMULATOR_STOP_POLL_INTERVAL_IN_MILLISECONDS = 500;
|
|
171
|
+
const EMULATOR_STOP_TIMEOUT_IN_MILLISECONDS = 2e4;
|
|
172
|
+
const HOST_PROCESS_QUERY_TIMEOUT_IN_MILLISECONDS = 3e4;
|
|
111
173
|
const HTTP_MULTIPLE_CHOICES = 300;
|
|
112
174
|
const HTTP_OK = 200;
|
|
113
175
|
const KEYCODE_MENU = 82;
|
|
114
176
|
const KEYCODE_WAKEUP = 224;
|
|
115
177
|
const MILLISECONDS_PER_SECOND = 1e3;
|
|
178
|
+
const NETWORK_READY_POLL_INTERVAL_IN_MILLISECONDS = 2e3;
|
|
116
179
|
const SERVER_INSTALL_TIMEOUT_IN_MILLISECONDS = 12e4;
|
|
117
180
|
const SERVER_LAUNCH_TIMEOUT_IN_MILLISECONDS = 12e4;
|
|
181
|
+
const SYNC_TEARDOWN_QUERY_TIMEOUT_IN_MILLISECONDS = 5e3;
|
|
118
182
|
let cachedTransport;
|
|
119
183
|
class AppiumTransportFactory {
|
|
120
184
|
type;
|
|
@@ -162,6 +226,7 @@ class AppiumTransportFactory {
|
|
|
162
226
|
isSessionOwner: false,
|
|
163
227
|
platform: "android",
|
|
164
228
|
shouldSweepLeftovers: willSweepLeftovers(options),
|
|
229
|
+
...options.appStartTimeoutInMilliseconds !== void 0 && { appStartTimeoutInMilliseconds: options.appStartTimeoutInMilliseconds },
|
|
165
230
|
...options.layoutReadyTimeoutInMilliseconds !== void 0 && { layoutReadyTimeoutInMilliseconds: options.layoutReadyTimeoutInMilliseconds },
|
|
166
231
|
...options.vaultBasePath !== void 0 && { vaultBasePath: options.vaultBasePath },
|
|
167
232
|
...options.webviewTimeoutInMilliseconds !== void 0 && { webviewTimeoutInMilliseconds: options.webviewTimeoutInMilliseconds }
|
|
@@ -231,6 +296,64 @@ class AppiumTransportFactory {
|
|
|
231
296
|
});
|
|
232
297
|
});
|
|
233
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* Waits out the Appium port and reports whether it went quiet, rather than
|
|
301
|
+
* throwing as {@link waitForAppiumStopped} does.
|
|
302
|
+
*
|
|
303
|
+
* @param url - The Appium server URL.
|
|
304
|
+
* @param timeoutInMilliseconds - How long to wait.
|
|
305
|
+
* @returns `true` when nothing answers on the port any more.
|
|
306
|
+
*/
|
|
307
|
+
async checkIsAppiumStopped(url, timeoutInMilliseconds) {
|
|
308
|
+
try {
|
|
309
|
+
await this.waitForAppiumStopped(url, timeoutInMilliseconds);
|
|
310
|
+
return true;
|
|
311
|
+
} catch {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Checks whether adb still lists the device **in any state**, without letting
|
|
317
|
+
* an adb that itself fails count as evidence.
|
|
318
|
+
*
|
|
319
|
+
* Any state, not just `device`: a dying emulator answers `offline` while it is
|
|
320
|
+
* still the thing that is wrong (the distinction `adb-device-list.ts` draws
|
|
321
|
+
* for teardown, and the reasoning carries over). Reading `offline` as gone
|
|
322
|
+
* here would report `device-gone` for what is really a wedge, sending the
|
|
323
|
+
* reader to look for a vanished emulator that is in fact still sitting there.
|
|
324
|
+
*
|
|
325
|
+
* @param deviceId - The device to look for.
|
|
326
|
+
* @returns `true` when it is listed; `false` when it is not, or adb could not be run.
|
|
327
|
+
*/
|
|
328
|
+
async checkIsDeviceListedQuietly(deviceId) {
|
|
329
|
+
try {
|
|
330
|
+
return checkIsDeviceListed({ deviceId, devicesOutput: await this.getDevicesOutput() });
|
|
331
|
+
} catch (error) {
|
|
332
|
+
this.log(`Could not re-check the device listing: ${error instanceof Error ? error.message : String(error)}`);
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Decides whether the emulator this run started is really gone.
|
|
338
|
+
*
|
|
339
|
+
* Two independent proofs, cheapest first: none of the PIDs this run owns is
|
|
340
|
+
* alive, and the device no longer appears in `adb devices` **in any state** (a
|
|
341
|
+
* dying emulator answers `offline` while it still holds the AVD).
|
|
342
|
+
*
|
|
343
|
+
* @param params - The device and the PIDs this run owns.
|
|
344
|
+
* @returns `true` when nothing of this run's emulator is left.
|
|
345
|
+
*/
|
|
346
|
+
async checkIsEmulatorGone(params) {
|
|
347
|
+
if (params.ownedEmulatorPids.some((pid) => checkIsProcessAlive(pid))) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
try {
|
|
351
|
+
return !checkIsDeviceListed({ deviceId: params.deviceId, devicesOutput: await this.getDevicesOutput() });
|
|
352
|
+
} catch (error) {
|
|
353
|
+
this.log(`Could not re-check connected devices while stopping the emulator: ${error instanceof Error ? error.message : String(error)}`);
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
234
357
|
async connectSession(params) {
|
|
235
358
|
const { remote } = await importWebdriverio();
|
|
236
359
|
return remote({
|
|
@@ -263,42 +386,66 @@ class AppiumTransportFactory {
|
|
|
263
386
|
throw new TypeError(`Invalid port in appiumUrl: ${url.port}`);
|
|
264
387
|
}
|
|
265
388
|
const appId = options.appId ?? APP_PACKAGE;
|
|
389
|
+
let actualDeviceId;
|
|
266
390
|
let appiumProcess;
|
|
267
391
|
let emulatorProcess;
|
|
392
|
+
let ownedEmulatorPids = [];
|
|
393
|
+
let result;
|
|
268
394
|
try {
|
|
269
|
-
let
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
395
|
+
for (let attempt = 1; attempt <= EMULATOR_BOOT_ATTEMPT_COUNT; attempt++) {
|
|
396
|
+
result = await this.startAppiumAndEmulator({
|
|
397
|
+
appiumStartTimeoutInMilliseconds: resolveAppiumStartTimeoutInMilliseconds(options),
|
|
398
|
+
appiumUrl: url,
|
|
399
|
+
avdName: options.avdName,
|
|
400
|
+
deviceIdleTimeoutInMilliseconds: resolveDeviceIdleTimeoutInMilliseconds(options),
|
|
401
|
+
isAppiumConsoleVisible: options.isAppiumConsoleVisible,
|
|
402
|
+
isEmulatorVisible: options.isEmulatorVisible,
|
|
403
|
+
networkReadyTimeoutInMilliseconds: resolveNetworkReadyTimeoutInMilliseconds(options),
|
|
404
|
+
port,
|
|
405
|
+
shouldAutoInstallAppiumDependencies: willAutoInstallAppiumDependencies(options),
|
|
406
|
+
shouldAutoStartAppium: options.shouldAutoStartAppium,
|
|
407
|
+
shouldReuseEmulatorSnapshot: options.shouldReuseEmulatorSnapshot
|
|
408
|
+
});
|
|
409
|
+
if (result.appiumProcess !== void 0) {
|
|
410
|
+
appiumProcess = result.appiumProcess;
|
|
274
411
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
412
|
+
emulatorProcess = result.emulatorProcess;
|
|
413
|
+
ownedEmulatorPids = result.ownedEmulatorPids;
|
|
414
|
+
actualDeviceId = result.actualDeviceId;
|
|
415
|
+
if (willSweepLeftovers(options)) {
|
|
416
|
+
await this.sweepDeviceLeftoverVaults({
|
|
417
|
+
deviceId: actualDeviceId,
|
|
418
|
+
vaultBasePath: options.vaultBasePath ?? DEFAULT_ANDROID_VAULT_BASE_PATH
|
|
419
|
+
});
|
|
278
420
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
await this.
|
|
297
|
-
|
|
298
|
-
|
|
421
|
+
const diagnosis = await this.diagnoseDevice(actualDeviceId, result.emulatorCapture);
|
|
422
|
+
if (diagnosis === void 0) {
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
const ownedEmulatorProcess = emulatorProcess;
|
|
426
|
+
const canRetry = attempt < EMULATOR_BOOT_ATTEMPT_COUNT && ownedEmulatorProcess !== void 0 && ownedEmulatorPids.length > 0;
|
|
427
|
+
if (!canRetry) {
|
|
428
|
+
throw new Error(diagnosis);
|
|
429
|
+
}
|
|
430
|
+
this.log(`${diagnosis}
|
|
431
|
+
|
|
432
|
+
Booting a fresh emulator and trying once more (attempt ${String(attempt + 1)} of ${String(EMULATOR_BOOT_ATTEMPT_COUNT)}).`);
|
|
433
|
+
const doomedDeviceId = actualDeviceId;
|
|
434
|
+
const doomedPids = ownedEmulatorPids;
|
|
435
|
+
emulatorProcess = void 0;
|
|
436
|
+
ownedEmulatorPids = [];
|
|
437
|
+
actualDeviceId = void 0;
|
|
438
|
+
await this.stopAutoStartedEmulator({
|
|
439
|
+
avdName: options.avdName,
|
|
440
|
+
deviceId: doomedDeviceId,
|
|
441
|
+
emulatorProcess: ownedEmulatorProcess,
|
|
442
|
+
ownedEmulatorPids: doomedPids
|
|
299
443
|
});
|
|
300
444
|
}
|
|
301
|
-
|
|
445
|
+
if (result === void 0 || actualDeviceId === void 0) {
|
|
446
|
+
throw new Error(`Could not provision an Android device for AVD "${options.avdName}".`);
|
|
447
|
+
}
|
|
448
|
+
const sessionResult = await this.establishSessionOrDiagnoseDevice(result.emulatorCapture, {
|
|
302
449
|
appId,
|
|
303
450
|
appiumServerMarker: result.appiumServerMarker,
|
|
304
451
|
appiumStartTimeoutInMilliseconds: resolveAppiumStartTimeoutInMilliseconds(options),
|
|
@@ -311,14 +458,18 @@ class AppiumTransportFactory {
|
|
|
311
458
|
url
|
|
312
459
|
});
|
|
313
460
|
const browser = sessionResult.browser;
|
|
314
|
-
|
|
461
|
+
if (sessionResult.appiumProcess !== void 0) {
|
|
462
|
+
appiumProcess = sessionResult.appiumProcess;
|
|
463
|
+
}
|
|
315
464
|
this.log("Appium session established.");
|
|
465
|
+
result.emulatorCapture?.stop();
|
|
316
466
|
const appiumTransport = new AppiumTransport({
|
|
317
467
|
appId,
|
|
318
468
|
browser,
|
|
319
469
|
deviceId: actualDeviceId,
|
|
320
470
|
platform: "android",
|
|
321
471
|
shouldSweepLeftovers: willSweepLeftovers(options),
|
|
472
|
+
...options.appStartTimeoutInMilliseconds !== void 0 && { appStartTimeoutInMilliseconds: options.appStartTimeoutInMilliseconds },
|
|
322
473
|
...options.layoutReadyTimeoutInMilliseconds !== void 0 && { layoutReadyTimeoutInMilliseconds: options.layoutReadyTimeoutInMilliseconds },
|
|
323
474
|
...options.vaultBasePath !== void 0 && { vaultBasePath: options.vaultBasePath },
|
|
324
475
|
...options.webviewTimeoutInMilliseconds !== void 0 && { webviewTimeoutInMilliseconds: options.webviewTimeoutInMilliseconds }
|
|
@@ -329,7 +480,7 @@ class AppiumTransportFactory {
|
|
|
329
480
|
try {
|
|
330
481
|
await originalDispose();
|
|
331
482
|
} finally {
|
|
332
|
-
|
|
483
|
+
await this.stopAutoStartedProcessesVerified(buildStopParams());
|
|
333
484
|
}
|
|
334
485
|
};
|
|
335
486
|
const originalDisposeSync = appiumTransport.disposeSync.bind(appiumTransport);
|
|
@@ -337,22 +488,25 @@ class AppiumTransportFactory {
|
|
|
337
488
|
try {
|
|
338
489
|
originalDisposeSync();
|
|
339
490
|
} finally {
|
|
340
|
-
|
|
491
|
+
this.stopAutoStartedProcessesBestEffort(buildStopParams());
|
|
341
492
|
}
|
|
342
493
|
};
|
|
343
494
|
return transport;
|
|
344
495
|
} catch (error) {
|
|
345
|
-
|
|
346
|
-
killProcessTree(appiumProcess);
|
|
347
|
-
clearAppiumServerMarker(port);
|
|
348
|
-
this.log("Killed auto-started Appium server after connection failure.");
|
|
349
|
-
}
|
|
350
|
-
if (emulatorProcess) {
|
|
351
|
-
killProcessTree(emulatorProcess);
|
|
352
|
-
this.log("Killed auto-started emulator after connection failure.");
|
|
353
|
-
}
|
|
496
|
+
await this.stopAutoStartedProcessesVerified(buildStopParams());
|
|
354
497
|
throw error;
|
|
355
498
|
}
|
|
499
|
+
function buildStopParams() {
|
|
500
|
+
return {
|
|
501
|
+
appiumProcess,
|
|
502
|
+
avdName: options.avdName,
|
|
503
|
+
deviceId: actualDeviceId,
|
|
504
|
+
emulatorProcess,
|
|
505
|
+
ownedEmulatorPids,
|
|
506
|
+
port,
|
|
507
|
+
url
|
|
508
|
+
};
|
|
509
|
+
}
|
|
356
510
|
}
|
|
357
511
|
/**
|
|
358
512
|
* Describes an adopted server's provenance for the preflight log, so a stale
|
|
@@ -367,7 +521,77 @@ class AppiumTransportFactory {
|
|
|
367
521
|
return "not started by this harness";
|
|
368
522
|
}
|
|
369
523
|
const ageInSeconds = Math.round((Date.now() - marker.startedAtInMilliseconds) / MILLISECONDS_PER_SECOND);
|
|
370
|
-
|
|
524
|
+
const unstoppedSuffix = marker.stopAttemptedAtInMilliseconds === void 0 ? "" : ", and an earlier run failed to stop it";
|
|
525
|
+
return `started by an earlier run of this harness, pid ${String(marker.pid)}, up for ${String(ageInSeconds)}s${unstoppedSuffix}`;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Probes the device and returns the failure message when it is no longer
|
|
529
|
+
* usable, or `undefined` when it is fine.
|
|
530
|
+
*
|
|
531
|
+
* The readiness gates that run before this one are deliberately best-effort —
|
|
532
|
+
* they warn and proceed — so nothing asked whether the device was still there
|
|
533
|
+
* at the moment it mattered. A guest that went quiet in the meantime was
|
|
534
|
+
* handed to Appium, which reported `Device <id> was not in the list of
|
|
535
|
+
* connected devices`; `adb devices` then listed it, and the trail went cold.
|
|
536
|
+
*
|
|
537
|
+
* The second probe is only paid for when the first one fails, and the verdict
|
|
538
|
+
* distinguishes a frozen guest from an unreachable emulator — see
|
|
539
|
+
* `emulator-liveness.ts` for the measurements behind that split.
|
|
540
|
+
*
|
|
541
|
+
* Returning the message rather than throwing it is what lets both callers use
|
|
542
|
+
* the same diagnosis: the provisioning loop decides whether to boot a fresh
|
|
543
|
+
* emulator, and the session path needs its own error to survive as the
|
|
544
|
+
* `cause`.
|
|
545
|
+
*
|
|
546
|
+
* @param deviceId - The device to probe.
|
|
547
|
+
* @param emulatorCapture - The emulator's output, when this run started it.
|
|
548
|
+
* @returns The diagnosis, or `undefined` when the device still answers.
|
|
549
|
+
*/
|
|
550
|
+
async diagnoseDevice(deviceId, emulatorCapture) {
|
|
551
|
+
const shellProbe = await this.probeDeviceShell(deviceId);
|
|
552
|
+
if (shellProbe === "answered") {
|
|
553
|
+
return void 0;
|
|
554
|
+
}
|
|
555
|
+
this.log(`Device ${deviceId} did not answer \`adb -s ${deviceId} shell\`; checking whether the emulator itself is still alive...`);
|
|
556
|
+
const [consoleProbe, isListedByAdb] = await Promise.all([
|
|
557
|
+
this.probeEmulatorConsole(deviceId),
|
|
558
|
+
this.checkIsDeviceListedQuietly(deviceId)
|
|
559
|
+
]);
|
|
560
|
+
const verdict = resolveEmulatorLivenessVerdict({
|
|
561
|
+
consoleProbe,
|
|
562
|
+
deviceId,
|
|
563
|
+
isListedByAdb,
|
|
564
|
+
shellProbe
|
|
565
|
+
});
|
|
566
|
+
this.log(`Device liveness: ${deviceId} shell=${shellProbe}, console=${consoleProbe} -> ${verdict}.`);
|
|
567
|
+
if (verdict === "alive") {
|
|
568
|
+
return void 0;
|
|
569
|
+
}
|
|
570
|
+
return buildEmulatorLivenessMessage({
|
|
571
|
+
deviceId,
|
|
572
|
+
emulatorOutput: emulatorCapture?.read() ?? "",
|
|
573
|
+
probeTimeoutInMilliseconds: DEVICE_LIVENESS_TIMEOUT_IN_MILLISECONDS,
|
|
574
|
+
verdict
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
dumpConnectivity(deviceId) {
|
|
578
|
+
return new Promise((resolve) => {
|
|
579
|
+
execFile(
|
|
580
|
+
"adb",
|
|
581
|
+
["-s", deviceId, "shell", "dumpsys", "connectivity"],
|
|
582
|
+
{ maxBuffer: ADB_DUMPSYS_MAX_BUFFER_IN_BYTES, timeout: ADB_DUMPSYS_TIMEOUT_IN_MILLISECONDS },
|
|
583
|
+
(error, stdout, stderr) => {
|
|
584
|
+
if (!error) {
|
|
585
|
+
resolve({ output: stdout });
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const detail = (stderr.trim() || error.message.trim()).split("\n", 1)[0] ?? "";
|
|
589
|
+
resolve({
|
|
590
|
+
failureReason: error.killed ? `no answer within ${String(ADB_DUMPSYS_TIMEOUT_IN_MILLISECONDS)}ms` : detail || "adb failed with no message"
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
);
|
|
594
|
+
});
|
|
371
595
|
}
|
|
372
596
|
/**
|
|
373
597
|
* Ensures the Appium toolchain is present before the server is auto-started:
|
|
@@ -425,7 +649,7 @@ class AppiumTransportFactory {
|
|
|
425
649
|
* @param avdName - The requested AVD name.
|
|
426
650
|
*/
|
|
427
651
|
async ensureAvdExists(avdName) {
|
|
428
|
-
const emulatorBinary =
|
|
652
|
+
const emulatorBinary = resolveEmulatorBinaryPath();
|
|
429
653
|
this.log(`Verifying AVD "${avdName}" exists (${emulatorBinary} -list-avds)...`);
|
|
430
654
|
const [error, stdout] = await new Promise((resolve) => {
|
|
431
655
|
execFile(emulatorBinary, ["-list-avds"], { timeout: EMULATOR_LIST_TIMEOUT_IN_MILLISECONDS }, (execError, execStdout) => {
|
|
@@ -446,27 +670,51 @@ class AppiumTransportFactory {
|
|
|
446
670
|
this.log(`AVD "${avdName}" exists.`);
|
|
447
671
|
}
|
|
448
672
|
async ensureDeviceConnected(params) {
|
|
449
|
-
const { avdName, deviceIdleTimeoutInMilliseconds, isEmulatorVisible } = params;
|
|
673
|
+
const { avdName, deviceIdleTimeoutInMilliseconds, isEmulatorVisible, networkReadyTimeoutInMilliseconds } = params;
|
|
674
|
+
const timeouts = { deviceIdleTimeoutInMilliseconds, networkReadyTimeoutInMilliseconds };
|
|
450
675
|
const deviceIdsBefore = await this.getConnectedDeviceIds();
|
|
451
676
|
this.log(`Checking existing devices for AVD "${avdName}"... (connected: [${deviceIdsBefore.join(", ")}])`);
|
|
452
|
-
const
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
677
|
+
const probeResults = await this.probeDevicesForAvd(avdName, deviceIdsBefore);
|
|
678
|
+
this.log(`AVD probe: ${buildAvdProbeSummary(probeResults)}.`);
|
|
679
|
+
const probeVerdict = resolveAvdProbeVerdict(probeResults);
|
|
680
|
+
switch (probeVerdict.verdict) {
|
|
681
|
+
case "refuse": {
|
|
682
|
+
throw new Error(buildUnreadableDevicesMessage({
|
|
683
|
+
avdName,
|
|
684
|
+
probeTimeoutInMilliseconds: ADB_DEVICE_CHECK_TIMEOUT_IN_MILLISECONDS,
|
|
685
|
+
unreadableDeviceIds: probeVerdict.unreadableDeviceIds
|
|
686
|
+
}));
|
|
687
|
+
}
|
|
688
|
+
case "reuse": {
|
|
689
|
+
return await this.reuseConnectedDevice(avdName, probeVerdict.deviceId, timeouts);
|
|
690
|
+
}
|
|
691
|
+
case "start-new": {
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
default: {
|
|
695
|
+
return assertNever(probeVerdict);
|
|
696
|
+
}
|
|
457
697
|
}
|
|
458
698
|
this.log(`AVD "${avdName}" not found on any existing device, starting a new emulator...`);
|
|
459
699
|
await this.ensureAvdExists(avdName);
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
} finally {
|
|
465
|
-
emulator.stopCapture();
|
|
700
|
+
const emulatorPidsBefore = await this.listEmulatorBackendPids([]);
|
|
701
|
+
const shouldReuseSnapshot = params.shouldReuseEmulatorSnapshot === true;
|
|
702
|
+
if (shouldReuseSnapshot) {
|
|
703
|
+
this.logSnapshotAge(avdName);
|
|
466
704
|
}
|
|
467
|
-
this.
|
|
705
|
+
const emulator = this.startEmulator(avdName, shouldReuseSnapshot, isEmulatorVisible);
|
|
706
|
+
const actualDeviceId = await this.waitForNewDevice(deviceIdsBefore, emulator, timeouts);
|
|
707
|
+
const ownedEmulatorPids = await this.listEmulatorBackendPids(emulatorPidsBefore);
|
|
708
|
+
this.log(
|
|
709
|
+
`Emulator "${avdName}" started, device ${actualDeviceId} is connected (owned emulator PIDs: [${ownedEmulatorPids.join(", ")}]).`
|
|
710
|
+
);
|
|
468
711
|
await this.suppressErrorDialogs(actualDeviceId);
|
|
469
|
-
return {
|
|
712
|
+
return {
|
|
713
|
+
actualDeviceId,
|
|
714
|
+
emulatorCapture: { read: emulator.readOutput, stop: emulator.stopCapture },
|
|
715
|
+
emulatorProcess: emulator.process,
|
|
716
|
+
ownedEmulatorPids
|
|
717
|
+
};
|
|
470
718
|
}
|
|
471
719
|
async ensureUiautomator2DriverInstalled() {
|
|
472
720
|
this.log(`Checking whether the ${UIAUTOMATOR2_DRIVER_NAME} driver is installed...`);
|
|
@@ -518,39 +766,37 @@ class AppiumTransportFactory {
|
|
|
518
766
|
return await this.restartWedgedServerAndRetry(params, error);
|
|
519
767
|
}
|
|
520
768
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
769
|
+
/**
|
|
770
|
+
* Establishes the session, and when that fails, asks the device whether it is
|
|
771
|
+
* still there before letting the failure stand.
|
|
772
|
+
*
|
|
773
|
+
* `establishSession` owns exactly one diagnosis — the stale Appium server —
|
|
774
|
+
* and rethrows everything else untouched. That is right as far as it goes, but
|
|
775
|
+
* every signature this harness actually fails with on a wedged emulator falls
|
|
776
|
+
* into "everything else": `Device <id> was not in the list of connected
|
|
777
|
+
* devices`, `error: closed`, and a bare `POST /session` timeout. Rather than
|
|
778
|
+
* teaching the server module to recognize error strings that are not about the
|
|
779
|
+
* server, the device is simply re-probed here, where the device is known. A
|
|
780
|
+
* wedged emulator then reports itself, and the original error is kept as the
|
|
781
|
+
* `cause`.
|
|
782
|
+
*
|
|
783
|
+
* @param emulatorCapture - The emulator's output, when this run started it.
|
|
784
|
+
* @param params - The session parameters.
|
|
785
|
+
* @returns The established session.
|
|
786
|
+
*/
|
|
787
|
+
async establishSessionOrDiagnoseDevice(emulatorCapture, params) {
|
|
788
|
+
try {
|
|
789
|
+
return await this.establishSession(params);
|
|
790
|
+
} catch (error) {
|
|
791
|
+
const diagnosis = await this.diagnoseDevice(params.deviceId, emulatorCapture);
|
|
792
|
+
if (diagnosis === void 0) {
|
|
793
|
+
throw error;
|
|
535
794
|
}
|
|
795
|
+
throw new Error(diagnosis, { cause: error });
|
|
536
796
|
}
|
|
537
|
-
return void 0;
|
|
538
797
|
}
|
|
539
798
|
async getConnectedDeviceIds() {
|
|
540
|
-
|
|
541
|
-
execFile("adb", ["devices"], { timeout: ADB_DEVICE_CHECK_TIMEOUT_IN_MILLISECONDS }, (error, stdout, stderr) => {
|
|
542
|
-
if (error) {
|
|
543
|
-
reject(new Error(`Failed to run 'adb devices': ${error.message}. Is ADB installed and in PATH?`));
|
|
544
|
-
return;
|
|
545
|
-
}
|
|
546
|
-
if (stderr) {
|
|
547
|
-
this.log(`ADB stderr: ${stderr.trim()}`);
|
|
548
|
-
}
|
|
549
|
-
resolve(stdout);
|
|
550
|
-
});
|
|
551
|
-
});
|
|
552
|
-
const lines = output.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
553
|
-
return lines.filter((line) => line.includes(" device")).map((line) => line.split(" ", 1)[0] ?? "");
|
|
799
|
+
return listOnlineDeviceIds(await this.getDevicesOutput());
|
|
554
800
|
}
|
|
555
801
|
/**
|
|
556
802
|
* Lists the host's connected devices for the wedged-server cross-check, where
|
|
@@ -578,6 +824,99 @@ class AppiumTransportFactory {
|
|
|
578
824
|
);
|
|
579
825
|
});
|
|
580
826
|
}
|
|
827
|
+
/**
|
|
828
|
+
* Runs `adb devices` and returns its raw stdout.
|
|
829
|
+
*
|
|
830
|
+
* The raw listing is what teardown needs: `getConnectedDeviceIds` keeps only
|
|
831
|
+
* the `device` state, and an emulator on its way out answers `offline` while
|
|
832
|
+
* still holding the AVD — see `adb-device-list.ts`.
|
|
833
|
+
*
|
|
834
|
+
* @returns The raw `adb devices` output.
|
|
835
|
+
* @throws If adb could not be run at all.
|
|
836
|
+
*/
|
|
837
|
+
getDevicesOutput() {
|
|
838
|
+
return new Promise((resolve, reject) => {
|
|
839
|
+
execFile("adb", ["devices"], { timeout: ADB_DEVICE_CHECK_TIMEOUT_IN_MILLISECONDS }, (error, stdout, stderr) => {
|
|
840
|
+
if (error) {
|
|
841
|
+
reject(new Error(`Failed to run 'adb devices': ${error.message}. Is ADB installed and in PATH?`));
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
if (stderr) {
|
|
845
|
+
this.log(`ADB stderr: ${stderr.trim()}`);
|
|
846
|
+
}
|
|
847
|
+
resolve(stdout);
|
|
848
|
+
});
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Asks the emulator to shut itself down over its console.
|
|
853
|
+
*
|
|
854
|
+
* Preferred over killing the process outright because it is the path that
|
|
855
|
+
* releases the AVD's `multiinstance.lock`. Best-effort: a console that does
|
|
856
|
+
* not answer is reported and the caller falls through to the kill.
|
|
857
|
+
*
|
|
858
|
+
* @param deviceId - The emulator's device ID.
|
|
859
|
+
*/
|
|
860
|
+
killEmulatorConsole(deviceId) {
|
|
861
|
+
return new Promise((resolve) => {
|
|
862
|
+
execFile("adb", ["-s", deviceId, "emu", "kill"], { timeout: ADB_DEVICE_CHECK_TIMEOUT_IN_MILLISECONDS }, (error, stdout) => {
|
|
863
|
+
this.log(
|
|
864
|
+
error ? `Emulator console shutdown for ${deviceId} did not answer: ${error.message}` : `Emulator console shutdown for ${deviceId}: ${stdout.trim()}`
|
|
865
|
+
);
|
|
866
|
+
resolve();
|
|
867
|
+
});
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Lists the emulator processes currently running on the host, excluding a set
|
|
872
|
+
* that is already accounted for.
|
|
873
|
+
*
|
|
874
|
+
* Called twice around a launch: with an empty `knownPids` to snapshot what
|
|
875
|
+
* predates it, then with that snapshot to name what the launch added — which
|
|
876
|
+
* is precisely the set this run owns.
|
|
877
|
+
*
|
|
878
|
+
* Best-effort: a listing that cannot be produced yields no PIDs, so an
|
|
879
|
+
* unavailable `tasklist`/`ps` degrades to "nothing to escalate to" rather than
|
|
880
|
+
* failing the run it is cleaning up for. **It says so, loudly** — an empty set
|
|
881
|
+
* that means "no backend to own" and one that means "the query failed" are
|
|
882
|
+
* otherwise the same log line, and the second silently disarms the escalation.
|
|
883
|
+
* That is not hypothetical: the first end-to-end run of this code logged
|
|
884
|
+
* `owned emulator PIDs: []` for a launch whose backend was demonstrably there,
|
|
885
|
+
* because `tasklist` overran a 10s budget on a host the wedged emulator had
|
|
886
|
+
* already slowed to the point where every `adb` call was timing out too — the
|
|
887
|
+
* same contention **L45** sizes `ADB_DUMPSYS_TIMEOUT_IN_MILLISECONDS` for, and
|
|
888
|
+
* the same "wrong budget silently disables the check" shape.
|
|
889
|
+
*
|
|
890
|
+
* A host always has processes, so a listing that parses to **zero** rows is a
|
|
891
|
+
* failed query however it exited, and is reported like one.
|
|
892
|
+
*
|
|
893
|
+
* @param knownPids - Emulator PIDs to exclude.
|
|
894
|
+
* @returns The emulator PIDs not in `knownPids`.
|
|
895
|
+
*/
|
|
896
|
+
async listEmulatorBackendPids(knownPids) {
|
|
897
|
+
const query = buildHostProcessQuery();
|
|
898
|
+
const output = await new Promise((resolve) => {
|
|
899
|
+
execFile(
|
|
900
|
+
query.command,
|
|
901
|
+
query.commandArguments,
|
|
902
|
+
{ maxBuffer: ADB_DUMPSYS_MAX_BUFFER_IN_BYTES, timeout: HOST_PROCESS_QUERY_TIMEOUT_IN_MILLISECONDS },
|
|
903
|
+
(error, stdout) => {
|
|
904
|
+
if (error) {
|
|
905
|
+
this.log(`Warning: could not list host processes (\`${query.command}\`): ${error.message}`);
|
|
906
|
+
}
|
|
907
|
+
resolve(error ? "" : stdout);
|
|
908
|
+
}
|
|
909
|
+
);
|
|
910
|
+
});
|
|
911
|
+
const processes = parseHostProcessList(output);
|
|
912
|
+
if (processes.length === 0) {
|
|
913
|
+
this.log(
|
|
914
|
+
`Warning: \`${query.command}\` listed no processes, so this run cannot identify the emulator backend it owns. Teardown will fall back to \`adb devices\` alone and will have no PID to escalate to.`
|
|
915
|
+
);
|
|
916
|
+
return [];
|
|
917
|
+
}
|
|
918
|
+
return selectEmulatorBackendPids({ knownPids, processes });
|
|
919
|
+
}
|
|
581
920
|
listInstalledPackages(deviceId) {
|
|
582
921
|
return new Promise((resolve) => {
|
|
583
922
|
execFile(
|
|
@@ -590,17 +929,185 @@ class AppiumTransportFactory {
|
|
|
590
929
|
);
|
|
591
930
|
});
|
|
592
931
|
}
|
|
932
|
+
/**
|
|
933
|
+
* Finds the processes still listening on a port.
|
|
934
|
+
*
|
|
935
|
+
* This is the only real escalation available for the Appium server: the PID
|
|
936
|
+
* the harness holds is the shell wrapper it spawned, so re-killing it achieves
|
|
937
|
+
* nothing, while a socket still answering on the port is direct evidence of
|
|
938
|
+
* what survived.
|
|
939
|
+
*
|
|
940
|
+
* @param port - The port to query.
|
|
941
|
+
* @returns The listening PIDs, or an empty list when the query could not be run.
|
|
942
|
+
*/
|
|
943
|
+
listPortOwnerPids(port) {
|
|
944
|
+
const query = buildPortOwnerQuery(port);
|
|
945
|
+
return new Promise((resolve) => {
|
|
946
|
+
execFile(
|
|
947
|
+
query.command,
|
|
948
|
+
query.commandArguments,
|
|
949
|
+
{ maxBuffer: ADB_DUMPSYS_MAX_BUFFER_IN_BYTES, timeout: HOST_PROCESS_QUERY_TIMEOUT_IN_MILLISECONDS },
|
|
950
|
+
(error, stdout) => {
|
|
951
|
+
resolve(parsePortOwnerPids({ output: error ? "" : stdout, port }));
|
|
952
|
+
}
|
|
953
|
+
);
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* Synchronous {@link listPortOwnerPids}, for the `process.on('exit')` teardown
|
|
958
|
+
* that cannot await.
|
|
959
|
+
*
|
|
960
|
+
* Its budget is deliberately **not** the async path's: this call blocks process
|
|
961
|
+
* exit outright, so it takes a short one and gives up rather than holding the
|
|
962
|
+
* exit handler for half a minute on a contended host. Giving up loses the
|
|
963
|
+
* escalation, which the sync path's log already admits it cannot confirm.
|
|
964
|
+
*
|
|
965
|
+
* @param port - The port to query.
|
|
966
|
+
* @returns The listening PIDs, or an empty list when the query could not be run in time.
|
|
967
|
+
*/
|
|
968
|
+
listPortOwnerPidsSync(port) {
|
|
969
|
+
const query = buildPortOwnerQuery(port);
|
|
970
|
+
try {
|
|
971
|
+
const output = execFileSync(query.command, query.commandArguments, {
|
|
972
|
+
encoding: "utf-8",
|
|
973
|
+
maxBuffer: ADB_DUMPSYS_MAX_BUFFER_IN_BYTES,
|
|
974
|
+
timeout: SYNC_TEARDOWN_QUERY_TIMEOUT_IN_MILLISECONDS
|
|
975
|
+
});
|
|
976
|
+
return parsePortOwnerPids({ output, port });
|
|
977
|
+
} catch {
|
|
978
|
+
return [];
|
|
979
|
+
}
|
|
980
|
+
}
|
|
593
981
|
log(message) {
|
|
594
982
|
log(`[transport-factory:${this.type}] ${message}`);
|
|
595
983
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
984
|
+
/**
|
|
985
|
+
* Logs how old the snapshot a run has opted into resuming is.
|
|
986
|
+
*
|
|
987
|
+
* Best-effort: a missing snapshot is the normal state of a fresh AVD, not a
|
|
988
|
+
* failure, and this is a diagnostic rather than a gate.
|
|
989
|
+
*
|
|
990
|
+
* @param avdName - The AVD whose snapshot is about to be resumed.
|
|
991
|
+
*/
|
|
992
|
+
logSnapshotAge(avdName) {
|
|
993
|
+
let savedAt;
|
|
994
|
+
for (const candidate of buildAvdSnapshotDirectoryCandidates({ avdName, environment: process.env, homeDirectory: homedir() })) {
|
|
995
|
+
try {
|
|
996
|
+
savedAt = statSync(candidate).mtime;
|
|
997
|
+
break;
|
|
998
|
+
} catch {
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
this.log(buildSnapshotAgeMessage({ avdName, savedAt }));
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Reads one emulator's AVD name from its console, retrying once.
|
|
1005
|
+
*
|
|
1006
|
+
* The retry is what makes the refusal proportionate: the probe's whole budget
|
|
1007
|
+
* is 5s, and a second look costs less than a colliding launch does. What it
|
|
1008
|
+
* must never do is report a non-answer as an answer — the discarded `_error`
|
|
1009
|
+
* this replaces resolved `''`, which compared unequal to the wanted AVD and so
|
|
1010
|
+
* read as a definite "some other AVD".
|
|
1011
|
+
*
|
|
1012
|
+
* @param deviceId - The emulator to ask.
|
|
1013
|
+
* @returns The AVD name it answered, or `undefined` when it did not answer.
|
|
1014
|
+
*/
|
|
1015
|
+
async probeAvdName(deviceId) {
|
|
1016
|
+
for (let attempt = 1; attempt <= AVD_PROBE_ATTEMPT_COUNT; attempt++) {
|
|
1017
|
+
const answer = await new Promise((resolve) => {
|
|
1018
|
+
execFile(
|
|
1019
|
+
"adb",
|
|
1020
|
+
["-s", deviceId, "emu", "avd", "name"],
|
|
1021
|
+
{ timeout: ADB_DEVICE_CHECK_TIMEOUT_IN_MILLISECONDS },
|
|
1022
|
+
(error, stdout) => {
|
|
1023
|
+
resolve(error ? void 0 : stdout.split("\n", 1)[0]?.trim());
|
|
1024
|
+
}
|
|
1025
|
+
);
|
|
1026
|
+
});
|
|
1027
|
+
if (answer !== void 0 && answer.length > 0) {
|
|
1028
|
+
return answer;
|
|
1029
|
+
}
|
|
1030
|
+
if (attempt < AVD_PROBE_ATTEMPT_COUNT) {
|
|
1031
|
+
this.log(
|
|
1032
|
+
`Device ${deviceId} did not answer \`adb -s ${deviceId} emu avd name\` within ${String(ADB_DEVICE_CHECK_TIMEOUT_IN_MILLISECONDS)}ms; retrying once.`
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
return void 0;
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1039
|
+
* Asks every connected device which AVD it is serving.
|
|
1040
|
+
*
|
|
1041
|
+
* A device that is not a locally started emulator is never asked: its console
|
|
1042
|
+
* cannot answer however healthy it is, and reading that as silence would
|
|
1043
|
+
* refuse every run on a host with a handset plugged in — see
|
|
1044
|
+
* `avd-probe-verdict.ts`.
|
|
1045
|
+
*
|
|
1046
|
+
* @param avdName - The AVD the run wants.
|
|
1047
|
+
* @param deviceIds - The connected devices.
|
|
1048
|
+
* @returns One outcome per device, in listed order.
|
|
1049
|
+
*/
|
|
1050
|
+
async probeDevicesForAvd(avdName, deviceIds) {
|
|
1051
|
+
const results = [];
|
|
1052
|
+
for (const deviceId of deviceIds) {
|
|
1053
|
+
const probedAvdName = checkIsEmulatorDeviceId(deviceId) ? await this.probeAvdName(deviceId) : void 0;
|
|
1054
|
+
results.push({ deviceId, outcome: classifyAvdProbe({ avdName, deviceId, probedAvdName }) });
|
|
1055
|
+
}
|
|
1056
|
+
return results;
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Asks the **guest** whether it is still scheduling work, via `adbd`.
|
|
1060
|
+
*
|
|
1061
|
+
* @param deviceId - The device to probe.
|
|
1062
|
+
* @returns What it answered.
|
|
1063
|
+
*/
|
|
1064
|
+
probeDeviceShell(deviceId) {
|
|
1065
|
+
return this.runLivenessProbe(["-s", deviceId, "shell", "true"]);
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Asks the **emulator process** whether it is still running, via its console.
|
|
1069
|
+
*
|
|
1070
|
+
* The console is served by the emulator itself rather than by the guest, which
|
|
1071
|
+
* is what makes it able to tell a frozen guest from a wedged emulator.
|
|
1072
|
+
*
|
|
1073
|
+
* @param deviceId - The device to probe.
|
|
1074
|
+
* @returns What it answered.
|
|
1075
|
+
*/
|
|
1076
|
+
probeEmulatorConsole(deviceId) {
|
|
1077
|
+
return this.runLivenessProbe(["-s", deviceId, "emu", "avd", "status"]);
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Replaces a leftover server an earlier run failed to stop, instead of
|
|
1081
|
+
* adopting it.
|
|
1082
|
+
*
|
|
1083
|
+
* This is the other half of {@link stopAutoStartedAppiumServer}'s stamped
|
|
1084
|
+
* marker, and it is the case that motivated the whole verified teardown: the
|
|
1085
|
+
* leftover answers `/status` perfectly, is adopted, and then dies seconds into the session as
|
|
1086
|
+
* it finally finishes shutting down — a failure that reads as a device or
|
|
1087
|
+
* network fault. A server we know we already asked to die is not a server to
|
|
1088
|
+
* build a suite on.
|
|
1089
|
+
*
|
|
1090
|
+
* @param params - The marker, the port and whether a replacement may be started.
|
|
1091
|
+
* @returns `true` when the port was freed and a fresh server must be started.
|
|
1092
|
+
*/
|
|
1093
|
+
async reclaimUnstoppedAppiumServer(params) {
|
|
1094
|
+
const stopAttemptedAtInMilliseconds = params.marker.stopAttemptedAtInMilliseconds ?? Date.now();
|
|
1095
|
+
const ageInSeconds = Math.round((Date.now() - stopAttemptedAtInMilliseconds) / MILLISECONDS_PER_SECOND);
|
|
1096
|
+
const provenance = `the server on port ${String(params.port)} is a leftover an earlier run of this harness tried to stop ${String(ageInSeconds)}s ago and could not`;
|
|
1097
|
+
if (params.shouldAutoStartAppium === false) {
|
|
1098
|
+
this.log(`WARNING: ${provenance}. Auto-start is disabled, so this run adopts it anyway; if the session dies mid-flight, that is why.`);
|
|
1099
|
+
return false;
|
|
1100
|
+
}
|
|
1101
|
+
this.log(`Refusing to adopt a known-doomed server: ${provenance}. Killing whatever holds the port and starting a fresh server...`);
|
|
1102
|
+
for (const pid of await this.listPortOwnerPids(params.port)) {
|
|
1103
|
+
killProcessTreeByPid(pid);
|
|
1104
|
+
}
|
|
1105
|
+
clearAppiumServerMarker(params.port);
|
|
1106
|
+
if (await this.checkIsAppiumStopped(params.url, APPIUM_ESCALATED_STOP_TIMEOUT_IN_MILLISECONDS)) {
|
|
1107
|
+
return true;
|
|
602
1108
|
}
|
|
603
|
-
|
|
1109
|
+
this.log(`WARNING: ${provenance}, and it survived this run's kill too. Adopting it, which may fail mid-session.`);
|
|
1110
|
+
return false;
|
|
604
1111
|
}
|
|
605
1112
|
/**
|
|
606
1113
|
* Replaces a wedged server this harness started earlier and retries the
|
|
@@ -623,7 +1130,7 @@ class AppiumTransportFactory {
|
|
|
623
1130
|
killProcessTreeByPid(marker.pid);
|
|
624
1131
|
clearAppiumServerMarker(params.port);
|
|
625
1132
|
try {
|
|
626
|
-
await this.waitForAppiumStopped(params.url);
|
|
1133
|
+
await this.waitForAppiumStopped(params.url, APPIUM_STOP_TIMEOUT_IN_MILLISECONDS);
|
|
627
1134
|
} catch (error) {
|
|
628
1135
|
throw new Error(this.buildWedgedMessage(params, "restart-did-not-help"), { cause: error });
|
|
629
1136
|
}
|
|
@@ -638,6 +1145,48 @@ class AppiumTransportFactory {
|
|
|
638
1145
|
throw new Error(this.buildWedgedMessage(params, "restart-did-not-help"), { cause: error });
|
|
639
1146
|
}
|
|
640
1147
|
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Adopts a device already serving the requested AVD.
|
|
1150
|
+
*
|
|
1151
|
+
* @param avdName - The AVD it is serving.
|
|
1152
|
+
* @param deviceId - The device to adopt.
|
|
1153
|
+
* @param timeouts - The two post-boot readiness budgets.
|
|
1154
|
+
* @returns The adopted device, owning no emulator PIDs.
|
|
1155
|
+
*/
|
|
1156
|
+
async reuseConnectedDevice(avdName, deviceId, timeouts) {
|
|
1157
|
+
this.log(`AVD "${avdName}" is already running on device ${deviceId}, reusing.`);
|
|
1158
|
+
await this.suppressErrorDialogs(deviceId);
|
|
1159
|
+
await this.waitForBoot(deviceId, Date.now() + EMULATOR_BOOT_TIMEOUT_IN_MILLISECONDS, void 0);
|
|
1160
|
+
await this.waitForDeviceReady(deviceId, timeouts);
|
|
1161
|
+
await this.wakeScreen(deviceId);
|
|
1162
|
+
return { actualDeviceId: deviceId, ownedEmulatorPids: [] };
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Runs one liveness probe, retrying once before calling it silence.
|
|
1166
|
+
*
|
|
1167
|
+
* Only success counts as an answer: a failed `adb ... emu` may be the adb
|
|
1168
|
+
* server refusing an `offline` device rather than the console being dead, and
|
|
1169
|
+
* the two are indistinguishable from here (see `emulator-liveness.ts`). The
|
|
1170
|
+
* single retry is the same restraint `probeAvdName` applies for the same
|
|
1171
|
+
* reason — a second look is far cheaper than a wrong verdict, and this one
|
|
1172
|
+
* decides whether a run is aborted.
|
|
1173
|
+
*
|
|
1174
|
+
* @param input - The adb arguments.
|
|
1175
|
+
* @returns Whether the probe got an answer.
|
|
1176
|
+
*/
|
|
1177
|
+
async runLivenessProbe(input) {
|
|
1178
|
+
for (let attempt = 1; attempt <= DEVICE_LIVENESS_ATTEMPT_COUNT; attempt++) {
|
|
1179
|
+
const isAnswered = await new Promise((resolve) => {
|
|
1180
|
+
execFile("adb", [...input], { timeout: DEVICE_LIVENESS_TIMEOUT_IN_MILLISECONDS }, (error) => {
|
|
1181
|
+
resolve(!error);
|
|
1182
|
+
});
|
|
1183
|
+
});
|
|
1184
|
+
if (isAnswered) {
|
|
1185
|
+
return "answered";
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
return "no-answer";
|
|
1189
|
+
}
|
|
641
1190
|
async sendKeyEvent(deviceId, keyCode, description) {
|
|
642
1191
|
await new Promise((resolve) => {
|
|
643
1192
|
execFile(
|
|
@@ -656,7 +1205,7 @@ class AppiumTransportFactory {
|
|
|
656
1205
|
});
|
|
657
1206
|
}
|
|
658
1207
|
async startAppiumAndEmulator(params) {
|
|
659
|
-
const { appiumStartTimeoutInMilliseconds, appiumUrl, avdName, deviceIdleTimeoutInMilliseconds, isAppiumConsoleVisible, isEmulatorVisible, port, shouldAutoInstallAppiumDependencies, shouldAutoStartAppium } = params;
|
|
1208
|
+
const { appiumStartTimeoutInMilliseconds, appiumUrl, avdName, deviceIdleTimeoutInMilliseconds, isAppiumConsoleVisible, isEmulatorVisible, networkReadyTimeoutInMilliseconds, port, shouldAutoInstallAppiumDependencies, shouldAutoStartAppium, shouldReuseEmulatorSnapshot } = params;
|
|
660
1209
|
let needsAppiumStart = false;
|
|
661
1210
|
let appiumServerMarker;
|
|
662
1211
|
this.log(`Checking Appium server at ${appiumUrl.href}...`);
|
|
@@ -664,6 +1213,17 @@ class AppiumTransportFactory {
|
|
|
664
1213
|
await this.checkAppiumReachable(appiumUrl);
|
|
665
1214
|
appiumServerMarker = readAppiumServerMarker(port);
|
|
666
1215
|
this.log(`Appium server is reachable (${this.describeAdoptedServer(appiumServerMarker)}).`);
|
|
1216
|
+
if (appiumServerMarker?.stopAttemptedAtInMilliseconds !== void 0) {
|
|
1217
|
+
needsAppiumStart = await this.reclaimUnstoppedAppiumServer({
|
|
1218
|
+
marker: appiumServerMarker,
|
|
1219
|
+
port,
|
|
1220
|
+
shouldAutoStartAppium,
|
|
1221
|
+
url: appiumUrl
|
|
1222
|
+
});
|
|
1223
|
+
if (needsAppiumStart) {
|
|
1224
|
+
appiumServerMarker = void 0;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
667
1227
|
} catch (error) {
|
|
668
1228
|
if (shouldAutoStartAppium === false) {
|
|
669
1229
|
throw error;
|
|
@@ -679,27 +1239,34 @@ class AppiumTransportFactory {
|
|
|
679
1239
|
appiumLaunch = this.startAppiumServer(port, isAppiumConsoleVisible);
|
|
680
1240
|
}
|
|
681
1241
|
const appiumProcess = appiumLaunch?.process;
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
1242
|
+
const [appiumOutcome, deviceOutcome] = await Promise.allSettled([
|
|
1243
|
+
appiumLaunch ? this.waitForAppiumReady(appiumUrl, appiumStartTimeoutInMilliseconds, appiumLaunch).then(() => {
|
|
1244
|
+
this.log("Auto-started Appium server is ready.");
|
|
1245
|
+
}) : Promise.resolve(),
|
|
1246
|
+
this.ensureDeviceConnected({ avdName, deviceIdleTimeoutInMilliseconds, isEmulatorVisible, networkReadyTimeoutInMilliseconds, shouldReuseEmulatorSnapshot })
|
|
1247
|
+
]);
|
|
1248
|
+
const deviceResult = deviceOutcome.status === "fulfilled" ? deviceOutcome.value : void 0;
|
|
1249
|
+
if (appiumOutcome.status === "rejected" || deviceResult === void 0) {
|
|
1250
|
+
await this.stopAutoStartedProcessesVerified({
|
|
691
1251
|
appiumProcess,
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
}
|
|
701
|
-
throw error;
|
|
1252
|
+
avdName,
|
|
1253
|
+
deviceId: deviceResult?.actualDeviceId,
|
|
1254
|
+
emulatorProcess: deviceResult?.emulatorProcess,
|
|
1255
|
+
ownedEmulatorPids: deviceResult?.ownedEmulatorPids ?? [],
|
|
1256
|
+
port,
|
|
1257
|
+
url: appiumUrl
|
|
1258
|
+
});
|
|
1259
|
+
throw getSettledFailure([appiumOutcome, deviceOutcome]);
|
|
702
1260
|
}
|
|
1261
|
+
return {
|
|
1262
|
+
actualDeviceId: deviceResult.actualDeviceId,
|
|
1263
|
+
appiumProcess,
|
|
1264
|
+
appiumServerMarker,
|
|
1265
|
+
emulatorCapture: deviceResult.emulatorCapture,
|
|
1266
|
+
emulatorProcess: deviceResult.emulatorProcess,
|
|
1267
|
+
isAdoptedAppiumServer: !needsAppiumStart,
|
|
1268
|
+
ownedEmulatorPids: deviceResult.ownedEmulatorPids
|
|
1269
|
+
};
|
|
703
1270
|
}
|
|
704
1271
|
startAppiumServer(port, isAppiumConsoleVisible) {
|
|
705
1272
|
const isConsoleHidden = shouldHideAppiumConsole(isAppiumConsoleVisible);
|
|
@@ -740,10 +1307,10 @@ class AppiumTransportFactory {
|
|
|
740
1307
|
capturedOutput = (capturedOutput + chunk.toString()).slice(-APPIUM_OUTPUT_TAIL_MAX_LENGTH);
|
|
741
1308
|
}
|
|
742
1309
|
}
|
|
743
|
-
startEmulator(avdName, isEmulatorVisible) {
|
|
744
|
-
const emulatorBinary =
|
|
1310
|
+
startEmulator(avdName, shouldReuseSnapshot, isEmulatorVisible) {
|
|
1311
|
+
const emulatorBinary = resolveEmulatorBinaryPath();
|
|
745
1312
|
const isWindowHidden = shouldHideEmulatorWindow(isEmulatorVisible);
|
|
746
|
-
const input = buildEmulatorArguments({ avdName, isHidden: isWindowHidden });
|
|
1313
|
+
const input = buildEmulatorArguments({ avdName, isHidden: isWindowHidden, shouldReuseSnapshot });
|
|
747
1314
|
const { detached, windowsHide } = resolveEmulatorSpawnFlags(isWindowHidden);
|
|
748
1315
|
this.log(`Running: ${emulatorBinary} ${input.join(" ")}`);
|
|
749
1316
|
const child = spawn(emulatorBinary, input, {
|
|
@@ -798,6 +1365,150 @@ class AppiumTransportFactory {
|
|
|
798
1365
|
*
|
|
799
1366
|
* @param deviceId - The device UDID to configure.
|
|
800
1367
|
*/
|
|
1368
|
+
/**
|
|
1369
|
+
* Stops the Appium server this run started, and **verifies** it stopped.
|
|
1370
|
+
*
|
|
1371
|
+
* The port is the verdict: a socket still answering `/status` after the kill
|
|
1372
|
+
* is the server, whatever the PID table says. When it is still there the
|
|
1373
|
+
* listener is killed by port ownership — the only escalation that means
|
|
1374
|
+
* anything, since re-killing the shell wrapper's PID would just repeat the
|
|
1375
|
+
* kill that already failed.
|
|
1376
|
+
*
|
|
1377
|
+
* @param params - The server process, its port and its URL.
|
|
1378
|
+
*/
|
|
1379
|
+
async stopAutoStartedAppiumServer(params) {
|
|
1380
|
+
killProcessTree(params.appiumProcess);
|
|
1381
|
+
let hasEscalated = false;
|
|
1382
|
+
let isStopped = await this.checkIsAppiumStopped(params.url, APPIUM_STOP_TIMEOUT_IN_MILLISECONDS);
|
|
1383
|
+
if (!isStopped) {
|
|
1384
|
+
const ownerPids = await this.listPortOwnerPids(params.port);
|
|
1385
|
+
if (ownerPids.length > 0) {
|
|
1386
|
+
hasEscalated = true;
|
|
1387
|
+
this.log(
|
|
1388
|
+
`Auto-started Appium server still answers on ${params.url.origin} after its process tree was killed; escalating to the PID(s) holding the port: [${ownerPids.join(", ")}].`
|
|
1389
|
+
);
|
|
1390
|
+
for (const pid of ownerPids) {
|
|
1391
|
+
killProcessTreeByPid(pid);
|
|
1392
|
+
}
|
|
1393
|
+
isStopped = await this.checkIsAppiumStopped(params.url, APPIUM_ESCALATED_STOP_TIMEOUT_IN_MILLISECONDS);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
this.log(buildTeardownMessage({
|
|
1397
|
+
evidence: `port ${String(params.port)}`,
|
|
1398
|
+
outcome: resolveTeardownOutcome({ hasEscalated, isStopped }),
|
|
1399
|
+
subject: "Auto-started Appium server",
|
|
1400
|
+
timeoutInMilliseconds: APPIUM_STOP_TIMEOUT_IN_MILLISECONDS
|
|
1401
|
+
}));
|
|
1402
|
+
if (isStopped) {
|
|
1403
|
+
clearAppiumServerMarker(params.port);
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
recordAppiumServerStopAttempt(params.port);
|
|
1407
|
+
}
|
|
1408
|
+
/**
|
|
1409
|
+
* Stops the emulator this run started, and **verifies** it stopped.
|
|
1410
|
+
*
|
|
1411
|
+
* The console shutdown goes first because it is the only path that releases
|
|
1412
|
+
* the AVD's `multiinstance.lock`; a `taskkill` leaves the lock behind, and a
|
|
1413
|
+
* stale lock is what makes the next run fail with `Running multiple emulators
|
|
1414
|
+
* with the same AVD` — a FATAL the emulator writes to its own stdout, where
|
|
1415
|
+
* nobody sees it.
|
|
1416
|
+
*
|
|
1417
|
+
* @param params - The emulator process, the device it serves and the PIDs this run owns.
|
|
1418
|
+
*/
|
|
1419
|
+
async stopAutoStartedEmulator(params) {
|
|
1420
|
+
await this.killEmulatorConsole(params.deviceId);
|
|
1421
|
+
killProcessTree(params.emulatorProcess);
|
|
1422
|
+
const waitParams = {
|
|
1423
|
+
deviceId: params.deviceId,
|
|
1424
|
+
ownedEmulatorPids: params.ownedEmulatorPids,
|
|
1425
|
+
timeoutInMilliseconds: EMULATOR_STOP_TIMEOUT_IN_MILLISECONDS
|
|
1426
|
+
};
|
|
1427
|
+
let hasEscalated = false;
|
|
1428
|
+
let isStopped = await this.waitForEmulatorStopped(waitParams);
|
|
1429
|
+
if (!isStopped) {
|
|
1430
|
+
const survivingPids = params.ownedEmulatorPids.filter((pid) => checkIsProcessAlive(pid));
|
|
1431
|
+
if (survivingPids.length > 0) {
|
|
1432
|
+
hasEscalated = true;
|
|
1433
|
+
this.log(
|
|
1434
|
+
`Auto-started emulator outlived the launcher's process tree; escalating to the backend PID(s) this run started: [${survivingPids.join(", ")}].`
|
|
1435
|
+
);
|
|
1436
|
+
for (const pid of survivingPids) {
|
|
1437
|
+
killProcessTreeByPid(pid);
|
|
1438
|
+
}
|
|
1439
|
+
isStopped = await this.waitForEmulatorStopped({ ...waitParams, timeoutInMilliseconds: EMULATOR_ESCALATED_STOP_TIMEOUT_IN_MILLISECONDS });
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
this.log(buildTeardownMessage({
|
|
1443
|
+
evidence: `AVD "${params.avdName}" on device ${params.deviceId}`,
|
|
1444
|
+
outcome: resolveTeardownOutcome({ hasEscalated, isStopped }),
|
|
1445
|
+
subject: "Auto-started emulator",
|
|
1446
|
+
timeoutInMilliseconds: EMULATOR_STOP_TIMEOUT_IN_MILLISECONDS
|
|
1447
|
+
}));
|
|
1448
|
+
}
|
|
1449
|
+
/**
|
|
1450
|
+
* Best-effort teardown for `process.on('exit')`, which cannot await.
|
|
1451
|
+
*
|
|
1452
|
+
* It kills, looks once for a survivor still holding the Appium port or a
|
|
1453
|
+
* still-live emulator PID, kills those too — and then says exactly that. It
|
|
1454
|
+
* never claims a verified stop, because it cannot wait to earn one.
|
|
1455
|
+
*
|
|
1456
|
+
* @param params - Everything this run started.
|
|
1457
|
+
*/
|
|
1458
|
+
stopAutoStartedProcessesBestEffort(params) {
|
|
1459
|
+
if (params.appiumProcess) {
|
|
1460
|
+
killProcessTree(params.appiumProcess);
|
|
1461
|
+
const ownerPids = this.listPortOwnerPidsSync(params.port);
|
|
1462
|
+
for (const pid of ownerPids) {
|
|
1463
|
+
killProcessTreeByPid(pid);
|
|
1464
|
+
}
|
|
1465
|
+
if (ownerPids.length > 0) {
|
|
1466
|
+
this.log(
|
|
1467
|
+
`Auto-started Appium server: stop requested and PID(s) [${ownerPids.join(", ")}] holding port ${String(params.port)} killed \u2014 sync teardown cannot wait to confirm.`
|
|
1468
|
+
);
|
|
1469
|
+
recordAppiumServerStopAttempt(params.port);
|
|
1470
|
+
} else {
|
|
1471
|
+
this.log(`Auto-started Appium server: stop requested, nothing left listening on port ${String(params.port)}.`);
|
|
1472
|
+
clearAppiumServerMarker(params.port);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
if (params.emulatorProcess) {
|
|
1476
|
+
killProcessTree(params.emulatorProcess);
|
|
1477
|
+
const survivingPids = params.ownedEmulatorPids.filter((pid) => checkIsProcessAlive(pid));
|
|
1478
|
+
for (const pid of survivingPids) {
|
|
1479
|
+
killProcessTreeByPid(pid);
|
|
1480
|
+
}
|
|
1481
|
+
this.log(
|
|
1482
|
+
survivingPids.length > 0 ? `Auto-started emulator: stop requested and surviving backend PID(s) [${survivingPids.join(", ")}] killed \u2014 sync teardown cannot wait to confirm.` : "Auto-started emulator: stop requested, no process of this run left running."
|
|
1483
|
+
);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
/**
|
|
1487
|
+
* Stops everything this run auto-started, verifying each stop.
|
|
1488
|
+
*
|
|
1489
|
+
* @param params - Everything this run started.
|
|
1490
|
+
*/
|
|
1491
|
+
async stopAutoStartedProcessesVerified(params) {
|
|
1492
|
+
if (!params.appiumProcess && !params.emulatorProcess) {
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
this.log("Stopping everything this run auto-started...");
|
|
1496
|
+
if (params.appiumProcess) {
|
|
1497
|
+
await this.stopAutoStartedAppiumServer({
|
|
1498
|
+
appiumProcess: params.appiumProcess,
|
|
1499
|
+
port: params.port,
|
|
1500
|
+
url: params.url
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
if (params.emulatorProcess && params.deviceId !== void 0) {
|
|
1504
|
+
await this.stopAutoStartedEmulator({
|
|
1505
|
+
avdName: params.avdName,
|
|
1506
|
+
deviceId: params.deviceId,
|
|
1507
|
+
emulatorProcess: params.emulatorProcess,
|
|
1508
|
+
ownedEmulatorPids: params.ownedEmulatorPids
|
|
1509
|
+
});
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
801
1512
|
async suppressErrorDialogs(deviceId) {
|
|
802
1513
|
this.log(`Disabling crash/ANR dialogs on device ${deviceId} (settings put global hide_error_dialogs 1)...`);
|
|
803
1514
|
await new Promise((resolve) => {
|
|
@@ -915,10 +1626,11 @@ ${outputTail}` : "";
|
|
|
915
1626
|
* Waits until nothing answers `/status` on the port any more.
|
|
916
1627
|
*
|
|
917
1628
|
* @param url - The Appium server URL.
|
|
1629
|
+
* @param timeoutInMilliseconds - How long to wait before giving up.
|
|
918
1630
|
* @throws If the port is still served when the timeout elapses.
|
|
919
1631
|
*/
|
|
920
|
-
async waitForAppiumStopped(url) {
|
|
921
|
-
const deadline = Date.now() +
|
|
1632
|
+
async waitForAppiumStopped(url, timeoutInMilliseconds) {
|
|
1633
|
+
const deadline = Date.now() + timeoutInMilliseconds;
|
|
922
1634
|
while (Date.now() < deadline) {
|
|
923
1635
|
try {
|
|
924
1636
|
await this.checkAppiumReachable(url);
|
|
@@ -930,9 +1642,16 @@ ${outputTail}` : "";
|
|
|
930
1642
|
});
|
|
931
1643
|
}
|
|
932
1644
|
throw new Error(
|
|
933
|
-
`Something is still serving ${url.origin} ${String(
|
|
1645
|
+
`Something is still serving ${url.origin} ${String(timeoutInMilliseconds)}ms after the Appium server was killed.`
|
|
934
1646
|
);
|
|
935
1647
|
}
|
|
1648
|
+
/**
|
|
1649
|
+
* Polls `sys.boot_completed` until the device reports a finished boot.
|
|
1650
|
+
*
|
|
1651
|
+
* @param deviceId - The device UDID to poll.
|
|
1652
|
+
* @param deadline - The absolute time at which to give up.
|
|
1653
|
+
* @param emulator - The emulator this run started, so its early death fails fast instead of polling out the deadline. Omitted for a reused device, which this run did not launch and cannot inspect.
|
|
1654
|
+
*/
|
|
936
1655
|
async waitForBoot(deviceId, deadline, emulator) {
|
|
937
1656
|
const remainingMs = Math.max(0, deadline - Date.now());
|
|
938
1657
|
this.log(
|
|
@@ -953,11 +1672,11 @@ ${outputTail}` : "";
|
|
|
953
1672
|
this.log(`Device ${deviceId} boot completed.`);
|
|
954
1673
|
return;
|
|
955
1674
|
}
|
|
956
|
-
const exitInfo = emulator
|
|
1675
|
+
const exitInfo = emulator?.readExitInfo();
|
|
957
1676
|
if (exitInfo) {
|
|
958
1677
|
throw new Error(buildProcessExitMessage({
|
|
959
1678
|
exitInfo,
|
|
960
|
-
output: emulator
|
|
1679
|
+
output: emulator?.readOutput() ?? "",
|
|
961
1680
|
outputLabel: "Emulator output",
|
|
962
1681
|
subject: "Android emulator"
|
|
963
1682
|
}));
|
|
@@ -966,13 +1685,14 @@ ${outputTail}` : "";
|
|
|
966
1685
|
setTimeout(resolve, EMULATOR_BOOT_POLL_INTERVAL_IN_MILLISECONDS);
|
|
967
1686
|
});
|
|
968
1687
|
}
|
|
969
|
-
throw new Error(
|
|
970
|
-
`Device "${deviceId}" connected but did not finish booting within ${String(EMULATOR_BOOT_TIMEOUT_IN_MILLISECONDS)}ms
|
|
971
|
-
|
|
1688
|
+
throw new Error(appendProcessOutputTail(
|
|
1689
|
+
`Device "${deviceId}" connected but did not finish booting within ${String(EMULATOR_BOOT_TIMEOUT_IN_MILLISECONDS)}ms.`,
|
|
1690
|
+
{ output: emulator?.readOutput() ?? "", outputLabel: "Emulator output" }
|
|
1691
|
+
));
|
|
972
1692
|
}
|
|
973
1693
|
/**
|
|
974
|
-
* Waits for a
|
|
975
|
-
* established.
|
|
1694
|
+
* Waits for a booted emulator to become idle before the session is
|
|
1695
|
+
* established — whether this run started it or found it already running.
|
|
976
1696
|
*
|
|
977
1697
|
* `sys.boot_completed` fires before the guest is actually idle — package
|
|
978
1698
|
* optimization and services keep churning — so establishing the Appium
|
|
@@ -981,6 +1701,10 @@ ${outputTail}` : "";
|
|
|
981
1701
|
* a later, quieter signal (boot animation stopped + package manager serving,
|
|
982
1702
|
* via {@link checkDeviceIdle}) and returns as soon as it is satisfied.
|
|
983
1703
|
*
|
|
1704
|
+
* A **reused** device needs this every bit as much as a started one: being
|
|
1705
|
+
* listed in `adb devices` says only that adbd answers, and the churn it does
|
|
1706
|
+
* not gate is paid later by whatever polls the WebView.
|
|
1707
|
+
*
|
|
984
1708
|
* Best-effort: if the guest does not report idle within the budget it logs a
|
|
985
1709
|
* warning and proceeds (a slow session is better than a failed run), and a
|
|
986
1710
|
* budget of `0` skips the wait entirely.
|
|
@@ -1016,7 +1740,102 @@ ${outputTail}` : "";
|
|
|
1016
1740
|
`Warning: device ${deviceId} did not report idle within ${String(timeoutInMilliseconds)}ms; proceeding with session establishment anyway.`
|
|
1017
1741
|
);
|
|
1018
1742
|
}
|
|
1019
|
-
|
|
1743
|
+
/**
|
|
1744
|
+
* Runs both post-boot readiness gates, in order, on a device that has just
|
|
1745
|
+
* reported `sys.boot_completed`.
|
|
1746
|
+
*
|
|
1747
|
+
* The single owner of "which gates a device passes before a session", so the
|
|
1748
|
+
* started-device and reused-device branches cannot diverge on it — the branch
|
|
1749
|
+
* that skipped a gate entirely is the hole a reused device once fell into (**L43**).
|
|
1750
|
+
*
|
|
1751
|
+
* @param deviceId - The device UDID to gate on.
|
|
1752
|
+
* @param timeouts - The two resolved budgets.
|
|
1753
|
+
*/
|
|
1754
|
+
async waitForDeviceReady(deviceId, timeouts) {
|
|
1755
|
+
await this.waitForDeviceIdle(deviceId, timeouts.deviceIdleTimeoutInMilliseconds);
|
|
1756
|
+
await this.waitForNetworkValidated(deviceId, timeouts.networkReadyTimeoutInMilliseconds);
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Waits for a booted emulator to have a **validated default network** before
|
|
1760
|
+
* the session is established.
|
|
1761
|
+
*
|
|
1762
|
+
* The idle gate above says nothing about connectivity, and its two signals are
|
|
1763
|
+
* satisfied well before the default network is created and validated — that
|
|
1764
|
+
* lands ~80s into guest uptime, tens of seconds after the boot flag on a fast
|
|
1765
|
+
* host. A suite started in that gap does not merely run slowly: a test
|
|
1766
|
+
* that reaches the network runs to completion against a silently **empty
|
|
1767
|
+
* result**, which no assertion inside the suite can distinguish from a
|
|
1768
|
+
* genuinely empty response. Only a readiness gate can catch that, which is why
|
|
1769
|
+
* this exists (see {@link checkNetworkValidated}, which also records why the
|
|
1770
|
+
* three obvious connectivity probes are all wrong).
|
|
1771
|
+
*
|
|
1772
|
+
* Best-effort, on the same contract as the idle gate: if no validated network
|
|
1773
|
+
* appears within the budget it logs a warning **naming the missing network**
|
|
1774
|
+
* and proceeds (an offline AVD is still a usable one for suites that never
|
|
1775
|
+
* touch the network), and a budget of `0` skips the wait entirely. The warning
|
|
1776
|
+
* is the point — the failure it precedes otherwise surfaces as a bare
|
|
1777
|
+
* `WebDriverError: script timeout` naming the transport, which reads as a
|
|
1778
|
+
* harness defect rather than a missing route.
|
|
1779
|
+
*
|
|
1780
|
+
* @param deviceId - The device UDID to poll.
|
|
1781
|
+
* @param timeoutInMilliseconds - Maximum time to wait; `0` skips the wait.
|
|
1782
|
+
*/
|
|
1783
|
+
/**
|
|
1784
|
+
* Polls until this run's emulator is gone, or the budget elapses.
|
|
1785
|
+
*
|
|
1786
|
+
* @param params - The device, the PIDs this run owns, and the budget.
|
|
1787
|
+
* @returns `true` when the emulator disappeared within the budget.
|
|
1788
|
+
*/
|
|
1789
|
+
async waitForEmulatorStopped(params) {
|
|
1790
|
+
const deadline = Date.now() + params.timeoutInMilliseconds;
|
|
1791
|
+
while (Date.now() < deadline) {
|
|
1792
|
+
if (await this.checkIsEmulatorGone(params)) {
|
|
1793
|
+
return true;
|
|
1794
|
+
}
|
|
1795
|
+
await new Promise((resolve) => {
|
|
1796
|
+
setTimeout(resolve, EMULATOR_STOP_POLL_INTERVAL_IN_MILLISECONDS);
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
return false;
|
|
1800
|
+
}
|
|
1801
|
+
async waitForNetworkValidated(deviceId, timeoutInMilliseconds) {
|
|
1802
|
+
if (timeoutInMilliseconds <= 0) {
|
|
1803
|
+
this.log(`Skipping network-ready wait for device ${deviceId} (timeout is 0).`);
|
|
1804
|
+
return;
|
|
1805
|
+
}
|
|
1806
|
+
const start = Date.now();
|
|
1807
|
+
const deadline = start + timeoutInMilliseconds;
|
|
1808
|
+
this.log(
|
|
1809
|
+
`Waiting for device ${deviceId} to report a validated network (timeout: ${String(timeoutInMilliseconds)}ms, poll: ${String(NETWORK_READY_POLL_INTERVAL_IN_MILLISECONDS)}ms)...`
|
|
1810
|
+
);
|
|
1811
|
+
let probeFailureCount = 0;
|
|
1812
|
+
let lastFailureReason = "";
|
|
1813
|
+
while (Date.now() < deadline) {
|
|
1814
|
+
const probe = await this.dumpConnectivity(deviceId);
|
|
1815
|
+
const elapsed = String(Date.now() - start);
|
|
1816
|
+
const connectivityOutput = probe.output;
|
|
1817
|
+
if (connectivityOutput === void 0) {
|
|
1818
|
+
probeFailureCount++;
|
|
1819
|
+
lastFailureReason = probe.failureReason ?? "unknown adb failure";
|
|
1820
|
+
this.log(
|
|
1821
|
+
`Device ${deviceId} connectivity probe failed (elapsed: ${elapsed}ms): ${lastFailureReason}. Retrying...`
|
|
1822
|
+
);
|
|
1823
|
+
} else if (checkNetworkValidated({ connectivityOutput })) {
|
|
1824
|
+
this.log(`Device ${deviceId} has a validated network after ${elapsed}ms.`);
|
|
1825
|
+
return;
|
|
1826
|
+
} else {
|
|
1827
|
+
this.log(`Device ${deviceId} has no validated network yet (elapsed: ${elapsed}ms). Retrying...`);
|
|
1828
|
+
}
|
|
1829
|
+
await new Promise((resolve) => {
|
|
1830
|
+
setTimeout(resolve, NETWORK_READY_POLL_INTERVAL_IN_MILLISECONDS);
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
const diagnosis = probeFailureCount > 0 ? `${String(probeFailureCount)} of its connectivity probes failed, last "${lastFailureReason}", so the guest may be wedged rather than offline` : "it answered every probe and reported no validated default network";
|
|
1834
|
+
this.log(
|
|
1835
|
+
`Warning: device ${deviceId} reported no validated network within ${String(timeoutInMilliseconds)}ms (${diagnosis}); proceeding with session establishment anyway. Tests that reach the network will run against a device with no route, and may return EMPTY RESULTS rather than fail \u2014 read any empty-looking assertion failure below as a missing network first.`
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
async waitForNewDevice(deviceIdsBefore, emulator, timeouts) {
|
|
1020
1839
|
this.log(
|
|
1021
1840
|
`Waiting for a new device to appear in ADB (timeout: ${String(EMULATOR_BOOT_TIMEOUT_IN_MILLISECONDS)}ms, poll: ${String(EMULATOR_BOOT_POLL_INTERVAL_IN_MILLISECONDS)}ms)...`
|
|
1022
1841
|
);
|
|
@@ -1028,7 +1847,7 @@ ${outputTail}` : "";
|
|
|
1028
1847
|
const actualDeviceId = newIds[0] ?? "";
|
|
1029
1848
|
this.log(`Device ${actualDeviceId} appeared in ADB, waiting for boot to complete...`);
|
|
1030
1849
|
await this.waitForBoot(actualDeviceId, deadline, emulator);
|
|
1031
|
-
await this.
|
|
1850
|
+
await this.waitForDeviceReady(actualDeviceId, timeouts);
|
|
1032
1851
|
await this.wakeScreen(actualDeviceId);
|
|
1033
1852
|
return actualDeviceId;
|
|
1034
1853
|
}
|
|
@@ -1045,9 +1864,10 @@ ${outputTail}` : "";
|
|
|
1045
1864
|
setTimeout(resolve, EMULATOR_BOOT_POLL_INTERVAL_IN_MILLISECONDS);
|
|
1046
1865
|
});
|
|
1047
1866
|
}
|
|
1048
|
-
throw new Error(
|
|
1049
|
-
`No new emulator device appeared within ${String(EMULATOR_BOOT_TIMEOUT_IN_MILLISECONDS)}ms
|
|
1050
|
-
|
|
1867
|
+
throw new Error(appendProcessOutputTail(
|
|
1868
|
+
`No new emulator device appeared within ${String(EMULATOR_BOOT_TIMEOUT_IN_MILLISECONDS)}ms.`,
|
|
1869
|
+
{ output: emulator.readOutput(), outputLabel: "Emulator output" }
|
|
1870
|
+
));
|
|
1051
1871
|
}
|
|
1052
1872
|
async wakeScreen(deviceId) {
|
|
1053
1873
|
this.log(`Waking screen on device ${deviceId}...`);
|
|
@@ -1076,10 +1896,29 @@ async function getOrCreateTransport(options) {
|
|
|
1076
1896
|
cachedTransport = result;
|
|
1077
1897
|
return result;
|
|
1078
1898
|
}
|
|
1899
|
+
async function assertHarnessOwnedInstanceIsServing(host, port) {
|
|
1900
|
+
const cdpUrl = `http://${host}:${String(port)}`;
|
|
1901
|
+
try {
|
|
1902
|
+
const response = await fetch(`${cdpUrl}/json/version`);
|
|
1903
|
+
await response.body?.cancel();
|
|
1904
|
+
return;
|
|
1905
|
+
} catch {
|
|
1906
|
+
}
|
|
1907
|
+
throw buildOwnedInstanceExitedErrorFromMarker(cdpUrl, readOwnedInstanceExitMarker(port));
|
|
1908
|
+
}
|
|
1909
|
+
function buildHostProcessQuery() {
|
|
1910
|
+
return process.platform === "win32" ? { command: "tasklist", commandArguments: ["/FO", "CSV", "/NH"] } : { command: "ps", commandArguments: ["-eo", "pid=,comm="] };
|
|
1911
|
+
}
|
|
1912
|
+
function buildPortOwnerQuery(port) {
|
|
1913
|
+
return process.platform === "win32" ? { command: "netstat", commandArguments: ["-ano"] } : { command: "lsof", commandArguments: ["-ti", `tcp:${String(port)}`] };
|
|
1914
|
+
}
|
|
1079
1915
|
async function createCdpTransport(options) {
|
|
1080
1916
|
if (options?.port !== void 0) {
|
|
1081
1917
|
const ownedSuffix = options.isHarnessOwnedInstance ? " (harness-owned)" : "";
|
|
1082
1918
|
log(`[transport-factory:obsidian-cdp] Attaching to running Obsidian${ownedSuffix} (host=${options.host ?? "localhost"}, port=${String(options.port)})`);
|
|
1919
|
+
if (options.isHarnessOwnedInstance) {
|
|
1920
|
+
await assertHarnessOwnedInstanceIsServing(options.host ?? "localhost", options.port);
|
|
1921
|
+
}
|
|
1083
1922
|
return new DesktopCdpTransport(normalizeOptionalProperties({
|
|
1084
1923
|
cdpHost: options.host,
|
|
1085
1924
|
cdpPort: options.port,
|
|
@@ -1088,10 +1927,14 @@ async function createCdpTransport(options) {
|
|
|
1088
1927
|
}));
|
|
1089
1928
|
}
|
|
1090
1929
|
log("[transport-factory:obsidian-cdp] Creating owned isolated Obsidian instance");
|
|
1930
|
+
if (options?.configDirectory !== void 0) {
|
|
1931
|
+
assertValidConfigDirectory(options.configDirectory);
|
|
1932
|
+
}
|
|
1091
1933
|
const ownedInstance = await resolveOwnedInstanceConfig(options);
|
|
1092
1934
|
return new DesktopCdpTransport(normalizeOptionalProperties({
|
|
1093
1935
|
cdpHost: options?.host,
|
|
1094
1936
|
commandTimeoutInMilliseconds: options?.commandTimeoutInMilliseconds,
|
|
1937
|
+
configDirectory: options?.configDirectory,
|
|
1095
1938
|
deadBootGraceInMilliseconds: resolveDeadBootGraceInMilliseconds(options),
|
|
1096
1939
|
isObsidianAppVisible: options?.isObsidianAppVisible,
|
|
1097
1940
|
ownedInstance,
|
|
@@ -1105,9 +1948,23 @@ function createOwnedUserDataDirectory() {
|
|
|
1105
1948
|
mkdirSync(root, { recursive: true });
|
|
1106
1949
|
return mkdtempSync(join(root, OWNED_USER_DATA_DIR_PREFIX));
|
|
1107
1950
|
}
|
|
1951
|
+
function getSettledFailure(outcomes) {
|
|
1952
|
+
for (const outcome of outcomes) {
|
|
1953
|
+
if (outcome.status === "rejected") {
|
|
1954
|
+
return outcome.reason;
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
return new Error("Android provisioning failed without naming a reason.");
|
|
1958
|
+
}
|
|
1108
1959
|
async function importWebdriverio() {
|
|
1109
1960
|
return await import("webdriverio");
|
|
1110
1961
|
}
|
|
1962
|
+
function parseHostProcessList(output) {
|
|
1963
|
+
return process.platform === "win32" ? parseWindowsTaskList(output) : parsePosixProcessList(output);
|
|
1964
|
+
}
|
|
1965
|
+
function parsePortOwnerPids(params) {
|
|
1966
|
+
return process.platform === "win32" ? parseWindowsNetstatPids({ netstatOutput: params.output, port: params.port }) : parsePosixLsofPids(params.output);
|
|
1967
|
+
}
|
|
1111
1968
|
function resolveAndReportCompatibility(params) {
|
|
1112
1969
|
const { appVersion, installerVersion, shouldThrowOnIncompatibleInstaller, shouldWarnOnCompatibilityIssues } = params;
|
|
1113
1970
|
if (appVersion === void 0) {
|
|
@@ -1209,4 +2066,4 @@ export {
|
|
|
1209
2066
|
createTransportFromOptions,
|
|
1210
2067
|
getOrCreateTransport
|
|
1211
2068
|
};
|
|
1212
|
-
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC1mYWN0b3J5LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogRmFjdG9yeSBmb3IgY3JlYXRpbmcgdHJhbnNwb3J0IGluc3RhbmNlcyBmcm9tIHtAbGluayBPYnNpZGlhblRyYW5zcG9ydE9wdGlvbnN9LlxuICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBJbnRlZ3JhdGlvbi10aW1lIGZhY3RvcnkgY292ZXJlZCBieSBpbnRlZ3JhdGlvbiB0ZXN0cywgbm90IHVuaXQgdGVzdHMuICovXG5cbmltcG9ydCB0eXBlIHsgQ2hpbGRQcm9jZXNzIH0gZnJvbSAnbm9kZTpjaGlsZF9wcm9jZXNzJztcbmltcG9ydCB0eXBlIHtcbiAgYXR0YWNoLFxuICByZW1vdGVcbn0gZnJvbSAnd2ViZHJpdmVyaW8nO1xuXG5pbXBvcnQge1xuICBleGVjRmlsZSxcbiAgc3Bhd25cbn0gZnJvbSAnbm9kZTpjaGlsZF9wcm9jZXNzJztcbmltcG9ydCB7XG4gIG1rZGlyU3luYyxcbiAgbWtkdGVtcFN5bmNcbn0gZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgaHR0cCBmcm9tICdub2RlOmh0dHAnO1xuaW1wb3J0IHsgdG1wZGlyIH0gZnJvbSAnbm9kZTpvcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCBwcm9jZXNzIGZyb20gJ25vZGU6cHJvY2Vzcyc7XG5cbmltcG9ydCB0eXBlIHsgQXBwaXVtU2VydmVyTWFya2VyIH0gZnJvbSAnLi9hcHBpdW0tc2VydmVyLW1hcmtlci5tanMnO1xuaW1wb3J0IHR5cGUgeyBJbnN0YWxsZXJDb21wYXRpYmlsaXR5IH0gZnJvbSAnLi9pbnN0YWxsZXItY29tcGF0aWJpbGl0eS5tanMnO1xuaW1wb3J0IHR5cGUgeyBQcm9jZXNzRXhpdEluZm8gfSBmcm9tICcuL3Byb2Nlc3MtZXhpdC1tZXNzYWdlLm1qcyc7XG5pbXBvcnQgdHlwZSB7XG4gIERlc2t0b3BDZHBUcmFuc3BvcnRDb25maWcsXG4gIE93bmVkSW5zdGFuY2VDb25maWdcbn0gZnJvbSAnLi90cmFuc3BvcnQtZGVza3RvcC1jZHAubWpzJztcbmltcG9ydCB0eXBlIHtcbiAgT2JzaWRpYW5BbmRyb2lkQXBwaXVtVHJhbnNwb3J0T3B0aW9ucyxcbiAgT2JzaWRpYW5DZHBUcmFuc3BvcnRPcHRpb25zLFxuICBPYnNpZGlhblRyYW5zcG9ydE9wdGlvbnNcbn0gZnJvbSAnLi90cmFuc3BvcnQtb3B0aW9ucy5tanMnO1xuaW1wb3J0IHR5cGUgeyBPYnNpZGlhblRyYW5zcG9ydCB9IGZyb20gJy4vdHJhbnNwb3J0Lm1qcyc7XG5pbXBvcnQgdHlwZSB7IFdlZGdlZEFwcGl1bVNlcnZlclJlcG9ydFJlYXNvbiB9IGZyb20gJy4vd2VkZ2VkLWFwcGl1bS1zZXJ2ZXIubWpzJztcblxuaW1wb3J0IHtcbiAgY2hlY2tJc0FwcGl1bURyaXZlckluc3RhbGxlZCxcbiAgVUlBVVRPTUFUT1IyX0RSSVZFUl9OQU1FLFxuICB3aWxsQXV0b0luc3RhbGxBcHBpdW1EZXBlbmRlbmNpZXNcbn0gZnJvbSAnLi9hcHBpdW0tZGVwZW5kZW5jaWVzLm1qcyc7XG5pbXBvcnQge1xuICBjaGVja0lzSGFybmVzc093bmVkQXBwaXVtU2VydmVyLFxuICBjbGVhckFwcGl1bVNlcnZlck1hcmtlcixcbiAgcmVhZEFwcGl1bVNlcnZlck1hcmtlcixcbiAgd3JpdGVBcHBpdW1TZXJ2ZXJNYXJrZXJcbn0gZnJvbSAnLi9hcHBpdW0tc2VydmVyLW1hcmtlci5tanMnO1xuaW1wb3J0IHtcbiAgcmVzb2x2ZUFwcGl1bVN0YXJ0VGltZW91dEluTWlsbGlzZWNvbmRzLFxuICByZXNvbHZlU2Vzc2lvbkNvbm5lY3Rpb25SZXRyeVRpbWVvdXRJbk1pbGxpc2Vjb25kc1xufSBmcm9tICcuL2FwcGl1bS1zZXNzaW9uLWNvbmZpZy5tanMnO1xuaW1wb3J0IHtcbiAgY2hlY2tBdmRFeGlzdHMsXG4gIGxpc3RBdmFpbGFibGVBdmRzXG59IGZyb20gJy4vYXZkLWxpc3QubWpzJztcbmltcG9ydCB7XG4gIHJlc29sdmVJbnN0YWxsZXJDb21wYXRpYmlsaXR5QWN0aW9uLFxuICB3aWxsVGhyb3dPbkluY29tcGF0aWJsZUluc3RhbGxlcixcbiAgd2lsbFRocm93T25TaWxlbnRBc2FyRmFsbGJhY2ssXG4gIHdpbGxXYXJuT25Db21wYXRpYmlsaXR5SXNzdWVzXG59IGZyb20gJy4vY29tcGF0aWJpbGl0eS1vcHRpb25zLm1qcyc7XG5pbXBvcnQgeyBnZXRTZXR1cEVycm9yIH0gZnJvbSAnLi9jb250ZXh0LXByb3ZpZGVyLm1qcyc7XG5pbXBvcnQge1xuICBjaGVja0RldmljZUlkbGUsXG4gIHJlc29sdmVEZXZpY2VJZGxlVGltZW91dEluTWlsbGlzZWNvbmRzXG59IGZyb20gJy4vZGV2aWNlLXJlYWRpbmVzcy5tanMnO1xuaW1wb3J0IHsgYnVpbGRFbXVsYXRvckFyZ3VtZW50cyB9IGZyb20gJy4vZW11bGF0b3ItYXJndW1lbnRzLm1qcyc7XG5pbXBvcnQgeyBleGVjIH0gZnJvbSAnLi9leGVjLm1qcyc7XG5pbXBvcnQgeyBJbmNvbXBhdGlibGVJbnN0YWxsZXJWZXJzaW9uRXJyb3IgfSBmcm9tICcuL2luY29tcGF0aWJsZS1pbnN0YWxsZXItdmVyc2lvbi1lcnJvci5tanMnO1xuaW1wb3J0IHsgcmVzb2x2ZUluc3RhbGxlckNvbXBhdGliaWxpdHkgfSBmcm9tICcuL2luc3RhbGxlci1jb21wYXRpYmlsaXR5Lm1qcyc7XG5pbXBvcnQgeyBJbnRlZ3JhdGlvblNldHVwRmFpbGVkRXJyb3IgfSBmcm9tICcuL2ludGVncmF0aW9uLXNldHVwLWZhaWxlZC1lcnJvci5tanMnO1xuaW1wb3J0IHtcbiAga2lsbFByb2Nlc3NUcmVlLFxuICBraWxsUHJvY2Vzc1RyZWVCeVBpZFxufSBmcm9tICcuL2tpbGwtcHJvY2Vzcy10cmVlLm1qcyc7XG5pbXBvcnQge1xuICBIQVJORVNTX1RFTVBfRElSX05BTUUsXG4gIE9XTkVEX1VTRVJfREFUQV9ESVJfUFJFRklYLFxuICBzd2VlcERldmljZUxlZnRvdmVycyxcbiAgd2lsbFN3ZWVwTGVmdG92ZXJzXG59IGZyb20gJy4vbGVmdG92ZXItY2xlYW51cC5tanMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2cubWpzJztcbmltcG9ydCB7IG5vcm1hbGl6ZU9wdGlvbmFsUHJvcGVydGllcyB9IGZyb20gJy4vbm9ybWFsaXplLW9wdGlvbmFsLXByb3BlcnRpZXMubWpzJztcbmltcG9ydCB7IGdldE9ic2lkaWFuQ29uZmlnRGlyZWN0b3J5IH0gZnJvbSAnLi9vYnNpZGlhbi1jb25maWcubWpzJztcbmltcG9ydCB7IHJlc29sdmVPYnNpZGlhbkV4ZWN1dGFibGUgfSBmcm9tICcuL29ic2lkaWFuLWV4ZWN1dGFibGUubWpzJztcbmltcG9ydCB7XG4gIGRldGVjdEluc3RhbGxlZFNoZWxsVmVyc2lvbixcbiAgZW5zdXJlU2hlbGxDYWNoZWRcbn0gZnJvbSAnLi9vYnNpZGlhbi1pbnN0YWxsZXIubWpzJztcbmltcG9ydCB7IGdldFZlcnNpb25NZXRhZGF0YSB9IGZyb20gJy4vb2JzaWRpYW4tbWV0YWRhdGEubWpzJztcbmltcG9ydCB7XG4gIGVuc3VyZUFzYXJDYWNoZWQsXG4gIGZpbmROZXdlc3RBc2FyLFxuICByZXNvbHZlQ29uY3JldGVWZXJzaW9uXG59IGZyb20gJy4vb2JzaWRpYW4tdmVyc2lvbi1zd2l0Y2gubWpzJztcbmltcG9ydCB7IGNvbXBhcmVWZXJzaW9ucyB9IGZyb20gJy4vb2JzaWRpYW4tdmVyc2lvbi5tanMnO1xuaW1wb3J0IHsgYnVpbGRQcm9jZXNzRXhpdE1lc3NhZ2UgfSBmcm9tICcuL3Byb2Nlc3MtZXhpdC1tZXNzYWdlLm1qcyc7XG5pbXBvcnQgeyByZXNvbHZlRGVhZEJvb3RHcmFjZUluTWlsbGlzZWNvbmRzIH0gZnJvbSAnLi9yZW5kZXJlci1ib290LWRldGVjdGlvbi5tanMnO1xuaW1wb3J0IHtcbiAgcmVzb2x2ZUFwcGl1bVNwYXduRmxhZ3MsXG4gIHJlc29sdmVFbXVsYXRvclNwYXduRmxhZ3Ncbn0gZnJvbSAnLi9zcGF3bi1vcHRpb25zLm1qcyc7XG5pbXBvcnQge1xuICBBcHBpdW1UcmFuc3BvcnQsXG4gIERFRkFVTFRfQU5EUk9JRF9WQVVMVF9CQVNFX1BBVEhcbn0gZnJvbSAnLi90cmFuc3BvcnQtYXBwaXVtLm1qcyc7XG5pbXBvcnQgeyBEZXNrdG9wQ2RwVHJhbnNwb3J0IH0gZnJvbSAnLi90cmFuc3BvcnQtZGVza3RvcC1jZHAubWpzJztcbmltcG9ydCB7IGVuc3VyZU5vbk51bGxhYmxlIH0gZnJvbSAnLi90eXBlLWd1YXJkcy5tanMnO1xuaW1wb3J0IHtcbiAgc2hvdWxkSGlkZUFwcGl1bUNvbnNvbGUsXG4gIHNob3VsZEhpZGVFbXVsYXRvcldpbmRvd1xufSBmcm9tICcuL3Zpc2liaWxpdHkubWpzJztcbmltcG9ydCB7XG4gIGJ1aWxkV2VkZ2VkQXBwaXVtU2VydmVyTWVzc2FnZSxcbiAgY2hlY2tJc0FwcGl1bVN0YXR1c1JlYWR5LFxuICByZXNvbHZlV2VkZ2VkQXBwaXVtU2VydmVyUmVtZWR5XG59IGZyb20gJy4vd2VkZ2VkLWFwcGl1bS1zZXJ2ZXIubWpzJztcblxuY29uc3QgQVBQX1BBQ0tBR0UgPSAnbWQub2JzaWRpYW4nO1xuY29uc3QgQVBQX0FDVElWSVRZID0gYCR7QVBQX1BBQ0tBR0V9Lk1haW5BY3Rpdml0eWA7XG5jb25zdCBBREJfREVWSUNFX0NIRUNLX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gNTAwMDtcbmNvbnN0IEFQUElVTV9DT05ORUNUSU9OX1JFVFJZX0NPVU5UID0gMztcbmNvbnN0IEFQUElVTV9PVVRQVVRfVEFJTF9NQVhfTEVOR1RIID0gODAwMDtcbmNvbnN0IEFQUElVTV9QUkVGTElHSFRfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSA1MDAwO1xuY29uc3QgQVBQSVVNX1NUQVJUX1BPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTID0gNTAwO1xuY29uc3QgQVBQSVVNX1NUT1BfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSAxNV8wMDA7XG5jb25zdCBBREJfVkFVTFRfU1dFRVBfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSAzMF8wMDA7XG4vLyBBcHBpdW0gaW5zZWN1cmUgZmVhdHVyZSBsZXR0aW5nIHRoZSBVaUF1dG9tYXRvcjIgZHJpdmVyIGF1dG8tZG93bmxvYWQgYVxuLy8gQ2hyb21lZHJpdmVyIG1hdGNoaW5nIE9ic2lkaWFuJ3MgV2ViVmlldyBDaHJvbWUgdmVyc2lvbi4gRW5hYmxpbmcgaXQgb24gdGhlXG4vLyBBcHBpdW0gc2VydmVyIChpdCBoYXMgbm8gZWZmZWN0IGFzIGEgY2FwYWJpbGl0eSkgYXZvaWRzIHRoZSBmYWlsdXJlXG4vLyBcIk5vIENocm9tZWRyaXZlciBmb3VuZCB0aGF0IGNhbiBhdXRvbWF0ZSBDaHJvbWUgLi4uXCIuXG5jb25zdCBDSFJPTUVEUklWRVJfQVVUT0RPV05MT0FEX0ZFQVRVUkUgPSAndWlhdXRvbWF0b3IyOmNocm9tZWRyaXZlcl9hdXRvZG93bmxvYWQnO1xuY29uc3QgQ09NTUFORF9USU1FT1VUX0lOX01JTExJU0VDT05EUyA9IDMwMDtcbmNvbnN0IERFRkFVTFRfVFJBTlNQT1JUX1RZUEUgPSAnb2JzaWRpYW4tY2RwJztcbmNvbnN0IERFVklDRV9JRExFX1BPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTID0gMjAwMDtcbmNvbnN0IEVNVUxBVE9SX0JPT1RfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMgPSAyMDAwO1xuY29uc3QgRU1VTEFUT1JfQk9PVF9USU1FT1VUX0lOX01JTExJU0VDT05EUyA9IDEyMF8wMDA7XG5jb25zdCBFTVVMQVRPUl9MSVNUX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gMTBfMDAwO1xuY29uc3QgRU1VTEFUT1JfT1VUUFVUX1RBSUxfTUFYX0xFTkdUSCA9IDgwMDA7XG5jb25zdCBIVFRQX01VTFRJUExFX0NIT0lDRVMgPSAzMDA7XG5jb25zdCBIVFRQX09LID0gMjAwO1xuY29uc3QgS0VZQ09ERV9NRU5VID0gODI7XG5jb25zdCBLRVlDT0RFX1dBS0VVUCA9IDIyNDtcbmNvbnN0IE1JTExJU0VDT05EU19QRVJfU0VDT05EID0gMTAwMDtcbmNvbnN0IFNFUlZFUl9JTlNUQUxMX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gMTIwXzAwMDtcbmNvbnN0IFNFUlZFUl9MQVVOQ0hfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSAxMjBfMDAwO1xuXG4vKipcbiAqIEhvdyB0aGUgcmVxdWVzdGVkIGFwcCAoYXNhcikgdmVyc2lvbiB3aWxsIGJlIGFwcGxpZWQgdG8gYW4gb3duZWQgaW5zdGFuY2U7IGF0XG4gKiBtb3N0IG9uZSBmaWVsZCBpcyBzZXQgKHNlZSB7QGxpbmsgcmVzb2x2ZUFzYXJQbGFufSkuXG4gKi9cbmludGVyZmFjZSBBc2FyUGxhbiB7XG4gIC8qKlxuICBUaGUgdXNlcidzIG5ld2VzdCBpbnN0YWxsZWQgYXNhciB0byBwcm92aXNpb24gYXMtaXMgKG5vIGRvd25sb2FkKS5cbiAgICovXG4gIHJlYWRvbmx5IGFzYXI/OiBPd25lZEluc3RhbmNlQ29uZmlnWydhc2FyJ107XG5cbiAgLyoqXG4gIFRoZSBhcHAgdmVyc2lvbiB0byBkb3dubG9hZCBhbmQgYXNhci1zd2FwIG9udG8gdGhlIHNoZWxsLlxuICAgKi9cbiAgcmVhZG9ubHkgYXNhclZlcnNpb25Ub1N3YXA/OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSBhcHAgdmVyc2lvbiB3aG9zZSBvd24gaW5zdGFsbGVyIHNoZWxsIHRvIGRvd25sb2FkIChhIGRvd25ncmFkZSkuXG4gICAqL1xuICByZWFkb25seSBkb3duZ3JhZGVJbnN0YWxsZXJWZXJzaW9uPzogc3RyaW5nIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHtAbGluayBBcHBpdW1UcmFuc3BvcnRGYWN0b3J5LmVuc3VyZURldmljZUNvbm5lY3RlZH0uXG4gKi9cbmludGVyZmFjZSBFbnN1cmVEZXZpY2VDb25uZWN0ZWRQYXJhbXMge1xuICAvKipcbiAgQVZEIG5hbWUgdG8gY29ubmVjdCB0byAoc3RhcnRpbmcgYSBuZXcgZW11bGF0b3IgaWYgbm90IGFscmVhZHkgcnVubmluZykuXG4gICAqL1xuICByZWFkb25seSBhdmROYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gIFJlc29sdmVkIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgcG9zdC1ib290IGRldmljZS1pZGxlIHdhaXQgKGAwYCBza2lwcyBpdCkuXG4gICAqL1xuICByZWFkb25seSBkZXZpY2VJZGxlVGltZW91dEluTWlsbGlzZWNvbmRzOiBudW1iZXI7XG5cbiAgLyoqXG4gIFdoZXRoZXIgdGhlIGF1dG8tc3RhcnRlZCBlbXVsYXRvciB3aW5kb3cgaXMgc2hvd24gKG9taXR0ZWQgXHUyMTkyIGhpZGRlbikuXG4gICAqL1xuICByZWFkb25seSBpc0VtdWxhdG9yVmlzaWJsZT86IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogUmVzdWx0IG9mIHtAbGluayBBcHBpdW1UcmFuc3BvcnRGYWN0b3J5LmVuc3VyZURldmljZUNvbm5lY3RlZH0uXG4gKi9cbmludGVyZmFjZSBFbnN1cmVEZXZpY2VDb25uZWN0ZWRSZXN1bHQge1xuICAvKipcbiAgVGhlIGFjdHVhbCBkZXZpY2UgSUQgdGhhdCBpcyBjb25uZWN0ZWQgKG1heSBkaWZmZXIgZnJvbSB0aGUgcmVxdWVzdGVkIG9uZSkuXG4gICAqL1xuICByZWFkb25seSBhY3R1YWxEZXZpY2VJZDogc3RyaW5nO1xuXG4gIC8qKlxuICBUaGUgZW11bGF0b3IgcHJvY2VzcywgaWYgb25lIHdhcyBhdXRvLXN0YXJ0ZWQuXG4gICAqL1xuICByZWFkb25seSBlbXVsYXRvclByb2Nlc3M/OiBDaGlsZFByb2Nlc3MgfCB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3Ige0BsaW5rIEFwcGl1bVRyYW5zcG9ydEZhY3RvcnkuZXN0YWJsaXNoU2Vzc2lvbn0uXG4gKi9cbmludGVyZmFjZSBFc3RhYmxpc2hTZXNzaW9uUGFyYW1zIHtcbiAgLyoqXG4gIFRoZSBBbmRyb2lkIHBhY2thZ2UgdGhlIHNlc3Npb24gZHJpdmVzLlxuICAgKi9cbiAgcmVhZG9ubHkgYXBwSWQ6IHN0cmluZztcblxuICAvKipcbiAgVGhlIG1hcmtlciBvZiB0aGUgYWRvcHRlZCBzZXJ2ZXIsIHdoZW4gYW4gZWFybGllciBydW4gb2YgdGhpcyBoYXJuZXNzIGxlZnQgb25lLlxuICAgKi9cbiAgcmVhZG9ubHkgYXBwaXVtU2VydmVyTWFya2VyOiBBcHBpdW1TZXJ2ZXJNYXJrZXIgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFJlc29sdmVkIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBhIHJlcGxhY2VtZW50IEFwcGl1bSBzZXJ2ZXIgdG8gYmVjb21lIHJlYWR5LlxuICAgKi9cbiAgcmVhZG9ubHkgYXBwaXVtU3RhcnRUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcjtcblxuICAvKipcbiAgVGhlIGRldmljZSB0aGUgc2Vzc2lvbiBpcyBlc3RhYmxpc2hlZCBhZ2FpbnN0LlxuICAgKi9cbiAgcmVhZG9ubHkgZGV2aWNlSWQ6IHN0cmluZztcblxuICAvKipcbiAgV2hldGhlciB0aGUgc2VydmVyIHdhcyBhZG9wdGVkIHJhdGhlciB0aGFuIHN0YXJ0ZWQgYnkgdGhpcyBydW4uXG4gICAqL1xuICByZWFkb25seSBpc0Fkb3B0ZWRTZXJ2ZXI6IGJvb2xlYW47XG5cbiAgLyoqXG4gIFdoZXRoZXIgYSByZXBsYWNlbWVudCBzZXJ2ZXIncyBjb25zb2xlIHdpbmRvdyBpcyBzaG93biAob21pdHRlZCBcdTIxOTIgaGlkZGVuKS5cbiAgICovXG4gIHJlYWRvbmx5IGlzQXBwaXVtQ29uc29sZVZpc2libGU/OiBib29sZWFuIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICBUaGUgQXBwaXVtIHNlcnZlciBwb3J0LlxuICAgKi9cbiAgcmVhZG9ubHkgcG9ydDogbnVtYmVyO1xuXG4gIC8qKlxuICBSZXNvbHZlZCBXZWJEcml2ZXJJTyBjb25uZWN0aW9uIHJldHJ5IHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzLlxuICAgKi9cbiAgcmVhZG9ubHkgc2Vzc2lvbkNvbm5lY3Rpb25SZXRyeVRpbWVvdXRJbk1pbGxpc2Vjb25kczogbnVtYmVyO1xuXG4gIC8qKlxuICBXaGV0aGVyIEFwcGl1bSBhdXRvLXN0YXJ0IGlzIGFsbG93ZWQgXHUyMDE0IGEgYGZhbHNlYCBoZXJlIGFsc28gZm9yYmlkcyByZXBsYWNpbmcgYSB3ZWRnZWQgc2VydmVyLlxuICAgKi9cbiAgcmVhZG9ubHkgc2hvdWxkQXV0b1N0YXJ0QXBwaXVtPzogYm9vbGVhbiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgVGhlIEFwcGl1bSBzZXJ2ZXIgVVJMLlxuICAgKi9cbiAgcmVhZG9ubHkgdXJsOiBVUkw7XG59XG5cbi8qKlxuICogUmVzdWx0IG9mIHtAbGluayBBcHBpdW1UcmFuc3BvcnRGYWN0b3J5LmVzdGFibGlzaFNlc3Npb259LlxuICovXG5pbnRlcmZhY2UgRXN0YWJsaXNoU2Vzc2lvblJlc3VsdCB7XG4gIC8qKlxuICBUaGUgcmVwbGFjZW1lbnQgQXBwaXVtIHNlcnZlciBwcm9jZXNzLCB3aGVuIGEgd2VkZ2VkIG9uZSBoYWQgdG8gYmUgcmVzdGFydGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgYXBwaXVtUHJvY2Vzcz86IENoaWxkUHJvY2VzcyB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgVGhlIGVzdGFibGlzaGVkIHNlc3Npb24uXG4gICAqL1xuICByZWFkb25seSBicm93c2VyOiBBd2FpdGVkPFJldHVyblR5cGU8dHlwZW9mIHJlbW90ZT4+O1xufVxuXG4vKipcbiAqIFRoZSBsb2NhbGx5LWluc3RhbGxlZCBPYnNpZGlhbiBzaGVsbCByZXNvbHZlZCBieSB7QGxpbmsgcmVzb2x2ZUluc3RhbGxlZFNoZWxsT3JOdWxsfS5cbiAqL1xuaW50ZXJmYWNlIEluc3RhbGxlZFNoZWxsIHtcbiAgLyoqXG4gIEFic29sdXRlIHBhdGggdG8gdGhlIGluc3RhbGxlZCBzaGVsbCBleGVjdXRhYmxlLlxuICAgKi9cbiAgcmVhZG9ubHkgZXhlUGF0aDogc3RyaW5nO1xuXG4gIC8qKlxuICBUaGUgZGV0ZWN0ZWQgc2hlbGwgdmVyc2lvbiwgb3IgYHVuZGVmaW5lZGAgd2hlbiBpdCBjYW5ub3QgYmUgZGV0ZXJtaW5lZC5cbiAgICovXG4gIHJlYWRvbmx5IHNoZWxsVmVyc2lvbjogc3RyaW5nIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIEEgc3Bhd25lZCBjaGlsZCBwcm9jZXNzICh0aGUgQW5kcm9pZCBlbXVsYXRvciBvciB0aGUgQXBwaXVtIHNlcnZlcikgdG9nZXRoZXJcbiAqIHdpdGggaGVscGVycyB0byBpbnNwZWN0IGl0cyBjYXB0dXJlZCBvdXRwdXQgYW5kIGV4aXQgc3RhdHVzLlxuICovXG5pbnRlcmZhY2UgUHJvY2Vzc0xhdW5jaCB7XG4gIC8qKlxuICBUaGUgc3Bhd25lZCBwcm9jZXNzLlxuICAgKi9cbiAgcHJvY2VzczogQ2hpbGRQcm9jZXNzO1xuXG4gIC8qKlxuICBSZXR1cm5zIHRoZSBleGl0IC8gc3Bhd24tZmFpbHVyZSBkZXRhaWxzIG9uY2UgdGhlIHByb2Nlc3MgaXMgbm8gbG9uZ2VyIHJ1bm5pbmcsIG90aGVyd2lzZSBgdW5kZWZpbmVkYC5cbiAgICovXG4gIHJlYWRFeGl0SW5mbzogKCkgPT4gUHJvY2Vzc0V4aXRJbmZvIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICBSZXR1cm5zIHRoZSBjYXB0dXJlZCBzdGRvdXQrc3RkZXJyIChib3VuZGVkIHRvIHRoZSBtb3N0IHJlY2VudCBvdXRwdXQpLlxuICAgKi9cbiAgcmVhZE91dHB1dDogKCkgPT4gc3RyaW5nO1xuXG4gIC8qKlxuICBTdG9wcyBhY2N1bXVsYXRpbmcgb3V0cHV0LiBDYWxsIG9uY2Ugc3RhcnR1cCBoYXMgc3VjY2VlZGVkLlxuICAgKi9cbiAgc3RvcENhcHR1cmU6ICgpID0+IHZvaWQ7XG59XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3Ige0BsaW5rIEFwcGl1bVRyYW5zcG9ydEZhY3Rvcnkuc3RhcnRBcHBpdW1BbmRFbXVsYXRvcn0uXG4gKi9cbmludGVyZmFjZSBTdGFydEFwcGl1bUFuZEVtdWxhdG9yUGFyYW1zIHtcbiAgLyoqXG4gIFJlc29sdmVkIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgYXV0by1zdGFydGVkIEFwcGl1bSBzZXJ2ZXIgdG8gYmVjb21lIHJlYWR5LlxuICAgKi9cbiAgcmVhZG9ubHkgYXBwaXVtU3RhcnRUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcjtcblxuICAvKipcbiAgVGhlIEFwcGl1bSBzZXJ2ZXIgVVJMLlxuICAgKi9cbiAgcmVhZG9ubHkgYXBwaXVtVXJsOiBVUkw7XG5cbiAgLyoqXG4gIEFWRCBuYW1lIHRvIHN0YXJ0LlxuICAgKi9cbiAgcmVhZG9ubHkgYXZkTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICBSZXNvbHZlZCB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIHBvc3QtYm9vdCBkZXZpY2UtaWRsZSB3YWl0IChgMGAgc2tpcHMgaXQpLlxuICAgKi9cbiAgcmVhZG9ubHkgZGV2aWNlSWRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kczogbnVtYmVyO1xuXG4gIC8qKlxuICBXaGV0aGVyIHRoZSBhdXRvLXN0YXJ0ZWQgQXBwaXVtIHNlcnZlciBjb25zb2xlIHdpbmRvdyBpcyBzaG93biAob21pdHRlZCBcdTIxOTIgaGlkZGVuKS5cbiAgICovXG4gIHJlYWRvbmx5IGlzQXBwaXVtQ29uc29sZVZpc2libGU/OiBib29sZWFuIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICBXaGV0aGVyIHRoZSBhdXRvLXN0YXJ0ZWQgZW11bGF0b3Igd2luZG93IGlzIHNob3duIChvbWl0dGVkIFx1MjE5MiBoaWRkZW4pLlxuICAgKi9cbiAgcmVhZG9ubHkgaXNFbXVsYXRvclZpc2libGU/OiBib29sZWFuIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICBUaGUgQXBwaXVtIHNlcnZlciBwb3J0LlxuICAgKi9cbiAgcmVhZG9ubHkgcG9ydDogbnVtYmVyO1xuXG4gIC8qKlxuICBXaGV0aGVyIG1pc3NpbmcgQXBwaXVtIGRlcGVuZGVuY2llcyBtYXkgYmUgYXV0by1pbnN0YWxsZWQgYmVmb3JlIHRoZSBzZXJ2ZXIgaXMgYXV0by1zdGFydGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgc2hvdWxkQXV0b0luc3RhbGxBcHBpdW1EZXBlbmRlbmNpZXM6IGJvb2xlYW47XG5cbiAgLyoqXG4gIFdoZXRoZXIgQXBwaXVtIGF1dG8tc3RhcnQgaXMgYWxsb3dlZC5cbiAgICovXG4gIHJlYWRvbmx5IHNob3VsZEF1dG9TdGFydEFwcGl1bT86IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogUmVzdWx0IG9mIHtAbGluayBBcHBpdW1UcmFuc3BvcnRGYWN0b3J5LnN0YXJ0QXBwaXVtQW5kRW11bGF0b3J9LlxuICovXG5pbnRlcmZhY2UgU3RhcnRBcHBpdW1BbmRFbXVsYXRvclJlc3VsdCB7XG4gIC8qKlxuICBUaGUgYWN0dWFsIGRldmljZSBJRCB0aGF0IGlzIGNvbm5lY3RlZCAobWF5IGRpZmZlciBmcm9tIHRoZSByZXF1ZXN0ZWQgb25lKS5cbiAgICovXG4gIHJlYWRvbmx5IGFjdHVhbERldmljZUlkOiBzdHJpbmc7XG5cbiAgLyoqXG4gIFRoZSBBcHBpdW0gc2VydmVyIHByb2Nlc3MsIGlmIG9uZSB3YXMgYXV0by1zdGFydGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgYXBwaXVtUHJvY2Vzcz86IENoaWxkUHJvY2VzcyB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgVGhlIGFkb3B0ZWQgc2VydmVyJ3MgbWFya2VyLCB3aGVuIGFuIGVhcmxpZXIgcnVuIG9mIHRoaXMgaGFybmVzcyBsZWZ0IG9uZS5cbiAgICovXG4gIHJlYWRvbmx5IGFwcGl1bVNlcnZlck1hcmtlcj86IEFwcGl1bVNlcnZlck1hcmtlciB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgVGhlIGVtdWxhdG9yIHByb2Nlc3MsIGlmIG9uZSB3YXMgYXV0by1zdGFydGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgZW11bGF0b3JQcm9jZXNzPzogQ2hpbGRQcm9jZXNzIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIGFuIGFscmVhZHktbGlzdGVuaW5nIHNlcnZlciB3YXMgYWRvcHRlZCByYXRoZXIgdGhhbiBzdGFydGVkIGJ5IHRoaXNcbiAgICogcnVuLiBPbmx5IGFuIGFkb3B0ZWQgc2VydmVyIGNhbiBiZSB0aGUgc3RhbGUgb25lIGB3ZWRnZWQtYXBwaXVtLXNlcnZlci50c2BcbiAgICogZGVzY3JpYmVzLlxuICAgKi9cbiAgcmVhZG9ubHkgaXNBZG9wdGVkQXBwaXVtU2VydmVyOiBib29sZWFuO1xufVxuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHtAbGluayBBcHBpdW1UcmFuc3BvcnRGYWN0b3J5LnN3ZWVwRGV2aWNlTGVmdG92ZXJWYXVsdHN9LlxuICovXG5pbnRlcmZhY2UgU3dlZXBEZXZpY2VMZWZ0b3ZlclZhdWx0c1BhcmFtcyB7XG4gIC8qKlxuICBUaGUgZGV2aWNlIFVESUQgdG8gc3dlZXAuXG4gICAqL1xuICByZWFkb25seSBkZXZpY2VJZDogc3RyaW5nO1xuXG4gIC8qKlxuICBUaGUgZGV2aWNlLXNpZGUgZGlyZWN0b3J5IE9ic2lkaWFuIE1vYmlsZSBzdG9yZXMgaXRzIHZhdWx0cyBpbi5cbiAgICovXG4gIHJlYWRvbmx5IHZhdWx0QmFzZVBhdGg6IHN0cmluZztcbn1cblxubGV0IGNhY2hlZFRyYW5zcG9ydDogT2JzaWRpYW5UcmFuc3BvcnQgfCB1bmRlZmluZWQ7XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3Ige0BsaW5rIHJlc29sdmVBbmRSZXBvcnRDb21wYXRpYmlsaXR5fS5cbiAqL1xuaW50ZXJmYWNlIFJlc29sdmVBbmRSZXBvcnRDb21wYXRpYmlsaXR5UGFyYW1zIHtcbiAgLyoqXG4gICAqIFRoZSBhcHAgKGFzYXIpIHZlcnNpb24gdGhhdCB3aWxsIGJlIHN3YXBwZWQgb250byB0aGUgc2hlbGwsIG9yIGB1bmRlZmluZWRgXG4gICAqIHdoZW4gbm8gYXNhci1zd2FwIHdpbGwgaGFwcGVuIChub3RoaW5nIGlzIGNoZWNrZWQgdGhlbikuXG4gICAqL1xuICByZWFkb25seSBhcHBWZXJzaW9uOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSByZXNvbHZlZCBpbnN0YWxsZXIvc2hlbGwgdmVyc2lvbiwgb3IgYHVuZGVmaW5lZGAuXG4gICAqL1xuICByZWFkb25seSBpbnN0YWxsZXJWZXJzaW9uOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgYW4gYCd1bnJ1bm5hYmxlJ2AgdmVyZGljdCB0aHJvd3Mge0BsaW5rIEluY29tcGF0aWJsZUluc3RhbGxlclZlcnNpb25FcnJvcn1cbiAgICogKGB0cnVlYCkgb3IgcHJvY2VlZHMgdG8gbGF1bmNoIHdpdGggdGhlIHZlcmRpY3Qgc3VyZmFjZWQgYXMgZGF0YSAoYGZhbHNlYCkuXG4gICAqL1xuICByZWFkb25seSBzaG91bGRUaHJvd09uSW5jb21wYXRpYmxlSW5zdGFsbGVyOiBib29sZWFuO1xuXG4gIC8qKlxuICBXaGV0aGVyIGEgYCduYWdnZWQnYCAob3IgcHJvY2VlZGluZy1gJ3VucnVubmFibGUnYCkgdmVyZGljdCBpcyBsb2dnZWQuXG4gICAqL1xuICByZWFkb25seSBzaG91bGRXYXJuT25Db21wYXRpYmlsaXR5SXNzdWVzOiBib29sZWFuO1xufVxuXG4vKipcbiAqIFRoZSBzbGljZSBvZiBgd2ViZHJpdmVyaW9gJ3Mgc3VyZmFjZSB0aGUgQXBwaXVtIGZhY3RvcnkgY2FsbHMsIG5hbWVkIHNvIHRoZVxuICogbGF6eSBsb2FkIGhhcyBhIHJldHVybiB0eXBlIHdpdGhvdXQgYSBzdGF0aWMgaW1wb3J0IG9mIHRoZSBtb2R1bGUgaXRzZWxmLlxuICovXG5pbnRlcmZhY2UgV2ViZHJpdmVyaW9Nb2R1bGUge1xuICAvKipcbiAgUmVhdHRhY2hlcyB0byBhbiBleGlzdGluZyBXZWJEcml2ZXIgc2Vzc2lvbi5cbiAgICovXG4gIHJlYWRvbmx5IGF0dGFjaDogdHlwZW9mIGF0dGFjaDtcblxuICAvKipcbiAgQ3JlYXRlcyBhIG5ldyBXZWJEcml2ZXIgc2Vzc2lvbi5cbiAgICovXG4gIHJlYWRvbmx5IHJlbW90ZTogdHlwZW9mIHJlbW90ZTtcbn1cblxuLyoqXG4gKiBFbmNhcHN1bGF0ZXMgYWxsIEFwcGl1bSB0cmFuc3BvcnQgY3JlYXRpb24gbG9naWMsIGluY2x1ZGluZyBBcHBpdW0gc2VydmVyXG4gKiBzdGFydHVwLCBlbXVsYXRvciBtYW5hZ2VtZW50LCBhbmQgV2ViRHJpdmVySU8gc2Vzc2lvbiBlc3RhYmxpc2htZW50LlxuICpcbiAqIFVzaW5nIGEgY2xhc3MgYXZvaWRzIHRocmVhZGluZyB0aGUgdHJhbnNwb3J0IGB0eXBlYCBsYWJlbCB0aHJvdWdoIGV2ZXJ5XG4gKiBoZWxwZXIgZnVuY3Rpb24gXHUyMDE0IGB0aGlzLmxvZygpYCBhdXRvbWF0aWNhbGx5IHByZWZpeGVzIGl0LlxuICovXG5jbGFzcyBBcHBpdW1UcmFuc3BvcnRGYWN0b3J5IHtcbiAgcHJpdmF0ZSByZWFkb25seSB0eXBlOiBzdHJpbmc7XG5cbiAgcHVibGljIGNvbnN0cnVjdG9yKHR5cGU6IHN0cmluZykge1xuICAgIHRoaXMudHlwZSA9IHR5cGU7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhbiBBcHBpdW0gdHJhbnNwb3J0IGJ5IGVzdGFibGlzaGluZyBhIFdlYkRyaXZlcklPIHNlc3Npb24uXG4gICAqXG4gICAqIElmIGBvcHRpb25zLnNlc3Npb25JZGAgaXMgcHJlc2VudCwgcmVhdHRhY2hlcyB0byB0aGUgZXhpc3Rpbmcgc2Vzc2lvblxuICAgKiBpbnN0ZWFkIG9mIGNyZWF0aW5nIGEgbmV3IG9uZS4gVGhpcyBhdm9pZHMgZHVwbGljYXRlIEFwcGl1bS9BREIgY29ubmVjdGlvbnNcbiAgICogd2hlbiB0ZXN0IHdvcmtlcnMgcmV1c2UgdGhlIGdsb2JhbCBzZXR1cCdzIHNlc3Npb24uXG4gICAqXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gQW5kcm9pZCBBcHBpdW0gdHJhbnNwb3J0IG9wdGlvbnMuXG4gICAqIEByZXR1cm5zIEEgY29uZmlndXJlZCBBcHBpdW0gdHJhbnNwb3J0LlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGNyZWF0ZShvcHRpb25zOiBPYnNpZGlhbkFuZHJvaWRBcHBpdW1UcmFuc3BvcnRPcHRpb25zKTogUHJvbWlzZTxPYnNpZGlhblRyYW5zcG9ydD4ge1xuICAgIGlmIChvcHRpb25zLnNlc3Npb25JZCAhPT0gdW5kZWZpbmVkICYmIG9wdGlvbnMuZGV2aWNlSWQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHRoaXMuYXR0YWNoVG9FeGlzdGluZ1Nlc3Npb24ob3B0aW9ucy5zZXNzaW9uSWQsIG9wdGlvbnMuZGV2aWNlSWQsIG9wdGlvbnMpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmNyZWF0ZU5ld1Nlc3Npb24ob3B0aW9ucyk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGF0dGFjaFRvRXhpc3RpbmdTZXNzaW9uKFxuICAgIHNlc3Npb25JZDogc3RyaW5nLFxuICAgIGRldmljZUlkOiBzdHJpbmcsXG4gICAgb3B0aW9uczogT2JzaWRpYW5BbmRyb2lkQXBwaXVtVHJhbnNwb3J0T3B0aW9uc1xuICApOiBQcm9taXNlPE9ic2lkaWFuVHJhbnNwb3J0PiB7XG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChvcHRpb25zLmFwcGl1bVVybCk7XG4gICAgY29uc3QgcG9ydCA9IE51bWJlcih1cmwucG9ydCk7XG4gICAgY29uc3QgYXBwSWQgPSBvcHRpb25zLmFwcElkID8/IEFQUF9QQUNLQUdFO1xuXG4gICAgdGhpcy5sb2coYFJlYXR0YWNoaW5nIHRvIGV4aXN0aW5nIEFwcGl1bSBzZXNzaW9uICR7c2Vzc2lvbklkfSAoZGV2aWNlPSR7ZGV2aWNlSWR9KWApO1xuXG4gICAgY29uc3QgeyBhdHRhY2ggfSA9IGF3YWl0IGltcG9ydFdlYmRyaXZlcmlvKCk7XG4gICAgY29uc3QgYnJvd3NlciA9IGF3YWl0IGF0dGFjaCh7XG4gICAgICBjYXBhYmlsaXRpZXM6IHtcbiAgICAgICAgcGxhdGZvcm1OYW1lOiAnQW5kcm9pZCdcbiAgICAgIH0sXG4gICAgICBob3N0bmFtZTogdXJsLmhvc3RuYW1lLFxuICAgICAgbG9nTGV2ZWw6ICd3YXJuJyxcbiAgICAgIHBhdGg6IHVybC5wYXRobmFtZSxcbiAgICAgIHBvcnQsXG4gICAgICBzZXNzaW9uSWQsXG4gICAgICB0cmFuc2Zvcm1SZXF1ZXN0OiBzdHJpcEZvcmJpZGRlbkZldGNoSGVhZGVyc1xuICAgIH0pO1xuXG4gICAgdGhpcy5sb2coJ1JlYXR0YWNoZWQgdG8gQXBwaXVtIHNlc3Npb24uJyk7XG5cbiAgICByZXR1cm4gbmV3IEFwcGl1bVRyYW5zcG9ydCh7XG4gICAgICBhcHBJZCxcbiAgICAgIGJyb3dzZXIsXG4gICAgICBkZXZpY2VJZCxcbiAgICAgIGlzU2Vzc2lvbk93bmVyOiBmYWxzZSxcbiAgICAgIHBsYXRmb3JtOiAnYW5kcm9pZCcsXG4gICAgICBzaG91bGRTd2VlcExlZnRvdmVyczogd2lsbFN3ZWVwTGVmdG92ZXJzKG9wdGlvbnMpLFxuICAgICAgLi4uKG9wdGlvbnMubGF5b3V0UmVhZHlUaW1lb3V0SW5NaWxsaXNlY29uZHMgIT09IHVuZGVmaW5lZCAmJiB7IGxheW91dFJlYWR5VGltZW91dEluTWlsbGlzZWNvbmRzOiBvcHRpb25zLmxheW91dFJlYWR5VGltZW91dEluTWlsbGlzZWNvbmRzIH0pLFxuICAgICAgLi4uKG9wdGlvbnMudmF1bHRCYXNlUGF0aCAhPT0gdW5kZWZpbmVkICYmIHsgdmF1bHRCYXNlUGF0aDogb3B0aW9ucy52YXVsdEJhc2VQYXRoIH0pLFxuICAgICAgLi4uKG9wdGlvbnMud2Vidmlld1RpbWVvdXRJbk1pbGxpc2Vjb25kcyAhPT0gdW5kZWZpbmVkICYmIHsgd2Vidmlld1RpbWVvdXRJbk1pbGxpc2Vjb25kczogb3B0aW9ucy53ZWJ2aWV3VGltZW91dEluTWlsbGlzZWNvbmRzIH0pXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGJ1aWxkV2VkZ2VkTWVzc2FnZShwYXJhbXM6IEVzdGFibGlzaFNlc3Npb25QYXJhbXMsIHJlYXNvbjogV2VkZ2VkQXBwaXVtU2VydmVyUmVwb3J0UmVhc29uKTogc3RyaW5nIHtcbiAgICBjb25zdCBtYXJrZXIgPSBwYXJhbXMuYXBwaXVtU2VydmVyTWFya2VyO1xuICAgIHJldHVybiBidWlsZFdlZGdlZEFwcGl1bVNlcnZlck1lc3NhZ2Uoe1xuICAgICAgYXBwaXVtT3JpZ2luOiBwYXJhbXMudXJsLm9yaWdpbixcbiAgICAgIGRldmljZUlkOiBwYXJhbXMuZGV2aWNlSWQsXG4gICAgICByZWFzb24sXG4gICAgICAuLi4obWFya2VyICE9PSB1bmRlZmluZWQgJiYge1xuICAgICAgICBzZXJ2ZXJBZ2VJbk1pbGxpc2Vjb25kczogRGF0ZS5ub3coKSAtIG1hcmtlci5zdGFydGVkQXRJbk1pbGxpc2Vjb25kcyxcbiAgICAgICAgc2VydmVyUGlkOiBtYXJrZXIucGlkXG4gICAgICB9KVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFByZWZsaWdodCBwcm9iZSBmb3IgYW4gYWxyZWFkeS1ydW5uaW5nIHNlcnZlci5cbiAgICpcbiAgICogTGl2ZW5lc3MgaXMgbm90IHJlYWRpbmVzczogcmVzb2x2aW5nIG9uICphbnkqIHJlc3BvbnNlIGFkb3B0cyBhIHNlcnZlciB0aGF0XG4gICAqIGlzIHJlZnVzaW5nIHNlc3Npb25zIChhIG5vbi0yeHggYC9zdGF0dXNgLCBvciBvbmUgdGhhdCByZXBvcnRzIGl0c2VsZlxuICAgKiBzaHV0dGluZyBkb3duKSBleGFjdGx5IGxpa2UgYSBoZWFsdGh5IG9uZS4gUmVqZWN0aW5nIGluc3RlYWQgaGFuZHMgdGhvc2VcbiAgICogY2FzZXMgdG8gdGhlIGF1dG8tc3RhcnQgcGF0aC4gSXQgY2Fubm90IGNhdGNoIHRoZSB3ZWRnZWQgc2VydmVyIG9mXG4gICAqIGB3ZWRnZWQtYXBwaXVtLXNlcnZlci50c2AgXHUyMDE0IHRoYXQgb25lIGFuc3dlcnMgYHJlYWR5OiB0cnVlYCBcdTIwMTQgd2hpY2ggaXMgd2h5XG4gICAqIHRoZSB3ZWRnZSBpcyByZWNvZ25pemVkIGZyb20gdGhlIGZhaWxlZCBzZXNzaW9uIGluc3RlYWQuXG4gICAqXG4gICAqIEBwYXJhbSB1cmwgLSBUaGUgQXBwaXVtIHNlcnZlciBVUkwuXG4gICAqL1xuICBwcml2YXRlIGNoZWNrQXBwaXVtUmVhY2hhYmxlKHVybDogVVJMKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IHN0YXR1c1VybCA9IG5ldyBVUkwoJy9zdGF0dXMnLCB1cmwpO1xuICAgICAgLypcbiAgICAgICAqIGBhZ2VudDogZmFsc2VgIFx1MjAxNCBuZXZlciBhIHBvb2xlZCBzb2NrZXQuIFRoZSBnbG9iYWwgYWdlbnQga2VlcHMgc29ja2V0c1xuICAgICAgICogYWxpdmUgcGVyIGhvc3Q6cG9ydCwgc28gYSBwcm9iZSBhZnRlciBhIHNlcnZlciBvbiB0aGF0IHBvcnQgd2FzIHJlcGxhY2VkXG4gICAgICAgKiBjYW4gcmV1c2UgdGhlIGRlYWQgc29ja2V0IGFuZCBmYWlsIHdpdGggYEVDT05OUkVTRVRgIHJlZ2FyZGxlc3Mgb2Ygd2hhdFxuICAgICAgICogaXMgbGlzdGVuaW5nIG5vdy4gVGhhdCB3b3VsZCBtYWtlIGB3YWl0Rm9yQXBwaXVtU3RvcHBlZGAgY2FsbCBhIGxpdmVcbiAgICAgICAqIHNlcnZlciBkZWFkLCBhbmQgaXQgaXMgZXhhY3RseSB0aGUgc2VxdWVuY2UgdGhlIHdlZGdlZC1zZXJ2ZXIgcmVzdGFydFxuICAgICAgICogcGVyZm9ybXMuIEEgZnJlc2ggc29ja2V0IHBlciBwcm9iZSBjb3N0cyBub3RoaW5nIGF0IHRoaXMgZnJlcXVlbmN5LlxuICAgICAgICovXG4gICAgICBjb25zdCByZXF1ZXN0ID0gaHR0cC5nZXQoc3RhdHVzVXJsLCB7IGFnZW50OiBmYWxzZSwgdGltZW91dDogQVBQSVVNX1BSRUZMSUdIVF9USU1FT1VUX0lOX01JTExJU0VDT05EUyB9LCAocmVzcG9uc2UpID0+IHtcbiAgICAgICAgY29uc3Qgc3RhdHVzQ29kZSA9IHJlc3BvbnNlLnN0YXR1c0NvZGUgPz8gMDtcbiAgICAgICAgaWYgKHN0YXR1c0NvZGUgPCBIVFRQX09LIHx8IHN0YXR1c0NvZGUgPj0gSFRUUF9NVUxUSVBMRV9DSE9JQ0VTKSB7XG4gICAgICAgICAgcmVzcG9uc2UucmVzdW1lKCk7XG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgQXBwaXVtIHNlcnZlciBhdCAke3VybC5vcmlnaW59IGFuc3dlcmVkIC9zdGF0dXMgd2l0aCBIVFRQICR7U3RyaW5nKHN0YXR1c0NvZGUpfTsgaXQgaXMgbm90IGFjY2VwdGluZyBzZXNzaW9ucy5gKSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgcmVzcG9uc2Uuc2V0RW5jb2RpbmcoJ3V0Zi04Jyk7XG4gICAgICAgIGxldCBib2R5ID0gJyc7XG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICBib2R5ICs9IGNodW5rO1xuICAgICAgICB9KTtcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcbiAgICAgICAgICBpZiAoY2hlY2tJc0FwcGl1bVN0YXR1c1JlYWR5KGJvZHkpKSB7XG4gICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgQXBwaXVtIHNlcnZlciBhdCAke3VybC5vcmlnaW59IHJlcG9ydHMgaXQgaXMgbm90IHJlYWR5IHRvIGFjY2VwdCBuZXcgY29ubmVjdGlvbnMuYCkpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgICAgcmVxdWVzdC5vbigndGltZW91dCcsICgpID0+IHtcbiAgICAgICAgcmVxdWVzdC5kZXN0cm95KCk7XG4gICAgICAgIHJlamVjdChcbiAgICAgICAgICBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgQXBwaXVtIHNlcnZlciBhdCAke3VybC5vcmlnaW59IGRpZCBub3QgcmVzcG9uZCB3aXRoaW4gJHtTdHJpbmcoQVBQSVVNX1BSRUZMSUdIVF9USU1FT1VUX0lOX01JTExJU0VDT05EUyl9bXMuIElzIHRoZSBBcHBpdW0gc2VydmVyIHJ1bm5pbmc/YFxuICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuICAgICAgcmVxdWVzdC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgICAgcmVqZWN0KFxuICAgICAgICAgIG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBDYW5ub3QgcmVhY2ggQXBwaXVtIHNlcnZlciBhdCAke3VybC5vcmlnaW59OiAke2Vycm9yLm1lc3NhZ2V9LiBJcyB0aGUgQXBwaXVtIHNlcnZlciBydW5uaW5nP2BcbiAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY29ubmVjdFNlc3Npb24ocGFyYW1zOiBFc3RhYmxpc2hTZXNzaW9uUGFyYW1zKTogUHJvbWlzZTxBd2FpdGVkPFJldHVyblR5cGU8dHlwZW9mIHJlbW90ZT4+PiB7XG4gICAgY29uc3QgeyByZW1vdGUgfSA9IGF3YWl0IGltcG9ydFdlYmRyaXZlcmlvKCk7XG4gICAgcmV0dXJuIHJlbW90ZSh7XG4gICAgICBjYXBhYmlsaXRpZXM6IHtcbiAgICAgICAgJ2FwcGl1bTphcHBBY3Rpdml0eSc6IEFQUF9BQ1RJVklUWSxcbiAgICAgICAgJ2FwcGl1bTphcHBQYWNrYWdlJzogcGFyYW1zLmFwcElkLFxuICAgICAgICAnYXBwaXVtOmF1dG9HcmFudFBlcm1pc3Npb25zJzogdHJ1ZSxcbiAgICAgICAgJ2FwcGl1bTphdXRvbWF0aW9uTmFtZSc6ICdVaUF1dG9tYXRvcjInLFxuICAgICAgICAnYXBwaXVtOm5ld0NvbW1hbmRUaW1lb3V0JzogQ09NTUFORF9USU1FT1VUX0lOX01JTExJU0VDT05EUyxcbiAgICAgICAgJ2FwcGl1bTpub1Jlc2V0JzogdHJ1ZSxcbiAgICAgICAgJ2FwcGl1bTp1ZGlkJzogcGFyYW1zLmRldmljZUlkLFxuICAgICAgICAnYXBwaXVtOnVpYXV0b21hdG9yMlNlcnZlckluc3RhbGxUaW1lb3V0JzogU0VSVkVSX0lOU1RBTExfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMsXG4gICAgICAgICdhcHBpdW06dWlhdXRvbWF0b3IyU2VydmVyTGF1bmNoVGltZW91dCc6IFNFUlZFUl9MQVVOQ0hfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMsXG4gICAgICAgICdwbGF0Zm9ybU5hbWUnOiAnQW5kcm9pZCdcbiAgICAgIH0sXG4gICAgICBjb25uZWN0aW9uUmV0cnlDb3VudDogQVBQSVVNX0NPTk5FQ1RJT05fUkVUUllfQ09VTlQsXG4gICAgICBjb25uZWN0aW9uUmV0cnlUaW1lb3V0OiBwYXJhbXMuc2Vzc2lvbkNvbm5lY3Rpb25SZXRyeVRpbWVvdXRJbk1pbGxpc2Vjb25kcyxcbiAgICAgIGhvc3RuYW1lOiBwYXJhbXMudXJsLmhvc3RuYW1lLFxuICAgICAgbG9nTGV2ZWw6ICd3YXJuJyxcbiAgICAgIHBhdGg6IHBhcmFtcy51cmwucGF0aG5hbWUsXG4gICAgICBwb3J0OiBwYXJhbXMucG9ydCxcbiAgICAgIHRyYW5zZm9ybVJlcXVlc3Q6IHN0cmlwRm9yYmlkZGVuRmV0Y2hIZWFkZXJzXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNyZWF0ZU5ld1Nlc3Npb24ob3B0aW9uczogT2JzaWRpYW5BbmRyb2lkQXBwaXVtVHJhbnNwb3J0T3B0aW9ucyk6IFByb21pc2U8T2JzaWRpYW5UcmFuc3BvcnQ+IHtcbiAgICB0aGlzLmxvZyhgQ3JlYXRpbmcgQXBwaXVtVHJhbnNwb3J0ICh1cmw9JHtvcHRpb25zLmFwcGl1bVVybH0sIGF2ZD0ke29wdGlvbnMuYXZkTmFtZX0pYCk7XG5cbiAgICBjb25zdCB1cmwgPSBuZXcgVVJMKG9wdGlvbnMuYXBwaXVtVXJsKTtcblxuICAgIGNvbnN0IHBvcnQgPSBOdW1iZXIodXJsLnBvcnQpO1xuICAgIGlmIChOdW1iZXIuaXNOYU4ocG9ydCkpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoYEludmFsaWQgcG9ydCBpbiBhcHBpdW1Vcmw6ICR7dXJsLnBvcnR9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgYXBwSWQgPSBvcHRpb25zLmFwcElkID8/IEFQUF9QQUNLQUdFO1xuXG4gICAgbGV0IGFwcGl1bVByb2Nlc3M6IENoaWxkUHJvY2VzcyB8IHVuZGVmaW5lZDtcbiAgICBsZXQgZW11bGF0b3JQcm9jZXNzOiBDaGlsZFByb2Nlc3MgfCB1bmRlZmluZWQ7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5zdGFydEFwcGl1bUFuZEVtdWxhdG9yKHtcbiAgICAgICAgYXBwaXVtU3RhcnRUaW1lb3V0SW5NaWxsaXNlY29uZHM6IHJlc29sdmVBcHBpdW1TdGFydFRpbWVvdXRJbk1pbGxpc2Vjb25kcyhvcHRpb25zKSxcbiAgICAgICAgYXBwaXVtVXJsOiB1cmwsXG4gICAgICAgIGF2ZE5hbWU6IG9wdGlvbnMuYXZkTmFtZSxcbiAgICAgICAgZGV2aWNlSWRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kczogcmVzb2x2ZURldmljZUlkbGVUaW1lb3V0SW5NaWxsaXNlY29uZHMob3B0aW9ucyksXG4gICAgICAgIGlzQXBwaXVtQ29uc29sZVZpc2libGU6IG9wdGlvbnMuaXNBcHBpdW1Db25zb2xlVmlzaWJsZSxcbiAgICAgICAgaXNFbXVsYXRvclZpc2libGU6IG9wdGlvbnMuaXNFbXVsYXRvclZpc2libGUsXG4gICAgICAgIHBvcnQsXG4gICAgICAgIHNob3VsZEF1dG9JbnN0YWxsQXBwaXVtRGVwZW5kZW5jaWVzOiB3aWxsQXV0b0luc3RhbGxBcHBpdW1EZXBlbmRlbmNpZXMob3B0aW9ucyksXG4gICAgICAgIHNob3VsZEF1dG9TdGFydEFwcGl1bTogb3B0aW9ucy5zaG91bGRBdXRvU3RhcnRBcHBpdW1cbiAgICAgIH0pO1xuXG4gICAgICBhcHBpdW1Qcm9jZXNzID0gcmVzdWx0LmFwcGl1bVByb2Nlc3M7XG4gICAgICBlbXVsYXRvclByb2Nlc3MgPSByZXN1bHQuZW11bGF0b3JQcm9jZXNzO1xuICAgICAgY29uc3QgYWN0dWFsRGV2aWNlSWQgPSByZXN1bHQuYWN0dWFsRGV2aWNlSWQ7XG5cbiAgICAgIC8qXG4gICAgICAgKiBCZWZvcmUgYHJlbW90ZSgpYCBsYXVuY2hlcyBPYnNpZGlhbiBcdTIwMTQgdGhlIGxhc3QgcG9pbnQgYXQgd2hpY2ggbm90aGluZ1xuICAgICAgICogaGFzIHRvIGVudW1lcmF0ZSB0aGUgZGV2aWNlJ3MgdmF1bHRzIHlldC5cbiAgICAgICAqL1xuICAgICAgaWYgKHdpbGxTd2VlcExlZnRvdmVycyhvcHRpb25zKSkge1xuICAgICAgICBhd2FpdCB0aGlzLnN3ZWVwRGV2aWNlTGVmdG92ZXJWYXVsdHMoe1xuICAgICAgICAgIGRldmljZUlkOiBhY3R1YWxEZXZpY2VJZCxcbiAgICAgICAgICB2YXVsdEJhc2VQYXRoOiBvcHRpb25zLnZhdWx0QmFzZVBhdGggPz8gREVGQVVMVF9BTkRST0lEX1ZBVUxUX0JBU0VfUEFUSFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2Vzc2lvblJlc3VsdCA9IGF3YWl0IHRoaXMuZXN0YWJsaXNoU2Vzc2lvbih7XG4gICAgICAgIGFwcElkLFxuICAgICAgICBhcHBpdW1TZXJ2ZXJNYXJrZXI6IHJlc3VsdC5hcHBpdW1TZXJ2ZXJNYXJrZXIsXG4gICAgICAgIGFwcGl1bVN0YXJ0VGltZW91dEluTWlsbGlzZWNvbmRzOiByZXNvbHZlQXBwaXVtU3RhcnRUaW1lb3V0SW5NaWxsaXNlY29uZHMob3B0aW9ucyksXG4gICAgICAgIGRldmljZUlkOiBhY3R1YWxEZXZpY2VJZCxcbiAgICAgICAgaXNBZG9wdGVkU2VydmVyOiByZXN1bHQuaXNBZG9wdGVkQXBwaXVtU2VydmVyLFxuICAgICAgICBpc0FwcGl1bUNvbnNvbGVWaXNpYmxlOiBvcHRpb25zLmlzQXBwaXVtQ29uc29sZVZpc2libGUsXG4gICAgICAgIHBvcnQsXG4gICAgICAgIHNlc3Npb25Db25uZWN0aW9uUmV0cnlUaW1lb3V0SW5NaWxsaXNlY29uZHM6IHJlc29sdmVTZXNzaW9uQ29ubmVjdGlvblJldHJ5VGltZW91dEluTWlsbGlzZWNvbmRzKG9wdGlvbnMpLFxuICAgICAgICBzaG91bGRBdXRvU3RhcnRBcHBpdW06IG9wdGlvbnMuc2hvdWxkQXV0b1N0YXJ0QXBwaXVtLFxuICAgICAgICB1cmxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBicm93c2VyID0gc2Vzc2lvblJlc3VsdC5icm93c2VyO1xuICAgICAgLy8gQSB3ZWRnZWQgYWRvcHRlZCBzZXJ2ZXIgaXMgcmVwbGFjZWQgYnkgb25lIHRoaXMgcnVuIG93bnMsIHNvIGl0IG11c3QgYmUgdG9ybiBkb3duIGxpa2UgYW55IG90aGVyIGF1dG8tc3RhcnRlZCBzZXJ2ZXIuXG4gICAgICBhcHBpdW1Qcm9jZXNzID0gc2Vzc2lvblJlc3VsdC5hcHBpdW1Qcm9jZXNzID8/IGFwcGl1bVByb2Nlc3M7XG5cbiAgICAgIHRoaXMubG9nKCdBcHBpdW0gc2Vzc2lvbiBlc3RhYmxpc2hlZC4nKTtcbiAgICAgIGNvbnN0IGFwcGl1bVRyYW5zcG9ydCA9IG5ldyBBcHBpdW1UcmFuc3BvcnQoe1xuICAgICAgICBhcHBJZCxcbiAgICAgICAgYnJvd3NlcixcbiAgICAgICAgZGV2aWNlSWQ6IGFjdHVhbERldmljZUlkLFxuICAgICAgICBwbGF0Zm9ybTogJ2FuZHJvaWQnLFxuICAgICAgICBzaG91bGRTd2VlcExlZnRvdmVyczogd2lsbFN3ZWVwTGVmdG92ZXJzKG9wdGlvbnMpLFxuICAgICAgICAuLi4ob3B0aW9ucy5sYXlvdXRSZWFkeVRpbWVvdXRJbk1pbGxpc2Vjb25kcyAhPT0gdW5kZWZpbmVkICYmIHsgbGF5b3V0UmVhZHlUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG9wdGlvbnMubGF5b3V0UmVhZHlUaW1lb3V0SW5NaWxsaXNlY29uZHMgfSksXG4gICAgICAgIC4uLihvcHRpb25zLnZhdWx0QmFzZVBhdGggIT09IHVuZGVmaW5lZCAmJiB7IHZhdWx0QmFzZVBhdGg6IG9wdGlvbnMudmF1bHRCYXNlUGF0aCB9KSxcbiAgICAgICAgLi4uKG9wdGlvbnMud2Vidmlld1RpbWVvdXRJbk1pbGxpc2Vjb25kcyAhPT0gdW5kZWZpbmVkICYmIHsgd2Vidmlld1RpbWVvdXRJbk1pbGxpc2Vjb25kczogb3B0aW9ucy53ZWJ2aWV3VGltZW91dEluTWlsbGlzZWNvbmRzIH0pXG4gICAgICB9KTtcblxuICAgICAgY29uc3Qgb3JpZ2luYWxEaXNwb3NlID0gYXBwaXVtVHJhbnNwb3J0LmRpc3Bvc2UuYmluZChhcHBpdW1UcmFuc3BvcnQpO1xuICAgICAgY29uc3QgdHJhbnNwb3J0OiBPYnNpZGlhblRyYW5zcG9ydCA9IGFwcGl1bVRyYW5zcG9ydDtcbiAgICAgIHRyYW5zcG9ydC5kaXNwb3NlID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IG9yaWdpbmFsRGlzcG9zZSgpO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIGtpbGxBdXRvU3RhcnRlZFByb2Nlc3NlcygpO1xuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICAvLyBDaGFpbiByYXRoZXIgdGhhbiByZXBsYWNlOiB0aGUgdHJhbnNwb3J0J3Mgb3duIHN5bmMgdGVhcmRvd24gZHJvcHMgdGhlIHRydXN0ZWQtaW5wdXQgY2hhbm5lbCdzXG4gICAgICAvLyBBZGIgcG9ydCBmb3J3YXJkLCB3aGljaCB3b3VsZCBvdGhlcndpc2UgYmUgc3RyYW5kZWQgb24gdGhlIGRldmljZSBieSBhbiBhYnJ1cHQgZXhpdC5cbiAgICAgIGNvbnN0IG9yaWdpbmFsRGlzcG9zZVN5bmMgPSBhcHBpdW1UcmFuc3BvcnQuZGlzcG9zZVN5bmMuYmluZChhcHBpdW1UcmFuc3BvcnQpO1xuICAgICAgdHJhbnNwb3J0LmRpc3Bvc2VTeW5jID0gKCk6IHZvaWQgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIG9yaWdpbmFsRGlzcG9zZVN5bmMoKTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICBraWxsQXV0b1N0YXJ0ZWRQcm9jZXNzZXMoKTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgcmV0dXJuIHRyYW5zcG9ydDtcblxuICAgICAgZnVuY3Rpb24ga2lsbEF1dG9TdGFydGVkUHJvY2Vzc2VzKCk6IHZvaWQge1xuICAgICAgICBpZiAoYXBwaXVtUHJvY2Vzcykge1xuICAgICAgICAgIGtpbGxQcm9jZXNzVHJlZShhcHBpdW1Qcm9jZXNzKTtcbiAgICAgICAgICAvLyBEcm9wIHRoZSBtYXJrZXIgd2l0aCB0aGUgc2VydmVyIGl0IGRlc2NyaWJlcywgc28gdGhlIG5leHQgcnVuIGNhbm5vdCBtaXN0YWtlIGEgcmVjeWNsZWQgUElEIGZvciBvdXJzLlxuICAgICAgICAgIGNsZWFyQXBwaXVtU2VydmVyTWFya2VyKHBvcnQpO1xuICAgICAgICAgIC8vIENhbm5vdCB1c2UgdGhpcy5sb2cgaW5zaWRlIG5lc3RlZCBmdW5jdGlvbiBcdTIwMTQgYHRoaXNgIGlzIG5vdCBjYXB0dXJlZC5cbiAgICAgICAgICBsb2coYFt0cmFuc3BvcnQtZmFjdG9yeToke29wdGlvbnMudHlwZX1dIEF1dG8tc3RhcnRlZCBBcHBpdW0gc2VydmVyIHN0b3BwZWQuYCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVtdWxhdG9yUHJvY2Vzcykge1xuICAgICAgICAgIGtpbGxQcm9jZXNzVHJlZShlbXVsYXRvclByb2Nlc3MpO1xuICAgICAgICAgIGxvZyhgW3RyYW5zcG9ydC1mYWN0b3J5OiR7b3B0aW9ucy50eXBlfV0gQXV0by1zdGFydGVkIGVtdWxhdG9yIHN0b3BwZWQuYCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgaWYgKGFwcGl1bVByb2Nlc3MpIHtcbiAgICAgICAga2lsbFByb2Nlc3NUcmVlKGFwcGl1bVByb2Nlc3MpO1xuICAgICAgICBjbGVhckFwcGl1bVNlcnZlck1hcmtlcihwb3J0KTtcbiAgICAgICAgdGhpcy5sb2coJ0tpbGxlZCBhdXRvLXN0YXJ0ZWQgQXBwaXVtIHNlcnZlciBhZnRlciBjb25uZWN0aW9uIGZhaWx1cmUuJyk7XG4gICAgICB9XG4gICAgICBpZiAoZW11bGF0b3JQcm9jZXNzKSB7XG4gICAgICAgIGtpbGxQcm9jZXNzVHJlZShlbXVsYXRvclByb2Nlc3MpO1xuICAgICAgICB0aGlzLmxvZygnS2lsbGVkIGF1dG8tc3RhcnRlZCBlbXVsYXRvciBhZnRlciBjb25uZWN0aW9uIGZhaWx1cmUuJyk7XG4gICAgICB9XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRGVzY3JpYmVzIGFuIGFkb3B0ZWQgc2VydmVyJ3MgcHJvdmVuYW5jZSBmb3IgdGhlIHByZWZsaWdodCBsb2csIHNvIGEgc3RhbGVcbiAgICogbGVmdG92ZXIgaXMgdmlzaWJsZSBpbiB0aGUgdHJhbnNjcmlwdCBvZiBhIHJ1biB0aGF0IGdvZXMgb24gdG8gc3VjY2VlZCBcdTIwMTQgbm90XG4gICAqIG9ubHkgaW4gdGhlIGVycm9yIG9mIG9uZSB0aGF0IGZhaWxzLlxuICAgKlxuICAgKiBAcGFyYW0gbWFya2VyIC0gVGhlIG1hcmtlciByZWFkIGZvciB0aGUgcG9ydCwgaWYgYW55LlxuICAgKiBAcmV0dXJucyBBIHNob3J0IHByb3ZlbmFuY2UgZGVzY3JpcHRpb24uXG4gICAqL1xuICBwcml2YXRlIGRlc2NyaWJlQWRvcHRlZFNlcnZlcihtYXJrZXI6IEFwcGl1bVNlcnZlck1hcmtlciB8IHVuZGVmaW5lZCk6IHN0cmluZyB7XG4gICAgaWYgKCFtYXJrZXIgfHwgIWNoZWNrSXNIYXJuZXNzT3duZWRBcHBpdW1TZXJ2ZXIobWFya2VyKSkge1xuICAgICAgcmV0dXJuICdub3Qgc3RhcnRlZCBieSB0aGlzIGhhcm5lc3MnO1xuICAgIH1cblxuICAgIGNvbnN0IGFnZUluU2Vjb25kcyA9IE1hdGgucm91bmQoKERhdGUubm93KCkgLSBtYXJrZXIuc3RhcnRlZEF0SW5NaWxsaXNlY29uZHMpIC8gTUlMTElTRUNPTkRTX1BFUl9TRUNPTkQpO1xuICAgIHJldHVybiBgc3RhcnRlZCBieSBhbiBlYXJsaWVyIHJ1biBvZiB0aGlzIGhhcm5lc3MsIHBpZCAke1N0cmluZyhtYXJrZXIucGlkKX0sIHVwIGZvciAke1N0cmluZyhhZ2VJblNlY29uZHMpfXNgO1xuICB9XG5cbiAgLyoqXG4gICAqIEVuc3VyZXMgdGhlIEFwcGl1bSB0b29sY2hhaW4gaXMgcHJlc2VudCBiZWZvcmUgdGhlIHNlcnZlciBpcyBhdXRvLXN0YXJ0ZWQ6XG4gICAqIEFwcGl1bSBpdHNlbGYsIHRoZW4gdGhlIGB1aWF1dG9tYXRvcjJgIGRyaXZlci4gRWFjaCBpcyBjaGVja2VkIGZpcnN0IGFuZFxuICAgKiBpbnN0YWxsZWQgb25seSB3aGVuIG1pc3NpbmcsIHNvIGEgZnVsbHktcHJvdmlzaW9uZWQgbWFjaGluZSBpbmN1cnMganVzdCB0d29cbiAgICogZmFzdCB2ZXJzaW9uL2xpc3QgcHJvYmVzLlxuICAgKlxuICAgKiBPbmx5IGludm9rZWQgd2hlbiB0aGUgaGFybmVzcyBpcyBhYm91dCB0byBhdXRvLXN0YXJ0IHRoZSBzZXJ2ZXIgYW5kXG4gICAqIHtAbGluayBPYnNpZGlhbkFuZHJvaWRBcHBpdW1UcmFuc3BvcnRPcHRpb25zLnNob3VsZEF1dG9JbnN0YWxsQXBwaXVtRGVwZW5kZW5jaWVzfVxuICAgKiBpcyBlbmFibGVkLiBDb21tYW5kcyBhcmUgcGFzc2VkIGFzIHN0cmluZ3Mgc28gYGV4ZWNgIHJ1bnMgdGhlbSB0aHJvdWdoIHRoZVxuICAgKiBzaGVsbCwgd2hpY2ggcmVzb2x2ZXMgdGhlIGBucG1gL2BucHhgIGAuY21kYCBzaGltcyBvbiBXaW5kb3dzICh0aGUgYXJyYXlcbiAgICogcGF0aCBzcGF3bnMgd2l0aG91dCBhIHNoZWxsIGFuZCBjYW5ub3QpLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVBcHBpdW1EZXBlbmRlbmNpZXMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVBcHBpdW1JbnN0YWxsZWQoKTtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZVVpYXV0b21hdG9yMkRyaXZlckluc3RhbGxlZCgpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVBcHBpdW1JbnN0YWxsZWQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5sb2coJ0NoZWNraW5nIHdoZXRoZXIgQXBwaXVtIGlzIGluc3RhbGxlZC4uLicpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGV4ZWMoJ25weCAtLW5vLWluc3RhbGwgYXBwaXVtIC0tdmVyc2lvbicsIHtcbiAgICAgIGlzUXVpZXQ6IHRydWUsXG4gICAgICBzaG91bGRJZ25vcmVFeGl0Q29kZTogdHJ1ZSxcbiAgICAgIHNob3VsZEluY2x1ZGVEZXRhaWxzOiB0cnVlXG4gICAgfSk7XG5cbiAgICBpZiAocmVzdWx0LmV4aXRDb2RlID09PSAwKSB7XG4gICAgICB0aGlzLmxvZyhgQXBwaXVtIGlzIGluc3RhbGxlZCAodmVyc2lvbiAke3Jlc3VsdC5zdGRvdXQudHJpbSgpIHx8ICd1bmtub3duJ30pLmApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMubG9nKCdBcHBpdW0gaXMgbm90IGluc3RhbGxlZC4gSW5zdGFsbGluZyBnbG9iYWxseSB2aWEgYG5wbSBpbnN0YWxsIC1nIGFwcGl1bWAuLi4nKTtcbiAgICBhd2FpdCBleGVjKCducG0gaW5zdGFsbCAtZyBhcHBpdW0nKTtcblxuICAgIC8qXG4gICAgICogUmUtdmVyaWZ5OiBhIGdsb2JhbCBpbnN0YWxsIGNhbiBsYW5kIHVuZGVyIGFuIG5wbSBwcmVmaXggd2hvc2UgYmluIGRpciBpc1xuICAgICAqIG5vdCBvbiB0aGUgc3Bhd24gUEFUSCAoZS5nLiBhIHNjb29wL252bS1tYW5hZ2VkIHByZWZpeCksIGluIHdoaWNoIGNhc2VcbiAgICAgKiBgbnB4IC0tbm8taW5zdGFsbCBhcHBpdW1gIHN0aWxsIGNhbm5vdCByZXNvbHZlIGl0LiBGYWlsIGZhc3Qgd2l0aCBhblxuICAgICAqIGFjdGlvbmFibGUgbWVzc2FnZSByYXRoZXIgdGhhbiBwcm9jZWVkaW5nIHRvIGF1dG8tc3RhcnQgYSBzZXJ2ZXIgdGhhdCBjYW5cbiAgICAgKiBuZXZlciBjb21lIHVwICh3aGljaCB3b3VsZCBvdGhlcndpc2Ugc3BpbiBvdXQgdGhlIGZ1bGwgcmVhZGluZXNzIHRpbWVvdXQpLlxuICAgICAqL1xuICAgIGNvbnN0IHZlcmlmeSA9IGF3YWl0IGV4ZWMoJ25weCAtLW5vLWluc3RhbGwgYXBwaXVtIC0tdmVyc2lvbicsIHtcbiAgICAgIGlzUXVpZXQ6IHRydWUsXG4gICAgICBzaG91bGRJZ25vcmVFeGl0Q29kZTogdHJ1ZSxcbiAgICAgIHNob3VsZEluY2x1ZGVEZXRhaWxzOiB0cnVlXG4gICAgfSk7XG4gICAgaWYgKHZlcmlmeS5leGl0Q29kZSAhPT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnQXBwaXVtIHdhcyBpbnN0YWxsZWQgdmlhIGBucG0gaW5zdGFsbCAtZyBhcHBpdW1gIGJ1dCBpcyBzdGlsbCBub3QgcmVzb2x2YWJsZSB2aWEgYG5weCAtLW5vLWluc3RhbGwgYXBwaXVtYC4gJ1xuICAgICAgICAgICsgJ1RoZSBucG0gZ2xvYmFsIGJpbiBkaXJlY3RvcnkgKHNlZSBgbnBtIGNvbmZpZyBnZXQgcHJlZml4YCkgaXMgbGlrZWx5IG5vdCBvbiBQQVRILiBBZGQgaXQgdG8gUEFUSCwgb3Igc2V0ICdcbiAgICAgICAgICArICdgc2hvdWxkQXV0b0luc3RhbGxBcHBpdW1EZXBlbmRlbmNpZXM6IGZhbHNlYCBhbmQgaW5zdGFsbC9tYW5hZ2UgQXBwaXVtIHlvdXJzZWxmLidcbiAgICAgICk7XG4gICAgfVxuICAgIHRoaXMubG9nKGBBcHBpdW0gaW5zdGFsbGVkICh2ZXJzaW9uICR7dmVyaWZ5LnN0ZG91dC50cmltKCkgfHwgJ3Vua25vd24nfSkuYCk7XG4gIH1cblxuICAvKipcbiAgICogRmFpbHMgZmFzdCB3aGVuIHRoZSByZXF1ZXN0ZWQgQVZEIGRvZXMgbm90IGV4aXN0LCBiZWZvcmUgYW4gZW11bGF0b3IgaXNcbiAgICogc3Bhd25lZC5cbiAgICpcbiAgICogV2l0aG91dCB0aGlzIHByZWZsaWdodCBhIG1pc3NpbmcgQVZEIG5hbWUgaXMgb25seSBkaXNjb3ZlcmVkIGFmdGVyXG4gICAqIHtAbGluayBzdGFydEVtdWxhdG9yfSBzcGF3bnMgYGVtdWxhdG9yIC1hdmQgPG5hbWU+YCBhbmQgdGhlIGJvb3QgbmV2ZXJcbiAgICogY29tcGxldGVzIFx1MjAxNCBhIGZ1bGwge0BsaW5rIEVNVUxBVE9SX0JPT1RfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFN9IHNwaW4gZW5kaW5nXG4gICAqIGluIGEgZ2VuZXJpYyBcIm5vIG5ldyBkZXZpY2UgYXBwZWFyZWRcIi4gSW5zdGVhZCB0aGlzIGxpc3RzIHRoZSBjb25maWd1cmVkXG4gICAqIEFWRHMgdXAgZnJvbnQgYW5kIHRocm93cyBhbiBhY3Rpb25hYmxlIGVycm9yIG5hbWluZyB0aGUgYXZhaWxhYmxlIG9uZXMuIEFWRFxuICAgKiBjcmVhdGlvbiBpcyBkZWxpYmVyYXRlbHkgbm90IGF1dG9tYXRlZCAoaXQgcmVxdWlyZXMgYSBzeXN0ZW0taW1hZ2UgZG93bmxvYWQsXG4gICAqIGxpY2Vuc2UgYWNjZXB0YW5jZSwgYW5kIGhhcmR3YXJlL0FQSS1sZXZlbCBjaG9pY2VzKS5cbiAgICpcbiAgICogQHBhcmFtIGF2ZE5hbWUgLSBUaGUgcmVxdWVzdGVkIEFWRCBuYW1lLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVBdmRFeGlzdHMoYXZkTmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZW11bGF0b3JCaW5hcnkgPSB0aGlzLnJlc29sdmVFbXVsYXRvckJpbmFyeSgpO1xuICAgIHRoaXMubG9nKGBWZXJpZnlpbmcgQVZEIFwiJHthdmROYW1lfVwiIGV4aXN0cyAoJHtlbXVsYXRvckJpbmFyeX0gLWxpc3QtYXZkcykuLi5gKTtcblxuICAgIGNvbnN0IFtlcnJvciwgc3Rkb3V0XSA9IGF3YWl0IG5ldyBQcm9taXNlPFtFcnJvciB8IG51bGwsIHN0cmluZ10+KChyZXNvbHZlKSA9PiB7XG4gICAgICBleGVjRmlsZShlbXVsYXRvckJpbmFyeSwgWyctbGlzdC1hdmRzJ10sIHsgdGltZW91dDogRU1VTEFUT1JfTElTVF9USU1FT1VUX0lOX01JTExJU0VDT05EUyB9LCAoZXhlY0Vycm9yLCBleGVjU3Rkb3V0KSA9PiB7XG4gICAgICAgIHJlc29sdmUoW2V4ZWNFcnJvciwgZXhlY1N0ZG91dF0pO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpZiAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEZhaWxlZCB0byBsaXN0IEFWRHMgdmlhIFxcYCR7ZW11bGF0b3JCaW5hcnl9IC1saXN0LWF2ZHNcXGA6ICR7ZXJyb3IubWVzc2FnZX0uIGBcbiAgICAgICAgICArICdJcyB0aGUgQW5kcm9pZCBTREsgZW11bGF0b3IgaW5zdGFsbGVkIGFuZCBBTkRST0lEX0hPTUUvQU5EUk9JRF9TREtfUk9PVCBjb3JyZWN0PydcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKCFjaGVja0F2ZEV4aXN0cyh7IGF2ZExpc3RPdXRwdXQ6IHN0ZG91dCwgYXZkTmFtZSB9KSkge1xuICAgICAgY29uc3QgYXZhaWxhYmxlID0gbGlzdEF2YWlsYWJsZUF2ZHMoc3Rkb3V0KTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEFuZHJvaWQgQVZEIFwiJHthdmROYW1lfVwiIG5vdCBmb3VuZC4gQXZhaWxhYmxlIEFWRHM6ICR7YXZhaWxhYmxlLmxlbmd0aCA+IDAgPyBhdmFpbGFibGUuam9pbignLCAnKSA6ICcobm9uZSknfS4gYFxuICAgICAgICAgICsgJ0NyZWF0ZSBpdCAoZS5nLiBpbiB0aGUgQW5kcm9pZCBTdHVkaW8gRGV2aWNlIE1hbmFnZXIsIG9yIHZpYSBgYXZkbWFuYWdlciBjcmVhdGUgYXZkYCksIG9yIHNldCBgYXZkTmFtZWAgdG8gYW4gZXhpc3RpbmcgQVZELidcbiAgICAgICk7XG4gICAgfVxuXG4gICAgdGhpcy5sb2coYEFWRCBcIiR7YXZkTmFtZX1cIiBleGlzdHMuYCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGVuc3VyZURldmljZUNvbm5lY3RlZChwYXJhbXM6IEVuc3VyZURldmljZUNvbm5lY3RlZFBhcmFtcyk6IFByb21pc2U8RW5zdXJlRGV2aWNlQ29ubmVjdGVkUmVzdWx0PiB7XG4gICAgY29uc3QgeyBhdmROYW1lLCBkZXZpY2VJZGxlVGltZW91dEluTWlsbGlzZWNvbmRzLCBpc0VtdWxhdG9yVmlzaWJsZSB9ID0gcGFyYW1zO1xuICAgIGNvbnN0IGRldmljZUlkc0JlZm9yZSA9IGF3YWl0IHRoaXMuZ2V0Q29ubmVjdGVkRGV2aWNlSWRzKCk7XG4gICAgdGhpcy5sb2coYENoZWNraW5nIGV4aXN0aW5nIGRldmljZXMgZm9yIEFWRCBcIiR7YXZkTmFtZX1cIi4uLiAoY29ubmVjdGVkOiBbJHtkZXZpY2VJZHNCZWZvcmUuam9pbignLCAnKX1dKWApO1xuXG4gICAgY29uc3QgZXhpc3RpbmdEZXZpY2VJZCA9IGF3YWl0IHRoaXMuZmluZERldmljZUJ5QXZkTmFtZShhdmROYW1lLCBkZXZpY2VJZHNCZWZvcmUpO1xuXG4gICAgaWYgKGV4aXN0aW5nRGV2aWNlSWQpIHtcbiAgICAgIHRoaXMubG9nKGBBVkQgXCIke2F2ZE5hbWV9XCIgaXMgYWxyZWFkeSBydW5uaW5nIG9uIGRldmljZSAke2V4aXN0aW5nRGV2aWNlSWR9LCByZXVzaW5nLmApO1xuICAgICAgYXdhaXQgdGhpcy5zdXBwcmVzc0Vycm9yRGlhbG9ncyhleGlzdGluZ0RldmljZUlkKTtcbiAgICAgIHJldHVybiB7IGFjdHVhbERldmljZUlkOiBleGlzdGluZ0RldmljZUlkIH07XG4gICAgfVxuXG4gICAgdGhpcy5sb2coYEFWRCBcIiR7YXZkTmFtZX1cIiBub3QgZm91bmQgb24gYW55IGV4aXN0aW5nIGRldmljZSwgc3RhcnRpbmcgYSBuZXcgZW11bGF0b3IuLi5gKTtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZUF2ZEV4aXN0cyhhdmROYW1lKTtcbiAgICBjb25zdCBlbXVsYXRvciA9IHRoaXMuc3RhcnRFbXVsYXRvcihhdmROYW1lLCBpc0VtdWxhdG9yVmlzaWJsZSk7XG5cbiAgICBsZXQgYWN0dWFsRGV2aWNlSWQ6IHN0cmluZztcbiAgICB0cnkge1xuICAgICAgYWN0dWFsRGV2aWNlSWQgPSBhd2FpdCB0aGlzLndhaXRGb3JOZXdEZXZpY2UoZGV2aWNlSWRzQmVmb3JlLCBlbXVsYXRvciwgZGV2aWNlSWRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kcyk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGVtdWxhdG9yLnN0b3BDYXB0dXJlKCk7XG4gICAgfVxuXG4gICAgdGhpcy5sb2coYEVtdWxhdG9yIFwiJHthdmROYW1lfVwiIHN0YXJ0ZWQsIGRldmljZSAke2FjdHVhbERldmljZUlkfSBpcyBjb25uZWN0ZWQuYCk7XG4gICAgYXdhaXQgdGhpcy5zdXBwcmVzc0Vycm9yRGlhbG9ncyhhY3R1YWxEZXZpY2VJZCk7XG4gICAgcmV0dXJuIHsgYWN0dWFsRGV2aWNlSWQsIGVtdWxhdG9yUHJvY2VzczogZW11bGF0b3IucHJvY2VzcyB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVVaWF1dG9tYXRvcjJEcml2ZXJJbnN0YWxsZWQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5sb2coYENoZWNraW5nIHdoZXRoZXIgdGhlICR7VUlBVVRPTUFUT1IyX0RSSVZFUl9OQU1FfSBkcml2ZXIgaXMgaW5zdGFsbGVkLi4uYCk7XG4gICAgY29uc3QgZHJpdmVyTGlzdEpzb24gPSBhd2FpdCBleGVjKCducHggLS1uby1pbnN0YWxsIGFwcGl1bSBkcml2ZXIgbGlzdCAtLWluc3RhbGxlZCAtLWpzb24nLCB7XG4gICAgICBpc1F1aWV0OiB0cnVlLFxuICAgICAgc2hvdWxkSWdub3JlRXhpdENvZGU6IHRydWVcbiAgICB9KTtcblxuICAgIGlmIChjaGVja0lzQXBwaXVtRHJpdmVySW5zdGFsbGVkKHsgZHJpdmVyTGlzdEpzb24sIGRyaXZlck5hbWU6IFVJQVVUT01BVE9SMl9EUklWRVJfTkFNRSB9KSkge1xuICAgICAgdGhpcy5sb2coYFRoZSAke1VJQVVUT01BVE9SMl9EUklWRVJfTkFNRX0gZHJpdmVyIGlzIGluc3RhbGxlZC5gKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmxvZyhgVGhlICR7VUlBVVRPTUFUT1IyX0RSSVZFUl9OQU1FfSBkcml2ZXIgaXMgbm90IGluc3RhbGxlZC4gSW5zdGFsbGluZyB2aWEgXFxgYXBwaXVtIGRyaXZlciBpbnN0YWxsICR7VUlBVVRPTUFUT1IyX0RSSVZFUl9OQU1FfVxcYC4uLmApO1xuICAgIGF3YWl0IGV4ZWMoYG5weCAtLW5vLWluc3RhbGwgYXBwaXVtIGRyaXZlciBpbnN0YWxsICR7VUlBVVRPTUFUT1IyX0RSSVZFUl9OQU1FfWApO1xuICAgIHRoaXMubG9nKGBUaGUgJHtVSUFVVE9NQVRPUjJfRFJJVkVSX05BTUV9IGRyaXZlciBpbnN0YWxsZWQuYCk7XG4gIH1cblxuICAvKipcbiAgICogRXN0YWJsaXNoZXMgdGhlIFdlYkRyaXZlcklPIHNlc3Npb24sIHJlY29nbml6aW5nIHRoZSBvbmUgZmFpbHVyZSB0aGF0IGJsYW1lc1xuICAgKiB0aGUgd3Jvbmcgc3ViamVjdDogYENvdWxkIG5vdCBmaW5kIGEgY29ubmVjdGVkIEFuZHJvaWQgZGV2aWNlYCBmcm9tIGEgc2VydmVyXG4gICAqIHdob3NlIGFkYiBpcyB3ZWRnZWQgd2hpbGUgdGhlIGhvc3QncyBvd24gYWRiIHNlZXMgdGhlIGRldmljZSBmaW5lLlxuICAgKlxuICAgKiBBIHNlcnZlciBhbiBlYXJsaWVyIHJ1biBvZiB0aGlzIGhhcm5lc3Mgc3RhcnRlZCBpcyByZXN0YXJ0ZWQgYW5kIHRoZSBzZXNzaW9uXG4gICAqIHJldHJpZWQgb25jZSBcdTIwMTQgdGhlIGNvbmZpcm1lZCByZW1lZHkuIEEgZm9yZWlnbiBvciB1c2VyLW1hbmFnZWQgc2VydmVyIGlzXG4gICAqIG5ldmVyIGtpbGxlZDsgaXQgaXMgcmVwb3J0ZWQgd2l0aCBhIG1lc3NhZ2UgdGhhdCBuYW1lcyB0aGUgc2VydmVyLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHNlc3Npb24gY2FwYWJpbGl0aWVzIHBsdXMgd2hhdCBpcyBrbm93biBhYm91dCB0aGUgc2VydmVyLlxuICAgKiBAcmV0dXJucyBUaGUgc2Vzc2lvbiwgYW5kIHRoZSByZXBsYWNlbWVudCBzZXJ2ZXIgcHJvY2VzcyB3aGVuIG9uZSB3YXMgc3RhcnRlZC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZXN0YWJsaXNoU2Vzc2lvbihwYXJhbXM6IEVzdGFibGlzaFNlc3Npb25QYXJhbXMpOiBQcm9taXNlPEVzdGFibGlzaFNlc3Npb25SZXN1bHQ+IHtcbiAgICB0aGlzLmxvZyhcbiAgICAgIGBDb25uZWN0aW5nIHRvIEFwcGl1bSAoZGV2aWNlPSR7cGFyYW1zLmRldmljZUlkfSwgYXBwPSR7cGFyYW1zLmFwcElkfSwgcmV0cnlUaW1lb3V0OiAke1N0cmluZyhwYXJhbXMuc2Vzc2lvbkNvbm5lY3Rpb25SZXRyeVRpbWVvdXRJbk1pbGxpc2Vjb25kcyl9bXMsIHJldHJpZXM6ICR7U3RyaW5nKEFQUElVTV9DT05ORUNUSU9OX1JFVFJZX0NPVU5UKX0pLi4uYFxuICAgICk7XG5cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHsgYnJvd3NlcjogYXdhaXQgdGhpcy5jb25uZWN0U2Vzc2lvbihwYXJhbXMpIH07XG4gICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgIGNvbnN0IHZlcmRpY3QgPSByZXNvbHZlV2VkZ2VkQXBwaXVtU2VydmVyUmVtZWR5KHtcbiAgICAgICAgY29ubmVjdGVkRGV2aWNlSWRzOiBhd2FpdCB0aGlzLmdldENvbm5lY3RlZERldmljZUlkc1F1aWV0bHkoKSxcbiAgICAgICAgZGV2aWNlSWQ6IHBhcmFtcy5kZXZpY2VJZCxcbiAgICAgICAgZXJyb3IsXG4gICAgICAgIGlzQWRvcHRlZFNlcnZlcjogcGFyYW1zLmlzQWRvcHRlZFNlcnZlcixcbiAgICAgICAgaXNBdXRvU3RhcnRBbGxvd2VkOiBwYXJhbXMuc2hvdWxkQXV0b1N0YXJ0QXBwaXVtICE9PSBmYWxzZSxcbiAgICAgICAgaXNIYXJuZXNzT3duZWRTZXJ2ZXI6IGNoZWNrSXNIYXJuZXNzT3duZWRBcHBpdW1TZXJ2ZXIocGFyYW1zLmFwcGl1bVNlcnZlck1hcmtlcilcbiAgICAgIH0pO1xuXG4gICAgICBpZiAodmVyZGljdC5yZW1lZHkgPT09ICdub3Qtd2VkZ2VkJykge1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cblxuICAgICAgaWYgKHZlcmRpY3QucmVtZWR5ID09PSAncmVwb3J0Jykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IodGhpcy5idWlsZFdlZGdlZE1lc3NhZ2UocGFyYW1zLCB2ZXJkaWN0LnJlYXNvbiksIHsgY2F1c2U6IGVycm9yIH0pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy5yZXN0YXJ0V2VkZ2VkU2VydmVyQW5kUmV0cnkocGFyYW1zLCBlcnJvcik7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBmaW5kRGV2aWNlQnlBdmROYW1lKGF2ZE5hbWU6IHN0cmluZywgZGV2aWNlSWRzOiBzdHJpbmdbXSk6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gICAgZm9yIChjb25zdCBkZXZpY2VJZCBvZiBkZXZpY2VJZHMpIHtcbiAgICAgIGNvbnN0IHJ1bm5pbmdBdmQgPSBhd2FpdCBuZXcgUHJvbWlzZTxzdHJpbmc+KChyZXNvbHZlKSA9PiB7XG4gICAgICAgIGV4ZWNGaWxlKFxuICAgICAgICAgICdhZGInLFxuICAgICAgICAgIFsnLXMnLCBkZXZpY2VJZCwgJ2VtdScsICdhdmQnLCAnbmFtZSddLFxuICAgICAgICAgIHsgdGltZW91dDogQURCX0RFVklDRV9DSEVDS19USU1FT1VUX0lOX01JTExJU0VDT05EUyB9LFxuICAgICAgICAgIChfZXJyb3IsIHN0ZG91dCkgPT4ge1xuICAgICAgICAgICAgcmVzb2x2ZShzdGRvdXQuc3BsaXQoJ1xcbicsIDEpWzBdPy50cmltKCkgPz8gJycpO1xuICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgIH0pO1xuXG4gICAgICBpZiAocnVubmluZ0F2ZCA9PT0gYXZkTmFtZSkge1xuICAgICAgICByZXR1cm4gZGV2aWNlSWQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZ2V0Q29ubmVjdGVkRGV2aWNlSWRzKCk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICBjb25zdCBvdXRwdXQgPSBhd2FpdCBuZXcgUHJvbWlzZTxzdHJpbmc+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGV4ZWNGaWxlKCdhZGInLCBbJ2RldmljZXMnXSwgeyB0aW1lb3V0OiBBREJfREVWSUNFX0NIRUNLX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTIH0sIChlcnJvciwgc3Rkb3V0LCBzdGRlcnIpID0+IHtcbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgRmFpbGVkIHRvIHJ1biAnYWRiIGRldmljZXMnOiAke2Vycm9yLm1lc3NhZ2V9LiBJcyBBREIgaW5zdGFsbGVkIGFuZCBpbiBQQVRIP2ApKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHN0ZGVycikge1xuICAgICAgICAgIHRoaXMubG9nKGBBREIgc3RkZXJyOiAke3N0ZGVyci50cmltKCl9YCk7XG4gICAgICAgIH1cbiAgICAgICAgcmVzb2x2ZShzdGRvdXQpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBjb25zdCBsaW5lcyA9IG91dHB1dC5zcGxpdCgnXFxuJykubWFwKChsaW5lKSA9PiBsaW5lLnRyaW0oKSkuZmlsdGVyKChsaW5lKSA9PiBsaW5lLmxlbmd0aCA+IDApO1xuICAgIHJldHVybiBsaW5lc1xuICAgICAgLmZpbHRlcigobGluZSkgPT4gbGluZS5pbmNsdWRlcygnXFx0ZGV2aWNlJykpXG4gICAgICAubWFwKChsaW5lKSA9PiBsaW5lLnNwbGl0KCdcXHQnLCAxKVswXSA/PyAnJyk7XG4gIH1cblxuICAvKipcbiAgICogTGlzdHMgdGhlIGhvc3QncyBjb25uZWN0ZWQgZGV2aWNlcyBmb3IgdGhlIHdlZGdlZC1zZXJ2ZXIgY3Jvc3MtY2hlY2ssIHdoZXJlXG4gICAqIGFuIGFkYiB0aGF0IGl0c2VsZiBmYWlscyBtdXN0IG5vdCBiZSByZWFkIGFzIGV2aWRlbmNlIGFnYWluc3QgdGhlIHNlcnZlci5cbiAgICpcbiAgICogQHJldHVybnMgVGhlIGNvbm5lY3RlZCBkZXZpY2UgSURzLCBvciBhbiBlbXB0eSBsaXN0IHdoZW4gYWRiIGNvdWxkIG5vdCBiZSBydW4uXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGdldENvbm5lY3RlZERldmljZUlkc1F1aWV0bHkoKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy5nZXRDb25uZWN0ZWREZXZpY2VJZHMoKTtcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgdGhpcy5sb2coYENvdWxkIG5vdCByZS1jaGVjayBjb25uZWN0ZWQgZGV2aWNlczogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCk7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBnZXREZXZpY2VQcm9wZXJ0eShkZXZpY2VJZDogc3RyaW5nLCBwcm9wZXJ0eTogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIGV4ZWNGaWxlKFxuICAgICAgICAnYWRiJyxcbiAgICAgICAgWyctcycsIGRldmljZUlkLCAnc2hlbGwnLCAnZ2V0cHJvcCcsIHByb3BlcnR5XSxcbiAgICAgICAgeyB0aW1lb3V0OiBBREJfREVWSUNFX0NIRUNLX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTIH0sXG4gICAgICAgIChlcnJvciwgc3Rkb3V0KSA9PiB7XG4gICAgICAgICAgLy8gUmV0dXJuIG5vIG91dHB1dCBvbiB0aW1lb3V0L2Vycm9yIChub3QgcGFydGlhbCBzdGRvdXQpIHNvIGEgbm9uLXJlc3BvbnNpdmUgZ3Vlc3QgcmVhZHMgYXMgXCJub3QgaWRsZVwiLlxuICAgICAgICAgIHJlc29sdmUoZXJyb3IgPyAnJyA6IHN0ZG91dCk7XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGxpc3RJbnN0YWxsZWRQYWNrYWdlcyhkZXZpY2VJZDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIGV4ZWNGaWxlKFxuICAgICAgICAnYWRiJyxcbiAgICAgICAgWyctcycsIGRldmljZUlkLCAnc2hlbGwnLCAnY21kJywgJ3BhY2thZ2UnLCAnbGlzdCcsICdwYWNrYWdlcyddLFxuICAgICAgICB7IHRpbWVvdXQ6IEFEQl9ERVZJQ0VfQ0hFQ0tfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgfSxcbiAgICAgICAgKGVycm9yLCBzdGRvdXQpID0+IHtcbiAgICAgICAgICAvLyBSZXR1cm4gbm8gb3V0cHV0IG9uIHRpbWVvdXQvZXJyb3Igc28gYSBjaHVybmluZyBndWVzdCdzIHNsb3cvcGFydGlhbCBwYWNrYWdlIGxpc3QgY2FuJ3QgZmFsc2VseSByZWFkIGFzIGlkbGUuXG4gICAgICAgICAgcmVzb2x2ZShlcnJvciA/ICcnIDogc3Rkb3V0KTtcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgbG9nKG1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xuICAgIGxvZyhgW3RyYW5zcG9ydC1mYWN0b3J5OiR7dGhpcy50eXBlfV0gJHttZXNzYWdlfWApO1xuICB9XG5cbiAgcHJpdmF0ZSByZXNvbHZlRW11bGF0b3JCaW5hcnkoKTogc3RyaW5nIHtcbiAgICBjb25zdCBzZGtSb290ID0gcHJvY2Vzcy5lbnZbJ0FORFJPSURfSE9NRSddID8/IHByb2Nlc3MuZW52WydBTkRST0lEX1NES19ST09UJ107XG4gICAgaWYgKCFzZGtSb290KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdDYW5ub3QgZmluZCBBbmRyb2lkIGVtdWxhdG9yOiBuZWl0aGVyIEFORFJPSURfSE9NRSBub3IgQU5EUk9JRF9TREtfUk9PVCBlbnZpcm9ubWVudCB2YXJpYWJsZSBpcyBzZXQuJ1xuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGpvaW4oc2RrUm9vdCwgJ2VtdWxhdG9yJywgJ2VtdWxhdG9yJyk7XG4gIH1cblxuICAvKipcbiAgICogUmVwbGFjZXMgYSB3ZWRnZWQgc2VydmVyIHRoaXMgaGFybmVzcyBzdGFydGVkIGVhcmxpZXIgYW5kIHJldHJpZXMgdGhlXG4gICAqIHNlc3Npb24gb25jZS5cbiAgICpcbiAgICogVGhlIG9sZCBzZXJ2ZXIgaXMga2lsbGVkIGFuZCB0aGUgcG9ydCBpcyB3YWl0ZWQgb3V0IGJlZm9yZSBhIHJlcGxhY2VtZW50IGlzXG4gICAqIHN0YXJ0ZWQ6IGEgc29ja2V0IHRoYXQga2VlcHMgYW5zd2VyaW5nIGAvc3RhdHVzYCB3b3VsZCBsZXQgdGhlIHJlYWRpbmVzc1xuICAgKiBwb2xsIHBhc3Mgb24gdGhlIGR5aW5nIHNlcnZlciwgYW5kIGEgcG9ydCB0aGF0IG5ldmVyIGdvZXMgcXVpZXQgbWVhbnMgdGhlXG4gICAqIGtpbGwgZGlkIG5vdCB0YWtlIFx1MjAxNCBpbiB3aGljaCBjYXNlIHN0YXJ0aW5nIGFueXRoaW5nIG9uIGl0IGlzIHBvaW50bGVzcy5cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtcyAtIFRoZSBzZXNzaW9uIGNhcGFiaWxpdGllcyBwbHVzIHdoYXQgaXMga25vd24gYWJvdXQgdGhlIHNlcnZlci5cbiAgICogQHBhcmFtIG9yaWdpbmFsRXJyb3IgLSBUaGUgZmFpbHVyZSB0aGF0IGNvbnZpY3RlZCB0aGUgc2VydmVyLCBsb2dnZWQgc28gdGhlIGRpYWdub3NpcyBpcyBvbiB0aGUgcmVjb3JkLlxuICAgKiBAcmV0dXJucyBUaGUgc2Vzc2lvbiBhbmQgdGhlIHJlcGxhY2VtZW50IHNlcnZlciBwcm9jZXNzLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZXN0YXJ0V2VkZ2VkU2VydmVyQW5kUmV0cnkocGFyYW1zOiBFc3RhYmxpc2hTZXNzaW9uUGFyYW1zLCBvcmlnaW5hbEVycm9yOiB1bmtub3duKTogUHJvbWlzZTxFc3RhYmxpc2hTZXNzaW9uUmVzdWx0PiB7XG4gICAgY29uc3QgbWFya2VyID0gZW5zdXJlTm9uTnVsbGFibGUocGFyYW1zLmFwcGl1bVNlcnZlck1hcmtlciwgJ0EgcmVzdGFydCB2ZXJkaWN0IHJlcXVpcmVzIHRoZSBtYXJrZXIgdGhhdCBwcm92ZWQgb3duZXJzaGlwLicpO1xuICAgIHRoaXMubG9nKFxuICAgICAgYEFwcGl1bSBhdCAke3BhcmFtcy51cmwub3JpZ2lufSBjYW5ub3Qgc2VlICR7cGFyYW1zLmRldmljZUlkfSBhbHRob3VnaCB0aGlzIGhvc3QncyBhZGIgY2FuIFx1MjAxNCB0aGUgc2VydmVyIHRoaXMgaGFybmVzcyBzdGFydGVkIGVhcmxpZXIgKHBpZCAke1N0cmluZyhtYXJrZXIucGlkKX0pIGlzIHN0YWxlLiBSZXN0YXJ0aW5nIGl0Li4uIChzZXNzaW9uIGZhaWxlZCB3aXRoOiAke29yaWdpbmFsRXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IG9yaWdpbmFsRXJyb3IubWVzc2FnZSA6IFN0cmluZyhvcmlnaW5hbEVycm9yKX0pYFxuICAgICk7XG5cbiAgICBraWxsUHJvY2Vzc1RyZWVCeVBpZChtYXJrZXIucGlkKTtcbiAgICBjbGVhckFwcGl1bVNlcnZlck1hcmtlcihwYXJhbXMucG9ydCk7XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy53YWl0Rm9yQXBwaXVtU3RvcHBlZChwYXJhbXMudXJsKTtcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMuYnVpbGRXZWRnZWRNZXNzYWdlKHBhcmFtcywgJ3Jlc3RhcnQtZGlkLW5vdC1oZWxwJyksIHsgY2F1c2U6IGVycm9yIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IGxhdW5jaCA9IHRoaXMuc3RhcnRBcHBpdW1TZXJ2ZXIocGFyYW1zLnBvcnQsIHBhcmFtcy5pc0FwcGl1bUNvbnNvbGVWaXNpYmxlKTtcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLndhaXRGb3JBcHBpdW1SZWFkeShwYXJhbXMudXJsLCBwYXJhbXMuYXBwaXVtU3RhcnRUaW1lb3V0SW5NaWxsaXNlY29uZHMsIGxhdW5jaCk7XG4gICAgICB0aGlzLmxvZygnUmVwbGFjZW1lbnQgQXBwaXVtIHNlcnZlciBpcyByZWFkeSwgcmV0cnlpbmcgdGhlIHNlc3Npb24uLi4nKTtcbiAgICAgIHJldHVybiB7IGFwcGl1bVByb2Nlc3M6IGxhdW5jaC5wcm9jZXNzLCBicm93c2VyOiBhd2FpdCB0aGlzLmNvbm5lY3RTZXNzaW9uKHBhcmFtcykgfTtcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAga2lsbFByb2Nlc3NUcmVlKGxhdW5jaC5wcm9jZXNzKTtcbiAgICAgIGNsZWFyQXBwaXVtU2VydmVyTWFya2VyKHBhcmFtcy5wb3J0KTtcbiAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzLmJ1aWxkV2VkZ2VkTWVzc2FnZShwYXJhbXMsICdyZXN0YXJ0LWRpZC1ub3QtaGVscCcpLCB7IGNhdXNlOiBlcnJvciB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHNlbmRLZXlFdmVudChkZXZpY2VJZDogc3RyaW5nLCBrZXlDb2RlOiBudW1iZXIsIGRlc2NyaXB0aW9uOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgICAgZXhlY0ZpbGUoXG4gICAgICAgICdhZGInLFxuICAgICAgICBbJy1zJywgZGV2aWNlSWQsICdzaGVsbCcsICdpbnB1dCcsICdrZXlldmVudCcsIFN0cmluZyhrZXlDb2RlKV0sXG4gICAgICAgIHsgdGltZW91dDogQURCX0RFVklDRV9DSEVDS19USU1FT1VUX0lOX01JTExJU0VDT05EUyB9LFxuICAgICAgICAoZXJyb3IpID0+IHtcbiAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgIHRoaXMubG9nKFxuICAgICAgICAgICAgICBgV2FybmluZzogZmFpbGVkIHRvICR7ZGVzY3JpcHRpb259IChrZXlldmVudCAke1N0cmluZyhrZXlDb2RlKX0pOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogJ3Vua25vd24gZXJyb3InfWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICB9XG4gICAgICApO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzdGFydEFwcGl1bUFuZEVtdWxhdG9yKHBhcmFtczogU3RhcnRBcHBpdW1BbmRFbXVsYXRvclBhcmFtcyk6IFByb21pc2U8U3RhcnRBcHBpdW1BbmRFbXVsYXRvclJlc3VsdD4ge1xuICAgIGNvbnN0IHsgYXBwaXVtU3RhcnRUaW1lb3V0SW5NaWxsaXNlY29uZHMsIGFwcGl1bVVybCwgYXZkTmFtZSwgZGV2aWNlSWRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kcywgaXNBcHBpdW1Db25zb2xlVmlzaWJsZSwgaXNFbXVsYXRvclZpc2libGUsIHBvcnQsIHNob3VsZEF1dG9JbnN0YWxsQXBwaXVtRGVwZW5kZW5jaWVzLCBzaG91bGRBdXRvU3RhcnRBcHBpdW0gfSA9IHBhcmFtcztcblxuICAgIGxldCBuZWVkc0FwcGl1bVN0YXJ0ID0gZmFsc2U7XG4gICAgbGV0IGFwcGl1bVNlcnZlck1hcmtlcjogQXBwaXVtU2VydmVyTWFya2VyIHwgdW5kZWZpbmVkO1xuXG4gICAgdGhpcy5sb2coYENoZWNraW5nIEFwcGl1bSBzZXJ2ZXIgYXQgJHthcHBpdW1VcmwuaHJlZn0uLi5gKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5jaGVja0FwcGl1bVJlYWNoYWJsZShhcHBpdW1VcmwpO1xuICAgICAgYXBwaXVtU2VydmVyTWFya2VyID0gcmVhZEFwcGl1bVNlcnZlck1hcmtlcihwb3J0KTtcbiAgICAgIHRoaXMubG9nKGBBcHBpdW0gc2VydmVyIGlzIHJlYWNoYWJsZSAoJHt0aGlzLmRlc2NyaWJlQWRvcHRlZFNlcnZlcihhcHBpdW1TZXJ2ZXJNYXJrZXIpfSkuYCk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgIGlmIChzaG91bGRBdXRvU3RhcnRBcHBpdW0gPT09IGZhbHNlKSB7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuICAgICAgbmVlZHNBcHBpdW1TdGFydCA9IHRydWU7XG4gICAgfVxuXG4gICAgbGV0IGFwcGl1bUxhdW5jaDogUHJvY2Vzc0xhdW5jaCB8IHVuZGVmaW5lZDtcblxuICAgIGlmIChuZWVkc0FwcGl1bVN0YXJ0KSB7XG4gICAgICBpZiAoc2hvdWxkQXV0b0luc3RhbGxBcHBpdW1EZXBlbmRlbmNpZXMpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5lbnN1cmVBcHBpdW1EZXBlbmRlbmNpZXMoKTtcbiAgICAgIH1cbiAgICAgIHRoaXMubG9nKGBBcHBpdW0gbm90IHJlYWNoYWJsZSwgYXV0by1zdGFydGluZyBvbiBwb3J0ICR7U3RyaW5nKHBvcnQpfS4uLmApO1xuICAgICAgYXBwaXVtTGF1bmNoID0gdGhpcy5zdGFydEFwcGl1bVNlcnZlcihwb3J0LCBpc0FwcGl1bUNvbnNvbGVWaXNpYmxlKTtcbiAgICB9XG5cbiAgICBjb25zdCBhcHBpdW1Qcm9jZXNzID0gYXBwaXVtTGF1bmNoPy5wcm9jZXNzO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IFssIGRldmljZVJlc3VsdF0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgIGFwcGl1bUxhdW5jaFxuICAgICAgICAgID8gdGhpcy53YWl0Rm9yQXBwaXVtUmVhZHkoYXBwaXVtVXJsLCBhcHBpdW1TdGFydFRpbWVvdXRJbk1pbGxpc2Vjb25kcywgYXBwaXVtTGF1bmNoKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMubG9nKCdBdXRvLXN0YXJ0ZWQgQXBwaXVtIHNlcnZlciBpcyByZWFkeS4nKTtcbiAgICAgICAgICB9KVxuICAgICAgICAgIDogUHJvbWlzZS5yZXNvbHZlKCksXG4gICAgICAgIHRoaXMuZW5zdXJlRGV2aWNlQ29ubmVjdGVkKHsgYXZkTmFtZSwgZGV2aWNlSWRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kcywgaXNFbXVsYXRvclZpc2libGUgfSlcbiAgICAgIF0pO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBhY3R1YWxEZXZpY2VJZDogZGV2aWNlUmVzdWx0LmFjdHVhbERldmljZUlkLFxuICAgICAgICBhcHBpdW1Qcm9jZXNzLFxuICAgICAgICBhcHBpdW1TZXJ2ZXJNYXJrZXIsXG4gICAgICAgIGVtdWxhdG9yUHJvY2VzczogZGV2aWNlUmVzdWx0LmVtdWxhdG9yUHJvY2VzcyxcbiAgICAgICAgaXNBZG9wdGVkQXBwaXVtU2VydmVyOiAhbmVlZHNBcHBpdW1TdGFydFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgaWYgKGFwcGl1bVByb2Nlc3MpIHtcbiAgICAgICAga2lsbFByb2Nlc3NUcmVlKGFwcGl1bVByb2Nlc3MpO1xuICAgICAgICB0aGlzLmxvZygnS2lsbGVkIGF1dG8tc3RhcnRlZCBBcHBpdW0gc2VydmVyIGFmdGVyIHN0YXJ0dXAgZmFpbHVyZS4nKTtcbiAgICAgIH1cbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3RhcnRBcHBpdW1TZXJ2ZXIocG9ydDogbnVtYmVyLCBpc0FwcGl1bUNvbnNvbGVWaXNpYmxlPzogYm9vbGVhbik6IFByb2Nlc3NMYXVuY2gge1xuICAgIGNvbnN0IGlzQ29uc29sZUhpZGRlbiA9IHNob3VsZEhpZGVBcHBpdW1Db25zb2xlKGlzQXBwaXVtQ29uc29sZVZpc2libGUpO1xuICAgIGNvbnN0IHsgZGV0YWNoZWQsIHdpbmRvd3NIaWRlIH0gPSByZXNvbHZlQXBwaXVtU3Bhd25GbGFncyhpc0NvbnNvbGVIaWRkZW4pO1xuICAgIC8qXG4gICAgICogYC0tbm8taW5zdGFsbGA6IEFwcGl1bSBpcyBndWFyYW50ZWVkIHByZXNlbnQgYnkgYGVuc3VyZUFwcGl1bUluc3RhbGxlZGBcbiAgICAgKiBiZWZvcmUgd2UgcmVhY2ggaGVyZSwgc28gcGluIG5weCB0byB0aGUgaW5zdGFsbGVkIGNvcHkuIFdpdGhvdXQgaXQsIG5weFxuICAgICAqIHdvdWxkIHNpbGVudGx5IHRyeSB0byBkb3dubG9hZCBBcHBpdW0gZnJlc2ggZnJvbSB0aGUgcmVnaXN0cnkgXHUyMDE0IGFcbiAgICAgKiBzbG93L2h1bmcgZmFpbHVyZSBpbiBhIGhpZGRlbiBjb25zb2xlIFx1MjAxNCB3aGVuZXZlciBpdCBjb3VsZCBub3QgcmVzb2x2ZSB0aGVcbiAgICAgKiBnbG9iYWwgaW5zdGFsbCAoZS5nLiBhIGdsb2JhbCBwcmVmaXggbm90IG9uIFBBVEgpLiBTZWUgYGVuc3VyZUFwcGl1bUluc3RhbGxlZGAuXG4gICAgICpcbiAgICAgKiBQaXBlIHN0ZG91dC9zdGRlcnIgZXZlbiB3aGVuIGhpZGRlbiAocmF0aGVyIHRoYW4gZGlzY2FyZGluZykgc28gYW4gZWFybHlcbiAgICAgKiBmYWlsdXJlIHN1Y2ggYXMgYSBjcmFzaCBvciBhIG1pc3NpbmcgZHJpdmVyIGlzIGNhcHR1cmVkIGFuZCBzdXJmYWNlZFxuICAgICAqIGltbWVkaWF0ZWx5IGJ5IGB3YWl0Rm9yQXBwaXVtUmVhZHlgLCBtaXJyb3JpbmcgYHN0YXJ0RW11bGF0b3JgO1xuICAgICAqIGB3aW5kb3dzSGlkZWAgc3RpbGwgc3VwcHJlc3NlcyB0aGUgY29uc29sZSB3aW5kb3cuXG4gICAgICovXG4gICAgY29uc3QgY2hpbGQgPSBzcGF3bihgbnB4IC0tbm8taW5zdGFsbCBhcHBpdW0gLS1sb2ctdGltZXN0YW1wIC0tcG9ydCAke1N0cmluZyhwb3J0KX0gLS1hbGxvdy1pbnNlY3VyZT0ke0NIUk9NRURSSVZFUl9BVVRPRE9XTkxPQURfRkVBVFVSRX1gLCB7XG4gICAgICBkZXRhY2hlZCxcbiAgICAgIHNoZWxsOiB0cnVlLFxuICAgICAgc3RkaW86IGlzQ29uc29sZUhpZGRlbiA/IFsnaWdub3JlJywgJ3BpcGUnLCAncGlwZSddIDogWydpZ25vcmUnLCAnaW5oZXJpdCcsICdpbmhlcml0J10sXG4gICAgICB3aW5kb3dzSGlkZVxuICAgIH0pO1xuXG4gICAgbGV0IGNhcHR1cmVkT3V0cHV0ID0gJyc7XG4gICAgbGV0IGV4aXRJbmZvOiBQcm9jZXNzRXhpdEluZm8gfCB1bmRlZmluZWQ7XG4gICAgbGV0IGlzQ2FwdHVyaW5nID0gdHJ1ZTtcblxuICAgIGNoaWxkLnN0ZG91dD8ub24oJ2RhdGEnLCBhcHBlbmRPdXRwdXQpO1xuICAgIGNoaWxkLnN0ZGVycj8ub24oJ2RhdGEnLCBhcHBlbmRPdXRwdXQpO1xuICAgIGNoaWxkLm9uY2UoJ2V4aXQnLCAoY29kZSwgc2lnbmFsKSA9PiB7XG4gICAgICBleGl0SW5mbyA9IHsgY29kZSwgc2lnbmFsIH07XG4gICAgfSk7XG4gICAgY2hpbGQub25jZSgnZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgIGV4aXRJbmZvID0geyBjb2RlOiBudWxsLCBzaWduYWw6IG51bGwsIHNwYXduRXJyb3I6IGVycm9yLm1lc3NhZ2UgfTtcbiAgICB9KTtcblxuICAgIGNoaWxkLnVucmVmKCk7XG5cbiAgICAvKlxuICAgICAqIFJlY29yZCB0aGUgc2VydmVyIGFzIG91cnMgYmVmb3JlIGFueXRoaW5nIGNhbiBhZG9wdCBpdC4gVGhlIG1hcmtlciBpcyB3aGF0XG4gICAgICogbGV0cyBhIGxhdGVyIHJ1biB0ZWxsIGl0cyBvd24gbGVmdG92ZXIgc2VydmVyIGZyb20gYSBmb3JlaWduIG9uZSwgYW5kIHNvXG4gICAgICogd2hldGhlciByZXN0YXJ0aW5nIGEgd2VkZ2VkIHNlcnZlciBpcyB0aGlzIGhhcm5lc3MncyBjYWxsIHRvIG1ha2UgXHUyMDE0IHNlZVxuICAgICAqIGBhcHBpdW0tc2VydmVyLW1hcmtlci50c2AuXG4gICAgICovXG4gICAgaWYgKGNoaWxkLnBpZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB3cml0ZUFwcGl1bVNlcnZlck1hcmtlcih7IHBpZDogY2hpbGQucGlkLCBwb3J0IH0pO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBwcm9jZXNzOiBjaGlsZCxcbiAgICAgIHJlYWRFeGl0SW5mbzogKCkgPT4gZXhpdEluZm8sXG4gICAgICByZWFkT3V0cHV0OiAoKSA9PiBjYXB0dXJlZE91dHB1dCxcbiAgICAgIHN0b3BDYXB0dXJlOiAoKTogdm9pZCA9PiB7XG4gICAgICAgIGlzQ2FwdHVyaW5nID0gZmFsc2U7XG4gICAgICB9XG4gICAgfTtcblxuICAgIGZ1bmN0aW9uIGFwcGVuZE91dHB1dChjaHVuazogQnVmZmVyKTogdm9pZCB7XG4gICAgICBpZiAoIWlzQ2FwdHVyaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGNhcHR1cmVkT3V0cHV0ID0gKGNhcHR1cmVkT3V0cHV0ICsgY2h1bmsudG9TdHJpbmcoKSkuc2xpY2UoLUFQUElVTV9PVVRQVVRfVEFJTF9NQVhfTEVOR1RIKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHN0YXJ0RW11bGF0b3IoYXZkTmFtZTogc3RyaW5nLCBpc0VtdWxhdG9yVmlzaWJsZT86IGJvb2xlYW4pOiBQcm9jZXNzTGF1bmNoIHtcbiAgICBjb25zdCBlbXVsYXRvckJpbmFyeSA9IHRoaXMucmVzb2x2ZUVtdWxhdG9yQmluYXJ5KCk7XG4gICAgY29uc3QgaXNXaW5kb3dIaWRkZW4gPSBzaG91bGRIaWRlRW11bGF0b3JXaW5kb3coaXNFbXVsYXRvclZpc2libGUpO1xuICAgIGNvbnN0IGlucHV0ID0gYnVpbGRFbXVsYXRvckFyZ3VtZW50cyh7IGF2ZE5hbWUsIGlzSGlkZGVuOiBpc1dpbmRvd0hpZGRlbiB9KTtcbiAgICBjb25zdCB7IGRldGFjaGVkLCB3aW5kb3dzSGlkZSB9ID0gcmVzb2x2ZUVtdWxhdG9yU3Bhd25GbGFncyhpc1dpbmRvd0hpZGRlbik7XG4gICAgdGhpcy5sb2coYFJ1bm5pbmc6ICR7ZW11bGF0b3JCaW5hcnl9ICR7aW5wdXQuam9pbignICcpfWApO1xuICAgIC8qXG4gICAgICogUGlwZSAocmF0aGVyIHRoYW4gaWdub3JlKSBzdGRvdXQvc3RkZXJyIHNvIGFuIGVhcmx5IGZhaWx1cmUgc3VjaCBhc1xuICAgICAqIFwieDg2XzY0IGVtdWxhdGlvbiBjdXJyZW50bHkgcmVxdWlyZXMgaGFyZHdhcmUgYWNjZWxlcmF0aW9uXCIgY2FuIGJlXG4gICAgICogc3VyZmFjZWQgaW1tZWRpYXRlbHkgaW5zdGVhZCBvZiB3YWl0aW5nIG91dCB0aGUgZnVsbCBib290IHRpbWVvdXQuXG4gICAgICovXG4gICAgY29uc3QgY2hpbGQgPSBzcGF3bihlbXVsYXRvckJpbmFyeSwgaW5wdXQsIHtcbiAgICAgIGRldGFjaGVkLFxuICAgICAgc3RkaW86IFsnaWdub3JlJywgJ3BpcGUnLCAncGlwZSddLFxuICAgICAgd2luZG93c0hpZGVcbiAgICB9KTtcblxuICAgIGxldCBjYXB0dXJlZE91dHB1dCA9ICcnO1xuICAgIGxldCBleGl0SW5mbzogUHJvY2Vzc0V4aXRJbmZvIHwgdW5kZWZpbmVkO1xuICAgIGxldCBpc0NhcHR1cmluZyA9IHRydWU7XG5cbiAgICBjaGlsZC5zdGRvdXQub24oJ2RhdGEnLCBhcHBlbmRPdXRwdXQpO1xuICAgIGNoaWxkLnN0ZGVyci5vbignZGF0YScsIGFwcGVuZE91dHB1dCk7XG4gICAgY2hpbGQub25jZSgnZXhpdCcsIChjb2RlLCBzaWduYWwpID0+IHtcbiAgICAgIGV4aXRJbmZvID0geyBjb2RlLCBzaWduYWwgfTtcbiAgICB9KTtcbiAgICAvKlxuICAgICAqIEEgc3Bhd24gZmFpbHVyZSAoZS5nLiBFTk9FTlQgZm9yIGEgbWlzc2luZy9icm9rZW4gZW11bGF0b3IgYmluYXJ5KSBlbWl0c1xuICAgICAqICdlcnJvcicsIG5vdCAnZXhpdCcuIFJlY29yZCBpdCBhcyBhIHN5bnRoZXRpYyBleGl0IHNvIHRoZSBib290L25ldy1kZXZpY2VcbiAgICAgKiBwb2xscyBmYWlsIGZhc3QgaW5zdGVhZCBvZiBzcGlubmluZyBvdXQgdGhlIGZ1bGwgYm9vdCB0aW1lb3V0LlxuICAgICAqL1xuICAgIGNoaWxkLm9uY2UoJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICBleGl0SW5mbyA9IHsgY29kZTogbnVsbCwgc2lnbmFsOiBudWxsLCBzcGF3bkVycm9yOiBlcnJvci5tZXNzYWdlIH07XG4gICAgfSk7XG5cbiAgICBjaGlsZC51bnJlZigpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHByb2Nlc3M6IGNoaWxkLFxuICAgICAgcmVhZEV4aXRJbmZvOiAoKSA9PiBleGl0SW5mbyxcbiAgICAgIHJlYWRPdXRwdXQ6ICgpID0+IGNhcHR1cmVkT3V0cHV0LFxuICAgICAgc3RvcENhcHR1cmU6ICgpOiB2b2lkID0+IHtcbiAgICAgICAgLypcbiAgICAgICAgICogTGVhdmUgdGhlIGBkYXRhYCBsaXN0ZW5lcnMgYXR0YWNoZWQgc28gdGhlIHBpcGVzIGtlZXAgZHJhaW5pbmcgKGFcbiAgICAgICAgICogZnVsbCBPUyBwaXBlIGJ1ZmZlciB3b3VsZCBibG9jayB0aGUgbG9uZy1ydW5uaW5nIGVtdWxhdG9yKTsgdGhlIGZsYWdcbiAgICAgICAgICoganVzdCBmcmVlemVzIHRoZSBjYXB0dXJlZCB0YWlsIG9uY2Ugc3RhcnR1cCBoYXMgc3VjY2VlZGVkLlxuICAgICAgICAgKi9cbiAgICAgICAgaXNDYXB0dXJpbmcgPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gYXBwZW5kT3V0cHV0KGNodW5rOiBCdWZmZXIpOiB2b2lkIHtcbiAgICAgIGlmICghaXNDYXB0dXJpbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgY2FwdHVyZWRPdXRwdXQgPSAoY2FwdHVyZWRPdXRwdXQgKyBjaHVuay50b1N0cmluZygpKS5zbGljZSgtRU1VTEFUT1JfT1VUUFVUX1RBSUxfTUFYX0xFTkdUSCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIERpc2FibGVzIHRoZSBndWVzdCdzIGNyYXNoL0FOUiBkaWFsb2dzIG9uIHRoZSBnaXZlbiBkZXZpY2UuXG4gICAqXG4gICAqIEEgcmVzb3VyY2Utc3RhcnZlZCBlbXVsYXRvciBjYW4gcmFpc2UgYSBcIlByb2Nlc3Mgc3lzdGVtIGlzbid0IHJlc3BvbmRpbmdcIlxuICAgKiBBTlIgKGFuIGBBY3Rpdml0eU1hbmFnZXJTZXJ2aWNlYCB0aW1lb3V0KSB3aG9zZSBkaWFsb2cgb3ZlcmxheXMgdGhlIFVJLiBJZlxuICAgKiBpdCBhcHBlYXJzIGJlZm9yZSBBcHBpdW0gYXR0YWNoZXMsIG5vdGhpbmcgY2FuIGRpc21pc3MgaXQgYW5kIHRoZSBydW4gaGFuZ3NcbiAgICogb3IgZmFpbHMgaW50ZXJtaXR0ZW50bHkuIFNldHRpbmcgdGhlIGBoaWRlX2Vycm9yX2RpYWxvZ3NgIGdsb2JhbCBcdTIwMTQgdGhlIHNhbWVcbiAgICogZmxhZyBBbmRyb2lkJ3Mgb3duIHRlc3QgaW5mcmEgdXNlcyBcdTIwMTQgdGVsbHMgYEFjdGl2aXR5TWFuYWdlclNlcnZpY2VgIHRvXG4gICAqIG5ldmVyIGRyYXcgY3Jhc2gvQU5SIGRpYWxvZ3MsIHNvIHRoZSBBTlIgY2FuIG5vIGxvbmdlciBibG9jayBhdXRvbWF0aW9uLlxuICAgKlxuICAgKiBUaGlzIGlzIHRoZSBlYXJsaWVzdCBwb2ludCBhdCB3aGljaCB0aGUgZmxhZyBjYW4gYmUgc2V0OiB0aGUgZnJhbWV3b3JrXG4gICAqIChgc3lzdGVtX3NlcnZlcmApIG11c3QgYmUgdXAgYmVmb3JlIGBzZXR0aW5ncyBwdXRgIHdvcmtzLCBzbyBjYWxsZXJzIGludm9rZVxuICAgKiBpdCBvbmx5IGFmdGVyIGBzeXMuYm9vdF9jb21wbGV0ZWRgLiBJdCBuYXJyb3dzIFx1MjAxNCBidXQgY2Fubm90IGZ1bGx5IGNsb3NlIFx1MjAxNFxuICAgKiB0aGUgcmFjZSB3aXRoIGFuIEFOUiB0aGF0IGZpcmVzIGJldHdlZW4gYm9vdCBjb21wbGV0aW5nIGFuZCB0aGlzIGNhbGw7IGFcbiAgICogcHJlLWJha2VkIHNuYXBzaG90IHdpdGggdGhlIGZsYWcgYWxyZWFkeSBzZXQgaXMgdGhlIG9ubHkgd2F5IHRvIGVsaW1pbmF0ZVxuICAgKiBpdCBlbnRpcmVseS4gQmVzdC1lZmZvcnQ6IGEgZmFpbHVyZSBpcyBsb2dnZWQsIG5vdCB0aHJvd24sIHNpbmNlIGl0IG9ubHlcbiAgICogc3VwcHJlc3NlcyBhIHN5bXB0b20uXG4gICAqXG4gICAqIEBwYXJhbSBkZXZpY2VJZCAtIFRoZSBkZXZpY2UgVURJRCB0byBjb25maWd1cmUuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHN1cHByZXNzRXJyb3JEaWFsb2dzKGRldmljZUlkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmxvZyhgRGlzYWJsaW5nIGNyYXNoL0FOUiBkaWFsb2dzIG9uIGRldmljZSAke2RldmljZUlkfSAoc2V0dGluZ3MgcHV0IGdsb2JhbCBoaWRlX2Vycm9yX2RpYWxvZ3MgMSkuLi5gKTtcblxuICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgICBleGVjRmlsZShcbiAgICAgICAgJ2FkYicsXG4gICAgICAgIFsnLXMnLCBkZXZpY2VJZCwgJ3NoZWxsJywgJ3NldHRpbmdzJywgJ3B1dCcsICdnbG9iYWwnLCAnaGlkZV9lcnJvcl9kaWFsb2dzJywgJzEnXSxcbiAgICAgICAgeyB0aW1lb3V0OiBBREJfREVWSUNFX0NIRUNLX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTIH0sXG4gICAgICAgIChlcnJvcikgPT4ge1xuICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgICAgIGBXYXJuaW5nOiBmYWlsZWQgdG8gZGlzYWJsZSBjcmFzaC9BTlIgZGlhbG9nczogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6ICd1bmtub3duIGVycm9yJ31gXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHRoZSBgdGVtcC12YXVsdC0qYCBkaXJlY3RvcmllcyBlYXJsaWVyIHJ1bnMgbGVmdCBvbiB0aGUgZGV2aWNlLlxuICAgKlxuICAgKiBSdW5zICoqYmVmb3JlKiogYHJlbW90ZSgpYCBsYXVuY2hlcyBPYnNpZGlhbiBcdTIwMTQgdGhlIGxhc3QgbW9tZW50IGF0IHdoaWNoXG4gICAqIG5vdGhpbmcgaGFzIHRvIGVudW1lcmF0ZSB0aGUgZGV2aWNlJ3MgdmF1bHRzIHlldCwgYW5kIHRoZSBvbmx5IHN3ZWVwIHRoYXRcbiAgICogZG9lcyBub3QgZGVwZW5kIG9uIGEgaGVhbHRoeSBXZWJWaWV3LiBUaGF0IGluZGVwZW5kZW5jZSBpcyB0aGUgd2hvbGUgcG9pbnQ6XG4gICAqIGEgcnVuIHdob3NlIFdlYlZpZXcgZGllZCBjYW5ub3QgdW5yZWdpc3RlciBvciBkZWxldGUgaXRzIG93biB2YXVsdCwgc29cbiAgICogd2l0aG91dCB0aGlzIGVhY2ggZmFpbHVyZSBsZWF2ZXMgcmVzaWR1ZSB0aGF0IHNsb3dzIHRoZSBuZXh0IHJ1bidzIHN0YXJ0dXBcbiAgICogZW51bWVyYXRpb24gYW5kIG1ha2VzIHRoZSBuZXh0IGZhaWx1cmUgbGlrZWxpZXIuXG4gICAqXG4gICAqIFVuY29uZGl0aW9uYWwgKG5vIGFnZSBnYXRlKSBcdTIwMTQgQW5kcm9pZCBydW5zIGhvbGQgdGhlIGV4Y2x1c2l2ZSBgYW5kcm9pZGBcbiAgICogc2V0dXAgbG9jaywgc28gbm8gY29uY3VycmVudCBydW4gY2FuIG93biBhIGRldmljZSB2YXVsdCwgYW5kIGFuIGFnZSBnYXRlXG4gICAqIHdvdWxkIGxldCBhIHZhdWx0IGxlYWtlZCBtaW51dGVzIGFnbyBzdXJ2aXZlIGludG8gdGhpcyBydW4uIEJlc3QtZWZmb3J0OiBhXG4gICAqIGZhaWx1cmUgaXMgbG9nZ2VkLCBub3QgdGhyb3duLlxuICAgKlxuICAgKiBUaGUgcmVtb3ZhbHMgZ28gb25lIGRpcmVjdG9yeSBhdCBhIHRpbWUgYW5kIHRoZSBvdXRjb21lIGlzIHJlLWxpc3RlZCByYXRoZXJcbiAgICogdGhhbiBpbmZlcnJlZDsge0BsaW5rIHN3ZWVwRGV2aWNlTGVmdG92ZXJzfSBleHBsYWlucyB3aHkuXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgZGV2aWNlIGFuZCB2YXVsdCBiYXNlIHBhdGggdG8gc3dlZXAuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHN3ZWVwRGV2aWNlTGVmdG92ZXJWYXVsdHMocGFyYW1zOiBTd2VlcERldmljZUxlZnRvdmVyVmF1bHRzUGFyYW1zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBkZXZpY2VJZCwgdmF1bHRCYXNlUGF0aCB9ID0gcGFyYW1zO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHN3ZWVwRGV2aWNlTGVmdG92ZXJzKHtcbiAgICAgICAgbGlzdE5hbWVzOiBhc3luYyAoKTogUHJvbWlzZTxzdHJpbmdbXT4gPT4ge1xuICAgICAgICAgIGNvbnN0IGxpc3RpbmcgPSBhd2FpdCBleGVjKFxuICAgICAgICAgICAgWydhZGInLCAnLXMnLCBkZXZpY2VJZCwgJ3NoZWxsJywgJ2xzJywgJy0xJywgdmF1bHRCYXNlUGF0aF0sXG4gICAgICAgICAgICB7IGlzUXVpZXQ6IHRydWUsIHNob3VsZElnbm9yZUV4aXRDb2RlOiB0cnVlLCB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IEFEQl9WQVVMVF9TV0VFUF9USU1FT1VUX0lOX01JTExJU0VDT05EUyB9XG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm4gbGlzdGluZy5zcGxpdCgnXFxuJyk7XG4gICAgICAgIH0sXG4gICAgICAgIHJlbW92ZURpcmVjdG9yeTogYXN5bmMgKHBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICAgIGF3YWl0IGV4ZWMoXG4gICAgICAgICAgICBbJ2FkYicsICctcycsIGRldmljZUlkLCAnc2hlbGwnLCAncm0nLCAnLXJmJywgcGF0aF0sXG4gICAgICAgICAgICB7IGlzUXVpZXQ6IHRydWUsIHNob3VsZElnbm9yZUV4aXRDb2RlOiB0cnVlLCB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IEFEQl9WQVVMVF9TV0VFUF9USU1FT1VUX0lOX01JTExJU0VDT05EUyB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfSxcbiAgICAgICAgdmF1bHRCYXNlUGF0aFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChyZXN1bHQucmVtb3ZlZENvdW50ID09PSAwICYmIHJlc3VsdC5mYWlsZWROYW1lcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgdGhpcy5sb2coYE5vIGxlZnRvdmVyIHRlbXAgdmF1bHRzIG9uIGRldmljZSAke2RldmljZUlkfS5gKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmxvZyhgUmVtb3ZlZCAke1N0cmluZyhyZXN1bHQucmVtb3ZlZENvdW50KX0gbGVmdG92ZXIgdGVtcCB2YXVsdChzKSBmcm9tICR7dmF1bHRCYXNlUGF0aH0gb24gZGV2aWNlICR7ZGV2aWNlSWR9LmApO1xuXG4gICAgICBpZiAocmVzdWx0LmZhaWxlZE5hbWVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgYFdhcm5pbmc6ICR7U3RyaW5nKHJlc3VsdC5mYWlsZWROYW1lcy5sZW5ndGgpfSBsZWZ0b3ZlciB0ZW1wIHZhdWx0KHMpIGNvdWxkIG5vdCBiZSByZW1vdmVkIGFuZCB3aWxsIGJlIHJldHJpZWQgbmV4dCBydW46ICR7cmVzdWx0LmZhaWxlZE5hbWVzLmpvaW4oJywgJyl9YFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICB0aGlzLmxvZyhgV2FybmluZzogZmFpbGVkIHRvIHN3ZWVwIGxlZnRvdmVyIHRlbXAgdmF1bHRzOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogJ3Vua25vd24gZXJyb3InfWApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgd2FpdEZvckFwcGl1bVJlYWR5KHVybDogVVJMLCB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlciwgbGF1bmNoOiBQcm9jZXNzTGF1bmNoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qgc3RhcnQgPSBEYXRlLm5vdygpO1xuICAgIHRoaXMubG9nKFxuICAgICAgYFdhaXRpbmcgZm9yIEFwcGl1bSBhdCAke3VybC5ocmVmfSAodGltZW91dDogJHtTdHJpbmcodGltZW91dEluTWlsbGlzZWNvbmRzKX1tcywgcG9sbDogJHtTdHJpbmcoQVBQSVVNX1NUQVJUX1BPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTKX1tcykuLi5gXG4gICAgKTtcbiAgICBjb25zdCBkZWFkbGluZSA9IHN0YXJ0ICsgdGltZW91dEluTWlsbGlzZWNvbmRzO1xuXG4gICAgd2hpbGUgKERhdGUubm93KCkgPCBkZWFkbGluZSkge1xuICAgICAgLypcbiAgICAgICAqIElmIHRoZSBzZXJ2ZXIgcHJvY2VzcyBhbHJlYWR5IGRpZWQgKGNyYXNoZWQsIG9yIG5ldmVyIHN0YXJ0ZWQpLCBzdG9wXG4gICAgICAgKiBwb2xsaW5nIGFuZCBzdXJmYWNlIHdoeSBcdTIwMTQgb3RoZXJ3aXNlIGEgZG9vbWVkIHNlcnZlciBzcGlucyBvdXQgdGhlIHdob2xlXG4gICAgICAgKiByZWFkaW5lc3MgdGltZW91dCB3aXRoIG5vIGRpYWdub3N0aWNzICh0aGUgb3JpZ2luYWwgVDg0IHN5bXB0b20pLlxuICAgICAgICovXG4gICAgICBjb25zdCBleGl0SW5mbyA9IGxhdW5jaC5yZWFkRXhpdEluZm8oKTtcbiAgICAgIGlmIChleGl0SW5mbykge1xuICAgICAgICB0aHJvdyBidWlsZERlYXRoRXJyb3IoZXhpdEluZm8pO1xuICAgICAgfVxuXG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0aGlzLmNoZWNrQXBwaXVtUmVhY2hhYmxlKHVybCk7XG4gICAgICAgIGxhdW5jaC5zdG9wQ2FwdHVyZSgpO1xuICAgICAgICB0aGlzLmxvZyhgQXBwaXVtIHNlcnZlciByZWFkeSBhZnRlciAke1N0cmluZyhEYXRlLm5vdygpIC0gc3RhcnQpfW1zLmApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgdGhpcy5sb2coYEFwcGl1bSBzZXJ2ZXIgbm90IHJlYWR5IHlldCAoZWxhcHNlZDogJHtTdHJpbmcoRGF0ZS5ub3coKSAtIHN0YXJ0KX1tcykuIFJldHJ5aW5nLi4uYCk7XG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBBUFBJVU1fU1RBUlRfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBmaW5hbEV4aXRJbmZvID0gbGF1bmNoLnJlYWRFeGl0SW5mbygpO1xuICAgIGlmIChmaW5hbEV4aXRJbmZvKSB7XG4gICAgICB0aHJvdyBidWlsZERlYXRoRXJyb3IoZmluYWxFeGl0SW5mbyk7XG4gICAgfVxuXG4gICAgY29uc3Qgb3V0cHV0VGFpbCA9IGxhdW5jaC5yZWFkT3V0cHV0KCkudHJpbSgpO1xuICAgIGNvbnN0IG91dHB1dFNlY3Rpb24gPSBvdXRwdXRUYWlsLmxlbmd0aCA+IDAgPyBgXFxuXFxuQXBwaXVtIHNlcnZlciBvdXRwdXQgKHRhaWwpOlxcbiR7b3V0cHV0VGFpbH1gIDogJyc7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBBdXRvLXN0YXJ0ZWQgQXBwaXVtIHNlcnZlciBkaWQgbm90IGJlY29tZSByZWFkeSB3aXRoaW4gJHtTdHJpbmcodGltZW91dEluTWlsbGlzZWNvbmRzKX1tcy4ke291dHB1dFNlY3Rpb259YCk7XG5cbiAgICBmdW5jdGlvbiBidWlsZERlYXRoRXJyb3IoZXhpdEluZm86IFByb2Nlc3NFeGl0SW5mbyk6IEVycm9yIHtcbiAgICAgIHJldHVybiBuZXcgRXJyb3IoYnVpbGRQcm9jZXNzRXhpdE1lc3NhZ2Uoe1xuICAgICAgICBleGl0SW5mbyxcbiAgICAgICAgb3V0cHV0OiBsYXVuY2gucmVhZE91dHB1dCgpLFxuICAgICAgICBvdXRwdXRMYWJlbDogJ0FwcGl1bSBzZXJ2ZXIgb3V0cHV0JyxcbiAgICAgICAgc3ViamVjdDogJ0F1dG8tc3RhcnRlZCBBcHBpdW0gc2VydmVyJ1xuICAgICAgfSkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBXYWl0cyB1bnRpbCBub3RoaW5nIGFuc3dlcnMgYC9zdGF0dXNgIG9uIHRoZSBwb3J0IGFueSBtb3JlLlxuICAgKlxuICAgKiBAcGFyYW0gdXJsIC0gVGhlIEFwcGl1bSBzZXJ2ZXIgVVJMLlxuICAgKiBAdGhyb3dzIElmIHRoZSBwb3J0IGlzIHN0aWxsIHNlcnZlZCB3aGVuIHRoZSB0aW1lb3V0IGVsYXBzZXMuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHdhaXRGb3JBcHBpdW1TdG9wcGVkKHVybDogVVJMKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZGVhZGxpbmUgPSBEYXRlLm5vdygpICsgQVBQSVVNX1NUT1BfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFM7XG5cbiAgICB3aGlsZSAoRGF0ZS5ub3coKSA8IGRlYWRsaW5lKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0aGlzLmNoZWNrQXBwaXVtUmVhY2hhYmxlKHVybCk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIEFQUElVTV9TVEFSVF9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgU29tZXRoaW5nIGlzIHN0aWxsIHNlcnZpbmcgJHt1cmwub3JpZ2lufSAke1N0cmluZyhBUFBJVU1fU1RPUF9USU1FT1VUX0lOX01JTExJU0VDT05EUyl9bXMgYWZ0ZXIgdGhlIHN0YWxlIEFwcGl1bSBzZXJ2ZXIgd2FzIGtpbGxlZC5gXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgd2FpdEZvckJvb3QoZGV2aWNlSWQ6IHN0cmluZywgZGVhZGxpbmU6IG51bWJlciwgZW11bGF0b3I6IFByb2Nlc3NMYXVuY2gpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCByZW1haW5pbmdNcyA9IE1hdGgubWF4KDAsIGRlYWRsaW5lIC0gRGF0ZS5ub3coKSk7XG4gICAgdGhpcy5sb2coXG4gICAgICBgV2FpdGluZyBmb3IgZGV2aWNlICR7ZGV2aWNlSWR9IHRvIGZpbmlzaCBib290aW5nIChyZW1haW5pbmc6ICR7U3RyaW5nKHJlbWFpbmluZ01zKX1tcywgcG9sbDogJHtTdHJpbmcoRU1VTEFUT1JfQk9PVF9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyl9bXMpLi4uYFxuICAgICk7XG5cbiAgICB3aGlsZSAoRGF0ZS5ub3coKSA8IGRlYWRsaW5lKSB7XG4gICAgICBjb25zdCBpc0Jvb3RlZCA9IGF3YWl0IG5ldyBQcm9taXNlPGJvb2xlYW4+KChyZXNvbHZlKSA9PiB7XG4gICAgICAgIGV4ZWNGaWxlKFxuICAgICAgICAgICdhZGInLFxuICAgICAgICAgIFsnLXMnLCBkZXZpY2VJZCwgJ3NoZWxsJywgJ2dldHByb3AnLCAnc3lzLmJvb3RfY29tcGxldGVkJ10sXG4gICAgICAgICAgeyB0aW1lb3V0OiBBREJfREVWSUNFX0NIRUNLX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTIH0sXG4gICAgICAgICAgKF9lcnJvciwgc3Rkb3V0KSA9PiB7XG4gICAgICAgICAgICByZXNvbHZlKHN0ZG91dC50cmltKCkgPT09ICcxJyk7XG4gICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGlmIChpc0Jvb3RlZCkge1xuICAgICAgICB0aGlzLmxvZyhgRGV2aWNlICR7ZGV2aWNlSWR9IGJvb3QgY29tcGxldGVkLmApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGV4aXRJbmZvID0gZW11bGF0b3IucmVhZEV4aXRJbmZvKCk7XG4gICAgICBpZiAoZXhpdEluZm8pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGJ1aWxkUHJvY2Vzc0V4aXRNZXNzYWdlKHtcbiAgICAgICAgICBleGl0SW5mbyxcbiAgICAgICAgICBvdXRwdXQ6IGVtdWxhdG9yLnJlYWRPdXRwdXQoKSxcbiAgICAgICAgICBvdXRwdXRMYWJlbDogJ0VtdWxhdG9yIG91dHB1dCcsXG4gICAgICAgICAgc3ViamVjdDogJ0FuZHJvaWQgZW11bGF0b3InXG4gICAgICAgIH0pKTtcbiAgICAgIH1cblxuICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBFTVVMQVRPUl9CT09UX1BPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBEZXZpY2UgXCIke2RldmljZUlkfVwiIGNvbm5lY3RlZCBidXQgZGlkIG5vdCBmaW5pc2ggYm9vdGluZyB3aXRoaW4gJHtTdHJpbmcoRU1VTEFUT1JfQk9PVF9USU1FT1VUX0lOX01JTExJU0VDT05EUyl9bXMuYFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogV2FpdHMgZm9yIGEgZnJlc2hseS1ib290ZWQgZW11bGF0b3IgdG8gYmVjb21lIGlkbGUgYmVmb3JlIHRoZSBzZXNzaW9uIGlzXG4gICAqIGVzdGFibGlzaGVkLlxuICAgKlxuICAgKiBgc3lzLmJvb3RfY29tcGxldGVkYCBmaXJlcyBiZWZvcmUgdGhlIGd1ZXN0IGlzIGFjdHVhbGx5IGlkbGUgXHUyMDE0IHBhY2thZ2VcbiAgICogb3B0aW1pemF0aW9uIGFuZCBzZXJ2aWNlcyBrZWVwIGNodXJuaW5nIFx1MjAxNCBzbyBlc3RhYmxpc2hpbmcgdGhlIEFwcGl1bVxuICAgKiBzZXNzaW9uIGltbWVkaWF0ZWx5IG1ha2VzIGV2ZXJ5IHNlcmlhbGl6ZWQgVWlBdXRvbWF0b3IyIGBhZGJgIHJvdW5kLXRyaXBcbiAgICogY29udGVuZCB3aXRoIHRoYXQgd29yayBhbmQgaW5mbGF0ZXMgc2Vzc2lvbiBlc3RhYmxpc2htZW50IH4zeC4gVGhpcyBwb2xsc1xuICAgKiBhIGxhdGVyLCBxdWlldGVyIHNpZ25hbCAoYm9vdCBhbmltYXRpb24gc3RvcHBlZCArIHBhY2thZ2UgbWFuYWdlciBzZXJ2aW5nLFxuICAgKiB2aWEge0BsaW5rIGNoZWNrRGV2aWNlSWRsZX0pIGFuZCByZXR1cm5zIGFzIHNvb24gYXMgaXQgaXMgc2F0aXNmaWVkLlxuICAgKlxuICAgKiBCZXN0LWVmZm9ydDogaWYgdGhlIGd1ZXN0IGRvZXMgbm90IHJlcG9ydCBpZGxlIHdpdGhpbiB0aGUgYnVkZ2V0IGl0IGxvZ3MgYVxuICAgKiB3YXJuaW5nIGFuZCBwcm9jZWVkcyAoYSBzbG93IHNlc3Npb24gaXMgYmV0dGVyIHRoYW4gYSBmYWlsZWQgcnVuKSwgYW5kIGFcbiAgICogYnVkZ2V0IG9mIGAwYCBza2lwcyB0aGUgd2FpdCBlbnRpcmVseS5cbiAgICpcbiAgICogQHBhcmFtIGRldmljZUlkIC0gVGhlIGRldmljZSBVRElEIHRvIHBvbGwuXG4gICAqIEBwYXJhbSB0aW1lb3V0SW5NaWxsaXNlY29uZHMgLSBNYXhpbXVtIHRpbWUgdG8gd2FpdDsgYDBgIHNraXBzIHRoZSB3YWl0LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB3YWl0Rm9yRGV2aWNlSWRsZShkZXZpY2VJZDogc3RyaW5nLCB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aW1lb3V0SW5NaWxsaXNlY29uZHMgPD0gMCkge1xuICAgICAgdGhpcy5sb2coYFNraXBwaW5nIHBvc3QtYm9vdCBpZGxlIHdhaXQgZm9yIGRldmljZSAke2RldmljZUlkfSAodGltZW91dCBpcyAwKS5gKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzdGFydCA9IERhdGUubm93KCk7XG4gICAgY29uc3QgZGVhZGxpbmUgPSBzdGFydCArIHRpbWVvdXRJbk1pbGxpc2Vjb25kcztcbiAgICB0aGlzLmxvZyhcbiAgICAgIGBXYWl0aW5nIGZvciBkZXZpY2UgJHtkZXZpY2VJZH0gdG8gYmVjb21lIGlkbGUgKHRpbWVvdXQ6ICR7U3RyaW5nKHRpbWVvdXRJbk1pbGxpc2Vjb25kcyl9bXMsIHBvbGw6ICR7U3RyaW5nKERFVklDRV9JRExFX1BPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTKX1tcykuLi5gXG4gICAgKTtcblxuICAgIHdoaWxlIChEYXRlLm5vdygpIDwgZGVhZGxpbmUpIHtcbiAgICAgIGNvbnN0IFtib290QW5pbWF0aW9uUHJvcGVydHksIHBhY2thZ2VMaXN0T3V0cHV0XSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgdGhpcy5nZXREZXZpY2VQcm9wZXJ0eShkZXZpY2VJZCwgJ2luaXQuc3ZjLmJvb3RhbmltJyksXG4gICAgICAgIHRoaXMubGlzdEluc3RhbGxlZFBhY2thZ2VzKGRldmljZUlkKVxuICAgICAgXSk7XG5cbiAgICAgIGlmIChjaGVja0RldmljZUlkbGUoeyBib290QW5pbWF0aW9uUHJvcGVydHksIHBhY2thZ2VMaXN0T3V0cHV0IH0pKSB7XG4gICAgICAgIHRoaXMubG9nKGBEZXZpY2UgJHtkZXZpY2VJZH0gaXMgaWRsZSBhZnRlciAke1N0cmluZyhEYXRlLm5vdygpIC0gc3RhcnQpfW1zLmApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubG9nKGBEZXZpY2UgJHtkZXZpY2VJZH0gbm90IGlkbGUgeWV0IChlbGFwc2VkOiAke1N0cmluZyhEYXRlLm5vdygpIC0gc3RhcnQpfW1zKS4gUmV0cnlpbmcuLi5gKTtcbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgREVWSUNFX0lETEVfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdGhpcy5sb2coXG4gICAgICBgV2FybmluZzogZGV2aWNlICR7ZGV2aWNlSWR9IGRpZCBub3QgcmVwb3J0IGlkbGUgd2l0aGluICR7U3RyaW5nKHRpbWVvdXRJbk1pbGxpc2Vjb25kcyl9bXM7IHByb2NlZWRpbmcgd2l0aCBzZXNzaW9uIGVzdGFibGlzaG1lbnQgYW55d2F5LmBcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB3YWl0Rm9yTmV3RGV2aWNlKGRldmljZUlkc0JlZm9yZTogc3RyaW5nW10sIGVtdWxhdG9yOiBQcm9jZXNzTGF1bmNoLCBkZXZpY2VJZGxlVGltZW91dEluTWlsbGlzZWNvbmRzOiBudW1iZXIpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRoaXMubG9nKFxuICAgICAgYFdhaXRpbmcgZm9yIGEgbmV3IGRldmljZSB0byBhcHBlYXIgaW4gQURCICh0aW1lb3V0OiAke1N0cmluZyhFTVVMQVRPUl9CT09UX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTKX1tcywgcG9sbDogJHtTdHJpbmcoRU1VTEFUT1JfQk9PVF9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyl9bXMpLi4uYFxuICAgICk7XG4gICAgY29uc3QgZGVhZGxpbmUgPSBEYXRlLm5vdygpICsgRU1VTEFUT1JfQk9PVF9USU1FT1VUX0lOX01JTExJU0VDT05EUztcblxuICAgIHdoaWxlIChEYXRlLm5vdygpIDwgZGVhZGxpbmUpIHtcbiAgICAgIGNvbnN0IGN1cnJlbnRJZHMgPSBhd2FpdCB0aGlzLmdldENvbm5lY3RlZERldmljZUlkcygpO1xuICAgICAgY29uc3QgbmV3SWRzID0gY3VycmVudElkcy5maWx0ZXIoKGlkKSA9PiAhZGV2aWNlSWRzQmVmb3JlLmluY2x1ZGVzKGlkKSk7XG5cbiAgICAgIGlmIChuZXdJZHMubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCBhY3R1YWxEZXZpY2VJZCA9IG5ld0lkc1swXSA/PyAnJztcbiAgICAgICAgdGhpcy5sb2coYERldmljZSAke2FjdHVhbERldmljZUlkfSBhcHBlYXJlZCBpbiBBREIsIHdhaXRpbmcgZm9yIGJvb3QgdG8gY29tcGxldGUuLi5gKTtcbiAgICAgICAgYXdhaXQgdGhpcy53YWl0Rm9yQm9vdChhY3R1YWxEZXZpY2VJZCwgZGVhZGxpbmUsIGVtdWxhdG9yKTtcbiAgICAgICAgYXdhaXQgdGhpcy53YWl0Rm9yRGV2aWNlSWRsZShhY3R1YWxEZXZpY2VJZCwgZGV2aWNlSWRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kcyk7XG4gICAgICAgIGF3YWl0IHRoaXMud2FrZVNjcmVlbihhY3R1YWxEZXZpY2VJZCk7XG4gICAgICAgIHJldHVybiBhY3R1YWxEZXZpY2VJZDtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZXhpdEluZm8gPSBlbXVsYXRvci5yZWFkRXhpdEluZm8oKTtcbiAgICAgIGlmIChleGl0SW5mbykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYnVpbGRQcm9jZXNzRXhpdE1lc3NhZ2Uoe1xuICAgICAgICAgIGV4aXRJbmZvLFxuICAgICAgICAgIG91dHB1dDogZW11bGF0b3IucmVhZE91dHB1dCgpLFxuICAgICAgICAgIG91dHB1dExhYmVsOiAnRW11bGF0b3Igb3V0cHV0JyxcbiAgICAgICAgICBzdWJqZWN0OiAnQW5kcm9pZCBlbXVsYXRvcidcbiAgICAgICAgfSkpO1xuICAgICAgfVxuXG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIEVNVUxBVE9SX0JPT1RfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYE5vIG5ldyBlbXVsYXRvciBkZXZpY2UgYXBwZWFyZWQgd2l0aGluICR7U3RyaW5nKEVNVUxBVE9SX0JPT1RfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMpfW1zLmBcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB3YWtlU2NyZWVuKGRldmljZUlkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmxvZyhgV2FraW5nIHNjcmVlbiBvbiBkZXZpY2UgJHtkZXZpY2VJZH0uLi5gKTtcblxuICAgIGF3YWl0IHRoaXMuc2VuZEtleUV2ZW50KGRldmljZUlkLCBLRVlDT0RFX1dBS0VVUCwgJ3dha2Ugc2NyZWVuJyk7XG4gICAgYXdhaXQgdGhpcy5zZW5kS2V5RXZlbnQoZGV2aWNlSWQsIEtFWUNPREVfTUVOVSwgJ2Rpc21pc3MgbG9jayBzY3JlZW4nKTtcblxuICAgIHRoaXMubG9nKGBTY3JlZW4gd2FrZSBjb21wbGV0ZSBvbiBkZXZpY2UgJHtkZXZpY2VJZH0uYCk7XG4gIH1cbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IHRyYW5zcG9ydCBpbnN0YW5jZSBmcm9tIHRoZSBnaXZlbiBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSBvcHRpb25zIC0gVHJhbnNwb3J0IGNvbmZpZ3VyYXRpb24uIERlZmF1bHRzIHRvIGFuIG93bmVkIGRlc2t0b3AgQ0RQIHRyYW5zcG9ydC5cbiAqIEByZXR1cm5zIEEgbmV3IHRyYW5zcG9ydCBpbnN0YW5jZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZVRyYW5zcG9ydEZyb21PcHRpb25zKG9wdGlvbnM/OiBPYnNpZGlhblRyYW5zcG9ydE9wdGlvbnMpOiBQcm9taXNlPE9ic2lkaWFuVHJhbnNwb3J0PiB7XG4gIGNvbnN0IHR5cGUgPSBvcHRpb25zPy50eXBlID8/IERFRkFVTFRfVFJBTlNQT1JUX1RZUEU7XG5cbiAgaWYgKCFvcHRpb25zIHx8IG9wdGlvbnMudHlwZSA9PT0gJ29ic2lkaWFuLWNkcCcpIHtcbiAgICByZXR1cm4gY3JlYXRlQ2RwVHJhbnNwb3J0KG9wdGlvbnMpO1xuICB9XG5cbiAgY29uc3QgZmFjdG9yeSA9IG5ldyBBcHBpdW1UcmFuc3BvcnRGYWN0b3J5KHR5cGUpO1xuICByZXR1cm4gZmFjdG9yeS5jcmVhdGUob3B0aW9ucyk7XG59XG5cbi8qKlxuICogUmV0dXJucyBhIGNhY2hlZCB0cmFuc3BvcnQgaW5zdGFuY2UsIGNyZWF0aW5nIG9uZSBmcm9tIHRoZSBnaXZlbiBvcHRpb25zXG4gKiBpZiBub3QgYWxyZWFkeSBjYWNoZWQuXG4gKlxuICogVGhlIHRyYW5zcG9ydCBpcyBjYWNoZWQgcGVyIHdvcmtlciBwcm9jZXNzIHNvIFdlYlNvY2tldC9BcHBpdW0gc2Vzc2lvbnNcbiAqIGFyZSByZXVzZWQgYWNyb3NzIGNhbGxzIHdpdGhpbiB0aGUgc2FtZSB0ZXN0IHdvcmtlci5cbiAqXG4gKiBUaGlzIGlzIHRoZSBzaW5nbGUgZW50cnkgcG9pbnQgZXZlcnkgd29ya2VyLXNpZGUgY2FsbGVyIHVzZXMgZm9yIHRoZSAqKmFtYmllbnQqKlxuICogdHJhbnNwb3J0LCBzbyBpdCBpcyBhbHNvIHdoZXJlIGEgZmFpbGVkIGdsb2JhbCBzZXR1cCBpcyB0dXJuZWQgaW50byBhIGZhaWxpbmcgdGVzdC5cbiAqIEEgZmFpbGVkIHNldHVwIHB1Ymxpc2hlcyBubyB0cmFuc3BvcnQgb3B0aW9ucywgYW5kIGB1bmRlZmluZWRgIG9wdGlvbnMgbWVhbiB0aGUgb3duZWRcbiAqICoqZGVza3RvcCoqIENEUCBkZWZhdWx0IFx1MjAxNCBzbyB3aXRob3V0IHRoaXMgZ3VhcmQgYW4gQW5kcm9pZCBwcm9qZWN0J3Mgc3VpdGUgd291bGQgcnVuXG4gKiBvbiBkZXNrdG9wIGFuZCB0aGVuIGRpZSBvbiBhbiB1bnJlbGF0ZWQgQ0RQIGVycm9yLCBoaWRpbmcgdGhlIHJlYWwgY2F1c2UgKCoqTDkqKikuXG4gKiBUaGUgc2V0dXAgcGF0aCBpdHNlbGYgaXMgdW5hZmZlY3RlZDogYGNvcmVTZXR1cGAgYnVpbGRzIGl0cyB0cmFuc3BvcnQgdGhyb3VnaFxuICoge0BsaW5rIGNyZWF0ZVRyYW5zcG9ydEZyb21PcHRpb25zfSB3aXRoIGV4cGxpY2l0IG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIG9wdGlvbnMgLSBUcmFuc3BvcnQgY29uZmlndXJhdGlvbi4gRGVmYXVsdHMgdG8gYW4gb3duZWQgZGVza3RvcCBDRFAgdHJhbnNwb3J0LlxuICogQHJldHVybnMgVGhlIGNhY2hlZCBvciBuZXdseSBjcmVhdGVkIHRyYW5zcG9ydC5cbiAqIEB0aHJvd3Mge0ludGVncmF0aW9uU2V0dXBGYWlsZWRFcnJvcn0gV2hlbiB0aGlzIHByb2plY3QncyBnbG9iYWwgc2V0dXAgZmFpbGVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0T3JDcmVhdGVUcmFuc3BvcnQob3B0aW9ucz86IE9ic2lkaWFuVHJhbnNwb3J0T3B0aW9ucyk6IFByb21pc2U8T2JzaWRpYW5UcmFuc3BvcnQ+IHtcbiAgY29uc3Qgc2V0dXBFcnJvciA9IGdldFNldHVwRXJyb3IoKTtcbiAgaWYgKHNldHVwRXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgSW50ZWdyYXRpb25TZXR1cEZhaWxlZEVycm9yKHNldHVwRXJyb3IpO1xuICB9XG5cbiAgaWYgKGNhY2hlZFRyYW5zcG9ydCkge1xuICAgIHJldHVybiBjYWNoZWRUcmFuc3BvcnQ7XG4gIH1cblxuICBjb25zdCByZXN1bHQgPSBhd2FpdCBjcmVhdGVUcmFuc3BvcnRGcm9tT3B0aW9ucyhvcHRpb25zKTtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHJlcXVpcmUtYXRvbWljLXVwZGF0ZXMgLS0gU2luZ2xlLXRocmVhZGVkIHdvcmtlcjsgbm8gY29uY3VycmVudCB3cml0ZXMuXG4gIGNhY2hlZFRyYW5zcG9ydCA9IHJlc3VsdDtcbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgZGVza3RvcCBDRFAgdHJhbnNwb3J0LiBXaGVuIGFuIGV4cGxpY2l0IGBwb3J0YCBpcyBnaXZlbiB0aGVcbiAqIHRyYW5zcG9ydCBhdHRhY2hlcyB0byBhbiBhbHJlYWR5LXJ1bm5pbmcgT2JzaWRpYW4gb24gdGhhdCBwb3J0OyBvdGhlcndpc2UgaXRcbiAqIGxhdW5jaGVzIGFuZCBvd25zIGFuIGlzb2xhdGVkIGluc3RhbmNlICh0aGUgZGVmYXVsdCwgaGVybWV0aWMgbW9kZSkuXG4gKlxuICogQHBhcmFtIG9wdGlvbnMgLSBDRFAgdHJhbnNwb3J0IG9wdGlvbnMuXG4gKiBAcmV0dXJucyBBIGNvbmZpZ3VyZWQgQ0RQIHRyYW5zcG9ydC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gY3JlYXRlQ2RwVHJhbnNwb3J0KG9wdGlvbnM/OiBPYnNpZGlhbkNkcFRyYW5zcG9ydE9wdGlvbnMpOiBQcm9taXNlPE9ic2lkaWFuVHJhbnNwb3J0PiB7XG4gIGlmIChvcHRpb25zPy5wb3J0ICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBvd25lZFN1ZmZpeCA9IG9wdGlvbnMuaXNIYXJuZXNzT3duZWRJbnN0YW5jZSA/ICcgKGhhcm5lc3Mtb3duZWQpJyA6ICcnO1xuICAgIGxvZyhgW3RyYW5zcG9ydC1mYWN0b3J5Om9ic2lkaWFuLWNkcF0gQXR0YWNoaW5nIHRvIHJ1bm5pbmcgT2JzaWRpYW4ke293bmVkU3VmZml4fSAoaG9zdD0ke29wdGlvbnMuaG9zdCA/PyAnbG9jYWxob3N0J30sIHBvcnQ9JHtTdHJpbmcob3B0aW9ucy5wb3J0KX0pYCk7XG4gICAgcmV0dXJuIG5ldyBEZXNrdG9wQ2RwVHJhbnNwb3J0KG5vcm1hbGl6ZU9wdGlvbmFsUHJvcGVydGllczxEZXNrdG9wQ2RwVHJhbnNwb3J0Q29uZmlnPih7XG4gICAgICBjZHBIb3N0OiBvcHRpb25zLmhvc3QsXG4gICAgICBjZHBQb3J0OiBvcHRpb25zLnBvcnQsXG4gICAgICBjb21tYW5kVGltZW91dEluTWlsbGlzZWNvbmRzOiBvcHRpb25zLmNvbW1hbmRUaW1lb3V0SW5NaWxsaXNlY29uZHMsXG4gICAgICBpc0hhcm5lc3NPd25lZEluc3RhbmNlOiBvcHRpb25zLmlzSGFybmVzc093bmVkSW5zdGFuY2VcbiAgICB9KSk7XG4gIH1cblxuICBsb2coJ1t0cmFuc3BvcnQtZmFjdG9yeTpvYnNpZGlhbi1jZHBdIENyZWF0aW5nIG93bmVkIGlzb2xhdGVkIE9ic2lkaWFuIGluc3RhbmNlJyk7XG4gIGNvbnN0IG93bmVkSW5zdGFuY2UgPSBhd2FpdCByZXNvbHZlT3duZWRJbnN0YW5jZUNvbmZpZyhvcHRpb25zKTtcbiAgcmV0dXJuIG5ldyBEZXNrdG9wQ2RwVHJhbnNwb3J0KG5vcm1hbGl6ZU9wdGlvbmFsUHJvcGVydGllczxEZXNrdG9wQ2RwVHJhbnNwb3J0Q29uZmlnPih7XG4gICAgY2RwSG9zdDogb3B0aW9ucz8uaG9zdCxcbiAgICBjb21tYW5kVGltZW91dEluTWlsbGlzZWNvbmRzOiBvcHRpb25zPy5jb21tYW5kVGltZW91dEluTWlsbGlzZWNvbmRzLFxuICAgIGRlYWRCb290R3JhY2VJbk1pbGxpc2Vjb25kczogcmVzb2x2ZURlYWRCb290R3JhY2VJbk1pbGxpc2Vjb25kcyhvcHRpb25zKSxcbiAgICBpc09ic2lkaWFuQXBwVmlzaWJsZTogb3B0aW9ucz8uaXNPYnNpZGlhbkFwcFZpc2libGUsXG4gICAgb3duZWRJbnN0YW5jZSxcbiAgICBzaG91bGREaXNhYmxlU2FuZGJveDogb3B0aW9ucz8uc2hvdWxkRGlzYWJsZVNhbmRib3gsXG4gICAgc2hvdWxkVGhyb3dPblNpbGVudEFzYXJGYWxsYmFjazogd2lsbFRocm93T25TaWxlbnRBc2FyRmFsbGJhY2sob3B0aW9ucz8uc2hvdWxkVGhyb3dPblNpbGVudEFzYXJGYWxsYmFjayksXG4gICAgc2hvdWxkV2Fybk9uQ29tcGF0aWJpbGl0eUlzc3Vlczogd2lsbFdhcm5PbkNvbXBhdGliaWxpdHlJc3N1ZXMob3B0aW9ucz8uc2hvdWxkV2Fybk9uQ29tcGF0aWJpbGl0eUlzc3VlcylcbiAgfSkpO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBmcmVzaCwgaXNvbGF0ZWQgdXNlci1kYXRhIGRpcmVjdG9yeSBmb3IgYW4gb3duZWQgaW5zdGFuY2UuXG4gKlxuICogQHJldHVybnMgVGhlIGFic29sdXRlIHBhdGggdG8gdGhlIG5ldyBkaXJlY3RvcnkuXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZU93bmVkVXNlckRhdGFEaXJlY3RvcnkoKTogc3RyaW5nIHtcbiAgY29uc3Qgcm9vdCA9IGpvaW4odG1wZGlyKCksIEhBUk5FU1NfVEVNUF9ESVJfTkFNRSk7XG4gIG1rZGlyU3luYyhyb290LCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgcmV0dXJuIG1rZHRlbXBTeW5jKGpvaW4ocm9vdCwgT1dORURfVVNFUl9EQVRBX0RJUl9QUkVGSVgpKTtcbn1cblxuLyoqXG4gKiBMb2FkcyBgd2ViZHJpdmVyaW9gIG9uIGRlbWFuZC5cbiAqXG4gKiBUaGUgbG9hZCBpcyBkZWZlcnJlZCBiZWNhdXNlIGEgc3RhdGljIGltcG9ydCB3b3VsZCBkcmFnIHRoZSB3aG9sZSBXZWJEcml2ZXJcbiAqIHN0YWNrIChgd2ViZHJpdmVyaW9gICsgYEB3ZGlvLypgICsgYGFyY2hpdmVyYC9gY2hlZXJpb2AvYGpzemlwYCkgaW50byBldmVyeVxuICogY29uc3VtZXIgb2YgdGhpcyBwYWNrYWdlJ3MgaW5kZXggXHUyMDE0IGBldmFsSW5PYnNpZGlhbmAgcmVhY2hlcyB0aGlzIG1vZHVsZSBcdTIwMTQgd2hlblxuICogb25seSB0aGUgQXBwaXVtIHRyYW5zcG9ydCBuZWVkcyBpdC4gTm90aGluZyBvbiB0aGUgZGVza3RvcCBDRFAgcGF0aCB0b3VjaGVzXG4gKiBgd2ViZHJpdmVyaW9gIGF0IGFsbC5cbiAqXG4gKiBJdCBhbHNvIGtlZXBzIGBjaGFsa2Agb3V0IG9mIHRoYXQgZ3JhcGguIGBAd2Rpby9sb2dnZXJgIGltcG9ydHMgYGNoYWxrQDVgLFxuICogd2hvc2UgaW50ZXJuYWwgYCNzdXBwb3J0cy1jb2xvcmAgc3VicGF0aCBpbXBvcnQgSmVzdCdzIFZNLW1vZHVsZXMgbGlua2VyIGZhaWxzXG4gKiB0byBsaW5rLCBzbyBhbiBlYWdlcmx5LWltcG9ydGVkIGB3ZWJkcml2ZXJpb2Aga2lsbHMgYSBKZXN0IEVTTSBzdWl0ZSBhdCBpbXBvcnRcbiAqIHdpdGggYFJlZmVyZW5jZUVycm9yOiBDYW5ub3QgYWNjZXNzICdzdXBwb3J0c0NvbG9yJyBiZWZvcmUgaW5pdGlhbGl6YXRpb25gXG4gKiBiZWZvcmUgYSBzaW5nbGUgdGVzdCBydW5zIFx1MjAxNCB3aGljaCBpcyB3aGF0IG1hZGUgYHRlc3Q6amVzdGAgcmVkIChUNzU1KS4gQVxuICogYG1vZHVsZU5hbWVNYXBwZXJgIGNhbm5vdCBwYXRjaCBpdDogdGhlIG1hcHBlciBpcyBieXBhc3NlZCBmb3IgYCNgIHNwZWNpZmllcnMuXG4gKlxuICogQHJldHVybnMgQSB7QGxpbmsgUHJvbWlzZX0gdGhhdCByZXNvbHZlcyB0byB0aGUgYHdlYmRyaXZlcmlvYCBlbnRyeSBwb2ludHMgdGhlXG4gKiBBcHBpdW0gZmFjdG9yeSBjYWxscy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gaW1wb3J0V2ViZHJpdmVyaW8oKTogUHJvbWlzZTxXZWJkcml2ZXJpb01vZHVsZT4ge1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcmVzdHJpY3RlZC1zeW50YXggLS0gYHdlYmRyaXZlcmlvYCBpcyBBcHBpdW0tb25seSwgc28gaXQgbXVzdCBiZSBsb2FkZWQgbGF6aWx5OiBhIHN0YXRpYyBpbXBvcnQgd291bGQgZHJhZyB0aGUgd2hvbGUgV2ViRHJpdmVyIHN0YWNrIGludG8gZXZlcnkgY29uc3VtZXIgb2YgdGhpcyBwYWNrYWdlJ3MgaW5kZXgsIGFuZCBgY2hhbGtgIHdpdGggaXQgKHNlZSB0aGUgZG9jIGNvbW1lbnQpLlxuICByZXR1cm4gYXdhaXQgaW1wb3J0KCd3ZWJkcml2ZXJpbycpO1xufVxuXG4vKipcbiAqIFJ1bnMgdGhlIHByb2FjdGl2ZSBpbnN0YWxsZXJcdTIxOTRhcHAgY29tcGF0aWJpbGl0eSBjaGVjayBmb3IgYW4gYXNhci1zd2FwIGFuZCBhY3RzXG4gKiBvbiB0aGUgdmVyZGljdDogZm9yIGFuIGluc3RhbGxlciBiZWxvdyB0aGUgYXBwJ3MgcnVuIGZsb29yIGVpdGhlciB0aHJvd3NcbiAqIHtAbGluayBJbmNvbXBhdGlibGVJbnN0YWxsZXJWZXJzaW9uRXJyb3J9ICh3aGVuXG4gKiB7QGxpbmsgUmVzb2x2ZUFuZFJlcG9ydENvbXBhdGliaWxpdHlQYXJhbXMuc2hvdWxkVGhyb3dPbkluY29tcGF0aWJsZUluc3RhbGxlcn0pXG4gKiBvciBwcm9jZWVkcyB0byBsYXVuY2ggd2l0aCBhIHdhcm5pbmc7IGZvciBhIHJ1bm5hYmxlLWJ1dC1iZWxvdy1yZWNvbW1lbmRlZFxuICogaW5zdGFsbGVyIGxvZ3MgYSB3YXJuaW5nLiBCb3RoIHdhcm5pbmdzIGFyZSBzdXBwcmVzc2VkIHdoZW5cbiAqIHtAbGluayBSZXNvbHZlQW5kUmVwb3J0Q29tcGF0aWJpbGl0eVBhcmFtcy5zaG91bGRXYXJuT25Db21wYXRpYmlsaXR5SXNzdWVzfSBpc1xuICogYGZhbHNlYC5cbiAqXG4gKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHJlc29sdmVkIHZlcnNpb25zIGFuZCB0aGUgd2Fybi90aHJvdyBrbm9icy5cbiAqIEByZXR1cm5zIFRoZSB2ZXJkaWN0LCBvciBgdW5kZWZpbmVkYCB3aGVuIHRoZXJlIGlzIG5vIGFzYXItc3dhcCB0byBjaGVjay5cbiAqL1xuZnVuY3Rpb24gcmVzb2x2ZUFuZFJlcG9ydENvbXBhdGliaWxpdHkocGFyYW1zOiBSZXNvbHZlQW5kUmVwb3J0Q29tcGF0aWJpbGl0eVBhcmFtcyk6IEluc3RhbGxlckNvbXBhdGliaWxpdHkgfCB1bmRlZmluZWQge1xuICBjb25zdCB7IGFwcFZlcnNpb24sIGluc3RhbGxlclZlcnNpb24sIHNob3VsZFRocm93T25JbmNvbXBhdGlibGVJbnN0YWxsZXIsIHNob3VsZFdhcm5PbkNvbXBhdGliaWxpdHlJc3N1ZXMgfSA9IHBhcmFtcztcbiAgaWYgKGFwcFZlcnNpb24gPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCBjb21wYXRpYmlsaXR5ID0gcmVzb2x2ZUluc3RhbGxlckNvbXBhdGliaWxpdHkoe1xuICAgIGFwcFZlcnNpb24sXG4gICAgaW5zdGFsbGVyVmVyc2lvbixcbiAgICBtZXRhZGF0YTogZ2V0VmVyc2lvbk1ldGFkYXRhKGFwcFZlcnNpb24pXG4gIH0pO1xuXG4gIGNvbnN0IGFjdGlvbiA9IHJlc29sdmVJbnN0YWxsZXJDb21wYXRpYmlsaXR5QWN0aW9uKHtcbiAgICBzaG91bGRUaHJvd09uSW5jb21wYXRpYmxlSW5zdGFsbGVyLFxuICAgIHNob3VsZFdhcm5PbkNvbXBhdGliaWxpdHlJc3N1ZXMsXG4gICAgdGllcjogY29tcGF0aWJpbGl0eS50aWVyXG4gIH0pO1xuXG4gIGlmIChhY3Rpb24gPT09ICd0aHJvdycpIHtcbiAgICB0aHJvdyBuZXcgSW5jb21wYXRpYmxlSW5zdGFsbGVyVmVyc2lvbkVycm9yKHtcbiAgICAgIGFwcFZlcnNpb246IGNvbXBhdGliaWxpdHkuYXBwVmVyc2lvbixcbiAgICAgIGluc3RhbGxlclZlcnNpb246IGVuc3VyZU5vbk51bGxhYmxlKGNvbXBhdGliaWxpdHkuaW5zdGFsbGVyVmVyc2lvbiksXG4gICAgICBtaW5SdW5uYWJsZUluc3RhbGxlclZlcnNpb246IGVuc3VyZU5vbk51bGxhYmxlKGNvbXBhdGliaWxpdHkubWluUnVubmFibGVJbnN0YWxsZXJWZXJzaW9uKVxuICAgIH0pO1xuICB9XG5cbiAgaWYgKGFjdGlvbiA9PT0gJ3dhcm4tdW5ydW5uYWJsZScpIHtcbiAgICBsb2coXG4gICAgICBgW3RyYW5zcG9ydC1mYWN0b3J5Om9ic2lkaWFuLWNkcF0gT2JzaWRpYW4gaW5zdGFsbGVyICR7ZW5zdXJlTm9uTnVsbGFibGUoY29tcGF0aWJpbGl0eS5pbnN0YWxsZXJWZXJzaW9uKX0gaXMgYmVsb3cgdGhlIGBcbiAgICAgICAgKyBgcnVuIGZsb29yICR7ZW5zdXJlTm9uTnVsbGFibGUoY29tcGF0aWJpbGl0eS5taW5SdW5uYWJsZUluc3RhbGxlclZlcnNpb24pfSBmb3IgT2JzaWRpYW4gJHtjb21wYXRpYmlsaXR5LmFwcFZlcnNpb259OyBgXG4gICAgICAgICsgJ3Byb2NlZWRpbmcgdG8gbGF1bmNoIChzaG91bGRUaHJvd09uSW5jb21wYXRpYmxlSW5zdGFsbGVyIGlzIGZhbHNlKSBcdTIwMTQgdGhlIGJvb3Qgd2lsbCBsaWtlbHkgZGVhZC1ib290LidcbiAgICApO1xuICB9IGVsc2UgaWYgKGFjdGlvbiA9PT0gJ3dhcm4tbmFnZ2VkJykge1xuICAgIGxvZyhgW3RyYW5zcG9ydC1mYWN0b3J5Om9ic2lkaWFuLWNkcF0gJHtlbnN1cmVOb25OdWxsYWJsZShjb21wYXRpYmlsaXR5Lm1lc3NhZ2UpfWApO1xuICB9XG5cbiAgcmV0dXJuIGNvbXBhdGliaWxpdHk7XG59XG5cbi8qKlxuICogRGVjaWRlcyBob3cgdGhlIHJlcXVlc3RlZCBhcHAgKGFzYXIpIHZlcnNpb24gd2lsbCBiZSBhcHBsaWVkIHRvIGFuIG93bmVkXG4gKiBpbnN0YW5jZSwgd2l0aG91dCBkb3dubG9hZGluZyBhbnl0aGluZyB5ZXQ6IGFuIHVwZ3JhZGUtb25seSBhc2FyLXN3YXAgb250byB0aGVcbiAqIHNoZWxsLCBhIGRvd25ncmFkZSB0byB0aGUgYXBwJ3Mgb3duIGluc3RhbGxlciBzaGVsbCwgb3IgdGhlIHVzZXIncyBuZXdlc3RcbiAqIGluc3RhbGxlZCBhc2FyIHdoZW4gbmVpdGhlciB2ZXJzaW9uIGlzIHBpbm5lZC5cbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIENEUCB0cmFuc3BvcnQgb3B0aW9ucy5cbiAqIEBwYXJhbSBzaGVsbFZlcnNpb24gLSBUaGUgcmVzb2x2ZWQgaW5zdGFsbGVyL3NoZWxsIHZlcnNpb24sIG9yIGB1bmRlZmluZWRgLlxuICogQHJldHVybnMgVGhlIGFzYXIgcGxhbiAoYXQgbW9zdCBvbmUgb2YgaXRzIGZpZWxkcyBpcyBzZXQpLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlQXNhclBsYW4oXG4gIG9wdGlvbnM6IE9ic2lkaWFuQ2RwVHJhbnNwb3J0T3B0aW9ucyB8IHVuZGVmaW5lZCxcbiAgc2hlbGxWZXJzaW9uOiBzdHJpbmcgfCB1bmRlZmluZWRcbik6IFByb21pc2U8QXNhclBsYW4+IHtcbiAgaWYgKG9wdGlvbnM/Lm9ic2lkaWFuVmVyc2lvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgYXNhclZlcnNpb24gPSBhd2FpdCByZXNvbHZlQ29uY3JldGVWZXJzaW9uKG9wdGlvbnMub2JzaWRpYW5WZXJzaW9uKTtcbiAgICBpZiAoc2hlbGxWZXJzaW9uICE9PSB1bmRlZmluZWQgJiYgY29tcGFyZVZlcnNpb25zKGFzYXJWZXJzaW9uLCBzaGVsbFZlcnNpb24pID49IDApIHtcbiAgICAgIHJldHVybiB7IGFzYXJWZXJzaW9uVG9Td2FwOiBhc2FyVmVyc2lvbiB9O1xuICAgIH1cblxuICAgIC8vIEFzYXItc3dhcCBpcyB1cGdyYWRlLW9ubHksIHNvIGl0IGNhbm5vdCBhcHBseSBhIHZlcnNpb24gb2xkZXIgdGhhbiB0aGVcbiAgICAvLyBTaGVsbCdzIGJ1bmRsZWQgb25lIFx1MjAxNCBhbmQgd2hlbiB0aGUgc2hlbGwgdmVyc2lvbiBpcyB1bmtub3duIChhIExpbnV4XG4gICAgLy8gUGF0aC1wYXJzZSBtaXNzKSB3ZSBjYW5ub3QgcHJvdmUgdGhlIHN3YXAgd291bGQgYXBwbHkgYXQgYWxsLiBJbiBib3RoXG4gICAgLy8gQ2FzZXMgdXNlIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbidzIG93biBpbnN0YWxsZXIgc2hlbGwsIHdob3NlIGJ1bmRsZWQgYXNhclxuICAgIC8vIElzIGV4YWN0bHkgdGhpcyB2ZXJzaW9uLCBzbyB0aGUgcGluIGlzIGFsd2F5cyBob25vcmVkLlxuICAgIGxvZyhgW3RyYW5zcG9ydC1mYWN0b3J5Om9ic2lkaWFuLWNkcF0gVXNpbmcgdGhlICR7YXNhclZlcnNpb259IGluc3RhbGxlciBzaGVsbCAoc2hlbGwgdmVyc2lvbiAke3NoZWxsVmVyc2lvbiA/PyAndW5rbm93bid9OyBhc2FyLXN3YXAgaXMgdXBncmFkZS1vbmx5KS5gKTtcbiAgICByZXR1cm4geyBkb3duZ3JhZGVJbnN0YWxsZXJWZXJzaW9uOiBhc2FyVmVyc2lvbiB9O1xuICB9XG5cbiAgaWYgKG9wdGlvbnM/Lm9ic2lkaWFuSW5zdGFsbGVyVmVyc2lvbiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgbmV3ZXN0ID0gZmluZE5ld2VzdEFzYXIoZ2V0T2JzaWRpYW5Db25maWdEaXJlY3RvcnkoKSk7XG4gICAgaWYgKG5ld2VzdCAmJiAoc2hlbGxWZXJzaW9uID09PSB1bmRlZmluZWQgfHwgY29tcGFyZVZlcnNpb25zKG5ld2VzdC52ZXJzaW9uLCBzaGVsbFZlcnNpb24pID49IDApKSB7XG4gICAgICByZXR1cm4geyBhc2FyOiB7IHBhdGg6IG5ld2VzdC5wYXRoLCB2ZXJzaW9uOiBuZXdlc3QudmVyc2lvbiB9IH07XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHt9O1xufVxuXG4vKipcbiAqIFJlc29sdmVzIHRoZSBsb2NhbGx5LWluc3RhbGxlZCBPYnNpZGlhbiBzaGVsbCwgdG9sZXJhdGluZyBpdHMgYWJzZW5jZS5cbiAqXG4gKiBVbmxpa2Uge0BsaW5rIHJlc29sdmVPYnNpZGlhbkV4ZWN1dGFibGV9ICh3aGljaCB0aHJvd3Mgd2hlbiBPYnNpZGlhbiBpcyBub3RcbiAqIGluc3RhbGxlZCksIHRoaXMgcmV0dXJucyBgdW5kZWZpbmVkYCBpbiB0aGF0IGNhc2UsIHNvIGEgY2FsbGVyIHBpbm5pbmcgYW5cbiAqIGluc3RhbGxlciB2ZXJzaW9uIGNhbiBmYWxsIGJhY2sgdG8gZG93bmxvYWRpbmcgdGhlIHBpbm5lZCBzaGVsbCBpbnN0ZWFkIG9mXG4gKiBmYWlsaW5nIG9uIGEgaG9zdCB3aXRoIG5vIE9ic2lkaWFuIGluc3RhbGxlZCAoZS5nLiBDSSkuXG4gKlxuICogQHJldHVybnMgVGhlIGluc3RhbGxlZCBzaGVsbCdzIHBhdGggYW5kIGRldGVjdGVkIHZlcnNpb24sIG9yIGB1bmRlZmluZWRgIHdoZW5cbiAqICAgbm8gT2JzaWRpYW4gaXMgaW5zdGFsbGVkLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlSW5zdGFsbGVkU2hlbGxPck51bGwoKTogUHJvbWlzZTxJbnN0YWxsZWRTaGVsbCB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IGV4ZVBhdGggPSBhd2FpdCByZXNvbHZlT2JzaWRpYW5FeGVjdXRhYmxlKCk7XG4gICAgcmV0dXJuIHsgZXhlUGF0aCwgc2hlbGxWZXJzaW9uOiBkZXRlY3RJbnN0YWxsZWRTaGVsbFZlcnNpb24oZXhlUGF0aCkgfTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIFJlc29sdmVzIHRoZSBzaGVsbCBleGVjdXRhYmxlLCBhc2FyIHByb3Zpc2lvbmluZywgYW5kIGlzb2xhdGVkIHVzZXItZGF0YSBkaXJcbiAqIGZvciBhIGhhcm5lc3Mtb3duZWQgaW5zdGFuY2UgZnJvbSB0aGUgcmVxdWVzdGVkIHZlcnNpb24ga25vYnMuXG4gKlxuICogLSBgb2JzaWRpYW5JbnN0YWxsZXJWZXJzaW9uYCBwaW5zIHRoZSBFbGVjdHJvbiBzaGVsbCAoZG93bmxvYWRzICsgZXh0cmFjdHMgYVxuICogICBwb3J0YWJsZSBidWlsZCB3aGVuIGl0IGRpZmZlcnMgZnJvbSB0aGUgaW5zdGFsbGVkIHNoZWxsKS5cbiAqIC0gYG9ic2lkaWFuVmVyc2lvbmAgcGlucyB0aGUgYXBwOiBhbiBhc2FyLXN3YXAgd2hlbiBpdCBpcyA+PSB0aGUgc2hlbGwgdmVyc2lvblxuICogICAoY2hlYXApLCBvdGhlcndpc2UgdGhlIG1hdGNoaW5nIGluc3RhbGxlciBzaGVsbCBpcyB1c2VkIChkb3duZ3JhZGUpLlxuICogLSBXaGVuIG5laXRoZXIgaXMgc2V0LCB0aGUgdXNlcidzIG5ld2VzdCBpbnN0YWxsZWQgYXNhciBpcyBjb3BpZWQgaW4gKHNvIHRoZVxuICogICBvd25lZCBpbnN0YW5jZSBtYXRjaGVzIHRoZSB2ZXJzaW9uIHRoZSB1c2VyIGN1cnJlbnRseSBydW5zKSB3aXRoIHplcm8gbmV0d29yay5cbiAqXG4gKiBUaGUgY29uY3JldGUgKGFwcCwgaW5zdGFsbGVyKSB2ZXJzaW9uIHBhaXIgaXMgcmVzb2x2ZWQgKmJlZm9yZSogYW55IHNoZWxsL2FzYXJcbiAqIGRvd25sb2FkLCBzbyBhIHByb2FjdGl2ZSBpbnN0YWxsZXJcdTIxOTRhcHAgY29tcGF0aWJpbGl0eSBjaGVja1xuICogKHtAbGluayByZXNvbHZlSW5zdGFsbGVyQ29tcGF0aWJpbGl0eX0pIGNhbiBmYWlsIGZhc3Q6IGFuIGluc3RhbGxlciBiZWxvdyB0aGVcbiAqIGFwcCdzIHJ1biBmbG9vciB0aHJvd3Mge0BsaW5rIEluY29tcGF0aWJsZUluc3RhbGxlclZlcnNpb25FcnJvcn0gYmVmb3JlXG4gKiBhbnl0aGluZyBpcyBkb3dubG9hZGVkIG9yIGxhdW5jaGVkIChzdXBlcnNlZGluZyB0aGUgcmVhY3RpdmUgZGVhZC1ib290XG4gKiBmYXN0LWZhaWwgZm9yIHRhYmxlLWtub3duIGNvbWJvcyksIGFuZCBhIHJ1bm5hYmxlLWJ1dC1iZWxvdy1yZWNvbW1lbmRlZFxuICogaW5zdGFsbGVyIGxvZ3MgYSB3YXJuaW5nLiBUaGUgdmVyZGljdCBpcyB0aHJlYWRlZCBvbnRvIHRoZSByZXR1cm5lZCBjb25maWcgc29cbiAqIHRoZSB0cmFuc3BvcnQgY2FuIHN1cmZhY2UgaXQgYXMgZGF0YS5cbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIENEUCB0cmFuc3BvcnQgb3B0aW9ucy5cbiAqIEByZXR1cm5zIFRoZSByZXNvbHZlZCBvd25lZC1pbnN0YW5jZSBjb25maWcuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVPd25lZEluc3RhbmNlQ29uZmlnKG9wdGlvbnM/OiBPYnNpZGlhbkNkcFRyYW5zcG9ydE9wdGlvbnMpOiBQcm9taXNlPE93bmVkSW5zdGFuY2VDb25maWc+IHtcbiAgLy8gUmVzb2x2ZSB0aGUgY29uY3JldGUgc2hlbGwgKGluc3RhbGxlcikgdmVyc2lvbiBmaXJzdCwgYnV0IGZvciBhIHBpbm5lZFxuICAvLyBJbnN0YWxsZXIgREVGRVIgcmVzb2x2aW5nL2Rvd25sb2FkaW5nIHRoZSBhY3R1YWwgc2hlbGwgdW50aWwgYWZ0ZXIgdGhlXG4gIC8vIFByb2FjdGl2ZSBjb21wYXRpYmlsaXR5IGNoZWNrLCBzbyBhbiB1bnJ1bm5hYmxlIHBpbiBmYWlscyBmYXN0IFx1MjAxNCBiZWZvcmUgdGhlXG4gIC8vIChwb3NzaWJseSBzbG93KSBpbnN0YWxsZWQtc2hlbGwgZGV0ZWN0aW9uIGFuZCBhbnkgZG93bmxvYWQuXG4gIGxldCBleGVQYXRoOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGxldCBzaGVsbFZlcnNpb246IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgbGV0IHBpbm5lZEluc3RhbGxlclZlcnNpb246IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICBpZiAob3B0aW9ucz8ub2JzaWRpYW5JbnN0YWxsZXJWZXJzaW9uID09PSB1bmRlZmluZWQpIHtcbiAgICBleGVQYXRoID0gYXdhaXQgcmVzb2x2ZU9ic2lkaWFuRXhlY3V0YWJsZSgpO1xuICAgIHNoZWxsVmVyc2lvbiA9IGRldGVjdEluc3RhbGxlZFNoZWxsVmVyc2lvbihleGVQYXRoKTtcbiAgfSBlbHNlIHtcbiAgICAvLyBBIHBpbm5lZCBpbnN0YWxsZXIgdmVyc2lvbiBmdWxseSBkZXRlcm1pbmVzIHRoZSBzaGVsbCB2ZXJzaW9uIHVwIGZyb250LFxuICAgIC8vIFdpdGhvdXQgcmVxdWlyaW5nIGEgbG9jYWxseS1pbnN0YWxsZWQgT2JzaWRpYW4gKGEgQ0kgcnVubmVyIGhhcyBub25lKS5cbiAgICBwaW5uZWRJbnN0YWxsZXJWZXJzaW9uID0gYXdhaXQgcmVzb2x2ZUNvbmNyZXRlVmVyc2lvbihvcHRpb25zLm9ic2lkaWFuSW5zdGFsbGVyVmVyc2lvbik7XG4gICAgc2hlbGxWZXJzaW9uID0gcGlubmVkSW5zdGFsbGVyVmVyc2lvbjtcbiAgfVxuXG4gIC8vIERlY2lkZSBob3cgdGhlIGFwcCAoYXNhcikgdmVyc2lvbiB3aWxsIGJlIGFwcGxpZWQsIHN0aWxsIFdJVEhPVVQgZG93bmxvYWRpbmcuXG4gIGNvbnN0IHBsYW4gPSBhd2FpdCByZXNvbHZlQXNhclBsYW4ob3B0aW9ucywgc2hlbGxWZXJzaW9uKTtcblxuICAvLyBUaGUgYXBwIHZlcnNpb24gdGhhdCB3aWxsIHJ1biBhcyBhbiBhc2FyLXN3YXAgb250byBgc2hlbGxWZXJzaW9uYCBcdTIwMTQgdGhlIG9ubHlcbiAgLy8gQ29tYmluYXRpb24gdGhhdCBjYW4gZGVhZC1ib290LiBUaGUgZG93bmdyYWRlIC8gb3duLWluc3RhbGxlciBwYXRocyBydW4gdGhlXG4gIC8vIEFwcCdzIG93biBpbnN0YWxsZXIgc2hlbGwsIHNvIHRoZXkgYWx3YXlzIGJvb3QgYW5kIGFyZSBub3QgY2hlY2tlZC5cbiAgY29uc3Qgc3dhcEFwcFZlcnNpb24gPSBwbGFuLmFzYXJWZXJzaW9uVG9Td2FwID8/IHBsYW4uYXNhcj8udmVyc2lvbjtcbiAgY29uc3QgY29tcGF0aWJpbGl0eSA9IHJlc29sdmVBbmRSZXBvcnRDb21wYXRpYmlsaXR5KHtcbiAgICBhcHBWZXJzaW9uOiBzd2FwQXBwVmVyc2lvbixcbiAgICBpbnN0YWxsZXJWZXJzaW9uOiBzaGVsbFZlcnNpb24sXG4gICAgc2hvdWxkVGhyb3dPbkluY29tcGF0aWJsZUluc3RhbGxlcjogd2lsbFRocm93T25JbmNvbXBhdGlibGVJbnN0YWxsZXIob3B0aW9ucz8uc2hvdWxkVGhyb3dPbkluY29tcGF0aWJsZUluc3RhbGxlciksXG4gICAgc2hvdWxkV2Fybk9uQ29tcGF0aWJpbGl0eUlzc3Vlczogd2lsbFdhcm5PbkNvbXBhdGliaWxpdHlJc3N1ZXMob3B0aW9ucz8uc2hvdWxkV2Fybk9uQ29tcGF0aWJpbGl0eUlzc3VlcylcbiAgfSk7XG5cbiAgLy8gVGhlIHBpbiBpcyBrbm93biBydW5uYWJsZSBcdTIwMTQgcmVzb2x2ZS9kb3dubG9hZCB0aGUgZGVmZXJyZWQgc2hlbGwgKyBhc2FyIG5vdy5cbiAgLy8gUmV1c2UgdGhlIGluc3RhbGxlZCBzaGVsbCBvbmx5IHdoZW4gaXQgYWxyZWFkeSBtYXRjaGVzIHRoZSBwaW4gKHNhdmVzIHRoZVxuICAvLyBEb3dubG9hZCk7IG90aGVyd2lzZSBkb3dubG9hZCBhbmQgZXh0cmFjdCB0aGUgcGlubmVkIGluc3RhbGxlci5cbiAgaWYgKHBpbm5lZEluc3RhbGxlclZlcnNpb24gIT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IGluc3RhbGxlZCA9IGF3YWl0IHJlc29sdmVJbnN0YWxsZWRTaGVsbE9yTnVsbCgpO1xuICAgIGV4ZVBhdGggPSBpbnN0YWxsZWQ/LnNoZWxsVmVyc2lvbiA9PT0gcGlubmVkSW5zdGFsbGVyVmVyc2lvbiA/IGluc3RhbGxlZC5leGVQYXRoIDogYXdhaXQgZW5zdXJlU2hlbGxDYWNoZWQocGlubmVkSW5zdGFsbGVyVmVyc2lvbik7XG4gIH1cbiAgaWYgKHBsYW4uZG93bmdyYWRlSW5zdGFsbGVyVmVyc2lvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgZXhlUGF0aCA9IGF3YWl0IGVuc3VyZVNoZWxsQ2FjaGVkKHBsYW4uZG93bmdyYWRlSW5zdGFsbGVyVmVyc2lvbik7XG4gIH1cblxuICBjb25zdCBhc2FyID0gcGxhbi5hc2FyVmVyc2lvblRvU3dhcCA9PT0gdW5kZWZpbmVkXG4gICAgPyBwbGFuLmFzYXJcbiAgICA6IHsgcGF0aDogYXdhaXQgZW5zdXJlQXNhckNhY2hlZChwbGFuLmFzYXJWZXJzaW9uVG9Td2FwKSwgdmVyc2lvbjogcGxhbi5hc2FyVmVyc2lvblRvU3dhcCB9O1xuXG4gIHJldHVybiB7XG4gICAgLi4uKGFzYXIgJiYgeyBhc2FyIH0pLFxuICAgIC4uLihjb21wYXRpYmlsaXR5ICYmIHsgY29tcGF0aWJpbGl0eSB9KSxcbiAgICBleGVQYXRoOiBlbnN1cmVOb25OdWxsYWJsZShleGVQYXRoKSxcblxuICAgIHVzZXJEYXRhRGlyZWN0b3J5OiBjcmVhdGVPd25lZFVzZXJEYXRhRGlyZWN0b3J5KClcbiAgfTtcbn1cblxuLyoqXG4gKiBSZW1vdmVzIGBDb25uZWN0aW9uYCBhbmQgYENvbnRlbnQtTGVuZ3RoYCBmcm9tIGEgV2ViRHJpdmVyIHJlcXVlc3QncyBoZWFkZXJzLlxuICpcbiAqIFRoZSBidW5kbGVkIGB3ZWJkcml2ZXJgIHBhY2thZ2Ugc2V0cyBib3RoIGhlYWRlcnMgZXhwbGljaXRseS4gVGhleSBhcmVcbiAqIGZvcmJpZGRlbiByZXF1ZXN0IGhlYWRlcnMgcGVyIHRoZSBGZXRjaCBzcGVjOiBOb2RlIHVwIHRvIDI1IGFjY2VwdGVkIHRoZW1cbiAqIHNpbGVudGx5LCBidXQgTm9kZSAyNiByZWplY3RzIHRoZW0gd2l0aCBgVU5EX0VSUl9JTlZBTElEX0FSR2AsIGJyZWFraW5nIHRoZVxuICogQXBwaXVtIGAvc2Vzc2lvbmAgcmVxdWVzdC4gVGhlIHRyYW5zcG9ydCBsYXllciBtYW5hZ2VzIGNvbm5lY3Rpb24gcmV1c2UgYW5kXG4gKiB0aGUgRmV0Y2ggQVBJIGNvbXB1dGVzIGBDb250ZW50LUxlbmd0aGAgZnJvbSB0aGUgYm9keSwgc28gZHJvcHBpbmcgYm90aCBpc1xuICogc2FmZSBvbiBldmVyeSBOb2RlIHZlcnNpb24uIFNlZSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL3dlYmRyaXZlcmlvL3dlYmRyaXZlcmlvL2lzc3Vlcy8xNTI2NX0uXG4gKlxuICogQHBhcmFtIHJlcXVlc3RPcHRpb25zIC0gVGhlIHJlcXVlc3Qgb3B0aW9ucyBhYm91dCB0byBiZSBzZW50IGJ5IFdlYkRyaXZlcklPLlxuICogQHJldHVybnMgVGhlIHNhbWUgcmVxdWVzdCBvcHRpb25zIHdpdGggdGhlIGZvcmJpZGRlbiBoZWFkZXJzIHJlbW92ZWQuXG4gKi9cbmZ1bmN0aW9uIHN0cmlwRm9yYmlkZGVuRmV0Y2hIZWFkZXJzKHJlcXVlc3RPcHRpb25zOiBSZXF1ZXN0SW5pdCk6IFJlcXVlc3RJbml0IHtcbiAgaWYgKHJlcXVlc3RPcHRpb25zLmhlYWRlcnMgaW5zdGFuY2VvZiBIZWFkZXJzKSB7XG4gICAgcmVxdWVzdE9wdGlvbnMuaGVhZGVycy5kZWxldGUoJ0Nvbm5lY3Rpb24nKTtcbiAgICByZXF1ZXN0T3B0aW9ucy5oZWFkZXJzLmRlbGV0ZSgnQ29udGVudC1MZW5ndGgnKTtcbiAgfVxuXG4gIHJldHVybiByZXF1ZXN0T3B0aW9ucztcbn1cblxuLyogdjggaWdub3JlIHN0b3AgKi9cbiJdLAogICJtYXBwaW5ncyI6ICJBQWNBO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1A7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFDUCxPQUFPLFVBQVU7QUFDakIsU0FBUyxjQUFjO0FBQ3ZCLFNBQVMsWUFBWTtBQUNyQixPQUFPLGFBQWE7QUFpQnBCO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFDUDtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1A7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQLFNBQVMscUJBQXFCO0FBQzlCO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsU0FBUyw4QkFBOEI7QUFDdkMsU0FBUyxZQUFZO0FBQ3JCLFNBQVMseUNBQXlDO0FBQ2xELFNBQVMscUNBQXFDO0FBQzlDLFNBQVMsbUNBQW1DO0FBQzVDO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1A7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQLFNBQVMsV0FBVztBQUNwQixTQUFTLG1DQUFtQztBQUM1QyxTQUFTLGtDQUFrQztBQUMzQyxTQUFTLGlDQUFpQztBQUMxQztBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEs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QSxlQUFlLDhCQUFtRTtBQUNoRixNQUFJO0FBQ0YsVUFBTSxVQUFVLE1BQU0sMEJBQTBCO0FBQ2hELFdBQU8sRUFBRSxTQUFTLGNBQWMsNEJBQTRCLE9BQU8sRUFBRTtBQUFBLEVBQ3ZFLFFBQVE7QUFDTixXQUFPO0FBQUEsRUFDVDtBQUNGO0FBeUJBLGVBQWUsMkJBQTJCLFNBQXFFO0FBSzdHLE1BQUk7QUFDSixNQUFJO0FBQ0osTUFBSTtBQUVKLE1BQUksU0FBUyw2QkFBNkIsUUFBVztBQUNuRCxjQUFVLE1BQU0sMEJBQTBCO0FBQzFDLG1CQUFlLDRCQUE0QixPQUFPO0FBQUEsRUFDcEQsT0FBTztBQUdMLDZCQUF5QixNQUFNLHVCQUF1QixRQUFRLHdCQUF3QjtBQUN0RixtQkFBZTtBQUFBLEVBQ2pCO0FBR0EsUUFBTSxPQUFPLE1BQU0sZ0JBQWdCLFNBQVMsWUFBWTtBQUt4RCxRQUFNLGlCQUFpQixLQUFLLHFCQUFxQixLQUFLLE1BQU07QUFDNUQsUUFBTSxnQkFBZ0IsOEJBQThCO0FBQUEsSUFDbEQsWUFBWTtBQUFBLElBQ1osa0JBQWtCO0FBQUEsSUFDbEIsb0NBQW9DLGlDQUFpQyxTQUFTLGtDQUFrQztBQUFBLElBQ2hILGlDQUFpQyw4QkFBOEIsU0FBUywrQkFBK0I7QUFBQSxFQUN6RyxDQUFDO0FBS0QsTUFBSSwyQkFBMkIsUUFBVztBQUN4QyxVQUFNLFlBQVksTUFBTSw0QkFBNEI7QUFDcEQsY0FBVSxXQUFXLGlCQUFpQix5QkFBeUIsVUFBVSxVQUFVLE1BQU0sa0JBQWtCLHNCQUFzQjtBQUFBLEVBQ25JO0FBQ0EsTUFBSSxLQUFLLDhCQUE4QixRQUFXO0FBQ2hELGNBQVUsTUFBTSxrQkFBa0IsS0FBSyx5QkFBeUI7QUFBQSxFQUNsRTtBQUVBLFFBQU0sT0FBTyxLQUFLLHNCQUFzQixTQUNwQyxLQUFLLE9BQ0wsRUFBRSxNQUFNLE1BQU0saUJBQWlCLEtBQUssaUJBQWlCLEdBQUcsU0FBUyxLQUFLLGtCQUFrQjtBQUU1RixTQUFPO0FBQUEsSUFDTCxHQUFJLFFBQVEsRUFBRSxLQUFLO0FBQUEsSUFDbkIsR0FBSSxpQkFBaUIsRUFBRSxjQUFjO0FBQUEsSUFDckMsU0FBUyxrQkFBa0IsT0FBTztBQUFBLElBRWxDLG1CQUFtQiw2QkFBNkI7QUFBQSxFQUNsRDtBQUNGO0FBZUEsU0FBUywyQkFBMkIsZ0JBQTBDO0FBQzVFLE1BQUksZUFBZSxtQkFBbUIsU0FBUztBQUM3QyxtQkFBZSxRQUFRLE9BQU8sWUFBWTtBQUMxQyxtQkFBZSxRQUFRLE9BQU8sZ0JBQWdCO0FBQUEsRUFDaEQ7QUFFQSxTQUFPO0FBQ1Q7IiwKICAibmFtZXMiOiBbImtpbGxBdXRvU3RhcnRlZFByb2Nlc3NlcyJdCn0K
|
|
2069
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL3RyYW5zcG9ydC1mYWN0b3J5LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogRmFjdG9yeSBmb3IgY3JlYXRpbmcgdHJhbnNwb3J0IGluc3RhbmNlcyBmcm9tIHtAbGluayBPYnNpZGlhblRyYW5zcG9ydE9wdGlvbnN9LlxuICovXG5cbi8qIHY4IGlnbm9yZSBzdGFydCAtLSBJbnRlZ3JhdGlvbi10aW1lIGZhY3RvcnkgY292ZXJlZCBieSBpbnRlZ3JhdGlvbiB0ZXN0cywgbm90IHVuaXQgdGVzdHMuICovXG5cbmltcG9ydCB0eXBlIHsgQ2hpbGRQcm9jZXNzIH0gZnJvbSAnbm9kZTpjaGlsZF9wcm9jZXNzJztcbmltcG9ydCB0eXBlIHtcbiAgYXR0YWNoLFxuICByZW1vdGVcbn0gZnJvbSAnd2ViZHJpdmVyaW8nO1xuXG5pbXBvcnQge1xuICBleGVjRmlsZSxcbiAgZXhlY0ZpbGVTeW5jLFxuICBzcGF3blxufSBmcm9tICdub2RlOmNoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHtcbiAgbWtkaXJTeW5jLFxuICBta2R0ZW1wU3luYyxcbiAgc3RhdFN5bmNcbn0gZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgaHR0cCBmcm9tICdub2RlOmh0dHAnO1xuaW1wb3J0IHtcbiAgaG9tZWRpcixcbiAgdG1wZGlyXG59IGZyb20gJ25vZGU6b3MnO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgcHJvY2VzcyBmcm9tICdub2RlOnByb2Nlc3MnO1xuXG5pbXBvcnQgdHlwZSB7IEFwcGl1bVNlcnZlck1hcmtlciB9IGZyb20gJy4vYXBwaXVtLXNlcnZlci1tYXJrZXIubWpzJztcbmltcG9ydCB0eXBlIHsgQXZkUHJvYmVSZXN1bHQgfSBmcm9tICcuL2F2ZC1wcm9iZS12ZXJkaWN0Lm1qcyc7XG5pbXBvcnQgdHlwZSB7IFByb2Nlc3NMaXN0RW50cnkgfSBmcm9tICcuL2VtdWxhdG9yLWJhY2tlbmQubWpzJztcbmltcG9ydCB0eXBlIHsgRW11bGF0b3JMaXZlbmVzc1Byb2JlT3V0Y29tZSB9IGZyb20gJy4vZW11bGF0b3ItbGl2ZW5lc3MubWpzJztcbmltcG9ydCB0eXBlIHsgSW5zdGFsbGVyQ29tcGF0aWJpbGl0eSB9IGZyb20gJy4vaW5zdGFsbGVyLWNvbXBhdGliaWxpdHkubWpzJztcbmltcG9ydCB0eXBlIHsgUHJvY2Vzc0V4aXRJbmZvIH0gZnJvbSAnLi9wcm9jZXNzLWV4aXQtbWVzc2FnZS5tanMnO1xuaW1wb3J0IHR5cGUge1xuICBEZXNrdG9wQ2RwVHJhbnNwb3J0Q29uZmlnLFxuICBPd25lZEluc3RhbmNlQ29uZmlnXG59IGZyb20gJy4vdHJhbnNwb3J0LWRlc2t0b3AtY2RwLm1qcyc7XG5pbXBvcnQgdHlwZSB7XG4gIE9ic2lkaWFuQW5kcm9pZEFwcGl1bVRyYW5zcG9ydE9wdGlvbnMsXG4gIE9ic2lkaWFuQ2RwVHJhbnNwb3J0T3B0aW9ucyxcbiAgT2JzaWRpYW5UcmFuc3BvcnRPcHRpb25zXG59IGZyb20gJy4vdHJhbnNwb3J0LW9wdGlvbnMubWpzJztcbmltcG9ydCB0eXBlIHsgT2JzaWRpYW5UcmFuc3BvcnQgfSBmcm9tICcuL3RyYW5zcG9ydC5tanMnO1xuaW1wb3J0IHR5cGUgeyBXZWRnZWRBcHBpdW1TZXJ2ZXJSZXBvcnRSZWFzb24gfSBmcm9tICcuL3dlZGdlZC1hcHBpdW0tc2VydmVyLm1qcyc7XG5cbmltcG9ydCB7XG4gIGNoZWNrSXNEZXZpY2VMaXN0ZWQsXG4gIGxpc3RPbmxpbmVEZXZpY2VJZHNcbn0gZnJvbSAnLi9hZGItZGV2aWNlLWxpc3QubWpzJztcbmltcG9ydCB7IHJlc29sdmVFbXVsYXRvckJpbmFyeVBhdGggfSBmcm9tICcuL2FuZHJvaWQtc2RrLm1qcyc7XG5pbXBvcnQge1xuICBjaGVja0lzQXBwaXVtRHJpdmVySW5zdGFsbGVkLFxuICBVSUFVVE9NQVRPUjJfRFJJVkVSX05BTUUsXG4gIHdpbGxBdXRvSW5zdGFsbEFwcGl1bURlcGVuZGVuY2llc1xufSBmcm9tICcuL2FwcGl1bS1kZXBlbmRlbmNpZXMubWpzJztcbmltcG9ydCB7XG4gIGNoZWNrSXNIYXJuZXNzT3duZWRBcHBpdW1TZXJ2ZXIsXG4gIGNsZWFyQXBwaXVtU2VydmVyTWFya2VyLFxuICByZWFkQXBwaXVtU2VydmVyTWFya2VyLFxuICByZWNvcmRBcHBpdW1TZXJ2ZXJTdG9wQXR0ZW1wdCxcbiAgd3JpdGVBcHBpdW1TZXJ2ZXJNYXJrZXJcbn0gZnJvbSAnLi9hcHBpdW0tc2VydmVyLW1hcmtlci5tanMnO1xuaW1wb3J0IHtcbiAgcmVzb2x2ZUFwcGl1bVN0YXJ0VGltZW91dEluTWlsbGlzZWNvbmRzLFxuICByZXNvbHZlU2Vzc2lvbkNvbm5lY3Rpb25SZXRyeVRpbWVvdXRJbk1pbGxpc2Vjb25kc1xufSBmcm9tICcuL2FwcGl1bS1zZXNzaW9uLWNvbmZpZy5tanMnO1xuaW1wb3J0IHtcbiAgY2hlY2tBdmRFeGlzdHMsXG4gIGxpc3RBdmFpbGFibGVBdmRzXG59IGZyb20gJy4vYXZkLWxpc3QubWpzJztcbmltcG9ydCB7XG4gIGJ1aWxkQXZkUHJvYmVTdW1tYXJ5LFxuICBidWlsZFVucmVhZGFibGVEZXZpY2VzTWVzc2FnZSxcbiAgY2hlY2tJc0VtdWxhdG9yRGV2aWNlSWQsXG4gIGNsYXNzaWZ5QXZkUHJvYmUsXG4gIHJlc29sdmVBdmRQcm9iZVZlcmRpY3Rcbn0gZnJvbSAnLi9hdmQtcHJvYmUtdmVyZGljdC5tanMnO1xuaW1wb3J0IHtcbiAgcmVzb2x2ZUluc3RhbGxlckNvbXBhdGliaWxpdHlBY3Rpb24sXG4gIHdpbGxUaHJvd09uSW5jb21wYXRpYmxlSW5zdGFsbGVyLFxuICB3aWxsVGhyb3dPblNpbGVudEFzYXJGYWxsYmFjayxcbiAgd2lsbFdhcm5PbkNvbXBhdGliaWxpdHlJc3N1ZXNcbn0gZnJvbSAnLi9jb21wYXRpYmlsaXR5LW9wdGlvbnMubWpzJztcbmltcG9ydCB7IGFzc2VydFZhbGlkQ29uZmlnRGlyZWN0b3J5IH0gZnJvbSAnLi9jb25maWctZGlyZWN0b3J5Lm1qcyc7XG5pbXBvcnQgeyBnZXRTZXR1cEVycm9yIH0gZnJvbSAnLi9jb250ZXh0LXByb3ZpZGVyLm1qcyc7XG5pbXBvcnQge1xuICBjaGVja0RldmljZUlkbGUsXG4gIGNoZWNrTmV0d29ya1ZhbGlkYXRlZCxcbiAgcmVzb2x2ZURldmljZUlkbGVUaW1lb3V0SW5NaWxsaXNlY29uZHMsXG4gIHJlc29sdmVOZXR3b3JrUmVhZHlUaW1lb3V0SW5NaWxsaXNlY29uZHNcbn0gZnJvbSAnLi9kZXZpY2UtcmVhZGluZXNzLm1qcyc7XG5pbXBvcnQgeyBidWlsZEVtdWxhdG9yQXJndW1lbnRzIH0gZnJvbSAnLi9lbXVsYXRvci1hcmd1bWVudHMubWpzJztcbmltcG9ydCB7XG4gIHBhcnNlUG9zaXhQcm9jZXNzTGlzdCxcbiAgcGFyc2VXaW5kb3dzVGFza0xpc3QsXG4gIHNlbGVjdEVtdWxhdG9yQmFja2VuZFBpZHNcbn0gZnJvbSAnLi9lbXVsYXRvci1iYWNrZW5kLm1qcyc7XG5pbXBvcnQge1xuICBidWlsZEVtdWxhdG9yTGl2ZW5lc3NNZXNzYWdlLFxuICByZXNvbHZlRW11bGF0b3JMaXZlbmVzc1ZlcmRpY3Rcbn0gZnJvbSAnLi9lbXVsYXRvci1saXZlbmVzcy5tanMnO1xuaW1wb3J0IHtcbiAgYnVpbGRBdmRTbmFwc2hvdERpcmVjdG9yeUNhbmRpZGF0ZXMsXG4gIGJ1aWxkU25hcHNob3RBZ2VNZXNzYWdlXG59IGZyb20gJy4vZW11bGF0b3Itc25hcHNob3QubWpzJztcbmltcG9ydCB7IGV4ZWMgfSBmcm9tICcuL2V4ZWMubWpzJztcbmltcG9ydCB7IEluY29tcGF0aWJsZUluc3RhbGxlclZlcnNpb25FcnJvciB9IGZyb20gJy4vaW5jb21wYXRpYmxlLWluc3RhbGxlci12ZXJzaW9uLWVycm9yLm1qcyc7XG5pbXBvcnQgeyByZXNvbHZlSW5zdGFsbGVyQ29tcGF0aWJpbGl0eSB9IGZyb20gJy4vaW5zdGFsbGVyLWNvbXBhdGliaWxpdHkubWpzJztcbmltcG9ydCB7IEludGVncmF0aW9uU2V0dXBGYWlsZWRFcnJvciB9IGZyb20gJy4vaW50ZWdyYXRpb24tc2V0dXAtZmFpbGVkLWVycm9yLm1qcyc7XG5pbXBvcnQge1xuICBraWxsUHJvY2Vzc1RyZWUsXG4gIGtpbGxQcm9jZXNzVHJlZUJ5UGlkXG59IGZyb20gJy4va2lsbC1wcm9jZXNzLXRyZWUubWpzJztcbmltcG9ydCB7XG4gIEhBUk5FU1NfVEVNUF9ESVJfTkFNRSxcbiAgT1dORURfVVNFUl9EQVRBX0RJUl9QUkVGSVgsXG4gIHN3ZWVwRGV2aWNlTGVmdG92ZXJzLFxuICB3aWxsU3dlZXBMZWZ0b3ZlcnNcbn0gZnJvbSAnLi9sZWZ0b3Zlci1jbGVhbnVwLm1qcyc7XG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZy5tanMnO1xuaW1wb3J0IHsgbm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzIH0gZnJvbSAnLi9ub3JtYWxpemUtb3B0aW9uYWwtcHJvcGVydGllcy5tanMnO1xuaW1wb3J0IHsgZ2V0T2JzaWRpYW5Db25maWdEaXJlY3RvcnkgfSBmcm9tICcuL29ic2lkaWFuLWNvbmZpZy5tanMnO1xuaW1wb3J0IHsgcmVzb2x2ZU9ic2lkaWFuRXhlY3V0YWJsZSB9IGZyb20gJy4vb2JzaWRpYW4tZXhlY3V0YWJsZS5tanMnO1xuaW1wb3J0IHtcbiAgZGV0ZWN0SW5zdGFsbGVkU2hlbGxWZXJzaW9uLFxuICBlbnN1cmVTaGVsbENhY2hlZFxufSBmcm9tICcuL29ic2lkaWFuLWluc3RhbGxlci5tanMnO1xuaW1wb3J0IHsgZ2V0VmVyc2lvbk1ldGFkYXRhIH0gZnJvbSAnLi9vYnNpZGlhbi1tZXRhZGF0YS5tanMnO1xuaW1wb3J0IHtcbiAgZW5zdXJlQXNhckNhY2hlZCxcbiAgZmluZE5ld2VzdEFzYXIsXG4gIHJlc29sdmVDb25jcmV0ZVZlcnNpb25cbn0gZnJvbSAnLi9vYnNpZGlhbi12ZXJzaW9uLXN3aXRjaC5tanMnO1xuaW1wb3J0IHsgY29tcGFyZVZlcnNpb25zIH0gZnJvbSAnLi9vYnNpZGlhbi12ZXJzaW9uLm1qcyc7XG5pbXBvcnQgeyByZWFkT3duZWRJbnN0YW5jZUV4aXRNYXJrZXIgfSBmcm9tICcuL293bmVkLWluc3RhbmNlLWV4aXQtbWFya2VyLm1qcyc7XG5pbXBvcnQgeyBidWlsZE93bmVkSW5zdGFuY2VFeGl0ZWRFcnJvckZyb21NYXJrZXIgfSBmcm9tICcuL293bmVkLWluc3RhbmNlLWV4aXRlZC1lcnJvci5tanMnO1xuaW1wb3J0IHtcbiAgcGFyc2VQb3NpeExzb2ZQaWRzLFxuICBwYXJzZVdpbmRvd3NOZXRzdGF0UGlkc1xufSBmcm9tICcuL3BvcnQtb3duZXIubWpzJztcbmltcG9ydCB7XG4gIGFwcGVuZFByb2Nlc3NPdXRwdXRUYWlsLFxuICBidWlsZFByb2Nlc3NFeGl0TWVzc2FnZVxufSBmcm9tICcuL3Byb2Nlc3MtZXhpdC1tZXNzYWdlLm1qcyc7XG5pbXBvcnQgeyBjaGVja0lzUHJvY2Vzc0FsaXZlIH0gZnJvbSAnLi9wcm9jZXNzLWxpdmVuZXNzLm1qcyc7XG5pbXBvcnQgeyByZXNvbHZlRGVhZEJvb3RHcmFjZUluTWlsbGlzZWNvbmRzIH0gZnJvbSAnLi9yZW5kZXJlci1ib290LWRldGVjdGlvbi5tanMnO1xuaW1wb3J0IHtcbiAgcmVzb2x2ZUFwcGl1bVNwYXduRmxhZ3MsXG4gIHJlc29sdmVFbXVsYXRvclNwYXduRmxhZ3Ncbn0gZnJvbSAnLi9zcGF3bi1vcHRpb25zLm1qcyc7XG5pbXBvcnQge1xuICBidWlsZFRlYXJkb3duTWVzc2FnZSxcbiAgcmVzb2x2ZVRlYXJkb3duT3V0Y29tZVxufSBmcm9tICcuL3RlYXJkb3duLXZlcmRpY3QubWpzJztcbmltcG9ydCB7XG4gIEFwcGl1bVRyYW5zcG9ydCxcbiAgREVGQVVMVF9BTkRST0lEX1ZBVUxUX0JBU0VfUEFUSFxufSBmcm9tICcuL3RyYW5zcG9ydC1hcHBpdW0ubWpzJztcbmltcG9ydCB7IERlc2t0b3BDZHBUcmFuc3BvcnQgfSBmcm9tICcuL3RyYW5zcG9ydC1kZXNrdG9wLWNkcC5tanMnO1xuaW1wb3J0IHtcbiAgYXNzZXJ0TmV2ZXIsXG4gIGVuc3VyZU5vbk51bGxhYmxlXG59IGZyb20gJy4vdHlwZS1ndWFyZHMubWpzJztcbmltcG9ydCB7XG4gIHNob3VsZEhpZGVBcHBpdW1Db25zb2xlLFxuICBzaG91bGRIaWRlRW11bGF0b3JXaW5kb3dcbn0gZnJvbSAnLi92aXNpYmlsaXR5Lm1qcyc7XG5pbXBvcnQge1xuICBidWlsZFdlZGdlZEFwcGl1bVNlcnZlck1lc3NhZ2UsXG4gIGNoZWNrSXNBcHBpdW1TdGF0dXNSZWFkeSxcbiAgcmVzb2x2ZVdlZGdlZEFwcGl1bVNlcnZlclJlbWVkeVxufSBmcm9tICcuL3dlZGdlZC1hcHBpdW0tc2VydmVyLm1qcyc7XG5cbmNvbnN0IEFQUF9QQUNLQUdFID0gJ21kLm9ic2lkaWFuJztcbmNvbnN0IEFQUF9BQ1RJVklUWSA9IGAke0FQUF9QQUNLQUdFfS5NYWluQWN0aXZpdHlgO1xuY29uc3QgQURCX0RFVklDRV9DSEVDS19USU1FT1VUX0lOX01JTExJU0VDT05EUyA9IDUwMDA7XG4vKlxuICogSG93IG1hbnkgdGltZXMgdGhlIEFWRCBhZG9wdGlvbiBwcm9iZSBhc2tzIGEgZGV2aWNlIHdoaWNoIEFWRCBpdCBpcyBzZXJ2aW5nLlxuICogT25lIHJldHJ5LCBiZWNhdXNlIHRoZSBhbHRlcm5hdGl2ZSB0byBhbiBhbnN3ZXIgaXMgcmVmdXNpbmcgdG8gbGF1bmNoOiBhXG4gKiBzZWNvbmQgNXMgbG9vayBpcyBmYXIgY2hlYXBlciB0aGFuIGVpdGhlciBhIGZhbHNlIHJlZnVzYWwgb3IgdGhlIGNvbGxpZGluZ1xuICogbGF1bmNoIGEgZGlzY2FyZGVkIHRpbWVvdXQgdXNlZCB0byBhdXRob3JpemUgKHNlZSBgYXZkLXByb2JlLXZlcmRpY3QudHNgKS5cbiAqL1xuY29uc3QgQVZEX1BST0JFX0FUVEVNUFRfQ09VTlQgPSAyO1xuLypcbiAqIGBkdW1wc3lzIGNvbm5lY3Rpdml0eWAgaXMgZmFyIGxhcmdlciB0aGFuIHRoZSBvdGhlciBwcm9iZXMnIG91dHB1dCwgYW5kIE5vZGUnc1xuICogZGVmYXVsdCAxIE1pQiBgbWF4QnVmZmVyYCB3b3VsZCBmYWlsIHRoZSBjYWxsIHJhdGhlciB0aGFuIHRydW5jYXRlIGl0IFx1MjAxNCB3aGljaFxuICogd291bGQgcmVhZCBhcyBcIm5vdCByZWFkeVwiIGZvcmV2ZXIgYW5kIGJ1cm4gdGhlIHdob2xlIG5ldHdvcmsgYnVkZ2V0LlxuICovXG5jb25zdCBBREJfRFVNUFNZU19NQVhfQlVGRkVSX0lOX0JZVEVTID0gOF8zODhfNjA4O1xuLypcbiAqIFRoZSBjb25uZWN0aXZpdHkgZHVtcCBnZXRzIGEgYnVkZ2V0IG9mIGl0cyBPV04sIHdlbGwgYWJvdmUgdGhlIDVzIHRoZSBvdGhlclxuICogcHJvYmVzIHNoYXJlIFx1MjAxNCBub3QgYmVjYXVzZSB0aGUgZHVtcCBpcyBzbG93IChtZWFzdXJlZCAwLjktMi40cyBvbiBhIHJlc3BvbnNpdmVcbiAqIGd1ZXN0LCBhbG9uZ3NpZGUgYGdldHByb3BgJ3MgMC43LTIuMXMpLCBidXQgYmVjYXVzZSBpdCBydW5zIGluIHRoZSB3aW5kb3dcbiAqIHdoZXJlIHJlc2lkdWFsIHBvc3QtYm9vdCBjb250ZW50aW9uIHN0aWxsIGluZmxhdGVzIGV2ZXJ5IGBhZGJgIHJvdW5kLXRyaXBcbiAqIDI1LTUweCAoTDE5KS4gQXQgNXMgaXQgb3ZlcnJhbiBvbiBFVkVSWSBwb2xsIG9mIHRoZSBmaXJzdCBlbmQtdG8tZW5kIHJ1bixcbiAqIGFuZCBhbiBvdmVycnVuIGlzIHJlcG9ydGVkIGFzIFwibm8gbmV0d29ya1wiLCBzbyB0b28gc21hbGwgYSBidWRnZXQgZG9lcyBub3RcbiAqIGRlZ3JhZGUgdGhpcyBnYXRlIFx1MjAxNCBpdCBzaWxlbnRseSBkaXNhYmxlcyBpdCB3aGlsZSB0aGUgZ2F0ZSBjbGFpbXMgdGhlXG4gKiBvcHBvc2l0ZS4gMzBzIGlzIH4xNXggdGhlIGlkbGUgY29zdCwgd2hpY2ggaXMgdGhhdCBpbmZsYXRpb24gd2l0aCByb29tLlxuICovXG5jb25zdCBBREJfRFVNUFNZU19USU1FT1VUX0lOX01JTExJU0VDT05EUyA9IDMwXzAwMDtcbmNvbnN0IEFQUElVTV9DT05ORUNUSU9OX1JFVFJZX0NPVU5UID0gMztcbmNvbnN0IEFQUElVTV9FU0NBTEFURURfU1RPUF9USU1FT1VUX0lOX01JTExJU0VDT05EUyA9IDUwMDA7XG5jb25zdCBBUFBJVU1fT1VUUFVUX1RBSUxfTUFYX0xFTkdUSCA9IDgwMDA7XG5jb25zdCBBUFBJVU1fUFJFRkxJR0hUX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gNTAwMDtcbmNvbnN0IEFQUElVTV9TVEFSVF9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyA9IDUwMDtcbmNvbnN0IEFQUElVTV9TVE9QX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gMTVfMDAwO1xuY29uc3QgQURCX1ZBVUxUX1NXRUVQX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gMzBfMDAwO1xuLy8gQXBwaXVtIGluc2VjdXJlIGZlYXR1cmUgbGV0dGluZyB0aGUgVWlBdXRvbWF0b3IyIGRyaXZlciBhdXRvLWRvd25sb2FkIGFcbi8vIENocm9tZWRyaXZlciBtYXRjaGluZyBPYnNpZGlhbidzIFdlYlZpZXcgQ2hyb21lIHZlcnNpb24uIEVuYWJsaW5nIGl0IG9uIHRoZVxuLy8gQXBwaXVtIHNlcnZlciAoaXQgaGFzIG5vIGVmZmVjdCBhcyBhIGNhcGFiaWxpdHkpIGF2b2lkcyB0aGUgZmFpbHVyZVxuLy8gXCJObyBDaHJvbWVkcml2ZXIgZm91bmQgdGhhdCBjYW4gYXV0b21hdGUgQ2hyb21lIC4uLlwiLlxuY29uc3QgQ0hST01FRFJJVkVSX0FVVE9ET1dOTE9BRF9GRUFUVVJFID0gJ3VpYXV0b21hdG9yMjpjaHJvbWVkcml2ZXJfYXV0b2Rvd25sb2FkJztcbmNvbnN0IENPTU1BTkRfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSAzMDA7XG5jb25zdCBERUZBVUxUX1RSQU5TUE9SVF9UWVBFID0gJ29ic2lkaWFuLWNkcCc7XG5jb25zdCBERVZJQ0VfSURMRV9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyA9IDIwMDA7XG4vKlxuICogQnVkZ2V0IGZvciBlYWNoIG9mIHRoZSB0d28gbGl2ZW5lc3MgcHJvYmVzIHRha2VuIGltbWVkaWF0ZWx5IGJlZm9yZSB0aGVcbiAqIHNlc3Npb24gKHNlZSBgZW11bGF0b3ItbGl2ZW5lc3MudHNgKS4gV2VsbCBhYm92ZSB0aGUgNXMgdGhlIHByZWZsaWdodCBwcm9iZXNcbiAqIHNoYXJlLCBiZWNhdXNlIHRoaXMgb25lIHJ1bnMgaW4gdGhlIHBvc3QtYm9vdCBjb250ZW50aW9uIHdpbmRvdyB0aGF0IGluZmxhdGVzXG4gKiBldmVyeSBgYWRiYCByb3VuZC10cmlwIDI1LTUweCAoTDQ1KSBcdTIwMTQgYW5kIGhlcmUgYSBmYWxzZSBcIm5vIGFuc3dlclwiIHdvdWxkXG4gKiBhYm9ydCBhIHJ1biB0aGF0IHdhcyBhYm91dCB0byB3b3JrLCB3aGljaCBpcyBhIHdvcnNlIGVycm9yIHRoYW4gd2FpdGluZy5cbiAqIDE1cyBpcyB3aGF0IHRoZSBzaXggaGFuZC1ib290cyB0aGF0IG1lYXN1cmVkIHRoZSB3ZWRnZSB1c2VkLCBhbmQgbm8gaGVhbHRoeVxuICogZ3Vlc3QgY2FtZSBjbG9zZSB0byBpdDogdGhlIGZhaWx1cmVzIGh1bmcgaW5kZWZpbml0ZWx5IHJhdGhlciB0aGFuIGFuc3dlcmluZ1xuICogc2xvd2x5LlxuICovXG5jb25zdCBERVZJQ0VfTElWRU5FU1NfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSAxNV8wMDA7XG4vKlxuICogSG93IG1hbnkgdGltZXMgZWFjaCBsaXZlbmVzcyBwcm9iZSBpcyBhc2tlZCBiZWZvcmUgaXRzIHNpbGVuY2UgaXMgYmVsaWV2ZWQuXG4gKiBPbmUgcmV0cnksIG1hdGNoaW5nIGBBVkRfUFJPQkVfQVRURU1QVF9DT1VOVGAgYW5kIGZvciB0aGUgc2FtZSByZWFzb246IHRoZVxuICogdmVyZGljdCBhYm9ydHMgdGhlIHJ1biwgc28gYSBzZWNvbmQgbG9vayBpcyBmYXIgY2hlYXBlciB0aGFuIGEgd3JvbmcgY2FsbC5cbiAqL1xuY29uc3QgREVWSUNFX0xJVkVORVNTX0FUVEVNUFRfQ09VTlQgPSAyO1xuLypcbiAqIEhvdyBtYW55IGVtdWxhdG9ycyBhIHJ1biBtYXkgYm9vdCBiZWZvcmUgZ2l2aW5nIHVwLiBPbmUgcmV0cnk6IHRoZSB3ZWRnZSB0aGF0XG4gKiBtb3RpdmF0ZXMgaXQgaXMgbm90IGRldGVybWluaXN0aWMgXHUyMDE0IG1lYXN1cmVkIDIwMjYtMDktMDUsIGEgZmlyc3QgZW11bGF0b3Igd2VudFxuICogcXVpZXQgMTI5cyBpbiBhbmQgdGhlIHJlcGxhY2VtZW50IGJvb3RlZCAxMXMgbGF0ZXIgcmFuIHRoZSB3aG9sZSBzdWl0ZSBcdTIwMTQgYnV0IGFcbiAqIGNvbGQgYm9vdCBjb3N0cyB+OTAtMjIwcywgc28gYSBzZWNvbmQgZmFpbHVyZSBpcyB3aGVyZSB0aGUgcnVuIHNob3VsZCBzdG9wIGFuZFxuICogc2F5IHNvIHJhdGhlciB0aGFuIGtlZXAgcGF5aW5nLlxuICovXG5jb25zdCBFTVVMQVRPUl9CT09UX0FUVEVNUFRfQ09VTlQgPSAyO1xuY29uc3QgRU1VTEFUT1JfQk9PVF9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyA9IDIwMDA7XG5jb25zdCBFTVVMQVRPUl9CT09UX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gMTIwXzAwMDtcbmNvbnN0IEVNVUxBVE9SX0VTQ0FMQVRFRF9TVE9QX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gNTAwMDtcbmNvbnN0IEVNVUxBVE9SX0xJU1RfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSAxMF8wMDA7XG5jb25zdCBFTVVMQVRPUl9PVVRQVVRfVEFJTF9NQVhfTEVOR1RIID0gODAwMDtcbmNvbnN0IEVNVUxBVE9SX1NUT1BfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMgPSA1MDA7XG5jb25zdCBFTVVMQVRPUl9TVE9QX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gMjBfMDAwO1xuLypcbiAqIDMwcywgbm90IHRoZSAxMHMgYSBgdGFza2xpc3RgIGNvc3RzIG9uIGFuIGlkbGUgaG9zdDogdGhpcyBxdWVyeSBydW5zIGluIHRoZVxuICogc2FtZSBwb3N0LWJvb3QgY29udGVudGlvbiB3aW5kb3cgdGhhdCBpbmZsYXRlcyBldmVyeSBgYWRiYCByb3VuZC10cmlwIDI1LTUweFxuICogKEw0NSksIGFuZCB0aGUgZmlyc3QgZW5kLXRvLWVuZCBydW4gb3ZlcnJhbiBhIDEwcyBidWRnZXQgdGhlcmUgXHUyMDE0IHNpbGVudGx5XG4gKiBkaXNhcm1pbmcgdGhlIHRlYXJkb3duIGVzY2FsYXRpb24uIFNpemVkIGxpa2UgYEFEQl9EVU1QU1lTX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTYCxcbiAqIGZvciB0aGUgc2FtZSByZWFzb24uXG4gKi9cbmNvbnN0IEhPU1RfUFJPQ0VTU19RVUVSWV9USU1FT1VUX0lOX01JTExJU0VDT05EUyA9IDMwXzAwMDtcbmNvbnN0IEhUVFBfTVVMVElQTEVfQ0hPSUNFUyA9IDMwMDtcbmNvbnN0IEhUVFBfT0sgPSAyMDA7XG5jb25zdCBLRVlDT0RFX01FTlUgPSA4MjtcbmNvbnN0IEtFWUNPREVfV0FLRVVQID0gMjI0O1xuY29uc3QgTUlMTElTRUNPTkRTX1BFUl9TRUNPTkQgPSAxMDAwO1xuY29uc3QgTkVUV09SS19SRUFEWV9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyA9IDIwMDA7XG5jb25zdCBTRVJWRVJfSU5TVEFMTF9USU1FT1VUX0lOX01JTExJU0VDT05EUyA9IDEyMF8wMDA7XG5jb25zdCBTRVJWRVJfTEFVTkNIX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTID0gMTIwXzAwMDtcbi8qXG4gKiBUaGUgc3luYyB0ZWFyZG93biBydW5zIGluc2lkZSBgcHJvY2Vzcy5vbignZXhpdCcpYCwgc28gdGhpcyBxdWVyeSBibG9ja3MgdGhlXG4gKiBleGl0IGl0c2VsZi4gU2hvcnQgb24gcHVycG9zZTogbG9zaW5nIHRoZSBlc2NhbGF0aW9uIGlzIGJldHRlciB0aGFuIGhvbGRpbmdcbiAqIHRoZSBoYW5kbGVyIGZvciB0aGUgYXN5bmMgcGF0aCdzIDMwcywgYW5kIHRoZSBzeW5jIGxvZyBuZXZlciBjbGFpbXMgYVxuICogdmVyaWZpZWQgc3RvcCBhbnl3YXkuXG4gKi9cbmNvbnN0IFNZTkNfVEVBUkRPV05fUVVFUllfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgPSA1MDAwO1xuXG4vKipcbiAqIEhvdyB0aGUgcmVxdWVzdGVkIGFwcCAoYXNhcikgdmVyc2lvbiB3aWxsIGJlIGFwcGxpZWQgdG8gYW4gb3duZWQgaW5zdGFuY2U7IGF0XG4gKiBtb3N0IG9uZSBmaWVsZCBpcyBzZXQgKHNlZSB7QGxpbmsgcmVzb2x2ZUFzYXJQbGFufSkuXG4gKi9cbmludGVyZmFjZSBBc2FyUGxhbiB7XG4gIC8qKlxuICBUaGUgdXNlcidzIG5ld2VzdCBpbnN0YWxsZWQgYXNhciB0byBwcm92aXNpb24gYXMtaXMgKG5vIGRvd25sb2FkKS5cbiAgICovXG4gIHJlYWRvbmx5IGFzYXI/OiBPd25lZEluc3RhbmNlQ29uZmlnWydhc2FyJ107XG5cbiAgLyoqXG4gIFRoZSBhcHAgdmVyc2lvbiB0byBkb3dubG9hZCBhbmQgYXNhci1zd2FwIG9udG8gdGhlIHNoZWxsLlxuICAgKi9cbiAgcmVhZG9ubHkgYXNhclZlcnNpb25Ub1N3YXA/OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSBhcHAgdmVyc2lvbiB3aG9zZSBvd24gaW5zdGFsbGVyIHNoZWxsIHRvIGRvd25sb2FkIChhIGRvd25ncmFkZSkuXG4gICAqL1xuICByZWFkb25seSBkb3duZ3JhZGVJbnN0YWxsZXJWZXJzaW9uPzogc3RyaW5nIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIE91dGNvbWUgb2Ygb25lIGBkdW1wc3lzIGNvbm5lY3Rpdml0eWAgcHJvYmU6IGV4YWN0bHkgb25lIGZpZWxkIGlzIHNldC5cbiAqXG4gKiBBIGZhaWxlZCBwcm9iZSBjYXJyaWVzICoqd2h5KiogaXQgZmFpbGVkIHJhdGhlciB0aGFuIGNvbGxhcHNpbmcgaW50byBcIm5vXG4gKiBvdXRwdXRcIiwgYmVjYXVzZSB0aGUgdHdvIGZhaWx1cmVzIGxvb2sgbm90aGluZyBhbGlrZSBpbiBwcmFjdGljZSBhbmQgb25seSBvbmVcbiAqIG9mIHRoZW0gaXMgd29ydGggd2FpdGluZyBvdXQgXHUyMDE0IGEgMzBzIHRpbWVvdXQgaXMgYSBjb250ZW5kZWQgZ3Vlc3QsIHdoaWxlIGFuXG4gKiBpbnN0YW50IGBlcnJvcjogY2xvc2VkYCBpcyBhIGRlYWQgb25lLlxuICovXG5pbnRlcmZhY2UgQ2hlY2tJc0VtdWxhdG9yR29uZVBhcmFtcyB7XG4gIC8qKlxuICBUaGUgZGV2aWNlIHRoZSBlbXVsYXRvciBzZXJ2ZXMuXG4gICAqL1xuICByZWFkb25seSBkZXZpY2VJZDogc3RyaW5nO1xuXG4gIC8qKlxuICBUaGUgZW11bGF0b3IgUElEcyB0aGlzIHJ1biBvd25zLlxuICAgKi9cbiAgcmVhZG9ubHkgb3duZWRFbXVsYXRvclBpZHM6IHJlYWRvbmx5IG51bWJlcltdO1xufVxuXG5pbnRlcmZhY2UgQ29ubmVjdGl2aXR5UHJvYmVSZXN1bHQge1xuICAvKipcbiAgV2h5IHRoZSBwcm9iZSBmYWlsZWQsIHNldCBpZmYgaXQgZGlkIG5vdCBhbnN3ZXIuXG4gICAqL1xuICByZWFkb25seSBmYWlsdXJlUmVhc29uPzogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICBUaGUgcmF3IGR1bXAsIHNldCBpZmYgdGhlIHByb2JlIGFuc3dlcmVkLlxuICAgKi9cbiAgcmVhZG9ubHkgb3V0cHV0Pzogc3RyaW5nIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFRoZSB0d28gcG9zdC1ib290IHJlYWRpbmVzcyBidWRnZXRzLCBjYXJyaWVkIHRvZ2V0aGVyIHNvIHRoZSBzdGFydGVkLWRldmljZVxuICogYW5kIHJldXNlZC1kZXZpY2UgYnJhbmNoZXMgY2Fubm90IGRyaWZ0IGFwYXJ0IG9uIHdoaWNoIGdhdGVzIHRoZXkgcnVuLlxuICovXG5pbnRlcmZhY2UgRGV2aWNlUmVhZGluZXNzVGltZW91dHMge1xuICAvKipcbiAgUmVzb2x2ZWQgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBwb3N0LWJvb3QgZGV2aWNlLWlkbGUgd2FpdCAoYDBgIHNraXBzIGl0KS5cbiAgICovXG4gIHJlYWRvbmx5IGRldmljZUlkbGVUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcjtcblxuICAvKipcbiAgUmVzb2x2ZWQgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBuZXR3b3JrLXJlYWR5IHdhaXQgKGAwYCBza2lwcyBpdCkuXG4gICAqL1xuICByZWFkb25seSBuZXR3b3JrUmVhZHlUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBUaGUgZW11bGF0b3IncyBjYXB0dXJlZCBvdXRwdXQsIGNhcnJpZWQgcGFzdCBib290IHNvIGEgZmFpbHVyZSBkdXJpbmcgc2Vzc2lvblxuICogY3JlYXRpb24gY2FuIHN0aWxsIHF1b3RlIGl0LlxuICpcbiAqIEJvb3QgdXNlZCB0byBiZSB0aGUgZW5kIG9mIHRoZSBlbXVsYXRvcidzIHVzZWZ1bG5lc3MgYXMgYSB3aXRuZXNzOiB0aGUgY2FwdHVyZVxuICogd2FzIGZyb3plbiB0aGUgbW9tZW50IGEgZGV2aWNlIGFwcGVhcmVkLCBhbmQgbm90aGluZyByZWFkIGl0IGFnYWluLiBCdXQgdGhlXG4gKiBsaW5lcyB0aGF0IGV4cGxhaW4gYSB3ZWRnZSBcdTIwMTQgYGRldGVjdGVkIGEgaGFuZ2luZyB0aHJlYWQgJ1FFTVUyIG1haW4gbG9vcCdgLFxuICogbmV0c2ltJ3MgYFVuYWJsZSB0byByZWNvbm5lY3QgdG8gcGFja2V0IHN0cmVhbWVyYCBcdTIwMTQgYXJlIHByaW50ZWQgKmFmdGVyKiB0aGF0LFxuICogd2hpbGUgdGhlIGhhcm5lc3MgaXMgaW5zaWRlIGBlc3RhYmxpc2hTZXNzaW9uYC4gU28gdGhlIHdpbmRvdyBub3cgY2xvc2VzIHdoZW5cbiAqIHRoZSBzZXNzaW9uIGlzIGVzdGFibGlzaGVkIHJhdGhlciB0aGFuIHdoZW4gdGhlIGRldmljZSBhcHBlYXJzLCBhbmQgdGhpcyBwYWlyXG4gKiBpcyB3aGF0IHRoZSBzZXNzaW9uIHBhdGggbmVlZHMgdG8gaG9sZCB0byBkbyB0aGF0IChzZWUgYGVtdWxhdG9yLWxpdmVuZXNzLnRzYCkuXG4gKi9cbmludGVyZmFjZSBFbXVsYXRvckNhcHR1cmUge1xuICAvKipcbiAgUmV0dXJucyB0aGUgY2FwdHVyZWQgc3Rkb3V0K3N0ZGVyciB0YWlsIChib3VuZGVkIHRvIHRoZSBtb3N0IHJlY2VudCBvdXRwdXQpLlxuICAgKi9cbiAgcmVhZG9ubHkgcmVhZDogKCkgPT4gc3RyaW5nO1xuXG4gIC8qKlxuICBGcmVlemVzIHRoZSB0YWlsLiBDYWxsZWQgb25jZSB0aGUgc2Vzc2lvbiBpcyBlc3RhYmxpc2hlZCBhbmQgdGhlIGVtdWxhdG9yIGhhcyBub3RoaW5nIGxlZnQgdG8gZXhwbGFpbi5cbiAgICovXG4gIHJlYWRvbmx5IHN0b3A6ICgpID0+IHZvaWQ7XG59XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3Ige0BsaW5rIEFwcGl1bVRyYW5zcG9ydEZhY3RvcnkuZW5zdXJlRGV2aWNlQ29ubmVjdGVkfS5cbiAqL1xuaW50ZXJmYWNlIEVuc3VyZURldmljZUNvbm5lY3RlZFBhcmFtcyB7XG4gIC8qKlxuICBBVkQgbmFtZSB0byBjb25uZWN0IHRvIChzdGFydGluZyBhIG5ldyBlbXVsYXRvciBpZiBub3QgYWxyZWFkeSBydW5uaW5nKS5cbiAgICovXG4gIHJlYWRvbmx5IGF2ZE5hbWU6IHN0cmluZztcblxuICAvKipcbiAgUmVzb2x2ZWQgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBwb3N0LWJvb3QgZGV2aWNlLWlkbGUgd2FpdCAoYDBgIHNraXBzIGl0KS5cbiAgICovXG4gIHJlYWRvbmx5IGRldmljZUlkbGVUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcjtcblxuICAvKipcbiAgV2hldGhlciB0aGUgYXV0by1zdGFydGVkIGVtdWxhdG9yIHdpbmRvdyBpcyBzaG93biAob21pdHRlZCBcdTIxOTIgaGlkZGVuKS5cbiAgICovXG4gIHJlYWRvbmx5IGlzRW11bGF0b3JWaXNpYmxlPzogYm9vbGVhbiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgUmVzb2x2ZWQgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBuZXR3b3JrLXJlYWR5IHdhaXQgKGAwYCBza2lwcyBpdCkuXG4gICAqL1xuICByZWFkb25seSBuZXR3b3JrUmVhZHlUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcjtcblxuICAvKipcbiAgV2hldGhlciB0aGUgYXV0by1zdGFydGVkIGVtdWxhdG9yIG1heSByZXN1bWUgYW5kIHJlZnJlc2ggdGhlIEFWRCdzIGJvb3Qgc25hcHNob3QgKG9taXR0ZWQgXHUyMTkyIGNvbGQgYm9vdCkuXG4gICAqL1xuICByZWFkb25seSBzaG91bGRSZXVzZUVtdWxhdG9yU25hcHNob3Q/OiBib29sZWFuIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFJlc3VsdCBvZiB7QGxpbmsgQXBwaXVtVHJhbnNwb3J0RmFjdG9yeS5lbnN1cmVEZXZpY2VDb25uZWN0ZWR9LlxuICovXG5pbnRlcmZhY2UgRW5zdXJlRGV2aWNlQ29ubmVjdGVkUmVzdWx0IHtcbiAgLyoqXG4gIFRoZSBhY3R1YWwgZGV2aWNlIElEIHRoYXQgaXMgY29ubmVjdGVkIChtYXkgZGlmZmVyIGZyb20gdGhlIHJlcXVlc3RlZCBvbmUpLlxuICAgKi9cbiAgcmVhZG9ubHkgYWN0dWFsRGV2aWNlSWQ6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGVtdWxhdG9yJ3Mgb3V0cHV0IGNhcHR1cmUsIHdoZW4gdGhpcyBydW4gc3RhcnRlZCBpdC4gQWJzZW50IGZvciBhblxuICAgKiBhZG9wdGVkIGRldmljZSwgd2hvc2UgZW11bGF0b3IgdGhpcyBydW4gbmV2ZXIgc3Bhd25lZCBhbmQgd2hvc2Ugb3V0cHV0IGl0XG4gICAqIHRoZXJlZm9yZSBuZXZlciBoYWQuXG4gICAqL1xuICByZWFkb25seSBlbXVsYXRvckNhcHR1cmU/OiBFbXVsYXRvckNhcHR1cmUgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSBlbXVsYXRvciBwcm9jZXNzLCBpZiBvbmUgd2FzIGF1dG8tc3RhcnRlZC5cbiAgICovXG4gIHJlYWRvbmx5IGVtdWxhdG9yUHJvY2Vzcz86IENoaWxkUHJvY2VzcyB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogVGhlIGVtdWxhdG9yIHByb2Nlc3NlcyB0aGlzIHJ1biBpcyByZXNwb25zaWJsZSBmb3Iga2lsbGluZyBcdTIwMTQgdGhlIGxhdW5jaGVyXG4gICAqIHBsdXMgdGhlIFFFTVUgYmFja2VuZCBpdCBmb3JrZWQsIGlkZW50aWZpZWQgYnkgZGlmZmluZyB0aGUgaG9zdCdzIHByb2Nlc3NcbiAgICogbGlzdCBhY3Jvc3MgdGhlIGxhdW5jaC4gRW1wdHkgd2hlbiB0aGUgZGV2aWNlIHdhcyByZXVzZWQgcmF0aGVyIHRoYW5cbiAgICogc3RhcnRlZC4gU2VlIGBlbXVsYXRvci1iYWNrZW5kLnRzYCBmb3Igd2h5IHRoZSBsYXVuY2hlcidzIFBJRCBhbG9uZSBpcyBub3RcbiAgICogZW5vdWdoLlxuICAgKi9cbiAgcmVhZG9ubHkgb3duZWRFbXVsYXRvclBpZHM6IHJlYWRvbmx5IG51bWJlcltdO1xufVxuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHtAbGluayBBcHBpdW1UcmFuc3BvcnRGYWN0b3J5LmVzdGFibGlzaFNlc3Npb259LlxuICovXG5pbnRlcmZhY2UgRXN0YWJsaXNoU2Vzc2lvblBhcmFtcyB7XG4gIC8qKlxuICBUaGUgQW5kcm9pZCBwYWNrYWdlIHRoZSBzZXNzaW9uIGRyaXZlcy5cbiAgICovXG4gIHJlYWRvbmx5IGFwcElkOiBzdHJpbmc7XG5cbiAgLyoqXG4gIFRoZSBtYXJrZXIgb2YgdGhlIGFkb3B0ZWQgc2VydmVyLCB3aGVuIGFuIGVhcmxpZXIgcnVuIG9mIHRoaXMgaGFybmVzcyBsZWZ0IG9uZS5cbiAgICovXG4gIHJlYWRvbmx5IGFwcGl1bVNlcnZlck1hcmtlcjogQXBwaXVtU2VydmVyTWFya2VyIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICBSZXNvbHZlZCB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgYSByZXBsYWNlbWVudCBBcHBpdW0gc2VydmVyIHRvIGJlY29tZSByZWFkeS5cbiAgICovXG4gIHJlYWRvbmx5IGFwcGl1bVN0YXJ0VGltZW91dEluTWlsbGlzZWNvbmRzOiBudW1iZXI7XG5cbiAgLyoqXG4gIFRoZSBkZXZpY2UgdGhlIHNlc3Npb24gaXMgZXN0YWJsaXNoZWQgYWdhaW5zdC5cbiAgICovXG4gIHJlYWRvbmx5IGRldmljZUlkOiBzdHJpbmc7XG5cbiAgLyoqXG4gIFdoZXRoZXIgdGhlIHNlcnZlciB3YXMgYWRvcHRlZCByYXRoZXIgdGhhbiBzdGFydGVkIGJ5IHRoaXMgcnVuLlxuICAgKi9cbiAgcmVhZG9ubHkgaXNBZG9wdGVkU2VydmVyOiBib29sZWFuO1xuXG4gIC8qKlxuICBXaGV0aGVyIGEgcmVwbGFjZW1lbnQgc2VydmVyJ3MgY29uc29sZSB3aW5kb3cgaXMgc2hvd24gKG9taXR0ZWQgXHUyMTkyIGhpZGRlbikuXG4gICAqL1xuICByZWFkb25seSBpc0FwcGl1bUNvbnNvbGVWaXNpYmxlPzogYm9vbGVhbiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgVGhlIEFwcGl1bSBzZXJ2ZXIgcG9ydC5cbiAgICovXG4gIHJlYWRvbmx5IHBvcnQ6IG51bWJlcjtcblxuICAvKipcbiAgUmVzb2x2ZWQgV2ViRHJpdmVySU8gY29ubmVjdGlvbiByZXRyeSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcy5cbiAgICovXG4gIHJlYWRvbmx5IHNlc3Npb25Db25uZWN0aW9uUmV0cnlUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcjtcblxuICAvKipcbiAgV2hldGhlciBBcHBpdW0gYXV0by1zdGFydCBpcyBhbGxvd2VkIFx1MjAxNCBhIGBmYWxzZWAgaGVyZSBhbHNvIGZvcmJpZHMgcmVwbGFjaW5nIGEgd2VkZ2VkIHNlcnZlci5cbiAgICovXG4gIHJlYWRvbmx5IHNob3VsZEF1dG9TdGFydEFwcGl1bT86IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSBBcHBpdW0gc2VydmVyIFVSTC5cbiAgICovXG4gIHJlYWRvbmx5IHVybDogVVJMO1xufVxuXG4vKipcbiAqIFJlc3VsdCBvZiB7QGxpbmsgQXBwaXVtVHJhbnNwb3J0RmFjdG9yeS5lc3RhYmxpc2hTZXNzaW9ufS5cbiAqL1xuaW50ZXJmYWNlIEVzdGFibGlzaFNlc3Npb25SZXN1bHQge1xuICAvKipcbiAgVGhlIHJlcGxhY2VtZW50IEFwcGl1bSBzZXJ2ZXIgcHJvY2Vzcywgd2hlbiBhIHdlZGdlZCBvbmUgaGFkIHRvIGJlIHJlc3RhcnRlZC5cbiAgICovXG4gIHJlYWRvbmx5IGFwcGl1bVByb2Nlc3M/OiBDaGlsZFByb2Nlc3MgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSBlc3RhYmxpc2hlZCBzZXNzaW9uLlxuICAgKi9cbiAgcmVhZG9ubHkgYnJvd3NlcjogQXdhaXRlZDxSZXR1cm5UeXBlPHR5cGVvZiByZW1vdGU+Pjtcbn1cblxuLyoqXG4gKiBUaGUgbG9jYWxseS1pbnN0YWxsZWQgT2JzaWRpYW4gc2hlbGwgcmVzb2x2ZWQgYnkge0BsaW5rIHJlc29sdmVJbnN0YWxsZWRTaGVsbE9yTnVsbH0uXG4gKi9cbmludGVyZmFjZSBIb3N0Q29tbWFuZFF1ZXJ5IHtcbiAgLyoqXG4gIFRoZSBleGVjdXRhYmxlIHRvIHJ1bi5cbiAgICovXG4gIHJlYWRvbmx5IGNvbW1hbmQ6IHN0cmluZztcblxuICAvKipcbiAgVGhlIGNvbW1hbmQncyBhcmd1bWVudHMuXG4gICAqL1xuICByZWFkb25seSBjb21tYW5kQXJndW1lbnRzOiBzdHJpbmdbXTtcbn1cblxuaW50ZXJmYWNlIEluc3RhbGxlZFNoZWxsIHtcbiAgLyoqXG4gIEFic29sdXRlIHBhdGggdG8gdGhlIGluc3RhbGxlZCBzaGVsbCBleGVjdXRhYmxlLlxuICAgKi9cbiAgcmVhZG9ubHkgZXhlUGF0aDogc3RyaW5nO1xuXG4gIC8qKlxuICBUaGUgZGV0ZWN0ZWQgc2hlbGwgdmVyc2lvbiwgb3IgYHVuZGVmaW5lZGAgd2hlbiBpdCBjYW5ub3QgYmUgZGV0ZXJtaW5lZC5cbiAgICovXG4gIHJlYWRvbmx5IHNoZWxsVmVyc2lvbjogc3RyaW5nIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIEEgc3Bhd25lZCBjaGlsZCBwcm9jZXNzICh0aGUgQW5kcm9pZCBlbXVsYXRvciBvciB0aGUgQXBwaXVtIHNlcnZlcikgdG9nZXRoZXJcbiAqIHdpdGggaGVscGVycyB0byBpbnNwZWN0IGl0cyBjYXB0dXJlZCBvdXRwdXQgYW5kIGV4aXQgc3RhdHVzLlxuICovXG5pbnRlcmZhY2UgUGFyc2VQb3J0T3duZXJQaWRzUGFyYW1zIHtcbiAgLyoqXG4gIFJhdyBzdGRvdXQgb2YgdGhlIHBsYXRmb3JtJ3MgcG9ydCBxdWVyeS5cbiAgICovXG4gIHJlYWRvbmx5IG91dHB1dDogc3RyaW5nO1xuXG4gIC8qKlxuICBUaGUgcG9ydCB0aGF0IHdhcyBxdWVyaWVkLlxuICAgKi9cbiAgcmVhZG9ubHkgcG9ydDogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgUHJvY2Vzc0xhdW5jaCB7XG4gIC8qKlxuICBUaGUgc3Bhd25lZCBwcm9jZXNzLlxuICAgKi9cbiAgcHJvY2VzczogQ2hpbGRQcm9jZXNzO1xuXG4gIC8qKlxuICBSZXR1cm5zIHRoZSBleGl0IC8gc3Bhd24tZmFpbHVyZSBkZXRhaWxzIG9uY2UgdGhlIHByb2Nlc3MgaXMgbm8gbG9uZ2VyIHJ1bm5pbmcsIG90aGVyd2lzZSBgdW5kZWZpbmVkYC5cbiAgICovXG4gIHJlYWRFeGl0SW5mbzogKCkgPT4gUHJvY2Vzc0V4aXRJbmZvIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICBSZXR1cm5zIHRoZSBjYXB0dXJlZCBzdGRvdXQrc3RkZXJyIChib3VuZGVkIHRvIHRoZSBtb3N0IHJlY2VudCBvdXRwdXQpLlxuICAgKi9cbiAgcmVhZE91dHB1dDogKCkgPT4gc3RyaW5nO1xuXG4gIC8qKlxuICBTdG9wcyBhY2N1bXVsYXRpbmcgb3V0cHV0LiBDYWxsIG9uY2Ugc3RhcnR1cCBoYXMgc3VjY2VlZGVkLlxuICAgKi9cbiAgc3RvcENhcHR1cmU6ICgpID0+IHZvaWQ7XG59XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3Ige0BsaW5rIEFwcGl1bVRyYW5zcG9ydEZhY3Rvcnkuc3RhcnRBcHBpdW1BbmRFbXVsYXRvcn0uXG4gKi9cbmludGVyZmFjZSBSZWNsYWltVW5zdG9wcGVkQXBwaXVtU2VydmVyUGFyYW1zIHtcbiAgLyoqXG4gIFRoZSBtYXJrZXIgdGhhdCBwcm92ZXMgdGhlIGxlZnRvdmVyIGlzIHRoaXMgaGFybmVzcydzIG93bi5cbiAgICovXG4gIHJlYWRvbmx5IG1hcmtlcjogQXBwaXVtU2VydmVyTWFya2VyO1xuXG4gIC8qKlxuICBUaGUgcG9ydCBpdCBpcyBob2xkaW5nLlxuICAgKi9cbiAgcmVhZG9ubHkgcG9ydDogbnVtYmVyO1xuXG4gIC8qKlxuICBXaGV0aGVyIHRoaXMgcnVuIGlzIGFsbG93ZWQgdG8gc3RhcnQgYSByZXBsYWNlbWVudC5cbiAgICovXG4gIHJlYWRvbmx5IHNob3VsZEF1dG9TdGFydEFwcGl1bT86IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSBzZXJ2ZXIncyBVUkwuXG4gICAqL1xuICByZWFkb25seSB1cmw6IFVSTDtcbn1cblxuaW50ZXJmYWNlIFN0YXJ0QXBwaXVtQW5kRW11bGF0b3JQYXJhbXMge1xuICAvKipcbiAgUmVzb2x2ZWQgdGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIHRoZSBhdXRvLXN0YXJ0ZWQgQXBwaXVtIHNlcnZlciB0byBiZWNvbWUgcmVhZHkuXG4gICAqL1xuICByZWFkb25seSBhcHBpdW1TdGFydFRpbWVvdXRJbk1pbGxpc2Vjb25kczogbnVtYmVyO1xuXG4gIC8qKlxuICBUaGUgQXBwaXVtIHNlcnZlciBVUkwuXG4gICAqL1xuICByZWFkb25seSBhcHBpdW1Vcmw6IFVSTDtcblxuICAvKipcbiAgQVZEIG5hbWUgdG8gc3RhcnQuXG4gICAqL1xuICByZWFkb25seSBhdmROYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gIFJlc29sdmVkIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgcG9zdC1ib290IGRldmljZS1pZGxlIHdhaXQgKGAwYCBza2lwcyBpdCkuXG4gICAqL1xuICByZWFkb25seSBkZXZpY2VJZGxlVGltZW91dEluTWlsbGlzZWNvbmRzOiBudW1iZXI7XG5cbiAgLyoqXG4gIFdoZXRoZXIgdGhlIGF1dG8tc3RhcnRlZCBBcHBpdW0gc2VydmVyIGNvbnNvbGUgd2luZG93IGlzIHNob3duIChvbWl0dGVkIFx1MjE5MiBoaWRkZW4pLlxuICAgKi9cbiAgcmVhZG9ubHkgaXNBcHBpdW1Db25zb2xlVmlzaWJsZT86IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFdoZXRoZXIgdGhlIGF1dG8tc3RhcnRlZCBlbXVsYXRvciB3aW5kb3cgaXMgc2hvd24gKG9taXR0ZWQgXHUyMTkyIGhpZGRlbikuXG4gICAqL1xuICByZWFkb25seSBpc0VtdWxhdG9yVmlzaWJsZT86IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFJlc29sdmVkIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgbmV0d29yay1yZWFkeSB3YWl0IChgMGAgc2tpcHMgaXQpLlxuICAgKi9cbiAgcmVhZG9ubHkgbmV0d29ya1JlYWR5VGltZW91dEluTWlsbGlzZWNvbmRzOiBudW1iZXI7XG5cbiAgLyoqXG4gIFRoZSBBcHBpdW0gc2VydmVyIHBvcnQuXG4gICAqL1xuICByZWFkb25seSBwb3J0OiBudW1iZXI7XG5cbiAgLyoqXG4gIFdoZXRoZXIgbWlzc2luZyBBcHBpdW0gZGVwZW5kZW5jaWVzIG1heSBiZSBhdXRvLWluc3RhbGxlZCBiZWZvcmUgdGhlIHNlcnZlciBpcyBhdXRvLXN0YXJ0ZWQuXG4gICAqL1xuICByZWFkb25seSBzaG91bGRBdXRvSW5zdGFsbEFwcGl1bURlcGVuZGVuY2llczogYm9vbGVhbjtcblxuICAvKipcbiAgV2hldGhlciBBcHBpdW0gYXV0by1zdGFydCBpcyBhbGxvd2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgc2hvdWxkQXV0b1N0YXJ0QXBwaXVtPzogYm9vbGVhbiB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgV2hldGhlciB0aGUgYXV0by1zdGFydGVkIGVtdWxhdG9yIG1heSByZXN1bWUgYW5kIHJlZnJlc2ggdGhlIEFWRCdzIGJvb3Qgc25hcHNob3QgKG9taXR0ZWQgXHUyMTkyIGNvbGQgYm9vdCkuXG4gICAqL1xuICByZWFkb25seSBzaG91bGRSZXVzZUVtdWxhdG9yU25hcHNob3Q/OiBib29sZWFuIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFJlc3VsdCBvZiB7QGxpbmsgQXBwaXVtVHJhbnNwb3J0RmFjdG9yeS5zdGFydEFwcGl1bUFuZEVtdWxhdG9yfS5cbiAqL1xuaW50ZXJmYWNlIFN0YXJ0QXBwaXVtQW5kRW11bGF0b3JSZXN1bHQge1xuICAvKipcbiAgVGhlIGFjdHVhbCBkZXZpY2UgSUQgdGhhdCBpcyBjb25uZWN0ZWQgKG1heSBkaWZmZXIgZnJvbSB0aGUgcmVxdWVzdGVkIG9uZSkuXG4gICAqL1xuICByZWFkb25seSBhY3R1YWxEZXZpY2VJZDogc3RyaW5nO1xuXG4gIC8qKlxuICBUaGUgQXBwaXVtIHNlcnZlciBwcm9jZXNzLCBpZiBvbmUgd2FzIGF1dG8tc3RhcnRlZC5cbiAgICovXG4gIHJlYWRvbmx5IGFwcGl1bVByb2Nlc3M/OiBDaGlsZFByb2Nlc3MgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSBhZG9wdGVkIHNlcnZlcidzIG1hcmtlciwgd2hlbiBhbiBlYXJsaWVyIHJ1biBvZiB0aGlzIGhhcm5lc3MgbGVmdCBvbmUuXG4gICAqL1xuICByZWFkb25seSBhcHBpdW1TZXJ2ZXJNYXJrZXI/OiBBcHBpdW1TZXJ2ZXJNYXJrZXIgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSBlbXVsYXRvcidzIG91dHB1dCBjYXB0dXJlLCB3aGVuIHRoaXMgcnVuIHN0YXJ0ZWQgaXQuXG4gICAqL1xuICByZWFkb25seSBlbXVsYXRvckNhcHR1cmU/OiBFbXVsYXRvckNhcHR1cmUgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSBlbXVsYXRvciBwcm9jZXNzLCBpZiBvbmUgd2FzIGF1dG8tc3RhcnRlZC5cbiAgICovXG4gIHJlYWRvbmx5IGVtdWxhdG9yUHJvY2Vzcz86IENoaWxkUHJvY2VzcyB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogV2hldGhlciBhbiBhbHJlYWR5LWxpc3RlbmluZyBzZXJ2ZXIgd2FzIGFkb3B0ZWQgcmF0aGVyIHRoYW4gc3RhcnRlZCBieSB0aGlzXG4gICAqIHJ1bi4gT25seSBhbiBhZG9wdGVkIHNlcnZlciBjYW4gYmUgdGhlIHN0YWxlIG9uZSBgd2VkZ2VkLWFwcGl1bS1zZXJ2ZXIudHNgXG4gICAqIGRlc2NyaWJlcy5cbiAgICovXG4gIHJlYWRvbmx5IGlzQWRvcHRlZEFwcGl1bVNlcnZlcjogYm9vbGVhbjtcblxuICAvKipcbiAgVGhlIGVtdWxhdG9yIHByb2Nlc3NlcyB0aGlzIHJ1biBpcyByZXNwb25zaWJsZSBmb3Iga2lsbGluZzsgZW1wdHkgd2hlbiB0aGUgZGV2aWNlIHdhcyByZXVzZWQuXG4gICAqL1xuICByZWFkb25seSBvd25lZEVtdWxhdG9yUGlkczogcmVhZG9ubHkgbnVtYmVyW107XG59XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3Ige0BsaW5rIEFwcGl1bVRyYW5zcG9ydEZhY3Rvcnkuc3dlZXBEZXZpY2VMZWZ0b3ZlclZhdWx0c30uXG4gKi9cbmludGVyZmFjZSBTdG9wQXV0b1N0YXJ0ZWRBcHBpdW1TZXJ2ZXJQYXJhbXMge1xuICAvKipcbiAgVGhlIHNlcnZlciBwcm9jZXNzIHRoaXMgcnVuIHNwYXduZWQuXG4gICAqL1xuICByZWFkb25seSBhcHBpdW1Qcm9jZXNzOiBDaGlsZFByb2Nlc3M7XG5cbiAgLyoqXG4gIFRoZSBwb3J0IGl0IHdhcyBzdGFydGVkIG9uLCB3aG9zZSBtYXJrZXIgaXMgY2xlYXJlZCBvciBzdGFtcGVkIGJ5IHRoZSBvdXRjb21lLlxuICAgKi9cbiAgcmVhZG9ubHkgcG9ydDogbnVtYmVyO1xuXG4gIC8qKlxuICBUaGUgc2VydmVyJ3MgVVJMLCBwb2xsZWQgdG8gZGVjaWRlIHdoZXRoZXIgaXQgYWN0dWFsbHkgc3RvcHBlZC5cbiAgICovXG4gIHJlYWRvbmx5IHVybDogVVJMO1xufVxuXG5pbnRlcmZhY2UgU3RvcEF1dG9TdGFydGVkRW11bGF0b3JQYXJhbXMge1xuICAvKipcbiAgVGhlIEFWRCBuYW1lLCBuYW1lZCBpbiB0aGUgd2FybmluZyBzbyB0aGUgbGVmdG92ZXIgaXMgaWRlbnRpZmlhYmxlLlxuICAgKi9cbiAgcmVhZG9ubHkgYXZkTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICBUaGUgZGV2aWNlIHRoZSBlbXVsYXRvciBpcyBzZXJ2aW5nLCBwb2xsZWQgdG8gZGVjaWRlIHdoZXRoZXIgaXQgYWN0dWFsbHkgc3RvcHBlZC5cbiAgICovXG4gIHJlYWRvbmx5IGRldmljZUlkOiBzdHJpbmc7XG5cbiAgLyoqXG4gIFRoZSBlbXVsYXRvciBsYXVuY2hlciBwcm9jZXNzIHRoaXMgcnVuIHNwYXduZWQuXG4gICAqL1xuICByZWFkb25seSBlbXVsYXRvclByb2Nlc3M6IENoaWxkUHJvY2VzcztcblxuICAvKipcbiAgVGhlIGVtdWxhdG9yIFBJRHMgdGhpcyBydW4gb3ducywgZXNjYWxhdGVkIHRvIHdoZW4gdGhlIGxhdW5jaGVyJ3MgdHJlZSBraWxsIGxlYXZlcyBvbmUgYmVoaW5kLlxuICAgKi9cbiAgcmVhZG9ubHkgb3duZWRFbXVsYXRvclBpZHM6IHJlYWRvbmx5IG51bWJlcltdO1xufVxuXG5pbnRlcmZhY2UgU3RvcEF1dG9TdGFydGVkUHJvY2Vzc2VzUGFyYW1zIHtcbiAgLyoqXG4gIFRoZSBBcHBpdW0gc2VydmVyIHByb2Nlc3MsIHdoZW4gdGhpcyBydW4gc3RhcnRlZCBvbmUuXG4gICAqL1xuICByZWFkb25seSBhcHBpdW1Qcm9jZXNzPzogQ2hpbGRQcm9jZXNzIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICBUaGUgQVZEIG5hbWUsIGZvciB0aGUgZW11bGF0b3IncyB3YXJuaW5nLlxuICAgKi9cbiAgcmVhZG9ubHkgYXZkTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICBUaGUgZGV2aWNlIHRoZSBlbXVsYXRvciBpcyBzZXJ2aW5nLCB3aGVuIHRoaXMgcnVuIHN0YXJ0ZWQgb25lLlxuICAgKi9cbiAgcmVhZG9ubHkgZGV2aWNlSWQ/OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSBlbXVsYXRvciBsYXVuY2hlciBwcm9jZXNzLCB3aGVuIHRoaXMgcnVuIHN0YXJ0ZWQgb25lLlxuICAgKi9cbiAgcmVhZG9ubHkgZW11bGF0b3JQcm9jZXNzPzogQ2hpbGRQcm9jZXNzIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICBUaGUgZW11bGF0b3IgUElEcyB0aGlzIHJ1biBvd25zLlxuICAgKi9cbiAgcmVhZG9ubHkgb3duZWRFbXVsYXRvclBpZHM6IHJlYWRvbmx5IG51bWJlcltdO1xuXG4gIC8qKlxuICBUaGUgQXBwaXVtIHBvcnQuXG4gICAqL1xuICByZWFkb25seSBwb3J0OiBudW1iZXI7XG5cbiAgLyoqXG4gIFRoZSBBcHBpdW0gc2VydmVyIFVSTC5cbiAgICovXG4gIHJlYWRvbmx5IHVybDogVVJMO1xufVxuXG5pbnRlcmZhY2UgU3dlZXBEZXZpY2VMZWZ0b3ZlclZhdWx0c1BhcmFtcyB7XG4gIC8qKlxuICBUaGUgZGV2aWNlIFVESUQgdG8gc3dlZXAuXG4gICAqL1xuICByZWFkb25seSBkZXZpY2VJZDogc3RyaW5nO1xuXG4gIC8qKlxuICBUaGUgZGV2aWNlLXNpZGUgZGlyZWN0b3J5IE9ic2lkaWFuIE1vYmlsZSBzdG9yZXMgaXRzIHZhdWx0cyBpbi5cbiAgICovXG4gIHJlYWRvbmx5IHZhdWx0QmFzZVBhdGg6IHN0cmluZztcbn1cblxubGV0IGNhY2hlZFRyYW5zcG9ydDogT2JzaWRpYW5UcmFuc3BvcnQgfCB1bmRlZmluZWQ7XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3Ige0BsaW5rIHJlc29sdmVBbmRSZXBvcnRDb21wYXRpYmlsaXR5fS5cbiAqL1xuaW50ZXJmYWNlIFJlc29sdmVBbmRSZXBvcnRDb21wYXRpYmlsaXR5UGFyYW1zIHtcbiAgLyoqXG4gICAqIFRoZSBhcHAgKGFzYXIpIHZlcnNpb24gdGhhdCB3aWxsIGJlIHN3YXBwZWQgb250byB0aGUgc2hlbGwsIG9yIGB1bmRlZmluZWRgXG4gICAqIHdoZW4gbm8gYXNhci1zd2FwIHdpbGwgaGFwcGVuIChub3RoaW5nIGlzIGNoZWNrZWQgdGhlbikuXG4gICAqL1xuICByZWFkb25seSBhcHBWZXJzaW9uOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gIFRoZSByZXNvbHZlZCBpbnN0YWxsZXIvc2hlbGwgdmVyc2lvbiwgb3IgYHVuZGVmaW5lZGAuXG4gICAqL1xuICByZWFkb25seSBpbnN0YWxsZXJWZXJzaW9uOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgYW4gYCd1bnJ1bm5hYmxlJ2AgdmVyZGljdCB0aHJvd3Mge0BsaW5rIEluY29tcGF0aWJsZUluc3RhbGxlclZlcnNpb25FcnJvcn1cbiAgICogKGB0cnVlYCkgb3IgcHJvY2VlZHMgdG8gbGF1bmNoIHdpdGggdGhlIHZlcmRpY3Qgc3VyZmFjZWQgYXMgZGF0YSAoYGZhbHNlYCkuXG4gICAqL1xuICByZWFkb25seSBzaG91bGRUaHJvd09uSW5jb21wYXRpYmxlSW5zdGFsbGVyOiBib29sZWFuO1xuXG4gIC8qKlxuICBXaGV0aGVyIGEgYCduYWdnZWQnYCAob3IgcHJvY2VlZGluZy1gJ3VucnVubmFibGUnYCkgdmVyZGljdCBpcyBsb2dnZWQuXG4gICAqL1xuICByZWFkb25seSBzaG91bGRXYXJuT25Db21wYXRpYmlsaXR5SXNzdWVzOiBib29sZWFuO1xufVxuXG4vKipcbiAqIFRoZSBzbGljZSBvZiBgd2ViZHJpdmVyaW9gJ3Mgc3VyZmFjZSB0aGUgQXBwaXVtIGZhY3RvcnkgY2FsbHMsIG5hbWVkIHNvIHRoZVxuICogbGF6eSBsb2FkIGhhcyBhIHJldHVybiB0eXBlIHdpdGhvdXQgYSBzdGF0aWMgaW1wb3J0IG9mIHRoZSBtb2R1bGUgaXRzZWxmLlxuICovXG5pbnRlcmZhY2UgV2FpdEZvckVtdWxhdG9yU3RvcHBlZFBhcmFtcyB7XG4gIC8qKlxuICBUaGUgZGV2aWNlIHRoZSBlbXVsYXRvciBzZXJ2ZXMuXG4gICAqL1xuICByZWFkb25seSBkZXZpY2VJZDogc3RyaW5nO1xuXG4gIC8qKlxuICBUaGUgZW11bGF0b3IgUElEcyB0aGlzIHJ1biBvd25zLlxuICAgKi9cbiAgcmVhZG9ubHkgb3duZWRFbXVsYXRvclBpZHM6IHJlYWRvbmx5IG51bWJlcltdO1xuXG4gIC8qKlxuICBIb3cgbG9uZyB0byB3YWl0IGZvciB0aGUgZW11bGF0b3IgdG8gZGlzYXBwZWFyLCBpbiBtaWxsaXNlY29uZHMuXG4gICAqL1xuICByZWFkb25seSB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFdlYmRyaXZlcmlvTW9kdWxlIHtcbiAgLyoqXG4gIFJlYXR0YWNoZXMgdG8gYW4gZXhpc3RpbmcgV2ViRHJpdmVyIHNlc3Npb24uXG4gICAqL1xuICByZWFkb25seSBhdHRhY2g6IHR5cGVvZiBhdHRhY2g7XG5cbiAgLyoqXG4gIENyZWF0ZXMgYSBuZXcgV2ViRHJpdmVyIHNlc3Npb24uXG4gICAqL1xuICByZWFkb25seSByZW1vdGU6IHR5cGVvZiByZW1vdGU7XG59XG5cbi8qKlxuICogRW5jYXBzdWxhdGVzIGFsbCBBcHBpdW0gdHJhbnNwb3J0IGNyZWF0aW9uIGxvZ2ljLCBpbmNsdWRpbmcgQXBwaXVtIHNlcnZlclxuICogc3RhcnR1cCwgZW11bGF0b3IgbWFuYWdlbWVudCwgYW5kIFdlYkRyaXZlcklPIHNlc3Npb24gZXN0YWJsaXNobWVudC5cbiAqXG4gKiBVc2luZyBhIGNsYXNzIGF2b2lkcyB0aHJlYWRpbmcgdGhlIHRyYW5zcG9ydCBgdHlwZWAgbGFiZWwgdGhyb3VnaCBldmVyeVxuICogaGVscGVyIGZ1bmN0aW9uIFx1MjAxNCBgdGhpcy5sb2coKWAgYXV0b21hdGljYWxseSBwcmVmaXhlcyBpdC5cbiAqL1xuY2xhc3MgQXBwaXVtVHJhbnNwb3J0RmFjdG9yeSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgdHlwZTogc3RyaW5nO1xuXG4gIHB1YmxpYyBjb25zdHJ1Y3Rvcih0eXBlOiBzdHJpbmcpIHtcbiAgICB0aGlzLnR5cGUgPSB0eXBlO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gQXBwaXVtIHRyYW5zcG9ydCBieSBlc3RhYmxpc2hpbmcgYSBXZWJEcml2ZXJJTyBzZXNzaW9uLlxuICAgKlxuICAgKiBJZiBgb3B0aW9ucy5zZXNzaW9uSWRgIGlzIHByZXNlbnQsIHJlYXR0YWNoZXMgdG8gdGhlIGV4aXN0aW5nIHNlc3Npb25cbiAgICogaW5zdGVhZCBvZiBjcmVhdGluZyBhIG5ldyBvbmUuIFRoaXMgYXZvaWRzIGR1cGxpY2F0ZSBBcHBpdW0vQURCIGNvbm5lY3Rpb25zXG4gICAqIHdoZW4gdGVzdCB3b3JrZXJzIHJldXNlIHRoZSBnbG9iYWwgc2V0dXAncyBzZXNzaW9uLlxuICAgKlxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIEFuZHJvaWQgQXBwaXVtIHRyYW5zcG9ydCBvcHRpb25zLlxuICAgKiBAcmV0dXJucyBBIGNvbmZpZ3VyZWQgQXBwaXVtIHRyYW5zcG9ydC5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBjcmVhdGUob3B0aW9uczogT2JzaWRpYW5BbmRyb2lkQXBwaXVtVHJhbnNwb3J0T3B0aW9ucyk6IFByb21pc2U8T2JzaWRpYW5UcmFuc3BvcnQ+IHtcbiAgICBpZiAob3B0aW9ucy5zZXNzaW9uSWQgIT09IHVuZGVmaW5lZCAmJiBvcHRpb25zLmRldmljZUlkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB0aGlzLmF0dGFjaFRvRXhpc3RpbmdTZXNzaW9uKG9wdGlvbnMuc2Vzc2lvbklkLCBvcHRpb25zLmRldmljZUlkLCBvcHRpb25zKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5jcmVhdGVOZXdTZXNzaW9uKG9wdGlvbnMpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBhdHRhY2hUb0V4aXN0aW5nU2Vzc2lvbihcbiAgICBzZXNzaW9uSWQ6IHN0cmluZyxcbiAgICBkZXZpY2VJZDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IE9ic2lkaWFuQW5kcm9pZEFwcGl1bVRyYW5zcG9ydE9wdGlvbnNcbiAgKTogUHJvbWlzZTxPYnNpZGlhblRyYW5zcG9ydD4ge1xuICAgIGNvbnN0IHVybCA9IG5ldyBVUkwob3B0aW9ucy5hcHBpdW1VcmwpO1xuICAgIGNvbnN0IHBvcnQgPSBOdW1iZXIodXJsLnBvcnQpO1xuICAgIGNvbnN0IGFwcElkID0gb3B0aW9ucy5hcHBJZCA/PyBBUFBfUEFDS0FHRTtcblxuICAgIHRoaXMubG9nKGBSZWF0dGFjaGluZyB0byBleGlzdGluZyBBcHBpdW0gc2Vzc2lvbiAke3Nlc3Npb25JZH0gKGRldmljZT0ke2RldmljZUlkfSlgKTtcblxuICAgIGNvbnN0IHsgYXR0YWNoIH0gPSBhd2FpdCBpbXBvcnRXZWJkcml2ZXJpbygpO1xuICAgIGNvbnN0IGJyb3dzZXIgPSBhd2FpdCBhdHRhY2goe1xuICAgICAgY2FwYWJpbGl0aWVzOiB7XG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ0FuZHJvaWQnXG4gICAgICB9LFxuICAgICAgaG9zdG5hbWU6IHVybC5ob3N0bmFtZSxcbiAgICAgIGxvZ0xldmVsOiAnd2FybicsXG4gICAgICBwYXRoOiB1cmwucGF0aG5hbWUsXG4gICAgICBwb3J0LFxuICAgICAgc2Vzc2lvbklkLFxuICAgICAgdHJhbnNmb3JtUmVxdWVzdDogc3RyaXBGb3JiaWRkZW5GZXRjaEhlYWRlcnNcbiAgICB9KTtcblxuICAgIHRoaXMubG9nKCdSZWF0dGFjaGVkIHRvIEFwcGl1bSBzZXNzaW9uLicpO1xuXG4gICAgcmV0dXJuIG5ldyBBcHBpdW1UcmFuc3BvcnQoe1xuICAgICAgYXBwSWQsXG4gICAgICBicm93c2VyLFxuICAgICAgZGV2aWNlSWQsXG4gICAgICBpc1Nlc3Npb25Pd25lcjogZmFsc2UsXG4gICAgICBwbGF0Zm9ybTogJ2FuZHJvaWQnLFxuICAgICAgc2hvdWxkU3dlZXBMZWZ0b3ZlcnM6IHdpbGxTd2VlcExlZnRvdmVycyhvcHRpb25zKSxcbiAgICAgIC4uLihvcHRpb25zLmFwcFN0YXJ0VGltZW91dEluTWlsbGlzZWNvbmRzICE9PSB1bmRlZmluZWQgJiYgeyBhcHBTdGFydFRpbWVvdXRJbk1pbGxpc2Vjb25kczogb3B0aW9ucy5hcHBTdGFydFRpbWVvdXRJbk1pbGxpc2Vjb25kcyB9KSxcbiAgICAgIC4uLihvcHRpb25zLmxheW91dFJlYWR5VGltZW91dEluTWlsbGlzZWNvbmRzICE9PSB1bmRlZmluZWQgJiYgeyBsYXlvdXRSZWFkeVRpbWVvdXRJbk1pbGxpc2Vjb25kczogb3B0aW9ucy5sYXlvdXRSZWFkeVRpbWVvdXRJbk1pbGxpc2Vjb25kcyB9KSxcbiAgICAgIC4uLihvcHRpb25zLnZhdWx0QmFzZVBhdGggIT09IHVuZGVmaW5lZCAmJiB7IHZhdWx0QmFzZVBhdGg6IG9wdGlvbnMudmF1bHRCYXNlUGF0aCB9KSxcbiAgICAgIC4uLihvcHRpb25zLndlYnZpZXdUaW1lb3V0SW5NaWxsaXNlY29uZHMgIT09IHVuZGVmaW5lZCAmJiB7IHdlYnZpZXdUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG9wdGlvbnMud2Vidmlld1RpbWVvdXRJbk1pbGxpc2Vjb25kcyB9KVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFdlZGdlZE1lc3NhZ2UocGFyYW1zOiBFc3RhYmxpc2hTZXNzaW9uUGFyYW1zLCByZWFzb246IFdlZGdlZEFwcGl1bVNlcnZlclJlcG9ydFJlYXNvbik6IHN0cmluZyB7XG4gICAgY29uc3QgbWFya2VyID0gcGFyYW1zLmFwcGl1bVNlcnZlck1hcmtlcjtcbiAgICByZXR1cm4gYnVpbGRXZWRnZWRBcHBpdW1TZXJ2ZXJNZXNzYWdlKHtcbiAgICAgIGFwcGl1bU9yaWdpbjogcGFyYW1zLnVybC5vcmlnaW4sXG4gICAgICBkZXZpY2VJZDogcGFyYW1zLmRldmljZUlkLFxuICAgICAgcmVhc29uLFxuICAgICAgLi4uKG1hcmtlciAhPT0gdW5kZWZpbmVkICYmIHtcbiAgICAgICAgc2VydmVyQWdlSW5NaWxsaXNlY29uZHM6IERhdGUubm93KCkgLSBtYXJrZXIuc3RhcnRlZEF0SW5NaWxsaXNlY29uZHMsXG4gICAgICAgIHNlcnZlclBpZDogbWFya2VyLnBpZFxuICAgICAgfSlcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcmVmbGlnaHQgcHJvYmUgZm9yIGFuIGFscmVhZHktcnVubmluZyBzZXJ2ZXIuXG4gICAqXG4gICAqIExpdmVuZXNzIGlzIG5vdCByZWFkaW5lc3M6IHJlc29sdmluZyBvbiAqYW55KiByZXNwb25zZSBhZG9wdHMgYSBzZXJ2ZXIgdGhhdFxuICAgKiBpcyByZWZ1c2luZyBzZXNzaW9ucyAoYSBub24tMnh4IGAvc3RhdHVzYCwgb3Igb25lIHRoYXQgcmVwb3J0cyBpdHNlbGZcbiAgICogc2h1dHRpbmcgZG93bikgZXhhY3RseSBsaWtlIGEgaGVhbHRoeSBvbmUuIFJlamVjdGluZyBpbnN0ZWFkIGhhbmRzIHRob3NlXG4gICAqIGNhc2VzIHRvIHRoZSBhdXRvLXN0YXJ0IHBhdGguIEl0IGNhbm5vdCBjYXRjaCB0aGUgd2VkZ2VkIHNlcnZlciBvZlxuICAgKiBgd2VkZ2VkLWFwcGl1bS1zZXJ2ZXIudHNgIFx1MjAxNCB0aGF0IG9uZSBhbnN3ZXJzIGByZWFkeTogdHJ1ZWAgXHUyMDE0IHdoaWNoIGlzIHdoeVxuICAgKiB0aGUgd2VkZ2UgaXMgcmVjb2duaXplZCBmcm9tIHRoZSBmYWlsZWQgc2Vzc2lvbiBpbnN0ZWFkLlxuICAgKlxuICAgKiBAcGFyYW0gdXJsIC0gVGhlIEFwcGl1bSBzZXJ2ZXIgVVJMLlxuICAgKi9cbiAgcHJpdmF0ZSBjaGVja0FwcGl1bVJlYWNoYWJsZSh1cmw6IFVSTCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBzdGF0dXNVcmwgPSBuZXcgVVJMKCcvc3RhdHVzJywgdXJsKTtcbiAgICAgIC8qXG4gICAgICAgKiBgYWdlbnQ6IGZhbHNlYCBcdTIwMTQgbmV2ZXIgYSBwb29sZWQgc29ja2V0LiBUaGUgZ2xvYmFsIGFnZW50IGtlZXBzIHNvY2tldHNcbiAgICAgICAqIGFsaXZlIHBlciBob3N0OnBvcnQsIHNvIGEgcHJvYmUgYWZ0ZXIgYSBzZXJ2ZXIgb24gdGhhdCBwb3J0IHdhcyByZXBsYWNlZFxuICAgICAgICogY2FuIHJldXNlIHRoZSBkZWFkIHNvY2tldCBhbmQgZmFpbCB3aXRoIGBFQ09OTlJFU0VUYCByZWdhcmRsZXNzIG9mIHdoYXRcbiAgICAgICAqIGlzIGxpc3RlbmluZyBub3cuIFRoYXQgd291bGQgbWFrZSBgd2FpdEZvckFwcGl1bVN0b3BwZWRgIGNhbGwgYSBsaXZlXG4gICAgICAgKiBzZXJ2ZXIgZGVhZCwgYW5kIGl0IGlzIGV4YWN0bHkgdGhlIHNlcXVlbmNlIHRoZSB3ZWRnZWQtc2VydmVyIHJlc3RhcnRcbiAgICAgICAqIHBlcmZvcm1zLiBBIGZyZXNoIHNvY2tldCBwZXIgcHJvYmUgY29zdHMgbm90aGluZyBhdCB0aGlzIGZyZXF1ZW5jeS5cbiAgICAgICAqL1xuICAgICAgY29uc3QgcmVxdWVzdCA9IGh0dHAuZ2V0KHN0YXR1c1VybCwgeyBhZ2VudDogZmFsc2UsIHRpbWVvdXQ6IEFQUElVTV9QUkVGTElHSFRfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgfSwgKHJlc3BvbnNlKSA9PiB7XG4gICAgICAgIGNvbnN0IHN0YXR1c0NvZGUgPSByZXNwb25zZS5zdGF0dXNDb2RlID8/IDA7XG4gICAgICAgIGlmIChzdGF0dXNDb2RlIDwgSFRUUF9PSyB8fCBzdGF0dXNDb2RlID49IEhUVFBfTVVMVElQTEVfQ0hPSUNFUykge1xuICAgICAgICAgIHJlc3BvbnNlLnJlc3VtZSgpO1xuICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoYEFwcGl1bSBzZXJ2ZXIgYXQgJHt1cmwub3JpZ2lufSBhbnN3ZXJlZCAvc3RhdHVzIHdpdGggSFRUUCAke1N0cmluZyhzdGF0dXNDb2RlKX07IGl0IGlzIG5vdCBhY2NlcHRpbmcgc2Vzc2lvbnMuYCkpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlc3BvbnNlLnNldEVuY29kaW5nKCd1dGYtOCcpO1xuICAgICAgICBsZXQgYm9keSA9ICcnO1xuICAgICAgICByZXNwb25zZS5vbignZGF0YScsIChjaHVuazogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgYm9keSArPSBjaHVuaztcbiAgICAgICAgfSk7XG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XG4gICAgICAgICAgaWYgKGNoZWNrSXNBcHBpdW1TdGF0dXNSZWFkeShib2R5KSkge1xuICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoYEFwcGl1bSBzZXJ2ZXIgYXQgJHt1cmwub3JpZ2lufSByZXBvcnRzIGl0IGlzIG5vdCByZWFkeSB0byBhY2NlcHQgbmV3IGNvbm5lY3Rpb25zLmApKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICAgIHJlcXVlc3Qub24oJ3RpbWVvdXQnLCAoKSA9PiB7XG4gICAgICAgIHJlcXVlc3QuZGVzdHJveSgpO1xuICAgICAgICByZWplY3QoXG4gICAgICAgICAgbmV3IEVycm9yKFxuICAgICAgICAgICAgYEFwcGl1bSBzZXJ2ZXIgYXQgJHt1cmwub3JpZ2lufSBkaWQgbm90IHJlc3BvbmQgd2l0aGluICR7U3RyaW5nKEFQUElVTV9QUkVGTElHSFRfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMpfW1zLiBJcyB0aGUgQXBwaXVtIHNlcnZlciBydW5uaW5nP2BcbiAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICB9KTtcbiAgICAgIHJlcXVlc3Qub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICAgIHJlamVjdChcbiAgICAgICAgICBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgQ2Fubm90IHJlYWNoIEFwcGl1bSBzZXJ2ZXIgYXQgJHt1cmwub3JpZ2lufTogJHtlcnJvci5tZXNzYWdlfS4gSXMgdGhlIEFwcGl1bSBzZXJ2ZXIgcnVubmluZz9gXG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogV2FpdHMgb3V0IHRoZSBBcHBpdW0gcG9ydCBhbmQgcmVwb3J0cyB3aGV0aGVyIGl0IHdlbnQgcXVpZXQsIHJhdGhlciB0aGFuXG4gICAqIHRocm93aW5nIGFzIHtAbGluayB3YWl0Rm9yQXBwaXVtU3RvcHBlZH0gZG9lcy5cbiAgICpcbiAgICogQHBhcmFtIHVybCAtIFRoZSBBcHBpdW0gc2VydmVyIFVSTC5cbiAgICogQHBhcmFtIHRpbWVvdXRJbk1pbGxpc2Vjb25kcyAtIEhvdyBsb25nIHRvIHdhaXQuXG4gICAqIEByZXR1cm5zIGB0cnVlYCB3aGVuIG5vdGhpbmcgYW5zd2VycyBvbiB0aGUgcG9ydCBhbnkgbW9yZS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY2hlY2tJc0FwcGl1bVN0b3BwZWQodXJsOiBVUkwsIHRpbWVvdXRJbk1pbGxpc2Vjb25kczogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMud2FpdEZvckFwcGl1bVN0b3BwZWQodXJsLCB0aW1lb3V0SW5NaWxsaXNlY29uZHMpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyB3aGV0aGVyIGFkYiBzdGlsbCBsaXN0cyB0aGUgZGV2aWNlICoqaW4gYW55IHN0YXRlKiosIHdpdGhvdXQgbGV0dGluZ1xuICAgKiBhbiBhZGIgdGhhdCBpdHNlbGYgZmFpbHMgY291bnQgYXMgZXZpZGVuY2UuXG4gICAqXG4gICAqIEFueSBzdGF0ZSwgbm90IGp1c3QgYGRldmljZWA6IGEgZHlpbmcgZW11bGF0b3IgYW5zd2VycyBgb2ZmbGluZWAgd2hpbGUgaXQgaXNcbiAgICogc3RpbGwgdGhlIHRoaW5nIHRoYXQgaXMgd3JvbmcgKHRoZSBkaXN0aW5jdGlvbiBgYWRiLWRldmljZS1saXN0LnRzYCBkcmF3c1xuICAgKiBmb3IgdGVhcmRvd24sIGFuZCB0aGUgcmVhc29uaW5nIGNhcnJpZXMgb3ZlcikuIFJlYWRpbmcgYG9mZmxpbmVgIGFzIGdvbmVcbiAgICogaGVyZSB3b3VsZCByZXBvcnQgYGRldmljZS1nb25lYCBmb3Igd2hhdCBpcyByZWFsbHkgYSB3ZWRnZSwgc2VuZGluZyB0aGVcbiAgICogcmVhZGVyIHRvIGxvb2sgZm9yIGEgdmFuaXNoZWQgZW11bGF0b3IgdGhhdCBpcyBpbiBmYWN0IHN0aWxsIHNpdHRpbmcgdGhlcmUuXG4gICAqXG4gICAqIEBwYXJhbSBkZXZpY2VJZCAtIFRoZSBkZXZpY2UgdG8gbG9vayBmb3IuXG4gICAqIEByZXR1cm5zIGB0cnVlYCB3aGVuIGl0IGlzIGxpc3RlZDsgYGZhbHNlYCB3aGVuIGl0IGlzIG5vdCwgb3IgYWRiIGNvdWxkIG5vdCBiZSBydW4uXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNoZWNrSXNEZXZpY2VMaXN0ZWRRdWlldGx5KGRldmljZUlkOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGNoZWNrSXNEZXZpY2VMaXN0ZWQoeyBkZXZpY2VJZCwgZGV2aWNlc091dHB1dDogYXdhaXQgdGhpcy5nZXREZXZpY2VzT3V0cHV0KCkgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgIHRoaXMubG9nKGBDb3VsZCBub3QgcmUtY2hlY2sgdGhlIGRldmljZSBsaXN0aW5nOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRGVjaWRlcyB3aGV0aGVyIHRoZSBlbXVsYXRvciB0aGlzIHJ1biBzdGFydGVkIGlzIHJlYWxseSBnb25lLlxuICAgKlxuICAgKiBUd28gaW5kZXBlbmRlbnQgcHJvb2ZzLCBjaGVhcGVzdCBmaXJzdDogbm9uZSBvZiB0aGUgUElEcyB0aGlzIHJ1biBvd25zIGlzXG4gICAqIGFsaXZlLCBhbmQgdGhlIGRldmljZSBubyBsb25nZXIgYXBwZWFycyBpbiBgYWRiIGRldmljZXNgICoqaW4gYW55IHN0YXRlKiogKGFcbiAgICogZHlpbmcgZW11bGF0b3IgYW5zd2VycyBgb2ZmbGluZWAgd2hpbGUgaXQgc3RpbGwgaG9sZHMgdGhlIEFWRCkuXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgZGV2aWNlIGFuZCB0aGUgUElEcyB0aGlzIHJ1biBvd25zLlxuICAgKiBAcmV0dXJucyBgdHJ1ZWAgd2hlbiBub3RoaW5nIG9mIHRoaXMgcnVuJ3MgZW11bGF0b3IgaXMgbGVmdC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY2hlY2tJc0VtdWxhdG9yR29uZShwYXJhbXM6IENoZWNrSXNFbXVsYXRvckdvbmVQYXJhbXMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAocGFyYW1zLm93bmVkRW11bGF0b3JQaWRzLnNvbWUoKHBpZCkgPT4gY2hlY2tJc1Byb2Nlc3NBbGl2ZShwaWQpKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICByZXR1cm4gIWNoZWNrSXNEZXZpY2VMaXN0ZWQoeyBkZXZpY2VJZDogcGFyYW1zLmRldmljZUlkLCBkZXZpY2VzT3V0cHV0OiBhd2FpdCB0aGlzLmdldERldmljZXNPdXRwdXQoKSB9KTtcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgLypcbiAgICAgICAqIEFuIGFkYiB0aGF0IGNhbm5vdCBydW4gaXMgbm90IGV2aWRlbmNlIGFib3V0IHRoZSBlbXVsYXRvciBcdTIwMTQgYW5kIHRoZSBQSURcbiAgICAgICAqIHByb2JlIGFib3ZlIGhhcyBhbHJlYWR5IHNhaWQgdGhpcyBydW4ncyBwcm9jZXNzZXMgYXJlIGdvbmUsIHdoaWNoIGlzIHRoZVxuICAgICAgICogc3Ryb25nZXIgb2YgdGhlIHR3byBwcm9vZnMuXG4gICAgICAgKi9cbiAgICAgIHRoaXMubG9nKGBDb3VsZCBub3QgcmUtY2hlY2sgY29ubmVjdGVkIGRldmljZXMgd2hpbGUgc3RvcHBpbmcgdGhlIGVtdWxhdG9yOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY29ubmVjdFNlc3Npb24ocGFyYW1zOiBFc3RhYmxpc2hTZXNzaW9uUGFyYW1zKTogUHJvbWlzZTxBd2FpdGVkPFJldHVyblR5cGU8dHlwZW9mIHJlbW90ZT4+PiB7XG4gICAgY29uc3QgeyByZW1vdGUgfSA9IGF3YWl0IGltcG9ydFdlYmRyaXZlcmlvKCk7XG4gICAgcmV0dXJuIHJlbW90ZSh7XG4gICAgICBjYXBhYmlsaXRpZXM6IHtcbiAgICAgICAgJ2FwcGl1bTphcHBBY3Rpdml0eSc6IEFQUF9BQ1RJVklUWSxcbiAgICAgICAgJ2FwcGl1bTphcHBQYWNrYWdlJzogcGFyYW1zLmFwcElkLFxuICAgICAgICAnYXBwaXVtOmF1dG9HcmFudFBlcm1pc3Npb25zJzogdHJ1ZSxcbiAgICAgICAgJ2FwcGl1bTphdXRvbWF0aW9uTmFtZSc6ICdVaUF1dG9tYXRvcjInLFxuICAgICAgICAnYXBwaXVtOm5ld0NvbW1hbmRUaW1lb3V0JzogQ09NTUFORF9USU1FT1VUX0lOX01JTExJU0VDT05EUyxcbiAgICAgICAgJ2FwcGl1bTpub1Jlc2V0JzogdHJ1ZSxcbiAgICAgICAgJ2FwcGl1bTp1ZGlkJzogcGFyYW1zLmRldmljZUlkLFxuICAgICAgICAnYXBwaXVtOnVpYXV0b21hdG9yMlNlcnZlckluc3RhbGxUaW1lb3V0JzogU0VSVkVSX0lOU1RBTExfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMsXG4gICAgICAgICdhcHBpdW06dWlhdXRvbWF0b3IyU2VydmVyTGF1bmNoVGltZW91dCc6IFNFUlZFUl9MQVVOQ0hfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMsXG4gICAgICAgICdwbGF0Zm9ybU5hbWUnOiAnQW5kcm9pZCdcbiAgICAgIH0sXG4gICAgICBjb25uZWN0aW9uUmV0cnlDb3VudDogQVBQSVVNX0NPTk5FQ1RJT05fUkVUUllfQ09VTlQsXG4gICAgICBjb25uZWN0aW9uUmV0cnlUaW1lb3V0OiBwYXJhbXMuc2Vzc2lvbkNvbm5lY3Rpb25SZXRyeVRpbWVvdXRJbk1pbGxpc2Vjb25kcyxcbiAgICAgIGhvc3RuYW1lOiBwYXJhbXMudXJsLmhvc3RuYW1lLFxuICAgICAgbG9nTGV2ZWw6ICd3YXJuJyxcbiAgICAgIHBhdGg6IHBhcmFtcy51cmwucGF0aG5hbWUsXG4gICAgICBwb3J0OiBwYXJhbXMucG9ydCxcbiAgICAgIHRyYW5zZm9ybVJlcXVlc3Q6IHN0cmlwRm9yYmlkZGVuRmV0Y2hIZWFkZXJzXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNyZWF0ZU5ld1Nlc3Npb24ob3B0aW9uczogT2JzaWRpYW5BbmRyb2lkQXBwaXVtVHJhbnNwb3J0T3B0aW9ucyk6IFByb21pc2U8T2JzaWRpYW5UcmFuc3BvcnQ+IHtcbiAgICB0aGlzLmxvZyhgQ3JlYXRpbmcgQXBwaXVtVHJhbnNwb3J0ICh1cmw9JHtvcHRpb25zLmFwcGl1bVVybH0sIGF2ZD0ke29wdGlvbnMuYXZkTmFtZX0pYCk7XG5cbiAgICBjb25zdCB1cmwgPSBuZXcgVVJMKG9wdGlvbnMuYXBwaXVtVXJsKTtcblxuICAgIGNvbnN0IHBvcnQgPSBOdW1iZXIodXJsLnBvcnQpO1xuICAgIGlmIChOdW1iZXIuaXNOYU4ocG9ydCkpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoYEludmFsaWQgcG9ydCBpbiBhcHBpdW1Vcmw6ICR7dXJsLnBvcnR9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgYXBwSWQgPSBvcHRpb25zLmFwcElkID8/IEFQUF9QQUNLQUdFO1xuXG4gICAgbGV0IGFjdHVhbERldmljZUlkOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgbGV0IGFwcGl1bVByb2Nlc3M6IENoaWxkUHJvY2VzcyB8IHVuZGVmaW5lZDtcbiAgICBsZXQgZW11bGF0b3JQcm9jZXNzOiBDaGlsZFByb2Nlc3MgfCB1bmRlZmluZWQ7XG4gICAgbGV0IG93bmVkRW11bGF0b3JQaWRzOiByZWFkb25seSBudW1iZXJbXSA9IFtdO1xuXG4gICAgbGV0IHJlc3VsdDogU3RhcnRBcHBpdW1BbmRFbXVsYXRvclJlc3VsdCB8IHVuZGVmaW5lZDtcblxuICAgIHRyeSB7XG4gICAgICAvKlxuICAgICAgICogUHJvdmlzaW9uLCB0aGVuIGNoZWNrIHRoZSBkZXZpY2UgaXMgc3RpbGwgYW5zd2VyaW5nIFx1MjAxNCBhbmQgd2hlbiBpdCBpcyBub3RcbiAgICAgICAqIGFuZCB0aGUgZW11bGF0b3IgaXMgb3VycywgYm9vdCBhIGZyZXNoIG9uZSBpbnN0ZWFkIG9mIGNhcnJ5aW5nIG9uLlxuICAgICAgICpcbiAgICAgICAqIEEgd2VkZ2UgaXMgTk9UIGRldGVybWluaXN0aWMsIHdoaWNoIGlzIHdoYXQganVzdGlmaWVzIHRoZSByZXRyeS4gSW4gdGhlXG4gICAgICAgKiBydW4gdGhhdCBwcm92ZWQgaXQgKDIwMjYtMDktMDUpIHRoZSBmaXJzdCBlbXVsYXRvciB3ZW50IHF1aWV0IDEyOXMgaW4gYW5kXG4gICAgICAgKiB0aGUgc2Vjb25kLCBib290ZWQgMTFzIGxhdGVyIGZyb20gdGhlIHNhbWUgQVZEIHdpdGggdGhlIHNhbWUgYXJndW1lbnRzLFxuICAgICAgICogZXN0YWJsaXNoZWQgYSBzZXNzaW9uIGFuZCBkcm92ZSB0aGUgV2ViVmlldyB0byBjb21wbGV0aW9uLiBBbiBlYXJsaWVyXG4gICAgICAgKiBkcmFmdCBvZiB0aGlzIHdvcmsgYXJndWVkIHRoZSBvcHBvc2l0ZSBmcm9tIHRoZSBoYW5kLWJvb3QgZGF0YSBcdTIwMTQgdGhhdCBhXG4gICAgICAgKiByZS1ib290IGJ1eXMgdGhlIHNhbWUgZmFpbHVyZSA5MHMgbGF0ZXIgXHUyMDE0IGFuZCB0aGF0IHdhcyBzaW1wbHkgd3Jvbmc6XG4gICAgICAgKiBldmVyeSBoYW5kLWJvb3Qgd2FzIGEgZmlyc3QgYm9vdCwgc28gdGhlIGRhdGEgc2FpZCBub3RoaW5nIGFib3V0IHNlY29uZFxuICAgICAgICogb25lcy5cbiAgICAgICAqL1xuICAgICAgZm9yIChsZXQgYXR0ZW1wdCA9IDE7IGF0dGVtcHQgPD0gRU1VTEFUT1JfQk9PVF9BVFRFTVBUX0NPVU5UOyBhdHRlbXB0KyspIHtcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgdGhpcy5zdGFydEFwcGl1bUFuZEVtdWxhdG9yKHtcbiAgICAgICAgICBhcHBpdW1TdGFydFRpbWVvdXRJbk1pbGxpc2Vjb25kczogcmVzb2x2ZUFwcGl1bVN0YXJ0VGltZW91dEluTWlsbGlzZWNvbmRzKG9wdGlvbnMpLFxuICAgICAgICAgIGFwcGl1bVVybDogdXJsLFxuICAgICAgICAgIGF2ZE5hbWU6IG9wdGlvbnMuYXZkTmFtZSxcbiAgICAgICAgICBkZXZpY2VJZGxlVGltZW91dEluTWlsbGlzZWNvbmRzOiByZXNvbHZlRGV2aWNlSWRsZVRpbWVvdXRJbk1pbGxpc2Vjb25kcyhvcHRpb25zKSxcbiAgICAgICAgICBpc0FwcGl1bUNvbnNvbGVWaXNpYmxlOiBvcHRpb25zLmlzQXBwaXVtQ29uc29sZVZpc2libGUsXG4gICAgICAgICAgaXNFbXVsYXRvclZpc2libGU6IG9wdGlvbnMuaXNFbXVsYXRvclZpc2libGUsXG4gICAgICAgICAgbmV0d29ya1JlYWR5VGltZW91dEluTWlsbGlzZWNvbmRzOiByZXNvbHZlTmV0d29ya1JlYWR5VGltZW91dEluTWlsbGlzZWNvbmRzKG9wdGlvbnMpLFxuICAgICAgICAgIHBvcnQsXG4gICAgICAgICAgc2hvdWxkQXV0b0luc3RhbGxBcHBpdW1EZXBlbmRlbmNpZXM6IHdpbGxBdXRvSW5zdGFsbEFwcGl1bURlcGVuZGVuY2llcyhvcHRpb25zKSxcbiAgICAgICAgICBzaG91bGRBdXRvU3RhcnRBcHBpdW06IG9wdGlvbnMuc2hvdWxkQXV0b1N0YXJ0QXBwaXVtLFxuICAgICAgICAgIHNob3VsZFJldXNlRW11bGF0b3JTbmFwc2hvdDogb3B0aW9ucy5zaG91bGRSZXVzZUVtdWxhdG9yU25hcHNob3RcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLypcbiAgICAgICAgICogT25seSBldmVyIFJFUExBQ0UgdGhpcyBoYW5kbGUsIG5ldmVyIGNsZWFyIGl0LiBUaGUgcmV0cnkgbGVhdmVzIHRoaXNcbiAgICAgICAgICogcnVuJ3MgQXBwaXVtIHNlcnZlciBydW5uaW5nIGFuZCBzd2FwcyBvbmx5IHRoZSBlbXVsYXRvciwgc28gdGhlIHNlY29uZFxuICAgICAgICAgKiBwYXNzIGZpbmRzIHRoYXQgc2VydmVyIHJlYWNoYWJsZSwgQURPUFRTIGl0LCBhbmQgcmV0dXJucyBubyBwcm9jZXNzXG4gICAgICAgICAqIGhhbmRsZS4gV3JpdGluZyB0aGF0IGB1bmRlZmluZWRgIG92ZXIgdGhlIGhhbmRsZSBmcm9tIHRoZSBmaXJzdCBwYXNzXG4gICAgICAgICAqIHdvdWxkIG9ycGhhbiB0aGUgdmVyeSBzZXJ2ZXIgdGhpcyBydW4gc3RhcnRlZCBcdTIwMTQgdGhlIGxlYWsgTDQ2IGV4aXN0cyB0b1xuICAgICAgICAgKiBwcmV2ZW50LCByZWludHJvZHVjZWQgYnkgdGhlIHJldHJ5LlxuICAgICAgICAgKi9cbiAgICAgICAgaWYgKHJlc3VsdC5hcHBpdW1Qcm9jZXNzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBhcHBpdW1Qcm9jZXNzID0gcmVzdWx0LmFwcGl1bVByb2Nlc3M7XG4gICAgICAgIH1cbiAgICAgICAgZW11bGF0b3JQcm9jZXNzID0gcmVzdWx0LmVtdWxhdG9yUHJvY2VzcztcbiAgICAgICAgb3duZWRFbXVsYXRvclBpZHMgPSByZXN1bHQub3duZWRFbXVsYXRvclBpZHM7XG4gICAgICAgIGFjdHVhbERldmljZUlkID0gcmVzdWx0LmFjdHVhbERldmljZUlkO1xuXG4gICAgICAgIC8qXG4gICAgICAgICAqIEJlZm9yZSBgcmVtb3RlKClgIGxhdW5jaGVzIE9ic2lkaWFuIFx1MjAxNCB0aGUgbGFzdCBwb2ludCBhdCB3aGljaCBub3RoaW5nXG4gICAgICAgICAqIGhhcyB0byBlbnVtZXJhdGUgdGhlIGRldmljZSdzIHZhdWx0cyB5ZXQuXG4gICAgICAgICAqL1xuICAgICAgICBpZiAod2lsbFN3ZWVwTGVmdG92ZXJzKG9wdGlvbnMpKSB7XG4gICAgICAgICAgYXdhaXQgdGhpcy5zd2VlcERldmljZUxlZnRvdmVyVmF1bHRzKHtcbiAgICAgICAgICAgIGRldmljZUlkOiBhY3R1YWxEZXZpY2VJZCxcbiAgICAgICAgICAgIHZhdWx0QmFzZVBhdGg6IG9wdGlvbnMudmF1bHRCYXNlUGF0aCA/PyBERUZBVUxUX0FORFJPSURfVkFVTFRfQkFTRV9QQVRIXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICAvKlxuICAgICAgICAgKiBUaGUgbGFzdCBwb2ludCBhdCB3aGljaCBhIGRldmljZSB0aGF0IGhhcyBnb25lIHF1aWV0IGNhbiBzdGlsbCBiZVxuICAgICAgICAgKiByZXBvcnRlZCBhcyBpdHNlbGYuIFBhc3QgaGVyZSB0aGUgZmFpbHVyZSBiZWxvbmdzIHRvIEFwcGl1bSwgd2hpY2ggY2FuXG4gICAgICAgICAqIG9ubHkgc2F5IHRoZSBkZXZpY2UgaXMgXCJub3QgaW4gdGhlIGxpc3Qgb2YgY29ubmVjdGVkIGRldmljZXNcIiBcdTIwMTQgYW5cbiAgICAgICAgICogZXJyb3IgdGhhdCBuYW1lcyB0aGUgb25lIHRoaW5nIHRoYXQgaXMgbm90IHdyb25nLlxuICAgICAgICAgKi9cbiAgICAgICAgY29uc3QgZGlhZ25vc2lzID0gYXdhaXQgdGhpcy5kaWFnbm9zZURldmljZShhY3R1YWxEZXZpY2VJZCwgcmVzdWx0LmVtdWxhdG9yQ2FwdHVyZSk7XG4gICAgICAgIGlmIChkaWFnbm9zaXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgLypcbiAgICAgICAgICogT25seSBhbiBlbXVsYXRvciB0aGlzIHJ1biBzdGFydGVkIG1heSBiZSByZXBsYWNlZC4gQSBkZXZpY2UgdGhhdCB3YXNcbiAgICAgICAgICogYWRvcHRlZCAoYG93bmVkRW11bGF0b3JQaWRzYCBlbXB0eSkgaXMgc29tZWJvZHkgZWxzZSdzIHRvIHJlc3RhcnQgXHUyMDE0XG4gICAgICAgICAqIHRoZSBzYW1lIG93bmVyc2hpcCBsaW5lIHRlYXJkb3duIGRyYXdzIGluIG5ldmVyIHN3ZWVwaW5nIGBxZW11KmAuXG4gICAgICAgICAqL1xuICAgICAgICBjb25zdCBvd25lZEVtdWxhdG9yUHJvY2VzcyA9IGVtdWxhdG9yUHJvY2VzcztcbiAgICAgICAgY29uc3QgY2FuUmV0cnkgPSBhdHRlbXB0IDwgRU1VTEFUT1JfQk9PVF9BVFRFTVBUX0NPVU5UICYmIG93bmVkRW11bGF0b3JQcm9jZXNzICE9PSB1bmRlZmluZWQgJiYgb3duZWRFbXVsYXRvclBpZHMubGVuZ3RoID4gMDtcbiAgICAgICAgaWYgKCFjYW5SZXRyeSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihkaWFnbm9zaXMpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5sb2coYCR7ZGlhZ25vc2lzfVxcblxcbkJvb3RpbmcgYSBmcmVzaCBlbXVsYXRvciBhbmQgdHJ5aW5nIG9uY2UgbW9yZSAoYXR0ZW1wdCAke1N0cmluZyhhdHRlbXB0ICsgMSl9IG9mICR7U3RyaW5nKEVNVUxBVE9SX0JPT1RfQVRURU1QVF9DT1VOVCl9KS5gKTtcbiAgICAgICAgLypcbiAgICAgICAgICogRGlzb3duIEJFRk9SRSBzdG9wcGluZywgbm90IGFmdGVyOiB0aGlzIHJ1biBoYW5kcyB0aGUgZW11bGF0b3Igb3ZlciB0b1xuICAgICAgICAgKiBgc3RvcEF1dG9TdGFydGVkRW11bGF0b3JgIGFuZCBtdXN0IG5vdCBzdGlsbCBiZSBob2xkaW5nIGl0IGlmIHRoYXRcbiAgICAgICAgICogdGhyb3dzLCBvciB0aGUgb3V0ZXIgY2F0Y2gncyB0ZWFyZG93biB3b3VsZCBnbyBhZnRlciB0aGUgc2FtZVxuICAgICAgICAgKiBwcm9jZXNzZXMgYSBzZWNvbmQgdGltZS5cbiAgICAgICAgICovXG4gICAgICAgIGNvbnN0IGRvb21lZERldmljZUlkID0gYWN0dWFsRGV2aWNlSWQ7XG4gICAgICAgIGNvbnN0IGRvb21lZFBpZHMgPSBvd25lZEVtdWxhdG9yUGlkcztcbiAgICAgICAgZW11bGF0b3JQcm9jZXNzID0gdW5kZWZpbmVkO1xuICAgICAgICBvd25lZEVtdWxhdG9yUGlkcyA9IFtdO1xuICAgICAgICBhY3R1YWxEZXZpY2VJZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgYXdhaXQgdGhpcy5zdG9wQXV0b1N0YXJ0ZWRFbXVsYXRvcih7XG4gICAgICAgICAgYXZkTmFtZTogb3B0aW9ucy5hdmROYW1lLFxuICAgICAgICAgIGRldmljZUlkOiBkb29tZWREZXZpY2VJZCxcbiAgICAgICAgICBlbXVsYXRvclByb2Nlc3M6IG93bmVkRW11bGF0b3JQcm9jZXNzLFxuICAgICAgICAgIG93bmVkRW11bGF0b3JQaWRzOiBkb29tZWRQaWRzXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBpZiAocmVzdWx0ID09PSB1bmRlZmluZWQgfHwgYWN0dWFsRGV2aWNlSWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBwcm92aXNpb24gYW4gQW5kcm9pZCBkZXZpY2UgZm9yIEFWRCBcIiR7b3B0aW9ucy5hdmROYW1lfVwiLmApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzZXNzaW9uUmVzdWx0ID0gYXdhaXQgdGhpcy5lc3RhYmxpc2hTZXNzaW9uT3JEaWFnbm9zZURldmljZShyZXN1bHQuZW11bGF0b3JDYXB0dXJlLCB7XG4gICAgICAgIGFwcElkLFxuICAgICAgICBhcHBpdW1TZXJ2ZXJNYXJrZXI6IHJlc3VsdC5hcHBpdW1TZXJ2ZXJNYXJrZXIsXG4gICAgICAgIGFwcGl1bVN0YXJ0VGltZW91dEluTWlsbGlzZWNvbmRzOiByZXNvbHZlQXBwaXVtU3RhcnRUaW1lb3V0SW5NaWxsaXNlY29uZHMob3B0aW9ucyksXG4gICAgICAgIGRldmljZUlkOiBhY3R1YWxEZXZpY2VJZCxcbiAgICAgICAgaXNBZG9wdGVkU2VydmVyOiByZXN1bHQuaXNBZG9wdGVkQXBwaXVtU2VydmVyLFxuICAgICAgICBpc0FwcGl1bUNvbnNvbGVWaXNpYmxlOiBvcHRpb25zLmlzQXBwaXVtQ29uc29sZVZpc2libGUsXG4gICAgICAgIHBvcnQsXG4gICAgICAgIHNlc3Npb25Db25uZWN0aW9uUmV0cnlUaW1lb3V0SW5NaWxsaXNlY29uZHM6IHJlc29sdmVTZXNzaW9uQ29ubmVjdGlvblJldHJ5VGltZW91dEluTWlsbGlzZWNvbmRzKG9wdGlvbnMpLFxuICAgICAgICBzaG91bGRBdXRvU3RhcnRBcHBpdW06IG9wdGlvbnMuc2hvdWxkQXV0b1N0YXJ0QXBwaXVtLFxuICAgICAgICB1cmxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBicm93c2VyID0gc2Vzc2lvblJlc3VsdC5icm93c2VyO1xuICAgICAgLy8gQSB3ZWRnZWQgYWRvcHRlZCBzZXJ2ZXIgaXMgcmVwbGFjZWQgYnkgb25lIHRoaXMgcnVuIG93bnMsIHNvIGl0IG11c3QgYmUgdG9ybiBkb3duIGxpa2UgYW55IG90aGVyIGF1dG8tc3RhcnRlZCBzZXJ2ZXIuXG4gICAgICBpZiAoc2Vzc2lvblJlc3VsdC5hcHBpdW1Qcm9jZXNzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgYXBwaXVtUHJvY2VzcyA9IHNlc3Npb25SZXN1bHQuYXBwaXVtUHJvY2VzcztcbiAgICAgIH1cblxuICAgICAgdGhpcy5sb2coJ0FwcGl1bSBzZXNzaW9uIGVzdGFibGlzaGVkLicpO1xuICAgICAgLypcbiAgICAgICAqIFRoZSBlbXVsYXRvciBoYXMgbm90aGluZyBsZWZ0IHRvIGV4cGxhaW4sIHNvIGZyZWV6ZSBpdHMgdGFpbCBoZXJlIHJhdGhlclxuICAgICAgICogdGhhbiBhdCBib290LiBFdmVyeXRoaW5nIHVwIHRvIHRoaXMgbGluZSBcdTIwMTQgaW5jbHVkaW5nIHRoZSB3aW5kb3cgaW4gd2hpY2hcbiAgICAgICAqIGEgd2VkZ2Ugc3VyZmFjZXMgXHUyMDE0IGlzIG5vdyBpbnNpZGUgdGhlIGNhcHR1cmVkIG91dHB1dC5cbiAgICAgICAqL1xuICAgICAgcmVzdWx0LmVtdWxhdG9yQ2FwdHVyZT8uc3RvcCgpO1xuICAgICAgY29uc3QgYXBwaXVtVHJhbnNwb3J0ID0gbmV3IEFwcGl1bVRyYW5zcG9ydCh7XG4gICAgICAgIGFwcElkLFxuICAgICAgICBicm93c2VyLFxuICAgICAgICBkZXZpY2VJZDogYWN0dWFsRGV2aWNlSWQsXG4gICAgICAgIHBsYXRmb3JtOiAnYW5kcm9pZCcsXG4gICAgICAgIHNob3VsZFN3ZWVwTGVmdG92ZXJzOiB3aWxsU3dlZXBMZWZ0b3ZlcnMob3B0aW9ucyksXG4gICAgICAgIC4uLihvcHRpb25zLmFwcFN0YXJ0VGltZW91dEluTWlsbGlzZWNvbmRzICE9PSB1bmRlZmluZWQgJiYgeyBhcHBTdGFydFRpbWVvdXRJbk1pbGxpc2Vjb25kczogb3B0aW9ucy5hcHBTdGFydFRpbWVvdXRJbk1pbGxpc2Vjb25kcyB9KSxcbiAgICAgICAgLi4uKG9wdGlvbnMubGF5b3V0UmVhZHlUaW1lb3V0SW5NaWxsaXNlY29uZHMgIT09IHVuZGVmaW5lZCAmJiB7IGxheW91dFJlYWR5VGltZW91dEluTWlsbGlzZWNvbmRzOiBvcHRpb25zLmxheW91dFJlYWR5VGltZW91dEluTWlsbGlzZWNvbmRzIH0pLFxuICAgICAgICAuLi4ob3B0aW9ucy52YXVsdEJhc2VQYXRoICE9PSB1bmRlZmluZWQgJiYgeyB2YXVsdEJhc2VQYXRoOiBvcHRpb25zLnZhdWx0QmFzZVBhdGggfSksXG4gICAgICAgIC4uLihvcHRpb25zLndlYnZpZXdUaW1lb3V0SW5NaWxsaXNlY29uZHMgIT09IHVuZGVmaW5lZCAmJiB7IHdlYnZpZXdUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG9wdGlvbnMud2Vidmlld1RpbWVvdXRJbk1pbGxpc2Vjb25kcyB9KVxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IG9yaWdpbmFsRGlzcG9zZSA9IGFwcGl1bVRyYW5zcG9ydC5kaXNwb3NlLmJpbmQoYXBwaXVtVHJhbnNwb3J0KTtcbiAgICAgIGNvbnN0IHRyYW5zcG9ydDogT2JzaWRpYW5UcmFuc3BvcnQgPSBhcHBpdW1UcmFuc3BvcnQ7XG4gICAgICB0cmFuc3BvcnQuZGlzcG9zZSA9IGFzeW5jICgpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCBvcmlnaW5hbERpc3Bvc2UoKTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICBhd2FpdCB0aGlzLnN0b3BBdXRvU3RhcnRlZFByb2Nlc3Nlc1ZlcmlmaWVkKGJ1aWxkU3RvcFBhcmFtcygpKTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgLy8gQ2hhaW4gcmF0aGVyIHRoYW4gcmVwbGFjZTogdGhlIHRyYW5zcG9ydCdzIG93biBzeW5jIHRlYXJkb3duIGRyb3BzIHRoZSB0cnVzdGVkLWlucHV0IGNoYW5uZWwnc1xuICAgICAgLy8gQWRiIHBvcnQgZm9yd2FyZCwgd2hpY2ggd291bGQgb3RoZXJ3aXNlIGJlIHN0cmFuZGVkIG9uIHRoZSBkZXZpY2UgYnkgYW4gYWJydXB0IGV4aXQuXG4gICAgICBjb25zdCBvcmlnaW5hbERpc3Bvc2VTeW5jID0gYXBwaXVtVHJhbnNwb3J0LmRpc3Bvc2VTeW5jLmJpbmQoYXBwaXVtVHJhbnNwb3J0KTtcbiAgICAgIHRyYW5zcG9ydC5kaXNwb3NlU3luYyA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBvcmlnaW5hbERpc3Bvc2VTeW5jKCk7XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgdGhpcy5zdG9wQXV0b1N0YXJ0ZWRQcm9jZXNzZXNCZXN0RWZmb3J0KGJ1aWxkU3RvcFBhcmFtcygpKTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgcmV0dXJuIHRyYW5zcG9ydDtcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgYXdhaXQgdGhpcy5zdG9wQXV0b1N0YXJ0ZWRQcm9jZXNzZXNWZXJpZmllZChidWlsZFN0b3BQYXJhbXMoKSk7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBidWlsZFN0b3BQYXJhbXMoKTogU3RvcEF1dG9TdGFydGVkUHJvY2Vzc2VzUGFyYW1zIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFwcGl1bVByb2Nlc3MsXG4gICAgICAgIGF2ZE5hbWU6IG9wdGlvbnMuYXZkTmFtZSxcbiAgICAgICAgZGV2aWNlSWQ6IGFjdHVhbERldmljZUlkLFxuICAgICAgICBlbXVsYXRvclByb2Nlc3MsXG4gICAgICAgIG93bmVkRW11bGF0b3JQaWRzLFxuICAgICAgICBwb3J0LFxuICAgICAgICB1cmxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIERlc2NyaWJlcyBhbiBhZG9wdGVkIHNlcnZlcidzIHByb3ZlbmFuY2UgZm9yIHRoZSBwcmVmbGlnaHQgbG9nLCBzbyBhIHN0YWxlXG4gICAqIGxlZnRvdmVyIGlzIHZpc2libGUgaW4gdGhlIHRyYW5zY3JpcHQgb2YgYSBydW4gdGhhdCBnb2VzIG9uIHRvIHN1Y2NlZWQgXHUyMDE0IG5vdFxuICAgKiBvbmx5IGluIHRoZSBlcnJvciBvZiBvbmUgdGhhdCBmYWlscy5cbiAgICpcbiAgICogQHBhcmFtIG1hcmtlciAtIFRoZSBtYXJrZXIgcmVhZCBmb3IgdGhlIHBvcnQsIGlmIGFueS5cbiAgICogQHJldHVybnMgQSBzaG9ydCBwcm92ZW5hbmNlIGRlc2NyaXB0aW9uLlxuICAgKi9cbiAgcHJpdmF0ZSBkZXNjcmliZUFkb3B0ZWRTZXJ2ZXIobWFya2VyOiBBcHBpdW1TZXJ2ZXJNYXJrZXIgfCB1bmRlZmluZWQpOiBzdHJpbmcge1xuICAgIGlmICghbWFya2VyIHx8ICFjaGVja0lzSGFybmVzc093bmVkQXBwaXVtU2VydmVyKG1hcmtlcikpIHtcbiAgICAgIHJldHVybiAnbm90IHN0YXJ0ZWQgYnkgdGhpcyBoYXJuZXNzJztcbiAgICB9XG5cbiAgICBjb25zdCBhZ2VJblNlY29uZHMgPSBNYXRoLnJvdW5kKChEYXRlLm5vdygpIC0gbWFya2VyLnN0YXJ0ZWRBdEluTWlsbGlzZWNvbmRzKSAvIE1JTExJU0VDT05EU19QRVJfU0VDT05EKTtcbiAgICBjb25zdCB1bnN0b3BwZWRTdWZmaXggPSBtYXJrZXIuc3RvcEF0dGVtcHRlZEF0SW5NaWxsaXNlY29uZHMgPT09IHVuZGVmaW5lZCA/ICcnIDogJywgYW5kIGFuIGVhcmxpZXIgcnVuIGZhaWxlZCB0byBzdG9wIGl0JztcbiAgICByZXR1cm4gYHN0YXJ0ZWQgYnkgYW4gZWFybGllciBydW4gb2YgdGhpcyBoYXJuZXNzLCBwaWQgJHtTdHJpbmcobWFya2VyLnBpZCl9LCB1cCBmb3IgJHtTdHJpbmcoYWdlSW5TZWNvbmRzKX1zJHt1bnN0b3BwZWRTdWZmaXh9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcm9iZXMgdGhlIGRldmljZSBhbmQgcmV0dXJucyB0aGUgZmFpbHVyZSBtZXNzYWdlIHdoZW4gaXQgaXMgbm8gbG9uZ2VyXG4gICAqIHVzYWJsZSwgb3IgYHVuZGVmaW5lZGAgd2hlbiBpdCBpcyBmaW5lLlxuICAgKlxuICAgKiBUaGUgcmVhZGluZXNzIGdhdGVzIHRoYXQgcnVuIGJlZm9yZSB0aGlzIG9uZSBhcmUgZGVsaWJlcmF0ZWx5IGJlc3QtZWZmb3J0IFx1MjAxNFxuICAgKiB0aGV5IHdhcm4gYW5kIHByb2NlZWQgXHUyMDE0IHNvIG5vdGhpbmcgYXNrZWQgd2hldGhlciB0aGUgZGV2aWNlIHdhcyBzdGlsbCB0aGVyZVxuICAgKiBhdCB0aGUgbW9tZW50IGl0IG1hdHRlcmVkLiBBIGd1ZXN0IHRoYXQgd2VudCBxdWlldCBpbiB0aGUgbWVhbnRpbWUgd2FzXG4gICAqIGhhbmRlZCB0byBBcHBpdW0sIHdoaWNoIHJlcG9ydGVkIGBEZXZpY2UgPGlkPiB3YXMgbm90IGluIHRoZSBsaXN0IG9mXG4gICAqIGNvbm5lY3RlZCBkZXZpY2VzYDsgYGFkYiBkZXZpY2VzYCB0aGVuIGxpc3RlZCBpdCwgYW5kIHRoZSB0cmFpbCB3ZW50IGNvbGQuXG4gICAqXG4gICAqIFRoZSBzZWNvbmQgcHJvYmUgaXMgb25seSBwYWlkIGZvciB3aGVuIHRoZSBmaXJzdCBvbmUgZmFpbHMsIGFuZCB0aGUgdmVyZGljdFxuICAgKiBkaXN0aW5ndWlzaGVzIGEgZnJvemVuIGd1ZXN0IGZyb20gYW4gdW5yZWFjaGFibGUgZW11bGF0b3IgXHUyMDE0IHNlZVxuICAgKiBgZW11bGF0b3ItbGl2ZW5lc3MudHNgIGZvciB0aGUgbWVhc3VyZW1lbnRzIGJlaGluZCB0aGF0IHNwbGl0LlxuICAgKlxuICAgKiBSZXR1cm5pbmcgdGhlIG1lc3NhZ2UgcmF0aGVyIHRoYW4gdGhyb3dpbmcgaXQgaXMgd2hhdCBsZXRzIGJvdGggY2FsbGVycyB1c2VcbiAgICogdGhlIHNhbWUgZGlhZ25vc2lzOiB0aGUgcHJvdmlzaW9uaW5nIGxvb3AgZGVjaWRlcyB3aGV0aGVyIHRvIGJvb3QgYSBmcmVzaFxuICAgKiBlbXVsYXRvciwgYW5kIHRoZSBzZXNzaW9uIHBhdGggbmVlZHMgaXRzIG93biBlcnJvciB0byBzdXJ2aXZlIGFzIHRoZVxuICAgKiBgY2F1c2VgLlxuICAgKlxuICAgKiBAcGFyYW0gZGV2aWNlSWQgLSBUaGUgZGV2aWNlIHRvIHByb2JlLlxuICAgKiBAcGFyYW0gZW11bGF0b3JDYXB0dXJlIC0gVGhlIGVtdWxhdG9yJ3Mgb3V0cHV0LCB3aGVuIHRoaXMgcnVuIHN0YXJ0ZWQgaXQuXG4gICAqIEByZXR1cm5zIFRoZSBkaWFnbm9zaXMsIG9yIGB1bmRlZmluZWRgIHdoZW4gdGhlIGRldmljZSBzdGlsbCBhbnN3ZXJzLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBkaWFnbm9zZURldmljZShkZXZpY2VJZDogc3RyaW5nLCBlbXVsYXRvckNhcHR1cmU/OiBFbXVsYXRvckNhcHR1cmUpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICAgIGNvbnN0IHNoZWxsUHJvYmUgPSBhd2FpdCB0aGlzLnByb2JlRGV2aWNlU2hlbGwoZGV2aWNlSWQpO1xuICAgIGlmIChzaGVsbFByb2JlID09PSAnYW5zd2VyZWQnKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHRoaXMubG9nKGBEZXZpY2UgJHtkZXZpY2VJZH0gZGlkIG5vdCBhbnN3ZXIgXFxgYWRiIC1zICR7ZGV2aWNlSWR9IHNoZWxsXFxgOyBjaGVja2luZyB3aGV0aGVyIHRoZSBlbXVsYXRvciBpdHNlbGYgaXMgc3RpbGwgYWxpdmUuLi5gKTtcbiAgICBjb25zdCBbY29uc29sZVByb2JlLCBpc0xpc3RlZEJ5QWRiXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgIHRoaXMucHJvYmVFbXVsYXRvckNvbnNvbGUoZGV2aWNlSWQpLFxuICAgICAgdGhpcy5jaGVja0lzRGV2aWNlTGlzdGVkUXVpZXRseShkZXZpY2VJZClcbiAgICBdKTtcblxuICAgIGNvbnN0IHZlcmRpY3QgPSByZXNvbHZlRW11bGF0b3JMaXZlbmVzc1ZlcmRpY3Qoe1xuICAgICAgY29uc29sZVByb2JlLFxuICAgICAgZGV2aWNlSWQsXG4gICAgICBpc0xpc3RlZEJ5QWRiLFxuICAgICAgc2hlbGxQcm9iZVxuICAgIH0pO1xuICAgIHRoaXMubG9nKGBEZXZpY2UgbGl2ZW5lc3M6ICR7ZGV2aWNlSWR9IHNoZWxsPSR7c2hlbGxQcm9iZX0sIGNvbnNvbGU9JHtjb25zb2xlUHJvYmV9IC0+ICR7dmVyZGljdH0uYCk7XG5cbiAgICAvLyBVbnJlYWNoYWJsZSBpbiBwcmFjdGljZSBcdTIwMTQgdGhlIHZlcmRpY3QgaXMgb25seSBgJ2FsaXZlJ2Agd2hlbiB0aGUgc2hlbGwgYW5zd2VyZWQsIHdoaWNoIHJldHVybmVkIGFib3ZlIFx1MjAxNCBidXQgaXQgaXMgd2hhdCBuYXJyb3dzIHRoZSB0eXBlIGZvciB0aGUgYnVpbGRlci5cbiAgICBpZiAodmVyZGljdCA9PT0gJ2FsaXZlJykge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICByZXR1cm4gYnVpbGRFbXVsYXRvckxpdmVuZXNzTWVzc2FnZSh7XG4gICAgICBkZXZpY2VJZCxcbiAgICAgIGVtdWxhdG9yT3V0cHV0OiBlbXVsYXRvckNhcHR1cmU/LnJlYWQoKSA/PyAnJyxcbiAgICAgIHByb2JlVGltZW91dEluTWlsbGlzZWNvbmRzOiBERVZJQ0VfTElWRU5FU1NfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMsXG4gICAgICB2ZXJkaWN0XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGR1bXBDb25uZWN0aXZpdHkoZGV2aWNlSWQ6IHN0cmluZyk6IFByb21pc2U8Q29ubmVjdGl2aXR5UHJvYmVSZXN1bHQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgIGV4ZWNGaWxlKFxuICAgICAgICAnYWRiJyxcbiAgICAgICAgWyctcycsIGRldmljZUlkLCAnc2hlbGwnLCAnZHVtcHN5cycsICdjb25uZWN0aXZpdHknXSxcbiAgICAgICAgeyBtYXhCdWZmZXI6IEFEQl9EVU1QU1lTX01BWF9CVUZGRVJfSU5fQllURVMsIHRpbWVvdXQ6IEFEQl9EVU1QU1lTX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTIH0sXG4gICAgICAgIChlcnJvciwgc3Rkb3V0LCBzdGRlcnIpID0+IHtcbiAgICAgICAgICAvKlxuICAgICAgICAgICAqIEEgZmFpbHVyZSBjYXJyaWVzIGl0cyByZWFzb24sIE5PVCBhbiBlbXB0eSBzdHJpbmcuIFRoZSBvdGhlciBwcm9iZXNcbiAgICAgICAgICAgKiBjb2xsYXBzZSBhIGZhaWx1cmUgaW50byBlbXB0eSBvdXRwdXQgYmVjYXVzZSB0aGVyZSBcImVtcHR5XCIgYW5kXG4gICAgICAgICAgICogXCJmYWlsZWRcIiBib3RoIG1lYW4gbm90LWlkbGUsIGJ1dCBoZXJlIHRoZXkgbWVhbiBkaWZmZXJlbnQgdGhpbmdzIGFuZFxuICAgICAgICAgICAqIG9ubHkgb25lIG9mIHRoZW0gaXMgYWJvdXQgdGhlIG5ldHdvcms6IGEgcHJvYmUgdGhhdCBuZXZlciBhbnN3ZXJzXG4gICAgICAgICAgICogbXVzdCBub3QgYmUgcmVwb3J0ZWQgYXMgYSBndWVzdCB3aXRob3V0IGEgcm91dGUuXG4gICAgICAgICAgICovXG4gICAgICAgICAgaWYgKCFlcnJvcikge1xuICAgICAgICAgICAgcmVzb2x2ZSh7IG91dHB1dDogc3Rkb3V0IH0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnN0IGRldGFpbCA9IChzdGRlcnIudHJpbSgpIHx8IGVycm9yLm1lc3NhZ2UudHJpbSgpKS5zcGxpdCgnXFxuJywgMSlbMF0gPz8gJyc7XG4gICAgICAgICAgcmVzb2x2ZSh7XG4gICAgICAgICAgICBmYWlsdXJlUmVhc29uOiBlcnJvci5raWxsZWRcbiAgICAgICAgICAgICAgPyBgbm8gYW5zd2VyIHdpdGhpbiAke1N0cmluZyhBREJfRFVNUFNZU19USU1FT1VUX0lOX01JTExJU0VDT05EUyl9bXNgXG4gICAgICAgICAgICAgIDogZGV0YWlsIHx8ICdhZGIgZmFpbGVkIHdpdGggbm8gbWVzc2FnZSdcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbnN1cmVzIHRoZSBBcHBpdW0gdG9vbGNoYWluIGlzIHByZXNlbnQgYmVmb3JlIHRoZSBzZXJ2ZXIgaXMgYXV0by1zdGFydGVkOlxuICAgKiBBcHBpdW0gaXRzZWxmLCB0aGVuIHRoZSBgdWlhdXRvbWF0b3IyYCBkcml2ZXIuIEVhY2ggaXMgY2hlY2tlZCBmaXJzdCBhbmRcbiAgICogaW5zdGFsbGVkIG9ubHkgd2hlbiBtaXNzaW5nLCBzbyBhIGZ1bGx5LXByb3Zpc2lvbmVkIG1hY2hpbmUgaW5jdXJzIGp1c3QgdHdvXG4gICAqIGZhc3QgdmVyc2lvbi9saXN0IHByb2Jlcy5cbiAgICpcbiAgICogT25seSBpbnZva2VkIHdoZW4gdGhlIGhhcm5lc3MgaXMgYWJvdXQgdG8gYXV0by1zdGFydCB0aGUgc2VydmVyIGFuZFxuICAgKiB7QGxpbmsgT2JzaWRpYW5BbmRyb2lkQXBwaXVtVHJhbnNwb3J0T3B0aW9ucy5zaG91bGRBdXRvSW5zdGFsbEFwcGl1bURlcGVuZGVuY2llc31cbiAgICogaXMgZW5hYmxlZC4gQ29tbWFuZHMgYXJlIHBhc3NlZCBhcyBzdHJpbmdzIHNvIGBleGVjYCBydW5zIHRoZW0gdGhyb3VnaCB0aGVcbiAgICogc2hlbGwsIHdoaWNoIHJlc29sdmVzIHRoZSBgbnBtYC9gbnB4YCBgLmNtZGAgc2hpbXMgb24gV2luZG93cyAodGhlIGFycmF5XG4gICAqIHBhdGggc3Bhd25zIHdpdGhvdXQgYSBzaGVsbCBhbmQgY2Fubm90KS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZW5zdXJlQXBwaXVtRGVwZW5kZW5jaWVzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlQXBwaXVtSW5zdGFsbGVkKCk7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVVaWF1dG9tYXRvcjJEcml2ZXJJbnN0YWxsZWQoKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZW5zdXJlQXBwaXVtSW5zdGFsbGVkKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMubG9nKCdDaGVja2luZyB3aGV0aGVyIEFwcGl1bSBpcyBpbnN0YWxsZWQuLi4nKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBleGVjKCducHggLS1uby1pbnN0YWxsIGFwcGl1bSAtLXZlcnNpb24nLCB7XG4gICAgICBpc1F1aWV0OiB0cnVlLFxuICAgICAgc2hvdWxkSWdub3JlRXhpdENvZGU6IHRydWUsXG4gICAgICBzaG91bGRJbmNsdWRlRGV0YWlsczogdHJ1ZVxuICAgIH0pO1xuXG4gICAgaWYgKHJlc3VsdC5leGl0Q29kZSA9PT0gMCkge1xuICAgICAgdGhpcy5sb2coYEFwcGl1bSBpcyBpbnN0YWxsZWQgKHZlcnNpb24gJHtyZXN1bHQuc3Rkb3V0LnRyaW0oKSB8fCAndW5rbm93bid9KS5gKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmxvZygnQXBwaXVtIGlzIG5vdCBpbnN0YWxsZWQuIEluc3RhbGxpbmcgZ2xvYmFsbHkgdmlhIGBucG0gaW5zdGFsbCAtZyBhcHBpdW1gLi4uJyk7XG4gICAgYXdhaXQgZXhlYygnbnBtIGluc3RhbGwgLWcgYXBwaXVtJyk7XG5cbiAgICAvKlxuICAgICAqIFJlLXZlcmlmeTogYSBnbG9iYWwgaW5zdGFsbCBjYW4gbGFuZCB1bmRlciBhbiBucG0gcHJlZml4IHdob3NlIGJpbiBkaXIgaXNcbiAgICAgKiBub3Qgb24gdGhlIHNwYXduIFBBVEggKGUuZy4gYSBzY29vcC9udm0tbWFuYWdlZCBwcmVmaXgpLCBpbiB3aGljaCBjYXNlXG4gICAgICogYG5weCAtLW5vLWluc3RhbGwgYXBwaXVtYCBzdGlsbCBjYW5ub3QgcmVzb2x2ZSBpdC4gRmFpbCBmYXN0IHdpdGggYW5cbiAgICAgKiBhY3Rpb25hYmxlIG1lc3NhZ2UgcmF0aGVyIHRoYW4gcHJvY2VlZGluZyB0byBhdXRvLXN0YXJ0IGEgc2VydmVyIHRoYXQgY2FuXG4gICAgICogbmV2ZXIgY29tZSB1cCAod2hpY2ggd291bGQgb3RoZXJ3aXNlIHNwaW4gb3V0IHRoZSBmdWxsIHJlYWRpbmVzcyB0aW1lb3V0KS5cbiAgICAgKi9cbiAgICBjb25zdCB2ZXJpZnkgPSBhd2FpdCBleGVjKCducHggLS1uby1pbnN0YWxsIGFwcGl1bSAtLXZlcnNpb24nLCB7XG4gICAgICBpc1F1aWV0OiB0cnVlLFxuICAgICAgc2hvdWxkSWdub3JlRXhpdENvZGU6IHRydWUsXG4gICAgICBzaG91bGRJbmNsdWRlRGV0YWlsczogdHJ1ZVxuICAgIH0pO1xuICAgIGlmICh2ZXJpZnkuZXhpdENvZGUgIT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ0FwcGl1bSB3YXMgaW5zdGFsbGVkIHZpYSBgbnBtIGluc3RhbGwgLWcgYXBwaXVtYCBidXQgaXMgc3RpbGwgbm90IHJlc29sdmFibGUgdmlhIGBucHggLS1uby1pbnN0YWxsIGFwcGl1bWAuICdcbiAgICAgICAgICArICdUaGUgbnBtIGdsb2JhbCBiaW4gZGlyZWN0b3J5IChzZWUgYG5wbSBjb25maWcgZ2V0IHByZWZpeGApIGlzIGxpa2VseSBub3Qgb24gUEFUSC4gQWRkIGl0IHRvIFBBVEgsIG9yIHNldCAnXG4gICAgICAgICAgKyAnYHNob3VsZEF1dG9JbnN0YWxsQXBwaXVtRGVwZW5kZW5jaWVzOiBmYWxzZWAgYW5kIGluc3RhbGwvbWFuYWdlIEFwcGl1bSB5b3Vyc2VsZi4nXG4gICAgICApO1xuICAgIH1cbiAgICB0aGlzLmxvZyhgQXBwaXVtIGluc3RhbGxlZCAodmVyc2lvbiAke3ZlcmlmeS5zdGRvdXQudHJpbSgpIHx8ICd1bmtub3duJ30pLmApO1xuICB9XG5cbiAgLyoqXG4gICAqIEZhaWxzIGZhc3Qgd2hlbiB0aGUgcmVxdWVzdGVkIEFWRCBkb2VzIG5vdCBleGlzdCwgYmVmb3JlIGFuIGVtdWxhdG9yIGlzXG4gICAqIHNwYXduZWQuXG4gICAqXG4gICAqIFdpdGhvdXQgdGhpcyBwcmVmbGlnaHQgYSBtaXNzaW5nIEFWRCBuYW1lIGlzIG9ubHkgZGlzY292ZXJlZCBhZnRlclxuICAgKiB7QGxpbmsgc3RhcnRFbXVsYXRvcn0gc3Bhd25zIGBlbXVsYXRvciAtYXZkIDxuYW1lPmAgYW5kIHRoZSBib290IG5ldmVyXG4gICAqIGNvbXBsZXRlcyBcdTIwMTQgYSBmdWxsIHtAbGluayBFTVVMQVRPUl9CT09UX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTfSBzcGluIGVuZGluZ1xuICAgKiBpbiBhIGdlbmVyaWMgXCJubyBuZXcgZGV2aWNlIGFwcGVhcmVkXCIuIEluc3RlYWQgdGhpcyBsaXN0cyB0aGUgY29uZmlndXJlZFxuICAgKiBBVkRzIHVwIGZyb250IGFuZCB0aHJvd3MgYW4gYWN0aW9uYWJsZSBlcnJvciBuYW1pbmcgdGhlIGF2YWlsYWJsZSBvbmVzLiBBVkRcbiAgICogY3JlYXRpb24gaXMgZGVsaWJlcmF0ZWx5IG5vdCBhdXRvbWF0ZWQgKGl0IHJlcXVpcmVzIGEgc3lzdGVtLWltYWdlIGRvd25sb2FkLFxuICAgKiBsaWNlbnNlIGFjY2VwdGFuY2UsIGFuZCBoYXJkd2FyZS9BUEktbGV2ZWwgY2hvaWNlcykuXG4gICAqXG4gICAqIEBwYXJhbSBhdmROYW1lIC0gVGhlIHJlcXVlc3RlZCBBVkQgbmFtZS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZW5zdXJlQXZkRXhpc3RzKGF2ZE5hbWU6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGVtdWxhdG9yQmluYXJ5ID0gcmVzb2x2ZUVtdWxhdG9yQmluYXJ5UGF0aCgpO1xuICAgIHRoaXMubG9nKGBWZXJpZnlpbmcgQVZEIFwiJHthdmROYW1lfVwiIGV4aXN0cyAoJHtlbXVsYXRvckJpbmFyeX0gLWxpc3QtYXZkcykuLi5gKTtcblxuICAgIGNvbnN0IFtlcnJvciwgc3Rkb3V0XSA9IGF3YWl0IG5ldyBQcm9taXNlPFtFcnJvciB8IG51bGwsIHN0cmluZ10+KChyZXNvbHZlKSA9PiB7XG4gICAgICBleGVjRmlsZShlbXVsYXRvckJpbmFyeSwgWyctbGlzdC1hdmRzJ10sIHsgdGltZW91dDogRU1VTEFUT1JfTElTVF9USU1FT1VUX0lOX01JTExJU0VDT05EUyB9LCAoZXhlY0Vycm9yLCBleGVjU3Rkb3V0KSA9PiB7XG4gICAgICAgIHJlc29sdmUoW2V4ZWNFcnJvciwgZXhlY1N0ZG91dF0pO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpZiAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEZhaWxlZCB0byBsaXN0IEFWRHMgdmlhIFxcYCR7ZW11bGF0b3JCaW5hcnl9IC1saXN0LWF2ZHNcXGA6ICR7ZXJyb3IubWVzc2FnZX0uIGBcbiAgICAgICAgICArICdJcyB0aGUgQW5kcm9pZCBTREsgZW11bGF0b3IgaW5zdGFsbGVkIGFuZCBBTkRST0lEX0hPTUUvQU5EUk9JRF9TREtfUk9PVCBjb3JyZWN0PydcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKCFjaGVja0F2ZEV4aXN0cyh7IGF2ZExpc3RPdXRwdXQ6IHN0ZG91dCwgYXZkTmFtZSB9KSkge1xuICAgICAgY29uc3QgYXZhaWxhYmxlID0gbGlzdEF2YWlsYWJsZUF2ZHMoc3Rkb3V0KTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEFuZHJvaWQgQVZEIFwiJHthdmROYW1lfVwiIG5vdCBmb3VuZC4gQXZhaWxhYmxlIEFWRHM6ICR7YXZhaWxhYmxlLmxlbmd0aCA+IDAgPyBhdmFpbGFibGUuam9pbignLCAnKSA6ICcobm9uZSknfS4gYFxuICAgICAgICAgICsgJ0NyZWF0ZSBpdCAoZS5nLiBpbiB0aGUgQW5kcm9pZCBTdHVkaW8gRGV2aWNlIE1hbmFnZXIsIG9yIHZpYSBgYXZkbWFuYWdlciBjcmVhdGUgYXZkYCksIG9yIHNldCBgYXZkTmFtZWAgdG8gYW4gZXhpc3RpbmcgQVZELidcbiAgICAgICk7XG4gICAgfVxuXG4gICAgdGhpcy5sb2coYEFWRCBcIiR7YXZkTmFtZX1cIiBleGlzdHMuYCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGVuc3VyZURldmljZUNvbm5lY3RlZChwYXJhbXM6IEVuc3VyZURldmljZUNvbm5lY3RlZFBhcmFtcyk6IFByb21pc2U8RW5zdXJlRGV2aWNlQ29ubmVjdGVkUmVzdWx0PiB7XG4gICAgY29uc3QgeyBhdmROYW1lLCBkZXZpY2VJZGxlVGltZW91dEluTWlsbGlzZWNvbmRzLCBpc0VtdWxhdG9yVmlzaWJsZSwgbmV0d29ya1JlYWR5VGltZW91dEluTWlsbGlzZWNvbmRzIH0gPSBwYXJhbXM7XG4gICAgY29uc3QgdGltZW91dHM6IERldmljZVJlYWRpbmVzc1RpbWVvdXRzID0geyBkZXZpY2VJZGxlVGltZW91dEluTWlsbGlzZWNvbmRzLCBuZXR3b3JrUmVhZHlUaW1lb3V0SW5NaWxsaXNlY29uZHMgfTtcbiAgICBjb25zdCBkZXZpY2VJZHNCZWZvcmUgPSBhd2FpdCB0aGlzLmdldENvbm5lY3RlZERldmljZUlkcygpO1xuICAgIHRoaXMubG9nKGBDaGVja2luZyBleGlzdGluZyBkZXZpY2VzIGZvciBBVkQgXCIke2F2ZE5hbWV9XCIuLi4gKGNvbm5lY3RlZDogWyR7ZGV2aWNlSWRzQmVmb3JlLmpvaW4oJywgJyl9XSlgKTtcblxuICAgIGNvbnN0IHByb2JlUmVzdWx0cyA9IGF3YWl0IHRoaXMucHJvYmVEZXZpY2VzRm9yQXZkKGF2ZE5hbWUsIGRldmljZUlkc0JlZm9yZSk7XG4gICAgdGhpcy5sb2coYEFWRCBwcm9iZTogJHtidWlsZEF2ZFByb2JlU3VtbWFyeShwcm9iZVJlc3VsdHMpfS5gKTtcbiAgICBjb25zdCBwcm9iZVZlcmRpY3QgPSByZXNvbHZlQXZkUHJvYmVWZXJkaWN0KHByb2JlUmVzdWx0cyk7XG5cbiAgICBzd2l0Y2ggKHByb2JlVmVyZGljdC52ZXJkaWN0KSB7XG4gICAgICBjYXNlICdyZWZ1c2UnOiB7XG4gICAgICAgIC8qXG4gICAgICAgICAqIFNpbGVuY2UgaXMgbm90IGEgc2tpcC4gRmFsbGluZyB0aHJvdWdoIHRvIGEgbGF1bmNoIGhlcmUgaXMgd2hhdFxuICAgICAgICAgKiBwcm9kdWNlZCBgRkFUQUwgfCBSdW5uaW5nIG11bHRpcGxlIGVtdWxhdG9ycyB3aXRoIHRoZSBzYW1lIEFWRGAgXHUyMDE0XG4gICAgICAgICAqIHNlZSBgYXZkLXByb2JlLXZlcmRpY3QudHNgIGZvciB0aGUgcnVuIHRoaXMgcmVwcm9kdWNlcy5cbiAgICAgICAgICovXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihidWlsZFVucmVhZGFibGVEZXZpY2VzTWVzc2FnZSh7XG4gICAgICAgICAgYXZkTmFtZSxcbiAgICAgICAgICBwcm9iZVRpbWVvdXRJbk1pbGxpc2Vjb25kczogQURCX0RFVklDRV9DSEVDS19USU1FT1VUX0lOX01JTExJU0VDT05EUyxcbiAgICAgICAgICB1bnJlYWRhYmxlRGV2aWNlSWRzOiBwcm9iZVZlcmRpY3QudW5yZWFkYWJsZURldmljZUlkc1xuICAgICAgICB9KSk7XG4gICAgICB9XG4gICAgICBjYXNlICdyZXVzZSc6IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucmV1c2VDb25uZWN0ZWREZXZpY2UoYXZkTmFtZSwgcHJvYmVWZXJkaWN0LmRldmljZUlkLCB0aW1lb3V0cyk7XG4gICAgICB9XG4gICAgICBjYXNlICdzdGFydC1uZXcnOiB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgZGVmYXVsdDoge1xuICAgICAgICByZXR1cm4gYXNzZXJ0TmV2ZXIocHJvYmVWZXJkaWN0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmxvZyhgQVZEIFwiJHthdmROYW1lfVwiIG5vdCBmb3VuZCBvbiBhbnkgZXhpc3RpbmcgZGV2aWNlLCBzdGFydGluZyBhIG5ldyBlbXVsYXRvci4uLmApO1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlQXZkRXhpc3RzKGF2ZE5hbWUpO1xuICAgIC8qXG4gICAgICogU25hcHNob3QgdGhlIGVtdWxhdG9yIHByb2Nlc3NlcyB0aGF0IHByZWRhdGUgdGhpcyBsYXVuY2gsIHNvIHRoZSBvbmVzIHRoYXRcbiAgICAgKiBhcHBlYXIgYWNyb3NzIGl0IGNhbiBiZSBpZGVudGlmaWVkIGFzIE9VUlMuIFRoZSBsYXVuY2hlcidzIFBJRCBpcyBub3RcbiAgICAgKiBlbm91Z2ggdG8ga2lsbDogdW5kZXIgYC1uby13aW5kb3dgIHRoZSBwcm9jZXNzIHRoYXQgaG9sZHMgdGhlIEFWRCBpcyB0aGVcbiAgICAgKiBgcWVtdS1zeXN0ZW0tKi1oZWFkbGVzc2AgYmFja2VuZCBpdCBmb3Jrcywgd2hpY2ggc3Vydml2ZXMgYSBgdGFza2tpbGwgL1RgXG4gICAgICogb2YgdGhlIGxhdW5jaGVyIChzZWUgYGVtdWxhdG9yLWJhY2tlbmQudHNgKS4gRGlmZmluZyBoZXJlIFx1MjAxNCByYXRoZXIgdGhhblxuICAgICAqIHN3ZWVwaW5nIGBxZW11KmAgYXQgdGVhcmRvd24gXHUyMDE0IGlzIHdoYXQga2VlcHMgdGhlIGhhcm5lc3MgZnJvbSBraWxsaW5nXG4gICAgICogc29tZWJvZHkgZWxzZSdzIGVtdWxhdG9yLlxuICAgICAqL1xuICAgIGNvbnN0IGVtdWxhdG9yUGlkc0JlZm9yZSA9IGF3YWl0IHRoaXMubGlzdEVtdWxhdG9yQmFja2VuZFBpZHMoW10pO1xuICAgIGNvbnN0IHNob3VsZFJldXNlU25hcHNob3QgPSBwYXJhbXMuc2hvdWxkUmV1c2VFbXVsYXRvclNuYXBzaG90ID09PSB0cnVlO1xuICAgIGlmIChzaG91bGRSZXVzZVNuYXBzaG90KSB7XG4gICAgICB0aGlzLmxvZ1NuYXBzaG90QWdlKGF2ZE5hbWUpO1xuICAgIH1cbiAgICBjb25zdCBlbXVsYXRvciA9IHRoaXMuc3RhcnRFbXVsYXRvcihhdmROYW1lLCBzaG91bGRSZXVzZVNuYXBzaG90LCBpc0VtdWxhdG9yVmlzaWJsZSk7XG5cbiAgICAvKlxuICAgICAqIFRoZSBjYXB0dXJlIGlzIE5PVCBzdG9wcGVkIGhlcmUgYW55IG1vcmUuIEl0IHVzZWQgdG8gYmUsIGluIGEgYGZpbmFsbHlgXG4gICAgICogdGhlIG1vbWVudCBhIGRldmljZSBhcHBlYXJlZCBcdTIwMTQgd2hpY2ggZnJvemUgdGhlIGVtdWxhdG9yJ3MgdGVzdGltb255XG4gICAgICogZXhhY3RseSBvbmUgc3RlcCBiZWZvcmUgdGhlIGZhaWx1cmUgdGhpcyBoYXJuZXNzIGNvdWxkIG5vdCBleHBsYWluLiBUaGVcbiAgICAgKiBoYW5naW5nLXRocmVhZCBhbmQgcGFja2V0LXN0cmVhbWVyIGxpbmVzIGFyZSBwcmludGVkIGxhdGVyLCB3aGlsZSB0aGUgcnVuXG4gICAgICogaXMgaW5zaWRlIGBlc3RhYmxpc2hTZXNzaW9uYC4gVGhlIHdpbmRvdyBub3cgY2xvc2VzIHRoZXJlIGluc3RlYWQuXG4gICAgICovXG4gICAgY29uc3QgYWN0dWFsRGV2aWNlSWQgPSBhd2FpdCB0aGlzLndhaXRGb3JOZXdEZXZpY2UoZGV2aWNlSWRzQmVmb3JlLCBlbXVsYXRvciwgdGltZW91dHMpO1xuXG4gICAgY29uc3Qgb3duZWRFbXVsYXRvclBpZHMgPSBhd2FpdCB0aGlzLmxpc3RFbXVsYXRvckJhY2tlbmRQaWRzKGVtdWxhdG9yUGlkc0JlZm9yZSk7XG4gICAgdGhpcy5sb2coXG4gICAgICBgRW11bGF0b3IgXCIke2F2ZE5hbWV9XCIgc3RhcnRlZCwgZGV2aWNlICR7YWN0dWFsRGV2aWNlSWR9IGlzIGNvbm5lY3RlZCAob3duZWQgZW11bGF0b3IgUElEczogWyR7b3duZWRFbXVsYXRvclBpZHMuam9pbignLCAnKX1dKS5gXG4gICAgKTtcbiAgICBhd2FpdCB0aGlzLnN1cHByZXNzRXJyb3JEaWFsb2dzKGFjdHVhbERldmljZUlkKTtcbiAgICByZXR1cm4ge1xuICAgICAgYWN0dWFsRGV2aWNlSWQsXG4gICAgICBlbXVsYXRvckNhcHR1cmU6IHsgcmVhZDogZW11bGF0b3IucmVhZE91dHB1dCwgc3RvcDogZW11bGF0b3Iuc3RvcENhcHR1cmUgfSxcbiAgICAgIGVtdWxhdG9yUHJvY2VzczogZW11bGF0b3IucHJvY2VzcyxcbiAgICAgIG93bmVkRW11bGF0b3JQaWRzXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZW5zdXJlVWlhdXRvbWF0b3IyRHJpdmVySW5zdGFsbGVkKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMubG9nKGBDaGVja2luZyB3aGV0aGVyIHRoZSAke1VJQVVUT01BVE9SMl9EUklWRVJfTkFNRX0gZHJpdmVyIGlzIGluc3RhbGxlZC4uLmApO1xuICAgIGNvbnN0IGRyaXZlckxpc3RKc29uID0gYXdhaXQgZXhlYygnbnB4IC0tbm8taW5zdGFsbCBhcHBpdW0gZHJpdmVyIGxpc3QgLS1pbnN0YWxsZWQgLS1qc29uJywge1xuICAgICAgaXNRdWlldDogdHJ1ZSxcbiAgICAgIHNob3VsZElnbm9yZUV4aXRDb2RlOiB0cnVlXG4gICAgfSk7XG5cbiAgICBpZiAoY2hlY2tJc0FwcGl1bURyaXZlckluc3RhbGxlZCh7IGRyaXZlckxpc3RKc29uLCBkcml2ZXJOYW1lOiBVSUFVVE9NQVRPUjJfRFJJVkVSX05BTUUgfSkpIHtcbiAgICAgIHRoaXMubG9nKGBUaGUgJHtVSUFVVE9NQVRPUjJfRFJJVkVSX05BTUV9IGRyaXZlciBpcyBpbnN0YWxsZWQuYCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5sb2coYFRoZSAke1VJQVVUT01BVE9SMl9EUklWRVJfTkFNRX0gZHJpdmVyIGlzIG5vdCBpbnN0YWxsZWQuIEluc3RhbGxpbmcgdmlhIFxcYGFwcGl1bSBkcml2ZXIgaW5zdGFsbCAke1VJQVVUT01BVE9SMl9EUklWRVJfTkFNRX1cXGAuLi5gKTtcbiAgICBhd2FpdCBleGVjKGBucHggLS1uby1pbnN0YWxsIGFwcGl1bSBkcml2ZXIgaW5zdGFsbCAke1VJQVVUT01BVE9SMl9EUklWRVJfTkFNRX1gKTtcbiAgICB0aGlzLmxvZyhgVGhlICR7VUlBVVRPTUFUT1IyX0RSSVZFUl9OQU1FfSBkcml2ZXIgaW5zdGFsbGVkLmApO1xuICB9XG5cbiAgLyoqXG4gICAqIEVzdGFibGlzaGVzIHRoZSBXZWJEcml2ZXJJTyBzZXNzaW9uLCByZWNvZ25pemluZyB0aGUgb25lIGZhaWx1cmUgdGhhdCBibGFtZXNcbiAgICogdGhlIHdyb25nIHN1YmplY3Q6IGBDb3VsZCBub3QgZmluZCBhIGNvbm5lY3RlZCBBbmRyb2lkIGRldmljZWAgZnJvbSBhIHNlcnZlclxuICAgKiB3aG9zZSBhZGIgaXMgd2VkZ2VkIHdoaWxlIHRoZSBob3N0J3Mgb3duIGFkYiBzZWVzIHRoZSBkZXZpY2UgZmluZS5cbiAgICpcbiAgICogQSBzZXJ2ZXIgYW4gZWFybGllciBydW4gb2YgdGhpcyBoYXJuZXNzIHN0YXJ0ZWQgaXMgcmVzdGFydGVkIGFuZCB0aGUgc2Vzc2lvblxuICAgKiByZXRyaWVkIG9uY2UgXHUyMDE0IHRoZSBjb25maXJtZWQgcmVtZWR5LiBBIGZvcmVpZ24gb3IgdXNlci1tYW5hZ2VkIHNlcnZlciBpc1xuICAgKiBuZXZlciBraWxsZWQ7IGl0IGlzIHJlcG9ydGVkIHdpdGggYSBtZXNzYWdlIHRoYXQgbmFtZXMgdGhlIHNlcnZlci5cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtcyAtIFRoZSBzZXNzaW9uIGNhcGFiaWxpdGllcyBwbHVzIHdoYXQgaXMga25vd24gYWJvdXQgdGhlIHNlcnZlci5cbiAgICogQHJldHVybnMgVGhlIHNlc3Npb24sIGFuZCB0aGUgcmVwbGFjZW1lbnQgc2VydmVyIHByb2Nlc3Mgd2hlbiBvbmUgd2FzIHN0YXJ0ZWQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGVzdGFibGlzaFNlc3Npb24ocGFyYW1zOiBFc3RhYmxpc2hTZXNzaW9uUGFyYW1zKTogUHJvbWlzZTxFc3RhYmxpc2hTZXNzaW9uUmVzdWx0PiB7XG4gICAgdGhpcy5sb2coXG4gICAgICBgQ29ubmVjdGluZyB0byBBcHBpdW0gKGRldmljZT0ke3BhcmFtcy5kZXZpY2VJZH0sIGFwcD0ke3BhcmFtcy5hcHBJZH0sIHJldHJ5VGltZW91dDogJHtTdHJpbmcocGFyYW1zLnNlc3Npb25Db25uZWN0aW9uUmV0cnlUaW1lb3V0SW5NaWxsaXNlY29uZHMpfW1zLCByZXRyaWVzOiAke1N0cmluZyhBUFBJVU1fQ09OTkVDVElPTl9SRVRSWV9DT1VOVCl9KS4uLmBcbiAgICApO1xuXG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiB7IGJyb3dzZXI6IGF3YWl0IHRoaXMuY29ubmVjdFNlc3Npb24ocGFyYW1zKSB9O1xuICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICBjb25zdCB2ZXJkaWN0ID0gcmVzb2x2ZVdlZGdlZEFwcGl1bVNlcnZlclJlbWVkeSh7XG4gICAgICAgIGNvbm5lY3RlZERldmljZUlkczogYXdhaXQgdGhpcy5nZXRDb25uZWN0ZWREZXZpY2VJZHNRdWlldGx5KCksXG4gICAgICAgIGRldmljZUlkOiBwYXJhbXMuZGV2aWNlSWQsXG4gICAgICAgIGVycm9yLFxuICAgICAgICBpc0Fkb3B0ZWRTZXJ2ZXI6IHBhcmFtcy5pc0Fkb3B0ZWRTZXJ2ZXIsXG4gICAgICAgIGlzQXV0b1N0YXJ0QWxsb3dlZDogcGFyYW1zLnNob3VsZEF1dG9TdGFydEFwcGl1bSAhPT0gZmFsc2UsXG4gICAgICAgIGlzSGFybmVzc093bmVkU2VydmVyOiBjaGVja0lzSGFybmVzc093bmVkQXBwaXVtU2VydmVyKHBhcmFtcy5hcHBpdW1TZXJ2ZXJNYXJrZXIpXG4gICAgICB9KTtcblxuICAgICAgaWYgKHZlcmRpY3QucmVtZWR5ID09PSAnbm90LXdlZGdlZCcpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG5cbiAgICAgIGlmICh2ZXJkaWN0LnJlbWVkeSA9PT0gJ3JlcG9ydCcpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMuYnVpbGRXZWRnZWRNZXNzYWdlKHBhcmFtcywgdmVyZGljdC5yZWFzb24pLCB7IGNhdXNlOiBlcnJvciB9KTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucmVzdGFydFdlZGdlZFNlcnZlckFuZFJldHJ5KHBhcmFtcywgZXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBFc3RhYmxpc2hlcyB0aGUgc2Vzc2lvbiwgYW5kIHdoZW4gdGhhdCBmYWlscywgYXNrcyB0aGUgZGV2aWNlIHdoZXRoZXIgaXQgaXNcbiAgICogc3RpbGwgdGhlcmUgYmVmb3JlIGxldHRpbmcgdGhlIGZhaWx1cmUgc3RhbmQuXG4gICAqXG4gICAqIGBlc3RhYmxpc2hTZXNzaW9uYCBvd25zIGV4YWN0bHkgb25lIGRpYWdub3NpcyBcdTIwMTQgdGhlIHN0YWxlIEFwcGl1bSBzZXJ2ZXIgXHUyMDE0XG4gICAqIGFuZCByZXRocm93cyBldmVyeXRoaW5nIGVsc2UgdW50b3VjaGVkLiBUaGF0IGlzIHJpZ2h0IGFzIGZhciBhcyBpdCBnb2VzLCBidXRcbiAgICogZXZlcnkgc2lnbmF0dXJlIHRoaXMgaGFybmVzcyBhY3R1YWxseSBmYWlscyB3aXRoIG9uIGEgd2VkZ2VkIGVtdWxhdG9yIGZhbGxzXG4gICAqIGludG8gXCJldmVyeXRoaW5nIGVsc2VcIjogYERldmljZSA8aWQ+IHdhcyBub3QgaW4gdGhlIGxpc3Qgb2YgY29ubmVjdGVkXG4gICAqIGRldmljZXNgLCBgZXJyb3I6IGNsb3NlZGAsIGFuZCBhIGJhcmUgYFBPU1QgL3Nlc3Npb25gIHRpbWVvdXQuIFJhdGhlciB0aGFuXG4gICAqIHRlYWNoaW5nIHRoZSBzZXJ2ZXIgbW9kdWxlIHRvIHJlY29nbml6ZSBlcnJvciBzdHJpbmdzIHRoYXQgYXJlIG5vdCBhYm91dCB0aGVcbiAgICogc2VydmVyLCB0aGUgZGV2aWNlIGlzIHNpbXBseSByZS1wcm9iZWQgaGVyZSwgd2hlcmUgdGhlIGRldmljZSBpcyBrbm93bi4gQVxuICAgKiB3ZWRnZWQgZW11bGF0b3IgdGhlbiByZXBvcnRzIGl0c2VsZiwgYW5kIHRoZSBvcmlnaW5hbCBlcnJvciBpcyBrZXB0IGFzIHRoZVxuICAgKiBgY2F1c2VgLlxuICAgKlxuICAgKiBAcGFyYW0gZW11bGF0b3JDYXB0dXJlIC0gVGhlIGVtdWxhdG9yJ3Mgb3V0cHV0LCB3aGVuIHRoaXMgcnVuIHN0YXJ0ZWQgaXQuXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgc2Vzc2lvbiBwYXJhbWV0ZXJzLlxuICAgKiBAcmV0dXJucyBUaGUgZXN0YWJsaXNoZWQgc2Vzc2lvbi5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZXN0YWJsaXNoU2Vzc2lvbk9yRGlhZ25vc2VEZXZpY2UoXG4gICAgZW11bGF0b3JDYXB0dXJlOiBFbXVsYXRvckNhcHR1cmUgfCB1bmRlZmluZWQsXG4gICAgcGFyYW1zOiBFc3RhYmxpc2hTZXNzaW9uUGFyYW1zXG4gICk6IFByb21pc2U8RXN0YWJsaXNoU2Vzc2lvblJlc3VsdD4ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy5lc3RhYmxpc2hTZXNzaW9uKHBhcmFtcyk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgIGNvbnN0IGRpYWdub3NpcyA9IGF3YWl0IHRoaXMuZGlhZ25vc2VEZXZpY2UocGFyYW1zLmRldmljZUlkLCBlbXVsYXRvckNhcHR1cmUpO1xuICAgICAgaWYgKGRpYWdub3NpcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoZGlhZ25vc2lzLCB7IGNhdXNlOiBlcnJvciB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGdldENvbm5lY3RlZERldmljZUlkcygpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgcmV0dXJuIGxpc3RPbmxpbmVEZXZpY2VJZHMoYXdhaXQgdGhpcy5nZXREZXZpY2VzT3V0cHV0KCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIExpc3RzIHRoZSBob3N0J3MgY29ubmVjdGVkIGRldmljZXMgZm9yIHRoZSB3ZWRnZWQtc2VydmVyIGNyb3NzLWNoZWNrLCB3aGVyZVxuICAgKiBhbiBhZGIgdGhhdCBpdHNlbGYgZmFpbHMgbXVzdCBub3QgYmUgcmVhZCBhcyBldmlkZW5jZSBhZ2FpbnN0IHRoZSBzZXJ2ZXIuXG4gICAqXG4gICAqIEByZXR1cm5zIFRoZSBjb25uZWN0ZWQgZGV2aWNlIElEcywgb3IgYW4gZW1wdHkgbGlzdCB3aGVuIGFkYiBjb3VsZCBub3QgYmUgcnVuLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRDb25uZWN0ZWREZXZpY2VJZHNRdWlldGx5KCk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuZ2V0Q29ubmVjdGVkRGV2aWNlSWRzKCk7XG4gICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgIHRoaXMubG9nKGBDb3VsZCBub3QgcmUtY2hlY2sgY29ubmVjdGVkIGRldmljZXM6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWApO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0RGV2aWNlUHJvcGVydHkoZGV2aWNlSWQ6IHN0cmluZywgcHJvcGVydHk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICBleGVjRmlsZShcbiAgICAgICAgJ2FkYicsXG4gICAgICAgIFsnLXMnLCBkZXZpY2VJZCwgJ3NoZWxsJywgJ2dldHByb3AnLCBwcm9wZXJ0eV0sXG4gICAgICAgIHsgdGltZW91dDogQURCX0RFVklDRV9DSEVDS19USU1FT1VUX0lOX01JTExJU0VDT05EUyB9LFxuICAgICAgICAoZXJyb3IsIHN0ZG91dCkgPT4ge1xuICAgICAgICAgIC8vIFJldHVybiBubyBvdXRwdXQgb24gdGltZW91dC9lcnJvciAobm90IHBhcnRpYWwgc3Rkb3V0KSBzbyBhIG5vbi1yZXNwb25zaXZlIGd1ZXN0IHJlYWRzIGFzIFwibm90IGlkbGVcIi5cbiAgICAgICAgICByZXNvbHZlKGVycm9yID8gJycgOiBzdGRvdXQpO1xuICAgICAgICB9XG4gICAgICApO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgYGFkYiBkZXZpY2VzYCBhbmQgcmV0dXJucyBpdHMgcmF3IHN0ZG91dC5cbiAgICpcbiAgICogVGhlIHJhdyBsaXN0aW5nIGlzIHdoYXQgdGVhcmRvd24gbmVlZHM6IGBnZXRDb25uZWN0ZWREZXZpY2VJZHNgIGtlZXBzIG9ubHlcbiAgICogdGhlIGBkZXZpY2VgIHN0YXRlLCBhbmQgYW4gZW11bGF0b3Igb24gaXRzIHdheSBvdXQgYW5zd2VycyBgb2ZmbGluZWAgd2hpbGVcbiAgICogc3RpbGwgaG9sZGluZyB0aGUgQVZEIFx1MjAxNCBzZWUgYGFkYi1kZXZpY2UtbGlzdC50c2AuXG4gICAqXG4gICAqIEByZXR1cm5zIFRoZSByYXcgYGFkYiBkZXZpY2VzYCBvdXRwdXQuXG4gICAqIEB0aHJvd3MgSWYgYWRiIGNvdWxkIG5vdCBiZSBydW4gYXQgYWxsLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXREZXZpY2VzT3V0cHV0KCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPHN0cmluZz4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgZXhlY0ZpbGUoJ2FkYicsIFsnZGV2aWNlcyddLCB7IHRpbWVvdXQ6IEFEQl9ERVZJQ0VfQ0hFQ0tfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgfSwgKGVycm9yLCBzdGRvdXQsIHN0ZGVycikgPT4ge1xuICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKGBGYWlsZWQgdG8gcnVuICdhZGIgZGV2aWNlcyc6ICR7ZXJyb3IubWVzc2FnZX0uIElzIEFEQiBpbnN0YWxsZWQgYW5kIGluIFBBVEg/YCkpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc3RkZXJyKSB7XG4gICAgICAgICAgdGhpcy5sb2coYEFEQiBzdGRlcnI6ICR7c3RkZXJyLnRyaW0oKX1gKTtcbiAgICAgICAgfVxuICAgICAgICByZXNvbHZlKHN0ZG91dCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc2tzIHRoZSBlbXVsYXRvciB0byBzaHV0IGl0c2VsZiBkb3duIG92ZXIgaXRzIGNvbnNvbGUuXG4gICAqXG4gICAqIFByZWZlcnJlZCBvdmVyIGtpbGxpbmcgdGhlIHByb2Nlc3Mgb3V0cmlnaHQgYmVjYXVzZSBpdCBpcyB0aGUgcGF0aCB0aGF0XG4gICAqIHJlbGVhc2VzIHRoZSBBVkQncyBgbXVsdGlpbnN0YW5jZS5sb2NrYC4gQmVzdC1lZmZvcnQ6IGEgY29uc29sZSB0aGF0IGRvZXNcbiAgICogbm90IGFuc3dlciBpcyByZXBvcnRlZCBhbmQgdGhlIGNhbGxlciBmYWxscyB0aHJvdWdoIHRvIHRoZSBraWxsLlxuICAgKlxuICAgKiBAcGFyYW0gZGV2aWNlSWQgLSBUaGUgZW11bGF0b3IncyBkZXZpY2UgSUQuXG4gICAqL1xuICBwcml2YXRlIGtpbGxFbXVsYXRvckNvbnNvbGUoZGV2aWNlSWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgICAgZXhlY0ZpbGUoJ2FkYicsIFsnLXMnLCBkZXZpY2VJZCwgJ2VtdScsICdraWxsJ10sIHsgdGltZW91dDogQURCX0RFVklDRV9DSEVDS19USU1FT1VUX0lOX01JTExJU0VDT05EUyB9LCAoZXJyb3IsIHN0ZG91dCkgPT4ge1xuICAgICAgICB0aGlzLmxvZyhcbiAgICAgICAgICBlcnJvclxuICAgICAgICAgICAgPyBgRW11bGF0b3IgY29uc29sZSBzaHV0ZG93biBmb3IgJHtkZXZpY2VJZH0gZGlkIG5vdCBhbnN3ZXI6ICR7ZXJyb3IubWVzc2FnZX1gXG4gICAgICAgICAgICA6IGBFbXVsYXRvciBjb25zb2xlIHNodXRkb3duIGZvciAke2RldmljZUlkfTogJHtzdGRvdXQudHJpbSgpfWBcbiAgICAgICAgKTtcbiAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogTGlzdHMgdGhlIGVtdWxhdG9yIHByb2Nlc3NlcyBjdXJyZW50bHkgcnVubmluZyBvbiB0aGUgaG9zdCwgZXhjbHVkaW5nIGEgc2V0XG4gICAqIHRoYXQgaXMgYWxyZWFkeSBhY2NvdW50ZWQgZm9yLlxuICAgKlxuICAgKiBDYWxsZWQgdHdpY2UgYXJvdW5kIGEgbGF1bmNoOiB3aXRoIGFuIGVtcHR5IGBrbm93blBpZHNgIHRvIHNuYXBzaG90IHdoYXRcbiAgICogcHJlZGF0ZXMgaXQsIHRoZW4gd2l0aCB0aGF0IHNuYXBzaG90IHRvIG5hbWUgd2hhdCB0aGUgbGF1bmNoIGFkZGVkIFx1MjAxNCB3aGljaFxuICAgKiBpcyBwcmVjaXNlbHkgdGhlIHNldCB0aGlzIHJ1biBvd25zLlxuICAgKlxuICAgKiBCZXN0LWVmZm9ydDogYSBsaXN0aW5nIHRoYXQgY2Fubm90IGJlIHByb2R1Y2VkIHlpZWxkcyBubyBQSURzLCBzbyBhblxuICAgKiB1bmF2YWlsYWJsZSBgdGFza2xpc3RgL2Bwc2AgZGVncmFkZXMgdG8gXCJub3RoaW5nIHRvIGVzY2FsYXRlIHRvXCIgcmF0aGVyIHRoYW5cbiAgICogZmFpbGluZyB0aGUgcnVuIGl0IGlzIGNsZWFuaW5nIHVwIGZvci4gKipJdCBzYXlzIHNvLCBsb3VkbHkqKiBcdTIwMTQgYW4gZW1wdHkgc2V0XG4gICAqIHRoYXQgbWVhbnMgXCJubyBiYWNrZW5kIHRvIG93blwiIGFuZCBvbmUgdGhhdCBtZWFucyBcInRoZSBxdWVyeSBmYWlsZWRcIiBhcmVcbiAgICogb3RoZXJ3aXNlIHRoZSBzYW1lIGxvZyBsaW5lLCBhbmQgdGhlIHNlY29uZCBzaWxlbnRseSBkaXNhcm1zIHRoZSBlc2NhbGF0aW9uLlxuICAgKiBUaGF0IGlzIG5vdCBoeXBvdGhldGljYWw6IHRoZSBmaXJzdCBlbmQtdG8tZW5kIHJ1biBvZiB0aGlzIGNvZGUgbG9nZ2VkXG4gICAqIGBvd25lZCBlbXVsYXRvciBQSURzOiBbXWAgZm9yIGEgbGF1bmNoIHdob3NlIGJhY2tlbmQgd2FzIGRlbW9uc3RyYWJseSB0aGVyZSxcbiAgICogYmVjYXVzZSBgdGFza2xpc3RgIG92ZXJyYW4gYSAxMHMgYnVkZ2V0IG9uIGEgaG9zdCB0aGUgd2VkZ2VkIGVtdWxhdG9yIGhhZFxuICAgKiBhbHJlYWR5IHNsb3dlZCB0byB0aGUgcG9pbnQgd2hlcmUgZXZlcnkgYGFkYmAgY2FsbCB3YXMgdGltaW5nIG91dCB0b28gXHUyMDE0IHRoZVxuICAgKiBzYW1lIGNvbnRlbnRpb24gKipMNDUqKiBzaXplcyBgQURCX0RVTVBTWVNfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFNgIGZvciwgYW5kXG4gICAqIHRoZSBzYW1lIFwid3JvbmcgYnVkZ2V0IHNpbGVudGx5IGRpc2FibGVzIHRoZSBjaGVja1wiIHNoYXBlLlxuICAgKlxuICAgKiBBIGhvc3QgYWx3YXlzIGhhcyBwcm9jZXNzZXMsIHNvIGEgbGlzdGluZyB0aGF0IHBhcnNlcyB0byAqKnplcm8qKiByb3dzIGlzIGFcbiAgICogZmFpbGVkIHF1ZXJ5IGhvd2V2ZXIgaXQgZXhpdGVkLCBhbmQgaXMgcmVwb3J0ZWQgbGlrZSBvbmUuXG4gICAqXG4gICAqIEBwYXJhbSBrbm93blBpZHMgLSBFbXVsYXRvciBQSURzIHRvIGV4Y2x1ZGUuXG4gICAqIEByZXR1cm5zIFRoZSBlbXVsYXRvciBQSURzIG5vdCBpbiBga25vd25QaWRzYC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgbGlzdEVtdWxhdG9yQmFja2VuZFBpZHMoa25vd25QaWRzOiByZWFkb25seSBudW1iZXJbXSk6IFByb21pc2U8bnVtYmVyW10+IHtcbiAgICBjb25zdCBxdWVyeSA9IGJ1aWxkSG9zdFByb2Nlc3NRdWVyeSgpO1xuICAgIGNvbnN0IG91dHB1dCA9IGF3YWl0IG5ldyBQcm9taXNlPHN0cmluZz4oKHJlc29sdmUpID0+IHtcbiAgICAgIGV4ZWNGaWxlKFxuICAgICAgICBxdWVyeS5jb21tYW5kLFxuICAgICAgICBxdWVyeS5jb21tYW5kQXJndW1lbnRzLFxuICAgICAgICB7IG1heEJ1ZmZlcjogQURCX0RVTVBTWVNfTUFYX0JVRkZFUl9JTl9CWVRFUywgdGltZW91dDogSE9TVF9QUk9DRVNTX1FVRVJZX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTIH0sXG4gICAgICAgIChlcnJvciwgc3Rkb3V0KSA9PiB7XG4gICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICB0aGlzLmxvZyhgV2FybmluZzogY291bGQgbm90IGxpc3QgaG9zdCBwcm9jZXNzZXMgKFxcYCR7cXVlcnkuY29tbWFuZH1cXGApOiAke2Vycm9yLm1lc3NhZ2V9YCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJlc29sdmUoZXJyb3IgPyAnJyA6IHN0ZG91dCk7XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBjb25zdCBwcm9jZXNzZXMgPSBwYXJzZUhvc3RQcm9jZXNzTGlzdChvdXRwdXQpO1xuICAgIGlmIChwcm9jZXNzZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aGlzLmxvZyhcbiAgICAgICAgYFdhcm5pbmc6IFxcYCR7cXVlcnkuY29tbWFuZH1cXGAgbGlzdGVkIG5vIHByb2Nlc3Nlcywgc28gdGhpcyBydW4gY2Fubm90IGlkZW50aWZ5IHRoZSBlbXVsYXRvciBiYWNrZW5kIGl0IG93bnMuIFRlYXJkb3duIHdpbGwgZmFsbCBiYWNrIHRvIFxcYGFkYiBkZXZpY2VzXFxgIGFsb25lIGFuZCB3aWxsIGhhdmUgbm8gUElEIHRvIGVzY2FsYXRlIHRvLmBcbiAgICAgICk7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgcmV0dXJuIHNlbGVjdEVtdWxhdG9yQmFja2VuZFBpZHMoeyBrbm93blBpZHMsIHByb2Nlc3NlcyB9KTtcbiAgfVxuXG4gIHByaXZhdGUgbGlzdEluc3RhbGxlZFBhY2thZ2VzKGRldmljZUlkOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgZXhlY0ZpbGUoXG4gICAgICAgICdhZGInLFxuICAgICAgICBbJy1zJywgZGV2aWNlSWQsICdzaGVsbCcsICdjbWQnLCAncGFja2FnZScsICdsaXN0JywgJ3BhY2thZ2VzJ10sXG4gICAgICAgIHsgdGltZW91dDogQURCX0RFVklDRV9DSEVDS19USU1FT1VUX0lOX01JTExJU0VDT05EUyB9LFxuICAgICAgICAoZXJyb3IsIHN0ZG91dCkgPT4ge1xuICAgICAgICAgIC8vIFJldHVybiBubyBvdXRwdXQgb24gdGltZW91dC9lcnJvciBzbyBhIGNodXJuaW5nIGd1ZXN0J3Mgc2xvdy9wYXJ0aWFsIHBhY2thZ2UgbGlzdCBjYW4ndCBmYWxzZWx5IHJlYWQgYXMgaWRsZS5cbiAgICAgICAgICByZXNvbHZlKGVycm9yID8gJycgOiBzdGRvdXQpO1xuICAgICAgICB9XG4gICAgICApO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmRzIHRoZSBwcm9jZXNzZXMgc3RpbGwgbGlzdGVuaW5nIG9uIGEgcG9ydC5cbiAgICpcbiAgICogVGhpcyBpcyB0aGUgb25seSByZWFsIGVzY2FsYXRpb24gYXZhaWxhYmxlIGZvciB0aGUgQXBwaXVtIHNlcnZlcjogdGhlIFBJRFxuICAgKiB0aGUgaGFybmVzcyBob2xkcyBpcyB0aGUgc2hlbGwgd3JhcHBlciBpdCBzcGF3bmVkLCBzbyByZS1raWxsaW5nIGl0IGFjaGlldmVzXG4gICAqIG5vdGhpbmcsIHdoaWxlIGEgc29ja2V0IHN0aWxsIGFuc3dlcmluZyBvbiB0aGUgcG9ydCBpcyBkaXJlY3QgZXZpZGVuY2Ugb2ZcbiAgICogd2hhdCBzdXJ2aXZlZC5cbiAgICpcbiAgICogQHBhcmFtIHBvcnQgLSBUaGUgcG9ydCB0byBxdWVyeS5cbiAgICogQHJldHVybnMgVGhlIGxpc3RlbmluZyBQSURzLCBvciBhbiBlbXB0eSBsaXN0IHdoZW4gdGhlIHF1ZXJ5IGNvdWxkIG5vdCBiZSBydW4uXG4gICAqL1xuICBwcml2YXRlIGxpc3RQb3J0T3duZXJQaWRzKHBvcnQ6IG51bWJlcik6IFByb21pc2U8bnVtYmVyW10+IHtcbiAgICBjb25zdCBxdWVyeSA9IGJ1aWxkUG9ydE93bmVyUXVlcnkocG9ydCk7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPG51bWJlcltdPigocmVzb2x2ZSkgPT4ge1xuICAgICAgZXhlY0ZpbGUoXG4gICAgICAgIHF1ZXJ5LmNvbW1hbmQsXG4gICAgICAgIHF1ZXJ5LmNvbW1hbmRBcmd1bWVudHMsXG4gICAgICAgIHsgbWF4QnVmZmVyOiBBREJfRFVNUFNZU19NQVhfQlVGRkVSX0lOX0JZVEVTLCB0aW1lb3V0OiBIT1NUX1BST0NFU1NfUVVFUllfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgfSxcbiAgICAgICAgKGVycm9yLCBzdGRvdXQpID0+IHtcbiAgICAgICAgICAvLyBgbHNvZmAgZXhpdHMgbm9uLXplcm8gd2hlbiBub3RoaW5nIGhvbGRzIHRoZSBwb3J0LCB3aGljaCBpcyBhIGxlZ2l0aW1hdGUgZW1wdHkgYW5zd2VyLlxuICAgICAgICAgIHJlc29sdmUocGFyc2VQb3J0T3duZXJQaWRzKHsgb3V0cHV0OiBlcnJvciA/ICcnIDogc3Rkb3V0LCBwb3J0IH0pKTtcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTeW5jaHJvbm91cyB7QGxpbmsgbGlzdFBvcnRPd25lclBpZHN9LCBmb3IgdGhlIGBwcm9jZXNzLm9uKCdleGl0JylgIHRlYXJkb3duXG4gICAqIHRoYXQgY2Fubm90IGF3YWl0LlxuICAgKlxuICAgKiBJdHMgYnVkZ2V0IGlzIGRlbGliZXJhdGVseSAqKm5vdCoqIHRoZSBhc3luYyBwYXRoJ3M6IHRoaXMgY2FsbCBibG9ja3MgcHJvY2Vzc1xuICAgKiBleGl0IG91dHJpZ2h0LCBzbyBpdCB0YWtlcyBhIHNob3J0IG9uZSBhbmQgZ2l2ZXMgdXAgcmF0aGVyIHRoYW4gaG9sZGluZyB0aGVcbiAgICogZXhpdCBoYW5kbGVyIGZvciBoYWxmIGEgbWludXRlIG9uIGEgY29udGVuZGVkIGhvc3QuIEdpdmluZyB1cCBsb3NlcyB0aGVcbiAgICogZXNjYWxhdGlvbiwgd2hpY2ggdGhlIHN5bmMgcGF0aCdzIGxvZyBhbHJlYWR5IGFkbWl0cyBpdCBjYW5ub3QgY29uZmlybS5cbiAgICpcbiAgICogQHBhcmFtIHBvcnQgLSBUaGUgcG9ydCB0byBxdWVyeS5cbiAgICogQHJldHVybnMgVGhlIGxpc3RlbmluZyBQSURzLCBvciBhbiBlbXB0eSBsaXN0IHdoZW4gdGhlIHF1ZXJ5IGNvdWxkIG5vdCBiZSBydW4gaW4gdGltZS5cbiAgICovXG4gIHByaXZhdGUgbGlzdFBvcnRPd25lclBpZHNTeW5jKHBvcnQ6IG51bWJlcik6IG51bWJlcltdIHtcbiAgICBjb25zdCBxdWVyeSA9IGJ1aWxkUG9ydE93bmVyUXVlcnkocG9ydCk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IG91dHB1dCA9IGV4ZWNGaWxlU3luYyhxdWVyeS5jb21tYW5kLCBxdWVyeS5jb21tYW5kQXJndW1lbnRzLCB7XG4gICAgICAgIGVuY29kaW5nOiAndXRmLTgnLFxuICAgICAgICBtYXhCdWZmZXI6IEFEQl9EVU1QU1lTX01BWF9CVUZGRVJfSU5fQllURVMsXG4gICAgICAgIHRpbWVvdXQ6IFNZTkNfVEVBUkRPV05fUVVFUllfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFNcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHBhcnNlUG9ydE93bmVyUGlkcyh7IG91dHB1dCwgcG9ydCB9KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGxvZyhtZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBsb2coYFt0cmFuc3BvcnQtZmFjdG9yeToke3RoaXMudHlwZX1dICR7bWVzc2FnZX1gKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2dzIGhvdyBvbGQgdGhlIHNuYXBzaG90IGEgcnVuIGhhcyBvcHRlZCBpbnRvIHJlc3VtaW5nIGlzLlxuICAgKlxuICAgKiBCZXN0LWVmZm9ydDogYSBtaXNzaW5nIHNuYXBzaG90IGlzIHRoZSBub3JtYWwgc3RhdGUgb2YgYSBmcmVzaCBBVkQsIG5vdCBhXG4gICAqIGZhaWx1cmUsIGFuZCB0aGlzIGlzIGEgZGlhZ25vc3RpYyByYXRoZXIgdGhhbiBhIGdhdGUuXG4gICAqXG4gICAqIEBwYXJhbSBhdmROYW1lIC0gVGhlIEFWRCB3aG9zZSBzbmFwc2hvdCBpcyBhYm91dCB0byBiZSByZXN1bWVkLlxuICAgKi9cbiAgcHJpdmF0ZSBsb2dTbmFwc2hvdEFnZShhdmROYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBsZXQgc2F2ZWRBdDogRGF0ZSB8IHVuZGVmaW5lZDtcblxuICAgIGZvciAoY29uc3QgY2FuZGlkYXRlIG9mIGJ1aWxkQXZkU25hcHNob3REaXJlY3RvcnlDYW5kaWRhdGVzKHsgYXZkTmFtZSwgZW52aXJvbm1lbnQ6IHByb2Nlc3MuZW52LCBob21lRGlyZWN0b3J5OiBob21lZGlyKCkgfSkpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHNhdmVkQXQgPSBzdGF0U3luYyhjYW5kaWRhdGUpLm10aW1lO1xuICAgICAgICBicmVhaztcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBOb3QgdGhpcyBBVkQgaG9tZSBcdTIwMTQgdHJ5IHRoZSBuZXh0IGNhbmRpZGF0ZS5cbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmxvZyhidWlsZFNuYXBzaG90QWdlTWVzc2FnZSh7IGF2ZE5hbWUsIHNhdmVkQXQgfSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlYWRzIG9uZSBlbXVsYXRvcidzIEFWRCBuYW1lIGZyb20gaXRzIGNvbnNvbGUsIHJldHJ5aW5nIG9uY2UuXG4gICAqXG4gICAqIFRoZSByZXRyeSBpcyB3aGF0IG1ha2VzIHRoZSByZWZ1c2FsIHByb3BvcnRpb25hdGU6IHRoZSBwcm9iZSdzIHdob2xlIGJ1ZGdldFxuICAgKiBpcyA1cywgYW5kIGEgc2Vjb25kIGxvb2sgY29zdHMgbGVzcyB0aGFuIGEgY29sbGlkaW5nIGxhdW5jaCBkb2VzLiBXaGF0IGl0XG4gICAqIG11c3QgbmV2ZXIgZG8gaXMgcmVwb3J0IGEgbm9uLWFuc3dlciBhcyBhbiBhbnN3ZXIgXHUyMDE0IHRoZSBkaXNjYXJkZWQgYF9lcnJvcmBcbiAgICogdGhpcyByZXBsYWNlcyByZXNvbHZlZCBgJydgLCB3aGljaCBjb21wYXJlZCB1bmVxdWFsIHRvIHRoZSB3YW50ZWQgQVZEIGFuZCBzb1xuICAgKiByZWFkIGFzIGEgZGVmaW5pdGUgXCJzb21lIG90aGVyIEFWRFwiLlxuICAgKlxuICAgKiBAcGFyYW0gZGV2aWNlSWQgLSBUaGUgZW11bGF0b3IgdG8gYXNrLlxuICAgKiBAcmV0dXJucyBUaGUgQVZEIG5hbWUgaXQgYW5zd2VyZWQsIG9yIGB1bmRlZmluZWRgIHdoZW4gaXQgZGlkIG5vdCBhbnN3ZXIuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHByb2JlQXZkTmFtZShkZXZpY2VJZDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgICBmb3IgKGxldCBhdHRlbXB0ID0gMTsgYXR0ZW1wdCA8PSBBVkRfUFJPQkVfQVRURU1QVF9DT1VOVDsgYXR0ZW1wdCsrKSB7XG4gICAgICBjb25zdCBhbnN3ZXIgPSBhd2FpdCBuZXcgUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgICAgIGV4ZWNGaWxlKFxuICAgICAgICAgICdhZGInLFxuICAgICAgICAgIFsnLXMnLCBkZXZpY2VJZCwgJ2VtdScsICdhdmQnLCAnbmFtZSddLFxuICAgICAgICAgIHsgdGltZW91dDogQURCX0RFVklDRV9DSEVDS19USU1FT1VUX0lOX01JTExJU0VDT05EUyB9LFxuICAgICAgICAgIChlcnJvciwgc3Rkb3V0KSA9PiB7XG4gICAgICAgICAgICByZXNvbHZlKGVycm9yID8gdW5kZWZpbmVkIDogc3Rkb3V0LnNwbGl0KCdcXG4nLCAxKVswXT8udHJpbSgpKTtcbiAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKGFuc3dlciAhPT0gdW5kZWZpbmVkICYmIGFuc3dlci5sZW5ndGggPiAwKSB7XG4gICAgICAgIHJldHVybiBhbnN3ZXI7XG4gICAgICB9XG5cbiAgICAgIGlmIChhdHRlbXB0IDwgQVZEX1BST0JFX0FUVEVNUFRfQ09VTlQpIHtcbiAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgYERldmljZSAke2RldmljZUlkfSBkaWQgbm90IGFuc3dlciBcXGBhZGIgLXMgJHtkZXZpY2VJZH0gZW11IGF2ZCBuYW1lXFxgIHdpdGhpbiAke1N0cmluZyhBREJfREVWSUNFX0NIRUNLX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTKX1tczsgcmV0cnlpbmcgb25jZS5gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc2tzIGV2ZXJ5IGNvbm5lY3RlZCBkZXZpY2Ugd2hpY2ggQVZEIGl0IGlzIHNlcnZpbmcuXG4gICAqXG4gICAqIEEgZGV2aWNlIHRoYXQgaXMgbm90IGEgbG9jYWxseSBzdGFydGVkIGVtdWxhdG9yIGlzIG5ldmVyIGFza2VkOiBpdHMgY29uc29sZVxuICAgKiBjYW5ub3QgYW5zd2VyIGhvd2V2ZXIgaGVhbHRoeSBpdCBpcywgYW5kIHJlYWRpbmcgdGhhdCBhcyBzaWxlbmNlIHdvdWxkXG4gICAqIHJlZnVzZSBldmVyeSBydW4gb24gYSBob3N0IHdpdGggYSBoYW5kc2V0IHBsdWdnZWQgaW4gXHUyMDE0IHNlZVxuICAgKiBgYXZkLXByb2JlLXZlcmRpY3QudHNgLlxuICAgKlxuICAgKiBAcGFyYW0gYXZkTmFtZSAtIFRoZSBBVkQgdGhlIHJ1biB3YW50cy5cbiAgICogQHBhcmFtIGRldmljZUlkcyAtIFRoZSBjb25uZWN0ZWQgZGV2aWNlcy5cbiAgICogQHJldHVybnMgT25lIG91dGNvbWUgcGVyIGRldmljZSwgaW4gbGlzdGVkIG9yZGVyLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwcm9iZURldmljZXNGb3JBdmQoYXZkTmFtZTogc3RyaW5nLCBkZXZpY2VJZHM6IHJlYWRvbmx5IHN0cmluZ1tdKTogUHJvbWlzZTxBdmRQcm9iZVJlc3VsdFtdPiB7XG4gICAgY29uc3QgcmVzdWx0czogQXZkUHJvYmVSZXN1bHRbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBkZXZpY2VJZCBvZiBkZXZpY2VJZHMpIHtcbiAgICAgIGNvbnN0IHByb2JlZEF2ZE5hbWUgPSBjaGVja0lzRW11bGF0b3JEZXZpY2VJZChkZXZpY2VJZCkgPyBhd2FpdCB0aGlzLnByb2JlQXZkTmFtZShkZXZpY2VJZCkgOiB1bmRlZmluZWQ7XG4gICAgICByZXN1bHRzLnB1c2goeyBkZXZpY2VJZCwgb3V0Y29tZTogY2xhc3NpZnlBdmRQcm9iZSh7IGF2ZE5hbWUsIGRldmljZUlkLCBwcm9iZWRBdmROYW1lIH0pIH0pO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFza3MgdGhlICoqZ3Vlc3QqKiB3aGV0aGVyIGl0IGlzIHN0aWxsIHNjaGVkdWxpbmcgd29yaywgdmlhIGBhZGJkYC5cbiAgICpcbiAgICogQHBhcmFtIGRldmljZUlkIC0gVGhlIGRldmljZSB0byBwcm9iZS5cbiAgICogQHJldHVybnMgV2hhdCBpdCBhbnN3ZXJlZC5cbiAgICovXG4gIHByaXZhdGUgcHJvYmVEZXZpY2VTaGVsbChkZXZpY2VJZDogc3RyaW5nKTogUHJvbWlzZTxFbXVsYXRvckxpdmVuZXNzUHJvYmVPdXRjb21lPiB7XG4gICAgcmV0dXJuIHRoaXMucnVuTGl2ZW5lc3NQcm9iZShbJy1zJywgZGV2aWNlSWQsICdzaGVsbCcsICd0cnVlJ10pO1xuICB9XG5cbiAgLyoqXG4gICAqIEFza3MgdGhlICoqZW11bGF0b3IgcHJvY2VzcyoqIHdoZXRoZXIgaXQgaXMgc3RpbGwgcnVubmluZywgdmlhIGl0cyBjb25zb2xlLlxuICAgKlxuICAgKiBUaGUgY29uc29sZSBpcyBzZXJ2ZWQgYnkgdGhlIGVtdWxhdG9yIGl0c2VsZiByYXRoZXIgdGhhbiBieSB0aGUgZ3Vlc3QsIHdoaWNoXG4gICAqIGlzIHdoYXQgbWFrZXMgaXQgYWJsZSB0byB0ZWxsIGEgZnJvemVuIGd1ZXN0IGZyb20gYSB3ZWRnZWQgZW11bGF0b3IuXG4gICAqXG4gICAqIEBwYXJhbSBkZXZpY2VJZCAtIFRoZSBkZXZpY2UgdG8gcHJvYmUuXG4gICAqIEByZXR1cm5zIFdoYXQgaXQgYW5zd2VyZWQuXG4gICAqL1xuICBwcml2YXRlIHByb2JlRW11bGF0b3JDb25zb2xlKGRldmljZUlkOiBzdHJpbmcpOiBQcm9taXNlPEVtdWxhdG9yTGl2ZW5lc3NQcm9iZU91dGNvbWU+IHtcbiAgICByZXR1cm4gdGhpcy5ydW5MaXZlbmVzc1Byb2JlKFsnLXMnLCBkZXZpY2VJZCwgJ2VtdScsICdhdmQnLCAnc3RhdHVzJ10pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlcGxhY2VzIGEgbGVmdG92ZXIgc2VydmVyIGFuIGVhcmxpZXIgcnVuIGZhaWxlZCB0byBzdG9wLCBpbnN0ZWFkIG9mXG4gICAqIGFkb3B0aW5nIGl0LlxuICAgKlxuICAgKiBUaGlzIGlzIHRoZSBvdGhlciBoYWxmIG9mIHtAbGluayBzdG9wQXV0b1N0YXJ0ZWRBcHBpdW1TZXJ2ZXJ9J3Mgc3RhbXBlZFxuICAgKiBtYXJrZXIsIGFuZCBpdCBpcyB0aGUgY2FzZSB0aGF0IG1vdGl2YXRlZCB0aGUgd2hvbGUgdmVyaWZpZWQgdGVhcmRvd246IHRoZVxuICAgKiBsZWZ0b3ZlciBhbnN3ZXJzIGAvc3RhdHVzYCBwZXJmZWN0bHksIGlzIGFkb3B0ZWQsIGFuZCB0aGVuIGRpZXMgc2Vjb25kcyBpbnRvIHRoZSBzZXNzaW9uIGFzXG4gICAqIGl0IGZpbmFsbHkgZmluaXNoZXMgc2h1dHRpbmcgZG93biBcdTIwMTQgYSBmYWlsdXJlIHRoYXQgcmVhZHMgYXMgYSBkZXZpY2Ugb3JcbiAgICogbmV0d29yayBmYXVsdC4gQSBzZXJ2ZXIgd2Uga25vdyB3ZSBhbHJlYWR5IGFza2VkIHRvIGRpZSBpcyBub3QgYSBzZXJ2ZXIgdG9cbiAgICogYnVpbGQgYSBzdWl0ZSBvbi5cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtcyAtIFRoZSBtYXJrZXIsIHRoZSBwb3J0IGFuZCB3aGV0aGVyIGEgcmVwbGFjZW1lbnQgbWF5IGJlIHN0YXJ0ZWQuXG4gICAqIEByZXR1cm5zIGB0cnVlYCB3aGVuIHRoZSBwb3J0IHdhcyBmcmVlZCBhbmQgYSBmcmVzaCBzZXJ2ZXIgbXVzdCBiZSBzdGFydGVkLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZWNsYWltVW5zdG9wcGVkQXBwaXVtU2VydmVyKHBhcmFtczogUmVjbGFpbVVuc3RvcHBlZEFwcGl1bVNlcnZlclBhcmFtcyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHN0b3BBdHRlbXB0ZWRBdEluTWlsbGlzZWNvbmRzID0gcGFyYW1zLm1hcmtlci5zdG9wQXR0ZW1wdGVkQXRJbk1pbGxpc2Vjb25kcyA/PyBEYXRlLm5vdygpO1xuICAgIGNvbnN0IGFnZUluU2Vjb25kcyA9IE1hdGgucm91bmQoKERhdGUubm93KCkgLSBzdG9wQXR0ZW1wdGVkQXRJbk1pbGxpc2Vjb25kcykgLyBNSUxMSVNFQ09ORFNfUEVSX1NFQ09ORCk7XG4gICAgY29uc3QgcHJvdmVuYW5jZSA9IGB0aGUgc2VydmVyIG9uIHBvcnQgJHtTdHJpbmcocGFyYW1zLnBvcnQpfSBpcyBhIGxlZnRvdmVyIGFuIGVhcmxpZXIgcnVuIG9mIHRoaXMgaGFybmVzcyB0cmllZCB0byBzdG9wICR7U3RyaW5nKGFnZUluU2Vjb25kcyl9cyBhZ28gYW5kIGNvdWxkIG5vdGA7XG5cbiAgICBpZiAocGFyYW1zLnNob3VsZEF1dG9TdGFydEFwcGl1bSA9PT0gZmFsc2UpIHtcbiAgICAgIHRoaXMubG9nKGBXQVJOSU5HOiAke3Byb3ZlbmFuY2V9LiBBdXRvLXN0YXJ0IGlzIGRpc2FibGVkLCBzbyB0aGlzIHJ1biBhZG9wdHMgaXQgYW55d2F5OyBpZiB0aGUgc2Vzc2lvbiBkaWVzIG1pZC1mbGlnaHQsIHRoYXQgaXMgd2h5LmApO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHRoaXMubG9nKGBSZWZ1c2luZyB0byBhZG9wdCBhIGtub3duLWRvb21lZCBzZXJ2ZXI6ICR7cHJvdmVuYW5jZX0uIEtpbGxpbmcgd2hhdGV2ZXIgaG9sZHMgdGhlIHBvcnQgYW5kIHN0YXJ0aW5nIGEgZnJlc2ggc2VydmVyLi4uYCk7XG4gICAgZm9yIChjb25zdCBwaWQgb2YgYXdhaXQgdGhpcy5saXN0UG9ydE93bmVyUGlkcyhwYXJhbXMucG9ydCkpIHtcbiAgICAgIGtpbGxQcm9jZXNzVHJlZUJ5UGlkKHBpZCk7XG4gICAgfVxuICAgIGNsZWFyQXBwaXVtU2VydmVyTWFya2VyKHBhcmFtcy5wb3J0KTtcblxuICAgIGlmIChhd2FpdCB0aGlzLmNoZWNrSXNBcHBpdW1TdG9wcGVkKHBhcmFtcy51cmwsIEFQUElVTV9FU0NBTEFURURfU1RPUF9USU1FT1VUX0lOX01JTExJU0VDT05EUykpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHRoaXMubG9nKGBXQVJOSU5HOiAke3Byb3ZlbmFuY2V9LCBhbmQgaXQgc3Vydml2ZWQgdGhpcyBydW4ncyBraWxsIHRvby4gQWRvcHRpbmcgaXQsIHdoaWNoIG1heSBmYWlsIG1pZC1zZXNzaW9uLmApO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXBsYWNlcyBhIHdlZGdlZCBzZXJ2ZXIgdGhpcyBoYXJuZXNzIHN0YXJ0ZWQgZWFybGllciBhbmQgcmV0cmllcyB0aGVcbiAgICogc2Vzc2lvbiBvbmNlLlxuICAgKlxuICAgKiBUaGUgb2xkIHNlcnZlciBpcyBraWxsZWQgYW5kIHRoZSBwb3J0IGlzIHdhaXRlZCBvdXQgYmVmb3JlIGEgcmVwbGFjZW1lbnQgaXNcbiAgICogc3RhcnRlZDogYSBzb2NrZXQgdGhhdCBrZWVwcyBhbnN3ZXJpbmcgYC9zdGF0dXNgIHdvdWxkIGxldCB0aGUgcmVhZGluZXNzXG4gICAqIHBvbGwgcGFzcyBvbiB0aGUgZHlpbmcgc2VydmVyLCBhbmQgYSBwb3J0IHRoYXQgbmV2ZXIgZ29lcyBxdWlldCBtZWFucyB0aGVcbiAgICoga2lsbCBkaWQgbm90IHRha2UgXHUyMDE0IGluIHdoaWNoIGNhc2Ugc3RhcnRpbmcgYW55dGhpbmcgb24gaXQgaXMgcG9pbnRsZXNzLlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHNlc3Npb24gY2FwYWJpbGl0aWVzIHBsdXMgd2hhdCBpcyBrbm93biBhYm91dCB0aGUgc2VydmVyLlxuICAgKiBAcGFyYW0gb3JpZ2luYWxFcnJvciAtIFRoZSBmYWlsdXJlIHRoYXQgY29udmljdGVkIHRoZSBzZXJ2ZXIsIGxvZ2dlZCBzbyB0aGUgZGlhZ25vc2lzIGlzIG9uIHRoZSByZWNvcmQuXG4gICAqIEByZXR1cm5zIFRoZSBzZXNzaW9uIGFuZCB0aGUgcmVwbGFjZW1lbnQgc2VydmVyIHByb2Nlc3MuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHJlc3RhcnRXZWRnZWRTZXJ2ZXJBbmRSZXRyeShwYXJhbXM6IEVzdGFibGlzaFNlc3Npb25QYXJhbXMsIG9yaWdpbmFsRXJyb3I6IHVua25vd24pOiBQcm9taXNlPEVzdGFibGlzaFNlc3Npb25SZXN1bHQ+IHtcbiAgICBjb25zdCBtYXJrZXIgPSBlbnN1cmVOb25OdWxsYWJsZShwYXJhbXMuYXBwaXVtU2VydmVyTWFya2VyLCAnQSByZXN0YXJ0IHZlcmRpY3QgcmVxdWlyZXMgdGhlIG1hcmtlciB0aGF0IHByb3ZlZCBvd25lcnNoaXAuJyk7XG4gICAgdGhpcy5sb2coXG4gICAgICBgQXBwaXVtIGF0ICR7cGFyYW1zLnVybC5vcmlnaW59IGNhbm5vdCBzZWUgJHtwYXJhbXMuZGV2aWNlSWR9IGFsdGhvdWdoIHRoaXMgaG9zdCdzIGFkYiBjYW4gXHUyMDE0IHRoZSBzZXJ2ZXIgdGhpcyBoYXJuZXNzIHN0YXJ0ZWQgZWFybGllciAocGlkICR7U3RyaW5nKG1hcmtlci5waWQpfSkgaXMgc3RhbGUuIFJlc3RhcnRpbmcgaXQuLi4gKHNlc3Npb24gZmFpbGVkIHdpdGg6ICR7b3JpZ2luYWxFcnJvciBpbnN0YW5jZW9mIEVycm9yID8gb3JpZ2luYWxFcnJvci5tZXNzYWdlIDogU3RyaW5nKG9yaWdpbmFsRXJyb3IpfSlgXG4gICAgKTtcblxuICAgIGtpbGxQcm9jZXNzVHJlZUJ5UGlkKG1hcmtlci5waWQpO1xuICAgIGNsZWFyQXBwaXVtU2VydmVyTWFya2VyKHBhcmFtcy5wb3J0KTtcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLndhaXRGb3JBcHBpdW1TdG9wcGVkKHBhcmFtcy51cmwsIEFQUElVTV9TVE9QX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTKTtcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMuYnVpbGRXZWRnZWRNZXNzYWdlKHBhcmFtcywgJ3Jlc3RhcnQtZGlkLW5vdC1oZWxwJyksIHsgY2F1c2U6IGVycm9yIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IGxhdW5jaCA9IHRoaXMuc3RhcnRBcHBpdW1TZXJ2ZXIocGFyYW1zLnBvcnQsIHBhcmFtcy5pc0FwcGl1bUNvbnNvbGVWaXNpYmxlKTtcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLndhaXRGb3JBcHBpdW1SZWFkeShwYXJhbXMudXJsLCBwYXJhbXMuYXBwaXVtU3RhcnRUaW1lb3V0SW5NaWxsaXNlY29uZHMsIGxhdW5jaCk7XG4gICAgICB0aGlzLmxvZygnUmVwbGFjZW1lbnQgQXBwaXVtIHNlcnZlciBpcyByZWFkeSwgcmV0cnlpbmcgdGhlIHNlc3Npb24uLi4nKTtcbiAgICAgIHJldHVybiB7IGFwcGl1bVByb2Nlc3M6IGxhdW5jaC5wcm9jZXNzLCBicm93c2VyOiBhd2FpdCB0aGlzLmNvbm5lY3RTZXNzaW9uKHBhcmFtcykgfTtcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAga2lsbFByb2Nlc3NUcmVlKGxhdW5jaC5wcm9jZXNzKTtcbiAgICAgIGNsZWFyQXBwaXVtU2VydmVyTWFya2VyKHBhcmFtcy5wb3J0KTtcbiAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzLmJ1aWxkV2VkZ2VkTWVzc2FnZShwYXJhbXMsICdyZXN0YXJ0LWRpZC1ub3QtaGVscCcpLCB7IGNhdXNlOiBlcnJvciB9KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWRvcHRzIGEgZGV2aWNlIGFscmVhZHkgc2VydmluZyB0aGUgcmVxdWVzdGVkIEFWRC5cbiAgICpcbiAgICogQHBhcmFtIGF2ZE5hbWUgLSBUaGUgQVZEIGl0IGlzIHNlcnZpbmcuXG4gICAqIEBwYXJhbSBkZXZpY2VJZCAtIFRoZSBkZXZpY2UgdG8gYWRvcHQuXG4gICAqIEBwYXJhbSB0aW1lb3V0cyAtIFRoZSB0d28gcG9zdC1ib290IHJlYWRpbmVzcyBidWRnZXRzLlxuICAgKiBAcmV0dXJucyBUaGUgYWRvcHRlZCBkZXZpY2UsIG93bmluZyBubyBlbXVsYXRvciBQSURzLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZXVzZUNvbm5lY3RlZERldmljZShhdmROYW1lOiBzdHJpbmcsIGRldmljZUlkOiBzdHJpbmcsIHRpbWVvdXRzOiBEZXZpY2VSZWFkaW5lc3NUaW1lb3V0cyk6IFByb21pc2U8RW5zdXJlRGV2aWNlQ29ubmVjdGVkUmVzdWx0PiB7XG4gICAgdGhpcy5sb2coYEFWRCBcIiR7YXZkTmFtZX1cIiBpcyBhbHJlYWR5IHJ1bm5pbmcgb24gZGV2aWNlICR7ZGV2aWNlSWR9LCByZXVzaW5nLmApO1xuICAgIGF3YWl0IHRoaXMuc3VwcHJlc3NFcnJvckRpYWxvZ3MoZGV2aWNlSWQpO1xuICAgIC8qXG4gICAgICogQSByZXVzZWQgZGV2aWNlIGdldHMgdGhlIFNBTUUgc2V0dGxlIGdhdGUgYSBoYXJuZXNzLXN0YXJ0ZWQgb25lIGdldHMuXG4gICAgICogQXBwZWFyaW5nIGluIGBhZGIgZGV2aWNlc2Agc2F5cyBvbmx5IHRoYXQgYWRiZCBpcyB1cDogdGhlIGd1ZXN0IGNhblxuICAgICAqIHN0aWxsIGJlIHJ1bm5pbmcgdGhlIGJvb3QgYW5pbWF0aW9uIG9yIG9wdGltaXppbmcgcGFja2FnZXMsIGFuZCBhXG4gICAgICogc2Vzc2lvbiBlc3RhYmxpc2hlZCBhZ2FpbnN0IHRoYXQgY29udGVuZHMgd2l0aCB0aGUgY2h1cm4gYW5kIGluZmxhdGVzXG4gICAgICogZXZlcnkgc3Vic2VxdWVudCByb3VuZC10cmlwIDI1LTUweCAoTDE5KS4gU2tpcHBpbmcgdGhlIGdhdGUgaGVyZSBpc1xuICAgICAqIHdoYXQgbGV0IGEgcmVsZWFzZSBwcmVmbGlnaHQgc3BlbmQgaXRzIHdob2xlIGxheW91dC1yZWFkeSBidWRnZXQgb24gYVxuICAgICAqIGhhbmRmdWwgb2YgY29udGVuZGVkIHByb2JlcyB3aGlsZSBgYWRiIGRldmljZXNgIHJlcG9ydGVkIGBkZXZpY2VgXG4gICAgICogdGhyb3VnaG91dC4gVGhlIHNhbWUgYXJndW1lbnQgYXBwbGllcyB0byB0aGUgbmV0d29yayBnYXRlOiBhIGRldmljZVxuICAgICAqIHRoYXQgaGFzIGJlZW4gdXAgZm9yIHNlY29uZHMgaXMgZXhhY3RseSBvbmUgd2l0aCBubyB2YWxpZGF0ZWQgbmV0d29ya1xuICAgICAqIHlldC5cbiAgICAgKi9cbiAgICBhd2FpdCB0aGlzLndhaXRGb3JCb290KGRldmljZUlkLCBEYXRlLm5vdygpICsgRU1VTEFUT1JfQk9PVF9USU1FT1VUX0lOX01JTExJU0VDT05EUywgdW5kZWZpbmVkKTtcbiAgICBhd2FpdCB0aGlzLndhaXRGb3JEZXZpY2VSZWFkeShkZXZpY2VJZCwgdGltZW91dHMpO1xuICAgIGF3YWl0IHRoaXMud2FrZVNjcmVlbihkZXZpY2VJZCk7XG4gICAgLy8gQSBkZXZpY2UgdGhpcyBydW4gZGlkIG5vdCBzdGFydCBpcyBub3QgdGhpcyBydW4ncyB0byBzdG9wLlxuICAgIHJldHVybiB7IGFjdHVhbERldmljZUlkOiBkZXZpY2VJZCwgb3duZWRFbXVsYXRvclBpZHM6IFtdIH07XG4gIH1cblxuICAvKipcbiAgICogUnVucyBvbmUgbGl2ZW5lc3MgcHJvYmUsIHJldHJ5aW5nIG9uY2UgYmVmb3JlIGNhbGxpbmcgaXQgc2lsZW5jZS5cbiAgICpcbiAgICogT25seSBzdWNjZXNzIGNvdW50cyBhcyBhbiBhbnN3ZXI6IGEgZmFpbGVkIGBhZGIgLi4uIGVtdWAgbWF5IGJlIHRoZSBhZGJcbiAgICogc2VydmVyIHJlZnVzaW5nIGFuIGBvZmZsaW5lYCBkZXZpY2UgcmF0aGVyIHRoYW4gdGhlIGNvbnNvbGUgYmVpbmcgZGVhZCwgYW5kXG4gICAqIHRoZSB0d28gYXJlIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gaGVyZSAoc2VlIGBlbXVsYXRvci1saXZlbmVzcy50c2ApLiBUaGVcbiAgICogc2luZ2xlIHJldHJ5IGlzIHRoZSBzYW1lIHJlc3RyYWludCBgcHJvYmVBdmROYW1lYCBhcHBsaWVzIGZvciB0aGUgc2FtZVxuICAgKiByZWFzb24gXHUyMDE0IGEgc2Vjb25kIGxvb2sgaXMgZmFyIGNoZWFwZXIgdGhhbiBhIHdyb25nIHZlcmRpY3QsIGFuZCB0aGlzIG9uZVxuICAgKiBkZWNpZGVzIHdoZXRoZXIgYSBydW4gaXMgYWJvcnRlZC5cbiAgICpcbiAgICogQHBhcmFtIGlucHV0IC0gVGhlIGFkYiBhcmd1bWVudHMuXG4gICAqIEByZXR1cm5zIFdoZXRoZXIgdGhlIHByb2JlIGdvdCBhbiBhbnN3ZXIuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHJ1bkxpdmVuZXNzUHJvYmUoaW5wdXQ6IHJlYWRvbmx5IHN0cmluZ1tdKTogUHJvbWlzZTxFbXVsYXRvckxpdmVuZXNzUHJvYmVPdXRjb21lPiB7XG4gICAgZm9yIChsZXQgYXR0ZW1wdCA9IDE7IGF0dGVtcHQgPD0gREVWSUNFX0xJVkVORVNTX0FUVEVNUFRfQ09VTlQ7IGF0dGVtcHQrKykge1xuICAgICAgY29uc3QgaXNBbnN3ZXJlZCA9IGF3YWl0IG5ldyBQcm9taXNlPGJvb2xlYW4+KChyZXNvbHZlKSA9PiB7XG4gICAgICAgIGV4ZWNGaWxlKCdhZGInLCBbLi4uaW5wdXRdLCB7IHRpbWVvdXQ6IERFVklDRV9MSVZFTkVTU19USU1FT1VUX0lOX01JTExJU0VDT05EUyB9LCAoZXJyb3IpID0+IHtcbiAgICAgICAgICByZXNvbHZlKCFlcnJvcik7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGlmIChpc0Fuc3dlcmVkKSB7XG4gICAgICAgIHJldHVybiAnYW5zd2VyZWQnO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiAnbm8tYW5zd2VyJztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgc2VuZEtleUV2ZW50KGRldmljZUlkOiBzdHJpbmcsIGtleUNvZGU6IG51bWJlciwgZGVzY3JpcHRpb246IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgICBleGVjRmlsZShcbiAgICAgICAgJ2FkYicsXG4gICAgICAgIFsnLXMnLCBkZXZpY2VJZCwgJ3NoZWxsJywgJ2lucHV0JywgJ2tleWV2ZW50JywgU3RyaW5nKGtleUNvZGUpXSxcbiAgICAgICAgeyB0aW1lb3V0OiBBREJfREVWSUNFX0NIRUNLX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTIH0sXG4gICAgICAgIChlcnJvcikgPT4ge1xuICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgICAgIGBXYXJuaW5nOiBmYWlsZWQgdG8gJHtkZXNjcmlwdGlvbn0gKGtleWV2ZW50ICR7U3RyaW5nKGtleUNvZGUpfSk6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAndW5rbm93biBlcnJvcid9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHN0YXJ0QXBwaXVtQW5kRW11bGF0b3IocGFyYW1zOiBTdGFydEFwcGl1bUFuZEVtdWxhdG9yUGFyYW1zKTogUHJvbWlzZTxTdGFydEFwcGl1bUFuZEVtdWxhdG9yUmVzdWx0PiB7XG4gICAgY29uc3QgeyBhcHBpdW1TdGFydFRpbWVvdXRJbk1pbGxpc2Vjb25kcywgYXBwaXVtVXJsLCBhdmROYW1lLCBkZXZpY2VJZGxlVGltZW91dEluTWlsbGlzZWNvbmRzLCBpc0FwcGl1bUNvbnNvbGVWaXNpYmxlLCBpc0VtdWxhdG9yVmlzaWJsZSwgbmV0d29ya1JlYWR5VGltZW91dEluTWlsbGlzZWNvbmRzLCBwb3J0LCBzaG91bGRBdXRvSW5zdGFsbEFwcGl1bURlcGVuZGVuY2llcywgc2hvdWxkQXV0b1N0YXJ0QXBwaXVtLCBzaG91bGRSZXVzZUVtdWxhdG9yU25hcHNob3QgfSA9IHBhcmFtcztcblxuICAgIGxldCBuZWVkc0FwcGl1bVN0YXJ0ID0gZmFsc2U7XG4gICAgbGV0IGFwcGl1bVNlcnZlck1hcmtlcjogQXBwaXVtU2VydmVyTWFya2VyIHwgdW5kZWZpbmVkO1xuXG4gICAgdGhpcy5sb2coYENoZWNraW5nIEFwcGl1bSBzZXJ2ZXIgYXQgJHthcHBpdW1VcmwuaHJlZn0uLi5gKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5jaGVja0FwcGl1bVJlYWNoYWJsZShhcHBpdW1VcmwpO1xuICAgICAgYXBwaXVtU2VydmVyTWFya2VyID0gcmVhZEFwcGl1bVNlcnZlck1hcmtlcihwb3J0KTtcbiAgICAgIHRoaXMubG9nKGBBcHBpdW0gc2VydmVyIGlzIHJlYWNoYWJsZSAoJHt0aGlzLmRlc2NyaWJlQWRvcHRlZFNlcnZlcihhcHBpdW1TZXJ2ZXJNYXJrZXIpfSkuYCk7XG5cbiAgICAgIGlmIChhcHBpdW1TZXJ2ZXJNYXJrZXI/LnN0b3BBdHRlbXB0ZWRBdEluTWlsbGlzZWNvbmRzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbmVlZHNBcHBpdW1TdGFydCA9IGF3YWl0IHRoaXMucmVjbGFpbVVuc3RvcHBlZEFwcGl1bVNlcnZlcih7XG4gICAgICAgICAgbWFya2VyOiBhcHBpdW1TZXJ2ZXJNYXJrZXIsXG4gICAgICAgICAgcG9ydCxcbiAgICAgICAgICBzaG91bGRBdXRvU3RhcnRBcHBpdW0sXG4gICAgICAgICAgdXJsOiBhcHBpdW1VcmxcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChuZWVkc0FwcGl1bVN0YXJ0KSB7XG4gICAgICAgICAgYXBwaXVtU2VydmVyTWFya2VyID0gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3I6IHVua25vd24pIHtcbiAgICAgIGlmIChzaG91bGRBdXRvU3RhcnRBcHBpdW0gPT09IGZhbHNlKSB7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuICAgICAgbmVlZHNBcHBpdW1TdGFydCA9IHRydWU7XG4gICAgfVxuXG4gICAgbGV0IGFwcGl1bUxhdW5jaDogUHJvY2Vzc0xhdW5jaCB8IHVuZGVmaW5lZDtcblxuICAgIGlmIChuZWVkc0FwcGl1bVN0YXJ0KSB7XG4gICAgICBpZiAoc2hvdWxkQXV0b0luc3RhbGxBcHBpdW1EZXBlbmRlbmNpZXMpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5lbnN1cmVBcHBpdW1EZXBlbmRlbmNpZXMoKTtcbiAgICAgIH1cbiAgICAgIHRoaXMubG9nKGBBcHBpdW0gbm90IHJlYWNoYWJsZSwgYXV0by1zdGFydGluZyBvbiBwb3J0ICR7U3RyaW5nKHBvcnQpfS4uLmApO1xuICAgICAgYXBwaXVtTGF1bmNoID0gdGhpcy5zdGFydEFwcGl1bVNlcnZlcihwb3J0LCBpc0FwcGl1bUNvbnNvbGVWaXNpYmxlKTtcbiAgICB9XG5cbiAgICBjb25zdCBhcHBpdW1Qcm9jZXNzID0gYXBwaXVtTGF1bmNoPy5wcm9jZXNzO1xuXG4gICAgLypcbiAgICAgKiBgYWxsU2V0dGxlZGAsIG5vdCBgYWxsYDogdGhlIHR3byBoYWx2ZXMgc3RhcnQgdG9nZXRoZXIsIHNvIGEgcmVqZWN0ZWRcbiAgICAgKiBBcHBpdW0gd2FpdCB1c2VkIHRvIGFiYW5kb24gYW4gZW11bGF0b3IgdGhhdCB3ZW50IG9uIHRvIGJvb3QgcGVyZmVjdGx5IFx1MjAxNFxuICAgICAqIHRoZSBsZWFrIHN1cnZpdmVkIHRoZSB2ZXJ5IHRlYXJkb3duIHRoYXQgd2FzIHN1cHBvc2VkIHRvIHByZXZlbnQgaXQsXG4gICAgICogYmVjYXVzZSB0aGUgZW11bGF0b3IncyBoYW5kbGUgb25seSBleGlzdHMgaW5zaWRlIHRoZSByZXN1bHQgYFByb21pc2UuYWxsYFxuICAgICAqIGRpc2NhcmRlZC4gQm90aCBvdXRjb21lcyBhcmUgY29sbGVjdGVkIHNvIGJvdGggY2FuIGJlIHN0b3BwZWQuXG4gICAgICovXG4gICAgY29uc3QgW2FwcGl1bU91dGNvbWUsIGRldmljZU91dGNvbWVdID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcbiAgICAgIGFwcGl1bUxhdW5jaFxuICAgICAgICA/IHRoaXMud2FpdEZvckFwcGl1bVJlYWR5KGFwcGl1bVVybCwgYXBwaXVtU3RhcnRUaW1lb3V0SW5NaWxsaXNlY29uZHMsIGFwcGl1bUxhdW5jaCkudGhlbigoKSA9PiB7XG4gICAgICAgICAgdGhpcy5sb2coJ0F1dG8tc3RhcnRlZCBBcHBpdW0gc2VydmVyIGlzIHJlYWR5LicpO1xuICAgICAgICB9KVxuICAgICAgICA6IFByb21pc2UucmVzb2x2ZSgpLFxuICAgICAgdGhpcy5lbnN1cmVEZXZpY2VDb25uZWN0ZWQoeyBhdmROYW1lLCBkZXZpY2VJZGxlVGltZW91dEluTWlsbGlzZWNvbmRzLCBpc0VtdWxhdG9yVmlzaWJsZSwgbmV0d29ya1JlYWR5VGltZW91dEluTWlsbGlzZWNvbmRzLCBzaG91bGRSZXVzZUVtdWxhdG9yU25hcHNob3QgfSlcbiAgICBdKTtcblxuICAgIGNvbnN0IGRldmljZVJlc3VsdCA9IGRldmljZU91dGNvbWUuc3RhdHVzID09PSAnZnVsZmlsbGVkJyA/IGRldmljZU91dGNvbWUudmFsdWUgOiB1bmRlZmluZWQ7XG5cbiAgICBpZiAoYXBwaXVtT3V0Y29tZS5zdGF0dXMgPT09ICdyZWplY3RlZCcgfHwgZGV2aWNlUmVzdWx0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGF3YWl0IHRoaXMuc3RvcEF1dG9TdGFydGVkUHJvY2Vzc2VzVmVyaWZpZWQoe1xuICAgICAgICBhcHBpdW1Qcm9jZXNzLFxuICAgICAgICBhdmROYW1lLFxuICAgICAgICBkZXZpY2VJZDogZGV2aWNlUmVzdWx0Py5hY3R1YWxEZXZpY2VJZCxcbiAgICAgICAgZW11bGF0b3JQcm9jZXNzOiBkZXZpY2VSZXN1bHQ/LmVtdWxhdG9yUHJvY2VzcyxcbiAgICAgICAgb3duZWRFbXVsYXRvclBpZHM6IGRldmljZVJlc3VsdD8ub3duZWRFbXVsYXRvclBpZHMgPz8gW10sXG4gICAgICAgIHBvcnQsXG4gICAgICAgIHVybDogYXBwaXVtVXJsXG4gICAgICB9KTtcblxuICAgICAgdGhyb3cgZ2V0U2V0dGxlZEZhaWx1cmUoW2FwcGl1bU91dGNvbWUsIGRldmljZU91dGNvbWVdKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgYWN0dWFsRGV2aWNlSWQ6IGRldmljZVJlc3VsdC5hY3R1YWxEZXZpY2VJZCxcbiAgICAgIGFwcGl1bVByb2Nlc3MsXG4gICAgICBhcHBpdW1TZXJ2ZXJNYXJrZXIsXG4gICAgICBlbXVsYXRvckNhcHR1cmU6IGRldmljZVJlc3VsdC5lbXVsYXRvckNhcHR1cmUsXG4gICAgICBlbXVsYXRvclByb2Nlc3M6IGRldmljZVJlc3VsdC5lbXVsYXRvclByb2Nlc3MsXG4gICAgICBpc0Fkb3B0ZWRBcHBpdW1TZXJ2ZXI6ICFuZWVkc0FwcGl1bVN0YXJ0LFxuICAgICAgb3duZWRFbXVsYXRvclBpZHM6IGRldmljZVJlc3VsdC5vd25lZEVtdWxhdG9yUGlkc1xuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXJ0QXBwaXVtU2VydmVyKHBvcnQ6IG51bWJlciwgaXNBcHBpdW1Db25zb2xlVmlzaWJsZT86IGJvb2xlYW4pOiBQcm9jZXNzTGF1bmNoIHtcbiAgICBjb25zdCBpc0NvbnNvbGVIaWRkZW4gPSBzaG91bGRIaWRlQXBwaXVtQ29uc29sZShpc0FwcGl1bUNvbnNvbGVWaXNpYmxlKTtcbiAgICBjb25zdCB7IGRldGFjaGVkLCB3aW5kb3dzSGlkZSB9ID0gcmVzb2x2ZUFwcGl1bVNwYXduRmxhZ3MoaXNDb25zb2xlSGlkZGVuKTtcbiAgICAvKlxuICAgICAqIGAtLW5vLWluc3RhbGxgOiBBcHBpdW0gaXMgZ3VhcmFudGVlZCBwcmVzZW50IGJ5IGBlbnN1cmVBcHBpdW1JbnN0YWxsZWRgXG4gICAgICogYmVmb3JlIHdlIHJlYWNoIGhlcmUsIHNvIHBpbiBucHggdG8gdGhlIGluc3RhbGxlZCBjb3B5LiBXaXRob3V0IGl0LCBucHhcbiAgICAgKiB3b3VsZCBzaWxlbnRseSB0cnkgdG8gZG93bmxvYWQgQXBwaXVtIGZyZXNoIGZyb20gdGhlIHJlZ2lzdHJ5IFx1MjAxNCBhXG4gICAgICogc2xvdy9odW5nIGZhaWx1cmUgaW4gYSBoaWRkZW4gY29uc29sZSBcdTIwMTQgd2hlbmV2ZXIgaXQgY291bGQgbm90IHJlc29sdmUgdGhlXG4gICAgICogZ2xvYmFsIGluc3RhbGwgKGUuZy4gYSBnbG9iYWwgcHJlZml4IG5vdCBvbiBQQVRIKS4gU2VlIGBlbnN1cmVBcHBpdW1JbnN0YWxsZWRgLlxuICAgICAqXG4gICAgICogUGlwZSBzdGRvdXQvc3RkZXJyIGV2ZW4gd2hlbiBoaWRkZW4gKHJhdGhlciB0aGFuIGRpc2NhcmRpbmcpIHNvIGFuIGVhcmx5XG4gICAgICogZmFpbHVyZSBzdWNoIGFzIGEgY3Jhc2ggb3IgYSBtaXNzaW5nIGRyaXZlciBpcyBjYXB0dXJlZCBhbmQgc3VyZmFjZWRcbiAgICAgKiBpbW1lZGlhdGVseSBieSBgd2FpdEZvckFwcGl1bVJlYWR5YCwgbWlycm9yaW5nIGBzdGFydEVtdWxhdG9yYDtcbiAgICAgKiBgd2luZG93c0hpZGVgIHN0aWxsIHN1cHByZXNzZXMgdGhlIGNvbnNvbGUgd2luZG93LlxuICAgICAqL1xuICAgIGNvbnN0IGNoaWxkID0gc3Bhd24oYG5weCAtLW5vLWluc3RhbGwgYXBwaXVtIC0tbG9nLXRpbWVzdGFtcCAtLXBvcnQgJHtTdHJpbmcocG9ydCl9IC0tYWxsb3ctaW5zZWN1cmU9JHtDSFJPTUVEUklWRVJfQVVUT0RPV05MT0FEX0ZFQVRVUkV9YCwge1xuICAgICAgZGV0YWNoZWQsXG4gICAgICBzaGVsbDogdHJ1ZSxcbiAgICAgIHN0ZGlvOiBpc0NvbnNvbGVIaWRkZW4gPyBbJ2lnbm9yZScsICdwaXBlJywgJ3BpcGUnXSA6IFsnaWdub3JlJywgJ2luaGVyaXQnLCAnaW5oZXJpdCddLFxuICAgICAgd2luZG93c0hpZGVcbiAgICB9KTtcblxuICAgIGxldCBjYXB0dXJlZE91dHB1dCA9ICcnO1xuICAgIGxldCBleGl0SW5mbzogUHJvY2Vzc0V4aXRJbmZvIHwgdW5kZWZpbmVkO1xuICAgIGxldCBpc0NhcHR1cmluZyA9IHRydWU7XG5cbiAgICBjaGlsZC5zdGRvdXQ/Lm9uKCdkYXRhJywgYXBwZW5kT3V0cHV0KTtcbiAgICBjaGlsZC5zdGRlcnI/Lm9uKCdkYXRhJywgYXBwZW5kT3V0cHV0KTtcbiAgICBjaGlsZC5vbmNlKCdleGl0JywgKGNvZGUsIHNpZ25hbCkgPT4ge1xuICAgICAgZXhpdEluZm8gPSB7IGNvZGUsIHNpZ25hbCB9O1xuICAgIH0pO1xuICAgIGNoaWxkLm9uY2UoJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICBleGl0SW5mbyA9IHsgY29kZTogbnVsbCwgc2lnbmFsOiBudWxsLCBzcGF3bkVycm9yOiBlcnJvci5tZXNzYWdlIH07XG4gICAgfSk7XG5cbiAgICBjaGlsZC51bnJlZigpO1xuXG4gICAgLypcbiAgICAgKiBSZWNvcmQgdGhlIHNlcnZlciBhcyBvdXJzIGJlZm9yZSBhbnl0aGluZyBjYW4gYWRvcHQgaXQuIFRoZSBtYXJrZXIgaXMgd2hhdFxuICAgICAqIGxldHMgYSBsYXRlciBydW4gdGVsbCBpdHMgb3duIGxlZnRvdmVyIHNlcnZlciBmcm9tIGEgZm9yZWlnbiBvbmUsIGFuZCBzb1xuICAgICAqIHdoZXRoZXIgcmVzdGFydGluZyBhIHdlZGdlZCBzZXJ2ZXIgaXMgdGhpcyBoYXJuZXNzJ3MgY2FsbCB0byBtYWtlIFx1MjAxNCBzZWVcbiAgICAgKiBgYXBwaXVtLXNlcnZlci1tYXJrZXIudHNgLlxuICAgICAqL1xuICAgIGlmIChjaGlsZC5waWQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgd3JpdGVBcHBpdW1TZXJ2ZXJNYXJrZXIoeyBwaWQ6IGNoaWxkLnBpZCwgcG9ydCB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgcHJvY2VzczogY2hpbGQsXG4gICAgICByZWFkRXhpdEluZm86ICgpID0+IGV4aXRJbmZvLFxuICAgICAgcmVhZE91dHB1dDogKCkgPT4gY2FwdHVyZWRPdXRwdXQsXG4gICAgICBzdG9wQ2FwdHVyZTogKCk6IHZvaWQgPT4ge1xuICAgICAgICBpc0NhcHR1cmluZyA9IGZhbHNlO1xuICAgICAgfVxuICAgIH07XG5cbiAgICBmdW5jdGlvbiBhcHBlbmRPdXRwdXQoY2h1bms6IEJ1ZmZlcik6IHZvaWQge1xuICAgICAgaWYgKCFpc0NhcHR1cmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBjYXB0dXJlZE91dHB1dCA9IChjYXB0dXJlZE91dHB1dCArIGNodW5rLnRvU3RyaW5nKCkpLnNsaWNlKC1BUFBJVU1fT1VUUFVUX1RBSUxfTUFYX0xFTkdUSCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzdGFydEVtdWxhdG9yKGF2ZE5hbWU6IHN0cmluZywgc2hvdWxkUmV1c2VTbmFwc2hvdDogYm9vbGVhbiwgaXNFbXVsYXRvclZpc2libGU/OiBib29sZWFuKTogUHJvY2Vzc0xhdW5jaCB7XG4gICAgY29uc3QgZW11bGF0b3JCaW5hcnkgPSByZXNvbHZlRW11bGF0b3JCaW5hcnlQYXRoKCk7XG4gICAgY29uc3QgaXNXaW5kb3dIaWRkZW4gPSBzaG91bGRIaWRlRW11bGF0b3JXaW5kb3coaXNFbXVsYXRvclZpc2libGUpO1xuICAgIGNvbnN0IGlucHV0ID0gYnVpbGRFbXVsYXRvckFyZ3VtZW50cyh7IGF2ZE5hbWUsIGlzSGlkZGVuOiBpc1dpbmRvd0hpZGRlbiwgc2hvdWxkUmV1c2VTbmFwc2hvdCB9KTtcbiAgICBjb25zdCB7IGRldGFjaGVkLCB3aW5kb3dzSGlkZSB9ID0gcmVzb2x2ZUVtdWxhdG9yU3Bhd25GbGFncyhpc1dpbmRvd0hpZGRlbik7XG4gICAgdGhpcy5sb2coYFJ1bm5pbmc6ICR7ZW11bGF0b3JCaW5hcnl9ICR7aW5wdXQuam9pbignICcpfWApO1xuICAgIC8qXG4gICAgICogUGlwZSAocmF0aGVyIHRoYW4gaWdub3JlKSBzdGRvdXQvc3RkZXJyIHNvIGFuIGVhcmx5IGZhaWx1cmUgc3VjaCBhc1xuICAgICAqIFwieDg2XzY0IGVtdWxhdGlvbiBjdXJyZW50bHkgcmVxdWlyZXMgaGFyZHdhcmUgYWNjZWxlcmF0aW9uXCIgY2FuIGJlXG4gICAgICogc3VyZmFjZWQgaW1tZWRpYXRlbHkgaW5zdGVhZCBvZiB3YWl0aW5nIG91dCB0aGUgZnVsbCBib290IHRpbWVvdXQuXG4gICAgICovXG4gICAgY29uc3QgY2hpbGQgPSBzcGF3bihlbXVsYXRvckJpbmFyeSwgaW5wdXQsIHtcbiAgICAgIGRldGFjaGVkLFxuICAgICAgc3RkaW86IFsnaWdub3JlJywgJ3BpcGUnLCAncGlwZSddLFxuICAgICAgd2luZG93c0hpZGVcbiAgICB9KTtcblxuICAgIGxldCBjYXB0dXJlZE91dHB1dCA9ICcnO1xuICAgIGxldCBleGl0SW5mbzogUHJvY2Vzc0V4aXRJbmZvIHwgdW5kZWZpbmVkO1xuICAgIGxldCBpc0NhcHR1cmluZyA9IHRydWU7XG5cbiAgICBjaGlsZC5zdGRvdXQub24oJ2RhdGEnLCBhcHBlbmRPdXRwdXQpO1xuICAgIGNoaWxkLnN0ZGVyci5vbignZGF0YScsIGFwcGVuZE91dHB1dCk7XG4gICAgY2hpbGQub25jZSgnZXhpdCcsIChjb2RlLCBzaWduYWwpID0+IHtcbiAgICAgIGV4aXRJbmZvID0geyBjb2RlLCBzaWduYWwgfTtcbiAgICB9KTtcbiAgICAvKlxuICAgICAqIEEgc3Bhd24gZmFpbHVyZSAoZS5nLiBFTk9FTlQgZm9yIGEgbWlzc2luZy9icm9rZW4gZW11bGF0b3IgYmluYXJ5KSBlbWl0c1xuICAgICAqICdlcnJvcicsIG5vdCAnZXhpdCcuIFJlY29yZCBpdCBhcyBhIHN5bnRoZXRpYyBleGl0IHNvIHRoZSBib290L25ldy1kZXZpY2VcbiAgICAgKiBwb2xscyBmYWlsIGZhc3QgaW5zdGVhZCBvZiBzcGlubmluZyBvdXQgdGhlIGZ1bGwgYm9vdCB0aW1lb3V0LlxuICAgICAqL1xuICAgIGNoaWxkLm9uY2UoJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICBleGl0SW5mbyA9IHsgY29kZTogbnVsbCwgc2lnbmFsOiBudWxsLCBzcGF3bkVycm9yOiBlcnJvci5tZXNzYWdlIH07XG4gICAgfSk7XG5cbiAgICBjaGlsZC51bnJlZigpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHByb2Nlc3M6IGNoaWxkLFxuICAgICAgcmVhZEV4aXRJbmZvOiAoKSA9PiBleGl0SW5mbyxcbiAgICAgIHJlYWRPdXRwdXQ6ICgpID0+IGNhcHR1cmVkT3V0cHV0LFxuICAgICAgc3RvcENhcHR1cmU6ICgpOiB2b2lkID0+IHtcbiAgICAgICAgLypcbiAgICAgICAgICogTGVhdmUgdGhlIGBkYXRhYCBsaXN0ZW5lcnMgYXR0YWNoZWQgc28gdGhlIHBpcGVzIGtlZXAgZHJhaW5pbmcgKGFcbiAgICAgICAgICogZnVsbCBPUyBwaXBlIGJ1ZmZlciB3b3VsZCBibG9jayB0aGUgbG9uZy1ydW5uaW5nIGVtdWxhdG9yKTsgdGhlIGZsYWdcbiAgICAgICAgICoganVzdCBmcmVlemVzIHRoZSBjYXB0dXJlZCB0YWlsIG9uY2Ugc3RhcnR1cCBoYXMgc3VjY2VlZGVkLlxuICAgICAgICAgKi9cbiAgICAgICAgaXNDYXB0dXJpbmcgPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gYXBwZW5kT3V0cHV0KGNodW5rOiBCdWZmZXIpOiB2b2lkIHtcbiAgICAgIGlmICghaXNDYXB0dXJpbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgY2FwdHVyZWRPdXRwdXQgPSAoY2FwdHVyZWRPdXRwdXQgKyBjaHVuay50b1N0cmluZygpKS5zbGljZSgtRU1VTEFUT1JfT1VUUFVUX1RBSUxfTUFYX0xFTkdUSCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIERpc2FibGVzIHRoZSBndWVzdCdzIGNyYXNoL0FOUiBkaWFsb2dzIG9uIHRoZSBnaXZlbiBkZXZpY2UuXG4gICAqXG4gICAqIEEgcmVzb3VyY2Utc3RhcnZlZCBlbXVsYXRvciBjYW4gcmFpc2UgYSBcIlByb2Nlc3Mgc3lzdGVtIGlzbid0IHJlc3BvbmRpbmdcIlxuICAgKiBBTlIgKGFuIGBBY3Rpdml0eU1hbmFnZXJTZXJ2aWNlYCB0aW1lb3V0KSB3aG9zZSBkaWFsb2cgb3ZlcmxheXMgdGhlIFVJLiBJZlxuICAgKiBpdCBhcHBlYXJzIGJlZm9yZSBBcHBpdW0gYXR0YWNoZXMsIG5vdGhpbmcgY2FuIGRpc21pc3MgaXQgYW5kIHRoZSBydW4gaGFuZ3NcbiAgICogb3IgZmFpbHMgaW50ZXJtaXR0ZW50bHkuIFNldHRpbmcgdGhlIGBoaWRlX2Vycm9yX2RpYWxvZ3NgIGdsb2JhbCBcdTIwMTQgdGhlIHNhbWVcbiAgICogZmxhZyBBbmRyb2lkJ3Mgb3duIHRlc3QgaW5mcmEgdXNlcyBcdTIwMTQgdGVsbHMgYEFjdGl2aXR5TWFuYWdlclNlcnZpY2VgIHRvXG4gICAqIG5ldmVyIGRyYXcgY3Jhc2gvQU5SIGRpYWxvZ3MsIHNvIHRoZSBBTlIgY2FuIG5vIGxvbmdlciBibG9jayBhdXRvbWF0aW9uLlxuICAgKlxuICAgKiBUaGlzIGlzIHRoZSBlYXJsaWVzdCBwb2ludCBhdCB3aGljaCB0aGUgZmxhZyBjYW4gYmUgc2V0OiB0aGUgZnJhbWV3b3JrXG4gICAqIChgc3lzdGVtX3NlcnZlcmApIG11c3QgYmUgdXAgYmVmb3JlIGBzZXR0aW5ncyBwdXRgIHdvcmtzLCBzbyBjYWxsZXJzIGludm9rZVxuICAgKiBpdCBvbmx5IGFmdGVyIGBzeXMuYm9vdF9jb21wbGV0ZWRgLiBJdCBuYXJyb3dzIFx1MjAxNCBidXQgY2Fubm90IGZ1bGx5IGNsb3NlIFx1MjAxNFxuICAgKiB0aGUgcmFjZSB3aXRoIGFuIEFOUiB0aGF0IGZpcmVzIGJldHdlZW4gYm9vdCBjb21wbGV0aW5nIGFuZCB0aGlzIGNhbGw7IGFcbiAgICogcHJlLWJha2VkIHNuYXBzaG90IHdpdGggdGhlIGZsYWcgYWxyZWFkeSBzZXQgaXMgdGhlIG9ubHkgd2F5IHRvIGVsaW1pbmF0ZVxuICAgKiBpdCBlbnRpcmVseS4gQmVzdC1lZmZvcnQ6IGEgZmFpbHVyZSBpcyBsb2dnZWQsIG5vdCB0aHJvd24sIHNpbmNlIGl0IG9ubHlcbiAgICogc3VwcHJlc3NlcyBhIHN5bXB0b20uXG4gICAqXG4gICAqIEBwYXJhbSBkZXZpY2VJZCAtIFRoZSBkZXZpY2UgVURJRCB0byBjb25maWd1cmUuXG4gICAqL1xuICAvKipcbiAgICogU3RvcHMgdGhlIEFwcGl1bSBzZXJ2ZXIgdGhpcyBydW4gc3RhcnRlZCwgYW5kICoqdmVyaWZpZXMqKiBpdCBzdG9wcGVkLlxuICAgKlxuICAgKiBUaGUgcG9ydCBpcyB0aGUgdmVyZGljdDogYSBzb2NrZXQgc3RpbGwgYW5zd2VyaW5nIGAvc3RhdHVzYCBhZnRlciB0aGUga2lsbFxuICAgKiBpcyB0aGUgc2VydmVyLCB3aGF0ZXZlciB0aGUgUElEIHRhYmxlIHNheXMuIFdoZW4gaXQgaXMgc3RpbGwgdGhlcmUgdGhlXG4gICAqIGxpc3RlbmVyIGlzIGtpbGxlZCBieSBwb3J0IG93bmVyc2hpcCBcdTIwMTQgdGhlIG9ubHkgZXNjYWxhdGlvbiB0aGF0IG1lYW5zXG4gICAqIGFueXRoaW5nLCBzaW5jZSByZS1raWxsaW5nIHRoZSBzaGVsbCB3cmFwcGVyJ3MgUElEIHdvdWxkIGp1c3QgcmVwZWF0IHRoZVxuICAgKiBraWxsIHRoYXQgYWxyZWFkeSBmYWlsZWQuXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgc2VydmVyIHByb2Nlc3MsIGl0cyBwb3J0IGFuZCBpdHMgVVJMLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzdG9wQXV0b1N0YXJ0ZWRBcHBpdW1TZXJ2ZXIocGFyYW1zOiBTdG9wQXV0b1N0YXJ0ZWRBcHBpdW1TZXJ2ZXJQYXJhbXMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBraWxsUHJvY2Vzc1RyZWUocGFyYW1zLmFwcGl1bVByb2Nlc3MpO1xuXG4gICAgbGV0IGhhc0VzY2FsYXRlZCA9IGZhbHNlO1xuICAgIGxldCBpc1N0b3BwZWQgPSBhd2FpdCB0aGlzLmNoZWNrSXNBcHBpdW1TdG9wcGVkKHBhcmFtcy51cmwsIEFQUElVTV9TVE9QX1RJTUVPVVRfSU5fTUlMTElTRUNPTkRTKTtcblxuICAgIGlmICghaXNTdG9wcGVkKSB7XG4gICAgICBjb25zdCBvd25lclBpZHMgPSBhd2FpdCB0aGlzLmxpc3RQb3J0T3duZXJQaWRzKHBhcmFtcy5wb3J0KTtcbiAgICAgIGlmIChvd25lclBpZHMubGVuZ3RoID4gMCkge1xuICAgICAgICBoYXNFc2NhbGF0ZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLmxvZyhcbiAgICAgICAgICBgQXV0by1zdGFydGVkIEFwcGl1bSBzZXJ2ZXIgc3RpbGwgYW5zd2VycyBvbiAke3BhcmFtcy51cmwub3JpZ2lufSBhZnRlciBpdHMgcHJvY2VzcyB0cmVlIHdhcyBraWxsZWQ7IGVzY2FsYXRpbmcgdG8gdGhlIFBJRChzKSBob2xkaW5nIHRoZSBwb3J0OiBbJHtvd25lclBpZHMuam9pbignLCAnKX1dLmBcbiAgICAgICAgKTtcbiAgICAgICAgZm9yIChjb25zdCBwaWQgb2Ygb3duZXJQaWRzKSB7XG4gICAgICAgICAga2lsbFByb2Nlc3NUcmVlQnlQaWQocGlkKTtcbiAgICAgICAgfVxuICAgICAgICBpc1N0b3BwZWQgPSBhd2FpdCB0aGlzLmNoZWNrSXNBcHBpdW1TdG9wcGVkKHBhcmFtcy51cmwsIEFQUElVTV9FU0NBTEFURURfU1RPUF9USU1FT1VUX0lOX01JTExJU0VDT05EUyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5sb2coYnVpbGRUZWFyZG93bk1lc3NhZ2Uoe1xuICAgICAgZXZpZGVuY2U6IGBwb3J0ICR7U3RyaW5nKHBhcmFtcy5wb3J0KX1gLFxuICAgICAgb3V0Y29tZTogcmVzb2x2ZVRlYXJkb3duT3V0Y29tZSh7IGhhc0VzY2FsYXRlZCwgaXNTdG9wcGVkIH0pLFxuICAgICAgc3ViamVjdDogJ0F1dG8tc3RhcnRlZCBBcHBpdW0gc2VydmVyJyxcbiAgICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kczogQVBQSVVNX1NUT1BfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFNcbiAgICB9KSk7XG5cbiAgICBpZiAoaXNTdG9wcGVkKSB7XG4gICAgICAvLyBEcm9wIHRoZSBtYXJrZXIgd2l0aCB0aGUgc2VydmVyIGl0IGRlc2NyaWJlcywgc28gdGhlIG5leHQgcnVuIGNhbm5vdCBtaXN0YWtlIGEgcmVjeWNsZWQgUElEIGZvciBvdXJzLlxuICAgICAgY2xlYXJBcHBpdW1TZXJ2ZXJNYXJrZXIocGFyYW1zLnBvcnQpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIEtlZXAgdGhlIG1hcmtlciwgc3RhbXBlZDogYSBsZWZ0b3ZlciB3ZSBjb3VsZCBub3Qga2lsbCBtdXN0IHN0YXkgY29udmljdGFibGUgYnkgdGhlIG5leHQgcnVuLlxuICAgIHJlY29yZEFwcGl1bVNlcnZlclN0b3BBdHRlbXB0KHBhcmFtcy5wb3J0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9wcyB0aGUgZW11bGF0b3IgdGhpcyBydW4gc3RhcnRlZCwgYW5kICoqdmVyaWZpZXMqKiBpdCBzdG9wcGVkLlxuICAgKlxuICAgKiBUaGUgY29uc29sZSBzaHV0ZG93biBnb2VzIGZpcnN0IGJlY2F1c2UgaXQgaXMgdGhlIG9ubHkgcGF0aCB0aGF0IHJlbGVhc2VzXG4gICAqIHRoZSBBVkQncyBgbXVsdGlpbnN0YW5jZS5sb2NrYDsgYSBgdGFza2tpbGxgIGxlYXZlcyB0aGUgbG9jayBiZWhpbmQsIGFuZCBhXG4gICAqIHN0YWxlIGxvY2sgaXMgd2hhdCBtYWtlcyB0aGUgbmV4dCBydW4gZmFpbCB3aXRoIGBSdW5uaW5nIG11bHRpcGxlIGVtdWxhdG9yc1xuICAgKiB3aXRoIHRoZSBzYW1lIEFWRGAgXHUyMDE0IGEgRkFUQUwgdGhlIGVtdWxhdG9yIHdyaXRlcyB0byBpdHMgb3duIHN0ZG91dCwgd2hlcmVcbiAgICogbm9ib2R5IHNlZXMgaXQuXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgZW11bGF0b3IgcHJvY2VzcywgdGhlIGRldmljZSBpdCBzZXJ2ZXMgYW5kIHRoZSBQSURzIHRoaXMgcnVuIG93bnMuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHN0b3BBdXRvU3RhcnRlZEVtdWxhdG9yKHBhcmFtczogU3RvcEF1dG9TdGFydGVkRW11bGF0b3JQYXJhbXMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmtpbGxFbXVsYXRvckNvbnNvbGUocGFyYW1zLmRldmljZUlkKTtcbiAgICBraWxsUHJvY2Vzc1RyZWUocGFyYW1zLmVtdWxhdG9yUHJvY2Vzcyk7XG5cbiAgICBjb25zdCB3YWl0UGFyYW1zOiBXYWl0Rm9yRW11bGF0b3JTdG9wcGVkUGFyYW1zID0ge1xuICAgICAgZGV2aWNlSWQ6IHBhcmFtcy5kZXZpY2VJZCxcbiAgICAgIG93bmVkRW11bGF0b3JQaWRzOiBwYXJhbXMub3duZWRFbXVsYXRvclBpZHMsXG4gICAgICB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IEVNVUxBVE9SX1NUT1BfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFNcbiAgICB9O1xuXG4gICAgbGV0IGhhc0VzY2FsYXRlZCA9IGZhbHNlO1xuICAgIGxldCBpc1N0b3BwZWQgPSBhd2FpdCB0aGlzLndhaXRGb3JFbXVsYXRvclN0b3BwZWQod2FpdFBhcmFtcyk7XG5cbiAgICBpZiAoIWlzU3RvcHBlZCkge1xuICAgICAgY29uc3Qgc3Vydml2aW5nUGlkcyA9IHBhcmFtcy5vd25lZEVtdWxhdG9yUGlkcy5maWx0ZXIoKHBpZCkgPT4gY2hlY2tJc1Byb2Nlc3NBbGl2ZShwaWQpKTtcbiAgICAgIGlmIChzdXJ2aXZpbmdQaWRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgaGFzRXNjYWxhdGVkID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgYEF1dG8tc3RhcnRlZCBlbXVsYXRvciBvdXRsaXZlZCB0aGUgbGF1bmNoZXIncyBwcm9jZXNzIHRyZWU7IGVzY2FsYXRpbmcgdG8gdGhlIGJhY2tlbmQgUElEKHMpIHRoaXMgcnVuIHN0YXJ0ZWQ6IFske3N1cnZpdmluZ1BpZHMuam9pbignLCAnKX1dLmBcbiAgICAgICAgKTtcbiAgICAgICAgZm9yIChjb25zdCBwaWQgb2Ygc3Vydml2aW5nUGlkcykge1xuICAgICAgICAgIGtpbGxQcm9jZXNzVHJlZUJ5UGlkKHBpZCk7XG4gICAgICAgIH1cbiAgICAgICAgaXNTdG9wcGVkID0gYXdhaXQgdGhpcy53YWl0Rm9yRW11bGF0b3JTdG9wcGVkKHsgLi4ud2FpdFBhcmFtcywgdGltZW91dEluTWlsbGlzZWNvbmRzOiBFTVVMQVRPUl9FU0NBTEFURURfU1RPUF9USU1FT1VUX0lOX01JTExJU0VDT05EUyB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmxvZyhidWlsZFRlYXJkb3duTWVzc2FnZSh7XG4gICAgICBldmlkZW5jZTogYEFWRCBcIiR7cGFyYW1zLmF2ZE5hbWV9XCIgb24gZGV2aWNlICR7cGFyYW1zLmRldmljZUlkfWAsXG4gICAgICBvdXRjb21lOiByZXNvbHZlVGVhcmRvd25PdXRjb21lKHsgaGFzRXNjYWxhdGVkLCBpc1N0b3BwZWQgfSksXG4gICAgICBzdWJqZWN0OiAnQXV0by1zdGFydGVkIGVtdWxhdG9yJyxcbiAgICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kczogRU1VTEFUT1JfU1RPUF9USU1FT1VUX0lOX01JTExJU0VDT05EU1xuICAgIH0pKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCZXN0LWVmZm9ydCB0ZWFyZG93biBmb3IgYHByb2Nlc3Mub24oJ2V4aXQnKWAsIHdoaWNoIGNhbm5vdCBhd2FpdC5cbiAgICpcbiAgICogSXQga2lsbHMsIGxvb2tzIG9uY2UgZm9yIGEgc3Vydml2b3Igc3RpbGwgaG9sZGluZyB0aGUgQXBwaXVtIHBvcnQgb3IgYVxuICAgKiBzdGlsbC1saXZlIGVtdWxhdG9yIFBJRCwga2lsbHMgdGhvc2UgdG9vIFx1MjAxNCBhbmQgdGhlbiBzYXlzIGV4YWN0bHkgdGhhdC4gSXRcbiAgICogbmV2ZXIgY2xhaW1zIGEgdmVyaWZpZWQgc3RvcCwgYmVjYXVzZSBpdCBjYW5ub3Qgd2FpdCB0byBlYXJuIG9uZS5cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtcyAtIEV2ZXJ5dGhpbmcgdGhpcyBydW4gc3RhcnRlZC5cbiAgICovXG4gIHByaXZhdGUgc3RvcEF1dG9TdGFydGVkUHJvY2Vzc2VzQmVzdEVmZm9ydChwYXJhbXM6IFN0b3BBdXRvU3RhcnRlZFByb2Nlc3Nlc1BhcmFtcyk6IHZvaWQge1xuICAgIGlmIChwYXJhbXMuYXBwaXVtUHJvY2Vzcykge1xuICAgICAga2lsbFByb2Nlc3NUcmVlKHBhcmFtcy5hcHBpdW1Qcm9jZXNzKTtcbiAgICAgIGNvbnN0IG93bmVyUGlkcyA9IHRoaXMubGlzdFBvcnRPd25lclBpZHNTeW5jKHBhcmFtcy5wb3J0KTtcbiAgICAgIGZvciAoY29uc3QgcGlkIG9mIG93bmVyUGlkcykge1xuICAgICAgICBraWxsUHJvY2Vzc1RyZWVCeVBpZChwaWQpO1xuICAgICAgfVxuXG4gICAgICBpZiAob3duZXJQaWRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgYEF1dG8tc3RhcnRlZCBBcHBpdW0gc2VydmVyOiBzdG9wIHJlcXVlc3RlZCBhbmQgUElEKHMpIFske293bmVyUGlkcy5qb2luKCcsICcpfV0gaG9sZGluZyBwb3J0ICR7U3RyaW5nKHBhcmFtcy5wb3J0KX0ga2lsbGVkIFx1MjAxNCBzeW5jIHRlYXJkb3duIGNhbm5vdCB3YWl0IHRvIGNvbmZpcm0uYFxuICAgICAgICApO1xuICAgICAgICByZWNvcmRBcHBpdW1TZXJ2ZXJTdG9wQXR0ZW1wdChwYXJhbXMucG9ydCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmxvZyhgQXV0by1zdGFydGVkIEFwcGl1bSBzZXJ2ZXI6IHN0b3AgcmVxdWVzdGVkLCBub3RoaW5nIGxlZnQgbGlzdGVuaW5nIG9uIHBvcnQgJHtTdHJpbmcocGFyYW1zLnBvcnQpfS5gKTtcbiAgICAgICAgY2xlYXJBcHBpdW1TZXJ2ZXJNYXJrZXIocGFyYW1zLnBvcnQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChwYXJhbXMuZW11bGF0b3JQcm9jZXNzKSB7XG4gICAgICBraWxsUHJvY2Vzc1RyZWUocGFyYW1zLmVtdWxhdG9yUHJvY2Vzcyk7XG4gICAgICBjb25zdCBzdXJ2aXZpbmdQaWRzID0gcGFyYW1zLm93bmVkRW11bGF0b3JQaWRzLmZpbHRlcigocGlkKSA9PiBjaGVja0lzUHJvY2Vzc0FsaXZlKHBpZCkpO1xuICAgICAgZm9yIChjb25zdCBwaWQgb2Ygc3Vydml2aW5nUGlkcykge1xuICAgICAgICBraWxsUHJvY2Vzc1RyZWVCeVBpZChwaWQpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmxvZyhcbiAgICAgICAgc3Vydml2aW5nUGlkcy5sZW5ndGggPiAwXG4gICAgICAgICAgPyBgQXV0by1zdGFydGVkIGVtdWxhdG9yOiBzdG9wIHJlcXVlc3RlZCBhbmQgc3Vydml2aW5nIGJhY2tlbmQgUElEKHMpIFske3N1cnZpdmluZ1BpZHMuam9pbignLCAnKX1dIGtpbGxlZCBcdTIwMTQgc3luYyB0ZWFyZG93biBjYW5ub3Qgd2FpdCB0byBjb25maXJtLmBcbiAgICAgICAgICA6ICdBdXRvLXN0YXJ0ZWQgZW11bGF0b3I6IHN0b3AgcmVxdWVzdGVkLCBubyBwcm9jZXNzIG9mIHRoaXMgcnVuIGxlZnQgcnVubmluZy4nXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9wcyBldmVyeXRoaW5nIHRoaXMgcnVuIGF1dG8tc3RhcnRlZCwgdmVyaWZ5aW5nIGVhY2ggc3RvcC5cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtcyAtIEV2ZXJ5dGhpbmcgdGhpcyBydW4gc3RhcnRlZC5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc3RvcEF1dG9TdGFydGVkUHJvY2Vzc2VzVmVyaWZpZWQocGFyYW1zOiBTdG9wQXV0b1N0YXJ0ZWRQcm9jZXNzZXNQYXJhbXMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXBhcmFtcy5hcHBpdW1Qcm9jZXNzICYmICFwYXJhbXMuZW11bGF0b3JQcm9jZXNzKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5sb2coJ1N0b3BwaW5nIGV2ZXJ5dGhpbmcgdGhpcyBydW4gYXV0by1zdGFydGVkLi4uJyk7XG5cbiAgICBpZiAocGFyYW1zLmFwcGl1bVByb2Nlc3MpIHtcbiAgICAgIGF3YWl0IHRoaXMuc3RvcEF1dG9TdGFydGVkQXBwaXVtU2VydmVyKHtcbiAgICAgICAgYXBwaXVtUHJvY2VzczogcGFyYW1zLmFwcGl1bVByb2Nlc3MsXG4gICAgICAgIHBvcnQ6IHBhcmFtcy5wb3J0LFxuICAgICAgICB1cmw6IHBhcmFtcy51cmxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMuZW11bGF0b3JQcm9jZXNzICYmIHBhcmFtcy5kZXZpY2VJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBhd2FpdCB0aGlzLnN0b3BBdXRvU3RhcnRlZEVtdWxhdG9yKHtcbiAgICAgICAgYXZkTmFtZTogcGFyYW1zLmF2ZE5hbWUsXG4gICAgICAgIGRldmljZUlkOiBwYXJhbXMuZGV2aWNlSWQsXG4gICAgICAgIGVtdWxhdG9yUHJvY2VzczogcGFyYW1zLmVtdWxhdG9yUHJvY2VzcyxcbiAgICAgICAgb3duZWRFbXVsYXRvclBpZHM6IHBhcmFtcy5vd25lZEVtdWxhdG9yUGlkc1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzdXBwcmVzc0Vycm9yRGlhbG9ncyhkZXZpY2VJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5sb2coYERpc2FibGluZyBjcmFzaC9BTlIgZGlhbG9ncyBvbiBkZXZpY2UgJHtkZXZpY2VJZH0gKHNldHRpbmdzIHB1dCBnbG9iYWwgaGlkZV9lcnJvcl9kaWFsb2dzIDEpLi4uYCk7XG5cbiAgICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgICAgZXhlY0ZpbGUoXG4gICAgICAgICdhZGInLFxuICAgICAgICBbJy1zJywgZGV2aWNlSWQsICdzaGVsbCcsICdzZXR0aW5ncycsICdwdXQnLCAnZ2xvYmFsJywgJ2hpZGVfZXJyb3JfZGlhbG9ncycsICcxJ10sXG4gICAgICAgIHsgdGltZW91dDogQURCX0RFVklDRV9DSEVDS19USU1FT1VUX0lOX01JTExJU0VDT05EUyB9LFxuICAgICAgICAoZXJyb3IpID0+IHtcbiAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgIHRoaXMubG9nKFxuICAgICAgICAgICAgICBgV2FybmluZzogZmFpbGVkIHRvIGRpc2FibGUgY3Jhc2gvQU5SIGRpYWxvZ3M6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAndW5rbm93biBlcnJvcid9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyB0aGUgYHRlbXAtdmF1bHQtKmAgZGlyZWN0b3JpZXMgZWFybGllciBydW5zIGxlZnQgb24gdGhlIGRldmljZS5cbiAgICpcbiAgICogUnVucyAqKmJlZm9yZSoqIGByZW1vdGUoKWAgbGF1bmNoZXMgT2JzaWRpYW4gXHUyMDE0IHRoZSBsYXN0IG1vbWVudCBhdCB3aGljaFxuICAgKiBub3RoaW5nIGhhcyB0byBlbnVtZXJhdGUgdGhlIGRldmljZSdzIHZhdWx0cyB5ZXQsIGFuZCB0aGUgb25seSBzd2VlcCB0aGF0XG4gICAqIGRvZXMgbm90IGRlcGVuZCBvbiBhIGhlYWx0aHkgV2ViVmlldy4gVGhhdCBpbmRlcGVuZGVuY2UgaXMgdGhlIHdob2xlIHBvaW50OlxuICAgKiBhIHJ1biB3aG9zZSBXZWJWaWV3IGRpZWQgY2Fubm90IHVucmVnaXN0ZXIgb3IgZGVsZXRlIGl0cyBvd24gdmF1bHQsIHNvXG4gICAqIHdpdGhvdXQgdGhpcyBlYWNoIGZhaWx1cmUgbGVhdmVzIHJlc2lkdWUgdGhhdCBzbG93cyB0aGUgbmV4dCBydW4ncyBzdGFydHVwXG4gICAqIGVudW1lcmF0aW9uIGFuZCBtYWtlcyB0aGUgbmV4dCBmYWlsdXJlIGxpa2VsaWVyLlxuICAgKlxuICAgKiBVbmNvbmRpdGlvbmFsIChubyBhZ2UgZ2F0ZSkgXHUyMDE0IEFuZHJvaWQgcnVucyBob2xkIHRoZSBleGNsdXNpdmUgYGFuZHJvaWRgXG4gICAqIHNldHVwIGxvY2ssIHNvIG5vIGNvbmN1cnJlbnQgcnVuIGNhbiBvd24gYSBkZXZpY2UgdmF1bHQsIGFuZCBhbiBhZ2UgZ2F0ZVxuICAgKiB3b3VsZCBsZXQgYSB2YXVsdCBsZWFrZWQgbWludXRlcyBhZ28gc3Vydml2ZSBpbnRvIHRoaXMgcnVuLiBCZXN0LWVmZm9ydDogYVxuICAgKiBmYWlsdXJlIGlzIGxvZ2dlZCwgbm90IHRocm93bi5cbiAgICpcbiAgICogVGhlIHJlbW92YWxzIGdvIG9uZSBkaXJlY3RvcnkgYXQgYSB0aW1lIGFuZCB0aGUgb3V0Y29tZSBpcyByZS1saXN0ZWQgcmF0aGVyXG4gICAqIHRoYW4gaW5mZXJyZWQ7IHtAbGluayBzd2VlcERldmljZUxlZnRvdmVyc30gZXhwbGFpbnMgd2h5LlxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zIC0gVGhlIGRldmljZSBhbmQgdmF1bHQgYmFzZSBwYXRoIHRvIHN3ZWVwLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzd2VlcERldmljZUxlZnRvdmVyVmF1bHRzKHBhcmFtczogU3dlZXBEZXZpY2VMZWZ0b3ZlclZhdWx0c1BhcmFtcyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgZGV2aWNlSWQsIHZhdWx0QmFzZVBhdGggfSA9IHBhcmFtcztcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBzd2VlcERldmljZUxlZnRvdmVycyh7XG4gICAgICAgIGxpc3ROYW1lczogYXN5bmMgKCk6IFByb21pc2U8c3RyaW5nW10+ID0+IHtcbiAgICAgICAgICBjb25zdCBsaXN0aW5nID0gYXdhaXQgZXhlYyhcbiAgICAgICAgICAgIFsnYWRiJywgJy1zJywgZGV2aWNlSWQsICdzaGVsbCcsICdscycsICctMScsIHZhdWx0QmFzZVBhdGhdLFxuICAgICAgICAgICAgeyBpc1F1aWV0OiB0cnVlLCBzaG91bGRJZ25vcmVFeGl0Q29kZTogdHJ1ZSwgdGltZW91dEluTWlsbGlzZWNvbmRzOiBBREJfVkFVTFRfU1dFRVBfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIGxpc3Rpbmcuc3BsaXQoJ1xcbicpO1xuICAgICAgICB9LFxuICAgICAgICByZW1vdmVEaXJlY3Rvcnk6IGFzeW5jIChwYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgICBhd2FpdCBleGVjKFxuICAgICAgICAgICAgWydhZGInLCAnLXMnLCBkZXZpY2VJZCwgJ3NoZWxsJywgJ3JtJywgJy1yZicsIHBhdGhdLFxuICAgICAgICAgICAgeyBpc1F1aWV0OiB0cnVlLCBzaG91bGRJZ25vcmVFeGl0Q29kZTogdHJ1ZSwgdGltZW91dEluTWlsbGlzZWNvbmRzOiBBREJfVkFVTFRfU1dFRVBfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgfVxuICAgICAgICAgICk7XG4gICAgICAgIH0sXG4gICAgICAgIHZhdWx0QmFzZVBhdGhcbiAgICAgIH0pO1xuXG4gICAgICBpZiAocmVzdWx0LnJlbW92ZWRDb3VudCA9PT0gMCAmJiByZXN1bHQuZmFpbGVkTmFtZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRoaXMubG9nKGBObyBsZWZ0b3ZlciB0ZW1wIHZhdWx0cyBvbiBkZXZpY2UgJHtkZXZpY2VJZH0uYCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5sb2coYFJlbW92ZWQgJHtTdHJpbmcocmVzdWx0LnJlbW92ZWRDb3VudCl9IGxlZnRvdmVyIHRlbXAgdmF1bHQocykgZnJvbSAke3ZhdWx0QmFzZVBhdGh9IG9uIGRldmljZSAke2RldmljZUlkfS5gKTtcblxuICAgICAgaWYgKHJlc3VsdC5mYWlsZWROYW1lcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMubG9nKFxuICAgICAgICAgIGBXYXJuaW5nOiAke1N0cmluZyhyZXN1bHQuZmFpbGVkTmFtZXMubGVuZ3RoKX0gbGVmdG92ZXIgdGVtcCB2YXVsdChzKSBjb3VsZCBub3QgYmUgcmVtb3ZlZCBhbmQgd2lsbCBiZSByZXRyaWVkIG5leHQgcnVuOiAke3Jlc3VsdC5mYWlsZWROYW1lcy5qb2luKCcsICcpfWBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgdGhpcy5sb2coYFdhcm5pbmc6IGZhaWxlZCB0byBzd2VlcCBsZWZ0b3ZlciB0ZW1wIHZhdWx0czogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6ICd1bmtub3duIGVycm9yJ31gKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHdhaXRGb3JBcHBpdW1SZWFkeSh1cmw6IFVSTCwgdGltZW91dEluTWlsbGlzZWNvbmRzOiBudW1iZXIsIGxhdW5jaDogUHJvY2Vzc0xhdW5jaCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHN0YXJ0ID0gRGF0ZS5ub3coKTtcbiAgICB0aGlzLmxvZyhcbiAgICAgIGBXYWl0aW5nIGZvciBBcHBpdW0gYXQgJHt1cmwuaHJlZn0gKHRpbWVvdXQ6ICR7U3RyaW5nKHRpbWVvdXRJbk1pbGxpc2Vjb25kcyl9bXMsIHBvbGw6ICR7U3RyaW5nKEFQUElVTV9TVEFSVF9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyl9bXMpLi4uYFxuICAgICk7XG4gICAgY29uc3QgZGVhZGxpbmUgPSBzdGFydCArIHRpbWVvdXRJbk1pbGxpc2Vjb25kcztcblxuICAgIHdoaWxlIChEYXRlLm5vdygpIDwgZGVhZGxpbmUpIHtcbiAgICAgIC8qXG4gICAgICAgKiBJZiB0aGUgc2VydmVyIHByb2Nlc3MgYWxyZWFkeSBkaWVkIChjcmFzaGVkLCBvciBuZXZlciBzdGFydGVkKSwgc3RvcFxuICAgICAgICogcG9sbGluZyBhbmQgc3VyZmFjZSB3aHkgXHUyMDE0IG90aGVyd2lzZSBhIGRvb21lZCBzZXJ2ZXIgc3BpbnMgb3V0IHRoZSB3aG9sZVxuICAgICAgICogcmVhZGluZXNzIHRpbWVvdXQgd2l0aCBubyBkaWFnbm9zdGljcywgdGhlIG9yaWdpbmFsIHN5bXB0b20gdGhpcyBleGlzdHNcbiAgICAgICAqIHRvIHByZXZlbnQuXG4gICAgICAgKi9cbiAgICAgIGNvbnN0IGV4aXRJbmZvID0gbGF1bmNoLnJlYWRFeGl0SW5mbygpO1xuICAgICAgaWYgKGV4aXRJbmZvKSB7XG4gICAgICAgIHRocm93IGJ1aWxkRGVhdGhFcnJvcihleGl0SW5mbyk7XG4gICAgICB9XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuY2hlY2tBcHBpdW1SZWFjaGFibGUodXJsKTtcbiAgICAgICAgbGF1bmNoLnN0b3BDYXB0dXJlKCk7XG4gICAgICAgIHRoaXMubG9nKGBBcHBpdW0gc2VydmVyIHJlYWR5IGFmdGVyICR7U3RyaW5nKERhdGUubm93KCkgLSBzdGFydCl9bXMuYCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICB0aGlzLmxvZyhgQXBwaXVtIHNlcnZlciBub3QgcmVhZHkgeWV0IChlbGFwc2VkOiAke1N0cmluZyhEYXRlLm5vdygpIC0gc3RhcnQpfW1zKS4gUmV0cnlpbmcuLi5gKTtcbiAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIEFQUElVTV9TVEFSVF9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGZpbmFsRXhpdEluZm8gPSBsYXVuY2gucmVhZEV4aXRJbmZvKCk7XG4gICAgaWYgKGZpbmFsRXhpdEluZm8pIHtcbiAgICAgIHRocm93IGJ1aWxkRGVhdGhFcnJvcihmaW5hbEV4aXRJbmZvKTtcbiAgICB9XG5cbiAgICBjb25zdCBvdXRwdXRUYWlsID0gbGF1bmNoLnJlYWRPdXRwdXQoKS50cmltKCk7XG4gICAgY29uc3Qgb3V0cHV0U2VjdGlvbiA9IG91dHB1dFRhaWwubGVuZ3RoID4gMCA/IGBcXG5cXG5BcHBpdW0gc2VydmVyIG91dHB1dCAodGFpbCk6XFxuJHtvdXRwdXRUYWlsfWAgOiAnJztcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEF1dG8tc3RhcnRlZCBBcHBpdW0gc2VydmVyIGRpZCBub3QgYmVjb21lIHJlYWR5IHdpdGhpbiAke1N0cmluZyh0aW1lb3V0SW5NaWxsaXNlY29uZHMpfW1zLiR7b3V0cHV0U2VjdGlvbn1gKTtcblxuICAgIGZ1bmN0aW9uIGJ1aWxkRGVhdGhFcnJvcihleGl0SW5mbzogUHJvY2Vzc0V4aXRJbmZvKTogRXJyb3Ige1xuICAgICAgcmV0dXJuIG5ldyBFcnJvcihidWlsZFByb2Nlc3NFeGl0TWVzc2FnZSh7XG4gICAgICAgIGV4aXRJbmZvLFxuICAgICAgICBvdXRwdXQ6IGxhdW5jaC5yZWFkT3V0cHV0KCksXG4gICAgICAgIG91dHB1dExhYmVsOiAnQXBwaXVtIHNlcnZlciBvdXRwdXQnLFxuICAgICAgICBzdWJqZWN0OiAnQXV0by1zdGFydGVkIEFwcGl1bSBzZXJ2ZXInXG4gICAgICB9KSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFdhaXRzIHVudGlsIG5vdGhpbmcgYW5zd2VycyBgL3N0YXR1c2Agb24gdGhlIHBvcnQgYW55IG1vcmUuXG4gICAqXG4gICAqIEBwYXJhbSB1cmwgLSBUaGUgQXBwaXVtIHNlcnZlciBVUkwuXG4gICAqIEBwYXJhbSB0aW1lb3V0SW5NaWxsaXNlY29uZHMgLSBIb3cgbG9uZyB0byB3YWl0IGJlZm9yZSBnaXZpbmcgdXAuXG4gICAqIEB0aHJvd3MgSWYgdGhlIHBvcnQgaXMgc3RpbGwgc2VydmVkIHdoZW4gdGhlIHRpbWVvdXQgZWxhcHNlcy5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgd2FpdEZvckFwcGl1bVN0b3BwZWQodXJsOiBVUkwsIHRpbWVvdXRJbk1pbGxpc2Vjb25kczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZGVhZGxpbmUgPSBEYXRlLm5vdygpICsgdGltZW91dEluTWlsbGlzZWNvbmRzO1xuXG4gICAgd2hpbGUgKERhdGUubm93KCkgPCBkZWFkbGluZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5jaGVja0FwcGl1bVJlYWNoYWJsZSh1cmwpO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBBUFBJVU1fU1RBUlRfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYFNvbWV0aGluZyBpcyBzdGlsbCBzZXJ2aW5nICR7dXJsLm9yaWdpbn0gJHtTdHJpbmcodGltZW91dEluTWlsbGlzZWNvbmRzKX1tcyBhZnRlciB0aGUgQXBwaXVtIHNlcnZlciB3YXMga2lsbGVkLmBcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFBvbGxzIGBzeXMuYm9vdF9jb21wbGV0ZWRgIHVudGlsIHRoZSBkZXZpY2UgcmVwb3J0cyBhIGZpbmlzaGVkIGJvb3QuXG4gICAqXG4gICAqIEBwYXJhbSBkZXZpY2VJZCAtIFRoZSBkZXZpY2UgVURJRCB0byBwb2xsLlxuICAgKiBAcGFyYW0gZGVhZGxpbmUgLSBUaGUgYWJzb2x1dGUgdGltZSBhdCB3aGljaCB0byBnaXZlIHVwLlxuICAgKiBAcGFyYW0gZW11bGF0b3IgLSBUaGUgZW11bGF0b3IgdGhpcyBydW4gc3RhcnRlZCwgc28gaXRzIGVhcmx5IGRlYXRoIGZhaWxzIGZhc3QgaW5zdGVhZCBvZiBwb2xsaW5nIG91dCB0aGUgZGVhZGxpbmUuIE9taXR0ZWQgZm9yIGEgcmV1c2VkIGRldmljZSwgd2hpY2ggdGhpcyBydW4gZGlkIG5vdCBsYXVuY2ggYW5kIGNhbm5vdCBpbnNwZWN0LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB3YWl0Rm9yQm9vdChkZXZpY2VJZDogc3RyaW5nLCBkZWFkbGluZTogbnVtYmVyLCBlbXVsYXRvcjogUHJvY2Vzc0xhdW5jaCB8IHVuZGVmaW5lZCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHJlbWFpbmluZ01zID0gTWF0aC5tYXgoMCwgZGVhZGxpbmUgLSBEYXRlLm5vdygpKTtcbiAgICB0aGlzLmxvZyhcbiAgICAgIGBXYWl0aW5nIGZvciBkZXZpY2UgJHtkZXZpY2VJZH0gdG8gZmluaXNoIGJvb3RpbmcgKHJlbWFpbmluZzogJHtTdHJpbmcocmVtYWluaW5nTXMpfW1zLCBwb2xsOiAke1N0cmluZyhFTVVMQVRPUl9CT09UX1BPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTKX1tcykuLi5gXG4gICAgKTtcblxuICAgIHdoaWxlIChEYXRlLm5vdygpIDwgZGVhZGxpbmUpIHtcbiAgICAgIGNvbnN0IGlzQm9vdGVkID0gYXdhaXQgbmV3IFByb21pc2U8Ym9vbGVhbj4oKHJlc29sdmUpID0+IHtcbiAgICAgICAgZXhlY0ZpbGUoXG4gICAgICAgICAgJ2FkYicsXG4gICAgICAgICAgWyctcycsIGRldmljZUlkLCAnc2hlbGwnLCAnZ2V0cHJvcCcsICdzeXMuYm9vdF9jb21wbGV0ZWQnXSxcbiAgICAgICAgICB7IHRpbWVvdXQ6IEFEQl9ERVZJQ0VfQ0hFQ0tfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFMgfSxcbiAgICAgICAgICAoX2Vycm9yLCBzdGRvdXQpID0+IHtcbiAgICAgICAgICAgIHJlc29sdmUoc3Rkb3V0LnRyaW0oKSA9PT0gJzEnKTtcbiAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKGlzQm9vdGVkKSB7XG4gICAgICAgIHRoaXMubG9nKGBEZXZpY2UgJHtkZXZpY2VJZH0gYm9vdCBjb21wbGV0ZWQuYCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZXhpdEluZm8gPSBlbXVsYXRvcj8ucmVhZEV4aXRJbmZvKCk7XG4gICAgICBpZiAoZXhpdEluZm8pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGJ1aWxkUHJvY2Vzc0V4aXRNZXNzYWdlKHtcbiAgICAgICAgICBleGl0SW5mbyxcbiAgICAgICAgICBvdXRwdXQ6IGVtdWxhdG9yPy5yZWFkT3V0cHV0KCkgPz8gJycsXG4gICAgICAgICAgb3V0cHV0TGFiZWw6ICdFbXVsYXRvciBvdXRwdXQnLFxuICAgICAgICAgIHN1YmplY3Q6ICdBbmRyb2lkIGVtdWxhdG9yJ1xuICAgICAgICB9KSk7XG4gICAgICB9XG5cbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgRU1VTEFUT1JfQk9PVF9QT0xMX0lOVEVSVkFMX0lOX01JTExJU0VDT05EUyk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvKlxuICAgICAqIFRoZSB0YWlsIGdvZXMgb24gdGhlIFRJTUVPVVQgdG9vLCBub3Qgb25seSBvbiB0aGUgZXhpdC4gQW4gZW11bGF0b3IgdGhhdFxuICAgICAqIHByaW50cyBgRkFUQUwgfCBSdW5uaW5nIG11bHRpcGxlIGVtdWxhdG9ycyB3aXRoIHRoZSBzYW1lIEFWRGAgYW5kIHRoZW5cbiAgICAgKiBsaW5nZXJzIG5ldmVyIHNldHMgYGV4aXRJbmZvYCwgc28gdGhpcyB1c2VkIHRvIGJlIHRoZSB3aG9sZSBvZiB3aGF0IHRoZVxuICAgICAqIHJlYWRlciBnb3QgXHUyMDE0IGEgYnVkZ2V0LCB3aXRoIHRoZSBleHBsYW5hdGlvbiBjYXB0dXJlZCBhbmQgZGlzY2FyZGVkLlxuICAgICAqL1xuICAgIHRocm93IG5ldyBFcnJvcihhcHBlbmRQcm9jZXNzT3V0cHV0VGFpbChcbiAgICAgIGBEZXZpY2UgXCIke2RldmljZUlkfVwiIGNvbm5lY3RlZCBidXQgZGlkIG5vdCBmaW5pc2ggYm9vdGluZyB3aXRoaW4gJHtTdHJpbmcoRU1VTEFUT1JfQk9PVF9USU1FT1VUX0lOX01JTExJU0VDT05EUyl9bXMuYCxcbiAgICAgIHsgb3V0cHV0OiBlbXVsYXRvcj8ucmVhZE91dHB1dCgpID8/ICcnLCBvdXRwdXRMYWJlbDogJ0VtdWxhdG9yIG91dHB1dCcgfVxuICAgICkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFdhaXRzIGZvciBhIGJvb3RlZCBlbXVsYXRvciB0byBiZWNvbWUgaWRsZSBiZWZvcmUgdGhlIHNlc3Npb24gaXNcbiAgICogZXN0YWJsaXNoZWQgXHUyMDE0IHdoZXRoZXIgdGhpcyBydW4gc3RhcnRlZCBpdCBvciBmb3VuZCBpdCBhbHJlYWR5IHJ1bm5pbmcuXG4gICAqXG4gICAqIGBzeXMuYm9vdF9jb21wbGV0ZWRgIGZpcmVzIGJlZm9yZSB0aGUgZ3Vlc3QgaXMgYWN0dWFsbHkgaWRsZSBcdTIwMTQgcGFja2FnZVxuICAgKiBvcHRpbWl6YXRpb24gYW5kIHNlcnZpY2VzIGtlZXAgY2h1cm5pbmcgXHUyMDE0IHNvIGVzdGFibGlzaGluZyB0aGUgQXBwaXVtXG4gICAqIHNlc3Npb24gaW1tZWRpYXRlbHkgbWFrZXMgZXZlcnkgc2VyaWFsaXplZCBVaUF1dG9tYXRvcjIgYGFkYmAgcm91bmQtdHJpcFxuICAgKiBjb250ZW5kIHdpdGggdGhhdCB3b3JrIGFuZCBpbmZsYXRlcyBzZXNzaW9uIGVzdGFibGlzaG1lbnQgfjN4LiBUaGlzIHBvbGxzXG4gICAqIGEgbGF0ZXIsIHF1aWV0ZXIgc2lnbmFsIChib290IGFuaW1hdGlvbiBzdG9wcGVkICsgcGFja2FnZSBtYW5hZ2VyIHNlcnZpbmcsXG4gICAqIHZpYSB7QGxpbmsgY2hlY2tEZXZpY2VJZGxlfSkgYW5kIHJldHVybnMgYXMgc29vbiBhcyBpdCBpcyBzYXRpc2ZpZWQuXG4gICAqXG4gICAqIEEgKipyZXVzZWQqKiBkZXZpY2UgbmVlZHMgdGhpcyBldmVyeSBiaXQgYXMgbXVjaCBhcyBhIHN0YXJ0ZWQgb25lOiBiZWluZ1xuICAgKiBsaXN0ZWQgaW4gYGFkYiBkZXZpY2VzYCBzYXlzIG9ubHkgdGhhdCBhZGJkIGFuc3dlcnMsIGFuZCB0aGUgY2h1cm4gaXQgZG9lc1xuICAgKiBub3QgZ2F0ZSBpcyBwYWlkIGxhdGVyIGJ5IHdoYXRldmVyIHBvbGxzIHRoZSBXZWJWaWV3LlxuICAgKlxuICAgKiBCZXN0LWVmZm9ydDogaWYgdGhlIGd1ZXN0IGRvZXMgbm90IHJlcG9ydCBpZGxlIHdpdGhpbiB0aGUgYnVkZ2V0IGl0IGxvZ3MgYVxuICAgKiB3YXJuaW5nIGFuZCBwcm9jZWVkcyAoYSBzbG93IHNlc3Npb24gaXMgYmV0dGVyIHRoYW4gYSBmYWlsZWQgcnVuKSwgYW5kIGFcbiAgICogYnVkZ2V0IG9mIGAwYCBza2lwcyB0aGUgd2FpdCBlbnRpcmVseS5cbiAgICpcbiAgICogQHBhcmFtIGRldmljZUlkIC0gVGhlIGRldmljZSBVRElEIHRvIHBvbGwuXG4gICAqIEBwYXJhbSB0aW1lb3V0SW5NaWxsaXNlY29uZHMgLSBNYXhpbXVtIHRpbWUgdG8gd2FpdDsgYDBgIHNraXBzIHRoZSB3YWl0LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB3YWl0Rm9yRGV2aWNlSWRsZShkZXZpY2VJZDogc3RyaW5nLCB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aW1lb3V0SW5NaWxsaXNlY29uZHMgPD0gMCkge1xuICAgICAgdGhpcy5sb2coYFNraXBwaW5nIHBvc3QtYm9vdCBpZGxlIHdhaXQgZm9yIGRldmljZSAke2RldmljZUlkfSAodGltZW91dCBpcyAwKS5gKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzdGFydCA9IERhdGUubm93KCk7XG4gICAgY29uc3QgZGVhZGxpbmUgPSBzdGFydCArIHRpbWVvdXRJbk1pbGxpc2Vjb25kcztcbiAgICB0aGlzLmxvZyhcbiAgICAgIGBXYWl0aW5nIGZvciBkZXZpY2UgJHtkZXZpY2VJZH0gdG8gYmVjb21lIGlkbGUgKHRpbWVvdXQ6ICR7U3RyaW5nKHRpbWVvdXRJbk1pbGxpc2Vjb25kcyl9bXMsIHBvbGw6ICR7U3RyaW5nKERFVklDRV9JRExFX1BPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTKX1tcykuLi5gXG4gICAgKTtcblxuICAgIHdoaWxlIChEYXRlLm5vdygpIDwgZGVhZGxpbmUpIHtcbiAgICAgIGNvbnN0IFtib290QW5pbWF0aW9uUHJvcGVydHksIHBhY2thZ2VMaXN0T3V0cHV0XSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgdGhpcy5nZXREZXZpY2VQcm9wZXJ0eShkZXZpY2VJZCwgJ2luaXQuc3ZjLmJvb3RhbmltJyksXG4gICAgICAgIHRoaXMubGlzdEluc3RhbGxlZFBhY2thZ2VzKGRldmljZUlkKVxuICAgICAgXSk7XG5cbiAgICAgIGlmIChjaGVja0RldmljZUlkbGUoeyBib290QW5pbWF0aW9uUHJvcGVydHksIHBhY2thZ2VMaXN0T3V0cHV0IH0pKSB7XG4gICAgICAgIHRoaXMubG9nKGBEZXZpY2UgJHtkZXZpY2VJZH0gaXMgaWRsZSBhZnRlciAke1N0cmluZyhEYXRlLm5vdygpIC0gc3RhcnQpfW1zLmApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMubG9nKGBEZXZpY2UgJHtkZXZpY2VJZH0gbm90IGlkbGUgeWV0IChlbGFwc2VkOiAke1N0cmluZyhEYXRlLm5vdygpIC0gc3RhcnQpfW1zKS4gUmV0cnlpbmcuLi5gKTtcbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgREVWSUNFX0lETEVfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdGhpcy5sb2coXG4gICAgICBgV2FybmluZzogZGV2aWNlICR7ZGV2aWNlSWR9IGRpZCBub3QgcmVwb3J0IGlkbGUgd2l0aGluICR7U3RyaW5nKHRpbWVvdXRJbk1pbGxpc2Vjb25kcyl9bXM7IHByb2NlZWRpbmcgd2l0aCBzZXNzaW9uIGVzdGFibGlzaG1lbnQgYW55d2F5LmBcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgYm90aCBwb3N0LWJvb3QgcmVhZGluZXNzIGdhdGVzLCBpbiBvcmRlciwgb24gYSBkZXZpY2UgdGhhdCBoYXMganVzdFxuICAgKiByZXBvcnRlZCBgc3lzLmJvb3RfY29tcGxldGVkYC5cbiAgICpcbiAgICogVGhlIHNpbmdsZSBvd25lciBvZiBcIndoaWNoIGdhdGVzIGEgZGV2aWNlIHBhc3NlcyBiZWZvcmUgYSBzZXNzaW9uXCIsIHNvIHRoZVxuICAgKiBzdGFydGVkLWRldmljZSBhbmQgcmV1c2VkLWRldmljZSBicmFuY2hlcyBjYW5ub3QgZGl2ZXJnZSBvbiBpdCBcdTIwMTQgdGhlIGJyYW5jaFxuICAgKiB0aGF0IHNraXBwZWQgYSBnYXRlIGVudGlyZWx5IGlzIHRoZSBob2xlIGEgcmV1c2VkIGRldmljZSBvbmNlIGZlbGwgaW50byAoKipMNDMqKikuXG4gICAqXG4gICAqIEBwYXJhbSBkZXZpY2VJZCAtIFRoZSBkZXZpY2UgVURJRCB0byBnYXRlIG9uLlxuICAgKiBAcGFyYW0gdGltZW91dHMgLSBUaGUgdHdvIHJlc29sdmVkIGJ1ZGdldHMuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHdhaXRGb3JEZXZpY2VSZWFkeShkZXZpY2VJZDogc3RyaW5nLCB0aW1lb3V0czogRGV2aWNlUmVhZGluZXNzVGltZW91dHMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLndhaXRGb3JEZXZpY2VJZGxlKGRldmljZUlkLCB0aW1lb3V0cy5kZXZpY2VJZGxlVGltZW91dEluTWlsbGlzZWNvbmRzKTtcbiAgICBhd2FpdCB0aGlzLndhaXRGb3JOZXR3b3JrVmFsaWRhdGVkKGRldmljZUlkLCB0aW1lb3V0cy5uZXR3b3JrUmVhZHlUaW1lb3V0SW5NaWxsaXNlY29uZHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFdhaXRzIGZvciBhIGJvb3RlZCBlbXVsYXRvciB0byBoYXZlIGEgKip2YWxpZGF0ZWQgZGVmYXVsdCBuZXR3b3JrKiogYmVmb3JlXG4gICAqIHRoZSBzZXNzaW9uIGlzIGVzdGFibGlzaGVkLlxuICAgKlxuICAgKiBUaGUgaWRsZSBnYXRlIGFib3ZlIHNheXMgbm90aGluZyBhYm91dCBjb25uZWN0aXZpdHksIGFuZCBpdHMgdHdvIHNpZ25hbHMgYXJlXG4gICAqIHNhdGlzZmllZCB3ZWxsIGJlZm9yZSB0aGUgZGVmYXVsdCBuZXR3b3JrIGlzIGNyZWF0ZWQgYW5kIHZhbGlkYXRlZCBcdTIwMTQgdGhhdFxuICAgKiBsYW5kcyB+ODBzIGludG8gZ3Vlc3QgdXB0aW1lLCB0ZW5zIG9mIHNlY29uZHMgYWZ0ZXIgdGhlIGJvb3QgZmxhZyBvbiBhIGZhc3RcbiAgICogaG9zdC4gQSBzdWl0ZSBzdGFydGVkIGluIHRoYXQgZ2FwIGRvZXMgbm90IG1lcmVseSBydW4gc2xvd2x5OiBhIHRlc3RcbiAgICogdGhhdCByZWFjaGVzIHRoZSBuZXR3b3JrIHJ1bnMgdG8gY29tcGxldGlvbiBhZ2FpbnN0IGEgc2lsZW50bHkgKiplbXB0eVxuICAgKiByZXN1bHQqKiwgd2hpY2ggbm8gYXNzZXJ0aW9uIGluc2lkZSB0aGUgc3VpdGUgY2FuIGRpc3Rpbmd1aXNoIGZyb20gYVxuICAgKiBnZW51aW5lbHkgZW1wdHkgcmVzcG9uc2UuIE9ubHkgYSByZWFkaW5lc3MgZ2F0ZSBjYW4gY2F0Y2ggdGhhdCwgd2hpY2ggaXMgd2h5XG4gICAqIHRoaXMgZXhpc3RzIChzZWUge0BsaW5rIGNoZWNrTmV0d29ya1ZhbGlkYXRlZH0sIHdoaWNoIGFsc28gcmVjb3JkcyB3aHkgdGhlXG4gICAqIHRocmVlIG9idmlvdXMgY29ubmVjdGl2aXR5IHByb2JlcyBhcmUgYWxsIHdyb25nKS5cbiAgICpcbiAgICogQmVzdC1lZmZvcnQsIG9uIHRoZSBzYW1lIGNvbnRyYWN0IGFzIHRoZSBpZGxlIGdhdGU6IGlmIG5vIHZhbGlkYXRlZCBuZXR3b3JrXG4gICAqIGFwcGVhcnMgd2l0aGluIHRoZSBidWRnZXQgaXQgbG9ncyBhIHdhcm5pbmcgKipuYW1pbmcgdGhlIG1pc3NpbmcgbmV0d29yayoqXG4gICAqIGFuZCBwcm9jZWVkcyAoYW4gb2ZmbGluZSBBVkQgaXMgc3RpbGwgYSB1c2FibGUgb25lIGZvciBzdWl0ZXMgdGhhdCBuZXZlclxuICAgKiB0b3VjaCB0aGUgbmV0d29yayksIGFuZCBhIGJ1ZGdldCBvZiBgMGAgc2tpcHMgdGhlIHdhaXQgZW50aXJlbHkuIFRoZSB3YXJuaW5nXG4gICAqIGlzIHRoZSBwb2ludCBcdTIwMTQgdGhlIGZhaWx1cmUgaXQgcHJlY2VkZXMgb3RoZXJ3aXNlIHN1cmZhY2VzIGFzIGEgYmFyZVxuICAgKiBgV2ViRHJpdmVyRXJyb3I6IHNjcmlwdCB0aW1lb3V0YCBuYW1pbmcgdGhlIHRyYW5zcG9ydCwgd2hpY2ggcmVhZHMgYXMgYVxuICAgKiBoYXJuZXNzIGRlZmVjdCByYXRoZXIgdGhhbiBhIG1pc3Npbmcgcm91dGUuXG4gICAqXG4gICAqIEBwYXJhbSBkZXZpY2VJZCAtIFRoZSBkZXZpY2UgVURJRCB0byBwb2xsLlxuICAgKiBAcGFyYW0gdGltZW91dEluTWlsbGlzZWNvbmRzIC0gTWF4aW11bSB0aW1lIHRvIHdhaXQ7IGAwYCBza2lwcyB0aGUgd2FpdC5cbiAgICovXG4gIC8qKlxuICAgKiBQb2xscyB1bnRpbCB0aGlzIHJ1bidzIGVtdWxhdG9yIGlzIGdvbmUsIG9yIHRoZSBidWRnZXQgZWxhcHNlcy5cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtcyAtIFRoZSBkZXZpY2UsIHRoZSBQSURzIHRoaXMgcnVuIG93bnMsIGFuZCB0aGUgYnVkZ2V0LlxuICAgKiBAcmV0dXJucyBgdHJ1ZWAgd2hlbiB0aGUgZW11bGF0b3IgZGlzYXBwZWFyZWQgd2l0aGluIHRoZSBidWRnZXQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHdhaXRGb3JFbXVsYXRvclN0b3BwZWQocGFyYW1zOiBXYWl0Rm9yRW11bGF0b3JTdG9wcGVkUGFyYW1zKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgZGVhZGxpbmUgPSBEYXRlLm5vdygpICsgcGFyYW1zLnRpbWVvdXRJbk1pbGxpc2Vjb25kcztcblxuICAgIHdoaWxlIChEYXRlLm5vdygpIDwgZGVhZGxpbmUpIHtcbiAgICAgIGlmIChhd2FpdCB0aGlzLmNoZWNrSXNFbXVsYXRvckdvbmUocGFyYW1zKSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBFTVVMQVRPUl9TVE9QX1BPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgd2FpdEZvck5ldHdvcmtWYWxpZGF0ZWQoZGV2aWNlSWQ6IHN0cmluZywgdGltZW91dEluTWlsbGlzZWNvbmRzOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGltZW91dEluTWlsbGlzZWNvbmRzIDw9IDApIHtcbiAgICAgIHRoaXMubG9nKGBTa2lwcGluZyBuZXR3b3JrLXJlYWR5IHdhaXQgZm9yIGRldmljZSAke2RldmljZUlkfSAodGltZW91dCBpcyAwKS5gKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBzdGFydCA9IERhdGUubm93KCk7XG4gICAgY29uc3QgZGVhZGxpbmUgPSBzdGFydCArIHRpbWVvdXRJbk1pbGxpc2Vjb25kcztcbiAgICB0aGlzLmxvZyhcbiAgICAgIGBXYWl0aW5nIGZvciBkZXZpY2UgJHtkZXZpY2VJZH0gdG8gcmVwb3J0IGEgdmFsaWRhdGVkIG5ldHdvcmsgKHRpbWVvdXQ6ICR7U3RyaW5nKHRpbWVvdXRJbk1pbGxpc2Vjb25kcyl9bXMsIHBvbGw6ICR7U3RyaW5nKE5FVFdPUktfUkVBRFlfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMpfW1zKS4uLmBcbiAgICApO1xuXG4gICAgbGV0IHByb2JlRmFpbHVyZUNvdW50ID0gMDtcbiAgICBsZXQgbGFzdEZhaWx1cmVSZWFzb24gPSAnJztcblxuICAgIHdoaWxlIChEYXRlLm5vdygpIDwgZGVhZGxpbmUpIHtcbiAgICAgIGNvbnN0IHByb2JlID0gYXdhaXQgdGhpcy5kdW1wQ29ubmVjdGl2aXR5KGRldmljZUlkKTtcbiAgICAgIGNvbnN0IGVsYXBzZWQgPSBTdHJpbmcoRGF0ZS5ub3coKSAtIHN0YXJ0KTtcbiAgICAgIGNvbnN0IGNvbm5lY3Rpdml0eU91dHB1dCA9IHByb2JlLm91dHB1dDtcblxuICAgICAgaWYgKGNvbm5lY3Rpdml0eU91dHB1dCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHByb2JlRmFpbHVyZUNvdW50Kys7XG4gICAgICAgIGxhc3RGYWlsdXJlUmVhc29uID0gcHJvYmUuZmFpbHVyZVJlYXNvbiA/PyAndW5rbm93biBhZGIgZmFpbHVyZSc7XG4gICAgICAgIHRoaXMubG9nKFxuICAgICAgICAgIGBEZXZpY2UgJHtkZXZpY2VJZH0gY29ubmVjdGl2aXR5IHByb2JlIGZhaWxlZCAoZWxhcHNlZDogJHtlbGFwc2VkfW1zKTogJHtsYXN0RmFpbHVyZVJlYXNvbn0uIFJldHJ5aW5nLi4uYFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIGlmIChjaGVja05ldHdvcmtWYWxpZGF0ZWQoeyBjb25uZWN0aXZpdHlPdXRwdXQgfSkpIHtcbiAgICAgICAgdGhpcy5sb2coYERldmljZSAke2RldmljZUlkfSBoYXMgYSB2YWxpZGF0ZWQgbmV0d29yayBhZnRlciAke2VsYXBzZWR9bXMuYCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMubG9nKGBEZXZpY2UgJHtkZXZpY2VJZH0gaGFzIG5vIHZhbGlkYXRlZCBuZXR3b3JrIHlldCAoZWxhcHNlZDogJHtlbGFwc2VkfW1zKS4gUmV0cnlpbmcuLi5gKTtcbiAgICAgIH1cblxuICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgICAgc2V0VGltZW91dChyZXNvbHZlLCBORVRXT1JLX1JFQURZX1BPTExfSU5URVJWQUxfSU5fTUlMTElTRUNPTkRTKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qXG4gICAgICogVHdvIGRpZmZlcmVudCBkaWFnbm9zZXMsIG5ldmVyIG1lcmdlZCBpbnRvIG9uZSBzZW50ZW5jZTogYSBndWVzdCB0aGF0XG4gICAgICogYW5zd2VyZWQgYW5kIHJlcG9ydGVkIG5vIG5ldHdvcmsgaXMgb2ZmbGluZSwgd2hpbGUgYSBndWVzdCB0aGF0IG5ldmVyXG4gICAgICogYW5zd2VyZWQgc2F5cyBub3RoaW5nIGFib3V0IGl0cyBuZXR3b3JrIGFuZCBldmVyeXRoaW5nIGFib3V0IGl0c2VsZi5cbiAgICAgKi9cbiAgICBjb25zdCBkaWFnbm9zaXMgPSBwcm9iZUZhaWx1cmVDb3VudCA+IDBcbiAgICAgID8gYCR7U3RyaW5nKHByb2JlRmFpbHVyZUNvdW50KX0gb2YgaXRzIGNvbm5lY3Rpdml0eSBwcm9iZXMgZmFpbGVkLCBsYXN0IFwiJHtsYXN0RmFpbHVyZVJlYXNvbn1cIiwgc28gdGhlIGd1ZXN0IG1heSBiZSB3ZWRnZWQgcmF0aGVyIHRoYW4gb2ZmbGluZWBcbiAgICAgIDogJ2l0IGFuc3dlcmVkIGV2ZXJ5IHByb2JlIGFuZCByZXBvcnRlZCBubyB2YWxpZGF0ZWQgZGVmYXVsdCBuZXR3b3JrJztcbiAgICB0aGlzLmxvZyhcbiAgICAgIGBXYXJuaW5nOiBkZXZpY2UgJHtkZXZpY2VJZH0gcmVwb3J0ZWQgbm8gdmFsaWRhdGVkIG5ldHdvcmsgd2l0aGluICR7U3RyaW5nKHRpbWVvdXRJbk1pbGxpc2Vjb25kcyl9bXMgKCR7ZGlhZ25vc2lzfSk7IGBcbiAgICAgICAgKyAncHJvY2VlZGluZyB3aXRoIHNlc3Npb24gZXN0YWJsaXNobWVudCBhbnl3YXkuIFRlc3RzIHRoYXQgcmVhY2ggdGhlIG5ldHdvcmsgd2lsbCBydW4gYWdhaW5zdCBhIGRldmljZSB3aXRoIG5vIHJvdXRlLCAnXG4gICAgICAgICsgJ2FuZCBtYXkgcmV0dXJuIEVNUFRZIFJFU1VMVFMgcmF0aGVyIHRoYW4gZmFpbCBcdTIwMTQgcmVhZCBhbnkgZW1wdHktbG9va2luZyBhc3NlcnRpb24gZmFpbHVyZSBiZWxvdyBhcyBhIG1pc3NpbmcgbmV0d29yayBmaXJzdC4nXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgd2FpdEZvck5ld0RldmljZShkZXZpY2VJZHNCZWZvcmU6IHN0cmluZ1tdLCBlbXVsYXRvcjogUHJvY2Vzc0xhdW5jaCwgdGltZW91dHM6IERldmljZVJlYWRpbmVzc1RpbWVvdXRzKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICB0aGlzLmxvZyhcbiAgICAgIGBXYWl0aW5nIGZvciBhIG5ldyBkZXZpY2UgdG8gYXBwZWFyIGluIEFEQiAodGltZW91dDogJHtTdHJpbmcoRU1VTEFUT1JfQk9PVF9USU1FT1VUX0lOX01JTExJU0VDT05EUyl9bXMsIHBvbGw6ICR7U3RyaW5nKEVNVUxBVE9SX0JPT1RfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMpfW1zKS4uLmBcbiAgICApO1xuICAgIGNvbnN0IGRlYWRsaW5lID0gRGF0ZS5ub3coKSArIEVNVUxBVE9SX0JPT1RfVElNRU9VVF9JTl9NSUxMSVNFQ09ORFM7XG5cbiAgICB3aGlsZSAoRGF0ZS5ub3coKSA8IGRlYWRsaW5lKSB7XG4gICAgICBjb25zdCBjdXJyZW50SWRzID0gYXdhaXQgdGhpcy5nZXRDb25uZWN0ZWREZXZpY2VJZHMoKTtcbiAgICAgIGNvbnN0IG5ld0lkcyA9IGN1cnJlbnRJZHMuZmlsdGVyKChpZCkgPT4gIWRldmljZUlkc0JlZm9yZS5pbmNsdWRlcyhpZCkpO1xuXG4gICAgICBpZiAobmV3SWRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc3QgYWN0dWFsRGV2aWNlSWQgPSBuZXdJZHNbMF0gPz8gJyc7XG4gICAgICAgIHRoaXMubG9nKGBEZXZpY2UgJHthY3R1YWxEZXZpY2VJZH0gYXBwZWFyZWQgaW4gQURCLCB3YWl0aW5nIGZvciBib290IHRvIGNvbXBsZXRlLi4uYCk7XG4gICAgICAgIGF3YWl0IHRoaXMud2FpdEZvckJvb3QoYWN0dWFsRGV2aWNlSWQsIGRlYWRsaW5lLCBlbXVsYXRvcik7XG4gICAgICAgIGF3YWl0IHRoaXMud2FpdEZvckRldmljZVJlYWR5KGFjdHVhbERldmljZUlkLCB0aW1lb3V0cyk7XG4gICAgICAgIGF3YWl0IHRoaXMud2FrZVNjcmVlbihhY3R1YWxEZXZpY2VJZCk7XG4gICAgICAgIHJldHVybiBhY3R1YWxEZXZpY2VJZDtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZXhpdEluZm8gPSBlbXVsYXRvci5yZWFkRXhpdEluZm8oKTtcbiAgICAgIGlmIChleGl0SW5mbykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYnVpbGRQcm9jZXNzRXhpdE1lc3NhZ2Uoe1xuICAgICAgICAgIGV4aXRJbmZvLFxuICAgICAgICAgIG91dHB1dDogZW11bGF0b3IucmVhZE91dHB1dCgpLFxuICAgICAgICAgIG91dHB1dExhYmVsOiAnRW11bGF0b3Igb3V0cHV0JyxcbiAgICAgICAgICBzdWJqZWN0OiAnQW5kcm9pZCBlbXVsYXRvcidcbiAgICAgICAgfSkpO1xuICAgICAgfVxuXG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIEVNVUxBVE9SX0JPT1RfUE9MTF9JTlRFUlZBTF9JTl9NSUxMSVNFQ09ORFMpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gQXMgaW4gYHdhaXRGb3JCb290YDogYW4gZW11bGF0b3IgdGhhdCBoYW5ncyBoYXMgYXMgbXVjaCB0byBzYXkgYXMgb25lIHRoYXQgZGllcy5cbiAgICB0aHJvdyBuZXcgRXJyb3IoYXBwZW5kUHJvY2Vzc091dHB1dFRhaWwoXG4gICAgICBgTm8gbmV3IGVtdWxhdG9yIGRldmljZSBhcHBlYXJlZCB3aXRoaW4gJHtTdHJpbmcoRU1VTEFUT1JfQk9PVF9USU1FT1VUX0lOX01JTExJU0VDT05EUyl9bXMuYCxcbiAgICAgIHsgb3V0cHV0OiBlbXVsYXRvci5yZWFkT3V0cHV0KCksIG91dHB1dExhYmVsOiAnRW11bGF0b3Igb3V0cHV0JyB9XG4gICAgKSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHdha2VTY3JlZW4oZGV2aWNlSWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMubG9nKGBXYWtpbmcgc2NyZWVuIG9uIGRldmljZSAke2RldmljZUlkfS4uLmApO1xuXG4gICAgYXdhaXQgdGhpcy5zZW5kS2V5RXZlbnQoZGV2aWNlSWQsIEtFWUNPREVfV0FLRVVQLCAnd2FrZSBzY3JlZW4nKTtcbiAgICBhd2FpdCB0aGlzLnNlbmRLZXlFdmVudChkZXZpY2VJZCwgS0VZQ09ERV9NRU5VLCAnZGlzbWlzcyBsb2NrIHNjcmVlbicpO1xuXG4gICAgdGhpcy5sb2coYFNjcmVlbiB3YWtlIGNvbXBsZXRlIG9uIGRldmljZSAke2RldmljZUlkfS5gKTtcbiAgfVxufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgdHJhbnNwb3J0IGluc3RhbmNlIGZyb20gdGhlIGdpdmVuIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIG9wdGlvbnMgLSBUcmFuc3BvcnQgY29uZmlndXJhdGlvbi4gRGVmYXVsdHMgdG8gYW4gb3duZWQgZGVza3RvcCBDRFAgdHJhbnNwb3J0LlxuICogQHJldHVybnMgQSBuZXcgdHJhbnNwb3J0IGluc3RhbmNlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlVHJhbnNwb3J0RnJvbU9wdGlvbnMob3B0aW9ucz86IE9ic2lkaWFuVHJhbnNwb3J0T3B0aW9ucyk6IFByb21pc2U8T2JzaWRpYW5UcmFuc3BvcnQ+IHtcbiAgY29uc3QgdHlwZSA9IG9wdGlvbnM/LnR5cGUgPz8gREVGQVVMVF9UUkFOU1BPUlRfVFlQRTtcblxuICBpZiAoIW9wdGlvbnMgfHwgb3B0aW9ucy50eXBlID09PSAnb2JzaWRpYW4tY2RwJykge1xuICAgIHJldHVybiBjcmVhdGVDZHBUcmFuc3BvcnQob3B0aW9ucyk7XG4gIH1cblxuICBjb25zdCBmYWN0b3J5ID0gbmV3IEFwcGl1bVRyYW5zcG9ydEZhY3RvcnkodHlwZSk7XG4gIHJldHVybiBmYWN0b3J5LmNyZWF0ZShvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgY2FjaGVkIHRyYW5zcG9ydCBpbnN0YW5jZSwgY3JlYXRpbmcgb25lIGZyb20gdGhlIGdpdmVuIG9wdGlvbnNcbiAqIGlmIG5vdCBhbHJlYWR5IGNhY2hlZC5cbiAqXG4gKiBUaGUgdHJhbnNwb3J0IGlzIGNhY2hlZCBwZXIgd29ya2VyIHByb2Nlc3Mgc28gV2ViU29ja2V0L0FwcGl1bSBzZXNzaW9uc1xuICogYXJlIHJldXNlZCBhY3Jvc3MgY2FsbHMgd2l0aGluIHRoZSBzYW1lIHRlc3Qgd29ya2VyLlxuICpcbiAqIFRoaXMgaXMgdGhlIHNpbmdsZSBlbnRyeSBwb2ludCBldmVyeSB3b3JrZXItc2lkZSBjYWxsZXIgdXNlcyBmb3IgdGhlICoqYW1iaWVudCoqXG4gKiB0cmFuc3BvcnQsIHNvIGl0IGlzIGFsc28gd2hlcmUgYSBmYWlsZWQgZ2xvYmFsIHNldHVwIGlzIHR1cm5lZCBpbnRvIGEgZmFpbGluZyB0ZXN0LlxuICogQSBmYWlsZWQgc2V0dXAgcHVibGlzaGVzIG5vIHRyYW5zcG9ydCBvcHRpb25zLCBhbmQgYHVuZGVmaW5lZGAgb3B0aW9ucyBtZWFuIHRoZSBvd25lZFxuICogKipkZXNrdG9wKiogQ0RQIGRlZmF1bHQgXHUyMDE0IHNvIHdpdGhvdXQgdGhpcyBndWFyZCBhbiBBbmRyb2lkIHByb2plY3QncyBzdWl0ZSB3b3VsZCBydW5cbiAqIG9uIGRlc2t0b3AgYW5kIHRoZW4gZGllIG9uIGFuIHVucmVsYXRlZCBDRFAgZXJyb3IsIGhpZGluZyB0aGUgcmVhbCBjYXVzZSAoKipMOSoqKS5cbiAqIFRoZSBzZXR1cCBwYXRoIGl0c2VsZiBpcyB1bmFmZmVjdGVkOiBgY29yZVNldHVwYCBidWlsZHMgaXRzIHRyYW5zcG9ydCB0aHJvdWdoXG4gKiB7QGxpbmsgY3JlYXRlVHJhbnNwb3J0RnJvbU9wdGlvbnN9IHdpdGggZXhwbGljaXQgb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFRyYW5zcG9ydCBjb25maWd1cmF0aW9uLiBEZWZhdWx0cyB0byBhbiBvd25lZCBkZXNrdG9wIENEUCB0cmFuc3BvcnQuXG4gKiBAcmV0dXJucyBUaGUgY2FjaGVkIG9yIG5ld2x5IGNyZWF0ZWQgdHJhbnNwb3J0LlxuICogQHRocm93cyB7SW50ZWdyYXRpb25TZXR1cEZhaWxlZEVycm9yfSBXaGVuIHRoaXMgcHJvamVjdCdzIGdsb2JhbCBzZXR1cCBmYWlsZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRPckNyZWF0ZVRyYW5zcG9ydChvcHRpb25zPzogT2JzaWRpYW5UcmFuc3BvcnRPcHRpb25zKTogUHJvbWlzZTxPYnNpZGlhblRyYW5zcG9ydD4ge1xuICBjb25zdCBzZXR1cEVycm9yID0gZ2V0U2V0dXBFcnJvcigpO1xuICBpZiAoc2V0dXBFcnJvcikge1xuICAgIHRocm93IG5ldyBJbnRlZ3JhdGlvblNldHVwRmFpbGVkRXJyb3Ioc2V0dXBFcnJvcik7XG4gIH1cblxuICBpZiAoY2FjaGVkVHJhbnNwb3J0KSB7XG4gICAgcmV0dXJuIGNhY2hlZFRyYW5zcG9ydDtcbiAgfVxuXG4gIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNyZWF0ZVRyYW5zcG9ydEZyb21PcHRpb25zKG9wdGlvbnMpO1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVxdWlyZS1hdG9taWMtdXBkYXRlcyAtLSBTaW5nbGUtdGhyZWFkZWQgd29ya2VyOyBubyBjb25jdXJyZW50IHdyaXRlcy5cbiAgY2FjaGVkVHJhbnNwb3J0ID0gcmVzdWx0O1xuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIFZlcmlmaWVzIHRoZSBoYXJuZXNzLW93bmVkIGluc3RhbmNlIGEgd29ya2VyIHdhcyB0b2xkIHRvIGF0dGFjaCB0byBpcyBzdGlsbFxuICogc2VydmluZyBDRFAsIGJlZm9yZSBoYW5kaW5nIGJhY2sgYSB0cmFuc3BvcnQgdGhhdCBjYW4gb25seSBmYWlsIGFnYWluc3QgaXQuXG4gKlxuICogVGhpcyBpcyB0aGUgb25jZS1wZXItZmlsZSBjaGVjazogdHJhbnNwb3J0IGNyZWF0aW9uIGlzIGNhY2hlZCBwZXIgd29ya2VyLCBzb1xuICogYSBsaXZlIGluc3RhbmNlIHBheXMgb25lIGxvb3BiYWNrIHJlcXVlc3QgcGVyIHRlc3QgZmlsZSBhbmQgYSBkZWFkIG9uZSB0dXJuc1xuICogdGhlIHdob2xlIGZpbGUgaW50byBhIHNpbmdsZSBuYW1lZCBlcnJvciwgcmFpc2VkIGJlZm9yZSB0aGUgZmlyc3QgdGVzdC4gSXRcbiAqIHJlcGxhY2VzIHRoZSBgRUNPTk5SRUZVU0VEYC1wZXItZmlsZSBjYXNjYWRlIGEgbWlkLXJ1biBkZWF0aCB1c2VkIHRvIHByb2R1Y2UgXHUyMDE0XG4gKiBhbmQgdGhlIHBlci1maWxlIHByb2JlIGNvbnN1bWVycyB3ZXJlIHdyaXRpbmcgaW50byB0aGVpciBvd24gYHNldHVwRmlsZXNgIHRvXG4gKiBnZXQgdGhlIHNhbWUgZWZmZWN0LlxuICpcbiAqIE9ubHkgZm9yIHRoZSBoYXJuZXNzJ3Mgb3duIGluc3RhbmNlczogYSBwbGFpbiBhdHRhY2ggdGFyZ2V0cyBhIGZvcmVpZ25cbiAqIE9ic2lkaWFuIHdob3NlIGFic2VuY2UgaXMgdGhlIHVzZXIncyB0byByZXNvbHZlLCBhbmQgYHByZWZsaWdodENoZWNrYCBhbHJlYWR5XG4gKiBoYXMgYSBzdG9yeSBmb3IgaXQuXG4gKlxuICogQHBhcmFtIGhvc3QgLSBUaGUgQ0RQIGhvc3QgdG8gcHJvYmUuXG4gKiBAcGFyYW0gcG9ydCAtIFRoZSBDRFAgcG9ydCB0byBwcm9iZS5cbiAqIEB0aHJvd3Mge093bmVkSW5zdGFuY2VFeGl0ZWRFcnJvcn0gV2hlbiBub3RoaW5nIGlzIHNlcnZpbmcgQ0RQIG9uIHRoZSBwb3J0LlxuICovXG5hc3luYyBmdW5jdGlvbiBhc3NlcnRIYXJuZXNzT3duZWRJbnN0YW5jZUlzU2VydmluZyhob3N0OiBzdHJpbmcsIHBvcnQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBjZHBVcmwgPSBgaHR0cDovLyR7aG9zdH06JHtTdHJpbmcocG9ydCl9YDtcbiAgdHJ5IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke2NkcFVybH0vanNvbi92ZXJzaW9uYCk7XG4gICAgYXdhaXQgcmVzcG9uc2UuYm9keT8uY2FuY2VsKCk7XG4gICAgcmV0dXJuO1xuICB9IGNhdGNoIHtcbiAgICAvLyBOb3RoaW5nIGlzIGxpc3RlbmluZyBcdTIwMTQgdGhlIGluc3RhbmNlIHRoZSBnbG9iYWwgc2V0dXAgbGF1bmNoZWQgaXMgZ29uZS5cbiAgfVxuXG4gIHRocm93IGJ1aWxkT3duZWRJbnN0YW5jZUV4aXRlZEVycm9yRnJvbU1hcmtlcihjZHBVcmwsIHJlYWRPd25lZEluc3RhbmNlRXhpdE1hcmtlcihwb3J0KSk7XG59XG5cbi8qKlxuICogQnVpbGRzIHRoZSBwbGF0Zm9ybSdzIFwibGlzdCBldmVyeSBwcm9jZXNzXCIgcXVlcnkuXG4gKlxuICogQHJldHVybnMgVGhlIGNvbW1hbmQgYW5kIGFyZ3VtZW50cyB0byBydW4uXG4gKi9cbmZ1bmN0aW9uIGJ1aWxkSG9zdFByb2Nlc3NRdWVyeSgpOiBIb3N0Q29tbWFuZFF1ZXJ5IHtcbiAgcmV0dXJuIHByb2Nlc3MucGxhdGZvcm0gPT09ICd3aW4zMidcbiAgICA/IHsgY29tbWFuZDogJ3Rhc2tsaXN0JywgY29tbWFuZEFyZ3VtZW50czogWycvRk8nLCAnQ1NWJywgJy9OSCddIH1cbiAgICA6IHsgY29tbWFuZDogJ3BzJywgY29tbWFuZEFyZ3VtZW50czogWyctZW8nLCAncGlkPSxjb21tPSddIH07XG59XG5cbi8qKlxuICogQnVpbGRzIHRoZSBwbGF0Zm9ybSdzIFwid2hvIGhvbGRzIHRoaXMgcG9ydFwiIHF1ZXJ5LlxuICpcbiAqIGBuZXRzdGF0YCBjYW5ub3QgZmlsdGVyIGJ5IHBvcnQsIHNvIHRoZSB3aG9sZSB0YWJsZSBjb21lcyBiYWNrIGFuZCB0aGUgcGFyc2VyXG4gKiBkb2VzIHRoZSBtYXRjaGluZzsgYGxzb2ZgIGZpbHRlcnMgc2VydmVyLXNpZGUgYW5kIGFuc3dlcnMgd2l0aCBiYXJlIFBJRHMuXG4gKlxuICogQHBhcmFtIHBvcnQgLSBUaGUgcG9ydCB0byBxdWVyeS5cbiAqIEByZXR1cm5zIFRoZSBjb21tYW5kIGFuZCBhcmd1bWVudHMgdG8gcnVuLlxuICovXG5mdW5jdGlvbiBidWlsZFBvcnRPd25lclF1ZXJ5KHBvcnQ6IG51bWJlcik6IEhvc3RDb21tYW5kUXVlcnkge1xuICByZXR1cm4gcHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJ1xuICAgID8geyBjb21tYW5kOiAnbmV0c3RhdCcsIGNvbW1hbmRBcmd1bWVudHM6IFsnLWFubyddIH1cbiAgICA6IHsgY29tbWFuZDogJ2xzb2YnLCBjb21tYW5kQXJndW1lbnRzOiBbJy10aScsIGB0Y3A6JHtTdHJpbmcocG9ydCl9YF0gfTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgZGVza3RvcCBDRFAgdHJhbnNwb3J0LiBXaGVuIGFuIGV4cGxpY2l0IGBwb3J0YCBpcyBnaXZlbiB0aGVcbiAqIHRyYW5zcG9ydCBhdHRhY2hlcyB0byBhbiBhbHJlYWR5LXJ1bm5pbmcgT2JzaWRpYW4gb24gdGhhdCBwb3J0OyBvdGhlcndpc2UgaXRcbiAqIGxhdW5jaGVzIGFuZCBvd25zIGFuIGlzb2xhdGVkIGluc3RhbmNlICh0aGUgZGVmYXVsdCwgaGVybWV0aWMgbW9kZSkuXG4gKlxuICogQHBhcmFtIG9wdGlvbnMgLSBDRFAgdHJhbnNwb3J0IG9wdGlvbnMuXG4gKiBAcmV0dXJucyBBIGNvbmZpZ3VyZWQgQ0RQIHRyYW5zcG9ydC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gY3JlYXRlQ2RwVHJhbnNwb3J0KG9wdGlvbnM/OiBPYnNpZGlhbkNkcFRyYW5zcG9ydE9wdGlvbnMpOiBQcm9taXNlPE9ic2lkaWFuVHJhbnNwb3J0PiB7XG4gIGlmIChvcHRpb25zPy5wb3J0ICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBvd25lZFN1ZmZpeCA9IG9wdGlvbnMuaXNIYXJuZXNzT3duZWRJbnN0YW5jZSA/ICcgKGhhcm5lc3Mtb3duZWQpJyA6ICcnO1xuICAgIGxvZyhgW3RyYW5zcG9ydC1mYWN0b3J5Om9ic2lkaWFuLWNkcF0gQXR0YWNoaW5nIHRvIHJ1bm5pbmcgT2JzaWRpYW4ke293bmVkU3VmZml4fSAoaG9zdD0ke29wdGlvbnMuaG9zdCA/PyAnbG9jYWxob3N0J30sIHBvcnQ9JHtTdHJpbmcob3B0aW9ucy5wb3J0KX0pYCk7XG4gICAgaWYgKG9wdGlvbnMuaXNIYXJuZXNzT3duZWRJbnN0YW5jZSkge1xuICAgICAgYXdhaXQgYXNzZXJ0SGFybmVzc093bmVkSW5zdGFuY2VJc1NlcnZpbmcob3B0aW9ucy5ob3N0ID8/ICdsb2NhbGhvc3QnLCBvcHRpb25zLnBvcnQpO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IERlc2t0b3BDZHBUcmFuc3BvcnQobm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzPERlc2t0b3BDZHBUcmFuc3BvcnRDb25maWc+KHtcbiAgICAgIGNkcEhvc3Q6IG9wdGlvbnMuaG9zdCxcbiAgICAgIGNkcFBvcnQ6IG9wdGlvbnMucG9ydCxcbiAgICAgIGNvbW1hbmRUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG9wdGlvbnMuY29tbWFuZFRpbWVvdXRJbk1pbGxpc2Vjb25kcyxcbiAgICAgIGlzSGFybmVzc093bmVkSW5zdGFuY2U6IG9wdGlvbnMuaXNIYXJuZXNzT3duZWRJbnN0YW5jZVxuICAgIH0pKTtcbiAgfVxuXG4gIGxvZygnW3RyYW5zcG9ydC1mYWN0b3J5Om9ic2lkaWFuLWNkcF0gQ3JlYXRpbmcgb3duZWQgaXNvbGF0ZWQgT2JzaWRpYW4gaW5zdGFuY2UnKTtcbiAgLy8gQmVmb3JlIGByZXNvbHZlT3duZWRJbnN0YW5jZUNvbmZpZ2AsIHdoaWNoIG1heSBkb3dubG9hZCBhbmQgY2FjaGUgYW4gaW5zdGFsbGVyIHNoZWxsOlxuICAvLyBBIHN0cnVjdHVyYWxseSBpbnZhbGlkIGNvbmZpZyBmb2xkZXIgbmFtZSBjYW5ub3QgYmVjb21lIHZhbGlkIGxhdGVyLCBzbyBwYXlpbmcgZm9yIGFcbiAgLy8gUHJvdmlzaW9uaW5nIHJvdW5kLXRyaXAgZmlyc3Qgd291bGQgb25seSBkZWxheSB0aGUgc2FtZSBmYWlsdXJlLlxuICBpZiAob3B0aW9ucz8uY29uZmlnRGlyZWN0b3J5ICE9PSB1bmRlZmluZWQpIHtcbiAgICBhc3NlcnRWYWxpZENvbmZpZ0RpcmVjdG9yeShvcHRpb25zLmNvbmZpZ0RpcmVjdG9yeSk7XG4gIH1cbiAgY29uc3Qgb3duZWRJbnN0YW5jZSA9IGF3YWl0IHJlc29sdmVPd25lZEluc3RhbmNlQ29uZmlnKG9wdGlvbnMpO1xuICByZXR1cm4gbmV3IERlc2t0b3BDZHBUcmFuc3BvcnQobm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzPERlc2t0b3BDZHBUcmFuc3BvcnRDb25maWc+KHtcbiAgICBjZHBIb3N0OiBvcHRpb25zPy5ob3N0LFxuICAgIGNvbW1hbmRUaW1lb3V0SW5NaWxsaXNlY29uZHM6IG9wdGlvbnM/LmNvbW1hbmRUaW1lb3V0SW5NaWxsaXNlY29uZHMsXG4gICAgY29uZmlnRGlyZWN0b3J5OiBvcHRpb25zPy5jb25maWdEaXJlY3RvcnksXG4gICAgZGVhZEJvb3RHcmFjZUluTWlsbGlzZWNvbmRzOiByZXNvbHZlRGVhZEJvb3RHcmFjZUluTWlsbGlzZWNvbmRzKG9wdGlvbnMpLFxuICAgIGlzT2JzaWRpYW5BcHBWaXNpYmxlOiBvcHRpb25zPy5pc09ic2lkaWFuQXBwVmlzaWJsZSxcbiAgICBvd25lZEluc3RhbmNlLFxuICAgIHNob3VsZERpc2FibGVTYW5kYm94OiBvcHRpb25zPy5zaG91bGREaXNhYmxlU2FuZGJveCxcbiAgICBzaG91bGRUaHJvd09uU2lsZW50QXNhckZhbGxiYWNrOiB3aWxsVGhyb3dPblNpbGVudEFzYXJGYWxsYmFjayhvcHRpb25zPy5zaG91bGRUaHJvd09uU2lsZW50QXNhckZhbGxiYWNrKSxcbiAgICBzaG91bGRXYXJuT25Db21wYXRpYmlsaXR5SXNzdWVzOiB3aWxsV2Fybk9uQ29tcGF0aWJpbGl0eUlzc3VlcyhvcHRpb25zPy5zaG91bGRXYXJuT25Db21wYXRpYmlsaXR5SXNzdWVzKVxuICB9KSk7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIGZyZXNoLCBpc29sYXRlZCB1c2VyLWRhdGEgZGlyZWN0b3J5IGZvciBhbiBvd25lZCBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgbmV3IGRpcmVjdG9yeS5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlT3duZWRVc2VyRGF0YURpcmVjdG9yeSgpOiBzdHJpbmcge1xuICBjb25zdCByb290ID0gam9pbih0bXBkaXIoKSwgSEFSTkVTU19URU1QX0RJUl9OQU1FKTtcbiAgbWtkaXJTeW5jKHJvb3QsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICByZXR1cm4gbWtkdGVtcFN5bmMoam9pbihyb290LCBPV05FRF9VU0VSX0RBVEFfRElSX1BSRUZJWCkpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIGZpcnN0IHJlamVjdGlvbiByZWFzb24gYW1vbmcgc2V0dGxlZCBvdXRjb21lcy5cbiAqXG4gKiBAcGFyYW0gb3V0Y29tZXMgLSBUaGUgc2V0dGxlZCBvdXRjb21lcywgYXQgbGVhc3Qgb25lIG9mIHdoaWNoIGlzIGV4cGVjdGVkIHRvIGhhdmUgcmVqZWN0ZWQuXG4gKiBAcmV0dXJucyBUaGUgZmlyc3QgcmVqZWN0aW9uIHJlYXNvbiwgb3IgYSBzdGFuZC1pbiBlcnJvciB3aGVuIG5vbmUgcmVqZWN0ZWQuXG4gKi9cbmZ1bmN0aW9uIGdldFNldHRsZWRGYWlsdXJlKG91dGNvbWVzOiByZWFkb25seSBQcm9taXNlU2V0dGxlZFJlc3VsdDx1bmtub3duPltdKTogdW5rbm93biB7XG4gIGZvciAoY29uc3Qgb3V0Y29tZSBvZiBvdXRjb21lcykge1xuICAgIGlmIChvdXRjb21lLnN0YXR1cyA9PT0gJ3JlamVjdGVkJykge1xuICAgICAgcmV0dXJuIG91dGNvbWUucmVhc29uO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBuZXcgRXJyb3IoJ0FuZHJvaWQgcHJvdmlzaW9uaW5nIGZhaWxlZCB3aXRob3V0IG5hbWluZyBhIHJlYXNvbi4nKTtcbn1cblxuLyoqXG4gKiBMb2FkcyBgd2ViZHJpdmVyaW9gIG9uIGRlbWFuZC5cbiAqXG4gKiBUaGUgbG9hZCBpcyBkZWZlcnJlZCBiZWNhdXNlIGEgc3RhdGljIGltcG9ydCB3b3VsZCBkcmFnIHRoZSB3aG9sZSBXZWJEcml2ZXJcbiAqIHN0YWNrIChgd2ViZHJpdmVyaW9gICsgYEB3ZGlvLypgICsgYGFyY2hpdmVyYC9gY2hlZXJpb2AvYGpzemlwYCkgaW50byBldmVyeVxuICogY29uc3VtZXIgb2YgdGhpcyBwYWNrYWdlJ3MgaW5kZXggXHUyMDE0IGBldmFsSW5PYnNpZGlhbmAgcmVhY2hlcyB0aGlzIG1vZHVsZSBcdTIwMTQgd2hlblxuICogb25seSB0aGUgQXBwaXVtIHRyYW5zcG9ydCBuZWVkcyBpdC4gTm90aGluZyBvbiB0aGUgZGVza3RvcCBDRFAgcGF0aCB0b3VjaGVzXG4gKiBgd2ViZHJpdmVyaW9gIGF0IGFsbC5cbiAqXG4gKiBJdCBhbHNvIGtlZXBzIGBjaGFsa2Agb3V0IG9mIHRoYXQgZ3JhcGguIGBAd2Rpby9sb2dnZXJgIGltcG9ydHMgYGNoYWxrQDVgLFxuICogd2hvc2UgaW50ZXJuYWwgYCNzdXBwb3J0cy1jb2xvcmAgc3VicGF0aCBpbXBvcnQgSmVzdCdzIFZNLW1vZHVsZXMgbGlua2VyIGZhaWxzXG4gKiB0byBsaW5rLCBzbyBhbiBlYWdlcmx5LWltcG9ydGVkIGB3ZWJkcml2ZXJpb2Aga2lsbHMgYSBKZXN0IEVTTSBzdWl0ZSBhdCBpbXBvcnRcbiAqIHdpdGggYFJlZmVyZW5jZUVycm9yOiBDYW5ub3QgYWNjZXNzICdzdXBwb3J0c0NvbG9yJyBiZWZvcmUgaW5pdGlhbGl6YXRpb25gXG4gKiBiZWZvcmUgYSBzaW5nbGUgdGVzdCBydW5zIFx1MjAxNCB3aGljaCBpcyB3aGF0IG9uY2UgbWFkZSBgdGVzdDpqZXN0YCByZWQuIEFcbiAqIGBtb2R1bGVOYW1lTWFwcGVyYCBjYW5ub3QgcGF0Y2ggaXQ6IHRoZSBtYXBwZXIgaXMgYnlwYXNzZWQgZm9yIGAjYCBzcGVjaWZpZXJzLlxuICpcbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGB3ZWJkcml2ZXJpb2AgZW50cnkgcG9pbnRzIHRoZVxuICogQXBwaXVtIGZhY3RvcnkgY2FsbHMuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGltcG9ydFdlYmRyaXZlcmlvKCk6IFByb21pc2U8V2ViZHJpdmVyaW9Nb2R1bGU+IHtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXJlc3RyaWN0ZWQtc3ludGF4IC0tIGB3ZWJkcml2ZXJpb2AgaXMgQXBwaXVtLW9ubHksIHNvIGl0IG11c3QgYmUgbG9hZGVkIGxhemlseTogYSBzdGF0aWMgaW1wb3J0IHdvdWxkIGRyYWcgdGhlIHdob2xlIFdlYkRyaXZlciBzdGFjayBpbnRvIGV2ZXJ5IGNvbnN1bWVyIG9mIHRoaXMgcGFja2FnZSdzIGluZGV4LCBhbmQgYGNoYWxrYCB3aXRoIGl0IChzZWUgdGhlIGRvYyBjb21tZW50KS5cbiAgcmV0dXJuIGF3YWl0IGltcG9ydCgnd2ViZHJpdmVyaW8nKTtcbn1cblxuLyoqXG4gKiBQYXJzZXMgYSBob3N0IHByb2Nlc3MgbGlzdGluZyB3aXRoIHRoZSBwbGF0Zm9ybSdzIHBhcnNlci5cbiAqXG4gKiBAcGFyYW0gb3V0cHV0IC0gUmF3IHN0ZG91dCBvZiB7QGxpbmsgYnVpbGRIb3N0UHJvY2Vzc1F1ZXJ5fSdzIGNvbW1hbmQuXG4gKiBAcmV0dXJucyBUaGUgbGlzdGVkIHByb2Nlc3Nlcy5cbiAqL1xuZnVuY3Rpb24gcGFyc2VIb3N0UHJvY2Vzc0xpc3Qob3V0cHV0OiBzdHJpbmcpOiBQcm9jZXNzTGlzdEVudHJ5W10ge1xuICByZXR1cm4gcHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJyA/IHBhcnNlV2luZG93c1Rhc2tMaXN0KG91dHB1dCkgOiBwYXJzZVBvc2l4UHJvY2Vzc0xpc3Qob3V0cHV0KTtcbn1cblxuLyoqXG4gKiBQYXJzZXMgYSBwb3J0LW93bmVyIGxpc3Rpbmcgd2l0aCB0aGUgcGxhdGZvcm0ncyBwYXJzZXIuXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIFRoZSByYXcgb3V0cHV0IGFuZCB0aGUgcG9ydCB0aGF0IHdhcyBxdWVyaWVkLlxuICogQHJldHVybnMgVGhlIFBJRHMgaG9sZGluZyB0aGUgcG9ydC5cbiAqL1xuZnVuY3Rpb24gcGFyc2VQb3J0T3duZXJQaWRzKHBhcmFtczogUGFyc2VQb3J0T3duZXJQaWRzUGFyYW1zKTogbnVtYmVyW10ge1xuICByZXR1cm4gcHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJ1xuICAgID8gcGFyc2VXaW5kb3dzTmV0c3RhdFBpZHMoeyBuZXRzdGF0T3V0cHV0OiBwYXJhbXMub3V0cHV0LCBwb3J0OiBwYXJhbXMucG9ydCB9KVxuICAgIDogcGFyc2VQb3NpeExzb2ZQaWRzKHBhcmFtcy5vdXRwdXQpO1xufVxuXG4vKipcbiAqIFJ1bnMgdGhlIHByb2FjdGl2ZSBpbnN0YWxsZXJcdTIxOTRhcHAgY29tcGF0aWJpbGl0eSBjaGVjayBmb3IgYW4gYXNhci1zd2FwIGFuZCBhY3RzXG4gKiBvbiB0aGUgdmVyZGljdDogZm9yIGFuIGluc3RhbGxlciBiZWxvdyB0aGUgYXBwJ3MgcnVuIGZsb29yIGVpdGhlciB0aHJvd3NcbiAqIHtAbGluayBJbmNvbXBhdGlibGVJbnN0YWxsZXJWZXJzaW9uRXJyb3J9ICh3aGVuXG4gKiB7QGxpbmsgUmVzb2x2ZUFuZFJlcG9ydENvbXBhdGliaWxpdHlQYXJhbXMuc2hvdWxkVGhyb3dPbkluY29tcGF0aWJsZUluc3RhbGxlcn0pXG4gKiBvciBwcm9jZWVkcyB0byBsYXVuY2ggd2l0aCBhIHdhcm5pbmc7IGZvciBhIHJ1bm5hYmxlLWJ1dC1iZWxvdy1yZWNvbW1lbmRlZFxuICogaW5zdGFsbGVyIGxvZ3MgYSB3YXJuaW5nLiBCb3RoIHdhcm5pbmdzIGFyZSBzdXBwcmVzc2VkIHdoZW5cbiAqIHtAbGluayBSZXNvbHZlQW5kUmVwb3J0Q29tcGF0aWJpbGl0eVBhcmFtcy5zaG91bGRXYXJuT25Db21wYXRpYmlsaXR5SXNzdWVzfSBpc1xuICogYGZhbHNlYC5cbiAqXG4gKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHJlc29sdmVkIHZlcnNpb25zIGFuZCB0aGUgd2Fybi90aHJvdyBrbm9icy5cbiAqIEByZXR1cm5zIFRoZSB2ZXJkaWN0LCBvciBgdW5kZWZpbmVkYCB3aGVuIHRoZXJlIGlzIG5vIGFzYXItc3dhcCB0byBjaGVjay5cbiAqL1xuZnVuY3Rpb24gcmVzb2x2ZUFuZFJlcG9ydENvbXBhdGliaWxpdHkocGFyYW1zOiBSZXNvbHZlQW5kUmVwb3J0Q29tcGF0aWJpbGl0eVBhcmFtcyk6IEluc3RhbGxlckNvbXBhdGliaWxpdHkgfCB1bmRlZmluZWQge1xuICBjb25zdCB7IGFwcFZlcnNpb24sIGluc3RhbGxlclZlcnNpb24sIHNob3VsZFRocm93T25JbmNvbXBhdGlibGVJbnN0YWxsZXIsIHNob3VsZFdhcm5PbkNvbXBhdGliaWxpdHlJc3N1ZXMgfSA9IHBhcmFtcztcbiAgaWYgKGFwcFZlcnNpb24gPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCBjb21wYXRpYmlsaXR5ID0gcmVzb2x2ZUluc3RhbGxlckNvbXBhdGliaWxpdHkoe1xuICAgIGFwcFZlcnNpb24sXG4gICAgaW5zdGFsbGVyVmVyc2lvbixcbiAgICBtZXRhZGF0YTogZ2V0VmVyc2lvbk1ldGFkYXRhKGFwcFZlcnNpb24pXG4gIH0pO1xuXG4gIGNvbnN0IGFjdGlvbiA9IHJlc29sdmVJbnN0YWxsZXJDb21wYXRpYmlsaXR5QWN0aW9uKHtcbiAgICBzaG91bGRUaHJvd09uSW5jb21wYXRpYmxlSW5zdGFsbGVyLFxuICAgIHNob3VsZFdhcm5PbkNvbXBhdGliaWxpdHlJc3N1ZXMsXG4gICAgdGllcjogY29tcGF0aWJpbGl0eS50aWVyXG4gIH0pO1xuXG4gIGlmIChhY3Rpb24gPT09ICd0aHJvdycpIHtcbiAgICB0aHJvdyBuZXcgSW5jb21wYXRpYmxlSW5zdGFsbGVyVmVyc2lvbkVycm9yKHtcbiAgICAgIGFwcFZlcnNpb246IGNvbXBhdGliaWxpdHkuYXBwVmVyc2lvbixcbiAgICAgIGluc3RhbGxlclZlcnNpb246IGVuc3VyZU5vbk51bGxhYmxlKGNvbXBhdGliaWxpdHkuaW5zdGFsbGVyVmVyc2lvbiksXG4gICAgICBtaW5SdW5uYWJsZUluc3RhbGxlclZlcnNpb246IGVuc3VyZU5vbk51bGxhYmxlKGNvbXBhdGliaWxpdHkubWluUnVubmFibGVJbnN0YWxsZXJWZXJzaW9uKVxuICAgIH0pO1xuICB9XG5cbiAgaWYgKGFjdGlvbiA9PT0gJ3dhcm4tdW5ydW5uYWJsZScpIHtcbiAgICBsb2coXG4gICAgICBgW3RyYW5zcG9ydC1mYWN0b3J5Om9ic2lkaWFuLWNkcF0gT2JzaWRpYW4gaW5zdGFsbGVyICR7ZW5zdXJlTm9uTnVsbGFibGUoY29tcGF0aWJpbGl0eS5pbnN0YWxsZXJWZXJzaW9uKX0gaXMgYmVsb3cgdGhlIGBcbiAgICAgICAgKyBgcnVuIGZsb29yICR7ZW5zdXJlTm9uTnVsbGFibGUoY29tcGF0aWJpbGl0eS5taW5SdW5uYWJsZUluc3RhbGxlclZlcnNpb24pfSBmb3IgT2JzaWRpYW4gJHtjb21wYXRpYmlsaXR5LmFwcFZlcnNpb259OyBgXG4gICAgICAgICsgJ3Byb2NlZWRpbmcgdG8gbGF1bmNoIChzaG91bGRUaHJvd09uSW5jb21wYXRpYmxlSW5zdGFsbGVyIGlzIGZhbHNlKSBcdTIwMTQgdGhlIGJvb3Qgd2lsbCBsaWtlbHkgZGVhZC1ib290LidcbiAgICApO1xuICB9IGVsc2UgaWYgKGFjdGlvbiA9PT0gJ3dhcm4tbmFnZ2VkJykge1xuICAgIGxvZyhgW3RyYW5zcG9ydC1mYWN0b3J5Om9ic2lkaWFuLWNkcF0gJHtlbnN1cmVOb25OdWxsYWJsZShjb21wYXRpYmlsaXR5Lm1lc3NhZ2UpfWApO1xuICB9XG5cbiAgcmV0dXJuIGNvbXBhdGliaWxpdHk7XG59XG5cbi8qKlxuICogRGVjaWRlcyBob3cgdGhlIHJlcXVlc3RlZCBhcHAgKGFzYXIpIHZlcnNpb24gd2lsbCBiZSBhcHBsaWVkIHRvIGFuIG93bmVkXG4gKiBpbnN0YW5jZSwgd2l0aG91dCBkb3dubG9hZGluZyBhbnl0aGluZyB5ZXQ6IGFuIHVwZ3JhZGUtb25seSBhc2FyLXN3YXAgb250byB0aGVcbiAqIHNoZWxsLCBhIGRvd25ncmFkZSB0byB0aGUgYXBwJ3Mgb3duIGluc3RhbGxlciBzaGVsbCwgb3IgdGhlIHVzZXIncyBuZXdlc3RcbiAqIGluc3RhbGxlZCBhc2FyIHdoZW4gbmVpdGhlciB2ZXJzaW9uIGlzIHBpbm5lZC5cbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIENEUCB0cmFuc3BvcnQgb3B0aW9ucy5cbiAqIEBwYXJhbSBzaGVsbFZlcnNpb24gLSBUaGUgcmVzb2x2ZWQgaW5zdGFsbGVyL3NoZWxsIHZlcnNpb24sIG9yIGB1bmRlZmluZWRgLlxuICogQHJldHVybnMgVGhlIGFzYXIgcGxhbiAoYXQgbW9zdCBvbmUgb2YgaXRzIGZpZWxkcyBpcyBzZXQpLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlQXNhclBsYW4oXG4gIG9wdGlvbnM6IE9ic2lkaWFuQ2RwVHJhbnNwb3J0T3B0aW9ucyB8IHVuZGVmaW5lZCxcbiAgc2hlbGxWZXJzaW9uOiBzdHJpbmcgfCB1bmRlZmluZWRcbik6IFByb21pc2U8QXNhclBsYW4+IHtcbiAgaWYgKG9wdGlvbnM/Lm9ic2lkaWFuVmVyc2lvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgYXNhclZlcnNpb24gPSBhd2FpdCByZXNvbHZlQ29uY3JldGVWZXJzaW9uKG9wdGlvbnMub2JzaWRpYW5WZXJzaW9uKTtcbiAgICBpZiAoc2hlbGxWZXJzaW9uICE9PSB1bmRlZmluZWQgJiYgY29tcGFyZVZlcnNpb25zKGFzYXJWZXJzaW9uLCBzaGVsbFZlcnNpb24pID49IDApIHtcbiAgICAgIHJldHVybiB7IGFzYXJWZXJzaW9uVG9Td2FwOiBhc2FyVmVyc2lvbiB9O1xuICAgIH1cblxuICAgIC8vIEFzYXItc3dhcCBpcyB1cGdyYWRlLW9ubHksIHNvIGl0IGNhbm5vdCBhcHBseSBhIHZlcnNpb24gb2xkZXIgdGhhbiB0aGVcbiAgICAvLyBTaGVsbCdzIGJ1bmRsZWQgb25lIFx1MjAxNCBhbmQgd2hlbiB0aGUgc2hlbGwgdmVyc2lvbiBpcyB1bmtub3duIChhIExpbnV4XG4gICAgLy8gUGF0aC1wYXJzZSBtaXNzKSB3ZSBjYW5ub3QgcHJvdmUgdGhlIHN3YXAgd291bGQgYXBwbHkgYXQgYWxsLiBJbiBib3RoXG4gICAgLy8gQ2FzZXMgdXNlIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbidzIG93biBpbnN0YWxsZXIgc2hlbGwsIHdob3NlIGJ1bmRsZWQgYXNhclxuICAgIC8vIElzIGV4YWN0bHkgdGhpcyB2ZXJzaW9uLCBzbyB0aGUgcGluIGlzIGFsd2F5cyBob25vcmVkLlxuICAgIGxvZyhgW3RyYW5zcG9ydC1mYWN0b3J5Om9ic2lkaWFuLWNkcF0gVXNpbmcgdGhlICR7YXNhclZlcnNpb259IGluc3RhbGxlciBzaGVsbCAoc2hlbGwgdmVyc2lvbiAke3NoZWxsVmVyc2lvbiA/PyAndW5rbm93bid9OyBhc2FyLXN3YXAgaXMgdXBncmFkZS1vbmx5KS5gKTtcbiAgICByZXR1cm4geyBkb3duZ3JhZGVJbnN0YWxsZXJWZXJzaW9uOiBhc2FyVmVyc2lvbiB9O1xuICB9XG5cbiAgaWYgKG9wdGlvbnM/Lm9ic2lkaWFuSW5zdGFsbGVyVmVyc2lvbiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgbmV3ZXN0ID0gZmluZE5ld2VzdEFzYXIoZ2V0T2JzaWRpYW5Db25maWdEaXJlY3RvcnkoKSk7XG4gICAgaWYgKG5ld2VzdCAmJiAoc2hlbGxWZXJzaW9uID09PSB1bmRlZmluZWQgfHwgY29tcGFyZVZlcnNpb25zKG5ld2VzdC52ZXJzaW9uLCBzaGVsbFZlcnNpb24pID49IDApKSB7XG4gICAgICByZXR1cm4geyBhc2FyOiB7IHBhdGg6IG5ld2VzdC5wYXRoLCB2ZXJzaW9uOiBuZXdlc3QudmVyc2lvbiB9IH07XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHt9O1xufVxuXG4vKipcbiAqIFJlc29sdmVzIHRoZSBsb2NhbGx5LWluc3RhbGxlZCBPYnNpZGlhbiBzaGVsbCwgdG9sZXJhdGluZyBpdHMgYWJzZW5jZS5cbiAqXG4gKiBVbmxpa2Uge0BsaW5rIHJlc29sdmVPYnNpZGlhbkV4ZWN1dGFibGV9ICh3aGljaCB0aHJvd3Mgd2hlbiBPYnNpZGlhbiBpcyBub3RcbiAqIGluc3RhbGxlZCksIHRoaXMgcmV0dXJucyBgdW5kZWZpbmVkYCBpbiB0aGF0IGNhc2UsIHNvIGEgY2FsbGVyIHBpbm5pbmcgYW5cbiAqIGluc3RhbGxlciB2ZXJzaW9uIGNhbiBmYWxsIGJhY2sgdG8gZG93bmxvYWRpbmcgdGhlIHBpbm5lZCBzaGVsbCBpbnN0ZWFkIG9mXG4gKiBmYWlsaW5nIG9uIGEgaG9zdCB3aXRoIG5vIE9ic2lkaWFuIGluc3RhbGxlZCAoZS5nLiBDSSkuXG4gKlxuICogQHJldHVybnMgVGhlIGluc3RhbGxlZCBzaGVsbCdzIHBhdGggYW5kIGRldGVjdGVkIHZlcnNpb24sIG9yIGB1bmRlZmluZWRgIHdoZW5cbiAqICAgbm8gT2JzaWRpYW4gaXMgaW5zdGFsbGVkLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlSW5zdGFsbGVkU2hlbGxPck51bGwoKTogUHJvbWlzZTxJbnN0YWxsZWRTaGVsbCB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IGV4ZVBhdGggPSBhd2FpdCByZXNvbHZlT2JzaWRpYW5FeGVjdXRhYmxlKCk7XG4gICAgcmV0dXJuIHsgZXhlUGF0aCwgc2hlbGxWZXJzaW9uOiBkZXRlY3RJbnN0YWxsZWRTaGVsbFZlcnNpb24oZXhlUGF0aCkgfTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIFJlc29sdmVzIHRoZSBzaGVsbCBleGVjdXRhYmxlLCBhc2FyIHByb3Zpc2lvbmluZywgYW5kIGlzb2xhdGVkIHVzZXItZGF0YSBkaXJcbiAqIGZvciBhIGhhcm5lc3Mtb3duZWQgaW5zdGFuY2UgZnJvbSB0aGUgcmVxdWVzdGVkIHZlcnNpb24ga25vYnMuXG4gKlxuICogLSBgb2JzaWRpYW5JbnN0YWxsZXJWZXJzaW9uYCBwaW5zIHRoZSBFbGVjdHJvbiBzaGVsbCAoZG93bmxvYWRzICsgZXh0cmFjdHMgYVxuICogICBwb3J0YWJsZSBidWlsZCB3aGVuIGl0IGRpZmZlcnMgZnJvbSB0aGUgaW5zdGFsbGVkIHNoZWxsKS5cbiAqIC0gYG9ic2lkaWFuVmVyc2lvbmAgcGlucyB0aGUgYXBwOiBhbiBhc2FyLXN3YXAgd2hlbiBpdCBpcyA+PSB0aGUgc2hlbGwgdmVyc2lvblxuICogICAoY2hlYXApLCBvdGhlcndpc2UgdGhlIG1hdGNoaW5nIGluc3RhbGxlciBzaGVsbCBpcyB1c2VkIChkb3duZ3JhZGUpLlxuICogLSBXaGVuIG5laXRoZXIgaXMgc2V0LCB0aGUgdXNlcidzIG5ld2VzdCBpbnN0YWxsZWQgYXNhciBpcyBjb3BpZWQgaW4gKHNvIHRoZVxuICogICBvd25lZCBpbnN0YW5jZSBtYXRjaGVzIHRoZSB2ZXJzaW9uIHRoZSB1c2VyIGN1cnJlbnRseSBydW5zKSB3aXRoIHplcm8gbmV0d29yay5cbiAqXG4gKiBUaGUgY29uY3JldGUgKGFwcCwgaW5zdGFsbGVyKSB2ZXJzaW9uIHBhaXIgaXMgcmVzb2x2ZWQgKmJlZm9yZSogYW55IHNoZWxsL2FzYXJcbiAqIGRvd25sb2FkLCBzbyBhIHByb2FjdGl2ZSBpbnN0YWxsZXJcdTIxOTRhcHAgY29tcGF0aWJpbGl0eSBjaGVja1xuICogKHtAbGluayByZXNvbHZlSW5zdGFsbGVyQ29tcGF0aWJpbGl0eX0pIGNhbiBmYWlsIGZhc3Q6IGFuIGluc3RhbGxlciBiZWxvdyB0aGVcbiAqIGFwcCdzIHJ1biBmbG9vciB0aHJvd3Mge0BsaW5rIEluY29tcGF0aWJsZUluc3RhbGxlclZlcnNpb25FcnJvcn0gYmVmb3JlXG4gKiBhbnl0aGluZyBpcyBkb3dubG9hZGVkIG9yIGxhdW5jaGVkIChzdXBlcnNlZGluZyB0aGUgcmVhY3RpdmUgZGVhZC1ib290XG4gKiBmYXN0LWZhaWwgZm9yIHRhYmxlLWtub3duIGNvbWJvcyksIGFuZCBhIHJ1bm5hYmxlLWJ1dC1iZWxvdy1yZWNvbW1lbmRlZFxuICogaW5zdGFsbGVyIGxvZ3MgYSB3YXJuaW5nLiBUaGUgdmVyZGljdCBpcyB0aHJlYWRlZCBvbnRvIHRoZSByZXR1cm5lZCBjb25maWcgc29cbiAqIHRoZSB0cmFuc3BvcnQgY2FuIHN1cmZhY2UgaXQgYXMgZGF0YS5cbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIENEUCB0cmFuc3BvcnQgb3B0aW9ucy5cbiAqIEByZXR1cm5zIFRoZSByZXNvbHZlZCBvd25lZC1pbnN0YW5jZSBjb25maWcuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVPd25lZEluc3RhbmNlQ29uZmlnKG9wdGlvbnM/OiBPYnNpZGlhbkNkcFRyYW5zcG9ydE9wdGlvbnMpOiBQcm9taXNlPE93bmVkSW5zdGFuY2VDb25maWc+IHtcbiAgLy8gUmVzb2x2ZSB0aGUgY29uY3JldGUgc2hlbGwgKGluc3RhbGxlcikgdmVyc2lvbiBmaXJzdCwgYnV0IGZvciBhIHBpbm5lZFxuICAvLyBJbnN0YWxsZXIgREVGRVIgcmVzb2x2aW5nL2Rvd25sb2FkaW5nIHRoZSBhY3R1YWwgc2hlbGwgdW50aWwgYWZ0ZXIgdGhlXG4gIC8vIFByb2FjdGl2ZSBjb21wYXRpYmlsaXR5IGNoZWNrLCBzbyBhbiB1bnJ1bm5hYmxlIHBpbiBmYWlscyBmYXN0IFx1MjAxNCBiZWZvcmUgdGhlXG4gIC8vIChwb3NzaWJseSBzbG93KSBpbnN0YWxsZWQtc2hlbGwgZGV0ZWN0aW9uIGFuZCBhbnkgZG93bmxvYWQuXG4gIGxldCBleGVQYXRoOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGxldCBzaGVsbFZlcnNpb246IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgbGV0IHBpbm5lZEluc3RhbGxlclZlcnNpb246IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICBpZiAob3B0aW9ucz8ub2JzaWRpYW5JbnN0YWxsZXJWZXJzaW9uID09PSB1bmRlZmluZWQpIHtcbiAgICBleGVQYXRoID0gYXdhaXQgcmVzb2x2ZU9ic2lkaWFuRXhlY3V0YWJsZSgpO1xuICAgIHNoZWxsVmVyc2lvbiA9IGRldGVjdEluc3RhbGxlZFNoZWxsVmVyc2lvbihleGVQYXRoKTtcbiAgfSBlbHNlIHtcbiAgICAvLyBBIHBpbm5lZCBpbnN0YWxsZXIgdmVyc2lvbiBmdWxseSBkZXRlcm1pbmVzIHRoZSBzaGVsbCB2ZXJzaW9uIHVwIGZyb250LFxuICAgIC8vIFdpdGhvdXQgcmVxdWlyaW5nIGEgbG9jYWxseS1pbnN0YWxsZWQgT2JzaWRpYW4gKGEgQ0kgcnVubmVyIGhhcyBub25lKS5cbiAgICBwaW5uZWRJbnN0YWxsZXJWZXJzaW9uID0gYXdhaXQgcmVzb2x2ZUNvbmNyZXRlVmVyc2lvbihvcHRpb25zLm9ic2lkaWFuSW5zdGFsbGVyVmVyc2lvbik7XG4gICAgc2hlbGxWZXJzaW9uID0gcGlubmVkSW5zdGFsbGVyVmVyc2lvbjtcbiAgfVxuXG4gIC8vIERlY2lkZSBob3cgdGhlIGFwcCAoYXNhcikgdmVyc2lvbiB3aWxsIGJlIGFwcGxpZWQsIHN0aWxsIFdJVEhPVVQgZG93bmxvYWRpbmcuXG4gIGNvbnN0IHBsYW4gPSBhd2FpdCByZXNvbHZlQXNhclBsYW4ob3B0aW9ucywgc2hlbGxWZXJzaW9uKTtcblxuICAvLyBUaGUgYXBwIHZlcnNpb24gdGhhdCB3aWxsIHJ1biBhcyBhbiBhc2FyLXN3YXAgb250byBgc2hlbGxWZXJzaW9uYCBcdTIwMTQgdGhlIG9ubHlcbiAgLy8gQ29tYmluYXRpb24gdGhhdCBjYW4gZGVhZC1ib290LiBUaGUgZG93bmdyYWRlIC8gb3duLWluc3RhbGxlciBwYXRocyBydW4gdGhlXG4gIC8vIEFwcCdzIG93biBpbnN0YWxsZXIgc2hlbGwsIHNvIHRoZXkgYWx3YXlzIGJvb3QgYW5kIGFyZSBub3QgY2hlY2tlZC5cbiAgY29uc3Qgc3dhcEFwcFZlcnNpb24gPSBwbGFuLmFzYXJWZXJzaW9uVG9Td2FwID8/IHBsYW4uYXNhcj8udmVyc2lvbjtcbiAgY29uc3QgY29tcGF0aWJpbGl0eSA9IHJlc29sdmVBbmRSZXBvcnRDb21wYXRpYmlsaXR5KHtcbiAgICBhcHBWZXJzaW9uOiBzd2FwQXBwVmVyc2lvbixcbiAgICBpbnN0YWxsZXJWZXJzaW9uOiBzaGVsbFZlcnNpb24sXG4gICAgc2hvdWxkVGhyb3dPbkluY29tcGF0aWJsZUluc3RhbGxlcjogd2lsbFRocm93T25JbmNvbXBhdGlibGVJbnN0YWxsZXIob3B0aW9ucz8uc2hvdWxkVGhyb3dPbkluY29tcGF0aWJsZUluc3RhbGxlciksXG4gICAgc2hvdWxkV2Fybk9uQ29tcGF0aWJpbGl0eUlzc3Vlczogd2lsbFdhcm5PbkNvbXBhdGliaWxpdHlJc3N1ZXMob3B0aW9ucz8uc2hvdWxkV2Fybk9uQ29tcGF0aWJpbGl0eUlzc3VlcylcbiAgfSk7XG5cbiAgLy8gVGhlIHBpbiBpcyBrbm93biBydW5uYWJsZSBcdTIwMTQgcmVzb2x2ZS9kb3dubG9hZCB0aGUgZGVmZXJyZWQgc2hlbGwgKyBhc2FyIG5vdy5cbiAgLy8gUmV1c2UgdGhlIGluc3RhbGxlZCBzaGVsbCBvbmx5IHdoZW4gaXQgYWxyZWFkeSBtYXRjaGVzIHRoZSBwaW4gKHNhdmVzIHRoZVxuICAvLyBEb3dubG9hZCk7IG90aGVyd2lzZSBkb3dubG9hZCBhbmQgZXh0cmFjdCB0aGUgcGlubmVkIGluc3RhbGxlci5cbiAgaWYgKHBpbm5lZEluc3RhbGxlclZlcnNpb24gIT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IGluc3RhbGxlZCA9IGF3YWl0IHJlc29sdmVJbnN0YWxsZWRTaGVsbE9yTnVsbCgpO1xuICAgIGV4ZVBhdGggPSBpbnN0YWxsZWQ/LnNoZWxsVmVyc2lvbiA9PT0gcGlubmVkSW5zdGFsbGVyVmVyc2lvbiA/IGluc3RhbGxlZC5leGVQYXRoIDogYXdhaXQgZW5zdXJlU2hlbGxDYWNoZWQocGlubmVkSW5zdGFsbGVyVmVyc2lvbik7XG4gIH1cbiAgaWYgKHBsYW4uZG93bmdyYWRlSW5zdGFsbGVyVmVyc2lvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgZXhlUGF0aCA9IGF3YWl0IGVuc3VyZVNoZWxsQ2FjaGVkKHBsYW4uZG93bmdyYWRlSW5zdGFsbGVyVmVyc2lvbik7XG4gIH1cblxuICBjb25zdCBhc2FyID0gcGxhbi5hc2FyVmVyc2lvblRvU3dhcCA9PT0gdW5kZWZpbmVkXG4gICAgPyBwbGFuLmFzYXJcbiAgICA6IHsgcGF0aDogYXdhaXQgZW5zdXJlQXNhckNhY2hlZChwbGFuLmFzYXJWZXJzaW9uVG9Td2FwKSwgdmVyc2lvbjogcGxhbi5hc2FyVmVyc2lvblRvU3dhcCB9O1xuXG4gIHJldHVybiB7XG4gICAgLi4uKGFzYXIgJiYgeyBhc2FyIH0pLFxuICAgIC4uLihjb21wYXRpYmlsaXR5ICYmIHsgY29tcGF0aWJpbGl0eSB9KSxcbiAgICBleGVQYXRoOiBlbnN1cmVOb25OdWxsYWJsZShleGVQYXRoKSxcblxuICAgIHVzZXJEYXRhRGlyZWN0b3J5OiBjcmVhdGVPd25lZFVzZXJEYXRhRGlyZWN0b3J5KClcbiAgfTtcbn1cblxuLyoqXG4gKiBSZW1vdmVzIGBDb25uZWN0aW9uYCBhbmQgYENvbnRlbnQtTGVuZ3RoYCBmcm9tIGEgV2ViRHJpdmVyIHJlcXVlc3QncyBoZWFkZXJzLlxuICpcbiAqIFRoZSBidW5kbGVkIGB3ZWJkcml2ZXJgIHBhY2thZ2Ugc2V0cyBib3RoIGhlYWRlcnMgZXhwbGljaXRseS4gVGhleSBhcmVcbiAqIGZvcmJpZGRlbiByZXF1ZXN0IGhlYWRlcnMgcGVyIHRoZSBGZXRjaCBzcGVjOiBOb2RlIHVwIHRvIDI1IGFjY2VwdGVkIHRoZW1cbiAqIHNpbGVudGx5LCBidXQgTm9kZSAyNiByZWplY3RzIHRoZW0gd2l0aCBgVU5EX0VSUl9JTlZBTElEX0FSR2AsIGJyZWFraW5nIHRoZVxuICogQXBwaXVtIGAvc2Vzc2lvbmAgcmVxdWVzdC4gVGhlIHRyYW5zcG9ydCBsYXllciBtYW5hZ2VzIGNvbm5lY3Rpb24gcmV1c2UgYW5kXG4gKiB0aGUgRmV0Y2ggQVBJIGNvbXB1dGVzIGBDb250ZW50LUxlbmd0aGAgZnJvbSB0aGUgYm9keSwgc28gZHJvcHBpbmcgYm90aCBpc1xuICogc2FmZSBvbiBldmVyeSBOb2RlIHZlcnNpb24uIFNlZSB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL3dlYmRyaXZlcmlvL3dlYmRyaXZlcmlvL2lzc3Vlcy8xNTI2NX0uXG4gKlxuICogQHBhcmFtIHJlcXVlc3RPcHRpb25zIC0gVGhlIHJlcXVlc3Qgb3B0aW9ucyBhYm91dCB0byBiZSBzZW50IGJ5IFdlYkRyaXZlcklPLlxuICogQHJldHVybnMgVGhlIHNhbWUgcmVxdWVzdCBvcHRpb25zIHdpdGggdGhlIGZvcmJpZGRlbiBoZWFkZXJzIHJlbW92ZWQuXG4gKi9cbmZ1bmN0aW9uIHN0cmlwRm9yYmlkZGVuRmV0Y2hIZWFkZXJzKHJlcXVlc3RPcHRpb25zOiBSZXF1ZXN0SW5pdCk6IFJlcXVlc3RJbml0IHtcbiAgaWYgKHJlcXVlc3RPcHRpb25zLmhlYWRlcnMgaW5zdGFuY2VvZiBIZWFkZXJzKSB7XG4gICAgcmVxdWVzdE9wdGlvbnMuaGVhZGVycy5kZWxldGUoJ0Nvbm5lY3Rpb24nKTtcbiAgICByZXF1ZXN0T3B0aW9ucy5oZWFkZXJzLmRlbGV0ZSgnQ29udGVudC1MZW5ndGgnKTtcbiAgfVxuXG4gIHJldHVybiByZXF1ZXN0T3B0aW9ucztcbn1cblxuLyogdjggaWdub3JlIHN0b3AgKi9cbiJdLAogICJtYXBwaW5ncyI6ICJBQWNBO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQLE9BQU8sVUFBVTtBQUNqQjtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQLFNBQVMsWUFBWTtBQUNyQixPQUFPLGFBQWE7QUFvQnBCO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsU0FBUyxpQ0FBaUM7QUFDMUM7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1A7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFDUDtBQUFBLEVB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
|