@bxjs/base
Version:
bxjs base framework & api
813 lines • 130 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* 对于阿里云OTS表格存储的业务封装
*
* NOSQL的应用使用约定
* OTS四个KEYS字段2个占用,2个应用自己扩展使用,OTS限制最多定义4个主键,并且第一个主键zone为分区主键。
* KEYS:
* zone (如果在insert的时候不填写,按照uuid时间顺序生成分区键确保主键的唯一顺序性)
* [可扩展业务自定义的两个主键]
* id
* COLUMNS:
* // 预定义如下两个字段用于跟踪记录的创建时间和修改时间(不支持is_deleted假删除标记OTS的业务特点不适合使用)
* created_at
* updated_at
*/
var TableStore = require('tablestore');
var Long = TableStore.Long;
var _ = require('lodash');
var moment = require('moment');
var uuidv1 = require('uuid/v1');
// INT64基本数据类型的表格存储的扩展
function int64(v) {
if (typeof v == 'string') {
return Long.fromString(v);
}
else if (typeof v == 'number') {
return Long.fromNumber(v);
}
else {
xthrow(ERR$PARAM, { v: v, type: typeof v });
}
}
var inerface_1 = require("./inerface");
var NosqlAliyunTablestore = /** @class */ (function (_super) {
__extends(NosqlAliyunTablestore, _super);
function NosqlAliyunTablestore(table, config) {
if (config === void 0) { config = 'default'; }
var _this = _super.call(this, table, config) || this;
var instances = xconfig('plugins.nosql');
xassert(instances && _.isPlainObject(instances) && config in instances, ERR$CONFIG, { instances: instances });
_this._table = table;
_this._schema = Object.assign({}, instances[config].OTS_TABLES[table]);
// BUGFIX 解决tablestore特殊的设计进行包装通过约定对应用进行透明实现。
// 默认增加第一个zone分区键占用设置(插入数据没有赋值会自动补上散列算法自动进行算法实现),
// 如果没有定义主键自动补上一个id自增主键兼容业务应用(仅仅为KEYS为空的时候自动补上改值)。
if (_.isEmpty(_this._schema.KEYS))
_this._schema.KEYS = {};
if (_.isEmpty(_this._schema.COLUMNS))
_this._schema.COLUMNS = {};
// zone和id为约定主键禁止应用将其使用到主键或属性列定义中
xassert(!(inerface_1.ZONE_KEY_NAME in _this._schema.KEYS) && !(inerface_1.AUTO_KEY_NAME in _this._schema.KEYS), ERR$CONFIG, { schema: _this._schema });
xassert(!(inerface_1.ZONE_KEY_NAME in _this._schema.COLUMNS) && !(inerface_1.AUTO_KEY_NAME in _this._schema.COLUMNS), ERR$CONFIG, { schema: _this._schema });
// 检查主键数量最多用户可以自定义使用2个(id自增主键放在最后,zone分区键放在最前面)
xassert(_.keys(_this._schema.KEYS).length <= 2, ERR$CONFIG, { schema: _this._schema });
// zone为约定分区键无需在schema中定义是string类型会自动补上对应的主键定义(在表插入的时候如果用户不赋值则自动补上随机散列值)
var obj = {}; // 确保在新增两个约定主键后主键定义顺序与应用保持一致
obj[inerface_1.ZONE_KEY_NAME] = 'string';
if (_.isEmpty(_this._schema.KEYS)) {
// 如果一个用户自定义的主键都没有就自动补上一个自增主键id进行唯一标识(只能补到第二列才能正确检索)
obj[inerface_1.AUTO_KEY_NAME] = 'integer';
}
else {
for (var k in _this._schema.KEYS) {
obj[k] = _this._schema.KEYS[k];
}
}
_this._schema.KEYS = obj;
// 确保两个缺省字段都不存在在用户自定义的字段中(添加到COLUMNS定义中)
_this._schema.COLUMNS['created_at'] = 'string';
_this._schema.COLUMNS['updated_at'] = 'string';
_this._client = new TableStore.Client({
accessKeyId: instances[config].OTS_ACCESS_KEY_ID,
secretAccessKey: instances[config].OTS_SECRETE_ACCESS_KEY,
endpoint: instances[config].OTS_ENDPOINT,
instancename: instances[config].OTS_INSTANCENAME
});
return _this;
}
NosqlAliyunTablestore.prototype._check_type = function (value) {
return _.includes(['string', 'number', 'boolean'], typeof value);
};
// 对于行记录的schema模式校验确保数据类型严格的正确以及拼接完整的tablestore数据结构中的主键和属性两个字段
NosqlAliyunTablestore.prototype._check_schema = function (row, params, is_insert_check) {
if (is_insert_check === void 0) { is_insert_check = false; }
var _a, _b, _c, _d, _e;
// 需要对应用传入的主键序列严格按照schema定义的排序(否则OTS服务端无法进行正确处理而导致报错异常)
for (var k in this._schema.KEYS) {
if (!(k in row)) {
// 只有非插入属性并且为非自增主键的情况才会允许主键字段的输入必须要完整
xassert(is_insert_check && k == inerface_1.AUTO_KEY_NAME, ERR$PARAM, { k: k, row: row, params: params });
}
if (is_insert_check && k == inerface_1.AUTO_KEY_NAME) {
params.primaryKey.push((_a = {}, _a[inerface_1.AUTO_KEY_NAME] = TableStore.PK_AUTO_INCR, _a)); // 以id约定为自增表主键值
}
else if (this._schema.KEYS[k] == 'integer') {
xassert(this._check_type(row[k]), ERR$PARAM, { k: k, row: row, params: params });
params.primaryKey.push((_b = {}, _b[k] = int64(row[k]), _b));
}
else {
xassert(this._check_type(row[k]), ERR$PARAM, { k: k, row: row, params: params });
params.primaryKey.push((_c = {}, _c[k] = row[k], _c));
}
}
// 按照schema定义进行属性赋值
for (var k in this._schema.COLUMNS) {
if (!(k in row)) {
continue;
}
if (this._schema.COLUMNS[k] == 'integer') {
xassert(this._check_type(row[k]), ERR$PARAM, { k: k, row: row, params: params });
params.attributeColumns.push((_d = {}, _d[k] = int64(row[k]), _d));
}
else {
xassert(this._check_type(row[k]), ERR$PARAM, { k: k, row: row, params: params });
params.attributeColumns.push((_e = {}, _e[k] = row[k], _e));
}
}
// TODO 对于所有主键和属性的数据类型转换处理防止属性赋值错误进行检查判断
};
// 约定所有表都需要有自增主键id作为内部唯一标识码,其余三个主键必须全部为字符串。(后端需要扩展int和date基本数据类型以及操作符重载实现优化开发)
// 属性字段可以根据业务演变任意的扩展增加由业务代码对于老数据不存在新增字段值的情况做兼容处理
NosqlAliyunTablestore.prototype.insert = function (row) {
return __awaiter(this, void 0, void 0, function () {
var _a, __this__, params;
return __generator(this, function (_b) {
if (!row)
row = {};
row = Object.assign((_a = {}, _a[inerface_1.ZONE_KEY_NAME] = '', _a), row);
xassert(_.isPlainObject(row), ERR$PARAM, { row: row });
// 没有指定分区间为其自动随机补上一个分区键值进行散列算法实现
// if (!(ZONE_KEY_NAME in row)) {
// // const shortid = require('shortid')
// // row[ZONE_KEY_NAME] = shortid.generate()
// // 改用uuid1的时间连续性的唯一值进行有序排列数据方便应用遍历查找
// // row[ZONE_KEY_NAME] = uuidv1().replace(/\-/g, '') // 添加ZONE分区键(按照时间顺序uuid排列)
// row[ZONE_KEY_NAME] = '' // FIXME 暂时完全忽略掉存在问题
// }
delete row[inerface_1.AUTO_KEY_NAME]; // 删除可能的不需要输入的id值避免潜在插入错误
// 自动补上updated_at和created_at两个缺省字段值的自动设置
row['created_at'] = row['updated_at'] = moment().format('YYYY-MM-DD HH:mm:ss');
__this__ = this;
params = {
tableName: this._table,
condition: new TableStore.Condition(TableStore.RowExistenceExpectation.IGNORE, null),
primaryKey: [],
attributeColumns: [],
// 按照下面数据格式进行schema定义的验证以及数据类型转换
// primaryKey: [{'gid': Long.fromNumber(20013)}, {'uid': Long.fromNumber(20013)}],
// attributeColumns: [
// {'col1': '表格存储'},
// {'col2': '2', 'timestamp': currentTimeStamp}, // 允许修改时间戳乐观锁功能实现暂不支持
// {'col3': 3.1},
// {'col4': -0.32},
// {'col5': Long.fromNumber(123456789)}
// ],
// primaryKey: [
// {'short_id': 'pk1'},
// {[AUTO_KEY_NAME]: TableStore.PK_AUTO_INCR}
// ],
// attributeColumns: [
// {'appcode': 'app1'}
// ],
returnContent: { returnType: TableStore.ReturnType.Primarykey }
};
this._check_schema(row, params, true);
return [2 /*return*/, new Promise(function (resolve, reject) {
try {
__this__._client.putRow(params, function (err, data) {
if (err) {
xthrow(new Error(err), reject, { params: params, data: data });
return;
}
//{"consumed":{"capacity_unit":{"read":0,"write":1}},"row":{
// "primaryKey":[{"name":"short_id","value":"abcd"},{"name":"id","value":1520765502347000}],
// "attributes":[]},
// "RequestId":"00056720-cf8d-d4a8-8ae8-970a17894ce6"}
// 插入后返回主键列表新增的自增字段值给应用做应用关联
xassert(data.row && data.row.primaryKey && _.isArray(data.row.primaryKey), ERR$PARAM, { data: data, table: __this__._table });
var out = Object.assign({}, row);
for (var k in data.row.primaryKey) {
var value = data.row.primaryKey[k].value;
// int64转换回到number的javascript类型处理
if (typeof value == 'object') {
out[data.row.primaryKey[k].name] = value.toNumber();
}
else {
out[data.row.primaryKey[k].name] = value;
}
}
resolve(out);
});
}
catch (err) {
xthrow(err, reject);
}
})];
});
});
};
// 条件更新必须要填写主键记录值(仅仅允许更新属性字段而主键字段是不允许更新的,
// 整列更新和删除列属于运维操作禁止应用中使用需要单独接口以及权限认证)
NosqlAliyunTablestore.prototype.update = function (row, condition) {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _c, _d, __this__, params, k, k, size1, size2, k, and, k;
return __generator(this, function (_e) {
xassert(row && condition && _.isPlainObject(row) && _.isPlainObject(condition));
row = xassign({}, row);
condition = xassign((_a = {}, _a[inerface_1.ZONE_KEY_NAME] = '', _a), condition);
// 检查主键条件严格保证匹配,当主键不完整的时候需要通过id主键查找原始值补全缺少的主键值(FIXME OTS的缺陷规避掉)
// xassert('id' in condition, ERR$PARAM, {row, condition})
// let tmp = await this.query({id: condition.id}) // 检查id的有效性
// xassert(tmp, ERR$EMPTY, {row, condition, tmp})
// condition = xassign({}, condition)
// for (let k in this._schema.KEYS) {
// condition[k] = tmp[k] // 补全完整的字段
// }
// 更新缺省自定义的属性字段
row['updated_at'] = moment().format('YYYY-MM-DD HH:mm:ss');
__this__ = this;
params = {
tableName: this._table,
condition: null,
// condition: new TableStore.Condition(TableStore.RowExistenceExpectation.EXPECT_EXIST
// , new TableStore.SingleColumnCondition("col1", 'test5', TableStore.ComparatorType.EQUAL)),
// primaryKey: [{'gid': Long.fromNumber(20013)}, {'uid': Long.fromNumber(20013)}],
primaryKey: [],
// updateOfAttributeColumns: [{'PUT': [{'col1': 'test6'}]}]
updateOfAttributeColumns: [{ 'PUT': [] }]
};
// 先处理更新字段的赋值处理
for (k in row) {
xassert(k in this._schema.COLUMNS && this._check_type(row[k]), ERR$PARAM, { k: k, row: row, schema: this._schema });
params.updateOfAttributeColumns[0]['PUT'].push((_b = {}, _b[k] = row[k], _b));
}
// 再处理主键查询条件(所有主键字段必须要设置)
for (k in this._schema.KEYS) {
xassert(k in condition && this._check_type(condition[k]), ERR$PARAM, { k: k, condition: condition });
if (this._schema.KEYS[k] == 'integer') {
params.primaryKey.push((_c = {}, _c[k] = int64(condition[k]), _c));
}
else {
params.primaryKey.push((_d = {}, _d[k] = condition[k], _d));
}
}
size1 = _.keys(condition).length;
size2 = _.keys(this._schema.KEYS).length;
if (size1 == size2) {
// 只有属性字段等价于无条件更新属性
params.condition = new TableStore.Condition(TableStore.RowExistenceExpectation.IGNORE, null);
}
else if (size1 == size2 + 1) {
// 只有一个属性字段查询条件
for (k in condition) {
if (k in this._schema.KEYS) {
continue;
}
xassert(!params.condition, ERR$PARAM, { condition: condition, KEYS: this._schema.KEYS });
if (this._schema.KEYS[k] == 'integer') {
params.condition = new TableStore.Condition(TableStore.RowExistenceExpectation.EXPECT_EXIST, new TableStore.SingleColumnCondition(k, int64(condition[k]), TableStore.ComparatorType.EQUAL));
}
else {
params.condition = new TableStore.Condition(TableStore.RowExistenceExpectation.EXPECT_EXIST, new TableStore.SingleColumnCondition(k, condition[k], TableStore.ComparatorType.EQUAL));
}
}
}
else {
and = new TableStore.CompositeCondition(TableStore.LogicalOperator.AND);
for (k in condition) {
if (k in this._schema.KEYS) {
continue;
}
if (this._schema.KEYS[k] == 'integer') {
and.addSubCondition(k, int64(condition[k]), TableStore.ComparatorType.EQUAL);
}
else {
and.addSubCondition(k, condition[k], TableStore.ComparatorType.EQUAL);
}
}
params.condition = new TableStore.Condition(TableStore.RowExistenceExpectation.EXPECT_EXIST, and);
}
return [2 /*return*/, new Promise(function (resolve, reject) {
try {
__this__._client.updateRow(params, function (err, data) {
if (err) {
xthrow(new Error(err), reject, { params: params, data: data });
return;
}
resolve();
});
}
catch (err) {
xthrow(err, reject);
}
})];
});
});
};
// 以主键作为条件删除记录值
NosqlAliyunTablestore.prototype.delete = function (row) {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, __this__, params, k;
return __generator(this, function (_c) {
__this__ = this;
params = {
tableName: this._table,
condition: new TableStore.Condition(TableStore.RowExistenceExpectation.IGNORE, null),
// primaryKey: [{ 'gid': Long.fromNumber(8) }, { 'uid': Long.fromNumber(80) }]
primaryKey: []
};
// 至少一个主键
xassert(_.keys(this._schema.KEYS).length > 0, ERR$PARAM, { schema: this._schema });
for (k in this._schema.KEYS) {
// 所有的主键条件必须都要存在
xassert(k in row, ERR$PARAM, { k: k, row: row, params: params });
if (this._schema.KEYS[k] == 'integer') {
params.primaryKey.push((_a = {}, _a[k] = int64(row[k]), _a));
}
else {
params.primaryKey.push((_b = {}, _b[k] = row[k], _b));
}
}
return [2 /*return*/, new Promise(function (resolve, reject) {
try {
__this__._client.deleteRow(params, function (err, data) {
if (err) {
xthrow(new Error(err), reject, { params: params, data: data });
return;
}
resolve();
});
}
catch (err) {
xthrow(err, reject);
}
})];
});
});
};
// 分页查询一次检索N条记录(
// 分布式系统的特点不适合批量查询多条记录,如有这种需求需要mongodb或mysql完成,
// tablestore更加适合分布式session存储这种数据特点的应用,
// 大数据检索需要借助opensearch直通表同步完成实现无运维NOSQL完整方案,
// 只有需要事务特性关键应用才需要mysql不过这部分基本上不是nodejs的工作范围而需要下层到java服务层去实现更合适。
// )
// private async _query_by_opensearch(row: ROW) {
// // TODO ... (需要通过schema配置在创建表的时候自动进行opensearch关联表创建,在insert和update数据的时候自动同步opensearch数据)
// }
NosqlAliyunTablestore.prototype._query_by_range = function (range, limit, is_asc_or_desc) {
if (limit === void 0) { limit = 10; }
if (is_asc_or_desc === void 0) { is_asc_or_desc = true; }
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, k, __this__, params, k;
return __generator(this, function (_s) {
if (!range) {
range = {};
}
xassert(_.isPlainObject(range) && _.isInteger(limit) && limit >= 1 && _.isBoolean(is_asc_or_desc), ERR$PARAM, { range: range });
// 验证查询范围数据合法性(所有字段必须要是主键)
xassert(_.keys(range).length <= _.keys(this._schema.KEYS).length, ERR$PARAM, { range: range });
for (k in this._schema.KEYS) {
if (!(k in range)) {
continue;
}
if (_.isArray(range[k])) {
xassert(range[k].length == 2, ERR$PARAM, { k: k, range: range });
xassert(this._check_type(range[k][0]) && this._check_type(range[k][1]), ERR$PARAM, { k: k, range: range });
}
else {
xassert(this._check_type(range[k]), ERR$PARAM, { k: k, range: range });
}
}
__this__ = this;
params = {
tableName: this._table,
direction: is_asc_or_desc ? TableStore.Direction.FORWARD : TableStore.Direction.BACKWARD,
// inclusiveStartPrimaryKey: [{"gid": TableStore.INF_MIN}, {"uid": TableStore.INF_MIN}],
// exclusiveEndPrimaryKey: [{"gid": TableStore.INF_MAX}, {"uid": TableStore.INF_MAX}],
inclusiveStartPrimaryKey: [],
exclusiveEndPrimaryKey: [],
limit: limit
};
// 根据主键的查询条件进行查询范围的设置(按照schema定义字段进行排序处理)
for (k in this._schema.KEYS) {
if (!(k in range)) {
// FIXME 规避OTS的设计缺陷必须要补上分区键并且确保左闭右开的查询数据结构,否则就是全表查询。
if (k == inerface_1.ZONE_KEY_NAME) {
if (is_asc_or_desc) {
params.inclusiveStartPrimaryKey.push((_a = {}, _a[k] = '', _a));
params.exclusiveEndPrimaryKey.push((_b = {}, _b[k] = '!', _b));
}
else {
params.inclusiveStartPrimaryKey.push((_c = {}, _c[k] = '!', _c));
params.exclusiveEndPrimaryKey.push((_d = {}, _d[k] = '', _d));
}
continue;
}
// 不填的主键参数按照最小和最大范围自动补上查询条件(有问题会查询出所有的满足条件的数据)
if (is_asc_or_desc) {
// 升序逻辑处理
params.inclusiveStartPrimaryKey.push((_e = {}, _e[k] = TableStore.INF_MIN, _e));
params.exclusiveEndPrimaryKey.push((_f = {}, _f[k] = TableStore.INF_MAX, _f));
}
else {
// 降序逻辑处理
params.inclusiveStartPrimaryKey.push((_g = {}, _g[k] = TableStore.INF_MAX, _g));
params.exclusiveEndPrimaryKey.push((_h = {}, _h[k] = TableStore.INF_MIN, _h));
}
}
else if (_.isArray(range[k])) {
// 用户指定范围进行查询
if (this._schema.KEYS[k] == 'integer') {
params.inclusiveStartPrimaryKey.push((_j = {}, _j[k] = int64(range[k][0]), _j));
params.exclusiveEndPrimaryKey.push((_k = {}, _k[k] = int64(range[k][1]), _k));
}
else {
params.inclusiveStartPrimaryKey.push((_l = {}, _l[k] = range[k][0], _l));
params.exclusiveEndPrimaryKey.push((_m = {}, _m[k] = range[k][1], _m));
}
}
else {
// 等值确定条件查询
if (this._schema.KEYS[k] == 'integer') {
params.inclusiveStartPrimaryKey.push((_o = {}, _o[k] = int64(range[k]), _o));
params.exclusiveEndPrimaryKey.push((_p = {}, _p[k] = int64(range[k]), _p));
}
else {
params.inclusiveStartPrimaryKey.push((_q = {}, _q[k] = range[k], _q));
params.exclusiveEndPrimaryKey.push((_r = {}, _r[k] = range[k], _r));
}
}
}
return [2 /*return*/, new Promise(function (resolve, reject) {
var resultRows = []; // 递归嵌套查询的最终查询完成的数据集合(等查询结束后再进行统一处理)
var getRange = function () {
__this__._client.getRange(params, function (err, data) {
if (err) {
xthrow(new Error(err), reject, { params: params, data: data });
return;
}
resultRows = resultRows.concat(data.rows);
//如果data.next_start_primary_key不为空,说明需要继续读取
// if (data.next_start_primary_key) {
if (false) {
// // params.inclusiveStartPrimaryKey = [
// // {"gid": data.next_start_primary_key[0].value},
// // {"uid": data.next_start_primary_key[1].value}
// // ]
// params.inclusiveStartPrimaryKey = []
// let i = 0
// for (let k in __this__._schema.KEYS) {
// if (__this__._schema.KEYS[k] == 'integer') {
// params.inclusiveStartPrimaryKey.push({[k]: int64(data.next_start_primary_key[i].value.toNumber())})
// } else {
// params.inclusiveStartPrimaryKey.push({[k]: data.next_start_primary_key[i].value})
// }
// i += 1
// }
// getRange() // 分页数过大接口自动完成多次嵌套递归查询形成应用逻辑上的一个分页单次查询结果输出
}
else {
// 统一的数据类型转换最终的数据结果处理
// [ { primaryKey: [ [Object], [Object] ], attributes: [ [Object] ] },
// { primaryKey: [ [Object], [Object] ], attributes: [ [Object] ] },
// { primaryKey: [ [Object], [Object] ], attributes: [ [Object] ] },
// { primaryKey: [ [Object], [Object] ], attributes: [ [Object] ] } ]
// xlog(JSON.stringify(resultRows))
var out = [];
for (var k in resultRows) {
var obj = {};
if (resultRows[k].primaryKey) {
for (var j in resultRows[k].primaryKey) {
var value = resultRows[k].primaryKey[j].value;
// int64转换回到number的javascript类型处理
if (typeof value == 'object') {
obj[resultRows[k].primaryKey[j].name] = value.toNumber();
}
else {
obj[resultRows[k].primaryKey[j].name] = value;
}
}
}
if (resultRows[k].attributes) {
for (var j in resultRows[k].attributes) {
var value = resultRows[k].attributes[j].columnValue;
if (typeof value == 'object') {
obj[resultRows[k].attributes[j].columnName] = value.toNumber();
}
else {
obj[resultRows[k].attributes[j].columnName] = value;
}
}
}
out.push(obj);
}
if (out.length == 0)
out = undefined;
return resolve(out);
}
});
};
getRange();
})];
});
});
};
NosqlAliyunTablestore.prototype._query_by_key = function (row) {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _c, __this__, params, k, condition, sub_condition_count, k, k, i;
return __generator(this, function (_d) {
row = xassign((_a = {}, _a[inerface_1.ZONE_KEY_NAME] = '', _a), row); // 补上ZONE缺省值
__this__ = this;
params = {
tableName: this._table,
primaryKey: [],
// primaryKey: [{'gid': Long.fromNumber(20013)}, {'uid': Long.fromNumber(20013)}],
columnFilter: null,
};
// 补上主键值equal查询(注意事项:OTS接口必须要所有key都存在才允许查询,而且每个表必须要至少一个主键,
// 此处的主键与数据库中的主键并非同一个含义而是分布式系统数据散列的一个分区条件字段而已并非一定需要保持唯一。)
xassert(_.keys(this._schema.KEYS).length >= 1, ERR$PARAM, { row: row, KEYS: this._schema.KEYS });
for (k in this._schema.KEYS) {
// 检查输入条件中所有的主键字段是否完整
xassert(k in row && this._check_type(row[k]), ERR$PARAM, { k: k, row: row, params: params });
if (this._schema.KEYS[k] == 'integer') {
params.primaryKey.push((_b = {}, _b[k] = int64(row[k]), _b));
}
else {
params.primaryKey.push((_c = {}, _c[k] = row[k], _c));
}
}
condition = new TableStore.CompositeCondition(TableStore.LogicalOperator.AND);
sub_condition_count = 0;
for (k in this._schema.COLUMNS) {
if (!(k in row)) {
continue;
}
xassert(this._check_type(row[k]), ERR$PARAM, { k: k, row: row, params: params });
if (this._schema.COLUMNS[k] == 'integer') {
condition.addSubCondition(new TableStore.SingleColumnCondition(k, int64(row[k]), TableStore.ComparatorType.EQUAL));
}
else {
condition.addSubCondition(new TableStore.SingleColumnCondition(k, row[k], TableStore.ComparatorType.EQUAL));
}
}
if (sub_condition_count < 2) {
// 检查主键查询条件至少要有一个
xassert(params.primaryKey.length >= 1, ERR$PARAM, { row: row, params: params });
k = _.keys(this._schema.KEYS)[0];
for (i = 0; i + sub_condition_count < 2; i++) {
if (this._schema.KEYS[k] == 'integer') {
condition.addSubCondition(new TableStore.SingleColumnCondition(k, int64(row[k]), TableStore.ComparatorType.EQUAL));
}
else {
condition.addSubCondition(new TableStore.SingleColumnCondition(k, row[k], TableStore.ComparatorType.EQUAL));
}
}
}
params.columnFilter = condition;
return [2 /*return*/, new Promise(function (resolve, reject) {
__this__._client.getRow(params, function (err, data) {
if (err) {
xthrow(new Error(err), reject, { params: params, data: data });
return;
}
// 返回数据格式类型进行转换处理
// {"consumed":{"capacity_unit":{"read":1,"write":0}},
// "row":{"primaryKey":[{"name":"gid","value":20013},{"name":"uid","value":20013}],
// "attributes":[{"columnName":"col1","columnValue":"表格存储","timestamp":1520734520286},
// {"columnName":"col2","columnValue":"2","timestamp":1520734520064},
// {"columnName":"col3","columnValue":3.1,"timestamp":1520734520286},
// {"columnName":"col4","columnValue":-0.32,"timestamp":1520734520286},
// {"columnName":"col5","columnValue":123456789,"timestamp":1520734520286}]
// },
// "next_token":null,"RequestId":"00056719-e2ad-73b1-dbd8-970a19522f4b"}
// 将数据结果进行转换处理合并为一个普通对象给应用使用
try {
var out = {};
if (!data.row) {
return resolve(undefined);
}
if (data.row.primaryKey) {
for (var k in data.row.primaryKey) {
var value = data.row.primaryKey[k].value;
// int64转换回到number的javascript类型处理
if (typeof value == 'object') {
out[data.row.primaryKey[k].name] = value.toNumber();
}
else {
out[data.row.primaryKey[k].name] = value;
}
}
}
if (data.row.attributes) {
for (var k in data.row.attributes) {
var value = data.row.attributes[k].columnValue;
if (typeof value == 'object') {
out[data.row.attributes[k].columnName] = value.toNumber();
}
else {
out[data.row.attributes[k].columnName] = value;
}
}
}
if (_.keys(out).length == 0)
out = undefined;
resolve(out);
}
catch (err) {
xthrow(new Error(err), reject, { params: params, data: data });
return;
}
});
})];
});
});
};
// 范围查询需要数据自动同步到opensearch进行索引同步后进行各种复杂的查询操作实现免运维系统的实现
// 单表逻辑条件的简单and与equal的查询,返回满足条件的第一条记录 (合并为一个查询兼容mongodb的查询扩展)
NosqlAliyunTablestore.prototype.query = function (row, limit, is_asc_or_desc) {
if (limit === void 0) { limit = 1; }
if (is_asc_or_desc === void 0) { is_asc_or_desc = true; }
return __awaiter(this, void 0, void 0, function () {
var size, is_asc;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!_.isInteger(row)) return [3 /*break*/, 2];
size = row;
is_asc = is_asc_or_desc;
if (_.isBoolean(limit)) {
is_asc = limit;
}
return [4 /*yield*/, this._query_by_range(undefined, size, is_asc)]; // 一个条件都不输入进行全表遍历查询
case 1: return [2 /*return*/, _a.sent()]; // 一个条件都不输入进行全表遍历查询
case 2:
// 至少输入一个查询条件的情况处理
xassert(_.isInteger(limit), ERR$PARAM, { row: row, limit: limit, is_asc_or_desc: is_asc_or_desc });
if (!(limit == 1)) return [3 /*break*/, 4];
return [4 /*yield*/, this._query_by_key(row)
// // FIXME 规避OTS的设计缺陷只有ZONE和ID两个主键的时候才可以按KEY查找单条数据
// if (_.keys(this._schema.KEYS).length == 2 && AUTO_KEY_NAME in this._schema.KEYS) {
// row = {
// [ZONE_KEY_NAME]: row[ZONE_KEY_NAME] ? row[ZONE_KEY_NAME] : '',
// [AUTO_KEY_NAME]: row[AUTO_KEY_NAME],
// }
// return await this._query_by_key(row as ROW)
// }
// // FIXME 规避OTS的设计缺陷解决通过range查询替代主键查询
// let out = await this._query_by_range(row as RANGE, limit as number, is_asc_or_desc)
// if (!out) return undefined
// return out[0]
];
case 3: return [2 /*return*/, _a.sent()
// // FIXME 规避OTS的设计缺陷只有ZONE和ID两个主键的时候才可以按KEY查找单条数据
// if (_.keys(this._schema.KEYS).length == 2 && AUTO_KEY_NAME in this._schema.KEYS) {
// row = {
// [ZONE_KEY_NAME]: row[ZONE_KEY_NAME] ? row[ZONE_KEY_NAME] : '',
// [AUTO_KEY_NAME]: row[AUTO_KEY_NAME],
// }
// return await this._query_by_key(row as ROW)
// }
// // FIXME 规避OTS的设计缺陷解决通过range查询替代主键查询
// let out = await this._query_by_range(row as RANGE, limit as number, is_asc_or_desc)
// if (!out) return undefined
// return out[0]
];
case 4: return [4 /*yield*/, this._query_by_range(row, limit, is_asc_or_desc)];
case 5: return [2 /*return*/, _a.sent()];
}
});
});
};
// 销毁表
NosqlAliyunTablestore.prototype.destroy = function () {
return __awaiter(this, void 0, void 0, function () {
var __this__, params;
return __generator(this, function (_a) {
__this__ = this;
params = {
tableName: this._table
};
return [2 /*return*/, new Promise(function (resolve, reject) {
__this__._client.deleteTable(params, function (err, data) {
if (err) {
xthrow(new Error(err), reject, { params: params });
return;
}
resolve();
});
})];
});
});
};
// 创建表
NosqlAliyunTablestore.prototype.create = function () {
return __awaiter(this, void 0, void 0, function () {
var __this__, params, k, obj;
return __generator(this, function (_a) {
__this__ = this;
params = {
tableMeta: {
tableName: this._table,
primaryKey: [],
},
reservedThroughput: {
capacityUnit: {
read: 0,
write: 0
}
},
tableOptions: {
timeToLive: -1,
maxVersions: 1 // 保存的最大版本数, 设置为1即代表每列上最多保存一个版本(保存最新的版本).
}
};
// 自动转换schema定义为OTS的数据结构
for (k in this._schema.KEYS) {
obj = {
name: k,
type: _.upperCase(this._schema.KEYS[k])
};
if (k == inerface_1.AUTO_KEY_NAME) {
obj['option'] = 'AUTO_INCREMENT';
}
params.tableMeta.primaryKey.push(obj);
}
// bugfix解决第一个分区键不能为主键的问题默认补上一个_id字段值的问题(只做提示暂不解决约定一个_id分区键强制设置)
// "400: \n\u0013OTSParameterInvalid\u0012*first primary key can't be AUTO_INCREMENT."
return [2 /*return*/, new Promise(function (resolve, reject) {
__this__._client.createTable(params, function (err, data) {
if (err) {
xthrow(new Error(err), reject, { params: params, data: data });
return;
}
resolve();
});
})];
});
});
};
// 重置表
NosqlAliyunTablestore.prototype.reset = function () {
return __awaiter(this, void 0, void 0, function () {
var err_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
return [4 /*yield*/, this.destroy()];
case 1:
_a.sent();
return [3 /*break*/, 3];
case 2:
err_1 = _a.sent();
return [3 /*break*/, 3];
case 3: return [4 /*yield*/, this.create()];
case 4:
_a.sent();
return [2 /*return*/];
}
});
});
};
return NosqlAliyunTablestore;
}(inerface_1.NosqlInterface));
exports.NosqlAliyunTablestore = NosqlAliyunTablestore;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9zcWwtYWxpeXVuLXRhYmxlc3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJub3NxbC1hbGl5dW4tdGFibGVzdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxJQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUE7QUFDeEMsSUFBTSxJQUFJLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQTtBQUM1QixJQUFNLENBQUMsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUE7QUFDM0IsSUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBQ2hDLElBQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQTtBQUVqQyxzQkFBc0I7QUFDdEIsZUFBZSxDQUFrQjtJQUM3QixJQUFJLE9BQU8sQ0FBQyxJQUFJLFFBQVEsRUFBRTtRQUN0QixPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUE7S0FDNUI7U0FBTSxJQUFJLE9BQU8sQ0FBQyxJQUFJLFFBQVEsRUFBRTtRQUM3QixPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUE7S0FDNUI7U0FBTTtRQUNILE1BQU0sQ0FBQyxTQUFTLEVBQUUsRUFBQyxDQUFDLEdBQUEsRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLEVBQUMsQ0FBQyxDQUFBO0tBQ3pDO0FBQ0wsQ0FBQztBQUVELHVDQUFtRjtBQUVuRjtJQUEyQyx5Q0FBYztJQUtyRCwrQkFBWSxLQUFhLEVBQUUsTUFBMEI7UUFBMUIsdUJBQUEsRUFBQSxrQkFBMEI7UUFBckQsWUFDSSxrQkFBTSxLQUFLLEVBQUUsTUFBTSxDQUFDLFNBMkN2QjtRQTFDRyxJQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUE7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T0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztxQkFDMUMsQ0FBQTtvQkFDRCxJQUFJLENBQUMsSUFBSSx3QkFBYSxFQUFFO3dCQUNwQixHQUFHLENBQUMsUUFBUSxDQUFDLEdBQUcsZ0JBQWdCLENBQUE7cUJBQ25DO29CQUNELE1BQU0sQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtpQkFDeEM7Z0JBQ0QsZ0VBQWdFO2dCQUNoRSxzRkFBc0Y7Z0JBRXRGLHNCQUFPLElBQUksT0FBTyxDQUFDLFVBQUMsT0FBTyxFQUFFLE1BQU07d0JBQy9CLFFBQVEsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLE1BQU0sRUFBRSxVQUFVLEdBQUcsRUFBRSxJQUFJOzRCQUNwRCxJQUFJLEdBQUcsRUFBRTtnQ0FDTCxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUMsTUFBTSxRQUFBLEVBQUUsSUFBSSxNQUFBLEVBQUMsQ0FBQyxDQUFBO2dDQUM5QyxPQUFNOzZCQUNUOzRCQUNELE9BQU8sRUFBRSxDQUFBO3dCQUNiLENBQUMsQ0FBQyxDQUFBO29CQUNOLENBQUMsQ0FBQyxFQUFBOzs7S0FDTDtJQUVELE1BQU07SUFDTyxxQ0FBSyxHQUFsQjs7Ozs7Ozt3QkFFUSxxQkFBTSxJQUFJLENBQUMsT0FBTyxFQUFFLEVBQUE7O3dCQUFwQixTQUFvQixDQUFBOzs7Ozs0QkFJeEIscUJBQU0sSUFBSSxDQUFDLE1BQU0sRUFBRSxFQUFBOzt3QkFBbkIsU0FBbUIsQ0FBQTs7Ozs7S0FDdEI7SUFDTCw0QkFBQztBQUFELENBQUMsQUF4cUJELENBQTJDLHlCQUFjLEdBd3FCeEQ7QUF4cUJZLHNEQUFxQiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICog5a+55LqO6Zi/6YeM5LqRT1RT6KGo5qC85a2Y5YKo55qE5Lia5Yqh5bCB6KOFXG4gKlxuICogTk9TUUznmoTlupTnlKjkvb/nlKjnuqblrppcbiAqIE9UU+Wbm+S4qktFWVPlrZfmrrUy5Liq5Y2g55So77yMMuS4quW6lOeUqOiHquW3seaJqeWxleS9v+eUqO+8jE9UU+mZkOWItuacgOWkmuWumuS5iTTkuKrkuLvplK7vvIzlubbkuJTnrKzkuIDkuKrkuLvplK56b25l5Li65YiG5Yy65Li76ZSu44CCXG4gKiBLRVlT77yaXG4gKiAgem9uZSAo5aaC5p6c5ZyoaW5zZXJ055qE5pe25YCZ5LiN5aGr5YaZ77yM5oyJ54WndXVpZOaXtumXtOmhuuW6j+eUn+aIkOWIhuWMuumUruehruS/neS4u+mUrueahOWUr+S4gOmhuuW6j+aApylcbiAqICBb5Y+v5omp5bGV5Lia5Yqh6Ieq5a6a5LmJ55qE5Lik5Liq5Li76ZSuXVxuICogIGlkXG4gKiBDT0xVTU5T77yaXG4gKiAgLy8g6aKE5a6a5LmJ5aaC5LiL5Lik5Liq5a2X5q6155So5LqO6Lef6Liq6K6w5b2V55qE5Yib5bu65pe26Ze05ZKM5L+u5pS55pe26Ze077yI5LiN5pSv5oyBaXNfZGVsZXRlZOWBh+WIoOmZpOagh+iusE9UU+eahOS4muWKoeeJueeCueS4jemAguWQiOS9v+eUqO+8iVxuICogIGNyZWF0ZWRfYXRcbiAqICB1cGRhdGVkX2F0XG4gKi9cbmNvbnN0IFRhYmxlU3RvcmUgPSByZXF1aXJlKCd0YWJsZXN0b3JlJylcbmNvbnN0IExvbmcgPSBUYWJsZVN0b3JlLkxvbmdcbmNvbnN0IF8gPSByZXF1aXJlKCdsb2Rhc2gnKVxuY29uc3QgbW9tZW50ID0gcmVxdWlyZSgnbW9tZW50JylcbmNvbnN0IHV1aWR2MSA9IHJlcXVpcmUoJ3V1aWQvdjEnKVxuXG4vLyBJTlQ2NOWfuuacrOaVsOaNruexu+Wei+eahOihqOagvOWtmOWCqOeahOaJqeWxlVxuZnVuY3Rpb24gaW50NjQodjogc3RyaW5nIHwgbnVtYmVyKSB7XG4gICAgaWYgKHR5cGVvZiB2ID09ICdzdHJpbmcnKSB7XG4gICAgICAgIHJldHVybiBMb25nLmZyb21TdHJpbmcodilcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiB2ID09ICdudW1iZXInKSB7XG4gICAgICAgIHJldHVybiBMb25nLmZyb21OdW1iZXIodilcbiAgICB9IGVsc2Uge1xuICAgICAgICB4dGhyb3coRVJSJFBBUkFNLCB7diwgdHlwZTogdHlwZW9mIHZ9KVxuICAgIH1cbn1cblxuaW1wb3J0IHtOb3NxbEludGVyZmFjZSwgUk9XLCBSQU5HRSwgQVVUT19LRVlfTkFNRSwgWk9ORV9LRVlfTkFNRX0gZnJvbSAnLi9pbmVyZmFjZSdcblxuZXhwb3J0IGNsYXNzIE5vc3FsQWxpeXVuVGFibGVzdG9yZSBleHRlbmRzIE5vc3FsSW50ZXJmYWNlIHtcbiAgICBwcml2YXRlIF90YWJsZTogc3RyaW5nXG4gICAgcHJpdmF0ZSBfY2xpZW50OiBhbnlcbiAgICBwcml2YXRlIF9zY2hlbWE6IGFueVxuXG4gICAgY29uc3RydWN0b3IodGFibGU6IHN0cmluZywgY29uZmlnOiBzdHJpbmcgPSAnZGVmYXVsdCcpIHtcbiAgICAgICAgc3VwZXIodGFibGUsIGNvbmZpZylcbiAgICAgICAgY29uc3QgaW5zdGFuY2VzID0geGNvbmZpZygncGx1Z2lucy5ub3NxbCcpXG4gICAgICAgIHhhc3NlcnQoaW5zdGFuY2VzICYmIF8uaXNQbGFpbk9iamVjdChpbnN0YW5jZXMpICYmIGNvbmZpZyBpbiBpbnN0YW5jZXMsXG4gICAgICAgICAgICBFUlIkQ09ORklHLCB7aW5zdGFuY2VzfSlcbiAgICAgICAgdGhpcy5fdGFibGUgPSB0YWJsZVxuICAgICAgICB0aGlzLl9zY2hlbWEgPSBPYmplY3QuYXNzaWduKHt9LCBpbnN0YW5jZXNbY29uZmlnXS5PVFNfVEFCTEVTW3RhYmxlXSlcblxuICAgICAgICAvLyBCVUdGSVgg6Kej5YazdGFibGVzdG9yZeeJueauiueahOiuvuiuoei/m+ihjOWMheijhemAmui/h+e6puWumuWvueW6lOeUqOi/m+ihjOmAj+aYjuWunueOsOOAglxuICAgICAgICAvLyDpu5jorqTlop7liqDnrKzkuIDkuKp6b25l5YiG5Yy66ZSu5Y2g55So6K6+572u77yI5o+S5YWl5pWw5o2u5rKh5pyJ6LWL5YC85Lya6Ieq5Yqo6KGl5LiK5pWj5YiX566X5rOV6Ieq5Yqo6L+b6KGM566X5rOV5a6e546w77yJ77yMXG4gICAgICAgIC8vIOWmguaenOayoeacieWumuS5ieS4u+mUruiHquWKqOihpeS4iuS4gOS4qmlk6Ieq5aKe5Li76ZSu5YW85a655Lia5Yqh5bqU55So77yI5LuF5LuF5Li6S0VZU+S4uuepuueahOaXtuWAmeiHquWKqOihpeS4iuaUueWAvO+8ieOAglxuICAgICAgICBpZiAoXy5pc0VtcHR5KHRoaXMuX3NjaGVtYS5LRVlTKSkgdGhpcy5fc2NoZW1hLktFWVMgPSB7fVxuICAgICAgICBpZiAoXy5pc0VtcHR5KHRoaXMuX3NjaGVtYS5DT0xVTU5TKSkgdGhpcy5fc2NoZW1hLkNPTFVNTlMgPSB7fVxuICAgICAgICAvLyB6b25l5ZKMaWTkuLrnuqblrprkuLvplK7npoHmraLlupTnlKjlsIblhbbkvb/nlKjliLDkuLvplK7miJblsZ7mgKfliJflrprkuYnkuK1cbiAgICAgICAgeGFzc2VydCghKFpPTkVfS0VZX05BTUUgaW4gdGhpcy5fc2NoZW1hLktFWVMpICYmICEoQVVUT19LRVlfTkFNRSBpbiB0aGlzLl9zY2hlbWEuS0VZUyksXG4gICAgICAgICAgICBFUlIkQ09ORklHLCB7c2NoZW1hOiB0aGlzLl9zY2hlbWF9KVxuICAgICAgICB4YXNzZXJ0KCEoWk9ORV9LRVlfTkFNRSBpbiB0aGlzLl9zY2hlbWEuQ09MVU1OUykgJiYgIShBVVRPX0tFWV9OQU1FIGluIHRoaXMuX3NjaGVtYS5DT0xVTU5TKSxcbiAgICAgICAgICAgIEVSUiRDT05GSUcsIHtzY2hlbWE6IHRoaXMuX3NjaGVtYX0pXG4gICAgICAgIC8vIOajgOafpeS4u+mUruaVsOmHj+acgOWkmueUqOaIt+WPr+S7peiHquWumuS5ieS9v+eUqDLkuKooaWToh6rlop7kuLvplK7mlL7lnKjmnIDlkI7vvIx6b25l5YiG5Yy66ZSu5pS+5Zyo5pyA5YmN6Z2iKVxuICAgICAgICB4YXNzZXJ0KF8ua2V5cyh0aGlzLl9zY2hlbWEuS0VZUykubGVuZ3RoIDw9IDIsIEVSUiRDT05GSUcsIHtzY2hlbWE6IHRoaXMuX3NjaGVtYX0pXG5cbiAgICAgICAgLy8gem9uZeS4uue6puWumuWIhuWMuumUruaXoOmcgOWcqHNjaGVtYeS4reWumuS5ieaYr3N0cmluZ+exu+Wei+S8muiHquWKqOihpeS4iuWvueW6lOeahOS4u+mUruWumuS5ie+8iOWcqOihqOaPkuWFpeeahOaXtuWAmeWmguaenOeUqOaIt+S4jei1i+WAvOWImeiHquWKqOihpeS4iumaj+acuuaVo+WIl+WAvO+8iVxuICAgICAgICBsZXQgb2JqID0ge30gLy8g56Gu5L+d5Zyo5paw5aKe5Lik5Liq57qm5a6a5Li76ZSu5ZCO5Li76ZSu5a6a5LmJ6aG65bqP5LiO5bqU55So5L+d5oyB5LiA6Ie0XG4gICAgICAgIG9ialtaT05FX0tFWV9OQU1FXSA9ICdzdHJpbmcnXG4gICAgICAgIGlmIChfLmlzRW1wdHkodGhpcy5fc2NoZW1hLktFWVMpKSB7XG4gICAgICAgICAgICAvLyDlpoLmnpzkuIDkuKrnlKjmiLfoh6rlrprkuYnnmoTkuLvplK7pg73msqHmnInlsLHoh6rliqjooaXkuIrkuIDkuKroh6rlop7kuLvplK5pZOi/m+ihjOWUr+S4gOagh+ivhijlj6rog73ooaXliLDnrKzkuozliJfmiY3og73mraPnoa7mo4DntKIpXG4gICAgICAgICAgICBvYmpbQVVUT19LRVlfTkFNRV0gPSAnaW50ZWdlcidcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGZvciAobGV0IGsgaW4gdGhpcy5fc2NoZW1hLktFWVMpIHtcbiAgICAgICAgICAgICAgICBvYmpba10gPSB0aGlzLl9zY2hlbWEuS0VZU1trXVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3NjaGVtYS5LRVlTID0gb2JqXG5cbiAgICAgICAgLy8g56Gu5L+d5Lik5Liq57y655yB5a2X5q616YO95LiN5a2Y5Zyo5Zyo55So5oi36Ieq5a6a5LmJ55qE5a2X5q615Lit77yI5re75Yqg5YiwQ09MVU1OU+WumuS5ieS4re+8iVxuICAgICAgICB0aGlzLl9zY2hlbWEuQ09MVU1OU1snY3JlYXRlZF9hdCddID0gJ3N0cmluZydcbiAgICAgICAgdGhpcy5fc2NoZW1hLkNPTFVNTlNbJ3VwZGF0ZWRfYXQnXSA9ICdzdHJpbmcnXG5cbiAgICAgICAgdGhpcy5fY2xpZW50ID0gbmV3IFRhYmxlU3RvcmUuQ2xpZW50KHtcbiAgICAgICAgICAgIGFjY2Vzc0tleUlkOiBpbnN0YW5jZXNbY29uZmlnXS5PVFNfQUNDRVNTX0tFWV9JRCxcbiAgICAgICAgICAgIHNlY3JldEFjY2Vzc0tleTogaW5zdGFuY2VzW2NvbmZpZ10uT1RTX1NFQ1JFVEVfQUNDRVNTX0tFWSxcbiAgICAgICAgICAgIGVuZHBvaW50OiBpbnN0YW5jZXNbY29uZmlnXS5PVFNfRU5EUE9JTlQsXG4gICAgICAgICAgICBpbnN0YW5jZW5hbWU6IGluc3RhbmNlc1tjb25maWddLk9UU19JTlNUQU5DRU5BTUVcbiAgICAgICAgfSlcbiAgICB9XG5cbiAgICBwcml2YXRlIF9jaGVja190eXBlKHZhbHVlKSB7XG4gICAgICAgIHJldHVybiBfLmluY2x1ZGVzKFsnc3RyaW5nJywgJ251bWJlcicsICdib29sZWFuJ10sIHR5cGVvZiB2YWx1ZSlcbiAgICB9XG5cbiAgICAvLyDlr7nkuo7ooYzorrDlvZXnmoRzY2hlbWHmqKHlvI/moKHpqoznoa7kv53mlbDmja7nsbvlnovkuKXmoLznmoTmraPnoa7ku6Xlj4rmi7zmjqXlrozmlbTnmoR0YWJsZXN0b3Jl5pWw5o2u57uT5p6E5Lit55qE5Li76ZSu5ZKM5bGe5oCn5Lik5Liq5a2X5q61XG4gICAgcHJpdmF0ZSBfY2hlY2tfc2NoZW1hKHJvdzogUk9XLCBwYXJhbXM6IGFueSwgaXNfaW5zZXJ0X2NoZWNrOiBib29sZWFuID0gZmFsc2UpIHtcblxuICAgICAgICAvLyDpnIDopoHlr7nlupTnlKjkvKDlhaXnmoTkuLvplK7luo/liJfkuKXmoLzmjInnhadzY2hlbWHlrprkuYnnmoTmjpLluo/vvIjlkKbliJlPVFPmnI3liqHnq6/ml6Dms5Xov5vooYzmraPnoa7lpITnkIbogIzlr7zoh7TmiqXplJnlvILluLjvvIlcbiAgICAgICAgZm9yIChsZXQgayBpbiB0aGlzLl9zY2hlbWEuS0VZUykge1xuICAgICAgICAgICAgaWYgKCEoayBpbiByb3cpKSB7XG4gICAgICAgICAgICAgICAgLy8g5Y+q5pyJ6Z2e5o+S5YWl5bGe5oCn5bm25LiU5Li66Z2e6Ieq5aKe5Li76ZSu55qE5oOF5Ya15omN5Lya5YWB6K645Li76ZSu5a2X5q6155qE6L6T5YWl5b+F6aG76KaB5a6M5pW0XG4gICAgICAgICAgICAgICAgeGFzc2VydChpc19pbnNlcnRfY2hlY2sgJiYgayA9PSBBVVRPX0tFWV9OQU1FLCBFUlIkUEFSQU0sIHtrLCByb3csIHBhcmFtc30pXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoaXNfaW5zZXJ0X2NoZWNrICYmIGsgPT0gQVVUT19LRVlfTkFNRSkge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5wcmltYXJ5S2V5LnB1c2goe1tBVVRPX0tFWV9OQU1FXTogVGFibGVTdG9yZS5QS19BVVRPX0lOQ1J9KS8vIOS7pWlk57qm5a6a5Li66Ieq5aKe6KGo5Li76ZSu5YC8XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuX3NjaGVtYS5LRVlTW2tdID09ICdpbnRlZ2VyJykge1xuICAgICAgICAgICAgICAgIHhhc3NlcnQodGhpcy5fY2hlY2tfdHlwZShyb3dba10pLCBFUlIkUEFSQU0sIHtrLCByb3csIHBhcmFtc30pXG4gICAgICAgICAgICAgICAgcGFyYW1zLnByaW1hcnlLZXkucHVzaCh7W2tdOiBpbnQ2NChyb3dba10gYXMgc3RyaW5nIHwgbnVtYmVyKX0pXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHhhc3NlcnQodGhpcy5fY2hlY2tfdHlwZShyb3dba10pLCBFUlIkUEFSQU0sIHtrLCByb3csIHBhcmFtc30pXG4gICAgICAgICAgICAgICAgcGFyYW1zLnByaW1hcnlLZXkucHVzaCh7W2tdOiByb3dba119KVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8g5oyJ54Wnc2NoZW1h5a6a5LmJ6L+b6KGM5bGe5oCn6LWL5YC8XG4gICAgICAgIGZvciAobGV0IGsgaW4gdGhpcy5fc2NoZW1hLkNPTFVNTlMpIHtcbiAgICAgICAgICAgIGlmICghKGsgaW4gcm93KSkge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGhpcy5fc2NoZW1hLkNPTFVNTlNba10gPT0gJ2ludGVnZXInKSB7XG4gICAgICAgICAgICAgICAgeGFzc2VydCh0aGlzLl9jaGVja190eXBlKHJvd1trXSksIEVSUiRQQVJBTSwge2ssIHJvdywgcGFyYW1zfSlcbiAgICAgICAgICAgICAgICBwYXJhbXMuYXR0cmlidXRlQ29sdW1ucy5wdXNoKHtba106IGludDY0KHJvd1trXSBhcyBzdHJpbmcgfCBudW1iZXIpfSlcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgeGFzc2VydCh0aGlzLl9jaGVja190eXBlKHJvd1trXSksIEVSUiRQQVJBTSwge2ssIHJvdywgcGFyYW1zfSlcbiAgICAgICAgICAgICAgICBwYXJhbXMuYXR0cmlidXRlQ29sdW1ucy5wdXNoKHtba106IHJvd1trXX0pXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUT0RPIOWvueS6juaJgOacieS4u+mUruWSjOWxnuaAp+eahOaVsOaNruexu+Wei+i9rOaNouWkhOeQhumYsuatouWxnuaAp+i1i+WAvOmUmeivr+i/m+ihjOajgOafpeWIpOaWrVxuICAgIH1cblxuICAgIC8vIOe6puWumuaJgOacieihqOmDvemcgOimgeacieiHquWinuS4u+mUrmlk5L2c5Li65YaF6YOo5ZSv5LiA5qCH6K+G56CB77yM5YW25L2Z5LiJ5Liq5Li76ZSu5b+F6aG75YWo6YOo5Li65a2X56ym5Liy44CC77yI5ZCO56uv6ZyA6KaB5omp5bGVaW505ZKMZGF0ZeWfuuacrOaVsOaNruexu+Wei+S7peWPiuaTjeS9nOespumHjei9veWunueOsOS8mOWMluW8gOWPke+8iVxuICAgIC8vIOWxnuaAp+Wtl+auteWPr+S7peagueaNruS4muWKoea8lOWPmOS7u+aEj+eahOaJqeWxleWinuWKoOeUseS4muWKoeS7o+eggeWvueS6juiAgeaVsOaNruS4jeWtmOWcqOaWsOWinuWtl+auteWAvOeahOaDheWGteWBmuWFvOWuueWkhOeQhlxuICAgIHB1YmxpYyBhc3luYyBpbnNlcnQocm93OiBST1cpIHtcbiAgICAgICAgaWYgKCFyb3cpIHJvdyA9IHt9XG4gICAgICAgIHJvdyA9IE9iamVjdC5hc3NpZ24oe1taT05FX0tFWV9OQU1FXTogJyd9LCByb3cpXG4gICAgICAgIHhhc3NlcnQoXy5pc1BsYWluT2JqZWN0KHJvdyksIEVSUiRQQVJBTSwge3Jvd30pXG4gICAgICAgIC8vIOayoeacieaMh+WumuWIhuWMuumXtOS4uuWFtuiHquWKqOmaj+acuuihpeS4iuS4gOS4quWIhuWMuumUruWAvOi/m+ihjOaVo+WIl+eul+azleWunueOsFxuICAgICAgICAvLyBpZiAoIShaT05FX0tFWV9OQU1FIGluIHJvdykpIHtcbiAgICAgICAgLy8gICAgIC8vIGNvbnN0IHNob3J0aWQgPSByZXF1aXJlKCdzaG9ydGlkJylcbiAgICAgICAgLy8gICAgIC8vIHJvd1taT05FX0tFWV9OQU1FXSA9IHNob3J0aWQuZ2VuZXJhdGUoKVxuICAgICAgICAvLyAgICAgLy8g5pS555SodXVpZDHnmoTml7bpl7Tov57nu63mgKfnmoTllK/kuIDlgLzov5vooYzmnInluo/mjpLliJfmlbDmja7mlrnkvr/lupTnlKjpgY3ljobmn6Xmib5cbiAgICAgICAgLy8gICAgIC8vIHJvd1taT05FX0tFWV9OQU1FXSA9IHV1aWR2MSgpLnJlcGxhY2UoL1xcLS9nLCAnJykgLy8g5re75YqgWk9OReWIhuWMuumUru+8iOaMieeFp+aXtumXtOmhuuW6j3V1aWTmjpLliJfvvIlcbiAgICAgICAgLy8gICAgIHJvd1taT05FX0tFWV9OQU1FXSA9ICcnIC8vIEZJWE1FIOaaguaXtuWujOWFqOW/veeVpeaOieWtmOWcqOmXrumimFxuICAgICAgICAvLyB9XG4gICAgICAgIGRlbGV0ZSByb3dbQVVUT19LRVlfTkFNRV0gLy8g5Yig6Zmk5Y+v6IO955qE5LiN6ZyA6KaB6L6T5YWl55qEaWTlgLzpgb/lhY3mvZzlnKjmj5LlhaXplJnor69cbiAgICAgICAgLy8g6Ieq5Yqo6KGl5LiKdXBkYXRlZF9hdOWSjGNyZWF0ZWRfYXTkuKTkuKrnvLrnnIHlrZfmrrXlgLznmoToh6rliqjorr7nva5cbiAgICAgICAgcm93WydjcmVhdGVkX2F0J10gPSByb3dbJ3VwZGF0ZWRfYXQnXSA9IG1vbWVudCgpLmZvcm1hdCgnWVlZWS1NTS1ERCBISDptbTpzcycpXG5cbiAgICAgICAgY29uc3QgX190aGlzX18gPSB0aGlzXG4gICAgICAgIC8vIHZhciBjdXJyZW50VGltZVN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgICAgY29uc3QgcGFyYW1zID0ge1xuICAgICAgICAgICAgdGFibGVOYW1lOiB0aGlzLl90YWJsZSxcbiAgICAgICAgICAgIGNvbmRpdGlvbjogbmV3IFRhYmxlU3RvcmUuQ29uZGl0aW9uKFRhYmxlU3RvcmUuUm93RXhpc3RlbmNlRXhwZWN0YXRpb24uSUdOT1JFLCBudWxsKSxcbiAgICAgICAgICAgIHByaW1hcnlLZXk6IFtdLFxuICAgICAgICAgICAgYXR0cmlidXRlQ29sdW1uczogW10sXG4gICAgICAgICAgICAvLyDmjInnhafkuIvpnaLmlbDmja7moLzlvI/ov5vooYxzY2hlbWHlrprkuYnnmoTpqozor4Hku6Xlj4rmlbDmja7nsbvlnovovazmjaJcbiAgICAgICAgICAgIC8vIHByaW1hcnlLZXk6IFt7J2dpZCc6IExvbmcuZnJvbU51bWJlcigyMDAxMyl9LCB7J3VpZCc6IExvbmcuZnJvbU51bWJlcigyMDAxMyl9XSxcbiAgICAgICAgICAgIC8vIGF0dHJpYnV0ZUNvbHVtbnM6IFtcbiAgICAgICAgICAgIC8vICAgICB7J2NvbDEnOiAn6KGo5qC85a2Y5YKoJ30sXG4gICAgICAgICAgICAvLyAgICAgeydjb2wyJzogJzInLCAndGltZXN0YW1wJzogY3VycmVudFRpbWVTdGFtcH0sIC8vIOWFgeiuuOS/ruaUueaXtumXtOaIs+S5kOingumUgeWKn+iDveWunueOsOaaguS4jeaUr+aMgVxuICAgICAgICAgICAgLy8gICAgIHsnY29sMyc6IDMuMX0sXG4gICAgICAgICAgICAvLyAgICAgeydjb2w0JzogLTAuMzJ9LFxuICAgICAgICAgICAgLy8gICAgIHsnY29sNSc6IExvbmcuZnJvbU51bWJlcigxMjM0NTY3ODkpfVxuICAgICAgICAgICAgLy8gXSxcbiAgICAgICAgICAgIC8vIHByaW1hcnlLZXk6IFtcbiAgICAgICAgICAgIC8vICAgICB7J3Nob3J0X2lkJzogJ3BrMSd9LFxuICAgICAgICAgICAgLy8gICAgIHtbQVVUT19LRVlfTkFNRV06IFRhYmxlU3RvcmUuUEtfQVVUT19JTkNSfVxuICAgICAgICAgICAgLy8gXSxcbiAgICAgICAgICAgIC8vIGF0dHJpYnV0ZUNvbHVtbnM6IFtcbiAgICAgICAgICAgIC8vICAgICB7J2FwcGNvZGUnOiAnYXBwMSd9XG4gICAgICAgICAgICAvLyBdLFxuICAgICAgICAgICAgcmV0dXJuQ29udGVudDoge3JldHVyblR5cGU6IFRhYmxlU3RvcmUuUmV0dXJuVHlwZS5QcmltYXJ5a2V5fVxuICAgICAgICB9XG4gICAgICAgIHRoaXMuX2NoZWNrX3NjaGVtYShyb3csIHBhcmFtcywgdHJ1ZSlcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgX190aGlzX18uX2NsaWVudC5wdXRSb3cocGFyYW1zLCBmdW5jdGlvbiAoZXJyLCBkYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHh0aHJvdyhuZXcgRXJyb3IoZXJyKSwgcmVqZWN0LCB7cGFyYW1zLCBkYXRhfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8ve1wiY29uc3VtZWRcIjp7XCJjYXBhY2l0eV91bml0XCI6e1wicmVhZFwiOjAsXCJ3cml0ZVwiOjF9fSxcInJvd1wiOntcbiAgICAgICAgICAgICAgICAgICAgLy8gIFwicHJpbWFyeUtleVwiOlt7XCJuYW1lXCI6XCJzaG9ydF9pZFwiLFwidmFsdWVcIjpcImFiY2RcIn0se1wibmFtZVwiOlwiaWRcIixcInZhbHVlXCI6MTUyMDc2NTUwMjM0NzAwMH1dLFxuICAgICAgICAgICAgICAgICAgICAvLyAgXCJhdHRyaWJ1dGVzXCI6W119LFxuICAgICAgICAgICAgICAgICAgICAvLyBcIlJlcXVlc3RJZFwiOlwiMDAwNTY3MjAtY2Y4ZC1kNGE4LThhZTgtOTcwYTE3ODk0Y2U2XCJ9XG4gICAgICAgICAgICAgICAgICAgIC8vIOaPkuWFpeWQjui/lOWbnuS4u+mUruWIl+ihqOaWsOWinueahOiHquWinuWtl+auteWAvOe7meW6lOeUqOWBmuW6lOeUqOWFs+iBlFxuICAgICAgICAgICAgICAgICAgICB4YXNzZXJ0KGRhdGEucm93ICYmIGRhdGEucm93LnByaW1hcnlLZXkgJiYgXy5pc0FycmF5KGRhdGEucm93LnByaW1hcnlLZXkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgRVJSJFBBUkFNLCB7ZGF0YSwgdGFibGU6IF9fdGhpc19fLl90YWJsZX0pXG4gICAgICAgICAgICAgICAgICAgIGxldCBvdXQgPSBPYmplY3QuYXNzaWduKHt9LCByb3cpXG4gICAgICAgICAgICAgICAgICAgIGZvciAobGV0IGsgaW4gZGF0YS5yb3cucHJpbWFyeUtleSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHZhbHVlID0gZGF0YS5yb3cucHJpbWFyeUtleVtrXS52YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW50NjTovazmjaLlm57liLBudW1iZXLnmoRqYXZhc2NyaXB057G75Z6L5aSE55CGXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlIGFzIGFueSA9PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dFtkYXRhLnJvdy5wcmltYXJ5S2V5W2tdLm5hbWVdID0gdmFsdWUudG9OdW1iZXIoKVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRbZGF0YS5yb3cucHJpbWFyeUtleVtrXS5uYW1lXSA9IHZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShvdXQpXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIHh0aHJvdyhlcnIsIHJlamVjdClcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICB9XG5cbiAgICAvLyDmnaHku7bmm7TmlrDlv4XpobvopoHloavlhpnkuLvplK7orrDlvZXlgLwo5LuF5LuF5YWB6K645pu05paw5bGe5oCn5a2X5q616ICM5Li76ZSu5a2X5q615piv5LiN5YWB6K645pu05paw55qE77yMXG4gICAgLy8gICAgICDmlbTliJfmm7TmlrDlkozliKDpmaTliJflsZ7kuo7ov5Dnu7Tmk43kvZznpoHmraLlupTnlKjkuK3kvb/nlKjpnIDopoHljZXni6zmjqXlj6Pku6Xlj4rmnYPpmZDorqTor4EpXG4gICAgcHVibGljIGFzeW5jIHVwZGF0ZShyb3c6IFJPVywgY29uZGl0aW9uOiBST1cpIHtcbiAgICAgICAgeGFzc2VydChyb3cgJiYgY29uZGl0aW9uICYmIF8uaXNQbGFpbk9iamVjdChyb3cpICYmIF8uaXNQbGFpbk9iamVjdChjb25kaXRpb24pKVxuICAgICAgICByb3cgPSB4YXNzaWduKHt9LCByb3cpXG4gICAgICAgIGNvbmRpdGlvbiA9IHhhc3NpZ24oe1taT05FX0tFWV9OQU1FXTogJyd9LCBjb25kaXRpb24pXG4gICAgICAgIC8vIOajgOafpeS4u+mUruadoeS7tuS4peagvOS/neivgeWMuemFje+8jOW9k+S4u+mUruS4jeWujOaVtOeahOaXtuWAmemcgOimgemAmui/h2lk5Li76ZSu5p+l5om+5Y6f5aeL5YC86KGl5YWo57y65bCR55qE5Li76ZSu5YC877yIRklYTUUgT1RT55qE57y66Zm36KeE6YG/5o6J77yJXG4gICAgICAgIC8vIHhhc3NlcnQoJ2lkJyBpbiBjb25kaXRpb24sIEVSUiRQQVJBTSwge3JvdywgY29uZGl0aW9ufSlcbiAgICAgICAgLy8gbGV0IHRtcCA9IGF3YWl0IHRoaXMucXVlcnkoe2lkOiBjb25kaXRpb24uaWR9KSAvLyDmo4Dmn6VpZOeahOacieaViOaAp1xuICAgICAgICAvLyB4YXNzZXJ0KHRtcCwgRVJSJEVNUFRZLCB7cm93LCBjb25kaXRpb24sIHRtcH0pXG4gICAgICAgIC8vIGNvbmRpdGlvbiA9IHhhc3NpZ24oe30sIGNvbmRpdGlvbilcbiAgICAgICAgLy8gZm9yIChsZXQgayBpbiB0aGlzLl9zY2hlbWEuS0VZUykge1xuICAgICAgICAvLyAgICAgY29uZGl0aW9uW2tdID0gdG1wW2tdIC8vIOihpeWFqOWujOaVtOeahOWtl+autVxuICAgICAgICAvLyB9XG5cbiAgICAgICAgLy8g5pu05paw57y655yB6Ieq5a6a5LmJ55qE5bGe5oCn5a2X5q61XG4gICAgICAgIHJvd1sndXBkYXRlZF9hdCddID0gbW9tZW50KCkuZm9ybWF0KCdZWVlZLU1NLUREIEhIOm1tOnNzJylcblxuICAgICAgICBjb25zdCBfX3RoaXNfXyA9IHRoaXNcbiAgICAgICAgY29uc3QgcGFyYW1zID0ge1xuICAgICAgICAgICAgdGFibGVOYW1lOiB0aGlzLl90YWJsZSxcbiAgICAgICAgICAgIGNvbmRpdGlvbjogbnVsbCxcbiAgICAgICAgICAgIC8vIGNvbmRpdGlvbjogbmV3IFRhYmxlU3RvcmUuQ29uZGl0aW9uKFRhYmxlU3RvcmUuUm93RXhpc3RlbmNlRXhwZWN0YXRpb24uRVhQRUNUX0VYSVNUXG4gICAgICAgICAgICAvLyAgICAgLCBuZXcgVGFibGVTdG9yZS5TaW5nbGVDb2x1bW5Db25kaXRpb24oXCJjb2wxXCIsICd0ZXN0NScsIFRhYmxlU3RvcmUuQ29tcGFyYXRvclR5cGUuRVFVQUwpKSxcbiAgICAgICAgICAgIC8vIHByaW1hcnlLZXk6IFt7J2dpZCc6IExvbmcuZnJvbU51bWJlcigyMDAxMyl9LCB7J3VpZCc6IExvbmcuZnJvbU51bWJlcigyMDAxMyl9XSxcbiAgICAgICAgICAgIHByaW1hcnlLZXk6IFtdIGFzIGFueVtdLFxuICAgICAgICAgICAgLy8gdXBkYXRlT2ZBdHRyaWJ1dGVDb2x1bW5zOiBbeydQVVQnOiBbeydjb2wxJzogJ3Rlc3Q2J31dfV1cbiAgICAgICAgICAgIHVwZGF0ZU9mQXR0cmlidXRlQ29sdW1uczogW3snUFVUJzogW10gYXMgYW55W119XVxuICAgICAgICB9XG5cbiAgICAgICAgLy8g5YWI5aSE55CG5pu05paw5a2X5q6155qE6LWL5YC85aSE55CGXG4gICAgICAgIGZvciAobGV0IGsgaW4gcm93KSB7XG4gICAgICAgICAgICB4YXNzZXJ0KGsgaW4gdGhpcy5fc2NoZW1hLkNPTFVNTlMgJiYgdGhpcy5fY2hlY2tfdHlwZShyb3dba10pLFxuICAgICAgICAgICAgICAgIEVSUiRQQVJBTSwge2ssIHJvdywgc2NoZW1hOiB0aGlzLl9zY2hlbWF9KVxuICAgICAgICAgICAgcGFyYW1zLnVwZGF0ZU9mQXR0cmlidXRlQ29sdW1uc1swXVsnUFVUJ10ucHVzaCh7W2tdOiByb3dba119KVxuICAgICAgICB9XG5cbiAgICAgICAgLy8g5YaN5aSE55CG5Li76ZSu5p+l6K+i5p2h5Lu277yI5omA5pyJ5Li76ZSu5a2X5q615b+F6aG76KaB6K6+572u77yJXG4gICAgICAgIGZvciAobGV0IGsgaW4gdGhpcy5fc2NoZW1hLktFWVMpIHtcbiAgICAgICAgICAgIHhhc3NlcnQoayBpbiBjb25kaXRpb24gJiYgdGhpcy5fY2hlY2tfdHlwZShjb25kaXRpb25ba10pLCBFUlIkUEFSQU0sIHtrLCBjb25kaXRpb259KVxuICAgICAgICAgICAgaWYgKHRoaXMuX3NjaGVtYS5LRVlTW2tdID09ICdpbnRlZ2VyJykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5wcmltYXJ5S2V5LnB1c2goe1trXTogaW50NjQoY29uZGl0aW9uW2tdIGFzIGFueSl9KVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMucHJpbWFyeUtleS5wdXNoKHtba106IGNvbmRpdGlvbltrXX0pXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyDmnIDlkI7lpITnkIblsZ7mgKfmnaHku7bnmoTnu4TlkIjmn6Xor6LlpITnkIYoY2FzZTEg5Y+q5pyJ5Li76ZSu5a2X5q6177yMY2FzZTIg5Y+q5pyJ5LiA5Liq5bGe5oCn5a2X5q6177yMIGNhc2UzIOacieS4pOS4quaIluS7peS4iueahOWxnuaAp+Wtl+autSlcbiAgICAgICAgbGV0IHNpemUxID0gXy5rZXlzKGNvbmRpdGlvbikubGVuZ3RoXG4gICAgICAgIGxldCBzaXplMiA9IF8ua2V5cyh0aGlzLl9zY2hlbWEuS0VZUykubGVuZ3RoXG4gICAgICAgIGlmIChzaXplMSA9PSBzaXplMikge1xuICAgICAgICAgICAgLy8g5Y+q5pyJ5bGe5oCn5a2X5q61562J5Lu35LqO5peg5p2h5Lu25pu05paw5bGe5oCnXG4gICAgICAgICAgICBwYXJhbXMuY29uZGl0aW9uID0gbmV3IFRhYmxlU3RvcmUuQ29uZGl0aW9uKFRhYmxlU3RvcmUuUm93RXhpc3RlbmNlRXhwZWN0YXRpb24uSUdOT1JFLCBudWxsKVxuICAgICAgICB9IGVsc2UgaWYgKHNpemUxID09IHNpemUyICsgMSkge1xuICAgICAgICAgICAgLy8g5Y+q5pyJ5LiA5Liq5bGe5oCn5a2X5q615p+l6K+i5p2h5Lu2XG4gICAgICAgICAgICBmb3IgKGxldCBrIGluIGNvbmRpdGlvbikge1xuICAgICAgICAgICAgICAgIGlmIChrIGluIHRoaXMuX3NjaGVtYS5LRVlTKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHhhc3NlcnQoIXBhcmFtcy5jb25kaXRpb24gYXMgYW55LCBFUlIkUEFSQU0sIHtjb25kaXRpb24sIEtFWVM6IHRoaXMuX3NjaGVtYS5LRVlTfSlcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5fc2NoZW1hLktFWVNba10gPT0gJ2ludGVnZXInKSB7XG4gICAgICAgICAgICAgICAgICAgIHBhcmFtcy5jb25kaXRpb24gPSBuZXcgVGFibGVTdG9yZS5Db25kaXRpb24oVGFibGVTdG9yZS5Sb3dFeGlzdGVuY2VFeHBlY3RhdGlvbi5FWFBFQ1RfRVhJU1QsXG4gICAgICAgICAgICAgICAgICAgICAgICBuZXcgVGFibGVTdG9yZS5TaW5nbGVDb2x1bW5Db25kaXRpb24oaywgaW50NjQoY29uZGl0aW9uW2tdIGFzIGFueSksIFRhYmxlU3RvcmUuQ29tcGFyYXRvclR5cGUuRVFVQUwpKVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHBhcmFtcy5jb25kaXRpb24gPSBuZXcgVGFibGVTdG9yZS5Db25kaXRpb24oVGFibGVTdG9yZS5Sb3dFeGlzdGVuY2VFeHBlY3RhdGlvbi5FWFBFQ1RfRVhJU1QsXG4gICAgICAgICAgICAgICAgICAgICAgICBuZXcgVGFibGVTdG9yZS5TaW5nbGVDb2x1bW5Db25kaXRpb24oaywgY29uZGl0aW9uW2tdLCBUYWJsZVN0b3JlLkNvbXBhcmF0b3JUeXBlLkVRVUFMKSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyDkuKTkuKrmiJbkuKTkuKrku6XkuIrlsZ7mgKflrZfmrrXmn6Xor6LmnaHku7bvvIjlpI3lkIjmnaHku7bmn6Xor6LlpITnkIbvvIlcbiAgICAgICAgICAgIGxldCBhbmQ6IGFueSA9IG5ldyBUYWJsZVN0b3JlLkNvbXBvc2l0ZUNvbmRpdGlvbihUYWJsZVN0b3JlLkxvZ2ljYWxPcGVyYXRvci5BTkQpXG4gICAgICAgICAgICBmb3IgKGxldCBrIGluIGNvbmRpdGlvbikge1xuICAgICAgICAgICAgICAgIGlmIChrIGluIHRoaXMuX3NjaGVtYS5LRVlTKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICh0aGlzLl9zY2hlbWEuS0VZU1trXSA9PSAnaW50ZWdlcicpIHtcbiAgICAgICAgICAgICAgICAgICAgYW5kLmFkZFN1YkNvbmRpdGlvbihrLCBpbnQ2NChjb25kaXRpb25ba10gYXMgYW55KSwgVGFibGVTdG9yZS5Db21wYXJhdG9yVHlwZS5FUVVBTClcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBhbmQuYWRkU3ViQ29uZGl0aW9uKGssIGNvbmRpdGlvbltrXSwgVGFibGVTdG9yZS5Db21wYXJhdG9yVHlwZS5FUVVBTClcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBwYXJhbXMuY29uZGl0aW9uID0gbmV3IFRhYmxlU3RvcmUuQ29uZGl0aW9uKFRhYmxlU3RvcmUuUm93RXhpc3RlbmNlRXhwZWN0YXRpb24uRVhQRUNUX0VYSVNULCBhbmQpXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgX190aGlzX18uX2NsaWVudC51cGRhdGVSb3cocGFyYW1zLCBmdW5jdGlvbiAoZXJyLCBkYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHh0aHJvdyhuZXcgRXJyb3IoZXJyKSwgcmVqZWN0LCB7cGFyYW1zLCBkYXRhfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICB4dGhyb3coZXJyLCByZWplY3QpXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgfVxuXG4gICAgLy8g5Lul5Li76ZSu5L2c5Li65p2h5Lu25Yig6Zmk6K6w5b2V5YC8XG4gICAgcHVibGljIGFzeW5jIGRlbGV0ZShyb3c6IFJPVykge1xuICAgICAgICBjb25zdCBfX3RoaXNfXyA9IHRoaXNcbiAgICAgICAgY29uc3QgcGFyYW1zID0ge1xuICAgICAgICAgICAgdGFibGVOYW1lOiB0aGlzLl90YWJsZSxcbiAgICAgICAgICAgIGNvbmRpdGlvbjogbmV3IFRhYmxlU3RvcmUuQ29uZGl0aW9uKFRhYmxlU3RvcmUuUm93RXhpc3RlbmNlRXhwZWN0YXRpb24uSUdOT1JFLCBudWxsKSxcbiAgICAgICAgICAgIC8vIHByaW1hcnlLZXk6IFt7ICdnaWQnOiBMb25nLmZyb21OdW1iZXIoOCkgfSwgeyAndWlkJzogTG9uZy5mcm9tTnVtYmVyKDgwKSB9XVxuICAgICAgICAgICAgcHJpbWFyeUtleTogW10gYXMgYW55W11cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIOiHs+WwkeS4gOS4quS4u+mUrlxuICAgICAgICB4YXNzZXJ0KF8ua2V5cyh0aGlzLl9zY2hlbWEuS0VZUykubGVuZ3RoID4gMCwgRVJSJFBBUkFNLCB7c2NoZW1hOiB0aGlzLl9zY2hlbWF9KVxuICAgICAgICBmb3IgKGxldCBrIGluIHRoaXMuX3NjaGVtYS5LRVlTKSB7XG4gICAgICAgICAgICAvLyDmiYDmnInnmoTkuLvplK7mnaHku7blv4Xpobvpg73opoHlrZjlnKhcbiAgICAgICAgICAgIHhhc3NlcnQoayBpbiByb3csIEVSUiRQQVJBTSwge2ssIHJvdywgcGFyYW1zfSlcbiAgICAgICAgICAgIGlmICh0aGlzLl9zY2hlbWEuS0VZU1trXSA9PSAnaW50ZWdlcicpIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMucHJpbWFyeUtleS5wdXNoKHtba106IGludDY0KHJvd1trXSBhcyBhbnkpfSlcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zLnByaW1hcnlLZXkucHVzaCh7W2tdOiByb3dba10gYXMgYW55fSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIF9fdGhpc19fLl9jbGllbnQuZGVsZXRlUm93KHBhcmFtcywgZnVuY3Rpb24gKGVyciwgZGF0YSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB4dGhyb3cobmV3IEVycm9yKGVyciksIHJlamVjdCwge3BhcmFtcywgZGF0YX0pXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKClcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgeHRocm93KGVyciwgcmVqZWN0KVxuICAgICAgICAgICAgfVxuICAgICAgICB9KVxuICAgIH1cblxuICAgIC8vIOWIhumhteafpeivouS4gOasoeajgOe0ok7mnaHorrDlvZXvvIhcbiAgICAvLyAgICAgIOWIhuW4g+W8j+ezu+e7n+eahOeJueeCueS4jemAguWQiOaJuemHj+afpeivouWkmuadoeiusOW9le+8jOWmguaciei/meenjemcgOaxgumcgOimgW1vbmdvZGLmiJZteXNxbOWujOaIkO+8jFxuICAgIC8vICAgICAgdGFibGVzdG9yZeabtOWKoOmAguWQiOWIhuW4g+W8j3Nlc3Npb27lrZjlgqjov5nnp43mlbDmja7nibnngrnnmoTlupTnlKjvvIxcbiAgICAvLyAgICAgIOWkp+aVsOaNruajgOe0oumcgOimgeWAn+WKqW9wZW5zZWFyY2jnm7TpgJrooajlkIzmraXlrozmiJDlrp7njrDml6Dov5Dnu7ROT1NRTOWujOaVtOaWueahiO+8jFxuICAgIC8vICAgICAg5Y+q5pyJ6ZyA6KaB5LqL5Yqh54m55oCn5YWz6ZSu5bqU55So5omN6ZyA6KaBbXlzcWzkuI3ov4fov5npg6jliIbln7rmnKzkuIrkuI3mmK9ub2RlanPnmoTlt6XkvZzojIPlm7TogIzpnIDopoHkuIvlsYLliLBqYXZh5pyN5Yqh5bGC5Y675a6e546w5pu05ZCI6YCC44CCXG4gICAgLy8g77yJXG4gICAgLy8gcHJpdmF0ZSBhc3luYyBfcXVlcnlfYnlfb3BlbnNlYXJjaChyb3c6IFJPVykge1xuICAgIC8vICAgICAvLyBUT0RPIC4uLiAo6ZyA6KaB6YCa6L+Hc2NoZW1h6YWN572u5Zyo5Yib5bu66KGo55qE5pe25YCZ6Ieq5Yqo6L+b6KGMb3BlbnNlYXJjaOWFs+iBlOihqOWIm+W7uu+8jOWcqGluc2VydOWSjHVwZGF0ZeaVsOaNrueahOaXtuWAmeiHquWKqOWQjOatpW9wZW5zZWFyY2jmlbDmja4pXG4gICAgLy8gfVxuICAgIHByaXZhdGUgYXN5bmMgX3F1ZXJ5X2J5X3JhbmdlKHJhbmdlOiBSQU5HRSB8IHVuZGVmaW5lZCwgbGltaXQ6IG51bWJlciA9IDEwLCBpc19hc2Nfb3JfZGVzYzogYm9vbGVhbiA9IHRydWUpIHtcbiAgICAgICAgaWYgKCFyYW5nZSkge1xuICAgICAgICAgICAgcmFuZ2UgPSB7fVxuICAgICAgICB9XG4gICAgICAgIHhhc3NlcnQoXy5pc1BsYWluT2JqZWN0KHJhbmdlKSAmJiBfLmlzSW50ZWdlcihsaW1pdCkgJiYgbGltaXQgPj0gMSAmJiBfLmlzQm9vbGVhbihpc19hc2Nfb3JfZGVzYyksIEVSUiRQQVJBTSwge3JhbmdlfSlcbiAgICAgICAgLy8g6aqM6K+B5p+l6K+i6IyD5Zu05pWw5o2u5ZCI5rOV5oCnKOaJgOacieWtl+auteW/hemhu+imgeaYr+S4u+mUru+8iVxuICAgICAgICB4YXNzZXJ0KF8ua2V5cyhyYW5nZSkubGVuZ3RoIDw9IF8ua2V5cyh0aGlzLl9zY2hlbWEuS0VZUykubGVuZ3RoLCBFUlIkUEFSQU0sIHtyYW5nZX0pXG4gICAgICAgIGZvciAobGV0IGsgaW4gdGhpcy5fc2NoZW1hLktFWVMpIHtcbiAgICAgICAgICAgIGlmICghKGsgaW4gcmFuZ2UpKSB7XG4gICAgICAgICAgICAgICAgY29udGludWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChfLmlzQXJyYXkocmFuZ2Vba10pKSB7XG4gICAgICAgICAgICAgICAgeGFzc2VydCgocmFuZ2Vba10gYXMgYW55W10pLmxlbmd0aCA9PSAyLCBFUlIkUEFSQU0sIHtrLCByYW5nZX0pXG4gICAgICAgICAgICAgICAgeGFzc2VydCh0aGlzLl9jaGVja190eXBlKHJhbmdlW2tdWzBdKSAmJiB0aGlzLl9jaGVja190eXBlKHJhbmdlW2tdWzFdKSwgRVJSJFBBUkFNLCB7aywgcmFuZ2V9KVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB4YXNzZXJ0KHRoaXMuX2NoZWNrX3R5cGUocmFuZ2Vba10pLCBFUlIkUEFSQU0sIHtrLCByYW5nZX0pXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyDmi7zoo4Xmn6Xor6Llj4LmlbBcbiAgICAgICAgY29uc3QgX190aGlzX18gPSB0aGlzXG4gICAgICAgIGNvbnN0IHBhcmFtcyA9IHtcbiAgICAgICAgICAgIHRhYmxlTmFtZTogdGhpcy5fdGFibGUsXG4gICAgICAgICAgICBkaXJlY3Rpb246IGlzX2FzY19vcl9kZXNjID8gVGFibGVTdG9yZS5EaXJlY3Rpb24uRk9SV0FSRCA6IFRhYmxlU3RvcmUuRGlyZWN0aW9uLkJBQ0tXQVJELFxuICAgICAgICAgICAgLy8gaW5jbHVzaXZlU3RhcnRQcmltYXJ5S2V5OiBbe1wiZ2lkXCI6IFRhYmxlU3RvcmUuSU5GX01JTn0sIHtcInVpZFwiOiBUYWJsZVN0b3JlLklORl9NSU59XSxcbiAgICAgICAgICAgIC8vIGV4Y2x1c2l2ZUVuZFByaW1hcnlLZXk6IFt7XCJnaWRcIjogVGFibGVTdG9yZS5JTkZfTUFYfSwge1widWlkXCI6IFRhYmxlU3RvcmUuSU5GX01BWH1dLFxuICAgICAgICAgICAgaW5jbHVzaXZlU3RhcnRQcmltYXJ5S2V5OiBbXSBhcyBhbnlbXSxcbiAgICAgICAgICAgIGV4Y2x1c2l2ZUVuZFByaW1hcnlLZXk6IFtdIGFzIGFueVtdLFxuICAgICAgICAgICAgbGltaXQ6IGxpbWl0XG4gICAgICAgIH1cbiAgICAgICAgLy8g5qC55o2u5Li76ZSu55qE5p+l6K+i5p2h5Lu26L+b6KGM5p+l6K+i6IyD5Zu055qE6K6+572uKOaMieeFp3NjaGVtYeWumuS5ieWtl+autei/m+ihjOaOkuW6j+WkhOeQhilcbiAgICAgICAgZm9yIChsZXQgayBpbiB0aGlzLl9zY2hlbWEuS0VZUykge1xuICAgICAgICAgICAgaWYgKCEoayBpbiByYW5nZSkpIHtcbiAgICAgICAgICAgICAgICAvLyBGSVhNRSDop4Tpgb9PVFPnmoTorr7orqHnvLrpmbflv4XpobvopoHooaXkuIrliIbljLrplK7lubbkuJTnoa7kv53lt6bpl63lj7PlvIDnmoTmn6Xor6LmlbDmja7nu5PmnoTvvIzlkKbliJnlsLHmmK/lhajooajmn6Xor6LjgIJcbiAgICAgICAgICAgICAgICBpZiAoayA9PSBaT05FX0tFWV9OQU1FKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpc19hc2Nfb3JfZGVzYykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLmluY2x1c2l2ZVN0YXJ0UHJpbWFyeUtleS5wdXNoKHtba106ICcnfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtcy5leGNsdXNpdmVFbmRQcmltYXJ5S2V5LnB1c2goe1trXTogJyEnfSlcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtcy5pbmNsdXNpdmVTdGFydFByaW1hcnlLZXkucHVzaCh7W2tdOiAnISd9KVxuICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLmV4Y2x1c2l2ZUVuZFByaW1hcnlLZXkucHVzaCh7W2tdOiAnJ30pXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29udGludWVcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8g5LiN5aGr55qE5Li76ZSu5Y+C5pWw5oyJ54Wn5pyA5bCP5ZKM5pyA5aSn6IyD5Zu06Ieq5Yqo6KGl5LiK5p+l6K+i5p2h5Lu2KOaciemXrumimOS8muafpeivouWHuuaJgOacieeahOa7oei2s+adoeS7tueahOaVsOaNrilcbiAgICAgICAgICAgICAgICBpZiAoaXNfYXNjX29yX2Rlc2MpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8g5Y2H5bqP6YC76L6R5aSE55CGXG4gICAgICAgICAgICAgICAgICAgIHBhcmFtcy5pbmNsdXNpdmVTdGFydFByaW1hcnlLZXkucHVzaCh7W2tdOiBUYWJsZVN0b3JlLklORl9NSU59KVxuICAgICAgICAgICAgICAgICAgICBwYXJhbXMuZXhjbHVzaXZlRW5kUHJpbWFyeUtleS5wdXNoKHtba106IFRhYmxlU3RvcmUuSU5GX01BWH0pXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8g6ZmN5bqP6YC76L6R5aSE55CGXG4gICAgICAgICAgICAgICAgICAgIHBhcmFtcy5pbmNsdXNpdmVTdGFydFByaW1hcnlLZXkucHVzaCh7W2tdOiBUYWJsZVN0b3JlLklORl9NQVh9KVxuICAgICAgICAgICAgICAgICAgICBwYXJhbXMuZXhjbHVzaXZlRW5kUHJpbWFyeUtleS5wdXNoKHtba106IFRhYmxlU3RvcmUuSU5GX01JTn0pXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIGlmIChfLmlzQXJyYXkocmFuZ2Vba10pKSB7XG4gICAgICAgICAgICAgICAgLy8g55So5oi35oyH5a6a6IyD5Zu06L+b6KGM5p+l6K+iXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuX3NjaGVtYS5LRVlTW2tdID09ICdpbnRlZ2VyJykge1xuICAgICAgICAgICAgICAgICAgICBwYXJhbXMuaW5jbHVzaXZlU3RhcnRQcmltYXJ5S2V5LnB1c2goe1trXTogaW50NjQocmFuZ2Vba11bMF0gYXMgYW55KX0pXG4gICAgICAgICAgICAgICAgICAgIHBhcmFtcy5leGNsdXNpdmVFbmRQcmltYXJ5S2V5LnB1c2goe1trXTogaW50NjQocmFuZ2Vba11bMV0gYXMgYW55KX0pXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcGFyYW1zLmluY2x1c2l2ZVN0YXJ0UHJpbWFyeUtleS5wdXNoKHtba106IHJhbmdlW2tdWzBdfSlcbiAgICAgICAgICAgICAgICAgICAgcGFyYW1zLmV4Y2x1c2l2ZUVuZFByaW1hcnlLZXkucHVzaCh7W2tdOiByYW5nZVtrXVsxXX0pXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyDnrYnlgLznoa7lrprmnaHku7bmn6Xor6JcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5fc2NoZW1hLktFWVNba10gPT0gJ2ludGVnZXInKSB7XG4gICAgICAgICAgICAgICAgICAgIHBhcmFtcy5pbmNsdXNpdmVTdGFydFByaW1hcnlLZXkucHVzaCh7W2tdOiBpbnQ2NChyYW5nZVtrXSBhcyBhbnkpfSlcbiAgICAgICAgICAgICAgICAgICAgcGFyYW1zLmV4Y2x1c2l2ZUVuZFByaW1hcnlLZXkucHVzaCh7W2tdOiBpbnQ2NChyYW5nZVtrXSBhcyBhbnkpfSlcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBwYXJhbXMuaW5jbHVzaXZlU3RhcnRQcmltYXJ5S2V5LnB1c2goe1trXTogcmFuZ2Vba119KVxuICAgICAgICAgICAgICAgICAgICBwYXJhbXMuZXhjbHVzaXZlRW5kUHJpbWFyeUtleS5wdXNoKHtba106IHJhbmdlW2tdfSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgbGV0IHJlc3VsdFJvd3MgPSBbXSAvLyDpgJLlvZLltYzlpZfmn6Xor6LnmoTmnIDnu4jmn6Xor6LlrozmiJDnmoTmlbDmja7pm4blkIjvvIjnrYnmn6Xor6Lnu5PmnZ/lkI7lho3ov5vooYznu5/kuIDlpITnkIbvvIlcbiAgICAgICAgICAgIGNvbnN0IGdldFJhbmdlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIF9fdGhpc19fLl9jbGllbnQuZ2V0UmFuZ2UocGFyYW1zLCBmdW5jdGlvbiAoZXJyLCBkYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHh0aHJvdyhuZXcgRXJyb3IoZXJyKSwgcmVqZWN0LCB7cGFyYW1zLCBkYXRhfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdFJvd3MgPSByZXN1bHRSb3dzLmNvbmNhdChkYXRhLnJvd3MpXG4gICAgICAgICAgICAgICAgICAgIC8v5aaC5p6cZGF0YS5uZXh0X3N0YXJ0X3ByaW1hcnlfa2V55LiN5Li656m677yM6K+05piO6ZyA6KaB57un57ut6K+75Y+WXG4gICAgICAgICAgICAgICAgICAgIC8vIGlmIChkYXRhLm5leHRfc3RhcnRfcHJpbWFyeV9rZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAvLyBwYXJhbXMuaW5jbHVzaXZlU3RhcnRQcmltYXJ5S2V5ID0gW1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gLy8gICAgIHtcImdpZFwiOiBkYXRhLm5leHRfc3RhcnRfcHJpbWFyeV9rZXlbMF0udmFsdWV9LFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gLy8gICAgIHtcInVpZFwiOiBkYXRhLm5leHRfc3RhcnRfcHJpbWFyeV9rZXlbMV0udmFsdWV9XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAvLyBdXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBwYXJhbXMuaW5jbHVzaXZlU3RhcnRQcmltYXJ5S2V5ID0gW11cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxldCBpID0gMFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZm9yIChsZXQgayBpbiBfX3RoaXNfXy5fc2NoZW1hLktFWVMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICBpZiAoX190aGlzX18uX3NjaGVtYS5LRVlTW2tdID09ICdpbnRlZ2VyJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgICAgICBwYXJhbXMuaW5jbHVzaXZlU3RhcnRQcmltYXJ5S2V5LnB1c2goe1trXTogaW50NjQoZGF0YS5uZXh0X3N0YXJ0X3ByaW1hcnlfa2V5W2ldLnZhbHVlLnRvTnVtYmVyKCkpfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgICAgICBwYXJhbXMuaW5jbHVzaXZlU3RhcnRQcmltYXJ5S2V5LnB1c2goe1trXTogZGF0YS5uZXh0X3N0YXJ0X3ByaW1hcnlfa2V5W2ldLnZhbHVlfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgaSArPSAxXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB9XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBnZXRSYW5nZSgpIC8vIOWIhumhteaVsOi/h+Wkp+aOpeWPo+iHquWKqOWujOaIkOWkmuasoeW1jOWll+mAkuW9kuafpeivouW9ouaIkOW6lOeUqOmAu+i+keS4iueahOS4gOS4quWIhumhteWNleasoeafpeivoue7k+aenOi+k+WHulxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8g57uf5LiA55qE5pWw5o2u57G75Z6L6L2s5o2i5pyA57uI55qE5pWw5o2u57uT5p6c5aSE55CGXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBbIHsgcHJpbWFyeUtleTogWyBbT2JqZWN0XSwgW09iamVjdF0gXSwgYXR0cmlidXRlczogWyBbT2JqZWN0XSBdIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgeyBwcmltYXJ5S2V5OiBbIFtPYmplY3RdLCBbT2JqZWN0XSBdLCBhdHRyaWJ1dGVzOiBbIFtPYmplY3RdIF0gfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICB7IHByaW1hcnlLZXk6IFsgW09iamVjdF0sIFtPYmplY3RdIF0sIGF0dHJpYnV0ZXM6IFsgW09iamVjdF0gXSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgIHsgcHJpbWFyeUtleTogWyBbT2JqZWN0XSwgW09iamVjdF0gXSwgYXR0cmlidXRlczogWyBbT2JqZWN0XSBdIH0gXVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8geGxvZyhKU09OLnN0cmluZ2lmeShyZXN1bHRSb3dzKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBvdXQ6IGFueSA9IFtdXG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBrIGluIHJlc3VsdFJvd3MgYXMgYW55KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IG9iaiA9IHt9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdFJvd3Nba10ucHJpbWFyeUtleSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBqIGluIHJlc3VsdFJvd3Nba10ucHJpbWFyeUtleSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHZhbHVlID0gcmVzdWx0Um93c1trXS5wcmltYXJ5S2V5W2pdLnZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpbnQ2NOi9rOaNouWbnuWIsG51bWJlcueahGphdmFzY3JpcHTnsbvlnovlpITnkIZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgYXMgYW55ID09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JqW3Jlc3VsdFJvd3Nba10ucHJpbWFyeUtleVtqXS5uYW1lXSA9IHZhbHVlLnRvTnVtYmVyKClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JqW3Jlc3VsdFJvd3Nba10ucHJpbWFyeUtleVtqXS5uYW1lXSA9IHZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdFJvd3Nba10uYXR0cmlidXRlcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBqIGluIHJlc3VsdFJvd3Nba10uYXR0cmlidXRlcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHZhbHVlID0gcmVzdWx0Um93c1trXS5hdHRyaWJ1dGVzW2pdLmNvbHVtblZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlIGFzIGFueSA9PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ialtyZXN1bHRSb3dzW2tdLmF0dHJpYnV0ZXNbal0uY29sdW1uTmFtZV0gPSB2YWx1ZS50b051bWJlcigpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ialtyZXN1bHRSb3dzW2tdLmF0dHJpYnV0ZXNbal0uY29sdW1uTmFtZV0gPSB2YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dC5wdXNoKG9iailcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChvdXQubGVuZ3RoID09IDApIG91dCA9IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc29sdmUob3V0KVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGdldFJhbmdlKClcbiAgICAgICAgfSlcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9xdWVyeV9ieV9rZXkocm93OiBST1cpIHtcbiAgICAgICAgcm93ID0geGFzc2lnbih7W1pPTkVfS0VZX05BTUVdOiAnJ30sIHJvdykgLy8g6KGl5LiKWk9ORee8uuecgeWAvFxuICAgICAgICBjb25zdCBfX3RoaXNfXyA9IHRoaXNcbiAgICAgICAgY29uc3QgcGFyYW1zID0ge1xuICAgICAgICAgICAgdGFibGVOYW1lOiB0aGlzLl90YWJsZSxcbiAgICAgICAgICAgIHByaW1hcnlLZXk6IFtdIGFzIGFueVtdLFxuICAgICAgICAgICAgLy8gcHJpbWFyeUtleTogW3snZ2lkJzogTG9uZy5mcm9tTnVtYmVyKDIwMDEzKX0sIHsndWlkJzogTG9uZy5mcm9tTnVtYmVyKDIwMDEzKX1dLFxuICAgICAgICAgICAgY29sdW1uRmlsdGVyOiBudWxsLFxuICAgICAgICB9XG5cbiAgICAgICAgLy8g6KGl5LiK5Li76ZSu5YC8ZXF1YWzmn6Xor6Io5rOo5oSP5LqL6aG577yaT1RT5o6l5Y+j5b+F6aG76KaB5omA5pyJa2V56YO95a2Y5Zyo5omN5YWB6K645p+l6K+iLOiAjOS4lOavj+S4quihqOW/hemhu+imgeiHs+WwkeS4gOS4quS4u+mUru+8jFxuICAgICAgICAvLyDmraTlpITnmoTkuLvplK7kuI7mlbDmja7lupPkuK3nmoTkuLvplK7lubbpnZ7lkIzkuIDkuKrlkKvkuYnogIzmmK/liIbluIPlvI/ns7vnu5/mlbDmja7mlaPliJfnmoTkuIDkuKrliIbljLrmnaHku7blrZfmrrXogIzlt7LlubbpnZ7kuIDlrprpnIDopoHkv53mjIHllK/kuIDjgIIpXG4gICAgICAgIHhhc3NlcnQoXy5rZXlzKHRoaXMuX3NjaGVtYS5LRVlTKS5sZW5ndGggPj0gMSwgRVJSJFBBUkFNLCB7cm93LCBLRVlTOiB0aGlzLl9zY2hlbWEuS0VZU30pXG4gICAgICAgIGZvciAobGV0IGsgaW4gdGhpcy5fc2NoZW1hLktFWVMpIHtcbiAgICAgICAgICAgIC8vIOajgOafpei+k+WFpeadoeS7tuS4reaJgOacieeahOS4u+mUruWtl+auteaYr+WQpuWujOaVtFxuICAgICAgICAgICAgeGFzc2VydChrIGluIHJvdyAmJiB0aGlzLl9jaGVja190eXBlKHJvd1trXSksIEVSUiRQQVJBTSwge2ssIHJvdywgcGFyYW1zfSlcbiAgICAgICAgICAgIGlmICh0aGlzLl9zY2hlbWEuS0VZU1trXSA9PSAnaW50ZWdlcicpIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMucHJpbWFyeUtleS5wdXNoKHtba106IGludDY0KHJvd1trXSBhcyBhbnkpfSlcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zLnByaW1hcnlLZXkucHVzaCh7W2tdOiByb3dba119KVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8g5Y+I5piv5LiA5Liq5Z2R54K577ya5b+F6aG76KaB6Iez5bCRMuS4quWtkOafpeivouadoeS7tuaJjeiDveeUn+aViO+8jOWmguaenOW6lOeUqOi+k+WFpeeahOWPguaVsOi/h+WwkemcgOimgeiHquWKqOihpeS4iumHjeWkjeeahOafpeivouadoeS7tui/m+ihjOWFvOWuueWkhOeQhuOAglxuICAgICAgICAvLyDooaXkuIrlrZfmrrXlgLxlcXVhbOafpeivolxuICAgICAgICBsZXQgY29uZGl0aW9uOiBhbnkgPSBuZXcgVGFibGVTdG9yZS5Db21wb3NpdGVDb25kaXRpb24oVGFibGVTdG9yZS5Mb2dpY2FsT3BlcmF0b3IuQU5EKVxuICAgICAgICBsZXQgc3ViX2NvbmRpdGlvbl9jb3VudCA9IDBcbiAgICAgICAgZm9yIChsZXQgayBpbiB0aGlzLl9zY2hlbWEuQ09MVU1OUykge1xuICAgICAgICAgICAgaWYgKCEoayBpbiByb3cpKSB7XG4gICAgICAgICAgICAgICAgY29udGludWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHhhc3NlcnQodGhpcy5fY2hlY2tfdHlwZShyb3dba10pLCBFUlIkUEFSQU0sIHtrLCByb3csIHBhcmFtc30pXG4gICAgICAgICAgICBpZiAodGhpcy5fc2NoZW1hLkNPTFVNTlNba10gPT0gJ2ludGVnZXInKSB7XG4gICAgICAgICAgICAgICAgY29uZGl0aW9uLmFkZFN1YkNvbmRpdGlvbihuZXcgVGFibGVTdG9yZS5TaW5nbGVDb2x1bW5Db25kaXRpb24oXG4gICAgICAgICAgICAgICAgICAgIGssIGludDY0KHJvd1trXSBhcyBhbnkpLCBUYWJsZVN0b3JlLkNvbXBhcmF0b3JUeXBlLkVRVUFMKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbmRpdGlvbi5hZGRTdWJDb25kaXRpb24obmV3IFRhYmxlU3RvcmUuU2luZ2xlQ29sdW1uQ29uZGl0aW9uKFxuICAgICAgICAgICAgICAgICAgICBrLCByb3dba10sIFRhYmxlU3RvcmUuQ29tcGFyYXRvclR5cGUuRVFVQUwpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoc3ViX2NvbmRpdGlvbl9jb3VudCA8IDIpIHtcbiAgICAgICAgICAgIC8vIOajgOafpeS4u+mUruafpeivouadoeS7tuiHs+WwkeimgeacieS4gOS4qlxuICAgICAgICAgICAgeGFzc2VydChwYXJhbXMucHJpbWFyeUtleS5sZW5ndGggPj0gMSwgRVJSJFBBUkFNLCB7cm93LCBwYXJhbXN9KVxuICAgICAgICAgICAgLy8g55So5Li76ZSu6KGl5LiK5Lik5Liq5a2Q5p+l6K+i5p2h5Lu2SEFDS+aOieaOpeWPo+WtmOWcqOeahEJVR+i/m+ihjOWFvOWuueaAp+WkhOeQhlxuICAgICAgICAgICAgbGV0IGsgPSBfLmtleXModGhpcy5fc2NoZW1hLktFWVMpWzBdXG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSArIHN1Yl9jb25kaXRpb25fY291bnQgPCAyOyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5fc2NoZW1hLktFWVNba10gPT0gJ2ludGVnZXInKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbmRpdGlvbi5hZGRTdWJDb25kaXRpb24obmV3IFRhYmxlU3RvcmUuU2luZ2xlQ29sdW1uQ29uZGl0aW9uKFxuICAgICAgICAgICAgICAgICAgICAgICAgaywgaW50NjQocm93W2tdIGFzIGFueSksIFRhYmxlU3RvcmUuQ29tcGFyYXRvclR5cGUuRVFVQUwpKVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbmRpdGlvbi5hZGRTdWJDb25kaXRpb24obmV3IFRhYmxlU3RvcmUuU2luZ2xlQ29sdW1uQ29uZGl0aW9uKFxuICAgICAgICAgICAgICAgICAgICAgICAgaywgcm93W2tdLCBUYWJsZVN0b3JlLkNvbXBhcmF0b3JUeXBlLkVRVUFMKSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcGFyYW1zLmNvbHVtbkZpbHRlciA9IGNvbmRpdGlvblxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgX190aGlzX18uX2NsaWVudC5nZXRSb3cocGFyYW1zLCBmdW5jdGlvbiAoZXJyLCBkYXRhKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgICAgICB4dGhyb3cobmV3IEVycm9yKGVyciksIHJlamVjdCwge3BhcmFtcywgZGF0YX0pXG4gICAgICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIOi/lOWbnuaVsOaNruagvOW8j+exu+Wei+i/m+ihjOi9rOaNouWkhOeQhlxuICAgICAgICAgICAgICAgIC8vIHtcImNvbnN1bWVkXCI6e1wiY2FwYWNpdHlfdW5pdFwiOntcInJlYWRcIjoxLFwid3JpdGVcIjowfX0sXG4gICAgICAgICAgICAgICAgLy8gIFwicm93XCI6e1wicHJpbWFyeUtleVwiOlt7XCJuYW1lXCI6XCJnaWRcIixcInZhbHVlXCI6MjAwMTN9LHtcIm5hbWVcIjpcInVpZFwiLFwidmFsdWVcIjoyMDAxM31dLFxuICAgICAgICAgICAgICAgIC8vICAgICAgICAgIFwiYXR0cmlidXRlc1wiOlt7XCJjb2x1bW5OYW1lXCI6XCJjb2wxXCIsXCJjb2x1bW5WYWx1ZVwiOlwi6KGo5qC85a2Y5YKoXCIsXCJ0aW1lc3RhbXBcIjoxNTIwNzM0NTIwMjg2fSxcbiAgICAgICAgICAgICAgICAvLyAgICAgICAgICAgICAgICAgICAgICB7XCJjb2x1bW5OYW1lXCI6XCJjb2wyXCIsXCJjb2x1bW5WYWx1ZVwiOlwiMlwiLFwidGltZXN0YW1wXCI6MTUyMDczNDUyMDA2NH0sXG4gICAgICAgICAgICAgICAgLy8gICAgICAgICAgICAgICAgICAgICB7XCJjb2x1bW5OYW1lXCI6XCJjb2wzXCIsXCJjb2x1bW5WYWx1ZVwiOjMuMSxcInRpbWVzdGFtcFwiOjE1MjA3MzQ1MjAyODZ9LFxuICAgICAgICAgICAgICAgIC8vICAgICAgICAgICAgICAgICAgICAge1wiY29sdW1uTmFtZVwiOlwiY29sNFwiLFwiY29sdW1uVmFsdWVcIjotMC4zMixcInRpbWVzdGFtcFwiOjE1MjA3MzQ1MjAyODZ9LFxuICAgICAgICAgICAgICAgIC8vICAgICAgICAgICAgICAgICAgICAge1wiY29sdW1uTmFtZVwiOlwiY29sNVwiLFwiY29sdW1uVmFsdWVcIjoxMjM0NTY3ODksXCJ0aW1lc3RhbXBcIjoxNTIwNzM0NTIwMjg2fV1cbiAgICAgICAgICAgICAgICAvLyAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAvLyBcIm5leHRfdG9rZW5cIjpudWxsLFwiUmVxdWVzdElkXCI6XCIwMDA1NjcxOS1lMmFkLTczYjEtZGJkOC05NzBhMTk1MjJmNGJcIn1cblxuICAgICAgICAgICAgICAgIC8vIOWwhuaVsOaNrue7k+aenOi/m+ihjOi9rOaNouWkhOeQhuWQiOW5tuS4uuS4gOS4quaZrumAmuWvueixoee7meW6lOeUqOS9v+eUqFxuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBvdXQ6IGFueSA9IHt9XG4gICAgICAgICAgICAgICAgICAgIGlmICghZGF0YS5yb3cpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXNvbHZlKHVuZGVmaW5lZClcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoZGF0YS5yb3cucHJpbWFyeUtleSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgayBpbiBkYXRhLnJvdy5wcmltYXJ5S2V5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHZhbHVlID0gZGF0YS5yb3cucHJpbWFyeUtleVtrXS52YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGludDY06L2s5o2i5Zue5YiwbnVtYmVy55qEamF2YXNjcmlwdOexu+Wei+WkhOeQhlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgYXMgYW55ID09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dFtkYXRhLnJvdy5wcmltYXJ5S2V5W2tdLm5hbWVdID0gdmFsdWUudG9OdW1iZXIoKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dFtkYXRhLnJvdy5wcmltYXJ5S2V5W2tdLm5hbWVdID0gdmFsdWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKGRhdGEucm93LmF0dHJpYnV0ZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAobGV0IGsgaW4gZGF0YS5yb3cuYXR0cmlidXRlcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldCB2YWx1ZSA9IGRhdGEucm93LmF0dHJpYnV0ZXNba10uY29sdW1uVmFsdWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlIGFzIGFueSA9PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRbZGF0YS5yb3cuYXR0cmlidXRlc1trXS5jb2x1bW5OYW1lXSA9IHZhbHVlLnRvTnVtYmVyKClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRbZGF0YS5yb3cuYXR0cmlidXRlc1trXS5jb2x1bW5OYW1lXSA9IHZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmIChfLmtleXMob3V0KS5sZW5ndGggPT0gMCkgb3V0ID0gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUob3V0KVxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgICAgICB4dGhyb3cobmV3IEVycm9yKGVyciksIHJlamVjdCwge3BhcmFtcywgZGF0YX0pXG4gICAgICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgIH0pXG4gICAgfVxuXG4gICAgLy8g6IyD5Zu05p+l6K+i6ZyA6KaB5pWw5o2u6Ieq5Yqo5ZCM5q2l5Yiwb3BlbnNlYXJjaOi/m+ihjOe0ouW8leWQjOatpeWQjui/m+ihjOWQhOenjeWkjeadgueahOafpeivouaTjeS9nOWunueOsOWFjei/kOe7tOezu+e7n+eahOWunueOsFxuICAgIC8vIOWNleihqOmAu+i+keadoeS7tueahOeugOWNlWFuZOS4jmVxdWFs55qE5p+l6K+i77yM6L+U5Zue5ruh6Laz5p2h5Lu255qE56ys5LiA5p2h6K6w5b2VIO+8iOWQiOW5tuS4uuS4gOS4quafpeivouWFvOWuuW1vbmdvZGLnmoTmn6Xor6LmianlsZXvvIlcbiAgICBwdWJsaWMgYXN5bmMgcXVlcnkocm93OiBST1cgfCBSQU5HRSB8IG51bWJlciwgbGltaXQ6IG51bWJlciB8IGJvb2xlYW4gPSAxLCBpc19hc2Nfb3JfZGVzYzogYm9vbGVhbiA9IHRydWUpOiBQcm9taXNlPGFueT4ge1xuICAgICAgICBpZiAoXy5pc0ludGVnZXIocm93KSkge1xuICAgICAgICAgICAgLy8g562J5Lu35LqOcm935Li6bGltaXTov5vooYzlhajooajljYfnuqfpgY3ljobmn6Xor6JcbiAgICAgICAgICAgIGxldCBzaXplID0gcm93XG4gICAgICAgICAgICBsZXQgaXNfYXNjID0gaXNfYXNjX29yX2Rlc2NcbiAgICAgICAgICAgIGlmIChfLmlzQm9vbGVhbihsaW1pdCkpIHtcbiAgICAgICAgICAgICAgICBpc19hc2MgPSBsaW1pdCBhcyBib29sZWFuXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5fcXVlcnlfYnlfcmFuZ2UodW5kZWZpbmVkLCBzaXplIGFzIG51bWJlciwgaXNfYXNjKSAvLyDkuIDkuKrmnaHku7bpg73kuI3ovpPlhaXov5vooYzlhajooajpgY3ljobmn6Xor6JcbiAgICAgICAgfVxuICAgICAgICAvLyDoh7PlsJHovpPlhaXkuIDkuKrmn6Xor6LmnaHku7bnmoTmg4XlhrXlpITnkIZcbiAgICAgICAgeGFzc2VydChfLmlzSW50ZWdlcihsaW1pdCksIEVSUiRQQVJBTSwge3JvdywgbGltaXQsIGlzX2FzY19vcl9kZXNjfSlcbiAgICAgICAgaWYgKGxpbWl0ID09IDEpIHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLl9xdWVyeV9ieV9rZXkocm93IGFzIFJPVylcbiAgICAgICAgICAgIC8vIC8vIEZJWE1FIOinhOmBv09UU+eahOiuvuiuoee8uumZt+WPquaciVpPTkXlkoxJROS4pOS4quS4u+mUrueahOaXtuWAmeaJjeWPr+S7peaMiUtFWeafpeaJvuWNleadoeaVsOaNrlxuICAgICAgICAgICAgLy8gaWYgKF8ua2V5cyh0aGlzLl9zY2hlbWEuS0VZUykubGVuZ3RoID09IDIgJiYgQVVUT19LRVlfTkFNRSBpbiB0aGlzLl9zY2hlbWEuS0VZUykge1xuICAgICAgICAgICAgLy8gICAgIHJvdyA9IHtcbiAgICAgICAgICAgIC8vICAgICAgICAgW1pPTkVfS0VZX05BTUVdOiByb3dbWk9ORV9LRVlfTkFNRV0gPyByb3dbWk9ORV9LRVlfTkFNRV0gOiAnJyxcbiAgICAgICAgICAgIC8vICAgICAgICAgW0FVVE9fS0VZX05BTUVdOiByb3dbQVVUT19LRVlfTkFNRV0sXG4gICAgICAgICAgICAvLyAgICAgfVxuICAgICAgICAgICAgLy8gICAgIHJldHVybiBhd2FpdCB0aGlzLl9xdWVyeV9ieV9rZXkocm93IGFzIFJPVylcbiAgICAgICAgICAgIC8vIH1cbiAgICAgICAgICAgIC8vIC8vIEZJWE1FIOinhOmBv09UU+eahOiuvuiuoee8uumZt+ino+WGs+mAmui/h3Jhbmdl5p+l6K+i5pu/5Luj5Li76ZSu5p+l6K+iXG4gICAgICAgICAgICAvLyBsZXQgb3V0ID0gYXdhaXQgdGhpcy5fcXVlcnlfYnlfcmFuZ2Uocm93IGFzIFJBTkdFLCBsaW1pdCBhcyBudW1iZXIsIGlzX2FzY19vcl9kZXNjKVxuICAgICAgICAgICAgLy8gaWYgKCFvdXQpIHJldHVybiB1bmRlZmluZWRcbiAgICAgICAgICAgIC8vIHJldHVybiBvdXRbMF1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5fcXVlcnlfYnlfcmFuZ2Uocm93IGFzIFJBTkdFLCBsaW1pdCBhcyBudW1iZXIsIGlzX2FzY19vcl9kZXNjKVxuICAgIH1cblxuICAgIC8vIOmUgOavgeihqFxuICAgIHB1YmxpYyBhc3luYyBkZXN0cm95KCkge1xuICAgICAgICBjb25zdCBfX3RoaXNfXyA9IHRoaXNcbiAgICAgICAgY29uc3QgcGFyYW1zID0ge1xuICAgICAgICAgICAgdGFibGVOYW1lOiB0aGlzLl90YWJsZVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICBfX3RoaXNfXy5fY2xpZW50LmRlbGV0ZVRhYmxlKHBhcmFtcywgZnVuY3Rpb24gKGVyciwgZGF0YSkge1xuICAgICAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgeHRocm93KG5ldyBFcnJvcihlcnIpLCByZWplY3QsIHtwYXJhbXN9KVxuICAgICAgICAgICAgICAgICAgICByZXR1cm5cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmVzb2x2ZSgpXG4gICAgICAgICAgICB9KVxuICAgICAgICB9KVxuICAgIH1cblxuICAgIC8vIOWIm+W7uuihqFxuICAgIHB1YmxpYyBhc3luYyBjcmVhdGUoKSB7XG4gICAgICAgIGNvbnN0IF9fdGhpc19fID0gdGhpc1xuICAgICAgICBjb25zdCBwYXJhbXMgPSB7XG4gICAgICAgICAgICB0YWJsZU1ldGE6IHtcbiAgICAgICAgICAgICAgICB0YWJsZU5hbWU6IHRoaXMuX3RhYmxlLFxuICAgICAgICAgICAgICAgIHByaW1hcnlLZXk6IFtdIGFzIGFueVtdLFxuICAgICAgICAgICAgICAgIC8vIHByaW1hcnlLZXk6IFtcbiAgICAgICAgICAgICAgICAvLyAgICAge1xuICAgICAgICAgICAgICAgIC8vICAgICAgICAgbmFtZTogJ3Nob3J0X2lkJyxcbiAgICAgICAgICAgICAgICAvLyAgICAgICAgIHR5cGU6ICdTVFJJTkcnXG4gICAgICAgICAgICAgICAgLy8gICAgIH0sXG4gICAgICAgICAgICAgICAgLy8gICAgIHtcbiAgICAgICAgICAgICAgICAvLyAgICAgICAgIG5hbWU6IEFVVE9fS0VZX05BTUUsXG4gICAgICAgICAgICAgICAgLy8gICAgICAgICB0eXBlOiAnSU5URUdFUicsXG4gICAgICAgICAgICAgICAgLy8gICAgICAgICBvcHRpb246ICdBVVRPX0lOQ1JFTUVOVCcsXG4gICAgICAgICAgICAgICAgLy8gICAgIH1cbiAgICAgICAgICAgICAgICAvLyBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgcmVzZXJ2ZWRUaHJvdWdocHV0OiB7XG4gICAgICAgICAgICAgICAgY2FwYWNpdHlVbml0OiB7XG4gICAgICAgICAgICAgICAgICAgIHJlYWQ6IDAsXG4gICAgICAgICAgICAgICAgICAgIHdyaXRlOiAwXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHRhYmxlT3B0aW9uczoge1xuICAgICAgICAgICAgICAgIHRpbWVUb0xpdmU6IC0xLC8vIOaVsOaNrueahOi/h+acn+aXtumXtCwg5Y2V5L2N56eSLCAtMeS7o+ihqOawuOS4jei/h+acny4g5YGH5aaC6K6+572u6L+H5pyf5pe26Ze05Li65LiA5bm0LCDljbPkuLogMzY1ICogMjQgKiAzNjAwLlxuICAgICAgICAgICAgICAgIG1heFZlcnNpb25zOiAxLy8g5L+d5a2Y55qE5pyA5aSn54mI5pys5pWwLCDorr7nva7kuLox5Y2z5Luj6KGo5q+P5YiX5LiK5pyA5aSa5L+d5a2Y5LiA5Liq54mI5pysKOS/neWtmOacgOaWsOeahOeJiOacrCkuXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8g6Ieq5Yqo6L2s5o2ic2NoZW1h5a6a5LmJ5Li6T1RT55qE5pWw5o2u57uT5p6EXG4gICAgICAgIGZvciAobGV0IGsgaW4gdGhpcy5fc2NoZW1hLktFWVMpIHtcbiAgICAgICAgICAgIGxldCBvYmogPSB7XG4gICAgICAgICAgICAgICAgbmFtZTogayxcbiAgICAgICAgICAgICAgICB0eXBlOiBfLnVwcGVyQ2FzZSh0aGlzLl9zY2hlbWEuS0VZU1trXSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChrID09IEFVVE9fS0VZX05BTUUpIHtcbiAgICAgICAgICAgICAgICBvYmpbJ29wdGlvbiddID0gJ0FVVE9fSU5DUkVNRU5UJ1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcGFyYW1zLnRhYmxlTWV0YS5wcmltYXJ5S2V5LnB1c2gob2JqKVxuICAgICAgICB9XG4gICAgICAgIC8vIGJ1Z2ZpeOino+WGs+esrOS4gOS4quWIhuWMuumUruS4jeiDveS4uuS4u+mUrueahOmXrumimOm7mOiupOihpeS4iuS4gOS4ql9pZOWtl+auteWAvOeahOmXrumimO+8iOWPquWBmuaPkOekuuaaguS4jeino+WGs+e6puWumuS4gOS4ql9pZOWIhuWMuumUruW8uuWItuiuvue9ru+8iVxuICAgICAgICAvLyBcIjQwMDogXFxuXFx1MDAxM09UU1BhcmFtZXRlckludmFsaWRcXHUwMDEyKmZpcnN0IHByaW1hcnkga2V5IGNhbid0IGJlIEFVVE9fSU5DUkVNRU5ULlwiXG5cbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIF9fdGhpc19fLl9jbGllbnQuY3JlYXRlVGFibGUocGFyYW1zLCBmdW5jdGlvbiAoZXJyLCBkYXRhKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgICAgICB4dGhyb3cobmV3IEVycm9yKGVyciksIHJlamVjdCwge3BhcmFtcywgZGF0YX0pXG4gICAgICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXNvbHZlKClcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH0pXG4gICAgfVxuXG4gICAgLy8g6YeN572u6KGoXG4gICAgcHVibGljIGFzeW5jIHJlc2V0KCkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5kZXN0cm95KClcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAvLyBpZ25vcmUgZXJyb3JcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLmNyZWF0ZSgpXG4gICAgfVxufVxuXG4iXX0=