sonamu 0.7.16 → 0.7.17
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/ai/providers/rtzr/error.d.ts +1 -1
- package/dist/ai/providers/rtzr/error.d.ts.map +1 -1
- package/dist/api/config.d.ts +1 -0
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +1 -1
- package/dist/api/decorators.d.ts +1 -1
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +1 -1
- package/dist/api/sonamu.d.ts +3 -1
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +48 -38
- package/dist/syncer/checksum.d.ts +8 -3
- package/dist/syncer/checksum.d.ts.map +1 -1
- package/dist/syncer/checksum.js +17 -9
- package/dist/syncer/code-generator.js +7 -2
- package/dist/syncer/syncer.d.ts +6 -6
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +27 -13
- package/dist/template/implementations/model.template.js +5 -5
- package/dist/template/implementations/services.template.d.ts +17 -0
- package/dist/template/implementations/services.template.d.ts.map +1 -0
- package/dist/template/implementations/services.template.js +159 -0
- package/dist/template/implementations/view_form.template.js +2 -2
- package/dist/template/implementations/view_id_async_select.template.js +2 -2
- package/dist/template/implementations/view_list.template.js +5 -5
- package/dist/types/types.d.ts +2 -14
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +3 -15
- package/dist/ui/ai-api.d.ts +2 -0
- package/dist/ui/ai-api.d.ts.map +1 -1
- package/dist/ui/ai-api.js +43 -49
- package/dist/ui/ai-client.d.ts +10 -0
- package/dist/ui/ai-client.d.ts.map +1 -1
- package/dist/ui/ai-client.js +457 -437
- package/dist/ui/api.d.ts.map +1 -1
- package/dist/ui/api.js +3 -1
- package/dist/ui-web/assets/index-DzqUrTB-.js +92 -0
- package/dist/ui-web/index.html +1 -1
- package/package.json +11 -7
- package/src/api/config.ts +3 -0
- package/src/api/decorators.ts +6 -1
- package/src/api/sonamu.ts +68 -50
- package/src/shared/app.shared.ts.txt +1 -1
- package/src/shared/web.shared.ts.txt +0 -43
- package/src/syncer/checksum.ts +31 -9
- package/src/syncer/code-generator.ts +8 -1
- package/src/syncer/syncer.ts +38 -26
- package/src/template/implementations/model.template.ts +4 -4
- package/src/template/implementations/services.template.ts +226 -0
- package/src/template/implementations/view_form.template.ts +1 -1
- package/src/template/implementations/view_id_async_select.template.ts +1 -1
- package/src/template/implementations/view_list.template.ts +4 -4
- package/src/types/types.ts +2 -14
- package/src/ui/ai-api.ts +61 -60
- package/src/ui/ai-client.ts +535 -499
- package/src/ui/api.ts +3 -0
- package/src/ui/entity.instructions.md +536 -0
- package/dist/template/implementations/service.template.d.ts +0 -29
- package/dist/template/implementations/service.template.d.ts.map +0 -1
- package/dist/template/implementations/service.template.js +0 -202
- package/dist/ui-web/assets/index-BcbbB-BB.js +0 -95
- package/dist/ui-web/assets/provider-utils_false-BKJD46kk.js +0 -1
- package/dist/ui-web/assets/provider-utils_false-Bu5lmX18.js +0 -1
- package/src/template/implementations/service.template.ts +0 -328
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import assert from "assert";
|
|
2
|
-
import inflection from "inflection";
|
|
3
|
-
import { diff, group, sort, unique } from "radashi";
|
|
4
|
-
import { apiParamToTsCode, apiParamToTsCodeAsObject, apiParamTypeToTsType, unwrapPromiseOnce } from "../../api/code-converters.js";
|
|
5
|
-
import { Sonamu } from "../../api/sonamu.js";
|
|
6
|
-
import { Naite } from "../../naite/naite.js";
|
|
7
|
-
import { ApiParamType } from "../../types/types.js";
|
|
8
|
-
import { assertDefined } from "../../utils/utils.js";
|
|
9
|
-
import { Template } from "../template.js";
|
|
10
|
-
import { zodTypeToTsTypeDef } from "../zod-converter.js";
|
|
11
|
-
export class Template__service extends Template {
|
|
12
|
-
constructor(){
|
|
13
|
-
super("service");
|
|
14
|
-
}
|
|
15
|
-
getTargetAndPath(names) {
|
|
16
|
-
return {
|
|
17
|
-
target: ":target/src/services",
|
|
18
|
-
path: `${names.fs}/${names.fs}.service.ts`
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
render({ namesRecord }) {
|
|
22
|
-
Naite.t("render", {
|
|
23
|
-
namesRecord
|
|
24
|
-
});
|
|
25
|
-
const { syncer: { apis } } = Sonamu;
|
|
26
|
-
const apisForThisModel = apis.filter((api)=>api.modelName === `${namesRecord.capital}Model` || api.modelName === `${namesRecord.capital}Frame`);
|
|
27
|
-
// 서비스 TypeSource
|
|
28
|
-
const { lines, importKeys } = this.getTypeSource(apisForThisModel);
|
|
29
|
-
// AxiosProgressEvent 있는지 확인
|
|
30
|
-
const hasAxiosProgressEvent = apis.find((api)=>(api.options.clients ?? []).includes("axios-multipart"));
|
|
31
|
-
return {
|
|
32
|
-
...this.getTargetAndPath(namesRecord),
|
|
33
|
-
body: lines.join("\n"),
|
|
34
|
-
importKeys: importKeys.filter((key)=>[
|
|
35
|
-
"ListResult"
|
|
36
|
-
].includes(key) === false),
|
|
37
|
-
customHeaders: [
|
|
38
|
-
`import { z } from 'zod';`,
|
|
39
|
-
`import qs from "qs";`,
|
|
40
|
-
`import useSWR, { type SWRResponse } from "swr";`,
|
|
41
|
-
`import { fetch, ListResult, SWRError, SwrOptions, handleConditional, swrPostFetcher, EventHandlers, SSEStreamOptions, useSSEStream } from '../sonamu.shared';`,
|
|
42
|
-
...hasAxiosProgressEvent ? [
|
|
43
|
-
`import { type AxiosProgressEvent } from 'axios';`
|
|
44
|
-
] : []
|
|
45
|
-
]
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
getTypeSource(apis) {
|
|
49
|
-
const importKeys = [];
|
|
50
|
-
// 제네릭에서 선언한 타입, importKeys에서 제외 필요
|
|
51
|
-
let typeParamNames = [];
|
|
52
|
-
const groups = group(apis, (api)=>api.modelName);
|
|
53
|
-
const body = Object.keys(groups).map((modelName)=>{
|
|
54
|
-
const methods = groups[modelName];
|
|
55
|
-
assert(methods);
|
|
56
|
-
const methodCodes = methods.map((api)=>{
|
|
57
|
-
// 컨텍스트 제외된 파라미터 리스트
|
|
58
|
-
const paramsWithoutContext = api.parameters.filter((param)=>!ApiParamType.isContext(param.type) && !ApiParamType.isRefKnex(param.type) && !(param.optional === true && param.name.startsWith("_")));
|
|
59
|
-
// 파라미터 타입 정의
|
|
60
|
-
const typeParametersAsTsType = api.typeParameters.map((typeParam)=>{
|
|
61
|
-
return apiParamTypeToTsType(typeParam, importKeys);
|
|
62
|
-
}).join(", ");
|
|
63
|
-
const typeParamsDef = typeParametersAsTsType ? `<${typeParametersAsTsType}>` : "";
|
|
64
|
-
typeParamNames = typeParamNames.concat(api.typeParameters.map((typeParam)=>typeParam.id));
|
|
65
|
-
// 파라미터 정의
|
|
66
|
-
const paramsDef = apiParamToTsCode(paramsWithoutContext, importKeys);
|
|
67
|
-
// 파라미터 정의 (객체 형태)
|
|
68
|
-
const paramsDefAsObject = apiParamToTsCodeAsObject(paramsWithoutContext, importKeys);
|
|
69
|
-
// 리턴 타입 정의
|
|
70
|
-
const returnTypeDef = apiParamTypeToTsType(assertDefined(unwrapPromiseOnce(api.returnType)), importKeys);
|
|
71
|
-
// 페이로드 데이터 정의
|
|
72
|
-
const payloadDef = `{ ${paramsWithoutContext.map((param)=>param.name).join(", ")} }`;
|
|
73
|
-
// 기본 URL
|
|
74
|
-
const apiBaseUrl = `${Sonamu.config.api.route.prefix}${api.path}`;
|
|
75
|
-
const clients = api.options.clients ?? [];
|
|
76
|
-
return [
|
|
77
|
-
// 클라이언트별로 생성
|
|
78
|
-
...sort(clients, (client)=>client === "swr" ? 0 : 1).map((client)=>{
|
|
79
|
-
switch(client){
|
|
80
|
-
case "axios":
|
|
81
|
-
return this.renderAxios(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, payloadDef);
|
|
82
|
-
case "axios-multipart":
|
|
83
|
-
return this.renderAxiosMultipart(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, paramsWithoutContext);
|
|
84
|
-
case "swr":
|
|
85
|
-
return this.renderSwr(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, payloadDef);
|
|
86
|
-
case "window-fetch":
|
|
87
|
-
return this.renderWindowFetch(api, apiBaseUrl, typeParamsDef, paramsDef, payloadDef);
|
|
88
|
-
default:
|
|
89
|
-
return `// Not supported ${inflection.camelize(client, true)} yet.`;
|
|
90
|
-
}
|
|
91
|
-
}),
|
|
92
|
-
// 스트리밍인 경우
|
|
93
|
-
...api.streamOptions ? [
|
|
94
|
-
this.renderStream(api, apiBaseUrl, paramsDefAsObject)
|
|
95
|
-
] : []
|
|
96
|
-
].join("\n");
|
|
97
|
-
}).join("\n\n");
|
|
98
|
-
return `export namespace ${modelName.replace(/Model$/, "Service").replace(/Frame$/, "Service")} {
|
|
99
|
-
${methodCodes}
|
|
100
|
-
}`;
|
|
101
|
-
}).join("\n\n");
|
|
102
|
-
return {
|
|
103
|
-
lines: [
|
|
104
|
-
body
|
|
105
|
-
],
|
|
106
|
-
importKeys: diff(unique(importKeys), typeParamNames)
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
renderAxios(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, payloadDef) {
|
|
110
|
-
const methodNameAxios = api.options.resourceName ? `get${inflection.camelize(api.options.resourceName)}` : api.methodName;
|
|
111
|
-
if (api.options.httpMethod === "GET") {
|
|
112
|
-
return `
|
|
113
|
-
export async function ${methodNameAxios}${typeParamsDef}(${paramsDef}): Promise<${returnTypeDef}> {
|
|
114
|
-
return fetch({
|
|
115
|
-
method: "GET",
|
|
116
|
-
url: \`${apiBaseUrl}?\${qs.stringify(${payloadDef})}\`,
|
|
117
|
-
${api.options.timeout ? `signal: AbortSignal.timeout(${api.options.timeout}),` : ""}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
`.trim();
|
|
121
|
-
} else {
|
|
122
|
-
return `
|
|
123
|
-
export async function ${methodNameAxios}${typeParamsDef}(${paramsDef}): Promise<${returnTypeDef}> {
|
|
124
|
-
return fetch({
|
|
125
|
-
method: '${api.options.httpMethod}',
|
|
126
|
-
url: \`${apiBaseUrl}\`,
|
|
127
|
-
data: ${payloadDef},
|
|
128
|
-
${api.options.timeout ? `signal: AbortSignal.timeout(${api.options.timeout}),` : ""}
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
`.trim();
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
renderAxiosMultipart(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, paramsWithoutContext) {
|
|
135
|
-
const isMultiple = api.uploadOptions?.mode === "multiple";
|
|
136
|
-
const fileParamName = isMultiple ? "files" : "file";
|
|
137
|
-
const fileParamType = isMultiple ? "File[]" : "File";
|
|
138
|
-
const formDataDef = isMultiple ? [
|
|
139
|
-
`${fileParamName}.forEach(f => { formData.append("${fileParamName}", f) } ); `,
|
|
140
|
-
...paramsWithoutContext.map((param)=>`formData.append('${param.name}', String(${param.name}));`)
|
|
141
|
-
].join("\n") : [
|
|
142
|
-
`formData.append("${fileParamName}", ${fileParamName});`,
|
|
143
|
-
...paramsWithoutContext.map((param)=>`formData.append('${param.name}', String(${param.name}));`)
|
|
144
|
-
].join("\n");
|
|
145
|
-
const paramsDefComma = paramsDef !== "" ? ", " : "";
|
|
146
|
-
return `
|
|
147
|
-
export async function ${api.methodName}${typeParamsDef}(
|
|
148
|
-
${paramsDef}${paramsDefComma}
|
|
149
|
-
${fileParamName}: ${fileParamType},
|
|
150
|
-
onUploadProgress?: (pe:AxiosProgressEvent) => void
|
|
151
|
-
): Promise<${returnTypeDef}> {
|
|
152
|
-
const formData = new FormData();
|
|
153
|
-
${formDataDef}
|
|
154
|
-
return fetch({
|
|
155
|
-
method: 'POST',
|
|
156
|
-
url: \`${apiBaseUrl}\`,
|
|
157
|
-
headers: {
|
|
158
|
-
"Content-Type": "multipart/form-data",
|
|
159
|
-
},
|
|
160
|
-
onUploadProgress,
|
|
161
|
-
data: formData,
|
|
162
|
-
${api.options.timeout ? `signal: AbortSignal.timeout(${api.options.timeout}),` : ""}
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
`.trim();
|
|
166
|
-
}
|
|
167
|
-
renderSwr(api, apiBaseUrl, typeParamsDef, paramsDef, returnTypeDef, payloadDef) {
|
|
168
|
-
const methodNameSwr = api.options.resourceName ? `use${inflection.camelize(api.options.resourceName)}` : `use${inflection.camelize(api.methodName)}`;
|
|
169
|
-
return ` export function ${inflection.camelize(methodNameSwr, true)}${typeParamsDef}(${[
|
|
170
|
-
paramsDef,
|
|
171
|
-
"swrOptions?: SwrOptions"
|
|
172
|
-
].filter((p)=>p !== "").join(",")}, ): SWRResponse<${returnTypeDef}, SWRError> {
|
|
173
|
-
return useSWR(handleConditional([
|
|
174
|
-
\`${apiBaseUrl}\`,
|
|
175
|
-
${payloadDef},
|
|
176
|
-
], swrOptions?.conditional)${api.options.httpMethod === "POST" ? ", swrPostFetcher" : ""}${api.options.timeout ? `, { loadingTimeout: ${api.options.timeout} }` : ""});
|
|
177
|
-
}`;
|
|
178
|
-
}
|
|
179
|
-
renderWindowFetch(api, apiBaseUrl, typeParamsDef, paramsDef, payloadDef) {
|
|
180
|
-
return `
|
|
181
|
-
export async function ${api.methodName}${typeParamsDef}(${paramsDef}): Promise<Response> {
|
|
182
|
-
return window.fetch(\`${apiBaseUrl}?\${qs.stringify(${payloadDef})}\`${api.options.timeout ? `, { signal: AbortSignal.timeout(${api.options.timeout}) }` : ""});
|
|
183
|
-
}
|
|
184
|
-
`.trim();
|
|
185
|
-
}
|
|
186
|
-
renderStream(api, apiBaseUrl, paramsDefAsObject) {
|
|
187
|
-
if (!api.streamOptions) {
|
|
188
|
-
return "// streamOptions not found";
|
|
189
|
-
}
|
|
190
|
-
const methodNameStream = api.options.resourceName ? `use${inflection.camelize(api.options.resourceName)}` : `use${inflection.camelize(api.methodName)}`;
|
|
191
|
-
const methodNameStreamCamelized = inflection.camelize(methodNameStream, true);
|
|
192
|
-
const eventsTypeDef = zodTypeToTsTypeDef(api.streamOptions.events);
|
|
193
|
-
return ` export function ${methodNameStreamCamelized}(
|
|
194
|
-
params: ${paramsDefAsObject},
|
|
195
|
-
handlers: EventHandlers<${eventsTypeDef} & { end?: () => void }>,
|
|
196
|
-
options: SSEStreamOptions) {
|
|
197
|
-
return useSSEStream<${eventsTypeDef}>(\`${apiBaseUrl}\`, params, handlers, options);
|
|
198
|
-
}`;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy90ZW1wbGF0ZS9pbXBsZW1lbnRhdGlvbnMvc2VydmljZS50ZW1wbGF0ZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBpbmZsZWN0aW9uIGZyb20gXCJpbmZsZWN0aW9uXCI7XG5pbXBvcnQgeyBkaWZmLCBncm91cCwgc29ydCwgdW5pcXVlIH0gZnJvbSBcInJhZGFzaGlcIjtcbmltcG9ydCB7XG4gIGFwaVBhcmFtVG9Uc0NvZGUsXG4gIGFwaVBhcmFtVG9Uc0NvZGVBc09iamVjdCxcbiAgYXBpUGFyYW1UeXBlVG9Uc1R5cGUsXG4gIHVud3JhcFByb21pc2VPbmNlLFxufSBmcm9tIFwiLi4vLi4vYXBpL2NvZGUtY29udmVydGVyc1wiO1xuaW1wb3J0IHR5cGUgeyBFeHRlbmRlZEFwaSB9IGZyb20gXCIuLi8uLi9hcGkvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgU29uYW11IH0gZnJvbSBcIi4uLy4uL2FwaS9zb25hbXVcIjtcbmltcG9ydCB0eXBlIHsgRW50aXR5TmFtZXNSZWNvcmQgfSBmcm9tIFwiLi4vLi4vZW50aXR5L2VudGl0eS1tYW5hZ2VyXCI7XG5pbXBvcnQgeyBOYWl0ZSB9IGZyb20gXCIuLi8uLi9uYWl0ZS9uYWl0ZVwiO1xuaW1wb3J0IHR5cGUgeyBUZW1wbGF0ZU9wdGlvbnMgfSBmcm9tIFwiLi4vLi4vdHlwZXMvdHlwZXNcIjtcbmltcG9ydCB7IHR5cGUgQXBpUGFyYW0sIEFwaVBhcmFtVHlwZSB9IGZyb20gXCIuLi8uLi90eXBlcy90eXBlc1wiO1xuaW1wb3J0IHsgYXNzZXJ0RGVmaW5lZCB9IGZyb20gXCIuLi8uLi91dGlscy91dGlsc1wiO1xuaW1wb3J0IHsgVGVtcGxhdGUgfSBmcm9tIFwiLi4vdGVtcGxhdGVcIjtcbmltcG9ydCB7IHpvZFR5cGVUb1RzVHlwZURlZiB9IGZyb20gXCIuLi96b2QtY29udmVydGVyXCI7XG5cbmV4cG9ydCBjbGFzcyBUZW1wbGF0ZV9fc2VydmljZSBleHRlbmRzIFRlbXBsYXRlIHtcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgc3VwZXIoXCJzZXJ2aWNlXCIpO1xuICB9XG5cbiAgZ2V0VGFyZ2V0QW5kUGF0aChuYW1lczogRW50aXR5TmFtZXNSZWNvcmQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgdGFyZ2V0OiBcIjp0YXJnZXQvc3JjL3NlcnZpY2VzXCIsXG4gICAgICBwYXRoOiBgJHtuYW1lcy5mc30vJHtuYW1lcy5mc30uc2VydmljZS50c2AsXG4gICAgfTtcbiAgfVxuXG4gIHJlbmRlcih7IG5hbWVzUmVjb3JkIH06IFRlbXBsYXRlT3B0aW9uc1tcInNlcnZpY2VcIl0pIHtcbiAgICBOYWl0ZS50KFwicmVuZGVyXCIsIHsgbmFtZXNSZWNvcmQgfSk7XG5cbiAgICBjb25zdCB7XG4gICAgICBzeW5jZXI6IHsgYXBpcyB9LFxuICAgIH0gPSBTb25hbXU7XG5cbiAgICBjb25zdCBhcGlzRm9yVGhpc01vZGVsID0gYXBpcy5maWx0ZXIoXG4gICAgICAoYXBpKSA9PlxuICAgICAgICBhcGkubW9kZWxOYW1lID09PSBgJHtuYW1lc1JlY29yZC5jYXBpdGFsfU1vZGVsYCB8fFxuICAgICAgICBhcGkubW9kZWxOYW1lID09PSBgJHtuYW1lc1JlY29yZC5jYXBpdGFsfUZyYW1lYCxcbiAgICApO1xuXG4gICAgLy8g7ISc67mE7IqkIFR5cGVTb3VyY2VcbiAgICBjb25zdCB7IGxpbmVzLCBpbXBvcnRLZXlzIH0gPSB0aGlzLmdldFR5cGVTb3VyY2UoYXBpc0ZvclRoaXNNb2RlbCk7XG5cbiAgICAvLyBBeGlvc1Byb2dyZXNzRXZlbnQg7J6I64qU7KeAIO2ZleyduFxuICAgIGNvbnN0IGhhc0F4aW9zUHJvZ3Jlc3NFdmVudCA9IGFwaXMuZmluZCgoYXBpKSA9PlxuICAgICAgKGFwaS5vcHRpb25zLmNsaWVudHMgPz8gW10pLmluY2x1ZGVzKFwiYXhpb3MtbXVsdGlwYXJ0XCIpLFxuICAgICk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4udGhpcy5nZXRUYXJnZXRBbmRQYXRoKG5hbWVzUmVjb3JkKSxcbiAgICAgIGJvZHk6IGxpbmVzLmpvaW4oXCJcXG5cIiksXG4gICAgICBpbXBvcnRLZXlzOiBpbXBvcnRLZXlzLmZpbHRlcigoa2V5KSA9PiBbXCJMaXN0UmVzdWx0XCJdLmluY2x1ZGVzKGtleSkgPT09IGZhbHNlKSxcbiAgICAgIGN1c3RvbUhlYWRlcnM6IFtcbiAgICAgICAgYGltcG9ydCB7IHogfSBmcm9tICd6b2QnO2AsXG4gICAgICAgIGBpbXBvcnQgcXMgZnJvbSBcInFzXCI7YCxcbiAgICAgICAgYGltcG9ydCB1c2VTV1IsIHsgdHlwZSBTV1JSZXNwb25zZSB9IGZyb20gXCJzd3JcIjtgLFxuICAgICAgICBgaW1wb3J0IHsgZmV0Y2gsIExpc3RSZXN1bHQsIFNXUkVycm9yLCBTd3JPcHRpb25zLCBoYW5kbGVDb25kaXRpb25hbCwgc3dyUG9zdEZldGNoZXIsIEV2ZW50SGFuZGxlcnMsIFNTRVN0cmVhbU9wdGlvbnMsIHVzZVNTRVN0cmVhbSB9IGZyb20gJy4uL3NvbmFtdS5zaGFyZWQnO2AsXG4gICAgICAgIC4uLihoYXNBeGlvc1Byb2dyZXNzRXZlbnQgPyBbYGltcG9ydCB7IHR5cGUgQXhpb3NQcm9ncmVzc0V2ZW50IH0gZnJvbSAnYXhpb3MnO2BdIDogW10pLFxuICAgICAgXSxcbiAgICB9O1xuICB9XG5cbiAgZ2V0VHlwZVNvdXJjZShhcGlzOiBFeHRlbmRlZEFwaVtdKToge1xuICAgIGxpbmVzOiBzdHJpbmdbXTtcbiAgICBpbXBvcnRLZXlzOiBzdHJpbmdbXTtcbiAgfSB7XG4gICAgY29uc3QgaW1wb3J0S2V5czogc3RyaW5nW10gPSBbXTtcblxuICAgIC8vIOygnOuEpOumreyXkOyEnCDshKDslrjtlZwg7YOA7J6FLCBpbXBvcnRLZXlz7JeQ7IScIOygnOyZuCDtlYTsmpRcbiAgICBsZXQgdHlwZVBhcmFtTmFtZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICBjb25zdCBncm91cHMgPSBncm91cChhcGlzLCAoYXBpKSA9PiBhcGkubW9kZWxOYW1lKTtcbiAgICBjb25zdCBib2R5ID0gT2JqZWN0LmtleXMoZ3JvdXBzKVxuICAgICAgLm1hcCgobW9kZWxOYW1lKSA9PiB7XG4gICAgICAgIGNvbnN0IG1ldGhvZHMgPSBncm91cHNbbW9kZWxOYW1lXTtcbiAgICAgICAgYXNzZXJ0KG1ldGhvZHMpO1xuICAgICAgICBjb25zdCBtZXRob2RDb2RlcyA9IG1ldGhvZHNcbiAgICAgICAgICAubWFwKChhcGkpID0+IHtcbiAgICAgICAgICAgIC8vIOy7qO2FjeyKpO2KuCDsoJzsmbjrkJwg7YyM652866+47YSwIOumrOyKpO2KuFxuICAgICAgICAgICAgY29uc3QgcGFyYW1zV2l0aG91dENvbnRleHQgPSBhcGkucGFyYW1ldGVycy5maWx0ZXIoXG4gICAgICAgICAgICAgIChwYXJhbSkgPT5cbiAgICAgICAgICAgICAgICAhQXBpUGFyYW1UeXBlLmlzQ29udGV4dChwYXJhbS50eXBlKSAmJlxuICAgICAgICAgICAgICAgICFBcGlQYXJhbVR5cGUuaXNSZWZLbmV4KHBhcmFtLnR5cGUpICYmXG4gICAgICAgICAgICAgICAgIShwYXJhbS5vcHRpb25hbCA9PT0gdHJ1ZSAmJiBwYXJhbS5uYW1lLnN0YXJ0c1dpdGgoXCJfXCIpKSwgLy8gX+uhnCDsi5zsnpHtlZjripQg7YyM652866+47YSw64qUIOygnOyZuFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgLy8g7YyM652866+47YSwIO2DgOyehSDsoJXsnZhcbiAgICAgICAgICAgIGNvbnN0IHR5cGVQYXJhbWV0ZXJzQXNUc1R5cGUgPSBhcGkudHlwZVBhcmFtZXRlcnNcbiAgICAgICAgICAgICAgLm1hcCgodHlwZVBhcmFtKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFwaVBhcmFtVHlwZVRvVHNUeXBlKHR5cGVQYXJhbSwgaW1wb3J0S2V5cyk7XG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIC5qb2luKFwiLCBcIik7XG4gICAgICAgICAgICBjb25zdCB0eXBlUGFyYW1zRGVmID0gdHlwZVBhcmFtZXRlcnNBc1RzVHlwZSA/IGA8JHt0eXBlUGFyYW1ldGVyc0FzVHNUeXBlfT5gIDogXCJcIjtcbiAgICAgICAgICAgIHR5cGVQYXJhbU5hbWVzID0gdHlwZVBhcmFtTmFtZXMuY29uY2F0KFxuICAgICAgICAgICAgICBhcGkudHlwZVBhcmFtZXRlcnMubWFwKCh0eXBlUGFyYW0pID0+IHR5cGVQYXJhbS5pZCksXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAvLyDtjIzrnbzrr7jthLAg7KCV7J2YXG4gICAgICAgICAgICBjb25zdCBwYXJhbXNEZWYgPSBhcGlQYXJhbVRvVHNDb2RlKHBhcmFtc1dpdGhvdXRDb250ZXh0LCBpbXBvcnRLZXlzKTtcblxuICAgICAgICAgICAgLy8g7YyM652866+47YSwIOygleydmCAo6rCd7LK0IO2Yle2DnClcbiAgICAgICAgICAgIGNvbnN0IHBhcmFtc0RlZkFzT2JqZWN0ID0gYXBpUGFyYW1Ub1RzQ29kZUFzT2JqZWN0KHBhcmFtc1dpdGhvdXRDb250ZXh0LCBpbXBvcnRLZXlzKTtcblxuICAgICAgICAgICAgLy8g66as7YS0IO2DgOyehSDsoJXsnZhcbiAgICAgICAgICAgIGNvbnN0IHJldHVyblR5cGVEZWYgPSBhcGlQYXJhbVR5cGVUb1RzVHlwZShcbiAgICAgICAgICAgICAgYXNzZXJ0RGVmaW5lZCh1bndyYXBQcm9taXNlT25jZShhcGkucmV0dXJuVHlwZSkpLFxuICAgICAgICAgICAgICBpbXBvcnRLZXlzLFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgLy8g7Y6Y7J2066Gc65OcIOuNsOydtO2EsCDsoJXsnZhcbiAgICAgICAgICAgIGNvbnN0IHBheWxvYWREZWYgPSBgeyAke3BhcmFtc1dpdGhvdXRDb250ZXh0Lm1hcCgocGFyYW0pID0+IHBhcmFtLm5hbWUpLmpvaW4oXCIsIFwiKX0gfWA7XG5cbiAgICAgICAgICAgIC8vIOq4sOuzuCBVUkxcbiAgICAgICAgICAgIGNvbnN0IGFwaUJhc2VVcmwgPSBgJHtTb25hbXUuY29uZmlnLmFwaS5yb3V0ZS5wcmVmaXh9JHthcGkucGF0aH1gO1xuXG4gICAgICAgICAgICBjb25zdCBjbGllbnRzID0gYXBpLm9wdGlvbnMuY2xpZW50cyA/PyBbXTtcbiAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgIC8vIO2BtOudvOydtOyWuO2KuOuzhOuhnCDsg53shLFcbiAgICAgICAgICAgICAgLi4uc29ydChjbGllbnRzLCAoY2xpZW50KSA9PiAoY2xpZW50ID09PSBcInN3clwiID8gMCA6IDEpKS5tYXAoKGNsaWVudCkgPT4ge1xuICAgICAgICAgICAgICAgIHN3aXRjaCAoY2xpZW50KSB7XG4gICAgICAgICAgICAgICAgICBjYXNlIFwiYXhpb3NcIjpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVuZGVyQXhpb3MoXG4gICAgICAgICAgICAgICAgICAgICAgYXBpLFxuICAgICAgICAgICAgICAgICAgICAgIGFwaUJhc2VVcmwsXG4gICAgICAgICAgICAgICAgICAgICAgdHlwZVBhcmFtc0RlZixcbiAgICAgICAgICAgICAgICAgICAgICBwYXJhbXNEZWYsXG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuVHlwZURlZixcbiAgICAgICAgICAgICAgICAgICAgICBwYXlsb2FkRGVmLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgY2FzZSBcImF4aW9zLW11bHRpcGFydFwiOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5yZW5kZXJBeGlvc011bHRpcGFydChcbiAgICAgICAgICAgICAgICAgICAgICBhcGksXG4gICAgICAgICAgICAgICAgICAgICAgYXBpQmFzZVVybCxcbiAgICAgICAgICAgICAgICAgICAgICB0eXBlUGFyYW1zRGVmLFxuICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc0RlZixcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm5UeXBlRGVmLFxuICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc1dpdGhvdXRDb250ZXh0LFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgY2FzZSBcInN3clwiOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5yZW5kZXJTd3IoXG4gICAgICAgICAgICAgICAgICAgICAgYXBpLFxuICAgICAgICAgICAgICAgICAgICAgIGFwaUJhc2VVcmwsXG4gICAgICAgICAgICAgICAgICAgICAgdHlwZVBhcmFtc0RlZixcbiAgICAgICAgICAgICAgICAgICAgICBwYXJhbXNEZWYsXG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuVHlwZURlZixcbiAgICAgICAgICAgICAgICAgICAgICBwYXlsb2FkRGVmLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgY2FzZSBcIndpbmRvdy1mZXRjaFwiOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5yZW5kZXJXaW5kb3dGZXRjaChcbiAgICAgICAgICAgICAgICAgICAgICBhcGksXG4gICAgICAgICAgICAgICAgICAgICAgYXBpQmFzZVVybCxcbiAgICAgICAgICAgICAgICAgICAgICB0eXBlUGFyYW1zRGVmLFxuICAgICAgICAgICAgICAgICAgICAgIHBhcmFtc0RlZixcbiAgICAgICAgICAgICAgICAgICAgICBwYXlsb2FkRGVmLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGAvLyBOb3Qgc3VwcG9ydGVkICR7aW5mbGVjdGlvbi5jYW1lbGl6ZShjbGllbnQsIHRydWUpfSB5ZXQuYDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAvLyDsiqTtirjrpqzrsI3snbgg6rK97JqwXG4gICAgICAgICAgICAgIC4uLihhcGkuc3RyZWFtT3B0aW9ucyA/IFt0aGlzLnJlbmRlclN0cmVhbShhcGksIGFwaUJhc2VVcmwsIHBhcmFtc0RlZkFzT2JqZWN0KV0gOiBbXSksXG4gICAgICAgICAgICBdLmpvaW4oXCJcXG5cIik7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuam9pbihcIlxcblxcblwiKTtcblxuICAgICAgICByZXR1cm4gYGV4cG9ydCBuYW1lc3BhY2UgJHttb2RlbE5hbWUucmVwbGFjZSgvTW9kZWwkLywgXCJTZXJ2aWNlXCIpLnJlcGxhY2UoL0ZyYW1lJC8sIFwiU2VydmljZVwiKX0ge1xuJHttZXRob2RDb2Rlc31cbn1gO1xuICAgICAgfSlcbiAgICAgIC5qb2luKFwiXFxuXFxuXCIpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGxpbmVzOiBbYm9keV0sXG4gICAgICBpbXBvcnRLZXlzOiBkaWZmKHVuaXF1ZShpbXBvcnRLZXlzKSwgdHlwZVBhcmFtTmFtZXMpLFxuICAgIH07XG4gIH1cblxuICByZW5kZXJBeGlvcyhcbiAgICBhcGk6IEV4dGVuZGVkQXBpLFxuICAgIGFwaUJhc2VVcmw6IHN0cmluZyxcbiAgICB0eXBlUGFyYW1zRGVmOiBzdHJpbmcsXG4gICAgcGFyYW1zRGVmOiBzdHJpbmcsXG4gICAgcmV0dXJuVHlwZURlZjogc3RyaW5nLFxuICAgIHBheWxvYWREZWY6IHN0cmluZyxcbiAgKSB7XG4gICAgY29uc3QgbWV0aG9kTmFtZUF4aW9zID0gYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lXG4gICAgICA/IGBnZXQke2luZmxlY3Rpb24uY2FtZWxpemUoYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lKX1gXG4gICAgICA6IGFwaS5tZXRob2ROYW1lO1xuXG4gICAgaWYgKGFwaS5vcHRpb25zLmh0dHBNZXRob2QgPT09IFwiR0VUXCIpIHtcbiAgICAgIHJldHVybiBgXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gJHttZXRob2ROYW1lQXhpb3N9JHt0eXBlUGFyYW1zRGVmfSgke3BhcmFtc0RlZn0pOiBQcm9taXNlPCR7cmV0dXJuVHlwZURlZn0+IHtcbiAgICByZXR1cm4gZmV0Y2goe1xuICAgICAgbWV0aG9kOiBcIkdFVFwiLFxuICAgICAgdXJsOiBcXGAke2FwaUJhc2VVcmx9P1xcJHtxcy5zdHJpbmdpZnkoJHtwYXlsb2FkRGVmfSl9XFxgLFxuICAgICAgJHthcGkub3B0aW9ucy50aW1lb3V0ID8gYHNpZ25hbDogQWJvcnRTaWduYWwudGltZW91dCgke2FwaS5vcHRpb25zLnRpbWVvdXR9KSxgIDogXCJcIn1cbiAgICB9KTtcbn1cbiAgICBgLnRyaW0oKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGBcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiAke21ldGhvZE5hbWVBeGlvc30ke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSk6IFByb21pc2U8JHtyZXR1cm5UeXBlRGVmfT4ge1xuICAgIHJldHVybiBmZXRjaCh7XG4gICAgICBtZXRob2Q6ICcke2FwaS5vcHRpb25zLmh0dHBNZXRob2R9JyxcbiAgICAgIHVybDogXFxgJHthcGlCYXNlVXJsfVxcYCxcbiAgICAgIGRhdGE6ICR7cGF5bG9hZERlZn0sXG4gICAgICAke2FwaS5vcHRpb25zLnRpbWVvdXQgPyBgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KCR7YXBpLm9wdGlvbnMudGltZW91dH0pLGAgOiBcIlwifVxuICAgIH0pO1xufVxuICAgICAgYC50cmltKCk7XG4gICAgfVxuICB9XG5cbiAgcmVuZGVyQXhpb3NNdWx0aXBhcnQoXG4gICAgYXBpOiBFeHRlbmRlZEFwaSxcbiAgICBhcGlCYXNlVXJsOiBzdHJpbmcsXG4gICAgdHlwZVBhcmFtc0RlZjogc3RyaW5nLFxuICAgIHBhcmFtc0RlZjogc3RyaW5nLFxuICAgIHJldHVyblR5cGVEZWY6IHN0cmluZyxcbiAgICBwYXJhbXNXaXRob3V0Q29udGV4dDogQXBpUGFyYW1bXSxcbiAgKSB7XG4gICAgY29uc3QgaXNNdWx0aXBsZSA9IGFwaS51cGxvYWRPcHRpb25zPy5tb2RlID09PSBcIm11bHRpcGxlXCI7XG4gICAgY29uc3QgZmlsZVBhcmFtTmFtZSA9IGlzTXVsdGlwbGUgPyBcImZpbGVzXCIgOiBcImZpbGVcIjtcbiAgICBjb25zdCBmaWxlUGFyYW1UeXBlID0gaXNNdWx0aXBsZSA/IFwiRmlsZVtdXCIgOiBcIkZpbGVcIjtcblxuICAgIGNvbnN0IGZvcm1EYXRhRGVmID0gaXNNdWx0aXBsZVxuICAgICAgPyBbXG4gICAgICAgICAgYCR7ZmlsZVBhcmFtTmFtZX0uZm9yRWFjaChmID0+IHsgZm9ybURhdGEuYXBwZW5kKFwiJHtmaWxlUGFyYW1OYW1lfVwiLCBmKSB9ICk7IGAsXG4gICAgICAgICAgLi4ucGFyYW1zV2l0aG91dENvbnRleHQubWFwKFxuICAgICAgICAgICAgKHBhcmFtKSA9PiBgZm9ybURhdGEuYXBwZW5kKCcke3BhcmFtLm5hbWV9JywgU3RyaW5nKCR7cGFyYW0ubmFtZX0pKTtgLFxuICAgICAgICAgICksXG4gICAgICAgIF0uam9pbihcIlxcblwiKVxuICAgICAgOiBbXG4gICAgICAgICAgYGZvcm1EYXRhLmFwcGVuZChcIiR7ZmlsZVBhcmFtTmFtZX1cIiwgJHtmaWxlUGFyYW1OYW1lfSk7YCxcbiAgICAgICAgICAuLi5wYXJhbXNXaXRob3V0Q29udGV4dC5tYXAoXG4gICAgICAgICAgICAocGFyYW0pID0+IGBmb3JtRGF0YS5hcHBlbmQoJyR7cGFyYW0ubmFtZX0nLCBTdHJpbmcoJHtwYXJhbS5uYW1lfSkpO2AsXG4gICAgICAgICAgKSxcbiAgICAgICAgXS5qb2luKFwiXFxuXCIpO1xuXG4gICAgY29uc3QgcGFyYW1zRGVmQ29tbWEgPSBwYXJhbXNEZWYgIT09IFwiXCIgPyBcIiwgXCIgOiBcIlwiO1xuICAgIHJldHVybiBgXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gJHthcGkubWV0aG9kTmFtZX0ke3R5cGVQYXJhbXNEZWZ9KFxuICAke3BhcmFtc0RlZn0ke3BhcmFtc0RlZkNvbW1hfVxuICAke2ZpbGVQYXJhbU5hbWV9OiAke2ZpbGVQYXJhbVR5cGV9LFxuICBvblVwbG9hZFByb2dyZXNzPzogKHBlOkF4aW9zUHJvZ3Jlc3NFdmVudCkgPT4gdm9pZFxuICApOiBQcm9taXNlPCR7cmV0dXJuVHlwZURlZn0+IHtcbiAgICBjb25zdCBmb3JtRGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICR7Zm9ybURhdGFEZWZ9XG4gICAgcmV0dXJuIGZldGNoKHtcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgdXJsOiBcXGAke2FwaUJhc2VVcmx9XFxgLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcIm11bHRpcGFydC9mb3JtLWRhdGFcIixcbiAgICAgIH0sXG4gICAgICBvblVwbG9hZFByb2dyZXNzLFxuICAgICAgZGF0YTogZm9ybURhdGEsXG4gICAgICAke2FwaS5vcHRpb25zLnRpbWVvdXQgPyBgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KCR7YXBpLm9wdGlvbnMudGltZW91dH0pLGAgOiBcIlwifVxuICAgIH0pO1xuICB9XG4gIGAudHJpbSgpO1xuICB9XG5cbiAgcmVuZGVyU3dyKFxuICAgIGFwaTogRXh0ZW5kZWRBcGksXG4gICAgYXBpQmFzZVVybDogc3RyaW5nLFxuICAgIHR5cGVQYXJhbXNEZWY6IHN0cmluZyxcbiAgICBwYXJhbXNEZWY6IHN0cmluZyxcbiAgICByZXR1cm5UeXBlRGVmOiBzdHJpbmcsXG4gICAgcGF5bG9hZERlZjogc3RyaW5nLFxuICApIHtcbiAgICBjb25zdCBtZXRob2ROYW1lU3dyID0gYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lXG4gICAgICA/IGB1c2Uke2luZmxlY3Rpb24uY2FtZWxpemUoYXBpLm9wdGlvbnMucmVzb3VyY2VOYW1lKX1gXG4gICAgICA6IGB1c2Uke2luZmxlY3Rpb24uY2FtZWxpemUoYXBpLm1ldGhvZE5hbWUpfWA7XG4gICAgcmV0dXJuIGAgIGV4cG9ydCBmdW5jdGlvbiAke2luZmxlY3Rpb24uY2FtZWxpemUobWV0aG9kTmFtZVN3ciwgdHJ1ZSl9JHt0eXBlUGFyYW1zRGVmfSgke1tcbiAgICAgIHBhcmFtc0RlZixcbiAgICAgIFwic3dyT3B0aW9ucz86IFN3ck9wdGlvbnNcIixcbiAgICBdXG4gICAgICAuZmlsdGVyKChwKSA9PiBwICE9PSBcIlwiKVxuICAgICAgLmpvaW4oXCIsXCIpfSwgKTogU1dSUmVzcG9uc2U8JHtyZXR1cm5UeXBlRGVmfSwgU1dSRXJyb3I+IHtcbiAgICByZXR1cm4gdXNlU1dSKGhhbmRsZUNvbmRpdGlvbmFsKFtcbiAgICAgIFxcYCR7YXBpQmFzZVVybH1cXGAsXG4gICAgICAke3BheWxvYWREZWZ9LFxuICAgIF0sIHN3ck9wdGlvbnM/LmNvbmRpdGlvbmFsKSR7YXBpLm9wdGlvbnMuaHR0cE1ldGhvZCA9PT0gXCJQT1NUXCIgPyBcIiwgc3dyUG9zdEZldGNoZXJcIiA6IFwiXCJ9JHtcbiAgICAgIGFwaS5vcHRpb25zLnRpbWVvdXQgPyBgLCB7IGxvYWRpbmdUaW1lb3V0OiAke2FwaS5vcHRpb25zLnRpbWVvdXR9IH1gIDogXCJcIlxuICAgIH0pO1xuICB9YDtcbiAgfVxuXG4gIHJlbmRlcldpbmRvd0ZldGNoKFxuICAgIGFwaTogRXh0ZW5kZWRBcGksXG4gICAgYXBpQmFzZVVybDogc3RyaW5nLFxuICAgIHR5cGVQYXJhbXNEZWY6IHN0cmluZyxcbiAgICBwYXJhbXNEZWY6IHN0cmluZyxcbiAgICBwYXlsb2FkRGVmOiBzdHJpbmcsXG4gICkge1xuICAgIHJldHVybiBgXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gJHthcGkubWV0aG9kTmFtZX0ke3R5cGVQYXJhbXNEZWZ9KCR7cGFyYW1zRGVmfSk6IFByb21pc2U8UmVzcG9uc2U+IHtcbiAgICByZXR1cm4gd2luZG93LmZldGNoKFxcYCR7YXBpQmFzZVVybH0/XFwke3FzLnN0cmluZ2lmeSgke3BheWxvYWREZWZ9KX1cXGAke1xuICAgICAgYXBpLm9wdGlvbnMudGltZW91dCA/IGAsIHsgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KCR7YXBpLm9wdGlvbnMudGltZW91dH0pIH1gIDogXCJcIlxuICAgIH0pO1xufVxuICAgIGAudHJpbSgpO1xuICB9XG5cbiAgcmVuZGVyU3RyZWFtKGFwaTogRXh0ZW5kZWRBcGksIGFwaUJhc2VVcmw6IHN0cmluZywgcGFyYW1zRGVmQXNPYmplY3Q6IHN0cmluZykge1xuICAgIGlmICghYXBpLnN0cmVhbU9wdGlvbnMpIHtcbiAgICAgIHJldHVybiBcIi8vIHN0cmVhbU9wdGlvbnMgbm90IGZvdW5kXCI7XG4gICAgfVxuXG4gICAgY29uc3QgbWV0aG9kTmFtZVN0cmVhbSA9IGFwaS5vcHRpb25zLnJlc291cmNlTmFtZVxuICAgICAgPyBgdXNlJHtpbmZsZWN0aW9uLmNhbWVsaXplKGFwaS5vcHRpb25zLnJlc291cmNlTmFtZSl9YFxuICAgICAgOiBgdXNlJHtpbmZsZWN0aW9uLmNhbWVsaXplKGFwaS5tZXRob2ROYW1lKX1gO1xuICAgIGNvbnN0IG1ldGhvZE5hbWVTdHJlYW1DYW1lbGl6ZWQgPSBpbmZsZWN0aW9uLmNhbWVsaXplKG1ldGhvZE5hbWVTdHJlYW0sIHRydWUpO1xuXG4gICAgY29uc3QgZXZlbnRzVHlwZURlZiA9IHpvZFR5cGVUb1RzVHlwZURlZihhcGkuc3RyZWFtT3B0aW9ucy5ldmVudHMpO1xuXG4gICAgcmV0dXJuIGAgIGV4cG9ydCBmdW5jdGlvbiAke21ldGhvZE5hbWVTdHJlYW1DYW1lbGl6ZWR9KFxuICBwYXJhbXM6ICR7cGFyYW1zRGVmQXNPYmplY3R9LFxuICBoYW5kbGVyczogRXZlbnRIYW5kbGVyczwke2V2ZW50c1R5cGVEZWZ9ICYgeyBlbmQ/OiAoKSA9PiB2b2lkIH0+LFxuICBvcHRpb25zOiBTU0VTdHJlYW1PcHRpb25zKSB7XG4gICAgcmV0dXJuIHVzZVNTRVN0cmVhbTwke2V2ZW50c1R5cGVEZWZ9PihcXGAke2FwaUJhc2VVcmx9XFxgLCBwYXJhbXMsIGhhbmRsZXJzLCBvcHRpb25zKTtcbiAgfWA7XG4gIH1cbn1cbiJdLCJuYW1lcyI6WyJhc3NlcnQiLCJpbmZsZWN0aW9uIiwiZGlmZiIsImdyb3VwIiwic29ydCIsInVuaXF1ZSIsImFwaVBhcmFtVG9Uc0NvZGUiLCJhcGlQYXJhbVRvVHNDb2RlQXNPYmplY3QiLCJhcGlQYXJhbVR5cGVUb1RzVHlwZSIsInVud3JhcFByb21pc2VPbmNlIiwiU29uYW11IiwiTmFpdGUiLCJBcGlQYXJhbVR5cGUiLCJhc3NlcnREZWZpbmVkIiwiVGVtcGxhdGUiLCJ6b2RUeXBlVG9Uc1R5cGVEZWYiLCJUZW1wbGF0ZV9fc2VydmljZSIsImdldFRhcmdldEFuZFBhdGgiLCJuYW1lcyIsInRhcmdldCIsInBhdGgiLCJmcyIsInJlbmRlciIsIm5hbWVzUmVjb3JkIiwidCIsInN5bmNlciIsImFwaXMiLCJhcGlzRm9yVGhpc01vZGVsIiwiZmlsdGVyIiwiYXBpIiwibW9kZWxOYW1lIiwiY2FwaXRhbCIsImxpbmVzIiwiaW1wb3J0S2V5cyIsImdldFR5cGVTb3VyY2UiLCJoYXNBeGlvc1Byb2dyZXNzRXZlbnQiLCJmaW5kIiwib3B0aW9ucyIsImNsaWVudHMiLCJpbmNsdWRlcyIsImJvZHkiLCJqb2luIiwia2V5IiwiY3VzdG9tSGVhZGVycyIsInR5cGVQYXJhbU5hbWVzIiwiZ3JvdXBzIiwiT2JqZWN0Iiwia2V5cyIsIm1hcCIsIm1ldGhvZHMiLCJtZXRob2RDb2RlcyIsInBhcmFtc1dpdGhvdXRDb250ZXh0IiwicGFyYW1ldGVycyIsInBhcmFtIiwiaXNDb250ZXh0IiwidHlwZSIsImlzUmVmS25leCIsIm9wdGlvbmFsIiwibmFtZSIsInN0YXJ0c1dpdGgiLCJ0eXBlUGFyYW1ldGVyc0FzVHNUeXBlIiwidHlwZVBhcmFtZXRlcnMiLCJ0eXBlUGFyYW0iLCJ0eXBlUGFyYW1zRGVmIiwiY29uY2F0IiwiaWQiLCJwYXJhbXNEZWYiLCJwYXJhbXNEZWZBc09iamVjdCIsInJldHVyblR5cGVEZWYiLCJyZXR1cm5UeXBlIiwicGF5bG9hZERlZiIsImFwaUJhc2VVcmwiLCJjb25maWciLCJyb3V0ZSIsInByZWZpeCIsImNsaWVudCIsInJlbmRlckF4aW9zIiwicmVuZGVyQXhpb3NNdWx0aXBhcnQiLCJyZW5kZXJTd3IiLCJyZW5kZXJXaW5kb3dGZXRjaCIsImNhbWVsaXplIiwic3RyZWFtT3B0aW9ucyIsInJlbmRlclN0cmVhbSIsInJlcGxhY2UiLCJtZXRob2ROYW1lQXhpb3MiLCJyZXNvdXJjZU5hbWUiLCJtZXRob2ROYW1lIiwiaHR0cE1ldGhvZCIsInRpbWVvdXQiLCJ0cmltIiwiaXNNdWx0aXBsZSIsInVwbG9hZE9wdGlvbnMiLCJtb2RlIiwiZmlsZVBhcmFtTmFtZSIsImZpbGVQYXJhbVR5cGUiLCJmb3JtRGF0YURlZiIsInBhcmFtc0RlZkNvbW1hIiwibWV0aG9kTmFtZVN3ciIsInAiLCJtZXRob2ROYW1lU3RyZWFtIiwibWV0aG9kTmFtZVN0cmVhbUNhbWVsaXplZCIsImV2ZW50c1R5cGVEZWYiLCJldmVudHMiXSwibWFwcGluZ3MiOiJBQUFBLE9BQU9BLFlBQVksU0FBUztBQUM1QixPQUFPQyxnQkFBZ0IsYUFBYTtBQUNwQyxTQUFTQyxJQUFJLEVBQUVDLEtBQUssRUFBRUMsSUFBSSxFQUFFQyxNQUFNLFFBQVEsVUFBVTtBQUNwRCxTQUNFQyxnQkFBZ0IsRUFDaEJDLHdCQUF3QixFQUN4QkMsb0JBQW9CLEVBQ3BCQyxpQkFBaUIsUUFDWiwrQkFBNEI7QUFFbkMsU0FBU0MsTUFBTSxRQUFRLHNCQUFtQjtBQUUxQyxTQUFTQyxLQUFLLFFBQVEsdUJBQW9CO0FBRTFDLFNBQXdCQyxZQUFZLFFBQVEsdUJBQW9CO0FBQ2hFLFNBQVNDLGFBQWEsUUFBUSx1QkFBb0I7QUFDbEQsU0FBU0MsUUFBUSxRQUFRLGlCQUFjO0FBQ3ZDLFNBQVNDLGtCQUFrQixRQUFRLHNCQUFtQjtBQUV0RCxPQUFPLE1BQU1DLDBCQUEwQkY7SUFDckMsYUFBYztRQUNaLEtBQUssQ0FBQztJQUNSO0lBRUFHLGlCQUFpQkMsS0FBd0IsRUFBRTtRQUN6QyxPQUFPO1lBQ0xDLFFBQVE7WUFDUkMsTUFBTSxHQUFHRixNQUFNRyxFQUFFLENBQUMsQ0FBQyxFQUFFSCxNQUFNRyxFQUFFLENBQUMsV0FBVyxDQUFDO1FBQzVDO0lBQ0Y7SUFF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
|