444 lines
58 KiB
JavaScript
444 lines
58 KiB
JavaScript
|
|
"use strict";
|
||
|
|
|
||
|
|
Object.defineProperty(exports, "__esModule", {
|
||
|
|
value: true
|
||
|
|
});
|
||
|
|
exports.UnexpectedTokenError = exports.TokenHandler = exports.RequestTokenHandler = exports.Login7TokenHandler = exports.InitialSqlTokenHandler = exports.AttentionTokenHandler = void 0;
|
||
|
|
var _request = _interopRequireDefault(require("../request"));
|
||
|
|
var _errors = require("../errors");
|
||
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
|
class UnexpectedTokenError extends Error {
|
||
|
|
constructor(handler, token) {
|
||
|
|
super('Unexpected token `' + token.name + '` in `' + handler.constructor.name + '`');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
exports.UnexpectedTokenError = UnexpectedTokenError;
|
||
|
|
class TokenHandler {
|
||
|
|
onInfoMessage(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onErrorMessage(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onSSPI(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onDatabaseChange(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onLanguageChange(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onCharsetChange(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onSqlCollationChange(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onRoutingChange(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onPacketSizeChange(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onResetConnection(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onBeginTransaction(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onCommitTransaction(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onRollbackTransaction(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onFedAuthInfo(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onFeatureExtAck(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onLoginAck(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onColMetadata(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onOrder(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onRow(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onReturnStatus(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onReturnValue(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onDoneProc(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onDoneInProc(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onDone(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
onDatabaseMirroringPartner(token) {
|
||
|
|
throw new UnexpectedTokenError(this, token);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* A handler for tokens received in the response message to the initial SQL Batch request
|
||
|
|
* that sets up different connection settings.
|
||
|
|
*/
|
||
|
|
exports.TokenHandler = TokenHandler;
|
||
|
|
class InitialSqlTokenHandler extends TokenHandler {
|
||
|
|
constructor(connection) {
|
||
|
|
super();
|
||
|
|
this.connection = connection;
|
||
|
|
}
|
||
|
|
onInfoMessage(token) {
|
||
|
|
this.connection.emit('infoMessage', token);
|
||
|
|
}
|
||
|
|
onErrorMessage(token) {
|
||
|
|
this.connection.emit('errorMessage', token);
|
||
|
|
}
|
||
|
|
onDatabaseChange(token) {
|
||
|
|
this.connection.emit('databaseChange', token.newValue);
|
||
|
|
}
|
||
|
|
onLanguageChange(token) {
|
||
|
|
this.connection.emit('languageChange', token.newValue);
|
||
|
|
}
|
||
|
|
onCharsetChange(token) {
|
||
|
|
this.connection.emit('charsetChange', token.newValue);
|
||
|
|
}
|
||
|
|
onSqlCollationChange(token) {
|
||
|
|
this.connection.databaseCollation = token.newValue;
|
||
|
|
}
|
||
|
|
onPacketSizeChange(token) {
|
||
|
|
this.connection.messageIo.packetSize(token.newValue);
|
||
|
|
}
|
||
|
|
onBeginTransaction(token) {
|
||
|
|
this.connection.transactionDescriptors.push(token.newValue);
|
||
|
|
this.connection.inTransaction = true;
|
||
|
|
}
|
||
|
|
onCommitTransaction(token) {
|
||
|
|
this.connection.transactionDescriptors.length = 1;
|
||
|
|
this.connection.inTransaction = false;
|
||
|
|
}
|
||
|
|
onRollbackTransaction(token) {
|
||
|
|
this.connection.transactionDescriptors.length = 1;
|
||
|
|
// An outermost transaction was rolled back. Reset the transaction counter
|
||
|
|
this.connection.inTransaction = false;
|
||
|
|
this.connection.emit('rollbackTransaction');
|
||
|
|
}
|
||
|
|
onColMetadata(token) {
|
||
|
|
this.connection.emit('error', new Error("Received 'columnMetadata' when no sqlRequest is in progress"));
|
||
|
|
this.connection.close();
|
||
|
|
}
|
||
|
|
onOrder(token) {
|
||
|
|
this.connection.emit('error', new Error("Received 'order' when no sqlRequest is in progress"));
|
||
|
|
this.connection.close();
|
||
|
|
}
|
||
|
|
onRow(token) {
|
||
|
|
this.connection.emit('error', new Error("Received 'row' when no sqlRequest is in progress"));
|
||
|
|
this.connection.close();
|
||
|
|
}
|
||
|
|
onReturnStatus(token) {
|
||
|
|
// Do nothing
|
||
|
|
}
|
||
|
|
onReturnValue(token) {
|
||
|
|
// Do nothing
|
||
|
|
}
|
||
|
|
onDoneProc(token) {
|
||
|
|
// Do nothing
|
||
|
|
}
|
||
|
|
onDoneInProc(token) {
|
||
|
|
// Do nothing
|
||
|
|
}
|
||
|
|
onDone(token) {
|
||
|
|
// Do nothing
|
||
|
|
}
|
||
|
|
onResetConnection(token) {
|
||
|
|
this.connection.emit('resetConnection');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* A handler for tokens received in the response message to a Login7 message.
|
||
|
|
*/
|
||
|
|
exports.InitialSqlTokenHandler = InitialSqlTokenHandler;
|
||
|
|
class Login7TokenHandler extends TokenHandler {
|
||
|
|
constructor(connection) {
|
||
|
|
super();
|
||
|
|
this.loginAckReceived = false;
|
||
|
|
this.connection = connection;
|
||
|
|
}
|
||
|
|
onInfoMessage(token) {
|
||
|
|
this.connection.emit('infoMessage', token);
|
||
|
|
}
|
||
|
|
onErrorMessage(token) {
|
||
|
|
this.connection.emit('errorMessage', token);
|
||
|
|
const error = new _errors.ConnectionError(token.message, 'ELOGIN');
|
||
|
|
const isLoginErrorTransient = this.connection.transientErrorLookup.isTransientError(token.number);
|
||
|
|
if (isLoginErrorTransient && this.connection.curTransientRetryCount !== this.connection.config.options.maxRetriesOnTransientErrors) {
|
||
|
|
error.isTransient = true;
|
||
|
|
}
|
||
|
|
this.connection.loginError = error;
|
||
|
|
}
|
||
|
|
onSSPI(token) {
|
||
|
|
if (token.ntlmpacket) {
|
||
|
|
this.connection.ntlmpacket = token.ntlmpacket;
|
||
|
|
this.connection.ntlmpacketBuffer = token.ntlmpacketBuffer;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
onDatabaseChange(token) {
|
||
|
|
this.connection.emit('databaseChange', token.newValue);
|
||
|
|
}
|
||
|
|
onLanguageChange(token) {
|
||
|
|
this.connection.emit('languageChange', token.newValue);
|
||
|
|
}
|
||
|
|
onCharsetChange(token) {
|
||
|
|
this.connection.emit('charsetChange', token.newValue);
|
||
|
|
}
|
||
|
|
onSqlCollationChange(token) {
|
||
|
|
this.connection.databaseCollation = token.newValue;
|
||
|
|
}
|
||
|
|
onFedAuthInfo(token) {
|
||
|
|
this.fedAuthInfoToken = token;
|
||
|
|
}
|
||
|
|
onFeatureExtAck(token) {
|
||
|
|
const {
|
||
|
|
authentication
|
||
|
|
} = this.connection.config;
|
||
|
|
if (authentication.type === 'azure-active-directory-password' || authentication.type === 'azure-active-directory-access-token' || authentication.type === 'azure-active-directory-msi-vm' || authentication.type === 'azure-active-directory-msi-app-service' || authentication.type === 'azure-active-directory-service-principal-secret' || authentication.type === 'azure-active-directory-default') {
|
||
|
|
if (token.fedAuth === undefined) {
|
||
|
|
this.connection.loginError = new _errors.ConnectionError('Did not receive Active Directory authentication acknowledgement');
|
||
|
|
} else if (token.fedAuth.length !== 0) {
|
||
|
|
this.connection.loginError = new _errors.ConnectionError(`Active Directory authentication acknowledgment for ${authentication.type} authentication method includes extra data`);
|
||
|
|
}
|
||
|
|
} else if (token.fedAuth === undefined && token.utf8Support === undefined) {
|
||
|
|
this.connection.loginError = new _errors.ConnectionError('Received acknowledgement for unknown feature');
|
||
|
|
} else if (token.fedAuth) {
|
||
|
|
this.connection.loginError = new _errors.ConnectionError('Did not request Active Directory authentication, but received the acknowledgment');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
onLoginAck(token) {
|
||
|
|
if (!token.tdsVersion) {
|
||
|
|
// unsupported TDS version
|
||
|
|
this.connection.loginError = new _errors.ConnectionError('Server responded with unknown TDS version.', 'ETDS');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (!token.interface) {
|
||
|
|
// unsupported interface
|
||
|
|
this.connection.loginError = new _errors.ConnectionError('Server responded with unsupported interface.', 'EINTERFACENOTSUPP');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// use negotiated version
|
||
|
|
this.connection.config.options.tdsVersion = token.tdsVersion;
|
||
|
|
this.loginAckReceived = true;
|
||
|
|
}
|
||
|
|
onRoutingChange(token) {
|
||
|
|
// Removes instance name attached to the redirect url. E.g., redirect.db.net\instance1 --> redirect.db.net
|
||
|
|
const [server] = token.newValue.server.split('\\');
|
||
|
|
this.routingData = {
|
||
|
|
server,
|
||
|
|
port: token.newValue.port
|
||
|
|
};
|
||
|
|
}
|
||
|
|
onDoneInProc(token) {
|
||
|
|
// Do nothing
|
||
|
|
}
|
||
|
|
onDone(token) {
|
||
|
|
// Do nothing
|
||
|
|
}
|
||
|
|
onPacketSizeChange(token) {
|
||
|
|
this.connection.messageIo.packetSize(token.newValue);
|
||
|
|
}
|
||
|
|
onDatabaseMirroringPartner(token) {
|
||
|
|
// Do nothing
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* A handler for tokens received in the response message to a RPC Request,
|
||
|
|
* a SQL Batch Request, a Bulk Load BCP Request or a Transaction Manager Request.
|
||
|
|
*/
|
||
|
|
exports.Login7TokenHandler = Login7TokenHandler;
|
||
|
|
class RequestTokenHandler extends TokenHandler {
|
||
|
|
constructor(connection, request) {
|
||
|
|
super();
|
||
|
|
this.connection = connection;
|
||
|
|
this.request = request;
|
||
|
|
this.errors = [];
|
||
|
|
}
|
||
|
|
onInfoMessage(token) {
|
||
|
|
this.connection.emit('infoMessage', token);
|
||
|
|
}
|
||
|
|
onErrorMessage(token) {
|
||
|
|
this.connection.emit('errorMessage', token);
|
||
|
|
if (!this.request.canceled) {
|
||
|
|
const error = new _errors.RequestError(token.message, 'EREQUEST');
|
||
|
|
error.number = token.number;
|
||
|
|
error.state = token.state;
|
||
|
|
error.class = token.class;
|
||
|
|
error.serverName = token.serverName;
|
||
|
|
error.procName = token.procName;
|
||
|
|
error.lineNumber = token.lineNumber;
|
||
|
|
this.errors.push(error);
|
||
|
|
this.request.error = error;
|
||
|
|
if (this.request instanceof _request.default && this.errors.length > 1) {
|
||
|
|
this.request.error = new AggregateError(this.errors);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
onDatabaseChange(token) {
|
||
|
|
this.connection.emit('databaseChange', token.newValue);
|
||
|
|
}
|
||
|
|
onLanguageChange(token) {
|
||
|
|
this.connection.emit('languageChange', token.newValue);
|
||
|
|
}
|
||
|
|
onCharsetChange(token) {
|
||
|
|
this.connection.emit('charsetChange', token.newValue);
|
||
|
|
}
|
||
|
|
onSqlCollationChange(token) {
|
||
|
|
this.connection.databaseCollation = token.newValue;
|
||
|
|
}
|
||
|
|
onPacketSizeChange(token) {
|
||
|
|
this.connection.messageIo.packetSize(token.newValue);
|
||
|
|
}
|
||
|
|
onBeginTransaction(token) {
|
||
|
|
this.connection.transactionDescriptors.push(token.newValue);
|
||
|
|
this.connection.inTransaction = true;
|
||
|
|
}
|
||
|
|
onCommitTransaction(token) {
|
||
|
|
this.connection.transactionDescriptors.length = 1;
|
||
|
|
this.connection.inTransaction = false;
|
||
|
|
}
|
||
|
|
onRollbackTransaction(token) {
|
||
|
|
this.connection.transactionDescriptors.length = 1;
|
||
|
|
// An outermost transaction was rolled back. Reset the transaction counter
|
||
|
|
this.connection.inTransaction = false;
|
||
|
|
this.connection.emit('rollbackTransaction');
|
||
|
|
}
|
||
|
|
onColMetadata(token) {
|
||
|
|
if (!this.request.canceled) {
|
||
|
|
if (this.connection.config.options.useColumnNames) {
|
||
|
|
const columns = Object.create(null);
|
||
|
|
for (let j = 0, len = token.columns.length; j < len; j++) {
|
||
|
|
const col = token.columns[j];
|
||
|
|
if (columns[col.colName] == null) {
|
||
|
|
columns[col.colName] = col;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
this.request.emit('columnMetadata', columns);
|
||
|
|
} else {
|
||
|
|
this.request.emit('columnMetadata', token.columns);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
onOrder(token) {
|
||
|
|
if (!this.request.canceled) {
|
||
|
|
this.request.emit('order', token.orderColumns);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
onRow(token) {
|
||
|
|
if (!this.request.canceled) {
|
||
|
|
if (this.connection.config.options.rowCollectionOnRequestCompletion) {
|
||
|
|
this.request.rows.push(token.columns);
|
||
|
|
}
|
||
|
|
if (this.connection.config.options.rowCollectionOnDone) {
|
||
|
|
this.request.rst.push(token.columns);
|
||
|
|
}
|
||
|
|
this.request.emit('row', token.columns);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
onReturnStatus(token) {
|
||
|
|
if (!this.request.canceled) {
|
||
|
|
// Keep value for passing in 'doneProc' event.
|
||
|
|
this.connection.procReturnStatusValue = token.value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
onReturnValue(token) {
|
||
|
|
if (!this.request.canceled) {
|
||
|
|
this.request.emit('returnValue', token.paramName, token.value, token.metadata);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
onDoneProc(token) {
|
||
|
|
if (!this.request.canceled) {
|
||
|
|
if (token.sqlError && !this.request.error) {
|
||
|
|
// check if the DONE_ERROR flags was set, but an ERROR token was not sent.
|
||
|
|
this.request.error = new _errors.RequestError('An unknown error has occurred.', 'UNKNOWN');
|
||
|
|
}
|
||
|
|
this.request.emit('doneProc', token.rowCount, token.more, this.connection.procReturnStatusValue, this.request.rst);
|
||
|
|
this.connection.procReturnStatusValue = undefined;
|
||
|
|
if (token.rowCount !== undefined) {
|
||
|
|
this.request.rowCount += token.rowCount;
|
||
|
|
}
|
||
|
|
if (this.connection.config.options.rowCollectionOnDone) {
|
||
|
|
this.request.rst = [];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
onDoneInProc(token) {
|
||
|
|
if (!this.request.canceled) {
|
||
|
|
this.request.emit('doneInProc', token.rowCount, token.more, this.request.rst);
|
||
|
|
if (token.rowCount !== undefined) {
|
||
|
|
this.request.rowCount += token.rowCount;
|
||
|
|
}
|
||
|
|
if (this.connection.config.options.rowCollectionOnDone) {
|
||
|
|
this.request.rst = [];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
onDone(token) {
|
||
|
|
if (!this.request.canceled) {
|
||
|
|
if (token.sqlError && !this.request.error) {
|
||
|
|
// check if the DONE_ERROR flags was set, but an ERROR token was not sent.
|
||
|
|
this.request.error = new _errors.RequestError('An unknown error has occurred.', 'UNKNOWN');
|
||
|
|
}
|
||
|
|
this.request.emit('done', token.rowCount, token.more, this.request.rst);
|
||
|
|
if (token.rowCount !== undefined) {
|
||
|
|
this.request.rowCount += token.rowCount;
|
||
|
|
}
|
||
|
|
if (this.connection.config.options.rowCollectionOnDone) {
|
||
|
|
this.request.rst = [];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
onResetConnection(token) {
|
||
|
|
this.connection.emit('resetConnection');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* A handler for the attention acknowledgement message.
|
||
|
|
*
|
||
|
|
* This message only contains a `DONE` token that acknowledges
|
||
|
|
* that the attention message was received by the server.
|
||
|
|
*/
|
||
|
|
exports.RequestTokenHandler = RequestTokenHandler;
|
||
|
|
class AttentionTokenHandler extends TokenHandler {
|
||
|
|
/**
|
||
|
|
* Returns whether an attention acknowledgement was received.
|
||
|
|
*/
|
||
|
|
|
||
|
|
constructor(connection, request) {
|
||
|
|
super();
|
||
|
|
this.connection = connection;
|
||
|
|
this.request = request;
|
||
|
|
this.attentionReceived = false;
|
||
|
|
}
|
||
|
|
onDone(token) {
|
||
|
|
if (token.attention) {
|
||
|
|
this.attentionReceived = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
exports.AttentionTokenHandler = AttentionTokenHandler;
|
||
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVxdWVzdCIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX2Vycm9ycyIsIm9iaiIsIl9fZXNNb2R1bGUiLCJkZWZhdWx0IiwiVW5leHBlY3RlZFRva2VuRXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwiaGFuZGxlciIsInRva2VuIiwibmFtZSIsImV4cG9ydHMiLCJUb2tlbkhhbmRsZXIiLCJvbkluZm9NZXNzYWdlIiwib25FcnJvck1lc3NhZ2UiLCJvblNTUEkiLCJvbkRhdGFiYXNlQ2hhbmdlIiwib25MYW5ndWFnZUNoYW5nZSIsIm9uQ2hhcnNldENoYW5nZSIsIm9uU3FsQ29sbGF0aW9uQ2hhbmdlIiwib25Sb3V0aW5nQ2hhbmdlIiwib25QYWNrZXRTaXplQ2hhbmdlIiwib25SZXNldENvbm5lY3Rpb24iLCJvbkJlZ2luVHJhbnNhY3Rpb24iLCJvbkNvbW1pdFRyYW5zYWN0aW9uIiwib25Sb2xsYmFja1RyYW5zYWN0aW9uIiwib25GZWRBdXRoSW5mbyIsIm9uRmVhdHVyZUV4dEFjayIsIm9uTG9naW5BY2siLCJvbkNvbE1ldGFkYXRhIiwib25PcmRlciIsIm9uUm93Iiwib25SZXR1cm5TdGF0dXMiLCJvblJldHVyblZhbHVlIiwib25Eb25lUHJvYyIsIm9uRG9uZUluUHJvYyIsIm9uRG9uZSIsIm9uRGF0YWJhc2VNaXJyb3JpbmdQYXJ0bmVyIiwiSW5pdGlhbFNxbFRva2VuSGFuZGxlciIsImNvbm5lY3Rpb24iLCJlbWl0IiwibmV3VmFsdWUiLCJkYXRhYmFzZUNvbGxhdGlvbiIsIm1lc3NhZ2VJbyIsInBhY2tldFNpemUiLCJ0cmFuc2FjdGlvbkRlc2NyaXB0b3JzIiwicHVzaCIsImluVHJhbnNhY3Rpb24iLCJsZW5ndGgiLCJjbG9zZSIsIkxvZ2luN1Rva2VuSGFuZGxlciIsImxvZ2luQWNrUmVjZWl2ZWQiLCJlcnJvciIsIkNvbm5lY3Rpb25FcnJvciIsIm1lc3NhZ2UiLCJpc0xvZ2luRXJyb3JUcmFuc2llbnQiLCJ0cmFuc2llbnRFcnJvckxvb2t1cCIsImlzVHJhbnNpZW50RXJyb3IiLCJudW1iZXIiLCJjdXJUcmFuc2llbnRSZXRyeUNvdW50IiwiY29uZmlnIiwib3B0aW9ucyIsIm1heFJldHJpZXNPblRyYW5zaWVudEVycm9ycyIsImlzVHJhbnNpZW50IiwibG9naW5FcnJvciIsIm50bG1wYWNrZXQiLCJudGxtcGFja2V0QnVmZmVyIiwiZmVkQXV0aEluZm9Ub2tlbiIsImF1dGhlbnRpY2F0aW9uIiwidHlwZSIsImZlZEF1dGgiLCJ1bmRlZmluZWQiLCJ1dGY4U3VwcG9ydCIsInRkc1ZlcnNpb24iLCJpbnRlcmZhY2UiLCJzZXJ2ZXIiLCJzcGxpdCIsInJvdXRpbmdEYXRhIiwicG9ydCIsIlJlcXVlc3RUb2tlbkhhbmRsZXIiLCJyZXF1ZXN0IiwiZXJyb3JzIiwiY2FuY2VsZWQiLCJSZXF1ZXN0RXJyb3IiLCJzdGF0ZSIsImNsYXNzIiwic2VydmVyTmFtZSIsInByb2NOYW1lIiwibGluZU51bWJlciIsIlJlcXVlc3QiLCJBZ2dyZWdhdGVFcnJvciIsInVzZUNvbHVtbk5hbWVzIiwiY29sdW1ucyIsIk9iamVjdCIsImNyZWF0ZSIsImoiLCJsZW4iLCJjb2wiLCJjb2xOYW1lIiwib3JkZXJDb2x1bW5zIiwicm93Q29sbGVjdGlvbk9uUmVxdWVzdENvbXBsZXRpb24iLCJyb3dzIiwicm93Q29sbGVjdGlvbk9uRG9uZSIsInJzdCIsInByb2NSZXR1cm5TdGF0dXNWYWx1ZSIsInZhbHVlIiwicGFyYW1OYW1lIiwibWV0YWRhdGEiLCJzcWxFcnJvciIsInJvd0NvdW50IiwibW9yZSIsIkF0dGVudGlvblRva2VuSGFuZGxlciIsImF0dGVudGlvblJlY2VpdmVkIiwiYXR0ZW50aW9uIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rva2VuL2hhbmRsZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IENvbm5lY3Rpb24gZnJvbSAnLi4vY29ubmVjdGlvbic7XG5pbXBvcnQgUmVxdWVzdCBmcm9tICcuLi9yZXF1ZXN0JztcbmltcG9ydCB7IENvbm5lY3Rpb25FcnJvciwgUmVxdWVzdEVycm9yIH0gZnJvbSAnLi4vZXJyb3JzJztcbmltcG9ydCB7IHR5cGUgQ29sdW1uTWV0YWRhdGEgfSBmcm9tICcuL2NvbG1ldGFkYXRhLXRva2VuLXBhcnNlcic7XG5pbXBvcnQge1xuICBCZWdpblRyYW5zYWN0aW9uRW52Q2hhbmdlVG9rZW4sXG4gIENoYXJzZXRFbnZDaGFuZ2VUb2tlbixcbiAgQ29sbGF0aW9uQ2hhbmdlVG9rZW4sXG4gIENvbE1ldGFkYXRhVG9rZW4sXG4gIENvbW1pdFRyYW5zYWN0aW9uRW52Q2hhbmdlVG9rZW4sXG4gIERhdGFiYXNlRW52Q2hhbmdlVG9rZW4sXG4gIERhdGFiYXNlTWlycm9yaW5nUGFydG5lckVudkNoYW5nZVRva2VuLFxuICBEb25lSW5Qcm9jVG9rZW4sXG4gIERvbmVQcm9jVG9rZW4sXG4gIERvbmVUb2tlbixcbiAgRXJyb3JNZXNzYWdlVG9rZW4sXG4gIEZlYXR1cmVFeHRBY2tUb2tlbixcbiAgRmVkQXV0aEluZm9Ub2tlbixcbiAgSW5mb01lc3NhZ2VUb2tlbixcbiAgTGFuZ3VhZ2VFbnZDaGFuZ2VUb2tlbixcbiAgTG9naW5BY2tUb2tlbixcbiAgTkJDUm93VG9rZW4sXG4gIE9yZGVyVG9rZW4sXG4gIFBhY2tldFNpemVFbnZDaGFuZ2VUb2tlbixcbiAgUmVzZXRDb25uZWN0aW9uRW52Q2hhbmdlVG9rZW4sXG4gIFJldHVyblN0YXR1c1Rva2VuLFxuICBSZXR1cm5WYWx1ZVRva2VuLFxuICBSb2xsYmFja1RyYW5zYWN0aW9uRW52Q2hhbmdlVG9rZW4sXG4gIFJvdXRpbmdFbnZDaGFuZ2VUb2tlbixcbiAgUm93VG9rZW4sXG4gIFNTUElUb2tlbixcbiAgVG9rZW5cbn0gZnJvbSAnLi90b2tlbic7XG5pbXBvcnQgQnVsa0xvYWQgZnJvbSAnLi4vYnVsay1sb2FkJztcblxuZXhwb3J0IGNsYXNzIFVuZXhwZWN0ZWRUb2tlbkVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihoYW5kbGVyOiBUb2tlbkhhbmRsZXIsIHRva2VuOiBUb2tlbikge1xuICAgIHN1cGVyKCdVbmV4cGVjdGVkIHRva2VuIGAnICsgdG9rZW4ubmFtZSArICdgIGluIGAnICsgaGFuZGxlci5jb25zdHJ1Y3Rvci5uYW1lICsgJ2AnKTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgVG9rZW5IYW5kbGVyIHtcbiAgb25JbmZvTWVzc2FnZSh0b2tlbjogSW5mb01lc3NhZ2VUb2tlbikge1xuICAgIHRocm93IG5ldyBVbmV4cGVjdGVkVG9rZW5FcnJvcih0aGlzLCB0b2tlbik7XG4gIH1cblxuICBvbkVycm9yTWVzc2FnZSh0b2tlbjogRXJyb3JNZXNzYWdlVG9rZW4pIHtcbiAgICB0aHJvdyB
|