db-migrate-pg-aurora
Version:
A db-migrate driver for postgres aurora serverless.
633 lines • 54.9 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
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 extendStatics(d, b);
};
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) {
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());
});
};
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 });
var AWS = require("aws-sdk");
var Bluebird = require("bluebird");
var semver = require("semver");
// @ts-ignore
var Promise = require("bluebird");
var BaseDriver = require("db-migrate-base");
var AuroraDataApiDriver = /** @class */ (function (_super_1) {
__extends(AuroraDataApiDriver, _super_1);
function AuroraDataApiDriver(internals, rdsParams) {
var _this = _super_1.call(this, internals) || this;
_this.internals = internals;
console.debug("Initializing driver...");
_this._escapeDDL = "\"";
_this._escapeString = "'";
_this.internals.rdsParams = rdsParams;
_this.internals.connection = new AWS.RDSDataService({
apiVersion: "2018-08-01",
region: rdsParams.region,
maxRetries: rdsParams.maxRetries !== undefined ? rdsParams.maxRetries : 3,
httpOptions: {
connectTimeout: rdsParams.connectTimeout !== undefined
? rdsParams.connectTimeout
: 45000,
},
});
_this.internals.notransactions = false;
return _this;
}
AuroraDataApiDriver.prototype.getConnection = function () {
console.debug("Retrieving connection...");
return this.internals.connection;
};
AuroraDataApiDriver.prototype.startMigration = function (cb) {
console.debug("Starting migration...");
if (!this.internals.notransactions) {
return Promise.cast(this.startTransaction).thenReturn().nodeify(cb);
}
};
AuroraDataApiDriver.prototype.startTransaction = function () {
return __awaiter(this, void 0, void 0, function () {
var transactionId;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.debug("Initializing Transaction...");
return [4 /*yield*/, this.internals.connection
.beginTransaction({
resourceArn: this.internals.rdsParams.resourceArn,
secretArn: this.internals.rdsParams.secretArn,
database: this.internals.rdsParams.database,
schema: this.internals.rdsParams.schema,
})
.promise()];
case 1:
transactionId = (_a.sent()).transactionId;
this.internals.currentTransaction = transactionId;
return [2 /*return*/];
}
});
});
};
AuroraDataApiDriver.prototype.endMigration = function (cb) {
console.debug("Finishing migration...");
if (!this.internals.notransactions) {
return Promise.cast(this.commitTransaction).thenReturn().nodeify(cb);
}
};
AuroraDataApiDriver.prototype.commitTransaction = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.debug("Committing Transaction...");
return [4 /*yield*/, this.internals.connection
.commitTransaction({
resourceArn: this.internals.rdsParams.resourceArn,
secretArn: this.internals.rdsParams.secretArn,
transactionId: this.internals.currentTransaction,
})
.promise()];
case 1:
_a.sent();
delete this.internals.currentTransaction;
return [2 /*return*/];
}
});
});
};
AuroraDataApiDriver.prototype.mapDataType = function (str) {
switch (str) {
case "json":
case "jsonb":
return str.toUpperCase();
case "string":
return "TEXT";
case "datetime":
return "TIMESTAMP";
case "blob":
return "BYTEA";
}
return _super_1.prototype.mapDataType.call(this, str);
};
AuroraDataApiDriver.prototype.createColumnDef = function (name, spec, options) {
name = this._escapeDDL + name + this._escapeDDL;
var type = this.mapDataType(spec.type);
var len = spec.length ? "(" + spec.length + ")" : "";
var constraints = this.createColumnConstraint(spec, options).constraints;
return {
constraints: [name, type, len, constraints].join(" "),
};
};
AuroraDataApiDriver.prototype.createColumnConstraint = function (spec, options, tableName, columnName) {
var constraints = [];
var cb;
if (spec.timezone) {
constraints.push("WITH TIME ZONE");
}
if (spec.notNull) {
constraints.push("NOT NULL");
}
if (spec.defaultValue !== undefined) {
constraints.push("DEFAULT");
if (typeof spec.defaultValue === "string") {
constraints.push("'" + spec.defaultValue + "'");
}
else if (typeof spec.defaultValue.prep === "string") {
constraints.push(String(spec.defaultValue.prep));
}
else {
constraints.push(String(spec.defaultValue));
}
}
// keep foreignKey for backward compatible, push to callbacks in the future
if (spec.foreignKey) {
cb = this.bindForeignKey(tableName, columnName, spec.foreignKey);
}
return {
foreignKey: cb,
constraints: String(constraints.join(" ")),
};
};
AuroraDataApiDriver.prototype.renameTable = function (tableName, newTableName) {
var sql = "ALTER TABLE IF EXISTS \"" + tableName + "\" RENAME TO \"" + newTableName + "\"";
return this.runSql(sql);
};
AuroraDataApiDriver.prototype.createDatabase = function (dbName, options) {
var createDBSQL = "CREATE DATABASE \"" + dbName + "\"";
if (options.ifNotExists) {
return this.runSql("CREATE EXTENSION IF NOT EXISTS dblink;\n DO $$\n BEGIN\n PERFORM dblink_exec('', '" + createDBSQL + "');\n EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;\n END\n $$;");
}
else {
return this.runSql(createDBSQL);
}
};
AuroraDataApiDriver.prototype.dropDatabase = function (dbName, options) {
var ifExists = options.ifExists ? "IF EXISTS" : "";
return this.runSql("DROP DATABASE " + ifExists + " \"" + dbName + "\"");
};
AuroraDataApiDriver.prototype.createSequence = function (sqName, options) {
var _a;
var temp = ((_a = options) === null || _a === void 0 ? void 0 : _a.temp) ? "TEMP" : "";
return this.runSql("CREATE " + temp + " SEQUENCE \"" + sqName + "\"");
};
AuroraDataApiDriver.prototype.switchDatabase = function (options) {
if (typeof options === "object" && typeof options.database === "string") {
this.log.info("Ignore database option, not available with postgres. Use schema instead!");
return this.runSql("SET search_path TO \"" + options.database + "\"");
}
else if (typeof options === "string") {
return this.runSql("SET search_path TO \"" + options + "\"");
}
};
AuroraDataApiDriver.prototype.dropSequence = function (dbName, options) {
var ifExists = options.ifExists ? "IF EXISTS" : "";
var rule = options.cascade ? "CASCADE" : options.restrict ? "RESTRICT" : "";
return this.runSql("DROP SEQUENCE " + ifExists + " \"" + dbName + "\" " + rule);
};
AuroraDataApiDriver.prototype.removeColumn = function (tableName, columnName) {
return this.runSql("ALTER TABLE \"" + tableName + "\"\n DROP COLUMN IF EXISTS \"" + columnName + "\"");
};
AuroraDataApiDriver.prototype.createMigrationsTable = function (cb) {
var _this = this;
var options = {
columns: {
id: {
type: "SERIAL",
notNull: true,
primaryKey: true,
},
name: { type: "TEXT", notNull: true },
run_on: { type: "TIMESTAMP", notNull: true },
},
ifNotExists: true,
};
console.debug("Creating migrations table (if necessary)...");
return this.all("show server_version_num")
.then(function (result) {
if (result && result.length > 0 && result[0].server_version_num) {
var version = result[0].server_version_num;
var major = Math.floor(version / 10000);
var minor = Math.floor((version - major * 10000) / 100);
var patch = Math.floor(version - major * 10000 - minor * 100);
version = major + "." + minor + "." + patch;
options.ifNotExists = semver.gte(version, "9.1.0");
}
// Get the current search path so we can change the current schema
// if necessary
return _this.all("SHOW search_path");
})
// not all DBs support server_version_num, fall back to server_version
.catch(function () {
return _this.all("show server_version").then(function (result) {
if (result && result.length > 0 && result[0].server_version) {
var version = result[0].server_version;
// handle versions like “10.2 (Ubuntu 10.2)”
version = version.split(" ")[0];
// handle missing patch numbers
if (version.split(".").length !== 3) {
version += ".0";
}
options.ifNotExists = semver.gte(version, "9.1.0");
// Get the current search path so we can change the current
// schema if necessary
return _this.all("SHOW search_path");
}
});
}).then(function (result) {
var searchPath;
var searchPaths = result[0].search_path.split(",");
for (var i = 0; i < searchPaths.length; ++i) {
if (searchPaths[i].indexOf("\"") !== 0) {
searchPaths[i] = "\"" + searchPaths[i].trim() + "\"";
}
}
result[0].search_path = searchPaths.join(",");
// if the user specified a different schema, prepend it to the search path.
// This will make all DDL/DML/SQL operate on the specified schema.
if (_this.schema === "public") {
searchPath = result[0].search_path;
}
else {
searchPath = "\"" + _this.schema + "\"," + result[0].search_path;
}
return _this.all("SET search_path TO " + searchPath);
}).then(function () {
return _this.all("SELECT table_name FROM information_schema.tables WHERE table_name = '" + _this.internals.migrationTable + "' " + (_this.schema ? " AND table_schema = '${this.schema}'" : ""));
}).then(function (result) {
var _a;
if (((_a = result) === null || _a === void 0 ? void 0 : _a.length) < 1) {
console.debug("Creating migrations table with " + JSON.stringify(options) + "...");
return _this.createTable(_this.internals.migrationTable, options);
}
console.debug("Found existing migrations table, no need to recreate.");
return Promise.resolve();
}).nodeify(cb);
};
AuroraDataApiDriver.prototype.createSeedsTable = function (cb) {
var _this = this;
var options = {
columns: {
id: {
type: "SERIAL",
notNull: true,
primaryKey: true,
},
name: { type: "TEXT", notNull: true },
run_on: { type: "TIMESTAMP", notNull: true },
},
ifNotExists: true,
};
return this.all("select version() as version")
.then(function (result) {
if (result && result.length > 0 && result[0].version) {
var version = result[0].version;
var match = version.match(/\d+\.\d+\.\d+/);
if (match && match[0] && semver.gte(match[0], "9.1.0")) {
options.ifNotExists = true;
}
}
// Get the current search path so we can change the current schema if necessary
return _this.all("SHOW search_path");
}).then(function (result) {
var searchPath;
// if the user specified a different schema, prepend it to the search path.
// This will make all DDL/DML/SQL operate on the specified schema.
if (_this.schema === "public") {
searchPath = result[0].search_path;
}
else {
searchPath = "\"" + _this.schema + "\"," + result[0].search_path;
}
return _this.all("SET search_path TO " + searchPath);
}).then(function () {
return _this.all("SELECT table_name FROM information_schema.tables WHERE table_name = '" + _this.internals.seedTable + "' " + (_this.schema ? " AND table_schema = '${this.schema}'" : ""));
}).then(function (result) {
var _a;
if (((_a = result) === null || _a === void 0 ? void 0 : _a.length) < 1) {
return _this.createTable(_this.internals.seedTable, options);
}
return Promise.resolve();
}).nodeify(cb);
};
AuroraDataApiDriver.prototype.createTable = function (tableName, options) {
var _a;
console.log("creating table: " + tableName);
var columnSpecs = options;
var opts;
if (options.columns !== undefined) {
columnSpecs = options.columns;
opts = options;
}
var ifNotExistsSql = "";
if ((_a = opts) === null || _a === void 0 ? void 0 : _a.ifNotExists) {
ifNotExistsSql = "IF NOT EXISTS";
}
var primaryKeyColumns = [];
var columnDefOptions = {
emitPrimaryKey: false,
};
for (var columnName in columnSpecs) {
var columnSpec = this.normalizeColumnSpec(columnSpecs[columnName]);
columnSpecs[columnName] = columnSpec;
if (columnSpec.primaryKey) {
primaryKeyColumns.push({ spec: columnSpec, name: columnName });
}
}
var pkSql = "";
if (primaryKeyColumns.length > 1) {
pkSql = this._handleMultiPrimaryKeys(primaryKeyColumns);
}
else if (primaryKeyColumns.length === 1) {
primaryKeyColumns[0] = primaryKeyColumns[0].name;
columnDefOptions.emitPrimaryKey = true;
}
var columnDefs = [];
var extensions = "";
var tableOptions = "";
for (var columnName in columnSpecs) {
var columnSpec = columnSpecs[columnName];
this._prepareSpec(columnName, columnSpec, columnDefOptions, tableName);
var constraint = this.createColumnDef(columnName, columnSpec, columnDefOptions);
columnDefs.push(constraint.constraints);
}
var sql = "CREATE TABLE " + ifNotExistsSql + " " + this.escapeDDL(tableName) + " (" + columnDefs.join(", ") + extensions + pkSql + ") " + tableOptions;
return this.runSql(sql);
};
AuroraDataApiDriver.prototype.addIndex = function (tableName, indexName, columns, unique) {
if (!Array.isArray(columns)) {
columns = [columns];
}
var createIndexSQL = "CREATE " + (unique ? "UNIQUE" : "") + " INDEX IF NOT EXISTS \"" + indexName + "\"\n ON \"" + tableName + "\" (" + columns.map(function (column) { return (typeof column === "string" ? column : column.name); }).join(", ") + ");";
return this.runSql(createIndexSQL);
};
AuroraDataApiDriver.prototype.removeIndex = function (tableName, indexName) {
// tableName is optional for other drivers, but required for mySql.
// So, check the args to ensure they are valid
if (!indexName) {
throw new Error("Illegal arguments, must provide \"tableName\" and \"indexName\"");
}
return this.runSql("DROP INDEX IF EXISTS \"" + indexName + "\";");
};
AuroraDataApiDriver.prototype.renameColumn = function (tableName, oldColumnName, newColumnName) {
return __awaiter(this, void 0, Bluebird, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.runSql("ALTER TABLE IF EXISTS \"" + tableName + "\"\n RENAME COLUMN \"" + oldColumnName + "\" TO \"" + newColumnName + "\";")];
});
});
};
AuroraDataApiDriver.prototype.changeColumn = function (tableName, columnName, columnSpec) {
return __awaiter(this, void 0, void 0, function () {
var setOrDrop, sql, sql, using, sql;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(columnSpec.notNull !== undefined)) return [3 /*break*/, 2];
setOrDrop = columnSpec.notNull ? "SET" : "DROP";
return [4 /*yield*/, this.runSql("ALTER TABLE IF EXISTS \"" + tableName + "\"\n ALTER COLUMN \"" + columnName + "\" " + setOrDrop + " NOT NULL")];
case 1:
_a.sent();
_a.label = 2;
case 2:
if (!(columnSpec.unique !== undefined)) return [3 /*break*/, 4];
sql = columnSpec.unique
? "ALTER TABLE \"" + tableName + "\" ADD CONSTRAINT \"" + columnName + "\" UNIQUE (" + columnName + ");"
: "ALTER TABLE \"" + tableName + "\" DROP CONSTRAINT \"" + columnName + "\";";
return [4 /*yield*/, this.runSql(sql)];
case 3:
_a.sent();
_a.label = 4;
case 4:
if (!(columnSpec.defaultValue !== undefined)) return [3 /*break*/, 6];
sql = "ALTER TABLE \"" + tableName + "\"\n ALTER COLUMN \"" + columnName + "\" SET DEFAULT " + (typeof columnSpec.defaultValue === "string"
? "'" + columnSpec.defaultValue + "'"
: columnSpec.defaultValue);
return [4 /*yield*/, this.runSql(sql)];
case 5:
_a.sent();
_a.label = 6;
case 6:
if (!(columnSpec.type !== undefined)) return [3 /*break*/, 8];
using = "USING \"" + columnName + "\"::" + this.mapDataType(columnSpec.type);
sql = "ALTER TABLE \"" + tableName + "\"\nALTER COLUMN \"" + columnName + "\" TYPE " + this.mapDataType(columnSpec.type) + " " + using;
return [4 /*yield*/, this.runSql(sql)];
case 7:
_a.sent();
_a.label = 8;
case 8: return [2 /*return*/];
}
});
});
};
AuroraDataApiDriver.prototype.addPrivateTableData = function (name, tableName, callback) {
return this.runSql("INSERT INTO \"" + tableName + "\" (name, run_on) VALUES (:name, CURRENT_TIMESTAMP);", [{ name: "name", value: { stringValue: name } }]).then(function (result) { return callback(undefined, result); })
.catch(function (err) { return callback(err); });
};
AuroraDataApiDriver.prototype.addMigrationRecord = function (name, callback) {
console.debug("Adding Migration Record: " + name);
return this.addPrivateTableData(name, this.internals.migrationTable, callback);
};
/**
* Deletes a migration
*
* @param migrationName - The name of the migration to be deleted
*/
AuroraDataApiDriver.prototype.deleteMigration = function (migrationName, callback) {
return __awaiter(this, void 0, void 0, function () {
var sql, result, error;
return __generator(this, function (_a) {
sql = "DELETE FROM \"" + this.internals.migrationTable + "\" WHERE NAME = :name";
try {
result = this.runSql(sql, [
{
name: "name",
value: {
stringValue: migrationName,
},
},
]);
}
catch (ex) {
error = ex;
}
if (callback) {
return [2 /*return*/, callback(error, result)];
}
else if (error) {
throw error;
}
return [2 /*return*/, result];
});
});
};
AuroraDataApiDriver.prototype.addSeedRecord = function (name, callback) {
return this.addPrivateTableData(name, this.internals.seedTable, callback);
};
AuroraDataApiDriver.prototype.addForeignKey = function (tableName, referencedTableName, keyName, fieldMapping, rules) {
if (rules === void 0) { rules = {}; }
var columns = Object.keys(fieldMapping);
var referencedColumns = columns.map(function (key) { return fieldMapping[key]; });
var sql = "ALTER TABLE \"" + tableName + "\"\n ADD CONSTRAINT \"" + keyName + "\"\n FOREIGN KEY (" + this.quoteDDLArr(columns) + ")\n REFERENCES \"" + referencedTableName + "\" (" + this.quoteDDLArr(referencedColumns) + ") ON DELETE " + (rules.onDelete || "NO ACTION");
return this.runSql(sql);
};
AuroraDataApiDriver.prototype.removeForeignKey = function (tableName, keyName) {
return __awaiter(this, void 0, Bluebird, function () {
var sql;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
sql = "ALTER TABLE \"" + tableName + "\"\n DROP CONSTRAINT \"" + keyName + "\"";
return [4 /*yield*/, this.runSql(sql)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
AuroraDataApiDriver.prototype.insert = function () {
var index = 1;
if (arguments.length > 3) {
index = 2;
}
arguments[index] = arguments[index].map(function (value) {
return typeof value === "string" ? value : JSON.stringify(value);
});
return this._super.apply(this, arguments);
};
AuroraDataApiDriver.prototype.runSql = function (sql, parameters) {
var _a;
return __awaiter(this, void 0, Bluebird, function () {
var params, exec, result, ex_1;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
this.internals.mod.log.sql.apply(null, [sql, parameters]);
if (this.internals.dryRun) {
return [2 /*return*/, Bluebird.resolve()];
}
if (((_a = parameters) === null || _a === void 0 ? void 0 : _a.length) && sql.indexOf("?") >= 0) {
parameters.forEach(function (value) {
sql = sql.replace("?", ":" + value.name);
});
}
params = {
secretArn: this.internals.rdsParams.secretArn,
resourceArn: this.internals.rdsParams.resourceArn,
database: this.internals.rdsParams.database,
schema: this.internals.rdsParams.schema,
transactionId: this.internals.currentTransaction,
includeResultMetadata: true,
parameters: parameters,
sql: sql,
};
exec = Bluebird.promisify(this.internals.connection.executeStatement).bind(this.internals.connection);
_b.label = 1;
case 1:
_b.trys.push([1, 3, , 4]);
return [4 /*yield*/, exec(params).then(AuroraDataApiDriver.convertResultsToObjects)];
case 2:
result = _b.sent();
return [3 /*break*/, 4];
case 3:
ex_1 = _b.sent();
console.error("Error executing " + sql + ": " + ex_1.message);
throw ex_1;
case 4: return [2 /*return*/, result];
}
});
});
};
AuroraDataApiDriver.convertResultsToObjects = function (data) {
if (!data || !data.records) {
return [];
}
return data.records.map(function (record) {
var result = {};
data.columnMetadata.forEach(function (value, idx) {
result[value.name] =
record[idx].stringValue ||
record[idx].longValue ||
record[idx].doubleValue ||
record[idx].booleanValue ||
record[idx].blobValue;
});
return result;
});
};
// @ts-ignore
AuroraDataApiDriver.prototype.all = function (sql, callback) {
return __awaiter(this, void 0, void 0, function () {
var result, error, ex_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
return [4 /*yield*/, this.runSql(sql)];
case 1:
result = _a.sent();
return [3 /*break*/, 3];
case 2:
ex_2 = _a.sent();
error = ex_2;
return [3 /*break*/, 3];
case 3:
if (callback) {
callback(error, result);
}
if (error) {
throw error;
}
return [2 /*return*/, result];
}
});
});
};
AuroraDataApiDriver.prototype.close = function () {
return Bluebird.resolve();
};
return AuroraDataApiDriver;
}(BaseDriver));
exports.default = AuroraDataApiDriver;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXVyb3JhRGF0YUFwaURyaXZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9BdXJvcmFEYXRhQXBpRHJpdmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDZCQUErQjtBQUUvQixtQ0FBc0M7QUFDdEMsK0JBQWtDO0FBRWxDLGFBQWE7QUFDYixJQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7QUFDcEMsSUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLGlCQUFpQixDQUFDLENBQUM7QUF3QzlDO0lBQWlELHlDQUFVO0lBSXpELDZCQUFvQixTQUEyQixFQUFFLFNBQW9CO1FBQXJFLFlBQ0Usb0JBQU0sU0FBUyxDQUFDLFNBbUJqQjtRQXBCbUIsZUFBUyxHQUFULFNBQVMsQ0FBa0I7UUFHN0MsT0FBTyxDQUFDLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1FBQ3hDLEtBQUksQ0FBQyxVQUFVLEdBQUcsSUFBRyxDQUFDO1FBQ3RCLEtBQUksQ0FBQyxhQUFhLEdBQUcsR0FBRyxDQUFDO1FBRXpCLEtBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztRQUNyQyxLQUFJLENBQUMsU0FBUyxDQUFDLFVBQVUsR0FBRyxJQUFJLEdBQUcsQ0FBQyxjQUFjLENBQUM7WUFDakQsVUFBVSxFQUFFLFlBQVk7WUFDeEIsTUFBTSxFQUFFLFNBQVMsQ0FBQyxNQUFNO1lBQ3hCLFVBQVUsRUFBRSxTQUFTLENBQUMsVUFBVSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUN6RSxXQUFXLEVBQUU7Z0JBQ1gsY0FBYyxFQUNaLFNBQVMsQ0FBQyxjQUFjLEtBQUssU0FBUztvQkFDcEMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxjQUFjO29CQUMxQixDQUFDLENBQUMsS0FBSzthQUNaO1NBQ0YsQ0FBQyxDQUFDO1FBQ0gsS0FBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDOztJQUN4QyxDQUFDO0lBRUQsMkNBQWEsR0FBYjtRQUNFLE9BQU8sQ0FBQyxLQUFLLENBQUMsMEJBQTBCLENBQUMsQ0FBQztRQUMxQyxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDO0lBQ25DLENBQUM7SUFFRCw0Q0FBYyxHQUFkLFVBQWUsRUFBb0I7UUFDakMsT0FBTyxDQUFDLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1FBQ3ZDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRTtZQUNsQyxPQUFPLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUMsVUFBVSxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1NBQ3JFO0lBQ0gsQ0FBQztJQUVLLDhDQUFnQixHQUF0Qjs7Ozs7O3dCQUNFLE9BQU8sQ0FBQyxLQUFLLENBQUMsNkJBQTZCLENBQUMsQ0FBQzt3QkFDbkIscUJBQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxVQUFVO2lDQUN0RCxnQkFBZ0IsQ0FBQztnQ0FDaEIsV0FBVyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLFdBQVc7Z0NBQ2pELFNBQVMsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxTQUFTO2dDQUM3QyxRQUFRLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsUUFBUTtnQ0FDM0MsTUFBTSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLE1BQU07NkJBQ3hDLENBQUM7aUNBQ0QsT0FBTyxFQUFFLEVBQUE7O3dCQVBKLGFBQWEsR0FBSyxDQUFBLFNBT2QsQ0FBQSxjQVBTO3dCQVFyQixJQUFJLENBQUMsU0FBUyxDQUFDLGtCQUFrQixHQUFHLGFBQWEsQ0FBQzs7Ozs7S0FDbkQ7SUFFRCwwQ0FBWSxHQUFaLFVBQWEsRUFBb0I7UUFDL0IsT0FBTyxDQUFDLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1FBQ3hDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRTtZQUNsQyxPQUFPLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUMsVUFBVSxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1NBQ3RFO0lBQ0gsQ0FBQztJQUVLLCtDQUFpQixHQUF2Qjs7Ozs7d0JBQ0UsT0FBTyxDQUFDLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO3dCQUMzQyxxQkFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLFVBQVU7aUNBQzVCLGlCQUFpQixDQUFDO2dDQUNqQixXQUFXLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsV0FBVztnQ0FDakQsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLFNBQVM7Z0NBQzdDLGFBQWEsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLGtCQUFrQjs2QkFDakQsQ0FBQztpQ0FDRCxPQUFPLEVBQUUsRUFBQTs7d0JBTlosU0FNWSxDQUFDO3dCQUNiLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsQ0FBQzs7Ozs7S0FDMUM7SUFFRCx5Q0FBVyxHQUFYLFVBQVksR0FBVztRQUNyQixRQUFRLEdBQUcsRUFBRTtZQUNYLEtBQUssTUFBTSxDQUFDO1lBQ1osS0FBSyxPQUFPO2dCQUNWLE9BQU8sR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQzNCLEtBQUssUUFBUTtnQkFDWCxPQUFPLE1BQU0sQ0FBQztZQUNoQixLQUFLLFVBQVU7Z0JBQ2IsT0FBTyxXQUFXLENBQUM7WUFDckIsS0FBSyxNQUFNO2dCQUNULE9BQU8sT0FBTyxDQUFDO1NBQ2xCO1FBRUQsT0FBTyxtQkFBTSxXQUFXLFlBQUMsR0FBRyxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVELDZDQUFlLEdBQWYsVUFBZ0IsSUFBWSxFQUFFLElBQVMsRUFBRSxPQUFZO1FBQ25ELElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO1FBQ2hELElBQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3pDLElBQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQUksSUFBSSxDQUFDLE1BQU0sTUFBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDbEQsSUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLHNCQUFzQixDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQyxXQUFXLENBQUM7UUFFM0UsT0FBTztZQUNMLFdBQVcsRUFBRSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLFdBQVcsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7U0FDdEQsQ0FBQztJQUNKLENBQUM7SUFFRCxvREFBc0IsR0FBdEIsVUFDRSxJQUFTLEVBQ1QsT0FBYSxFQUNiLFNBQWtCLEVBQ2xCLFVBQW1CO1FBQ25CLElBQU0sV0FBVyxHQUFrQixFQUFFLENBQUM7UUFDdEMsSUFBSSxFQUFFLENBQUM7UUFFUCxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDakIsV0FBVyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1NBQ3BDO1FBRUQsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFO1lBQ2hCLFdBQVcsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7U0FDOUI7UUFFRCxJQUFJLElBQUksQ0FBQyxZQUFZLEtBQUssU0FBUyxFQUFFO1lBQ25DLFdBQVcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDNUIsSUFBSSxPQUFPLElBQUksQ0FBQyxZQUFZLEtBQUssUUFBUSxFQUFFO2dCQUN6QyxXQUFXLENBQUMsSUFBSSxDQUFDLE1BQUksSUFBSSxDQUFDLFlBQVksTUFBRyxDQUFDLENBQUM7YUFDNUM7aUJBQU0sSUFBSSxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRTtnQkFDckQsV0FBVyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO2FBQ2xEO2lCQUFNO2dCQUNMLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDO2FBQzdDO1NBQ0Y7UUFFRCwyRUFBMkU7UUFDM0UsSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFO1lBQ25CLEVBQUUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLFNBQVMsRUFBRSxVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1NBQ2xFO1FBRUQsT0FBTztZQUNMLFVBQVUsRUFBRSxFQUFFO1lBQ2QsV0FBVyxFQUFFLE1BQU0sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQzNDLENBQUM7SUFDSixDQUFDO0lBRUQseUNBQVcsR0FBWCxVQUFZLFNBQWlCLEVBQUUsWUFBb0I7UUFDakQsSUFBTSxHQUFHLEdBQUcsNkJBQTBCLFNBQVMsdUJBQWdCLFlBQVksT0FBRyxDQUFDO1FBQy9FLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBRUQsNENBQWMsR0FBZCxVQUFlLE1BQWMsRUFBRSxPQUFZO1FBQ3pDLElBQU0sV0FBVyxHQUFHLHVCQUFvQixNQUFNLE9BQUcsQ0FBQztRQUNsRCxJQUFJLE9BQU8sQ0FBQyxXQUFXLEVBQUU7WUFDdkIsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLHNHQUdVLFdBQVcsMElBR3RDLENBQUMsQ0FBQztTQUNMO2FBQU07WUFDTCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7U0FDakM7SUFDSCxDQUFDO0lBRUQsMENBQVksR0FBWixVQUFhLE1BQWMsRUFBRSxPQUE4QjtRQUN6RCxJQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUVyRCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsbUJBQWlCLFFBQVEsV0FBSyxNQUFNLE9BQUcsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFRCw0Q0FBYyxHQUFkLFVBQWUsTUFBYyxFQUFFLE9BQWE7O1FBQzFDLElBQU0sSUFBSSxHQUFHLE9BQUEsT0FBTywwQ0FBRSxJQUFJLEVBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBRXpDLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFVLElBQUksb0JBQWMsTUFBTSxPQUFHLENBQUMsQ0FBQztJQUM1RCxDQUFDO0lBRUQsNENBQWMsR0FBZCxVQUFlLE9BQXdDO1FBQ3JELElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxJQUFJLE9BQU8sT0FBTyxDQUFDLFFBQVEsS0FBSyxRQUFRLEVBQUU7WUFDdkUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQ1gsMEVBQTBFLENBQzNFLENBQUM7WUFDRixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsMEJBQXVCLE9BQU8sQ0FBQyxRQUFRLE9BQUcsQ0FBQyxDQUFDO1NBQ2hFO2FBQU0sSUFBSSxPQUFPLE9BQU8sS0FBSyxRQUFRLEVBQUU7WUFDdEMsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLDBCQUF1QixPQUFPLE9BQUcsQ0FBQyxDQUFDO1NBQ3ZEO0lBQ0gsQ0FBQztJQUVELDBDQUFZLEdBQVosVUFBYSxNQUFjLEVBQUUsT0FBWTtRQUN2QyxJQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNyRCxJQUFNLElBQUksR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBRTlFLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxtQkFBaUIsUUFBUSxXQUFLLE1BQU0sV0FBSyxJQUFNLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBRUQsMENBQVksR0FBWixVQUFhLFNBQWlCLEVBQUUsVUFBa0I7UUFDaEQsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLG1CQUFnQixTQUFTLHdDQUNuQixVQUFVLE9BQUcsQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFRCxtREFBcUIsR0FBckIsVUFBc0IsRUFBb0I7UUFBMUMsaUJBK0VDO1FBOUVDLElBQU0sT0FBTyxHQUFHO1lBQ2QsT0FBTyxFQUFFO2dCQUNQLEVBQUUsRUFBRTtvQkFDRixJQUFJLEVBQUUsUUFBUTtvQkFDZCxPQUFPLEVBQUUsSUFBSTtvQkFDYixVQUFVLEVBQUUsSUFBSTtpQkFDakI7Z0JBQ0QsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFO2dCQUNyQyxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUU7YUFDN0M7WUFDRCxXQUFXLEVBQUUsSUFBSTtTQUNsQixDQUFDO1FBRUYsT0FBTyxDQUFDLEtBQUssQ0FBQyw2Q0FBNkMsQ0FBQyxDQUFDO1FBQzdELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsQ0FBQzthQUN2QyxJQUFJLENBQUMsVUFBQyxNQUFXO1lBQ2hCLElBQUksTUFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxrQkFBa0IsRUFBRTtnQkFDL0QsSUFBSSxPQUFPLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLGtCQUFrQixDQUFDO2dCQUMzQyxJQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUMsQ0FBQztnQkFDMUMsSUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLE9BQU8sR0FBRyxLQUFLLEdBQUcsS0FBSyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7Z0JBQzFELElBQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLEtBQUssR0FBRyxLQUFLLEdBQUcsS0FBSyxHQUFHLEdBQUcsQ0FBQyxDQUFDO2dCQUNoRSxPQUFPLEdBQUcsS0FBSyxHQUFHLEdBQUcsR0FBRyxLQUFLLEdBQUcsR0FBRyxHQUFHLEtBQUssQ0FBQztnQkFDNUMsT0FBTyxDQUFDLFdBQVcsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQzthQUNwRDtZQUVELGtFQUFrRTtZQUNsRSxlQUFlO1lBQ2YsT0FBTyxLQUFJLENBQUMsR0FBRyxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDdEMsQ0FBQyxDQUFDO1lBQ0Ysc0VBQXNFO2FBQ3JFLEtBQUssQ0FBQztZQUNMLE9BQU8sS0FBSSxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLElBQUksQ0FDekMsVUFBQyxNQUFXO2dCQUNWLElBQUksTUFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxjQUFjLEVBQUU7b0JBQzNELElBQUksT0FBTyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxjQUFjLENBQUM7b0JBQ3ZDLDRDQUE0QztvQkFDNUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7b0JBQ2hDLCtCQUErQjtvQkFDL0IsSUFBSSxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7d0JBQ25DLE9BQU8sSUFBSSxJQUFJLENBQUM7cUJBQ2pCO29CQUNELE9BQU8sQ0FBQyxXQUFXLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7b0JBQ25ELDJEQUEyRDtvQkFDM0Qsc0JBQXNCO29CQUN0QixPQUFPLEtBQUksQ0FBQyxHQUFHLENBQUMsa0JBQWtCLENBQUMsQ0FBQztpQkFDckM7WUFDSCxDQUFDLENBQ0YsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFDLE1BQVc7WUFDbEIsSUFBSSxVQUFVLENBQUM7WUFDZixJQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUVyRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsV0FBVyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsRUFBRTtnQkFDM0MsSUFBSSxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRTtvQkFDdEMsV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFHLE9BQUksV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxPQUFHLENBQUM7aUJBQy9DO2FBQ0Y7WUFFRCxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7WUFFOUMsMkVBQTJFO1lBQzNFLGtFQUFrRTtZQUNsRSxJQUFJLEtBQUksQ0FBQyxNQUFNLEtBQUssUUFBUSxFQUFFO2dCQUM1QixVQUFVLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQzthQUNwQztpQkFBTTtnQkFDTCxVQUFVLEdBQUcsT0FBSSxLQUFJLENBQUMsTUFBTSxXQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFhLENBQUM7YUFDMUQ7WUFDRCxPQUFPLEtBQUksQ0FBQyxHQUFHLENBQUMscUJBQXFCLEdBQUcsVUFBVSxDQUFDLENBQUM7UUFDdEQsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBQ04sT0FBTyxLQUFJLENBQUMsR0FBRyxDQUFDLDBFQUF3RSxLQUFJLENBQUMsU0FBUyxDQUFDLGNBQWMsV0FBSyxLQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFFLENBQUMsQ0FBQztRQUN6TCxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBQyxNQUFXOztZQUNsQixJQUFJLE9BQUEsTUFBTSwwQ0FBRSxNQUFNLElBQUcsQ0FBQyxFQUFFO2dCQUN0QixPQUFPLENBQUMsS0FBSyxDQUFDLG9DQUFrQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxRQUFLLENBQUMsQ0FBQztnQkFDOUUsT0FBTyxLQUFJLENBQUMsV0FBVyxDQUFDLEtBQUksQ0FBQyxTQUFTLENBQUMsY0FBYyxFQUFFLE9BQU8sQ0FBQyxDQUFDO2FBQ2pFO1lBQ0QsT0FBTyxDQUFDLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO1lBQ3ZFLE9BQU8sT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQzNCLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNuQixDQUFDO0lBRUQsOENBQWdCLEdBQWhCLFVBQWlCLEVBQW9CO1FBQXJDLGlCQThDQztRQTdDQyxJQUFNLE9BQU8sR0FBRztZQUNkLE9BQU8sRUFBRTtnQkFDUCxFQUFFLEVBQUU7b0JBQ0YsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsT0FBTyxFQUFFLElBQUk7b0JBQ2IsVUFBVSxFQUFFLElBQUk7aUJBQ2pCO2dCQUNELElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRTtnQkFDckMsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFO2FBQzdDO1lBQ0QsV0FBVyxFQUFFLElBQUk7U0FDbEIsQ0FBQztRQUVGLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsQ0FBQzthQUMzQyxJQUFJLENBQUMsVUFBQyxNQUFXO1lBQ2hCLElBQUksTUFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUU7Z0JBQ3BELElBQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7Z0JBQ2xDLElBQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLENBQUM7Z0JBQzdDLElBQUksS0FBSyxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsRUFBRTtvQkFDdEQsT0FBTyxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7aUJBQzVCO2FBQ0Y7WUFFRCwrRUFBK0U7WUFDL0UsT0FBTyxLQUFJLENBQUMsR0FBRyxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDdEMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQUMsTUFBVztZQUNsQixJQUFJLFVBQVUsQ0FBQztZQUVmLDJFQUEyRTtZQUMzRSxrRUFBa0U7WUFDbEUsSUFBSSxLQUFJLENBQUMsTUFBTSxLQUFLLFFBQVEsRUFBRTtnQkFDNUIsVUFBVSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUM7YUFDcEM7aUJBQU07Z0JBQ0wsVUFBVSxHQUFHLE9BQUksS0FBSSxDQUFDLE1BQU0sV0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBYSxDQUFDO2FBQzFEO1lBRUQsT0FBTyxLQUFJLENBQUMsR0FBRyxDQUFDLHFCQUFxQixHQUFHLFVBQVUsQ0FBQyxDQUFDO1FBQ3RELENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztZQUNOLE9BQU8sS0FBSSxDQUFDLEdBQUcsQ0FBQywwRUFBd0UsS0FBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLFdBQUssS0FBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsc0NBQXNDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBRSxDQUFDLENBQUM7UUFDcEwsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQUMsTUFBVzs7WUFDbEIsSUFBSSxPQUFBLE1BQU0sMENBQUUsTUFBTSxJQUFHLENBQUMsRUFBRTtnQkFDdEIsT0FBTyxLQUFJLENBQUMsV0FBVyxDQUFDLEtBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO2FBQzVEO1lBQ0QsT0FBTyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDM0IsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ25CLENBQUM7SUFFRCx5Q0FBVyxHQUFYLFVBQVksU0FBaUIsRUFBRSxPQUFZOztRQUN6QyxPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFtQixTQUFXLENBQUMsQ0FBQztRQUM1QyxJQUFJLFdBQVcsR0FBRyxPQUFPLENBQUM7UUFDMUIsSUFBSSxJQUFJLENBQUM7UUFFVCxJQUFJLE9BQU8sQ0FBQyxPQUFPLEtBQUssU0FBUyxFQUFFO1lBQ2pDLFdBQVcsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDO1lBQzlCLElBQUksR0FBRyxPQUFPLENBQUM7U0FDaEI7UUFFRCxJQUFJLGNBQWMsR0FBRyxFQUFFLENBQUM7UUFDeEIsVUFBSSxJQUFJLDBDQUFFLFdBQVcsRUFBRTtZQUNyQixjQUFjLEdBQUcsZUFBZSxDQUFDO1NBQ2xDO1FBRUQsSUFBTSxpQkFBaUIsR0FBRyxFQUFFLENBQUM7UUFDN0IsSUFBTSxnQkFBZ0IsR0FBRztZQUN2QixjQUFjLEVBQUUsS0FBSztTQUN0QixDQUFDO1FBRUYsS0FBSyxJQUFJLFVBQVUsSUFBSSxXQUFXLEVBQUU7WUFDbEMsSUFBSSxVQUFVLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1lBQ25FLFdBQVcsQ0FBQyxVQUFVLENBQUMsR0FBRyxVQUFVLENBQUM7WUFDckMsSUFBSSxVQUFVLENBQUMsVUFBVSxFQUFFO2dCQUN6QixpQkFBaUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDO2FBQ2hFO1NBQ0Y7UUFFRCxJQUFJLEtBQUssR0FBRyxFQUFFLENBQUM7UUFDZixJQUFJLGlCQUFpQixDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDaEMsS0FBSyxHQUFHLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1NBQ3pEO2FBQU0sSUFBSSxpQkFBaUIsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQ3pDLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxHQUFHLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztZQUNqRCxnQkFBZ0IsQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDO1NBQ3hDO1FBRUQsSUFBSSxVQUFVLEdBQUcsRUFBRSxDQUFDO1FBQ3BCLElBQUksVUFBVSxHQUFHLEVBQUUsQ0FBQztRQUNwQixJQUFJLFlBQVksR0FBRyxFQUFFLENBQUM7UUFFdEIsS0FBSyxJQUFJLFVBQVUsSUFBSSxXQUFXLEVBQUU7WUFDbEMsSUFBSSxVQUFVLEdBQUcsV0FBVyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ3pDLElBQUksQ0FBQyxZQUFZLENBQUMsVUFBVSxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxTQUFTLENBQUMsQ0FBQztZQUN2RSxJQUFJLFVBQVUsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUNuQyxVQUFVLEVBQ1YsVUFBVSxFQUNWLGdCQUFnQixDQUNqQixDQUFDO1lBRUYsVUFBVSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7U0FDekM7UUFFRCxJQUFNLEdBQUcsR0FBRyxrQkFBZ0IsY0FBYyxTQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLFVBQUssVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxVQUFVLEdBQUcsS0FBSyxVQUFLLFlBQWMsQ0FBQztRQUMxSSxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQUVELHNDQUFRLEdBQVIsVUFDRSxTQUFpQixFQUNqQixTQUFpQixFQUNqQixPQUE2QyxFQUM3QyxNQUFnQjtRQUVoQixJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRTtZQUMzQixPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztTQUNyQjtRQUVELElBQU0sY0FBYyxHQUFHLGFBQVUsTUFBTSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsZ0NBQXlCLFNBQVMscUJBQ25GLFNBQVMsWUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQUMsTUFBTSxJQUFLLE9BQUEsQ0FBQyxPQUFPLE1BQU0sS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFuRCxDQUFtRCxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFJLENBQUM7UUFDakgsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFRCx5Q0FBVyxHQUFYLFVBQVksU0FBaUIsRUFBRSxTQUFrQjtRQUMvQyxtRUFBbUU7UUFDbkUsOENBQThDO1FBQzlDLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDZCxNQUFNLElBQUksS0FBSyxDQUNiLGlFQUFpRSxDQUNsRSxDQUFDO1NBQ0g7UUFFRCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsNEJBQXlCLFNBQVMsUUFBSSxDQUFDLENBQUM7SUFDN0QsQ0FBQztJQUVLLDBDQUFZLEdBQWxCLFVBQ0UsU0FBaUIsRUFDakIsYUFBcUIsRUFDckIsYUFBcUI7dUNBQ3BCLFFBQVE7O2dCQUNULHNCQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsNkJBQTBCLFNBQVMsZ0NBQ3JDLGFBQWEsZ0JBQVMsYUFBYSxRQUFJLENBQUMsRUFBQzs7O0tBQzNEO0lBRUssMENBQVksR0FBbEIsVUFDRSxTQUFpQixFQUNqQixVQUFrQixFQUNsQixVQUFvQzs7Ozs7OzZCQUVoQyxDQUFBLFVBQVUsQ0FBQyxPQUFPLEtBQUssU0FBUyxDQUFBLEVBQWhDLHdCQUFnQzt3QkFDNUIsU0FBUyxHQUFHLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO3dCQUV0RCxxQkFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLDZCQUEwQixTQUFTLCtCQUN2QyxVQUFVLFdBQUssU0FBUyxjQUFXLENBQUMsRUFBQTs7d0JBRGxELFNBQ2tELENBQUM7Ozs2QkFFakQsQ0FBQSxVQUFVLENBQUMsTUFBTSxLQUFLLFNBQVMsQ0FBQSxFQUEvQix3QkFBK0I7d0JBQzNCLEdBQUcsR0FBRyxVQUFVLENBQUMsTUFBTTs0QkFDM0IsQ0FBQyxDQUFDLG1CQUFnQixTQUFTLDRCQUFxQixVQUFVLG1CQUFhLFVBQVUsT0FBSTs0QkFDckYsQ0FBQyxDQUFDLG1CQUFnQixTQUFTLDZCQUFzQixVQUFVLFFBQUksQ0FBQzt3QkFDbEUscUJBQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBQTs7d0JBQXRCLFNBQXNCLENBQUM7Ozs2QkFFckIsQ0FBQSxVQUFVLENBQUMsWUFBWSxLQUFLLFNBQVMsQ0FBQSxFQUFyQyx3QkFBcUM7d0JBQ2pDLEdBQUcsR0FBRyxtQkFBZ0IsU0FBUywrQkFDdkIsVUFBVSx3QkFBaUIsT0FBTyxVQUFVLENBQUMsWUFBWSxLQUFLLFFBQVE7NEJBQ2xGLENBQUMsQ0FBQyxNQUFJLFVBQVUsQ0FBQyxZQUFZLE1BQUc7NEJBQ2hDLENBQUMsQ0FBQyxVQUFVLENBQUMsWUFBWSxDQUFFLENBQUM7d0JBQzlCLHFCQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUE7O3dCQUF0QixTQUFzQixDQUFDOzs7NkJBRXJCLENBQUEsVUFBVSxDQUFDLElBQUksS0FBSyxTQUFTLENBQUEsRUFBN0Isd0JBQTZCO3dCQUN6QixLQUFLLEdBQUcsYUFBVSxVQUFVLFlBQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFHLENBQUM7d0JBQ3RFLEdBQUcsR0FBRyxtQkFBZ0IsU0FBUywyQkFDM0IsVUFBVSxnQkFBVSxJQUFJLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBSSxLQUFPLENBQUM7d0JBQzNFLHFCQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUE7O3dCQUF0QixTQUFzQixDQUFDOzs7Ozs7S0FFMUI7SUFFUyxpREFBbUIsR0FBN0IsVUFDRSxJQUFZLEVBQ1osU0FBaUIsRUFDakIsUUFBd0M7UUFFeEMsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUNoQixtQkFBZ0IsU0FBUyx5REFBcUQsRUFDOUUsQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUMsQ0FDakQsQ0FBQyxJQUFJLENBQUMsVUFBQyxNQUFXLElBQUssT0FBQSxRQUFRLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxFQUEzQixDQUEyQixDQUFDO2FBQ2pELEtBQUssQ0FBQyxVQUFDLEdBQVEsSUFBSyxPQUFBLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBYixDQUFhLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBRUQsZ0RBQWtCLEdBQWxCLFVBQ0UsSUFBWSxFQUNaLFFBQXdDO1FBRXhDLE9BQU8sQ0FBQyxLQUFLLENBQUMsOEJBQTRCLElBQU0sQ0FBQyxDQUFDO1FBQ2xELE9BQU8sSUFBSSxDQUFDLG1CQUFtQixDQUM3QixJQUFJLEVBQ0osSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQzdCLFFBQVEsQ0FDVCxDQUFDO0lBQ0osQ0FBQztJQUVEOzs7O09BSUc7SUFDRyw2Q0FBZSxHQUFyQixVQUFzQixhQUFxQixFQUFFLFFBQTBCOzs7O2dCQUMvRCxHQUFHLEdBQUcsbUJBQWdCLElBQUksQ0FBQyxTQUFTLENBQUMsY0FBYywyQkFBdUIsQ0FBQztnQkFHakYsS