UNPKG

tedious

Version:

A TDS driver, for connecting to MS SQLServer databases.

416 lines (385 loc) • 43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _events = require("events"); var _writableTrackingBuffer = _interopRequireDefault(require("./tracking-buffer/writable-tracking-buffer")); var _token = require("./token/token"); var _errors = require("./errors"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } /** * @private */ const FLAGS = { nullable: 1 << 0, caseSen: 1 << 1, updateableReadWrite: 1 << 2, updateableUnknown: 1 << 3, identity: 1 << 4, computed: 1 << 5, // introduced in TDS 7.2 fixedLenCLRType: 1 << 8, // introduced in TDS 7.2 sparseColumnSet: 1 << 10, // introduced in TDS 7.3.B hidden: 1 << 13, // introduced in TDS 7.2 key: 1 << 14, // introduced in TDS 7.2 nullableUnknown: 1 << 15 // introduced in TDS 7.2 }; /** * @private */ const DONE_STATUS = { FINAL: 0x00, MORE: 0x1, ERROR: 0x2, INXACT: 0x4, COUNT: 0x10, ATTN: 0x20, SRVERROR: 0x100 }; /** * @private */ /** * A BulkLoad instance is used to perform a bulk insert. * * Use [[Connection.newBulkLoad]] to create a new instance, and [[Connection.execBulkLoad]] to execute it. * * Example of BulkLoad Usages: * * ```js * // optional BulkLoad options * const options = { keepNulls: true }; * * // instantiate - provide the table where you'll be inserting to, options and a callback * const bulkLoad = connection.newBulkLoad('MyTable', options, (error, rowCount) => { * console.log('inserted %d rows', rowCount); * }); * * // setup your columns - always indicate whether the column is nullable * bulkLoad.addColumn('myInt', TYPES.Int, { nullable: false }); * bulkLoad.addColumn('myString', TYPES.NVarChar, { length: 50, nullable: true }); * * // execute * connection.execBulkLoad(bulkLoad, [ * { myInt: 7, myString: 'hello' }, * { myInt: 23, myString: 'world' } * ]); * ``` */ class BulkLoad extends _events.EventEmitter { /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ /** * @private */ constructor(table, collation, connectionOptions, { checkConstraints = false, fireTriggers = false, keepNulls = false, lockTable = false, order = {} }, callback) { if (typeof checkConstraints !== 'boolean') { throw new TypeError('The "options.checkConstraints" property must be of type boolean.'); } if (typeof fireTriggers !== 'boolean') { throw new TypeError('The "options.fireTriggers" property must be of type boolean.'); } if (typeof keepNulls !== 'boolean') { throw new TypeError('The "options.keepNulls" property must be of type boolean.'); } if (typeof lockTable !== 'boolean') { throw new TypeError('The "options.lockTable" property must be of type boolean.'); } if (typeof order !== 'object' || order === null) { throw new TypeError('The "options.order" property must be of type object.'); } for (const [column, direction] of Object.entries(order)) { if (direction !== 'ASC' && direction !== 'DESC') { throw new TypeError('The value of the "' + column + '" key in the "options.order" object must be either "ASC" or "DESC".'); } } super(); this.error = undefined; this.canceled = false; this.executionStarted = false; this.collation = collation; this.table = table; this.options = connectionOptions; this.callback = callback; this.columns = []; this.columnsByName = {}; this.bulkOptions = { checkConstraints, fireTriggers, keepNulls, lockTable, order }; } /** * Adds a column to the bulk load. * * The column definitions should match the table you are trying to insert into. * Attempting to call addColumn after the first row has been added will throw an exception. * * ```js * bulkLoad.addColumn('MyIntColumn', TYPES.Int, { nullable: false }); * ``` * * @param name The name of the column. * @param type One of the supported `data types`. * @param __namedParameters Additional column type information. At a minimum, `nullable` must be set to true or false. * @param length For VarChar, NVarChar, VarBinary. Use length as `Infinity` for VarChar(max), NVarChar(max) and VarBinary(max). * @param nullable Indicates whether the column accepts NULL values. * @param objName If the name of the column is different from the name of the property found on `rowObj` arguments passed to [[addRow]] or [[Connection.execBulkLoad]], then you can use this option to specify the property name. * @param precision For Numeric, Decimal. * @param scale For Numeric, Decimal, Time, DateTime2, DateTimeOffset. */ addColumn(name, type, { output = false, length, precision, scale, objName = name, nullable = true }) { if (this.executionStarted) { throw new Error('Columns cannot be added to bulk insert after execution has started.'); } const column = { type: type, name: name, value: null, output: output, length: length, precision: precision, scale: scale, objName: objName, nullable: nullable, collation: this.collation }; // Note: this is deliberately not keyed off the legacy variable-length // type id bit pattern ((type.id & 0x30) === 0x20), as that pattern does // not hold for type ids introduced in TDS 7.2 and later (e.g. XMLTYPE // 0xF1 or VECTORTYPE 0xF5). A type has a length whenever it can resolve // one, mirroring how precision and scale are resolved below. if (column.length == null && type.resolveLength) { column.length = type.resolveLength(column); } if (type.resolvePrecision && column.precision == null) { column.precision = type.resolvePrecision(column); } if (type.resolveScale && column.scale == null) { column.scale = type.resolveScale(column); } this.columns.push(column); this.columnsByName[name] = column; } /** * @private */ getOptionsSql() { const addOptions = []; if (this.bulkOptions.checkConstraints) { addOptions.push('CHECK_CONSTRAINTS'); } if (this.bulkOptions.fireTriggers) { addOptions.push('FIRE_TRIGGERS'); } if (this.bulkOptions.keepNulls) { addOptions.push('KEEP_NULLS'); } if (this.bulkOptions.lockTable) { addOptions.push('TABLOCK'); } if (this.bulkOptions.order) { const orderColumns = []; for (const [column, direction] of Object.entries(this.bulkOptions.order)) { orderColumns.push(`${column} ${direction}`); } if (orderColumns.length) { addOptions.push(`ORDER (${orderColumns.join(', ')})`); } } if (addOptions.length > 0) { return ` WITH (${addOptions.join(',')})`; } else { return ''; } } /** * @private */ getBulkInsertSql() { let sql = 'insert bulk ' + this.table + '('; for (let i = 0, len = this.columns.length; i < len; i++) { const c = this.columns[i]; if (i !== 0) { sql += ', '; } sql += '[' + c.name + '] ' + c.type.declaration(c); } sql += ')'; sql += this.getOptionsSql(); return sql; } /** * This is simply a helper utility function which returns a `CREATE TABLE SQL` statement based on the columns added to the bulkLoad object. * This may be particularly handy when you want to insert into a temporary table (a table which starts with `#`). * * ```js * var sql = bulkLoad.getTableCreationSql(); * ``` * * A side note on bulk inserting into temporary tables: if you want to access a local temporary table after executing the bulk load, * you'll need to use the same connection and execute your requests using [[Connection.execSqlBatch]] instead of [[Connection.execSql]] */ getTableCreationSql() { let sql = 'CREATE TABLE ' + this.table + '(\n'; for (let i = 0, len = this.columns.length; i < len; i++) { const c = this.columns[i]; if (i !== 0) { sql += ',\n'; } sql += '[' + c.name + '] ' + c.type.declaration(c); if (c.nullable !== undefined) { sql += ' ' + (c.nullable ? 'NULL' : 'NOT NULL'); } } sql += '\n)'; return sql; } /** * @private */ getColMetaData() { const tBuf = new _writableTrackingBuffer.default(); // TokenType tBuf.writeUInt8(_token.TYPE.COLMETADATA); // Count tBuf.writeUInt16LE(this.columns.length); for (let j = 0, len = this.columns.length; j < len; j++) { const c = this.columns[j]; // UserType if (this.options.tdsVersion < '7_2') { tBuf.writeUInt16LE(0); } else { tBuf.writeUInt32LE(0); } // Flags let flags = FLAGS.updateableReadWrite; if (c.nullable) { flags |= FLAGS.nullable; } else if (c.nullable === undefined && this.options.tdsVersion >= '7_2') { flags |= FLAGS.nullableUnknown; } tBuf.writeUInt16LE(flags); // TYPE_INFO try { c.type.writeTypeInfo(tBuf, c, this.options); } catch (error) { throw new _errors.InputError(`Column '${c.name}' could not be serialized`, { cause: error }); } // TableName if (c.type.hasTableName) { tBuf.writeUsVarchar(this.table, 'ucs2'); } // ColName tBuf.writeBVarchar(c.name, 'ucs2'); } return tBuf.data; } /** * Sets a timeout for this bulk load. * * ```js * bulkLoad.setTimeout(timeout); * ``` * * @param timeout The number of milliseconds before the bulk load is considered failed, or 0 for no timeout. * When no timeout is set for the bulk load, the [[ConnectionOptions.requestTimeout]] of the Connection is used. */ setTimeout(timeout) { this.timeout = timeout; } /** * @private */ createDoneToken() { // It might be nice to make DoneToken a class if anything needs to create them, but for now, just do it here const tBuf = new _writableTrackingBuffer.default(); tBuf.writeUInt8(_token.TYPE.DONE); const status = DONE_STATUS.FINAL; tBuf.writeUInt16LE(status); tBuf.writeUInt16LE(0); // CurCmd (TDS ignores this) tBuf.writeUInt32LE(0); // row count - doesn't really matter if (this.options.tdsVersion >= '7_2') { tBuf.writeUInt32LE(0); // row count is 64 bits in >= TDS 7.2 } return tBuf.data; } /** * @private */ cancel() { if (this.canceled) { return; } this.canceled = true; this.emit('cancel'); } } var _default = exports.default = BulkLoad; module.exports = BulkLoad; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZXZlbnRzIiwicmVxdWlyZSIsIl93cml0YWJsZVRyYWNraW5nQnVmZmVyIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsIl90b2tlbiIsIl9lcnJvcnMiLCJlIiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJGTEFHUyIsIm51bGxhYmxlIiwiY2FzZVNlbiIsInVwZGF0ZWFibGVSZWFkV3JpdGUiLCJ1cGRhdGVhYmxlVW5rbm93biIsImlkZW50aXR5IiwiY29tcHV0ZWQiLCJmaXhlZExlbkNMUlR5cGUiLCJzcGFyc2VDb2x1bW5TZXQiLCJoaWRkZW4iLCJrZXkiLCJudWxsYWJsZVVua25vd24iLCJET05FX1NUQVRVUyIsIkZJTkFMIiwiTU9SRSIsIkVSUk9SIiwiSU5YQUNUIiwiQ09VTlQiLCJBVFROIiwiU1JWRVJST1IiLCJCdWxrTG9hZCIsIkV2ZW50RW1pdHRlciIsImNvbnN0cnVjdG9yIiwidGFibGUiLCJjb2xsYXRpb24iLCJjb25uZWN0aW9uT3B0aW9ucyIsImNoZWNrQ29uc3RyYWludHMiLCJmaXJlVHJpZ2dlcnMiLCJrZWVwTnVsbHMiLCJsb2NrVGFibGUiLCJvcmRlciIsImNhbGxiYWNrIiwiVHlwZUVycm9yIiwiY29sdW1uIiwiZGlyZWN0aW9uIiwiT2JqZWN0IiwiZW50cmllcyIsImVycm9yIiwidW5kZWZpbmVkIiwiY2FuY2VsZWQiLCJleGVjdXRpb25TdGFydGVkIiwib3B0aW9ucyIsImNvbHVtbnMiLCJjb2x1bW5zQnlOYW1lIiwiYnVsa09wdGlvbnMiLCJhZGRDb2x1bW4iLCJuYW1lIiwidHlwZSIsIm91dHB1dCIsImxlbmd0aCIsInByZWNpc2lvbiIsInNjYWxlIiwib2JqTmFtZSIsIkVycm9yIiwidmFsdWUiLCJyZXNvbHZlTGVuZ3RoIiwicmVzb2x2ZVByZWNpc2lvbiIsInJlc29sdmVTY2FsZSIsInB1c2giLCJnZXRPcHRpb25zU3FsIiwiYWRkT3B0aW9ucyIsIm9yZGVyQ29sdW1ucyIsImpvaW4iLCJnZXRCdWxrSW5zZXJ0U3FsIiwic3FsIiwiaSIsImxlbiIsImMiLCJkZWNsYXJhdGlvbiIsImdldFRhYmxlQ3JlYXRpb25TcWwiLCJnZXRDb2xNZXRhRGF0YSIsInRCdWYiLCJXcml0YWJsZVRyYWNraW5nQnVmZmVyIiwid3JpdGVVSW50OCIsIlRPS0VOX1RZUEUiLCJDT0xNRVRBREFUQSIsIndyaXRlVUludDE2TEUiLCJqIiwidGRzVmVyc2lvbiIsIndyaXRlVUludDMyTEUiLCJmbGFncyIsIndyaXRlVHlwZUluZm8iLCJJbnB1dEVycm9yIiwiY2F1c2UiLCJoYXNUYWJsZU5hbWUiLCJ3cml0ZVVzVmFyY2hhciIsIndyaXRlQlZhcmNoYXIiLCJkYXRhIiwic2V0VGltZW91dCIsInRpbWVvdXQiLCJjcmVhdGVEb25lVG9rZW4iLCJET05FIiwic3RhdHVzIiwiY2FuY2VsIiwiZW1pdCIsIl9kZWZhdWx0IiwiZXhwb3J0cyIsIm1vZHVsZSJdLCJzb3VyY2VzIjpbIi4uL3NyYy9idWxrLWxvYWQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSAnZXZlbnRzJztcbmltcG9ydCBXcml0YWJsZVRyYWNraW5nQnVmZmVyIGZyb20gJy4vdHJhY2tpbmctYnVmZmVyL3dyaXRhYmxlLXRyYWNraW5nLWJ1ZmZlcic7XG5pbXBvcnQgQ29ubmVjdGlvbiwgeyB0eXBlIEludGVybmFsQ29ubmVjdGlvbk9wdGlvbnMgfSBmcm9tICcuL2Nvbm5lY3Rpb24nO1xuXG5pbXBvcnQgeyBUWVBFIGFzIFRPS0VOX1RZUEUgfSBmcm9tICcuL3Rva2VuL3Rva2VuJztcblxuaW1wb3J0IHsgdHlwZSBEYXRhVHlwZSwgdHlwZSBQYXJhbWV0ZXIgfSBmcm9tICcuL2RhdGEtdHlwZSc7XG5pbXBvcnQgeyBJbnB1dEVycm9yIH0gZnJvbSAnLi9lcnJvcnMnO1xuaW1wb3J0IHsgQ29sbGF0aW9uIH0gZnJvbSAnLi9jb2xsYXRpb24nO1xuXG4vKipcbiAqIEBwcml2YXRlXG4gKi9cbmNvbnN0IEZMQUdTID0ge1xuICBudWxsYWJsZTogMSA8PCAwLFxuICBjYXNlU2VuOiAxIDw8IDEsXG4gIHVwZGF0ZWFibGVSZWFkV3JpdGU6IDEgPDwgMixcbiAgdXBkYXRlYWJsZVVua25vd246IDEgPDwgMyxcbiAgaWRlbnRpdHk6IDEgPDwgNCxcbiAgY29tcHV0ZWQ6IDEgPDwgNSwgLy8gaW50cm9kdWNlZCBpbiBURFMgNy4yXG4gIGZpeGVkTGVuQ0xSVHlwZTogMSA8PCA4LCAvLyBpbnRyb2R1Y2VkIGluIFREUyA3LjJcbiAgc3BhcnNlQ29sdW1uU2V0OiAxIDw8IDEwLCAvLyBpbnRyb2R1Y2VkIGluIFREUyA3LjMuQlxuICBoaWRkZW46IDEgPDwgMTMsIC8vIGludHJvZHVjZWQgaW4gVERTIDcuMlxuICBrZXk6IDEgPDwgMTQsIC8vIGludHJvZHVjZWQgaW4gVERTIDcuMlxuICBudWxsYWJsZVVua25vd246IDEgPDwgMTUgLy8gaW50cm9kdWNlZCBpbiBURFMgNy4yXG59O1xuXG4vKipcbiAqIEBwcml2YXRlXG4gKi9cbmNvbnN0IERPTkVfU1RBVFVTID0ge1xuICBGSU5BTDogMHgwMCxcbiAgTU9SRTogMHgxLFxuICBFUlJPUjogMHgyLFxuICBJTlhBQ1Q6IDB4NCxcbiAgQ09VTlQ6IDB4MTAsXG4gIEFUVE46IDB4MjAsXG4gIFNSVkVSUk9SOiAweDEwMFxufTtcblxuLyoqXG4gKiBAcHJpdmF0ZVxuICovXG5pbnRlcmZhY2UgSW50ZXJuYWxPcHRpb25zIHtcbiAgY2hlY2tDb25zdHJhaW50czogYm9vbGVhbjtcbiAgZmlyZVRyaWdnZXJzOiBib29sZWFuO1xuICBrZWVwTnVsbHM6IGJvb2xlYW47XG4gIGxvY2tUYWJsZTogYm9vbGVhbjtcbiAgb3JkZXI6IHsgW2NvbHVtbk5hbWU6IHN0cmluZ106ICdBU0MnIHwgJ0RFU0MnIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBIb25vcnMgY29uc3RyYWludHMgZHVyaW5nIGJ1bGsgbG9hZCwgdXNpbmcgVC1TUUxcbiAgICogW0NIRUNLX0NPTlNUUkFJTlRTXShodHRwczovL3RlY2huZXQubWljcm9zb2Z0LmNvbS9lbi11cy9saWJyYXJ5L21zMTg2MjQ3KHY9c3FsLjEwNSkuYXNweCkuXG4gICAqIChkZWZhdWx0OiBgZmFsc2VgKVxuICAgKi9cbiAgY2hlY2tDb25zdHJhaW50cz86IEludGVybmFsT3B0aW9uc1snY2hlY2tDb25zdHJhaW50cyddIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBIb25vcnMgaW5zZXJ0IHRyaWdnZXJzIGR1cmluZyBidWxrIGxvYWQsIHVzaW5nIHRoZSBULVNRTCBbRklSRV9UUklHR0VSU10oaHR0cHM6Ly90ZWNobmV0Lm1pY3Jvc29mdC5jb20vZW4tdXMvbGlicmFyeS9tczE4NzY0MCh2PXNxbC4xMDUpLmFzcHgpLiAoZGVmYXVsdDogYGZhbHNlYClcbiAgICovXG4gIGZpcmVUcmlnZ2Vycz86IEludGVybmFsT3B0aW9uc1snZmlyZVRyaWdnZXJzJ10gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEhvbm9ycyBudWxsIHZhbHVlIHBhc3NlZCwgaWdub3JlcyB0aGUgZGVmYXVsdCB2YWx1ZXMgc2V0IG9uIHRhYmxlLCB1c2luZyBULVNRTCBbS0VFUF9OVUxMU10oaHR0cHM6Ly9tc2RuLm1pY3Jvc29mdC5jb20vZW4tdXMvbGlicmFyeS9tczE4Nzg4Nyh2PXNxbC4xMjApLmFzcHgpLiAoZGVmYXVsdDogYGZhbHNlYClcbiAgICovXG4gIGtlZXBOdWxscz86IEludGVybmFsT3B0aW9uc1sna2VlcE51bGxzJ10gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIFBsYWNlcyBhIGJ1bGsgdXBkYXRlKEJVKSBsb2NrIG9uIHRhYmxlIHdoaWxlIHBlcmZvcm1pbmcgYnVsayBsb2FkLCB1c2luZyBULVNRTCBbVEFCTE9DS10oaHR0cHM6Ly90ZWNobmV0Lm1pY3Jvc29mdC5jb20vZW4tdXMvbGlicmFyeS9tczE4MDg3Nih2PXNxbC4xMDUpLmFzcHgpLiAoZGVmYXVsdDogYGZhbHNlYClcbiAgICovXG4gIGxvY2tUYWJsZT86IEludGVybmFsT3B0aW9uc1snbG9ja1RhYmxlJ10gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIFNwZWNpZmllcyB0aGUgb3JkZXJpbmcgb2YgdGhlIGRhdGEgdG8gcG9zc2libHkgaW5jcmVhc2UgYnVsayBpbnNlcnQgcGVyZm9ybWFuY2UsIHVzaW5nIFQtU1FMIFtPUkRFUl0oaHR0cHM6Ly9kb2NzLm1pY3Jvc29mdC5jb20vZW4tdXMvcHJldmlvdXMtdmVyc2lvbnMvc3FsL3NxbC1zZXJ2ZXItMjAwOC1yMi9tczE3NzQ2OCh2PXNxbC4xMDUpKS4gKGRlZmF1bHQ6IGB7fWApXG4gICAqL1xuICBvcmRlcj86IEludGVybmFsT3B0aW9uc1snb3JkZXInXSB8IHVuZGVmaW5lZDtcbn1cblxuXG5leHBvcnQgdHlwZSBDYWxsYmFjayA9XG4gIC8qKlxuICAgKiBBIGZ1bmN0aW9uIHdoaWNoIHdpbGwgYmUgY2FsbGVkIGFmdGVyIHRoZSBbW0J1bGtMb2FkXV0gZmluaXNoZXMgZXhlY3V0aW5nLlxuICAgKlxuICAgKiBAcGFyYW0gcm93Q291bnQgdGhlIG51bWJlciBvZiByb3dzIGluc2VydGVkXG4gICAqL1xuICAoZXJyOiBFcnJvciB8IHVuZGVmaW5lZCB8IG51bGwsIHJvd0NvdW50PzogbnVtYmVyKSA9PiB2b2lkO1xuXG5pbnRlcmZhY2UgQ29sdW1uIGV4dGVuZHMgUGFyYW1ldGVyIHtcbiAgb2JqTmFtZTogc3RyaW5nO1xuICBjb2xsYXRpb246IENvbGxhdGlvbiB8IHVuZGVmaW5lZDtcbn1cblxuaW50ZXJmYWNlIENvbHVtbk9wdGlvbnMge1xuICBvdXRwdXQ/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBGb3IgVmFyQ2hhciwgTlZhckNoYXIsIFZhckJpbmFyeS4gVXNlIGxlbmd0aCBhcyBgSW5maW5pdHlgIGZvciBWYXJDaGFyKG1heCksIE5WYXJDaGFyKG1heCkgYW5kIFZhckJpbmFyeShtYXgpLlxuICAgKi9cbiAgbGVuZ3RoPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBGb3IgTnVtZXJpYywgRGVjaW1hbC5cbiAgICovXG4gIHByZWNpc2lvbj86IG51bWJlcjtcblxuICAvKipcbiAgICogRm9yIE51bWVyaWMsIERlY2ltYWwsIFRpbWUsIERhdGVUaW1lMiwgRGF0ZVRpbWVPZmZzZXQuXG4gICAqL1xuICBzY2FsZT86IG51bWJlcjtcblxuICAvKipcbiAgICogSWYgdGhlIG5hbWUgb2YgdGhlIGNvbHVtbiBpcyBkaWZmZXJlbnQgZnJvbSB0aGUgbmFtZSBvZiB0aGUgcHJvcGVydHkgZm91bmQgb24gYHJvd09iamAgYXJndW1lbnRzIHBhc3NlZCB0byBbW2FkZFJvd11dLCB0aGVuIHlvdSBjYW4gdXNlIHRoaXMgb3B0aW9uIHRvIHNwZWNpZnkgdGhlIHByb3BlcnR5IG5hbWUuXG4gICAqL1xuICBvYmpOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgd2hldGhlciB0aGUgY29sdW1uIGFjY2VwdHMgTlVMTCB2YWx1ZXMuXG4gICAqL1xuICBudWxsYWJsZT86IGJvb2xlYW47XG59XG5cbi8qKlxuICogQSBCdWxrTG9hZCBpbnN0YW5jZSBpcyB1c2VkIHRvIHBlcmZvcm0gYSBidWxrIGluc2VydC5cbiAqXG4gKiBVc2UgW1tDb25uZWN0aW9uLm5ld0J1bGtMb2FkXV0gdG8gY3JlYXRlIGEgbmV3IGluc3RhbmNlLCBhbmQgW1tDb25uZWN0aW9uLmV4ZWNCdWxrTG9hZF1dIHRvIGV4ZWN1dGUgaXQuXG4gKlxuICogRXhhbXBsZSBvZiBCdWxrTG9hZCBVc2FnZXM6XG4gKlxuICogYGBganNcbiAqIC8vIG9wdGlvbmFsIEJ1bGtMb2FkIG9wdGlvbnNcbiAqIGNvbnN0IG9wdGlvbnMgPSB7IGtlZXBOdWxsczogdHJ1ZSB9O1xuICpcbiAqIC8vIGluc3RhbnRpYXRlIC0gcHJvdmlkZSB0aGUgdGFibGUgd2hlcmUgeW91J2xsIGJlIGluc2VydGluZyB0bywgb3B0aW9ucyBhbmQgYSBjYWxsYmFja1xuICogY29uc3QgYnVsa0xvYWQgPSBjb25uZWN0aW9uLm5ld0J1bGtMb2FkKCdNeVRhYmxlJywgb3B0aW9ucywgKGVycm9yLCByb3dDb3VudCkgPT4ge1xuICogICBjb25zb2xlLmxvZygnaW5zZXJ0ZWQgJWQgcm93cycsIHJvd0NvdW50KTtcbiAqIH0pO1xuICpcbiAqIC8vIHNldHVwIHlvdXIgY29sdW1ucyAtIGFsd2F5cyBpbmRpY2F0ZSB3aGV0aGVyIHRoZSBjb2x1bW4gaXMgbnVsbGFibGVcbiAqIGJ1bGtMb2FkLmFkZENvbHVtbignbXlJbnQnLCBUWVBFUy5JbnQsIHsgbnVsbGFibGU6IGZhbHNlIH0pO1xuICogYnVsa0xvYWQuYWRkQ29sdW1uKCdteVN0cmluZycsIFRZUEVTLk5WYXJDaGFyLCB7IGxlbmd0aDogNTAsIG51bGxhYmxlOiB0cnVlIH0pO1xuICpcbiAqIC8vIGV4ZWN1dGVcbiAqIGNvbm5lY3Rpb24uZXhlY0J1bGtMb2FkKGJ1bGtMb2FkLCBbXG4gKiAgIHsgbXlJbnQ6IDcsIG15U3RyaW5nOiAnaGVsbG8nIH0sXG4gKiAgIHsgbXlJbnQ6IDIzLCBteVN0cmluZzogJ3dvcmxkJyB9XG4gKiBdKTtcbiAqIGBgYFxuICovXG5jbGFzcyBCdWxrTG9hZCBleHRlbmRzIEV2ZW50RW1pdHRlciB7XG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgZGVjbGFyZSBlcnJvcjogRXJyb3IgfCB1bmRlZmluZWQ7XG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgZGVjbGFyZSBjYW5jZWxlZDogYm9vbGVhbjtcbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBkZWNsYXJlIGV4ZWN1dGlvblN0YXJ0ZWQ6IGJvb2xlYW47XG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBkZWNsYXJlIHRhYmxlOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgZGVjbGFyZSB0aW1lb3V0OiBudW1iZXIgfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBkZWNsYXJlIG9wdGlvbnM6IEludGVybmFsQ29ubmVjdGlvbk9wdGlvbnM7XG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgZGVjbGFyZSBjYWxsYmFjazogQ2FsbGJhY2s7XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBkZWNsYXJlIGNvbHVtbnM6IEFycmF5PENvbHVtbj47XG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgZGVjbGFyZSBjb2x1bW5zQnlOYW1lOiB7IFtuYW1lOiBzdHJpbmddOiBDb2x1bW4gfTtcblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIGRlY2xhcmUgYnVsa09wdGlvbnM6IEludGVybmFsT3B0aW9ucztcblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIGRlY2xhcmUgY29ubmVjdGlvbjogQ29ubmVjdGlvbiB8IHVuZGVmaW5lZDtcbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBkZWNsYXJlIHJvd3M6IEFycmF5PGFueT4gfCB1bmRlZmluZWQ7XG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgZGVjbGFyZSByc3Q6IEFycmF5PGFueT4gfCB1bmRlZmluZWQ7XG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgZGVjbGFyZSByb3dDb3VudDogbnVtYmVyIHwgdW5kZWZpbmVkO1xuXG4gIGRlY2xhcmUgY29sbGF0aW9uOiBDb2xsYXRpb24gfCB1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih0YWJsZTogc3RyaW5nLCBjb2xsYXRpb246IENvbGxhdGlvbiB8IHVuZGVmaW5lZCwgY29ubmVjdGlvbk9wdGlvbnM6IEludGVybmFsQ29ubmVjdGlvbk9wdGlvbnMsIHtcbiAgICBjaGVja0NvbnN0cmFpbnRzID0gZmFsc2UsXG4gICAgZmlyZVRyaWdnZXJzID0gZmFsc2UsXG4gICAga2VlcE51bGxzID0gZmFsc2UsXG4gICAgbG9ja1RhYmxlID0gZmFsc2UsXG4gICAgb3JkZXIgPSB7fSxcbiAgfTogT3B0aW9ucywgY2FsbGJhY2s6IENhbGxiYWNrKSB7XG4gICAgaWYgKHR5cGVvZiBjaGVja0NvbnN0cmFpbnRzICE9PSAnYm9vbGVhbicpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1RoZSBcIm9wdGlvbnMuY2hlY2tDb25zdHJhaW50c1wiIHByb3BlcnR5IG11c3QgYmUgb2YgdHlwZSBib29sZWFuLicpO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgZmlyZVRyaWdnZXJzICE9PSAnYm9vbGVhbicpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1RoZSBcIm9wdGlvbnMuZmlyZVRyaWdnZXJzXCIgcHJvcGVydHkgbXVzdCBiZSBvZiB0eXBlIGJvb2xlYW4uJyk7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBrZWVwTnVsbHMgIT09ICdib29sZWFuJykge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVGhlIFwib3B0aW9ucy5rZWVwTnVsbHNcIiBwcm9wZXJ0eSBtdXN0IGJlIG9mIHR5cGUgYm9vbGVhbi4nKTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGxvY2tUYWJsZSAhPT0gJ2Jvb2xlYW4nKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdUaGUgXCJvcHRpb25zLmxvY2tUYWJsZVwiIHByb3BlcnR5IG11c3QgYmUgb2YgdHlwZSBib29sZWFuLicpO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2Ygb3JkZXIgIT09ICdvYmplY3QnIHx8IG9yZGVyID09PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdUaGUgXCJvcHRpb25zLm9yZGVyXCIgcHJvcGVydHkgbXVzdCBiZSBvZiB0eXBlIG9iamVjdC4nKTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFtjb2x1bW4sIGRpcmVjdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMob3JkZXIpKSB7XG4gICAgICBpZiAoZGlyZWN0aW9uICE9PSAnQVNDJyAmJiBkaXJlY3Rpb24gIT09ICdERVNDJykge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdUaGUgdmFsdWUgb2YgdGhlIFwiJyArIGNvbHVtbiArICdcIiBrZXkgaW4gdGhlIFwib3B0aW9ucy5vcmRlclwiIG9iamVjdCBtdXN0IGJlIGVpdGhlciBcIkFTQ1wiIG9yIFwiREVTQ1wiLicpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHN1cGVyKCk7XG5cbiAgICB0aGlzLmVycm9yID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuY2FuY2VsZWQgPSBmYWxzZTtcbiAgICB0aGlzLmV4ZWN1dGlvblN0YXJ0ZWQgPSBmYWxzZTtcblxuICAgIHRoaXMuY29sbGF0aW9uID0gY29sbGF0aW9uO1xuXG4gICAgdGhpcy50YWJsZSA9IHRhYmxlO1xuICAgIHRoaXMub3B0aW9ucyA9IGNvbm5lY3Rpb25PcHRpb25zO1xuICAgIHRoaXMuY2FsbGJhY2sgPSBjYWxsYmFjaztcbiAgICB0aGlzLmNvbHVtbnMgPSBbXTtcbiAgICB0aGlzLmNvbHVtbnNCeU5hbWUgPSB7fTtcblxuICAgIHRoaXMuYnVsa09wdGlvbnMgPSB7IGNoZWNrQ29uc3RyYWludHMsIGZpcmVUcmlnZ2Vycywga2VlcE51bGxzLCBsb2NrVGFibGUsIG9yZGVyIH07XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIGNvbHVtbiB0byB0aGUgYnVsayBsb2FkLlxuICAgKlxuICAgKiBUaGUgY29sdW1uIGRlZmluaXRpb25zIHNob3VsZCBtYXRjaCB0aGUgdGFibGUgeW91IGFyZSB0cnlpbmcgdG8gaW5zZXJ0IGludG8uXG4gICAqIEF0dGVtcHRpbmcgdG8gY2FsbCBhZGRDb2x1bW4gYWZ0ZXIgdGhlIGZpcnN0IHJvdyBoYXMgYmVlbiBhZGRlZCB3aWxsIHRocm93IGFuIGV4Y2VwdGlvbi5cbiAgICpcbiAgICogYGBganNcbiAgICogYnVsa0xvYWQuYWRkQ29sdW1uKCdNeUludENvbHVtbicsIFRZUEVTLkludCwgeyBudWxsYWJsZTogZmFsc2UgfSk7XG4gICAqIGBgYFxuICAgKlxuICAgKiBAcGFyYW0gbmFtZSBUaGUgbmFtZSBvZiB0aGUgY29sdW1uLlxuICAgKiBAcGFyYW0gdHlwZSBPbmUgb2YgdGhlIHN1cHBvcnRlZCBgZGF0YSB0eXBlc2AuXG4gICAqIEBwYXJhbSBfX25hbWVkUGFyYW1ldGVycyBBZGRpdGlvbmFsIGNvbHVtbiB0eXBlIGluZm9ybWF0aW9uLiBBdCBhIG1pbmltdW0sIGBudWxsYWJsZWAgbXVzdCBiZSBzZXQgdG8gdHJ1ZSBvciBmYWxzZS5cbiAgICogQHBhcmFtIGxlbmd0aCBGb3IgVmFyQ2hhciwgTlZhckNoYXIsIFZhckJpbmFyeS4gVXNlIGxlbmd0aCBhcyBgSW5maW5pdHlgIGZvciBWYXJDaGFyKG1heCksIE5WYXJDaGFyKG1heCkgYW5kIFZhckJpbmFyeShtYXgpLlxuICAgKiBAcGFyYW0gbnVsbGFibGUgSW5kaWNhdGVzIHdoZXRoZXIgdGhlIGNvbHVtbiBhY2NlcHRzIE5VTEwgdmFsdWVzLlxuICAgKiBAcGFyYW0gb2JqTmFtZSBJZiB0aGUgbmFtZSBvZiB0aGUgY29sdW1uIGlzIGRpZmZlcmVudCBmcm9tIHRoZSBuYW1lIG9mIHRoZSBwcm9wZXJ0eSBmb3VuZCBvbiBgcm93T2JqYCBhcmd1bWVudHMgcGFzc2VkIHRvIFtbYWRkUm93XV0gb3IgW1tDb25uZWN0aW9uLmV4ZWNCdWxrTG9hZF1dLCB0aGVuIHlvdSBjYW4gdXNlIHRoaXMgb3B0aW9uIHRvIHNwZWNpZnkgdGhlIHByb3BlcnR5IG5hbWUuXG4gICAqIEBwYXJhbSBwcmVjaXNpb24gRm9yIE51bWVyaWMsIERlY2ltYWwuXG4gICAqIEBwYXJhbSBzY2FsZSBGb3IgTnVtZXJpYywgRGVjaW1hbCwgVGltZSwgRGF0ZVRpbWUyLCBEYXRlVGltZU9mZnNldC5cbiAgKi9cbiAgYWRkQ29sdW1uKG5hbWU6IHN0cmluZywgdHlwZTogRGF0YVR5cGUsIHsgb3V0cHV0ID0gZmFsc2UsIGxlbmd0aCwgcHJlY2lzaW9uLCBzY2FsZSwgb2JqTmFtZSA9IG5hbWUsIG51bGxhYmxlID0gdHJ1ZSB9OiBDb2x1bW5PcHRpb25zKSB7XG4gICAgaWYgKHRoaXMuZXhlY3V0aW9uU3RhcnRlZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb2x1bW5zIGNhbm5vdCBiZSBhZGRlZCB0byBidWxrIGluc2VydCBhZnRlciBleGVjdXRpb24gaGFzIHN0YXJ0ZWQuJyk7XG4gICAgfVxuXG4gICAgY29uc3QgY29sdW1uOiBDb2x1bW4gPSB7XG4gICAgICB0eXBlOiB0eXBlLFxuICAgICAgbmFtZTogbmFtZSxcbiAgICAgIHZhbHVlOiBudWxsLFxuICAgICAgb3V0cHV0OiBvdXRwdXQsXG4gICAgICBsZW5ndGg6IGxlbmd0aCxcbiAgICAgIHByZWNpc2lvbjogcHJlY2lzaW9uLFxuICAgICAgc2NhbGU6IHNjYWxlLFxuICAgICAgb2JqTmFtZTogb2JqTmFtZSxcbiAgICAgIG51bGxhYmxlOiBudWxsYWJsZSxcbiAgICAgIGNvbGxhdGlvbjogdGhpcy5jb2xsYXRpb25cbiAgICB9O1xuXG4gICAgLy8gTm90ZTogdGhpcyBpcyBkZWxpYmVyYXRlbHkgbm90IGtleWVkIG9mZiB0aGUgbGVnYWN5IHZhcmlhYmxlLWxlbmd0aFxuICAgIC8vIHR5cGUgaWQgYml0IHBhdHRlcm4gKCh0eXBlLmlkICYgMHgzMCkgPT09IDB4MjApLCBhcyB0aGF0IHBhdHRlcm4gZG9lc1xuICAgIC8vIG5vdCBob2xkIGZvciB0eXBlIGlkcyBpbnRyb2R1Y2VkIGluIFREUyA3LjIgYW5kIGxhdGVyIChlLmcuIFhNTFRZUEVcbiAgICAvLyAweEYxIG9yIFZFQ1RPUlRZUEUgMHhGNSkuIEEgdHlwZSBoYXMgYSBsZW5ndGggd2hlbmV2ZXIgaXQgY2FuIHJlc29sdmVcbiAgICAvLyBvbmUsIG1pcnJvcmluZyBob3cgcHJlY2lzaW9uIGFuZCBzY2FsZSBhcmUgcmVzb2x2ZWQgYmVsb3cuXG4gICAgaWYgKGNvbHVtbi5sZW5ndGggPT0gbnVsbCAmJiB0eXBlLnJlc29sdmVMZW5ndGgpIHtcbiAgICAgIGNvbHVtbi5sZW5ndGggPSB0eXBlLnJlc29sdmVMZW5ndGgoY29sdW1uKTtcbiAgICB9XG5cbiAgICBpZiAodHlwZS5yZXNvbHZlUHJlY2lzaW9uICYmIGNvbHVtbi5wcmVjaXNpb24gPT0gbnVsbCkge1xuICAgICAgY29sdW1uLnByZWNpc2lvbiA9IHR5cGUucmVzb2x2ZVByZWNpc2lvbihjb2x1bW4pO1xuICAgIH1cblxuICAgIGlmICh0eXBlLnJlc29sdmVTY2FsZSAmJiBjb2x1bW4uc2NhbGUgPT0gbnVsbCkge1xuICAgICAgY29sdW1uLnNjYWxlID0gdHlwZS5yZXNvbHZlU2NhbGUoY29sdW1uKTtcbiAgICB9XG5cbiAgICB0aGlzLmNvbHVtbnMucHVzaChjb2x1bW4pO1xuXG4gICAgdGhpcy5jb2x1bW5zQnlOYW1lW25hbWVdID0gY29sdW1uO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBnZXRPcHRpb25zU3FsKCkge1xuICAgIGNvbnN0IGFkZE9wdGlvbnMgPSBbXTtcblxuICAgIGlmICh0aGlzLmJ1bGtPcHRpb25zLmNoZWNrQ29uc3RyYWludHMpIHtcbiAgICAgIGFkZE9wdGlvbnMucHVzaCgnQ0hFQ0tfQ09OU1RSQUlOVFMnKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5idWxrT3B0aW9ucy5maXJlVHJpZ2dlcnMpIHtcbiAgICAgIGFkZE9wdGlvbnMucHVzaCgnRklSRV9UUklHR0VSUycpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmJ1bGtPcHRpb25zLmtlZXBOdWxscykge1xuICAgICAgYWRkT3B0aW9ucy5wdXNoKCdLRUVQX05VTExTJyk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuYnVsa09wdGlvbnMubG9ja1RhYmxlKSB7XG4gICAgICBhZGRPcHRpb25zLnB1c2goJ1RBQkxPQ0snKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5idWxrT3B0aW9ucy5vcmRlcikge1xuICAgICAgY29uc3Qgb3JkZXJDb2x1bW5zID0gW107XG5cbiAgICAgIGZvciAoY29uc3QgW2NvbHVtbiwgZGlyZWN0aW9uXSBvZiBPYmplY3QuZW50cmllcyh0aGlzLmJ1bGtPcHRpb25zLm9yZGVyKSkge1xuICAgICAgICBvcmRlckNvbHVtbnMucHVzaChgJHtjb2x1bW59ICR7ZGlyZWN0aW9ufWApO1xuICAgICAgfVxuXG4gICAgICBpZiAob3JkZXJDb2x1bW5zLmxlbmd0aCkge1xuICAgICAgICBhZGRPcHRpb25zLnB1c2goYE9SREVSICgke29yZGVyQ29sdW1ucy5qb2luKCcsICcpfSlgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoYWRkT3B0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICByZXR1cm4gYCBXSVRIICgke2FkZE9wdGlvbnMuam9pbignLCcpfSlgO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBnZXRCdWxrSW5zZXJ0U3FsKCkge1xuICAgIGxldCBzcWwgPSAnaW5zZXJ0IGJ1bGsgJyArIHRoaXMudGFibGUgKyAnKCc7XG4gICAgZm9yIChsZXQgaSA9IDAsIGxlbiA9IHRoaXMuY29sdW1ucy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgICAgY29uc3QgYyA9IHRoaXMuY29sdW1uc1tpXTtcbiAgICAgIGlmIChpICE9PSAwKSB7XG4gICAgICAgIHNxbCArPSAnLCAnO1xuICAgICAgfVxuICAgICAgc3FsICs9ICdbJyArIGMubmFtZSArICddICcgKyAoYy50eXBlLmRlY2xhcmF0aW9uKGMpKTtcbiAgICB9XG4gICAgc3FsICs9ICcpJztcblxuICAgIHNxbCArPSB0aGlzLmdldE9wdGlvbnNTcWwoKTtcbiAgICByZXR1cm4gc3FsO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoaXMgaXMgc2ltcGx5IGEgaGVscGVyIHV0aWxpdHkgZnVuY3Rpb24gd2hpY2ggcmV0dXJucyBhIGBDUkVBVEUgVEFCTEUgU1FMYCBzdGF0ZW1lbnQgYmFzZWQgb24gdGhlIGNvbHVtbnMgYWRkZWQgdG8gdGhlIGJ1bGtMb2FkIG9iamVjdC5cbiAgICogVGhpcyBtYXkgYmUgcGFydGljdWxhcmx5IGhhbmR5IHdoZW4geW91IHdhbnQgdG8gaW5zZXJ0IGludG8gYSB0ZW1wb3JhcnkgdGFibGUgKGEgdGFibGUgd2hpY2ggc3RhcnRzIHdpdGggYCNgKS5cbiAgICpcbiAgICogYGBganNcbiAgICogdmFyIHNxbCA9IGJ1bGtMb2FkLmdldFRhYmxlQ3JlYXRpb25TcWwoKTtcbiAgICogYGBgXG4gICAqXG4gICAqIEEgc2lkZSBub3RlIG9uIGJ1bGsgaW5zZXJ0aW5nIGludG8gdGVtcG9yYXJ5IHRhYmxlczogaWYgeW91IHdhbnQgdG8gYWNjZXNzIGEgbG9jYWwgdGVtcG9yYXJ5IHRhYmxlIGFmdGVyIGV4ZWN1dGluZyB0aGUgYnVsayBsb2FkLFxuICAgKiB5b3UnbGwgbmVlZCB0byB1c2UgdGhlIHNhbWUgY29ubmVjdGlvbiBhbmQgZXhlY3V0ZSB5b3VyIHJlcXVlc3RzIHVzaW5nIFtbQ29ubmVjdGlvbi5leGVjU3FsQmF0Y2hdXSBpbnN0ZWFkIG9mIFtbQ29ubmVjdGlvbi5leGVjU3FsXV1cbiAgICovXG4gIGdldFRhYmxlQ3JlYXRpb25TcWwoKSB7XG4gICAgbGV0IHNxbCA9ICdDUkVBVEUgVEFCTEUgJyArIHRoaXMudGFibGUgKyAnKFxcbic7XG4gICAgZm9yIChsZXQgaSA9IDAsIGxlbiA9IHRoaXMuY29sdW1ucy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgICAgY29uc3QgYyA9IHRoaXMuY29sdW1uc1tpXTtcbiAgICAgIGlmIChpICE9PSAwKSB7XG4gICAgICAgIHNxbCArPSAnLFxcbic7XG4gICAgICB9XG4gICAgICBzcWwgKz0gJ1snICsgYy5uYW1lICsgJ10gJyArIChjLnR5cGUuZGVjbGFyYXRpb24oYykpO1xuICAgICAgaWYgKGMubnVsbGFibGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBzcWwgKz0gJyAnICsgKGMubnVsbGFibGUgPyAnTlVMTCcgOiAnTk9UIE5VTEwnKTtcbiAgICAgIH1cbiAgICB9XG4gICAgc3FsICs9ICdcXG4pJztcbiAgICByZXR1cm4gc3FsO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBnZXRDb2xNZXRhRGF0YSgpIHtcbiAgICBjb25zdCB0QnVmID0gbmV3IFdyaXRhYmxlVHJhY2tpbmdCdWZmZXIoKTtcbiAgICAvLyBUb2tlblR5cGVcbiAgICB0QnVmLndyaXRlVUludDgoVE9LRU5fVFlQRS5DT0xNRVRBREFUQSk7XG4gICAgLy8gQ291bnRcbiAgICB0QnVmLndyaXRlVUludDE2TEUodGhpcy5jb2x1bW5zLmxlbmd0aCk7XG5cbiAgICBmb3IgKGxldCBqID0gMCwgbGVuID0gdGhpcy5jb2x1bW5zLmxlbmd0aDsgaiA8IGxlbjsgaisrKSB7XG4gICAgICBjb25zdCBjID0gdGhpcy5jb2x1bW5zW2pdO1xuICAgICAgLy8gVXNlclR5cGVcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMudGRzVmVyc2lvbiA8ICc3XzInKSB7XG4gICAgICAgIHRCdWYud3JpdGVVSW50MTZMRSgwKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRCdWYud3JpdGVVSW50MzJMRSgwKTtcbiAgICAgIH1cblxuICAgICAgLy8gRmxhZ3NcbiAgICAgIGxldCBmbGFncyA9IEZMQUdTLnVwZGF0ZWFibGVSZWFkV3JpdGU7XG4gICAgICBpZiAoYy5udWxsYWJsZSkge1xuICAgICAgICBmbGFncyB8PSBGTEFHUy5udWxsYWJsZTtcbiAgICAgIH0gZWxzZSBpZiAoYy5udWxsYWJsZSA9PT0gdW5kZWZpbmVkICYmIHRoaXMub3B0aW9ucy50ZHNWZXJzaW9uID49ICc3XzInKSB7XG4gICAgICAgIGZsYWdzIHw9IEZMQUdTLm51bGxhYmxlVW5rbm93bjtcbiAgICAgIH1cbiAgICAgIHRCdWYud3JpdGVVSW50MTZMRShmbGFncyk7XG5cbiAgICAgIC8vIFRZUEVfSU5GT1xuICAgICAgdHJ5IHtcbiAgICAgICAgYy50eXBlLndyaXRlVHlwZUluZm8odEJ1ZiwgYywgdGhpcy5vcHRpb25zKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHRocm93IG5ldyBJbnB1dEVycm9yKGBDb2x1bW4gJyR7Yy5uYW1lfScgY291bGQgbm90IGJlIHNlcmlhbGl6ZWRgLCB7IGNhdXNlOiBlcnJvciB9KTtcbiAgICAgIH1cblxuICAgICAgLy8gVGFibGVOYW1lXG4gICAgICBpZiAoYy50eXBlLmhhc1RhYmxlTmFtZSkge1xuICAgICAgICB0QnVmLndyaXRlVXNWYXJjaGFyKHRoaXMudGFibGUsICd1Y3MyJyk7XG4gICAgICB9XG5cbiAgICAgIC8vIENvbE5hbWVcbiAgICAgIHRCdWYud3JpdGVCVmFyY2hhcihjLm5hbWUsICd1Y3MyJyk7XG4gICAgfVxuICAgIHJldHVybiB0QnVmLmRhdGE7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyBhIHRpbWVvdXQgZm9yIHRoaXMgYnVsayBsb2FkLlxuICAgKlxuICAgKiBgYGBqc1xuICAgKiBidWxrTG9hZC5zZXRUaW1lb3V0KHRpbWVvdXQpO1xuICAgKiBgYGBcbiAgICpcbiAgICogQHBhcmFtIHRpbWVvdXQgVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgYmVmb3JlIHRoZSBidWxrIGxvYWQgaXMgY29uc2lkZXJlZCBmYWlsZWQsIG9yIDAgZm9yIG5vIHRpbWVvdXQuXG4gICAqICAgV2hlbiBubyB0aW1lb3V0IGlzIHNldCBmb3IgdGhlIGJ1bGsgbG9hZCwgdGhlIFtbQ29ubmVjdGlvbk9wdGlvbnMucmVxdWVzdFRpbWVvdXRdXSBvZiB0aGUgQ29ubmVjdGlvbiBpcyB1c2VkLlxuICAgKi9cbiAgc2V0VGltZW91dCh0aW1lb3V0PzogbnVtYmVyKSB7XG4gICAgdGhpcy50aW1lb3V0ID0gdGltZW91dDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgY3JlYXRlRG9uZVRva2VuKCkge1xuICAgIC8vIEl0IG1pZ2h0IGJlIG5pY2UgdG8gbWFrZSBEb25lVG9rZW4gYSBjbGFzcyBpZiBhbnl0aGluZyBuZWVkcyB0byBjcmVhdGUgdGhlbSwgYnV0IGZvciBub3csIGp1c3QgZG8gaXQgaGVyZVxuICAgIGNvbnN0IHRCdWYgPSBuZXcgV3JpdGFibGVUcmFja2luZ0J1ZmZlcigpO1xuICAgIHRCdWYud3JpdGVVSW50OChUT0tFTl9UWVBFLkRPTkUpO1xuICAgIGNvbnN0IHN0YXR1cyA9IERPTkVfU1RBVFVTLkZJTkFMO1xuICAgIHRCdWYud3JpdGVVSW50MTZMRShzdGF0dXMpO1xuICAgIHRCdWYud3JpdGVVSW50MTZMRSgwKTsgLy8gQ3VyQ21kIChURFMgaWdub3JlcyB0aGlzKVxuICAgIHRCdWYud3JpdGVVSW50MzJMRSgwKTsgLy8gcm93IGNvdW50IC0gZG9lc24ndCByZWFsbHkgbWF0dGVyXG4gICAgaWYgKHRoaXMub3B0aW9ucy50ZHNWZXJzaW9uID49ICc3XzInKSB7XG4gICAgICB0QnVmLndyaXRlVUludDMyTEUoMCk7IC8vIHJvdyBjb3VudCBpcyA2NCBiaXRzIGluID49IFREUyA3LjJcbiAgICB9XG4gICAgcmV0dXJuIHRCdWYuZGF0YTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgY2FuY2VsKCkge1xuICAgIGlmICh0aGlzLmNhbmNlbGVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5jYW5jZWxlZCA9IHRydWU7XG4gICAgdGhpcy5lbWl0KCdjYW5jZWwnKTtcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBCdWxrTG9hZDtcbm1vZHVsZS5leHBvcnRzID0gQnVsa0xvYWQ7XG4iXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLElBQUFBLE9BQUEsR0FBQUMsT0FBQTtBQUNBLElBQUFDLHVCQUFBLEdBQUFDLHNCQUFBLENBQUFGLE9BQUE7QUFHQSxJQUFBRyxNQUFBLEdBQUFILE9BQUE7QUFHQSxJQUFBSSxPQUFBLEdBQUFKLE9BQUE7QUFBc0MsU0FBQUUsdUJBQUFHLENBQUEsV0FBQUEsQ0FBQSxJQUFBQSxDQUFBLENBQUFDLFVBQUEsR0FBQUQsQ0FBQSxLQUFBRSxPQUFBLEVB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