UNPKG

@hpcc-js/comms

Version:
1,397 lines (1,295 loc) 214 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var util = require('@hpcc-js/util'); var fs = require('fs'); var path = require('path'); var cp = require('child_process'); var os = require('os'); var tmp = require('tmp'); var xmldom = require('xmldom'); var fetch$1 = _interopDefault(require('node-fetch')); var safeBuffer = require('safe-buffer'); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. 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 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ 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); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __awaiter(thisArg, _arguments, P, generator) { 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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(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 }; } } var logger = util.scopedLogger("comms/connection.ts"); var DefaultOptions = { type: "post", baseUrl: "", userID: "", password: "", rejectUnauthorized: false, timeoutSecs: 60 }; // comms --- function serializeRequest(obj, prefix) { if (prefix === void 0) { prefix = ""; } if (prefix) { prefix += "."; } if (typeof obj !== "object") { return encodeURIComponent(obj); } var str = []; var _loop_1 = function (key) { if (obj.hasOwnProperty(key)) { if (obj[key] instanceof Array) { // Specific to ESP - but no REST standard exists... var includeItemCount_1 = false; obj[key].forEach(function (row, i) { if (typeof row === "object") { includeItemCount_1 = true; str.push(serializeRequest(row, prefix + encodeURIComponent(key + "." + i))); } else { str.push(prefix + encodeURIComponent(key + "_i" + i) + "=" + serializeRequest(row)); } }); if (includeItemCount_1) { str.push(prefix + encodeURIComponent(key + ".itemcount") + "=" + obj[key].length); } } else if (typeof obj[key] === "object") { if (obj[key] && obj[key]["Item"] instanceof Array) { // Specific to ws_machine.GetTargetClusterInfo? str.push(serializeRequest(obj[key]["Item"], prefix + encodeURIComponent(key))); str.push(prefix + encodeURIComponent(key + ".itemcount") + "=" + obj[key]["Item"].length); } else { str.push(serializeRequest(obj[key], prefix + encodeURIComponent(key))); } } else if (obj[key] !== undefined) { str.push(prefix + encodeURIComponent(key) + "=" + encodeURIComponent(obj[key])); } else { str.push(prefix + encodeURIComponent(key)); } } }; for (var key in obj) { _loop_1(key); } return str.join("&"); } function deserializeResponse(body) { return JSON.parse(body); } function jsonp(opts, action, request, responseType) { if (request === void 0) { request = {}; } if (responseType === void 0) { responseType = "json"; } return new Promise(function (resolve, reject) { var respondedTimeout = opts.timeoutSecs * 1000; var respondedTick = 5000; var callbackName = "jsonp_callback_" + Math.round(Math.random() * 999999); window[callbackName] = function (response) { respondedTimeout = 0; doCallback(); resolve(responseType === "json" && typeof response === "string" ? deserializeResponse(response) : response); }; var script = document.createElement("script"); var url = util.join(opts.baseUrl, action); url += url.indexOf("?") >= 0 ? "&" : "?"; script.src = url + "jsonp=" + callbackName + "&" + serializeRequest(request); document.body.appendChild(script); var progress = setInterval(function () { if (respondedTimeout <= 0) { clearInterval(progress); } else { respondedTimeout -= respondedTick; if (respondedTimeout <= 0) { clearInterval(progress); logger.error("Request timeout: " + script.src); doCallback(); reject(Error("Request timeout: " + script.src)); } else { logger.debug("Request pending (" + respondedTimeout / 1000 + " sec): " + script.src); } } }, respondedTick); function doCallback() { delete window[callbackName]; document.body.removeChild(script); } }); } function authHeader(opts) { return opts.userID ? { Authorization: "Basic " + btoa(opts.userID + ":" + opts.password) } : {}; } // _omitMap is a workaround for older HPCC-Platform instances without credentials --- var _omitMap = {}; function doFetch(opts, action, requestInit, headersInit, responseType) { headersInit = __assign({}, authHeader(opts), headersInit); requestInit = __assign({ credentials: _omitMap[opts.baseUrl] ? "omit" : "include" }, requestInit, { headers: headersInit }); function handleResponse(response) { if (response.ok) { return responseType === "json" ? response.json() : response.text(); } throw new Error(response.statusText); } return util.promiseTimeout(opts.timeoutSecs * 1000, fetch(util.join(opts.baseUrl, action), requestInit) .then(handleResponse) .catch(function (e) { // Try again with the opposite credentials mode --- requestInit.credentials = !_omitMap[opts.baseUrl] ? "omit" : "include"; return fetch(util.join(opts.baseUrl, action), requestInit) .then(handleResponse) .then(function (responseBody) { _omitMap[opts.baseUrl] = !_omitMap[opts.baseUrl]; // The "opposite" credentials mode is known to work --- return responseBody; }); })); } function post(opts, action, request, responseType) { if (responseType === void 0) { responseType = "json"; } return doFetch(opts, action, { method: "post", body: serializeRequest(request) }, { "Content-Type": "application/x-www-form-urlencoded" }, responseType); } function get(opts, action, request, responseType) { if (responseType === void 0) { responseType = "json"; } return doFetch(opts, action + "?" + serializeRequest(request), { method: "get" }, {}, responseType); } function send(opts, action, request, responseType) { if (responseType === void 0) { responseType = "json"; } var retVal; switch (opts.type) { case "jsonp": retVal = jsonp(opts, action, request, responseType); break; case "get": retVal = get(opts, action, request, responseType); break; case "post": default: retVal = post(opts, action, request, responseType); break; } return retVal; } var hookedSend = send; function hookSend(newSend) { var retVal = hookedSend; if (newSend) { hookedSend = newSend; } return retVal; } var Connection = /** @class */ (function () { function Connection(opts) { this.opts(opts); } Connection.prototype.opts = function (_) { if (arguments.length === 0) return this._opts; this._opts = __assign({}, DefaultOptions, _); return this; }; Connection.prototype.send = function (action, request, responseType) { if (responseType === void 0) { responseType = "json"; } return hookedSend(this._opts, action, request, responseType); }; Connection.prototype.clone = function () { return new Connection(this.opts()); }; return Connection; }()); exports.createConnection = function (opts) { return new Connection(opts); }; function setTransportFactory(newFunc) { var retVal = exports.createConnection; exports.createConnection = newFunc; return retVal; } function isArray(arg) { return Object.prototype.toString.call(arg) === "[object Array]"; } var ESPExceptions = /** @class */ (function (_super) { __extends(ESPExceptions, _super); function ESPExceptions(action, request, exceptions) { var _this = _super.call(this, "ESPException: " + exceptions.Source) || this; _this.isESPExceptions = true; _this.action = action; _this.request = request; _this.Source = exceptions.Source; _this.Exception = exceptions.Exception; if (exceptions.Exception.length) { _this.message = exceptions.Exception[0].Code + ": " + exceptions.Exception[0].Message; } return _this; } return ESPExceptions; }(Error)); function isConnection(optsConnection) { return optsConnection.send !== undefined; } var ESPConnection = /** @class */ (function () { function ESPConnection(optsConnection, service, version) { this._connection = isConnection(optsConnection) ? optsConnection : exports.createConnection(optsConnection); this._service = service; this._version = version; } ESPConnection.prototype.service = function (_) { if (_ === void 0) return this._service; this._service = _; return this; }; ESPConnection.prototype.version = function (_) { if (_ === void 0) return this._version; this._version = _; return this; }; ESPConnection.prototype.toESPStringArray = function (target, arrayName) { if (isArray(target[arrayName])) { for (var i = 0; i < target[arrayName].length; ++i) { target[arrayName + "_i" + i] = target[arrayName][i]; } delete target[arrayName]; } return target; }; ESPConnection.prototype.opts = function (_) { if (_ === void 0) return this._connection.opts(); this._connection.opts(_); return this; }; ESPConnection.prototype.send = function (action, _request, espResponseType, largeUpload) { if (_request === void 0) { _request = {}; } if (espResponseType === void 0) { espResponseType = "json"; } if (largeUpload === void 0) { largeUpload = false; } var request = __assign({}, _request, { ver_: this._version }); if (largeUpload) { request["upload_"] = true; } var serviceAction; var responseType = "json"; switch (espResponseType) { case "text": serviceAction = util.join(this._service, action); responseType = "text"; break; case "xsd": serviceAction = util.join(this._service, action + ".xsd"); responseType = "text"; break; case "json2": serviceAction = util.join(this._service, action + "/json"); espResponseType = "json"; var actionParts = action.split("/"); action = actionParts.pop(); break; default: serviceAction = util.join(this._service, action + ".json"); } return this._connection.send(serviceAction, request, responseType).then(function (response) { if (espResponseType === "json") { var retVal = void 0; if (response && response.Exceptions) { throw new ESPExceptions(action, request, response.Exceptions); } else if (response) { retVal = response[(action === "WUCDebug" ? "WUDebug" : action) + "Response"]; } if (!retVal) { throw new ESPExceptions(action, request, { Source: "ESPConnection.send", Exception: [{ Code: 0, Message: "Missing Response" }] }); } return retVal; } return response; }).catch(function (e) { if (e.isESPExceptions) { throw e; } throw new ESPExceptions(action, request, { Source: "ESPConnection.send", Exception: [{ Code: 0, Message: e.message }] }); }); }; ESPConnection.prototype.clone = function () { return new ESPConnection(this._connection.clone(), this._service, this._version); }; return ESPConnection; }()); /* export class WsECLConnection extends ESPConnection { send(action: string, _request: any = {}, responseType: ResponseType = "json"): Promise<any> { if (responseType === "json") { serviceAction = join(this._service, action + "/json"); responseType = "json"; const actionParts = action.split("/"); action = actionParts.pop()!; } return super.send(action, _request, responseType); } } */ var AccountService = /** @class */ (function () { function AccountService(optsConnection) { this._connection = new ESPConnection(optsConnection, "Ws_Account", "1.03"); } AccountService.prototype.connectionOptions = function () { return this._connection.opts(); }; AccountService.prototype.VerifyUser = function (request) { return this._connection.send("VerifyUser", request); }; return AccountService; }()); var DFUService = /** @class */ (function () { function DFUService(optsConnection) { this._connection = new ESPConnection(optsConnection, "WsDFU", "1.35"); } DFUService.prototype.DFUQuery = function (request) { return this._connection.send("DFUQuery", request); }; return DFUService; }()); function jsonToIField(id, item) { var type = typeof item; switch (type) { case "boolean": case "number": case "string": return { id: id, type: type }; case "object": if (item.Row instanceof Array) { item = item.Row; } if (item instanceof Array) { return { id: id, type: "dataset", children: jsonToIFieldArr(item[0]) }; } // Fall through --- default: throw new Error("Unknown field type"); } } function jsonToIFieldArr(json) { if (json.Row && json.Row instanceof Array) { json = json.Row[0]; } var retVal = []; for (var key in json) { retVal.push(jsonToIField(key, json[key])); } return retVal; } var EclService = /** @class */ (function () { function EclService(optsConnection) { this._connection = new ESPConnection(optsConnection, "WsEcl", "0"); } EclService.prototype.opts = function () { return this._connection.opts(); }; EclService.prototype.requestJson = function (querySet, queryId) { // http://192.168.3.22:8002/WsEcl/example/request/query/roxie/peopleaccounts/json?display return this._connection.send("example/request/query/" + querySet + "/" + queryId + "/json", {}, "text").then(function (response) { var requestSchema = JSON.parse(response); for (var key in requestSchema) { return requestSchema[key]; } return {}; }).then(jsonToIFieldArr); }; EclService.prototype.responseJson = function (querySet, queryId) { // http://192.168.3.22:8002/WsEcl/example/response/query/roxie/peopleaccounts/json?display return this._connection.send("example/response/query/" + querySet + "/" + queryId + "/json", {}, "text").then(function (response) { var responseSchema = JSON.parse(response); for (var key in responseSchema) { return responseSchema[key].Results; } return {}; }).then(function (resultsJson) { var retVal = {}; for (var key in resultsJson) { retVal[key] = jsonToIFieldArr(resultsJson[key]); } return retVal; }); }; EclService.prototype.submit = function (querySet, queryId, request) { // http://192.168.3.22:8002/WsEcl/submit/query/roxie/peopleaccounts.1/json var action = "submit/query/" + querySet + "/" + queryId; return this._connection.send(action, request, "json2").then(function (response) { if (response.Results && response.Results.Exception) { throw new ESPExceptions(action, request, { Source: "wsEcl.submit", Exception: response.Results.Exception }); } return response.Results; }); }; return EclService; }()); var MachineService = /** @class */ (function () { function MachineService(optsConnection) { this._connection = new ESPConnection(optsConnection, "ws_machine", "1.13"); } MachineService.prototype.GetTargetClusterInfo = function (request) { if (request === void 0) { request = {}; } return this._connection.send("GetTargetClusterInfo", request); }; return MachineService; }()); var SMCService = /** @class */ (function () { function SMCService(optsConnection) { this._connection = new ESPConnection(optsConnection, "WsSMC", "1.19"); } SMCService.prototype.connectionOptions = function () { return this._connection.opts(); }; SMCService.prototype.Activity = function (request) { return this._connection.send("Activity", request).then(function (response) { return __assign({ Running: { ActiveWorkunit: [] } }, response); }); }; return SMCService; }()); var TopologyService = /** @class */ (function () { function TopologyService(optsConnection) { this._connection = new ESPConnection(optsConnection, "WsTopology", "1.25"); } TopologyService.prototype.connectionOptions = function () { return this._connection.opts(); }; TopologyService.prototype.protocol = function () { var parts = this._connection.opts().baseUrl.split("//"); return parts[0]; }; TopologyService.prototype.ip = function () { var parts = this._connection.opts().baseUrl.split("//"); var parts2 = parts[1].split(":"); return parts2[0]; }; TopologyService.prototype.TpLogicalClusterQuery = function (request) { if (request === void 0) { request = {}; } return this._connection.send("TpLogicalClusterQuery", request); }; TopologyService.prototype.DefaultTpLogicalClusterQuery = function (request) { if (request === void 0) { request = {}; } return this.TpLogicalClusterQuery(request).then(function (response) { if (response.default) { return response.default; } var firstHThor; var first; response.TpLogicalClusters.TpLogicalCluster.some(function (item, idx) { if (idx === 0) { first = item; } if (item.Type === "hthor") { firstHThor = item; return true; } return false; }); return firstHThor || first; }); }; TopologyService.prototype.TpServiceQuery = function (request) { return this._connection.send("TpServiceQuery", request); }; TopologyService.prototype.TpTargetClusterQuery = function (request) { return this._connection.send("TpTargetClusterQuery", request); }; return TopologyService; }()); (function (WUStateID) { WUStateID[WUStateID["Unknown"] = 0] = "Unknown"; WUStateID[WUStateID["Compiled"] = 1] = "Compiled"; WUStateID[WUStateID["Running"] = 2] = "Running"; WUStateID[WUStateID["Completed"] = 3] = "Completed"; WUStateID[WUStateID["Failed"] = 4] = "Failed"; WUStateID[WUStateID["Archived"] = 5] = "Archived"; WUStateID[WUStateID["Aborting"] = 6] = "Aborting"; WUStateID[WUStateID["Aborted"] = 7] = "Aborted"; WUStateID[WUStateID["Blocked"] = 8] = "Blocked"; WUStateID[WUStateID["Submitted"] = 9] = "Submitted"; WUStateID[WUStateID["Scheduled"] = 10] = "Scheduled"; WUStateID[WUStateID["Compiling"] = 11] = "Compiling"; WUStateID[WUStateID["Wait"] = 12] = "Wait"; WUStateID[WUStateID["UploadingFiled"] = 13] = "UploadingFiled"; WUStateID[WUStateID["DebugPaused"] = 14] = "DebugPaused"; WUStateID[WUStateID["DebugRunning"] = 15] = "DebugRunning"; WUStateID[WUStateID["Paused"] = 16] = "Paused"; WUStateID[WUStateID["LAST"] = 17] = "LAST"; WUStateID[WUStateID["NotFound"] = 999] = "NotFound"; })(exports.WUStateID || (exports.WUStateID = {})); (function (WUUpdate) { var Action; (function (Action) { Action[Action["Unknown"] = 0] = "Unknown"; Action[Action["Compile"] = 1] = "Compile"; Action[Action["Check"] = 2] = "Check"; Action[Action["Run"] = 3] = "Run"; Action[Action["ExecuteExisting"] = 4] = "ExecuteExisting"; Action[Action["Pause"] = 5] = "Pause"; Action[Action["PauseNow"] = 6] = "PauseNow"; Action[Action["Resume"] = 7] = "Resume"; Action[Action["Debug"] = 8] = "Debug"; Action[Action["__size"] = 9] = "__size"; })(Action = WUUpdate.Action || (WUUpdate.Action = {})); })(exports.WUUpdate || (exports.WUUpdate = {})); function isWUQueryECLWorkunit(_) { return _.TotalClusterTime !== undefined; } function isWUInfoWorkunit(_) { return _.StateEx !== undefined; } var WorkunitsService = /** @class */ (function () { function WorkunitsService(optsConnection) { this._connection = new ESPConnection(optsConnection, "WsWorkunits", "1.68"); } WorkunitsService.prototype.opts = function () { return this._connection.opts(); }; WorkunitsService.prototype.connection = function () { return this._connection; }; WorkunitsService.prototype.WUQuery = function (request) { if (request === void 0) { request = {}; } return this._connection.send("WUQuery", request).then(function (response) { return util.deepMixin({ Workunits: { ECLWorkunit: [] } }, response); }); }; WorkunitsService.prototype.WUInfo = function (_request) { var request = __assign({ Wuid: "", TruncateEclTo64k: true, IncludeExceptions: false, IncludeGraphs: false, IncludeSourceFiles: false, IncludeResults: false, IncludeResultsViewNames: false, IncludeVariables: false, IncludeTimers: false, IncludeDebugValues: false, IncludeApplicationValues: false, IncludeWorkflows: false, IncludeXmlSchemas: false, IncludeResourceURLs: false, SuppressResultSchemas: true }, _request); return this._connection.send("WUInfo", request); }; WorkunitsService.prototype.WUCreate = function () { return this._connection.send("WUCreate"); }; WorkunitsService.prototype.WUUpdate = function (request) { return this._connection.send("WUUpdate", request, "json", true); }; WorkunitsService.prototype.WUSubmit = function (request) { return this._connection.send("WUSubmit", request); }; WorkunitsService.prototype.WUResubmit = function (request) { this._connection.toESPStringArray(request, "Wuids"); return this._connection.send("WUResubmit", request); }; WorkunitsService.prototype.WUQueryDetails = function (request) { return this._connection.send("WUQueryDetails", request); }; WorkunitsService.prototype.WUListQueries = function (request) { return this._connection.send("WUListQueries", request); }; WorkunitsService.prototype.WUPushEvent = function (request) { return this._connection.send("WUPushEvent", request); }; WorkunitsService.prototype.WUAction = function (request) { request.ActionType = request.WUActionType; // v5.x compatibility return this._connection.send("WUAction", request); }; WorkunitsService.prototype.WUGetZAPInfo = function (request) { return this._connection.send("WUGetZAPInfo", request); }; WorkunitsService.prototype.WUShowScheduled = function (request) { return this._connection.send("WUShowScheduled", request); }; WorkunitsService.prototype.WUQuerySetAliasAction = function (request) { return this._connection.send("WUQuerySetAliasAction", request); }; WorkunitsService.prototype.WUQuerySetQueryAction = function (request) { return this._connection.send("WUQuerySetQueryAction", request); }; WorkunitsService.prototype.WUPublishWorkunit = function (request) { return this._connection.send("WUPublishWorkunit", request); }; WorkunitsService.prototype.WUGetGraph = function (request) { return this._connection.send("WUGetGraph", request); }; WorkunitsService.prototype.WUResult = function (request) { return this._connection.send("WUResult", request); }; WorkunitsService.prototype.WUQueryGetGraph = function (request) { return this._connection.send("WUQueryGetGraph", request); }; WorkunitsService.prototype.WUFile = function (request) { return this._connection.send("WUFile", request, "text"); }; WorkunitsService.prototype.WUGetStats = function (request) { return this._connection.send("WUGetStats", request); }; WorkunitsService.prototype.WUDetailsMeta = function (request) { if (!this._WUDetailsMetaPromise) { this._WUDetailsMetaPromise = this._connection.send("WUDetailsMeta", request); } return this._WUDetailsMetaPromise; }; WorkunitsService.prototype.WUDetails = function (request) { return this._connection.send("WUDetails", request); }; WorkunitsService.prototype.WUCDebug = function (request) { return this._connection.send("WUCDebug", request).then(function (response) { var retVal = util.xml2json(response.Result); var children = retVal.children(); if (children.length) { return children[0]; } return null; }); }; return WorkunitsService; }()); var t0 = new Date, t1 = new Date; function newInterval(floori, offseti, count, field) { function interval(date) { return floori(date = new Date(+date)), date; } interval.floor = interval; interval.ceil = function(date) { return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date; }; interval.round = function(date) { var d0 = interval(date), d1 = interval.ceil(date); return date - d0 < d1 - date ? d0 : d1; }; interval.offset = function(date, step) { return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date; }; interval.range = function(start, stop, step) { var range = []; start = interval.ceil(start); step = step == null ? 1 : Math.floor(step); if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date do range.push(new Date(+start)); while (offseti(start, step), floori(start), start < stop) return range; }; interval.filter = function(test) { return newInterval(function(date) { if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1); }, function(date, step) { if (date >= date) while (--step >= 0) while (offseti(date, 1), !test(date)) {} // eslint-disable-line no-empty }); }; if (count) { interval.count = function(start, end) { t0.setTime(+start), t1.setTime(+end); floori(t0), floori(t1); return Math.floor(count(t0, t1)); }; interval.every = function(step) { step = Math.floor(step); return !isFinite(step) || !(step > 0) ? null : !(step > 1) ? interval : interval.filter(field ? function(d) { return field(d) % step === 0; } : function(d) { return interval.count(0, d) % step === 0; }); }; } return interval; } var millisecond = newInterval(function() { // noop }, function(date, step) { date.setTime(+date + step); }, function(start, end) { return end - start; }); // An optimized implementation for this simple case. millisecond.every = function(k) { k = Math.floor(k); if (!isFinite(k) || !(k > 0)) return null; if (!(k > 1)) return millisecond; return newInterval(function(date) { date.setTime(Math.floor(date / k) * k); }, function(date, step) { date.setTime(+date + step * k); }, function(start, end) { return (end - start) / k; }); }; var durationSecond = 1e3; var durationMinute = 6e4; var durationHour = 36e5; var durationDay = 864e5; var durationWeek = 6048e5; var second = newInterval(function(date) { date.setTime(Math.floor(date / durationSecond) * durationSecond); }, function(date, step) { date.setTime(+date + step * durationSecond); }, function(start, end) { return (end - start) / durationSecond; }, function(date) { return date.getUTCSeconds(); }); var minute = newInterval(function(date) { date.setTime(Math.floor(date / durationMinute) * durationMinute); }, function(date, step) { date.setTime(+date + step * durationMinute); }, function(start, end) { return (end - start) / durationMinute; }, function(date) { return date.getMinutes(); }); var hour = newInterval(function(date) { var offset = date.getTimezoneOffset() * durationMinute % durationHour; if (offset < 0) offset += durationHour; date.setTime(Math.floor((+date - offset) / durationHour) * durationHour + offset); }, function(date, step) { date.setTime(+date + step * durationHour); }, function(start, end) { return (end - start) / durationHour; }, function(date) { return date.getHours(); }); var day = newInterval(function(date) { date.setHours(0, 0, 0, 0); }, function(date, step) { date.setDate(date.getDate() + step); }, function(start, end) { return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay; }, function(date) { return date.getDate() - 1; }); function weekday(i) { return newInterval(function(date) { date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7); date.setHours(0, 0, 0, 0); }, function(date, step) { date.setDate(date.getDate() + step * 7); }, function(start, end) { return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek; }); } var sunday = weekday(0); var monday = weekday(1); var tuesday = weekday(2); var wednesday = weekday(3); var thursday = weekday(4); var friday = weekday(5); var saturday = weekday(6); var sundays = sunday.range; var mondays = monday.range; var thursdays = thursday.range; var month = newInterval(function(date) { date.setDate(1); date.setHours(0, 0, 0, 0); }, function(date, step) { date.setMonth(date.getMonth() + step); }, function(start, end) { return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12; }, function(date) { return date.getMonth(); }); var year = newInterval(function(date) { date.setMonth(0, 1); date.setHours(0, 0, 0, 0); }, function(date, step) { date.setFullYear(date.getFullYear() + step); }, function(start, end) { return end.getFullYear() - start.getFullYear(); }, function(date) { return date.getFullYear(); }); // An optimized implementation for this simple case. year.every = function(k) { return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) { date.setFullYear(Math.floor(date.getFullYear() / k) * k); date.setMonth(0, 1); date.setHours(0, 0, 0, 0); }, function(date, step) { date.setFullYear(date.getFullYear() + step * k); }); }; var utcMinute = newInterval(function(date) { date.setUTCSeconds(0, 0); }, function(date, step) { date.setTime(+date + step * durationMinute); }, function(start, end) { return (end - start) / durationMinute; }, function(date) { return date.getUTCMinutes(); }); var utcHour = newInterval(function(date) { date.setUTCMinutes(0, 0, 0); }, function(date, step) { date.setTime(+date + step * durationHour); }, function(start, end) { return (end - start) / durationHour; }, function(date) { return date.getUTCHours(); }); var utcDay = newInterval(function(date) { date.setUTCHours(0, 0, 0, 0); }, function(date, step) { date.setUTCDate(date.getUTCDate() + step); }, function(start, end) { return (end - start) / durationDay; }, function(date) { return date.getUTCDate() - 1; }); function utcWeekday(i) { return newInterval(function(date) { date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7); date.setUTCHours(0, 0, 0, 0); }, function(date, step) { date.setUTCDate(date.getUTCDate() + step * 7); }, function(start, end) { return (end - start) / durationWeek; }); } var utcSunday = utcWeekday(0); var utcMonday = utcWeekday(1); var utcTuesday = utcWeekday(2); var utcWednesday = utcWeekday(3); var utcThursday = utcWeekday(4); var utcFriday = utcWeekday(5); var utcSaturday = utcWeekday(6); var utcSundays = utcSunday.range; var utcMondays = utcMonday.range; var utcThursdays = utcThursday.range; var utcMonth = newInterval(function(date) { date.setUTCDate(1); date.setUTCHours(0, 0, 0, 0); }, function(date, step) { date.setUTCMonth(date.getUTCMonth() + step); }, function(start, end) { return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12; }, function(date) { return date.getUTCMonth(); }); var utcYear = newInterval(function(date) { date.setUTCMonth(0, 1); date.setUTCHours(0, 0, 0, 0); }, function(date, step) { date.setUTCFullYear(date.getUTCFullYear() + step); }, function(start, end) { return end.getUTCFullYear() - start.getUTCFullYear(); }, function(date) { return date.getUTCFullYear(); }); // An optimized implementation for this simple case. utcYear.every = function(k) { return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) { date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k); date.setUTCMonth(0, 1); date.setUTCHours(0, 0, 0, 0); }, function(date, step) { date.setUTCFullYear(date.getUTCFullYear() + step * k); }); }; function localDate(d) { if (0 <= d.y && d.y < 100) { var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L); date.setFullYear(d.y); return date; } return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L); } function utcDate(d) { if (0 <= d.y && d.y < 100) { var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L)); date.setUTCFullYear(d.y); return date; } return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L)); } function newYear(y) { return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0}; } function formatLocale(locale) { var locale_dateTime = locale.dateTime, locale_date = locale.date, locale_time = locale.time, locale_periods = locale.periods, locale_weekdays = locale.days, locale_shortWeekdays = locale.shortDays, locale_months = locale.months, locale_shortMonths = locale.shortMonths; var periodRe = formatRe(locale_periods), periodLookup = formatLookup(locale_periods), weekdayRe = formatRe(locale_weekdays), weekdayLookup = formatLookup(locale_weekdays), shortWeekdayRe = formatRe(locale_shortWeekdays), shortWeekdayLookup = formatLookup(locale_shortWeekdays), monthRe = formatRe(locale_months), monthLookup = formatLookup(locale_months), shortMonthRe = formatRe(locale_shortMonths), shortMonthLookup = formatLookup(locale_shortMonths); var formats = { "a": formatShortWeekday, "A": formatWeekday, "b": formatShortMonth, "B": formatMonth, "c": null, "d": formatDayOfMonth, "e": formatDayOfMonth, "f": formatMicroseconds, "H": formatHour24, "I": formatHour12, "j": formatDayOfYear, "L": formatMilliseconds, "m": formatMonthNumber, "M": formatMinutes, "p": formatPeriod, "Q": formatUnixTimestamp, "s": formatUnixTimestampSeconds, "S": formatSeconds, "u": formatWeekdayNumberMonday, "U": formatWeekNumberSunday, "V": formatWeekNumberISO, "w": formatWeekdayNumberSunday, "W": formatWeekNumberMonday, "x": null, "X": null, "y": formatYear, "Y": formatFullYear, "Z": formatZone, "%": formatLiteralPercent }; var utcFormats = { "a": formatUTCShortWeekday, "A": formatUTCWeekday, "b": formatUTCShortMonth, "B": formatUTCMonth, "c": null, "d": formatUTCDayOfMonth, "e": formatUTCDayOfMonth, "f": formatUTCMicroseconds, "H": formatUTCHour24, "I": formatUTCHour12, "j": formatUTCDayOfYear, "L": formatUTCMilliseconds, "m": formatUTCMonthNumber, "M": formatUTCMinutes, "p": formatUTCPeriod, "Q": formatUnixTimestamp, "s": formatUnixTimestampSeconds, "S": formatUTCSeconds, "u": formatUTCWeekdayNumberMonday, "U": formatUTCWeekNumberSunday, "V": formatUTCWeekNumberISO, "w": formatUTCWeekdayNumberSunday, "W": formatUTCWeekNumberMonday, "x": null, "X": null, "y": formatUTCYear, "Y": formatUTCFullYear, "Z": formatUTCZone, "%": formatLiteralPercent }; var parses = { "a": parseShortWeekday, "A": parseWeekday, "b": parseShortMonth, "B": parseMonth, "c": parseLocaleDateTime, "d": parseDayOfMonth, "e": parseDayOfMonth, "f": parseMicroseconds, "H": parseHour24, "I": parseHour24, "j": parseDayOfYear, "L": parseMilliseconds, "m": parseMonthNumber, "M": parseMinutes, "p": parsePeriod, "Q": parseUnixTimestamp, "s": parseUnixTimestampSeconds, "S": parseSeconds, "u": parseWeekdayNumberMonday, "U": parseWeekNumberSunday, "V": parseWeekNumberISO, "w": parseWeekdayNumberSunday, "W": parseWeekNumberMonday, "x": parseLocaleDate, "X": parseLocaleTime, "y": parseYear, "Y": parseFullYear, "Z": parseZone, "%": parseLiteralPercent }; // These recursive directive definitions must be deferred. formats.x = newFormat(locale_date, formats); formats.X = newFormat(locale_time, formats); formats.c = newFormat(locale_dateTime, formats); utcFormats.x = newFormat(locale_date, utcFormats); utcFormats.X = newFormat(locale_time, utcFormats); utcFormats.c = newFormat(locale_dateTime, utcFormats); function newFormat(specifier, formats) { return function(date) { var string = [], i = -1, j = 0, n = specifier.length, c, pad, format; if (!(date instanceof Date)) date = new Date(+date); while (++i < n) { if (specifier.charCodeAt(i) === 37) { string.push(specifier.slice(j, i)); if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i); else pad = c === "e" ? " " : "0"; if (format = formats[c]) c = format(date, pad); string.push(c); j = i + 1; } } string.push(specifier.slice(j, i)); return string.join(""); }; } function newParse(specifier, newDate) { return function(string) { var d = newYear(1900), i = parseSpecifier(d, specifier, string += "", 0), week, day$$1; if (i != string.length) return null; // If a UNIX timestamp is specified, return it. if ("Q" in d) return new Date(d.Q); // The am-pm flag is 0 for AM, and 1 for PM. if ("p" in d) d.H = d.H % 12 + d.p * 12; // Convert day-of-week and week-of-year to day-of-year. if ("V" in d) { if (d.V < 1 || d.V > 53) return null; if (!("w" in d)) d.w = 1; if ("Z" in d) { week = utcDate(newYear(d.y)), day$$1 = week.getUTCDay(); week = day$$1 > 4 || day$$1 === 0 ? utcMonday.ceil(week) : utcMonday(week); week = utcDay.offset(week, (d.V - 1) * 7); d.y = week.getUTCFullYear(); d.m = week.getUTCMonth(); d.d = week.getUTCDate() + (d.w + 6) % 7; } else { week = newDate(newYear(d.y)), day$$1 = week.getDay(); week = day$$1 > 4 || day$$1 === 0 ? monday.ceil(week) : monday(week); week = day.offset(week, (d.V - 1) * 7); d.y = week.getFullYear(); d.m = week.getMonth(); d.d = week.getDate() + (d.w + 6) % 7; } } else if ("W" in d || "U" in d) { if (!("w" in d)) d.w = "u" in d ? d.u % 7 : "W" in d ? 1 : 0; day$$1 = "Z" in d ? utcDate(newYear(d.y)).getUTCDay() : newDate(newYear(d.y)).getDay(); d.m = 0; d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day$$1 + 5) % 7 : d.w + d.U * 7 - (day$$1 + 6) % 7; } // If a time zone is specified, all fields are interpreted as UTC and then // offset according to the specified time zone. if ("Z" in d) { d.H += d.Z / 100 | 0; d.M += d.Z % 100; return utcDate(d); } // Otherwise, all fields are in local time. return newDate(d); }; } function parseSpecifier(d, specifier, string, j) { var i = 0, n = specifier.length, m = string.length, c, parse; while (i < n) { if (j >= m) return -1; c = specifier.charCodeAt(i++); if (c === 37) { c = specifier.charAt(i++); parse = parses[c in pads ? specifier.charAt(i++) : c]; if (!parse || ((j = parse(d, string, j)) < 0)) return -1; } else if (c != string.charCodeAt(j++)) { return -1; } } return j; } function parsePeriod(d, string, i) { var n = periodRe.exec(string.slice(i)); return n ? (d.p = periodLookup[n[0].toLowerCase()], i + n[0].length) : -1; } function parseShortWeekday(d, string, i) { var n = shortWeekdayRe.exec(string.slice(i)); return n ? (d.w = shortWeekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1; } function parseWeekday(d, string, i) { var n = weekdayRe.exec(string.slice(i)); return n ? (d.w = weekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1; } function parseShortMonth(d, string, i) { var n = shortMonthRe.exec(string.slice(i)); return n ? (d.m = shortMonthLookup[n[0].toLowerCase()], i + n[0].length) : -1; } function parseMonth(d, string, i) { var n = monthRe.exec(string.slice(i)); return n ? (d.m = monthLookup[n[0].toLowerCase()], i + n[0].length) : -1; } function parseLocaleDateTime(d, string, i) { return parseSpecifier(d, locale_dateTime, string, i); } function parseLocaleDate(d, string, i) { return parseSpecifier(d, locale_date, string, i); } function parseLocaleTime(d, string, i) { return parseSpecifier(d, locale_time, string, i); } function formatShortWeekday(d) { return locale_shortWeekdays[d.getDay()]; } function formatWeekday(d) { return locale_weekdays[d.getDay()]; } function formatShortMonth(d) { return locale_shortMonths[d.getMonth()]; } function formatMonth(d) { return locale_months[d.getMonth()]; } function formatPeriod(d) { return locale_periods[+(d.getHours() >= 12)]; } function formatUTCShortWeekday(d) { return locale_shortWeekdays[d.getUTCDay()]; } function formatUTCWeekday(d) { return locale_weekdays[d.getUTCDay()]; } function formatUTCShortMonth(d) { return locale_shortMonths[d.getUTCMonth()]; } function formatUTCMonth(d) { return locale_months[d.getUTCMonth()]; } function formatUTCPeriod(d) { return locale_periods[+(d.getUTCHours() >= 12)]; } return { format: function(specifier) { var f = newFormat(specifier += "", formats); f.toString = function() { return specifier; }; return f; }, parse: function(specifier) { var p = newParse(specifier += "", localDate); p.toString = function() { return specifier; }; return p; }, utcFormat: function(specifier) { var f = newFormat(specifier += "", utcFormats); f.toString = function() { return specifier; }; return f; }, utcParse: function(specifier) { var p = newParse(specifier, utcDate); p.toString = function() { return specifier; }; return p; } }; } var pads = {"-": "", "_": " ", "0": "0"}, numberRe = /^\s*\d+/, // note: ignores next directive percentRe = /^%/, requoteRe = /[\\^$*+?|[\]().{}]/g; function pad(value, fill, width) { var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); } function requote(s) { return s.replace(requoteRe, "\\$&"); } function formatRe(names) { return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i"); } function formatLookup(names) { var map = {}, i = -1, n = names.length; while (++i < n) map[names[i].toLowerCase()] = i; return map; } function parseWeekdayNumberSunday(d, string, i) { var n = numberRe.exec(string.slice(i, i + 1)); return n ? (d.w