pj
Version:
Create SQL strings for PostgreSQL by interfacing with a javascript API
343 lines (251 loc) • 21.9 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
// third-party modules
var _classer = require('classer');
var _classer2 = _interopRequireDefault(_classer);
var _pg = require('pg');
var _pg2 = _interopRequireDefault(_pg);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
// local classes
/**
* static:
**/
// connection string regex parser
// const R_CONNECT = /^\s*(?:(?:(?:(\w+):\/\/)?(\w+)(?::([^@]+))?@)?(\w+)?\/)?(\w+)(\?.+)\s*$/;
var R_CONNECT = /^\s*([\w\-]+)?(:[^@]+)?@([^:\/?\s]+)?(:\d+)?\/([^?\s]+)\s*/;
// connection defaults
var H_CONNECT_DEFAULTS = {
protocol: 'postgres',
user: 'root',
host: 'localhost'
};
// connect to database using string
var connect_string = function connect_string(s_connect) {
// parse connection string
var m_connect = R_CONNECT.exec(s_connect);
// invalid connection string
if (!m_connect) return local.fail('invalid connection string: "' + s_connect + '"');
// construct full postgres connection string
return ''
// protocol
+ (false || H_CONNECT_DEFAULTS.protocol) + '://'
// user
+ (m_connect[1] || H_CONNECT_DEFAULTS.user)
// password
+ (m_connect[2] ? m_connect[2] : '') + '@'
// host
+ (m_connect[3] || H_CONNECT_DEFAULTS.host)
// port
+ (m_connect[4] ? m_connect[4] : '') + '/'
// database
+ m_connect[5];
};
// escape string literal
var escape_literal = function escape_literal(s_value) {
return s_value.replace(/'/g, '\'\'').replace(/\t/g, '\\t').replace(/\n/g, '\\n');
};
//
var valuify = function valuify(z_value) {
switch (typeof z_value === 'undefined' ? 'undefined' : _typeof(z_value)) {
case 'string':
return '\'' + escape_literal(z_value) + '\'';
case 'number':
return z_value;
case 'boolean':
return z_value ? 'TRUE' : 'FALSE';
case 'object':
// null
if (null === z_value) {
return null;
}
// raw sql
else if ('string' === typeof z_value.raw) {
return z_value.raw;
}
// default
return escape_literal(JSON.stringify(z_value));
case 'function':
return z_value() + '';
default:
throw 'unable to convert into safe value: "${z_value}"';
}
};
//
var H_WRITERS = {
// convert hash query to string query
insert: function insert(h_query) {
// ref insert list
var a_inserts = h_query.insert;
// prep list of rows that have been observed from first element
var a_keys = Object.keys(a_inserts[0]);
// build columns part of sql string
var s_keys = a_keys.map(function (s_key) {
return '"' + s_key + '"';
}).join(',');
// build values part of sql string
var a_rows = [];
// each insert row
a_inserts.forEach(function (h_row) {
// list of values to insert for this row
var a_values = [];
// each key-value pair in row
for (var s_key in h_row) {
// key is missing from accepted values section
if (-1 === a_keys.indexOf(s_key)) {
return local.fail('new key "${s_key}" introduced after first element in insert chain');
}
// append to values
a_values.push(valuify(h_row[s_key]));
}
// push row to values list
a_rows.push('(' + a_values.join(',') + ')');
});
//
var s_tail = '';
//
if (h_query.conflict_target && h_query.conflict_action) {
s_tail += 'on conflict ' + h_query.conflict_target + ' ' + h_query.conflict_action;
}
// prep sql query string
return 'insert into "' + h_query.into + '" (' + s_keys + ') values ' + a_rows.join(',') + ' ' + s_tail;
}
};
/**
* class:
**/
var local = (0, _classer2.default)('pj', function (z_config) {
//
var a_queue = [];
// connection string
var s_connection = function () {
// setup postgres connection
switch (typeof z_config === 'undefined' ? 'undefined' : _typeof(z_config)) {
// config given as string
case 'string':
// connection string
return connect_string(z_config);
}
return false;
}();
//
if (!s_connection) return local.fail('failed to understand connection config argument');
//
local.info('connecting to postgres w/ ' + s_connection);
// postgres client
var y_client = new _pg2.default.Client(s_connection);
// initiate connection
y_client.connect(function (e_connect) {
// connection error
if (e_connect) {
local.fail('failed to connect');
}
//
next_query();
});
//
var next_query = function next_query() {
// queue is not empty
if (a_queue.length) {
// shift first query from beginning
var h_query = a_queue.shift();
// execute query
y_client.query(h_query.sql, h_query.callback);
}
};
// submit a query to be executed
var submit_query = function submit_query(s_query, f_okay) {
// push to queue
a_queue.push({
sql: s_query,
callback: f_okay
});
// queue was empty
if (1 === a_queue.length) {
// initiate
next_query();
}
};
// query-building for insertion
var qb_insert = function qb_insert(h_query) {
// default insert hash
h_query.insert = h_query.insert || [];
//
var self = {
// insert rows
insert: function insert(z_values) {
// list of rows to insert simultaneously
if (Array.isArray(z_values)) {
var _h_query$insert;
// append to existing insertion list
(_h_query$insert = h_query.insert).push.apply(_h_query$insert, _toConsumableArray(z_values));
}
// values hash
else if ('object' === (typeof z_values === 'undefined' ? 'undefined' : _typeof(z_values))) {
// single row to append to insertion list
h_query.insert.push(z_values);
}
// other type
else {
local.fail('invalid type for insertion argument');
}
// normal insert actions
return self;
},
// on conflict
on_conflict: function on_conflict(s_target) {
// set conflict target
h_query.conflict_target = '(' + s_target + ')';
// next action hash
return {
// do nothing
do_nothing: function do_nothing() {
// set conflict action
h_query.conflict_action = 'do nothing';
// normal insert actions
return self;
}
};
},
//
debug: function debug() {
// generate sql
var s_sql = H_WRITERS.insert(h_query);
debugger;
return self;
},
//
exec: function exec(f_okay) {
// generate sql
var s_sql = H_WRITERS.insert(h_query);
// submit
submit_query(s_sql, function (e_insert, w_result) {
// insert error
if (e_insert) {
local.fail(e_insert);
}
//
if ('function' === typeof f_okay) {
f_okay(w_result);
}
});
}
};
//
return self;
};
//
return _classer2.default.operator(function () {}, {
// start of an insert query
into: function into(s_table) {
return qb_insert({
into: s_table
});
}
});
});
exports.default = local;
//# sourceMappingURL=data:application/json;base64,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aUIsT0FBakIsQ0FBUjs7O0FBSFEsZ0JBTVosQ0FBYSxLQUFiLEVBQW9CLFVBQUMsUUFBRCxFQUFXLFFBQVgsRUFBd0I7OztBQUczQyxTQUFHLFFBQUgsRUFBYTtBQUNaLFlBQU0sSUFBTixDQUFXLFFBQVgsRUFEWTtNQUFiOzs7QUFIMkMsU0FReEMsZUFBZSxPQUFPLE1BQVAsRUFBZTtBQUNoQyxhQUFPLFFBQVAsRUFEZ0M7TUFBakM7S0FSbUIsQ0FBcEIsQ0FOWTtJQTFERDtHQUFQOzs7QUFOd0IsU0FzRnZCLElBQVAsQ0F0RjhCO0VBQWI7OztBQXZFNEIsUUFrS3ZDLGtCQUFRLFFBQVIsQ0FBaUIsWUFBVyxFQUFYLEVBRXJCOzs7O0FBR0Ysc0JBQUssU0FBUztBQUNiLFVBQU8sVUFBVTtBQUNoQixVQUFNLE9BQU47SUFETSxDQUFQLENBRGE7R0FIWjtFQUZJLENBQVAsQ0FsSzhDO0NBQW5CLENBQXRCOztrQkErS1MiLCJmaWxlIjoicGouanMiLCJzb3VyY2VzQ29udGVudCI6WyJcbi8vIHRoaXJkLXBhcnR5IG1vZHVsZXNcbmltcG9ydCBjbGFzc2VyIGZyb20gJ2NsYXNzZXInO1xuaW1wb3J0IHBnIGZyb20gJ3BnJztcblxuLy8gbG9jYWwgY2xhc3Nlc1xuXG4vKipcbiogc3RhdGljOlxuKiovXG5cbi8vIGNvbm5lY3Rpb24gc3RyaW5nIHJlZ2V4IHBhcnNlclxuLy8gY29uc3QgUl9DT05ORUNUID0gL15cXHMqKD86KD86KD86KFxcdyspOlxcL1xcLyk/KFxcdyspKD86OihbXkBdKykpP0ApPyhcXHcrKT9cXC8pPyhcXHcrKShcXD8uKylcXHMqJC87XG5jb25zdCBSX0NPTk5FQ1QgPSAvXlxccyooW1xcd1xcLV0rKT8oOlteQF0rKT9AKFteOlxcLz9cXHNdKyk/KDpcXGQrKT9cXC8oW14/XFxzXSspXFxzKi87XG5cbi8vIGNvbm5lY3Rpb24gZGVmYXVsdHNcbmNvbnN0IEhfQ09OTkVDVF9ERUZBVUxUUyA9IHtcblx0cHJvdG9jb2w6ICdwb3N0Z3JlcycsXG5cdHVzZXI6ICdyb290Jyxcblx0aG9zdDogJ2xvY2FsaG9zdCcsXG59O1xuXG5cbi8vIGNvbm5lY3QgdG8gZGF0YWJhc2UgdXNpbmcgc3RyaW5nXG5jb25zdCBjb25uZWN0X3N0cmluZyA9IChzX2Nvbm5lY3QpID0+IHtcblxuXHQvLyBwYXJzZSBjb25uZWN0aW9uIHN0cmluZ1xuXHR2YXIgbV9jb25uZWN0ID0gUl9DT05ORUNULmV4ZWMoc19jb25uZWN0KTtcblxuXHQvLyBpbnZhbGlkIGNvbm5lY3Rpb24gc3RyaW5nXG5cdGlmKCFtX2Nvbm5lY3QpIHJldHVybiBsb2NhbC5mYWlsKGBpbnZhbGlkIGNvbm5lY3Rpb24gc3RyaW5nOiBcIiR7c19jb25uZWN0fVwiYCk7XG5cblx0Ly8gY29uc3RydWN0IGZ1bGwgcG9zdGdyZXMgY29ubmVjdGlvbiBzdHJpbmdcblx0cmV0dXJuICcnXG5cdFx0XHQvLyBwcm90b2NvbFxuXHRcdFx0KyhmYWxzZSB8fCBIX0NPTk5FQ1RfREVGQVVMVFMucHJvdG9jb2wpKyc6Ly8nXG5cdFx0XHQvLyB1c2VyXG5cdFx0XHQrKG1fY29ubmVjdFsxXSB8fCBIX0NPTk5FQ1RfREVGQVVMVFMudXNlcilcblx0XHRcdFx0Ly8gcGFzc3dvcmRcblx0XHRcdFx0KyhtX2Nvbm5lY3RbMl0/IG1fY29ubmVjdFsyXTogJycpKydAJ1xuXHRcdFx0Ly8gaG9zdFxuXHRcdFx0KyhtX2Nvbm5lY3RbM10gfHwgSF9DT05ORUNUX0RFRkFVTFRTLmhvc3QpXG5cdFx0XHRcdC8vIHBvcnRcblx0XHRcdFx0KyhtX2Nvbm5lY3RbNF0/IG1fY29ubmVjdFs0XTogJycpKycvJ1xuXHRcdFx0Ly8gZGF0YWJhc2Vcblx0XHRcdCttX2Nvbm5lY3RbNV07XG59O1xuXG4vLyBlc2NhcGUgc3RyaW5nIGxpdGVyYWxcbmNvbnN0IGVzY2FwZV9saXRlcmFsID0gKHNfdmFsdWUpID0+IHtcblx0cmV0dXJuIHNfdmFsdWVcblx0XHQucmVwbGFjZSgvJy9nLCAnXFwnXFwnJylcblx0XHQucmVwbGFjZSgvXFx0L2csICdcXFxcdCcpXG5cdFx0LnJlcGxhY2UoL1xcbi9nLCAnXFxcXG4nKTtcbn07XG5cbi8vXG5jb25zdCB2YWx1aWZ5ID0gKHpfdmFsdWUpID0+IHtcblx0c3dpdGNoKHR5cGVvZiB6X3ZhbHVlKSB7XG5cdFx0Y2FzZSAnc3RyaW5nJzpcblx0XHRcdHJldHVybiBgJyR7ZXNjYXBlX2xpdGVyYWwoel92YWx1ZSl9J2A7XG5cblx0XHRjYXNlICdudW1iZXInOlxuXHRcdFx0cmV0dXJuIHpfdmFsdWU7XG5cblx0XHRjYXNlICdib29sZWFuJzpcblx0XHRcdHJldHVybiB6X3ZhbHVlPyAnVFJVRSc6ICdGQUxTRSc7XG5cblx0XHRjYXNlICdvYmplY3QnOlxuXHRcdFx0Ly8gbnVsbFxuXHRcdFx0aWYobnVsbCA9PT0gel92YWx1ZSkge1xuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblx0XHRcdH1cblx0XHRcdC8vIHJhdyBzcWxcblx0XHRcdGVsc2UgaWYoJ3N0cmluZycgPT09IHR5cGVvZiB6X3ZhbHVlLnJhdykge1xuXHRcdFx0XHRyZXR1cm4gel92YWx1ZS5yYXc7XG5cdFx0XHR9XG5cblx0XHRcdC8vIGRlZmF1bHRcblx0XHRcdHJldHVybiBlc2NhcGVfbGl0ZXJhbChcblx0XHRcdFx0SlNPTi5zdHJpbmdpZnkoel92YWx1ZSlcblx0XHRcdCk7XG5cblx0XHRjYXNlICdmdW5jdGlvbic6XG5cdFx0XHRyZXR1cm4gel92YWx1ZSgpKycnO1xuXG5cdFx0ZGVmYXVsdDpcblx0XHRcdHRocm93ICd1bmFibGUgdG8gY29udmVydCBpbnRvIHNhZmUgdmFsdWU6IFwiJHt6X3ZhbHVlfVwiJztcblx0fVxufTtcblxuLy8gXG5jb25zdCBIX1dSSVRFUlMgPSB7XG5cblx0Ly8gY29udmVydCBoYXNoIHF1ZXJ5IHRvIHN0cmluZyBxdWVyeVxuXHRpbnNlcnQoaF9xdWVyeSkge1xuXG5cdFx0Ly8gcmVmIGluc2VydCBsaXN0XG5cdFx0bGV0IGFfaW5zZXJ0cyA9IGhfcXVlcnkuaW5zZXJ0O1xuXG5cdFx0Ly8gcHJlcCBsaXN0IG9mIHJvd3MgdGhhdCBoYXZlIGJlZW4gb2JzZXJ2ZWQgZnJvbSBmaXJzdCBlbGVtZW50XG5cdFx0bGV0IGFfa2V5cyA9IE9iamVjdC5rZXlzKGFfaW5zZXJ0c1swXSk7XG5cblx0XHQvLyBidWlsZCBjb2x1bW5zIHBhcnQgb2Ygc3FsIHN0cmluZ1xuXHRcdGxldCBzX2tleXMgPSBhX2tleXMubWFwKHNfa2V5ID0+IGBcIiR7c19rZXl9XCJgKS5qb2luKCcsJyk7XG5cblx0XHQvLyBidWlsZCB2YWx1ZXMgcGFydCBvZiBzcWwgc3RyaW5nXG5cdFx0bGV0IGFfcm93cyA9IFtdO1xuXG5cdFx0Ly8gZWFjaCBpbnNlcnQgcm93XG5cdFx0YV9pbnNlcnRzLmZvckVhY2goKGhfcm93KSA9PiB7XG5cblx0XHRcdC8vIGxpc3Qgb2YgdmFsdWVzIHRvIGluc2VydCBmb3IgdGhpcyByb3dcblx0XHRcdGxldCBhX3ZhbHVlcyA9IFtdO1xuXG5cdFx0XHQvLyBlYWNoIGtleS12YWx1ZSBwYWlyIGluIHJvd1xuXHRcdFx0Zm9yKGxldCBzX2tleSBpbiBoX3Jvdykge1xuXG5cdFx0XHRcdC8vIGtleSBpcyBtaXNzaW5nIGZyb20gYWNjZXB0ZWQgdmFsdWVzIHNlY3Rpb25cblx0XHRcdFx0aWYoLTEgPT09IGFfa2V5cy5pbmRleE9mKHNfa2V5KSkge1xuXHRcdFx0XHRcdHJldHVybiBsb2NhbC5mYWlsKCduZXcga2V5IFwiJHtzX2tleX1cIiBpbnRyb2R1Y2VkIGFmdGVyIGZpcnN0IGVsZW1lbnQgaW4gaW5zZXJ0IGNoYWluJyk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBhcHBlbmQgdG8gdmFsdWVzXG5cdFx0XHRcdGFfdmFsdWVzLnB1c2godmFsdWlmeShoX3Jvd1tzX2tleV0pKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gcHVzaCByb3cgdG8gdmFsdWVzIGxpc3Rcblx0XHRcdGFfcm93cy5wdXNoKGAoJHthX3ZhbHVlcy5qb2luKCcsJyl9KWApO1xuXHRcdH0pO1xuXG5cdFx0Ly9cblx0XHRsZXQgc190YWlsID0gJyc7XG5cblx0XHQvL1xuXHRcdGlmKGhfcXVlcnkuY29uZmxpY3RfdGFyZ2V0ICYmIGhfcXVlcnkuY29uZmxpY3RfYWN0aW9uKSB7XG5cdFx0XHRzX3RhaWwgKz0gYG9uIGNvbmZsaWN0ICR7aF9xdWVyeS5jb25mbGljdF90YXJnZXR9ICR7aF9xdWVyeS5jb25mbGljdF9hY3Rpb259YDtcblx0XHR9XG5cblx0XHQvLyBwcmVwIHNxbCBxdWVyeSBzdHJpbmdcblx0XHRyZXR1cm4gYGluc2VydCBpbnRvIFwiJHtoX3F1ZXJ5LmludG99XCIgKCR7c19rZXlzfSkgdmFsdWVzICR7YV9yb3dzLmpvaW4oJywnKX0gJHtzX3RhaWx9YDtcblx0fSxcbn07XG5cblxuXG4vKipcbiogY2xhc3M6XG4qKi9cbmNvbnN0IGxvY2FsID0gY2xhc3NlcigncGonLCBmdW5jdGlvbih6X2NvbmZpZykge1xuXG5cdC8vXG5cdGxldCBhX3F1ZXVlID0gW107XG5cblx0Ly8gY29ubmVjdGlvbiBzdHJpbmdcblx0bGV0IHNfY29ubmVjdGlvbiA9ICgoKSA9PiB7XG5cblx0XHQvLyBzZXR1cCBwb3N0Z3JlcyBjb25uZWN0aW9uXG5cdFx0c3dpdGNoKHR5cGVvZiB6X2NvbmZpZykge1xuXG5cdFx0XHQvLyBjb25maWcgZ2l2ZW4gYXMgc3RyaW5nXG5cdFx0XHRjYXNlICdzdHJpbmcnOlxuXHRcdFx0XHQvLyBjb25uZWN0aW9uIHN0cmluZ1xuXHRcdFx0XHRyZXR1cm4gY29ubmVjdF9zdHJpbmcoel9jb25maWcpO1xuXHRcdH1cblxuXHRcdHJldHVybiBmYWxzZTtcblx0fSkoKTtcblxuXHQvL1xuXHRpZighc19jb25uZWN0aW9uKSByZXR1cm4gbG9jYWwuZmFpbCgnZmFpbGVkIHRvIHVuZGVyc3RhbmQgY29ubmVjdGlvbiBjb25maWcgYXJndW1lbnQnKTtcblxuXHQvL1xuXHRsb2NhbC5pbmZvKGBjb25uZWN0aW5nIHRvIHBvc3RncmVzIHcvICR7c19jb25uZWN0aW9ufWApO1xuXG5cdC8vIHBvc3RncmVzIGNsaWVudFxuXHRsZXQgeV9jbGllbnQgPSBuZXcgcGcuQ2xpZW50KHNfY29ubmVjdGlvbik7XG5cblx0Ly8gaW5pdGlhdGUgY29ubmVjdGlvblxuXHR5X2NsaWVudC5jb25uZWN0KChlX2Nvbm5lY3QpID0+IHtcblxuXHRcdC8vIGNvbm5lY3Rpb24gZXJyb3Jcblx0XHRpZihlX2Nvbm5lY3QpIHtcblx0XHRcdGxvY2FsLmZhaWwoJ2ZhaWxlZCB0byBjb25uZWN0Jyk7XG5cdFx0fVxuXG5cdFx0Ly8gXG5cdFx0bmV4dF9xdWVyeSgpO1xuXHR9KTtcblxuXHQvL1xuXHRjb25zdCBuZXh0X3F1ZXJ5ID0gKCkgPT4ge1xuXG5cdFx0Ly8gcXVldWUgaXMgbm90IGVtcHR5XG5cdFx0aWYoYV9xdWV1ZS5sZW5ndGgpIHtcblx0XHRcdC8vIHNoaWZ0IGZpcnN0IHF1ZXJ5IGZyb20gYmVnaW5uaW5nXG5cdFx0XHRsZXQgaF9xdWVyeSA9IGFfcXVldWUuc2hpZnQoKTtcblxuXHRcdFx0Ly8gZXhlY3V0ZSBxdWVyeVxuXHRcdFx0eV9jbGllbnQucXVlcnkoaF9xdWVyeS5zcWwsIGhfcXVlcnkuY2FsbGJhY2spO1xuXHRcdH1cblx0fTtcblxuXHQvLyBzdWJtaXQgYSBxdWVyeSB0byBiZSBleGVjdXRlZFxuXHRjb25zdCBzdWJtaXRfcXVlcnkgPSAoc19xdWVyeSwgZl9va2F5KSA9PiB7XG5cblx0XHQvLyBwdXNoIHRvIHF1ZXVlXG5cdFx0YV9xdWV1ZS5wdXNoKHtcblx0XHRcdHNxbDogc19xdWVyeSxcblx0XHRcdGNhbGxiYWNrOiBmX29rYXksXG5cdFx0fSk7XG5cblx0XHQvLyBxdWV1ZSB3YXMgZW1wdHlcblx0XHRpZigxID09PSBhX3F1ZXVlLmxlbmd0aCkge1xuXHRcdFx0Ly8gaW5pdGlhdGVcblx0XHRcdG5leHRfcXVlcnkoKTtcblx0XHR9XG5cdH07XG5cblx0Ly8gcXVlcnktYnVpbGRpbmcgZm9yIGluc2VydGlvblxuXHRjb25zdCBxYl9pbnNlcnQgPSAoaF9xdWVyeSkgPT4ge1xuXG5cdFx0Ly8gZGVmYXVsdCBpbnNlcnQgaGFzaFxuXHRcdGhfcXVlcnkuaW5zZXJ0ID0gaF9xdWVyeS5pbnNlcnQgfHwgW107XG5cblx0XHQvL1xuXHRcdGNvbnN0IHNlbGYgPSB7XG5cblx0XHRcdC8vIGluc2VydCByb3dzXG5cdFx0XHRpbnNlcnQoel92YWx1ZXMpIHtcblxuXHRcdFx0XHQvLyBsaXN0IG9mIHJvd3MgdG8gaW5zZXJ0IHNpbXVsdGFuZW91c2x5XG5cdFx0XHRcdGlmKEFycmF5LmlzQXJyYXkoel92YWx1ZXMpKSB7XG5cblx0XHRcdFx0XHQvLyBhcHBlbmQgdG8gZXhpc3RpbmcgaW5zZXJ0aW9uIGxpc3Rcblx0XHRcdFx0XHRoX3F1ZXJ5Lmluc2VydC5wdXNoKC4uLnpfdmFsdWVzKTtcblx0XHRcdFx0fVxuXHRcdFx0XHQvLyB2YWx1ZXMgaGFzaFxuXHRcdFx0XHRlbHNlIGlmKCdvYmplY3QnID09PSB0eXBlb2Ygel92YWx1ZXMpIHtcblxuXHRcdFx0XHRcdC8vIHNpbmdsZSByb3cgdG8gYXBwZW5kIHRvIGluc2VydGlvbiBsaXN0XG5cdFx0XHRcdFx0aF9xdWVyeS5pbnNlcnQucHVzaCh6X3ZhbHVlcyk7XG5cdFx0XHRcdH1cblx0XHRcdFx0Ly8gb3RoZXIgdHlwZVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRsb2NhbC5mYWlsKCdpbnZhbGlkIHR5cGUgZm9yIGluc2VydGlvbiBhcmd1bWVudCcpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gbm9ybWFsIGluc2VydCBhY3Rpb25zXG5cdFx0XHRcdHJldHVybiBzZWxmO1xuXHRcdFx0fSxcblxuXHRcdFx0Ly8gb24gY29uZmxpY3Rcblx0XHRcdG9uX2NvbmZsaWN0KHNfdGFyZ2V0KSB7XG5cblx0XHRcdFx0Ly8gc2V0IGNvbmZsaWN0IHRhcmdldFxuXHRcdFx0XHRoX3F1ZXJ5LmNvbmZsaWN0X3RhcmdldCA9IGAoJHtzX3RhcmdldH0pYDtcblxuXHRcdFx0XHQvLyBuZXh0IGFjdGlvbiBoYXNoXG5cdFx0XHRcdHJldHVybiB7XG5cblx0XHRcdFx0XHQvLyBkbyBub3RoaW5nXG5cdFx0XHRcdFx0ZG9fbm90aGluZygpIHtcblxuXHRcdFx0XHRcdFx0Ly8gc2V0IGNvbmZsaWN0IGFjdGlvblxuXHRcdFx0XHRcdFx0aF9xdWVyeS5jb25mbGljdF9hY3Rpb24gPSAnZG8gbm90aGluZyc7XG5cblx0XHRcdFx0XHRcdC8vIG5vcm1hbCBpbnNlcnQgYWN0aW9uc1xuXHRcdFx0XHRcdFx0cmV0dXJuIHNlbGY7XG5cdFx0XHRcdFx0fSxcblx0XHRcdFx0fTtcblx0XHRcdH0sXG5cblx0XHRcdC8vXG5cdFx0XHRkZWJ1ZygpIHtcblxuXHRcdFx0XHQvLyBnZW5lcmF0ZSBzcWxcblx0XHRcdFx0bGV0IHNfc3FsID0gSF9XUklURVJTLmluc2VydChoX3F1ZXJ5KTtcblxuXHRcdFx0XHRkZWJ1Z2dlcjtcblx0XHRcdFx0cmV0dXJuIHNlbGY7XG5cdFx0XHR9LFxuXG5cdFx0XHQvL1xuXHRcdFx0ZXhlYyhmX29rYXkpIHtcblxuXHRcdFx0XHQvLyBnZW5lcmF0ZSBzcWxcblx0XHRcdFx0bGV0IHNfc3FsID0gSF9XUklURVJTLmluc2VydChoX3F1ZXJ5KTtcblxuXHRcdFx0XHQvLyBzdWJtaXRcblx0XHRcdFx0c3VibWl0X3F1ZXJ5KHNfc3FsLCAoZV9pbnNlcnQsIHdfcmVzdWx0KSA9PiB7XG5cblx0XHRcdFx0XHQvLyBpbnNlcnQgZXJyb3Jcblx0XHRcdFx0XHRpZihlX2luc2VydCkge1xuXHRcdFx0XHRcdFx0bG9jYWwuZmFpbChlX2luc2VydCk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly9cblx0XHRcdFx0XHRpZignZnVuY3Rpb24nID09PSB0eXBlb2YgZl9va2F5KSB7XG5cdFx0XHRcdFx0XHRmX29rYXkod19yZXN1bHQpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSk7XG5cdFx0XHR9LFxuXHRcdH07XG5cblx0XHQvL1xuXHRcdHJldHVybiBzZWxmO1xuXHR9O1xuXG5cblx0Ly9cblx0cmV0dXJuIGNsYXNzZXIub3BlcmF0b3IoZnVuY3Rpb24oKSB7XG5cblx0fSwge1xuXG5cdFx0Ly8gc3RhcnQgb2YgYW4gaW5zZXJ0IHF1ZXJ5XG5cdFx0aW50byhzX3RhYmxlKSB7XG5cdFx0XHRyZXR1cm4gcWJfaW5zZXJ0KHtcblx0XHRcdFx0aW50bzogc190YWJsZSxcblx0XHRcdH0pO1xuXHRcdH0sXG5cdH0pO1xufSk7XG5cbmV4cG9ydCBkZWZhdWx0IGxvY2FsO1xuIl0sInNvdXJjZVJvb3QiOiIvc291cmNlLyJ9
;