UNPKG

25.1 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.matchesLiteralSections = matchesLiteralSections;
7exports.default = void 0;
8
9var _locale = require("locale");
10
11var _fusionCore = require("fusion-core");
12
13var _fusionPluginUniversalEvents = require("fusion-plugin-universal-events");
14
15var _koaBodyparser = _interopRequireDefault(require("koa-bodyparser"));
16
17var _querystring = _interopRequireDefault(require("querystring"));
18
19var _tokens = require("./tokens.js");
20
21var _loader = _interopRequireDefault(require("./loader.js"));
22
23function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
24
25/** Copyright (c) 2018 Uber Technologies, Inc.
26 *
27 * This source code is licensed under the MIT license found in the
28 * LICENSE file in the root directory of this source tree.
29 *
30 *
31 */
32
33/* eslint-env node */
34// exported for testing
35function matchesLiteralSections(literalSections) {
36 return translation => {
37 let lastMatchIndex = 0;
38
39 if (literalSections.length === 1) {
40 const literal = literalSections[0];
41 return literal !== '' && translation === literal;
42 }
43
44 return literalSections.every((literal, literalIndex) => {
45 if (literal === '') {
46 // literal section either:
47 // - starts/ends the literal
48 // - is the result of two adjacent interpolations
49 return true;
50 } else if (literalIndex === 0 && translation.startsWith(literal)) {
51 lastMatchIndex += literal.length;
52 return true;
53 } else if (literalIndex === literalSections.length - 1 && translation.endsWith(literal)) {
54 return true;
55 } else {
56 // start search from `lastMatchIndex`
57 const matchIndex = translation.indexOf(literal, lastMatchIndex);
58
59 if (matchIndex !== -1) {
60 lastMatchIndex = matchIndex + literal.length;
61 return true;
62 }
63 } // matching failed
64
65
66 return false;
67 });
68 };
69}
70
71function getKeysFromContext(ctx) {
72 if (ctx.request.body && Array.isArray(ctx.request.body)) {
73 return ctx.request.body;
74 }
75
76 const querystringParams = _querystring.default.parse(ctx.querystring);
77
78 if (querystringParams.keys) {
79 try {
80 const keys = JSON.parse(querystringParams.keys);
81 return Array.isArray(keys) ? keys : [];
82 } catch (e) {
83 return [];
84 }
85 }
86
87 return [];
88}
89
90const pluginFactory = () => (0, _fusionCore.createPlugin)({
91 deps: {
92 loader: _tokens.I18nLoaderToken.optional,
93 events: _fusionPluginUniversalEvents.UniversalEventsToken.optional
94 },
95 provides: ({
96 loader,
97 events
98 }) => {
99 class I18n {
100 constructor(ctx) {
101 if (!loader) {
102 loader = (0, _loader.default)();
103 }
104
105 const {
106 translations,
107 locale
108 } = loader.from(ctx);
109 this.emitter = events && events.from(ctx);
110 this.translations = translations;
111 this.locale = locale;
112 }
113
114 async load() {} //mirror client API
115
116
117 translate(key, interpolations = {}) {
118 const template = this.translations[key];
119
120 if (typeof template !== 'string') {
121 this.emitter && this.emitter.emit('i18n-translate-miss', {
122 key
123 });
124 return key;
125 }
126
127 return template.replace(/\${(.*?)}/g, (_, k) => interpolations[k] === void 0 ? '${' + k + '}' : String(interpolations[k]));
128 }
129
130 }
131
132 const service = {
133 from: (0, _fusionCore.memoize)(ctx => new I18n(ctx))
134 };
135 return service;
136 },
137 middleware: (_, plugin) => {
138 // TODO(#4) refactor: this currently depends on babel plugins in framework's webpack config.
139 // Ideally these babel plugins should be part of this package, not hard-coded in framework core
140 const chunkTranslationMap = require('../chunk-translation-map');
141
142 const parseBody = (0, _koaBodyparser.default)();
143 return async (ctx, next) => {
144 if (ctx.element) {
145 await next();
146 const i18n = plugin.from(ctx); // get the webpack chunks that are used and serialize their translations
147
148 const chunks = [...ctx.syncChunks, ...ctx.preloadChunks];
149 const translations = {};
150 const possibleTranslations = i18n.translations ? Object.keys(i18n.translations) : [];
151 chunks.forEach(id => {
152 const keys = Array.from(chunkTranslationMap.translationsForChunk(id));
153 keys.forEach(key => {
154 if (Array.isArray(key)) {
155 const matches = possibleTranslations.filter(matchesLiteralSections(key));
156
157 for (const match of matches) {
158 translations[match] = i18n.translations && i18n.translations[match];
159 }
160 } else {
161 translations[key] = i18n.translations && i18n.translations[key];
162 }
163 });
164 }); // i18n.locale is actually a locale.Locale instance
165
166 if (!i18n.locale) {
167 throw new Error('i18n.locale was empty');
168 }
169
170 const localeCode = typeof i18n.locale === 'string' ? i18n.locale : i18n.locale.code;
171 const serialized = JSON.stringify({
172 localeCode,
173 translations
174 });
175 const script = (0, _fusionCore.html)`
176 <script type="application/json" id="__TRANSLATIONS__">
177 ${serialized}
178 </script>
179 `; // consumed by ./browser
180
181 ctx.template.body.push(script); // set HTML lang tag as a hint for signal screen readers to switch to the
182 // recommended language.
183
184 ctx.template.htmlAttrs.lang = localeCode;
185 } else if (ctx.path === '/_translations') {
186 const i18n = plugin.from(ctx);
187
188 try {
189 await parseBody(ctx, () => Promise.resolve());
190 } catch (e) {
191 ctx.request.body = [];
192 }
193
194 const keys = getKeysFromContext(ctx);
195 const possibleTranslations = i18n.translations ? Object.keys(i18n.translations) : [];
196 const translations = keys.reduce((acc, key) => {
197 if (Array.isArray(key)) {
198 const matches = possibleTranslations.filter(matchesLiteralSections(key));
199
200 for (const match of matches) {
201 acc[match] = i18n.translations && i18n.translations[match];
202 }
203 } else {
204 acc[key] = i18n.translations && i18n.translations[key];
205 }
206
207 return acc;
208 }, {});
209 ctx.body = translations;
210 ctx.set('cache-control', 'public, max-age=3600'); // cache translations for up to 1 hour
211
212 return next();
213 } else {
214 return next();
215 }
216 };
217 }
218});
219
220var _default = true && pluginFactory();
221
222exports.default = _default;
223//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGUuanMiXSwibmFtZXMiOlsibWF0Y2hlc0xpdGVyYWxTZWN0aW9ucyIsImxpdGVyYWxTZWN0aW9ucyIsInRyYW5zbGF0aW9uIiwibGFzdE1hdGNoSW5kZXgiLCJsZW5ndGgiLCJsaXRlcmFsIiwiZXZlcnkiLCJsaXRlcmFsSW5kZXgiLCJzdGFydHNXaXRoIiwiZW5kc1dpdGgiLCJtYXRjaEluZGV4IiwiaW5kZXhPZiIsImdldEtleXNGcm9tQ29udGV4dCIsImN0eCIsInJlcXVlc3QiLCJib2R5IiwiQXJyYXkiLCJpc0FycmF5IiwicXVlcnlzdHJpbmdQYXJhbXMiLCJxdWVyeXN0cmluZyIsInBhcnNlIiwia2V5cyIsIkpTT04iLCJlIiwicGx1Z2luRmFjdG9yeSIsImRlcHMiLCJsb2FkZXIiLCJJMThuTG9hZGVyVG9rZW4iLCJvcHRpb25hbCIsImV2ZW50cyIsIlVuaXZlcnNhbEV2ZW50c1Rva2VuIiwicHJvdmlkZXMiLCJJMThuIiwiY29uc3RydWN0b3IiLCJ0cmFuc2xhdGlvbnMiLCJsb2NhbGUiLCJmcm9tIiwiZW1pdHRlciIsImxvYWQiLCJ0cmFuc2xhdGUiLCJrZXkiLCJpbnRlcnBvbGF0aW9ucyIsInRlbXBsYXRlIiwiZW1pdCIsInJlcGxhY2UiLCJfIiwiayIsIlN0cmluZyIsInNlcnZpY2UiLCJtaWRkbGV3YXJlIiwicGx1Z2luIiwiY2h1bmtUcmFuc2xhdGlvbk1hcCIsInJlcXVpcmUiLCJwYXJzZUJvZHkiLCJuZXh0IiwiZWxlbWVudCIsImkxOG4iLCJjaHVua3MiLCJzeW5jQ2h1bmtzIiwicHJlbG9hZENodW5rcyIsInBvc3NpYmxlVHJhbnNsYXRpb25zIiwiT2JqZWN0IiwiZm9yRWFjaCIsImlkIiwidHJhbnNsYXRpb25zRm9yQ2h1bmsiLCJtYXRjaGVzIiwiZmlsdGVyIiwibWF0Y2giLCJFcnJvciIsImxvY2FsZUNvZGUiLCJjb2RlIiwic2VyaWFsaXplZCIsInN0cmluZ2lmeSIsInNjcmlwdCIsInB1c2giLCJodG1sQXR0cnMiLCJs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LFFBQUFBLEdBQUcsQ0FBQ3FFLEdBQUosQ0FBUSxlQUFSLEVBQXlCLHNCQUF6QixFQXpCd0MsQ0F5QlU7O0FBQ2xELGVBQU81QixJQUFJLEVBQVg7QUFDRCxPQTNCTSxNQTJCQTtBQUNMLGVBQU9BLElBQUksRUFBWDtBQUNEO0FBQ0YsS0EvRUQ7QUFnRkQ7QUE5SFUsQ0FBYixDQURGOztlQWtJaUIsUUFBWTlCLGFBQWEsRSIsInNvdXJjZXNDb250ZW50IjpbIi8qKiBDb3B5cmlnaHQgKGMpIDIwMTggVWJlciBUZWNobm9sb2dpZXMsIEluYy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKiBAZmxvd1xuICovXG5cbi8qIGVzbGludC1lbnYgbm9kZSAqL1xuXG5pbXBvcnQge0xvY2FsZX0gZnJvbSAnbG9jYWxlJztcblxuaW1wb3J0IHtjcmVhdGVQbHVnaW4sIG1lbW9pemUsIGh0bWx9IGZyb20gJ2Z1c2lvbi1jb3JlJztcbmltcG9ydCB0eXBlIHtGdXNpb25QbHVnaW4sIENvbnRleHR9IGZyb20gJ2Z1c2lvbi1jb3JlJztcbmltcG9ydCB7VW5pdmVyc2FsRXZlbnRzVG9rZW59IGZyb20gJ2Z1c2lvbi1wbHVnaW4tdW5pdmVyc2FsLWV2ZW50cyc7XG5pbXBvcnQgYm9keXBhcnNlciBmcm9tICdrb2EtYm9keXBhcnNlcic7XG5pbXBvcnQgcXVlcnlzdHJpbmcgZnJvbSAncXVlcnlzdHJpbmcnO1xuXG5pbXBvcnQge0kxOG5Mb2FkZXJUb2tlbn0gZnJvbSAnLi90b2tlbnMuanMnO1xuaW1wb3J0IGNyZWF0ZUxvYWRlciBmcm9tICcuL2xvYWRlci5qcyc7XG5pbXBvcnQgdHlwZSB7XG4gIEkxOG5EZXBzVHlwZSxcbiAgSTE4blNlcnZpY2VUeXBlLFxuICBUcmFuc2xhdGlvbnNPYmplY3RUeXBlLFxuICBJRW1pdHRlcixcbn0gZnJvbSAnLi90eXBlcy5qcyc7XG5cbi8vIGV4cG9ydGVkIGZvciB0ZXN0aW5nXG5leHBvcnQgZnVuY3Rpb24gbWF0Y2hlc0xpdGVyYWxTZWN0aW9ucyhsaXRlcmFsU2VjdGlvbnM6IEFycmF5PHN0cmluZz4pIHtcbiAgcmV0dXJuICh0cmFuc2xhdGlvbjogc3RyaW5nKSA9PiB7XG4gICAgbGV0IGxhc3RNYXRjaEluZGV4ID0gMDtcblxuICAgIGlmIChsaXRlcmFsU2VjdGlvbnMubGVuZ3RoID09PSAxKSB7XG4gICAgICBjb25zdCBsaXRlcmFsID0gbGl0ZXJhbFNlY3Rpb25zWzBdO1xuICAgICAgcmV0dXJuIGxpdGVyYWwgIT09ICcnICYmIHRyYW5zbGF0aW9uID09PSBsaXRlcmFsO1xuICAgIH1cblxuICAgIHJldHVybiBsaXRlcmFsU2VjdGlvbnMuZXZlcnkoKGxpdGVyYWwsIGxpdGVyYWxJbmRleCkgPT4ge1xuICAgICAgaWYgKGxpdGVyYWwgPT09ICcnKSB7XG4gICAgICAgIC8vIGxpdGVyYWwgc2VjdGlvbiBlaXRoZXI6XG4gICAgICAgIC8vIC0gc3RhcnRzL2VuZHMgdGhlIGxpdGVyYWxcbiAgICAgICAgLy8gLSBpcyB0aGUgcmVzdWx0IG9mIHR3byBhZGphY2VudCBpbnRlcnBvbGF0aW9uc1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH0gZWxzZSBpZiAobGl0ZXJhbEluZGV4ID09PSAwICYmIHRyYW5zbGF0aW9uLnN0YXJ0c1dpdGgobGl0ZXJhbCkpIHtcbiAgICAgICAgbGFzdE1hdGNoSW5kZXggKz0gbGl0ZXJhbC5sZW5ndGg7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgbGl0ZXJhbEluZGV4ID09PSBsaXRlcmFsU2VjdGlvbnMubGVuZ3RoIC0gMSAmJlxuICAgICAgICB0cmFuc2xhdGlvbi5lbmRzV2l0aChsaXRlcmFsKVxuICAgICAgKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gc3RhcnQgc2VhcmNoIGZyb20gYGxhc3RNYXRjaEluZGV4YFxuICAgICAgICBjb25zdCBtYXRjaEluZGV4ID0gdHJhbnNsYXRpb24uaW5kZXhPZihsaXRlcmFsLCBsYXN0TWF0Y2hJbmRleCk7XG4gICAgICAgIGlmIChtYXRjaEluZGV4ICE9PSAtMSkge1xuICAgICAgICAgIGxhc3RNYXRjaEluZGV4ID0gbWF0Y2hJbmRleCArIGxpdGVyYWwubGVuZ3RoO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBtYXRjaGluZyBmYWlsZWRcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9KTtcbiAgfTtcbn1cblxuZnVuY3Rpb24gZ2V0S2V5c0Zyb21Db250ZXh0KGN0eDogQ29udGV4dCk6IHN0cmluZ1tdIHtcbiAgaWYgKGN0eC5yZXF1ZXN0LmJvZHkgJiYgQXJyYXkuaXNBcnJheShjdHgucmVxdWVzdC5ib2R5KSkge1xuICAgIHJldHVybiAoY3R4LnJlcXVlc3QuYm9keTogYW55KTtcbiAgfVxuXG4gIGNvbnN0IHF1ZXJ5c3RyaW5nUGFyYW1zID0gcXVlcnlzdHJpbmcucGFyc2UoY3R4LnF1ZXJ5c3RyaW5nKTtcbiAgaWYgKHF1ZXJ5c3RyaW5nUGFyYW1zLmtleXMpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3Qga2V5cyA9IEpTT04ucGFyc2UocXVlcnlzdHJpbmdQYXJhbXMua2V5cyk7XG4gICAgICByZXR1cm4gQXJyYXkuaXNBcnJheShrZXlzKSA/IGtleXMgOiBbXTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIFtdO1xufVxuXG50eXBlIFBsdWdpblR5cGUgPSBGdXNpb25QbHVnaW48STE4bkRlcHNUeXBlLCBJMThuU2VydmljZVR5cGU+O1xuY29uc3QgcGx1Z2luRmFjdG9yeTogKCkgPT4gUGx1Z2luVHlwZSA9ICgpID0+XG4gIGNyZWF0ZVBsdWdpbih7XG4gICAgZGVwczoge1xuICAgICAgbG9hZGVyOiBJMThuTG9hZGVyVG9rZW4ub3B0aW9uYWwsXG4gICAgICBldmVudHM6IFVuaXZlcnNhbEV2ZW50c1Rva2VuLm9wdGlvbmFsLFxuICAgIH0sXG4gICAgcHJvdmlkZXM6ICh7bG9hZGVyLCBldmVudHN9KSA9PiB7XG4gICAgICBjbGFzcyBJMThuIHtcbiAgICAgICAgdHJhbnNsYXRpb25zOiBUcmFuc2xhdGlvbnNPYmplY3RUeXBlO1xuICAgICAgICBsb2NhbGU6IHN0cmluZyB8IExvY2FsZTtcbiAgICAgICAgZW1pdHRlcjogP0lFbWl0dGVyO1xuXG4gICAgICAgIGNvbnN0cnVjdG9yKGN0eCkge1xuICAgICAgICAgIGlmICghbG9hZGVyKSB7XG4gICAgICAgICAgICBsb2FkZXIgPSBjcmVhdGVMb2FkZXIoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3Qge3RyYW5zbGF0aW9ucywgbG9jYWxlfSA9IGxvYWRlci5mcm9tKGN0eCk7XG4gICAgICAgICAgdGhpcy5lbWl0dGVyID0gZXZlbnRzICYmIGV2ZW50cy5mcm9tKGN0eCk7XG4gICAgICAgICAgdGhpcy50cmFuc2xhdGlvbnMgPSB0cmFuc2xhdGlvbnM7XG4gICAgICAgICAgdGhpcy5sb2NhbGUgPSBsb2NhbGU7XG4gICAgICAgIH1cbiAgICAgICAgYXN5bmMgbG9hZCgpIHt9IC8vbWlycm9yIGNsaWVudCBBUElcbiAgICAgICAgdHJhbnNsYXRlKGtleSwgaW50ZXJwb2xhdGlvbnMgPSB7fSkge1xuICAgICAgICAgIGNvbnN0IHRlbXBsYXRlID0gdGhpcy50cmFuc2xhdGlvbnNba2V5XTtcblxuICAgICAgICAgIGlmICh0eXBlb2YgdGVtcGxhdGUgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICB0aGlzLmVtaXR0ZXIgJiYgdGhpcy5lbWl0dGVyLmVtaXQoJ2kxOG4tdHJhbnNsYXRlLW1pc3MnLCB7a2V5fSk7XG4gICAgICAgICAgICByZXR1cm4ga2V5O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiB0ZW1wbGF0ZS5yZXBsYWNlKC9cXCR7KC4qPyl9L2csIChfLCBrKSA9PlxuICAgICAgICAgICAgaW50ZXJwb2xhdGlvbnNba10gPT09IHZvaWQgMFxuICAgICAgICAgICAgICA/ICckeycgKyBrICsgJ30nXG4gICAgICAgICAgICAgIDogU3RyaW5nKGludGVycG9sYXRpb25zW2tdKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2VydmljZSA9IHtmcm9tOiBtZW1vaXplKGN0eCA9PiBuZXcgSTE4bihjdHgpKX07XG4gICAgICByZXR1cm4gc2VydmljZTtcbiAgICB9LFxuICAgIG1pZGRsZXdhcmU6IChfLCBwbHVnaW4pID0+IHtcbiAgICAgIC8vIFRPRE8oIzQpIHJlZmFjdG9yOiB0aGlzIGN1cnJlbnRseSBkZXBlbmRzIG9uIGJhYmVsIHBsdWdpbnMgaW4gZnJhbWV3b3JrJ3Mgd2VicGFjayBjb25maWcuXG4gICAgICAvLyBJZGVhbGx5IHRoZXNlIGJhYmVsIHBsdWdpbnMgc2hvdWxkIGJlIHBhcnQgb2YgdGhpcyBwYWNrYWdlLCBub3QgaGFyZC1jb2RlZCBpbiBmcmFtZXdvcmsgY29yZVxuICAgICAgY29uc3QgY2h1bmtUcmFuc2xhdGlvbk1hcCA9IHJlcXVpcmUoJy4uL2NodW5rLXRyYW5zbGF0aW9uLW1hcCcpO1xuICAgICAgY29uc3QgcGFyc2VCb2R5ID0gYm9keXBhcnNlcigpO1xuXG4gICAgICByZXR1cm4gYXN5bmMgKGN0eCwgbmV4dCkgPT4ge1xuICAgICAgICBpZiAoY3R4LmVsZW1lbnQpIHtcbiAgICAgICAgICBhd2FpdCBuZXh0KCk7XG4gICAgICAgICAgY29uc3QgaTE4biA9IHBsdWdpbi5mcm9tKGN0eCk7XG5cbiAgICAgICAgICAvLyBnZXQgdGhlIHdlYnBhY2sgY2h1bmtzIHRoYXQgYXJlIHVzZWQgYW5kIHNlcmlhbGl6ZSB0aGVpciB0cmFuc2xhdGlvbnNcbiAgICAgICAgICBjb25zdCBjaHVua3M6IEFycmF5PHN0cmluZyB8IG51bWJlcj4gPSBbXG4gICAgICAgICAgICAuLi5jdHguc3luY0NodW5rcyxcbiAgICAgICAgICAgIC4uLmN0eC5wcmVsb2FkQ2h1bmtzLFxuICAgICAgICAgIF07XG4gICAgICAgICAgY29uc3QgdHJhbnNsYXRpb25zID0ge307XG4gICAgICAgICAgY29uc3QgcG9zc2libGVUcmFuc2xhdGlvbnMgPSBpMThuLnRyYW5zbGF0aW9uc1xuICAgICAgICAgICAgPyBPYmplY3Qua2V5cyhpMThuLnRyYW5zbGF0aW9ucylcbiAgICAgICAgICAgIDogW107XG4gICAgICAgICAgY2h1bmtzLmZvckVhY2goaWQgPT4ge1xuICAgICAgICAgICAgY29uc3Qga2V5cyA9IEFycmF5LmZyb20oXG4gICAgICAgICAgICAgIGNodW5rVHJhbnNsYXRpb25NYXAudHJhbnNsYXRpb25zRm9yQ2h1bmsoaWQpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAga2V5cy5mb3JFYWNoKGtleSA9PiB7XG4gICAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KGtleSkpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBtYXRjaGVzID0gcG9zc2libGVUcmFuc2xhdGlvbnMuZmlsdGVyKFxuICAgICAgICAgICAgICAgICAgbWF0Y2hlc0xpdGVyYWxTZWN0aW9ucyhrZXkpXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IG1hdGNoIG9mIG1hdGNoZXMpIHtcbiAgICAgICAgICAgICAgICAgIHRyYW5zbGF0aW9uc1ttYXRjaF0gPVxuICAgICAgICAgICAgICAgICAgICBpMThuLnRyYW5zbGF0aW9ucyAmJiBpMThuLnRyYW5zbGF0aW9uc1ttYXRjaF07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRyYW5zbGF0aW9uc1trZXldID0gaTE4bi50cmFuc2xhdGlvbnMgJiYgaTE4bi50cmFuc2xhdGlvbnNba2V5XTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgLy8gaTE4bi5sb2NhbGUgaXMgYWN0dWFsbHkgYSBsb2NhbGUuTG9jYWxlIGluc3RhbmNlXG4gICAgICAgICAgaWYgKCFpMThuLmxvY2FsZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpMThuLmxvY2FsZSB3YXMgZW1wdHknKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgbG9jYWxlQ29kZSA9XG4gICAgICAgICAgICB0eXBlb2YgaTE4bi5sb2NhbGUgPT09ICdzdHJpbmcnID8gaTE4bi5sb2NhbGUgOiBpMThuLmxvY2FsZS5jb2RlO1xuICAgICAgICAgIGNvbnN0IHNlcmlhbGl6ZWQgPSBKU09OLnN0cmluZ2lmeSh7bG9jYWxlQ29kZSwgdHJhbnNsYXRpb25zfSk7XG4gICAgICAgICAgY29uc3Qgc2NyaXB0ID0gaHRtbGBcbiAgICAgICAgICAgIDxzY3JpcHQgdHlwZT1cImFwcGxpY2F0aW9uL2pzb25cIiBpZD1cIl9fVFJBTlNMQVRJT05TX19cIj5cbiAgICAgICAgICAgICAgJHtzZXJpYWxpemVkfVxuICAgICAgICAgICAgPC9zY3JpcHQ+XG4gICAgICAgICAgYDsgLy8gY29uc3VtZWQgYnkgLi9icm93c2VyXG4gICAgICAgICAgY3R4LnRlbXBsYXRlLmJvZHkucHVzaChzY3JpcHQpO1xuXG4gICAgICAgICAgLy8gc2V0IEhUTUwgbGFuZyB0YWcgYXMgYSBoaW50IGZvciBzaWduYWwgc2NyZWVuIHJlYWRlcnMgdG8gc3dpdGNoIHRvIHRoZVxuICAgICAgICAgIC8vIHJlY29tbWVuZGVkIGxhbmd1YWdlLlxuICAgICAgICAgIGN0eC50ZW1wbGF0ZS5odG1sQXR0cnMubGFuZyA9IGxvY2FsZUNvZGU7XG4gICAgICAgIH0gZWxzZSBpZiAoY3R4LnBhdGggPT09ICcvX3RyYW5zbGF0aW9ucycpIHtcbiAgICAgICAgICBjb25zdCBpMThuID0gcGx1Z2luLmZyb20oY3R4KTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgcGFyc2VCb2R5KGN0eCwgKCkgPT4gUHJvbWlzZS5yZXNvbHZlKCkpO1xuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGN0eC5yZXF1ZXN0LmJvZHkgPSBbXTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3Qga2V5cyA9IGdldEtleXNGcm9tQ29udGV4dChjdHgpO1xuICAgICAgICAgIGNvbnN0IHBvc3NpYmxlVHJhbnNsYXRpb25zID0gaTE4bi50cmFuc2xhdGlvbnNcbiAgICAgICAgICAgID8gT2JqZWN0LmtleXMoaTE4bi50cmFuc2xhdGlvbnMpXG4gICAgICAgICAgICA6IFtdO1xuICAgICAgICAgIGNvbnN0IHRyYW5zbGF0aW9ucyA9IGtleXMucmVkdWNlKChhY2MsIGtleSkgPT4ge1xuICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoa2V5KSkge1xuICAgICAgICAgICAgICBjb25zdCBtYXRjaGVzID0gcG9zc2libGVUcmFuc2xhdGlvbnMuZmlsdGVyKFxuICAgICAgICAgICAgICAgIG1hdGNoZXNMaXRlcmFsU2VjdGlvbnMoa2V5KVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICBmb3IgKGNvbnN0IG1hdGNoIG9mIG1hdGNoZXMpIHtcbiAgICAgICAgICAgICAgICBhY2NbbWF0Y2hdID0gaTE4bi50cmFuc2xhdGlvbnMgJiYgaTE4bi50cmFuc2xhdGlvbnNbbWF0Y2hdO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBhY2Nba2V5XSA9IGkxOG4udHJhbnNsYXRpb25zICYmIGkxOG4udHJhbnNsYXRpb25zW2tleV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgICAgIH0sIHt9KTtcbiAgICAgICAgICBjdHguYm9keSA9IHRyYW5zbGF0aW9ucztcbiAgICAgICAgICBjdHguc2V0KCdjYWNoZS1jb250cm9sJywgJ3B1YmxpYywgbWF4LWFnZT0zNjAwJyk7IC8vIGNhY2hlIHRyYW5zbGF0aW9ucyBmb3IgdXAgdG8gMSBob3VyXG4gICAgICAgICAgcmV0dXJuIG5leHQoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gbmV4dCgpO1xuICAgICAgICB9XG4gICAgICB9O1xuICAgIH0sXG4gIH0pO1xuXG5leHBvcnQgZGVmYXVsdCAoKF9fTk9ERV9fICYmIHBsdWdpbkZhY3RvcnkoKTogYW55KTogUGx1Z2luVHlwZSk7XG4iXX0=
\No newline at end of file