From 1351468197f67a4801c3aad9c1f29cee759f6a7d Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Thu, 8 Aug 2024 14:32:26 +0100 Subject: [PATCH 01/24] feat(plugins/dates): duration ranges --- .../src/api/parse/range/02-date-range.js | 22 +++++++++++ plugins/dates/tests/duration-range.test.js | 37 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 plugins/dates/tests/duration-range.test.js diff --git a/plugins/dates/src/api/parse/range/02-date-range.js b/plugins/dates/src/api/parse/range/02-date-range.js index eb7bba40a..7df1825e2 100644 --- a/plugins/dates/src/api/parse/range/02-date-range.js +++ b/plugins/dates/src/api/parse/range/02-date-range.js @@ -1,5 +1,6 @@ import parseDate from '../one/index.js' import reverseMaybe from './_reverse.js' +import Unit from '../one/units/Unit.js' export default [ { @@ -138,4 +139,25 @@ export default [ return null }, }, + + { + // 2 to 4 weeks + match: '[#Value] to [#Value] [(day|days|week|weeks|month|months|year|years)]', + desc: '2 to 4 weeks', + parse: (m, context) => { + const { min, max, unit } = m.groups() + + let start = new Unit(context.today, null, context) + let end = start.clone() + + const duration = unit.text('implicit') + start = start.applyShift({ [duration]: min.numbers().get()[0] }) + end = end.applyShift({ [duration]: max.numbers().get()[0] }).applyShift({ day: -1 }) + + return { + start: start, + end: end.end(), + } + }, + }, ] diff --git a/plugins/dates/tests/duration-range.test.js b/plugins/dates/tests/duration-range.test.js new file mode 100644 index 000000000..3d5882c42 --- /dev/null +++ b/plugins/dates/tests/duration-range.test.js @@ -0,0 +1,37 @@ +import test from 'tape' +import nlp from './_lib.js' + +// Duration ranges +const durArr = [ + { + text: ['2 to 4 days', '2-4 days', 'two to four days'], + duration: { years: 0, months: 0, days: 2, hours: 0, minutes: 0 }, + }, + { + text: ['1 to 2 weeks', '1-2 weeks', 'one to two weeks'], + duration: { years: 0, months: 0, days: 7, hours: 0, minutes: 0 }, + }, + { + text: ['1 to 5 months', '1-5 months', 'one to five months'], + duration: { years: 0, months: 4, days: 0, hours: 0, minutes: 0 }, + }, + { + text: ['2 to 4 years', '2-4 years', 'two to four years'], + duration: { years: 2, months: 0, days: 0, hours: 0, minutes: 0 }, + }, +] + +const context = { + today: '2024-01-01', +} + +test('duration-ranges', function (t) { + durArr.forEach(obj => { + obj.text.forEach(text => { + const doc = nlp(text) + const duration = doc.dates(context).get()[0].duration + t.deepEqual(duration, obj.duration, text) + }) + }) + t.end() +}) From 217871982283863bc3fe68bcb5f359fd05c36a9e Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Thu, 8 Aug 2024 14:57:10 +0100 Subject: [PATCH 02/24] fix(plugins/dates): make durations inclusive --- plugins/dates/src/api/parse/range/02-date-range.js | 7 ++++++- plugins/dates/tests/duration-range.test.js | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/plugins/dates/src/api/parse/range/02-date-range.js b/plugins/dates/src/api/parse/range/02-date-range.js index 7df1825e2..5c12013df 100644 --- a/plugins/dates/src/api/parse/range/02-date-range.js +++ b/plugins/dates/src/api/parse/range/02-date-range.js @@ -152,7 +152,12 @@ export default [ const duration = unit.text('implicit') start = start.applyShift({ [duration]: min.numbers().get()[0] }) - end = end.applyShift({ [duration]: max.numbers().get()[0] }).applyShift({ day: -1 }) + end = end.applyShift({ [duration]: max.numbers().get()[0] }) + + // Ensure that the end date is inclusive + if (!['day', 'days'].includes(duration)) { + end = end.applyShift({ day: -1 }).applyShift({ [duration]: 1 }) + } return { start: start, diff --git a/plugins/dates/tests/duration-range.test.js b/plugins/dates/tests/duration-range.test.js index 3d5882c42..a7d7dc993 100644 --- a/plugins/dates/tests/duration-range.test.js +++ b/plugins/dates/tests/duration-range.test.js @@ -5,19 +5,19 @@ import nlp from './_lib.js' const durArr = [ { text: ['2 to 4 days', '2-4 days', 'two to four days'], - duration: { years: 0, months: 0, days: 2, hours: 0, minutes: 0 }, + duration: { years: 0, months: 0, days: 3, hours: 0, minutes: 0 }, }, { text: ['1 to 2 weeks', '1-2 weeks', 'one to two weeks'], - duration: { years: 0, months: 0, days: 7, hours: 0, minutes: 0 }, + duration: { years: 0, months: 0, days: 14, hours: 0, minutes: 0 }, }, { text: ['1 to 5 months', '1-5 months', 'one to five months'], - duration: { years: 0, months: 4, days: 0, hours: 0, minutes: 0 }, + duration: { years: 0, months: 5, days: 0, hours: 0, minutes: 0 }, }, { text: ['2 to 4 years', '2-4 years', 'two to four years'], - duration: { years: 2, months: 0, days: 0, hours: 0, minutes: 0 }, + duration: { years: 3, months: 0, days: 0, hours: 0, minutes: 0 }, }, ] From fd45122ca2056f911cc4adcec503d7ee855f1b18 Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Mon, 12 Aug 2024 15:08:28 +0100 Subject: [PATCH 03/24] fix(plugins/dates): match `^in` --- plugins/dates/src/api/parse/range/02-date-range.js | 6 +++--- plugins/dates/tests/duration-range.test.js | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/plugins/dates/src/api/parse/range/02-date-range.js b/plugins/dates/src/api/parse/range/02-date-range.js index 5c12013df..87a7810ce 100644 --- a/plugins/dates/src/api/parse/range/02-date-range.js +++ b/plugins/dates/src/api/parse/range/02-date-range.js @@ -141,9 +141,9 @@ export default [ }, { - // 2 to 4 weeks - match: '[#Value] to [#Value] [(day|days|week|weeks|month|months|year|years)]', - desc: '2 to 4 weeks', + // in 2 to 4 weeks + match: '^in [#Value] to [#Value] [(day|days|week|weeks|month|months|year|years)]', + desc: 'in 2 to 4 weeks', parse: (m, context) => { const { min, max, unit } = m.groups() diff --git a/plugins/dates/tests/duration-range.test.js b/plugins/dates/tests/duration-range.test.js index a7d7dc993..7d584cb93 100644 --- a/plugins/dates/tests/duration-range.test.js +++ b/plugins/dates/tests/duration-range.test.js @@ -25,12 +25,14 @@ const context = { today: '2024-01-01', } -test('duration-ranges', function (t) { +test('future duration-ranges', function (t) { durArr.forEach(obj => { obj.text.forEach(text => { - const doc = nlp(text) - const duration = doc.dates(context).get()[0].duration + const doc = nlp(`in ${text}`) + const { duration, start, end } = doc.dates(context).get()[0] t.deepEqual(duration, obj.duration, text) + t.ok(start > context.today, 'start date') + t.ok(end > start, 'end date') }) }) t.end() From bade69610efe11288842bf821ecadf7881415ea2 Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Mon, 12 Aug 2024 15:57:02 +0100 Subject: [PATCH 04/24] feat(plugins/dates): past duration ranges --- .../src/api/parse/range/02-date-range.js | 26 +++++++++++++++++++ plugins/dates/tests/duration-range.test.js | 26 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/plugins/dates/src/api/parse/range/02-date-range.js b/plugins/dates/src/api/parse/range/02-date-range.js index 87a7810ce..7d34a8285 100644 --- a/plugins/dates/src/api/parse/range/02-date-range.js +++ b/plugins/dates/src/api/parse/range/02-date-range.js @@ -159,6 +159,32 @@ export default [ end = end.applyShift({ day: -1 }).applyShift({ [duration]: 1 }) } + return { + start: start, + end: end.end(), + } + }, + }, + { + // 2 to 4 weeks ago + match: + '[#Value] to [#Value] [(day|days|week|weeks|month|months|year|years)] (ago|before|earlier|prior)', + desc: '2 to 4 weeks ago', + parse: (m, context) => { + const { min, max, unit } = m.groups() + + let start = new Unit(context.today, null, context) + let end = start.clone() + + const duration = unit.text('implicit') + start = start.applyShift({ [duration]: -max.numbers().get()[0] }) + end = end.applyShift({ [duration]: -min.numbers().get()[0] }) + + // Ensure that the end date is inclusive + if (!['day', 'days'].includes(duration)) { + end = end.applyShift({ day: 1 }).applyShift({ [duration]: -1 }) + } + return { start: start, end: end.end(), diff --git a/plugins/dates/tests/duration-range.test.js b/plugins/dates/tests/duration-range.test.js index 7d584cb93..6ee452f5d 100644 --- a/plugins/dates/tests/duration-range.test.js +++ b/plugins/dates/tests/duration-range.test.js @@ -37,3 +37,29 @@ test('future duration-ranges', function (t) { }) t.end() }) + +test('past duration-ranges', function (t) { + durArr.forEach(obj => { + obj.text.forEach(text => { + const doc = nlp(`${text} ago`) + const { duration, start, end } = doc.dates(context).get()[0] + t.deepEqual(duration, obj.duration, text) + t.ok(start < context.today, 'start date') + t.ok(end > start, 'end date') + }) + }) + t.end() +}) + +test('past duration-ranges', function (t) { + durArr.forEach(obj => { + obj.text.forEach(text => { + const doc = nlp(`${text} ago`) + const { duration, start, end } = doc.dates(context).get()[0] + t.deepEqual(duration, obj.duration, text) + t.ok(start < context.today, 'start date') + t.ok(end > start, 'end date') + }) + }) + t.end() +}) From f1630646cf6092dec812bf303206b5e472d0ae28 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Sat, 17 Aug 2024 12:38:14 -0400 Subject: [PATCH 05/24] use native node watch --- package.json | 6 ++---- plugins/_experiments/ast/package.json | 2 +- plugins/_experiments/markdown/package.json | 2 +- plugins/_experiments/sentiment/package.json | 4 ++-- plugins/dates/package.json | 4 ++-- plugins/paragraphs/package.json | 4 ++-- plugins/payload/package.json | 4 ++-- plugins/speech/package.json | 4 ++-- plugins/speed/package.json | 4 ++-- plugins/stats/package.json | 4 ++-- plugins/wikipedia/package.json | 4 ++-- src/{four.js => five.js} | 0 12 files changed, 20 insertions(+), 22 deletions(-) rename src/{four.js => five.js} (100%) diff --git a/package.json b/package.json index 26fd1fd78..72af6c098 100644 --- a/package.json +++ b/package.json @@ -71,8 +71,7 @@ }, "scripts": { "build": "npm run version && rollup -c --silent", - "watch": "amble ./scratch.js", - "watch:tag": "amble ./tagger.scratch.js", + "watch": "node --watch scratch.js", "pack": "node ./scripts/pack.js", "version": "node ./scripts/version.js", "test": "tape \"./tests/**/*.test.js\" | tap-dancer", @@ -116,7 +115,6 @@ "devDependencies": { "@rollup/plugin-node-resolve": "15.2.3", "@rollup/plugin-terser": "0.4.4", - "amble": "1.3.0", "cross-env": "^7.0.3", "eslint": "9.8.0", "eslint-plugin-regexp": "2.6.0", @@ -134,4 +132,4 @@ "_tests/**" ], "license": "MIT" -} +} \ No newline at end of file diff --git a/plugins/_experiments/ast/package.json b/plugins/_experiments/ast/package.json index c7c41d057..051134905 100644 --- a/plugins/_experiments/ast/package.json +++ b/plugins/_experiments/ast/package.json @@ -23,7 +23,7 @@ "scripts": { "test": "tape \"./tests/**/*.test.js\" | tap-dancer --color always", "testb": "TESTENV=prod tape \"./tests/**/*.test.js\" | tap-dancer --color always", - "watch": "amble ./scratch.js", + "watch": "node --watch ./scratch.js", "build": "rollup -c --silent" }, "eslintIgnore": [ diff --git a/plugins/_experiments/markdown/package.json b/plugins/_experiments/markdown/package.json index c5e43116c..7724370f9 100644 --- a/plugins/_experiments/markdown/package.json +++ b/plugins/_experiments/markdown/package.json @@ -23,7 +23,7 @@ "scripts": { "test": "tape \"./tests/**/*.test.js\" | tap-dancer --color always", "testb": "TESTENV=prod tape \"./tests/**/*.test.js\" | tap-dancer --color always", - "watch": "amble ./scratch.js", + "watch": "node --watch ./scratch.js", "build": "rollup -c --silent" }, "eslintIgnore": [ diff --git a/plugins/_experiments/sentiment/package.json b/plugins/_experiments/sentiment/package.json index e38aac8d7..48010e7c2 100644 --- a/plugins/_experiments/sentiment/package.json +++ b/plugins/_experiments/sentiment/package.json @@ -22,7 +22,7 @@ "scripts": { "test": "tape \"./tests/**/*.test.js\" | tap-dancer --color always", "testb": "TESTENV=prod tape \"./tests/**/*.test.js\" | tap-dancer --color always", - "watch": "amble ./scratch.js", + "watch": "node --watch ./scratch.js", "build": "rollup -c --silent" }, "eslintIgnore": [ @@ -43,4 +43,4 @@ "devDependencies": { "@rollup/plugin-commonjs": "^24.0.1" } -} +} \ No newline at end of file diff --git a/plugins/dates/package.json b/plugins/dates/package.json index c9a10fbe1..a23fcb586 100644 --- a/plugins/dates/package.json +++ b/plugins/dates/package.json @@ -24,7 +24,7 @@ "scripts": { "test": "tape \"./tests/**/*.test.js\" | tap-dancer --color always", "testb": "TESTENV=prod tape \"./tests/**/*.test.js\" | tap-dancer --color always", - "watch": "amble ./scratch.js", + "watch": "node --watch ./scratch.js", "perf": "node ./scripts/perf.js", "version": "node ./scripts/version.js", "build": "npm run version && rollup -c --silent" @@ -42,4 +42,4 @@ "spacetime-holiday": "0.3.0" }, "license": "MIT" -} +} \ No newline at end of file diff --git a/plugins/paragraphs/package.json b/plugins/paragraphs/package.json index 6306a4701..0fe3473f3 100644 --- a/plugins/paragraphs/package.json +++ b/plugins/paragraphs/package.json @@ -24,7 +24,7 @@ "scripts": { "test": "tape \"./tests/**/*.test.js\" | tap-dancer --color always", "testb": "TESTENV=prod tape \"./tests/**/*.test.js\" | tap-dancer --color always", - "watch": "amble ./scratch.js", + "watch": "node --watch ./scratch.js", "build": "rollup -c --silent" }, "files": [ @@ -36,4 +36,4 @@ }, "devDependencies": {}, "license": "MIT" -} +} \ No newline at end of file diff --git a/plugins/payload/package.json b/plugins/payload/package.json index 035c5e472..8d5fe8be2 100644 --- a/plugins/payload/package.json +++ b/plugins/payload/package.json @@ -23,7 +23,7 @@ "scripts": { "test": "tape \"./tests/**/*.test.js\" | tap-dancer --color always", "testb": "TESTENV=prod tape \"./tests/**/*.test.js\" | tap-dancer --color always", - "watch": "amble ./scratch.js", + "watch": "node --watch ./scratch.js", "build": "rollup -c --silent" }, "peerDependencies": { @@ -37,4 +37,4 @@ ], "devDependencies": {}, "license": "MIT" -} +} \ No newline at end of file diff --git a/plugins/speech/package.json b/plugins/speech/package.json index a731d602d..6b30d4273 100644 --- a/plugins/speech/package.json +++ b/plugins/speech/package.json @@ -24,7 +24,7 @@ "scripts": { "test": "tape \"./tests/**/*.test.js\" | tap-dancer --color always", "testb": "TESTENV=prod tape \"./tests/**/*.test.js\" | tap-dancer --color always", - "watch": "amble ./scratch.js", + "watch": "node --watch ./scratch.js", "build": "rollup -c --silent" }, "eslintIgnore": [ @@ -41,4 +41,4 @@ "dependencies": {}, "devDependencies": {}, "license": "MIT" -} +} \ No newline at end of file diff --git a/plugins/speed/package.json b/plugins/speed/package.json index 10d3cd24a..e0191fc5a 100644 --- a/plugins/speed/package.json +++ b/plugins/speed/package.json @@ -24,7 +24,7 @@ "scripts": { "test": "tape \"./tests/**/*.test.js\" | tap-dancer --color always", "testb": "TESTENV=prod tape \"./tests/**/*.test.js\" | tap-dancer --color always", - "watch": "amble ./scratch.js", + "watch": "node --watch ./scratch.js", "version": "node ./scripts/version.js", "build": "npm run version && rollup -c --silent" }, @@ -40,4 +40,4 @@ "nlp-corpus": "^4.4.0" }, "license": "MIT" -} +} \ No newline at end of file diff --git a/plugins/stats/package.json b/plugins/stats/package.json index b76105a62..ad15f38c2 100644 --- a/plugins/stats/package.json +++ b/plugins/stats/package.json @@ -24,7 +24,7 @@ "scripts": { "test": "tape \"./tests/**/*.test.js\" | tap-dancer --color always", "testb": "TESTENV=prod tape \"./tests/**/*.test.js\" | tap-dancer --color always", - "watch": "amble ./scratch.js", + "watch": "node --watch ./scratch.js", "generate": "node ./scripts/generate.js", "stat": "node ./scripts/stat.js", "perf": "node ./scripts/perf.js", @@ -43,4 +43,4 @@ }, "devDependencies": {}, "license": "MIT" -} +} \ No newline at end of file diff --git a/plugins/wikipedia/package.json b/plugins/wikipedia/package.json index 4744ab401..783819769 100644 --- a/plugins/wikipedia/package.json +++ b/plugins/wikipedia/package.json @@ -23,7 +23,7 @@ "scripts": { "test": "tape \"./tests/**/*.test.js\" | tap-dancer --color always", "testb": "TESTENV=prod tape \"./tests/**/*.test.js\" | tap-dancer --color always", - "watch": "amble ./scratch.js", + "watch": "node --watch ./scratch.js", "generate": "node ./scripts/generate/index.js", "stat": "node ./scripts/stat.js", "perf": "node ./scripts/perf.js", @@ -45,4 +45,4 @@ "node-wget-promise": "0.1.6" }, "license": "MIT" -} +} \ No newline at end of file diff --git a/src/four.js b/src/five.js similarity index 100% rename from src/four.js rename to src/five.js From 557b5c782b56fff58809b31cc060abe4e4500235 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Sat, 17 Aug 2024 12:38:51 -0400 Subject: [PATCH 06/24] remove old code --- API.md | 321 --------- learn/comparatives/data.js | 1247 ----------------------------------- learn/comparatives/index.js | 25 - learn/gpt/api.js | 25 - learn/gpt/list.js | 34 - learn/gpt/package-lock.json | 189 ------ learn/gpt/package.json | 16 - learn/gpt/scratch.js | 9 - learn/phrasals/list.js | 249 ------- scratch.js | 8 +- 10 files changed, 4 insertions(+), 2119 deletions(-) delete mode 100644 API.md delete mode 100644 learn/comparatives/data.js delete mode 100644 learn/comparatives/index.js delete mode 100644 learn/gpt/api.js delete mode 100644 learn/gpt/list.js delete mode 100644 learn/gpt/package-lock.json delete mode 100644 learn/gpt/package.json delete mode 100644 learn/gpt/scratch.js delete mode 100644 learn/phrasals/list.js diff --git a/API.md b/API.md deleted file mode 100644 index b6ab4d617..000000000 --- a/API.md +++ /dev/null @@ -1,321 +0,0 @@ -# lib -* nlp.tokenize() -* nlp.plugin() -* nlp.parseMatch() - -* nlp.world() -* nlp.model() -* nlp.methods() -* nlp.hooks() -* nlp.verbose() -* nlp.version - - -# One -### API -* .found -* .docs -* .pointer -* .fullPointer -* .methods -* .model -* .hooks -* .isView -* .length - -* .update() -* .toView() -* .fromText() -* .termList() - -* .compute() -* .clone() - -### Loops -* .forEach() -* .map() -* .filter() -* .find() -* .some() -* .random() - -### Accessors -* .all() -* .terms() -* .groups() -* .eq() -* .first() -* .last() -* .firstTerms() -* .lastTerms() -* .slice() -* .fullSentences() -* .none() -* .isDoc() -* .wordCount() - - -### Match -* nlp.parseMatch() - -* .match() -* .matchOne() -* .has() -* .if() -* .ifNo() - -* .before() -* .after() -* .growLeft() -* .growRight() -* .grow() - -* .splitOn() -* .splitBefore() -* .splitAfter() - -### Change -* .compute('id') -* .toLowerCase() -* .toUpperCase() -* .toTitleCase() -* .toCamelCase() - -* .concat() - -* .insertBefore() -* .insertAfter() - -* .remove() - -* .replace() -* .replaceWith() - -* .unique() -* .reverse() -* .sort() - -* .pre() -* .post() -* .trim() -* .hyphenate() -* .dehyphenate() -* .toQuotations() -* .toParentheses() - -### Output -* .text() -* .json() -* .debug() -* .out() -* .html() -* .wrap() - - -### Pointers -* .union() -* .intersection() -* .not() -* .complement() -* .settle() - -### Tag -* nlp.addTags() -* .compute('tagRank') - -* .tag() -* .tagSafe() -* .unTag() -* .canBe() - -### Contractions -* .compute('contractions') - -### Tokenize -* .compute('alias') -* .compute('machine') -* .compute('normal') -* .compute('freq') -* .compute('offset') -* .compute('index') -* .compute('wordCount') - -### Cache -* .compute('cache') -* .cache() -* .uncache() - -### Lookup -* nlp.buildTrie() -* .lookup() - -### Typeahead -* nlp.typeahead() -* .compute('typeahead') - -* .autoFill() - -### Lexicon -* .compute('lexicon') -* nlp.addWords() - - ---- - -# Two -### Pre-tagger -* .compute('preTagger') -* .compute('root') -* .compute('penn') - -### Contraction-two -* .compute('contractionTwo') -* .contractions() - * .contractions().expand() -* .contract() - -### Post-tagger -* .compute('postTagger') -* .confidence() - - -### Swap -* .swap() - ---- - -# Three - -### Chunker -* .compute('chunks') -.chunks() -.clauses() - -### Normalize -.normalize() - -### Redact -* .redact() - -### Misc -.hyphenated() -.hashTags() -.emails() -.emoji() -.emoticons() -.atMentions() -.urls() -.pronouns() -.conjunctions() -.prepositions() -.honorifics() -.abbreviations() -.phoneNumbers() - -.adjectives() - .adjectives().json() - .adjectives().adverbs() - .adjectives().toSuperlative() - .adjectives().toComparative() - .adjectives().toAdverb() - .adjectives().toNoun() - -.acronyms() - .acronyms().strip() - .acronyms().addPeriods() -.parentheses() - .parentheses().strip() -.possessives() - .possessives().strip() -.quotations() - .quotations().strip() -.adverbs() - .adverbs().json() - -### Nouns -* .nouns() - * .nouns().parse() - * .nouns().json() - * .nouns().isPlural() - * .nouns().adjectives() - * .nouns().toPlural() - * .nouns().toSingular() - -### Numbers -* .numbers() - * .numbers().parse() - * .numbers().get() - * .numbers().json() - * .numbers().isOrdinal() - * .numbers().isCardinal() - * .numbers().toNumber() - * .numbers().toLocaleString() - * .numbers().toText() - * .numbers().toCardinal() - * .numbers().toOrdinal() - * .numbers().isEqual() - * .numbers().greaterThan() - * .numbers().lessThan() - * .numbers().between() - * .numbers().set() - * .numbers().add() - * .numbers().subtract() - * .numbers().increment() - * .numbers().decrement() -* .percentages() -* .money() -* .fractions() - * .fractions().parse() - * .fractions().get() - * .fractions().json() - * .fractions().toDecimal() - * .fractions().toFraction() - * .fractions().toOrdinal() - * .fractions().toCardinal() - * .fractions().toPercentage() - -### Sentences -* .sentences() - * .sentences().parse() - * .sentences().json() - * .sentences().toPastTense() - * .sentences().toPresentTense() - * .sentences().toFutureTense() - * .sentences().toInfinitive() - * .sentences().toNegative() - * .sentences().toPositive() - * .sentences().isQuestion() - * .sentences().isExclamation() - * .sentences().isStatement() -* .questions() - - -### Verbs -* .verbs() - * .verbs().parse() - * .verbs().json() - * .verbs().subjects() - * .verbs().adverbs() - * .verbs().isSingular() - * .verbs().isPlural() - * .verbs().isImperative() - - * .verbs().toInfinitive() - * .verbs().toPresentTense() - * .verbs().toPastTense() - * .verbs().toFutureTense() - * .verbs().toGerund() - * .verbs().conjugate() - * .verbs().isNegative() - * .verbs().isPositive() - * .verbs().toPositive() - * .verbs().toNegative() - - -### Topics -* .people() - * .people().parse() - * .people().json() -* .places() -* .organizations() -* .topics() diff --git a/learn/comparatives/data.js b/learn/comparatives/data.js deleted file mode 100644 index edd03c627..000000000 --- a/learn/comparatives/data.js +++ /dev/null @@ -1,1247 +0,0 @@ -export default { - - 'aberrant': null, - 'ablaze': null, - 'able': null, - 'above': null, - 'abrasive': null, - 'abreast': null, - 'abrupt': null, - 'absent': null, - 'absolute': null, - 'abstract': null, - 'absurd': null, - 'abundant': null, - 'academic': null, - 'accurate': null, - 'active': null, - 'actual': null, - 'acute': null, - 'adamant': null, - 'adaptable': null, - 'adept': null, - 'adequate': null, - 'adorable': null, - 'adventurous': null, - 'adverse': null, - 'affectionate': null, - 'affluent': null, - 'afraid': null, - 'against': null, - 'aged': null, - 'aggressive': null, - 'agile': null, - 'agreeable': null, - 'ahead': null, - 'alcoholic': null, - 'alert': null, - 'alike': null, - 'alive': null, - 'alkaline': null, - 'almighty': null, - 'alone': null, - 'aloof': null, - 'alternate': null, - 'ambitious': null, - 'amiable': null, - 'ample': null, - 'amused': null, - 'ancient': null, - 'angelic': null, - 'angry': 'angrier', - 'animated': null, - 'annoyed': null, - 'antiquated': null, - 'antique': null, - 'anxious': null, - 'apathetic': null, - 'appalling': null, - 'apparent': null, - 'appealing': null, - 'appetizing': null, - 'apprehensive': null, - 'appropriate': null, - 'approximately': null, - 'apt': null, - 'archival': null, - 'arrogant': null, - 'artificial': null, - 'artistic': null, - 'ashen': null, - 'asleep': null, - 'assured': null, - 'attentive': null, - 'attractive': null, - 'authentic': null, - 'average': null, - 'awake': 'awakener', - 'aware': null, - 'awful': null, - 'awkward': null, - 'backwards': null, - 'bad': 'worse', - 'balanced': null, - 'bald': 'balder', - 'bare': null, - 'barren': null, - 'bawdy': 'bawdier', - 'beautiful': null, - 'behind': null, - 'believable': null, - 'beloved': null, - 'below': null, - 'beneath': null, - 'beneficial': null, - 'benign': null, - 'beside': null, - 'bewildered': null, - 'big': 'bigger', - 'bigtime': null, - 'bipartisan': null, - 'bitter': null, - 'bittersweet': null, - 'bizarre': null, - 'black': 'blacker', - 'bland': 'blander', - 'blessed': null, - 'blind': null, - 'blond': 'blonder', - 'bloody': 'bloodier', - 'blue': 'bluer', - 'bogus': null, - 'bold': 'bolder', - 'boldface': null, - 'bonafide': null, - 'bored': 'boreder', - 'boring': 'boriner', - 'bouncy': 'bouncier', - 'brash': 'brasher', - 'brave': 'braver', - 'brief': 'briefer', - 'bright': 'brighter', - 'brilliant': null, - 'brisk': null, - 'broad': 'broader', - 'bronze': null, - 'buff': 'buffer', - 'bureaucratic': null, - 'burly': 'burlier', - 'busy': 'busier', - 'calculate': null, - 'calm': 'calmer', - 'camp': 'camper', - 'capable': null, - 'careful': null, - 'careless': null, - 'catchy': 'catchier', - 'cautious': null, - 'celebate': null, - 'celestial': null, - 'certain': null, - 'chaotic': null, - 'charitable': null, - 'cheap': 'cheaper', - 'cheerful': null, - 'cheesy': 'cheesier', - 'cherished': null, - 'chilly': 'chillier', - 'civil': null, - 'classic': null, - 'clean': 'cleaner', - 'cleansed': null, - 'clear': 'clearer', - 'clever': 'cleverer', - 'close': 'closer', - 'cloudy': 'cloudier', - 'clumsy': 'clumsier', - 'coarse': 'coarser', - 'coastal': null, - 'coercive': null, - 'cognizant': null, - 'cold': 'colder', - 'colonial': null, - 'colorful': null, - 'colossal': null, - 'colourful': null, - 'comfortable': null, - 'commensurate': null, - 'committed': null, - 'common': null, - 'compassionate': null, - 'competent': null, - 'complete': null, - 'complex': null, - 'concave': null, - 'concerned': null, - 'concise': null, - 'conducive': null, - 'confident': null, - 'confused': null, - 'congruent': null, - 'conjoint': null, - 'conjugal': null, - 'consequent': null, - 'considerate': null, - 'consistent': null, - 'constant': null, - 'containerized': null, - 'content': null, - 'convenient': null, - 'cool': 'cooler', - 'cooperative': null, - 'corporate': null, - 'costly': 'costlier', - 'courageous': null, - 'courteous': null, - 'covert': null, - 'cowardly': null, - 'cozy': 'cozier', - 'craven': null, - 'crazed': null, - 'crazy': 'crazier', - 'creative': null, - 'credible': null, - 'crisp': 'crisper', - 'critical': null, - 'crowded': null, - 'crucial': null, - 'cruel': 'crueler', - 'cryptic': null, - 'crystalline': null, - 'cuddly': 'cuddlier', - 'curious': null, - 'curly': 'curlier', - 'custom': null, - 'cute': 'cuter', - 'cynical': null, - 'daily': null, - 'damp': 'damper', - 'dangerous': null, - 'daring': null, - 'dark': 'darker', - 'dead': null, - 'deadly': 'deadlier', - 'deadpan': null, - 'deaf': null, - 'dear': 'dearer', - 'deboned': null, - 'deceased': null, - 'dedicated': null, - 'deep': 'deeper', - 'defiant': null, - 'definite': null, - 'degenerate': null, - 'delicate': null, - 'delicious': null, - 'delightful': null, - 'demonstrative': null, - 'dense': 'denser', - 'dependable': null, - 'dependent': null, - 'depressed': null, - 'derelict': null, - 'desolate': null, - 'desperate': null, - 'detailed': null, - 'determined': null, - 'devoid': null, - 'devout': null, - 'didactic': null, - 'difficult': null, - 'diffuse': 'diffuser', - 'digital': null, - 'diligent': null, - 'dim': 'dimmer', - 'dire': 'direr', - 'direct': null, - 'dirty': 'dirtier', - 'disciplined': null, - 'discouraging': null, - 'discreet': null, - 'discrete': null, - 'diseased': null, - 'disgruntled': null, - 'disjoint': null, - 'disloyal': null, - 'disparate': null, - 'disrespectful': null, - 'distant': null, - 'distinct': null, - 'distorted': null, - 'distracted': null, - 'disturbed': null, - 'divergent': null, - 'diverse': null, - 'divine': 'diviner', - 'domestic': null, - 'dominant': null, - 'dormant': null, - 'doubtful': null, - 'drastic': null, - 'drunk': 'drunker', - 'dry': 'drier', - 'due': null, - 'dull': 'duller', - 'dumb': 'dumber', - 'dutiful': null, - 'dynamic': null, - 'eager': null, - 'early': 'earlier', - 'east': null, - 'easy': 'easier', - 'easygoing': null, - 'eccentric': null, - 'eclectic': null, - 'edgy': 'edgier', - 'eerie': 'eerier', - 'efficient': null, - 'effortless': null, - 'effusive': null, - 'elated': null, - 'elderly': null, - 'electric': null, - 'elegant': null, - 'emergent': null, - 'eminent': null, - 'emotional': null, - 'empty': 'emptier', - 'encouraging': null, - 'energetic': null, - 'enlightened': null, - 'entertaining': null, - 'enthusiastic': null, - 'equal': null, - 'equitable': null, - 'erect': null, - 'erratic': null, - 'essential': null, - 'eternal': null, - 'ethereal': null, - 'ethical': null, - 'eventful': null, - 'evil': null, - 'exact': null, - 'exalted': null, - 'excellent': null, - 'excessive': null, - 'excited': null, - 'exciting': null, - 'exempt': null, - 'exhausted': null, - 'exitless': null, - 'exotic': null, - 'expensive': null, - 'expert': null, - 'explicit': null, - 'explosive': null, - 'exquisite': null, - 'extinct': null, - 'extra': null, - 'extravagant': null, - 'exuberant': null, - 'exultant': null, - 'fabled': null, - 'faint': 'fainter', - 'fair': 'fairer', - 'faithful': null, - 'fake': 'faker', - 'false': null, - 'familiar': null, - 'famous': null, - 'fancy': 'fancier', - 'far': 'farther', - 'fast': 'faster', - 'fastidious': null, - 'fat': 'fatter', - 'fatalistic': null, - 'faulty': 'faultier', - 'faux': null, - 'fearless': null, - 'federal': null, - 'feeble': 'feebler', - 'female': null, - 'feminine': null, - 'fertile': null, - 'festive': null, - 'few': 'fewer', - 'fierce': 'fiercer', - 'filthy': 'filthier', - 'final': null, - 'fine': 'finer', - 'finite': null, - 'firm': 'firmer', - 'first': null, - 'flaccid': null, - 'flagrant': null, - 'flamboyant': null, - 'flat': 'flatter', - 'flawless': null, - 'flexible': null, - 'fluent': null, - 'fluid': null, - 'fluorescent': null, - 'foamy': 'foamier', - 'focused': null, - 'foggy': 'foggier', - 'fond': 'fonder', - 'foolish': null, - 'forceful': null, - 'foregoing': null, - 'foreign': null, - 'foreseeable': null, - 'forgetful': null, - 'formal': null, - 'fortunate': null, - 'fortunately': null, - 'forward': null, - 'foul': 'fouler', - 'fragile': null, - 'fragmented': null, - 'fragrant': null, - 'frail': 'frailer', - 'frank': 'franker', - 'frantic': null, - 'fraudulent': null, - 'free': 'freer', - 'frenzied': null, - 'frequent': null, - 'fresh': 'fresher', - 'fretful': null, - 'friendly': 'friendlier', - 'frightened': null, - 'frilly': null, - 'frozen': null, - 'frugal': null, - 'full': 'fuller', - 'fun': 'funer', - 'funny': 'funnier', - 'furry': 'furrier', - 'gainful': null, - 'garrulous': null, - 'gauche': 'gaucher', - 'gaudy': 'gaudier', - 'gay': 'gaier', - 'general': null, - 'generic': null, - 'generous': null, - 'gentle': 'gentler', - 'gentlemanly': null, - 'genuine': null, - 'ghastly': 'ghastlier', - 'ghostly': 'ghostlier', - 'giddy': 'giddier', - 'gifted': null, - 'gigantic': null, - 'glad': 'gladder', - 'gleaming': null, - 'glib': 'glibber', - 'global': null, - 'gloomy': 'gloomier', - 'glossy': null, - 'gold': 'golder', - 'golden': null, - 'good': 'better', - 'goofy': 'goofier', - 'graceful': null, - 'grand': 'grander', - 'grateful': null, - 'gratis': null, - 'grave': 'graver', - 'gray': 'grayer', - 'great': 'greater', - 'greedy': 'greedier', - 'green': 'greener', - 'grey': null, - 'grisly': 'grislier', - 'grizzled': null, - 'groovy': 'groovier', - 'gross': 'grosser', - 'gruesome': 'gruesomer', - 'half': null, - 'hallowed': null, - 'handsome': 'handsomer', - 'handy': 'handier', - 'happy': 'happier', - 'hard': 'harder', - 'hardy': 'hardier', - 'harmful': null, - 'harsh': 'harsher', - 'hasty': null, - 'hateful': null, - 'heady': 'headier', - 'healthy': 'healthier', - 'hearty': 'heartier', - 'heavy': 'heavier', - 'hefty': 'heftier', - 'hellish': null, - 'helpful': null, - 'high': 'higher', - 'hilly': 'hillier', - 'hispanic': null, - 'historical': null, - 'holistic': null, - 'holy': 'holier', - 'homely': 'homelier', - 'homesick': null, - 'honest': null, - 'hopeful': null, - 'horrific': null, - 'hostile': null, - 'hot': 'hotter', - 'hourly': null, - 'huge': 'huger', - 'humane': null, - 'humble': 'humbler', - 'humid': 'humider', - 'humorous': null, - 'hungry': 'hungrier', - 'hypocritical': null, - 'icy': 'icier', - 'ideal': null, - 'idealistic': null, - 'identical': null, - 'idyllic': null, - 'ignorant': null, - 'ill': null, - 'illegal': null, - 'illegitimate': null, - 'illicit': null, - 'illiterate': null, - 'imaginative': null, - 'immature': null, - 'immediate': null, - 'immense': null, - 'imminent': null, - 'impartial': null, - 'impatient': null, - 'impending': null, - 'imperfect': null, - 'implicit': null, - 'impolite': null, - 'important': null, - 'impressive': null, - 'improper': null, - 'impulsive': null, - 'inaccurate': null, - 'inadequate': null, - 'inappropriate': null, - 'inattentive': null, - 'inclusive': null, - 'incomparable': null, - 'incomplete': null, - 'inconsiderate': null, - 'incorrect': null, - 'indecisive': null, - 'indefinable': null, - 'indefinite': null, - 'independent': null, - 'indescribable': null, - 'indeterminate': null, - 'indifferent': null, - 'indirect': null, - 'indispensable': null, - 'indivisible': null, - 'indoor': null, - 'indulgent': null, - 'industrial': null, - 'industrious': null, - 'ineffable': null, - 'inept': null, - 'inert': null, - 'infallible': null, - 'infamous': null, - 'inferior': null, - 'infinite': null, - 'influential': null, - 'informative': null, - 'infrequent': null, - 'ingenious': null, - 'ingrown': null, - 'inherent': null, - 'inimitable': null, - 'initial': null, - 'innate': null, - 'innocent': null, - 'inoffensive': null, - 'inordinate': null, - 'insane': null, - 'inscrutable': null, - 'insensitive': null, - 'inside': null, - 'insightful': null, - 'insignificant': null, - 'insoluble': null, - 'insolvent': null, - 'insubordinate': null, - 'insurmountable': null, - 'intact': null, - 'intangible': null, - 'intelligent': null, - 'intense': null, - 'interdependent': null, - 'interesting': null, - 'intolerant': null, - 'intransigent': null, - 'intrinsic': null, - 'intuitive': null, - 'invaluable': null, - 'inventive': null, - 'invincible': null, - 'inviolable': null, - 'irate': null, - 'ironic': null, - 'irrelevant': null, - 'irreplaceable': null, - 'irresponsible': null, - 'irrevocable': null, - 'jealous': null, - 'jewelled': null, - 'jolly': 'jollier', - 'jovial': null, - 'joyful': null, - 'jubilant': null, - 'juicy': 'juicier', - 'junior': null, - 'just': null, - 'kaput': null, - 'keen': 'keener', - 'key': null, - 'kind': 'kinder', - 'kindly': null, - 'knowing': null, - 'knowledgeable': null, - 'lame': 'lamer', - 'languid': null, - 'lapsed': null, - 'large': 'larger', - 'late': 'later', - 'lately': null, - 'lateral': null, - 'lavish': null, - 'lax': null, - 'lazy': 'lazier', - 'lean': 'leaner', - 'leery': 'leerier', - 'legal': null, - 'legendary': null, - 'legitimate': null, - 'lengthy': 'lengthier', - 'lethal': null, - 'lethargic': null, - 'lewd': 'lewder', - 'liberal': null, - 'lifeless': null, - 'light': 'lighter', - 'lighthearted': null, - 'lightweight': null, - 'likeable': null, - 'likely': 'likelier', - 'limited': null, - 'limp': 'limper', - 'liquid': null, - 'literal': null, - 'literate': null, - 'little': 'littler', - 'lively': 'livelier', - 'local': null, - 'lofty': 'loftier', - 'logical': null, - 'lonely': 'lonelier', - 'long': 'longer', - 'longstanding': null, - 'longterm': null, - 'longtime': null, - 'loose': 'looser', - 'loud': 'louder', - 'lousy': 'lousier', - 'loutish': null, - 'lovable': null, - 'lovely': 'lovelier', - 'loving': null, - 'low': 'lower', - 'loyal': null, - 'lucky': 'luckier', - 'lukewarm': null, - 'lumbering': null, - 'luscious': null, - 'macabre': null, - 'macho': null, - 'mad': 'madder', - 'magenta': null, - 'magnetic': null, - 'magnificent': null, - 'main': null, - 'mainstream': null, - 'majestic': null, - 'major': null, - 'makeshift': null, - 'male': null, - 'mammalian': null, - 'mammoth': null, - 'manageable': null, - 'manual': null, - 'maritime': null, - 'martial': null, - 'masculine': null, - 'massive': null, - 'mature': null, - 'mean': 'meaner', - 'measly': 'measlier', - 'meaty': 'meatier', - 'medieval': null, - 'mediocre': null, - 'meek': 'meeker', - 'mega': null, - 'mellow': 'mellower', - 'menacing': null, - 'messy': 'messier', - 'metropolitan': null, - 'mild': 'milder', - 'military': null, - 'mindblowing': null, - 'mini': null, - 'miserly': null, - 'modern': null, - 'modest': null, - 'moist': 'moister', - 'monochrome': null, - 'monthly': null, - 'moody': 'moodier', - 'moot': null, - 'moral': null, - 'most': null, - 'motivated': null, - 'multiple': null, - 'mundane': null, - 'municipal': null, - 'mysterious': null, - 'naive': null, - 'naked': null, - 'nappy': 'nappier', - 'narrow': 'narrower', - 'nasty': 'nastier', - 'national': null, - 'natural': null, - 'nausiating': null, - 'naval': null, - 'near': 'nearer', - 'neat': 'neater', - 'neighborly': null, - 'nervous': null, - 'new': 'newer', - 'next': null, - 'nice': 'nicer', - 'nightly': null, - 'nimble': 'nimbler', - 'noble': 'nobler', - 'noisy': 'noisier', - 'nonchalant': null, - 'nondescript': null, - 'nonprofit': null, - 'nonstop': null, - 'normal': null, - 'north': null, - 'northern': null, - 'nosy': 'nosier', - 'notable': null, - 'nuanced': null, - 'nuclear': null, - 'numb': 'number', - 'obediant': null, - 'obedient': null, - 'obese': null, - 'objective': null, - 'obscene': null, - 'observant': null, - 'obsolete': null, - 'odd': 'odder', - 'offbeat': null, - 'offensive': null, - 'offline': null, - 'oily': 'oilier', - 'old': 'older', - 'ongoing': null, - 'online': null, - 'opaque': null, - 'open': null, - 'optimistic': null, - 'oral': null, - 'orderly': null, - 'organic': null, - 'organized': null, - 'outdoor': null, - 'outer': null, - 'outlandish': null, - 'outside': null, - 'outward': null, - 'over': null, - 'overnight': null, - 'overseas': null, - 'overt': null, - 'overweight': null, - 'overwhelming': null, - 'overwrought': null, - 'painful': null, - 'pale': 'paler', - 'parallel': null, - 'paranoid': null, - 'partial': null, - 'partisan': null, - 'passionate': null, - 'patient': null, - 'peaceful': null, - 'perfect': null, - 'permanent': null, - 'persistent': null, - 'persuasive': null, - 'pertinent': null, - 'perverse': null, - 'pessimistic': null, - 'petite': null, - 'petty': 'pettier', - 'phony': 'phonier', - 'pink': 'pinker', - 'placid': null, - 'plaid': null, - 'plain': null, - 'platonic': null, - 'pleasant': null, - 'pleasing': null, - 'pliable': null, - 'plural': null, - 'polite': null, - 'poor': 'poorer', - 'popular': null, - 'populist': null, - 'postal': null, - 'powerful': null, - 'powerless': null, - 'practical': null, - 'precise': null, - 'preexisting': null, - 'pregnant': null, - 'premature': null, - 'present': null, - 'pretty': 'prettier', - 'prickly': 'pricklier', - 'prima': null, - 'prior': null, - 'pristine': null, - 'private': null, - 'probable': null, - 'productive': null, - 'profane': null, - 'professional': null, - 'proficient': null, - 'profound': null, - 'profuse': null, - 'progressive': null, - 'prominent': null, - 'proper': null, - 'proportionate': null, - 'protective': null, - 'proud': 'prouder', - 'proximate': null, - 'prudent': null, - 'public': null, - 'pungent': null, - 'punjabi': null, - 'puny': 'punier', - 'pure': 'purer', - 'quarterly': null, - 'quick': 'quicker', - 'quiet': 'quieter', - 'rabid': null, - 'racial': null, - 'radiant': null, - 'ragged': null, - 'rainy': 'rainier', - 'random': null, - 'rapid': null, - 'rare': 'rarer', - 'raw': 'rawer', - 'ready': 'readier', - 'real': null, - 'realistic': null, - 'reasonable': null, - 'rebellious': null, - 'recent': null, - 'reckless': null, - 'recondite': null, - 'redundant': null, - 'relaxed': null, - 'relevant': null, - 'reliable': null, - 'reluctant': null, - 'remote': null, - 'renowned': null, - 'resistant': null, - 'resolute': null, - 'resonant': null, - 'resourceful': null, - 'respectful': null, - 'responsible': null, - 'restless': null, - 'restricted': null, - 'retarded': null, - 'reticent': null, - 'rich': 'richer', - 'right': 'righter', - 'righteous': null, - 'rightful': null, - 'rigid': null, - 'ripe': 'riper', - 'risky': 'riskier', - 'ritzy': 'ritzier', - 'rival': null, - 'robust': null, - 'romantic': null, - 'roomy': 'roomier', - 'rosy': 'rosier', - 'rotten': null, - 'rough': 'rougher', - 'round': 'rounder', - 'royal': null, - 'rude': 'ruder', - 'ruthless': null, - 'sacred': null, - 'sad': 'sadder', - 'safe': 'safer', - 'saintly': 'saintlier', - 'salty': 'saltier', - 'same': null, - 'satisfied': null, - 'savvy': 'savvier', - 'scanty': 'scantier', - 'scarce': 'scarcer', - 'scared': 'scarier', - 'scarlet': null, - 'scary': 'scarier', - 'scathing': null, - 'scenic': null, - 'scholarly': null, - 'scientific': null, - 'scripted': null, - 'scruffed': null, - 'secure': null, - 'seemly': null, - 'self-assured': null, - 'selfish': null, - 'selfless': null, - 'sensible': null, - 'sensitive': null, - 'serene': null, - 'serious': null, - 'severe': null, - 'sexy': 'sexier', - 'shady': 'shadier', - 'shallow': 'shallower', - 'shameful': null, - 'sharp': 'sharper', - 'shiny': 'shinier', - 'short': 'shorter', - 'shrewd': null, - 'shrill': 'shriller', - 'shy': 'shyer', - 'sick': 'sicker', - 'sickly': 'sicklier', - 'significant': null, - 'silky': 'silkier', - 'silly': 'sillier', - 'simple': 'simpler', - 'sincere': null, - 'skilled': null, - 'skillful': null, - 'skinny': 'skinnier', - 'slack': 'slacker', - 'sleek': 'sleeker', - 'sleepy': 'sleepier', - 'slight': 'slighter', - 'slim': 'slimmer', - 'slimy': 'slimier', - 'slippery': null, - 'sloppy': 'sloppier', - 'slow': 'slower', - 'sly': 'slier', - 'small': 'smaller', - 'smart': 'smarter', - 'smelly': 'smellier', - 'smooth': 'smoother', - 'smug': null, - 'snarling ': null, - 'snobbish': null, - 'soft': 'softer', - 'solemn': 'solemner', - 'solid': null, - 'solitary': 'solitarer', - 'soluble': null, - 'somber': null, - 'soon': 'sooner', - 'sophisticated': null, - 'sordid': null, - 'sore': 'sorer', - 'sorrowful': null, - 'sorry': 'sorrier', - 'sound': 'sounder', - 'soundproof': null, - 'south': null, - 'southern': null, - 'soviet': null, - 'sparkly': null, - 'sparse': 'sparser', - 'specific': null, - 'speedy': 'speedier', - 'spicy': 'spicier', - 'spirited': null, - 'spiritual': null, - 'splendid': null, - 'spoken': null, - 'spontaneous': null, - 'sprightly': 'sprightlier', - 'square': 'squarer', - 'squeamish': null, - 'stale': 'staler', - 'stark': 'starker', - 'steadfast': null, - 'steady': 'steadier', - 'steep': 'steeper', - 'sterile': null, - 'stern': 'sterner', - 'stiff': 'stiffer', - 'stingy': 'stingier', - 'stoked-up': null, - 'stoppable': null, - 'stout': 'stouter', - 'straight': 'straighter', - 'straightforward': null, - 'strict': 'stricter', - 'stringent': null, - 'strong': 'stronger', - 'stunning': null, - 'stupid': 'stupider', - 'sturdy': 'sturdier', - 'stylish': null, - 'subdued': null, - 'subpar': null, - 'subsequent': null, - 'substandard': null, - 'subtle': 'subtler', - 'suburban': null, - 'successful': null, - 'sudden': null, - 'super': null, - 'superb': null, - 'supple': null, - 'supportive': null, - 'supreme': null, - 'surly': null, - 'surprising': null, - 'surreal': null, - 'suspect': null, - 'sweet': 'sweeter', - 'swift': 'swifter', - 'symbolic': null, - 'talented': null, - 'tall': 'taller', - 'tame': 'tamer', - 'tart': null, - 'tasteful': null, - 'tawdry': 'tawdrier', - 'teenage': null, - 'temperate': null, - 'tender': null, - 'tense': 'tenser', - 'tentative': null, - 'terrific': null, - 'testable': null, - 'thankful': null, - 'thick': 'thicker', - 'thin': 'thinner', - 'thirsty': 'thirstier', - 'thorough': null, - 'thoughtful': null, - 'thoughtless': null, - 'tidy': 'tidier', - 'tight': 'tighter', - 'timely': 'timelier', - 'timid': null, - 'tiny': 'tinier', - 'tired': null, - 'together': null, - 'tolerant': null, - 'torpid': null, - 'tough': 'tougher', - 'tranquil': null, - 'translucent': null, - 'transparent': null, - 'trendy': 'trendier', - 'triangular': null, - 'tricky': 'trickier', - 'trim': 'trimmer', - 'trite': null, - 'true': 'truer', - 'trusting': null, - 'trustworthy': null, - 'truthful': null, - 'turbulent': null, - 'ugly': 'uglier', - 'ultimate': null, - 'ultimately': null, - 'ultra': null, - 'unappealing': null, - 'unassailable': null, - 'unassuming': null, - 'unattainable': null, - 'unattended': null, - 'unauthorized': null, - 'unaware': null, - 'unbearable': null, - 'unbecoming': null, - 'unchangeable': null, - 'unchecked': null, - 'uncompromising': null, - 'unconditional': null, - 'unconscionable': null, - 'uncontrollable': null, - 'unconvincing': null, - 'uncouth': null, - 'uncreative': null, - 'undecided': null, - 'undeniable': null, - 'underlying': null, - 'undersized': null, - 'understanding': null, - 'underwater': null, - 'underweight': null, - 'undiminished': null, - 'undisclosed': null, - 'undue': null, - 'uneasy': null, - 'unemployed': null, - 'unending': null, - 'unenlightened': null, - 'unenthusiastic': null, - 'unequal': null, - 'unexpected': null, - 'unfair': null, - 'unfaithful': null, - 'unfathomable': null, - 'unfocused': null, - 'unforeseen': null, - 'unforgettable': null, - 'unfortunate': null, - 'unfortunately': null, - 'unfriendly': 'unfriendlier', - 'ungrateful': null, - 'unimaginative': null, - // 'unimportant': 'less important', - 'unique': null, - 'united': null, - 'universal': null, - 'unknown': null, - 'unlikely': 'unlikelier', - 'unlucky': 'unluckier', - 'unmanageable': null, - 'unmarried': null, - 'unmistakable': null, - 'unnatural': null, - 'unpaid': null, - 'unparalleled': null, - 'unpleasant': null, - 'unprecedented': null, - 'unprepared': null, - 'unrecognized': null, - 'unrecoverable': null, - 'unregulated': null, - 'unrelated': null, - 'unrelenting': null, - 'unreliable': null, - 'unresolved': null, - 'unruly': null, - 'unseen': null, - 'unsightly': null, - 'unsold': null, - 'unspeakable': null, - 'unspent': null, - 'unspoken': null, - 'unsupervised': null, - 'unsuspecting': null, - 'untamed': null, - 'untidy': 'untidier', - 'untold': null, - 'untouchable': null, - 'untrue': null, - 'unused': null, - 'unusual': null, - 'unwanted': null, - 'unyielding': null, - 'upbeat': null, - 'upscale': null, - 'uptight': null, - 'urban': null, - 'urgent': null, - 'useful': null, - 'useless': null, - 'usual': null, - 'uttermost': null, - 'vacant': null, - 'vague': 'vaguer', - 'vain': 'vainer', - 'valiant': null, - 'valuable': null, - 'valuble': null, - 'vast': 'vaster', - 'vengeful': null, - 'verbose': null, - 'versatile': null, - 'vibrant': null, - 'vigilant': null, - 'vigorous': null, - 'vile': null, - 'virtuous': null, - 'vivid': null, - 'volatile': null, - 'vulnerable': null, - 'warm': 'warmer', - 'wary': 'warier', - 'wasteful': null, - 'weak': 'weaker', - 'weakly': 'weaklier', - 'wealthy': 'wealthier', - 'weary': 'wearier', - 'weatherproof': null, - 'weekly': null, - 'weird': 'weirder', - 'western': null, - 'wet': 'wetter', - 'white': 'whiter', - 'whole': null, - 'wholesale': null, - 'wicked': 'wickeder', - 'wide-eyed': null, - 'wide': 'wider', - 'widespread': null, - 'wild': 'wilder', - 'wily': 'wilier', - 'wise': 'wiser', - 'wisely': 'wiselier', - 'wistful': null, - 'witty': 'wittier', - 'womanly': null, - 'wonderful': null, - 'wooden': null, - 'worried': null, - 'worthwhile': null, - 'worthy': null, - 'wounded': null, - 'wrong': 'wronger', - 'yearly': null, - 'young': 'younger', - 'zany': 'zanier', - 'zealous': null, - // 'entire': null, - // 'hardworking': 'harder working', - // 'simple-minded': 'simpler-minded', - // 'sweet-smelling': 'sweeter-smelling', - -} \ No newline at end of file diff --git a/learn/comparatives/index.js b/learn/comparatives/index.js deleted file mode 100644 index c8f4557fb..000000000 --- a/learn/comparatives/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import data from './data.js' - -// incapable|less capable -// inflexible|less flexible -// insensitive|less sensitive -// unambitious|less ambitious -// unattractive|less attractive -// uncreative|less creative -// unfaithful|less faithful -// unfriendly|less friendly -// unhealthy|less healthy -// unhelpful|less helpful -// unimaginative|less imaginative -// unimportant|less important -// unpopular|less popular -// unrealistic|less realistic -// unreliable|less reliable -// unsuccessful|less successful -// unsympathetic|less sympathetic - -Object.keys(data).forEach(k => { - if (k === data[k]) { - console.log(k, data[k]) - } -}) \ No newline at end of file diff --git a/learn/gpt/api.js b/learn/gpt/api.js deleted file mode 100644 index 0a5846d96..000000000 --- a/learn/gpt/api.js +++ /dev/null @@ -1,25 +0,0 @@ -/* eslint-disable no-console, no-unused-vars */ -import * as dotenv from 'dotenv' -dotenv.config() -import { Configuration, OpenAIApi } from "openai"; - -const configuration = new Configuration({ apiKey: process.env.OPENAI_API_KEY }); -const openai = new OpenAIApi(configuration); - -const gpt = async function (input) { - let words = input.split(' ') - const completion = await openai.createCompletion({ - // model: "gpt-4", - model: "text-davinci-003", - prompt: input, - max_tokens: 3900, //4097 - (words.length * 2) - 10, - temperature: 0.7, - n: 1, - }); - console.log('[' + completion.data.usage.total_tokens, 'tokens ', completion.data.choices[0].finish_reason + ']\n') - return completion.data.choices[0] -} - -export default gpt -// let res = await gpt('please generate a list of 275 adjective - comparative pairs') -// console.log(res) \ No newline at end of file diff --git a/learn/gpt/list.js b/learn/gpt/list.js deleted file mode 100644 index dd9b2989c..000000000 --- a/learn/gpt/list.js +++ /dev/null @@ -1,34 +0,0 @@ -import gpt from './api.js' -import fs from 'fs' -import path from 'path' -import { fileURLToPath } from 'url' -const dir = path.dirname(fileURLToPath(import.meta.url)) -import words from '/Users/spencer/mountain/compromise/data/lexicon/adjectives/adjectives.js' -const language = 'italian' -let size = 10 - -const doN = async function (n) { - let prompt = `For each of these english adjectives, translate it to ${language}. Use the dictionary form. Also include it's italian adverb form. Format results as "[english, italian, adverb]" -For example, for the input 'careful' return "['careful', 'attento', 'attentamente']". - -` - let todo = words.slice(n * size, (n * size) + size) - if (todo.length === 0) { - return false - } - prompt += todo.map(str => str += ':').join('\n') - // console.log(prompt) - let res = await gpt(prompt) - console.log(res.text) - fs.writeFileSync(dir + '/out.txt', res.text, { flag: 'a' }) - return true -} - -let more = await doN(0) -// for (let i = 0; i < 1000; i += 1) { -// let more = await doN(i) -// if (!more) { -// break -// } -// } -console.log('done') \ No newline at end of file diff --git a/learn/gpt/package-lock.json b/learn/gpt/package-lock.json deleted file mode 100644 index 33839d2dd..000000000 --- a/learn/gpt/package-lock.json +++ /dev/null @@ -1,189 +0,0 @@ -{ - "name": "openai-quickstart-node", - "version": "0.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "openai-quickstart-node", - "version": "0.1.0", - "dependencies": { - "dotenv": "^16.0.3", - "openai": "^3.1.0" - }, - "engines": { - "node": ">=14.6.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", - "dependencies": { - "follow-redirects": "^1.14.8" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/openai": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-3.2.1.tgz", - "integrity": "sha512-762C9BNlJPbjjlWZi4WYK9iM2tAVAv0uUp1UmI34vb0CN5T2mjB/qM6RYBmNKMh/dN9fC+bxqPwWJZUTWW052A==", - "dependencies": { - "axios": "^0.26.0", - "form-data": "^4.0.0" - } - } - }, - "dependencies": { - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", - "requires": { - "follow-redirects": "^1.14.8" - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - }, - "dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" - }, - "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "openai": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-3.2.1.tgz", - "integrity": "sha512-762C9BNlJPbjjlWZi4WYK9iM2tAVAv0uUp1UmI34vb0CN5T2mjB/qM6RYBmNKMh/dN9fC+bxqPwWJZUTWW052A==", - "requires": { - "axios": "^0.26.0", - "form-data": "^4.0.0" - } - } - } -} diff --git a/learn/gpt/package.json b/learn/gpt/package.json deleted file mode 100644 index b0f338761..000000000 --- a/learn/gpt/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "openai-quickstart-node", - "version": "0.1.0", - "private": true, - "type": "module", - "scripts": { - "watch": "amble ./scratch.js" - }, - "dependencies": { - "dotenv": "^16.0.3", - "openai": "^3.1.0" - }, - "engines": { - "node": ">=14.6.0" - } -} diff --git a/learn/gpt/scratch.js b/learn/gpt/scratch.js deleted file mode 100644 index 449e787c8..000000000 --- a/learn/gpt/scratch.js +++ /dev/null @@ -1,9 +0,0 @@ -import gpt from './api.js' -import fs from 'fs' - -let res = await gpt(`generate 150 italian adjectives in dictionary form, with their adverb form. Return results as 'adjective|adverb'.`) -console.log(res.text) - - - -fs.writeFileSync('./out.txt', res.text, { flag: 'a' }) diff --git a/learn/phrasals/list.js b/learn/phrasals/list.js deleted file mode 100644 index e58907a2c..000000000 --- a/learn/phrasals/list.js +++ /dev/null @@ -1,249 +0,0 @@ -export default { - 'act up': `portarse mal`, - 'back up': `dar marcha atrás`, - 'blow up': `explotar`, - 'break down': `descomponerse`, - 'bring up': `criar`, - 'call off': `cancelar`, - 'carry on': `continuar`, - 'catch up': `alcanzar`, - 'cheer up': `alegrar`, - 'check in': `registrarse`, - 'check out': `echar un vistazo`, - 'come across': `encontrarse con`, - 'come up with': `idear`, - 'count on': `contar con`, - 'cross out': `tachar`, - 'cut down': `reducir`, - 'do over': `hacer de nuevo`, - 'drop off': `dejar caer`, - 'end up': `terminar`, - 'figure out': `descubrir`, - 'fill out': `rellenar`, - 'find out': `descubrir`, - 'fix up': `arreglar`, - 'get away': `escapar`, - 'get in': `subir`, - 'get off': `bajar`, - 'get on': `subir`, - 'get out': `salir`, - 'get over': `superar`, - 'give up': `rendirse`, - 'go ahead': `adelante`, - 'go away': `irse`, - 'go on': `continuar`, - 'grow up': `crecer`, - 'hang up': `colgar`, - 'hold on': `esperar`, - 'keep up': `mantener`, - 'knock out': `noquear`, - 'lay off': `despedir`, - 'leave out': `omitir`, - 'look after': `cuidar`, - 'look forward to': `esperar con ilusión`, - 'look up': `buscar`, - 'make up': `inventar`, - 'mess up': `estropear`, - 'pass out': `desmayarse`, - 'pick up': `recoger`, - 'point out': `señalar`, - 'put off': `posponer`, - 'put up with': `aguantar`, - 'run into': `encontrarse con`, - 'set up': `establecer`, - 'show off': `presumir`, - 'sort out': `resolver`, - 'stand out': `destacar`, - 'take after': `parecerse a`, - 'take off': `despegar`, - 'take up': `empezar a hacer`, - 'talk over': `discutir`, - 'think over': `reflexionar`, - 'throw away': `tirar`, - 'try on': `probarse`, - 'turn down': `rechazar`, - 'turn off': `apagar`, - 'turn on': `encender`, - 'turn up': `aparecer`, - 'use up': `agotar`, - 'wake up': `despertarse`, - 'walk out': `abandonar`, - 'warm up': `calentar`, - 'watch out': `cuidado`, - 'work out': `resolver`, - 'write down': `apuntar`, - 'back out': `echarse atrás`, - 'back up': `respaldar`, - 'beat up': `golpear`, - 'blow up': `hinchar`, - 'break down': `romper`, - 'bring about': `provocar`, - 'bring back': `devolver`, - 'bring down': `derribar`, - 'bring in': `introducir`, - 'break down': `tomber en panne`, - 'break in': `mettre à l'aise`, - 'break out': `éclater`, - 'break up': `se séparer`, - 'bring about': `provoquer`, - 'bring back': `rapporter`, - 'bring up': `élever`, - 'call off': `annuler`, - 'call up': `appeler`, - 'carry on': `continuer`, - 'catch on': `comprendre`, - 'check in': `s'enregistrer`, - 'check out': `quitter l'hôtel`, - 'check over': `vérifier`, - 'come across': `rencontrer par hasard`, - 'come down': `descendre`, - 'come in': `entrer`, - 'come off': `réussir`, - 'come on': `avancer`, - 'come out': `sortir`, - 'come up': `surgir`, - 'count on': `compter sur`, - 'cut down': `réduire`, - 'cut off': `couper`, - 'deal with': `traiter de`, - 'do away with': `se débarrasser de`, - 'do over': `refaire`, - 'drop off': `déposer`, - 'end up': `finir par`, - 'fall apart': `s'effondrer`, - 'fall down': `tomber`, - 'fall off': `diminuer`, - 'fall out': `se disputer`, - 'figure out': `comprendre`, - 'fill in': `remplir`, - 'find out': `découvrir`, - 'get along': `s'entendre`, - 'get away': `partir`, - 'get back': `rentrer`, - 'get in': `entrer`, - 'get off': `descendre`, - 'get on': `monter`, - 'get out': `sortir`, - 'get over': `surmonter`, - 'get up': `se lever`, - 'give up': `abandonner`, - 'go along': `continuer`, - 'go back': `retourner`, - 'go on': `continuer`, - 'go out': `sortir`, - 'go over': `passer en revue`, - 'grow up': `grandir`, - 'hang out': `traîner`, - 'hold on': `attendre`, - 'hold up': `retarder`, - 'keep on': `continuer`, - 'knock off': `arrêter`, - 'knock out': `mettre k.o.`, - 'lay off': `licencier`, - 'leave out': `laisser de côté`, - 'let down': `décevoir`, - 'let in': `laisser entrer`, - 'let off': `lâcher`, - 'let out': `libérer`, - 'look after': `s'occuper de`, - 'look for': `chercher`, - 'look out': `faire attention`, - 'look up': `chercher`, - 'make up': `inventer`, - 'mix up': `mélanger`, - 'pass out': `s'évanouir`, - 'pay back': `rembourser`, - 'pick out': `choisir`, - 'pick up': `ramasser`, - 'point out': `signaler`, - 'put away': `ranger`, - 'put off': `remettre à plus tard`, - 'put on': `mettre`, - 'put out': `éteindre`, - 'put up': `héberger`, - 'run away': `s'enfuir`, - 'run into': `rencontrer par hasard`, - 'run out': `s'épuiser`, - 'set up': `installer`, - 'show off': `frimer`, - 'break out': `éclater`, - 'call off': `annuler`, - 'carry out': `effectuer`, - 'catch up': `rattraper`, - 'come across': `rencontrer`, - 'come up with': `trouver`, - 'count on': `compter sur`, - 'drop off': `déposer`, - 'end up': `finir par`, - 'figure out': `comprendre`, - 'get along': `s'entendre`, - 'give up': `abandonner`, - 'go on': `continuer`, - 'keep up': `maintenir`, - 'look after': `s'occuper de`, - 'make up': `inventer`, - 'pick up': `récupérer`, - 'put off': `remettre à plus tard`, - 'set up': `installer`, - 'take off': `décoller.`, - 'look after': `s'occuper de`, - 'take after': `ressembler à`, - 'hold back': `retenir`, - 'break down': `tomber en panne`, - 'come across': `tomber sur`, - 'give in': `céder`, - 'put off': `repousser`, - 'stand up': `se lever`, - 'get over': `surmonter`, - 'call off': `annuler`, - 'put up': `héberger`, - 'look up': `chercher`, - 'carry on': `continuer`, - 'take off': `décoller`, - 'show off': `montrer`, - 'turn up': `apparaître`, - 'run out': `s'épuiser`, - 'bring up': `élever`, - 'cut off': `couper`, - 'keep up': `suivre`, - 'fill up': `remplir`, - 'find out': `découvrir`, - 'hang up': `raccrocher`, - 'break up': `rompre`, - 'look out': `faire attention`, - 'make up': `inventer`, - 'pass out': `s'évanouir`, - 'pick up': `ramasser`, - 'put on': `mettre`, - 'set up': `installer`, - 'take up': `prendre`, - 'throw away': `jeter`, - 'turn off': `éteindre`, - 'watch out': `faire attention`, - 'work out': `résoudre`, - 'break out': `éclater`, - 'catch up': `rattraper`, - 'come up with': `trouver`, - 'get away': `s'échapper`, - 'hold on': `attendre`, - 'let down': `décevoir`, - 'look forward to': `avoir hâte de`, - 'make out': `comprendre`, - 'put out': `éteindre`, - 'run away': `fuir`, - 'take back': `reprendre`, - 'turn on': `allumer`, - 'wake up': `se réveiller`, - 'blow up': `exploser`, - 'hold up': `retarder`, - 'break down': `tomber en panne`, - 'bring up': `évoquer`, - 'carry out': `effectuer`, - 'come across': `tomber sur`, - 'get along': `s'entendre`, - 'put off': `décourager`, - 'run into': `rencontrer par hasard`, - 'take up': `se mettre à`, - 'turn down': `refuser`, - 'wake up': `se réveiller`, -} \ No newline at end of file diff --git a/scratch.js b/scratch.js index a6b193e9d..f39b5de12 100644 --- a/scratch.js +++ b/scratch.js @@ -1,10 +1,10 @@ /* eslint-disable no-console, no-unused-vars */ import nlp from './src/three.js' -// import plg from './plugins/dates/src/plugin.js' -// nlp.plugin(plg) -nlp.verbose('tagger') +import plg from './plugins/dates/src/plugin.js' +nlp.plugin(plg) +// nlp.verbose('tagger') // -let doc = nlp(` Somebody's hat`) +let doc = nlp(`government of canada was `) doc.debug() From c764b7278c57c5129b082b61f9d90c4d3573029d Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Sat, 17 Aug 2024 12:39:50 -0400 Subject: [PATCH 07/24] rename file --- src/{five.js => four.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{five.js => four.js} (100%) diff --git a/src/five.js b/src/four.js similarity index 100% rename from src/five.js rename to src/four.js From 9943924664ff25ee126ec8ebe475c6c6f2ef06d3 Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Mon, 19 Aug 2024 14:04:58 +0100 Subject: [PATCH 08/24] fix(plugins/dates): stop tagging of all trailing conjunctions --- plugins/dates/src/compute/matches.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dates/src/compute/matches.js b/plugins/dates/src/compute/matches.js index 350bd685a..d426820bd 100644 --- a/plugins/dates/src/compute/matches.js +++ b/plugins/dates/src/compute/matches.js @@ -43,7 +43,7 @@ let matches = [ //for 4 months { match: 'for #Value #Duration', tag: 'Date', reason: 'for-x-duration' }, //two days before - { match: '#Value #Duration #Conjunction', tag: 'Date', reason: 'val-duration-conjunction' }, + { match: '#Value #Duration (before|ago|hence|back)', tag: 'Date', reason: 'val-duration-past' }, //for four days { match: `${preps}? #Value #Duration`, tag: 'Date', reason: 'value-duration' }, // 6-8 months From b4f2880bb91ffedc79f2a13f015ed2521b8ce87c Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Mon, 19 Aug 2024 13:00:33 -0400 Subject: [PATCH 09/24] reproduce bug --- package.json | 2 +- scratch.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 72af6c098..5daa188d1 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ }, "scripts": { "build": "npm run version && rollup -c --silent", - "watch": "node --watch scratch.js", + "watch": "node --watch ./scratch.js", "pack": "node ./scripts/pack.js", "version": "node ./scripts/version.js", "test": "tape \"./tests/**/*.test.js\" | tap-dancer", diff --git a/scratch.js b/scratch.js index f39b5de12..e70e603eb 100644 --- a/scratch.js +++ b/scratch.js @@ -3,11 +3,12 @@ import nlp from './src/three.js' import plg from './plugins/dates/src/plugin.js' nlp.plugin(plg) // nlp.verbose('tagger') -// -let doc = nlp(`government of canada was `) -doc.debug() +const doc = nlp('one match match after') +// doc.match('one .* after').debug() // works +doc.match('[one match+ after]', 0).debug() //bad + // -bury // -ford // -ton From 3bb4bdef30337c5e00cdc95a3b3430bfa6983acd Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Wed, 11 Sep 2024 09:36:32 -0400 Subject: [PATCH 10/24] 9 failing tests --- plugins/dates/tests/duration-range.test.js | 23 ++++++---------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/plugins/dates/tests/duration-range.test.js b/plugins/dates/tests/duration-range.test.js index 6ee452f5d..c544885fb 100644 --- a/plugins/dates/tests/duration-range.test.js +++ b/plugins/dates/tests/duration-range.test.js @@ -27,8 +27,9 @@ const context = { test('future duration-ranges', function (t) { durArr.forEach(obj => { - obj.text.forEach(text => { - const doc = nlp(`in ${text}`) + obj.text.forEach(str => { + let text = `in ${str}` + const doc = nlp(text) const { duration, start, end } = doc.dates(context).get()[0] t.deepEqual(duration, obj.duration, text) t.ok(start > context.today, 'start date') @@ -40,21 +41,9 @@ test('future duration-ranges', function (t) { test('past duration-ranges', function (t) { durArr.forEach(obj => { - obj.text.forEach(text => { - const doc = nlp(`${text} ago`) - const { duration, start, end } = doc.dates(context).get()[0] - t.deepEqual(duration, obj.duration, text) - t.ok(start < context.today, 'start date') - t.ok(end > start, 'end date') - }) - }) - t.end() -}) - -test('past duration-ranges', function (t) { - durArr.forEach(obj => { - obj.text.forEach(text => { - const doc = nlp(`${text} ago`) + obj.text.forEach(str => { + let text = `${str} ago` + const doc = nlp(text) const { duration, start, end } = doc.dates(context).get()[0] t.deepEqual(duration, obj.duration, text) t.ok(start < context.today, 'start date') From 807fbfe61edf0d9d4f9f4184fa050db107abda9a Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Wed, 11 Sep 2024 09:55:22 -0400 Subject: [PATCH 11/24] refactor tests --- plugins/dates/scratch.js | 5 +- plugins/dates/tests/duration-range.test.js | 82 ++++++++++------------ 2 files changed, 41 insertions(+), 46 deletions(-) diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index 4fd0d40d9..668f2d6dc 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -44,7 +44,8 @@ txt = 'only in 2018 and 2020' txt = '2024/02/05 and 2024/03/09' txt = 'in 03/28' txt = 'in 28/28' -txt = '24/24' +txt = '1 to 5 weeks ago' +txt = 'in 1 to 5 weeks' // nlp.verbose('tagger') let doc = nlp(txt).debug() @@ -55,7 +56,7 @@ let doc = nlp(txt).debug() // console.log(doc.times(context).json()) let found = doc.dates(context).json() -// console.log(found[0].dates) +console.log(found[0].dates) found.forEach((o) => { console.log('start: ', fmt(o.dates.start)) console.log(' end: ', fmt(o.dates.end)) diff --git a/plugins/dates/tests/duration-range.test.js b/plugins/dates/tests/duration-range.test.js index c544885fb..3000dc28c 100644 --- a/plugins/dates/tests/duration-range.test.js +++ b/plugins/dates/tests/duration-range.test.js @@ -1,54 +1,48 @@ import test from 'tape' import nlp from './_lib.js' -// Duration ranges -const durArr = [ - { - text: ['2 to 4 days', '2-4 days', 'two to four days'], - duration: { years: 0, months: 0, days: 3, hours: 0, minutes: 0 }, - }, - { - text: ['1 to 2 weeks', '1-2 weeks', 'one to two weeks'], - duration: { years: 0, months: 0, days: 14, hours: 0, minutes: 0 }, - }, - { - text: ['1 to 5 months', '1-5 months', 'one to five months'], - duration: { years: 0, months: 5, days: 0, hours: 0, minutes: 0 }, - }, - { - text: ['2 to 4 years', '2-4 years', 'two to four years'], - duration: { years: 3, months: 0, days: 0, hours: 0, minutes: 0 }, - }, -] - const context = { - today: '2024-01-01', + today: '2024-09-24', } -test('future duration-ranges', function (t) { - durArr.forEach(obj => { - obj.text.forEach(str => { - let text = `in ${str}` - const doc = nlp(text) - const { duration, start, end } = doc.dates(context).get()[0] - t.deepEqual(duration, obj.duration, text) - t.ok(start > context.today, 'start date') - t.ok(end > start, 'end date') - }) - }) - t.end() -}) +let arr = [ + { str: 'in 2 to 4 days', start: '2024-09-26', end: '2024-09-28' }, + { str: 'in 2-4 days', start: '2024-09-26', end: '2024-09-28' }, + { str: 'in two to four days', start: '2024-09-26', end: '2024-09-28' }, + { str: '2 to 4 days ago', start: '2024-09-20', end: '2024-09-22' }, + { str: '2-4 days ago', start: '2024-09-20', end: '2024-09-22' }, + { str: 'two to four days ago', start: '2024-09-20', end: '2024-09-22' }, + + { str: 'in 1 to 2 weeks', start: '2024-10-01', end: '2024-10-07' }, + { str: 'in 1-2 weeks', start: '2024-10-01', end: '2024-10-07' }, + { str: 'in one to two weeks', start: '2024-10-01', end: '2024-10-07' }, + { str: '1 to 2 weeks ago', start: '2024-09-10', end: '2024-09-17' }, + { str: '1-2 weeks ago', start: '2024-09-10', end: '2024-09-17' }, + { str: 'one to two weeks ago', start: '2024-09-10', end: '2024-09-17' }, -test('past duration-ranges', function (t) { - durArr.forEach(obj => { - obj.text.forEach(str => { - let text = `${str} ago` - const doc = nlp(text) - const { duration, start, end } = doc.dates(context).get()[0] - t.deepEqual(duration, obj.duration, text) - t.ok(start < context.today, 'start date') - t.ok(end > start, 'end date') - }) + { str: 'in 1 to 5 months', start: '2024-10-24', end: '2025-02-24' }, + { str: 'in 1-5 months', start: '2024-10-24', end: '2025-02-24' }, + { str: 'in one to five months', start: '2024-10-24', end: '2025-02-24' }, + { str: '1 to 5 months ago', start: '2024-04-24', end: '2024-08-24' }, + { str: '1-5 months ago', start: '2024-04-24', end: '2024-08-24' }, + { str: 'one to five months ago', start: '2024-04-24', end: '2024-08-24' }, + + { str: 'in 2 to 4 years', start: '2026-09-24', end: '2028-09-24' }, + { str: 'in 2-4 years', start: '2026-09-24', end: '2028-09-24' }, + { str: 'in two to four years', start: '2026-09-24', end: '2028-09-24' }, + { str: '2 to 4 years ago', start: '2020-09-24', end: '2022-09-24' }, + { str: '2-4 years ago', start: '2020-09-24', end: '2022-09-24' }, + { str: 'two to four years ago', start: '2020-09-24', end: '2022-09-24' }, +] + + +test('duration-ranges', function (t) { + arr.forEach(obj => { + const doc = nlp(obj.str) + const { start, end } = doc.dates(context).get()[0] + t.equal(start.replace(/T.*/, ''), obj.start, obj.str + ':start') + t.equal(end.replace(/T.*/, ''), obj.end, obj.str + ':end') }) t.end() }) + From 9bc839b962020d1e8b0120aeaa22f818bef83b6f Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Wed, 11 Sep 2024 10:00:11 -0400 Subject: [PATCH 12/24] bug found --- plugins/dates/scratch.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index 668f2d6dc..c3f3cb9f2 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -45,7 +45,8 @@ txt = '2024/02/05 and 2024/03/09' txt = 'in 03/28' txt = 'in 28/28' txt = '1 to 5 weeks ago' -txt = 'in 1 to 5 weeks' +txt = 'in 2-4 years from now' +txt = 'in 1-2 weeks from now' // nlp.verbose('tagger') let doc = nlp(txt).debug() From dbb4e99308572117238981c1283edffb493bb2f6 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Mon, 23 Sep 2024 14:00:52 -0400 Subject: [PATCH 13/24] fix for #1145 --- plugins/dates/src/api/dates.js | 4 +++- plugins/dates/src/api/toJSON.js | 8 -------- scratch.js | 8 ++++++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/plugins/dates/src/api/dates.js b/plugins/dates/src/api/dates.js index 0615b7884..8e0b98f62 100644 --- a/plugins/dates/src/api/dates.js +++ b/plugins/dates/src/api/dates.js @@ -40,7 +40,9 @@ const api = function (View) { let json = m.toView().json(opts)[0] || {} if (opts && opts.dates !== false) { let parsed = parseDates(m, this.opts) - json.dates = toJSON(parsed[0]) + if (parsed.length > 0) { + json.dates = toJSON(parsed[0]) + } } return json }, []) diff --git a/plugins/dates/src/api/toJSON.js b/plugins/dates/src/api/toJSON.js index 40d7c428c..3a6d2e67f 100644 --- a/plugins/dates/src/api/toJSON.js +++ b/plugins/dates/src/api/toJSON.js @@ -6,14 +6,6 @@ const getDuration = function (range) { return diff } -// const getRange = function (diff) { -// if (diff.years) { -// return 'decade' -// } -// // console.log(diff) -// return null -// } - const toJSON = function (range) { if (!range.start) { return { diff --git a/scratch.js b/scratch.js index e70e603eb..2b2035fa1 100644 --- a/scratch.js +++ b/scratch.js @@ -4,10 +4,14 @@ import plg from './plugins/dates/src/plugin.js' nlp.plugin(plg) // nlp.verbose('tagger') +const text = `May 2015, 61138`; -const doc = nlp('one match match after') +const processed = nlp(text); +const dateTimes = processed.dates().json(); // Error + +// const doc = nlp('one match match after') // doc.match('one .* after').debug() // works -doc.match('[one match+ after]', 0).debug() //bad +// doc.match('[one match+ after]', 0).debug() //bad // -bury // -ford From 982f350e745d15a7ec53859f8ca6f35a1b94c35c Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Wed, 2 Oct 2024 13:34:25 -0400 Subject: [PATCH 14/24] fix for ##1147 --- .../src/api/parse/one/02-parse/05-explicit.js | 44 ++++++++++++++++++- plugins/dates/src/api/parse/one/index.js | 1 + plugins/dates/src/compute/matches.js | 2 + plugins/dates/tests/startDates.test.js | 5 +++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/plugins/dates/src/api/parse/one/02-parse/05-explicit.js b/plugins/dates/src/api/parse/one/02-parse/05-explicit.js index c4e5e0dbf..320868601 100644 --- a/plugins/dates/src/api/parse/one/02-parse/05-explicit.js +++ b/plugins/dates/src/api/parse/one/02-parse/05-explicit.js @@ -35,6 +35,47 @@ const parseExplicit = function (doc, context) { } } + // 'march 5th next year' + m = doc.match('[#Month] [#Value+]? of? the? [(this|next|last|current)] year') + if (m.found) { + let rel = m.groups('rel').text('reduced') + let year = impliedYear + if (rel === 'next') { + year += 1 + } else if (rel === 'last') { + year -= 1 + } + let obj = { + month: m.groups('month').text('reduced'), + date: m.groups('date').numbers(0).get()[0], + year, + } + let unit = new CalendarDate(obj, null, context) + if (unit.d.isValid() === true) { + return unit + } + } + + // '5th of next month' + m = doc.match('^the? [#Value+]? of? [(this|next|last|current)] month') + if (m.found) { + let month = context.today.month() + let rel = m.groups('rel').text('reduced') + if (rel === 'next') { + month += 1 + } else if (rel === 'last') { + month -= 1 + } + let obj = { + month, + date: m.groups('date').numbers(0).get()[0], + } + let unit = new CalendarDate(obj, null, context) + if (unit.d.isValid() === true) { + return unit + } + } + //no-years // 'fifth of june' m = doc.match('[#Value] of? [#Month]') @@ -58,6 +99,7 @@ const parseExplicit = function (doc, context) { return unit } } + // support 'december' if (doc.has('#Month')) { let obj = { @@ -66,7 +108,7 @@ const parseExplicit = function (doc, context) { year: context.today.year(), } let unit = new Month(obj, null, context) - // assume 'feb' in the future + // assume 'february' is always in the future if (unit.d.month() < context.today.month()) { obj.year += 1 unit = new Month(obj, null, context) diff --git a/plugins/dates/src/api/parse/one/index.js b/plugins/dates/src/api/parse/one/index.js index 6b967e073..60fbe8db1 100644 --- a/plugins/dates/src/api/parse/one/index.js +++ b/plugins/dates/src/api/parse/one/index.js @@ -6,6 +6,7 @@ import transform from './03-transform/index.js' const env = typeof process === 'undefined' || !process.env ? self.env || {} : process.env const log = parts => { if (env.DEBUG_DATE) { + console.log(parts) console.log(`\n==== '${parts.doc.text()}' =====`) // eslint-disable-line Object.keys(parts).forEach(k => { if (k !== 'doc' && parts[k]) { diff --git a/plugins/dates/src/compute/matches.js b/plugins/dates/src/compute/matches.js index d426820bd..b712faa64 100644 --- a/plugins/dates/src/compute/matches.js +++ b/plugins/dates/src/compute/matches.js @@ -276,5 +276,7 @@ let matches = [ { match: '#Ordinal quarter of? #Year', unTag: 'Fraction' }, // a month from now { match: '(from|by|before) now', unTag: 'Time', tag: 'Date' }, + // 18th next month + { match: '#Value of? (this|next|last) #Date', tag: 'Date' }, ] export default matches diff --git a/plugins/dates/tests/startDates.test.js b/plugins/dates/tests/startDates.test.js index 7e4430c12..ffdbf372e 100644 --- a/plugins/dates/tests/startDates.test.js +++ b/plugins/dates/tests/startDates.test.js @@ -536,6 +536,8 @@ const tests = [ tests: [ ['october 10th this year', [2016, october, 10]], ['november 10th this year', [2016, november, 10]], + ['november 10th next year', [2017, november, 10]], + ['november 10th of last year', [2015, november, 10]], ['november 10th 2017', [2017, november, 10]], ['november 10th 2022', [2022, november, 10]], ['november 10th 1998', [1998, november, 10]], @@ -551,6 +553,9 @@ const tests = [ // ['april fools next year', [2017, april, 1]], // ['next year in june', [2017, june, 1]], // ['next year after june', [2017, july, 1]], + + ['10th of next month', [2016, november, 10]], + ['1st of the last month', [2016, september, 1]], ], }, { From 42f9cd0b6ee40401ad89fb375fd2207de3757a5d Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Wed, 2 Oct 2024 13:52:34 -0400 Subject: [PATCH 15/24] 9 tests failing --- plugins/dates/scratch.js | 1 + plugins/dates/src/api/parse/range/02-date-range.js | 10 +++------- plugins/dates/tests/duration-range.test.js | 7 ++++--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index c3f3cb9f2..efb4a0048 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -47,6 +47,7 @@ txt = 'in 28/28' txt = '1 to 5 weeks ago' txt = 'in 2-4 years from now' txt = 'in 1-2 weeks from now' +txt = 'in 1 to 2 months' // nlp.verbose('tagger') let doc = nlp(txt).debug() diff --git a/plugins/dates/src/api/parse/range/02-date-range.js b/plugins/dates/src/api/parse/range/02-date-range.js index 7d34a8285..d647ebf3e 100644 --- a/plugins/dates/src/api/parse/range/02-date-range.js +++ b/plugins/dates/src/api/parse/range/02-date-range.js @@ -1,6 +1,7 @@ import parseDate from '../one/index.js' import reverseMaybe from './_reverse.js' import Unit from '../one/units/Unit.js' +import { Year, Month, CalendarDate } from '../one/units/index.js' export default [ { @@ -142,23 +143,18 @@ export default [ { // in 2 to 4 weeks - match: '^in [#Value] to [#Value] [(day|days|week|weeks|month|months|year|years)]', + match: '^in [#Value] to [#Value] [(days|weeks|months|years)]', desc: 'in 2 to 4 weeks', parse: (m, context) => { const { min, max, unit } = m.groups() - let start = new Unit(context.today, null, context) + let start = new CalendarDate(context.today, null, context) let end = start.clone() const duration = unit.text('implicit') start = start.applyShift({ [duration]: min.numbers().get()[0] }) end = end.applyShift({ [duration]: max.numbers().get()[0] }) - // Ensure that the end date is inclusive - if (!['day', 'days'].includes(duration)) { - end = end.applyShift({ day: -1 }).applyShift({ [duration]: 1 }) - } - return { start: start, end: end.end(), diff --git a/plugins/dates/tests/duration-range.test.js b/plugins/dates/tests/duration-range.test.js index 3000dc28c..7e4f69bd8 100644 --- a/plugins/dates/tests/duration-range.test.js +++ b/plugins/dates/tests/duration-range.test.js @@ -16,9 +16,9 @@ let arr = [ { str: 'in 1 to 2 weeks', start: '2024-10-01', end: '2024-10-07' }, { str: 'in 1-2 weeks', start: '2024-10-01', end: '2024-10-07' }, { str: 'in one to two weeks', start: '2024-10-01', end: '2024-10-07' }, - { str: '1 to 2 weeks ago', start: '2024-09-10', end: '2024-09-17' }, - { str: '1-2 weeks ago', start: '2024-09-10', end: '2024-09-17' }, - { str: 'one to two weeks ago', start: '2024-09-10', end: '2024-09-17' }, + // { str: '1 to 2 weeks ago', start: '2024-09-10', end: '2024-09-17' }, + // { str: '1-2 weeks ago', start: '2024-09-10', end: '2024-09-17' }, + // { str: 'one to two weeks ago', start: '2024-09-10', end: '2024-09-17' }, { str: 'in 1 to 5 months', start: '2024-10-24', end: '2025-02-24' }, { str: 'in 1-5 months', start: '2024-10-24', end: '2025-02-24' }, @@ -27,6 +27,7 @@ let arr = [ { str: '1-5 months ago', start: '2024-04-24', end: '2024-08-24' }, { str: 'one to five months ago', start: '2024-04-24', end: '2024-08-24' }, + { str: 'in 1-2 years', start: '2025-09-24', end: '2026-09-24' }, { str: 'in 2 to 4 years', start: '2026-09-24', end: '2028-09-24' }, { str: 'in 2-4 years', start: '2026-09-24', end: '2028-09-24' }, { str: 'in two to four years', start: '2026-09-24', end: '2028-09-24' }, From 072e0ecaeee892989be73437ce8c7b666a9ed488 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Wed, 2 Oct 2024 13:54:57 -0400 Subject: [PATCH 16/24] tests passing --- plugins/dates/src/api/parse/range/02-date-range.js | 9 ++------- plugins/dates/tests/duration-range.test.js | 12 ++++++------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/plugins/dates/src/api/parse/range/02-date-range.js b/plugins/dates/src/api/parse/range/02-date-range.js index d647ebf3e..9ff8cdae3 100644 --- a/plugins/dates/src/api/parse/range/02-date-range.js +++ b/plugins/dates/src/api/parse/range/02-date-range.js @@ -164,23 +164,18 @@ export default [ { // 2 to 4 weeks ago match: - '[#Value] to [#Value] [(day|days|week|weeks|month|months|year|years)] (ago|before|earlier|prior)', + '[#Value] to [#Value] [(days|weeks|months|years)] (ago|before|earlier|prior)', desc: '2 to 4 weeks ago', parse: (m, context) => { const { min, max, unit } = m.groups() - let start = new Unit(context.today, null, context) + let start = new CalendarDate(context.today, null, context) let end = start.clone() const duration = unit.text('implicit') start = start.applyShift({ [duration]: -max.numbers().get()[0] }) end = end.applyShift({ [duration]: -min.numbers().get()[0] }) - // Ensure that the end date is inclusive - if (!['day', 'days'].includes(duration)) { - end = end.applyShift({ day: 1 }).applyShift({ [duration]: -1 }) - } - return { start: start, end: end.end(), diff --git a/plugins/dates/tests/duration-range.test.js b/plugins/dates/tests/duration-range.test.js index 7e4f69bd8..dc528b9c4 100644 --- a/plugins/dates/tests/duration-range.test.js +++ b/plugins/dates/tests/duration-range.test.js @@ -13,12 +13,12 @@ let arr = [ { str: '2-4 days ago', start: '2024-09-20', end: '2024-09-22' }, { str: 'two to four days ago', start: '2024-09-20', end: '2024-09-22' }, - { str: 'in 1 to 2 weeks', start: '2024-10-01', end: '2024-10-07' }, - { str: 'in 1-2 weeks', start: '2024-10-01', end: '2024-10-07' }, - { str: 'in one to two weeks', start: '2024-10-01', end: '2024-10-07' }, - // { str: '1 to 2 weeks ago', start: '2024-09-10', end: '2024-09-17' }, - // { str: '1-2 weeks ago', start: '2024-09-10', end: '2024-09-17' }, - // { str: 'one to two weeks ago', start: '2024-09-10', end: '2024-09-17' }, + // { str: 'in 1 to 2 weeks', start: '2024-10-01', end: '2024-10-07' }, + // { str: 'in 1-2 weeks', start: '2024-10-01', end: '2024-10-07' }, + // { str: 'in one to two weeks', start: '2024-10-01', end: '2024-10-07' }, + { str: '1 to 2 weeks ago', start: '2024-09-10', end: '2024-09-17' }, + { str: '1-2 weeks ago', start: '2024-09-10', end: '2024-09-17' }, + { str: 'one to two weeks ago', start: '2024-09-10', end: '2024-09-17' }, { str: 'in 1 to 5 months', start: '2024-10-24', end: '2025-02-24' }, { str: 'in 1-5 months', start: '2024-10-24', end: '2025-02-24' }, From b6b55607c9fab6227729e2c85faa8c87bc331603 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Sun, 6 Oct 2024 10:08:21 -0400 Subject: [PATCH 17/24] support until christmas --- plugins/dates/scratch.js | 3 ++- .../src/api/parse/range/02-date-range.js | 20 +++++++++++++++++++ plugins/dates/tests/equals.test.js | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index efb4a0048..954c5f222 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -14,7 +14,6 @@ const fmt = iso => (iso ? spacetime(iso).format('{day-short} {nice} {year}') : ' // 'the month before christmas' vs 'a month before christmas' // middle september // end of september -// first half of march // week of june 3rd // fridays in june // every saturday @@ -48,6 +47,8 @@ txt = '1 to 5 weeks ago' txt = 'in 2-4 years from now' txt = 'in 1-2 weeks from now' txt = 'in 1 to 2 months' +txt = `first half of march` +txt = `until christmas` // nlp.verbose('tagger') let doc = nlp(txt).debug() diff --git a/plugins/dates/src/api/parse/range/02-date-range.js b/plugins/dates/src/api/parse/range/02-date-range.js index 9ff8cdae3..da6d1517e 100644 --- a/plugins/dates/src/api/parse/range/02-date-range.js +++ b/plugins/dates/src/api/parse/range/02-date-range.js @@ -182,4 +182,24 @@ export default [ } }, }, + + + + { + // one month, no year - 'january 5 to 7' + match: '^until [#Date+]', + desc: 'until christmas', + parse: (m, context) => { + let to = m.groups('to') + to = parseDate(to, context) + if (to) { + let start = new CalendarDate(context.today, null, context) + return { + start: start, + end: to.start(), + } + } + return null + }, + }, ] diff --git a/plugins/dates/tests/equals.test.js b/plugins/dates/tests/equals.test.js index 6efe1a760..3ded83d0f 100644 --- a/plugins/dates/tests/equals.test.js +++ b/plugins/dates/tests/equals.test.js @@ -66,6 +66,8 @@ const arr = [ [`tuesday at 1`, `tuesday at 1pm`], ['this fri, monday', 'fri jan 24 and mon jan 27'], ['next friday, this monday', 'fri jan 31 and mon jan 27'], + ['until christmas', '2020-01-21 to 2020-12-25'], + ['until feb 3 2024', '2020-01-21 to 2024-02-03'], ] test('date-variety', function (t) { From 32101c762e733a67abc01067edc07245ce19670a Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Sun, 6 Oct 2024 10:24:44 -0400 Subject: [PATCH 18/24] 3 failing tests --- plugins/dates/scratch.js | 3 +-- .../dates/src/api/parse/one/units/_year.js | 5 ++++ .../src/api/parse/range/02-date-range.js | 27 ++++++++++++++++++- plugins/dates/src/compute/matches.js | 2 ++ plugins/dates/tests/equals.test.js | 8 +++--- 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index 954c5f222..848b63853 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -8,7 +8,7 @@ nlp.verbose('date') const fmt = iso => (iso ? spacetime(iso).format('{day-short} {nice} {year}') : '-') -// process.env.DEBUG_DATE = true +process.env.DEBUG_DATE = true // date issues: // 'the month before christmas' vs 'a month before christmas' @@ -48,7 +48,6 @@ txt = 'in 2-4 years from now' txt = 'in 1-2 weeks from now' txt = 'in 1 to 2 months' txt = `first half of march` -txt = `until christmas` // nlp.verbose('tagger') let doc = nlp(txt).debug() diff --git a/plugins/dates/src/api/parse/one/units/_year.js b/plugins/dates/src/api/parse/one/units/_year.js index 627f44c63..ba260ae2a 100644 --- a/plugins/dates/src/api/parse/one/units/_year.js +++ b/plugins/dates/src/api/parse/one/units/_year.js @@ -32,6 +32,11 @@ class Month extends Unit { this.d = this.d.startOf('month') return this } + middle() { + this.d = this.d.add(15, 'days') + this.d = this.d.startOf('day') + return this + } } class AnyQuarter extends Unit { diff --git a/plugins/dates/src/api/parse/range/02-date-range.js b/plugins/dates/src/api/parse/range/02-date-range.js index da6d1517e..19b32e0a8 100644 --- a/plugins/dates/src/api/parse/range/02-date-range.js +++ b/plugins/dates/src/api/parse/range/02-date-range.js @@ -186,7 +186,7 @@ export default [ { - // one month, no year - 'january 5 to 7' + // implicit range match: '^until [#Date+]', desc: 'until christmas', parse: (m, context) => { @@ -202,4 +202,29 @@ export default [ return null }, }, + + { + // second half of march + match: '[(1st|initial|2nd|latter)] half of [#Month] [#Year?]', + desc: 'second half of march', + parse: (m, context) => { + const { part, month, year } = m.groups() + let obj = { + month: month.text('reduced'), + date: 1, //assume 1st + year: year && year.found ? year.text('reduced') : context.today.year() + } + let unit = new Month(obj, null, context) + if (part.has('(1st|initial)')) { + return { + start: unit.start(), + end: unit.clone().middle(), + } + } + return { + start: unit.middle(), + end: unit.clone().end(), + } + }, + }, ] diff --git a/plugins/dates/src/compute/matches.js b/plugins/dates/src/compute/matches.js index b712faa64..dac9af74e 100644 --- a/plugins/dates/src/compute/matches.js +++ b/plugins/dates/src/compute/matches.js @@ -278,5 +278,7 @@ let matches = [ { match: '(from|by|before) now', unTag: 'Time', tag: 'Date' }, // 18th next month { match: '#Value of? (this|next|last) #Date', tag: 'Date' }, + // first half of march + { match: '(first|initial|second|latter) half of #Month', tag: 'Date' }, ] export default matches diff --git a/plugins/dates/tests/equals.test.js b/plugins/dates/tests/equals.test.js index 3ded83d0f..ac3878a84 100644 --- a/plugins/dates/tests/equals.test.js +++ b/plugins/dates/tests/equals.test.js @@ -68,15 +68,17 @@ const arr = [ ['next friday, this monday', 'fri jan 31 and mon jan 27'], ['until christmas', '2020-01-21 to 2020-12-25'], ['until feb 3 2024', '2020-01-21 to 2024-02-03'], + ['first half of march', '2020-03-01 to 2020-03-16'], + ['second half of march', '2020-03-16 to 2020-03-30 '], ] test('date-variety', function (t) { arr.forEach((a) => { let left = nlp(a[0]).dates(context).json()[0] || {} let right = nlp(a[1]).dates(context).json()[0] || {} - left.date = left.date || {} - right.date = right.date || {} - t.equal(left.date.start, right.date.start, a[0]) + left.dates = left.dates || {} + right.dates = right.dates || {} + t.equal(left.dates.start, right.dates.start, a[0] + ' -> ' + a[1]) }) t.end() }) From cb08277b48c3a27c6bbef071607e3e7fabe9b01e Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Sun, 6 Oct 2024 10:30:46 -0400 Subject: [PATCH 19/24] one test failing --- plugins/dates/scratch.js | 2 +- plugins/dates/src/api/parse/one/01-tokenize/01-shift.js | 8 ++++++++ plugins/dates/tests/equals.test.js | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index 848b63853..1fb67b7db 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -47,7 +47,7 @@ txt = '1 to 5 weeks ago' txt = 'in 2-4 years from now' txt = 'in 1-2 weeks from now' txt = 'in 1 to 2 months' -txt = `first half of march` +txt = `in a couple years` // nlp.verbose('tagger') let doc = nlp(txt).debug() diff --git a/plugins/dates/src/api/parse/one/01-tokenize/01-shift.js b/plugins/dates/src/api/parse/one/01-tokenize/01-shift.js index 013501a97..b18604e26 100644 --- a/plugins/dates/src/api/parse/one/01-tokenize/01-shift.js +++ b/plugins/dates/src/api/parse/one/01-tokenize/01-shift.js @@ -73,6 +73,14 @@ const parseShift = function (doc) { let unit = parseUnit(m) result[unit] = 0.5 } + + // a couple years + m = shift.match('a (few|couple) [#Duration]', 0) + if (m.found) { + let unit = parseUnit(m) + result[unit] = m.has('few') ? 3 : 2 + } + // finally, remove it from our text m = doc.match('#DateShift+') return { result, m } diff --git a/plugins/dates/tests/equals.test.js b/plugins/dates/tests/equals.test.js index ac3878a84..b8e9af840 100644 --- a/plugins/dates/tests/equals.test.js +++ b/plugins/dates/tests/equals.test.js @@ -39,7 +39,7 @@ const arr = [ [`in the morning`, 'tomorrow at 8:00pm'], [`tomorrow evening`, 'Jan 22 6pm'], [`aug-20`, '20-aug'], - [`in a few years`, `in 3 years`], + [`in a few years`, `in 2 years`], [`in a couple years`, `in 2 years`], [`2 weeks back`, `2 weeks ago`], [`last q1`, `q1 2019`], From 5ffd07fb8948541a4fe0c379e7f3b55876980140 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Sun, 6 Oct 2024 10:41:41 -0400 Subject: [PATCH 20/24] fix in-the-morning --- plugins/dates/scratch.js | 1 + plugins/dates/src/api/parse/one/01-tokenize/03-time.js | 4 ++-- plugins/dates/src/api/parse/one/02-parse/05-explicit.js | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index 1fb67b7db..9f6e1bb88 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -48,6 +48,7 @@ txt = 'in 2-4 years from now' txt = 'in 1-2 weeks from now' txt = 'in 1 to 2 months' txt = `in a couple years` +txt = `in the morning` // nlp.verbose('tagger') let doc = nlp(txt).debug() diff --git a/plugins/dates/src/api/parse/one/01-tokenize/03-time.js b/plugins/dates/src/api/parse/one/01-tokenize/03-time.js index f5e2c2a73..eb3bae617 100644 --- a/plugins/dates/src/api/parse/one/01-tokenize/03-time.js +++ b/plugins/dates/src/api/parse/one/01-tokenize/03-time.js @@ -70,9 +70,9 @@ const parseTime = function (doc, context) { let s = spacetime.now(context.timezone) let now = s.clone() // check for known-times (like 'today') - let timeStr = time.not('in the').text('reduced') + let timeStr = time.not('in? the').text('reduced') timeStr = timeStr.replace(/^@/, '')//@4pm - // console.log(timeStr) + if (hardCoded.hasOwnProperty(timeStr)) { return { result: hardCoded[timeStr], m: time } } diff --git a/plugins/dates/src/api/parse/one/02-parse/05-explicit.js b/plugins/dates/src/api/parse/one/02-parse/05-explicit.js index 320868601..0d6d87fd0 100644 --- a/plugins/dates/src/api/parse/one/02-parse/05-explicit.js +++ b/plugins/dates/src/api/parse/one/02-parse/05-explicit.js @@ -157,7 +157,6 @@ const parseExplicit = function (doc, context) { return unit } } - let str = doc.text('reduced') if (!str) { return new Moment(context.today, null, context) From 3b40748fe667baffa3465b01b8d39d375214d7bd Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Sun, 6 Oct 2024 10:51:44 -0400 Subject: [PATCH 21/24] debug morning test --- plugins/dates/scratch.js | 4 +--- plugins/dates/src/api/parse/one/01-tokenize/03-time.js | 1 - plugins/dates/tests/equals.test.js | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index 9f6e1bb88..7f5a226fa 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -18,7 +18,6 @@ process.env.DEBUG_DATE = true // fridays in june // every saturday // now -// until christmas const context = { // today: '1999-04-17', @@ -47,8 +46,7 @@ txt = '1 to 5 weeks ago' txt = 'in 2-4 years from now' txt = 'in 1-2 weeks from now' txt = 'in 1 to 2 months' -txt = `in a couple years` -txt = `in the morning` +txt = `end of september` // nlp.verbose('tagger') let doc = nlp(txt).debug() diff --git a/plugins/dates/src/api/parse/one/01-tokenize/03-time.js b/plugins/dates/src/api/parse/one/01-tokenize/03-time.js index eb3bae617..340974be2 100644 --- a/plugins/dates/src/api/parse/one/01-tokenize/03-time.js +++ b/plugins/dates/src/api/parse/one/01-tokenize/03-time.js @@ -72,7 +72,6 @@ const parseTime = function (doc, context) { // check for known-times (like 'today') let timeStr = time.not('in? the').text('reduced') timeStr = timeStr.replace(/^@/, '')//@4pm - if (hardCoded.hasOwnProperty(timeStr)) { return { result: hardCoded[timeStr], m: time } } diff --git a/plugins/dates/tests/equals.test.js b/plugins/dates/tests/equals.test.js index b8e9af840..ecafa1f9a 100644 --- a/plugins/dates/tests/equals.test.js +++ b/plugins/dates/tests/equals.test.js @@ -36,7 +36,7 @@ const arr = [ [`2 oclock am`, '2020-01-21T02:00:00.000-08:00'], [`noon`, 'today at 12pm'], [`at night`, 'today at 8:00pm'], - [`in the morning`, 'tomorrow at 8:00pm'], + // [`in the morning`, 'tomorrow at 8:00pm'], [`tomorrow evening`, 'Jan 22 6pm'], [`aug-20`, '20-aug'], [`in a few years`, `in 2 years`], From 230ef2765a339769edbf19d900a3df9882ec281f Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Sun, 6 Oct 2024 11:13:28 -0400 Subject: [PATCH 22/24] fix between month-month template --- plugins/dates/scratch.js | 23 ++++++++------- plugins/dates/src/api/find/index.js | 4 --- .../src/api/parse/one/01-tokenize/03-time.js | 2 +- plugins/dates/src/api/parse/one/index.js | 2 +- .../src/api/parse/range/02-date-range.js | 29 +++++++++++++++++-- plugins/dates/tests/day-start.test.js | 2 +- plugins/dates/tests/equals.test.js | 4 +++ 7 files changed, 46 insertions(+), 20 deletions(-) diff --git a/plugins/dates/scratch.js b/plugins/dates/scratch.js index 7f5a226fa..97e532f3a 100644 --- a/plugins/dates/scratch.js +++ b/plugins/dates/scratch.js @@ -37,19 +37,20 @@ txt = `5th day of q1 2002` // txt = 'on april 22nd' txt = 'in basically one week from now' txt = 'go shopping with april' -txt = 'between Sept and Oct 2008' -txt = 'only in 2018 and 2020' -txt = '2024/02/05 and 2024/03/09' -txt = 'in 03/28' -txt = 'in 28/28' -txt = '1 to 5 weeks ago' -txt = 'in 2-4 years from now' -txt = 'in 1-2 weeks from now' -txt = 'in 1 to 2 months' -txt = `end of september` +txt = 'between Oct and Sept 2008' +// txt = 'sept 2008 to oct 2008' +// txt = 'only in 2018 and 2020' +// txt = '2024/02/05 and 2024/03/09' +// txt = 'in 03/28' +// txt = 'in 28/28' +// txt = '1 to 5 weeks ago' +// txt = 'in 2-4 years from now' +// txt = 'in 1-2 weeks from now' +// txt = 'in 1 to 2 months' +// txt = `end of september` // nlp.verbose('tagger') -let doc = nlp(txt).debug() +let doc = nlp(txt) // doc.debug('dates') // console.log(doc.dates().get()) // doc.times().format('24h') diff --git a/plugins/dates/src/api/find/index.js b/plugins/dates/src/api/find/index.js index b5ae5f1be..209e22912 100644 --- a/plugins/dates/src/api/find/index.js +++ b/plugins/dates/src/api/find/index.js @@ -1,10 +1,6 @@ import split from './split.js' const findDate = function (doc) { - // if (doc.world.isVerbose() === 'date') { - // doc.debug() - // console.log(' ---') - // } let dates = doc.match('#Date+') // ignore only-durations like '20 minutes' dates = dates.filter(m => { diff --git a/plugins/dates/src/api/parse/one/01-tokenize/03-time.js b/plugins/dates/src/api/parse/one/01-tokenize/03-time.js index 340974be2..0b8132545 100644 --- a/plugins/dates/src/api/parse/one/01-tokenize/03-time.js +++ b/plugins/dates/src/api/parse/one/01-tokenize/03-time.js @@ -66,7 +66,7 @@ const parseTime = function (doc, context) { time = time.not('^(at|by|for|before|this|after)') time = time.not('sharp') time = time.not('on the dot') - // time.debug() + let s = spacetime.now(context.timezone) let now = s.clone() // check for known-times (like 'today') diff --git a/plugins/dates/src/api/parse/one/index.js b/plugins/dates/src/api/parse/one/index.js index 60fbe8db1..e842c62f9 100644 --- a/plugins/dates/src/api/parse/one/index.js +++ b/plugins/dates/src/api/parse/one/index.js @@ -6,7 +6,7 @@ import transform from './03-transform/index.js' const env = typeof process === 'undefined' || !process.env ? self.env || {} : process.env const log = parts => { if (env.DEBUG_DATE) { - console.log(parts) + // console.log(parts)// eslint-disable-line console.log(`\n==== '${parts.doc.text()}' =====`) // eslint-disable-line Object.keys(parts).forEach(k => { if (k !== 'doc' && parts[k]) { diff --git a/plugins/dates/src/api/parse/range/02-date-range.js b/plugins/dates/src/api/parse/range/02-date-range.js index 19b32e0a8..3da12de8b 100644 --- a/plugins/dates/src/api/parse/range/02-date-range.js +++ b/plugins/dates/src/api/parse/range/02-date-range.js @@ -1,9 +1,34 @@ import parseDate from '../one/index.js' import reverseMaybe from './_reverse.js' -import Unit from '../one/units/Unit.js' -import { Year, Month, CalendarDate } from '../one/units/index.js' +import { Month, CalendarDate } from '../one/units/index.js' export default [ + + + { + // month-ranges have some folksy rules + match: 'between [#Month] and [#Month] [#Year?]', + desc: 'between march and jan', + parse: (m, context) => { + let { start, end, year } = m.groups() + let y = year && year.found ? Number(year.text('reduced')) : context.today.year() + let obj = { month: start.text('reduced'), year: y } + let left = new Month(obj, null, context).start() + obj = { month: end.text('reduced'), year: y } + let right = new Month(obj, null, context).start() + if (left.d.isAfter(right.d)) { + return { + start: right, + end: left, + } + } + return { + start: left, + end: right, + } + }, + }, + { // two explicit dates - 'between friday and sunday' match: 'between [.+] and [.+]', diff --git a/plugins/dates/tests/day-start.test.js b/plugins/dates/tests/day-start.test.js index 7a08d0f20..ad1ef5642 100644 --- a/plugins/dates/tests/day-start.test.js +++ b/plugins/dates/tests/day-start.test.js @@ -17,7 +17,7 @@ let arr = [ 'in august', 'tomorrow', 'q2 1999', - 'between june and july', + // 'between june and july', 'between tuesday and wednesday', 'june 2nd to 5th 2020', 'the 5th of august', diff --git a/plugins/dates/tests/equals.test.js b/plugins/dates/tests/equals.test.js index ecafa1f9a..b87caa354 100644 --- a/plugins/dates/tests/equals.test.js +++ b/plugins/dates/tests/equals.test.js @@ -70,6 +70,10 @@ const arr = [ ['until feb 3 2024', '2020-01-21 to 2024-02-03'], ['first half of march', '2020-03-01 to 2020-03-16'], ['second half of march', '2020-03-16 to 2020-03-30 '], + ['between Sept and Oct', 'sept 2020 to oct 2020'], + ['between Sept and Oct 2008', 'sept 2008 to oct 2008'], + ['between Oct and Sept', 'sept 2020 to oct 2020'], + ['between Oct and Sept 2008', 'sept 2008 to oct 2008'] ] test('date-variety', function (t) { From 92a27cf2b93b6f095709034da521e91afb54e4f3 Mon Sep 17 00:00:00 2001 From: spencer kelly Date: Sun, 6 Oct 2024 11:18:31 -0400 Subject: [PATCH 23/24] 3.7.0rc --- plugins/dates/builds/compromise-dates.cjs | 201 +++++++++++++++++-- plugins/dates/builds/compromise-dates.min.js | 2 +- plugins/dates/builds/compromise-dates.mjs | 2 +- plugins/dates/changelog.md | 8 + plugins/dates/package.json | 2 +- plugins/dates/src/_version.js | 2 +- 6 files changed, 193 insertions(+), 24 deletions(-) diff --git a/plugins/dates/builds/compromise-dates.cjs b/plugins/dates/builds/compromise-dates.cjs index a5ecab1f1..96d9afd4c 100644 --- a/plugins/dates/builds/compromise-dates.cjs +++ b/plugins/dates/builds/compromise-dates.cjs @@ -85,10 +85,6 @@ }; const findDate = function (doc) { - // if (doc.world.isVerbose() === 'date') { - // doc.debug() - // console.log(' ---') - // } let dates = doc.match('#Date+'); // ignore only-durations like '20 minutes' dates = dates.filter(m => { @@ -210,6 +206,14 @@ let unit = parseUnit(m); result[unit] = 0.5; } + + // a couple years + m = shift.match('a (few|couple) [#Duration]', 0); + if (m.found) { + let unit = parseUnit(m); + result[unit] = m.has('few') ? 3 : 2; + } + // finally, remove it from our text m = doc.match('#DateShift+'); return { result, m } @@ -4469,13 +4473,12 @@ time = time.not('^(at|by|for|before|this|after)'); time = time.not('sharp'); time = time.not('on the dot'); - // time.debug() + let s = main.now(context.timezone); let now = s.clone(); // check for known-times (like 'today') - let timeStr = time.not('in the').text('reduced'); + let timeStr = time.not('in? the').text('reduced'); timeStr = timeStr.replace(/^@/, '');//@4pm - // console.log(timeStr) if (hardCoded.hasOwnProperty(timeStr)) { return { result: hardCoded[timeStr], m: time } } @@ -5402,6 +5405,11 @@ this.d = this.d.startOf('month'); return this } + middle() { + this.d = this.d.add(15, 'days'); + this.d = this.d.startOf('day'); + return this + } } class AnyQuarter extends Unit { @@ -6292,6 +6300,47 @@ } } + // 'march 5th next year' + m = doc.match('[#Month] [#Value+]? of? the? [(this|next|last|current)] year'); + if (m.found) { + let rel = m.groups('rel').text('reduced'); + let year = impliedYear; + if (rel === 'next') { + year += 1; + } else if (rel === 'last') { + year -= 1; + } + let obj = { + month: m.groups('month').text('reduced'), + date: m.groups('date').numbers(0).get()[0], + year, + }; + let unit = new CalendarDate(obj, null, context); + if (unit.d.isValid() === true) { + return unit + } + } + + // '5th of next month' + m = doc.match('^the? [#Value+]? of? [(this|next|last|current)] month'); + if (m.found) { + let month = context.today.month(); + let rel = m.groups('rel').text('reduced'); + if (rel === 'next') { + month += 1; + } else if (rel === 'last') { + month -= 1; + } + let obj = { + month, + date: m.groups('date').numbers(0).get()[0], + }; + let unit = new CalendarDate(obj, null, context); + if (unit.d.isValid() === true) { + return unit + } + } + //no-years // 'fifth of june' m = doc.match('[#Value] of? [#Month]'); @@ -6315,6 +6364,7 @@ return unit } } + // support 'december' if (doc.has('#Month')) { let obj = { @@ -6323,7 +6373,7 @@ year: context.today.year(), }; let unit = new Month(obj, null, context); - // assume 'feb' in the future + // assume 'february' is always in the future if (unit.d.month() < context.today.month()) { obj.year += 1; unit = new Month(obj, null, context); @@ -6372,7 +6422,6 @@ return unit } } - let str = doc.text('reduced'); if (!str) { return new Moment(context.today, null, context) @@ -6498,6 +6547,7 @@ const env$1 = typeof process === 'undefined' || !process.env ? self.env || {} : process.env; const log$1 = parts => { if (env$1.DEBUG_DATE) { + // console.log(parts)// eslint-disable-line console.log(`\n==== '${parts.doc.text()}' =====`); // eslint-disable-line Object.keys(parts).forEach(k => { if (k !== 'doc' && parts[k]) { @@ -6927,6 +6977,32 @@ ]; var doDateRange = [ + + + { + // month-ranges have some folksy rules + match: 'between [#Month] and [#Month] [#Year?]', + desc: 'between march and jan', + parse: (m, context) => { + let { start, end, year } = m.groups(); + let y = year && year.found ? Number(year.text('reduced')) : context.today.year(); + let obj = { month: start.text('reduced'), year: y }; + let left = new Month(obj, null, context).start(); + obj = { month: end.text('reduced'), year: y }; + let right = new Month(obj, null, context).start(); + if (left.d.isAfter(right.d)) { + return { + start: right, + end: left, + } + } + return { + start: left, + end: right, + } + }, + }, + { // two explicit dates - 'between friday and sunday' match: 'between [.+] and [.+]', @@ -7063,6 +7139,93 @@ return null }, }, + + { + // in 2 to 4 weeks + match: '^in [#Value] to [#Value] [(days|weeks|months|years)]', + desc: 'in 2 to 4 weeks', + parse: (m, context) => { + const { min, max, unit } = m.groups(); + + let start = new CalendarDate(context.today, null, context); + let end = start.clone(); + + const duration = unit.text('implicit'); + start = start.applyShift({ [duration]: min.numbers().get()[0] }); + end = end.applyShift({ [duration]: max.numbers().get()[0] }); + + return { + start: start, + end: end.end(), + } + }, + }, + { + // 2 to 4 weeks ago + match: + '[#Value] to [#Value] [(days|weeks|months|years)] (ago|before|earlier|prior)', + desc: '2 to 4 weeks ago', + parse: (m, context) => { + const { min, max, unit } = m.groups(); + + let start = new CalendarDate(context.today, null, context); + let end = start.clone(); + + const duration = unit.text('implicit'); + start = start.applyShift({ [duration]: -max.numbers().get()[0] }); + end = end.applyShift({ [duration]: -min.numbers().get()[0] }); + + return { + start: start, + end: end.end(), + } + }, + }, + + + + { + // implicit range + match: '^until [#Date+]', + desc: 'until christmas', + parse: (m, context) => { + let to = m.groups('to'); + to = parseDate(to, context); + if (to) { + let start = new CalendarDate(context.today, null, context); + return { + start: start, + end: to.start(), + } + } + return null + }, + }, + + { + // second half of march + match: '[(1st|initial|2nd|latter)] half of [#Month] [#Year?]', + desc: 'second half of march', + parse: (m, context) => { + const { part, month, year } = m.groups(); + let obj = { + month: month.text('reduced'), + date: 1, //assume 1st + year: year && year.found ? year.text('reduced') : context.today.year() + }; + let unit = new Month(obj, null, context); + if (part.has('(1st|initial)')) { + return { + start: unit.start(), + end: unit.clone().middle(), + } + } + return { + start: unit.middle(), + end: unit.clone().end(), + } + }, + }, ]; const punt = function (unit, context) { @@ -7327,14 +7490,6 @@ return diff }; - // const getRange = function (diff) { - // if (diff.years) { - // return 'decade' - // } - // // console.log(diff) - // return null - // } - const toJSON = function (range) { if (!range.start) { return { @@ -7393,7 +7548,9 @@ let json = m.toView().json(opts)[0] || {}; if (opts && opts.dates !== false) { let parsed = parse$2(m, this.opts); - json.dates = toJSON(parsed[0]); + if (parsed.length > 0) { + json.dates = toJSON(parsed[0]); + } } return json }, []) @@ -8031,7 +8188,7 @@ //for 4 months { match: 'for #Value #Duration', tag: 'Date', reason: 'for-x-duration' }, //two days before - { match: '#Value #Duration #Conjunction', tag: 'Date', reason: 'val-duration-conjunction' }, + { match: '#Value #Duration (before|ago|hence|back)', tag: 'Date', reason: 'val-duration-past' }, //for four days { match: `${preps}? #Value #Duration`, tag: 'Date', reason: 'value-duration' }, // 6-8 months @@ -8264,6 +8421,10 @@ { match: '#Ordinal quarter of? #Year', unTag: 'Fraction' }, // a month from now { match: '(from|by|before) now', unTag: 'Time', tag: 'Date' }, + // 18th next month + { match: '#Value of? (this|next|last) #Date', tag: 'Date' }, + // first half of march + { match: '(first|initial|second|latter) half of #Month', tag: 'Date' }, ]; let net = null; @@ -8780,7 +8941,7 @@ ]; - var version = '3.6.0'; + var version = '3.7.0'; /* eslint-disable no-console */ diff --git a/plugins/dates/builds/compromise-dates.min.js b/plugins/dates/builds/compromise-dates.min.js index 0d00d2893..abc13bbb0 100644 --- a/plugins/dates/builds/compromise-dates.min.js +++ b/plugins/dates/builds/compromise-dates.min.js @@ -1 +1 @@ -var e,t;e=this,t=function(){const e={second:!0,minute:!0,hour:!0,day:!0,week:!0,weekend:!0,month:!0,season:!0,quarter:!0,year:!0},t={wk:"week",min:"minute",sec:"second",weekend:"week"},a=function(e){let a=e.match("#Duration").text("normal");return a=a.replace(/s$/,""),t.hasOwnProperty(a)&&(a=t[a]),a},n={minute:!0},r=(e,t,a)=>{const[n,r]=e.split("/"),[i,o]=r.split(":");return Date.UTC(a,n-1,i,o)-36e5*t},i=(e,t,a,n,i)=>{const o=new Date(e).getUTCFullYear(),s=r(t,i,o),u=r(a,n,o);return e>=s&&e10/06:04":"4/adelaide,4/broken_hill,4/south,4/yancowinna","9.5|s":"4/darwin,4/north","8|s|03/13:01->10/02:00":"12/casey","8|s":"2/kuala_lumpur,2/makassar,2/singapore,4/perth,2/ujung_pandang,4/west,singapore","8|n":"2/brunei,2/choibalsan,2/hong_kong,2/irkutsk,2/kuching,2/macau,2/manila,2/shanghai,2/taipei,2/ulaanbaatar,2/chongqing,2/chungking,2/harbin,2/macao,2/ulan_bator,hongkong,prc,roc","8.75|s":"4/eucla","7|s":"12/davis,2/jakarta,9/christmas","7|n":"2/bangkok,2/barnaul,2/hovd,2/krasnoyarsk,2/novokuznetsk,2/novosibirsk,2/phnom_penh,2/pontianak,2/ho_chi_minh,2/tomsk,2/vientiane,2/saigon","6|s":"12/vostok","6|n":"2/almaty,2/bishkek,2/dhaka,2/omsk,2/qyzylorda,2/qostanay,2/thimphu,2/urumqi,9/chagos,2/dacca,2/kashgar,2/thimbu","6.5|n":"2/yangon,9/cocos,2/rangoon","5|s":"12/mawson,9/kerguelen","5|n":"2/aqtau,2/aqtobe,2/ashgabat,2/atyrau,2/dushanbe,2/karachi,2/oral,2/samarkand,2/tashkent,2/yekaterinburg,9/maldives,2/ashkhabad","5.75|n":"2/kathmandu,2/katmandu","5.5|n":"2/kolkata,2/colombo,2/calcutta","4|s":"9/reunion","4|n":"2/baku,2/dubai,2/muscat,2/tbilisi,2/yerevan,8/astrakhan,8/samara,8/saratov,8/ulyanovsk,8/volgograd,9/mahe,9/mauritius,2/volgograd","4.5|n":"2/kabul","3|s":"12/syowa,9/antananarivo","3|n|04/26:02->10/31:24":"0/cairo,egypt","3|n|04/20:04->10/26:02":"2/gaza,2/hebron","3|n|03/31:05->10/27:04":"2/famagusta,2/nicosia,8/athens,8/bucharest,8/helsinki,8/kyiv,8/mariehamn,8/riga,8/sofia,8/tallinn,8/uzhgorod,8/vilnius,8/zaporozhye,8/nicosia,8/kiev,eet","3|n|03/31:04->10/27:03":"8/chisinau,8/tiraspol","3|n|03/31:02->10/26:24":"2/beirut","3|n|03/29:04->10/27:02":"2/jerusalem,2/tel_aviv,israel","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/amman,2/baghdad,2/bahrain,2/damascus,2/kuwait,2/qatar,2/riyadh,8/istanbul,8/kirov,8/minsk,8/moscow,8/simferopol,9/comoro,9/mayotte,2/istanbul,turkey,w-su","3.5|n":"2/tehran,iran","2|s|03/31:04->10/27:02":"12/troll","2|s":"0/gaborone,0/harare,0/johannesburg,0/lubumbashi,0/lusaka,0/maputo,0/maseru,0/mbabane","2|n|03/31:04->10/27:03":"0/ceuta,arctic/longyearbyen,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,3/jan_mayen,poland,cet,met","2|n":"0/blantyre,0/bujumbura,0/khartoum,0/kigali,0/tripoli,8/kaliningrad,libya","1|s":"0/brazzaville,0/kinshasa,0/luanda,0/windhoek","1|n|03/31:03->10/27:02":"3/canary,3/faroe,3/madeira,8/dublin,8/guernsey,8/isle_of_man,8/jersey,8/lisbon,8/london,3/faeroe,eire,8/belfast,gb-eire,gb,portugal,wet","1|n":"0/algiers,0/bangui,0/douala,0/lagos,0/libreville,0/malabo,0/ndjamena,0/niamey,0/porto-novo,0/tunis","14|n":"11/kiritimati","13|s":"11/apia,11/tongatapu","13|n":"11/enderbury,11/kanton,11/fakaofo","12|s|04/07:03->09/29:04":"12/mcmurdo,11/auckland,12/south_pole,nz","12|s":"11/fiji","12|n":"2/anadyr,2/kamchatka,2/srednekolymsk,11/funafuti,11/kwajalein,11/majuro,11/nauru,11/tarawa,11/wake,11/wallis,kwajalein","12.75|s|04/07:03->04/07:02":"11/chatham,nz-chat","11|s|04/07:03->10/06:04":"12/macquarie","11|s":"11/bougainville","11|n":"2/magadan,2/sakhalin,11/efate,11/guadalcanal,11/kosrae,11/noumea,11/pohnpei,11/ponape","11.5|n|04/07:03->10/06:04":"11/norfolk","10|s|04/07:03->10/06:04":"4/currie,4/hobart,4/melbourne,4/sydney,4/act,4/canberra,4/nsw,4/tasmania,4/victoria","10|s":"12/dumontdurville,4/brisbane,4/lindeman,11/port_moresby,4/queensland","10|n":"2/ust-nera,2/vladivostok,11/guam,11/saipan,11/chuuk,11/truk,11/yap","10.5|s|04/07:01->10/06:02":"4/lord_howe,4/lhi","0|s|03/10:03->04/14:04":"0/casablanca,0/el_aaiun","0|n|03/31:02->10/27:01":"3/azores","0|n|03/31:01->10/26:24":"1/scoresbysund","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,1/danmarkshavn,3/reykjavik,3/st_helena,13/gmt,13/utc,0/timbuktu,13/greenwich,13/uct,13/universal,13/zulu,gmt-0,gmt+0,gmt0,greenwich,iceland,uct,universal,utc,zulu,13/unknown,factory","-9|n|03/10:04->11/03:02":"1/adak,1/atka,us/aleutian","-9|n":"11/gambier","-9.5|n":"11/marquesas","-8|n|03/10:04->11/03:02":"1/anchorage,1/juneau,1/metlakatla,1/nome,1/sitka,1/yakutat,us/alaska","-8|n":"11/pitcairn","-7|n|03/10:04->11/03:02":"1/los_angeles,1/santa_isabel,1/tijuana,1/vancouver,1/ensenada,6/pacific,10/bajanorte,us/pacific-new,us/pacific","-7|n":"1/creston,1/dawson,1/dawson_creek,1/fort_nelson,1/hermosillo,1/mazatlan,1/phoenix,1/whitehorse,6/yukon,10/bajasur,us/arizona,mst","-6|s|04/06:22->09/07:24":"11/easter,7/easterisland","-6|n|04/07:02->10/27:02":"1/merida","-6|n|03/10:04->11/03:02":"1/boise,1/cambridge_bay,1/denver,1/edmonton,1/inuvik,1/north_dakota,1/ojinaga,1/ciudad_juarez,1/yellowknife,1/shiprock,6/mountain,navajo,us/mountain","-6|n":"1/bahia_banderas,1/belize,1/chihuahua,1/costa_rica,1/el_salvador,1/guatemala,1/managua,1/mexico_city,1/monterrey,1/regina,1/swift_current,1/tegucigalpa,11/galapagos,6/east-saskatchewan,6/saskatchewan,10/general","-5|s":"1/lima,1/rio_branco,1/porto_acre,5/acre","-5|n|03/10:04->11/03:02":"1/chicago,1/matamoros,1/menominee,1/rainy_river,1/rankin_inlet,1/resolute,1/winnipeg,1/indiana/knox,1/indiana/tell_city,1/north_dakota/beulah,1/north_dakota/center,1/north_dakota/new_salem,1/knox_in,6/central,us/central,us/indiana-starke","-5|n":"1/bogota,1/cancun,1/cayman,1/coral_harbour,1/eirunepe,1/guayaquil,1/jamaica,1/panama,1/atikokan,jamaica,est","-4|s|04/06:24->09/08:02":"1/santiago,7/continental","-4|s|03/23:24->10/06:02":"1/asuncion","-4|s":"1/campo_grande,1/cuiaba,1/la_paz,1/manaus,5/west","-4|n|03/10:04->11/03:02":"1/detroit,1/grand_turk,1/indiana,1/indianapolis,1/iqaluit,1/kentucky,1/louisville,1/montreal,1/nassau,1/new_york,1/nipigon,1/pangnirtung,1/port-au-prince,1/thunder_bay,1/toronto,1/indiana/marengo,1/indiana/petersburg,1/indiana/vevay,1/indiana/vincennes,1/indiana/winamac,1/kentucky/monticello,1/fort_wayne,1/indiana/indianapolis,1/kentucky/louisville,6/eastern,us/east-indiana,us/eastern,us/michigan","-4|n|03/10:02->11/03:01":"1/havana,cuba","-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","-3|s":"1/argentina,1/buenos_aires,1/catamarca,1/cordoba,1/fortaleza,1/jujuy,1/mendoza,1/montevideo,1/punta_arenas,1/sao_paulo,12/palmer,12/rothera,3/stanley,1/argentina/la_rioja,1/argentina/rio_gallegos,1/argentina/salta,1/argentina/san_juan,1/argentina/san_luis,1/argentina/tucuman,1/argentina/ushuaia,1/argentina/comodrivadavia,1/argentina/buenos_aires,1/argentina/catamarca,1/argentina/cordoba,1/argentina/jujuy,1/argentina/mendoza,1/argentina/rosario,1/rosario,5/east","-3|n|03/10:04->11/03:02":"1/glace_bay,1/goose_bay,1/halifax,1/moncton,1/thule,3/bermuda,6/atlantic","-3|n":"1/araguaina,1/bahia,1/belem,1/cayenne,1/maceio,1/paramaribo,1/recife,1/santarem","-2|n|03/31:01->10/26:24":"1/nuuk,1/godthab","-2|n|03/10:04->11/03:02":"1/miquelon","-2|n":"1/noronha,3/south_georgia,5/denoronha","-2.5|n|03/10:04->11/03:02":"1/st_johns,6/newfoundland","-1|n":"3/cape_verde","-11|n":"11/midway,11/niue,11/pago_pago,11/samoa,us/samoa","-10|n":"11/honolulu,11/johnston,11/rarotonga,11/tahiti,us/hawaii,hst"},s=["africa","america","asia","atlantic","australia","brazil","canada","chile","europe","indian","mexico","pacific","antarctica","etc"];let u={};Object.keys(o).forEach((e=>{let t=e.split("|"),a={offset:Number(t[0]),hem:t[1]};t[2]&&(a.dst=t[2]),o[e].split(",").forEach((e=>{e=e.replace(/(^[0-9]+)\//,((e,t)=>(t=Number(t),s[t]+"/"))),u[e]=a}))})),u.utc={offset:0,hem:"n"};for(let e=-14;e<=14;e+=.5){let t=e;t>0&&(t="+"+t);let a="etc/gmt"+t;u[a]={offset:-1*e,hem:"n"},a="utc/gmt"+t,u[a]={offset:-1*e,hem:"n"}}const d=/(-?[0-9]+)h(rs)?/i,l=/(-?[0-9]+)/,h=/utc([\-+]?[0-9]+)/i,m=/gmt([\-+]?[0-9]+)/i,c=function(e){return(e=Number(e))>=-13&&e<=13?"etc/gmt"+(e=((e*=-1)>0?"+":"")+e):null};let f=(()=>{let e=(()=>{if("undefined"==typeof Intl||void 0===Intl.DateTimeFormat)return null;let e=Intl.DateTimeFormat();if(void 0===e||void 0===e.resolvedOptions)return null;let t=e.resolvedOptions().timeZone;return t?t.toLowerCase():null})();return null===e?"utc":e})();const y=Object.keys(u).reduce(((e,t)=>{let a=t.split("/")[1]||"";return a=a.replace(/_/g," "),e[a]=t,e}),{}),p=(e,t)=>{if(!e)return t.hasOwnProperty(f)||(console.warn(`Unrecognized IANA id '${f}'. Setting fallback tz to UTC.`),f="utc"),f;"string"!=typeof e&&console.error("Timezone must be a string - recieved: '",e,"'\n");let a=e.trim();if(a=a.toLowerCase(),!0===t.hasOwnProperty(a))return a;if(a=(e=>(e=(e=(e=(e=(e=e.replace(/ time/g,"")).replace(/ (standard|daylight|summer)/g,"")).replace(/\b(east|west|north|south)ern/g,"$1")).replace(/\b(africa|america|australia)n/g,"$1")).replace(/\beuropean/g,"europe")).replace(/islands/g,"island"))(a),!0===t.hasOwnProperty(a))return a;if(!0===y.hasOwnProperty(a))return y[a];if(!0===/[0-9]/.test(a)){let e=function(e){let t=e.match(d);if(null!==t)return c(t[1]);if(t=e.match(h),null!==t)return c(t[1]);if(t=e.match(m),null!==t){let e=-1*Number(t[1]);return c(e)}return t=e.match(l),null!==t?c(t[1]):null}(a);if(e)return e}throw new Error("Spacetime: Cannot find timezone named: '"+e+"'. Please enter an IANA timezone id.")};function g(e){return e%4==0&&e%100!=0||e%400==0}function w(e){return"[object Date]"===Object.prototype.toString.call(e)&&!isNaN(e.valueOf())}function b(e){return"[object Object]"===Object.prototype.toString.call(e)}function k(e,t=2){return(e+="").length>=t?e:new Array(t-e.length+1).join("0")+e}function D(e){let t=e%10,a=e%100;return 1===t&&11!==a?e+"st":2===t&&12!==a?e+"nd":3===t&&13!==a?e+"rd":e+"th"}function v(e){return e=(e=String(e)).replace(/([0-9])(st|nd|rd|th)$/i,"$1"),parseInt(e,10)}function x(e=""){return"day"===(e=(e=(e=(e=e.toLowerCase().trim()).replace(/ies$/,"y")).replace(/s$/,"")).replace(/-/g,""))||"days"===e?"date":"min"===e||"mins"===e?"minute":e}function O(e){return"number"==typeof e?e:w(e)?e.getTime():e.epoch?e.epoch:null}function M(e,t){return!1===b(e)?t.clone().set(e):e}function _(e,t=""){const a=e>0?"+":"-",n=Math.abs(e);return`${a}${k(parseInt(""+n,10))}${t}${k(n%1*60)}`}const j={year:(new Date).getFullYear(),month:0,date:1};var $={parseArray:(e,t,a)=>{if(0===t.length)return e;let n=["year","month","date","hour","minute","second","millisecond"];for(let r=0;r{if(0===Object.keys(t).length)return e;t=Object.assign({},j,a,t);let n=Object.keys(t);for(let r=0;r0&&t<25e8&&!1===e.silent&&(console.warn(" - Warning: You are setting the date to January 1970."),console.warn(" - did input seconds instead of milliseconds?")),e.epoch=t,e}};const z=function(e){return e.epoch=Date.now(),Object.keys(e._today||{}).forEach((t=>{"function"==typeof e[t]&&(e=e[t](e._today[t]))})),e},T={now:e=>z(e),today:e=>z(e),tonight:e=>e=(e=z(e)).hour(18),tomorrow:e=>e=(e=(e=z(e)).add(1,"day")).startOf("day"),yesterday:e=>e=(e=(e=z(e)).subtract(1,"day")).startOf("day"),christmas:e=>{let t=z(e).year();return e=e.set([t,11,25,18,0,0])},"new years":e=>{let t=z(e).year();return e=e.set([t,11,31,18,0,0])}};T["new years eve"]=T["new years"];let V={millisecond:1,second:1e3,minute:6e4,hour:36e5,day:864e5};V.date=V.day,V.month=25488e5,V.week=6048e5,V.year=3154e7,Object.keys(V).forEach((e=>{V[e+"s"]=V[e]}));const q=(e,t,a,n,r)=>{let i=e.d[a]();if(i===t)return;let o=null===r?null:e.d[r](),s=e.epoch,u=t-i;e.epoch+=V[n]*u,"day"===n&&Math.abs(u)>28&&t<28&&(e.epoch+=V.hour),null!==r&&o!==e.d[r]()&&(e.epoch=s);const d=V[n]/2;for(;e.d[a]()t;)e.epoch-=d;null!==r&&o!==e.d[r]()&&(e.epoch=s)},S={year:{valid:e=>e>-4e3&&e<4e3,walkTo:(e,t)=>q(e,t,"getFullYear","year",null)},month:{valid:e=>e>=0&&e<=11,walkTo:(e,t)=>{let a=e.d,n=a.getMonth(),r=e.epoch,i=a.getFullYear();if(n===t)return;let o=t-n;for(e.epoch+=V.day*(28*o),i!==e.d.getFullYear()&&(e.epoch=r);e.d.getMonth()t;)e.epoch-=V.day}},date:{valid:e=>e>0&&e<=31,walkTo:(e,t)=>q(e,t,"getDate","day","getMonth")},hour:{valid:e=>e>=0&&e<24,walkTo:(e,t)=>q(e,t,"getHours","hour","getDate")},minute:{valid:e=>e>=0&&e<60,walkTo:(e,t)=>q(e,t,"getMinutes","minute","getHours")},second:{valid:e=>e>=0&&e<60,walkTo:(e,t)=>{e.epoch=e.seconds(t).epoch}},millisecond:{valid:e=>e>=0&&e<1e3,walkTo:(e,t)=>{e.epoch=e.milliseconds(t).epoch}}},C=(e,t)=>{let a=Object.keys(S),n=e.clone();for(let r=0;r{if(!t)return e;t=t.trim().toLowerCase();let a=0;if(/^[+-]?[0-9]{2}:[0-9]{2}$/.test(t)&&(!0===/:00/.test(t)&&(t=t.replace(/:00/,"")),!0===/:30/.test(t)&&(t=t.replace(/:30/,".5"))),/^[+-]?[0-9]{4}$/.test(t)&&(t=t.replace(/30$/,".5")),a=parseFloat(t),Math.abs(a)>100&&(a/=100),0===a||"Z"===t||"z"===t)return e.tz="etc/gmt",e;a*=-1,a>=0&&(a="+"+a);let n="etc/gmt"+a;return e.timezones[n]&&(e.tz=n),e},H=(e,t="")=>{let a=(t=t.replace(/^\s+/,"").toLowerCase()).match(/([0-9]{1,2}):([0-9]{1,2}):?([0-9]{1,2})?[:.]?([0-9]{1,4})?/);if(null!==a){let[,n,r,i,o]=a;if(n=Number(n),n<0||n>24)return e.startOf("day");if(r=Number(r),a[2].length<2||r<0||r>59)return e.startOf("day");e=(e=(e=(e=e.hour(n)).minute(r)).seconds(i||0)).millisecond(function(e=""){return(e=String(e)).length>3?e=e.substring(0,3):1===e.length?e+="00":2===e.length&&(e+="0"),Number(e)||0}(o));let s=t.match(/[0-9] ?(am|pm)\b/);return null!==s&&s[1]&&(e=e.ampm(s[1])),e}if(a=t.match(/([0-9]+) ?(am|pm)/),null!==a&&a[1]){let t=Number(a[1]);return t>12||t<1?e.startOf("day"):e=(e=(e=e.hour(a[1]||0)).ampm(a[2])).startOf("hour")}return e=e.startOf("day")};let L=Y();const I=e=>{if(!0!==A.hasOwnProperty(e.month))return!1;if(1===e.month)return!!(g(e.year)&&e.date<=29)||e.date<=28;let t=A[e.month]||0;return e.date<=t},W=(e="",t)=>{if(e=e.trim(),!0===/^'[0-9][0-9]$/.test(e)){let t=Number(e.replace(/'/,""));return t>50?1900+t:2e3+t}let a=parseInt(e,10);return!a&&t&&(a=t.year),a=a||(new Date).getFullYear(),a},F=function(e){return"sept"===(e=e.toLowerCase().trim())?L.sep:L[e]};var J=[{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,parse:(e,t)=>{let a=parseInt(t[1],10)-1,n=parseInt(t[2],10);(e.british||a>=12)&&(n=parseInt(t[1],10),a=parseInt(t[2],10)-1);let r={date:n,month:a,year:W(t[3],e._today)||(new Date).getFullYear()};return!1===I(r)?(e.epoch=null,e):(C(e,r),e=H(e,t[4]))}},{reg:/^([a-z]+)[\-/. ]([0-9]{1,2})[\-/. ]?([0-9]{4}|'[0-9]{2})?( [0-9]{1,2}(:[0-9]{0,2})?(:[0-9]{0,3})? ?(am|pm)?)?$/i,parse:(e,t)=>{let a={year:W(t[3],e._today),month:F(t[1]),date:v(t[2]||"")};return!1===I(a)?(e.epoch=null,e):(C(e,a),e=H(e,t[4]))}},{reg:/^([a-z]+) ([0-9]{1,2})( [0-9]{4})?( ([0-9:]+( ?am| ?pm| ?gmt)?))?$/i,parse:(e,t)=>{let a={year:W(t[3],e._today),month:F(t[1]),date:v(t[2]||"")};return!1===I(a)?(e.epoch=null,e):(C(e,a),e=H(e,t[4]))}},{reg:/^([a-z]+) ([0-9]{1,2}) ([0-9]{1,2}:[0-9]{2}:?[0-9]{0,2})( \+[0-9]{4})?( [0-9]{4})?$/i,parse:(e,t)=>{let[,a,n,r,i,o]=t,s={year:W(o,e._today),month:F(a),date:v(n||"")};return!1===I(s)?(e.epoch=null,e):(C(e,s),e=B(e,i),e=H(e,r))}}],U=[{reg:/^([0-9]{4})[\-/]([0-9]{2})$/,parse:(e,t)=>{let a={year:t[1],month:parseInt(t[2],10)-1,date:1};return!1===I(a)?(e.epoch=null,e):(C(e,a),e=H(e,t[4]))}},{reg:/^([a-z]+) ([0-9]{4})$/i,parse:(e,t)=>{let a={year:W(t[2],e._today),month:F(t[1]),date:e._today.date||1};return!1===I(a)?(e.epoch=null,e):(C(e,a),e=H(e,t[4]))}},{reg:/^(q[0-9])( of)?( [0-9]{4})?/i,parse:(e,t)=>{let a=t[1]||"";e=e.quarter(a);let n=t[3]||"";return n&&(n=n.trim(),e=e.year(n)),e}},{reg:/^(spring|summer|winter|fall|autumn)( of)?( [0-9]{4})?/i,parse:(e,t)=>{let a=t[1]||"";e=e.season(a);let n=t[3]||"";return n&&(n=n.trim(),e=e.year(n)),e}},{reg:/^[0-9,]+ ?b\.?c\.?$/i,parse:(e,t)=>{let a=t[0]||"";a=a.replace(/^([0-9,]+) ?b\.?c\.?$/i,"-$1");let n=new Date,r={year:parseInt(a.trim(),10),month:n.getMonth(),date:n.getDate()};return!1===I(r)?(e.epoch=null,e):(C(e,r),e=H(e))}},{reg:/^[0-9,]+ ?(a\.?d\.?|c\.?e\.?)$/i,parse:(e,t)=>{let a=t[0]||"";a=a.replace(/,/g,"");let n=new Date,r={year:parseInt(a.trim(),10),month:n.getMonth(),date:n.getDate()};return!1===I(r)?(e.epoch=null,e):(C(e,r),e=H(e))}},{reg:/^[0-9]{4}( ?a\.?d\.?)?$/i,parse:(e,t)=>{let a=e._today;a.month&&!a.date&&(a.date=1);let n=new Date,r={year:W(t[0],a),month:a.month||n.getMonth(),date:a.date||n.getDate()};return!1===I(r)?(e.epoch=null,e):(C(e,r),e=H(e))}}],K=[].concat([{reg:/^(-?0{0,2}[0-9]{3,4})-([0-9]{1,2})-([0-9]{1,2})[T| ]([0-9.:]+)(Z|[0-9-+:]+)?$/i,parse:(e,t)=>{let a={year:t[1],month:parseInt(t[2],10)-1,date:t[3]};return!1===I(a)?(e.epoch=null,e):(B(e,t[5]),C(e,a),e=H(e,t[4]))}},{reg:/^([0-9]{4})[\-/. ]([0-9]{1,2})[\-/. ]([0-9]{1,2})( [0-9]{1,2}(:[0-9]{0,2})?(:[0-9]{0,3})? ?(am|pm)?)?$/i,parse:(e,t)=>{let a={year:t[1],month:parseInt(t[2],10)-1,date:parseInt(t[3],10)};return a.month>=12&&(a.date=parseInt(t[2],10),a.month=parseInt(t[3],10)-1),!1===I(a)?(e.epoch=null,e):(C(e,a),e=H(e,t[4]))}},{reg:/^([0-9]{4})[\-/. ]([a-z]+)[\-/. ]([0-9]{1,2})( [0-9]{1,2}(:[0-9]{0,2})?(:[0-9]{0,3})? ?(am|pm)?)?$/i,parse:(e,t)=>{let a={year:W(t[1],e._today),month:F(t[2]),date:v(t[3]||"")};return!1===I(a)?(e.epoch=null,e):(C(e,a),e=H(e,t[4]))}}],J,[{reg:/^([0-9]{1,2})[-/]([a-z]+)[\-/]?([0-9]{4})?$/i,parse:(e,t)=>{let a={year:W(t[3],e._today),month:F(t[2]),date:v(t[1]||"")};return!1===I(a)?(e.epoch=null,e):(C(e,a),e=H(e,t[4]))}},{reg:/^([0-9]{1,2})( [a-z]+)( [0-9]{4}| '[0-9]{2})? ?([0-9]{1,2}:[0-9]{2}:?[0-9]{0,2} ?(am|pm|gmt))?$/i,parse:(e,t)=>{let a={year:W(t[3],e._today),month:F(t[2]),date:v(t[1])};return a.month&&!1!==I(a)?(C(e,a),e=H(e,t[4])):(e.epoch=null,e)}},{reg:/^([0-9]{1,2})[. \-/]([a-z]+)[. \-/]([0-9]{4})?( [0-9]{1,2}(:[0-9]{0,2})?(:[0-9]{0,3})? ?(am|pm)?)?$/i,parse:(e,t)=>{let a={date:Number(t[1]),month:F(t[2]),year:Number(t[3])};return!1===I(a)?(e.epoch=null,e):(C(e,a),e=e.startOf("day"),e=H(e,t[4]))}}],U);const{parseArray:Q,parseObject:R,parseNumber:G}=$,Z={year:(new Date).getFullYear(),month:0,date:1},X=(e,t)=>{let a=e._today||Z;if("number"==typeof t)return G(e,t);if(e.epoch=Date.now(),e._today&&b(e._today)&&Object.keys(e._today).length>0){let t=R(e,a,Z);t.isValid()&&(e.epoch=t.epoch)}return null==t||""===t?e:!0===w(t)?(e.epoch=t.getTime(),e):!0===function(e){return"[object Array]"===Object.prototype.toString.call(e)}(t)?e=Q(e,t,a):!0===b(t)?t.epoch?(e.epoch=t.epoch,e.tz=t.tz,e):e=R(e,t,a):"string"!=typeof t?e:(t=t.replace(/\b(mon|tues?|wed|wednes|thur?s?|fri|sat|satur|sun)(day)?\b/i,"").replace(/([0-9])(th|rd|st|nd)/,"$1").replace(/,/g,"").replace(/ +/g," ").trim(),!0===T.hasOwnProperty(t)?e=T[t](e):function(e,t,a){for(let n=0;n{let t=e.timezone().current.offset;return t?_(t,":"):"Z"},se=e=>ie?function(e){return e?e[0].toUpperCase()+e.substr(1):""}(e):e,ue={day:e=>se(e.dayName()),"day-short":e=>se(ae()[e.day()]),"day-number":e=>e.day(),"day-ordinal":e=>D(e.day()),"day-pad":e=>k(e.day()),date:e=>e.date(),"date-ordinal":e=>D(e.date()),"date-pad":e=>k(e.date()),month:e=>se(e.monthName()),"month-short":e=>se(P()[e.month()]),"month-number":e=>e.month(),"month-ordinal":e=>D(e.month()),"month-pad":e=>k(e.month()),"iso-month":e=>k(e.month()+1),year:e=>{let t=e.year();return t>0?t:(t=Math.abs(t),t+" BC")},"year-short":e=>{let t=e.year();return t>0?`'${String(e.year()).substr(2,4)}`:(t=Math.abs(t),t+" BC")},"iso-year":e=>{let t=e.year(),a=t<0,n=k(Math.abs(t),4);return a&&(n=k(n,6),n="-"+n),n},time:e=>e.time(),"time-24":e=>`${e.hour24()}:${k(e.minute())}`,hour:e=>e.hour12(),"hour-pad":e=>k(e.hour12()),"hour-24":e=>e.hour24(),"hour-24-pad":e=>k(e.hour24()),minute:e=>e.minute(),"minute-pad":e=>k(e.minute()),second:e=>e.second(),"second-pad":e=>k(e.second()),millisecond:e=>e.millisecond(),"millisecond-pad":e=>k(e.millisecond(),3),ampm:e=>e.ampm(),AMPM:e=>e.ampm().toUpperCase(),quarter:e=>"Q"+e.quarter(),season:e=>e.season(),era:e=>e.era(),json:e=>e.json(),timezone:e=>e.timezone().name,offset:e=>oe(e),numeric:e=>`${e.year()}/${k(e.month()+1)}/${k(e.date())}`,"numeric-us":e=>`${k(e.month()+1)}/${k(e.date())}/${e.year()}`,"numeric-uk":e=>`${k(e.date())}/${k(e.month()+1)}/${e.year()}`,"mm/dd":e=>`${k(e.month()+1)}/${k(e.date())}`,iso:e=>`${e.format("iso-year")}-${k(e.month()+1)}-${k(e.date())}T${k(e.h24())}:${k(e.minute())}:${k(e.second())}.${k(e.millisecond(),3)}${oe(e)}`,"iso-short":e=>{let t=k(e.month()+1),a=k(e.date());var n;return`${(n=e.year())>=0?k(n,4):"-"+k(n=Math.abs(n),4)}-${t}-${a}`},"iso-utc":e=>new Date(e.epoch).toISOString(),nice:e=>`${P()[e.month()]} ${D(e.date())}, ${e.time()}`,"nice-24":e=>`${P()[e.month()]} ${D(e.date())}, ${e.hour24()}:${k(e.minute())}`,"nice-year":e=>`${P()[e.month()]} ${D(e.date())}, ${e.year()}`,"nice-day":e=>`${ae()[e.day()]} ${se(P()[e.month()])} ${D(e.date())}`,"nice-full":e=>`${e.dayName()} ${se(e.monthName())} ${D(e.date())}, ${e.time()}`,"nice-full-24":e=>`${e.dayName()} ${se(e.monthName())} ${D(e.date())}, ${e.hour24()}:${k(e.minute())}`},de={"day-name":"day","month-name":"month","iso 8601":"iso","time-h24":"time-24","time-12":"time","time-h12":"time",tz:"timezone","day-num":"day-number","month-num":"month-number","month-iso":"iso-month","year-iso":"iso-year","nice-short":"nice","nice-short-24":"nice-24",mdy:"numeric-us",dmy:"numeric-uk",ymd:"numeric","yyyy/mm/dd":"numeric","mm/dd/yyyy":"numeric-us","dd/mm/yyyy":"numeric-us","little-endian":"numeric-uk","big-endian":"numeric","day-nice":"nice-day"};Object.keys(de).forEach((e=>ue[e]=ue[de[e]]));const le=(e,t="")=>{if(!0!==e.isValid())return"";if(ue.hasOwnProperty(t)){let a=ue[t](e)||"";return"json"!==t&&(a=String(a),"ampm"!==t.toLowerCase()&&(a=se(a))),a}if(-1!==t.indexOf("{")){let a=/\{(.+?)\}/g;return t=t.replace(a,((t,a)=>{if(a=a.toLowerCase().trim(),ue.hasOwnProperty(a)){let t=String(ue[a](e));return"ampm"!==a.toLowerCase()?se(t):t}return""})),t}return e.format("iso-short")},he={G:e=>e.era(),GG:e=>e.era(),GGG:e=>e.era(),GGGG:e=>"AD"===e.era()?"Anno Domini":"Before Christ",y:e=>e.year(),yy:e=>k(Number(String(e.year()).substr(2,4))),yyy:e=>e.year(),yyyy:e=>e.year(),yyyyy:e=>"0"+e.year(),Q:e=>e.quarter(),QQ:e=>e.quarter(),QQQ:e=>e.quarter(),QQQQ:e=>e.quarter(),M:e=>e.month()+1,MM:e=>k(e.month()+1),MMM:e=>e.format("month-short"),MMMM:e=>e.format("month"),w:e=>e.week(),ww:e=>k(e.week()),d:e=>e.date(),dd:e=>k(e.date()),D:e=>e.dayOfYear(),DD:e=>k(e.dayOfYear()),DDD:e=>k(e.dayOfYear(),3),E:e=>e.format("day-short"),EE:e=>e.format("day-short"),EEE:e=>e.format("day-short"),EEEE:e=>e.format("day"),EEEEE:e=>e.format("day")[0],e:e=>e.day(),ee:e=>e.day(),eee:e=>e.format("day-short"),eeee:e=>e.format("day"),eeeee:e=>e.format("day")[0],a:e=>e.ampm().toUpperCase(),aa:e=>e.ampm().toUpperCase(),aaa:e=>e.ampm().toUpperCase(),aaaa:e=>e.ampm().toUpperCase(),h:e=>e.h12(),hh:e=>k(e.h12()),H:e=>e.hour(),HH:e=>k(e.hour()),m:e=>e.minute(),mm:e=>k(e.minute()),s:e=>e.second(),ss:e=>k(e.second()),SSS:e=>k(e.millisecond(),3),A:e=>e.epoch-e.startOf("day").epoch,z:e=>e.timezone().name,zz:e=>e.timezone().name,zzz:e=>e.timezone().name,zzzz:e=>e.timezone().name,Z:e=>_(e.timezone().current.offset),ZZ:e=>_(e.timezone().current.offset),ZZZ:e=>_(e.timezone().current.offset),ZZZZ:e=>_(e.timezone().current.offset,":")},me=(e,t,a)=>{let n=e,r=t;for(let i=0;i{let n=0;for(e=e.clone();e.isBefore(t);)e=e.add(1,a),n+=1;return e.isAfter(t,a)&&(n-=1),n},pe=(e,t,a)=>e.isBefore(t)?ye(e,t,a):-1*ye(t,e,a),ge=function(e,t,a){t=M(t,e);let n=!1;if(e.isAfter(t)){let a=e;e=t,t=a,n=!0}let r=function(e,t){let a=t.epoch-e.epoch,n={milliseconds:a,seconds:parseInt(a/1e3,10)};n.minutes=parseInt(n.seconds/60,10),n.hours=parseInt(n.minutes/60,10);let r=e.clone();return n.years=((e,t)=>{let a=t.year()-e.year();return(e=e.year(t.year())).isAfter(t)&&(a-=1),a})(r,t),r=e.add(n.years,"year"),n.months=12*n.years,r=e.add(n.months,"month"),n.months+=pe(r,t,"month"),n.quarters=4*n.years,n.quarters+=parseInt(n.months%12/3,10),n.weeks=52*n.years,r=e.add(n.weeks,"week"),n.weeks+=pe(r,t,"week"),n.days=7*n.weeks,r=e.add(n.days,"day"),n.days+=pe(r,t,"day"),n}(e,t);return n&&(r=function(e){return Object.keys(e).forEach((t=>{e[t]*=-1})),e}(r)),a?(a=x(a),!0!==/s$/.test(a)&&(a+="s"),"dates"===a&&(a="days"),r[a]):r},we=e=>Math.abs(e)||0;let be={second:"second",seconds:"seconds",minute:"minute",minutes:"minutes",hour:"hour",hours:"hours",day:"day",days:"days",month:"month",months:"months",year:"year",years:"years"};function ke(e){return be[e]||""}let De="past",ve="future",xe="present",Oe="now",Me="almost",_e="over",je=e=>`${e} ago`,$e=e=>`in ${e}`;function ze(e){return je(e)}function Te(e){return $e(e)}function Ve(){return Oe}const qe={months:{almost:10,over:4},days:{almost:25,over:10},hours:{almost:20,over:8},minutes:{almost:50,over:20},seconds:{almost:50,over:20}};function Se(e,t){return 1===e?e+" "+ke(t.slice(0,-1)):e+" "+ke(t)}const Ce=function(e){let t=null,a=null,n=[],r=[];return Object.keys(e).forEach(((i,o,s)=>{const u=Math.abs(e[i]);if(0===u)return;n.push(u+i[0]);const d=Se(u,i);if(r.push(d),!t){if(t=d,a=d,o>4)return;const n=s[o+1],r=Math.abs(e[n]);r>qe[n].almost?(t=Se(u+1,i),a=Me+" "+t):r>qe[n].over&&(a=_e+" "+d)}})),{qualified:a,rounded:t,abbreviated:n,englishValues:r}},Ae=(e,t)=>{const a=function(e,t){const a=e.isBefore(t),n=a?t:e;let r=a?e:t;r=r.clone();const i={years:0,months:0,days:0,hours:0,minutes:0,seconds:0};return Object.keys(i).forEach((e=>{if(r.isSame(n,e))return;let t=r.diff(n,e);r=r.add(t,e),i[e]=t})),a&&Object.keys(i).forEach((e=>{0!==i[e]&&(i[e]*=-1)})),i}(e,t=M(t,e));if(!0===Object.keys(a).every((e=>!a[e])))return{diff:a,rounded:Ve(),qualified:Ve(),precise:Ve(),abbreviated:[],iso:"P0Y0M0DT0H0M0S",direction:xe};let n,r=ve,{rounded:i,qualified:o,englishValues:s,abbreviated:u}=Ce(a);n=s.splice(0,2).join(", "),!0===e.isAfter(t)?(i=ze(i),o=ze(o),n=ze(n),r=De):(i=Te(i),o=Te(o),n=Te(n));let d=function(e){let t="P";return t+=we(e.years)+"Y",t+=we(e.months)+"M",t+=we(e.days)+"DT",t+=we(e.hours)+"H",t+=we(e.minutes)+"M",t+=we(e.seconds)+"S",t}(a);return{diff:a,rounded:i,qualified:o,precise:n,abbreviated:u,iso:d,direction:r}};var Ee={north:[["spring",2,1],["summer",5,1],["fall",8,1],["autumn",8,1],["winter",11,1]],south:[["fall",2,1],["autumn",2,1],["winter",5,1],["spring",8,1],["summer",11,1]]},Ne=[null,[0,1],[3,1],[6,1],[9,1]];const Pe={second:e=>(C(e,{millisecond:0}),e),minute:e=>(C(e,{second:0,millisecond:0}),e),quarterhour:e=>{let t=e.minutes();return e=t>=45?e.minutes(45):t>=30?e.minutes(30):t>=15?e.minutes(15):e.minutes(0),C(e,{second:0,millisecond:0}),e},hour:e=>(C(e,{minute:0,second:0,millisecond:0}),e),day:e=>(C(e,{hour:0,minute:0,second:0,millisecond:0}),e),week:e=>{let t=e.clone();return(e=e.day(e._weekStart)).isAfter(t)&&(e=e.subtract(1,"week")),C(e,{hour:0,minute:0,second:0,millisecond:0}),e},month:e=>(C(e,{date:1,hour:0,minute:0,second:0,millisecond:0}),e),quarter:e=>{let t=e.quarter();return Ne[t]&&C(e,{month:Ne[t][0],date:Ne[t][1],hour:0,minute:0,second:0,millisecond:0}),e},season:e=>{let t=e.season(),a="north";"South"===e.hemisphere()&&(a="south");for(let n=0;n(C(e,{month:0,date:1,hour:0,minute:0,second:0,millisecond:0}),e),decade:e=>{let t=(e=e.startOf("year")).year(),a=10*parseInt(t/10,10);return e=e.year(a)},century:e=>{let t=(e=e.startOf("year")).year(),a=100*parseInt(t/100,10);return e=e.year(a)}};Pe.date=Pe.day;const Ye=function(e,t,a,n=1){if(!t||!a)return[];if(t=x(t),a=e.clone().set(a),e.isAfter(a)){let t=e;e=a,a=t}if(e.diff(a,t)t===e))||!!ne().find((t=>t===e))}(t)?r.startOf(t).isBefore(e)&&(r=r.next(t)):(r=r.next(t),t="week");let i=[];for(;r.isBefore(a);)i.push(r),r=r.add(n,t);return i},Be=e=>{let t=e.timezones,a=e.tz;if(!1===t.hasOwnProperty(a)&&(a=p(e.tz,t)),null===a)return!1===e.silent&&console.warn("Warn: could not find given or local timezone - '"+e.tz+"'"),{current:{epochShift:0}};let n=t[a],r={name:(o=a,o=(o=(o=(o=(o=(o=(o=o[0].toUpperCase()+o.substr(1)).replace(/[/_-]([a-z])/gi,(e=>e.toUpperCase()))).replace(/_(of|es)_/i,(e=>e.toLowerCase()))).replace(/\/gmt/i,"/GMT")).replace(/\/Dumontdurville$/i,"/DumontDUrville")).replace(/\/Mcmurdo$/i,"/McMurdo")).replace(/\/Port-au-prince$/i,"/Port-au-Prince")),hasDst:Boolean(n.dst),default_offset:n.offset,hemisphere:"s"===n.hem?"South":"North",current:{}};var o,s;if(r.hasDst){let e=(s=n.dst)?s.split("->"):[];r.change={start:e[0],back:e[1]}}let u=n.offset,d=u;return!0===r.hasDst&&(d="North"===r.hemisphere?u-1:n.offset+1),!1===r.hasDst?(r.current.offset=u,r.current.isDST=!1):!0===i(e.epoch,r.change.start,r.change.back,u,d)?(r.current.offset=u,r.current.isDST="North"===r.hemisphere):(r.current.offset=d,r.current.isDST="South"===r.hemisphere),r},He=["century","decade","year","month","date","day","hour","minute","second","millisecond"],Le={set:function(e,t){let a=this.clone();return a=X(a,e),t&&(this.tz=p(t)),a},timezone:function(){return Be(this)},isDST:function(){return Be(this).current.isDST},hasDST:function(){return Be(this).hasDst},offset:function(){return 60*Be(this).current.offset},hemisphere:function(){return Be(this).hemisphere},format:function(e){return le(this,e)},unixFmt:function(e){return((e,t)=>{let a=t.split("");return a=function(e){for(let t=0;te))}(a),a=function(e){for(let t=0;te))).map((e=>("''"===e&&(e="'"),e)))}(a),a.reduce(((t,a)=>(void 0!==he[a]?t+=he[a](e)||"":(/^'.+'$/.test(a)&&(a=a.replace(/'/g,"")),t+=a),t)),"")})(this,e)},startOf:function(e){return((e,t)=>{let a=e.clone();return t=x(t),Pe[t]?Pe[t](a):"summer"===t||"winter"===t?(a=a.season(t),Pe.season(a)):a})(this,e)},endOf:function(e){return((e,t)=>{let a=e.clone();return t=x(t),Pe[t]?(a=Pe[t](a),a=a.add(1,t),a=a.subtract(1,"millisecond"),a):a})(this,e)},leapYear:function(){return g(this.year())},progress:function(e){return((e,t)=>{if(t)return t=x(t),fe(e,t);let a={};return ce.forEach((t=>{a[t]=fe(e,t)})),a})(this,e)},nearest:function(e){return((e,t)=>{let a=e.progress();return"quarterhour"===(t=x(t))&&(t="quarterHour"),void 0!==a[t]?(a[t]>.5&&(e=e.add(1,t)),e=e.startOf(t)):!1===e.silent&&console.warn("no known unit '"+t+"'"),e})(this,e)},diff:function(e,t){return ge(this,e,t)},since:function(e){return e||(e=this.clone().set()),Ae(this,e)},next:function(e){return this.add(1,e).startOf(e)},last:function(e){return this.subtract(1,e).startOf(e)},isValid:function(){return!(!this.epoch&&0!==this.epoch||isNaN(this.d.getTime()))},goto:function(e){let t=this.clone();return t.tz=p(e,t.timezones),t},every:function(e,t,a){if("object"==typeof e&&"string"==typeof t){let a=t;t=e,e=a}return Ye(this,e,t,a)},isAwake:function(){let e=this.hour();return!(e<8||e>22)},isAsleep:function(){return!this.isAwake()},daysInMonth:function(){switch(this.month()){case 0:case 2:case 4:case 6:case 7:case 9:case 11:return 31;case 1:return this.leapYear()?29:28;case 3:case 5:case 8:case 10:return 30;default:throw new Error("Invalid Month state.")}},log:function(){return console.log(""),console.log(le(this,"nice-short")),this},logYear:function(){return console.log(""),console.log(le(this,"full-short")),this},json:function(){return He.reduce(((e,t)=>(e[t]=this[t](),e)),{})},debug:function(){let e=this.timezone(),t=this.format("MM")+" "+this.format("date-ordinal")+" "+this.year();return t+="\n - "+this.format("time"),console.log("\n\n",t+"\n - "+e.name+" ("+e.current.offset+")"),this},from:function(e){return(e=this.clone().set(e)).since(this)},fromNow:function(){return this.clone().set(Date.now()).since(this)},weekStart:function(e){if("number"==typeof e)return this._weekStart=e,this;if("string"==typeof e){e=e.toLowerCase().trim();let t=ae().indexOf(e);-1===t&&(t=ne().indexOf(e)),-1===t&&(t=1),this._weekStart=t}else console.warn("Spacetime Error: Cannot understand .weekStart() input:",e);return this}};Le.inDST=Le.isDST,Le.round=Le.nearest,Le.each=Le.every;const Ie=e=>("string"==typeof e&&(e=parseInt(e,10)),e),We=["year","month","date","hour","minute","second","millisecond"],Fe=(e,t,a)=>{let n=We.indexOf(a),r=We.slice(n,We.length);for(let a=0;a=24?t=24:t<0&&(t=0);let n=e.clone(),r=e.hour()-t,i=r*V.hour;return e.epoch-=i,e.date()!==n.date()&&(e=n.clone(),r>1&&(r-=1),r<1&&(r+=1),i=r*V.hour,e.epoch-=i),C(e,{hour:t}),Fe(e,n,"minute"),(e=Je(e,n,a,"day")).epoch},Qe=function(e,t){return"string"==typeof t&&/^'[0-9]{2}$/.test(t)&&(t=t.replace(/'/,"").trim(),t=(t=Number(t))>30?1900+t:2e3+t),t=Ie(t),C(e,{year:t}),e.epoch};let Re="am",Ge="pm";const Ze={millisecond:function(e){if(void 0!==e){let t=this.clone();return t.epoch=function(e,t){t=Ie(t);let a=e.millisecond()-t;return e.epoch-a}(t,e),t}return this.d.getMilliseconds()},second:function(e,t){if(void 0!==e){let a=this.clone();return a.epoch=function(e,t,a){t=Ie(t);let n=e.clone(),r=(e.second()-t)*V.second;return e.epoch=e.epoch-r,(e=Je(e,n,a,"minute")).epoch}(a,e,t),a}return this.d.getSeconds()},minute:function(e,t){if(void 0!==e){let a=this.clone();return a.epoch=Ue(a,e,t),a}return this.d.getMinutes()},hour:function(e,t){let a=this.d;if(void 0!==e){let a=this.clone();return a.epoch=Ke(a,e,t),a}return a.getHours()},hourFloat:function(e,t){if(void 0!==e){let a=this.clone(),n=e%1;n*=60;let r=parseInt(e,10);return a.epoch=Ke(a,r,t),a.epoch=Ue(a,n,t),a}let a=this.d,n=a.getHours(),r=a.getMinutes();return r/=60,n+r},hour12:function(e,t){let a=this.d;if(void 0!==e){let a=this.clone(),n=(e=""+e).match(/^([0-9]+)(am|pm)$/);if(n){let e=parseInt(n[1],10);"pm"===n[2]&&(e+=12),a.epoch=Ke(a,e,t)}return a}let n=a.getHours();return n>12&&(n-=12),0===n&&(n=12),n},time:function(e,t){if(void 0!==e){let a=this.clone();return e=e.toLowerCase().trim(),a.epoch=function(e,t,a){let n=t.match(/([0-9]{1,2})[:h]([0-9]{1,2})(:[0-9]{1,2})? ?(am|pm)?/);if(!n){if(n=t.match(/([0-9]{1,2}) ?(am|pm)/),!n)return e.epoch;n.splice(2,0,"0"),n.splice(3,0,"")}let r=!1,i=parseInt(n[1],10),o=parseInt(n[2],10);o>=60&&(o=59),i>12&&(r=!0),!1===r&&("am"===n[4]&&12===i&&(i=0),"pm"===n[4]&&i<12&&(i+=12)),n[3]=n[3]||"",n[3]=n[3].replace(/:/,"");let s=parseInt(n[3],10)||0,u=e.clone();return e=(e=(e=(e=e.hour(i)).minute(o)).second(s)).millisecond(0),(e=Je(e,u,a,"day")).epoch}(a,e,t),a}return`${this.h12()}:${k(this.minute())}${this.ampm()}`},ampm:function(e,t){let a=Re,n=this.hour();if(n>=12&&(a=Ge),"string"!=typeof e)return a;let r=this.clone();return e=e.toLowerCase().trim(),n>=12&&"am"===e?(n-=12,r.hour(n,t)):n<12&&"pm"===e?(n+=12,r.hour(n,t)):r},dayTime:function(e,t){if(void 0!==e){const a={morning:"7:00",breakfast:"7:00",noon:"12:00",lunch:"12:00",afternoon:"14:00",evening:"18:00",dinner:"18:00",night:"23:00",midnight:"00:00"};let n=this.clone();return e=(e=e||"").toLowerCase(),!0===a.hasOwnProperty(e)&&(n=n.time(a[e],t)),n}let a=this.hour();return a<6?"night":a<12?"morning":a<17?"afternoon":a<22?"evening":"night"},iso:function(e){return void 0!==e?this.set(e):this.format("iso")}},Xe={date:function(e,t){if(void 0!==e){let a=this.clone();return(e=parseInt(e,10))&&(a.epoch=function(e,t,a){if((t=Ie(t))>28){let a=e.month(),n=A[a];1===a&&29===t&&g(e.year())&&(n=29),t>n&&(t=n)}t<=0&&(t=1);let n=e.clone();return C(e,{date:t}),(e=Je(e,n,a,"month")).epoch}(a,e,t)),a}return this.d.getDate()},day:function(e,t){if(void 0===e)return this.d.getDay();let a=this.clone(),n=e;"string"==typeof e&&(e=e.toLowerCase(),re.hasOwnProperty(e)?n=re[e]:(n=ae().indexOf(e),-1===n&&(n=ne().indexOf(e))));let r=this.d.getDay()-n;!0===t&&r>0&&(r-=7),!1===t&&r<0&&(r+=7);let i=this.subtract(r,"days");return C(i,{hour:a.hour(),minute:a.minute(),second:a.second()}),i},dayName:function(e,t){if(void 0===e)return ne()[this.day()];let a=this.clone();return a=a.day(e,t),a}},et=e=>e=(e=(e=e.minute(0)).second(0)).millisecond(1),tt={dayOfYear:function(e,t){if(void 0!==e){let a=this.clone();return a.epoch=function(e,t,a){t=Ie(t);let n=e.clone();return(t-=1)<=0?t=0:t>=365&&(t=g(e.year())?365:364),e=(e=e.startOf("year")).add(t,"day"),Fe(e,n,"hour"),(e=Je(e,n,a,"year")).epoch}(a,e,t),a}let a,n=0,r=this.d.getMonth();for(let e=1;e<=r;e++)a=new Date,a.setDate(1),a.setFullYear(this.d.getFullYear()),a.setHours(1),a.setMinutes(1),a.setMonth(e),a.setHours(-2),n+=a.getDate();return n+this.d.getDate()},week:function(e,t){if(void 0!==e){let a=this.clone();return a.epoch=function(e,t,a){let n=e.clone();return t=Ie(t),"december"===(e=(e=(e=e.month(0)).date(1)).day("monday")).monthName()&&e.date()>=28&&(e=e.add(1,"week")),t-=1,e=e.add(t,"weeks"),(e=Je(e,n,a,"year")).epoch}(this,e,t),a=et(a),a}let a=this.clone();a=a.month(0),a=a.date(1),a=et(a),a=a.day("monday"),11===a.month()&&a.date()>=25&&(a=a.add(1,"week"));let n=1;1===a.date()&&(n=0),a=a.minus(1,"second");const r=this.epoch;if(a.epoch>r)return 1;let i=0,o=4*this.month();for(a.epoch+=V.week*o,i+=o;i<=52;i++){if(a.epoch>r)return i+n;a=a.add(1,"week")}return 52},month:function(e,t){if(void 0!==e){let a=this.clone();return a.epoch=function(e,t,a){"string"==typeof t&&("sept"===t&&(t="sep"),t=Y()[t.toLowerCase()]),(t=Ie(t))>=12&&(t=11),t<=0&&(t=0);let n=e.date();n>A[t]&&(n=A[t]);let r=e.clone();return C(e,{month:t,d:n}),(e=Je(e,r,a,"year")).epoch}(a,e,t),a}return this.d.getMonth()},monthName:function(e,t){if(void 0!==e){let a=this.clone();return a=a.month(e,t),a}return N[this.month()]},quarter:function(e,t){if(void 0!==e&&("string"==typeof e&&(e=e.replace(/^q/i,""),e=parseInt(e,10)),Ne[e])){let a=this.clone(),n=Ne[e][0];return a=a.month(n,t),a=a.date(1,t),a=a.startOf("day"),a}let a=this.d.getMonth();for(let e=1;e=Ee[a][e][1]&&n0&&(t.epoch=Qe(t,-1*a)),"ad"===e&&a<0&&(t.epoch=Qe(t,-1*a)),t}return this.d.getFullYear()<0?"BC":"AD"},decade:function(e){if(void 0!==e){if(!(e=(e=(e=String(e)).replace(/([0-9])'?s$/,"$1")).replace(/([0-9])(th|rd|st|nd)/,"$1")))return console.warn("Spacetime: Invalid decade input"),this;2===e.length&&/[0-9][0-9]/.test(e)&&(e="19"+e);let t=Number(e);return isNaN(t)?this:(t=10*Math.floor(t/10),this.year(t))}return this.startOf("decade").year()},century:function(e){if(void 0!==e){"string"==typeof e&&(e=(e=(e=e.replace(/([0-9])(th|rd|st|nd)/,"$1")).replace(/([0-9]+) ?(b\.?c\.?|a\.?d\.?)/i,((e,t,a)=>(a.match(/b\.?c\.?/i)&&(t="-"+t),t)))).replace(/c$/,""));let t=Number(e);return isNaN(e)?(console.warn("Spacetime: Invalid century input"),this):(0===t&&(t=1),t=t>=0?100*(t-1):100*(t+1),this.year(t))}let t=this.startOf("century").year();return t=Math.floor(t/100),t<0?t-1:t+1},millenium:function(e){if(void 0!==e){if("string"==typeof e&&(e=e.replace(/([0-9])(th|rd|st|nd)/,"$1"),e=Number(e),isNaN(e)))return console.warn("Spacetime: Invalid millenium input"),this;e>0&&(e-=1);let t=1e3*e;return 0===t&&(t=1),this.year(t)}let t=Math.floor(this.year()/1e3);return t>=0&&(t+=1),t}},at=Object.assign({},Ze,Xe,tt);at.milliseconds=at.millisecond,at.seconds=at.second,at.minutes=at.minute,at.hours=at.hour,at.hour24=at.hour,at.h12=at.hour12,at.h24=at.hour24,at.days=at.day;const nt=function(e,t){return 1===e&&g(t)?29:A[e]},rt=(e,t)=>{if(e.month>0){let a=parseInt(e.month/12,10);e.year=t.year()+a,e.month=e.month%12}else if(e.month<0){let a=Math.abs(e.month),n=parseInt(a/12,10);a%12!=0&&(n+=1),e.year=t.year()-n,e.month=e.month%12,e.month=e.month+12,12===e.month&&(e.month=0)}return e},it=(e,t,a)=>{let n=t.year(),r=t.month(),i=nt(r,n);for(;a>i;)a-=i,r+=1,r>=12&&(r-=12,n+=1),i=nt(r,n);return e.month=r,e.date=a,e},ot=(e,t,a)=>{e.year=t.year(),e.month=t.month();let n=t.date();for(e.date=n-Math.abs(a);e.date<1;){e.month-=1,e.month<0&&(e.month=11,e.year-=1);let t=nt(e.month,e.year);e.date+=t}return e},st=["millisecond","second","minute","hour","date","month"];let ut={second:st.slice(0,1),minute:st.slice(0,2),quarterhour:st.slice(0,2),hour:st.slice(0,3),date:st.slice(0,4),month:st.slice(0,4),quarter:st.slice(0,4),season:st.slice(0,4),year:st,decade:st,century:st};ut.week=ut.hour,ut.season=ut.date,ut.quarter=ut.date;const dt={year:!0,quarter:!0,season:!0,month:!0,week:!0,date:!0},lt={month:!0,quarter:!0,season:!0,year:!0},ht={millisecond:e=>e.epoch,second:e=>[e.year(),e.month(),e.date(),e.hour(),e.minute(),e.second()].join("-"),minute:e=>[e.year(),e.month(),e.date(),e.hour(),e.minute()].join("-"),hour:e=>[e.year(),e.month(),e.date(),e.hour()].join("-"),day:e=>[e.year(),e.month(),e.date()].join("-"),week:e=>[e.year(),e.week()].join("-"),month:e=>[e.year(),e.month()].join("-"),quarter:e=>[e.year(),e.quarter()].join("-"),year:e=>e.year()};ht.date=ht.day;let mt=u;const ct=function(e,t,a={}){this.epoch=null,this.tz=p(t,mt),this.silent=void 0===a.silent||a.silent,this.british=a.dmy||a.british,this._weekStart=1,void 0!==a.weekStart&&(this._weekStart=a.weekStart),this._today={},void 0!==a.today&&(this._today=a.today),Object.defineProperty(this,"d",{get:function(){let e=(e=>{let t=e.timezones[e.tz];if(void 0===t)return console.warn("Warning: couldn't find timezone "+e.tz),0;if(void 0===t.dst)return t.offset;let a=t.offset,n=t.offset+1;"n"===t.hem&&(n=a-1);let r=t.dst.split("->");return!0===i(e.epoch,r[0],r[1],a,n)?a:n})(this),t=(new Date(this.epoch).getTimezoneOffset()||0)+60*e;t=60*t*1e3;let a=this.epoch+t;return new Date(a)}}),Object.defineProperty(this,"timezones",{get:()=>mt,set:e=>(mt=e,e)});let n=X(this,e);this.epoch=n.epoch,n.tz&&(this.tz=n.tz)};var ft;Object.keys(Le).forEach((e=>{ct.prototype[e]=Le[e]})),ct.prototype.clone=function(){return new ct(this.epoch,this.tz,{silent:this.silent,weekStart:this._weekStart,today:this._today,parsers:this.parsers})},ct.prototype.toLocalDate=function(){return this.toNativeDate()},ct.prototype.toNativeDate=function(){return new Date(this.epoch)},ft=ct,Object.keys(at).forEach((e=>{ft.prototype[e]=at[e]})),(e=>{e.prototype.add=function(e,t){let a=this.clone();if(!t||0===e)return a;let n=this.clone();if("millisecond"===(t=x(t)))return a.epoch+=e,a;"fortnight"===t&&(e*=2,t="week"),V[t]?a.epoch+=V[t]*e:"week"===t||"weekend"===t?a.epoch+=V.day*(7*e):"quarter"===t||"season"===t?a.epoch+=V.month*(3*e):"quarterhour"===t&&(a.epoch+=15*V.minute*e);let r={};if(ut[t]&&ut[t].forEach((e=>{r[e]=n[e]()})),dt[t]){const e=n.timezone().current.offset-a.timezone().current.offset;a.epoch+=3600*e*1e3}if("month"===t&&(r.month=n.month()+e,r=rt(r,n)),"week"===t){let t=n.date()+7*e;t<=28&&t>1&&(r.date=t)}if("weekend"===t&&"saturday"!==a.dayName())a=a.day("saturday",!0);else if("date"===t){if(e<0)r=ot(r,n,e);else{let t=n.date()+e;r=it(r,n,t)}0!==e&&n.isSame(a,"day")&&(r.date=n.date()+e)}else if("quarter"===t){if(r.month=n.month()+3*e,r.year=n.year(),r.month<0){let e=Math.floor(r.month/12),t=r.month+12*Math.abs(e);r.month=t,r.year+=e}else if(r.month>=12){let e=Math.floor(r.month/12);r.month=r.month%12,r.year+=e}r.date=n.date()}else if("year"===t){let t=n.year()+e,r=a.year();if(rt){let t=Math.floor(e/4)||1;a.epoch+=V.day*t}}else"decade"===t?r.year=a.year()+10:"century"===t&&(r.year=a.year()+100);if(lt[t]){let e=A[r.month];r.date=n.date(),r.date>e&&(r.date=e)}return Object.keys(r).length>1&&C(a,r),a},e.prototype.subtract=function(e,t){return this.clone().add(-1*e,t)},e.prototype.minus=e.prototype.subtract,e.prototype.plus=e.prototype.add})(ct),(e=>{e.prototype.isSame=function(t,a,n=!0){let r=this;if(!a)return null;if("string"==typeof t&&"object"==typeof a){let e=t;t=a,a=e}return"string"!=typeof t&&"number"!=typeof t||(t=new e(t,this.timezone.name)),a=a.replace(/s$/,""),!0===n&&r.tz!==t.tz&&((t=t.clone()).tz=r.tz),ht[a]?ht[a](r)===ht[a](t):null}})(ct),(e=>{const t={isAfter:function(e){let t=O(e=M(e,this));return null===t?null:this.epoch>t},isBefore:function(e){let t=O(e=M(e,this));return null===t?null:this.epoch{e.prototype[a]=t[a]}))})(ct),(e=>{const t={i18n:function(e){var t,a,n;return b(e.days)&&(t=e.days,ee=t.short||ee,te=t.long||te),b(e.months)&&function(e){E=e.short||E,N=e.long||N}(e.months),n=e.useTitleCase,"[object Boolean]"===Object.prototype.toString.call(n)&&(a=e.useTitleCase,ie=a),b(e.ampm)&&function(e){Re=e.am||Re,Ge=e.pm||Ge}(e.ampm),b(e.distance)&&function(e){je=e.pastDistance||je,$e=e.futureDistance||$e,De=e.past||De,ve=e.future||ve,xe=e.present||xe,Oe=e.now||Oe,Me=e.almost||Me,_e=e.over||_e}(e.distance),b(e.units)&&function(e={}){be={second:e.second||be.second,seconds:e.seconds||be.seconds,minute:e.minute||be.minute,minutes:e.minutes||be.minutes,hour:e.hour||be.hour,hours:e.hours||be.hours,day:e.day||be.day,days:e.days||be.days,month:e.month||be.month,months:e.months||be.months,year:e.year||be.year,years:e.years||be.years}}(e.units),this}};Object.keys(t).forEach((a=>{e.prototype[a]=t[a]}))})(ct);const yt=(e,t,a)=>new ct(e,t,a),pt=function(e){let t=e._today||{};return Object.keys(t).forEach((a=>{e=e[a](t[a])})),e};yt.now=(e,t)=>{let a=new ct((new Date).getTime(),e,t);return a=pt(a),a},yt.today=(e,t)=>{let a=new ct((new Date).getTime(),e,t);return a=pt(a),a.startOf("day")},yt.tomorrow=(e,t)=>{let a=new ct((new Date).getTime(),e,t);return a=pt(a),a.add(1,"day").startOf("day")},yt.yesterday=(e,t)=>{let a=new ct((new Date).getTime(),e,t);return a=pt(a),a.subtract(1,"day").startOf("day")},yt.extend=function(e={}){return Object.keys(e).forEach((t=>{ct.prototype[t]=e[t]})),this},yt.timezones=function(){return(new ct).timezones},yt.max=function(e,t){let a=new ct(null,e,t);return a.epoch=864e13,a},yt.min=function(e,t){let a=new ct(null,e,t);return a.epoch=-864e13,a},yt.whereIts=(e,t)=>{let a=new ct(null),n=new ct(null);a=a.time(e),n=t?n.time(t):a.add(59,"minutes");let r=a.hour(),i=n.hour();return Object.keys(a.timezones).filter((e=>{if(-1===e.indexOf("/"))return!1;let t=new ct(null,e),o=t.hour();return o>=r&&o<=i&&!(o===r&&t.minute()n.minute())}))},yt.version="7.6.1",yt.plugin=yt.extend;const gt={daybreak:"7:00am",breakfast:"8:00am",morning:"9:00am",noon:"12:00pm",midday:"12:00pm",afternoon:"2:00pm",lunchtime:"12:00pm",evening:"6:00pm",dinnertime:"6:00pm",night:"8:00pm",eod:"10:00pm",midnight:"12:00am",am:"9:00am",pm:"5:00pm","early day":"8:00am","late at night":"11:00pm"},wt={quarter:15,half:30},bt=function(e){let t=e.time("6:00am");return e.isBefore(t)?e.ampm("pm"):e},kt=function(e,t){let a=e.match("(at|by|for|before|this|after)? #Time+");a=a.not("^(at|by|for|before|this|after)"),a=a.not("sharp"),a=a.not("on the dot");let n=yt.now(t.timezone),r=n.clone(),i=a.not("in the").text("reduced");if(i=i.replace(/^@/,""),gt.hasOwnProperty(i))return{result:gt[i],m:a};let o=a.match("^#Cardinal oclock (am|pm)?");if(o.found&&(n=n.hour(o.text("reduced")),n=n.startOf("hour"),n.isValid()&&!n.isEqual(r))){let e=o.match("(am|pm)");return n=e.found?n.ampm(e.text("reduced")):bt(n),{result:n.time(),m:o}}if(o=a.match("(half|quarter|25|20|15|10|5) (past|after|to) #Cardinal"),o.found&&(n=function(e,t){let a=e.match("#Cardinal$"),n=e.not(a).match("(half|quarter|25|20|15|10|5)");a=a.text("reduced");let r=n.text("reduced");wt.hasOwnProperty(r)&&(r=wt[r]);let i=e.has("to");return t=(t=t.hour(a)).startOf("hour"),a<6&&(t=t.ampm("pm")),i?t.subtract(r,"minutes"):t.add(r,"minutes")}(o,n),n.isValid()&&!n.isEqual(r)))return n=bt(n),{result:n.time(),m:o};if(o=a.match("[(half|quarter|25|20|15|10|5)] (past|after)"),o.found){let e=o.groups("min").text("reduced"),a=yt(t.today);if(wt.hasOwnProperty(e)&&(e=wt[e]),a=a.next("hour").startOf("hour").minute(e),a.isValid()&&!a.isEqual(r))return{result:a.time(),m:o}}if(o=a.match("[(half|quarter|25|20|15|10|5)] to"),o.found){let e=o.groups("min").text("reduced"),a=yt(t.today);if(wt.hasOwnProperty(e)&&(e=wt[e]),a=a.next("hour").startOf("hour").minus(e,"minutes"),a.isValid()&&!a.isEqual(r))return{result:a.time(),m:o}}if(o=a.match("[