ngx-atomic-i18n 0.1.0 → 0.1.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.
@@ -1,245 +0,0 @@
1
- import { effect, inject, Injector, runInInjectionContext } from "@angular/core";
2
- import { Observable } from "rxjs";
3
- /** Normalizes a language code against the configured supported languages. */
4
- export function normalizeLangCode(lang, supportedLangs) {
5
- if (!lang)
6
- return null;
7
- const variants = new Set();
8
- variants.add(lang);
9
- variants.add(lang.replace(/_/g, '-'));
10
- variants.add(lang.replace(/-/g, '_'));
11
- variants.add(lang.toLowerCase());
12
- variants.add(lang.replace(/_/g, '-').toLowerCase());
13
- for (const candidate of variants) {
14
- const match = supportedLangs.find(supported => supported.toLowerCase() === candidate.toLowerCase());
15
- if (match)
16
- return match;
17
- }
18
- return null;
19
- }
20
- /** Determines the most appropriate language using the configured detection order. */
21
- export function detectPreferredLang(config) {
22
- const { supportedLangs, fallbackLang, langDetectionOrder } = config;
23
- for (const source of langDetectionOrder) {
24
- let lang;
25
- switch (source) {
26
- case 'url':
27
- lang = typeof window !== 'undefined' ? window.location.pathname.split('/')[1] : null;
28
- break;
29
- case 'clientRequest':
30
- lang = config.clientRequestLang ?? null;
31
- break;
32
- case 'localStorage':
33
- lang = typeof window !== 'undefined' ? localStorage.getItem('lang') : null;
34
- break;
35
- case 'browser':
36
- const langTag = globalThis?.navigator?.language ?? '';
37
- lang = supportedLangs.find(s => langTag.startsWith(s)) ?? null;
38
- break;
39
- case 'customLang':
40
- lang = typeof config.customLang === 'function' ? config.customLang() : config.customLang ?? null;
41
- break;
42
- case 'fallback':
43
- lang = fallbackLang;
44
- break;
45
- }
46
- const normalized = normalizeLangCode(lang, supportedLangs);
47
- if (normalized) {
48
- return normalized;
49
- }
50
- ;
51
- }
52
- return normalizeLangCode(fallbackLang, supportedLangs) ?? fallbackLang;
53
- }
54
- /** Lightweight ICU parser that supports nested select/plural structures. */
55
- export function parseICU(templateText, params) {
56
- if (typeof params === 'object' ? !Object.keys(params).length : true)
57
- return templateText;
58
- const paramMap = {};
59
- for (const [key, val] of Object.entries(params)) {
60
- paramMap[key] = String(val);
61
- }
62
- function extractBlock(text, startIndex) {
63
- let depth = 0;
64
- let i = startIndex;
65
- while (i < text.length) {
66
- if (text[i] === '{') {
67
- if (depth === 0)
68
- startIndex = i;
69
- depth++;
70
- }
71
- else if (text[i] === '}') {
72
- depth--;
73
- if (depth === 0)
74
- return [text.slice(startIndex, i + 1), i + 1];
75
- }
76
- i++;
77
- }
78
- return [text.slice(startIndex), text.length];
79
- }
80
- function extractOptions(body) {
81
- const options = {};
82
- let i = 0;
83
- while (i < body.length) {
84
- while (body[i] === ' ')
85
- i++;
86
- let key = '';
87
- while (i < body.length && body[i] !== '{' && body[i] !== ' ') {
88
- key += body[i++];
89
- }
90
- while (i < body.length && body[i] === ' ')
91
- i++;
92
- if (body[i] !== '{') {
93
- // Option must have a nested block; otherwise skip it.
94
- i++;
95
- continue;
96
- }
97
- const [block, next] = extractBlock(body, i);
98
- options[key] = block.slice(1, -1);
99
- i = next;
100
- }
101
- return options;
102
- }
103
- function resolveICU(text) {
104
- text = text.replace(/\{\{(\w+)\}\}/g, (_, key) => paramMap[key] ?? '');
105
- let result = '';
106
- let cursor = 0;
107
- while (cursor < text.length) {
108
- const start = text.indexOf('{', cursor);
109
- if (start === -1) {
110
- result += text.slice(cursor);
111
- break;
112
- }
113
- result += text.slice(cursor, start);
114
- const [block, nextIndex] = extractBlock(text, start);
115
- if (!block || block === '' || block === '{}') {
116
- cursor = nextIndex;
117
- continue;
118
- }
119
- const match = block.match(/^\{(\w+),\s*(plural|select),/);
120
- if (!match) {
121
- result += block;
122
- cursor = nextIndex;
123
- continue;
124
- }
125
- const [, varName, type] = match;
126
- const rawVal = paramMap[varName] ?? '';
127
- const numVal = Number(rawVal);
128
- const body = block.slice(match[0].length, -1);
129
- const options = extractOptions(body);
130
- const selected = options[`=${rawVal}`] ||
131
- (type === 'plural' && numVal === 1 && options['one']) ||
132
- options[rawVal] ||
133
- options['other'] ||
134
- '';
135
- if (!selected) {
136
- result += block;
137
- cursor = nextIndex;
138
- continue;
139
- }
140
- let resolved = resolveICU(selected);
141
- if (type === 'plural') {
142
- resolved = resolved.replace(/#/g, rawVal);
143
- }
144
- resolved = resolved.replace(/{{(\w+)}}|\{(\w+)\}/g, (_, k1, k2) => {
145
- const k = k1 || k2;
146
- return paramMap[k] ?? '';
147
- });
148
- result += resolved;
149
- cursor = nextIndex;
150
- }
151
- return result;
152
- }
153
- return resolveICU(templateText);
154
- }
155
- /** Flattens a nested translation object using dot notation keys. */
156
- export function flattenTranslations(obj, prefix = '') {
157
- const result = {};
158
- for (const [key, value] of Object.entries(obj)) {
159
- const newKey = prefix ? `${prefix}.${key}` : key;
160
- if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
161
- Object.assign(result, flattenTranslations(value, newKey));
162
- }
163
- else {
164
- result[newKey] = String(value);
165
- }
166
- }
167
- return result;
168
- }
169
- /** Converts a signal to an observable while preserving injection context. */
170
- export function toObservable(signal) {
171
- const injector = inject(Injector);
172
- return new Observable(subscribe => {
173
- subscribe.next(signal());
174
- const stop = runInInjectionContext(injector, () => effect(() => subscribe.next(signal()), { allowSignalWrites: true }));
175
- return () => stop.destroy();
176
- });
177
- }
178
- /** Deeply merges plain objects, replacing non-object values by assignment. */
179
- export function deepMerge(target, source) {
180
- const output = { ...target };
181
- for (const key in source) {
182
- const targetValue = target[key];
183
- if (source.hasOwnProperty(key) &&
184
- typeof source[key] === 'object' &&
185
- source[key] !== null &&
186
- !Array.isArray(source[key]) &&
187
- typeof targetValue === 'object' &&
188
- targetValue !== null &&
189
- !Array.isArray(targetValue)) {
190
- output[key] = deepMerge(targetValue, source[key]);
191
- }
192
- else {
193
- output[key] = source[key];
194
- }
195
- }
196
- return output;
197
- }
198
- /** Recursively retains only keys that are not already present in the existing object. */
199
- export function filterNewKeysDeep(bundle, existing) {
200
- const result = {};
201
- for (const key in bundle) {
202
- const existValue = existing[key];
203
- if (typeof bundle[key] === 'object' &&
204
- bundle[key] !== null &&
205
- !Array.isArray(bundle[key]) &&
206
- typeof existValue === 'object' &&
207
- existValue !== null &&
208
- !Array.isArray(existValue)) {
209
- result[key] = filterNewKeysDeep(bundle[key], existValue);
210
- }
211
- else if (!(key in existing)) {
212
- result[key] = bundle[key];
213
- }
214
- }
215
- return result;
216
- }
217
- /** Safely reads a dotted path from a nested object. */
218
- export function getNested(obj, path) {
219
- return path.split('.').reduce((res, key) => res?.[key], obj);
220
- }
221
- /** Removes any leading slashes from path-like strings. */
222
- export const stripLeadingSep = (s) => s.replace(/^[\\/]+/, '');
223
- /** Normalises the path template configuration to an array form. */
224
- export const tempToArray = (template) => Array.isArray(template) ? template : (template ? [template] : undefined);
225
- /**
226
- * Detect current build version from injected script names (CSR only).
227
- * Matches filenames like: main.<hash>.js, runtime.<hash>.js, polyfills.<hash>.js
228
- */
229
- export function detectBuildVersion() {
230
- try {
231
- if (typeof document === 'undefined' || !document?.scripts)
232
- return null;
233
- const regex = /\/(?:main|runtime|polyfills)\.([a-f0-9]{8,})\.[^\/]*\.js(?:\?|$)/i;
234
- for (const s of Array.from(document.scripts)) {
235
- const version = regex.exec(s.src);
236
- if (version?.[1])
237
- return version[1];
238
- }
239
- return null;
240
- }
241
- catch {
242
- return null;
243
- }
244
- }
245
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsYXRlLnV0aWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtYXRvbWljLWkxOG4vc3JjL2xpYi90cmFuc2xhdGUudXRpbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUscUJBQXFCLEVBQVUsTUFBTSxlQUFlLENBQUM7QUFFeEYsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUVsQyw2RUFBNkU7QUFDN0UsTUFBTSxVQUFVLGlCQUFpQixDQUMvQixJQUErQixFQUMvQixjQUF3QjtJQUV4QixJQUFJLENBQUMsSUFBSTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3ZCLE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDbkMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNuQixRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDdEMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3RDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDakMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO0lBQ3BELEtBQUssTUFBTSxTQUFTLElBQUksUUFBUSxFQUFFLENBQUM7UUFDakMsTUFBTSxLQUFLLEdBQUcsY0FBYyxDQUFDLElBQUksQ0FDL0IsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsV0FBVyxFQUFFLEtBQUssU0FBUyxDQUFDLFdBQVcsRUFBRSxD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QUFFLENBQUM7WUFDN0MsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBRSxDQUF1QixDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3pELElBQUksT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDO2dCQUFFLE9BQU8sT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3RDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZWZmZWN0LCBpbmplY3QsIEluamVjdG9yLCBydW5JbkluamVjdGlvbkNvbnRleHQsIFNpZ25hbCB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBEZWVwUGFydGlhbCwgUGF0aFRlbXBsYXRlLCBUcmFuc2xhdGlvbkNvbmZpZyB9IGZyb20gXCIuL3RyYW5zbGF0ZS50eXBlXCI7XG5pbXBvcnQgeyBPYnNlcnZhYmxlIH0gZnJvbSBcInJ4anNcIjtcblxuLyoqIE5vcm1hbGl6ZXMgYSBsYW5ndWFnZSBjb2RlIGFnYWluc3QgdGhlIGNvbmZpZ3VyZWQgc3VwcG9ydGVkIGxhbmd1YWdlcy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVMYW5nQ29kZShcbiAgbGFuZzogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgc3VwcG9ydGVkTGFuZ3M6IHN0cmluZ1tdXG4pOiBzdHJpbmcgfCBudWxsIHtcbiAgaWYgKCFsYW5nKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgdmFyaWFudHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgdmFyaWFudHMuYWRkKGxhbmcpO1xuICB2YXJpYW50cy5hZGQobGFuZy5yZXBsYWNlKC9fL2csICctJykpO1xuICB2YXJpYW50cy5hZGQobGFuZy5yZXBsYWNlKC8tL2csICdfJykpO1xuICB2YXJpYW50cy5hZGQobGFuZy50b0xvd2VyQ2FzZSgpKTtcbiAgdmFyaWFudHMuYWRkKGxhbmcucmVwbGFjZSgvXy9nLCAnLScpLnRvTG93ZXJDYXNlKCkpO1xuICBmb3IgKGNvbnN0IGNhbmRpZGF0ZSBvZiB2YXJpYW50cykge1xuICAgIGNvbnN0IG1hdGNoID0gc3VwcG9ydGVkTGFuZ3MuZmluZChcbiAgICAgIHN1cHBvcnRlZCA9PiBzdXBwb3J0ZWQudG9Mb3dlckNhc2UoKSA9PT0gY2FuZGlkYXRlLnRvTG93ZXJDYXNlKClcbiAgICApO1xuICAgIGlmIChtYXRjaCkgcmV0dXJuIG1hdGNoO1xuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG4vKiogRGV0ZXJtaW5lcyB0aGUgbW9zdCBhcHByb3ByaWF0ZSBsYW5ndWFnZSB1c2luZyB0aGUgY29uZmlndXJlZCBkZXRlY3Rpb24gb3JkZXIuICovXG5leHBvcnQgZnVuY3Rpb24gZGV0ZWN0UHJlZmVycmVkTGFuZyhjb25maWc6IFRyYW5zbGF0aW9uQ29uZmlnKTogc3RyaW5nIHtcbiAgY29uc3QgeyBzdXBwb3J0ZWRMYW5ncywgZmFsbGJhY2tMYW5nLCBsYW5nRGV0ZWN0aW9uT3JkZXIgfSA9IGNvbmZpZztcbiAgZm9yIChjb25zdCBzb3VyY2Ugb2YgbGFuZ0RldGVjdGlvbk9yZGVyKSB7XG4gICAgbGV0IGxhbmc6IHN0cmluZyB8IG51bGw7XG4gICAgc3dpdGNoIChzb3VyY2UpIHtcbiAgICAgIGNhc2UgJ3VybCc6XG4gICAgICAgIGxhbmcgPSB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyA/IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZS5zcGxpdCgnLycpWzFdIDogbnVsbDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdjbGllbnRSZXF1ZXN0JzpcbiAgICAgICAgbGFuZyA9IGNvbmZpZy5jbGllbnRSZXF1ZXN0TGFuZyA/PyBudWxsO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2xvY2FsU3RvcmFnZSc6XG4gICAgICAgIGxhbmcgPSB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyA/IGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdsYW5nJykgOiBudWxsO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2Jyb3dzZXInOlxuICAgICAgICBjb25zdCBsYW5nVGFnID0gKGdsb2JhbFRoaXMgYXMgYW55KT8ubmF2aWdhdG9yPy5sYW5ndWFnZSA/PyAnJztcbiAgICAgICAgbGFuZyA9IHN1cHBvcnRlZExhbmdzLmZpbmQocyA9PiBsYW5nVGFnLnN0YXJ0c1dpdGgocykpID8/IG51bGw7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnY3VzdG9tTGFuZyc6XG4gICAgICAgIGxhbmcgPSB0eXBlb2YgY29uZmlnLmN1c3RvbUxhbmcgPT09ICdmdW5jdGlvbicgPyBjb25maWcuY3VzdG9tTGFuZygpIDogY29uZmlnLmN1c3RvbUxhbmcgPz8gbnVsbDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdmYWxsYmFjayc6XG4gICAgICAgIGxhbmcgPSBmYWxsYmFja0xhbmc7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgICBjb25zdCBub3JtYWxpemVkID0gbm9ybWFsaXplTGFuZ0NvZGUobGFuZywgc3VwcG9ydGVkTGFuZ3MpO1xuICAgIGlmIChub3JtYWxpemVkKSB7XG4gICAgICByZXR1cm4gbm9ybWFsaXplZDtcbiAgICB9O1xuICB9XG4gIHJldHVybiBub3JtYWxpemVMYW5nQ29kZShmYWxsYmFja0xhbmcsIHN1cHBvcnRlZExhbmdzKSA/PyBmYWxsYmFja0xhbmc7XG59XG5cbi8qKiBMaWdodHdlaWdodCBJQ1UgcGFyc2VyIHRoYXQgc3VwcG9ydHMgbmVzdGVkIHNlbGVjdC9wbHVyYWwgc3RydWN0dXJlcy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUlDVSh0ZW1wbGF0ZVRleHQ6IHN0cmluZywgcGFyYW1zPzogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgbnVtYmVyPik6IHN0cmluZyB7XG4gIGlmICh0eXBlb2YgcGFyYW1zID09PSAnb2JqZWN0JyA/ICFPYmplY3Qua2V5cyhwYXJhbXMpLmxlbmd0aCA6IHRydWUpIHJldHVybiB0ZW1wbGF0ZVRleHQ7XG5cbiAgY29uc3QgcGFyYW1NYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgZm9yIChjb25zdCBba2V5LCB2YWxdIG9mIE9iamVjdC5lbnRyaWVzKHBhcmFtcyEpKSB7XG4gICAgcGFyYW1NYXBba2V5XSA9IFN0cmluZyh2YWwpO1xuICB9XG5cbiAgZnVuY3Rpb24gZXh0cmFjdEJsb2NrKHRleHQ6IHN0cmluZywgc3RhcnRJbmRleDogbnVtYmVyKTogW3N0cmluZywgbnVtYmVyXSB7XG4gICAgbGV0IGRlcHRoID0gMDtcbiAgICBsZXQgaSA9IHN0YXJ0SW5kZXg7XG4gICAgd2hpbGUgKGkgPCB0ZXh0Lmxlbmd0aCkge1xuICAgICAgaWYgKHRleHRbaV0gPT09ICd7Jykge1xuICAgICAgICBpZiAoZGVwdGggPT09IDApIHN0YXJ0SW5kZXggPSBpO1xuICAgICAgICBkZXB0aCsrO1xuICAgICAgfSBlbHNlIGlmICh0ZXh0W2ldID09PSAnfScpIHtcbiAgICAgICAgZGVwdGgtLTtcbiAgICAgICAgaWYgKGRlcHRoID09PSAwKSByZXR1cm4gW3RleHQuc2xpY2Uoc3RhcnRJbmRleCwgaSArIDEpLCBpICsgMV07XG4gICAgICB9XG4gICAgICBpKys7XG4gICAgfVxuICAgIHJldHVybiBbdGV4dC5zbGljZShzdGFydEluZGV4KSwgdGV4dC5sZW5ndGhdO1xuICB9XG5cbiAgZnVuY3Rpb24gZXh0cmFjdE9wdGlvbnMoYm9keTogc3RyaW5nKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gICAgY29uc3Qgb3B0aW9uczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICAgIGxldCBpID0gMDtcbiAgICB3aGlsZSAoaSA8IGJvZHkubGVuZ3RoKSB7XG4gICAgICB3aGlsZSAoYm9keVtpXSA9PT0gJyAnKSBpKys7XG4gICAgICBsZXQga2V5ID0gJyc7XG4gICAgICB3aGlsZSAoaSA8IGJvZHkubGVuZ3RoICYmIGJvZHlbaV0gIT09ICd7JyAmJiBib2R5W2ldICE9PSAnICcpIHtcbiAgICAgICAga2V5ICs9IGJvZHlbaSsrXTtcbiAgICAgIH1cbiAgICAgIHdoaWxlIChpIDwgYm9keS5sZW5ndGggJiYgYm9keVtpXSA9PT0gJyAnKSBpKys7XG4gICAgICBpZiAoYm9keVtpXSAhPT0gJ3snKSB7XG4gICAgICAgIC8vIE9wdGlvbiBtdXN0IGhhdmUgYSBuZXN0ZWQgYmxvY2s7IG90aGVyd2lzZSBza2lwIGl0LlxuICAgICAgICBpKys7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgW2Jsb2NrLCBuZXh0XSA9IGV4dHJhY3RCbG9jayhib2R5LCBpKTtcbiAgICAgIG9wdGlvbnNba2V5XSA9IGJsb2NrLnNsaWNlKDEsIC0xKTtcbiAgICAgIGkgPSBuZXh0O1xuICAgIH1cbiAgICByZXR1cm4gb3B0aW9ucztcbiAgfVxuXG4gIGZ1bmN0aW9uIHJlc29sdmVJQ1UodGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXHtcXHsoXFx3KylcXH1cXH0vZywgKF8sIGtleSkgPT4gcGFyYW1NYXBba2V5XSA/PyAnJyk7XG4gICAgbGV0IHJlc3VsdCA9ICcnO1xuICAgIGxldCBjdXJzb3IgPSAwO1xuXG4gICAgd2hpbGUgKGN1cnNvciA8IHRleHQubGVuZ3RoKSB7XG4gICAgICBjb25zdCBzdGFydCA9IHRleHQuaW5kZXhPZigneycsIGN1cnNvcik7XG4gICAgICBpZiAoc3RhcnQgPT09IC0xKSB7XG4gICAgICAgIHJlc3VsdCArPSB0ZXh0LnNsaWNlKGN1cnNvcik7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICByZXN1bHQgKz0gdGV4dC5zbGljZShjdXJzb3IsIHN0YXJ0KTtcblxuICAgICAgY29uc3QgW2Jsb2NrLCBuZXh0SW5kZXhdID0gZXh0cmFjdEJsb2NrKHRleHQsIHN0YXJ0KTtcblxuICAgICAgaWYgKCFibG9jayB8fCBibG9jayA9PT0gJycgfHwgYmxvY2sgPT09ICd7fScpIHtcbiAgICAgICAgY3Vyc29yID0gbmV4dEluZGV4O1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbWF0Y2ggPSBibG9jay5tYXRjaCgvXlxceyhcXHcrKSxcXHMqKHBsdXJhbHxzZWxlY3QpLC8pO1xuICAgICAgaWYgKCFtYXRjaCkge1xuICAgICAgICByZXN1bHQgKz0gYmxvY2s7XG4gICAgICAgIGN1cnNvciA9IG5leHRJbmRleDtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IFssIHZhck5hbWUsIHR5cGVdID0gbWF0Y2g7XG4gICAgICBjb25zdCByYXdWYWwgPSBwYXJhbU1hcFt2YXJOYW1lXSA/PyAnJztcbiAgICAgIGNvbnN0IG51bVZhbCA9IE51bWJlcihyYXdWYWwpO1xuICAgICAgY29uc3QgYm9keSA9IGJsb2NrLnNsaWNlKG1hdGNoWzBdLmxlbmd0aCwgLTEpO1xuICAgICAgY29uc3Qgb3B0aW9ucyA9IGV4dHJhY3RPcHRpb25zKGJvZHkpO1xuXG4gICAgICBjb25zdCBzZWxlY3RlZCA9XG4gICAgICAgIG9wdGlvbnNbYD0ke3Jhd1ZhbH1gXSB8fFxuICAgICAgICAodHlwZSA9PT0gJ3BsdXJhbCcgJiYgbnVtVmFsID09PSAxICYmIG9wdGlvbnNbJ29uZSddKSB8fFxuICAgICAgICBvcHRpb25zW3Jhd1ZhbF0gfHxcbiAgICAgICAgb3B0aW9uc1snb3RoZXInXSB8fFxuICAgICAgICAnJztcblxuICAgICAgaWYgKCFzZWxlY3RlZCkge1xuICAgICAgICByZXN1bHQgKz0gYmxvY2s7XG4gICAgICAgIGN1cnNvciA9IG5leHRJbmRleDtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGxldCByZXNvbHZlZCA9IHJlc29sdmVJQ1Uoc2VsZWN0ZWQpO1xuXG4gICAgICBpZiAodHlwZSA9PT0gJ3BsdXJhbCcpIHtcbiAgICAgICAgcmVzb2x2ZWQgPSByZXNvbHZlZC5yZXBsYWNlKC8jL2csIHJhd1ZhbCk7XG4gICAgICB9XG5cbiAgICAgIHJlc29sdmVkID0gcmVzb2x2ZWQucmVwbGFjZSgve3soXFx3Kyl9fXxcXHsoXFx3KylcXH0vZywgKF8sIGsxLCBrMikgPT4ge1xuICAgICAgICBjb25zdCBrID0gazEgfHwgazI7XG4gICAgICAgIHJldHVybiBwYXJhbU1hcFtrXSA/PyAnJztcbiAgICAgIH0pO1xuXG4gICAgICByZXN1bHQgKz0gcmVzb2x2ZWQ7XG4gICAgICBjdXJzb3IgPSBuZXh0SW5kZXg7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHJldHVybiByZXNvbHZlSUNVKHRlbXBsYXRlVGV4dCk7XG59XG5cblxuXG4vKiogRmxhdHRlbnMgYSBuZXN0ZWQgdHJhbnNsYXRpb24gb2JqZWN0IHVzaW5nIGRvdCBub3RhdGlvbiBrZXlzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZsYXR0ZW5UcmFuc2xhdGlvbnMob2JqOiBhbnksIHByZWZpeCA9ICcnKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvYmopKSB7XG4gICAgY29uc3QgbmV3S2V5ID0gcHJlZml4ID8gYCR7cHJlZml4fS4ke2tleX1gIDoga2V5O1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlICE9PSBudWxsICYmICFBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgT2JqZWN0LmFzc2lnbihyZXN1bHQsIGZsYXR0ZW5UcmFuc2xhdGlvbnModmFsdWUsIG5ld0tleSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXN1bHRbbmV3S2V5XSA9IFN0cmluZyh2YWx1ZSk7XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cblxuLyoqIENvbnZlcnRzIGEgc2lnbmFsIHRvIGFuIG9ic2VydmFibGUgd2hpbGUgcHJlc2VydmluZyBpbmplY3Rpb24gY29udGV4dC4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0b09ic2VydmFibGU8VD4oc2lnbmFsOiBTaWduYWw8VD4pOiBPYnNlcnZhYmxlPFQ+IHtcbiAgY29uc3QgaW5qZWN0b3IgPSBpbmplY3QoSW5qZWN0b3IpO1xuICByZXR1cm4gbmV3IE9ic2VydmFibGUoc3Vic2NyaWJlID0+IHtcbiAgICBzdWJzY3JpYmUubmV4dChzaWduYWwoKSk7XG4gICAgY29uc3Qgc3RvcCA9IHJ1bkluSW5qZWN0aW9uQ29udGV4dChpbmplY3RvciwgKCkgPT4gZWZmZWN0KCgpID0+IHN1YnNjcmliZS5uZXh0KHNpZ25hbCgpKSwgeyBhbGxvd1NpZ25hbFdyaXRlczogdHJ1ZSB9KSk7XG4gICAgcmV0dXJuICgpID0+IHN0b3AuZGVzdHJveSgpO1xuICB9KTtcbn1cblxuXG4vKiogRGVlcGx5IG1lcmdlcyBwbGFpbiBvYmplY3RzLCByZXBsYWNpbmcgbm9uLW9iamVjdCB2YWx1ZXMgYnkgYXNzaWdubWVudC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWVwTWVyZ2U8VCBleHRlbmRzIG9iamVjdCwgVSBleHRlbmRzIG9iamVjdD4odGFyZ2V0OiBULCBzb3VyY2U6IFUpOiBUICYgVSB7XG4gIGNvbnN0IG91dHB1dCA9IHsgLi4udGFyZ2V0IH0gYXMgVCAmIFU7XG4gIGZvciAoY29uc3Qga2V5IGluIHNvdXJjZSkge1xuICAgIGNvbnN0IHRhcmdldFZhbHVlID0gKHRhcmdldCBhcyBhbnkpW2tleV07XG4gICAgaWYgKFxuICAgICAgc291cmNlLmhhc093blByb3BlcnR5KGtleSkgJiZcbiAgICAgIHR5cGVvZiBzb3VyY2Vba2V5XSA9PT0gJ29iamVjdCcgJiZcbiAgICAgIHNvdXJjZVtrZXldICE9PSBudWxsICYmXG4gICAgICAhQXJyYXkuaXNBcnJheShzb3VyY2Vba2V5XSkgJiZcbiAgICAgIHR5cGVvZiB0YXJnZXRWYWx1ZSA9PT0gJ29iamVjdCcgJiZcbiAgICAgIHRhcmdldFZhbHVlICE9PSBudWxsICYmXG4gICAgICAhQXJyYXkuaXNBcnJheSh0YXJnZXRWYWx1ZSlcbiAgICApIHtcbiAgICAgIG91dHB1dFtrZXldID0gZGVlcE1lcmdlKHRhcmdldFZhbHVlIGFzIGFueSwgc291cmNlW2tleV0gYXMgYW55KTtcbiAgICB9IGVsc2Uge1xuICAgICAgb3V0cHV0W2tleV0gPSBzb3VyY2Vba2V5XSBhcyBhbnk7XG4gICAgfVxuICB9XG4gIHJldHVybiBvdXRwdXQ7XG59XG5cbi8qKiBSZWN1cnNpdmVseSByZXRhaW5zIG9ubHkga2V5cyB0aGF0IGFyZSBub3QgYWxyZWFkeSBwcmVzZW50IGluIHRoZSBleGlzdGluZyBvYmplY3QuICovXG5leHBvcnQgZnVuY3Rpb24gZmlsdGVyTmV3S2V5c0RlZXA8VCBleHRlbmRzIG9iamVjdCwgVSBleHRlbmRzIG9iamVjdD4oYnVuZGxlOiBULCBleGlzdGluZzogVSk6IERlZXBQYXJ0aWFsPFQ+IHtcbiAgY29uc3QgcmVzdWx0ID0ge30gYXMgUGFydGlhbDxUPjtcbiAgZm9yIChjb25zdCBrZXkgaW4gYnVuZGxlKSB7XG4gICAgY29uc3QgZXhpc3RWYWx1ZSA9IChleGlzdGluZyBhcyBhbnkpW2tleV07XG4gICAgaWYgKFxuICAgICAgdHlwZW9mIGJ1bmRsZVtrZXldID09PSAnb2JqZWN0JyAmJlxuICAgICAgYnVuZGxlW2tleV0gIT09IG51bGwgJiZcbiAgICAgICFBcnJheS5pc0FycmF5KGJ1bmRsZVtrZXldKSAmJlxuICAgICAgdHlwZW9mIGV4aXN0VmFsdWUgPT09ICdvYmplY3QnICYmXG4gICAgICBleGlzdFZhbHVlICE9PSBudWxsICYmXG4gICAgICAhQXJyYXkuaXNBcnJheShleGlzdFZhbHVlKVxuICAgICkge1xuICAgICAgcmVzdWx0W2tleV0gPSBmaWx0ZXJOZXdLZXlzRGVlcChidW5kbGVba2V5XSwgZXhpc3RWYWx1ZSkgYXMgYW55O1xuICAgIH0gZWxzZSBpZiAoIShrZXkgaW4gZXhpc3RpbmcpKSB7XG4gICAgICByZXN1bHRba2V5XSA9IGJ1bmRsZVtrZXldO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKiogU2FmZWx5IHJlYWRzIGEgZG90dGVkIHBhdGggZnJvbSBhIG5lc3RlZCBvYmplY3QuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmVzdGVkKG9iajogYW55LCBwYXRoOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICByZXR1cm4gcGF0aC5zcGxpdCgnLicpLnJlZHVjZSgocmVzLCBrZXkpID0+IHJlcz8uW2tleV0sIG9iaik7XG59XG5cbi8qKiBSZW1vdmVzIGFueSBsZWFkaW5nIHNsYXNoZXMgZnJvbSBwYXRoLWxpa2Ugc3RyaW5ncy4gKi9cbmV4cG9ydCBjb25zdCBzdHJpcExlYWRpbmdTZXAgPSAoczogc3RyaW5nKSA9PiBzLnJlcGxhY2UoL15bXFxcXC9dKy8sICcnKTtcblxuLyoqIE5vcm1hbGlzZXMgdGhlIHBhdGggdGVtcGxhdGUgY29uZmlndXJhdGlvbiB0byBhbiBhcnJheSBmb3JtLiAqL1xuZXhwb3J0IGNvbnN0IHRlbXBUb0FycmF5ID0gKHRlbXBsYXRlOiBQYXRoVGVtcGxhdGUpID0+IEFycmF5LmlzQXJyYXkodGVtcGxhdGUpID8gdGVtcGxhdGUgOiAodGVtcGxhdGUgPyBbdGVtcGxhdGVdIDogdW5kZWZpbmVkKTtcblxuLyoqXG4gKiBEZXRlY3QgY3VycmVudCBidWlsZCB2ZXJzaW9uIGZyb20gaW5qZWN0ZWQgc2NyaXB0IG5hbWVzIChDU1Igb25seSkuXG4gKiBNYXRjaGVzIGZpbGVuYW1lcyBsaWtlOiBtYWluLjxoYXNoPi5qcywgcnVudGltZS48aGFzaD4uanMsIHBvbHlmaWxscy48aGFzaD4uanNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRldGVjdEJ1aWxkVmVyc2lvbigpOiBzdHJpbmcgfCBudWxsIHtcbiAgdHJ5IHtcbiAgICBpZiAodHlwZW9mIGRvY3VtZW50ID09PSAndW5kZWZpbmVkJyB8fCAhZG9jdW1lbnQ/LnNjcmlwdHMpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IHJlZ2V4ID0gL1xcLyg/Om1haW58cnVudGltZXxwb2x5ZmlsbHMpXFwuKFthLWYwLTldezgsfSlcXC5bXlxcL10qXFwuanMoPzpcXD98JCkvaTtcbiAgICBmb3IgKGNvbnN0IHMgb2YgQXJyYXkuZnJvbShkb2N1bWVudC5zY3JpcHRzKSkge1xuICAgICAgY29uc3QgdmVyc2lvbiA9IHJlZ2V4LmV4ZWMoKHMgYXMgSFRNTFNjcmlwdEVsZW1lbnQpLnNyYyk7XG4gICAgICBpZiAodmVyc2lvbj8uWzFdKSByZXR1cm4gdmVyc2lvblsxXTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBudWxsO1xuICB9XG59XG4iXX0=