@angular/core
Version:
Angular - the core framework
121 lines • 17.6 kB
JavaScript
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// i18nPostprocess consts
const ROOT_TEMPLATE_ID = 0;
const PP_MULTI_VALUE_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]/;
const PP_PLACEHOLDERS_REGEXP = /\[(�.+?�?)\]|(�\/?\*\d+:\d+�)/g;
const PP_ICU_VARS_REGEXP = /({\s*)(VAR_(PLURAL|SELECT)(_\d+)?)(\s*,)/g;
const PP_ICU_PLACEHOLDERS_REGEXP = /{([A-Z0-9_]+)}/g;
const PP_ICUS_REGEXP = /�I18N_EXP_(ICU(_\d+)?)�/g;
const PP_CLOSE_TEMPLATE_REGEXP = /\/\*/;
const PP_TEMPLATE_ID_REGEXP = /\d+\:(\d+)/;
/**
* Handles message string post-processing for internationalization.
*
* Handles message string post-processing by transforming it from intermediate
* format (that might contain some markers that we need to replace) to the final
* form, consumable by i18nStart instruction. Post processing steps include:
*
* 1. Resolve all multi-value cases (like [�*1:1��#2:1�|�#4:1�|�5�])
* 2. Replace all ICU vars (like "VAR_PLURAL")
* 3. Replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
* 4. Replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�)
* in case multiple ICUs have the same placeholder name
*
* @param message Raw translation string for post processing
* @param replacements Set of replacements that should be applied
*
* @returns Transformed string that can be consumed by i18nStart instruction
*
* @codeGenApi
*/
export function i18nPostprocess(message, replacements = {}) {
/**
* Step 1: resolve all multi-value placeholders like [�#5�|�*1:1��#2:1�|�#4:1�]
*
* Note: due to the way we process nested templates (BFS), multi-value placeholders are typically
* grouped by templates, for example: [�#5�|�#6�|�#1:1�|�#3:2�] where �#5� and �#6� belong to root
* template, �#1:1� belong to nested template with index 1 and �#1:2� - nested template with index
* 3. However in real templates the order might be different: i.e. �#1:1� and/or �#3:2� may go in
* front of �#6�. The post processing step restores the right order by keeping track of the
* template id stack and looks for placeholders that belong to the currently active template.
*/
let result = message;
if (PP_MULTI_VALUE_PLACEHOLDERS_REGEXP.test(message)) {
const matches = {};
const templateIdsStack = [ROOT_TEMPLATE_ID];
result = result.replace(PP_PLACEHOLDERS_REGEXP, (m, phs, tmpl) => {
const content = phs || tmpl;
const placeholders = matches[content] || [];
if (!placeholders.length) {
content.split('|').forEach((placeholder) => {
const match = placeholder.match(PP_TEMPLATE_ID_REGEXP);
const templateId = match ? parseInt(match[1], 10) : ROOT_TEMPLATE_ID;
const isCloseTemplateTag = PP_CLOSE_TEMPLATE_REGEXP.test(placeholder);
placeholders.push([templateId, isCloseTemplateTag, placeholder]);
});
matches[content] = placeholders;
}
if (!placeholders.length) {
throw new Error(`i18n postprocess: unmatched placeholder - ${content}`);
}
const currentTemplateId = templateIdsStack[templateIdsStack.length - 1];
let idx = 0;
// find placeholder index that matches current template id
for (let i = 0; i < placeholders.length; i++) {
if (placeholders[i][0] === currentTemplateId) {
idx = i;
break;
}
}
// update template id stack based on the current tag extracted
const [templateId, isCloseTemplateTag, placeholder] = placeholders[idx];
if (isCloseTemplateTag) {
templateIdsStack.pop();
}
else if (currentTemplateId !== templateId) {
templateIdsStack.push(templateId);
}
// remove processed tag from the list
placeholders.splice(idx, 1);
return placeholder;
});
}
// return current result if no replacements specified
if (!Object.keys(replacements).length) {
return result;
}
/**
* Step 2: replace all ICU vars (like "VAR_PLURAL")
*/
result = result.replace(PP_ICU_VARS_REGEXP, (match, start, key, _type, _idx, end) => {
return replacements.hasOwnProperty(key) ? `${start}${replacements[key]}${end}` : match;
});
/**
* Step 3: replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
*/
result = result.replace(PP_ICU_PLACEHOLDERS_REGEXP, (match, key) => {
return replacements.hasOwnProperty(key) ? replacements[key] : match;
});
/**
* Step 4: replace all ICU references with corresponding values (like �ICU_EXP_ICU_1�) in case
* multiple ICUs have the same placeholder name
*/
result = result.replace(PP_ICUS_REGEXP, (match, key) => {
if (replacements.hasOwnProperty(key)) {
const list = replacements[key];
if (!list.length) {
throw new Error(`i18n postprocess: unmatched ICU - ${match} with key: ${key}`);
}
return list.shift();
}
return match;
});
return result;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaTE4bl9wb3N0cHJvY2Vzcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL2NvcmUvc3JjL3JlbmRlcjMvaTE4bi9pMThuX3Bvc3Rwcm9jZXNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILHlCQUF5QjtBQUN6QixNQUFNLGdCQUFnQixHQUFHLENBQUMsQ0FBQztBQUMzQixNQUFNLGtDQUFrQyxHQUFHLGNBQWMsQ0FBQztBQUMxRCxNQUFNLHNCQUFzQixHQUFHLGdDQUFnQyxDQUFDO0FBQ2hFLE1BQU0sa0JBQWtCLEdBQUcsMkNBQTJDLENBQUM7QUFDdkUsTUFBTSwwQkFBMEIsR0FBRyxpQkFBaUIsQ0FBQztBQUNyRCxNQUFNLGNBQWMsR0FBRywwQkFBMEIsQ0FBQztBQUNsRCxNQUFNLHdCQUF3QixHQUFHLE1BQU0sQ0FBQztBQUN4QyxNQUFNLHFCQUFxQixHQUFHLFlBQVksQ0FBQztBQU8zQzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUNILE1BQU0sVUFBVSxlQUFlLENBQzNCLE9BQWUsRUFBRSxlQUFtRCxFQUFFO0lBQ3hFOzs7Ozs7Ozs7T0FTRztJQUNILElBQUksTUFBTSxHQUFXLE9BQU8sQ0FBQztJQUM3QixJQUFJLGtDQUFrQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQ3JELE1BQU0sT0FBTyxHQUE4QyxFQUFFLENBQUM7UUFDOUQsTUFBTSxnQkFBZ0IsR0FBYSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDdEQsTUFBTSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsc0JBQXNCLEVBQUUsQ0FBQyxDQUFNLEVBQUUsR0FBVyxFQUFFLElBQVksRUFBVSxFQUFFO1lBQzVGLE1BQU0sT0FBTyxHQUFHLEdBQUcsSUFBSSxJQUFJLENBQUM7WUFDNUIsTUFBTSxZQUFZLEdBQTZCLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxF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QVksQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQVcsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQ2hGLENBQUMsQ0FBQyxDQUFDO0lBRUg7OztPQUdHO0lBQ0gsTUFBTSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsY0FBYyxFQUFFLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBVSxFQUFFO1FBQzdELElBQUksWUFBWSxDQUFDLGNBQWMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3JDLE1BQU0sSUFBSSxHQUFHLFlBQVksQ0FBQyxHQUFHLENBQWEsQ0FBQztZQUMzQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUNqQixNQUFNLElBQUksS0FBSyxDQUFDLHFDQUFxQyxLQUFLLGNBQWMsR0FBRyxFQUFFLENBQUMsQ0FBQztZQUNqRixDQUFDO1lBQ0QsT0FBTyxJQUFJLENBQUMsS0FBSyxFQUFHLENBQUM7UUFDdkIsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQyxDQUFDLENBQUM7SUFFSCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbi8vIGkxOG5Qb3N0cHJvY2VzcyBjb25zdHNcbmNvbnN0IFJPT1RfVEVNUExBVEVfSUQgPSAwO1xuY29uc3QgUFBfTVVMVElfVkFMVUVfUExBQ0VIT0xERVJTX1JFR0VYUCA9IC9cXFso77+9Lis/77+9PylcXF0vO1xuY29uc3QgUFBfUExBQ0VIT0xERVJTX1JFR0VYUCA9IC9cXFso77+9Lis/77+9PylcXF18KO+/vVxcLz9cXCpcXGQrOlxcZCvvv70pL2c7XG5jb25zdCBQUF9JQ1VfVkFSU19SRUdFWFAgPSAvKHtcXHMqKShWQVJfKFBMVVJBTHxTRUxFQ1QpKF9cXGQrKT8pKFxccyosKS9nO1xuY29uc3QgUFBfSUNVX1BMQUNFSE9MREVSU19SRUdFWFAgPSAveyhbQS1aMC05X10rKX0vZztcbmNvbnN0IFBQX0lDVVNfUkVHRVhQID0gL++/vUkxOE5fRVhQXyhJQ1UoX1xcZCspPynvv70vZztcbmNvbnN0IFBQX0NMT1NFX1RFTVBMQVRFX1JFR0VYUCA9IC9cXC9cXCovO1xuY29uc3QgUFBfVEVNUExBVEVfSURfUkVHRVhQID0gL1xcZCtcXDooXFxkKykvO1xuXG4vLyBQYXJzZWQgcGxhY2Vob2xkZXIgc3RydWN0dXJlIHVzZWQgaW4gcG9zdHByb2Nlc3NpbmcgKHdpdGhpbiBgaTE4blBvc3Rwcm9jZXNzYCBmdW5jdGlvbilcbi8vIENvbnRhaW5zIHRoZSBmb2xsb3dpbmcgZmllbGRzOiBbdGVtcGxhdGVJZCwgaXNDbG9zZVRlbXBsYXRlVGFnLCBwbGFjZWhvbGRlcl1cbnR5cGUgUG9zdHByb2Nlc3NQbGFjZWhvbGRlciA9IFtudW1iZXIsIGJvb2xlYW4sIHN0cmluZ107XG5cblxuLyoqXG4gKiBIYW5kbGVzIG1lc3NhZ2Ugc3RyaW5nIHBvc3QtcHJvY2Vzc2luZyBmb3IgaW50ZXJuYXRpb25hbGl6YXRpb24uXG4gKlxuICogSGFuZGxlcyBtZXNzYWdlIHN0cmluZyBwb3N0LXByb2Nlc3NpbmcgYnkgdHJhbnNmb3JtaW5nIGl0IGZyb20gaW50ZXJtZWRpYXRlXG4gKiBmb3JtYXQgKHRoYXQgbWlnaHQgY29udGFpbiBzb21lIG1hcmtlcnMgdGhhdCB3ZSBuZWVkIHRvIHJlcGxhY2UpIHRvIHRoZSBmaW5hbFxuICogZm9ybSwgY29uc3VtYWJsZSBieSBpMThuU3RhcnQgaW5zdHJ1Y3Rpb24uIFBvc3QgcHJvY2Vzc2luZyBzdGVwcyBpbmNsdWRlOlxuICpcbiAqIDEuIFJlc29sdmUgYWxsIG11bHRpLXZhbHVlIGNhc2VzIChsaWtlIFvvv70qMTox77+977+9IzI6Me+/vXzvv70jNDox77+9fO+/vTXvv71dKVxuICogMi4gUmVwbGFjZSBhbGwgSUNVIHZhcnMgKGxpa2UgXCJWQVJfUExVUkFMXCIpXG4gKiAzLiBSZXBsYWNlIGFsbCBwbGFjZWhvbGRlcnMgdXNlZCBpbnNpZGUgSUNVcyBpbiBhIGZvcm0gb2Yge1BMQUNFSE9MREVSfVxuICogNC4gUmVwbGFjZSBhbGwgSUNVIHJlZmVyZW5jZXMgd2l0aCBjb3JyZXNwb25kaW5nIHZhbHVlcyAobGlrZSDvv71JQ1VfRVhQX0lDVV8x77+9KVxuICogICAgaW4gY2FzZSBtdWx0aXBsZSBJQ1VzIGhhdmUgdGhlIHNhbWUgcGxhY2Vob2xkZXIgbmFtZVxuICpcbiAqIEBwYXJhbSBtZXNzYWdlIFJhdyB0cmFuc2xhdGlvbiBzdHJpbmcgZm9yIHBvc3QgcHJvY2Vzc2luZ1xuICogQHBhcmFtIHJlcGxhY2VtZW50cyBTZXQgb2YgcmVwbGFjZW1lbnRzIHRoYXQgc2hvdWxkIGJlIGFwcGxpZWRcbiAqXG4gKiBAcmV0dXJucyBUcmFuc2Zvcm1lZCBzdHJpbmcgdGhhdCBjYW4gYmUgY29uc3VtZWQgYnkgaTE4blN0YXJ0IGluc3RydWN0aW9uXG4gKlxuICogQGNvZGVHZW5BcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGkxOG5Qb3N0cHJvY2VzcyhcbiAgICBtZXNzYWdlOiBzdHJpbmcsIHJlcGxhY2VtZW50czoge1trZXk6IHN0cmluZ106IChzdHJpbmd8c3RyaW5nW10pfSA9IHt9KTogc3RyaW5nIHtcbiAgLyoqXG4gICAqIFN0ZXAgMTogcmVzb2x2ZSBhbGwgbXVsdGktdmFsdWUgcGxhY2Vob2xkZXJzIGxpa2UgW++/vSM177+9fO+/vSoxOjHvv73vv70jMjox77+9fO+/vSM0OjHvv71dXG4gICAqXG4gICAqIE5vdGU6IGR1ZSB0byB0aGUgd2F5IHdlIHByb2Nlc3MgbmVzdGVkIHRlbXBsYXRlcyAoQkZTKSwgbXVsdGktdmFsdWUgcGxhY2Vob2xkZXJzIGFyZSB0eXBpY2FsbHlcbiAgICogZ3JvdXBlZCBieSB0ZW1wbGF0ZXMsIGZvciBleGFtcGxlOiBb77+9IzXvv71877+9Izbvv71877+9IzE6Me+/vXzvv70jMzoy77+9XSB3aGVyZSDvv70jNe+/vSBhbmQg77+9Izbvv70gYmVsb25nIHRvIHJvb3RcbiAgICogdGVtcGxhdGUsIO+/vSMxOjHvv70gYmVsb25nIHRvIG5lc3RlZCB0ZW1wbGF0ZSB3aXRoIGluZGV4IDEgYW5kIO+/vSMxOjLvv70gLSBuZXN0ZWQgdGVtcGxhdGUgd2l0aCBpbmRleFxuICAgKiAzLiBIb3dldmVyIGluIHJlYWwgdGVtcGxhdGVzIHRoZSBvcmRlciBtaWdodCBiZSBkaWZmZXJlbnQ6IGkuZS4g77+9IzE6Me+/vSBhbmQvb3Ig77+9IzM6Mu+/vSBtYXkgZ28gaW5cbiAgICogZnJvbnQgb2Yg77+9Izbvv70uIFRoZSBwb3N0IHByb2Nlc3Npbmcgc3RlcCByZXN0b3JlcyB0aGUgcmlnaHQgb3JkZXIgYnkga2VlcGluZyB0cmFjayBvZiB0aGVcbiAgICogdGVtcGxhdGUgaWQgc3RhY2sgYW5kIGxvb2tzIGZvciBwbGFjZWhvbGRlcnMgdGhhdCBiZWxvbmcgdG8gdGhlIGN1cnJlbnRseSBhY3RpdmUgdGVtcGxhdGUuXG4gICAqL1xuICBsZXQgcmVzdWx0OiBzdHJpbmcgPSBtZXNzYWdlO1xuICBpZiAoUFBfTVVMVElfVkFMVUVfUExBQ0VIT0xERVJTX1JFR0VYUC50ZXN0KG1lc3NhZ2UpKSB7XG4gICAgY29uc3QgbWF0Y2hlczoge1trZXk6IHN0cmluZ106IFBvc3Rwcm9jZXNzUGxhY2Vob2xkZXJbXX0gPSB7fTtcbiAgICBjb25zdCB0ZW1wbGF0ZUlkc1N0YWNrOiBudW1iZXJbXSA9IFtST09UX1RFTVBMQVRFX0lEXTtcbiAgICByZXN1bHQgPSByZXN1bHQucmVwbGFjZShQUF9QTEFDRUhPTERFUlNfUkVHRVhQLCAobTogYW55LCBwaHM6IHN0cmluZywgdG1wbDogc3RyaW5nKTogc3RyaW5nID0+IHtcbiAgICAgIGNvbnN0IGNvbnRlbnQgPSBwaHMgfHwgdG1wbDtcbiAgICAgIGNvbnN0IHBsYWNlaG9sZGVyczogUG9zdHByb2Nlc3NQbGFjZWhvbGRlcltdID0gbWF0Y2hlc1tjb250ZW50XSB8fCBbXTtcbiAgICAgIGlmICghcGxhY2Vob2xkZXJzLmxlbmd0aCkge1xuICAgICAgICBjb250ZW50LnNwbGl0KCd8JykuZm9yRWFjaCgocGxhY2Vob2xkZXI6IHN0cmluZykgPT4ge1xuICAgICAgICAgIGNvbnN0IG1hdGNoID0gcGxhY2Vob2xkZXIubWF0Y2goUFBfVEVNUExBVEVfSURfUkVHRVhQKTtcbiAgICAgICAgICBjb25zdCB0ZW1wbGF0ZUlkID0gbWF0Y2ggPyBwYXJzZUludChtYXRjaFsxXSwgMTApIDogUk9PVF9URU1QTEFURV9JRDtcbiAgICAgICAgICBjb25zdCBpc0Nsb3NlVGVtcGxhdGVUYWcgPSBQUF9DTE9TRV9URU1QTEFURV9SRUdFWFAudGVzdChwbGFjZWhvbGRlcik7XG4gICAgICAgICAgcGxhY2Vob2xkZXJzLnB1c2goW3RlbXBsYXRlSWQsIGlzQ2xvc2VUZW1wbGF0ZVRhZywgcGxhY2Vob2xkZXJdKTtcbiAgICAgICAgfSk7XG4gICAgICAgIG1hdGNoZXNbY29udGVudF0gPSBwbGFjZWhvbGRlcnM7XG4gICAgICB9XG5cbiAgICAgIGlmICghcGxhY2Vob2xkZXJzLmxlbmd0aCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGkxOG4gcG9zdHByb2Nlc3M6IHVubWF0Y2hlZCBwbGFjZWhvbGRlciAtICR7Y29udGVudH1gKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgY3VycmVudFRlbXBsYXRlSWQgPSB0ZW1wbGF0ZUlkc1N0YWNrW3RlbXBsYXRlSWRzU3RhY2subGVuZ3RoIC0gMV07XG4gICAgICBsZXQgaWR4ID0gMDtcbiAgICAgIC8vIGZpbmQgcGxhY2Vob2xkZXIgaW5kZXggdGhhdCBtYXRjaGVzIGN1cnJlbnQgdGVtcGxhdGUgaWRcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGxhY2Vob2xkZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChwbGFjZWhvbGRlcnNbaV1bMF0gPT09IGN1cnJlbnRUZW1wbGF0ZUlkKSB7XG4gICAgICAgICAgaWR4ID0gaTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gdXBkYXRlIHRlbXBsYXRlIGlkIHN0YWNrIGJhc2VkIG9uIHRoZSBjdXJyZW50IHRhZyBleHRyYWN0ZWRcbiAgICAgIGNvbnN0IFt0ZW1wbGF0ZUlkLCBpc0Nsb3NlVGVtcGxhdGVUYWcsIHBsYWNlaG9sZGVyXSA9IHBsYWNlaG9sZGVyc1tpZHhdO1xuICAgICAgaWYgKGlzQ2xvc2VUZW1wbGF0ZVRhZykge1xuICAgICAgICB0ZW1wbGF0ZUlkc1N0YWNrLnBvcCgpO1xuICAgICAgfSBlbHNlIGlmIChjdXJyZW50VGVtcGxhdGVJZCAhPT0gdGVtcGxhdGVJZCkge1xuICAgICAgICB0ZW1wbGF0ZUlkc1N0YWNrLnB1c2godGVtcGxhdGVJZCk7XG4gICAgICB9XG4gICAgICAvLyByZW1vdmUgcHJvY2Vzc2VkIHRhZyBmcm9tIHRoZSBsaXN0XG4gICAgICBwbGFjZWhvbGRlcnMuc3BsaWNlKGlkeCwgMSk7XG4gICAgICByZXR1cm4gcGxhY2Vob2xkZXI7XG4gICAgfSk7XG4gIH1cblxuICAvLyByZXR1cm4gY3VycmVudCByZXN1bHQgaWYgbm8gcmVwbGFjZW1lbnRzIHNwZWNpZmllZFxuICBpZiAoIU9iamVjdC5rZXlzKHJlcGxhY2VtZW50cykubGVuZ3RoKSB7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGVwIDI6IHJlcGxhY2UgYWxsIElDVSB2YXJzIChsaWtlIFwiVkFSX1BMVVJBTFwiKVxuICAgKi9cbiAgcmVzdWx0ID0gcmVzdWx0LnJlcGxhY2UoUFBfSUNVX1ZBUlNfUkVHRVhQLCAobWF0Y2gsIHN0YXJ0LCBrZXksIF90eXBlLCBfaWR4LCBlbmQpOiBzdHJpbmcgPT4ge1xuICAgIHJldHVybiByZXBsYWNlbWVudHMuaGFzT3duUHJvcGVydHkoa2V5KSA/IGAke3N0YXJ0fSR7cmVwbGFjZW1lbnRzW2tleV19JHtlbmR9YCA6IG1hdGNoO1xuICB9KTtcblxuICAvKipcbiAgICogU3RlcCAzOiByZXBsYWNlIGFsbCBwbGFjZWhvbGRlcnMgdXNlZCBpbnNpZGUgSUNVcyBpbiBhIGZvcm0gb2Yge1BMQUNFSE9MREVSfVxuICAgKi9cbiAgcmVzdWx0ID0gcmVzdWx0LnJlcGxhY2UoUFBfSUNVX1BMQUNFSE9MREVSU19SRUdFWFAsIChtYXRjaCwga2V5KTogc3RyaW5nID0+IHtcbiAgICByZXR1cm4gcmVwbGFjZW1lbnRzLmhhc093blByb3BlcnR5KGtleSkgPyByZXBsYWNlbWVudHNba2V5XSBhcyBzdHJpbmcgOiBtYXRjaDtcbiAgfSk7XG5cbiAgLyoqXG4gICAqIFN0ZXAgNDogcmVwbGFjZSBhbGwgSUNVIHJlZmVyZW5jZXMgd2l0aCBjb3JyZXNwb25kaW5nIHZhbHVlcyAobGlrZSDvv71JQ1VfRVhQX0lDVV8x77+9KSBpbiBjYXNlXG4gICAqIG11bHRpcGxlIElDVXMgaGF2ZSB0aGUgc2FtZSBwbGFjZWhvbGRlciBuYW1lXG4gICAqL1xuICByZXN1bHQgPSByZXN1bHQucmVwbGFjZShQUF9JQ1VTX1JFR0VYUCwgKG1hdGNoLCBrZXkpOiBzdHJpbmcgPT4ge1xuICAgIGlmIChyZXBsYWNlbWVudHMuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgY29uc3QgbGlzdCA9IHJlcGxhY2VtZW50c1trZXldIGFzIHN0cmluZ1tdO1xuICAgICAgaWYgKCFsaXN0Lmxlbmd0aCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGkxOG4gcG9zdHByb2Nlc3M6IHVubWF0Y2hlZCBJQ1UgLSAke21hdGNofSB3aXRoIGtleTogJHtrZXl9YCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbGlzdC5zaGlmdCgpITtcbiAgICB9XG4gICAgcmV0dXJuIG1hdGNoO1xuICB9KTtcblxuICByZXR1cm4gcmVzdWx0O1xufVxuIl19