|
@@ -1,16 +1,19 @@
|
|
|
+/**
|
|
|
+ * @author n1474335 [n1474335@gmail.com]
|
|
|
+ * @copyright Crown Copyright 2016
|
|
|
+ * @license Apache-2.0
|
|
|
+ */
|
|
|
+
|
|
|
import utf8 from "utf8";
|
|
|
+import moment from "moment-timezone";
|
|
|
+import {fromBase64} from "./lib/Base64";
|
|
|
+import {toHexFast, fromHex} from "./lib/Hex";
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Utility functions for use in operations, the core framework and the stage.
|
|
|
- *
|
|
|
- * @author n1474335 [n1474335@gmail.com]
|
|
|
- * @copyright Crown Copyright 2016
|
|
|
- * @license Apache-2.0
|
|
|
- *
|
|
|
- * @namespace
|
|
|
*/
|
|
|
-const Utils = {
|
|
|
+class Utils {
|
|
|
|
|
|
/**
|
|
|
* Translates an ordinal into a character.
|
|
@@ -22,7 +25,7 @@ const Utils = {
|
|
|
* // returns 'a'
|
|
|
* Utils.chr(97);
|
|
|
*/
|
|
|
- chr: function(o) {
|
|
|
+ static chr(o) {
|
|
|
// Detect astral symbols
|
|
|
// Thanks to @mathiasbynens for this solution
|
|
|
// https://mathiasbynens.be/notes/javascript-unicode
|
|
@@ -34,7 +37,7 @@ const Utils = {
|
|
|
}
|
|
|
|
|
|
return String.fromCharCode(o);
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -47,7 +50,7 @@ const Utils = {
|
|
|
* // returns 97
|
|
|
* Utils.ord('a');
|
|
|
*/
|
|
|
- ord: function(c) {
|
|
|
+ static ord(c) {
|
|
|
// Detect astral symbols
|
|
|
// Thanks to @mathiasbynens for this solution
|
|
|
// https://mathiasbynens.be/notes/javascript-unicode
|
|
@@ -61,7 +64,7 @@ const Utils = {
|
|
|
}
|
|
|
|
|
|
return c.charCodeAt(0);
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -87,8 +90,7 @@ const Utils = {
|
|
|
* // returns ["t", "e", "s", "t", 1, 1, 1, 1]
|
|
|
* Utils.padBytesRight("test", 8, 1);
|
|
|
*/
|
|
|
- padBytesRight: function(arr, numBytes, padByte) {
|
|
|
- padByte = padByte || 0;
|
|
|
+ static padBytesRight(arr, numBytes, padByte=0) {
|
|
|
const paddedBytes = new Array(numBytes);
|
|
|
paddedBytes.fill(padByte);
|
|
|
|
|
@@ -97,7 +99,7 @@ const Utils = {
|
|
|
});
|
|
|
|
|
|
return paddedBytes;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -115,13 +117,12 @@ const Utils = {
|
|
|
* // returns "A long s-"
|
|
|
* Utils.truncate("A long string", 9, "-");
|
|
|
*/
|
|
|
- truncate: function(str, max, suffix) {
|
|
|
- suffix = suffix || "...";
|
|
|
+ static truncate(str, max, suffix="...") {
|
|
|
if (str.length > max) {
|
|
|
str = str.slice(0, max - suffix.length) + suffix;
|
|
|
}
|
|
|
return str;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -138,11 +139,10 @@ const Utils = {
|
|
|
* // returns "6e"
|
|
|
* Utils.hex(110);
|
|
|
*/
|
|
|
- hex: function(c, length) {
|
|
|
+ static hex(c, length=2) {
|
|
|
c = typeof c == "string" ? Utils.ord(c) : c;
|
|
|
- length = length || 2;
|
|
|
return c.toString(16).padStart(length, "0");
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -159,11 +159,10 @@ const Utils = {
|
|
|
* // returns "01101110"
|
|
|
* Utils.bin(110);
|
|
|
*/
|
|
|
- bin: function(c, length) {
|
|
|
+ static bin(c, length=8) {
|
|
|
c = typeof c == "string" ? Utils.ord(c) : c;
|
|
|
- length = length || 8;
|
|
|
return c.toString(2).padStart(length, "0");
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -173,7 +172,7 @@ const Utils = {
|
|
|
* @param {boolean} [preserveWs=false] - Whether or not to print whitespace.
|
|
|
* @returns {string}
|
|
|
*/
|
|
|
- printable: function(str, preserveWs) {
|
|
|
+ static printable(str, preserveWs=false) {
|
|
|
if (ENVIRONMENT_IS_WEB() && window.app && !window.app.options.treatAsUtf8) {
|
|
|
str = Utils.byteArrayToChars(Utils.strToByteArray(str));
|
|
|
}
|
|
@@ -184,7 +183,7 @@ const Utils = {
|
|
|
str = str.replace(re, ".");
|
|
|
if (!preserveWs) str = str.replace(wsRe, ".");
|
|
|
return str;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -200,25 +199,38 @@ const Utils = {
|
|
|
* // returns "\n"
|
|
|
* Utils.parseEscapedChars("\\n");
|
|
|
*/
|
|
|
- parseEscapedChars: function(str) {
|
|
|
- return str.replace(/(\\)?\\([nrtbf]|x[\da-fA-F]{2})/g, function(m, a, b) {
|
|
|
+ static parseEscapedChars(str) {
|
|
|
+ return str.replace(/(\\)?\\([bfnrtv0'"]|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\})/g, function(m, a, b) {
|
|
|
if (a === "\\") return "\\"+b;
|
|
|
switch (b[0]) {
|
|
|
- case "n":
|
|
|
- return "\n";
|
|
|
- case "r":
|
|
|
- return "\r";
|
|
|
- case "t":
|
|
|
- return "\t";
|
|
|
+ case "0":
|
|
|
+ return "\0";
|
|
|
case "b":
|
|
|
return "\b";
|
|
|
+ case "t":
|
|
|
+ return "\t";
|
|
|
+ case "n":
|
|
|
+ return "\n";
|
|
|
+ case "v":
|
|
|
+ return "\v";
|
|
|
case "f":
|
|
|
return "\f";
|
|
|
+ case "r":
|
|
|
+ return "\r";
|
|
|
+ case '"':
|
|
|
+ return '"';
|
|
|
+ case "'":
|
|
|
+ return "'";
|
|
|
case "x":
|
|
|
- return Utils.chr(parseInt(b.substr(1), 16));
|
|
|
+ return String.fromCharCode(parseInt(b.substr(1), 16));
|
|
|
+ case "u":
|
|
|
+ if (b[1] === "{")
|
|
|
+ return String.fromCodePoint(parseInt(b.slice(2, -1), 16));
|
|
|
+ else
|
|
|
+ return String.fromCharCode(parseInt(b.substr(1), 16));
|
|
|
}
|
|
|
});
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -232,9 +244,9 @@ const Utils = {
|
|
|
* // returns "\[example\]"
|
|
|
* Utils.escapeRegex("[example]");
|
|
|
*/
|
|
|
- escapeRegex: function(str) {
|
|
|
+ static escapeRegex(str) {
|
|
|
return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, "\\$1");
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -253,14 +265,14 @@ const Utils = {
|
|
|
* // returns ["a", "b", "c", "d", "0", "-", "3"]
|
|
|
* Utils.expandAlphRange("a-d0\\-3")
|
|
|
*/
|
|
|
- expandAlphRange: function(alphStr) {
|
|
|
+ static expandAlphRange(alphStr) {
|
|
|
const alphArr = [];
|
|
|
|
|
|
for (let i = 0; i < alphStr.length; i++) {
|
|
|
if (i < alphStr.length - 2 &&
|
|
|
alphStr[i+1] === "-" &&
|
|
|
alphStr[i] !== "\\") {
|
|
|
- let start = Utils.ord(alphStr[i]),
|
|
|
+ const start = Utils.ord(alphStr[i]),
|
|
|
end = Utils.ord(alphStr[i+2]);
|
|
|
|
|
|
for (let j = start; j <= end; j++) {
|
|
@@ -277,7 +289,7 @@ const Utils = {
|
|
|
}
|
|
|
}
|
|
|
return alphArr;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -298,19 +310,19 @@ const Utils = {
|
|
|
* // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
|
|
|
* Utils.convertToByteArray("0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1", "base64");
|
|
|
*/
|
|
|
- convertToByteArray: function(str, type) {
|
|
|
+ static convertToByteArray(str, type) {
|
|
|
switch (type.toLowerCase()) {
|
|
|
case "hex":
|
|
|
- return Utils.fromHex(str);
|
|
|
+ return fromHex(str);
|
|
|
case "base64":
|
|
|
- return Utils.fromBase64(str, null, "byteArray");
|
|
|
+ return fromBase64(str, null, "byteArray");
|
|
|
case "utf8":
|
|
|
return Utils.strToUtf8ByteArray(str);
|
|
|
case "latin1":
|
|
|
default:
|
|
|
return Utils.strToByteArray(str);
|
|
|
}
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -322,28 +334,28 @@ const Utils = {
|
|
|
* @returns {string}
|
|
|
*
|
|
|
* @example
|
|
|
- * // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
|
|
|
- * Utils.convertToByteArray("Привет", "utf8");
|
|
|
+ * // returns "ÐÑивеÑ"
|
|
|
+ * Utils.convertToByteString("Привет", "utf8");
|
|
|
*
|
|
|
- * // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
|
|
|
- * Utils.convertToByteArray("d097d0b4d180d0b0d0b2d181d182d0b2d183d0b9d182d0b5", "hex");
|
|
|
+ * // returns "ÐдÑавÑÑвÑйÑе"
|
|
|
+ * Utils.convertToByteString("d097d0b4d180d0b0d0b2d181d182d0b2d183d0b9d182d0b5", "hex");
|
|
|
*
|
|
|
- * // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130]
|
|
|
- * Utils.convertToByteArray("0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1", "base64");
|
|
|
+ * // returns "ÐдÑавÑÑвÑйÑе"
|
|
|
+ * Utils.convertToByteString("0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1", "base64");
|
|
|
*/
|
|
|
- convertToByteString: function(str, type) {
|
|
|
+ static convertToByteString(str, type) {
|
|
|
switch (type.toLowerCase()) {
|
|
|
case "hex":
|
|
|
- return Utils.byteArrayToChars(Utils.fromHex(str));
|
|
|
+ return Utils.byteArrayToChars(fromHex(str));
|
|
|
case "base64":
|
|
|
- return Utils.byteArrayToChars(Utils.fromBase64(str, null, "byteArray"));
|
|
|
+ return Utils.byteArrayToChars(fromBase64(str, null, "byteArray"));
|
|
|
case "utf8":
|
|
|
return utf8.encode(str);
|
|
|
case "latin1":
|
|
|
default:
|
|
|
return str;
|
|
|
}
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -360,7 +372,7 @@ const Utils = {
|
|
|
* // returns [228,189,160,229,165,189]
|
|
|
* Utils.strToByteArray("你好");
|
|
|
*/
|
|
|
- strToByteArray: function(str) {
|
|
|
+ static strToByteArray(str) {
|
|
|
const byteArray = new Array(str.length);
|
|
|
let i = str.length, b;
|
|
|
while (i--) {
|
|
@@ -370,7 +382,7 @@ const Utils = {
|
|
|
if (b > 255) return Utils.strToUtf8ByteArray(str);
|
|
|
}
|
|
|
return byteArray;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -386,7 +398,7 @@ const Utils = {
|
|
|
* // returns [228,189,160,229,165,189]
|
|
|
* Utils.strToUtf8ByteArray("你好");
|
|
|
*/
|
|
|
- strToUtf8ByteArray: function(str) {
|
|
|
+ static strToUtf8ByteArray(str) {
|
|
|
const utf8Str = utf8.encode(str);
|
|
|
|
|
|
if (str.length !== utf8Str.length) {
|
|
@@ -398,7 +410,7 @@ const Utils = {
|
|
|
}
|
|
|
|
|
|
return Utils.strToByteArray(utf8Str);
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -414,7 +426,7 @@ const Utils = {
|
|
|
* // returns [20320,22909]
|
|
|
* Utils.strToCharcode("你好");
|
|
|
*/
|
|
|
- strToCharcode: function(str) {
|
|
|
+ static strToCharcode(str) {
|
|
|
const charcode = [];
|
|
|
|
|
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -432,7 +444,7 @@ const Utils = {
|
|
|
}
|
|
|
|
|
|
return charcode;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -448,7 +460,7 @@ const Utils = {
|
|
|
* // returns "你好"
|
|
|
* Utils.byteArrayToUtf8([228,189,160,229,165,189]);
|
|
|
*/
|
|
|
- byteArrayToUtf8: function(byteArray) {
|
|
|
+ static byteArrayToUtf8(byteArray) {
|
|
|
const str = Utils.byteArrayToChars(byteArray);
|
|
|
try {
|
|
|
const utf8Str = utf8.decode(str);
|
|
@@ -465,7 +477,7 @@ const Utils = {
|
|
|
// If it fails, treat it as ANSI
|
|
|
return str;
|
|
|
}
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -481,14 +493,14 @@ const Utils = {
|
|
|
* // returns "你好"
|
|
|
* Utils.byteArrayToChars([20320,22909]);
|
|
|
*/
|
|
|
- byteArrayToChars: function(byteArray) {
|
|
|
+ static byteArrayToChars(byteArray) {
|
|
|
if (!byteArray) return "";
|
|
|
let str = "";
|
|
|
for (let i = 0; i < byteArray.length;) {
|
|
|
str += String.fromCharCode(byteArray[i++]);
|
|
|
}
|
|
|
return str;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -502,221 +514,10 @@ const Utils = {
|
|
|
* // returns "hello"
|
|
|
* Utils.arrayBufferToStr(Uint8Array.from([104,101,108,108,111]).buffer);
|
|
|
*/
|
|
|
- arrayBufferToStr: function(arrayBuffer, utf8=true) {
|
|
|
+ static arrayBufferToStr(arrayBuffer, utf8=true) {
|
|
|
const byteArray = Array.prototype.slice.call(new Uint8Array(arrayBuffer));
|
|
|
return utf8 ? Utils.byteArrayToUtf8(byteArray) : Utils.byteArrayToChars(byteArray);
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Base64's the input byte array using the given alphabet, returning a string.
|
|
|
- *
|
|
|
- * @param {byteArray|Uint8Array|string} data
|
|
|
- * @param {string} [alphabet]
|
|
|
- * @returns {string}
|
|
|
- *
|
|
|
- * @example
|
|
|
- * // returns "SGVsbG8="
|
|
|
- * Utils.toBase64([72, 101, 108, 108, 111]);
|
|
|
- *
|
|
|
- * // returns "SGVsbG8="
|
|
|
- * Utils.toBase64("Hello");
|
|
|
- */
|
|
|
- toBase64: function(data, alphabet) {
|
|
|
- if (!data) return "";
|
|
|
- if (typeof data == "string") {
|
|
|
- data = Utils.strToByteArray(data);
|
|
|
- }
|
|
|
-
|
|
|
- alphabet = alphabet ?
|
|
|
- Utils.expandAlphRange(alphabet).join("") :
|
|
|
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
|
- let output = "",
|
|
|
- chr1, chr2, chr3,
|
|
|
- enc1, enc2, enc3, enc4,
|
|
|
- i = 0;
|
|
|
-
|
|
|
- while (i < data.length) {
|
|
|
- chr1 = data[i++];
|
|
|
- chr2 = data[i++];
|
|
|
- chr3 = data[i++];
|
|
|
-
|
|
|
- enc1 = chr1 >> 2;
|
|
|
- enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
|
|
- enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
|
|
- enc4 = chr3 & 63;
|
|
|
-
|
|
|
- if (isNaN(chr2)) {
|
|
|
- enc3 = enc4 = 64;
|
|
|
- } else if (isNaN(chr3)) {
|
|
|
- enc4 = 64;
|
|
|
- }
|
|
|
-
|
|
|
- output += alphabet.charAt(enc1) + alphabet.charAt(enc2) +
|
|
|
- alphabet.charAt(enc3) + alphabet.charAt(enc4);
|
|
|
- }
|
|
|
-
|
|
|
- return output;
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * UnBase64's the input string using the given alphabet, returning a byte array.
|
|
|
- *
|
|
|
- * @param {byteArray} data
|
|
|
- * @param {string} [alphabet]
|
|
|
- * @param {string} [returnType="string"] - Either "string" or "byteArray"
|
|
|
- * @param {boolean} [removeNonAlphChars=true]
|
|
|
- * @returns {byteArray}
|
|
|
- *
|
|
|
- * @example
|
|
|
- * // returns "Hello"
|
|
|
- * Utils.fromBase64("SGVsbG8=");
|
|
|
- *
|
|
|
- * // returns [72, 101, 108, 108, 111]
|
|
|
- * Utils.fromBase64("SGVsbG8=", null, "byteArray");
|
|
|
- */
|
|
|
- fromBase64: function(data, alphabet, returnType, removeNonAlphChars) {
|
|
|
- returnType = returnType || "string";
|
|
|
-
|
|
|
- if (!data) {
|
|
|
- return returnType === "string" ? "" : [];
|
|
|
- }
|
|
|
-
|
|
|
- alphabet = alphabet ?
|
|
|
- Utils.expandAlphRange(alphabet).join("") :
|
|
|
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
|
- if (removeNonAlphChars === undefined)
|
|
|
- removeNonAlphChars = true;
|
|
|
-
|
|
|
- let output = [],
|
|
|
- chr1, chr2, chr3,
|
|
|
- enc1, enc2, enc3, enc4,
|
|
|
- i = 0;
|
|
|
-
|
|
|
- if (removeNonAlphChars) {
|
|
|
- const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
|
|
|
- data = data.replace(re, "");
|
|
|
- }
|
|
|
-
|
|
|
- while (i < data.length) {
|
|
|
- enc1 = alphabet.indexOf(data.charAt(i++));
|
|
|
- enc2 = alphabet.indexOf(data.charAt(i++) || "=");
|
|
|
- enc3 = alphabet.indexOf(data.charAt(i++) || "=");
|
|
|
- enc4 = alphabet.indexOf(data.charAt(i++) || "=");
|
|
|
-
|
|
|
- enc2 = enc2 === -1 ? 64 : enc2;
|
|
|
- enc3 = enc3 === -1 ? 64 : enc3;
|
|
|
- enc4 = enc4 === -1 ? 64 : enc4;
|
|
|
-
|
|
|
- chr1 = (enc1 << 2) | (enc2 >> 4);
|
|
|
- chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
|
|
- chr3 = ((enc3 & 3) << 6) | enc4;
|
|
|
-
|
|
|
- output.push(chr1);
|
|
|
-
|
|
|
- if (enc3 !== 64) {
|
|
|
- output.push(chr2);
|
|
|
- }
|
|
|
- if (enc4 !== 64) {
|
|
|
- output.push(chr3);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return returnType === "string" ? Utils.byteArrayToUtf8(output) : output;
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Convert a byte array into a hex string.
|
|
|
- *
|
|
|
- * @param {Uint8Array|byteArray} data
|
|
|
- * @param {string} [delim=" "]
|
|
|
- * @param {number} [padding=2]
|
|
|
- * @returns {string}
|
|
|
- *
|
|
|
- * @example
|
|
|
- * // returns "0a 14 1e"
|
|
|
- * Utils.toHex([10,20,30]);
|
|
|
- *
|
|
|
- * // returns "0a:14:1e"
|
|
|
- * Utils.toHex([10,20,30], ":");
|
|
|
- */
|
|
|
- toHex: function(data, delim, padding) {
|
|
|
- if (!data) return "";
|
|
|
-
|
|
|
- delim = typeof delim == "string" ? delim : " ";
|
|
|
- padding = padding || 2;
|
|
|
- let output = "";
|
|
|
-
|
|
|
- for (let i = 0; i < data.length; i++) {
|
|
|
- output += data[i].toString(16).padStart(padding, "0") + delim;
|
|
|
- }
|
|
|
-
|
|
|
- // Add \x or 0x to beginning
|
|
|
- if (delim === "0x") output = "0x" + output;
|
|
|
- if (delim === "\\x") output = "\\x" + output;
|
|
|
-
|
|
|
- if (delim.length)
|
|
|
- return output.slice(0, -delim.length);
|
|
|
- else
|
|
|
- return output;
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Convert a byte array into a hex string as efficiently as possible with no options.
|
|
|
- *
|
|
|
- * @param {byteArray} data
|
|
|
- * @returns {string}
|
|
|
- *
|
|
|
- * @example
|
|
|
- * // returns "0a141e"
|
|
|
- * Utils.toHex([10,20,30]);
|
|
|
- */
|
|
|
- toHexFast: function(data) {
|
|
|
- if (!data) return "";
|
|
|
-
|
|
|
- const output = [];
|
|
|
-
|
|
|
- for (let i = 0; i < data.length; i++) {
|
|
|
- output.push((data[i] >>> 4).toString(16));
|
|
|
- output.push((data[i] & 0x0f).toString(16));
|
|
|
- }
|
|
|
-
|
|
|
- return output.join("");
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Convert a hex string into a byte array.
|
|
|
- *
|
|
|
- * @param {string} data
|
|
|
- * @param {string} [delim]
|
|
|
- * @param {number} [byteLen=2]
|
|
|
- * @returns {byteArray}
|
|
|
- *
|
|
|
- * @example
|
|
|
- * // returns [10,20,30]
|
|
|
- * Utils.fromHex("0a 14 1e");
|
|
|
- *
|
|
|
- * // returns [10,20,30]
|
|
|
- * Utils.fromHex("0a:14:1e", "Colon");
|
|
|
- */
|
|
|
- fromHex: function(data, delim, byteLen) {
|
|
|
- delim = delim || (data.indexOf(" ") >= 0 ? "Space" : "None");
|
|
|
- byteLen = byteLen || 2;
|
|
|
- if (delim !== "None") {
|
|
|
- const delimRegex = Utils.regexRep[delim];
|
|
|
- data = data.replace(delimRegex, "");
|
|
|
- }
|
|
|
-
|
|
|
- const output = [];
|
|
|
- for (let i = 0; i < data.length; i += byteLen) {
|
|
|
- output.push(parseInt(data.substr(i, byteLen), 16));
|
|
|
- }
|
|
|
- return output;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -729,14 +530,13 @@ const Utils = {
|
|
|
* // returns [["head1", "head2"], ["data1", "data2"]]
|
|
|
* Utils.parseCSV("head1,head2\ndata1,data2");
|
|
|
*/
|
|
|
- parseCSV: function(data) {
|
|
|
-
|
|
|
+ static parseCSV(data) {
|
|
|
let b,
|
|
|
ignoreNext = false,
|
|
|
inString = false,
|
|
|
cell = "",
|
|
|
- line = [],
|
|
|
- lines = [];
|
|
|
+ line = [];
|
|
|
+ const lines = [];
|
|
|
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
|
b = data[i];
|
|
@@ -769,26 +569,27 @@ const Utils = {
|
|
|
}
|
|
|
|
|
|
return lines;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Removes all HTML (or XML) tags from the input string.
|
|
|
*
|
|
|
* @param {string} htmlStr
|
|
|
- * @param {boolean} removeScriptAndStyle - Flag to specify whether to remove entire script or style blocks
|
|
|
+ * @param {boolean} [removeScriptAndStyle=false]
|
|
|
+ * - Flag to specify whether to remove entire script or style blocks
|
|
|
* @returns {string}
|
|
|
*
|
|
|
* @example
|
|
|
* // returns "Test"
|
|
|
* Utils.stripHtmlTags("<div>Test</div>");
|
|
|
*/
|
|
|
- stripHtmlTags: function(htmlStr, removeScriptAndStyle) {
|
|
|
+ static stripHtmlTags(htmlStr, removeScriptAndStyle=false) {
|
|
|
if (removeScriptAndStyle) {
|
|
|
htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
|
|
|
}
|
|
|
return htmlStr.replace(/<[^>]+>/g, "");
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -802,7 +603,7 @@ const Utils = {
|
|
|
* // return "A <script> tag"
|
|
|
* Utils.escapeHtml("A <script> tag");
|
|
|
*/
|
|
|
- escapeHtml: function(str) {
|
|
|
+ static escapeHtml(str) {
|
|
|
const HTML_CHARS = {
|
|
|
"&": "&",
|
|
|
"<": "<",
|
|
@@ -816,7 +617,7 @@ const Utils = {
|
|
|
return str.replace(/[&<>"'/`]/g, function (match) {
|
|
|
return HTML_CHARS[match];
|
|
|
});
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -829,7 +630,7 @@ const Utils = {
|
|
|
* // return "A <script> tag"
|
|
|
* Utils.unescapeHtml("A <script> tag");
|
|
|
*/
|
|
|
- unescapeHtml: function(str) {
|
|
|
+ static unescapeHtml(str) {
|
|
|
const HTML_CHARS = {
|
|
|
"&": "&",
|
|
|
"<": "<",
|
|
@@ -843,7 +644,7 @@ const Utils = {
|
|
|
return str.replace(/&#?x?[a-z0-9]{2,4};/ig, function (match) {
|
|
|
return HTML_CHARS[match] || match;
|
|
|
});
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -868,7 +669,7 @@ const Utils = {
|
|
|
* @param {string} str
|
|
|
* @returns {string}
|
|
|
*/
|
|
|
- encodeURIFragment: function(str) {
|
|
|
+ static encodeURIFragment(str) {
|
|
|
const LEGAL_CHARS = {
|
|
|
"%2D": "-",
|
|
|
"%2E": ".",
|
|
@@ -895,7 +696,7 @@ const Utils = {
|
|
|
return str.replace(/%[0-9A-F]{2}/g, function (match) {
|
|
|
return LEGAL_CHARS[match] || match;
|
|
|
});
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -909,10 +710,10 @@ const Utils = {
|
|
|
* for users.
|
|
|
*
|
|
|
* @param {Object[]} recipeConfig
|
|
|
- * @param {boolean} newline - whether to add a newline after each operation
|
|
|
+ * @param {boolean} [newline=false] - whether to add a newline after each operation
|
|
|
* @returns {string}
|
|
|
*/
|
|
|
- generatePrettyRecipe: function(recipeConfig, newline) {
|
|
|
+ static generatePrettyRecipe(recipeConfig, newline=false) {
|
|
|
let prettyConfig = "",
|
|
|
name = "",
|
|
|
args = "",
|
|
@@ -935,27 +736,26 @@ const Utils = {
|
|
|
if (newline) prettyConfig += "\n";
|
|
|
});
|
|
|
return prettyConfig;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Converts a recipe string to the JSON representation of the recipe.
|
|
|
- * Accepts either stringified JSON or bespoke "pretty" recipe format.
|
|
|
+ * Accepts either stringified JSON or the bespoke "pretty" recipe format.
|
|
|
*
|
|
|
* @param {string} recipe
|
|
|
* @returns {Object[]}
|
|
|
*/
|
|
|
- parseRecipeConfig: function(recipe) {
|
|
|
+ static parseRecipeConfig(recipe) {
|
|
|
recipe = recipe.trim();
|
|
|
if (recipe.length === 0) return [];
|
|
|
if (recipe[0] === "[") return JSON.parse(recipe);
|
|
|
|
|
|
// Parse bespoke recipe format
|
|
|
recipe = recipe.replace(/\n/g, "");
|
|
|
- let m,
|
|
|
- recipeRegex = /([^(]+)\(((?:'[^'\\]*(?:\\.[^'\\]*)*'|[^)/'])*)(\/[^)]+)?\)/g,
|
|
|
- recipeConfig = [],
|
|
|
- args;
|
|
|
+ let m, args;
|
|
|
+ const recipeRegex = /([^(]+)\(((?:'[^'\\]*(?:\\.[^'\\]*)*'|[^)/'])*)(\/[^)]+)?\)/g,
|
|
|
+ recipeConfig = [];
|
|
|
|
|
|
while ((m = recipeRegex.exec(recipe))) {
|
|
|
// Translate strings in args back to double-quotes
|
|
@@ -966,7 +766,7 @@ const Utils = {
|
|
|
.replace(/\\'/g, "'"); // Unescape single quotes
|
|
|
args = "[" + args + "]";
|
|
|
|
|
|
- let op = {
|
|
|
+ const op = {
|
|
|
op: m[1].replace(/_/g, " "),
|
|
|
args: JSON.parse(args)
|
|
|
};
|
|
@@ -975,7 +775,7 @@ const Utils = {
|
|
|
recipeConfig.push(op);
|
|
|
}
|
|
|
return recipeConfig;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -1005,24 +805,9 @@ const Utils = {
|
|
|
* // returns "5 days"
|
|
|
* Utils.fuzzyTime(456851321);
|
|
|
*/
|
|
|
- fuzzyTime: function(ms) {
|
|
|
+ static fuzzyTime(ms) {
|
|
|
return moment.duration(ms, "milliseconds").humanize();
|
|
|
- },
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * Adds the properties of one Object to another.
|
|
|
- *
|
|
|
- * @param {Object} a
|
|
|
- * @param {Object} b
|
|
|
- * @returns {Object}
|
|
|
- */
|
|
|
- extend: function(a, b){
|
|
|
- for (const key in b)
|
|
|
- if (b.hasOwnProperty(key))
|
|
|
- a[key] = b[key];
|
|
|
- return a;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -1036,7 +821,7 @@ const Utils = {
|
|
|
* @param {Object[]} files
|
|
|
* @returns {html}
|
|
|
*/
|
|
|
- displayFilesAsHTML: function(files) {
|
|
|
+ static displayFilesAsHTML(files) {
|
|
|
/* <NL> and <SP> used to denote newlines and spaces in HTML markup.
|
|
|
* If a non-html operation is used, all markup will be removed but these
|
|
|
* whitespace chars will remain for formatting purposes.
|
|
@@ -1071,7 +856,7 @@ const Utils = {
|
|
|
title='Download ${Utils.escapeHtml(file.fileName)}'
|
|
|
download='${Utils.escapeHtml(file.fileName)}'>💾</a>`;
|
|
|
|
|
|
- const hexFileData = Utils.toHexFast(new Uint8Array(file.bytes));
|
|
|
+ const hexFileData = toHexFast(new Uint8Array(file.bytes));
|
|
|
|
|
|
const switchToInputElem = `<a href='#switchFileToInput${i}'
|
|
|
class='file-switch'
|
|
@@ -1117,7 +902,7 @@ const Utils = {
|
|
|
return html.replace(/(?:(<pre>(?:\n|.)*<\/pre>)|\s{2,})/g, "$1") // Remove whitespace from markup
|
|
|
.replace(/<NL>/g, "\n") // Replace <NP> with newlines
|
|
|
.replace(/<SP>/g, " "); // Replace <SP> with spaces
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -1131,7 +916,7 @@ const Utils = {
|
|
|
* Utils.parseURIParams("?a=abc&b=123")
|
|
|
* Utils.parseURIParams("#a=abc&b=123")
|
|
|
*/
|
|
|
- parseURIParams: function(paramStr) {
|
|
|
+ static parseURIParams(paramStr) {
|
|
|
if (paramStr === "") return {};
|
|
|
|
|
|
// Cut off ? or # and split on &
|
|
@@ -1153,7 +938,7 @@ const Utils = {
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -1164,9 +949,9 @@ const Utils = {
|
|
|
* @param {number} y
|
|
|
* @returns {number}
|
|
|
*/
|
|
|
- mod: function (x, y) {
|
|
|
+ static mod(x, y) {
|
|
|
return ((x % y) + y) % y;
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -1177,12 +962,12 @@ const Utils = {
|
|
|
* @param {number} y
|
|
|
* @returns {number}
|
|
|
*/
|
|
|
- gcd: function(x, y) {
|
|
|
+ static gcd(x, y) {
|
|
|
if (!y) {
|
|
|
return x;
|
|
|
}
|
|
|
return Utils.gcd(y, x % y);
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
@@ -1193,55 +978,63 @@ const Utils = {
|
|
|
* @param {number} y
|
|
|
* @returns {number}
|
|
|
*/
|
|
|
- modInv: function(x, y) {
|
|
|
+ static modInv(x, y) {
|
|
|
x %= y;
|
|
|
for (let i = 1; i < y; i++) {
|
|
|
if ((x * i) % 26 === 1) {
|
|
|
return i;
|
|
|
}
|
|
|
}
|
|
|
- },
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
|
* A mapping of names of delimiter characters to their symbols.
|
|
|
- * @constant
|
|
|
+ *
|
|
|
+ * @param {string} token
|
|
|
+ * @returns {string}
|
|
|
*/
|
|
|
- charRep: {
|
|
|
- "Space": " ",
|
|
|
- "Comma": ",",
|
|
|
- "Semi-colon": ";",
|
|
|
- "Colon": ":",
|
|
|
- "Line feed": "\n",
|
|
|
- "CRLF": "\r\n",
|
|
|
- "Forward slash": "/",
|
|
|
- "Backslash": "\\",
|
|
|
- "0x": "0x",
|
|
|
- "\\x": "\\x",
|
|
|
- "Nothing (separate chars)": "",
|
|
|
- "None": "",
|
|
|
- },
|
|
|
+ static charRep(token) {
|
|
|
+ return {
|
|
|
+ "Space": " ",
|
|
|
+ "Comma": ",",
|
|
|
+ "Semi-colon": ";",
|
|
|
+ "Colon": ":",
|
|
|
+ "Line feed": "\n",
|
|
|
+ "CRLF": "\r\n",
|
|
|
+ "Forward slash": "/",
|
|
|
+ "Backslash": "\\",
|
|
|
+ "0x": "0x",
|
|
|
+ "\\x": "\\x",
|
|
|
+ "Nothing (separate chars)": "",
|
|
|
+ "None": "",
|
|
|
+ }[token];
|
|
|
+ }
|
|
|
|
|
|
|
|
|
/**
|
|
|
* A mapping of names of delimiter characters to regular expressions which can select them.
|
|
|
- * @constant
|
|
|
+ *
|
|
|
+ * @param {string} token
|
|
|
+ * @returns {RegExp}
|
|
|
*/
|
|
|
- regexRep: {
|
|
|
- "Space": /\s+/g,
|
|
|
- "Comma": /,/g,
|
|
|
- "Semi-colon": /;/g,
|
|
|
- "Colon": /:/g,
|
|
|
- "Line feed": /\n/g,
|
|
|
- "CRLF": /\r\n/g,
|
|
|
- "Forward slash": /\//g,
|
|
|
- "Backslash": /\\/g,
|
|
|
- "0x": /0x/g,
|
|
|
- "\\x": /\\x/g,
|
|
|
- "None": /\s+/g // Included here to remove whitespace when there shouldn't be any
|
|
|
- },
|
|
|
+ static regexRep(token) {
|
|
|
+ return {
|
|
|
+ "Space": /\s+/g,
|
|
|
+ "Comma": /,/g,
|
|
|
+ "Semi-colon": /;/g,
|
|
|
+ "Colon": /:/g,
|
|
|
+ "Line feed": /\n/g,
|
|
|
+ "CRLF": /\r\n/g,
|
|
|
+ "Forward slash": /\//g,
|
|
|
+ "Backslash": /\\/g,
|
|
|
+ "0x": /0x/g,
|
|
|
+ "\\x": /\\x/g,
|
|
|
+ "None": /\s+/g // Included here to remove whitespace when there shouldn't be any
|
|
|
+ }[token];
|
|
|
+ }
|
|
|
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
export default Utils;
|
|
|
|
|
@@ -1259,7 +1052,7 @@ export default Utils;
|
|
|
* ["One", "Two", "Three", "One"].unique();
|
|
|
*/
|
|
|
Array.prototype.unique = function() {
|
|
|
- let u = {}, a = [];
|
|
|
+ const u = {}, a = [];
|
|
|
for (let i = 0, l = this.length; i < l; i++) {
|
|
|
if (u.hasOwnProperty(this[i])) {
|
|
|
continue;
|