UNPKG

firebase-bolt

Version:

Firebase Bolt Security and Modeling Language Compiler

194 lines (192 loc) 23.3 kB
"use strict"; exports.__esModule = true; /* * Firebase helper functions for REST API (using Promises). * * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var https = require("https"); var util = require("./util"); var querystring = require("querystring"); var uuid = require('node-uuid'); var FirebaseTokenGenerator = require('firebase-token-generator'); var FIREBASE_HOST = 'firebaseio.com'; var DEBUG_HEADER = 'x-firebase-auth-debug'; exports.RULES_LOCATION = '/.settings/rules'; exports.TIMESTAMP = { '.sv': 'timestamp' }; var Client = /** @class */ (function () { function Client(appName, authToken, uid) { this.appName = appName; this.authToken = authToken; this.uid = uid; this.debug = false; } Client.prototype.setDebug = function (debug) { if (debug === void 0) { debug = true; } this.debug = debug; return this; }; Client.prototype.get = function (location) { return this.request({ method: 'GET' }, location); }; Client.prototype.put = function (location, content) { return this.request({ method: 'PUT', print: 'silent' }, location, content); }; Client.prototype.request = function (opt, path, content) { var options = { hostname: this.appName + '.' + FIREBASE_HOST, path: path + '.json', method: opt.method }; var query = {}; if (opt.print) { query.print = opt.print; } if (this.authToken) { query.auth = this.authToken; } if (Object.keys(query).length > 0) { options.path += '?' + querystring.stringify(query); } content = util.prettyJSON(content); return request(options, content, this.debug).then(function (body) { return body === '' ? null : JSON.parse(body); }); }; return Client; }()); exports.Client = Client; var ridNext = 0; function request(options, content, debug) { ridNext += 1; var rid = ridNext; function log(s) { if (debug) { console.error('Request<' + rid + '>: ' + s); } } log('Request: ' + util.prettyJSON(options)); if (content) { log('Body: \'' + content + '\''); } return new Promise(function (resolve, reject) { // TODO: Why isn't this argument typed as per https.request? var req = https.request(options, function (res) { var chunks = []; res.on('data', function (body) { chunks.push(body); }); res.on('end', function () { var result = chunks.join(''); log('Result (' + res.statusCode + '): \'' + result + '\''); var message = 'Status = ' + res.statusCode + ' ' + result; // Dump debug information if present for both successful and failed // requests. if (res.headers[DEBUG_HEADER]) { var formattedHeader = res.headers[DEBUG_HEADER].split(' /').join('\n /'); log(formattedHeader); message += '\n' + formattedHeader; } if (res.statusCode && Math.floor(res.statusCode / 100) !== 2) { reject(new Error(message)); } else { resolve(result); } }); }); if (content) { req.write(content, 'utf8'); } req.end(); req.on('error', function (error) { log('Request error: ' + error); reject(error); }); }); } // opts { debug: Boolean, admin: Boolean } function generateUidAuthToken(secret, opts) { opts = util.extend({ debug: false, admin: false }, opts); var tokenGenerator = new FirebaseTokenGenerator(secret); var uid = uuid.v4(); var token = tokenGenerator.createToken({ uid: uid }, opts); return { uid: uid, token: token }; } exports.generateUidAuthToken = generateUidAuthToken; /** * Fancy ID generator that creates 20-character string identifiers with the * following properties: * * 1. They're based on timestamp so that they sort *after* any existing ids. * 2. They contain 72-bits of random data after the timestamp so that IDs won't * collide with other clients' IDs. * 3. They sort *lexicographically* (so the timestamp is converted to characters * that will sort properly). * 4. They're monotonically increasing. Even if you generate more than one in * the same timestamp, the latter ones will sort after the former ones. We do * this by using the previous random bits but "incrementing" them by 1 (only in * the case of a timestamp collision). */ // Modeled after base64 web-safe chars, but ordered by ASCII. var PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'; // Timestamp of last push, used to prevent local collisions if you push twice in // one ms. var lastPushTime = 0; // We generate 72-bits of randomness which get turned into 12 characters and // appended to the timestamp to prevent collisions with other clients. We store // the last characters we generated because in the event of a collision, we'll // use those same characters except "incremented" by one. var lastRandChars = []; function generatePushID() { var now = new Date().getTime(); var duplicateTime = (now === lastPushTime); lastPushTime = now; var timeStampChars = new Array(8); for (var i = 7; i >= 0; i--) { timeStampChars[i] = PUSH_CHARS.charAt(now % 64); // NOTE: Can't use << here because javascript will convert to int and lose // the upper bits. now = Math.floor(now / 64); } if (now !== 0) { throw new Error('We should have converted the entire timestamp.'); } var id = timeStampChars.join(''); if (!duplicateTime) { for (i = 0; i < 12; i++) { lastRandChars[i] = Math.floor(Math.random() * 64); } } else { // If the timestamp hasn't changed since last push, use the same random // number, except incremented by 1. for (i = 11; i >= 0 && lastRandChars[i] === 63; i--) { lastRandChars[i] = 0; } lastRandChars[i]++; } for (i = 0; i < 12; i++) { id += PUSH_CHARS.charAt(lastRandChars[i]); } if (id.length !== 20) { throw new Error('Length should be 20.'); } return id; } exports.generatePushID = generatePushID; //# sourceMappingURL=data:application/json;charset=utf8;base64,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SUFBSSxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztLQUNuRTtJQUVELElBQUksRUFBRSxHQUFHLGNBQWMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFFakMsSUFBSSxDQUFDLGFBQWEsRUFBRTtRQUNsQixLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUN2QixhQUFhLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7U0FDbkQ7S0FDRjtTQUFNO1FBQ0wsdUVBQXVFO1FBQ3ZFLG1DQUFtQztRQUNuQyxLQUFLLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxhQUFhLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ25ELGFBQWEsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDdEI7UUFDRCxhQUFhLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUNwQjtJQUNELEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ3ZCLEVBQUUsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0tBQzNDO0lBQ0QsSUFBSSxFQUFFLENBQUMsTUFBTSxLQUFLLEVBQUUsRUFBRTtRQUNwQixNQUFNLElBQUksS0FBSyxDQUFDLHNCQUFzQixDQUFDLENBQUM7S0FDekM7SUFFRCxPQUFPLEVBQUUsQ0FBQztBQUNaLENBQUM7QUF0Q0Qsd0NBc0NDIiwiZmlsZSI6ImZpcmViYXNlLXJlc3QuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogRmlyZWJhc2UgaGVscGVyIGZ1bmN0aW9ucyBmb3IgUkVTVCBBUEkgKHVzaW5nIFByb21pc2VzKS5cbiAqXG4gKiBDb3B5cmlnaHQgMjAxNSBHb29nbGUgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuaW1wb3J0IGh0dHBzID0gcmVxdWlyZSgnaHR0cHMnKTtcbmltcG9ydCBodHRwID0gcmVxdWlyZSgnaHR0cCcpO1xuaW1wb3J0ICogYXMgdXRpbCBmcm9tICcuL3V0aWwnO1xuaW1wb3J0IHF1ZXJ5c3RyaW5nID0gcmVxdWlyZSgncXVlcnlzdHJpbmcnKTtcbmxldCB1dWlkID0gcmVxdWlyZSgnbm9kZS11dWlkJyk7XG52YXIgRmlyZWJhc2VUb2tlbkdlbmVyYXRvciA9IHJlcXVpcmUoJ2ZpcmViYXNlLXRva2VuLWdlbmVyYXRvcicpO1xuXG52YXIgRklSRUJBU0VfSE9TVCA9ICdmaXJlYmFzZWlvLmNvbSc7XG52YXIgREVCVUdfSEVBREVSID0gJ3gtZmlyZWJhc2UtYXV0aC1kZWJ1Zyc7XG5cbmV4cG9ydCB2YXIgUlVMRVNfTE9DQVRJT04gPSAnLy5zZXR0aW5ncy9ydWxlcyc7XG5leHBvcnQgdmFyIFRJTUVTVEFNUCA9IHtcbiAgJy5zdic6ICd0aW1lc3RhbXAnXG59O1xuXG5leHBvcnQgdHlwZSBSZXF1ZXN0T3B0aW9ucyA9IHtcbiAgbWV0aG9kOiBzdHJpbmcsXG4gIHByaW50Pzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgQ2xpZW50IHtcbiAgcHJpdmF0ZSBkZWJ1ZyA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgICAgcHJpdmF0ZSBhcHBOYW1lOiBzdHJpbmcsIHByaXZhdGUgYXV0aFRva2VuPzogc3RyaW5nLFxuICAgICAgcHVibGljIHVpZD86IHN0cmluZykge31cblxuICBzZXREZWJ1ZyhkZWJ1ZyA9IHRydWUpIHtcbiAgICB0aGlzLmRlYnVnID0gZGVidWc7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXQobG9jYXRpb246IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIHRoaXMucmVxdWVzdCh7bWV0aG9kOiAnR0VUJ30sIGxvY2F0aW9uKTtcbiAgfVxuXG4gIHB1dChsb2NhdGlvbjogc3RyaW5nLCBjb250ZW50OiBhbnkpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiB0aGlzLnJlcXVlc3Qoe21ldGhvZDogJ1BVVCcsIHByaW50OiAnc2lsZW50J30sIGxvY2F0aW9uLCBjb250ZW50KTtcbiAgfVxuXG4gIHJlcXVlc3Qob3B0OiBSZXF1ZXN0T3B0aW9ucywgcGF0aDogc3RyaW5nLCBjb250ZW50PzogYW55KSB7XG4gICAgdmFyIG9wdGlvbnMgPSB7XG4gICAgICBob3N0bmFtZTogdGhpcy5hcHBOYW1lICsgJy4nICsgRklSRUJBU0VfSE9TVCxcbiAgICAgIHBhdGg6IHBhdGggKyAnLmpzb24nLFxuICAgICAgbWV0aG9kOiBvcHQubWV0aG9kLFxuICAgIH07XG5cbiAgICB2YXIgcXVlcnk6IGFueSA9IHt9O1xuICAgIGlmIChvcHQucHJpbnQpIHtcbiAgICAgIHF1ZXJ5LnByaW50ID0gb3B0LnByaW50O1xuICAgIH1cblxuICAgIGlmICh0aGlzLmF1dGhUb2tlbikge1xuICAgICAgcXVlcnkuYXV0aCA9IHRoaXMuYXV0aFRva2VuO1xuICAgIH1cblxuICAgIGlmIChPYmplY3Qua2V5cyhxdWVyeSkubGVuZ3RoID4gMCkge1xuICAgICAgb3B0aW9ucy5wYXRoICs9ICc/JyArIHF1ZXJ5c3RyaW5nLnN0cmluZ2lmeShxdWVyeSk7XG4gICAgfVxuXG4gICAgY29udGVudCA9IHV0aWwucHJldHR5SlNPTihjb250ZW50KTtcblxuICAgIHJldHVybiByZXF1ZXN0KG9wdGlvbnMsIGNvbnRlbnQsIHRoaXMuZGVidWcpLnRoZW4oZnVuY3Rpb24oYm9keTogc3RyaW5nKSB7XG4gICAgICByZXR1cm4gYm9keSA9PT0gJycgPyBudWxsIDogSlNPTi5wYXJzZShib2R5KTtcbiAgICB9KTtcbiAgfVxufVxuXG52YXIgcmlkTmV4dCA9IDA7XG5cbmZ1bmN0aW9uIHJlcXVlc3Qob3B0aW9uczogYW55LCBjb250ZW50OiBhbnksIGRlYnVnOiBib29sZWFuKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgcmlkTmV4dCArPSAxO1xuICB2YXIgcmlkID0gcmlkTmV4dDtcblxuICBmdW5jdGlvbiBsb2coczogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKGRlYnVnKSB7XG4gICAgICBjb25zb2xlLmVycm9yKCdSZXF1ZXN0PCcgKyByaWQgKyAnPjogJyArIHMpO1xuICAgIH1cbiAgfVxuXG4gIGxvZygnUmVxdWVzdDogJyArIHV0aWwucHJldHR5SlNPTihvcHRpb25zKSk7XG4gIGlmIChjb250ZW50KSB7XG4gICAgbG9nKCdCb2R5OiBcXCcnICsgY29udGVudCArICdcXCcnKTtcbiAgfVxuXG4gIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAvLyBUT0RPOiBXaHkgaXNuJ3QgdGhpcyBhcmd1bWVudCB0eXBlZCBhcyBwZXIgaHR0cHMucmVxdWVzdD9cbiAgICB2YXIgcmVxID0gaHR0cHMucmVxdWVzdChvcHRpb25zLCBmdW5jdGlvbihyZXM6IGh0dHAuQ2xpZW50UmVzcG9uc2UpIHtcbiAgICAgIHZhciBjaHVua3MgPSA8c3RyaW5nW10+W107XG5cbiAgICAgIHJlcy5vbignZGF0YScsIGZ1bmN0aW9uKGJvZHk6IHN0cmluZykge1xuICAgICAgICBjaHVua3MucHVzaChib2R5KTtcbiAgICAgIH0pO1xuXG4gICAgICByZXMub24oJ2VuZCcsIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgcmVzdWx0OiBzdHJpbmcgPSBjaHVua3Muam9pbignJyk7XG4gICAgICAgIGxvZygnUmVzdWx0ICgnICsgcmVzLnN0YXR1c0NvZGUgKyAnKTogXFwnJyArIHJlc3VsdCArICdcXCcnKTtcbiAgICAgICAgbGV0IG1lc3NhZ2UgPSAnU3RhdHVzID0gJyArIHJlcy5zdGF0dXNDb2RlICsgJyAnICsgcmVzdWx0O1xuXG4gICAgICAgIC8vIER1bXAgZGVidWcgaW5mb3JtYXRpb24gaWYgcHJlc2VudCBmb3IgYm90aCBzdWNjZXNzZnVsIGFuZCBmYWlsZWRcbiAgICAgICAgLy8gcmVxdWVzdHMuXG4gICAgICAgIGlmIChyZXMuaGVhZGVyc1tERUJVR19IRUFERVJdKSB7XG4gICAgICAgICAgbGV0IGZvcm1hdHRlZEhlYWRlciA9XG4gICAgICAgICAgICAgIHJlcy5oZWFkZXJzW0RFQlVHX0hFQURFUl0uc3BsaXQoJyAvJykuam9pbignXFxuICAvJyk7XG4gICAgICAgICAgbG9nKGZvcm1hdHRlZEhlYWRlcik7XG4gICAgICAgICAgbWVzc2FnZSArPSAnXFxuJyArIGZvcm1hdHRlZEhlYWRlcjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyZXMuc3RhdHVzQ29kZSAmJiBNYXRoLmZsb29yKHJlcy5zdGF0dXNDb2RlIC8gMTAwKSAhPT0gMikge1xuICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IobWVzc2FnZSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJlc29sdmUocmVzdWx0KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpZiAoY29udGVudCkge1xuICAgICAgcmVxLndyaXRlKGNvbnRlbnQsICd1dGY4Jyk7XG4gICAgfVxuICAgIHJlcS5lbmQoKTtcblxuICAgIHJlcS5vbignZXJyb3InLCBmdW5jdGlvbihlcnJvcjogRXJyb3IpIHtcbiAgICAgIGxvZygnUmVxdWVzdCBlcnJvcjogJyArIGVycm9yKTtcbiAgICAgIHJlamVjdChlcnJvcik7XG4gICAgfSk7XG4gIH0pO1xufVxuXG4vLyBvcHRzIHsgZGVidWc6IEJvb2xlYW4sIGFkbWluOiBCb29sZWFuIH1cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZVVpZEF1dGhUb2tlbihzZWNyZXQ6IHN0cmluZywgb3B0czogYW55KSB7XG4gIG9wdHMgPSB1dGlsLmV4dGVuZCh7ZGVidWc6IGZhbHNlLCBhZG1pbjogZmFsc2V9LCBvcHRzKTtcblxuICB2YXIgdG9rZW5HZW5lcmF0b3IgPSBuZXcgRmlyZWJhc2VUb2tlbkdlbmVyYXRvcihzZWNyZXQpO1xuICB2YXIgdWlkID0gdXVpZC52NCgpO1xuICB2YXIgdG9rZW4gPSB0b2tlbkdlbmVyYXRvci5jcmVhdGVUb2tlbih7dWlkOiB1aWR9LCBvcHRzKTtcbiAgcmV0dXJuIHt1aWQ6IHVpZCwgdG9rZW46IHRva2VufTtcbn1cblxuLyoqXG4gKiBGYW5jeSBJRCBnZW5lcmF0b3IgdGhhdCBjcmVhdGVzIDIwLWNoYXJhY3RlciBzdHJpbmcgaWRlbnRpZmllcnMgd2l0aCB0aGVcbiAqIGZvbGxvd2luZyBwcm9wZXJ0aWVzOlxuICpcbiAqIDEuIFRoZXkncmUgYmFzZWQgb24gdGltZXN0YW1wIHNvIHRoYXQgdGhleSBzb3J0ICphZnRlciogYW55IGV4aXN0aW5nIGlkcy5cbiAqIDIuIFRoZXkgY29udGFpbiA3Mi1iaXRzIG9mIHJhbmRvbSBkYXRhIGFmdGVyIHRoZSB0aW1lc3RhbXAgc28gdGhhdCBJRHMgd29uJ3RcbiAqIGNvbGxpZGUgd2l0aCBvdGhlciBjbGllbnRzJyBJRHMuXG4gKiAzLiBUaGV5IHNvcnQgKmxleGljb2dyYXBoaWNhbGx5KiAoc28gdGhlIHRpbWVzdGFtcCBpcyBjb252ZXJ0ZWQgdG8gY2hhcmFjdGVyc1xuICogdGhhdCB3aWxsIHNvcnQgcHJvcGVybHkpLlxuICogNC4gVGhleSdyZSBtb25vdG9uaWNhbGx5IGluY3JlYXNpbmcuICBFdmVuIGlmIHlvdSBnZW5lcmF0ZSBtb3JlIHRoYW4gb25lIGluXG4gKiB0aGUgc2FtZSB0aW1lc3RhbXAsIHRoZSBsYXR0ZXIgb25lcyB3aWxsIHNvcnQgYWZ0ZXIgdGhlIGZvcm1lciBvbmVzLiAgV2UgZG9cbiAqIHRoaXMgYnkgdXNpbmcgdGhlIHByZXZpb3VzIHJhbmRvbSBiaXRzIGJ1dCBcImluY3JlbWVudGluZ1wiIHRoZW0gYnkgMSAob25seSBpblxuICogdGhlIGNhc2Ugb2YgYSB0aW1lc3RhbXAgY29sbGlzaW9uKS5cbiAqL1xuXG4vLyBNb2RlbGVkIGFmdGVyIGJhc2U2NCB3ZWItc2FmZSBjaGFycywgYnV0IG9yZGVyZWQgYnkgQVNDSUkuXG52YXIgUFVTSF9DSEFSUyA9XG4gICAgJy0wMTIzNDU2Nzg5QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpfYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXonO1xuXG4vLyBUaW1lc3RhbXAgb2YgbGFzdCBwdXNoLCB1c2VkIHRvIHByZXZlbnQgbG9jYWwgY29sbGlzaW9ucyBpZiB5b3UgcHVzaCB0d2ljZSBpblxuLy8gb25lIG1zLlxudmFyIGxhc3RQdXNoVGltZSA9IDA7XG5cbi8vIFdlIGdlbmVyYXRlIDcyLWJpdHMgb2YgcmFuZG9tbmVzcyB3aGljaCBnZXQgdHVybmVkIGludG8gMTIgY2hhcmFjdGVycyBhbmRcbi8vIGFwcGVuZGVkIHRvIHRoZSB0aW1lc3RhbXAgdG8gcHJldmVudCBjb2xsaXNpb25zIHdpdGggb3RoZXIgY2xpZW50cy4gIFdlIHN0b3JlXG4vLyB0aGUgbGFzdCBjaGFyYWN0ZXJzIHdlIGdlbmVyYXRlZCBiZWNhdXNlIGluIHRoZSBldmVudCBvZiBhIGNvbGxpc2lvbiwgd2UnbGxcbi8vIHVzZSB0aG9zZSBzYW1lIGNoYXJhY3RlcnMgZXhjZXB0IFwiaW5jcmVtZW50ZWRcIiBieSBvbmUuXG52YXIgbGFzdFJhbmRDaGFycyA9IDxudW1iZXJbXT5bXTtcblxuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlUHVzaElEKCk6IHN0cmluZyB7XG4gIHZhciBub3cgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgdmFyIGR1cGxpY2F0ZVRpbWUgPSAobm93ID09PSBsYXN0UHVzaFRpbWUpO1xuICBsYXN0UHVzaFRpbWUgPSBub3c7XG5cbiAgdmFyIHRpbWVTdGFtcENoYXJzID0gbmV3IEFycmF5KDgpO1xuICBmb3IgKHZhciBpID0gNzsgaSA+PSAwOyBpLS0pIHtcbiAgICB0aW1lU3RhbXBDaGFyc1tpXSA9IFBVU0hfQ0hBUlMuY2hhckF0KG5vdyAlIDY0KTtcbiAgICAvLyBOT1RFOiBDYW4ndCB1c2UgPDwgaGVyZSBiZWNhdXNlIGphdmFzY3JpcHQgd2lsbCBjb252ZXJ0IHRvIGludCBhbmQgbG9zZVxuICAgIC8vIHRoZSB1cHBlciBiaXRzLlxuICAgIG5vdyA9IE1hdGguZmxvb3Iobm93IC8gNjQpO1xuICB9XG4gIGlmIChub3cgIT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1dlIHNob3VsZCBoYXZlIGNvbnZlcnRlZCB0aGUgZW50aXJlIHRpbWVzdGFtcC4nKTtcbiAgfVxuXG4gIHZhciBpZCA9IHRpbWVTdGFtcENoYXJzLmpvaW4oJycpO1xuXG4gIGlmICghZHVwbGljYXRlVGltZSkge1xuICAgIGZvciAoaSA9IDA7IGkgPCAxMjsgaSsrKSB7XG4gICAgICBsYXN0UmFuZENoYXJzW2ldID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogNjQpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICAvLyBJZiB0aGUgdGltZXN0YW1wIGhhc24ndCBjaGFuZ2VkIHNpbmNlIGxhc3QgcHVzaCwgdXNlIHRoZSBzYW1lIHJhbmRvbVxuICAgIC8vIG51bWJlciwgZXhjZXB0IGluY3JlbWVudGVkIGJ5IDEuXG4gICAgZm9yIChpID0gMTE7IGkgPj0gMCAmJiBsYXN0UmFuZENoYXJzW2ldID09PSA2MzsgaS0tKSB7XG4gICAgICBsYXN0UmFuZENoYXJzW2ldID0gMDtcbiAgICB9XG4gICAgbGFzdFJhbmRDaGFyc1tpXSsrO1xuICB9XG4gIGZvciAoaSA9IDA7IGkgPCAxMjsgaSsrKSB7XG4gICAgaWQgKz0gUFVTSF9DSEFSUy5jaGFyQXQobGFzdFJhbmRDaGFyc1tpXSk7XG4gIH1cbiAgaWYgKGlkLmxlbmd0aCAhPT0gMjApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0xlbmd0aCBzaG91bGQgYmUgMjAuJyk7XG4gIH1cblxuICByZXR1cm4gaWQ7XG59XG4iXX0=