///
///
///
///
export var ip = require('./ip');
export var epoch = require('./epoch');
export var config = require('./config');
import crypto = require('crypto');
/*
Common utility functions
*/
var iconv = require("iconv-lite");
export function superRandom(bytes: number = 20) {
return crypto.randomBytes(bytes).toString('base64');
}
// return whether an object is an array or not
export function isArray(obj): boolean {
return Object.prototype.toString.call(obj) === '[object Array]';
}
// Add a prefix to all the attributes. This is used when manipulating nested objects.
export function prefixAttributes(obj: Object, prefix: string): Object {
for (var attrib in obj) {
if (obj.hasOwnProperty(attrib)) {
// skip over arrays and $ operators
if (!isArray(obj) && attrib.substr(0, 1) != '$' && attrib.substr(0, prefix.length) != prefix) {
obj[prefix + '.' + attrib] = obj[attrib];
delete obj[attrib];
} else {
if (typeof obj[attrib] == 'object') {
obj[attrib] = prefixAttributes(obj[attrib], prefix);
}
}
}
}
return obj;
}
export function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
// Convert an integer to a 4 byte array
export function toBytes(num: number) {
var data = new Uint8Array(4);
for (var i = 0; i < 4; i++) {
data[i] = (num >> (i * 8)) & 0xff;
}
return data;
}
export function uuid(len?: number, radix?: number) {
var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
var chars = CHARS, uuid = [], i;
radix = radix || chars.length;
if (len) {
// Compact form
for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
} else {
// rfc4122, version 4 form
var r;
// rfc4122 requires these characters
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4';
// Fill in random data. At i==19 set the high bits of clock sequence as
// per rfc4122, sec. 4.1.5
for (i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | Math.random() * 16;
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
}
}
}
return uuid.join('');
}
/**
* this base62 is only safe for decoding to integers
*/
export function base62decode(a: string): number {
var b, c, d;
for (
b = c = ( // 'false - 1' will return '-1' and 'true - 1' will return '0'
a === (/\W|_|^$/.test(a += "") || a) // tests if 'a' is a properly base62-encoded string and coerces it to one
? 1 : 0) - 1; // so, 'b' and 'c' are initialized with either '-1' or '0'
d = a.charCodeAt(c++); // if 'c' equals '-1', 'd' is 'NaN' which breaks the loop execution
)
b = b * 62 + d - [, 48, 29, 87][d >> 5]; // See comments : https://gist.github.com/1170594#gistcomment-48129
return b; // positive base10 integer or '-1' if 'a' is not a base62 encoded string
}
/**
* this base62 is only safe for encoding integers
*/
export function base62encode(a): string {
var b, c;
for (
a = a !== +a || a % 1 ? -1 : a, b = ""; // if not a base10 integer, 'a' will be '-1'
// for example, '.5 % 1 == .5' but '1 % 1 == 0'
a >= 0; // also prevents the user to use negative base10 integers
a = Math.floor(a / 62) || -1 // using a bitwise hack here will fail with great numbers
)
// a%62 -> 0-61
// 0-9 | 36-61 | 10-35
// 48-57 | 65-90 | 97-121
// 0-9 | A-Z | a-z
b = String.fromCharCode(((c = a % 62) > 9 ? c > 35 ? 29 : 87 : 48) + c) + b;
return b; // will return either an empty or a base62-encoded string
}
export function isUTF8(charset) {
if (!charset) {
return true;
}
charset = charset.toLowerCase();
return charset === 'utf8' || charset === 'utf-8';
}
export function padLeft(value: any, padChar: string, padCount: number) {
var str = "" + value;
var padBuff = Array(padCount + 1);
var pad = padBuff.join(padChar);
return pad.substring(0, pad.length - str.length) + str
}
export function urlDecode(str, charset) {
if (isUTF8(charset)) {
try {
return decodeURIComponent(str);
} catch (err) {
return str;
}
}
var bytes = [];
for (var i = 0; i < str.length;) {
if (str[i] === '%') {
i++;
bytes.push(parseInt(str.substring(i, i + 2), 16));
i += 2;
} else {
bytes.push(str.charCodeAt(i));
i++;
}
}
var buf = new Buffer(bytes);
return iconv.decode(buf, charset);
}
// SHALLOW clone an object into a new object. No functions will be carried over.
export function clone(o: Object): Object {
var copy = Object.create(o.constructor.prototype);
if (!o || typeof (o) != 'object')
return o;
return JSON.parse(JSON.stringify(o));
}
// Concatenate two objects into the first object
export function extend(o1: Object, o2: Object): Object {
if (o1 == null || o2 == null)
return o1;
for (var key in o2)
if (o2.hasOwnProperty(key))
o1[key] = o2[key];
}
/**
* Copies the specified property from the second object into the first object if it exists
* returns true if the property was found and copied
*/
export function copyProperty(
/**
* The property you are copying
*/
property: string,
/**
* The object you are copying to
*/
o1: Object,
/**
* The object you are copying from
*/
o2: Object,
/**
* Allow the copying of null values
*/
allowNull: boolean = false,
/**
* Allow the copying of empty values
*/
allowEmpty: boolean = false): boolean {
if (o1 == null || o2 == null)
throw new Error('both objects must have a value');
if (property == null)
throw new Error('you must specify a property value');
/// I felt this was far more readable than the alternative method started with
var copy = false;
if (o2.hasOwnProperty(property)) {
if (allowNull && o2[property] == null) {
copy = true;
}
else if (o2[property] instanceof Date) {
copy = true;
}
else if (o2[property] != null) {
if (allowEmpty || typeof o2[property] !== 'object') {
copy = true;
}
else if (!empty(o2[property])) {
copy = true;
}
}
}
if (copy)
o1[property] = o2[property];
return copy;
}
export function isFunction(functionToCheck) {
var getType = {};
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}
// replaceAll string function, needed since javascript's replace function only replaces the first instance
export function replaceAll(original: string, search: string, replacement: string) {
return original.split(search).join(replacement);
}
// Format an object to html with indentation and spaces
export function htmlify(obj): string {
return '
' + JSON.stringify(obj, null, 4) + '
';
}
// Return whether an object is empty or noe
export function empty(obj: Object): boolean {
return Object.keys(obj).length == 0;
}
// trim a specific string off the start of a string
export function trimStart(value: string, start: string) {
if (value.length == 0) return value;
start = start ? start : ' ';
var i = 0, val = 0;
for (; value.charAt(i) == start && i < value.length; i++);
return value.substring(i);
}
/**
* Get the value from a cookie from the raw header string
*/
export function parseCookieValueFromString(headerVal: string, key: string) {
var result;
return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(headerVal)) ? (result[1]) : null;
}
// trim a specific string off the end of a string
export function trimEnd(val: string, end: string): string {
if (val.slice(-end.length) === end)
return val.substr(0, val.length - end.length);
else
return val;
}
// Repeat a string N times
export function repeat(val: string, n: number): string {
n = n || 1;
return Array(n + 1).join(val);
}
// Repeat html spaces N times
export function spaces(n: number): string {
return this.repeat(' ', n);
}
// merge two object - overwrite existing elements, if specified
export function merge(o1: any, o2: any, overwrite: boolean): Object {
if (!o1)
return o2;
var o: Object = clone(o1);
for (var key in o2) {
if (o2.hasOwnProperty(key)) {
if (o[key] == undefined) {
o[key] = o2[key];
} else {
if (typeof o2[key] == 'object') {
o[key] = merge(o[key], o2[key], overwrite);
} else {
if (overwrite) {
o[key] = o2[key];
}
}
}
}
}
return o;
}
export function validEmail(email: string) {
return email && email.indexOf('@') > -1 && email.indexOf('.') > -1;
}
// Collect missing arguments on a REST request
export function missingParams(params: Object, requiredParams: Array): Array {
var missing = [];
for (var a = 0; a < requiredParams.length; a++) {
if (!params || !params.hasOwnProperty(requiredParams[a])) {
missing.push(requiredParams[a]);
}
}
return missing;
}
/**
* Generates a GUID string.
* example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
*/
export function guid() {
function _p8(s?) {
var p = (Math.random().toString(16) + "000000000").substr(2, 8);
return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p;
}
return _p8() + _p8(true) + _p8(true) + _p8();
}
// Return a 32-bit integer hash from a string. This uses a variation of the murmur3 hash algorithm. The collision
// rate is very small.
// Params: input - the string to hash
export function hash(input: string): number {
var hash = 0, len: number;
for (var i = 0, len = input.length; i < len; i++) {
hash = ((hash << 5) - hash) + input.charCodeAt(i);
hash |= 0;
}
return hash;
}