anylang
Version:
A translator's kit that uses the free APIs of Google Translate, Yandex, Bing, ChatGPT, and other LLMs
231 lines (229 loc) • 27.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.GoogleTranslatorTokenFree = exports.GoogleTranslator = exports.AbstractGoogleTranslator = void 0;
var _queryString = _interopRequireDefault(require("query-string"));
var _BaseTranslator = require("../BaseTranslator");
var _languages = require("./languages");
var _token = require("./token");
var _utils = require("./utils");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
var __awaiter = void 0 && (void 0).__awaiter || function (thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P ? value : new P(function (resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/**
* Common class for google translator implementations
*/
class AbstractGoogleTranslator extends _BaseTranslator.BaseTranslator {
static isSupportedAutoFrom() {
return true;
}
static getSupportedLanguages() {
return _languages.languageAliases.getAll();
}
getLengthLimit() {
return 4000;
}
getRequestsTimeout() {
return 300;
}
}
/**
* Translator implementation which use Google API with token from https://translate.google.com
*/
exports.AbstractGoogleTranslator = AbstractGoogleTranslator;
class GoogleTranslator extends AbstractGoogleTranslator {
checkLimitExceeding(text) {
if (Array.isArray(text)) {
const encodedText = (0, _utils.encodeForBatch)(text).join('');
const extra = encodedText.length - this.getLengthLimit();
return extra > 0 ? extra : 0;
} else {
const extra = text.length - this.getLengthLimit();
return extra > 0 ? extra : 0;
}
}
translate(text, from, to) {
return (0, _token.getToken)(text).then(({
value: tk
}) => {
const apiPath = 'https://translate.google.com/translate_a/single';
const data = {
client: 't',
sl: (0, _languages.getFixedLanguage)(from),
tl: (0, _languages.getFixedLanguage)(to),
hl: (0, _languages.getFixedLanguage)(to),
dt: ['at', 'bd', 'ex', 'ld', 'md', 'qca', 'rw', 'rm', 'ss', 't'],
ie: 'UTF-8',
oe: 'UTF-8',
otf: 1,
ssel: 0,
tsel: 0,
kc: 7,
q: text,
tk
};
const url = apiPath + '?' + _queryString.default.stringify(data);
return this.fetch(url, {
responseType: 'json',
method: 'GET',
headers: this.options.headers
}).then(rsp => rsp.data).then(rsp => {
if (!(rsp instanceof Array) || !(rsp[0] instanceof Array)) {
throw new Error('Unexpected response');
}
const translatedText = rsp[0].map(chunk => chunk instanceof Array && typeof chunk[0] === 'string' ? chunk[0] : '').join('');
return translatedText;
});
});
}
translateBatch(text, from, to) {
const preparedText = (0, _utils.encodeForBatch)(text);
return (0, _token.getToken)(preparedText.join('')).then(({
value: tk
}) => {
const apiPath = 'https://translate.googleapis.com/translate_a/t';
const data = {
anno: 3,
client: 'te',
v: '1.0',
format: 'html',
sl: (0, _languages.getFixedLanguage)(from),
tl: (0, _languages.getFixedLanguage)(to),
tk
};
const url = apiPath + '?' + _queryString.default.stringify(data);
const body = preparedText.map(text => `&q=${encodeURIComponent(text)}`).join('');
return this.fetch(url, {
responseType: 'json',
method: 'POST',
headers: Object.assign({
'Content-Type': 'application/x-www-form-urlencoded'
}, this.options.headers),
body
}).then(rsp => rsp.data).then(rawResp => {
try {
if (!Array.isArray(rawResp)) {
throw new Error('Unexpected response');
}
const isSingleResponseMode = text.length === 1;
const result = [];
(0, _utils.visitArrayItems)(rawResp, obj => {
if (isSingleResponseMode && result.length === 1) return;
if (typeof obj !== 'string') return;
if (isSingleResponseMode) {
const parsedText = (0, _utils.parseXMLResponse)(obj);
result.push(parsedText || obj);
} else {
const parsedText = (0, _utils.parseXMLResponse)(obj);
if (parsedText !== null) {
result.push(parsedText);
}
}
});
if (result.length !== text.length) {
throw new Error('Mismatching a lengths of original and translated arrays');
}
return result;
} catch (err) {
console.warn('Got response', rawResp);
throw err;
}
});
});
}
}
exports.GoogleTranslator = GoogleTranslator;
GoogleTranslator.translatorName = 'GoogleTranslator';
/**
* Translator implementation which use Google API without token
*/
class GoogleTranslatorTokenFree extends AbstractGoogleTranslator {
constructor() {
super(...arguments);
this.translate = (text, from, to) => __awaiter(this, void 0, void 0, function* () {
const [translation] = yield this.translateBatch([text], from, to);
return translation;
});
}
translateBatch(text, from, to) {
const apiPath = 'https://translate.googleapis.com/translate_a/t';
const data = {
client: 'dict-chrome-ex',
sl: (0, _languages.getFixedLanguage)(from),
tl: (0, _languages.getFixedLanguage)(to),
q: text
};
const url = apiPath + '?' + _queryString.default.stringify(data);
return this.fetch(url, {
responseType: 'json',
method: 'GET',
headers: Object.assign({
'Content-Type': 'application/x-www-form-urlencoded'
}, this.options.headers)
}).then(rsp => rsp.data).then(rawResp => {
try {
if (!Array.isArray(rawResp)) {
throw new Error('Unexpected response');
}
const intermediateTextsArray = [];
(0, _utils.visitArrayItems)(rawResp, obj => {
if (typeof obj === 'string') {
intermediateTextsArray.push(obj);
}
});
const result = [];
const isSingleResponseMode = text.length === 1;
const isOneToOneMappingMode = intermediateTextsArray.length === text.length;
for (let idx = 0; idx < intermediateTextsArray.length; idx++) {
const text = intermediateTextsArray[idx];
if (isSingleResponseMode) {
result.push(text);
break;
}
// Each second text it's not translation if not 1-1 mapping
const isTranslation = isOneToOneMappingMode || Number(idx) % 2 === 0;
if (isTranslation) {
result.push(text);
}
}
if (result.length !== text.length) {
console.warn('Translation result', result);
throw new Error('Mismatching a lengths of original and translated arrays');
}
return result;
} catch (err) {
console.warn('Got response', rawResp);
throw err;
}
});
}
}
exports.GoogleTranslatorTokenFree = GoogleTranslatorTokenFree;
GoogleTranslatorTokenFree.translatorName = 'GoogleTranslatorTokenFree';
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsYXRvcnMvR29vZ2xlVHJhbnNsYXRvci9pbmRleC5qcyIsIm5hbWVzIjpbIl9xdWVyeVN0cmluZyIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX0Jhc2VUcmFuc2xhdG9yIiwiX2xhbmd1YWdlcyIsIl90b2tlbiIsIl91dGlscyIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsIkFic3RyYWN0R29vZ2xlVHJhbnNsYXRvciIsIkJhc2VUcmFuc2xhdG9yIiwiaXNTdXBwb3J0ZWRBdXRvRnJvbSIsImdldFN1cHBvcnRlZExhbmd1YWdlcyIsImxhbmd1YWdlQWxpYXNlcyIsImdldEFsbCIsImdldExlbmd0aExpbWl0IiwiZ2V0UmVxdWVzdHNUaW1lb3V0IiwiZXhwb3J0cyIsIkdvb2dsZVRyYW5zbGF0b3IiLCJjaGVja0xpbWl0RXhjZWVkaW5nIiwidGV4dCIsIkFycmF5IiwiaXNBcnJheSIsImVuY29kZWRUZXh0IiwiZW5jb2RlRm9yQmF0Y2giLCJqb2luIiwiZXh0cmEiLCJsZW5ndGgiLCJ0cmFuc2xhdGUiLCJmcm9tIiwidG8iLCJnZXRUb2tlbiIsInRoZW4iLCJ2YWx1ZSIsInRrIiwiYXBpUGF0aCIsImRhdGEiLCJjbGllbnQiLCJzbCIsImdldEZpeGVkTGFuZ3VhZ2UiLCJ0bCIsImhsIiwiZHQiLCJpZSIsIm9lIiwib3RmIiwic3NlbCIsInRzZWwiLCJrYyIsInEiLCJ1cmwiLCJxdWVyeVN0cmluZyIsInN0cmluZ2lmeSIsImZldGNoIiwicmVzcG9uc2VUeXBlIiwibWV0aG9kIiwiaGVhZGVycyIsIm9wdGlvbnMiLCJyc3AiLCJFcnJvciIsInRyYW5zbGF0ZWRUZXh0IiwibWFwIiwiY2h1bmsiLCJ0cmFuc2xhdGVCYXRjaCIsInByZXBhcmVkVGV4dCIsImFubm8iLCJ2IiwiZm9ybWF0IiwiYm9keSIsImVuY29kZVVSSUNvbXBvbmVudCIsIk9iamVjdCIsImFzc2lnbiIsInJhd1Jlc3AiLCJpc1NpbmdsZVJlc3BvbnNlTW9kZSIsInJlc3VsdCIsInZpc2l0QXJyYXlJdGVtcyIsIm9iaiIsInBhcnNlZFRleHQiLCJwYXJzZVhNTFJlc3BvbnNlIiwicHVzaCIsImVyciIsImNvbnNvbGUiLCJ3YXJuIiwidHJhbnNsYXRvck5hbWUiLCJHb29nbGVUcmFuc2xhdG9yVG9rZW5GcmVlIiwiY29uc3RydWN0b3IiLCJfX2F3YWl0ZXIiLCJ0cmFuc2xhdGlvbiIsImludGVybWVkaWF0ZVRleHRzQXJyYXkiLCJpc09uZVRvT25lTWFwcGluZ01vZGUiLCJpZHgiLCJpc1RyYW5zbGF0aW9uIiwiTnVtYmVyIl0sInNvdXJjZXMiOlsidHJhbnNsYXRvcnMvR29vZ2xlVHJhbnNsYXRvci9pbmRleC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgcXVlcnlTdHJpbmcgZnJvbSAncXVlcnktc3RyaW5nJztcblxuaW1wb3J0IHsgQmFzZVRyYW5zbGF0b3IgfSBmcm9tICcuLi9CYXNlVHJhbnNsYXRvcic7XG5pbXBvcnQgeyBnZXRGaXhlZExhbmd1YWdlLCBsYW5ndWFnZUFsaWFzZXMgfSBmcm9tICcuL2xhbmd1YWdlcyc7XG5pbXBvcnQgeyBnZXRUb2tlbiB9IGZyb20gJy4vdG9rZW4nO1xuaW1wb3J0IHsgZW5jb2RlRm9yQmF0Y2gsIHBhcnNlWE1MUmVzcG9uc2UsIHZpc2l0QXJyYXlJdGVtcyB9IGZyb20gJy4vdXRpbHMnO1xuXG4vKipcbiAqIENvbW1vbiBjbGFzcyBmb3IgZ29vZ2xlIHRyYW5zbGF0b3IgaW1wbGVtZW50YXRpb25zXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBBYnN0cmFjdEdvb2dsZVRyYW5zbGF0b3IgZXh0ZW5kcyBCYXNlVHJhbnNsYXRvciB7XG5cdHB1YmxpYyBzdGF0aWMgaXNTdXBwb3J0ZWRBdXRvRnJvbSgpIHtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXG5cdHB1YmxpYyBzdGF0aWMgZ2V0U3VwcG9ydGVkTGFuZ3VhZ2VzKCk6IHN0cmluZ1tdIHtcblx0XHRyZXR1cm4gbGFuZ3VhZ2VBbGlhc2VzLmdldEFsbCgpO1xuXHR9XG5cblx0cHVibGljIGdldExlbmd0aExpbWl0KCkge1xuXHRcdHJldHVybiA0MDAwO1xuXHR9XG5cblx0cHVibGljIGdldFJlcXVlc3RzVGltZW91dCgpIHtcblx0XHRyZXR1cm4gMzAwO1xuXHR9XG59XG5cbi8qKlxuICogVHJhbnNsYXRvciBpbXBsZW1lbnRhdGlvbiB3aGljaCB1c2UgR29vZ2xlIEFQSSB3aXRoIHRva2VuIGZyb20gaHR0cHM6Ly90cmFuc2xhdGUuZ29vZ2xlLmNvbVxuICovXG5leHBvcnQgY2xhc3MgR29vZ2xlVHJhbnNsYXRvciBleHRlbmRzIEFic3RyYWN0R29vZ2xlVHJhbnNsYXRvciB7XG5cdHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgdHJhbnNsYXRvck5hbWUgPSAnR29vZ2xlVHJhbnNsYXRvcic7XG5cblx0cHVibGljIGNoZWNrTGltaXRFeGNlZWRpbmcodGV4dDogc3RyaW5nIHwgc3RyaW5nW10pIHtcblx0XHRpZiAoQXJyYXkuaXNBcnJheSh0ZXh0KSkge1xuXHRcdFx0Y29uc3QgZW5jb2RlZFRleHQgPSBlbmNvZGVGb3JCYXRjaCh0ZXh0KS5qb2luKCcnKTtcblx0XHRcdGNvbnN0IGV4dHJhID0gZW5jb2RlZFRleHQubGVuZ3RoIC0gdGhpcy5nZXRMZW5ndGhMaW1pdCgpO1xuXHRcdFx0cmV0dXJuIGV4dHJhID4gMCA/IGV4dHJhIDogMDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Y29uc3QgZXh0cmEgPSB0ZXh0Lmxlbmd0aCAtIHRoaXMuZ2V0TGVuZ3RoTGltaXQoKTtcblx0XHRcdHJldHVybiBleHRyYSA+IDAgPyBleHRyYSA6IDA7XG5cdFx0fVxuXHR9XG5cblx0cHVibGljIHRyYW5zbGF0ZSh0ZXh0OiBzdHJpbmcsIGZyb206IHN0cmluZywgdG86IHN0cmluZykge1xuXHRcdHJldHVybiBnZXRUb2tlbih0ZXh0KS50aGVuKCh7IHZhbHVlOiB0ayB9KSA9PiB7XG5cdFx0XHRjb25zdCBhcGlQYXRoID0gJ2h0dHBzOi8vdHJhbnNsYXRlLmdvb2dsZS5jb20vdHJhbnNsYXRlX2Evc2luZ2xlJztcblxuXHRcdFx0Y29uc3QgZGF0YSA9IHtcblx0XHRcdFx0Y2xpZW50OiAndCcsXG5cdFx0XHRcdHNsOiBnZXRGaXhlZExhbmd1YWdlKGZyb20pLFxuXHRcdFx0XHR0bDogZ2V0Rml4ZWRMYW5ndWFnZSh0byksXG5cdFx0XHRcdGhsOiBnZXRGaXhlZExhbmd1YWdlKHRvKSxcblx0XHRcdFx0ZHQ6IFsnYXQnLCAnYmQnLCAnZXgnLCAnbGQnLCAnbWQnLCAncWNhJywgJ3J3JywgJ3JtJywgJ3NzJywgJ3QnXSxcblx0XHRcdFx0aWU6ICdVVEYtOCcsXG5cdFx0XHRcdG9lOiAnVVRGLTgnLFxuXHRcdFx0XHRvdGY6IDEsXG5cdFx0XHRcdHNzZWw6IDAsXG5cdFx0XHRcdHRzZWw6IDAsXG5cdFx0XHRcdGtjOiA3LFxuXHRcdFx0XHRxOiB0ZXh0LFxuXHRcdFx0XHR0ayxcblx0XHRcdH07XG5cblx0XHRcdGNvbnN0IHVybCA9IGFwaVBhdGggKyAnPycgKyBxdWVyeVN0cmluZy5zdHJpbmdpZnkoZGF0YSk7XG5cblx0XHRcdHJldHVybiB0aGlzLmZldGNoKHVybCwge1xuXHRcdFx0XHRyZXNwb25zZVR5cGU6ICdqc29uJyxcblx0XHRcdFx0bWV0aG9kOiAnR0VUJyxcblx0XHRcdFx0aGVhZGVyczogdGhpcy5vcHRpb25zLmhlYWRlcnMsXG5cdFx0XHR9KVxuXHRcdFx0XHQudGhlbigocnNwKSA9PiByc3AuZGF0YSlcblx0XHRcdFx0LnRoZW4oKHJzcCkgPT4ge1xuXHRcdFx0XHRcdGlmICghKHJzcCBpbnN0YW5jZW9mIEFycmF5KSB8fCAhKHJzcFswXSBpbnN0YW5jZW9mIEFycmF5KSkge1xuXHRcdFx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCdVbmV4cGVjdGVkIHJlc3BvbnNlJyk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Y29uc3QgdHJhbnNsYXRlZFRleHQgPSByc3BbMF1cblx0XHRcdFx0XHRcdC5tYXAoKGNodW5rKSA9PlxuXHRcdFx0XHRcdFx0XHRjaHVuayBpbnN0YW5jZW9mIEFycmF5ICYmIHR5cGVvZiBjaHVua1swXSA9PT0gJ3N0cmluZydcblx0XHRcdFx0XHRcdFx0XHQ/IGNodW5rWzBdXG5cdFx0XHRcdFx0XHRcdFx0OiAnJyxcblx0XHRcdFx0XHRcdClcblx0XHRcdFx0XHRcdC5qb2luKCcnKTtcblxuXHRcdFx0XHRcdHJldHVybiB0cmFuc2xhdGVkVGV4dDtcblx0XHRcdFx0fSk7XG5cdFx0fSk7XG5cdH1cblxuXHRwdWJsaWMgdHJhbnNsYXRlQmF0Y2godGV4dDogc3RyaW5nW10sIGZyb206IHN0cmluZywgdG86IHN0cmluZykge1xuXHRcdGNvbnN0IHByZXBhcmVkVGV4dCA9IGVuY29kZUZvckJhdGNoKHRleHQpO1xuXHRcdHJldHVybiBnZXRUb2tlbihwcmVwYXJlZFRleHQuam9pbignJykpLnRoZW4oKHsgdmFsdWU6IHRrIH0pID0+IHtcblx0XHRcdGNvbnN0IGFwaVBhdGggPSAnaHR0cHM6Ly90cmFuc2xhdGUuZ29vZ2xlYXBpcy5jb20vdHJhbnNsYXRlX2EvdCc7XG5cblx0XHRcdGNvbnN0IGRhdGEgPSB7XG5cdFx0XHRcdGFubm86IDMsXG5cdFx0XHRcdGNsaWVudDogJ3RlJyxcblx0XHRcdFx0djogJzEuMCcsXG5cdFx0XHRcdGZvcm1hdDogJ2h0bWwnLFxuXHRcdFx0XHRzbDogZ2V0Rml4ZWRMYW5ndWFnZShmcm9tKSxcblx0XHRcdFx0dGw6IGdldEZpeGVkTGFuZ3VhZ2UodG8pLFxuXHRcdFx0XHR0ayxcblx0XHRcdH07XG5cblx0XHRcdGNvbnN0IHVybCA9IGFwaVBhdGggKyAnPycgKyBxdWVyeVN0cmluZy5zdHJpbmdpZnkoZGF0YSk7XG5cdFx0XHRjb25zdCBib2R5ID0gcHJlcGFyZWRUZXh0XG5cdFx0XHRcdC5tYXAoKHRleHQpID0+IGAmcT0ke2VuY29kZVVSSUNvbXBvbmVudCh0ZXh0KX1gKVxuXHRcdFx0XHQuam9pbignJyk7XG5cblx0XHRcdHJldHVybiB0aGlzLmZldGNoKHVybCwge1xuXHRcdFx0XHRyZXNwb25zZVR5cGU6ICdqc29uJyxcblx0XHRcdFx0bWV0aG9kOiAnUE9TVCcsXG5cdFx0XHRcdGhlYWRlcnM6IHtcblx0XHRcdFx0XHQnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCcsXG5cdFx0XHRcdFx0Li4udGhpcy5vcHRpb25zLmhlYWRlcnMsXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGJvZHksXG5cdFx0XHR9KVxuXHRcdFx0XHQudGhlbigocnNwKSA9PiByc3AuZGF0YSlcblx0XHRcdFx0LnRoZW4oKHJhd1Jlc3ApID0+IHtcblx0XHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdFx0aWYgKCFBcnJheS5pc0FycmF5KHJhd1Jlc3ApKSB7XG5cdFx0XHRcdFx0XHRcdHRocm93IG5ldyBFcnJvcignVW5leHBlY3RlZCByZXNwb25zZScpO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRjb25zdCBpc1NpbmdsZVJlc3BvbnNlTW9kZSA9IHRleHQubGVuZ3RoID09PSAxO1xuXG5cdFx0XHRcdFx0XHRjb25zdCByZXN1bHQ6IHN0cmluZ1tdID0gW107XG5cdFx0XHRcdFx0XHR2aXNpdEFycmF5SXRlbXMocmF3UmVzcCwgKG9iaikgPT4ge1xuXHRcdFx0XHRcdFx0XHRpZiAoaXNTaW5nbGVSZXNwb25zZU1vZGUgJiYgcmVzdWx0Lmxlbmd0aCA9PT0gMSkgcmV0dXJuO1xuXG5cdFx0XHRcdFx0XHRcdGlmICh0eXBlb2Ygb2JqICE9PSAnc3RyaW5nJykgcmV0dXJuO1xuXG5cdFx0XHRcdFx0XHRcdGlmIChpc1NpbmdsZVJlc3BvbnNlTW9kZSkge1xuXHRcdFx0XHRcdFx0XHRcdGNvbnN0IHBhcnNlZFRleHQgPSBwYXJzZVhNTFJlc3BvbnNlKG9iaik7XG5cdFx0XHRcdFx0XHRcdFx0cmVzdWx0LnB1c2gocGFyc2VkVGV4dCB8fCBvYmopO1xuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdGNvbnN0IHBhcnNlZFRleHQgPSBwYXJzZVhNTFJlc3BvbnNlKG9iaik7XG5cdFx0XHRcdFx0XHRcdFx0aWYgKHBhcnNlZFRleHQgIT09IG51bGwpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHJlc3VsdC5wdXNoKHBhcnNlZFRleHQpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0XHRcdGlmIChyZXN1bHQubGVuZ3RoICE9PSB0ZXh0Lmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoXG5cdFx0XHRcdFx0XHRcdFx0J01pc21hdGNoaW5nIGEgbGVuZ3RocyBvZiBvcmlnaW5hbCBhbmQgdHJhbnNsYXRlZCBhcnJheXMnLFxuXHRcdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRyZXR1cm4gcmVzdWx0O1xuXHRcdFx0XHRcdH0gY2F0Y2ggKGVycikge1xuXHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCdHb3QgcmVzcG9uc2UnLCByYXdSZXNwKTtcblx0XHRcdFx0XHRcdHRocm93IGVycjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0pO1xuXHRcdH0pO1xuXHR9XG59XG5cbi8qKlxuICogVHJhbnNsYXRvciBpbXBsZW1lbnRhdGlvbiB3aGljaCB1c2UgR29vZ2xlIEFQSSB3aXRob3V0IHRva2VuXG4gKi9cbmV4cG9ydCBjbGFzcyBHb29nbGVUcmFuc2xhdG9yVG9rZW5GcmVlIGV4dGVuZHMgQWJzdHJhY3RHb29nbGVUcmFuc2xhdG9yIHtcblx0cHVibGljIHN0YXRpYyByZWFkb25seSB0cmFuc2xhdG9yTmFtZSA9ICdHb29nbGVUcmFuc2xhdG9yVG9rZW5GcmVlJztcblxuXHRwdWJsaWMgdHJhbnNsYXRlID0gYXN5bmMgKHRleHQ6IHN0cmluZywgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nKSA9PiB7XG5cdFx0Y29uc3QgW3RyYW5zbGF0aW9uXSA9IGF3YWl0IHRoaXMudHJhbnNsYXRlQmF0Y2goW3RleHRdLCBmcm9tLCB0byk7XG5cdFx0cmV0dXJuIHRyYW5zbGF0aW9uO1xuXHR9O1xuXG5cdHB1YmxpYyB0cmFuc2xhdGVCYXRjaCh0ZXh0OiBzdHJpbmdbXSwgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nKSB7XG5cdFx0Y29uc3QgYXBpUGF0aCA9ICdodHRwczovL3RyYW5zbGF0ZS5nb29nbGVhcGlzLmNvbS90cmFuc2xhdGVfYS90JztcblxuXHRcdGNvbnN0IGRhdGEgPSB7XG5cdFx0XHRjbGllbnQ6ICdkaWN0LWNocm9tZS1leCcsXG5cdFx0XHRzbDogZ2V0Rml4ZWRMYW5ndWFnZShmcm9tKSxcblx0XHRcdHRsOiBnZXRGaXhlZExhbmd1YWdlKHRvKSxcblx0XHRcdHE6IHRleHQsXG5cdFx0fTtcblxuXHRcdGNvbnN0IHVybCA9IGFwaVBhdGggKyAnPycgKyBxdWVyeVN0cmluZy5zdHJpbmdpZnkoZGF0YSk7XG5cblx0XHRyZXR1cm4gdGhpcy5mZXRjaCh1cmwsIHtcblx0XHRcdHJlc3BvbnNlVHlwZTogJ2pzb24nLFxuXHRcdFx0bWV0aG9kOiAnR0VUJyxcblx0XHRcdGhlYWRlcnM6IHtcblx0XHRcdFx0J0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQnLFxuXHRcdFx0XHQuLi50aGlzLm9wdGlvbnMuaGVhZGVycyxcblx0XHRcdH0sXG5cdFx0fSlcblx0XHRcdC50aGVuKChyc3ApID0+IHJzcC5kYXRhKVxuXHRcdFx0LnRoZW4oKHJhd1Jlc3ApID0+IHtcblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRpZiAoIUFycmF5LmlzQXJyYXkocmF3UmVzcCkpIHtcblx0XHRcdFx0XHRcdHRocm93IG5ldyBFcnJvcignVW5leHBlY3RlZCByZXNwb25zZScpO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGNvbnN0IGludGVybWVkaWF0ZVRleHRzQXJyYXk6IHN0cmluZ1tdID0gW107XG5cdFx0XHRcdFx0dmlzaXRBcnJheUl0ZW1zKHJhd1Jlc3AsIChvYmopID0+IHtcblx0XHRcdFx0XHRcdGlmICh0eXBlb2Ygb2JqID09PSAnc3RyaW5nJykge1xuXHRcdFx0XHRcdFx0XHRpbnRlcm1lZGlhdGVUZXh0c0FycmF5LnB1c2gob2JqKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9KTtcblxuXHRcdFx0XHRcdGNvbnN0IHJlc3VsdDogc3RyaW5nW10gPSBbXTtcblxuXHRcdFx0XHRcdGNvbnN0IGlzU2luZ2xlUmVzcG9uc2VNb2RlID0gdGV4dC5sZW5ndGggPT09IDE7XG5cdFx0XHRcdFx0Y29uc3QgaXNPbmVUb09uZU1hcHBpbmdNb2RlID1cblx0XHRcdFx0XHRcdGludGVybWVkaWF0ZVRleHRzQXJyYXkubGVuZ3RoID09PSB0ZXh0Lmxlbmd0aDtcblx0XHRcdFx0XHRmb3IgKGxldCBpZHggPSAwOyBpZHggPCBpbnRlcm1lZGlhdGVUZXh0c0FycmF5Lmxlbmd0aDsgaWR4KyspIHtcblx0XHRcdFx0XHRcdGNvbnN0IHRleHQgPSBpbnRlcm1lZGlhdGVUZXh0c0FycmF5W2lkeF07XG5cblx0XHRcdFx0XHRcdGlmIChpc1NpbmdsZVJlc3BvbnNlTW9kZSkge1xuXHRcdFx0XHRcdFx0XHRyZXN1bHQucHVzaCh0ZXh0KTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdC8vIEVhY2ggc2Vjb25kIHRleHQgaXQncyBub3QgdHJhbnNsYXRpb24gaWYgbm90IDEtMSBtYXBwaW5nXG5cdFx0XHRcdFx0XHRjb25zdCBpc1RyYW5zbGF0aW9uID1cblx0XHRcdFx0XHRcdFx0aXNPbmVUb09uZU1hcHBpbmdNb2RlIHx8IE51bWJlcihpZHgpICUgMiA9PT0gMDtcblx0XHRcdFx0XHRcdGlmIChpc1RyYW5zbGF0aW9uKSB7XG5cdFx0XHRcdFx0XHRcdHJlc3VsdC5wdXNoKHRleHQpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmIChyZXN1bHQubGVuZ3RoICE9PSB0ZXh0Lmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCdUcmFuc2xhdGlvbiByZXN1bHQnLCByZXN1bHQpO1xuXHRcdFx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKFxuXHRcdFx0XHRcdFx0XHQnTWlzbWF0Y2hpbmcgYSBsZW5ndGhzIG9mIG9yaWdpbmFsIGFuZCB0cmFuc2xhdGVkIGFycmF5cycsXG5cdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdHJldHVybiByZXN1bHQ7XG5cdFx0XHRcdH0gY2F0Y2ggKGVycikge1xuXHRcdFx0XHRcdGNvbnNvbGUud2FybignR290IHJlc3BvbnNlJywgcmF3UmVzcCk7XG5cdFx0XHRcdFx0dGhyb3cgZXJyO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0fVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxJQUFBQSxZQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBQyxlQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxVQUFBLEdBQUFGLE9BQUE7QUFDQSxJQUFBRyxNQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxNQUFBLEdBQUFKLE9BQUE7QUFBNEUsU0FBQUQsdUJBQUFNLENBQUEsV0FBQUEsQ0FBQSxJQUFBQSxDQUFBLENBQUFDLFVBQUEsR0FBQUQsQ0FBQSxLQUFBRSxPQUFBLEVBQUFGLENBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFNUU7OztBQUdNLE1BQWdCRyx3QkFBeUIsU0FBUUMsOEJBQWM7RUFDN0QsT0FBT0MsbUJBQW1CQSxDQUFBO0lBQ2hDLE9BQU8sSUFBSTtFQUNaO0VBRU8sT0FBT0MscUJBQXFCQSxDQUFBO0lBQ2xDLE9BQU9DLDBCQUFlLENBQUNDLE1BQU0sRUFBRTtFQUNoQztFQUVPQyxjQUFjQSxDQUFBO0lBQ3BCLE9BQU8sSUFBSTtFQUNaO0VBRU9DLGtCQUFrQkEsQ0FBQTtJQUN4QixPQUFPLEdBQUc7RUFDWDs7QUFHRDs7O0FBQUFDLE9BQUEsQ0FBQVIsd0JBQUEsR0FBQUEsd0JBQUE7QUFHTSxNQUFPUyxnQkFBaUIsU0FBUVQsd0JBQXdCO0VB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QUFLLENBQUMscUJBQXFCLENBQUM7UUFDdkM7UUFFQSxNQUFNNkIsc0JBQXNCLEdBQWEsRUFBRTtRQUMzQyxJQUFBYixzQkFBZSxFQUFDSCxPQUFPLEVBQUdJLEdBQUcsSUFBSTtVQUNoQyxJQUFJLE9BQU9BLEdBQUcsS0FBSyxRQUFRLEVBQUU7WUFDNUJZLHNCQUFzQixDQUFDVCxJQUFJLENBQUNILEdBQUcsQ0FBQztVQUNqQztRQUNELENBQUMsQ0FBQztRQUVGLE1BQU1GLE1BQU0sR0FBYSxFQUFFO1FBRTNCLE1BQU1ELG9CQUFvQixHQUFHckQsSUFBSSxDQUFDTyxNQUFNLEtBQUssQ0FBQztRQUM5QyxNQUFNOEQscUJBQXFCLEdBQzFCRCxzQkFBc0IsQ0FBQzdELE1BQU0sS0FBS1AsSUFBSSxDQUFDTyxNQUFNO1FBQzlDLEtBQUssSUFBSStELEdBQUcsR0FBRyxDQUFDLEVBQUVBLEdBQUcsR0FBR0Ysc0JBQXNCLENBQUM3RCxNQUFNLEVBQUUrRCxHQUFHLEVBQUUsRUFBRTtVQUM3RCxNQUFNdEUsSUFBSSxHQUFHb0Usc0JBQXNCLENBQUNFLEdBQUcsQ0FBQztVQUV4QyxJQUFJakIsb0JBQW9CLEVBQUU7WUFDekJDLE1BQU0sQ0FBQ0ssSUFBSSxDQUFDM0QsSUFBSSxDQUFDO1lBQ2pCO1VBQ0Q7VUFFQTtVQUNBLE1BQU11RSxhQUFhLEdBQ2xCRixxQkFBcUIsSUFBSUcsTUFBTSxDQUFDRixHQUFHLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQztVQUMvQyxJQUFJQyxhQUFhLEVBQUU7WUFDbEJqQixNQUFNLENBQUNLLElBQUksQ0FBQzNELElBQUksQ0FBQztVQUNsQjtRQUNEO1FBRUEsSUFBSXNELE1BQU0sQ0FBQy9DLE1BQU0sS0FBS1AsSUFBSSxDQUFDTyxNQUFNLEVBQUU7VUFDbENzRCxPQUFPLENBQUNDLElBQUksQ0FBQyxvQkFBb0IsRUFBRVIsTUFBTSxDQUFDO1VBQzFDLE1BQU0sSUFBSWYsS0FBSyxDQUNkLHlEQUF5RCxDQUN6RDtRQUNGO1FBRUEsT0FBT2UsTUFBTTtNQUNkLENBQUMsQ0FBQyxPQUFPTSxHQUFHLEVBQUU7UUFDYkMsT0FBTyxDQUFDQyxJQUFJLENBQUMsY0FBYyxFQUFFVixPQUFPLENBQUM7UUFDckMsTUFBTVEsR0FBRztNQUNWO0lBQ0QsQ0FBQyxDQUFDO0VBQ0o7OztBQTNFdUJJLHlCQUFBLENBQUFELGNBQWMsR0FBRywyQkFBSCIsImlnbm9yZUxpc3QiOltdfQ==