@cartanova/qgrid-cli 2.5.3 → 2.5.5

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 (65) hide show
  1. package/README.ko.md +7 -2
  2. package/README.md +7 -2
  3. package/bundle/dist/application/monit/monit.frame.js +3 -3
  4. package/bundle/dist/application/qgrid/oauth.js +1 -1
  5. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +36 -14
  6. package/bundle/dist/application/qgrid/qgrid.frame.js +19 -5
  7. package/bundle/dist/application/qgrid/tool-emulation-schema.js +93 -0
  8. package/bundle/dist/application/qgrid/tool-emulation.js +116 -96
  9. package/bundle/dist/application/request-log/request-log.model.js +3 -3
  10. package/bundle/dist/application/request-log-step/request-log-step.model.js +2 -2
  11. package/bundle/dist/application/token/token.model.js +2 -2
  12. package/bundle/dist/server-error-handler.js +15 -0
  13. package/bundle/dist/sonamu.config.js +4 -7
  14. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +4 -3
  15. package/bundle/dist/utils/providers/anthropic/claude-session.js +7 -5
  16. package/bundle/dist/utils/providers/common/json-schema-keywords.js +77 -0
  17. package/bundle/dist/utils/providers/common/schema-validation.js +178 -0
  18. package/bundle/dist/utils/providers/common/strictifier.js +332 -42
  19. package/bundle/dist/utils/providers/openai/codex-worker.js +16 -8
  20. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +5 -37
  21. package/bundle/dist/utils/providers/openai/openai-worker-pool-config.js +37 -0
  22. package/bundle/src/application/monit/monit.frame.ts +1 -1
  23. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +103 -0
  24. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +337 -0
  25. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +45 -25
  26. package/bundle/src/application/qgrid/qgrid.frame.test.ts +580 -8
  27. package/bundle/src/application/qgrid/qgrid.frame.ts +28 -1
  28. package/bundle/src/application/qgrid/tool-emulation-schema.test.ts +188 -0
  29. package/bundle/src/application/qgrid/tool-emulation-schema.ts +177 -0
  30. package/bundle/src/application/qgrid/tool-emulation.test.ts +285 -67
  31. package/bundle/src/application/qgrid/tool-emulation.ts +199 -102
  32. package/bundle/src/server-error-handler.ts +22 -0
  33. package/bundle/src/sonamu.config.test.ts +37 -0
  34. package/bundle/src/sonamu.config.ts +2 -5
  35. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.test.ts +44 -0
  36. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +2 -2
  37. package/bundle/src/utils/providers/anthropic/claude-session.test.ts +10 -0
  38. package/bundle/src/utils/providers/anthropic/claude-session.ts +6 -1
  39. package/bundle/src/utils/providers/common/json-schema-keywords.ts +72 -0
  40. package/bundle/src/utils/providers/common/schema-validation.test.ts +284 -0
  41. package/bundle/src/utils/providers/common/schema-validation.ts +308 -0
  42. package/bundle/src/utils/providers/common/strictifier.test.ts +746 -0
  43. package/bundle/src/utils/providers/common/strictifier.ts +520 -52
  44. package/bundle/src/utils/providers/openai/codex-worker.test.ts +31 -0
  45. package/bundle/src/utils/providers/openai/codex-worker.ts +12 -4
  46. package/bundle/src/utils/providers/openai/openai-dispatcher.test.ts +6 -4
  47. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +6 -79
  48. package/bundle/src/utils/providers/openai/openai-worker-pool-config.ts +80 -0
  49. package/bundle/web-dist/client/assets/{index-DXdGBfB8.js → index-CN_kMswh.js} +3 -3
  50. package/bundle/web-dist/client/assets/{logs-D_j1yxC4.js → logs-6nYj9OKL.js} +1 -1
  51. package/bundle/web-dist/client/assets/{monit-CIToyoxW.js → monit-CaPH9Uwc.js} +1 -1
  52. package/bundle/web-dist/client/assets/{routes-Dd21A-wi.js → routes-Dh5HPi-b.js} +1 -1
  53. package/bundle/web-dist/client/assets/{show-DfePWRbc.js → show-Be_LVd9d.js} +1 -1
  54. package/bundle/web-dist/client/assets/{tokens-B4MV2fdk.js → tokens-CAi3zu_0.js} +1 -1
  55. package/bundle/web-dist/client/index.html +1 -1
  56. package/bundle/web-dist/server/entry-server.generated.js +1 -1
  57. package/package.json +1 -1
  58. package/skills/qgrid/references/ai-sdk-provider-contract.md +34 -2
  59. package/skills/qgrid/references/anthropic-claude-code-runtime.md +3 -0
  60. package/skills/qgrid/references/cli-env-and-server-boot.md +1 -1
  61. package/skills/qgrid/references/decision-rationale.md +10 -1
  62. package/skills/qgrid/references/docs-workflow.md +9 -0
  63. package/skills/qgrid/references/repo-map.md +2 -1
  64. package/skills/qgrid/references/tool-calling-and-multiturn.md +145 -6
  65. package/skills/qgrid/references/verification-and-debugging.md +16 -1
@@ -0,0 +1,178 @@
1
+ import { Buffer } from "node:buffer";
2
+ //#region src/utils/providers/common/schema-validation.ts
3
+ /**
4
+ * Caller-provided schemas are serialized, copied, and recursively normalized before dispatch.
5
+ * Keep these limits comfortably above normal generated schemas while bounding that preprocessing
6
+ * well below the API's 10 MiB request-body ceiling.
7
+ */
8
+ const CALLER_SCHEMA_LIMITS = {
9
+ maxUtf8Bytes: 512 * 1024,
10
+ maxNodes: 2e4,
11
+ maxDepth: 128
12
+ };
13
+ const ARGV_SAFE_MAX_UTF8_BYTES = 64 * 1024;
14
+ const ANTHROPIC_SCHEMA_ARGV_MAX_UTF8_BYTES = ARGV_SAFE_MAX_UTF8_BYTES;
15
+ var CallerSchemaValidationError = class extends Error {
16
+ constructor(message) {
17
+ super(`qgrid: ${message}`);
18
+ this.name = "CallerSchemaValidationError";
19
+ }
20
+ };
21
+ function parseAndValidateCallerSchemas(input) {
22
+ const state = {
23
+ utf8Bytes: 0,
24
+ nodes: 0,
25
+ schemas: 0
26
+ };
27
+ let outputSchema;
28
+ if (input.jsonSchema !== void 0) {
29
+ addUtf8Bytes(Buffer.byteLength(input.jsonSchema, "utf8"), "jsonSchema", state);
30
+ let parsed;
31
+ try {
32
+ parsed = JSON.parse(input.jsonSchema);
33
+ } catch {
34
+ throw new CallerSchemaValidationError("jsonSchema must contain valid JSON");
35
+ }
36
+ if (!isRecord(parsed) || parsed.type !== "object") throw new CallerSchemaValidationError("jsonSchema top-level type must be \"object\"");
37
+ addComplexity(parsed, "jsonSchema", state);
38
+ state.schemas += 1;
39
+ outputSchema = parsed;
40
+ }
41
+ for (const [index, tool] of (input.tools ?? []).entries()) {
42
+ addToolMetadataUtf8Bytes(tool, index, state);
43
+ const path = `tools[${index}].inputSchema`;
44
+ addComplexity(tool.inputSchema, path, state, true);
45
+ addUtf8Bytes(jsonStringContentUtf8ByteUpperBound(stringifyJsonOrThrow(tool.inputSchema, path)), path, state);
46
+ state.schemas += 1;
47
+ }
48
+ return outputSchema;
49
+ }
50
+ function serializeAndValidateDispatchSchema(schema, provider) {
51
+ if (schema === void 0) return void 0;
52
+ const serialized = stringifyJsonOrThrow(schema, "dispatch schema");
53
+ if (Buffer.byteLength(serialized, "utf8") > CALLER_SCHEMA_LIMITS.maxUtf8Bytes) throw new CallerSchemaValidationError(`dispatch schema exceeds UTF-8 byte limit of ${CALLER_SCHEMA_LIMITS.maxUtf8Bytes}`);
54
+ if (provider === "anthropic") assertAnthropicSchemaArgvSize(serialized);
55
+ return serialized;
56
+ }
57
+ function assertAnthropicSchemaArgvSize(jsonSchema) {
58
+ if (Buffer.byteLength(jsonSchema, "utf8") > 65536) throw new CallerSchemaValidationError(`Anthropic dispatch schema exceeds argv UTF-8 byte limit of ${ANTHROPIC_SCHEMA_ARGV_MAX_UTF8_BYTES}`);
59
+ }
60
+ function stringifyJsonOrThrow(value, subject) {
61
+ let serialized;
62
+ try {
63
+ serialized = JSON.stringify(value);
64
+ } catch {
65
+ throw new CallerSchemaValidationError(`${subject} must be JSON-serializable`);
66
+ }
67
+ if (serialized === void 0) throw new CallerSchemaValidationError(`${subject} must be JSON-serializable`);
68
+ return serialized;
69
+ }
70
+ function addUtf8Bytes(byteLength, path, state) {
71
+ state.utf8Bytes += byteLength;
72
+ if (state.utf8Bytes > CALLER_SCHEMA_LIMITS.maxUtf8Bytes) throwLimitError(path, "UTF-8 byte", CALLER_SCHEMA_LIMITS.maxUtf8Bytes, state);
73
+ }
74
+ const TOOL_DESCRIPTION_ENTRY_PREFIX = "- ";
75
+ const TOOL_DESCRIPTION_NAME_SEPARATOR = ": ";
76
+ const TOOL_DESCRIPTION_INPUT_SCHEMA_PREFIX = "\n inputSchema: ";
77
+ const TOOL_DESCRIPTION_ENTRY_SEPARATOR = "\n";
78
+ function addToolMetadataUtf8Bytes(tool, index, state) {
79
+ const toolPath = `tools[${index}]`;
80
+ addUtf8Bytes(jsonStringContentUtf8ByteUpperBound(tool.name) * 2 + 2, `${toolPath}.name`, state);
81
+ if (tool.description !== void 0) addUtf8Bytes(jsonStringContentUtf8ByteUpperBound(tool.description), `${toolPath}.description`, state);
82
+ addUtf8Bytes(jsonStringContentUtf8ByteUpperBound(TOOL_DESCRIPTION_ENTRY_PREFIX) + jsonStringContentUtf8ByteUpperBound(TOOL_DESCRIPTION_NAME_SEPARATOR) + jsonStringContentUtf8ByteUpperBound(TOOL_DESCRIPTION_INPUT_SCHEMA_PREFIX) + (index === 0 ? 0 : jsonStringContentUtf8ByteUpperBound(TOOL_DESCRIPTION_ENTRY_SEPARATOR) + 1), toolPath, state);
83
+ }
84
+ /**
85
+ * Returns a conservative UTF-8 byte count for a string when it becomes JSON string content,
86
+ * without allocating the escaped representation. JSON.stringify uses short two-byte escapes for
87
+ * five control characters; counting every control character as a six-byte `\u00XX` escape keeps
88
+ * this an upper bound while avoiding a second large temporary string.
89
+ */
90
+ function jsonStringContentUtf8ByteUpperBound(value) {
91
+ let bytes = 0;
92
+ for (let index = 0; index < value.length; index += 1) {
93
+ const codeUnit = value.charCodeAt(index);
94
+ if (codeUnit === 34 || codeUnit === 92) {
95
+ bytes += 2;
96
+ continue;
97
+ }
98
+ if (codeUnit <= 31) {
99
+ bytes += 6;
100
+ continue;
101
+ }
102
+ if (codeUnit >= 55296 && codeUnit <= 56319) {
103
+ const nextCodeUnit = value.charCodeAt(index + 1);
104
+ if (nextCodeUnit >= 56320 && nextCodeUnit <= 57343) {
105
+ bytes += 4;
106
+ index += 1;
107
+ } else bytes += 6;
108
+ continue;
109
+ }
110
+ if (codeUnit >= 56320 && codeUnit <= 57343) {
111
+ bytes += 6;
112
+ continue;
113
+ }
114
+ bytes += codeUnit <= 127 ? 1 : codeUnit <= 2047 ? 2 : 3;
115
+ }
116
+ return bytes;
117
+ }
118
+ function addComplexity(root, path, state, precheckUtf8Bytes = false) {
119
+ const rawUtf8Bytes = { value: 0 };
120
+ if (precheckUtf8Bytes && typeof root === "string") addRawUtf8LowerBound(root, path, state, rawUtf8Bytes);
121
+ addNode(path, state);
122
+ if (root === null || typeof root !== "object") return;
123
+ const stack = [{
124
+ value: root,
125
+ depth: 0
126
+ }];
127
+ while (stack.length > 0) {
128
+ const current = stack.pop();
129
+ if (Array.isArray(current.value)) {
130
+ for (let index = 0; index < current.value.length; index += 1) {
131
+ const depth = current.depth + 1;
132
+ assertDepthWithinLimit(depth, path);
133
+ addNode(path, state);
134
+ const child = current.value[index];
135
+ if (precheckUtf8Bytes && typeof child === "string") addRawUtf8LowerBound(child, path, state, rawUtf8Bytes);
136
+ if (child !== null && typeof child === "object") stack.push({
137
+ value: child,
138
+ depth
139
+ });
140
+ }
141
+ continue;
142
+ }
143
+ for (const key in current.value) {
144
+ if (!Object.hasOwn(current.value, key)) continue;
145
+ if (precheckUtf8Bytes) addRawUtf8LowerBound(key, path, state, rawUtf8Bytes);
146
+ const depth = current.depth + 1;
147
+ assertDepthWithinLimit(depth, path);
148
+ addNode(path, state);
149
+ const child = current.value[key];
150
+ if (precheckUtf8Bytes && typeof child === "string") addRawUtf8LowerBound(child, path, state, rawUtf8Bytes);
151
+ if (child !== null && typeof child === "object") stack.push({
152
+ value: child,
153
+ depth
154
+ });
155
+ }
156
+ }
157
+ }
158
+ function addRawUtf8LowerBound(value, path, state, rawUtf8Bytes) {
159
+ rawUtf8Bytes.value += Buffer.byteLength(value, "utf8");
160
+ if (state.utf8Bytes + rawUtf8Bytes.value > CALLER_SCHEMA_LIMITS.maxUtf8Bytes) throwLimitError(path, "UTF-8 byte", CALLER_SCHEMA_LIMITS.maxUtf8Bytes, state);
161
+ }
162
+ function assertDepthWithinLimit(depth, path) {
163
+ if (depth > CALLER_SCHEMA_LIMITS.maxDepth) throw new CallerSchemaValidationError(`${path} exceeds depth limit of ${CALLER_SCHEMA_LIMITS.maxDepth}`);
164
+ }
165
+ function addNode(path, state) {
166
+ state.nodes += 1;
167
+ if (state.nodes > CALLER_SCHEMA_LIMITS.maxNodes) throwLimitError(path, "node", CALLER_SCHEMA_LIMITS.maxNodes, state);
168
+ }
169
+ function throwLimitError(path, kind, limit, state) {
170
+ throw new CallerSchemaValidationError(state.schemas === 0 ? `${path} exceeds ${kind} limit of ${limit}` : `caller schemas exceed aggregate ${kind} limit of ${limit}`);
171
+ }
172
+ function isRecord(value) {
173
+ return value !== null && typeof value === "object" && !Array.isArray(value);
174
+ }
175
+ //#endregion
176
+ export { ANTHROPIC_SCHEMA_ARGV_MAX_UTF8_BYTES, ARGV_SAFE_MAX_UTF8_BYTES, CALLER_SCHEMA_LIMITS, CallerSchemaValidationError, assertAnthropicSchemaArgvSize, parseAndValidateCallerSchemas, serializeAndValidateDispatchSchema };
177
+
178
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NoZW1hLXZhbGlkYXRpb24uanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Byb3ZpZGVycy9jb21tb24vc2NoZW1hLXZhbGlkYXRpb24udHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQnVmZmVyIH0gZnJvbSBcIm5vZGU6YnVmZmVyXCI7XG5cbmltcG9ydCB7IHR5cGUgSnNvblZhbHVlIH0gZnJvbSBcIi4uLy4uLy4uL2NvZGV4LXByb3RvY29sL3NlcmRlX2pzb24vSnNvblZhbHVlXCI7XG5cbi8qKlxuICogQ2FsbGVyLXByb3ZpZGVkIHNjaGVtYXMgYXJlIHNlcmlhbGl6ZWQsIGNvcGllZCwgYW5kIHJlY3Vyc2l2ZWx5IG5vcm1hbGl6ZWQgYmVmb3JlIGRpc3BhdGNoLlxuICogS2VlcCB0aGVzZSBsaW1pdHMgY29tZm9ydGFibHkgYWJvdmUgbm9ybWFsIGdlbmVyYXRlZCBzY2hlbWFzIHdoaWxlIGJvdW5kaW5nIHRoYXQgcHJlcHJvY2Vzc2luZ1xuICogd2VsbCBiZWxvdyB0aGUgQVBJJ3MgMTAgTWlCIHJlcXVlc3QtYm9keSBjZWlsaW5nLlxuICovXG5leHBvcnQgY29uc3QgQ0FMTEVSX1NDSEVNQV9MSU1JVFMgPSB7XG4gIG1heFV0ZjhCeXRlczogNTEyICogMTAyNCxcbiAgbWF4Tm9kZXM6IDIwXzAwMCxcbiAgbWF4RGVwdGg6IDEyOCxcbn0gYXMgY29uc3Q7XG5cbi8vIExpbnV4IHBlcm1pdHMgYXQgbW9zdCAxMjggS2lCIChNQVhfQVJHX1NUUkxFTikgZm9yIG9uZSBhcmd2IHZhbHVlLiBxZ3JpZCB1c2VzIGEgNTAlIHNhZmV0eVxuLy8gbWFyZ2luIGZvciBldmVyeSBhcmd2LWRlbGl2ZXJlZCBwYXlsb2FkIOKAlCBDbGF1ZGUgQ29kZSAtLWpzb24tc2NoZW1hIGhlcmUgYW5kIHRoZSBzeXN0ZW0tcHJvbXB0XG4vLyB0cmFuc3BvcnQgKGNsYXVkZS1zZXNzaW9uKSBib3RoIGRlcml2ZSBmcm9tIHRoaXMgc2luZ2xlIGNvbnN0YW50LlxuZXhwb3J0IGNvbnN0IEFSR1ZfU0FGRV9NQVhfVVRGOF9CWVRFUyA9IDY0ICogMTAyNDtcbmV4cG9ydCBjb25zdCBBTlRIUk9QSUNfU0NIRU1BX0FSR1ZfTUFYX1VURjhfQllURVMgPSBBUkdWX1NBRkVfTUFYX1VURjhfQllURVM7XG5cbmV4cG9ydCBjbGFzcyBDYWxsZXJTY2hlbWFWYWxpZGF0aW9uRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZykge1xuICAgIHN1cGVyKGBxZ3JpZDogJHttZXNzYWdlfWApO1xuICAgIHRoaXMubmFtZSA9IFwiQ2FsbGVyU2NoZW1hVmFsaWRhdGlvbkVycm9yXCI7XG4gIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBDYWxsZXJTY2hlbWFzSW5wdXQge1xuICBqc29uU2NoZW1hPzogc3RyaW5nO1xuICB0b29scz86IEFycmF5PHsgbmFtZTogc3RyaW5nOyBkZXNjcmlwdGlvbj86IHN0cmluZzsgaW5wdXRTY2hlbWE6IHVua25vd24gfT47XG59XG5cbmludGVyZmFjZSBDb21wbGV4aXR5U3RhdGUge1xuICB1dGY4Qnl0ZXM6IG51bWJlcjtcbiAgbm9kZXM6IG51bWJlcjtcbiAgc2NoZW1hczogbnVtYmVyO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VBbmRWYWxpZGF0ZUNhbGxlclNjaGVtYXMoaW5wdXQ6IENhbGxlclNjaGVtYXNJbnB1dCk6IEpzb25WYWx1ZSB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHN0YXRlOiBDb21wbGV4aXR5U3RhdGUgPSB7XG4gICAgdXRmOEJ5dGVzOiAwLFxuICAgIG5vZGVzOiAwLFxuICAgIHNjaGVtYXM6IDAsXG4gIH07XG4gIGxldCBvdXRwdXRTY2hlbWE6IEpzb25WYWx1ZSB8IHVuZGVmaW5lZDtcblxuICBpZiAoaW5wdXQuanNvblNjaGVtYSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgYWRkVXRmOEJ5dGVzKEJ1ZmZlci5ieXRlTGVuZ3RoKGlucHV0Lmpzb25TY2hlbWEsIFwidXRmOFwiKSwgXCJqc29uU2NoZW1hXCIsIHN0YXRlKTtcblxuICAgIGxldCBwYXJzZWQ6IHVua25vd247XG4gICAgdHJ5IHtcbiAgICAgIHBhcnNlZCA9IEpTT04ucGFyc2UoaW5wdXQuanNvblNjaGVtYSk7XG4gICAgfSBjYXRjaCB7XG4gICAgICB0aHJvdyBuZXcgQ2FsbGVyU2NoZW1hVmFsaWRhdGlvbkVycm9yKFwianNvblNjaGVtYSBtdXN0IGNvbnRhaW4gdmFsaWQgSlNPTlwiKTtcbiAgICB9XG5cbiAgICBpZiAoIWlzUmVjb3JkKHBhcnNlZCkgfHwgcGFyc2VkLnR5cGUgIT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHRocm93IG5ldyBDYWxsZXJTY2hlbWFWYWxpZGF0aW9uRXJyb3IoJ2pzb25TY2hlbWEgdG9wLWxldmVsIHR5cGUgbXVzdCBiZSBcIm9iamVjdFwiJyk7XG4gICAgfVxuXG4gICAgYWRkQ29tcGxleGl0eShwYXJzZWQsIFwianNvblNjaGVtYVwiLCBzdGF0ZSk7XG4gICAgc3RhdGUuc2NoZW1hcyArPSAxO1xuICAgIG91dHB1dFNjaGVtYSA9IHBhcnNlZCBhcyBKc29uVmFsdWU7XG4gIH1cblxuICBmb3IgKGNvbnN0IFtpbmRleCwgdG9vbF0gb2YgKGlucHV0LnRvb2xzID8/IFtdKS5lbnRyaWVzKCkpIHtcbiAgICBhZGRUb29sTWV0YWRhdGFVdGY4Qnl0ZXModG9vbCwgaW5kZXgsIHN0YXRlKTtcblxuICAgIGNvbnN0IHBhdGggPSBgdG9vbHNbJHtpbmRleH1dLmlucHV0U2NoZW1hYDtcbiAgICBhZGRDb21wbGV4aXR5KHRvb2wuaW5wdXRTY2hlbWEsIHBhdGgsIHN0YXRlLCB0cnVlKTtcblxuICAgIGNvbnN0IHNlcmlhbGl6ZWQgPSBzdHJpbmdpZnlKc29uT3JUaHJvdyh0b29sLmlucHV0U2NoZW1hLCBwYXRoKTtcblxuICAgIC8vIGJ1aWxkVG9vbENhbGxTY2hlbWEgZW1iZWRzIHRoaXMgc2VyaWFsaXphdGlvbiBpbnNpZGUgYW5vdGhlciBKU09OIHN0cmluZy4gQ2hhcmdlIHRoZVxuICAgIC8vIGVzY2FwZWQgb3V0ZXItc3RyaW5nIHJlcHJlc2VudGF0aW9uIGJlZm9yZSB0aGF0IGNvbXBvc2VkIGRlc2NyaXB0aW9uIGlzIG1hdGVyaWFsaXplZC5cbiAgICBhZGRVdGY4Qnl0ZXMoanNvblN0cmluZ0NvbnRlbnRVdGY4Qnl0ZVVwcGVyQm91bmQoc2VyaWFsaXplZCksIHBhdGgsIHN0YXRlKTtcbiAgICBzdGF0ZS5zY2hlbWFzICs9IDE7XG4gIH1cblxuICByZXR1cm4gb3V0cHV0U2NoZW1hO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2VyaWFsaXplQW5kVmFsaWRhdGVEaXNwYXRjaFNjaGVtYShcbiAgc2NoZW1hOiB1bmtub3duLFxuICBwcm92aWRlcj86IHN0cmluZyxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmIChzY2hlbWEgPT09IHVuZGVmaW5lZCkgcmV0dXJuIHVuZGVmaW5lZDtcblxuICBjb25zdCBzZXJpYWxpemVkID0gc3RyaW5naWZ5SnNvbk9yVGhyb3coc2NoZW1hLCBcImRpc3BhdGNoIHNjaGVtYVwiKTtcblxuICBjb25zdCBieXRlTGVuZ3RoID0gQnVmZmVyLmJ5dGVMZW5ndGgoc2VyaWFsaXplZCwgXCJ1dGY4XCIpO1xuICBpZiAoYnl0ZUxlbmd0aCA+IENBTExFUl9TQ0hFTUFfTElNSVRTLm1heFV0ZjhCeXRlcykge1xuICAgIHRocm93IG5ldyBDYWxsZXJTY2hlbWFWYWxpZGF0aW9uRXJyb3IoXG4gICAgICBgZGlzcGF0Y2ggc2NoZW1hIGV4Y2VlZHMgVVRGLTggYnl0ZSBsaW1pdCBvZiAke0NBTExFUl9TQ0hFTUFfTElNSVRTLm1heFV0ZjhCeXRlc31gLFxuICAgICk7XG4gIH1cbiAgaWYgKHByb3ZpZGVyID09PSBcImFudGhyb3BpY1wiKSB7XG4gICAgYXNzZXJ0QW50aHJvcGljU2NoZW1hQXJndlNpemUoc2VyaWFsaXplZCk7XG4gIH1cblxuICByZXR1cm4gc2VyaWFsaXplZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGFzc2VydEFudGhyb3BpY1NjaGVtYUFyZ3ZTaXplKGpzb25TY2hlbWE6IHN0cmluZyk6IHZvaWQge1xuICBpZiAoQnVmZmVyLmJ5dGVMZW5ndGgoanNvblNjaGVtYSwgXCJ1dGY4XCIpID4gQU5USFJPUElDX1NDSEVNQV9BUkdWX01BWF9VVEY4X0JZVEVTKSB7XG4gICAgdGhyb3cgbmV3IENhbGxlclNjaGVtYVZhbGlkYXRpb25FcnJvcihcbiAgICAgIGBBbnRocm9waWMgZGlzcGF0Y2ggc2NoZW1hIGV4Y2VlZHMgYXJndiBVVEYtOCBieXRlIGxpbWl0IG9mICR7QU5USFJPUElDX1NDSEVNQV9BUkdWX01BWF9VVEY4X0JZVEVTfWAsXG4gICAgKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBzdHJpbmdpZnlKc29uT3JUaHJvdyh2YWx1ZTogdW5rbm93biwgc3ViamVjdDogc3RyaW5nKTogc3RyaW5nIHtcbiAgbGV0IHNlcmlhbGl6ZWQ6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgdHJ5IHtcbiAgICBzZXJpYWxpemVkID0gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICB9IGNhdGNoIHtcbiAgICB0aHJvdyBuZXcgQ2FsbGVyU2NoZW1hVmFsaWRhdGlvbkVycm9yKGAke3N1YmplY3R9IG11c3QgYmUgSlNPTi1zZXJpYWxpemFibGVgKTtcbiAgfVxuICBpZiAoc2VyaWFsaXplZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgdGhyb3cgbmV3IENhbGxlclNjaGVtYVZhbGlkYXRpb25FcnJvcihgJHtzdWJqZWN0fSBtdXN0IGJlIEpTT04tc2VyaWFsaXphYmxlYCk7XG4gIH1cbiAgcmV0dXJuIHNlcmlhbGl6ZWQ7XG59XG5cbmZ1bmN0aW9uIGFkZFV0ZjhCeXRlcyhieXRlTGVuZ3RoOiBudW1iZXIsIHBhdGg6IHN0cmluZywgc3RhdGU6IENvbXBsZXhpdHlTdGF0ZSk6IHZvaWQge1xuICBzdGF0ZS51dGY4Qnl0ZXMgKz0gYnl0ZUxlbmd0aDtcbiAgaWYgKHN0YXRlLnV0ZjhCeXRlcyA+IENBTExFUl9TQ0hFTUFfTElNSVRTLm1heFV0ZjhCeXRlcykge1xuICAgIHRocm93TGltaXRFcnJvcihwYXRoLCBcIlVURi04IGJ5dGVcIiwgQ0FMTEVSX1NDSEVNQV9MSU1JVFMubWF4VXRmOEJ5dGVzLCBzdGF0ZSk7XG4gIH1cbn1cblxuY29uc3QgVE9PTF9ERVNDUklQVElPTl9FTlRSWV9QUkVGSVggPSBcIi0gXCI7XG5jb25zdCBUT09MX0RFU0NSSVBUSU9OX05BTUVfU0VQQVJBVE9SID0gXCI6IFwiO1xuY29uc3QgVE9PTF9ERVNDUklQVElPTl9JTlBVVF9TQ0hFTUFfUFJFRklYID0gXCJcXG4gIGlucHV0U2NoZW1hOiBcIjtcbmNvbnN0IFRPT0xfREVTQ1JJUFRJT05fRU5UUllfU0VQQVJBVE9SID0gXCJcXG5cIjtcblxuZnVuY3Rpb24gYWRkVG9vbE1ldGFkYXRhVXRmOEJ5dGVzKFxuICB0b29sOiBOb25OdWxsYWJsZTxDYWxsZXJTY2hlbWFzSW5wdXRbXCJ0b29sc1wiXT5bbnVtYmVyXSxcbiAgaW5kZXg6IG51bWJlcixcbiAgc3RhdGU6IENvbXBsZXhpdHlTdGF0ZSxcbik6IHZvaWQge1xuICBjb25zdCB0b29sUGF0aCA9IGB0b29sc1ske2luZGV4fV1gO1xuXG4gIC8vIGJ1aWxkVG9vbENhbGxTY2hlbWEgcGxhY2VzIGV2ZXJ5IHRvb2wgbmFtZSBpbiBib3RoIHRoZSBlbnVtIGFuZCB0aGUgaHVtYW4tcmVhZGFibGUgdG9vbFxuICAvLyBkZXNjcmlwdGlvbi4gQ291bnQgYm90aCBlc2NhcGVkIG9jY3VycmVuY2VzLCBwbHVzIHRoZSBlbnVtJ3MgSlNPTiBzdHJpbmcgZGVsaW1pdGVycy5cbiAgY29uc3QgZW5jb2RlZE5hbWVCeXRlcyA9IGpzb25TdHJpbmdDb250ZW50VXRmOEJ5dGVVcHBlckJvdW5kKHRvb2wubmFtZSk7XG4gIGFkZFV0ZjhCeXRlcyhlbmNvZGVkTmFtZUJ5dGVzICogMiArIDIsIGAke3Rvb2xQYXRofS5uYW1lYCwgc3RhdGUpO1xuXG4gIGlmICh0b29sLmRlc2NyaXB0aW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICBhZGRVdGY4Qnl0ZXMoXG4gICAgICBqc29uU3RyaW5nQ29udGVudFV0ZjhCeXRlVXBwZXJCb3VuZCh0b29sLmRlc2NyaXB0aW9uKSxcbiAgICAgIGAke3Rvb2xQYXRofS5kZXNjcmlwdGlvbmAsXG4gICAgICBzdGF0ZSxcbiAgICApO1xuICB9XG5cbiAgLy8gUGVyLXRvb2wgZnJhbWluZyBhbHNvIGdyb3dzIHdpdGggdGhlIG51bWJlciBvZiB0b29scyBldmVuIHdoZW4gYWxsIGNhbGxlciBzdHJpbmdzIGFyZSBlbXB0eS5cbiAgLy8gSW5jbHVkZSBib3RoIHRoZSB0b29sRGVzY3JpcHRpb25zIGpvaW4gc2VwYXJhdG9yIGFuZCB0aGUgZW51bSBjb21tYSBhZnRlciB0aGUgZmlyc3QgZW50cnkuXG4gIGNvbnN0IGZyYW1pbmdCeXRlcyA9XG4gICAganNvblN0cmluZ0NvbnRlbnRVdGY4Qnl0ZVVwcGVyQm91bmQoVE9PTF9ERVNDUklQVElPTl9FTlRSWV9QUkVGSVgpICtcbiAgICBqc29uU3RyaW5nQ29udGVudFV0ZjhCeXRlVXBwZXJCb3VuZChUT09MX0RFU0NSSVBUSU9OX05BTUVfU0VQQVJBVE9SKSArXG4gICAganNvblN0cmluZ0NvbnRlbnRVdGY4Qnl0ZVVwcGVyQm91bmQoVE9PTF9ERVNDUklQVElPTl9JTlBVVF9TQ0hFTUFfUFJFRklYKSArXG4gICAgKGluZGV4ID09PSAwID8gMCA6IGpzb25TdHJpbmdDb250ZW50VXRmOEJ5dGVVcHBlckJvdW5kKFRPT0xfREVTQ1JJUFRJT05fRU5UUllfU0VQQVJBVE9SKSArIDEpO1xuICBhZGRVdGY4Qnl0ZXMoZnJhbWluZ0J5dGVzLCB0b29sUGF0aCwgc3RhdGUpO1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBjb25zZXJ2YXRpdmUgVVRGLTggYnl0ZSBjb3VudCBmb3IgYSBzdHJpbmcgd2hlbiBpdCBiZWNvbWVzIEpTT04gc3RyaW5nIGNvbnRlbnQsXG4gKiB3aXRob3V0IGFsbG9jYXRpbmcgdGhlIGVzY2FwZWQgcmVwcmVzZW50YXRpb24uIEpTT04uc3RyaW5naWZ5IHVzZXMgc2hvcnQgdHdvLWJ5dGUgZXNjYXBlcyBmb3JcbiAqIGZpdmUgY29udHJvbCBjaGFyYWN0ZXJzOyBjb3VudGluZyBldmVyeSBjb250cm9sIGNoYXJhY3RlciBhcyBhIHNpeC1ieXRlIGBcXHUwMFhYYCBlc2NhcGUga2VlcHNcbiAqIHRoaXMgYW4gdXBwZXIgYm91bmQgd2hpbGUgYXZvaWRpbmcgYSBzZWNvbmQgbGFyZ2UgdGVtcG9yYXJ5IHN0cmluZy5cbiAqL1xuZnVuY3Rpb24ganNvblN0cmluZ0NvbnRlbnRVdGY4Qnl0ZVVwcGVyQm91bmQodmFsdWU6IHN0cmluZyk6IG51bWJlciB7XG4gIGxldCBieXRlcyA9IDA7XG5cbiAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IHZhbHVlLmxlbmd0aDsgaW5kZXggKz0gMSkge1xuICAgIGNvbnN0IGNvZGVVbml0ID0gdmFsdWUuY2hhckNvZGVBdChpbmRleCk7XG5cbiAgICBpZiAoY29kZVVuaXQgPT09IDB4MjIgfHwgY29kZVVuaXQgPT09IDB4NWMpIHtcbiAgICAgIGJ5dGVzICs9IDI7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgaWYgKGNvZGVVbml0IDw9IDB4MWYpIHtcbiAgICAgIGJ5dGVzICs9IDY7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgaWYgKGNvZGVVbml0ID49IDB4ZDgwMCAmJiBjb2RlVW5pdCA8PSAweGRiZmYpIHtcbiAgICAgIGNvbnN0IG5leHRDb2RlVW5pdCA9IHZhbHVlLmNoYXJDb2RlQXQoaW5kZXggKyAxKTtcbiAgICAgIGlmIChuZXh0Q29kZVVuaXQgPj0gMHhkYzAwICYmIG5leHRDb2RlVW5pdCA8PSAweGRmZmYpIHtcbiAgICAgICAgYnl0ZXMgKz0gNDtcbiAgICAgICAgaW5kZXggKz0gMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFdlbGwtZm9ybWVkIEpTT04uc3RyaW5naWZ5IGVzY2FwZXMgbG9uZSBzdXJyb2dhdGVzIGFzIGBcXHVYWFhYYC5cbiAgICAgICAgYnl0ZXMgKz0gNjtcbiAgICAgIH1cbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBpZiAoY29kZVVuaXQgPj0gMHhkYzAwICYmIGNvZGVVbml0IDw9IDB4ZGZmZikge1xuICAgICAgYnl0ZXMgKz0gNjtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGJ5dGVzICs9IGNvZGVVbml0IDw9IDB4N2YgPyAxIDogY29kZVVuaXQgPD0gMHg3ZmYgPyAyIDogMztcbiAgfVxuXG4gIHJldHVybiBieXRlcztcbn1cblxuZnVuY3Rpb24gYWRkQ29tcGxleGl0eShcbiAgcm9vdDogdW5rbm93bixcbiAgcGF0aDogc3RyaW5nLFxuICBzdGF0ZTogQ29tcGxleGl0eVN0YXRlLFxuICBwcmVjaGVja1V0ZjhCeXRlcyA9IGZhbHNlLFxuKTogdm9pZCB7XG4gIGNvbnN0IHJhd1V0ZjhCeXRlcyA9IHsgdmFsdWU6IDAgfTtcbiAgaWYgKHByZWNoZWNrVXRmOEJ5dGVzICYmIHR5cGVvZiByb290ID09PSBcInN0cmluZ1wiKSB7XG4gICAgYWRkUmF3VXRmOExvd2VyQm91bmQocm9vdCwgcGF0aCwgc3RhdGUsIHJhd1V0ZjhCeXRlcyk7XG4gIH1cbiAgYWRkTm9kZShwYXRoLCBzdGF0ZSk7XG4gIGlmIChyb290ID09PSBudWxsIHx8IHR5cGVvZiByb290ICE9PSBcIm9iamVjdFwiKSByZXR1cm47XG5cbiAgY29uc3Qgc3RhY2s6IEFycmF5PHsgdmFsdWU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5rbm93bltdOyBkZXB0aDogbnVtYmVyIH0+ID0gW1xuICAgIHsgdmFsdWU6IHJvb3QgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmtub3duW10sIGRlcHRoOiAwIH0sXG4gIF07XG5cbiAgd2hpbGUgKHN0YWNrLmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCBjdXJyZW50ID0gc3RhY2sucG9wKCkhO1xuICAgIGlmIChBcnJheS5pc0FycmF5KGN1cnJlbnQudmFsdWUpKSB7XG4gICAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgY3VycmVudC52YWx1ZS5sZW5ndGg7IGluZGV4ICs9IDEpIHtcbiAgICAgICAgY29uc3QgZGVwdGggPSBjdXJyZW50LmRlcHRoICsgMTtcbiAgICAgICAgYXNzZXJ0RGVwdGhXaXRoaW5MaW1pdChkZXB0aCwgcGF0aCk7XG4gICAgICAgIGFkZE5vZGUocGF0aCwgc3RhdGUpO1xuXG4gICAgICAgIGNvbnN0IGNoaWxkID0gY3VycmVudC52YWx1ZVtpbmRleF07XG4gICAgICAgIGlmIChwcmVjaGVja1V0ZjhCeXRlcyAmJiB0eXBlb2YgY2hpbGQgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICBhZGRSYXdVdGY4TG93ZXJCb3VuZChjaGlsZCwgcGF0aCwgc3RhdGUsIHJhd1V0ZjhCeXRlcyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNoaWxkICE9PSBudWxsICYmIHR5cGVvZiBjaGlsZCA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICAgIHN0YWNrLnB1c2goeyB2YWx1ZTogY2hpbGQgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmtub3duW10sIGRlcHRoIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGtleSBpbiBjdXJyZW50LnZhbHVlKSB7XG4gICAgICBpZiAoIU9iamVjdC5oYXNPd24oY3VycmVudC52YWx1ZSwga2V5KSkgY29udGludWU7XG4gICAgICBpZiAocHJlY2hlY2tVdGY4Qnl0ZXMpIHtcbiAgICAgICAgYWRkUmF3VXRmOExvd2VyQm91bmQoa2V5LCBwYXRoLCBzdGF0ZSwgcmF3VXRmOEJ5dGVzKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGRlcHRoID0gY3VycmVudC5kZXB0aCArIDE7XG4gICAgICBhc3NlcnREZXB0aFdpdGhpbkxpbWl0KGRlcHRoLCBwYXRoKTtcbiAgICAgIGFkZE5vZGUocGF0aCwgc3RhdGUpO1xuXG4gICAgICBjb25zdCBjaGlsZCA9IGN1cnJlbnQudmFsdWVba2V5XTtcbiAgICAgIGlmIChwcmVjaGVja1V0ZjhCeXRlcyAmJiB0eXBlb2YgY2hpbGQgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgYWRkUmF3VXRmOExvd2VyQm91bmQoY2hpbGQsIHBhdGgsIHN0YXRlLCByYXdVdGY4Qnl0ZXMpO1xuICAgICAgfVxuICAgICAgaWYgKGNoaWxkICE9PSBudWxsICYmIHR5cGVvZiBjaGlsZCA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICBzdGFjay5wdXNoKHsgdmFsdWU6IGNoaWxkIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5rbm93bltdLCBkZXB0aCB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gYWRkUmF3VXRmOExvd2VyQm91bmQoXG4gIHZhbHVlOiBzdHJpbmcsXG4gIHBhdGg6IHN0cmluZyxcbiAgc3RhdGU6IENvbXBsZXhpdHlTdGF0ZSxcbiAgcmF3VXRmOEJ5dGVzOiB7IHZhbHVlOiBudW1iZXIgfSxcbik6IHZvaWQge1xuICByYXdVdGY4Qnl0ZXMudmFsdWUgKz0gQnVmZmVyLmJ5dGVMZW5ndGgodmFsdWUsIFwidXRmOFwiKTtcbiAgaWYgKHN0YXRlLnV0ZjhCeXRlcyArIHJhd1V0ZjhCeXRlcy52YWx1ZSA+IENBTExFUl9TQ0hFTUFfTElNSVRTLm1heFV0ZjhCeXRlcykge1xuICAgIHRocm93TGltaXRFcnJvcihwYXRoLCBcIlVURi04IGJ5dGVcIiwgQ0FMTEVSX1NDSEVNQV9MSU1JVFMubWF4VXRmOEJ5dGVzLCBzdGF0ZSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gYXNzZXJ0RGVwdGhXaXRoaW5MaW1pdChkZXB0aDogbnVtYmVyLCBwYXRoOiBzdHJpbmcpOiB2b2lkIHtcbiAgaWYgKGRlcHRoID4gQ0FMTEVSX1NDSEVNQV9MSU1JVFMubWF4RGVwdGgpIHtcbiAgICB0aHJvdyBuZXcgQ2FsbGVyU2NoZW1hVmFsaWRhdGlvbkVycm9yKFxuICAgICAgYCR7cGF0aH0gZXhjZWVkcyBkZXB0aCBsaW1pdCBvZiAke0NBTExFUl9TQ0hFTUFfTElNSVRTLm1heERlcHRofWAsXG4gICAgKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBhZGROb2RlKHBhdGg6IHN0cmluZywgc3RhdGU6IENvbXBsZXhpdHlTdGF0ZSk6IHZvaWQge1xuICBzdGF0ZS5ub2RlcyArPSAxO1xuICBpZiAoc3RhdGUubm9kZXMgPiBDQUxMRVJfU0NIRU1BX0xJTUlUUy5tYXhOb2Rlcykge1xuICAgIHRocm93TGltaXRFcnJvcihwYXRoLCBcIm5vZGVcIiwgQ0FMTEVSX1NDSEVNQV9MSU1JVFMubWF4Tm9kZXMsIHN0YXRlKTtcbiAgfVxufVxuXG5mdW5jdGlvbiB0aHJvd0xpbWl0RXJyb3IoXG4gIHBhdGg6IHN0cmluZyxcbiAga2luZDogXCJVVEYtOCBieXRlXCIgfCBcIm5vZGVcIixcbiAgbGltaXQ6IG51bWJlcixcbiAgc3RhdGU6IENvbXBsZXhpdHlTdGF0ZSxcbik6IG5ldmVyIHtcbiAgdGhyb3cgbmV3IENhbGxlclNjaGVtYVZhbGlkYXRpb25FcnJvcihcbiAgICBzdGF0ZS5zY2hlbWFzID09PSAwXG4gICAgICA/IGAke3BhdGh9IGV4Y2VlZHMgJHtraW5kfSBsaW1pdCBvZiAke2xpbWl0fWBcbiAgICAgIDogYGNhbGxlciBzY2hlbWFzIGV4Y2VlZCBhZ2dyZWdhdGUgJHtraW5kfSBsaW1pdCBvZiAke2xpbWl0fWAsXG4gICk7XG59XG5cbmZ1bmN0aW9uIGlzUmVjb3JkKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4gdmFsdWUgIT09IG51bGwgJiYgdHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiICYmICFBcnJheS5pc0FycmF5KHZhbHVlKTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQVNBLE1BQWEsdUJBQXVCO0NBQ2xDLGNBQWMsTUFBTTtDQUNwQixVQUFVO0NBQ1YsVUFBVTtBQUNaO0FBS0EsTUFBYSwyQkFBMkIsS0FBSztBQUM3QyxNQUFhLHVDQUF1QztBQUVwRCxJQUFhLDhCQUFiLGNBQWlELE1BQU07Q0FDckQsWUFBWSxTQUFpQjtFQUMzQixNQUFNLFVBQVUsU0FBUztFQUN6QixLQUFLLE9BQU87Q0FDZDtBQUNGO0FBYUEsU0FBZ0IsOEJBQThCLE9BQWtEO0NBQzlGLE1BQU0sUUFBeUI7RUFDN0IsV0FBVztFQUNYLE9BQU87RUFDUCxTQUFTO0NBQ1g7Q0FDQSxJQUFJO0NBRUosSUFBSSxNQUFNLGVBQWUsUUFBVztFQUNsQyxhQUFhLE9BQU8sV0FBVyxNQUFNLFlBQVksTUFBTSxHQUFHLGNBQWMsS0FBSztFQUU3RSxJQUFJO0VBQ0osSUFBSTtHQUNGLFNBQVMsS0FBSyxNQUFNLE1BQU0sVUFBVTtFQUN0QyxRQUFRO0dBQ04sTUFBTSxJQUFJLDRCQUE0QixvQ0FBb0M7RUFDNUU7RUFFQSxJQUFJLENBQUMsU0FBUyxNQUFNLEtBQUssT0FBTyxTQUFTLFVBQ3ZDLE1BQU0sSUFBSSw0QkFBNEIsOENBQTRDO0VBR3BGLGNBQWMsUUFBUSxjQUFjLEtBQUs7RUFDekMsTUFBTSxXQUFXO0VBQ2pCLGVBQWU7Q0FDakI7Q0FFQSxLQUFLLE1BQU0sQ0FBQyxPQUFPLFVBQVUsTUFBTSxTQUFTLENBQUMsRUFBQSxDQUFHLFFBQVEsR0FBRztFQUN6RCx5QkFBeUIsTUFBTSxPQUFPLEtBQUs7RUFFM0MsTUFBTSxPQUFPLFNBQVMsTUFBTTtFQUM1QixjQUFjLEtBQUssYUFBYSxNQUFNLE9BQU8sSUFBSTtFQU1qRCxhQUFhLG9DQUpNLHFCQUFxQixLQUFLLGFBQWEsSUFJVCxDQUFVLEdBQUcsTUFBTSxLQUFLO0VBQ3pFLE1BQU0sV0FBVztDQUNuQjtDQUVBLE9BQU87QUFDVDtBQUVBLFNBQWdCLG1DQUNkLFFBQ0EsVUFDb0I7Q0FDcEIsSUFBSSxXQUFXLFFBQVcsT0FBTztDQUVqQyxNQUFNLGFBQWEscUJBQXFCLFFBQVEsaUJBQWlCO0NBR2pFLElBRG1CLE9BQU8sV0FBVyxZQUFZLE1BQzdDLElBQWEscUJBQXFCLGNBQ3BDLE1BQU0sSUFBSSw0QkFDUiwrQ0FBK0MscUJBQXFCLGNBQ3RFO0NBRUYsSUFBSSxhQUFhLGFBQ2YsOEJBQThCLFVBQVU7Q0FHMUMsT0FBTztBQUNUO0FBRUEsU0FBZ0IsOEJBQThCLFlBQTBCO0NBQ3RFLElBQUksT0FBTyxXQUFXLFlBQVksTUFBTSxJQUFBLE9BQ3RDLE1BQU0sSUFBSSw0QkFDUiw4REFBOEQsc0NBQ2hFO0FBRUo7QUFFQSxTQUFTLHFCQUFxQixPQUFnQixTQUF5QjtDQUNyRSxJQUFJO0NBQ0osSUFBSTtFQUNGLGFBQWEsS0FBSyxVQUFVLEtBQUs7Q0FDbkMsUUFBUTtFQUNOLE1BQU0sSUFBSSw0QkFBNEIsR0FBRyxRQUFRLDJCQUEyQjtDQUM5RTtDQUNBLElBQUksZUFBZSxRQUNqQixNQUFNLElBQUksNEJBQTRCLEdBQUcsUUFBUSwyQkFBMkI7Q0FFOUUsT0FBTztBQUNUO0FBRUEsU0FBUyxhQUFhLFlBQW9CLE1BQWMsT0FBOEI7Q0FDcEYsTUFBTSxhQUFhO0NBQ25CLElBQUksTUFBTSxZQUFZLHFCQUFxQixjQUN6QyxnQkFBZ0IsTUFBTSxjQUFjLHFCQUFxQixjQUFjLEtBQUs7QUFFaEY7QUFFQSxNQUFNLGdDQUFnQztBQUN0QyxNQUFNLGtDQUFrQztBQUN4QyxNQUFNLHVDQUF1QztBQUM3QyxNQUFNLG1DQUFtQztBQUV6QyxTQUFTLHlCQUNQLE1BQ0EsT0FDQSxPQUNNO0NBQ04sTUFBTSxXQUFXLFNBQVMsTUFBTTtDQUtoQyxhQUR5QixvQ0FBb0MsS0FBSyxJQUNyRCxJQUFtQixJQUFJLEdBQUcsR0FBRyxTQUFTLFFBQVEsS0FBSztDQUVoRSxJQUFJLEtBQUssZ0JBQWdCLFFBQ3ZCLGFBQ0Usb0NBQW9DLEtBQUssV0FBVyxHQUNwRCxHQUFHLFNBQVMsZUFDWixLQUNGO0NBVUYsYUFKRSxvQ0FBb0MsNkJBQTZCLElBQ2pFLG9DQUFvQywrQkFBK0IsSUFDbkUsb0NBQW9DLG9DQUFvQyxLQUN2RSxVQUFVLElBQUksSUFBSSxvQ0FBb0MsZ0NBQWdDLElBQUksSUFDbEUsVUFBVSxLQUFLO0FBQzVDOzs7Ozs7O0FBUUEsU0FBUyxvQ0FBb0MsT0FBdUI7Q0FDbEUsSUFBSSxRQUFRO0NBRVosS0FBSyxJQUFJLFFBQVEsR0FBRyxRQUFRLE1BQU0sUUFBUSxTQUFTLEdBQUc7RUFDcEQsTUFBTSxXQUFXLE1BQU0sV0FBVyxLQUFLO0VBRXZDLElBQUksYUFBYSxNQUFRLGFBQWEsSUFBTTtHQUMxQyxTQUFTO0dBQ1Q7RUFDRjtFQUNBLElBQUksWUFBWSxJQUFNO0dBQ3BCLFNBQVM7R0FDVDtFQUNGO0VBQ0EsSUFBSSxZQUFZLFNBQVUsWUFBWSxPQUFRO0dBQzVDLE1BQU0sZUFBZSxNQUFNLFdBQVcsUUFBUSxDQUFDO0dBQy9DLElBQUksZ0JBQWdCLFNBQVUsZ0JBQWdCLE9BQVE7SUFDcEQsU0FBUztJQUNULFNBQVM7R0FDWCxPQUVFLFNBQVM7R0FFWDtFQUNGO0VBQ0EsSUFBSSxZQUFZLFNBQVUsWUFBWSxPQUFRO0dBQzVDLFNBQVM7R0FDVDtFQUNGO0VBRUEsU0FBUyxZQUFZLE1BQU8sSUFBSSxZQUFZLE9BQVEsSUFBSTtDQUMxRDtDQUVBLE9BQU87QUFDVDtBQUVBLFNBQVMsY0FDUCxNQUNBLE1BQ0EsT0FDQSxvQkFBb0IsT0FDZDtDQUNOLE1BQU0sZUFBZSxFQUFFLE9BQU8sRUFBRTtDQUNoQyxJQUFJLHFCQUFxQixPQUFPLFNBQVMsVUFDdkMscUJBQXFCLE1BQU0sTUFBTSxPQUFPLFlBQVk7Q0FFdEQsUUFBUSxNQUFNLEtBQUs7Q0FDbkIsSUFBSSxTQUFTLFFBQVEsT0FBTyxTQUFTLFVBQVU7Q0FFL0MsTUFBTSxRQUE4RSxDQUNsRjtFQUFFLE9BQU87RUFBNkMsT0FBTztDQUFFLENBQ2pFO0NBRUEsT0FBTyxNQUFNLFNBQVMsR0FBRztFQUN2QixNQUFNLFVBQVUsTUFBTSxJQUFJO0VBQzFCLElBQUksTUFBTSxRQUFRLFFBQVEsS0FBSyxHQUFHO0dBQ2hDLEtBQUssSUFBSSxRQUFRLEdBQUcsUUFBUSxRQUFRLE1BQU0sUUFBUSxTQUFTLEdBQUc7SUFDNUQsTUFBTSxRQUFRLFFBQVEsUUFBUTtJQUM5Qix1QkFBdUIsT0FBTyxJQUFJO0lBQ2xDLFFBQVEsTUFBTSxLQUFLO0lBRW5CLE1BQU0sUUFBUSxRQUFRLE1BQU07SUFDNUIsSUFBSSxxQkFBcUIsT0FBTyxVQUFVLFVBQ3hDLHFCQUFxQixPQUFPLE1BQU0sT0FBTyxZQUFZO0lBRXZELElBQUksVUFBVSxRQUFRLE9BQU8sVUFBVSxVQUNyQyxNQUFNLEtBQUs7S0FBRSxPQUFPO0tBQThDO0lBQU0sQ0FBQztHQUU3RTtHQUNBO0VBQ0Y7RUFFQSxLQUFLLE1BQU0sT0FBTyxRQUFRLE9BQU87R0FDL0IsSUFBSSxDQUFDLE9BQU8sT0FBTyxRQUFRLE9BQU8sR0FBRyxHQUFHO0dBQ3hDLElBQUksbUJBQ0YscUJBQXFCLEtBQUssTUFBTSxPQUFPLFlBQVk7R0FFckQsTUFBTSxRQUFRLFFBQVEsUUFBUTtHQUM5Qix1QkFBdUIsT0FBTyxJQUFJO0dBQ2xDLFFBQVEsTUFBTSxLQUFLO0dBRW5CLE1BQU0sUUFBUSxRQUFRLE1BQU07R0FDNUIsSUFBSSxxQkFBcUIsT0FBTyxVQUFVLFVBQ3hDLHFCQUFxQixPQUFPLE1BQU0sT0FBTyxZQUFZO0dBRXZELElBQUksVUFBVSxRQUFRLE9BQU8sVUFBVSxVQUNyQyxNQUFNLEtBQUs7SUFBRSxPQUFPO0lBQThDO0dBQU0sQ0FBQztFQUU3RTtDQUNGO0FBQ0Y7QUFFQSxTQUFTLHFCQUNQLE9BQ0EsTUFDQSxPQUNBLGNBQ007Q0FDTixhQUFhLFNBQVMsT0FBTyxXQUFXLE9BQU8sTUFBTTtDQUNyRCxJQUFJLE1BQU0sWUFBWSxhQUFhLFFBQVEscUJBQXFCLGNBQzlELGdCQUFnQixNQUFNLGNBQWMscUJBQXFCLGNBQWMsS0FBSztBQUVoRjtBQUVBLFNBQVMsdUJBQXVCLE9BQWUsTUFBb0I7Q0FDakUsSUFBSSxRQUFRLHFCQUFxQixVQUMvQixNQUFNLElBQUksNEJBQ1IsR0FBRyxLQUFLLDBCQUEwQixxQkFBcUIsVUFDekQ7QUFFSjtBQUVBLFNBQVMsUUFBUSxNQUFjLE9BQThCO0NBQzNELE1BQU0sU0FBUztDQUNmLElBQUksTUFBTSxRQUFRLHFCQUFxQixVQUNyQyxnQkFBZ0IsTUFBTSxRQUFRLHFCQUFxQixVQUFVLEtBQUs7QUFFdEU7QUFFQSxTQUFTLGdCQUNQLE1BQ0EsTUFDQSxPQUNBLE9BQ087Q0FDUCxNQUFNLElBQUksNEJBQ1IsTUFBTSxZQUFZLElBQ2QsR0FBRyxLQUFLLFdBQVcsS0FBSyxZQUFZLFVBQ3BDLG1DQUFtQyxLQUFLLFlBQVksT0FDMUQ7QUFDRjtBQUVBLFNBQVMsU0FBUyxPQUFrRDtDQUNsRSxPQUFPLFVBQVUsUUFBUSxPQUFPLFVBQVUsWUFBWSxDQUFDLE1BQU0sUUFBUSxLQUFLO0FBQzVFIn0=