UNPKG

@ngneat/transloco

Version:

The internationalization (i18n) library for Angular

578 lines 79.7 kB
import { Inject, Injectable, Optional } from '@angular/core'; import { BehaviorSubject, catchError, combineLatest, EMPTY, forkJoin, from, map, of, retry, shareReplay, Subject, switchMap, tap, } from 'rxjs'; import { DefaultLoader, TRANSLOCO_LOADER, } from './transloco.loader'; import { TRANSLOCO_TRANSPILER, } from './transloco.transpiler'; import { flatten, isEmpty, isNil, isScopeArray, isScopeObject, isString, size, toCamelCase, unflatten, } from './helpers'; import { TRANSLOCO_CONFIG } from './transloco.config'; import { TRANSLOCO_MISSING_HANDLER, } from './transloco-missing-handler'; import { TRANSLOCO_INTERCEPTOR, } from './transloco.interceptor'; import { TRANSLOCO_FALLBACK_STRATEGY, } from './transloco-fallback-strategy'; import { getEventPayload, getLangFromScope, getScopeFromLang, resolveInlineLoader, } from './shared'; import { getFallbacksLoaders } from './get-fallbacks-loaders'; import { resolveLoader } from './resolve-loader'; import * as i0 from "@angular/core"; let service; export function translate(key, params = {}, lang) { return service.translate(key, params, lang); } export function translateObject(key, params = {}, lang) { return service.translateObject(key, params, lang); } export class TranslocoService { loader; parser; missingHandler; interceptor; fallbackStrategy; langChanges$; subscription = null; translations = new Map(); cache = new Map(); firstFallbackLang; defaultLang = ''; availableLangs = []; isResolvedMissingOnce = false; lang; failedLangs = new Set(); events = new Subject(); events$ = this.events.asObservable(); config; constructor(loader, parser, missingHandler, interceptor, userConfig, fallbackStrategy) { this.loader = loader; this.parser = parser; this.missingHandler = missingHandler; this.interceptor = interceptor; this.fallbackStrategy = fallbackStrategy; if (!this.loader) { this.loader = new DefaultLoader(this.translations); } service = this; this.config = JSON.parse(JSON.stringify(userConfig)); this.setAvailableLangs(this.config.availableLangs || []); this.setFallbackLangForMissingTranslation(this.config); this.setDefaultLang(this.config.defaultLang); this.lang = new BehaviorSubject(this.getDefaultLang()); // Don't use distinctUntilChanged as we need the ability to update // the value when using setTranslation or setTranslationKeys this.langChanges$ = this.lang.asObservable(); /** * When we have a failure, we want to define the next language that succeeded as the active */ this.subscription = this.events$.subscribe((e) => { if (e.type === 'translationLoadSuccess' && e.wasFailure) { this.setActiveLang(e.payload.langName); } }); } getDefaultLang() { return this.defaultLang; } setDefaultLang(lang) { this.defaultLang = lang; } getActiveLang() { return this.lang.getValue(); } setActiveLang(lang) { this.parser.onLangChanged?.(lang); this.lang.next(lang); this.events.next({ type: 'langChanged', payload: getEventPayload(lang), }); return this; } setAvailableLangs(langs) { this.availableLangs = langs; } /** * Gets the available languages. * * @returns * An array of the available languages. Can be either a `string[]` or a `{ id: string; label: string }[]` * depending on how the available languages are set in your module. */ getAvailableLangs() { return this.availableLangs; } load(path, options = {}) { const cached = this.cache.get(path); if (cached) { return cached; } let loadTranslation; const isScope = this._isLangScoped(path); let scope; if (isScope) { scope = getScopeFromLang(path); } const loadersOptions = { path, mainLoader: this.loader, inlineLoader: options.inlineLoader, data: isScope ? { scope: scope } : undefined, }; if (this.useFallbackTranslation(path)) { // if the path is scope the fallback should be `scope/fallbackLang`; const fallback = isScope ? `${scope}/${this.firstFallbackLang}` : this.firstFallbackLang; const loaders = getFallbacksLoaders({ ...loadersOptions, fallbackPath: fallback, }); loadTranslation = forkJoin(loaders); } else { const loader = resolveLoader(loadersOptions); loadTranslation = from(loader); } const load$ = loadTranslation.pipe(retry(this.config.failedRetries), tap((translation) => { if (Array.isArray(translation)) { translation.forEach((t) => { this.handleSuccess(t.lang, t.translation); // Save the fallback in cache so we'll not create a redundant request if (t.lang !== path) { this.cache.set(t.lang, of({})); } }); return; } this.handleSuccess(path, translation); }), catchError((error) => { if (!this.config.prodMode) { console.error(`Error while trying to load "${path}"`, error); } return this.handleFailure(path, options); }), shareReplay(1)); this.cache.set(path, load$); return load$; } /** * Gets the instant translated value of a key * * @example * * translate<string>('hello') * translate('hello', { value: 'value' }) * translate<string[]>(['hello', 'key']) * translate('hello', { }, 'en') * translate('scope.someKey', { }, 'en') */ translate(key, params = {}, lang = this.getActiveLang()) { if (!key) return key; const { scope, resolveLang } = this.resolveLangAndScope(lang); if (Array.isArray(key)) { return key.map((k) => this.translate(scope ? `${scope}.${k}` : k, params, resolveLang)); } key = scope ? `${scope}.${key}` : key; const translation = this.getTranslation(resolveLang); const value = translation[key]; if (!value) { return this._handleMissingKey(key, value, params); } return this.parser.transpile(value, params, translation, key); } /** * Gets the translated value of a key as observable * * @example * * selectTranslate<string>('hello').subscribe(value => ...) * selectTranslate<string>('hello', {}, 'es').subscribe(value => ...) * selectTranslate<string>('hello', {}, 'todos').subscribe(value => ...) * selectTranslate<string>('hello', {}, { scope: 'todos' }).subscribe(value => ...) * */ selectTranslate(key, params, lang, _isObject = false) { let inlineLoader; const load = (lang, options) => this.load(lang, options).pipe(map(() => _isObject ? this.translateObject(key, params, lang) : this.translate(key, params, lang))); if (isNil(lang)) { return this.langChanges$.pipe(switchMap((lang) => load(lang))); } if (isScopeArray(lang) || isScopeObject(lang)) { // it's a scope object. const providerScope = Array.isArray(lang) ? lang[0] : lang; lang = providerScope.scope; inlineLoader = resolveInlineLoader(providerScope, providerScope.scope); } lang = lang; if (this.isLang(lang) || this.isScopeWithLang(lang)) { return load(lang); } // it's a scope const scope = lang; return this.langChanges$.pipe(switchMap((lang) => load(`${scope}/${lang}`, { inlineLoader }))); } /** * Whether the scope with lang * * @example * * todos/en => true * todos => false */ isScopeWithLang(lang) { return this.isLang(getLangFromScope(lang)); } translateObject(key, params = {}, lang = this.getActiveLang()) { if (isString(key) || Array.isArray(key)) { const { resolveLang, scope } = this.resolveLangAndScope(lang); if (Array.isArray(key)) { return key.map((k) => this.translateObject(scope ? `${scope}.${k}` : k, params, resolveLang)); } const translation = this.getTranslation(resolveLang); key = scope ? `${scope}.${key}` : key; const value = unflatten(this.getObjectByKey(translation, key)); /* If an empty object was returned we want to try and translate the key as a string and not an object */ return isEmpty(value) ? this.translate(key, params, lang) : this.parser.transpile(value, params, translation, key); } const translations = []; for (const [_key, _params] of this.getEntries(key)) { translations.push(this.translateObject(_key, _params, lang)); } return translations; } selectTranslateObject(key, params, lang) { if (isString(key) || Array.isArray(key)) { return this.selectTranslate(key, params, lang, true); } const [[firstKey, firstParams], ...rest] = this.getEntries(key); /* In order to avoid subscribing multiple times to the load language event by calling selectTranslateObject for each pair, * we listen to when the first key has been translated (the language is loaded) and translate the rest synchronously */ return this.selectTranslateObject(firstKey, firstParams, lang).pipe(map((value) => { const translations = [value]; for (const [_key, _params] of rest) { translations.push(this.translateObject(_key, _params, lang)); } return translations; })); } getTranslation(langOrScope) { if (langOrScope) { if (this.isLang(langOrScope)) { return this.translations.get(langOrScope) || {}; } else { // This is a scope, build the scope value from the translation object const { scope, resolveLang } = this.resolveLangAndScope(langOrScope); const translation = this.translations.get(resolveLang) || {}; return this.getObjectByKey(translation, scope); } } return this.translations; } /** * Gets an object of translations for a given language * * @example * * selectTranslation().subscribe() - will return the current lang translation * selectTranslation('es').subscribe() * selectTranslation('admin-page').subscribe() - will return the current lang scope translation * selectTranslation('admin-page/es').subscribe() */ selectTranslation(lang) { let language$ = this.langChanges$; if (lang) { const scopeLangSpecified = getLangFromScope(lang) !== lang; if (this.isLang(lang) || scopeLangSpecified) { language$ = of(lang); } else { language$ = this.langChanges$.pipe(map((currentLang) => `${lang}/${currentLang}`)); } } return language$.pipe(switchMap((language) => this.load(language).pipe(map(() => this.getTranslation(language))))); } /** * Sets or merge a given translation object to current lang * * @example * * setTranslation({ ... }) * setTranslation({ ... }, 'en') * setTranslation({ ... }, 'es', { merge: false } ) * setTranslation({ ... }, 'todos/en', { merge: false } ) */ setTranslation(translation, lang = this.getActiveLang(), options = {}) { const defaults = { merge: true, emitChange: true }; const mergedOptions = { ...defaults, ...options }; const scope = getScopeFromLang(lang); /** * If this isn't a scope we use the whole translation as is * otherwise we need to flat the scope and use it */ let flattenScopeOrTranslation = translation; // Merged the scoped language into the active language if (scope) { const key = this.getMappedScope(scope); flattenScopeOrTranslation = flatten({ [key]: translation }); } const currentLang = scope ? getLangFromScope(lang) : lang; const mergedTranslation = { ...(mergedOptions.merge && this.getTranslation(currentLang)), ...flattenScopeOrTranslation, }; const flattenTranslation = this.config.flatten.aot ? mergedTranslation : flatten(mergedTranslation); const withHook = this.interceptor.preSaveTranslation(flattenTranslation, currentLang); this.translations.set(currentLang, withHook); mergedOptions.emitChange && this.setActiveLang(this.getActiveLang()); } /** * Sets translation key with given value * * @example * * setTranslationKey('key', 'value') * setTranslationKey('key.nested', 'value') * setTranslationKey('key.nested', 'value', 'en') * setTranslationKey('key.nested', 'value', 'en', { emitChange: false } ) */ setTranslationKey(key, value, // Todo: Add the lang to the options in v3 lang = this.getActiveLang(), options = {}) { const withHook = this.interceptor.preSaveTranslationKey(key, value, lang); const newValue = { [key]: withHook, }; this.setTranslation(newValue, lang, { ...options, merge: true }); } /** * Sets the fallback lang for the currently active language * @param fallbackLang */ setFallbackLangForMissingTranslation({ fallbackLang, }) { const lang = Array.isArray(fallbackLang) ? fallbackLang[0] : fallbackLang; if (fallbackLang && this.useFallbackTranslation(lang)) { this.firstFallbackLang = lang; } } /** * @internal */ _handleMissingKey(key, value, params) { if (this.config.missingHandler.allowEmpty && value === '') { return ''; } if (!this.isResolvedMissingOnce && this.useFallbackTranslation()) { // We need to set it to true to prevent a loop this.isResolvedMissingOnce = true; const fallbackValue = this.translate(key, params, this.firstFallbackLang); this.isResolvedMissingOnce = false; return fallbackValue; } return this.missingHandler.handle(key, this.getMissingHandlerData(), params); } /** * @internal */ _isLangScoped(lang) { return this.getAvailableLangsIds().indexOf(lang) === -1; } /** * Checks if a given string is one of the specified available languages. * @returns * True if the given string is an available language. * False if the given string is not an available language. */ isLang(lang) { return this.getAvailableLangsIds().indexOf(lang) !== -1; } /** * @internal * * We always want to make sure the global lang is loaded * before loading the scope since you can access both via the pipe/directive. */ _loadDependencies(path, inlineLoader) { const mainLang = getLangFromScope(path); if (this._isLangScoped(path) && !this.isLoadedTranslation(mainLang)) { return combineLatest([ this.load(mainLang), this.load(path, { inlineLoader }), ]); } return this.load(path, { inlineLoader }); } /** * @internal */ _completeScopeWithLang(langOrScope) { if (this._isLangScoped(langOrScope) && !this.isLang(getLangFromScope(langOrScope))) { return `${langOrScope}/${this.getActiveLang()}`; } return langOrScope; } /** * @internal */ _setScopeAlias(scope, alias) { if (!this.config.scopeMapping) { this.config.scopeMapping = {}; } this.config.scopeMapping[scope] = alias; } ngOnDestroy() { if (this.subscription) { this.subscription.unsubscribe(); // Caretaker note: it's important to clean up references to subscriptions since they save the `next` // callback within its `destination` property, preventing classes from being GC'd. this.subscription = null; } // Caretaker note: since this is the root provider, it'll be destroyed when the `NgModuleRef.destroy()` is run. // Cached values capture `this`, thus leading to a circular reference and preventing the `TranslocoService` from // being GC'd. This would lead to a memory leak when server-side rendering is used since the service is created // and destroyed per each HTTP request, but any service is not getting GC'd. this.cache.clear(); } isLoadedTranslation(lang) { return size(this.getTranslation(lang)); } getAvailableLangsIds() { const first = this.getAvailableLangs()[0]; if (isString(first)) { return this.getAvailableLangs(); } return this.getAvailableLangs().map((l) => l.id); } getMissingHandlerData() { return { ...this.config, activeLang: this.getActiveLang(), availableLangs: this.availableLangs, defaultLang: this.defaultLang, }; } /** * Use a fallback translation set for missing keys of the primary language * This is unrelated to the fallback language (which changes the active language) */ useFallbackTranslation(lang) { return (this.config.missingHandler.useFallbackTranslation && lang !== this.firstFallbackLang); } handleSuccess(lang, translation) { this.setTranslation(translation, lang, { emitChange: false }); this.events.next({ wasFailure: !!this.failedLangs.size, type: 'translationLoadSuccess', payload: getEventPayload(lang), }); this.failedLangs.forEach((l) => this.cache.delete(l)); this.failedLangs.clear(); } handleFailure(lang, loadOptions) { // When starting to load a first choice language, initialize // the failed counter and resolve the fallback langs. if (isNil(loadOptions.failedCounter)) { loadOptions.failedCounter = 0; if (!loadOptions.fallbackLangs) { loadOptions.fallbackLangs = this.fallbackStrategy.getNextLangs(lang); } } const splitted = lang.split('/'); const fallbacks = loadOptions.fallbackLangs; const nextLang = fallbacks[loadOptions.failedCounter]; this.failedLangs.add(lang); // This handles the case where a loaded fallback language is requested again if (this.cache.has(nextLang)) { this.handleSuccess(nextLang, this.getTranslation(nextLang)); return EMPTY; } const isFallbackLang = nextLang === splitted[splitted.length - 1]; if (!nextLang || isFallbackLang) { let msg = `Unable to load translation and all the fallback languages`; if (splitted.length > 1) { msg += `, did you misspelled the scope name?`; } throw new Error(msg); } let resolveLang = nextLang; // if it's scoped lang if (splitted.length > 1) { // We need to resolve it to: // todos/langNotExists => todos/nextLang splitted[splitted.length - 1] = nextLang; resolveLang = splitted.join('/'); } loadOptions.failedCounter++; this.events.next({ type: 'translationLoadFailure', payload: getEventPayload(lang), }); return this.load(resolveLang, loadOptions); } getMappedScope(scope) { const { scopeMapping = {} } = this.config; return scopeMapping[scope] || toCamelCase(scope); } /** * If lang is scope we need to check the following cases: * todos/es => in this case we should take `es` as lang * todos => in this case we should set the active lang as lang */ resolveLangAndScope(lang) { let resolveLang = lang; let scope; if (this._isLangScoped(lang)) { // en for example const langFromScope = getLangFromScope(lang); // en is lang const hasLang = this.isLang(langFromScope); // take en resolveLang = hasLang ? langFromScope : this.getActiveLang(); // find the scope scope = this.getMappedScope(hasLang ? getScopeFromLang(lang) : lang); } return { scope, resolveLang }; } getObjectByKey(translation, key) { const result = {}; const prefix = `${key}.`; for (const currentKey in translation) { if (currentKey.startsWith(prefix)) { result[currentKey.replace(prefix, '')] = translation[currentKey]; } } return result; } getEntries(key) { return key instanceof Map ? key.entries() : Object.entries(key); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", 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 }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: TranslocoService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: TranslocoService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [TRANSLOCO_LOADER] }] }, { type: undefined, decorators: [{ type: Inject, args: [TRANSLOCO_TRANSPILER] }] }, { type: undefined, decorators: [{ type: Inject, args: [TRANSLOCO_MISSING_HANDLER] }] }, { type: undefined, decorators: [{ type: Inject, args: [TRANSLOCO_INTERCEPTOR] }] }, { type: undefined, decorators: [{ type: Inject, args: [TRANSLOCO_CONFIG] }] }, { type: undefined, decorators: [{ type: Inject, args: [TRANSLOCO_FALLBACK_STRATEGY] }] }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsb2NvLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWJzL3RyYW5zbG9jby9zcmMvbGliL3RyYW5zbG9jby5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFhLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN4RSxPQUFPLEVBQ0wsZUFBZSxFQUNmLFVBQVUsRUFDVixhQUFhLEVBQ2IsS0FBSyxFQUNMLFFBQVEsRUFDUixJQUFJLEVBQ0osR0FBRyxFQUVILEVBQUUsRUFDRixLQUFLLEVBQ0wsV0FBVyxFQUNYLE9BQU8sRUFFUCxTQUFTLEVBQ1QsR0FBRyxHQUNKLE1BQU0sTUFBTSxDQUFDO0FBRWQsT0FBTyxFQUNMLGFBQWEsRUFDYixnQkFBZ0IsR0FFakIsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQ0wsb0JBQW9CLEdBRXJCLE1BQU0sd0JBQXdCLENBQUM7QUFjaEMsT0FBTyxFQUNMLE9BQU8sRUFDUCxPQUFPLEVBQ1AsS0FBSyxFQUNMLFlBQVksRUFDWixhQUFhLEVBQ2IsUUFBUSxFQUNSLElBQUksRUFDSixXQUFXLEVBQ1gsU0FBUyxHQUNWLE1BQU0sV0FBVyxDQUFDO0FBQ25CLE9BQU8sRUFBRSxnQkFBZ0IsRUFBbUIsTUFBTSxvQkFBb0IsQ0FBQztBQUN2RSxPQUFPLEVBQ0wseUJBQXlCLEdBRzFCLE1BQU0sNkJBQTZCLENBQUM7QUFDckMsT0FBTyxFQUNMLHFCQUFxQixHQUV0QixNQUFNLHlCQUF5QixDQUFDO0FBQ2pDLE9BQU8sRUFDTCwyQkFBMkIsR0FFNUIsTUFBTSwrQkFBK0IsQ0FBQztBQUN2QyxPQUFPLEVBQ0wsZUFBZSxFQUNmLGdCQUFnQixFQUNoQixnQkFBZ0IsRUFDaEIsbUJBQW1CLEdBQ3BCLE1BQU0sVUFBVSxDQUFDO0FBQ2xCLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHlCQUF5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QUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2xFLENBQUM7dUdBdHVCVSxnQkFBZ0Isa0JBb0JMLGdCQUFnQiw2QkFDNUIsb0JBQW9CLGFBQ3BCLHlCQUF5QixhQUV6QixxQkFBcUIsYUFDckIsZ0JBQWdCLGFBQ2hCLDJCQUEyQjsyR0ExQjFCLGdCQUFnQixjQURILE1BQU07OzJGQUNuQixnQkFBZ0I7a0JBRDVCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFOzswQkFxQjdCLFFBQVE7OzBCQUFJLE1BQU07MkJBQUMsZ0JBQWdCOzswQkFDbkMsTUFBTTsyQkFBQyxvQkFBb0I7OzBCQUMzQixNQUFNOzJCQUFDLHlCQUF5Qjs7MEJBRWhDLE1BQU07MkJBQUMscUJBQXFCOzswQkFDNUIsTUFBTTsyQkFBQyxnQkFBZ0I7OzBCQUN2QixNQUFNOzJCQUFDLDJCQUEyQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSwgT25EZXN0cm95LCBPcHRpb25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgQmVoYXZpb3JTdWJqZWN0LFxuICBjYXRjaEVycm9yLFxuICBjb21iaW5lTGF0ZXN0LFxuICBFTVBUWSxcbiAgZm9ya0pvaW4sXG4gIGZyb20sXG4gIG1hcCxcbiAgT2JzZXJ2YWJsZSxcbiAgb2YsXG4gIHJldHJ5LFxuICBzaGFyZVJlcGxheSxcbiAgU3ViamVjdCxcbiAgU3Vic2NyaXB0aW9uLFxuICBzd2l0Y2hNYXAsXG4gIHRhcCxcbn0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB7XG4gIERlZmF1bHRMb2FkZXIsXG4gIFRSQU5TTE9DT19MT0FERVIsXG4gIFRyYW5zbG9jb0xvYWRlcixcbn0gZnJvbSAnLi90cmFuc2xvY28ubG9hZGVyJztcbmltcG9ydCB7XG4gIFRSQU5TTE9DT19UUkFOU1BJTEVSLFxuICBUcmFuc2xvY29UcmFuc3BpbGVyLFxufSBmcm9tICcuL3RyYW5zbG9jby50cmFuc3BpbGVyJztcbmltcG9ydCB7XG4gIEF2YWlsYWJsZUxhbmdzLFxuICBIYXNoTWFwLFxuICBJbmxpbmVMb2FkZXIsXG4gIExhbmdEZWZpbml0aW9uLFxuICBMb2FkT3B0aW9ucyxcbiAgU2V0VHJhbnNsYXRpb25PcHRpb25zLFxuICBUcmFuc2xhdGVPYmplY3RQYXJhbXMsXG4gIFRyYW5zbGF0ZVBhcmFtcyxcbiAgVHJhbnNsYXRpb24sXG4gIFRyYW5zbG9jb0V2ZW50cyxcbiAgVHJhbnNsb2NvU2NvcGUsXG59IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHtcbiAgZmxhdHRlbixcbiAgaXNFbXB0eSxcbiAgaXNOaWwsXG4gIGlzU2NvcGVBcnJheSxcbiAgaXNTY29wZU9iamVjdCxcbiAgaXNTdHJpbmcsXG4gIHNpemUsXG4gIHRvQ2FtZWxDYXNlLFxuICB1bmZsYXR0ZW4sXG59IGZyb20gJy4vaGVscGVycyc7XG5pbXBvcnQgeyBUUkFOU0xPQ09fQ09ORklHLCBUcmFuc2xvY29Db25maWcgfSBmcm9tICcuL3RyYW5zbG9jby5jb25maWcnO1xuaW1wb3J0IHtcbiAgVFJBTlNMT0NPX01JU1NJTkdfSEFORExFUixcbiAgVHJhbnNsb2NvTWlzc2luZ0hhbmRsZXIsXG4gIFRyYW5zbG9jb01pc3NpbmdIYW5kbGVyRGF0YSxcbn0gZnJvbSAnLi90cmFuc2xvY28tbWlzc2luZy1oYW5kbGVyJztcbmltcG9ydCB7XG4gIFRSQU5TTE9DT19JTlRFUkNFUFRPUixcbiAgVHJhbnNsb2NvSW50ZXJjZXB0b3IsXG59IGZyb20gJy4vdHJhbnNsb2NvLmludGVyY2VwdG9yJztcbmltcG9ydCB7XG4gIFRSQU5TTE9DT19GQUxMQkFDS19TVFJBVEVHWSxcbiAgVHJhbnNsb2NvRmFsbGJhY2tTdHJhdGVneSxcbn0gZnJvbSAnLi90cmFuc2xvY28tZmFsbGJhY2stc3RyYXRlZ3knO1xuaW1wb3J0IHtcbiAgZ2V0RXZlbnRQYXlsb2FkLFxuICBnZXRMYW5nRnJvbVNjb3BlLFxuICBnZXRTY29wZUZyb21MYW5nLFxuICByZXNvbHZlSW5saW5lTG9hZGVyLFxufSBmcm9tICcuL3NoYXJlZCc7XG5pbXBvcnQgeyBnZXRGYWxsYmFja3NMb2FkZXJzIH0gZnJvbSAnLi9nZXQtZmFsbGJhY2tzLWxvYWRlcnMnO1xuaW1wb3J0IHsgcmVzb2x2ZUxvYWRlciB9IGZyb20gJy4vcmVzb2x2ZS1sb2FkZXInO1xuXG5sZXQgc2VydmljZTogVHJhbnNsb2NvU2VydmljZTtcblxuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zbGF0ZTxUID0gc3RyaW5nPihcbiAga2V5OiBUcmFuc2xhdGVQYXJhbXMsXG4gIHBhcmFtczogSGFzaE1hcCA9IHt9LFxuICBsYW5nPzogc3RyaW5nXG4pOiBUIHtcbiAgcmV0dXJuIHNlcnZpY2UudHJhbnNsYXRlPFQ+KGtleSwgcGFyYW1zLCBsYW5nKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zbGF0ZU9iamVjdDxUPihcbiAga2V5OiBUcmFuc2xhdGVQYXJhbXMsXG4gIHBhcmFtczogSGFzaE1hcCA9IHt9LFxuICBsYW5nPzogc3RyaW5nXG4pOiBUIHwgVFtdIHtcbiAgcmV0dXJuIHNlcnZpY2UudHJhbnNsYXRlT2JqZWN0PFQ+KGtleSwgcGFyYW1zLCBsYW5nKTtcbn1cblxuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBUcmFuc2xvY29TZXJ2aWNlIGltcGxlbWVudHMgT25EZXN0cm95IHtcbiAgbGFuZ0NoYW5nZXMkOiBPYnNlcnZhYmxlPHN0cmluZz47XG5cbiAgcHJpdmF0ZSBzdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbiB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHRyYW5zbGF0aW9ucyA9IG5ldyBNYXA8c3RyaW5nLCBUcmFuc2xhdGlvbj4oKTtcbiAgcHJpdmF0ZSBjYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCBPYnNlcnZhYmxlPFRyYW5zbGF0aW9uPj4oKTtcbiAgcHJpdmF0ZSBmaXJzdEZhbGxiYWNrTGFuZzogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIGRlZmF1bHRMYW5nID0gJyc7XG4gIHByaXZhdGUgYXZhaWxhYmxlTGFuZ3M6IEF2YWlsYWJsZUxhbmdzID0gW107XG4gIHByaXZhdGUgaXNSZXNvbHZlZE1pc3NpbmdPbmNlID0gZmFsc2U7XG4gIHByaXZhdGUgbGFuZzogQmVoYXZpb3JTdWJqZWN0PHN0cmluZz47XG4gIHByaXZhdGUgZm