From a82ce4892ad099e261ab65b6264a2eb3073a1f2b Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Mon, 22 Feb 2021 17:39:41 -0500 Subject: [PATCH 01/29] bring-back plugin ci functions --- .github/workflows/build-and-test.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 95665b4ec..43389076f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -34,7 +34,7 @@ jobs: run: | npm ci npm i --no-save eslint ts-node typescript - # npm run plugins:ci + npm run plugins:ci - name: static checks run: | @@ -43,7 +43,7 @@ jobs: - name: build run: | npm run build - # npm run plugins:build + npm run plugins:build - name: test run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 66527c73b..b3bbd6ba3 100755 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,7 +36,7 @@ jobs: run: | npm ci npm i --no-save eslint ts-node typescript - # npm run plugins:ci + npm run plugins:ci - name: static checks run: | @@ -45,7 +45,7 @@ jobs: - name: build run: | npm run build - # npm run plugins:build + npm run plugins:build - name: test run: | From 9039167e0d1b370caf4f26fff9cf269a382327a2 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Mon, 22 Feb 2021 17:43:37 -0500 Subject: [PATCH 02/29] add italics --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef40a1638..1b10a731d 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ it is small, quick, - and often good-enough. + and often good-enough. From fc2f8a91377e13ed7317ab53dec718c3cc92f09c Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Tue, 23 Feb 2021 13:52:45 -0500 Subject: [PATCH 03/29] support for one-word durations like 20min --- plugins/dates/scratch.js | 16 +++++----- plugins/dates/src/durations/index.js | 4 ++- plugins/dates/src/durations/parse.js | 42 ++++++++++++++++++++------- plugins/dates/tests/durations.test.js | 18 ++++++++++++ 4 files changed, 62 insertions(+), 18 deletions(-) diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index aaa6257e4..6bf0437c6 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -16,15 +16,17 @@ const context = { // max_repeat: 50, } +let doc = nlp(`20m`).tag('Duration').debug() +console.log(doc.durations().get(0)) + // let doc = nlp(`any mondays`) -let doc = nlp(`any monday in June`) -let dates = doc.dates(context) //.debug() -let date = dates.get(0) -console.log(date) +// let dates = doc.dates(context) //.debug() +// let date = dates.get(0) +// console.log(date) // console.log(JSON.stringify(json.date, null, 2)) -console.log('start: ', fmt(date.start)) -console.log(' end: ', fmt(date.end)) -console.log('=-=-=-= here -=-=-=-') +// console.log('start: ', fmt(date.start)) +// console.log(' end: ', fmt(date.end)) +// console.log('=-=-=-= here -=-=-=-') // console.log(nlp('it was ten after 9').debug().times().get()) // console.log(nlp('around four oclock').times().get()) diff --git a/plugins/dates/src/durations/index.js b/plugins/dates/src/durations/index.js index ce08012c3..de6bc520e 100644 --- a/plugins/dates/src/durations/index.js +++ b/plugins/dates/src/durations/index.js @@ -70,7 +70,9 @@ const addDurations = function (Doc) { /** phrases like '2 months' */ Doc.prototype.durations = function (n) { - let m = this.match('#Value+ #Duration and? #Value+? #Duration?') + let m = this.match('#Value+ #Duration (and? #Value+ #Duration)?') + // add '20mins' + m = m.concat(this.match('(#Duration && /[0-9][a-z]+$/)')) if (typeof n === 'number') { m = m.get(n) } diff --git a/plugins/dates/src/durations/parse.js b/plugins/dates/src/durations/parse.js index c1a94d55b..39d7dcbed 100644 --- a/plugins/dates/src/durations/parse.js +++ b/plugins/dates/src/durations/parse.js @@ -15,6 +15,8 @@ const known = { } let mapping = { + m: 'minute', + h: 'hour', hr: 'hour', min: 'minute', sec: 'second', @@ -31,17 +33,37 @@ Object.keys(mapping).forEach((k) => { const parse = function (doc) { let duration = {} //parse '8 minutes' - doc.match('#Value+ #Duration').forEach((m) => { - let num = m.numbers().get(0) - let unit = m.match('#Duration').nouns().toSingular().text() - // turn 'mins' into 'minute' - if (mapping.hasOwnProperty(unit)) { - unit = mapping[unit] + let twoWord = doc.match('#Value+ #Duration') + if (twoWord.found) { + twoWord.forEach((m) => { + let num = m.numbers().get(0) + let unit = m.terms().last().nouns().toSingular().text() + // turn 'mins' into 'minute' + if (mapping.hasOwnProperty(unit)) { + unit = mapping[unit] + } + if (known.hasOwnProperty(unit) && num !== null) { + duration[unit] = num + } + }) + } else { + let oneWord = doc.match('(#Duration && /[0-9][a-z]+$/)') + if (oneWord.found) { + let str = doc.text() + let num = str.match(/([0-9]+)/) + let unit = str.match(/([a-z]+)/) + if (num && unit) { + num = num[0] || null + unit = unit[0] || null + if (mapping.hasOwnProperty(unit)) { + unit = mapping[unit] + } + if (known.hasOwnProperty(unit) && num !== null) { + duration[unit] = Number(num) + } + } } - if (known.hasOwnProperty(unit) && num) { - duration[unit] = num - } - }) + } return duration } module.exports = parse diff --git a/plugins/dates/tests/durations.test.js b/plugins/dates/tests/durations.test.js index eb3769716..7479f0c9e 100644 --- a/plugins/dates/tests/durations.test.js +++ b/plugins/dates/tests/durations.test.js @@ -9,6 +9,24 @@ test('durations json', function (t) { t.end() }) +test('one-word durations', function (t) { + let arr = [ + ['20m', { minute: 20 }], + ['20min', { minute: 20 }], + ['20mins', { minute: 20 }], + ['10mins', { minute: 10 }], + ['1min', { minute: 1 }], + ['1sec', { second: 1 }], + ['1 sec', { second: 1 }], + ] + arr.forEach((a) => { + let doc = nlp(a[0]).tag('Duration') + let found = doc.durations().get(0) + t.deepEqual(found, a[1], a[0]) + }) + t.end() +}) + test('durations normalize', function (t) { let arr = [ ['blah blah two hours and 8 mins foobar', 'blah blah 2 hours and 8 minutes foobar'], From 9fa40d84b3fe6d1635a0f907d5ee5289891e132d Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Tue, 23 Feb 2021 14:06:09 -0500 Subject: [PATCH 04/29] try removing durations from date-responses, 2 tests failing --- plugins/dates/package-lock.json | 6 +++--- plugins/dates/package.json | 2 +- plugins/dates/scratch.js | 4 ++-- plugins/dates/src/generate.js | 1 + plugins/dates/src/index.js | 9 +++++++++ plugins/dates/tests/misc.test.js | 11 +++++++++++ 6 files changed, 27 insertions(+), 6 deletions(-) diff --git a/plugins/dates/package-lock.json b/plugins/dates/package-lock.json index 6779fdbba..1339d55d4 100644 --- a/plugins/dates/package-lock.json +++ b/plugins/dates/package-lock.json @@ -826,9 +826,9 @@ } }, "rollup": { - "version": "2.39.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.39.0.tgz", - "integrity": "sha512-+WR3bttcq7zE+BntH09UxaW3bQo3vItuYeLsyk4dL2tuwbeSKJuvwiawyhEnvRdRgrII0Uzk00FpctHO/zB1kw==", + "version": "2.39.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.39.1.tgz", + "integrity": "sha512-9rfr0Z6j+vE+eayfNVFr1KZ+k+jiUl2+0e4quZafy1x6SFCjzFspfRSO2ZZQeWeX9noeDTUDgg6eCENiEPFvQg==", "dev": true, "requires": { "fsevents": "~2.3.1" diff --git a/plugins/dates/package.json b/plugins/dates/package.json index 272fa5849..a6fd4d16c 100644 --- a/plugins/dates/package.json +++ b/plugins/dates/package.json @@ -40,7 +40,7 @@ "@rollup/plugin-commonjs": "17.1.0", "@rollup/plugin-json": "4.1.0", "@rollup/plugin-node-resolve": "11.2.0", - "rollup": "2.39.0", + "rollup": "2.39.1", "rollup-plugin-babel": "4.4.0", "rollup-plugin-filesize-check": "0.0.1", "rollup-plugin-terser": "7.0.2", diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index 6bf0437c6..ab7f21eeb 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -16,8 +16,8 @@ const context = { // max_repeat: 50, } -let doc = nlp(`20m`).tag('Duration').debug() -console.log(doc.durations().get(0)) +let doc = nlp(`q4`).debug() +console.log(doc.dates().get(0)) // let doc = nlp(`any mondays`) // let dates = doc.dates(context) //.debug() diff --git a/plugins/dates/src/generate.js b/plugins/dates/src/generate.js index e248db47a..a0981fa4b 100644 --- a/plugins/dates/src/generate.js +++ b/plugins/dates/src/generate.js @@ -27,6 +27,7 @@ const generateDates = function (result, context) { } // start going! let loops = 0 + // TODO: learn how to write better software. while (list.length < max_count && s.epoch < end.epoch) { if (shouldPick(s, byDay, end)) { list.push(s.iso()) diff --git a/plugins/dates/src/index.js b/plugins/dates/src/index.js index 8f857edac..9cf2468d7 100644 --- a/plugins/dates/src/index.js +++ b/plugins/dates/src/index.js @@ -42,6 +42,15 @@ const addMethods = function (Doc, world) { context = Object.assign({}, context, opts) // let r = this.clauses() let dates = this.match('#Date+') + // ignore only-durations like '20 minutes' + dates = dates.filter((m) => { + let isDuration = m.has('^#Duration+$') || m.has('^#Value #Duration+$') + // allow 'q4', etc + if (isDuration === true && m.has('#FinancialQuarter')) { + isDuration = false + } + return isDuration === false + }) if (typeof n === 'number') { dates = dates.get(n) } diff --git a/plugins/dates/tests/misc.test.js b/plugins/dates/tests/misc.test.js index fa13e0d69..67f320cff 100644 --- a/plugins/dates/tests/misc.test.js +++ b/plugins/dates/tests/misc.test.js @@ -38,3 +38,14 @@ test('never allow end > start', (t) => { }) t.end() }) + +test('durations are not dates', function (t) { + let doc = nlp('it took 20 minutes') + t.equal(doc.dates().length, 0, 'no-dates') + t.equal(doc.durations().length, 1, 'one-duration') + + doc = nlp('it took 20mins') + t.equal(doc.dates().length, 0, 'no-dates-compact') + t.equal(doc.durations().length, 1, 'one-duration-compact') + t.end() +}) From ea34f5696f6c63375f6d52919b0d194729c4bd05 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Wed, 24 Feb 2021 12:44:24 -0500 Subject: [PATCH 05/29] start improving readme --- plugins/dates/README.md | 352 ++++++++++--------- plugins/dates/builds/compromise-dates.js | 64 +++- plugins/dates/builds/compromise-dates.js.map | 2 +- plugins/dates/builds/compromise-dates.min.js | 2 +- plugins/dates/builds/compromise-dates.mjs | 64 +++- 5 files changed, 301 insertions(+), 183 deletions(-) diff --git a/plugins/dates/README.md b/plugins/dates/README.md index 3428d8ca1..f7457ec58 100644 --- a/plugins/dates/README.md +++ b/plugins/dates/README.md @@ -1,7 +1,7 @@
-
WIP date-parsing plugin for compromise
+
date-parsing plugin for compromise
@@ -15,126 +15,188 @@
-
- npm install compromise-dates + + + + +This library is an earnest attempt to get date information out of text, in a clear way. + + + + + +
+ 1 - Regular-expressions are the wrong way to parse dates. +
+ +
+ 2 - Neural-nets are the wrong way to parse dates.
-`compromise-date` also depends on [compromise-numbers](../numbers) +
+ 3 - A startup is the wrong place to build a universal date-parser. +
+ + + + + +Parsing *dates*, *times*, and *durations* from natural language can be a solved-problem. + +A rule-based, community open-source library - *one based on simple NLP* - is the best way to build a natural language date parser - commercial, or otherwise - for the frontend, or the backend. + +The *[match-syntax](https://observablehq.com/@spencermountain/compromise-match-syntax)* is effective and easy, *javascript* is prevailing, and the more people who contribute, the better. + + +
- npm install compromise-numbers + npm install compromise-dates +
-`compromise-dates` can turn natural-language date forms like `June ninth-fourteenth` into parsed ISO dates with start+end times. + + + ```js const nlp = require('compromise') nlp.extend(require('compromise-dates')) -nlp.extend(require('compromise-numbers')) - -let doc = nlp('my birthday is June 5th 1998') -doc.dates().json() -/*[{ - text: 'June 5th 1998', - date: { start: '1998-06-05T00:00:00.000-04:00', end: null } -}]*/ + +let doc = nlp('the second monday of february') +doc.dates().get(0) +/* + {} +*/ ``` -### Things it does: - -**explicit-dates** -- `march 2nd` -- `2 march` -- `tues march 2` -- `march the second` -- `on the 2nd` -**numerical-dates** -- `1999/03/02` -- `1999-03-02` -- `03-02-1999` -- `03/02` -- `2015.08.13` -**named-dates** -- `today` -- `easter` -- `q1` -- `tomorrow` -**time:** -- `2pm` -- `2:12pm` -- `2:12` -- `02:12:00` -- `2 oclock` -- `before 1` -- `noon` -- `at night` -- `in the morning` -- `tomorrow evening` -**timezone:** -- `eastern time` -- `est` -- `peru time` -- `GMT+9` -**relative duration** -- `this march` -- `this week` -- `this sunday` -- `next april` -- `this past year` -- `second week of march` -- `last weekend of march` -- `last spring` -- `the saturday after next` -**punt** -- `two days after tomorrow` -- `in seven weeks` -- `2 weeks from now` -- `2 weeks after` -- `2 years 4 months 5 days ago` -- `a week friday` -- `a week and a half before` -- `on the 1st` -**start/end** -- `end of the week` -- `start of next year` -- `start of next year` -- `middle of q2 last year` - -#### Date-ranges -- `between [june] and [july]` -- `from [today] to [haloween]` -- `[aug 1] - [aug 31]` -- `[today] to [next friday]` -- `during june` -- `before [2019]` -- `by march` -- `after february` -- `22-23 February` - - -### Things it does awkwardly -* `middle of 2019/June` - tries to find the center -* `good friday 2025` - tries to reckon astronomically-set holidays -* historical DST changes `Oct 22 1975 in PST` (always uses this year's DST date) - -### Things it doesn't do -* things like `not this Saturday, but the Saturday after` -* repeating dates like `every sunday` - only contiguous times are supported -* `3 years ago tomorrow` -* military time formats like `2100` -* 'bare' 2-digit years like `may 97` - ('97 is supported) + + +--- + + + +### *This parser is getting really good:* + + + +#### Things it does well: + +| `explicit-dates` | *description* | `Start` | `End` | +| ------------- |:-------------:| -----:| -----:| +| *march 2nd* | |March 2, 12:00am | March 2, 11:59pm +| *2 march* | | '' | '' +| *tues march 2*| | '' | '' +| *march the second* | *natural-language number* | '' | '' +| *on the 2nd* | *implicit months* | '' | '' +| *tuesday the 2nd* | *date-reckoning* | '' | '' +|**`numeric-dates:`**| | +| *2020/03/02* |*iso formats* | '' | '' +| *2020-03-02* | | '' | '' +| *03-02-2020* |*british formats* | '' | '' +| *03/02* | | '' | '' +| *2020.08.13* | | '' | '' +|**`named-dates:`**| | +| *today* | | '' | '' +| *easter* | | '' | '' +| *q1* | | '' | '' +| *tomorrow* | | '' | '' +|**`times:`**| | +| *2pm* | | '' | '' +| *2:12pm* | | '' | '' +| *2:12* | | '' | '' +| *02:12:00* | | '' | '' +| *2 oclock* | | '' | '' +| *before 1* | | '' | '' +| *noon* | | '' | '' +| *at night* | | '' | '' +| *in the morning* | | '' | '' +| *tomorrow evening* | | '' | '' +|**`timezones:`**| | +| *eastern time* | | '' | '' +| *est* | | '' | '' +| *peru time* | | '' | '' +| *GMT+9* | | '' | '' +|**`relative durations:`**| | +| *this march* | | '' | '' +| *this week* | | '' | '' +| *this sunday* | | '' | '' +| *next april* | | '' | '' +| *this past year* | | '' | '' +| *second week of march* | | '' | '' +| *last weekend of march* | | '' | '' +| *last spring* | | '' | '' +| *the saturday after next* | | '' | '' +|**`punted dates:`**| | +| *two days after tomorrow* | | '' | '' +| *in seven weeks* | | '' | '' +| *2 weeks from now* | | '' | '' +| *2 weeks after* | | '' | '' +| *2 years 4 months 5 days ago* | | '' | '' +| *a week friday* | | '' | '' +| *a week and a half before* | | '' | '' +| *on the 1st* | | '' | '' +|**`start/end:`**| | +| *end of the week* | | '' | '' +| *start of next year* | | '' | '' +| *start of next year* | | '' | '' +| *middle of q2 last year* | | '' | '' +|**`date-ranges:`**| | +| *between [june] and [july]* | | '' | '' +| *from [today] to [haloween]* | | '' | '' +| *[aug 1] - [aug 31]* | | '' | '' +| *[today] to [next friday]* | | '' | '' +| *during june`* | | '' | '' +| *before [2019]* | | '' | '' +| *by march* | | '' | '' +| *after february* | | '' | '' +| *22-23 February* | | '' | '' + + +### Things it does awkwardly: +| | *description* | `Start` | `End` | +| ------------- |:-------------:| :-------------:| :-------------:| +| *middle of 2019/June* | tries to find the center | '' | '' | +| *good friday 2025* | tries to reckon astronomically-set holidays| '' | '' | +| *Oct 22 1975 in PST* | historical DST changes | '' | '' | + +### Things it doesn't do: +| | *description* | `Start` | `End` | +| ------------- |:-------------:| :-------------:| :-------------:| +| *middle of 2019/June* | tries to find the center | '' | '' | +| *not this Saturday, but the Saturday after* | internal logic | '' | '' | +| *3 years ago tomorrow* | folksy short-hand | '' | '' | +| *2100* | military time formats | '' | '' | +| *may 97* | 'bare' 2-digit years | '' | '' | + + + + +
+ + +
## API - **.dates()** - find dates like `June 8th` or `03/03/18` - - **.dates().json()** - overloaded output with date metadata + - **.dates().get()** - parsed dates as json + - **.dates().json()** - overloaded json output with date metadata - **.dates().format('')** - convert the dates to specific formats + - **.durations()** - find unspecified lengths of time like `two hours and 30mins` - - **.durations().json()** - overloaded output with duration metadata + - **.durations().get()** - parsed durations as json + - **.durations().json()** - overloaded json output with duration metadata - **.durations().normalize()** - turn 3mins into 3 minutes + +- **.times()** - find day-times like `three oclock` + - **.times().get()** - parsed times as json + - **.times().json()** - overloaded json output with time metadata + - **.times().normalize()** - turn 3mins into 3 minutes `.dates()` accepts an optional object, that lets you set the context for the date parsing. +### Configuration: ```js const context = { timezone: 'Canada/Eastern', //the default timezone is 'ETC/UTC' @@ -144,50 +206,9 @@ const context = { dayEndt: '5:30pm' } -nlp('in two days') - .dates(context) - .json() +nlp('in two days').dates(context).json() ``` -### Method - -ranges: - * *between {} and {}* - * *in {}* - * *before {}* - * *after {}* - -tokens: -``` - shift: '5 weeks before' to {weeks:-5} - '14 hours after' to {hours:14} - - counter: '4th week of' to {unit:week, num:4} - '10th hour in' to {unit:hour, num:10} - 'last hour in' to {unit:hour, num:'last'} - - time: 'at 5pm' to '5:00pm' - - timezone: 'EST' to 'America/New_York' - - relative: 'next wednesday' -``` - -Units: - * **Week** - 'mon-sun' - * **Month** - 'march 2020' - * **Quarter** - 'q2 2020' - * **Season** - 'summer' - * **Year** - '2019' - * **Weekend** - 'sat-sun' - * **Day** - '12:00am-11:59pm' - * **CalendarDate** - 'June 22' - * **WeekDay** - 'thursday' - * **Holiday** - 'easter' - * **Hour** - '4pm' - * **Minute** - '4:32pm' - - ## API - **[.dates()](https://observablehq.com/@spencermountain/compromise-dates)** - 'June 2021', 'next week' - **[.dates().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with date metadata @@ -203,23 +224,27 @@ Units: -## Opinions -### Start of week + + + +## *Opinions*: + +#### *Start of week:* By default, weeks start on a Monday, and *'next week'* will run from Monday morning to Sunday night. This can be configued in spacetime, but right now we are not passing-through this config. -### Implied durations +#### *Implied durations* *'after October'* returns a range starting **Nov 1st**, and ending **2-weeks** after, by default. This can be configured by setting `punt` param in the context object: ```js doc.dates({punt: { month: 1 }}) ``` -### Future bias +#### *Future bias* *'May 7th'* will prefer a May 7th in the future -### This/Next/Last +#### *This/Next/Last* *'this/next/last week'* is mostly straight-forward. But *'this monday'* and *'monday'* is more ambiguous - here, it always refers to the future. On tuesday, saying 'this monday' means 'next monday'. As I understand it, this is the most-intuitive interpretation. Saying *'this monday'* on monday, is itself. @@ -228,48 +253,61 @@ Likewise, *'this june'* in June, is itself. *'this june'* in any other month, is Future versions of this library may look at sentence-tense to help disambiguate these dates - *'i paid on monday'* vs *'i will pay on monday'*. -### Nth Week +#### *Nth Week* The first week of a month, or a year is the first week *with a thursday in it*. This is a weird, but widely-held standard. I believe it's a military formalism. It cannot be (easily) configued. This means that the start-date for *first week of January* may be a Monday in December, etc. As expected, *first monday of January* will always be in January. -### British/American ambiguity +#### *British/American ambiguity* by default, we use the same interpretation of dates as javascript does - we assume `01/02/2020` is Jan 2nd, (US-version) but allow `13/01/2020` to be Jan 13th (UK-version). This should be possible to configure in the near future. -### Seasons +#### *Seasons* By default, *'this summer'* will return **June 1 - Sept 1**, which is northern hemisphere ISO. Configuring the default hemisphere should be possible in the future. -### Day times +#### *Day times* There are some hardcoded times for *'lunch time'* and others, but mainly, a day begins at `12:00am` and ends at `11:59pm` - the last millisecond of the day. -### Invalid dates +#### *Invalid dates* compromise will tag anything that looks like a date, but not validate the dates until they are parsed. * *'january 34th 2020'* will return **Jan 31 2020**. * *'tomorrow at 2:62pm'* will return just return 'tomorrow'. * *'6th week of february* will return the 2nd week of march. * Setting an hour that's skipped, or repeated by a DST change will return the closest valid time to the DST change. -### Inclusive/exclusive ranges +#### *Inclusive/exclusive ranges* *'between january and march'* will include all of march. This is usually pretty-ambiguous normally. -### Misc +#### *Misc* * *'thursday the 16th'* - will set to the 16th, even if it's not thursday * *'in a few hours/years'* - in 2 hours/years * *'jan 5th 2008 to Jan 6th the following year'* - date-range explicit references * assume *'half past 5'* is 5pm + +
+ +
+
+
+ +
+ + ### See also * [Duckling](https://duckling.wit.ai/) - by wit.ai (facebook) * [Chronic](https://github.com/mojombo/chronic) - by Tom Preston-Werner (Ruby) * [SUTime](https://nlp.stanford.edu/software/sutime.shtml) - by Angel Chang, Christopher Manning (Java) * [Natty](http://natty.joestelmach.com/) - by Joe Stelmach (Java) * [ParseDateTime](https://pypi.org/project/parsedatetime/) by Mike Taylor (Python) +* [rrule](https://github.com/jakubroztocil/rrule) - repeating date-interval handler (js) -Work in progress. - +
+ +
Work on compromise-date is sponsored by [Simform](https://www.simform.com/) - +
+ -MIT +**MIT** licenced diff --git a/plugins/dates/builds/compromise-dates.js b/plugins/dates/builds/compromise-dates.js index ef7e89692..2fbf85741 100644 --- a/plugins/dates/builds/compromise-dates.js +++ b/plugins/dates/builds/compromise-dates.js @@ -8162,7 +8162,7 @@ } // start going! - var loops = 0; + var loops = 0; // TODO: learn how to write better software. while (list.length < max_count && s.epoch < end.epoch) { if (shouldPick(s, byDay)) { @@ -8353,6 +8353,8 @@ season: true }; var mapping$1 = { + m: 'minute', + h: 'hour', hr: 'hour', min: 'minute', sec: 'second', @@ -8369,18 +8371,44 @@ var parse$2 = function parse(doc) { var duration = {}; //parse '8 minutes' - doc.match('#Value+ #Duration').forEach(function (m) { - var num = m.numbers().get(0); - var unit = m.match('#Duration').nouns().toSingular().text(); // turn 'mins' into 'minute' + var twoWord = doc.match('#Value+ #Duration'); - if (mapping$1.hasOwnProperty(unit)) { - unit = mapping$1[unit]; - } + if (twoWord.found) { + twoWord.forEach(function (m) { + var num = m.numbers().get(0); + var unit = m.terms().last().nouns().toSingular().text(); // turn 'mins' into 'minute' + + if (mapping$1.hasOwnProperty(unit)) { + unit = mapping$1[unit]; + } + + if (known.hasOwnProperty(unit) && num !== null) { + duration[unit] = num; + } + }); + } else { + var oneWord = doc.match('(#Duration && /[0-9][a-z]+$/)'); + + if (oneWord.found) { + var str = doc.text(); + var num = str.match(/([0-9]+)/); + var unit = str.match(/([a-z]+)/); + + if (num && unit) { + num = num[0] || null; + unit = unit[0] || null; + + if (mapping$1.hasOwnProperty(unit)) { + unit = mapping$1[unit]; + } - if (known.hasOwnProperty(unit) && num) { - duration[unit] = num; + if (known.hasOwnProperty(unit) && num !== null) { + duration[unit] = Number(num); + } + } } - }); + } + return duration; }; @@ -8481,7 +8509,9 @@ /** phrases like '2 months' */ Doc.prototype.durations = function (n) { - var m = this.match('#Value+ #Duration and? #Value+? #Duration?'); + var m = this.match('#Value+ #Duration (and? #Value+ #Duration)?'); // add '20mins' + + m = m.concat(this.match('(#Duration && /[0-9][a-z]+$/)')); if (typeof n === 'number') { m = m.get(n); @@ -8635,7 +8665,17 @@ context = Object.assign({}, context, opts); // let r = this.clauses() - var dates = this.match('#Date+'); + var dates = this.match('#Date+'); // ignore only-durations like '20 minutes' + + dates = dates.filter(function (m) { + var isDuration = m.has('^#Duration+$') || m.has('^#Value #Duration+$'); // allow 'q4', etc + + if (isDuration === true && m.has('#FinancialQuarter')) { + isDuration = false; + } + + return isDuration === false; + }); if (typeof n === 'number') { dates = dates.get(n); diff --git a/plugins/dates/builds/compromise-dates.js.map b/plugins/dates/builds/compromise-dates.js.map index b5fff5a02..721c54602 100644 --- a/plugins/dates/builds/compromise-dates.js.map +++ b/plugins/dates/builds/compromise-dates.js.map @@ -1 +1 @@ -{"version":3,"file":"compromise-dates.js","sources":["../src/01-tagger/00-basic.js","../src/01-tagger/01-values.js","../src/01-tagger/02-dates.js","../src/01-tagger/03-sections.js","../src/01-tagger/04-time.js","../src/01-tagger/05-shifts.js","../src/01-tagger/06-intervals.js","../src/01-tagger/07-fixup.js","../src/01-tagger/index.js","../src/data/_tags.js","../node_modules/spacetime/builds/spacetime.js","../src/data/_timezones.js","../src/data/words/dates.js","../src/data/words/durations.js","../src/data/words/holidays.js","../src/data/words/times.js","../src/data/words/index.js","../src/parseDate/units/Unit.js","../src/parseDate/units/_day.js","../src/parseDate/units/_year.js","../src/parseDate/units/_week.js","../src/parseDate/units/_time.js","../src/parseDate/units/index.js","../src/parseDate/01-tokenize/01-shift.js","../src/parseDate/01-tokenize/02-counter.js","../src/parseDate/01-tokenize/03-time.js","../src/parseDate/01-tokenize/04-relative.js","../src/parseDate/01-tokenize/05-section.js","../src/parseDate/01-tokenize/06-timezone.js","../src/parseDate/01-tokenize/07-weekday.js","../src/parseDate/02-parse/01-today.js","../node_modules/spacetime-holiday/builds/spacetime-holiday.js","../src/parseDate/02-parse/02-holidays.js","../src/parseDate/02-parse/03-next-last.js","../src/parseDate/02-parse/04-yearly.js","../src/parseDate/02-parse/05-explicit.js","../src/parseDate/03-transform/addCounter.js","../src/parseDate/parse.js","../src/02-ranges/intervals.js","../src/02-ranges/ranges.js","../src/02-ranges/index.js","../src/normalize.js","../src/generate.js","../src/parse.js","../src/data/_abbrevs.js","../src/methods.js","../src/durations/parse.js","../src/durations/index.js","../src/times/parse.js","../src/times/index.js","../src/index.js"],"sourcesContent":["//ambiguous 'may' and 'march'\nconst preps = '(in|by|before|during|on|until|after|of|within|all)' //6\nconst thisNext = '(last|next|this|previous|current|upcoming|coming)' //2\nconst sections = '(start|end|middle|starting|ending|midpoint|beginning)' //2\nconst seasons = '(spring|summer|winter|fall|autumn)'\n\n//ensure a year is approximately typical for common years\n//please change in one thousand years\nconst tagYear = (m, reason) => {\n if (m.found !== true) {\n return\n }\n m.forEach((p) => {\n let str = p.text('reduced')\n let num = parseInt(str, 10)\n if (num && num > 1000 && num < 3000) {\n p.tag('Year', reason)\n }\n })\n}\n//same, but for less-confident values\nconst tagYearSafe = (m, reason) => {\n if (m.found !== true) {\n return\n }\n m.forEach((p) => {\n let str = p.text('reduced')\n let num = parseInt(str, 10)\n if (num && num > 1900 && num < 2030) {\n p.tag('Year', reason)\n }\n })\n}\n\nconst tagDates = function (doc) {\n // in the evening\n doc.match('in the (night|evening|morning|afternoon|day|daytime)').tag('Time', 'in-the-night')\n // 8 pm\n doc.match('(#Value|#Time) (am|pm)').tag('Time', 'value-ampm')\n // 22-aug\n // doc.match('/^[0-9]{2}-(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov)/').tag('Date', '20-jan')\n // 2012-06\n doc.match('/^[0-9]{4}-[0-9]{2}$/').tag('Date', '2012-06')\n\n // misc weekday words\n doc.match('(tue|thu)').tag('WeekDay', 'misc-weekday')\n\n //months:\n let month = doc.if('#Month')\n if (month.found === true) {\n //June 5-7th\n month.match(`#Month #Date+`).tag('Date', 'correction-numberRange')\n //5th of March\n month.match('#Value of #Month').tag('Date', 'value-of-month')\n //5 March\n month.match('#Cardinal #Month').tag('Date', 'cardinal-month')\n //march 5 to 7\n month.match('#Month #Value to #Value').tag('Date', 'value-to-value')\n //march the 12th\n month.match('#Month the #Value').tag('Date', 'month-the-value')\n }\n\n //months:\n let val = doc.if('#Value')\n if (val.found === true) {\n //june 7\n val.match('(#WeekDay|#Month) #Value').ifNo('#Money').tag('Date', 'date-value')\n\n //7 june\n val.match('#Value (#WeekDay|#Month)').ifNo('#Money').tag('Date', 'value-date')\n\n //may twenty five\n val.match('#TextValue #TextValue').if('#Date').tag('#Date', 'textvalue-date')\n\n //two thursdays back\n val.match('#Value (#WeekDay|#Duration) back').tag('#Date', '3-back')\n\n //eg 'year'\n let duration = val.if('#Duration')\n if (duration.found === true) {\n //for 4 months\n duration.match('for #Value #Duration').tag('Date', 'for-x-duration')\n //two days before\n duration.match('#Value #Duration #Conjunction').tag('Date', 'val-duration-conjunction')\n //for four days\n duration.match(`${preps}? #Value #Duration`).tag('Date', 'value-duration')\n //two years old\n duration.match('#Value #Duration old').unTag('Date', 'val-years-old')\n }\n }\n\n //seasons\n let season = doc.if(seasons)\n if (season.found === true) {\n season.match(`${preps}? ${thisNext} ${seasons}`).tag('Date', 'thisNext-season')\n season.match(`the? ${sections} of ${seasons}`).tag('Date', 'section-season')\n season.match(`${seasons} ${preps}? #Cardinal`).tag('Date', 'season-year')\n }\n\n //rest-dates\n let date = doc.if('#Date')\n if (date.found === true) {\n //june the 5th\n date.match('#Date the? #Ordinal').tag('Date', 'correction')\n //last month\n date.match(`${thisNext} #Date`).tag('Date', 'thisNext')\n //by 5 March\n date.match('due? (by|before|after|until) #Date').tag('Date', 'by')\n //next feb\n date.match('(last|next|this|previous|current|upcoming|coming|the) #Date').tag('Date', 'next-feb')\n //start of june\n date.match(`the? ${sections} of #Date`).tag('Date', 'section-of')\n //fifth week in 1998\n date.match('#Ordinal #Duration in #Date').tag('Date', 'duration-in')\n //early in june\n date.match('(early|late) (at|in)? the? #Date').tag('Time', 'early-evening')\n //tomorrow before 3\n date.match('#Date (by|before|after|at|@|about) #Cardinal').not('^#Date').tag('Time', 'date-before-Cardinal')\n //saturday am\n date.match('#Date [(am|pm)]', 0).unTag('Verb').unTag('Copula').tag('Time', 'date-am')\n //feb to june\n date.match('#Date (#Preposition|to) #Date').ifNo('#Duration').tag('Date', 'date-prep-date')\n //2nd quarter of 2019\n // date.match('#Date of #Date').tag('Date', 'date-of-date')\n }\n\n //year/cardinal tagging\n let cardinal = doc.if('#Cardinal')\n if (cardinal.found === true) {\n let v = cardinal.match(`#Date #Value [#Cardinal]`, 0)\n tagYear(v, 'date-value-year')\n //scoops up a bunch\n v = cardinal.match(`#Date [#Cardinal]`, 0)\n tagYearSafe(v, 'date-year')\n //middle of 1999\n v = cardinal.match(`${sections} of [#Cardinal]`)\n tagYearSafe(v, 'section-year')\n //feb 8 2018\n v = cardinal.match(`#Month #Value [#Cardinal]`, 0)\n tagYear(v, 'month-value-year')\n //feb 8 to 10th 2018\n v = cardinal.match(`#Month #Value to #Value [#Cardinal]`, 0)\n tagYear(v, 'month-range-year')\n //in 1998\n v = cardinal.match(`(in|of|by|during|before|starting|ending|for|year|since) [#Cardinal]`, 0)\n tagYear(v, 'in-year-1')\n //q2 2009\n v = cardinal.match('(q1|q2|q3|q4) [#Cardinal]', 0)\n tagYear(v, 'in-year-2')\n //2nd quarter 2009\n v = cardinal.match('#Ordinal quarter of? [#Cardinal]', 0)\n tagYear(v, 'in-year-3')\n //in the year 1998\n v = cardinal.match('the year [#Cardinal]', 0)\n tagYear(v, 'in-year-4')\n //it was 1998\n v = cardinal.match('it (is|was) [#Cardinal]', 0)\n tagYearSafe(v, 'in-year-5')\n // re-tag this part\n cardinal.match(`${sections} of #Year`).tag('Date')\n //between 1999 and 1998\n let m = cardinal.match('between [#Cardinal] and [#Cardinal]')\n tagYear(m.groups('0'), 'between-year-and-year-1')\n tagYear(m.groups('1'), 'between-year-and-year-2')\n }\n\n let time = doc.if('#Time')\n if (time.found === true) {\n //by 6pm\n time.match('(by|before|after|at|@|about) #Time').tag('Time', 'preposition-time')\n //7 7pm\n // time.match('#Cardinal #Time').not('#Year').tag('Time', 'value-time')\n //2pm est\n time.match('#Time [(eastern|pacific|central|mountain)]', 0).tag('Date', 'timezone')\n //6pm est\n time.match('#Time [(est|pst|gmt)]', 0).tag('Date', 'timezone abbr')\n }\n //'2020' bare input\n let m = doc.match('^/^20[012][0-9]$/$')\n tagYearSafe(m, '2020-ish')\n\n // in 20mins\n doc.match('(in|after) /^[0-9]+(min|sec|wk)s?/').tag('Date', 'shift-units')\n return doc\n}\nmodule.exports = tagDates\n","const here = 'date-values'\n//\nconst values = function (doc) {\n // a year ago\n if (!doc.has('once [a] #Duration')) {\n doc.match('[a] #Duration', 0).replaceWith('1').tag('Cardinal', here)\n }\n if (doc.has('#Value')) {\n //june 5 to 7th\n doc.match('#Month #Value to #Value of? #Year?').tag('Date', here)\n //5 to 7th june\n doc.match('#Value to #Value of? #Month #Year?').tag('Date', here)\n //third week of may\n doc.match('#Value #Duration of #Date').tag('Date', here)\n //two days after\n doc.match('#Value+ #Duration (after|before|into|later|afterwards|ago)?').tag('Date', here)\n //two days\n doc.match('#Value #Date').tag('Date', here)\n //june 5th\n doc.match('#Date #Value').tag('Date', here)\n //tuesday at 5\n doc.match('#Date #Preposition #Value').tag('Date', here)\n //tomorrow before 3\n doc.match('#Date (after|before|during|on|in) #Value').tag('Date', here)\n //a year and a half\n doc.match('#Value (year|month|week|day) and a half').tag('Date', here)\n //5 and a half years\n doc.match('#Value and a half (years|months|weeks|days)').tag('Date', here)\n //on the fifth\n doc.match('on the #Ordinal').tag('Date', here)\n }\n return doc\n}\nmodule.exports = values\n","const here = 'date-tagger'\n//\nconst dateTagger = function (doc) {\n doc.match('(spring|summer|winter|fall|autumn|springtime|wintertime|summertime)').match('#Noun').tag('Season', here)\n doc.match('(q1|q2|q3|q4)').tag('FinancialQuarter', here)\n doc.match('(this|next|last|current) quarter').tag('FinancialQuarter', here)\n doc.match('(this|next|last|current) season').tag('Season', here)\n\n if (doc.has('#Date')) {\n //friday to sunday\n doc.match('#Date #Preposition #Date').tag('Date', here)\n //once a day..\n doc.match('(once|twice) (a|an|each) #Date').tag('Date', here)\n //TODO:fixme\n doc.match('(by|until|on|in|at|during|over|every|each|due) the? #Date').tag('Date', here)\n //tuesday\n doc.match('#Date+').tag('Date', here)\n //by June\n doc.match('(by|until|on|in|at|during|over|every|each|due) the? #Date').tag('Date', here)\n //a year after..\n doc.match('a #Duration').tag('Date', here)\n //between x and y\n doc.match('(between|from) #Date').tag('Date', here)\n doc.match('(to|until|upto) #Date').tag('Date', here)\n doc.match('#Date and #Date').tag('Date', here)\n //during this june\n doc.match('(by|until|after|before|during|on|in|following|since) (next|this|last)? (#Date|#Date)').tag('Date', here)\n //day after next\n doc.match('the? #Date after next one?').tag('Date', here)\n //approximately...\n doc.match('(about|approx|approximately|around) #Date').tag('Date', here)\n }\n return doc\n}\nmodule.exports = dateTagger\n","const here = 'section-tagger'\n//\nconst sectionTagger = function (doc) {\n if (doc.has('#Date')) {\n // //next september\n doc.match('this? (last|next|past|this|previous|current|upcoming|coming|the) #Date').tag('Date', here)\n //starting this june\n doc.match('(starting|beginning|ending) #Date').tag('Date', here)\n //start of june\n doc.match('the? (start|end|middle|beginning) of (last|next|this|the) (#Date|#Date)').tag('Date', here)\n //this coming june\n doc.match('(the|this) #Date').tag('Date', here)\n //january up to june\n doc.match('#Date up to #Date').tag('Date', here)\n }\n return doc\n}\nmodule.exports = sectionTagger\n","const here = 'time-tagger'\n\n//\nconst timeTagger = function (doc) {\n // 2 oclock\n doc.match('#Cardinal oclock').tag('Time', here)\n // 13h30\n doc.match('/^[0-9]{2}h[0-9]{2}$/').tag('Time', here)\n // 03/02\n doc.match('/^[0-9]{2}/[0-9]{2}/').tag('Date', here).unTag('Value')\n // 3 in the morning\n doc.match('[#Value] (in|at) the? (morning|evening|night|nighttime)').tag('Time', here)\n if (doc.has('#Cardinal') && !doc.has('#Month')) {\n // quarter to seven (not march 5 to 7)\n doc.match('1? (half|quarter|25|15|10|5) (past|after|to) #Cardinal').tag('Time', here)\n // ten to seven\n doc.match('(5|10|15|20|five|ten|fifteen|20) (to|after|past) [#Cardinal]').tag('Time', here) //add check for 1 to 1 etc.\n }\n //timezone\n if (doc.has('#Date')) {\n // iso (2020-03-02T00:00:00.000Z)\n doc.match('/^[0-9]{4}[:-][0-9]{2}[:-][0-9]{2}T[0-9]/').tag('Time', here)\n // tuesday at 4\n doc.match('#Date [at #Cardinal]', 0).notIf('#Year').tag('Time', here)\n // half an hour\n doc.match('half an (hour|minute|second)').tag('Date', here)\n //eastern daylight time\n doc.match('#Noun (standard|daylight|central|mountain)? time').tag('Timezone', here)\n //utc+5\n doc.match('/^utc[+-][0-9]/').tag('Timezone', here)\n doc.match('/^gmt[+-][0-9]/').tag('Timezone', here)\n\n doc.match('(in|for|by|near|at) #Timezone').tag('Timezone', here)\n // 2pm eastern\n doc.match('#Time [(eastern|mountain|pacific|central)]', 0).tag('Timezone', here)\n }\n // around four thirty\n doc.match('(at|around|near) [#Cardinal (thirty|fifteen) (am|pm)?]', 0).tag('Time', here)\n return doc\n}\nmodule.exports = timeTagger\n","const here = 'shift-tagger'\n//\nconst shiftTagger = function (doc) {\n if (doc.has('#Date')) {\n //'two days before'/ 'nine weeks frow now'\n doc.match('#Cardinal #Duration (before|after|ago|from|hence|back)').tag('DateShift', here)\n // in two weeks\n doc.match('in #Cardinal #Duration').tag('DateShift', here)\n // in a few weeks\n doc.match('in a (few|couple) of? #Duration').tag('DateShift', here)\n //two weeks and three days before\n doc.match('#Cardinal #Duration and? #DateShift').tag('DateShift', here)\n doc.match('#DateShift and #Cardinal #Duration').tag('DateShift', here)\n // 'day after tomorrow'\n doc.match('[#Duration (after|before)] #Date', 0).tag('DateShift', here)\n // in half an hour\n doc.match('in half (a|an) #Duration').tag('DateShift', here)\n }\n return doc\n}\nmodule.exports = shiftTagger\n","const tagIntervals = function (doc) {\n // july 3rd and 4th\n doc.match('#Month #Ordinal and #Ordinal').tag('Date', 'ord-and-ord')\n // every other week\n doc.match('every other #Duration').tag('Date', 'every-other')\n // every weekend\n doc.match('(every|any|each|a) (day|weekday|week day|weekend|weekend day)').tag('Date', 'any-weekday')\n // any-wednesday\n doc.match('(every|any|each|a) (#WeekDay)').tag('Date', 'any-wednesday')\n // any week\n doc.match('(every|any|each|a) (#Duration)').tag('Date', 'any-week')\n}\nmodule.exports = tagIntervals\n","const here = 'fix-tagger'\n//\nconst fixUp = function (doc) {\n //fixups\n if (doc.has('#Date')) {\n //first day by monday\n let oops = doc.match('#Date+ by #Date+')\n if (oops.found && !oops.has('^due')) {\n oops.match('^#Date+').unTag('Date', 'by-monday')\n }\n\n let d = doc.match('#Date+')\n //'spa day'\n d.match('^day$').unTag('Date', 'spa-day')\n // tomorrow's meeting\n d.match('(in|of|by|for)? (#Possessive && #Date)').unTag('Date', 'tomorrows meeting')\n\n let knownDate = '(yesterday|today|tomorrow)'\n if (d.has(knownDate)) {\n //yesterday 7\n d.match(`${knownDate} [#Value]$`).unTag('Date', 'yesterday-7')\n //7 yesterday\n d.match(`^[#Value] ${knownDate}$`, 0).unTag('Date', '7 yesterday')\n //friday yesterday\n d.match(`#WeekDay+ ${knownDate}$`).unTag('Date').lastTerm().tag('Date', 'fri-yesterday')\n\n // yesterday yesterday\n // d.match(`${knownDate}+ ${knownDate}$`)\n // .unTag('Date')\n // .lastTerm()\n // .tag('Date', here)\n d.match(`(this|last|next) #Date ${knownDate}$`).unTag('Date').lastTerm().tag('Date', 'this month yesterday')\n }\n //tomorrow on 5\n d.match(`on #Cardinal$`).unTag('Date', here)\n //this tomorrow\n d.match(`this tomorrow`).terms(0).unTag('Date', 'this-tomorrow')\n //q2 2019\n d.match(`(q1|q2|q3|q4) #Year`).tag('Date', here)\n //5 tuesday\n // d.match(`^#Value #WeekDay`).terms(0).unTag('Date');\n //5 next week\n d.match(`^#Value (this|next|last)`).terms(0).unTag('Date', here)\n\n if (d.has('(last|this|next)')) {\n //this month 7\n d.match(`(last|this|next) #Duration #Value`).terms(2).unTag('Date', here)\n //7 this month\n d.match(`!#Month #Value (last|this|next) #Date`).terms(0).unTag('Date', here)\n }\n //january 5 5\n if (d.has('(#Year|#Time|#TextValue|#NumberRange)') === false) {\n d.match('(#Month|#WeekDay) #Value #Value').terms(2).unTag('Date', here)\n }\n //between june\n if (d.has('^between') && !d.has('and .')) {\n d.unTag('Date', here)\n }\n //june june\n if (d.has('#Month #Month') && !d.has('@hasHyphen') && !d.has('@hasComma')) {\n d.match('#Month').lastTerm().unTag('Date', 'month-month')\n }\n // log the hours\n if (d.has('(minutes|seconds|weeks|hours|days|months)') && !d.has('#Value #Duration')) {\n d.match('(minutes|seconds|weeks|hours|days|months)').unTag('Date', 'log-hours')\n }\n // about thanksgiving\n if (d.has('about #Holiday')) {\n d.match('about').unTag('#Date', 'about-thanksgiving')\n }\n\n // second quarter of 2020\n d.match('#Ordinal quarter of? #Year').unTag('Fraction')\n\n // a month from now\n d.match('(from|by|before) now').unTag('Time')\n // dangling date-chunks\n // if (d.has('!#Date (in|of|by|for) !#Date')) {\n // d.unTag('Date', 'dangling-date')\n // }\n // the day after next\n d.match('#Date+').match('^the').unTag('Date')\n }\n return doc\n}\nmodule.exports = fixUp\n","const methods = [\n require('./00-basic'),\n require('./01-values'),\n require('./02-dates'),\n require('./03-sections'),\n require('./04-time'),\n require('./05-shifts'),\n require('./06-intervals'),\n require('./07-fixup'),\n]\n\n// normalizations to run before tagger\nconst normalize = function (doc) {\n // turn '20mins' into '20 mins'\n doc.numbers().normalize() // this is sorta problematic\n return doc\n}\n\n// run each of the taggers\nconst tagDate = function (doc) {\n doc = normalize(doc)\n // run taggers\n methods.forEach((fn) => fn(doc))\n return doc\n}\nmodule.exports = tagDate\n","module.exports = {\n FinancialQuarter: {\n isA: 'Date',\n notA: 'Fraction',\n },\n // 'summer'\n Season: {\n isA: 'Date',\n },\n // '1982'\n Year: {\n isA: ['Date'],\n notA: 'RomanNumeral',\n },\n // 'months'\n Duration: {\n isA: ['Date', 'Noun'],\n },\n // 'easter'\n Holiday: {\n isA: ['Date', 'Noun'],\n },\n // 'PST'\n Timezone: {\n isA: ['Date', 'Noun'],\n notA: ['Adjective', 'DateShift'],\n },\n // 'two weeks before'\n DateShift: {\n isA: ['Date'],\n notA: ['TimeZone', 'Holiday'],\n },\n}\n","/* spencermountain/spacetime 6.12.5 Apache 2.0 */\n(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.spacetime = factory());\n}(this, (function () { 'use strict';\n\n function _slicedToArray(arr, i) {\n return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();\n }\n\n function _arrayWithHoles(arr) {\n if (Array.isArray(arr)) return arr;\n }\n\n function _iterableToArrayLimit(arr, i) {\n if (typeof Symbol === \"undefined\" || !(Symbol.iterator in Object(arr))) return;\n var _arr = [];\n var _n = true;\n var _d = false;\n var _e = undefined;\n\n try {\n for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {\n _arr.push(_s.value);\n\n if (i && _arr.length === i) break;\n }\n } catch (err) {\n _d = true;\n _e = err;\n } finally {\n try {\n if (!_n && _i[\"return\"] != null) _i[\"return\"]();\n } finally {\n if (_d) throw _e;\n }\n }\n\n return _arr;\n }\n\n function _unsupportedIterableToArray(o, minLen) {\n if (!o) return;\n if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n var n = Object.prototype.toString.call(o).slice(8, -1);\n if (n === \"Object\" && o.constructor) n = o.constructor.name;\n if (n === \"Map\" || n === \"Set\") return Array.from(o);\n if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n }\n\n function _arrayLikeToArray(arr, len) {\n if (len == null || len > arr.length) len = arr.length;\n\n for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n\n return arr2;\n }\n\n function _nonIterableRest() {\n throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n }\n\n var MSEC_IN_HOUR = 60 * 60 * 1000; //convert our local date syntax a javascript UTC date\n\n var toUtc = function toUtc(dstChange, offset, year) {\n var _dstChange$split = dstChange.split('/'),\n _dstChange$split2 = _slicedToArray(_dstChange$split, 2),\n month = _dstChange$split2[0],\n rest = _dstChange$split2[1];\n\n var _rest$split = rest.split(':'),\n _rest$split2 = _slicedToArray(_rest$split, 2),\n day = _rest$split2[0],\n hour = _rest$split2[1];\n\n return Date.UTC(year, month - 1, day, hour) - offset * MSEC_IN_HOUR;\n }; // compare epoch with dst change events (in utc)\n\n\n var inSummerTime = function inSummerTime(epoch, start, end, summerOffset, winterOffset) {\n var year = new Date(epoch).getUTCFullYear();\n var startUtc = toUtc(start, winterOffset, year);\n var endUtc = toUtc(end, summerOffset, year); // simple number comparison now\n\n return epoch >= startUtc && epoch < endUtc;\n };\n\n var summerTime = inSummerTime;\n\n // it reproduces some things in ./index.js, but speeds up spacetime considerably\n\n var quickOffset = function quickOffset(s) {\n var zones = s.timezones;\n var obj = zones[s.tz];\n\n if (obj === undefined) {\n console.warn(\"Warning: couldn't find timezone \" + s.tz);\n return 0;\n }\n\n if (obj.dst === undefined) {\n return obj.offset;\n } //get our two possible offsets\n\n\n var jul = obj.offset;\n var dec = obj.offset + 1; // assume it's the same for now\n\n if (obj.hem === 'n') {\n dec = jul - 1;\n }\n\n var split = obj.dst.split('->');\n var inSummer = summerTime(s.epoch, split[0], split[1], jul, dec);\n\n if (inSummer === true) {\n return jul;\n }\n\n return dec;\n };\n\n var quick = quickOffset;\n\n var _build = {\n \t\"9|s\": \"2/dili,2/jayapura\",\n \t\"9|n\": \"2/chita,2/khandyga,2/pyongyang,2/seoul,2/tokyo,11/palau\",\n \t\"9.5|s|04/04:03->10/03:02\": \"4/adelaide,4/broken_hill,4/south,4/yancowinna\",\n \t\"9.5|s\": \"4/darwin,4/north\",\n \t\"8|s|03/08:01->10/04:00\": \"12/casey\",\n \t\"8|s\": \"2/kuala_lumpur,2/makassar,2/singapore,4/perth,4/west\",\n \t\"8|n|03/25:03->09/29:23\": \"2/ulan_bator\",\n \t\"8|n\": \"2/brunei,2/choibalsan,2/chongqing,2/chungking,2/harbin,2/hong_kong,2/irkutsk,2/kuching,2/macao,2/macau,2/manila,2/shanghai,2/taipei,2/ujung_pandang,2/ulaanbaatar\",\n \t\"8.75|s\": \"4/eucla\",\n \t\"7|s\": \"12/davis,2/jakarta,9/christmas\",\n \t\"7|n\": \"2/bangkok,2/barnaul,2/ho_chi_minh,2/hovd,2/krasnoyarsk,2/novokuznetsk,2/novosibirsk,2/phnom_penh,2/pontianak,2/saigon,2/tomsk,2/vientiane\",\n \t\"6|s\": \"12/vostok\",\n \t\"6|n\": \"2/almaty,2/bishkek,2/dacca,2/dhaka,2/kashgar,2/omsk,2/qyzylorda,2/qostanay,2/thimbu,2/thimphu,2/urumqi,9/chagos\",\n \t\"6.5|n\": \"2/rangoon,2/yangon,9/cocos\",\n \t\"5|s\": \"12/mawson,9/kerguelen\",\n \t\"5|n\": \"2/aqtau,2/aqtobe,2/ashgabat,2/ashkhabad,2/atyrau,2/baku,2/dushanbe,2/karachi,2/oral,2/samarkand,2/tashkent,2/yekaterinburg,9/maldives\",\n \t\"5.75|n\": \"2/kathmandu,2/katmandu\",\n \t\"5.5|n\": \"2/calcutta,2/colombo,2/kolkata\",\n \t\"4|s\": \"9/reunion\",\n \t\"4|n\": \"2/dubai,2/muscat,2/tbilisi,2/yerevan,8/astrakhan,8/samara,8/saratov,8/ulyanovsk,8/volgograd,2/volgograd,9/mahe,9/mauritius\",\n \t\"4.5|n|03/22:00->09/21:24\": \"2/tehran\",\n \t\"4.5|n\": \"2/kabul\",\n \t\"3|s\": \"12/syowa,9/antananarivo\",\n \t\"3|n|03/28:03->10/31:04\": \"2/famagusta,2/nicosia,8/athens,8/bucharest,8/helsinki,8/kiev,8/mariehamn,8/nicosia,8/riga,8/sofia,8/tallinn,8/uzhgorod,8/vilnius,8/zaporozhye\",\n \t\"3|n|03/28:02->10/31:03\": \"8/chisinau,8/tiraspol\",\n \t\"3|n|03/28:00->10/30:24\": \"2/beirut\",\n \t\"3|n|03/27:00->10/30:01\": \"2/gaza,2/hebron\",\n \t\"3|n|03/26:02->10/31:02\": \"2/jerusalem,2/tel_aviv\",\n \t\"3|n|03/26:00->10/29:01\": \"2/amman\",\n \t\"3|n|03/26:00->10/28:24\": \"2/damascus\",\n \t\"3|n\": \"0/addis_ababa,0/asmara,0/asmera,0/dar_es_salaam,0/djibouti,0/juba,0/kampala,0/mogadishu,0/nairobi,2/aden,2/baghdad,2/bahrain,2/istanbul,2/kuwait,2/qatar,2/riyadh,8/istanbul,8/kirov,8/minsk,8/moscow,8/simferopol,9/comoro,9/mayotte\",\n \t\"2|s|03/28:02->10/31:02\": \"12/troll\",\n \t\"2|s\": \"0/gaborone,0/harare,0/johannesburg,0/lubumbashi,0/lusaka,0/maputo,0/maseru,0/mbabane\",\n \t\"2|n|03/28:02->10/31:03\": \"0/ceuta,arctic/longyearbyen,3/jan_mayen,8/amsterdam,8/andorra,8/belgrade,8/berlin,8/bratislava,8/brussels,8/budapest,8/busingen,8/copenhagen,8/gibraltar,8/ljubljana,8/luxembourg,8/madrid,8/malta,8/monaco,8/oslo,8/paris,8/podgorica,8/prague,8/rome,8/san_marino,8/sarajevo,8/skopje,8/stockholm,8/tirane,8/vaduz,8/vatican,8/vienna,8/warsaw,8/zagreb,8/zurich\",\n \t\"2|n\": \"0/blantyre,0/bujumbura,0/cairo,0/khartoum,0/kigali,0/tripoli,8/kaliningrad\",\n \t\"1|s|04/02:01->09/03:03\": \"0/windhoek\",\n \t\"1|s\": \"0/kinshasa,0/luanda\",\n \t\"1|n|04/11:03->05/16:02\": \"0/casablanca,0/el_aaiun\",\n \t\"1|n|03/28:01->10/31:02\": \"3/canary,3/faeroe,3/faroe,3/madeira,8/belfast,8/dublin,8/guernsey,8/isle_of_man,8/jersey,8/lisbon,8/london\",\n \t\"1|n\": \"0/algiers,0/bangui,0/brazzaville,0/douala,0/lagos,0/libreville,0/malabo,0/ndjamena,0/niamey,0/porto-novo,0/tunis\",\n \t\"14|n\": \"11/kiritimati\",\n \t\"13|s|04/04:04->09/26:03\": \"11/apia\",\n \t\"13|s|01/15:02->11/05:03\": \"11/tongatapu\",\n \t\"13|n\": \"11/enderbury,11/fakaofo\",\n \t\"12|s|04/04:03->09/26:02\": \"12/mcmurdo,12/south_pole,11/auckland\",\n \t\"12|s|01/17:03->11/14:02\": \"11/fiji\",\n \t\"12|n\": \"2/anadyr,2/kamchatka,2/srednekolymsk,11/funafuti,11/kwajalein,11/majuro,11/nauru,11/tarawa,11/wake,11/wallis\",\n \t\"12.75|s|04/04:03->04/04:02\": \"11/chatham\",\n \t\"11|s|04/04:03->10/03:02\": \"12/macquarie\",\n \t\"11|s\": \"11/bougainville\",\n \t\"11|n\": \"2/magadan,2/sakhalin,11/efate,11/guadalcanal,11/kosrae,11/noumea,11/pohnpei,11/ponape\",\n \t\"11.5|n|04/04:03->10/03:02\": \"11/norfolk\",\n \t\"10|s|04/04:03->10/03:02\": \"4/act,4/canberra,4/currie,4/hobart,4/melbourne,4/nsw,4/sydney,4/tasmania,4/victoria\",\n \t\"10|s\": \"12/dumontdurville,4/brisbane,4/lindeman,4/queensland\",\n \t\"10|n\": \"2/ust-nera,2/vladivostok,2/yakutsk,11/chuuk,11/guam,11/port_moresby,11/saipan,11/truk,11/yap\",\n \t\"10.5|s|04/04:01->10/03:02\": \"4/lhi,4/lord_howe\",\n \t\"0|n|03/28:00->10/31:01\": \"1/scoresbysund,3/azores\",\n \t\"0|n\": \"0/abidjan,0/accra,0/bamako,0/banjul,0/bissau,0/conakry,0/dakar,0/freetown,0/lome,0/monrovia,0/nouakchott,0/ouagadougou,0/sao_tome,0/timbuktu,1/danmarkshavn,3/reykjavik,3/st_helena,13/gmt,13/gmt+0,13/gmt-0,13/gmt0,13/greenwich,13/utc,13/universal,13/zulu\",\n \t\"-9|n|03/14:02->11/07:02\": \"1/adak,1/atka\",\n \t\"-9|n\": \"11/gambier\",\n \t\"-9.5|n\": \"11/marquesas\",\n \t\"-8|n|03/14:02->11/07:02\": \"1/anchorage,1/juneau,1/metlakatla,1/nome,1/sitka,1/yakutat\",\n \t\"-8|n\": \"11/pitcairn\",\n \t\"-7|n|03/14:02->11/07:02\": \"1/ensenada,1/los_angeles,1/santa_isabel,1/tijuana,1/vancouver,6/pacific,10/bajanorte\",\n \t\"-7|n|03/08:02->11/01:01\": \"1/dawson,1/whitehorse,6/yukon\",\n \t\"-7|n\": \"1/creston,1/dawson_creek,1/fort_nelson,1/hermosillo,1/phoenix\",\n \t\"-6|s|04/03:22->09/04:22\": \"7/easterisland,11/easter\",\n \t\"-6|n|04/04:02->10/31:02\": \"1/chihuahua,1/mazatlan,10/bajasur\",\n \t\"-6|n|03/14:02->11/07:02\": \"1/boise,1/cambridge_bay,1/denver,1/edmonton,1/inuvik,1/ojinaga,1/shiprock,1/yellowknife,6/mountain\",\n \t\"-6|n\": \"1/belize,1/costa_rica,1/el_salvador,1/guatemala,1/managua,1/regina,1/swift_current,1/tegucigalpa,6/east-saskatchewan,6/saskatchewan,11/galapagos\",\n \t\"-5|s\": \"1/lima,1/rio_branco,5/acre\",\n \t\"-5|n|04/04:02->10/31:02\": \"1/bahia_banderas,1/merida,1/mexico_city,1/monterrey,10/general\",\n \t\"-5|n|03/14:02->11/07:02\": \"1/chicago,1/knox_in,1/matamoros,1/menominee,1/rainy_river,1/rankin_inlet,1/resolute,1/winnipeg,6/central\",\n \t\"-5|n|03/12:03->11/05:01\": \"1/north_dakota\",\n \t\"-5|n\": \"1/atikokan,1/bogota,1/cancun,1/cayman,1/coral_harbour,1/eirunepe,1/guayaquil,1/jamaica,1/panama,1/porto_acre\",\n \t\"-4|s|05/13:23->08/13:01\": \"12/palmer\",\n \t\"-4|s|04/03:24->09/05:00\": \"1/santiago,7/continental\",\n \t\"-4|s|03/27:24->10/03:00\": \"1/asuncion\",\n \t\"-4|s|02/16:24->11/03:00\": \"1/campo_grande,1/cuiaba\",\n \t\"-4|s\": \"1/la_paz,1/manaus,5/west\",\n \t\"-4|n|03/14:02->11/07:02\": \"1/detroit,1/fort_wayne,1/grand_turk,1/indianapolis,1/iqaluit,1/louisville,1/montreal,1/nassau,1/new_york,1/nipigon,1/pangnirtung,1/port-au-prince,1/thunder_bay,1/toronto,6/eastern\",\n \t\"-4|n|03/14:00->11/07:01\": \"1/havana\",\n \t\"-4|n|03/12:03->11/05:01\": \"1/indiana,1/kentucky\",\n \t\"-4|n\": \"1/anguilla,1/antigua,1/aruba,1/barbados,1/blanc-sablon,1/boa_vista,1/caracas,1/curacao,1/dominica,1/grenada,1/guadeloupe,1/guyana,1/kralendijk,1/lower_princes,1/marigot,1/martinique,1/montserrat,1/port_of_spain,1/porto_velho,1/puerto_rico,1/santo_domingo,1/st_barthelemy,1/st_kitts,1/st_lucia,1/st_thomas,1/st_vincent,1/tortola,1/virgin\",\n \t\"-3|s\": \"1/argentina,1/buenos_aires,1/cordoba,1/fortaleza,1/montevideo,1/punta_arenas,1/sao_paulo,12/rothera,3/stanley,5/east\",\n \t\"-3|n|03/27:22->10/30:23\": \"1/nuuk\",\n \t\"-3|n|03/14:02->11/07:02\": \"1/glace_bay,1/goose_bay,1/halifax,1/moncton,1/thule,3/bermuda,6/atlantic\",\n \t\"-3|n\": \"1/araguaina,1/bahia,1/belem,1/catamarca,1/cayenne,1/jujuy,1/maceio,1/mendoza,1/paramaribo,1/recife,1/rosario,1/santarem\",\n \t\"-2|s\": \"5/denoronha\",\n \t\"-2|n|03/27:22->10/30:23\": \"1/godthab\",\n \t\"-2|n|03/14:02->11/07:02\": \"1/miquelon\",\n \t\"-2|n\": \"1/noronha,3/south_georgia\",\n \t\"-2.5|n|03/14:02->11/07:02\": \"1/st_johns,6/newfoundland\",\n \t\"-1|n\": \"3/cape_verde\",\n \t\"-11|n\": \"11/midway,11/niue,11/pago_pago,11/samoa\",\n \t\"-10|n\": \"11/honolulu,11/johnston,11/rarotonga,11/tahiti\"\n };\n\n var _build$1 = /*#__PURE__*/Object.freeze({\n __proto__: null,\n 'default': _build\n });\n\n //prefixes for iana names..\n var _prefixes = ['africa', 'america', 'asia', 'atlantic', 'australia', 'brazil', 'canada', 'chile', 'europe', 'indian', 'mexico', 'pacific', 'antarctica', 'etc'];\n\n function createCommonjsModule(fn, module) {\n \treturn module = { exports: {} }, fn(module, module.exports), module.exports;\n }\n\n function getCjsExportFromNamespace (n) {\n \treturn n && n['default'] || n;\n }\n\n var data = getCjsExportFromNamespace(_build$1);\n\n var all = {};\n Object.keys(data).forEach(function (k) {\n var split = k.split('|');\n var obj = {\n offset: Number(split[0]),\n hem: split[1]\n };\n\n if (split[2]) {\n obj.dst = split[2];\n }\n\n var names = data[k].split(',');\n names.forEach(function (str) {\n str = str.replace(/(^[0-9]+)\\//, function (before, num) {\n num = Number(num);\n return _prefixes[num] + '/';\n });\n all[str] = obj;\n });\n });\n all['utc'] = {\n offset: 0,\n hem: 'n' //default to northern hemisphere - (sorry!)\n\n }; //add etc/gmt+n\n\n for (var i = -14; i <= 14; i += 0.5) {\n var num = i;\n\n if (num > 0) {\n num = '+' + num;\n }\n\n var name = 'etc/gmt' + num;\n all[name] = {\n offset: i * -1,\n //they're negative!\n hem: 'n' //(sorry)\n\n };\n name = 'utc/gmt' + num; //this one too, why not.\n\n all[name] = {\n offset: i * -1,\n hem: 'n'\n };\n }\n\n var unpack = all;\n\n //find the implicit iana code for this machine.\n //safely query the Intl object\n //based on - https://bitbucket.org/pellepim/jstimezonedetect/src\n var fallbackTZ = 'utc'; //\n //this Intl object is not supported often, yet\n\n var safeIntl = function safeIntl() {\n if (typeof Intl === 'undefined' || typeof Intl.DateTimeFormat === 'undefined') {\n return null;\n }\n\n var format = Intl.DateTimeFormat();\n\n if (typeof format === 'undefined' || typeof format.resolvedOptions === 'undefined') {\n return null;\n }\n\n var timezone = format.resolvedOptions().timeZone;\n\n if (!timezone) {\n return null;\n }\n\n return timezone.toLowerCase();\n };\n\n var guessTz = function guessTz() {\n var timezone = safeIntl();\n\n if (timezone === null) {\n return fallbackTZ;\n }\n\n return timezone;\n }; //do it once per computer\n\n\n var guessTz_1 = guessTz;\n\n var isOffset = /(\\-?[0-9]+)h(rs)?/i;\n var isNumber = /(\\-?[0-9]+)/;\n var utcOffset = /utc([\\-+]?[0-9]+)/i;\n var gmtOffset = /gmt([\\-+]?[0-9]+)/i;\n\n var toIana = function toIana(num) {\n num = Number(num);\n\n if (num >= -13 && num <= 13) {\n num = num * -1; //it's opposite!\n\n num = (num > 0 ? '+' : '') + num; //add plus sign\n\n return 'etc/gmt' + num;\n }\n\n return null;\n };\n\n var parseOffset = function parseOffset(tz) {\n // '+5hrs'\n var m = tz.match(isOffset);\n\n if (m !== null) {\n return toIana(m[1]);\n } // 'utc+5'\n\n\n m = tz.match(utcOffset);\n\n if (m !== null) {\n return toIana(m[1]);\n } // 'GMT-5' (not opposite)\n\n\n m = tz.match(gmtOffset);\n\n if (m !== null) {\n var num = Number(m[1]) * -1;\n return toIana(num);\n } // '+5'\n\n\n m = tz.match(isNumber);\n\n if (m !== null) {\n return toIana(m[1]);\n }\n\n return null;\n };\n\n var parseOffset_1 = parseOffset;\n\n var local = guessTz_1(); //add all the city names by themselves\n\n var cities = Object.keys(unpack).reduce(function (h, k) {\n var city = k.split('/')[1] || '';\n city = city.replace(/_/g, ' ');\n h[city] = k;\n return h;\n }, {}); //try to match these against iana form\n\n var normalize = function normalize(tz) {\n tz = tz.replace(/ time/g, '');\n tz = tz.replace(/ (standard|daylight|summer)/g, '');\n tz = tz.replace(/\\b(east|west|north|south)ern/g, '$1');\n tz = tz.replace(/\\b(africa|america|australia)n/g, '$1');\n tz = tz.replace(/\\beuropean/g, 'europe');\n tz = tz.replace(/\\islands/g, 'island');\n return tz;\n }; // try our best to reconcile the timzone to this given string\n\n\n var lookupTz = function lookupTz(str, zones) {\n if (!str) {\n return local;\n }\n\n if (typeof str !== 'string') {\n console.error(\"Timezone must be a string - recieved: '\", str, \"'\\n\");\n }\n\n var tz = str.trim();\n var split = str.split('/'); //support long timezones like 'America/Argentina/Rio_Gallegos'\n\n if (split.length > 2 && zones.hasOwnProperty(tz) === false) {\n tz = split[0] + '/' + split[1];\n }\n\n tz = tz.toLowerCase();\n\n if (zones.hasOwnProperty(tz) === true) {\n return tz;\n } //lookup more loosely..\n\n\n tz = normalize(tz);\n\n if (zones.hasOwnProperty(tz) === true) {\n return tz;\n } //try city-names\n\n\n if (cities.hasOwnProperty(tz) === true) {\n return cities[tz];\n } // //try to parse '-5h'\n\n\n if (/[0-9]/.test(tz) === true) {\n var id = parseOffset_1(tz);\n\n if (id) {\n return id;\n }\n }\n\n throw new Error(\"Spacetime: Cannot find timezone named: '\" + str + \"'. Please enter an IANA timezone id.\");\n };\n\n var find = lookupTz;\n\n var o = {\n millisecond: 1\n };\n o.second = 1000;\n o.minute = 60000;\n o.hour = 3.6e6; // dst is supported post-hoc\n\n o.day = 8.64e7; //\n\n o.date = o.day;\n o.month = 8.64e7 * 29.5; //(average)\n\n o.week = 6.048e8;\n o.year = 3.154e10; // leap-years are supported post-hoc\n //add plurals\n\n Object.keys(o).forEach(function (k) {\n o[k + 's'] = o[k];\n });\n var milliseconds = o;\n\n var walk = function walk(s, n, fn, unit, previous) {\n var current = s.d[fn]();\n\n if (current === n) {\n return; //already there\n }\n\n var startUnit = previous === null ? null : s.d[previous]();\n var original = s.epoch; //try to get it as close as we can\n\n var diff = n - current;\n s.epoch += milliseconds[unit] * diff; //DST edge-case: if we are going many days, be a little conservative\n // console.log(unit, diff)\n\n if (unit === 'day') {\n // s.epoch -= ms.minute\n //but don't push it over a month\n if (Math.abs(diff) > 28 && n < 28) {\n s.epoch += milliseconds.hour;\n }\n } // 1st time: oops, did we change previous unit? revert it.\n\n\n if (previous !== null && startUnit !== s.d[previous]()) {\n // console.warn('spacetime warning: missed setting ' + unit)\n s.epoch = original; // s.epoch += ms[unit] * diff * 0.89 // maybe try and make it close...?\n } //repair it if we've gone too far or something\n //(go by half-steps, just in case)\n\n\n var halfStep = milliseconds[unit] / 2;\n\n while (s.d[fn]() < n) {\n s.epoch += halfStep;\n }\n\n while (s.d[fn]() > n) {\n s.epoch -= halfStep;\n } // 2nd time: did we change previous unit? revert it.\n\n\n if (previous !== null && startUnit !== s.d[previous]()) {\n // console.warn('spacetime warning: missed setting ' + unit)\n s.epoch = original;\n }\n }; //find the desired date by a increment/check while loop\n\n\n var units = {\n year: {\n valid: function valid(n) {\n return n > -4000 && n < 4000;\n },\n walkTo: function walkTo(s, n) {\n return walk(s, n, 'getFullYear', 'year', null);\n }\n },\n month: {\n valid: function valid(n) {\n return n >= 0 && n <= 11;\n },\n walkTo: function walkTo(s, n) {\n var d = s.d;\n var current = d.getMonth();\n var original = s.epoch;\n var startUnit = d.getFullYear();\n\n if (current === n) {\n return;\n } //try to get it as close as we can..\n\n\n var diff = n - current;\n s.epoch += milliseconds.day * (diff * 28); //special case\n //oops, did we change the year? revert it.\n\n if (startUnit !== s.d.getFullYear()) {\n s.epoch = original;\n } //increment by day\n\n\n while (s.d.getMonth() < n) {\n s.epoch += milliseconds.day;\n }\n\n while (s.d.getMonth() > n) {\n s.epoch -= milliseconds.day;\n }\n }\n },\n date: {\n valid: function valid(n) {\n return n > 0 && n <= 31;\n },\n walkTo: function walkTo(s, n) {\n return walk(s, n, 'getDate', 'day', 'getMonth');\n }\n },\n hour: {\n valid: function valid(n) {\n return n >= 0 && n < 24;\n },\n walkTo: function walkTo(s, n) {\n return walk(s, n, 'getHours', 'hour', 'getDate');\n }\n },\n minute: {\n valid: function valid(n) {\n return n >= 0 && n < 60;\n },\n walkTo: function walkTo(s, n) {\n return walk(s, n, 'getMinutes', 'minute', 'getHours');\n }\n },\n second: {\n valid: function valid(n) {\n return n >= 0 && n < 60;\n },\n walkTo: function walkTo(s, n) {\n //do this one directly\n s.epoch = s.seconds(n).epoch;\n }\n },\n millisecond: {\n valid: function valid(n) {\n return n >= 0 && n < 1000;\n },\n walkTo: function walkTo(s, n) {\n //do this one directly\n s.epoch = s.milliseconds(n).epoch;\n }\n }\n };\n\n var walkTo = function walkTo(s, wants) {\n var keys = Object.keys(units);\n var old = s.clone();\n\n for (var i = 0; i < keys.length; i++) {\n var k = keys[i];\n var n = wants[k];\n\n if (n === undefined) {\n n = old[k]();\n }\n\n if (typeof n === 'string') {\n n = parseInt(n, 10);\n } //make-sure it's valid\n\n\n if (!units[k].valid(n)) {\n s.epoch = null;\n\n if (s.silent === false) {\n console.warn('invalid ' + k + ': ' + n);\n }\n\n return;\n }\n\n units[k].walkTo(s, n);\n }\n\n return;\n };\n\n var walk_1 = walkTo;\n\n var shortMonths = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sept', 'oct', 'nov', 'dec'];\n var longMonths = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];\n\n function buildMapping() {\n var obj = {\n sep: 8 //support this format\n\n };\n\n for (var i = 0; i < shortMonths.length; i++) {\n obj[shortMonths[i]] = i;\n }\n\n for (var _i = 0; _i < longMonths.length; _i++) {\n obj[longMonths[_i]] = _i;\n }\n\n return obj;\n }\n\n var months = {\n \"short\": function short() {\n return shortMonths;\n },\n \"long\": function long() {\n return longMonths;\n },\n mapping: function mapping() {\n return buildMapping();\n },\n set: function set(i18n) {\n shortMonths = i18n[\"short\"] || shortMonths;\n longMonths = i18n[\"long\"] || longMonths;\n }\n };\n\n //pull-apart ISO offsets, like \"+0100\"\n var parseOffset$1 = function parseOffset(s, offset) {\n if (!offset) {\n return s;\n } //this is a fancy-move\n\n\n if (offset === 'Z' || offset === 'z') {\n offset = '+0000';\n } // according to ISO8601, tz could be hh:mm, hhmm or hh\n // so need few more steps before the calculation.\n\n\n var num = 0; // for (+-)hh:mm\n\n if (/^[\\+-]?[0-9]{2}:[0-9]{2}$/.test(offset)) {\n //support \"+01:00\"\n if (/:00/.test(offset) === true) {\n offset = offset.replace(/:00/, '');\n } //support \"+01:30\"\n\n\n if (/:30/.test(offset) === true) {\n offset = offset.replace(/:30/, '.5');\n }\n } // for (+-)hhmm\n\n\n if (/^[\\+-]?[0-9]{4}$/.test(offset)) {\n offset = offset.replace(/30$/, '.5');\n }\n\n num = parseFloat(offset); //divide by 100 or 10 - , \"+0100\", \"+01\"\n\n if (Math.abs(num) > 100) {\n num = num / 100;\n } //okay, try to match it to a utc timezone\n //remember - this is opposite! a -5 offset maps to Etc/GMT+5 ¯\\_(:/)_/¯\n //https://askubuntu.com/questions/519550/why-is-the-8-timezone-called-gmt-8-in-the-filesystem\n\n\n num *= -1;\n\n if (num >= 0) {\n num = '+' + num;\n }\n\n var tz = 'etc/gmt' + num;\n var zones = s.timezones;\n\n if (zones[tz]) {\n // log a warning if we're over-writing a given timezone?\n // console.log('changing timezone to: ' + tz)\n s.tz = tz;\n }\n\n return s;\n };\n\n var parseOffset_1$1 = parseOffset$1;\n\n var parseTime = function parseTime(s) {\n var str = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n str = str.replace(/^\\s+/, '').toLowerCase(); //trim\n //formal time formats - 04:30.23\n\n var arr = str.match(/([0-9]{1,2}):([0-9]{1,2}):?([0-9]{1,2})?[:\\.]?([0-9]{1,4})?/);\n\n if (arr !== null) {\n //validate it a little\n var h = Number(arr[1]);\n\n if (h < 0 || h > 24) {\n return s.startOf('day');\n }\n\n var m = Number(arr[2]); //don't accept '5:3pm'\n\n if (arr[2].length < 2 || m < 0 || m > 59) {\n return s.startOf('day');\n }\n\n if (arr[4] > 999) {\n // fix overflow issue with milliseconds, if input is longer than standard (e.g. 2017-08-06T09:00:00.123456Z)\n arr[4] = parseInt(\"\".concat(arr[4]).substring(0, 3), 10);\n }\n\n s = s.hour(h);\n s = s.minute(m);\n s = s.seconds(arr[3] || 0);\n s = s.millisecond(arr[4] || 0); //parse-out am/pm\n\n var ampm = str.match(/[\\b0-9](am|pm)\\b/);\n\n if (ampm !== null && ampm[1]) {\n s = s.ampm(ampm[1]);\n }\n\n return s;\n } //try an informal form - 5pm (no minutes)\n\n\n arr = str.match(/([0-9]+) ?(am|pm)/);\n\n if (arr !== null && arr[1]) {\n var _h = Number(arr[1]); //validate it a little..\n\n\n if (_h > 12 || _h < 1) {\n return s.startOf('day');\n }\n\n s = s.hour(arr[1] || 0);\n s = s.ampm(arr[2]);\n s = s.startOf('hour');\n return s;\n } //no time info found, use start-of-day\n\n\n s = s.startOf('day');\n return s;\n };\n\n var parseTime_1 = parseTime;\n\n var monthLengths = [31, // January - 31 days\n 28, // February - 28 days in a common year and 29 days in leap years\n 31, // March - 31 days\n 30, // April - 30 days\n 31, // May - 31 days\n 30, // June - 30 days\n 31, // July - 31 days\n 31, // August - 31 days\n 30, // September - 30 days\n 31, // October - 31 days\n 30, // November - 30 days\n 31 // December - 31 days\n ];\n var monthLengths_1 = monthLengths; // 28 - feb\n\n var fns = createCommonjsModule(function (module, exports) {\n //git:blame @JuliasCaesar https://www.timeanddate.com/date/leapyear.html\n exports.isLeapYear = function (year) {\n return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;\n }; // unsurprisingly-nasty `typeof date` call\n\n\n exports.isDate = function (d) {\n return Object.prototype.toString.call(d) === '[object Date]' && !isNaN(d.valueOf());\n };\n\n exports.isArray = function (input) {\n return Object.prototype.toString.call(input) === '[object Array]';\n };\n\n exports.isObject = function (input) {\n return Object.prototype.toString.call(input) === '[object Object]';\n };\n\n exports.isBoolean = function (input) {\n return Object.prototype.toString.call(input) === '[object Boolean]';\n };\n\n exports.zeroPad = function (str) {\n var len = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2;\n var pad = '0';\n str = str + '';\n return str.length >= len ? str : new Array(len - str.length + 1).join(pad) + str;\n };\n\n exports.titleCase = function (str) {\n if (!str) {\n return '';\n }\n\n return str[0].toUpperCase() + str.substr(1);\n };\n\n exports.ordinal = function (i) {\n var j = i % 10;\n var k = i % 100;\n\n if (j === 1 && k !== 11) {\n return i + 'st';\n }\n\n if (j === 2 && k !== 12) {\n return i + 'nd';\n }\n\n if (j === 3 && k !== 13) {\n return i + 'rd';\n }\n\n return i + 'th';\n }; //strip 'st' off '1st'..\n\n\n exports.toCardinal = function (str) {\n str = String(str);\n str = str.replace(/([0-9])(st|nd|rd|th)$/i, '$1');\n return parseInt(str, 10);\n }; //used mostly for cleanup of unit names, like 'months'\n\n\n exports.normalize = function () {\n var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n str = str.toLowerCase().trim();\n str = str.replace(/ies$/, 'y'); //'centuries'\n\n str = str.replace(/s$/, '');\n str = str.replace(/-/g, '');\n\n if (str === 'day' || str === 'days') {\n return 'date';\n }\n\n if (str === 'min' || str === 'mins') {\n return 'minute';\n }\n\n return str;\n };\n\n exports.getEpoch = function (tmp) {\n //support epoch\n if (typeof tmp === 'number') {\n return tmp;\n } //suport date objects\n\n\n if (exports.isDate(tmp)) {\n return tmp.getTime();\n }\n\n if (tmp.epoch) {\n return tmp.epoch;\n }\n\n return null;\n }; //make sure this input is a spacetime obj\n\n\n exports.beADate = function (d, s) {\n if (exports.isObject(d) === false) {\n return s.clone().set(d);\n }\n\n return d;\n };\n\n exports.formatTimezone = function (offset) {\n var delimiter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n var sign = offset > 0 ? '+' : '-';\n var absOffset = Math.abs(offset);\n var hours = exports.zeroPad(parseInt('' + absOffset, 10));\n var minutes = exports.zeroPad(absOffset % 1 * 60);\n return \"\".concat(sign).concat(hours).concat(delimiter).concat(minutes);\n };\n });\n fns.isLeapYear;\n fns.isDate;\n fns.isArray;\n fns.isObject;\n fns.isBoolean;\n fns.zeroPad;\n fns.titleCase;\n fns.ordinal;\n fns.toCardinal;\n fns.normalize;\n fns.getEpoch;\n fns.beADate;\n fns.formatTimezone;\n\n var isLeapYear = fns.isLeapYear; //given a month, return whether day number exists in it\n\n var hasDate = function hasDate(obj) {\n //invalid values\n if (monthLengths_1.hasOwnProperty(obj.month) !== true) {\n return false;\n } //support leap-year in february\n\n\n if (obj.month === 1) {\n if (isLeapYear(obj.year) && obj.date <= 29) {\n return true;\n } else {\n return obj.date <= 28;\n }\n } //is this date too-big for this month?\n\n\n var max = monthLengths_1[obj.month] || 0;\n\n if (obj.date <= max) {\n return true;\n }\n\n return false;\n };\n\n var hasDate_1 = hasDate;\n\n var months$1 = months.mapping();\n\n var parseYear = function parseYear() {\n var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n var today = arguments.length > 1 ? arguments[1] : undefined;\n var year = parseInt(str.trim(), 10); // use a given year from options.today\n\n if (!year && today) {\n year = today.year;\n } // fallback to this year\n\n\n year = year || new Date().getFullYear();\n return year;\n };\n\n var strFmt = [//iso-this 1998-05-30T22:00:00:000Z, iso-that 2017-04-03T08:00:00-0700\n {\n reg: /^(\\-?0?0?[0-9]{3,4})-([0-9]{1,2})-([0-9]{1,2})[T| ]([0-9.:]+)(Z|[0-9\\-\\+:]+)?$/i,\n parse: function parse(s, arr, givenTz, options) {\n var month = parseInt(arr[2], 10) - 1;\n var obj = {\n year: arr[1],\n month: month,\n date: arr[3]\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n parseOffset_1$1(s, arr[5]);\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //iso \"2015-03-25\" or \"2015/03/25\" or \"2015/03/25 12:26:14 PM\"\n {\n reg: /^([0-9]{4})[\\-\\/.]([0-9]{1,2})[\\-\\/.]([0-9]{1,2}),?( [0-9]{1,2}:[0-9]{2}:?[0-9]{0,2}? ?(am|pm|gmt))?$/i,\n parse: function parse(s, arr) {\n var obj = {\n year: arr[1],\n month: parseInt(arr[2], 10) - 1,\n date: parseInt(arr[3], 10)\n };\n\n if (obj.month >= 12) {\n //support yyyy/dd/mm (weird, but ok)\n obj.date = parseInt(arr[2], 10);\n obj.month = parseInt(arr[3], 10) - 1;\n }\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //mm/dd/yyyy - uk/canada \"6/28/2019, 12:26:14 PM\"\n {\n reg: /^([0-9]{1,2})[\\-\\/.]([0-9]{1,2})[\\-\\/.]?([0-9]{4})?,?( [0-9]{1,2}:[0-9]{2}:?[0-9]{0,2}? ?(am|pm|gmt))?$/i,\n parse: function parse(s, arr) {\n var month = parseInt(arr[1], 10) - 1;\n var date = parseInt(arr[2], 10); //support dd/mm/yyy\n\n if (s.british || month >= 12) {\n date = parseInt(arr[1], 10);\n month = parseInt(arr[2], 10) - 1;\n }\n\n var year = parseYear(arr[3], s._today) || new Date().getFullYear();\n var obj = {\n year: year,\n month: month,\n date: date\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, // '2012-06' last attempt at iso-like format\n {\n reg: /^([0-9]{4})[\\-\\/]([0-9]{2})$/i,\n parse: function parse(s, arr, givenTz, options) {\n var month = parseInt(arr[2], 10) - 1;\n var obj = {\n year: arr[1],\n month: month,\n date: 1\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n parseOffset_1$1(s, arr[5]);\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //common british format - \"25-feb-2015\"\n {\n reg: /^([0-9]{1,2})[\\-\\/]([a-z]+)[\\-\\/]?([0-9]{4})?$/i,\n parse: function parse(s, arr) {\n var month = months$1[arr[2].toLowerCase()];\n var year = parseYear(arr[3], s._today);\n var obj = {\n year: year,\n month: month,\n date: fns.toCardinal(arr[1] || '')\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //alt short format - \"feb-25-2015\"\n {\n reg: /^([a-z]+)[\\-\\/]([0-9]{1,2})[\\-\\/]?([0-9]{4})?$/i,\n parse: function parse(s, arr) {\n var month = months$1[arr[1].toLowerCase()];\n var year = parseYear(arr[3], s._today);\n var obj = {\n year: year,\n month: month,\n date: fns.toCardinal(arr[2] || '')\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //Long \"Mar 25 2015\"\n //February 22, 2017 15:30:00\n {\n reg: /^([a-z]+) ([0-9]{1,2}(?:st|nd|rd|th)?),?( [0-9]{4})?( ([0-9:]+( ?am| ?pm| ?gmt)?))?$/i,\n parse: function parse(s, arr) {\n var month = months$1[arr[1].toLowerCase()];\n var year = parseYear(arr[3], s._today);\n var obj = {\n year: year,\n month: month,\n date: fns.toCardinal(arr[2] || '')\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //February 2017 (implied date)\n {\n reg: /^([a-z]+) ([0-9]{4})$/i,\n parse: function parse(s, arr) {\n var month = months$1[arr[1].toLowerCase()];\n var year = parseYear(arr[2], s._today);\n var obj = {\n year: year,\n month: month,\n date: s._today.date || 1\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //Long \"25 Mar 2015\"\n {\n reg: /^([0-9]{1,2}(?:st|nd|rd|th)?) ([a-z]+),?( [0-9]{4})?,? ?([0-9]{1,2}:[0-9]{2}:?[0-9]{0,2}? ?(am|pm|gmt))?$/i,\n parse: function parse(s, arr) {\n var month = months$1[arr[2].toLowerCase()];\n\n if (!month) {\n return null;\n }\n\n var year = parseYear(arr[3], s._today);\n var obj = {\n year: year,\n month: month,\n date: fns.toCardinal(arr[1])\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, {\n // 'q2 2002'\n reg: /^(q[0-9])( of)?( [0-9]{4})?/i,\n parse: function parse(s, arr) {\n var quarter = arr[1] || '';\n s = s.quarter(quarter);\n var year = arr[3] || '';\n\n if (year) {\n year = year.trim();\n s = s.year(year);\n }\n\n return s;\n }\n }, {\n // 'summer 2002'\n reg: /^(spring|summer|winter|fall|autumn)( of)?( [0-9]{4})?/i,\n parse: function parse(s, arr) {\n var season = arr[1] || '';\n s = s.season(season);\n var year = arr[3] || '';\n\n if (year) {\n year = year.trim();\n s = s.year(year);\n }\n\n return s;\n }\n }, {\n // '200bc'\n reg: /^[0-9,]+ ?b\\.?c\\.?$/i,\n parse: function parse(s, arr) {\n var str = arr[0] || ''; //make negative-year\n\n str = str.replace(/^([0-9,]+) ?b\\.?c\\.?$/i, '-$1'); //remove commas\n\n str = str.replace(/,/g, '');\n var year = parseInt(str.trim(), 10);\n var d = new Date();\n var obj = {\n year: year,\n month: d.getMonth(),\n date: d.getDate()\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s);\n return s;\n }\n }, {\n // '200ad'\n reg: /^[0-9,]+ ?(a\\.?d\\.?|c\\.?e\\.?)$/i,\n parse: function parse(s, arr) {\n var str = arr[0] || ''; //remove commas\n\n str = str.replace(/,/g, '');\n var year = parseInt(str.trim(), 10);\n var d = new Date();\n var obj = {\n year: year,\n month: d.getMonth(),\n date: d.getDate()\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s);\n return s;\n }\n }, {\n // '1992'\n reg: /^[0-9]{4}( ?a\\.?d\\.?)?$/i,\n parse: function parse(s, arr) {\n var today = s._today;\n var year = parseYear(arr[0], today);\n var d = new Date(); // using today's date, but a new month is awkward.\n\n if (today.month && !today.date) {\n today.date = 1;\n }\n\n var obj = {\n year: year,\n month: today.month || d.getMonth(),\n date: today.date || d.getDate()\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s);\n return s;\n }\n }];\n var strParse = strFmt;\n\n // pull in 'today' data for the baseline moment\n var getNow = function getNow(s) {\n s.epoch = Date.now();\n Object.keys(s._today || {}).forEach(function (k) {\n if (typeof s[k] === 'function') {\n s = s[k](s._today[k]);\n }\n });\n return s;\n };\n\n var dates = {\n now: function now(s) {\n return getNow(s);\n },\n today: function today(s) {\n return getNow(s);\n },\n tonight: function tonight(s) {\n s = getNow(s);\n s = s.hour(18); //6pm\n\n return s;\n },\n tomorrow: function tomorrow(s) {\n s = getNow(s);\n s = s.add(1, 'day');\n s = s.startOf('day');\n return s;\n },\n yesterday: function yesterday(s) {\n s = getNow(s);\n s = s.subtract(1, 'day');\n s = s.startOf('day');\n return s;\n },\n christmas: function christmas(s) {\n var year = getNow(s).year();\n s = s.set([year, 11, 25, 18, 0, 0]); // Dec 25\n\n return s;\n },\n 'new years': function newYears(s) {\n var year = getNow(s).year();\n s = s.set([year, 11, 31, 18, 0, 0]); // Dec 31\n\n return s;\n }\n };\n dates['new years eve'] = dates['new years'];\n var namedDates = dates;\n\n // - can't use built-in js parser ;(\n //=========================================\n // ISO Date\t \"2015-03-25\"\n // Short Date\t\"03/25/2015\" or \"2015/03/25\"\n // Long Date\t\"Mar 25 2015\" or \"25 Mar 2015\"\n // Full Date\t\"Wednesday March 25 2015\"\n //=========================================\n //-- also -\n // if the given epoch is really small, they've probably given seconds and not milliseconds\n // anything below this number is likely (but not necessarily) a mistaken input.\n // this may seem like an arbitrary number, but it's 'within jan 1970'\n // this is only really ambiguous until 2054 or so\n\n var minimumEpoch = 2500000000;\n var defaults = {\n year: new Date().getFullYear(),\n month: 0,\n date: 1\n }; //support [2016, 03, 01] format\n\n var handleArray = function handleArray(s, arr, today) {\n if (arr.length === 0) {\n return s;\n }\n\n var order = ['year', 'month', 'date', 'hour', 'minute', 'second', 'millisecond'];\n\n for (var i = 0; i < order.length; i++) {\n var num = arr[i] || today[order[i]] || defaults[order[i]] || 0;\n s = s[order[i]](num);\n }\n\n return s;\n }; //support {year:2016, month:3} format\n\n\n var handleObject = function handleObject(s, obj, today) {\n // if obj is empty, do nothing\n if (Object.keys(obj).length === 0) {\n return s;\n }\n\n obj = Object.assign({}, defaults, today, obj);\n var keys = Object.keys(obj);\n\n for (var i = 0; i < keys.length; i++) {\n var unit = keys[i]; //make sure we have this method\n\n if (s[unit] === undefined || typeof s[unit] !== 'function') {\n continue;\n } //make sure the value is a number\n\n\n if (obj[unit] === null || obj[unit] === undefined || obj[unit] === '') {\n continue;\n }\n\n var num = obj[unit] || today[unit] || defaults[unit] || 0;\n s = s[unit](num);\n }\n\n return s;\n }; //find the epoch from different input styles\n\n\n var parseInput = function parseInput(s, input, givenTz) {\n var today = s._today || defaults; //if we've been given a epoch number, it's easy\n\n if (typeof input === 'number') {\n if (input > 0 && input < minimumEpoch && s.silent === false) {\n console.warn(' - Warning: You are setting the date to January 1970.');\n console.warn(' - did input seconds instead of milliseconds?');\n }\n\n s.epoch = input;\n return s;\n } //set tmp time\n\n\n s.epoch = Date.now(); // overwrite tmp time with 'today' value, if exists\n\n if (s._today && fns.isObject(s._today) && Object.keys(s._today).length > 0) {\n var res = handleObject(s, today, defaults);\n\n if (res.isValid()) {\n s.epoch = res.epoch;\n }\n } // null input means 'now'\n\n\n if (input === null || input === undefined || input === '') {\n return s; //k, we're good.\n } //support input of Date() object\n\n\n if (fns.isDate(input) === true) {\n s.epoch = input.getTime();\n return s;\n } //support [2016, 03, 01] format\n\n\n if (fns.isArray(input) === true) {\n s = handleArray(s, input, today);\n return s;\n } //support {year:2016, month:3} format\n\n\n if (fns.isObject(input) === true) {\n //support spacetime object as input\n if (input.epoch) {\n s.epoch = input.epoch;\n s.tz = input.tz;\n return s;\n }\n\n s = handleObject(s, input, today);\n return s;\n } //input as a string..\n\n\n if (typeof input !== 'string') {\n return s;\n } //little cleanup..\n\n\n input = input.replace(/\\b(mon|tues|wed|wednes|thu|thurs|fri|sat|satur|sun)(day)?\\b/i, '');\n input = input.replace(/,/g, '');\n input = input.replace(/ +/g, ' ').trim(); //try some known-words, like 'now'\n\n if (namedDates.hasOwnProperty(input) === true) {\n s = namedDates[input](s);\n return s;\n } //try each text-parse template, use the first good result\n\n\n for (var i = 0; i < strParse.length; i++) {\n var m = input.match(strParse[i].reg);\n\n if (m) {\n // console.log(strFmt[i].reg)\n var _res = strParse[i].parse(s, m, givenTz);\n\n if (_res !== null && _res.isValid()) {\n return _res;\n }\n }\n }\n\n if (s.silent === false) {\n console.warn(\"Warning: couldn't parse date-string: '\" + input + \"'\");\n }\n\n s.epoch = null;\n return s;\n };\n\n var input = parseInput;\n\n var shortDays = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];\n var longDays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];\n var days = {\n \"short\": function short() {\n return shortDays;\n },\n \"long\": function long() {\n return longDays;\n },\n set: function set(i18n) {\n shortDays = i18n[\"short\"] || shortDays;\n longDays = i18n[\"long\"] || longDays;\n },\n aliases: {\n tues: 2,\n thur: 4,\n thurs: 4\n }\n };\n\n var titleCaseEnabled = true;\n var caseFormat = {\n useTitleCase: function useTitleCase() {\n return titleCaseEnabled;\n },\n set: function set(useTitleCase) {\n titleCaseEnabled = useTitleCase;\n }\n };\n\n // it's kind of nuts how involved this is\n // \"+01:00\", \"+0100\", or simply \"+01\"\n\n var isoOffset = function isoOffset(s) {\n var offset = s.timezone().current.offset;\n return !offset ? 'Z' : fns.formatTimezone(offset, ':');\n };\n\n var _offset = isoOffset;\n\n var applyCaseFormat = function applyCaseFormat(str) {\n if (caseFormat.useTitleCase()) {\n return fns.titleCase(str);\n }\n\n return str;\n };\n\n var format = {\n day: function day(s) {\n return applyCaseFormat(s.dayName());\n },\n 'day-short': function dayShort(s) {\n return applyCaseFormat(days[\"short\"]()[s.day()]);\n },\n 'day-number': function dayNumber(s) {\n return s.day();\n },\n 'day-ordinal': function dayOrdinal(s) {\n return fns.ordinal(s.day());\n },\n 'day-pad': function dayPad(s) {\n return fns.zeroPad(s.day());\n },\n date: function date(s) {\n return s.date();\n },\n 'date-ordinal': function dateOrdinal(s) {\n return fns.ordinal(s.date());\n },\n 'date-pad': function datePad(s) {\n return fns.zeroPad(s.date());\n },\n month: function month(s) {\n return applyCaseFormat(s.monthName());\n },\n 'month-short': function monthShort(s) {\n return applyCaseFormat(months[\"short\"]()[s.month()]);\n },\n 'month-number': function monthNumber(s) {\n return s.month();\n },\n 'month-ordinal': function monthOrdinal(s) {\n return fns.ordinal(s.month());\n },\n 'month-pad': function monthPad(s) {\n return fns.zeroPad(s.month());\n },\n 'iso-month': function isoMonth(s) {\n return fns.zeroPad(s.month() + 1);\n },\n //1-based months\n year: function year(s) {\n var year = s.year();\n\n if (year > 0) {\n return year;\n }\n\n year = Math.abs(year);\n return year + ' BC';\n },\n 'year-short': function yearShort(s) {\n var year = s.year();\n\n if (year > 0) {\n return \"'\".concat(String(s.year()).substr(2, 4));\n }\n\n year = Math.abs(year);\n return year + ' BC';\n },\n 'iso-year': function isoYear(s) {\n var year = s.year();\n var isNegative = year < 0;\n var str = fns.zeroPad(Math.abs(year), 4); //0-padded\n\n if (isNegative) {\n //negative years are for some reason 6-digits ('-00008')\n str = fns.zeroPad(str, 6);\n str = '-' + str;\n }\n\n return str;\n },\n time: function time(s) {\n return s.time();\n },\n 'time-24': function time24(s) {\n return \"\".concat(s.hour24(), \":\").concat(fns.zeroPad(s.minute()));\n },\n hour: function hour(s) {\n return s.hour12();\n },\n 'hour-pad': function hourPad(s) {\n return fns.zeroPad(s.hour12());\n },\n 'hour-24': function hour24(s) {\n return s.hour24();\n },\n 'hour-24-pad': function hour24Pad(s) {\n return fns.zeroPad(s.hour24());\n },\n minute: function minute(s) {\n return s.minute();\n },\n 'minute-pad': function minutePad(s) {\n return fns.zeroPad(s.minute());\n },\n second: function second(s) {\n return s.second();\n },\n 'second-pad': function secondPad(s) {\n return fns.zeroPad(s.second());\n },\n ampm: function ampm(s) {\n return s.ampm();\n },\n quarter: function quarter(s) {\n return 'Q' + s.quarter();\n },\n season: function season(s) {\n return s.season();\n },\n era: function era(s) {\n return s.era();\n },\n json: function json(s) {\n return s.json();\n },\n timezone: function timezone(s) {\n return s.timezone().name;\n },\n offset: function offset(s) {\n return _offset(s);\n },\n numeric: function numeric(s) {\n return \"\".concat(s.year(), \"/\").concat(fns.zeroPad(s.month() + 1), \"/\").concat(fns.zeroPad(s.date()));\n },\n // yyyy/mm/dd\n 'numeric-us': function numericUs(s) {\n return \"\".concat(fns.zeroPad(s.month() + 1), \"/\").concat(fns.zeroPad(s.date()), \"/\").concat(s.year());\n },\n // mm/dd/yyyy\n 'numeric-uk': function numericUk(s) {\n return \"\".concat(fns.zeroPad(s.date()), \"/\").concat(fns.zeroPad(s.month() + 1), \"/\").concat(s.year());\n },\n //dd/mm/yyyy\n 'mm/dd': function mmDd(s) {\n return \"\".concat(fns.zeroPad(s.month() + 1), \"/\").concat(fns.zeroPad(s.date()));\n },\n //mm/dd\n // ... https://en.wikipedia.org/wiki/ISO_8601 ;(((\n iso: function iso(s) {\n var year = s.format('iso-year');\n var month = fns.zeroPad(s.month() + 1); //1-based months\n\n var date = fns.zeroPad(s.date());\n var hour = fns.zeroPad(s.h24());\n var minute = fns.zeroPad(s.minute());\n var second = fns.zeroPad(s.second());\n var ms = fns.zeroPad(s.millisecond(), 3);\n var offset = _offset(s);\n return \"\".concat(year, \"-\").concat(month, \"-\").concat(date, \"T\").concat(hour, \":\").concat(minute, \":\").concat(second, \".\").concat(ms).concat(offset); //2018-03-09T08:50:00.000-05:00\n },\n 'iso-short': function isoShort(s) {\n var month = fns.zeroPad(s.month() + 1); //1-based months\n\n var date = fns.zeroPad(s.date());\n return \"\".concat(s.year(), \"-\").concat(month, \"-\").concat(date); //2017-02-15\n },\n 'iso-utc': function isoUtc(s) {\n return new Date(s.epoch).toISOString(); //2017-03-08T19:45:28.367Z\n },\n //i made these up\n nice: function nice(s) {\n return \"\".concat(months[\"short\"]()[s.month()], \" \").concat(fns.ordinal(s.date()), \", \").concat(s.time());\n },\n 'nice-24': function nice24(s) {\n return \"\".concat(months[\"short\"]()[s.month()], \" \").concat(fns.ordinal(s.date()), \", \").concat(s.hour24(), \":\").concat(fns.zeroPad(s.minute()));\n },\n 'nice-year': function niceYear(s) {\n return \"\".concat(months[\"short\"]()[s.month()], \" \").concat(fns.ordinal(s.date()), \", \").concat(s.year());\n },\n 'nice-day': function niceDay(s) {\n return \"\".concat(days[\"short\"]()[s.day()], \" \").concat(applyCaseFormat(months[\"short\"]()[s.month()]), \" \").concat(fns.ordinal(s.date()));\n },\n 'nice-full': function niceFull(s) {\n return \"\".concat(s.dayName(), \" \").concat(applyCaseFormat(s.monthName()), \" \").concat(fns.ordinal(s.date()), \", \").concat(s.time());\n },\n 'nice-full-24': function niceFull24(s) {\n return \"\".concat(s.dayName(), \" \").concat(applyCaseFormat(s.monthName()), \" \").concat(fns.ordinal(s.date()), \", \").concat(s.hour24(), \":\").concat(fns.zeroPad(s.minute()));\n }\n }; //aliases\n\n var aliases = {\n 'day-name': 'day',\n 'month-name': 'month',\n 'iso 8601': 'iso',\n 'time-h24': 'time-24',\n 'time-12': 'time',\n 'time-h12': 'time',\n tz: 'timezone',\n 'day-num': 'day-number',\n 'month-num': 'month-number',\n 'month-iso': 'iso-month',\n 'year-iso': 'iso-year',\n 'nice-short': 'nice',\n 'nice-short-24': 'nice-24',\n mdy: 'numeric-us',\n dmy: 'numeric-uk',\n ymd: 'numeric',\n 'yyyy/mm/dd': 'numeric',\n 'mm/dd/yyyy': 'numeric-us',\n 'dd/mm/yyyy': 'numeric-us',\n 'little-endian': 'numeric-uk',\n 'big-endian': 'numeric',\n 'day-nice': 'nice-day'\n };\n Object.keys(aliases).forEach(function (k) {\n return format[k] = format[aliases[k]];\n });\n\n var printFormat = function printFormat(s) {\n var str = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n\n //don't print anything if it's an invalid date\n if (s.isValid() !== true) {\n return '';\n } //support .format('month')\n\n\n if (format.hasOwnProperty(str)) {\n var out = format[str](s) || '';\n\n if (str !== 'json') {\n out = String(out);\n\n if (str !== 'ampm') {\n out = applyCaseFormat(out);\n }\n }\n\n return out;\n } //support '{hour}:{minute}' notation\n\n\n if (str.indexOf('{') !== -1) {\n var sections = /\\{(.+?)\\}/g;\n str = str.replace(sections, function (_, fmt) {\n fmt = fmt.toLowerCase().trim();\n\n if (format.hasOwnProperty(fmt)) {\n var _out = String(format[fmt](s));\n\n if (fmt !== 'ampm') {\n return applyCaseFormat(_out);\n }\n\n return _out;\n }\n\n return '';\n });\n return str;\n }\n\n return s.format('iso-short');\n };\n\n var format_1 = printFormat;\n\n var pad = fns.zeroPad;\n var formatTimezone = fns.formatTimezone; //parse this insane unix-time-templating thing, from the 19th century\n //http://unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns\n //time-symbols we support\n\n var mapping = {\n G: function G(s) {\n return s.era();\n },\n GG: function GG(s) {\n return s.era();\n },\n GGG: function GGG(s) {\n return s.era();\n },\n GGGG: function GGGG(s) {\n return s.era() === 'AD' ? 'Anno Domini' : 'Before Christ';\n },\n //year\n y: function y(s) {\n return s.year();\n },\n yy: function yy(s) {\n //last two chars\n return parseInt(String(s.year()).substr(2, 4), 10);\n },\n yyy: function yyy(s) {\n return s.year();\n },\n yyyy: function yyyy(s) {\n return s.year();\n },\n yyyyy: function yyyyy(s) {\n return '0' + s.year();\n },\n // u: (s) => {},//extended non-gregorian years\n //quarter\n Q: function Q(s) {\n return s.quarter();\n },\n QQ: function QQ(s) {\n return s.quarter();\n },\n QQQ: function QQQ(s) {\n return s.quarter();\n },\n QQQQ: function QQQQ(s) {\n return s.quarter();\n },\n //month\n M: function M(s) {\n return s.month() + 1;\n },\n MM: function MM(s) {\n return pad(s.month() + 1);\n },\n MMM: function MMM(s) {\n return s.format('month-short');\n },\n MMMM: function MMMM(s) {\n return s.format('month');\n },\n //week\n w: function w(s) {\n return s.week();\n },\n ww: function ww(s) {\n return pad(s.week());\n },\n //week of month\n // W: (s) => s.week(),\n //date of month\n d: function d(s) {\n return s.date();\n },\n dd: function dd(s) {\n return pad(s.date());\n },\n //date of year\n D: function D(s) {\n return s.dayOfYear();\n },\n DD: function DD(s) {\n return pad(s.dayOfYear());\n },\n DDD: function DDD(s) {\n return pad(s.dayOfYear(), 3);\n },\n // F: (s) => {},//date of week in month\n // g: (s) => {},//modified julian day\n //day\n E: function E(s) {\n return s.format('day-short');\n },\n EE: function EE(s) {\n return s.format('day-short');\n },\n EEE: function EEE(s) {\n return s.format('day-short');\n },\n EEEE: function EEEE(s) {\n return s.format('day');\n },\n EEEEE: function EEEEE(s) {\n return s.format('day')[0];\n },\n e: function e(s) {\n return s.day();\n },\n ee: function ee(s) {\n return s.day();\n },\n eee: function eee(s) {\n return s.format('day-short');\n },\n eeee: function eeee(s) {\n return s.format('day');\n },\n eeeee: function eeeee(s) {\n return s.format('day')[0];\n },\n //am/pm\n a: function a(s) {\n return s.ampm().toUpperCase();\n },\n aa: function aa(s) {\n return s.ampm().toUpperCase();\n },\n aaa: function aaa(s) {\n return s.ampm().toUpperCase();\n },\n aaaa: function aaaa(s) {\n return s.ampm().toUpperCase();\n },\n //hour\n h: function h(s) {\n return s.h12();\n },\n hh: function hh(s) {\n return pad(s.h12());\n },\n H: function H(s) {\n return s.hour();\n },\n HH: function HH(s) {\n return pad(s.hour());\n },\n // j: (s) => {},//weird hour format\n m: function m(s) {\n return s.minute();\n },\n mm: function mm(s) {\n return pad(s.minute());\n },\n s: function s(_s) {\n return _s.second();\n },\n ss: function ss(s) {\n return pad(s.second());\n },\n //milliseconds in the day\n A: function A(s) {\n return s.epoch - s.startOf('day').epoch;\n },\n //timezone\n z: function z(s) {\n return s.timezone().name;\n },\n zz: function zz(s) {\n return s.timezone().name;\n },\n zzz: function zzz(s) {\n return s.timezone().name;\n },\n zzzz: function zzzz(s) {\n return s.timezone().name;\n },\n Z: function Z(s) {\n return formatTimezone(s.timezone().current.offset);\n },\n ZZ: function ZZ(s) {\n return formatTimezone(s.timezone().current.offset);\n },\n ZZZ: function ZZZ(s) {\n return formatTimezone(s.timezone().current.offset);\n },\n ZZZZ: function ZZZZ(s) {\n return formatTimezone(s.timezone().current.offset, ':');\n }\n };\n\n var addAlias = function addAlias(_char, to, n) {\n var name = _char;\n var toName = to;\n\n for (var i = 0; i < n; i += 1) {\n mapping[name] = mapping[toName];\n name += _char;\n toName += to;\n }\n };\n\n addAlias('q', 'Q', 4);\n addAlias('L', 'M', 4);\n addAlias('Y', 'y', 4);\n addAlias('c', 'e', 4);\n addAlias('k', 'H', 2);\n addAlias('K', 'h', 2);\n addAlias('S', 's', 2);\n addAlias('v', 'z', 4);\n addAlias('V', 'Z', 4); // support unix-style escaping with ' character\n\n var escapeChars = function escapeChars(arr) {\n for (var i = 0; i < arr.length; i += 1) {\n if (arr[i] === \"'\") {\n // greedy-search for next apostrophe\n for (var o = i + 1; o < arr.length; o += 1) {\n if (arr[o]) {\n arr[i] += arr[o];\n }\n\n if (arr[o] === \"'\") {\n arr[o] = null;\n break;\n }\n\n arr[o] = null;\n }\n }\n }\n\n return arr.filter(function (ch) {\n return ch;\n });\n }; //combine consecutive chars, like 'yyyy' as one.\n\n\n var combineRepeated = function combineRepeated(arr) {\n for (var i = 0; i < arr.length; i += 1) {\n var c = arr[i]; // greedy-forward\n\n for (var o = i + 1; o < arr.length; o += 1) {\n if (arr[o] === c) {\n arr[i] += arr[o];\n arr[o] = null;\n } else {\n break;\n }\n }\n } // '' means one apostrophe\n\n\n arr = arr.filter(function (ch) {\n return ch;\n });\n arr = arr.map(function (str) {\n if (str === \"''\") {\n str = \"'\";\n }\n\n return str;\n });\n return arr;\n };\n\n var unixFmt = function unixFmt(s, str) {\n var arr = str.split(''); // support character escaping\n\n arr = escapeChars(arr); //combine 'yyyy' as string.\n\n arr = combineRepeated(arr);\n return arr.reduce(function (txt, c) {\n if (mapping[c] !== undefined) {\n txt += mapping[c](s) || '';\n } else {\n // 'unescape'\n if (/^'.{1,}'$/.test(c)) {\n c = c.replace(/'/g, '');\n }\n\n txt += c;\n }\n\n return txt;\n }, '');\n };\n\n var unixFmt_1 = unixFmt;\n\n var units$1 = ['year', 'season', 'quarter', 'month', 'week', 'day', 'quarterHour', 'hour', 'minute'];\n\n var doUnit = function doUnit(s, k) {\n var start = s.clone().startOf(k);\n var end = s.clone().endOf(k);\n var duration = end.epoch - start.epoch;\n var percent = (s.epoch - start.epoch) / duration;\n return parseFloat(percent.toFixed(2));\n }; //how far it is along, from 0-1\n\n\n var progress = function progress(s, unit) {\n if (unit) {\n unit = fns.normalize(unit);\n return doUnit(s, unit);\n }\n\n var obj = {};\n units$1.forEach(function (k) {\n obj[k] = doUnit(s, k);\n });\n return obj;\n };\n\n var progress_1 = progress;\n\n var nearest = function nearest(s, unit) {\n //how far have we gone?\n var prog = s.progress();\n unit = fns.normalize(unit); //fix camel-case for this one\n\n if (unit === 'quarterhour') {\n unit = 'quarterHour';\n }\n\n if (prog[unit] !== undefined) {\n // go forward one?\n if (prog[unit] > 0.5) {\n s = s.add(1, unit);\n } // go to start\n\n\n s = s.startOf(unit);\n } else if (s.silent === false) {\n console.warn(\"no known unit '\" + unit + \"'\");\n }\n\n return s;\n };\n\n var nearest_1 = nearest;\n\n //increment until dates are the same\n var climb = function climb(a, b, unit) {\n var i = 0;\n a = a.clone();\n\n while (a.isBefore(b)) {\n //do proper, expensive increment to catch all-the-tricks\n a = a.add(1, unit);\n i += 1;\n } //oops, we went too-far..\n\n\n if (a.isAfter(b, unit)) {\n i -= 1;\n }\n\n return i;\n }; // do a thurough +=1 on the unit, until they match\n // for speed-reasons, only used on day, month, week.\n\n\n var diffOne = function diffOne(a, b, unit) {\n if (a.isBefore(b)) {\n return climb(a, b, unit);\n } else {\n return climb(b, a, unit) * -1; //reverse it\n }\n };\n\n var one = diffOne;\n\n // 2020 - 2019 may be 1 year, or 0 years\n // - '1 year difference' means 366 days during a leap year\n\n var fastYear = function fastYear(a, b) {\n var years = b.year() - a.year(); // should we decrement it by 1?\n\n a = a.year(b.year());\n\n if (a.isAfter(b)) {\n years -= 1;\n }\n\n return years;\n }; // use a waterfall-method for computing a diff of any 'pre-knowable' units\n // compute years, then compute months, etc..\n // ... then ms-math for any very-small units\n\n\n var diff = function diff(a, b) {\n // an hour is always the same # of milliseconds\n // so these units can be 'pre-calculated'\n var msDiff = b.epoch - a.epoch;\n var obj = {\n milliseconds: msDiff,\n seconds: parseInt(msDiff / 1000, 10)\n };\n obj.minutes = parseInt(obj.seconds / 60, 10);\n obj.hours = parseInt(obj.minutes / 60, 10); //do the year\n\n var tmp = a.clone();\n obj.years = fastYear(tmp, b);\n tmp = a.add(obj.years, 'year'); //there's always 12 months in a year...\n\n obj.months = obj.years * 12;\n tmp = a.add(obj.months, 'month');\n obj.months += one(tmp, b, 'month'); // there's always atleast 52 weeks in a year..\n // (month * 4) isn't as close\n\n obj.weeks = obj.years * 52;\n tmp = a.add(obj.weeks, 'week');\n obj.weeks += one(tmp, b, 'week'); // there's always atleast 7 days in a week\n\n obj.days = obj.weeks * 7;\n tmp = a.add(obj.days, 'day');\n obj.days += one(tmp, b, 'day');\n return obj;\n };\n\n var waterfall = diff;\n\n var reverseDiff = function reverseDiff(obj) {\n Object.keys(obj).forEach(function (k) {\n obj[k] *= -1;\n });\n return obj;\n }; // this method counts a total # of each unit, between a, b.\n // '1 month' means 28 days in february\n // '1 year' means 366 days in a leap year\n\n\n var main = function main(a, b, unit) {\n b = fns.beADate(b, a); //reverse values, if necessary\n\n var reversed = false;\n\n if (a.isAfter(b)) {\n var tmp = a;\n a = b;\n b = tmp;\n reversed = true;\n } //compute them all (i know!)\n\n\n var obj = waterfall(a, b);\n\n if (reversed) {\n obj = reverseDiff(obj);\n } //return just the requested unit\n\n\n if (unit) {\n //make sure it's plural-form\n unit = fns.normalize(unit);\n\n if (/s$/.test(unit) !== true) {\n unit += 's';\n }\n\n if (unit === 'dates') {\n unit = 'days';\n }\n\n return obj[unit];\n }\n\n return obj;\n };\n\n var diff$1 = main;\n\n //our conceptual 'break-points' for each unit\n\n var qualifiers = {\n months: {\n almost: 10,\n over: 4\n },\n days: {\n almost: 25,\n over: 10\n },\n hours: {\n almost: 20,\n over: 8\n },\n minutes: {\n almost: 50,\n over: 20\n },\n seconds: {\n almost: 50,\n over: 20\n }\n }; //get number of hours/minutes... between the two dates\n\n function getDiff(a, b) {\n var isBefore = a.isBefore(b);\n var later = isBefore ? b : a;\n var earlier = isBefore ? a : b;\n earlier = earlier.clone();\n var diff = {\n years: 0,\n months: 0,\n days: 0,\n hours: 0,\n minutes: 0,\n seconds: 0\n };\n Object.keys(diff).forEach(function (unit) {\n if (earlier.isSame(later, unit)) {\n return;\n }\n\n var max = earlier.diff(later, unit);\n earlier = earlier.add(max, unit);\n diff[unit] = max;\n }); //reverse it, if necessary\n\n if (isBefore) {\n Object.keys(diff).forEach(function (u) {\n if (diff[u] !== 0) {\n diff[u] *= -1;\n }\n });\n }\n\n return diff;\n } // Expects a plural unit arg\n\n\n function pluralize(value, unit) {\n if (value === 1) {\n unit = unit.slice(0, -1);\n }\n\n return value + ' ' + unit;\n } //create the human-readable diff between the two dates\n\n\n var since = function since(start, end) {\n end = fns.beADate(end, start);\n var diff = getDiff(start, end);\n var isNow = Object.keys(diff).every(function (u) {\n return !diff[u];\n });\n\n if (isNow === true) {\n return {\n diff: diff,\n rounded: 'now',\n qualified: 'now',\n precise: 'now'\n };\n }\n\n var rounded;\n var qualified;\n var precise;\n var englishValues = []; //go through each value and create its text-representation\n\n Object.keys(diff).forEach(function (unit, i, units) {\n var value = Math.abs(diff[unit]);\n\n if (value === 0) {\n return;\n }\n\n var englishValue = pluralize(value, unit);\n englishValues.push(englishValue);\n\n if (!rounded) {\n rounded = qualified = englishValue;\n\n if (i > 4) {\n return;\n } //is it a 'almost' something, etc?\n\n\n var nextUnit = units[i + 1];\n var nextValue = Math.abs(diff[nextUnit]);\n\n if (nextValue > qualifiers[nextUnit].almost) {\n rounded = pluralize(value + 1, unit);\n qualified = 'almost ' + rounded;\n } else if (nextValue > qualifiers[nextUnit].over) qualified = 'over ' + englishValue;\n }\n }); //make them into a string\n\n precise = englishValues.splice(0, 2).join(', '); //handle before/after logic\n\n if (start.isAfter(end) === true) {\n rounded += ' ago';\n qualified += ' ago';\n precise += ' ago';\n } else {\n rounded = 'in ' + rounded;\n qualified = 'in ' + qualified;\n precise = 'in ' + precise;\n }\n\n return {\n diff: diff,\n rounded: rounded,\n qualified: qualified,\n precise: precise\n };\n };\n\n var since_1 = since;\n\n //https://www.timeanddate.com/calendar/aboutseasons.html\n // Spring - from March 1 to May 31;\n // Summer - from June 1 to August 31;\n // Fall (autumn) - from September 1 to November 30; and,\n // Winter - from December 1 to February 28 (February 29 in a leap year).\n var seasons = {\n north: [['spring', 2, 1], //spring march 1\n ['summer', 5, 1], //june 1\n ['fall', 8, 1], //sept 1\n ['autumn', 8, 1], //sept 1\n ['winter', 11, 1] //dec 1\n ],\n south: [['fall', 2, 1], //march 1\n ['autumn', 2, 1], //march 1\n ['winter', 5, 1], //june 1\n ['spring', 8, 1], //sept 1\n ['summer', 11, 1] //dec 1\n ]\n };\n\n var quarters = [null, [0, 1], //jan 1\n [3, 1], //apr 1\n [6, 1], //july 1\n [9, 1] //oct 1\n ];\n\n var units$2 = {\n minute: function minute(s) {\n walk_1(s, {\n second: 0,\n millisecond: 0\n });\n return s;\n },\n quarterhour: function quarterhour(s) {\n var minute = s.minutes();\n\n if (minute >= 45) {\n s = s.minutes(45);\n } else if (minute >= 30) {\n s = s.minutes(30);\n } else if (minute >= 15) {\n s = s.minutes(15);\n } else {\n s = s.minutes(0);\n }\n\n walk_1(s, {\n second: 0,\n millisecond: 0\n });\n return s;\n },\n hour: function hour(s) {\n walk_1(s, {\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n },\n day: function day(s) {\n walk_1(s, {\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n },\n week: function week(s) {\n var original = s.clone();\n s = s.day(s._weekStart); //monday\n\n if (s.isAfter(original)) {\n s = s.subtract(1, 'week');\n }\n\n walk_1(s, {\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n },\n month: function month(s) {\n walk_1(s, {\n date: 1,\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n },\n quarter: function quarter(s) {\n var q = s.quarter();\n\n if (quarters[q]) {\n walk_1(s, {\n month: quarters[q][0],\n date: quarters[q][1],\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n }\n\n return s;\n },\n season: function season(s) {\n var current = s.season();\n var hem = 'north';\n\n if (s.hemisphere() === 'South') {\n hem = 'south';\n }\n\n for (var i = 0; i < seasons[hem].length; i++) {\n if (seasons[hem][i][0] === current) {\n //winter goes between years\n var year = s.year();\n\n if (current === 'winter' && s.month() < 3) {\n year -= 1;\n }\n\n walk_1(s, {\n year: year,\n month: seasons[hem][i][1],\n date: seasons[hem][i][2],\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n }\n }\n\n return s;\n },\n year: function year(s) {\n walk_1(s, {\n month: 0,\n date: 1,\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n },\n decade: function decade(s) {\n s = s.startOf('year');\n var year = s.year();\n var decade = parseInt(year / 10, 10) * 10;\n s = s.year(decade);\n return s;\n },\n century: function century(s) {\n s = s.startOf('year');\n var year = s.year(); // near 0AD goes '-1 | +1'\n\n var decade = parseInt(year / 100, 10) * 100;\n s = s.year(decade);\n return s;\n }\n };\n units$2.date = units$2.day;\n\n var startOf = function startOf(a, unit) {\n var s = a.clone();\n unit = fns.normalize(unit);\n\n if (units$2[unit]) {\n return units$2[unit](s);\n }\n\n if (unit === 'summer' || unit === 'winter') {\n s = s.season(unit);\n return units$2.season(s);\n }\n\n return s;\n }; //piggy-backs off startOf\n\n\n var endOf = function endOf(a, unit) {\n var s = a.clone();\n unit = fns.normalize(unit);\n\n if (units$2[unit]) {\n // go to beginning, go to next one, step back 1ms\n s = units$2[unit](s); // startof\n\n s = s.add(1, unit);\n s = s.subtract(1, 'millisecond');\n return s;\n }\n\n return s;\n };\n\n var startOf_1 = {\n startOf: startOf,\n endOf: endOf\n };\n\n var isDay = function isDay(unit) {\n if (days[\"short\"]().find(function (s) {\n return s === unit;\n })) {\n return true;\n }\n\n if (days[\"long\"]().find(function (s) {\n return s === unit;\n })) {\n return true;\n }\n\n return false;\n }; // return a list of the weeks/months/days between a -> b\n // returns spacetime objects in the timezone of the input\n\n\n var every = function every(start) {\n var unit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n var end = arguments.length > 2 ? arguments[2] : undefined;\n\n if (!unit || !end) {\n return [];\n } //cleanup unit param\n\n\n unit = fns.normalize(unit); //cleanup to param\n\n end = start.clone().set(end); //swap them, if they're backwards\n\n if (start.isAfter(end)) {\n var tmp = start;\n start = end;\n end = tmp;\n } //support 'every wednesday'\n\n\n var d = start.clone();\n\n if (isDay(unit)) {\n d = d.next(unit);\n unit = 'week';\n } else {\n d = d.next(unit);\n } //okay, actually start doing it\n\n\n var result = [];\n\n while (d.isBefore(end)) {\n result.push(d);\n d = d.add(1, unit);\n }\n\n return result;\n };\n\n var every_1 = every;\n\n var parseDst = function parseDst(dst) {\n if (!dst) {\n return [];\n }\n\n return dst.split('->');\n };\n\n var titleCase = function titleCase(str) {\n str = str[0].toUpperCase() + str.substr(1);\n str = str.replace(/\\/gmt/, '/GMT');\n str = str.replace(/[\\/_]([a-z])/gi, function (s) {\n return s.toUpperCase();\n });\n return str;\n }; //get metadata about this timezone\n\n\n var timezone = function timezone(s) {\n var zones = s.timezones;\n var tz = s.tz;\n\n if (zones.hasOwnProperty(tz) === false) {\n tz = find(s.tz, zones);\n }\n\n if (tz === null) {\n if (s.silent === false) {\n console.warn(\"Warn: could not find given or local timezone - '\" + s.tz + \"'\");\n }\n\n return {\n current: {\n epochShift: 0\n }\n };\n }\n\n var found = zones[tz];\n var result = {\n name: titleCase(tz),\n hasDst: Boolean(found.dst),\n default_offset: found.offset,\n //do north-hemisphere version as default (sorry!)\n hemisphere: found.hem === 's' ? 'South' : 'North',\n current: {}\n };\n\n if (result.hasDst) {\n var arr = parseDst(found.dst);\n result.change = {\n start: arr[0],\n back: arr[1]\n };\n } //find the offsets for summer/winter times\n //(these variable names are north-centric)\n\n\n var summer = found.offset; // (july)\n\n var winter = summer; // (january) assume it's the same for now\n\n if (result.hasDst === true) {\n if (result.hemisphere === 'North') {\n winter = summer - 1;\n } else {\n //southern hemisphere\n winter = found.offset + 1;\n }\n } //find out which offset to use right now\n //use 'summer' time july-time\n\n\n if (result.hasDst === false) {\n result.current.offset = summer;\n result.current.isDST = false;\n } else if (summerTime(s.epoch, result.change.start, result.change.back, summer, winter) === true) {\n result.current.offset = summer;\n result.current.isDST = result.hemisphere === 'North'; //dst 'on' in winter in north\n } else {\n //use 'winter' january-time\n result.current.offset = winter;\n result.current.isDST = result.hemisphere === 'South'; //dst 'on' in summer in south\n }\n\n return result;\n };\n\n var timezone_1 = timezone;\n\n var units$3 = ['century', 'decade', 'year', 'month', 'date', 'day', 'hour', 'minute', 'second', 'millisecond']; //the spacetime instance methods (also, the API)\n\n var methods = {\n set: function set(input$1, tz) {\n var s = this.clone();\n s = input(s, input$1, null);\n\n if (tz) {\n this.tz = find(tz);\n }\n\n return s;\n },\n timezone: function timezone() {\n return timezone_1(this);\n },\n isDST: function isDST() {\n return timezone_1(this).current.isDST;\n },\n hasDST: function hasDST() {\n return timezone_1(this).hasDst;\n },\n offset: function offset() {\n return timezone_1(this).current.offset * 60;\n },\n hemisphere: function hemisphere() {\n return timezone_1(this).hemisphere;\n },\n format: function format(fmt) {\n return format_1(this, fmt);\n },\n unixFmt: function unixFmt(fmt) {\n return unixFmt_1(this, fmt);\n },\n startOf: function startOf(unit) {\n return startOf_1.startOf(this, unit);\n },\n endOf: function endOf(unit) {\n return startOf_1.endOf(this, unit);\n },\n leapYear: function leapYear() {\n var year = this.year();\n return fns.isLeapYear(year);\n },\n progress: function progress(unit) {\n return progress_1(this, unit);\n },\n nearest: function nearest(unit) {\n return nearest_1(this, unit);\n },\n diff: function diff(d, unit) {\n return diff$1(this, d, unit);\n },\n since: function since(d) {\n if (!d) {\n d = this.clone().set();\n }\n\n return since_1(this, d);\n },\n next: function next(unit) {\n var s = this.add(1, unit);\n return s.startOf(unit);\n },\n //the start of the previous year/week/century\n last: function last(unit) {\n var s = this.subtract(1, unit);\n return s.startOf(unit);\n },\n isValid: function isValid() {\n //null/undefined epochs\n if (!this.epoch && this.epoch !== 0) {\n return false;\n }\n\n return !isNaN(this.d.getTime());\n },\n //travel to this timezone\n \"goto\": function goto(tz) {\n var s = this.clone();\n s.tz = find(tz, s.timezones); //science!\n\n return s;\n },\n //get each week/month/day between a -> b\n every: function every(unit, to) {\n return every_1(this, unit, to);\n },\n isAwake: function isAwake() {\n var hour = this.hour(); //10pm -> 8am\n\n if (hour < 8 || hour > 22) {\n return false;\n }\n\n return true;\n },\n isAsleep: function isAsleep() {\n return !this.isAwake();\n },\n //pretty-printing\n log: function log() {\n console.log('');\n console.log(format_1(this, 'nice-short'));\n return this;\n },\n logYear: function logYear() {\n console.log('');\n console.log(format_1(this, 'full-short'));\n return this;\n },\n json: function json() {\n var _this = this;\n\n return units$3.reduce(function (h, unit) {\n h[unit] = _this[unit]();\n return h;\n }, {});\n },\n debug: function debug() {\n var tz = this.timezone();\n var date = this.format('MM') + ' ' + this.format('date-ordinal') + ' ' + this.year();\n date += '\\n - ' + this.format('time');\n console.log('\\n\\n', date + '\\n - ' + tz.name + ' (' + tz.current.offset + ')');\n return this;\n },\n //alias of 'since' but opposite - like moment.js\n from: function from(d) {\n d = this.clone().set(d);\n return d.since(this);\n },\n fromNow: function fromNow() {\n var d = this.clone().set(Date.now());\n return d.since(this);\n },\n weekStart: function weekStart(input) {\n //accept a number directly\n if (typeof input === 'number') {\n this._weekStart = input;\n return this;\n }\n\n if (typeof input === 'string') {\n // accept 'wednesday'\n input = input.toLowerCase().trim();\n var num = days[\"short\"]().indexOf(input);\n\n if (num === -1) {\n num = days[\"long\"]().indexOf(input);\n }\n\n if (num === -1) {\n num = 1; //go back to default\n }\n\n this._weekStart = num;\n } else {\n console.warn('Spacetime Error: Cannot understand .weekStart() input:', input);\n }\n\n return this;\n }\n }; // aliases\n\n methods.inDST = methods.isDST;\n methods.round = methods.nearest;\n methods.each = methods.every;\n var methods_1 = methods;\n\n //these methods wrap around them.\n\n var isLeapYear$1 = fns.isLeapYear;\n\n var validate = function validate(n) {\n //handle number as a string\n if (typeof n === 'string') {\n n = parseInt(n, 10);\n }\n\n return n;\n };\n\n var order = ['year', 'month', 'date', 'hour', 'minute', 'second', 'millisecond']; //reduce hostile micro-changes when moving dates by millisecond\n\n var confirm = function confirm(s, tmp, unit) {\n var n = order.indexOf(unit);\n var arr = order.slice(n, order.length);\n\n for (var i = 0; i < arr.length; i++) {\n var want = tmp[arr[i]]();\n s[arr[i]](want);\n }\n\n return s;\n };\n\n var set = {\n milliseconds: function milliseconds(s, n) {\n n = validate(n);\n var current = s.millisecond();\n var diff = current - n; //milliseconds to shift by\n\n return s.epoch - diff;\n },\n seconds: function seconds(s, n) {\n n = validate(n);\n var diff = s.second() - n;\n var shift = diff * milliseconds.second;\n return s.epoch - shift;\n },\n minutes: function minutes(s, n) {\n n = validate(n);\n var old = s.clone();\n var diff = s.minute() - n;\n var shift = diff * milliseconds.minute;\n s.epoch -= shift; // check against a screw-up\n // if (old.hour() != s.hour()) {\n // walkTo(old, {\n // minute: n\n // })\n // return old.epoch\n // }\n\n confirm(s, old, 'second');\n return s.epoch;\n },\n hours: function hours(s, n) {\n n = validate(n);\n\n if (n >= 24) {\n n = 24;\n } else if (n < 0) {\n n = 0;\n }\n\n var old = s.clone();\n var diff = s.hour() - n;\n var shift = diff * milliseconds.hour;\n s.epoch -= shift; // oops, did we change the day?\n\n if (s.date() !== old.date()) {\n s = old.clone();\n\n if (diff > 1) {\n diff -= 1;\n }\n\n if (diff < 1) {\n diff += 1;\n }\n\n shift = diff * milliseconds.hour;\n s.epoch -= shift;\n }\n\n walk_1(s, {\n hour: n\n });\n confirm(s, old, 'minute');\n return s.epoch;\n },\n //support setting time by '4:25pm' - this isn't very-well developed..\n time: function time(s, str) {\n var m = str.match(/([0-9]{1,2})[:h]([0-9]{1,2})(:[0-9]{1,2})? ?(am|pm)?/);\n\n if (!m) {\n //fallback to support just '2am'\n m = str.match(/([0-9]{1,2}) ?(am|pm)/);\n\n if (!m) {\n return s.epoch;\n }\n\n m.splice(2, 0, '0'); //add implicit 0 minutes\n\n m.splice(3, 0, ''); //add implicit seconds\n }\n\n var h24 = false;\n var hour = parseInt(m[1], 10);\n var minute = parseInt(m[2], 10);\n\n if (hour > 12) {\n h24 = true;\n } //make the hour into proper 24h time\n\n\n if (h24 === false) {\n if (m[4] === 'am' && hour === 12) {\n //12am is midnight\n hour = 0;\n }\n\n if (m[4] === 'pm' && hour < 12) {\n //12pm is noon\n hour += 12;\n }\n } // handle seconds\n\n\n m[3] = m[3] || '';\n m[3] = m[3].replace(/:/, '');\n var sec = parseInt(m[3], 10) || 0;\n s = s.hour(hour);\n s = s.minute(minute);\n s = s.second(sec);\n s = s.millisecond(0);\n return s.epoch;\n },\n date: function date(s, n) {\n n = validate(n); //avoid setting february 31st\n\n if (n > 28) {\n var month = s.month();\n var max = monthLengths_1[month]; // support leap day in february\n\n if (month === 1 && n === 29 && isLeapYear$1(s.year())) {\n max = 29;\n }\n\n if (n > max) {\n n = max;\n }\n } //avoid setting < 0\n\n\n if (n <= 0) {\n n = 1;\n }\n\n walk_1(s, {\n date: n\n });\n return s.epoch;\n },\n //this one's tricky\n month: function month(s, n) {\n if (typeof n === 'string') {\n n = months.mapping()[n.toLowerCase()];\n }\n\n n = validate(n); //don't go past december\n\n if (n >= 12) {\n n = 11;\n }\n\n if (n <= 0) {\n n = 0;\n }\n\n var date = s.date(); //there's no 30th of february, etc.\n\n if (date > monthLengths_1[n]) {\n //make it as close as we can..\n date = monthLengths_1[n];\n }\n\n walk_1(s, {\n month: n,\n date: date\n });\n return s.epoch;\n },\n year: function year(s, n) {\n // support '97\n if (typeof n === 'string' && /^'[0-9]{2}$/.test(n)) {\n n = n.replace(/'/, '').trim();\n n = Number(n); // '89 is 1989\n\n if (n > 30) {\n //change this in 10y\n n = 1900 + n;\n } else {\n // '12 is 2012\n n = 2000 + n;\n }\n }\n\n n = validate(n);\n walk_1(s, {\n year: n\n });\n return s.epoch;\n },\n dayOfYear: function dayOfYear(s, n) {\n n = validate(n);\n var old = s.clone();\n n -= 1; //days are 1-based\n\n if (n <= 0) {\n n = 0;\n } else if (n >= 365) {\n n = 364;\n }\n\n s = s.startOf('year');\n s = s.add(n, 'day');\n confirm(s, old, 'hour');\n return s.epoch;\n }\n };\n\n var methods$1 = {\n millisecond: function millisecond(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.milliseconds(s, num);\n return s;\n }\n\n return this.d.getMilliseconds();\n },\n second: function second(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.seconds(s, num);\n return s;\n }\n\n return this.d.getSeconds();\n },\n minute: function minute(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.minutes(s, num);\n return s;\n }\n\n return this.d.getMinutes();\n },\n hour: function hour(num) {\n var d = this.d;\n\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.hours(s, num);\n return s;\n }\n\n return d.getHours();\n },\n //'3:30' is 3.5\n hourFloat: function hourFloat(num) {\n if (num !== undefined) {\n var s = this.clone();\n\n var _minute = num % 1;\n\n _minute = _minute * 60;\n\n var _hour = parseInt(num, 10);\n\n s.epoch = set.hours(s, _hour);\n s.epoch = set.minutes(s, _minute);\n return s;\n }\n\n var d = this.d;\n var hour = d.getHours();\n var minute = d.getMinutes();\n minute = minute / 60;\n return hour + minute;\n },\n // hour in 12h format\n hour12: function hour12(str) {\n var d = this.d;\n\n if (str !== undefined) {\n var s = this.clone();\n str = '' + str;\n var m = str.match(/^([0-9]+)(am|pm)$/);\n\n if (m) {\n var hour = parseInt(m[1], 10);\n\n if (m[2] === 'pm') {\n hour += 12;\n }\n\n s.epoch = set.hours(s, hour);\n }\n\n return s;\n } //get the hour\n\n\n var hour12 = d.getHours();\n\n if (hour12 > 12) {\n hour12 = hour12 - 12;\n }\n\n if (hour12 === 0) {\n hour12 = 12;\n }\n\n return hour12;\n },\n //some ambiguity here with 12/24h\n time: function time(str) {\n if (str !== undefined) {\n var s = this.clone();\n str = str.toLowerCase().trim();\n s.epoch = set.time(s, str);\n return s;\n }\n\n return \"\".concat(this.h12(), \":\").concat(fns.zeroPad(this.minute())).concat(this.ampm());\n },\n // either 'am' or 'pm'\n ampm: function ampm(input) {\n var which = 'am';\n var hour = this.hour();\n\n if (hour >= 12) {\n which = 'pm';\n }\n\n if (typeof input !== 'string') {\n return which;\n } //okay, we're doing a setter\n\n\n var s = this.clone();\n input = input.toLowerCase().trim(); //ampm should never change the day\n // - so use `.hour(n)` instead of `.minus(12,'hour')`\n\n if (hour >= 12 && input === 'am') {\n //noon is 12pm\n hour -= 12;\n return s.hour(hour);\n }\n\n if (hour < 12 && input === 'pm') {\n hour += 12;\n return s.hour(hour);\n }\n\n return s;\n },\n //some hard-coded times of day, like 'noon'\n dayTime: function dayTime(str) {\n if (str !== undefined) {\n var times = {\n morning: '7:00am',\n breakfast: '7:00am',\n noon: '12:00am',\n lunch: '12:00pm',\n afternoon: '2:00pm',\n evening: '6:00pm',\n dinner: '6:00pm',\n night: '11:00pm',\n midnight: '23:59pm'\n };\n var s = this.clone();\n str = str || '';\n str = str.toLowerCase();\n\n if (times.hasOwnProperty(str) === true) {\n s = s.time(times[str]);\n }\n\n return s;\n }\n\n var h = this.hour();\n\n if (h < 6) {\n return 'night';\n }\n\n if (h < 12) {\n //until noon\n return 'morning';\n }\n\n if (h < 17) {\n //until 5pm\n return 'afternoon';\n }\n\n if (h < 22) {\n //until 10pm\n return 'evening';\n }\n\n return 'night';\n },\n //parse a proper iso string\n iso: function iso(num) {\n if (num !== undefined) {\n return this.set(num);\n }\n\n return this.format('iso');\n }\n };\n var _01Time = methods$1;\n\n var methods$2 = {\n // # day in the month\n date: function date(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.date(s, num);\n return s;\n }\n\n return this.d.getDate();\n },\n //like 'wednesday' (hard!)\n day: function day(input) {\n if (input === undefined) {\n return this.d.getDay();\n }\n\n var original = this.clone();\n var want = input; // accept 'wednesday'\n\n if (typeof input === 'string') {\n input = input.toLowerCase();\n\n if (days.aliases.hasOwnProperty(input)) {\n want = days.aliases[input];\n } else {\n want = days[\"short\"]().indexOf(input);\n\n if (want === -1) {\n want = days[\"long\"]().indexOf(input);\n }\n }\n } //move approx\n\n\n var day = this.d.getDay();\n var diff = day - want;\n var s = this.subtract(diff, 'days'); //tighten it back up\n\n walk_1(s, {\n hour: original.hour(),\n minute: original.minute(),\n second: original.second()\n });\n return s;\n },\n //these are helpful name-wrappers\n dayName: function dayName(input) {\n if (input === undefined) {\n return days[\"long\"]()[this.day()];\n }\n\n var s = this.clone();\n s = s.day(input);\n return s;\n },\n //either name or number\n month: function month(input) {\n if (input !== undefined) {\n var s = this.clone();\n s.epoch = set.month(s, input);\n return s;\n }\n\n return this.d.getMonth();\n }\n };\n var _02Date = methods$2;\n\n var clearMinutes = function clearMinutes(s) {\n s = s.minute(0);\n s = s.second(0);\n s = s.millisecond(1);\n return s;\n };\n\n var methods$3 = {\n // day 0-366\n dayOfYear: function dayOfYear(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.dayOfYear(s, num);\n return s;\n } //days since newyears - jan 1st is 1, jan 2nd is 2...\n\n\n var sum = 0;\n var month = this.d.getMonth();\n var tmp; //count the num days in each month\n\n for (var i = 1; i <= month; i++) {\n tmp = new Date();\n tmp.setDate(1);\n tmp.setFullYear(this.d.getFullYear()); //the year matters, because leap-years\n\n tmp.setHours(1);\n tmp.setMinutes(1);\n tmp.setMonth(i);\n tmp.setHours(-2); //the last day of the month\n\n sum += tmp.getDate();\n }\n\n return sum + this.d.getDate();\n },\n //since the start of the year\n week: function week(num) {\n // week-setter\n if (num !== undefined) {\n var s = this.clone();\n s = s.month(0);\n s = s.date(1);\n s = s.day('monday');\n s = clearMinutes(s); //first week starts first Thurs in Jan\n // so mon dec 28th is 1st week\n // so mon dec 29th is not the week\n\n if (s.monthName() === 'december' && s.date() >= 28) {\n s = s.add(1, 'week');\n }\n\n num -= 1; //1-based\n\n s = s.add(num, 'weeks');\n return s;\n } //find-out which week it is\n\n\n var tmp = this.clone();\n tmp = tmp.month(0);\n tmp = tmp.date(1);\n tmp = clearMinutes(tmp);\n tmp = tmp.day('monday'); //don't go into last-year\n\n if (tmp.monthName() === 'december' && tmp.date() >= 28) {\n tmp = tmp.add(1, 'week');\n } // is first monday the 1st?\n\n\n var toAdd = 1;\n\n if (tmp.date() === 1) {\n toAdd = 0;\n }\n\n tmp = tmp.minus(1, 'second');\n var thisOne = this.epoch; //if the week technically hasn't started yet\n\n if (tmp.epoch > thisOne) {\n return 1;\n } //speed it up, if we can\n\n\n var i = 0;\n var skipWeeks = this.month() * 4;\n tmp.epoch += milliseconds.week * skipWeeks;\n i += skipWeeks;\n\n for (; i < 52; i++) {\n if (tmp.epoch > thisOne) {\n return i + toAdd;\n }\n\n tmp = tmp.add(1, 'week');\n }\n\n return 52;\n },\n //'january'\n monthName: function monthName(input) {\n if (input === undefined) {\n return months[\"long\"]()[this.month()];\n }\n\n var s = this.clone();\n s = s.month(input);\n return s;\n },\n //q1, q2, q3, q4\n quarter: function quarter(num) {\n if (num !== undefined) {\n if (typeof num === 'string') {\n num = num.replace(/^q/i, '');\n num = parseInt(num, 10);\n }\n\n if (quarters[num]) {\n var s = this.clone();\n var _month = quarters[num][0];\n s = s.month(_month);\n s = s.date(1);\n s = s.startOf('day');\n return s;\n }\n }\n\n var month = this.d.getMonth();\n\n for (var i = 1; i < quarters.length; i++) {\n if (month < quarters[i][0]) {\n return i - 1;\n }\n }\n\n return 4;\n },\n //spring, summer, winter, fall\n season: function season(input) {\n var hem = 'north';\n\n if (this.hemisphere() === 'South') {\n hem = 'south';\n }\n\n if (input !== undefined) {\n var s = this.clone();\n\n for (var i = 0; i < seasons[hem].length; i++) {\n if (input === seasons[hem][i][0]) {\n s = s.month(seasons[hem][i][1]);\n s = s.date(1);\n s = s.startOf('day');\n }\n }\n\n return s;\n }\n\n var month = this.d.getMonth();\n\n for (var _i = 0; _i < seasons[hem].length - 1; _i++) {\n if (month >= seasons[hem][_i][1] && month < seasons[hem][_i + 1][1]) {\n return seasons[hem][_i][0];\n }\n }\n\n return 'winter';\n },\n //the year number\n year: function year(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.year(s, num);\n return s;\n }\n\n return this.d.getFullYear();\n },\n //bc/ad years\n era: function era(str) {\n if (str !== undefined) {\n var s = this.clone();\n str = str.toLowerCase(); //TODO: there is no year-0AD i think. may have off-by-1 error here\n\n var year = s.d.getFullYear(); //make '1992' into 1992bc..\n\n if (str === 'bc' && year > 0) {\n s.epoch = set.year(s, year * -1);\n } //make '1992bc' into '1992'\n\n\n if (str === 'ad' && year < 0) {\n s.epoch = set.year(s, year * -1);\n }\n\n return s;\n }\n\n if (this.d.getFullYear() < 0) {\n return 'BC';\n }\n\n return 'AD';\n },\n // 2019 -> 2010\n decade: function decade(input) {\n if (input !== undefined) {\n input = String(input);\n input = input.replace(/([0-9])'?s$/, '$1'); //1950's\n\n input = input.replace(/([0-9])(th|rd|st|nd)/, '$1'); //fix ordinals\n\n if (!input) {\n console.warn('Spacetime: Invalid decade input');\n return this;\n } // assume 20th century?? for '70s'.\n\n\n if (input.length === 2 && /[0-9][0-9]/.test(input)) {\n input = '19' + input;\n }\n\n var year = Number(input);\n\n if (isNaN(year)) {\n return this;\n } // round it down to the decade\n\n\n year = Math.floor(year / 10) * 10;\n return this.year(year); //.startOf('decade')\n }\n\n return this.startOf('decade').year();\n },\n // 1950 -> 19+1\n century: function century(input) {\n if (input !== undefined) {\n if (typeof input === 'string') {\n input = input.replace(/([0-9])(th|rd|st|nd)/, '$1'); //fix ordinals\n\n input = input.replace(/([0-9]+) ?(b\\.?c\\.?|a\\.?d\\.?)/i, function (a, b, c) {\n if (c.match(/b\\.?c\\.?/i)) {\n b = '-' + b;\n }\n\n return b;\n });\n input = input.replace(/c$/, ''); //20thC\n }\n\n var year = Number(input);\n\n if (isNaN(input)) {\n console.warn('Spacetime: Invalid century input');\n return this;\n } // there is no century 0\n\n\n if (year === 0) {\n year = 1;\n }\n\n if (year >= 0) {\n year = (year - 1) * 100;\n } else {\n year = (year + 1) * 100;\n }\n\n return this.year(year);\n } // century getter\n\n\n var num = this.startOf('century').year();\n num = Math.floor(num / 100);\n\n if (num < 0) {\n return num - 1;\n }\n\n return num + 1;\n },\n // 2019 -> 2+1\n millenium: function millenium(input) {\n if (input !== undefined) {\n if (typeof input === 'string') {\n input = input.replace(/([0-9])(th|rd|st|nd)/, '$1'); //fix ordinals\n\n input = Number(input);\n\n if (isNaN(input)) {\n console.warn('Spacetime: Invalid millenium input');\n return this;\n }\n }\n\n if (input > 0) {\n input -= 1;\n }\n\n var year = input * 1000; // there is no year 0\n\n if (year === 0) {\n year = 1;\n }\n\n return this.year(year);\n } // get the current millenium\n\n\n var num = Math.floor(this.year() / 1000);\n\n if (num >= 0) {\n num += 1;\n }\n\n return num;\n }\n };\n var _03Year = methods$3;\n\n var methods$4 = Object.assign({}, _01Time, _02Date, _03Year); //aliases\n\n methods$4.milliseconds = methods$4.millisecond;\n methods$4.seconds = methods$4.second;\n methods$4.minutes = methods$4.minute;\n methods$4.hours = methods$4.hour;\n methods$4.hour24 = methods$4.hour;\n methods$4.h12 = methods$4.hour12;\n methods$4.h24 = methods$4.hour24;\n methods$4.days = methods$4.day;\n\n var addMethods = function addMethods(Space) {\n //hook the methods into prototype\n Object.keys(methods$4).forEach(function (k) {\n Space.prototype[k] = methods$4[k];\n });\n };\n\n var query = addMethods;\n\n var isLeapYear$2 = fns.isLeapYear;\n\n var getMonthLength = function getMonthLength(month, year) {\n if (month === 1 && isLeapYear$2(year)) {\n return 29;\n }\n\n return monthLengths_1[month];\n }; //month is the one thing we 'model/compute'\n //- because ms-shifting can be off by enough\n\n\n var rollMonth = function rollMonth(want, old) {\n //increment year\n if (want.month > 0) {\n var years = parseInt(want.month / 12, 10);\n want.year = old.year() + years;\n want.month = want.month % 12;\n } else if (want.month < 0) {\n //decrement year\n var _years = Math.floor(Math.abs(want.month) / 13, 10);\n\n _years = Math.abs(_years) + 1;\n want.year = old.year() - _years; //ignore extras\n\n want.month = want.month % 12;\n want.month = want.month + 12;\n\n if (want.month === 12) {\n want.month = 0;\n }\n }\n\n return want;\n }; // briefly support day=-2 (this does not need to be perfect.)\n\n\n var rollDaysDown = function rollDaysDown(want, old, sum) {\n want.year = old.year();\n want.month = old.month();\n var date = old.date();\n want.date = date - Math.abs(sum);\n\n while (want.date < 1) {\n want.month -= 1;\n\n if (want.month < 0) {\n want.month = 11;\n want.year -= 1;\n }\n\n var max = getMonthLength(want.month, want.year);\n want.date += max;\n }\n\n return want;\n }; // briefly support day=33 (this does not need to be perfect.)\n\n\n var rollDaysUp = function rollDaysUp(want, old, sum) {\n var year = old.year();\n var month = old.month();\n var max = getMonthLength(month, year);\n\n while (sum > max) {\n sum -= max;\n month += 1;\n\n if (month >= 12) {\n month -= 12;\n year += 1;\n }\n\n max = getMonthLength(month, year);\n }\n\n want.month = month;\n want.date = sum;\n return want;\n };\n\n var _model = {\n months: rollMonth,\n days: rollDaysUp,\n daysBack: rollDaysDown\n };\n\n // but briefly:\n // millisecond-math, and some post-processing covers most-things\n // we 'model' the calendar here only a little bit\n // and that usually works-out...\n\n var order$1 = ['millisecond', 'second', 'minute', 'hour', 'date', 'month'];\n var keep = {\n second: order$1.slice(0, 1),\n minute: order$1.slice(0, 2),\n quarterhour: order$1.slice(0, 2),\n hour: order$1.slice(0, 3),\n date: order$1.slice(0, 4),\n month: order$1.slice(0, 4),\n quarter: order$1.slice(0, 4),\n season: order$1.slice(0, 4),\n year: order$1,\n decade: order$1,\n century: order$1\n };\n keep.week = keep.hour;\n keep.season = keep.date;\n keep.quarter = keep.date; // Units need to be dst adjuested\n\n var dstAwareUnits = {\n year: true,\n quarter: true,\n season: true,\n month: true,\n week: true,\n day: true\n };\n var keepDate = {\n month: true,\n quarter: true,\n season: true,\n year: true\n };\n\n var addMethods$1 = function addMethods(SpaceTime) {\n SpaceTime.prototype.add = function (num, unit) {\n var s = this.clone();\n\n if (!unit || num === 0) {\n return s; //don't bother\n }\n\n var old = this.clone();\n unit = fns.normalize(unit);\n\n if (unit === 'millisecond') {\n s.epoch += num;\n return s;\n } // support 'fortnight' alias\n\n\n if (unit === 'fortnight') {\n num *= 2;\n unit = 'week';\n } //move forward by the estimated milliseconds (rough)\n\n\n if (milliseconds[unit]) {\n s.epoch += milliseconds[unit] * num;\n } else if (unit === 'week') {\n s.epoch += milliseconds.day * (num * 7);\n } else if (unit === 'quarter' || unit === 'season') {\n s.epoch += milliseconds.month * (num * 3);\n } else if (unit === 'quarterhour') {\n s.epoch += milliseconds.minute * 15 * num;\n } //now ensure our milliseconds/etc are in-line\n\n\n var want = {};\n\n if (keep[unit]) {\n keep[unit].forEach(function (u) {\n want[u] = old[u]();\n });\n }\n\n if (dstAwareUnits[unit]) {\n var diff = old.timezone().current.offset - s.timezone().current.offset;\n s.epoch += diff * 3600 * 1000;\n } //ensure month/year has ticked-over\n\n\n if (unit === 'month') {\n want.month = old.month() + num; //month is the one unit we 'model' directly\n\n want = _model.months(want, old);\n } //support coercing a week, too\n\n\n if (unit === 'week') {\n var sum = old.date() + num * 7;\n\n if (sum <= 28 && sum > 1) {\n want.date = sum;\n }\n } //support 25-hour day-changes on dst-changes\n else if (unit === 'date') {\n if (num < 0) {\n want = _model.daysBack(want, old, num);\n } else {\n //specify a naive date number, if it's easy to do...\n var _sum = old.date() + num; // ok, model this one too\n\n\n want = _model.days(want, old, _sum);\n } //manually punt it if we haven't moved at all..\n\n\n if (num !== 0 && old.isSame(s, 'day')) {\n want.date = old.date() + num;\n }\n } // ensure a quarter is 3 months over\n else if (unit === 'quarter') {\n want.month = old.month() + num * 3;\n want.year = old.year(); // handle rollover\n\n if (want.month < 0) {\n var years = Math.floor(want.month / 12);\n var remainder = want.month + Math.abs(years) * 12;\n want.month = remainder;\n want.year += years;\n } else if (want.month >= 12) {\n var _years = Math.floor(want.month / 12);\n\n want.month = want.month % 12;\n want.year += _years;\n }\n\n want.date = old.date();\n } //ensure year has changed (leap-years)\n else if (unit === 'year') {\n var wantYear = old.year() + num;\n var haveYear = s.year();\n\n if (haveYear < wantYear) {\n s.epoch += milliseconds.day;\n } else if (haveYear > wantYear) {\n s.epoch += milliseconds.day;\n }\n } //these are easier\n else if (unit === 'decade') {\n want.year = s.year() + 10;\n } else if (unit === 'century') {\n want.year = s.year() + 100;\n } //keep current date, unless the month doesn't have it.\n\n\n if (keepDate[unit]) {\n var max = monthLengths_1[want.month];\n want.date = old.date();\n\n if (want.date > max) {\n want.date = max;\n }\n }\n\n if (Object.keys(want).length > 1) {\n walk_1(s, want);\n }\n\n return s;\n }; //subtract is only add *-1\n\n\n SpaceTime.prototype.subtract = function (num, unit) {\n var s = this.clone();\n return s.add(num * -1, unit);\n }; //add aliases\n\n\n SpaceTime.prototype.minus = SpaceTime.prototype.subtract;\n SpaceTime.prototype.plus = SpaceTime.prototype.add;\n };\n\n var add = addMethods$1;\n\n //make a string, for easy comparison between dates\n var print = {\n millisecond: function millisecond(s) {\n return s.epoch;\n },\n second: function second(s) {\n return [s.year(), s.month(), s.date(), s.hour(), s.minute(), s.second()].join('-');\n },\n minute: function minute(s) {\n return [s.year(), s.month(), s.date(), s.hour(), s.minute()].join('-');\n },\n hour: function hour(s) {\n return [s.year(), s.month(), s.date(), s.hour()].join('-');\n },\n day: function day(s) {\n return [s.year(), s.month(), s.date()].join('-');\n },\n week: function week(s) {\n return [s.year(), s.week()].join('-');\n },\n month: function month(s) {\n return [s.year(), s.month()].join('-');\n },\n quarter: function quarter(s) {\n return [s.year(), s.quarter()].join('-');\n },\n year: function year(s) {\n return s.year();\n }\n };\n print.date = print.day;\n\n var addMethods$2 = function addMethods(SpaceTime) {\n SpaceTime.prototype.isSame = function (b, unit) {\n var tzAware = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n var a = this;\n\n if (!unit) {\n return null;\n }\n\n if (typeof b === 'string' || typeof b === 'number') {\n b = new SpaceTime(b, this.timezone.name);\n } //support 'seconds' aswell as 'second'\n\n\n unit = unit.replace(/s$/, ''); // make them the same timezone for proper comparison\n\n if (tzAware === true && a.tz !== b.tz) {\n b = b.clone();\n b.tz = a.tz;\n }\n\n if (print[unit]) {\n return print[unit](a) === print[unit](b);\n }\n\n return null;\n };\n };\n\n var same = addMethods$2;\n\n var addMethods$3 = function addMethods(SpaceTime) {\n var methods = {\n isAfter: function isAfter(d) {\n d = fns.beADate(d, this);\n var epoch = fns.getEpoch(d);\n\n if (epoch === null) {\n return null;\n }\n\n return this.epoch > epoch;\n },\n isBefore: function isBefore(d) {\n d = fns.beADate(d, this);\n var epoch = fns.getEpoch(d);\n\n if (epoch === null) {\n return null;\n }\n\n return this.epoch < epoch;\n },\n isEqual: function isEqual(d) {\n d = fns.beADate(d, this);\n var epoch = fns.getEpoch(d);\n\n if (epoch === null) {\n return null;\n }\n\n return this.epoch === epoch;\n },\n isBetween: function isBetween(start, end) {\n var isInclusive = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n start = fns.beADate(start, this);\n end = fns.beADate(end, this);\n var startEpoch = fns.getEpoch(start);\n\n if (startEpoch === null) {\n return null;\n }\n\n var endEpoch = fns.getEpoch(end);\n\n if (endEpoch === null) {\n return null;\n }\n\n if (isInclusive) {\n return this.isBetween(start, end) || this.isEqual(start) || this.isEqual(end);\n }\n\n return startEpoch < this.epoch && this.epoch < endEpoch;\n }\n }; //hook them into proto\n\n Object.keys(methods).forEach(function (k) {\n SpaceTime.prototype[k] = methods[k];\n });\n };\n\n var compare = addMethods$3;\n\n var addMethods$4 = function addMethods(SpaceTime) {\n var methods = {\n i18n: function i18n(data) {\n //change the day names\n if (fns.isObject(data.days)) {\n days.set(data.days);\n } //change the month names\n\n\n if (fns.isObject(data.months)) {\n months.set(data.months);\n } // change the the display style of the month / day names\n\n\n if (fns.isBoolean(data.useTitleCase)) {\n caseFormat.set(data.useTitleCase);\n }\n }\n }; //hook them into proto\n\n Object.keys(methods).forEach(function (k) {\n SpaceTime.prototype[k] = methods[k];\n });\n };\n\n var i18n = addMethods$4;\n\n var timezones = unpack; //fake timezone-support, for fakers (es5 class)\n\n var SpaceTime = function SpaceTime(input$1, tz) {\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n //the holy moment\n this.epoch = null; //the shift for the given timezone\n\n this.tz = find(tz, timezones); //whether to output warnings to console\n\n this.silent = options.silent || true; // favour british interpretation of 02/02/2018, etc\n\n this.british = options.dmy || options.british; //does the week start on sunday, or monday:\n\n this._weekStart = 1; //default to monday\n\n if (options.weekStart !== undefined) {\n this._weekStart = options.weekStart;\n } // the reference today date object, (for testing)\n\n\n this._today = {};\n\n if (options.today !== undefined) {\n this._today = options.today;\n } //add getter/setters\n\n\n Object.defineProperty(this, 'd', {\n //return a js date object\n get: function get() {\n var offset = quick(this); //every computer is somewhere- get this computer's built-in offset\n\n var bias = new Date(this.epoch).getTimezoneOffset() || 0; //movement\n\n var shift = bias + offset * 60; //in minutes\n\n shift = shift * 60 * 1000; //in ms\n //remove this computer's offset\n\n var epoch = this.epoch + shift;\n var d = new Date(epoch);\n return d;\n }\n }); //add this data on the object, to allow adding new timezones\n\n Object.defineProperty(this, 'timezones', {\n get: function get() {\n return timezones;\n },\n set: function set(obj) {\n timezones = obj;\n return obj;\n }\n }); //parse the various formats\n\n var tmp = input(this, input$1, tz);\n this.epoch = tmp.epoch;\n }; //(add instance methods to prototype)\n\n\n Object.keys(methods_1).forEach(function (k) {\n SpaceTime.prototype[k] = methods_1[k];\n }); // ¯\\_(ツ)_/¯\n\n SpaceTime.prototype.clone = function () {\n return new SpaceTime(this.epoch, this.tz, {\n silent: this.silent,\n weekStart: this._weekStart,\n today: this._today\n });\n }; //return native date object at the same epoch\n\n\n SpaceTime.prototype.toLocalDate = function () {\n return new Date(this.epoch);\n }; //append more methods\n\n\n query(SpaceTime);\n add(SpaceTime);\n same(SpaceTime);\n compare(SpaceTime);\n i18n(SpaceTime);\n var spacetime = SpaceTime;\n\n var whereIts = function whereIts(a, b) {\n var start = new spacetime(null);\n var end = new spacetime(null);\n start = start.time(a); //if b is undefined, use as 'within one hour'\n\n if (b) {\n end = end.time(b);\n } else {\n end = start.add(59, 'minutes');\n }\n\n var startHour = start.hour();\n var endHour = end.hour();\n var tzs = Object.keys(start.timezones).filter(function (tz) {\n if (tz.indexOf('/') === -1) {\n return false;\n }\n\n var m = new spacetime(null, tz);\n var hour = m.hour(); //do 'calendar-compare' not real-time-compare\n\n if (hour >= startHour && hour <= endHour) {\n //test minutes too, if applicable\n if (hour === startHour && m.minute() < start.minute()) {\n return false;\n }\n\n if (hour === endHour && m.minute() > end.minute()) {\n return false;\n }\n\n return true;\n }\n\n return false;\n });\n return tzs;\n };\n\n var whereIts_1 = whereIts;\n\n var _version = '6.12.5';\n\n var main$1 = function main(input, tz, options) {\n return new spacetime(input, tz, options);\n }; // set all properties of a given 'today' object\n\n\n var setToday = function setToday(s) {\n var today = s._today || {};\n Object.keys(today).forEach(function (k) {\n s = s[k](today[k]);\n });\n return s;\n }; //some helper functions on the main method\n\n\n main$1.now = function (tz, options) {\n var s = new spacetime(new Date().getTime(), tz, options);\n s = setToday(s);\n return s;\n };\n\n main$1.today = function (tz, options) {\n var s = new spacetime(new Date().getTime(), tz, options);\n s = setToday(s);\n return s.startOf('day');\n };\n\n main$1.tomorrow = function (tz, options) {\n var s = new spacetime(new Date().getTime(), tz, options);\n s = setToday(s);\n return s.add(1, 'day').startOf('day');\n };\n\n main$1.yesterday = function (tz, options) {\n var s = new spacetime(new Date().getTime(), tz, options);\n s = setToday(s);\n return s.subtract(1, 'day').startOf('day');\n };\n\n main$1.extend = function (obj) {\n Object.keys(obj).forEach(function (k) {\n spacetime.prototype[k] = obj[k];\n });\n return this;\n };\n\n main$1.timezones = function () {\n var s = new spacetime();\n return s.timezones;\n }; //find tz by time\n\n\n main$1.whereIts = whereIts_1;\n main$1.version = _version; //aliases:\n\n main$1.plugin = main$1.extend;\n var src = main$1;\n\n return src;\n\n})));\n","// some opinionated-but-common-sense timezone abbreviations\n// these timezone abbreviations are wholly made-up by me, Spencer Kelly, with no expertise in geography\n// generated humbly from https://github.com/spencermountain/spacetime-informal\nconst spacetime = require('spacetime')\n\nconst america = 'America/'\nconst asia = 'Asia/'\nconst europe = 'Europe/'\nconst africa = 'Africa/'\nconst aus = 'Australia/'\nconst pac = 'Pacific/'\n\nconst informal = {\n //europe\n 'british summer time': europe + 'London',\n bst: europe + 'London',\n 'british time': europe + 'London',\n 'britain time': europe + 'London',\n 'irish summer time': europe + 'Dublin',\n 'irish time': europe + 'Dublin',\n ireland: europe + 'Dublin',\n 'central european time': europe + 'Berlin',\n cet: europe + 'Berlin',\n 'central european summer time': europe + 'Berlin',\n cest: europe + 'Berlin',\n 'central europe': europe + 'Berlin',\n 'eastern european time': europe + 'Riga',\n eet: europe + 'Riga',\n 'eastern european summer time': europe + 'Riga',\n eest: europe + 'Riga',\n 'eastern europe time': europe + 'Riga',\n 'western european time': europe + 'Lisbon',\n // wet: europe+'Lisbon',\n 'western european summer time': europe + 'Lisbon',\n // west: europe+'Lisbon',\n 'western europe': europe + 'Lisbon',\n 'turkey standard time': europe + 'Istanbul',\n trt: europe + 'Istanbul',\n 'turkish time': europe + 'Istanbul',\n\n //africa\n etc: africa + 'Freetown',\n utc: africa + 'Freetown',\n 'greenwich standard time': africa + 'Freetown',\n gmt: africa + 'Freetown',\n 'east africa time': africa + 'Nairobi',\n // eat: africa+'Nairobi',\n 'east african time': africa + 'Nairobi',\n 'eastern africa time': africa + 'Nairobi',\n 'central africa time': africa + 'Khartoum',\n // cat: africa+'Khartoum',\n 'central african time': africa + 'Khartoum',\n 'south africa standard time': africa + 'Johannesburg',\n sast: africa + 'Johannesburg',\n 'southern africa': africa + 'Johannesburg',\n 'south african': africa + 'Johannesburg',\n 'west africa standard time': africa + 'Lagos',\n // wat: africa+'Lagos',\n 'western africa time': africa + 'Lagos',\n 'west african time': africa + 'Lagos',\n\n 'australian central standard time': aus + 'Adelaide',\n acst: aus + 'Adelaide',\n 'australian central daylight time': aus + 'Adelaide',\n acdt: aus + 'Adelaide',\n 'australia central': aus + 'Adelaide',\n 'australian eastern standard time': aus + 'Brisbane',\n aest: aus + 'Brisbane',\n 'australian eastern daylight time': aus + 'Brisbane',\n aedt: aus + 'Brisbane',\n 'australia east': aus + 'Brisbane',\n 'australian western standard time': aus + 'Perth',\n awst: aus + 'Perth',\n 'australian western daylight time': aus + 'Perth',\n awdt: aus + 'Perth',\n 'australia west': aus + 'Perth',\n 'australian central western standard time': aus + 'Eucla',\n acwst: aus + 'Eucla',\n 'australia central west': aus + 'Eucla',\n 'lord howe standard time': aus + 'Lord_Howe',\n lhst: aus + 'Lord_Howe',\n 'lord howe daylight time': aus + 'Lord_Howe',\n lhdt: aus + 'Lord_Howe',\n 'russian standard time': europe + 'Moscow',\n msk: europe + 'Moscow',\n russian: europe + 'Moscow',\n\n //america\n 'central standard time': america + 'Chicago',\n 'central time': america + 'Chicago',\n cst: america + 'Havana',\n 'central daylight time': america + 'Chicago',\n cdt: america + 'Havana',\n 'mountain standard time': america + 'Denver',\n 'mountain time': america + 'Denver',\n mst: america + 'Denver',\n 'mountain daylight time': america + 'Denver',\n mdt: america + 'Denver',\n 'atlantic standard time': america + 'Halifax',\n 'atlantic time': america + 'Halifax',\n ast: asia + 'Baghdad',\n 'atlantic daylight time': america + 'Halifax',\n adt: america + 'Halifax',\n 'eastern standard time': america + 'New_York',\n 'eastern time': america + 'New_York',\n est: america + 'New_York',\n 'eastern daylight time': america + 'New_York',\n edt: america + 'New_York',\n 'pacific time': america + 'Los_Angeles',\n 'pacific standard time': america + 'Los_Angeles',\n pst: america + 'Los_Angeles',\n 'pacific daylight time': america + 'Los_Angeles',\n pdt: america + 'Los_Angeles',\n 'alaskan standard time': america + 'Anchorage',\n 'alaskan time': america + 'Anchorage',\n ahst: america + 'Anchorage',\n 'alaskan daylight time': america + 'Anchorage',\n ahdt: america + 'Anchorage',\n 'hawaiian standard time': pac + 'Honolulu',\n 'hawaiian time': pac + 'Honolulu',\n hst: pac + 'Honolulu',\n 'aleutian time': pac + 'Honolulu',\n 'hawaii time': pac + 'Honolulu',\n 'newfoundland standard time': america + 'St_Johns',\n 'newfoundland time': america + 'St_Johns',\n nst: america + 'St_Johns',\n 'newfoundland daylight time': america + 'St_Johns',\n ndt: america + 'St_Johns',\n 'brazil time': america + 'Sao_Paulo',\n brt: america + 'Sao_Paulo',\n brasília: america + 'Sao_Paulo',\n brasilia: america + 'Sao_Paulo',\n 'brazilian time': america + 'Sao_Paulo',\n 'argentina time': america + 'Buenos_Aires',\n // art: a+'Buenos_Aires',\n 'argentinian time': america + 'Buenos_Aires',\n 'amazon time': america + 'Manaus',\n amt: america + 'Manaus',\n 'amazonian time': america + 'Manaus',\n 'easter island standard time': 'Chile/Easterisland',\n east: 'Chile/Easterisland',\n 'easter island summer time': 'Chile/Easterisland',\n easst: 'Chile/Easterisland',\n 'venezuelan standard time': america + 'Caracas',\n 'venezuelan time': america + 'Caracas',\n vet: america + 'Caracas',\n 'venezuela time': america + 'Caracas',\n 'paraguay time': america + 'Asuncion',\n pyt: america + 'Asuncion',\n 'paraguay summer time': america + 'Asuncion',\n pyst: america + 'Asuncion',\n 'cuba standard time': america + 'Havana',\n 'cuba time': america + 'Havana',\n 'cuba daylight time': america + 'Havana',\n 'cuban time': america + 'Havana',\n 'bolivia time': america + 'La_Paz',\n // bot: a+'La_Paz',\n 'bolivian time': america + 'La_Paz',\n 'colombia time': america + 'Bogota',\n cot: america + 'Bogota',\n 'colombian time': america + 'Bogota',\n 'acre time': america + 'Eirunepe',\n // act: a+'Eirunepe',\n 'peru time': america + 'Lima',\n // pet: a+'Lima',\n 'chile standard time': america + 'Punta_Arenas',\n 'chile time': america + 'Punta_Arenas',\n clst: america + 'Punta_Arenas',\n 'chile summer time': america + 'Punta_Arenas',\n cldt: america + 'Punta_Arenas',\n 'uruguay time': america + 'Montevideo',\n uyt: america + 'Montevideo',\n\n //asia\n ist: asia + 'Jerusalem',\n 'arabic standard time': asia + 'Baghdad',\n 'arabic time': asia + 'Baghdad',\n 'arab time': asia + 'Baghdad',\n 'iran standard time': asia + 'Tehran',\n 'iran time': asia + 'Tehran',\n irst: asia + 'Tehran',\n 'iran daylight time': asia + 'Tehran',\n irdt: asia + 'Tehran',\n iranian: asia + 'Tehran',\n 'pakistan standard time': asia + 'Karachi',\n 'pakistan time': asia + 'Karachi',\n pkt: asia + 'Karachi',\n 'india standard time': asia + 'Kolkata',\n 'indian time': asia + 'Kolkata',\n 'indochina time': asia + 'Bangkok',\n ict: asia + 'Bangkok',\n 'south east asia': asia + 'Bangkok',\n 'china standard time': asia + 'Shanghai',\n ct: asia + 'Shanghai',\n 'chinese time': asia + 'Shanghai',\n 'alma-ata time': asia + 'Almaty',\n almt: asia + 'Almaty',\n 'oral time': asia + 'Oral',\n 'orat time': asia + 'Oral',\n 'yakutsk time': asia + 'Yakutsk',\n yakt: asia + 'Yakutsk',\n 'gulf standard time': asia + 'Dubai',\n 'gulf time': asia + 'Dubai',\n gst: asia + 'Dubai',\n uae: asia + 'Dubai',\n 'hong kong time': asia + 'Hong_Kong',\n hkt: asia + 'Hong_Kong',\n 'western indonesian time': asia + 'Jakarta',\n wib: asia + 'Jakarta',\n 'indonesia time': asia + 'Jakarta',\n 'central indonesian time': asia + 'Makassar',\n wita: asia + 'Makassar',\n 'israel daylight time': asia + 'Jerusalem',\n idt: asia + 'Jerusalem',\n 'israel standard time': asia + 'Jerusalem',\n 'israel time': asia + 'Jerusalem',\n israeli: asia + 'Jerusalem',\n 'krasnoyarsk time': asia + 'Krasnoyarsk',\n krat: asia + 'Krasnoyarsk',\n 'malaysia time': asia + 'Kuala_Lumpur',\n myt: asia + 'Kuala_Lumpur',\n 'singapore time': asia + 'Singapore',\n sgt: asia + 'Singapore',\n 'korea standard time': asia + 'Seoul',\n 'korea time': asia + 'Seoul',\n kst: asia + 'Seoul',\n 'korean time': asia + 'Seoul',\n 'uzbekistan time': asia + 'Samarkand',\n uzt: asia + 'Samarkand',\n 'vladivostok time': asia + 'Vladivostok',\n vlat: asia + 'Vladivostok',\n\n //indian\n 'maldives time': 'Indian/Maldives',\n mvt: 'Indian/Maldives',\n 'mauritius time': 'Indian/Mauritius',\n mut: 'Indian/Mauritius',\n\n // pacific\n 'marshall islands time': pac + 'Kwajalein',\n mht: pac + 'Kwajalein',\n 'samoa standard time': pac + 'Midway',\n sst: pac + 'Midway',\n 'somoan time': pac + 'Midway',\n 'chamorro standard time': pac + 'Guam',\n chst: pac + 'Guam',\n 'papua new guinea time': pac + 'Bougainville',\n pgt: pac + 'Bougainville',\n}\n\n//add the official iana zonefile names\nlet iana = spacetime().timezones\nlet formal = Object.keys(iana).reduce((h, k) => {\n h[k] = k\n return h\n}, {})\nmodule.exports = Object.assign({}, informal, formal)\n","module.exports = [\n 'weekday',\n\n 'summer',\n 'winter',\n 'autumn',\n\n 'some day',\n 'one day',\n 'all day',\n 'some point',\n\n 'eod',\n 'eom',\n 'eoy',\n 'standard time',\n 'daylight time',\n 'tommorrow',\n]\n","module.exports = [\n 'centuries',\n 'century',\n 'day',\n 'days',\n 'decade',\n 'decades',\n 'hour',\n 'hours',\n 'hr',\n 'hrs',\n 'millisecond',\n 'milliseconds',\n 'minute',\n 'minutes',\n 'min',\n 'mins',\n 'month',\n 'months',\n 'seconds',\n 'sec',\n 'secs',\n 'week end',\n 'week ends',\n 'weekend',\n 'weekends',\n 'week',\n 'weeks',\n 'wk',\n 'wks',\n 'year',\n 'years',\n 'yr',\n 'yrs',\n 'quarter',\n // 'quarters',\n 'qtr',\n 'qtrs',\n 'season',\n 'seasons',\n]\n","module.exports = [\n 'all hallows eve',\n 'all saints day',\n 'all sts day',\n 'april fools',\n 'armistice day',\n 'australia day',\n 'bastille day',\n 'boxing day',\n 'canada day',\n 'christmas eve',\n 'christmas',\n 'cinco de mayo',\n 'day of the dead',\n 'dia de muertos',\n 'dieciseis de septiembre',\n 'emancipation day',\n 'grito de dolores',\n 'groundhog day',\n 'halloween',\n 'harvey milk day',\n 'inauguration day',\n 'independence day',\n 'independents day',\n 'juneteenth',\n 'labour day',\n 'national freedom day',\n 'national nurses day',\n 'new years eve',\n 'new years',\n 'purple heart day',\n 'rememberance day',\n 'rosa parks day',\n 'saint andrews day',\n 'saint patricks day',\n 'saint stephens day',\n 'saint valentines day',\n 'st andrews day',\n 'st patricks day',\n 'st stephens day',\n 'st valentines day ',\n 'valentines day',\n 'valentines',\n 'veterans day',\n 'victoria day',\n 'womens equality day',\n 'xmas',\n // Fixed religious and cultural holidays\n // Catholic + Christian\n 'epiphany',\n 'orthodox christmas day',\n 'orthodox new year',\n 'assumption of mary',\n 'all souls day',\n 'feast of the immaculate conception',\n 'feast of our lady of guadalupe',\n\n // Kwanzaa\n 'kwanzaa',\n // Pagan / metal 🤘\n 'imbolc',\n 'beltaine',\n 'lughnassadh',\n 'samhain',\n 'martin luther king day',\n 'mlk day',\n 'presidents day',\n 'mardi gras',\n 'tax day',\n 'commonwealth day',\n 'mothers day',\n 'memorial day',\n 'fathers day',\n 'columbus day',\n 'indigenous peoples day',\n 'canadian thanksgiving',\n 'election day',\n 'thanksgiving',\n 't-day',\n 'turkey day',\n 'black friday',\n 'cyber monday',\n // Astronomical religious and cultural holidays\n 'ash wednesday',\n 'palm sunday',\n 'maundy thursday',\n 'good friday',\n 'holy saturday',\n 'easter',\n 'easter sunday',\n 'easter monday',\n 'orthodox good friday',\n 'orthodox holy saturday',\n 'orthodox easter',\n 'orthodox easter monday',\n 'ascension day',\n 'pentecost',\n 'whitsunday',\n 'whit sunday',\n 'whit monday',\n 'trinity sunday',\n 'corpus christi',\n 'advent',\n // Jewish\n 'tu bishvat',\n 'tu bshevat',\n 'purim',\n 'passover',\n 'yom hashoah',\n 'lag baomer',\n 'shavuot',\n 'tisha bav',\n 'rosh hashana',\n 'yom kippur',\n 'sukkot',\n 'shmini atzeret',\n 'simchat torah',\n 'chanukah',\n 'hanukkah',\n // Muslim\n 'isra and miraj',\n 'lailat al-qadr',\n 'eid al-fitr',\n 'id al-Fitr',\n 'eid ul-Fitr',\n 'ramadan',\n 'eid al-adha',\n 'muharram',\n 'the prophets birthday',\n 'ostara',\n 'march equinox',\n 'vernal equinox',\n 'litha',\n 'june solistice',\n 'summer solistice',\n 'mabon',\n 'september equinox',\n 'fall equinox',\n 'autumnal equinox',\n 'yule',\n 'december solstice',\n 'winter solstice',\n // Additional important holidays\n 'chinese new year',\n 'diwali',\n]\n","module.exports = [\n 'noon',\n 'midnight',\n 'now',\n 'morning',\n 'tonight',\n 'evening',\n 'afternoon',\n 'night',\n 'breakfast time',\n 'lunchtime',\n 'dinnertime',\n 'sometime',\n 'midday',\n 'eod',\n 'oclock',\n 'oclock',\n 'all day',\n 'at night',\n]\n","const timezones = require('../_timezones')\nconst data = [\n [require('./dates'), '#Date'],\n [require('./durations'), '#Duration'],\n [require('./holidays'), '#Holiday'],\n [require('./times'), '#Time'],\n [Object.keys(timezones), '#Timezone'],\n]\nlet lex = {\n 'a couple': 'Value',\n}\ndata.forEach((a) => {\n for (let i = 0; i < a[0].length; i++) {\n lex[a[0][i]] = a[1]\n }\n})\n\nmodule.exports = lex\n","const spacetime = require('spacetime')\n\nclass Unit {\n constructor(input, unit, context) {\n this.unit = unit || 'day'\n context = context || {}\n let today = {}\n if (context.today) {\n today = {\n date: context.today.date(),\n month: context.today.month(),\n year: context.today.year(),\n }\n }\n // set it to the beginning of the given unit\n let d = spacetime(input, context.timezone, { today: today })\n\n // set to beginning?\n // if (d.isValid() && keepTime !== true) {\n // d = d.startOf(this.unit)\n // }\n Object.defineProperty(this, 'd', {\n enumerable: false,\n writable: true,\n value: d,\n })\n Object.defineProperty(this, 'context', {\n enumerable: false,\n writable: true,\n value: context,\n })\n }\n // make a new one\n clone() {\n let d = new Unit(this.d, this.unit, this.context)\n return d\n }\n log() {\n console.log('--')\n this.d.log()\n console.log('\\n')\n return this\n }\n applyShift(obj = {}) {\n Object.keys(obj).forEach((unit) => {\n this.d = this.d.add(obj[unit], unit)\n })\n return this\n }\n applyTime(str) {\n if (str) {\n this.d = this.d.time(str)\n } else {\n this.d = this.d.startOf('day') //zero-out time\n }\n return this\n }\n applyWeekDay(day) {\n if (day) {\n let epoch = this.d.epoch\n this.d = this.d.day(day)\n if (this.d.epoch < epoch) {\n this.d = this.d.add(1, 'week')\n }\n }\n return this\n }\n applyRel(rel) {\n if (rel === 'next') {\n return this.next()\n }\n if (rel === 'last') {\n return this.last()\n }\n return this\n }\n applySection(section) {\n if (section === 'start') {\n return this.start()\n }\n if (section === 'end') {\n return this.end()\n }\n if (section === 'middle') {\n return this.middle()\n }\n return this\n }\n format(fmt) {\n return this.d.format(fmt)\n }\n start() {\n this.d = this.d.startOf(this.unit)\n if (this.context.dayStart) {\n this.d = this.d.time(this.context.dayStart)\n }\n return this\n }\n end() {\n this.d = this.d.endOf(this.unit)\n if (this.context.dayEnd) {\n this.d = this.d.time(this.context.dayEnd)\n }\n return this\n }\n middle() {\n let diff = this.d.diff(this.d.endOf(this.unit))\n let minutes = Math.round(diff.minutes / 2)\n this.d = this.d.add(minutes, 'minutes')\n return this\n }\n // the millescond before\n before() {\n this.d = this.d.minus(1, this.unit)\n this.d = this.d.endOf(this.unit)\n if (this.context.dayEnd) {\n this.d = this.d.time(this.context.dayEnd)\n }\n return this\n }\n // 'after 2019'\n after() {\n this.d = this.d.add(1, this.unit)\n this.d = this.d.startOf(this.unit)\n return this\n }\n // tricky: 'next june' 'next tuesday'\n next() {\n this.d = this.d.add(1, this.unit)\n this.d = this.d.startOf(this.unit)\n return this\n }\n // tricky: 'last june' 'last tuesday'\n last() {\n this.d = this.d.minus(1, this.unit)\n this.d = this.d.startOf(this.unit)\n return this\n }\n}\nmodule.exports = Unit\n","const spacetime = require('spacetime')\nconst Unit = require('./Unit')\n\nclass Day extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'day'\n if (this.d.isValid()) {\n this.d = this.d.startOf('day')\n }\n }\n}\n\n// like 'feb 2'\nclass CalendarDate extends Day {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'day'\n if (this.d.isValid()) {\n this.d = this.d.startOf('day')\n }\n }\n next() {\n this.d = this.d.add(1, 'year')\n return this\n }\n last() {\n this.d = this.d.minus(1, 'year')\n return this\n }\n}\n\nclass WeekDay extends Day {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'week'\n // is the input just a weekday?\n if (typeof input === 'string') {\n this.d = spacetime(context.today, context.timezone)\n this.d = this.d.day(input)\n // assume a wednesday in the future\n if (this.d.isBefore(context.today)) {\n this.d = this.d.add(7, 'days')\n }\n } else {\n this.d = input\n }\n this.weekDay = this.d.dayName()\n if (this.d.isValid()) {\n this.d = this.d.startOf('day')\n }\n }\n clone() {\n //overloaded method\n return new WeekDay(this.d, this.unit, this.context)\n }\n end() {\n //overloaded method\n this.d = this.d.endOf('day')\n if (this.context.dayEnd) {\n this.d = this.d.time(this.context.dayEnd)\n }\n return this\n }\n next() {\n this.d = this.d.add(7, 'days')\n this.d = this.d.day(this.weekDay)\n return this\n }\n last() {\n this.d = this.d.minus(7, 'days')\n this.d = this.d.day(this.weekDay)\n return this\n }\n}\n\n// like 'haloween'\nclass Holiday extends CalendarDate {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'day'\n if (this.d.isValid()) {\n this.d = this.d.startOf('day')\n }\n }\n}\n\nmodule.exports = {\n Day: Day,\n WeekDay: WeekDay,\n CalendarDate: CalendarDate,\n Holiday: Holiday,\n}\n","const Unit = require('./Unit')\n\n// a specific month, like 'March'\nclass AnyMonth extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'month'\n // set to beginning\n if (this.d.isValid()) {\n this.d = this.d.startOf(this.unit)\n }\n }\n}\n\n// a specific month, like 'March'\nclass Month extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'month'\n // set to beginning\n if (this.d.isValid()) {\n this.d = this.d.startOf(this.unit)\n }\n }\n next() {\n this.d = this.d.add(1, 'year')\n this.d = this.d.startOf('month')\n return this\n }\n last() {\n this.d = this.d.minus(1, 'year')\n this.d = this.d.startOf('month')\n return this\n }\n}\nclass AnyQuarter extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'quarter'\n // set to beginning\n if (this.d.isValid()) {\n this.d = this.d.startOf(this.unit)\n }\n }\n last() {\n this.d = this.d.minus(1, 'quarter')\n this.d = this.d.startOf(this.unit)\n return this\n }\n}\n\nclass Quarter extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'quarter'\n // set to beginning\n if (this.d.isValid()) {\n this.d = this.d.startOf(this.unit)\n }\n }\n next() {\n this.d = this.d.add(1, 'year')\n this.d = this.d.startOf(this.unit)\n return this\n }\n last() {\n this.d = this.d.minus(1, 'year')\n this.d = this.d.startOf(this.unit)\n return this\n }\n}\nclass Season extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'season'\n // set to beginning\n if (this.d.isValid()) {\n this.d = this.d.startOf(this.unit)\n }\n }\n next() {\n this.d = this.d.add(1, 'year')\n this.d = this.d.startOf(this.unit)\n return this\n }\n last() {\n this.d = this.d.minus(1, 'year')\n this.d = this.d.startOf(this.unit)\n return this\n }\n}\nclass Year extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'year'\n if (this.d.isValid()) {\n this.d = this.d.startOf('year')\n }\n }\n}\n\nmodule.exports = {\n AnyMonth: AnyMonth,\n Month: Month,\n Quarter: Quarter,\n AnyQuarter: AnyQuarter,\n Season: Season,\n Year: Year,\n}\n","const Unit = require('./Unit')\n\nclass Week extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'week'\n if (this.d.isValid()) {\n this.d = this.d.startOf('week')\n }\n }\n}\n\n//may need some work\nclass WeekEnd extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'week'\n if (this.d.isValid()) {\n this.d = this.d.day('saturday')\n this.d = this.d.startOf('day')\n }\n }\n start() {\n this.d = this.d.day('saturday').startOf('day')\n return this\n }\n // end() {\n // this.d = this.d.day('sunday').endOf('day')\n // return this\n // }\n next() {\n this.d = this.d.add(1, this.unit)\n this.d = this.d.startOf('weekend')\n return this\n }\n last() {\n this.d = this.d.minus(1, this.unit)\n this.d = this.d.startOf('weekend')\n return this\n }\n}\n\nmodule.exports = {\n Week: Week,\n WeekEnd: WeekEnd,\n}\n","const Unit = require('./Unit')\n\nclass Hour extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context, true)\n this.unit = 'hour'\n if (this.d.isValid()) {\n this.d = this.d.startOf('hour')\n }\n }\n}\nclass Minute extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context, true)\n this.unit = 'minute'\n if (this.d.isValid()) {\n this.d = this.d.startOf('minute')\n }\n }\n}\nclass Moment extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context, true)\n this.unit = 'millisecond'\n }\n}\n\nmodule.exports = {\n Hour: Hour,\n Minute: Minute,\n Moment: Moment,\n}\n","module.exports = Object.assign(\n { Unit: require('./Unit') },\n require('./_day'),\n require('./_year'),\n require('./_week'),\n require('./_time')\n)\n","const knownUnits = {\n second: true,\n minute: true,\n hour: true,\n day: true,\n week: true,\n weekend: true,\n month: true,\n season: true,\n quarter: true,\n year: true,\n}\n\nconst aliases = {\n wk: 'week',\n min: 'minute',\n sec: 'second',\n weekend: 'week', //for now...\n}\n\nconst parseUnit = function (m) {\n let unit = m.match('#Duration').text('normal')\n unit = unit.replace(/s$/, '')\n // support shorthands like 'min'\n if (aliases.hasOwnProperty(unit)) {\n unit = aliases[unit]\n }\n return unit\n}\n\n//turn '5 weeks before' to {weeks:5}\nconst parseShift = function (doc) {\n let result = {}\n let shift = doc.match('#DateShift+')\n if (shift.found === false) {\n return result\n }\n // '5 weeks'\n shift.match('#Cardinal #Duration').forEach((ts) => {\n let num = ts.match('#Cardinal').text('normal')\n num = parseFloat(num)\n if (num && typeof num === 'number') {\n let unit = parseUnit(ts)\n if (knownUnits[unit] === true) {\n result[unit] = num\n }\n }\n })\n //is it 2 weeks ago? → -2\n if (shift.has('(before|ago|hence|back)$') === true) {\n Object.keys(result).forEach((k) => (result[k] *= -1))\n }\n shift.remove('#Cardinal #Duration')\n // supoprt '1 day after tomorrow'\n let m = shift.match('[#Duration] [(after|before)]')\n if (m.found) {\n let unit = m.groups('unit').text('reduced')\n // unit = unit.replace(/s$/, '')\n let dir = m.groups('dir').text('reduced')\n if (dir === 'after') {\n result[unit] = 1\n } else if (dir === 'before') {\n result[unit] = -1\n }\n }\n // in half an hour\n m = shift.match('half (a|an) [#Duration]', 0)\n if (m.found) {\n let unit = parseUnit(m)\n result[unit] = 0.5\n }\n // finally, remove it from our text\n doc.remove('#DateShift')\n return result\n}\nmodule.exports = parseShift\n","/*\na 'counter' is a Unit determined after a point\n * first hour of x\n * 7th week in x\n * last year in x\n * \nunlike a shift, like \"2 weeks after x\"\n*/\nconst oneBased = {\n minute: true,\n}\nconst getCounter = function (doc) {\n // 7th week of\n let m = doc.match('[#Value] [#Duration+] (of|in)')\n if (m.found) {\n let obj = m.groups()\n let num = obj.num.text('reduced')\n let unit = obj.unit.text('reduced')\n let found = {\n unit: unit,\n num: Number(num) || 0,\n }\n // 0-based or 1-based units\n if (!oneBased[unit]) {\n found.num -= 1\n }\n doc = doc.remove(m)\n return found\n }\n // first week of\n m = doc.match('[(first|initial|last|final)] [#Duration+] (of|in)')\n if (m.found) {\n let obj = m.groups()\n let dir = obj.dir.text('reduced')\n let unit = obj.unit.text('reduced')\n if (dir === 'initial') {\n dir = 'first'\n }\n if (dir === 'final') {\n dir = 'last'\n }\n let found = {\n unit: unit,\n dir: dir,\n }\n doc = doc.remove(m)\n return found\n }\n\n return {}\n}\nmodule.exports = getCounter\n","const spacetime = require('spacetime')\n\nconst hardCoded = {\n daybreak: '7:00am', //ergh\n breakfast: '8:00am',\n morning: '9:00am',\n noon: '12:00pm',\n midday: '12:00pm',\n afternoon: '2:00pm',\n lunchtime: '12:00pm',\n evening: '6:00pm',\n dinnertime: '6:00pm',\n night: '8:00pm',\n eod: '10:00pm',\n midnight: '12:00am',\n}\n\nconst halfPast = function (m, s) {\n let hour = m.match('#Cardinal$').text('reduced')\n\n let term = m.match('(half|quarter|25|15|10|5)')\n let mins = term.text('reduced')\n if (term.has('half')) {\n mins = '30'\n }\n if (term.has('quarter')) {\n mins = '15'\n }\n let behind = m.has('to')\n // apply it\n s = s.hour(hour)\n s = s.startOf('hour')\n // assume 'half past 5' is 5pm\n if (hour < 6) {\n s = s.ampm('pm')\n }\n if (behind) {\n s = s.subtract(mins, 'minutes')\n } else {\n s = s.add(mins, 'minutes')\n }\n return s\n}\n\nconst parseTime = function (doc, context) {\n let time = doc.match('(at|by|for|before|this)? #Time+')\n if (time.found) {\n doc.remove(time)\n }\n // get the main part of the time\n time = time.not('^(at|by|for|before|this)')\n time = time.not('sharp')\n time = time.not('on the dot')\n let s = spacetime.now(context.timezone)\n let now = s.clone()\n\n // check for known-times (like 'today')\n let timeStr = time.text('reduced')\n if (hardCoded.hasOwnProperty(timeStr)) {\n return hardCoded[timeStr]\n }\n\n // '5 oclock'\n let m = time.match('^#Cardinal oclock (am|pm)?')\n if (m.found) {\n m = m.not('oclock')\n s = s.hour(m.text('reduced'))\n s = s.startOf('hour')\n if (s.isValid() && !s.isEqual(now)) {\n let ampm = m.match('(am|pm)').text('reduced')\n s = s.ampm(ampm)\n return s.time()\n }\n }\n\n // 'quarter to two'\n m = time.match('(half|quarter|25|15|10|5) (past|after|to) #Cardinal')\n if (m.found) {\n s = halfPast(m, s)\n if (s.isValid() && !s.isEqual(now)) {\n return s.time()\n }\n }\n // '4 in the evening'\n m = time.match('[
+ + + + + +
+ 1 - Regular-expressions are the wrong way to parse dates. +
+ +
+ 2 - Neural-nets are the wrong way to parse dates. +
+ +
+ 3 - A startup is the wrong place to build a universal date-parser. +
+ + + + + +Parsing *dates*, *times*, and *durations* from natural language can be a solved-problem. + +A rule-based, community open-source library - *one based on simple NLP* - is the best way to build a natural language date parser - commercial, or otherwise - for the frontend, or the backend. + +The *[match-syntax](https://observablehq.com/@spencermountain/compromise-match-syntax)* is effective and easy, *javascript* is prevailing, and the more people who contribute, the better. + + + ### See also * [Duckling](https://duckling.wit.ai/) - by wit.ai (facebook) * [Chronic](https://github.com/mojombo/chronic) - by Tom Preston-Werner (Ruby) diff --git a/plugins/dates/tmp.html b/plugins/dates/tmp.html new file mode 100644 index 000000000..812ba01d4 --- /dev/null +++ b/plugins/dates/tmp.html @@ -0,0 +1,102 @@ + + + + + +
+ +[two weeks and 4.5 days after] + punt + +[the 2nd monday of] + ordinal + +[this] + relative + +[feb] + root + +[at 2pm] + time + +[kabul time] + timezone + + +
+ + + \ No newline at end of file From df2c615a2060adbbfe0bf8facfac3c3bcc4a7bcd Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Wed, 24 Feb 2021 13:52:09 -0500 Subject: [PATCH 07/29] more readme improvements --- plugins/dates/README.md | 50 +++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/plugins/dates/README.md b/plugins/dates/README.md index e679e76d2..0685a7006 100644 --- a/plugins/dates/README.md +++ b/plugins/dates/README.md @@ -21,8 +21,8 @@ -This library is an earnest attempt to get date information out of text, in a clear way. - +This library is an earnest attempt to get date information out of text, in a clear way - +- including all informal formats, and folksy shorthands. @@ -49,17 +49,16 @@ doc.dates().get(0)
- Timezone and DST reckoning with spacetime [1] + Tokenization and disambiguation with compromise.
- Number-parsing with compromise-numbers [1] + Timezone and DST reckoning with spacetime [1]
- Tokenization and disambiguation with compromise. + Number-parsing with compromise-numbers [1]
-
- • Intuitive timezone reconciliation with spacetime-informal [1] + Timezone reconciliation with spacetime-informal [1]
@@ -85,18 +84,19 @@ doc.dates().get(0) | *march the second* | *natural-language number* | '' | '' | *on the 2nd* | *implicit months* | '' | '' | *tuesday the 2nd* | *date-reckoning* | '' | '' -|**`numeric-dates:`**| | +|
**`numeric-dates:`**| | | *2020/03/02* |*iso formats* | '' | '' | *2020-03-02* | | '' | '' | *03-02-2020* |*british formats* | '' | '' | *03/02* | | '' | '' | *2020.08.13* | | '' | '' -|**`named-dates:`**| | -| *today* | | '' | '' -| *easter* | | '' | '' -| *q1* | | '' | '' +|
**`named-dates:`**| | +| *today* | | - | - | *tomorrow* | | '' | '' -|**`times:`**| | +| *christmas eve* |*calendar-holidays* | Dec 24, 12:00am | Dec 24, 11:59pm +| *easter* |*astronomical holidays* | -depends- | - +| *q1* | | Jan 1, 12:00am | Mar 31, 11:59pm +|
**`times:`**| | | *2pm* | | '' | '' | *2:12pm* | | '' | '' | *2:12* | | '' | '' @@ -107,12 +107,12 @@ doc.dates().get(0) | *at night* | | '' | '' | *in the morning* | | '' | '' | *tomorrow evening* | | '' | '' -|**`timezones:`**| | +|
**`timezones:`**| | | *eastern time* | | '' | '' | *est* | | '' | '' | *peru time* | | '' | '' | *GMT+9* | | '' | '' -|**`relative durations:`**| | +|
**`relative durations:`**| | | *this march* | | '' | '' | *this week* | | '' | '' | *this sunday* | | '' | '' @@ -122,7 +122,7 @@ doc.dates().get(0) | *last weekend of march* | | '' | '' | *last spring* | | '' | '' | *the saturday after next* | | '' | '' -|**`punted dates:`**| | +|
**`punted dates:`**| | | *two days after tomorrow* | | '' | '' | *in seven weeks* | | '' | '' | *2 weeks from now* | | '' | '' @@ -131,12 +131,12 @@ doc.dates().get(0) | *a week friday* | | '' | '' | *a week and a half before* | | '' | '' | *on the 1st* | | '' | '' -|**`start/end:`**| | +|
**`start/end:`**| | | *end of the week* | | '' | '' | *start of next year* | | '' | '' | *start of next year* | | '' | '' | *middle of q2 last year* | | '' | '' -|**`date-ranges:`**| | +|
**`date-ranges:`**| | | *between [june] and [july]* | | '' | '' | *from [today] to [haloween]* | | '' | '' | *[aug 1] - [aug 31]* | | '' | '' @@ -148,15 +148,21 @@ doc.dates().get(0) | *22-23 February* | | '' | '' -### Things it does awkwardly: -| | *description* | `Start` | `End` | + + + +### *Things it does awkwardly:* +| *`hmmm,`* | *description* | `Start` | `End` | | ------------- |:-------------:| :-------------:| :-------------:| | *middle of 2019/June* | tries to find the center | '' | '' | | *good friday 2025* | tries to reckon astronomically-set holidays| '' | '' | | *Oct 22 1975 in PST* | historical DST changes | '' | '' | -### Things it doesn't do: -| | *description* | `Start` | `End` | + + + +### *Things it doesn't do:* +| *😓,* | *description* | `Start` | `End` | | ------------- |:-------------:| :-------------:| :-------------:| | *middle of 2019/June* | tries to find the center | '' | '' | | *not this Saturday, but the Saturday after* | internal logic | '' | '' | From 2f02d8d84ac065f61265eaa2b48d00fe8c6d6698 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Wed, 24 Feb 2021 14:02:12 -0500 Subject: [PATCH 08/29] papercuts --- plugins/dates/README.md | 49 +++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/plugins/dates/README.md b/plugins/dates/README.md index 0685a7006..6e4a608d1 100644 --- a/plugins/dates/README.md +++ b/plugins/dates/README.md @@ -22,7 +22,9 @@ This library is an earnest attempt to get date information out of text, in a clear way - +
- including all informal formats, and folksy shorthands. +
@@ -74,7 +76,7 @@ doc.dates().get(0) -#### *Things it does well:* +### *Things it does well:* | `explicit-dates` | *description* | `Start` | `End` | | ------------- |:-------------:| -----:| -----:| @@ -154,9 +156,9 @@ doc.dates().get(0) ### *Things it does awkwardly:* | *`hmmm,`* | *description* | `Start` | `End` | | ------------- |:-------------:| :-------------:| :-------------:| -| *middle of 2019/June* | tries to find the center | '' | '' | +| *middle of 2019/June* | tries to find the sorta-center | 'June 15' | '' | | *good friday 2025* | tries to reckon astronomically-set holidays| '' | '' | -| *Oct 22 1975 in PST* | historical DST changes | '' | '' | +| *Oct 22 1975 2am in PST* | historical DST changes (assumes current dates) | '' | '' | @@ -164,8 +166,7 @@ doc.dates().get(0) ### *Things it doesn't do:* | *😓,* | *description* | `Start` | `End` | | ------------- |:-------------:| :-------------:| :-------------:| -| *middle of 2019/June* | tries to find the center | '' | '' | -| *not this Saturday, but the Saturday after* | internal logic | '' | '' | +| *not this Saturday, but the Saturday after* | self-reference logic | '' | '' | | *3 years ago tomorrow* | folksy short-hand | '' | '' | | *2100* | military time formats | '' | '' | | *may 97* | 'bare' 2-digit years | '' | '' | @@ -197,6 +198,10 @@ doc.dates().get(0) `.dates()` accepts an optional object, that lets you set the context for the date parsing. + + + + ### Configuration: ```js const context = { @@ -210,6 +215,13 @@ const context = { nlp('in two days').dates(context).json() ``` + + + +
+ +
+ ## API - **[.dates()](https://observablehq.com/@spencermountain/compromise-dates)** - 'June 2021', 'next week' - **[.dates().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with date metadata @@ -235,17 +247,17 @@ nlp('in two days').dates(context).json() By default, weeks start on a Monday, and *'next week'* will run from Monday morning to Sunday night. This can be configued in spacetime, but right now we are not passing-through this config. -#### *Implied durations* +#### *Implied durations:* *'after October'* returns a range starting **Nov 1st**, and ending **2-weeks** after, by default. This can be configured by setting `punt` param in the context object: ```js doc.dates({punt: { month: 1 }}) ``` -#### *Future bias* +#### *Future bias:* *'May 7th'* will prefer a May 7th in the future -#### *This/Next/Last* +#### *This/Next/Last:* *'this/next/last week'* is mostly straight-forward. But *'this monday'* and *'monday'* is more ambiguous - here, it always refers to the future. On tuesday, saying 'this monday' means 'next monday'. As I understand it, this is the most-intuitive interpretation. Saying *'this monday'* on monday, is itself. @@ -254,32 +266,32 @@ Likewise, *'this june'* in June, is itself. *'this june'* in any other month, is Future versions of this library may look at sentence-tense to help disambiguate these dates - *'i paid on monday'* vs *'i will pay on monday'*. -#### *Nth Week* +#### *Nth Week:* The first week of a month, or a year is the first week *with a thursday in it*. This is a weird, but widely-held standard. I believe it's a military formalism. It cannot be (easily) configued. This means that the start-date for *first week of January* may be a Monday in December, etc. As expected, *first monday of January* will always be in January. -#### *British/American ambiguity* +#### *British/American ambiguity:* by default, we use the same interpretation of dates as javascript does - we assume `01/02/2020` is Jan 2nd, (US-version) but allow `13/01/2020` to be Jan 13th (UK-version). This should be possible to configure in the near future. -#### *Seasons* +#### *Seasons:* By default, *'this summer'* will return **June 1 - Sept 1**, which is northern hemisphere ISO. Configuring the default hemisphere should be possible in the future. -#### *Day times* +#### *Day times:* There are some hardcoded times for *'lunch time'* and others, but mainly, a day begins at `12:00am` and ends at `11:59pm` - the last millisecond of the day. -#### *Invalid dates* +#### *Invalid dates:* compromise will tag anything that looks like a date, but not validate the dates until they are parsed. * *'january 34th 2020'* will return **Jan 31 2020**. * *'tomorrow at 2:62pm'* will return just return 'tomorrow'. * *'6th week of february* will return the 2nd week of march. * Setting an hour that's skipped, or repeated by a DST change will return the closest valid time to the DST change. -#### *Inclusive/exclusive ranges* +#### *Inclusive/exclusive ranges:* *'between january and march'* will include all of march. This is usually pretty-ambiguous normally. -#### *Misc* +#### *Misc:* * *'thursday the 16th'* - will set to the 16th, even if it's not thursday * *'in a few hours/years'* - in 2 hours/years * *'jan 5th 2008 to Jan 6th the following year'* - date-range explicit references @@ -294,7 +306,7 @@ compromise will tag anything that looks like a date, but not validate the dates - +### *About:* @@ -323,6 +335,7 @@ A rule-based, community open-source library - *one based on simple NLP* - is the The *[match-syntax](https://observablehq.com/@spencermountain/compromise-match-syntax)* is effective and easy, *javascript* is prevailing, and the more people who contribute, the better. + ### See also * [Duckling](https://duckling.wit.ai/) - by wit.ai (facebook) @@ -336,8 +349,6 @@ The *[match-syntax](https://observablehq.com/@spencermountain/compromise-match-s -Work on compromise-date is sponsored by [Simform](https://www.simform.com/) - - +Work on compromise-date is sponsored by **MIT** licenced From 36614a48ebbf26d08d1e92e23fe33085e9e0d4ea Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Wed, 24 Feb 2021 14:37:44 -0500 Subject: [PATCH 09/29] more examples --- plugins/dates/README.md | 92 +++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/plugins/dates/README.md b/plugins/dates/README.md index 6e4a608d1..38f18f45e 100644 --- a/plugins/dates/README.md +++ b/plugins/dates/README.md @@ -23,7 +23,7 @@ This library is an earnest attempt to get date information out of text, in a clear way -
-- including all informal formats, and folksy shorthands. +- including all informal text formats, and folksy shorthands.
@@ -71,7 +71,7 @@ doc.dates().get(0) @@ -91,7 +91,7 @@ doc.dates().get(0) | *2020-03-02* | | '' | '' | *03-02-2020* |*british formats* | '' | '' | *03/02* | | '' | '' -| *2020.08.13* | | '' | '' +| *2020.08.13* | *alt-ISO*| '' | '' |
**`named-dates:`**| | | *today* | | - | - | *tomorrow* | | '' | '' @@ -102,18 +102,21 @@ doc.dates().get(0) | *2pm* | | '' | '' | *2:12pm* | | '' | '' | *2:12* | | '' | '' -| *02:12:00* | | '' | '' -| *2 oclock* | | '' | '' +| *02:12:00* | *weird iso-times*| '' | '' +| *two oclock* |*written formats* | '' | '' | *before 1* | | '' | '' | *noon* | | '' | '' -| *at night* | | '' | '' +| *at night* | *informal daytimes* | '' | '' | *in the morning* | | '' | '' | *tomorrow evening* | | '' | '' |
**`timezones:`**| | -| *eastern time* | | '' | '' -| *est* | | '' | '' +| *eastern time* | *informal zone support*| '' | '' +| *est* |*TZ shorthands* | '' | '' | *peru time* | | '' | '' -| *GMT+9* | | '' | '' +| *..in beirut* | *by location* | '' | '' +| *GMT+9* | *by UTC/GMT offset*| '' | '' +| *-4h* | '' | '' | '' +| *Canada/Eastern* | *IANA codes*| '' | '' |
**`relative durations:`**| | | *this march* | | '' | '' | *this week* | | '' | '' @@ -125,30 +128,34 @@ doc.dates().get(0) | *last spring* | | '' | '' | *the saturday after next* | | '' | '' |
**`punted dates:`**| | -| *two days after tomorrow* | | '' | '' -| *in seven weeks* | | '' | '' +| *in seven weeks* | *now+duration*| '' | '' +| *two days after june 6th* | *date+duration*| '' | '' | *2 weeks from now* | | '' | '' -| *2 weeks after* | | '' | '' -| *2 years 4 months 5 days ago* | | '' | '' -| *a week friday* | | '' | '' -| *a week and a half before* | | '' | '' -| *on the 1st* | | '' | '' +| *2 weeks after june* | | '' | '' +| *2 years, 4 months, and 5 days ago* | *complex durations*| '' | '' +| *a week and a half before* | *written-out numbers*| '' | '' +| *a week friday* | *idiom format*| '' | '' |
**`start/end:`**| | -| *end of the week* | | '' | '' -| *start of next year* | | '' | '' -| *start of next year* | | '' | '' -| *middle of q2 last year* | | '' | '' +| *end of the week* | *up-against the ending* | '' | '' +| *start of next year* | *lean-toward starting*| '' | '' +| *middle of q2 last year* |*rough-center calculation* | '' | '' |
**`date-ranges:`**| | -| *between [june] and [july]* | | '' | '' -| *from [today] to [haloween]* | | '' | '' -| *[aug 1] - [aug 31]* | | '' | '' -| *[today] to [next friday]* | | '' | '' -| *during june`* | | '' | '' -| *before [2019]* | | '' | '' -| *by march* | | '' | '' -| *after february* | | '' | '' +| *between june and july* |*explicit ranges* | '' | '' +| *from today to next haloween* | | '' | '' +| *aug 1 - aug 31* | *dash-ranges*| '' | '' | *22-23 February* | | '' | '' - +| *today to next friday* | | '' | '' +| *during june* | | '' | '' +| *aug to june 1999* | *shared range info*| '' | '' +| *before [2019]* |*up-to a date* | '' | '' +| *by march* | | '' | '' +| *after february* | *date-to-infinity*| '' | '' +|
**`repeating-intervals:`**| | +| *any wednesday* | *n-repeating dates* | | +| *any day in June* | *repeating-date in range* | June 1 ... | .. June 30 +| *any wednesday this week* | | '' | '' +| *weekends in July* | *more-complex interval*| '' | '' +| *every weekday until February* | *interval until date*| '' | '' @@ -156,7 +163,7 @@ doc.dates().get(0) ### *Things it does awkwardly:* | *`hmmm,`* | *description* | `Start` | `End` | | ------------- |:-------------:| :-------------:| :-------------:| -| *middle of 2019/June* | tries to find the sorta-center | 'June 15' | '' | +| *middle of 2019/June* | tries to find the sorta-center | June 15 | '' | | *good friday 2025* | tries to reckon astronomically-set holidays| '' | '' | | *Oct 22 1975 2am in PST* | historical DST changes (assumes current dates) | '' | '' | @@ -196,23 +203,26 @@ doc.dates().get(0) - **.times().json()** - overloaded json output with time metadata - **.times().normalize()** - turn 3mins into 3 minutes -`.dates()` accepts an optional object, that lets you set the context for the date parsing. ### Configuration: +`.dates()` accepts an optional object, that lets you set the context for the date parsing. ```js const context = { timezone: 'Canada/Eastern', //the default timezone is 'ETC/UTC' today: '2020-02-20', //the implicit, or reference day/year punt: { weeks: 2 }, // the implied duration to use for 'after june 2nd' dayStart: '8:00am', - dayEndt: '5:30pm' + dayEnd: '5:30pm' } -nlp('in two days').dates(context).json() +nlp('in two days').dates(context).get() +/* + [{ start: '2020-02-22T08:00:00.000+5:00', end: '2020-02-22T17:30:00.000+5:00' }] +*/ ``` @@ -223,18 +233,18 @@ nlp('in two days').dates(context).json() ## API -- **[.dates()](https://observablehq.com/@spencermountain/compromise-dates)** - 'June 2021', 'next week' +- **[.dates()](https://observablehq.com/@spencermountain/compromise-dates)** - find dates like `June 8th` or `03/03/18` + - **[.dates().get()](https://observablehq.com/@spencermountain/compromise-dates)** - simple start/end json result - **[.dates().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with date metadata - **[.dates().format('')](https://observablehq.com/@spencermountain/compromise-dates)** - convert the dates to specific formats - **[.dates().toShortForm()](https://observablehq.com/@spencermountain/compromise-dates)** - convert 'Wednesday' to 'Wed', etc - **[.dates().toLongForm()](https://observablehq.com/@spencermountain/compromise-dates)** - convert 'Feb' to 'February', etc -- **.durations()** - 'seven days and two hours', '30mins' - - **.json()** - overloaded json output with duration info - - **.get()** - grab parsed duration -- **.times()** - 'three pm', '9 oclock' - - **.json()** - overloaded json output with time info - - **.get()** - grab parsed time - +- **[.durations()](https://observablehq.com/@spencermountain/compromise-dates)** - `2 weeks` or `5mins` + - **[.durations().get()](https://observablehq.com/@spencermountain/compromise-dates)** - return simple json for duration + - **[.durations().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with duration metadata +- **[.times()](https://observablehq.com/@spencermountain/compromise-dates)** - `4:30pm` or `half past five` + - **[.durations().get()](https://observablehq.com/@spencermountain/compromise-dates)** - return simple json for times + - **[.times().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with time metadata From a12dd60fa479643dbd68cd499fdafc28d6c812a9 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Fri, 26 Feb 2021 14:18:47 -0500 Subject: [PATCH 10/29] fix tokenization of weekdays, and duration-dates --- plugins/dates/README.md | 14 ++++---- plugins/dates/scratch.js | 15 ++++---- plugins/dates/src/find.js | 49 +++++++++++++++++++++++++++ plugins/dates/src/index.js | 14 ++------ plugins/dates/tests/durations.test.js | 18 ++++++++++ plugins/dates/tests/misc.test.js | 10 ++++++ scratch.js | 20 +++-------- 7 files changed, 99 insertions(+), 41 deletions(-) create mode 100644 plugins/dates/src/find.js diff --git a/plugins/dates/README.md b/plugins/dates/README.md index 38f18f45e..1328957c2 100644 --- a/plugins/dates/README.md +++ b/plugins/dates/README.md @@ -37,7 +37,7 @@ nlp.extend(require('compromise-dates')) let doc = nlp('the second monday of february') doc.dates().get(0) /* - {} + { start: '2021-02-08T00:00:00.000Z', end: '2021-02-08T23:59:59.999Z'} */ ``` @@ -323,22 +323,22 @@ compromise will tag anything that looks like a date, but not validate the dates
- 1 - Regular-expressions are the wrong way to parse dates. + 1 - Regular-expressions are too-brittle to parse dates.
- 2 - Neural-nets are the wrong way to parse dates. + 2 - Neural-nets are too-wonky to parse dates.
- 3 - A startup is the wrong place to build a universal date-parser. + 3 - A corporation, or startup is the wrong place to build a universal date-parser.
-Parsing *dates*, *times*, and *durations* from natural language can be a solved-problem. +Parsing *dates*, *times*, *durations*, and *intervals* from natural language can be a solved-problem. A rule-based, community open-source library - *one based on simple NLP* - is the best way to build a natural language date parser - commercial, or otherwise - for the frontend, or the backend. @@ -352,13 +352,13 @@ The *[match-syntax](https://observablehq.com/@spencermountain/compromise-match-s * [Chronic](https://github.com/mojombo/chronic) - by Tom Preston-Werner (Ruby) * [SUTime](https://nlp.stanford.edu/software/sutime.shtml) - by Angel Chang, Christopher Manning (Java) * [Natty](http://natty.joestelmach.com/) - by Joe Stelmach (Java) -* [ParseDateTime](https://pypi.org/project/parsedatetime/) by Mike Taylor (Python) * [rrule](https://github.com/jakubroztocil/rrule) - repeating date-interval handler (js) +* [ParseDateTime](https://pypi.org/project/parsedatetime/) by Mike Taylor (Python)
-Work on compromise-date is sponsored by +compromise-date is sponsored by **MIT** licenced diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index ab7f21eeb..9e55dd816 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -16,16 +16,15 @@ const context = { // max_repeat: 50, } -let doc = nlp(`q4`).debug() -console.log(doc.dates().get(0)) - +let doc = nlp('2nd monday of february') // let doc = nlp(`any mondays`) -// let dates = doc.dates(context) //.debug() -// let date = dates.get(0) -// console.log(date) + +let dates = doc.dates(context) //.debug() +let date = dates.get(0) +console.log(date) // console.log(JSON.stringify(json.date, null, 2)) -// console.log('start: ', fmt(date.start)) -// console.log(' end: ', fmt(date.end)) +console.log('start: ', fmt(date.start)) +console.log(' end: ', fmt(date.end)) // console.log('=-=-=-= here -=-=-=-') // console.log(nlp('it was ten after 9').debug().times().get()) diff --git a/plugins/dates/src/find.js b/plugins/dates/src/find.js new file mode 100644 index 000000000..172a95bef --- /dev/null +++ b/plugins/dates/src/find.js @@ -0,0 +1,49 @@ +const findDate = function (doc) { + // let r = this.clauses() + let dates = doc.match('#Date+') + // ignore only-durations like '20 minutes' + dates = dates.filter((m) => { + let isDuration = m.has('^#Duration+$') || m.has('^#Value #Duration+$') + // allow 'q4', etc + if (isDuration === true && m.has('#FinancialQuarter')) { + isDuration = false + } + return isDuration === false + }) + // 30 minutes on tuesday + let m = dates.match('[#Cardinal #Duration (in|on|this|next|during|for)] #Date', 0) + if (m.found) { + dates = dates.not(m) + } + // 30 minutes tuesday + m = dates.match('[#Cardinal #Duration] #WeekDay', 0) + if (m.found) { + dates = dates.not(m) + } + // tuesday for 30 mins + m = dates.match('#Date [for #Value #Duration]$', 0) + if (m.found) { + dates = dates.not(m) + } + // 'tuesday, wednesday' + m = dates.match('^[#WeekDay] #WeekDay$', 0) + if (m.found) { + dates = dates.splitAfter(m) + dates = dates.not('^(and|or)') + } + // 'tuesday, wednesday, and friday' + m = dates.match('#WeekDay #WeekDay and #WeekDay') + if (m.found) { + dates = dates.splitOn('#WeekDay') + dates = dates.not('^(and|or)') + } + // // 'january, february' + // m = dates.match('^[#Month] (and|or)? #Month$', 0) + // if (m.found) { + // dates = dates.splitAfter(m) + // dates = dates.not('^(and|or)') + // } + + return dates +} +module.exports = findDate diff --git a/plugins/dates/src/index.js b/plugins/dates/src/index.js index 9cf2468d7..151c1ec5e 100644 --- a/plugins/dates/src/index.js +++ b/plugins/dates/src/index.js @@ -5,6 +5,7 @@ const methods = require('./methods') const addDurations = require('./durations') const addTimes = require('./times') const spacetime = require('spacetime') +const findDates = require('./find') const opts = { punt: { weeks: 2 }, @@ -40,17 +41,8 @@ const addMethods = function (Doc, world) { n = null } context = Object.assign({}, context, opts) - // let r = this.clauses() - let dates = this.match('#Date+') - // ignore only-durations like '20 minutes' - dates = dates.filter((m) => { - let isDuration = m.has('^#Duration+$') || m.has('^#Value #Duration+$') - // allow 'q4', etc - if (isDuration === true && m.has('#FinancialQuarter')) { - isDuration = false - } - return isDuration === false - }) + + let dates = findDates(this) if (typeof n === 'number') { dates = dates.get(n) } diff --git a/plugins/dates/tests/durations.test.js b/plugins/dates/tests/durations.test.js index 7479f0c9e..61b6def6d 100644 --- a/plugins/dates/tests/durations.test.js +++ b/plugins/dates/tests/durations.test.js @@ -1,6 +1,24 @@ const test = require('tape') const nlp = require('./_lib') +test('durations vs dates', function (t) { + let arr = [ + `30mins tuesday`, + `30 minutes on tuesday`, + `30 minutes on january 2nd`, + `tuesday for 30 mins`, + `january 1st 2020 for 30 mins`, + ] + arr.forEach((str) => { + let doc = nlp(str) + let dates = doc.dates().get(0) + let durations = doc.durations().get(0) + t.ok(dates.start, `[date] ${str}`) + t.equal(durations.minute, 30, `[duration] ${str}`) + }) + t.end() +}) + test('durations json', function (t) { let doc = nlp('blah blah two hours and 8 mins foobar') let json = doc.durations().json(0) diff --git a/plugins/dates/tests/misc.test.js b/plugins/dates/tests/misc.test.js index 67f320cff..b3f490eac 100644 --- a/plugins/dates/tests/misc.test.js +++ b/plugins/dates/tests/misc.test.js @@ -49,3 +49,13 @@ test('durations are not dates', function (t) { t.equal(doc.durations().length, 1, 'one-duration-compact') t.end() }) + +test('lists of days', function (t) { + let doc = nlp('tuesday, wednesday, or friday') + t.equal(doc.dates().length, 3, '3-dates in list') + + doc = nlp('wednesday, friday, and sunday') + t.equal(doc.dates().length, 3, '3-dates in AND list') + + t.end() +}) diff --git a/scratch.js b/scratch.js index 1d2fba694..d87a5c1af 100644 --- a/scratch.js +++ b/scratch.js @@ -13,18 +13,8 @@ nlp.extend(require('./plugins/dates/src')) // complex denominators - 'one fifty fourths', 'one thirty third' // -// let doc = nlp.tokenize(`one after`) -// console.log('\n\n============\n\n') -// console.log('|' + doc.match(`one !foo? moo? after`).text() + '|') -// console.log('|' + doc.match(`one !foo? after`).text() + '|') - -let doc = nlp.tokenize(`have not booked him`) -console.log('\n\n\n======\n') -// console.log(doc.match(`have !not? * booked`).found) -// true -// console.log('|' + doc.match(`have !not? *? booked`).text() + '|') -//false - -doc = nlp.tokenize('spencer other') -// t.equals(doc.match('(cool|spencer)').text(), 'spencer', 'optional-true') -console.log(doc.match('!(cool|spencer)').text() + '|') +// let doc = nlp(`30mins tuesday`).debug() +let doc = nlp(`q4`) +// let doc = nlp(`january and march`) +console.log(doc.dates().debug().get()) +// console.log(doc.durations().get(0)) From 81d7df5bc5171b8720301a2148f337d695be93e0 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Fri, 26 Feb 2021 14:31:32 -0500 Subject: [PATCH 11/29] date tests are passing --- plugins/dates/src/find.js | 5 +++-- plugins/dates/src/parseDate/parse.js | 3 +++ plugins/dates/tests/chronic.test.js | 6 +++--- scratch.js | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/plugins/dates/src/find.js b/plugins/dates/src/find.js index 172a95bef..dc267835e 100644 --- a/plugins/dates/src/find.js +++ b/plugins/dates/src/find.js @@ -1,12 +1,13 @@ const findDate = function (doc) { // let r = this.clauses() let dates = doc.match('#Date+') + // ignore only-durations like '20 minutes' dates = dates.filter((m) => { let isDuration = m.has('^#Duration+$') || m.has('^#Value #Duration+$') // allow 'q4', etc - if (isDuration === true && m.has('#FinancialQuarter')) { - isDuration = false + if (isDuration === true && m.has('(#FinancialQuarter|quarter)')) { + return true } return isDuration === false }) diff --git a/plugins/dates/src/parseDate/parse.js b/plugins/dates/src/parseDate/parse.js index b88228f50..d741f8ebe 100644 --- a/plugins/dates/src/parseDate/parse.js +++ b/plugins/dates/src/parseDate/parse.js @@ -32,12 +32,14 @@ const parseDate = function (doc, context) { let weekDay = tokens.weekday(doc, context) let section = tokens.section(doc, context) let rel = tokens.relative(doc) + //set our new timezone if (tz) { context = Object.assign({}, context, { timezone: tz }) let iso = context.today.format('iso-short') context.today = context.today.goto(context.timezone).set(iso) } + let unit = null //'in two days' unit = unit || parse.today(doc, context, { shift, time, rel }) @@ -49,6 +51,7 @@ const parseDate = function (doc, context) { unit = unit || parse.yearly(doc, context) // 'this june 2nd' unit = unit || parse.explicit(doc, context) + if (!unit) { return null } diff --git a/plugins/dates/tests/chronic.test.js b/plugins/dates/tests/chronic.test.js index 480cef596..e948086f0 100644 --- a/plugins/dates/tests/chronic.test.js +++ b/plugins/dates/tests/chronic.test.js @@ -349,10 +349,10 @@ test('chronic-tests-two', (t) => { // t.equal(nlpDate('this q2'), mk(2006, 4, 1),'q1') // t.equal(nlpDate('last q2'), mk(2006, 4, 1),'q1') // t.equal(nlpDate('next q2'), mk(2007, 4, 1),'q1') - t.equal(nlpDate('Q4'), mk(2006, 10, 1), 'q4') - t.equal(nlpDate('fourth quarter'), mk(2006, 10, 1), 'q4') + t.equal(nlpDate('Q4'), mk(2006, 10, 1), 'q4 #1') + t.equal(nlpDate('fourth quarter'), mk(2006, 10, 1), 'q4 #2') // t.equal(nlpDate('4th quarter'), mk(2005, 10, 1), 'q4') - t.equal(nlpDate('4th quarter 2005'), mk(2005, 10, 1), 'q4') + t.equal(nlpDate('4th quarter 2005'), mk(2005, 10, 1), 'q4 #3') // t.equal(nlpDate('2005 4th quarter'), mk(2005, 10, 1), 'q4') // t.equal(nlpDate('4th quarter this year'), mk(2006, 10, 1), 'q4') // t.equal(nlpDate('this year 4th quarter'), mk(2006, 10, 1), 'q4') diff --git a/scratch.js b/scratch.js index d87a5c1af..f6fca1d40 100644 --- a/scratch.js +++ b/scratch.js @@ -14,7 +14,7 @@ nlp.extend(require('./plugins/dates/src')) // // let doc = nlp(`30mins tuesday`).debug() -let doc = nlp(`q4`) +let doc = nlp(`fourth quarter`) // let doc = nlp(`january and march`) -console.log(doc.dates().debug().get()) +console.log(doc.dates({ today: '1999-02-03' }).debug().get()) // console.log(doc.durations().get(0)) From 544f7d954ce5771def26540d8f0a3beb1dc822c5 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Fri, 26 Feb 2021 14:41:30 -0500 Subject: [PATCH 12/29] compromise-sentences 0.2.0 --- .../sentences/builds/compromise-sentences.js | 10 +- .../builds/compromise-sentences.js.map | 2 +- .../sentences/builds/compromise-sentences.mjs | 10 +- plugins/sentences/changelog.md | 2 + plugins/sentences/package-lock.json | 289 +++++++----------- plugins/sentences/package.json | 10 +- 6 files changed, 127 insertions(+), 196 deletions(-) create mode 100644 plugins/sentences/changelog.md diff --git a/plugins/sentences/builds/compromise-sentences.js b/plugins/sentences/builds/compromise-sentences.js index 7a703bd8c..9bf178d4d 100644 --- a/plugins/sentences/builds/compromise-sentences.js +++ b/plugins/sentences/builds/compromise-sentences.js @@ -1,4 +1,4 @@ -/* compromise-sentences 0.1.1 MIT */ +/* compromise-sentences 0.2.0 MIT */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : @@ -386,13 +386,13 @@ return false; }; - var isQuestion_1 = isQuestion; + var isQuestion_1$1 = isQuestion; /** return sentences ending with '?' */ - var isQuestion_1$1 = function isQuestion_1$1() { + var isQuestion_1 = function isQuestion_1() { return this.filter(function (d) { - return isQuestion_1(d); + return isQuestion_1$1(d); }); }; /** return sentences ending with '!' */ @@ -436,7 +436,7 @@ }; var questions = { - isQuestion: isQuestion_1$1, + isQuestion: isQuestion_1, isExclamation: isExclamation, isStatement: isStatement, toExclamation: toExclamation, diff --git a/plugins/sentences/builds/compromise-sentences.js.map b/plugins/sentences/builds/compromise-sentences.js.map index f4a839178..aabbb8f77 100644 --- a/plugins/sentences/builds/compromise-sentences.js.map +++ b/plugins/sentences/builds/compromise-sentences.js.map @@ -1 +1 @@ -{"version":3,"file":"compromise-sentences.js","sources":["../src/tags.js","../src/tagger.js","../src/misc/append.js","../src/parse/mainClause.js","../src/parse/index.js","../src/misc/json.js","../src/misc/negative.js","../src/questions/isQuestion.js","../src/questions/index.js","../src/tense/index.js","../src/phrases/index.js","../src/index.js"],"sourcesContent":["module.exports = {\n // Phrase: {},\n NounPhrase: {\n // isA: 'Phrase',\n notA: ['VerbPhrase', 'AdjectivePhrase'],\n color: 'blue',\n },\n VerbPhrase: {\n // isA: 'Phrase',\n notA: ['AdjectivePhrase', 'NounPhrase'],\n color: 'green',\n },\n AdjectivePhrase: {\n // isA: 'Phrase',\n notA: ['VerbPhrase', 'NounPhrase'],\n color: 'magenta',\n },\n Subordinate: {\n // isA: 'Phrase',\n notA: [],\n // color: '',\n },\n}\n","const tagger = function (doc) {\n doc.match('#Noun').tag('NounPhrase')\n doc.match('#Verb').tag('VerbPhrase')\n\n // NounPhrase\n doc.match('(this|that|those|these)').tag('NounPhrase')\n doc.match('#Adjective+ #NounPhrase').tagSafe('NounPhrase')\n doc.match('#NounPhrase #Adjective+').tagSafe('NounPhrase')\n // numbers\n doc.match('#Value #NounPhrase').tag('NounPhrase')\n // (determiners)\n doc.match('#Determiner #NounPhrase').tag('NounPhrase')\n doc.match('#Determiner #Adverb+? #Adjective+ #NounPhrase').tag('NounPhrase')\n doc.match('(many|most|all|one|some|plenty) of #NounPhrase').tag('NounPhrase')\n doc.match('such a #NounPhrase').tag('NounPhrase')\n\n // VerbPhrase\n doc.match('#VerbPhrase #Adverb+').tagSafe('VerbPhrase')\n doc.match('#Adverb+ #VerbPhrase').tagSafe('VerbPhrase')\n doc.match('#Auxiliary+ #VerbPhrase').tagSafe('VerbPhrase')\n doc.match('#VerbPhrase no').tagSafe('VerbPhrase')\n doc.match('not #VerbPhrase').tagSafe('VerbPhrase')\n\n // claiming that\n doc.match('#VerbPhrase [that]', 0).unTag('NounPhrase')\n // (conjunctions)\n doc.match('#VerbPhrase #Conjunction #VerbPhrase').tagSafe('VerbPhrase')\n\n // nouns\n doc.match('(who|what|which)').tag('NounPhrase')\n\n // Adjective\n doc.match('#Adverb+ #Adjective').tagSafe('AdjectivePhrase')\n doc.match('#Adjective').tagSafe('AdjectivePhrase')\n\n // missing\n doc.match('#Value').tagSafe('NounPhrase')\n doc.match('#Date').tagSafe('NounPhrase')\n doc.match('#Date at #Date').tagSafe('NounPhrase')\n}\nmodule.exports = tagger\n","/** add a word to the start of this sentence */\nexports.prepend = function (str) {\n this.forEach((doc) => {\n // repair the titlecase\n let firstTerms = doc.match('^.')\n firstTerms.not('#ProperNoun').toLowerCase()\n // actually add the word\n firstTerms._prepend(str)\n // add a titlecase\n firstTerms.terms(0).toTitleCase()\n })\n return this\n}\n\n/** add a word to the end of this sentence */\nexports.append = function (str) {\n let hasEnd = /[.?!]\\s*$/.test(str)\n this.forEach((doc) => {\n let end = doc.match('.$')\n let lastTerm = end.termList(0)\n let punct = lastTerm.post\n if (hasEnd === true) {\n punct = ''\n }\n // add punctuation to the end\n end._append(str + punct)\n // remove punctuation from the former last-term\n lastTerm.post = ' '\n })\n return this\n}\n","// if a clause starts with these, it's not a main clause\nconst subordinate = `(after|although|as|because|before|if|since|than|that|though|when|whenever|where|whereas|wherever|whether|while|why|unless|until|once)`\nconst relative = `(that|which|whichever|who|whoever|whom|whose|whomever)`\n\n//try to remove secondary clauses\nconst mainClause = function(og) {\n let m = og.clone(true)\n if (m.length === 1) {\n return m\n }\n // if there's no verb?\n m = m.if('#Verb')\n if (m.length === 1) {\n return m\n }\n // this is a signal for subordinate-clauses\n m = m.ifNo(subordinate)\n m = m.ifNo('^even (if|though)')\n m = m.ifNo('^so that')\n m = m.ifNo('^rather than')\n m = m.ifNo('^provided that')\n if (m.length === 1) {\n return m\n }\n // relative clauses\n m = m.ifNo(relative)\n if (m.length === 1) {\n return m\n }\n\n m = m.ifNo('(despite|during|before|through|throughout)')\n if (m.length === 1) {\n return m\n }\n // did we go too far?\n if (m.length === 0) {\n m = og\n }\n // choose the first one?\n return m.eq(0)\n}\nmodule.exports = mainClause\n","const mainClause = require('./mainClause')\n\nconst parse = function(doc) {\n let clauses = doc.clauses()\n let main = mainClause(clauses)\n let nouns = main.match('#Determiner? (#Noun|#Adjective)+').if('#Noun')\n let verb = main.verbs().eq(0)\n // match('(do|will)? not? #Verb+ not?').eq(0)\n return {\n subject: nouns.eq(0),\n verb: verb,\n object: verb.lookAhead('.*'),\n }\n}\nmodule.exports = parse\n","const parse = require('../parse')\n\n/** overload the original json with noun information */\nexports.json = function (options) {\n let n = null\n if (typeof options === 'number') {\n n = options\n options = null\n }\n options = options || { text: true, normal: true, trim: true, terms: true }\n let res = []\n this.forEach((doc) => {\n let json = doc._json(options)[0]\n let obj = parse(doc)\n json.subject = obj.subject.json(options)[0]\n json.verb = obj.verb.json(options)[0]\n json.object = obj.object.json(options)[0]\n res.push(json)\n })\n if (n !== null) {\n return res[n]\n }\n return res\n}\n","const parse = require('../parse')\n\n/** he walks -> he did not walk */\nexports.toNegative = function() {\n this.forEach(doc => {\n let obj = parse(doc)\n let vb = obj.verb.clone()\n vb = vb.verbs().toNegative()\n obj.verb.replaceWith(vb, false)\n })\n return this\n}\n/** he doesn't walk -> he walks */\nexports.toPositive = function() {\n this.forEach(doc => {\n let obj = parse(doc)\n let vb = obj.verb.clone()\n vb = vb.verbs().toPositive()\n obj.verb.replaceWith(vb, false)\n })\n return this\n}\n","//is this sentence asking a question?\nconst isQuestion = function (doc) {\n let endPunct = doc.post()\n let clauses = doc.clauses()\n\n if (/\\?/.test(endPunct) === true) {\n return true\n }\n\n // Has ellipsis at the end means it's probably not a question\n // e.g., Is this just fantasy...\n if (/\\.\\.$/.test(doc.out('text'))) {\n return false\n }\n\n // Starts with question word, but has a comma, so probably not a question\n // e.g., Why are we caught in a land slide, no escape from reality\n if (doc.has('^#QuestionWord') && doc.has('#Comma')) {\n return false\n }\n\n // Starts with a #QuestionWord\n // e.g., What open your eyes look up to the skies and see\n if (doc.has('^#QuestionWord')) {\n return true\n }\n\n // Second word is a #QuestionWord\n // e.g., I'm what a poor boy\n // case ts.has('^\\w+\\s#QuestionWord'):\n // return true;\n\n // is it, do you - start of sentence\n // e.g., Do I need no sympathy\n if (doc.has('^(do|does|did|is|was|can|could|will|would|may) #Noun')) {\n return true\n }\n\n // these are a little more loose..\n // e.g., Must I be come easy come easy go\n if (doc.has('^(have|must) you')) {\n return true\n }\n\n // Clause starts with a question word\n // e.g., Anyway the wind blows, what doesn't really matter to me\n if (clauses.has('^#QuestionWord')) {\n return true\n }\n\n //is wayne gretskzy alive\n if (clauses.has('(do|does|is|was) #Noun+ #Adverb? (#Adjective|#Infinitive)$')) {\n return true\n }\n\n // Probably not a question\n return false\n}\nmodule.exports = isQuestion\n","const isQuestion = require('./isQuestion')\n\n/** return sentences ending with '?' */\nexports.isQuestion = function () {\n return this.filter((d) => isQuestion(d))\n}\n/** return sentences ending with '!' */\nexports.isExclamation = function () {\n return this.filter((doc) => {\n let term = doc.lastTerm().termList(0)\n return term.hasPost('!')\n })\n}\n/** return sentences with neither a question or an exclamation */\nexports.isStatement = function () {\n return this.filter((doc) => {\n let term = doc.lastTerm().termList(0)\n return !term.hasPost('?') && !term.hasPost('!')\n })\n}\n\n/** 'he is.' -> 'he is!' */\nexports.toExclamation = function () {\n this.post('!')\n return this\n}\n/** 'he is.' -> 'he is?' */\nexports.toQuestion = function () {\n this.post('?')\n return this\n}\n/** 'he is?' -> 'he is.' */\nexports.toStatement = function () {\n this.post('.')\n return this\n}\n","const parse = require('../parse')\n\n// 'i could drive' -> 'i could have driven'\nconst useParticiple = function (vb) {\n if (vb.has('(could|should|would|may|can|must)')) {\n return true\n }\n return false\n}\n\n/** he walks -> he walked */\nexports.toPastTense = function () {\n this.forEach((doc) => {\n if (doc.has('#PastTense')) {\n return\n }\n let obj = parse(doc)\n let vb = obj.verb.clone()\n // support 'he could drive' -> 'he could have driven'\n if (useParticiple(vb)) {\n vb = vb.verbs().toParticiple()\n obj.verb.replaceWith(vb, false)\n } else {\n // //do a normal conjugation\n vb = vb.verbs().toPastTense()\n obj.verb.replaceWith(vb, false)\n }\n // // trailing gerund/future/present are okay, but 'walked and eats' is not\n if (obj.object && obj.object.found && obj.object.has('#PresentTense')) {\n let verbs = obj.object.verbs()\n verbs.if('#PresentTense').verbs().toPastTense()\n }\n })\n return this\n}\n\n/** he drives -> he has driven */\nexports.toParticiple = function () {\n this.forEach((doc) => {\n if (doc.has('has #Participle')) {\n return\n }\n let obj = parse(doc)\n let vb = obj.verb.clone()\n vb = vb.verbs().toParticiple()\n obj.verb.replaceWith(vb, false)\n // trailing gerund/future/present are okay, but 'walked and eats' is not\n if (obj.object && obj.object.found && obj.object.has('#PresentTense')) {\n let verbs = obj.object.verbs()\n verbs.if('#PresentTense').verbs().toParticiple()\n }\n })\n return this\n}\n\n/** he walked -> he walks */\nexports.toPresentTense = function () {\n this.forEach((doc) => {\n let obj = parse(doc)\n let isPlural = obj.verb.lookBehind('(i|we) (#Adverb|#Verb)?$').found\n let vb = obj.verb.clone()\n // 'i look', not 'i looks'\n if (isPlural) {\n //quick hack for copula verb - be/am\n if (vb.has('(is|was|am|be)')) {\n vb = vb.replace('will? (is|was|am|be)', 'am')\n } else {\n vb = vb.verbs().toInfinitive()\n }\n } else {\n //'he looks'\n vb = vb.verbs().toPresentTense()\n }\n obj.verb.replaceWith(vb, false)\n\n // future is okay, but 'walks and ate' -> 'walks and eats'\n if (obj.object && obj.object.found && obj.object.has('#PastTense')) {\n let verbs = obj.object.verbs()\n verbs.if('#PastTense').verbs().toPresentTense()\n }\n })\n return this\n}\n\n/**he walked -> he will walk */\nexports.toFutureTense = function () {\n this.forEach((doc) => {\n let obj = parse(doc)\n let vb = obj.verb.clone()\n vb = vb.verbs().toFutureTense()\n obj.verb.replaceWith(vb, false)\n //Present is okay, but 'will walk and ate' -> 'will walk and eat'\n if (obj.object && obj.object.found && obj.object.has('(#PastTense|#PresentTense)')) {\n let verbs = obj.object.verbs()\n verbs.if('(#PastTense|#PresentTense)').verbs().toInfinitive()\n }\n })\n return this\n}\n\n/** the main noun of the sentence */\nexports.subjects = function () {\n return this.map((doc) => {\n let res = parse(doc)\n return res.subject\n })\n}\n\n/** return sentences that are in passive-voice */\nexports.isPassive = function () {\n return this.if('was #Adverb? #PastTense #Adverb? by') //haha\n}\n","exports.phrases = function () {\n let arr = []\n this.forEach((s) => {\n s = s.splitOn('#VerbPhrase+')\n s = s.splitOn('#NounPhrase+')\n s = s.splitOn('#AdjectivePhrase+')\n arr = arr.concat(s.list)\n })\n return this.buildFrom(arr)\n}\n","const tags = require('./tags')\nconst tagger = require('./tagger')\n\nconst methods = Object.assign(\n {},\n require('./misc/append'),\n require('./misc/json'),\n require('./misc/negative'),\n require('./questions'),\n require('./tense'),\n require('./phrases')\n)\n\nconst plugin = function (Doc, world) {\n // our new tags\n world.addTags(tags)\n // run our tagger\n world.postProcess(tagger)\n /** */\n class Sentences extends Doc {\n constructor(list, from, w) {\n list = list.map((p) => p.clone(true))\n super(list, from, w)\n }\n }\n // add some aliases\n methods.questions = methods.isQuestion\n methods.exclamations = methods.isExclamation\n methods.statements = methods.isStatement\n // keep backups of these methods\n methods._prepend = Sentences.prototype.prepend\n methods._append = Sentences.prototype.append\n methods._json = Sentences.prototype.json\n Object.assign(Sentences.prototype, methods)\n\n /** create a new Sentences object */\n Sentences.prototype.buildFrom = function (list) {\n list = list.map((p) => p.clone(true))\n let doc = new Sentences(list, this, this.world)\n return doc\n }\n /** create a new Doc object */\n Sentences.prototype.toDoc = function () {\n return Doc.prototype.buildFrom(this.list)\n }\n\n /** overload original sentences() method and return Sentence class**/\n Doc.prototype.sentences = function (n) {\n let arr = []\n this.list.forEach((p) => {\n arr.push(p.fullSentence())\n })\n let s = new Sentences(arr, this, this.world)\n if (typeof n === 'number') {\n s = s.get(n)\n }\n return s\n }\n return Doc\n}\nmodule.exports = plugin\n"],"names":["NounPhrase","notA","color","VerbPhrase","AdjectivePhrase","Subordinate","tagger","doc","match","tag","tagSafe","unTag","str","forEach","firstTerms","not","toLowerCase","_prepend","terms","toTitleCase","hasEnd","test","end","lastTerm","termList","punct","post","_append","subordinate","relative","mainClause","og","m","clone","length","ifNo","eq","parse","clauses","main","nouns","verb","verbs","subject","object","lookAhead","options","n","text","normal","trim","res","json","_json","obj","push","vb","toNegative","replaceWith","toPositive","isQuestion","endPunct","out","has","filter","d","term","hasPost","useParticiple","toParticiple","toPastTense","found","isPlural","lookBehind","replace","toInfinitive","toPresentTense","toFutureTense","map","arr","s","splitOn","concat","list","buildFrom","methods","Object","assign","require$$0","require$$1","require$$2","require$$3","require$$4","require$$5","plugin","Doc","world","addTags","tags","postProcess","Sentences","from","w","p","questions","exclamations","isExclamation","statements","isStatement","prototype","prepend","append","toDoc","sentences","fullSentence","get"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"compromise-sentences.js","sources":["../src/tags.js","../src/tagger.js","../src/misc/append.js","../src/parse/mainClause.js","../src/parse/index.js","../src/misc/json.js","../src/misc/negative.js","../src/questions/isQuestion.js","../src/questions/index.js","../src/tense/index.js","../src/phrases/index.js","../src/index.js"],"sourcesContent":["module.exports = {\n // Phrase: {},\n NounPhrase: {\n // isA: 'Phrase',\n notA: ['VerbPhrase', 'AdjectivePhrase'],\n color: 'blue',\n },\n VerbPhrase: {\n // isA: 'Phrase',\n notA: ['AdjectivePhrase', 'NounPhrase'],\n color: 'green',\n },\n AdjectivePhrase: {\n // isA: 'Phrase',\n notA: ['VerbPhrase', 'NounPhrase'],\n color: 'magenta',\n },\n Subordinate: {\n // isA: 'Phrase',\n notA: [],\n // color: '',\n },\n}\n","const tagger = function (doc) {\n doc.match('#Noun').tag('NounPhrase')\n doc.match('#Verb').tag('VerbPhrase')\n\n // NounPhrase\n doc.match('(this|that|those|these)').tag('NounPhrase')\n doc.match('#Adjective+ #NounPhrase').tagSafe('NounPhrase')\n doc.match('#NounPhrase #Adjective+').tagSafe('NounPhrase')\n // numbers\n doc.match('#Value #NounPhrase').tag('NounPhrase')\n // (determiners)\n doc.match('#Determiner #NounPhrase').tag('NounPhrase')\n doc.match('#Determiner #Adverb+? #Adjective+ #NounPhrase').tag('NounPhrase')\n doc.match('(many|most|all|one|some|plenty) of #NounPhrase').tag('NounPhrase')\n doc.match('such a #NounPhrase').tag('NounPhrase')\n\n // VerbPhrase\n doc.match('#VerbPhrase #Adverb+').tagSafe('VerbPhrase')\n doc.match('#Adverb+ #VerbPhrase').tagSafe('VerbPhrase')\n doc.match('#Auxiliary+ #VerbPhrase').tagSafe('VerbPhrase')\n doc.match('#VerbPhrase no').tagSafe('VerbPhrase')\n doc.match('not #VerbPhrase').tagSafe('VerbPhrase')\n\n // claiming that\n doc.match('#VerbPhrase [that]', 0).unTag('NounPhrase')\n // (conjunctions)\n doc.match('#VerbPhrase #Conjunction #VerbPhrase').tagSafe('VerbPhrase')\n\n // nouns\n doc.match('(who|what|which)').tag('NounPhrase')\n\n // Adjective\n doc.match('#Adverb+ #Adjective').tagSafe('AdjectivePhrase')\n doc.match('#Adjective').tagSafe('AdjectivePhrase')\n\n // missing\n doc.match('#Value').tagSafe('NounPhrase')\n doc.match('#Date').tagSafe('NounPhrase')\n doc.match('#Date at #Date').tagSafe('NounPhrase')\n}\nmodule.exports = tagger\n","/** add a word to the start of this sentence */\nexports.prepend = function (str) {\n this.forEach((doc) => {\n // repair the titlecase\n let firstTerms = doc.match('^.')\n firstTerms.not('#ProperNoun').toLowerCase()\n // actually add the word\n firstTerms._prepend(str)\n // add a titlecase\n firstTerms.terms(0).toTitleCase()\n })\n return this\n}\n\n/** add a word to the end of this sentence */\nexports.append = function (str) {\n let hasEnd = /[.?!]\\s*$/.test(str)\n this.forEach((doc) => {\n let end = doc.match('.$')\n let lastTerm = end.termList(0)\n let punct = lastTerm.post\n if (hasEnd === true) {\n punct = ''\n }\n // add punctuation to the end\n end._append(str + punct)\n // remove punctuation from the former last-term\n lastTerm.post = ' '\n })\n return this\n}\n","// if a clause starts with these, it's not a main clause\nconst subordinate = `(after|although|as|because|before|if|since|than|that|though|when|whenever|where|whereas|wherever|whether|while|why|unless|until|once)`\nconst relative = `(that|which|whichever|who|whoever|whom|whose|whomever)`\n\n//try to remove secondary clauses\nconst mainClause = function(og) {\n let m = og.clone(true)\n if (m.length === 1) {\n return m\n }\n // if there's no verb?\n m = m.if('#Verb')\n if (m.length === 1) {\n return m\n }\n // this is a signal for subordinate-clauses\n m = m.ifNo(subordinate)\n m = m.ifNo('^even (if|though)')\n m = m.ifNo('^so that')\n m = m.ifNo('^rather than')\n m = m.ifNo('^provided that')\n if (m.length === 1) {\n return m\n }\n // relative clauses\n m = m.ifNo(relative)\n if (m.length === 1) {\n return m\n }\n\n m = m.ifNo('(despite|during|before|through|throughout)')\n if (m.length === 1) {\n return m\n }\n // did we go too far?\n if (m.length === 0) {\n m = og\n }\n // choose the first one?\n return m.eq(0)\n}\nmodule.exports = mainClause\n","const mainClause = require('./mainClause')\n\nconst parse = function(doc) {\n let clauses = doc.clauses()\n let main = mainClause(clauses)\n let nouns = main.match('#Determiner? (#Noun|#Adjective)+').if('#Noun')\n let verb = main.verbs().eq(0)\n // match('(do|will)? not? #Verb+ not?').eq(0)\n return {\n subject: nouns.eq(0),\n verb: verb,\n object: verb.lookAhead('.*'),\n }\n}\nmodule.exports = parse\n","const parse = require('../parse')\n\n/** overload the original json with noun information */\nexports.json = function (options) {\n let n = null\n if (typeof options === 'number') {\n n = options\n options = null\n }\n options = options || { text: true, normal: true, trim: true, terms: true }\n let res = []\n this.forEach((doc) => {\n let json = doc._json(options)[0]\n let obj = parse(doc)\n json.subject = obj.subject.json(options)[0]\n json.verb = obj.verb.json(options)[0]\n json.object = obj.object.json(options)[0]\n res.push(json)\n })\n if (n !== null) {\n return res[n]\n }\n return res\n}\n","const parse = require('../parse')\n\n/** he walks -> he did not walk */\nexports.toNegative = function() {\n this.forEach(doc => {\n let obj = parse(doc)\n let vb = obj.verb.clone()\n vb = vb.verbs().toNegative()\n obj.verb.replaceWith(vb, false)\n })\n return this\n}\n/** he doesn't walk -> he walks */\nexports.toPositive = function() {\n this.forEach(doc => {\n let obj = parse(doc)\n let vb = obj.verb.clone()\n vb = vb.verbs().toPositive()\n obj.verb.replaceWith(vb, false)\n })\n return this\n}\n","//is this sentence asking a question?\nconst isQuestion = function (doc) {\n let endPunct = doc.post()\n let clauses = doc.clauses()\n\n if (/\\?/.test(endPunct) === true) {\n return true\n }\n\n // Has ellipsis at the end means it's probably not a question\n // e.g., Is this just fantasy...\n if (/\\.\\.$/.test(doc.out('text'))) {\n return false\n }\n\n // Starts with question word, but has a comma, so probably not a question\n // e.g., Why are we caught in a land slide, no escape from reality\n if (doc.has('^#QuestionWord') && doc.has('#Comma')) {\n return false\n }\n\n // Starts with a #QuestionWord\n // e.g., What open your eyes look up to the skies and see\n if (doc.has('^#QuestionWord')) {\n return true\n }\n\n // Second word is a #QuestionWord\n // e.g., I'm what a poor boy\n // case ts.has('^\\w+\\s#QuestionWord'):\n // return true;\n\n // is it, do you - start of sentence\n // e.g., Do I need no sympathy\n if (doc.has('^(do|does|did|is|was|can|could|will|would|may) #Noun')) {\n return true\n }\n\n // these are a little more loose..\n // e.g., Must I be come easy come easy go\n if (doc.has('^(have|must) you')) {\n return true\n }\n\n // Clause starts with a question word\n // e.g., Anyway the wind blows, what doesn't really matter to me\n if (clauses.has('^#QuestionWord')) {\n return true\n }\n\n //is wayne gretskzy alive\n if (clauses.has('(do|does|is|was) #Noun+ #Adverb? (#Adjective|#Infinitive)$')) {\n return true\n }\n\n // Probably not a question\n return false\n}\nmodule.exports = isQuestion\n","const isQuestion = require('./isQuestion')\n\n/** return sentences ending with '?' */\nexports.isQuestion = function () {\n return this.filter((d) => isQuestion(d))\n}\n/** return sentences ending with '!' */\nexports.isExclamation = function () {\n return this.filter((doc) => {\n let term = doc.lastTerm().termList(0)\n return term.hasPost('!')\n })\n}\n/** return sentences with neither a question or an exclamation */\nexports.isStatement = function () {\n return this.filter((doc) => {\n let term = doc.lastTerm().termList(0)\n return !term.hasPost('?') && !term.hasPost('!')\n })\n}\n\n/** 'he is.' -> 'he is!' */\nexports.toExclamation = function () {\n this.post('!')\n return this\n}\n/** 'he is.' -> 'he is?' */\nexports.toQuestion = function () {\n this.post('?')\n return this\n}\n/** 'he is?' -> 'he is.' */\nexports.toStatement = function () {\n this.post('.')\n return this\n}\n","const parse = require('../parse')\n\n// 'i could drive' -> 'i could have driven'\nconst useParticiple = function (vb) {\n if (vb.has('(could|should|would|may|can|must)')) {\n return true\n }\n return false\n}\n\n/** he walks -> he walked */\nexports.toPastTense = function () {\n this.forEach((doc) => {\n if (doc.has('#PastTense')) {\n return\n }\n let obj = parse(doc)\n let vb = obj.verb.clone()\n // support 'he could drive' -> 'he could have driven'\n if (useParticiple(vb)) {\n vb = vb.verbs().toParticiple()\n obj.verb.replaceWith(vb, false)\n } else {\n // //do a normal conjugation\n vb = vb.verbs().toPastTense()\n obj.verb.replaceWith(vb, false)\n }\n // // trailing gerund/future/present are okay, but 'walked and eats' is not\n if (obj.object && obj.object.found && obj.object.has('#PresentTense')) {\n let verbs = obj.object.verbs()\n verbs.if('#PresentTense').verbs().toPastTense()\n }\n })\n return this\n}\n\n/** he drives -> he has driven */\nexports.toParticiple = function () {\n this.forEach((doc) => {\n if (doc.has('has #Participle')) {\n return\n }\n let obj = parse(doc)\n let vb = obj.verb.clone()\n vb = vb.verbs().toParticiple()\n obj.verb.replaceWith(vb, false)\n // trailing gerund/future/present are okay, but 'walked and eats' is not\n if (obj.object && obj.object.found && obj.object.has('#PresentTense')) {\n let verbs = obj.object.verbs()\n verbs.if('#PresentTense').verbs().toParticiple()\n }\n })\n return this\n}\n\n/** he walked -> he walks */\nexports.toPresentTense = function () {\n this.forEach((doc) => {\n let obj = parse(doc)\n let isPlural = obj.verb.lookBehind('(i|we) (#Adverb|#Verb)?$').found\n let vb = obj.verb.clone()\n // 'i look', not 'i looks'\n if (isPlural) {\n //quick hack for copula verb - be/am\n if (vb.has('(is|was|am|be)')) {\n vb = vb.replace('will? (is|was|am|be)', 'am')\n } else {\n vb = vb.verbs().toInfinitive()\n }\n } else {\n //'he looks'\n vb = vb.verbs().toPresentTense()\n }\n obj.verb.replaceWith(vb, false)\n\n // future is okay, but 'walks and ate' -> 'walks and eats'\n if (obj.object && obj.object.found && obj.object.has('#PastTense')) {\n let verbs = obj.object.verbs()\n verbs.if('#PastTense').verbs().toPresentTense()\n }\n })\n return this\n}\n\n/**he walked -> he will walk */\nexports.toFutureTense = function () {\n this.forEach((doc) => {\n let obj = parse(doc)\n let vb = obj.verb.clone()\n vb = vb.verbs().toFutureTense()\n obj.verb.replaceWith(vb, false)\n //Present is okay, but 'will walk and ate' -> 'will walk and eat'\n if (obj.object && obj.object.found && obj.object.has('(#PastTense|#PresentTense)')) {\n let verbs = obj.object.verbs()\n verbs.if('(#PastTense|#PresentTense)').verbs().toInfinitive()\n }\n })\n return this\n}\n\n/** the main noun of the sentence */\nexports.subjects = function () {\n return this.map((doc) => {\n let res = parse(doc)\n return res.subject\n })\n}\n\n/** return sentences that are in passive-voice */\nexports.isPassive = function () {\n return this.if('was #Adverb? #PastTense #Adverb? by') //haha\n}\n","exports.phrases = function () {\n let arr = []\n this.forEach((s) => {\n s = s.splitOn('#VerbPhrase+')\n s = s.splitOn('#NounPhrase+')\n s = s.splitOn('#AdjectivePhrase+')\n arr = arr.concat(s.list)\n })\n return this.buildFrom(arr)\n}\n","const tags = require('./tags')\nconst tagger = require('./tagger')\n\nconst methods = Object.assign(\n {},\n require('./misc/append'),\n require('./misc/json'),\n require('./misc/negative'),\n require('./questions'),\n require('./tense'),\n require('./phrases')\n)\n\nconst plugin = function (Doc, world) {\n // our new tags\n world.addTags(tags)\n // run our tagger\n world.postProcess(tagger)\n /** */\n class Sentences extends Doc {\n constructor(list, from, w) {\n list = list.map((p) => p.clone(true))\n super(list, from, w)\n }\n }\n // add some aliases\n methods.questions = methods.isQuestion\n methods.exclamations = methods.isExclamation\n methods.statements = methods.isStatement\n // keep backups of these methods\n methods._prepend = Sentences.prototype.prepend\n methods._append = Sentences.prototype.append\n methods._json = Sentences.prototype.json\n Object.assign(Sentences.prototype, methods)\n\n /** create a new Sentences object */\n Sentences.prototype.buildFrom = function (list) {\n list = list.map((p) => p.clone(true))\n let doc = new Sentences(list, this, this.world)\n return doc\n }\n /** create a new Doc object */\n Sentences.prototype.toDoc = function () {\n return Doc.prototype.buildFrom(this.list)\n }\n\n /** overload original sentences() method and return Sentence class**/\n Doc.prototype.sentences = function (n) {\n let arr = []\n this.list.forEach((p) => {\n arr.push(p.fullSentence())\n })\n let s = new Sentences(arr, this, this.world)\n if (typeof n === 'number') {\n s = s.get(n)\n }\n return s\n }\n return Doc\n}\nmodule.exports = plugin\n"],"names":["NounPhrase","notA","color","VerbPhrase","AdjectivePhrase","Subordinate","tagger","doc","match","tag","tagSafe","unTag","str","forEach","firstTerms","not","toLowerCase","_prepend","terms","toTitleCase","hasEnd","test","end","lastTerm","termList","punct","post","_append","subordinate","relative","mainClause","og","m","clone","length","ifNo","eq","parse","clauses","main","nouns","verb","verbs","subject","object","lookAhead","options","n","text","normal","trim","res","json","_json","obj","push","vb","toNegative","replaceWith","toPositive","isQuestion","endPunct","out","has","filter","d","term","hasPost","useParticiple","toParticiple","toPastTense","found","isPlural","lookBehind","replace","toInfinitive","toPresentTense","toFutureTense","map","arr","s","splitOn","concat","list","buildFrom","methods","Object","assign","require$$0","require$$1","require$$2","require$$3","require$$4","require$$5","plugin","Doc","world","addTags","tags","postProcess","Sentences","from","w","p","questions","exclamations","isExclamation","statements","isStatement","prototype","prepend","append","toDoc","sentences","fullSentence","get"],"mappings":"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"} \ No newline at end of file diff --git a/plugins/sentences/builds/compromise-sentences.mjs b/plugins/sentences/builds/compromise-sentences.mjs index 4a9a65cc6..d5486503f 100644 --- a/plugins/sentences/builds/compromise-sentences.mjs +++ b/plugins/sentences/builds/compromise-sentences.mjs @@ -1,4 +1,4 @@ -/* compromise-sentences 0.1.1 MIT */ +/* compromise-sentences 0.2.0 MIT */ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); @@ -380,13 +380,13 @@ var isQuestion = function isQuestion(doc) { return false; }; -var isQuestion_1 = isQuestion; +var isQuestion_1$1 = isQuestion; /** return sentences ending with '?' */ -var isQuestion_1$1 = function isQuestion_1$1() { +var isQuestion_1 = function isQuestion_1() { return this.filter(function (d) { - return isQuestion_1(d); + return isQuestion_1$1(d); }); }; /** return sentences ending with '!' */ @@ -430,7 +430,7 @@ var toStatement = function toStatement() { }; var questions = { - isQuestion: isQuestion_1$1, + isQuestion: isQuestion_1, isExclamation: isExclamation, isStatement: isStatement, toExclamation: toExclamation, diff --git a/plugins/sentences/changelog.md b/plugins/sentences/changelog.md new file mode 100644 index 000000000..f34909e4b --- /dev/null +++ b/plugins/sentences/changelog.md @@ -0,0 +1,2 @@ +### 0.2.0 [Feb 2020] +- update deps, fix peerDependency issue \ No newline at end of file diff --git a/plugins/sentences/package-lock.json b/plugins/sentences/package-lock.json index a79736c2d..a8b201ccc 100644 --- a/plugins/sentences/package-lock.json +++ b/plugins/sentences/package-lock.json @@ -1,6 +1,6 @@ { "name": "compromise-sentences", - "version": "0.1.1", + "version": "0.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -51,9 +51,9 @@ } }, "@rollup/plugin-commonjs": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-17.0.0.tgz", - "integrity": "sha512-/omBIJG1nHQc+bgkYDuLpb/V08QyutP9amOrJRUSlYJZP+b/68gM//D8sxJe3Yry2QnYIr3QjR3x4AlxJEN3GA==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-17.1.0.tgz", + "integrity": "sha512-PoMdXCw0ZyvjpCMT5aV4nkL0QywxP29sODQsSGeDpr/oI49Qq9tRtAsb/LbYbDzFlOydVEqHmmZWFtXJEAX9ew==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -75,9 +75,9 @@ } }, "@rollup/plugin-node-resolve": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.0.1.tgz", - "integrity": "sha512-ltlsj/4Bhwwhb+Nb5xCz/6vieuEj2/BAkkqVIKmZwC7pIdl8srmgmglE4S0jFlZa32K4qvdQ6NHdmpRKD/LwoQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.0.tgz", + "integrity": "sha512-qHjNIKYt5pCcn+5RUBQxK8krhRvf1HnyVgUCcFFcweDS7fhkOLZeYh0mhHK6Ery8/bb9tvN/ubPzmfF0qjDCTA==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -181,19 +181,19 @@ "dev": true }, "builtin-modules": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", - "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", + "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", "dev": true }, "call-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", - "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dev": true, "requires": { "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.0" + "get-intrinsic": "^1.0.2" } }, "chalk": { @@ -308,36 +308,39 @@ } }, "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "version": "1.18.0-next.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", + "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", "dev": true, "requires": { + "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2", "has": "^1.0.3", "has-symbols": "^1.0.1", "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.1", "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", + "object-inspect": "^1.9.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.3", + "string.prototype.trimstart": "^1.0.3" } }, "es-get-iterator": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.1.tgz", - "integrity": "sha512-qorBw8Y7B15DVLaJWy6WdEV/ZkieBcu6QCq/xzWzGOKJqgG1j754vXRfZ3NY7HSShneqU43mPB4OkQBTkvHhFw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.1", + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", "has-symbols": "^1.0.1", - "is-arguments": "^1.0.4", - "is-map": "^2.0.1", - "is-set": "^2.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", "is-string": "^1.0.5", "isarray": "^2.0.5" }, @@ -395,9 +398,9 @@ "dev": true }, "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "optional": true }, @@ -408,9 +411,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", - "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -494,9 +497,9 @@ } }, "is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", "dev": true }, "is-core-module": { @@ -548,11 +551,12 @@ } }, "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", "dev": true, "requires": { + "call-bind": "^1.0.2", "has-symbols": "^1.0.1" } }, @@ -578,38 +582,16 @@ } }, "is-typed-array": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.4.tgz", - "integrity": "sha512-ILaRgn4zaSrVNXNGtON6iFNotXW3hAPF3+0fB1usg2jFlWqo5fEDdmJkz0zBfoi7Dgskr8Khi2xZ8cXqZEfXNA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.5.tgz", + "integrity": "sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug==", "dev": true, "requires": { "available-typed-arrays": "^1.0.2", - "call-bind": "^1.0.0", - "es-abstract": "^1.18.0-next.1", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.0-next.2", "foreach": "^2.0.5", "has-symbols": "^1.0.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } } }, "is-weakmap": { @@ -707,12 +689,12 @@ "dev": true }, "object-is": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz", - "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, @@ -798,22 +780,22 @@ } }, "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { - "is-core-module": "^2.1.0", + "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } }, @@ -827,12 +809,12 @@ } }, "rollup": { - "version": "2.35.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.35.1.tgz", - "integrity": "sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA==", + "version": "2.40.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.40.0.tgz", + "integrity": "sha512-WiOGAPbXoHu+TOz6hyYUxIksOwsY/21TRWoO593jgYt8mvYafYqQl+axaA8y1z2HFazNUUrsMSjahV2A6/2R9A==", "dev": true, "requires": { - "fsevents": "~2.1.2" + "fsevents": "~2.3.1" } }, "rollup-plugin-babel": { @@ -896,35 +878,14 @@ } }, "side-channel": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.3.tgz", - "integrity": "sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, "requires": { - "es-abstract": "^1.18.0-next.0", - "object-inspect": "^1.8.0" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" } }, "source-map": { @@ -967,55 +928,33 @@ } }, "string.prototype.trim": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.3.tgz", - "integrity": "sha512-16IL9pIBA5asNOSukPfxX2W68BaBvxyiRK16H3RA/lWW9BDosh+w7f+LhomPHpXJ82QEe7w7/rY/S1CV97raLg==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.4.tgz", + "integrity": "sha512-hWCk/iqf7lp0/AgTF7/ddO1IWtSNPASjlzCicV5irAVdE1grjsneK26YG6xACMBEdCvO8fUST0UzDMh/2Qy+9Q==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "es-abstract": "^1.18.0-next.2" } }, "string.prototype.trimend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", - "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, "string.prototype.trimstart": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", - "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, @@ -1119,28 +1058,40 @@ } }, "tape": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/tape/-/tape-5.0.1.tgz", - "integrity": "sha512-wVsOl2shKPcjdJdc8a+PwacvrOdJZJ57cLUXlxW4TQ2R6aihXwG0m0bKm4mA4wjtQNTaLMCrYNEb4f9fjHKUYQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/tape/-/tape-5.2.0.tgz", + "integrity": "sha512-J7stlwNrBEpHlZvbvPEAFvMmqIy79kMYvXiyekl5w6O7C2HF63bFKi8su70mdUtZZvNMm7EbIzLyI+fk6U9Ntg==", "dev": true, "requires": { - "deep-equal": "^2.0.3", + "call-bind": "^1.0.2", + "deep-equal": "^2.0.5", "defined": "^1.0.0", "dotignore": "^0.1.2", "for-each": "^0.3.3", - "function-bind": "^1.1.1", "glob": "^7.1.6", "has": "^1.0.3", "inherits": "^2.0.4", - "is-regex": "^1.0.5", + "is-regex": "^1.1.2", "minimist": "^1.2.5", - "object-inspect": "^1.7.0", - "object-is": "^1.1.2", - "object.assign": "^4.1.0", - "resolve": "^1.17.0", + "object-inspect": "^1.9.0", + "object-is": "^1.1.4", + "object.assign": "^4.1.2", + "resolve": "^2.0.0-next.3", "resumer": "^0.0.0", - "string.prototype.trim": "^1.2.1", + "string.prototype.trim": "^1.2.3", "through": "^2.3.8" + }, + "dependencies": { + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } } }, "terser": { @@ -1216,28 +1167,6 @@ "function-bind": "^1.1.1", "has-symbols": "^1.0.1", "is-typed-array": "^1.1.3" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } } }, "wrappy": { diff --git a/plugins/sentences/package.json b/plugins/sentences/package.json index 61fb84231..a1db6b0a9 100644 --- a/plugins/sentences/package.json +++ b/plugins/sentences/package.json @@ -1,7 +1,7 @@ { "name": "compromise-sentences", "description": "plugin for nlp-compromise", - "version": "0.1.1", + "version": "0.2.0", "author": "Spencer Kelly (http://spencermounta.in)", "main": "./builds/compromise-sentences.js", "unpkg": "./builds/compromise-sentences.min.js", @@ -36,15 +36,15 @@ }, "dependencies": {}, "devDependencies": { - "@rollup/plugin-commonjs": "17.0.0", + "@rollup/plugin-commonjs": "17.1.0", "@rollup/plugin-json": "4.1.0", - "@rollup/plugin-node-resolve": "11.0.1", - "rollup": "2.35.1", + "@rollup/plugin-node-resolve": "11.2.0", + "rollup": "2.40.0", "rollup-plugin-babel": "4.4.0", "rollup-plugin-filesize-check": "0.0.1", "rollup-plugin-terser": "7.0.2", "tap-dancer": "0.3.1", - "tape": "5.0.1" + "tape": "5.2.0" }, "license": "MIT" } From f0f1634742971da864188c9daf5ecadf2b486e7f Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Fri, 26 Feb 2021 14:53:25 -0500 Subject: [PATCH 13/29] for 20mins vs in 20mins --- plugins/dates/README.md | 1 + plugins/dates/changelog.md | 6 ++++++ plugins/dates/package.json | 2 +- plugins/dates/src/data/words/index.js | 1 + plugins/dates/src/durations/index.js | 4 ++++ plugins/dates/src/find.js | 6 ++++++ plugins/dates/tests/durations.test.js | 11 +++++++++++ scratch.js | 6 +++--- 8 files changed, 33 insertions(+), 4 deletions(-) diff --git a/plugins/dates/README.md b/plugins/dates/README.md index 1328957c2..d8aac5b60 100644 --- a/plugins/dates/README.md +++ b/plugins/dates/README.md @@ -16,6 +16,7 @@
npm install compromise-dates
+ Work-in-Progress diff --git a/plugins/dates/changelog.md b/plugins/dates/changelog.md index cf5c5ba4c..3cba6b24c 100644 --- a/plugins/dates/changelog.md +++ b/plugins/dates/changelog.md @@ -1,6 +1,12 @@ +### 1.4.1 [Jan 2021] +- **[change]** - date tokenization of multiple AND and OR dates +- **[change]** - smart tokenization of duration and date +- **[change]** - 'in 2 minutes' vs 'for 2 minutes' + + ### 1.4.0 [Jan 2021] - **[new]** - `.durations()` method - **[new]** - `.times()` method diff --git a/plugins/dates/package.json b/plugins/dates/package.json index a6fd4d16c..edad16f21 100644 --- a/plugins/dates/package.json +++ b/plugins/dates/package.json @@ -1,7 +1,7 @@ { "name": "compromise-dates", "description": "plugin for nlp-compromise", - "version": "1.4.0", + "version": "1.4.1", "author": "Spencer Kelly (http://spencermounta.in)", "main": "./builds/compromise-dates.js", "unpkg": "./builds/compromise-dates.min.js", diff --git a/plugins/dates/src/data/words/index.js b/plugins/dates/src/data/words/index.js index cd113fa8e..38ff7db24 100644 --- a/plugins/dates/src/data/words/index.js +++ b/plugins/dates/src/data/words/index.js @@ -8,6 +8,7 @@ const data = [ ] let lex = { 'a couple': 'Value', + thur: 'WeekDay', } data.forEach((a) => { for (let i = 0; i < a[0].length; i++) { diff --git a/plugins/dates/src/durations/index.js b/plugins/dates/src/durations/index.js index de6bc520e..89d2f35ae 100644 --- a/plugins/dates/src/durations/index.js +++ b/plugins/dates/src/durations/index.js @@ -73,6 +73,10 @@ const addDurations = function (Doc) { let m = this.match('#Value+ #Duration (and? #Value+ #Duration)?') // add '20mins' m = m.concat(this.match('(#Duration && /[0-9][a-z]+$/)')) + + // not 'in 20 minutes' + m = m.notIf('#DateShift') + if (typeof n === 'number') { m = m.get(n) } diff --git a/plugins/dates/src/find.js b/plugins/dates/src/find.js index dc267835e..0f24aba65 100644 --- a/plugins/dates/src/find.js +++ b/plugins/dates/src/find.js @@ -38,6 +38,12 @@ const findDate = function (doc) { dates = dates.splitOn('#WeekDay') dates = dates.not('^(and|or)') } + + // for 20 minutes + m = dates.match('for #Cardinal #Duration') + if (m.found) { + dates = dates.not(m) + } // // 'january, february' // m = dates.match('^[#Month] (and|or)? #Month$', 0) // if (m.found) { diff --git a/plugins/dates/tests/durations.test.js b/plugins/dates/tests/durations.test.js index 61b6def6d..c184b5e6b 100644 --- a/plugins/dates/tests/durations.test.js +++ b/plugins/dates/tests/durations.test.js @@ -19,6 +19,17 @@ test('durations vs dates', function (t) { t.end() }) +test('in 4 mins', function (t) { + let doc = nlp(`in 20 mins`) + t.equal(doc.dates().found, true, 'in-20 mins Date') + t.equal(doc.durations().found, false, 'in-20 mins !Duration') + + doc = nlp(`for 20 mins`) + t.equal(doc.dates().found, false, 'for-20 mins !Date') + t.equal(doc.durations().found, true, 'for-20 mins Duration') + t.end() +}) + test('durations json', function (t) { let doc = nlp('blah blah two hours and 8 mins foobar') let json = doc.durations().json(0) diff --git a/scratch.js b/scratch.js index f6fca1d40..9fbc49059 100644 --- a/scratch.js +++ b/scratch.js @@ -14,7 +14,7 @@ nlp.extend(require('./plugins/dates/src')) // // let doc = nlp(`30mins tuesday`).debug() -let doc = nlp(`fourth quarter`) -// let doc = nlp(`january and march`) -console.log(doc.dates({ today: '1999-02-03' }).debug().get()) +let doc = nlp(`for 20 mins`).debug() +// let doc = nlp(`in 20 mins`).debug() +console.log(doc.dates().get()) // console.log(doc.durations().get(0)) From 5d95d4d17fd019081ebd99fc64ea4c634890c4b4 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Fri, 26 Feb 2021 14:56:55 -0500 Subject: [PATCH 14/29] dates@1.4.1 --- plugins/dates/README.md | 2 +- plugins/dates/builds/compromise-dates.js | 92 ++++++++++++++++---- plugins/dates/builds/compromise-dates.js.map | 2 +- plugins/dates/builds/compromise-dates.min.js | 2 +- plugins/dates/builds/compromise-dates.mjs | 92 ++++++++++++++++---- plugins/dates/tests/durations.test.js | 4 + 6 files changed, 159 insertions(+), 35 deletions(-) diff --git a/plugins/dates/README.md b/plugins/dates/README.md index d8aac5b60..ab87da0f3 100644 --- a/plugins/dates/README.md +++ b/plugins/dates/README.md @@ -16,7 +16,7 @@
npm install compromise-dates
- Work-in-Progress + -work-in-Progress- diff --git a/plugins/dates/builds/compromise-dates.js b/plugins/dates/builds/compromise-dates.js index 2fbf85741..d0aea2f60 100644 --- a/plugins/dates/builds/compromise-dates.js +++ b/plugins/dates/builds/compromise-dates.js @@ -1,4 +1,4 @@ -/* compromise-dates 1.4.0 MIT */ +/* compromise-dates 1.4.1 MIT */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : @@ -5313,7 +5313,8 @@ var data = [[dates, '#Date'], [durations, '#Duration'], [holidays, '#Holiday'], [times, '#Time'], [Object.keys(_timezones), '#Timezone']]; var lex = { - 'a couple': 'Value' + 'a couple': 'Value', + thur: 'WeekDay' }; data.forEach(function (a) { for (var i = 0; i < a[0].length; i++) { @@ -8511,7 +8512,9 @@ Doc.prototype.durations = function (n) { var m = this.match('#Value+ #Duration (and? #Value+ #Duration)?'); // add '20mins' - m = m.concat(this.match('(#Duration && /[0-9][a-z]+$/)')); + m = m.concat(this.match('(#Duration && /[0-9][a-z]+$/)')); // not 'in 20 minutes' + + m = m.notIf('#DateShift'); if (typeof n === 'number') { m = m.get(n); @@ -8615,6 +8618,74 @@ var times$1 = addTimes; + var findDate = function findDate(doc) { + // let r = this.clauses() + var dates = doc.match('#Date+'); // ignore only-durations like '20 minutes' + + dates = dates.filter(function (m) { + var isDuration = m.has('^#Duration+$') || m.has('^#Value #Duration+$'); // allow 'q4', etc + + if (isDuration === true && m.has('(#FinancialQuarter|quarter)')) { + return true; + } + + return isDuration === false; + }); // 30 minutes on tuesday + + var m = dates.match('[#Cardinal #Duration (in|on|this|next|during|for)] #Date', 0); + + if (m.found) { + dates = dates.not(m); + } // 30 minutes tuesday + + + m = dates.match('[#Cardinal #Duration] #WeekDay', 0); + + if (m.found) { + dates = dates.not(m); + } // tuesday for 30 mins + + + m = dates.match('#Date [for #Value #Duration]$', 0); + + if (m.found) { + dates = dates.not(m); + } // 'tuesday, wednesday' + + + m = dates.match('^[#WeekDay] #WeekDay$', 0); + + if (m.found) { + dates = dates.splitAfter(m); + dates = dates.not('^(and|or)'); + } // 'tuesday, wednesday, and friday' + + + m = dates.match('#WeekDay #WeekDay and #WeekDay'); + + if (m.found) { + dates = dates.splitOn('#WeekDay'); + dates = dates.not('^(and|or)'); + } // for 20 minutes + + + m = dates.match('for #Cardinal #Duration'); + + if (m.found) { + dates = dates.not(m); + } // // 'january, february' + // m = dates.match('^[#Month] (and|or)? #Month$', 0) + // if (m.found) { + // dates = dates.splitAfter(m) + // dates = dates.not('^(and|or)') + // } + + + return dates; + }; + + var find = findDate; + var opts = { punt: { weeks: 2 @@ -8663,19 +8734,8 @@ n = null; } - context = Object.assign({}, context, opts); // let r = this.clauses() - - var dates = this.match('#Date+'); // ignore only-durations like '20 minutes' - - dates = dates.filter(function (m) { - var isDuration = m.has('^#Duration+$') || m.has('^#Value #Duration+$'); // allow 'q4', etc - - if (isDuration === true && m.has('#FinancialQuarter')) { - isDuration = false; - } - - return isDuration === false; - }); + context = Object.assign({}, context, opts); + var dates = find(this); if (typeof n === 'number') { dates = dates.get(n); diff --git a/plugins/dates/builds/compromise-dates.js.map b/plugins/dates/builds/compromise-dates.js.map index 721c54602..3e46f2049 100644 --- a/plugins/dates/builds/compromise-dates.js.map +++ b/plugins/dates/builds/compromise-dates.js.map @@ -1 +1 @@ -{"version":3,"file":"compromise-dates.js","sources":["../src/01-tagger/00-basic.js","../src/01-tagger/01-values.js","../src/01-tagger/02-dates.js","../src/01-tagger/03-sections.js","../src/01-tagger/04-time.js","../src/01-tagger/05-shifts.js","../src/01-tagger/06-intervals.js","../src/01-tagger/07-fixup.js","../src/01-tagger/index.js","../src/data/_tags.js","../node_modules/spacetime/builds/spacetime.js","../src/data/_timezones.js","../src/data/words/dates.js","../src/data/words/durations.js","../src/data/words/holidays.js","../src/data/words/times.js","../src/data/words/index.js","../src/parseDate/units/Unit.js","../src/parseDate/units/_day.js","../src/parseDate/units/_year.js","../src/parseDate/units/_week.js","../src/parseDate/units/_time.js","../src/parseDate/units/index.js","../src/parseDate/01-tokenize/01-shift.js","../src/parseDate/01-tokenize/02-counter.js","../src/parseDate/01-tokenize/03-time.js","../src/parseDate/01-tokenize/04-relative.js","../src/parseDate/01-tokenize/05-section.js","../src/parseDate/01-tokenize/06-timezone.js","../src/parseDate/01-tokenize/07-weekday.js","../src/parseDate/02-parse/01-today.js","../node_modules/spacetime-holiday/builds/spacetime-holiday.js","../src/parseDate/02-parse/02-holidays.js","../src/parseDate/02-parse/03-next-last.js","../src/parseDate/02-parse/04-yearly.js","../src/parseDate/02-parse/05-explicit.js","../src/parseDate/03-transform/addCounter.js","../src/parseDate/parse.js","../src/02-ranges/intervals.js","../src/02-ranges/ranges.js","../src/02-ranges/index.js","../src/normalize.js","../src/generate.js","../src/parse.js","../src/data/_abbrevs.js","../src/methods.js","../src/durations/parse.js","../src/durations/index.js","../src/times/parse.js","../src/times/index.js","../src/index.js"],"sourcesContent":["//ambiguous 'may' and 'march'\nconst preps = '(in|by|before|during|on|until|after|of|within|all)' //6\nconst thisNext = '(last|next|this|previous|current|upcoming|coming)' //2\nconst sections = '(start|end|middle|starting|ending|midpoint|beginning)' //2\nconst seasons = '(spring|summer|winter|fall|autumn)'\n\n//ensure a year is approximately typical for common years\n//please change in one thousand years\nconst tagYear = (m, reason) => {\n if (m.found !== true) {\n return\n }\n m.forEach((p) => {\n let str = p.text('reduced')\n let num = parseInt(str, 10)\n if (num && num > 1000 && num < 3000) {\n p.tag('Year', reason)\n }\n })\n}\n//same, but for less-confident values\nconst tagYearSafe = (m, reason) => {\n if (m.found !== true) {\n return\n }\n m.forEach((p) => {\n let str = p.text('reduced')\n let num = parseInt(str, 10)\n if (num && num > 1900 && num < 2030) {\n p.tag('Year', reason)\n }\n })\n}\n\nconst tagDates = function (doc) {\n // in the evening\n doc.match('in the (night|evening|morning|afternoon|day|daytime)').tag('Time', 'in-the-night')\n // 8 pm\n doc.match('(#Value|#Time) (am|pm)').tag('Time', 'value-ampm')\n // 22-aug\n // doc.match('/^[0-9]{2}-(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov)/').tag('Date', '20-jan')\n // 2012-06\n doc.match('/^[0-9]{4}-[0-9]{2}$/').tag('Date', '2012-06')\n\n // misc weekday words\n doc.match('(tue|thu)').tag('WeekDay', 'misc-weekday')\n\n //months:\n let month = doc.if('#Month')\n if (month.found === true) {\n //June 5-7th\n month.match(`#Month #Date+`).tag('Date', 'correction-numberRange')\n //5th of March\n month.match('#Value of #Month').tag('Date', 'value-of-month')\n //5 March\n month.match('#Cardinal #Month').tag('Date', 'cardinal-month')\n //march 5 to 7\n month.match('#Month #Value to #Value').tag('Date', 'value-to-value')\n //march the 12th\n month.match('#Month the #Value').tag('Date', 'month-the-value')\n }\n\n //months:\n let val = doc.if('#Value')\n if (val.found === true) {\n //june 7\n val.match('(#WeekDay|#Month) #Value').ifNo('#Money').tag('Date', 'date-value')\n\n //7 june\n val.match('#Value (#WeekDay|#Month)').ifNo('#Money').tag('Date', 'value-date')\n\n //may twenty five\n val.match('#TextValue #TextValue').if('#Date').tag('#Date', 'textvalue-date')\n\n //two thursdays back\n val.match('#Value (#WeekDay|#Duration) back').tag('#Date', '3-back')\n\n //eg 'year'\n let duration = val.if('#Duration')\n if (duration.found === true) {\n //for 4 months\n duration.match('for #Value #Duration').tag('Date', 'for-x-duration')\n //two days before\n duration.match('#Value #Duration #Conjunction').tag('Date', 'val-duration-conjunction')\n //for four days\n duration.match(`${preps}? #Value #Duration`).tag('Date', 'value-duration')\n //two years old\n duration.match('#Value #Duration old').unTag('Date', 'val-years-old')\n }\n }\n\n //seasons\n let season = doc.if(seasons)\n if (season.found === true) {\n season.match(`${preps}? ${thisNext} ${seasons}`).tag('Date', 'thisNext-season')\n season.match(`the? ${sections} of ${seasons}`).tag('Date', 'section-season')\n season.match(`${seasons} ${preps}? #Cardinal`).tag('Date', 'season-year')\n }\n\n //rest-dates\n let date = doc.if('#Date')\n if (date.found === true) {\n //june the 5th\n date.match('#Date the? #Ordinal').tag('Date', 'correction')\n //last month\n date.match(`${thisNext} #Date`).tag('Date', 'thisNext')\n //by 5 March\n date.match('due? (by|before|after|until) #Date').tag('Date', 'by')\n //next feb\n date.match('(last|next|this|previous|current|upcoming|coming|the) #Date').tag('Date', 'next-feb')\n //start of june\n date.match(`the? ${sections} of #Date`).tag('Date', 'section-of')\n //fifth week in 1998\n date.match('#Ordinal #Duration in #Date').tag('Date', 'duration-in')\n //early in june\n date.match('(early|late) (at|in)? the? #Date').tag('Time', 'early-evening')\n //tomorrow before 3\n date.match('#Date (by|before|after|at|@|about) #Cardinal').not('^#Date').tag('Time', 'date-before-Cardinal')\n //saturday am\n date.match('#Date [(am|pm)]', 0).unTag('Verb').unTag('Copula').tag('Time', 'date-am')\n //feb to june\n date.match('#Date (#Preposition|to) #Date').ifNo('#Duration').tag('Date', 'date-prep-date')\n //2nd quarter of 2019\n // date.match('#Date of #Date').tag('Date', 'date-of-date')\n }\n\n //year/cardinal tagging\n let cardinal = doc.if('#Cardinal')\n if (cardinal.found === true) {\n let v = cardinal.match(`#Date #Value [#Cardinal]`, 0)\n tagYear(v, 'date-value-year')\n //scoops up a bunch\n v = cardinal.match(`#Date [#Cardinal]`, 0)\n tagYearSafe(v, 'date-year')\n //middle of 1999\n v = cardinal.match(`${sections} of [#Cardinal]`)\n tagYearSafe(v, 'section-year')\n //feb 8 2018\n v = cardinal.match(`#Month #Value [#Cardinal]`, 0)\n tagYear(v, 'month-value-year')\n //feb 8 to 10th 2018\n v = cardinal.match(`#Month #Value to #Value [#Cardinal]`, 0)\n tagYear(v, 'month-range-year')\n //in 1998\n v = cardinal.match(`(in|of|by|during|before|starting|ending|for|year|since) [#Cardinal]`, 0)\n tagYear(v, 'in-year-1')\n //q2 2009\n v = cardinal.match('(q1|q2|q3|q4) [#Cardinal]', 0)\n tagYear(v, 'in-year-2')\n //2nd quarter 2009\n v = cardinal.match('#Ordinal quarter of? [#Cardinal]', 0)\n tagYear(v, 'in-year-3')\n //in the year 1998\n v = cardinal.match('the year [#Cardinal]', 0)\n tagYear(v, 'in-year-4')\n //it was 1998\n v = cardinal.match('it (is|was) [#Cardinal]', 0)\n tagYearSafe(v, 'in-year-5')\n // re-tag this part\n cardinal.match(`${sections} of #Year`).tag('Date')\n //between 1999 and 1998\n let m = cardinal.match('between [#Cardinal] and [#Cardinal]')\n tagYear(m.groups('0'), 'between-year-and-year-1')\n tagYear(m.groups('1'), 'between-year-and-year-2')\n }\n\n let time = doc.if('#Time')\n if (time.found === true) {\n //by 6pm\n time.match('(by|before|after|at|@|about) #Time').tag('Time', 'preposition-time')\n //7 7pm\n // time.match('#Cardinal #Time').not('#Year').tag('Time', 'value-time')\n //2pm est\n time.match('#Time [(eastern|pacific|central|mountain)]', 0).tag('Date', 'timezone')\n //6pm est\n time.match('#Time [(est|pst|gmt)]', 0).tag('Date', 'timezone abbr')\n }\n //'2020' bare input\n let m = doc.match('^/^20[012][0-9]$/$')\n tagYearSafe(m, '2020-ish')\n\n // in 20mins\n doc.match('(in|after) /^[0-9]+(min|sec|wk)s?/').tag('Date', 'shift-units')\n return doc\n}\nmodule.exports = tagDates\n","const here = 'date-values'\n//\nconst values = function (doc) {\n // a year ago\n if (!doc.has('once [a] #Duration')) {\n doc.match('[a] #Duration', 0).replaceWith('1').tag('Cardinal', here)\n }\n if (doc.has('#Value')) {\n //june 5 to 7th\n doc.match('#Month #Value to #Value of? #Year?').tag('Date', here)\n //5 to 7th june\n doc.match('#Value to #Value of? #Month #Year?').tag('Date', here)\n //third week of may\n doc.match('#Value #Duration of #Date').tag('Date', here)\n //two days after\n doc.match('#Value+ #Duration (after|before|into|later|afterwards|ago)?').tag('Date', here)\n //two days\n doc.match('#Value #Date').tag('Date', here)\n //june 5th\n doc.match('#Date #Value').tag('Date', here)\n //tuesday at 5\n doc.match('#Date #Preposition #Value').tag('Date', here)\n //tomorrow before 3\n doc.match('#Date (after|before|during|on|in) #Value').tag('Date', here)\n //a year and a half\n doc.match('#Value (year|month|week|day) and a half').tag('Date', here)\n //5 and a half years\n doc.match('#Value and a half (years|months|weeks|days)').tag('Date', here)\n //on the fifth\n doc.match('on the #Ordinal').tag('Date', here)\n }\n return doc\n}\nmodule.exports = values\n","const here = 'date-tagger'\n//\nconst dateTagger = function (doc) {\n doc.match('(spring|summer|winter|fall|autumn|springtime|wintertime|summertime)').match('#Noun').tag('Season', here)\n doc.match('(q1|q2|q3|q4)').tag('FinancialQuarter', here)\n doc.match('(this|next|last|current) quarter').tag('FinancialQuarter', here)\n doc.match('(this|next|last|current) season').tag('Season', here)\n\n if (doc.has('#Date')) {\n //friday to sunday\n doc.match('#Date #Preposition #Date').tag('Date', here)\n //once a day..\n doc.match('(once|twice) (a|an|each) #Date').tag('Date', here)\n //TODO:fixme\n doc.match('(by|until|on|in|at|during|over|every|each|due) the? #Date').tag('Date', here)\n //tuesday\n doc.match('#Date+').tag('Date', here)\n //by June\n doc.match('(by|until|on|in|at|during|over|every|each|due) the? #Date').tag('Date', here)\n //a year after..\n doc.match('a #Duration').tag('Date', here)\n //between x and y\n doc.match('(between|from) #Date').tag('Date', here)\n doc.match('(to|until|upto) #Date').tag('Date', here)\n doc.match('#Date and #Date').tag('Date', here)\n //during this june\n doc.match('(by|until|after|before|during|on|in|following|since) (next|this|last)? (#Date|#Date)').tag('Date', here)\n //day after next\n doc.match('the? #Date after next one?').tag('Date', here)\n //approximately...\n doc.match('(about|approx|approximately|around) #Date').tag('Date', here)\n }\n return doc\n}\nmodule.exports = dateTagger\n","const here = 'section-tagger'\n//\nconst sectionTagger = function (doc) {\n if (doc.has('#Date')) {\n // //next september\n doc.match('this? (last|next|past|this|previous|current|upcoming|coming|the) #Date').tag('Date', here)\n //starting this june\n doc.match('(starting|beginning|ending) #Date').tag('Date', here)\n //start of june\n doc.match('the? (start|end|middle|beginning) of (last|next|this|the) (#Date|#Date)').tag('Date', here)\n //this coming june\n doc.match('(the|this) #Date').tag('Date', here)\n //january up to june\n doc.match('#Date up to #Date').tag('Date', here)\n }\n return doc\n}\nmodule.exports = sectionTagger\n","const here = 'time-tagger'\n\n//\nconst timeTagger = function (doc) {\n // 2 oclock\n doc.match('#Cardinal oclock').tag('Time', here)\n // 13h30\n doc.match('/^[0-9]{2}h[0-9]{2}$/').tag('Time', here)\n // 03/02\n doc.match('/^[0-9]{2}/[0-9]{2}/').tag('Date', here).unTag('Value')\n // 3 in the morning\n doc.match('[#Value] (in|at) the? (morning|evening|night|nighttime)').tag('Time', here)\n if (doc.has('#Cardinal') && !doc.has('#Month')) {\n // quarter to seven (not march 5 to 7)\n doc.match('1? (half|quarter|25|15|10|5) (past|after|to) #Cardinal').tag('Time', here)\n // ten to seven\n doc.match('(5|10|15|20|five|ten|fifteen|20) (to|after|past) [#Cardinal]').tag('Time', here) //add check for 1 to 1 etc.\n }\n //timezone\n if (doc.has('#Date')) {\n // iso (2020-03-02T00:00:00.000Z)\n doc.match('/^[0-9]{4}[:-][0-9]{2}[:-][0-9]{2}T[0-9]/').tag('Time', here)\n // tuesday at 4\n doc.match('#Date [at #Cardinal]', 0).notIf('#Year').tag('Time', here)\n // half an hour\n doc.match('half an (hour|minute|second)').tag('Date', here)\n //eastern daylight time\n doc.match('#Noun (standard|daylight|central|mountain)? time').tag('Timezone', here)\n //utc+5\n doc.match('/^utc[+-][0-9]/').tag('Timezone', here)\n doc.match('/^gmt[+-][0-9]/').tag('Timezone', here)\n\n doc.match('(in|for|by|near|at) #Timezone').tag('Timezone', here)\n // 2pm eastern\n doc.match('#Time [(eastern|mountain|pacific|central)]', 0).tag('Timezone', here)\n }\n // around four thirty\n doc.match('(at|around|near) [#Cardinal (thirty|fifteen) (am|pm)?]', 0).tag('Time', here)\n return doc\n}\nmodule.exports = timeTagger\n","const here = 'shift-tagger'\n//\nconst shiftTagger = function (doc) {\n if (doc.has('#Date')) {\n //'two days before'/ 'nine weeks frow now'\n doc.match('#Cardinal #Duration (before|after|ago|from|hence|back)').tag('DateShift', here)\n // in two weeks\n doc.match('in #Cardinal #Duration').tag('DateShift', here)\n // in a few weeks\n doc.match('in a (few|couple) of? #Duration').tag('DateShift', here)\n //two weeks and three days before\n doc.match('#Cardinal #Duration and? #DateShift').tag('DateShift', here)\n doc.match('#DateShift and #Cardinal #Duration').tag('DateShift', here)\n // 'day after tomorrow'\n doc.match('[#Duration (after|before)] #Date', 0).tag('DateShift', here)\n // in half an hour\n doc.match('in half (a|an) #Duration').tag('DateShift', here)\n }\n return doc\n}\nmodule.exports = shiftTagger\n","const tagIntervals = function (doc) {\n // july 3rd and 4th\n doc.match('#Month #Ordinal and #Ordinal').tag('Date', 'ord-and-ord')\n // every other week\n doc.match('every other #Duration').tag('Date', 'every-other')\n // every weekend\n doc.match('(every|any|each|a) (day|weekday|week day|weekend|weekend day)').tag('Date', 'any-weekday')\n // any-wednesday\n doc.match('(every|any|each|a) (#WeekDay)').tag('Date', 'any-wednesday')\n // any week\n doc.match('(every|any|each|a) (#Duration)').tag('Date', 'any-week')\n}\nmodule.exports = tagIntervals\n","const here = 'fix-tagger'\n//\nconst fixUp = function (doc) {\n //fixups\n if (doc.has('#Date')) {\n //first day by monday\n let oops = doc.match('#Date+ by #Date+')\n if (oops.found && !oops.has('^due')) {\n oops.match('^#Date+').unTag('Date', 'by-monday')\n }\n\n let d = doc.match('#Date+')\n //'spa day'\n d.match('^day$').unTag('Date', 'spa-day')\n // tomorrow's meeting\n d.match('(in|of|by|for)? (#Possessive && #Date)').unTag('Date', 'tomorrows meeting')\n\n let knownDate = '(yesterday|today|tomorrow)'\n if (d.has(knownDate)) {\n //yesterday 7\n d.match(`${knownDate} [#Value]$`).unTag('Date', 'yesterday-7')\n //7 yesterday\n d.match(`^[#Value] ${knownDate}$`, 0).unTag('Date', '7 yesterday')\n //friday yesterday\n d.match(`#WeekDay+ ${knownDate}$`).unTag('Date').lastTerm().tag('Date', 'fri-yesterday')\n\n // yesterday yesterday\n // d.match(`${knownDate}+ ${knownDate}$`)\n // .unTag('Date')\n // .lastTerm()\n // .tag('Date', here)\n d.match(`(this|last|next) #Date ${knownDate}$`).unTag('Date').lastTerm().tag('Date', 'this month yesterday')\n }\n //tomorrow on 5\n d.match(`on #Cardinal$`).unTag('Date', here)\n //this tomorrow\n d.match(`this tomorrow`).terms(0).unTag('Date', 'this-tomorrow')\n //q2 2019\n d.match(`(q1|q2|q3|q4) #Year`).tag('Date', here)\n //5 tuesday\n // d.match(`^#Value #WeekDay`).terms(0).unTag('Date');\n //5 next week\n d.match(`^#Value (this|next|last)`).terms(0).unTag('Date', here)\n\n if (d.has('(last|this|next)')) {\n //this month 7\n d.match(`(last|this|next) #Duration #Value`).terms(2).unTag('Date', here)\n //7 this month\n d.match(`!#Month #Value (last|this|next) #Date`).terms(0).unTag('Date', here)\n }\n //january 5 5\n if (d.has('(#Year|#Time|#TextValue|#NumberRange)') === false) {\n d.match('(#Month|#WeekDay) #Value #Value').terms(2).unTag('Date', here)\n }\n //between june\n if (d.has('^between') && !d.has('and .')) {\n d.unTag('Date', here)\n }\n //june june\n if (d.has('#Month #Month') && !d.has('@hasHyphen') && !d.has('@hasComma')) {\n d.match('#Month').lastTerm().unTag('Date', 'month-month')\n }\n // log the hours\n if (d.has('(minutes|seconds|weeks|hours|days|months)') && !d.has('#Value #Duration')) {\n d.match('(minutes|seconds|weeks|hours|days|months)').unTag('Date', 'log-hours')\n }\n // about thanksgiving\n if (d.has('about #Holiday')) {\n d.match('about').unTag('#Date', 'about-thanksgiving')\n }\n\n // second quarter of 2020\n d.match('#Ordinal quarter of? #Year').unTag('Fraction')\n\n // a month from now\n d.match('(from|by|before) now').unTag('Time')\n // dangling date-chunks\n // if (d.has('!#Date (in|of|by|for) !#Date')) {\n // d.unTag('Date', 'dangling-date')\n // }\n // the day after next\n d.match('#Date+').match('^the').unTag('Date')\n }\n return doc\n}\nmodule.exports = fixUp\n","const methods = [\n require('./00-basic'),\n require('./01-values'),\n require('./02-dates'),\n require('./03-sections'),\n require('./04-time'),\n require('./05-shifts'),\n require('./06-intervals'),\n require('./07-fixup'),\n]\n\n// normalizations to run before tagger\nconst normalize = function (doc) {\n // turn '20mins' into '20 mins'\n doc.numbers().normalize() // this is sorta problematic\n return doc\n}\n\n// run each of the taggers\nconst tagDate = function (doc) {\n doc = normalize(doc)\n // run taggers\n methods.forEach((fn) => fn(doc))\n return doc\n}\nmodule.exports = tagDate\n","module.exports = {\n FinancialQuarter: {\n isA: 'Date',\n notA: 'Fraction',\n },\n // 'summer'\n Season: {\n isA: 'Date',\n },\n // '1982'\n Year: {\n isA: ['Date'],\n notA: 'RomanNumeral',\n },\n // 'months'\n Duration: {\n isA: ['Date', 'Noun'],\n },\n // 'easter'\n Holiday: {\n isA: ['Date', 'Noun'],\n },\n // 'PST'\n Timezone: {\n isA: ['Date', 'Noun'],\n notA: ['Adjective', 'DateShift'],\n },\n // 'two weeks before'\n DateShift: {\n isA: ['Date'],\n notA: ['TimeZone', 'Holiday'],\n },\n}\n","/* spencermountain/spacetime 6.12.5 Apache 2.0 */\n(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.spacetime = factory());\n}(this, (function () { 'use strict';\n\n function _slicedToArray(arr, i) {\n return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();\n }\n\n function _arrayWithHoles(arr) {\n if (Array.isArray(arr)) return arr;\n }\n\n function _iterableToArrayLimit(arr, i) {\n if (typeof Symbol === \"undefined\" || !(Symbol.iterator in Object(arr))) return;\n var _arr = [];\n var _n = true;\n var _d = false;\n var _e = undefined;\n\n try {\n for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {\n _arr.push(_s.value);\n\n if (i && _arr.length === i) break;\n }\n } catch (err) {\n _d = true;\n _e = err;\n } finally {\n try {\n if (!_n && _i[\"return\"] != null) _i[\"return\"]();\n } finally {\n if (_d) throw _e;\n }\n }\n\n return _arr;\n }\n\n function _unsupportedIterableToArray(o, minLen) {\n if (!o) return;\n if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n var n = Object.prototype.toString.call(o).slice(8, -1);\n if (n === \"Object\" && o.constructor) n = o.constructor.name;\n if (n === \"Map\" || n === \"Set\") return Array.from(o);\n if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n }\n\n function _arrayLikeToArray(arr, len) {\n if (len == null || len > arr.length) len = arr.length;\n\n for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n\n return arr2;\n }\n\n function _nonIterableRest() {\n throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n }\n\n var MSEC_IN_HOUR = 60 * 60 * 1000; //convert our local date syntax a javascript UTC date\n\n var toUtc = function toUtc(dstChange, offset, year) {\n var _dstChange$split = dstChange.split('/'),\n _dstChange$split2 = _slicedToArray(_dstChange$split, 2),\n month = _dstChange$split2[0],\n rest = _dstChange$split2[1];\n\n var _rest$split = rest.split(':'),\n _rest$split2 = _slicedToArray(_rest$split, 2),\n day = _rest$split2[0],\n hour = _rest$split2[1];\n\n return Date.UTC(year, month - 1, day, hour) - offset * MSEC_IN_HOUR;\n }; // compare epoch with dst change events (in utc)\n\n\n var inSummerTime = function inSummerTime(epoch, start, end, summerOffset, winterOffset) {\n var year = new Date(epoch).getUTCFullYear();\n var startUtc = toUtc(start, winterOffset, year);\n var endUtc = toUtc(end, summerOffset, year); // simple number comparison now\n\n return epoch >= startUtc && epoch < endUtc;\n };\n\n var summerTime = inSummerTime;\n\n // it reproduces some things in ./index.js, but speeds up spacetime considerably\n\n var quickOffset = function quickOffset(s) {\n var zones = s.timezones;\n var obj = zones[s.tz];\n\n if (obj === undefined) {\n console.warn(\"Warning: couldn't find timezone \" + s.tz);\n return 0;\n }\n\n if (obj.dst === undefined) {\n return obj.offset;\n } //get our two possible offsets\n\n\n var jul = obj.offset;\n var dec = obj.offset + 1; // assume it's the same for now\n\n if (obj.hem === 'n') {\n dec = jul - 1;\n }\n\n var split = obj.dst.split('->');\n var inSummer = summerTime(s.epoch, split[0], split[1], jul, dec);\n\n if (inSummer === true) {\n return jul;\n }\n\n return dec;\n };\n\n var quick = quickOffset;\n\n var _build = {\n \t\"9|s\": \"2/dili,2/jayapura\",\n \t\"9|n\": \"2/chita,2/khandyga,2/pyongyang,2/seoul,2/tokyo,11/palau\",\n \t\"9.5|s|04/04:03->10/03:02\": \"4/adelaide,4/broken_hill,4/south,4/yancowinna\",\n \t\"9.5|s\": \"4/darwin,4/north\",\n \t\"8|s|03/08:01->10/04:00\": \"12/casey\",\n \t\"8|s\": \"2/kuala_lumpur,2/makassar,2/singapore,4/perth,4/west\",\n \t\"8|n|03/25:03->09/29:23\": \"2/ulan_bator\",\n \t\"8|n\": \"2/brunei,2/choibalsan,2/chongqing,2/chungking,2/harbin,2/hong_kong,2/irkutsk,2/kuching,2/macao,2/macau,2/manila,2/shanghai,2/taipei,2/ujung_pandang,2/ulaanbaatar\",\n \t\"8.75|s\": \"4/eucla\",\n \t\"7|s\": \"12/davis,2/jakarta,9/christmas\",\n \t\"7|n\": \"2/bangkok,2/barnaul,2/ho_chi_minh,2/hovd,2/krasnoyarsk,2/novokuznetsk,2/novosibirsk,2/phnom_penh,2/pontianak,2/saigon,2/tomsk,2/vientiane\",\n \t\"6|s\": \"12/vostok\",\n \t\"6|n\": \"2/almaty,2/bishkek,2/dacca,2/dhaka,2/kashgar,2/omsk,2/qyzylorda,2/qostanay,2/thimbu,2/thimphu,2/urumqi,9/chagos\",\n \t\"6.5|n\": \"2/rangoon,2/yangon,9/cocos\",\n \t\"5|s\": \"12/mawson,9/kerguelen\",\n \t\"5|n\": \"2/aqtau,2/aqtobe,2/ashgabat,2/ashkhabad,2/atyrau,2/baku,2/dushanbe,2/karachi,2/oral,2/samarkand,2/tashkent,2/yekaterinburg,9/maldives\",\n \t\"5.75|n\": \"2/kathmandu,2/katmandu\",\n \t\"5.5|n\": \"2/calcutta,2/colombo,2/kolkata\",\n \t\"4|s\": \"9/reunion\",\n \t\"4|n\": \"2/dubai,2/muscat,2/tbilisi,2/yerevan,8/astrakhan,8/samara,8/saratov,8/ulyanovsk,8/volgograd,2/volgograd,9/mahe,9/mauritius\",\n \t\"4.5|n|03/22:00->09/21:24\": \"2/tehran\",\n \t\"4.5|n\": \"2/kabul\",\n \t\"3|s\": \"12/syowa,9/antananarivo\",\n \t\"3|n|03/28:03->10/31:04\": \"2/famagusta,2/nicosia,8/athens,8/bucharest,8/helsinki,8/kiev,8/mariehamn,8/nicosia,8/riga,8/sofia,8/tallinn,8/uzhgorod,8/vilnius,8/zaporozhye\",\n \t\"3|n|03/28:02->10/31:03\": \"8/chisinau,8/tiraspol\",\n \t\"3|n|03/28:00->10/30:24\": \"2/beirut\",\n \t\"3|n|03/27:00->10/30:01\": \"2/gaza,2/hebron\",\n \t\"3|n|03/26:02->10/31:02\": \"2/jerusalem,2/tel_aviv\",\n \t\"3|n|03/26:00->10/29:01\": \"2/amman\",\n \t\"3|n|03/26:00->10/28:24\": \"2/damascus\",\n \t\"3|n\": \"0/addis_ababa,0/asmara,0/asmera,0/dar_es_salaam,0/djibouti,0/juba,0/kampala,0/mogadishu,0/nairobi,2/aden,2/baghdad,2/bahrain,2/istanbul,2/kuwait,2/qatar,2/riyadh,8/istanbul,8/kirov,8/minsk,8/moscow,8/simferopol,9/comoro,9/mayotte\",\n \t\"2|s|03/28:02->10/31:02\": \"12/troll\",\n \t\"2|s\": \"0/gaborone,0/harare,0/johannesburg,0/lubumbashi,0/lusaka,0/maputo,0/maseru,0/mbabane\",\n \t\"2|n|03/28:02->10/31:03\": \"0/ceuta,arctic/longyearbyen,3/jan_mayen,8/amsterdam,8/andorra,8/belgrade,8/berlin,8/bratislava,8/brussels,8/budapest,8/busingen,8/copenhagen,8/gibraltar,8/ljubljana,8/luxembourg,8/madrid,8/malta,8/monaco,8/oslo,8/paris,8/podgorica,8/prague,8/rome,8/san_marino,8/sarajevo,8/skopje,8/stockholm,8/tirane,8/vaduz,8/vatican,8/vienna,8/warsaw,8/zagreb,8/zurich\",\n \t\"2|n\": \"0/blantyre,0/bujumbura,0/cairo,0/khartoum,0/kigali,0/tripoli,8/kaliningrad\",\n \t\"1|s|04/02:01->09/03:03\": \"0/windhoek\",\n \t\"1|s\": \"0/kinshasa,0/luanda\",\n \t\"1|n|04/11:03->05/16:02\": \"0/casablanca,0/el_aaiun\",\n \t\"1|n|03/28:01->10/31:02\": \"3/canary,3/faeroe,3/faroe,3/madeira,8/belfast,8/dublin,8/guernsey,8/isle_of_man,8/jersey,8/lisbon,8/london\",\n \t\"1|n\": \"0/algiers,0/bangui,0/brazzaville,0/douala,0/lagos,0/libreville,0/malabo,0/ndjamena,0/niamey,0/porto-novo,0/tunis\",\n \t\"14|n\": \"11/kiritimati\",\n \t\"13|s|04/04:04->09/26:03\": \"11/apia\",\n \t\"13|s|01/15:02->11/05:03\": \"11/tongatapu\",\n \t\"13|n\": \"11/enderbury,11/fakaofo\",\n \t\"12|s|04/04:03->09/26:02\": \"12/mcmurdo,12/south_pole,11/auckland\",\n \t\"12|s|01/17:03->11/14:02\": \"11/fiji\",\n \t\"12|n\": \"2/anadyr,2/kamchatka,2/srednekolymsk,11/funafuti,11/kwajalein,11/majuro,11/nauru,11/tarawa,11/wake,11/wallis\",\n \t\"12.75|s|04/04:03->04/04:02\": \"11/chatham\",\n \t\"11|s|04/04:03->10/03:02\": \"12/macquarie\",\n \t\"11|s\": \"11/bougainville\",\n \t\"11|n\": \"2/magadan,2/sakhalin,11/efate,11/guadalcanal,11/kosrae,11/noumea,11/pohnpei,11/ponape\",\n \t\"11.5|n|04/04:03->10/03:02\": \"11/norfolk\",\n \t\"10|s|04/04:03->10/03:02\": \"4/act,4/canberra,4/currie,4/hobart,4/melbourne,4/nsw,4/sydney,4/tasmania,4/victoria\",\n \t\"10|s\": \"12/dumontdurville,4/brisbane,4/lindeman,4/queensland\",\n \t\"10|n\": \"2/ust-nera,2/vladivostok,2/yakutsk,11/chuuk,11/guam,11/port_moresby,11/saipan,11/truk,11/yap\",\n \t\"10.5|s|04/04:01->10/03:02\": \"4/lhi,4/lord_howe\",\n \t\"0|n|03/28:00->10/31:01\": \"1/scoresbysund,3/azores\",\n \t\"0|n\": \"0/abidjan,0/accra,0/bamako,0/banjul,0/bissau,0/conakry,0/dakar,0/freetown,0/lome,0/monrovia,0/nouakchott,0/ouagadougou,0/sao_tome,0/timbuktu,1/danmarkshavn,3/reykjavik,3/st_helena,13/gmt,13/gmt+0,13/gmt-0,13/gmt0,13/greenwich,13/utc,13/universal,13/zulu\",\n \t\"-9|n|03/14:02->11/07:02\": \"1/adak,1/atka\",\n \t\"-9|n\": \"11/gambier\",\n \t\"-9.5|n\": \"11/marquesas\",\n \t\"-8|n|03/14:02->11/07:02\": \"1/anchorage,1/juneau,1/metlakatla,1/nome,1/sitka,1/yakutat\",\n \t\"-8|n\": \"11/pitcairn\",\n \t\"-7|n|03/14:02->11/07:02\": \"1/ensenada,1/los_angeles,1/santa_isabel,1/tijuana,1/vancouver,6/pacific,10/bajanorte\",\n \t\"-7|n|03/08:02->11/01:01\": \"1/dawson,1/whitehorse,6/yukon\",\n \t\"-7|n\": \"1/creston,1/dawson_creek,1/fort_nelson,1/hermosillo,1/phoenix\",\n \t\"-6|s|04/03:22->09/04:22\": \"7/easterisland,11/easter\",\n \t\"-6|n|04/04:02->10/31:02\": \"1/chihuahua,1/mazatlan,10/bajasur\",\n \t\"-6|n|03/14:02->11/07:02\": \"1/boise,1/cambridge_bay,1/denver,1/edmonton,1/inuvik,1/ojinaga,1/shiprock,1/yellowknife,6/mountain\",\n \t\"-6|n\": \"1/belize,1/costa_rica,1/el_salvador,1/guatemala,1/managua,1/regina,1/swift_current,1/tegucigalpa,6/east-saskatchewan,6/saskatchewan,11/galapagos\",\n \t\"-5|s\": \"1/lima,1/rio_branco,5/acre\",\n \t\"-5|n|04/04:02->10/31:02\": \"1/bahia_banderas,1/merida,1/mexico_city,1/monterrey,10/general\",\n \t\"-5|n|03/14:02->11/07:02\": \"1/chicago,1/knox_in,1/matamoros,1/menominee,1/rainy_river,1/rankin_inlet,1/resolute,1/winnipeg,6/central\",\n \t\"-5|n|03/12:03->11/05:01\": \"1/north_dakota\",\n \t\"-5|n\": \"1/atikokan,1/bogota,1/cancun,1/cayman,1/coral_harbour,1/eirunepe,1/guayaquil,1/jamaica,1/panama,1/porto_acre\",\n \t\"-4|s|05/13:23->08/13:01\": \"12/palmer\",\n \t\"-4|s|04/03:24->09/05:00\": \"1/santiago,7/continental\",\n \t\"-4|s|03/27:24->10/03:00\": \"1/asuncion\",\n \t\"-4|s|02/16:24->11/03:00\": \"1/campo_grande,1/cuiaba\",\n \t\"-4|s\": \"1/la_paz,1/manaus,5/west\",\n \t\"-4|n|03/14:02->11/07:02\": \"1/detroit,1/fort_wayne,1/grand_turk,1/indianapolis,1/iqaluit,1/louisville,1/montreal,1/nassau,1/new_york,1/nipigon,1/pangnirtung,1/port-au-prince,1/thunder_bay,1/toronto,6/eastern\",\n \t\"-4|n|03/14:00->11/07:01\": \"1/havana\",\n \t\"-4|n|03/12:03->11/05:01\": \"1/indiana,1/kentucky\",\n \t\"-4|n\": \"1/anguilla,1/antigua,1/aruba,1/barbados,1/blanc-sablon,1/boa_vista,1/caracas,1/curacao,1/dominica,1/grenada,1/guadeloupe,1/guyana,1/kralendijk,1/lower_princes,1/marigot,1/martinique,1/montserrat,1/port_of_spain,1/porto_velho,1/puerto_rico,1/santo_domingo,1/st_barthelemy,1/st_kitts,1/st_lucia,1/st_thomas,1/st_vincent,1/tortola,1/virgin\",\n \t\"-3|s\": \"1/argentina,1/buenos_aires,1/cordoba,1/fortaleza,1/montevideo,1/punta_arenas,1/sao_paulo,12/rothera,3/stanley,5/east\",\n \t\"-3|n|03/27:22->10/30:23\": \"1/nuuk\",\n \t\"-3|n|03/14:02->11/07:02\": \"1/glace_bay,1/goose_bay,1/halifax,1/moncton,1/thule,3/bermuda,6/atlantic\",\n \t\"-3|n\": \"1/araguaina,1/bahia,1/belem,1/catamarca,1/cayenne,1/jujuy,1/maceio,1/mendoza,1/paramaribo,1/recife,1/rosario,1/santarem\",\n \t\"-2|s\": \"5/denoronha\",\n \t\"-2|n|03/27:22->10/30:23\": \"1/godthab\",\n \t\"-2|n|03/14:02->11/07:02\": \"1/miquelon\",\n \t\"-2|n\": \"1/noronha,3/south_georgia\",\n \t\"-2.5|n|03/14:02->11/07:02\": \"1/st_johns,6/newfoundland\",\n \t\"-1|n\": \"3/cape_verde\",\n \t\"-11|n\": \"11/midway,11/niue,11/pago_pago,11/samoa\",\n \t\"-10|n\": \"11/honolulu,11/johnston,11/rarotonga,11/tahiti\"\n };\n\n var _build$1 = /*#__PURE__*/Object.freeze({\n __proto__: null,\n 'default': _build\n });\n\n //prefixes for iana names..\n var _prefixes = ['africa', 'america', 'asia', 'atlantic', 'australia', 'brazil', 'canada', 'chile', 'europe', 'indian', 'mexico', 'pacific', 'antarctica', 'etc'];\n\n function createCommonjsModule(fn, module) {\n \treturn module = { exports: {} }, fn(module, module.exports), module.exports;\n }\n\n function getCjsExportFromNamespace (n) {\n \treturn n && n['default'] || n;\n }\n\n var data = getCjsExportFromNamespace(_build$1);\n\n var all = {};\n Object.keys(data).forEach(function (k) {\n var split = k.split('|');\n var obj = {\n offset: Number(split[0]),\n hem: split[1]\n };\n\n if (split[2]) {\n obj.dst = split[2];\n }\n\n var names = data[k].split(',');\n names.forEach(function (str) {\n str = str.replace(/(^[0-9]+)\\//, function (before, num) {\n num = Number(num);\n return _prefixes[num] + '/';\n });\n all[str] = obj;\n });\n });\n all['utc'] = {\n offset: 0,\n hem: 'n' //default to northern hemisphere - (sorry!)\n\n }; //add etc/gmt+n\n\n for (var i = -14; i <= 14; i += 0.5) {\n var num = i;\n\n if (num > 0) {\n num = '+' + num;\n }\n\n var name = 'etc/gmt' + num;\n all[name] = {\n offset: i * -1,\n //they're negative!\n hem: 'n' //(sorry)\n\n };\n name = 'utc/gmt' + num; //this one too, why not.\n\n all[name] = {\n offset: i * -1,\n hem: 'n'\n };\n }\n\n var unpack = all;\n\n //find the implicit iana code for this machine.\n //safely query the Intl object\n //based on - https://bitbucket.org/pellepim/jstimezonedetect/src\n var fallbackTZ = 'utc'; //\n //this Intl object is not supported often, yet\n\n var safeIntl = function safeIntl() {\n if (typeof Intl === 'undefined' || typeof Intl.DateTimeFormat === 'undefined') {\n return null;\n }\n\n var format = Intl.DateTimeFormat();\n\n if (typeof format === 'undefined' || typeof format.resolvedOptions === 'undefined') {\n return null;\n }\n\n var timezone = format.resolvedOptions().timeZone;\n\n if (!timezone) {\n return null;\n }\n\n return timezone.toLowerCase();\n };\n\n var guessTz = function guessTz() {\n var timezone = safeIntl();\n\n if (timezone === null) {\n return fallbackTZ;\n }\n\n return timezone;\n }; //do it once per computer\n\n\n var guessTz_1 = guessTz;\n\n var isOffset = /(\\-?[0-9]+)h(rs)?/i;\n var isNumber = /(\\-?[0-9]+)/;\n var utcOffset = /utc([\\-+]?[0-9]+)/i;\n var gmtOffset = /gmt([\\-+]?[0-9]+)/i;\n\n var toIana = function toIana(num) {\n num = Number(num);\n\n if (num >= -13 && num <= 13) {\n num = num * -1; //it's opposite!\n\n num = (num > 0 ? '+' : '') + num; //add plus sign\n\n return 'etc/gmt' + num;\n }\n\n return null;\n };\n\n var parseOffset = function parseOffset(tz) {\n // '+5hrs'\n var m = tz.match(isOffset);\n\n if (m !== null) {\n return toIana(m[1]);\n } // 'utc+5'\n\n\n m = tz.match(utcOffset);\n\n if (m !== null) {\n return toIana(m[1]);\n } // 'GMT-5' (not opposite)\n\n\n m = tz.match(gmtOffset);\n\n if (m !== null) {\n var num = Number(m[1]) * -1;\n return toIana(num);\n } // '+5'\n\n\n m = tz.match(isNumber);\n\n if (m !== null) {\n return toIana(m[1]);\n }\n\n return null;\n };\n\n var parseOffset_1 = parseOffset;\n\n var local = guessTz_1(); //add all the city names by themselves\n\n var cities = Object.keys(unpack).reduce(function (h, k) {\n var city = k.split('/')[1] || '';\n city = city.replace(/_/g, ' ');\n h[city] = k;\n return h;\n }, {}); //try to match these against iana form\n\n var normalize = function normalize(tz) {\n tz = tz.replace(/ time/g, '');\n tz = tz.replace(/ (standard|daylight|summer)/g, '');\n tz = tz.replace(/\\b(east|west|north|south)ern/g, '$1');\n tz = tz.replace(/\\b(africa|america|australia)n/g, '$1');\n tz = tz.replace(/\\beuropean/g, 'europe');\n tz = tz.replace(/\\islands/g, 'island');\n return tz;\n }; // try our best to reconcile the timzone to this given string\n\n\n var lookupTz = function lookupTz(str, zones) {\n if (!str) {\n return local;\n }\n\n if (typeof str !== 'string') {\n console.error(\"Timezone must be a string - recieved: '\", str, \"'\\n\");\n }\n\n var tz = str.trim();\n var split = str.split('/'); //support long timezones like 'America/Argentina/Rio_Gallegos'\n\n if (split.length > 2 && zones.hasOwnProperty(tz) === false) {\n tz = split[0] + '/' + split[1];\n }\n\n tz = tz.toLowerCase();\n\n if (zones.hasOwnProperty(tz) === true) {\n return tz;\n } //lookup more loosely..\n\n\n tz = normalize(tz);\n\n if (zones.hasOwnProperty(tz) === true) {\n return tz;\n } //try city-names\n\n\n if (cities.hasOwnProperty(tz) === true) {\n return cities[tz];\n } // //try to parse '-5h'\n\n\n if (/[0-9]/.test(tz) === true) {\n var id = parseOffset_1(tz);\n\n if (id) {\n return id;\n }\n }\n\n throw new Error(\"Spacetime: Cannot find timezone named: '\" + str + \"'. Please enter an IANA timezone id.\");\n };\n\n var find = lookupTz;\n\n var o = {\n millisecond: 1\n };\n o.second = 1000;\n o.minute = 60000;\n o.hour = 3.6e6; // dst is supported post-hoc\n\n o.day = 8.64e7; //\n\n o.date = o.day;\n o.month = 8.64e7 * 29.5; //(average)\n\n o.week = 6.048e8;\n o.year = 3.154e10; // leap-years are supported post-hoc\n //add plurals\n\n Object.keys(o).forEach(function (k) {\n o[k + 's'] = o[k];\n });\n var milliseconds = o;\n\n var walk = function walk(s, n, fn, unit, previous) {\n var current = s.d[fn]();\n\n if (current === n) {\n return; //already there\n }\n\n var startUnit = previous === null ? null : s.d[previous]();\n var original = s.epoch; //try to get it as close as we can\n\n var diff = n - current;\n s.epoch += milliseconds[unit] * diff; //DST edge-case: if we are going many days, be a little conservative\n // console.log(unit, diff)\n\n if (unit === 'day') {\n // s.epoch -= ms.minute\n //but don't push it over a month\n if (Math.abs(diff) > 28 && n < 28) {\n s.epoch += milliseconds.hour;\n }\n } // 1st time: oops, did we change previous unit? revert it.\n\n\n if (previous !== null && startUnit !== s.d[previous]()) {\n // console.warn('spacetime warning: missed setting ' + unit)\n s.epoch = original; // s.epoch += ms[unit] * diff * 0.89 // maybe try and make it close...?\n } //repair it if we've gone too far or something\n //(go by half-steps, just in case)\n\n\n var halfStep = milliseconds[unit] / 2;\n\n while (s.d[fn]() < n) {\n s.epoch += halfStep;\n }\n\n while (s.d[fn]() > n) {\n s.epoch -= halfStep;\n } // 2nd time: did we change previous unit? revert it.\n\n\n if (previous !== null && startUnit !== s.d[previous]()) {\n // console.warn('spacetime warning: missed setting ' + unit)\n s.epoch = original;\n }\n }; //find the desired date by a increment/check while loop\n\n\n var units = {\n year: {\n valid: function valid(n) {\n return n > -4000 && n < 4000;\n },\n walkTo: function walkTo(s, n) {\n return walk(s, n, 'getFullYear', 'year', null);\n }\n },\n month: {\n valid: function valid(n) {\n return n >= 0 && n <= 11;\n },\n walkTo: function walkTo(s, n) {\n var d = s.d;\n var current = d.getMonth();\n var original = s.epoch;\n var startUnit = d.getFullYear();\n\n if (current === n) {\n return;\n } //try to get it as close as we can..\n\n\n var diff = n - current;\n s.epoch += milliseconds.day * (diff * 28); //special case\n //oops, did we change the year? revert it.\n\n if (startUnit !== s.d.getFullYear()) {\n s.epoch = original;\n } //increment by day\n\n\n while (s.d.getMonth() < n) {\n s.epoch += milliseconds.day;\n }\n\n while (s.d.getMonth() > n) {\n s.epoch -= milliseconds.day;\n }\n }\n },\n date: {\n valid: function valid(n) {\n return n > 0 && n <= 31;\n },\n walkTo: function walkTo(s, n) {\n return walk(s, n, 'getDate', 'day', 'getMonth');\n }\n },\n hour: {\n valid: function valid(n) {\n return n >= 0 && n < 24;\n },\n walkTo: function walkTo(s, n) {\n return walk(s, n, 'getHours', 'hour', 'getDate');\n }\n },\n minute: {\n valid: function valid(n) {\n return n >= 0 && n < 60;\n },\n walkTo: function walkTo(s, n) {\n return walk(s, n, 'getMinutes', 'minute', 'getHours');\n }\n },\n second: {\n valid: function valid(n) {\n return n >= 0 && n < 60;\n },\n walkTo: function walkTo(s, n) {\n //do this one directly\n s.epoch = s.seconds(n).epoch;\n }\n },\n millisecond: {\n valid: function valid(n) {\n return n >= 0 && n < 1000;\n },\n walkTo: function walkTo(s, n) {\n //do this one directly\n s.epoch = s.milliseconds(n).epoch;\n }\n }\n };\n\n var walkTo = function walkTo(s, wants) {\n var keys = Object.keys(units);\n var old = s.clone();\n\n for (var i = 0; i < keys.length; i++) {\n var k = keys[i];\n var n = wants[k];\n\n if (n === undefined) {\n n = old[k]();\n }\n\n if (typeof n === 'string') {\n n = parseInt(n, 10);\n } //make-sure it's valid\n\n\n if (!units[k].valid(n)) {\n s.epoch = null;\n\n if (s.silent === false) {\n console.warn('invalid ' + k + ': ' + n);\n }\n\n return;\n }\n\n units[k].walkTo(s, n);\n }\n\n return;\n };\n\n var walk_1 = walkTo;\n\n var shortMonths = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sept', 'oct', 'nov', 'dec'];\n var longMonths = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];\n\n function buildMapping() {\n var obj = {\n sep: 8 //support this format\n\n };\n\n for (var i = 0; i < shortMonths.length; i++) {\n obj[shortMonths[i]] = i;\n }\n\n for (var _i = 0; _i < longMonths.length; _i++) {\n obj[longMonths[_i]] = _i;\n }\n\n return obj;\n }\n\n var months = {\n \"short\": function short() {\n return shortMonths;\n },\n \"long\": function long() {\n return longMonths;\n },\n mapping: function mapping() {\n return buildMapping();\n },\n set: function set(i18n) {\n shortMonths = i18n[\"short\"] || shortMonths;\n longMonths = i18n[\"long\"] || longMonths;\n }\n };\n\n //pull-apart ISO offsets, like \"+0100\"\n var parseOffset$1 = function parseOffset(s, offset) {\n if (!offset) {\n return s;\n } //this is a fancy-move\n\n\n if (offset === 'Z' || offset === 'z') {\n offset = '+0000';\n } // according to ISO8601, tz could be hh:mm, hhmm or hh\n // so need few more steps before the calculation.\n\n\n var num = 0; // for (+-)hh:mm\n\n if (/^[\\+-]?[0-9]{2}:[0-9]{2}$/.test(offset)) {\n //support \"+01:00\"\n if (/:00/.test(offset) === true) {\n offset = offset.replace(/:00/, '');\n } //support \"+01:30\"\n\n\n if (/:30/.test(offset) === true) {\n offset = offset.replace(/:30/, '.5');\n }\n } // for (+-)hhmm\n\n\n if (/^[\\+-]?[0-9]{4}$/.test(offset)) {\n offset = offset.replace(/30$/, '.5');\n }\n\n num = parseFloat(offset); //divide by 100 or 10 - , \"+0100\", \"+01\"\n\n if (Math.abs(num) > 100) {\n num = num / 100;\n } //okay, try to match it to a utc timezone\n //remember - this is opposite! a -5 offset maps to Etc/GMT+5 ¯\\_(:/)_/¯\n //https://askubuntu.com/questions/519550/why-is-the-8-timezone-called-gmt-8-in-the-filesystem\n\n\n num *= -1;\n\n if (num >= 0) {\n num = '+' + num;\n }\n\n var tz = 'etc/gmt' + num;\n var zones = s.timezones;\n\n if (zones[tz]) {\n // log a warning if we're over-writing a given timezone?\n // console.log('changing timezone to: ' + tz)\n s.tz = tz;\n }\n\n return s;\n };\n\n var parseOffset_1$1 = parseOffset$1;\n\n var parseTime = function parseTime(s) {\n var str = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n str = str.replace(/^\\s+/, '').toLowerCase(); //trim\n //formal time formats - 04:30.23\n\n var arr = str.match(/([0-9]{1,2}):([0-9]{1,2}):?([0-9]{1,2})?[:\\.]?([0-9]{1,4})?/);\n\n if (arr !== null) {\n //validate it a little\n var h = Number(arr[1]);\n\n if (h < 0 || h > 24) {\n return s.startOf('day');\n }\n\n var m = Number(arr[2]); //don't accept '5:3pm'\n\n if (arr[2].length < 2 || m < 0 || m > 59) {\n return s.startOf('day');\n }\n\n if (arr[4] > 999) {\n // fix overflow issue with milliseconds, if input is longer than standard (e.g. 2017-08-06T09:00:00.123456Z)\n arr[4] = parseInt(\"\".concat(arr[4]).substring(0, 3), 10);\n }\n\n s = s.hour(h);\n s = s.minute(m);\n s = s.seconds(arr[3] || 0);\n s = s.millisecond(arr[4] || 0); //parse-out am/pm\n\n var ampm = str.match(/[\\b0-9](am|pm)\\b/);\n\n if (ampm !== null && ampm[1]) {\n s = s.ampm(ampm[1]);\n }\n\n return s;\n } //try an informal form - 5pm (no minutes)\n\n\n arr = str.match(/([0-9]+) ?(am|pm)/);\n\n if (arr !== null && arr[1]) {\n var _h = Number(arr[1]); //validate it a little..\n\n\n if (_h > 12 || _h < 1) {\n return s.startOf('day');\n }\n\n s = s.hour(arr[1] || 0);\n s = s.ampm(arr[2]);\n s = s.startOf('hour');\n return s;\n } //no time info found, use start-of-day\n\n\n s = s.startOf('day');\n return s;\n };\n\n var parseTime_1 = parseTime;\n\n var monthLengths = [31, // January - 31 days\n 28, // February - 28 days in a common year and 29 days in leap years\n 31, // March - 31 days\n 30, // April - 30 days\n 31, // May - 31 days\n 30, // June - 30 days\n 31, // July - 31 days\n 31, // August - 31 days\n 30, // September - 30 days\n 31, // October - 31 days\n 30, // November - 30 days\n 31 // December - 31 days\n ];\n var monthLengths_1 = monthLengths; // 28 - feb\n\n var fns = createCommonjsModule(function (module, exports) {\n //git:blame @JuliasCaesar https://www.timeanddate.com/date/leapyear.html\n exports.isLeapYear = function (year) {\n return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;\n }; // unsurprisingly-nasty `typeof date` call\n\n\n exports.isDate = function (d) {\n return Object.prototype.toString.call(d) === '[object Date]' && !isNaN(d.valueOf());\n };\n\n exports.isArray = function (input) {\n return Object.prototype.toString.call(input) === '[object Array]';\n };\n\n exports.isObject = function (input) {\n return Object.prototype.toString.call(input) === '[object Object]';\n };\n\n exports.isBoolean = function (input) {\n return Object.prototype.toString.call(input) === '[object Boolean]';\n };\n\n exports.zeroPad = function (str) {\n var len = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2;\n var pad = '0';\n str = str + '';\n return str.length >= len ? str : new Array(len - str.length + 1).join(pad) + str;\n };\n\n exports.titleCase = function (str) {\n if (!str) {\n return '';\n }\n\n return str[0].toUpperCase() + str.substr(1);\n };\n\n exports.ordinal = function (i) {\n var j = i % 10;\n var k = i % 100;\n\n if (j === 1 && k !== 11) {\n return i + 'st';\n }\n\n if (j === 2 && k !== 12) {\n return i + 'nd';\n }\n\n if (j === 3 && k !== 13) {\n return i + 'rd';\n }\n\n return i + 'th';\n }; //strip 'st' off '1st'..\n\n\n exports.toCardinal = function (str) {\n str = String(str);\n str = str.replace(/([0-9])(st|nd|rd|th)$/i, '$1');\n return parseInt(str, 10);\n }; //used mostly for cleanup of unit names, like 'months'\n\n\n exports.normalize = function () {\n var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n str = str.toLowerCase().trim();\n str = str.replace(/ies$/, 'y'); //'centuries'\n\n str = str.replace(/s$/, '');\n str = str.replace(/-/g, '');\n\n if (str === 'day' || str === 'days') {\n return 'date';\n }\n\n if (str === 'min' || str === 'mins') {\n return 'minute';\n }\n\n return str;\n };\n\n exports.getEpoch = function (tmp) {\n //support epoch\n if (typeof tmp === 'number') {\n return tmp;\n } //suport date objects\n\n\n if (exports.isDate(tmp)) {\n return tmp.getTime();\n }\n\n if (tmp.epoch) {\n return tmp.epoch;\n }\n\n return null;\n }; //make sure this input is a spacetime obj\n\n\n exports.beADate = function (d, s) {\n if (exports.isObject(d) === false) {\n return s.clone().set(d);\n }\n\n return d;\n };\n\n exports.formatTimezone = function (offset) {\n var delimiter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n var sign = offset > 0 ? '+' : '-';\n var absOffset = Math.abs(offset);\n var hours = exports.zeroPad(parseInt('' + absOffset, 10));\n var minutes = exports.zeroPad(absOffset % 1 * 60);\n return \"\".concat(sign).concat(hours).concat(delimiter).concat(minutes);\n };\n });\n fns.isLeapYear;\n fns.isDate;\n fns.isArray;\n fns.isObject;\n fns.isBoolean;\n fns.zeroPad;\n fns.titleCase;\n fns.ordinal;\n fns.toCardinal;\n fns.normalize;\n fns.getEpoch;\n fns.beADate;\n fns.formatTimezone;\n\n var isLeapYear = fns.isLeapYear; //given a month, return whether day number exists in it\n\n var hasDate = function hasDate(obj) {\n //invalid values\n if (monthLengths_1.hasOwnProperty(obj.month) !== true) {\n return false;\n } //support leap-year in february\n\n\n if (obj.month === 1) {\n if (isLeapYear(obj.year) && obj.date <= 29) {\n return true;\n } else {\n return obj.date <= 28;\n }\n } //is this date too-big for this month?\n\n\n var max = monthLengths_1[obj.month] || 0;\n\n if (obj.date <= max) {\n return true;\n }\n\n return false;\n };\n\n var hasDate_1 = hasDate;\n\n var months$1 = months.mapping();\n\n var parseYear = function parseYear() {\n var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n var today = arguments.length > 1 ? arguments[1] : undefined;\n var year = parseInt(str.trim(), 10); // use a given year from options.today\n\n if (!year && today) {\n year = today.year;\n } // fallback to this year\n\n\n year = year || new Date().getFullYear();\n return year;\n };\n\n var strFmt = [//iso-this 1998-05-30T22:00:00:000Z, iso-that 2017-04-03T08:00:00-0700\n {\n reg: /^(\\-?0?0?[0-9]{3,4})-([0-9]{1,2})-([0-9]{1,2})[T| ]([0-9.:]+)(Z|[0-9\\-\\+:]+)?$/i,\n parse: function parse(s, arr, givenTz, options) {\n var month = parseInt(arr[2], 10) - 1;\n var obj = {\n year: arr[1],\n month: month,\n date: arr[3]\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n parseOffset_1$1(s, arr[5]);\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //iso \"2015-03-25\" or \"2015/03/25\" or \"2015/03/25 12:26:14 PM\"\n {\n reg: /^([0-9]{4})[\\-\\/.]([0-9]{1,2})[\\-\\/.]([0-9]{1,2}),?( [0-9]{1,2}:[0-9]{2}:?[0-9]{0,2}? ?(am|pm|gmt))?$/i,\n parse: function parse(s, arr) {\n var obj = {\n year: arr[1],\n month: parseInt(arr[2], 10) - 1,\n date: parseInt(arr[3], 10)\n };\n\n if (obj.month >= 12) {\n //support yyyy/dd/mm (weird, but ok)\n obj.date = parseInt(arr[2], 10);\n obj.month = parseInt(arr[3], 10) - 1;\n }\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //mm/dd/yyyy - uk/canada \"6/28/2019, 12:26:14 PM\"\n {\n reg: /^([0-9]{1,2})[\\-\\/.]([0-9]{1,2})[\\-\\/.]?([0-9]{4})?,?( [0-9]{1,2}:[0-9]{2}:?[0-9]{0,2}? ?(am|pm|gmt))?$/i,\n parse: function parse(s, arr) {\n var month = parseInt(arr[1], 10) - 1;\n var date = parseInt(arr[2], 10); //support dd/mm/yyy\n\n if (s.british || month >= 12) {\n date = parseInt(arr[1], 10);\n month = parseInt(arr[2], 10) - 1;\n }\n\n var year = parseYear(arr[3], s._today) || new Date().getFullYear();\n var obj = {\n year: year,\n month: month,\n date: date\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, // '2012-06' last attempt at iso-like format\n {\n reg: /^([0-9]{4})[\\-\\/]([0-9]{2})$/i,\n parse: function parse(s, arr, givenTz, options) {\n var month = parseInt(arr[2], 10) - 1;\n var obj = {\n year: arr[1],\n month: month,\n date: 1\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n parseOffset_1$1(s, arr[5]);\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //common british format - \"25-feb-2015\"\n {\n reg: /^([0-9]{1,2})[\\-\\/]([a-z]+)[\\-\\/]?([0-9]{4})?$/i,\n parse: function parse(s, arr) {\n var month = months$1[arr[2].toLowerCase()];\n var year = parseYear(arr[3], s._today);\n var obj = {\n year: year,\n month: month,\n date: fns.toCardinal(arr[1] || '')\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //alt short format - \"feb-25-2015\"\n {\n reg: /^([a-z]+)[\\-\\/]([0-9]{1,2})[\\-\\/]?([0-9]{4})?$/i,\n parse: function parse(s, arr) {\n var month = months$1[arr[1].toLowerCase()];\n var year = parseYear(arr[3], s._today);\n var obj = {\n year: year,\n month: month,\n date: fns.toCardinal(arr[2] || '')\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //Long \"Mar 25 2015\"\n //February 22, 2017 15:30:00\n {\n reg: /^([a-z]+) ([0-9]{1,2}(?:st|nd|rd|th)?),?( [0-9]{4})?( ([0-9:]+( ?am| ?pm| ?gmt)?))?$/i,\n parse: function parse(s, arr) {\n var month = months$1[arr[1].toLowerCase()];\n var year = parseYear(arr[3], s._today);\n var obj = {\n year: year,\n month: month,\n date: fns.toCardinal(arr[2] || '')\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //February 2017 (implied date)\n {\n reg: /^([a-z]+) ([0-9]{4})$/i,\n parse: function parse(s, arr) {\n var month = months$1[arr[1].toLowerCase()];\n var year = parseYear(arr[2], s._today);\n var obj = {\n year: year,\n month: month,\n date: s._today.date || 1\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, //Long \"25 Mar 2015\"\n {\n reg: /^([0-9]{1,2}(?:st|nd|rd|th)?) ([a-z]+),?( [0-9]{4})?,? ?([0-9]{1,2}:[0-9]{2}:?[0-9]{0,2}? ?(am|pm|gmt))?$/i,\n parse: function parse(s, arr) {\n var month = months$1[arr[2].toLowerCase()];\n\n if (!month) {\n return null;\n }\n\n var year = parseYear(arr[3], s._today);\n var obj = {\n year: year,\n month: month,\n date: fns.toCardinal(arr[1])\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s, arr[4]);\n return s;\n }\n }, {\n // 'q2 2002'\n reg: /^(q[0-9])( of)?( [0-9]{4})?/i,\n parse: function parse(s, arr) {\n var quarter = arr[1] || '';\n s = s.quarter(quarter);\n var year = arr[3] || '';\n\n if (year) {\n year = year.trim();\n s = s.year(year);\n }\n\n return s;\n }\n }, {\n // 'summer 2002'\n reg: /^(spring|summer|winter|fall|autumn)( of)?( [0-9]{4})?/i,\n parse: function parse(s, arr) {\n var season = arr[1] || '';\n s = s.season(season);\n var year = arr[3] || '';\n\n if (year) {\n year = year.trim();\n s = s.year(year);\n }\n\n return s;\n }\n }, {\n // '200bc'\n reg: /^[0-9,]+ ?b\\.?c\\.?$/i,\n parse: function parse(s, arr) {\n var str = arr[0] || ''; //make negative-year\n\n str = str.replace(/^([0-9,]+) ?b\\.?c\\.?$/i, '-$1'); //remove commas\n\n str = str.replace(/,/g, '');\n var year = parseInt(str.trim(), 10);\n var d = new Date();\n var obj = {\n year: year,\n month: d.getMonth(),\n date: d.getDate()\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s);\n return s;\n }\n }, {\n // '200ad'\n reg: /^[0-9,]+ ?(a\\.?d\\.?|c\\.?e\\.?)$/i,\n parse: function parse(s, arr) {\n var str = arr[0] || ''; //remove commas\n\n str = str.replace(/,/g, '');\n var year = parseInt(str.trim(), 10);\n var d = new Date();\n var obj = {\n year: year,\n month: d.getMonth(),\n date: d.getDate()\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s);\n return s;\n }\n }, {\n // '1992'\n reg: /^[0-9]{4}( ?a\\.?d\\.?)?$/i,\n parse: function parse(s, arr) {\n var today = s._today;\n var year = parseYear(arr[0], today);\n var d = new Date(); // using today's date, but a new month is awkward.\n\n if (today.month && !today.date) {\n today.date = 1;\n }\n\n var obj = {\n year: year,\n month: today.month || d.getMonth(),\n date: today.date || d.getDate()\n };\n\n if (hasDate_1(obj) === false) {\n s.epoch = null;\n return s;\n }\n\n walk_1(s, obj);\n s = parseTime_1(s);\n return s;\n }\n }];\n var strParse = strFmt;\n\n // pull in 'today' data for the baseline moment\n var getNow = function getNow(s) {\n s.epoch = Date.now();\n Object.keys(s._today || {}).forEach(function (k) {\n if (typeof s[k] === 'function') {\n s = s[k](s._today[k]);\n }\n });\n return s;\n };\n\n var dates = {\n now: function now(s) {\n return getNow(s);\n },\n today: function today(s) {\n return getNow(s);\n },\n tonight: function tonight(s) {\n s = getNow(s);\n s = s.hour(18); //6pm\n\n return s;\n },\n tomorrow: function tomorrow(s) {\n s = getNow(s);\n s = s.add(1, 'day');\n s = s.startOf('day');\n return s;\n },\n yesterday: function yesterday(s) {\n s = getNow(s);\n s = s.subtract(1, 'day');\n s = s.startOf('day');\n return s;\n },\n christmas: function christmas(s) {\n var year = getNow(s).year();\n s = s.set([year, 11, 25, 18, 0, 0]); // Dec 25\n\n return s;\n },\n 'new years': function newYears(s) {\n var year = getNow(s).year();\n s = s.set([year, 11, 31, 18, 0, 0]); // Dec 31\n\n return s;\n }\n };\n dates['new years eve'] = dates['new years'];\n var namedDates = dates;\n\n // - can't use built-in js parser ;(\n //=========================================\n // ISO Date\t \"2015-03-25\"\n // Short Date\t\"03/25/2015\" or \"2015/03/25\"\n // Long Date\t\"Mar 25 2015\" or \"25 Mar 2015\"\n // Full Date\t\"Wednesday March 25 2015\"\n //=========================================\n //-- also -\n // if the given epoch is really small, they've probably given seconds and not milliseconds\n // anything below this number is likely (but not necessarily) a mistaken input.\n // this may seem like an arbitrary number, but it's 'within jan 1970'\n // this is only really ambiguous until 2054 or so\n\n var minimumEpoch = 2500000000;\n var defaults = {\n year: new Date().getFullYear(),\n month: 0,\n date: 1\n }; //support [2016, 03, 01] format\n\n var handleArray = function handleArray(s, arr, today) {\n if (arr.length === 0) {\n return s;\n }\n\n var order = ['year', 'month', 'date', 'hour', 'minute', 'second', 'millisecond'];\n\n for (var i = 0; i < order.length; i++) {\n var num = arr[i] || today[order[i]] || defaults[order[i]] || 0;\n s = s[order[i]](num);\n }\n\n return s;\n }; //support {year:2016, month:3} format\n\n\n var handleObject = function handleObject(s, obj, today) {\n // if obj is empty, do nothing\n if (Object.keys(obj).length === 0) {\n return s;\n }\n\n obj = Object.assign({}, defaults, today, obj);\n var keys = Object.keys(obj);\n\n for (var i = 0; i < keys.length; i++) {\n var unit = keys[i]; //make sure we have this method\n\n if (s[unit] === undefined || typeof s[unit] !== 'function') {\n continue;\n } //make sure the value is a number\n\n\n if (obj[unit] === null || obj[unit] === undefined || obj[unit] === '') {\n continue;\n }\n\n var num = obj[unit] || today[unit] || defaults[unit] || 0;\n s = s[unit](num);\n }\n\n return s;\n }; //find the epoch from different input styles\n\n\n var parseInput = function parseInput(s, input, givenTz) {\n var today = s._today || defaults; //if we've been given a epoch number, it's easy\n\n if (typeof input === 'number') {\n if (input > 0 && input < minimumEpoch && s.silent === false) {\n console.warn(' - Warning: You are setting the date to January 1970.');\n console.warn(' - did input seconds instead of milliseconds?');\n }\n\n s.epoch = input;\n return s;\n } //set tmp time\n\n\n s.epoch = Date.now(); // overwrite tmp time with 'today' value, if exists\n\n if (s._today && fns.isObject(s._today) && Object.keys(s._today).length > 0) {\n var res = handleObject(s, today, defaults);\n\n if (res.isValid()) {\n s.epoch = res.epoch;\n }\n } // null input means 'now'\n\n\n if (input === null || input === undefined || input === '') {\n return s; //k, we're good.\n } //support input of Date() object\n\n\n if (fns.isDate(input) === true) {\n s.epoch = input.getTime();\n return s;\n } //support [2016, 03, 01] format\n\n\n if (fns.isArray(input) === true) {\n s = handleArray(s, input, today);\n return s;\n } //support {year:2016, month:3} format\n\n\n if (fns.isObject(input) === true) {\n //support spacetime object as input\n if (input.epoch) {\n s.epoch = input.epoch;\n s.tz = input.tz;\n return s;\n }\n\n s = handleObject(s, input, today);\n return s;\n } //input as a string..\n\n\n if (typeof input !== 'string') {\n return s;\n } //little cleanup..\n\n\n input = input.replace(/\\b(mon|tues|wed|wednes|thu|thurs|fri|sat|satur|sun)(day)?\\b/i, '');\n input = input.replace(/,/g, '');\n input = input.replace(/ +/g, ' ').trim(); //try some known-words, like 'now'\n\n if (namedDates.hasOwnProperty(input) === true) {\n s = namedDates[input](s);\n return s;\n } //try each text-parse template, use the first good result\n\n\n for (var i = 0; i < strParse.length; i++) {\n var m = input.match(strParse[i].reg);\n\n if (m) {\n // console.log(strFmt[i].reg)\n var _res = strParse[i].parse(s, m, givenTz);\n\n if (_res !== null && _res.isValid()) {\n return _res;\n }\n }\n }\n\n if (s.silent === false) {\n console.warn(\"Warning: couldn't parse date-string: '\" + input + \"'\");\n }\n\n s.epoch = null;\n return s;\n };\n\n var input = parseInput;\n\n var shortDays = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];\n var longDays = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];\n var days = {\n \"short\": function short() {\n return shortDays;\n },\n \"long\": function long() {\n return longDays;\n },\n set: function set(i18n) {\n shortDays = i18n[\"short\"] || shortDays;\n longDays = i18n[\"long\"] || longDays;\n },\n aliases: {\n tues: 2,\n thur: 4,\n thurs: 4\n }\n };\n\n var titleCaseEnabled = true;\n var caseFormat = {\n useTitleCase: function useTitleCase() {\n return titleCaseEnabled;\n },\n set: function set(useTitleCase) {\n titleCaseEnabled = useTitleCase;\n }\n };\n\n // it's kind of nuts how involved this is\n // \"+01:00\", \"+0100\", or simply \"+01\"\n\n var isoOffset = function isoOffset(s) {\n var offset = s.timezone().current.offset;\n return !offset ? 'Z' : fns.formatTimezone(offset, ':');\n };\n\n var _offset = isoOffset;\n\n var applyCaseFormat = function applyCaseFormat(str) {\n if (caseFormat.useTitleCase()) {\n return fns.titleCase(str);\n }\n\n return str;\n };\n\n var format = {\n day: function day(s) {\n return applyCaseFormat(s.dayName());\n },\n 'day-short': function dayShort(s) {\n return applyCaseFormat(days[\"short\"]()[s.day()]);\n },\n 'day-number': function dayNumber(s) {\n return s.day();\n },\n 'day-ordinal': function dayOrdinal(s) {\n return fns.ordinal(s.day());\n },\n 'day-pad': function dayPad(s) {\n return fns.zeroPad(s.day());\n },\n date: function date(s) {\n return s.date();\n },\n 'date-ordinal': function dateOrdinal(s) {\n return fns.ordinal(s.date());\n },\n 'date-pad': function datePad(s) {\n return fns.zeroPad(s.date());\n },\n month: function month(s) {\n return applyCaseFormat(s.monthName());\n },\n 'month-short': function monthShort(s) {\n return applyCaseFormat(months[\"short\"]()[s.month()]);\n },\n 'month-number': function monthNumber(s) {\n return s.month();\n },\n 'month-ordinal': function monthOrdinal(s) {\n return fns.ordinal(s.month());\n },\n 'month-pad': function monthPad(s) {\n return fns.zeroPad(s.month());\n },\n 'iso-month': function isoMonth(s) {\n return fns.zeroPad(s.month() + 1);\n },\n //1-based months\n year: function year(s) {\n var year = s.year();\n\n if (year > 0) {\n return year;\n }\n\n year = Math.abs(year);\n return year + ' BC';\n },\n 'year-short': function yearShort(s) {\n var year = s.year();\n\n if (year > 0) {\n return \"'\".concat(String(s.year()).substr(2, 4));\n }\n\n year = Math.abs(year);\n return year + ' BC';\n },\n 'iso-year': function isoYear(s) {\n var year = s.year();\n var isNegative = year < 0;\n var str = fns.zeroPad(Math.abs(year), 4); //0-padded\n\n if (isNegative) {\n //negative years are for some reason 6-digits ('-00008')\n str = fns.zeroPad(str, 6);\n str = '-' + str;\n }\n\n return str;\n },\n time: function time(s) {\n return s.time();\n },\n 'time-24': function time24(s) {\n return \"\".concat(s.hour24(), \":\").concat(fns.zeroPad(s.minute()));\n },\n hour: function hour(s) {\n return s.hour12();\n },\n 'hour-pad': function hourPad(s) {\n return fns.zeroPad(s.hour12());\n },\n 'hour-24': function hour24(s) {\n return s.hour24();\n },\n 'hour-24-pad': function hour24Pad(s) {\n return fns.zeroPad(s.hour24());\n },\n minute: function minute(s) {\n return s.minute();\n },\n 'minute-pad': function minutePad(s) {\n return fns.zeroPad(s.minute());\n },\n second: function second(s) {\n return s.second();\n },\n 'second-pad': function secondPad(s) {\n return fns.zeroPad(s.second());\n },\n ampm: function ampm(s) {\n return s.ampm();\n },\n quarter: function quarter(s) {\n return 'Q' + s.quarter();\n },\n season: function season(s) {\n return s.season();\n },\n era: function era(s) {\n return s.era();\n },\n json: function json(s) {\n return s.json();\n },\n timezone: function timezone(s) {\n return s.timezone().name;\n },\n offset: function offset(s) {\n return _offset(s);\n },\n numeric: function numeric(s) {\n return \"\".concat(s.year(), \"/\").concat(fns.zeroPad(s.month() + 1), \"/\").concat(fns.zeroPad(s.date()));\n },\n // yyyy/mm/dd\n 'numeric-us': function numericUs(s) {\n return \"\".concat(fns.zeroPad(s.month() + 1), \"/\").concat(fns.zeroPad(s.date()), \"/\").concat(s.year());\n },\n // mm/dd/yyyy\n 'numeric-uk': function numericUk(s) {\n return \"\".concat(fns.zeroPad(s.date()), \"/\").concat(fns.zeroPad(s.month() + 1), \"/\").concat(s.year());\n },\n //dd/mm/yyyy\n 'mm/dd': function mmDd(s) {\n return \"\".concat(fns.zeroPad(s.month() + 1), \"/\").concat(fns.zeroPad(s.date()));\n },\n //mm/dd\n // ... https://en.wikipedia.org/wiki/ISO_8601 ;(((\n iso: function iso(s) {\n var year = s.format('iso-year');\n var month = fns.zeroPad(s.month() + 1); //1-based months\n\n var date = fns.zeroPad(s.date());\n var hour = fns.zeroPad(s.h24());\n var minute = fns.zeroPad(s.minute());\n var second = fns.zeroPad(s.second());\n var ms = fns.zeroPad(s.millisecond(), 3);\n var offset = _offset(s);\n return \"\".concat(year, \"-\").concat(month, \"-\").concat(date, \"T\").concat(hour, \":\").concat(minute, \":\").concat(second, \".\").concat(ms).concat(offset); //2018-03-09T08:50:00.000-05:00\n },\n 'iso-short': function isoShort(s) {\n var month = fns.zeroPad(s.month() + 1); //1-based months\n\n var date = fns.zeroPad(s.date());\n return \"\".concat(s.year(), \"-\").concat(month, \"-\").concat(date); //2017-02-15\n },\n 'iso-utc': function isoUtc(s) {\n return new Date(s.epoch).toISOString(); //2017-03-08T19:45:28.367Z\n },\n //i made these up\n nice: function nice(s) {\n return \"\".concat(months[\"short\"]()[s.month()], \" \").concat(fns.ordinal(s.date()), \", \").concat(s.time());\n },\n 'nice-24': function nice24(s) {\n return \"\".concat(months[\"short\"]()[s.month()], \" \").concat(fns.ordinal(s.date()), \", \").concat(s.hour24(), \":\").concat(fns.zeroPad(s.minute()));\n },\n 'nice-year': function niceYear(s) {\n return \"\".concat(months[\"short\"]()[s.month()], \" \").concat(fns.ordinal(s.date()), \", \").concat(s.year());\n },\n 'nice-day': function niceDay(s) {\n return \"\".concat(days[\"short\"]()[s.day()], \" \").concat(applyCaseFormat(months[\"short\"]()[s.month()]), \" \").concat(fns.ordinal(s.date()));\n },\n 'nice-full': function niceFull(s) {\n return \"\".concat(s.dayName(), \" \").concat(applyCaseFormat(s.monthName()), \" \").concat(fns.ordinal(s.date()), \", \").concat(s.time());\n },\n 'nice-full-24': function niceFull24(s) {\n return \"\".concat(s.dayName(), \" \").concat(applyCaseFormat(s.monthName()), \" \").concat(fns.ordinal(s.date()), \", \").concat(s.hour24(), \":\").concat(fns.zeroPad(s.minute()));\n }\n }; //aliases\n\n var aliases = {\n 'day-name': 'day',\n 'month-name': 'month',\n 'iso 8601': 'iso',\n 'time-h24': 'time-24',\n 'time-12': 'time',\n 'time-h12': 'time',\n tz: 'timezone',\n 'day-num': 'day-number',\n 'month-num': 'month-number',\n 'month-iso': 'iso-month',\n 'year-iso': 'iso-year',\n 'nice-short': 'nice',\n 'nice-short-24': 'nice-24',\n mdy: 'numeric-us',\n dmy: 'numeric-uk',\n ymd: 'numeric',\n 'yyyy/mm/dd': 'numeric',\n 'mm/dd/yyyy': 'numeric-us',\n 'dd/mm/yyyy': 'numeric-us',\n 'little-endian': 'numeric-uk',\n 'big-endian': 'numeric',\n 'day-nice': 'nice-day'\n };\n Object.keys(aliases).forEach(function (k) {\n return format[k] = format[aliases[k]];\n });\n\n var printFormat = function printFormat(s) {\n var str = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n\n //don't print anything if it's an invalid date\n if (s.isValid() !== true) {\n return '';\n } //support .format('month')\n\n\n if (format.hasOwnProperty(str)) {\n var out = format[str](s) || '';\n\n if (str !== 'json') {\n out = String(out);\n\n if (str !== 'ampm') {\n out = applyCaseFormat(out);\n }\n }\n\n return out;\n } //support '{hour}:{minute}' notation\n\n\n if (str.indexOf('{') !== -1) {\n var sections = /\\{(.+?)\\}/g;\n str = str.replace(sections, function (_, fmt) {\n fmt = fmt.toLowerCase().trim();\n\n if (format.hasOwnProperty(fmt)) {\n var _out = String(format[fmt](s));\n\n if (fmt !== 'ampm') {\n return applyCaseFormat(_out);\n }\n\n return _out;\n }\n\n return '';\n });\n return str;\n }\n\n return s.format('iso-short');\n };\n\n var format_1 = printFormat;\n\n var pad = fns.zeroPad;\n var formatTimezone = fns.formatTimezone; //parse this insane unix-time-templating thing, from the 19th century\n //http://unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns\n //time-symbols we support\n\n var mapping = {\n G: function G(s) {\n return s.era();\n },\n GG: function GG(s) {\n return s.era();\n },\n GGG: function GGG(s) {\n return s.era();\n },\n GGGG: function GGGG(s) {\n return s.era() === 'AD' ? 'Anno Domini' : 'Before Christ';\n },\n //year\n y: function y(s) {\n return s.year();\n },\n yy: function yy(s) {\n //last two chars\n return parseInt(String(s.year()).substr(2, 4), 10);\n },\n yyy: function yyy(s) {\n return s.year();\n },\n yyyy: function yyyy(s) {\n return s.year();\n },\n yyyyy: function yyyyy(s) {\n return '0' + s.year();\n },\n // u: (s) => {},//extended non-gregorian years\n //quarter\n Q: function Q(s) {\n return s.quarter();\n },\n QQ: function QQ(s) {\n return s.quarter();\n },\n QQQ: function QQQ(s) {\n return s.quarter();\n },\n QQQQ: function QQQQ(s) {\n return s.quarter();\n },\n //month\n M: function M(s) {\n return s.month() + 1;\n },\n MM: function MM(s) {\n return pad(s.month() + 1);\n },\n MMM: function MMM(s) {\n return s.format('month-short');\n },\n MMMM: function MMMM(s) {\n return s.format('month');\n },\n //week\n w: function w(s) {\n return s.week();\n },\n ww: function ww(s) {\n return pad(s.week());\n },\n //week of month\n // W: (s) => s.week(),\n //date of month\n d: function d(s) {\n return s.date();\n },\n dd: function dd(s) {\n return pad(s.date());\n },\n //date of year\n D: function D(s) {\n return s.dayOfYear();\n },\n DD: function DD(s) {\n return pad(s.dayOfYear());\n },\n DDD: function DDD(s) {\n return pad(s.dayOfYear(), 3);\n },\n // F: (s) => {},//date of week in month\n // g: (s) => {},//modified julian day\n //day\n E: function E(s) {\n return s.format('day-short');\n },\n EE: function EE(s) {\n return s.format('day-short');\n },\n EEE: function EEE(s) {\n return s.format('day-short');\n },\n EEEE: function EEEE(s) {\n return s.format('day');\n },\n EEEEE: function EEEEE(s) {\n return s.format('day')[0];\n },\n e: function e(s) {\n return s.day();\n },\n ee: function ee(s) {\n return s.day();\n },\n eee: function eee(s) {\n return s.format('day-short');\n },\n eeee: function eeee(s) {\n return s.format('day');\n },\n eeeee: function eeeee(s) {\n return s.format('day')[0];\n },\n //am/pm\n a: function a(s) {\n return s.ampm().toUpperCase();\n },\n aa: function aa(s) {\n return s.ampm().toUpperCase();\n },\n aaa: function aaa(s) {\n return s.ampm().toUpperCase();\n },\n aaaa: function aaaa(s) {\n return s.ampm().toUpperCase();\n },\n //hour\n h: function h(s) {\n return s.h12();\n },\n hh: function hh(s) {\n return pad(s.h12());\n },\n H: function H(s) {\n return s.hour();\n },\n HH: function HH(s) {\n return pad(s.hour());\n },\n // j: (s) => {},//weird hour format\n m: function m(s) {\n return s.minute();\n },\n mm: function mm(s) {\n return pad(s.minute());\n },\n s: function s(_s) {\n return _s.second();\n },\n ss: function ss(s) {\n return pad(s.second());\n },\n //milliseconds in the day\n A: function A(s) {\n return s.epoch - s.startOf('day').epoch;\n },\n //timezone\n z: function z(s) {\n return s.timezone().name;\n },\n zz: function zz(s) {\n return s.timezone().name;\n },\n zzz: function zzz(s) {\n return s.timezone().name;\n },\n zzzz: function zzzz(s) {\n return s.timezone().name;\n },\n Z: function Z(s) {\n return formatTimezone(s.timezone().current.offset);\n },\n ZZ: function ZZ(s) {\n return formatTimezone(s.timezone().current.offset);\n },\n ZZZ: function ZZZ(s) {\n return formatTimezone(s.timezone().current.offset);\n },\n ZZZZ: function ZZZZ(s) {\n return formatTimezone(s.timezone().current.offset, ':');\n }\n };\n\n var addAlias = function addAlias(_char, to, n) {\n var name = _char;\n var toName = to;\n\n for (var i = 0; i < n; i += 1) {\n mapping[name] = mapping[toName];\n name += _char;\n toName += to;\n }\n };\n\n addAlias('q', 'Q', 4);\n addAlias('L', 'M', 4);\n addAlias('Y', 'y', 4);\n addAlias('c', 'e', 4);\n addAlias('k', 'H', 2);\n addAlias('K', 'h', 2);\n addAlias('S', 's', 2);\n addAlias('v', 'z', 4);\n addAlias('V', 'Z', 4); // support unix-style escaping with ' character\n\n var escapeChars = function escapeChars(arr) {\n for (var i = 0; i < arr.length; i += 1) {\n if (arr[i] === \"'\") {\n // greedy-search for next apostrophe\n for (var o = i + 1; o < arr.length; o += 1) {\n if (arr[o]) {\n arr[i] += arr[o];\n }\n\n if (arr[o] === \"'\") {\n arr[o] = null;\n break;\n }\n\n arr[o] = null;\n }\n }\n }\n\n return arr.filter(function (ch) {\n return ch;\n });\n }; //combine consecutive chars, like 'yyyy' as one.\n\n\n var combineRepeated = function combineRepeated(arr) {\n for (var i = 0; i < arr.length; i += 1) {\n var c = arr[i]; // greedy-forward\n\n for (var o = i + 1; o < arr.length; o += 1) {\n if (arr[o] === c) {\n arr[i] += arr[o];\n arr[o] = null;\n } else {\n break;\n }\n }\n } // '' means one apostrophe\n\n\n arr = arr.filter(function (ch) {\n return ch;\n });\n arr = arr.map(function (str) {\n if (str === \"''\") {\n str = \"'\";\n }\n\n return str;\n });\n return arr;\n };\n\n var unixFmt = function unixFmt(s, str) {\n var arr = str.split(''); // support character escaping\n\n arr = escapeChars(arr); //combine 'yyyy' as string.\n\n arr = combineRepeated(arr);\n return arr.reduce(function (txt, c) {\n if (mapping[c] !== undefined) {\n txt += mapping[c](s) || '';\n } else {\n // 'unescape'\n if (/^'.{1,}'$/.test(c)) {\n c = c.replace(/'/g, '');\n }\n\n txt += c;\n }\n\n return txt;\n }, '');\n };\n\n var unixFmt_1 = unixFmt;\n\n var units$1 = ['year', 'season', 'quarter', 'month', 'week', 'day', 'quarterHour', 'hour', 'minute'];\n\n var doUnit = function doUnit(s, k) {\n var start = s.clone().startOf(k);\n var end = s.clone().endOf(k);\n var duration = end.epoch - start.epoch;\n var percent = (s.epoch - start.epoch) / duration;\n return parseFloat(percent.toFixed(2));\n }; //how far it is along, from 0-1\n\n\n var progress = function progress(s, unit) {\n if (unit) {\n unit = fns.normalize(unit);\n return doUnit(s, unit);\n }\n\n var obj = {};\n units$1.forEach(function (k) {\n obj[k] = doUnit(s, k);\n });\n return obj;\n };\n\n var progress_1 = progress;\n\n var nearest = function nearest(s, unit) {\n //how far have we gone?\n var prog = s.progress();\n unit = fns.normalize(unit); //fix camel-case for this one\n\n if (unit === 'quarterhour') {\n unit = 'quarterHour';\n }\n\n if (prog[unit] !== undefined) {\n // go forward one?\n if (prog[unit] > 0.5) {\n s = s.add(1, unit);\n } // go to start\n\n\n s = s.startOf(unit);\n } else if (s.silent === false) {\n console.warn(\"no known unit '\" + unit + \"'\");\n }\n\n return s;\n };\n\n var nearest_1 = nearest;\n\n //increment until dates are the same\n var climb = function climb(a, b, unit) {\n var i = 0;\n a = a.clone();\n\n while (a.isBefore(b)) {\n //do proper, expensive increment to catch all-the-tricks\n a = a.add(1, unit);\n i += 1;\n } //oops, we went too-far..\n\n\n if (a.isAfter(b, unit)) {\n i -= 1;\n }\n\n return i;\n }; // do a thurough +=1 on the unit, until they match\n // for speed-reasons, only used on day, month, week.\n\n\n var diffOne = function diffOne(a, b, unit) {\n if (a.isBefore(b)) {\n return climb(a, b, unit);\n } else {\n return climb(b, a, unit) * -1; //reverse it\n }\n };\n\n var one = diffOne;\n\n // 2020 - 2019 may be 1 year, or 0 years\n // - '1 year difference' means 366 days during a leap year\n\n var fastYear = function fastYear(a, b) {\n var years = b.year() - a.year(); // should we decrement it by 1?\n\n a = a.year(b.year());\n\n if (a.isAfter(b)) {\n years -= 1;\n }\n\n return years;\n }; // use a waterfall-method for computing a diff of any 'pre-knowable' units\n // compute years, then compute months, etc..\n // ... then ms-math for any very-small units\n\n\n var diff = function diff(a, b) {\n // an hour is always the same # of milliseconds\n // so these units can be 'pre-calculated'\n var msDiff = b.epoch - a.epoch;\n var obj = {\n milliseconds: msDiff,\n seconds: parseInt(msDiff / 1000, 10)\n };\n obj.minutes = parseInt(obj.seconds / 60, 10);\n obj.hours = parseInt(obj.minutes / 60, 10); //do the year\n\n var tmp = a.clone();\n obj.years = fastYear(tmp, b);\n tmp = a.add(obj.years, 'year'); //there's always 12 months in a year...\n\n obj.months = obj.years * 12;\n tmp = a.add(obj.months, 'month');\n obj.months += one(tmp, b, 'month'); // there's always atleast 52 weeks in a year..\n // (month * 4) isn't as close\n\n obj.weeks = obj.years * 52;\n tmp = a.add(obj.weeks, 'week');\n obj.weeks += one(tmp, b, 'week'); // there's always atleast 7 days in a week\n\n obj.days = obj.weeks * 7;\n tmp = a.add(obj.days, 'day');\n obj.days += one(tmp, b, 'day');\n return obj;\n };\n\n var waterfall = diff;\n\n var reverseDiff = function reverseDiff(obj) {\n Object.keys(obj).forEach(function (k) {\n obj[k] *= -1;\n });\n return obj;\n }; // this method counts a total # of each unit, between a, b.\n // '1 month' means 28 days in february\n // '1 year' means 366 days in a leap year\n\n\n var main = function main(a, b, unit) {\n b = fns.beADate(b, a); //reverse values, if necessary\n\n var reversed = false;\n\n if (a.isAfter(b)) {\n var tmp = a;\n a = b;\n b = tmp;\n reversed = true;\n } //compute them all (i know!)\n\n\n var obj = waterfall(a, b);\n\n if (reversed) {\n obj = reverseDiff(obj);\n } //return just the requested unit\n\n\n if (unit) {\n //make sure it's plural-form\n unit = fns.normalize(unit);\n\n if (/s$/.test(unit) !== true) {\n unit += 's';\n }\n\n if (unit === 'dates') {\n unit = 'days';\n }\n\n return obj[unit];\n }\n\n return obj;\n };\n\n var diff$1 = main;\n\n //our conceptual 'break-points' for each unit\n\n var qualifiers = {\n months: {\n almost: 10,\n over: 4\n },\n days: {\n almost: 25,\n over: 10\n },\n hours: {\n almost: 20,\n over: 8\n },\n minutes: {\n almost: 50,\n over: 20\n },\n seconds: {\n almost: 50,\n over: 20\n }\n }; //get number of hours/minutes... between the two dates\n\n function getDiff(a, b) {\n var isBefore = a.isBefore(b);\n var later = isBefore ? b : a;\n var earlier = isBefore ? a : b;\n earlier = earlier.clone();\n var diff = {\n years: 0,\n months: 0,\n days: 0,\n hours: 0,\n minutes: 0,\n seconds: 0\n };\n Object.keys(diff).forEach(function (unit) {\n if (earlier.isSame(later, unit)) {\n return;\n }\n\n var max = earlier.diff(later, unit);\n earlier = earlier.add(max, unit);\n diff[unit] = max;\n }); //reverse it, if necessary\n\n if (isBefore) {\n Object.keys(diff).forEach(function (u) {\n if (diff[u] !== 0) {\n diff[u] *= -1;\n }\n });\n }\n\n return diff;\n } // Expects a plural unit arg\n\n\n function pluralize(value, unit) {\n if (value === 1) {\n unit = unit.slice(0, -1);\n }\n\n return value + ' ' + unit;\n } //create the human-readable diff between the two dates\n\n\n var since = function since(start, end) {\n end = fns.beADate(end, start);\n var diff = getDiff(start, end);\n var isNow = Object.keys(diff).every(function (u) {\n return !diff[u];\n });\n\n if (isNow === true) {\n return {\n diff: diff,\n rounded: 'now',\n qualified: 'now',\n precise: 'now'\n };\n }\n\n var rounded;\n var qualified;\n var precise;\n var englishValues = []; //go through each value and create its text-representation\n\n Object.keys(diff).forEach(function (unit, i, units) {\n var value = Math.abs(diff[unit]);\n\n if (value === 0) {\n return;\n }\n\n var englishValue = pluralize(value, unit);\n englishValues.push(englishValue);\n\n if (!rounded) {\n rounded = qualified = englishValue;\n\n if (i > 4) {\n return;\n } //is it a 'almost' something, etc?\n\n\n var nextUnit = units[i + 1];\n var nextValue = Math.abs(diff[nextUnit]);\n\n if (nextValue > qualifiers[nextUnit].almost) {\n rounded = pluralize(value + 1, unit);\n qualified = 'almost ' + rounded;\n } else if (nextValue > qualifiers[nextUnit].over) qualified = 'over ' + englishValue;\n }\n }); //make them into a string\n\n precise = englishValues.splice(0, 2).join(', '); //handle before/after logic\n\n if (start.isAfter(end) === true) {\n rounded += ' ago';\n qualified += ' ago';\n precise += ' ago';\n } else {\n rounded = 'in ' + rounded;\n qualified = 'in ' + qualified;\n precise = 'in ' + precise;\n }\n\n return {\n diff: diff,\n rounded: rounded,\n qualified: qualified,\n precise: precise\n };\n };\n\n var since_1 = since;\n\n //https://www.timeanddate.com/calendar/aboutseasons.html\n // Spring - from March 1 to May 31;\n // Summer - from June 1 to August 31;\n // Fall (autumn) - from September 1 to November 30; and,\n // Winter - from December 1 to February 28 (February 29 in a leap year).\n var seasons = {\n north: [['spring', 2, 1], //spring march 1\n ['summer', 5, 1], //june 1\n ['fall', 8, 1], //sept 1\n ['autumn', 8, 1], //sept 1\n ['winter', 11, 1] //dec 1\n ],\n south: [['fall', 2, 1], //march 1\n ['autumn', 2, 1], //march 1\n ['winter', 5, 1], //june 1\n ['spring', 8, 1], //sept 1\n ['summer', 11, 1] //dec 1\n ]\n };\n\n var quarters = [null, [0, 1], //jan 1\n [3, 1], //apr 1\n [6, 1], //july 1\n [9, 1] //oct 1\n ];\n\n var units$2 = {\n minute: function minute(s) {\n walk_1(s, {\n second: 0,\n millisecond: 0\n });\n return s;\n },\n quarterhour: function quarterhour(s) {\n var minute = s.minutes();\n\n if (minute >= 45) {\n s = s.minutes(45);\n } else if (minute >= 30) {\n s = s.minutes(30);\n } else if (minute >= 15) {\n s = s.minutes(15);\n } else {\n s = s.minutes(0);\n }\n\n walk_1(s, {\n second: 0,\n millisecond: 0\n });\n return s;\n },\n hour: function hour(s) {\n walk_1(s, {\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n },\n day: function day(s) {\n walk_1(s, {\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n },\n week: function week(s) {\n var original = s.clone();\n s = s.day(s._weekStart); //monday\n\n if (s.isAfter(original)) {\n s = s.subtract(1, 'week');\n }\n\n walk_1(s, {\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n },\n month: function month(s) {\n walk_1(s, {\n date: 1,\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n },\n quarter: function quarter(s) {\n var q = s.quarter();\n\n if (quarters[q]) {\n walk_1(s, {\n month: quarters[q][0],\n date: quarters[q][1],\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n }\n\n return s;\n },\n season: function season(s) {\n var current = s.season();\n var hem = 'north';\n\n if (s.hemisphere() === 'South') {\n hem = 'south';\n }\n\n for (var i = 0; i < seasons[hem].length; i++) {\n if (seasons[hem][i][0] === current) {\n //winter goes between years\n var year = s.year();\n\n if (current === 'winter' && s.month() < 3) {\n year -= 1;\n }\n\n walk_1(s, {\n year: year,\n month: seasons[hem][i][1],\n date: seasons[hem][i][2],\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n }\n }\n\n return s;\n },\n year: function year(s) {\n walk_1(s, {\n month: 0,\n date: 1,\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0\n });\n return s;\n },\n decade: function decade(s) {\n s = s.startOf('year');\n var year = s.year();\n var decade = parseInt(year / 10, 10) * 10;\n s = s.year(decade);\n return s;\n },\n century: function century(s) {\n s = s.startOf('year');\n var year = s.year(); // near 0AD goes '-1 | +1'\n\n var decade = parseInt(year / 100, 10) * 100;\n s = s.year(decade);\n return s;\n }\n };\n units$2.date = units$2.day;\n\n var startOf = function startOf(a, unit) {\n var s = a.clone();\n unit = fns.normalize(unit);\n\n if (units$2[unit]) {\n return units$2[unit](s);\n }\n\n if (unit === 'summer' || unit === 'winter') {\n s = s.season(unit);\n return units$2.season(s);\n }\n\n return s;\n }; //piggy-backs off startOf\n\n\n var endOf = function endOf(a, unit) {\n var s = a.clone();\n unit = fns.normalize(unit);\n\n if (units$2[unit]) {\n // go to beginning, go to next one, step back 1ms\n s = units$2[unit](s); // startof\n\n s = s.add(1, unit);\n s = s.subtract(1, 'millisecond');\n return s;\n }\n\n return s;\n };\n\n var startOf_1 = {\n startOf: startOf,\n endOf: endOf\n };\n\n var isDay = function isDay(unit) {\n if (days[\"short\"]().find(function (s) {\n return s === unit;\n })) {\n return true;\n }\n\n if (days[\"long\"]().find(function (s) {\n return s === unit;\n })) {\n return true;\n }\n\n return false;\n }; // return a list of the weeks/months/days between a -> b\n // returns spacetime objects in the timezone of the input\n\n\n var every = function every(start) {\n var unit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n var end = arguments.length > 2 ? arguments[2] : undefined;\n\n if (!unit || !end) {\n return [];\n } //cleanup unit param\n\n\n unit = fns.normalize(unit); //cleanup to param\n\n end = start.clone().set(end); //swap them, if they're backwards\n\n if (start.isAfter(end)) {\n var tmp = start;\n start = end;\n end = tmp;\n } //support 'every wednesday'\n\n\n var d = start.clone();\n\n if (isDay(unit)) {\n d = d.next(unit);\n unit = 'week';\n } else {\n d = d.next(unit);\n } //okay, actually start doing it\n\n\n var result = [];\n\n while (d.isBefore(end)) {\n result.push(d);\n d = d.add(1, unit);\n }\n\n return result;\n };\n\n var every_1 = every;\n\n var parseDst = function parseDst(dst) {\n if (!dst) {\n return [];\n }\n\n return dst.split('->');\n };\n\n var titleCase = function titleCase(str) {\n str = str[0].toUpperCase() + str.substr(1);\n str = str.replace(/\\/gmt/, '/GMT');\n str = str.replace(/[\\/_]([a-z])/gi, function (s) {\n return s.toUpperCase();\n });\n return str;\n }; //get metadata about this timezone\n\n\n var timezone = function timezone(s) {\n var zones = s.timezones;\n var tz = s.tz;\n\n if (zones.hasOwnProperty(tz) === false) {\n tz = find(s.tz, zones);\n }\n\n if (tz === null) {\n if (s.silent === false) {\n console.warn(\"Warn: could not find given or local timezone - '\" + s.tz + \"'\");\n }\n\n return {\n current: {\n epochShift: 0\n }\n };\n }\n\n var found = zones[tz];\n var result = {\n name: titleCase(tz),\n hasDst: Boolean(found.dst),\n default_offset: found.offset,\n //do north-hemisphere version as default (sorry!)\n hemisphere: found.hem === 's' ? 'South' : 'North',\n current: {}\n };\n\n if (result.hasDst) {\n var arr = parseDst(found.dst);\n result.change = {\n start: arr[0],\n back: arr[1]\n };\n } //find the offsets for summer/winter times\n //(these variable names are north-centric)\n\n\n var summer = found.offset; // (july)\n\n var winter = summer; // (january) assume it's the same for now\n\n if (result.hasDst === true) {\n if (result.hemisphere === 'North') {\n winter = summer - 1;\n } else {\n //southern hemisphere\n winter = found.offset + 1;\n }\n } //find out which offset to use right now\n //use 'summer' time july-time\n\n\n if (result.hasDst === false) {\n result.current.offset = summer;\n result.current.isDST = false;\n } else if (summerTime(s.epoch, result.change.start, result.change.back, summer, winter) === true) {\n result.current.offset = summer;\n result.current.isDST = result.hemisphere === 'North'; //dst 'on' in winter in north\n } else {\n //use 'winter' january-time\n result.current.offset = winter;\n result.current.isDST = result.hemisphere === 'South'; //dst 'on' in summer in south\n }\n\n return result;\n };\n\n var timezone_1 = timezone;\n\n var units$3 = ['century', 'decade', 'year', 'month', 'date', 'day', 'hour', 'minute', 'second', 'millisecond']; //the spacetime instance methods (also, the API)\n\n var methods = {\n set: function set(input$1, tz) {\n var s = this.clone();\n s = input(s, input$1, null);\n\n if (tz) {\n this.tz = find(tz);\n }\n\n return s;\n },\n timezone: function timezone() {\n return timezone_1(this);\n },\n isDST: function isDST() {\n return timezone_1(this).current.isDST;\n },\n hasDST: function hasDST() {\n return timezone_1(this).hasDst;\n },\n offset: function offset() {\n return timezone_1(this).current.offset * 60;\n },\n hemisphere: function hemisphere() {\n return timezone_1(this).hemisphere;\n },\n format: function format(fmt) {\n return format_1(this, fmt);\n },\n unixFmt: function unixFmt(fmt) {\n return unixFmt_1(this, fmt);\n },\n startOf: function startOf(unit) {\n return startOf_1.startOf(this, unit);\n },\n endOf: function endOf(unit) {\n return startOf_1.endOf(this, unit);\n },\n leapYear: function leapYear() {\n var year = this.year();\n return fns.isLeapYear(year);\n },\n progress: function progress(unit) {\n return progress_1(this, unit);\n },\n nearest: function nearest(unit) {\n return nearest_1(this, unit);\n },\n diff: function diff(d, unit) {\n return diff$1(this, d, unit);\n },\n since: function since(d) {\n if (!d) {\n d = this.clone().set();\n }\n\n return since_1(this, d);\n },\n next: function next(unit) {\n var s = this.add(1, unit);\n return s.startOf(unit);\n },\n //the start of the previous year/week/century\n last: function last(unit) {\n var s = this.subtract(1, unit);\n return s.startOf(unit);\n },\n isValid: function isValid() {\n //null/undefined epochs\n if (!this.epoch && this.epoch !== 0) {\n return false;\n }\n\n return !isNaN(this.d.getTime());\n },\n //travel to this timezone\n \"goto\": function goto(tz) {\n var s = this.clone();\n s.tz = find(tz, s.timezones); //science!\n\n return s;\n },\n //get each week/month/day between a -> b\n every: function every(unit, to) {\n return every_1(this, unit, to);\n },\n isAwake: function isAwake() {\n var hour = this.hour(); //10pm -> 8am\n\n if (hour < 8 || hour > 22) {\n return false;\n }\n\n return true;\n },\n isAsleep: function isAsleep() {\n return !this.isAwake();\n },\n //pretty-printing\n log: function log() {\n console.log('');\n console.log(format_1(this, 'nice-short'));\n return this;\n },\n logYear: function logYear() {\n console.log('');\n console.log(format_1(this, 'full-short'));\n return this;\n },\n json: function json() {\n var _this = this;\n\n return units$3.reduce(function (h, unit) {\n h[unit] = _this[unit]();\n return h;\n }, {});\n },\n debug: function debug() {\n var tz = this.timezone();\n var date = this.format('MM') + ' ' + this.format('date-ordinal') + ' ' + this.year();\n date += '\\n - ' + this.format('time');\n console.log('\\n\\n', date + '\\n - ' + tz.name + ' (' + tz.current.offset + ')');\n return this;\n },\n //alias of 'since' but opposite - like moment.js\n from: function from(d) {\n d = this.clone().set(d);\n return d.since(this);\n },\n fromNow: function fromNow() {\n var d = this.clone().set(Date.now());\n return d.since(this);\n },\n weekStart: function weekStart(input) {\n //accept a number directly\n if (typeof input === 'number') {\n this._weekStart = input;\n return this;\n }\n\n if (typeof input === 'string') {\n // accept 'wednesday'\n input = input.toLowerCase().trim();\n var num = days[\"short\"]().indexOf(input);\n\n if (num === -1) {\n num = days[\"long\"]().indexOf(input);\n }\n\n if (num === -1) {\n num = 1; //go back to default\n }\n\n this._weekStart = num;\n } else {\n console.warn('Spacetime Error: Cannot understand .weekStart() input:', input);\n }\n\n return this;\n }\n }; // aliases\n\n methods.inDST = methods.isDST;\n methods.round = methods.nearest;\n methods.each = methods.every;\n var methods_1 = methods;\n\n //these methods wrap around them.\n\n var isLeapYear$1 = fns.isLeapYear;\n\n var validate = function validate(n) {\n //handle number as a string\n if (typeof n === 'string') {\n n = parseInt(n, 10);\n }\n\n return n;\n };\n\n var order = ['year', 'month', 'date', 'hour', 'minute', 'second', 'millisecond']; //reduce hostile micro-changes when moving dates by millisecond\n\n var confirm = function confirm(s, tmp, unit) {\n var n = order.indexOf(unit);\n var arr = order.slice(n, order.length);\n\n for (var i = 0; i < arr.length; i++) {\n var want = tmp[arr[i]]();\n s[arr[i]](want);\n }\n\n return s;\n };\n\n var set = {\n milliseconds: function milliseconds(s, n) {\n n = validate(n);\n var current = s.millisecond();\n var diff = current - n; //milliseconds to shift by\n\n return s.epoch - diff;\n },\n seconds: function seconds(s, n) {\n n = validate(n);\n var diff = s.second() - n;\n var shift = diff * milliseconds.second;\n return s.epoch - shift;\n },\n minutes: function minutes(s, n) {\n n = validate(n);\n var old = s.clone();\n var diff = s.minute() - n;\n var shift = diff * milliseconds.minute;\n s.epoch -= shift; // check against a screw-up\n // if (old.hour() != s.hour()) {\n // walkTo(old, {\n // minute: n\n // })\n // return old.epoch\n // }\n\n confirm(s, old, 'second');\n return s.epoch;\n },\n hours: function hours(s, n) {\n n = validate(n);\n\n if (n >= 24) {\n n = 24;\n } else if (n < 0) {\n n = 0;\n }\n\n var old = s.clone();\n var diff = s.hour() - n;\n var shift = diff * milliseconds.hour;\n s.epoch -= shift; // oops, did we change the day?\n\n if (s.date() !== old.date()) {\n s = old.clone();\n\n if (diff > 1) {\n diff -= 1;\n }\n\n if (diff < 1) {\n diff += 1;\n }\n\n shift = diff * milliseconds.hour;\n s.epoch -= shift;\n }\n\n walk_1(s, {\n hour: n\n });\n confirm(s, old, 'minute');\n return s.epoch;\n },\n //support setting time by '4:25pm' - this isn't very-well developed..\n time: function time(s, str) {\n var m = str.match(/([0-9]{1,2})[:h]([0-9]{1,2})(:[0-9]{1,2})? ?(am|pm)?/);\n\n if (!m) {\n //fallback to support just '2am'\n m = str.match(/([0-9]{1,2}) ?(am|pm)/);\n\n if (!m) {\n return s.epoch;\n }\n\n m.splice(2, 0, '0'); //add implicit 0 minutes\n\n m.splice(3, 0, ''); //add implicit seconds\n }\n\n var h24 = false;\n var hour = parseInt(m[1], 10);\n var minute = parseInt(m[2], 10);\n\n if (hour > 12) {\n h24 = true;\n } //make the hour into proper 24h time\n\n\n if (h24 === false) {\n if (m[4] === 'am' && hour === 12) {\n //12am is midnight\n hour = 0;\n }\n\n if (m[4] === 'pm' && hour < 12) {\n //12pm is noon\n hour += 12;\n }\n } // handle seconds\n\n\n m[3] = m[3] || '';\n m[3] = m[3].replace(/:/, '');\n var sec = parseInt(m[3], 10) || 0;\n s = s.hour(hour);\n s = s.minute(minute);\n s = s.second(sec);\n s = s.millisecond(0);\n return s.epoch;\n },\n date: function date(s, n) {\n n = validate(n); //avoid setting february 31st\n\n if (n > 28) {\n var month = s.month();\n var max = monthLengths_1[month]; // support leap day in february\n\n if (month === 1 && n === 29 && isLeapYear$1(s.year())) {\n max = 29;\n }\n\n if (n > max) {\n n = max;\n }\n } //avoid setting < 0\n\n\n if (n <= 0) {\n n = 1;\n }\n\n walk_1(s, {\n date: n\n });\n return s.epoch;\n },\n //this one's tricky\n month: function month(s, n) {\n if (typeof n === 'string') {\n n = months.mapping()[n.toLowerCase()];\n }\n\n n = validate(n); //don't go past december\n\n if (n >= 12) {\n n = 11;\n }\n\n if (n <= 0) {\n n = 0;\n }\n\n var date = s.date(); //there's no 30th of february, etc.\n\n if (date > monthLengths_1[n]) {\n //make it as close as we can..\n date = monthLengths_1[n];\n }\n\n walk_1(s, {\n month: n,\n date: date\n });\n return s.epoch;\n },\n year: function year(s, n) {\n // support '97\n if (typeof n === 'string' && /^'[0-9]{2}$/.test(n)) {\n n = n.replace(/'/, '').trim();\n n = Number(n); // '89 is 1989\n\n if (n > 30) {\n //change this in 10y\n n = 1900 + n;\n } else {\n // '12 is 2012\n n = 2000 + n;\n }\n }\n\n n = validate(n);\n walk_1(s, {\n year: n\n });\n return s.epoch;\n },\n dayOfYear: function dayOfYear(s, n) {\n n = validate(n);\n var old = s.clone();\n n -= 1; //days are 1-based\n\n if (n <= 0) {\n n = 0;\n } else if (n >= 365) {\n n = 364;\n }\n\n s = s.startOf('year');\n s = s.add(n, 'day');\n confirm(s, old, 'hour');\n return s.epoch;\n }\n };\n\n var methods$1 = {\n millisecond: function millisecond(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.milliseconds(s, num);\n return s;\n }\n\n return this.d.getMilliseconds();\n },\n second: function second(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.seconds(s, num);\n return s;\n }\n\n return this.d.getSeconds();\n },\n minute: function minute(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.minutes(s, num);\n return s;\n }\n\n return this.d.getMinutes();\n },\n hour: function hour(num) {\n var d = this.d;\n\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.hours(s, num);\n return s;\n }\n\n return d.getHours();\n },\n //'3:30' is 3.5\n hourFloat: function hourFloat(num) {\n if (num !== undefined) {\n var s = this.clone();\n\n var _minute = num % 1;\n\n _minute = _minute * 60;\n\n var _hour = parseInt(num, 10);\n\n s.epoch = set.hours(s, _hour);\n s.epoch = set.minutes(s, _minute);\n return s;\n }\n\n var d = this.d;\n var hour = d.getHours();\n var minute = d.getMinutes();\n minute = minute / 60;\n return hour + minute;\n },\n // hour in 12h format\n hour12: function hour12(str) {\n var d = this.d;\n\n if (str !== undefined) {\n var s = this.clone();\n str = '' + str;\n var m = str.match(/^([0-9]+)(am|pm)$/);\n\n if (m) {\n var hour = parseInt(m[1], 10);\n\n if (m[2] === 'pm') {\n hour += 12;\n }\n\n s.epoch = set.hours(s, hour);\n }\n\n return s;\n } //get the hour\n\n\n var hour12 = d.getHours();\n\n if (hour12 > 12) {\n hour12 = hour12 - 12;\n }\n\n if (hour12 === 0) {\n hour12 = 12;\n }\n\n return hour12;\n },\n //some ambiguity here with 12/24h\n time: function time(str) {\n if (str !== undefined) {\n var s = this.clone();\n str = str.toLowerCase().trim();\n s.epoch = set.time(s, str);\n return s;\n }\n\n return \"\".concat(this.h12(), \":\").concat(fns.zeroPad(this.minute())).concat(this.ampm());\n },\n // either 'am' or 'pm'\n ampm: function ampm(input) {\n var which = 'am';\n var hour = this.hour();\n\n if (hour >= 12) {\n which = 'pm';\n }\n\n if (typeof input !== 'string') {\n return which;\n } //okay, we're doing a setter\n\n\n var s = this.clone();\n input = input.toLowerCase().trim(); //ampm should never change the day\n // - so use `.hour(n)` instead of `.minus(12,'hour')`\n\n if (hour >= 12 && input === 'am') {\n //noon is 12pm\n hour -= 12;\n return s.hour(hour);\n }\n\n if (hour < 12 && input === 'pm') {\n hour += 12;\n return s.hour(hour);\n }\n\n return s;\n },\n //some hard-coded times of day, like 'noon'\n dayTime: function dayTime(str) {\n if (str !== undefined) {\n var times = {\n morning: '7:00am',\n breakfast: '7:00am',\n noon: '12:00am',\n lunch: '12:00pm',\n afternoon: '2:00pm',\n evening: '6:00pm',\n dinner: '6:00pm',\n night: '11:00pm',\n midnight: '23:59pm'\n };\n var s = this.clone();\n str = str || '';\n str = str.toLowerCase();\n\n if (times.hasOwnProperty(str) === true) {\n s = s.time(times[str]);\n }\n\n return s;\n }\n\n var h = this.hour();\n\n if (h < 6) {\n return 'night';\n }\n\n if (h < 12) {\n //until noon\n return 'morning';\n }\n\n if (h < 17) {\n //until 5pm\n return 'afternoon';\n }\n\n if (h < 22) {\n //until 10pm\n return 'evening';\n }\n\n return 'night';\n },\n //parse a proper iso string\n iso: function iso(num) {\n if (num !== undefined) {\n return this.set(num);\n }\n\n return this.format('iso');\n }\n };\n var _01Time = methods$1;\n\n var methods$2 = {\n // # day in the month\n date: function date(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.date(s, num);\n return s;\n }\n\n return this.d.getDate();\n },\n //like 'wednesday' (hard!)\n day: function day(input) {\n if (input === undefined) {\n return this.d.getDay();\n }\n\n var original = this.clone();\n var want = input; // accept 'wednesday'\n\n if (typeof input === 'string') {\n input = input.toLowerCase();\n\n if (days.aliases.hasOwnProperty(input)) {\n want = days.aliases[input];\n } else {\n want = days[\"short\"]().indexOf(input);\n\n if (want === -1) {\n want = days[\"long\"]().indexOf(input);\n }\n }\n } //move approx\n\n\n var day = this.d.getDay();\n var diff = day - want;\n var s = this.subtract(diff, 'days'); //tighten it back up\n\n walk_1(s, {\n hour: original.hour(),\n minute: original.minute(),\n second: original.second()\n });\n return s;\n },\n //these are helpful name-wrappers\n dayName: function dayName(input) {\n if (input === undefined) {\n return days[\"long\"]()[this.day()];\n }\n\n var s = this.clone();\n s = s.day(input);\n return s;\n },\n //either name or number\n month: function month(input) {\n if (input !== undefined) {\n var s = this.clone();\n s.epoch = set.month(s, input);\n return s;\n }\n\n return this.d.getMonth();\n }\n };\n var _02Date = methods$2;\n\n var clearMinutes = function clearMinutes(s) {\n s = s.minute(0);\n s = s.second(0);\n s = s.millisecond(1);\n return s;\n };\n\n var methods$3 = {\n // day 0-366\n dayOfYear: function dayOfYear(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.dayOfYear(s, num);\n return s;\n } //days since newyears - jan 1st is 1, jan 2nd is 2...\n\n\n var sum = 0;\n var month = this.d.getMonth();\n var tmp; //count the num days in each month\n\n for (var i = 1; i <= month; i++) {\n tmp = new Date();\n tmp.setDate(1);\n tmp.setFullYear(this.d.getFullYear()); //the year matters, because leap-years\n\n tmp.setHours(1);\n tmp.setMinutes(1);\n tmp.setMonth(i);\n tmp.setHours(-2); //the last day of the month\n\n sum += tmp.getDate();\n }\n\n return sum + this.d.getDate();\n },\n //since the start of the year\n week: function week(num) {\n // week-setter\n if (num !== undefined) {\n var s = this.clone();\n s = s.month(0);\n s = s.date(1);\n s = s.day('monday');\n s = clearMinutes(s); //first week starts first Thurs in Jan\n // so mon dec 28th is 1st week\n // so mon dec 29th is not the week\n\n if (s.monthName() === 'december' && s.date() >= 28) {\n s = s.add(1, 'week');\n }\n\n num -= 1; //1-based\n\n s = s.add(num, 'weeks');\n return s;\n } //find-out which week it is\n\n\n var tmp = this.clone();\n tmp = tmp.month(0);\n tmp = tmp.date(1);\n tmp = clearMinutes(tmp);\n tmp = tmp.day('monday'); //don't go into last-year\n\n if (tmp.monthName() === 'december' && tmp.date() >= 28) {\n tmp = tmp.add(1, 'week');\n } // is first monday the 1st?\n\n\n var toAdd = 1;\n\n if (tmp.date() === 1) {\n toAdd = 0;\n }\n\n tmp = tmp.minus(1, 'second');\n var thisOne = this.epoch; //if the week technically hasn't started yet\n\n if (tmp.epoch > thisOne) {\n return 1;\n } //speed it up, if we can\n\n\n var i = 0;\n var skipWeeks = this.month() * 4;\n tmp.epoch += milliseconds.week * skipWeeks;\n i += skipWeeks;\n\n for (; i < 52; i++) {\n if (tmp.epoch > thisOne) {\n return i + toAdd;\n }\n\n tmp = tmp.add(1, 'week');\n }\n\n return 52;\n },\n //'january'\n monthName: function monthName(input) {\n if (input === undefined) {\n return months[\"long\"]()[this.month()];\n }\n\n var s = this.clone();\n s = s.month(input);\n return s;\n },\n //q1, q2, q3, q4\n quarter: function quarter(num) {\n if (num !== undefined) {\n if (typeof num === 'string') {\n num = num.replace(/^q/i, '');\n num = parseInt(num, 10);\n }\n\n if (quarters[num]) {\n var s = this.clone();\n var _month = quarters[num][0];\n s = s.month(_month);\n s = s.date(1);\n s = s.startOf('day');\n return s;\n }\n }\n\n var month = this.d.getMonth();\n\n for (var i = 1; i < quarters.length; i++) {\n if (month < quarters[i][0]) {\n return i - 1;\n }\n }\n\n return 4;\n },\n //spring, summer, winter, fall\n season: function season(input) {\n var hem = 'north';\n\n if (this.hemisphere() === 'South') {\n hem = 'south';\n }\n\n if (input !== undefined) {\n var s = this.clone();\n\n for (var i = 0; i < seasons[hem].length; i++) {\n if (input === seasons[hem][i][0]) {\n s = s.month(seasons[hem][i][1]);\n s = s.date(1);\n s = s.startOf('day');\n }\n }\n\n return s;\n }\n\n var month = this.d.getMonth();\n\n for (var _i = 0; _i < seasons[hem].length - 1; _i++) {\n if (month >= seasons[hem][_i][1] && month < seasons[hem][_i + 1][1]) {\n return seasons[hem][_i][0];\n }\n }\n\n return 'winter';\n },\n //the year number\n year: function year(num) {\n if (num !== undefined) {\n var s = this.clone();\n s.epoch = set.year(s, num);\n return s;\n }\n\n return this.d.getFullYear();\n },\n //bc/ad years\n era: function era(str) {\n if (str !== undefined) {\n var s = this.clone();\n str = str.toLowerCase(); //TODO: there is no year-0AD i think. may have off-by-1 error here\n\n var year = s.d.getFullYear(); //make '1992' into 1992bc..\n\n if (str === 'bc' && year > 0) {\n s.epoch = set.year(s, year * -1);\n } //make '1992bc' into '1992'\n\n\n if (str === 'ad' && year < 0) {\n s.epoch = set.year(s, year * -1);\n }\n\n return s;\n }\n\n if (this.d.getFullYear() < 0) {\n return 'BC';\n }\n\n return 'AD';\n },\n // 2019 -> 2010\n decade: function decade(input) {\n if (input !== undefined) {\n input = String(input);\n input = input.replace(/([0-9])'?s$/, '$1'); //1950's\n\n input = input.replace(/([0-9])(th|rd|st|nd)/, '$1'); //fix ordinals\n\n if (!input) {\n console.warn('Spacetime: Invalid decade input');\n return this;\n } // assume 20th century?? for '70s'.\n\n\n if (input.length === 2 && /[0-9][0-9]/.test(input)) {\n input = '19' + input;\n }\n\n var year = Number(input);\n\n if (isNaN(year)) {\n return this;\n } // round it down to the decade\n\n\n year = Math.floor(year / 10) * 10;\n return this.year(year); //.startOf('decade')\n }\n\n return this.startOf('decade').year();\n },\n // 1950 -> 19+1\n century: function century(input) {\n if (input !== undefined) {\n if (typeof input === 'string') {\n input = input.replace(/([0-9])(th|rd|st|nd)/, '$1'); //fix ordinals\n\n input = input.replace(/([0-9]+) ?(b\\.?c\\.?|a\\.?d\\.?)/i, function (a, b, c) {\n if (c.match(/b\\.?c\\.?/i)) {\n b = '-' + b;\n }\n\n return b;\n });\n input = input.replace(/c$/, ''); //20thC\n }\n\n var year = Number(input);\n\n if (isNaN(input)) {\n console.warn('Spacetime: Invalid century input');\n return this;\n } // there is no century 0\n\n\n if (year === 0) {\n year = 1;\n }\n\n if (year >= 0) {\n year = (year - 1) * 100;\n } else {\n year = (year + 1) * 100;\n }\n\n return this.year(year);\n } // century getter\n\n\n var num = this.startOf('century').year();\n num = Math.floor(num / 100);\n\n if (num < 0) {\n return num - 1;\n }\n\n return num + 1;\n },\n // 2019 -> 2+1\n millenium: function millenium(input) {\n if (input !== undefined) {\n if (typeof input === 'string') {\n input = input.replace(/([0-9])(th|rd|st|nd)/, '$1'); //fix ordinals\n\n input = Number(input);\n\n if (isNaN(input)) {\n console.warn('Spacetime: Invalid millenium input');\n return this;\n }\n }\n\n if (input > 0) {\n input -= 1;\n }\n\n var year = input * 1000; // there is no year 0\n\n if (year === 0) {\n year = 1;\n }\n\n return this.year(year);\n } // get the current millenium\n\n\n var num = Math.floor(this.year() / 1000);\n\n if (num >= 0) {\n num += 1;\n }\n\n return num;\n }\n };\n var _03Year = methods$3;\n\n var methods$4 = Object.assign({}, _01Time, _02Date, _03Year); //aliases\n\n methods$4.milliseconds = methods$4.millisecond;\n methods$4.seconds = methods$4.second;\n methods$4.minutes = methods$4.minute;\n methods$4.hours = methods$4.hour;\n methods$4.hour24 = methods$4.hour;\n methods$4.h12 = methods$4.hour12;\n methods$4.h24 = methods$4.hour24;\n methods$4.days = methods$4.day;\n\n var addMethods = function addMethods(Space) {\n //hook the methods into prototype\n Object.keys(methods$4).forEach(function (k) {\n Space.prototype[k] = methods$4[k];\n });\n };\n\n var query = addMethods;\n\n var isLeapYear$2 = fns.isLeapYear;\n\n var getMonthLength = function getMonthLength(month, year) {\n if (month === 1 && isLeapYear$2(year)) {\n return 29;\n }\n\n return monthLengths_1[month];\n }; //month is the one thing we 'model/compute'\n //- because ms-shifting can be off by enough\n\n\n var rollMonth = function rollMonth(want, old) {\n //increment year\n if (want.month > 0) {\n var years = parseInt(want.month / 12, 10);\n want.year = old.year() + years;\n want.month = want.month % 12;\n } else if (want.month < 0) {\n //decrement year\n var _years = Math.floor(Math.abs(want.month) / 13, 10);\n\n _years = Math.abs(_years) + 1;\n want.year = old.year() - _years; //ignore extras\n\n want.month = want.month % 12;\n want.month = want.month + 12;\n\n if (want.month === 12) {\n want.month = 0;\n }\n }\n\n return want;\n }; // briefly support day=-2 (this does not need to be perfect.)\n\n\n var rollDaysDown = function rollDaysDown(want, old, sum) {\n want.year = old.year();\n want.month = old.month();\n var date = old.date();\n want.date = date - Math.abs(sum);\n\n while (want.date < 1) {\n want.month -= 1;\n\n if (want.month < 0) {\n want.month = 11;\n want.year -= 1;\n }\n\n var max = getMonthLength(want.month, want.year);\n want.date += max;\n }\n\n return want;\n }; // briefly support day=33 (this does not need to be perfect.)\n\n\n var rollDaysUp = function rollDaysUp(want, old, sum) {\n var year = old.year();\n var month = old.month();\n var max = getMonthLength(month, year);\n\n while (sum > max) {\n sum -= max;\n month += 1;\n\n if (month >= 12) {\n month -= 12;\n year += 1;\n }\n\n max = getMonthLength(month, year);\n }\n\n want.month = month;\n want.date = sum;\n return want;\n };\n\n var _model = {\n months: rollMonth,\n days: rollDaysUp,\n daysBack: rollDaysDown\n };\n\n // but briefly:\n // millisecond-math, and some post-processing covers most-things\n // we 'model' the calendar here only a little bit\n // and that usually works-out...\n\n var order$1 = ['millisecond', 'second', 'minute', 'hour', 'date', 'month'];\n var keep = {\n second: order$1.slice(0, 1),\n minute: order$1.slice(0, 2),\n quarterhour: order$1.slice(0, 2),\n hour: order$1.slice(0, 3),\n date: order$1.slice(0, 4),\n month: order$1.slice(0, 4),\n quarter: order$1.slice(0, 4),\n season: order$1.slice(0, 4),\n year: order$1,\n decade: order$1,\n century: order$1\n };\n keep.week = keep.hour;\n keep.season = keep.date;\n keep.quarter = keep.date; // Units need to be dst adjuested\n\n var dstAwareUnits = {\n year: true,\n quarter: true,\n season: true,\n month: true,\n week: true,\n day: true\n };\n var keepDate = {\n month: true,\n quarter: true,\n season: true,\n year: true\n };\n\n var addMethods$1 = function addMethods(SpaceTime) {\n SpaceTime.prototype.add = function (num, unit) {\n var s = this.clone();\n\n if (!unit || num === 0) {\n return s; //don't bother\n }\n\n var old = this.clone();\n unit = fns.normalize(unit);\n\n if (unit === 'millisecond') {\n s.epoch += num;\n return s;\n } // support 'fortnight' alias\n\n\n if (unit === 'fortnight') {\n num *= 2;\n unit = 'week';\n } //move forward by the estimated milliseconds (rough)\n\n\n if (milliseconds[unit]) {\n s.epoch += milliseconds[unit] * num;\n } else if (unit === 'week') {\n s.epoch += milliseconds.day * (num * 7);\n } else if (unit === 'quarter' || unit === 'season') {\n s.epoch += milliseconds.month * (num * 3);\n } else if (unit === 'quarterhour') {\n s.epoch += milliseconds.minute * 15 * num;\n } //now ensure our milliseconds/etc are in-line\n\n\n var want = {};\n\n if (keep[unit]) {\n keep[unit].forEach(function (u) {\n want[u] = old[u]();\n });\n }\n\n if (dstAwareUnits[unit]) {\n var diff = old.timezone().current.offset - s.timezone().current.offset;\n s.epoch += diff * 3600 * 1000;\n } //ensure month/year has ticked-over\n\n\n if (unit === 'month') {\n want.month = old.month() + num; //month is the one unit we 'model' directly\n\n want = _model.months(want, old);\n } //support coercing a week, too\n\n\n if (unit === 'week') {\n var sum = old.date() + num * 7;\n\n if (sum <= 28 && sum > 1) {\n want.date = sum;\n }\n } //support 25-hour day-changes on dst-changes\n else if (unit === 'date') {\n if (num < 0) {\n want = _model.daysBack(want, old, num);\n } else {\n //specify a naive date number, if it's easy to do...\n var _sum = old.date() + num; // ok, model this one too\n\n\n want = _model.days(want, old, _sum);\n } //manually punt it if we haven't moved at all..\n\n\n if (num !== 0 && old.isSame(s, 'day')) {\n want.date = old.date() + num;\n }\n } // ensure a quarter is 3 months over\n else if (unit === 'quarter') {\n want.month = old.month() + num * 3;\n want.year = old.year(); // handle rollover\n\n if (want.month < 0) {\n var years = Math.floor(want.month / 12);\n var remainder = want.month + Math.abs(years) * 12;\n want.month = remainder;\n want.year += years;\n } else if (want.month >= 12) {\n var _years = Math.floor(want.month / 12);\n\n want.month = want.month % 12;\n want.year += _years;\n }\n\n want.date = old.date();\n } //ensure year has changed (leap-years)\n else if (unit === 'year') {\n var wantYear = old.year() + num;\n var haveYear = s.year();\n\n if (haveYear < wantYear) {\n s.epoch += milliseconds.day;\n } else if (haveYear > wantYear) {\n s.epoch += milliseconds.day;\n }\n } //these are easier\n else if (unit === 'decade') {\n want.year = s.year() + 10;\n } else if (unit === 'century') {\n want.year = s.year() + 100;\n } //keep current date, unless the month doesn't have it.\n\n\n if (keepDate[unit]) {\n var max = monthLengths_1[want.month];\n want.date = old.date();\n\n if (want.date > max) {\n want.date = max;\n }\n }\n\n if (Object.keys(want).length > 1) {\n walk_1(s, want);\n }\n\n return s;\n }; //subtract is only add *-1\n\n\n SpaceTime.prototype.subtract = function (num, unit) {\n var s = this.clone();\n return s.add(num * -1, unit);\n }; //add aliases\n\n\n SpaceTime.prototype.minus = SpaceTime.prototype.subtract;\n SpaceTime.prototype.plus = SpaceTime.prototype.add;\n };\n\n var add = addMethods$1;\n\n //make a string, for easy comparison between dates\n var print = {\n millisecond: function millisecond(s) {\n return s.epoch;\n },\n second: function second(s) {\n return [s.year(), s.month(), s.date(), s.hour(), s.minute(), s.second()].join('-');\n },\n minute: function minute(s) {\n return [s.year(), s.month(), s.date(), s.hour(), s.minute()].join('-');\n },\n hour: function hour(s) {\n return [s.year(), s.month(), s.date(), s.hour()].join('-');\n },\n day: function day(s) {\n return [s.year(), s.month(), s.date()].join('-');\n },\n week: function week(s) {\n return [s.year(), s.week()].join('-');\n },\n month: function month(s) {\n return [s.year(), s.month()].join('-');\n },\n quarter: function quarter(s) {\n return [s.year(), s.quarter()].join('-');\n },\n year: function year(s) {\n return s.year();\n }\n };\n print.date = print.day;\n\n var addMethods$2 = function addMethods(SpaceTime) {\n SpaceTime.prototype.isSame = function (b, unit) {\n var tzAware = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;\n var a = this;\n\n if (!unit) {\n return null;\n }\n\n if (typeof b === 'string' || typeof b === 'number') {\n b = new SpaceTime(b, this.timezone.name);\n } //support 'seconds' aswell as 'second'\n\n\n unit = unit.replace(/s$/, ''); // make them the same timezone for proper comparison\n\n if (tzAware === true && a.tz !== b.tz) {\n b = b.clone();\n b.tz = a.tz;\n }\n\n if (print[unit]) {\n return print[unit](a) === print[unit](b);\n }\n\n return null;\n };\n };\n\n var same = addMethods$2;\n\n var addMethods$3 = function addMethods(SpaceTime) {\n var methods = {\n isAfter: function isAfter(d) {\n d = fns.beADate(d, this);\n var epoch = fns.getEpoch(d);\n\n if (epoch === null) {\n return null;\n }\n\n return this.epoch > epoch;\n },\n isBefore: function isBefore(d) {\n d = fns.beADate(d, this);\n var epoch = fns.getEpoch(d);\n\n if (epoch === null) {\n return null;\n }\n\n return this.epoch < epoch;\n },\n isEqual: function isEqual(d) {\n d = fns.beADate(d, this);\n var epoch = fns.getEpoch(d);\n\n if (epoch === null) {\n return null;\n }\n\n return this.epoch === epoch;\n },\n isBetween: function isBetween(start, end) {\n var isInclusive = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;\n start = fns.beADate(start, this);\n end = fns.beADate(end, this);\n var startEpoch = fns.getEpoch(start);\n\n if (startEpoch === null) {\n return null;\n }\n\n var endEpoch = fns.getEpoch(end);\n\n if (endEpoch === null) {\n return null;\n }\n\n if (isInclusive) {\n return this.isBetween(start, end) || this.isEqual(start) || this.isEqual(end);\n }\n\n return startEpoch < this.epoch && this.epoch < endEpoch;\n }\n }; //hook them into proto\n\n Object.keys(methods).forEach(function (k) {\n SpaceTime.prototype[k] = methods[k];\n });\n };\n\n var compare = addMethods$3;\n\n var addMethods$4 = function addMethods(SpaceTime) {\n var methods = {\n i18n: function i18n(data) {\n //change the day names\n if (fns.isObject(data.days)) {\n days.set(data.days);\n } //change the month names\n\n\n if (fns.isObject(data.months)) {\n months.set(data.months);\n } // change the the display style of the month / day names\n\n\n if (fns.isBoolean(data.useTitleCase)) {\n caseFormat.set(data.useTitleCase);\n }\n }\n }; //hook them into proto\n\n Object.keys(methods).forEach(function (k) {\n SpaceTime.prototype[k] = methods[k];\n });\n };\n\n var i18n = addMethods$4;\n\n var timezones = unpack; //fake timezone-support, for fakers (es5 class)\n\n var SpaceTime = function SpaceTime(input$1, tz) {\n var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n //the holy moment\n this.epoch = null; //the shift for the given timezone\n\n this.tz = find(tz, timezones); //whether to output warnings to console\n\n this.silent = options.silent || true; // favour british interpretation of 02/02/2018, etc\n\n this.british = options.dmy || options.british; //does the week start on sunday, or monday:\n\n this._weekStart = 1; //default to monday\n\n if (options.weekStart !== undefined) {\n this._weekStart = options.weekStart;\n } // the reference today date object, (for testing)\n\n\n this._today = {};\n\n if (options.today !== undefined) {\n this._today = options.today;\n } //add getter/setters\n\n\n Object.defineProperty(this, 'd', {\n //return a js date object\n get: function get() {\n var offset = quick(this); //every computer is somewhere- get this computer's built-in offset\n\n var bias = new Date(this.epoch).getTimezoneOffset() || 0; //movement\n\n var shift = bias + offset * 60; //in minutes\n\n shift = shift * 60 * 1000; //in ms\n //remove this computer's offset\n\n var epoch = this.epoch + shift;\n var d = new Date(epoch);\n return d;\n }\n }); //add this data on the object, to allow adding new timezones\n\n Object.defineProperty(this, 'timezones', {\n get: function get() {\n return timezones;\n },\n set: function set(obj) {\n timezones = obj;\n return obj;\n }\n }); //parse the various formats\n\n var tmp = input(this, input$1, tz);\n this.epoch = tmp.epoch;\n }; //(add instance methods to prototype)\n\n\n Object.keys(methods_1).forEach(function (k) {\n SpaceTime.prototype[k] = methods_1[k];\n }); // ¯\\_(ツ)_/¯\n\n SpaceTime.prototype.clone = function () {\n return new SpaceTime(this.epoch, this.tz, {\n silent: this.silent,\n weekStart: this._weekStart,\n today: this._today\n });\n }; //return native date object at the same epoch\n\n\n SpaceTime.prototype.toLocalDate = function () {\n return new Date(this.epoch);\n }; //append more methods\n\n\n query(SpaceTime);\n add(SpaceTime);\n same(SpaceTime);\n compare(SpaceTime);\n i18n(SpaceTime);\n var spacetime = SpaceTime;\n\n var whereIts = function whereIts(a, b) {\n var start = new spacetime(null);\n var end = new spacetime(null);\n start = start.time(a); //if b is undefined, use as 'within one hour'\n\n if (b) {\n end = end.time(b);\n } else {\n end = start.add(59, 'minutes');\n }\n\n var startHour = start.hour();\n var endHour = end.hour();\n var tzs = Object.keys(start.timezones).filter(function (tz) {\n if (tz.indexOf('/') === -1) {\n return false;\n }\n\n var m = new spacetime(null, tz);\n var hour = m.hour(); //do 'calendar-compare' not real-time-compare\n\n if (hour >= startHour && hour <= endHour) {\n //test minutes too, if applicable\n if (hour === startHour && m.minute() < start.minute()) {\n return false;\n }\n\n if (hour === endHour && m.minute() > end.minute()) {\n return false;\n }\n\n return true;\n }\n\n return false;\n });\n return tzs;\n };\n\n var whereIts_1 = whereIts;\n\n var _version = '6.12.5';\n\n var main$1 = function main(input, tz, options) {\n return new spacetime(input, tz, options);\n }; // set all properties of a given 'today' object\n\n\n var setToday = function setToday(s) {\n var today = s._today || {};\n Object.keys(today).forEach(function (k) {\n s = s[k](today[k]);\n });\n return s;\n }; //some helper functions on the main method\n\n\n main$1.now = function (tz, options) {\n var s = new spacetime(new Date().getTime(), tz, options);\n s = setToday(s);\n return s;\n };\n\n main$1.today = function (tz, options) {\n var s = new spacetime(new Date().getTime(), tz, options);\n s = setToday(s);\n return s.startOf('day');\n };\n\n main$1.tomorrow = function (tz, options) {\n var s = new spacetime(new Date().getTime(), tz, options);\n s = setToday(s);\n return s.add(1, 'day').startOf('day');\n };\n\n main$1.yesterday = function (tz, options) {\n var s = new spacetime(new Date().getTime(), tz, options);\n s = setToday(s);\n return s.subtract(1, 'day').startOf('day');\n };\n\n main$1.extend = function (obj) {\n Object.keys(obj).forEach(function (k) {\n spacetime.prototype[k] = obj[k];\n });\n return this;\n };\n\n main$1.timezones = function () {\n var s = new spacetime();\n return s.timezones;\n }; //find tz by time\n\n\n main$1.whereIts = whereIts_1;\n main$1.version = _version; //aliases:\n\n main$1.plugin = main$1.extend;\n var src = main$1;\n\n return src;\n\n})));\n","// some opinionated-but-common-sense timezone abbreviations\n// these timezone abbreviations are wholly made-up by me, Spencer Kelly, with no expertise in geography\n// generated humbly from https://github.com/spencermountain/spacetime-informal\nconst spacetime = require('spacetime')\n\nconst america = 'America/'\nconst asia = 'Asia/'\nconst europe = 'Europe/'\nconst africa = 'Africa/'\nconst aus = 'Australia/'\nconst pac = 'Pacific/'\n\nconst informal = {\n //europe\n 'british summer time': europe + 'London',\n bst: europe + 'London',\n 'british time': europe + 'London',\n 'britain time': europe + 'London',\n 'irish summer time': europe + 'Dublin',\n 'irish time': europe + 'Dublin',\n ireland: europe + 'Dublin',\n 'central european time': europe + 'Berlin',\n cet: europe + 'Berlin',\n 'central european summer time': europe + 'Berlin',\n cest: europe + 'Berlin',\n 'central europe': europe + 'Berlin',\n 'eastern european time': europe + 'Riga',\n eet: europe + 'Riga',\n 'eastern european summer time': europe + 'Riga',\n eest: europe + 'Riga',\n 'eastern europe time': europe + 'Riga',\n 'western european time': europe + 'Lisbon',\n // wet: europe+'Lisbon',\n 'western european summer time': europe + 'Lisbon',\n // west: europe+'Lisbon',\n 'western europe': europe + 'Lisbon',\n 'turkey standard time': europe + 'Istanbul',\n trt: europe + 'Istanbul',\n 'turkish time': europe + 'Istanbul',\n\n //africa\n etc: africa + 'Freetown',\n utc: africa + 'Freetown',\n 'greenwich standard time': africa + 'Freetown',\n gmt: africa + 'Freetown',\n 'east africa time': africa + 'Nairobi',\n // eat: africa+'Nairobi',\n 'east african time': africa + 'Nairobi',\n 'eastern africa time': africa + 'Nairobi',\n 'central africa time': africa + 'Khartoum',\n // cat: africa+'Khartoum',\n 'central african time': africa + 'Khartoum',\n 'south africa standard time': africa + 'Johannesburg',\n sast: africa + 'Johannesburg',\n 'southern africa': africa + 'Johannesburg',\n 'south african': africa + 'Johannesburg',\n 'west africa standard time': africa + 'Lagos',\n // wat: africa+'Lagos',\n 'western africa time': africa + 'Lagos',\n 'west african time': africa + 'Lagos',\n\n 'australian central standard time': aus + 'Adelaide',\n acst: aus + 'Adelaide',\n 'australian central daylight time': aus + 'Adelaide',\n acdt: aus + 'Adelaide',\n 'australia central': aus + 'Adelaide',\n 'australian eastern standard time': aus + 'Brisbane',\n aest: aus + 'Brisbane',\n 'australian eastern daylight time': aus + 'Brisbane',\n aedt: aus + 'Brisbane',\n 'australia east': aus + 'Brisbane',\n 'australian western standard time': aus + 'Perth',\n awst: aus + 'Perth',\n 'australian western daylight time': aus + 'Perth',\n awdt: aus + 'Perth',\n 'australia west': aus + 'Perth',\n 'australian central western standard time': aus + 'Eucla',\n acwst: aus + 'Eucla',\n 'australia central west': aus + 'Eucla',\n 'lord howe standard time': aus + 'Lord_Howe',\n lhst: aus + 'Lord_Howe',\n 'lord howe daylight time': aus + 'Lord_Howe',\n lhdt: aus + 'Lord_Howe',\n 'russian standard time': europe + 'Moscow',\n msk: europe + 'Moscow',\n russian: europe + 'Moscow',\n\n //america\n 'central standard time': america + 'Chicago',\n 'central time': america + 'Chicago',\n cst: america + 'Havana',\n 'central daylight time': america + 'Chicago',\n cdt: america + 'Havana',\n 'mountain standard time': america + 'Denver',\n 'mountain time': america + 'Denver',\n mst: america + 'Denver',\n 'mountain daylight time': america + 'Denver',\n mdt: america + 'Denver',\n 'atlantic standard time': america + 'Halifax',\n 'atlantic time': america + 'Halifax',\n ast: asia + 'Baghdad',\n 'atlantic daylight time': america + 'Halifax',\n adt: america + 'Halifax',\n 'eastern standard time': america + 'New_York',\n 'eastern time': america + 'New_York',\n est: america + 'New_York',\n 'eastern daylight time': america + 'New_York',\n edt: america + 'New_York',\n 'pacific time': america + 'Los_Angeles',\n 'pacific standard time': america + 'Los_Angeles',\n pst: america + 'Los_Angeles',\n 'pacific daylight time': america + 'Los_Angeles',\n pdt: america + 'Los_Angeles',\n 'alaskan standard time': america + 'Anchorage',\n 'alaskan time': america + 'Anchorage',\n ahst: america + 'Anchorage',\n 'alaskan daylight time': america + 'Anchorage',\n ahdt: america + 'Anchorage',\n 'hawaiian standard time': pac + 'Honolulu',\n 'hawaiian time': pac + 'Honolulu',\n hst: pac + 'Honolulu',\n 'aleutian time': pac + 'Honolulu',\n 'hawaii time': pac + 'Honolulu',\n 'newfoundland standard time': america + 'St_Johns',\n 'newfoundland time': america + 'St_Johns',\n nst: america + 'St_Johns',\n 'newfoundland daylight time': america + 'St_Johns',\n ndt: america + 'St_Johns',\n 'brazil time': america + 'Sao_Paulo',\n brt: america + 'Sao_Paulo',\n brasília: america + 'Sao_Paulo',\n brasilia: america + 'Sao_Paulo',\n 'brazilian time': america + 'Sao_Paulo',\n 'argentina time': america + 'Buenos_Aires',\n // art: a+'Buenos_Aires',\n 'argentinian time': america + 'Buenos_Aires',\n 'amazon time': america + 'Manaus',\n amt: america + 'Manaus',\n 'amazonian time': america + 'Manaus',\n 'easter island standard time': 'Chile/Easterisland',\n east: 'Chile/Easterisland',\n 'easter island summer time': 'Chile/Easterisland',\n easst: 'Chile/Easterisland',\n 'venezuelan standard time': america + 'Caracas',\n 'venezuelan time': america + 'Caracas',\n vet: america + 'Caracas',\n 'venezuela time': america + 'Caracas',\n 'paraguay time': america + 'Asuncion',\n pyt: america + 'Asuncion',\n 'paraguay summer time': america + 'Asuncion',\n pyst: america + 'Asuncion',\n 'cuba standard time': america + 'Havana',\n 'cuba time': america + 'Havana',\n 'cuba daylight time': america + 'Havana',\n 'cuban time': america + 'Havana',\n 'bolivia time': america + 'La_Paz',\n // bot: a+'La_Paz',\n 'bolivian time': america + 'La_Paz',\n 'colombia time': america + 'Bogota',\n cot: america + 'Bogota',\n 'colombian time': america + 'Bogota',\n 'acre time': america + 'Eirunepe',\n // act: a+'Eirunepe',\n 'peru time': america + 'Lima',\n // pet: a+'Lima',\n 'chile standard time': america + 'Punta_Arenas',\n 'chile time': america + 'Punta_Arenas',\n clst: america + 'Punta_Arenas',\n 'chile summer time': america + 'Punta_Arenas',\n cldt: america + 'Punta_Arenas',\n 'uruguay time': america + 'Montevideo',\n uyt: america + 'Montevideo',\n\n //asia\n ist: asia + 'Jerusalem',\n 'arabic standard time': asia + 'Baghdad',\n 'arabic time': asia + 'Baghdad',\n 'arab time': asia + 'Baghdad',\n 'iran standard time': asia + 'Tehran',\n 'iran time': asia + 'Tehran',\n irst: asia + 'Tehran',\n 'iran daylight time': asia + 'Tehran',\n irdt: asia + 'Tehran',\n iranian: asia + 'Tehran',\n 'pakistan standard time': asia + 'Karachi',\n 'pakistan time': asia + 'Karachi',\n pkt: asia + 'Karachi',\n 'india standard time': asia + 'Kolkata',\n 'indian time': asia + 'Kolkata',\n 'indochina time': asia + 'Bangkok',\n ict: asia + 'Bangkok',\n 'south east asia': asia + 'Bangkok',\n 'china standard time': asia + 'Shanghai',\n ct: asia + 'Shanghai',\n 'chinese time': asia + 'Shanghai',\n 'alma-ata time': asia + 'Almaty',\n almt: asia + 'Almaty',\n 'oral time': asia + 'Oral',\n 'orat time': asia + 'Oral',\n 'yakutsk time': asia + 'Yakutsk',\n yakt: asia + 'Yakutsk',\n 'gulf standard time': asia + 'Dubai',\n 'gulf time': asia + 'Dubai',\n gst: asia + 'Dubai',\n uae: asia + 'Dubai',\n 'hong kong time': asia + 'Hong_Kong',\n hkt: asia + 'Hong_Kong',\n 'western indonesian time': asia + 'Jakarta',\n wib: asia + 'Jakarta',\n 'indonesia time': asia + 'Jakarta',\n 'central indonesian time': asia + 'Makassar',\n wita: asia + 'Makassar',\n 'israel daylight time': asia + 'Jerusalem',\n idt: asia + 'Jerusalem',\n 'israel standard time': asia + 'Jerusalem',\n 'israel time': asia + 'Jerusalem',\n israeli: asia + 'Jerusalem',\n 'krasnoyarsk time': asia + 'Krasnoyarsk',\n krat: asia + 'Krasnoyarsk',\n 'malaysia time': asia + 'Kuala_Lumpur',\n myt: asia + 'Kuala_Lumpur',\n 'singapore time': asia + 'Singapore',\n sgt: asia + 'Singapore',\n 'korea standard time': asia + 'Seoul',\n 'korea time': asia + 'Seoul',\n kst: asia + 'Seoul',\n 'korean time': asia + 'Seoul',\n 'uzbekistan time': asia + 'Samarkand',\n uzt: asia + 'Samarkand',\n 'vladivostok time': asia + 'Vladivostok',\n vlat: asia + 'Vladivostok',\n\n //indian\n 'maldives time': 'Indian/Maldives',\n mvt: 'Indian/Maldives',\n 'mauritius time': 'Indian/Mauritius',\n mut: 'Indian/Mauritius',\n\n // pacific\n 'marshall islands time': pac + 'Kwajalein',\n mht: pac + 'Kwajalein',\n 'samoa standard time': pac + 'Midway',\n sst: pac + 'Midway',\n 'somoan time': pac + 'Midway',\n 'chamorro standard time': pac + 'Guam',\n chst: pac + 'Guam',\n 'papua new guinea time': pac + 'Bougainville',\n pgt: pac + 'Bougainville',\n}\n\n//add the official iana zonefile names\nlet iana = spacetime().timezones\nlet formal = Object.keys(iana).reduce((h, k) => {\n h[k] = k\n return h\n}, {})\nmodule.exports = Object.assign({}, informal, formal)\n","module.exports = [\n 'weekday',\n\n 'summer',\n 'winter',\n 'autumn',\n\n 'some day',\n 'one day',\n 'all day',\n 'some point',\n\n 'eod',\n 'eom',\n 'eoy',\n 'standard time',\n 'daylight time',\n 'tommorrow',\n]\n","module.exports = [\n 'centuries',\n 'century',\n 'day',\n 'days',\n 'decade',\n 'decades',\n 'hour',\n 'hours',\n 'hr',\n 'hrs',\n 'millisecond',\n 'milliseconds',\n 'minute',\n 'minutes',\n 'min',\n 'mins',\n 'month',\n 'months',\n 'seconds',\n 'sec',\n 'secs',\n 'week end',\n 'week ends',\n 'weekend',\n 'weekends',\n 'week',\n 'weeks',\n 'wk',\n 'wks',\n 'year',\n 'years',\n 'yr',\n 'yrs',\n 'quarter',\n // 'quarters',\n 'qtr',\n 'qtrs',\n 'season',\n 'seasons',\n]\n","module.exports = [\n 'all hallows eve',\n 'all saints day',\n 'all sts day',\n 'april fools',\n 'armistice day',\n 'australia day',\n 'bastille day',\n 'boxing day',\n 'canada day',\n 'christmas eve',\n 'christmas',\n 'cinco de mayo',\n 'day of the dead',\n 'dia de muertos',\n 'dieciseis de septiembre',\n 'emancipation day',\n 'grito de dolores',\n 'groundhog day',\n 'halloween',\n 'harvey milk day',\n 'inauguration day',\n 'independence day',\n 'independents day',\n 'juneteenth',\n 'labour day',\n 'national freedom day',\n 'national nurses day',\n 'new years eve',\n 'new years',\n 'purple heart day',\n 'rememberance day',\n 'rosa parks day',\n 'saint andrews day',\n 'saint patricks day',\n 'saint stephens day',\n 'saint valentines day',\n 'st andrews day',\n 'st patricks day',\n 'st stephens day',\n 'st valentines day ',\n 'valentines day',\n 'valentines',\n 'veterans day',\n 'victoria day',\n 'womens equality day',\n 'xmas',\n // Fixed religious and cultural holidays\n // Catholic + Christian\n 'epiphany',\n 'orthodox christmas day',\n 'orthodox new year',\n 'assumption of mary',\n 'all souls day',\n 'feast of the immaculate conception',\n 'feast of our lady of guadalupe',\n\n // Kwanzaa\n 'kwanzaa',\n // Pagan / metal 🤘\n 'imbolc',\n 'beltaine',\n 'lughnassadh',\n 'samhain',\n 'martin luther king day',\n 'mlk day',\n 'presidents day',\n 'mardi gras',\n 'tax day',\n 'commonwealth day',\n 'mothers day',\n 'memorial day',\n 'fathers day',\n 'columbus day',\n 'indigenous peoples day',\n 'canadian thanksgiving',\n 'election day',\n 'thanksgiving',\n 't-day',\n 'turkey day',\n 'black friday',\n 'cyber monday',\n // Astronomical religious and cultural holidays\n 'ash wednesday',\n 'palm sunday',\n 'maundy thursday',\n 'good friday',\n 'holy saturday',\n 'easter',\n 'easter sunday',\n 'easter monday',\n 'orthodox good friday',\n 'orthodox holy saturday',\n 'orthodox easter',\n 'orthodox easter monday',\n 'ascension day',\n 'pentecost',\n 'whitsunday',\n 'whit sunday',\n 'whit monday',\n 'trinity sunday',\n 'corpus christi',\n 'advent',\n // Jewish\n 'tu bishvat',\n 'tu bshevat',\n 'purim',\n 'passover',\n 'yom hashoah',\n 'lag baomer',\n 'shavuot',\n 'tisha bav',\n 'rosh hashana',\n 'yom kippur',\n 'sukkot',\n 'shmini atzeret',\n 'simchat torah',\n 'chanukah',\n 'hanukkah',\n // Muslim\n 'isra and miraj',\n 'lailat al-qadr',\n 'eid al-fitr',\n 'id al-Fitr',\n 'eid ul-Fitr',\n 'ramadan',\n 'eid al-adha',\n 'muharram',\n 'the prophets birthday',\n 'ostara',\n 'march equinox',\n 'vernal equinox',\n 'litha',\n 'june solistice',\n 'summer solistice',\n 'mabon',\n 'september equinox',\n 'fall equinox',\n 'autumnal equinox',\n 'yule',\n 'december solstice',\n 'winter solstice',\n // Additional important holidays\n 'chinese new year',\n 'diwali',\n]\n","module.exports = [\n 'noon',\n 'midnight',\n 'now',\n 'morning',\n 'tonight',\n 'evening',\n 'afternoon',\n 'night',\n 'breakfast time',\n 'lunchtime',\n 'dinnertime',\n 'sometime',\n 'midday',\n 'eod',\n 'oclock',\n 'oclock',\n 'all day',\n 'at night',\n]\n","const timezones = require('../_timezones')\nconst data = [\n [require('./dates'), '#Date'],\n [require('./durations'), '#Duration'],\n [require('./holidays'), '#Holiday'],\n [require('./times'), '#Time'],\n [Object.keys(timezones), '#Timezone'],\n]\nlet lex = {\n 'a couple': 'Value',\n}\ndata.forEach((a) => {\n for (let i = 0; i < a[0].length; i++) {\n lex[a[0][i]] = a[1]\n }\n})\n\nmodule.exports = lex\n","const spacetime = require('spacetime')\n\nclass Unit {\n constructor(input, unit, context) {\n this.unit = unit || 'day'\n context = context || {}\n let today = {}\n if (context.today) {\n today = {\n date: context.today.date(),\n month: context.today.month(),\n year: context.today.year(),\n }\n }\n // set it to the beginning of the given unit\n let d = spacetime(input, context.timezone, { today: today })\n\n // set to beginning?\n // if (d.isValid() && keepTime !== true) {\n // d = d.startOf(this.unit)\n // }\n Object.defineProperty(this, 'd', {\n enumerable: false,\n writable: true,\n value: d,\n })\n Object.defineProperty(this, 'context', {\n enumerable: false,\n writable: true,\n value: context,\n })\n }\n // make a new one\n clone() {\n let d = new Unit(this.d, this.unit, this.context)\n return d\n }\n log() {\n console.log('--')\n this.d.log()\n console.log('\\n')\n return this\n }\n applyShift(obj = {}) {\n Object.keys(obj).forEach((unit) => {\n this.d = this.d.add(obj[unit], unit)\n })\n return this\n }\n applyTime(str) {\n if (str) {\n this.d = this.d.time(str)\n } else {\n this.d = this.d.startOf('day') //zero-out time\n }\n return this\n }\n applyWeekDay(day) {\n if (day) {\n let epoch = this.d.epoch\n this.d = this.d.day(day)\n if (this.d.epoch < epoch) {\n this.d = this.d.add(1, 'week')\n }\n }\n return this\n }\n applyRel(rel) {\n if (rel === 'next') {\n return this.next()\n }\n if (rel === 'last') {\n return this.last()\n }\n return this\n }\n applySection(section) {\n if (section === 'start') {\n return this.start()\n }\n if (section === 'end') {\n return this.end()\n }\n if (section === 'middle') {\n return this.middle()\n }\n return this\n }\n format(fmt) {\n return this.d.format(fmt)\n }\n start() {\n this.d = this.d.startOf(this.unit)\n if (this.context.dayStart) {\n this.d = this.d.time(this.context.dayStart)\n }\n return this\n }\n end() {\n this.d = this.d.endOf(this.unit)\n if (this.context.dayEnd) {\n this.d = this.d.time(this.context.dayEnd)\n }\n return this\n }\n middle() {\n let diff = this.d.diff(this.d.endOf(this.unit))\n let minutes = Math.round(diff.minutes / 2)\n this.d = this.d.add(minutes, 'minutes')\n return this\n }\n // the millescond before\n before() {\n this.d = this.d.minus(1, this.unit)\n this.d = this.d.endOf(this.unit)\n if (this.context.dayEnd) {\n this.d = this.d.time(this.context.dayEnd)\n }\n return this\n }\n // 'after 2019'\n after() {\n this.d = this.d.add(1, this.unit)\n this.d = this.d.startOf(this.unit)\n return this\n }\n // tricky: 'next june' 'next tuesday'\n next() {\n this.d = this.d.add(1, this.unit)\n this.d = this.d.startOf(this.unit)\n return this\n }\n // tricky: 'last june' 'last tuesday'\n last() {\n this.d = this.d.minus(1, this.unit)\n this.d = this.d.startOf(this.unit)\n return this\n }\n}\nmodule.exports = Unit\n","const spacetime = require('spacetime')\nconst Unit = require('./Unit')\n\nclass Day extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'day'\n if (this.d.isValid()) {\n this.d = this.d.startOf('day')\n }\n }\n}\n\n// like 'feb 2'\nclass CalendarDate extends Day {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'day'\n if (this.d.isValid()) {\n this.d = this.d.startOf('day')\n }\n }\n next() {\n this.d = this.d.add(1, 'year')\n return this\n }\n last() {\n this.d = this.d.minus(1, 'year')\n return this\n }\n}\n\nclass WeekDay extends Day {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'week'\n // is the input just a weekday?\n if (typeof input === 'string') {\n this.d = spacetime(context.today, context.timezone)\n this.d = this.d.day(input)\n // assume a wednesday in the future\n if (this.d.isBefore(context.today)) {\n this.d = this.d.add(7, 'days')\n }\n } else {\n this.d = input\n }\n this.weekDay = this.d.dayName()\n if (this.d.isValid()) {\n this.d = this.d.startOf('day')\n }\n }\n clone() {\n //overloaded method\n return new WeekDay(this.d, this.unit, this.context)\n }\n end() {\n //overloaded method\n this.d = this.d.endOf('day')\n if (this.context.dayEnd) {\n this.d = this.d.time(this.context.dayEnd)\n }\n return this\n }\n next() {\n this.d = this.d.add(7, 'days')\n this.d = this.d.day(this.weekDay)\n return this\n }\n last() {\n this.d = this.d.minus(7, 'days')\n this.d = this.d.day(this.weekDay)\n return this\n }\n}\n\n// like 'haloween'\nclass Holiday extends CalendarDate {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'day'\n if (this.d.isValid()) {\n this.d = this.d.startOf('day')\n }\n }\n}\n\nmodule.exports = {\n Day: Day,\n WeekDay: WeekDay,\n CalendarDate: CalendarDate,\n Holiday: Holiday,\n}\n","const Unit = require('./Unit')\n\n// a specific month, like 'March'\nclass AnyMonth extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'month'\n // set to beginning\n if (this.d.isValid()) {\n this.d = this.d.startOf(this.unit)\n }\n }\n}\n\n// a specific month, like 'March'\nclass Month extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'month'\n // set to beginning\n if (this.d.isValid()) {\n this.d = this.d.startOf(this.unit)\n }\n }\n next() {\n this.d = this.d.add(1, 'year')\n this.d = this.d.startOf('month')\n return this\n }\n last() {\n this.d = this.d.minus(1, 'year')\n this.d = this.d.startOf('month')\n return this\n }\n}\nclass AnyQuarter extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'quarter'\n // set to beginning\n if (this.d.isValid()) {\n this.d = this.d.startOf(this.unit)\n }\n }\n last() {\n this.d = this.d.minus(1, 'quarter')\n this.d = this.d.startOf(this.unit)\n return this\n }\n}\n\nclass Quarter extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'quarter'\n // set to beginning\n if (this.d.isValid()) {\n this.d = this.d.startOf(this.unit)\n }\n }\n next() {\n this.d = this.d.add(1, 'year')\n this.d = this.d.startOf(this.unit)\n return this\n }\n last() {\n this.d = this.d.minus(1, 'year')\n this.d = this.d.startOf(this.unit)\n return this\n }\n}\nclass Season extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'season'\n // set to beginning\n if (this.d.isValid()) {\n this.d = this.d.startOf(this.unit)\n }\n }\n next() {\n this.d = this.d.add(1, 'year')\n this.d = this.d.startOf(this.unit)\n return this\n }\n last() {\n this.d = this.d.minus(1, 'year')\n this.d = this.d.startOf(this.unit)\n return this\n }\n}\nclass Year extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'year'\n if (this.d.isValid()) {\n this.d = this.d.startOf('year')\n }\n }\n}\n\nmodule.exports = {\n AnyMonth: AnyMonth,\n Month: Month,\n Quarter: Quarter,\n AnyQuarter: AnyQuarter,\n Season: Season,\n Year: Year,\n}\n","const Unit = require('./Unit')\n\nclass Week extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'week'\n if (this.d.isValid()) {\n this.d = this.d.startOf('week')\n }\n }\n}\n\n//may need some work\nclass WeekEnd extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context)\n this.unit = 'week'\n if (this.d.isValid()) {\n this.d = this.d.day('saturday')\n this.d = this.d.startOf('day')\n }\n }\n start() {\n this.d = this.d.day('saturday').startOf('day')\n return this\n }\n // end() {\n // this.d = this.d.day('sunday').endOf('day')\n // return this\n // }\n next() {\n this.d = this.d.add(1, this.unit)\n this.d = this.d.startOf('weekend')\n return this\n }\n last() {\n this.d = this.d.minus(1, this.unit)\n this.d = this.d.startOf('weekend')\n return this\n }\n}\n\nmodule.exports = {\n Week: Week,\n WeekEnd: WeekEnd,\n}\n","const Unit = require('./Unit')\n\nclass Hour extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context, true)\n this.unit = 'hour'\n if (this.d.isValid()) {\n this.d = this.d.startOf('hour')\n }\n }\n}\nclass Minute extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context, true)\n this.unit = 'minute'\n if (this.d.isValid()) {\n this.d = this.d.startOf('minute')\n }\n }\n}\nclass Moment extends Unit {\n constructor(input, unit, context) {\n super(input, unit, context, true)\n this.unit = 'millisecond'\n }\n}\n\nmodule.exports = {\n Hour: Hour,\n Minute: Minute,\n Moment: Moment,\n}\n","module.exports = Object.assign(\n { Unit: require('./Unit') },\n require('./_day'),\n require('./_year'),\n require('./_week'),\n require('./_time')\n)\n","const knownUnits = {\n second: true,\n minute: true,\n hour: true,\n day: true,\n week: true,\n weekend: true,\n month: true,\n season: true,\n quarter: true,\n year: true,\n}\n\nconst aliases = {\n wk: 'week',\n min: 'minute',\n sec: 'second',\n weekend: 'week', //for now...\n}\n\nconst parseUnit = function (m) {\n let unit = m.match('#Duration').text('normal')\n unit = unit.replace(/s$/, '')\n // support shorthands like 'min'\n if (aliases.hasOwnProperty(unit)) {\n unit = aliases[unit]\n }\n return unit\n}\n\n//turn '5 weeks before' to {weeks:5}\nconst parseShift = function (doc) {\n let result = {}\n let shift = doc.match('#DateShift+')\n if (shift.found === false) {\n return result\n }\n // '5 weeks'\n shift.match('#Cardinal #Duration').forEach((ts) => {\n let num = ts.match('#Cardinal').text('normal')\n num = parseFloat(num)\n if (num && typeof num === 'number') {\n let unit = parseUnit(ts)\n if (knownUnits[unit] === true) {\n result[unit] = num\n }\n }\n })\n //is it 2 weeks ago? → -2\n if (shift.has('(before|ago|hence|back)$') === true) {\n Object.keys(result).forEach((k) => (result[k] *= -1))\n }\n shift.remove('#Cardinal #Duration')\n // supoprt '1 day after tomorrow'\n let m = shift.match('[#Duration] [(after|before)]')\n if (m.found) {\n let unit = m.groups('unit').text('reduced')\n // unit = unit.replace(/s$/, '')\n let dir = m.groups('dir').text('reduced')\n if (dir === 'after') {\n result[unit] = 1\n } else if (dir === 'before') {\n result[unit] = -1\n }\n }\n // in half an hour\n m = shift.match('half (a|an) [#Duration]', 0)\n if (m.found) {\n let unit = parseUnit(m)\n result[unit] = 0.5\n }\n // finally, remove it from our text\n doc.remove('#DateShift')\n return result\n}\nmodule.exports = parseShift\n","/*\na 'counter' is a Unit determined after a point\n * first hour of x\n * 7th week in x\n * last year in x\n * \nunlike a shift, like \"2 weeks after x\"\n*/\nconst oneBased = {\n minute: true,\n}\nconst getCounter = function (doc) {\n // 7th week of\n let m = doc.match('[#Value] [#Duration+] (of|in)')\n if (m.found) {\n let obj = m.groups()\n let num = obj.num.text('reduced')\n let unit = obj.unit.text('reduced')\n let found = {\n unit: unit,\n num: Number(num) || 0,\n }\n // 0-based or 1-based units\n if (!oneBased[unit]) {\n found.num -= 1\n }\n doc = doc.remove(m)\n return found\n }\n // first week of\n m = doc.match('[(first|initial|last|final)] [#Duration+] (of|in)')\n if (m.found) {\n let obj = m.groups()\n let dir = obj.dir.text('reduced')\n let unit = obj.unit.text('reduced')\n if (dir === 'initial') {\n dir = 'first'\n }\n if (dir === 'final') {\n dir = 'last'\n }\n let found = {\n unit: unit,\n dir: dir,\n }\n doc = doc.remove(m)\n return found\n }\n\n return {}\n}\nmodule.exports = getCounter\n","const spacetime = require('spacetime')\n\nconst hardCoded = {\n daybreak: '7:00am', //ergh\n breakfast: '8:00am',\n morning: '9:00am',\n noon: '12:00pm',\n midday: '12:00pm',\n afternoon: '2:00pm',\n lunchtime: '12:00pm',\n evening: '6:00pm',\n dinnertime: '6:00pm',\n night: '8:00pm',\n eod: '10:00pm',\n midnight: '12:00am',\n}\n\nconst halfPast = function (m, s) {\n let hour = m.match('#Cardinal$').text('reduced')\n\n let term = m.match('(half|quarter|25|15|10|5)')\n let mins = term.text('reduced')\n if (term.has('half')) {\n mins = '30'\n }\n if (term.has('quarter')) {\n mins = '15'\n }\n let behind = m.has('to')\n // apply it\n s = s.hour(hour)\n s = s.startOf('hour')\n // assume 'half past 5' is 5pm\n if (hour < 6) {\n s = s.ampm('pm')\n }\n if (behind) {\n s = s.subtract(mins, 'minutes')\n } else {\n s = s.add(mins, 'minutes')\n }\n return s\n}\n\nconst parseTime = function (doc, context) {\n let time = doc.match('(at|by|for|before|this)? #Time+')\n if (time.found) {\n doc.remove(time)\n }\n // get the main part of the time\n time = time.not('^(at|by|for|before|this)')\n time = time.not('sharp')\n time = time.not('on the dot')\n let s = spacetime.now(context.timezone)\n let now = s.clone()\n\n // check for known-times (like 'today')\n let timeStr = time.text('reduced')\n if (hardCoded.hasOwnProperty(timeStr)) {\n return hardCoded[timeStr]\n }\n\n // '5 oclock'\n let m = time.match('^#Cardinal oclock (am|pm)?')\n if (m.found) {\n m = m.not('oclock')\n s = s.hour(m.text('reduced'))\n s = s.startOf('hour')\n if (s.isValid() && !s.isEqual(now)) {\n let ampm = m.match('(am|pm)').text('reduced')\n s = s.ampm(ampm)\n return s.time()\n }\n }\n\n // 'quarter to two'\n m = time.match('(half|quarter|25|15|10|5) (past|after|to) #Cardinal')\n if (m.found) {\n s = halfPast(m, s)\n if (s.isValid() && !s.isEqual(now)) {\n return s.time()\n }\n }\n // '4 in the evening'\n m = time.match('[