(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.date = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0) --n diff += (7 * n) this.update(diff * _day) return this } /** * Update the date * * @param {Number} ms * @return {Date} * @api private */ date.prototype.update = function (ms) { this.date = new Date(this.date.getTime() + ms) return this } /** * leap year * * @param {Number} yr * @return {Boolean} */ function leapyear (yr) { return (yr % 4 === 0 && yr % 100 !== 0) || yr % 400 === 0 } },{"debug":10}],3:[function(require,module,exports){ module.exports={ "op": { "plus": ["and", "plus", "+", "add", "on"], "minus": ["minus", "subtract"], "times": ["times", "multiply"], "divide": ["divide"] }, "o": { "plus": ["at", "in", "past", "late", "later", "after", "next", "from", "start", "starting", "since", "coming"], "minus": ["last", "minus", "subtract", "ago", "before", "from"] }, "n": { "0.25": ["quarter"], "0.5": ["half", "1/2", "half an"], "0": ["zero"], "1": ["one", "a", "an", "first"], "2": ["two", "second"], "3": ["three", "third"], "4": ["four", "fourth"], "5": ["five", "fifth"], "6": ["six", "sixth"], "7": ["seven", "seventh"], "8": ["eight", "eighth"], "9": ["nine", "ninth"], "10": ["ten", "tenth"], "11": ["eleven", "eleventh"], "12": ["twelve", "twelveth"], "13": ["thirteen", "thirteenth"], "14": ["fourteen", "fourteenth"], "15": ["fifteen", "fifteenth"], "16": ["sixteen", "sixteenth"], "17": ["seventeen", "seventeenth"], "18": ["eighteen", "eighteenth"], "19": ["nineteen", "nineteenth"], "20": ["twenty", "twentieth"], "30": ["thirty", "thirtieth"], "40": ["fourty", "fourtieth"], "50": ["fifty", "fiftieth"], "60": ["sixty", "sixtieth"], "70": ["seventy", "seventieth"], "80": ["eighty", "eightieth"], "90": ["ninety", "ninetieth"], "100": ["hundred", "hundreds", "hundredth"], "1000": ["thousand", "thousands", "thousandth", "k", "K"] }, "t": { }, "dt": { "s": ["second", "seconds", "s", "sec", "secs"], "m": ["minute", "minutes", "m", "min", "mins"], "h": ["hour", "hours", "h", "hr", "hrs"], "d": ["day", "days", "d", "dai"], "w": ["week", "weeks", "w", "wk", "wks"], "M": ["month", "months", "monthes", "M", "mo", "moon", "moons"], "y": ["year", "years", "y", "yr", "yrs"] }, "T": { "t:,dt:=3h": ["later", "soon"], "t:=1d,dt:": ["st", "nd", "rd", "th", "st day", "nd day", "rd day", "th day"], "t:,dt:1w": ["st week", "nd week", "rd week", "th week"], "t:,dt:14d": ["day", "fortnight"], "t:=0h=0m=0s1mer,dt:": ["pm", "p.m", "p.m.", "noon"], "t:,dt:1d": ["tomorrow", "tmr"], "t:,dt:-1d": ["yesterday", "ytd"], "t:,0dt:": ["today"], "t:=2h=0m=0s1mer,dt:": ["afternoon"], "t:=6h=0m=0s0mer,dt:": ["dawn"], "t:=7h=0m=0s0mer,dt:": ["am", "a.m", "a.m."], "t:=7h=0m=0s1mer,dt:": ["evening"], "t:=8h=0m=0s0mer,dt:": ["morning"], "t:=9h=0m=0s1mer,dt:": ["tonight", "night"], "t:=0h=0m=0s0mer,dt:1d": ["midnight"], "t:,dt:=0w0wd": ["sunday", "sun"], "t:,dt:=0w1wd": ["monday", "mon"], "t:,dt:=0w2wd": ["tuesday", "tue", "tues"], "t:,dt:=0w3wd": ["wednesday", "wed"], "t:,dt:=0w4wd": ["thursday", "thu", "thur", "thurs"], "t:,dt:=0w5wd": ["friday", "fri"], "t:,dt:=0w6wd": ["saturday", "sat"], "t:1M=1d,dt:": ["january", "jan"], "t:2M=1d,dt:": ["february", "feb"], "t:3M=1d,dt:": ["march", "mar"], "t:4M=1d,dt:": ["april", "apr"], "t:5M=1d,dt:": ["may"], "t:6M=1d,dt:": ["june", "jun"], "t:7M=1d,dt:": ["july", "jul"], "t:8M=1d,dt:": ["august", "aug"], "t:9M=1d,dt:": ["september", "sept", "sep"], "t:10M=1d,dt:": ["october", "oct"], "t:11M=1d,dt:": ["november", "nov"], "t:12M=1d,dt:": ["december", "dec"], "t:12M25d,dt:": ["christmas"] }, "f": { "1": ["once"], "2": ["twice"] } } },{}],4:[function(require,module,exports){ // Production rule module for the CFG // !leap year // !proper carry considering # of days per month /** * Module Dependencies */ var _ = require('./subdash') var util = require('./util') var symbol = require('./symbol') var tokenize = require('./tokenize') /** * Export `norm` */ module.exports = norm // a partial implementation of norm /** * Preprocess a string using the human language for time CFG, return a triple of original str, preprocessed tokens, and the normal forms (extracted dates in normal forms) */ function norm (str, offset) { try { // Production rules: CFG algorithm for human language for time var tokObj = tokenize(str) // console.log('p#0: parse normal forms', tokObj) var syms = pickTokens(tokObj.symbols) || [] // console.log('p#0: remove nulls, pick tokens', syms) syms = reduce(syms, ['n', 'n']) // console.log('p#1: arithmetics: [] ~ , + if n1 > n2, * else', syms) syms = nTnRedistribute(syms) // console.log('p#2: redistribute, [] ~ [] ', syms) syms = reduce(syms, ['o', 'o']) // console.log('p#3: ~ *', syms) // preprocessing ends, now format output var restored = restoreTokens(syms, tokObj) return restored } catch (e) { return { str: str, tokens: [], normals: [] } } } /** * format a preprocessed array of symbols back into string, using some info from tokObj */ function restoreTokens (syms, tokObj) { var tokens = [], normals = [], tokensOut = tokObj.tokensOut, tokensIn = tokObj.tokensIn syms = util.removeTnPlus(syms) for (var i = 0; i < syms.length; i++) { var s = syms[i], sName = util.sName(s), token = '' switch (sName) { case 'n': // if token is already numeric, use it token = (s.token.match(/^\s*[\d\.\-\+]+\s*$/)) ? s.token.trim() : s.value.toString() break case 'T': // handles shits like 1 am ~ t:1h00m,dt:, am (token returned) token = restoreNormal(s) break default: // the other cases like op, o, cron, range token = s.token.toString() } // extract the protected normal string if (typeof token == 'string') { tokens.push(token) } else { // get protected normal forms normals.push(token.normal) } } return { tokens: tokens, str: tokens.join(' ').replace(/\s+/g, ' '), normals: normals } } /** * Given a T symbol, try to restore its normal form (return wrapped in JSON if it's a complete date string {normal: }), or just return the plain string as token */ function restoreNormal (T) { var token = T.token if (token.match(util.reT)) { // if it is normal form, convert back into the normal1 or normal2 strings var split = util.splitT(token) if (_.includes(split, undefined)) { // if it's normal2 form // either it's a date or time var dateArr = split.slice(0, 3), timeArr = split.slice(3) if (timeArr[0] != undefined) { // check time first, it's first signature (hour) is defined // return hh:mm return util.TtoStdT(token).match(/(\d+\:\d+)/)[1] } else { // else it's a date, parse arr and return complete stdT instead // return wrapped in JSON if it's a complete date string return { normal: util.TtoStdT(token) } } } else { // if it's normal1 form, use TtoStd // return wrapped in JSON if it's a complete date string return { normal: util.TtoStdT(token) } } } else if (!util.has_t(T) && util.has_dt(T) && util.has_pureTimeUnit(T)) { // handle pure dt: T that are purel displacement, e.g. week, fortnight var dtStr = '', units = _.keys(T.dt), dt = T.dt // accumulate dtStr for (var i = 0; i < units.length; i++) { var u = units[i], kval = parseFloat(dt[u]), // set number has default, or is 0, 1 numStr = (kval != dt[u] || kval == 0 || Math.abs(kval) == 1) ? '' : dt[u].toString() + ' ' // set canon from lemma only if it exists, and key is word, else use u var canon = u if (T.canon != undefined) { // and if it's also a timeUnit canon = T.canon } else { // get the lemma for u, its canon and key var lemma = util.lemma(u), lemmaCanon = lemma.canon, lemmaKey = lemma.value if (lemmaKey && lemmaKey.match(/^\w+$/)) { canon = lemmaCanon } } // set the units, number, and canonical form of the unit dtStr = dtStr + numStr + canon + ' ' } return dtStr } else { // else it's just plain english, return return token } } // var fakes = { t: { h: '1', m: '00' }, dt: {}, token: 't:1h00m,dt:' } // var fakes = { t: { M: '12', d: '25', m: '00' }, dt: {}, token: 't:12M25d00m,dt:' } // console.log(restoreNormal(fakes)) /** * !Backburner for future extension: Main method: Run the CFG algorithm to parse the string, return JSON of {input, output, diffStr}. Normalize the string before Matt's algorithm runs it. * @example * var str = 'having lunch today at 3 hours after 9am' * norm(str) * // => { input: 'having lunch today at 3 hours after 9am', * output: '2016-03-04T05:00:09Z', * difference: 'having lunch' } */ function CFGproduce (str, offset) { // try all the below till all is elegantly fixed var diffStr = str, finalStr = null, output = str // Production rules: CFG algorithm for human language for time // p#0: tokenize, remove nulls, pick tokens var tokObj = tokenize(str) var syms = pickTokens(tokObj.symbols) // console.log('p#0: parse normal forms, remove nulls, pick tokens', tokObj) try { syms = reduce(syms, ['n', 'n']) // console.log('p#1: arithmetics: [] ~ , + if n1 > n2, * else', syms) syms = nTnRedistribute(syms) // console.log('p#2: redistribute, [] ~ [] ', syms) output = util.tokenToStr(syms) // !okay replace back the normal forms in the str // // !Till future completion: Mute from below // syms = reduce(syms, ['n', 'T']) // // console.log('p#3: [] ~ , * if dt, + if t', syms) // syms = reduce(syms, ['T', 'T']) // // console.log('p#4: [] ~ ', syms) // syms = nDefTSyms(syms) // // console.log('p#5: defaulter ~ , d defaults to t:h', syms) // syms = reduce(syms, ['o', 'o']) // // console.log('p#6: ~ *', syms) // syms = autoHourModding(syms) // syms = weekModding(syms, offset) // // console.log('p#7: modding: meridiem, weeks', syms) // syms = optReduce(syms, ['T', 'T'], ['o'], null, symbol(util.nowT(offset))) // // console.log('p#8: ~ ', syms) // // !future: // // syms = reduce(syms, ['T'], ['r']) // // syms = reduce(syms, ['f', 'T', 'rT'], ['c']) // console.log('tokObj', tokObj) syms = finalizeT(syms, offset) // console.log('p#9: finalizeT with origin', syms) finalStr = symsToStdT(syms, offset) // console.log('finalStr', finalStr) } catch (e) {} // extract the tokens for difference string later // diffStr = util.unparsedStr(tokObj.str, tokObj.symbols) // console.log('diffStr', diffStr) // !convert dt into proper terms return { input: str, // output: new Date(finalStr), output: output, difference: diffStr } } /** * Production rule #0: pick tokens, remove nulls. * 1. break into chunks of arrs delimited by triple-null-or-more * 2. reorder chunks by arr length * 3.1 init candidate = [] * 3.2 pull and push the chunks not containing into candidate * 3.3 pull and push the chunks containing into candidate * 4. pick the last candidate */ function pickTokens (syms) { // 1. 2. 3. var delimited = util.delimSyms(syms), chunks = util.splitSyms(delimited, 'trinull'), candidates = util.orderChunks(chunks) // 4. return candidates.pop() } /** * Reduce an array of symbols with binary operations between permissible symbols. * @param {Array} syms Array of input symbols * @param {Array} varArr String names of permissible variables. * @param {Array} opArr String names of permissible operations. * @return {Array} The reduced result. */ function reduce (syms, varArr, opArr) { if (syms.length < 2) { return syms } // the operator arrays var opArr = opArr || ['op'] // endmark for handling last symbol syms.push('null') // the result, past-pointer(previous non-null symbol), default-op, current-op, and whether current-op is inter-symbol op, i.e. will not be used up var res = [], past = null, defOp = null, op = defOp, interOp = false for (var i = 0; i < syms.length; i++) { var s = syms[i] if (!past || !s) { // edge case or null if (i == 0) { past = s; } } else if (util.isSym(s, opArr)) { // s is an op. mark op as won't be used yet op = s interOp = true // the nDefT for when past = 'n', s = 'o' } else if (util.isSym(past, [varArr[0]]) && util.isSym(s, [varArr[1]])) { // s and past are operable variables specified by varArr past = execOp(past, op, s) // reset after op is used op = defOp interOp = false } else { // no further legal operation made, push and continue // change of class, past is finalized, push to res res.push(past) if (Array.isArray(past)) { // if past was returned from execOp as array (not executed), then flatten it and dont push op to res, since it's already included in op res = _.flatten(res) } else { // if inter-op (not used), push a clone (prevent overwrite later) if (interOp) { res.push(symbol(op.value)) } } // reset op = defOp interOp = false past = s } } return res } /** * Optional reduce: similar to reduce() but either argument is optional. * algorithm: return a T * 1. for each t, dt, do: * 2. for each key in union of keys for Lt, Rt, do: * 3. _Rt = _Rt op _Lt * @param {Array} syms Array of input symbols * @param {Array} varArr String names of permissible variables. * @param {Array} opArr String names of permissible operations. * @param {symbol} Ldef default for left argument * @param {symbol} Rdef default for right argument * @return {Array} The reduced result. */ function optReduce (syms, varArr, opArr, Ldef, Rdef) { if (syms.length < 2) { return syms } // use peek var res = [], sum = null, L = null, R = null for (var i = 0; i < syms.length; i++) { var s = syms[i] if (util.isSym(s, opArr)) { if (sum == null) { L = syms[i - 1] sum = (util.isSym(L, [varArr[0]])) ? L : Ldef } R = syms[i + 1] // if is var skip it since will be consumed if (util.isSym(R, [varArr[1]])) { i++; } // else reset to default else { R = Rdef; } // compute: sum = execOp(sum, s, R) // before loop quits due to possible i++, push the last if (i == syms.length - 1) { res.push(sum) } } else { // s is not opArr, can't have been varArr either // edge case: at first dont push if (i > 0) { res.push(sum) res.push(s) sum = null } } } return res } /** * Execute non-commutative operation between 2 argument symbols and an op symbol; carry out respective ops according to symbol names. * @param {symbol} L Left argument * @param {symbol} op operation * @param {symbol} R Right argument * @param {str} offset The time origin offset * @return {symbol} Result */ function execOp (L, op, R, offset) { var otype = util.opType(L, op, R), res = null if (_.includes(['nn'], otype)) { res = nnOp(L, op, R) } else if (_.includes(['nT'], otype)) { res = nTOp(L, op, R) } else if (_.includes(['TT'], otype)) { res = TTOp(L, op, R) } else if (_.includes(['ToT', 'oT', 'To'], otype)) { res = ToTOp(L, op, R, offset) } else if (_.includes(['oo'], otype)) { res = ooOp(L, R) } else if (_.includes(['rT', 'TrT'], otype)) { // has optional arg res = rTOp(L, R) } else if (_.includes(['cT', 'fcT', 'crT', 'fcrT'], otype)) { // has optional arg res = cTOp(L, R) } else { // not executable, e.g. not in the right order, return fully res = (op == null) ? [L, R] : [L, op, R] } return res } /** * Atomic binary arithmetic operation on the numerical level, with default overriding the argument prepended with '='. * @param {string|Number} Lval The left argument value. * @param {symbol} op The op symbol * @param {string|Number} Rval The right argument value. * @return {Number} Result from the operation. */ function atomicOp (Lval, op, Rval, dontOp) { dontOp = dontOp || false var oName = op.value if (Lval == undefined) { // if L is missing, R must exist tho return (oName == 'minus') ? Rval.toString().replace(/(\d)/, '-$1') : Rval } else if (Rval == undefined) { // if L exists, be it def or not, R missing return Lval } else { // or R exist or is default (parse to NaN), L can be default too but ignore then var defL = Lval.toString().match(/^=/), defR = Rval.toString().match(/^=/) var l = parseFloat(Lval.toString().replace(/^=/, '')), r = parseFloat(Rval.toString().replace(/^=/, '')) if (defL && defR) { // if both are default, return r 'last come last serve' return r } else if (defL && !defR) { // if either default, return the non-default return r } else if (!defL && defR) { return l } else { // none default if (dontOp) { // if is a don't operate together, i.e. for t, just return l // 'first come first serve' return l } else { // make the into proper floats first if (oName == 'minus') { return l - r } else if (oName == 'plus') { return l + r } else if (oName == 'times') { return l * r } else if (oName == 'divide') { return l / r } } } } } /** * p#1: arithmetics: [] ~ , + if n1 > n2, * else */ function nnOp (L, op, R) { var l = L.value, r = R.value // set the default op according to value in nn op if (l > r) { op = op || symbol('plus') } else { op = op || symbol('times') } var res = atomicOp(l, op, r) return symbol(res) } /** * p#2: redistribute, [] ~ [] * algorithm: note that from previous steps no 's can occur adjacently * 1. scan array L to R, on each found: * 2.1 if its R is , continue * 2.2 else, this is the target. do: * 3.1 init carry = []. remove and push into carry, * 3.2 if its L is , remove and prepend into carry, * 4.1 find the first to the left, if not , drop the carry and continue * 4.2 else merge the carry after the * 5. At the end of loop, rerun production rule #1 */ function nTnRedistribute (syms) { if (syms.length < 2) { return syms } // 1. for (var i = 0; i < syms.length; i++) { var s = syms[i] if (util.sName(s) != 'n') { continue } // 1. var R = syms[i + 1] if (util.sName(R) == 'T') { continue } // 2.2 // 3.1 prepare the carry var carry = [] // 3.2 the Left symbol var L = syms[i - 1], Li = -1 if (util.sName(L) == 'op') { // if L is an 'op', remember to pull it later Li = i - 1 } // 4.1 // find L...L of L that is 'n' var LLi = _.findLastIndex(syms.slice(0, i - 1), function (Ls) { return util.sName(Ls) == 'n' }) if (!syms[LLi] || util.sName(syms[LLi + 1]) != 'T') { // if can't find 'n' (index = -1), or the R of 'n' isn't T, abort mission // syms.splice(i, 0, carry) } else { // 4.2 // else, pull s at [i], optional L at [Li], and push at LLi+1 carry.push(_.pullAt(syms, i)[0]) if (Li != -1) { carry.unshift(_.pullAt(syms, Li)[0]) } syms.splice(LLi + 1, 0, carry) syms = _.flatten(syms) } } // 5. redo the op syms = reduce(syms, ['n', 'n']) return syms } /** * p#3: [] ~ , * if dt, + if t * 1. if t can be overidden, start from the highest unit set to n, then return. * 2. otherwise, if
not empty,
= *
, then return * 3. else, if not empty, = +, then return */ function nTOp (nL, op, TR) { var tOverrideUnit = util.highestOverride(TR.t) if (tOverrideUnit) { // 1. TR.t[tOverrideUnit] = nL.value } else if (_.keys(TR.dt).length) { // 2. op = op || symbol('times') for (var k in TR.dt) { if (k == 'wd') { continue } TR.dt[k] = atomicOp(nL.value, op, TR.dt[k]) } } else if (_.keys(TR.t).length) { // 3. op = op || symbol('plus') for (var k in TR.t) { TR.t[k] = atomicOp(nL.value, op, TR.t[k]) } } return TR } /** * p#4: [] ~ */ function TTOp (TL, op, TR) { // set the default op op = op || symbol('plus') // util.sName // mutate into TL for (var k in TR.t) { // okay done add absolute time, just as you don't add origins together put u take gradual specificity, the 'true' param for dontOp if exist, return r // override default tho, taken care of by atomic TL.t[k] = atomicOp(TL.t[k], op, TR.t[k], true) } for (var k in TR.dt) { if (k == 'wd') { continue } TL.dt[k] = atomicOp(TL.dt[k], op, TR.dt[k]) } return TL } /** * p#5: defaulter ~ , d defaults to t:h */ function nDefTSyms (syms) { var res = [] for (var i = 0; i < syms.length; i++) { var s = syms[i] res.push(util.isSym(s, ['n']) ? nDefT(s) : s) } return res } /** * Helper: default a singlet n to T, i.e. next available hour */ function nDefT (n) { var deft = symbol('t:1h,dt:') var nVal = n.value var currentHour = new Date().getHours() var nextnVal = Math.floor(currentHour / 12) * 12 + nVal var tHour = execOp(symbol(nextnVal), symbol('times'), deft) return tHour } /** * ~ * * To handle 'before next' etc. */ function ooOp (L, R) { var Lsign = (L.value == 'plus') ? +1 : -1, Rsign = (R.value == 'plus') ? +1 : -1, LRsign = Lsign * Rsign return (LRsign > 0) ? symbol('after') : symbol('before') } /** * Next available T', given an offset, by incrementing in dt the next unit ++1 from the current largest unit in t. */ function nextAvailable (T, offset) { // find the current largest and next largest unit var nextUnit = util.nextLargestUnit(T) // first finalized T var finT1 = finalizeT([T], offset)[0], stdStr1 = util.TtoStdT(finT1), UTC1 = Date.parse(stdStr1), UTCnow = Date.parse(new Date()), UTCdiff = UTC1 - UTCnow // if UTC1 is not in the future, add next unit if (UTCdiff < 0) { T.dt[nextUnit] = (T.dt[nextUnit] || 0) + 1 var finT2 = finalizeT([T], offset)[0] return finT2 } else { return finT1 } } /** * p#6: ~ */ function ToTOp (L, op, R, offset) { if (L && !R) { // if R is missing, set to now R = symbol(util.nowT(offset)) } else if (!L && R) { // if L missing if (util.has_t(R)) { // if R has t => part of origin, so L shd be the according dt var nextUnit = util.nextLargestUnit(R) R = nextAvailable(R, offset) // so arbitrarily set as 0.5 * next largest unit L = execOp(symbol(0.5), symbol('times'), symbol(nextUnit)) } else { // R has dt only, make L an origin then L = symbol(util.nowT(offset)) } } else if (!L && !R) { L = symbol(util.nowT(offset)) R = symbol(util.nowT(offset)) } var Ttype = ['t', 'dt'] for (var i = 0; i < Ttype.length; i++) { var _Ttype = Ttype[i], // the dontOp for 't' dontOp = (_Ttype == 't') var concatKeys = _.keys(L[_Ttype]).concat(_.keys(R[_Ttype])) var keys = _.unique(concatKeys) for (var j = 0; j < keys.length; j++) { var k = keys[j] // run atomic op, note the reversed order of R op L R[_Ttype][k] = atomicOp(R[_Ttype][k], op, L[_Ttype][k], dontOp) } } return R } /** * p#7: auto-hour-modding: t:h mod 12 * then add the meridiem to t:h if exist */ function autoHourModding (syms) { for (var i = 0; i < syms.length; i++) { var s = syms[i] if (util.isSym(s, ['T'])) { if (syms[i]['t']['h']) { // if t has 'h', mod it var value = syms[i]['t']['h'].toString() var isDefault = (value.match(/^=/) || [])[0] || '' value = parseFloat(value.replace(/^=/, '')) value = value > 12 ? value % 12 : value syms[i]['t']['h'] = isDefault + value } // apply the non-0 meridiem after modding: if (syms[i]['t']['mer']) { var dt_h = (syms[i]['dt']['h'] || '0').toString() // dump default at last dt_h = dt_h.replace(/^=/, '') if (syms[i]['t']['mer'] == 1) { syms[i]['dt']['h'] = parseFloat(dt_h) + 12 } // delete mer delete syms[i]['t']['mer'] } } } return syms } // do it at last, to use like '2nd week of march' function weekModding (syms, offset) { // weekday of the offset to calculate dt:d var offsetWD = new Date(util.TtoStdT(util.nowT())).getDay() for (var i = 0; i < syms.length; i++) { var s = syms[i] if (util.isSym(s, ['T'])) { if (syms[i]['dt']['wd']) { // if dt has 'wd', mod it and turn into dt:d + %wd var WD = parseInt(syms[i]['dt']['wd']) var diffWD = (WD - offsetWD) % 7 if (diffWD < 0) { diffWD = diffWD + 7 } syms[i]['dt']['d'] = (syms[i]['dt']['d'] || 0) + diffWD delete syms[i]['dt']['wd'] } } } return syms } /** * p#8: Finalize each T in syms array: * 1. remove defaults from T * 2. add origin symbol.nowT() with given T.t, override missing units * 3. add t and dt */ function finalizeT (syms, offset) { // remove defaults for (var i = 0; i < syms.length; i++) { syms[i] = removeDefaults(syms[i]) } // default with origin at end syms.push(symbol(util.nowT(offset))) syms = reduce(syms, ['T', 'T']) // combine t and dt var newSyms = [] for (var i = 0; i < syms.length; i++) { var s = syms[i], sum = tdtAdd(s) sum.token = util.TtoStr(sum) newSyms.push(tdtAdd(s)) } return syms } /** * remove the defaults before adding with origin */ function removeDefaults (T) { for (var k in T.dt) { T.dt[k] = T.dt[k].toString().replace(/^=/, '') } for (var k in T.t) { T.t[k] = T.t[k].toString().replace(/^=/, '') } // delete meridiem too delete T['t']['mer'] return T } /** * add t and dt within a T together, delete the dt keys */ function tdtAdd (T) { // guard for non-T if (!util.isSym(T, ['T'])) { return T } for (var k in T.dt) { // absolute add, disregard defaults var t_k = (T.t[k] == undefined) ? 0 : T.t[k], dt_k = T.dt[k] // cleanup the default t_k = t_k.toString().replace(/^=/, '') dt_k = dt_k.toString().replace(/^=/, '') var sum = parseFloat(t_k) + parseFloat(dt_k) // set the result, remove used dt T.t[k] = sum delete T.dt[k] } return T } /** * p#9: Convert an array of symbols to normalized stdT strings. * if token was normal form already, parse into stdT. * if is n: return n.value * else return org token */ function symsToStdT (syms, offset) { var tokens = [] for (var i = 0; i < syms.length; i++) { var s = syms[i], token = s.token.toString() // default, don't switch unless: if (util.isSym(s, ['n'])) { token = s.value } else if (token.match(util.reT)) { // is normal T form token = util.TtoStdT(token, offset) } tokens.push(token) } return tokens.join(' ') } /** * !to be implemented for range */ function rTOp (L, R) { var start, end if (!R) { start = symbol(util.nowT()) end = L } else { start = L end = R } return symbol({ start: start, end: end }) } /** * !to be implemented for cron */ function cTOp (L, R) {} },{"./subdash":6,"./symbol":7,"./tokenize":8,"./util":9}],5:[function(require,module,exports){ /** * Module Dependencies */ var debug = require('debug')('date:parser') var date = require('./date') var norm = require('./norm') /** * Days */ var days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'] var months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december' ] /** * Regexs */ // 5, 05, 5:30, 5.30, 05:30:10, 05:30.10, 05.30.10, at 5 var rMeridiem = /^(\d{1,2})([:.](\d{1,2}))?([:.](\d{1,2}))?\s*([ap]m)/ var rHourMinute = /^(\d{1,2})([:.](\d{1,2}))([:.](\d{1,2}))?/ var rAtHour = /^at\s?(\d{1,2})$/ var rDays = /\b(sun(day)?|mon(day)?|tues(day)?|wed(nesday)?|thur(sday|s)?|fri(day)?|sat(urday)?)s?\b/ var rMonths = /^((\d{1,2})\s*(st|nd|rd|th))\s(day\s)?(of\s)?(january|february|march|april|may|june|july|august|september|october|november|december)/i var rPast = /\b(last|yesterday|ago)\b/ var rDayMod = /\b(morning|noon|afternoon|night|evening|midnight)\b/ var rAgo = /^(\d*)\s?\b(second|minute|hour|day|week|month|year)[s]?\b\s?ago$/ /** * Expose `parser` */ module.exports = parser /** * Initialize `parser` * * @param {String} str * @return {Date} * @api publics */ function parser (str, offset) { if (!(this instanceof parser)) return new parser(str, offset) if (typeof offset == 'string') offset = parser(offset) // CFG preprocessing into normalized format, // get {str, tokens, normals} // !future: return multiple parsed times, some from it var prepro = norm(str, offset) // console.log(prepro) // reset the str to prepro str str = prepro.str // if proprocessed doesn't leave any str to be processed (non-date-time) format, check normals if (!str) { if (prepro.normals.length) { // if there's normal date parsed already, // !return the first return new Date(prepro.normals[0]) } else { // otherwise go back to below to return proper Error str = str } } var d = offset || new Date this.date = new date(d) this.original = str this.str = str.toLowerCase() this.stash = [] this.tokens = [] while (this.advance() !== 'eos') debug('tokens %j', this.tokens) this.nextTime(d) if (this.date.date == d) throw new Error('Invalid date') return this.date.date } /** * Advance a token */ parser.prototype.advance = function () { var tok = this.eos() || this.space() || this._next() || this.last() || this.dayByName() || this.monthByName() || this.timeAgo() || this.ago() || this.yesterday() || this.tomorrow() || this.noon() || this.midnight() || this.night() || this.evening() || this.afternoon() || this.morning() || this.tonight() || this.meridiem() || this.hourminute() || this.athour() || this.week() || this.month() || this.year() || this.second() || this.minute() || this.hour() || this.day() || this.number() || this.string() || this.other() this.tokens.push(tok) return tok } /** * Lookahead `n` tokens. * * @param {Number} n * @return {Object} * @api private */ parser.prototype.lookahead = function (n) { var fetch = n - this.stash.length if (fetch == 0) return this.lookahead(++n) while (fetch-- > 0) this.stash.push(this.advance()) return this.stash[--n] } /** * Lookahead a single token. * * @return {Token} * @api private */ parser.prototype.peek = function () { return this.lookahead(1) } /** * Fetch next token including those stashed by peek. * * @return {Token} * @api private */ parser.prototype.next = function () { var tok = this.stashed() || this.advance() return tok } /** * Return the next possibly stashed token. * * @return {Token} * @api private */ parser.prototype.stashed = function () { var stashed = this.stash.shift() return stashed } /** * Consume the given `len`. * * @param {Number|Array} len * @api private */ parser.prototype.skip = function (len) { this.str = this.str.substr(Array.isArray(len) ? len[0].length : len) } /** * EOS */ parser.prototype.eos = function () { if (this.str.length) return return 'eos' } /** * Space */ parser.prototype.space = function () { var captures if (captures = /^([ \t]+)/.exec(this.str)) { this.skip(captures) return this.advance() } } /** * Second */ parser.prototype.second = function () { var captures if (captures = /^s(ec|econd)?s?/.exec(this.str)) { this.skip(captures) return 'second' } } /** * Minute */ parser.prototype.minute = function () { var captures if (captures = /^m(in|inute)?s?/.exec(this.str)) { this.skip(captures) return 'minute' } } /** * Hour */ parser.prototype.hour = function () { var captures if (captures = /^h(r|our)s?/.exec(this.str)) { this.skip(captures) return 'hour' } } /** * Day */ parser.prototype.day = function () { var captures if (captures = /^d(ay)?s?/.exec(this.str)) { this.skip(captures) return 'day' } } /** * Day by name */ parser.prototype.dayByName = function () { var captures var r = new RegExp('^' + rDays.source) if (captures = r.exec(this.str)) { var day = captures[1] this.skip(captures) this.date[day](1) return captures[1] } } /** * Month by name */ parser.prototype.monthByName = function () { var captures if (captures = rMonths.exec(this.str)) { var day = captures[2] var month = captures[6] this.date.date.setMonth((months.indexOf(month))) if (day) this.date.date.setDate(parseInt(day)) this.skip(captures) return captures[0] } } parser.prototype.timeAgo = function () { var captures if (captures = rAgo.exec(this.str)) { var num = captures[1] var mod = captures[2] this.date[mod](-num) this.skip(captures) return 'timeAgo' } } /** * Week */ parser.prototype.week = function () { var captures if (captures = /^w(k|eek)s?/.exec(this.str)) { this.skip(captures) return 'week' } } /** * Month */ parser.prototype.month = function () { var captures if (captures = /^mon(th)?(es|s)?\b/.exec(this.str)) { this.skip(captures) return 'month' } } /** * Week */ parser.prototype.year = function () { var captures if (captures = /^y(r|ear)s?/.exec(this.str)) { this.skip(captures) return 'year' } } /** * Meridiem am/pm */ parser.prototype.meridiem = function () { var captures if (captures = rMeridiem.exec(this.str)) { this.skip(captures) this.time(captures[1], captures[3], captures[5], captures[6]) return 'meridiem' } } /** * Hour Minute (ex. 12:30) */ parser.prototype.hourminute = function () { var captures if (captures = rHourMinute.exec(this.str)) { this.skip(captures) this.time(captures[1], captures[3], captures[5], this._meridiem) return 'hourminute' } } /** * At Hour (ex. at 5) */ parser.prototype.athour = function () { var captures if (captures = rAtHour.exec(this.str)) { this.skip(captures) this.time(captures[1], 0, 0, this._meridiem) this._meridiem = null return 'athour' } } /** * Time set helper */ parser.prototype.time = function (h, m, s, meridiem) { var d = this.date var before = d.clone() if (meridiem) { // convert to 24 hour h = ('pm' == meridiem && 12 > h) ? +h + 12 : h; // 6pm => 18 h = ('am' == meridiem && 12 == h) ? 0 : h; // 12am => 0 } m = (!m && d.changed('minutes')) ? false : m s = (!s && d.changed('seconds')) ? false : s d.time(h, m, s) } /** * Best attempt to pick the next time this date will occur * * TODO: place at the end of the parsing */ parser.prototype.nextTime = function (before) { var d = this.date var orig = this.original if (before <= d.date || rPast.test(orig)) return this // If time is in the past, we need to guess at the next time if (rDays.test(orig)) { d.day(7) } else if ((before - d.date) / 1000 > 60) { // If it is a month in the past, don't add a day if (rMonths.test(orig)) { d.day(0) } else { d.day(1) } } return this } /** * Yesterday */ parser.prototype.yesterday = function () { var captures if (captures = /^(yes(terday)?)/.exec(this.str)) { this.skip(captures) this.date.day(-1) return 'yesterday' } } /** * Tomorrow */ parser.prototype.tomorrow = function () { var captures if (captures = /^tom(orrow)?/.exec(this.str)) { this.skip(captures) this.date.day(1) return 'tomorrow' } } /** * Noon */ parser.prototype.noon = function () { var captures if (captures = /^noon\b/.exec(this.str)) { this.skip(captures) var before = this.date.clone() this.date.date.setHours(12, 0, 0) return 'noon' } } /** * Midnight */ parser.prototype.midnight = function () { var captures if (captures = /^midnight\b/.exec(this.str)) { this.skip(captures) var before = this.date.clone() this.date.date.setHours(0, 0, 0) return 'midnight' } } /** * Night (arbitrarily set at 7pm) */ parser.prototype.night = function () { var captures if (captures = /^night\b/.exec(this.str)) { this.skip(captures) this._meridiem = 'pm' var before = this.date.clone() this.date.date.setHours(19, 0, 0) return 'night' } } /** * Evening (arbitrarily set at 5pm) */ parser.prototype.evening = function () { var captures if (captures = /^evening\b/.exec(this.str)) { this.skip(captures) this._meridiem = 'pm' var before = this.date.clone() this.date.date.setHours(17, 0, 0) return 'evening' } } /** * Afternoon (arbitrarily set at 2pm) */ parser.prototype.afternoon = function () { var captures if (captures = /^afternoon\b/.exec(this.str)) { this.skip(captures) this._meridiem = 'pm' var before = this.date.clone() if (this.date.changed('hours')) return 'afternoon' this.date.date.setHours(14, 0, 0) return 'afternoon' } } /** * Morning (arbitrarily set at 8am) */ parser.prototype.morning = function () { var captures if (captures = /^morning\b/.exec(this.str)) { this.skip(captures) this._meridiem = 'am' var before = this.date.clone() if (!this.date.changed('hours')) this.date.date.setHours(8, 0, 0) return 'morning' } } /** * Tonight */ parser.prototype.tonight = function () { var captures if (captures = /^tonight\b/.exec(this.str)) { this.skip(captures) this._meridiem = 'pm' return 'tonight' } } /** * Next time */ parser.prototype._next = function () { var captures if (captures = /^next/.exec(this.str)) { this.skip(captures) var d = new Date(this.date.date) var mod = this.peek() // If we have a defined modifier, then update if (this.date[mod]) { this.next() // slight hack to modify already modified this.date = date(d) this.date[mod](1) } else if (rDayMod.test(mod)) { this.date.day(1) } return 'next' } } /** * Last time */ parser.prototype.last = function () { var captures if (captures = /^last/.exec(this.str)) { this.skip(captures) var d = new Date(this.date.date) var mod = this.peek() // If we have a defined modifier, then update if (this.date[mod]) { this.next() // slight hack to modify already modified this.date = date(d) this.date[mod](-1) } else if (rDayMod.test(mod)) { this.date.day(-1) } return 'last' } } /** * Ago */ parser.prototype.ago = function () { var captures if (captures = /^ago\b/.exec(this.str)) { this.skip(captures) return 'ago' } } /** * Number */ parser.prototype.number = function () { var captures if (captures = /^(\d+)/.exec(this.str)) { var n = captures[1] this.skip(captures) var mod = this.peek() // If we have a defined modifier, then update if (this.date[mod]) { if ('ago' == this.peek()) n = -n this.date[mod](n) } else if (this._meridiem) { // when we don't have meridiem, possibly use context to guess this.time(n, 0, 0, this._meridiem) this._meridiem = null } else if (this.original.indexOf('at') > -1) { this.time(n, 0, 0, this._meridiem) this._meridiem = null } return 'number' } } /** * String */ parser.prototype.string = function () { var captures if (captures = /^\w+/.exec(this.str)) { this.skip(captures) return 'string' } } /** * Other */ parser.prototype.other = function () { var captures if (captures = /^./.exec(this.str)) { this.skip(captures) return 'other' } } },{"./date":2,"./norm":4,"debug":10}],6:[function(require,module,exports){ /** * Substitutes for lodash methods */ exports.difference = function (bigArr, smallArr) { var diff = [] for (var i = 0; i < bigArr.length; i++) { var ele = bigArr[i] if (smallArr.indexOf(ele) == -1) { diff.push(ele) } } return diff } exports.flatten = function (arr) { return [].concat.apply([], arr) } exports.find = function (arr, fn) { var found = null for (var i = 0; i < arr.length; i++) { if (fn(arr[i])) { found = arr[i] break } } return found } exports.findLastIndex = function (arr, fn) { var found = -1 for (var i = arr.length - 1; i >= 0; i--) { if (fn(arr[i])) { found = i break } } return found } exports.includes = function (arr, item) { var found = false for (var i = 0; i < arr.length; i++) { if (arr[i] === item) { found = true break } } return found } exports.isNaN = function (n) { return Number.isNaN(n) } exports.keys = function (obj) { return Object.keys(obj) } exports.pullAt = function (arr, i) { var res = arr.splice(i, 1) return res } exports.unique = function (arr, i) { return arr.filter(function (elem, pos) { return arr.indexOf(elem) == pos }) } },{}],7:[function(require,module,exports){ // Module to enumerate all CFG symbols for the human language for time /** * Module Dependencies */ var maps = require('./maps.json') var util = require('./util') /** * Constructors for all types of symbols */ var symbolConstructors = { op: op, c: c, r: r, n: n, t: T, dt: T, T: T, f: f, o: o, rT: rT, cT: cT, } /** * Export `symbol` */ module.exports = symbol /** * The symbol constructor, given a string, lemmatize it, then return a symbol from {∅=null,op,c,r,n,t,dt,T,f}. * i.e. str -> parseFloat(str) -> new n(str) -> return * or str -> lemma(str) -> new (symbol-value) -> return * @param {string} str the input string * @return {*} The object from the class of symbols * @example * symbol('90') * // => n { value: 10 } * symbol('hour') * // a
time difference object * // => dt { h: '1' } * symbol('tonight') * // or equivalently, takes the T string too * symbol('t:=9h,dt:12h') * // a T object containing ,
* // => T { t: t { h: '=9' }, dt: dt { h: '12' } } * symbol('unrecognized') * // an unrecognized string yields the null symbol ∅ * // => null */ function symbol (str) { var s if (str == null) { // null gets null s = null } else if (str['start'] && str['end']) { // range: with 'start' and 'end' s = new symbolConstructors['rT'](str) } else if (parseFloat(str) == str) { // 'n' s = new symbolConstructors['n'](str) } else if (str.match(util.reT)) { // if is of the T string format t:,dt: s = str.match(/\s+/g) ? null : new symbolConstructors['T'](str) } else { var lem = util.lemma(str) s = lem.name ? new symbolConstructors[lem.name](lem.value, lem.name) : null // set the canonical word from lemma if (s) { s.canon = lem.canon } // set the original token for reference } if (s) { s.token = str } return s } // console.log(symbol('10')) // console.log(symbol('hour')) // console.log(symbol('tonight')) // console.log(symbol('t:=9h,dt:12h')) // console.log(symbol('unrecognized')) // /////////////////// // the CFG symbols // // /////////////////// /** * The op for arithmetic operator. * note that since scaling(*,/) is very rare, we omit its implementation for now. */ function op (value) { this.value = value } /** * The origin operator. */ function o (value) { this.value = value } /** * The range operator. */ function r (value) { this.value = value } /** * The cron operator. */ function c (value) { this.value = value } /** * The n number. Calls parseFloat. */ function n (value) { this.value = parseFloat(value) } /** * The t for time t, i.e. a point in the timeline * units: ms, s, m, h, d, w, M, y * All values are string, to represent the "=" default in the units. so when performing numerical operation, use parseFloat. * @example * new t(undefined) * new t("") * // => t {} * new t("7h30m") * // => t { h: '7', m: '30' } * new t("7h=30m") * // => t { h: '7', m: '=30' } */ function t (value) { // guard against falsy input if (!value) { return null } // 1. see if unit is prepended with "=" for default, or set to '' // 2. then consume chunks of like "30m" while (value) { var isDefault = (value.match(/^=/) || [])[0] || '' value = value.replace(/^=/, '') // default number is "1" var number = (value.match(/^\-?\d+(\.\d+)?/) || [])[0] || '1' value = value.replace(/^\-?\d+(\.\d+)?/, '') var unit = (value.match(/^[a-zA-Z]+/) || [])[0] value = value.replace(/^[a-zA-Z]+/, '') // prepend the number (string) with isDefault, i.e. "=" or "" this[unit] = isDefault + number } } /** * The dt for time t, i.e. a displacement in the timeline * units: ms, s, m, h, d, w, M, y * All values are string, to represent the "=" default in the units. so when performing numerical operation, use parseFloat. * Same keys as to allow for component-wise operation, e.g. t + dt = { ms+(d)ms, s+(d)s, ... } */ function dt (value) { // guard against falsy input if (!value) { return null } // 1. see if unit is prepended with "=" for default, or set to '' // 2. then consume chunks of like "30m" while (value) { var isDefault = (value.match(/^=/) || [])[0] || '' value = value.replace(/^=/, '') // default number is "1" var number = (value.match(/^\-?\d+(\.\d+)?/) || [])[0] || '1' value = value.replace(/^\-?\d+(\.\d+)?/, '') var unit = (value.match(/^[a-zA-Z]+/) || [])[0] value = value.replace(/^[a-zA-Z]+/, '') // prepend the number (string) with isDefault, i.e. "=" or "" this[unit] = isDefault + number } } // console.log(new t(undefined)) // console.log(new t("")) // console.log(new t("7h30m")) // console.log(new t("=7h30m")) // console.log(new t().constructor.name) /** * The T, implementation-specific, is a linear combination of and
. * Used to capture the human Ts, e.g. noon, afternoon, dawn, evening, today, tonight, Sunday, fortnight, weekdays, weekends, christmas, spring, summer, holidays etc. * To specify T in maps.json, follow the syntax: * `:` means "set", `=` means "default", use t:,dt: for the symbol-value, e.g. "t:=7h,dt:0h" * evening ~ t:=7h,dt:12h, read as "t set to default 7h, dt set to 12h" * later ~ t:,dt:=3h, read as "t set to nothing, dt set to default 3h" * beware, "" and "0" are diferent, the former is empty, the later a numerical value. * @param {string} value from the Symbol. * @param {string} [name] from the Symbol. * @example * var T = new symbol("t:=7h,dt:0h") * // => T { t: t { h: '=7' }, dt: dt { h: '0' } } * T.t * // => t { h: '=7' } * T.dt * // => t { h: '0' } */ function T (value, name) { if (name == 't') { this.t = new t(value) this.dt = new dt() } else if (name == 'dt') { this.t = new t() this.dt = new dt(value) } else { var split = value.split(','), _t = split[0].split(':').pop(), _dt = split[1].split(':').pop() this.t = new t(_t) this.dt = new dt(_dt) } } // var T = new T("t:=7h,dt:0h") // console.log(T.t) // console.log(T.dt) /** * The product of , gives a time interval */ function rT (interval) { this.start = interval.start this.end = interval.end } /** * The f to capture frequency for . */ function f (value) { this.value = value } /** * The product of or , gives a cron time */ function cT (cron) { this.cron = cron } },{"./maps.json":3,"./util":9}],8:[function(require,module,exports){ // Module to tokenize a string into CFG symbols /** * Module Dependencies */ var util = require('./util') var symbol = require('./symbol') var maps = require('./maps.json') /** * regexes for Subnormal forms */ var re = { // 12/20 - 12/21, 2012/12 - 2013/12 MMsDDdMMsDD: /(?!\d{1,4}\/\d{1,4}\s*-\s*\d{1,4}\/\d{1,4}\/)(\d{1,4})\/(\d{1,4})\s*-\s*(\d{1,4})\/(\d{1,4})/g, // 12/22 - 23, 2012/10 - 12 MMsDDdDD: /(?!\d{1,4}\/\d{1,4}\s*-\s*\d{1,4}\/)(\d{1,4})\/(\d{1,4})\s*-\s*(\d{1,4})/g, // 12/24, 2012/12 MMsDD: /(?!\d{1,4}\/\d{1,4}\/)(\d{1,4})\/(\d{1,4})/g, // 05:30pm, 0530pm, 1730, 1730pm, 1730[re:h], remove the [re:h] hhcmm: /(\s+\d{1,2}|^\d{1,2})\:?(\d{2})\s*(\S+)*/g } /** * Export `tokenize` */ module.exports = tokenize /** * Parse and tokenize a string into array of valid CFG symbols, in these steps: * 1. parse normal forms * 2. parse subnormal forms * 3. parse english forms * @param {string} str The input string. * @return {JSON} {str, tokensIn, tokensOut, symbols} */ function tokenize (str) { // split num from alphabets str = (' ' + str) .replace(/\s+(\d+)([a-zA-Z]+)/g, ' $1 $2') .replace(/\s+([a-zA-Z]+)(\d+)/g, ' $1 $2') .replace(/\s+/g, ' ') .replace(/^\s+/, '') // 1. 2. parse normal and subnormal forms var p = parseNormal12(str), pStr = p.str, tokens = pStr.split(' '), symbols = [] // clean the non-normal tokens a bit, allow to be wrapped by words only for (var i = 0; i < tokens.length; i++) { if (!tokens[i].match(util.reT)) { tokens[i] = tokens[i].replace(/^\W+/, '').replace(/\W+$/, '') } } // 3. parse english forms for (var i = 0; i < tokens.length; i++) { var tok = tokens[i] var oneGram = tok, twoGram = tok + ' ' + (tokens[i + 1] || ''), oneSym = symbol(oneGram), twoSym = symbol(twoGram) if (twoSym && twoSym.value == oneSym.value) { // if lemmatization must happen for both, // pick the longer, skip next token // skip this once, reset skip i++ symbols.push(symbol(twoGram)) } else { symbols.push(symbol(oneGram)) } } return { str: pStr, tokensOut: p.tokensOut, tokensIn: p.tokensIn, symbols: symbols } } /** * Run 1. parseNormal then 2. parseNormal2, return the parsed string with T-format tokens. * @private * @param {string} str The input string * @return {JSON} Parsed string */ function parseNormal12 (str) { var p1 = parseNormal1(str) // find tokens that are purely normal, and reinject into string var p1TokensOut = p1.tokensOut.filter(notSubnormal) var p1Str = injectNormal(str, p1TokensOut) // now parse the subnormal var p2 = parseNormal2(p1Str, [], []) // the tokens that taken out, and their replacements, in order var pTokensOut = p1.tokensOut.concat(p2.tokensOut) var pTokensIn = p1.tokensIn.concat(p2.tokensIn) return { str: p2.str, tokensOut: pTokensOut, tokensIn: pTokensIn } } /** * 1. Parse normal forms. Try to parse and return a normal Date, parseable from new Date(str), by continuously trimming off its tail and retry until either get a valid date, or string runs out. * Doesn't parse string with length <5 * @private * @param {string} str The input string. * @return {string} A Date in stdT string, or null. */ function parseNormal1 (str) { // keep chopping off tail until either get a valid date, or string runs out // array of parsed date and the string consumed var tokensIn = [], tokensOut = [] // ensure single spacing str = str.replace(/\s+/g, ' ') // tokenize by space var strArr = str.split(/\s+/g) // init the normalDate and head string used var normalDate = null, head = '' // do while there's still string to go while (strArr.length) { head = (head + ' ' + strArr.shift()).trim() try { normalDate = util.stdT(new Date(head)) // Extend head: if parse successful, extend continuously until failure, then that's the longest parseable head string, ... var advanceHead = head + ' ' + strArr[0] while (1) { try { var advanceDate = util.stdT(new Date(advanceHead)) if (advanceDate != 'Invalid Date') { // if advanceDate is parseable, set to current, update heads var normalDate = advanceDate head = head + ' ' + strArr.shift() advanceHead = advanceHead + ' ' + strArr[0] } else { break } } catch (e) { // when fail, just break break } } // Shrink head: from the whole parseable head ..., trim front till we get while (1) { try { if (util.stdT(new Date(head.replace(/^\s*\S+\s*/, ''))) != normalDate) { // front token eaten causes change, dont update head break } else { // update head head = head.replace(/^\s*\S+\s*/, '') } } catch (e) { break } } // only consider a valid parse if the parsed str is long enough if (head.length > 6) { tokensIn.push(normalDate) // get head = only, then reset tokensOut.push(head) } head = '' } catch (e) {} } return { tokensIn: tokensIn, tokensOut: tokensOut } } /** * 2. Parse subnormal forms after parseNormal. Gradually replace tokens of the input string while parseable. * @private */ function parseNormal2 (str, tokensIn, tokensOut) { var m, res if (m = re.MMsDDdMMsDD.exec(str)) { // 12/20 - 12/21 var yMd1 = yMdParse(m[1], m[2]) var yMd2 = yMdParse(m[3], m[4]) res = ' t:' + yMd1 + ',dt: - t:' + yMd2 + ',dt: ' } else if (m = re.MMsDDdDD.exec(str)) { // 12/22 - 23 var yMd1 = yMdParse(m[1], m[2]) var yMd2 = yMdParse(m[1], m[3]) res = ' t:' + yMd1 + ',dt: - t:' + yMd2 + ',dt: ' } else if (m = re.MMsDD.exec(str)) { // if year var yMd = yMdParse(m[1], m[2]) // 12/24 res = ' t:' + yMd + ',dt: ' } else if (m = re.hhcmm.exec(str)) { // 05:30pm, 0530pm, 1730, 1730pm, 1730[re:h], remove the [re:h] res = ' t:' + m[1].trim() + 'h' + m[2] + 'm' + ',dt: ' + (m[3] || '') } else { // exit recursion if hits here return { str: str, tokensIn: tokensIn, tokensOut: tokensOut } } // recurse down till no more substitution (CFG is not cyclic, so ok) tokensOut.push(m[0]) tokensIn.push(res) str = parseNormal2(str.replace(m[0], res), tokensIn, tokensOut).str return { str: str, tokensIn: tokensIn, tokensOut: tokensOut } } // //////////////////// // Helper functions // // //////////////////// /** * Try to parse two tokens for T form into MM/dd, or MM/yyyy if either token hsa length 4. * @private * @param {string} token1 * @param {string} token2 * @return {string} in the form */ function yMdParse (token1, token2) { var part0 = [token1, token2].filter(function (token) { return token.length == 4 }) var part1 = [token1, token2].filter(function (token) { return token.length != 4 }) var y = part0[0] ? part0[0] + 'y' : '' var M = part1[0] + 'M' var d = part1[1] ? part1[1] + 'd' : '' return y + M + d } /** * Check if the dateStr is strictly normal and not subnormal. Used to extract parseNormal2 overrides. * @private * @param {string} dateStr * @return {Boolean} */ function notSubnormal (dateStr) { var subnormalStr = parseNormal2(dateStr, [], []).str // remove T and see if still has words var noT = subnormalStr.replace(/t\:\S*,dt\:\S*(\s*-\s*t\:\S*,dt\:\S*)?/, '') return /\w+/g.exec(noT) != null } /** * Given a string and array of its parsed phrases, convert them into T stdT then T format, and inject into the original string, return. * @private * @param {string} str The original string. * @param {Array} parsedArr The parsed phrases from the string. * @return {string} The string with parsed phrases replaced in T format. * * @example * injectNormal('05 October 2011 14:48 UTC 08/11 2020', [ '05 October 2011 14:48 UTC', '08/11 2020' ]) * // => 't:2011y10M05d14h48m00.000s,dt: t:2020y08M11d04h00m00.000s,dt: ' */ function injectNormal (str, parsedArr) { for (var i = 0; i < parsedArr.length; i++) { var parsed = parsedArr[i] var T = util.stdTtoT(util.stdT(new Date(parsed))) str = str.replace(parsed, T) } return str } },{"./maps.json":3,"./symbol":7,"./util":9}],9:[function(require,module,exports){ /** * Module Dependencies */ var _ = require('./subdash') var maps = require('./maps.json') /** * The T string regex, e.g. "t:=9h,dt:12h", to encode T =
. Is case sensitive. */ var reT = /t\:\S*,dt\:\S*/g /** * The ordering of time units, large to small, * 'mer' is the meridiem, 0 for am, 1 for pm * and the units used for carrying */ var timeUnitOrder = ['y', 'M', 'w', 'd', 'h', 'm', 's', 'ms'] var canonTimeUnitOrder = [] for (var i = 0; i < timeUnitOrder.length; i++) { var unit = timeUnitOrder[i] canonTimeUnitOrder.push(lemma(unit).canon) } var tOrdering = ['y', 'M', 'd', 'h', 'm', 's'] var tFactor = [365, 30, 24, 60, 60] /** * Delimiters for stdT string */ var stdTdelim = ['-', '-', ' ', ':', ':', ''] /** * Export `util` */ module.exports = { TtoStdT: TtoStdT, TtoStr: TtoStr, delimSyms: delimSyms, hasSym: hasSym, has_dt: has_dt, has_pureTimeUnit: has_pureTimeUnit, has_t: has_t, highestOverride: highestOverride, isSym: isSym, largestUnit: largestUnit, lemma: lemma, nextLargestUnit: nextLargestUnit, nowT: nowT, opType: opType, orderChunks: orderChunks, removeTnPlus: removeTnPlus, reT: reT, sName: sName, splitByArr: splitByArr, splitSyms: splitSyms, splitT: splitT, stdT: stdT, stdTdelim: stdTdelim, stdTtoT: stdTtoT, tOrdering: tOrdering, timeUnitOrder: timeUnitOrder, canonTimeUnitOrder: canonTimeUnitOrder, tokenToStr: tokenToStr, unparsedStr: unparsedStr, } /** * Convert a T string to stdT string, with default filled by nowT(). * @example * TtoStdT('t:10M05d14h48m00.000s,dt:') * // => 2016-10-05 14:48:00 */ function TtoStdT (str, offset) { if (typeof str != 'string') { str = TtoStr(str) } var nowStr = nowT(offset), nowArr = splitT(nowStr), strArr = splitT(str) var resArr = [] for (var i = 0; i < nowArr.length; i++) { var val = parseFloat(strArr[i]) if (Number.isNaN(val)) { val = parseFloat(nowArr[i]) } resArr.push(val) } var resStr = '' for (var i = 0; i < stdTdelim.length; i++) { var num = resArr[i].toString() // e.g. '5.123' tends to be '05.123', fix it var predecimal = /(\d+)(\.\d+)?/.exec(num)[1], postdecimal = /(\d+)\.?(\d+)?/.exec(num)[2] if (predecimal.length == 1) { num = '0' + num } if (postdecimal != null) { for (var j = 0; j < 3 - postdecimal.length; j++) { num = num + '0' } } resStr += (num + stdTdelim[i]) } // console.log('resStr', resStr) return resStr } // console.log(TtoStdT('t:10M05d14h48m00.010s,dt:')) /** * Convert a T symbol into its T string. */ function TtoStr (T) { var tStr = 't:', dtStr = ',dt:' for (var i = 0; i < timeUnitOrder.length; i++) { var tUnit = timeUnitOrder[i] // if unit exist, write to str if (T['t'][tUnit] != undefined) { tStr += T['t'][tUnit] + tUnit } if (T['dt'][tUnit] != undefined) { dtStr += T['dt'][tUnit] + tUnit } } return tStr + dtStr } /** * Delimit the array of timeChunk symbols by combining consecutive nulls (>3) into one, and dumping those shorter. Result is then delimited by 'trinull'. * @param {Array} syms Of parsed symbols aka time chunks. * @return {Array} symbols delimited by 'trinull' */ function delimSyms (syms) { // 1. // contract the nulls into trinulls in a single array var newSyms = [], count = 0 for (var i = 0; i < syms.length; i++) { var s = syms[i] if (s == null) { count++ } else { if (count > 2) { newSyms.push('trinull') } newSyms.push(s) count = 0 } } return newSyms } // console.log(delimSyms([1, 2, null, null, null, 3])) /** * Check if arr has symbol whose name is listen in symArr. * @param {Array} arr Array of symbols. * @param {Array} symArr Array of symbol names. * @return {Boolean} */ function hasSym (syms, symArr) { var found = false for (var i = 0; i < syms.length; i++) { if (isSym(syms[i], symArr)) { found = true break } } return found } /** * Check if T.dt is not empty */ function has_dt (T) { return _.keys(T.dt).length > 0 } /** * Check if T has only t, dt with units from timeUnitOrder */ function has_pureTimeUnit (T) { var dt = T.dt, t = T.t var pure = true for (var k in dt) { if (!_.includes(timeUnitOrder, k)) { pure = false break } } for (var k in t) { if (!_.includes(timeUnitOrder, k)) { pure = false break } } return pure } /** * Check if T.t is not empty */ function has_t (T) { return _.keys(T.t).length > 0 } /** * find the lowest overridable unit in t or dt */ function highestOverride (t) { var lowestOverable = null for (var i = 0; i < tOrdering.length; i++) { var unit = tOrdering[i] if (/^=/.exec(t[unit])) { lowestOverable = unit break } } return lowestOverable } /** * Check if arr has the symbol name of s. * @param {symbol} s symbol object * @param {Array} arr Of string symbol names * @return {Boolean} */ function isSym (s, arr) { return _.includes(arr, sName(s)) } /** * Find the largest enumerated unit in T.t, or if none, in T.dt */ function largestUnit (T) { var lu = _.find(tOrdering, function (unit) { return T.t[unit] }) if (lu == null) { lu = _.find(tOrdering, function (unit) { return T.dt[unit] }) } return lu } /** * Return the lemma symbol of a word string, i.e. the name and value of the symbol it belongs to in the CFG. Uses ./maps.json. * NLP Lemmatization refers here: htp://nlp.stanford.edu/Ir-book/html/htmledition/stemming-and-lemmatization-1.html. Inflections = all possible alternative words of a lemma. * @param {string} str To lemmatize. * @return {JSON} Lemma symbol {name, value} for CFG * @example * lemma('zero') * // => { value: '0', name: 'n' } */ function lemma (str) { // change all to lower case except for 'M' for month str = (str == 'M') ? str : str.toLowerCase() var lem = {}, name = null, value = null, canon = str var mapsKeys = _.keys(maps) for (var i = 0; i < mapsKeys.length; i++) { var sMap = maps[mapsKeys[i]], sMapKeys = _.keys(sMap) for (var j = 0; j < sMapKeys.length; j++) { var inflectionArr = sMap[sMapKeys[j]] if (_.includes(inflectionArr, str)) { // set the canonical form as the first in inflectionArr canon = inflectionArr[0] // if str is in inflections value = sMapKeys[j] break } } if (value != null) { name = mapsKeys[i] break } } // set value lem['name'] = name lem['value'] = value lem['canon'] = canon return lem } // console.log(lemma('zero')) /** * Find the next largest enumerated unit in T.t, or if none, in T.dt */ function nextLargestUnit (T) { var lu = largestUnit(T) return tOrdering[tOrdering.indexOf(lu) - 1] } /** * Convenient method to get current time in T format. * @return {string} T format string. */ function nowT (offset) { var dateStr = (offset == undefined) ? stdT(new Date()) : stdT(offset) return stdTtoT(dateStr) } /** * Determine the op type based on arguments */ function opType (L, op, R) { var LsName = sName(L) || '', RsName = sName(R) || '' var opsName = sName(op) if (opsName != 'o' && opsName != 'r' && opsName != 'c') { opsName = '' } return LsName + opsName + RsName } /** * Order time chunks by not containing T, short to long, then containing T, short to long. Used for .pop() to get the candidate timechunk for parsing. */ function orderChunks (matrix) { // 2. // ok partition first then sort var hasNoT = matrix.filter(function (row) { return !hasSym(row, ['T']) }) var hasT = matrix.filter(function (row) { return hasSym(row, ['T']) }) // matrix, sorted short to long var lengthSortedNotTMat = hasNoT.sort(function (a, b) { return a.length - b.length }) var lengthSortedTMat = hasT.sort(function (a, b) { return a.length - b.length }) // 3.1 3.2 3.3 return lengthSortedNotTMat.concat(lengthSortedTMat) } /** * !remove the defaul that is 'plus' between , for defaulting to plus. * !is a quickfix for mat */ function removeTnPlus (syms) { for (var i = 0; i < syms.length; i++) { var s = syms[i] if (isSym(s, ['op']) && s.value == 'plus' && isSym(syms[i + 1], ['n'])) { syms.splice(i, 1) } } return syms } /** * Return the name of a symbol: {op,c,r,n,T,f} * @param {Symbol} symbol A CFG symbol. * @return {string} name of the symbol. */ function sName (symbol) { return symbol ? symbol.constructor.name : null } /** * Split a string by an array of tokens. * @param {string} str The input string. * @param {Array} tokenArr Array of tokens to split the string by. * @return {Array} The split string array. */ function splitByArr (str, tokenArr) { var delim = '#{REPLACE}' // inject into tokens for (var i = 0; i < tokenArr.length; i++) { var token = tokenArr[i] str = str.replace(token, delim) } // split into arr return str.split(delim) } // console.log(splitByArr('lorem 1 ipsum 2 dolor 3', [1,2,3])) /** * Split an array of symbols by delimiter into matrix. * @param {Array} syms The input array * @param {string|symbol} delimiter To split the array by * @return {matrix} delimited arrays. */ function splitSyms (syms, delimiter) { // split the single array into matrix var matrix = [], newRow = [] for (var i = 0; i < syms.length; i++) { var s = syms[i] if (s == delimiter || sName(s) == delimiter) { // delimit and push to matrix matrix.push(newRow) newRow = [] } else if (i == syms.length - 1) { // edge case, push res newRow.push(s) matrix.push(newRow) } else { // accumulate in row newRow.push(s) } } return matrix } /** * Split a T string into array of [_y, _M, _d, _h, _m, _s] */ function splitT (str) { if (!str.match(reT)) { return null } var _y = (/(\d+(\.\d+)?)y/.exec(str) || [])[1], _M = (/(\d+(\.\d+)?)M/.exec(str) || [])[1], _w = (/(\d+(\.\d+)?)w/.exec(str) || [])[1], _d = (/(\d+(\.\d+)?)d/.exec(str) || [])[1], _h = (/(\d+(\.\d+)?)h/.exec(str) || [])[1], _m = (/(\d+(\.\d+)?)m/.exec(str) || [])[1], _s = (/(\d+(\.\d+)?)s/.exec(str) || [])[1] // The Time Object var TO = { y: _y, M: _M, w: _w, d: _d, h: _h, m: _m, s: _s } // do the carries TO = carry(TO) // compose results var res = [] for (var i = 0; i < tOrdering.length; i++) { var k = tOrdering[i] res.push(TO[k]) } return res } /** * Function to properly down- and up- carry Time Object * 1. dumpweek, 2. carryDown, 3. carryUp */ function carry (TO) { TO = dumpWeek(TO) TO = carryDown(TO) TO = carryUp(TO) return TO } /** * 1. dumpWeek */ function dumpWeek (TO) { var _w = parseFloat(TO['w'] || '0'), _d = parseFloat(TO['d'] || '0') TO['d'] = _d + (_w * 7) delete TO['w'] return TO } /** * 2. carryDown */ function carryDown (TO) { // shall reverse the ordering and factors for opp direction var ordering = tOrdering, factor = tFactor var carry = 0 for (var i = 0; i < ordering.length; i++) { // the time unit in the ordering var u = ordering[i] // skip the rest of loopbody if this unit is undefined and nothing to carry if (TO[u] == undefined && carry == 0) { continue } // carry TO[u] = parseFloat(TO[u] || '0') + carry // dont go in after the last one if (i == ordering.length - 1) { // overlong s decimal will be fixed in TtoStdT break } var decimal = parseFloat(TO[u] || '0') - parseInt(TO[u] || '0') if (decimal > 0) { // set next carry carry = decimal * factor[i] // update current u TO[u] = parseInt(TO[u]) } else { // else reset to 0 if no carry carry = 0 } } return TO } /** * 3. carryUp */ function carryUp (TO) { // shall reverse the ordering and factors for opp direction var ordering = tOrdering.slice().reverse(), factor = tFactor.slice().reverse() var carry = 0 for (var i = 0; i < ordering.length; i++) { // the time unit in the ordering var u = ordering[i] // skip the rest of loopbody if this unit is undefined and nothing to carry if (TO[u] == undefined && carry == 0) { continue } // carry TO[u] = parseFloat(TO[u] || '0') + carry // dont go in after the last one if (i == ordering.length - 1) { break } var deci = parseInt(parseFloat(TO[u] || '0') / factor[i]) if (deci > 0) { // set next carry carry = deci // update current u TO[u] = parseFloat(TO[u] || '0') % factor[i] } else { // else reset to 0 if no carry carry = 0 } } return TO } /** * Take a date or string, parse it into standard format as yyyy-MM-dd hh:mm:ss.sss */ function stdT (date) { if (typeof date == 'string') { date = new Date(date) } var _y = date.getFullYear(), _M = date.getMonth() + 1, _d = date.getDate(), _date = [_y, _M, _d].join('-') _time = /(\d\S+)/.exec(date.toTimeString())[1], format = _date + ' ' + _time return format } /** * Convert std time string to T string. * @example * stdTtoT('2011-10-05T14:48:00.000') * // => 't:2011y10M05d14h48m00.000s,dt:' */ function stdTtoT (str) { var datetime = str.split(' ') var date = datetime[0].split('-'), time = datetime[1].split(':') return 't:' + date[0] + 'y' + date[1] + 'M' + date[2] + 'd' + time[0] + 'h' + time[1] + 'm' + time[2] + 's,dt:' } // console.log(stdTtoT('2011-10-05T14:48:00.000Z')) /** * Recombine array of symbols back into str */ function tokenToStr (syms) { var tokens = [] for (var i = 0; i < syms.length; i++) { tokens.push(syms[i].token) } return tokens.join(' ') } /** * Extract unparsedTokens from str and parsed syms then join them */ function unparsedStr (str, syms) { var inputTokens = str.split(/\s+/) var tokens = [] for (var i = 0; i < syms.length; i++) { if (syms[i] == null) { tokens.push(inputTokens[i]) } } return tokens.join(' ') } },{"./maps.json":3,"./subdash":6}],10:[function(require,module,exports){ /** * This is the web browser implementation of `debug()`. * * Expose `debug()` as the module. */ exports = module.exports = require('./debug'); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; exports.load = load; exports.useColors = useColors; exports.storage = 'undefined' != typeof chrome && 'undefined' != typeof chrome.storage ? chrome.storage.local : localstorage(); /** * Colors. */ exports.colors = [ '#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC', '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF', '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC', '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF', '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033', '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366', '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933', '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC', '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF', '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33' ]; /** * Currently only WebKit-based Web Inspectors, Firefox >= v31, * and the Firebug extension (any Firefox version) are known * to support "%c" CSS customizations. * * TODO: add a `localStorage` variable to explicitly enable/disable colors */ function useColors() { // NB: In an Electron preload script, document will be defined but not fully // initialized. Since we know we're in Chrome, we'll just detect this case // explicitly if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { return true; } // Internet Explorer and Edge do not support colors. if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) { return false; } // is webkit? http://stackoverflow.com/a/16459606/376773 // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || // is firebug? http://stackoverflow.com/a/398120/376773 (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || // is firefox >= v31? // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || // double check webkit in userAgent just in case we are in a worker (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); } /** * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. */ exports.formatters.j = function(v) { try { return JSON.stringify(v); } catch (err) { return '[UnexpectedJSONParseError]: ' + err.message; } }; /** * Colorize log arguments if enabled. * * @api public */ function formatArgs(args) { var useColors = this.useColors; args[0] = (useColors ? '%c' : '') + this.namespace + (useColors ? ' %c' : ' ') + args[0] + (useColors ? '%c ' : ' ') + '+' + exports.humanize(this.diff); if (!useColors) return; var c = 'color: ' + this.color; args.splice(1, 0, c, 'color: inherit') // the final "%c" is somewhat tricky, because there could be other // arguments passed either before or after the %c, so we need to // figure out the correct index to insert the CSS into var index = 0; var lastC = 0; args[0].replace(/%[a-zA-Z%]/g, function(match) { if ('%%' === match) return; index++; if ('%c' === match) { // we only are interested in the *last* %c // (the user may have provided their own) lastC = index; } }); args.splice(lastC, 0, c); } /** * Invokes `console.log()` when available. * No-op when `console.log` is not a "function". * * @api public */ function log() { // this hackery is required for IE8/9, where // the `console.log` function doesn't have 'apply' return 'object' === typeof console && console.log && Function.prototype.apply.call(console.log, console, arguments); } /** * Save `namespaces`. * * @param {String} namespaces * @api private */ function save(namespaces) { try { if (null == namespaces) { exports.storage.removeItem('debug'); } else { exports.storage.debug = namespaces; } } catch(e) {} } /** * Load `namespaces`. * * @return {String} returns the previously persisted debug modes * @api private */ function load() { var r; try { r = exports.storage.debug; } catch(e) {} // If debug isn't set in LS, and we're in Electron, try to load $DEBUG if (!r && typeof process !== 'undefined' && 'env' in process) { r = process.env.DEBUG; } return r; } /** * Enable namespaces listed in `localStorage.debug` initially. */ exports.enable(load()); /** * Localstorage attempts to return the localstorage. * * This is necessary because safari throws * when a user disables cookies/localstorage * and you attempt to access it. * * @return {LocalStorage} * @api private */ function localstorage() { try { return window.localStorage; } catch (e) {} } },{"./debug":11}],11:[function(require,module,exports){ /** * This is the common logic for both the Node.js and web browser * implementations of `debug()`. * * Expose `debug()` as the module. */ exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; exports.humanize = require('ms'); /** * Active `debug` instances. */ exports.instances = []; /** * The currently active debug mode names, and names to skip. */ exports.names = []; exports.skips = []; /** * Map of special "%n" handling functions, for the debug "format" argument. * * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". */ exports.formatters = {}; /** * Select a color. * @param {String} namespace * @return {Number} * @api private */ function selectColor(namespace) { var hash = 0, i; for (i in namespace) { hash = ((hash << 5) - hash) + namespace.charCodeAt(i); hash |= 0; // Convert to 32bit integer } return exports.colors[Math.abs(hash) % exports.colors.length]; } /** * Create a debugger with the given `namespace`. * * @param {String} namespace * @return {Function} * @api public */ function createDebug(namespace) { var prevTime; function debug() { // disabled? if (!debug.enabled) return; var self = debug; // set `diff` timestamp var curr = +new Date(); var ms = curr - (prevTime || curr); self.diff = ms; self.prev = prevTime; self.curr = curr; prevTime = curr; // turn the `arguments` into a proper Array var args = new Array(arguments.length); for (var i = 0; i < args.length; i++) { args[i] = arguments[i]; } args[0] = exports.coerce(args[0]); if ('string' !== typeof args[0]) { // anything else let's inspect with %O args.unshift('%O'); } // apply any `formatters` transformations var index = 0; args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { // if we encounter an escaped % then don't increase the array index if (match === '%%') return match; index++; var formatter = exports.formatters[format]; if ('function' === typeof formatter) { var val = args[index]; match = formatter.call(self, val); // now we need to remove `args[index]` since it's inlined in the `format` args.splice(index, 1); index--; } return match; }); // apply env-specific formatting (colors, etc.) exports.formatArgs.call(self, args); var logFn = debug.log || exports.log || console.log.bind(console); logFn.apply(self, args); } debug.namespace = namespace; debug.enabled = exports.enabled(namespace); debug.useColors = exports.useColors(); debug.color = selectColor(namespace); debug.destroy = destroy; // env-specific initialization logic for debug instances if ('function' === typeof exports.init) { exports.init(debug); } exports.instances.push(debug); return debug; } function destroy () { var index = exports.instances.indexOf(this); if (index !== -1) { exports.instances.splice(index, 1); return true; } else { return false; } } /** * Enables a debug mode by namespaces. This can include modes * separated by a colon and wildcards. * * @param {String} namespaces * @api public */ function enable(namespaces) { exports.save(namespaces); exports.names = []; exports.skips = []; var i; var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); var len = split.length; for (i = 0; i < len; i++) { if (!split[i]) continue; // ignore empty strings namespaces = split[i].replace(/\*/g, '.*?'); if (namespaces[0] === '-') { exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); } else { exports.names.push(new RegExp('^' + namespaces + '$')); } } for (i = 0; i < exports.instances.length; i++) { var instance = exports.instances[i]; instance.enabled = exports.enabled(instance.namespace); } } /** * Disable debug output. * * @api public */ function disable() { exports.enable(''); } /** * Returns true if the given mode name is enabled, false otherwise. * * @param {String} name * @return {Boolean} * @api public */ function enabled(name) { if (name[name.length - 1] === '*') { return true; } var i, len; for (i = 0, len = exports.skips.length; i < len; i++) { if (exports.skips[i].test(name)) { return false; } } for (i = 0, len = exports.names.length; i < len; i++) { if (exports.names[i].test(name)) { return true; } } return false; } /** * Coerce `val`. * * @param {Mixed} val * @return {Mixed} * @api private */ function coerce(val) { if (val instanceof Error) return val.stack || val.message; return val; } },{"ms":12}],12:[function(require,module,exports){ /** * Helpers. */ var s = 1000; var m = s * 60; var h = m * 60; var d = h * 24; var y = d * 365.25; /** * Parse or format the given `val`. * * Options: * * - `long` verbose formatting [false] * * @param {String|Number} val * @param {Object} [options] * @throws {Error} throw an error if val is not a non-empty string or a number * @return {String|Number} * @api public */ module.exports = function(val, options) { options = options || {}; var type = typeof val; if (type === 'string' && val.length > 0) { return parse(val); } else if (type === 'number' && isNaN(val) === false) { return options.long ? fmtLong(val) : fmtShort(val); } throw new Error( 'val is not a non-empty string or a valid number. val=' + JSON.stringify(val) ); }; /** * Parse the given `str` and return milliseconds. * * @param {String} str * @return {Number} * @api private */ function parse(str) { str = String(str); if (str.length > 100) { return; } var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( str ); if (!match) { return; } var n = parseFloat(match[1]); var type = (match[2] || 'ms').toLowerCase(); switch (type) { case 'years': case 'year': case 'yrs': case 'yr': case 'y': return n * y; case 'days': case 'day': case 'd': return n * d; case 'hours': case 'hour': case 'hrs': case 'hr': case 'h': return n * h; case 'minutes': case 'minute': case 'mins': case 'min': case 'm': return n * m; case 'seconds': case 'second': case 'secs': case 'sec': case 's': return n * s; case 'milliseconds': case 'millisecond': case 'msecs': case 'msec': case 'ms': return n; default: return undefined; } } /** * Short format for `ms`. * * @param {Number} ms * @return {String} * @api private */ function fmtShort(ms) { if (ms >= d) { return Math.round(ms / d) + 'd'; } if (ms >= h) { return Math.round(ms / h) + 'h'; } if (ms >= m) { return Math.round(ms / m) + 'm'; } if (ms >= s) { return Math.round(ms / s) + 's'; } return ms + 'ms'; } /** * Long format for `ms`. * * @param {Number} ms * @return {String} * @api private */ function fmtLong(ms) { return plural(ms, d, 'day') || plural(ms, h, 'hour') || plural(ms, m, 'minute') || plural(ms, s, 'second') || ms + ' ms'; } /** * Pluralization helper. */ function plural(ms, n, name) { if (ms < n) { return; } if (ms < n * 1.5) { return Math.floor(ms / n) + ' ' + name; } return Math.ceil(ms / n) + ' ' + name + 's'; } },{}]},{},[1])(1) });