@cartanova/qgrid-cli 2.3.2 → 2.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +94 -278
  2. package/bundle/dist/application/qgrid/qgrid.frame.js +15 -5
  3. package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +33 -12
  4. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +42 -98
  5. package/bundle/dist/utils/providers/anthropic/claude-session.js +54 -32
  6. package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +7 -37
  7. package/bundle/dist/utils/providers/common/model-cost.js +3 -2
  8. package/bundle/dist/utils/providers/openai/codex-worker.js +1 -2
  9. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +19 -12
  10. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +235 -7
  11. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +152 -364
  12. package/bundle/src/application/qgrid/qgrid.frame.ts +38 -23
  13. package/bundle/src/utils/providers/anthropic/anthropic-constants.test.ts +60 -0
  14. package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +57 -16
  15. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.test.ts +92 -340
  16. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +61 -188
  17. package/bundle/src/utils/providers/anthropic/claude-session.test.ts +89 -62
  18. package/bundle/src/utils/providers/anthropic/claude-session.ts +71 -46
  19. package/bundle/src/utils/providers/anthropic/stream-json-adapter.test.ts +74 -30
  20. package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +40 -102
  21. package/bundle/src/utils/providers/common/model-cost.test.ts +19 -1
  22. package/bundle/src/utils/providers/common/model-cost.ts +2 -1
  23. package/bundle/src/utils/providers/common/provider-dispatcher.ts +7 -4
  24. package/bundle/src/utils/providers/openai/codex-worker.ts +2 -8
  25. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +18 -11
  26. package/package.json +1 -1
@@ -1,58 +1,42 @@
1
1
  import "../../../_virtual/_rolldown/runtime.js";
2
- import { canonicalAnthropicModel } from "./anthropic-constants.js";
3
2
  import { getExpiresAt, getRefreshToken } from "../common/credentials.js";
4
3
  import { TokenModel } from "../../../application/token/token.model.js";
5
- import { compatibilityKey, makeAnthropicWorkerId, runClaudeSession } from "./claude-session.js";
4
+ import { assertSupportedOneMillionSuffix, canonicalAnthropicModel } from "./anthropic-constants.js";
5
+ import { makeAnthropicWorkerId, runClaudeSession } from "./claude-session.js";
6
6
  import { getLogger } from "@logtape/logtape";
7
7
  //#region src/utils/providers/anthropic/anthropic-dispatcher.ts
8
8
  /**
9
- * AnthropicDispatcher — Claude(Anthropic) provider 의 ProviderDispatcher 구현.
9
+ * AnthropicDispatcher
10
10
  *
11
- * OpenAIDispatcher 패턴을 미러링하되, worker pool 대신 요청별 fresh spawn(U4 runClaudeSession)을
12
- * 쓴다. 토큰은 자체 풀(Map) 관리하고 least-used round-robin 으로 고른다.
11
+ * OpenAIDispatcher 달리, worker pool 두는 대신 요청별 fresh spawn
12
+ * 토큰은 인메모리(MAP)으로 관리하고 least-used, round-robin 으로 고른다
13
13
  *
14
- * 멀티턴 / 동시성 계약:
15
- * - **eligibility compatibilityKey(system+model+schema)** 판정한다. systemHash 아니다.
16
- * GenerateRequest.reuse 들어오면 threadId(=claude session-id)에 대해 dispatcher-local
17
- * `sessionCompat` 저장해 호환키와 이번 요청 호환키를 비교 일치 시 resume, 불일치/없음 시
18
- * cold(새 session-id).
19
- * - **compat 는 threadCoord 로 왕복하지 않는다.** sessionCompat 는 이 dispatcher 인스턴스 메모리에만
20
- * 산다(TTL sweep + 토큰 제거 시 정리). threadCoord.systemHash 는 상위 issueConvContext 가 따로
21
- * 채우지만 Anthropic resume eligibility 판정에는 쓰이지 않는다.
22
- * - **락 소유권**: claude session-id 직렬화는 U4 `runClaudeSession` 이 단독 소유한다.
23
- * dispatcher 는 resume eligibility / token ownership 만 판정하고 `withSessionLock` 으로 감싸지 않는다.
24
- * 여기서 다시 감싸면 U4 내부 락과 같은 session-id 로 재진입해 deadlock 이 난다.
25
- * cold 첫 호출 경쟁을 따로 막지 않는 근거는 run() 의 락 주석 참조(IF/owner scope 의 순차 호출 전제).
26
- * - 발급한 session-id 와 호환키를 GenerateResult.threadCoord(threadId=session-id, workerId=tokenId,
27
- * epoch=0)로 올려, 상위(issueConvContext)가 클라에 회송할 좌표를 만든다.
14
+ * - 모든 요청은 fresh `--session-id` 로 실행
15
+ * - 멀티턴 문맥은 클라이언트가 호출 보내는 full history 를 평탄화해 전달한다.
16
+ * - 발급한 session-id 를 GenerateResult.threadCoord(threadId=session-id, workerId=tokenId,
17
+ * epoch=0)로 올려, 상위(issueConvContext)가 클라에 회송할 좌표를 만든다. 다음 turn 좌표를
18
+ * 회송해도 Anthropic 라우팅에는 쓰지 않는다.
28
19
  */
29
20
  const logger = getLogger(["qgrid", "anthropic-dispatcher"]);
30
- const DEFAULT_TIMEOUT_MS = 12e4;
21
+ const DEFAULT_TIMEOUT_MS = 24e4;
31
22
  const REFRESH_SAFETY_MS = 6e4;
32
- const ANTHROPIC_PROVIDER = "anthropic";
33
- const SESSION_COMPAT_TTL_MS = 600 * 1e3;
34
- function isRetryableResumeFailure(error) {
35
- const lower = (error instanceof Error ? error.message : String(error)).toLowerCase();
36
- if (lower.includes("timeout") || lower.includes("aborted") || lower.includes("spawn error") || lower.includes("quota") || lower.includes("you've hit") || lower.includes("unauthorized") || lower.includes("authentication") || lower.includes("invalid oauth") || lower.includes("permission denied") || lower.includes("max_turns") || lower.includes("max-turns") || lower.includes("schema") || lower.includes("model_error") || lower.includes("model error")) return false;
37
- return lower.includes("closed without result") || /\b(resume|transcript)\b/.test(lower);
38
- }
39
23
  var AnthropicDispatcher = class {
40
24
  tokenPool = /* @__PURE__ */ new Map();
41
25
  requestCounts = /* @__PURE__ */ new Map();
42
26
  rrIndex = 0;
43
- sessionCompat = /* @__PURE__ */ new Map();
44
27
  async start() {
45
28
  const tokens = await TokenModel.findActiveByProvider("A", "anthropic");
46
- for (const t of tokens) this.tokenPool.set(t.id, {
47
- id: t.id,
48
- name: t.name,
49
- credentials: t.credentials
50
- });
51
- logger.info(`anthropic dispatcher started (${this.tokenPool.size} tokens)`);
29
+ for (const t of tokens) {
30
+ this.tokenPool.set(t.id, {
31
+ id: t.id,
32
+ name: t.name,
33
+ credentials: t.credentials
34
+ });
35
+ logger.info(`worker spawned: ${t.name}`);
36
+ }
52
37
  }
53
38
  async stop() {
54
39
  this.tokenPool.clear();
55
- this.sessionCompat.clear();
56
40
  this.requestCounts.clear();
57
41
  this.rrIndex = 0;
58
42
  }
@@ -74,8 +58,6 @@ var AnthropicDispatcher = class {
74
58
  });
75
59
  }
76
60
  onTokenUpdated(id, name, credentials) {
77
- const existing = this.tokenPool.get(id);
78
- if (existing !== void 0 && existing.credentials.accountUuid !== credentials.accountUuid) this.clearSessionCompatFor(id);
79
61
  this.tokenPool.set(id, {
80
62
  id,
81
63
  name,
@@ -85,10 +67,6 @@ var AnthropicDispatcher = class {
85
67
  onTokenRemoved(id) {
86
68
  this.tokenPool.delete(id);
87
69
  this.requestCounts.delete(id);
88
- this.clearSessionCompatFor(id);
89
- }
90
- clearSessionCompatFor(tokenId) {
91
- for (const [sid, e] of this.sessionCompat) if (e.tokenId === tokenId) this.sessionCompat.delete(sid);
92
70
  }
93
71
  countOf(id) {
94
72
  return this.requestCounts.get(id) ?? 0;
@@ -102,46 +80,27 @@ var AnthropicDispatcher = class {
102
80
  this.rrIndex++;
103
81
  return this.charge(picked);
104
82
  }
105
- pickToken(id) {
106
- const token = this.tokenPool.get(id);
107
- return token ? this.charge(token) : null;
108
- }
109
83
  charge(token) {
110
84
  this.requestCounts.set(token.id, this.countOf(token.id) + 1);
111
85
  return token;
112
86
  }
113
- sweepSessionCompat() {
114
- const now = Date.now();
115
- for (const [sid, e] of this.sessionCompat) if (now - e.lastUsedAt > SESSION_COMPAT_TTL_MS) this.sessionCompat.delete(sid);
116
- }
117
87
  async generate(req) {
118
88
  return this.run(req, () => {});
119
89
  }
120
90
  async generateStream(req, cb) {
121
91
  try {
122
- const result = await this.run(req, cb.onDelta);
92
+ const result = await this.run(req, cb.onDelta, { includePartialMessages: true });
123
93
  cb.onThreadId?.(result.threadCoord.threadId);
124
94
  cb.onComplete(result);
125
95
  } catch (e) {
126
96
  cb.onError(e);
127
97
  }
128
98
  }
129
- async run(req, onDelta) {
130
- this.sweepSessionCompat();
99
+ async run(req, onDelta, opts) {
100
+ assertSupportedOneMillionSuffix(req.model);
131
101
  const model = canonicalAnthropicModel(req.model);
132
102
  const jsonSchema = req.outputSchema !== void 0 ? JSON.stringify(req.outputSchema) : void 0;
133
- const compat = compatibilityKey({
134
- system: req.systemPrompt,
135
- model,
136
- outputSchema: jsonSchema
137
- });
138
- const candidate = req.reuse?.threadId;
139
- const stored = candidate !== void 0 ? this.sessionCompat.get(candidate) : void 0;
140
- const ownerMatches = stored !== void 0 && stored.tokenId === req.reuse?.workerId;
141
- const resumeToken = stored?.compat === compat && ownerMatches ? this.pickToken(stored.tokenId) : null;
142
- const isResume = resumeToken !== null;
143
- const resumeSessionId = isResume ? candidate : void 0;
144
- const token = resumeToken ?? this.selectToken();
103
+ const token = this.selectToken();
145
104
  if (!token) throw new Error("No anthropic tokens available");
146
105
  const exec = async () => {
147
106
  let accessToken = token.credentials.accessToken;
@@ -150,48 +109,33 @@ var AnthropicDispatcher = class {
150
109
  const { QgridFrame } = await import("../../../application/qgrid/qgrid.frame.js");
151
110
  accessToken = await QgridFrame.refreshToken({
152
111
  id: token.id,
153
- provider: ANTHROPIC_PROVIDER,
112
+ provider: "anthropic",
154
113
  name: token.name,
155
114
  credentials: token.credentials
156
115
  });
157
116
  } catch (e) {
158
117
  logger.warn(`refresh failed for ${token.name}: ${e.message}`);
159
118
  }
160
- const runSession = (resume) => {
161
- logger.info(`→ ${token.name} (model: ${model}, ${resume ? "resume" : "cold"})`);
162
- return runClaudeSession({
163
- tokenId: token.id,
164
- token: accessToken,
165
- model,
166
- system: req.systemPrompt,
167
- jsonSchema,
168
- effort: req.effort,
169
- timeoutMs: DEFAULT_TIMEOUT_MS,
170
- coldHistory: resume ? void 0 : req.coldHistory,
171
- input: resume && req.reuseInput ? req.reuseInput : req.coldInput,
172
- resumeSessionId: resume ? resumeSessionId : void 0,
173
- abortSignal: req.abortSignal
174
- }, onDelta);
175
- };
176
- let session;
177
- try {
178
- session = await runSession(isResume);
179
- } catch (e) {
180
- if (!isResume || !isRetryableResumeFailure(e)) throw e;
181
- if (candidate) this.sessionCompat.delete(candidate);
182
- logger.warn(`resume failed for ${token.name}; retrying cold once: ${e.message}`);
183
- session = await runSession(false);
184
- }
119
+ logger.info(`→ ${token.name} (model: ${model})`);
120
+ const session = await runClaudeSession({
121
+ tokenId: token.id,
122
+ token: accessToken,
123
+ model,
124
+ system: req.systemPrompt,
125
+ jsonSchema,
126
+ effort: req.effort,
127
+ timeoutMs: DEFAULT_TIMEOUT_MS,
128
+ coldHistory: req.coldHistory,
129
+ input: req.coldInput,
130
+ abortSignal: req.abortSignal,
131
+ includePartialMessages: opts?.includePartialMessages
132
+ }, onDelta);
185
133
  if (session.quotaExhausted) throw new Error(`quota exhausted (${token.name})`);
186
134
  if (session.isError) {
187
- const detail = session.text || `empty text, outputTokens=${session.usage.outputTokens}`;
188
- throw new Error(`claude error (${token.name}): ${detail}`);
135
+ const reason = session.subtype ?? session.terminalReason ?? (session.isError ? "is_error" : "unknown");
136
+ const body = session.text ? session.text.length > 500 ? `${session.text.slice(0, 500)}…(${session.text.length} chars)` : session.text : `empty text, outputTokens=${session.usage.outputTokens}`;
137
+ throw new Error(`claude error (${token.name}) [${reason}]: ${body}`);
189
138
  }
190
- this.sessionCompat.set(session.sessionId, {
191
- compat,
192
- tokenId: token.id,
193
- lastUsedAt: Date.now()
194
- });
195
139
  return {
196
140
  text: session.text,
197
141
  tokenName: token.name,
@@ -212,4 +156,4 @@ var AnthropicDispatcher = class {
212
156
  //#endregion
213
157
  export { AnthropicDispatcher };
214
158
 
215
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW50aHJvcGljLWRpc3BhdGNoZXIuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Byb3ZpZGVycy9hbnRocm9waWMvYW50aHJvcGljLWRpc3BhdGNoZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBbnRocm9waWNEaXNwYXRjaGVyIOKAlCBDbGF1ZGUoQW50aHJvcGljKSBwcm92aWRlciDsnZggUHJvdmlkZXJEaXNwYXRjaGVyIOq1rO2YhC5cbiAqXG4gKiBPcGVuQUlEaXNwYXRjaGVyIO2MqO2EtOydhCDrr7jrn6zrp4HtlZjrkJgsIHdvcmtlciBwb29sIOuMgOyLoCDsmpTssq3rs4QgZnJlc2ggc3Bhd24oVTQgcnVuQ2xhdWRlU2Vzc2lvbinsnYRcbiAqIOyTtOuLpC4g7Yag7YGw7J2AIOyekOyytCDtkoAoTWFwKeuhnCDqtIDrpqztlZjqs6AgbGVhc3QtdXNlZCByb3VuZC1yb2JpbiDsnLzroZwg6rOg66W464ukLlxuICpcbiAqIOupgO2LsO2EtCAvIOuPmeyLnOyEsSDqs4Tslb06XG4gKiAgLSAqKmVsaWdpYmlsaXR5IOuKlCBjb21wYXRpYmlsaXR5S2V5KHN5c3RlbSttb2RlbCtzY2hlbWEpKiog66GcIO2MkOygle2VnOuLpC4gc3lzdGVtSGFzaCDqsIAg7JWE64uI64ukLlxuICogICAgR2VuZXJhdGVSZXF1ZXN0LnJldXNlIOqwgCDrk6TslrTsmKTrqbQg6re4IHRocmVhZElkKD1jbGF1ZGUgc2Vzc2lvbi1pZCnsl5Ag64yA7ZW0IGRpc3BhdGNoZXItbG9jYWxcbiAqICAgIGBzZXNzaW9uQ29tcGF0YCDsl5Ag7KCA7J6l7ZW0IOuRlCDtmLjtmZjtgqTsmYAg7J2067KIIOyalOyyrSDtmLjtmZjtgqTrpbwg67mE6rWQIOKAlCDsnbzsuZgg7IucIHJlc3VtZSwg67aI7J287LmYL+yXhuydjCDsi5xcbiAqICAgIGNvbGQo7IOIIHNlc3Npb24taWQpLlxuICogIC0gKipjb21wYXQg64qUIHRocmVhZENvb3JkIOuhnCDsmZXrs7XtlZjsp4Ag7JWK64qU64ukLioqIHNlc3Npb25Db21wYXQg64qUIOydtCBkaXNwYXRjaGVyIOyduOyKpO2EtOyKpCDrqZTrqqjrpqzsl5Drp4xcbiAqICAgIOyCsOuLpChUVEwgc3dlZXAgKyDthqDtgbAg7KCc6rGwIOyLnCDsoJXrpqwpLiB0aHJlYWRDb29yZC5zeXN0ZW1IYXNoIOuKlCDsg4HsnIQgaXNzdWVDb252Q29udGV4dCDqsIAg65Sw66GcXG4gKiAgICDssYTsmrDsp4Drp4wgQW50aHJvcGljIHJlc3VtZSBlbGlnaWJpbGl0eSDtjJDsoJXsl5DripQg7JOw7J207KeAIOyViuuKlOuLpC5cbiAqICAtICoq6529IOyGjOycoOq2jCoqOiBjbGF1ZGUgc2Vzc2lvbi1pZCDsp4HroKztmZTripQgVTQgYHJ1bkNsYXVkZVNlc3Npb25gIOydtCDri6jrj4Ug7IaM7Jyg7ZWc64ukLlxuICogICAgZGlzcGF0Y2hlciDripQgcmVzdW1lIGVsaWdpYmlsaXR5IC8gdG9rZW4gb3duZXJzaGlwIOunjCDtjJDsoJXtlZjqs6AgYHdpdGhTZXNzaW9uTG9ja2Ag7Jy866GcIOqwkOyLuOyngCDslYrripTri6QuXG4gKiAgICDsl6zquLDshJwg64uk7IucIOqwkOyLuOuptCBVNCDrgrTrtoAg65296rO8IOqwmeydgCBzZXNzaW9uLWlkIOuhnCDsnqzsp4TsnoXtlbQgZGVhZGxvY2sg7J20IOuCnOuLpC5cbiAqICAgIGNvbGQg7LKrIO2YuOy2nCDqsr3sn4HsnYQg65Sw66GcIOunieyngCDslYrripQg6re86rGw64qUIHJ1bigpIOydmCDrnb0g7KO87ISdIOywuOyhsChJRi9vd25lciBzY29wZSDsnZgg7Iic7LCoIO2YuOy2nCDsoITsoJwpLlxuICogIC0g67Cc6riJ7ZWcIHNlc3Npb24taWQg7JmAIO2YuO2ZmO2CpOulvCBHZW5lcmF0ZVJlc3VsdC50aHJlYWRDb29yZCh0aHJlYWRJZD1zZXNzaW9uLWlkLCB3b3JrZXJJZD10b2tlbklkLFxuICogICAgZXBvY2g9MCnroZwg7Jis66CkLCDsg4HsnIQoaXNzdWVDb252Q29udGV4dCnqsIAg7YG065287JeQIO2ajOyGoe2VoCDsooztkZzrpbwg66eM65Og64ukLlxuICovXG5cbmltcG9ydCB7IGdldExvZ2dlciB9IGZyb20gXCJAbG9ndGFwZS9sb2d0YXBlXCI7XG5cbmltcG9ydCB7IFRva2VuTW9kZWwgfSBmcm9tIFwiLi4vLi4vLi4vYXBwbGljYXRpb24vdG9rZW4vdG9rZW4ubW9kZWxcIjtcbmltcG9ydCB7IHR5cGUgQW50aHJvcGljQ3JlZGVudGlhbHMgfSBmcm9tIFwiLi4vLi4vLi4vYXBwbGljYXRpb24vdG9rZW4vdG9rZW4udHlwZXNcIjtcbmltcG9ydCB7IGdldEV4cGlyZXNBdCwgZ2V0UmVmcmVzaFRva2VuIH0gZnJvbSBcIi4uL2NvbW1vbi9jcmVkZW50aWFsc1wiO1xuaW1wb3J0IHtcbiAgdHlwZSBHZW5lcmF0ZVJlcXVlc3QsXG4gIHR5cGUgR2VuZXJhdGVSZXN1bHQsXG4gIHR5cGUgR2VuZXJhdGVTdHJlYW1DYWxsYmFja3MsXG4gIHR5cGUgUHJvdmlkZXJEaXNwYXRjaGVyLFxufSBmcm9tIFwiLi4vY29tbW9uL3Byb3ZpZGVyLWRpc3BhdGNoZXJcIjtcbmltcG9ydCB7IGNhbm9uaWNhbEFudGhyb3BpY01vZGVsIH0gZnJvbSBcIi4vYW50aHJvcGljLWNvbnN0YW50c1wiO1xuaW1wb3J0IHsgY29tcGF0aWJpbGl0eUtleSwgbWFrZUFudGhyb3BpY1dvcmtlcklkLCBydW5DbGF1ZGVTZXNzaW9uIH0gZnJvbSBcIi4vY2xhdWRlLXNlc3Npb25cIjtcblxuY29uc3QgbG9nZ2VyID0gZ2V0TG9nZ2VyKFtcInFncmlkXCIsIFwiYW50aHJvcGljLWRpc3BhdGNoZXJcIl0pO1xuXG5jb25zdCBERUZBVUxUX1RJTUVPVVRfTVMgPSAxMjBfMDAwO1xuLy8gYWNjZXNzIHRva2VuIOunjOujjCDsnoTrsJUg7J6E6rOEIOKAlCDquLDsobQgc3RhbmRhbG9uZSDqsr3roZwocWdyaWQuZGlzcGF0Y2hlci50cynsmYAg64+Z7J28KDYwcykuXG5jb25zdCBSRUZSRVNIX1NBRkVUWV9NUyA9IDYwXzAwMDtcblxuaW50ZXJmYWNlIFBvb2xlZFRva2VuIHtcbiAgaWQ6IG51bWJlcjtcbiAgbmFtZTogc3RyaW5nO1xuICBjcmVkZW50aWFsczogQW50aHJvcGljQ3JlZGVudGlhbHM7XG59XG5cbi8vIFFncmlkRnJhbWUucmVmcmVzaFRva2VuIOydgCBUb2tlblN1YnNldEEo7Yq57Z6IIHByb3ZpZGVyKeulvCDrsJvslYQgVG9rZW5Nb2RlbC5zYXZlIOyXkCDrhJjquLTri6QuXG4vLyBhbnRocm9waWMg7ZKA7J2YIO2GoO2BsOydgCDtla3sg4EgcHJvdmlkZXI9XCJhbnRocm9waWNcIiDsnbTrr4DroZwgcmVmcmVzaCDsi5wg7J20IOqwkuydhCDqs6DsoJXsnLzroZwg7LGE7Jq064ukLlxuLy8gKHByb3ZpZGVyIOuIhOudvSDsi5wgc2F2ZSDsi6TtjKgg4oaSIOunjOujjOuQnCBhY2Nlc3MgdG9rZW4g7Jy866GcIOynhO2Wie2VmOuKlCDrsoTqt7jqsIAg64Kc64ukLilcbmNvbnN0IEFOVEhST1BJQ19QUk9WSURFUiA9IFwiYW50aHJvcGljXCIgYXMgY29uc3Q7XG5cbi8vIHNlc3Npb24taWQg4oaSIGNvbXBhdCDrp6TtlZEgVFRMLiDshJzrsoQgdGhyZWFkIGlkbGUgVFRMKDEw67aEKeqzvCDsoJXtlakg4oCUIOq3uOuztOuLpCDsmKTrnpjrkJwg7IS47IWY7J2AXG4vLyDslrTssKjtlLwgcmVzdW1lIOu2iOqwgO2VmOuvgOuhnCDtj5DquLDtlbTrj4Qg7JWI7KCEKHNlc3Npb25Db21wYXQg66y07ZWcIOymneqwgCDrsKnsp4ApLlxuY29uc3QgU0VTU0lPTl9DT01QQVRfVFRMX01TID0gMTAgKiA2MCAqIDEwMDA7XG5cbmludGVyZmFjZSBDb21wYXRFbnRyeSB7XG4gIGNvbXBhdDogc3RyaW5nO1xuICB0b2tlbklkOiBudW1iZXI7XG4gIGxhc3RVc2VkQXQ6IG51bWJlcjtcbn1cblxuZnVuY3Rpb24gaXNSZXRyeWFibGVSZXN1bWVGYWlsdXJlKGVycm9yOiB1bmtub3duKTogYm9vbGVhbiB7XG4gIGNvbnN0IG1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7XG4gIGNvbnN0IGxvd2VyID0gbWVzc2FnZS50b0xvd2VyQ2FzZSgpO1xuICBpZiAoXG4gICAgbG93ZXIuaW5jbHVkZXMoXCJ0aW1lb3V0XCIpIHx8XG4gICAgbG93ZXIuaW5jbHVkZXMoXCJhYm9ydGVkXCIpIHx8XG4gICAgbG93ZXIuaW5jbHVkZXMoXCJzcGF3biBlcnJvclwiKSB8fFxuICAgIGxvd2VyLmluY2x1ZGVzKFwicXVvdGFcIikgfHxcbiAgICBsb3dlci5pbmNsdWRlcyhcInlvdSd2ZSBoaXRcIikgfHxcbiAgICBsb3dlci5pbmNsdWRlcyhcInVuYXV0aG9yaXplZFwiKSB8fFxuICAgIGxvd2VyLmluY2x1ZGVzKFwiYXV0aGVudGljYXRpb25cIikgfHxcbiAgICBsb3dlci5pbmNsdWRlcyhcImludmFsaWQgb2F1dGhcIikgfHxcbiAgICBsb3dlci5pbmNsdWRlcyhcInBlcm1pc3Npb24gZGVuaWVkXCIpIHx8XG4gICAgbG93ZXIuaW5jbHVkZXMoXCJtYXhfdHVybnNcIikgfHxcbiAgICBsb3dlci5pbmNsdWRlcyhcIm1heC10dXJuc1wiKSB8fFxuICAgIGxvd2VyLmluY2x1ZGVzKFwic2NoZW1hXCIpIHx8XG4gICAgbG93ZXIuaW5jbHVkZXMoXCJtb2RlbF9lcnJvclwiKSB8fFxuICAgIGxvd2VyLmluY2x1ZGVzKFwibW9kZWwgZXJyb3JcIilcbiAgKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiBsb3dlci5pbmNsdWRlcyhcImNsb3NlZCB3aXRob3V0IHJlc3VsdFwiKSB8fCAvXFxiKHJlc3VtZXx0cmFuc2NyaXB0KVxcYi8udGVzdChsb3dlcik7XG59XG5cbmV4cG9ydCBjbGFzcyBBbnRocm9waWNEaXNwYXRjaGVyIGltcGxlbWVudHMgUHJvdmlkZXJEaXNwYXRjaGVyIHtcbiAgLy8gdG9rZW5JZCDihpIg7ZKAIO2VreuqqS4gc3RhcnQoKS90b2tlbiDsnbTrsqTtirjroZwg7LGE7Jq064ukLlxuICBwcml2YXRlIHRva2VuUG9vbCA9IG5ldyBNYXA8bnVtYmVyLCBQb29sZWRUb2tlbj4oKTtcbiAgLy8gdG9rZW5JZCDrs4Qg7IKs7JqpIOy5tOyatO2EsChsZWFzdC11c2VkIFJSKS4gbmFtZSDsnbQg7JWE64uI6528IGlkIOq4sOykgCDigJQg7J2066aEIOy2qeuPjCDslYjsoIQuXG4gIHByaXZhdGUgcmVxdWVzdENvdW50cyA9IG5ldyBNYXA8bnVtYmVyLCBudW1iZXI+KCk7XG4gIHByaXZhdGUgcnJJbmRleCA9IDA7XG4gIC8vIGNsYXVkZSBzZXNzaW9uLWlkIOKGkiDqt7gg7IS47IWY7J2EIOunjOuToCDsmpTssq3snZgg7Zi47ZmY7YKkKCt0b2tlbklkL2xhc3RVc2VkQXQpLiByZXN1bWUgZWxpZ2liaWxpdHkg7YyQ7KCVLlxuICAvLyBUVEwgc3dlZXAgKyDthqDtgbAg7KCc6rGwIOyLnCDsoJXrpqzroZwg66y07ZWcIOymneqwgCDrsKnsp4AuXG4gIHByaXZhdGUgc2Vzc2lvbkNvbXBhdCA9IG5ldyBNYXA8c3RyaW5nLCBDb21wYXRFbnRyeT4oKTtcblxuICAvLyDilIDilIAgbGlmZWN5Y2xlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIGFzeW5jIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIE9wZW5BSURpc3BhdGNoZXIuc3RhcnQoKSDsmYAg64+Z7J287ZWY6rKMIERCIOyXkOyEnCDquLDsobQgYW50aHJvcGljIO2GoO2BsOydhCBzZWxmLWJvb3RzdHJhcCDtlZzri6QuXG4gICAgLy8gKOyEnOuyhCDsnqzsi5zsnpEg7IucIE5PVElGWSDqsIAg7JWIIOyYpOuvgOuhnCDrtoDtirjsiqTtirjrnqnsnbQg7JeG7Jy866m0IO2SgOydtCDruYgg7LGE66GcIOuCqOuKlOuLpC4pXG4gICAgLy8g7J207ZuEIOuzgOqyveu2hOydgCB0b2tlbi1zdWJzY3JpYmVyIOqwgCBvblRva2VuQWRkZWQvVXBkYXRlZC9SZW1vdmVkIOuhnCDsoITri6ztlZzri6QuXG4gICAgLy8gZmluZEFjdGl2ZUJ5UHJvdmlkZXIg6rCAIGFjdGl2ZT10cnVlICsgcHJvdmlkZXIg7ZWE7YSw66W8IERCIOyXkOyEnCDsspjrpqwg4oaSIGluYWN0aXZlIOuKlCDslaDstIjsl5Ag7JWIIOyYqOuLpC5cbiAgICBjb25zdCB0b2tlbnMgPSBhd2FpdCBUb2tlbk1vZGVsLmZpbmRBY3RpdmVCeVByb3ZpZGVyKFwiQVwiLCBcImFudGhyb3BpY1wiKTtcbiAgICBmb3IgKGNvbnN0IHQgb2YgdG9rZW5zKSB7XG4gICAgICB0aGlzLnRva2VuUG9vbC5zZXQodC5pZCwge1xuICAgICAgICBpZDogdC5pZCxcbiAgICAgICAgbmFtZTogdC5uYW1lLFxuICAgICAgICBjcmVkZW50aWFsczogdC5jcmVkZW50aWFscyBhcyBBbnRocm9waWNDcmVkZW50aWFscyxcbiAgICAgIH0pO1xuICAgIH1cbiAgICBsb2dnZXIuaW5mbyhgYW50aHJvcGljIGRpc3BhdGNoZXIgc3RhcnRlZCAoJHt0aGlzLnRva2VuUG9vbC5zaXplfSB0b2tlbnMpYCk7XG4gIH1cblxuICBhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMudG9rZW5Qb29sLmNsZWFyKCk7XG4gICAgdGhpcy5zZXNzaW9uQ29tcGF0LmNsZWFyKCk7XG4gICAgLy8gbGlmZWN5Y2xlIOygle2VqTogUlIg7Lm07Jq07YSwL+yduOuNseyKpOuPhCDruYTsm4wgc3RvcOKGknN0YXJ0IOyerOuTseuhnSDsi5wg7J207KCEIOy5tOyatO2KuOqwgCDslYgg64Ko6rKMIO2VnOuLpC5cbiAgICB0aGlzLnJlcXVlc3RDb3VudHMuY2xlYXIoKTtcbiAgICB0aGlzLnJySW5kZXggPSAwO1xuICB9XG5cbiAgLy8g7ZiE7J6sIO2SgOydmCDthqDtgbAg7IiYKHN0YXJ0dXAg66Gc6re4L2hlYWx0aCDsmqkpLlxuICBnZXQgdG9rZW5Db3VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnRva2VuUG9vbC5zaXplO1xuICB9XG5cbiAgLy8gREIgYWN0aXZlIGFudGhyb3BpYyDthqDtgbAg66qp66Gd7Jy866GcIO2SgOydhCDsnqzrj5nquLDtmZTtlZzri6QocGVyaW9kaWMgcmVjb25jaWxlL+yerOyXsOqysOyaqSkuXG4gIC8vIExJU1RFTi9OT1RJRlkg6rCAIOuBiuq4tCDrj5nslYgg7Jyg7Iuk65CcIOy2lOqwgC/sgq3soJwv67mE7Zmc7ISx7ZmU66W8IERCIOq4sOykgOycvOuhnCDri6Tsi5wg66ee7LaY64ukLlxuICAvLyDsnbTrsqTtirgg7ZW465Ok65+s66W8IOyerOyCrOyaqe2VtCBpZGVudGl0eS1jaGFuZ2UgLyBzZXNzaW9uQ29tcGF0IOygleumrOqwgCDsnbzqtIDrkJjqsowg7KCB7Jqp65CY64+E66GdIO2VnOuLpDpcbiAgLy8gIC0gREIg7JeQIOyXhuuKlOuNsCDtkoDsl5Ag7J6I64qUIO2GoO2BsCDihpIgb25Ub2tlblJlbW92ZWQgKGNvbXBhdCDsoJXrpqwg7Y+s7ZWoKVxuICAvLyAgLSBEQiDsl5Ag7J6I64qUIO2GoO2BsCDihpIg7Iug6rec66m0IG9uVG9rZW5BZGRlZCwg6riw7KG07J2066m0IG9uVG9rZW5VcGRhdGVkKGlkZW50aXR5IOuzgOqyvSDqsJDsp4ApXG4gIHJlcGxhY2VUb2tlbnMoXG4gICAgcm93czogQXJyYXk8eyBpZDogbnVtYmVyOyBuYW1lOiBzdHJpbmc7IGNyZWRlbnRpYWxzOiBBbnRocm9waWNDcmVkZW50aWFscyB9PixcbiAgKTogdm9pZCB7XG4gICAgY29uc3QgbmV4dCA9IG5ldyBTZXQocm93cy5tYXAoKHIpID0+IHIuaWQpKTtcbiAgICAvLyBvblRva2VuUmVtb3ZlZCDqsIAgdG9rZW5Qb29sIOydhCBkZWxldGUg7ZWY66+A66GcIOyInO2ajCDspJEg7IiY7KCV7J2EIO2UvO2VmOugpCDtgqTrpbwg66i87KCAIOyKpOuDheyDt+2VnOuLpC5cbiAgICBjb25zdCBjdXJyZW50SWRzID0gQXJyYXkuZnJvbSh0aGlzLnRva2VuUG9vbC5rZXlzKCkpO1xuICAgIGZvciAoY29uc3QgaWQgb2YgY3VycmVudElkcykge1xuICAgICAgaWYgKCFuZXh0LmhhcyhpZCkpIHRoaXMub25Ub2tlblJlbW92ZWQoaWQpO1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IHIgb2Ygcm93cykge1xuICAgICAgaWYgKHRoaXMudG9rZW5Qb29sLmhhcyhyLmlkKSkgdGhpcy5vblRva2VuVXBkYXRlZChyLmlkLCByLm5hbWUsIHIuY3JlZGVudGlhbHMpO1xuICAgICAgZWxzZSB0aGlzLm9uVG9rZW5BZGRlZChyLmlkLCByLm5hbWUsIHIuY3JlZGVudGlhbHMpO1xuICAgIH1cbiAgfVxuXG4gIC8vIOKUgOKUgCB0b2tlbiBldmVudHMgKHRva2VuLXN1YnNjcmliZXIg6rCAIO2YuOy2nCkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgb25Ub2tlbkFkZGVkKGlkOiBudW1iZXIsIG5hbWU6IHN0cmluZywgY3JlZGVudGlhbHM6IEFudGhyb3BpY0NyZWRlbnRpYWxzKTogdm9pZCB7XG4gICAgdGhpcy50b2tlblBvb2wuc2V0KGlkLCB7IGlkLCBuYW1lLCBjcmVkZW50aWFscyB9KTtcbiAgfVxuICBvblRva2VuVXBkYXRlZChpZDogbnVtYmVyLCBuYW1lOiBzdHJpbmcsIGNyZWRlbnRpYWxzOiBBbnRocm9waWNDcmVkZW50aWFscyk6IHZvaWQge1xuICAgIC8vIGFjY2Vzcy9yZWZyZXNoIHRva2VuIHJvdGF0aW9uKOqwmeydgCDqs4TsoJUp7J2066m0IGluLXBsYWNlIOqwseyLoOycvOuhnCDshLjshZjsnYQg7Jyg7KeA7ZWc64ukLlxuICAgIC8vIO2VmOyngOunjCBhY2NvdW50VXVpZCDqsIAg67CU64CQIOyerOuhnOq3uOyduC/qs4TsoJUg6rWQ7LK066m0LCDqsJnsnYAgdG9rZW5JZCDslYTrnpgg7IK07JWE64Ko7J2AIHNlc3Npb25Db21wYXQg6rCAXG4gICAgLy8g7J207KCEIOqzhOygleycvOuhnCDrp4zrk6Agc2Vzc2lvbi1pZCDrpbwg7IOIIOqzhOyglSBjcmVkZW50aWFscyDroZwgcmVzdW1lIOyLnO2CpOuKlCDqsqnrpqwg7JyE67CY7J20IOuQnOuLpC5cbiAgICAvLyBPcGVuQUkgZGlzcGF0Y2hlciDqsIAgbG9naW4gaWRlbnRpdHkg67OA6rK97J2EIHdvcmtlciByZXN0YXJ0IOuhnCDqtazrtoTtlZjripQg6rKD6rO8IOuPmeydvO2VnCDsspjrpqw6XG4gICAgLy8gaWRlbnRpdHkg6rCAIOuwlOuAjOuptCDqt7ggdG9rZW5JZCDsnZgg7IS47IWYIGNvbXBhdCDsnYQg7Y+Q6riw7ZW0IOydtO2bhCDtmLjstpzsnbQgY29sZCDroZwg65ao7Ja07KeA6rKMIO2VnOuLpC5cbiAgICBjb25zdCBleGlzdGluZyA9IHRoaXMudG9rZW5Qb29sLmdldChpZCk7XG4gICAgY29uc3QgaWRlbnRpdHlDaGFuZ2VkID1cbiAgICAgIGV4aXN0aW5nICE9PSB1bmRlZmluZWQgJiYgZXhpc3RpbmcuY3JlZGVudGlhbHMuYWNjb3VudFV1aWQgIT09IGNyZWRlbnRpYWxzLmFjY291bnRVdWlkO1xuICAgIGlmIChpZGVudGl0eUNoYW5nZWQpIHRoaXMuY2xlYXJTZXNzaW9uQ29tcGF0Rm9yKGlkKTtcbiAgICB0aGlzLnRva2VuUG9vbC5zZXQoaWQsIHsgaWQsIG5hbWUsIGNyZWRlbnRpYWxzIH0pO1xuICB9XG4gIG9uVG9rZW5SZW1vdmVkKGlkOiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLnRva2VuUG9vbC5kZWxldGUoaWQpO1xuICAgIHRoaXMucmVxdWVzdENvdW50cy5kZWxldGUoaWQpO1xuICAgIC8vIOydtCDthqDtgbDsnLzroZwg66eM65OgIOyEuOyFmOydmCBjb21wYXQg7JeU7Yq466as64+EIOygleumrC5cbiAgICB0aGlzLmNsZWFyU2Vzc2lvbkNvbXBhdEZvcihpZCk7XG4gIH1cblxuICAvLyDtirnsoJUgdG9rZW5JZCDroZwg66eM65OgIOuqqOuToCBzZXNzaW9uQ29tcGF0IOyXlO2KuOumrCDtj5DquLAo7Yag7YGwIOygnOqxsCAvIGlkZW50aXR5IOuzgOqyvSDsi5wg6rO17Ya1KS5cbiAgcHJpdmF0ZSBjbGVhclNlc3Npb25Db21wYXRGb3IodG9rZW5JZDogbnVtYmVyKTogdm9pZCB7XG4gICAgZm9yIChjb25zdCBbc2lkLCBlXSBvZiB0aGlzLnNlc3Npb25Db21wYXQpIHtcbiAgICAgIGlmIChlLnRva2VuSWQgPT09IHRva2VuSWQpIHRoaXMuc2Vzc2lvbkNvbXBhdC5kZWxldGUoc2lkKTtcbiAgICB9XG4gIH1cblxuICAvLyDilIDilIAgdG9rZW4gc2VsZWN0aW9uIChsZWFzdC11c2VkIFJSLCB0b2tlbklkIOq4sOykgCkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJpdmF0ZSBjb3VudE9mKGlkOiBudW1iZXIpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnJlcXVlc3RDb3VudHMuZ2V0KGlkKSA/PyAwO1xuICB9XG5cbiAgLy8gY29sZCDqsr3roZw6IGxlYXN0LXVzZWQgUlIg66GcIO2GoO2BsOydhCDqs6Drpbjri6Qo64+Z7KCQ7J2066m0IHJySW5kZXgg66GcIO2ajOyghCkuXG4gIHByaXZhdGUgc2VsZWN0VG9rZW4oKTogUG9vbGVkVG9rZW4gfCBudWxsIHtcbiAgICBjb25zdCByb3dzID0gWy4uLnRoaXMudG9rZW5Qb29sLnZhbHVlcygpXTtcbiAgICBpZiAocm93cy5sZW5ndGggPT09IDApIHJldHVybiBudWxsO1xuICAgIGNvbnN0IG1pbkNvdW50ID0gTWF0aC5taW4oLi4ucm93cy5tYXAoKHIpID0+IHRoaXMuY291bnRPZihyLmlkKSkpO1xuICAgIGNvbnN0IGlkbGUgPSByb3dzLmZpbHRlcigocikgPT4gdGhpcy5jb3VudE9mKHIuaWQpID09PSBtaW5Db3VudCk7XG4gICAgY29uc3QgcGlja2VkID0gaWRsZVt0aGlzLnJySW5kZXggJSBpZGxlLmxlbmd0aF0hO1xuICAgIHRoaXMucnJJbmRleCsrO1xuICAgIHJldHVybiB0aGlzLmNoYXJnZShwaWNrZWQpO1xuICB9XG5cbiAgLy8gcmVzdW1lIOqyveuhnDog7IS47IWY7J2EIOunjOuToCDthqDtgbDsnYQgaWQg66GcIOqzoOyglSDshKDtg53tlZzri6QuIO2SgOyXkCDsl4bsnLzrqbQgbnVsbCjihpIgY29sZCBmYWxsYmFjaykuXG4gIC8vIHJlc3VtZSDshLjshZjsnYAg6re4IO2GoO2BsOydmCBDTEFVREVfQ09ORklHX0RJUiDsl5AgdHJhbnNjcmlwdCDqsIAg66y27JesIOyeiOyWtCwg64uk66W4IO2GoO2BsOycvOuhnCByZXN1bWUg7ZWY66m0XG4gIC8vIHRyYW5zY3JpcHQg6rCAIOyXhuyWtCDquajsp4Tri6QuIOq3uOuemOyEnCBSUiDsnYQg7JOw7KeAIOyViuqzoCDshozsnKAg7Yag7YGw7J2EIOq3uOuMgOuhnCDsnqHslYTslbwg7ZWc64ukLlxuICBwcml2YXRlIHBpY2tUb2tlbihpZDogbnVtYmVyKTogUG9vbGVkVG9rZW4gfCBudWxsIHtcbiAgICBjb25zdCB0b2tlbiA9IHRoaXMudG9rZW5Qb29sLmdldChpZCk7XG4gICAgcmV0dXJuIHRva2VuID8gdGhpcy5jaGFyZ2UodG9rZW4pIDogbnVsbDtcbiAgfVxuXG4gIC8vIOyEoO2DneuQnCDthqDtgbDsnZgg7IKs7JqpIOy5tOyatO2KuOulvCBhd2FpdCDsoITsl5Ag7ISg67CY7JiBKOuPmeyLnCDsmpTssq3snbQg64uk66W4IO2GoO2BsOydhCDqs6DrpbTrj4TroZ0pLlxuICBwcml2YXRlIGNoYXJnZSh0b2tlbjogUG9vbGVkVG9rZW4pOiBQb29sZWRUb2tlbiB7XG4gICAgdGhpcy5yZXF1ZXN0Q291bnRzLnNldCh0b2tlbi5pZCwgdGhpcy5jb3VudE9mKHRva2VuLmlkKSArIDEpO1xuICAgIHJldHVybiB0b2tlbjtcbiAgfVxuXG4gIC8vIOunjOujjOuQnCBjb21wYXQg7JeU7Yq466asIOygleumrChsYXp5IHN3ZWVwIOKAlCBnZW5lcmF0ZSDsp4TsnoUg7IucIO2YuOy2nCkuXG4gIHByaXZhdGUgc3dlZXBTZXNzaW9uQ29tcGF0KCk6IHZvaWQge1xuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgZm9yIChjb25zdCBbc2lkLCBlXSBvZiB0aGlzLnNlc3Npb25Db21wYXQpIHtcbiAgICAgIGlmIChub3cgLSBlLmxhc3RVc2VkQXQgPiBTRVNTSU9OX0NPTVBBVF9UVExfTVMpIHRoaXMuc2Vzc2lvbkNvbXBhdC5kZWxldGUoc2lkKTtcbiAgICB9XG4gIH1cblxuICAvLyDilIDilIAgZ2VuZXJhdGUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgYXN5bmMgZ2VuZXJhdGUocmVxOiBHZW5lcmF0ZVJlcXVlc3QpOiBQcm9taXNlPEdlbmVyYXRlUmVzdWx0PiB7XG4gICAgcmV0dXJuIHRoaXMucnVuKHJlcSwgKCkgPT4ge30pO1xuICB9XG5cbiAgYXN5bmMgZ2VuZXJhdGVTdHJlYW0ocmVxOiBHZW5lcmF0ZVJlcXVlc3QsIGNiOiBHZW5lcmF0ZVN0cmVhbUNhbGxiYWNrcyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJ1bihyZXEsIGNiLm9uRGVsdGEpO1xuICAgICAgY2Iub25UaHJlYWRJZD8uKHJlc3VsdC50aHJlYWRDb29yZC50aHJlYWRJZCk7XG4gICAgICBjYi5vbkNvbXBsZXRlKHJlc3VsdCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY2Iub25FcnJvcihlIGFzIEVycm9yKTtcbiAgICB9XG4gIH1cblxuICAvLyBnZW5lcmF0ZS9nZW5lcmF0ZVN0cmVhbSDqs7XthrUg7Iuk7ZaJLiBvbkRlbHRhIOuKlCDsiqTtirjrprzsnbTrqbQg7KCQ7KeEIOuwqey2nCwg67mE7Iqk7Yq466a87J2066m0IG5vLW9wLlxuICBwcml2YXRlIGFzeW5jIHJ1bihyZXE6IEdlbmVyYXRlUmVxdWVzdCwgb25EZWx0YTogKHQ6IHN0cmluZykgPT4gdm9pZCk6IFByb21pc2U8R2VuZXJhdGVSZXN1bHQ+IHtcbiAgICB0aGlzLnN3ZWVwU2Vzc2lvbkNvbXBhdCgpO1xuXG4gICAgLy8gbW9kZWwg7KCV6rec7ZmU66W8IGRpc3BhdGNoZXIg7KeE7J6F7KCQ7JeQ7IScIO2VnCDrsogg7ZWc64ukOiBjb21wYXQgLyByZXN1bHQubW9kZWwgLyBydW5DbGF1ZGVTZXNzaW9uIOyghOu2gFxuICAgIC8vIGNhbm9uaWNhbChwcmVmaXgg7JeG64qUIGNvc3Qg7YKkKSDsnYQg7JOw6rKMIO2GteydvC4g66+47KeA7KCV7J2066m0IEFOVEhST1BJQ19ERUZBVUxUX01PREVMIOKAlCBxZ3JpZC5kaXNwYXRjaGVyXG4gICAgLy8g7J2YIFwic29ubmV0XCIg67OE7LmtIOyasO2ajCDssKjri6guIOygleq3nO2ZlCDqt5zsuZnsnYAgZmFsbGJhY2sg6rK966Gc7JmAIOqzteycoChjYW5vbmljYWxBbnRocm9waWNNb2RlbCkuXG4gICAgY29uc3QgbW9kZWwgPSBjYW5vbmljYWxBbnRocm9waWNNb2RlbChyZXEubW9kZWwpO1xuICAgIGNvbnN0IGpzb25TY2hlbWEgPVxuICAgICAgcmVxLm91dHB1dFNjaGVtYSAhPT0gdW5kZWZpbmVkID8gSlNPTi5zdHJpbmdpZnkocmVxLm91dHB1dFNjaGVtYSkgOiB1bmRlZmluZWQ7XG4gICAgY29uc3QgY29tcGF0ID0gY29tcGF0aWJpbGl0eUtleSh7IHN5c3RlbTogcmVxLnN5c3RlbVByb21wdCwgbW9kZWwsIG91dHB1dFNjaGVtYToganNvblNjaGVtYSB9KTtcblxuICAgIC8vIOKUgOKUgCByZXN1bWUgZWxpZ2liaWxpdHkgKyDthqDtgbAg7ISg7YOdIChyZXN1bWUg64qUIOyEuOyFmCDshozsnKAg7Yag7YGw7Jy866Gc66eMKSDilIDilIBcbiAgICAvLyAgcmVzdW1lIOqwgCDshLHrpr3tlZjroKTrqbQg7IS4IOyhsOqxtOydtCDrqqjrkZAg7LC47J207Ja07JW8IO2VnOuLpDpcbiAgICAvLyAgIChhKSByZXVzZS50aHJlYWRJZCDsnZgg7KCA7J6l65CcIO2YuO2ZmO2CpCA9PSDsnbTrsogg7JqU7LKtIO2YuO2ZmO2CpCAo66qo6424L3N5c3RlbS9zY2hlbWEg67OA6rK9IOyYpOyXvCDrsKnsp4ApXG4gICAgLy8gICAoYikg7KCA7J6l65CcIHRva2VuSWQgPT0gcmV1c2Uud29ya2VySWQgKGNvb3JkIOyZleuztSDrrLTqsrDshLEpIOydtOqzoFxuICAgIC8vICAgKGMpIOq3uCDthqDtgbDsnbQg7JWE7KeBIO2SgOyXkCDsgrTslYTsnojsnYwuXG4gICAgLy8gIO2VmOuCmOudvOuPhCDslrTquIvrgpjrqbQgcmVzdW1lIOu2iOqwgCDihpIgY29sZCDroZwg65ao7Ja07KeA6rOgIFJSIOuhnCDsg4gg7Yag7YGw7J2EIOqzoOuluOuLpC5cbiAgICAvLyAgcmVzdW1lIOydvCDrlYzripQg67CY65Oc7IucIOyEuOyFmOydhCDrp4zrk6Ag6re4IO2GoO2BsChzdG9yZWQudG9rZW5JZCnsnYQg6rOg7KCVIOyEoO2Dne2VnOuLpCDigJQgUlIg66GcIOuLpOuluCDthqDtgbDsnYQg7J6h7Jy866m0XG4gICAgLy8gIOq3uCDthqDtgbDsnZggQ0xBVURFX0NPTkZJR19ESVIg7JeQIHRyYW5zY3JpcHQg6rCAIOyXhuyWtCByZXN1bWUg7J20IOq5qOynhOuLpC5cbiAgICBjb25zdCBjYW5kaWRhdGUgPSByZXEucmV1c2U/LnRocmVhZElkO1xuICAgIGNvbnN0IHN0b3JlZCA9IGNhbmRpZGF0ZSAhPT0gdW5kZWZpbmVkID8gdGhpcy5zZXNzaW9uQ29tcGF0LmdldChjYW5kaWRhdGUpIDogdW5kZWZpbmVkO1xuICAgIGNvbnN0IG93bmVyTWF0Y2hlcyA9IHN0b3JlZCAhPT0gdW5kZWZpbmVkICYmIHN0b3JlZC50b2tlbklkID09PSByZXEucmV1c2U/LndvcmtlcklkO1xuICAgIGNvbnN0IHJlc3VtZVRva2VuID1cbiAgICAgIHN0b3JlZD8uY29tcGF0ID09PSBjb21wYXQgJiYgb3duZXJNYXRjaGVzID8gdGhpcy5waWNrVG9rZW4oc3RvcmVkLnRva2VuSWQpIDogbnVsbDtcblxuICAgIGNvbnN0IGlzUmVzdW1lID0gcmVzdW1lVG9rZW4gIT09IG51bGw7XG4gICAgY29uc3QgcmVzdW1lU2Vzc2lvbklkID0gaXNSZXN1bWUgPyBjYW5kaWRhdGUgOiB1bmRlZmluZWQ7XG5cbiAgICAvLyByZXN1bWUg66m0IOyGjOycoCDthqDtgbAg6rOg7KCVLCDslYTri4jrqbQgY29sZCBSUiDshKDtg50uXG4gICAgY29uc3QgdG9rZW4gPSByZXN1bWVUb2tlbiA/PyB0aGlzLnNlbGVjdFRva2VuKCk7XG4gICAgaWYgKCF0b2tlbikgdGhyb3cgbmV3IEVycm9yKFwiTm8gYW50aHJvcGljIHRva2VucyBhdmFpbGFibGVcIik7XG5cbiAgICAvLyDrnb0g7IaM7Jyg6raMOlxuICAgIC8vICBzZXNzaW9uLWlkIOuLqOychCDsp4HroKztmZQg65297J2AICoqVTQgcnVuQ2xhdWRlU2Vzc2lvbiDsnbQg64uo64+FIOyGjOycoCoq7ZWc64ukLiBkaXNwYXRjaGVyIOqwgCDsl6zquLDshJxcbiAgICAvLyAgd2l0aFNlc3Npb25Mb2NrKHJlc3VtZVNlc3Npb25JZCkg7Jy866GcIO2VnCDrsogg642UIOqwkOyLuOuptCwgZXhlYygpIOyViOydmCBydW5DbGF1ZGVTZXNzaW9uIOydtCDqsJnsnYBcbiAgICAvLyAgc2Vzc2lvbi1pZCDroZwg65297JeQIOyerOynhOyehe2VmOuKlOuNsCB3aXRoU2Vzc2lvbkxvY2sg7J2AIHJlZW50cmFudCDqsIAg7JWE64uI6528IOyekOq4sCDsnpDsi6DsnYQg6riw64uk66as64qUXG4gICAgLy8gIGRlYWRsb2NrIOydtCDrgpzri6Qo7LKrIHJlc3VtZSDtmLjstpzsnbQg7JiB6rWsIOygleyngCkuIFUxL1U1IGRpc3BhdGNoZXIg64qUIHRva2VuIG93bmVyc2hpcCAvIGNvbXBhdCDrp4xcbiAgICAvLyAg7YyQ7KCV7ZWY6rOgLCB0cmFuc2NyaXB0IOyngeugrO2ZlOuKlCBVNCDrnb3sl5Ag7JyE7J6E7ZWc64ukLlxuICAgIC8vICBjb2xkIOyyqy3tmLjstpwg64+Z7Iuc7ISx7J2EIGRpc3BhdGNoZXIg6rCAIOuUsOuhnCDrp4nsp4Ag7JWK64qUIOq3vOqxsDogc2Vzc2lvbktleSDripQg7ISc67KE66GcIOyYpOyngCDslYrslYQo7YG06528XG4gICAgLy8gIHN0b3JlIOq0gOumrCwg7KKM7ZGc66eMIO2ajOyGoSkgY29sZCDrs4Qg65297J2YIOyeheugpSDsnpDssrTqsIAg7JeG6rOgLCDtmITsnqwgSUYvb3duZXIg64qUIExMTSDtmLjstpzsnYQg7KCE67aAIOyInOywqOuhnFxuICAgIC8vICDrj4zroKQg64+Z7IucIOyyqyDtmLjstpzsnbQg64KY7KeAIOyViuuKlOuLpCgyMDI2LTA2LTA2IEwyMS9MMjQ4KS4g67OR66Cs7ZmUL+yEnOuyhOyghOuLrOuhnCDrsJTrgIzrqbQg7J6s6rKA7YagLlxuICAgIGNvbnN0IGV4ZWMgPSBhc3luYyAoKTogUHJvbWlzZTxHZW5lcmF0ZVJlc3VsdD4gPT4ge1xuICAgICAgLy8g66eM66OMIOyehOuwlSDthqDtgbAgcHJlZW1wdGl2ZSByZWZyZXNoKOq4sOyhtCBzdGFuZGFsb25lIOqyveuhnOyZgCDrj5nsnbwpLiDsi6TtjKjtlbTrj4Qg7KeE7ZaJLlxuICAgICAgbGV0IGFjY2Vzc1Rva2VuID0gdG9rZW4uY3JlZGVudGlhbHMuYWNjZXNzVG9rZW47XG4gICAgICBjb25zdCBleHBpcmVzQXQgPSBnZXRFeHBpcmVzQXQodG9rZW4uY3JlZGVudGlhbHMpO1xuICAgICAgaWYgKFxuICAgICAgICBleHBpcmVzQXQgJiZcbiAgICAgICAgZXhwaXJlc0F0IC0gRGF0ZS5ub3coKSA8IFJFRlJFU0hfU0FGRVRZX01TICYmXG4gICAgICAgIGdldFJlZnJlc2hUb2tlbih0b2tlbi5jcmVkZW50aWFscylcbiAgICAgICkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHsgUWdyaWRGcmFtZSB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vLi4vLi4vYXBwbGljYXRpb24vcWdyaWQvcWdyaWQuZnJhbWVcIik7XG4gICAgICAgICAgLy8gcHJvdmlkZXIg66W8IOuwmOuTnOyLnCDssYTsm4zslbwgcmVmcmVzaFRva2VuIOuCtOu2gCBUb2tlbk1vZGVsLnNhdmUg6rCAIOyEseqzte2VnOuLpC5cbiAgICAgICAgICAvLyByZWZyZXNoVG9rZW4oVG9rZW5TdWJzZXRBKSDripQgaWQvcHJvdmlkZXIvY3JlZGVudGlhbHMvbmFtZSDrp4wg7IKs7Jqp7ZWY66+A66GcIOq3uCA06rCc66eMIOuEmOq4tOuLpC5cbiAgICAgICAgICBhY2Nlc3NUb2tlbiA9IGF3YWl0IFFncmlkRnJhbWUucmVmcmVzaFRva2VuKHtcbiAgICAgICAgICAgIGlkOiB0b2tlbi5pZCxcbiAgICAgICAgICAgIHByb3ZpZGVyOiBBTlRIUk9QSUNfUFJPVklERVIsXG4gICAgICAgICAgICBuYW1lOiB0b2tlbi5uYW1lLFxuICAgICAgICAgICAgY3JlZGVudGlhbHM6IHRva2VuLmNyZWRlbnRpYWxzLFxuICAgICAgICAgIH0gYXMgUGFyYW1ldGVyczx0eXBlb2YgUWdyaWRGcmFtZS5yZWZyZXNoVG9rZW4+WzBdKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIGxvZ2dlci53YXJuKGByZWZyZXNoIGZhaWxlZCBmb3IgJHt0b2tlbi5uYW1lfTogJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBydW5TZXNzaW9uID0gKHJlc3VtZTogYm9vbGVhbikgPT4ge1xuICAgICAgICBsb2dnZXIuaW5mbyhg4oaSICR7dG9rZW4ubmFtZX0gKG1vZGVsOiAke21vZGVsfSwgJHtyZXN1bWUgPyBcInJlc3VtZVwiIDogXCJjb2xkXCJ9KWApO1xuICAgICAgICByZXR1cm4gcnVuQ2xhdWRlU2Vzc2lvbihcbiAgICAgICAgICB7XG4gICAgICAgICAgICB0b2tlbklkOiB0b2tlbi5pZCxcbiAgICAgICAgICAgIHRva2VuOiBhY2Nlc3NUb2tlbixcbiAgICAgICAgICAgIG1vZGVsLFxuICAgICAgICAgICAgc3lzdGVtOiByZXEuc3lzdGVtUHJvbXB0LFxuICAgICAgICAgICAganNvblNjaGVtYSxcbiAgICAgICAgICAgIGVmZm9ydDogcmVxLmVmZm9ydCxcbiAgICAgICAgICAgIHRpbWVvdXRNczogREVGQVVMVF9USU1FT1VUX01TLFxuICAgICAgICAgICAgY29sZEhpc3Rvcnk6IHJlc3VtZSA/IHVuZGVmaW5lZCA6IHJlcS5jb2xkSGlzdG9yeSxcbiAgICAgICAgICAgIGlucHV0OiByZXN1bWUgJiYgcmVxLnJldXNlSW5wdXQgPyByZXEucmV1c2VJbnB1dCA6IHJlcS5jb2xkSW5wdXQsXG4gICAgICAgICAgICByZXN1bWVTZXNzaW9uSWQ6IHJlc3VtZSA/IHJlc3VtZVNlc3Npb25JZCA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGFib3J0U2lnbmFsOiByZXEuYWJvcnRTaWduYWwsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBvbkRlbHRhLFxuICAgICAgICApO1xuICAgICAgfTtcblxuICAgICAgbGV0IHNlc3Npb247XG4gICAgICB0cnkge1xuICAgICAgICBzZXNzaW9uID0gYXdhaXQgcnVuU2Vzc2lvbihpc1Jlc3VtZSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGlmICghaXNSZXN1bWUgfHwgIWlzUmV0cnlhYmxlUmVzdW1lRmFpbHVyZShlKSkgdGhyb3cgZTtcbiAgICAgICAgaWYgKGNhbmRpZGF0ZSkgdGhpcy5zZXNzaW9uQ29tcGF0LmRlbGV0ZShjYW5kaWRhdGUpO1xuICAgICAgICBsb2dnZXIud2FybihgcmVzdW1lIGZhaWxlZCBmb3IgJHt0b2tlbi5uYW1lfTsgcmV0cnlpbmcgY29sZCBvbmNlOiAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgICAgICBzZXNzaW9uID0gYXdhaXQgcnVuU2Vzc2lvbihmYWxzZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzZXNzaW9uLnF1b3RhRXhoYXVzdGVkKSB0aHJvdyBuZXcgRXJyb3IoYHF1b3RhIGV4aGF1c3RlZCAoJHt0b2tlbi5uYW1lfSlgKTtcbiAgICAgIGlmIChzZXNzaW9uLmlzRXJyb3IpIHtcbiAgICAgICAgLy8gdGV4dCDqsIAg67mE7Ja0IOyeiOydhCDsiJgg7J6I7Jy866+A66GcIOynhOuLqCDqsIDriqXtlZwg7ZiV7YOc66GcIOuplOyLnOyngOulvCDrp4zrk6Dri6Qoc3VidHlwZSDrk7HsnYAgcmF3IOuhnOq3uCDssLjsobApLlxuICAgICAgICBjb25zdCBkZXRhaWwgPSBzZXNzaW9uLnRleHQgfHwgYGVtcHR5IHRleHQsIG91dHB1dFRva2Vucz0ke3Nlc3Npb24udXNhZ2Uub3V0cHV0VG9rZW5zfWA7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgY2xhdWRlIGVycm9yICgke3Rva2VuLm5hbWV9KTogJHtkZXRhaWx9YCk7XG4gICAgICB9XG5cbiAgICAgIC8vIOuwnOq4ie2VnCBzZXNzaW9uLWlkIOydmCDtmLjtmZjtgqQg7KCA7J6lKOuLpOydjCByZXN1bWUg7YyQ7KCV7JqpKS4gY29tcGF0IOuKlCDsl6zquLAgZGlzcGF0Y2hlci1sb2NhbCDsl5Drp4xcbiAgICAgIC8vIOuztOyhtO2VnOuLpCDigJQgdGhyZWFkQ29vcmQuc3lzdGVtSGFzaCDroZwg7JmV67O17ZWY7KeAIOyViuuKlOuLpC4g7IOB7JyEIGlzc3VlQ29udkNvbnRleHQg6rCAIHN5c3RlbUhhc2gg66W8XG4gICAgICAvLyDrlLDroZwg7LGE7Jqw7KeA66eMIEFudGhyb3BpYyByZXN1bWUgZWxpZ2liaWxpdHkg64qUIOydtCBzZXNzaW9uQ29tcGF0IOqwgCDri6jrj4Ug7YyQ7KCVLlxuICAgICAgdGhpcy5zZXNzaW9uQ29tcGF0LnNldChzZXNzaW9uLnNlc3Npb25JZCwge1xuICAgICAgICBjb21wYXQsXG4gICAgICAgIHRva2VuSWQ6IHRva2VuLmlkLFxuICAgICAgICBsYXN0VXNlZEF0OiBEYXRlLm5vdygpLFxuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHRleHQ6IHNlc3Npb24udGV4dCxcbiAgICAgICAgdG9rZW5OYW1lOiB0b2tlbi5uYW1lLFxuICAgICAgICB1c2FnZTogc2Vzc2lvbi51c2FnZSxcbiAgICAgICAgZHVyYXRpb25Nczogc2Vzc2lvbi5kdXJhdGlvbk1zLFxuICAgICAgICBjb3N0VXNkOiBzZXNzaW9uLmNvc3RVc2QsXG4gICAgICAgIG1vZGVsLFxuICAgICAgICAvLyBzeXN0ZW1IYXNoIOuKlCDsg4HsnIQgaXNzdWVDb252Q29udGV4dCDqsIAg7LGE7Jq064ukKOyXrOq4sOyEoCDruYTsmrTri6QpLlxuICAgICAgICB0aHJlYWRDb29yZDoge1xuICAgICAgICAgIHdvcmtlcklkOiBtYWtlQW50aHJvcGljV29ya2VySWQodG9rZW4uaWQpLFxuICAgICAgICAgIHRocmVhZElkOiBzZXNzaW9uLnNlc3Npb25JZCxcbiAgICAgICAgICBlcG9jaDogMCxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfTtcblxuICAgIHJldHVybiBleGVjKCk7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQW9DQSxNQUFNLFNBQVMsVUFBVSxDQUFDLFNBQVMsdUJBQXVCLENBQUM7QUFFM0QsTUFBTSxxQkFBcUI7QUFFM0IsTUFBTSxvQkFBb0I7QUFXMUIsTUFBTSxxQkFBcUI7QUFJM0IsTUFBTSx3QkFBd0IsTUFBVTtBQVF4QyxTQUFTLHlCQUF5QixPQUF5QjtDQUV6RCxNQUFNLFNBRFUsaUJBQWlCLFFBQVEsTUFBTSxVQUFVLE9BQU8sTUFBTSxFQUNoRCxhQUFhO0FBQ25DLEtB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
159
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW50aHJvcGljLWRpc3BhdGNoZXIuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Byb3ZpZGVycy9hbnRocm9waWMvYW50aHJvcGljLWRpc3BhdGNoZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBbnRocm9waWNEaXNwYXRjaGVyXG4gKlxuICogT3BlbkFJRGlzcGF0Y2hlcuyZgCDri6zrpqwsIHdvcmtlciBwb29s7J2EIOuRkOuKlCDrjIDsi6Ag7JqU7LKt67OEIGZyZXNoIHNwYXduXG4gKiDthqDtgbDsnYAg7J2466mU66qo66asKE1BUCnsnLzroZwg6rSA66as7ZWY6rOgIGxlYXN0LXVzZWQsIHJvdW5kLXJvYmluIOycvOuhnCDqs6Drpbjri6RcbiAqXG4gKiAtIOuqqOuToCDsmpTssq3snYAgZnJlc2ggYC0tc2Vzc2lvbi1pZGAg66GcIOyLpO2WiVxuICogLSDrqYDti7DthLQg66y466el7J2AIO2BtOudvOydtOyWuO2KuOqwgCDrp6Qg7Zi47LacIOuztOuCtOuKlCBmdWxsIGhpc3Rvcnkg66W8IO2Pie2DhO2ZlO2VtCDsoITri6ztlZzri6QuXG4gKiAtIOuwnOq4ie2VnCBzZXNzaW9uLWlkIOulvCBHZW5lcmF0ZVJlc3VsdC50aHJlYWRDb29yZCh0aHJlYWRJZD1zZXNzaW9uLWlkLCB3b3JrZXJJZD10b2tlbklkLFxuICogICBlcG9jaD0wKeuhnCDsmKzroKQsIOyDgeychChpc3N1ZUNvbnZDb250ZXh0KeqwgCDtgbTrnbzsl5Ag7ZqM7Iah7ZWgIOyijO2RnOulvCDrp4zrk6Dri6QuIOuLpOydjCB0dXJuIOydtCDsooztkZzrpbxcbiAqICAg7ZqM7Iah7ZW064+EIEFudGhyb3BpYyDrnbzsmrDtjIXsl5DripQg7JOw7KeAIOyViuuKlOuLpC5cbiAqL1xuXG5pbXBvcnQgeyBnZXRMb2dnZXIgfSBmcm9tIFwiQGxvZ3RhcGUvbG9ndGFwZVwiO1xuXG5pbXBvcnQgeyBUb2tlbk1vZGVsIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3Rva2VuL3Rva2VuLm1vZGVsXCI7XG5pbXBvcnQgeyB0eXBlIEFudGhyb3BpY0NyZWRlbnRpYWxzIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3Rva2VuL3Rva2VuLnR5cGVzXCI7XG5pbXBvcnQgeyBnZXRFeHBpcmVzQXQsIGdldFJlZnJlc2hUb2tlbiB9IGZyb20gXCIuLi9jb21tb24vY3JlZGVudGlhbHNcIjtcbmltcG9ydCB7XG4gIHR5cGUgR2VuZXJhdGVSZXF1ZXN0LFxuICB0eXBlIEdlbmVyYXRlUmVzdWx0LFxuICB0eXBlIEdlbmVyYXRlU3RyZWFtQ2FsbGJhY2tzLFxuICB0eXBlIFByb3ZpZGVyRGlzcGF0Y2hlcixcbn0gZnJvbSBcIi4uL2NvbW1vbi9wcm92aWRlci1kaXNwYXRjaGVyXCI7XG5pbXBvcnQgeyBhc3NlcnRTdXBwb3J0ZWRPbmVNaWxsaW9uU3VmZml4LCBjYW5vbmljYWxBbnRocm9waWNNb2RlbCB9IGZyb20gXCIuL2FudGhyb3BpYy1jb25zdGFudHNcIjtcbmltcG9ydCB7IG1ha2VBbnRocm9waWNXb3JrZXJJZCwgcnVuQ2xhdWRlU2Vzc2lvbiB9IGZyb20gXCIuL2NsYXVkZS1zZXNzaW9uXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGdldExvZ2dlcihbXCJxZ3JpZFwiLCBcImFudGhyb3BpYy1kaXNwYXRjaGVyXCJdKTtcblxuLy8gMU0gY29udGV4dCDsoJXsg4Eg7IOd7ISx7J2AIOyLpOy4oeyDgSAxMDBzK+q5jOyngCDqsITri6QuIDI0MHPripQg7JmE7LapIOyepey5mOydvCDrv5AsXG4vLyDqsbDrtoAr6rGw64yAIHN5c3RlbSDsnqzsg53shLEg7KeA7Jew7J2EIOyZhOyghO2eiCDtlbTqsrDtlZjripQg6rCS7J2AIOyVhOuLiOuLpC5cbmNvbnN0IERFRkFVTFRfVElNRU9VVF9NUyA9IDI0MF8wMDA7XG4vLyBhY2Nlc3MgdG9rZW4g66eM66OMIOyehOuwlSDsnoTqs4Qg4oCUIOq4sOyhtCBzdGFuZGFsb25lIOqyveuhnChxZ3JpZC5kaXNwYXRjaGVyLnRzKeyZgCDrj5nsnbwoNjBzKS5cbmNvbnN0IFJFRlJFU0hfU0FGRVRZX01TID0gNjBfMDAwO1xuXG5pbnRlcmZhY2UgUG9vbGVkVG9rZW4ge1xuICBpZDogbnVtYmVyO1xuICBuYW1lOiBzdHJpbmc7XG4gIGNyZWRlbnRpYWxzOiBBbnRocm9waWNDcmVkZW50aWFscztcbn1cblxuZXhwb3J0IGNsYXNzIEFudGhyb3BpY0Rpc3BhdGNoZXIgaW1wbGVtZW50cyBQcm92aWRlckRpc3BhdGNoZXIge1xuICAvLyB0b2tlbklkIOKGkiDtkoAg7ZWt66qpLiBzdGFydCgpL3Rva2VuIOydtOuypO2KuOuhnCDssYTsm4BcbiAgcHJpdmF0ZSB0b2tlblBvb2wgPSBuZXcgTWFwPG51bWJlciwgUG9vbGVkVG9rZW4+KCk7XG4gIC8vIHRva2VuSWQg67OEIOyCrOyaqSDsubTsmrTthLAobGVhc3QtdXNlZCBSUikuIG5hbWUg7J20IOyVhOuLiOudvCBpZCDquLDspIAg4oCUIOydtOumhCDstqnrj4wg7JWI7KCEXG4gIHByaXZhdGUgcmVxdWVzdENvdW50cyA9IG5ldyBNYXA8bnVtYmVyLCBudW1iZXI+KCk7XG4gIHByaXZhdGUgcnJJbmRleCA9IDA7XG5cbiAgYXN5bmMgc3RhcnQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gT3BlbkFJRGlzcGF0Y2hlci5zdGFydCgpIOyZgCDrj5nsnbztlZjqsowgREIg7JeQ7IScIOq4sOyhtCBhbnRocm9waWMg7Yag7YGw7J2EIHNlbGYtYm9vdHN0cmFwIO2VnOuLpC5cbiAgICAvLyAo7ISc67KEIOyerOyLnOyekSDsi5wgTk9USUZZIOqwgCDslYgg7Jik66+A66GcIOu2gO2KuOyKpO2KuOueqeydtCDsl4bsnLzrqbQg7ZKA7J20IOu5iCDssYTroZwg64Ko64qU64ukLilcbiAgICAvLyDsnbTtm4Qg67OA6rK967aE7J2AIHRva2VuLXN1YnNjcmliZXIg6rCAIG9uVG9rZW5BZGRlZC9VcGRhdGVkL1JlbW92ZWQg66GcIOyghOuLrO2VnOuLpC5cbiAgICAvLyBmaW5kQWN0aXZlQnlQcm92aWRlciDqsIAgYWN0aXZlPXRydWUgKyBwcm92aWRlciDtlYTthLDrpbwgREIg7JeQ7IScIOyymOumrCDihpIgaW5hY3RpdmUg64qUIOyVoOy0iOyXkCDslYgg7Jio64ukLlxuICAgIGNvbnN0IHRva2VucyA9IGF3YWl0IFRva2VuTW9kZWwuZmluZEFjdGl2ZUJ5UHJvdmlkZXIoXCJBXCIsIFwiYW50aHJvcGljXCIpO1xuICAgIGZvciAoY29uc3QgdCBvZiB0b2tlbnMpIHtcbiAgICAgIHRoaXMudG9rZW5Qb29sLnNldCh0LmlkLCB7XG4gICAgICAgIGlkOiB0LmlkLFxuICAgICAgICBuYW1lOiB0Lm5hbWUsXG4gICAgICAgIGNyZWRlbnRpYWxzOiB0LmNyZWRlbnRpYWxzIGFzIEFudGhyb3BpY0NyZWRlbnRpYWxzLFxuICAgICAgfSk7XG4gICAgICBsb2dnZXIuaW5mbyhgd29ya2VyIHNwYXduZWQ6ICR7dC5uYW1lfWApO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIHN0b3AoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy50b2tlblBvb2wuY2xlYXIoKTtcbiAgICAvLyBsaWZlY3ljbGUg7KCV7ZWpOiBSUiDsubTsmrTthLAv7J24642x7Iqk64+EIOu5hOybjCBzdG9w4oaSc3RhcnQg7J6s65Ox66GdIOyLnCDsnbTsoIQg7Lm07Jq07Yq46rCAIOyViCDrgqjqsowg7ZWc64ukLlxuICAgIHRoaXMucmVxdWVzdENvdW50cy5jbGVhcigpO1xuICAgIHRoaXMucnJJbmRleCA9IDA7XG4gIH1cblxuICAvLyDtmITsnqwg7ZKA7J2YIO2GoO2BsCDsiJgoc3RhcnR1cCDroZzqt7gvaGVhbHRoIOyaqSkuXG4gIGdldCB0b2tlbkNvdW50KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMudG9rZW5Qb29sLnNpemU7XG4gIH1cblxuICAvLyBEQiBhY3RpdmUgYW50aHJvcGljIO2GoO2BsCDrqqnroZ3snLzroZwg7ZKA7J2EIOyerOuPmeq4sO2ZlO2VnOuLpChwZXJpb2RpYyByZWNvbmNpbGUv7J6s7Jew6rKw7JqpKS5cbiAgLy8gTElTVEVOL05PVElGWSDqsIAg64GK6ri0IOuPmeyViCDsnKDsi6TrkJwg7LaU6rCAL+yCreygnC/ruYTtmZzshLHtmZTrpbwgREIg6riw7KSA7Jy866GcIOuLpOyLnCDrp57stpjri6QuXG4gIC8vIOydtOuypO2KuCDtlbjrk6Trn6zrpbwg7J6s7IKs7Jqp7ZW0IO2SgCDqsLHsi6DsnbQg7J286rSA65CY6rKMIOyggeyaqeuQmOuPhOuhnSDtlZzri6Q6XG4gIC8vICAtIERCIOyXkCDsl4bripTrjbAg7ZKA7JeQIOyeiOuKlCDthqDtgbAg4oaSIG9uVG9rZW5SZW1vdmVkXG4gIC8vICAtIERCIOyXkCDsnojripQg7Yag7YGwIOKGkiDsi6Dqt5zrqbQgb25Ub2tlbkFkZGVkLCDquLDsobTsnbTrqbQgb25Ub2tlblVwZGF0ZWRcbiAgcmVwbGFjZVRva2VucyhcbiAgICByb3dzOiBBcnJheTx7IGlkOiBudW1iZXI7IG5hbWU6IHN0cmluZzsgY3JlZGVudGlhbHM6IEFudGhyb3BpY0NyZWRlbnRpYWxzIH0+LFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBuZXh0ID0gbmV3IFNldChyb3dzLm1hcCgocikgPT4gci5pZCkpO1xuICAgIC8vIG9uVG9rZW5SZW1vdmVkIOqwgCB0b2tlblBvb2wg7J2EIGRlbGV0ZSDtlZjrr4DroZwg7Iic7ZqMIOykkSDsiJjsoJXsnYQg7ZS87ZWY66CkIO2CpOulvCDrqLzsoIAg7Iqk64OF7IO37ZWc64ukLlxuICAgIGNvbnN0IGN1cnJlbnRJZHMgPSBBcnJheS5mcm9tKHRoaXMudG9rZW5Qb29sLmtleXMoKSk7XG4gICAgZm9yIChjb25zdCBpZCBvZiBjdXJyZW50SWRzKSB7XG4gICAgICBpZiAoIW5leHQuaGFzKGlkKSkgdGhpcy5vblRva2VuUmVtb3ZlZChpZCk7XG4gICAgfVxuICAgIGZvciAoY29uc3QgciBvZiByb3dzKSB7XG4gICAgICBpZiAodGhpcy50b2tlblBvb2wuaGFzKHIuaWQpKSB0aGlzLm9uVG9rZW5VcGRhdGVkKHIuaWQsIHIubmFtZSwgci5jcmVkZW50aWFscyk7XG4gICAgICBlbHNlIHRoaXMub25Ub2tlbkFkZGVkKHIuaWQsIHIubmFtZSwgci5jcmVkZW50aWFscyk7XG4gICAgfVxuICB9XG5cbiAgLy8gdG9rZW4gZXZlbnRzICh0b2tlbi1zdWJzY3JpYmVyIOqwgCDtmLjstpwpXG4gIG9uVG9rZW5BZGRlZChpZDogbnVtYmVyLCBuYW1lOiBzdHJpbmcsIGNyZWRlbnRpYWxzOiBBbnRocm9waWNDcmVkZW50aWFscyk6IHZvaWQge1xuICAgIHRoaXMudG9rZW5Qb29sLnNldChpZCwgeyBpZCwgbmFtZSwgY3JlZGVudGlhbHMgfSk7XG4gIH1cblxuICBvblRva2VuVXBkYXRlZChpZDogbnVtYmVyLCBuYW1lOiBzdHJpbmcsIGNyZWRlbnRpYWxzOiBBbnRocm9waWNDcmVkZW50aWFscyk6IHZvaWQge1xuICAgIHRoaXMudG9rZW5Qb29sLnNldChpZCwgeyBpZCwgbmFtZSwgY3JlZGVudGlhbHMgfSk7XG4gIH1cblxuICBvblRva2VuUmVtb3ZlZChpZDogbnVtYmVyKTogdm9pZCB7XG4gICAgdGhpcy50b2tlblBvb2wuZGVsZXRlKGlkKTtcbiAgICB0aGlzLnJlcXVlc3RDb3VudHMuZGVsZXRlKGlkKTtcbiAgfVxuXG4gIHByaXZhdGUgY291bnRPZihpZDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5yZXF1ZXN0Q291bnRzLmdldChpZCkgPz8gMDtcbiAgfVxuXG4gIC8vIOyalOyyreuniOuLpCBsZWFzdC11c2VkIFJSIOuhnCDthqDtgbDsnYQg6rOg66W464ukKOuPmeygkOydtOuptCByckluZGV4IOuhnCDtmozsoIQpLlxuICBwcml2YXRlIHNlbGVjdFRva2VuKCk6IFBvb2xlZFRva2VuIHwgbnVsbCB7XG4gICAgY29uc3Qgcm93cyA9IFsuLi50aGlzLnRva2VuUG9vbC52YWx1ZXMoKV07XG4gICAgaWYgKHJvd3MubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBtaW5Db3VudCA9IE1hdGgubWluKC4uLnJvd3MubWFwKChyKSA9PiB0aGlzLmNvdW50T2Yoci5pZCkpKTtcbiAgICBjb25zdCBpZGxlID0gcm93cy5maWx0ZXIoKHIpID0+IHRoaXMuY291bnRPZihyLmlkKSA9PT0gbWluQ291bnQpO1xuICAgIGNvbnN0IHBpY2tlZCA9IGlkbGVbdGhpcy5yckluZGV4ICUgaWRsZS5sZW5ndGhdITtcbiAgICB0aGlzLnJySW5kZXgrKztcbiAgICByZXR1cm4gdGhpcy5jaGFyZ2UocGlja2VkKTtcbiAgfVxuXG4gIC8vIOyEoO2DneuQnCDthqDtgbDsnZgg7IKs7JqpIOy5tOyatO2KuOulvCBhd2FpdCDsoITsl5Ag7ISg67CY7JiBKOuPmeyLnCDsmpTssq3snbQg64uk66W4IO2GoO2BsOydhCDqs6DrpbTrj4TroZ0pLlxuICBwcml2YXRlIGNoYXJnZSh0b2tlbjogUG9vbGVkVG9rZW4pOiBQb29sZWRUb2tlbiB7XG4gICAgdGhpcy5yZXF1ZXN0Q291bnRzLnNldCh0b2tlbi5pZCwgdGhpcy5jb3VudE9mKHRva2VuLmlkKSArIDEpO1xuICAgIHJldHVybiB0b2tlbjtcbiAgfVxuXG4gIGFzeW5jIGdlbmVyYXRlKHJlcTogR2VuZXJhdGVSZXF1ZXN0KTogUHJvbWlzZTxHZW5lcmF0ZVJlc3VsdD4ge1xuICAgIHJldHVybiB0aGlzLnJ1bihyZXEsICgpID0+IHt9KTtcbiAgfVxuXG4gIGFzeW5jIGdlbmVyYXRlU3RyZWFtKHJlcTogR2VuZXJhdGVSZXF1ZXN0LCBjYjogR2VuZXJhdGVTdHJlYW1DYWxsYmFja3MpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5ydW4ocmVxLCBjYi5vbkRlbHRhLCB7IGluY2x1ZGVQYXJ0aWFsTWVzc2FnZXM6IHRydWUgfSk7XG4gICAgICBjYi5vblRocmVhZElkPy4ocmVzdWx0LnRocmVhZENvb3JkLnRocmVhZElkKTtcbiAgICAgIGNiLm9uQ29tcGxldGUocmVzdWx0KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjYi5vbkVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8vIGdlbmVyYXRlL2dlbmVyYXRlU3RyZWFtIOqzte2GtSDsi6TtlokuIG9uRGVsdGEg64qUIOyKpO2KuOumvOydtOuptCDsoJDsp4Qg67Cp7LacLCDruYTsiqTtirjrprzsnbTrqbQgbm8tb3AuXG4gIHByaXZhdGUgYXN5bmMgcnVuKFxuICAgIHJlcTogR2VuZXJhdGVSZXF1ZXN0LFxuICAgIG9uRGVsdGE6ICh0OiBzdHJpbmcpID0+IHZvaWQsXG4gICAgb3B0cz86IHsgaW5jbHVkZVBhcnRpYWxNZXNzYWdlcz86IGJvb2xlYW4gfSxcbiAgKTogUHJvbWlzZTxHZW5lcmF0ZVJlc3VsdD4ge1xuICAgIC8vIG1vZGVsIOygleq3nO2ZlOulvCBkaXNwYXRjaGVyIOynhOyeheygkOyXkOyEnCDtlZwg67KIIO2VnOuLpDogcmVzdWx0Lm1vZGVsIC8gcnVuQ2xhdWRlU2Vzc2lvbiDsoITrtoBcbiAgICAvLyBjYW5vbmljYWwocHJlZml4IOyXhuuKlCBjb3N0IO2CpCkg7J2EIOyTsOqyjCDthrXsnbwuIOuvuOyngOygleydtOuptCBBTlRIUk9QSUNfREVGQVVMVF9NT0RFTCDigJQgcWdyaWQuZGlzcGF0Y2hlclxuICAgIC8vIOydmCBcInNvbm5ldFwiIOuzhOy5rSDsmrDtmowg7LCo64uoLiDsoJXqt5ztmZQg6rec7LmZ7J2AIGZhbGxiYWNrIOqyveuhnOyZgCDqs7XsnKAoY2Fub25pY2FsQW50aHJvcGljTW9kZWwpLlxuICAgIGFzc2VydFN1cHBvcnRlZE9uZU1pbGxpb25TdWZmaXgocmVxLm1vZGVsKTtcbiAgICBjb25zdCBtb2RlbCA9IGNhbm9uaWNhbEFudGhyb3BpY01vZGVsKHJlcS5tb2RlbCk7XG4gICAgY29uc3QganNvblNjaGVtYSA9XG4gICAgICByZXEub3V0cHV0U2NoZW1hICE9PSB1bmRlZmluZWQgPyBKU09OLnN0cmluZ2lmeShyZXEub3V0cHV0U2NoZW1hKSA6IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IHRva2VuID0gdGhpcy5zZWxlY3RUb2tlbigpO1xuICAgIGlmICghdG9rZW4pIHRocm93IG5ldyBFcnJvcihcIk5vIGFudGhyb3BpYyB0b2tlbnMgYXZhaWxhYmxlXCIpO1xuXG4gICAgY29uc3QgZXhlYyA9IGFzeW5jICgpOiBQcm9taXNlPEdlbmVyYXRlUmVzdWx0PiA9PiB7XG4gICAgICAvLyDrp4zro4wg7J6E67CVIO2GoO2BsCBwcmVlbXB0aXZlIHJlZnJlc2go6riw7KG0IHN0YW5kYWxvbmUg6rK966Gc7JmAIOuPmeydvCkuIOyLpO2MqO2VtOuPhCDsp4TtlokuXG4gICAgICBsZXQgYWNjZXNzVG9rZW4gPSB0b2tlbi5jcmVkZW50aWFscy5hY2Nlc3NUb2tlbjtcbiAgICAgIGNvbnN0IGV4cGlyZXNBdCA9IGdldEV4cGlyZXNBdCh0b2tlbi5jcmVkZW50aWFscyk7XG4gICAgICBpZiAoXG4gICAgICAgIGV4cGlyZXNBdCAmJlxuICAgICAgICBleHBpcmVzQXQgLSBEYXRlLm5vdygpIDwgUkVGUkVTSF9TQUZFVFlfTVMgJiZcbiAgICAgICAgZ2V0UmVmcmVzaFRva2VuKHRva2VuLmNyZWRlbnRpYWxzKVxuICAgICAgKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgeyBRZ3JpZEZyYW1lIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi8uLi8uLi9hcHBsaWNhdGlvbi9xZ3JpZC9xZ3JpZC5mcmFtZVwiKTtcbiAgICAgICAgICAvLyBwcm92aWRlciDrpbwg67CY65Oc7IucIOyxhOybjOyVvCByZWZyZXNoVG9rZW4g64K067aAIFRva2VuTW9kZWwuc2F2ZSDqsIAg7ISx6rO17ZWc64ukLlxuICAgICAgICAgIC8vIHJlZnJlc2hUb2tlbihUb2tlblN1YnNldEEpIOuKlCBpZC9wcm92aWRlci9jcmVkZW50aWFscy9uYW1lIOunjCDsgqzsmqntlZjrr4DroZwg6re4IDTqsJzrp4wg64SY6ri064ukLlxuICAgICAgICAgIGFjY2Vzc1Rva2VuID0gYXdhaXQgUWdyaWRGcmFtZS5yZWZyZXNoVG9rZW4oe1xuICAgICAgICAgICAgaWQ6IHRva2VuLmlkLFxuICAgICAgICAgICAgcHJvdmlkZXI6IFwiYW50aHJvcGljXCIsXG4gICAgICAgICAgICBuYW1lOiB0b2tlbi5uYW1lLFxuICAgICAgICAgICAgY3JlZGVudGlhbHM6IHRva2VuLmNyZWRlbnRpYWxzLFxuICAgICAgICAgIH0gYXMgUGFyYW1ldGVyczx0eXBlb2YgUWdyaWRGcmFtZS5yZWZyZXNoVG9rZW4+WzBdKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIGxvZ2dlci53YXJuKGByZWZyZXNoIGZhaWxlZCBmb3IgJHt0b2tlbi5uYW1lfTogJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBsb2dnZXIuaW5mbyhg4oaSICR7dG9rZW4ubmFtZX0gKG1vZGVsOiAke21vZGVsfSlgKTtcbiAgICAgIGNvbnN0IHNlc3Npb24gPSBhd2FpdCBydW5DbGF1ZGVTZXNzaW9uKFxuICAgICAgICB7XG4gICAgICAgICAgdG9rZW5JZDogdG9rZW4uaWQsXG4gICAgICAgICAgdG9rZW46IGFjY2Vzc1Rva2VuLFxuICAgICAgICAgIG1vZGVsLFxuICAgICAgICAgIHN5c3RlbTogcmVxLnN5c3RlbVByb21wdCxcbiAgICAgICAgICBqc29uU2NoZW1hLFxuICAgICAgICAgIGVmZm9ydDogcmVxLmVmZm9ydCxcbiAgICAgICAgICB0aW1lb3V0TXM6IERFRkFVTFRfVElNRU9VVF9NUyxcbiAgICAgICAgICBjb2xkSGlzdG9yeTogcmVxLmNvbGRIaXN0b3J5LFxuICAgICAgICAgIGlucHV0OiByZXEuY29sZElucHV0LFxuICAgICAgICAgIGFib3J0U2lnbmFsOiByZXEuYWJvcnRTaWduYWwsXG4gICAgICAgICAgaW5jbHVkZVBhcnRpYWxNZXNzYWdlczogb3B0cz8uaW5jbHVkZVBhcnRpYWxNZXNzYWdlcyxcbiAgICAgICAgfSxcbiAgICAgICAgb25EZWx0YSxcbiAgICAgICk7XG5cbiAgICAgIGlmIChzZXNzaW9uLnF1b3RhRXhoYXVzdGVkKSB0aHJvdyBuZXcgRXJyb3IoYHF1b3RhIGV4aGF1c3RlZCAoJHt0b2tlbi5uYW1lfSlgKTtcbiAgICAgIGlmIChzZXNzaW9uLmlzRXJyb3IpIHtcbiAgICAgICAgLy8g7KeE64uoKFNPTi00OTUpOiBpc0Vycm9yIO2MkOyglSDsgqzsnKAoc3VidHlwZS90ZXJtaW5hbF9yZWFzb24p66W8IOuplOyLnOyngCDslZ7sl5Ag65Oc65+s64K464ukLlxuICAgICAgICAvLyDqt7jrj5nslYggZGV0YWlsIOydtCBzZXNzaW9uLnRleHQo7JmE7KCE7ZWcIEpTT04g67O466y4Keu/kOydtOudvCBcInNjaGVtYSDsnITrsJjsnbjsp4AgLyBtYXggcmV0cmllcyDsnbjsp4AgL1xuICAgICAgICAvLyBtYXggdHVybnMg7J247KeAXCLrpbwg6rWs67aE7ZWgIOyImCDsl4bsl4jri6QuIHRleHQg64qUIOynhOuLqOyXkCDtlYTsmpTtlZwg66eM7YG866eMIOyemOudvCDrjafrtpnsnbjri6QuXG4gICAgICAgIGNvbnN0IHJlYXNvbiA9XG4gICAgICAgICAgc2Vzc2lvbi5zdWJ0eXBlID8/IHNlc3Npb24udGVybWluYWxSZWFzb24gPz8gKHNlc3Npb24uaXNFcnJvciA/IFwiaXNfZXJyb3JcIiA6IFwidW5rbm93blwiKTtcbiAgICAgICAgY29uc3QgYm9keSA9IHNlc3Npb24udGV4dFxuICAgICAgICAgID8gc2Vzc2lvbi50ZXh0Lmxlbmd0aCA+IDUwMFxuICAgICAgICAgICAgPyBgJHtzZXNzaW9uLnRleHQuc2xpY2UoMCwgNTAwKX3igKYoJHtzZXNzaW9uLnRleHQubGVuZ3RofSBjaGFycylgXG4gICAgICAgICAgICA6IHNlc3Npb24udGV4dFxuICAgICAgICAgIDogYGVtcHR5IHRleHQsIG91dHB1dFRva2Vucz0ke3Nlc3Npb24udXNhZ2Uub3V0cHV0VG9rZW5zfWA7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgY2xhdWRlIGVycm9yICgke3Rva2VuLm5hbWV9KSBbJHtyZWFzb259XTogJHtib2R5fWApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICB0ZXh0OiBzZXNzaW9uLnRleHQsXG4gICAgICAgIHRva2VuTmFtZTogdG9rZW4ubmFtZSxcbiAgICAgICAgdXNhZ2U6IHNlc3Npb24udXNhZ2UsXG4gICAgICAgIGR1cmF0aW9uTXM6IHNlc3Npb24uZHVyYXRpb25NcyxcbiAgICAgICAgY29zdFVzZDogc2Vzc2lvbi5jb3N0VXNkLFxuICAgICAgICBtb2RlbCxcbiAgICAgICAgLy8gc3lzdGVtSGFzaCDripQg7IOB7JyEIGlzc3VlQ29udkNvbnRleHQg6rCAIOyxhOyatOuLpCjsl6zquLDshKAg67mE7Jq064ukKS5cbiAgICAgICAgdGhyZWFkQ29vcmQ6IHtcbiAgICAgICAgICB3b3JrZXJJZDogbWFrZUFudGhyb3BpY1dvcmtlcklkKHRva2VuLmlkKSxcbiAgICAgICAgICB0aHJlYWRJZDogc2Vzc2lvbi5zZXNzaW9uSWQsXG4gICAgICAgICAgZXBvY2g6IDAsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgIH07XG5cbiAgICByZXR1cm4gZXhlYygpO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUEyQkEsTUFBTSxTQUFTLFVBQVUsQ0FBQyxTQUFTLHVCQUF1QixDQUFDO0FBSTNELE1BQU0scUJBQXFCO0FBRTNCLE1BQU0sb0JBQW9CO0FBUTFCLElBQWEsc0JBQWIsTUFBK0Q7Q0FFN0QsNEJBQW9CLElBQUksS0FBMEI7Q0FFbEQsZ0NBQXdCLElBQUksS0FBcUI7Q0FDakQsVUFBa0I7Q0FFbEIsTUFBTSxRQUF1QjtFQUszQixNQUFNLFNBQVMsTUFBTSxXQUFXLHFCQUFxQixLQUFLLFlBQVk7QUFDdEUsT0FBSyxNQUFNLEtBQUssUUFBUTtBQUN0QixRQUFLLFVBQVUsSUFBSSxFQUFFLElBQUk7SUFDdkIsSUFBSSxFQUFFO0lBQ04sTUFBTSxFQUFFO0lBQ1IsYUFBYSxFQUFFO0lBQ2hC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