UNPKG

386 kBJavaScriptView Raw
1/* compromise 13.9.0 MIT */
2function _typeof(obj) {
3 "@babel/helpers - typeof";
4
5 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
6 _typeof = function (obj) {
7 return typeof obj;
8 };
9 } else {
10 _typeof = function (obj) {
11 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
12 };
13 }
14
15 return _typeof(obj);
16}
17
18function _classCallCheck(instance, Constructor) {
19 if (!(instance instanceof Constructor)) {
20 throw new TypeError("Cannot call a class as a function");
21 }
22}
23
24function _defineProperties(target, props) {
25 for (var i = 0; i < props.length; i++) {
26 var descriptor = props[i];
27 descriptor.enumerable = descriptor.enumerable || false;
28 descriptor.configurable = true;
29 if ("value" in descriptor) descriptor.writable = true;
30 Object.defineProperty(target, descriptor.key, descriptor);
31 }
32}
33
34function _createClass(Constructor, protoProps, staticProps) {
35 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
36 if (staticProps) _defineProperties(Constructor, staticProps);
37 return Constructor;
38}
39
40function _inherits(subClass, superClass) {
41 if (typeof superClass !== "function" && superClass !== null) {
42 throw new TypeError("Super expression must either be null or a function");
43 }
44
45 subClass.prototype = Object.create(superClass && superClass.prototype, {
46 constructor: {
47 value: subClass,
48 writable: true,
49 configurable: true
50 }
51 });
52 if (superClass) _setPrototypeOf(subClass, superClass);
53}
54
55function _getPrototypeOf(o) {
56 _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
57 return o.__proto__ || Object.getPrototypeOf(o);
58 };
59 return _getPrototypeOf(o);
60}
61
62function _setPrototypeOf(o, p) {
63 _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
64 o.__proto__ = p;
65 return o;
66 };
67
68 return _setPrototypeOf(o, p);
69}
70
71function _isNativeReflectConstruct() {
72 if (typeof Reflect === "undefined" || !Reflect.construct) return false;
73 if (Reflect.construct.sham) return false;
74 if (typeof Proxy === "function") return true;
75
76 try {
77 Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
78 return true;
79 } catch (e) {
80 return false;
81 }
82}
83
84function _assertThisInitialized(self) {
85 if (self === void 0) {
86 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
87 }
88
89 return self;
90}
91
92function _possibleConstructorReturn(self, call) {
93 if (call && (typeof call === "object" || typeof call === "function")) {
94 return call;
95 }
96
97 return _assertThisInitialized(self);
98}
99
100function _createSuper(Derived) {
101 var hasNativeReflectConstruct = _isNativeReflectConstruct();
102
103 return function _createSuperInternal() {
104 var Super = _getPrototypeOf(Derived),
105 result;
106
107 if (hasNativeReflectConstruct) {
108 var NewTarget = _getPrototypeOf(this).constructor;
109
110 result = Reflect.construct(Super, arguments, NewTarget);
111 } else {
112 result = Super.apply(this, arguments);
113 }
114
115 return _possibleConstructorReturn(this, result);
116 };
117}
118
119//this is a not-well-thought-out way to reduce our dependence on `object===object` stuff
120var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split(''); //generates a unique id for this term
121
122function makeId(str) {
123 str = str || '_';
124 var text = str + '-';
125
126 for (var i = 0; i < 7; i++) {
127 text += chars[Math.floor(Math.random() * chars.length)];
128 }
129
130 return text;
131}
132
133var _id = makeId;
134
135//a hugely-ignorant, and widely subjective transliteration of latin, cryllic, greek unicode characters to english ascii.
136//approximate visual (not semantic or phonetic) relationship between unicode and ascii characters
137//http://en.wikipedia.org/wiki/List_of_Unicode_characters
138//https://docs.google.com/spreadsheet/ccc?key=0Ah46z755j7cVdFRDM1A2YVpwa1ZYWlpJM2pQZ003M0E
139var compact = {
140 '!': '¡',
141 '?': '¿Ɂ',
142 '"': '“”"❝❞',
143 "'": '‘‛❛❜',
144 '-': '—–',
145 a: 'ªÀÁÂÃÄÅàáâãäåĀāĂ㥹ǍǎǞǟǠǡǺǻȀȁȂȃȦȧȺΆΑΔΛάαλАадѦѧӐӑӒӓƛɅæ',
146 b: 'ßþƀƁƂƃƄƅɃΒβϐϦБВЪЬвъьѢѣҌҍ',
147 c: '¢©ÇçĆćĈĉĊċČčƆƇƈȻȼͻͼͽϲϹϽϾСсєҀҁҪҫ',
148 d: 'ÐĎďĐđƉƊȡƋƌǷ',
149 e: 'ÈÉÊËèéêëĒēĔĕĖėĘęĚěƎƏƐǝȄȅȆȇȨȩɆɇΈΕΞΣέεξϱϵ϶ЀЁЕЭеѐёҼҽҾҿӖӗӘәӚӛӬӭ',
150 f: 'ƑƒϜϝӺӻҒғſ',
151 g: 'ĜĝĞğĠġĢģƓǤǥǦǧǴǵ',
152 h: 'ĤĥĦħƕǶȞȟΉΗЂЊЋНнђћҢңҤҥҺһӉӊ',
153 I: 'ÌÍÎÏ',
154 i: 'ìíîïĨĩĪīĬĭĮįİıƖƗȈȉȊȋΊΐΪίιϊІЇії',
155 j: 'ĴĵǰȷɈɉϳЈј',
156 k: 'ĶķĸƘƙǨǩΚκЌЖКжкќҚқҜҝҞҟҠҡ',
157 l: 'ĹĺĻļĽľĿŀŁłƚƪǀǏǐȴȽΙӀӏ',
158 m: 'ΜϺϻМмӍӎ',
159 n: 'ÑñŃńŅņŇňʼnŊŋƝƞǸǹȠȵΝΠήηϞЍИЙЛПийлпѝҊҋӅӆӢӣӤӥπ',
160 o: 'ÒÓÔÕÖØðòóôõöøŌōŎŏŐőƟƠơǑǒǪǫǬǭǾǿȌȍȎȏȪȫȬȭȮȯȰȱΌΘΟθοσόϕϘϙϬϭϴОФоѲѳӦӧӨөӪӫ',
161 p: 'ƤƿΡρϷϸϼРрҎҏÞ',
162 q: 'Ɋɋ',
163 r: 'ŔŕŖŗŘřƦȐȑȒȓɌɍЃГЯгяѓҐґ',
164 s: 'ŚśŜŝŞşŠšƧƨȘșȿЅѕ',
165 t: 'ŢţŤťŦŧƫƬƭƮȚțȶȾΓΤτϮТт',
166 u: 'µÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųƯưƱƲǓǔǕǖǗǘǙǚǛǜȔȕȖȗɄΰμυϋύ',
167 v: 'νѴѵѶѷ',
168 w: 'ŴŵƜωώϖϢϣШЩшщѡѿ',
169 x: '×ΧχϗϰХхҲҳӼӽӾӿ',
170 y: 'ÝýÿŶŷŸƳƴȲȳɎɏΎΥΫγψϒϓϔЎУучўѰѱҮүҰұӮӯӰӱӲӳ',
171 z: 'ŹźŻżŽžƩƵƶȤȥɀΖζ'
172}; //decompress data into two hashes
173
174var unicode = {};
175Object.keys(compact).forEach(function (k) {
176 compact[k].split('').forEach(function (s) {
177 unicode[s] = k;
178 });
179});
180
181var killUnicode = function killUnicode(str) {
182 var chars = str.split('');
183 chars.forEach(function (s, i) {
184 if (unicode[s]) {
185 chars[i] = unicode[s];
186 }
187 });
188 return chars.join('');
189};
190
191var unicode_1 = killUnicode; // console.log(killUnicode('bjŏȒk—Ɏó'));
192
193var periodAcronym = /([A-Z]\.)+[A-Z]?,?$/;
194var oneLetterAcronym = /^[A-Z]\.,?$/;
195var noPeriodAcronym = /[A-Z]{2,}('s|,)?$/;
196var lowerCaseAcronym = /([a-z]\.){1,}[a-z]\.?$/;
197
198var isAcronym = function isAcronym(str) {
199 //like N.D.A
200 if (periodAcronym.test(str) === true) {
201 return true;
202 } //like c.e.o
203
204
205 if (lowerCaseAcronym.test(str) === true) {
206 return true;
207 } //like 'F.'
208
209
210 if (oneLetterAcronym.test(str) === true) {
211 return true;
212 } //like NDA
213
214
215 if (noPeriodAcronym.test(str) === true) {
216 return true;
217 }
218
219 return false;
220};
221
222var isAcronym_1 = isAcronym;
223
224var hasSlash = /[a-z\u00C0-\u00FF] ?\/ ?[a-z\u00C0-\u00FF]/;
225/** some basic operations on a string to reduce noise */
226
227var clean = function clean(str) {
228 str = str || '';
229 str = str.toLowerCase();
230 str = str.trim();
231 var original = str; //(very) rough ASCII transliteration - bjŏrk -> bjork
232
233 str = unicode_1(str); //rough handling of slashes - 'see/saw'
234
235 if (hasSlash.test(str) === true) {
236 str = str.replace(/\/.*/, '');
237 } //#tags, @mentions
238
239
240 str = str.replace(/^[#@]/, ''); //punctuation
241
242 str = str.replace(/[,;.!?]+$/, ''); // coerce single curly quotes
243
244 str = str.replace(/[\u0027\u0060\u00B4\u2018\u2019\u201A\u201B\u2032\u2035\u2039\u203A]+/g, "'"); // coerce double curly quotes
245
246 str = str.replace(/[\u0022\u00AB\u00BB\u201C\u201D\u201E\u201F\u2033\u2034\u2036\u2037\u2E42\u301D\u301E\u301F\uFF02]+/g, '"'); //coerce Unicode ellipses
247
248 str = str.replace(/\u2026/g, '...'); //en-dash
249
250 str = str.replace(/\u2013/g, '-'); //lookin'->looking (make it easier for conjugation)
251
252 str = str.replace(/([aeiou][ktrp])in$/, '$1ing'); //turn re-enactment to reenactment
253
254 if (/^(re|un)-?[^aeiou]./.test(str) === true) {
255 str = str.replace('-', '');
256 } //compact acronyms
257
258
259 if (isAcronym_1(str)) {
260 str = str.replace(/\./g, '');
261 } //strip leading & trailing grammatical punctuation
262
263
264 if (/^[:;]/.test(str) === false) {
265 str = str.replace(/\.{3,}$/g, '');
266 str = str.replace(/[",\.!:;\?\)]+$/g, '');
267 str = str.replace(/^['"\(]+/g, '');
268 } // remove zero-width characters
269
270
271 str = str.replace(/[\u200B-\u200D\uFEFF]/g, ''); //do this again..
272
273 str = str.trim(); //oh shucks,
274
275 if (str === '') {
276 str = original;
277 } //nice-numbers
278
279
280 str = str.replace(/([0-9]),([0-9])/g, '$1$2');
281 return str;
282};
283
284var clean_1 = clean; // console.log(normalize('Dr. V Cooper'));
285
286/** reduced is one step further than clean */
287var reduced = function reduced(str) {
288 // remove apostrophes
289 str = str.replace(/['’]s$/, '');
290 str = str.replace(/s['’]$/, 's');
291 return str;
292};
293
294var reduce = reduced;
295
296//all punctuation marks, from https://en.wikipedia.org/wiki/Punctuation
297//we have slightly different rules for start/end - like #hashtags.
298
299var startings = /^[ \n\t\.’'\[\](){}⟨⟩:,،、‒–—―…!.‹›«»‐\-?‘’;\/⁄·&*•^†‡°¡¿※№÷׺ª%‰+−=‱¶′″‴§~|‖¦©℗®℠™¤₳฿\u0022|\uFF02|\u0027|\u201C|\u2018|\u201F|\u201B|\u201E|\u2E42|\u201A|\u00AB|\u2039|\u2035|\u2036|\u2037|\u301D|\u0060|\u301F]+/;
300var endings = /[ \n\t\.’'\[\](){}⟨⟩:,،、‒–—―…!.‹›«»‐\-?‘’;\/⁄·&*@•^†‡°¡¿※#№÷׺ª‰+−=‱¶′″‴§~|‖¦©℗®℠™¤₳฿\u0022|\uFF02|\u0027|\u201D|\u2019|\u201D|\u2019|\u201D|\u201D|\u2019|\u00BB|\u203A|\u2032|\u2033|\u2034|\u301E|\u00B4|\u301E]+$/; //money = ₵¢₡₢$₫₯֏₠€ƒ₣₲₴₭₺₾ℳ₥₦₧₱₰£៛₽₹₨₪৳₸₮₩¥
301
302var hasSlash$1 = /\//;
303var hasApostrophe = /['’]/;
304var hasAcronym = /^[a-z]\.([a-z]\.)+/i;
305var minusNumber = /^[-+\.][0-9]/;
306var shortYear = /^'[0-9]{2}/;
307/** turn given text into a parsed-up object
308 * seperate the 'meat' of the word from the whitespace+punctuation
309 */
310
311var parseTerm = function parseTerm(str) {
312 var original = str;
313 var pre = '';
314 var post = '';
315 str = str.replace(startings, function (found) {
316 pre = found; // support '-40'
317
318 if ((pre === '-' || pre === '+' || pre === '.') && minusNumber.test(str)) {
319 pre = '';
320 return found;
321 } // support years like '97
322
323
324 if (pre === "'" && shortYear.test(str)) {
325 pre = '';
326 return found;
327 }
328
329 return '';
330 });
331 str = str.replace(endings, function (found) {
332 post = found; // keep s-apostrophe - "flanders'" or "chillin'"
333
334 if (hasApostrophe.test(found) && /[sn]['’]$/.test(original) && hasApostrophe.test(pre) === false) {
335 post = post.replace(hasApostrophe, '');
336 return "'";
337 } //keep end-period in acronym
338
339
340 if (hasAcronym.test(str) === true) {
341 post = post.replace(/\./, '');
342 return '.';
343 }
344
345 return '';
346 }); //we went too far..
347
348 if (str === '') {
349 // do a very mild parse, and hope for the best.
350 original = original.replace(/ *$/, function (after) {
351 post = after || '';
352 return '';
353 });
354 str = original;
355 pre = '';
356 post = post;
357 } // create the various forms of our text,
358
359
360 var clean = clean_1(str);
361 var parsed = {
362 text: str,
363 clean: clean,
364 reduced: reduce(clean),
365 pre: pre,
366 post: post
367 }; // support aliases for slashes
368
369 if (hasSlash$1.test(str)) {
370 str.split(hasSlash$1).forEach(function (word) {
371 parsed.alias = parsed.alias || {};
372 parsed.alias[word.trim()] = true;
373 });
374 }
375
376 return parsed;
377};
378
379var parse = parseTerm;
380
381function createCommonjsModule(fn) {
382 var module = { exports: {} };
383 return fn(module, module.exports), module.exports;
384}
385
386var _01Case = createCommonjsModule(function (module, exports) {
387 var titleCase = /^[A-Z][a-z'\u00C0-\u00FF]/;
388 var upperCase = /^[A-Z]+s?$/;
389 /** convert all text to uppercase */
390
391 exports.toUpperCase = function () {
392 this.text = this.text.toUpperCase();
393 return this;
394 };
395 /** convert all text to lowercase */
396
397
398 exports.toLowerCase = function () {
399 this.text = this.text.toLowerCase();
400 return this;
401 };
402 /** only set the first letter to uppercase
403 * leave any existing uppercase alone
404 */
405
406
407 exports.toTitleCase = function () {
408 this.text = this.text.replace(/^ *[a-z\u00C0-\u00FF]/, function (x) {
409 return x.toUpperCase();
410 }); //support unicode?
411
412 return this;
413 };
414 /** if all letters are uppercase */
415
416
417 exports.isUpperCase = function () {
418 return upperCase.test(this.text);
419 };
420 /** if the first letter is uppercase, and the rest are lowercase */
421
422
423 exports.isTitleCase = function () {
424 return titleCase.test(this.text);
425 };
426
427 exports.titleCase = exports.isTitleCase;
428});
429
430var _02Punctuation = createCommonjsModule(function (module, exports) {
431 // these methods are called with '@hasComma' in the match syntax
432 // various unicode quotation-mark formats
433 var startQuote = /(\u0022|\uFF02|\u0027|\u201C|\u2018|\u201F|\u201B|\u201E|\u2E42|\u201A|\u00AB|\u2039|\u2035|\u2036|\u2037|\u301D|\u0060|\u301F)/;
434 var endQuote = /(\u0022|\uFF02|\u0027|\u201D|\u2019|\u201D|\u2019|\u201D|\u201D|\u2019|\u00BB|\u203A|\u2032|\u2033|\u2034|\u301E|\u00B4|\u301E)/;
435 /** search the term's 'post' punctuation */
436
437 exports.hasPost = function (punct) {
438 return this.post.indexOf(punct) !== -1;
439 };
440 /** search the term's 'pre' punctuation */
441
442
443 exports.hasPre = function (punct) {
444 return this.pre.indexOf(punct) !== -1;
445 };
446 /** does it have a quotation symbol? */
447
448
449 exports.hasQuote = function () {
450 return startQuote.test(this.pre) || endQuote.test(this.post);
451 };
452
453 exports.hasQuotation = exports.hasQuote;
454 /** does it have a comma? */
455
456 exports.hasComma = function () {
457 return this.hasPost(',');
458 };
459 /** does it end in a period? */
460
461
462 exports.hasPeriod = function () {
463 return this.hasPost('.') === true && this.hasPost('...') === false;
464 };
465 /** does it end in an exclamation */
466
467
468 exports.hasExclamation = function () {
469 return this.hasPost('!');
470 };
471 /** does it end with a question mark? */
472
473
474 exports.hasQuestionMark = function () {
475 return this.hasPost('?') || this.hasPost('¿');
476 };
477 /** is there a ... at the end? */
478
479
480 exports.hasEllipses = function () {
481 return this.hasPost('..') || this.hasPost('…') || this.hasPre('..') || this.hasPre('…');
482 };
483 /** is there a semicolon after this word? */
484
485
486 exports.hasSemicolon = function () {
487 return this.hasPost(';');
488 };
489 /** is there a slash '/' in this word? */
490
491
492 exports.hasSlash = function () {
493 return /\//.test(this.text);
494 };
495 /** a hyphen connects two words like-this */
496
497
498 exports.hasHyphen = function () {
499 var hyphen = /^(-|–|—)$/;
500 return hyphen.test(this.post) || hyphen.test(this.pre);
501 };
502 /** a dash separates words - like that */
503
504
505 exports.hasDash = function () {
506 var hyphen = / (-|–|—) /;
507 return hyphen.test(this.post) || hyphen.test(this.pre);
508 };
509 /** is it multiple words combinded */
510
511
512 exports.hasContraction = function () {
513 return Boolean(this.implicit);
514 };
515 /** try to sensibly put this punctuation mark into the term */
516
517
518 exports.addPunctuation = function (punct) {
519 // dont add doubles
520 if (punct === ',' || punct === ';') {
521 this.post = this.post.replace(punct, '');
522 }
523
524 this.post = punct + this.post;
525 return this;
526 };
527});
528
529// fuzzy-match (damerau-levenshtein)
530// Based on tad-lispy /node-damerau-levenshtein
531// https://github.com/tad-lispy/node-damerau-levenshtein/blob/master/index.js
532// count steps (insertions, deletions, substitutions, or transpositions)
533var editDistance = function editDistance(strA, strB) {
534 var aLength = strA.length,
535 bLength = strB.length; // fail-fast
536
537 if (aLength === 0) {
538 return bLength;
539 }
540
541 if (bLength === 0) {
542 return aLength;
543 } // If the limit is not defined it will be calculate from this and that args.
544
545
546 var limit = (bLength > aLength ? bLength : aLength) + 1;
547
548 if (Math.abs(aLength - bLength) > (limit || 100)) {
549 return limit || 100;
550 } // init the array
551
552
553 var matrix = [];
554
555 for (var i = 0; i < limit; i++) {
556 matrix[i] = [i];
557 matrix[i].length = limit;
558 }
559
560 for (var _i = 0; _i < limit; _i++) {
561 matrix[0][_i] = _i;
562 } // Calculate matrix.
563
564
565 var j, a_index, b_index, cost, min, t;
566
567 for (var _i2 = 1; _i2 <= aLength; ++_i2) {
568 a_index = strA[_i2 - 1];
569
570 for (j = 1; j <= bLength; ++j) {
571 // Check the jagged distance total so far
572 if (_i2 === j && matrix[_i2][j] > 4) {
573 return aLength;
574 }
575
576 b_index = strB[j - 1];
577 cost = a_index === b_index ? 0 : 1; // Step 5
578 // Calculate the minimum (much faster than Math.min(...)).
579
580 min = matrix[_i2 - 1][j] + 1; // Deletion.
581
582 if ((t = matrix[_i2][j - 1] + 1) < min) min = t; // Insertion.
583
584 if ((t = matrix[_i2 - 1][j - 1] + cost) < min) min = t; // Substitution.
585 // Update matrix.
586
587 var shouldUpdate = _i2 > 1 && j > 1 && a_index === strB[j - 2] && strA[_i2 - 2] === b_index && (t = matrix[_i2 - 2][j - 2] + cost) < min;
588
589 if (shouldUpdate) {
590 matrix[_i2][j] = t;
591 } else {
592 matrix[_i2][j] = min;
593 }
594 }
595 } // return number of steps
596
597
598 return matrix[aLength][bLength];
599}; // score similarity by from 0-1 (steps/length)
600
601
602var fuzzyMatch = function fuzzyMatch(strA, strB) {
603 var minLength = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 3;
604
605 if (strA === strB) {
606 return 1;
607 } //don't even bother on tiny strings
608
609
610 if (strA.length < minLength || strB.length < minLength) {
611 return 0;
612 }
613
614 var steps = editDistance(strA, strB);
615 var length = Math.max(strA.length, strB.length);
616 var relative = length === 0 ? 0 : steps / length;
617 var similarity = 1 - relative;
618 return similarity;
619};
620
621var _fuzzy = fuzzyMatch; // console.log(fuzzyMatch('test', 'test')) //exact match
622
623var wrapMatch = function wrapMatch() {};
624/** ignore optional/greedy logic, straight-up term match*/
625
626
627var doesMatch = function doesMatch(t, reg, index, length) {
628 // support id matches
629 if (reg.id === t.id) {
630 return true;
631 } // support '.'
632
633
634 if (reg.anything === true) {
635 return true;
636 } // support '^' (in parentheses)
637
638
639 if (reg.start === true && index !== 0) {
640 return false;
641 } // support '$' (in parentheses)
642
643
644 if (reg.end === true && index !== length - 1) {
645 return false;
646 } //support a text match
647
648
649 if (reg.word !== undefined) {
650 //match contractions
651 if (t.implicit !== null && t.implicit === reg.word) {
652 return true;
653 } // term aliases for slashes and things
654
655
656 if (t.alias !== undefined && t.alias.hasOwnProperty(reg.word)) {
657 return true;
658 } // support ~ match
659
660
661 if (reg.soft === true && reg.word === t.root) {
662 return true;
663 } // support fuzzy match param
664
665
666 if (reg.fuzzy !== undefined) {
667 var score = _fuzzy(reg.word, t.reduced);
668
669 if (score > reg.fuzzy) {
670 return true;
671 } // support fuzzy + soft match
672
673
674 if (reg.soft === true) {
675 score = _fuzzy(reg.word, t.root);
676
677 if (score > reg.fuzzy) {
678 return true;
679 }
680 }
681 } //match either .clean or .text
682
683
684 return reg.word === t.clean || reg.word === t.text || reg.word === t.reduced;
685 } //support #Tag
686
687
688 if (reg.tag !== undefined) {
689 return t.tags[reg.tag] === true;
690 } //support @method
691
692
693 if (reg.method !== undefined) {
694 if (typeof t[reg.method] === 'function' && t[reg.method]() === true) {
695 return true;
696 }
697
698 return false;
699 } //support /reg/
700
701
702 if (reg.regex !== undefined) {
703 return reg.regex.test(t.clean);
704 } // support optimized (one|two)
705
706
707 if (reg.fastOr !== undefined) {
708 return reg.fastOr.hasOwnProperty(t.reduced) || reg.fastOr.hasOwnProperty(t.text);
709 } //support slower (one|two)
710
711
712 if (reg.choices !== undefined) {
713 // try to support && operator
714 if (reg.operator === 'and') {
715 // must match them all
716 return reg.choices.every(function (r) {
717 return wrapMatch(t, r, index, length);
718 });
719 } // or must match one
720
721
722 return reg.choices.some(function (r) {
723 return wrapMatch(t, r, index, length);
724 });
725 }
726
727 return false;
728}; // wrap result for !negative match logic
729
730
731wrapMatch = function wrapMatch(t, reg, index, length) {
732 var result = doesMatch(t, reg, index, length);
733
734 if (reg.negative === true) {
735 return !result;
736 }
737
738 return result;
739};
740
741var _doesMatch = wrapMatch;
742
743var boring = {};
744/** check a match object against this term */
745
746var doesMatch_1 = function doesMatch_1(reg, index, length) {
747 return _doesMatch(this, reg, index, length);
748};
749/** does this term look like an acronym? */
750
751
752var isAcronym_1$1 = function isAcronym_1$1() {
753 return isAcronym_1(this.text);
754};
755/** is this term implied by a contraction? */
756
757
758var isImplicit = function isImplicit() {
759 return this.text === '' && Boolean(this.implicit);
760};
761/** does the term have at least one good tag? */
762
763
764var isKnown = function isKnown() {
765 return Object.keys(this.tags).some(function (t) {
766 return boring[t] !== true;
767 });
768};
769/** cache the root property of the term */
770
771
772var setRoot = function setRoot(world) {
773 var transform = world.transforms;
774 var str = this.implicit || this.clean;
775
776 if (this.tags.Plural) {
777 str = transform.toSingular(str, world);
778 }
779
780 if (this.tags.Verb && !this.tags.Negative && !this.tags.Infinitive) {
781 var tense = null;
782
783 if (this.tags.PastTense) {
784 tense = 'PastTense';
785 } else if (this.tags.Gerund) {
786 tense = 'Gerund';
787 } else if (this.tags.PresentTense) {
788 tense = 'PresentTense';
789 } else if (this.tags.Participle) {
790 tense = 'Participle';
791 } else if (this.tags.Actor) {
792 tense = 'Actor';
793 }
794
795 str = transform.toInfinitive(str, world, tense);
796 }
797
798 this.root = str;
799};
800
801var _03Misc = {
802 doesMatch: doesMatch_1,
803 isAcronym: isAcronym_1$1,
804 isImplicit: isImplicit,
805 isKnown: isKnown,
806 setRoot: setRoot
807};
808
809var hasSpace = /[\s-]/;
810var isUpperCase = /^[A-Z-]+$/; // const titleCase = str => {
811// return str.charAt(0).toUpperCase() + str.substr(1)
812// }
813
814/** return various text formats of this term */
815
816var textOut = function textOut(options, showPre, showPost) {
817 options = options || {};
818 var word = this.text;
819 var before = this.pre;
820 var after = this.post; // -word-
821
822 if (options.reduced === true) {
823 word = this.reduced || '';
824 }
825
826 if (options.root === true) {
827 word = this.root || '';
828 }
829
830 if (options.implicit === true && this.implicit) {
831 word = this.implicit || '';
832 }
833
834 if (options.normal === true) {
835 word = this.clean || this.text || '';
836 }
837
838 if (options.root === true) {
839 word = this.root || this.reduced || '';
840 }
841
842 if (options.unicode === true) {
843 word = unicode_1(word);
844 } // cleanup case
845
846
847 if (options.titlecase === true) {
848 if (this.tags.ProperNoun && !this.titleCase()) ; else if (this.tags.Acronym) {
849 word = word.toUpperCase(); //uppercase acronyms
850 } else if (isUpperCase.test(word) && !this.tags.Acronym) {
851 // lowercase everything else
852 word = word.toLowerCase();
853 }
854 }
855
856 if (options.lowercase === true) {
857 word = word.toLowerCase();
858 } // remove the '.'s from 'F.B.I.' (safely)
859
860
861 if (options.acronyms === true && this.tags.Acronym) {
862 word = word.replace(/\./g, '');
863 } // -before/after-
864
865
866 if (options.whitespace === true || options.root === true) {
867 before = '';
868 after = ' ';
869
870 if ((hasSpace.test(this.post) === false || options.last) && !this.implicit) {
871 after = '';
872 }
873 }
874
875 if (options.punctuation === true && !options.root) {
876 //normalized end punctuation
877 if (this.hasPost('.') === true) {
878 after = '.' + after;
879 } else if (this.hasPost('?') === true) {
880 after = '?' + after;
881 } else if (this.hasPost('!') === true) {
882 after = '!' + after;
883 } else if (this.hasPost(',') === true) {
884 after = ',' + after;
885 } else if (this.hasEllipses() === true) {
886 after = '...' + after;
887 }
888 }
889
890 if (showPre !== true) {
891 before = '';
892 }
893
894 if (showPost !== true) {
895 // let keep = after.match(/\)/) || ''
896 after = ''; //keep //after.replace(/[ .?!,]+/, '')
897 } // remove the '.' from 'Mrs.' (safely)
898
899
900 if (options.abbreviations === true && this.tags.Abbreviation) {
901 after = after.replace(/^\./, '');
902 }
903
904 return before + word + after;
905};
906
907var _04Text = {
908 textOut: textOut
909};
910
911var boringTags = {
912 Auxiliary: 1,
913 Possessive: 1
914};
915/** a subjective ranking of tags kinda tfidf-based */
916
917var rankTags = function rankTags(term, world) {
918 var tags = Object.keys(term.tags);
919 var tagSet = world.tags;
920 tags = tags.sort(function (a, b) {
921 //bury the tags we dont want
922 if (boringTags[b] || !tagSet[b]) {
923 return -1;
924 } // unknown tags are interesting
925
926
927 if (!tagSet[b]) {
928 return 1;
929 }
930
931 if (!tagSet[a]) {
932 return 0;
933 } // then sort by #of parent tags (most-specific tags first)
934
935
936 if (tagSet[a].lineage.length > tagSet[b].lineage.length) {
937 return 1;
938 }
939
940 if (tagSet[a].isA.length > tagSet[b].isA.length) {
941 return -1;
942 }
943
944 return 0;
945 });
946 return tags;
947};
948
949var _bestTag = rankTags;
950
951var jsonDefault = {
952 text: true,
953 tags: true,
954 implicit: true,
955 whitespace: true,
956 clean: false,
957 id: false,
958 index: false,
959 offset: false,
960 bestTag: false
961};
962/** return various metadata for this term */
963
964var json = function json(options, world) {
965 options = options || {};
966 options = Object.assign({}, jsonDefault, options);
967 var result = {}; // default on
968
969 if (options.text) {
970 result.text = this.text;
971 }
972
973 if (options.normal) {
974 result.normal = this.clean;
975 }
976
977 if (options.tags) {
978 result.tags = Object.keys(this.tags);
979 } // default off
980
981
982 if (options.clean) {
983 result.clean = this.clean;
984 }
985
986 if (options.id || options.offset) {
987 result.id = this.id;
988 }
989
990 if (options.implicit && this.implicit !== null) {
991 result.implicit = this.implicit;
992 }
993
994 if (options.whitespace) {
995 result.pre = this.pre;
996 result.post = this.post;
997 }
998
999 if (options.bestTag) {
1000 result.bestTag = _bestTag(this, world)[0];
1001 }
1002
1003 return result;
1004};
1005
1006var _05Json = {
1007 json: json
1008};
1009
1010var methods = Object.assign({}, _01Case, _02Punctuation, _03Misc, _04Text, _05Json);
1011
1012function isClientSide() {
1013 return typeof window !== 'undefined' && window.document;
1014}
1015/** add spaces at the end */
1016
1017
1018var padEnd = function padEnd(str, width) {
1019 str = str.toString();
1020
1021 while (str.length < width) {
1022 str += ' ';
1023 }
1024
1025 return str;
1026};
1027/** output for verbose-mode */
1028
1029
1030var logTag = function logTag(t, tag, reason) {
1031 if (isClientSide()) {
1032 console.log('%c' + padEnd(t.clean, 3) + ' + ' + tag + ' ', 'color: #6accb2;');
1033 return;
1034 } //server-side
1035
1036
1037 var log = '\x1b[33m' + padEnd(t.clean, 15) + '\x1b[0m + \x1b[32m' + tag + '\x1b[0m ';
1038
1039 if (reason) {
1040 log = padEnd(log, 35) + ' ' + reason + '';
1041 }
1042
1043 console.log(log);
1044};
1045/** output for verbose mode */
1046
1047
1048var logUntag = function logUntag(t, tag, reason) {
1049 if (isClientSide()) {
1050 console.log('%c' + padEnd(t.clean, 3) + ' - ' + tag + ' ', 'color: #AB5850;');
1051 return;
1052 } //server-side
1053
1054
1055 var log = '\x1b[33m' + padEnd(t.clean, 3) + ' \x1b[31m - #' + tag + '\x1b[0m ';
1056
1057 if (reason) {
1058 log = padEnd(log, 35) + ' ' + reason;
1059 }
1060
1061 console.log(log);
1062};
1063
1064var isArray = function isArray(arr) {
1065 return Object.prototype.toString.call(arr) === '[object Array]';
1066};
1067
1068var titleCase = function titleCase(str) {
1069 return str.charAt(0).toUpperCase() + str.substr(1);
1070};
1071
1072var fns = {
1073 logTag: logTag,
1074 logUntag: logUntag,
1075 isArray: isArray,
1076 titleCase: titleCase
1077};
1078
1079/** add a tag, and its descendents, to a term */
1080
1081var addTag = function addTag(t, tag, reason, world) {
1082 var tagset = world.tags; //support '.' or '-' notation for skipping the tag
1083
1084 if (tag === '' || tag === '.' || tag === '-') {
1085 return;
1086 }
1087
1088 if (tag[0] === '#') {
1089 tag = tag.replace(/^#/, '');
1090 }
1091
1092 tag = fns.titleCase(tag); //if we already got this one
1093
1094 if (t.tags[tag] === true) {
1095 return;
1096 } // log it?
1097
1098
1099 var isVerbose = world.isVerbose();
1100
1101 if (isVerbose === true) {
1102 fns.logTag(t, tag, reason);
1103 } //add tag
1104
1105
1106 t.tags[tag] = true; //whee!
1107 //check tagset for any additional things to do...
1108
1109 if (tagset.hasOwnProperty(tag) === true) {
1110 //add parent Tags
1111 tagset[tag].isA.forEach(function (down) {
1112 t.tags[down] = true;
1113
1114 if (isVerbose === true) {
1115 fns.logTag(t, '→ ' + down);
1116 }
1117 }); //remove any contrary tags
1118
1119 t.unTag(tagset[tag].notA, '←', world);
1120 }
1121};
1122/** support an array of tags */
1123
1124
1125var addTags = function addTags(term, tags, reason, world) {
1126 if (typeof tags !== 'string') {
1127 for (var i = 0; i < tags.length; i++) {
1128 addTag(term, tags[i], reason, world);
1129 } // tags.forEach(tag => addTag(term, tag, reason, world))
1130
1131 } else {
1132 addTag(term, tags, reason, world);
1133 }
1134};
1135
1136var add = addTags;
1137
1138var lowerCase = /^[a-z]/;
1139
1140var titleCase$1 = function titleCase(str) {
1141 return str.charAt(0).toUpperCase() + str.substr(1);
1142};
1143/** remove this tag, and its descentents from the term */
1144
1145
1146var unTag = function unTag(t, tag, reason, world) {
1147 var isVerbose = world.isVerbose(); //support '*' for removing all tags
1148
1149 if (tag === '*') {
1150 t.tags = {};
1151 return t;
1152 }
1153
1154 tag = tag.replace(/^#/, '');
1155
1156 if (lowerCase.test(tag) === true) {
1157 tag = titleCase$1(tag);
1158 } // remove the tag
1159
1160
1161 if (t.tags[tag] === true) {
1162 delete t.tags[tag]; //log in verbose-mode
1163
1164 if (isVerbose === true) {
1165 fns.logUntag(t, tag, reason);
1166 }
1167 } //delete downstream tags too
1168
1169
1170 var tagset = world.tags;
1171
1172 if (tagset[tag]) {
1173 var lineage = tagset[tag].lineage;
1174
1175 for (var i = 0; i < lineage.length; i++) {
1176 if (t.tags[lineage[i]] === true) {
1177 delete t.tags[lineage[i]];
1178
1179 if (isVerbose === true) {
1180 fns.logUntag(t, ' - ' + lineage[i]);
1181 }
1182 }
1183 }
1184 }
1185
1186 return t;
1187}; //handle an array of tags
1188
1189
1190var untagAll = function untagAll(term, tags, reason, world) {
1191 if (typeof tags !== 'string' && tags) {
1192 for (var i = 0; i < tags.length; i++) {
1193 unTag(term, tags[i], reason, world);
1194 }
1195
1196 return;
1197 }
1198
1199 unTag(term, tags, reason, world);
1200};
1201
1202var unTag_1 = untagAll;
1203
1204var canBe = function canBe(term, tag, world) {
1205 var tagset = world.tags; // cleanup tag
1206
1207 if (tag[0] === '#') {
1208 tag = tag.replace(/^#/, '');
1209 } //fail-fast
1210
1211
1212 if (tagset[tag] === undefined) {
1213 return true;
1214 } //loop through tag's contradictory tags
1215
1216
1217 var enemies = tagset[tag].notA || [];
1218
1219 for (var i = 0; i < enemies.length; i++) {
1220 if (term.tags[enemies[i]] === true) {
1221 return false;
1222 }
1223 }
1224
1225 if (tagset[tag].isA !== undefined) {
1226 return canBe(term, tagset[tag].isA, world); //recursive
1227 }
1228
1229 return true;
1230};
1231
1232var canBe_1 = canBe;
1233
1234/** add a tag or tags, and their descendents to this term
1235 * @param {string | string[]} tags - a tag or tags
1236 * @param {string?} [reason] a clue for debugging
1237 */
1238
1239var tag_1 = function tag_1(tags, reason, world) {
1240 add(this, tags, reason, world);
1241 return this;
1242};
1243/** only tag this term if it's consistent with it's current tags */
1244
1245
1246var tagSafe = function tagSafe(tags, reason, world) {
1247 if (canBe_1(this, tags, world)) {
1248 add(this, tags, reason, world);
1249 }
1250
1251 return this;
1252};
1253/** remove a tag or tags, and their descendents from this term
1254 * @param {string | string[]} tags - a tag or tags
1255 * @param {string?} [reason] a clue for debugging
1256 */
1257
1258
1259var unTag_1$1 = function unTag_1$1(tags, reason, world) {
1260 unTag_1(this, tags, reason, world);
1261 return this;
1262};
1263/** is this tag consistent with the word's current tags?
1264 * @param {string | string[]} tags - a tag or tags
1265 * @returns {boolean}
1266 */
1267
1268
1269var canBe_1$1 = function canBe_1$1(tags, world) {
1270 return canBe_1(this, tags, world);
1271};
1272
1273var tag = {
1274 tag: tag_1,
1275 tagSafe: tagSafe,
1276 unTag: unTag_1$1,
1277 canBe: canBe_1$1
1278};
1279
1280var Term = /*#__PURE__*/function () {
1281 function Term() {
1282 var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
1283
1284 _classCallCheck(this, Term);
1285
1286 text = String(text);
1287 var obj = parse(text); // the various forms of our text
1288
1289 this.text = obj.text || '';
1290 this.clean = obj.clean;
1291 this.reduced = obj.reduced;
1292 this.root = null;
1293 this.implicit = null;
1294 this.pre = obj.pre || '';
1295 this.post = obj.post || '';
1296 this.tags = {};
1297 this.prev = null;
1298 this.next = null;
1299 this.id = _id(obj.clean);
1300 this.isA = 'Term'; // easier than .constructor...
1301 // support alternative matches
1302
1303 if (obj.alias) {
1304 this.alias = obj.alias;
1305 }
1306 }
1307 /** set the text of the Term to something else*/
1308
1309
1310 _createClass(Term, [{
1311 key: "set",
1312 value: function set(str) {
1313 var obj = parse(str);
1314 this.text = obj.text;
1315 this.clean = obj.clean;
1316 return this;
1317 }
1318 }]);
1319
1320 return Term;
1321}();
1322/** create a deep-copy of this term */
1323
1324
1325Term.prototype.clone = function () {
1326 var term = new Term(this.text);
1327 term.pre = this.pre;
1328 term.post = this.post;
1329 term.clean = this.clean;
1330 term.reduced = this.reduced;
1331 term.root = this.root;
1332 term.implicit = this.implicit;
1333 term.tags = Object.assign({}, this.tags); //use the old id, so it can be matched with .match(doc)
1334 // term.id = this.id
1335
1336 return term;
1337};
1338
1339Object.assign(Term.prototype, methods);
1340Object.assign(Term.prototype, tag);
1341var Term_1 = Term;
1342
1343/** return a flat array of Term objects */
1344var terms = function terms(n) {
1345 if (this.length === 0) {
1346 return [];
1347 } // use cache, if it exists
1348
1349
1350 if (this.cache.terms) {
1351 if (n !== undefined) {
1352 return this.cache.terms[n];
1353 }
1354
1355 return this.cache.terms;
1356 }
1357
1358 var terms = [this.pool.get(this.start)];
1359
1360 for (var i = 0; i < this.length - 1; i += 1) {
1361 var id = terms[terms.length - 1].next;
1362
1363 if (id === null) {
1364 // throw new Error('linked-list broken')
1365 console.error("Compromise error: Linked list broken in phrase '" + this.start + "'");
1366 break;
1367 }
1368
1369 var term = this.pool.get(id);
1370 terms.push(term); //return this one?
1371
1372 if (n !== undefined && n === i) {
1373 return terms[n];
1374 }
1375 }
1376
1377 if (n === undefined) {
1378 this.cache.terms = terms;
1379 }
1380
1381 if (n !== undefined) {
1382 return terms[n];
1383 }
1384
1385 return terms;
1386};
1387/** return a shallow or deep copy of this phrase */
1388
1389
1390var clone = function clone(isShallow) {
1391 var _this = this;
1392
1393 if (isShallow) {
1394 var p = this.buildFrom(this.start, this.length);
1395 p.cache = this.cache;
1396 return p;
1397 } //how do we clone part of the pool?
1398
1399
1400 var terms = this.terms();
1401 var newTerms = terms.map(function (t) {
1402 return t.clone();
1403 }); // console.log(newTerms)
1404 //connect these new ids up
1405
1406 newTerms.forEach(function (t, i) {
1407 //add it to the pool..
1408 _this.pool.add(t);
1409
1410 if (newTerms[i + 1]) {
1411 t.next = newTerms[i + 1].id;
1412 }
1413
1414 if (newTerms[i - 1]) {
1415 t.prev = newTerms[i - 1].id;
1416 }
1417 });
1418 return this.buildFrom(newTerms[0].id, newTerms.length);
1419};
1420/** return last term object */
1421
1422
1423var lastTerm = function lastTerm() {
1424 var terms = this.terms();
1425 return terms[terms.length - 1];
1426};
1427/** quick lookup for a term id */
1428
1429
1430var hasId = function hasId(wantId) {
1431 if (this.length === 0 || !wantId) {
1432 return false;
1433 }
1434
1435 if (this.start === wantId) {
1436 return true;
1437 } // use cache, if available
1438
1439
1440 if (this.cache.terms) {
1441 var _terms = this.cache.terms;
1442
1443 for (var i = 0; i < _terms.length; i++) {
1444 if (_terms[i].id === wantId) {
1445 return true;
1446 }
1447 }
1448
1449 return false;
1450 } // otherwise, go through each term
1451
1452
1453 var lastId = this.start;
1454
1455 for (var _i = 0; _i < this.length - 1; _i += 1) {
1456 var term = this.pool.get(lastId);
1457
1458 if (term === undefined) {
1459 console.error("Compromise error: Linked list broken. Missing term '".concat(lastId, "' in phrase '").concat(this.start, "'\n")); // throw new Error('linked List error')
1460
1461 return false;
1462 }
1463
1464 if (term.next === wantId) {
1465 return true;
1466 }
1467
1468 lastId = term.next;
1469 }
1470
1471 return false;
1472};
1473/** how many seperate, non-empty words is it? */
1474
1475
1476var wordCount = function wordCount() {
1477 return this.terms().filter(function (t) {
1478 return t.text !== '';
1479 }).length;
1480};
1481/** get the full-sentence this phrase belongs to */
1482
1483
1484var fullSentence = function fullSentence() {
1485 var t = this.terms(0); //find first term in sentence
1486
1487 while (t.prev) {
1488 t = this.pool.get(t.prev);
1489 }
1490
1491 var start = t.id;
1492 var len = 1; //go to end of sentence
1493
1494 while (t.next) {
1495 t = this.pool.get(t.next);
1496 len += 1;
1497 }
1498
1499 return this.buildFrom(start, len);
1500};
1501
1502var _01Utils = {
1503 terms: terms,
1504 clone: clone,
1505 lastTerm: lastTerm,
1506 hasId: hasId,
1507 wordCount: wordCount,
1508 fullSentence: fullSentence
1509};
1510
1511var trimEnd = function trimEnd(str) {
1512 return str.replace(/ +$/, '');
1513};
1514/** produce output in the given format */
1515
1516
1517var text = function text() {
1518 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1519 var isFirst = arguments.length > 1 ? arguments[1] : undefined;
1520 var isLast = arguments.length > 2 ? arguments[2] : undefined;
1521
1522 if (typeof options === 'string') {
1523 if (options === 'normal') {
1524 options = {
1525 whitespace: true,
1526 unicode: true,
1527 lowercase: true,
1528 punctuation: true,
1529 acronyms: true,
1530 abbreviations: true,
1531 implicit: true,
1532 normal: true
1533 };
1534 } else if (options === 'clean') {
1535 options = {
1536 titlecase: false,
1537 lowercase: true,
1538 punctuation: true,
1539 whitespace: true,
1540 unicode: true,
1541 implicit: true,
1542 normal: true
1543 };
1544 } else if (options === 'reduced') {
1545 options = {
1546 punctuation: false,
1547 //Hmm: is this reversed?
1548 titlecase: false,
1549 lowercase: true,
1550 whitespace: true,
1551 unicode: true,
1552 implicit: true,
1553 reduced: true
1554 };
1555 } else if (options === 'root') {
1556 options = {
1557 titlecase: false,
1558 lowercase: true,
1559 punctuation: true,
1560 whitespace: true,
1561 unicode: true,
1562 implicit: true,
1563 root: true
1564 };
1565 } else {
1566 options = {};
1567 }
1568 }
1569
1570 var terms = this.terms(); //this this phrase a complete sentence?
1571
1572 var isFull = false;
1573
1574 if (terms[0] && terms[0].prev === null && terms[terms.length - 1].next === null) {
1575 isFull = true;
1576 }
1577
1578 var text = terms.reduce(function (str, t, i) {
1579 options.last = isLast && i === terms.length - 1;
1580 var showPre = true;
1581 var showPost = true;
1582
1583 if (isFull === false) {
1584 // dont show beginning whitespace
1585 if (i === 0 && isFirst) {
1586 showPre = false;
1587 } // dont show end-whitespace
1588
1589
1590 if (i === terms.length - 1 && isLast) {
1591 showPost = false;
1592 }
1593 }
1594
1595 var txt = t.textOut(options, showPre, showPost); // if (options.titlecase && i === 0) {
1596 // txt = titleCase(txt)
1597 // }
1598
1599 return str + txt;
1600 }, ''); //full-phrases show punctuation, but not whitespace
1601
1602 if (isFull === true && isLast) {
1603 text = trimEnd(text);
1604 }
1605
1606 if (options.trim === true) {
1607 text = text.trim();
1608 }
1609
1610 return text;
1611};
1612
1613var _02Text = {
1614 text: text
1615};
1616
1617/** remove start and end whitespace */
1618var trim = function trim() {
1619 var terms = this.terms();
1620
1621 if (terms.length > 0) {
1622 //trim starting
1623 terms[0].pre = terms[0].pre.replace(/^\s+/, ''); //trim ending
1624
1625 var lastTerm = terms[terms.length - 1];
1626 lastTerm.post = lastTerm.post.replace(/\s+$/, '');
1627 }
1628
1629 return this;
1630};
1631
1632var _03Change = {
1633 trim: trim
1634};
1635
1636var endOfSentence = /[.?!]\s*$/; // replacing a 'word.' with a 'word!'
1637
1638var combinePost = function combinePost(before, after) {
1639 //only transfer the whitespace
1640 if (endOfSentence.test(after)) {
1641 var whitespace = before.match(/\s*$/);
1642 return after + whitespace;
1643 }
1644
1645 return before;
1646}; //add whitespace to the start of the second bit
1647
1648
1649var addWhitespace = function addWhitespace(beforeTerms, newTerms) {
1650 // add any existing pre-whitespace to beginning
1651 newTerms[0].pre = beforeTerms[0].pre;
1652 var lastTerm = beforeTerms[beforeTerms.length - 1]; //add any existing punctuation to end of our new terms
1653
1654 var newTerm = newTerms[newTerms.length - 1];
1655 newTerm.post = combinePost(lastTerm.post, newTerm.post); // remove existing punctuation
1656
1657 lastTerm.post = ''; //before ←[space] - after
1658
1659 if (lastTerm.post === '') {
1660 lastTerm.post += ' ';
1661 }
1662}; //insert this segment into the linked-list
1663
1664
1665var stitchIn = function stitchIn(beforeTerms, newTerms, pool) {
1666 var lastBefore = beforeTerms[beforeTerms.length - 1];
1667 var lastNew = newTerms[newTerms.length - 1];
1668 var afterId = lastBefore.next; //connect ours in (main → newPhrase)
1669
1670 lastBefore.next = newTerms[0].id; //stich the end in (newPhrase → after)
1671
1672 lastNew.next = afterId; //do it backwards, too
1673
1674 if (afterId) {
1675 // newPhrase ← after
1676 var afterTerm = pool.get(afterId);
1677 afterTerm.prev = lastNew.id;
1678 } // before ← newPhrase
1679
1680
1681 var beforeId = beforeTerms[0].id;
1682
1683 if (beforeId) {
1684 var newTerm = newTerms[0];
1685 newTerm.prev = beforeId;
1686 }
1687}; // avoid stretching a phrase twice.
1688
1689
1690var unique = function unique(list) {
1691 return list.filter(function (o, i) {
1692 return list.indexOf(o) === i;
1693 });
1694}; //append one phrase onto another.
1695
1696
1697var appendPhrase = function appendPhrase(before, newPhrase, doc) {
1698 var beforeTerms = before.terms();
1699 var newTerms = newPhrase.terms(); //spruce-up the whitespace issues
1700
1701 addWhitespace(beforeTerms, newTerms); //insert this segment into the linked-list
1702
1703 stitchIn(beforeTerms, newTerms, before.pool); // stretch!
1704 // make each effected phrase longer
1705
1706 var toStretch = [before];
1707 var hasId = before.start;
1708 var docs = [doc];
1709 docs = docs.concat(doc.parents()); // find them all!
1710
1711 docs.forEach(function (parent) {
1712 // only the phrases that should change
1713 var shouldChange = parent.list.filter(function (p) {
1714 return p.hasId(hasId);
1715 });
1716 toStretch = toStretch.concat(shouldChange);
1717 }); // don't double-count a phrase
1718
1719 toStretch = unique(toStretch);
1720 toStretch.forEach(function (p) {
1721 p.length += newPhrase.length;
1722 });
1723 before.cache = {};
1724 return before;
1725};
1726
1727var append = appendPhrase;
1728
1729var hasSpace$1 = / /; //a new space needs to be added, either on the new phrase, or the old one
1730// '[new] [◻old]' -or- '[old] [◻new] [old]'
1731
1732var addWhitespace$1 = function addWhitespace(newTerms) {
1733 //add a space before our new text?
1734 // add a space after our text
1735 var lastTerm = newTerms[newTerms.length - 1];
1736
1737 if (hasSpace$1.test(lastTerm.post) === false) {
1738 lastTerm.post += ' ';
1739 }
1740
1741 return;
1742}; //insert this segment into the linked-list
1743
1744
1745var stitchIn$1 = function stitchIn(main, newPhrase, newTerms) {
1746 // [newPhrase] → [main]
1747 var lastTerm = newTerms[newTerms.length - 1];
1748 lastTerm.next = main.start; // [before] → [main]
1749
1750 var pool = main.pool;
1751 var start = pool.get(main.start);
1752
1753 if (start.prev) {
1754 var before = pool.get(start.prev);
1755 before.next = newPhrase.start;
1756 } //do it backwards, too
1757 // before ← newPhrase
1758
1759
1760 newTerms[0].prev = main.terms(0).prev; // newPhrase ← main
1761
1762 main.terms(0).prev = lastTerm.id;
1763};
1764
1765var unique$1 = function unique(list) {
1766 return list.filter(function (o, i) {
1767 return list.indexOf(o) === i;
1768 });
1769}; //append one phrase onto another
1770
1771
1772var joinPhrase = function joinPhrase(original, newPhrase, doc) {
1773 var starterId = original.start;
1774 var newTerms = newPhrase.terms(); //spruce-up the whitespace issues
1775
1776 addWhitespace$1(newTerms); //insert this segment into the linked-list
1777
1778 stitchIn$1(original, newPhrase, newTerms); //increase the length of our phrases
1779
1780 var toStretch = [original];
1781 var docs = [doc];
1782 docs = docs.concat(doc.parents());
1783 docs.forEach(function (d) {
1784 // only the phrases that should change
1785 var shouldChange = d.list.filter(function (p) {
1786 return p.hasId(starterId) || p.hasId(newPhrase.start);
1787 });
1788 toStretch = toStretch.concat(shouldChange);
1789 }); // don't double-count
1790
1791 toStretch = unique$1(toStretch); // stretch these phrases
1792
1793 toStretch.forEach(function (p) {
1794 p.length += newPhrase.length; // change the start too, if necessary
1795
1796 if (p.start === starterId) {
1797 p.start = newPhrase.start;
1798 }
1799
1800 p.cache = {};
1801 });
1802 return original;
1803};
1804
1805var prepend = joinPhrase;
1806
1807//recursively decrease the length of all the parent phrases
1808var shrinkAll = function shrinkAll(doc, id, deleteLength, after) {
1809 var arr = doc.parents();
1810 arr.push(doc);
1811 arr.forEach(function (d) {
1812 //find our phrase to shrink
1813 var phrase = d.list.find(function (p) {
1814 return p.hasId(id);
1815 });
1816
1817 if (!phrase) {
1818 return;
1819 }
1820
1821 phrase.length -= deleteLength; // does it start with this soon-removed word?
1822
1823 if (phrase.start === id) {
1824 phrase.start = after.id;
1825 }
1826
1827 phrase.cache = {};
1828 }); // cleanup empty phrase objects
1829
1830 doc.list = doc.list.filter(function (p) {
1831 if (!p.start || !p.length) {
1832 return false;
1833 }
1834
1835 return true;
1836 });
1837};
1838/** wrap the linked-list around these terms
1839 * so they don't appear any more
1840 */
1841
1842
1843var deletePhrase = function deletePhrase(phrase, doc) {
1844 var pool = doc.pool();
1845 var terms = phrase.terms(); //grab both sides of the chain,
1846
1847 var prev = pool.get(terms[0].prev) || {};
1848 var after = pool.get(terms[terms.length - 1].next) || {};
1849
1850 if (terms[0].implicit && prev.implicit) {
1851 prev.set(prev.implicit);
1852 prev.post += ' ';
1853 } // //first, change phrase lengths
1854
1855
1856 shrinkAll(doc, phrase.start, phrase.length, after); // connect [prev]->[after]
1857
1858 if (prev) {
1859 prev.next = after.id;
1860 } // connect [prev]<-[after]
1861
1862
1863 if (after) {
1864 after.prev = prev.id;
1865 } // lastly, actually delete the terms from the pool?
1866 // for (let i = 0; i < terms.length; i++) {
1867 // pool.remove(terms[i].id)
1868 // }
1869
1870};
1871
1872var _delete = deletePhrase;
1873
1874/** put this text at the end */
1875
1876var append_1 = function append_1(newPhrase, doc) {
1877 append(this, newPhrase, doc);
1878 return this;
1879};
1880/** add this text to the beginning */
1881
1882
1883var prepend_1 = function prepend_1(newPhrase, doc) {
1884 prepend(this, newPhrase, doc);
1885 return this;
1886};
1887
1888var _delete$1 = function _delete$1(doc) {
1889 _delete(this, doc);
1890 return this;
1891}; // stich-in newPhrase, stretch 'doc' + parents
1892
1893
1894var replace = function replace(newPhrase, doc) {
1895 //add it do the end
1896 var firstLength = this.length;
1897 append(this, newPhrase, doc); //delete original terms
1898
1899 var tmp = this.buildFrom(this.start, this.length);
1900 tmp.length = firstLength;
1901 _delete(tmp, doc);
1902};
1903/**
1904 * Turn this phrase object into 3 phrase objects
1905 */
1906
1907
1908var splitOn = function splitOn(p) {
1909 var terms = this.terms();
1910 var result = {
1911 before: null,
1912 match: null,
1913 after: null
1914 };
1915 var index = terms.findIndex(function (t) {
1916 return t.id === p.start;
1917 });
1918
1919 if (index === -1) {
1920 return result;
1921 } //make all three sections into phrase-objects
1922
1923
1924 var start = terms.slice(0, index);
1925
1926 if (start.length > 0) {
1927 result.before = this.buildFrom(start[0].id, start.length);
1928 }
1929
1930 var match = terms.slice(index, index + p.length);
1931
1932 if (match.length > 0) {
1933 result.match = this.buildFrom(match[0].id, match.length);
1934 }
1935
1936 var end = terms.slice(index + p.length, terms.length);
1937
1938 if (end.length > 0) {
1939 result.after = this.buildFrom(end[0].id, end.length, this.pool);
1940 }
1941
1942 return result;
1943};
1944
1945var _04Insert = {
1946 append: append_1,
1947 prepend: prepend_1,
1948 "delete": _delete$1,
1949 replace: replace,
1950 splitOn: splitOn
1951};
1952
1953/** return json metadata for this phrase */
1954var json$1 = function json() {
1955 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1956 var world = arguments.length > 1 ? arguments[1] : undefined;
1957 var res = {}; // text data
1958
1959 if (options.text) {
1960 res.text = this.text();
1961 }
1962
1963 if (options.normal) {
1964 res.normal = this.text('normal');
1965 }
1966
1967 if (options.clean) {
1968 res.clean = this.text('clean');
1969 }
1970
1971 if (options.reduced) {
1972 res.reduced = this.text('reduced');
1973 }
1974
1975 if (options.root) {
1976 res.root = this.text('root');
1977 }
1978
1979 if (options.trim) {
1980 if (res.text) {
1981 res.text = res.text.trim();
1982 }
1983
1984 if (res.normal) {
1985 res.normal = res.normal.trim();
1986 }
1987
1988 if (res.reduced) {
1989 res.reduced = res.reduced.trim();
1990 }
1991 } // terms data
1992
1993
1994 if (options.terms) {
1995 if (options.terms === true) {
1996 options.terms = {};
1997 }
1998
1999 res.terms = this.terms().map(function (t) {
2000 return t.json(options.terms, world);
2001 });
2002 }
2003
2004 return res;
2005};
2006
2007var _05Json$1 = {
2008 json: json$1
2009};
2010
2011/** match any terms after this phrase */
2012var lookAhead = function lookAhead(regs) {
2013 // if empty match string, return everything after
2014 if (!regs) {
2015 regs = '.*';
2016 }
2017
2018 var pool = this.pool; // get a list of all terms preceding our start
2019
2020 var terms = [];
2021
2022 var getAfter = function getAfter(id) {
2023 var term = pool.get(id);
2024
2025 if (!term) {
2026 return;
2027 }
2028
2029 terms.push(term);
2030
2031 if (term.prev) {
2032 getAfter(term.next); //recursion
2033 }
2034 };
2035
2036 var all = this.terms();
2037 var lastTerm = all[all.length - 1];
2038 getAfter(lastTerm.next);
2039
2040 if (terms.length === 0) {
2041 return [];
2042 } // got the terms, make a phrase from them
2043
2044
2045 var p = this.buildFrom(terms[0].id, terms.length);
2046 return p.match(regs);
2047};
2048/** match any terms before this phrase */
2049
2050
2051var lookBehind = function lookBehind(regs) {
2052 // if empty match string, return everything before
2053 if (!regs) {
2054 regs = '.*';
2055 }
2056
2057 var pool = this.pool; // get a list of all terms preceding our start
2058
2059 var terms = [];
2060
2061 var getBefore = function getBefore(id) {
2062 var term = pool.get(id);
2063
2064 if (!term) {
2065 return;
2066 }
2067
2068 terms.push(term);
2069
2070 if (term.prev) {
2071 getBefore(term.prev); //recursion
2072 }
2073 };
2074
2075 var term = pool.get(this.start);
2076 getBefore(term.prev);
2077
2078 if (terms.length === 0) {
2079 return [];
2080 } // got the terms, make a phrase from them
2081
2082
2083 var p = this.buildFrom(terms[terms.length - 1].id, terms.length);
2084 return p.match(regs);
2085};
2086
2087var _06Lookahead = {
2088 lookAhead: lookAhead,
2089 lookBehind: lookBehind
2090};
2091
2092var methods$1 = Object.assign({}, _01Utils, _02Text, _03Change, _04Insert, _05Json$1, _06Lookahead);
2093
2094// try to avoid doing the match
2095var failFast = function failFast(p, regs) {
2096 if (regs.length === 0) {
2097 return true;
2098 }
2099
2100 for (var i = 0; i < regs.length; i += 1) {
2101 var reg = regs[i]; //logical quick-ones
2102
2103 if (reg.optional !== true && reg.negative !== true) {
2104 //start/end impossibilites
2105 if (reg.start === true && i > 0) {
2106 return true;
2107 }
2108 } //this is not possible
2109
2110
2111 if (reg.anything === true && reg.negative === true) {
2112 return true;
2113 }
2114 }
2115
2116 return false;
2117};
2118
2119var _02FailFast = failFast;
2120
2121var _matchLogic = createCommonjsModule(function (module, exports) {
2122 //found a match? it's greedy? keep going!
2123 exports.getGreedy = function (state, endReg) {
2124 // for greedy checking, we no longer care about the reg.start
2125 // value, and leaving it can cause failures for anchored greedy
2126 // matches. ditto for end-greedy matches: we need an earlier non-
2127 // ending match to succceed until we get to the actual end.
2128 var reg = Object.assign({}, state.regs[state.r], {
2129 start: false,
2130 end: false
2131 });
2132 var start = state.t;
2133
2134 for (; state.t < state.terms.length; state.t += 1) {
2135 //stop for next-reg match
2136 if (endReg && state.terms[state.t].doesMatch(endReg, state.start_i + state.t, state.phrase_length)) {
2137 return state.t;
2138 }
2139
2140 var count = state.t - start + 1; // is it max-length now?
2141
2142 if (reg.max !== undefined && count === reg.max) {
2143 return state.t;
2144 } //stop here
2145
2146
2147 if (state.terms[state.t].doesMatch(reg, state.start_i + state.t, state.phrase_length) === false) {
2148 // is it too short?
2149 if (reg.min !== undefined && count < reg.min) {
2150 return null;
2151 }
2152
2153 return state.t;
2154 }
2155 }
2156
2157 return state.t;
2158 }; //'unspecific greedy' is a weird situation.
2159
2160
2161 exports.greedyTo = function (state, nextReg) {
2162 var t = state.t; //if there's no next one, just go off the end!
2163
2164 if (!nextReg) {
2165 return state.terms.length;
2166 } //otherwise, we're looking for the next one
2167
2168
2169 for (; t < state.terms.length; t += 1) {
2170 if (state.terms[t].doesMatch(nextReg, state.start_i + t, state.phrase_length) === true) {
2171 return t;
2172 }
2173 } //guess it doesn't exist, then.
2174
2175
2176 return null;
2177 }; //we have a special case where an end-anchored greedy match may need to
2178 //start matching before the actual end; we do this by (temporarily!)
2179 //removing the "end" property from the matching token... since this is
2180 //very situation-specific, we *only* do this when we really need to.
2181
2182
2183 exports.isEndGreedy = function (reg, state) {
2184 if (reg.end === true && reg.greedy === true) {
2185 if (state.start_i + state.t < state.phrase_length - 1) {
2186 var tmpReg = Object.assign({}, reg, {
2187 end: false
2188 });
2189
2190 if (state.terms[state.t].doesMatch(tmpReg, state.start_i + state.t, state.phrase_length) === true) {
2191 return true;
2192 }
2193 }
2194 }
2195
2196 if (state.terms[state.t].doesMatch(reg, state.start_i + state.t, state.phrase_length) === true) {
2197 return true;
2198 }
2199
2200 return false;
2201 }; // match complex OR cases like (a|b|foo bar)
2202
2203
2204 exports.doOrBlock = function (state) {
2205 var skipN = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
2206 var reg = state.regs[state.r];
2207 var wasFound = false; // do each multiword sequence
2208
2209 for (var c = 0; c < reg.choices.length; c += 1) {
2210 // try to match this list of tokens
2211 var block = reg.choices[c];
2212 wasFound = block.every(function (cr, w_index) {
2213 var tryTerm = state.t + w_index + skipN;
2214
2215 if (state.terms[tryTerm] === undefined) {
2216 return false;
2217 }
2218
2219 return state.terms[tryTerm].doesMatch(cr, tryTerm + state.start_i, state.phrase_length);
2220 });
2221
2222 if (wasFound) {
2223 skipN += block.length;
2224 break;
2225 }
2226 } // we found a match - is it greedy though?
2227
2228
2229 if (wasFound && reg.greedy === true) {
2230 return exports.doOrBlock(state, skipN); // try it again!
2231 }
2232
2233 return skipN;
2234 }; // match AND cases like (#Noun && foo)
2235
2236
2237 exports.doAndBlock = function (state) {
2238 var longest = 0; // all blocks must match, and we return the greediest match
2239
2240 var reg = state.regs[state.r];
2241 var allDidMatch = reg.choices.every(function (block) {
2242 // for multi-word blocks, all must match
2243 var allWords = block.every(function (cr, w_index) {
2244 var tryTerm = state.t + w_index;
2245
2246 if (state.terms[tryTerm] === undefined) {
2247 return false;
2248 }
2249
2250 return state.terms[tryTerm].doesMatch(cr, tryTerm, state.phrase_length);
2251 });
2252
2253 if (allWords === true && block.length > longest) {
2254 longest = block.length;
2255 }
2256
2257 return allWords;
2258 });
2259
2260 if (allDidMatch === true) {
2261 return longest;
2262 }
2263
2264 return false;
2265 }; // get or create named group
2266
2267
2268 exports.getGroup = function (state, term_index, name) {
2269 if (state.groups[state.groupId]) {
2270 return state.groups[state.groupId];
2271 }
2272
2273 var termId = state.terms[term_index].id;
2274 state.groups[state.groupId] = {
2275 group: String(name),
2276 start: termId,
2277 length: 0
2278 };
2279 return state.groups[state.groupId];
2280 };
2281});
2282
2283/** tries to match a sequence of terms, starting from here */
2284
2285var tryHere = function tryHere(terms, regs, start_i, phrase_length) {
2286 // all the variables that matter
2287 var state = {
2288 t: 0,
2289 //the term index we're on
2290 terms: terms,
2291 //the working slice of term objects
2292 r: 0,
2293 // the reg index we're on
2294 regs: regs,
2295 //our match conditions
2296 groups: {},
2297 //all named-group matches
2298 start_i: start_i,
2299 // term index we're starting from
2300 phrase_length: phrase_length,
2301 // # of terms in the sentence
2302 hasGroup: false,
2303 groupId: null,
2304 previousGroup: null
2305 }; // we must satisfy each rule in 'regs'
2306
2307 for (; state.r < regs.length; state.r += 1) {
2308 var reg = regs[state.r]; // Check if this reg has a named capture group
2309
2310 state.hasGroup = typeof reg.named === 'string' || typeof reg.named === 'number'; // Reuse previous capture group if same
2311
2312 if (state.hasGroup === true) {
2313 var prev = regs[state.r - 1];
2314
2315 if (prev && prev.named === reg.named && state.previousGroup) {
2316 state.groupId = state.previousGroup;
2317 } else {
2318 state.groupId = _id(reg.named);
2319 state.previousGroup = state.groupId;
2320 }
2321 } //hve we run-out of terms?
2322
2323
2324 if (!state.terms[state.t]) {
2325 //are all remaining regs optional?
2326 var haveNeeds = regs.slice(state.r).some(function (remain) {
2327 return !remain.optional;
2328 });
2329
2330 if (haveNeeds === false) {
2331 break; //done!
2332 }
2333
2334 return null; // die
2335 } //support 'unspecific greedy' .* properly
2336
2337
2338 if (reg.anything === true && reg.greedy === true) {
2339 var skipto = _matchLogic.greedyTo(state, regs[state.r + 1]); // ensure it's long enough
2340
2341 if (reg.min !== undefined && skipto - state.t < reg.min) {
2342 return null;
2343 } // reduce it back, if it's too long
2344
2345
2346 if (reg.max !== undefined && skipto - state.t > reg.max) {
2347 state.t = state.t + reg.max;
2348 continue;
2349 }
2350
2351 if (skipto === null) {
2352 return null; //couldn't find it
2353 } // is it really this easy?....
2354
2355
2356 if (state.hasGroup === true) {
2357 var g = _matchLogic.getGroup(state, state.t, reg.named);
2358 g.length = skipto - state.t;
2359 }
2360
2361 state.t = skipto;
2362 continue;
2363 } // support multi-word OR (a|b|foo bar)
2364
2365
2366 if (reg.choices !== undefined && reg.operator === 'or') {
2367 var skipNum = _matchLogic.doOrBlock(state);
2368
2369 if (skipNum) {
2370 // handle 'not' logic
2371 if (reg.negative === true) {
2372 return null; // die
2373 }
2374
2375 if (state.hasGroup === true) {
2376 var _g = _matchLogic.getGroup(state, state.t, reg.named);
2377
2378 _g.length += skipNum;
2379 }
2380
2381 state.t += skipNum;
2382 continue;
2383 } else if (!reg.optional) {
2384 return null; //die
2385 }
2386 } // support AND (#Noun && foo) blocks
2387
2388
2389 if (reg.choices !== undefined && reg.operator === 'and') {
2390 var _skipNum = _matchLogic.doAndBlock(state);
2391
2392 if (_skipNum) {
2393 // handle 'not' logic
2394 if (reg.negative === true) {
2395 return null; // die
2396 }
2397
2398 if (state.hasGroup === true) {
2399 var _g2 = _matchLogic.getGroup(state, state.t, reg.named);
2400
2401 _g2.length += _skipNum;
2402 }
2403
2404 state.t += _skipNum;
2405 continue;
2406 } else if (!reg.optional) {
2407 return null; //die
2408 }
2409 }
2410
2411 if (reg.anything === true || _matchLogic.isEndGreedy(reg, state)) {
2412 var startAt = state.t; // okay, it was a match, but if it optional too,
2413 // we should check the next reg too, to skip it?
2414
2415 if (reg.optional && regs[state.r + 1]) {
2416 // does the next reg match it too?
2417 if (state.terms[state.t].doesMatch(regs[state.r + 1], state.start_i + state.t, state.phrase_length)) {
2418 // but does the next reg match the next term??
2419 // only skip if it doesn't
2420 if (!state.terms[state.t + 1] || !state.terms[state.t + 1].doesMatch(regs[state.r + 1], state.start_i + state.t, state.phrase_length)) {
2421 state.r += 1;
2422 }
2423 }
2424 } //advance to the next term!
2425
2426
2427 state.t += 1; //check any ending '$' flags
2428
2429 if (reg.end === true) {
2430 //if this isn't the last term, refuse the match
2431 if (state.t !== state.terms.length && reg.greedy !== true) {
2432 return null; //die
2433 }
2434 } //try keep it going!
2435
2436
2437 if (reg.greedy === true) {
2438 state.t = _matchLogic.getGreedy(state, regs[state.r + 1]);
2439
2440 if (state.t === null) {
2441 return null; //greedy was too short
2442 }
2443
2444 if (reg.min && reg.min > state.t) {
2445 return null; //greedy was too short
2446 } // if this was also an end-anchor match, check to see we really
2447 // reached the end
2448
2449
2450 if (reg.end === true && state.start_i + state.t !== phrase_length) {
2451 return null; //greedy didn't reach the end
2452 }
2453 }
2454
2455 if (state.hasGroup === true) {
2456 // Get or create capture group
2457 var _g3 = _matchLogic.getGroup(state, startAt, reg.named); // Update group - add greedy or increment length
2458
2459
2460 if (state.t > 1 && reg.greedy) {
2461 _g3.length += state.t - startAt;
2462 } else {
2463 _g3.length++;
2464 }
2465 }
2466
2467 continue;
2468 } //bah, who cares, keep going
2469
2470
2471 if (reg.optional === true) {
2472 continue;
2473 } // should we skip-over an implicit word?
2474
2475
2476 if (state.terms[state.t].isImplicit() && regs[state.r - 1] && state.terms[state.t + 1]) {
2477 // does the next one match?
2478 if (state.terms[state.t + 1].doesMatch(reg, state.start_i + state.t, state.phrase_length)) {
2479 state.t += 2;
2480 continue;
2481 }
2482 }
2483
2484 return null; //die
2485 } //return our result
2486
2487
2488 return {
2489 match: state.terms.slice(0, state.t),
2490 groups: state.groups
2491 };
2492};
2493
2494var _03TryMatch = tryHere;
2495
2496// final checks on the validity of our results
2497var postProcess = function postProcess(terms, regs, matches) {
2498 if (!matches || matches.length === 0) {
2499 return matches;
2500 } // ensure end reg has the end term
2501
2502
2503 var atEnd = regs.some(function (r) {
2504 return r.end;
2505 });
2506
2507 if (atEnd) {
2508 var lastTerm = terms[terms.length - 1];
2509 matches = matches.filter(function (_ref) {
2510 var arr = _ref.match;
2511 return arr.indexOf(lastTerm) !== -1;
2512 });
2513 }
2514
2515 return matches;
2516};
2517
2518var _04PostProcess = postProcess;
2519
2520/* break-down a match expression into this:
2521{
2522 word:'',
2523 tag:'',
2524 regex:'',
2525
2526 start:false,
2527 end:false,
2528 negative:false,
2529 anything:false,
2530 greedy:false,
2531 optional:false,
2532
2533 named:'',
2534 choices:[],
2535}
2536*/
2537var hasMinMax = /\{([0-9]+,?[0-9]*)\}/;
2538var andSign = /&&/;
2539var captureName = new RegExp(/^<(\S+)>/);
2540
2541var titleCase$2 = function titleCase(str) {
2542 return str.charAt(0).toUpperCase() + str.substr(1);
2543};
2544
2545var end = function end(str) {
2546 return str[str.length - 1];
2547};
2548
2549var start = function start(str) {
2550 return str[0];
2551};
2552
2553var stripStart = function stripStart(str) {
2554 return str.substr(1);
2555};
2556
2557var stripEnd = function stripEnd(str) {
2558 return str.substr(0, str.length - 1);
2559};
2560
2561var stripBoth = function stripBoth(str) {
2562 str = stripStart(str);
2563 str = stripEnd(str);
2564 return str;
2565}; //
2566
2567
2568var parseToken = function parseToken(w) {
2569 var obj = {}; //collect any flags (do it twice)
2570
2571 for (var i = 0; i < 2; i += 1) {
2572 //end-flag
2573 if (end(w) === '$') {
2574 obj.end = true;
2575 w = stripEnd(w);
2576 } //front-flag
2577
2578
2579 if (start(w) === '^') {
2580 obj.start = true;
2581 w = stripStart(w);
2582 } //capture group (this one can span multiple-terms)
2583
2584
2585 if (start(w) === '[' || end(w) === ']') {
2586 obj.named = true;
2587
2588 if (start(w) === '[') {
2589 obj.groupType = end(w) === ']' ? 'single' : 'start';
2590 } else {
2591 obj.groupType = 'end';
2592 }
2593
2594 w = w.replace(/^\[/, '');
2595 w = w.replace(/\]$/, ''); // Use capture group name
2596
2597 if (start(w) === '<') {
2598 var res = captureName.exec(w);
2599
2600 if (res.length >= 2) {
2601 obj.named = res[1];
2602 w = w.replace(res[0], '');
2603 }
2604 }
2605 } //back-flags
2606
2607
2608 if (end(w) === '+') {
2609 obj.greedy = true;
2610 w = stripEnd(w);
2611 }
2612
2613 if (w !== '*' && end(w) === '*' && w !== '\\*') {
2614 obj.greedy = true;
2615 w = stripEnd(w);
2616 }
2617
2618 if (end(w) === '?') {
2619 obj.optional = true;
2620 w = stripEnd(w);
2621 }
2622
2623 if (start(w) === '!') {
2624 obj.negative = true; // obj.optional = true
2625
2626 w = stripStart(w);
2627 } //wrapped-flags
2628
2629
2630 if (start(w) === '(' && end(w) === ')') {
2631 // support (one && two)
2632 if (andSign.test(w)) {
2633 obj.choices = w.split(andSign);
2634 obj.operator = 'and';
2635 } else {
2636 obj.choices = w.split('|');
2637 obj.operator = 'or';
2638 } //remove '(' and ')'
2639
2640
2641 obj.choices[0] = stripStart(obj.choices[0]);
2642 var last = obj.choices.length - 1;
2643 obj.choices[last] = stripEnd(obj.choices[last]); // clean up the results
2644
2645 obj.choices = obj.choices.map(function (s) {
2646 return s.trim();
2647 });
2648 obj.choices = obj.choices.filter(function (s) {
2649 return s;
2650 }); //recursion alert!
2651
2652 obj.choices = obj.choices.map(function (str) {
2653 return str.split(/ /g).map(parseToken);
2654 });
2655 w = '';
2656 } //regex
2657
2658
2659 if (start(w) === '/' && end(w) === '/') {
2660 w = stripBoth(w);
2661 obj.regex = new RegExp(w); //potential vuln - security/detect-non-literal-regexp
2662
2663 return obj;
2664 } //soft-match
2665
2666
2667 if (start(w) === '~' && end(w) === '~') {
2668 w = stripBoth(w);
2669 obj.soft = true;
2670 obj.word = w;
2671 return obj;
2672 }
2673 } // support #Tag{1,9}
2674
2675
2676 if (hasMinMax.test(w) === true) {
2677 w = w.replace(hasMinMax, function (a, b) {
2678 var arr = b.split(/,/g);
2679
2680 if (arr.length === 1) {
2681 // '{3}' Exactly three times
2682 obj.min = Number(arr[0]);
2683 obj.max = Number(arr[0]);
2684 } else {
2685 // '{2,4}' Two to four times
2686 // '{3,}' Three or more times
2687 obj.min = Number(arr[0]);
2688 obj.max = Number(arr[1] || 999);
2689 } // use same method as '+'
2690
2691
2692 obj.greedy = true; // 0 as min means the same as '?'
2693
2694 obj.optional = true;
2695 return '';
2696 });
2697 } //do the actual token content
2698
2699
2700 if (start(w) === '#') {
2701 obj.tag = stripStart(w);
2702 obj.tag = titleCase$2(obj.tag);
2703 return obj;
2704 } //dynamic function on a term object
2705
2706
2707 if (start(w) === '@') {
2708 obj.method = stripStart(w);
2709 return obj;
2710 }
2711
2712 if (w === '.') {
2713 obj.anything = true;
2714 return obj;
2715 } //support alone-astrix
2716
2717
2718 if (w === '*') {
2719 obj.anything = true;
2720 obj.greedy = true;
2721 obj.optional = true;
2722 return obj;
2723 }
2724
2725 if (w) {
2726 //somehow handle encoded-chars?
2727 w = w.replace('\\*', '*');
2728 w = w.replace('\\.', '.');
2729 obj.word = w.toLowerCase();
2730 }
2731
2732 return obj;
2733};
2734
2735var _01ParseToken = parseToken;
2736
2737// name any [unnamed] capture-groups with a number
2738var nameGroups = function nameGroups(tokens) {
2739 var convert = false;
2740 var index = -1;
2741 var current; //'fill in' capture groups between start-end
2742
2743 for (var i = 0; i < tokens.length; i++) {
2744 var token = tokens[i]; // Give name to un-named single tokens
2745
2746 if (token.groupType === 'single' && token.named === true) {
2747 index += 1;
2748 token.named = index;
2749 continue;
2750 } // Start converting tokens
2751
2752
2753 if (token.groupType === 'start') {
2754 convert = true;
2755
2756 if (typeof token.named === 'string' || typeof token.named === 'number') {
2757 current = token.named;
2758 } else {
2759 index += 1;
2760 current = index;
2761 }
2762 } // Ensure this token has the right name
2763
2764
2765 if (convert) {
2766 token.named = current;
2767 } // Stop converting tokens
2768
2769
2770 if (token.groupType === 'end') {
2771 convert = false;
2772 }
2773 }
2774
2775 return tokens;
2776}; // optimize an 'or' lookup, when the (a|b|c) list is simple or multi-word
2777
2778
2779var doFastOrMode = function doFastOrMode(tokens) {
2780 return tokens.map(function (token) {
2781 if (token.choices !== undefined) {
2782 // are they all straight-up words? then optimize them.
2783 var shouldPack = token.choices.every(function (block) {
2784 if (block.length !== 1) {
2785 return false;
2786 }
2787
2788 var reg = block[0];
2789
2790 if (reg.word !== undefined && reg.negative !== true && reg.optional !== true && reg.method !== true) {
2791 return true; //reg is simple-enough
2792 }
2793
2794 return false;
2795 });
2796
2797 if (shouldPack === true) {
2798 var oneOf = {};
2799 token.choices.forEach(function (block) {
2800 oneOf[block[0].word] = true;
2801 });
2802 token.fastOr = oneOf;
2803 delete token.choices;
2804 }
2805 }
2806
2807 return token;
2808 });
2809}; // allow multiword OR (foo|one two)
2810// const doMultiWord = function (tokens) {
2811// return tokens.map(token => {
2812// if (token.choices !== undefined) {
2813// let isMulti = token.choices.find(o => hasASpace.test(o.word)) || false
2814// if (isMulti !== false) {
2815// token.multiword = true
2816// // turn all choices into arrays
2817// token.choices = token.choices.map(choice => {
2818// if (choice.word) {
2819// choice.sequence = choice.word.split(hasASpace)
2820// delete choice.word
2821// }
2822// return choice
2823// })
2824// }
2825// }
2826// return token
2827// })
2828// }
2829// const doBlockMode = function (tokens) {
2830// return tokens.map(token => {
2831// // we've already setup fastOr mode
2832// if (token.choices !== undefined) {
2833// // console.log(token)
2834// }
2835// return token
2836// })
2837// }
2838
2839
2840var postProcess$1 = function postProcess(tokens) {
2841 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2842 // ensure all capture groups are filled between start and end
2843 // give all capture groups names
2844 var count = tokens.filter(function (t) {
2845 return t.groupType;
2846 }).length;
2847
2848 if (count > 0) {
2849 tokens = nameGroups(tokens);
2850 } // convert 'choices' format to 'fastOr' format
2851
2852
2853 if (!opts.fuzzy) {
2854 tokens = doFastOrMode(tokens);
2855 } // support multiword OR (foo bar|baz)
2856 // tokens = doMultiWord(tokens)
2857 // support (one two three)
2858 // tokens = doBlockMode(tokens)
2859
2860
2861 return tokens;
2862};
2863
2864var _02PostProcess = postProcess$1;
2865
2866var hasReg = /[^[a-z]]\//g;
2867
2868var isArray$1 = function isArray(arr) {
2869 return Object.prototype.toString.call(arr) === '[object Array]';
2870}; // don't split up a regular expression
2871
2872
2873var mergeRegexes = function mergeRegexes(arr) {
2874 arr.forEach(function (s, i) {
2875 var m = s.match(hasReg); // has 1 slash
2876
2877 if (m !== null && m.length === 1 && arr[i + 1]) {
2878 // merge next one
2879 arr[i] += arr[i + 1];
2880 arr[i + 1] = ''; // try 2nd one
2881
2882 m = arr[i].match(hasReg);
2883
2884 if (m !== null && m.length === 1) {
2885 arr[i] += arr[i + 2];
2886 arr[i + 2] = '';
2887 }
2888 }
2889 });
2890 arr = arr.filter(function (s) {
2891 return s;
2892 });
2893 return arr;
2894}; //split-up by (these things)
2895
2896
2897var byParentheses = function byParentheses(str) {
2898 var arr = str.split(/([\^\[\!]*(?:<\S+>)?\(.*?\)[?+*]*\]?\$?)/);
2899 arr = arr.map(function (s) {
2900 return s.trim();
2901 });
2902
2903 if (hasReg.test(str)) {
2904 arr = mergeRegexes(arr);
2905 }
2906
2907 return arr;
2908};
2909
2910var byWords = function byWords(arr) {
2911 var words = [];
2912 arr.forEach(function (a) {
2913 //keep brackets lumped together
2914 if (/\(.*\)/.test(a)) {
2915 words.push(a);
2916 return;
2917 }
2918
2919 var list = a.split(' ');
2920 list = list.filter(function (w) {
2921 return w;
2922 });
2923 words = words.concat(list);
2924 });
2925 return words;
2926}; //turn an array into a 'choices' list
2927
2928
2929var byArray = function byArray(arr) {
2930 var blocks = arr.map(function (s) {
2931 return [{
2932 word: s
2933 }];
2934 });
2935 return [{
2936 choices: blocks,
2937 operator: 'or'
2938 }];
2939}; // turn a Doc object into a reg of ids to lookup
2940
2941
2942var fromDoc = function fromDoc(doc) {
2943 if (!doc || !doc.list || !doc.list[0]) {
2944 return [];
2945 }
2946
2947 var regs = [];
2948 doc.list.forEach(function (p) {
2949 var ids = [];
2950 p.terms().forEach(function (t) {
2951 ids.push(t.id);
2952 });
2953 regs.push(ids);
2954 });
2955 return [{
2956 idBlocks: regs
2957 }];
2958}; // add fuzziness etc to each reg
2959
2960
2961var addOptions = function addOptions(tokens, opts) {
2962 // add default fuzzy-search limit
2963 if (opts.fuzzy === true) {
2964 opts.fuzzy = 0.85;
2965 }
2966
2967 if (typeof opts.fuzzy === 'number') {
2968 tokens = tokens.map(function (reg) {
2969 // add a fuzzy-match on 'word' tokens
2970 if (opts.fuzzy > 0 && reg.word) {
2971 reg.fuzzy = opts.fuzzy;
2972 } //add it to or|and choices too
2973
2974
2975 if (reg.choices) {
2976 reg.choices.forEach(function (block) {
2977 block.forEach(function (r) {
2978 r.fuzzy = opts.fuzzy;
2979 });
2980 });
2981 }
2982
2983 return reg;
2984 });
2985 }
2986
2987 return tokens;
2988};
2989/** parse a match-syntax string into json */
2990
2991
2992var syntax = function syntax(input) {
2993 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2994
2995 // fail-fast
2996 if (input === null || input === undefined || input === '') {
2997 return [];
2998 } //try to support a ton of different formats:
2999
3000
3001 if (_typeof(input) === 'object') {
3002 if (isArray$1(input)) {
3003 if (input.length === 0 || !input[0]) {
3004 return [];
3005 } //is it a pre-parsed reg-list?
3006
3007
3008 if (_typeof(input[0]) === 'object') {
3009 return input;
3010 } //support a flat array of normalized words
3011
3012
3013 if (typeof input[0] === 'string') {
3014 return byArray(input);
3015 }
3016 } //support passing-in a compromise object as a match
3017
3018
3019 if (input && input.isA === 'Doc') {
3020 return fromDoc(input);
3021 }
3022
3023 return [];
3024 }
3025
3026 if (typeof input === 'number') {
3027 input = String(input); //go for it?
3028 }
3029
3030 var tokens = byParentheses(input); // console.log(tokens)
3031
3032 tokens = byWords(tokens);
3033 tokens = tokens.map(function (str) {
3034 return _01ParseToken(str);
3035 }); //clean up anything weird
3036
3037 tokens = _02PostProcess(tokens, opts); // add fuzzy limits, etc
3038
3039 tokens = addOptions(tokens, opts); // console.log(tokens)
3040
3041 return tokens;
3042};
3043
3044var matchSyntax = syntax; // console.log(syntax('before [(united states|canadian)] after'))
3045
3046// match an explicit sequence of term ids
3047// take a phrase and find any of the idBlocks in it
3048var idLookup = function idLookup(terms, regs) {
3049 var matches = [];
3050 var blocklist = regs[0].idBlocks;
3051
3052 var _loop = function _loop(_t) {
3053 blocklist.forEach(function (block) {
3054 if (block.length === 0) {
3055 t = _t;
3056 return;
3057 }
3058
3059 var foundAll = block.every(function (id, i) {
3060 t = _t;
3061 return terms[_t + i].id === id;
3062 });
3063
3064 if (foundAll) {
3065 matches.push({
3066 match: terms.slice(_t, _t + block.length)
3067 }); // skip top-loop forward
3068
3069 _t += block.length - 1;
3070 }
3071 });
3072 t = _t;
3073 };
3074
3075 for (var t = 0; t < terms.length; t += 1) {
3076 _loop(t);
3077 }
3078
3079 return matches;
3080};
3081
3082var idLookup_1 = idLookup;
3083
3084/** returns a simple array of arrays */
3085
3086var matchAll = function matchAll(p, regs) {
3087 var matchOne = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
3088
3089 //if we forgot to parse it..
3090 if (typeof regs === 'string') {
3091 regs = matchSyntax(regs);
3092 } //try to dismiss it, at-once
3093
3094
3095 if (_02FailFast(p, regs) === true) {
3096 return [];
3097 } //any match needs to be this long, at least
3098
3099
3100 var minLength = regs.filter(function (r) {
3101 return r.optional !== true && r.negative !== true;
3102 }).length;
3103 var terms = p.terms();
3104 var matches = []; // these id-lookups can be super-fast
3105
3106 if (regs[0].idBlocks) {
3107 var res = idLookup_1(terms, regs);
3108
3109 if (res && res.length > 0) {
3110 return _04PostProcess(terms, regs, res);
3111 }
3112 } //optimisation for '^' start logic
3113
3114
3115 if (regs[0].start === true) {
3116 var _res = _03TryMatch(terms, regs, 0, terms.length);
3117
3118 if (_res && _res.match && _res.match.length > 0) {
3119 _res.match = _res.match.filter(function (m) {
3120 return m;
3121 });
3122 matches.push(_res);
3123 }
3124
3125 return _04PostProcess(terms, regs, matches);
3126 } //try starting, from every term
3127
3128
3129 for (var i = 0; i < terms.length; i += 1) {
3130 // slice may be too short
3131 if (i + minLength > terms.length) {
3132 break;
3133 } //try it!
3134
3135
3136 var _res2 = _03TryMatch(terms.slice(i), regs, i, terms.length);
3137
3138 if (_res2 && _res2.match && _res2.match.length > 0) {
3139 //zoom forward!
3140 i += _res2.match.length - 1; //[capture-groups] return some null responses
3141
3142 _res2.match = _res2.match.filter(function (m) {
3143 return m;
3144 });
3145 matches.push(_res2); //ok, maybe that's enough?
3146
3147 if (matchOne === true) {
3148 return _04PostProcess(terms, regs, matches);
3149 }
3150 }
3151 }
3152
3153 return _04PostProcess(terms, regs, matches);
3154};
3155
3156var _01MatchAll = matchAll;
3157
3158/** return anything that doesn't match.
3159 * returns a simple array of arrays
3160 */
3161
3162var notMatch = function notMatch(p, regs) {
3163 var found = {};
3164 var arr = _01MatchAll(p, regs);
3165 arr.forEach(function (_ref) {
3166 var ts = _ref.match;
3167 ts.forEach(function (t) {
3168 found[t.id] = true;
3169 });
3170 }); //return anything not found
3171
3172 var terms = p.terms();
3173 var result = [];
3174 var current = [];
3175 terms.forEach(function (t) {
3176 if (found[t.id] === true) {
3177 if (current.length > 0) {
3178 result.push(current);
3179 current = [];
3180 }
3181
3182 return;
3183 }
3184
3185 current.push(t);
3186 });
3187
3188 if (current.length > 0) {
3189 result.push(current);
3190 }
3191
3192 return result;
3193};
3194
3195var not = notMatch;
3196
3197/** return an array of matching phrases */
3198
3199var match_1 = function match_1(regs) {
3200 var _this = this;
3201
3202 var justOne = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
3203 var matches = _01MatchAll(this, regs, justOne); //make them phrase objects
3204
3205 matches = matches.map(function (_ref) {
3206 var match = _ref.match,
3207 groups = _ref.groups;
3208
3209 var p = _this.buildFrom(match[0].id, match.length, groups);
3210
3211 p.cache.terms = match;
3212 return p;
3213 });
3214 return matches;
3215};
3216/** return boolean if one match is found */
3217
3218
3219var has = function has(regs) {
3220 var matches = _01MatchAll(this, regs, true);
3221 return matches.length > 0;
3222};
3223/** remove all matches from the result */
3224
3225
3226var not$1 = function not$1(regs) {
3227 var _this2 = this;
3228
3229 var matches = not(this, regs); //make them phrase objects
3230
3231 matches = matches.map(function (list) {
3232 return _this2.buildFrom(list[0].id, list.length);
3233 });
3234 return matches;
3235};
3236/** return a list of phrases that can have this tag */
3237
3238
3239var canBe$1 = function canBe(tag, world) {
3240 var _this3 = this;
3241
3242 var results = [];
3243 var terms = this.terms();
3244 var previous = false;
3245
3246 for (var i = 0; i < terms.length; i += 1) {
3247 var can = terms[i].canBe(tag, world);
3248
3249 if (can === true) {
3250 if (previous === true) {
3251 //add it to the end
3252 results[results.length - 1].push(terms[i]);
3253 } else {
3254 results.push([terms[i]]); //make a new one
3255 }
3256
3257 previous = can;
3258 }
3259 } //turn them into Phrase objects
3260
3261
3262 results = results.filter(function (a) {
3263 return a.length > 0;
3264 }).map(function (arr) {
3265 return _this3.buildFrom(arr[0].id, arr.length);
3266 });
3267 return results;
3268};
3269
3270var match = {
3271 match: match_1,
3272 has: has,
3273 not: not$1,
3274 canBe: canBe$1
3275};
3276
3277var Phrase = function Phrase(id, length, pool) {
3278 _classCallCheck(this, Phrase);
3279
3280 this.start = id;
3281 this.length = length;
3282 this.isA = 'Phrase'; // easier than .constructor...
3283
3284 Object.defineProperty(this, 'pool', {
3285 enumerable: false,
3286 writable: true,
3287 value: pool
3288 });
3289 Object.defineProperty(this, 'cache', {
3290 enumerable: false,
3291 writable: true,
3292 value: {}
3293 });
3294 Object.defineProperty(this, 'groups', {
3295 enumerable: false,
3296 writable: true,
3297 value: {}
3298 });
3299};
3300/** create a new Phrase object from an id and length */
3301
3302
3303Phrase.prototype.buildFrom = function (id, length, groups) {
3304 var p = new Phrase(id, length, this.pool); //copy-over or replace capture-groups too
3305
3306 if (groups && Object.keys(groups).length > 0) {
3307 p.groups = groups;
3308 } else {
3309 p.groups = this.groups;
3310 }
3311
3312 return p;
3313}; //apply methods
3314
3315
3316Object.assign(Phrase.prototype, match);
3317Object.assign(Phrase.prototype, methods$1); //apply aliases
3318
3319var aliases = {
3320 term: 'terms'
3321};
3322Object.keys(aliases).forEach(function (k) {
3323 return Phrase.prototype[k] = Phrase.prototype[aliases[k]];
3324});
3325var Phrase_1 = Phrase;
3326
3327/** a key-value store of all terms in our Document */
3328var Pool = /*#__PURE__*/function () {
3329 function Pool() {
3330 var words = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
3331
3332 _classCallCheck(this, Pool);
3333
3334 //quiet this property in console.logs
3335 Object.defineProperty(this, 'words', {
3336 enumerable: false,
3337 value: words
3338 });
3339 }
3340 /** throw a new term object in */
3341
3342
3343 _createClass(Pool, [{
3344 key: "add",
3345 value: function add(term) {
3346 this.words[term.id] = term;
3347 return this;
3348 }
3349 /** find a term by it's id */
3350
3351 }, {
3352 key: "get",
3353 value: function get(id) {
3354 return this.words[id];
3355 }
3356 /** find a term by it's id */
3357
3358 }, {
3359 key: "remove",
3360 value: function remove(id) {
3361 delete this.words[id];
3362 }
3363 }, {
3364 key: "merge",
3365 value: function merge(pool) {
3366 Object.assign(this.words, pool.words);
3367 return this;
3368 }
3369 /** helper method */
3370
3371 }, {
3372 key: "stats",
3373 value: function stats() {
3374 return {
3375 words: Object.keys(this.words).length
3376 };
3377 }
3378 }]);
3379
3380 return Pool;
3381}();
3382/** make a deep-copy of all terms */
3383
3384
3385Pool.prototype.clone = function () {
3386 var _this = this;
3387
3388 var keys = Object.keys(this.words);
3389 var words = keys.reduce(function (h, k) {
3390 var t = _this.words[k].clone();
3391
3392 h[t.id] = t;
3393 return h;
3394 }, {});
3395 return new Pool(words);
3396};
3397
3398var Pool_1 = Pool;
3399
3400//add forward/backward 'linked-list' prev/next ids
3401var linkTerms = function linkTerms(terms) {
3402 terms.forEach(function (term, i) {
3403 if (i > 0) {
3404 term.prev = terms[i - 1].id;
3405 }
3406
3407 if (terms[i + 1]) {
3408 term.next = terms[i + 1].id;
3409 }
3410 });
3411};
3412
3413var _linkTerms = linkTerms;
3414
3415//(Rule-based sentence boundary segmentation) - chop given text into its proper sentences.
3416// Ignore periods/questions/exclamations used in acronyms/abbreviations/numbers, etc.
3417// @spencermountain 2017 MIT
3418//proper nouns with exclamation marks
3419// const blacklist = {
3420// yahoo: true,
3421// joomla: true,
3422// jeopardy: true,
3423// }
3424//regs-
3425var initSplit = /(\S.+?[.!?\u203D\u2E18\u203C\u2047-\u2049])(?=\s+|$)/g;
3426var hasSomething = /\S/;
3427var isAcronym$1 = /[ .][A-Z]\.? *$/i;
3428var hasEllipse = /(?:\u2026|\.{2,}) *$/;
3429var newLine = /((?:\r?\n|\r)+)/; // Match different new-line formats
3430
3431var hasLetter = /[a-z0-9\u00C0-\u00FF\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]/i;
3432var startWhitespace = /^\s+/; // Start with a regex:
3433
3434var naiive_split = function naiive_split(text) {
3435 var all = []; //first, split by newline
3436
3437 var lines = text.split(newLine);
3438
3439 for (var i = 0; i < lines.length; i++) {
3440 //split by period, question-mark, and exclamation-mark
3441 var arr = lines[i].split(initSplit);
3442
3443 for (var o = 0; o < arr.length; o++) {
3444 all.push(arr[o]);
3445 }
3446 }
3447
3448 return all;
3449};
3450/** does this look like a sentence? */
3451
3452
3453var isSentence = function isSentence(str, abbrevs) {
3454 // check for 'F.B.I.'
3455 if (isAcronym$1.test(str) === true) {
3456 return false;
3457 } //check for '...'
3458
3459
3460 if (hasEllipse.test(str) === true) {
3461 return false;
3462 } // must have a letter
3463
3464
3465 if (hasLetter.test(str) === false) {
3466 return false;
3467 }
3468
3469 var txt = str.replace(/[.!?\u203D\u2E18\u203C\u2047-\u2049] *$/, '');
3470 var words = txt.split(' ');
3471 var lastWord = words[words.length - 1].toLowerCase(); // check for 'Mr.'
3472
3473 if (abbrevs.hasOwnProperty(lastWord)) {
3474 return false;
3475 } // //check for jeopardy!
3476 // if (blacklist.hasOwnProperty(lastWord)) {
3477 // return false
3478 // }
3479
3480
3481 return true;
3482};
3483
3484var splitSentences = function splitSentences(text, world) {
3485 var abbrevs = world.cache.abbreviations;
3486 text = text || '';
3487 text = String(text);
3488 var sentences = []; // First do a greedy-split..
3489
3490 var chunks = []; // Ensure it 'smells like' a sentence
3491
3492 if (!text || typeof text !== 'string' || hasSomething.test(text) === false) {
3493 return sentences;
3494 } // cleanup unicode-spaces
3495
3496
3497 text = text.replace('\xa0', ' '); // Start somewhere:
3498
3499 var splits = naiive_split(text); // Filter-out the crap ones
3500
3501 for (var i = 0; i < splits.length; i++) {
3502 var s = splits[i];
3503
3504 if (s === undefined || s === '') {
3505 continue;
3506 } //this is meaningful whitespace
3507
3508
3509 if (hasSomething.test(s) === false) {
3510 //add it to the last one
3511 if (chunks[chunks.length - 1]) {
3512 chunks[chunks.length - 1] += s;
3513 continue;
3514 } else if (splits[i + 1]) {
3515 //add it to the next one
3516 splits[i + 1] = s + splits[i + 1];
3517 continue;
3518 }
3519 } //else, only whitespace, no terms, no sentence
3520
3521
3522 chunks.push(s);
3523 } //detection of non-sentence chunks:
3524 //loop through these chunks, and join the non-sentence chunks back together..
3525
3526
3527 for (var _i = 0; _i < chunks.length; _i++) {
3528 var c = chunks[_i]; //should this chunk be combined with the next one?
3529
3530 if (chunks[_i + 1] && isSentence(c, abbrevs) === false) {
3531 chunks[_i + 1] = c + (chunks[_i + 1] || '');
3532 } else if (c && c.length > 0) {
3533 //&& hasLetter.test(c)
3534 //this chunk is a proper sentence..
3535 sentences.push(c);
3536 chunks[_i] = '';
3537 }
3538 } //if we never got a sentence, return the given text
3539
3540
3541 if (sentences.length === 0) {
3542 return [text];
3543 } //move whitespace to the ends of sentences, when possible
3544 //['hello',' world'] -> ['hello ','world']
3545
3546
3547 for (var _i2 = 1; _i2 < sentences.length; _i2 += 1) {
3548 var ws = sentences[_i2].match(startWhitespace);
3549
3550 if (ws !== null) {
3551 sentences[_i2 - 1] += ws[0];
3552 sentences[_i2] = sentences[_i2].replace(startWhitespace, '');
3553 }
3554 }
3555
3556 return sentences;
3557};
3558
3559var _01Sentences = splitSentences; // console.log(sentence_parser('john f. kennedy'));
3560
3561var wordlike = /\S/;
3562var isBoundary = /^[!?.]+$/;
3563var naiiveSplit = /(\S+)/;
3564var isSlash = /[a-z] ?\/ ?[a-z]*$/;
3565var notWord = ['.', '?', '!', ':', ';', '-', '–', '—', '--', '...', '(', ')', '[', ']', '"', "'", '`'];
3566notWord = notWord.reduce(function (h, c) {
3567 h[c] = true;
3568 return h;
3569}, {});
3570
3571var hasHyphen = function hasHyphen(str) {
3572 //dont split 're-do'
3573 if (/^(re|un)-?[^aeiou]./.test(str) === true) {
3574 return false;
3575 } //letter-number 'aug-20'
3576
3577
3578 var reg = /^([a-z\u00C0-\u00FF`"'/]+)(-|–|—)([a-z0-9\u00C0-\u00FF].*)/i;
3579
3580 if (reg.test(str) === true) {
3581 return true;
3582 } //number-letter '20-aug'
3583
3584
3585 var reg2 = /^([0-9]{1,4})(-|–|—)([a-z\u00C0-\u00FF`"'/-]+$)/i;
3586
3587 if (reg2.test(str) === true) {
3588 return true;
3589 } //support weird number-emdash combo '2010–2011'
3590 // let reg2 = /^([0-9]+)(–|—)([0-9].*)/i
3591 // if (reg2.test(str)) {
3592 // return true
3593 // }
3594
3595
3596 return false;
3597}; // 'he / she' should be one word
3598
3599
3600var combineSlashes = function combineSlashes(arr) {
3601 for (var i = 1; i < arr.length - 1; i++) {
3602 if (isSlash.test(arr[i])) {
3603 arr[i - 1] += arr[i] + arr[i + 1];
3604 arr[i] = null;
3605 arr[i + 1] = null;
3606 }
3607 }
3608
3609 return arr;
3610};
3611
3612var splitHyphens = function splitHyphens(word) {
3613 var arr = []; //support multiple-hyphenated-terms
3614
3615 var hyphens = word.split(/[-–—]/);
3616 var whichDash = '-';
3617 var found = word.match(/[-–—]/);
3618
3619 if (found && found[0]) {
3620 whichDash = found;
3621 }
3622
3623 for (var o = 0; o < hyphens.length; o++) {
3624 if (o === hyphens.length - 1) {
3625 arr.push(hyphens[o]);
3626 } else {
3627 arr.push(hyphens[o] + whichDash);
3628 }
3629 }
3630
3631 return arr;
3632};
3633
3634var isArray$2 = function isArray(arr) {
3635 return Object.prototype.toString.call(arr) === '[object Array]';
3636}; //turn a string into an array of strings (naiive for now, lumped later)
3637
3638
3639var splitWords = function splitWords(str) {
3640 var result = [];
3641 var arr = []; //start with a naiive split
3642
3643 str = str || '';
3644
3645 if (typeof str === 'number') {
3646 str = String(str);
3647 }
3648
3649 if (isArray$2(str)) {
3650 return str;
3651 }
3652
3653 var words = str.split(naiiveSplit);
3654
3655 for (var i = 0; i < words.length; i++) {
3656 //split 'one-two'
3657 if (hasHyphen(words[i]) === true) {
3658 arr = arr.concat(splitHyphens(words[i]));
3659 continue;
3660 }
3661
3662 arr.push(words[i]);
3663 } //greedy merge whitespace+arr to the right
3664
3665
3666 var carry = '';
3667
3668 for (var _i = 0; _i < arr.length; _i++) {
3669 var word = arr[_i]; //if it's more than a whitespace
3670
3671 if (wordlike.test(word) === true && notWord.hasOwnProperty(word) === false && isBoundary.test(word) === false) {
3672 //put whitespace on end of previous term, if possible
3673 if (result.length > 0) {
3674 result[result.length - 1] += carry;
3675 result.push(word);
3676 } else {
3677 //otherwise, but whitespace before
3678 result.push(carry + word);
3679 }
3680
3681 carry = '';
3682 } else {
3683 carry += word;
3684 }
3685 } //handle last one
3686
3687
3688 if (carry) {
3689 if (result.length === 0) {
3690 result[0] = '';
3691 }
3692
3693 result[result.length - 1] += carry; //put it on the end
3694 } // combine 'one / two'
3695
3696
3697 result = combineSlashes(result); // remove empty results
3698
3699 result = result.filter(function (s) {
3700 return s;
3701 });
3702 return result;
3703};
3704
3705var _02Words = splitWords;
3706
3707var isArray$3 = function isArray(arr) {
3708 return Object.prototype.toString.call(arr) === '[object Array]';
3709};
3710/** turn a string into an array of Phrase objects */
3711
3712
3713var fromText = function fromText() {
3714 var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
3715 var world = arguments.length > 1 ? arguments[1] : undefined;
3716 var pool = arguments.length > 2 ? arguments[2] : undefined;
3717 var sentences = null; //a bit of validation, first
3718
3719 if (typeof text !== 'string') {
3720 if (typeof text === 'number') {
3721 text = String(text);
3722 } else if (isArray$3(text)) {
3723 sentences = text;
3724 }
3725 } //tokenize into words
3726
3727
3728 sentences = sentences || _01Sentences(text, world);
3729 sentences = sentences.map(function (str) {
3730 return _02Words(str);
3731 }); //turn them into proper objects
3732
3733 pool = pool || new Pool_1();
3734 var phrases = sentences.map(function (terms) {
3735 terms = terms.map(function (str) {
3736 var term = new Term_1(str);
3737 pool.add(term);
3738 return term;
3739 }); //add next/previous ids
3740
3741 _linkTerms(terms); //return phrase objects
3742
3743 var p = new Phrase_1(terms[0].id, terms.length, pool);
3744 p.cache.terms = terms;
3745 return p;
3746 }); //return them ready for a Document object
3747
3748 return phrases;
3749};
3750
3751var _01Tokenizer = fromText;
3752
3753var fromJSON = function fromJSON(json, world) {
3754 var pool = new Pool_1();
3755 var phrases = json.map(function (p, k) {
3756 var terms = p.terms.map(function (o, i) {
3757 var term = new Term_1(o.text);
3758 term.pre = o.pre !== undefined ? o.pre : '';
3759
3760 if (o.post === undefined) {
3761 o.post = ' '; //no given space for very last term
3762
3763 if (i >= p.terms.length - 1) {
3764 o.post = '. ';
3765
3766 if (k >= p.terms.length - 1) {
3767 o.post = '.';
3768 }
3769 }
3770 }
3771
3772 term.post = o.post !== undefined ? o.post : ' ';
3773
3774 if (o.tags) {
3775 o.tags.forEach(function (tag) {
3776 return term.tag(tag, '', world);
3777 });
3778 }
3779
3780 pool.add(term);
3781 return term;
3782 }); //add prev/next links
3783
3784 _linkTerms(terms); // return a proper Phrase object
3785
3786 return new Phrase_1(terms[0].id, terms.length, pool);
3787 });
3788 return phrases;
3789};
3790
3791var fromJSON_1 = fromJSON;
3792
3793var _version = '13.9.0';
3794
3795var _data = {
3796 "Comparative": "true¦better",
3797 "Superlative": "true¦earlier",
3798 "PresentTense": "true¦is,sounds",
3799 "Value": "true¦a few",
3800 "Noun": "true¦a5b4c2f1here,ie,lit,m0no doubt,pd,tce;a,d;t,y;a,ca,o0;l,rp;a,l;d,l,rc",
3801 "Copula": "true¦a1is,w0;as,ere;m,re",
3802 "PastTense": "true¦be3came,d2had,lied,meant,sa2taken,w0;as,e0;nt,re;id;en,gan",
3803 "Condition": "true¦if,lest,unless",
3804 "Preposition": "true¦'o,-,aLbIcHdGexcept,fFiDmidQnotwithstandiRoBpSqua,sAt6u3vi2w0;/o,hereNith0;!in,oR;a,s-a-vis;n1p0;!on;like,til;h0ill,owards;an,r0;ough0u;!oJ;ans,ince,o that;',f0n2ut;!f;f,n0;!to;or,rom;espite,own,u3;hez,irca;ar1e0oAy;sides,tween;ri6;',bo7cross,ft6lo5m3propos,round,s1t0;!op;! long 0;as;id0ong0;!st;ng;er;ut",
3805 "Gerund": "true¦accord0be0develop0go0result0stain0;ing",
3806 "Negative": "true¦n0;ever,o0;!n,t",
3807 "QuestionWord": "true¦how3wh0;at,e1ich,o0y;!m,se;n,re; come,'s",
3808 "Plural": "true¦records",
3809 "Conjunction": "true¦&,aFbBcuz,how9in caEno8o7p5supposing,t2v1wh0yet;eth9ile;ers4s;h0o;eref9o0;!uC;l0rovided that;us;r,therwi6; matt1r;!ev0;er;e0ut;cau1f0;ore;se;lthou1nd,s 0;far as,if;gh",
3810 "Abbreviation": "true¦a0Tb0Qc0Kd0Ie0Ff0Cg0Ah08i06j04k02l00mRnOoNpIqHrFs9t6u5v2w0yb,µg;is0r,y0L;!c;a,b,e1i0ol,s,t;tro,vo;r,t;niv,safa,t;b1ce,d,e0sp;l,mp,nn,x;!l,sp;ask,e3fc,gt,i2q1r,s,t,u0;pt,rg;! ft;r,tu;c,nVp0;!t;b,d,e0;pSs,v;t,ue;a,d,enn3hd,l,p,r1s0t,vt;!eud;ef,o0;b,f,n;!a;ct,kla,nt,z;e0ov;b0e;!r;a7b,d,essrs,g,i4l3m2p1rHs0t;!tr;h,s;!e;!le;!n1s0;c,ter;!n;!j,r,sc;at,b,it,lb,m,ng,t0x;!d;an6b,g,m0;!ph;an,d,r,u0;l,n;a,da,e,n0;c,f;g,on,r0wy,z;!s;a0b,en,ov;!l;e1ig,l0m,r,t,y;! oz,a;b,m;a,g,ng,s1tc,x0;!p;p,q,t;ak,e0g,ist,l,m,r;c,f,pt,t;a3ca,g,l,m2o0pl,res,yn;!l0mdr,nn,rp;!o;!dr;!l0pt;!if;a,c,l1r0;ig,os;!dg,vd;d4l3p2r1ss0tty,ug,ve;n,t;c,iz;prox,r,t;!ta;!j,m,v",
3811 "Pronoun": "true¦'em,elle,h4i3me,ourselves,she5th1us,we,you0;!rself;e0ou;m,y;!l,t;e0im;!'s",
3812 "Singular": "true¦0:15;1:18;2:12;a15b0Sc0Jd0Ce09f04gZhViUjel0kitty,lSmOnNoMpHquestionGrEs9t6u4w3;ay,om02;nc0Zs 3;doll0Kst0M; rex,a4h3ic,ragedy,v show;ere,i1;l0x return;i6ky,omeoMt3uper bowl,yst14;ep4ri1u3;de0Xff;faSmoS;st2ze;al0i1o3;om,se;! mark;a6i2la5r4u3;dPrpoH;eroga00ie0Gobl0U;te,y2;rt,te0N;bjWceJthers,verview;othi1umb2;a5ee08o3;del,m3nopo0rni1th2;!my;n,yf0;i3unch;ne;ci1nsect;ead start,o3uman right;l0me4u3;se;! run;adf0entlem6irl02laci2od,rand4u3;l0y; slam,fa3mo3;th2;an;a6ella,ly,ol0r4un3;di1;ee market,iWo3;nti2sP;mi0th2;conomy,gg,ner7ven4x3;ampTecu9;i1t;ad8e5inn2o3ragonf0ude;cumentGg3i0l0or;gy;ath,t3;ec3;tive;!dy;a9eili1h7i5o3redit card;ttage,u3;ri2sin;ty,vil w3;ar;andeli2ocol3;ate;n3rF;ary;aCel0lesJo8r5u3;n3tterf0;ti1;eakfa4o3;!th2;st;dy,tt5y3;!fri3;end;le;nki1r3;ri2;er;d5l0noma0u3;nt;ly; homin5verti3;si1;ng;em",
3813 "FemaleName": "true¦0:J3;1:J7;2:IG;3:IF;4:IX;5:IK;6:JO;7:H0;8:JK;9:JG;A:HN;B:HY;C:IT;D:JD;E:IP;F:HC;G:I0;aGRbFLcDPdCYeBOfB4gADh9Ti9Gj8Gk7Gl60m49n3No3Jp37qu36r2Ds16t0Eu0Cv02wVxiTyOzH;aLeIineb,oHsof2;e3Uf2la,ra;h3iKlIna,ynH;ab,ep;da,ma;da,h3iHra;nab;aKeJi0Fol5BuIvH;etAonDO;i0na;le0sen2;el,gm3Jn,rGJs8W;aoHme0nyi;m62yAE;aMendDYhiDFiH;dele9lJnH;if48niHo0;e,f47;a,helmi0lHma;a,ow;ka0nB;aNeKiHusa5;cIktoriBMlAole7viH;anC3enJ0;kF9tor2;da,lA9nus,rHs0;a,nHoniH4;a,iFQ;leHnesH4;nIHrH;i1y;g9rHxH5;su5te;aYeUhRiNoLrIuHy3;i,la;acIZiHu0L;c2na,sH;hBPta;nHr0H;iBNya;aJffaEOnHs6;a,gtiH;ng;!nFQra;aIeHomasi0;a,l9Po8Ares1;l2ndolwethu;g9Go88rIssH;!a,ie;eHi,ri8;sa,za;bPlNmLnJrIs6tHwa0;ia0um;a63yn;iHya;a,ka,s6;arB6e3iHmEDra;!ka;a,iH;a,t6;at6it6;a0Fcarlet3We0BhXiTkye,neza0oRtNuIyH;bIBlvi1;e,ha,mayIEni7sIzH;an3MetAie,y;anHi8;!a,e,nH;aEe;aJeH;fHl5GphH;an4;cHZr5;b2fiA8m0OnHphi1;d3ia,ja,ya;er3lJmon1nIobh8PtH;a,i;dy;lEPv2;aMeIirHo0risF7y5;a,lDK;ba,e0i5lJrH;iHrDOyl;!d8Hfa;ia,lDX;hd,iMki3nJrIu0w0yH;la,ma,na;i,le9on,ron;aIda,ia,nHon;a,on;!ya;k6mH;!aa;lJrItaye81vH;da,inj;e0ife;en1i0ma;anA5bNd3Nh1RiBkMlLmJndIrHs6vannaE;aEi0;ra,y;aHi3;nt6ra;lDKma,ome;ee0in8Ru3;in1ri0;a05e00hYiVoIuH;by,thDH;bScRghQl2KnPsJwIxH;anAXie,y;an,e0;aIeHie,lD; merBLann8ll1marDBt7;!lHnn1;iHyn;e,nH;a,d9K;da,i,na;ayy8D;hel62io;bDKer7yn;a,cIkHmas,n9Fta,ya;ki,o;helGki;ea,iannGDoH;da,n1K;an0bJem9Agi0iInHta,y0;a88ee;han83na;a,eH;cEAkaE;bi0chIe,i0mo0nHquEKvCy0;di,ia;aEIelHiB;!e,le;een4ia0;aNeMhKipaluk,oJrHute66;iHudenCQ;scil3LyamvaB;lly,rt2;ilome0oebe,ylH;is,lis;arl,ggy,nelope,r5t3;ige,m0TnKo5rvaDGtIulH;a,etAin1;ricHsy,tBY;a,e,ia;do3i06;ctav2dIfCZis6lHphCZumC3yunbileg;a,ga,iv2;eHvAC;l2tA;aWeUiMoIurHy5;!ay,ul;a,eJor,rIuH;f,r;aEeCma;ll1mi;aNcLhariBOkKlaJna,sHta,vi;anHha;ur;!y;a,iDTki;hoGk9VolH;a,eDJ;!mh;hir,lHna,risFsreC;!a,lBT;asuLdKh2i6CnJomi8rgEPtHzanin zah3;aHhal4;li1s6;cy,etA;a,e9iEV;nngu30;a09ckenz4e01iMoJrignayani,uriDDyH;a,rH;a,lNna,tG;bi0i3llBInH;a,iH;ca,ka,qD3;a,cTkaSlNmi,nLrItzi,yH;ar;aIiam,lH;anEO;!l,nB;dy,eHh,n4;nhGrva;aKdJiCPlH;iHy;cent,e;red;!gros;!e5;ae5hH;ae5el3Z;ag5EgNi,lKrH;edi79iIjem,on,yH;em,l;em,sF;an4iHliF;nHsCE;a,da;!an,han;b0DcASd0Be,g09ha,i08ja,l06n04rLsoum60tKuIv82x9IyHz4;a,bell,ra,soB9;de,rH;a,eC;h8Fild1t4;a,cYgUiKjor4l7Sn4s6tJwa,yH;!aHbe6Wja9lAE;m,nBH;a,ha,in1;!aJbCBeIja,lDna,sHt64;!a,ol,sa;!l1H;! Jh,mInH;!a,e,n1;!awit,i;aliAHcJeduarBfernIjHlui5Y;o6Ful2;anB;ecil2la3;arJeIie,oHr44ueriA;!t;!ry;et42i37;el4Ui76y;dHon,ue5;akran7y;ak,en,iHk,lo3O;a,ka,nB;a,re,s4te;daHg4;!l3A;alDd4elHge,isDBon0;ei9in1yn;el,le;a0Ne0CiYoQuLyH;d2la,nH;!a,dIeBGnHsCL;!a,eBF;a,sCJ;aCWcJel0PiFlIna,pHz;e,i7;a,u,wa;iHy;a0Se,ja,l2JnB;is,l1SrJttIuHvel4;el5is1;e,ie;aKeIi8na,rH;a86i8;lHn1t7;ei;!in1;aSbb9CdRepa,lMnJsIv2zH;!a,be5LetAz4;a,etA;!a,dH;a,sHy;ay,ey,i,y;a,iJja,lHy;iHy;aA0e;!aH;!n5F;ia,ya;!nH;!a,ne;aPda,e0iNjYla,nMoKsJtHx4y5;iHt4;c2t2;e2LlCG;la,nHra;a,ie,o3;a,or1;a,gh,laH;!ni;!h,nH;a,d3e,n5P;cOdon97iNkes6mi9Ana,rMtJurIvHxmi,y5;ern1in2;a,e54ie,yn;as6iIoH;nya,ya;fa,s6;a,isF;a,la;ey,ie,y;a04eZhXiOlAKoNrJyH;lHra;a,ee,ie;istHy6D;a,en,iIyH;!na;!e,n59;nul,ri,urtnB0;aOerNlAZmJrHzzy;a,stH;en,in;!berlImernH;aq;eHi,y;e,y;a,stC;!na,ra;aHei3ongordzol;dij1w5;el7QiKjsi,lJnIrH;a,i,ri;d3na,za;ey,i,lBDs4y;ra,s6;bi7cAJdiat7IeB2iRlQmPnyakuma19rNss6KtKvi7yH;!e,lH;a,eH;e,i8L;a6DeIhHi4NlDri0y;ar6Ber6Bie,leCrB2y;!lyn8Gri0;a,en,iHl5Soli0yn;!ma,n3VsF;a5il1;ei8Ei,l4;a,tl6L;a07eYiVoNuH;anLdKliHst63;a8HeHsF;!n9tH;!a,te;e5Ji3Jy;a,i7;!anNcelDd6RelGhan7RlLni,sIva0yH;a,ce;eHie;fHlDph5U;a,in1;eHie;en,n1;!a,e,n41;lHng;!i1ClH;!i1B;anMle0nJrIsH;i8Csi8C;i,ri;!a,elGif2CnH;a,etAiHy;!e,f2A;a,e8EiInH;a,e8DiH;e,n1;cMd1mi,nIque4Xsmin3Ovie3y9zH;min8;a8eIiH;ce,e,n1s;!lHsFt0F;e,le;inIk4lDquelH;in1yn;da,ta;lRmPnOo0rNsIvaHzaro;!a0lu,na;aJiIlaHob84;!n9N;do3;!belHdo3;!a,e,l39;a77en1i0ma;a,di3es,gr6Yji;a9elBogH;en1;a,e9iHo0se;a0na;aSeOiJoHusFyacin2B;da,ll4rten23snH;a,i9Q;lImaH;ri;aIdHlaI;a,egard;ry;ath1CiJlInriet7rmi9sH;sa,t1B;en2Sga,mi;di;bi2Dil8IlNnMrJsItHwa,yl8Iz7H;i5St4;n5Yti;iHmo51ri52;etH;!te;aEnaE;a,ey,l4;a03eXiSlQoOrKunJwH;enHyne1Q;!dolD;ay,el;acIetHiselB;a,chC;e,ieH;!la;ld1AogooH;sh;adys,enHor2yn2H;a,da,na;aKgi,lIna,ov89selHta;a,e,le;da,liH;an;!n0;mLnJorgIrH;ald3Pi,m3Ctru8B;etAi4W;a,eHna;s26vieve;ma;bIil,le,mHrnet,yG;al5Ni5;i5FrielH;a,l1;aVeSiRloOoz2rH;anJeIiH;da,eB;da,ja;!cH;esIiHoi0O;n1s61;!ca;!rH;a,encH;e,ia;en,o0;lIn0rnH;!anB;ec2ic2;jr,n7rKtHy8;emIiHma,ouma7;ha,ma,n;eh;ah,iBrah,za0;cr4Nd0Ne0Mi0Lk7l04mWn4YrTsNtMuLvH;aJelIiH;!e,ta;in0Gyn;!ngel2S;geni1la,ni45;h5Sta;mLperanKtH;eIhHrel5;er;l30r8;za;a,eralB;iHma,nest2Jyn;cHka,n;a,ka;a,eMiJmH;aHie,y;!li9;lHn1;ee,iHy;a,e,ja;lHrald;da,y;aWeUiNlMma,no3oKsJvH;a,iH;na,ra;a,ie;iHuiH;se;a,en,ie,y;a0c2da,f,nMsJzaH;!betHve7;e,h;aHe,ka;!beH;th;!a,or;anor,nH;!a;!in1na;leCs6;vi;eIiHna,wi0;e,th;l,n;aYeMh2iLjeneKoHul30;lor5Tminiq4In3FrHtt4;a,eCis,la,othHthy;ea,y;ba;an0AnaEon9x4ya;anQbPde,eOiMja,lJmetr2nHsir5K;a,iH;ce,se;a,iIla,orHphi9;es,is;a,l6D;dHrdH;re;!d5Cna;!b2HoraEra;a,d3nH;!a,e;hl2i0l0HmNnLphn1rIvi1XyH;le,na;a,by,cIia,lH;a,en1;ey,ie;a,etAiH;!ca,el1Cka,z;arHia;is;a0Se0Oh05i03lVoKrIynH;di,th2;istHy05;al,i0;lPnMrIurH;tn1E;aJd2NiHn2Nri9;!nH;a,e,n1;!l1X;cepci59n4sH;tanHuelo;ce,za;eHleC;en,tA;aJeoIotH;il51;!pat3;ir8rJudH;etAiH;a,ne;a,e,iH;ce,sZ;a3er3ndH;i,y;aReNloe,rH;isJyH;stH;al;sy,tH;a1Ren,iHy;!an1e,n1;deJlseIrH;!i8yl;a,y;li9;nMrH;isKlImH;ai9;a,eHotA;n1tA;!sa;d3elGtH;al,elG;cIlH;esAi44;el2ilH;e,ia,y;itlZlYmilXndWrOsMtHy5;aKeJhHri0;erHleCrDy;in1;ri0;li0ri0;a33sH;a32ie;a,iNlLmeJolIrH;ie,ol;!e,in1yn;lHn;!a,la;a,eHie,o7y;ne,y;na,sF;a0Hi0H;a,e,l1;is7l4;in,yn;a0Ie02iZlXoUrH;andSeQiJoIyH;an0nn;nwDok8;an3DdgLg0XtH;n2XtH;!aInH;ey,i,y;ny;etH;!t8;an0e,nH;da,na;i8y;bbi8glarIlo05nH;i7n4;ka;ancHossom,ythe;a,he;an17lja0nHsm3I;i7tH;ou;aUcky,linTni7rPssOtJulaEvH;!erlH;ey,y;hJsy,tH;e,iHy8;e,na;!anH;ie,y;!ie;nHt6yl;adIiH;ce;etAi9;ay,da;!triH;ce,z;rbJyaH;rmH;aa;a3ie,o3ra;a2Sb2Md23g1Zi1Qj5l16m0Xn09oi,r04sUtTuPvOwa,yIzH;ra,u0;aKes6gJlIseH;!l;in;un;!nH;a,na;a,i2Ir2J;drJgus1RrIsteH;ja;el2;a,ey,i,y;aahua,he0;hIi2Gja,mi7s2DtrH;id;aMlIraqHt21;at;eIi8yH;!n;e,iHy;gh;!nH;ti;iJleIo6pi7;ta;en,n1tA;aHelG;!n1J;a00dje5eYgUiSjQnJohito,toHya;inetAnH;el5ia;!aKeIiHmJ;e,ka;!mHtA;ar4;!belIliFmU;sa;!le;a,eliH;ca;ka,sHta;a,sa;elHie;a,iH;a,ca,n1qH;ue;!tA;te;! JbImHstasiNya;ar2;el;cla3jul2pau5;aLberKeliJiHy;e,l2naH;!ta;a,ja;!ly;hGiIl2nB;da;a,ra;le;aWba,ePiMlKma,thJyH;a,c2sH;a,on,sa;ea;iHys0N;e,s0M;a,cIn1sHza;a,e,ha,on,sa;e,ia,ja;c2is6jaKksaKna,sJxH;aHia;!nd3;ia,saH;nd3;ra;ia;i0nIyH;ah,na;a,is,naEoud;la;c6da,leCmNnLsH;haElH;inHyY;g,n;!h;a,o,slH;ey;ee;en;at6g4nIusH;ti0;es;ie;aWdiTelMrH;eJiH;anMenH;a,e,ne;an0;na;!aLeKiIyH;nn;a,n1;a,e;!ne;!iH;de;e,lDsH;on;yn;!lH;i9yn;ne;aKbIiHrL;!gaK;ey,i8y;!e;gaH;il;dKliyJradhIs6;ha;ya;ah;a,ya",
3814 "Actor": "true¦aJbGcFdCengineIfAgardenIh9instructPjournalLlawyIm8nurse,opeOp5r3s1t0;echnCherapK;ailNcientJecretary,oldiGu0;pervKrgeon;e0oofE;ceptionGsearC;hotographClumbColi1r0sychologF;actitionBogrammB;cem6t5;echanic,inist9us4;airdress8ousekeep8;arm7ire0;fight6m2;eputy,iet0;ici0;an;arpent2lerk;ricklay1ut0;ch0;er;ccoun6d2ge7r0ssis6ttenda7;chitect,t0;ist;minist1v0;is1;rat0;or;ta0;nt",
3815 "Honorific": "true¦a01bYcQdPeOfiJgIhon,jr,king,lHmCoffic00p7queen,r3s0taoiseach,vice6;e1fc,gt,ir,r,u0;ltRpt,rg;cond liInBrgeaJ;abbi,e0;ar1p9s,v0;!erend; admirX;astOhd,r0vt;esideDi1of0;!essM;me mini4nce0;!ss;a3essrs,i2lle,me,r1s0;!tr;!s;stK;gistrate,j,r6yF;i3lb,t;en,ov;eld mar3rst l0;ady,i0;eutena0;nt;shG;sq,xcellency;et,oct6r,utchess;apt6hance4mdr,o0pl;lonel,m2ngress0unci3;m0wom0;an;dr,mand5;ll0;or;!ain;ldg,rig0;!adi0;er;d0sst,tty,yatullah;j,m0v;!ir0;al",
3816 "SportsTeam": "true¦0:1A;1:1H;2:1G;a1Eb16c0Td0Kfc dallas,g0Ihouston 0Hindiana0Gjacksonville jagua0k0El0Bm01newToQpJqueens parkIreal salt lake,sAt5utah jazz,vancouver whitecaps,w3yW;ashington 3est ham0Rh10;natio1Oredski2wizar0W;ampa bay 6e5o3;ronto 3ttenham hotspur;blue ja0Mrapto0;nnessee tita2xasC;buccanee0ra0K;a7eattle 5heffield0Kporting kansas0Wt3;. louis 3oke0V;c1Frams;marine0s3;eah15ounG;cramento Rn 3;antonio spu0diego 3francisco gJjose earthquak1;char08paA; ran07;a8h5ittsburgh 4ortland t3;imbe0rail blaze0;pirat1steele0;il3oenix su2;adelphia 3li1;eagl1philNunE;dr1;akland 3klahoma city thunder,rlando magic;athle0Mrai3;de0; 3castle01;england 7orleans 6york 3;city fc,g4je0FknXme0Fred bul0Yy3;anke1;ian0D;pelica2sain0C;patrio0Brevolut3;ion;anchester Be9i3ontreal impact;ami 7lwaukee b6nnesota 3;t4u0Fvi3;kings;imberwolv1wi2;rewe0uc0K;dolphi2heat,marli2;mphis grizz3ts;li1;cXu08;a4eicesterVos angeles 3;clippe0dodDla9; galaxy,ke0;ansas city 3nE;chiefs,roya0E; pace0polis colU;astr06dynamo,rockeTtexa2;olden state warrio0reen bay pac3;ke0;.c.Aallas 7e3i05od5;nver 5troit 3;lio2pisto2ti3;ge0;broncZnuggeM;cowbo4maver3;ic00;ys; uQ;arCelKh8incinnati 6leveland 5ol3;orado r3umbus crew sc;api5ocki1;brow2cavalie0india2;bengaWre3;ds;arlotte horAicago 3;b4cubs,fire,wh3;iteB;ea0ulR;diff3olina panthe0; c3;ity;altimore 9lackburn rove0oston 5rooklyn 3uffalo bilN;ne3;ts;cel4red3; sox;tics;rs;oriol1rave2;rizona Ast8tlanta 3;brav1falco2h4u3;nited;aw9;ns;es;on villa,r3;os;c5di3;amondbac3;ks;ardi3;na3;ls",
3817 "Uncountable": "true¦0:1I;1:1X;2:16;a1Rb1Jc1Ad17e10f0Ug0Nh0Ii0Ej0Dknowled1Ql08mYnews,oXpTrOsDt8vi7w3;a5ea0Bi4oo3;d,l;ldlife,ne;rmth,t0;neg17ol0Ctae;e6h5oothpaste,r3una;affTou3;ble,sers,t;ermod1Mund0;a,nnis;aBcene0Aeri2hAil9kittl2now,o8p6t4u3;g10nshi0Q;ati1Le3;am,el;ace1Ee3;ci2ed;ap,cc0;k,v0;eep,ingl2;d0Dfe18l3nd;m11t;a6e4ic3;e,ke0M;c3laxa0Isearch;ogni0Hrea0H;bi2in;aPe5hys1last9o3ress04;l3rk,w0;it1yA;a12trZ;bstetr1il,xygen;aAe8ilk,o5u3;mps,s3;ic;n3o0I;ey,o3;gamy;a3chan1;sl2t;chine3il,themat1; learn0Bry;aught0e5i4ogi0Su3;ck,g0I;ce,ghtn08ngui0QteratN;a3isM;th0;ewelAusti0L;ce,mp3nformaUtself;a3ortan0J;ti3;en0H;a6isto5o3;ck3mework,n3spitali0B;ey;ry;ir,libut,ppiD;ene6o4r3um,ymna0D;aCound;l3ssip;d,f; 3t1;editQpo3;ol;i7lour,o4urnit3;ure;od,rgive3uri0wl;ne3;ss;c9sh;conom1duca8lectr7n5quip6th1very3;body,o3thH;ne;joy3tertain3;ment;iciPon1;tiI;ar4iabet2raugh4;es;ts;aAelcius,h6iv1l5o3urrency;al,ld w3nfusiDttD;ar;ass1oth5;aos,e3;e4w3;ing;se;r7sh;a7eef,i4lood,owls,read,utt0;er;lliar4s3;on;ds;g3ss;ga3;ge;c8dvi7ero5ir4mnes3rt,thlet1;ty;craft;b1d3naut1;ynam1;ce;id,ou3;st1;ics",
3818 "Infinitive": "true¦0:6S;1:76;2:5C;3:74;4:73;5:67;6:6F;7:6Y;8:6Q;9:72;A:70;B:6X;C:5X;D:77;E:6L;F:5B;a6Kb66c57d4De3Xf3Jg3Dh37i2Uj2Sk2Ql2Hm26n23o1Yp1Jr0Rs06tYuTvOwHyG;awn,ield;aJe1Zhist6iIoGre6D;nd0rG;k,ry;pe,sh,th0;lk,nHrGsh,tEve;n,raD;d0t;aJiHoG;te,w;eGsB;!w;l6Jry;nHpGr4se;gra4Pli41;dGi9lo5Zpub3Q;erGo;mi5Cw1I;aMeLhKig5SoJrHuGwi7;ne,rn;aGe0Mi5Uu7y;de,in,nsf0p,v5J;r2ZuE;ank,reatC;nd,st;lk,rg1Qs9;aZcWeVhTi4Dkip,lSmRnee3Lo52pQtJuGwitE;bmBck,ff0gge7ppHrGspe5;ge,pri1rou4Zvi3;ly,o36;aLeKoJrHuG;dy,mb6;aFeGi3;ngthCss,tE;p,re;m,p;in,ke,r0Qy;la58oil,rink6;e1Zi6o3J;am,ip;a2iv0oG;ck,rtCut;arEem,le5n1r3tt6;aHo2rG;atEew;le,re;il,ve;a05eIisk,oHuG;in,le,sh;am,ll;a01cZdu8fYgXje5lUmTnt,pQquPsKtJvGwa5V;eGiew,o36;al,l,rG;se,t;aFi2u44;eJi7oItG;!o2rG;i5uc20;l3rt;mb6nt,r3;e7i2;air,eHlGo43r0K;a8y;at;aFemb0i3Zo3;aHeGi3y;a1nt;te,x;a5Dr0J;act1Yer,le5u1;a13ei3k5PoGyc6;gni2Cnci6rd;ch,li2Bs5N;i1nG;ge,k;aTerSiRlOoMrIuG;b21ll,mp,rGsh;cha1s4Q;ai1eIiDoG;cGdu8greAhibBmi1te7vi2W;eAlaim;di5pa2ss,veD;iDp,rtr46sGur;e,t;aHead,uG;g,n4;n,y;ck,le;fo34mBsi7;ck,iDrt4Mss,u1;bJccur,ff0pera9utweIverGwe;co47lap,ta22u1wG;helm;igh;ser3taF;eHotG;e,i8;ed,gle5;aMeLiIoHuG;ltip3Grd0;nit13ve;nHrr12sreprG;eseD;d,g6us;asu2lt,n0Nr4;intaFna4rHtG;ch,t0;ch,kGry;et;aMeLiJoGu1C;aHck,oGve;k,sC;d,n;ft,g35ke,mBnk,st2YveG;!n;a2Fc0Et;b0Nck,uG;gh,nE;iGno34;ck,ll,ss;am,oFuG;d4mp;gno2mQnGss3H;cOdica9flu0MhNsKtIvG;eGol3;nt,st;erGrodu8;a5fe2;i7tG;aGru5;ll;abBibB;lu1Fr1D;agi24pG;lemeDo22ro3;aKeIi2oHuG;nt,rry;n02pe,st;aGlp;d,t;nd6ppCrm,te;aKloAove1PrIuG;arGeAi15;ant39d;aGip,ow,umb6;b,sp;in,th0ze;aReaQiOlMoJrHuncG;ti3J;acGeshC;tu2;cus,lHrG;ce,eca7m,s30;d,l24;a1ZoG;at,od,w;gu2lGni1Xt,x;e,l;r,tu2;il,stCvG;or;a15cho,le5mSnPstNvalua9xG;a0AcLerKi7pGte19;a18eHi2laFoGreA;rt,se;ct,riG;en8;ci1t;el,han4;abGima9;li1J;ab6couXdHfor8ga4han8j03riEsu2t0vG;isi2Vy;!u2;body,er4pG;hasiGow0;ze;a07eUiLoKrHuG;mp;aHeAiG;ft;g,in;d4ubt;ff0p,re5sHvG;iZor8;aKcHliGmiApl1Btingui14;ke;oGuA;uGv0;ra4;gr1YppG;ear,ro3;cOeNfLliv0ma0Fny,pKsHterG;mi0G;cribe,er3iHtrG;oy;gn,re;a0Be0Ai5osB;eGi0By;at,ct;m,pC;iIlHrG;ea1;a2i06;de;ma4n8rGte;e,kC;a0Ae09h06i9l04oJrG;aHeGoAu0Hy;a9dB;ck,ve;llZmSnHok,py,uGv0;gh,nt;cePdu5fMsKtIvG;eGin8;rt,y;aFin0VrG;a7ibu9ol;iGtitu9;d0st;iHoGroD;rm;gu2rm;rn;biLfoKmaJpG;a2laF;in;re;nd;rt;ne;ap1e5;aGip,o1;im,w;aHeG;at,ck,w;llen4n4r4se;a1nt0;ll,ncIrGt0u1;eGry;!en;el;aSePloOoMrIuG;lGry;ly;igHuG;sh;htC;en;a7mb,o7rrGth0un8;ow;ck;ar,lHnefBtrG;ay;ie3ong;ng,se;band0Jc0Bd06ffo05gr04id,l01mu1nYppTrQsKttGvoid,waB;acIeHra5;ct;m0Fnd;h,k;k,sG;eIiHocia9uG;me;gn,st;mb6rt;le;chHgGri3;ue;!i3;eaJlIroG;aEve;ch;aud,y;l,r;noun8sw0tG;icipa9;ce;lHt0;er;e4ow;ee;rd;aRdIju7mBoR;it;st;!reA;ss;cJhie3knowled4tiva9;te;ge;ve;eIouDu1;se;nt;pt;on",
3819 "Unit": "true¦0:19;a14b12c0Od0Ne0Lf0Gg0Ch09in0Hjoule0k02l00mNnMoLpIqHsqCt7volts,w6y4z3°2µ1;g,s;c,f,n;b,e2;a0Nb,d0Dears old,o1;tt0H;att0b;able4b3d,e2on1sp;!ne0;a2r0D;!l,sp;spo04; ft,uare 1;c0Id0Hf3i0Fkilo0Jm1ya0E;e0Mil1;e0li0H;eet0o0D;t,uart0;ascals,e2i1ou0Pt;c0Mnt0;rcent,t02;hms,uYz;an0JewtT;/s,b,e9g,i3l,m2p1²,³;h,s;!²;!/h,cro5l1;e1li08;! pFs1²;! 1;anEpD;g06s0B;gQter1;! 2s1;! 1;per second;b,i00m,u1x;men0x0;b,elvin0g,ilo2m1nR;!/h,ph,²;byZgXmeter1;! p2s1;! p1;er1; hour;e1g,r0z;ct1rtz0;aXogQ;al2b,igAra1;in0m0;!l1;on0;a4emtPl2t1;²,³; oz,uid ou1;nce0;hrenheit0rad0;b,x1;abyH;eciCg,l,mA;arat0eAg,m9oulomb0u1;bic 1p0;c5d4fo3i2meAya1;rd0;nch0;ot0;eci2;enti1;me4;!²,³;lsius0nti1;g2li1me1;ter0;ram0;bl,y1;te0;c4tt1;os1;eco1;nd0;re0;!s",
3820 "Organization": "true¦0:46;a3Ab2Qc2Ad21e1Xf1Tg1Lh1Gi1Dj19k17l13m0Sn0Go0Dp07qu06rZsStFuBv8w3y1;amaha,m0Xou1w0X;gov,tu2S;a3e1orld trade organizati41;lls fargo,st1;fie22inghou16;l1rner br3D;-m11gree31l street journ25m11;an halNeriz3Wisa,o1;dafo2Gl1;kswagLvo;bs,kip,n2ps,s1;a tod2Rps;es35i1;lev2Xted natio2Uv; mobi2Kaco bePd bMeAgi frida9h3im horto2Tmz,o1witt2W;shiba,y1;ota,s r Y;e 1in lizzy;b3carpen33daily ma2Xguess w2holli0rolling st1Ms1w2;mashing pumpki2Ouprem0;ho;ea1lack eyed pe3Fyrds;ch bo1tl0;ys;l2s1;co,la m12;efoni07us;a6e4ieme2Gnp,o2pice gir5ta1ubaru;rbucks,to2N;ny,undgard1;en;a2Rx pisto1;ls;few25insbu26msu1X;.e.m.,adiohead,b6e3oyal 1yan2X;b1dutch she4;ank;/max,aders dige1Ed 1vl32;bu1c1Uhot chili peppe2Klobst28;ll;c,s;ant2Vizno2F;an5bs,e3fiz24hilip morrBi2r1;emier27octer & gamb1Rudenti14;nk floyd,zza hut;psi28tro1uge08;br2Qchina,n2Q; 2ason1Xda2G;ld navy,pec,range juli2xf1;am;us;a9b8e5fl,h4i3o1sa,wa;kia,tre dame,vart1;is;ke,ntendo,ss0K;l,s;c,st1Etflix,w1; 1sweek;kids on the block,york08;a,c;nd1Us2t1;ional aca2Fo,we0Q;a,cYd0O;aAcdonald9e5i3lb,o1tv,yspace;b1Nnsanto,ody blu0t1;ley crue,or0O;crosoft,t1;as,subisO;dica3rcedes2talli1;ca;!-benz;id,re;'s,s;c's milk,tt13z1Y;'ore09a3e1g,ittle caesa1Ktd;novo,x1;is,mark; pres5-z-boy,bour party;atv,fc,kk,m1od1K;art;iffy lu0Lo3pmorgan1sa;! cha1;se;hnson & johns1Sy d1R;bm,hop,n1tv;c,g,te1;l,rpol; & m,asbro,ewlett-packaTi3o1sbc,yundai;me dep1n1J;ot;tac1zbollah;hi;eneral 6hq,l5mb,o2reen d0Iu1;cci,ns n ros0;ldman sachs,o1;dye1g0B;ar;axo smith kliZencore;electr0Im1;oto0V;a3bi,da,edex,i1leetwood mac,oGrito-l0A;at,nancial1restoV; tim0;cebook,nnie mae;b06sa,u3xxon1; m1m1;ob0H;!rosceptics;aiml0Ae5isney,o3u1;nkin donuts,po0Wran dur1;an;j,w j1;on0;a,f leppa3ll,p2r spiegZstiny's chi1;ld;eche mode,t;rd;aEbc,hBi9nn,o3r1;aigsli5eedence clearwater reviv1ossra05;al;!ca c5l4m1o0Ast05;ca2p1;aq;st;dplMgate;ola;a,sco1tigroup;! systems;ev2i1;ck fil-a,na daily;r0Hy;dbury,pital o1rl's jr;ne;aGbc,eCfAl6mw,ni,o2p,r1;exiteeWos;ei3mbardiJston 1;glo1pizza;be;ng;ack & deckFo2ue c1;roX;ckbuster video,omingda1;le; g1g1;oodriN;cht3e ge0n & jer2rkshire hathaw1;ay;ryH;el;nana republ3s1xt5y5;f,kin robbi1;ns;ic;bXcSdidRerosmith,ig,lLmFnheuser-busEol,ppleAr7s3t&t,v2y1;er;is,on;hland2s1;n,ociated F; o1;il;by4g2m1;co;os; compu2bee1;'s;te1;rs;ch;c,d,erican3t1;!r1;ak; ex1;pre1;ss; 4catel2t1;air;!-luce1;nt;jazeera,qae1;da;as;/dc,a3er,t1;ivisi1;on;demy of scienc0;es;ba,c",
3821 "Demonym": "true¦0:16;1:13;a0Wb0Nc0Cd0Ae09f07g04h02iYjVkTlPmLnIomHpDqatari,rBs7t5u4v3wel0Rz2;am0Fimbabwe0;enezuel0ietnam0H;g9krai1;aiwThai,rinida0Iu2;ni0Qrkmen;a4cot0Ke3ingapoOlovak,oma0Tpa05udRw2y0X;edi0Kiss;negal0Br08;mo0uU;o6us0Lw2;and0;a3eru0Hhilipp0Po2;li0Ertugu06;kist3lesti1na2raguay0;ma1;ani;amiZi2orweP;caragu0geri2;an,en;a3ex0Mo2;ngo0Erocc0;cedo1la2;gasy,y08;a4eb9i2;b2thua1;e0Dy0;o,t02;azakh,eny0o2uwaiti;re0;a2orda1;ma0Bp2;anN;celandic,nd4r2sraeli,ta02vo06;a2iT;ni0qi;i0oneV;aiDin2ondur0unN;di;amDe2hanai0reek,uatemal0;or2rm0;gi0;i2ren7;lipino,n4;cuadoVgyp6ngliJsto1thiopi0urope0;a2ominXut4;niH;a9h6o4roa3ub0ze2;ch;ti0;lom2ngol5;bi0;a6i2;le0n2;ese;lifor1m2na3;bo2eroo1;di0;angladeshi,el8o6r3ul2;gaG;aziBi2;ti2;sh;li2s1;vi0;aru2gi0;si0;fAl7merBngol0r5si0us2;sie,tr2;a2i0;li0;gent2me1;ine;ba1ge2;ri0;ni0;gh0r2;ic0;an",
3822 "Possessive": "true¦anyAh5its,m3noCo1sometBthe0yo1;ir1mselves;ur0;!s;i8y0;!se4;er1i0;mse2s;!s0;!e0;lf;o1t0;hing;ne",
3823 "Currency": "true¦$,aud,bScQdLeurKfJgbp,hkd,iIjpy,kGlEp8r7s3usd,x2y1z0¢,£,¥,ден,лв,руб,฿,₡,₨,€,₭,﷼;lotySł;en,uanR;af,of;h0t5;e0il5;k0q0;elM;iel,oubleLp,upeeL;e2ound st0;er0;lingI;n0soH;ceGn0;ies,y;e0i8;i,mpi7;n,r0wanzaCyatC;!onaBw;ls,nr;ori7ranc9;!o8;en3i2kk,o0;b0ll2;ra5;me4n0rham4;ar3;ad,e0ny;nt1;aht,itcoin0;!s",
3824 "City": "true¦a2Wb26c1Wd1Re1Qf1Og1Ih1Ai18jakar2Hk0Zl0Tm0Gn0Co0ApZquiYrVsLtCuBv8w3y1z0;agreb,uri1Z;ang1Te0okohama;katerin1Hrev34;ars3e2i0rocl3;ckl0Vn0;nipeg,terth0W;llingt1Oxford;aw;a1ern1Mi0;en2Hlni2Z;lenc2Uncouv0Gr2Gughn;lan bat0Dtrecht;a6bilisi,e5he4i3o2rondheim,u0;nVr0;in,ku;kyo,ronIulouC;anj23l13miso2Jra2A; haJssaloni0X;gucigalpa,hr2Ol av0L;i0llinn,mpe2Bngi07rtu;chu22n2MpT;a3e2h1kopje,t0ydney;ockholm,uttga12;angh1Fenzh1X;o0KvZ;int peters0Ul3n0ppo1F; 0ti1B;jo0salv2;se;v0z0Q;adU;eykjavik,i1o0;me,sario,t25;ga,o de janei17;to;a8e6h5i4o2r0ueb1Qyongya1N;a0etor24;gue;rt0zn24; elizabe3o;ls1Grae24;iladelph1Znom pe07oenix;r0tah tik19;th;lerJr0tr10;is;dessa,s0ttawa;a1Hlo;a2ew 0is;delTtaip0york;ei;goya,nt0Upl0Uv1R;a5e4i3o1u0;mb0Lni0I;nt0scH;evideo,real;l1Mn01skolc;dellín,lbour0S;drid,l5n3r0;ib1se0;ille;or;chest0dalWi0Z;er;mo;a4i1o0vAy01;nd00s angel0F;ege,ma0nz,sbZverpo1;!ss0;ol; pla0Iusan0F;a5hark4i3laipeda,o1rak0uala lump2;ow;be,pavog0sice;ur;ev,ng8;iv;b3mpa0Kndy,ohsiu0Hra0un03;c0j;hi;ncheMstanb0̇zmir;ul;a5e3o0; chi mi1ms,u0;stI;nh;lsin0rakliG;ki;ifa,m0noi,va0A;bu0SiltD;alw4dan3en2hent,iza,othen1raz,ua0;dalaj0Gngzhou;bu0P;eUoa;sk;ay;es,rankfu0;rt;dmont4indhovU;a1ha01oha,u0;blRrb0Eshanbe;e0kar,masc0FugavpiJ;gu,je0;on;a7ebu,h2o0raioJuriti01;lo0nstanJpenhagNrk;gFmbo;enn3i1ristchur0;ch;ang m1c0ttagoL;ago;ai;i0lgary,pe town,rac4;ro;aHeBirminghWogoAr5u0;char3dap3enos air2r0sZ;g0sa;as;es;est;a2isba1usse0;ls;ne;silPtisla0;va;ta;i3lgrade,r0;g1l0n;in;en;ji0rut;ng;ku,n3r0sel;celo1ranquil0;la;na;g1ja lu0;ka;alo0kok;re;aBb9hmedabad,l7m4n2qa1sh0thens,uckland;dod,gabat;ba;k0twerp;ara;m5s0;terd0;am;exandr0maty;ia;idj0u dhabi;an;lbo1rh0;us;rg",
3825 "Country": "true¦0:38;1:2L;a2Wb2Dc21d1Xe1Rf1Lg1Bh19i13j11k0Zl0Um0Gn05om3CpZqat1JrXsKtCu6v4wal3yemTz2;a24imbabwe;es,lis and futu2X;a2enezue31ietnam;nuatu,tican city;.5gTkraiZnited 3ruXs2zbeE;a,sr;arab emirat0Kkingdom,states2;! of am2X;k.,s.2; 27a.;a7haBimor-les0Bo6rinidad4u2;nis0rk2valu;ey,me2Xs and caic1T; and 2-2;toba1J;go,kel0Ynga;iw2Vji2nz2R;ki2T;aCcotl1eBi8lov7o5pa2Bri lanka,u4w2yr0;az2ed9itzerl1;il1;d2Qriname;lomon1Vmal0uth 2;afr2IkLsud2O;ak0en0;erra leoEn2;gapo1Wt maart2;en;negKrb0ychellY;int 2moa,n marino,udi arab0;hele24luc0mart1Z;epublic of ir0Com2Cuss0w2;an25;a3eHhilippinTitcairn1Ko2uerto riM;l1rtugE;ki2Bl3nama,pua new0Tra2;gu6;au,esti2;ne;aAe8i6or2;folk1Gth3w2;ay; k2ern mariana1B;or0M;caragua,ger2ue;!ia;p2ther18w zeal1;al;mib0u2;ru;a6exi5icro09o2yanm04;ldova,n2roc4zamb9;a3gol0t2;enegro,serrat;co;c9dagascZl6r4urit3yot2;te;an0i14;shall0Vtin2;ique;a3div2i,ta;es;wi,ys0;ao,ed00;a5e4i2uxembourg;b2echtenste10thu1E;er0ya;ban0Gsotho;os,tv0;azakh1De2iriba02osovo,uwait,yrgyz1D;eling0Jnya;a2erF;ma15p1B;c6nd5r3s2taly,vory coast;le of m19rael;a2el1;n,q;ia,oI;el1;aiSon2ungary;dur0Mg kong;aAermany,ha0Pibralt9re7u2;a5ern4inea2ya0O;!-biss2;au;sey;deloupe,m,tema0P;e2na0M;ce,nl1;ar;bTmb0;a6i5r2;ance,ench 2;guia0Dpoly2;nes0;ji,nl1;lklandTroeT;ast tim6cu5gypt,l salv5ngl1quatorial3ritr4st2thiop0;on0; guin2;ea;ad2;or;enmark,jibou4ominica3r con2;go;!n B;ti;aAentral african 9h7o4roat0u3yprQzech2; 8ia;ba,racao;c3lo2morPngo-brazzaville,okFsta r03te d'ivoiK;mb0;osD;i2ristmasF;le,na;republic;m2naTpe verde,yman9;bod0ero2;on;aFeChut00o8r4u2;lgar0r2;kina faso,ma,undi;azil,itish 2unei;virgin2; is2;lands;liv0nai4snia and herzegoviGtswaGuvet2; isl1;and;re;l2n7rmuF;ar2gium,ize;us;h3ngladesh,rbad2;os;am3ra2;in;as;fghaFlCmAn5r3ustr2zerbaijH;al0ia;genti2men0uba;na;dorra,g4t2;arct6igua and barbu2;da;o2uil2;la;er2;ica;b2ger0;an0;ia;ni2;st2;an",
3826 "Region": "true¦0:1U;a20b1Sc1Id1Des1Cf19g13h10i0Xj0Vk0Tl0Qm0FnZoXpSqPrMsDtAut9v6w3y1zacatec22;o05u1;cat18kZ;a1est vi4isconsin,yomi14;rwick0shington1;! dc;er2i1;rgin1S;acruz,mont;ah,tar pradesh;a2e1laxca1DuscaA;nnessee,x1R;bas0Kmaulip1QsmJ;a6i4o2taf0Ou1ylh13;ffVrr00s0Y;me10no1Auth 1;cSdR;ber1Ic1naloa;hu0Sily;n2skatchew0Rxo1;ny; luis potosi,ta catari1I;a1hode7;j1ngp02;asth0Mshahi;inghai,u1;e1intana roo;bec,ensWreta0E;ara4e2rince edward1; isU;i,nnsylv1rnambu02;an14;!na;axa0Ndisha,h1klaho1Bntar1reg4x04;io;ayarit,eBo3u1;evo le1nav0L;on;r1tt0Rva scot0X;f6mandy,th1; 1ampton0;c3d2yo1;rk0;ako0Y;aroli0V;olk;bras0Xva01w1; 2foundland1;! and labrador;brunswick,hamp0jers1mexiJyork state;ey;a6i2o1;nta0Nrelos;ch3dlanBn2ss1;issippi,ouri;as geraGneso0M;igQoacQ;dhya,harasht04ine,ni3r1ssachusetts;anhao,y1;land;p1toba;ur;anca0e1incoln0ouis8;e1iH;ds;a1entucky,hul0A;ns08rnata0Dshmir;alis1iangxi;co;daho,llino2nd1owa;ia05;is;a2ert1idalEunA;ford0;mp0waii;ansu,eorgWlou5u1;an2erre1izhou,jarat;ro;ajuato,gdo1;ng;cester0;lori2uji1;an;da;sex;e4o2uran1;go;rs1;et;lawaErby0;a8ea7hi6o1umbrH;ahui4l3nnectic2rsi1ventry;ca;ut;iMorado;la;apEhuahua;ra;l8m1;bridge0peche;a5r4uck1;ingham0;shi1;re;emen,itish columb3;h2ja cal1sque,var2;iforn1;ia;guascalientes,l4r1;izo2kans1;as;na;a2ber1;ta;ba2s1;ka;ma",
3827 "Place": "true¦a07b05cZdYeXfVgRhQiOjfk,kMlKmHneEoDp9que,rd,s8t5u4v3w0yyz;is1y0;!o;!c;a,t;pYsafa,t;e1he 0;bronx,hamptons;nn,x;ask,fo,oho,t,under6yd;a2e1h0;l,x;k,nnK;!cifX;kla,nt,rd;b1w eng0;land;!r;a1co,i0t,uc;dKnn;libu,nhattS;a0gw,hr;s,x;an0ul;!s;a0cn,da,ndianMst;!x;arlem,kg,nd,wy;a2re0;at 0enwich;britain,lak6;!y village;co,l0ra;!a;urope,verglad2;ak,en,fw,ist,own4xb;al4dg,gk,hina3l2o1r0;es;lo,nn;!t;town;!if;cn,e0kk,lvd,rooklyn;l air,verly hills;frica,lta,m5ntarct2r1sia,tl0ve;!ant1;ct0iz;ic0; oce0;an;ericas,s",
3828 "WeekDay": "true¦fri2mon2s1t0wednesd3;hurs1ues1;aturd1und1;!d0;ay0;!s",
3829 "Month": "true¦aBdec9feb7j2mar,nov9oct1sep0;!t8;!o8;an3u0;l1n0;!e;!y;!u1;!ru0;ary;!em0;ber;pr1ug0;!ust;!il",
3830 "Date": "true¦ago,t2week0yesterd4; e0e0;nd;mr2o0;d0morrow;ay;!w",
3831 "FirstName": "true¦aKblair,cGdevFgabrieEhinaDjBk8l7m3nelly,quinn,re2sh0;ay,e0iloh;a,lby;g6ne;a1el0ina,org5;!okuh9;naia,r0;ion,lo;ashawn,uca;asCe1ir0rE;an;lsAnyat2rry;am0ess6ie,ude;ie,m5;ta;le;an,on;as2h0;arl0eyenne;ie;ey,sidy;lex2ndr1ubr0;ey;a,ea;is",
3832 "LastName": "true¦0:9F;1:9V;2:9X;3:9H;4:9N;5:8J;6:9K;7:A0;8:9E;9:88;A:77;B:6E;C:6J;a9Ub8Lc7Kd6Xe6Rf6Dg5Vh58i54j4Pk45l3Nm2Rn2Eo26p1Nquispe,r17s0Ft05vVwOxNyGzD;aytsADhD;aDou,u;ng,o;aGeun7ZiDoshiA9un;!lD;diDmaz;rim,z;maDng;da,guc97mo6UsDzaA;aAhiA7;iao,u;aHeGiEoDright,u;jc8Sng;lDmm0nkl0sniewsA;liA1s2;b0iss,lt0;a5Rgn0lDng,tanabe;k0sh;aHeGiEoDukB;lk5roby5;dBllalDnogr2Zr0Zss0val37;ba,obos;lasEsel7N;lGn dFrg8EsEzD;qu7;ily9Oqu7silj9O;en b35ijk,yk;enzue95verde;aLeix1JhHi4j6ka3IoGrFsui,uD;om4ZrD;c4n0un1;an,embl8TynisA;dor95lst31m3rr9th;at5Mi7LoD;mErD;are6Ylaci64;ps2s0Y;hirBkah8Dnaka;a00chWeThPiNmKoItFuEvDzabo;en8Aobod34;ar7bot3lliv4zuA;aEein0oD;i67j3Lyan8V;l6rm0;kol5lovy5re6Psa,to,uD;ng,sa;iDy5Z;rn5tD;!h;l5YmDngh,rbu;mo6Do6J;aFeDimizu;hu,vchD;en7Cuk;la,r17;gu8mDoh,pulve8Trra4R;jDyD;on5;evi6Filtz,miDneid0roed0ulz,warz;dEtD;!z;!t;ar42h6ito,lFnDr3saAto,v3;ch7d0AtDz;a4Pe,os;as,ihBm3Zo0Q;aOeNiKoGuEyD;a66oo,u;bio,iz,sD;so,u;bEc7Bdrigue57g03j73mDosevelt,ssi,ta7Nux,w3Z;a4Be0O;ertsDins2;!on;bei0LcEes,vDzzo;as,e8;ci,hards2;ag4es,it0ut0y9;dFmEnDsmu7Zv5F;tan1;ir7os;ic,u;aSeLhJiGoErDut6;asad,if5Zochazk1W;lishc24pDrti62u55we66;e2Tov48;cEe09nD;as,to;as60hl0;aDillips;k,m,n5K;de3AetIna,rGtD;ersErovDtersC;!a,ic;en,on;eDic,ry,ss2;i8ra,tz,z;ers;h71k,rk0tEvD;ic,l3T;el,t2O;bJconnor,g2ClGnei5PrEzD;demir,turk;ella3MtDwe5N;ega,iz;iDof6GsC;vDyn1F;ei8;aPri1;aLeJguy1iFoDune44ym4;rodahl,vDwak;ak3Uik5otn56;eEkolDlsCx2;ic,ov6X;ls1miD;!n1;ils2mD;co42ec;gy,kaEray4varD;ro;jiDmu8shiD;ma;aXcVeQiPoIuD;lGnFrDssoli5T;atDpUr68;i,ov3;oz,te4B;d0l0;h4lIo0HrEsDza0Z;er,s;aFeEiDoz5r3Ete4B;!n6F;au,i8no,t4M;!l9;i2Rl0;crac5Ohhail5kke3Qll0;hmeGij0j2ElFndErci0ssiDyer19;!er;e3Bo2Z;n0Io;dBti;cartDlaughl6;hy;dMe6Dgnu5Ei0jer34kLmJnci59rFtEyD;er,r;ei,ic,su1N;iEkBqu9roqu6tinD;ez,s;a54c,nD;!o;a52mD;ad5;e5Oin1;rig4Ns1;aSeMiIoGuEyD;!nch;k3nDo;d,gu;mbarDpe2Rvr3;di;!nDu,yana1R;coln,dD;bDholm;erg;bed5TfeGhtFitn0kaEn6rDw2G;oy;!j;in1on1;bvDvD;re;iDmmy,rsCu,voie;ne,t11;aTennedy,h4iSlQnez46oJrGuEvar4woD;k,n;cerDmar58znets5;a,o2G;aDem0i2Zyeziu;sni3PvD;ch3U;bay4Frh0Jsk0TvaFwalDzl5;czDsA;yk;cFlD;!cDen3Q;huk;!ev3ic,s;e6uiveD;rt;eff0l3mu8nnun1;hn,lloe,minsArEstra31to,ur,yDzl5;a,s0;j0GlsC;aMenLha2Pim0QoEuD;ng,r3;e2JhFnErge2Ju2NvD;anB;es,ss2;anEnsD;en,on,t2;nesDsC;en,s1;ki26s1;cGkob3RnsDrv06;en,sD;enDon;!s;ks2obs1;brahimBglesi3Ake4Ll0CnoZoneFshikEto,vanoD;u,v4A;awa;scu;aPeIitchcock,jaltal6oFrist46uD;!aDb0gh9ynh;m4ng;a23dz3fEjga2Sk,rDx3B;ak0Yvat;er,fm3B;iGmingw3NnErD;nand7re8;dDriks1;ers2;kkiEnD;on1;la,n1;dz3g1lvoLmJnsCqIrr0SsFuEyD;as36es;g1ng;anEhiD;mo0Q;i,ov08;ue;alaD;in1;rs1;aMeorgLheorghe,iJjonIoGrEuDw2;o,staf2Utierr7zm4;ayDg3iffitUub0;li1G;lub3Rme0JnD;calv9zale0I;aj,i;l,mDordaL;en7;iev3B;gnJlGmaFnd2No,rDs2Nuthi0;cDza;ia;ge;eaElD;agh0i,o;no;e,on;ab0erMiIjeldsted,lor9oGrFuD;cDent9ji3F;hs;an1Wiedm4;ntaDrt6st0urni0;na;lipEsD;ch0;ovD;!ic;hatBnandeVrD;arDei8;a,i;ov3;dHinste6riksCsDva0D;cob2ZpDtra2X;inoDosiM;za;en,s2;er,is2wards;aUeMiKjurhuJoHrisco0YuEvorakD;!oQ;arte,boEmitru,rDt2U;and,ic;is;g4he0Hmingu7n2Ord19tD;to;us;aDmitr29ssanayake;s,z; GbnaFlEmirDrvis1Lvi,w4;!ov3;gado,ic;th;bo0groot,jo03lEsilDvri9;va;a cruz,e2uD;ca;hl,mcevsAnErw6t2EviD;d5es,s;ieDku1S;ls1;ki;a05e00hNiobMlarkLoFrD;ivDuz;elli;h1lGntFop0rDs26x;byn,reD;a,ia;i,rer0O;em4liD;ns;!e;anu;aLeIiu,oGriDuJwe;stD;eDiaD;ns1;i,ng,uFwDy;!dhury;!n,onEuD;ng;!g;kEnDtterjee,v7;!d,g;ma,raboD;rty;bGl09ng3rD;eghetEnD;a,y;ti;an,ota0M;cer9lder2mpbeIrFstDvadi08;iDro;llo;doEt0uDvalho;so;so,zo;ll;es;a09eXhUiSlNoGrFyD;rne,tyD;qi;ank5iem,ooks,yant;gdan5nFruya,su,uchEyHziD;c,n5;ard;darDik;enD;ko;ov;aEondD;al;nEzD;ev3;co;ancRshwD;as;a01oDuiy4;umDwmD;ik;ckNethov1gu,ktLnJrD;gGisFnD;ascoDds1;ni;ha;er,mD;ann;gtDit7nett;ss2;asD;hi;er,ham;b3ch,ez,hMiley,kk0nHrDu0;bEnDua;es,i0;ieDosa;ri;dDik;a8yopadhyD;ay;ra;er;k,ng;ic;cosZdYguilXkhtXlSnJrGsl4yD;aEd6;in;la;aEsl4;an;ujo,ya;dFgelD;ovD;!a;ersGov,reD;aDjL;ss1;en;en,on,s2;on;eksejGiyGmeiFvD;ar7es;ez;da;ev;ar;ams;ta",
3833 "MaleName": "true¦0:E5;1:D6;2:DO;3:AY;4:D2;5:CG;6:CW;7:C8;8:B6;9:DL;A:DK;B:A6;C:C2;aCObBLcAJd9He8Nf85g7Ih6Ui6Ej5Ek52l4Dm35n2To2Np2Fqu2Dr1Ls11t0Eu0Dv07wTxSyIzD;aDor0;cDh9Tkaria,n5W;hEkD;!aCM;ar5WeCL;aLoFuD;sDu2KvBY;if,uf;nFsEusD;ouf,sD;ef;aDg;s,tD;an,h0;hli,nBMssX;avi3ho4;aMeKiFoDyaC2;jcie8Clfgang,odrow,utD;!er;lDnst1;bFey,frD1lD;aBDiD;am,e,s;e9Fur;i,nde8sD;!l7t1;de,lErr9yD;l1ne;lDt3;aAAy;aGiDladimir,ojte7Z;cEha0kt69nceDrgAJva0;!nt;e3Vt67;lentDnA5;in4Y;ghBVlyss5Cnax,sm0;aXeShOiMoHrFuEyD;!l3ro6s1;nAr5C;avAWeDist0oy,um0;ntAOv5Zy;bGdFmDny;!as,mDoharu;aCTie,y;!d;iBy;mDt5;!my,othy;adFeoEia8GomD;!as;!do8P;!de5;dGrD;en9LrD;an9KeDy;ll,n9J;!dy;dgh,ha,iDnn3req,tsu4T;cB5ka;aTcotRePhLiJoHpenc3tDur1Vylve9Kzym1;anFeDua8D;f0phBTvDwa8C;e62ie;!islaw,l7;lom1nBFuD;leyma6ta;dDlBm1yabonga;!dhart7Bn7;aFeD;lDrm0;d1t1;h7Une,qu10un,wn,y6;aDbasti0k2Al4Rrg4Oth,ymoAU;m5n;!tD;!ie,y;lEmDnti2Eq5Bul;!ke5MmCu4;ik,vato7X;aYeUheAAiQoHuEyD;an,ou;b7NdEf5pe7SssD;!elBZ;ol3Fy;an,bKcJdIel,geHh0landBQmGnFry,sEyD;!ce;coe,s;!aAHnC;an,eo;l47r;e5Og3n7olfo,ri7A;co,ky;bCeB7;cDl7;ar6Pc6OhEkDo;!ey,ie,y;a99ie;gEid,ub9x,yDza;an1InY;gA8iD;naA4s;ch70fa4lHmGndFpha4sEul,wi2HyD;an,mo82;h7Vm5;alBDol2Uy;iATon;f,ph;ent2inD;cy,t1;aIeGhilFier72ol,rD;aka16eD;m,st1;!ip,lip;dALrcy,tD;ar,e3Gr1X;b4Kdra7Ft4ZulD;!o17;ctav3Fi3liv3mAFndrej,rHsEtDumAw9;is,to;aEcAkAm0vD;al5Z;ma;i,l53vL;aLeJiFoDu3A;aDel,j5l0ma0r3K;h,m;cEg4i49kD;!au,h7Uola;holBkDolB;!olB;al,d,il,ls1vD;il8Y;hom,thD;anDy;!a4i4;aZeWiMoHuEyD;l2Jr1;hamEr6XstaD;fa,p5C;ed,mH;di0We,hamFis2FntEsDussa;es,he;e,y;ad,ed,mD;ad,ed;cIgu4hai,kGlFnEtchD;!e8;a8Aik;house,o0Bt1;ae5YeA4olD;aj;ah,hDk7;aEeD;al,l;el,l;hElv2rD;le,ri8v2;di,met;ay0ck,hTjd,ks2DlRmadWnQrKs1tFuricExD;!imilian9Nwe8;e,io;eGhEiBtDus,yB;!eo,hew,ia;eDis;us,w;j,o;cHio,kGlFqu7Dsha8tDv2;iDy;!m,n;in,on;!el,oPus;!el9IoOus;iGu4;achDcolm,ik;ai,y;amEdi,eDmoud;sh;adDm5T;ou;aXeQiOlo3EoKuEyD;le,nd1;cGiFkDth3uk;aDe;!s;gi,s,z;as,iaD;no;g0nn7SrenFuDv8Jwe8;!iD;e,s;!zo;am,oD;n4r;a8Cevi,la5JnIoGst3thaFvD;eDi;nte;bo;!nD;!a6Sel;!ny;mFnErDur5Hwr5H;ry,s;ce,d1;ar,o5A;aLeGhaled,iDrist5Iu4Vy6X;er0p,rD;by,k,ollD;os;en0iGnDrmit,v44;!dEnDt5Z;e1Ay;a8ri59;r,th;cp3j5m66na73rEspAthem,uD;ri;im,l;a02eUiSoGuD;an,lDst2;en,iD;an,en,o,us;aNeLhnKkubBnIrGsD;eEhDi8Bue;!ua;!ph;dDge;an,i,on;!aDny;h,s,th5I;!ath5Hie,nC;!l,sDy;ph;o,qu2;an,mD;!mC;d,ffIrFsD;sDus;!e;a6BemEmai6oDry;me,ni0Y;i7Ty;!e60rD;ey,y;cKd9kImHrFsEvi3yD;!d9s1;on,p3;ed,od,rDv56;e5Nod;al,es4Xis1;a,e,oDub;b,v;k,ob,quD;es;aWbQchiPgNkeMlija,nuLonut,rJsFtDv0;ai,suD;ki;aEha0i7DmaDsac;el,il;ac,iaD;h,s;a,vinDw2;!g;k,nngu5S;!r;nacDor;io;ka;ai,rahD;im;aPeJoIuDydA;be2KgGmber4WsD;eyEsD;a2e2;in,n;h,o;m3ra3Gsse2wa4B;aHctGitGnrErD;be2Dm0;iDy;!q11;or;th;bMlLmza,nKo,rFsEyD;a4Jd9;an,s0;lGo50rFuDv7;hi4Gki,tD;a,o;is1y;an,ey;k,s;!im;ib;aVeRiPlenOoLrHuD;ilEsD;!tavo;herme,lerD;mo;aFegDov3;!g,orD;io,y;dy,h5Wnt;nzaErD;an,d1;lo;!n;lbe5Ano,oD;rg3Hvan5A;ne,oFrD;aDry;ld,rd5H;ffr7rge;brEl9rDv2;la28r3Sth,y;e3EielD;!i5;aTePiNlLorr0NrD;anFedDitz;!dCeDri2B;ri2A;cFkD;!ie,lD;in,yn;esLisD;!co,z36;etch3oD;yd;d4lDnn,onn;ip;deriFliEng,rnD;an06;pe,x;co;bi0di,hd;ar04dZfrYit0lSmKnHo2rFsteb0th0uge6vDym9zra;an,eD;ns,re36;gi,i0DnDrol,v2w2;est4Pie;oEriqDzo;ue;ch;aJerIiEmD;aIe2Z;lErD;!h0;!iD;o,s;s1y;nu4;be0Cd1iGliFmEt1viDwood;n,s;er,o;ot1Ys;!as,j4NsD;ha;a2en;!dCgAmGoEuEwD;a2Din;arD;do;o0Wu0W;l,nD;est;a01eRiOoHrGuFwEylD;an,l0;ay6ight;a6dl7nc0st2;ag0ew;minGnEri0ugDvydBy2D;!lB;!a2MnDov0;e8ie,y;go,iDykB;cDk;!k;armuEeDll1on,rk;go;id;anKj0lbeJmetri5nHon,rGsFvEwDxt3;ay6ey;en,in;hawn,mo0B;ek,ri0I;is,nDv3;is,y;rt;!dD;re;an,lNmLnKrGvD;e,iD;! lucDd;as,ca;en,iFne8rDyl;eDin,yl;l3Bn;n,o,us;!e,i4ny;iDon;an,en,on;e,lB;as;a09e07hYiar0lNoIrGuEyrD;il,us;rtD;!is;aDistob0U;ig;dy,lGnErD;ey,neli5y;or,rD;ad;by,e,in,l2t1;aIeFiDyK;fDnt;fo0Ft1;meEt5velaD;nd;nt;rFuEyD;!t1;de;enD;ce;aIeGrisEuD;ck;!tD;i0oph3;st3;er;d,rDs;b4leD;s,y;cDdric,sA;il;lGmer1rD;ey,lEro8y;ll;!os,t1;eb,v2;a07eZiVlaUoRrEuDyr1;ddy,rtK;aLeGiFuEyD;an,ce,on;ce,no;an,ce;nEtD;!t;dEtD;!on;an,on;dEndD;en,on;!foDl7y;rd;bErDyd;is;!by;i6ke;bFlEshD;al;al,lC;ek;nHrDshoi;at,nEtD;!r1C;aDie;rd14;!edict,iEjam2nC;ie,y;to;kaMlazs,nHrD;n7rDt;eDy;tt;ey;dDeE;ar,iD;le;ar17b0Vd0Rf0Pgust2hm0Mi0Jja0Il04m00nSputsiRrIsaHuFveEyDziz;a0kh0;ry;gust5st2;us;hi;aKchJiIjun,maHnFon,tDy0;hDu09;ur;av,oD;ld;an,nd0H;!el,ki;ie;ta;aq;as,dIgel0CtD;hoGoD;i6nD;!i09y;ne;ny;er,reDy;!as,i,s,w;iFmaDos;nu4r;el;ne,r,t;an,bePd9eJfHi,lGonFphXt1vD;aNin;on;so,zo;an,en;onTrD;edU;c,jaGksandFssaGxD;!andD;er,ru;ar,er;ndD;ro;rtN;ni;d9mA;ar;en;ad,eD;d,t;in;onD;so;aEi,olfDri0vik;!o;mDn;!a;dHeGraEuD;!bakr,lfazl;hDm;am;!l;allIelFoulaye,ulD;!lDrF;ah,o;! rD;ahm0;an;ah;av,on",
3834 "Person": "true¦ashton kutchTbScNdLeJgastOhHinez,jFkEleDmCnettKoBp9r4s3t2v0;a0irgin maH;lentino rossi,n go3;aylor,heresa may,iger woods,yra banks;addam hussain,carlett johanssKlobodan milosevic,uC;ay romano,e3o1ush limbau0;gh;d stewart,nald0;inho,o;ese witherspoFilly;a0ipJ;lmIris hiltD;prah winfrFra;essiaen,itt romnEubarek;bron james,e;anye west,iefer sutherland,obe bryant;aime,effers8k rowli0;ng;alle ber0itlBulk hogan;ry;ff0meril lagasse,zekiel;ie;a0enzel washingt2ick wolf;lt1nte;ar1lint0;on;dinal wols1son0;! palm2;ey;arack obama,rock;er",
3835 "Verb": "true¦awak9born,cannot,fr8g7h5k3le2m1s0wors9;e8h3;ake sure,sg;ngth6ss6;eep tabs,n0;own;as0e2;!t2;iv1onna;ight0;en",
3836 "PhrasalVerb": "true¦0:7E;1:72;2:7Q;3:7G;4:6V;5:7T;6:7I;7:71;8:6O;9:6P;A:5T;B:7L;C:7J;D:7D;E:7C;F:6Q;G:7S;H:46;a7Yb6Jc5Sd5Oe5Mf4Lg43h3Miron0j3Ik3Dl2Xm2Ln2Jo2Hp1ZquietFr1Ms0FtVuTvacuum 1wLyammerEzI;eroAip JonI;e0k0;by,up;aOeLhKiJorIrit5H;d 1k35;mp0n2Xpe0r8s8;eel Dip G;aJiIn2L;gh 0Crd0;n Dr 3S;it 60k8lk6rm 6Bsh 7Lt6Ov53;rgeEsI;e 9herA;aXeVhTiPoNrKuIype 68;ckArn I;d2in,o3Vup;aJiIot0y 2L;ckleFp G;ckFde 02;neFp Is4Q;d2o71up;ck KdJe Igh69me0p o0Kre0;aw3ba4d2in,up;e 60y 1;by,oC;ink Irow 6B;ba4ov7up;aIe 4Vll52;m 1r 01;ckEke Jlk I;ov7u53;aIba4d2in,o3Fup;ba4ft7p58w3;a0Nc0Me0Gh0Ci09l05m04n03o02pXquare WtOuMwI;earKiI;ngJtch I;aw3ba4o75; by;ck Iit 1m 1ss0;in,up;aNe10iMoKrIucH;aigh1ZiI;ke 6En3C;p Irm22;by,in,oC;nHr 1tc3V;cHmp0nd Ir6Xve6y 1;ba4d2up;d2oCup;arHeLiKlJrIurE;ingEuc8;a3Hit 47;l16n 1;e5Qll0;be4Prt0;ap 4Row D;ash 5Doke0;eep JiIow 9;c3Yp 1;in,oI;ff,v7;gn 4WngJt Iz8;d2o5up; al52le0;aKoIu4S;ot Iut0w 6B;aw3ba4f3IoC;cHdeAk56ve6;e Mll0nd LtI; Itl4G;d2in,o5upI;!on;aw3ba4d2in,o2Aup;o5to;al4Zout0rap4Z;il6v8;aTeQiPoLuI;b 4Sle0n Istl8;aIba4d2in5Ho3Tt3Bu3R;c29w3;ll Kot JuI;g2Vnd6;a29f32o5;arBin,o5;ng 51p6;aIel6inAnt0;c5Bd I;o33u0L;cHt0;aVeUiTlRoPrMsyc2JuI;ll Kt I;aIba4d2in,o1Rt3Fup;p3Kw3;ap3Jd2in,o5t3Dup;attleEess JiLoI;p 1;ah1Ron;iIp 5Fr3XurFwer 5F;nt0;ay4BuI;gAmp 9;ck Gg0leEn 9p48;el 4JncilA;c41ir 2Rn0ss KtJy I;ba4oC; d2c27;aw3ba4o1C;pIw3W;e3Vt D;arrowFerd0oI;d6teF;aQeNiMoKuI;ddl8lI;l 3I;cHp 1uth6ve I;al3Md2in,o5up;ss0x 1;asur8lJss I;a1Jup;t 9;ke Jn 9rIs1Sx0;k 9ry6;do,o47up;aVeTiOoIuck0;aMc3Gg LoIse0;k Ise3E;aft7ba4d2forw2Jin45ov7uI;nd7p;in,o0Q;d 9;e LghtKnJsIv1Y;ten G;e 1k 1; 1e36;arBd2;av1Mt 36velI; o3T;c8p 1sh ItchEugh6y20;in3To5;eJick6nock I;d2o3P;eIyA;l 2Pp I;aw3ba4d2fXin,o0Bto,up;aKoJuI;ic8mpA;ke30tF;c39zz 1;aUePiMoJuI;nkerFrry 1s0Z;lIneArse2W;d Ie 1;ba4d2fast,o05up;de Jt I;ba4on,up;aw3o5;aIlp0;d Kl 2Ar It 1;fIof;rom;in,oXu1H;cHm 1nJve Iz25;it,to;d Ig 2EkerK;d2in,o5;aWeQive Oloss 22oKrJunI; f0Q;in3Gow 2A; Iof 0Y;aJb1Dit,oIrBt0Su18;ff,n,v7;bo5ft7hOw3;aw3ba4d2in,oIup,w3;ff,n,ut;a1Dek0t I;aJb17d2oIrBup;ff,n,ut,v7;cJhIl1WrBt,w3;ead;ross;d aJnI;g 1;bo5;a0Ce05iWlSoOrKuI;cHel 1;k 1;eJighten IownEy 1;aw3oC;eIshe1N; 1z8;lKol I;aIwi1G;bo5rB;d 9low 1;aJeIip0;sh0;g 9ke0mIrI;e G;gPlNnLrJsIzzle0;h G;e Im 1;aw3ba4up;d0isI;h 1;e Il 19;aw3fN;ht ba4ure0;eNnJsI;s 1;cKd I;fIoC;or;e D;dWl 1;cMll Irm0t0W;ap05bKd2in,oJtI;hrough;ff,ut,v7;a4ehi20;e J;at0dge0nd Iy8;oCup;oKrI;ess 9op I;aw3bUin,o1D; 0Eubl8;aYhVlean 9oIross Dut 10;me LoJuntI; o1T;k 1l I;d2oC;aObNforLin,oKtJuI;nd7;ogeth7;ut,v7;th,wI;ard;a4y;pIrBw3;art;eIipA;ck DeI;r 1;lOncel0rLsKtch JveA; in;o1Cup;h Dt6;ry JvI;e 01;aw3o18;l ImF;aIba4d2o16up;rBw3;a0Ne0El07oYrNuI;bblKcklZil05lk 9ndlZrn 0Bst JtIy Gzz6;t D;in,o5up;e I;ov7;anReaPiIush6;ghMng I;aJba4d2forIin,o5up;th;bo5lIrBw3;ong;teI;n 1;k I;d2in,o5up;ch0;arPgFil 9n8oLssKttlJunce Ix D;aw3ba4;e 9; arB;k Dt 1;e 1;d2up; d2;d 1;aNeed0oIurt0;cKw I;aw3ba4d2o5up;ck;k I;in,oP;ck0nk0st6; oOaLef 1nd I;d2ov7up;er;up;r0t I;d2in,oIup;ff,ut;ff,nI;to;ck Oil0nKrgJsI;h D;ainEe D;g DkE; on;in,o5; o5;aw3d2o5up;ay;cRdNsk Kuction6; oC;ff;arBo5;ouI;nd;d I;d2oIup;ff,n;own;t G;o5up;ut",
3837 "Modal": "true¦c5lets,m4ought3sh1w0;ill,o5;a0o4;ll,nt;! to,a;ay,ight,ust;an,o0;uld",
3838 "Adjective": "true¦0:7P;1:84;2:83;3:8A;4:7W;5:5S;6:58;7:4O;8:4N;9:81;A:6I;a6Wb6Gc63d5Je54f4Hg49h3Wi39j37k36l2Vm2Ln2Bo1Wp1Dquack,r12s0Ft07uMvJwByear5;arp0eFholeEiDoB;man5oBu6P;d6Rzy;despr7Ls5S;!sa7;eClBste2A;co1Nl o4W;!k5;aCiBola4M;b89ce versa,ol5H;ca3gabo6Gnilla;ltUnHpCrb5Msu4tterB;!mo7G; Eb1SpDsBti1M;ca7etBide dKtairs;!ti2;er,i3U;f36to da1;aLbeco75convin29deIeHfair,ivers4knGprecedVrEsCwB;iel3Nritt6A;i1XuB;pervis0spec3Y;eBu5;cognHgul6Tl6T;own;ndi2v64xpect0;cid0rB;!grou5ZsB;iz0tood;b7pp0Dssu6UuthorB;iz0;i26ra;aGeEhDi6AoCrB;i1oubl0us3M;geth6p,rp6Vuc67;ough4Wril33;en60l32mpBrr2X;o6Ati2;boo,lBn;ent0;aWcVeThSiQmug,nobbi3LoOpNqueami3LtFuBymb6H;bDi gener5DpBrpri6D;erBre0N;! dup6b,i2C;du0seq52;anda77eGiFrBunni2y3F;aightCiB;ki2p0; fBfB;or5K;ll,r5S;aBreotyp0;dfa6Cmi2;a55ec2Gir1Hlend6Cot on; call0le,mb6phist1XrBu0Vvi48;d6Ary;gnifica3nB;ce51g7;am2Re6ocki2ut;cBda1em5lfi32ni1Wpa6Jre8;o1Er42;at5Gient28reec5G;cr0me;aJeEiCoB;bu60tt51uQy4;ghtBv4;!-2BfA;ar,bel,condi1du6Dfres5AlEpublic42sCtard0vB;ea26;is4CoB;lu1na3;aQe1Cuc4A;b5TciBllyi2;al,st;aOeLicayu8lac5Ropuli5QrCuB;bl5Jmp0n51;eGiDoB;!b07fu5RmiBp6;ne3si2;mCor,sBva1;ti8;a53e;ci5MmB;a0EiB;er,um;ac20rBti1;fe9ma2XpleBv38;xi2;rBst;allelDtB;-tiBi4;me;!ed;bLffJkIld fashion0nHpGrg1Eth6utFvB;al,erB;!all,niCt,wB;eiBrouB;ght;do0Ter,g2Qsi4B;en,posi1; boa5Og2Oli8;!ay; gua5MbBli8;eat;eDsB;cBer0Eole1;e8u3O;d2Xse;aJeIiHoBua4X;nFrCtB;ab7;thB;!eB;rn;chala3descri58stop;ght5;arby,cessa44ighbor5xt;k0usia1A;aIeGiDoBultip7;bi7derBl0Vnth5ot,st;a1n;nBx0;dblo0RiaBor;tu37;ande3Qdi4NnaBre;ci2;cBgenta,in,j01keshift,le,mmoth,ny,sculi8;ab33ho;aKeFiCoBu15;uti14vi2;mCteraB;l,te;it0;ftEgBth4;al,eCitiB;ma1;nda3K;!-0C;ngu3Zst,tt6;ap1Xind5no0A;agg0uB;niMstifi0veni7;de4gno4Klleg4mQnEpso 20rB;a1rB;eleBita0J;va3; KaJbr0corIdGfluenQiQnFsEtCviB;go0Fti2;a9en3SoxB;ic3B;a8i2Vul0D;a1er,oce3;iCoB;or;re9;deq3Qppr33;fBsitu,vitro;ro3;mFpB;arDerfe9oBrop6;li1rtB;a3ed;ti4;eBi0S;d2Vn3C;aIeFiDoBumdr3I;ne36ok0rrBs08ur5;if2Z;ghfalut1QspB;an2X;aClB;liYpfA;li2;lEnDrB;d04roB;wi2;dy;f,low0;ainfAener2Oiga24lHoGraDuB;ilBng ho;ty;cCtB;efAis;efA;ne,od;ea2Iob4;aTeNinMlKoFrB;a1VeDoz1MustB;raB;ti2;e2Gq10tfA;oDrB; keeps,eBm6tuna1;g03ign;liB;sh;aBue3;g31tte1P;al,i1;dFmCrB;ti7;a7ini8;ne;le; up;bl0i3l27r Cux,voB;ri1uri1;oBreac1E;ff;aLfficie3lKmHnFre9there4veExB;a9cess,pe1QtraCuB;be2Nl0E;!va1E;n,ryday; BcouraEti0O;rou1sui1;erCiB;ne3;gi2;abo23dMe17i1;g6sB;t,ygB;oi2;er;aReJiDoBrea14ue;mina3ne,ubB;le,tfA;dact1Bfficu1OsCvB;er1K;creDeas0gruntl0hone1FordCtB;a3ressM;er5;et; HadpGfFgene1PliDrang0spe1PtCvoB;ut;ail0ermin0;be1Mca1ghB;tfA;ia3;an;facto;i5magBngeroUs0G;ed,i2;ly;ertaMhief,ivil,oDrB;aBowd0u0G;mp0vZz0;loImGnCrrBve0P;e9u1I;cre1fu0LgrDsCtB;empo0Dra0E;ta3;ue3;mer08pleB;te,x;ni4ss4;in;aNeIizarHlFoCrB;and new,isk,okN;gCna fiUttom,urgeoB;is;us;ank,indB;!i2;re;autifAhiDloCnBst,yoD;eUt;v0w;nd;ul;ckCnkru0WrrB;en;!wards; priori,b0Mc0Jd09fra08g04h03lYmWntiquVppSrMsIttracti06utheHvEwB;aCkB;wa0T;ke,re;ant garCerB;age;de;ntU;leep,piDsuDtonB;isB;hi2;ri2;ab,bitEroDtiB;fiB;ci4;ga3;raB;ry;are3etiNrB;oprB;ia1;at0;aJuB;si2;arEcohCeBiIl,oof;rt;olB;ic;mi2;ead;ainDgressiConiB;zi2;ve;st;id; IeGuFvB;aCerB;se;nc0;ed;lt;pt,qB;ua1;hoc,infinitB;um;cuCtu4u1;al;ra1;erLlKoIruHsCuB;nda3;e3oCtra9;ct;lu1rbi2;ng;te;pt;aBve;rd;aze,e;ra3;nt",
3839 "Comparable": "true¦0:41;1:4I;2:45;3:4B;4:3X;5:2Y;a4Ob44c3Od3De35f2Rg2Fh24i1Vj1Uk1Rl1Jm1Dn17o15p0Vqu0Tr0KsTtMuIvFw7y6za13;ell27ou3;aBe9hi1Yi7r6;o3y;ck0Ode,l6n1ry,se;d,y;a6i4Mt;k,ry;n1Tr6sK;m,y;a7e6ulgar;nge4rda2xi3;g9in,st;g0n6pco3Mse4;like0t6;i1r6;ue;aAen9hi8i7ough,r6;anqu2Oen1ue;dy,g3Sme0ny,r09;ck,n,rs2P;d40se;ll,me,rt,s6wd45;te4;aVcarUeThRiQkin0FlMmKoHpGqua1FtAu7w6;eet,ift;b7dd13per0Gr6;e,re2H;sta2Ft5;aAe9iff,r7u6;pXr1;a6ict,o3;ig3Fn0U;a1ep,rn;le,rk;e22i3Fright0;ci28ft,l7o6re,ur;n,thi3;emn,id;a6el0ooth;ll,rt;e8i6ow,y;ck,g35m6;!y;ek,nd3D;ck,l0mp5;a6iTort,rill,y;dy,ll0Xrp;cu0Rve0Rxy;ce,ed,y;d,fe,int0l1Vv14;aBe9i8o6ude;mantic,o1Isy,u6;gh,nd;ch,pe,tzy;a6d,mo0H;dy,l;gg7ndom,p6re,w;id;ed;ai2i6;ck,et;aEhoDi1QlCoBr8u6;ny,r6;e,p5;egna2ic7o6;fouYud;ey,k0;li04or,te1B;ain,easa2;ny;in4le;dd,f6i0ld,ranQ;fi10;aAe8i7o6;b5isy,rm15sy;ce,mb5;a6w;r,t;ive,rr01;aAe8ild,o7u6;nda19te;ist,o1;a6ek,llX;n,s0ty;d,tuQ;aBeAi9o6ucky;f0Un7o1Du6ve0w17y0T;d,sy;e0g;g1Tke0tt5ve0;an,wd;me,r6te;ge;e7i6;nd;en;ol0ui1P;cy,ll,n6;sBt6;e6ima8;llege2r6;es7media6;te;ti3;ecu6ta2;re;aEeBiAo8u6;ge,m6ng1R;b5id;ll6me0t;ow;gh,l0;a6f04sita2;dy,v6;en0y;nd1Hppy,r6te4;d,sh;aGenFhDiClBoofy,r6;a9e8is0o6ue1E;o6ss;vy;at,en,y;nd,y;ad,ib,ooI;a2d1;a6o6;st0;t5uiY;u1y;aIeeb5iDlat,oAr8u6;ll,n6r14;!ny;aHe6iend0;e,sh;a7r6ul;get4mG;my;erce8n6rm;an6e;ciC;! ;le;ir,ke,n0Fr,st,t,ulA;aAerie,mp9sse7v6xtre0Q;il;nti6;al;ty;r7s6;tern,y;ly,th0;aFeCi9r7u6;ll,mb;u6y;nk;r7vi6;ne;e,ty;a6ep,nD;d6f,r;!ly;mp,pp03rk;aHhDlAo8r7u6;dd0r0te;isp,uel;ar6ld,mmon,ol,st0ward0zy;se;e6ou1;a6vW;n,r;ar8e6il0;ap,e6;sy;mi3;gey,lm8r6;e4i3;ful;!i3;aNiLlIoEr8u6;r0sy;ly;aAi7o6;ad,wn;ef,g7llia2;nt;ht;sh,ve;ld,r7un6;cy;ed,i3;ng;a7o6ue;nd,o1;ck,nd;g,tt6;er;d,ld,w1;dy;bsu9ng8we6;so6;me;ry;rd",
3840 "TextValue": "true¦bOeJfDhundredNmOninAone,qu8s6t0zeroN;enMh3rNw0;e0o;l0ntD;fHve;ir0ousandKree;d,t6;e0ix8;cond,pt1ven7xt1;adr0int0;illionD;e0th;!t0;e9ie8y;i3o0;rt1ur0;!t2;ie4y;ft0rst,ve;e3h,ie2y;ight0lev2;!e1h,ie0y;th;en0;!th;illion0;!s,th",
3841 "Ordinal": "true¦bGeDf9hundredHmGnin7qu6s4t0zeroH;enGh1rFwe0;lfFn9;ir0ousandE;d,t4;e0ixt9;cond,ptAvent8xtA;adr9int9;et0th;e6ie8;i2o0;r0urt3;tie5;ft1rst;ight0lev1;e0h,ie2;en1;illion0;th",
3842 "Cardinal": "true¦bHeEf8hundred,mHnineAone,qu6s4t0zero;en,h2rGw0;e0o;lve,n8;irt9ousandEree;e0ix5;pt1ven4xt1;adr0int0;illion;i3o0;r1ur0;!t2;ty;ft0ve;e2y;ight0lev1;!e0y;en;illion0;!s",
3843 "Expression": "true¦a02b01dXeVfuck,gShLlImHnGoDpBshAtsk,u7voi04w3y0;a1eLu0;ck,p;!a,hoo,y;h1ow,t0;af,f;e0oa;e,w;gh,h0;! 0h,m;huh,oh;eesh,hh,it;ff,hew,l0sst;ease,z;h1o0w,y;h,o,ps;!h;ah,ope;eh,mm;m1ol0;!s;ao,fao;a4e2i,mm,oly1urr0;ah;! mo6;e,ll0y;!o;ha0i;!ha;ah,ee,o0rr;l0odbye;ly;e0h,t cetera,ww;k,p;'oh,a0uh;m0ng;mit,n0;!it;ah,oo,ye; 1h0rgh;!em;la",
3844 "Adverb": "true¦a08by 06d02eYfShQinPjustOkinda,mMnJoEpCquite,r9s5t2up1very,well,ye0;p,s; to,wards5;h1iny bit,o0wiO;o,t6ward;en,us;everal,o0uch;!me1rt0; of;hYtimes,w09;a1e0;alT;ndomSthN;ar excellDer0oint blank; Nhaps;f3n0;ce0ly;! 0;ag02moW; courIten;ewKo0; longEt 0;onIwithstanding;aybe,eanwhiAore0;!ovB;! aboU;deed,steV;en0;ce;or2u0;lArther0;!moJ; 0ev3;examp0good,suH;le;n1v0;er; mas0ough;se;e0irect1; 1finite0;ly;ju8trop;far,n0;ow; DbroCd nauseam,gBl6ny3part,s2t 0w4;be6l0mo6wor6;arge,ea5; soon,ide;mo1w0;ay;re;l 1mo0one,ready,so,ways;st;b1t0;hat;ut;ain;ad;lot,posteriori",
3845 "Determiner": "true¦aAboth,d8e5few,l3mu7neiCown,plenty,some,th2various,wh0;at0ich0;evB;at,e3is,ose;a,e0;!ast,s;a1i6l0very;!se;ch;e0u;!s;!n0;!o0y;th0;er"
3846};
3847
3848var entity = ['Person', 'Place', 'Organization'];
3849var nouns = {
3850 Noun: {
3851 notA: ['Verb', 'Adjective', 'Adverb']
3852 },
3853 // - singular
3854 Singular: {
3855 isA: 'Noun',
3856 notA: 'Plural'
3857 },
3858 //a specific thing that's capitalized
3859 ProperNoun: {
3860 isA: 'Noun'
3861 },
3862 // -- people
3863 Person: {
3864 isA: ['ProperNoun', 'Singular'],
3865 notA: ['Place', 'Organization', 'Date']
3866 },
3867 FirstName: {
3868 isA: 'Person'
3869 },
3870 MaleName: {
3871 isA: 'FirstName',
3872 notA: ['FemaleName', 'LastName']
3873 },
3874 FemaleName: {
3875 isA: 'FirstName',
3876 notA: ['MaleName', 'LastName']
3877 },
3878 LastName: {
3879 isA: 'Person',
3880 notA: ['FirstName']
3881 },
3882 NickName: {
3883 isA: 'Person',
3884 notA: ['FirstName', 'LastName']
3885 },
3886 Honorific: {
3887 isA: 'Noun',
3888 notA: ['FirstName', 'LastName', 'Value']
3889 },
3890 // -- places
3891 Place: {
3892 isA: 'Singular',
3893 notA: ['Person', 'Organization']
3894 },
3895 Country: {
3896 isA: ['Place', 'ProperNoun'],
3897 notA: ['City']
3898 },
3899 City: {
3900 isA: ['Place', 'ProperNoun'],
3901 notA: ['Country']
3902 },
3903 Region: {
3904 isA: ['Place', 'ProperNoun']
3905 },
3906 Address: {
3907 isA: 'Place'
3908 },
3909 //---Orgs---
3910 Organization: {
3911 isA: ['Singular', 'ProperNoun'],
3912 notA: ['Person', 'Place']
3913 },
3914 SportsTeam: {
3915 isA: 'Organization'
3916 },
3917 School: {
3918 isA: 'Organization'
3919 },
3920 Company: {
3921 isA: 'Organization'
3922 },
3923 // - plural
3924 Plural: {
3925 isA: 'Noun',
3926 notA: ['Singular']
3927 },
3928 //(not plural or singular)
3929 Uncountable: {
3930 isA: 'Noun'
3931 },
3932 Pronoun: {
3933 isA: 'Noun',
3934 notA: entity
3935 },
3936 //a word for someone doing something -'plumber'
3937 Actor: {
3938 isA: 'Noun',
3939 notA: entity
3940 },
3941 //a gerund-as-noun - 'swimming'
3942 Activity: {
3943 isA: 'Noun',
3944 notA: ['Person', 'Place']
3945 },
3946 //'kilograms'
3947 Unit: {
3948 isA: 'Noun',
3949 notA: entity
3950 },
3951 //'Canadians'
3952 Demonym: {
3953 isA: ['Noun', 'ProperNoun'],
3954 notA: entity
3955 },
3956 //`john's`
3957 Possessive: {
3958 isA: 'Noun' // notA: 'Pronoun',
3959
3960 }
3961};
3962
3963var verbs = {
3964 Verb: {
3965 notA: ['Noun', 'Adjective', 'Adverb', 'Value']
3966 },
3967 // walks
3968 PresentTense: {
3969 isA: 'Verb',
3970 notA: ['PastTense', 'FutureTense']
3971 },
3972 // neutral form - 'walk'
3973 Infinitive: {
3974 isA: 'PresentTense',
3975 notA: ['PastTense', 'Gerund']
3976 },
3977 // walking
3978 Gerund: {
3979 isA: 'PresentTense',
3980 notA: ['PastTense', 'Copula', 'FutureTense']
3981 },
3982 // walked
3983 PastTense: {
3984 isA: 'Verb',
3985 notA: ['FutureTense']
3986 },
3987 // will walk
3988 FutureTense: {
3989 isA: 'Verb'
3990 },
3991 // is
3992 Copula: {
3993 isA: 'Verb'
3994 },
3995 // would have
3996 Modal: {
3997 isA: 'Verb',
3998 notA: ['Infinitive']
3999 },
4000 // had walked
4001 PerfectTense: {
4002 isA: 'Verb',
4003 notA: 'Gerund'
4004 },
4005 Pluperfect: {
4006 isA: 'Verb'
4007 },
4008 // shown
4009 Participle: {
4010 isA: 'PastTense'
4011 },
4012 // show up
4013 PhrasalVerb: {
4014 isA: 'Verb'
4015 },
4016 //'up' part
4017 Particle: {
4018 isA: 'PhrasalVerb'
4019 },
4020 //this can be an adverb
4021 Auxiliary: {
4022 notA: ['Noun', 'Adjective', 'Value']
4023 }
4024};
4025
4026var values = {
4027 Value: {
4028 notA: ['Verb', 'Adjective', 'Adverb']
4029 },
4030 Ordinal: {
4031 isA: 'Value',
4032 notA: ['Cardinal']
4033 },
4034 Cardinal: {
4035 isA: 'Value',
4036 notA: ['Ordinal']
4037 },
4038 RomanNumeral: {
4039 isA: 'Cardinal',
4040 //can be a person, too
4041 notA: ['Ordinal', 'TextValue']
4042 },
4043 TextValue: {
4044 isA: 'Value',
4045 notA: ['NumericValue']
4046 },
4047 NumericValue: {
4048 isA: 'Value',
4049 notA: ['TextValue']
4050 },
4051 Money: {
4052 isA: 'Cardinal'
4053 },
4054 Percent: {
4055 isA: 'Value'
4056 }
4057};
4058
4059var anything = ['Noun', 'Verb', 'Adjective', 'Adverb', 'Value', 'QuestionWord'];
4060var misc = {
4061 //--Adjectives--
4062 Adjective: {
4063 notA: ['Noun', 'Verb', 'Adverb', 'Value']
4064 },
4065 // adjectives that can conjugate
4066 Comparable: {
4067 isA: ['Adjective']
4068 },
4069 // better
4070 Comparative: {
4071 isA: ['Adjective']
4072 },
4073 // best
4074 Superlative: {
4075 isA: ['Adjective'],
4076 notA: ['Comparative']
4077 },
4078 NumberRange: {
4079 isA: ['Contraction']
4080 },
4081 Adverb: {
4082 notA: ['Noun', 'Verb', 'Adjective', 'Value']
4083 },
4084 // Dates:
4085 //not a noun, but usually is
4086 Date: {
4087 notA: ['Verb', 'Conjunction', 'Adverb', 'Preposition', 'Adjective']
4088 },
4089 Month: {
4090 isA: ['Date', 'Singular'],
4091 notA: ['Year', 'WeekDay', 'Time']
4092 },
4093 WeekDay: {
4094 isA: ['Date', 'Noun']
4095 },
4096 // '9:20pm'
4097 Time: {
4098 isA: ['Date'],
4099 notA: ['AtMention']
4100 },
4101 //glue
4102 Determiner: {
4103 notA: anything
4104 },
4105 Conjunction: {
4106 notA: anything
4107 },
4108 Preposition: {
4109 notA: anything
4110 },
4111 // what, who, why
4112 QuestionWord: {
4113 notA: ['Determiner']
4114 },
4115 // peso, euro
4116 Currency: {
4117 isA: ['Noun']
4118 },
4119 // ughh
4120 Expression: {
4121 notA: ['Noun', 'Adjective', 'Verb', 'Adverb']
4122 },
4123 // dr.
4124 Abbreviation: {},
4125 // internet tags
4126 Url: {
4127 notA: ['HashTag', 'PhoneNumber', 'Verb', 'Adjective', 'Value', 'AtMention', 'Email']
4128 },
4129 PhoneNumber: {
4130 notA: ['HashTag', 'Verb', 'Adjective', 'Value', 'AtMention', 'Email']
4131 },
4132 HashTag: {},
4133 AtMention: {
4134 isA: ['Noun'],
4135 notA: ['HashTag', 'Verb', 'Adjective', 'Value', 'Email']
4136 },
4137 Emoji: {
4138 notA: ['HashTag', 'Verb', 'Adjective', 'Value', 'AtMention']
4139 },
4140 Emoticon: {
4141 notA: ['HashTag', 'Verb', 'Adjective', 'Value', 'AtMention']
4142 },
4143 Email: {
4144 notA: ['HashTag', 'Verb', 'Adjective', 'Value', 'AtMention']
4145 },
4146 //non-exclusive
4147 Acronym: {
4148 notA: ['Plural', 'RomanNumeral']
4149 },
4150 Negative: {
4151 notA: ['Noun', 'Adjective', 'Value']
4152 },
4153 // if, unless, were
4154 Condition: {
4155 notA: ['Verb', 'Adjective', 'Noun', 'Value']
4156 }
4157};
4158
4159// i just made these up
4160var colorMap = {
4161 Noun: 'blue',
4162 Verb: 'green',
4163 Negative: 'green',
4164 Date: 'red',
4165 Value: 'red',
4166 Adjective: 'magenta',
4167 Preposition: 'cyan',
4168 Conjunction: 'cyan',
4169 Determiner: 'cyan',
4170 Adverb: 'cyan'
4171};
4172/** add a debug color to some tags */
4173
4174var addColors = function addColors(tags) {
4175 Object.keys(tags).forEach(function (k) {
4176 // assigned from plugin, for example
4177 if (tags[k].color) {
4178 tags[k].color = tags[k].color;
4179 return;
4180 } // defined above
4181
4182
4183 if (colorMap[k]) {
4184 tags[k].color = colorMap[k];
4185 return;
4186 }
4187
4188 tags[k].isA.some(function (t) {
4189 if (colorMap[t]) {
4190 tags[k].color = colorMap[t];
4191 return true;
4192 }
4193
4194 return false;
4195 });
4196 });
4197 return tags;
4198};
4199
4200var _color = addColors;
4201
4202var unique$2 = function unique(arr) {
4203 return arr.filter(function (v, i, a) {
4204 return a.indexOf(v) === i;
4205 });
4206}; //add 'downward' tags (that immediately depend on this one)
4207
4208
4209var inferIsA = function inferIsA(tags) {
4210 Object.keys(tags).forEach(function (k) {
4211 var tag = tags[k];
4212 var len = tag.isA.length;
4213
4214 for (var i = 0; i < len; i++) {
4215 var down = tag.isA[i];
4216
4217 if (tags[down]) {
4218 tag.isA = tag.isA.concat(tags[down].isA);
4219 }
4220 } // clean it up
4221
4222
4223 tag.isA = unique$2(tag.isA);
4224 });
4225 return tags;
4226};
4227
4228var _isA = inferIsA;
4229
4230var unique$3 = function unique(arr) {
4231 return arr.filter(function (v, i, a) {
4232 return a.indexOf(v) === i;
4233 });
4234}; // crawl the tag-graph and infer any conflicts
4235// faster than doing this at tag-time
4236
4237
4238var inferNotA = function inferNotA(tags) {
4239 var keys = Object.keys(tags);
4240 keys.forEach(function (k) {
4241 var tag = tags[k];
4242 tag.notA = tag.notA || [];
4243 tag.isA.forEach(function (down) {
4244 if (tags[down] && tags[down].notA) {
4245 // borrow its conflicts
4246 var notA = typeof tags[down].notA === 'string' ? [tags[down].isA] : tags[down].notA || [];
4247 tag.notA = tag.notA.concat(notA);
4248 }
4249 }); // any tag that lists us as a conflict, we conflict it back.
4250
4251 for (var i = 0; i < keys.length; i++) {
4252 var key = keys[i];
4253
4254 if (tags[key].notA.indexOf(k) !== -1) {
4255 tag.notA.push(key);
4256 }
4257 } // clean it up
4258
4259
4260 tag.notA = unique$3(tag.notA);
4261 });
4262 return tags;
4263};
4264
4265var _notA = inferNotA;
4266
4267// a lineage is all 'incoming' tags that have this as 'isA'
4268var inferLineage = function inferLineage(tags) {
4269 var keys = Object.keys(tags);
4270 keys.forEach(function (k) {
4271 var tag = tags[k];
4272 tag.lineage = []; // find all tags with it in their 'isA' set
4273
4274 for (var i = 0; i < keys.length; i++) {
4275 if (tags[keys[i]].isA.indexOf(k) !== -1) {
4276 tag.lineage.push(keys[i]);
4277 }
4278 }
4279 });
4280 return tags;
4281};
4282
4283var _lineage = inferLineage;
4284
4285var validate = function validate(tags) {
4286 // cleanup format
4287 Object.keys(tags).forEach(function (k) {
4288 var tag = tags[k]; // ensure isA is an array
4289
4290 tag.isA = tag.isA || [];
4291
4292 if (typeof tag.isA === 'string') {
4293 tag.isA = [tag.isA];
4294 } // ensure notA is an array
4295
4296
4297 tag.notA = tag.notA || [];
4298
4299 if (typeof tag.notA === 'string') {
4300 tag.notA = [tag.notA];
4301 }
4302 });
4303 return tags;
4304}; // build-out the tag-graph structure
4305
4306
4307var inferTags = function inferTags(tags) {
4308 // validate data
4309 tags = validate(tags); // build its 'down tags'
4310
4311 tags = _isA(tags); // infer the conflicts
4312
4313 tags = _notA(tags); // debug tag color
4314
4315 tags = _color(tags); // find incoming links
4316
4317 tags = _lineage(tags);
4318 return tags;
4319};
4320
4321var inference = inferTags;
4322
4323var addIn = function addIn(obj, tags) {
4324 Object.keys(obj).forEach(function (k) {
4325 tags[k] = obj[k];
4326 });
4327};
4328
4329var build = function build() {
4330 var tags = {};
4331 addIn(nouns, tags);
4332 addIn(verbs, tags);
4333 addIn(values, tags);
4334 addIn(misc, tags); // do the graph-stuff
4335
4336 tags = inference(tags);
4337 return tags;
4338};
4339
4340var tags = build();
4341
4342var seq = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
4343 cache = seq.split("").reduce(function (n, o, e) {
4344 return n[o] = e, n;
4345}, {}),
4346 toAlphaCode = function toAlphaCode(n) {
4347 if (void 0 !== seq[n]) return seq[n];
4348 var o = 1,
4349 e = 36,
4350 t = "";
4351
4352 for (; n >= e; n -= e, o++, e *= 36) {
4353 }
4354
4355 for (; o--;) {
4356 var _o = n % 36;
4357
4358 t = String.fromCharCode((_o < 10 ? 48 : 55) + _o) + t, n = (n - _o) / 36;
4359 }
4360
4361 return t;
4362},
4363 fromAlphaCode = function fromAlphaCode(n) {
4364 if (void 0 !== cache[n]) return cache[n];
4365 var o = 0,
4366 e = 1,
4367 t = 36,
4368 r = 1;
4369
4370 for (; e < n.length; o += t, e++, t *= 36) {
4371 }
4372
4373 for (var _e = n.length - 1; _e >= 0; _e--, r *= 36) {
4374 var _t = n.charCodeAt(_e) - 48;
4375
4376 _t > 10 && (_t -= 7), o += _t * r;
4377 }
4378
4379 return o;
4380};
4381
4382var encoding = {
4383 toAlphaCode: toAlphaCode,
4384 fromAlphaCode: fromAlphaCode
4385},
4386 symbols = function symbols(n) {
4387 var o = new RegExp("([0-9A-Z]+):([0-9A-Z]+)");
4388
4389 for (var e = 0; e < n.nodes.length; e++) {
4390 var t = o.exec(n.nodes[e]);
4391
4392 if (!t) {
4393 n.symCount = e;
4394 break;
4395 }
4396
4397 n.syms[encoding.fromAlphaCode(t[1])] = encoding.fromAlphaCode(t[2]);
4398 }
4399
4400 n.nodes = n.nodes.slice(n.symCount, n.nodes.length);
4401};
4402
4403var indexFromRef = function indexFromRef(n, o, e) {
4404 var t = encoding.fromAlphaCode(o);
4405 return t < n.symCount ? n.syms[t] : e + t + 1 - n.symCount;
4406},
4407 toArray = function toArray(n) {
4408 var o = [],
4409 e = function e(t, r) {
4410 var s = n.nodes[t];
4411 "!" === s[0] && (o.push(r), s = s.slice(1));
4412 var c = s.split(/([A-Z0-9,]+)/g);
4413
4414 for (var _s = 0; _s < c.length; _s += 2) {
4415 var u = c[_s],
4416 i = c[_s + 1];
4417 if (!u) continue;
4418 var l = r + u;
4419
4420 if ("," === i || void 0 === i) {
4421 o.push(l);
4422 continue;
4423 }
4424
4425 var f = indexFromRef(n, i, t);
4426 e(f, l);
4427 }
4428 };
4429
4430 return e(0, ""), o;
4431},
4432 unpack = function unpack(n) {
4433 var o = {
4434 nodes: n.split(";"),
4435 syms: [],
4436 symCount: 0
4437 };
4438 return n.match(":") && symbols(o), toArray(o);
4439};
4440
4441var unpack_1 = unpack,
4442 unpack_1$1 = function unpack_1$1(n) {
4443 var o = n.split("|").reduce(function (n, o) {
4444 var e = o.split("¦");
4445 return n[e[0]] = e[1], n;
4446 }, {}),
4447 e = {};
4448 return Object.keys(o).forEach(function (n) {
4449 var t = unpack_1(o[n]);
4450 "true" === n && (n = !0);
4451
4452 for (var _o2 = 0; _o2 < t.length; _o2++) {
4453 var r = t[_o2];
4454 !0 === e.hasOwnProperty(r) ? !1 === Array.isArray(e[r]) ? e[r] = [e[r], n] : e[r].push(n) : e[r] = n;
4455 }
4456 }), e;
4457};
4458
4459var efrtUnpack_min = unpack_1$1;
4460
4461//safely add it to the lexicon
4462var addWord = function addWord(word, tag, lex) {
4463 if (lex[word] !== undefined) {
4464 if (typeof lex[word] === 'string') {
4465 lex[word] = [lex[word]];
4466 }
4467
4468 if (typeof tag === 'string') {
4469 lex[word].push(tag);
4470 } else {
4471 lex[word] = lex[word].concat(tag);
4472 }
4473 } else {
4474 lex[word] = tag;
4475 }
4476}; // blast-out more forms for some given words
4477
4478
4479var addMore = function addMore(word, tag, world) {
4480 var lexicon = world.words;
4481 var transform = world.transforms; // cache multi-words
4482
4483 var words = word.split(' ');
4484
4485 if (words.length > 1) {
4486 //cache the beginning word
4487 world.hasCompound[words[0]] = true;
4488 } // inflect our nouns
4489
4490
4491 if (tag === 'Singular') {
4492 var plural = transform.toPlural(word, world);
4493 lexicon[plural] = lexicon[plural] || 'Plural'; // only if it's safe
4494 } //conjugate our verbs
4495
4496
4497 if (tag === 'Infinitive') {
4498 var conj = transform.conjugate(word, world);
4499 var tags = Object.keys(conj);
4500
4501 for (var i = 0; i < tags.length; i++) {
4502 var w = conj[tags[i]];
4503 lexicon[w] = lexicon[w] || tags[i]; // only if it's safe
4504 }
4505 } //derive more adjective forms
4506
4507
4508 if (tag === 'Comparable') {
4509 var _conj = transform.adjectives(word);
4510
4511 var _tags = Object.keys(_conj);
4512
4513 for (var _i = 0; _i < _tags.length; _i++) {
4514 var _w = _conj[_tags[_i]];
4515 lexicon[_w] = lexicon[_w] || _tags[_i]; // only if it's safe
4516 }
4517 } //conjugate phrasal-verbs
4518
4519
4520 if (tag === 'PhrasalVerb') {
4521 //add original form
4522 addWord(word, 'Infinitive', lexicon); //conjugate first word
4523
4524 var _conj2 = transform.conjugate(words[0], world);
4525
4526 var _tags2 = Object.keys(_conj2);
4527
4528 for (var _i2 = 0; _i2 < _tags2.length; _i2++) {
4529 //add it to our cache
4530 world.hasCompound[_conj2[_tags2[_i2]]] = true; //first + last words
4531
4532 var _w2 = _conj2[_tags2[_i2]] + ' ' + words[1];
4533
4534 addWord(_w2, _tags2[_i2], lexicon);
4535 addWord(_w2, 'PhrasalVerb', lexicon);
4536 }
4537 } // inflect our demonyms - 'germans'
4538
4539
4540 if (tag === 'Demonym') {
4541 var _plural = transform.toPlural(word, world);
4542
4543 lexicon[_plural] = lexicon[_plural] || ['Demonym', 'Plural']; // only if it's safe
4544 }
4545}; // throw a bunch of words in our lexicon
4546// const doWord = function(words, tag, world) {
4547// let lexicon = world.words
4548// for (let i = 0; i < words.length; i++) {
4549// addWord(words[i], tag, lexicon)
4550// // do some fancier stuff
4551// addMore(words[i], tag, world)
4552// }
4553// }
4554
4555
4556var addWords = {
4557 addWord: addWord,
4558 addMore: addMore
4559};
4560
4561// add words from plurals and conjugations data
4562var addIrregulars = function addIrregulars(world) {
4563 //add irregular plural nouns
4564 var nouns = world.irregulars.nouns;
4565 var words = Object.keys(nouns);
4566
4567 for (var i = 0; i < words.length; i++) {
4568 var w = words[i];
4569 world.words[w] = 'Singular';
4570 world.words[nouns[w]] = 'Plural';
4571 } // add irregular verb conjugations
4572
4573
4574 var verbs = world.irregulars.verbs;
4575 var keys = Object.keys(verbs);
4576
4577 var _loop = function _loop(_i) {
4578 var inf = keys[_i]; //add only if it it's safe...
4579
4580 world.words[inf] = world.words[inf] || 'Infinitive';
4581 var forms = world.transforms.conjugate(inf, world);
4582 forms = Object.assign(forms, verbs[inf]); //add the others
4583
4584 Object.keys(forms).forEach(function (tag) {
4585 world.words[forms[tag]] = world.words[forms[tag]] || tag; // lexicon should prefer other tags, over participle
4586
4587 if (world.words[forms[tag]] === 'Participle') {
4588 world.words[forms[tag]] = tag;
4589 }
4590 });
4591 };
4592
4593 for (var _i = 0; _i < keys.length; _i++) {
4594 _loop(_i);
4595 }
4596};
4597
4598var addIrregulars_1 = addIrregulars;
4599
4600//words that can't be compressed, for whatever reason
4601var misc$1 = {
4602 // numbers
4603 '20th century fox': 'Organization',
4604 // '3m': 'Organization',
4605 '7 eleven': 'Organization',
4606 'motel 6': 'Organization',
4607 g8: 'Organization',
4608 vh1: 'Organization',
4609 q1: 'Date',
4610 q2: 'Date',
4611 q3: 'Date',
4612 q4: 'Date',
4613 her: ['Possessive', 'Pronoun'],
4614 his: ['Possessive', 'Pronoun'],
4615 their: ['Possessive', 'Pronoun'],
4616 themselves: ['Possessive', 'Pronoun'],
4617 your: ['Possessive', 'Pronoun'],
4618 our: ['Possessive', 'Pronoun'],
4619 my: ['Possessive', 'Pronoun'],
4620 its: ['Possessive', 'Pronoun']
4621};
4622
4623//nouns with irregular plural/singular forms
4624//used in noun.inflect, and also in the lexicon.
4625var plurals = {
4626 addendum: 'addenda',
4627 alga: 'algae',
4628 alumna: 'alumnae',
4629 alumnus: 'alumni',
4630 analysis: 'analyses',
4631 antenna: 'antennae',
4632 appendix: 'appendices',
4633 avocado: 'avocados',
4634 axis: 'axes',
4635 bacillus: 'bacilli',
4636 barracks: 'barracks',
4637 beau: 'beaux',
4638 bus: 'buses',
4639 cactus: 'cacti',
4640 chateau: 'chateaux',
4641 child: 'children',
4642 circus: 'circuses',
4643 clothes: 'clothes',
4644 corpus: 'corpora',
4645 criterion: 'criteria',
4646 curriculum: 'curricula',
4647 database: 'databases',
4648 deer: 'deer',
4649 diagnosis: 'diagnoses',
4650 echo: 'echoes',
4651 embargo: 'embargoes',
4652 epoch: 'epochs',
4653 foot: 'feet',
4654 formula: 'formulae',
4655 fungus: 'fungi',
4656 genus: 'genera',
4657 goose: 'geese',
4658 halo: 'halos',
4659 hippopotamus: 'hippopotami',
4660 index: 'indices',
4661 larva: 'larvae',
4662 leaf: 'leaves',
4663 libretto: 'libretti',
4664 loaf: 'loaves',
4665 man: 'men',
4666 matrix: 'matrices',
4667 memorandum: 'memoranda',
4668 modulus: 'moduli',
4669 mosquito: 'mosquitoes',
4670 mouse: 'mice',
4671 // move: 'moves',
4672 nebula: 'nebulae',
4673 nucleus: 'nuclei',
4674 octopus: 'octopi',
4675 opus: 'opera',
4676 ovum: 'ova',
4677 ox: 'oxen',
4678 parenthesis: 'parentheses',
4679 person: 'people',
4680 phenomenon: 'phenomena',
4681 prognosis: 'prognoses',
4682 quiz: 'quizzes',
4683 radius: 'radii',
4684 referendum: 'referenda',
4685 rodeo: 'rodeos',
4686 sex: 'sexes',
4687 shoe: 'shoes',
4688 sombrero: 'sombreros',
4689 stimulus: 'stimuli',
4690 stomach: 'stomachs',
4691 syllabus: 'syllabi',
4692 synopsis: 'synopses',
4693 tableau: 'tableaux',
4694 thesis: 'theses',
4695 thief: 'thieves',
4696 tooth: 'teeth',
4697 tornado: 'tornados',
4698 tuxedo: 'tuxedos',
4699 vertebra: 'vertebrae' // virus: 'viri',
4700 // zero: 'zeros',
4701
4702};
4703
4704// a list of irregular verb conjugations
4705// used in verbs().conjugate()
4706// but also added to our lexicon
4707//use shorter key-names
4708var mapping = {
4709 g: 'Gerund',
4710 prt: 'Participle',
4711 perf: 'PerfectTense',
4712 pst: 'PastTense',
4713 fut: 'FuturePerfect',
4714 pres: 'PresentTense',
4715 pluperf: 'Pluperfect',
4716 a: 'Actor'
4717}; // '_' in conjugations is the infinitive form
4718// (order matters, to the lexicon)
4719
4720var conjugations = {
4721 act: {
4722 a: '_or'
4723 },
4724 ache: {
4725 pst: 'ached',
4726 g: 'aching'
4727 },
4728 age: {
4729 g: 'ageing',
4730 pst: 'aged',
4731 pres: 'ages'
4732 },
4733 aim: {
4734 a: '_er',
4735 g: '_ing',
4736 pst: '_ed'
4737 },
4738 arise: {
4739 prt: '_n',
4740 pst: 'arose'
4741 },
4742 babysit: {
4743 a: '_ter',
4744 pst: 'babysat'
4745 },
4746 ban: {
4747 a: '',
4748 g: '_ning',
4749 pst: '_ned'
4750 },
4751 be: {
4752 a: '',
4753 g: 'am',
4754 prt: 'been',
4755 pst: 'was',
4756 pres: 'is'
4757 },
4758 beat: {
4759 a: '_er',
4760 g: '_ing',
4761 prt: '_en'
4762 },
4763 become: {
4764 prt: '_'
4765 },
4766 begin: {
4767 g: '_ning',
4768 prt: 'begun',
4769 pst: 'began'
4770 },
4771 being: {
4772 g: 'are',
4773 pst: 'were',
4774 pres: 'are'
4775 },
4776 bend: {
4777 prt: 'bent'
4778 },
4779 bet: {
4780 a: '_ter',
4781 prt: '_'
4782 },
4783 bind: {
4784 pst: 'bound'
4785 },
4786 bite: {
4787 g: 'biting',
4788 prt: 'bitten',
4789 pst: 'bit'
4790 },
4791 bleed: {
4792 pst: 'bled',
4793 prt: 'bled'
4794 },
4795 blow: {
4796 prt: '_n',
4797 pst: 'blew'
4798 },
4799 boil: {
4800 a: '_er'
4801 },
4802 brake: {
4803 prt: 'broken'
4804 },
4805 "break": {
4806 pst: 'broke'
4807 },
4808 breed: {
4809 pst: 'bred'
4810 },
4811 bring: {
4812 pst: 'brought',
4813 prt: 'brought'
4814 },
4815 broadcast: {
4816 pst: '_'
4817 },
4818 budget: {
4819 pst: '_ed'
4820 },
4821 build: {
4822 pst: 'built',
4823 prt: 'built'
4824 },
4825 burn: {
4826 prt: '_ed'
4827 },
4828 burst: {
4829 prt: '_'
4830 },
4831 buy: {
4832 pst: 'bought',
4833 prt: 'bought'
4834 },
4835 can: {
4836 a: '',
4837 fut: '_',
4838 g: '',
4839 pst: 'could',
4840 perf: 'could',
4841 pluperf: 'could',
4842 pres: '_'
4843 },
4844 "catch": {
4845 pst: 'caught'
4846 },
4847 choose: {
4848 g: 'choosing',
4849 prt: 'chosen',
4850 pst: 'chose'
4851 },
4852 cling: {
4853 prt: 'clung'
4854 },
4855 come: {
4856 prt: '_',
4857 pst: 'came',
4858 g: 'coming'
4859 },
4860 compete: {
4861 a: 'competitor',
4862 g: 'competing',
4863 pst: '_d'
4864 },
4865 cost: {
4866 pst: '_'
4867 },
4868 creep: {
4869 prt: 'crept'
4870 },
4871 cut: {
4872 prt: '_'
4873 },
4874 deal: {
4875 pst: '_t',
4876 prt: '_t'
4877 },
4878 develop: {
4879 a: '_er',
4880 g: '_ing',
4881 pst: '_ed'
4882 },
4883 die: {
4884 g: 'dying',
4885 pst: '_d'
4886 },
4887 dig: {
4888 g: '_ging',
4889 pst: 'dug',
4890 prt: 'dug'
4891 },
4892 dive: {
4893 prt: '_d'
4894 },
4895 "do": {
4896 pst: 'did',
4897 pres: '_es'
4898 },
4899 draw: {
4900 prt: '_n',
4901 pst: 'drew'
4902 },
4903 dream: {
4904 prt: '_t'
4905 },
4906 drink: {
4907 prt: 'drunk',
4908 pst: 'drank'
4909 },
4910 drive: {
4911 g: 'driving',
4912 prt: '_n',
4913 pst: 'drove'
4914 },
4915 drop: {
4916 g: '_ping',
4917 pst: '_ped'
4918 },
4919 eat: {
4920 a: '_er',
4921 g: '_ing',
4922 prt: '_en',
4923 pst: 'ate'
4924 },
4925 edit: {
4926 pst: '_ed',
4927 g: '_ing'
4928 },
4929 egg: {
4930 pst: '_ed'
4931 },
4932 fall: {
4933 prt: '_en',
4934 pst: 'fell'
4935 },
4936 feed: {
4937 prt: 'fed',
4938 pst: 'fed'
4939 },
4940 feel: {
4941 a: '_er',
4942 pst: 'felt'
4943 },
4944 fight: {
4945 pst: 'fought',
4946 prt: 'fought'
4947 },
4948 find: {
4949 pst: 'found'
4950 },
4951 flee: {
4952 g: '_ing',
4953 prt: 'fled'
4954 },
4955 fling: {
4956 prt: 'flung'
4957 },
4958 fly: {
4959 prt: 'flown',
4960 pst: 'flew'
4961 },
4962 forbid: {
4963 pst: 'forbade'
4964 },
4965 forget: {
4966 g: '_ing',
4967 prt: 'forgotten',
4968 pst: 'forgot'
4969 },
4970 forgive: {
4971 g: 'forgiving',
4972 prt: '_n',
4973 pst: 'forgave'
4974 },
4975 free: {
4976 a: '',
4977 g: '_ing'
4978 },
4979 freeze: {
4980 g: 'freezing',
4981 prt: 'frozen',
4982 pst: 'froze'
4983 },
4984 get: {
4985 pst: 'got',
4986 prt: 'gotten'
4987 },
4988 give: {
4989 g: 'giving',
4990 prt: '_n',
4991 pst: 'gave'
4992 },
4993 go: {
4994 prt: '_ne',
4995 pst: 'went',
4996 pres: 'goes'
4997 },
4998 grow: {
4999 prt: '_n'
5000 },
5001 guide: {
5002 pst: '_d'
5003 },
5004 hang: {
5005 pst: 'hung',
5006 prt: 'hung'
5007 },
5008 have: {
5009 g: 'having',
5010 pst: 'had',
5011 prt: 'had',
5012 pres: 'has'
5013 },
5014 hear: {
5015 pst: '_d',
5016 prt: '_d'
5017 },
5018 hide: {
5019 prt: 'hidden',
5020 pst: 'hid'
5021 },
5022 hit: {
5023 prt: '_'
5024 },
5025 hold: {
5026 pst: 'held',
5027 prt: 'held'
5028 },
5029 hurt: {
5030 pst: '_',
5031 prt: '_'
5032 },
5033 ice: {
5034 g: 'icing',
5035 pst: '_d'
5036 },
5037 imply: {
5038 pst: 'implied',
5039 pres: 'implies'
5040 },
5041 is: {
5042 a: '',
5043 g: 'being',
5044 pst: 'was',
5045 pres: '_'
5046 },
5047 keep: {
5048 prt: 'kept'
5049 },
5050 kneel: {
5051 prt: 'knelt'
5052 },
5053 know: {
5054 prt: '_n'
5055 },
5056 lay: {
5057 pst: 'laid',
5058 prt: 'laid'
5059 },
5060 lead: {
5061 pst: 'led',
5062 prt: 'led'
5063 },
5064 leap: {
5065 prt: '_t'
5066 },
5067 leave: {
5068 pst: 'left',
5069 prt: 'left'
5070 },
5071 lend: {
5072 prt: 'lent'
5073 },
5074 lie: {
5075 g: 'lying',
5076 pst: 'lay'
5077 },
5078 light: {
5079 pst: 'lit',
5080 prt: 'lit'
5081 },
5082 log: {
5083 g: '_ging',
5084 pst: '_ged'
5085 },
5086 loose: {
5087 prt: 'lost'
5088 },
5089 lose: {
5090 g: 'losing',
5091 pst: 'lost'
5092 },
5093 make: {
5094 pst: 'made',
5095 prt: 'made'
5096 },
5097 mean: {
5098 pst: '_t',
5099 prt: '_t'
5100 },
5101 meet: {
5102 a: '_er',
5103 g: '_ing',
5104 pst: 'met',
5105 prt: 'met'
5106 },
5107 miss: {
5108 pres: '_'
5109 },
5110 name: {
5111 g: 'naming'
5112 },
5113 patrol: {
5114 g: '_ling',
5115 pst: '_led'
5116 },
5117 pay: {
5118 pst: 'paid',
5119 prt: 'paid'
5120 },
5121 prove: {
5122 prt: '_n'
5123 },
5124 puke: {
5125 g: 'puking'
5126 },
5127 put: {
5128 prt: '_'
5129 },
5130 quit: {
5131 prt: '_'
5132 },
5133 read: {
5134 pst: '_',
5135 prt: '_'
5136 },
5137 ride: {
5138 prt: 'ridden'
5139 },
5140 reside: {
5141 pst: '_d'
5142 },
5143 ring: {
5144 pst: 'rang',
5145 prt: 'rung'
5146 },
5147 rise: {
5148 fut: 'will have _n',
5149 g: 'rising',
5150 prt: '_n',
5151 pst: 'rose',
5152 pluperf: 'had _n'
5153 },
5154 rub: {
5155 g: '_bing',
5156 pst: '_bed'
5157 },
5158 run: {
5159 g: '_ning',
5160 prt: '_',
5161 pst: 'ran'
5162 },
5163 say: {
5164 pst: 'said',
5165 prt: 'said',
5166 pres: '_s'
5167 },
5168 seat: {
5169 pst: 'sat',
5170 prt: 'sat'
5171 },
5172 see: {
5173 g: '_ing',
5174 prt: '_n',
5175 pst: 'saw'
5176 },
5177 seek: {
5178 prt: 'sought'
5179 },
5180 sell: {
5181 pst: 'sold',
5182 prt: 'sold'
5183 },
5184 send: {
5185 prt: 'sent'
5186 },
5187 set: {
5188 prt: '_'
5189 },
5190 sew: {
5191 prt: '_n'
5192 },
5193 shake: {
5194 prt: '_n'
5195 },
5196 shave: {
5197 prt: '_d'
5198 },
5199 shed: {
5200 g: '_ding',
5201 pst: '_',
5202 pres: '_s'
5203 },
5204 shine: {
5205 pst: 'shone',
5206 prt: 'shone'
5207 },
5208 shoot: {
5209 pst: 'shot',
5210 prt: 'shot'
5211 },
5212 show: {
5213 pst: '_ed'
5214 },
5215 shut: {
5216 prt: '_'
5217 },
5218 sing: {
5219 prt: 'sung',
5220 pst: 'sang'
5221 },
5222 sink: {
5223 pst: 'sank',
5224 pluperf: 'had sunk'
5225 },
5226 sit: {
5227 pst: 'sat'
5228 },
5229 ski: {
5230 pst: '_ied'
5231 },
5232 slay: {
5233 prt: 'slain'
5234 },
5235 sleep: {
5236 prt: 'slept'
5237 },
5238 slide: {
5239 pst: 'slid',
5240 prt: 'slid'
5241 },
5242 smash: {
5243 pres: '_es'
5244 },
5245 sneak: {
5246 prt: 'snuck'
5247 },
5248 speak: {
5249 fut: 'will have spoken',
5250 prt: 'spoken',
5251 pst: 'spoke',
5252 perf: 'have spoken',
5253 pluperf: 'had spoken'
5254 },
5255 speed: {
5256 prt: 'sped'
5257 },
5258 spend: {
5259 prt: 'spent'
5260 },
5261 spill: {
5262 prt: '_ed',
5263 pst: 'spilt'
5264 },
5265 spin: {
5266 g: '_ning',
5267 pst: 'spun',
5268 prt: 'spun'
5269 },
5270 spit: {
5271 prt: 'spat'
5272 },
5273 split: {
5274 prt: '_'
5275 },
5276 spread: {
5277 pst: '_'
5278 },
5279 spring: {
5280 prt: 'sprung'
5281 },
5282 stand: {
5283 pst: 'stood'
5284 },
5285 steal: {
5286 a: '_er',
5287 pst: 'stole'
5288 },
5289 stick: {
5290 pst: 'stuck'
5291 },
5292 sting: {
5293 pst: 'stung'
5294 },
5295 stink: {
5296 pst: 'stunk',
5297 prt: 'stunk'
5298 },
5299 stream: {
5300 a: '_er'
5301 },
5302 strew: {
5303 prt: '_n'
5304 },
5305 strike: {
5306 g: 'striking',
5307 pst: 'struck'
5308 },
5309 suit: {
5310 a: '_er',
5311 g: '_ing',
5312 pst: '_ed'
5313 },
5314 sware: {
5315 prt: 'sworn'
5316 },
5317 swear: {
5318 pst: 'swore'
5319 },
5320 sweep: {
5321 prt: 'swept'
5322 },
5323 swim: {
5324 g: '_ming',
5325 pst: 'swam'
5326 },
5327 swing: {
5328 pst: 'swung'
5329 },
5330 take: {
5331 fut: 'will have _n',
5332 pst: 'took',
5333 perf: 'have _n',
5334 pluperf: 'had _n'
5335 },
5336 teach: {
5337 pst: 'taught',
5338 pres: '_es'
5339 },
5340 tear: {
5341 pst: 'tore'
5342 },
5343 tell: {
5344 pst: 'told'
5345 },
5346 think: {
5347 pst: 'thought'
5348 },
5349 thrive: {
5350 prt: '_d'
5351 },
5352 tie: {
5353 g: 'tying',
5354 pst: '_d'
5355 },
5356 undergo: {
5357 prt: '_ne'
5358 },
5359 understand: {
5360 pst: 'understood'
5361 },
5362 upset: {
5363 prt: '_'
5364 },
5365 wait: {
5366 a: '_er',
5367 g: '_ing',
5368 pst: '_ed'
5369 },
5370 wake: {
5371 pst: 'woke'
5372 },
5373 wear: {
5374 pst: 'wore'
5375 },
5376 weave: {
5377 prt: 'woven'
5378 },
5379 wed: {
5380 pst: 'wed'
5381 },
5382 weep: {
5383 prt: 'wept'
5384 },
5385 win: {
5386 g: '_ning',
5387 pst: 'won'
5388 },
5389 wind: {
5390 prt: 'wound'
5391 },
5392 withdraw: {
5393 pst: 'withdrew'
5394 },
5395 wring: {
5396 prt: 'wrung'
5397 },
5398 write: {
5399 g: 'writing',
5400 prt: 'written',
5401 pst: 'wrote'
5402 }
5403}; //uncompress our ad-hoc compression scheme
5404
5405var keys = Object.keys(conjugations);
5406
5407var _loop = function _loop(i) {
5408 var inf = keys[i];
5409 var _final = {};
5410 Object.keys(conjugations[inf]).forEach(function (key) {
5411 var str = conjugations[inf][key]; //swap-in infinitives for '_'
5412
5413 str = str.replace('_', inf);
5414 var full = mapping[key];
5415 _final[full] = str;
5416 }); //over-write original
5417
5418 conjugations[inf] = _final;
5419};
5420
5421for (var i = 0; i < keys.length; i++) {
5422 _loop(i);
5423}
5424
5425var conjugations_1 = conjugations;
5426
5427var endsWith = {
5428 b: [{
5429 reg: /([^aeiou][aeiou])b$/i,
5430 repl: {
5431 pr: '$1bs',
5432 pa: '$1bbed',
5433 gr: '$1bbing'
5434 }
5435 }],
5436 d: [{
5437 reg: /(end)$/i,
5438 repl: {
5439 pr: '$1s',
5440 pa: 'ent',
5441 gr: '$1ing',
5442 ar: '$1er'
5443 }
5444 }, {
5445 reg: /(eed)$/i,
5446 repl: {
5447 pr: '$1s',
5448 pa: '$1ed',
5449 gr: '$1ing',
5450 ar: '$1er'
5451 }
5452 }, {
5453 reg: /(ed)$/i,
5454 repl: {
5455 pr: '$1s',
5456 pa: '$1ded',
5457 ar: '$1der',
5458 gr: '$1ding'
5459 }
5460 }, {
5461 reg: /([^aeiou][ou])d$/i,
5462 repl: {
5463 pr: '$1ds',
5464 pa: '$1dded',
5465 gr: '$1dding'
5466 }
5467 }],
5468 e: [{
5469 reg: /(eave)$/i,
5470 repl: {
5471 pr: '$1s',
5472 pa: '$1d',
5473 gr: 'eaving',
5474 ar: '$1r'
5475 }
5476 }, {
5477 reg: /(ide)$/i,
5478 repl: {
5479 pr: '$1s',
5480 pa: 'ode',
5481 gr: 'iding',
5482 ar: 'ider'
5483 }
5484 }, {
5485 //shake
5486 reg: /(t|sh?)(ake)$/i,
5487 repl: {
5488 pr: '$1$2s',
5489 pa: '$1ook',
5490 gr: '$1aking',
5491 ar: '$1$2r'
5492 }
5493 }, {
5494 //awake
5495 reg: /w(ake)$/i,
5496 repl: {
5497 pr: 'w$1s',
5498 pa: 'woke',
5499 gr: 'waking',
5500 ar: 'w$1r'
5501 }
5502 }, {
5503 //make
5504 reg: /m(ake)$/i,
5505 repl: {
5506 pr: 'm$1s',
5507 pa: 'made',
5508 gr: 'making',
5509 ar: 'm$1r'
5510 }
5511 }, {
5512 reg: /(a[tg]|i[zn]|ur|nc|gl|is)e$/i,
5513 repl: {
5514 pr: '$1es',
5515 pa: '$1ed',
5516 gr: '$1ing' // prt: '$1en',
5517
5518 }
5519 }, {
5520 reg: /([bd]l)e$/i,
5521 repl: {
5522 pr: '$1es',
5523 pa: '$1ed',
5524 gr: '$1ing'
5525 }
5526 }, {
5527 reg: /(om)e$/i,
5528 repl: {
5529 pr: '$1es',
5530 pa: 'ame',
5531 gr: '$1ing'
5532 }
5533 }],
5534 g: [{
5535 reg: /([^aeiou][ou])g$/i,
5536 repl: {
5537 pr: '$1gs',
5538 pa: '$1gged',
5539 gr: '$1gging'
5540 }
5541 }],
5542 h: [{
5543 reg: /(..)([cs]h)$/i,
5544 repl: {
5545 pr: '$1$2es',
5546 pa: '$1$2ed',
5547 gr: '$1$2ing'
5548 }
5549 }],
5550 k: [{
5551 reg: /(ink)$/i,
5552 repl: {
5553 pr: '$1s',
5554 pa: 'unk',
5555 gr: '$1ing',
5556 ar: '$1er'
5557 }
5558 }],
5559 m: [{
5560 reg: /([^aeiou][aeiou])m$/i,
5561 repl: {
5562 pr: '$1ms',
5563 pa: '$1mmed',
5564 gr: '$1mming'
5565 }
5566 }],
5567 n: [{
5568 reg: /(en)$/i,
5569 repl: {
5570 pr: '$1s',
5571 pa: '$1ed',
5572 gr: '$1ing'
5573 }
5574 }],
5575 p: [{
5576 reg: /(e)(ep)$/i,
5577 repl: {
5578 pr: '$1$2s',
5579 pa: '$1pt',
5580 gr: '$1$2ing',
5581 ar: '$1$2er'
5582 }
5583 }, {
5584 reg: /([^aeiou][aeiou])p$/i,
5585 repl: {
5586 pr: '$1ps',
5587 pa: '$1pped',
5588 gr: '$1pping'
5589 }
5590 }, {
5591 reg: /([aeiu])p$/i,
5592 repl: {
5593 pr: '$1ps',
5594 pa: '$1p',
5595 gr: '$1pping'
5596 }
5597 }],
5598 r: [{
5599 reg: /([td]er)$/i,
5600 repl: {
5601 pr: '$1s',
5602 pa: '$1ed',
5603 gr: '$1ing'
5604 }
5605 }, {
5606 reg: /(er)$/i,
5607 repl: {
5608 pr: '$1s',
5609 pa: '$1ed',
5610 gr: '$1ing'
5611 }
5612 }],
5613 s: [{
5614 reg: /(ish|tch|ess)$/i,
5615 repl: {
5616 pr: '$1es',
5617 pa: '$1ed',
5618 gr: '$1ing'
5619 }
5620 }],
5621 t: [{
5622 reg: /(ion|end|e[nc]t)$/i,
5623 repl: {
5624 pr: '$1s',
5625 pa: '$1ed',
5626 gr: '$1ing'
5627 }
5628 }, {
5629 reg: /(.eat)$/i,
5630 repl: {
5631 pr: '$1s',
5632 pa: '$1ed',
5633 gr: '$1ing'
5634 }
5635 }, {
5636 reg: /([aeiu])t$/i,
5637 repl: {
5638 pr: '$1ts',
5639 pa: '$1t',
5640 gr: '$1tting'
5641 }
5642 }, {
5643 reg: /([^aeiou][aeiou])t$/i,
5644 repl: {
5645 pr: '$1ts',
5646 pa: '$1tted',
5647 gr: '$1tting'
5648 }
5649 }],
5650 w: [{
5651 reg: /(.llow)$/i,
5652 //follow, allow
5653 repl: {
5654 pr: '$1s',
5655 pa: '$1ed'
5656 }
5657 }, {
5658 reg: /(..)(ow)$/i,
5659 //grow
5660 repl: {
5661 pr: '$1$2s',
5662 pa: '$1ew',
5663 gr: '$1$2ing',
5664 prt: '$1$2n'
5665 }
5666 }],
5667 y: [{
5668 reg: /([i|f|rr])y$/i,
5669 repl: {
5670 pr: '$1ies',
5671 pa: '$1ied',
5672 gr: '$1ying'
5673 }
5674 }],
5675 z: [{
5676 reg: /([aeiou]zz)$/i,
5677 repl: {
5678 pr: '$1es',
5679 pa: '$1ed',
5680 gr: '$1ing'
5681 }
5682 }]
5683};
5684var suffixes = endsWith;
5685
5686var posMap = {
5687 pr: 'PresentTense',
5688 pa: 'PastTense',
5689 gr: 'Gerund',
5690 prt: 'Participle',
5691 ar: 'Actor'
5692};
5693
5694var doTransform = function doTransform(str, obj) {
5695 var found = {};
5696 var keys = Object.keys(obj.repl);
5697
5698 for (var i = 0; i < keys.length; i += 1) {
5699 var pos = keys[i];
5700 found[posMap[pos]] = str.replace(obj.reg, obj.repl[pos]);
5701 }
5702
5703 return found;
5704}; //look at the end of the word for clues
5705
5706
5707var checkSuffix = function checkSuffix() {
5708 var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
5709 var c = str[str.length - 1];
5710
5711 if (suffixes.hasOwnProperty(c) === true) {
5712 for (var r = 0; r < suffixes[c].length; r += 1) {
5713 var reg = suffixes[c][r].reg;
5714
5715 if (reg.test(str) === true) {
5716 return doTransform(str, suffixes[c][r]);
5717 }
5718 }
5719 }
5720
5721 return {};
5722};
5723
5724var _01Suffixes = checkSuffix;
5725
5726//non-specifc, 'hail-mary' transforms from infinitive, into other forms
5727var hasY = /[bcdfghjklmnpqrstvwxz]y$/;
5728var generic = {
5729 Gerund: function Gerund(inf) {
5730 if (inf.charAt(inf.length - 1) === 'e') {
5731 return inf.replace(/e$/, 'ing');
5732 }
5733
5734 return inf + 'ing';
5735 },
5736 PresentTense: function PresentTense(inf) {
5737 if (inf.charAt(inf.length - 1) === 's') {
5738 return inf + 'es';
5739 }
5740
5741 if (hasY.test(inf) === true) {
5742 return inf.slice(0, -1) + 'ies';
5743 }
5744
5745 return inf + 's';
5746 },
5747 PastTense: function PastTense(inf) {
5748 if (inf.charAt(inf.length - 1) === 'e') {
5749 return inf + 'd';
5750 }
5751
5752 if (inf.substr(-2) === 'ed') {
5753 return inf;
5754 }
5755
5756 if (hasY.test(inf) === true) {
5757 return inf.slice(0, -1) + 'ied';
5758 }
5759
5760 return inf + 'ed';
5761 }
5762};
5763var _02Generic = generic;
5764
5765//we assume the input word is a proper infinitive
5766
5767var conjugate = function conjugate() {
5768 var inf = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
5769 var world = arguments.length > 1 ? arguments[1] : undefined;
5770 var found = {}; // 1. look at irregulars
5771 //the lexicon doesn't pass this in
5772
5773 if (world && world.irregulars) {
5774 if (world.irregulars.verbs.hasOwnProperty(inf) === true) {
5775 found = Object.assign({}, world.irregulars.verbs[inf]);
5776 }
5777 } //2. rule-based regex
5778
5779
5780 found = Object.assign({}, _01Suffixes(inf), found); //3. generic transformations
5781 //'buzzing'
5782
5783 if (found.Gerund === undefined) {
5784 found.Gerund = _02Generic.Gerund(inf);
5785 } //'buzzed'
5786
5787
5788 if (found.PastTense === undefined) {
5789 found.PastTense = _02Generic.PastTense(inf);
5790 } //'buzzes'
5791
5792
5793 if (found.PresentTense === undefined) {
5794 found.PresentTense = _02Generic.PresentTense(inf);
5795 }
5796
5797 return found;
5798};
5799
5800var conjugate_1 = conjugate; // console.log(conjugate('bake'))
5801
5802//turn 'quick' into 'quickest'
5803var do_rules = [/ght$/, /nge$/, /ough$/, /ain$/, /uel$/, /[au]ll$/, /ow$/, /oud$/, /...p$/];
5804var dont_rules = [/ary$/];
5805var irregulars = {
5806 nice: 'nicest',
5807 late: 'latest',
5808 hard: 'hardest',
5809 inner: 'innermost',
5810 outer: 'outermost',
5811 far: 'furthest',
5812 worse: 'worst',
5813 bad: 'worst',
5814 good: 'best',
5815 big: 'biggest',
5816 large: 'largest'
5817};
5818var transforms = [{
5819 reg: /y$/i,
5820 repl: 'iest'
5821}, {
5822 reg: /([aeiou])t$/i,
5823 repl: '$1ttest'
5824}, {
5825 reg: /([aeou])de$/i,
5826 repl: '$1dest'
5827}, {
5828 reg: /nge$/i,
5829 repl: 'ngest'
5830}, {
5831 reg: /([aeiou])te$/i,
5832 repl: '$1test'
5833}];
5834
5835var to_superlative = function to_superlative(str) {
5836 //irregulars
5837 if (irregulars.hasOwnProperty(str)) {
5838 return irregulars[str];
5839 } //known transforms
5840
5841
5842 for (var i = 0; i < transforms.length; i++) {
5843 if (transforms[i].reg.test(str)) {
5844 return str.replace(transforms[i].reg, transforms[i].repl);
5845 }
5846 } //dont-rules
5847
5848
5849 for (var _i = 0; _i < dont_rules.length; _i++) {
5850 if (dont_rules[_i].test(str) === true) {
5851 return null;
5852 }
5853 } //do-rules
5854
5855
5856 for (var _i2 = 0; _i2 < do_rules.length; _i2++) {
5857 if (do_rules[_i2].test(str) === true) {
5858 if (str.charAt(str.length - 1) === 'e') {
5859 return str + 'st';
5860 }
5861
5862 return str + 'est';
5863 }
5864 }
5865
5866 return str + 'est';
5867};
5868
5869var toSuperlative = to_superlative;
5870
5871//turn 'quick' into 'quickly'
5872var do_rules$1 = [/ght$/, /nge$/, /ough$/, /ain$/, /uel$/, /[au]ll$/, /ow$/, /old$/, /oud$/, /e[ae]p$/];
5873var dont_rules$1 = [/ary$/, /ous$/];
5874var irregulars$1 = {
5875 grey: 'greyer',
5876 gray: 'grayer',
5877 green: 'greener',
5878 yellow: 'yellower',
5879 red: 'redder',
5880 good: 'better',
5881 well: 'better',
5882 bad: 'worse',
5883 sad: 'sadder',
5884 big: 'bigger'
5885};
5886var transforms$1 = [{
5887 reg: /y$/i,
5888 repl: 'ier'
5889}, {
5890 reg: /([aeiou])t$/i,
5891 repl: '$1tter'
5892}, {
5893 reg: /([aeou])de$/i,
5894 repl: '$1der'
5895}, {
5896 reg: /nge$/i,
5897 repl: 'nger'
5898}];
5899
5900var to_comparative = function to_comparative(str) {
5901 //known-irregulars
5902 if (irregulars$1.hasOwnProperty(str)) {
5903 return irregulars$1[str];
5904 } //known-transforms
5905
5906
5907 for (var i = 0; i < transforms$1.length; i++) {
5908 if (transforms$1[i].reg.test(str) === true) {
5909 return str.replace(transforms$1[i].reg, transforms$1[i].repl);
5910 }
5911 } //dont-patterns
5912
5913
5914 for (var _i = 0; _i < dont_rules$1.length; _i++) {
5915 if (dont_rules$1[_i].test(str) === true) {
5916 return null;
5917 }
5918 } //do-patterns
5919
5920
5921 for (var _i2 = 0; _i2 < do_rules$1.length; _i2++) {
5922 if (do_rules$1[_i2].test(str) === true) {
5923 return str + 'er';
5924 }
5925 } //easy-one
5926
5927
5928 if (/e$/.test(str) === true) {
5929 return str + 'r';
5930 }
5931
5932 return str + 'er';
5933};
5934
5935var toComparative = to_comparative;
5936
5937var fns$1 = {
5938 toSuperlative: toSuperlative,
5939 toComparative: toComparative
5940};
5941/** conjugate an adjective into other forms */
5942
5943var conjugate$1 = function conjugate(w) {
5944 var res = {}; // 'greatest'
5945
5946 var sup = fns$1.toSuperlative(w);
5947
5948 if (sup) {
5949 res.Superlative = sup;
5950 } // 'greater'
5951
5952
5953 var comp = fns$1.toComparative(w);
5954
5955 if (comp) {
5956 res.Comparative = comp;
5957 }
5958
5959 return res;
5960};
5961
5962var adjectives = conjugate$1;
5963
5964/** patterns for turning 'bus' to 'buses'*/
5965var suffixes$1 = {
5966 a: [[/(antenn|formul|nebul|vertebr|vit)a$/i, '$1ae'], [/([ti])a$/i, '$1a']],
5967 e: [[/(kn|l|w)ife$/i, '$1ives'], [/(hive)$/i, '$1s'], [/([m|l])ouse$/i, '$1ice'], [/([m|l])ice$/i, '$1ice']],
5968 f: [[/^(dwar|handkerchie|hoo|scar|whar)f$/i, '$1ves'], [/^((?:ca|e|ha|(?:our|them|your)?se|she|wo)l|lea|loa|shea|thie)f$/i, '$1ves']],
5969 i: [[/(octop|vir)i$/i, '$1i']],
5970 m: [[/([ti])um$/i, '$1a']],
5971 n: [[/^(oxen)$/i, '$1']],
5972 o: [[/(al|ad|at|er|et|ed|ad)o$/i, '$1oes']],
5973 s: [[/(ax|test)is$/i, '$1es'], [/(alias|status)$/i, '$1es'], [/sis$/i, 'ses'], [/(bu)s$/i, '$1ses'], [/(sis)$/i, 'ses'], [/^(?!talis|.*hu)(.*)man$/i, '$1men'], [/(octop|vir|radi|nucle|fung|cact|stimul)us$/i, '$1i']],
5974 x: [[/(matr|vert|ind|cort)(ix|ex)$/i, '$1ices'], [/^(ox)$/i, '$1en']],
5975 y: [[/([^aeiouy]|qu)y$/i, '$1ies']],
5976 z: [[/(quiz)$/i, '$1zes']]
5977};
5978var _rules = suffixes$1;
5979
5980var addE = /(x|ch|sh|s|z)$/;
5981
5982var trySuffix = function trySuffix(str) {
5983 var c = str[str.length - 1];
5984
5985 if (_rules.hasOwnProperty(c) === true) {
5986 for (var i = 0; i < _rules[c].length; i += 1) {
5987 var reg = _rules[c][i][0];
5988
5989 if (reg.test(str) === true) {
5990 return str.replace(reg, _rules[c][i][1]);
5991 }
5992 }
5993 }
5994
5995 return null;
5996};
5997/** Turn a singular noun into a plural
5998 * assume the given string is singular
5999 */
6000
6001
6002var pluralize = function pluralize() {
6003 var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
6004 var world = arguments.length > 1 ? arguments[1] : undefined;
6005 var irregulars = world.irregulars.nouns; // check irregulars list
6006
6007 if (irregulars.hasOwnProperty(str)) {
6008 return irregulars[str];
6009 } //we have some rules to try-out
6010
6011
6012 var plural = trySuffix(str);
6013
6014 if (plural !== null) {
6015 return plural;
6016 } //like 'church'
6017
6018
6019 if (addE.test(str)) {
6020 return str + 'es';
6021 } // ¯\_(ツ)_/¯
6022
6023
6024 return str + 's';
6025};
6026
6027var toPlural = pluralize;
6028
6029//patterns for turning 'dwarves' to 'dwarf'
6030var _rules$1 = [[/([^v])ies$/i, '$1y'], [/ises$/i, 'isis'], [/(kn|[^o]l|w)ives$/i, '$1ife'], [/^((?:ca|e|ha|(?:our|them|your)?se|she|wo)l|lea|loa|shea|thie)ves$/i, '$1f'], [/^(dwar|handkerchie|hoo|scar|whar)ves$/i, '$1f'], [/(antenn|formul|nebul|vertebr|vit)ae$/i, '$1a'], [/(octop|vir|radi|nucle|fung|cact|stimul)(i)$/i, '$1us'], [/(buffal|tomat|tornad)(oes)$/i, '$1o'], // [/(analy|diagno|parenthe|progno|synop|the)ses$/i, '$1sis'],
6031[/(eas)es$/i, '$1e'], //diseases
6032[/(..[aeiou]s)es$/i, '$1'], //geniouses
6033[/(vert|ind|cort)(ices)$/i, '$1ex'], [/(matr|append)(ices)$/i, '$1ix'], [/(x|ch|ss|sh|z|o)es$/i, '$1'], [/men$/i, 'man'], [/(n)ews$/i, '$1ews'], [/([ti])a$/i, '$1um'], [/([^aeiouy]|qu)ies$/i, '$1y'], [/(s)eries$/i, '$1eries'], [/(m)ovies$/i, '$1ovie'], [/([m|l])ice$/i, '$1ouse'], [/(cris|ax|test)es$/i, '$1is'], [/(alias|status)es$/i, '$1'], [/(ss)$/i, '$1'], [/(ics)$/i, '$1'], [/s$/i, '']];
6034
6035var invertObj = function invertObj(obj) {
6036 return Object.keys(obj).reduce(function (h, k) {
6037 h[obj[k]] = k;
6038 return h;
6039 }, {});
6040};
6041
6042var toSingular = function toSingular(str, world) {
6043 var irregulars = world.irregulars.nouns;
6044 var invert = invertObj(irregulars); //(not very efficient)
6045 // check irregulars list
6046
6047 if (invert.hasOwnProperty(str)) {
6048 return invert[str];
6049 } // go through our regexes
6050
6051
6052 for (var i = 0; i < _rules$1.length; i++) {
6053 if (_rules$1[i][0].test(str) === true) {
6054 str = str.replace(_rules$1[i][0], _rules$1[i][1]);
6055 return str;
6056 }
6057 }
6058
6059 return str;
6060};
6061
6062var toSingular_1 = toSingular;
6063
6064//rules for turning a verb into infinitive form
6065var rules = {
6066 Participle: [{
6067 reg: /own$/i,
6068 to: 'ow'
6069 }, {
6070 reg: /(.)un([g|k])$/i,
6071 to: '$1in$2'
6072 }],
6073 Actor: [{
6074 reg: /(er)er$/i,
6075 to: '$1'
6076 }],
6077 PresentTense: [{
6078 reg: /(..)(ies)$/i,
6079 to: '$1y'
6080 }, {
6081 reg: /(tch|sh)es$/i,
6082 to: '$1'
6083 }, {
6084 reg: /(ss|zz)es$/i,
6085 to: '$1'
6086 }, {
6087 reg: /([tzlshicgrvdnkmu])es$/i,
6088 to: '$1e'
6089 }, {
6090 reg: /(n[dtk]|c[kt]|[eo]n|i[nl]|er|a[ytrl])s$/i,
6091 to: '$1'
6092 }, {
6093 reg: /(ow)s$/i,
6094 to: '$1'
6095 }, {
6096 reg: /(op)s$/i,
6097 to: '$1'
6098 }, {
6099 reg: /([eirs])ts$/i,
6100 to: '$1t'
6101 }, {
6102 reg: /(ll)s$/i,
6103 to: '$1'
6104 }, {
6105 reg: /(el)s$/i,
6106 to: '$1'
6107 }, {
6108 reg: /(ip)es$/i,
6109 to: '$1e'
6110 }, {
6111 reg: /ss$/i,
6112 to: 'ss'
6113 }, {
6114 reg: /s$/i,
6115 to: ''
6116 }],
6117 Gerund: [{
6118 //popping -> pop
6119 reg: /(..)(p|d|t|g){2}ing$/i,
6120 to: '$1$2'
6121 }, {
6122 //fuzzing -> fuzz
6123 reg: /(ll|ss|zz)ing$/i,
6124 to: '$1'
6125 }, {
6126 reg: /([^aeiou])ying$/i,
6127 to: '$1y'
6128 }, {
6129 reg: /([^ae]i.)ing$/i,
6130 to: '$1e'
6131 }, {
6132 //eating, reading
6133 reg: /(ea[dklnrtv])ing$/i,
6134 to: '$1'
6135 }, {
6136 //washing -> wash
6137 reg: /(ch|sh)ing$/i,
6138 to: '$1'
6139 }, //soft-e forms:
6140 {
6141 //z : hazing (not buzzing)
6142 reg: /(z)ing$/i,
6143 to: '$1e'
6144 }, {
6145 //a : baking, undulating
6146 reg: /(a[gdkvtc])ing$/i,
6147 to: '$1e'
6148 }, {
6149 //u : conjuring, tubing
6150 reg: /(u[rtcbn])ing$/i,
6151 to: '$1e'
6152 }, {
6153 //o : forboding, poking, hoping, boring (not hooping)
6154 reg: /([^o]o[bdknprv])ing$/i,
6155 to: '$1e'
6156 }, {
6157 //ling : tingling, wrinkling, circling, scrambling, bustling
6158 reg: /([tbckg]l)ing$/i,
6159 //dp
6160 to: '$1e'
6161 }, {
6162 //cing : bouncing, denouncing
6163 reg: /(c|s)ing$/i,
6164 //dp
6165 to: '$1e'
6166 }, // {
6167 // //soft-e :
6168 // reg: /([ua]s|[dr]g|z|o[rlsp]|cre)ing$/i,
6169 // to: '$1e',
6170 // },
6171 {
6172 //fallback
6173 reg: /(..)ing$/i,
6174 to: '$1'
6175 }],
6176 PastTense: [{
6177 reg: /(ued)$/i,
6178 to: 'ue'
6179 }, {
6180 reg: /a([^aeiouy])ed$/i,
6181 to: 'a$1e'
6182 }, {
6183 reg: /([aeiou]zz)ed$/i,
6184 to: '$1'
6185 }, {
6186 reg: /(e|i)lled$/i,
6187 to: '$1ll'
6188 }, {
6189 reg: /(.)(sh|ch)ed$/i,
6190 to: '$1$2'
6191 }, {
6192 reg: /(tl|gl)ed$/i,
6193 to: '$1e'
6194 }, {
6195 reg: /(um?pt?)ed$/i,
6196 to: '$1'
6197 }, {
6198 reg: /(ss)ed$/i,
6199 to: '$1'
6200 }, {
6201 reg: /pped$/i,
6202 to: 'p'
6203 }, {
6204 reg: /tted$/i,
6205 to: 't'
6206 }, {
6207 reg: /(..)gged$/i,
6208 to: '$1g'
6209 }, {
6210 reg: /(..)lked$/i,
6211 to: '$1lk'
6212 }, {
6213 reg: /([^aeiouy][aeiou])ked$/i,
6214 to: '$1ke'
6215 }, {
6216 reg: /(.[aeiou])led$/i,
6217 to: '$1l'
6218 }, {
6219 reg: /(..)(h|ion|n[dt]|ai.|[cs]t|pp|all|ss|tt|int|ail|ld|en|oo.|er|k|pp|w|ou.|rt|ght|rm)ed$/i,
6220 to: '$1$2'
6221 }, {
6222 reg: /(.ut)ed$/i,
6223 to: '$1e'
6224 }, {
6225 reg: /(.pt)ed$/i,
6226 to: '$1'
6227 }, {
6228 reg: /(us)ed$/i,
6229 to: '$1e'
6230 }, {
6231 reg: /(dd)ed$/i,
6232 to: '$1'
6233 }, {
6234 reg: /(..[^aeiouy])ed$/i,
6235 to: '$1e'
6236 }, {
6237 reg: /(..)ied$/i,
6238 to: '$1y'
6239 }, {
6240 reg: /(.o)ed$/i,
6241 to: '$1o'
6242 }, {
6243 reg: /(..i)ed$/i,
6244 to: '$1'
6245 }, {
6246 reg: /(.a[^aeiou])ed$/i,
6247 to: '$1'
6248 }, {
6249 //owed, aced
6250 reg: /([aeiou][^aeiou])ed$/i,
6251 to: '$1e'
6252 }, {
6253 reg: /([rl])ew$/i,
6254 to: '$1ow'
6255 }, {
6256 reg: /([pl])t$/i,
6257 to: '$1t'
6258 }]
6259};
6260var _transform = rules;
6261
6262var guessVerb = {
6263 Gerund: ['ing'],
6264 Actor: ['erer'],
6265 Infinitive: ['ate', 'ize', 'tion', 'rify', 'then', 'ress', 'ify', 'age', 'nce', 'ect', 'ise', 'ine', 'ish', 'ace', 'ash', 'ure', 'tch', 'end', 'ack', 'and', 'ute', 'ade', 'ock', 'ite', 'ase', 'ose', 'use', 'ive', 'int', 'nge', 'lay', 'est', 'ain', 'ant', 'ent', 'eed', 'er', 'le', 'own', 'unk', 'ung', 'en'],
6266 PastTense: ['ed', 'lt', 'nt', 'pt', 'ew', 'ld'],
6267 PresentTense: ['rks', 'cks', 'nks', 'ngs', 'mps', 'tes', 'zes', 'ers', 'les', 'acks', 'ends', 'ands', 'ocks', 'lays', 'eads', 'lls', 'els', 'ils', 'ows', 'nds', 'ays', 'ams', 'ars', 'ops', 'ffs', 'als', 'urs', 'lds', 'ews', 'ips', 'es', 'ts', 'ns']
6268}; //flip it into a lookup object
6269
6270guessVerb = Object.keys(guessVerb).reduce(function (h, k) {
6271 guessVerb[k].forEach(function (a) {
6272 return h[a] = k;
6273 });
6274 return h;
6275}, {});
6276var _guess = guessVerb;
6277
6278/** it helps to know what we're conjugating from */
6279
6280var guessTense = function guessTense(str) {
6281 var three = str.substr(str.length - 3);
6282
6283 if (_guess.hasOwnProperty(three) === true) {
6284 return _guess[three];
6285 }
6286
6287 var two = str.substr(str.length - 2);
6288
6289 if (_guess.hasOwnProperty(two) === true) {
6290 return _guess[two];
6291 }
6292
6293 var one = str.substr(str.length - 1);
6294
6295 if (one === 's') {
6296 return 'PresentTense';
6297 }
6298
6299 return null;
6300};
6301
6302var toInfinitive = function toInfinitive(str, world, tense) {
6303 if (!str) {
6304 return '';
6305 } //1. look at known irregulars
6306
6307
6308 if (world.words.hasOwnProperty(str) === true) {
6309 var irregs = world.irregulars.verbs;
6310 var keys = Object.keys(irregs);
6311
6312 for (var i = 0; i < keys.length; i++) {
6313 var forms = Object.keys(irregs[keys[i]]);
6314
6315 for (var o = 0; o < forms.length; o++) {
6316 if (str === irregs[keys[i]][forms[o]]) {
6317 return keys[i];
6318 }
6319 }
6320 }
6321 } // give'r!
6322
6323
6324 tense = tense || guessTense(str);
6325
6326 if (tense && _transform[tense]) {
6327 for (var _i = 0; _i < _transform[tense].length; _i++) {
6328 var rule = _transform[tense][_i];
6329
6330 if (rule.reg.test(str) === true) {
6331 // console.log(rule.reg)
6332 return str.replace(rule.reg, rule.to);
6333 }
6334 }
6335 }
6336
6337 return str;
6338};
6339
6340var toInfinitive_1 = toInfinitive;
6341
6342var irregulars$2 = {
6343 nouns: plurals,
6344 verbs: conjugations_1
6345}; //these behaviours are configurable & shared across some plugins
6346
6347var transforms$2 = {
6348 conjugate: conjugate_1,
6349 adjectives: adjectives,
6350 toPlural: toPlural,
6351 toSingular: toSingular_1,
6352 toInfinitive: toInfinitive_1
6353};
6354var _isVerbose = false;
6355/** all configurable linguistic data */
6356
6357var World = /*#__PURE__*/function () {
6358 function World() {
6359 _classCallCheck(this, World);
6360
6361 // quiet these properties from a console.log
6362 Object.defineProperty(this, 'words', {
6363 enumerable: false,
6364 value: misc$1,
6365 writable: true
6366 });
6367 Object.defineProperty(this, 'hasCompound', {
6368 enumerable: false,
6369 value: {},
6370 writable: true
6371 });
6372 Object.defineProperty(this, 'irregulars', {
6373 enumerable: false,
6374 value: irregulars$2,
6375 writable: true
6376 });
6377 Object.defineProperty(this, 'tags', {
6378 enumerable: false,
6379 value: Object.assign({}, tags),
6380 writable: true
6381 });
6382 Object.defineProperty(this, 'transforms', {
6383 enumerable: false,
6384 value: transforms$2,
6385 writable: true
6386 });
6387 Object.defineProperty(this, 'taggers', {
6388 enumerable: false,
6389 value: [],
6390 writable: true
6391 }); // add our misc word-list
6392 // this.addWords(misc)
6393 // add our compressed data to lexicon
6394
6395 this.unpackWords(_data); // add our irregulars to lexicon
6396
6397 addIrregulars_1(this); // cache our abbreviations for our sentence-parser
6398
6399 Object.defineProperty(this, 'cache', {
6400 enumerable: false,
6401 value: {
6402 abbreviations: this.getByTag('Abbreviation')
6403 }
6404 });
6405 }
6406 /** more logs for debugging */
6407
6408
6409 _createClass(World, [{
6410 key: "verbose",
6411 value: function verbose(bool) {
6412 _isVerbose = bool;
6413 return this;
6414 }
6415 }, {
6416 key: "isVerbose",
6417 value: function isVerbose() {
6418 return _isVerbose;
6419 }
6420 /** get all terms in our lexicon with this tag */
6421
6422 }, {
6423 key: "getByTag",
6424 value: function getByTag(tag) {
6425 var lex = this.words;
6426 var res = {};
6427 var words = Object.keys(lex);
6428
6429 for (var i = 0; i < words.length; i++) {
6430 if (typeof lex[words[i]] === 'string') {
6431 if (lex[words[i]] === tag) {
6432 res[words[i]] = true;
6433 }
6434 } else if (lex[words[i]].some(function (t) {
6435 return t === tag;
6436 })) {
6437 res[words[i]] = true;
6438 }
6439 }
6440
6441 return res;
6442 }
6443 /** augment our lingustic data with new data */
6444
6445 }, {
6446 key: "unpackWords",
6447 value: function unpackWords(lex) {
6448 var tags = Object.keys(lex);
6449
6450 for (var i = 0; i < tags.length; i++) {
6451 var words = Object.keys(efrtUnpack_min(lex[tags[i]]));
6452
6453 for (var w = 0; w < words.length; w++) {
6454 addWords.addWord(words[w], tags[i], this.words); // do some fancier stuff
6455
6456 addWords.addMore(words[w], tags[i], this);
6457 }
6458 }
6459 }
6460 /** put new words into our lexicon, properly */
6461
6462 }, {
6463 key: "addWords",
6464 value: function addWords$1(obj) {
6465 var keys = Object.keys(obj);
6466
6467 for (var i = 0; i < keys.length; i++) {
6468 var word = keys[i].toLowerCase();
6469 addWords.addWord(word, obj[keys[i]], this.words); // do some fancier stuff
6470
6471 addWords.addMore(word, obj[keys[i]], this);
6472 }
6473 }
6474 /** add new custom conjugations */
6475
6476 }, {
6477 key: "addConjugations",
6478 value: function addConjugations(obj) {
6479 Object.assign(this.irregulars.verbs, obj);
6480 return this;
6481 }
6482 /** add new custom plural/singular pairs */
6483
6484 }, {
6485 key: "addPlurals",
6486 value: function addPlurals(obj) {
6487 Object.assign(this.irregulars.nouns, obj);
6488 return this;
6489 }
6490 /** extend the compromise tagset */
6491
6492 }, {
6493 key: "addTags",
6494 value: function addTags(tags) {
6495 tags = Object.assign({}, tags);
6496 this.tags = Object.assign(this.tags, tags); // calculate graph implications for the new tags
6497
6498 this.tags = inference(this.tags);
6499 return this;
6500 }
6501 /** call methods after tagger runs */
6502
6503 }, {
6504 key: "postProcess",
6505 value: function postProcess(fn) {
6506 this.taggers.push(fn);
6507 return this;
6508 }
6509 /** helper method for logging + debugging */
6510
6511 }, {
6512 key: "stats",
6513 value: function stats() {
6514 return {
6515 words: Object.keys(this.words).length,
6516 plurals: Object.keys(this.irregulars.nouns).length,
6517 conjugations: Object.keys(this.irregulars.verbs).length,
6518 compounds: Object.keys(this.hasCompound).length,
6519 postProcessors: this.taggers.length
6520 };
6521 }
6522 }]);
6523
6524 return World;
6525}(); // ¯\_(:/)_/¯
6526
6527
6528var clone$1 = function clone(obj) {
6529 return JSON.parse(JSON.stringify(obj));
6530};
6531/** produce a deep-copy of all lingustic data */
6532
6533
6534World.prototype.clone = function () {
6535 var w2 = new World(); // these are simple to copy:
6536
6537 w2.words = Object.assign({}, this.words);
6538 w2.hasCompound = Object.assign({}, this.hasCompound); //these ones are nested:
6539
6540 w2.irregulars = clone$1(this.irregulars);
6541 w2.tags = clone$1(this.tags); // these are functions
6542
6543 w2.transforms = this.transforms;
6544 w2.taggers = this.taggers;
6545 return w2;
6546};
6547
6548var World_1 = World;
6549
6550/** return the root, first document */
6551
6552var _01Utils$1 = createCommonjsModule(function (module, exports) {
6553 exports.all = function () {
6554 return this.parents()[0] || this;
6555 };
6556 /** return the previous result */
6557
6558
6559 exports.parent = function () {
6560 if (this.from) {
6561 return this.from;
6562 }
6563
6564 return this;
6565 };
6566 /** return a list of all previous results */
6567
6568
6569 exports.parents = function (n) {
6570 var arr = [];
6571
6572 var addParent = function addParent(doc) {
6573 if (doc.from) {
6574 arr.push(doc.from);
6575 addParent(doc.from);
6576 }
6577 };
6578
6579 addParent(this);
6580 arr = arr.reverse();
6581
6582 if (typeof n === 'number') {
6583 return arr[n];
6584 }
6585
6586 return arr;
6587 };
6588 /** deep-copy the document, so that no references remain */
6589
6590
6591 exports.clone = function (doShallow) {
6592 var list = this.list.map(function (ts) {
6593 return ts.clone(doShallow);
6594 });
6595 var tmp = this.buildFrom(list);
6596 return tmp;
6597 };
6598 /** how many seperate terms does the document have? */
6599
6600
6601 exports.wordCount = function () {
6602 return this.list.reduce(function (count, p) {
6603 count += p.wordCount();
6604 return count;
6605 }, 0);
6606 };
6607
6608 exports.wordcount = exports.wordCount;
6609 /** turn on logging for decision-debugging */
6610 // exports.verbose = function(bool) {
6611 // if (bool === undefined) {
6612 // bool = true
6613 // }
6614 // this.world.verbose = bool
6615 // }
6616});
6617
6618/** use only the first result(s) */
6619
6620var _02Accessors = createCommonjsModule(function (module, exports) {
6621 exports.first = function (n) {
6622 if (n === undefined) {
6623 return this.get(0);
6624 }
6625
6626 return this.slice(0, n);
6627 };
6628 /** use only the last result(s) */
6629
6630
6631 exports.last = function (n) {
6632 if (n === undefined) {
6633 return this.get(this.list.length - 1);
6634 }
6635
6636 var end = this.list.length;
6637 return this.slice(end - n, end);
6638 };
6639 /** grab a given subset of the results*/
6640
6641
6642 exports.slice = function (start, end) {
6643 var list = this.list.slice(start, end);
6644 return this.buildFrom(list);
6645 };
6646 /* grab nth result */
6647
6648
6649 exports.eq = function (n) {
6650 var p = this.list[n];
6651
6652 if (p === undefined) {
6653 return this.buildFrom([]);
6654 }
6655
6656 return this.buildFrom([p]);
6657 };
6658
6659 exports.get = exports.eq;
6660 /** grab term[0] for every match */
6661
6662 exports.firstTerms = function () {
6663 return this.match('^.');
6664 };
6665
6666 exports.firstTerm = exports.firstTerms;
6667 /** grab the last term for every match */
6668
6669 exports.lastTerms = function () {
6670 return this.match('.$');
6671 };
6672
6673 exports.lastTerm = exports.lastTerms;
6674 /** return a flat array of term objects */
6675
6676 exports.termList = function (num) {
6677 var arr = []; //'reduce' but faster
6678
6679 for (var i = 0; i < this.list.length; i++) {
6680 var terms = this.list[i].terms();
6681
6682 for (var o = 0; o < terms.length; o++) {
6683 arr.push(terms[o]); //support .termList(4)
6684
6685 if (num !== undefined && arr[num] !== undefined) {
6686 return arr[num];
6687 }
6688 }
6689 }
6690
6691 return arr;
6692 };
6693 /* grab named capture group terms as object */
6694
6695
6696 var getGroups = function getGroups(doc) {
6697 var res = {};
6698 var allGroups = {};
6699
6700 var _loop = function _loop(i) {
6701 var phrase = doc.list[i];
6702 var groups = Object.keys(phrase.groups).map(function (k) {
6703 return phrase.groups[k];
6704 });
6705
6706 for (var j = 0; j < groups.length; j++) {
6707 var _groups$j = groups[j],
6708 group = _groups$j.group,
6709 start = _groups$j.start,
6710 length = _groups$j.length;
6711
6712 if (!allGroups[group]) {
6713 allGroups[group] = [];
6714 }
6715
6716 allGroups[group].push(phrase.buildFrom(start, length));
6717 }
6718 };
6719
6720 for (var i = 0; i < doc.list.length; i++) {
6721 _loop(i);
6722 }
6723
6724 var keys = Object.keys(allGroups);
6725
6726 for (var _i = 0; _i < keys.length; _i++) {
6727 var key = keys[_i];
6728 res[key] = doc.buildFrom(allGroups[key]);
6729 }
6730
6731 return res;
6732 };
6733 /** lookup a named-group, by its name */
6734
6735
6736 var getOneName = function getOneName(doc, name) {
6737 var arr = [];
6738
6739 var _loop2 = function _loop2(i) {
6740 var phrase = doc.list[i];
6741 var keys = Object.keys(phrase.groups);
6742 keys = keys.filter(function (id) {
6743 return phrase.groups[id].group === name;
6744 });
6745 keys.forEach(function (id) {
6746 arr.push(phrase.buildFrom(phrase.groups[id].start, phrase.groups[id].length));
6747 });
6748 };
6749
6750 for (var i = 0; i < doc.list.length; i++) {
6751 _loop2(i);
6752 }
6753
6754 return doc.buildFrom(arr);
6755 };
6756 /** grab named capture group results */
6757
6758
6759 exports.groups = function (target) {
6760 if (target === undefined) {
6761 return getGroups(this);
6762 }
6763
6764 if (typeof target === 'number') {
6765 target = String(target);
6766 }
6767
6768 return getOneName(this, target) || this.buildFrom([]);
6769 };
6770
6771 exports.group = exports.groups;
6772 /** get the full-sentence each phrase belongs to */
6773
6774 exports.sentences = function (n) {
6775 var arr = [];
6776 this.list.forEach(function (p) {
6777 arr.push(p.fullSentence());
6778 });
6779
6780 if (typeof n === 'number') {
6781 return this.buildFrom([arr[n]]);
6782 }
6783
6784 return this.buildFrom(arr);
6785 };
6786
6787 exports.sentence = exports.sentences;
6788});
6789
6790// cache the easier conditions up-front
6791var cacheRequired = function cacheRequired(reg) {
6792 var needTags = [];
6793 var needWords = [];
6794 reg.forEach(function (obj) {
6795 if (obj.optional === true || obj.negative === true) {
6796 return;
6797 }
6798
6799 if (obj.tag !== undefined) {
6800 needTags.push(obj.tag);
6801 }
6802
6803 if (obj.word !== undefined) {
6804 needWords.push(obj.word);
6805 }
6806 });
6807 return {
6808 tags: needTags,
6809 words: needWords
6810 };
6811}; // try to pre-fail as many matches as possible, without doing them
6812
6813
6814var failFast$1 = function failFast(doc, regs) {
6815 if (doc._cache && doc._cache.set === true) {
6816 var _cacheRequired = cacheRequired(regs),
6817 words = _cacheRequired.words,
6818 tags = _cacheRequired.tags; //check required words
6819
6820
6821 for (var i = 0; i < words.length; i++) {
6822 if (doc._cache.words[words[i]] === undefined) {
6823 return false;
6824 }
6825 } //check required tags
6826
6827
6828 for (var _i = 0; _i < tags.length; _i++) {
6829 if (doc._cache.tags[tags[_i]] === undefined) {
6830 return false;
6831 }
6832 }
6833 }
6834
6835 return true;
6836};
6837
6838var _failFast = failFast$1;
6839
6840var _03Match = createCommonjsModule(function (module, exports) {
6841 /** return a new Doc, with this one as a parent */
6842 exports.match = function (reg) {
6843 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6844
6845 // support '0' shorthand for named-groups
6846 if (typeof opts === 'string' || typeof opts === 'number' || opts === null) {
6847 opts = {
6848 group: opts
6849 };
6850 } //parse-up the input expression
6851
6852
6853 var regs = matchSyntax(reg, opts);
6854
6855 if (regs.length === 0) {
6856 return this.buildFrom([]);
6857 } //check our cache, if it exists
6858
6859
6860 if (_failFast(this, regs) === false) {
6861 return this.buildFrom([]);
6862 } //try expression on each phrase
6863
6864
6865 var matches = this.list.reduce(function (arr, p) {
6866 return arr.concat(p.match(regs));
6867 }, []); // support returning named groups
6868
6869 if (opts.group !== undefined && opts.group !== null && opts.group !== '') {
6870 return this.buildFrom(matches).groups(opts.group);
6871 }
6872
6873 return this.buildFrom(matches);
6874 };
6875 /** return all results except for this */
6876
6877
6878 exports.not = function (reg) {
6879 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6880 //parse-up the input expression
6881 var regs = matchSyntax(reg, opts); //if it's empty, return them all!
6882
6883 if (regs.length === 0 || _failFast(this, regs) === false) {
6884 return this;
6885 } //try expression on each phrase
6886
6887
6888 var matches = this.list.reduce(function (arr, p) {
6889 return arr.concat(p.not(regs));
6890 }, []);
6891 return this.buildFrom(matches);
6892 };
6893 /** return only the first match */
6894
6895
6896 exports.matchOne = function (reg) {
6897 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6898 var regs = matchSyntax(reg, opts); //check our cache, if it exists
6899
6900 if (_failFast(this, regs) === false) {
6901 return this.buildFrom([]);
6902 }
6903
6904 for (var i = 0; i < this.list.length; i++) {
6905 var match = this.list[i].match(regs, true);
6906 return this.buildFrom(match);
6907 }
6908
6909 return this.buildFrom([]);
6910 };
6911 /** return each current phrase, only if it contains this match */
6912
6913
6914 exports["if"] = function (reg) {
6915 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6916 var regs = matchSyntax(reg, opts); //consult our cache, if it exists
6917
6918 if (_failFast(this, regs) === false) {
6919 return this.buildFrom([]);
6920 }
6921
6922 var found = this.list.filter(function (p) {
6923 return p.has(regs) === true;
6924 });
6925 return this.buildFrom(found);
6926 };
6927 /** Filter-out any current phrases that have this match*/
6928
6929
6930 exports.ifNo = function (reg) {
6931 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6932 var regs = matchSyntax(reg, opts);
6933 var found = this.list.filter(function (p) {
6934 return p.has(regs) === false;
6935 });
6936 return this.buildFrom(found);
6937 };
6938 /**Return a boolean if this match exists */
6939
6940
6941 exports.has = function (reg) {
6942 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6943 var regs = matchSyntax(reg, opts); //consult our cache, if it exists
6944
6945 if (_failFast(this, regs) === false) {
6946 return false;
6947 }
6948
6949 return this.list.some(function (p) {
6950 return p.has(regs) === true;
6951 });
6952 };
6953 /** match any terms after our matches, within the sentence */
6954
6955
6956 exports.lookAhead = function (reg) {
6957 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6958
6959 // find everything afterwards, by default
6960 if (!reg) {
6961 reg = '.*';
6962 }
6963
6964 var regs = matchSyntax(reg, opts);
6965 var matches = [];
6966 this.list.forEach(function (p) {
6967 matches = matches.concat(p.lookAhead(regs));
6968 });
6969 matches = matches.filter(function (p) {
6970 return p;
6971 });
6972 return this.buildFrom(matches);
6973 };
6974
6975 exports.lookAfter = exports.lookAhead;
6976 /** match any terms before our matches, within the sentence */
6977
6978 exports.lookBehind = function (reg) {
6979 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6980
6981 // find everything afterwards, by default
6982 if (!reg) {
6983 reg = '.*';
6984 }
6985
6986 var regs = matchSyntax(reg, opts);
6987 var matches = [];
6988 this.list.forEach(function (p) {
6989 matches = matches.concat(p.lookBehind(regs));
6990 });
6991 matches = matches.filter(function (p) {
6992 return p;
6993 });
6994 return this.buildFrom(matches);
6995 };
6996
6997 exports.lookBefore = exports.lookBehind;
6998 /** return all terms before a match, in each phrase */
6999
7000 exports.before = function (reg) {
7001 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7002 var regs = matchSyntax(reg, opts); //only the phrases we care about
7003
7004 var phrases = this["if"](regs).list;
7005 var befores = phrases.map(function (p) {
7006 var ids = p.terms().map(function (t) {
7007 return t.id;
7008 }); //run the search again
7009
7010 var m = p.match(regs)[0];
7011 var index = ids.indexOf(m.start); //nothing is before a first-term match
7012
7013 if (index === 0 || index === -1) {
7014 return null;
7015 }
7016
7017 return p.buildFrom(p.start, index);
7018 });
7019 befores = befores.filter(function (p) {
7020 return p !== null;
7021 });
7022 return this.buildFrom(befores);
7023 };
7024 /** return all terms after a match, in each phrase */
7025
7026
7027 exports.after = function (reg) {
7028 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7029 var regs = matchSyntax(reg, opts); //only the phrases we care about
7030
7031 var phrases = this["if"](regs).list;
7032 var befores = phrases.map(function (p) {
7033 var terms = p.terms();
7034 var ids = terms.map(function (t) {
7035 return t.id;
7036 }); //run the search again
7037
7038 var m = p.match(regs)[0];
7039 var index = ids.indexOf(m.start); //skip if nothing is after it
7040
7041 if (index === -1 || !terms[index + m.length]) {
7042 return null;
7043 } //create the new phrase, after our match.
7044
7045
7046 var id = terms[index + m.length].id;
7047 var len = p.length - index - m.length;
7048 return p.buildFrom(id, len);
7049 });
7050 befores = befores.filter(function (p) {
7051 return p !== null;
7052 });
7053 return this.buildFrom(befores);
7054 };
7055 /** return only results with this match afterwards */
7056
7057
7058 exports.hasAfter = function (reg) {
7059 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7060 return this.filter(function (doc) {
7061 return doc.lookAfter(reg, opts).found;
7062 });
7063 };
7064 /** return only results with this match before it */
7065
7066
7067 exports.hasBefore = function (reg) {
7068 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7069 return this.filter(function (doc) {
7070 return doc.lookBefore(reg, opts).found;
7071 });
7072 };
7073});
7074
7075/** apply a tag, or tags to all terms */
7076var tagTerms = function tagTerms(tag, doc, safe, reason) {
7077 var tagList = [];
7078
7079 if (typeof tag === 'string') {
7080 tagList = tag.split(' ');
7081 } // doc.parents()[0].reasons.push(reason)
7082 //do indepenent tags for each term:
7083
7084
7085 doc.list.forEach(function (p) {
7086 var terms = p.terms(); // tagSafe - apply only to fitting terms
7087
7088 if (safe === true) {
7089 terms = terms.filter(function (t) {
7090 return t.canBe(tag, doc.world);
7091 });
7092 }
7093
7094 terms.forEach(function (t, i) {
7095 //fancy version:
7096 if (tagList.length > 1) {
7097 if (tagList[i] && tagList[i] !== '.') {
7098 t.tag(tagList[i], reason, doc.world);
7099 }
7100 } else {
7101 //non-fancy version (same tag for all terms)
7102 t.tag(tag, reason, doc.world);
7103 }
7104 });
7105 });
7106 return;
7107};
7108
7109var _setTag = tagTerms;
7110
7111/** Give all terms the given tag */
7112
7113var tag$1 = function tag(tags, why) {
7114 if (!tags) {
7115 return this;
7116 }
7117
7118 _setTag(tags, this, false, why);
7119 return this;
7120};
7121/** Only apply tag to terms if it is consistent with current tags */
7122
7123
7124var tagSafe$1 = function tagSafe(tags, why) {
7125 if (!tags) {
7126 return this;
7127 }
7128
7129 _setTag(tags, this, true, why);
7130 return this;
7131};
7132/** Remove this term from the given terms */
7133
7134
7135var unTag$1 = function unTag(tags, why) {
7136 var _this = this;
7137
7138 this.list.forEach(function (p) {
7139 p.terms().forEach(function (t) {
7140 return t.unTag(tags, why, _this.world);
7141 });
7142 });
7143 return this;
7144};
7145/** return only the terms that can be this tag*/
7146
7147
7148var canBe$2 = function canBe(tag) {
7149 if (!tag) {
7150 return this;
7151 }
7152
7153 var world = this.world;
7154 var matches = this.list.reduce(function (arr, p) {
7155 return arr.concat(p.canBe(tag, world));
7156 }, []);
7157 return this.buildFrom(matches);
7158};
7159
7160var _04Tag = {
7161 tag: tag$1,
7162 tagSafe: tagSafe$1,
7163 unTag: unTag$1,
7164 canBe: canBe$2
7165};
7166
7167/* run each phrase through a function, and create a new document */
7168var map = function map(fn) {
7169 var _this = this;
7170
7171 if (!fn) {
7172 return this;
7173 }
7174
7175 var list = this.list.map(function (p, i) {
7176 var doc = _this.buildFrom([p]);
7177
7178 doc.from = null; //it's not a child/parent
7179
7180 var res = fn(doc, i); // if its a doc, return one result
7181
7182 if (res && res.list && res.list[0]) {
7183 return res.list[0];
7184 }
7185
7186 return res;
7187 }); //remove nulls
7188
7189 list = list.filter(function (x) {
7190 return x;
7191 }); // return an empty response
7192
7193 if (list.length === 0) {
7194 return this.buildFrom(list);
7195 } // if it is not a list of Phrase objects, then don't try to make a Doc object
7196
7197
7198 if (_typeof(list[0]) !== 'object' || list[0].isA !== 'Phrase') {
7199 return list;
7200 }
7201
7202 return this.buildFrom(list);
7203};
7204/** run a function on each phrase */
7205
7206
7207var forEach = function forEach(fn, detachParent) {
7208 var _this2 = this;
7209
7210 if (!fn) {
7211 return this;
7212 }
7213
7214 this.list.forEach(function (p, i) {
7215 var sub = _this2.buildFrom([p]); // if we're doing fancy insertions, we may want to skip updating the parent each time.
7216
7217
7218 if (detachParent === true) {
7219 sub.from = null; //
7220 }
7221
7222 fn(sub, i);
7223 });
7224 return this;
7225};
7226/** return only the phrases that return true */
7227
7228
7229var filter = function filter(fn) {
7230 var _this3 = this;
7231
7232 if (!fn) {
7233 return this;
7234 }
7235
7236 var list = this.list.filter(function (p, i) {
7237 var doc = _this3.buildFrom([p]);
7238
7239 doc.from = null; //it's not a child/parent
7240
7241 return fn(doc, i);
7242 });
7243 return this.buildFrom(list);
7244};
7245/** return a document with only the first phrase that matches */
7246
7247
7248var find = function find(fn) {
7249 var _this4 = this;
7250
7251 if (!fn) {
7252 return this;
7253 }
7254
7255 var phrase = this.list.find(function (p, i) {
7256 var doc = _this4.buildFrom([p]);
7257
7258 doc.from = null; //it's not a child/parent
7259
7260 return fn(doc, i);
7261 });
7262
7263 if (phrase) {
7264 return this.buildFrom([phrase]);
7265 }
7266
7267 return undefined;
7268};
7269/** return true or false if there is one matching phrase */
7270
7271
7272var some = function some(fn) {
7273 var _this5 = this;
7274
7275 if (!fn) {
7276 return this;
7277 }
7278
7279 return this.list.some(function (p, i) {
7280 var doc = _this5.buildFrom([p]);
7281
7282 doc.from = null; //it's not a child/parent
7283
7284 return fn(doc, i);
7285 });
7286};
7287/** sample a subset of the results */
7288
7289
7290var random = function random(n) {
7291 if (!this.found) {
7292 return this;
7293 }
7294
7295 var r = Math.floor(Math.random() * this.list.length);
7296
7297 if (n === undefined) {
7298 var list = [this.list[r]];
7299 return this.buildFrom(list);
7300 } //prevent it from going over the end
7301
7302
7303 if (r + n > this.length) {
7304 r = this.length - n;
7305 r = r < 0 ? 0 : r;
7306 }
7307
7308 return this.slice(r, r + n);
7309};
7310/** combine each phrase into a new data-structure */
7311// exports.reduce = function(fn, h) {
7312// let list = this.list.reduce((_h, ts) => {
7313// let doc = this.buildFrom([ts])
7314// doc.from = null //it's not a child/parent
7315// return fn(_h, doc)
7316// }, h)
7317// return this.buildFrom(list)
7318// }
7319
7320
7321var _05Loops = {
7322 map: map,
7323 forEach: forEach,
7324 filter: filter,
7325 find: find,
7326 some: some,
7327 random: random
7328};
7329
7330// const tokenize = require('../../01-tokenizer/02-words')
7331var tokenize = function tokenize(str) {
7332 return str.split(/[ -]/g);
7333}; // take a list of strings
7334// look them up in the document
7335
7336
7337var buildTree = function buildTree(termList) {
7338 var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
7339 var root = {}; // parse our input
7340
7341 termList.forEach(function (str, i) {
7342 var val = true;
7343
7344 if (values[i] !== undefined) {
7345 val = values[i];
7346 } // some rough normalization
7347
7348
7349 str = (str || '').toLowerCase();
7350 str = str.replace(/[,;.!?]+$/, '');
7351 var arr = tokenize(str).map(function (s) {
7352 return s.trim();
7353 });
7354 root[arr[0]] = root[arr[0]] || {};
7355
7356 if (arr.length === 1) {
7357 root[arr[0]].value = val;
7358 } else {
7359 root[arr[0]].more = root[arr[0]].more || [];
7360 root[arr[0]].more.push({
7361 rest: arr.slice(1),
7362 value: val
7363 });
7364 }
7365 }); // sort by longest-first?
7366 // console.log(JSON.stringify(root, null, 2))
7367
7368 return root;
7369};
7370
7371var fastLookup = function fastLookup(termList, values, doc) {
7372 var root = buildTree(termList, values);
7373 var found = []; // each phrase
7374
7375 var _loop = function _loop(i) {
7376 var p = doc.list[i];
7377 var terms = p.terms();
7378 var words = terms.map(function (t) {
7379 return t.reduced;
7380 }); // each word
7381
7382 var _loop2 = function _loop2(w) {
7383 if (root[words[w]] !== undefined) {
7384 // is it a multi-word match?
7385 if (root[words[w]].more !== undefined) {
7386 root[words[w]].more.forEach(function (more) {
7387 // is it too-long?
7388 if (words[w + more.rest.length] === undefined) {
7389 return;
7390 } // compare each subsequent term
7391
7392
7393 var everyTerm = more.rest.every(function (word, r) {
7394 return word === words[w + r + 1];
7395 });
7396
7397 if (everyTerm === true) {
7398 found.push({
7399 id: p.terms()[w].id,
7400 value: more.value,
7401 length: more.rest.length + 1
7402 });
7403 }
7404 });
7405 } // is it a single-word match?
7406
7407
7408 if (root[words[w]].value !== undefined) {
7409 found.push({
7410 id: p.terms()[w].id,
7411 value: root[words[w]].value,
7412 length: 1
7413 });
7414 }
7415 }
7416 };
7417
7418 for (var w = 0; w < words.length; w++) {
7419 _loop2(w);
7420 }
7421 };
7422
7423 for (var i = 0; i < doc.list.length; i++) {
7424 _loop(i);
7425 }
7426
7427 return found;
7428};
7429
7430var _lookup = fastLookup;
7431
7432var _06Lookup = createCommonjsModule(function (module, exports) {
7433 // compare one term and one match
7434 // const doesMatch = function(term, str) {
7435 // if (str === '') {
7436 // return false
7437 // }
7438 // return term.reduced === str || term.implicit === str || term.root === str || term.text.toLowerCase() === str
7439 // }
7440 var isObject = function isObject(obj) {
7441 return obj && Object.prototype.toString.call(obj) === '[object Object]';
7442 };
7443 /** lookup an array of words or phrases */
7444
7445
7446 exports.lookup = function (arr) {
7447 var _this = this;
7448
7449 var values = []; //is it a {key:val} object?
7450
7451 var isObj = isObject(arr);
7452
7453 if (isObj === true) {
7454 arr = Object.keys(arr).map(function (k) {
7455 values.push(arr[k]);
7456 return k;
7457 });
7458 } // support .lookup('foo')
7459
7460
7461 if (typeof arr === 'string') {
7462 arr = [arr];
7463 } //make sure we go fast.
7464
7465
7466 if (this._cache.set !== true) {
7467 this.cache();
7468 }
7469
7470 var found = _lookup(arr, values, this);
7471 var p = this.list[0]; // make object response
7472
7473 if (isObj === true) {
7474 var byVal = {};
7475 found.forEach(function (o) {
7476 byVal[o.value] = byVal[o.value] || [];
7477 byVal[o.value].push(p.buildFrom(o.id, o.length));
7478 });
7479 Object.keys(byVal).forEach(function (k) {
7480 byVal[k] = _this.buildFrom(byVal[k]);
7481 });
7482 return byVal;
7483 } // otherwise, make array response:
7484
7485
7486 found = found.map(function (o) {
7487 return p.buildFrom(o.id, o.length);
7488 });
7489 return this.buildFrom(found);
7490 };
7491
7492 exports.lookUp = exports.lookup;
7493});
7494
7495/** freeze the current state of the document, for speed-purposes*/
7496var cache$1 = function cache(options) {
7497 var _this = this;
7498
7499 options = options || {};
7500 var words = {};
7501 var tags = {};
7502 this._cache.words = words;
7503 this._cache.tags = tags;
7504 this._cache.set = true;
7505 this.list.forEach(function (p, i) {
7506 p.cache = p.cache || {}; //p.terms get cached automatically
7507
7508 var terms = p.terms(); // cache all the terms
7509
7510 terms.forEach(function (t) {
7511 if (words[t.reduced] && !words.hasOwnProperty(t.reduced)) {
7512 return; //skip prototype words
7513 }
7514
7515 words[t.reduced] = words[t.reduced] || [];
7516 words[t.reduced].push(i);
7517 Object.keys(t.tags).forEach(function (tag) {
7518 tags[tag] = tags[tag] || [];
7519 tags[tag].push(i);
7520 }); // cache root-form on Term, too
7521
7522 if (options.root) {
7523 t.setRoot(_this.world);
7524 words[t.root] = [i];
7525 }
7526 });
7527 });
7528 return this;
7529};
7530/** un-freezes the current state of the document, so it may be transformed */
7531
7532
7533var uncache = function uncache() {
7534 this._cache = {};
7535 this.list.forEach(function (p) {
7536 p.cache = {};
7537 }); // do parents too?
7538
7539 this.parents().forEach(function (doc) {
7540 doc._cache = {};
7541 doc.list.forEach(function (p) {
7542 p.cache = {};
7543 });
7544 });
7545 return this;
7546};
7547
7548var _07Cache = {
7549 cache: cache$1,
7550 uncache: uncache
7551};
7552
7553var titleCase$3 = function titleCase(str) {
7554 return str.charAt(0).toUpperCase() + str.substr(1);
7555};
7556/** substitute-in new content */
7557
7558
7559var replaceWith = function replaceWith(replace) {
7560 var _this = this;
7561
7562 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7563
7564 if (!replace) {
7565 return this["delete"]();
7566 } //support old-style params
7567
7568
7569 if (options === true) {
7570 options = {
7571 keepTags: true
7572 };
7573 }
7574
7575 if (options === false) {
7576 options = {
7577 keepTags: false
7578 };
7579 }
7580
7581 options = options || {}; // clear the cache
7582
7583 this.uncache(); // return this
7584
7585 this.list.forEach(function (p) {
7586 var input = replace; // accept a function for replace
7587
7588 if (typeof replace === 'function') {
7589 input = replace(p);
7590 }
7591
7592 var newPhrases; // accept a Doc object to replace
7593
7594 if (input && _typeof(input) === 'object' && input.isA === 'Doc') {
7595 newPhrases = input.list;
7596
7597 _this.pool().merge(input.pool());
7598 } else if (typeof input === 'string') {
7599 //input is a string
7600 if (options.keepCase !== false && p.terms(0).isTitleCase()) {
7601 input = titleCase$3(input);
7602 }
7603
7604 newPhrases = _01Tokenizer(input, _this.world, _this.pool()); //tag the new phrases
7605
7606 var tmpDoc = _this.buildFrom(newPhrases);
7607
7608 tmpDoc.tagger();
7609 newPhrases = tmpDoc.list;
7610 } else {
7611 return; //don't even bother
7612 } // try to keep its old tags, if appropriate
7613
7614
7615 if (options.keepTags === true) {
7616 var oldTags = p.json({
7617 terms: {
7618 tags: true
7619 }
7620 }).terms;
7621 newPhrases[0].terms().forEach(function (t, i) {
7622 if (oldTags[i]) {
7623 t.tagSafe(oldTags[i].tags, 'keptTag', _this.world);
7624 }
7625 });
7626 }
7627
7628 p.replace(newPhrases[0], _this); //Oneday: support multi-sentence replacements
7629 });
7630 return this;
7631};
7632/** search and replace match with new content */
7633
7634
7635var replace$1 = function replace(match, _replace, options) {
7636 // if there's no 2nd param, use replaceWith
7637 if (_replace === undefined) {
7638 return this.replaceWith(match, options);
7639 }
7640
7641 this.match(match).replaceWith(_replace, options);
7642 return this;
7643};
7644
7645var _01Replace = {
7646 replaceWith: replaceWith,
7647 replace: replace$1
7648};
7649
7650var _02Insert = createCommonjsModule(function (module, exports) {
7651 var isObject = function isObject(obj) {
7652 return obj && Object.prototype.toString.call(obj) === '[object Object]';
7653 }; // if it's empty, just create the phrase
7654
7655
7656 var makeNew = function makeNew(str, doc) {
7657 var phrase = _01Tokenizer(str, doc.world)[0]; //assume it's one sentence, for now
7658
7659 var tmpDoc = doc.buildFrom([phrase]);
7660 tmpDoc.tagger();
7661 doc.list = tmpDoc.list;
7662 return doc;
7663 };
7664 /** add these new terms to the end*/
7665
7666
7667 exports.append = function () {
7668 var _this = this;
7669
7670 var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
7671
7672 if (!str) {
7673 return this;
7674 } // if it's empty, just create the phrase
7675
7676
7677 if (!this.found) {
7678 return makeNew(str, this);
7679 } // clear the cache
7680
7681
7682 this.uncache(); //add it to end of every phrase
7683
7684 this.list.forEach(function (p) {
7685 //build it
7686 var phrase;
7687
7688 if (isObject(str) && str.isA === 'Doc') {
7689 phrase = str.list[0].clone(); //use the first phrase
7690 } else if (typeof str === 'string') {
7691 phrase = _01Tokenizer(str, _this.world, _this.pool())[0]; //assume it's one sentence, for now
7692 } //tag it
7693
7694
7695 var tmpDoc = _this.buildFrom([phrase]);
7696
7697 tmpDoc.tagger(); // push it onto the end
7698
7699 p.append(phrase, _this);
7700 });
7701 return this;
7702 };
7703
7704 exports.insertAfter = exports.append;
7705 exports.insertAt = exports.append;
7706 /** add these new terms to the front*/
7707
7708 exports.prepend = function (str) {
7709 var _this2 = this;
7710
7711 if (!str) {
7712 return this;
7713 } // if it's empty, just create the phrase
7714
7715
7716 if (!this.found) {
7717 return makeNew(str, this);
7718 } // clear the cache
7719
7720
7721 this.uncache(); //add it to start of every phrase
7722
7723 this.list.forEach(function (p) {
7724 //build it
7725 var phrase;
7726
7727 if (isObject(str) && str.isA === 'Doc') {
7728 phrase = str.list[0].clone(); //use the first phrase
7729 } else if (typeof str === 'string') {
7730 phrase = _01Tokenizer(str, _this2.world, _this2.pool())[0]; //assume it's one sentence, for now
7731 } //tag it
7732
7733
7734 var tmpDoc = _this2.buildFrom([phrase]);
7735
7736 tmpDoc.tagger(); // add it to the start
7737
7738 p.prepend(phrase, _this2);
7739 });
7740 return this;
7741 };
7742
7743 exports.insertBefore = exports.prepend;
7744 /** add these new things to the end*/
7745
7746 exports.concat = function () {
7747 // clear the cache
7748 this.uncache();
7749 var list = this.list.slice(0); //repeat for any number of params
7750
7751 for (var i = 0; i < arguments.length; i++) {
7752 var arg = arguments[i]; //support a fresh string
7753
7754 if (typeof arg === 'string') {
7755 var arr = _01Tokenizer(arg, this.world); //TODO: phrase.tagger()?
7756
7757 list = list.concat(arr);
7758 } else if (arg.isA === 'Doc') {
7759 list = list.concat(arg.list);
7760 } else if (arg.isA === 'Phrase') {
7761 list.push(arg);
7762 }
7763 }
7764
7765 return this.buildFrom(list);
7766 };
7767 /** fully remove these terms from the document */
7768
7769
7770 exports["delete"] = function (match) {
7771 var _this3 = this;
7772
7773 // clear the cache
7774 this.uncache();
7775 var toRemove = this;
7776
7777 if (match) {
7778 toRemove = this.match(match);
7779 }
7780
7781 toRemove.list.forEach(function (phrase) {
7782 return phrase["delete"](_this3);
7783 });
7784 return this;
7785 }; // aliases
7786
7787
7788 exports.remove = exports["delete"];
7789});
7790
7791var shouldTrim = {
7792 clean: true,
7793 reduced: true,
7794 root: true
7795};
7796/** return the document as text */
7797
7798var text$1 = function text(options) {
7799 var _this = this;
7800
7801 options = options || {}; //are we showing every phrase?
7802
7803 var showFull = false;
7804
7805 if (this.parents().length === 0) {
7806 showFull = true;
7807 } // cache roots, if necessary
7808
7809
7810 if (options === 'root' || _typeof(options) === 'object' && options.root) {
7811 this.list.forEach(function (p) {
7812 p.terms().forEach(function (t) {
7813 if (t.root === null) {
7814 t.setRoot(_this.world);
7815 }
7816 });
7817 });
7818 }
7819
7820 var txt = this.list.reduce(function (str, p, i) {
7821 var trimPre = !showFull && i === 0;
7822 var trimPost = !showFull && i === _this.list.length - 1;
7823 return str + p.text(options, trimPre, trimPost);
7824 }, ''); // clumsy final trim of leading/trailing whitespace
7825
7826 if (shouldTrim[options] === true || options.reduced === true || options.clean === true || options.root === true) {
7827 txt = txt.trim();
7828 }
7829
7830 return txt;
7831};
7832
7833var _01Text = {
7834 text: text$1
7835};
7836
7837// get all character startings in doc
7838var termOffsets = function termOffsets(doc) {
7839 var elapsed = 0;
7840 var index = 0;
7841 var offsets = {};
7842 doc.termList().forEach(function (term) {
7843 offsets[term.id] = {
7844 index: index,
7845 start: elapsed + term.pre.length,
7846 length: term.text.length
7847 };
7848 elapsed += term.pre.length + term.text.length + term.post.length;
7849 index += 1;
7850 });
7851 return offsets;
7852};
7853
7854var calcOffset = function calcOffset(doc, result, options) {
7855 // calculate offsets for each term
7856 var offsets = termOffsets(doc.all()); // add index values
7857
7858 if (options.terms.index || options.index) {
7859 result.forEach(function (o) {
7860 o.terms.forEach(function (t) {
7861 t.index = offsets[t.id].index;
7862 });
7863 o.index = o.terms[0].index;
7864 });
7865 } // add offset values
7866
7867
7868 if (options.terms.offset || options.offset) {
7869 result.forEach(function (o) {
7870 o.terms.forEach(function (t) {
7871 t.offset = offsets[t.id] || {};
7872 }); // let len = o.terms.reduce((n, t, i) => {
7873 // n += t.offset.length || 0
7874 // //add whitespace, too
7875 // console.log(t.post)
7876 // return n
7877 // }, 0)
7878 // The offset information for the entire doc starts at (or just before)
7879 // the first term, and is as long as the whole text. The code originally
7880 // copied the entire offset value from terms[0], but since we're now
7881 // overriding 2 of the three fields, it's cleaner to just create an all-
7882 // new object and not pretend it's "just" the same as terms[0].
7883
7884 o.offset = {
7885 index: o.terms[0].offset.index,
7886 start: o.terms[0].offset.start - o.text.indexOf(o.terms[0].text),
7887 length: o.text.length
7888 };
7889 });
7890 }
7891};
7892
7893var _offset = calcOffset;
7894
7895var _02Json = createCommonjsModule(function (module, exports) {
7896 var jsonDefaults = {
7897 text: true,
7898 terms: true,
7899 trim: true
7900 }; //some options have dependents
7901
7902 var setOptions = function setOptions(options) {
7903 options = Object.assign({}, jsonDefaults, options);
7904
7905 if (options.unique) {
7906 options.reduced = true;
7907 } //offset calculation requires these options to be on
7908
7909
7910 if (options.offset) {
7911 options.text = true;
7912
7913 if (!options.terms || options.terms === true) {
7914 options.terms = {};
7915 }
7916
7917 options.terms.offset = true;
7918 }
7919
7920 if (options.index || options.terms.index) {
7921 options.terms = options.terms === true ? {} : options.terms;
7922 options.terms.id = true;
7923 }
7924
7925 return options;
7926 };
7927 /** pull out desired metadata from the document */
7928
7929
7930 exports.json = function () {
7931 var _this = this;
7932
7933 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
7934
7935 //support json(3) format
7936 if (typeof options === 'number' && this.list[options]) {
7937 return this.list[options].json(jsonDefaults);
7938 }
7939
7940 options = setOptions(options); // cache root strings beforehand, if necessary
7941
7942 if (options.root === true) {
7943 this.list.forEach(function (p) {
7944 p.terms().forEach(function (t) {
7945 if (t.root === null) {
7946 t.setRoot(_this.world);
7947 }
7948 });
7949 });
7950 }
7951
7952 var result = this.list.map(function (p) {
7953 return p.json(options, _this.world);
7954 }); // add offset and index data for each term
7955
7956 if (options.terms.offset || options.offset || options.terms.index || options.index) {
7957 _offset(this, result, options);
7958 } // add frequency #s
7959
7960
7961 if (options.frequency || options.freq || options.count) {
7962 var obj = {};
7963 this.list.forEach(function (p) {
7964 var str = p.text('reduced');
7965 obj[str] = obj[str] || 0;
7966 obj[str] += 1;
7967 });
7968 this.list.forEach(function (p, i) {
7969 result[i].count = obj[p.text('reduced')];
7970 });
7971 } // remove duplicates
7972
7973
7974 if (options.unique) {
7975 var already = {};
7976 result = result.filter(function (o) {
7977 if (already[o.reduced] === true) {
7978 return false;
7979 }
7980
7981 already[o.reduced] = true;
7982 return true;
7983 });
7984 }
7985
7986 return result;
7987 }; //aliases
7988
7989
7990 exports.data = exports.json;
7991});
7992
7993var _debug = createCommonjsModule(function (module) {
7994 // https://stackoverflow.com/questions/9781218/how-to-change-node-jss-console-font-color
7995 var reset = '\x1b[0m';
7996
7997 var padEnd = function padEnd(str, width) {
7998 str = str.toString();
7999
8000 while (str.length < width) {
8001 str += ' ';
8002 }
8003
8004 return str;
8005 };
8006
8007 function isClientSide() {
8008 return typeof window !== 'undefined' && window.document;
8009 } // some nice colors for client-side debug
8010
8011
8012 var css = {
8013 green: '#7f9c6c',
8014 red: '#914045',
8015 blue: '#6699cc',
8016 magenta: '#6D5685',
8017 cyan: '#2D85A8',
8018 yellow: '#e6d7b3',
8019 black: '#303b50'
8020 };
8021
8022 var logClientSide = function logClientSide(doc) {
8023 var tagset = doc.world.tags;
8024 doc.list.forEach(function (p) {
8025 console.log('\n%c"' + p.text() + '"', 'color: #e6d7b3;');
8026 var terms = p.terms();
8027 terms.forEach(function (t) {
8028 var tags = Object.keys(t.tags);
8029 var text = t.text || '-';
8030
8031 if (t.implicit) {
8032 text = '[' + t.implicit + ']';
8033 }
8034
8035 var word = "'" + text + "'";
8036 word = padEnd(word, 8);
8037 var found = tags.find(function (tag) {
8038 return tagset[tag] && tagset[tag].color;
8039 });
8040 var color = 'steelblue';
8041
8042 if (tagset[found]) {
8043 color = tagset[found].color;
8044 color = css[color];
8045 }
8046
8047 console.log(" ".concat(word, " - %c").concat(tags.join(', ')), "color: ".concat(color || 'steelblue', ";"));
8048 });
8049 });
8050 }; //cheaper than requiring chalk
8051
8052
8053 var cli = {
8054 green: function green(str) {
8055 return '\x1b[32m' + str + reset;
8056 },
8057 red: function red(str) {
8058 return '\x1b[31m' + str + reset;
8059 },
8060 blue: function blue(str) {
8061 return '\x1b[34m' + str + reset;
8062 },
8063 magenta: function magenta(str) {
8064 return '\x1b[35m' + str + reset;
8065 },
8066 cyan: function cyan(str) {
8067 return '\x1b[36m' + str + reset;
8068 },
8069 yellow: function yellow(str) {
8070 return '\x1b[33m' + str + reset;
8071 },
8072 black: function black(str) {
8073 return '\x1b[30m' + str + reset;
8074 }
8075 };
8076
8077 var tagString = function tagString(tags, world) {
8078 tags = tags.map(function (tag) {
8079 if (!world.tags.hasOwnProperty(tag)) {
8080 return tag;
8081 }
8082
8083 var c = world.tags[tag].color || 'blue';
8084 return cli[c](tag);
8085 });
8086 return tags.join(', ');
8087 }; //output some helpful stuff to the console
8088
8089
8090 var debug = function debug(doc) {
8091 if (isClientSide()) {
8092 logClientSide(doc);
8093 return doc;
8094 }
8095
8096 console.log(cli.blue('====='));
8097 doc.list.forEach(function (p) {
8098 console.log(cli.blue(' -----'));
8099 var terms = p.terms();
8100 terms.forEach(function (t) {
8101 var tags = Object.keys(t.tags);
8102 var text = t.text || '-';
8103
8104 if (t.implicit) {
8105 text = '[' + t.implicit + ']';
8106 }
8107
8108 {
8109 text = cli.yellow(text);
8110 }
8111
8112 var word = "'" + text + "'";
8113 word = padEnd(word, 18);
8114 var str = cli.blue(' | ') + word + ' - ' + tagString(tags, doc.world);
8115 console.log(str);
8116 });
8117 });
8118 console.log('');
8119 return doc;
8120 };
8121
8122 module.exports = debug;
8123});
8124
8125var topk = function topk(doc) {
8126 var list = doc.json({
8127 text: false,
8128 terms: false,
8129 reduced: true
8130 }); // combine them
8131
8132 var obj = {};
8133 list.forEach(function (o) {
8134 if (!obj[o.reduced]) {
8135 o.count = 0;
8136 obj[o.reduced] = o;
8137 }
8138
8139 obj[o.reduced].count += 1;
8140 });
8141 var arr = Object.keys(obj).map(function (k) {
8142 return obj[k];
8143 }); // sort them
8144
8145 arr.sort(function (a, b) {
8146 if (a.count > b.count) {
8147 return -1;
8148 } else if (a.count < b.count) {
8149 return 1;
8150 }
8151
8152 return 0;
8153 });
8154 return arr;
8155};
8156
8157var _topk = topk;
8158
8159/** pretty-print the current document and its tags */
8160
8161var debug_1 = function debug_1() {
8162 _debug(this);
8163 return this;
8164};
8165/** some named output formats */
8166
8167
8168var out = function out(method) {
8169 if (method === 'text') {
8170 return this.text();
8171 }
8172
8173 if (method === 'normal') {
8174 return this.text('normal');
8175 }
8176
8177 if (method === 'json') {
8178 return this.json();
8179 }
8180
8181 if (method === 'offset' || method === 'offsets') {
8182 return this.json({
8183 offset: true
8184 });
8185 }
8186
8187 if (method === 'array') {
8188 return this.json({
8189 terms: false
8190 }).map(function (obj) {
8191 return obj.text;
8192 }).filter(function (str) {
8193 return str;
8194 });
8195 }
8196
8197 if (method === 'freq' || method === 'frequency') {
8198 return _topk(this);
8199 }
8200
8201 if (method === 'terms') {
8202 var list = [];
8203 this.json({
8204 text: false,
8205 terms: {
8206 text: true
8207 }
8208 }).forEach(function (obj) {
8209 var terms = obj.terms.map(function (t) {
8210 return t.text;
8211 });
8212 terms = terms.filter(function (t) {
8213 return t;
8214 });
8215 list = list.concat(terms);
8216 });
8217 return list;
8218 }
8219
8220 if (method === 'tags') {
8221 return this.list.map(function (p) {
8222 return p.terms().reduce(function (h, t) {
8223 h[t.clean || t.implicit] = Object.keys(t.tags);
8224 return h;
8225 }, {});
8226 });
8227 }
8228
8229 if (method === 'debug') {
8230 _debug(this);
8231 return this;
8232 }
8233
8234 return this.text();
8235};
8236
8237var _03Out = {
8238 debug: debug_1,
8239 out: out
8240};
8241
8242var methods$2 = {
8243 /** alphabetical order */
8244 alpha: function alpha(a, b) {
8245 var left = a.text('clean');
8246 var right = b.text('clean');
8247
8248 if (left < right) {
8249 return -1;
8250 }
8251
8252 if (left > right) {
8253 return 1;
8254 }
8255
8256 return 0;
8257 },
8258
8259 /** count the # of characters of each match */
8260 length: function length(a, b) {
8261 var left = a.text().trim().length;
8262 var right = b.text().trim().length;
8263
8264 if (left < right) {
8265 return 1;
8266 }
8267
8268 if (left > right) {
8269 return -1;
8270 }
8271
8272 return 0;
8273 },
8274
8275 /** count the # of terms in each match */
8276 wordCount: function wordCount(a, b) {
8277 var left = a.wordCount();
8278 var right = b.wordCount();
8279
8280 if (left < right) {
8281 return 1;
8282 }
8283
8284 if (left > right) {
8285 return -1;
8286 }
8287
8288 return 0;
8289 }
8290};
8291/** sort by # of duplicates in the document*/
8292
8293var byFreq = function byFreq(doc) {
8294 var counts = {};
8295 var options = {
8296 "case": true,
8297 punctuation: false,
8298 whitespace: true,
8299 unicode: true
8300 };
8301 doc.list.forEach(function (p) {
8302 var str = p.text(options);
8303 counts[str] = counts[str] || 0;
8304 counts[str] += 1;
8305 }); // sort by freq
8306
8307 doc.list.sort(function (a, b) {
8308 var left = counts[a.text(options)];
8309 var right = counts[b.text(options)];
8310
8311 if (left < right) {
8312 return 1;
8313 }
8314
8315 if (left > right) {
8316 return -1;
8317 }
8318
8319 return 0;
8320 });
8321 return doc;
8322}; // order results 'chronologically', or document-order
8323
8324
8325var sortSequential = function sortSequential(doc) {
8326 var order = {};
8327 doc.json({
8328 terms: {
8329 offset: true
8330 }
8331 }).forEach(function (o) {
8332 order[o.terms[0].id] = o.terms[0].offset.start;
8333 });
8334 doc.list = doc.list.sort(function (a, b) {
8335 if (order[a.start] > order[b.start]) {
8336 return 1;
8337 } else if (order[a.start] < order[b.start]) {
8338 return -1;
8339 }
8340
8341 return 0;
8342 });
8343 return doc;
8344}; //aliases
8345
8346
8347methods$2.alphabetical = methods$2.alpha;
8348methods$2.wordcount = methods$2.wordCount; // aliases for sequential ordering
8349
8350var seqNames = {
8351 index: true,
8352 sequence: true,
8353 seq: true,
8354 sequential: true,
8355 chron: true,
8356 chronological: true
8357};
8358/** re-arrange the order of the matches (in place) */
8359
8360var sort = function sort(input) {
8361 input = input || 'alpha'; //do this one up-front
8362
8363 if (input === 'freq' || input === 'frequency' || input === 'topk') {
8364 return byFreq(this);
8365 }
8366
8367 if (seqNames.hasOwnProperty(input)) {
8368 return sortSequential(this);
8369 }
8370
8371 input = methods$2[input] || input; // apply sort method on each phrase
8372
8373 if (typeof input === 'function') {
8374 this.list = this.list.sort(input);
8375 return this;
8376 }
8377
8378 return this;
8379};
8380/** reverse the order of the matches, but not the words */
8381
8382
8383var reverse = function reverse() {
8384 var list = [].concat(this.list);
8385 list = list.reverse();
8386 return this.buildFrom(list);
8387};
8388/** remove any duplicate matches */
8389
8390
8391var unique$4 = function unique() {
8392 var list = [].concat(this.list);
8393 var obj = {};
8394 list = list.filter(function (p) {
8395 var str = p.text('reduced').trim();
8396
8397 if (obj.hasOwnProperty(str) === true) {
8398 return false;
8399 }
8400
8401 obj[str] = true;
8402 return true;
8403 });
8404 return this.buildFrom(list);
8405};
8406
8407var _01Sort = {
8408 sort: sort,
8409 reverse: reverse,
8410 unique: unique$4
8411};
8412
8413var isPunct = /[\[\]{}⟨⟩:,،、‒–—―…‹›«»‐\-;\/⁄·*\•^†‡°¡¿※№÷׺ª%‰=‱¶§~|‖¦©℗®℠™¤₳฿]/g;
8414var quotes = /['‘’“”"′″‴]+/g;
8415var methods$3 = {
8416 // cleanup newlines and extra spaces
8417 whitespace: function whitespace(doc) {
8418 var termArr = doc.list.map(function (ts) {
8419 return ts.terms();
8420 });
8421 termArr.forEach(function (terms, o) {
8422 terms.forEach(function (t, i) {
8423 // keep dashes between words
8424 if (t.hasDash() === true) {
8425 t.post = ' - ';
8426 return;
8427 } // remove existing spaces
8428
8429
8430 t.pre = t.pre.replace(/\s/g, '');
8431 t.post = t.post.replace(/\s/g, ''); //last word? ensure there's a next sentence.
8432
8433 if (terms.length - 1 === i && !termArr[o + 1]) {
8434 return;
8435 } // no extra spaces for contractions
8436
8437
8438 if (t.implicit && Boolean(t.text) === true) {
8439 return;
8440 } // no extra spaces for hyphenated words
8441
8442
8443 if (t.hasHyphen() === true) {
8444 return;
8445 }
8446
8447 t.post += ' ';
8448 });
8449 });
8450 },
8451 punctuation: function punctuation(termList) {
8452 termList.forEach(function (t) {
8453 // space between hyphenated words
8454 if (t.hasHyphen() === true) {
8455 t.post = ' ';
8456 }
8457
8458 t.pre = t.pre.replace(isPunct, '');
8459 t.post = t.post.replace(isPunct, ''); // elipses
8460
8461 t.post = t.post.replace(/\.\.\./, ''); // only allow one exclamation
8462
8463 if (/!/.test(t.post) === true) {
8464 t.post = t.post.replace(/!/g, '');
8465 t.post = '!' + t.post;
8466 } // only allow one question mark
8467
8468
8469 if (/\?/.test(t.post) === true) {
8470 t.post = t.post.replace(/[\?!]*/, '');
8471 t.post = '?' + t.post;
8472 }
8473 });
8474 },
8475 unicode: function unicode(termList) {
8476 termList.forEach(function (t) {
8477 if (t.isImplicit() === true) {
8478 return;
8479 }
8480
8481 t.text = unicode_1(t.text);
8482 });
8483 },
8484 quotations: function quotations(termList) {
8485 termList.forEach(function (t) {
8486 t.post = t.post.replace(quotes, '');
8487 t.pre = t.pre.replace(quotes, '');
8488 });
8489 },
8490 adverbs: function adverbs(doc) {
8491 doc.match('#Adverb').not('(not|nary|seldom|never|barely|almost|basically|so)').remove();
8492 },
8493 // remove the '.' from 'Mrs.' (safely)
8494 abbreviations: function abbreviations(doc) {
8495 doc.list.forEach(function (ts) {
8496 var terms = ts.terms();
8497 terms.forEach(function (t, i) {
8498 if (t.tags.Abbreviation === true && terms[i + 1]) {
8499 t.post = t.post.replace(/^\./, '');
8500 }
8501 });
8502 });
8503 }
8504};
8505var _methods = methods$3;
8506
8507var defaults = {
8508 // light
8509 whitespace: true,
8510 unicode: true,
8511 punctuation: true,
8512 emoji: true,
8513 acronyms: true,
8514 abbreviations: true,
8515 // medium
8516 "case": false,
8517 contractions: false,
8518 parentheses: false,
8519 quotations: false,
8520 adverbs: false,
8521 // heavy (loose legibility)
8522 possessives: false,
8523 verbs: false,
8524 nouns: false,
8525 honorifics: false // pronouns: true,
8526
8527};
8528var mapping$1 = {
8529 light: {},
8530 medium: {
8531 "case": true,
8532 contractions: true,
8533 parentheses: true,
8534 quotations: true,
8535 adverbs: true
8536 }
8537};
8538mapping$1.heavy = Object.assign({}, mapping$1.medium, {
8539 possessives: true,
8540 verbs: true,
8541 nouns: true,
8542 honorifics: true
8543});
8544/** common ways to clean-up the document, and reduce noise */
8545
8546var normalize = function normalize(options) {
8547 options = options || {}; // support named forms
8548
8549 if (typeof options === 'string') {
8550 options = mapping$1[options] || {};
8551 } // set defaults
8552
8553
8554 options = Object.assign({}, defaults, options); // clear the cache
8555
8556 this.uncache();
8557 var termList = this.termList(); // lowercase things
8558
8559 if (options["case"]) {
8560 this.toLowerCase();
8561 } //whitespace
8562
8563
8564 if (options.whitespace) {
8565 _methods.whitespace(this);
8566 } // unicode: é -> e
8567
8568
8569 if (options.unicode) {
8570 _methods.unicode(termList);
8571 } //punctuation - keep sentence punctation, quotes, parenths
8572
8573
8574 if (options.punctuation) {
8575 _methods.punctuation(termList);
8576 } // remove ':)'
8577
8578
8579 if (options.emoji) {
8580 this.remove('(#Emoji|#Emoticon)');
8581 } // 'f.b.i.' -> 'FBI'
8582
8583
8584 if (options.acronyms) {
8585 this.acronyms().strip(); // .toUpperCase()
8586 } // remove period from abbreviations
8587
8588
8589 if (options.abbreviations) {
8590 _methods.abbreviations(this);
8591 } // --Medium methods--
8592 // `isn't` -> 'is not'
8593
8594
8595 if (options.contraction || options.contractions) {
8596 this.contractions().expand();
8597 } // '(word)' -> 'word'
8598
8599
8600 if (options.parentheses) {
8601 this.parentheses().unwrap();
8602 } // remove "" punctuation
8603
8604
8605 if (options.quotations || options.quotes) {
8606 _methods.quotations(termList);
8607 } // remove any un-necessary adverbs
8608
8609
8610 if (options.adverbs) {
8611 _methods.adverbs(this);
8612 } // --Heavy methods--
8613 // `cory hart's -> cory hart'
8614
8615
8616 if (options.possessive || options.possessives) {
8617 this.possessives().strip();
8618 } // 'he walked' -> 'he walk'
8619
8620
8621 if (options.verbs) {
8622 this.verbs().toInfinitive();
8623 } // 'three dogs' -> 'three dog'
8624
8625
8626 if (options.nouns || options.plurals) {
8627 this.nouns().toSingular();
8628 } // remove 'Mr.' from 'Mr John Smith'
8629
8630
8631 if (options.honorifics) {
8632 this.remove('#Honorific');
8633 }
8634
8635 return this;
8636};
8637
8638var _02Normalize = {
8639 normalize: normalize
8640};
8641
8642var _03Split = createCommonjsModule(function (module, exports) {
8643 /** return a Document with three parts for every match
8644 * seperate everything before the word, as a new phrase
8645 */
8646 exports.splitOn = function (reg) {
8647 // if there's no match, split parent, instead
8648 if (!reg) {
8649 var parent = this.parent();
8650 return parent.splitOn(this);
8651 } //start looking for a match..
8652
8653
8654 var regs = matchSyntax(reg);
8655 var matches = [];
8656 this.list.forEach(function (p) {
8657 var foundEm = p.match(regs); //no match here, add full sentence
8658
8659 if (foundEm.length === 0) {
8660 matches.push(p);
8661 return;
8662 } // we found something here.
8663
8664
8665 var carry = p;
8666 foundEm.forEach(function (found) {
8667 var parts = carry.splitOn(found); // add em in
8668
8669 if (parts.before) {
8670 matches.push(parts.before);
8671 }
8672
8673 if (parts.match) {
8674 matches.push(parts.match);
8675 } // start matching now on the end
8676
8677
8678 carry = parts.after;
8679 }); // add that last part
8680
8681 if (carry) {
8682 matches.push(carry);
8683 }
8684 });
8685 return this.buildFrom(matches);
8686 };
8687 /** return a Document with two parts for every match
8688 * seperate everything after the word, as a new phrase
8689 */
8690
8691
8692 exports.splitAfter = function (reg) {
8693 // if there's no match, split parent, instead
8694 if (!reg) {
8695 var parent = this.parent();
8696 return parent.splitAfter(this);
8697 } // start looking for our matches
8698
8699
8700 var regs = matchSyntax(reg);
8701 var matches = [];
8702 this.list.forEach(function (p) {
8703 var foundEm = p.match(regs); //no match here, add full sentence
8704
8705 if (foundEm.length === 0) {
8706 matches.push(p);
8707 return;
8708 } // we found something here.
8709
8710
8711 var carry = p;
8712 foundEm.forEach(function (found) {
8713 var parts = carry.splitOn(found); // add em in
8714
8715 if (parts.before && parts.match) {
8716 // merge these two together
8717 parts.before.length += parts.match.length;
8718 matches.push(parts.before);
8719 } else if (parts.match) {
8720 matches.push(parts.match);
8721 } // start matching now on the end
8722
8723
8724 carry = parts.after;
8725 }); // add that last part
8726
8727 if (carry) {
8728 matches.push(carry);
8729 }
8730 });
8731 return this.buildFrom(matches);
8732 };
8733
8734 exports.split = exports.splitAfter; //i guess?
8735
8736 /** return a Document with two parts for every match */
8737
8738 exports.splitBefore = function (reg) {
8739 // if there's no match, split parent, instead
8740 if (!reg) {
8741 var parent = this.parent();
8742 return parent.splitBefore(this);
8743 } //start looking for a match..
8744
8745
8746 var regs = matchSyntax(reg);
8747 var matches = [];
8748 this.list.forEach(function (p) {
8749 var foundEm = p.match(regs); //no match here, add full sentence
8750
8751 if (foundEm.length === 0) {
8752 matches.push(p);
8753 return;
8754 } // we found something here.
8755
8756
8757 var carry = p;
8758 foundEm.forEach(function (found) {
8759 var parts = carry.splitOn(found); // add before part in
8760
8761 if (parts.before) {
8762 matches.push(parts.before);
8763 } // merge match+after
8764
8765
8766 if (parts.match && parts.after) {
8767 parts.match.length += parts.after.length;
8768 } // start matching now on the end
8769
8770
8771 carry = parts.match;
8772 }); // add that last part
8773
8774 if (carry) {
8775 matches.push(carry);
8776 }
8777 });
8778 return this.buildFrom(matches);
8779 };
8780 /** split a document into labeled sections */
8781
8782
8783 exports.segment = function (regs, options) {
8784 regs = regs || {};
8785 options = options || {
8786 text: true
8787 };
8788 var doc = this;
8789 var keys = Object.keys(regs); // split em
8790
8791 keys.forEach(function (k) {
8792 doc = doc.splitOn(k);
8793 }); //add labels for each section
8794
8795 doc.list.forEach(function (p) {
8796 for (var i = 0; i < keys.length; i += 1) {
8797 if (p.has(keys[i])) {
8798 p.segment = regs[keys[i]];
8799 return;
8800 }
8801 }
8802 });
8803 return doc.list.map(function (p) {
8804 var res = p.json(options);
8805 res.segment = p.segment || null;
8806 return res;
8807 });
8808 };
8809});
8810
8811var eachTerm = function eachTerm(doc, fn) {
8812 var world = doc.world;
8813 doc.list.forEach(function (p) {
8814 p.terms().forEach(function (t) {
8815 return t[fn](world);
8816 });
8817 });
8818 return doc;
8819};
8820/** turn every letter of every term to lower-cse */
8821
8822
8823var toLowerCase = function toLowerCase() {
8824 return eachTerm(this, 'toLowerCase');
8825};
8826/** turn every letter of every term to upper case */
8827
8828
8829var toUpperCase = function toUpperCase() {
8830 return eachTerm(this, 'toUpperCase');
8831};
8832/** upper-case the first letter of each term */
8833
8834
8835var toTitleCase = function toTitleCase() {
8836 return eachTerm(this, 'toTitleCase');
8837};
8838/** remove whitespace and title-case each term */
8839
8840
8841var toCamelCase = function toCamelCase() {
8842 this.list.forEach(function (p) {
8843 //remove whitespace
8844 var terms = p.terms();
8845 terms.forEach(function (t, i) {
8846 if (i !== 0) {
8847 t.toTitleCase();
8848 }
8849
8850 if (i !== terms.length - 1) {
8851 t.post = '';
8852 }
8853 });
8854 }); // this.tag('#CamelCase', 'toCamelCase')
8855
8856 return this;
8857};
8858
8859var _04Case = {
8860 toLowerCase: toLowerCase,
8861 toUpperCase: toUpperCase,
8862 toTitleCase: toTitleCase,
8863 toCamelCase: toCamelCase
8864};
8865
8866/** add this punctuation or whitespace before each match: */
8867
8868var _05Whitespace = createCommonjsModule(function (module, exports) {
8869 exports.pre = function (str, concat) {
8870 if (str === undefined) {
8871 return this.list[0].terms(0).pre;
8872 }
8873
8874 this.list.forEach(function (p) {
8875 var term = p.terms(0);
8876
8877 if (concat === true) {
8878 term.pre += str;
8879 } else {
8880 term.pre = str;
8881 }
8882 });
8883 return this;
8884 };
8885 /** add this punctuation or whitespace after each match: */
8886
8887
8888 exports.post = function (str, concat) {
8889 // return array of post strings
8890 if (str === undefined) {
8891 return this.list.map(function (p) {
8892 var terms = p.terms();
8893 var term = terms[terms.length - 1];
8894 return term.post;
8895 });
8896 } // set post string on all ends
8897
8898
8899 this.list.forEach(function (p) {
8900 var terms = p.terms();
8901 var term = terms[terms.length - 1];
8902
8903 if (concat === true) {
8904 term.post += str;
8905 } else {
8906 term.post = str;
8907 }
8908 });
8909 return this;
8910 };
8911 /** remove start and end whitespace */
8912
8913
8914 exports.trim = function () {
8915 this.list = this.list.map(function (p) {
8916 return p.trim();
8917 });
8918 return this;
8919 };
8920 /** connect words with hyphen, and remove whitespace */
8921
8922
8923 exports.hyphenate = function () {
8924 this.list.forEach(function (p) {
8925 var terms = p.terms(); //remove whitespace
8926
8927 terms.forEach(function (t, i) {
8928 if (i !== 0) {
8929 t.pre = '';
8930 }
8931
8932 if (terms[i + 1]) {
8933 t.post = '-';
8934 }
8935 });
8936 });
8937 return this;
8938 };
8939 /** remove hyphens between words, and set whitespace */
8940
8941
8942 exports.dehyphenate = function () {
8943 var hasHyphen = /(-|–|—)/;
8944 this.list.forEach(function (p) {
8945 var terms = p.terms(); //remove whitespace
8946
8947 terms.forEach(function (t) {
8948 if (hasHyphen.test(t.post)) {
8949 t.post = ' ';
8950 }
8951 });
8952 });
8953 return this;
8954 };
8955
8956 exports.deHyphenate = exports.dehyphenate;
8957 /** add quotations around these matches */
8958
8959 exports.toQuotations = function (start, end) {
8960 start = start || "\"";
8961 end = end || "\"";
8962 this.list.forEach(function (p) {
8963 var terms = p.terms();
8964 terms[0].pre = start + terms[0].pre;
8965 var last = terms[terms.length - 1];
8966 last.post = end + last.post;
8967 });
8968 return this;
8969 };
8970
8971 exports.toQuotation = exports.toQuotations;
8972 /** add brackets around these matches */
8973
8974 exports.toParentheses = function (start, end) {
8975 start = start || "(";
8976 end = end || ")";
8977 this.list.forEach(function (p) {
8978 var terms = p.terms();
8979 terms[0].pre = start + terms[0].pre;
8980 var last = terms[terms.length - 1];
8981 last.post = end + last.post;
8982 });
8983 return this;
8984 };
8985});
8986
8987/** make all phrases into one phrase */
8988var join = function join(str) {
8989 // clear the cache
8990 this.uncache(); // make one large phrase - 'main'
8991
8992 var main = this.list[0];
8993 var before = main.length;
8994 var removed = {};
8995
8996 for (var i = 1; i < this.list.length; i++) {
8997 var p = this.list[i];
8998 removed[p.start] = true;
8999 var term = main.lastTerm(); // add whitespace between them
9000
9001 if (str) {
9002 term.post += str;
9003 } // main -> p
9004
9005
9006 term.next = p.start; // main <- p
9007
9008 p.terms(0).prev = term.id;
9009 main.length += p.length;
9010 main.cache = {};
9011 } // parents are bigger than than their children.
9012 // when we increase a child, we increase their parent too.
9013
9014
9015 var increase = main.length - before;
9016 this.parents().forEach(function (doc) {
9017 // increase length on each effected phrase
9018 doc.list.forEach(function (p) {
9019 var terms = p.terms();
9020
9021 for (var _i = 0; _i < terms.length; _i++) {
9022 if (terms[_i].id === main.start) {
9023 p.length += increase;
9024 break;
9025 }
9026 }
9027
9028 p.cache = {};
9029 }); // remove redundant phrases now
9030
9031 doc.list = doc.list.filter(function (p) {
9032 return removed[p.start] !== true;
9033 });
9034 }); // return one major phrase
9035
9036 return this.buildFrom([main]);
9037};
9038
9039var _06Join = {
9040 join: join
9041};
9042
9043var postPunct = /[,\)"';:\-–—\.…]/; // const irregulars = {
9044// 'will not': `won't`,
9045// 'i am': `i'm`,
9046// }
9047
9048var setContraction = function setContraction(m, suffix) {
9049 if (!m.found) {
9050 return;
9051 }
9052
9053 var terms = m.termList(); //avoid any problematic punctuation
9054
9055 for (var i = 0; i < terms.length - 1; i++) {
9056 var t = terms[i];
9057
9058 if (postPunct.test(t.post)) {
9059 return;
9060 }
9061 } // set them as implict
9062
9063
9064 terms.forEach(function (t) {
9065 t.implicit = t.clean;
9066 }); // perform the contraction
9067
9068 terms[0].text += suffix; // clean-up the others
9069
9070 terms.slice(1).forEach(function (t) {
9071 t.text = '';
9072 });
9073
9074 for (var _i = 0; _i < terms.length - 1; _i++) {
9075 var _t = terms[_i];
9076 _t.post = _t.post.replace(/ /, '');
9077 }
9078};
9079/** turn 'i am' into i'm */
9080
9081
9082var contract = function contract() {
9083 var doc = this.not('@hasContraction'); // we are -> we're
9084
9085 var m = doc.match('(we|they|you) are');
9086 setContraction(m, "'re"); // they will -> they'll
9087
9088 m = doc.match('(he|she|they|it|we|you) will');
9089 setContraction(m, "'ll"); // she is -> she's
9090
9091 m = doc.match('(he|she|they|it|we) is');
9092 setContraction(m, "'s"); // spencer is -> spencer's
9093
9094 m = doc.match('#Person is');
9095 setContraction(m, "'s"); // spencer would -> spencer'd
9096
9097 m = doc.match('#Person would');
9098 setContraction(m, "'d"); // would not -> wouldn't
9099
9100 m = doc.match('(is|was|had|would|should|could|do|does|have|has|can) not');
9101 setContraction(m, "n't"); // i have -> i've
9102
9103 m = doc.match('(i|we|they) have');
9104 setContraction(m, "'ve"); // would have -> would've
9105
9106 m = doc.match('(would|should|could) have');
9107 setContraction(m, "'ve"); // i am -> i'm
9108
9109 m = doc.match('i am');
9110 setContraction(m, "'m"); // going to -> gonna
9111
9112 m = doc.match('going to');
9113 return this;
9114};
9115
9116var _07Contract = {
9117 contract: contract
9118};
9119
9120var methods$4 = Object.assign({}, _01Utils$1, _02Accessors, _03Match, _04Tag, _05Loops, _06Lookup, _07Cache, _01Replace, _02Insert, _01Text, _02Json, _03Out, _01Sort, _02Normalize, _03Split, _04Case, _05Whitespace, _06Join, _07Contract);
9121
9122var methods$5 = {}; // allow helper methods like .adjectives() and .adverbs()
9123
9124var arr = [['terms', '.'], ['hyphenated', '@hasHyphen .'], ['adjectives', '#Adjective'], ['hashTags', '#HashTag'], ['emails', '#Email'], ['emoji', '#Emoji'], ['emoticons', '#Emoticon'], ['atMentions', '#AtMention'], ['urls', '#Url'], ['adverbs', '#Adverb'], ['pronouns', '#Pronoun'], ['conjunctions', '#Conjunction'], ['prepositions', '#Preposition']];
9125arr.forEach(function (a) {
9126 methods$5[a[0]] = function (n) {
9127 var m = this.match(a[1]);
9128
9129 if (typeof n === 'number') {
9130 m = m.get(n);
9131 }
9132
9133 return m;
9134 };
9135}); // aliases
9136
9137methods$5.emojis = methods$5.emoji;
9138methods$5.atmentions = methods$5.atMentions;
9139methods$5.words = methods$5.terms;
9140/** return anything tagged as a phone number */
9141
9142methods$5.phoneNumbers = function (n) {
9143 var m = this.splitAfter('@hasComma');
9144 m = m.match('#PhoneNumber+');
9145
9146 if (typeof n === 'number') {
9147 m = m.get(n);
9148 }
9149
9150 return m;
9151};
9152/** Deprecated: please use compromise-numbers plugin */
9153
9154
9155methods$5.money = function (n) {
9156 var m = this.match('#Money #Currency?');
9157
9158 if (typeof n === 'number') {
9159 m = m.get(n);
9160 }
9161
9162 return m;
9163};
9164/** return all cities, countries, addresses, and regions */
9165
9166
9167methods$5.places = function (n) {
9168 // don't split 'paris, france'
9169 var keep = this.match('(#City && @hasComma) (#Region|#Country)'); // but split the other commas
9170
9171 var m = this.not(keep).splitAfter('@hasComma'); // combine them back together
9172
9173 m = m.concat(keep);
9174 m.sort('index');
9175 m = m.match('#Place+');
9176
9177 if (typeof n === 'number') {
9178 m = m.get(n);
9179 }
9180
9181 return m;
9182};
9183/** return all schools, businesses and institutions */
9184
9185
9186methods$5.organizations = function (n) {
9187 var m = this.clauses();
9188 m = m.match('#Organization+');
9189
9190 if (typeof n === 'number') {
9191 m = m.get(n);
9192 }
9193
9194 return m;
9195}; //combine them with .topics() method
9196
9197
9198methods$5.entities = function (n) {
9199 var r = this.clauses(); // Find people, places, and organizations
9200
9201 var yup = r.people();
9202 yup = yup.concat(r.places());
9203 yup = yup.concat(r.organizations());
9204 var ignore = ['someone', 'man', 'woman', 'mother', 'brother', 'sister', 'father'];
9205 yup = yup.not(ignore); //return them to normal ordering
9206
9207 yup.sort('sequence'); // yup.unique() //? not sure
9208
9209 if (typeof n === 'number') {
9210 yup = yup.get(n);
9211 }
9212
9213 return yup;
9214}; //aliases
9215
9216
9217methods$5.things = methods$5.entities;
9218methods$5.topics = methods$5.entities;
9219var _simple = methods$5;
9220
9221var underOver = /^(under|over)-?/;
9222/** match a word-sequence, like 'super bowl' in the lexicon */
9223
9224var tryMultiple = function tryMultiple(terms, t, world) {
9225 var lex = world.words; //try a two-word version
9226
9227 var txt = terms[t].reduced + ' ' + terms[t + 1].reduced;
9228
9229 if (lex[txt] !== undefined && lex.hasOwnProperty(txt) === true) {
9230 terms[t].tag(lex[txt], 'lexicon-two', world);
9231 terms[t + 1].tag(lex[txt], 'lexicon-two', world);
9232 return 1;
9233 } //try a three-word version?
9234
9235
9236 if (t + 2 < terms.length) {
9237 txt += ' ' + terms[t + 2].reduced;
9238
9239 if (lex[txt] !== undefined && lex.hasOwnProperty(txt) === true) {
9240 terms[t].tag(lex[txt], 'lexicon-three', world);
9241 terms[t + 1].tag(lex[txt], 'lexicon-three', world);
9242 terms[t + 2].tag(lex[txt], 'lexicon-three', world);
9243 return 2;
9244 }
9245 } //try a four-word version?
9246
9247
9248 if (t + 3 < terms.length) {
9249 txt += ' ' + terms[t + 3].reduced;
9250
9251 if (lex[txt] !== undefined && lex.hasOwnProperty(txt) === true) {
9252 terms[t].tag(lex[txt], 'lexicon-four', world);
9253 terms[t + 1].tag(lex[txt], 'lexicon-four', world);
9254 terms[t + 2].tag(lex[txt], 'lexicon-four', world);
9255 terms[t + 3].tag(lex[txt], 'lexicon-four', world);
9256 return 3;
9257 }
9258 }
9259
9260 return 0;
9261};
9262/** look at each word in our list of known-words */
9263
9264
9265var checkLexicon = function checkLexicon(terms, world) {
9266 var lex = world.words;
9267 var hasCompound = world.hasCompound; // use reduced?
9268 //go through each term, and check the lexicon
9269
9270 for (var t = 0; t < terms.length; t += 1) {
9271 var str = terms[t].clean; //is it the start of a compound word, like 'super bowl'?
9272
9273 if (hasCompound[str] === true && t + 1 < terms.length) {
9274 var foundWords = tryMultiple(terms, t, world);
9275
9276 if (foundWords > 0) {
9277 t += foundWords; //skip any already-found words
9278
9279 continue;
9280 }
9281 } //try one-word lexicon
9282
9283
9284 if (lex[str] !== undefined && lex.hasOwnProperty(str) === true) {
9285 terms[t].tag(lex[str], 'lexicon', world);
9286 continue;
9287 } // look at reduced version of term, too
9288
9289
9290 if (str !== terms[t].reduced && lex.hasOwnProperty(terms[t].reduced) === true) {
9291 terms[t].tag(lex[terms[t].reduced], 'lexicon', world);
9292 continue;
9293 } // prefix strip: try to match 'take' for 'undertake'
9294
9295
9296 if (underOver.test(str) === true) {
9297 var noPrefix = str.replace(underOver, '');
9298
9299 if (lex.hasOwnProperty(noPrefix) === true) {
9300 terms[t].tag(lex[noPrefix], 'noprefix-lexicon', world);
9301 }
9302 }
9303 }
9304
9305 return terms;
9306};
9307
9308var _01Lexicon = checkLexicon;
9309
9310var apostrophes = /[\'‘’‛‵′`´]$/;
9311var perSec = /^(m|k|cm|km|m)\/(s|h|hr)$/; // '5 k/m'
9312//
9313
9314var checkPunctuation = function checkPunctuation(terms, i, world) {
9315 var term = terms[i]; //check hyphenation
9316 // if (term.post.indexOf('-') !== -1 && terms[i + 1] && terms[i + 1].pre === '') {
9317 // term.tag('Hyphenated', 'has-hyphen', world)
9318 // }
9319 // support 'head-over'
9320 // if (term.hasHyphen() === true) {
9321 // console.log(term.tags)
9322 // }
9323 // console.log(term.hasHyphen(), term.text)
9324 //an end-tick (trailing apostrophe) - flanders', or Carlos'
9325
9326 if (apostrophes.test(term.text)) {
9327 if (!apostrophes.test(term.pre) && !apostrophes.test(term.post) && term.clean.length > 2) {
9328 var endChar = term.clean[term.clean.length - 2]; //flanders'
9329
9330 if (endChar === 's') {
9331 term.tag(['Possessive', 'Noun'], 'end-tick', world);
9332 return;
9333 } //chillin'
9334
9335
9336 if (endChar === 'n') {
9337 term.tag(['Gerund'], 'chillin', world);
9338 }
9339 }
9340 } // '5 km/s'
9341
9342
9343 if (perSec.test(term.text)) {
9344 term.tag('Unit', 'per-sec', world);
9345 } // 'NASA' is, but not 'i REALLY love it.'
9346 // if (term.tags.Noun === true && isAcronym(term, world)) {
9347 // term.tag('Acronym', 'acronym-step', world)
9348 // term.tag('Noun', 'acronym-infer', world)
9349 // } else if (!oneLetterWord.hasOwnProperty(term.text) && oneLetterAcronym.test(term.text)) {
9350 // term.tag('Acronym', 'one-letter-acronym', world)
9351 // term.tag('Noun', 'one-letter-infer', world)
9352 // }
9353
9354};
9355
9356var _02Punctuation$1 = checkPunctuation;
9357
9358//these are regexes applied to t.text, instead of t.clean
9359// order matters.
9360var startsWith = [//web tags
9361[/^[\w\.]+@[\w\.]+\.[a-z]{2,3}$/, 'Email'], //not fancy
9362[/^#[a-z0-9_\u00C0-\u00FF]{2,}$/, 'HashTag'], [/^@1?[0-9](am|pm)$/i, 'Time'], // @6pm
9363[/^@1?[0-9]:[0-9]{2}(am|pm)?$/i, 'Time'], // @6:30
9364[/^@\w{2,}$/, 'AtMention'], //@spencermountain
9365[/^(https?:\/\/|www\.)\w+\.[a-z]{2,3}/, 'Url'], //with http/www
9366[/^[\w./]+\.(com|net|gov|org|ly|edu|info|biz|ru|jp|de|in|uk|br)/, 'Url'], //http://mostpopularwebsites.net/top-level-domain
9367//dates/times
9368[/^'[0-9]{2}$/, 'Year'], //like '97
9369[/^[012]?[0-9](:[0-5][0-9])(:[0-5][0-9])$/, 'Time'], //4:32:32
9370[/^[012]?[0-9](:[0-5][0-9])?(:[0-5][0-9])? ?(am|pm)$/i, 'Time'], //4pm
9371[/^[012]?[0-9](:[0-5][0-9])(:[0-5][0-9])? ?(am|pm)?$/i, 'Time'], //4:00pm
9372[/^[PMCE]ST$/, 'Time'], //PST, time zone abbrevs
9373[/^utc ?[+-]?[0-9]+?$/, 'Time'], //UTC 8+
9374[/^[a-z0-9]*? o\'?clock$/, 'Time'], //3 oclock
9375[/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}/i, 'Date'], // 2020-03-02T00:00:00.000Z
9376[/^[0-9]{1,4}-[0-9]{1,2}-[0-9]{1,4}$/, 'Date'], // 03-02-89
9377[/^[0-9]{1,4}\/[0-9]{1,2}\/[0-9]{1,4}$/, 'Date'], // 03/02/89
9378[/^[0-9]{1,4}-[a-z]{2,9}-[0-9]{1,4}$/i, 'Date'], // 03-March-89
9379//names
9380[/^ma?c\'.*/, 'LastName'], //mc'adams
9381[/^o\'[drlkn].*/, 'LastName'], //o'douggan
9382[/^ma?cd[aeiou]/, 'LastName'], //macdonell - Last patterns https://en.wikipedia.org/wiki/List_of_family_name_affixes
9383//slang things
9384[/^(lol)+[sz]$/, 'Expression'], //lol
9385[/^woo+a*?h?$/, 'Expression'], //whoaa, wooo
9386[/^(un|de|re)\\-[a-z\u00C0-\u00FF]{2}/, 'Verb'], // [/^(over|under)[a-z]{2,}/, 'Adjective'],
9387[/^[0-9]{1,4}\.[0-9]{1,2}\.[0-9]{1,4}$/, 'Date'], // 03-02-89
9388//phone numbers
9389[/^[0-9]{3}-[0-9]{4}$/, 'PhoneNumber'], //589-3809
9390[/^(\+?[0-9][ -])?[0-9]{3}[ -]?[0-9]{3}-[0-9]{4}$/, 'PhoneNumber'], //632-589-3809
9391//money
9392// currency regex
9393// /[\$\xA2-\xA5\u058F\u060B\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u17DB\u20A0-\u20BD\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6]
9394//like $5.30
9395[/^[-+]?[\$\xA2-\xA5\u058F\u060B\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u17DB\u20A0-\u20BD\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6][-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?(k|m|b|bn)?\+?$/, ['Money', 'Value']], //like 5.30$
9396[/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?[\$\xA2-\xA5\u058F\u060B\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u17DB\u20A0-\u20BD\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6]\+?$/, ['Money', 'Value']], //like $400usd
9397[/^[-+]?[\$£]?[0-9]([0-9,.])+?(usd|eur|jpy|gbp|cad|aud|chf|cny|hkd|nzd|kr|rub)$/i, ['Money', 'Value']], //numbers
9398// 50 | -50 | 3.23 | 5,999.0 | 10+
9399[/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?\+?$/, ['Cardinal', 'NumericValue']], [/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?(st|nd|rd|r?th)$/, ['Ordinal', 'NumericValue']], // .73th
9400[/^\.[0-9]+\+?$/, ['Cardinal', 'NumericValue']], //percent
9401[/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?%\+?$/, ['Percent', 'Cardinal', 'NumericValue']], //7% ..
9402[/^\.[0-9]+%$/, ['Percent', 'Cardinal', 'NumericValue']], //.7% ..
9403//fraction
9404[/^[0-9]{1,4}\/[0-9]{1,4}(st|nd|rd|th)?s?$/, 'Fraction'], //3/2ths
9405//range
9406[/^[0-9.]{1,2}[-–][0-9]{1,2}$/, ['Value', 'NumberRange']], //7-8
9407[/^[0-9.]{1,3}(st|nd|rd|th)?[-–][0-9\.]{1,3}(st|nd|rd|th)?$/, 'NumberRange'], //5-7
9408//with unit
9409[/^[0-9.]+([a-z]{1,4})$/, 'Value'] //like 5tbsp
9410//ordinal
9411// [/^[0-9][0-9,.]*(st|nd|rd|r?th)$/, ['NumericValue', 'Ordinal']], //like 5th
9412// [/^[0-9]+(st|nd|rd|th)$/, 'Ordinal'], //like 5th
9413];
9414
9415var romanNumeral = /^[IVXLCDM]{2,}$/;
9416var romanNumValid = /^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/; // https://stackoverflow.com/a/267405/168877
9417//try each of the ^regexes in our list
9418
9419var checkRegex = function checkRegex(term, world) {
9420 var str = term.text; // do them all!
9421
9422 for (var r = 0; r < startsWith.length; r += 1) {
9423 if (startsWith[r][0].test(str) === true) {
9424 term.tagSafe(startsWith[r][1], 'prefix #' + r, world);
9425 break;
9426 }
9427 } // do some more!
9428 //roman numberals - XVII
9429
9430
9431 if (term.text.length >= 2 && romanNumeral.test(str) && romanNumValid.test(str)) {
9432 term.tag('RomanNumeral', 'xvii', world);
9433 }
9434};
9435
9436var _03Prefixes = checkRegex;
9437
9438//regex suffix patterns and their most common parts of speech,
9439//built using wordnet, by spencer kelly.
9440//this mapping shrinks-down the uglified build
9441var Adj = 'Adjective';
9442var Inf = 'Infinitive';
9443var Pres = 'PresentTense';
9444var Sing = 'Singular';
9445var Past = 'PastTense';
9446var Adverb = 'Adverb';
9447var Exp = 'Expression';
9448var Actor = 'Actor';
9449var Verb = 'Verb';
9450var Noun = 'Noun';
9451var Last = 'LastName'; //the order here matters.
9452//regexes indexed by mandated last-character
9453
9454var endsWith$1 = {
9455 a: [[/.[aeiou]na$/, Noun], [/.[oau][wvl]ska$/, Last], //polish (female)
9456 [/.[^aeiou]ica$/, Sing], [/^([hyj]a)+$/, Exp] //hahah
9457 ],
9458 c: [[/.[^aeiou]ic$/, Adj]],
9459 d: [//==-ed==
9460 //double-consonant
9461 [/[aeiou](pp|ll|ss|ff|gg|tt|rr|bb|nn|mm)ed$/, Past], //popped, planned
9462 //double-vowel
9463 [/.[aeo]{2}[bdgmnprvz]ed$/, Past], //beeped, mooned, veered
9464 //-hed
9465 [/.[aeiou][sg]hed$/, Past], //stashed, sighed
9466 //-rd
9467 [/.[aeiou]red$/, Past], //stored
9468 [/.[aeiou]r?ried$/, Past], //buried
9469 //-led
9470 [/.[bcdgtr]led$/, Past], //startled, rumbled
9471 [/.[aoui]f?led$/, Past], //impaled, stifled
9472 //-sed
9473 [/.[iao]sed$/, Past], //franchised
9474 [/[aeiou]n?[cs]ed$/, Past], //laced, lanced
9475 //-med
9476 [/[aeiou][rl]?[mnf]ed$/, Past], //warmed, attained, engulfed
9477 //-ked
9478 [/[aeiou][ns]?c?ked$/, Past], //hooked, masked
9479 //-ged
9480 [/[aeiou][nl]?ged$/, Past], //engaged
9481 //-ted
9482 [/.[tdbwxz]ed$/, Past], //bribed, boxed
9483 [/[^aeiou][aeiou][tvx]ed$/, Past], //boxed
9484 //-ied
9485 [/.[cdlmnprstv]ied$/, Past], //rallied
9486 [/[^aeiou]ard$/, Sing], //card
9487 [/[aeiou][^aeiou]id$/, Adj], [/.[vrl]id$/, Adj]],
9488 e: [[/.[lnr]ize$/, Inf], [/.[^aeiou]ise$/, Inf], [/.[aeiou]te$/, Inf], [/.[^aeiou][ai]ble$/, Adj], [/.[^aeiou]eable$/, Adj], [/.[ts]ive$/, Adj]],
9489 h: [[/.[^aeiouf]ish$/, Adj], [/.v[iy]ch$/, Last], //east-europe
9490 [/^ug?h+$/, Exp], //uhh
9491 [/^uh[ -]?oh$/, Exp] //uhoh
9492 ],
9493 i: [[/.[oau][wvl]ski$/, Last] //polish (male)
9494 ],
9495 k: [[/^(k){2}$/, Exp] //kkkk
9496 ],
9497 l: [[/.[gl]ial$/, Adj], [/.[^aeiou]ful$/, Adj], [/.[nrtumcd]al$/, Adj], [/.[^aeiou][ei]al$/, Adj]],
9498 m: [[/.[^aeiou]ium$/, Sing], [/[^aeiou]ism$/, Sing], [/^h*u*m+$/, Exp], //mmmmmmm / ummmm / huuuuuummmmmm
9499 [/^\d+ ?[ap]m$/, 'Date']],
9500 n: [[/.[lsrnpb]ian$/, Adj], [/[^aeiou]ician$/, Actor], [/[aeiou][ktrp]in$/, 'Gerund'] // 'cookin', 'hootin'
9501 ],
9502 o: [[/^no+$/, Exp], //noooo
9503 [/^(yo)+$/, Exp], //yoyo
9504 [/^woo+[pt]?$/, Exp] //woo
9505 ],
9506 r: [[/.[bdfklmst]ler$/, 'Noun'], [/[aeiou][pns]er$/, Sing], [/[^i]fer$/, Inf], [/.[^aeiou][ao]pher$/, Actor], [/.[lk]er$/, 'Noun'], [/.ier$/, 'Comparative']],
9507 t: [[/.[di]est$/, 'Superlative'], [/.[icldtgrv]ent$/, Adj], [/[aeiou].*ist$/, Adj], [/^[a-z]et$/, Verb]],
9508 s: [[/.[^aeiou]ises$/, Pres], [/.[rln]ates$/, Pres], [/.[^z]ens$/, Verb], [/.[lstrn]us$/, Sing], [/.[aeiou]sks$/, Pres], //masks
9509 [/.[aeiou]kes$/, Pres], //bakes
9510 [/[aeiou][^aeiou]is$/, Sing], [/[a-z]\'s$/, Noun], [/^yes+$/, Exp] //yessss
9511 ],
9512 v: [[/.[^aeiou][ai][kln]ov$/, Last] //east-europe
9513 ],
9514 y: [[/.[cts]hy$/, Adj], [/.[st]ty$/, Adj], [/.[gk]y$/, Adj], [/.[tnl]ary$/, Adj], [/.[oe]ry$/, Sing], [/[rdntkbhs]ly$/, Adverb], [/...lly$/, Adverb], [/[bszmp]{2}y$/, Adj], [/.(gg|bb|zz)ly$/, Adj], [/.[ai]my$/, Adj], [/[ea]{2}zy$/, Adj], [/.[^aeiou]ity$/, Sing]]
9515};
9516
9517//just a foolish lookup of known suffixes
9518var Adj$1 = 'Adjective';
9519var Inf$1 = 'Infinitive';
9520var Pres$1 = 'PresentTense';
9521var Sing$1 = 'Singular';
9522var Past$1 = 'PastTense';
9523var Avb = 'Adverb';
9524var Plrl = 'Plural';
9525var Actor$1 = 'Actor';
9526var Vb = 'Verb';
9527var Noun$1 = 'Noun';
9528var Last$1 = 'LastName';
9529var Modal = 'Modal';
9530var Place = 'Place'; // find any issues - https://observablehq.com/@spencermountain/suffix-word-lookup
9531
9532var suffixMap = [null, //0
9533null, //1
9534{
9535 //2-letter
9536 ea: Sing$1,
9537 ia: Noun$1,
9538 ic: Adj$1,
9539 ly: Avb,
9540 "'n": Vb,
9541 "'t": Vb
9542}, {
9543 //3-letter
9544 oed: Past$1,
9545 ued: Past$1,
9546 xed: Past$1,
9547 ' so': Avb,
9548 "'ll": Modal,
9549 "'re": 'Copula',
9550 azy: Adj$1,
9551 eer: Noun$1,
9552 end: Vb,
9553 ped: Past$1,
9554 ffy: Adj$1,
9555 ify: Inf$1,
9556 ing: 'Gerund',
9557 //likely to be converted to Adj after lexicon pass
9558 ize: Inf$1,
9559 lar: Adj$1,
9560 mum: Adj$1,
9561 nes: Pres$1,
9562 nny: Adj$1,
9563 oid: Adj$1,
9564 ous: Adj$1,
9565 que: Adj$1,
9566 rol: Sing$1,
9567 sis: Sing$1,
9568 zes: Pres$1
9569}, {
9570 //4-letter
9571 amed: Past$1,
9572 aped: Past$1,
9573 ched: Past$1,
9574 lked: Past$1,
9575 nded: Past$1,
9576 cted: Past$1,
9577 dged: Past$1,
9578 akis: Last$1,
9579 //greek
9580 cede: Inf$1,
9581 chuk: Last$1,
9582 //east-europe
9583 czyk: Last$1,
9584 //polish (male)
9585 ects: Pres$1,
9586 ends: Vb,
9587 enko: Last$1,
9588 //east-europe
9589 ette: Sing$1,
9590 fies: Pres$1,
9591 fore: Avb,
9592 gate: Inf$1,
9593 gone: Adj$1,
9594 ices: Plrl,
9595 ints: Plrl,
9596 ines: Plrl,
9597 ions: Plrl,
9598 less: Avb,
9599 llen: Adj$1,
9600 made: Adj$1,
9601 nsen: Last$1,
9602 //norway
9603 oses: Pres$1,
9604 ould: Modal,
9605 some: Adj$1,
9606 sson: Last$1,
9607 //swedish male
9608 tage: Inf$1,
9609 teen: 'Value',
9610 tion: Sing$1,
9611 tive: Adj$1,
9612 tors: Noun$1,
9613 vice: Sing$1
9614}, {
9615 //5-letter
9616 tized: Past$1,
9617 urned: Past$1,
9618 eased: Past$1,
9619 ances: Plrl,
9620 bound: Adj$1,
9621 ettes: Plrl,
9622 fully: Avb,
9623 ishes: Pres$1,
9624 ities: Plrl,
9625 marek: Last$1,
9626 //polish (male)
9627 nssen: Last$1,
9628 //norway
9629 ology: Noun$1,
9630 ports: Plrl,
9631 rough: Adj$1,
9632 tches: Pres$1,
9633 tieth: 'Ordinal',
9634 tures: Plrl,
9635 wards: Avb,
9636 where: Avb
9637}, {
9638 //6-letter
9639 auskas: Last$1,
9640 //lithuania
9641 keeper: Actor$1,
9642 logist: Actor$1,
9643 teenth: 'Value'
9644}, {
9645 //7-letter
9646 opoulos: Last$1,
9647 //greek
9648 borough: Place,
9649 //Hillsborough
9650 sdottir: Last$1 //swedish female
9651
9652}];
9653
9654var endRegexs = function endRegexs(term, world) {
9655 var str = term.clean;
9656 var _char = str[str.length - 1];
9657
9658 if (endsWith$1.hasOwnProperty(_char) === true) {
9659 var regs = endsWith$1[_char];
9660
9661 for (var r = 0; r < regs.length; r += 1) {
9662 if (regs[r][0].test(str) === true) {
9663 term.tagSafe(regs[r][1], "endReg ".concat(_char, " #").concat(r), world);
9664 break;
9665 }
9666 }
9667 }
9668}; //sweep-through all suffixes
9669
9670
9671var knownSuffixes = function knownSuffixes(term, world) {
9672 var len = term.clean.length;
9673 var max = 7;
9674
9675 if (len <= max) {
9676 max = len - 1;
9677 }
9678
9679 for (var i = max; i > 1; i -= 1) {
9680 var str = term.clean.substr(len - i, len);
9681
9682 if (suffixMap[str.length].hasOwnProperty(str) === true) {
9683 var tag = suffixMap[str.length][str];
9684 term.tagSafe(tag, 'suffix -' + str, world);
9685 break;
9686 }
9687 }
9688}; //all-the-way-down!
9689
9690
9691var checkRegex$1 = function checkRegex(term, world) {
9692 knownSuffixes(term, world);
9693 endRegexs(term, world);
9694};
9695
9696var _04Suffixes = checkRegex$1;
9697
9698//just some of the most common emoticons
9699//faster than
9700//http://stackoverflow.com/questions/28077049/regex-matching-emoticons
9701var emoticons = {
9702 ':(': true,
9703 ':)': true,
9704 ':P': true,
9705 ':p': true,
9706 ':O': true,
9707 ':3': true,
9708 ':|': true,
9709 ':/': true,
9710 ':\\': true,
9711 ':$': true,
9712 ':*': true,
9713 ':@': true,
9714 ':-(': true,
9715 ':-)': true,
9716 ':-P': true,
9717 ':-p': true,
9718 ':-O': true,
9719 ':-3': true,
9720 ':-|': true,
9721 ':-/': true,
9722 ':-\\': true,
9723 ':-$': true,
9724 ':-*': true,
9725 ':-@': true,
9726 ':^(': true,
9727 ':^)': true,
9728 ':^P': true,
9729 ':^p': true,
9730 ':^O': true,
9731 ':^3': true,
9732 ':^|': true,
9733 ':^/': true,
9734 ':^\\': true,
9735 ':^$': true,
9736 ':^*': true,
9737 ':^@': true,
9738 '):': true,
9739 '(:': true,
9740 '$:': true,
9741 '*:': true,
9742 ')-:': true,
9743 '(-:': true,
9744 '$-:': true,
9745 '*-:': true,
9746 ')^:': true,
9747 '(^:': true,
9748 '$^:': true,
9749 '*^:': true,
9750 '<3': true,
9751 '</3': true,
9752 '<\\3': true
9753};
9754
9755var emojiReg = /^(\u00a9|\u00ae|[\u2319-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/; //for us, there's three types -
9756// * ;) - emoticons
9757// * 🌵 - unicode emoji
9758// * :smiling_face: - asci-represented emoji
9759//test for forms like ':woman_tone2:‍:ear_of_rice:'
9760//https://github.com/Kikobeats/emojis-keywords/blob/master/index.js
9761
9762var isCommaEmoji = function isCommaEmoji(raw) {
9763 if (raw.charAt(0) === ':') {
9764 //end comma can be last or second-last ':haircut_tone3:‍♀️'
9765 if (raw.match(/:.?$/) === null) {
9766 return false;
9767 } //ensure no spaces
9768
9769
9770 if (raw.match(' ')) {
9771 return false;
9772 } //reasonably sized
9773
9774
9775 if (raw.length > 35) {
9776 return false;
9777 }
9778
9779 return true;
9780 }
9781
9782 return false;
9783}; //check against emoticon whitelist
9784
9785
9786var isEmoticon = function isEmoticon(str) {
9787 str = str.replace(/^[:;]/, ':'); //normalize the 'eyes'
9788
9789 return emoticons.hasOwnProperty(str);
9790};
9791
9792var tagEmoji = function tagEmoji(term, world) {
9793 var raw = term.pre + term.text + term.post;
9794 raw = raw.trim(); //dont double-up on ending periods
9795
9796 raw = raw.replace(/[.!?,]$/, ''); //test for :keyword: emojis
9797
9798 if (isCommaEmoji(raw) === true) {
9799 term.tag('Emoji', 'comma-emoji', world);
9800 term.text = raw;
9801 term.pre = term.pre.replace(':', '');
9802 term.post = term.post.replace(':', '');
9803 } //test for unicode emojis
9804
9805
9806 if (term.text.match(emojiReg)) {
9807 term.tag('Emoji', 'unicode-emoji', world);
9808 term.text = raw;
9809 } //test for emoticon ':)' emojis
9810
9811
9812 if (isEmoticon(raw) === true) {
9813 term.tag('Emoticon', 'emoticon-emoji', world);
9814 term.text = raw;
9815 }
9816};
9817
9818var _05Emoji = tagEmoji;
9819
9820var steps = {
9821 lexicon: _01Lexicon,
9822 punctuation: _02Punctuation$1,
9823 regex: _03Prefixes,
9824 suffix: _04Suffixes,
9825 emoji: _05Emoji
9826}; //'lookups' look at a term by itself
9827
9828var lookups = function lookups(doc, terms) {
9829 var world = doc.world; //our list of known-words
9830
9831 steps.lexicon(terms, world); //try these other methods
9832
9833 for (var i = 0; i < terms.length; i += 1) {
9834 var term = terms[i]; //or maybe some helpful punctuation
9835
9836 steps.punctuation(terms, i, world); //mostly prefix checks
9837
9838 steps.regex(term, world); //maybe we can guess
9839
9840 steps.suffix(term, world); //emoji and emoticons
9841
9842 steps.emoji(term, world);
9843 }
9844
9845 return doc;
9846};
9847
9848var _01Init = lookups;
9849
9850//markov-like stats about co-occurance, for hints about unknown terms
9851//basically, a little-bit better than the noun-fallback
9852//just top n-grams from nlp tags, generated from nlp-corpus
9853//after this word, here's what happens usually
9854var afterThisWord = {
9855 i: 'Verb',
9856 //44% //i walk..
9857 first: 'Noun',
9858 //50% //first principles..
9859 it: 'Verb',
9860 //33%
9861 there: 'Verb',
9862 //35%
9863 not: 'Verb',
9864 //33%
9865 because: 'Noun',
9866 //31%
9867 "if": 'Noun',
9868 //32%
9869 but: 'Noun',
9870 //26%
9871 who: 'Verb',
9872 //40%
9873 "this": 'Noun',
9874 //37%
9875 his: 'Noun',
9876 //48%
9877 when: 'Noun',
9878 //33%
9879 you: 'Verb',
9880 //35%
9881 very: 'Adjective',
9882 // 39%
9883 old: 'Noun',
9884 //51%
9885 never: 'Verb',
9886 //42%
9887 before: 'Noun' //28%
9888
9889}; //in advance of this word, this is what happens usually
9890
9891var beforeThisWord = {
9892 there: 'Verb',
9893 //23% // be there
9894 me: 'Verb',
9895 //31% //see me
9896 man: 'Adjective',
9897 // 80% //quiet man
9898 only: 'Verb',
9899 //27% //sees only
9900 him: 'Verb',
9901 //32% //show him
9902 were: 'Noun',
9903 //48% //we were
9904 took: 'Noun',
9905 //38% //he took
9906 himself: 'Verb',
9907 //31% //see himself
9908 went: 'Noun',
9909 //43% //he went
9910 who: 'Noun',
9911 //47% //person who
9912 jr: 'Person'
9913}; //following this POS, this is likely
9914
9915var afterThisPOS = {
9916 Adjective: 'Noun',
9917 //36% //blue dress
9918 Possessive: 'Noun',
9919 //41% //his song
9920 Determiner: 'Noun',
9921 //47%
9922 Adverb: 'Verb',
9923 //20%
9924 Pronoun: 'Verb',
9925 //40%
9926 Value: 'Noun',
9927 //47%
9928 Ordinal: 'Noun',
9929 //53%
9930 Modal: 'Verb',
9931 //35%
9932 Superlative: 'Noun',
9933 //43%
9934 Demonym: 'Noun',
9935 //38%
9936 Honorific: 'Person' //
9937
9938}; //in advance of this POS, this is likely
9939
9940var beforeThisPOS = {
9941 Copula: 'Noun',
9942 //44% //spencer is
9943 PastTense: 'Noun',
9944 //33% //spencer walked
9945 Conjunction: 'Noun',
9946 //36%
9947 Modal: 'Noun',
9948 //38%
9949 Pluperfect: 'Noun',
9950 //40%
9951 PerfectTense: 'Verb' //32%
9952
9953};
9954var markov = {
9955 beforeThisWord: beforeThisWord,
9956 afterThisWord: afterThisWord,
9957 beforeThisPos: beforeThisPOS,
9958 afterThisPos: afterThisPOS
9959};
9960
9961var afterKeys = Object.keys(markov.afterThisPos);
9962var beforeKeys = Object.keys(markov.beforeThisPos);
9963
9964var checkNeighbours = function checkNeighbours(terms, world) {
9965 var _loop = function _loop(i) {
9966 var term = terms[i]; //do we still need a tag?
9967
9968 if (term.isKnown() === true) {
9969 return "continue";
9970 } //ok, this term needs a tag.
9971 //look at previous word for clues..
9972
9973
9974 var lastTerm = terms[i - 1];
9975
9976 if (lastTerm) {
9977 // 'foobar term'
9978 if (markov.afterThisWord.hasOwnProperty(lastTerm.clean) === true) {
9979 var tag = markov.afterThisWord[lastTerm.clean];
9980 term.tag(tag, 'after-' + lastTerm.clean, world);
9981 return "continue";
9982 } // 'Tag term'
9983 // (look at previous POS tags for clues..)
9984
9985
9986 var foundTag = afterKeys.find(function (tag) {
9987 return lastTerm.tags[tag];
9988 });
9989
9990 if (foundTag !== undefined) {
9991 var _tag = markov.afterThisPos[foundTag];
9992 term.tag(_tag, 'after-' + foundTag, world);
9993 return "continue";
9994 }
9995 } //look at next word for clues..
9996
9997
9998 var nextTerm = terms[i + 1];
9999
10000 if (nextTerm) {
10001 // 'term foobar'
10002 if (markov.beforeThisWord.hasOwnProperty(nextTerm.clean) === true) {
10003 var _tag2 = markov.beforeThisWord[nextTerm.clean];
10004 term.tag(_tag2, 'before-' + nextTerm.clean, world);
10005 return "continue";
10006 } // 'term Tag'
10007 // (look at next POS tags for clues..)
10008
10009
10010 var _foundTag = beforeKeys.find(function (tag) {
10011 return nextTerm.tags[tag];
10012 });
10013
10014 if (_foundTag !== undefined) {
10015 var _tag3 = markov.beforeThisPos[_foundTag];
10016 term.tag(_tag3, 'before-' + _foundTag, world);
10017 return "continue";
10018 }
10019 }
10020 };
10021
10022 for (var i = 0; i < terms.length; i += 1) {
10023 var _ret = _loop(i);
10024
10025 if (_ret === "continue") continue;
10026 }
10027};
10028
10029var _01Neighbours = checkNeighbours;
10030
10031var titleCase$4 = /^[A-Z][a-z'\u00C0-\u00FF]/;
10032var hasNumber = /[0-9]/;
10033/** look for any grammar signals based on capital/lowercase */
10034
10035var checkCase = function checkCase(doc) {
10036 var world = doc.world;
10037 doc.list.forEach(function (p) {
10038 var terms = p.terms();
10039
10040 for (var i = 1; i < terms.length; i++) {
10041 var term = terms[i];
10042
10043 if (titleCase$4.test(term.text) === true && hasNumber.test(term.text) === false && term.tags.Date === undefined) {
10044 term.tag('ProperNoun', 'titlecase-noun', world);
10045 }
10046 }
10047 });
10048};
10049
10050var _02Case = checkCase;
10051
10052var hasPrefix = /^(re|un)-?[a-z\u00C0-\u00FF]/;
10053var prefix = /^(re|un)-?/;
10054/** check 'rewatch' in lexicon as 'watch' */
10055
10056var checkPrefix = function checkPrefix(terms, world) {
10057 var lex = world.words;
10058 terms.forEach(function (term) {
10059 // skip if we have a good tag already
10060 if (term.isKnown() === true) {
10061 return;
10062 } //does it start with 'un|re'
10063
10064
10065 if (hasPrefix.test(term.clean) === true) {
10066 // look for the root word in the lexicon:
10067 var stem = term.clean.replace(prefix, '');
10068
10069 if (stem && stem.length > 3 && lex[stem] !== undefined && lex.hasOwnProperty(stem) === true) {
10070 term.tag(lex[stem], 'stem-' + stem, world);
10071 }
10072 }
10073 });
10074};
10075
10076var _03Stem = checkPrefix;
10077
10078//similar to plural/singularize rules, but not the same
10079var isPlural = [/(^v)ies$/i, /ises$/i, /ives$/i, /(antenn|formul|nebul|vertebr|vit)ae$/i, /(octop|vir|radi|nucle|fung|cact|stimul)i$/i, /(buffal|tomat|tornad)oes$/i, /(analy|ba|diagno|parenthe|progno|synop|the)ses$/i, /(vert|ind|cort)ices$/i, /(matr|append)ices$/i, /(x|ch|ss|sh|s|z|o)es$/i, /is$/i, /men$/i, /news$/i, /.tia$/i, /(^f)ves$/i, /(lr)ves$/i, /(^aeiouy|qu)ies$/i, /(m|l)ice$/i, /(cris|ax|test)es$/i, /(alias|status)es$/i, /ics$/i]; //similar to plural/singularize rules, but not the same
10080
10081var isSingular = [/(ax|test)is$/i, /(octop|vir|radi|nucle|fung|cact|stimul)us$/i, /(octop|vir)i$/i, /(rl)f$/i, /(alias|status)$/i, /(bu)s$/i, /(al|ad|at|er|et|ed|ad)o$/i, /(ti)um$/i, /(ti)a$/i, /sis$/i, /(?:(^f)fe|(lr)f)$/i, /hive$/i, /s[aeiou]+ns$/i, // sans, siens
10082/(^aeiouy|qu)y$/i, /(x|ch|ss|sh|z)$/i, /(matr|vert|ind|cort)(ix|ex)$/i, /(m|l)ouse$/i, /(m|l)ice$/i, /(antenn|formul|nebul|vertebr|vit)a$/i, /.sis$/i, /^(?!talis|.*hu)(.*)man$/i];
10083var isPlural_1 = {
10084 isSingular: isSingular,
10085 isPlural: isPlural
10086};
10087
10088var noPlurals = ['Uncountable', 'Pronoun', 'Place', 'Value', 'Person', 'Month', 'WeekDay', 'Holiday'];
10089var notPlural = [/ss$/, /sis$/, /[^aeiou][uo]s$/, /'s$/];
10090var notSingular = [/i$/, /ae$/];
10091/** turn nouns into singular/plural */
10092
10093var checkPlural = function checkPlural(t, world) {
10094 if (t.tags.Noun && !t.tags.Acronym) {
10095 var str = t.clean; //skip existing tags, fast
10096
10097 if (t.tags.Singular || t.tags.Plural) {
10098 return;
10099 } //too short
10100
10101
10102 if (str.length <= 3) {
10103 t.tag('Singular', 'short-singular', world);
10104 return;
10105 } //is it impossible to be plural?
10106
10107
10108 if (noPlurals.find(function (tag) {
10109 return t.tags[tag];
10110 })) {
10111 return;
10112 } // isPlural suffix rules
10113
10114
10115 if (isPlural_1.isPlural.find(function (reg) {
10116 return reg.test(str);
10117 })) {
10118 t.tag('Plural', 'plural-rules', world);
10119 return;
10120 } // isSingular suffix rules
10121
10122
10123 if (isPlural_1.isSingular.find(function (reg) {
10124 return reg.test(str);
10125 })) {
10126 t.tag('Singular', 'singular-rules', world);
10127 return;
10128 } // finally, fallback 'looks plural' rules..
10129
10130
10131 if (/s$/.test(str) === true) {
10132 //avoid anything too sketchy to be plural
10133 if (notPlural.find(function (reg) {
10134 return reg.test(str);
10135 })) {
10136 return;
10137 }
10138
10139 t.tag('Plural', 'plural-fallback', world);
10140 return;
10141 } //avoid anything too sketchy to be singular
10142
10143
10144 if (notSingular.find(function (reg) {
10145 return reg.test(str);
10146 })) {
10147 return;
10148 }
10149
10150 t.tag('Singular', 'singular-fallback', world);
10151 }
10152};
10153
10154var _04Plurals = checkPlural;
10155
10156//nouns that also signal the title of an unknown organization
10157//todo remove/normalize plural forms
10158var orgWords = ['academy', 'administration', 'agence', 'agences', 'agencies', 'agency', 'airlines', 'airways', 'army', 'assoc', 'associates', 'association', 'assurance', 'authority', 'autorite', 'aviation', 'bank', 'banque', 'board', 'boys', 'brands', 'brewery', 'brotherhood', 'brothers', 'building society', 'bureau', 'cafe', 'caisse', 'capital', 'care', 'cathedral', 'center', 'central bank', 'centre', 'chemicals', 'choir', 'chronicle', 'church', 'circus', 'clinic', 'clinique', 'club', 'co', 'coalition', 'coffee', 'collective', 'college', 'commission', 'committee', 'communications', 'community', 'company', 'comprehensive', 'computers', 'confederation', 'conference', 'conseil', 'consulting', 'containers', 'corporation', 'corps', 'corp', 'council', 'crew', 'daily news', 'data', 'departement', 'department', 'department store', 'departments', 'design', 'development', 'directorate', 'division', 'drilling', 'education', 'eglise', 'electric', 'electricity', 'energy', 'ensemble', 'enterprise', 'enterprises', 'entertainment', 'estate', 'etat', 'evening news', 'faculty', 'federation', 'financial', 'fm', 'foundation', 'fund', 'gas', 'gazette', 'girls', 'government', 'group', 'guild', 'health authority', 'herald', 'holdings', 'hospital', 'hotel', 'hotels', 'inc', 'industries', 'institut', 'institute', 'institute of technology', 'institutes', 'insurance', 'international', 'interstate', 'investment', 'investments', 'investors', 'journal', 'laboratory', 'labs', // 'law',
10159'liberation army', 'limited', 'local authority', 'local health authority', 'machines', 'magazine', 'management', 'marine', 'marketing', 'markets', 'media', 'memorial', 'mercantile exchange', 'ministere', 'ministry', 'military', 'mobile', 'motor', 'motors', 'musee', 'museum', // 'network',
10160'news', 'news service', 'observatory', 'office', 'oil', 'optical', 'orchestra', 'organization', 'partners', 'partnership', // 'party',
10161"people's party", 'petrol', 'petroleum', 'pharmacare', 'pharmaceutical', 'pharmaceuticals', 'pizza', 'plc', 'police', 'polytechnic', 'post', 'power', 'press', 'productions', 'quartet', 'radio', 'regional authority', 'regional health authority', 'reserve', 'resources', 'restaurant', 'restaurants', 'savings', 'school', 'securities', 'service', 'services', 'social club', 'societe', 'society', 'sons', 'standard', 'state police', 'state university', 'stock exchange', 'subcommittee', 'syndicat', 'systems', 'telecommunications', 'telegraph', 'television', 'times', 'tribunal', 'tv', 'union', 'university', 'utilities', 'workers'];
10162var organizations = orgWords.reduce(function (h, str) {
10163 h[str] = 'Noun';
10164 return h;
10165}, {});
10166
10167var maybeOrg = function maybeOrg(t) {
10168 //must be a noun
10169 if (!t.tags.Noun) {
10170 return false;
10171 } //can't be these things
10172
10173
10174 if (t.tags.Pronoun || t.tags.Comma || t.tags.Possessive) {
10175 return false;
10176 } //must be one of these
10177
10178
10179 if (t.tags.Organization || t.tags.Acronym || t.tags.Place || t.titleCase()) {
10180 return true;
10181 }
10182
10183 return false;
10184};
10185
10186var tagOrgs = function tagOrgs(terms, world) {
10187 for (var i = 0; i < terms.length; i += 1) {
10188 var t = terms[i];
10189
10190 if (organizations[t.clean] !== undefined && organizations.hasOwnProperty(t.clean) === true) {
10191 // look-backward - eg. 'Toronto University'
10192 var lastTerm = terms[i - 1];
10193
10194 if (lastTerm !== undefined && maybeOrg(lastTerm) === true) {
10195 lastTerm.tagSafe('Organization', 'org-word-1', world);
10196 t.tagSafe('Organization', 'org-word-2', world);
10197 continue;
10198 } //look-forward - eg. University of Toronto
10199
10200
10201 var nextTerm = terms[i + 1];
10202
10203 if (nextTerm !== undefined && nextTerm.clean === 'of') {
10204 if (terms[i + 2] && maybeOrg(terms[i + 2])) {
10205 t.tagSafe('Organization', 'org-of-word-1', world);
10206 nextTerm.tagSafe('Organization', 'org-of-word-2', world);
10207 terms[i + 2].tagSafe('Organization', 'org-of-word-3', world);
10208 continue;
10209 }
10210 }
10211 }
10212 }
10213};
10214
10215var _05Organizations = tagOrgs;
10216
10217var oneLetterAcronym$1 = /^[A-Z]('s|,)?$/;
10218var periodSeperated = /([A-Z]\.){2}[A-Z]?/i;
10219var oneLetterWord = {
10220 I: true,
10221 A: true
10222};
10223
10224var isAcronym$2 = function isAcronym(term, world) {
10225 var str = term.reduced; // a known acronym like fbi
10226
10227 if (term.tags.Acronym) {
10228 return true;
10229 } // if (term.tags.Adverb || term.tags.Verb || term.tags.Value || term.tags.Plural) {
10230 // return false
10231 // }
10232 // known-words, like 'PIZZA' is not an acronym.
10233
10234
10235 if (world.words[str]) {
10236 return false;
10237 } // long capitalized words are not usually either
10238
10239
10240 if (str.length > 5) {
10241 return false;
10242 }
10243
10244 return term.isAcronym();
10245}; // F.B.I., NBC, - but not 'NO COLLUSION'
10246
10247
10248var checkAcronym = function checkAcronym(terms, world) {
10249 terms.forEach(function (term) {
10250 //these are not acronyms
10251 if (term.tags.RomanNumeral === true) {
10252 return;
10253 } //period-ones F.D.B.
10254
10255
10256 if (periodSeperated.test(term.text) === true) {
10257 term.tag('Acronym', 'period-acronym', world);
10258 } //non-period ones are harder
10259
10260
10261 if (term.isUpperCase() && isAcronym$2(term, world)) {
10262 term.tag('Acronym', 'acronym-step', world);
10263 term.tag('Noun', 'acronym-infer', world);
10264 } else if (!oneLetterWord.hasOwnProperty(term.text) && oneLetterAcronym$1.test(term.text)) {
10265 term.tag('Acronym', 'one-letter-acronym', world);
10266 term.tag('Noun', 'one-letter-infer', world);
10267 } //if it's a organization,
10268
10269
10270 if (term.tags.Organization && term.text.length <= 3) {
10271 term.tag('Acronym', 'acronym-org', world);
10272 }
10273
10274 if (term.tags.Organization && term.isUpperCase() && term.text.length <= 6) {
10275 term.tag('Acronym', 'acronym-org-case', world);
10276 }
10277 });
10278};
10279
10280var _06Acronyms = checkAcronym;
10281
10282var step = {
10283 neighbours: _01Neighbours,
10284 "case": _02Case,
10285 stem: _03Stem,
10286 plural: _04Plurals,
10287 organizations: _05Organizations,
10288 acronyms: _06Acronyms
10289}; //
10290
10291var fallbacks = function fallbacks(doc, terms) {
10292 var world = doc.world; // if it's empty, consult it's neighbours, first
10293
10294 step.neighbours(terms, world); // is there a case-sensitive clue?
10295
10296 step["case"](doc); // check 'rewatch' as 'watch'
10297
10298 step.stem(terms, world); // ... fallback to a noun!
10299
10300 terms.forEach(function (t) {
10301 if (t.isKnown() === false) {
10302 t.tag('Noun', 'noun-fallback', doc.world);
10303 }
10304 }); // turn 'Foo University' into an Org
10305
10306 step.organizations(terms, world); //turn 'FBD' into an acronym
10307
10308 step.acronyms(terms, world); //are the nouns singular or plural?
10309
10310 terms.forEach(function (t) {
10311 step.plural(t, doc.world);
10312 });
10313 return doc;
10314};
10315
10316var _02Fallbacks = fallbacks;
10317
10318var hasNegative = /n't$/;
10319var irregulars$3 = {
10320 "won't": ['will', 'not'],
10321 wont: ['will', 'not'],
10322 "can't": ['can', 'not'],
10323 cant: ['can', 'not'],
10324 cannot: ['can', 'not'],
10325 "shan't": ['should', 'not'],
10326 dont: ['do', 'not'],
10327 dun: ['do', 'not'] // "ain't" is ambiguous for is/was
10328
10329}; // either 'is not' or 'are not'
10330
10331var doAint = function doAint(term, phrase) {
10332 var terms = phrase.terms();
10333 var index = terms.indexOf(term);
10334 var before = terms.slice(0, index); //look for the preceding noun
10335
10336 var noun = before.find(function (t) {
10337 return t.tags.Noun;
10338 });
10339
10340 if (noun && noun.tags.Plural) {
10341 return ['are', 'not'];
10342 }
10343
10344 return ['is', 'not'];
10345};
10346
10347var checkNegative = function checkNegative(term, phrase) {
10348 //check named-ones
10349 if (irregulars$3.hasOwnProperty(term.clean) === true) {
10350 return irregulars$3[term.clean];
10351 } //this word needs it's own logic:
10352
10353
10354 if (term.clean === "ain't" || term.clean === 'aint') {
10355 return doAint(term, phrase);
10356 } //try it normally
10357
10358
10359 if (hasNegative.test(term.clean) === true) {
10360 var main = term.clean.replace(hasNegative, '');
10361 return [main, 'not'];
10362 }
10363
10364 return null;
10365};
10366
10367var _01Negative = checkNegative;
10368
10369var contraction = /([a-z\u00C0-\u00FF]+)[\u0027\u0060\u00B4\u2018\u2019\u201A\u201B\u2032\u2035\u2039\u203A]([a-z]{1,2})$/i; //these ones don't seem to be ambiguous
10370
10371var easy = {
10372 ll: 'will',
10373 ve: 'have',
10374 re: 'are',
10375 m: 'am',
10376 "n't": 'not'
10377}; //
10378
10379var checkApostrophe = function checkApostrophe(term) {
10380 var parts = term.text.match(contraction);
10381
10382 if (parts === null) {
10383 return null;
10384 }
10385
10386 if (easy.hasOwnProperty(parts[2])) {
10387 return [parts[1], easy[parts[2]]];
10388 }
10389
10390 return null;
10391};
10392
10393var _02Simple = checkApostrophe;
10394
10395var irregulars$4 = {
10396 wanna: ['want', 'to'],
10397 gonna: ['going', 'to'],
10398 im: ['i', 'am'],
10399 alot: ['a', 'lot'],
10400 ive: ['i', 'have'],
10401 imma: ['I', 'will'],
10402 "where'd": ['where', 'did'],
10403 whered: ['where', 'did'],
10404 "when'd": ['when', 'did'],
10405 whend: ['when', 'did'],
10406 // "how'd": ['how', 'did'], //'how would?'
10407 // "what'd": ['what', 'did'], //'what would?'
10408 howd: ['how', 'did'],
10409 whatd: ['what', 'did'],
10410 // "let's": ['let', 'us'], //too weird
10411 //multiple word contractions
10412 dunno: ['do', 'not', 'know'],
10413 brb: ['be', 'right', 'back'],
10414 gtg: ['got', 'to', 'go'],
10415 irl: ['in', 'real', 'life'],
10416 tbh: ['to', 'be', 'honest'],
10417 imo: ['in', 'my', 'opinion'],
10418 til: ['today', 'i', 'learned'],
10419 rn: ['right', 'now'],
10420 twas: ['it', 'was'],
10421 '@': ['at']
10422}; //
10423
10424var checkIrregulars = function checkIrregulars(term) {
10425 //check white-list
10426 if (irregulars$4.hasOwnProperty(term.clean)) {
10427 return irregulars$4[term.clean];
10428 }
10429
10430 return null;
10431};
10432
10433var _03Irregulars = checkIrregulars;
10434
10435var hasApostropheS = /([a-z\u00C0-\u00FF]+)[\u0027\u0060\u00B4\u2018\u2019\u201A\u201B\u2032\u2035\u2039\u203A]s$/i;
10436var banList = {
10437 that: true,
10438 there: true
10439};
10440var hereThere = {
10441 here: true,
10442 there: true,
10443 everywhere: true
10444};
10445
10446var isPossessive = function isPossessive(term, pool) {
10447 // if we already know it
10448 if (term.tags.Possessive) {
10449 return true;
10450 } //a pronoun can't be possessive - "he's house"
10451
10452
10453 if (term.tags.Pronoun || term.tags.QuestionWord) {
10454 return false;
10455 }
10456
10457 if (banList.hasOwnProperty(term.reduced)) {
10458 return false;
10459 } //if end of sentence, it is possessive - "was spencer's"
10460
10461
10462 var nextTerm = pool.get(term.next);
10463
10464 if (!nextTerm) {
10465 return true;
10466 } //a gerund suggests 'is walking'
10467
10468
10469 if (nextTerm.tags.Verb) {
10470 //fix 'jamie's bite'
10471 if (nextTerm.tags.Infinitive) {
10472 return true;
10473 } //fix 'spencer's runs'
10474
10475
10476 if (nextTerm.tags.PresentTense) {
10477 return true;
10478 }
10479
10480 return false;
10481 } //spencer's house
10482
10483
10484 if (nextTerm.tags.Noun) {
10485 // 'spencer's here'
10486 if (hereThere.hasOwnProperty(nextTerm.reduced) === true) {
10487 return false;
10488 }
10489
10490 return true;
10491 } //rocket's red glare
10492
10493
10494 var twoTerm = pool.get(nextTerm.next);
10495
10496 if (twoTerm && twoTerm.tags.Noun && !twoTerm.tags.Pronoun) {
10497 return true;
10498 } //othwerwise, an adjective suggests 'is good'
10499
10500
10501 if (nextTerm.tags.Adjective || nextTerm.tags.Adverb || nextTerm.tags.Verb) {
10502 return false;
10503 }
10504
10505 return false;
10506};
10507
10508var isHas = function isHas(term, phrase) {
10509 var terms = phrase.terms();
10510 var index = terms.indexOf(term);
10511 var after = terms.slice(index + 1, index + 3); //look for a past-tense verb
10512
10513 return after.find(function (t) {
10514 return t.tags.PastTense;
10515 });
10516};
10517
10518var checkPossessive = function checkPossessive(term, phrase, world) {
10519 //the rest of 's
10520 var found = term.text.match(hasApostropheS);
10521
10522 if (found !== null) {
10523 //spencer's thing vs spencer-is
10524 if (isPossessive(term, phrase.pool) === true) {
10525 term.tag('#Possessive', 'isPossessive', world);
10526 return null;
10527 } //'spencer is'
10528
10529
10530 if (found !== null) {
10531 if (isHas(term, phrase)) {
10532 return [found[1], 'has'];
10533 }
10534
10535 return [found[1], 'is'];
10536 }
10537 }
10538
10539 return null;
10540};
10541
10542var _04Possessive = checkPossessive;
10543
10544var hasPerfect = /[a-z\u00C0-\u00FF]'d$/;
10545var useDid = {
10546 how: true,
10547 what: true
10548};
10549/** split `i'd` into 'i had', or 'i would' */
10550
10551var checkPerfect = function checkPerfect(term, phrase) {
10552 if (hasPerfect.test(term.clean)) {
10553 var root = term.clean.replace(/'d$/, ''); //look at the next few words
10554
10555 var terms = phrase.terms();
10556 var index = terms.indexOf(term);
10557 var after = terms.slice(index + 1, index + 4); //is it before a past-tense verb? - 'i'd walked'
10558
10559 for (var i = 0; i < after.length; i++) {
10560 var t = after[i];
10561
10562 if (t.tags.Verb) {
10563 if (t.tags.PastTense) {
10564 return [root, 'had'];
10565 } //what'd you see
10566
10567
10568 if (useDid[root] === true) {
10569 return [root, 'did'];
10570 }
10571
10572 return [root, 'would'];
10573 }
10574 } //otherwise, 'i'd walk'
10575
10576
10577 return [root, 'would'];
10578 }
10579
10580 return null;
10581};
10582
10583var _05PerfectTense = checkPerfect;
10584
10585var isRange = /^([0-9]{1,3}(?:st|nd|rd|th)?)[-–—]([0-9]{1,3}(?:st|nd|rd|th)?)$/i; //split '2-4' into '2 to 4'
10586
10587var checkRange = function checkRange(term) {
10588 if (term.tags.PhoneNumber === true) {
10589 return null;
10590 }
10591
10592 var parts = term.text.match(isRange);
10593
10594 if (parts !== null) {
10595 return [parts[1], 'to', parts[2]];
10596 }
10597
10598 return null;
10599};
10600
10601var _06Ranges = checkRange;
10602
10603var contraction$1 = /^(l|c|d|j|m|n|qu|s|t)[\u0027\u0060\u00B4\u2018\u2019\u201A\u201B\u2032\u2035\u2039\u203A]([a-z\u00C0-\u00FF]+)$/i; // basic support for ungendered french contractions
10604// not perfect, but better than nothing, to support matching on french text.
10605
10606var french = {
10607 l: 'le',
10608 // l'amour
10609 c: 'ce',
10610 // c'est
10611 d: 'de',
10612 // d'amerique
10613 j: 'je',
10614 // j'aime
10615 m: 'me',
10616 // m'appelle
10617 n: 'ne',
10618 // n'est
10619 qu: 'que',
10620 // qu'il
10621 s: 'se',
10622 // s'appelle
10623 t: 'tu' // t'aime
10624
10625};
10626
10627var checkFrench = function checkFrench(term) {
10628 var parts = term.text.match(contraction$1);
10629
10630 if (parts === null || french.hasOwnProperty(parts[1]) === false) {
10631 return null;
10632 }
10633
10634 var arr = [french[parts[1]], parts[2]];
10635
10636 if (arr[0] && arr[1]) {
10637 return arr;
10638 }
10639
10640 return null;
10641};
10642
10643var _07French = checkFrench;
10644
10645var isNumber = /^[0-9]+$/;
10646var isOrdinal = /^[0-9]+(st|nd|rd|th)$/;
10647
10648var createPhrase = function createPhrase(found, doc) {
10649 //create phrase from ['would', 'not']
10650 var phrase = _01Tokenizer(found.join(' '), doc.world, doc.pool())[0]; //tag it
10651
10652 var terms = phrase.terms();
10653 _01Lexicon(terms, doc.world); //make these terms implicit
10654
10655 terms.forEach(function (t) {
10656 t.implicit = t.text;
10657 t.text = '';
10658 t.clean = ''; // remove whitespace for implicit terms
10659
10660 t.pre = '';
10661 t.post = ''; // tag number-ranges
10662
10663 if (isNumber.test(t.implicit)) {
10664 t.tag('Cardinal', 'num-range', doc.world);
10665 } else if (isOrdinal.test(t.implicit)) {
10666 t.tag('Ordinal', 'ord-range', doc.world);
10667 } else if (Object.keys(t.tags).length === 0) {
10668 t.tags.Noun = true; // if no tag, give it a noun
10669 }
10670 });
10671 return phrase;
10672};
10673
10674var contractions = function contractions(doc) {
10675 var world = doc.world;
10676 doc.list.forEach(function (p) {
10677 var terms = p.terms();
10678
10679 for (var i = 0; i < terms.length; i += 1) {
10680 var term = terms[i];
10681 var found = _01Negative(term, p);
10682 found = found || _02Simple(term);
10683 found = found || _03Irregulars(term);
10684 found = found || _04Possessive(term, p, world);
10685 found = found || _05PerfectTense(term, p);
10686 found = found || _06Ranges(term);
10687 found = found || _07French(term); //add them in
10688
10689 if (found !== null) {
10690 var newPhrase = createPhrase(found, doc); // keep tag NumberRange, if we had it
10691
10692 if (p.has('#NumberRange') === true) {
10693 doc.buildFrom([newPhrase]).tag('NumberRange');
10694 } //set text as contraction
10695
10696
10697 var firstTerm = newPhrase.terms(0);
10698 firstTerm.text = term.text; //grab sub-phrase to remove
10699
10700 var match = p.buildFrom(term.id, 1, doc.pool());
10701 match.replace(newPhrase, doc, true);
10702 }
10703 }
10704 });
10705 return doc;
10706};
10707
10708var _03Contractions = contractions;
10709
10710var hasWord = function hasWord(doc, word) {
10711 var arr = doc._cache.words[word] || [];
10712 arr = arr.map(function (i) {
10713 return doc.list[i];
10714 });
10715 return doc.buildFrom(arr);
10716};
10717
10718var hasTag = function hasTag(doc, tag) {
10719 var arr = doc._cache.tags[tag] || [];
10720 arr = arr.map(function (i) {
10721 return doc.list[i];
10722 });
10723 return doc.buildFrom(arr);
10724}; //mostly pos-corections here
10725
10726
10727var miscCorrection = function miscCorrection(doc) {
10728 //exactly like
10729 var m = hasWord(doc, 'like');
10730 m.match('#Adverb like').notIf('(really|generally|typically|usually|sometimes|often|just) [like]').tag('Adverb', 'adverb-like'); //the orange.
10731
10732 m = hasTag(doc, 'Adjective');
10733 m.match('#Determiner #Adjective$').notIf('(#Comparative|#Superlative)').terms(1).tag('Noun', 'the-adj-1'); // Firstname x (dangerous)
10734
10735 m = hasTag(doc, 'FirstName');
10736 m.match('#FirstName (#Noun|@titleCase)').ifNo('^#Possessive').ifNo('(#Pronoun|#Plural)').ifNo('@hasComma .').lastTerm().tag('#LastName', 'firstname-noun'); //three trains / one train
10737
10738 m = hasTag(doc, 'Value');
10739 m = m.match('#Value #PresentTense').ifNo('#Copula');
10740
10741 if (m.found) {
10742 if (m.has('(one|1)') === true) {
10743 m.terms(1).tag('Singular', 'one-presentTense');
10744 } else {
10745 m.terms(1).tag('Plural', 'value-presentTense');
10746 }
10747 } // well i've been...
10748
10749
10750 doc.match('^(well|so|okay)').tag('Expression', 'well-'); //been walking
10751
10752 m = hasTag(doc, 'Gerund');
10753 m.match("(be|been) (#Adverb|not)+? #Gerund").not('#Verb$').tag('Auxiliary', 'be-walking'); // directive verb - 'use reverse'
10754
10755 doc.match('(try|use|attempt|build|make) #Verb').ifNo('(@hasComma|#Negative|#PhrasalVerb|#Copula|will|be)').lastTerm().tag('#Noun', 'do-verb'); //possessives
10756 //'her match' vs 'let her match'
10757
10758 m = hasTag(doc, 'Possessive');
10759 m = m.match('#Possessive [#Infinitive]', 0);
10760
10761 if (!m.lookBehind('(let|made|make|force|ask)').found) {
10762 m.tag('Noun', 'her-match');
10763 }
10764
10765 return doc;
10766};
10767
10768var fixMisc = miscCorrection;
10769
10770var unique$5 = function unique(arr) {
10771 var obj = {};
10772
10773 for (var i = 0; i < arr.length; i++) {
10774 obj[arr[i]] = true;
10775 }
10776
10777 return Object.keys(obj);
10778};
10779
10780var _unique = unique$5;
10781
10782// order matters
10783var list = [// ==== Mutliple tags ====
10784{
10785 match: 'too much',
10786 tag: 'Adverb Adjective',
10787 reason: 'bit-4'
10788}, // u r cool
10789{
10790 match: 'u r',
10791 tag: 'Pronoun Copula',
10792 reason: 'u r'
10793}, //sometimes adverbs - 'pretty good','well above'
10794{
10795 match: '#Copula (pretty|dead|full|well|sure) (#Adjective|#Noun)',
10796 tag: '#Copula #Adverb #Adjective',
10797 reason: 'sometimes-adverb'
10798}, //i better ..
10799{
10800 match: '(#Pronoun|#Person) (had|#Adverb)? [better] #PresentTense',
10801 group: 0,
10802 tag: 'Modal',
10803 reason: 'i-better'
10804}, //walking is cool
10805{
10806 match: '[#Gerund] #Adverb? not? #Copula',
10807 group: 0,
10808 tag: 'Activity',
10809 reason: 'gerund-copula'
10810}, //walking should be fun
10811{
10812 match: '[#Gerund] #Modal',
10813 group: 0,
10814 tag: 'Activity',
10815 reason: 'gerund-modal'
10816}, //swear-words as non-expression POS
10817{
10818 match: 'holy (shit|fuck|hell)',
10819 tag: 'Expression',
10820 reason: 'swears-expression'
10821}, //Aircraft designer
10822{
10823 match: '#Noun #Actor',
10824 tag: 'Actor',
10825 reason: 'thing-doer'
10826}, {
10827 match: '#Conjunction [u]',
10828 group: 0,
10829 tag: 'Pronoun',
10830 reason: 'u-pronoun-2'
10831}, //'u' as pronoun
10832{
10833 match: '[u] #Verb',
10834 group: 0,
10835 tag: 'Pronoun',
10836 reason: 'u-pronoun-1'
10837}, // ==== Determiners ====
10838{
10839 match: '#Noun [(who|whom)]',
10840 group: 0,
10841 tag: 'Determiner',
10842 reason: 'captain-who'
10843}, //that car goes
10844// { match: 'that #Noun [#PresentTense]', group: 0, tag: 'Determiner', reason: 'that-determiner' },
10845{
10846 match: 'a bit much',
10847 tag: 'Determiner Adverb Adjective',
10848 reason: 'bit-3'
10849}, // ==== Propositions ====
10850//all students
10851{
10852 match: '#Verb #Adverb? #Noun [(that|which)]',
10853 group: 0,
10854 tag: 'Preposition',
10855 reason: 'that-prep'
10856}, //work, which has been done.
10857{
10858 match: '@hasComma [which] (#Pronoun|#Verb)',
10859 group: 0,
10860 tag: 'Preposition',
10861 reason: 'which-copula'
10862}, {
10863 match: '#Copula just [like]',
10864 group: 0,
10865 tag: 'Preposition',
10866 reason: 'like-preposition'
10867}, //folks like her
10868{
10869 match: '#Noun [like] #Noun',
10870 group: 0,
10871 tag: 'Preposition',
10872 reason: 'noun-like'
10873}, //fix for busted-up phrasalVerbs
10874// { match: '#Noun [#Particle]', group: 0, tag: 'Preposition', reason: 'repair-noPhrasal' },
10875// ==== Conditions ====
10876// had he survived,
10877{
10878 match: '[had] #Noun+ #PastTense',
10879 group: 0,
10880 tag: 'Condition',
10881 reason: 'had-he'
10882}, // were he to survive
10883{
10884 match: '[were] #Noun+ to #Infinitive',
10885 group: 0,
10886 tag: 'Condition',
10887 reason: 'were-he'
10888}, // ==== Questions ====
10889//the word 'how'
10890{
10891 match: '^how',
10892 tag: 'QuestionWord',
10893 reason: 'how-question'
10894}, {
10895 match: '[how] (#Determiner|#Copula|#Modal|#PastTense)',
10896 group: 0,
10897 tag: 'QuestionWord',
10898 reason: 'how-is'
10899}, // //the word 'which'
10900{
10901 match: '^which',
10902 tag: 'QuestionWord',
10903 reason: 'which-question'
10904}, // { match: '[which] . (#Noun)+ #Pronoun', group: 0, tag: 'QuestionWord', reason: 'which-question2' },
10905// { match: 'which', tag: 'QuestionWord', reason: 'which-question3' },
10906// ==== Conjunctions ====
10907{
10908 match: '[so] #Noun',
10909 group: 0,
10910 tag: 'Conjunction',
10911 reason: 'so-conj'
10912}, //how he is driving
10913{
10914 match: '[(who|what|where|why|how|when)] #Noun #Copula #Adverb? (#Verb|#Adjective)',
10915 group: 0,
10916 tag: 'Conjunction',
10917 reason: 'how-he-is-x'
10918} // {
10919// match: '[(who|what|where|why|how|when)] #Noun #Adverb? #Infinitive not? #Gerund',
10920// group: 0,
10921// tag: 'Conjunction',
10922// reason: 'when-i-go-fishing',
10923// },
10924];
10925var _01Misc = list;
10926
10927var _ambig = {
10928 // adverbs than can be adjectives
10929 adverbAdjective: ['dark', 'bright', 'flat', 'light', 'soft', 'pale', 'dead', 'dim', 'faux', 'little', 'wee', 'sheer', 'most', 'near', 'good', 'extra', 'all'],
10930 // names that are dates
10931 personDate: ['april', 'june', 'may', 'jan', 'august', 'eve'],
10932 // names that may be months
10933 personMonth: ['january', 'april', 'may', 'june', 'jan', 'sep'],
10934 // names that are adjectives
10935 personAdjective: ['misty', 'rusty', 'dusty', 'rich', 'randy', 'young'],
10936 // names that are verbs
10937 personVerb: ['pat', 'wade', 'ollie', 'will', 'rob', 'buck', 'bob', 'mark', 'jack'],
10938 // names that are verbs
10939 personPlace: ['darwin', 'hamilton', 'paris', 'alexandria', 'houston', 'kobe', 'santiago', 'salvador', 'sydney', 'victoria'],
10940 // names that are nouns
10941 personNoun: ['art', 'baker', 'berg', 'bill', 'brown', 'charity', 'chin', 'christian', 'cliff', 'daisy', 'dawn', 'dick', 'dolly', 'faith', 'franco', 'gene', 'green', 'hall', 'hill', 'holly', 'hope', 'jean', 'jewel', 'joy', 'kelvin', 'king', 'kitty', 'lane', 'lily', 'melody', 'mercedes', 'miles', 'olive', 'penny', 'ray', 'reed', 'robin', 'rod', 'rose', 'sky', 'summer', 'trinity', 'van', 'viola', 'violet', 'wang', 'white']
10942};
10943
10944var dates = "(".concat(_ambig.personDate.join('|'), ")");
10945var list$1 = [// ==== Holiday ====
10946{
10947 match: '#Holiday (day|eve)',
10948 tag: 'Holiday',
10949 reason: 'holiday-day'
10950}, // the captain who
10951// ==== WeekDay ====
10952// sun the 5th
10953{
10954 match: '[sun] the #Ordinal',
10955 tag: 'WeekDay',
10956 reason: 'sun-the-5th'
10957}, //sun feb 2
10958{
10959 match: '[sun] #Date',
10960 group: 0,
10961 tag: 'WeekDay',
10962 reason: 'sun-feb'
10963}, //1pm next sun
10964{
10965 match: '#Date (on|this|next|last|during)? [sun]',
10966 group: 0,
10967 tag: 'WeekDay',
10968 reason: '1pm-sun'
10969}, //this sat
10970{
10971 match: "(in|by|before|during|on|until|after|of|within|all) [sat]",
10972 group: 0,
10973 tag: 'WeekDay',
10974 reason: 'sat'
10975}, {
10976 match: "(in|by|before|during|on|until|after|of|within|all) [wed]",
10977 group: 0,
10978 tag: 'WeekDay',
10979 reason: 'wed'
10980}, {
10981 match: "(in|by|before|during|on|until|after|of|within|all) [march]",
10982 group: 0,
10983 tag: 'Month',
10984 reason: 'march'
10985}, //sat november
10986{
10987 match: '[sat] #Date',
10988 group: 0,
10989 tag: 'WeekDay',
10990 reason: 'sat-feb'
10991}, // ==== Month ====
10992//all march
10993{
10994 match: "#Preposition [(march|may)]",
10995 group: 0,
10996 tag: 'Month',
10997 reason: 'in-month'
10998}, //this march
10999{
11000 match: "this [(march|may)]",
11001 group: 0,
11002 tag: 'Month',
11003 reason: 'this-month'
11004}, {
11005 match: "next [(march|may)]",
11006 group: 0,
11007 tag: 'Month',
11008 reason: 'this-month'
11009}, {
11010 match: "last [(march|may)]",
11011 group: 0,
11012 tag: 'Month',
11013 reason: 'this-month'
11014}, // march 5th
11015{
11016 match: "[(march|may)] the? #Value",
11017 group: 0,
11018 tag: 'Month',
11019 reason: 'march-5th'
11020}, // 5th of march
11021{
11022 match: "#Value of? [(march|may)]",
11023 group: 0,
11024 tag: 'Month',
11025 reason: '5th-of-march'
11026}, // march and feb
11027{
11028 match: "[(march|may)] .? #Date",
11029 group: 0,
11030 tag: 'Month',
11031 reason: 'march-and-feb'
11032}, // feb to march
11033{
11034 match: "#Date .? [(march|may)]",
11035 group: 0,
11036 tag: 'Month',
11037 reason: 'feb-and-march'
11038}, //quickly march
11039{
11040 match: "#Adverb [(march|may)]",
11041 group: 0,
11042 tag: 'Verb',
11043 reason: 'quickly-march'
11044}, //march quickly
11045{
11046 match: "[(march|may)] #Adverb",
11047 group: 0,
11048 tag: 'Verb',
11049 reason: 'march-quickly'
11050}, //5th of March
11051{
11052 match: '#Value of #Month',
11053 tag: 'Date',
11054 reason: 'value-of-month'
11055}, //5 March
11056{
11057 match: '#Cardinal #Month',
11058 tag: 'Date',
11059 reason: 'cardinal-month'
11060}, //march 5 to 7
11061{
11062 match: '#Month #Value to #Value',
11063 tag: 'Date',
11064 reason: 'value-to-value'
11065}, //march the 12th
11066{
11067 match: '#Month the #Value',
11068 tag: 'Date',
11069 reason: 'month-the-value'
11070}, //june 7
11071{
11072 match: '(#WeekDay|#Month) #Value',
11073 tag: 'Date',
11074 reason: 'date-value'
11075}, //7 june
11076{
11077 match: '#Value (#WeekDay|#Month)',
11078 tag: 'Date',
11079 reason: 'value-date'
11080}, //may twenty five
11081{
11082 match: '(#TextValue && #Date) #TextValue',
11083 tag: 'Date',
11084 reason: 'textvalue-date'
11085}, // in june
11086{
11087 match: "in [".concat(dates, "]"),
11088 group: 0,
11089 tag: 'Date',
11090 reason: 'in-june'
11091}, {
11092 match: "during [".concat(dates, "]"),
11093 group: 0,
11094 tag: 'Date',
11095 reason: 'in-june'
11096}, {
11097 match: "on [".concat(dates, "]"),
11098 group: 0,
11099 tag: 'Date',
11100 reason: 'in-june'
11101}, {
11102 match: "by [".concat(dates, "]"),
11103 group: 0,
11104 tag: 'Date',
11105 reason: 'by-june'
11106}, {
11107 match: "after [".concat(dates, "]"),
11108 group: 0,
11109 tag: 'Date',
11110 reason: 'after-june'
11111}, {
11112 match: "#Date [".concat(dates, "]"),
11113 group: 0,
11114 tag: 'Date',
11115 reason: 'in-june'
11116}, // june 1992
11117{
11118 match: "".concat(dates, " #Value"),
11119 tag: 'Date',
11120 reason: 'june-5th'
11121}, {
11122 match: "".concat(dates, " #Date"),
11123 tag: 'Date',
11124 reason: 'june-5th'
11125}, // June Smith
11126{
11127 match: "".concat(dates, " #ProperNoun"),
11128 tag: 'Person',
11129 reason: 'june-smith',
11130 safe: true
11131}, // june m. Cooper
11132{
11133 match: "".concat(dates, " #Acronym? (#ProperNoun && !#Month)"),
11134 tag: 'Person',
11135 reason: 'june-smith-jr'
11136}, // 'second'
11137{
11138 match: "#Cardinal [second]",
11139 tag: 'Unit',
11140 reason: 'one-second'
11141}, // second quarter
11142// { match: `#Ordinal quarter`, tag: 'Date', reason: 'second-quarter' },
11143// 'aug 20-21'
11144{
11145 match: "#Month #NumberRange",
11146 tag: 'Date',
11147 reason: 'aug 20-21'
11148}];
11149var _02Dates = list$1;
11150
11151var adjectives$1 = "(".concat(_ambig.personAdjective.join('|'), ")");
11152var list$2 = [// all fell apart
11153{
11154 match: '[all] #Determiner? #Noun',
11155 group: 0,
11156 tag: 'Adjective',
11157 reason: 'all-noun'
11158}, // very rusty
11159{
11160 match: "#Adverb [".concat(adjectives$1, "]"),
11161 group: 0,
11162 tag: 'Adjective',
11163 reason: 'really-rich'
11164}, // rusty smith
11165{
11166 match: "".concat(adjectives$1, " #Person"),
11167 tag: 'Person',
11168 reason: 'randy-smith'
11169}, // rusty a. smith
11170{
11171 match: "".concat(adjectives$1, " #Acronym? #ProperNoun"),
11172 tag: 'Person',
11173 reason: 'rusty-smith'
11174}, //sometimes not-adverbs
11175{
11176 match: '#Copula [(just|alone)]$',
11177 group: 0,
11178 tag: 'Adjective',
11179 reason: 'not-adverb'
11180}, //jack is guarded
11181{
11182 match: '#Singular is #Adverb? [#PastTense$]',
11183 group: 0,
11184 tag: 'Adjective',
11185 reason: 'is-filled'
11186}, // smoked poutine is
11187{
11188 match: '[#PastTense] #Singular is',
11189 group: 0,
11190 tag: 'Adjective',
11191 reason: 'smoked-poutine'
11192}, // baked onions are
11193{
11194 match: '[#PastTense] #Plural are',
11195 group: 0,
11196 tag: 'Adjective',
11197 reason: 'baked-onions'
11198}, // well made
11199{
11200 match: 'well [#PastTense]',
11201 group: 0,
11202 tag: 'Adjective',
11203 reason: 'well-made'
11204}, // is f*ed up
11205{
11206 match: '#Copula [fucked up?]',
11207 tag: 'Adjective',
11208 reason: 'swears-adjective'
11209}, //jack seems guarded
11210{
11211 match: '#Singular (seems|appears) #Adverb? [#PastTense$]',
11212 group: 0,
11213 tag: 'Adjective',
11214 reason: 'seems-filled'
11215}, // Gerund-Adjectives - 'amusing, annoying'
11216//a staggering cost
11217{
11218 match: '(a|an) [#Gerund]',
11219 group: 0,
11220 tag: 'Adjective',
11221 reason: 'a|an'
11222}, //as amusing as
11223{
11224 match: 'as [#Gerund] as',
11225 group: 0,
11226 tag: 'Adjective',
11227 reason: 'as-gerund-as'
11228}, // more amusing than
11229{
11230 match: 'more [#Gerund] than',
11231 group: 0,
11232 tag: 'Adjective',
11233 reason: 'more-gerund-than'
11234}, // very amusing
11235{
11236 match: '(so|very|extremely) [#Gerund]',
11237 group: 0,
11238 tag: 'Adjective',
11239 reason: 'so-gerund'
11240}, // it was amusing
11241{
11242 match: '(it|he|she|everything|something) #Adverb? was #Adverb? [#Gerund]',
11243 group: 0,
11244 tag: 'Adjective',
11245 reason: 'it-was-gerund'
11246}, // found it amusing
11247{
11248 match: '(found|found) it #Adverb? [#Gerund]',
11249 group: 0,
11250 tag: 'Adjective',
11251 reason: 'found-it-gerund'
11252}, // a bit amusing
11253{
11254 match: 'a (little|bit|wee) bit? [#Gerund]',
11255 group: 0,
11256 tag: 'Adjective',
11257 reason: 'a-bit-gerund'
11258}, // jury is out - preposition ➔ adjective
11259{
11260 match: '#Copula #Adjective? [(out|in|through)]$',
11261 group: 0,
11262 tag: 'Adjective',
11263 reason: 'still-out'
11264}];
11265var _03Adjective = list$2;
11266
11267var _04Noun = [// ==== Plural ====
11268//there are reasons
11269{
11270 match: 'there (are|were) #Adjective? [#PresentTense]',
11271 group: 0,
11272 tag: 'Plural',
11273 reason: 'there-are'
11274}, // ==== Singular ====
11275//the sun
11276{
11277 match: '#Determiner [sun]',
11278 group: 0,
11279 tag: 'Singular',
11280 reason: 'the-sun'
11281}, //did a 900, paid a 20
11282{
11283 match: '#Verb (a|an) [#Value]',
11284 group: 0,
11285 tag: 'Singular',
11286 reason: 'did-a-value'
11287}, //'the can'
11288{
11289 match: 'the [(can|will|may)]',
11290 group: 0,
11291 tag: 'Singular',
11292 reason: 'the can'
11293}, // ==== Possessive ====
11294//spencer kelly's
11295{
11296 match: '#FirstName #Acronym? (#Possessive && #LastName)',
11297 tag: 'Possessive',
11298 reason: 'name-poss'
11299}, //Super Corp's fundraiser
11300{
11301 match: '#Organization+ #Possessive',
11302 tag: 'Possessive',
11303 reason: 'org-possessive'
11304}, //Los Angeles's fundraiser
11305{
11306 match: '#Place+ #Possessive',
11307 tag: 'Possessive',
11308 reason: 'place-possessive'
11309}, // assign all tasks
11310{
11311 match: '(#Verb && !#Modal) (all|every|each|most|some|no) [#PresentTense]',
11312 group: 0,
11313 tag: 'Noun',
11314 reason: 'all-presentTense'
11315}, //the above is clear
11316{
11317 match: '#Determiner [#Adjective] #Copula',
11318 group: 0,
11319 tag: 'Noun',
11320 reason: 'the-adj-is'
11321}, //real evil is
11322{
11323 match: '#Adjective [#Adjective] #Copula',
11324 group: 0,
11325 tag: 'Noun',
11326 reason: 'adj-adj-is'
11327}, // PresentTense/Noun ambiguities
11328// big dreams, critical thinking
11329// have big dreams
11330{
11331 match: '(had|have|#PastTense) #Adjective [#PresentTense]',
11332 group: 0,
11333 tag: 'Noun',
11334 reason: 'adj-presentTense'
11335}, // excellent answer spencer
11336{
11337 match: '^#Adjective [#PresentTense]',
11338 group: 0,
11339 tag: 'Noun',
11340 reason: 'start adj-presentTense'
11341}, // one big reason
11342{
11343 match: '#Value #Adjective [#PresentTense]',
11344 group: 0,
11345 tag: 'Noun',
11346 reason: 'one-big-reason'
11347}, // won widespread support
11348{
11349 match: '#PastTense #Adjective+ [#PresentTense]',
11350 group: 0,
11351 tag: 'Noun',
11352 reason: 'won-wide-support'
11353}, // many poses
11354{
11355 match: '(many|few|several|couple) [#PresentTense]',
11356 group: 0,
11357 tag: 'Noun',
11358 reason: 'many-poses'
11359}, // very big dreams
11360{
11361 match: '#Adverb #Adjective [#PresentTense]',
11362 group: 0,
11363 tag: 'Noun',
11364 reason: 'very-big-dream'
11365}, // good wait staff
11366{
11367 match: '#Adjective [#Infinitive] #Noun',
11368 group: 0,
11369 tag: 'Noun',
11370 reason: 'good-wait-staff'
11371}, // adorable little store
11372{
11373 match: '#Adjective #Adjective [#PresentTense]',
11374 group: 0,
11375 tag: 'Noun',
11376 reason: 'adorable-little-store'
11377}, // of basic training
11378{
11379 match: '#Preposition #Adjective [#PresentTense]',
11380 group: 0,
11381 tag: 'Noun',
11382 reason: 'of-basic-training'
11383}, // early warning
11384{
11385 match: '#Adjective [#Gerund]',
11386 group: 0,
11387 tag: 'Noun',
11388 reason: 'early-warning'
11389}, // justifiying higher costs
11390{
11391 match: '#Gerund #Adverb? #Comparative [#PresentTense]',
11392 group: 0,
11393 tag: 'Noun',
11394 reason: 'higher-costs'
11395}, // do the dance
11396{
11397 match: '#Infinitive (this|that|the) [#Infinitive]',
11398 group: 0,
11399 tag: 'Noun',
11400 reason: 'do-this-dance'
11401}, //his fine
11402{
11403 match: '(his|her|its) [#Adjective]',
11404 group: 0,
11405 tag: 'Noun',
11406 reason: 'his-fine'
11407}, //some pressing issues
11408{
11409 match: 'some [#Verb] #Plural',
11410 group: 0,
11411 tag: 'Noun',
11412 reason: 'determiner6'
11413}, //'more' is not always an adverb
11414{
11415 match: 'more #Noun',
11416 tag: 'Noun',
11417 reason: 'more-noun'
11418}, {
11419 match: '(#Noun && @hasComma) #Noun (and|or) [#PresentTense]',
11420 group: 0,
11421 tag: 'Noun',
11422 reason: 'noun-list'
11423}, //3 feet
11424{
11425 match: '(right|rights) of .',
11426 tag: 'Noun',
11427 reason: 'right-of'
11428}, // a bit
11429{
11430 match: 'a [bit]',
11431 group: 0,
11432 tag: 'Noun',
11433 reason: 'bit-2'
11434}, // my first thought
11435{
11436 match: '#Possessive #Ordinal [#PastTense]',
11437 group: 0,
11438 tag: 'Noun',
11439 reason: 'first-thought'
11440}, //running-a-show
11441{
11442 match: '#Gerund #Determiner [#Infinitive]',
11443 group: 0,
11444 tag: 'Noun',
11445 reason: 'running-a-show'
11446}, //the-only-reason
11447{
11448 match: '#Determiner #Adverb [#Infinitive]',
11449 group: 0,
11450 tag: 'Noun',
11451 reason: 'the-reason'
11452}, //the nice swim
11453{
11454 match: '(the|this|those|these) #Adjective [#Verb]',
11455 group: 0,
11456 tag: 'Noun',
11457 reason: 'the-adj-verb'
11458}, // the truly nice swim
11459{
11460 match: '(the|this|those|these) #Adverb #Adjective [#Verb]',
11461 group: 0,
11462 tag: 'Noun',
11463 reason: 'determiner4'
11464}, //the orange is
11465{
11466 match: '#Determiner [#Adjective] (#Copula|#PastTense|#Auxiliary)',
11467 group: 0,
11468 tag: 'Noun',
11469 reason: 'the-adj-2'
11470}, // a stream runs
11471{
11472 match: '(the|this|a|an) [#Infinitive] #Adverb? #Verb',
11473 group: 0,
11474 tag: 'Noun',
11475 reason: 'determiner5'
11476}, //the test string
11477{
11478 match: '#Determiner [#Infinitive] #Noun',
11479 group: 0,
11480 tag: 'Noun',
11481 reason: 'determiner7'
11482}, //a nice deal
11483{
11484 match: '#Determiner #Adjective #Adjective? [#Infinitive]',
11485 group: 0,
11486 tag: 'Noun',
11487 reason: 'a-nice-inf'
11488}, //the wait to vote
11489{
11490 match: 'the [#Verb] #Preposition .',
11491 group: 0,
11492 tag: 'Noun',
11493 reason: 'determiner1'
11494}, //a sense of
11495{
11496 match: '#Determiner [#Verb] of',
11497 group: 0,
11498 tag: 'Noun',
11499 reason: 'the-verb-of'
11500}, //next career move
11501{
11502 match: '#Adjective #Noun+ [#Infinitive] #Copula',
11503 group: 0,
11504 tag: 'Noun',
11505 reason: 'career-move'
11506}, //the threat of force
11507{
11508 match: '#Determiner #Noun of [#Verb]',
11509 group: 0,
11510 tag: 'Noun',
11511 reason: 'noun-of-noun'
11512}, //the western line
11513{
11514 match: '#Determiner [(western|eastern|northern|southern|central)] #Noun',
11515 group: 0,
11516 tag: 'Noun',
11517 reason: 'western-line'
11518}, //her polling
11519{
11520 match: '#Possessive [#Gerund]',
11521 group: 0,
11522 tag: 'Noun',
11523 reason: 'her-polling'
11524}, //her fines
11525{
11526 match: '(his|her|its) [#PresentTense]',
11527 group: 0,
11528 tag: 'Noun',
11529 reason: 'its-polling'
11530}, //linear algebra
11531{
11532 match: '(#Determiner|#Value) [(linear|binary|mobile|lexical|technical|computer|scientific|formal)] #Noun',
11533 group: 0,
11534 tag: 'Noun',
11535 reason: 'technical-noun'
11536}, // a blown motor
11537{
11538 match: '(the|those|these|a|an) [#Participle] #Noun',
11539 group: 0,
11540 tag: 'Adjective',
11541 reason: 'blown-motor'
11542}, // walk the walk
11543{
11544 match: '(the|those|these|a|an) #Adjective? [#Infinitive]',
11545 group: 0,
11546 tag: 'Noun',
11547 reason: 'det-inf'
11548}, {
11549 match: '(the|those|these|a|an) #Adjective? [#PresentTense]',
11550 group: 0,
11551 tag: 'Noun',
11552 reason: 'det-pres'
11553}, {
11554 match: '(the|those|these|a|an) #Adjective? [#PastTense]',
11555 group: 0,
11556 tag: 'Noun',
11557 reason: 'det-past'
11558}, // this swimming
11559{
11560 match: '(this|that) [#Gerund]',
11561 group: 0,
11562 tag: 'Noun',
11563 reason: 'this-gerund'
11564}, // at some point
11565{
11566 match: 'at some [#Infinitive]',
11567 group: 0,
11568 tag: 'Noun',
11569 reason: 'at-some-inf'
11570}, //air-flow
11571{
11572 match: '(#Noun && @hasHyphen) #Verb',
11573 tag: 'Noun',
11574 reason: 'hyphen-verb'
11575}, //is no walk
11576{
11577 match: 'is no [#Verb]',
11578 group: 0,
11579 tag: 'Noun',
11580 reason: 'is-no-verb'
11581}, //different views than
11582{
11583 match: '[#Verb] than',
11584 group: 0,
11585 tag: 'Noun',
11586 reason: 'correction'
11587}, // goes to sleep
11588{
11589 match: '(go|goes|went) to [#Infinitive]',
11590 group: 0,
11591 tag: 'Noun',
11592 reason: 'goes-to-verb'
11593}, //a great run
11594// { match: '(a|an) #Adjective [(#Infinitive|#PresentTense)]', tag: 'Noun', reason: 'a|an2' },
11595//a tv show
11596{
11597 match: '(a|an) #Noun [#Infinitive]',
11598 group: 0,
11599 tag: 'Noun',
11600 reason: 'a-noun-inf'
11601}, //do so
11602{
11603 match: 'do [so]',
11604 group: 0,
11605 tag: 'Noun',
11606 reason: 'so-noun'
11607}, //is mark hughes
11608{
11609 match: '#Copula [#Infinitive] #Noun',
11610 group: 0,
11611 tag: 'Noun',
11612 reason: 'is-pres-noun'
11613}, //
11614// { match: '[#Infinitive] #Copula', group: 0, tag: 'Noun', reason: 'inf-copula' },
11615//a close
11616{
11617 match: '#Determiner #Adverb? [close]',
11618 group: 0,
11619 tag: 'Adjective',
11620 reason: 'a-close'
11621}, // what the hell
11622{
11623 match: '#Determiner [(shit|damn|hell)]',
11624 group: 0,
11625 tag: 'Noun',
11626 reason: 'swears-noun'
11627}, // the staff were
11628{
11629 match: '(the|these) [#Singular] (were|are)',
11630 group: 0,
11631 tag: 'Plural',
11632 reason: 'singular-were'
11633}, // running for congress
11634{
11635 match: '#Gerund #Adjective? for [#Infinitive]',
11636 group: 0,
11637 tag: 'Noun',
11638 reason: 'running-for'
11639}, // running to work
11640{
11641 match: '#Gerund #Adjective to [#Infinitive]',
11642 group: 0,
11643 tag: 'Noun',
11644 reason: 'running-to'
11645}, // any questions for
11646{
11647 match: '(many|any|some|several) [#PresentTense] for',
11648 group: 0,
11649 tag: 'Noun',
11650 reason: 'any-verbs-for'
11651}, // have fun
11652{
11653 match: "(have|had) [#Adjective] #Preposition .",
11654 group: 0,
11655 tag: 'Noun',
11656 reason: 'have-fun'
11657}, // co-founder
11658{
11659 match: "co #Noun",
11660 tag: 'Actor',
11661 reason: 'co-noun'
11662}];
11663
11664var adjectives$2 = "(".concat(_ambig.adverbAdjective.join('|'), ")");
11665var _05Adverb = [//still good
11666{
11667 match: '[still] #Adjective',
11668 group: 0,
11669 tag: 'Adverb',
11670 reason: 'still-advb'
11671}, //still make
11672{
11673 match: '[still] #Verb',
11674 group: 0,
11675 tag: 'Adverb',
11676 reason: 'still-verb'
11677}, // so hot
11678{
11679 match: '[so] #Adjective',
11680 group: 0,
11681 tag: 'Adverb',
11682 reason: 'so-adv'
11683}, // way hotter
11684{
11685 match: '[way] #Comparative',
11686 group: 0,
11687 tag: 'Adverb',
11688 reason: 'way-adj'
11689}, // way too hot
11690{
11691 match: '[way] #Adverb #Adjective',
11692 group: 0,
11693 tag: 'Adverb',
11694 reason: 'way-too-adj'
11695}, // all singing
11696{
11697 match: '[all] #Verb',
11698 group: 0,
11699 tag: 'Adverb',
11700 reason: 'all-verb'
11701}, // sing like an angel
11702{
11703 match: '(#Verb && !#Modal) [like]',
11704 group: 0,
11705 tag: 'Adverb',
11706 reason: 'verb-like'
11707}, //barely even walk
11708{
11709 match: '(barely|hardly) even',
11710 tag: 'Adverb',
11711 reason: 'barely-even'
11712}, //even held
11713{
11714 match: '[even] #Verb',
11715 group: 0,
11716 tag: 'Adverb',
11717 reason: 'even-walk'
11718}, // even left
11719{
11720 match: 'even left',
11721 tag: '#Adverb #Verb',
11722 reason: 'even-left'
11723}, //cheering hard - dropped -ly's
11724{
11725 match: '#PresentTense [(hard|quick|long|bright|slow)]',
11726 group: 0,
11727 tag: 'Adverb',
11728 reason: 'lazy-ly'
11729}, // much appreciated
11730{
11731 match: '[much] #Adjective',
11732 group: 0,
11733 tag: 'Adverb',
11734 reason: 'bit-1'
11735}, // is well
11736{
11737 match: '#Copula [#Adverb]$',
11738 group: 0,
11739 tag: 'Adjective',
11740 reason: 'is-well'
11741}, // a bit cold
11742{
11743 match: 'a [(little|bit|wee) bit?] #Adjective',
11744 group: 0,
11745 tag: 'Adverb',
11746 reason: 'a-bit-cold'
11747}, // dark green
11748{
11749 match: "[".concat(adjectives$2, "] #Adjective"),
11750 group: 0,
11751 tag: 'Adverb',
11752 reason: 'dark-green'
11753}, // kinda sparkly
11754{
11755 match: "#Adverb [#Adverb]$",
11756 group: 0,
11757 tag: 'Adjective',
11758 reason: 'kinda-sparkly'
11759}, {
11760 match: "#Adverb [#Adverb] (and|or|then)",
11761 group: 0,
11762 tag: 'Adjective',
11763 reason: 'kinda-sparkly-and'
11764}];
11765
11766var _06Value = [// ==== PhoneNumber ====
11767//1 800 ...
11768{
11769 match: '1 #Value #PhoneNumber',
11770 tag: 'PhoneNumber',
11771 reason: '1-800-Value'
11772}, //(454) 232-9873
11773{
11774 match: '#NumericValue #PhoneNumber',
11775 tag: 'PhoneNumber',
11776 reason: '(800) PhoneNumber'
11777}, // ==== Currency ====
11778// chinese yuan
11779{
11780 match: '#Demonym #Currency',
11781 tag: 'Currency',
11782 reason: 'demonym-currency'
11783}, // ==== Ordinal ====
11784{
11785 match: '[second] #Noun',
11786 group: 0,
11787 tag: 'Ordinal',
11788 reason: 'second-noun'
11789}, // ==== Unit ====
11790//5 yan
11791{
11792 match: '#Value+ [#Currency]',
11793 group: 0,
11794 tag: 'Unit',
11795 reason: '5-yan'
11796}, {
11797 match: '#Value [(foot|feet)]',
11798 group: 0,
11799 tag: 'Unit',
11800 reason: 'foot-unit'
11801}, //minus 7
11802{
11803 match: '(minus|negative) #Value',
11804 tag: 'Value',
11805 reason: 'minus-value'
11806}, //5 kg.
11807{
11808 match: '#Value [#Abbreviation]',
11809 group: 0,
11810 tag: 'Unit',
11811 reason: 'value-abbr'
11812}, {
11813 match: '#Value [k]',
11814 group: 0,
11815 tag: 'Unit',
11816 reason: 'value-k'
11817}, {
11818 match: '#Unit an hour',
11819 tag: 'Unit',
11820 reason: 'unit-an-hour'
11821}, //seven point five
11822{
11823 match: '#Value (point|decimal) #Value',
11824 tag: 'Value',
11825 reason: 'value-point-value'
11826}, // ten bucks
11827{
11828 match: '(#Value|a) [(buck|bucks|grand)]',
11829 group: 0,
11830 tag: 'Currency',
11831 reason: 'value-bucks'
11832}, //quarter million
11833{
11834 match: '#Determiner [(half|quarter)] #Ordinal',
11835 group: 0,
11836 tag: 'Value',
11837 reason: 'half-ordinal'
11838}, {
11839 match: 'a #Value',
11840 tag: 'Value',
11841 reason: 'a-value'
11842}, // ==== Money ====
11843{
11844 match: '[#Value+] #Currency',
11845 group: 0,
11846 tag: 'Money',
11847 reason: '15 usd'
11848}, // thousand and two
11849{
11850 match: "(hundred|thousand|million|billion|trillion|quadrillion)+ and #Value",
11851 tag: 'Value',
11852 reason: 'magnitude-and-value'
11853}, //'a/an' can mean 1 - "a hour"
11854{
11855 match: '!once [(a|an)] (#Duration|hundred|thousand|million|billion|trillion)',
11856 group: 0,
11857 tag: 'Value',
11858 reason: 'a-is-one'
11859}];
11860
11861var verbs$1 = "(".concat(_ambig.personVerb.join('|'), ")");
11862var list$3 = [// adj -> gerund
11863// amusing his aunt
11864{
11865 match: '[#Adjective] #Possessive #Noun',
11866 group: 0,
11867 tag: 'Verb',
11868 reason: 'gerund-his-noun'
11869}, // loving you
11870{
11871 match: '[#Adjective] (us|you)',
11872 group: 0,
11873 tag: 'Gerund',
11874 reason: 'loving-you'
11875}, // slowly stunning
11876{
11877 match: '(slowly|quickly) [#Adjective]',
11878 group: 0,
11879 tag: 'Gerund',
11880 reason: 'slowly-adj'
11881}, // like
11882{
11883 match: '(#Modal|i|they|we|do) not? [like]',
11884 group: 0,
11885 tag: 'PresentTense',
11886 reason: 'modal-like'
11887}, // do not simply like
11888{
11889 match: 'do (simply|just|really|not)+ [(#Adjective|like)]',
11890 group: 0,
11891 tag: 'Verb',
11892 reason: 'do-simply-like'
11893}, // does mean
11894{
11895 match: 'does (#Adverb|not)? [#Adjective]',
11896 group: 0,
11897 tag: 'PresentTense',
11898 reason: 'does-mean'
11899}, // i mean
11900{
11901 match: 'i (#Adverb|do)? not? [mean]',
11902 group: 0,
11903 tag: 'PresentTense',
11904 reason: 'i-mean'
11905}, // { match: '!are (i|you|we) (#Adverb|do)? [#Adjective]', group: 0, tag: 'PresentTense', reason: 'i-mean' },
11906// ==== Tense ====
11907//he left
11908{
11909 match: '#Noun #Adverb? [left]',
11910 group: 0,
11911 tag: 'PastTense',
11912 reason: 'left-verb'
11913}, //this rocks
11914{
11915 match: '(this|that) [#Plural]',
11916 group: 0,
11917 tag: 'PresentTense',
11918 reason: 'this-verbs'
11919}, // ==== Auxiliary ====
11920//was walking
11921{
11922 match: "[#Copula (#Adverb|not)+?] (#Gerund|#PastTense)",
11923 group: 0,
11924 tag: 'Auxiliary',
11925 reason: 'copula-walking'
11926}, //support a splattering of auxillaries before a verb
11927{
11928 match: "[(has|had) (#Adverb|not)+?] #PastTense",
11929 group: 0,
11930 tag: 'Auxiliary',
11931 reason: 'had-walked'
11932}, //would walk
11933{
11934 match: "[#Adverb+? (#Modal|did)+ (#Adverb|not)+?] #Verb",
11935 group: 0,
11936 tag: 'Auxiliary',
11937 reason: 'modal-verb'
11938}, //would have had
11939{
11940 match: "[#Modal (#Adverb|not)+? have (#Adverb|not)+? had (#Adverb|not)+?] #Verb",
11941 group: 0,
11942 tag: 'Auxiliary',
11943 reason: 'would-have'
11944}, //would be walking
11945// { match: `#Modal (#Adverb|not)+? be (#Adverb|not)+? #Verb`, group: 0, tag: 'Auxiliary', reason: 'would-be' },
11946//had been walking
11947// {
11948// match: `(#Modal|had|has) (#Adverb|not)+? been (#Adverb|not)+? #Verb`,
11949// group: 0,
11950// tag: 'Auxiliary',
11951// reason: 'had-been',
11952// },
11953//support a splattering of auxillaries before a verb
11954{
11955 match: "[(has|had) (#Adverb|not)+?] #PastTense",
11956 group: 0,
11957 tag: 'Auxiliary',
11958 reason: 'had-walked'
11959}, // will walk
11960{
11961 match: '[(do|does|will|have|had)] (not|#Adverb)? #Verb',
11962 group: 0,
11963 tag: 'Auxiliary',
11964 reason: 'have-had'
11965}, // about to go
11966{
11967 match: '[about to] #Adverb? #Verb',
11968 group: 0,
11969 tag: ['Auxiliary', 'Verb'],
11970 reason: 'about-to'
11971}, //would be walking
11972{
11973 match: "#Modal (#Adverb|not)+? be (#Adverb|not)+? #Verb",
11974 group: 0,
11975 tag: 'Auxiliary',
11976 reason: 'would-be'
11977}, //were being run
11978{
11979 match: "(were|was) being [#PresentTense]",
11980 group: 0,
11981 tag: 'PastTense',
11982 reason: 'was-being'
11983}, //have run
11984// { match: `have #PresentTense`, group: 0, tag: 'PastTense', reason: 'have-vb' },
11985//would have had
11986{
11987 match: "[#Modal (#Adverb|not)+? have (#Adverb|not)+? had (#Adverb|not)+?] #Verb",
11988 group: 0,
11989 tag: 'Auxiliary',
11990 reason: 'would-have'
11991}, //had been walking
11992{
11993 match: "(#Modal|had|has) (#Adverb|not)+? been (#Adverb|not)+? #Verb",
11994 group: 0,
11995 tag: 'Auxiliary',
11996 reason: 'had-been'
11997}, // was being driven
11998{
11999 match: '[(be|being|been)] #Participle',
12000 group: 0,
12001 tag: 'Auxiliary',
12002 reason: 'being-foo'
12003}, // ==== Phrasal ====
12004//'foo-up'
12005{
12006 match: '(#Verb && @hasHyphen) up',
12007 tag: 'PhrasalVerb',
12008 reason: 'foo-up'
12009}, {
12010 match: '(#Verb && @hasHyphen) off',
12011 tag: 'PhrasalVerb',
12012 reason: 'foo-off'
12013}, {
12014 match: '(#Verb && @hasHyphen) over',
12015 tag: 'PhrasalVerb',
12016 reason: 'foo-over'
12017}, {
12018 match: '(#Verb && @hasHyphen) out',
12019 tag: 'PhrasalVerb',
12020 reason: 'foo-out'
12021}, //fall over
12022{
12023 match: '#PhrasalVerb [#PhrasalVerb]',
12024 group: 0,
12025 tag: 'Particle',
12026 reason: 'phrasal-particle'
12027}, //back it up
12028{
12029 match: '#Verb (him|her|it|us|himself|herself|itself|everything|something) [(up|down)]',
12030 group: 0,
12031 tag: 'Adverb',
12032 reason: 'phrasal-pronoun-advb'
12033}, // ==== Copula ====
12034//will be running (not copula)
12035{
12036 match: '[will #Adverb? not? #Adverb? be] #Gerund',
12037 group: 0,
12038 tag: 'Copula',
12039 reason: 'will-be-copula'
12040}, //for more complex forms, just tag 'be'
12041{
12042 match: 'will #Adverb? not? #Adverb? [be] #Adjective',
12043 group: 0,
12044 tag: 'Copula',
12045 reason: 'be-copula'
12046}, // ==== Infinitive ====
12047//march to
12048{
12049 match: '[march] (up|down|back|to|toward)',
12050 group: 0,
12051 tag: 'Infinitive',
12052 reason: 'march-to'
12053}, //must march
12054{
12055 match: '#Modal [march]',
12056 group: 0,
12057 tag: 'Infinitive',
12058 reason: 'must-march'
12059}, //let him glue
12060{
12061 match: '(let|make|made) (him|her|it|#Person|#Place|#Organization)+ [#Singular] (a|an|the|it)',
12062 group: 0,
12063 tag: 'Infinitive',
12064 reason: 'let-him-glue'
12065}, //he quickly foo
12066// { match: '#Noun #Adverb [#Noun]', group: 0, tag: 'Verb', reason: 'quickly-foo' },
12067//will secure our
12068{
12069 match: 'will [#Adjective]',
12070 group: 0,
12071 tag: 'Verb',
12072 reason: 'will-adj'
12073}, //he disguised the thing
12074{
12075 match: '#Pronoun [#Adjective] #Determiner #Adjective? #Noun',
12076 group: 0,
12077 tag: 'Verb',
12078 reason: 'he-adj-the'
12079}, //is eager to go
12080{
12081 match: '#Copula [#Adjective to] #Verb',
12082 group: 0,
12083 tag: 'Verb',
12084 reason: 'adj-to'
12085}, // open the door
12086{
12087 match: '[open] #Determiner',
12088 group: 0,
12089 tag: 'Infinitive',
12090 reason: 'open-the'
12091}, // compromises are possible
12092{
12093 match: '[#PresentTense] (are|were|was) #Adjective',
12094 group: 0,
12095 tag: 'Plural',
12096 reason: 'compromises-are-possible'
12097}, // would wade
12098{
12099 match: "#Modal [".concat(verbs$1, "]"),
12100 group: 0,
12101 tag: 'Verb',
12102 reason: 'would-mark'
12103}, {
12104 match: "#Adverb [".concat(verbs$1, "]"),
12105 group: 0,
12106 tag: 'Verb',
12107 reason: 'really-mark'
12108}, //to mark
12109{
12110 match: '(to|#Modal) [mark]',
12111 group: 0,
12112 tag: 'PresentTense',
12113 reason: 'to-mark'
12114}, // wade smith
12115{
12116 match: "".concat(verbs$1, " #Person"),
12117 tag: 'Person',
12118 reason: 'rob-smith'
12119}, // wade m. Cooper
12120{
12121 match: "".concat(verbs$1, " #Acronym #ProperNoun"),
12122 tag: 'Person',
12123 reason: 'rob-a-smith'
12124}, // damn them
12125{
12126 match: '[shit] (#Determiner|#Possessive|them)',
12127 group: 0,
12128 tag: 'Verb',
12129 reason: 'swear1-verb'
12130}, {
12131 match: '[damn] (#Determiner|#Possessive|them)',
12132 group: 0,
12133 tag: 'Verb',
12134 reason: 'swear2-verb'
12135}, {
12136 match: '[fuck] (#Determiner|#Possessive|them)',
12137 group: 0,
12138 tag: 'Verb',
12139 reason: 'swear3-verb'
12140}];
12141var _07Verbs = list$3;
12142
12143var list$4 = [// ==== Region ====
12144//West Norforlk
12145{
12146 match: '(west|north|south|east|western|northern|southern|eastern)+ #Place',
12147 tag: 'Region',
12148 reason: 'west-norfolk'
12149}, //some us-state acronyms (exlude: al, in, la, mo, hi, me, md, ok..)
12150{
12151 match: '#City [(al|ak|az|ar|ca|ct|dc|fl|ga|id|il|nv|nh|nj|ny|oh|or|pa|sc|tn|tx|ut|vt|pr)]',
12152 group: 0,
12153 tag: 'Region',
12154 reason: 'us-state'
12155}, //Foo District
12156{
12157 match: '#ProperNoun+ (district|region|province|county|prefecture|municipality|territory|burough|reservation)',
12158 tag: 'Region',
12159 reason: 'foo-district'
12160}, //District of Foo
12161{
12162 match: '(district|region|province|municipality|territory|burough|state) of #ProperNoun',
12163 tag: 'Region',
12164 reason: 'district-of-Foo'
12165}, // in Foo California
12166{
12167 match: 'in [#ProperNoun] #Place',
12168 group: 0,
12169 tag: 'Place',
12170 reason: 'propernoun-place'
12171}, // ==== Address ====
12172{
12173 match: '#Value #Noun (st|street|rd|road|crescent|cr|way|tr|terrace|avenue|ave)',
12174 tag: 'Address',
12175 reason: 'address-st'
12176} // in houston
12177// { match: `in [${places}]`, group: 0, tag: 'Place', reason: 'in-paris' },
12178// { match: `near [${places}]`, group: 0, tag: 'Place', reason: 'near-paris' },
12179// { match: `at [${places}]`, group: 0, tag: 'Place', reason: 'at-paris' },
12180// { match: `from [${places}]`, group: 0, tag: 'Place', reason: 'from-paris' },
12181// { match: `to [${places}]`, group: 0, tag: 'Place', reason: 'to-paris' },
12182// { match: `#Place [${places}]`, group: 0, tag: 'Place', reason: 'tokyo-paris' },
12183// // houston texas
12184// { match: `[${places}] #Place`, group: 0, tag: 'Place', reason: 'paris-france' },
12185];
12186var _08Place = list$4;
12187
12188var _09Org = [//John & Joe's
12189{
12190 match: '#Noun (&|n) #Noun',
12191 tag: 'Organization',
12192 reason: 'Noun-&-Noun'
12193}, // teachers union of Ontario
12194{
12195 match: '#Organization of the? #ProperNoun',
12196 tag: 'Organization',
12197 reason: 'org-of-place',
12198 safe: true
12199}, //walmart USA
12200{
12201 match: '#Organization #Country',
12202 tag: 'Organization',
12203 reason: 'org-country'
12204}, //organization
12205{
12206 match: '#ProperNoun #Organization',
12207 tag: 'Organization',
12208 reason: 'titlecase-org'
12209}, //FitBit Inc
12210{
12211 match: '#ProperNoun (ltd|co|inc|dept|assn|bros)',
12212 tag: 'Organization',
12213 reason: 'org-abbrv'
12214}, // the OCED
12215{
12216 match: 'the [#Acronym]',
12217 group: 0,
12218 tag: 'Organization',
12219 reason: 'the-acronym',
12220 safe: true
12221}, // global trade union
12222{
12223 match: '(world|global|international|national|#Demonym) #Organization',
12224 tag: 'Organization',
12225 reason: 'global-org'
12226}, // schools
12227{
12228 match: '#Noun+ (public|private) school',
12229 tag: 'School',
12230 reason: 'noun-public-school'
12231}];
12232
12233var nouns$1 = "(".concat(_ambig.personNoun.join('|'), ")");
12234var months = "(".concat(_ambig.personMonth.join('|'), ")");
12235var places = "(".concat(_ambig.personPlace.join('|'), ")");
12236var list$5 = [// ==== Honorific ====
12237{
12238 match: '[(1st|2nd|first|second)] #Honorific',
12239 group: 0,
12240 tag: 'Honorific',
12241 reason: 'ordinal-honorific'
12242}, {
12243 match: '[(private|general|major|corporal|lord|lady|secretary|premier)] #Honorific? #Person',
12244 group: 0,
12245 tag: 'Honorific',
12246 reason: 'ambg-honorifics'
12247}, // ==== FirstNames ====
12248//is foo Smith
12249{
12250 match: '#Copula [(#Noun|#PresentTense)] #LastName',
12251 group: 0,
12252 tag: 'FirstName',
12253 reason: 'copula-noun-lastname'
12254}, //pope francis
12255{
12256 match: '(lady|queen|sister) #ProperNoun',
12257 tag: 'FemaleName',
12258 reason: 'lady-titlecase',
12259 safe: true
12260}, {
12261 match: '(king|pope|father) #ProperNoun',
12262 tag: 'MaleName',
12263 reason: 'pope-titlecase',
12264 safe: true
12265}, //ambiguous-but-common firstnames
12266{
12267 match: '[(will|may|april|june|said|rob|wade|ray|rusty|drew|miles|jack|chuck|randy|jan|pat|cliff|bill)] #LastName',
12268 group: 0,
12269 tag: 'FirstName',
12270 reason: 'maybe-lastname'
12271}, // ==== Nickname ====
12272// Dwayne 'the rock' Johnson
12273{
12274 match: '#FirstName [#Determiner #Noun] #LastName',
12275 group: 0,
12276 tag: 'NickName',
12277 reason: 'first-noun-last'
12278}, //my buddy
12279{
12280 match: '#Possessive [#FirstName]',
12281 group: 0,
12282 tag: 'Person',
12283 reason: 'possessive-name'
12284}, {
12285 match: '#ProperNoun (b|c|d|e|f|g|h|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z) #ProperNoun',
12286 tag: 'Person',
12287 reason: 'titlecase-acronym-titlecase',
12288 safe: true
12289}, //ludwig van beethovan
12290{
12291 match: '#Acronym #LastName',
12292 tag: 'Person',
12293 reason: 'acronym-latname',
12294 safe: true
12295}, //jk rowling
12296{
12297 match: '#Person (jr|sr|md)',
12298 tag: 'Person',
12299 reason: 'person-honorific'
12300}, //peter II
12301{
12302 match: '#Person #Person the? #RomanNumeral',
12303 tag: 'Person',
12304 reason: 'roman-numeral'
12305}, //'Professor Fink', 'General McCarthy'
12306{
12307 match: '#FirstName [/^[^aiurck]$/]',
12308 group: 0,
12309 tag: ['Acronym', 'Person'],
12310 reason: 'john-e'
12311}, //Doctor john smith jr
12312//general pearson
12313{
12314 match: '#Honorific #Person',
12315 tag: 'Person',
12316 reason: 'honorific-person'
12317}, //remove single 'mr'
12318{
12319 match: '#Honorific #Acronym',
12320 tag: 'Person',
12321 reason: 'Honorific-TitleCase'
12322}, //j.k Rowling
12323{
12324 match: '#Noun van der? #Noun',
12325 tag: 'Person',
12326 reason: 'van der noun',
12327 safe: true
12328}, //king of spain
12329{
12330 match: '(king|queen|prince|saint|lady) of #Noun',
12331 tag: 'Person',
12332 reason: 'king-of-noun',
12333 safe: true
12334}, //lady Florence
12335{
12336 match: '(prince|lady) #Place',
12337 tag: 'Person',
12338 reason: 'lady-place'
12339}, //saint Foo
12340{
12341 match: '(king|queen|prince|saint) #ProperNoun',
12342 tag: 'Person',
12343 reason: 'saint-foo'
12344}, //Foo U Ford
12345{
12346 match: '[#ProperNoun] #Person',
12347 group: 0,
12348 tag: 'Person',
12349 reason: 'proper-person',
12350 safe: true
12351}, // al sharpton
12352{
12353 match: 'al (#Person|#ProperNoun)',
12354 tag: 'Person',
12355 reason: 'al-borlen',
12356 safe: true
12357}, //ferdinand de almar
12358{
12359 match: '#FirstName de #Noun',
12360 tag: 'Person',
12361 reason: 'bill-de-noun'
12362}, //Osama bin Laden
12363{
12364 match: '#FirstName (bin|al) #Noun',
12365 tag: 'Person',
12366 reason: 'bill-al-noun'
12367}, //John L. Foo
12368{
12369 match: '#FirstName #Acronym #ProperNoun',
12370 tag: 'Person',
12371 reason: 'bill-acronym-title'
12372}, //Andrew Lloyd Webber
12373{
12374 match: '#FirstName #FirstName #ProperNoun',
12375 tag: 'Person',
12376 reason: 'bill-firstname-title'
12377}, //Mr Foo
12378{
12379 match: '#Honorific #FirstName? #ProperNoun',
12380 tag: 'Person',
12381 reason: 'dr-john-Title'
12382}, //peter the great
12383{
12384 match: '#FirstName the #Adjective',
12385 tag: 'Person',
12386 reason: 'name-the-great'
12387}, //very common-but-ambiguous lastnames
12388{
12389 match: '#FirstName (green|white|brown|hall|young|king|hill|cook|gray|price)',
12390 tag: 'Person',
12391 reason: 'bill-green'
12392}, // faith smith
12393{
12394 match: "".concat(nouns$1, " #Person"),
12395 tag: 'Person',
12396 reason: 'ray-smith',
12397 safe: true
12398}, // faith m. Smith
12399{
12400 match: "".concat(nouns$1, " #Acronym? #ProperNoun"),
12401 tag: 'Person',
12402 reason: 'ray-a-smith',
12403 safe: true
12404}, //give to april
12405{
12406 match: "#Infinitive #Determiner? #Adjective? #Noun? (to|for) [".concat(months, "]"),
12407 group: 0,
12408 tag: 'Person',
12409 reason: 'ambig-person'
12410}, // remind june
12411{
12412 match: "#Infinitive [".concat(months, "]"),
12413 group: 0,
12414 tag: 'Person',
12415 reason: 'infinitive-person'
12416}, // may waits for
12417// { match: `[${months}] #PresentTense for`, group: 0, tag: 'Person', reason: 'ambig-active-for' },
12418// may waits to
12419// { match: `[${months}] #PresentTense to`, group: 0, tag: 'Person', reason: 'ambig-active-to' },
12420// april will
12421{
12422 match: "[".concat(months, "] #Modal"),
12423 group: 0,
12424 tag: 'Person',
12425 reason: 'ambig-modal'
12426}, // may be
12427{
12428 match: "[may] be",
12429 group: 0,
12430 tag: 'Verb',
12431 reason: 'may-be'
12432}, // would april
12433{
12434 match: "#Modal [".concat(months, "]"),
12435 group: 0,
12436 tag: 'Person',
12437 reason: 'modal-ambig'
12438}, // it is may
12439{
12440 match: "#Copula [".concat(months, "]"),
12441 group: 0,
12442 tag: 'Person',
12443 reason: 'is-may'
12444}, // may is
12445{
12446 match: "[".concat(months, "] #Copula"),
12447 group: 0,
12448 tag: 'Person',
12449 reason: 'may-is'
12450}, // with april
12451{
12452 match: "that [".concat(months, "]"),
12453 group: 0,
12454 tag: 'Person',
12455 reason: 'that-month'
12456}, // with april
12457{
12458 match: "with [".concat(months, "]"),
12459 group: 0,
12460 tag: 'Person',
12461 reason: 'with-month'
12462}, // for april
12463{
12464 match: "for [".concat(months, "]"),
12465 group: 0,
12466 tag: 'Person',
12467 reason: 'for-month'
12468}, // this april
12469{
12470 match: "this [".concat(months, "]"),
12471 group: 0,
12472 tag: 'Month',
12473 reason: 'this-may'
12474}, //maybe not 'this'
12475// next april
12476{
12477 match: "next [".concat(months, "]"),
12478 group: 0,
12479 tag: 'Month',
12480 reason: 'next-may'
12481}, // last april
12482{
12483 match: "last [".concat(months, "]"),
12484 group: 0,
12485 tag: 'Month',
12486 reason: 'last-may'
12487}, // wednesday april
12488{
12489 match: "#Date [".concat(months, "]"),
12490 group: 0,
12491 tag: 'Month',
12492 reason: 'date-may'
12493}, // may 5th
12494{
12495 match: "[".concat(months, "] the? #Value"),
12496 group: 0,
12497 tag: 'Month',
12498 reason: 'may-5th'
12499}, // 5th of may
12500{
12501 match: "#Value of [".concat(months, "]"),
12502 group: 0,
12503 tag: 'Month',
12504 reason: '5th-of-may'
12505}, // dick van dyke
12506{
12507 match: '#ProperNoun (van|al|bin) #ProperNoun',
12508 tag: 'Person',
12509 reason: 'title-van-title',
12510 safe: true
12511}, //jose de Sucre
12512{
12513 match: '#ProperNoun (de|du) la? #ProperNoun',
12514 tag: 'Person',
12515 reason: 'title-de-title',
12516 safe: true
12517}, //Jani K. Smith
12518{
12519 match: '#Singular #Acronym #LastName',
12520 tag: '#Person',
12521 reason: 'title-acro-noun',
12522 safe: true
12523}, //John Foo
12524{
12525 match: '#FirstName (#Noun && #ProperNoun) #ProperNoun?',
12526 tag: 'Person',
12527 reason: 'firstname-titlecase'
12528}, //Joe K. Sombrero
12529{
12530 match: '#FirstName #Acronym #Noun',
12531 tag: 'Person',
12532 reason: 'n-acro-noun',
12533 safe: true
12534}, //Anthony de Marco
12535{
12536 match: '#FirstName [(de|di|du|van|von) #Person]',
12537 group: 0,
12538 tag: 'LastName',
12539 reason: 'de-firstname'
12540}, // Paris Berelc
12541{
12542 match: "[".concat(places, "] (#ProperNoun && !#Place)"),
12543 group: 0,
12544 tag: 'FirstName',
12545 reason: 'place-firstname'
12546}];
12547var _10People = list$5;
12548
12549var matches = [];
12550matches = matches.concat(_01Misc);
12551matches = matches.concat(_02Dates);
12552matches = matches.concat(_03Adjective);
12553matches = matches.concat(_04Noun);
12554matches = matches.concat(_05Adverb);
12555matches = matches.concat(_06Value);
12556matches = matches.concat(_07Verbs);
12557matches = matches.concat(_08Place);
12558matches = matches.concat(_09Org);
12559matches = matches.concat(_10People); // cache the easier conditions up-front
12560
12561var cacheRequired$1 = function cacheRequired(reg) {
12562 var needTags = [];
12563 var needWords = [];
12564 reg.forEach(function (obj) {
12565 if (obj.optional === true || obj.negative === true) {
12566 return;
12567 }
12568
12569 if (obj.tag !== undefined) {
12570 needTags.push(obj.tag);
12571 }
12572
12573 if (obj.word !== undefined) {
12574 needWords.push(obj.word);
12575 }
12576 });
12577 return {
12578 tags: _unique(needTags),
12579 words: _unique(needWords)
12580 };
12581}; // for speed, enumerate (a|b|c) to three matches
12582
12583
12584var allLists = function allLists(m) {
12585 var more = [];
12586 var lists = m.reg.filter(function (r) {
12587 return r.fastOr !== undefined;
12588 });
12589
12590 if (lists.length === 1) {
12591 var i = m.reg.findIndex(function (r) {
12592 return r.fastOr !== undefined;
12593 });
12594 Object.keys(m.reg[i].fastOr).forEach(function (w) {
12595 var newM = Object.assign({}, m);
12596 newM.reg = newM.reg.slice(0);
12597 newM.reg[i] = Object.assign({}, newM.reg[i]);
12598 newM.reg[i].word = w;
12599 delete newM.reg[i].operator;
12600 delete newM.reg[i].fastOr; // newM.reason += '-' + w
12601
12602 more.push(newM);
12603 });
12604 }
12605
12606 return more;
12607}; // parse them
12608
12609
12610var all = [];
12611matches.forEach(function (m) {
12612 m.reg = matchSyntax(m.match);
12613 var enumerated = allLists(m);
12614
12615 if (enumerated.length > 0) {
12616 all = all.concat(enumerated);
12617 } else {
12618 all.push(m); // console.log(m)
12619 }
12620});
12621all.forEach(function (m) {
12622 m.required = cacheRequired$1(m.reg);
12623 return m;
12624}); // console.log(all.length)
12625// console.log(all[all.length - 1])
12626
12627var matches_1 = all;
12628
12629var hasEvery = function hasEvery(chances) {
12630 if (chances.length === 0) {
12631 return [];
12632 }
12633
12634 var obj = {};
12635 chances.forEach(function (arr) {
12636 arr = _unique(arr);
12637
12638 for (var i = 0; i < arr.length; i++) {
12639 obj[arr[i]] = obj[arr[i]] || 0;
12640 obj[arr[i]] += 1;
12641 }
12642 });
12643 var res = Object.keys(obj);
12644 res = res.filter(function (k) {
12645 return obj[k] === chances.length;
12646 });
12647 res = res.map(function (num) {
12648 return Number(num);
12649 });
12650 return res;
12651};
12652
12653var runner = function runner(doc) {
12654 //find phrases to try for each match
12655 matches_1.forEach(function (m) {
12656 var allChances = [];
12657 m.required.words.forEach(function (w) {
12658 allChances.push(doc._cache.words[w] || []);
12659 });
12660 m.required.tags.forEach(function (tag) {
12661 allChances.push(doc._cache.tags[tag] || []);
12662 });
12663 var worthIt = hasEvery(allChances);
12664
12665 if (worthIt.length === 0) {
12666 return;
12667 }
12668
12669 var phrases = worthIt.map(function (index) {
12670 return doc.list[index];
12671 });
12672 var tryDoc = doc.buildFrom(phrases); // phrases getting tagged
12673
12674 var match = tryDoc.match(m.reg, m.group);
12675
12676 if (match.found) {
12677 if (m.safe === true) {
12678 match.tagSafe(m.tag, m.reason);
12679 } else {
12680 match.tag(m.tag, m.reason);
12681 }
12682 }
12683 });
12684};
12685
12686var runner_1 = runner; // console.log(hasEvery([[1, 2, 2, 3], [2, 3], []]))
12687
12688// misc: 40ms
12689//sequence of match-tag statements to correct mis-tags
12690
12691var corrections = function corrections(doc) {
12692 runner_1(doc);
12693 fixMisc(doc);
12694 return doc;
12695};
12696
12697var _04Correction = corrections;
12698
12699/** POS-tag all terms in this document */
12700
12701var tagger = function tagger(doc) {
12702 var terms = doc.termList(); // check against any known-words
12703
12704 doc = _01Init(doc, terms); // everything has gotta be something. ¯\_(:/)_/¯
12705
12706 doc = _02Fallbacks(doc, terms); // support "didn't" & "spencer's"
12707
12708 doc = _03Contractions(doc); //set our cache, to speed things up
12709
12710 doc.cache(); // wiggle-around the results, so they make more sense
12711
12712 doc = _04Correction(doc); // remove our cache, as it's invalidated now
12713
12714 doc.uncache(); // run any user-given tagger functions
12715
12716 doc.world.taggers.forEach(function (fn) {
12717 fn(doc);
12718 });
12719 return doc;
12720};
12721
12722var _02Tagger = tagger;
12723
12724var addMethod = function addMethod(Doc) {
12725 /** */
12726 var Abbreviations = /*#__PURE__*/function (_Doc) {
12727 _inherits(Abbreviations, _Doc);
12728
12729 var _super = _createSuper(Abbreviations);
12730
12731 function Abbreviations() {
12732 _classCallCheck(this, Abbreviations);
12733
12734 return _super.apply(this, arguments);
12735 }
12736
12737 _createClass(Abbreviations, [{
12738 key: "stripPeriods",
12739 value: function stripPeriods() {
12740 this.termList().forEach(function (t) {
12741 if (t.tags.Abbreviation === true && t.next) {
12742 t.post = t.post.replace(/^\./, '');
12743 }
12744
12745 var str = t.text.replace(/\./, '');
12746 t.set(str);
12747 });
12748 return this;
12749 }
12750 }, {
12751 key: "addPeriods",
12752 value: function addPeriods() {
12753 this.termList().forEach(function (t) {
12754 t.post = t.post.replace(/^\./, '');
12755 t.post = '.' + t.post;
12756 });
12757 return this;
12758 }
12759 }]);
12760
12761 return Abbreviations;
12762 }(Doc);
12763
12764 Abbreviations.prototype.unwrap = Abbreviations.prototype.stripPeriods;
12765
12766 Doc.prototype.abbreviations = function (n) {
12767 var match = this.match('#Abbreviation');
12768
12769 if (typeof n === 'number') {
12770 match = match.get(n);
12771 }
12772
12773 return new Abbreviations(match.list, this, this.world);
12774 };
12775
12776 return Doc;
12777};
12778
12779var Abbreviations = addMethod;
12780
12781var hasPeriod = /\./;
12782
12783var addMethod$1 = function addMethod(Doc) {
12784 /** */
12785 var Acronyms = /*#__PURE__*/function (_Doc) {
12786 _inherits(Acronyms, _Doc);
12787
12788 var _super = _createSuper(Acronyms);
12789
12790 function Acronyms() {
12791 _classCallCheck(this, Acronyms);
12792
12793 return _super.apply(this, arguments);
12794 }
12795
12796 _createClass(Acronyms, [{
12797 key: "stripPeriods",
12798 value: function stripPeriods() {
12799 this.termList().forEach(function (t) {
12800 var str = t.text.replace(/\./g, '');
12801 t.set(str);
12802 });
12803 return this;
12804 }
12805 }, {
12806 key: "addPeriods",
12807 value: function addPeriods() {
12808 this.termList().forEach(function (t) {
12809 var str = t.text.replace(/\./g, '');
12810 str = str.split('').join('.'); // don't add a end-period if there's a sentence-end one
12811
12812 if (hasPeriod.test(t.post) === false) {
12813 str += '.';
12814 }
12815
12816 t.set(str);
12817 });
12818 return this;
12819 }
12820 }]);
12821
12822 return Acronyms;
12823 }(Doc);
12824
12825 Acronyms.prototype.unwrap = Acronyms.prototype.stripPeriods;
12826 Acronyms.prototype.strip = Acronyms.prototype.stripPeriods;
12827
12828 Doc.prototype.acronyms = function (n) {
12829 var match = this.match('#Acronym');
12830
12831 if (typeof n === 'number') {
12832 match = match.get(n);
12833 }
12834
12835 return new Acronyms(match.list, this, this.world);
12836 };
12837
12838 return Doc;
12839};
12840
12841var Acronyms = addMethod$1;
12842
12843var addMethod$2 = function addMethod(Doc) {
12844 /** split into approximate sub-sentence phrases */
12845 Doc.prototype.clauses = function (n) {
12846 // an awkward way to disambiguate a comma use
12847 var commas = this["if"]('@hasComma').notIf('@hasComma @hasComma') //fun, cool...
12848 .notIf('@hasComma . .? (and|or) .') //cool, and fun
12849 .notIf('(#City && @hasComma) #Country') //'toronto, canada'
12850 .notIf('(#WeekDay && @hasComma) #Date') //'tuesday, march 2nd'
12851 .notIf('(#Date && @hasComma) #Year') //'july 6, 1992'
12852 .notIf('@hasComma (too|also)$') //at end of sentence
12853 .match('@hasComma');
12854 var found = this.splitAfter(commas);
12855 var quotes = found.quotations();
12856 found = found.splitOn(quotes);
12857 var parentheses = found.parentheses();
12858 found = found.splitOn(parentheses); // it is cool and it is ..
12859
12860 var conjunctions = found["if"]('#Copula #Adjective #Conjunction (#Pronoun|#Determiner) #Verb').match('#Conjunction');
12861 found = found.splitBefore(conjunctions); // if it is this then that
12862
12863 var condition = found["if"]('if .{2,9} then .').match('then');
12864 found = found.splitBefore(condition); // misc clause partitions
12865
12866 found = found.splitBefore('as well as .');
12867 found = found.splitBefore('such as .');
12868 found = found.splitBefore('in addition to .'); // semicolons, dashes
12869
12870 found = found.splitAfter('@hasSemicolon');
12871 found = found.splitAfter('@hasDash'); // passive voice verb - '.. which was robbed is empty'
12872 // let passive = found.match('#Noun (which|that) (was|is) #Adverb? #PastTense #Adverb?')
12873 // if (passive.found) {
12874 // found = found.splitAfter(passive)
12875 // }
12876 // //which the boy robbed
12877 // passive = found.match('#Noun (which|that) the? #Noun+ #Adverb? #PastTense #Adverb?')
12878 // if (passive.found) {
12879 // found = found.splitAfter(passive)
12880 // }
12881 // does there appear to have relative/subordinate clause still?
12882
12883 var tooLong = found.filter(function (d) {
12884 return d.wordCount() > 5 && d.match('#Verb+').length >= 2;
12885 });
12886
12887 if (tooLong.found) {
12888 var m = tooLong.splitAfter('#Noun .* #Verb .* #Noun+');
12889 found = found.splitOn(m.eq(0));
12890 }
12891
12892 if (typeof n === 'number') {
12893 found = found.get(n);
12894 }
12895
12896 return new Doc(found.list, this, this.world);
12897 };
12898
12899 return Doc;
12900};
12901
12902var Clauses = addMethod$2;
12903
12904var addMethod$3 = function addMethod(Doc) {
12905 /** */
12906 var Contractions = /*#__PURE__*/function (_Doc) {
12907 _inherits(Contractions, _Doc);
12908
12909 var _super = _createSuper(Contractions);
12910
12911 function Contractions(list, from, world) {
12912 var _this;
12913
12914 _classCallCheck(this, Contractions);
12915
12916 _this = _super.call(this, list, from, world);
12917 _this.contracted = null;
12918 return _this;
12919 }
12920 /** turn didn't into 'did not' */
12921
12922
12923 _createClass(Contractions, [{
12924 key: "expand",
12925 value: function expand() {
12926 this.list.forEach(function (p) {
12927 var terms = p.terms(); //change the case?
12928
12929 var isTitlecase = terms[0].isTitleCase();
12930 terms.forEach(function (t, i) {
12931 //use the implicit text
12932 t.set(t.implicit || t.text);
12933 t.implicit = undefined; //add whitespace
12934
12935 if (i < terms.length - 1 && t.post === '') {
12936 t.post += ' ';
12937 }
12938 }); //set titlecase
12939
12940 if (isTitlecase) {
12941 terms[0].toTitleCase();
12942 }
12943 });
12944 return this;
12945 }
12946 }]);
12947
12948 return Contractions;
12949 }(Doc); //find contractable, expanded-contractions
12950 // const findExpanded = r => {
12951 // let remain = r.not('#Contraction')
12952 // let m = remain.match('(#Noun|#QuestionWord) (#Copula|did|do|have|had|could|would|will)')
12953 // m.concat(remain.match('(they|we|you|i) have'))
12954 // m.concat(remain.match('i am'))
12955 // m.concat(remain.match('(#Copula|#Modal|do|does|have|has|can|will) not'))
12956 // return m
12957 // }
12958
12959
12960 Doc.prototype.contractions = function (n) {
12961 //find currently-contracted
12962 var found = this.match('@hasContraction+'); //(may want to split these up)
12963 //todo: split consecutive contractions
12964
12965 if (typeof n === 'number') {
12966 found = found.get(n);
12967 }
12968
12969 return new Contractions(found.list, this, this.world);
12970 }; //aliases
12971
12972
12973 Doc.prototype.expanded = Doc.prototype.isExpanded;
12974 Doc.prototype.contracted = Doc.prototype.isContracted;
12975 return Doc;
12976};
12977
12978var Contractions = addMethod$3;
12979
12980var addMethod$4 = function addMethod(Doc) {
12981 //pull it apart..
12982 var parse = function parse(doc) {
12983 var things = doc.splitAfter('@hasComma').splitOn('(and|or) not?').not('(and|or) not?');
12984 var beforeLast = doc.match('[.] (and|or)', 0);
12985 return {
12986 things: things,
12987 conjunction: doc.match('(and|or) not?'),
12988 beforeLast: beforeLast,
12989 hasOxford: beforeLast.has('@hasComma')
12990 };
12991 };
12992 /** cool, fun, and nice */
12993
12994
12995 var Lists = /*#__PURE__*/function (_Doc) {
12996 _inherits(Lists, _Doc);
12997
12998 var _super = _createSuper(Lists);
12999
13000 function Lists() {
13001 _classCallCheck(this, Lists);
13002
13003 return _super.apply(this, arguments);
13004 }
13005
13006 _createClass(Lists, [{
13007 key: "conjunctions",
13008
13009 /** coordinating conjunction */
13010 value: function conjunctions() {
13011 return this.match('(and|or)');
13012 }
13013 /** split-up by list object */
13014
13015 }, {
13016 key: "parts",
13017 value: function parts() {
13018 return this.splitAfter('@hasComma').splitOn('(and|or) not?');
13019 }
13020 /** remove the conjunction */
13021
13022 }, {
13023 key: "items",
13024 value: function items() {
13025 return parse(this).things;
13026 }
13027 /** add a new unit to the list */
13028
13029 }, {
13030 key: "add",
13031 value: function add(str) {
13032 this.forEach(function (p) {
13033 var beforeLast = parse(p).beforeLast;
13034 beforeLast.append(str); //add a comma to it
13035
13036 beforeLast.termList(0).addPunctuation(',');
13037 });
13038 return this;
13039 }
13040 /** remove any matching unit from the list */
13041
13042 }, {
13043 key: "remove",
13044 value: function remove(match) {
13045 return this.items()["if"](match).remove();
13046 }
13047 /** return only lists that use a serial comma */
13048
13049 }, {
13050 key: "hasOxfordComma",
13051 value: function hasOxfordComma() {
13052 return this.filter(function (doc) {
13053 return parse(doc).hasOxford;
13054 });
13055 }
13056 }, {
13057 key: "addOxfordComma",
13058 value: function addOxfordComma() {
13059 var items = this.items();
13060 var needsComma = items.eq(items.length - 2);
13061
13062 if (needsComma.found && needsComma.has('@hasComma') === false) {
13063 needsComma.post(', ');
13064 }
13065
13066 return this;
13067 }
13068 }, {
13069 key: "removeOxfordComma",
13070 value: function removeOxfordComma() {
13071 var items = this.items();
13072 var needsComma = items.eq(items.length - 2);
13073
13074 if (needsComma.found && needsComma.has('@hasComma') === true) {
13075 needsComma.post(' ');
13076 }
13077
13078 return this;
13079 }
13080 }]);
13081
13082 return Lists;
13083 }(Doc); // aliases
13084
13085
13086 Lists.prototype.things = Lists.prototype.items;
13087
13088 Doc.prototype.lists = function (n) {
13089 var m = this["if"]('@hasComma+ .? (and|or) not? .'); // person-list
13090
13091 var nounList = m.match('(#Noun|#Adjective|#Determiner|#Article)+ #Conjunction not? (#Article|#Determiner)? #Adjective? #Noun+')["if"]('#Noun');
13092 var adjList = m.match('(#Adjective|#Adverb)+ #Conjunction not? #Adverb? #Adjective+');
13093 var verbList = m.match('(#Verb|#Adverb)+ #Conjunction not? #Adverb? #Verb+');
13094 var result = nounList.concat(adjList);
13095 result = result.concat(verbList);
13096 result = result["if"]('@hasComma');
13097
13098 if (typeof n === 'number') {
13099 result = m.get(n);
13100 }
13101
13102 return new Lists(result.list, this, this.world);
13103 };
13104
13105 return Doc;
13106};
13107
13108var Lists = addMethod$4;
13109
13110var noPlural = '(#Pronoun|#Place|#Value|#Person|#Uncountable|#Month|#WeekDay|#Holiday|#Possessive)'; //certain words can't be plural, like 'peace'
13111
13112var hasPlural = function hasPlural(doc) {
13113 if (doc.has('#Plural') === true) {
13114 return true;
13115 } // these can't be plural
13116
13117
13118 if (doc.has(noPlural) === true) {
13119 return false;
13120 }
13121
13122 return true;
13123};
13124
13125var hasPlural_1 = hasPlural;
13126
13127var irregulars$5 = {
13128 hour: 'an',
13129 heir: 'an',
13130 heirloom: 'an',
13131 honest: 'an',
13132 honour: 'an',
13133 honor: 'an',
13134 uber: 'an' //german u
13135
13136}; //pronounced letters of acronyms that get a 'an'
13137
13138var an_acronyms = {
13139 a: true,
13140 e: true,
13141 f: true,
13142 h: true,
13143 i: true,
13144 l: true,
13145 m: true,
13146 n: true,
13147 o: true,
13148 r: true,
13149 s: true,
13150 x: true
13151}; //'a' regexes
13152
13153var a_regexs = [/^onc?e/i, //'wu' sound of 'o'
13154/^u[bcfhjkqrstn][aeiou]/i, // 'yu' sound for hard 'u'
13155/^eul/i];
13156
13157var makeArticle = function makeArticle(doc) {
13158 //no 'the john smith', but 'a london hotel'
13159 if (doc.has('#Person') || doc.has('#Place')) {
13160 return '';
13161 } //no a/an if it's plural
13162
13163
13164 if (doc.has('#Plural')) {
13165 return 'the';
13166 }
13167
13168 var str = doc.text('normal').trim(); //explicit irregular forms
13169
13170 if (irregulars$5.hasOwnProperty(str)) {
13171 return irregulars$5[str];
13172 } //spelled-out acronyms
13173
13174
13175 var firstLetter = str.substr(0, 1);
13176
13177 if (doc.has('^@isAcronym') && an_acronyms.hasOwnProperty(firstLetter)) {
13178 return 'an';
13179 } //'a' regexes
13180
13181
13182 for (var i = 0; i < a_regexs.length; i++) {
13183 if (a_regexs[i].test(str)) {
13184 return 'a';
13185 }
13186 } //basic vowel-startings
13187
13188
13189 if (/^[aeiou]/i.test(str)) {
13190 return 'an';
13191 }
13192
13193 return 'a';
13194};
13195
13196var getArticle = makeArticle;
13197
13198//similar to plural/singularize rules, but not the same
13199var isPlural$1 = [/(antenn|formul|nebul|vertebr|vit)ae$/i, /(octop|vir|radi|nucle|fung|cact|stimul)i$/i, /men$/i, /.tia$/i, /(m|l)ice$/i]; //similar to plural/singularize rules, but not the same
13200
13201var isSingular$1 = [/(ax|test)is$/i, /(octop|vir|radi|nucle|fung|cact|stimul)us$/i, /(octop|vir)i$/i, /(rl)f$/i, /(alias|status)$/i, /(bu)s$/i, /(al|ad|at|er|et|ed|ad)o$/i, /(ti)um$/i, /(ti)a$/i, /sis$/i, /(?:(^f)fe|(lr)f)$/i, /hive$/i, /(^aeiouy|qu)y$/i, /(x|ch|ss|sh|z)$/i, /(matr|vert|ind|cort)(ix|ex)$/i, /(m|l)ouse$/i, /(m|l)ice$/i, /(antenn|formul|nebul|vertebr|vit)a$/i, /.sis$/i, /^(?!talis|.*hu)(.*)man$/i];
13202var _rules$2 = {
13203 isSingular: isSingular$1,
13204 isPlural: isPlural$1
13205};
13206
13207var endS = /s$/; // double-check this term, if it is not plural, or singular.
13208// (this is a partial copy of ./tagger/fallbacks/plural)
13209// fallback plural if it ends in an 's'.
13210
13211var isPlural$2 = function isPlural(str) {
13212 // isSingular suffix rules
13213 if (_rules$2.isSingular.find(function (reg) {
13214 return reg.test(str);
13215 })) {
13216 return false;
13217 } // does it end in an s?
13218
13219
13220 if (endS.test(str) === true) {
13221 return true;
13222 } // is it a plural like 'fungi'?
13223
13224
13225 if (_rules$2.isPlural.find(function (reg) {
13226 return reg.test(str);
13227 })) {
13228 return true;
13229 }
13230
13231 return null;
13232};
13233
13234var isPlural_1$1 = isPlural$2;
13235
13236var exceptions = {
13237 he: 'his',
13238 she: 'hers',
13239 they: 'theirs',
13240 we: 'ours',
13241 i: 'mine',
13242 you: 'yours',
13243 her: 'hers',
13244 their: 'theirs',
13245 our: 'ours',
13246 my: 'mine',
13247 your: 'yours'
13248}; // turn "David" to "David's"
13249
13250var toPossessive = function toPossessive(doc) {
13251 var str = doc.text('text').trim(); // exceptions
13252
13253 if (exceptions.hasOwnProperty(str)) {
13254 doc.replaceWith(exceptions[str], true);
13255 doc.tag('Possessive', 'toPossessive');
13256 return;
13257 } // flanders'
13258
13259
13260 if (/s$/.test(str)) {
13261 str += "'";
13262 doc.replaceWith(str, true);
13263 doc.tag('Possessive', 'toPossessive');
13264 return;
13265 } //normal form:
13266
13267
13268 str += "'s";
13269 doc.replaceWith(str, true);
13270 doc.tag('Possessive', 'toPossessive');
13271 return;
13272};
13273
13274var toPossessive_1 = toPossessive;
13275
13276// .nouns() supports some noun-phrase-ish groupings
13277// pull these apart, if necessary
13278var parse$1 = function parse(doc) {
13279 var res = {
13280 main: doc
13281 }; //support 'mayor of chicago' as one noun-phrase
13282
13283 if (doc.has('#Noun (of|by|for) .')) {
13284 var m = doc.splitAfter('[#Noun+]', 0);
13285 res.main = m.eq(0);
13286 res.post = m.eq(1);
13287 }
13288
13289 return res;
13290};
13291
13292var parse_1 = parse$1;
13293
13294var methods$6 = {
13295 /** overload the original json with noun information */
13296 json: function json(options) {
13297 var n = null;
13298
13299 if (typeof options === 'number') {
13300 n = options;
13301 options = null;
13302 }
13303
13304 options = options || {
13305 text: true,
13306 normal: true,
13307 trim: true,
13308 terms: true
13309 };
13310 var res = [];
13311 this.forEach(function (doc) {
13312 var json = doc.json(options)[0];
13313 json.article = getArticle(doc);
13314 res.push(json);
13315 });
13316
13317 if (n !== null) {
13318 return res[n];
13319 }
13320
13321 return res;
13322 },
13323
13324 /** get all adjectives describing this noun*/
13325 adjectives: function adjectives() {
13326 var list = this.lookAhead('^(that|who|which)? (was|is|will)? be? #Adverb? #Adjective+');
13327 list = list.concat(this.lookBehind('#Adjective+ #Adverb?$'));
13328 list = list.match('#Adjective');
13329 return list.sort('index');
13330 },
13331 isPlural: function isPlural() {
13332 return this["if"]('#Plural'); //assume tagger has run?
13333 },
13334 hasPlural: function hasPlural() {
13335 return this.filter(function (d) {
13336 return hasPlural_1(d);
13337 });
13338 },
13339 toPlural: function toPlural(agree) {
13340 var _this = this;
13341
13342 var toPlural = this.world.transforms.toPlural;
13343 this.forEach(function (doc) {
13344 if (doc.has('#Plural') || hasPlural_1(doc) === false) {
13345 return;
13346 } // double-check it isn't an un-tagged plural
13347
13348
13349 var main = parse_1(doc).main;
13350 var str = main.text('reduced');
13351
13352 if (!main.has('#Singular') && isPlural_1$1(str) === true) {
13353 return;
13354 }
13355
13356 str = toPlural(str, _this.world);
13357 main.replace(str).tag('#Plural'); // 'an apple' -> 'apples'
13358
13359 if (agree) {
13360 var an = main.lookBefore('(an|a) #Adjective?$').not('#Adjective');
13361
13362 if (an.found === true) {
13363 an.remove();
13364 }
13365 }
13366 });
13367 return this;
13368 },
13369 toSingular: function toSingular(agree) {
13370 var _this2 = this;
13371
13372 var toSingular = this.world.transforms.toSingular;
13373 this.forEach(function (doc) {
13374 if (doc.has('^#Singular+$') || hasPlural_1(doc) === false) {
13375 return;
13376 } // double-check it isn't an un-tagged plural
13377
13378
13379 var main = parse_1(doc).main;
13380 var str = main.text('reduced');
13381
13382 if (!main.has('#Plural') && isPlural_1$1(str) !== true) {
13383 return;
13384 }
13385
13386 str = toSingular(str, _this2.world);
13387 main.replace(str).tag('#Singular'); // add an article
13388
13389 if (agree) {
13390 // 'apples' -> 'an apple'
13391 var start = doc;
13392 var adj = doc.lookBefore('#Adjective');
13393
13394 if (adj.found) {
13395 start = adj;
13396 }
13397
13398 var article = getArticle(start);
13399 start.insertBefore(article);
13400 }
13401 });
13402 return this;
13403 },
13404 toPossessive: function toPossessive() {
13405 this.forEach(function (d) {
13406 toPossessive_1(d);
13407 });
13408 return this;
13409 }
13410};
13411var methods_1 = methods$6;
13412
13413var addMethod$5 = function addMethod(Doc) {
13414 /** */
13415 var Nouns = /*#__PURE__*/function (_Doc) {
13416 _inherits(Nouns, _Doc);
13417
13418 var _super = _createSuper(Nouns);
13419
13420 function Nouns() {
13421 _classCallCheck(this, Nouns);
13422
13423 return _super.apply(this, arguments);
13424 }
13425
13426 return Nouns;
13427 }(Doc); // add-in our methods
13428
13429
13430 Object.assign(Nouns.prototype, methods_1);
13431
13432 Doc.prototype.nouns = function (n) {
13433 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
13434 // don't split 'paris, france'
13435 var keep = this.match('(#City && @hasComma) (#Region|#Country)'); // but split the other commas
13436
13437 var m = this.not(keep).splitAfter('@hasComma'); // combine them back together
13438
13439 m = m.concat(keep); // don't combine over scare-quotes
13440
13441 var quotes = m.quotations();
13442
13443 if (quotes.found) {
13444 m = m.splitOn(quotes.eq(0));
13445 }
13446
13447 m = m.match('#Noun+ (of|by)? the? #Noun+?'); //nouns that we don't want in these results, for weird reasons
13448
13449 if (opts.keep_anaphora !== true) {
13450 m = m.not('#Pronoun');
13451 m = m.not('(there|these)');
13452 m = m.not('(#Month|#WeekDay)'); //allow Durations, Holidays
13453 // //allow possessives like "spencer's", but not generic ones like,
13454
13455 m = m.not('(my|our|your|their|her|his)');
13456 }
13457
13458 m = m.not('(of|for|by|the)$');
13459
13460 if (typeof n === 'number') {
13461 m = m.get(n);
13462 }
13463
13464 return new Nouns(m.list, this, this.world);
13465 };
13466
13467 return Doc;
13468};
13469
13470var Nouns = addMethod$5;
13471
13472var open = /\(/;
13473var close = /\)/;
13474
13475var addMethod$6 = function addMethod(Doc) {
13476 /** anything between (these things) */
13477 var Parentheses = /*#__PURE__*/function (_Doc) {
13478 _inherits(Parentheses, _Doc);
13479
13480 var _super = _createSuper(Parentheses);
13481
13482 function Parentheses() {
13483 _classCallCheck(this, Parentheses);
13484
13485 return _super.apply(this, arguments);
13486 }
13487
13488 _createClass(Parentheses, [{
13489 key: "unwrap",
13490
13491 /** remove the parentheses characters */
13492 value: function unwrap() {
13493 this.list.forEach(function (p) {
13494 var first = p.terms(0);
13495 first.pre = first.pre.replace(open, '');
13496 var last = p.lastTerm();
13497 last.post = last.post.replace(close, '');
13498 });
13499 return this;
13500 }
13501 }]);
13502
13503 return Parentheses;
13504 }(Doc);
13505
13506 Doc.prototype.parentheses = function (n) {
13507 var list = [];
13508 this.list.forEach(function (p) {
13509 var terms = p.terms(); //look for opening brackets
13510
13511 for (var i = 0; i < terms.length; i += 1) {
13512 var t = terms[i];
13513
13514 if (open.test(t.pre)) {
13515 //look for the closing bracket..
13516 for (var o = i; o < terms.length; o += 1) {
13517 if (close.test(terms[o].post)) {
13518 var len = o - i + 1;
13519 list.push(p.buildFrom(t.id, len));
13520 i = o;
13521 break;
13522 }
13523 }
13524 }
13525 }
13526 }); //support nth result
13527
13528 if (typeof n === 'number') {
13529 if (list[n]) {
13530 list = [list[n]];
13531 } else {
13532 list = [];
13533 }
13534
13535 return new Parentheses(list, this, this.world);
13536 }
13537
13538 return new Parentheses(list, this, this.world);
13539 };
13540
13541 return Doc;
13542};
13543
13544var Parentheses = addMethod$6;
13545
13546var addMethod$7 = function addMethod(Doc) {
13547 /** */
13548 var Possessives = /*#__PURE__*/function (_Doc) {
13549 _inherits(Possessives, _Doc);
13550
13551 var _super = _createSuper(Possessives);
13552
13553 function Possessives(list, from, world) {
13554 var _this;
13555
13556 _classCallCheck(this, Possessives);
13557
13558 _this = _super.call(this, list, from, world);
13559 _this.contracted = null;
13560 return _this;
13561 }
13562 /** turn didn't into 'did not' */
13563
13564
13565 _createClass(Possessives, [{
13566 key: "strip",
13567 value: function strip() {
13568 this.list.forEach(function (p) {
13569 var terms = p.terms();
13570 terms.forEach(function (t) {
13571 var str = t.text.replace(/'s$/, '');
13572 t.set(str || t.text);
13573 });
13574 });
13575 return this;
13576 }
13577 }]);
13578
13579 return Possessives;
13580 }(Doc); //find contractable, expanded-contractions
13581 // const findExpanded = r => {
13582 // let remain = r.not('#Contraction')
13583 // let m = remain.match('(#Noun|#QuestionWord) (#Copula|did|do|have|had|could|would|will)')
13584 // m.concat(remain.match('(they|we|you|i) have'))
13585 // m.concat(remain.match('i am'))
13586 // m.concat(remain.match('(#Copula|#Modal|do|does|have|has|can|will) not'))
13587 // return m
13588 // }
13589
13590
13591 Doc.prototype.possessives = function (n) {
13592 //find currently-contracted
13593 var found = this.match('#Noun+? #Possessive'); //todo: split consecutive contractions
13594
13595 if (typeof n === 'number') {
13596 found = found.get(n);
13597 }
13598
13599 return new Possessives(found.list, this, this.world);
13600 };
13601
13602 return Doc;
13603};
13604
13605var Possessives = addMethod$7;
13606
13607var pairs = {
13608 "\"": "\"",
13609 // 'StraightDoubleQuotes'
13610 "\uFF02": "\uFF02",
13611 // 'StraightDoubleQuotesWide'
13612 "'": "'",
13613 // 'StraightSingleQuotes'
13614 "\u201C": "\u201D",
13615 // 'CommaDoubleQuotes'
13616 "\u2018": "\u2019",
13617 // 'CommaSingleQuotes'
13618 "\u201F": "\u201D",
13619 // 'CurlyDoubleQuotesReversed'
13620 "\u201B": "\u2019",
13621 // 'CurlySingleQuotesReversed'
13622 "\u201E": "\u201D",
13623 // 'LowCurlyDoubleQuotes'
13624 "\u2E42": "\u201D",
13625 // 'LowCurlyDoubleQuotesReversed'
13626 "\u201A": "\u2019",
13627 // 'LowCurlySingleQuotes'
13628 "\xAB": "\xBB",
13629 // 'AngleDoubleQuotes'
13630 "\u2039": "\u203A",
13631 // 'AngleSingleQuotes'
13632 // Prime 'non quotation'
13633 "\u2035": "\u2032",
13634 // 'PrimeSingleQuotes'
13635 "\u2036": "\u2033",
13636 // 'PrimeDoubleQuotes'
13637 "\u2037": "\u2034",
13638 // 'PrimeTripleQuotes'
13639 // Prime 'quotation' variation
13640 "\u301D": "\u301E",
13641 // 'PrimeDoubleQuotes'
13642 "`": "\xB4",
13643 // 'PrimeSingleQuotes'
13644 "\u301F": "\u301E" // 'LowPrimeDoubleQuotesReversed'
13645
13646};
13647var hasOpen = RegExp('(' + Object.keys(pairs).join('|') + ')');
13648
13649var addMethod$8 = function addMethod(Doc) {
13650 /** "these things" */
13651 var Quotations = /*#__PURE__*/function (_Doc) {
13652 _inherits(Quotations, _Doc);
13653
13654 var _super = _createSuper(Quotations);
13655
13656 function Quotations() {
13657 _classCallCheck(this, Quotations);
13658
13659 return _super.apply(this, arguments);
13660 }
13661
13662 _createClass(Quotations, [{
13663 key: "unwrap",
13664
13665 /** remove the quote characters */
13666 value: function unwrap() {
13667 return this;
13668 }
13669 }]);
13670
13671 return Quotations;
13672 }(Doc);
13673
13674 Doc.prototype.quotations = function (n) {
13675 var list = [];
13676 this.list.forEach(function (p) {
13677 var terms = p.terms(); //look for opening quotes
13678
13679 for (var i = 0; i < terms.length; i += 1) {
13680 var t = terms[i];
13681
13682 if (hasOpen.test(t.pre)) {
13683 var _char = (t.pre.match(hasOpen) || [])[0];
13684 var want = pairs[_char]; // if (!want) {
13685 // console.warn('missing quote char ' + char)
13686 // }
13687 //look for the closing bracket..
13688
13689 for (var o = i; o < terms.length; o += 1) {
13690 if (terms[o].post.indexOf(want) !== -1) {
13691 var len = o - i + 1;
13692 list.push(p.buildFrom(t.id, len));
13693 i = o;
13694 break;
13695 }
13696 }
13697 }
13698 }
13699 }); //support nth result
13700
13701 if (typeof n === 'number') {
13702 if (list[n]) {
13703 list = [list[n]];
13704 } else {
13705 list = [];
13706 }
13707
13708 return new Quotations(list, this, this.world);
13709 }
13710
13711 return new Quotations(list, this, this.world);
13712 }; // alias
13713
13714
13715 Doc.prototype.quotes = Doc.prototype.quotations;
13716 return Doc;
13717};
13718
13719var Quotations = addMethod$8;
13720
13721// walked => walk - turn a verb into it's root form
13722var toInfinitive$1 = function toInfinitive(parsed, world) {
13723 var verb = parsed.verb; // console.log(parsed)
13724 // verb.debug()
13725 //1. if it's already infinitive
13726
13727 var str = verb.text('reduced');
13728
13729 if (verb.has('#Infinitive')) {
13730 return str;
13731 } // 2. world transform does the heavy-lifting
13732
13733
13734 var tense = null;
13735
13736 if (verb.has('#PastTense')) {
13737 tense = 'PastTense';
13738 } else if (verb.has('#Gerund')) {
13739 tense = 'Gerund';
13740 } else if (verb.has('#PresentTense')) {
13741 tense = 'PresentTense';
13742 } else if (verb.has('#Participle')) {
13743 tense = 'Participle';
13744 } else if (verb.has('#Actor')) {
13745 tense = 'Actor';
13746 }
13747
13748 return world.transforms.toInfinitive(str, world, tense);
13749};
13750
13751var toInfinitive_1$1 = toInfinitive$1;
13752
13753// spencer walks -> singular
13754// we walk -> plural
13755// the most-recent noun-phrase, before this verb.
13756var findNoun = function findNoun(vb) {
13757 var noun = vb.lookBehind('#Noun+').last();
13758 return noun;
13759}; //sometimes you can tell if a verb is plural/singular, just by the verb
13760// i am / we were
13761// othertimes you need its subject 'we walk' vs 'i walk'
13762
13763
13764var isPlural$3 = function isPlural(parsed) {
13765 var vb = parsed.verb;
13766
13767 if (vb.has('(are|were|does)') || parsed.auxiliary.has('(are|were|does)')) {
13768 return true;
13769 }
13770
13771 if (vb.has('(is|am|do|was)') || parsed.auxiliary.has('(is|am|do|was)')) {
13772 return false;
13773 } //consider its prior noun
13774
13775
13776 var noun = findNoun(vb);
13777
13778 if (noun.has('(we|they|you)')) {
13779 return true;
13780 }
13781
13782 if (noun.has('#Plural')) {
13783 return true;
13784 }
13785
13786 if (noun.has('#Singular')) {
13787 return false;
13788 }
13789
13790 return null;
13791};
13792
13793var isPlural_1$2 = isPlural$3;
13794
13795// #Copula : is -> 'is not'
13796// #PastTense : walked -> did not walk
13797// #PresentTense : walks -> does not walk
13798// #Gerund : walking: -> not walking
13799// #Infinitive : walk -> do not walk
13800
13801var toNegative = function toNegative(parsed, world) {
13802 var vb = parsed.verb; // if it's already negative...
13803
13804 if (parsed.negative.found) {
13805 return;
13806 } // would walk -> would not walk
13807
13808
13809 if (parsed.auxiliary.found) {
13810 parsed.auxiliary.eq(0).append('not'); // 'would not have' ➔ 'would not have'
13811
13812 if (parsed.auxiliary.has('#Modal have not')) {
13813 parsed.auxiliary.replace('have not', 'not have');
13814 }
13815
13816 return;
13817 } // is walking -> is not walking
13818
13819
13820 if (vb.has('(#Copula|will|has|had|do)')) {
13821 vb.append('not');
13822 return;
13823 } // walked -> did not walk
13824
13825
13826 if (vb.has('#PastTense')) {
13827 var inf = toInfinitive_1$1(parsed, world);
13828 vb.replaceWith(inf, true);
13829 vb.prepend('did not');
13830 return;
13831 } // walks -> does not walk
13832
13833
13834 if (vb.has('#PresentTense')) {
13835 var _inf = toInfinitive_1$1(parsed, world);
13836
13837 vb.replaceWith(_inf, true);
13838
13839 if (isPlural_1$2(parsed)) {
13840 vb.prepend('do not');
13841 } else {
13842 vb.prepend('does not');
13843 }
13844
13845 return;
13846 } //walking -> not walking
13847
13848
13849 if (vb.has('#Gerund')) {
13850 var _inf2 = toInfinitive_1$1(parsed, world);
13851
13852 vb.replaceWith(_inf2, true);
13853 vb.prepend('not');
13854 return;
13855 } //fallback 1: walk -> does not walk
13856
13857
13858 if (isPlural_1$2(parsed)) {
13859 vb.prepend('does not');
13860 return;
13861 } //fallback 2: walk -> do not walk
13862
13863
13864 vb.prepend('do not');
13865 return;
13866};
13867
13868var toNegative_1 = toNegative;
13869
13870// who/what is doing this verb?
13871// get the prior verb most-likely doing this action
13872// (it can not-exist - 'close the door')
13873var getSubject = function getSubject(vb) {
13874 var behind = vb.lookBehind();
13875 var lastNoun = behind.nouns(null, {
13876 keep_anaphora: true
13877 }).last(); // support 'that' and 'this'
13878
13879 if (!lastNoun.found) {
13880 lastNoun = behind.match('(that|this|each)').last();
13881 lastNoun = lastNoun.tag('#Noun').nouns();
13882 }
13883
13884 return lastNoun;
13885};
13886
13887var getSubject_1 = getSubject;
13888
13889var parseVerb = function parseVerb(vb) {
13890 var parsed = {
13891 adverb: vb.match('#Adverb+'),
13892 // 'really'
13893 negative: vb.match('#Negative'),
13894 // 'not'
13895 auxiliary: vb.match('#Auxiliary+').not('(#Negative|#Adverb)'),
13896 // 'will' of 'will go'
13897 particle: vb.match('#Particle'),
13898 // 'up' of 'pull up'
13899 verb: vb.match('#Verb+').not('(#Adverb|#Negative|#Auxiliary|#Particle)'),
13900 original: vb,
13901 subject: getSubject_1(vb)
13902 }; // fallback, if no verb found
13903
13904 if (!parsed.verb.found) {
13905 // blank-everything
13906 Object.keys(parsed).forEach(function (k) {
13907 parsed[k] = parsed[k].not('.');
13908 }); // it's all the verb
13909
13910 parsed.verb = vb;
13911 return parsed;
13912 } //
13913
13914
13915 if (parsed.adverb && parsed.adverb.found) {
13916 var match = parsed.adverb.text('reduced') + '$';
13917
13918 if (vb.has(match)) {
13919 parsed.adverbAfter = true;
13920 }
13921 }
13922
13923 return parsed;
13924};
13925
13926var parse$2 = parseVerb;
13927
13928/** too many special cases for is/was/will be*/
13929
13930var toBe = function toBe(parsed) {
13931 var isI = false;
13932 var plural = isPlural_1$2(parsed);
13933 var isNegative = parsed.negative.found; //account for 'i is' -> 'i am' irregular
13934 // if (vb.parent && vb.parent.has('i #Adverb? #Copula')) {
13935 // isI = true;
13936 // }
13937 // 'i look', not 'i looks'
13938
13939 if (parsed.verb.lookBehind('(i|we) (#Adverb|#Verb)?$').found) {
13940 isI = true;
13941 }
13942
13943 var obj = {
13944 PastTense: 'was',
13945 PresentTense: 'is',
13946 FutureTense: 'will be',
13947 Infinitive: 'is',
13948 Gerund: 'being',
13949 Actor: '',
13950 PerfectTense: 'been',
13951 Pluperfect: 'been'
13952 }; //"i is" -> "i am"
13953
13954 if (isI === true) {
13955 obj.PresentTense = 'am';
13956 obj.Infinitive = 'am';
13957 }
13958
13959 if (plural) {
13960 obj.PastTense = 'were';
13961 obj.PresentTense = 'are';
13962 obj.Infinitive = 'are';
13963 }
13964
13965 if (isNegative) {
13966 obj.PastTense += ' not';
13967 obj.PresentTense += ' not';
13968 obj.FutureTense = 'will not be';
13969 obj.Infinitive += ' not';
13970 obj.PerfectTense = 'not ' + obj.PerfectTense;
13971 obj.Pluperfect = 'not ' + obj.Pluperfect;
13972 obj.Gerund = 'not ' + obj.Gerund;
13973 }
13974
13975 return obj;
13976};
13977
13978var toBe_1 = toBe;
13979
13980// 'may/could/should' -> 'may/could/should have'
13981var doModal = function doModal(parsed) {
13982 var str = parsed.verb.text();
13983 var res = {
13984 PastTense: str + ' have',
13985 PresentTense: str,
13986 FutureTense: str,
13987 Infinitive: str // Gerund: ,
13988 // Actor: '',
13989 // PerfectTense: '',
13990 // Pluperfect: '',
13991
13992 };
13993 return res;
13994};
13995
13996var doModal_1 = doModal;
13997
13998var conjugate$2 = function conjugate(parsed, world) {
13999 var verb = parsed.verb; //special handling of 'is', 'will be', etc.
14000
14001 if (verb.has('#Copula') || verb.out('normal') === 'be' && parsed.auxiliary.has('will')) {
14002 return toBe_1(parsed);
14003 } // special handling of 'are walking'
14004
14005
14006 if (parsed.auxiliary.has('are') && verb.has('#Gerund')) {
14007 var og = parsed.original.clone();
14008 var past = og.clone().replace('are', 'were');
14009 var fut = og.clone().replace('are', 'will be');
14010
14011 var _infinitive = toInfinitive_1$1(parsed, world);
14012
14013 var res = {
14014 PastTense: past.text(),
14015 PresentTense: og.text(),
14016 FutureTense: fut.text(),
14017 Infinitive: _infinitive
14018 };
14019 return res;
14020 } // special handling of 'he could.'
14021
14022
14023 if (verb.has('#Modal')) {
14024 return doModal_1(parsed);
14025 } // dont conjugate imperative form - 'close the door'
14026 // if (parsed.auxiliary.has('do')) {
14027 // let str = parsed.original.text()
14028 // let res = {
14029 // PastTense: str,
14030 // PresentTense: str,
14031 // FutureTense: str,
14032 // Infinitive: str,
14033 // }
14034 // return res
14035 // }
14036
14037
14038 var hasHyphen = parsed.verb.termList(0).hasHyphen();
14039 var infinitive = toInfinitive_1$1(parsed, world);
14040
14041 if (!infinitive) {
14042 return {};
14043 }
14044
14045 var forms = world.transforms.conjugate(infinitive, world);
14046 forms.Infinitive = infinitive; // add particle to phrasal verbs ('fall over')
14047
14048 if (parsed.particle.found) {
14049 var particle = parsed.particle.text();
14050 var space = hasHyphen === true ? '-' : ' ';
14051 Object.keys(forms).forEach(function (k) {
14052 return forms[k] += space + particle;
14053 });
14054 } //put the adverb at the end?
14055 // if (parsed.adverb.found) {
14056 // let adverb = parsed.adverb.text()
14057 // let space = hasHyphen === true ? '-' : ' '
14058 // if (parsed.adverbAfter === true) {
14059 // Object.keys(forms).forEach(k => (forms[k] += space + adverb))
14060 // } else {
14061 // Object.keys(forms).forEach(k => (forms[k] = adverb + space + forms[k]))
14062 // }
14063 // }
14064 //apply negative
14065
14066
14067 var isNegative = parsed.negative.found;
14068
14069 if (isNegative) {
14070 forms.PastTense = 'did not ' + forms.Infinitive;
14071 forms.PresentTense = 'does not ' + forms.Infinitive;
14072 forms.Gerund = 'not ' + forms.Gerund;
14073 } //future Tense is pretty straightforward
14074
14075
14076 if (!forms.FutureTense) {
14077 if (isNegative) {
14078 forms.FutureTense = 'will not ' + forms.Infinitive;
14079 } else {
14080 forms.FutureTense = 'will ' + forms.Infinitive;
14081 }
14082 }
14083
14084 if (isNegative) {
14085 forms.Infinitive = 'not ' + forms.Infinitive;
14086 }
14087
14088 return forms;
14089};
14090
14091var conjugate_1$1 = conjugate$2;
14092
14093// verb-phrases that are orders - 'close the door'
14094// these should not be conjugated
14095var isImperative = function isImperative(parsed) {
14096 // do the dishes
14097 if (parsed.auxiliary.has('do')) {
14098 return true;
14099 } // speak the truth
14100 // if (parsed.verb.has('^#Infinitive')) {
14101 // // 'i speak' is not imperative
14102 // if (parsed.subject.has('(i|we|you|they)')) {
14103 // return false
14104 // }
14105 // return true
14106 // }
14107
14108
14109 return false;
14110}; // // basically, don't conjugate it
14111// exports.toImperative = function (parsed) {
14112// let str = parsed.original.text()
14113// let res = {
14114// PastTense: str,
14115// PresentTense: str,
14116// FutureTense: str,
14117// Infinitive: str,
14118// }
14119// return res
14120// }
14121
14122
14123var imperative = {
14124 isImperative: isImperative
14125};
14126
14127// if something is 'modal-ish' we are forced to use past-participle
14128// ('i could drove' is wrong)
14129
14130var useParticiple = function useParticiple(parsed) {
14131 if (parsed.auxiliary.has('(could|should|would|may|can|must)')) {
14132 return true;
14133 }
14134
14135 if (parsed.auxiliary.has('am .+? being')) {
14136 return true;
14137 }
14138
14139 if (parsed.auxiliary.has('had .+? been')) {
14140 return true;
14141 }
14142
14143 return false;
14144}; // conjugate 'drive' ➔ 'have driven'
14145
14146
14147var toParticiple = function toParticiple(parsed, world) {
14148 //is it already a participle?
14149 if (parsed.auxiliary.has('(have|had)') && parsed.verb.has('#Participle')) {
14150 return;
14151 } // try to swap the main verb to its participle form
14152
14153
14154 var obj = conjugate_1$1(parsed, world);
14155 var str = obj.Participle || obj.PastTense;
14156
14157 if (str) {
14158 parsed.verb.replaceWith(str, false);
14159 } // 'am being driven' ➔ 'have been driven'
14160
14161
14162 if (parsed.auxiliary.has('am .+? being')) {
14163 parsed.auxiliary.remove('am');
14164 parsed.auxiliary.replace('being', 'have been');
14165 } // add a 'have'
14166
14167
14168 if (!parsed.auxiliary.has('have')) {
14169 parsed.auxiliary.append('have');
14170 } // tag it as a participle
14171
14172
14173 parsed.verb.tag('Participle', 'toParticiple'); // turn 'i can swim' to -> 'i could swim'
14174
14175 parsed.auxiliary.replace('can', 'could'); //'must be' ➔ 'must have been'
14176
14177 parsed.auxiliary.replace('be have', 'have been'); //'not have' ➔ 'have not'
14178
14179 parsed.auxiliary.replace('not have', 'have not'); // ensure all new words are tagged right
14180
14181 parsed.auxiliary.tag('Auxiliary');
14182};
14183
14184var participle = {
14185 useParticiple: useParticiple,
14186 toParticiple: toParticiple
14187};
14188
14189var isImperative$1 = imperative.isImperative;
14190var _toParticiple = participle.toParticiple,
14191 useParticiple$1 = participle.useParticiple; // remove any tense-information in auxiliary verbs
14192
14193var makeNeutral = function makeNeutral(parsed) {
14194 //remove tense-info from auxiliaries
14195 parsed.auxiliary.remove('(will|are|am|being)');
14196 parsed.auxiliary.remove('(did|does)');
14197 parsed.auxiliary.remove('(had|has|have)'); //our conjugation includes the 'not' and the phrasal-verb particle
14198
14199 parsed.particle.remove();
14200 parsed.negative.remove();
14201 return parsed;
14202};
14203
14204var methods$7 = {
14205 /** overload the original json with verb information */
14206 json: function json(options) {
14207 var _this = this;
14208
14209 var n = null;
14210
14211 if (typeof options === 'number') {
14212 n = options;
14213 options = null;
14214 }
14215
14216 options = options || {
14217 text: true,
14218 normal: true,
14219 trim: true,
14220 terms: true
14221 };
14222 var res = [];
14223 this.forEach(function (p) {
14224 var json = p.json(options)[0];
14225 var parsed = parse$2(p);
14226 json.parts = {};
14227 Object.keys(parsed).forEach(function (k) {
14228 if (parsed[k] && parsed[k].isA === 'Doc') {
14229 json.parts[k] = parsed[k].text('normal');
14230 } else {
14231 json.parts[k] = parsed[k];
14232 }
14233 });
14234 json.isNegative = p.has('#Negative');
14235 json.conjugations = conjugate_1$1(parsed, _this.world);
14236 res.push(json);
14237 });
14238
14239 if (n !== null) {
14240 return res[n];
14241 }
14242
14243 return res;
14244 },
14245
14246 /** grab the adverbs describing these verbs */
14247 adverbs: function adverbs() {
14248 var list = []; // look at internal adverbs
14249
14250 this.forEach(function (vb) {
14251 var advb = parse$2(vb).adverb;
14252
14253 if (advb.found) {
14254 list = list.concat(advb.list);
14255 }
14256 }); // look for leading adverbs
14257
14258 var m = this.lookBehind('#Adverb+$');
14259
14260 if (m.found) {
14261 list = m.list.concat(list);
14262 } // look for trailing adverbs
14263
14264
14265 m = this.lookAhead('^#Adverb+');
14266
14267 if (m.found) {
14268 list = list.concat(m.list);
14269 }
14270
14271 return this.buildFrom(list);
14272 },
14273 /// Verb Inflection
14274
14275 /**return verbs like 'we walk' and not 'spencer walks' */
14276 isPlural: function isPlural() {
14277 var _this2 = this;
14278
14279 var list = [];
14280 this.forEach(function (vb) {
14281 var parsed = parse$2(vb);
14282
14283 if (isPlural_1$2(parsed, _this2.world) === true) {
14284 list.push(vb.list[0]);
14285 }
14286 });
14287 return this.buildFrom(list);
14288 },
14289
14290 /** return verbs like 'spencer walks' and not 'we walk' */
14291 isSingular: function isSingular() {
14292 var _this3 = this;
14293
14294 var list = [];
14295 this.forEach(function (vb) {
14296 var parsed = parse$2(vb);
14297
14298 if (isPlural_1$2(parsed, _this3.world) === false) {
14299 list.push(vb.list[0]);
14300 }
14301 });
14302 return this.buildFrom(list);
14303 },
14304 /// Conjugation
14305
14306 /** return all forms of this verb */
14307 conjugate: function conjugate() {
14308 var _this4 = this;
14309
14310 var result = [];
14311 this.forEach(function (vb) {
14312 var parsed = parse$2(vb);
14313
14314 var forms = conjugate_1$1(parsed, _this4.world);
14315
14316 result.push(forms);
14317 });
14318 return result;
14319 },
14320
14321 /** walk ➔ walked*/
14322 toPastTense: function toPastTense() {
14323 var _this5 = this;
14324
14325 this.forEach(function (vb) {
14326 var parsed = parse$2(vb); // should we support 'would swim' ➔ 'would have swam'
14327
14328 if (useParticiple$1(parsed)) {
14329 _toParticiple(parsed, _this5.world);
14330
14331 return;
14332 }
14333
14334 if (isImperative$1(parsed)) {
14335 return;
14336 } // don't conjugate 'to be'
14337
14338
14339 if (vb.has('be') && vb.lookBehind('to$').found) {
14340 return;
14341 } // handle 'is raining' -> 'was raining'
14342
14343
14344 if (parsed.verb.has('#Gerund') && parsed.auxiliary.has('(is|will|was)')) {
14345 vb.replace('is', 'was');
14346 return;
14347 }
14348
14349 var str = conjugate_1$1(parsed, _this5.world).PastTense;
14350
14351 if (str) {
14352 parsed = makeNeutral(parsed);
14353 parsed.verb.replaceWith(str, false); // vb.tag('PastTense')
14354 }
14355 });
14356 return this;
14357 },
14358
14359 /** walk ➔ walks */
14360 toPresentTense: function toPresentTense() {
14361 var _this6 = this;
14362
14363 this.forEach(function (vb) {
14364 var parsed = parse$2(vb);
14365
14366 var obj = conjugate_1$1(parsed, _this6.world);
14367
14368 var str = obj.PresentTense; // 'i look', not 'i looks'
14369
14370 if (vb.lookBehind('(i|we) (#Adverb|#Verb)?$').found) {
14371 str = obj.Infinitive;
14372 }
14373
14374 if (str) {
14375 //awkward support for present-participle form
14376 // -- should we support 'have been swimming' ➔ 'am swimming'
14377 if (parsed.auxiliary.has('(have|had) been')) {
14378 parsed.auxiliary.replace('(have|had) been', 'am being');
14379
14380 if (obj.Particle) {
14381 str = obj.Particle || obj.PastTense;
14382 }
14383
14384 return;
14385 }
14386
14387 parsed.verb.replaceWith(str, false);
14388 parsed.verb.tag('PresentTense');
14389 parsed = makeNeutral(parsed); // avoid 'he would walks'
14390
14391 parsed.auxiliary.remove('#Modal');
14392 }
14393 });
14394 return this;
14395 },
14396
14397 /** walk ➔ will walk*/
14398 toFutureTense: function toFutureTense() {
14399 var _this7 = this;
14400
14401 this.forEach(function (vb) {
14402 var parsed = parse$2(vb); // 'i should drive' is already future-enough
14403
14404 if (useParticiple$1(parsed)) {
14405 return;
14406 }
14407
14408 var str = conjugate_1$1(parsed, _this7.world).FutureTense;
14409
14410 if (str) {
14411 parsed = makeNeutral(parsed); // avoid 'he would will go'
14412
14413 parsed.auxiliary.remove('#Modal');
14414 parsed.verb.replaceWith(str, false);
14415 parsed.verb.tag('FutureTense');
14416 }
14417 });
14418 return this;
14419 },
14420
14421 /** walks ➔ walk */
14422 toInfinitive: function toInfinitive() {
14423 var _this8 = this;
14424
14425 this.forEach(function (vb) {
14426 var parsed = parse$2(vb);
14427
14428 var str = conjugate_1$1(parsed, _this8.world).Infinitive;
14429
14430 if (str) {
14431 vb.replaceWith(str, false);
14432 vb.tag('Infinitive');
14433 }
14434 });
14435 return this;
14436 },
14437
14438 /** walk ➔ walking */
14439 toGerund: function toGerund() {
14440 var _this9 = this;
14441
14442 this.forEach(function (vb) {
14443 var parsed = parse$2(vb);
14444
14445 var str = conjugate_1$1(parsed, _this9.world).Gerund;
14446
14447 if (str) {
14448 vb.replaceWith(str, false);
14449 vb.tag('Gerund');
14450 }
14451 });
14452 return this;
14453 },
14454
14455 /** drive ➔ driven - naked past-participle if it exists, otherwise past-tense */
14456 toParticiple: function toParticiple() {
14457 var _this10 = this;
14458
14459 this.forEach(function (vb) {
14460 var parsed = parse$2(vb);
14461 var noAux = !parsed.auxiliary.found;
14462
14463 _toParticiple(parsed, _this10.world); // dirty trick to ensure our new auxiliary is found
14464
14465
14466 if (noAux) {
14467 parsed.verb.prepend(parsed.auxiliary.text());
14468 parsed.auxiliary.remove();
14469 }
14470 });
14471 return this;
14472 },
14473 /// Negation
14474
14475 /** return only verbs with 'not'*/
14476 isNegative: function isNegative() {
14477 return this["if"]('#Negative');
14478 },
14479
14480 /** return only verbs without 'not'*/
14481 isPositive: function isPositive() {
14482 return this.ifNo('#Negative');
14483 },
14484
14485 /** add a 'not' to these verbs */
14486 toNegative: function toNegative() {
14487 var _this11 = this;
14488
14489 this.list.forEach(function (p) {
14490 var doc = _this11.buildFrom([p]);
14491
14492 var parsed = parse$2(doc);
14493
14494 toNegative_1(parsed, doc.world);
14495 });
14496 return this;
14497 },
14498
14499 /** remove 'not' from these verbs */
14500 toPositive: function toPositive() {
14501 var m = this.match('do not #Verb');
14502
14503 if (m.found) {
14504 m.remove('do not');
14505 }
14506
14507 return this.remove('#Negative');
14508 },
14509
14510 /** who, or what is doing this action? */
14511 subject: function subject() {
14512 var list = [];
14513 this.forEach(function (p) {
14514 var found = getSubject_1(p);
14515
14516 if (found.list[0]) {
14517 list.push(found.list[0]);
14518 }
14519 });
14520 return this.buildFrom(list);
14521 }
14522};
14523
14524var addMethod$9 = function addMethod(Doc) {
14525 /** */
14526 var Verbs = /*#__PURE__*/function (_Doc) {
14527 _inherits(Verbs, _Doc);
14528
14529 var _super = _createSuper(Verbs);
14530
14531 function Verbs() {
14532 _classCallCheck(this, Verbs);
14533
14534 return _super.apply(this, arguments);
14535 }
14536
14537 return Verbs;
14538 }(Doc); // add-in our methods
14539
14540
14541 Object.assign(Verbs.prototype, methods$7); // aliases
14542
14543 Verbs.prototype.negate = Verbs.prototype.toNegative;
14544
14545 Doc.prototype.verbs = function (n) {
14546 var match = this.match('(#Adverb|#Auxiliary|#Verb|#Negative|#Particle)+'); // try to ignore leading and trailing adverbs
14547
14548 match = match.not('^#Adverb+');
14549 match = match.not('#Adverb+$'); // handle commas:
14550 // don't split 'really, really'
14551
14552 var keep = match.match('(#Adverb && @hasComma) #Adverb'); // // but split the other commas
14553
14554 var m = match.not(keep).splitAfter('@hasComma'); // i was shocked looking at...
14555
14556 var gerund = m.match('#PastTense #Gerund');
14557
14558 if (!gerund.has('(been|am|#Auxiliary) #Gerund')) {
14559 m = m.splitBefore(gerund.match('#Gerund'));
14560 } // combine them back together
14561
14562
14563 m = m.concat(keep);
14564 m.sort('index'); //handle slashes?
14565 //ensure there's actually a verb
14566
14567 m = m["if"]('#Verb'); // the reason he will is ...
14568
14569 if (m.has('(is|was)$')) {
14570 m = m.splitBefore('(is|was)$');
14571 } //ensure it's not two verbs
14572
14573
14574 if (m.has('#PresentTense #Adverb #PresentTense')) {
14575 m = m.splitBefore('#Adverb #PresentTense');
14576 } //grab (n)th result
14577
14578
14579 if (typeof n === 'number') {
14580 m = m.get(n);
14581 }
14582
14583 var vb = new Verbs(m.list, this, this.world);
14584 return vb;
14585 };
14586
14587 return Doc;
14588};
14589
14590var Verbs = addMethod$9;
14591
14592var addMethod$a = function addMethod(Doc) {
14593 /** */
14594 var People = /*#__PURE__*/function (_Doc) {
14595 _inherits(People, _Doc);
14596
14597 var _super = _createSuper(People);
14598
14599 function People() {
14600 _classCallCheck(this, People);
14601
14602 return _super.apply(this, arguments);
14603 }
14604
14605 return People;
14606 }(Doc);
14607
14608 Doc.prototype.people = function (n) {
14609 var match = this.splitAfter('@hasComma');
14610 match = match.match('#Person+'); //grab (n)th result
14611
14612 if (typeof n === 'number') {
14613 match = match.get(n);
14614 }
14615
14616 return new People(match.list, this, this.world);
14617 };
14618
14619 return Doc;
14620};
14621
14622var People = addMethod$a;
14623
14624var subclass = [Abbreviations, Acronyms, Clauses, Contractions, Lists, Nouns, Parentheses, Possessives, Quotations, Verbs, People];
14625
14626var extend = function extend(Doc) {
14627 // add basic methods
14628 Object.keys(_simple).forEach(function (k) {
14629 return Doc.prototype[k] = _simple[k];
14630 }); // add subclassed methods
14631
14632 subclass.forEach(function (addFn) {
14633 return addFn(Doc);
14634 });
14635 return Doc;
14636};
14637
14638var Subset = extend;
14639
14640var methods$8 = {
14641 misc: methods$4,
14642 selections: _simple
14643};
14644/** a parsed text object */
14645
14646var Doc = /*#__PURE__*/function () {
14647 function Doc(list, from, world) {
14648 var _this = this;
14649
14650 _classCallCheck(this, Doc);
14651
14652 this.list = list; // this.reasons = []
14653 //quiet these properties in console.logs
14654
14655 Object.defineProperty(this, 'from', {
14656 enumerable: false,
14657 value: from,
14658 writable: true
14659 }); //borrow some missing data from parent
14660
14661 if (world === undefined && from !== undefined) {
14662 world = from.world;
14663 } //'world' getter
14664
14665
14666 Object.defineProperty(this, 'world', {
14667 enumerable: false,
14668 value: world,
14669 writable: true
14670 }); //fast-scans for our data
14671
14672 Object.defineProperty(this, '_cache', {
14673 enumerable: false,
14674 writable: true,
14675 value: {}
14676 }); //'found' getter
14677
14678 Object.defineProperty(this, 'found', {
14679 get: function get() {
14680 return _this.list.length > 0;
14681 }
14682 }); //'length' getter
14683
14684 Object.defineProperty(this, 'length', {
14685 get: function get() {
14686 return _this.list.length;
14687 }
14688 }); // this is way easier than .constructor.name...
14689
14690 Object.defineProperty(this, 'isA', {
14691 get: function get() {
14692 return 'Doc';
14693 }
14694 });
14695 }
14696 /** run part-of-speech tagger on all results*/
14697
14698
14699 _createClass(Doc, [{
14700 key: "tagger",
14701 value: function tagger() {
14702 return _02Tagger(this);
14703 }
14704 /** pool is stored on phrase objects */
14705
14706 }, {
14707 key: "pool",
14708 value: function pool() {
14709 if (this.list.length > 0) {
14710 return this.list[0].pool;
14711 }
14712
14713 return this.all().list[0].pool;
14714 }
14715 }]);
14716
14717 return Doc;
14718}();
14719/** create a new Document object */
14720
14721
14722Doc.prototype.buildFrom = function (list) {
14723 list = list.map(function (p) {
14724 return p.clone(true);
14725 }); // new this.constructor()
14726
14727 var doc = new Doc(list, this, this.world);
14728 return doc;
14729};
14730/** create a new Document from plaintext. */
14731
14732
14733Doc.prototype.fromText = function (str) {
14734 var list = _01Tokenizer(str, this.world, this.pool());
14735 return this.buildFrom(list);
14736};
14737
14738Object.assign(Doc.prototype, methods$8.misc);
14739Object.assign(Doc.prototype, methods$8.selections); //add sub-classes
14740
14741Subset(Doc); //aliases
14742
14743var aliases$1 = {
14744 untag: 'unTag',
14745 and: 'match',
14746 notIf: 'ifNo',
14747 only: 'if',
14748 onlyIf: 'if'
14749};
14750Object.keys(aliases$1).forEach(function (k) {
14751 return Doc.prototype[k] = Doc.prototype[aliases$1[k]];
14752});
14753var Doc_1 = Doc;
14754
14755var smallTagger = function smallTagger(doc) {
14756 var terms = doc.termList();
14757 _01Lexicon(terms, doc.world); // run any user-given tagger functions
14758
14759 doc.world.taggers.forEach(function (fn) {
14760 fn(doc);
14761 });
14762 return doc;
14763};
14764
14765var tiny = smallTagger;
14766
14767function instance(worldInstance) {
14768 //blast-out our word-lists, just once
14769 var world = worldInstance;
14770 /** parse and tag text into a compromise object */
14771
14772 var nlp = function nlp() {
14773 var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
14774 var lexicon = arguments.length > 1 ? arguments[1] : undefined;
14775
14776 if (lexicon) {
14777 world.addWords(lexicon);
14778 }
14779
14780 var list = _01Tokenizer(text, world);
14781 var doc = new Doc_1(list, null, world);
14782 doc.tagger();
14783 return doc;
14784 };
14785 /** parse text into a compromise object, without running POS-tagging */
14786
14787
14788 nlp.tokenize = function () {
14789 var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
14790 var lexicon = arguments.length > 1 ? arguments[1] : undefined;
14791 var w = world;
14792
14793 if (lexicon) {
14794 w = w.clone();
14795 w.words = {};
14796 w.addWords(lexicon);
14797 }
14798
14799 var list = _01Tokenizer(text, w);
14800 var doc = new Doc_1(list, null, w);
14801
14802 if (lexicon || doc.world.taggers.length > 0) {
14803 tiny(doc);
14804 }
14805
14806 return doc;
14807 };
14808 /** mix in a compromise-plugin */
14809
14810
14811 nlp.extend = function (fn) {
14812 fn(Doc_1, world, this, Phrase_1, Term_1, Pool_1);
14813 return this;
14814 };
14815 /** create a compromise Doc object from .json() results */
14816
14817
14818 nlp.fromJSON = function (json) {
14819 var list = fromJSON_1(json, world);
14820 return new Doc_1(list, null, world);
14821 };
14822 /** make a deep-copy of the library state */
14823
14824
14825 nlp.clone = function () {
14826 return instance(world.clone());
14827 };
14828 /** log our decision-making for debugging */
14829
14830
14831 nlp.verbose = function () {
14832 var bool = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
14833 world.verbose(bool);
14834 return this;
14835 };
14836 /** grab currently-used World object */
14837
14838
14839 nlp.world = function () {
14840 return world;
14841 };
14842 /** pre-parse any match statements */
14843
14844
14845 nlp.parseMatch = function (str, opts) {
14846 return matchSyntax(str, opts);
14847 };
14848 /** current version of the library */
14849
14850
14851 nlp.version = _version; // aliases
14852
14853 nlp["import"] = nlp.load;
14854 nlp.plugin = nlp.extend;
14855 return nlp;
14856}
14857
14858var src = instance(new World_1());
14859
14860export default src;