anylang
Version:
A translator's kit that uses the free APIs of Google Translate, Yandex, Bing, ChatGPT, and other LLMs
116 lines (114 loc) • 16 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getPrompt = exports.LLMTranslator = void 0;
var _zod = require("zod");
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());
});
};
const getPrompt = (text, from, to) => {
// use full language name
const langFormatter = new Intl.DisplayNames(['en'], {
type: 'language'
});
const originLang = from == 'auto' ? 'auto' : langFormatter.of(from);
const targetLang = langFormatter.of(to);
return `You are a text translation service. I will provide an array of texts, and your task is to translate them from language ${originLang} to language ${targetLang}.
If I specify the source language as 'auto', you should automatically detect it and translate it into the target language I set.
The array in your response must be the same length as the one in the request. Do not add any explanations — translate strictly according to the content.
Be careful when creating an array; it must be syntactically correct and do not change quotation marks. Return an array of translated texts while preserving their order.
Here is the JSON array of texts: ${JSON.stringify(text)}`;
};
exports.getPrompt = getPrompt;
class LLMTranslator {
constructor(llm, options) {
var _a, _b, _c, _d, _e, _f, _g;
this.llm = llm;
this.config = {
retryLimit: (_b = (_a = options === null || options === void 0 ? void 0 : options.retryOptions) === null || _a === void 0 ? void 0 : _a.retryLimit) !== null && _b !== void 0 ? _b : 3,
retryTimeout: (_d = (_c = options === null || options === void 0 ? void 0 : options.retryOptions) === null || _c === void 0 ? void 0 : _c.retryTimeout) !== null && _d !== void 0 ? _d : this.llm.getRequestsTimeout(),
maxRetryTimeout: (_e = options === null || options === void 0 ? void 0 : options.retryOptions) === null || _e === void 0 ? void 0 : _e.maxRetryTimeout,
retryBackoffFactor: (_f = options === null || options === void 0 ? void 0 : options.retryOptions) === null || _f === void 0 ? void 0 : _f.retryBackoffFactor,
getPrompt: (_g = options === null || options === void 0 ? void 0 : options.getPrompt) !== null && _g !== void 0 ? _g : getPrompt
};
}
translate(text, from, to) {
return __awaiter(this, void 0, void 0, function* () {
const translated = yield this.translateBatch([text], from, to);
return translated[0];
});
}
translateBatch(text, from, to) {
return __awaiter(this, void 0, void 0, function* () {
let attempt = 0;
// Retry loop
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
while (true) {
try {
// first request without delay
if (attempt > 0) {
yield this.waitRetryDelay(attempt);
}
const response = yield this.llm.fetch(this.config.getPrompt(text, from, to));
const validateResult = _zod.z.string().array().length(text.length, {
message: 'The response must be the same length as the requested array'
}).parse(JSON.parse(response));
return validateResult;
} catch (error) {
attempt++;
if (attempt >= this.config.retryLimit) throw error;
}
}
});
}
getLengthLimit() {
return this.llm.getLengthLimit();
}
getRequestsTimeout() {
return this.llm.getRequestsTimeout();
}
checkLimitExceeding(text) {
const plainText = Array.isArray(text) ? text.join('') : text;
const extra = plainText.length - this.getLengthLimit();
return extra > 0 ? extra : 0;
}
/**
* Calculates retry delays: starts with retryTimeout,
* then increases exponentially (retryTimeout * factor^n) up to maxRetryTimeout (default: 4000).
* Default retryBackoffFactor: 1.5
*/
waitRetryDelay(attempt) {
var _a, _b;
const maxTimeout = (_a = this.config.maxRetryTimeout) !== null && _a !== void 0 ? _a : 4000;
const factor = (_b = this.config.retryBackoffFactor) !== null && _b !== void 0 ? _b : 1.5;
const delay = Math.min(maxTimeout, this.config.retryTimeout * Math.pow(factor, attempt - 1));
return new Promise(r => setTimeout(r, delay));
}
}
exports.LLMTranslator = LLMTranslator;
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNsYXRvcnMvTExNVHJhbnNsYXRvcnMvTExNVHJhbnNsYXRvci5qcyIsIm5hbWVzIjpbIl96b2QiLCJyZXF1aXJlIiwiZ2V0UHJvbXB0IiwidGV4dCIsImZyb20iLCJ0byIsImxhbmdGb3JtYXR0ZXIiLCJJbnRsIiwiRGlzcGxheU5hbWVzIiwidHlwZSIsIm9yaWdpbkxhbmciLCJvZiIsInRhcmdldExhbmciLCJKU09OIiwic3RyaW5naWZ5IiwiZXhwb3J0cyIsIkxMTVRyYW5zbGF0b3IiLCJjb25zdHJ1Y3RvciIsImxsbSIsIm9wdGlvbnMiLCJjb25maWciLCJyZXRyeUxpbWl0IiwiX2IiLCJfYSIsInJldHJ5T3B0aW9ucyIsInJldHJ5VGltZW91dCIsIl9kIiwiX2MiLCJnZXRSZXF1ZXN0c1RpbWVvdXQiLCJtYXhSZXRyeVRpbWVvdXQiLCJfZSIsInJldHJ5QmFja29mZkZhY3RvciIsIl9mIiwiX2ciLCJ0cmFuc2xhdGUiLCJ0cmFuc2xhdGVkIiwidHJhbnNsYXRlQmF0Y2giLCJhdHRlbXB0Iiwid2FpdFJldHJ5RGVsYXkiLCJyZXNwb25zZSIsImZldGNoIiwidmFsaWRhdGVSZXN1bHQiLCJ6Iiwic3RyaW5nIiwiYXJyYXkiLCJsZW5ndGgiLCJtZXNzYWdlIiwicGFyc2UiLCJlcnJvciIsImdldExlbmd0aExpbWl0IiwiY2hlY2tMaW1pdEV4Y2VlZGluZyIsInBsYWluVGV4dCIsIkFycmF5IiwiaXNBcnJheSIsImpvaW4iLCJleHRyYSIsIm1heFRpbWVvdXQiLCJmYWN0b3IiLCJkZWxheSIsIk1hdGgiLCJtaW4iLCJwb3ciLCJQcm9taXNlIiwiciIsInNldFRpbWVvdXQiXSwic291cmNlcyI6WyJ0cmFuc2xhdG9ycy9MTE1UcmFuc2xhdG9ycy9MTE1UcmFuc2xhdG9yLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xuXG5pbXBvcnQgeyBUcmFuc2xhdG9ySW5zdGFuY2VNZW1iZXJzIH0gZnJvbSAnLi4vVHJhbnNsYXRvcic7XG5pbXBvcnQgeyBMTE1GZXRjaGVyIH0gZnJvbSAnLic7XG5cbmV4cG9ydCB0eXBlIFByb21wdEdlbmVyYXRvciA9ICh0ZXh0czogc3RyaW5nW10sIGZyb206IHN0cmluZywgdG86IHN0cmluZykgPT4gc3RyaW5nO1xuXG5leHBvcnQgdHlwZSBMTE1UcmFuc2xhdG9yUmV0cnlPcHRpb25zID0ge1xuXHQvKipcblx0ICogTWF4aW11bSBudW1iZXIgb2YgcmV0cnkgYXR0ZW1wdHMgYWZ0ZXIgYSBmYWlsZWQgcmVxdWVzdFxuXHQgKi9cblx0cmV0cnlMaW1pdD86IG51bWJlcjtcblxuXHQvKipcblx0ICogRGVsYXkgYmVmb3JlIGZpcnN0IHJldHJ5IGluIG1zOyBpbmNyZWFzZXMgZXhwb25lbnRpYWxseSB1cCB0byBtYXhSZXRyeVRpbWVvdXRcblx0ICovXG5cdHJldHJ5VGltZW91dD86IG51bWJlcjtcblxuXHQvKipcblx0ICogTWF4aW11bSBkZWxheSBiZWZvcmUgdGhlIG5leHQgcmV0cnlcblx0ICovXG5cdG1heFJldHJ5VGltZW91dD86IG51bWJlcjtcblxuXHQvKipcblx0ICogQW4gZXhwb25lbnRpYWwgbXVsdGlwbGllciB1c2VkIHRvIGluY3JlYXNlIHRoZSBkZWxheSBiZXR3ZWVuIHJldHJ5IGF0dGVtcHRzLlxuXHQgKiBXaXRoIGVhY2ggYXR0ZW1wdCwgdGhlIGRlbGF5IGdyb3dzIGJhc2VkIG9uIHRoaXMgZmFjdG9yLlxuXHQgKi9cblx0cmV0cnlCYWNrb2ZmRmFjdG9yPzogbnVtYmVyO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldFByb21wdCA9ICh0ZXh0OiBzdHJpbmdbXSwgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nKSA9PiB7XG5cdC8vIHVzZSBmdWxsIGxhbmd1YWdlIG5hbWVcblx0Y29uc3QgbGFuZ0Zvcm1hdHRlciA9IG5ldyBJbnRsLkRpc3BsYXlOYW1lcyhbJ2VuJ10sIHsgdHlwZTogJ2xhbmd1YWdlJyB9KTtcblx0Y29uc3Qgb3JpZ2luTGFuZyA9IGZyb20gPT0gJ2F1dG8nID8gJ2F1dG8nIDogbGFuZ0Zvcm1hdHRlci5vZihmcm9tKTtcblx0Y29uc3QgdGFyZ2V0TGFuZyA9IGxhbmdGb3JtYXR0ZXIub2YodG8pO1xuXG5cdHJldHVybiBgWW91IGFyZSBhIHRleHQgdHJhbnNsYXRpb24gc2VydmljZS4gSSB3aWxsIHByb3ZpZGUgYW4gYXJyYXkgb2YgdGV4dHMsIGFuZCB5b3VyIHRhc2sgaXMgdG8gdHJhbnNsYXRlIHRoZW0gZnJvbSBsYW5ndWFnZSAke29yaWdpbkxhbmd9IHRvIGxhbmd1YWdlICR7dGFyZ2V0TGFuZ30uXG5JZiBJIHNwZWNpZnkgdGhlIHNvdXJjZSBsYW5ndWFnZSBhcyAnYXV0bycsIHlvdSBzaG91bGQgYXV0b21hdGljYWxseSBkZXRlY3QgaXQgYW5kIHRyYW5zbGF0ZSBpdCBpbnRvIHRoZSB0YXJnZXQgbGFuZ3VhZ2UgSSBzZXQuXG5UaGUgYXJyYXkgaW4geW91ciByZXNwb25zZSBtdXN0IGJlIHRoZSBzYW1lIGxlbmd0aCBhcyB0aGUgb25lIGluIHRoZSByZXF1ZXN0LiBEbyBub3QgYWRkIGFueSBleHBsYW5hdGlvbnMg4oCUIHRyYW5zbGF0ZSBzdHJpY3RseSBhY2NvcmRpbmcgdG8gdGhlIGNvbnRlbnQuIFxuQmUgY2FyZWZ1bCB3aGVuIGNyZWF0aW5nIGFuIGFycmF5OyBpdCBtdXN0IGJlIHN5bnRhY3RpY2FsbHkgY29ycmVjdCBhbmQgZG8gbm90IGNoYW5nZSBxdW90YXRpb24gbWFya3MuIFJldHVybiBhbiBhcnJheSBvZiB0cmFuc2xhdGVkIHRleHRzIHdoaWxlIHByZXNlcnZpbmcgdGhlaXIgb3JkZXIuXG5IZXJlIGlzIHRoZSBKU09OIGFycmF5IG9mIHRleHRzOiAke0pTT04uc3RyaW5naWZ5KHRleHQpfWA7XG59O1xuXG5leHBvcnQgY2xhc3MgTExNVHJhbnNsYXRvciBpbXBsZW1lbnRzIFRyYW5zbGF0b3JJbnN0YW5jZU1lbWJlcnMge1xuXHRwcml2YXRlIHJlYWRvbmx5IGNvbmZpZztcblxuXHRjb25zdHJ1Y3Rvcihcblx0XHRwcml2YXRlIHJlYWRvbmx5IGxsbTogTExNRmV0Y2hlcixcblx0XHRvcHRpb25zPzoge1xuXHRcdFx0Z2V0UHJvbXB0PzogUHJvbXB0R2VuZXJhdG9yO1xuXHRcdFx0cmV0cnlPcHRpb25zPzogTExNVHJhbnNsYXRvclJldHJ5T3B0aW9ucztcblx0XHR9LFxuXHQpIHtcblx0XHR0aGlzLmNvbmZpZyA9IHtcblx0XHRcdHJldHJ5TGltaXQ6IG9wdGlvbnM/LnJldHJ5T3B0aW9ucz8ucmV0cnlMaW1pdCA/PyAzLFxuXHRcdFx0cmV0cnlUaW1lb3V0OlxuXHRcdFx0XHRvcHRpb25zPy5yZXRyeU9wdGlvbnM/LnJldHJ5VGltZW91dCA/PyB0aGlzLmxsbS5nZXRSZXF1ZXN0c1RpbWVvdXQoKSxcblx0XHRcdG1heFJldHJ5VGltZW91dDogb3B0aW9ucz8ucmV0cnlPcHRpb25zPy5tYXhSZXRyeVRpbWVvdXQsXG5cdFx0XHRyZXRyeUJhY2tvZmZGYWN0b3I6IG9wdGlvbnM/LnJldHJ5T3B0aW9ucz8ucmV0cnlCYWNrb2ZmRmFjdG9yLFxuXHRcdFx0Z2V0UHJvbXB0OiBvcHRpb25zPy5nZXRQcm9tcHQgPz8gZ2V0UHJvbXB0LFxuXHRcdH07XG5cdH1cblxuXHRwdWJsaWMgYXN5bmMgdHJhbnNsYXRlKHRleHQ6IHN0cmluZywgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nKSB7XG5cdFx0Y29uc3QgdHJhbnNsYXRlZCA9IGF3YWl0IHRoaXMudHJhbnNsYXRlQmF0Y2goW3RleHRdLCBmcm9tLCB0byk7XG5cdFx0cmV0dXJuIHRyYW5zbGF0ZWRbMF07XG5cdH1cblxuXHRwdWJsaWMgYXN5bmMgdHJhbnNsYXRlQmF0Y2godGV4dDogc3RyaW5nW10sIGZyb206IHN0cmluZywgdG86IHN0cmluZykge1xuXHRcdGxldCBhdHRlbXB0ID0gMDtcblxuXHRcdC8vIFJldHJ5IGxvb3Bcblx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVubmVjZXNzYXJ5LWNvbmRpdGlvblxuXHRcdHdoaWxlICh0cnVlKSB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHQvLyBmaXJzdCByZXF1ZXN0IHdpdGhvdXQgZGVsYXlcblx0XHRcdFx0aWYgKGF0dGVtcHQgPiAwKSB7XG5cdFx0XHRcdFx0YXdhaXQgdGhpcy53YWl0UmV0cnlEZWxheShhdHRlbXB0KTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5sbG0uZmV0Y2goXG5cdFx0XHRcdFx0dGhpcy5jb25maWcuZ2V0UHJvbXB0KHRleHQsIGZyb20sIHRvKSxcblx0XHRcdFx0KTtcblxuXHRcdFx0XHRjb25zdCB2YWxpZGF0ZVJlc3VsdCA9IHpcblx0XHRcdFx0XHQuc3RyaW5nKClcblx0XHRcdFx0XHQuYXJyYXkoKVxuXHRcdFx0XHRcdC5sZW5ndGgodGV4dC5sZW5ndGgsIHtcblx0XHRcdFx0XHRcdG1lc3NhZ2U6XG5cdFx0XHRcdFx0XHRcdCdUaGUgcmVzcG9uc2UgbXVzdCBiZSB0aGUgc2FtZSBsZW5ndGggYXMgdGhlIHJlcXVlc3RlZCBhcnJheScsXG5cdFx0XHRcdFx0fSlcblx0XHRcdFx0XHQucGFyc2UoSlNPTi5wYXJzZShyZXNwb25zZSkpO1xuXG5cdFx0XHRcdHJldHVybiB2YWxpZGF0ZVJlc3VsdDtcblx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRcdGF0dGVtcHQrKztcblx0XHRcdFx0aWYgKGF0dGVtcHQgPj0gdGhpcy5jb25maWcucmV0cnlMaW1pdCkgdGhyb3cgZXJyb3I7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cHVibGljIGdldExlbmd0aExpbWl0KCkge1xuXHRcdHJldHVybiB0aGlzLmxsbS5nZXRMZW5ndGhMaW1pdCgpO1xuXHR9XG5cblx0cHVibGljIGdldFJlcXVlc3RzVGltZW91dCgpIHtcblx0XHRyZXR1cm4gdGhpcy5sbG0uZ2V0UmVxdWVzdHNUaW1lb3V0KCk7XG5cdH1cblxuXHRwdWJsaWMgY2hlY2tMaW1pdEV4Y2VlZGluZyh0ZXh0OiBzdHJpbmcgfCBzdHJpbmdbXSkge1xuXHRcdGNvbnN0IHBsYWluVGV4dCA9IEFycmF5LmlzQXJyYXkodGV4dCkgPyB0ZXh0LmpvaW4oJycpIDogdGV4dDtcblx0XHRjb25zdCBleHRyYSA9IHBsYWluVGV4dC5sZW5ndGggLSB0aGlzLmdldExlbmd0aExpbWl0KCk7XG5cdFx0cmV0dXJuIGV4dHJhID4gMCA/IGV4dHJhIDogMDtcblx0fVxuXG5cdC8qKlxuXHQgKiBDYWxjdWxhdGVzIHJldHJ5IGRlbGF5czogc3RhcnRzIHdpdGggcmV0cnlUaW1lb3V0LFxuXHQgKiB0aGVuIGluY3JlYXNlcyBleHBvbmVudGlhbGx5IChyZXRyeVRpbWVvdXQgKiBmYWN0b3JebikgdXAgdG8gbWF4UmV0cnlUaW1lb3V0IChkZWZhdWx0OiA0MDAwKS5cblx0ICogRGVmYXVsdCByZXRyeUJhY2tvZmZGYWN0b3I6IDEuNVxuXHQgKi9cblx0cHJpdmF0ZSB3YWl0UmV0cnlEZWxheShhdHRlbXB0OiBudW1iZXIpIHtcblx0XHRjb25zdCBtYXhUaW1lb3V0ID0gdGhpcy5jb25maWcubWF4UmV0cnlUaW1lb3V0ID8/IDQwMDA7XG5cdFx0Y29uc3QgZmFjdG9yID0gdGhpcy5jb25maWcucmV0cnlCYWNrb2ZmRmFjdG9yID8/IDEuNTtcblx0XHRjb25zdCBkZWxheSA9IE1hdGgubWluKFxuXHRcdFx0bWF4VGltZW91dCxcblx0XHRcdHRoaXMuY29uZmlnLnJldHJ5VGltZW91dCAqIGZhY3RvciAqKiAoYXR0ZW1wdCAtIDEpLFxuXHRcdCk7XG5cblx0XHRyZXR1cm4gbmV3IFByb21pc2UoKHIpID0+IHNldFRpbWVvdXQociwgZGVsYXkpKTtcblx0fVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxJQUFBQSxJQUFBLEdBQUFDLE9BQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUE4Qk8sTUFBTUMsU0FBUyxHQUFHQSxDQUFDQyxJQUFjLEVBQUVDLElBQVksRUFBRUMsRUFBVSxLQUFJO0VBQ3JFO0VBQ0EsTUFBTUMsYUFBYSxHQUFHLElBQUlD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QVEsQ0FBQyxDQUFDO1VBRTdCLE9BQU9FLGNBQWM7UUFDdEIsQ0FBQyxDQUFDLE9BQU9PLEtBQUssRUFBRTtVQUNmWCxPQUFPLEVBQUU7VUFDVCxJQUFJQSxPQUFPLElBQUksSUFBSSxDQUFDakIsTUFBTSxDQUFDQyxVQUFVLEVBQUUsTUFBTTJCLEtBQUs7UUFDbkQ7TUFDRDtJQUNELENBQUM7O0VBRU1DLGNBQWNBLENBQUE7SUFDcEIsT0FBTyxJQUFJLENBQUMvQixHQUFHLENBQUMrQixjQUFjLEVBQUU7RUFDakM7RUFFT3JCLGtCQUFrQkEsQ0FBQTtJQUN4QixPQUFPLElBQUksQ0FBQ1YsR0FBRyxDQUFDVSxrQkFBa0IsRUFBRTtFQUNyQztFQUVPc0IsbUJBQW1CQSxDQUFDL0MsSUFBdUI7SUFDakQsTUFBTWdELFNBQVMsR0FBR0MsS0FBSyxDQUFDQyxPQUFPLENBQUNsRCxJQUFJLENBQUMsR0FBR0EsSUFBSSxDQUFDbUQsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHbkQsSUFBSTtJQUM1RCxNQUFNb0QsS0FBSyxHQUFHSixTQUFTLENBQUNOLE1BQU0sR0FBRyxJQUFJLENBQUNJLGNBQWMsRUFBRTtJQUN0RCxPQUFPTSxLQUFLLEdBQUcsQ0FBQyxHQUFHQSxLQUFLLEdBQUcsQ0FBQztFQUM3QjtFQUVBOzs7OztFQUtRakIsY0FBY0EsQ0FBQ0QsT0FBZTs7SUFDckMsTUFBTW1CLFVBQVUsR0FBRyxDQUFBakMsRUFBQSxPQUFJLENBQUNILE1BQU0sQ0FBQ1MsZUFBZSxjQUFBTixFQUFBLGNBQUFBLEVBQUEsR0FBSSxJQUFJO0lBQ3RELE1BQU1rQyxNQUFNLEdBQUcsQ0FBQW5DLEVBQUEsT0FBSSxDQUFDRixNQUFNLENBQUNXLGtCQUFrQixjQUFBVCxFQUFBLGNBQUFBLEVBQUEsR0FBSSxHQUFHO0lBQ3BELE1BQU1vQyxLQUFLLEdBQUdDLElBQUksQ0FBQ0MsR0FBRyxDQUNyQkosVUFBVSxFQUNWLElBQUksQ0FBQ3BDLE1BQU0sQ0FBQ0ssWUFBWSxHQUFHa0MsSUFBQSxDQUFBRSxHQUFBLENBQUFKLE1BQU0sRUFBS3BCLE9BQU8sR0FBRyxDQUFFLEVBQ2xEO0lBRUQsT0FBTyxJQUFJeUIsT0FBTyxDQUFFQyxDQUFDLElBQUtDLFVBQVUsQ0FBQ0QsQ0FBQyxFQUFFTCxLQUFLLENBQUMsQ0FBQztFQUNoRDs7QUFDQTNDLE9BQUEsQ0FBQUMsYUFBQSxHQUFBQSxhQUFBIiwiaWdub3JlTGlzdCI6W119
;