@jsverse/transloco
Version:
The internationalization (i18n) library for Angular
577 lines • 79.8 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 { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { DefaultLoader, TRANSLOCO_LOADER, } from './transloco.loader';
import { TRANSLOCO_TRANSPILER, } from './transloco.transpiler';
import { flatten, isEmpty, isNil, 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$;
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.events$.pipe(takeUntilDestroyed()).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)));
}
lang = Array.isArray(lang) ? lang[0] : lang;
if (isScopeObject(lang)) {
// it's a scope object.
const providerScope = 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: 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, options = {}) {
const lang = options.lang || this.getActiveLang();
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() {
// 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 = {}, scopes = { keepCasing: false } } = this.config;
return (scopeMapping[scope] || (scopes.keepCasing ? 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: "18.0.4", 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: "18.0.4", ngImport: i0, type: TranslocoService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.4", ngImport: i0, type: TranslocoService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsb2NvLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWJzL3RyYW5zbG9jby9zcmMvbGliL3RyYW5zbG9jby5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFhLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN4RSxPQUFPLEVBQ0wsZUFBZSxFQUNmLFVBQVUsRUFDVixhQUFhLEVBQ2IsS0FBSyxFQUNMLFFBQVEsRUFDUixJQUFJLEVBQ0osR0FBRyxFQUVILEVBQUUsRUFDRixLQUFLLEVBQ0wsV0FBVyxFQUNYLE9BQU8sRUFDUCxTQUFTLEVBQ1QsR0FBRyxHQUNKLE1BQU0sTUFBTSxDQUFDO0FBQ2QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFaEUsT0FBTyxFQUNMLGFBQWEsRUFDYixnQkFBZ0IsR0FFakIsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQ0wsb0JBQW9CLEdBRXJCLE1BQU0sd0JBQXdCLENBQUM7QUFjaEMsT0FBTyxFQUNMLE9BQU8sRUFDUCxPQUFPLEVBQ1AsS0FBSyxFQUNMLGFBQWEsRUFDYixRQUFRLEVBQ1IsSUFBSSxFQUNKLFdBQVcsRUFDWCxTQUFTLEdBQ1YsTUFBTSxXQUFXLENBQUM7QUFDbkIsT0FBTyxFQUFFLGdCQUFnQixFQUFtQixNQUFNLG9CQUFvQixDQUFDO0FBQ3ZFLE9BQU8sRUFDTCx5QkFBeUIsR0FHMUIsTUFBTSw2QkFBNkIsQ0FBQztBQUNyQyxPQUFPLEVBQ0wscUJBQXFCLEdBRXRCLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxFQUNMLDJCQUEyQixHQUU1QixNQUFNLCtCQUErQixDQUFDO0FBQ3ZDLE9BQU8sRUFDTCxlQUFlLEVBQ2YsZ0JBQWdCLEVBQ2hCLGdCQUFnQixFQUNoQixtQkFBbUIsR0FDcEIsTUFBTSxVQUFVLENBQUM7QUFD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amVjdCwgSW5qZWN0YWJsZSwgT25EZXN0cm95LCBPcHRpb25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgQmVoYXZpb3JTdWJqZWN0LFxuICBjYXRjaEVycm9yLFxuICBjb21iaW5lTGF0ZXN0LFxuICBFTVBUWSxcbiAgZm9ya0pvaW4sXG4gIGZyb20sXG4gIG1hcCxcbiAgT2JzZXJ2YWJsZSxcbiAgb2YsXG4gIHJldHJ5LFxuICBzaGFyZVJlcGxheSxcbiAgU3ViamVjdCxcbiAgc3dpdGNoTWFwLFxuICB0YXAsXG59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgdGFrZVVudGlsRGVzdHJveWVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xuXG5pbXBvcnQge1xuICBEZWZhdWx0TG9hZGVyLFxuICBUUkFOU0xPQ09fTE9BREVSLFxuICBUcmFuc2xvY29Mb2FkZXIsXG59IGZyb20gJy4vdHJhbnNsb2NvLmxvYWRlcic7XG5pbXBvcnQge1xuICBUUkFOU0xPQ09fVFJBTlNQSUxFUixcbiAgVHJhbnNsb2NvVHJhbnNwaWxlcixcbn0gZnJvbSAnLi90cmFuc2xvY28udHJhbnNwaWxlcic7XG5pbXBvcnQge1xuICBBdmFpbGFibGVMYW5ncyxcbiAgSGFzaE1hcCxcbiAgSW5saW5lTG9hZGVyLFxuICBMYW5nRGVmaW5pdGlvbixcbiAgTG9hZE9wdGlvbnMsXG4gIFNldFRyYW5zbGF0aW9uT3B0aW9ucyxcbiAgVHJhbnNsYXRlT2JqZWN0UGFyYW1zLFxuICBUcmFuc2xhdGVQYXJhbXMsXG4gIFRyYW5zbGF0aW9uLFxuICBUcmFuc2xvY29FdmVudHMsXG4gIFRyYW5zbG9jb1Njb3BlLFxufSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB7XG4gIGZsYXR0ZW4sXG4gIGlzRW1wdHksXG4gIGlzTmlsLFxuICBpc1Njb3BlT2JqZWN0LFxuICBpc1N0cmluZyxcbiAgc2l6ZSxcbiAgdG9DYW1lbENhc2UsXG4gIHVuZmxhdHRlbixcbn0gZnJvbSAnLi9oZWxwZXJzJztcbmltcG9ydCB7IFRSQU5TTE9DT19DT05GSUcsIFRyYW5zbG9jb0NvbmZpZyB9IGZyb20gJy4vdHJhbnNsb2NvLmNvbmZpZyc7XG5pbXBvcnQge1xuICBUUkFOU0xPQ09fTUlTU0lOR19IQU5ETEVSLFxuICBUcmFuc2xvY29NaXNzaW5nSGFuZGxlcixcbiAgVHJhbnNsb2NvTWlzc2luZ0hhbmRsZXJEYXRhLFxufSBmcm9tICcuL3RyYW5zbG9jby1taXNzaW5nLWhhbmRsZXInO1xuaW1wb3J0IHtcbiAgVFJBTlNMT0NPX0lOVEVSQ0VQVE9SLFxuICBUcmFuc2xvY29JbnRlcmNlcHRvcixcbn0gZnJvbSAnLi90cmFuc2xvY28uaW50ZXJjZXB0b3InO1xuaW1wb3J0IHtcbiAgVFJBTlNMT0NPX0ZBTExCQUNLX1NUUkFURUdZLFxuICBUcmFuc2xvY29GYWxsYmFja1N0cmF0ZWd5LFxufSBmcm9tICcuL3RyYW5zbG9jby1mYWxsYmFjay1zdHJhdGVneSc7XG5pbXBvcnQge1xuICBnZXRFdmVudFBheWxvYWQsXG4gIGdldExhbmdGcm9tU2NvcGUsXG4gIGdldFNjb3BlRnJvbUxhbmcsXG4gIHJlc29sdmVJbmxpbmVMb2FkZXIsXG59IGZyb20gJy4vc2hhcmVkJztcbmltcG9ydCB7IGdldEZhbGxiYWNrc0xvYWRlcnMgfSBmcm9tICcuL2dldC1mYWxsYmFja3MtbG9hZGVycyc7XG5pbXBvcnQgeyByZXNvbHZlTG9hZGVyIH0gZnJvbSAnLi9yZXNvbHZlLWxvYWRlcic7XG5cbmxldCBzZXJ2aWNlOiBUcmFuc2xvY29TZXJ2aWNlO1xuXG5leHBvcnQgZnVuY3Rpb24gdHJhbnNsYXRlPFQgPSBzdHJpbmc+KFxuICBrZXk6IFRyYW5zbGF0ZVBhcmFtcyxcbiAgcGFyYW1zOiBIYXNoTWFwID0ge30sXG4gIGxhbmc/OiBzdHJpbmcsXG4pOiBUIHtcbiAgcmV0dXJuIHNlcnZpY2UudHJhbnNsYXRlPFQ+KGtleSwgcGFyYW1zLCBsYW5nKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zbGF0ZU9iamVjdDxUPihcbiAga2V5OiBUcmFuc2xhdGVQYXJhbXMsXG4gIHBhcmFtczogSGFzaE1hcCA9IHt9LFxuICBsYW5nPzogc3RyaW5nLFxuKTogVCB8IFRbXSB7XG4gIHJldHVybiBzZXJ2aWNlLnRyYW5zbGF0ZU9iamVjdDxUPihrZXksIHBhcmFtcywgbGFuZyk7XG59XG5cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgVHJhbnNsb2NvU2VydmljZSBpbXBsZW1lbnRzIE9uRGVzdHJveSB7XG4gIGxhbmdDaGFuZ2VzJDogT2JzZXJ2YWJsZTxzdHJpbmc+O1xuXG4gIHByaXZhdGUgdHJhbnNsYXRpb25zID0gbmV3IE1hcDxzdHJpbmcsIFRyYW5zbGF0aW9uPig