@jsverse/transloco 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1005 -0
- package/LICENSE +22 -0
- package/README.md +44 -0
- package/esm2022/index.mjs +20 -0
- package/esm2022/jsverse-transloco.mjs +5 -0
- package/esm2022/lib/browser-lang.mjs +28 -0
- package/esm2022/lib/get-fallbacks-loaders.mjs +13 -0
- package/esm2022/lib/helpers.mjs +104 -0
- package/esm2022/lib/lang-resolver.mjs +54 -0
- package/esm2022/lib/loader-component.component.mjs +21 -0
- package/esm2022/lib/resolve-loader.mjs +13 -0
- package/esm2022/lib/scope-resolver.mjs +24 -0
- package/esm2022/lib/shared.mjs +73 -0
- package/esm2022/lib/template-handler.mjs +28 -0
- package/esm2022/lib/transloco-fallback-strategy.mjs +26 -0
- package/esm2022/lib/transloco-lang.mjs +3 -0
- package/esm2022/lib/transloco-loading-template.mjs +3 -0
- package/esm2022/lib/transloco-missing-handler.mjs +18 -0
- package/esm2022/lib/transloco-scope.mjs +3 -0
- package/esm2022/lib/transloco-testing.module.mjs +76 -0
- package/esm2022/lib/transloco.config.mjs +37 -0
- package/esm2022/lib/transloco.directive.mjs +169 -0
- package/esm2022/lib/transloco.interceptor.mjs +17 -0
- package/esm2022/lib/transloco.loader.mjs +13 -0
- package/esm2022/lib/transloco.module.mjs +18 -0
- package/esm2022/lib/transloco.pipe.mjs +97 -0
- package/esm2022/lib/transloco.providers.mjs +92 -0
- package/esm2022/lib/transloco.service.mjs +579 -0
- package/esm2022/lib/transloco.transpiler.mjs +145 -0
- package/esm2022/lib/types.mjs +2 -0
- package/fesm2022/jsverse-transloco.mjs +1580 -0
- package/fesm2022/jsverse-transloco.mjs.map +1 -0
- package/index.d.ts +19 -0
- package/lib/browser-lang.d.ts +8 -0
- package/lib/get-fallbacks-loaders.d.ts +14 -0
- package/lib/helpers.d.ts +21 -0
- package/lib/lang-resolver.d.ts +32 -0
- package/lib/loader-component.component.d.ts +6 -0
- package/lib/resolve-loader.d.ts +10 -0
- package/lib/scope-resolver.d.ts +12 -0
- package/lib/shared.d.ts +17 -0
- package/lib/template-handler.d.ts +9 -0
- package/lib/transloco-fallback-strategy.d.ts +14 -0
- package/lib/transloco-lang.d.ts +2 -0
- package/lib/transloco-loading-template.d.ts +3 -0
- package/lib/transloco-missing-handler.d.ts +16 -0
- package/lib/transloco-scope.d.ts +3 -0
- package/lib/transloco-testing.module.d.ts +27 -0
- package/lib/transloco.config.d.ts +27 -0
- package/lib/transloco.directive.d.ts +50 -0
- package/lib/transloco.interceptor.d.ts +14 -0
- package/lib/transloco.loader.d.ts +15 -0
- package/lib/transloco.module.d.ts +8 -0
- package/lib/transloco.pipe.d.ts +23 -0
- package/lib/transloco.providers.d.ts +30 -0
- package/lib/transloco.service.d.ts +199 -0
- package/lib/transloco.transpiler.d.ts +58 -0
- package/lib/types.d.ts +45 -0
- package/package.json +54 -0
- package/schematics/src/assets/i18n/en.json +1 -0
- package/schematics/src/collection.json +59 -0
- package/schematics/src/component/index.d.ts +2 -0
- package/schematics/src/component/index.js +21 -0
- package/schematics/src/component/index.js.map +1 -0
- package/schematics/src/join/index.d.ts +3 -0
- package/schematics/src/join/index.js +79 -0
- package/schematics/src/join/index.js.map +1 -0
- package/schematics/src/join/schema.d.ts +28 -0
- package/schematics/src/join/schema.js +3 -0
- package/schematics/src/join/schema.js.map +1 -0
- package/schematics/src/join/schema.json +43 -0
- package/schematics/src/keys-manager/index.d.ts +5 -0
- package/schematics/src/keys-manager/index.js +97 -0
- package/schematics/src/keys-manager/index.js.map +1 -0
- package/schematics/src/keys-manager/schema.d.ts +19 -0
- package/schematics/src/keys-manager/schema.js +3 -0
- package/schematics/src/keys-manager/schema.js.map +1 -0
- package/schematics/src/keys-manager/schema.json +33 -0
- package/schematics/src/migrate/index.d.ts +3 -0
- package/schematics/src/migrate/index.js +21 -0
- package/schematics/src/migrate/index.js.map +1 -0
- package/schematics/src/migrate/ngx-translate-migration.d.ts +3 -0
- package/schematics/src/migrate/ngx-translate-migration.js +169 -0
- package/schematics/src/migrate/ngx-translate-migration.js.map +1 -0
- package/schematics/src/migrate/schema.d.ts +10 -0
- package/schematics/src/migrate/schema.js +3 -0
- package/schematics/src/migrate/schema.js.map +1 -0
- package/schematics/src/migrate/schema.json +23 -0
- package/schematics/src/ng-add/files/transloco-loader/transloco-loader.__ts__ +12 -0
- package/schematics/src/ng-add/files/transloco-module/transloco-root.module.__ts__ +24 -0
- package/schematics/src/ng-add/generators/http-loader.gen.d.ts +4 -0
- package/schematics/src/ng-add/generators/http-loader.gen.js +15 -0
- package/schematics/src/ng-add/generators/http-loader.gen.js.map +1 -0
- package/schematics/src/ng-add/generators/root-module.gen.d.ts +9 -0
- package/schematics/src/ng-add/generators/root-module.gen.js +31 -0
- package/schematics/src/ng-add/generators/root-module.gen.js.map +1 -0
- package/schematics/src/ng-add/generators/translation-files.gen.d.ts +4 -0
- package/schematics/src/ng-add/generators/translation-files.gen.js +23 -0
- package/schematics/src/ng-add/generators/translation-files.gen.js.map +1 -0
- package/schematics/src/ng-add/index.d.ts +3 -0
- package/schematics/src/ng-add/index.js +103 -0
- package/schematics/src/ng-add/index.js.map +1 -0
- package/schematics/src/ng-add/schema.d.ts +42 -0
- package/schematics/src/ng-add/schema.js +14 -0
- package/schematics/src/ng-add/schema.js.map +1 -0
- package/schematics/src/ng-add/schema.json +53 -0
- package/schematics/src/ng-migrate/index.d.ts +3 -0
- package/schematics/src/ng-migrate/index.js +14 -0
- package/schematics/src/ng-migrate/index.js.map +1 -0
- package/schematics/src/ng-migrate/ng-migrate.d.ts +5 -0
- package/schematics/src/ng-migrate/ng-migrate.js +106 -0
- package/schematics/src/ng-migrate/ng-migrate.js.map +1 -0
- package/schematics/src/ng-migrate/schema.d.ts +14 -0
- package/schematics/src/ng-migrate/schema.js +3 -0
- package/schematics/src/ng-migrate/schema.js.map +1 -0
- package/schematics/src/ng-migrate/schema.json +27 -0
- package/schematics/src/schematics.consts.d.ts +4 -0
- package/schematics/src/schematics.consts.js +8 -0
- package/schematics/src/schematics.consts.js.map +1 -0
- package/schematics/src/scope/index.d.ts +3 -0
- package/schematics/src/scope/index.js +101 -0
- package/schematics/src/scope/index.js.map +1 -0
- package/schematics/src/scope/schema.d.ts +28 -0
- package/schematics/src/scope/schema.js +3 -0
- package/schematics/src/scope/schema.js.map +1 -0
- package/schematics/src/scope/schema.json +84 -0
- package/schematics/src/split/index.d.ts +3 -0
- package/schematics/src/split/index.js +66 -0
- package/schematics/src/split/index.js.map +1 -0
- package/schematics/src/split/schema.d.ts +20 -0
- package/schematics/src/split/schema.js +3 -0
- package/schematics/src/split/schema.js.map +1 -0
- package/schematics/src/split/schema.json +35 -0
- package/schematics/src/types.d.ts +5 -0
- package/schematics/src/types.js +10 -0
- package/schematics/src/types.js.map +1 -0
- package/schematics/src/upgrade/index.d.ts +3 -0
- package/schematics/src/upgrade/index.js +19 -0
- package/schematics/src/upgrade/index.js.map +1 -0
- package/schematics/src/upgrade/schema.d.ts +6 -0
- package/schematics/src/upgrade/schema.js +3 -0
- package/schematics/src/upgrade/schema.js.map +1 -0
- package/schematics/src/upgrade/schema.json +16 -0
- package/schematics/src/upgrade/v2.d.ts +1 -0
- package/schematics/src/upgrade/v2.js +89 -0
- package/schematics/src/upgrade/v2.js.map +1 -0
- package/schematics/src/utils/array.d.ts +3 -0
- package/schematics/src/utils/array.js +12 -0
- package/schematics/src/utils/array.js.map +1 -0
- package/schematics/src/utils/config.d.ts +2 -0
- package/schematics/src/utils/config.js +13 -0
- package/schematics/src/utils/config.js.map +1 -0
- package/schematics/src/utils/find-module.d.ts +23 -0
- package/schematics/src/utils/find-module.js +110 -0
- package/schematics/src/utils/find-module.js.map +1 -0
- package/schematics/src/utils/package.d.ts +5 -0
- package/schematics/src/utils/package.js +19 -0
- package/schematics/src/utils/package.js.map +1 -0
- package/schematics/src/utils/projects.d.ts +8 -0
- package/schematics/src/utils/projects.js +56 -0
- package/schematics/src/utils/projects.js.map +1 -0
- package/schematics/src/utils/translations.d.ts +7 -0
- package/schematics/src/utils/translations.js +31 -0
- package/schematics/src/utils/translations.js.map +1 -0
- package/schematics/src/utils/transloco.d.ts +24 -0
- package/schematics/src/utils/transloco.js +93 -0
- package/schematics/src/utils/transloco.js.map +1 -0
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
import { Inject, Injectable, Optional } from '@angular/core';
|
|
2
|
+
import { BehaviorSubject, catchError, combineLatest, EMPTY, forkJoin, from, map, of, retry, shareReplay, Subject, switchMap, tap, } from 'rxjs';
|
|
3
|
+
import { DefaultLoader, TRANSLOCO_LOADER, } from './transloco.loader';
|
|
4
|
+
import { TRANSLOCO_TRANSPILER, } from './transloco.transpiler';
|
|
5
|
+
import { flatten, isEmpty, isNil, isScopeArray, isScopeObject, isString, size, toCamelCase, unflatten, } from './helpers';
|
|
6
|
+
import { TRANSLOCO_CONFIG } from './transloco.config';
|
|
7
|
+
import { TRANSLOCO_MISSING_HANDLER, } from './transloco-missing-handler';
|
|
8
|
+
import { TRANSLOCO_INTERCEPTOR, } from './transloco.interceptor';
|
|
9
|
+
import { TRANSLOCO_FALLBACK_STRATEGY, } from './transloco-fallback-strategy';
|
|
10
|
+
import { getEventPayload, getLangFromScope, getScopeFromLang, resolveInlineLoader, } from './shared';
|
|
11
|
+
import { getFallbacksLoaders } from './get-fallbacks-loaders';
|
|
12
|
+
import { resolveLoader } from './resolve-loader';
|
|
13
|
+
import * as i0 from "@angular/core";
|
|
14
|
+
let service;
|
|
15
|
+
export function translate(key, params = {}, lang) {
|
|
16
|
+
return service.translate(key, params, lang);
|
|
17
|
+
}
|
|
18
|
+
export function translateObject(key, params = {}, lang) {
|
|
19
|
+
return service.translateObject(key, params, lang);
|
|
20
|
+
}
|
|
21
|
+
export class TranslocoService {
|
|
22
|
+
loader;
|
|
23
|
+
parser;
|
|
24
|
+
missingHandler;
|
|
25
|
+
interceptor;
|
|
26
|
+
fallbackStrategy;
|
|
27
|
+
langChanges$;
|
|
28
|
+
subscription = null;
|
|
29
|
+
translations = new Map();
|
|
30
|
+
cache = new Map();
|
|
31
|
+
firstFallbackLang;
|
|
32
|
+
defaultLang = '';
|
|
33
|
+
availableLangs = [];
|
|
34
|
+
isResolvedMissingOnce = false;
|
|
35
|
+
lang;
|
|
36
|
+
failedLangs = new Set();
|
|
37
|
+
events = new Subject();
|
|
38
|
+
events$ = this.events.asObservable();
|
|
39
|
+
config;
|
|
40
|
+
constructor(loader, parser, missingHandler, interceptor, userConfig, fallbackStrategy) {
|
|
41
|
+
this.loader = loader;
|
|
42
|
+
this.parser = parser;
|
|
43
|
+
this.missingHandler = missingHandler;
|
|
44
|
+
this.interceptor = interceptor;
|
|
45
|
+
this.fallbackStrategy = fallbackStrategy;
|
|
46
|
+
if (!this.loader) {
|
|
47
|
+
this.loader = new DefaultLoader(this.translations);
|
|
48
|
+
}
|
|
49
|
+
service = this;
|
|
50
|
+
this.config = JSON.parse(JSON.stringify(userConfig));
|
|
51
|
+
this.setAvailableLangs(this.config.availableLangs || []);
|
|
52
|
+
this.setFallbackLangForMissingTranslation(this.config);
|
|
53
|
+
this.setDefaultLang(this.config.defaultLang);
|
|
54
|
+
this.lang = new BehaviorSubject(this.getDefaultLang());
|
|
55
|
+
// Don't use distinctUntilChanged as we need the ability to update
|
|
56
|
+
// the value when using setTranslation or setTranslationKeys
|
|
57
|
+
this.langChanges$ = this.lang.asObservable();
|
|
58
|
+
/**
|
|
59
|
+
* When we have a failure, we want to define the next language that succeeded as the active
|
|
60
|
+
*/
|
|
61
|
+
this.subscription = this.events$.subscribe((e) => {
|
|
62
|
+
if (e.type === 'translationLoadSuccess' && e.wasFailure) {
|
|
63
|
+
this.setActiveLang(e.payload.langName);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
getDefaultLang() {
|
|
68
|
+
return this.defaultLang;
|
|
69
|
+
}
|
|
70
|
+
setDefaultLang(lang) {
|
|
71
|
+
this.defaultLang = lang;
|
|
72
|
+
}
|
|
73
|
+
getActiveLang() {
|
|
74
|
+
return this.lang.getValue();
|
|
75
|
+
}
|
|
76
|
+
setActiveLang(lang) {
|
|
77
|
+
this.parser.onLangChanged?.(lang);
|
|
78
|
+
this.lang.next(lang);
|
|
79
|
+
this.events.next({
|
|
80
|
+
type: 'langChanged',
|
|
81
|
+
payload: getEventPayload(lang),
|
|
82
|
+
});
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
setAvailableLangs(langs) {
|
|
86
|
+
this.availableLangs = langs;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Gets the available languages.
|
|
90
|
+
*
|
|
91
|
+
* @returns
|
|
92
|
+
* An array of the available languages. Can be either a `string[]` or a `{ id: string; label: string }[]`
|
|
93
|
+
* depending on how the available languages are set in your module.
|
|
94
|
+
*/
|
|
95
|
+
getAvailableLangs() {
|
|
96
|
+
return this.availableLangs;
|
|
97
|
+
}
|
|
98
|
+
load(path, options = {}) {
|
|
99
|
+
const cached = this.cache.get(path);
|
|
100
|
+
if (cached) {
|
|
101
|
+
return cached;
|
|
102
|
+
}
|
|
103
|
+
let loadTranslation;
|
|
104
|
+
const isScope = this._isLangScoped(path);
|
|
105
|
+
let scope;
|
|
106
|
+
if (isScope) {
|
|
107
|
+
scope = getScopeFromLang(path);
|
|
108
|
+
}
|
|
109
|
+
const loadersOptions = {
|
|
110
|
+
path,
|
|
111
|
+
mainLoader: this.loader,
|
|
112
|
+
inlineLoader: options.inlineLoader,
|
|
113
|
+
data: isScope ? { scope: scope } : undefined,
|
|
114
|
+
};
|
|
115
|
+
if (this.useFallbackTranslation(path)) {
|
|
116
|
+
// if the path is scope the fallback should be `scope/fallbackLang`;
|
|
117
|
+
const fallback = isScope
|
|
118
|
+
? `${scope}/${this.firstFallbackLang}`
|
|
119
|
+
: this.firstFallbackLang;
|
|
120
|
+
const loaders = getFallbacksLoaders({
|
|
121
|
+
...loadersOptions,
|
|
122
|
+
fallbackPath: fallback,
|
|
123
|
+
});
|
|
124
|
+
loadTranslation = forkJoin(loaders);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
const loader = resolveLoader(loadersOptions);
|
|
128
|
+
loadTranslation = from(loader);
|
|
129
|
+
}
|
|
130
|
+
const load$ = loadTranslation.pipe(retry(this.config.failedRetries), tap((translation) => {
|
|
131
|
+
if (Array.isArray(translation)) {
|
|
132
|
+
translation.forEach((t) => {
|
|
133
|
+
this.handleSuccess(t.lang, t.translation);
|
|
134
|
+
// Save the fallback in cache so we'll not create a redundant request
|
|
135
|
+
if (t.lang !== path) {
|
|
136
|
+
this.cache.set(t.lang, of({}));
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
this.handleSuccess(path, translation);
|
|
142
|
+
}), catchError((error) => {
|
|
143
|
+
if (!this.config.prodMode) {
|
|
144
|
+
console.error(`Error while trying to load "${path}"`, error);
|
|
145
|
+
}
|
|
146
|
+
return this.handleFailure(path, options);
|
|
147
|
+
}), shareReplay(1));
|
|
148
|
+
this.cache.set(path, load$);
|
|
149
|
+
return load$;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Gets the instant translated value of a key
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
*
|
|
156
|
+
* translate<string>('hello')
|
|
157
|
+
* translate('hello', { value: 'value' })
|
|
158
|
+
* translate<string[]>(['hello', 'key'])
|
|
159
|
+
* translate('hello', { }, 'en')
|
|
160
|
+
* translate('scope.someKey', { }, 'en')
|
|
161
|
+
*/
|
|
162
|
+
translate(key, params = {}, lang = this.getActiveLang()) {
|
|
163
|
+
if (!key)
|
|
164
|
+
return key;
|
|
165
|
+
const { scope, resolveLang } = this.resolveLangAndScope(lang);
|
|
166
|
+
if (Array.isArray(key)) {
|
|
167
|
+
return key.map((k) => this.translate(scope ? `${scope}.${k}` : k, params, resolveLang));
|
|
168
|
+
}
|
|
169
|
+
key = scope ? `${scope}.${key}` : key;
|
|
170
|
+
const translation = this.getTranslation(resolveLang);
|
|
171
|
+
const value = translation[key];
|
|
172
|
+
if (!value) {
|
|
173
|
+
return this._handleMissingKey(key, value, params);
|
|
174
|
+
}
|
|
175
|
+
return this.parser.transpile({
|
|
176
|
+
value, params, translation, key
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Gets the translated value of a key as observable
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
*
|
|
184
|
+
* selectTranslate<string>('hello').subscribe(value => ...)
|
|
185
|
+
* selectTranslate<string>('hello', {}, 'es').subscribe(value => ...)
|
|
186
|
+
* selectTranslate<string>('hello', {}, 'todos').subscribe(value => ...)
|
|
187
|
+
* selectTranslate<string>('hello', {}, { scope: 'todos' }).subscribe(value => ...)
|
|
188
|
+
*
|
|
189
|
+
*/
|
|
190
|
+
selectTranslate(key, params, lang, _isObject = false) {
|
|
191
|
+
let inlineLoader;
|
|
192
|
+
const load = (lang, options) => this.load(lang, options).pipe(map(() => _isObject
|
|
193
|
+
? this.translateObject(key, params, lang)
|
|
194
|
+
: this.translate(key, params, lang)));
|
|
195
|
+
if (isNil(lang)) {
|
|
196
|
+
return this.langChanges$.pipe(switchMap((lang) => load(lang)));
|
|
197
|
+
}
|
|
198
|
+
if (isScopeArray(lang) || isScopeObject(lang)) {
|
|
199
|
+
// it's a scope object.
|
|
200
|
+
const providerScope = Array.isArray(lang) ? lang[0] : lang;
|
|
201
|
+
lang = providerScope.scope;
|
|
202
|
+
inlineLoader = resolveInlineLoader(providerScope, providerScope.scope);
|
|
203
|
+
}
|
|
204
|
+
lang = lang;
|
|
205
|
+
if (this.isLang(lang) || this.isScopeWithLang(lang)) {
|
|
206
|
+
return load(lang);
|
|
207
|
+
}
|
|
208
|
+
// it's a scope
|
|
209
|
+
const scope = lang;
|
|
210
|
+
return this.langChanges$.pipe(switchMap((lang) => load(`${scope}/${lang}`, { inlineLoader })));
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Whether the scope with lang
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
*
|
|
217
|
+
* todos/en => true
|
|
218
|
+
* todos => false
|
|
219
|
+
*/
|
|
220
|
+
isScopeWithLang(lang) {
|
|
221
|
+
return this.isLang(getLangFromScope(lang));
|
|
222
|
+
}
|
|
223
|
+
translateObject(key, params = {}, lang = this.getActiveLang()) {
|
|
224
|
+
if (isString(key) || Array.isArray(key)) {
|
|
225
|
+
const { resolveLang, scope } = this.resolveLangAndScope(lang);
|
|
226
|
+
if (Array.isArray(key)) {
|
|
227
|
+
return key.map((k) => this.translateObject(scope ? `${scope}.${k}` : k, params, resolveLang));
|
|
228
|
+
}
|
|
229
|
+
const translation = this.getTranslation(resolveLang);
|
|
230
|
+
key = scope ? `${scope}.${key}` : key;
|
|
231
|
+
const value = unflatten(this.getObjectByKey(translation, key));
|
|
232
|
+
/* If an empty object was returned we want to try and translate the key as a string and not an object */
|
|
233
|
+
return isEmpty(value)
|
|
234
|
+
? this.translate(key, params, lang)
|
|
235
|
+
: this.parser.transpile({ value, params: params, translation, key });
|
|
236
|
+
}
|
|
237
|
+
const translations = [];
|
|
238
|
+
for (const [_key, _params] of this.getEntries(key)) {
|
|
239
|
+
translations.push(this.translateObject(_key, _params, lang));
|
|
240
|
+
}
|
|
241
|
+
return translations;
|
|
242
|
+
}
|
|
243
|
+
selectTranslateObject(key, params, lang) {
|
|
244
|
+
if (isString(key) || Array.isArray(key)) {
|
|
245
|
+
return this.selectTranslate(key, params, lang, true);
|
|
246
|
+
}
|
|
247
|
+
const [[firstKey, firstParams], ...rest] = this.getEntries(key);
|
|
248
|
+
/* In order to avoid subscribing multiple times to the load language event by calling selectTranslateObject for each pair,
|
|
249
|
+
* we listen to when the first key has been translated (the language is loaded) and translate the rest synchronously */
|
|
250
|
+
return this.selectTranslateObject(firstKey, firstParams, lang).pipe(map((value) => {
|
|
251
|
+
const translations = [value];
|
|
252
|
+
for (const [_key, _params] of rest) {
|
|
253
|
+
translations.push(this.translateObject(_key, _params, lang));
|
|
254
|
+
}
|
|
255
|
+
return translations;
|
|
256
|
+
}));
|
|
257
|
+
}
|
|
258
|
+
getTranslation(langOrScope) {
|
|
259
|
+
if (langOrScope) {
|
|
260
|
+
if (this.isLang(langOrScope)) {
|
|
261
|
+
return this.translations.get(langOrScope) || {};
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
// This is a scope, build the scope value from the translation object
|
|
265
|
+
const { scope, resolveLang } = this.resolveLangAndScope(langOrScope);
|
|
266
|
+
const translation = this.translations.get(resolveLang) || {};
|
|
267
|
+
return this.getObjectByKey(translation, scope);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return this.translations;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Gets an object of translations for a given language
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
*
|
|
277
|
+
* selectTranslation().subscribe() - will return the current lang translation
|
|
278
|
+
* selectTranslation('es').subscribe()
|
|
279
|
+
* selectTranslation('admin-page').subscribe() - will return the current lang scope translation
|
|
280
|
+
* selectTranslation('admin-page/es').subscribe()
|
|
281
|
+
*/
|
|
282
|
+
selectTranslation(lang) {
|
|
283
|
+
let language$ = this.langChanges$;
|
|
284
|
+
if (lang) {
|
|
285
|
+
const scopeLangSpecified = getLangFromScope(lang) !== lang;
|
|
286
|
+
if (this.isLang(lang) || scopeLangSpecified) {
|
|
287
|
+
language$ = of(lang);
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
language$ = this.langChanges$.pipe(map((currentLang) => `${lang}/${currentLang}`));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return language$.pipe(switchMap((language) => this.load(language).pipe(map(() => this.getTranslation(language)))));
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Sets or merge a given translation object to current lang
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
*
|
|
300
|
+
* setTranslation({ ... })
|
|
301
|
+
* setTranslation({ ... }, 'en')
|
|
302
|
+
* setTranslation({ ... }, 'es', { merge: false } )
|
|
303
|
+
* setTranslation({ ... }, 'todos/en', { merge: false } )
|
|
304
|
+
*/
|
|
305
|
+
setTranslation(translation, lang = this.getActiveLang(), options = {}) {
|
|
306
|
+
const defaults = { merge: true, emitChange: true };
|
|
307
|
+
const mergedOptions = { ...defaults, ...options };
|
|
308
|
+
const scope = getScopeFromLang(lang);
|
|
309
|
+
/**
|
|
310
|
+
* If this isn't a scope we use the whole translation as is
|
|
311
|
+
* otherwise we need to flat the scope and use it
|
|
312
|
+
*/
|
|
313
|
+
let flattenScopeOrTranslation = translation;
|
|
314
|
+
// Merged the scoped language into the active language
|
|
315
|
+
if (scope) {
|
|
316
|
+
const key = this.getMappedScope(scope);
|
|
317
|
+
flattenScopeOrTranslation = flatten({ [key]: translation });
|
|
318
|
+
}
|
|
319
|
+
const currentLang = scope ? getLangFromScope(lang) : lang;
|
|
320
|
+
const mergedTranslation = {
|
|
321
|
+
...(mergedOptions.merge && this.getTranslation(currentLang)),
|
|
322
|
+
...flattenScopeOrTranslation,
|
|
323
|
+
};
|
|
324
|
+
const flattenTranslation = this.config.flatten.aot
|
|
325
|
+
? mergedTranslation
|
|
326
|
+
: flatten(mergedTranslation);
|
|
327
|
+
const withHook = this.interceptor.preSaveTranslation(flattenTranslation, currentLang);
|
|
328
|
+
this.translations.set(currentLang, withHook);
|
|
329
|
+
mergedOptions.emitChange && this.setActiveLang(this.getActiveLang());
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Sets translation key with given value
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
*
|
|
336
|
+
* setTranslationKey('key', 'value')
|
|
337
|
+
* setTranslationKey('key.nested', 'value')
|
|
338
|
+
* setTranslationKey('key.nested', 'value', 'en')
|
|
339
|
+
* setTranslationKey('key.nested', 'value', 'en', { emitChange: false } )
|
|
340
|
+
*/
|
|
341
|
+
setTranslationKey(key, value, options = {}) {
|
|
342
|
+
const lang = options.lang || this.getActiveLang();
|
|
343
|
+
const withHook = this.interceptor.preSaveTranslationKey(key, value, lang);
|
|
344
|
+
const newValue = {
|
|
345
|
+
[key]: withHook,
|
|
346
|
+
};
|
|
347
|
+
this.setTranslation(newValue, lang, { ...options, merge: true });
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Sets the fallback lang for the currently active language
|
|
351
|
+
* @param fallbackLang
|
|
352
|
+
*/
|
|
353
|
+
setFallbackLangForMissingTranslation({ fallbackLang, }) {
|
|
354
|
+
const lang = Array.isArray(fallbackLang) ? fallbackLang[0] : fallbackLang;
|
|
355
|
+
if (fallbackLang && this.useFallbackTranslation(lang)) {
|
|
356
|
+
this.firstFallbackLang = lang;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* @internal
|
|
361
|
+
*/
|
|
362
|
+
_handleMissingKey(key, value, params) {
|
|
363
|
+
if (this.config.missingHandler.allowEmpty && value === '') {
|
|
364
|
+
return '';
|
|
365
|
+
}
|
|
366
|
+
if (!this.isResolvedMissingOnce && this.useFallbackTranslation()) {
|
|
367
|
+
// We need to set it to true to prevent a loop
|
|
368
|
+
this.isResolvedMissingOnce = true;
|
|
369
|
+
const fallbackValue = this.translate(key, params, this.firstFallbackLang);
|
|
370
|
+
this.isResolvedMissingOnce = false;
|
|
371
|
+
return fallbackValue;
|
|
372
|
+
}
|
|
373
|
+
return this.missingHandler.handle(key, this.getMissingHandlerData(), params);
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* @internal
|
|
377
|
+
*/
|
|
378
|
+
_isLangScoped(lang) {
|
|
379
|
+
return this.getAvailableLangsIds().indexOf(lang) === -1;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Checks if a given string is one of the specified available languages.
|
|
383
|
+
* @returns
|
|
384
|
+
* True if the given string is an available language.
|
|
385
|
+
* False if the given string is not an available language.
|
|
386
|
+
*/
|
|
387
|
+
isLang(lang) {
|
|
388
|
+
return this.getAvailableLangsIds().indexOf(lang) !== -1;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* @internal
|
|
392
|
+
*
|
|
393
|
+
* We always want to make sure the global lang is loaded
|
|
394
|
+
* before loading the scope since you can access both via the pipe/directive.
|
|
395
|
+
*/
|
|
396
|
+
_loadDependencies(path, inlineLoader) {
|
|
397
|
+
const mainLang = getLangFromScope(path);
|
|
398
|
+
if (this._isLangScoped(path) && !this.isLoadedTranslation(mainLang)) {
|
|
399
|
+
return combineLatest([
|
|
400
|
+
this.load(mainLang),
|
|
401
|
+
this.load(path, { inlineLoader }),
|
|
402
|
+
]);
|
|
403
|
+
}
|
|
404
|
+
return this.load(path, { inlineLoader });
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* @internal
|
|
408
|
+
*/
|
|
409
|
+
_completeScopeWithLang(langOrScope) {
|
|
410
|
+
if (this._isLangScoped(langOrScope) &&
|
|
411
|
+
!this.isLang(getLangFromScope(langOrScope))) {
|
|
412
|
+
return `${langOrScope}/${this.getActiveLang()}`;
|
|
413
|
+
}
|
|
414
|
+
return langOrScope;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* @internal
|
|
418
|
+
*/
|
|
419
|
+
_setScopeAlias(scope, alias) {
|
|
420
|
+
if (!this.config.scopeMapping) {
|
|
421
|
+
this.config.scopeMapping = {};
|
|
422
|
+
}
|
|
423
|
+
this.config.scopeMapping[scope] = alias;
|
|
424
|
+
}
|
|
425
|
+
ngOnDestroy() {
|
|
426
|
+
if (this.subscription) {
|
|
427
|
+
this.subscription.unsubscribe();
|
|
428
|
+
// Caretaker note: it's important to clean up references to subscriptions since they save the `next`
|
|
429
|
+
// callback within its `destination` property, preventing classes from being GC'd.
|
|
430
|
+
this.subscription = null;
|
|
431
|
+
}
|
|
432
|
+
// Caretaker note: since this is the root provider, it'll be destroyed when the `NgModuleRef.destroy()` is run.
|
|
433
|
+
// Cached values capture `this`, thus leading to a circular reference and preventing the `TranslocoService` from
|
|
434
|
+
// being GC'd. This would lead to a memory leak when server-side rendering is used since the service is created
|
|
435
|
+
// and destroyed per each HTTP request, but any service is not getting GC'd.
|
|
436
|
+
this.cache.clear();
|
|
437
|
+
}
|
|
438
|
+
isLoadedTranslation(lang) {
|
|
439
|
+
return size(this.getTranslation(lang));
|
|
440
|
+
}
|
|
441
|
+
getAvailableLangsIds() {
|
|
442
|
+
const first = this.getAvailableLangs()[0];
|
|
443
|
+
if (isString(first)) {
|
|
444
|
+
return this.getAvailableLangs();
|
|
445
|
+
}
|
|
446
|
+
return this.getAvailableLangs().map((l) => l.id);
|
|
447
|
+
}
|
|
448
|
+
getMissingHandlerData() {
|
|
449
|
+
return {
|
|
450
|
+
...this.config,
|
|
451
|
+
activeLang: this.getActiveLang(),
|
|
452
|
+
availableLangs: this.availableLangs,
|
|
453
|
+
defaultLang: this.defaultLang,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Use a fallback translation set for missing keys of the primary language
|
|
458
|
+
* This is unrelated to the fallback language (which changes the active language)
|
|
459
|
+
*/
|
|
460
|
+
useFallbackTranslation(lang) {
|
|
461
|
+
return (this.config.missingHandler.useFallbackTranslation &&
|
|
462
|
+
lang !== this.firstFallbackLang);
|
|
463
|
+
}
|
|
464
|
+
handleSuccess(lang, translation) {
|
|
465
|
+
this.setTranslation(translation, lang, { emitChange: false });
|
|
466
|
+
this.events.next({
|
|
467
|
+
wasFailure: !!this.failedLangs.size,
|
|
468
|
+
type: 'translationLoadSuccess',
|
|
469
|
+
payload: getEventPayload(lang),
|
|
470
|
+
});
|
|
471
|
+
this.failedLangs.forEach((l) => this.cache.delete(l));
|
|
472
|
+
this.failedLangs.clear();
|
|
473
|
+
}
|
|
474
|
+
handleFailure(lang, loadOptions) {
|
|
475
|
+
// When starting to load a first choice language, initialize
|
|
476
|
+
// the failed counter and resolve the fallback langs.
|
|
477
|
+
if (isNil(loadOptions.failedCounter)) {
|
|
478
|
+
loadOptions.failedCounter = 0;
|
|
479
|
+
if (!loadOptions.fallbackLangs) {
|
|
480
|
+
loadOptions.fallbackLangs = this.fallbackStrategy.getNextLangs(lang);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const splitted = lang.split('/');
|
|
484
|
+
const fallbacks = loadOptions.fallbackLangs;
|
|
485
|
+
const nextLang = fallbacks[loadOptions.failedCounter];
|
|
486
|
+
this.failedLangs.add(lang);
|
|
487
|
+
// This handles the case where a loaded fallback language is requested again
|
|
488
|
+
if (this.cache.has(nextLang)) {
|
|
489
|
+
this.handleSuccess(nextLang, this.getTranslation(nextLang));
|
|
490
|
+
return EMPTY;
|
|
491
|
+
}
|
|
492
|
+
const isFallbackLang = nextLang === splitted[splitted.length - 1];
|
|
493
|
+
if (!nextLang || isFallbackLang) {
|
|
494
|
+
let msg = `Unable to load translation and all the fallback languages`;
|
|
495
|
+
if (splitted.length > 1) {
|
|
496
|
+
msg += `, did you misspelled the scope name?`;
|
|
497
|
+
}
|
|
498
|
+
throw new Error(msg);
|
|
499
|
+
}
|
|
500
|
+
let resolveLang = nextLang;
|
|
501
|
+
// if it's scoped lang
|
|
502
|
+
if (splitted.length > 1) {
|
|
503
|
+
// We need to resolve it to:
|
|
504
|
+
// todos/langNotExists => todos/nextLang
|
|
505
|
+
splitted[splitted.length - 1] = nextLang;
|
|
506
|
+
resolveLang = splitted.join('/');
|
|
507
|
+
}
|
|
508
|
+
loadOptions.failedCounter++;
|
|
509
|
+
this.events.next({
|
|
510
|
+
type: 'translationLoadFailure',
|
|
511
|
+
payload: getEventPayload(lang),
|
|
512
|
+
});
|
|
513
|
+
return this.load(resolveLang, loadOptions);
|
|
514
|
+
}
|
|
515
|
+
getMappedScope(scope) {
|
|
516
|
+
const { scopeMapping = {} } = this.config;
|
|
517
|
+
return scopeMapping[scope] || toCamelCase(scope);
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* If lang is scope we need to check the following cases:
|
|
521
|
+
* todos/es => in this case we should take `es` as lang
|
|
522
|
+
* todos => in this case we should set the active lang as lang
|
|
523
|
+
*/
|
|
524
|
+
resolveLangAndScope(lang) {
|
|
525
|
+
let resolveLang = lang;
|
|
526
|
+
let scope;
|
|
527
|
+
if (this._isLangScoped(lang)) {
|
|
528
|
+
// en for example
|
|
529
|
+
const langFromScope = getLangFromScope(lang);
|
|
530
|
+
// en is lang
|
|
531
|
+
const hasLang = this.isLang(langFromScope);
|
|
532
|
+
// take en
|
|
533
|
+
resolveLang = hasLang ? langFromScope : this.getActiveLang();
|
|
534
|
+
// find the scope
|
|
535
|
+
scope = this.getMappedScope(hasLang ? getScopeFromLang(lang) : lang);
|
|
536
|
+
}
|
|
537
|
+
return { scope, resolveLang };
|
|
538
|
+
}
|
|
539
|
+
getObjectByKey(translation, key) {
|
|
540
|
+
const result = {};
|
|
541
|
+
const prefix = `${key}.`;
|
|
542
|
+
for (const currentKey in translation) {
|
|
543
|
+
if (currentKey.startsWith(prefix)) {
|
|
544
|
+
result[currentKey.replace(prefix, '')] = translation[currentKey];
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return result;
|
|
548
|
+
}
|
|
549
|
+
getEntries(key) {
|
|
550
|
+
return key instanceof Map ? key.entries() : Object.entries(key);
|
|
551
|
+
}
|
|
552
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: TranslocoService, deps: [{ token: TRANSLOCO_LOADER, optional: true }, { token: TRANSLOCO_TRANSPILER }, { token: TRANSLOCO_MISSING_HANDLER }, { token: TRANSLOCO_INTERCEPTOR }, { token: TRANSLOCO_CONFIG }, { token: TRANSLOCO_FALLBACK_STRATEGY }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
553
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: TranslocoService, providedIn: 'root' });
|
|
554
|
+
}
|
|
555
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: TranslocoService, decorators: [{
|
|
556
|
+
type: Injectable,
|
|
557
|
+
args: [{ providedIn: 'root' }]
|
|
558
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
559
|
+
type: Optional
|
|
560
|
+
}, {
|
|
561
|
+
type: Inject,
|
|
562
|
+
args: [TRANSLOCO_LOADER]
|
|
563
|
+
}] }, { type: undefined, decorators: [{
|
|
564
|
+
type: Inject,
|
|
565
|
+
args: [TRANSLOCO_TRANSPILER]
|
|
566
|
+
}] }, { type: undefined, decorators: [{
|
|
567
|
+
type: Inject,
|
|
568
|
+
args: [TRANSLOCO_MISSING_HANDLER]
|
|
569
|
+
}] }, { type: undefined, decorators: [{
|
|
570
|
+
type: Inject,
|
|
571
|
+
args: [TRANSLOCO_INTERCEPTOR]
|
|
572
|
+
}] }, { type: undefined, decorators: [{
|
|
573
|
+
type: Inject,
|
|
574
|
+
args: [TRANSLOCO_CONFIG]
|
|
575
|
+
}] }, { type: undefined, decorators: [{
|
|
576
|
+
type: Inject,
|
|
577
|
+
args: [TRANSLOCO_FALLBACK_STRATEGY]
|
|
578
|
+
}] }] });
|
|
579
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsb2NvLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWJzL3RyYW5zbG9jby9zcmMvbGliL3RyYW5zbG9jby5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFhLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN4RSxPQUFPLEVBQ0wsZUFBZSxFQUNmLFVBQVUsRUFDVixhQUFhLEVBQ2IsS0FBSyxFQUNMLFFBQVEsRUFDUixJQUFJLEVBQ0osR0FBRyxFQUVILEVBQUUsRUFDRixLQUFLLEVBQ0wsV0FBVyxFQUNYLE9BQU8sRUFFUCxTQUFTLEVBQ1QsR0FBRyxHQUNKLE1BQU0sTUFBTSxDQUFDO0FBRWQsT0FBTyxFQUNMLGFBQWEsRUFDYixnQkFBZ0IsR0FFakIsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQ0wsb0JBQW9CLEdBRXJCLE1BQU0sd0JBQXdCLENBQUM7QUFjaEMsT0FBTyxFQUNMLE9BQU8sRUFDUCxPQUFPLEVBQ1AsS0FBSyxFQUNMLFlBQVksRUFDWixhQUFhLEVBQ2IsUUFBUSxFQUNSLElBQUksRUFDSixXQUFXLEVBQ1gsU0FBUyxHQUNWLE1BQU0sV0FBVyxDQUFDO0FBQ25CLE9BQU8sRUFBRSxnQkFBZ0IsRUFBbUIsTUFBTSxvQkFBb0IsQ0FBQztBQUN2RSxPQUFPLEVBQ0wseUJBQXlCLEdBRzFCLE1BQU0sNkJBQTZCLENBQUM7QUFDckMsT0FBTyxFQUNMLHFCQUFxQixHQUV0QixNQUFNLHlCQUF5QixDQUFDO0FBQ2pDLE9BQU8sRUFDTCwyQkFBMkIsR0FFNUIsTUFBTSwrQkFBK0IsQ0FBQztBQUN2QyxPQUFPLEVBQ0wsZUFBZSxFQUNmLGdCQUFnQixFQUNoQixnQkFBZ0IsRUFDaEIsbUJBQW1CLEdBQ3BCLE1BQU0sVUFBVSxDQUFDO0FBQ2xCLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHlCQUF5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RyxZQUFZLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2xFLENBQUM7dUdBdnVCVSxnQkFBZ0Isa0JBb0JMLGdCQUFnQiw2QkFDNUIsb0JBQW9CLGFBQ3BCLHlCQUF5QixhQUV6QixxQkFBcUIsYUFDckIsZ0JBQWdCLGFBQ2hCLDJCQUEyQjsyR0ExQjFCLGdCQUFnQixjQURILE1BQU07OzJGQUNuQixnQkFBZ0I7a0JBRDVCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFOzswQkFxQjdCLFFBQVE7OzBCQUFJLE1BQU07MkJBQUMsZ0JBQWdCOzswQkFDbkMsTUFBTTsyQkFBQyxvQkFBb0I7OzBCQUMzQixNQUFNOzJCQUFDLHlCQUF5Qjs7MEJBRWhDLE1BQU07MkJBQUMscUJBQXFCOzswQkFDNUIsTUFBTTsyQkFBQyxnQkFBZ0I7OzBCQUN2QixNQUFNOzJCQUFDLDJCQUEyQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSwgT25EZXN0cm95LCBPcHRpb25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgQmVoYXZpb3JTdWJqZWN0LFxuICBjYXRjaEVycm9yLFxuICBjb21iaW5lTGF0ZXN0LFxuICBFTVBUWSxcbiAgZm9ya0pvaW4sXG4gIGZyb20sXG4gIG1hcCxcbiAgT2JzZXJ2YWJsZSxcbiAgb2YsXG4gIHJldHJ5LFxuICBzaGFyZVJlcGxheSxcbiAgU3ViamVjdCxcbiAgU3Vic2NyaXB0aW9uLFxuICBzd2l0Y2hNYXAsXG4gIHRhcCxcbn0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB7XG4gIERlZmF1bHRMb2FkZXIsXG4gIFRSQU5TTE9DT19MT0FERVIsXG4gIFRyYW5zbG9jb0xvYWRlcixcbn0gZnJvbSAnLi90cmFuc2xvY28ubG9hZGVyJztcbmltcG9ydCB7XG4gIFRSQU5TTE9DT19UUkFOU1BJTEVSLFxuICBUcmFuc2xvY29UcmFuc3BpbGVyLFxufSBmcm9tICcuL3RyYW5zbG9jby50cmFuc3BpbGVyJztcbmltcG9ydCB7XG4gIEF2YWlsYWJsZUxhbmdzLFxuICBIYXNoTWFwLFxuICBJbmxpbmVMb2FkZXIsXG4gIExhbmdEZWZpbml0aW9uLFxuICBMb2FkT3B0aW9ucyxcbiAgU2V0VHJhbnNsYXRpb25PcHRpb25zLFxuICBUcmFuc2xhdGVPYmplY3RQYXJhbXMsXG4gIFRyYW5zbGF0ZVBhcmFtcyxcbiAgVHJhbnNsYXRpb24sXG4gIFRyYW5zbG9jb0V2ZW50cyxcbiAgVHJhbnNsb2NvU2NvcGUsXG59IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHtcbiAgZmxhdHRlbixcbiAgaXNFbXB0eSxcbiAgaXNOaWwsXG4gIGlzU2NvcGVBcnJheSxcbiAgaXNTY29wZU9iamVjdCxcbiAgaXNTdHJpbmcsXG4gIHNpemUsXG4gIHRvQ2FtZWxDYXNlLFxuICB1bmZsYXR0ZW4sXG59IGZyb20gJy4vaGVscGVycyc7XG5pbXBvcnQgeyBUUkFOU0xPQ09fQ09ORklHLCBUcmFuc2xvY29Db25maWcgfSBmcm9tICcuL3RyYW5zbG9jby5jb25maWcnO1xuaW1wb3J0IHtcbiAgVFJBTlNMT0NPX01JU1NJTkdfSEFORExFUixcbiAgVHJhbnNsb2NvTWlzc2luZ0hhbmRsZXIsXG4gIFRyYW5zbG9jb01pc3NpbmdIYW5kbGVyRGF0YSxcbn0gZnJvbSAnLi90cmFuc2xvY28tbWlzc2luZy1oYW5kbGVyJztcbmltcG9ydCB7XG4gIFRSQU5TTE9DT19JTlRFUkNFUFRPUixcbiAgVHJhbnNsb2NvSW50ZXJjZXB0b3IsXG59IGZyb20gJy4vdHJhbnNsb2NvLmludGVyY2VwdG9yJztcbmltcG9ydCB7XG4gIFRSQU5TTE9DT19GQUxMQkFDS19TVFJBVEVHWSxcbiAgVHJhbnNsb2NvRmFsbGJhY2tTdHJhdGVneSxcbn0gZnJvbSAnLi90cmFuc2xvY28tZmFsbGJhY2stc3RyYXRlZ3knO1xuaW1wb3J0IHtcbiAgZ2V0RXZlbnRQYXlsb2FkLFxuICBnZXRMYW5nRnJvbVNjb3BlLFxuICBnZXRTY29wZUZyb21MYW5nLFxuICByZXNvbHZlSW5saW5lTG9hZGVyLFxufSBmcm9tICcuL3NoYXJlZCc7XG5pbXBvcnQgeyBnZXRGYWxsYmFja3NMb2FkZXJzIH0gZnJvbSAnLi9nZXQtZmFsbGJhY2tzLWxvYWRlcnMnO1xuaW1wb3J0IHsgcmVzb2x2ZUxvYWRlciB9IGZyb20gJy4vcmVzb2x2ZS1sb2FkZXInO1xuXG5sZXQgc2VydmljZTogVHJhbnNsb2NvU2VydmljZTtcblxuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zbGF0ZTxUID0gc3RyaW5nPihcbiAga2V5OiBUcmFuc2xhdGVQYXJhbXMsXG4gIHBhcmFtczogSGFzaE1hcCA9IHt9LFxuICBsYW5nPzogc3RyaW5nXG4pOiBUIHtcbiAgcmV0dXJuIHNlcnZpY2UudHJhbnNsYXRlPFQ+KGtleSwgcGFyYW1zLCBsYW5nKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zbGF0ZU9iamVjdDxUPihcbiAga2V5OiBUcmFuc2xhdGVQYXJhbXMsXG4gIHBhcmFtczogSGFzaE1hcCA9IHt9LFxuICBsYW5nPzogc3RyaW5nXG4pOiBUIHwgVFtdIHtcbiAgcmV0dXJuIHNlcnZpY2UudHJhbnNsYXRlT2JqZWN0PFQ+KGtleSwgcGFyYW1zLCBsYW5nKTtcbn1cblxuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBUcmFuc2xvY29TZXJ2aWNlIGltcGxlbWVudHMgT25EZXN0cm95IHtcbiAgbGFuZ0NoYW5nZXMkOiBPYnNlcnZhYmxlPHN0cmluZz47XG5cbiAgcHJpdmF0ZSBzdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbiB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHRyYW5zbGF0aW9ucyA9IG5ldyBNYXA8c3RyaW5nLCBUcmFuc2xhdGlvbj4oKTtcbiAgcHJpdmF0ZSBjYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCBPYnNlcnZhYmxlPFRyYW5zbGF0aW9uPj4oKTtcbiAgcHJpdmF0ZSBmaXJzdEZhbGxiYWNrTGFuZzogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIGRlZmF1bHRMYW5nID0gJyc7XG4gIHByaXZhdGUgYXZhaWxhYmxlTGFuZ3M6IEF2YWlsYWJsZUxhbmdzID0gW107XG4gIHByaXZhdGUgaXNSZXNvbHZlZE1pc3NpbmdPbmNlID0gZmFsc2U7XG4gIHByaXZhdGUgbGFuZzogQmVoYXZpb3JTdWJqZWN0PHN0cmluZz47XG4gIHByaXZhdGUgZmFpbGVkTGFuZ3MgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgcHJpdmF0ZSBldmVudHMgPSBuZXcgU3ViamVjdDxUcmFuc2xvY29FdmVudHM+KCk7XG5cbiAgZXZlbnRzJCA9IHRoaXMuZXZlbnRzLmFzT2JzZXJ2YWJsZSgpO1xuICByZWFkb25seSBjb25maWc6IFRyYW5zbG9jb0NvbmZpZyAmIHtcbiAgICBzY29wZU1hcHBpbmc/OiBIYXNoTWFwPHN0cmluZz47XG4gIH07XG5cbiAgY29uc3RydWN0b3IoXG4gICAgQE9wdGlvbmFsKCkgQEluamVjdChUUkFOU0xPQ09fTE9BREVSKSBwcml2YXRlIGxvYWRlcjogVHJhbnNsb2NvTG9hZGVyLFxuICAgIEBJbmplY3QoVFJBTlNMT0NPX1RSQU5TUElMRVIpIHByaXZhdGUgcGFyc2VyOiBUcmFuc2xvY29UcmFuc3BpbGVyLFxuICAgIEBJbmplY3QoVFJBTlNMT0NPX01JU1NJTkdfSEFORExFUilcbiAgICBwcml2YXRlIG1pc3NpbmdIYW5kbGVyOiBUcmFuc2xvY29NaXNzaW5nSGFuZGxlcixcbiAgICBASW5qZWN0KFRSQU5TTE9DT19JTlRFUkNFUFRPUikgcHJpdmF0ZSBpbnRlcmNlcHRvcjogVHJhbnNsb2NvSW50ZXJjZXB0b3IsXG4gICAgQEluamVjdChUUkFOU0xPQ09fQ09ORklHKSB1c2VyQ29uZmlnOiBUcmFuc2xvY29Db25maWcsXG4gICAgQEluamVjdChUUkFOU0xPQ09fRkFMTEJBQ0tfU1RSQVRFR1kpXG4gICAgcHJpdmF0ZSBmYWxsYmFja1N0cmF0ZWd5OiBUcmFuc2xvY29GYWxsYmFja1N0cmF0ZWd5XG4gICkge1xuICAgIGlmICghdGhpcy5sb2FkZXIpIHtcbiAgICAgIHRoaXMubG9hZGVyID0gbmV3IERlZmF1bHRMb2FkZXIodGhpcy50cmFuc2xhdGlvbnMpO1xuICAgIH1cbiAgICBzZXJ2aWNlID0gdGhpcztcbiAgICB0aGlzLmNvbmZpZyA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkodXNlckNvbmZpZykpO1xuXG4gICAgdGhpcy5zZXRBdmFpbGFibGVMYW5ncyh0aGlzLmNvbmZpZy5hdmFpbGFibGVMYW5ncyB8fCBbXSk7XG4gICAgdGhpcy5zZXRGYWxsYmFja0xhbmdGb3JNaXNzaW5nVHJhbnNsYXRpb24odGhpcy5jb25maWcpO1xuICAgIHRoaXMuc2V0RGVmYXVsdExhbmcodGhpcy5jb25maWcuZGVmYXVsdExhbmcpO1xuICAgIHRoaXMubGFuZyA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPih0aGlzLmdldERlZmF1bHRMYW5nKCkpO1xuICAgIC8vIERvbid0IHVzZSBkaXN0aW5jdFVudGlsQ2hhbmdlZCBhcyB3ZSBuZWVkIHRoZSBhYmlsaXR5IHRvIHVwZGF0ZVxuICAgIC8vIHRoZSB2YWx1ZSB3aGVuIHVzaW5nIHNldFRyYW5zbGF0aW9uIG9yIHNldFRyYW5zbGF0aW9uS2V5c1xuICAgIHRoaXMubGFuZ0NoYW5nZXMkID0gdGhpcy5sYW5nLmFzT2JzZXJ2YWJsZSgpO1xuXG4gICAgLyoqXG4gICAgICogV2hlbiB3ZSBoYXZlIGEgZmFpbHVyZSwgd2Ugd2FudCB0byBkZWZpbmUgdGhlIG5leHQgbGFuZ3VhZ2UgdGhhdCBzdWNjZWVkZWQgYXMgdGhlIGFjdGl2ZVxuICAgICAqL1xuICAgIHRoaXMuc3Vic2NyaXB0aW9uID0gdGhpcy5ldmVudHMkLnN1YnNjcmliZSgoZSkgPT4ge1xuICAgICAgaWYgKGUudHlwZSA9PT0gJ3RyYW5zbGF0aW9uTG9hZFN1Y2Nlc3MnICYmIGUud2FzRmFpbHVyZSkge1xuICAgICAgICB0aGlzLnNldEFjdGl2ZUxhbmcoZS5wYXlsb2FkLmxhbmdOYW1lKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIGdldERlZmF1bHRMYW5nKCkge1xuICAgIHJldHVybiB0aGlzLmRlZmF1bHRMYW5nO1xuICB9XG5cbiAgc2V0RGVmYXVsdExhbmcobGFuZzogc3RyaW5nKSB7XG4gICAgdGhpcy5kZWZhdWx0TGFuZyA9IGxhbmc7XG4gIH1cblxuICBnZXRBY3RpdmVMYW5nKCkge1xuICAgIHJldHVybiB0aGlzLmxhbmcuZ2V0VmFsdWUoKTtcbiAgfVxuXG4gIHNldEFjdGl2ZUxhbmcobGFuZzogc3RyaW5nKSB7XG4gICAgdGhpcy5wYXJzZXIub25MYW5nQ2hhbmdlZD8uKGxhbmcpO1xuICAgIHRoaXMubGFuZy5uZXh0KGxhbmcpO1xuICAgIHRoaXMuZXZlbnRzLm5leHQoe1xuICAgICAgdHlwZTogJ2xhbmdDaGFuZ2VkJyxcbiAgICAgIHBheWxvYWQ6IGdldEV2ZW50UGF5bG9hZChsYW5nKSxcbiAgICB9KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldEF2YWlsYWJsZUxhbmdzKGxhbmdzOiBBdmFpbGFibGVMYW5ncykge1xuICAgIHRoaXMuYXZhaWxhYmxlTGFuZ3MgPSBsYW5ncztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBhdmFpbGFibGUgbGFuZ3VhZ2VzLlxuICAgKlxuICAgKiBAcmV0dXJuc1xuICAgKiBBbiBhcnJheSBvZiB0aGUgYXZhaWxhYmxlIGxhbmd1YWdlcy4gQ2FuIGJlIGVpdGhlciBhIGBzdHJpbmdbXWAgb3IgYSBgeyBpZDogc3RyaW5nOyBsYWJlbDogc3RyaW5nIH1bXWBcbiAgICogZGVwZW5kaW5nIG9uIGhvdyB0aGUgYXZhaWxhYmxlIGxhbmd1YWdlcyBhcmUgc2V0IGluIHlvdXIgbW9kdWxlLlxuICAgKi9cbiAgZ2V0QXZhaWxhYmxlTGFuZ3MoKSB7XG4gICAgcmV0dXJuIHRoaXMuYXZhaWxhYmxlTGFuZ3M7XG4gIH1cblxuICBsb2FkKHBhdGg6IHN0cmluZywgb3B0aW9uczogTG9hZE9wdGlvbnMgPSB7fSk6IE9ic2VydmFibGU8VHJhbnNsYXRpb24+IHtcbiAgICBjb25zdCBjYWNoZWQgPSB0aGlzLmNhY2hlLmdldChwYXRoKTtcbiAgICBpZiAoY2FjaGVkKSB7XG4gICAgICByZXR1cm4gY2FjaGVkO1xuICAgIH1cblxuICAgIGxldCBsb2FkVHJhbnNsYXRpb246IE9ic2VydmFibGU8XG4gICAgICBUcmFuc2xhdGlvbiB8IHsgdHJhbnNsYXRpb246IFRyYW5zbGF0aW9uOyBsYW5nOiBzdHJpbmcgfVtdXG4gICAgPjtcbiAgICBjb25zdCBpc1Njb3BlID0gdGhpcy5faXNMYW5nU2NvcGVkKHBhdGgpO1xuICAgIGxldCBzY29wZTogc3RyaW5nO1xuICAgIGlmIChpc1Njb3BlKSB7XG4gICAgICBzY29wZSA9IGdldFNjb3BlRnJvbUxhbmcocGF0aCk7XG4gICAgfVxuXG4gICAgY29uc3QgbG9hZGVyc09wdGlvbnMgPSB7XG4gICAgICBwYXRoLFxuICAgICAgbWFpbkxvYWRlcjogdGhpcy5sb2FkZXIsXG4gICAgICBpbmxpbmVMb2FkZXI6IG9wdGlvbnMuaW5saW5lTG9hZGVyLFxuICAgICAgZGF0YTogaXNTY29wZSA/IHsgc2NvcGU6IHNjb3BlISB9IDogdW5kZWZpbmVkLFxuICAgIH07XG5cbiAgICBpZiAodGhpcy51c2VGYWxsYmFja1RyYW5zbGF0aW9uKHBhdGgpKSB7XG4gICAgICAvLyBpZiB0aGUgcGF0aCBpcyBzY29wZSB0aGUgZmFsbGJhY2sgc2hvdWxkIGJlIGBzY29wZS9mYWxsYmFja0xhbmdgO1xuICAgICAgY29uc3QgZmFsbGJhY2sgPSBpc1Njb3BlXG4gICAgICAgID8gYCR7c2NvcGUhfS8ke3RoaXMuZmlyc3RGYWxsYmFja0xhbmd9YFxuICAgICAgICA6IHRoaXMuZmlyc3RGYWxsYmFja0xhbmc7XG5cbiAgICAgIGNvbnN0IGxvYWRlcnMgPSBnZXRGYWxsYmFja3NMb2FkZXJzKHtcbiAgICAgICAgLi4ubG9hZGVyc09wdGlvbnMsXG4gICAgICAgIGZhbGxiYWNrUGF0aDogZmFsbGJhY2shLFxuICAgICAgfSk7XG4gICAgICBsb2FkVHJhbnNsYXRpb24gPSBmb3JrSm9pbihsb2FkZXJzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbG9hZGVyID0gcmVzb2x2ZUxvYWRlcihsb2FkZXJzT3B0aW9ucyk7XG4gICAgICBsb2FkVHJhbnNsYXRpb24gPSBmcm9tKGxvYWRlcik7XG4gICAgfVxuXG4gICAgY29uc3QgbG9hZCQgPSBsb2FkVHJhbnNsYXRpb24ucGlwZShcbiAgICAgIHJldHJ5KHRoaXMuY29uZmlnLmZhaWxlZFJldHJpZXMpLFxuICAgICAgdGFwKCh0cmFuc2xhdGlvbikgPT4ge1xuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh0cmFuc2xhdGlvbikpIHtcbiAgICAgICAgICB0cmFuc2xhdGlvbi5mb3JFYWNoKCh0KSA9PiB7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZVN1Y2Nlc3ModC5sYW5nLCB0LnRyYW5zbGF0aW9uKTtcbiAgICAgICAgICAgIC8vIFNhdmUgdGhlIGZhbGxiYWNrIGluIGNhY2hlIHNvIHdlJ2xsIG5vdCBjcmVhdGUgYSByZWR1bmRhbnQgcmVxdWVzdFxuICAgICAgICAgICAgaWYgKHQubGFuZyAhPT0gcGF0aCkge1xuICAgICAgICAgICAgICB0aGlzLmNhY2hlLnNldCh0LmxhbmcsIG9mKHt9KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuaGFuZGxlU3VjY2VzcyhwYXRoLCB0cmFuc2xhdGlvbik7XG4gICAgICB9KSxcbiAgICAgIGNhdGNoRXJyb3IoKGVycm9yKSA9PiB7XG4gICAgICAgIGlmICghdGhpcy5jb25maWcucHJvZE1vZGUpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGBFcnJvciB3aGlsZSB0cnlpbmcgdG8gbG9hZCBcIiR7cGF0aH1cImAsIGVycm9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLmhhbmRsZUZhaWx1cmUocGF0aCwgb3B0aW9ucyk7XG4gICAgICB9KSxcbiAgICAgIHNoYXJlUmVwbGF5KDEpXG4gICAgKTtcblxuICAgIHRoaXMuY2FjaGUuc2V0KHBhdGgsIGxvYWQkKTtcblxuICAgIHJldHVybiBsb2FkJDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBpbnN0YW50IHRyYW5zbGF0ZWQgdmFsdWUgb2YgYSBrZXlcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogdHJhbnNsYXRlPHN0cmluZz4oJ2hlbGxvJylcbiAgICogdHJhbnNsYXRlKCdoZWxsbycsIHsgdmFsdWU6ICd2YWx1ZScgfSlcbiAgICogdHJhbnNsYXRlPHN0cmluZ1tdPihbJ2hlbGxvJywgJ2tleSddKVxuICAgKiB0cmFuc2xhdGUoJ2hlbGxvJywgeyB9LCAnZW4nKVxuICAgKiB0cmFuc2xhdGUoJ3Njb3BlLnNvbWVLZXknLCB7IH0sICdlbicpXG4gICAqL1xuICB0cmFuc2xhdGU8VCA9IHN0cmluZz4oXG4gICAga2V5OiBUcmFuc2xhdGVQYXJhbXMsXG4gICAgcGFyYW1zOiBIYXNoTWFwID0ge30sXG4gICAgbGFuZyA9IHRoaXMuZ2V0QWN0aXZlTGFuZygpXG4gICk6IFQge1xuICAgIGlmICgha2V5KSByZXR1cm4ga2V5IGFzIGFueTtcblxuICAgIGNvbnN0IHsgc2NvcGUsIHJlc29sdmVMYW5nIH0gPSB0aGlzLnJlc29sdmVMYW5nQW5kU2NvcGUobGFuZyk7XG5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShrZXkpKSB7XG4gICAgICByZXR1cm4ga2V5Lm1hcCgoaykgPT5cbiAgICAgICAgdGhpcy50cmFuc2xhdGUoc2NvcGUgPyBgJHtzY29wZX0uJHtrfWAgOiBrLCBwYXJhbXMsIHJlc29sdmVMYW5nKVxuICAgICAgKSBhcyBhbnk7XG4gICAgfVxuXG4gICAga2V5ID0gc2NvcGUgPyBgJHtzY29wZX0uJHtrZXl9YCA6IGtleTtcblxuICAgIGNvbnN0IHRyYW5zbGF0aW9uID0gdGhpcy5nZXRUcmFuc2xhdGlvbihyZXNvbHZlTGFuZyk7XG4gICAgY29uc3QgdmFsdWUgPSB0cmFuc2xhdGlvbltrZXldO1xuXG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU1pc3NpbmdLZXkoa2V5LCB2YWx1ZSwgcGFyYW1zKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5wYXJzZXIudHJhbnNwaWxlKHtcbiAgICAgIHZhbHVlLCBwYXJhbXMsIHRyYW5zbGF0aW9uLCBrZXlcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSB0cmFuc2xhdGVkIHZhbHVlIG9mIGEga2V5IGFzIG9ic2VydmFibGVcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogc2VsZWN0VHJhbnNsYXRlPHN0cmluZz4oJ2hlbGxvJykuc3Vic2NyaWJlKHZhbHVlID0+IC4uLilcbiAgICogc2VsZWN0VHJhbnNsYXRlPHN0cmluZz4oJ2hlbGxvJywge30sICdlcycpLnN1YnNjcmliZSh2YWx1ZSA9PiAuLi4pXG4gICAqIHNlbGVjdFRyYW5zbGF0ZTxzdHJpbmc+KCdoZWxsbycsIHt9LCAndG9kb3MnKS5zdWJzY3JpYmUodmFsdWUgPT4gLi4uKVxuICAgKiBzZWxlY3RUcmFuc2xhdGU8c3RyaW5nPignaGVsbG8nLCB7fSwgeyBzY29wZTogJ3RvZG9zJyB9KS5zdWJzY3JpYmUodmFsdWUgPT4gLi4uKVxuICAgKlxuICAgKi9cbiAgc2VsZWN0VHJhbnNsYXRlPFQgPSBhbnk+KFxuICAgIGtleTogVHJhbnNsYXRlUGFyYW1zLFxuICAgIHBhcmFtcz86IEhhc2hNYXAsXG4gICAgbGFuZz86IHN0cmluZyB8IFRyYW5zbG9jb1Njb3BlIHwgVHJhbnNsb2NvU2NvcGVbXSxcbiAgICBfaXNPYmplY3QgPSBmYWxzZVxuICApOiBPYnNlcnZhYmxlPFQ+IHtcbiAgICBsZXQgaW5saW5lTG9hZGVyOiBJbmxpbmVMb2FkZXIgfCB1bmRlZmluZWQ7XG4gICAgY29uc3QgbG9hZCA9IChsYW5nOiBzdHJpbmcsIG9wdGlvbnM/OiBMb2FkT3B0aW9ucykgPT5cbiAgICAgIHRoaXMubG9hZChsYW5nLCBvcHRpb25zKS5waXBlKFxuICAgICAgICBtYXAoKCkgPT5cbiAgICAgICAgICBfaXNPYmplY3RcbiAgICAgICAgICAgID8gdGhpcy50cmFuc2xhdGVPYmplY3Qoa2V5LCBwYXJhbXMsIGxhbmcpXG4gICAgICAgICAgICA6IHRoaXMudHJhbnNsYXRlKGtleSwgcGFyYW1zLCBsYW5nKVxuICAgICAgICApXG4gICAgICApO1xuICAgIGlmIChpc05pbChsYW5nKSkge1xuICAgICAgcmV0dXJuIHRoaXMubGFuZ0NoYW5nZXMkLnBpcGUoc3dpdGNoTWFwKChsYW5nKSA9PiBsb2FkKGxhbmcpKSk7XG4gICAgfVxuXG4gICAgaWYgKGlzU2NvcGVBcnJheShsYW5nKSB8fCBpc1Njb3BlT2JqZWN0KGxhbmcpKSB7XG4gICAgICAvLyBpdCdzIGEgc2NvcGUgb2JqZWN0LlxuICAgICAgY29uc3QgcHJvdmlkZXJTY29wZSA9IEFycmF5LmlzQXJyYXkobGFuZykgPyBsYW5nWzBdIDogbGFuZztcbiAgICAgIGxhbmcgPSBwcm92aWRlclNjb3BlLnNjb3BlO1xuICAgICAgaW5saW5lTG9hZGVyID0gcmVzb2x2ZUlubGluZUxvYWRlcihwcm92aWRlclNjb3BlLCBwcm92aWRlclNjb3BlLnNjb3BlKTtcbiAgICB9XG5cbiAgICBsYW5nID0gbGFuZyBhcyBzdHJpbmc7XG4gICAgaWYgKHRoaXMuaXNMYW5nKGxhbmcpIHx8IHRoaXMuaXNTY29wZVdpdGhMYW5nKGxhbmcpKSB7XG4gICAgICByZXR1cm4gbG9hZChsYW5nKTtcbiAgICB9XG4gICAgLy8gaXQncyBhIHNjb3BlXG4gICAgY29uc3Qgc2NvcGUgPSBsYW5nO1xuICAgIHJldHVybiB0aGlzLmxhbmdDaGFuZ2VzJC5waXBlKFxuICAgICAgc3dpdGNoTWFwKChsYW5nKSA9PiBsb2FkKGAke3Njb3BlfS8ke2xhbmd9YCwgeyBpbmxpbmVMb2FkZXIgfSkpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBzY29wZSB3aXRoIGxhbmdcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogdG9kb3MvZW4gPT4gdHJ1ZVxuICAgKiB0b2RvcyA9PiBmYWxzZVxuICAgKi9cbiAgcHJpdmF0ZSBpc1Njb3BlV2l0aExhbmcobGFuZzogc3RyaW5nKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNMYW5nKGdldExhbmdGcm9tU2NvcGUobGFuZykpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYW5zbGF0ZSB0aGUgZ2l2ZW4gcGF0aCB0aGF0IHJldHVybnMgYW4gb2JqZWN0XG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqIHNlcnZpY2UudHJhbnNsYXRlT2JqZWN0KCdwYXRoLnRvLm9iamVjdCcsIHsnc3VicGF0aCc6IHsgdmFsdWU6ICdzb21lVmFsdWUnfX0pID0+IHJldHVybnMgdHJhbnNsYXRlZCBvYmplY3RcbiAgICpcbiAgICovXG4gIHRyYW5zbGF0ZU9iamVjdDxUID0gYW55PihrZXk6IHN0cmluZywgcGFyYW1zPzogSGFzaE1hcCwgbGFuZz86IHN0cmluZyk6IFQ7XG4gIHRyYW5zbGF0ZU9iamVjdDxUID0gYW55PihrZXk6IHN0cmluZ1tdLCBwYXJhbXM/OiBIYXNoTWFwLCBsYW5nPzogc3RyaW5nKTogVFtdO1xuICB0cmFuc2xhdGVPYmplY3Q8VCA9IGFueT4oXG4gICAga2V5OiBUcmFuc2xhdGVQYXJhbXMsXG4gICAgcGFyYW1zPzogSGFzaE1hcCxcbiAgICBsYW5nPzogc3RyaW5nXG4gICk6IFQgfCBUW107XG4gIHRyYW5zbGF0ZU9iamVjdDxUID0gYW55PihcbiAgICBrZXk6IEhhc2hNYXAgfCBNYXA8c3RyaW5nLCBIYXNoTWFwPixcbiAgICBwYXJhbXM/OiBudWxsLFxuICAgIGxhbmc/OiBzdHJpbmdcbiAgKTogVFtdO1xuICB0cmFuc2xhdGVPYmplY3Q8VCA9IGFueT4oXG4gICAga2V5OiBUcmFuc2xhdGVPYmplY3RQYXJhbXMsXG4gICAgcGFyYW1zOiBIYXNoTWFwIHwgbnVsbCA9IHt9LFxuICAgIGxhbmcgPSB0aGlzLmdldEFjdGl2ZUxhbmcoKVxuICApOiBUIHwgVFtdIHtcbiAgICBpZiAoaXNTdHJpbmcoa2V5KSB8fCBBcnJheS5pc0FycmF5KGtleSkpIHtcbiAgICAgIGNvbnN0IHsgcmVzb2x2ZUxhbmcsIHNjb3BlIH0gPSB0aGlzLnJlc29sdmVMYW5nQW5kU2NvcGUobGFuZyk7XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShrZXkpKSB7XG4gICAgICAgIHJldHVybiBrZXkubWFwKChrKSA9PlxuICAgICAgICAgIHRoaXMudHJhbnNsYXRlT2JqZWN0KFxuICAgICAgICAgICAgc2NvcGUgPyBgJHtzY29wZX0uJHtrfWAgOiBrLFxuICAgICAgICAgICAgcGFyYW1zISxcbiAgICAgICAgICAgIHJlc29sdmVMYW5nXG4gICAgICAgICAgKVxuICAgICAgICApIGFzIGFueTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdHJhbnNsYXRpb24gPSB0aGlzLmdldFRyYW5zbGF0aW9uKHJlc29sdmVMYW5nKTtcbiAgICAgIGtleSA9IHNjb3BlID8gYCR7c2NvcGV9LiR7a2V5fWAgOiBrZXk7XG5cbiAgICAgIGNvbnN0IHZhbHVlID0gdW5mbGF0dGVuKHRoaXMuZ2V0T2JqZWN0QnlLZXkodHJhbnNsYXRpb24sIGtleSkpO1xuICAgICAgLyogSWYgYW4gZW1wdHkgb2JqZWN0IHdhcyByZXR1cm5lZCB3ZSB3YW50IHRvIHRyeSBhbmQgdHJhbnNsYXRlIHRoZSBrZXkgYXMgYSBzdHJpbmcgYW5kIG5vdCBhbiBvYmplY3QgKi9cbiAgICAgIHJldHVybiBpc0VtcHR5KHZhbHVlKVxuICAgICAgICA/IHRoaXMudHJhbnNsYXRlKGtleSwgcGFyYW1zISwgbGFuZylcbiAgICAgICAgOiB0aGlzLnBhcnNlci50cmFuc3BpbGUoe3ZhbHVlLCBwYXJhbXM6IHBhcmFtcyEsIHRyYW5zbGF0aW9uLCBrZXl9KTtcbiAgICB9XG5cbiAgICBjb25zdCB0cmFuc2xhdGlvbnM6IFRbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgW19rZXksIF9wYXJhbXNdIG9mIHRoaXMuZ2V0RW50cmllcyhrZXkpKSB7XG4gICAgICB0cmFuc2xhdGlvbnMucHVzaCh0aGlzLnRyYW5zbGF0ZU9iamVjdChfa2V5LCBfcGFyYW1zLCBsYW5nKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRyYW5zbGF0aW9ucztcbiAgfVxuXG4gIHNlbGVjdFRyYW5zbGF0ZU9iamVjdDxUID0gYW55PihcbiAgICBrZXk6IHN0cmluZyxcbiAgICBwYXJhbXM/OiBIYXNoTWFwLFxuICAgIGxhbmc/OiBzdHJpbmdcbiAgKTogT2JzZXJ2YWJsZTxUPjtcbiAgc2VsZWN0VHJhbnNsYXRlT2JqZWN0PFQgPSBhbnk+KFxuICAgIGtleTogc3RyaW5nW10sXG4gICAgcGFyYW1zPzogSGFzaE1hcCxcbiAgICBsYW5nPzogc3RyaW5nXG4gICk6IE9ic2VydmFibGU8VFtdPjtcbiAgc2VsZWN0VHJhbnNsYXRlT2JqZWN0PFQgPSBhbnk+KFxuICAgIGtleTogVHJhbnNsYXRlUGFyYW1zLFxuICAgIHBhcmFtcz86IEhhc2hNYXAsXG4gICAgbGFuZz86IHN0cmluZ1xuICApOiBPYnNlcnZhYmxlPFQ+IHwgT2JzZXJ2YWJsZTxUW10+O1xuICBzZWxlY3RUcmFuc2xhdGVPYmplY3Q8VCA9IGFueT4oXG4gICAga2V5OiBIYXNoTWFwIHwgTWFwPHN0cmluZywgSGFzaE1hcD4sXG4gICAgcGFyYW1zPzogbnVsbCxcbiAgICBsYW5nPzogc3RyaW5nXG4gICk6IE9ic2VydmFibGU8VFtdPjtcbiAgc2VsZWN0VHJhbnNsYXRlT2JqZWN0PFQgPSBhbnk+KFxuICAgIGtleTogVHJhbnNsYXRlT2JqZWN0UGFyYW1zLFxuICAgIHBhcmFtcz86IEhhc2hNYXAgfCBudWxsLFxuICAgIGxhbmc/OiBzdHJpbmdcbiAgKTogT2JzZXJ2YWJsZTxUPiB8IE9ic2VydmFibGU8VFtdPiB7XG4gICAgaWYgKGlzU3RyaW5nKGtleSkgfHwgQXJyYXkuaXNBcnJheShrZXkpKSB7XG4gICAgICByZXR1cm4gdGhpcy5zZWxlY3RUcmFuc2xhdGU8VD4oa2V5LCBwYXJhbXMhLCBsYW5nLCB0cnVlKTtcbiAgICB9XG5cbiAgICBjb25zdCBbW2ZpcnN0S2V5LCBmaXJzdFBhcmFtc10sIC4uLnJlc3RdID0gdGhpcy5nZXRFbnRyaWVzKGtleSk7XG5cbiAgICAvKiBJbiBvcmRlciB0byBhdm9pZCBzdWJzY3JpYmluZyBtdWx0aXBsZSB0aW1lcyB0byB0aGUgbG9hZCBsYW5ndWFnZSBldmVudCBieSBjYWxsaW5nIHNlbGVjdFRyYW5zbGF0ZU9iamVjdCBmb3IgZWFjaCBwYWlyLFxuICAgICAqIHdlIGxpc3RlbiB0byB3aGVuIHRoZSBmaXJzdCBrZXkgaGFzIGJlZW4gdHJhbnNsYXRlZCAodGhlIGxhbmd1YWdlIGlzIGxvYWRlZCkgYW5kIHRyYW5zbGF0ZSB0aGUgcmVzdCBzeW5jaHJvbm91c2x5ICovXG4gICAgcmV0dXJuIHRoaXMuc2VsZWN0VHJhbnNsYXRlT2JqZWN0PFQ+KGZpcnN0S2V5LCBmaXJzdFBhcmFtcywgbGFuZykucGlwZShcbiAgICAgIG1hcCgodmFsdWUpID0+IHtcbiAgICAgICAgY29uc3QgdHJhbnNsYXRpb25zID0gW3ZhbHVlXTtcbiAgICAgICAgZm9yIChjb25zdCBbX2tleSwgX3BhcmFtc10gb2YgcmVzdCkge1xuICAgICAgICAgIHRyYW5zbGF0aW9ucy5wdXNoKHRoaXMudHJhbnNsYXRlT2JqZWN0PFQ+KF9rZXksIF9wYXJhbXMsIGxhbmcpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0cmFuc2xhdGlvbnM7XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBhbiBvYmplY3Qgb2YgdHJhbnNsYXRpb25zIGZvciBhIGdpdmVuIGxhbmd1YWdlXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqIGdldFRyYW5zbGF0aW9uKClcbiAgICogZ2V0VHJhbnNsYXRpb24oJ2VuJylcbiAgICogZ2V0VHJhbnNsYXRpb24oJ2FkbWluLXBhZ2UvZW4nKVxuICAgKi9cbiAgZ2V0VHJhbnNsYXRpb24oKTogTWFwPHN0cmluZywgVHJhbnNsYXRpb24+O1xuICBnZXRUcmFuc2xhdGlvbihsYW5nT3JTY29wZTogc3RyaW5nKTogVHJhbnNsYXRpb247XG4gIGdldFRyYW5zbGF0aW9uKGxhbmdPclNjb3BlPzogc3RyaW5nKTogTWFwPHN0cmluZywgVHJhbnNsYXRpb24+IHwgVHJhbnNsYXRpb24ge1xuICAgIGlmIChsYW5nT3JTY29wZSkge1xuICAgICAgaWYgKHRoaXMuaXNMYW5nKGxhbmdPclNjb3BlKSkge1xuICAgICAgICByZXR1cm4gdGhpcy50cmFuc2xhdGlvbnMuZ2V0KGxhbmdPclNjb3BlKSB8fCB7fTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFRoaXMgaXMgYSBzY29wZSwgYnVpbGQgdGhlIHNjb3BlIHZhbHVlIGZyb20gdGhlIHRyYW5zbGF0aW9uIG9iamVjdFxuICAgICAgICBjb25zdCB7IHNjb3BlLCByZXNvbHZlTGFuZyB9ID0gdGhpcy5yZXNvbHZlTGFuZ0FuZFNjb3BlKGxhbmdPclNjb3BlKTtcbiAgICAgICAgY29uc3QgdHJhbnNsYXRpb24gPSB0aGlzLnRyYW5zbGF0aW9ucy5nZXQocmVzb2x2ZUxhbmcpIHx8IHt9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmdldE9iamVjdEJ5S2V5KHRyYW5zbGF0aW9uLCBzY29wZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMudHJhbnNsYXRpb25zO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgYW4gb2JqZWN0IG9mIHRyYW5zbGF0aW9ucyBmb3IgYSBnaXZlbiBsYW5ndWFnZVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiBzZWxlY3RUcmFuc2xhdGlvbigpLnN1YnNjcmliZSgpIC0gd2lsbCByZXR1cm4gdGhlIGN1cnJlbnQgbGFuZyB0cmFuc2xhdGlvblxuICAgKiBzZWxlY3RUcmFuc2xhdGlvbignZXMnKS5zdWJzY3JpYmUoKVxuICAgKiBzZWxlY3RUcmFuc2xhdGlvbignYWRtaW4tcGFnZScpLnN1YnNjcmliZSgpIC0gd2lsbCByZXR1cm4gdGhlIGN1cnJlbnQgbGFuZyBzY29wZSB0cmFuc2xhdGlvblxuICAgKiBzZWxlY3RUcmFuc2xhdGlvbignYWRtaW4tcGFnZS9lcycpLnN1YnNjcmliZSgpXG4gICAqL1xuICBzZWxlY3RUcmFuc2xhdGlvbihsYW5nPzogc3RyaW5nKTogT2JzZXJ2YWJsZTxUcmFuc2xhdGlvbj4ge1xuICAgIGxldCBsYW5ndWFnZSQgPSB0aGlzLmxhbmdDaGFuZ2VzJDtcbiAgICBpZiAobGFuZykge1xuICAgICAgY29uc3Qgc2NvcGVMYW5nU3BlY2lmaWVkID0gZ2V0TGFuZ0Zyb21TY29wZShsYW5nKSAhPT0gbGFuZztcbiAgICAgIGlmICh0aGlzLmlzTGFuZyhsYW5nKSB8fCBzY29wZUxhbmdTcGVjaWZpZWQpIHtcbiAgICAgICAgbGFuZ3VhZ2UkID0gb2YobGFuZyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsYW5ndWFnZSQgPSB0aGlzLmxhbmdDaGFuZ2VzJC5waXBlKFxuICAgICAgICAgIG1hcCgoY3VycmVudExhbmcpID0+IGAke2xhbmd9LyR7Y3VycmVudExhbmd9YClcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbGFuZ3VhZ2UkLnBpcGUoXG4gICAgICBzd2l0Y2hNYXAoKGxhbmd1YWdlKSA9PlxuICAgICAgICB0aGlzLmxvYWQobGFuZ3VhZ2UpLnBpcGUobWFwKCgpID0+IHRoaXMuZ2V0VHJhbnNsYXRpb24obGFuZ3VhZ2UpKSlcbiAgICAgIClcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgb3IgbWVyZ2UgYSBnaXZlbiB0cmFuc2xhdGlvbiBvYmplY3QgdG8gY3VycmVudCBsYW5nXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqIHNldFRyYW5zbGF0aW9uKHsgLi4uIH0pXG4gICAqIHNldFRyYW5zbGF0aW9uKHsgLi4uIH0sICdlbicpXG4gICAqIHNldFRyYW5zbGF0aW9uKHsgLi4uIH0sICdlcycsIHsgbWVyZ2U6IGZhbHNlIH0gKVxuICAgKiBzZXRUcmFuc2xhdGlvbih7IC4uLiB9LCAndG9kb3MvZW4nLCB7IG1lcmdlOiBmYWxzZSB9IClcbiAgICovXG4gIHNldFRyYW5zbGF0aW9uKFxuICAgIHRyYW5zbGF0aW9uOiBUcmFuc2xhdGlvbixcbiAgICBsYW5nID0gdGhpcy5nZXRBY3RpdmVMYW5nKCksXG4gICAgb3B0aW9uczogU2V0VHJhbnNsYXRpb25PcHRpb25zID0ge31cbiAgKSB7XG4gICAgY29uc3QgZGVmYXVsdHMgPSB7IG1lcmdlOiB0cnVlLCBlbWl0Q2hhbmdlOiB0cnVlIH07XG4gICAgY29uc3QgbWVyZ2VkT3B0aW9ucyA9IHsgLi4uZGVmYXVsdHMsIC4uLm9wdGlvbnMgfTtcbiAgICBjb25zdCBzY29wZSA9IGdldFNjb3BlRnJvbUxhbmcobGFuZyk7XG5cbiAgICAvKipcbiAgICAgKiBJZiB0aGlzIGlzbid0IGEgc2NvcGUgd2UgdXNlIHRoZSB3aG9sZSB0cmFuc2xhdGlvbiBhcyBpc1xuICAgICAqIG90aGVyd2lzZSB3ZSBuZWVkIHRvIGZsYXQgdGhlIHNjb3BlIGFuZCB1c2UgaXRcbiAgICAgKi9cbiAgICBsZXQgZmxhdHRlblNjb3BlT3JUcmFuc2xhdGlvbiA9IHRyYW5zbGF0aW9uO1xuXG4gICAgLy8gTWVyZ2VkIHRoZSBzY29wZWQgbGFuZ3VhZ2UgaW50byB0aGUgYWN0aXZlIGxhbmd1YWdlXG4gICAgaWYgKHNjb3BlKSB7XG4gICAgICBjb25zdCBrZXkgPSB0aGlzLmdldE1hcHBlZFNjb3BlKHNjb3BlKTtcbiAgICAgIGZsYXR0ZW5TY29wZU9yVHJhbnNsYXRpb24gPSBmbGF0dGVuKHsgW2tleV06IHRyYW5zbGF0aW9uIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IGN1cnJlbnRMYW5nID0gc2NvcGUgPyBnZXRMYW5nRnJvbVNjb3BlKGxhbmcpIDogbGFuZztcblxuICAgIGNvbnN0IG1lcmdlZFRyYW5zbGF0aW9uID0ge1xuICAgICAgLi4uKG1lcmdlZE9wdGlvbnMubWVyZ2UgJiYgdGhpcy5nZXRUcmFuc2xhdGlvbihjdXJyZW50TGFuZykpLFxuICAgICAgLi4uZmxhdHRlblNjb3BlT3JUcmFuc2xhdGlvbixcbiAgICB9O1xuXG4gICAgY29uc3QgZmxhdHRlblRyYW5zbGF0aW9uID0gdGhpcy5jb25maWcuZmxhdHRlbiEuYW90XG4gICAgICA/IG1lcmdlZFRyYW5zbGF0aW9uXG4gICAgICA6IGZsYXR0ZW4obWVyZ2VkVHJhbnNsYXRpb24pO1xuICAgIGNvbnN0IHdpdGhIb29rID0gdGhpcy5pbnRlcmNlcHRvci5wcmVTYXZlVHJhbnNsYXRpb24oXG4gICAgICBmbGF0dGVuVHJhbnNsYXRpb24sXG4gICAgICBjdXJyZW50TGFuZ1xuICAgICk7XG4gICAgdGhpcy50cmFuc2xhdGlvbnMuc2V0KGN1cnJlbnRMYW5nLCB3aXRoSG9vayk7XG4gICAgbWVyZ2VkT3B0aW9ucy5lbWl0Q2hhbmdlICYmIHRoaXMuc2V0QWN0aXZlTGFuZyh0aGlzLmdldEFjdGl2ZUxhbmcoKSk7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0cmFuc2xhdGlvbiBrZXkgd2l0aCBnaXZlbiB2YWx1ZVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiBzZXRUcmFuc2xhdGlvbktleSgna2V5JywgJ3ZhbHVlJylcbiAgICogc2V0VHJhbnNsYXRpb25LZXkoJ2tleS5uZXN0ZWQnLCAndmFsdWUnKVxuICAgKiBzZXRUcmFuc2xhdGlvbktleSgna2V5Lm5lc3RlZCcsICd2YWx1ZScsICdlbicpXG4gICAqIHNldFRyYW5zbGF0aW9uS2V5KCdrZXkubmVzdGVkJywgJ3ZhbHVlJywgJ2VuJywgeyBlbWl0Q2hhbmdlOiBmYWxzZSB9IClcbiAgICovXG4gIHNldFRyYW5zbGF0aW9uS2V5KFxuICAgIGtleTogc3RyaW5nLFxuICAgIHZhbHVlOiBzdHJpbmcsXG4gICAgb3B0aW9uczogT21pdDxTZXRUcmFuc2xhdGlvbk9wdGlvbnMsICdtZXJnZSc+ID0ge31cbiAgKSB7XG4gICAgY29uc3QgbGFuZyA9IG9wdGlvbnMubGFuZyB8fCB0aGlzLmdldEFjdGl2ZUxhbmcoKTtcbiAgICBjb25zdCB3aXRoSG9vayA9IHRoaXMuaW50ZXJjZXB0b3IucHJlU2F2ZVRyYW5zbGF0aW9uS2V5KGtleSwgdmFsdWUsIGxhbmcpO1xuICAgIGNvbnN0IG5ld1ZhbHVlID0ge1xuICAgICAgW2tleV06IHdpdGhIb29rLFxuICAgIH07XG5cbiAgICB0aGlzLnNldFRyYW5zbGF0aW9uKG5ld1ZhbHVlLCBsYW5nLCB7IC4uLm9wdGlvbnMsIG1lcmdlOiB0cnVlIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGZhbGxiYWNrIGxhbmcgZm9yIHRoZSBjdXJyZW50bHkgYWN0aXZlIGxhbmd1YWdlXG4gICAqIEBwYXJhbSBmYWxsYmFja0xhbmdcbiAgICovXG4gIHNldEZhbGxiYWNrTGFuZ0Zvck1pc3NpbmdUcmFuc2xhdGlvbih7XG4gICAgZmFsbGJhY2tMYW5nLFxuICB9OiBQaWNrPFRyYW5zbG9jb0NvbmZpZywgJ2ZhbGxiYWNrTGFuZyc+KSB7XG4gICAgY29uc3QgbGFuZyA9IEFycmF5LmlzQXJyYXkoZmFsbGJhY2tMYW5nKSA/IGZhbGxiYWNrTGFuZ1swXSA6IGZhbGxiYWNrTGFuZztcbiAgICBpZiAoZmFsbGJhY2tMYW5nICYmIHRoaXMudXNlRmFsbGJhY2tUcmFuc2xhdGlvbihsYW5nKSkge1xuICAgICAgdGhpcy5maXJzdEZhbGxiYWNrTGFuZyA9IGxhbmchO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIF9oYW5kbGVNaXNzaW5nS2V5KGtleTogc3RyaW5nLCB2YWx1ZTogYW55LCBwYXJhbXM/OiBIYXNoTWFwKSB7XG4gICAgaWYgKHRoaXMuY29uZmlnLm1pc3NpbmdIYW5kbGVyIS5hbGxvd0VtcHR5ICYmIHZhbHVlID09PSAnJykge1xuICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5pc1Jlc29sdmVkTWlzc2luZ09uY2UgJiYgdGhpcy51c2VGYWxsYmFja1RyYW5zbGF0aW9uKCkpIHtcbiAgICAgIC8vIFdlIG5lZWQgdG8gc2V0IGl0IHRvIHRydWUgdG8gcHJldmVudCBhIGxvb3BcbiAgICAgIHRoaXMuaXNSZXNvbHZlZE1pc3NpbmdPbmNlID0gdHJ1ZTtcbiAgICAgIGNvbnN0IGZhbGxiYWNrVmFsdWUgPSB0aGlzLnRyYW5zbGF0ZShcbiAgICAgICAga2V5LFxuICAgICAgICBwYXJhbXMsXG4gICAgICAgIHRoaXMuZmlyc3RGYWxsYmFja0xhbmchXG4gICAgICApO1xuICAgICAgdGhpcy5pc1Jlc29sdmVkTWlzc2luZ09uY2UgPSBmYWxzZTtcblxuICAgICAgcmV0dXJuIGZhbGxiYWNrVmFsdWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMubWlzc2luZ0hhbmRsZXIuaGFuZGxlKFxuICAgICAga2V5LFxuICAgICAgdGhpcy5nZXRNaXNzaW5nSGFuZGxlckRhdGEoKSxcbiAgICAgIHBhcmFtc1xuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQGludGVybmFsXG4gICAqL1xuICBfaXNMYW5nU2NvcGVkKGxhbmc6IHN0cmluZykge1xuICAgIHJldHVybiB0aGlzLmdldEF2YWlsYWJsZUxhbmdzSWRzKCkuaW5kZXhPZihsYW5nKSA9PT0gLTE7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGEgZ2l2ZW4gc3RyaW5nIGlzIG9uZSBvZiB0aGUgc3BlY2lmaWVkIGF2YWlsYWJsZSBsYW5ndWFnZXMuXG4gICAqIEByZXR1cm5zXG4gICAqIFRydWUgaWYgdGhlIGdpdmVuIHN0cmluZyBpcyBhbiBhdmFpbGFibGUgbGFuZ3VhZ2UuXG4gICAqIEZhbHNlIGlmIHRoZSBnaXZlbiBzdHJpbmcgaXMgbm90IGFuIGF2YWlsYWJsZSBsYW5ndWFnZS5cbiAgICovXG4gIGlzTGFuZyhsYW5nOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5nZXRBdmFpbGFibGVMYW5nc0lkcygpLmluZGV4T2YobGFuZykgIT09IC0xO1xuICB9XG5cbiAgLyoqXG4gICAqIEBpbnRlcm5hbFxuICAgKlxuICAgKiBXZSBhbHdheXMgd2FudCB0byBtYWtlIHN1cmUgdGhlIGdsb2JhbCBsYW5nIGlzIGxvYWRlZFxuICAgKiBiZWZvcmUgbG9hZGluZyB0aGUgc2NvcGUgc2luY2UgeW91IGNhbiBhY2Nlc3MgYm90aCB2aWEgdGhlIHBpcGUvZGlyZWN0aXZlLlxuICAgKi9cbiAgX2xvYWREZXBlbmRlbmNpZXMoXG4gICAgcGF0aDogc3RyaW5nLFxuICAgIGlubGluZUxvYWRlcj86IElubGluZUxvYWRlclxuICApOiBPYnNlcnZhYmxlPFRyYW5zbGF0aW9uIHwgVHJhbnNsYXRpb25bXT4ge1xuICAgIGNvbnN0IG1haW5MYW5nID0gZ2V0TGFuZ0Zyb21TY29wZShwYXRoKTtcblxuICAgIGlmICh0aGlzLl9pc0xhbmdTY29wZWQocGF0aCkgJiYgIXRoaXMuaXNMb2FkZWRUcmFuc2xhdGlvbihtYWluTGFuZykpIHtcbiAgICAgIHJldHVybiBjb21iaW5lTGF0ZXN0KFtcbiAgICAgICAgdGhpcy5sb2FkKG1haW5MYW5nKSxcbiAgICAgICAgdGhpcy5sb2FkKHBhdGgsIHsgaW5saW5lTG9hZGVyIH0pLFxuICAgICAgXSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmxvYWQocGF0aCwgeyBpbmxpbmVMb2FkZXIgfSk7XG4gIH1cblxuICAvKipcbiAgICogQGludGVybmFsXG4gICAqL1xuICBfY29tcGxldGVTY29wZVdpdGhMYW5nKGxhbmdPclNjb3BlOiBzdHJpbmcpIHtcbiAgICBpZiAoXG4gICAgICB0aGlzLl9pc0xhbmdTY29wZWQobGFuZ09yU2NvcGUpICYmXG4gICAgICAhdGhpcy5pc0xhbmcoZ2V0TGFuZ0Zyb21TY29wZShsYW5nT3JTY29wZSkpXG4gICAgKSB7XG4gICAgICByZXR1cm4gYCR7bGFuZ09yU2NvcGV9LyR7dGhpcy5nZXRBY3RpdmVMYW5nKCl9YDtcbiAgICB9XG4gICAgcmV0dXJuIGxhbmdPclNjb3BlO1xuICB9XG5cbiAgLyoqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgX3NldFNjb3BlQWxpYXMoc2NvcGU6IHN0cmluZywgYWxpYXM6IHN0cmluZykge1xuICAgIGlmICghdGhpcy5jb25maWcuc2NvcGVNYXBwaW5nKSB7XG4gICAgICB0aGlzLmNvbmZpZy5zY29wZU1hcHBpbmcgPSB7fTtcbiAgICB9XG4gICAgdGhpcy5jb25maWcuc2NvcGVNYXBwaW5nW3Njb3BlXSA9IGFsaWFzO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgaWYgKHRoaXMuc3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLnN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgICAgLy8gQ2FyZXRha2VyIG5vdGU6IGl0J3MgaW1wb3J0YW50IHRvIGNsZWFuIHVwIHJlZmVyZW5jZXMgdG8gc3Vic2NyaXB0aW9ucyBzaW5jZSB0aGV5IHNhdmUgdGhlIGBuZXh0YFxuICAgICAgLy8gY2FsbGJhY2sgd2l0aGluIGl0cyBgZGVzdGluYXRpb25gIHByb3BlcnR5LCBwcmV2ZW50aW5nIGNsYXNzZXMgZnJvbSBiZWluZyBHQydkLlxuICAgICAgdGhpcy5zdWJzY3JpcHRpb24gPSBudWxsO1xuICAgIH1cbiAgICAvLyBDYXJldGFrZXIgbm90ZTogc2luY2UgdGhpcyBpcyB0aGUgcm9vdCBwcm92aWRlciwgaXQnbGwgYmUgZGVzdHJveWVkIHdoZW4gdGhlIGBOZ01vZHVsZVJlZi5kZXN0cm95KClgIGlzIHJ1bi5cbiAgICAvLyBDYWNoZWQgdmFsdWVzIGNhcHR1cmUgYHRoaXNgLCB0aHVzIGxlYWRpbmcgdG8gYSBjaXJjdWxhciByZWZlcmVuY2UgYW5kIHByZXZlbnRpbmcgdGhlIGBUcmFuc2xvY29TZXJ2aWNlYCBmcm9tXG4gICAgLy8gYmVpbmcgR0MnZC4gVGhpcyB3b3VsZCBsZWFkIHRvIGEgbWVtb3J5IGxlYWsgd2hlbiBzZXJ2ZXItc2lkZSByZW5kZXJpbmcgaXMgdXNlZCBzaW5jZSB0aGUgc2VydmljZSBpcyBjcmVhdGVkXG4gICAgLy8gYW5kIGRlc3Ryb3llZCBwZXIgZWFjaCBIVFRQIHJlcXVlc3QsIGJ1dCBhbnkgc2VydmljZSBpcyBub3QgZ2V0dGluZyBHQydkLlxuICAgIHRoaXMuY2FjaGUuY2xlYXIoKTtcbiAgfVxuXG4gIHByaXZhdGUgaXNMb2FkZWRUcmFuc2xhdGlvbihsYW5nOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gc2l6ZSh0aGlzLmdldFRyYW5zbGF0aW9uKGxhbmcpKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0QXZhaWxhYmxlTGFuZ3NJZHMoKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IGZpcnN0ID0gdGhpcy5nZXRBdmFpbGFibGVMYW5ncygpWzBdO1xuXG4gICAgaWYgKGlzU3RyaW5nKGZpcnN0KSkge1xuICAgICAgcmV0dXJuIHRoaXMuZ2V0QXZhaWxhYmxlTGFuZ3MoKSBhcyBzdHJpbmdbXTtcbiAgICB9XG5cbiAgICByZXR1cm4gKHRoaXMuZ2V0QXZhaWxhYmxlTGFuZ3MoKSBhcyBMYW5nRGVmaW5pdGlvbltdKS5tYXAoKGwpID0+IGwuaWQpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRNaXNzaW5nSGFuZGxlckRhdGEoKTogVHJhbnNsb2NvTWlzc2luZ0hhbmRsZXJEYXRhIHtcbiAgICByZXR1cm4ge1xuICAgICAgLi4udGhpcy5jb25maWcsXG4gICAgICBhY3RpdmVMYW5nOiB0aGlzLmdldEFjdGl2ZUxhbmcoKSxcbiAgICAgIGF2YWlsYWJsZUxhbmdzOiB0aGlzLmF2YWlsYWJsZUxhbmdzLFxuICAgICAgZGVmYXVsdExhbmc6IHRoaXMuZGVmYXVsdExhbmcsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVc2UgYSBmYWxsYmFjayB0cmFuc2xhdGlvbiBzZXQgZm9yIG1pc3Npbmcga2V5cyBvZiB0aGUgcHJpbWFyeSBsYW5ndWFnZVxuICAgKiBUaGlzIGlzIHVucmVsYXRlZCB0byB0aGUgZmFsbGJhY2sgbGFuZ3VhZ2UgKHdoaWNoIGNoYW5nZXMgdGhlIGFjdGl2ZSBsYW5ndWFnZSlcbiAgICovXG4gIHByaXZhdGUgdXNlRmFsbGJhY2tUcmFuc2xhdGlvbihsYW5nPzogc3RyaW5nKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIHRoaXMuY29uZmlnLm1pc3NpbmdIYW5kbGVyIS51c2VGYWxsYmFja1RyYW5zbGF0aW9uICYmXG4gICAgICBsYW5nICE9PSB0aGlzLmZpcnN0RmFsbGJhY2tMYW5nXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlU3VjY2VzcyhsYW5nOiBzdHJpbmcsIHRyYW5zbGF0aW9uOiBUcmFuc2xhdGlvbikge1xuICAgIHRoaXMuc2V0VHJhbnNsYXRpb24odHJhbnNsYXRpb24sIGxhbmcsIHsgZW1pdENoYW5nZTogZmFsc2UgfSk7XG4gICAgdGhpcy5ldmVudHMubmV4dCh7XG4gICAgICB3YXNGYWlsdXJlOiAhIXRoaXMuZmFpbGVkTGFuZ3Muc2l6ZSxcbiAgICAgIHR5cGU6ICd0cmFuc2xhdGlvbkxvYWRTdWNjZXNzJyxcbiAgICAgIHBheWxvYWQ6IGdldEV2ZW50UGF5bG9hZChsYW5nKSxcbiAgICB9KTtcbiAgICB0aGlzLmZhaWxlZExhbmdzLmZvckVhY2goKGwpID0+IHRoaXMuY2FjaGUuZGVsZXRlKGwpKTtcbiAgICB0aGlzLmZhaWxlZExhbmdzLmNsZWFyKCk7XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZUZhaWx1cmUobGFuZzogc3RyaW5nLCBsb2FkT3B0aW9uczogTG9hZE9wdGlvbnMpIHtcbiAgICAvLyBXaGVuIHN0YXJ0aW5nIHRvIGxvYWQgYSBmaXJzdCBjaG9pY2UgbGFuZ3VhZ2UsIGluaXRpYWxpemVcbiAgICAvLyB0aGUgZmFpbGVkIGNvdW50ZXIgYW5kIHJlc29sdmUgdGhlIGZhbGxiYWNrIGxhbmdzLlxuICAgIGlmIChpc05pbChsb2FkT3B0aW9ucy5mYWlsZWRDb3VudGVyKSkge1xuICAgICAgbG9hZE9wdGlvbnMuZmFpbGVkQ291bnRlciA9IDA7XG5cbiAgICAgIGlmICghbG9hZE9wdGlvbnMuZmFsbGJhY2tMYW5ncykge1xuICAgICAgICBsb2FkT3B0aW9ucy5mYWxsYmFja0xhbmdzID0gdGhpcy5mYWxsYmFja1N0cmF0ZWd5LmdldE5leHRMYW5ncyhsYW5nKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBzcGxpdHRlZCA9IGxhbmcuc3BsaXQoJy8nKTtcbiAgICBjb25zdCBmYWxsYmFja3MgPSBsb2FkT3B0aW9ucy5mYWxsYmFja0xhbmdzO1xuICAgIGNvbnN0IG5leHRMYW5nID0gZmFsbGJhY2tzIVtsb2FkT3B0aW9ucy5mYWlsZWRDb3VudGVyIV07XG4gICAgdGhpcy5mYWlsZWRMYW5ncy5hZGQobGFuZyk7XG5cbiAgICAvLyBUaGlzIGhhbmRsZXMgdGhlIGNhc2Ugd2hlcmUgYSBsb2FkZWQgZmFsbGJhY2sgbGFuZ3VhZ2UgaXMgcmVxdWVzdGVkIGFnYWluXG4gICAgaWYgKHRoaXMuY2FjaGUuaGFzKG5leHRMYW5nKSkge1xuICAgICAgdGhpcy5oYW5kbGVTdWNjZXNzKG5leHRMYW5nLCB0aGlzLmdldFRyYW5zbGF0aW9uKG5leHRMYW5nKSk7XG4gICAgICByZXR1cm4gRU1QVFk7XG4gICAgfVxuXG4gICAgY29uc3QgaXNGYWxsYmFja0xhbmcgPSBuZXh0TGFuZyA9PT0gc3BsaXR0ZWRbc3BsaXR0ZWQubGVuZ3RoIC0gMV07XG5cbiAgICBpZiAoIW5leHRMYW5nIHx8IGlzRmFsbGJhY2tMYW5nKSB7XG4gICAgICBsZXQgbXNnID0gYFVuYWJsZSB0byBsb2FkIHRyYW5zbGF0aW9uIGFuZCBhbGwgdGhlIGZhbGxiYWNrIGxhbmd1YWdlc2A7XG4gICAgICBpZiAoc3BsaXR0ZWQubGVuZ3RoID4gMSkge1xuICAgICAgICBtc2cgKz0gYCwgZGlkIHlvdSBtaXNzcGVsbGVkIHRoZSBzY29wZSBuYW1lP2A7XG4gICAgICB9XG5cbiAgICAgIHRocm93IG5ldyBFcnJvcihtc2cpO1xuICAgIH1cblxuICAgIGxldCByZXNvbHZlTGFuZyA9IG5leHRMYW5nO1xuICAgIC8vIGlmIGl0J3Mgc2NvcGVkIGxhbmdcbiAgICBpZiAoc3BsaXR0ZWQubGVuZ3RoID4gMSkge1xuICAgICAgLy8gV2UgbmVlZCB0byByZXNvbHZlIGl0IHRvOlxuICAgICAgLy8gdG9kb3MvbGFuZ05vdEV4aXN0cyA9PiB0b2Rvcy9uZXh0TGFuZ1xuICAgICAgc3BsaXR0ZWRbc3BsaXR0ZWQubGVuZ3RoIC0gMV0gPSBuZXh0TGFuZztcbiAgICAgIHJlc29sdmVMYW5nID0gc3BsaXR0ZWQuam9pbignLycpO1xuICAgIH1cblxuICAgIGxvYWRPcHRpb25zLmZhaWxlZENvdW50ZXIhKys7XG4gICAgdGhpcy5ldmVudHMubmV4dCh7XG4gICAgICB0eXBlOiAndHJhbnNsYXRpb25Mb2FkRmFpbHVyZScsXG4gICAgICBwYXlsb2FkOiBnZXRFdmVudFBheWxvYWQobGFuZyksXG4gICAgfSk7XG5cbiAgICByZXR1cm4gdGhpcy5sb2FkKHJlc29sdmVMYW5nLCBsb2FkT3B0aW9ucyk7XG4gIH1cblxuICBwcml2YXRlIGdldE1hcHBlZFNjb3BlKHNjb3BlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHsgc2NvcGVNYXBwaW5nID0ge30gfSA9IHRoaXMuY29uZmlnO1xuICAgIHJldHVybiBzY29wZU1hcHBpbmdbc2NvcGVdIHx8IHRvQ2FtZWxDYXNlKHNjb3BlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJZiBsYW5nIGlzIHNjb3BlIHdlIG5lZWQgdG8gY2hlY2sgdGhlIGZvbGxvd2luZyBjYXNlczpcbiAgICogdG9kb3MvZXMgPT4gaW4gdGhpcyBjYXNlIHdlIHNob3VsZCB0YWtlIGBlc2AgYXMgbGFuZ1xuICAgKiB0b2RvcyA9PiBpbiB0aGlzIGNhc2Ugd2Ugc2hvdWxkIHNldCB0aGUgYWN0aXZlIGxhbmcgYXMgbGFuZ1xuICAgKi9cbiAgcHJpdmF0ZSByZXNvbHZlTGFuZ0FuZFNjb3BlKGxhbmc6IHN0cmluZykge1xuICAgIGxldCByZXNvbHZlTGFuZyA9IGxhbmc7XG4gICAgbGV0IHNjb3BlO1xuXG4gICAgaWYgKHRoaXMuX2lzTGFuZ1Njb3BlZChsYW5nKSkge1xuICAgICAgLy8gZW4gZm9yIGV4YW1wbGVcbiAgICAgIGNvbnN0IGxhbmdGcm9tU2NvcGUgPSBnZXRMYW5nRnJvbVNjb3BlKGxhbmcpO1xuICAgICAgLy8gZW4gaXMgbGFuZ1xuICAgICAgY29uc3QgaGFzTGFuZyA9IHRoaXMuaXNMYW5nKGxhbmdGcm9tU2NvcGUpO1xuICAgICAgLy8gdGFrZSBlblxuICAgICAgcmVzb2x2ZUxhbmcgPSBoYXNMYW5nID8gbGFuZ0Zyb21TY29wZSA6IHRoaXMuZ2V0QWN0aXZlTGFuZygpO1xuICAgICAgLy8gZmluZCB0aGUgc2NvcGVcbiAgICAgIHNjb3BlID0gdGhpcy5nZXRNYXBwZWRTY29wZShoYXNMYW5nID8gZ2V0U2NvcGVGcm9tTGFuZyhsYW5nKSA6IGxhbmcpO1xuICAgIH1cblxuICAgIHJldHVybiB7IHNjb3BlLCByZXNvbHZlTGFuZyB9O1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRPYmplY3RCeUtleSh0cmFuc2xhdGlvbjogVHJhbnNsYXRpb24sIGtleT86IHN0cmluZykge1xuICAgIGNvbnN0IHJlc3VsdDogVHJhbnNsYXRpb24gPSB7fTtcbiAgICBjb25zdCBwcmVmaXggPSBgJHtrZXl9LmA7XG5cbiAgICBmb3IgKGNvbnN0IGN1cnJlbnRLZXkgaW4gdHJhbnNsYXRpb24pIHtcbiAgICAgIGlmIChjdXJyZW50S2V5LnN0YXJ0c1dpdGgocHJlZml4KSkge1xuICAgICAgICByZXN1bHRbY3VycmVudEtleS5yZXBsYWNlKHByZWZpeCwgJycpXSA9IHRyYW5zbGF0aW9uW2N1cnJlbnRLZXldO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICBwcml2YXRlIGdldEVudHJpZXMoa2V5OiBIYXNoTWFwIHwgTWFwPHN0cmluZywgSGFzaE1hcD4pIHtcbiAgICByZXR1cm4ga2V5IGluc3RhbmNlb2YgTWFwID8ga2V5LmVudHJpZXMoKSA6IE9iamVjdC5lbnRyaWVzKGtleSk7XG4gIH1cbn1cbiJdfQ==
|