@ngneat/transloco
Version:
The internationalization (i18n) library for Angular
578 lines • 79.7 kB
JavaScript
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