UNPKG

411 kBJavaScriptView Raw
1/* compromise 13.9.0 MIT */
2(function (global, factory) {
3 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4 typeof define === 'function' && define.amd ? define(factory) :
5 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.nlp = factory());
6}(this, (function () { 'use strict';
7
8 function _typeof(obj) {
9 "@babel/helpers - typeof";
10
11 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
12 _typeof = function (obj) {
13 return typeof obj;
14 };
15 } else {
16 _typeof = function (obj) {
17 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
18 };
19 }
20
21 return _typeof(obj);
22 }
23
24 function _classCallCheck(instance, Constructor) {
25 if (!(instance instanceof Constructor)) {
26 throw new TypeError("Cannot call a class as a function");
27 }
28 }
29
30 function _defineProperties(target, props) {
31 for (var i = 0; i < props.length; i++) {
32 var descriptor = props[i];
33 descriptor.enumerable = descriptor.enumerable || false;
34 descriptor.configurable = true;
35 if ("value" in descriptor) descriptor.writable = true;
36 Object.defineProperty(target, descriptor.key, descriptor);
37 }
38 }
39
40 function _createClass(Constructor, protoProps, staticProps) {
41 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
42 if (staticProps) _defineProperties(Constructor, staticProps);
43 return Constructor;
44 }
45
46 function _inherits(subClass, superClass) {
47 if (typeof superClass !== "function" && superClass !== null) {
48 throw new TypeError("Super expression must either be null or a function");
49 }
50
51 subClass.prototype = Object.create(superClass && superClass.prototype, {
52 constructor: {
53 value: subClass,
54 writable: true,
55 configurable: true
56 }
57 });
58 if (superClass) _setPrototypeOf(subClass, superClass);
59 }
60
61 function _getPrototypeOf(o) {
62 _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
63 return o.__proto__ || Object.getPrototypeOf(o);
64 };
65 return _getPrototypeOf(o);
66 }
67
68 function _setPrototypeOf(o, p) {
69 _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
70 o.__proto__ = p;
71 return o;
72 };
73
74 return _setPrototypeOf(o, p);
75 }
76
77 function _isNativeReflectConstruct() {
78 if (typeof Reflect === "undefined" || !Reflect.construct) return false;
79 if (Reflect.construct.sham) return false;
80 if (typeof Proxy === "function") return true;
81
82 try {
83 Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
84 return true;
85 } catch (e) {
86 return false;
87 }
88 }
89
90 function _assertThisInitialized(self) {
91 if (self === void 0) {
92 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
93 }
94
95 return self;
96 }
97
98 function _possibleConstructorReturn(self, call) {
99 if (call && (typeof call === "object" || typeof call === "function")) {
100 return call;
101 }
102
103 return _assertThisInitialized(self);
104 }
105
106 function _createSuper(Derived) {
107 var hasNativeReflectConstruct = _isNativeReflectConstruct();
108
109 return function _createSuperInternal() {
110 var Super = _getPrototypeOf(Derived),
111 result;
112
113 if (hasNativeReflectConstruct) {
114 var NewTarget = _getPrototypeOf(this).constructor;
115
116 result = Reflect.construct(Super, arguments, NewTarget);
117 } else {
118 result = Super.apply(this, arguments);
119 }
120
121 return _possibleConstructorReturn(this, result);
122 };
123 }
124
125 //this is a not-well-thought-out way to reduce our dependence on `object===object` stuff
126 var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split(''); //generates a unique id for this term
127
128 function makeId(str) {
129 str = str || '_';
130 var text = str + '-';
131
132 for (var i = 0; i < 7; i++) {
133 text += chars[Math.floor(Math.random() * chars.length)];
134 }
135
136 return text;
137 }
138
139 var _id = makeId;
140
141 //a hugely-ignorant, and widely subjective transliteration of latin, cryllic, greek unicode characters to english ascii.
142 //approximate visual (not semantic or phonetic) relationship between unicode and ascii characters
143 //http://en.wikipedia.org/wiki/List_of_Unicode_characters
144 //https://docs.google.com/spreadsheet/ccc?key=0Ah46z755j7cVdFRDM1A2YVpwa1ZYWlpJM2pQZ003M0E
145 var compact = {
146 '!': '¡',
147 '?': '¿Ɂ',
148 '"': '“”"❝❞',
149 "'": '‘‛❛❜',
150 '-': '—–',
151 a: 'ªÀÁÂÃÄÅàáâãäåĀāĂ㥹ǍǎǞǟǠǡǺǻȀȁȂȃȦȧȺΆΑΔΛάαλАадѦѧӐӑӒӓƛɅæ',
152 b: 'ßþƀƁƂƃƄƅɃΒβϐϦБВЪЬвъьѢѣҌҍ',
153 c: '¢©ÇçĆćĈĉĊċČčƆƇƈȻȼͻͼͽϲϹϽϾСсєҀҁҪҫ',
154 d: 'ÐĎďĐđƉƊȡƋƌǷ',
155 e: 'ÈÉÊËèéêëĒēĔĕĖėĘęĚěƎƏƐǝȄȅȆȇȨȩɆɇΈΕΞΣέεξϱϵ϶ЀЁЕЭеѐёҼҽҾҿӖӗӘәӚӛӬӭ',
156 f: 'ƑƒϜϝӺӻҒғſ',
157 g: 'ĜĝĞğĠġĢģƓǤǥǦǧǴǵ',
158 h: 'ĤĥĦħƕǶȞȟΉΗЂЊЋНнђћҢңҤҥҺһӉӊ',
159 I: 'ÌÍÎÏ',
160 i: 'ìíîïĨĩĪīĬĭĮįİıƖƗȈȉȊȋΊΐΪίιϊІЇії',
161 j: 'ĴĵǰȷɈɉϳЈј',
162 k: 'ĶķĸƘƙǨǩΚκЌЖКжкќҚқҜҝҞҟҠҡ',
163 l: 'ĹĺĻļĽľĿŀŁłƚƪǀǏǐȴȽΙӀӏ',
164 m: 'ΜϺϻМмӍӎ',
165 n: 'ÑñŃńŅņŇňʼnŊŋƝƞǸǹȠȵΝΠήηϞЍИЙЛПийлпѝҊҋӅӆӢӣӤӥπ',
166 o: 'ÒÓÔÕÖØðòóôõöøŌōŎŏŐőƟƠơǑǒǪǫǬǭǾǿȌȍȎȏȪȫȬȭȮȯȰȱΌΘΟθοσόϕϘϙϬϭϴОФоѲѳӦӧӨөӪӫ',
167 p: 'ƤƿΡρϷϸϼРрҎҏÞ',
168 q: 'Ɋɋ',
169 r: 'ŔŕŖŗŘřƦȐȑȒȓɌɍЃГЯгяѓҐґ',
170 s: 'ŚśŜŝŞşŠšƧƨȘșȿЅѕ',
171 t: 'ŢţŤťŦŧƫƬƭƮȚțȶȾΓΤτϮТт',
172 u: 'µÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųƯưƱƲǓǔǕǖǗǘǙǚǛǜȔȕȖȗɄΰμυϋύ',
173 v: 'νѴѵѶѷ',
174 w: 'ŴŵƜωώϖϢϣШЩшщѡѿ',
175 x: '×ΧχϗϰХхҲҳӼӽӾӿ',
176 y: 'ÝýÿŶŷŸƳƴȲȳɎɏΎΥΫγψϒϓϔЎУучўѰѱҮүҰұӮӯӰӱӲӳ',
177 z: 'ŹźŻżŽžƩƵƶȤȥɀΖζ'
178 }; //decompress data into two hashes
179
180 var unicode = {};
181 Object.keys(compact).forEach(function (k) {
182 compact[k].split('').forEach(function (s) {
183 unicode[s] = k;
184 });
185 });
186
187 var killUnicode = function killUnicode(str) {
188 var chars = str.split('');
189 chars.forEach(function (s, i) {
190 if (unicode[s]) {
191 chars[i] = unicode[s];
192 }
193 });
194 return chars.join('');
195 };
196
197 var unicode_1 = killUnicode; // console.log(killUnicode('bjŏȒk—Ɏó'));
198
199 var periodAcronym = /([A-Z]\.)+[A-Z]?,?$/;
200 var oneLetterAcronym = /^[A-Z]\.,?$/;
201 var noPeriodAcronym = /[A-Z]{2,}('s|,)?$/;
202 var lowerCaseAcronym = /([a-z]\.){1,}[a-z]\.?$/;
203
204 var isAcronym = function isAcronym(str) {
205 //like N.D.A
206 if (periodAcronym.test(str) === true) {
207 return true;
208 } //like c.e.o
209
210
211 if (lowerCaseAcronym.test(str) === true) {
212 return true;
213 } //like 'F.'
214
215
216 if (oneLetterAcronym.test(str) === true) {
217 return true;
218 } //like NDA
219
220
221 if (noPeriodAcronym.test(str) === true) {
222 return true;
223 }
224
225 return false;
226 };
227
228 var isAcronym_1 = isAcronym;
229
230 var hasSlash = /[a-z\u00C0-\u00FF] ?\/ ?[a-z\u00C0-\u00FF]/;
231 /** some basic operations on a string to reduce noise */
232
233 var clean = function clean(str) {
234 str = str || '';
235 str = str.toLowerCase();
236 str = str.trim();
237 var original = str; //(very) rough ASCII transliteration - bjŏrk -> bjork
238
239 str = unicode_1(str); //rough handling of slashes - 'see/saw'
240
241 if (hasSlash.test(str) === true) {
242 str = str.replace(/\/.*/, '');
243 } //#tags, @mentions
244
245
246 str = str.replace(/^[#@]/, ''); //punctuation
247
248 str = str.replace(/[,;.!?]+$/, ''); // coerce single curly quotes
249
250 str = str.replace(/[\u0027\u0060\u00B4\u2018\u2019\u201A\u201B\u2032\u2035\u2039\u203A]+/g, "'"); // coerce double curly quotes
251
252 str = str.replace(/[\u0022\u00AB\u00BB\u201C\u201D\u201E\u201F\u2033\u2034\u2036\u2037\u2E42\u301D\u301E\u301F\uFF02]+/g, '"'); //coerce Unicode ellipses
253
254 str = str.replace(/\u2026/g, '...'); //en-dash
255
256 str = str.replace(/\u2013/g, '-'); //lookin'->looking (make it easier for conjugation)
257
258 str = str.replace(/([aeiou][ktrp])in$/, '$1ing'); //turn re-enactment to reenactment
259
260 if (/^(re|un)-?[^aeiou]./.test(str) === true) {
261 str = str.replace('-', '');
262 } //compact acronyms
263
264
265 if (isAcronym_1(str)) {
266 str = str.replace(/\./g, '');
267 } //strip leading & trailing grammatical punctuation
268
269
270 if (/^[:;]/.test(str) === false) {
271 str = str.replace(/\.{3,}$/g, '');
272 str = str.replace(/[",\.!:;\?\)]+$/g, '');
273 str = str.replace(/^['"\(]+/g, '');
274 } // remove zero-width characters
275
276
277 str = str.replace(/[\u200B-\u200D\uFEFF]/g, ''); //do this again..
278
279 str = str.trim(); //oh shucks,
280
281 if (str === '') {
282 str = original;
283 } //nice-numbers
284
285
286 str = str.replace(/([0-9]),([0-9])/g, '$1$2');
287 return str;
288 };
289
290 var clean_1 = clean; // console.log(normalize('Dr. V Cooper'));
291
292 /** reduced is one step further than clean */
293 var reduced = function reduced(str) {
294 // remove apostrophes
295 str = str.replace(/['’]s$/, '');
296 str = str.replace(/s['’]$/, 's');
297 return str;
298 };
299
300 var reduce = reduced;
301
302 //all punctuation marks, from https://en.wikipedia.org/wiki/Punctuation
303 //we have slightly different rules for start/end - like #hashtags.
304
305 var startings = /^[ \n\t\.’'\[\](){}⟨⟩:,،、‒–—―…!.‹›«»‐\-?‘’;\/⁄·&*•^†‡°¡¿※№÷׺ª%‰+−=‱¶′″‴§~|‖¦©℗®℠™¤₳฿\u0022|\uFF02|\u0027|\u201C|\u2018|\u201F|\u201B|\u201E|\u2E42|\u201A|\u00AB|\u2039|\u2035|\u2036|\u2037|\u301D|\u0060|\u301F]+/;
306 var endings = /[ \n\t\.’'\[\](){}⟨⟩:,،、‒–—―…!.‹›«»‐\-?‘’;\/⁄·&*@•^†‡°¡¿※#№÷׺ª‰+−=‱¶′″‴§~|‖¦©℗®℠™¤₳฿\u0022|\uFF02|\u0027|\u201D|\u2019|\u201D|\u2019|\u201D|\u201D|\u2019|\u00BB|\u203A|\u2032|\u2033|\u2034|\u301E|\u00B4|\u301E]+$/; //money = ₵¢₡₢$₫₯֏₠€ƒ₣₲₴₭₺₾ℳ₥₦₧₱₰£៛₽₹₨₪৳₸₮₩¥
307
308 var hasSlash$1 = /\//;
309 var hasApostrophe = /['’]/;
310 var hasAcronym = /^[a-z]\.([a-z]\.)+/i;
311 var minusNumber = /^[-+\.][0-9]/;
312 var shortYear = /^'[0-9]{2}/;
313 /** turn given text into a parsed-up object
314 * seperate the 'meat' of the word from the whitespace+punctuation
315 */
316
317 var parseTerm = function parseTerm(str) {
318 var original = str;
319 var pre = '';
320 var post = '';
321 str = str.replace(startings, function (found) {
322 pre = found; // support '-40'
323
324 if ((pre === '-' || pre === '+' || pre === '.') && minusNumber.test(str)) {
325 pre = '';
326 return found;
327 } // support years like '97
328
329
330 if (pre === "'" && shortYear.test(str)) {
331 pre = '';
332 return found;
333 }
334
335 return '';
336 });
337 str = str.replace(endings, function (found) {
338 post = found; // keep s-apostrophe - "flanders'" or "chillin'"
339
340 if (hasApostrophe.test(found) && /[sn]['’]$/.test(original) && hasApostrophe.test(pre) === false) {
341 post = post.replace(hasApostrophe, '');
342 return "'";
343 } //keep end-period in acronym
344
345
346 if (hasAcronym.test(str) === true) {
347 post = post.replace(/\./, '');
348 return '.';
349 }
350
351 return '';
352 }); //we went too far..
353
354 if (str === '') {
355 // do a very mild parse, and hope for the best.
356 original = original.replace(/ *$/, function (after) {
357 post = after || '';
358 return '';
359 });
360 str = original;
361 pre = '';
362 post = post;
363 } // create the various forms of our text,
364
365
366 var clean = clean_1(str);
367 var parsed = {
368 text: str,
369 clean: clean,
370 reduced: reduce(clean),
371 pre: pre,
372 post: post
373 }; // support aliases for slashes
374
375 if (hasSlash$1.test(str)) {
376 str.split(hasSlash$1).forEach(function (word) {
377 parsed.alias = parsed.alias || {};
378 parsed.alias[word.trim()] = true;
379 });
380 }
381
382 return parsed;
383 };
384
385 var parse = parseTerm;
386
387 function createCommonjsModule(fn) {
388 var module = { exports: {} };
389 return fn(module, module.exports), module.exports;
390 }
391
392 var _01Case = createCommonjsModule(function (module, exports) {
393 var titleCase = /^[A-Z][a-z'\u00C0-\u00FF]/;
394 var upperCase = /^[A-Z]+s?$/;
395 /** convert all text to uppercase */
396
397 exports.toUpperCase = function () {
398 this.text = this.text.toUpperCase();
399 return this;
400 };
401 /** convert all text to lowercase */
402
403
404 exports.toLowerCase = function () {
405 this.text = this.text.toLowerCase();
406 return this;
407 };
408 /** only set the first letter to uppercase
409 * leave any existing uppercase alone
410 */
411
412
413 exports.toTitleCase = function () {
414 this.text = this.text.replace(/^ *[a-z\u00C0-\u00FF]/, function (x) {
415 return x.toUpperCase();
416 }); //support unicode?
417
418 return this;
419 };
420 /** if all letters are uppercase */
421
422
423 exports.isUpperCase = function () {
424 return upperCase.test(this.text);
425 };
426 /** if the first letter is uppercase, and the rest are lowercase */
427
428
429 exports.isTitleCase = function () {
430 return titleCase.test(this.text);
431 };
432
433 exports.titleCase = exports.isTitleCase;
434 });
435
436 var _02Punctuation = createCommonjsModule(function (module, exports) {
437 // these methods are called with '@hasComma' in the match syntax
438 // various unicode quotation-mark formats
439 var startQuote = /(\u0022|\uFF02|\u0027|\u201C|\u2018|\u201F|\u201B|\u201E|\u2E42|\u201A|\u00AB|\u2039|\u2035|\u2036|\u2037|\u301D|\u0060|\u301F)/;
440 var endQuote = /(\u0022|\uFF02|\u0027|\u201D|\u2019|\u201D|\u2019|\u201D|\u201D|\u2019|\u00BB|\u203A|\u2032|\u2033|\u2034|\u301E|\u00B4|\u301E)/;
441 /** search the term's 'post' punctuation */
442
443 exports.hasPost = function (punct) {
444 return this.post.indexOf(punct) !== -1;
445 };
446 /** search the term's 'pre' punctuation */
447
448
449 exports.hasPre = function (punct) {
450 return this.pre.indexOf(punct) !== -1;
451 };
452 /** does it have a quotation symbol? */
453
454
455 exports.hasQuote = function () {
456 return startQuote.test(this.pre) || endQuote.test(this.post);
457 };
458
459 exports.hasQuotation = exports.hasQuote;
460 /** does it have a comma? */
461
462 exports.hasComma = function () {
463 return this.hasPost(',');
464 };
465 /** does it end in a period? */
466
467
468 exports.hasPeriod = function () {
469 return this.hasPost('.') === true && this.hasPost('...') === false;
470 };
471 /** does it end in an exclamation */
472
473
474 exports.hasExclamation = function () {
475 return this.hasPost('!');
476 };
477 /** does it end with a question mark? */
478
479
480 exports.hasQuestionMark = function () {
481 return this.hasPost('?') || this.hasPost('¿');
482 };
483 /** is there a ... at the end? */
484
485
486 exports.hasEllipses = function () {
487 return this.hasPost('..') || this.hasPost('…') || this.hasPre('..') || this.hasPre('…');
488 };
489 /** is there a semicolon after this word? */
490
491
492 exports.hasSemicolon = function () {
493 return this.hasPost(';');
494 };
495 /** is there a slash '/' in this word? */
496
497
498 exports.hasSlash = function () {
499 return /\//.test(this.text);
500 };
501 /** a hyphen connects two words like-this */
502
503
504 exports.hasHyphen = function () {
505 var hyphen = /^(-|–|—)$/;
506 return hyphen.test(this.post) || hyphen.test(this.pre);
507 };
508 /** a dash separates words - like that */
509
510
511 exports.hasDash = function () {
512 var hyphen = / (-|–|—) /;
513 return hyphen.test(this.post) || hyphen.test(this.pre);
514 };
515 /** is it multiple words combinded */
516
517
518 exports.hasContraction = function () {
519 return Boolean(this.implicit);
520 };
521 /** try to sensibly put this punctuation mark into the term */
522
523
524 exports.addPunctuation = function (punct) {
525 // dont add doubles
526 if (punct === ',' || punct === ';') {
527 this.post = this.post.replace(punct, '');
528 }
529
530 this.post = punct + this.post;
531 return this;
532 };
533 });
534
535 // fuzzy-match (damerau-levenshtein)
536 // Based on tad-lispy /node-damerau-levenshtein
537 // https://github.com/tad-lispy/node-damerau-levenshtein/blob/master/index.js
538 // count steps (insertions, deletions, substitutions, or transpositions)
539 var editDistance = function editDistance(strA, strB) {
540 var aLength = strA.length,
541 bLength = strB.length; // fail-fast
542
543 if (aLength === 0) {
544 return bLength;
545 }
546
547 if (bLength === 0) {
548 return aLength;
549 } // If the limit is not defined it will be calculate from this and that args.
550
551
552 var limit = (bLength > aLength ? bLength : aLength) + 1;
553
554 if (Math.abs(aLength - bLength) > (limit || 100)) {
555 return limit || 100;
556 } // init the array
557
558
559 var matrix = [];
560
561 for (var i = 0; i < limit; i++) {
562 matrix[i] = [i];
563 matrix[i].length = limit;
564 }
565
566 for (var _i = 0; _i < limit; _i++) {
567 matrix[0][_i] = _i;
568 } // Calculate matrix.
569
570
571 var j, a_index, b_index, cost, min, t;
572
573 for (var _i2 = 1; _i2 <= aLength; ++_i2) {
574 a_index = strA[_i2 - 1];
575
576 for (j = 1; j <= bLength; ++j) {
577 // Check the jagged distance total so far
578 if (_i2 === j && matrix[_i2][j] > 4) {
579 return aLength;
580 }
581
582 b_index = strB[j - 1];
583 cost = a_index === b_index ? 0 : 1; // Step 5
584 // Calculate the minimum (much faster than Math.min(...)).
585
586 min = matrix[_i2 - 1][j] + 1; // Deletion.
587
588 if ((t = matrix[_i2][j - 1] + 1) < min) min = t; // Insertion.
589
590 if ((t = matrix[_i2 - 1][j - 1] + cost) < min) min = t; // Substitution.
591 // Update matrix.
592
593 var shouldUpdate = _i2 > 1 && j > 1 && a_index === strB[j - 2] && strA[_i2 - 2] === b_index && (t = matrix[_i2 - 2][j - 2] + cost) < min;
594
595 if (shouldUpdate) {
596 matrix[_i2][j] = t;
597 } else {
598 matrix[_i2][j] = min;
599 }
600 }
601 } // return number of steps
602
603
604 return matrix[aLength][bLength];
605 }; // score similarity by from 0-1 (steps/length)
606
607
608 var fuzzyMatch = function fuzzyMatch(strA, strB) {
609 var minLength = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 3;
610
611 if (strA === strB) {
612 return 1;
613 } //don't even bother on tiny strings
614
615
616 if (strA.length < minLength || strB.length < minLength) {
617 return 0;
618 }
619
620 var steps = editDistance(strA, strB);
621 var length = Math.max(strA.length, strB.length);
622 var relative = length === 0 ? 0 : steps / length;
623 var similarity = 1 - relative;
624 return similarity;
625 };
626
627 var _fuzzy = fuzzyMatch; // console.log(fuzzyMatch('test', 'test')) //exact match
628
629 var wrapMatch = function wrapMatch() {};
630 /** ignore optional/greedy logic, straight-up term match*/
631
632
633 var doesMatch = function doesMatch(t, reg, index, length) {
634 // support id matches
635 if (reg.id === t.id) {
636 return true;
637 } // support '.'
638
639
640 if (reg.anything === true) {
641 return true;
642 } // support '^' (in parentheses)
643
644
645 if (reg.start === true && index !== 0) {
646 return false;
647 } // support '$' (in parentheses)
648
649
650 if (reg.end === true && index !== length - 1) {
651 return false;
652 } //support a text match
653
654
655 if (reg.word !== undefined) {
656 //match contractions
657 if (t.implicit !== null && t.implicit === reg.word) {
658 return true;
659 } // term aliases for slashes and things
660
661
662 if (t.alias !== undefined && t.alias.hasOwnProperty(reg.word)) {
663 return true;
664 } // support ~ match
665
666
667 if (reg.soft === true && reg.word === t.root) {
668 return true;
669 } // support fuzzy match param
670
671
672 if (reg.fuzzy !== undefined) {
673 var score = _fuzzy(reg.word, t.reduced);
674
675 if (score > reg.fuzzy) {
676 return true;
677 } // support fuzzy + soft match
678
679
680 if (reg.soft === true) {
681 score = _fuzzy(reg.word, t.root);
682
683 if (score > reg.fuzzy) {
684 return true;
685 }
686 }
687 } //match either .clean or .text
688
689
690 return reg.word === t.clean || reg.word === t.text || reg.word === t.reduced;
691 } //support #Tag
692
693
694 if (reg.tag !== undefined) {
695 return t.tags[reg.tag] === true;
696 } //support @method
697
698
699 if (reg.method !== undefined) {
700 if (typeof t[reg.method] === 'function' && t[reg.method]() === true) {
701 return true;
702 }
703
704 return false;
705 } //support /reg/
706
707
708 if (reg.regex !== undefined) {
709 return reg.regex.test(t.clean);
710 } // support optimized (one|two)
711
712
713 if (reg.fastOr !== undefined) {
714 return reg.fastOr.hasOwnProperty(t.reduced) || reg.fastOr.hasOwnProperty(t.text);
715 } //support slower (one|two)
716
717
718 if (reg.choices !== undefined) {
719 // try to support && operator
720 if (reg.operator === 'and') {
721 // must match them all
722 return reg.choices.every(function (r) {
723 return wrapMatch(t, r, index, length);
724 });
725 } // or must match one
726
727
728 return reg.choices.some(function (r) {
729 return wrapMatch(t, r, index, length);
730 });
731 }
732
733 return false;
734 }; // wrap result for !negative match logic
735
736
737 wrapMatch = function wrapMatch(t, reg, index, length) {
738 var result = doesMatch(t, reg, index, length);
739
740 if (reg.negative === true) {
741 return !result;
742 }
743
744 return result;
745 };
746
747 var _doesMatch = wrapMatch;
748
749 var boring = {};
750 /** check a match object against this term */
751
752 var doesMatch_1 = function doesMatch_1(reg, index, length) {
753 return _doesMatch(this, reg, index, length);
754 };
755 /** does this term look like an acronym? */
756
757
758 var isAcronym_1$1 = function isAcronym_1$1() {
759 return isAcronym_1(this.text);
760 };
761 /** is this term implied by a contraction? */
762
763
764 var isImplicit = function isImplicit() {
765 return this.text === '' && Boolean(this.implicit);
766 };
767 /** does the term have at least one good tag? */
768
769
770 var isKnown = function isKnown() {
771 return Object.keys(this.tags).some(function (t) {
772 return boring[t] !== true;
773 });
774 };
775 /** cache the root property of the term */
776
777
778 var setRoot = function setRoot(world) {
779 var transform = world.transforms;
780 var str = this.implicit || this.clean;
781
782 if (this.tags.Plural) {
783 str = transform.toSingular(str, world);
784 }
785
786 if (this.tags.Verb && !this.tags.Negative && !this.tags.Infinitive) {
787 var tense = null;
788
789 if (this.tags.PastTense) {
790 tense = 'PastTense';
791 } else if (this.tags.Gerund) {
792 tense = 'Gerund';
793 } else if (this.tags.PresentTense) {
794 tense = 'PresentTense';
795 } else if (this.tags.Participle) {
796 tense = 'Participle';
797 } else if (this.tags.Actor) {
798 tense = 'Actor';
799 }
800
801 str = transform.toInfinitive(str, world, tense);
802 }
803
804 this.root = str;
805 };
806
807 var _03Misc = {
808 doesMatch: doesMatch_1,
809 isAcronym: isAcronym_1$1,
810 isImplicit: isImplicit,
811 isKnown: isKnown,
812 setRoot: setRoot
813 };
814
815 var hasSpace = /[\s-]/;
816 var isUpperCase = /^[A-Z-]+$/; // const titleCase = str => {
817 // return str.charAt(0).toUpperCase() + str.substr(1)
818 // }
819
820 /** return various text formats of this term */
821
822 var textOut = function textOut(options, showPre, showPost) {
823 options = options || {};
824 var word = this.text;
825 var before = this.pre;
826 var after = this.post; // -word-
827
828 if (options.reduced === true) {
829 word = this.reduced || '';
830 }
831
832 if (options.root === true) {
833 word = this.root || '';
834 }
835
836 if (options.implicit === true && this.implicit) {
837 word = this.implicit || '';
838 }
839
840 if (options.normal === true) {
841 word = this.clean || this.text || '';
842 }
843
844 if (options.root === true) {
845 word = this.root || this.reduced || '';
846 }
847
848 if (options.unicode === true) {
849 word = unicode_1(word);
850 } // cleanup case
851
852
853 if (options.titlecase === true) {
854 if (this.tags.ProperNoun && !this.titleCase()) ; else if (this.tags.Acronym) {
855 word = word.toUpperCase(); //uppercase acronyms
856 } else if (isUpperCase.test(word) && !this.tags.Acronym) {
857 // lowercase everything else
858 word = word.toLowerCase();
859 }
860 }
861
862 if (options.lowercase === true) {
863 word = word.toLowerCase();
864 } // remove the '.'s from 'F.B.I.' (safely)
865
866
867 if (options.acronyms === true && this.tags.Acronym) {
868 word = word.replace(/\./g, '');
869 } // -before/after-
870
871
872 if (options.whitespace === true || options.root === true) {
873 before = '';
874 after = ' ';
875
876 if ((hasSpace.test(this.post) === false || options.last) && !this.implicit) {
877 after = '';
878 }
879 }
880
881 if (options.punctuation === true && !options.root) {
882 //normalized end punctuation
883 if (this.hasPost('.') === true) {
884 after = '.' + after;
885 } else if (this.hasPost('?') === true) {
886 after = '?' + after;
887 } else if (this.hasPost('!') === true) {
888 after = '!' + after;
889 } else if (this.hasPost(',') === true) {
890 after = ',' + after;
891 } else if (this.hasEllipses() === true) {
892 after = '...' + after;
893 }
894 }
895
896 if (showPre !== true) {
897 before = '';
898 }
899
900 if (showPost !== true) {
901 // let keep = after.match(/\)/) || ''
902 after = ''; //keep //after.replace(/[ .?!,]+/, '')
903 } // remove the '.' from 'Mrs.' (safely)
904
905
906 if (options.abbreviations === true && this.tags.Abbreviation) {
907 after = after.replace(/^\./, '');
908 }
909
910 return before + word + after;
911 };
912
913 var _04Text = {
914 textOut: textOut
915 };
916
917 var boringTags = {
918 Auxiliary: 1,
919 Possessive: 1
920 };
921 /** a subjective ranking of tags kinda tfidf-based */
922
923 var rankTags = function rankTags(term, world) {
924 var tags = Object.keys(term.tags);
925 var tagSet = world.tags;
926 tags = tags.sort(function (a, b) {
927 //bury the tags we dont want
928 if (boringTags[b] || !tagSet[b]) {
929 return -1;
930 } // unknown tags are interesting
931
932
933 if (!tagSet[b]) {
934 return 1;
935 }
936
937 if (!tagSet[a]) {
938 return 0;
939 } // then sort by #of parent tags (most-specific tags first)
940
941
942 if (tagSet[a].lineage.length > tagSet[b].lineage.length) {
943 return 1;
944 }
945
946 if (tagSet[a].isA.length > tagSet[b].isA.length) {
947 return -1;
948 }
949
950 return 0;
951 });
952 return tags;
953 };
954
955 var _bestTag = rankTags;
956
957 var jsonDefault = {
958 text: true,
959 tags: true,
960 implicit: true,
961 whitespace: true,
962 clean: false,
963 id: false,
964 index: false,
965 offset: false,
966 bestTag: false
967 };
968 /** return various metadata for this term */
969
970 var json = function json(options, world) {
971 options = options || {};
972 options = Object.assign({}, jsonDefault, options);
973 var result = {}; // default on
974
975 if (options.text) {
976 result.text = this.text;
977 }
978
979 if (options.normal) {
980 result.normal = this.clean;
981 }
982
983 if (options.tags) {
984 result.tags = Object.keys(this.tags);
985 } // default off
986
987
988 if (options.clean) {
989 result.clean = this.clean;
990 }
991
992 if (options.id || options.offset) {
993 result.id = this.id;
994 }
995
996 if (options.implicit && this.implicit !== null) {
997 result.implicit = this.implicit;
998 }
999
1000 if (options.whitespace) {
1001 result.pre = this.pre;
1002 result.post = this.post;
1003 }
1004
1005 if (options.bestTag) {
1006 result.bestTag = _bestTag(this, world)[0];
1007 }
1008
1009 return result;
1010 };
1011
1012 var _05Json = {
1013 json: json
1014 };
1015
1016 var methods = Object.assign({}, _01Case, _02Punctuation, _03Misc, _04Text, _05Json);
1017
1018 function isClientSide() {
1019 return typeof window !== 'undefined' && window.document;
1020 }
1021 /** add spaces at the end */
1022
1023
1024 var padEnd = function padEnd(str, width) {
1025 str = str.toString();
1026
1027 while (str.length < width) {
1028 str += ' ';
1029 }
1030
1031 return str;
1032 };
1033 /** output for verbose-mode */
1034
1035
1036 var logTag = function logTag(t, tag, reason) {
1037 if (isClientSide()) {
1038 console.log('%c' + padEnd(t.clean, 3) + ' + ' + tag + ' ', 'color: #6accb2;');
1039 return;
1040 } //server-side
1041
1042
1043 var log = '\x1b[33m' + padEnd(t.clean, 15) + '\x1b[0m + \x1b[32m' + tag + '\x1b[0m ';
1044
1045 if (reason) {
1046 log = padEnd(log, 35) + ' ' + reason + '';
1047 }
1048
1049 console.log(log);
1050 };
1051 /** output for verbose mode */
1052
1053
1054 var logUntag = function logUntag(t, tag, reason) {
1055 if (isClientSide()) {
1056 console.log('%c' + padEnd(t.clean, 3) + ' - ' + tag + ' ', 'color: #AB5850;');
1057 return;
1058 } //server-side
1059
1060
1061 var log = '\x1b[33m' + padEnd(t.clean, 3) + ' \x1b[31m - #' + tag + '\x1b[0m ';
1062
1063 if (reason) {
1064 log = padEnd(log, 35) + ' ' + reason;
1065 }
1066
1067 console.log(log);
1068 };
1069
1070 var isArray = function isArray(arr) {
1071 return Object.prototype.toString.call(arr) === '[object Array]';
1072 };
1073
1074 var titleCase = function titleCase(str) {
1075 return str.charAt(0).toUpperCase() + str.substr(1);
1076 };
1077
1078 var fns = {
1079 logTag: logTag,
1080 logUntag: logUntag,
1081 isArray: isArray,
1082 titleCase: titleCase
1083 };
1084
1085 /** add a tag, and its descendents, to a term */
1086
1087 var addTag = function addTag(t, tag, reason, world) {
1088 var tagset = world.tags; //support '.' or '-' notation for skipping the tag
1089
1090 if (tag === '' || tag === '.' || tag === '-') {
1091 return;
1092 }
1093
1094 if (tag[0] === '#') {
1095 tag = tag.replace(/^#/, '');
1096 }
1097
1098 tag = fns.titleCase(tag); //if we already got this one
1099
1100 if (t.tags[tag] === true) {
1101 return;
1102 } // log it?
1103
1104
1105 var isVerbose = world.isVerbose();
1106
1107 if (isVerbose === true) {
1108 fns.logTag(t, tag, reason);
1109 } //add tag
1110
1111
1112 t.tags[tag] = true; //whee!
1113 //check tagset for any additional things to do...
1114
1115 if (tagset.hasOwnProperty(tag) === true) {
1116 //add parent Tags
1117 tagset[tag].isA.forEach(function (down) {
1118 t.tags[down] = true;
1119
1120 if (isVerbose === true) {
1121 fns.logTag(t, '→ ' + down);
1122 }
1123 }); //remove any contrary tags
1124
1125 t.unTag(tagset[tag].notA, '←', world);
1126 }
1127 };
1128 /** support an array of tags */
1129
1130
1131 var addTags = function addTags(term, tags, reason, world) {
1132 if (typeof tags !== 'string') {
1133 for (var i = 0; i < tags.length; i++) {
1134 addTag(term, tags[i], reason, world);
1135 } // tags.forEach(tag => addTag(term, tag, reason, world))
1136
1137 } else {
1138 addTag(term, tags, reason, world);
1139 }
1140 };
1141
1142 var add = addTags;
1143
1144 var lowerCase = /^[a-z]/;
1145
1146 var titleCase$1 = function titleCase(str) {
1147 return str.charAt(0).toUpperCase() + str.substr(1);
1148 };
1149 /** remove this tag, and its descentents from the term */
1150
1151
1152 var unTag = function unTag(t, tag, reason, world) {
1153 var isVerbose = world.isVerbose(); //support '*' for removing all tags
1154
1155 if (tag === '*') {
1156 t.tags = {};
1157 return t;
1158 }
1159
1160 tag = tag.replace(/^#/, '');
1161
1162 if (lowerCase.test(tag) === true) {
1163 tag = titleCase$1(tag);
1164 } // remove the tag
1165
1166
1167 if (t.tags[tag] === true) {
1168 delete t.tags[tag]; //log in verbose-mode
1169
1170 if (isVerbose === true) {
1171 fns.logUntag(t, tag, reason);
1172 }
1173 } //delete downstream tags too
1174
1175
1176 var tagset = world.tags;
1177
1178 if (tagset[tag]) {
1179 var lineage = tagset[tag].lineage;
1180
1181 for (var i = 0; i < lineage.length; i++) {
1182 if (t.tags[lineage[i]] === true) {
1183 delete t.tags[lineage[i]];
1184
1185 if (isVerbose === true) {
1186 fns.logUntag(t, ' - ' + lineage[i]);
1187 }
1188 }
1189 }
1190 }
1191
1192 return t;
1193 }; //handle an array of tags
1194
1195
1196 var untagAll = function untagAll(term, tags, reason, world) {
1197 if (typeof tags !== 'string' && tags) {
1198 for (var i = 0; i < tags.length; i++) {
1199 unTag(term, tags[i], reason, world);
1200 }
1201
1202 return;
1203 }
1204
1205 unTag(term, tags, reason, world);
1206 };
1207
1208 var unTag_1 = untagAll;
1209
1210 var canBe = function canBe(term, tag, world) {
1211 var tagset = world.tags; // cleanup tag
1212
1213 if (tag[0] === '#') {
1214 tag = tag.replace(/^#/, '');
1215 } //fail-fast
1216
1217
1218 if (tagset[tag] === undefined) {
1219 return true;
1220 } //loop through tag's contradictory tags
1221
1222
1223 var enemies = tagset[tag].notA || [];
1224
1225 for (var i = 0; i < enemies.length; i++) {
1226 if (term.tags[enemies[i]] === true) {
1227 return false;
1228 }
1229 }
1230
1231 if (tagset[tag].isA !== undefined) {
1232 return canBe(term, tagset[tag].isA, world); //recursive
1233 }
1234
1235 return true;
1236 };
1237
1238 var canBe_1 = canBe;
1239
1240 /** add a tag or tags, and their descendents to this term
1241 * @param {string | string[]} tags - a tag or tags
1242 * @param {string?} [reason] a clue for debugging
1243 */
1244
1245 var tag_1 = function tag_1(tags, reason, world) {
1246 add(this, tags, reason, world);
1247 return this;
1248 };
1249 /** only tag this term if it's consistent with it's current tags */
1250
1251
1252 var tagSafe = function tagSafe(tags, reason, world) {
1253 if (canBe_1(this, tags, world)) {
1254 add(this, tags, reason, world);
1255 }
1256
1257 return this;
1258 };
1259 /** remove a tag or tags, and their descendents from this term
1260 * @param {string | string[]} tags - a tag or tags
1261 * @param {string?} [reason] a clue for debugging
1262 */
1263
1264
1265 var unTag_1$1 = function unTag_1$1(tags, reason, world) {
1266 unTag_1(this, tags, reason, world);
1267 return this;
1268 };
1269 /** is this tag consistent with the word's current tags?
1270 * @param {string | string[]} tags - a tag or tags
1271 * @returns {boolean}
1272 */
1273
1274
1275 var canBe_1$1 = function canBe_1$1(tags, world) {
1276 return canBe_1(this, tags, world);
1277 };
1278
1279 var tag = {
1280 tag: tag_1,
1281 tagSafe: tagSafe,
1282 unTag: unTag_1$1,
1283 canBe: canBe_1$1
1284 };
1285
1286 var Term = /*#__PURE__*/function () {
1287 function Term() {
1288 var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
1289
1290 _classCallCheck(this, Term);
1291
1292 text = String(text);
1293 var obj = parse(text); // the various forms of our text
1294
1295 this.text = obj.text || '';
1296 this.clean = obj.clean;
1297 this.reduced = obj.reduced;
1298 this.root = null;
1299 this.implicit = null;
1300 this.pre = obj.pre || '';
1301 this.post = obj.post || '';
1302 this.tags = {};
1303 this.prev = null;
1304 this.next = null;
1305 this.id = _id(obj.clean);
1306 this.isA = 'Term'; // easier than .constructor...
1307 // support alternative matches
1308
1309 if (obj.alias) {
1310 this.alias = obj.alias;
1311 }
1312 }
1313 /** set the text of the Term to something else*/
1314
1315
1316 _createClass(Term, [{
1317 key: "set",
1318 value: function set(str) {
1319 var obj = parse(str);
1320 this.text = obj.text;
1321 this.clean = obj.clean;
1322 return this;
1323 }
1324 }]);
1325
1326 return Term;
1327 }();
1328 /** create a deep-copy of this term */
1329
1330
1331 Term.prototype.clone = function () {
1332 var term = new Term(this.text);
1333 term.pre = this.pre;
1334 term.post = this.post;
1335 term.clean = this.clean;
1336 term.reduced = this.reduced;
1337 term.root = this.root;
1338 term.implicit = this.implicit;
1339 term.tags = Object.assign({}, this.tags); //use the old id, so it can be matched with .match(doc)
1340 // term.id = this.id
1341
1342 return term;
1343 };
1344
1345 Object.assign(Term.prototype, methods);
1346 Object.assign(Term.prototype, tag);
1347 var Term_1 = Term;
1348
1349 /** return a flat array of Term objects */
1350 var terms = function terms(n) {
1351 if (this.length === 0) {
1352 return [];
1353 } // use cache, if it exists
1354
1355
1356 if (this.cache.terms) {
1357 if (n !== undefined) {
1358 return this.cache.terms[n];
1359 }
1360
1361 return this.cache.terms;
1362 }
1363
1364 var terms = [this.pool.get(this.start)];
1365
1366 for (var i = 0; i < this.length - 1; i += 1) {
1367 var id = terms[terms.length - 1].next;
1368
1369 if (id === null) {
1370 // throw new Error('linked-list broken')
1371 console.error("Compromise error: Linked list broken in phrase '" + this.start + "'");
1372 break;
1373 }
1374
1375 var term = this.pool.get(id);
1376 terms.push(term); //return this one?
1377
1378 if (n !== undefined && n === i) {
1379 return terms[n];
1380 }
1381 }
1382
1383 if (n === undefined) {
1384 this.cache.terms = terms;
1385 }
1386
1387 if (n !== undefined) {
1388 return terms[n];
1389 }
1390
1391 return terms;
1392 };
1393 /** return a shallow or deep copy of this phrase */
1394
1395
1396 var clone = function clone(isShallow) {
1397 var _this = this;
1398
1399 if (isShallow) {
1400 var p = this.buildFrom(this.start, this.length);
1401 p.cache = this.cache;
1402 return p;
1403 } //how do we clone part of the pool?
1404
1405
1406 var terms = this.terms();
1407 var newTerms = terms.map(function (t) {
1408 return t.clone();
1409 }); // console.log(newTerms)
1410 //connect these new ids up
1411
1412 newTerms.forEach(function (t, i) {
1413 //add it to the pool..
1414 _this.pool.add(t);
1415
1416 if (newTerms[i + 1]) {
1417 t.next = newTerms[i + 1].id;
1418 }
1419
1420 if (newTerms[i - 1]) {
1421 t.prev = newTerms[i - 1].id;
1422 }
1423 });
1424 return this.buildFrom(newTerms[0].id, newTerms.length);
1425 };
1426 /** return last term object */
1427
1428
1429 var lastTerm = function lastTerm() {
1430 var terms = this.terms();
1431 return terms[terms.length - 1];
1432 };
1433 /** quick lookup for a term id */
1434
1435
1436 var hasId = function hasId(wantId) {
1437 if (this.length === 0 || !wantId) {
1438 return false;
1439 }
1440
1441 if (this.start === wantId) {
1442 return true;
1443 } // use cache, if available
1444
1445
1446 if (this.cache.terms) {
1447 var _terms = this.cache.terms;
1448
1449 for (var i = 0; i < _terms.length; i++) {
1450 if (_terms[i].id === wantId) {
1451 return true;
1452 }
1453 }
1454
1455 return false;
1456 } // otherwise, go through each term
1457
1458
1459 var lastId = this.start;
1460
1461 for (var _i = 0; _i < this.length - 1; _i += 1) {
1462 var term = this.pool.get(lastId);
1463
1464 if (term === undefined) {
1465 console.error("Compromise error: Linked list broken. Missing term '".concat(lastId, "' in phrase '").concat(this.start, "'\n")); // throw new Error('linked List error')
1466
1467 return false;
1468 }
1469
1470 if (term.next === wantId) {
1471 return true;
1472 }
1473
1474 lastId = term.next;
1475 }
1476
1477 return false;
1478 };
1479 /** how many seperate, non-empty words is it? */
1480
1481
1482 var wordCount = function wordCount() {
1483 return this.terms().filter(function (t) {
1484 return t.text !== '';
1485 }).length;
1486 };
1487 /** get the full-sentence this phrase belongs to */
1488
1489
1490 var fullSentence = function fullSentence() {
1491 var t = this.terms(0); //find first term in sentence
1492
1493 while (t.prev) {
1494 t = this.pool.get(t.prev);
1495 }
1496
1497 var start = t.id;
1498 var len = 1; //go to end of sentence
1499
1500 while (t.next) {
1501 t = this.pool.get(t.next);
1502 len += 1;
1503 }
1504
1505 return this.buildFrom(start, len);
1506 };
1507
1508 var _01Utils = {
1509 terms: terms,
1510 clone: clone,
1511 lastTerm: lastTerm,
1512 hasId: hasId,
1513 wordCount: wordCount,
1514 fullSentence: fullSentence
1515 };
1516
1517 var trimEnd = function trimEnd(str) {
1518 return str.replace(/ +$/, '');
1519 };
1520 /** produce output in the given format */
1521
1522
1523 var text = function text() {
1524 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1525 var isFirst = arguments.length > 1 ? arguments[1] : undefined;
1526 var isLast = arguments.length > 2 ? arguments[2] : undefined;
1527
1528 if (typeof options === 'string') {
1529 if (options === 'normal') {
1530 options = {
1531 whitespace: true,
1532 unicode: true,
1533 lowercase: true,
1534 punctuation: true,
1535 acronyms: true,
1536 abbreviations: true,
1537 implicit: true,
1538 normal: true
1539 };
1540 } else if (options === 'clean') {
1541 options = {
1542 titlecase: false,
1543 lowercase: true,
1544 punctuation: true,
1545 whitespace: true,
1546 unicode: true,
1547 implicit: true,
1548 normal: true
1549 };
1550 } else if (options === 'reduced') {
1551 options = {
1552 punctuation: false,
1553 //Hmm: is this reversed?
1554 titlecase: false,
1555 lowercase: true,
1556 whitespace: true,
1557 unicode: true,
1558 implicit: true,
1559 reduced: true
1560 };
1561 } else if (options === 'root') {
1562 options = {
1563 titlecase: false,
1564 lowercase: true,
1565 punctuation: true,
1566 whitespace: true,
1567 unicode: true,
1568 implicit: true,
1569 root: true
1570 };
1571 } else {
1572 options = {};
1573 }
1574 }
1575
1576 var terms = this.terms(); //this this phrase a complete sentence?
1577
1578 var isFull = false;
1579
1580 if (terms[0] && terms[0].prev === null && terms[terms.length - 1].next === null) {
1581 isFull = true;
1582 }
1583
1584 var text = terms.reduce(function (str, t, i) {
1585 options.last = isLast && i === terms.length - 1;
1586 var showPre = true;
1587 var showPost = true;
1588
1589 if (isFull === false) {
1590 // dont show beginning whitespace
1591 if (i === 0 && isFirst) {
1592 showPre = false;
1593 } // dont show end-whitespace
1594
1595
1596 if (i === terms.length - 1 && isLast) {
1597 showPost = false;
1598 }
1599 }
1600
1601 var txt = t.textOut(options, showPre, showPost); // if (options.titlecase && i === 0) {
1602 // txt = titleCase(txt)
1603 // }
1604
1605 return str + txt;
1606 }, ''); //full-phrases show punctuation, but not whitespace
1607
1608 if (isFull === true && isLast) {
1609 text = trimEnd(text);
1610 }
1611
1612 if (options.trim === true) {
1613 text = text.trim();
1614 }
1615
1616 return text;
1617 };
1618
1619 var _02Text = {
1620 text: text
1621 };
1622
1623 /** remove start and end whitespace */
1624 var trim = function trim() {
1625 var terms = this.terms();
1626
1627 if (terms.length > 0) {
1628 //trim starting
1629 terms[0].pre = terms[0].pre.replace(/^\s+/, ''); //trim ending
1630
1631 var lastTerm = terms[terms.length - 1];
1632 lastTerm.post = lastTerm.post.replace(/\s+$/, '');
1633 }
1634
1635 return this;
1636 };
1637
1638 var _03Change = {
1639 trim: trim
1640 };
1641
1642 var endOfSentence = /[.?!]\s*$/; // replacing a 'word.' with a 'word!'
1643
1644 var combinePost = function combinePost(before, after) {
1645 //only transfer the whitespace
1646 if (endOfSentence.test(after)) {
1647 var whitespace = before.match(/\s*$/);
1648 return after + whitespace;
1649 }
1650
1651 return before;
1652 }; //add whitespace to the start of the second bit
1653
1654
1655 var addWhitespace = function addWhitespace(beforeTerms, newTerms) {
1656 // add any existing pre-whitespace to beginning
1657 newTerms[0].pre = beforeTerms[0].pre;
1658 var lastTerm = beforeTerms[beforeTerms.length - 1]; //add any existing punctuation to end of our new terms
1659
1660 var newTerm = newTerms[newTerms.length - 1];
1661 newTerm.post = combinePost(lastTerm.post, newTerm.post); // remove existing punctuation
1662
1663 lastTerm.post = ''; //before ←[space] - after
1664
1665 if (lastTerm.post === '') {
1666 lastTerm.post += ' ';
1667 }
1668 }; //insert this segment into the linked-list
1669
1670
1671 var stitchIn = function stitchIn(beforeTerms, newTerms, pool) {
1672 var lastBefore = beforeTerms[beforeTerms.length - 1];
1673 var lastNew = newTerms[newTerms.length - 1];
1674 var afterId = lastBefore.next; //connect ours in (main → newPhrase)
1675
1676 lastBefore.next = newTerms[0].id; //stich the end in (newPhrase → after)
1677
1678 lastNew.next = afterId; //do it backwards, too
1679
1680 if (afterId) {
1681 // newPhrase ← after
1682 var afterTerm = pool.get(afterId);
1683 afterTerm.prev = lastNew.id;
1684 } // before ← newPhrase
1685
1686
1687 var beforeId = beforeTerms[0].id;
1688
1689 if (beforeId) {
1690 var newTerm = newTerms[0];
1691 newTerm.prev = beforeId;
1692 }
1693 }; // avoid stretching a phrase twice.
1694
1695
1696 var unique = function unique(list) {
1697 return list.filter(function (o, i) {
1698 return list.indexOf(o) === i;
1699 });
1700 }; //append one phrase onto another.
1701
1702
1703 var appendPhrase = function appendPhrase(before, newPhrase, doc) {
1704 var beforeTerms = before.terms();
1705 var newTerms = newPhrase.terms(); //spruce-up the whitespace issues
1706
1707 addWhitespace(beforeTerms, newTerms); //insert this segment into the linked-list
1708
1709 stitchIn(beforeTerms, newTerms, before.pool); // stretch!
1710 // make each effected phrase longer
1711
1712 var toStretch = [before];
1713 var hasId = before.start;
1714 var docs = [doc];
1715 docs = docs.concat(doc.parents()); // find them all!
1716
1717 docs.forEach(function (parent) {
1718 // only the phrases that should change
1719 var shouldChange = parent.list.filter(function (p) {
1720 return p.hasId(hasId);
1721 });
1722 toStretch = toStretch.concat(shouldChange);
1723 }); // don't double-count a phrase
1724
1725 toStretch = unique(toStretch);
1726 toStretch.forEach(function (p) {
1727 p.length += newPhrase.length;
1728 });
1729 before.cache = {};
1730 return before;
1731 };
1732
1733 var append = appendPhrase;
1734
1735 var hasSpace$1 = / /; //a new space needs to be added, either on the new phrase, or the old one
1736 // '[new] [◻old]' -or- '[old] [◻new] [old]'
1737
1738 var addWhitespace$1 = function addWhitespace(newTerms) {
1739 //add a space before our new text?
1740 // add a space after our text
1741 var lastTerm = newTerms[newTerms.length - 1];
1742
1743 if (hasSpace$1.test(lastTerm.post) === false) {
1744 lastTerm.post += ' ';
1745 }
1746
1747 return;
1748 }; //insert this segment into the linked-list
1749
1750
1751 var stitchIn$1 = function stitchIn(main, newPhrase, newTerms) {
1752 // [newPhrase] → [main]
1753 var lastTerm = newTerms[newTerms.length - 1];
1754 lastTerm.next = main.start; // [before] → [main]
1755
1756 var pool = main.pool;
1757 var start = pool.get(main.start);
1758
1759 if (start.prev) {
1760 var before = pool.get(start.prev);
1761 before.next = newPhrase.start;
1762 } //do it backwards, too
1763 // before ← newPhrase
1764
1765
1766 newTerms[0].prev = main.terms(0).prev; // newPhrase ← main
1767
1768 main.terms(0).prev = lastTerm.id;
1769 };
1770
1771 var unique$1 = function unique(list) {
1772 return list.filter(function (o, i) {
1773 return list.indexOf(o) === i;
1774 });
1775 }; //append one phrase onto another
1776
1777
1778 var joinPhrase = function joinPhrase(original, newPhrase, doc) {
1779 var starterId = original.start;
1780 var newTerms = newPhrase.terms(); //spruce-up the whitespace issues
1781
1782 addWhitespace$1(newTerms); //insert this segment into the linked-list
1783
1784 stitchIn$1(original, newPhrase, newTerms); //increase the length of our phrases
1785
1786 var toStretch = [original];
1787 var docs = [doc];
1788 docs = docs.concat(doc.parents());
1789 docs.forEach(function (d) {
1790 // only the phrases that should change
1791 var shouldChange = d.list.filter(function (p) {
1792 return p.hasId(starterId) || p.hasId(newPhrase.start);
1793 });
1794 toStretch = toStretch.concat(shouldChange);
1795 }); // don't double-count
1796
1797 toStretch = unique$1(toStretch); // stretch these phrases
1798
1799 toStretch.forEach(function (p) {
1800 p.length += newPhrase.length; // change the start too, if necessary
1801
1802 if (p.start === starterId) {
1803 p.start = newPhrase.start;
1804 }
1805
1806 p.cache = {};
1807 });
1808 return original;
1809 };
1810
1811 var prepend = joinPhrase;
1812
1813 //recursively decrease the length of all the parent phrases
1814 var shrinkAll = function shrinkAll(doc, id, deleteLength, after) {
1815 var arr = doc.parents();
1816 arr.push(doc);
1817 arr.forEach(function (d) {
1818 //find our phrase to shrink
1819 var phrase = d.list.find(function (p) {
1820 return p.hasId(id);
1821 });
1822
1823 if (!phrase) {
1824 return;
1825 }
1826
1827 phrase.length -= deleteLength; // does it start with this soon-removed word?
1828
1829 if (phrase.start === id) {
1830 phrase.start = after.id;
1831 }
1832
1833 phrase.cache = {};
1834 }); // cleanup empty phrase objects
1835
1836 doc.list = doc.list.filter(function (p) {
1837 if (!p.start || !p.length) {
1838 return false;
1839 }
1840
1841 return true;
1842 });
1843 };
1844 /** wrap the linked-list around these terms
1845 * so they don't appear any more
1846 */
1847
1848
1849 var deletePhrase = function deletePhrase(phrase, doc) {
1850 var pool = doc.pool();
1851 var terms = phrase.terms(); //grab both sides of the chain,
1852
1853 var prev = pool.get(terms[0].prev) || {};
1854 var after = pool.get(terms[terms.length - 1].next) || {};
1855
1856 if (terms[0].implicit && prev.implicit) {
1857 prev.set(prev.implicit);
1858 prev.post += ' ';
1859 } // //first, change phrase lengths
1860
1861
1862 shrinkAll(doc, phrase.start, phrase.length, after); // connect [prev]->[after]
1863
1864 if (prev) {
1865 prev.next = after.id;
1866 } // connect [prev]<-[after]
1867
1868
1869 if (after) {
1870 after.prev = prev.id;
1871 } // lastly, actually delete the terms from the pool?
1872 // for (let i = 0; i < terms.length; i++) {
1873 // pool.remove(terms[i].id)
1874 // }
1875
1876 };
1877
1878 var _delete = deletePhrase;
1879
1880 /** put this text at the end */
1881
1882 var append_1 = function append_1(newPhrase, doc) {
1883 append(this, newPhrase, doc);
1884 return this;
1885 };
1886 /** add this text to the beginning */
1887
1888
1889 var prepend_1 = function prepend_1(newPhrase, doc) {
1890 prepend(this, newPhrase, doc);
1891 return this;
1892 };
1893
1894 var _delete$1 = function _delete$1(doc) {
1895 _delete(this, doc);
1896 return this;
1897 }; // stich-in newPhrase, stretch 'doc' + parents
1898
1899
1900 var replace = function replace(newPhrase, doc) {
1901 //add it do the end
1902 var firstLength = this.length;
1903 append(this, newPhrase, doc); //delete original terms
1904
1905 var tmp = this.buildFrom(this.start, this.length);
1906 tmp.length = firstLength;
1907 _delete(tmp, doc);
1908 };
1909 /**
1910 * Turn this phrase object into 3 phrase objects
1911 */
1912
1913
1914 var splitOn = function splitOn(p) {
1915 var terms = this.terms();
1916 var result = {
1917 before: null,
1918 match: null,
1919 after: null
1920 };
1921 var index = terms.findIndex(function (t) {
1922 return t.id === p.start;
1923 });
1924
1925 if (index === -1) {
1926 return result;
1927 } //make all three sections into phrase-objects
1928
1929
1930 var start = terms.slice(0, index);
1931
1932 if (start.length > 0) {
1933 result.before = this.buildFrom(start[0].id, start.length);
1934 }
1935
1936 var match = terms.slice(index, index + p.length);
1937
1938 if (match.length > 0) {
1939 result.match = this.buildFrom(match[0].id, match.length);
1940 }
1941
1942 var end = terms.slice(index + p.length, terms.length);
1943
1944 if (end.length > 0) {
1945 result.after = this.buildFrom(end[0].id, end.length, this.pool);
1946 }
1947
1948 return result;
1949 };
1950
1951 var _04Insert = {
1952 append: append_1,
1953 prepend: prepend_1,
1954 "delete": _delete$1,
1955 replace: replace,
1956 splitOn: splitOn
1957 };
1958
1959 /** return json metadata for this phrase */
1960 var json$1 = function json() {
1961 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1962 var world = arguments.length > 1 ? arguments[1] : undefined;
1963 var res = {}; // text data
1964
1965 if (options.text) {
1966 res.text = this.text();
1967 }
1968
1969 if (options.normal) {
1970 res.normal = this.text('normal');
1971 }
1972
1973 if (options.clean) {
1974 res.clean = this.text('clean');
1975 }
1976
1977 if (options.reduced) {
1978 res.reduced = this.text('reduced');
1979 }
1980
1981 if (options.root) {
1982 res.root = this.text('root');
1983 }
1984
1985 if (options.trim) {
1986 if (res.text) {
1987 res.text = res.text.trim();
1988 }
1989
1990 if (res.normal) {
1991 res.normal = res.normal.trim();
1992 }
1993
1994 if (res.reduced) {
1995 res.reduced = res.reduced.trim();
1996 }
1997 } // terms data
1998
1999
2000 if (options.terms) {
2001 if (options.terms === true) {
2002 options.terms = {};
2003 }
2004
2005 res.terms = this.terms().map(function (t) {
2006 return t.json(options.terms, world);
2007 });
2008 }
2009
2010 return res;
2011 };
2012
2013 var _05Json$1 = {
2014 json: json$1
2015 };
2016
2017 /** match any terms after this phrase */
2018 var lookAhead = function lookAhead(regs) {
2019 // if empty match string, return everything after
2020 if (!regs) {
2021 regs = '.*';
2022 }
2023
2024 var pool = this.pool; // get a list of all terms preceding our start
2025
2026 var terms = [];
2027
2028 var getAfter = function getAfter(id) {
2029 var term = pool.get(id);
2030
2031 if (!term) {
2032 return;
2033 }
2034
2035 terms.push(term);
2036
2037 if (term.prev) {
2038 getAfter(term.next); //recursion
2039 }
2040 };
2041
2042 var all = this.terms();
2043 var lastTerm = all[all.length - 1];
2044 getAfter(lastTerm.next);
2045
2046 if (terms.length === 0) {
2047 return [];
2048 } // got the terms, make a phrase from them
2049
2050
2051 var p = this.buildFrom(terms[0].id, terms.length);
2052 return p.match(regs);
2053 };
2054 /** match any terms before this phrase */
2055
2056
2057 var lookBehind = function lookBehind(regs) {
2058 // if empty match string, return everything before
2059 if (!regs) {
2060 regs = '.*';
2061 }
2062
2063 var pool = this.pool; // get a list of all terms preceding our start
2064
2065 var terms = [];
2066
2067 var getBefore = function getBefore(id) {
2068 var term = pool.get(id);
2069
2070 if (!term) {
2071 return;
2072 }
2073
2074 terms.push(term);
2075
2076 if (term.prev) {
2077 getBefore(term.prev); //recursion
2078 }
2079 };
2080
2081 var term = pool.get(this.start);
2082 getBefore(term.prev);
2083
2084 if (terms.length === 0) {
2085 return [];
2086 } // got the terms, make a phrase from them
2087
2088
2089 var p = this.buildFrom(terms[terms.length - 1].id, terms.length);
2090 return p.match(regs);
2091 };
2092
2093 var _06Lookahead = {
2094 lookAhead: lookAhead,
2095 lookBehind: lookBehind
2096 };
2097
2098 var methods$1 = Object.assign({}, _01Utils, _02Text, _03Change, _04Insert, _05Json$1, _06Lookahead);
2099
2100 // try to avoid doing the match
2101 var failFast = function failFast(p, regs) {
2102 if (regs.length === 0) {
2103 return true;
2104 }
2105
2106 for (var i = 0; i < regs.length; i += 1) {
2107 var reg = regs[i]; //logical quick-ones
2108
2109 if (reg.optional !== true && reg.negative !== true) {
2110 //start/end impossibilites
2111 if (reg.start === true && i > 0) {
2112 return true;
2113 }
2114 } //this is not possible
2115
2116
2117 if (reg.anything === true && reg.negative === true) {
2118 return true;
2119 }
2120 }
2121
2122 return false;
2123 };
2124
2125 var _02FailFast = failFast;
2126
2127 var _matchLogic = createCommonjsModule(function (module, exports) {
2128 //found a match? it's greedy? keep going!
2129 exports.getGreedy = function (state, endReg) {
2130 // for greedy checking, we no longer care about the reg.start
2131 // value, and leaving it can cause failures for anchored greedy
2132 // matches. ditto for end-greedy matches: we need an earlier non-
2133 // ending match to succceed until we get to the actual end.
2134 var reg = Object.assign({}, state.regs[state.r], {
2135 start: false,
2136 end: false
2137 });
2138 var start = state.t;
2139
2140 for (; state.t < state.terms.length; state.t += 1) {
2141 //stop for next-reg match
2142 if (endReg && state.terms[state.t].doesMatch(endReg, state.start_i + state.t, state.phrase_length)) {
2143 return state.t;
2144 }
2145
2146 var count = state.t - start + 1; // is it max-length now?
2147
2148 if (reg.max !== undefined && count === reg.max) {
2149 return state.t;
2150 } //stop here
2151
2152
2153 if (state.terms[state.t].doesMatch(reg, state.start_i + state.t, state.phrase_length) === false) {
2154 // is it too short?
2155 if (reg.min !== undefined && count < reg.min) {
2156 return null;
2157 }
2158
2159 return state.t;
2160 }
2161 }
2162
2163 return state.t;
2164 }; //'unspecific greedy' is a weird situation.
2165
2166
2167 exports.greedyTo = function (state, nextReg) {
2168 var t = state.t; //if there's no next one, just go off the end!
2169
2170 if (!nextReg) {
2171 return state.terms.length;
2172 } //otherwise, we're looking for the next one
2173
2174
2175 for (; t < state.terms.length; t += 1) {
2176 if (state.terms[t].doesMatch(nextReg, state.start_i + t, state.phrase_length) === true) {
2177 return t;
2178 }
2179 } //guess it doesn't exist, then.
2180
2181
2182 return null;
2183 }; //we have a special case where an end-anchored greedy match may need to
2184 //start matching before the actual end; we do this by (temporarily!)
2185 //removing the "end" property from the matching token... since this is
2186 //very situation-specific, we *only* do this when we really need to.
2187
2188
2189 exports.isEndGreedy = function (reg, state) {
2190 if (reg.end === true && reg.greedy === true) {
2191 if (state.start_i + state.t < state.phrase_length - 1) {
2192 var tmpReg = Object.assign({}, reg, {
2193 end: false
2194 });
2195
2196 if (state.terms[state.t].doesMatch(tmpReg, state.start_i + state.t, state.phrase_length) === true) {
2197 return true;
2198 }
2199 }
2200 }
2201
2202 if (state.terms[state.t].doesMatch(reg, state.start_i + state.t, state.phrase_length) === true) {
2203 return true;
2204 }
2205
2206 return false;
2207 }; // match complex OR cases like (a|b|foo bar)
2208
2209
2210 exports.doOrBlock = function (state) {
2211 var skipN = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
2212 var reg = state.regs[state.r];
2213 var wasFound = false; // do each multiword sequence
2214
2215 for (var c = 0; c < reg.choices.length; c += 1) {
2216 // try to match this list of tokens
2217 var block = reg.choices[c];
2218 wasFound = block.every(function (cr, w_index) {
2219 var tryTerm = state.t + w_index + skipN;
2220
2221 if (state.terms[tryTerm] === undefined) {
2222 return false;
2223 }
2224
2225 return state.terms[tryTerm].doesMatch(cr, tryTerm + state.start_i, state.phrase_length);
2226 });
2227
2228 if (wasFound) {
2229 skipN += block.length;
2230 break;
2231 }
2232 } // we found a match - is it greedy though?
2233
2234
2235 if (wasFound && reg.greedy === true) {
2236 return exports.doOrBlock(state, skipN); // try it again!
2237 }
2238
2239 return skipN;
2240 }; // match AND cases like (#Noun && foo)
2241
2242
2243 exports.doAndBlock = function (state) {
2244 var longest = 0; // all blocks must match, and we return the greediest match
2245
2246 var reg = state.regs[state.r];
2247 var allDidMatch = reg.choices.every(function (block) {
2248 // for multi-word blocks, all must match
2249 var allWords = block.every(function (cr, w_index) {
2250 var tryTerm = state.t + w_index;
2251
2252 if (state.terms[tryTerm] === undefined) {
2253 return false;
2254 }
2255
2256 return state.terms[tryTerm].doesMatch(cr, tryTerm, state.phrase_length);
2257 });
2258
2259 if (allWords === true && block.length > longest) {
2260 longest = block.length;
2261 }
2262
2263 return allWords;
2264 });
2265
2266 if (allDidMatch === true) {
2267 return longest;
2268 }
2269
2270 return false;
2271 }; // get or create named group
2272
2273
2274 exports.getGroup = function (state, term_index, name) {
2275 if (state.groups[state.groupId]) {
2276 return state.groups[state.groupId];
2277 }
2278
2279 var termId = state.terms[term_index].id;
2280 state.groups[state.groupId] = {
2281 group: String(name),
2282 start: termId,
2283 length: 0
2284 };
2285 return state.groups[state.groupId];
2286 };
2287 });
2288
2289 /** tries to match a sequence of terms, starting from here */
2290
2291 var tryHere = function tryHere(terms, regs, start_i, phrase_length) {
2292 // all the variables that matter
2293 var state = {
2294 t: 0,
2295 //the term index we're on
2296 terms: terms,
2297 //the working slice of term objects
2298 r: 0,
2299 // the reg index we're on
2300 regs: regs,
2301 //our match conditions
2302 groups: {},
2303 //all named-group matches
2304 start_i: start_i,
2305 // term index we're starting from
2306 phrase_length: phrase_length,
2307 // # of terms in the sentence
2308 hasGroup: false,
2309 groupId: null,
2310 previousGroup: null
2311 }; // we must satisfy each rule in 'regs'
2312
2313 for (; state.r < regs.length; state.r += 1) {
2314 var reg = regs[state.r]; // Check if this reg has a named capture group
2315
2316 state.hasGroup = typeof reg.named === 'string' || typeof reg.named === 'number'; // Reuse previous capture group if same
2317
2318 if (state.hasGroup === true) {
2319 var prev = regs[state.r - 1];
2320
2321 if (prev && prev.named === reg.named && state.previousGroup) {
2322 state.groupId = state.previousGroup;
2323 } else {
2324 state.groupId = _id(reg.named);
2325 state.previousGroup = state.groupId;
2326 }
2327 } //hve we run-out of terms?
2328
2329
2330 if (!state.terms[state.t]) {
2331 //are all remaining regs optional?
2332 var haveNeeds = regs.slice(state.r).some(function (remain) {
2333 return !remain.optional;
2334 });
2335
2336 if (haveNeeds === false) {
2337 break; //done!
2338 }
2339
2340 return null; // die
2341 } //support 'unspecific greedy' .* properly
2342
2343
2344 if (reg.anything === true && reg.greedy === true) {
2345 var skipto = _matchLogic.greedyTo(state, regs[state.r + 1]); // ensure it's long enough
2346
2347 if (reg.min !== undefined && skipto - state.t < reg.min) {
2348 return null;
2349 } // reduce it back, if it's too long
2350
2351
2352 if (reg.max !== undefined && skipto - state.t > reg.max) {
2353 state.t = state.t + reg.max;
2354 continue;
2355 }
2356
2357 if (skipto === null) {
2358 return null; //couldn't find it
2359 } // is it really this easy?....
2360
2361
2362 if (state.hasGroup === true) {
2363 var g = _matchLogic.getGroup(state, state.t, reg.named);
2364 g.length = skipto - state.t;
2365 }
2366
2367 state.t = skipto;
2368 continue;
2369 } // support multi-word OR (a|b|foo bar)
2370
2371
2372 if (reg.choices !== undefined && reg.operator === 'or') {
2373 var skipNum = _matchLogic.doOrBlock(state);
2374
2375 if (skipNum) {
2376 // handle 'not' logic
2377 if (reg.negative === true) {
2378 return null; // die
2379 }
2380
2381 if (state.hasGroup === true) {
2382 var _g = _matchLogic.getGroup(state, state.t, reg.named);
2383
2384 _g.length += skipNum;
2385 }
2386
2387 state.t += skipNum;
2388 continue;
2389 } else if (!reg.optional) {
2390 return null; //die
2391 }
2392 } // support AND (#Noun && foo) blocks
2393
2394
2395 if (reg.choices !== undefined && reg.operator === 'and') {
2396 var _skipNum = _matchLogic.doAndBlock(state);
2397
2398 if (_skipNum) {
2399 // handle 'not' logic
2400 if (reg.negative === true) {
2401 return null; // die
2402 }
2403
2404 if (state.hasGroup === true) {
2405 var _g2 = _matchLogic.getGroup(state, state.t, reg.named);
2406
2407 _g2.length += _skipNum;
2408 }
2409
2410 state.t += _skipNum;
2411 continue;
2412 } else if (!reg.optional) {
2413 return null; //die
2414 }
2415 }
2416
2417 if (reg.anything === true || _matchLogic.isEndGreedy(reg, state)) {
2418 var startAt = state.t; // okay, it was a match, but if it optional too,
2419 // we should check the next reg too, to skip it?
2420
2421 if (reg.optional && regs[state.r + 1]) {
2422 // does the next reg match it too?
2423 if (state.terms[state.t].doesMatch(regs[state.r + 1], state.start_i + state.t, state.phrase_length)) {
2424 // but does the next reg match the next term??
2425 // only skip if it doesn't
2426 if (!state.terms[state.t + 1] || !state.terms[state.t + 1].doesMatch(regs[state.r + 1], state.start_i + state.t, state.phrase_length)) {
2427 state.r += 1;
2428 }
2429 }
2430 } //advance to the next term!
2431
2432
2433 state.t += 1; //check any ending '$' flags
2434
2435 if (reg.end === true) {
2436 //if this isn't the last term, refuse the match
2437 if (state.t !== state.terms.length && reg.greedy !== true) {
2438 return null; //die
2439 }
2440 } //try keep it going!
2441
2442
2443 if (reg.greedy === true) {
2444 state.t = _matchLogic.getGreedy(state, regs[state.r + 1]);
2445
2446 if (state.t === null) {
2447 return null; //greedy was too short
2448 }
2449
2450 if (reg.min && reg.min > state.t) {
2451 return null; //greedy was too short
2452 } // if this was also an end-anchor match, check to see we really
2453 // reached the end
2454
2455
2456 if (reg.end === true && state.start_i + state.t !== phrase_length) {
2457 return null; //greedy didn't reach the end
2458 }
2459 }
2460
2461 if (state.hasGroup === true) {
2462 // Get or create capture group
2463 var _g3 = _matchLogic.getGroup(state, startAt, reg.named); // Update group - add greedy or increment length
2464
2465
2466 if (state.t > 1 && reg.greedy) {
2467 _g3.length += state.t - startAt;
2468 } else {
2469 _g3.length++;
2470 }
2471 }
2472
2473 continue;
2474 } //bah, who cares, keep going
2475
2476
2477 if (reg.optional === true) {
2478 continue;
2479 } // should we skip-over an implicit word?
2480
2481
2482 if (state.terms[state.t].isImplicit() && regs[state.r - 1] && state.terms[state.t + 1]) {
2483 // does the next one match?
2484 if (state.terms[state.t + 1].doesMatch(reg, state.start_i + state.t, state.phrase_length)) {
2485 state.t += 2;
2486 continue;
2487 }
2488 }
2489
2490 return null; //die
2491 } //return our result
2492
2493
2494 return {
2495 match: state.terms.slice(0, state.t),
2496 groups: state.groups
2497 };
2498 };
2499
2500 var _03TryMatch = tryHere;
2501
2502 // final checks on the validity of our results
2503 var postProcess = function postProcess(terms, regs, matches) {
2504 if (!matches || matches.length === 0) {
2505 return matches;
2506 } // ensure end reg has the end term
2507
2508
2509 var atEnd = regs.some(function (r) {
2510 return r.end;
2511 });
2512
2513 if (atEnd) {
2514 var lastTerm = terms[terms.length - 1];
2515 matches = matches.filter(function (_ref) {
2516 var arr = _ref.match;
2517 return arr.indexOf(lastTerm) !== -1;
2518 });
2519 }
2520
2521 return matches;
2522 };
2523
2524 var _04PostProcess = postProcess;
2525
2526 /* break-down a match expression into this:
2527 {
2528 word:'',
2529 tag:'',
2530 regex:'',
2531
2532 start:false,
2533 end:false,
2534 negative:false,
2535 anything:false,
2536 greedy:false,
2537 optional:false,
2538
2539 named:'',
2540 choices:[],
2541 }
2542 */
2543 var hasMinMax = /\{([0-9]+,?[0-9]*)\}/;
2544 var andSign = /&&/;
2545 var captureName = new RegExp(/^<(\S+)>/);
2546
2547 var titleCase$2 = function titleCase(str) {
2548 return str.charAt(0).toUpperCase() + str.substr(1);
2549 };
2550
2551 var end = function end(str) {
2552 return str[str.length - 1];
2553 };
2554
2555 var start = function start(str) {
2556 return str[0];
2557 };
2558
2559 var stripStart = function stripStart(str) {
2560 return str.substr(1);
2561 };
2562
2563 var stripEnd = function stripEnd(str) {
2564 return str.substr(0, str.length - 1);
2565 };
2566
2567 var stripBoth = function stripBoth(str) {
2568 str = stripStart(str);
2569 str = stripEnd(str);
2570 return str;
2571 }; //
2572
2573
2574 var parseToken = function parseToken(w) {
2575 var obj = {}; //collect any flags (do it twice)
2576
2577 for (var i = 0; i < 2; i += 1) {
2578 //end-flag
2579 if (end(w) === '$') {
2580 obj.end = true;
2581 w = stripEnd(w);
2582 } //front-flag
2583
2584
2585 if (start(w) === '^') {
2586 obj.start = true;
2587 w = stripStart(w);
2588 } //capture group (this one can span multiple-terms)
2589
2590
2591 if (start(w) === '[' || end(w) === ']') {
2592 obj.named = true;
2593
2594 if (start(w) === '[') {
2595 obj.groupType = end(w) === ']' ? 'single' : 'start';
2596 } else {
2597 obj.groupType = 'end';
2598 }
2599
2600 w = w.replace(/^\[/, '');
2601 w = w.replace(/\]$/, ''); // Use capture group name
2602
2603 if (start(w) === '<') {
2604 var res = captureName.exec(w);
2605
2606 if (res.length >= 2) {
2607 obj.named = res[1];
2608 w = w.replace(res[0], '');
2609 }
2610 }
2611 } //back-flags
2612
2613
2614 if (end(w) === '+') {
2615 obj.greedy = true;
2616 w = stripEnd(w);
2617 }
2618
2619 if (w !== '*' && end(w) === '*' && w !== '\\*') {
2620 obj.greedy = true;
2621 w = stripEnd(w);
2622 }
2623
2624 if (end(w) === '?') {
2625 obj.optional = true;
2626 w = stripEnd(w);
2627 }
2628
2629 if (start(w) === '!') {
2630 obj.negative = true; // obj.optional = true
2631
2632 w = stripStart(w);
2633 } //wrapped-flags
2634
2635
2636 if (start(w) === '(' && end(w) === ')') {
2637 // support (one && two)
2638 if (andSign.test(w)) {
2639 obj.choices = w.split(andSign);
2640 obj.operator = 'and';
2641 } else {
2642 obj.choices = w.split('|');
2643 obj.operator = 'or';
2644 } //remove '(' and ')'
2645
2646
2647 obj.choices[0] = stripStart(obj.choices[0]);
2648 var last = obj.choices.length - 1;
2649 obj.choices[last] = stripEnd(obj.choices[last]); // clean up the results
2650
2651 obj.choices = obj.choices.map(function (s) {
2652 return s.trim();
2653 });
2654 obj.choices = obj.choices.filter(function (s) {
2655 return s;
2656 }); //recursion alert!
2657
2658 obj.choices = obj.choices.map(function (str) {
2659 return str.split(/ /g).map(parseToken);
2660 });
2661 w = '';
2662 } //regex
2663
2664
2665 if (start(w) === '/' && end(w) === '/') {
2666 w = stripBoth(w);
2667 obj.regex = new RegExp(w); //potential vuln - security/detect-non-literal-regexp
2668
2669 return obj;
2670 } //soft-match
2671
2672
2673 if (start(w) === '~' && end(w) === '~') {
2674 w = stripBoth(w);
2675 obj.soft = true;
2676 obj.word = w;
2677 return obj;
2678 }
2679 } // support #Tag{1,9}
2680
2681
2682 if (hasMinMax.test(w) === true) {
2683 w = w.replace(hasMinMax, function (a, b) {
2684 var arr = b.split(/,/g);
2685
2686 if (arr.length === 1) {
2687 // '{3}' Exactly three times
2688 obj.min = Number(arr[0]);
2689 obj.max = Number(arr[0]);
2690 } else {
2691 // '{2,4}' Two to four times
2692 // '{3,}' Three or more times
2693 obj.min = Number(arr[0]);
2694 obj.max = Number(arr[1] || 999);
2695 } // use same method as '+'
2696
2697
2698 obj.greedy = true; // 0 as min means the same as '?'
2699
2700 obj.optional = true;
2701 return '';
2702 });
2703 } //do the actual token content
2704
2705
2706 if (start(w) === '#') {
2707 obj.tag = stripStart(w);
2708 obj.tag = titleCase$2(obj.tag);
2709 return obj;
2710 } //dynamic function on a term object
2711
2712
2713 if (start(w) === '@') {
2714 obj.method = stripStart(w);
2715 return obj;
2716 }
2717
2718 if (w === '.') {
2719 obj.anything = true;
2720 return obj;
2721 } //support alone-astrix
2722
2723
2724 if (w === '*') {
2725 obj.anything = true;
2726 obj.greedy = true;
2727 obj.optional = true;
2728 return obj;
2729 }
2730
2731 if (w) {
2732 //somehow handle encoded-chars?
2733 w = w.replace('\\*', '*');
2734 w = w.replace('\\.', '.');
2735 obj.word = w.toLowerCase();
2736 }
2737
2738 return obj;
2739 };
2740
2741 var _01ParseToken = parseToken;
2742
2743 // name any [unnamed] capture-groups with a number
2744 var nameGroups = function nameGroups(tokens) {
2745 var convert = false;
2746 var index = -1;
2747 var current; //'fill in' capture groups between start-end
2748
2749 for (var i = 0; i < tokens.length; i++) {
2750 var token = tokens[i]; // Give name to un-named single tokens
2751
2752 if (token.groupType === 'single' && token.named === true) {
2753 index += 1;
2754 token.named = index;
2755 continue;
2756 } // Start converting tokens
2757
2758
2759 if (token.groupType === 'start') {
2760 convert = true;
2761
2762 if (typeof token.named === 'string' || typeof token.named === 'number') {
2763 current = token.named;
2764 } else {
2765 index += 1;
2766 current = index;
2767 }
2768 } // Ensure this token has the right name
2769
2770
2771 if (convert) {
2772 token.named = current;
2773 } // Stop converting tokens
2774
2775
2776 if (token.groupType === 'end') {
2777 convert = false;
2778 }
2779 }
2780
2781 return tokens;
2782 }; // optimize an 'or' lookup, when the (a|b|c) list is simple or multi-word
2783
2784
2785 var doFastOrMode = function doFastOrMode(tokens) {
2786 return tokens.map(function (token) {
2787 if (token.choices !== undefined) {
2788 // are they all straight-up words? then optimize them.
2789 var shouldPack = token.choices.every(function (block) {
2790 if (block.length !== 1) {
2791 return false;
2792 }
2793
2794 var reg = block[0];
2795
2796 if (reg.word !== undefined && reg.negative !== true && reg.optional !== true && reg.method !== true) {
2797 return true; //reg is simple-enough
2798 }
2799
2800 return false;
2801 });
2802
2803 if (shouldPack === true) {
2804 var oneOf = {};
2805 token.choices.forEach(function (block) {
2806 oneOf[block[0].word] = true;
2807 });
2808 token.fastOr = oneOf;
2809 delete token.choices;
2810 }
2811 }
2812
2813 return token;
2814 });
2815 }; // allow multiword OR (foo|one two)
2816 // const doMultiWord = function (tokens) {
2817 // return tokens.map(token => {
2818 // if (token.choices !== undefined) {
2819 // let isMulti = token.choices.find(o => hasASpace.test(o.word)) || false
2820 // if (isMulti !== false) {
2821 // token.multiword = true
2822 // // turn all choices into arrays
2823 // token.choices = token.choices.map(choice => {
2824 // if (choice.word) {
2825 // choice.sequence = choice.word.split(hasASpace)
2826 // delete choice.word
2827 // }
2828 // return choice
2829 // })
2830 // }
2831 // }
2832 // return token
2833 // })
2834 // }
2835 // const doBlockMode = function (tokens) {
2836 // return tokens.map(token => {
2837 // // we've already setup fastOr mode
2838 // if (token.choices !== undefined) {
2839 // // console.log(token)
2840 // }
2841 // return token
2842 // })
2843 // }
2844
2845
2846 var postProcess$1 = function postProcess(tokens) {
2847 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2848 // ensure all capture groups are filled between start and end
2849 // give all capture groups names
2850 var count = tokens.filter(function (t) {
2851 return t.groupType;
2852 }).length;
2853
2854 if (count > 0) {
2855 tokens = nameGroups(tokens);
2856 } // convert 'choices' format to 'fastOr' format
2857
2858
2859 if (!opts.fuzzy) {
2860 tokens = doFastOrMode(tokens);
2861 } // support multiword OR (foo bar|baz)
2862 // tokens = doMultiWord(tokens)
2863 // support (one two three)
2864 // tokens = doBlockMode(tokens)
2865
2866
2867 return tokens;
2868 };
2869
2870 var _02PostProcess = postProcess$1;
2871
2872 var hasReg = /[^[a-z]]\//g;
2873
2874 var isArray$1 = function isArray(arr) {
2875 return Object.prototype.toString.call(arr) === '[object Array]';
2876 }; // don't split up a regular expression
2877
2878
2879 var mergeRegexes = function mergeRegexes(arr) {
2880 arr.forEach(function (s, i) {
2881 var m = s.match(hasReg); // has 1 slash
2882
2883 if (m !== null && m.length === 1 && arr[i + 1]) {
2884 // merge next one
2885 arr[i] += arr[i + 1];
2886 arr[i + 1] = ''; // try 2nd one
2887
2888 m = arr[i].match(hasReg);
2889
2890 if (m !== null && m.length === 1) {
2891 arr[i] += arr[i + 2];
2892 arr[i + 2] = '';
2893 }
2894 }
2895 });
2896 arr = arr.filter(function (s) {
2897 return s;
2898 });
2899 return arr;
2900 }; //split-up by (these things)
2901
2902
2903 var byParentheses = function byParentheses(str) {
2904 var arr = str.split(/([\^\[\!]*(?:<\S+>)?\(.*?\)[?+*]*\]?\$?)/);
2905 arr = arr.map(function (s) {
2906 return s.trim();
2907 });
2908
2909 if (hasReg.test(str)) {
2910 arr = mergeRegexes(arr);
2911 }
2912
2913 return arr;
2914 };
2915
2916 var byWords = function byWords(arr) {
2917 var words = [];
2918 arr.forEach(function (a) {
2919 //keep brackets lumped together
2920 if (/\(.*\)/.test(a)) {
2921 words.push(a);
2922 return;
2923 }
2924
2925 var list = a.split(' ');
2926 list = list.filter(function (w) {
2927 return w;
2928 });
2929 words = words.concat(list);
2930 });
2931 return words;
2932 }; //turn an array into a 'choices' list
2933
2934
2935 var byArray = function byArray(arr) {
2936 var blocks = arr.map(function (s) {
2937 return [{
2938 word: s
2939 }];
2940 });
2941 return [{
2942 choices: blocks,
2943 operator: 'or'
2944 }];
2945 }; // turn a Doc object into a reg of ids to lookup
2946
2947
2948 var fromDoc = function fromDoc(doc) {
2949 if (!doc || !doc.list || !doc.list[0]) {
2950 return [];
2951 }
2952
2953 var regs = [];
2954 doc.list.forEach(function (p) {
2955 var ids = [];
2956 p.terms().forEach(function (t) {
2957 ids.push(t.id);
2958 });
2959 regs.push(ids);
2960 });
2961 return [{
2962 idBlocks: regs
2963 }];
2964 }; // add fuzziness etc to each reg
2965
2966
2967 var addOptions = function addOptions(tokens, opts) {
2968 // add default fuzzy-search limit
2969 if (opts.fuzzy === true) {
2970 opts.fuzzy = 0.85;
2971 }
2972
2973 if (typeof opts.fuzzy === 'number') {
2974 tokens = tokens.map(function (reg) {
2975 // add a fuzzy-match on 'word' tokens
2976 if (opts.fuzzy > 0 && reg.word) {
2977 reg.fuzzy = opts.fuzzy;
2978 } //add it to or|and choices too
2979
2980
2981 if (reg.choices) {
2982 reg.choices.forEach(function (block) {
2983 block.forEach(function (r) {
2984 r.fuzzy = opts.fuzzy;
2985 });
2986 });
2987 }
2988
2989 return reg;
2990 });
2991 }
2992
2993 return tokens;
2994 };
2995 /** parse a match-syntax string into json */
2996
2997
2998 var syntax = function syntax(input) {
2999 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
3000
3001 // fail-fast
3002 if (input === null || input === undefined || input === '') {
3003 return [];
3004 } //try to support a ton of different formats:
3005
3006
3007 if (_typeof(input) === 'object') {
3008 if (isArray$1(input)) {
3009 if (input.length === 0 || !input[0]) {
3010 return [];
3011 } //is it a pre-parsed reg-list?
3012
3013
3014 if (_typeof(input[0]) === 'object') {
3015 return input;
3016 } //support a flat array of normalized words
3017
3018
3019 if (typeof input[0] === 'string') {
3020 return byArray(input);
3021 }
3022 } //support passing-in a compromise object as a match
3023
3024
3025 if (input && input.isA === 'Doc') {
3026 return fromDoc(input);
3027 }
3028
3029 return [];
3030 }
3031
3032 if (typeof input === 'number') {
3033 input = String(input); //go for it?
3034 }
3035
3036 var tokens = byParentheses(input); // console.log(tokens)
3037
3038 tokens = byWords(tokens);
3039 tokens = tokens.map(function (str) {
3040 return _01ParseToken(str);
3041 }); //clean up anything weird
3042
3043 tokens = _02PostProcess(tokens, opts); // add fuzzy limits, etc
3044
3045 tokens = addOptions(tokens, opts); // console.log(tokens)
3046
3047 return tokens;
3048 };
3049
3050 var matchSyntax = syntax; // console.log(syntax('before [(united states|canadian)] after'))
3051
3052 // match an explicit sequence of term ids
3053 // take a phrase and find any of the idBlocks in it
3054 var idLookup = function idLookup(terms, regs) {
3055 var matches = [];
3056 var blocklist = regs[0].idBlocks;
3057
3058 var _loop = function _loop(_t) {
3059 blocklist.forEach(function (block) {
3060 if (block.length === 0) {
3061 t = _t;
3062 return;
3063 }
3064
3065 var foundAll = block.every(function (id, i) {
3066 t = _t;
3067 return terms[_t + i].id === id;
3068 });
3069
3070 if (foundAll) {
3071 matches.push({
3072 match: terms.slice(_t, _t + block.length)
3073 }); // skip top-loop forward
3074
3075 _t += block.length - 1;
3076 }
3077 });
3078 t = _t;
3079 };
3080
3081 for (var t = 0; t < terms.length; t += 1) {
3082 _loop(t);
3083 }
3084
3085 return matches;
3086 };
3087
3088 var idLookup_1 = idLookup;
3089
3090 /** returns a simple array of arrays */
3091
3092 var matchAll = function matchAll(p, regs) {
3093 var matchOne = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
3094
3095 //if we forgot to parse it..
3096 if (typeof regs === 'string') {
3097 regs = matchSyntax(regs);
3098 } //try to dismiss it, at-once
3099
3100
3101 if (_02FailFast(p, regs) === true) {
3102 return [];
3103 } //any match needs to be this long, at least
3104
3105
3106 var minLength = regs.filter(function (r) {
3107 return r.optional !== true && r.negative !== true;
3108 }).length;
3109 var terms = p.terms();
3110 var matches = []; // these id-lookups can be super-fast
3111
3112 if (regs[0].idBlocks) {
3113 var res = idLookup_1(terms, regs);
3114
3115 if (res && res.length > 0) {
3116 return _04PostProcess(terms, regs, res);
3117 }
3118 } //optimisation for '^' start logic
3119
3120
3121 if (regs[0].start === true) {
3122 var _res = _03TryMatch(terms, regs, 0, terms.length);
3123
3124 if (_res && _res.match && _res.match.length > 0) {
3125 _res.match = _res.match.filter(function (m) {
3126 return m;
3127 });
3128 matches.push(_res);
3129 }
3130
3131 return _04PostProcess(terms, regs, matches);
3132 } //try starting, from every term
3133
3134
3135 for (var i = 0; i < terms.length; i += 1) {
3136 // slice may be too short
3137 if (i + minLength > terms.length) {
3138 break;
3139 } //try it!
3140
3141
3142 var _res2 = _03TryMatch(terms.slice(i), regs, i, terms.length);
3143
3144 if (_res2 && _res2.match && _res2.match.length > 0) {
3145 //zoom forward!
3146 i += _res2.match.length - 1; //[capture-groups] return some null responses
3147
3148 _res2.match = _res2.match.filter(function (m) {
3149 return m;
3150 });
3151 matches.push(_res2); //ok, maybe that's enough?
3152
3153 if (matchOne === true) {
3154 return _04PostProcess(terms, regs, matches);
3155 }
3156 }
3157 }
3158
3159 return _04PostProcess(terms, regs, matches);
3160 };
3161
3162 var _01MatchAll = matchAll;
3163
3164 /** return anything that doesn't match.
3165 * returns a simple array of arrays
3166 */
3167
3168 var notMatch = function notMatch(p, regs) {
3169 var found = {};
3170 var arr = _01MatchAll(p, regs);
3171 arr.forEach(function (_ref) {
3172 var ts = _ref.match;
3173 ts.forEach(function (t) {
3174 found[t.id] = true;
3175 });
3176 }); //return anything not found
3177
3178 var terms = p.terms();
3179 var result = [];
3180 var current = [];
3181 terms.forEach(function (t) {
3182 if (found[t.id] === true) {
3183 if (current.length > 0) {
3184 result.push(current);
3185 current = [];
3186 }
3187
3188 return;
3189 }
3190
3191 current.push(t);
3192 });
3193
3194 if (current.length > 0) {
3195 result.push(current);
3196 }
3197
3198 return result;
3199 };
3200
3201 var not = notMatch;
3202
3203 /** return an array of matching phrases */
3204
3205 var match_1 = function match_1(regs) {
3206 var _this = this;
3207
3208 var justOne = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
3209 var matches = _01MatchAll(this, regs, justOne); //make them phrase objects
3210
3211 matches = matches.map(function (_ref) {
3212 var match = _ref.match,
3213 groups = _ref.groups;
3214
3215 var p = _this.buildFrom(match[0].id, match.length, groups);
3216
3217 p.cache.terms = match;
3218 return p;
3219 });
3220 return matches;
3221 };
3222 /** return boolean if one match is found */
3223
3224
3225 var has = function has(regs) {
3226 var matches = _01MatchAll(this, regs, true);
3227 return matches.length > 0;
3228 };
3229 /** remove all matches from the result */
3230
3231
3232 var not$1 = function not$1(regs) {
3233 var _this2 = this;
3234
3235 var matches = not(this, regs); //make them phrase objects
3236
3237 matches = matches.map(function (list) {
3238 return _this2.buildFrom(list[0].id, list.length);
3239 });
3240 return matches;
3241 };
3242 /** return a list of phrases that can have this tag */
3243
3244
3245 var canBe$1 = function canBe(tag, world) {
3246 var _this3 = this;
3247
3248 var results = [];
3249 var terms = this.terms();
3250 var previous = false;
3251
3252 for (var i = 0; i < terms.length; i += 1) {
3253 var can = terms[i].canBe(tag, world);
3254
3255 if (can === true) {
3256 if (previous === true) {
3257 //add it to the end
3258 results[results.length - 1].push(terms[i]);
3259 } else {
3260 results.push([terms[i]]); //make a new one
3261 }
3262
3263 previous = can;
3264 }
3265 } //turn them into Phrase objects
3266
3267
3268 results = results.filter(function (a) {
3269 return a.length > 0;
3270 }).map(function (arr) {
3271 return _this3.buildFrom(arr[0].id, arr.length);
3272 });
3273 return results;
3274 };
3275
3276 var match = {
3277 match: match_1,
3278 has: has,
3279 not: not$1,
3280 canBe: canBe$1
3281 };
3282
3283 var Phrase = function Phrase(id, length, pool) {
3284 _classCallCheck(this, Phrase);
3285
3286 this.start = id;
3287 this.length = length;
3288 this.isA = 'Phrase'; // easier than .constructor...
3289
3290 Object.defineProperty(this, 'pool', {
3291 enumerable: false,
3292 writable: true,
3293 value: pool
3294 });
3295 Object.defineProperty(this, 'cache', {
3296 enumerable: false,
3297 writable: true,
3298 value: {}
3299 });
3300 Object.defineProperty(this, 'groups', {
3301 enumerable: false,
3302 writable: true,
3303 value: {}
3304 });
3305 };
3306 /** create a new Phrase object from an id and length */
3307
3308
3309 Phrase.prototype.buildFrom = function (id, length, groups) {
3310 var p = new Phrase(id, length, this.pool); //copy-over or replace capture-groups too
3311
3312 if (groups && Object.keys(groups).length > 0) {
3313 p.groups = groups;
3314 } else {
3315 p.groups = this.groups;
3316 }
3317
3318 return p;
3319 }; //apply methods
3320
3321
3322 Object.assign(Phrase.prototype, match);
3323 Object.assign(Phrase.prototype, methods$1); //apply aliases
3324
3325 var aliases = {
3326 term: 'terms'
3327 };
3328 Object.keys(aliases).forEach(function (k) {
3329 return Phrase.prototype[k] = Phrase.prototype[aliases[k]];
3330 });
3331 var Phrase_1 = Phrase;
3332
3333 /** a key-value store of all terms in our Document */
3334 var Pool = /*#__PURE__*/function () {
3335 function Pool() {
3336 var words = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
3337
3338 _classCallCheck(this, Pool);
3339
3340 //quiet this property in console.logs
3341 Object.defineProperty(this, 'words', {
3342 enumerable: false,
3343 value: words
3344 });
3345 }
3346 /** throw a new term object in */
3347
3348
3349 _createClass(Pool, [{
3350 key: "add",
3351 value: function add(term) {
3352 this.words[term.id] = term;
3353 return this;
3354 }
3355 /** find a term by it's id */
3356
3357 }, {
3358 key: "get",
3359 value: function get(id) {
3360 return this.words[id];
3361 }
3362 /** find a term by it's id */
3363
3364 }, {
3365 key: "remove",
3366 value: function remove(id) {
3367 delete this.words[id];
3368 }
3369 }, {
3370 key: "merge",
3371 value: function merge(pool) {
3372 Object.assign(this.words, pool.words);
3373 return this;
3374 }
3375 /** helper method */
3376
3377 }, {
3378 key: "stats",
3379 value: function stats() {
3380 return {
3381 words: Object.keys(this.words).length
3382 };
3383 }
3384 }]);
3385
3386 return Pool;
3387 }();
3388 /** make a deep-copy of all terms */
3389
3390
3391 Pool.prototype.clone = function () {
3392 var _this = this;
3393
3394 var keys = Object.keys(this.words);
3395 var words = keys.reduce(function (h, k) {
3396 var t = _this.words[k].clone();
3397
3398 h[t.id] = t;
3399 return h;
3400 }, {});
3401 return new Pool(words);
3402 };
3403
3404 var Pool_1 = Pool;
3405
3406 //add forward/backward 'linked-list' prev/next ids
3407 var linkTerms = function linkTerms(terms) {
3408 terms.forEach(function (term, i) {
3409 if (i > 0) {
3410 term.prev = terms[i - 1].id;
3411 }
3412
3413 if (terms[i + 1]) {
3414 term.next = terms[i + 1].id;
3415 }
3416 });
3417 };
3418
3419 var _linkTerms = linkTerms;
3420
3421 //(Rule-based sentence boundary segmentation) - chop given text into its proper sentences.
3422 // Ignore periods/questions/exclamations used in acronyms/abbreviations/numbers, etc.
3423 // @spencermountain 2017 MIT
3424 //proper nouns with exclamation marks
3425 // const blacklist = {
3426 // yahoo: true,
3427 // joomla: true,
3428 // jeopardy: true,
3429 // }
3430 //regs-
3431 var initSplit = /(\S.+?[.!?\u203D\u2E18\u203C\u2047-\u2049])(?=\s+|$)/g;
3432 var hasSomething = /\S/;
3433 var isAcronym$1 = /[ .][A-Z]\.? *$/i;
3434 var hasEllipse = /(?:\u2026|\.{2,}) *$/;
3435 var newLine = /((?:\r?\n|\r)+)/; // Match different new-line formats
3436
3437 var hasLetter = /[a-z0-9\u00C0-\u00FF\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]/i;
3438 var startWhitespace = /^\s+/; // Start with a regex:
3439
3440 var naiive_split = function naiive_split(text) {
3441 var all = []; //first, split by newline
3442
3443 var lines = text.split(newLine);
3444
3445 for (var i = 0; i < lines.length; i++) {
3446 //split by period, question-mark, and exclamation-mark
3447 var arr = lines[i].split(initSplit);
3448
3449 for (var o = 0; o < arr.length; o++) {
3450 all.push(arr[o]);
3451 }
3452 }
3453
3454 return all;
3455 };
3456 /** does this look like a sentence? */
3457
3458
3459 var isSentence = function isSentence(str, abbrevs) {
3460 // check for 'F.B.I.'
3461 if (isAcronym$1.test(str) === true) {
3462 return false;
3463 } //check for '...'
3464
3465
3466 if (hasEllipse.test(str) === true) {
3467 return false;
3468 } // must have a letter
3469
3470
3471 if (hasLetter.test(str) === false) {
3472 return false;
3473 }
3474
3475 var txt = str.replace(/[.!?\u203D\u2E18\u203C\u2047-\u2049] *$/, '');
3476 var words = txt.split(' ');
3477 var lastWord = words[words.length - 1].toLowerCase(); // check for 'Mr.'
3478
3479 if (abbrevs.hasOwnProperty(lastWord)) {
3480 return false;
3481 } // //check for jeopardy!
3482 // if (blacklist.hasOwnProperty(lastWord)) {
3483 // return false
3484 // }
3485
3486
3487 return true;
3488 };
3489
3490 var splitSentences = function splitSentences(text, world) {
3491 var abbrevs = world.cache.abbreviations;
3492 text = text || '';
3493 text = String(text);
3494 var sentences = []; // First do a greedy-split..
3495
3496 var chunks = []; // Ensure it 'smells like' a sentence
3497
3498 if (!text || typeof text !== 'string' || hasSomething.test(text) === false) {
3499 return sentences;
3500 } // cleanup unicode-spaces
3501
3502
3503 text = text.replace('\xa0', ' '); // Start somewhere:
3504
3505 var splits = naiive_split(text); // Filter-out the crap ones
3506
3507 for (var i = 0; i < splits.length; i++) {
3508 var s = splits[i];
3509
3510 if (s === undefined || s === '') {
3511 continue;
3512 } //this is meaningful whitespace
3513
3514
3515 if (hasSomething.test(s) === false) {
3516 //add it to the last one
3517 if (chunks[chunks.length - 1]) {
3518 chunks[chunks.length - 1] += s;
3519 continue;
3520 } else if (splits[i + 1]) {
3521 //add it to the next one
3522 splits[i + 1] = s + splits[i + 1];
3523 continue;
3524 }
3525 } //else, only whitespace, no terms, no sentence
3526
3527
3528 chunks.push(s);
3529 } //detection of non-sentence chunks:
3530 //loop through these chunks, and join the non-sentence chunks back together..
3531
3532
3533 for (var _i = 0; _i < chunks.length; _i++) {
3534 var c = chunks[_i]; //should this chunk be combined with the next one?
3535
3536 if (chunks[_i + 1] && isSentence(c, abbrevs) === false) {
3537 chunks[_i + 1] = c + (chunks[_i + 1] || '');
3538 } else if (c && c.length > 0) {
3539 //&& hasLetter.test(c)
3540 //this chunk is a proper sentence..
3541 sentences.push(c);
3542 chunks[_i] = '';
3543 }
3544 } //if we never got a sentence, return the given text
3545
3546
3547 if (sentences.length === 0) {
3548 return [text];
3549 } //move whitespace to the ends of sentences, when possible
3550 //['hello',' world'] -> ['hello ','world']
3551
3552
3553 for (var _i2 = 1; _i2 < sentences.length; _i2 += 1) {
3554 var ws = sentences[_i2].match(startWhitespace);
3555
3556 if (ws !== null) {
3557 sentences[_i2 - 1] += ws[0];
3558 sentences[_i2] = sentences[_i2].replace(startWhitespace, '');
3559 }
3560 }
3561
3562 return sentences;
3563 };
3564
3565 var _01Sentences = splitSentences; // console.log(sentence_parser('john f. kennedy'));
3566
3567 var wordlike = /\S/;
3568 var isBoundary = /^[!?.]+$/;
3569 var naiiveSplit = /(\S+)/;
3570 var isSlash = /[a-z] ?\/ ?[a-z]*$/;
3571 var notWord = ['.', '?', '!', ':', ';', '-', '–', '—', '--', '...', '(', ')', '[', ']', '"', "'", '`'];
3572 notWord = notWord.reduce(function (h, c) {
3573 h[c] = true;
3574 return h;
3575 }, {});
3576
3577 var hasHyphen = function hasHyphen(str) {
3578 //dont split 're-do'
3579 if (/^(re|un)-?[^aeiou]./.test(str) === true) {
3580 return false;
3581 } //letter-number 'aug-20'
3582
3583
3584 var reg = /^([a-z\u00C0-\u00FF`"'/]+)(-|–|—)([a-z0-9\u00C0-\u00FF].*)/i;
3585
3586 if (reg.test(str) === true) {
3587 return true;
3588 } //number-letter '20-aug'
3589
3590
3591 var reg2 = /^([0-9]{1,4})(-|–|—)([a-z\u00C0-\u00FF`"'/-]+$)/i;
3592
3593 if (reg2.test(str) === true) {
3594 return true;
3595 } //support weird number-emdash combo '2010–2011'
3596 // let reg2 = /^([0-9]+)(–|—)([0-9].*)/i
3597 // if (reg2.test(str)) {
3598 // return true
3599 // }
3600
3601
3602 return false;
3603 }; // 'he / she' should be one word
3604
3605
3606 var combineSlashes = function combineSlashes(arr) {
3607 for (var i = 1; i < arr.length - 1; i++) {
3608 if (isSlash.test(arr[i])) {
3609 arr[i - 1] += arr[i] + arr[i + 1];
3610 arr[i] = null;
3611 arr[i + 1] = null;
3612 }
3613 }
3614
3615 return arr;
3616 };
3617
3618 var splitHyphens = function splitHyphens(word) {
3619 var arr = []; //support multiple-hyphenated-terms
3620
3621 var hyphens = word.split(/[-–—]/);
3622 var whichDash = '-';
3623 var found = word.match(/[-–—]/);
3624
3625 if (found && found[0]) {
3626 whichDash = found;
3627 }
3628
3629 for (var o = 0; o < hyphens.length; o++) {
3630 if (o === hyphens.length - 1) {
3631 arr.push(hyphens[o]);
3632 } else {
3633 arr.push(hyphens[o] + whichDash);
3634 }
3635 }
3636
3637 return arr;
3638 };
3639
3640 var isArray$2 = function isArray(arr) {
3641 return Object.prototype.toString.call(arr) === '[object Array]';
3642 }; //turn a string into an array of strings (naiive for now, lumped later)
3643
3644
3645 var splitWords = function splitWords(str) {
3646 var result = [];
3647 var arr = []; //start with a naiive split
3648
3649 str = str || '';
3650
3651 if (typeof str === 'number') {
3652 str = String(str);
3653 }
3654
3655 if (isArray$2(str)) {
3656 return str;
3657 }
3658
3659 var words = str.split(naiiveSplit);
3660
3661 for (var i = 0; i < words.length; i++) {
3662 //split 'one-two'
3663 if (hasHyphen(words[i]) === true) {
3664 arr = arr.concat(splitHyphens(words[i]));
3665 continue;
3666 }
3667
3668 arr.push(words[i]);
3669 } //greedy merge whitespace+arr to the right
3670
3671
3672 var carry = '';
3673
3674 for (var _i = 0; _i < arr.length; _i++) {
3675 var word = arr[_i]; //if it's more than a whitespace
3676
3677 if (wordlike.test(word) === true && notWord.hasOwnProperty(word) === false && isBoundary.test(word) === false) {
3678 //put whitespace on end of previous term, if possible
3679 if (result.length > 0) {
3680 result[result.length - 1] += carry;
3681 result.push(word);
3682 } else {
3683 //otherwise, but whitespace before
3684 result.push(carry + word);
3685 }
3686
3687 carry = '';
3688 } else {
3689 carry += word;
3690 }
3691 } //handle last one
3692
3693
3694 if (carry) {
3695 if (result.length === 0) {
3696 result[0] = '';
3697 }
3698
3699 result[result.length - 1] += carry; //put it on the end
3700 } // combine 'one / two'
3701
3702
3703 result = combineSlashes(result); // remove empty results
3704
3705 result = result.filter(function (s) {
3706 return s;
3707 });
3708 return result;
3709 };
3710
3711 var _02Words = splitWords;
3712
3713 var isArray$3 = function isArray(arr) {
3714 return Object.prototype.toString.call(arr) === '[object Array]';
3715 };
3716 /** turn a string into an array of Phrase objects */
3717
3718
3719 var fromText = function fromText() {
3720 var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
3721 var world = arguments.length > 1 ? arguments[1] : undefined;
3722 var pool = arguments.length > 2 ? arguments[2] : undefined;
3723 var sentences = null; //a bit of validation, first
3724
3725 if (typeof text !== 'string') {
3726 if (typeof text === 'number') {
3727 text = String(text);
3728 } else if (isArray$3(text)) {
3729 sentences = text;
3730 }
3731 } //tokenize into words
3732
3733
3734 sentences = sentences || _01Sentences(text, world);
3735 sentences = sentences.map(function (str) {
3736 return _02Words(str);
3737 }); //turn them into proper objects
3738
3739 pool = pool || new Pool_1();
3740 var phrases = sentences.map(function (terms) {
3741 terms = terms.map(function (str) {
3742 var term = new Term_1(str);
3743 pool.add(term);
3744 return term;
3745 }); //add next/previous ids
3746
3747 _linkTerms(terms); //return phrase objects
3748
3749 var p = new Phrase_1(terms[0].id, terms.length, pool);
3750 p.cache.terms = terms;
3751 return p;
3752 }); //return them ready for a Document object
3753
3754 return phrases;
3755 };
3756
3757 var _01Tokenizer = fromText;
3758
3759 var fromJSON = function fromJSON(json, world) {
3760 var pool = new Pool_1();
3761 var phrases = json.map(function (p, k) {
3762 var terms = p.terms.map(function (o, i) {
3763 var term = new Term_1(o.text);
3764 term.pre = o.pre !== undefined ? o.pre : '';
3765
3766 if (o.post === undefined) {
3767 o.post = ' '; //no given space for very last term
3768
3769 if (i >= p.terms.length - 1) {
3770 o.post = '. ';
3771
3772 if (k >= p.terms.length - 1) {
3773 o.post = '.';
3774 }
3775 }
3776 }
3777
3778 term.post = o.post !== undefined ? o.post : ' ';
3779
3780 if (o.tags) {
3781 o.tags.forEach(function (tag) {
3782 return term.tag(tag, '', world);
3783 });
3784 }
3785
3786 pool.add(term);
3787 return term;
3788 }); //add prev/next links
3789
3790 _linkTerms(terms); // return a proper Phrase object
3791
3792 return new Phrase_1(terms[0].id, terms.length, pool);
3793 });
3794 return phrases;
3795 };
3796
3797 var fromJSON_1 = fromJSON;
3798
3799 var _version = '13.9.0';
3800
3801 var _data = {
3802 "Comparative": "true¦better",
3803 "Superlative": "true¦earlier",
3804 "PresentTense": "true¦is,sounds",
3805 "Value": "true¦a few",
3806 "Noun": "true¦a5b4c2f1here,ie,lit,m0no doubt,pd,tce;a,d;t,y;a,ca,o0;l,rp;a,l;d,l,rc",
3807 "Copula": "true¦a1is,w0;as,ere;m,re",
3808 "PastTense": "true¦be3came,d2had,lied,meant,sa2taken,w0;as,e0;nt,re;id;en,gan",
3809 "Condition": "true¦if,lest,unless",
3810 "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",
3811 "Gerund": "true¦accord0be0develop0go0result0stain0;ing",
3812 "Negative": "true¦n0;ever,o0;!n,t",
3813 "QuestionWord": "true¦how3wh0;at,e1ich,o0y;!m,se;n,re; come,'s",
3814 "Plural": "true¦records",
3815 "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",
3816 "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",
3817 "Pronoun": "true¦'em,elle,h4i3me,ourselves,she5th1us,we,you0;!rself;e0ou;m,y;!l,t;e0im;!'s",
3818 "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",
3819 "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",
3820 "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",
3821 "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",
3822 "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",
3823 "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",
3824 "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",
3825 "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",
3826 "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",
3827 "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",
3828 "Possessive": "true¦anyAh5its,m3noCo1sometBthe0yo1;ir1mselves;ur0;!s;i8y0;!se4;er1i0;mse2s;!s0;!e0;lf;o1t0;hing;ne",
3829 "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",
3830 "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",
3831 "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",
3832 "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",
3833 "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",
3834 "WeekDay": "true¦fri2mon2s1t0wednesd3;hurs1ues1;aturd1und1;!d0;ay0;!s",
3835 "Month": "true¦aBdec9feb7j2mar,nov9oct1sep0;!t8;!o8;an3u0;l1n0;!e;!y;!u1;!ru0;ary;!em0;ber;pr1ug0;!ust;!il",
3836 "Date": "true¦ago,t2week0yesterd4; e0e0;nd;mr2o0;d0morrow;ay;!w",
3837 "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",
3838 "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",
3839 "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",
3840 "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",
3841 "Verb": "true¦awak9born,cannot,fr8g7h5k3le2m1s0wors9;e8h3;ake sure,sg;ngth6ss6;eep tabs,n0;own;as0e2;!t2;iv1onna;ight0;en",
3842 "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",
3843 "Modal": "true¦c5lets,m4ought3sh1w0;ill,o5;a0o4;ll,nt;! to,a;ay,ight,ust;an,o0;uld",
3844 "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",
3845 "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",
3846 "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",
3847 "Ordinal": "true¦bGeDf9hundredHmGnin7qu6s4t0zeroH;enGh1rFwe0;lfFn9;ir0ousandE;d,t4;e0ixt9;cond,ptAvent8xtA;adr9int9;et0th;e6ie8;i2o0;r0urt3;tie5;ft1rst;ight0lev1;e0h,ie2;en1;illion0;th",
3848 "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",
3849 "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",
3850 "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",
3851 "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"
3852 };
3853
3854 var entity = ['Person', 'Place', 'Organization'];
3855 var nouns = {
3856 Noun: {
3857 notA: ['Verb', 'Adjective', 'Adverb']
3858 },
3859 // - singular
3860 Singular: {
3861 isA: 'Noun',
3862 notA: 'Plural'
3863 },
3864 //a specific thing that's capitalized
3865 ProperNoun: {
3866 isA: 'Noun'
3867 },
3868 // -- people
3869 Person: {
3870 isA: ['ProperNoun', 'Singular'],
3871 notA: ['Place', 'Organization', 'Date']
3872 },
3873 FirstName: {
3874 isA: 'Person'
3875 },
3876 MaleName: {
3877 isA: 'FirstName',
3878 notA: ['FemaleName', 'LastName']
3879 },
3880 FemaleName: {
3881 isA: 'FirstName',
3882 notA: ['MaleName', 'LastName']
3883 },
3884 LastName: {
3885 isA: 'Person',
3886 notA: ['FirstName']
3887 },
3888 NickName: {
3889 isA: 'Person',
3890 notA: ['FirstName', 'LastName']
3891 },
3892 Honorific: {
3893 isA: 'Noun',
3894 notA: ['FirstName', 'LastName', 'Value']
3895 },
3896 // -- places
3897 Place: {
3898 isA: 'Singular',
3899 notA: ['Person', 'Organization']
3900 },
3901 Country: {
3902 isA: ['Place', 'ProperNoun'],
3903 notA: ['City']
3904 },
3905 City: {
3906 isA: ['Place', 'ProperNoun'],
3907 notA: ['Country']
3908 },
3909 Region: {
3910 isA: ['Place', 'ProperNoun']
3911 },
3912 Address: {
3913 isA: 'Place'
3914 },
3915 //---Orgs---
3916 Organization: {
3917 isA: ['Singular', 'ProperNoun'],
3918 notA: ['Person', 'Place']
3919 },
3920 SportsTeam: {
3921 isA: 'Organization'
3922 },
3923 School: {
3924 isA: 'Organization'
3925 },
3926 Company: {
3927 isA: 'Organization'
3928 },
3929 // - plural
3930 Plural: {
3931 isA: 'Noun',
3932 notA: ['Singular']
3933 },
3934 //(not plural or singular)
3935 Uncountable: {
3936 isA: 'Noun'
3937 },
3938 Pronoun: {
3939 isA: 'Noun',
3940 notA: entity
3941 },
3942 //a word for someone doing something -'plumber'
3943 Actor: {
3944 isA: 'Noun',
3945 notA: entity
3946 },
3947 //a gerund-as-noun - 'swimming'
3948 Activity: {
3949 isA: 'Noun',
3950 notA: ['Person', 'Place']
3951 },
3952 //'kilograms'
3953 Unit: {
3954 isA: 'Noun',
3955 notA: entity
3956 },
3957 //'Canadians'
3958 Demonym: {
3959 isA: ['Noun', 'ProperNoun'],
3960 notA: entity
3961 },
3962 //`john's`
3963 Possessive: {
3964 isA: 'Noun' // notA: 'Pronoun',
3965
3966 }
3967 };
3968
3969 var verbs = {
3970 Verb: {
3971 notA: ['Noun', 'Adjective', 'Adverb', 'Value']
3972 },
3973 // walks
3974 PresentTense: {
3975 isA: 'Verb',
3976 notA: ['PastTense', 'FutureTense']
3977 },
3978 // neutral form - 'walk'
3979 Infinitive: {
3980 isA: 'PresentTense',
3981 notA: ['PastTense', 'Gerund']
3982 },
3983 // walking
3984 Gerund: {
3985 isA: 'PresentTense',
3986 notA: ['PastTense', 'Copula', 'FutureTense']
3987 },
3988 // walked
3989 PastTense: {
3990 isA: 'Verb',
3991 notA: ['FutureTense']
3992 },
3993 // will walk
3994 FutureTense: {
3995 isA: 'Verb'
3996 },
3997 // is
3998 Copula: {
3999 isA: 'Verb'
4000 },
4001 // would have
4002 Modal: {
4003 isA: 'Verb',
4004 notA: ['Infinitive']
4005 },
4006 // had walked
4007 PerfectTense: {
4008 isA: 'Verb',
4009 notA: 'Gerund'
4010 },
4011 Pluperfect: {
4012 isA: 'Verb'
4013 },
4014 // shown
4015 Participle: {
4016 isA: 'PastTense'
4017 },
4018 // show up
4019 PhrasalVerb: {
4020 isA: 'Verb'
4021 },
4022 //'up' part
4023 Particle: {
4024 isA: 'PhrasalVerb'
4025 },
4026 //this can be an adverb
4027 Auxiliary: {
4028 notA: ['Noun', 'Adjective', 'Value']
4029 }
4030 };
4031
4032 var values = {
4033 Value: {
4034 notA: ['Verb', 'Adjective', 'Adverb']
4035 },
4036 Ordinal: {
4037 isA: 'Value',
4038 notA: ['Cardinal']
4039 },
4040 Cardinal: {
4041 isA: 'Value',
4042 notA: ['Ordinal']
4043 },
4044 RomanNumeral: {
4045 isA: 'Cardinal',
4046 //can be a person, too
4047 notA: ['Ordinal', 'TextValue']
4048 },
4049 TextValue: {
4050 isA: 'Value',
4051 notA: ['NumericValue']
4052 },
4053 NumericValue: {
4054 isA: 'Value',
4055 notA: ['TextValue']
4056 },
4057 Money: {
4058 isA: 'Cardinal'
4059 },
4060 Percent: {
4061 isA: 'Value'
4062 }
4063 };
4064
4065 var anything = ['Noun', 'Verb', 'Adjective', 'Adverb', 'Value', 'QuestionWord'];
4066 var misc = {
4067 //--Adjectives--
4068 Adjective: {
4069 notA: ['Noun', 'Verb', 'Adverb', 'Value']
4070 },
4071 // adjectives that can conjugate
4072 Comparable: {
4073 isA: ['Adjective']
4074 },
4075 // better
4076 Comparative: {
4077 isA: ['Adjective']
4078 },
4079 // best
4080 Superlative: {
4081 isA: ['Adjective'],
4082 notA: ['Comparative']
4083 },
4084 NumberRange: {
4085 isA: ['Contraction']
4086 },
4087 Adverb: {
4088 notA: ['Noun', 'Verb', 'Adjective', 'Value']
4089 },
4090 // Dates:
4091 //not a noun, but usually is
4092 Date: {
4093 notA: ['Verb', 'Conjunction', 'Adverb', 'Preposition', 'Adjective']
4094 },
4095 Month: {
4096 isA: ['Date', 'Singular'],
4097 notA: ['Year', 'WeekDay', 'Time']
4098 },
4099 WeekDay: {
4100 isA: ['Date', 'Noun']
4101 },
4102 // '9:20pm'
4103 Time: {
4104 isA: ['Date'],
4105 notA: ['AtMention']
4106 },
4107 //glue
4108 Determiner: {
4109 notA: anything
4110 },
4111 Conjunction: {
4112 notA: anything
4113 },
4114 Preposition: {
4115 notA: anything
4116 },
4117 // what, who, why
4118 QuestionWord: {
4119 notA: ['Determiner']
4120 },
4121 // peso, euro
4122 Currency: {
4123 isA: ['Noun']
4124 },
4125 // ughh
4126 Expression: {
4127 notA: ['Noun', 'Adjective', 'Verb', 'Adverb']
4128 },
4129 // dr.
4130 Abbreviation: {},
4131 // internet tags
4132 Url: {
4133 notA: ['HashTag', 'PhoneNumber', 'Verb', 'Adjective', 'Value', 'AtMention', 'Email']
4134 },
4135 PhoneNumber: {
4136 notA: ['HashTag', 'Verb', 'Adjective', 'Value', 'AtMention', 'Email']
4137 },
4138 HashTag: {},
4139 AtMention: {
4140 isA: ['Noun'],
4141 notA: ['HashTag', 'Verb', 'Adjective', 'Value', 'Email']
4142 },
4143 Emoji: {
4144 notA: ['HashTag', 'Verb', 'Adjective', 'Value', 'AtMention']
4145 },
4146 Emoticon: {
4147 notA: ['HashTag', 'Verb', 'Adjective', 'Value', 'AtMention']
4148 },
4149 Email: {
4150 notA: ['HashTag', 'Verb', 'Adjective', 'Value', 'AtMention']
4151 },
4152 //non-exclusive
4153 Acronym: {
4154 notA: ['Plural', 'RomanNumeral']
4155 },
4156 Negative: {
4157 notA: ['Noun', 'Adjective', 'Value']
4158 },
4159 // if, unless, were
4160 Condition: {
4161 notA: ['Verb', 'Adjective', 'Noun', 'Value']
4162 }
4163 };
4164
4165 // i just made these up
4166 var colorMap = {
4167 Noun: 'blue',
4168 Verb: 'green',
4169 Negative: 'green',
4170 Date: 'red',
4171 Value: 'red',
4172 Adjective: 'magenta',
4173 Preposition: 'cyan',
4174 Conjunction: 'cyan',
4175 Determiner: 'cyan',
4176 Adverb: 'cyan'
4177 };
4178 /** add a debug color to some tags */
4179
4180 var addColors = function addColors(tags) {
4181 Object.keys(tags).forEach(function (k) {
4182 // assigned from plugin, for example
4183 if (tags[k].color) {
4184 tags[k].color = tags[k].color;
4185 return;
4186 } // defined above
4187
4188
4189 if (colorMap[k]) {
4190 tags[k].color = colorMap[k];
4191 return;
4192 }
4193
4194 tags[k].isA.some(function (t) {
4195 if (colorMap[t]) {
4196 tags[k].color = colorMap[t];
4197 return true;
4198 }
4199
4200 return false;
4201 });
4202 });
4203 return tags;
4204 };
4205
4206 var _color = addColors;
4207
4208 var unique$2 = function unique(arr) {
4209 return arr.filter(function (v, i, a) {
4210 return a.indexOf(v) === i;
4211 });
4212 }; //add 'downward' tags (that immediately depend on this one)
4213
4214
4215 var inferIsA = function inferIsA(tags) {
4216 Object.keys(tags).forEach(function (k) {
4217 var tag = tags[k];
4218 var len = tag.isA.length;
4219
4220 for (var i = 0; i < len; i++) {
4221 var down = tag.isA[i];
4222
4223 if (tags[down]) {
4224 tag.isA = tag.isA.concat(tags[down].isA);
4225 }
4226 } // clean it up
4227
4228
4229 tag.isA = unique$2(tag.isA);
4230 });
4231 return tags;
4232 };
4233
4234 var _isA = inferIsA;
4235
4236 var unique$3 = function unique(arr) {
4237 return arr.filter(function (v, i, a) {
4238 return a.indexOf(v) === i;
4239 });
4240 }; // crawl the tag-graph and infer any conflicts
4241 // faster than doing this at tag-time
4242
4243
4244 var inferNotA = function inferNotA(tags) {
4245 var keys = Object.keys(tags);
4246 keys.forEach(function (k) {
4247 var tag = tags[k];
4248 tag.notA = tag.notA || [];
4249 tag.isA.forEach(function (down) {
4250 if (tags[down] && tags[down].notA) {
4251 // borrow its conflicts
4252 var notA = typeof tags[down].notA === 'string' ? [tags[down].isA] : tags[down].notA || [];
4253 tag.notA = tag.notA.concat(notA);
4254 }
4255 }); // any tag that lists us as a conflict, we conflict it back.
4256
4257 for (var i = 0; i < keys.length; i++) {
4258 var key = keys[i];
4259
4260 if (tags[key].notA.indexOf(k) !== -1) {
4261 tag.notA.push(key);
4262 }
4263 } // clean it up
4264
4265
4266 tag.notA = unique$3(tag.notA);
4267 });
4268 return tags;
4269 };
4270
4271 var _notA = inferNotA;
4272
4273 // a lineage is all 'incoming' tags that have this as 'isA'
4274 var inferLineage = function inferLineage(tags) {
4275 var keys = Object.keys(tags);
4276 keys.forEach(function (k) {
4277 var tag = tags[k];
4278 tag.lineage = []; // find all tags with it in their 'isA' set
4279
4280 for (var i = 0; i < keys.length; i++) {
4281 if (tags[keys[i]].isA.indexOf(k) !== -1) {
4282 tag.lineage.push(keys[i]);
4283 }
4284 }
4285 });
4286 return tags;
4287 };
4288
4289 var _lineage = inferLineage;
4290
4291 var validate = function validate(tags) {
4292 // cleanup format
4293 Object.keys(tags).forEach(function (k) {
4294 var tag = tags[k]; // ensure isA is an array
4295
4296 tag.isA = tag.isA || [];
4297
4298 if (typeof tag.isA === 'string') {
4299 tag.isA = [tag.isA];
4300 } // ensure notA is an array
4301
4302
4303 tag.notA = tag.notA || [];
4304
4305 if (typeof tag.notA === 'string') {
4306 tag.notA = [tag.notA];
4307 }
4308 });
4309 return tags;
4310 }; // build-out the tag-graph structure
4311
4312
4313 var inferTags = function inferTags(tags) {
4314 // validate data
4315 tags = validate(tags); // build its 'down tags'
4316
4317 tags = _isA(tags); // infer the conflicts
4318
4319 tags = _notA(tags); // debug tag color
4320
4321 tags = _color(tags); // find incoming links
4322
4323 tags = _lineage(tags);
4324 return tags;
4325 };
4326
4327 var inference = inferTags;
4328
4329 var addIn = function addIn(obj, tags) {
4330 Object.keys(obj).forEach(function (k) {
4331 tags[k] = obj[k];
4332 });
4333 };
4334
4335 var build = function build() {
4336 var tags = {};
4337 addIn(nouns, tags);
4338 addIn(verbs, tags);
4339 addIn(values, tags);
4340 addIn(misc, tags); // do the graph-stuff
4341
4342 tags = inference(tags);
4343 return tags;
4344 };
4345
4346 var tags = build();
4347
4348 var seq = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
4349 cache = seq.split("").reduce(function (n, o, e) {
4350 return n[o] = e, n;
4351 }, {}),
4352 toAlphaCode = function toAlphaCode(n) {
4353 if (void 0 !== seq[n]) return seq[n];
4354 var o = 1,
4355 e = 36,
4356 t = "";
4357
4358 for (; n >= e; n -= e, o++, e *= 36) {
4359 }
4360
4361 for (; o--;) {
4362 var _o = n % 36;
4363
4364 t = String.fromCharCode((_o < 10 ? 48 : 55) + _o) + t, n = (n - _o) / 36;
4365 }
4366
4367 return t;
4368 },
4369 fromAlphaCode = function fromAlphaCode(n) {
4370 if (void 0 !== cache[n]) return cache[n];
4371 var o = 0,
4372 e = 1,
4373 t = 36,
4374 r = 1;
4375
4376 for (; e < n.length; o += t, e++, t *= 36) {
4377 }
4378
4379 for (var _e = n.length - 1; _e >= 0; _e--, r *= 36) {
4380 var _t = n.charCodeAt(_e) - 48;
4381
4382 _t > 10 && (_t -= 7), o += _t * r;
4383 }
4384
4385 return o;
4386 };
4387
4388 var encoding = {
4389 toAlphaCode: toAlphaCode,
4390 fromAlphaCode: fromAlphaCode
4391 },
4392 symbols = function symbols(n) {
4393 var o = new RegExp("([0-9A-Z]+):([0-9A-Z]+)");
4394
4395 for (var e = 0; e < n.nodes.length; e++) {
4396 var t = o.exec(n.nodes[e]);
4397
4398 if (!t) {
4399 n.symCount = e;
4400 break;
4401 }
4402
4403 n.syms[encoding.fromAlphaCode(t[1])] = encoding.fromAlphaCode(t[2]);
4404 }
4405
4406 n.nodes = n.nodes.slice(n.symCount, n.nodes.length);
4407 };
4408
4409 var indexFromRef = function indexFromRef(n, o, e) {
4410 var t = encoding.fromAlphaCode(o);
4411 return t < n.symCount ? n.syms[t] : e + t + 1 - n.symCount;
4412 },
4413 toArray = function toArray(n) {
4414 var o = [],
4415 e = function e(t, r) {
4416 var s = n.nodes[t];
4417 "!" === s[0] && (o.push(r), s = s.slice(1));
4418 var c = s.split(/([A-Z0-9,]+)/g);
4419
4420 for (var _s = 0; _s < c.length; _s += 2) {
4421 var u = c[_s],
4422 i = c[_s + 1];
4423 if (!u) continue;
4424 var l = r + u;
4425
4426 if ("," === i || void 0 === i) {
4427 o.push(l);
4428 continue;
4429 }
4430
4431 var f = indexFromRef(n, i, t);
4432 e(f, l);
4433 }
4434 };
4435
4436 return e(0, ""), o;
4437 },
4438 unpack = function unpack(n) {
4439 var o = {
4440 nodes: n.split(";"),
4441 syms: [],
4442 symCount: 0
4443 };
4444 return n.match(":") && symbols(o), toArray(o);
4445 };
4446
4447 var unpack_1 = unpack,
4448 unpack_1$1 = function unpack_1$1(n) {
4449 var o = n.split("|").reduce(function (n, o) {
4450 var e = o.split("¦");
4451 return n[e[0]] = e[1], n;
4452 }, {}),
4453 e = {};
4454 return Object.keys(o).forEach(function (n) {
4455 var t = unpack_1(o[n]);
4456 "true" === n && (n = !0);
4457
4458 for (var _o2 = 0; _o2 < t.length; _o2++) {
4459 var r = t[_o2];
4460 !0 === e.hasOwnProperty(r) ? !1 === Array.isArray(e[r]) ? e[r] = [e[r], n] : e[r].push(n) : e[r] = n;
4461 }
4462 }), e;
4463 };
4464
4465 var efrtUnpack_min = unpack_1$1;
4466
4467 //safely add it to the lexicon
4468 var addWord = function addWord(word, tag, lex) {
4469 if (lex[word] !== undefined) {
4470 if (typeof lex[word] === 'string') {
4471 lex[word] = [lex[word]];
4472 }
4473
4474 if (typeof tag === 'string') {
4475 lex[word].push(tag);
4476 } else {
4477 lex[word] = lex[word].concat(tag);
4478 }
4479 } else {
4480 lex[word] = tag;
4481 }
4482 }; // blast-out more forms for some given words
4483
4484
4485 var addMore = function addMore(word, tag, world) {
4486 var lexicon = world.words;
4487 var transform = world.transforms; // cache multi-words
4488
4489 var words = word.split(' ');
4490
4491 if (words.length > 1) {
4492 //cache the beginning word
4493 world.hasCompound[words[0]] = true;
4494 } // inflect our nouns
4495
4496
4497 if (tag === 'Singular') {
4498 var plural = transform.toPlural(word, world);
4499 lexicon[plural] = lexicon[plural] || 'Plural'; // only if it's safe
4500 } //conjugate our verbs
4501
4502
4503 if (tag === 'Infinitive') {
4504 var conj = transform.conjugate(word, world);
4505 var tags = Object.keys(conj);
4506
4507 for (var i = 0; i < tags.length; i++) {
4508 var w = conj[tags[i]];
4509 lexicon[w] = lexicon[w] || tags[i]; // only if it's safe
4510 }
4511 } //derive more adjective forms
4512
4513
4514 if (tag === 'Comparable') {
4515 var _conj = transform.adjectives(word);
4516
4517 var _tags = Object.keys(_conj);
4518
4519 for (var _i = 0; _i < _tags.length; _i++) {
4520 var _w = _conj[_tags[_i]];
4521 lexicon[_w] = lexicon[_w] || _tags[_i]; // only if it's safe
4522 }
4523 } //conjugate phrasal-verbs
4524
4525
4526 if (tag === 'PhrasalVerb') {
4527 //add original form
4528 addWord(word, 'Infinitive', lexicon); //conjugate first word
4529
4530 var _conj2 = transform.conjugate(words[0], world);
4531
4532 var _tags2 = Object.keys(_conj2);
4533
4534 for (var _i2 = 0; _i2 < _tags2.length; _i2++) {
4535 //add it to our cache
4536 world.hasCompound[_conj2[_tags2[_i2]]] = true; //first + last words
4537
4538 var _w2 = _conj2[_tags2[_i2]] + ' ' + words[1];
4539
4540 addWord(_w2, _tags2[_i2], lexicon);
4541 addWord(_w2, 'PhrasalVerb', lexicon);
4542 }
4543 } // inflect our demonyms - 'germans'
4544
4545
4546 if (tag === 'Demonym') {
4547 var _plural = transform.toPlural(word, world);
4548
4549 lexicon[_plural] = lexicon[_plural] || ['Demonym', 'Plural']; // only if it's safe
4550 }
4551 }; // throw a bunch of words in our lexicon
4552 // const doWord = function(words, tag, world) {
4553 // let lexicon = world.words
4554 // for (let i = 0; i < words.length; i++) {
4555 // addWord(words[i], tag, lexicon)
4556 // // do some fancier stuff
4557 // addMore(words[i], tag, world)
4558 // }
4559 // }
4560
4561
4562 var addWords = {
4563 addWord: addWord,
4564 addMore: addMore
4565 };
4566
4567 // add words from plurals and conjugations data
4568 var addIrregulars = function addIrregulars(world) {
4569 //add irregular plural nouns
4570 var nouns = world.irregulars.nouns;
4571 var words = Object.keys(nouns);
4572
4573 for (var i = 0; i < words.length; i++) {
4574 var w = words[i];
4575 world.words[w] = 'Singular';
4576 world.words[nouns[w]] = 'Plural';
4577 } // add irregular verb conjugations
4578
4579
4580 var verbs = world.irregulars.verbs;
4581 var keys = Object.keys(verbs);
4582
4583 var _loop = function _loop(_i) {
4584 var inf = keys[_i]; //add only if it it's safe...
4585
4586 world.words[inf] = world.words[inf] || 'Infinitive';
4587 var forms = world.transforms.conjugate(inf, world);
4588 forms = Object.assign(forms, verbs[inf]); //add the others
4589
4590 Object.keys(forms).forEach(function (tag) {
4591 world.words[forms[tag]] = world.words[forms[tag]] || tag; // lexicon should prefer other tags, over participle
4592
4593 if (world.words[forms[tag]] === 'Participle') {
4594 world.words[forms[tag]] = tag;
4595 }
4596 });
4597 };
4598
4599 for (var _i = 0; _i < keys.length; _i++) {
4600 _loop(_i);
4601 }
4602 };
4603
4604 var addIrregulars_1 = addIrregulars;
4605
4606 //words that can't be compressed, for whatever reason
4607 var misc$1 = {
4608 // numbers
4609 '20th century fox': 'Organization',
4610 // '3m': 'Organization',
4611 '7 eleven': 'Organization',
4612 'motel 6': 'Organization',
4613 g8: 'Organization',
4614 vh1: 'Organization',
4615 q1: 'Date',
4616 q2: 'Date',
4617 q3: 'Date',
4618 q4: 'Date',
4619 her: ['Possessive', 'Pronoun'],
4620 his: ['Possessive', 'Pronoun'],
4621 their: ['Possessive', 'Pronoun'],
4622 themselves: ['Possessive', 'Pronoun'],
4623 your: ['Possessive', 'Pronoun'],
4624 our: ['Possessive', 'Pronoun'],
4625 my: ['Possessive', 'Pronoun'],
4626 its: ['Possessive', 'Pronoun']
4627 };
4628
4629 //nouns with irregular plural/singular forms
4630 //used in noun.inflect, and also in the lexicon.
4631 var plurals = {
4632 addendum: 'addenda',
4633 alga: 'algae',
4634 alumna: 'alumnae',
4635 alumnus: 'alumni',
4636 analysis: 'analyses',
4637 antenna: 'antennae',
4638 appendix: 'appendices',
4639 avocado: 'avocados',
4640 axis: 'axes',
4641 bacillus: 'bacilli',
4642 barracks: 'barracks',
4643 beau: 'beaux',
4644 bus: 'buses',
4645 cactus: 'cacti',
4646 chateau: 'chateaux',
4647 child: 'children',
4648 circus: 'circuses',
4649 clothes: 'clothes',
4650 corpus: 'corpora',
4651 criterion: 'criteria',
4652 curriculum: 'curricula',
4653 database: 'databases',
4654 deer: 'deer',
4655 diagnosis: 'diagnoses',
4656 echo: 'echoes',
4657 embargo: 'embargoes',
4658 epoch: 'epochs',
4659 foot: 'feet',
4660 formula: 'formulae',
4661 fungus: 'fungi',
4662 genus: 'genera',
4663 goose: 'geese',
4664 halo: 'halos',
4665 hippopotamus: 'hippopotami',
4666 index: 'indices',
4667 larva: 'larvae',
4668 leaf: 'leaves',
4669 libretto: 'libretti',
4670 loaf: 'loaves',
4671 man: 'men',
4672 matrix: 'matrices',
4673 memorandum: 'memoranda',
4674 modulus: 'moduli',
4675 mosquito: 'mosquitoes',
4676 mouse: 'mice',
4677 // move: 'moves',
4678 nebula: 'nebulae',
4679 nucleus: 'nuclei',
4680 octopus: 'octopi',
4681 opus: 'opera',
4682 ovum: 'ova',
4683 ox: 'oxen',
4684 parenthesis: 'parentheses',
4685 person: 'people',
4686 phenomenon: 'phenomena',
4687 prognosis: 'prognoses',
4688 quiz: 'quizzes',
4689 radius: 'radii',
4690 referendum: 'referenda',
4691 rodeo: 'rodeos',
4692 sex: 'sexes',
4693 shoe: 'shoes',
4694 sombrero: 'sombreros',
4695 stimulus: 'stimuli',
4696 stomach: 'stomachs',
4697 syllabus: 'syllabi',
4698 synopsis: 'synopses',
4699 tableau: 'tableaux',
4700 thesis: 'theses',
4701 thief: 'thieves',
4702 tooth: 'teeth',
4703 tornado: 'tornados',
4704 tuxedo: 'tuxedos',
4705 vertebra: 'vertebrae' // virus: 'viri',
4706 // zero: 'zeros',
4707
4708 };
4709
4710 // a list of irregular verb conjugations
4711 // used in verbs().conjugate()
4712 // but also added to our lexicon
4713 //use shorter key-names
4714 var mapping = {
4715 g: 'Gerund',
4716 prt: 'Participle',
4717 perf: 'PerfectTense',
4718 pst: 'PastTense',
4719 fut: 'FuturePerfect',
4720 pres: 'PresentTense',
4721 pluperf: 'Pluperfect',
4722 a: 'Actor'
4723 }; // '_' in conjugations is the infinitive form
4724 // (order matters, to the lexicon)
4725
4726 var conjugations = {
4727 act: {
4728 a: '_or'
4729 },
4730 ache: {
4731 pst: 'ached',
4732 g: 'aching'
4733 },
4734 age: {
4735 g: 'ageing',
4736 pst: 'aged',
4737 pres: 'ages'
4738 },
4739 aim: {
4740 a: '_er',
4741 g: '_ing',
4742 pst: '_ed'
4743 },
4744 arise: {
4745 prt: '_n',
4746 pst: 'arose'
4747 },
4748 babysit: {
4749 a: '_ter',
4750 pst: 'babysat'
4751 },
4752 ban: {
4753 a: '',
4754 g: '_ning',
4755 pst: '_ned'
4756 },
4757 be: {
4758 a: '',
4759 g: 'am',
4760 prt: 'been',
4761 pst: 'was',
4762 pres: 'is'
4763 },
4764 beat: {
4765 a: '_er',
4766 g: '_ing',
4767 prt: '_en'
4768 },
4769 become: {
4770 prt: '_'
4771 },
4772 begin: {
4773 g: '_ning',
4774 prt: 'begun',
4775 pst: 'began'
4776 },
4777 being: {
4778 g: 'are',
4779 pst: 'were',
4780 pres: 'are'
4781 },
4782 bend: {
4783 prt: 'bent'
4784 },
4785 bet: {
4786 a: '_ter',
4787 prt: '_'
4788 },
4789 bind: {
4790 pst: 'bound'
4791 },
4792 bite: {
4793 g: 'biting',
4794 prt: 'bitten',
4795 pst: 'bit'
4796 },
4797 bleed: {
4798 pst: 'bled',
4799 prt: 'bled'
4800 },
4801 blow: {
4802 prt: '_n',
4803 pst: 'blew'
4804 },
4805 boil: {
4806 a: '_er'
4807 },
4808 brake: {
4809 prt: 'broken'
4810 },
4811 "break": {
4812 pst: 'broke'
4813 },
4814 breed: {
4815 pst: 'bred'
4816 },
4817 bring: {
4818 pst: 'brought',
4819 prt: 'brought'
4820 },
4821 broadcast: {
4822 pst: '_'
4823 },
4824 budget: {
4825 pst: '_ed'
4826 },
4827 build: {
4828 pst: 'built',
4829 prt: 'built'
4830 },
4831 burn: {
4832 prt: '_ed'
4833 },
4834 burst: {
4835 prt: '_'
4836 },
4837 buy: {
4838 pst: 'bought',
4839 prt: 'bought'
4840 },
4841 can: {
4842 a: '',
4843 fut: '_',
4844 g: '',
4845 pst: 'could',
4846 perf: 'could',
4847 pluperf: 'could',
4848 pres: '_'
4849 },
4850 "catch": {
4851 pst: 'caught'
4852 },
4853 choose: {
4854 g: 'choosing',
4855 prt: 'chosen',
4856 pst: 'chose'
4857 },
4858 cling: {
4859 prt: 'clung'
4860 },
4861 come: {
4862 prt: '_',
4863 pst: 'came',
4864 g: 'coming'
4865 },
4866 compete: {
4867 a: 'competitor',
4868 g: 'competing',
4869 pst: '_d'
4870 },
4871 cost: {
4872 pst: '_'
4873 },
4874 creep: {
4875 prt: 'crept'
4876 },
4877 cut: {
4878 prt: '_'
4879 },
4880 deal: {
4881 pst: '_t',
4882 prt: '_t'
4883 },
4884 develop: {
4885 a: '_er',
4886 g: '_ing',
4887 pst: '_ed'
4888 },
4889 die: {
4890 g: 'dying',
4891 pst: '_d'
4892 },
4893 dig: {
4894 g: '_ging',
4895 pst: 'dug',
4896 prt: 'dug'
4897 },
4898 dive: {
4899 prt: '_d'
4900 },
4901 "do": {
4902 pst: 'did',
4903 pres: '_es'
4904 },
4905 draw: {
4906 prt: '_n',
4907 pst: 'drew'
4908 },
4909 dream: {
4910 prt: '_t'
4911 },
4912 drink: {
4913 prt: 'drunk',
4914 pst: 'drank'
4915 },
4916 drive: {
4917 g: 'driving',
4918 prt: '_n',
4919 pst: 'drove'
4920 },
4921 drop: {
4922 g: '_ping',
4923 pst: '_ped'
4924 },
4925 eat: {
4926 a: '_er',
4927 g: '_ing',
4928 prt: '_en',
4929 pst: 'ate'
4930 },
4931 edit: {
4932 pst: '_ed',
4933 g: '_ing'
4934 },
4935 egg: {
4936 pst: '_ed'
4937 },
4938 fall: {
4939 prt: '_en',
4940 pst: 'fell'
4941 },
4942 feed: {
4943 prt: 'fed',
4944 pst: 'fed'
4945 },
4946 feel: {
4947 a: '_er',
4948 pst: 'felt'
4949 },
4950 fight: {
4951 pst: 'fought',
4952 prt: 'fought'
4953 },
4954 find: {
4955 pst: 'found'
4956 },
4957 flee: {
4958 g: '_ing',
4959 prt: 'fled'
4960 },
4961 fling: {
4962 prt: 'flung'
4963 },
4964 fly: {
4965 prt: 'flown',
4966 pst: 'flew'
4967 },
4968 forbid: {
4969 pst: 'forbade'
4970 },
4971 forget: {
4972 g: '_ing',
4973 prt: 'forgotten',
4974 pst: 'forgot'
4975 },
4976 forgive: {
4977 g: 'forgiving',
4978 prt: '_n',
4979 pst: 'forgave'
4980 },
4981 free: {
4982 a: '',
4983 g: '_ing'
4984 },
4985 freeze: {
4986 g: 'freezing',
4987 prt: 'frozen',
4988 pst: 'froze'
4989 },
4990 get: {
4991 pst: 'got',
4992 prt: 'gotten'
4993 },
4994 give: {
4995 g: 'giving',
4996 prt: '_n',
4997 pst: 'gave'
4998 },
4999 go: {
5000 prt: '_ne',
5001 pst: 'went',
5002 pres: 'goes'
5003 },
5004 grow: {
5005 prt: '_n'
5006 },
5007 guide: {
5008 pst: '_d'
5009 },
5010 hang: {
5011 pst: 'hung',
5012 prt: 'hung'
5013 },
5014 have: {
5015 g: 'having',
5016 pst: 'had',
5017 prt: 'had',
5018 pres: 'has'
5019 },
5020 hear: {
5021 pst: '_d',
5022 prt: '_d'
5023 },
5024 hide: {
5025 prt: 'hidden',
5026 pst: 'hid'
5027 },
5028 hit: {
5029 prt: '_'
5030 },
5031 hold: {
5032 pst: 'held',
5033 prt: 'held'
5034 },
5035 hurt: {
5036 pst: '_',
5037 prt: '_'
5038 },
5039 ice: {
5040 g: 'icing',
5041 pst: '_d'
5042 },
5043 imply: {
5044 pst: 'implied',
5045 pres: 'implies'
5046 },
5047 is: {
5048 a: '',
5049 g: 'being',
5050 pst: 'was',
5051 pres: '_'
5052 },
5053 keep: {
5054 prt: 'kept'
5055 },
5056 kneel: {
5057 prt: 'knelt'
5058 },
5059 know: {
5060 prt: '_n'
5061 },
5062 lay: {
5063 pst: 'laid',
5064 prt: 'laid'
5065 },
5066 lead: {
5067 pst: 'led',
5068 prt: 'led'
5069 },
5070 leap: {
5071 prt: '_t'
5072 },
5073 leave: {
5074 pst: 'left',
5075 prt: 'left'
5076 },
5077 lend: {
5078 prt: 'lent'
5079 },
5080 lie: {
5081 g: 'lying',
5082 pst: 'lay'
5083 },
5084 light: {
5085 pst: 'lit',
5086 prt: 'lit'
5087 },
5088 log: {
5089 g: '_ging',
5090 pst: '_ged'
5091 },
5092 loose: {
5093 prt: 'lost'
5094 },
5095 lose: {
5096 g: 'losing',
5097 pst: 'lost'
5098 },
5099 make: {
5100 pst: 'made',
5101 prt: 'made'
5102 },
5103 mean: {
5104 pst: '_t',
5105 prt: '_t'
5106 },
5107 meet: {
5108 a: '_er',
5109 g: '_ing',
5110 pst: 'met',
5111 prt: 'met'
5112 },
5113 miss: {
5114 pres: '_'
5115 },
5116 name: {
5117 g: 'naming'
5118 },
5119 patrol: {
5120 g: '_ling',
5121 pst: '_led'
5122 },
5123 pay: {
5124 pst: 'paid',
5125 prt: 'paid'
5126 },
5127 prove: {
5128 prt: '_n'
5129 },
5130 puke: {
5131 g: 'puking'
5132 },
5133 put: {
5134 prt: '_'
5135 },
5136 quit: {
5137 prt: '_'
5138 },
5139 read: {
5140 pst: '_',
5141 prt: '_'
5142 },
5143 ride: {
5144 prt: 'ridden'
5145 },
5146 reside: {
5147 pst: '_d'
5148 },
5149 ring: {
5150 pst: 'rang',
5151 prt: 'rung'
5152 },
5153 rise: {
5154 fut: 'will have _n',
5155 g: 'rising',
5156 prt: '_n',
5157 pst: 'rose',
5158 pluperf: 'had _n'
5159 },
5160 rub: {
5161 g: '_bing',
5162 pst: '_bed'
5163 },
5164 run: {
5165 g: '_ning',
5166 prt: '_',
5167 pst: 'ran'
5168 },
5169 say: {
5170 pst: 'said',
5171 prt: 'said',
5172 pres: '_s'
5173 },
5174 seat: {
5175 pst: 'sat',
5176 prt: 'sat'
5177 },
5178 see: {
5179 g: '_ing',
5180 prt: '_n',
5181 pst: 'saw'
5182 },
5183 seek: {
5184 prt: 'sought'
5185 },
5186 sell: {
5187 pst: 'sold',
5188 prt: 'sold'
5189 },
5190 send: {
5191 prt: 'sent'
5192 },
5193 set: {
5194 prt: '_'
5195 },
5196 sew: {
5197 prt: '_n'
5198 },
5199 shake: {
5200 prt: '_n'
5201 },
5202 shave: {
5203 prt: '_d'
5204 },
5205 shed: {
5206 g: '_ding',
5207 pst: '_',
5208 pres: '_s'
5209 },
5210 shine: {
5211 pst: 'shone',
5212 prt: 'shone'
5213 },
5214 shoot: {
5215 pst: 'shot',
5216 prt: 'shot'
5217 },
5218 show: {
5219 pst: '_ed'
5220 },
5221 shut: {
5222 prt: '_'
5223 },
5224 sing: {
5225 prt: 'sung',
5226 pst: 'sang'
5227 },
5228 sink: {
5229 pst: 'sank',
5230 pluperf: 'had sunk'
5231 },
5232 sit: {
5233 pst: 'sat'
5234 },
5235 ski: {
5236 pst: '_ied'
5237 },
5238 slay: {
5239 prt: 'slain'
5240 },
5241 sleep: {
5242 prt: 'slept'
5243 },
5244 slide: {
5245 pst: 'slid',
5246 prt: 'slid'
5247 },
5248 smash: {
5249 pres: '_es'
5250 },
5251 sneak: {
5252 prt: 'snuck'
5253 },
5254 speak: {
5255 fut: 'will have spoken',
5256 prt: 'spoken',
5257 pst: 'spoke',
5258 perf: 'have spoken',
5259 pluperf: 'had spoken'
5260 },
5261 speed: {
5262 prt: 'sped'
5263 },
5264 spend: {
5265 prt: 'spent'
5266 },
5267 spill: {
5268 prt: '_ed',
5269 pst: 'spilt'
5270 },
5271 spin: {
5272 g: '_ning',
5273 pst: 'spun',
5274 prt: 'spun'
5275 },
5276 spit: {
5277 prt: 'spat'
5278 },
5279 split: {
5280 prt: '_'
5281 },
5282 spread: {
5283 pst: '_'
5284 },
5285 spring: {
5286 prt: 'sprung'
5287 },
5288 stand: {
5289 pst: 'stood'
5290 },
5291 steal: {
5292 a: '_er',
5293 pst: 'stole'
5294 },
5295 stick: {
5296 pst: 'stuck'
5297 },
5298 sting: {
5299 pst: 'stung'
5300 },
5301 stink: {
5302 pst: 'stunk',
5303 prt: 'stunk'
5304 },
5305 stream: {
5306 a: '_er'
5307 },
5308 strew: {
5309 prt: '_n'
5310 },
5311 strike: {
5312 g: 'striking',
5313 pst: 'struck'
5314 },
5315 suit: {
5316 a: '_er',
5317 g: '_ing',
5318 pst: '_ed'
5319 },
5320 sware: {
5321 prt: 'sworn'
5322 },
5323 swear: {
5324 pst: 'swore'
5325 },
5326 sweep: {
5327 prt: 'swept'
5328 },
5329 swim: {
5330 g: '_ming',
5331 pst: 'swam'
5332 },
5333 swing: {
5334 pst: 'swung'
5335 },
5336 take: {
5337 fut: 'will have _n',
5338 pst: 'took',
5339 perf: 'have _n',
5340 pluperf: 'had _n'
5341 },
5342 teach: {
5343 pst: 'taught',
5344 pres: '_es'
5345 },
5346 tear: {
5347 pst: 'tore'
5348 },
5349 tell: {
5350 pst: 'told'
5351 },
5352 think: {
5353 pst: 'thought'
5354 },
5355 thrive: {
5356 prt: '_d'
5357 },
5358 tie: {
5359 g: 'tying',
5360 pst: '_d'
5361 },
5362 undergo: {
5363 prt: '_ne'
5364 },
5365 understand: {
5366 pst: 'understood'
5367 },
5368 upset: {
5369 prt: '_'
5370 },
5371 wait: {
5372 a: '_er',
5373 g: '_ing',
5374 pst: '_ed'
5375 },
5376 wake: {
5377 pst: 'woke'
5378 },
5379 wear: {
5380 pst: 'wore'
5381 },
5382 weave: {
5383 prt: 'woven'
5384 },
5385 wed: {
5386 pst: 'wed'
5387 },
5388 weep: {
5389 prt: 'wept'
5390 },
5391 win: {
5392 g: '_ning',
5393 pst: 'won'
5394 },
5395 wind: {
5396 prt: 'wound'
5397 },
5398 withdraw: {
5399 pst: 'withdrew'
5400 },
5401 wring: {
5402 prt: 'wrung'
5403 },
5404 write: {
5405 g: 'writing',
5406 prt: 'written',
5407 pst: 'wrote'
5408 }
5409 }; //uncompress our ad-hoc compression scheme
5410
5411 var keys = Object.keys(conjugations);
5412
5413 var _loop = function _loop(i) {
5414 var inf = keys[i];
5415 var _final = {};
5416 Object.keys(conjugations[inf]).forEach(function (key) {
5417 var str = conjugations[inf][key]; //swap-in infinitives for '_'
5418
5419 str = str.replace('_', inf);
5420 var full = mapping[key];
5421 _final[full] = str;
5422 }); //over-write original
5423
5424 conjugations[inf] = _final;
5425 };
5426
5427 for (var i = 0; i < keys.length; i++) {
5428 _loop(i);
5429 }
5430
5431 var conjugations_1 = conjugations;
5432
5433 var endsWith = {
5434 b: [{
5435 reg: /([^aeiou][aeiou])b$/i,
5436 repl: {
5437 pr: '$1bs',
5438 pa: '$1bbed',
5439 gr: '$1bbing'
5440 }
5441 }],
5442 d: [{
5443 reg: /(end)$/i,
5444 repl: {
5445 pr: '$1s',
5446 pa: 'ent',
5447 gr: '$1ing',
5448 ar: '$1er'
5449 }
5450 }, {
5451 reg: /(eed)$/i,
5452 repl: {
5453 pr: '$1s',
5454 pa: '$1ed',
5455 gr: '$1ing',
5456 ar: '$1er'
5457 }
5458 }, {
5459 reg: /(ed)$/i,
5460 repl: {
5461 pr: '$1s',
5462 pa: '$1ded',
5463 ar: '$1der',
5464 gr: '$1ding'
5465 }
5466 }, {
5467 reg: /([^aeiou][ou])d$/i,
5468 repl: {
5469 pr: '$1ds',
5470 pa: '$1dded',
5471 gr: '$1dding'
5472 }
5473 }],
5474 e: [{
5475 reg: /(eave)$/i,
5476 repl: {
5477 pr: '$1s',
5478 pa: '$1d',
5479 gr: 'eaving',
5480 ar: '$1r'
5481 }
5482 }, {
5483 reg: /(ide)$/i,
5484 repl: {
5485 pr: '$1s',
5486 pa: 'ode',
5487 gr: 'iding',
5488 ar: 'ider'
5489 }
5490 }, {
5491 //shake
5492 reg: /(t|sh?)(ake)$/i,
5493 repl: {
5494 pr: '$1$2s',
5495 pa: '$1ook',
5496 gr: '$1aking',
5497 ar: '$1$2r'
5498 }
5499 }, {
5500 //awake
5501 reg: /w(ake)$/i,
5502 repl: {
5503 pr: 'w$1s',
5504 pa: 'woke',
5505 gr: 'waking',
5506 ar: 'w$1r'
5507 }
5508 }, {
5509 //make
5510 reg: /m(ake)$/i,
5511 repl: {
5512 pr: 'm$1s',
5513 pa: 'made',
5514 gr: 'making',
5515 ar: 'm$1r'
5516 }
5517 }, {
5518 reg: /(a[tg]|i[zn]|ur|nc|gl|is)e$/i,
5519 repl: {
5520 pr: '$1es',
5521 pa: '$1ed',
5522 gr: '$1ing' // prt: '$1en',
5523
5524 }
5525 }, {
5526 reg: /([bd]l)e$/i,
5527 repl: {
5528 pr: '$1es',
5529 pa: '$1ed',
5530 gr: '$1ing'
5531 }
5532 }, {
5533 reg: /(om)e$/i,
5534 repl: {
5535 pr: '$1es',
5536 pa: 'ame',
5537 gr: '$1ing'
5538 }
5539 }],
5540 g: [{
5541 reg: /([^aeiou][ou])g$/i,
5542 repl: {
5543 pr: '$1gs',
5544 pa: '$1gged',
5545 gr: '$1gging'
5546 }
5547 }],
5548 h: [{
5549 reg: /(..)([cs]h)$/i,
5550 repl: {
5551 pr: '$1$2es',
5552 pa: '$1$2ed',
5553 gr: '$1$2ing'
5554 }
5555 }],
5556 k: [{
5557 reg: /(ink)$/i,
5558 repl: {
5559 pr: '$1s',
5560 pa: 'unk',
5561 gr: '$1ing',
5562 ar: '$1er'
5563 }
5564 }],
5565 m: [{
5566 reg: /([^aeiou][aeiou])m$/i,
5567 repl: {
5568 pr: '$1ms',
5569 pa: '$1mmed',
5570 gr: '$1mming'
5571 }
5572 }],
5573 n: [{
5574 reg: /(en)$/i,
5575 repl: {
5576 pr: '$1s',
5577 pa: '$1ed',
5578 gr: '$1ing'
5579 }
5580 }],
5581 p: [{
5582 reg: /(e)(ep)$/i,
5583 repl: {
5584 pr: '$1$2s',
5585 pa: '$1pt',
5586 gr: '$1$2ing',
5587 ar: '$1$2er'
5588 }
5589 }, {
5590 reg: /([^aeiou][aeiou])p$/i,
5591 repl: {
5592 pr: '$1ps',
5593 pa: '$1pped',
5594 gr: '$1pping'
5595 }
5596 }, {
5597 reg: /([aeiu])p$/i,
5598 repl: {
5599 pr: '$1ps',
5600 pa: '$1p',
5601 gr: '$1pping'
5602 }
5603 }],
5604 r: [{
5605 reg: /([td]er)$/i,
5606 repl: {
5607 pr: '$1s',
5608 pa: '$1ed',
5609 gr: '$1ing'
5610 }
5611 }, {
5612 reg: /(er)$/i,
5613 repl: {
5614 pr: '$1s',
5615 pa: '$1ed',
5616 gr: '$1ing'
5617 }
5618 }],
5619 s: [{
5620 reg: /(ish|tch|ess)$/i,
5621 repl: {
5622 pr: '$1es',
5623 pa: '$1ed',
5624 gr: '$1ing'
5625 }
5626 }],
5627 t: [{
5628 reg: /(ion|end|e[nc]t)$/i,
5629 repl: {
5630 pr: '$1s',
5631 pa: '$1ed',
5632 gr: '$1ing'
5633 }
5634 }, {
5635 reg: /(.eat)$/i,
5636 repl: {
5637 pr: '$1s',
5638 pa: '$1ed',
5639 gr: '$1ing'
5640 }
5641 }, {
5642 reg: /([aeiu])t$/i,
5643 repl: {
5644 pr: '$1ts',
5645 pa: '$1t',
5646 gr: '$1tting'
5647 }
5648 }, {
5649 reg: /([^aeiou][aeiou])t$/i,
5650 repl: {
5651 pr: '$1ts',
5652 pa: '$1tted',
5653 gr: '$1tting'
5654 }
5655 }],
5656 w: [{
5657 reg: /(.llow)$/i,
5658 //follow, allow
5659 repl: {
5660 pr: '$1s',
5661 pa: '$1ed'
5662 }
5663 }, {
5664 reg: /(..)(ow)$/i,
5665 //grow
5666 repl: {
5667 pr: '$1$2s',
5668 pa: '$1ew',
5669 gr: '$1$2ing',
5670 prt: '$1$2n'
5671 }
5672 }],
5673 y: [{
5674 reg: /([i|f|rr])y$/i,
5675 repl: {
5676 pr: '$1ies',
5677 pa: '$1ied',
5678 gr: '$1ying'
5679 }
5680 }],
5681 z: [{
5682 reg: /([aeiou]zz)$/i,
5683 repl: {
5684 pr: '$1es',
5685 pa: '$1ed',
5686 gr: '$1ing'
5687 }
5688 }]
5689 };
5690 var suffixes = endsWith;
5691
5692 var posMap = {
5693 pr: 'PresentTense',
5694 pa: 'PastTense',
5695 gr: 'Gerund',
5696 prt: 'Participle',
5697 ar: 'Actor'
5698 };
5699
5700 var doTransform = function doTransform(str, obj) {
5701 var found = {};
5702 var keys = Object.keys(obj.repl);
5703
5704 for (var i = 0; i < keys.length; i += 1) {
5705 var pos = keys[i];
5706 found[posMap[pos]] = str.replace(obj.reg, obj.repl[pos]);
5707 }
5708
5709 return found;
5710 }; //look at the end of the word for clues
5711
5712
5713 var checkSuffix = function checkSuffix() {
5714 var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
5715 var c = str[str.length - 1];
5716
5717 if (suffixes.hasOwnProperty(c) === true) {
5718 for (var r = 0; r < suffixes[c].length; r += 1) {
5719 var reg = suffixes[c][r].reg;
5720
5721 if (reg.test(str) === true) {
5722 return doTransform(str, suffixes[c][r]);
5723 }
5724 }
5725 }
5726
5727 return {};
5728 };
5729
5730 var _01Suffixes = checkSuffix;
5731
5732 //non-specifc, 'hail-mary' transforms from infinitive, into other forms
5733 var hasY = /[bcdfghjklmnpqrstvwxz]y$/;
5734 var generic = {
5735 Gerund: function Gerund(inf) {
5736 if (inf.charAt(inf.length - 1) === 'e') {
5737 return inf.replace(/e$/, 'ing');
5738 }
5739
5740 return inf + 'ing';
5741 },
5742 PresentTense: function PresentTense(inf) {
5743 if (inf.charAt(inf.length - 1) === 's') {
5744 return inf + 'es';
5745 }
5746
5747 if (hasY.test(inf) === true) {
5748 return inf.slice(0, -1) + 'ies';
5749 }
5750
5751 return inf + 's';
5752 },
5753 PastTense: function PastTense(inf) {
5754 if (inf.charAt(inf.length - 1) === 'e') {
5755 return inf + 'd';
5756 }
5757
5758 if (inf.substr(-2) === 'ed') {
5759 return inf;
5760 }
5761
5762 if (hasY.test(inf) === true) {
5763 return inf.slice(0, -1) + 'ied';
5764 }
5765
5766 return inf + 'ed';
5767 }
5768 };
5769 var _02Generic = generic;
5770
5771 //we assume the input word is a proper infinitive
5772
5773 var conjugate = function conjugate() {
5774 var inf = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
5775 var world = arguments.length > 1 ? arguments[1] : undefined;
5776 var found = {}; // 1. look at irregulars
5777 //the lexicon doesn't pass this in
5778
5779 if (world && world.irregulars) {
5780 if (world.irregulars.verbs.hasOwnProperty(inf) === true) {
5781 found = Object.assign({}, world.irregulars.verbs[inf]);
5782 }
5783 } //2. rule-based regex
5784
5785
5786 found = Object.assign({}, _01Suffixes(inf), found); //3. generic transformations
5787 //'buzzing'
5788
5789 if (found.Gerund === undefined) {
5790 found.Gerund = _02Generic.Gerund(inf);
5791 } //'buzzed'
5792
5793
5794 if (found.PastTense === undefined) {
5795 found.PastTense = _02Generic.PastTense(inf);
5796 } //'buzzes'
5797
5798
5799 if (found.PresentTense === undefined) {
5800 found.PresentTense = _02Generic.PresentTense(inf);
5801 }
5802
5803 return found;
5804 };
5805
5806 var conjugate_1 = conjugate; // console.log(conjugate('bake'))
5807
5808 //turn 'quick' into 'quickest'
5809 var do_rules = [/ght$/, /nge$/, /ough$/, /ain$/, /uel$/, /[au]ll$/, /ow$/, /oud$/, /...p$/];
5810 var dont_rules = [/ary$/];
5811 var irregulars = {
5812 nice: 'nicest',
5813 late: 'latest',
5814 hard: 'hardest',
5815 inner: 'innermost',
5816 outer: 'outermost',
5817 far: 'furthest',
5818 worse: 'worst',
5819 bad: 'worst',
5820 good: 'best',
5821 big: 'biggest',
5822 large: 'largest'
5823 };
5824 var transforms = [{
5825 reg: /y$/i,
5826 repl: 'iest'
5827 }, {
5828 reg: /([aeiou])t$/i,
5829 repl: '$1ttest'
5830 }, {
5831 reg: /([aeou])de$/i,
5832 repl: '$1dest'
5833 }, {
5834 reg: /nge$/i,
5835 repl: 'ngest'
5836 }, {
5837 reg: /([aeiou])te$/i,
5838 repl: '$1test'
5839 }];
5840
5841 var to_superlative = function to_superlative(str) {
5842 //irregulars
5843 if (irregulars.hasOwnProperty(str)) {
5844 return irregulars[str];
5845 } //known transforms
5846
5847
5848 for (var i = 0; i < transforms.length; i++) {
5849 if (transforms[i].reg.test(str)) {
5850 return str.replace(transforms[i].reg, transforms[i].repl);
5851 }
5852 } //dont-rules
5853
5854
5855 for (var _i = 0; _i < dont_rules.length; _i++) {
5856 if (dont_rules[_i].test(str) === true) {
5857 return null;
5858 }
5859 } //do-rules
5860
5861
5862 for (var _i2 = 0; _i2 < do_rules.length; _i2++) {
5863 if (do_rules[_i2].test(str) === true) {
5864 if (str.charAt(str.length - 1) === 'e') {
5865 return str + 'st';
5866 }
5867
5868 return str + 'est';
5869 }
5870 }
5871
5872 return str + 'est';
5873 };
5874
5875 var toSuperlative = to_superlative;
5876
5877 //turn 'quick' into 'quickly'
5878 var do_rules$1 = [/ght$/, /nge$/, /ough$/, /ain$/, /uel$/, /[au]ll$/, /ow$/, /old$/, /oud$/, /e[ae]p$/];
5879 var dont_rules$1 = [/ary$/, /ous$/];
5880 var irregulars$1 = {
5881 grey: 'greyer',
5882 gray: 'grayer',
5883 green: 'greener',
5884 yellow: 'yellower',
5885 red: 'redder',
5886 good: 'better',
5887 well: 'better',
5888 bad: 'worse',
5889 sad: 'sadder',
5890 big: 'bigger'
5891 };
5892 var transforms$1 = [{
5893 reg: /y$/i,
5894 repl: 'ier'
5895 }, {
5896 reg: /([aeiou])t$/i,
5897 repl: '$1tter'
5898 }, {
5899 reg: /([aeou])de$/i,
5900 repl: '$1der'
5901 }, {
5902 reg: /nge$/i,
5903 repl: 'nger'
5904 }];
5905
5906 var to_comparative = function to_comparative(str) {
5907 //known-irregulars
5908 if (irregulars$1.hasOwnProperty(str)) {
5909 return irregulars$1[str];
5910 } //known-transforms
5911
5912
5913 for (var i = 0; i < transforms$1.length; i++) {
5914 if (transforms$1[i].reg.test(str) === true) {
5915 return str.replace(transforms$1[i].reg, transforms$1[i].repl);
5916 }
5917 } //dont-patterns
5918
5919
5920 for (var _i = 0; _i < dont_rules$1.length; _i++) {
5921 if (dont_rules$1[_i].test(str) === true) {
5922 return null;
5923 }
5924 } //do-patterns
5925
5926
5927 for (var _i2 = 0; _i2 < do_rules$1.length; _i2++) {
5928 if (do_rules$1[_i2].test(str) === true) {
5929 return str + 'er';
5930 }
5931 } //easy-one
5932
5933
5934 if (/e$/.test(str) === true) {
5935 return str + 'r';
5936 }
5937
5938 return str + 'er';
5939 };
5940
5941 var toComparative = to_comparative;
5942
5943 var fns$1 = {
5944 toSuperlative: toSuperlative,
5945 toComparative: toComparative
5946 };
5947 /** conjugate an adjective into other forms */
5948
5949 var conjugate$1 = function conjugate(w) {
5950 var res = {}; // 'greatest'
5951
5952 var sup = fns$1.toSuperlative(w);
5953
5954 if (sup) {
5955 res.Superlative = sup;
5956 } // 'greater'
5957
5958
5959 var comp = fns$1.toComparative(w);
5960
5961 if (comp) {
5962 res.Comparative = comp;
5963 }
5964
5965 return res;
5966 };
5967
5968 var adjectives = conjugate$1;
5969
5970 /** patterns for turning 'bus' to 'buses'*/
5971 var suffixes$1 = {
5972 a: [[/(antenn|formul|nebul|vertebr|vit)a$/i, '$1ae'], [/([ti])a$/i, '$1a']],
5973 e: [[/(kn|l|w)ife$/i, '$1ives'], [/(hive)$/i, '$1s'], [/([m|l])ouse$/i, '$1ice'], [/([m|l])ice$/i, '$1ice']],
5974 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']],
5975 i: [[/(octop|vir)i$/i, '$1i']],
5976 m: [[/([ti])um$/i, '$1a']],
5977 n: [[/^(oxen)$/i, '$1']],
5978 o: [[/(al|ad|at|er|et|ed|ad)o$/i, '$1oes']],
5979 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']],
5980 x: [[/(matr|vert|ind|cort)(ix|ex)$/i, '$1ices'], [/^(ox)$/i, '$1en']],
5981 y: [[/([^aeiouy]|qu)y$/i, '$1ies']],
5982 z: [[/(quiz)$/i, '$1zes']]
5983 };
5984 var _rules = suffixes$1;
5985
5986 var addE = /(x|ch|sh|s|z)$/;
5987
5988 var trySuffix = function trySuffix(str) {
5989 var c = str[str.length - 1];
5990
5991 if (_rules.hasOwnProperty(c) === true) {
5992 for (var i = 0; i < _rules[c].length; i += 1) {
5993 var reg = _rules[c][i][0];
5994
5995 if (reg.test(str) === true) {
5996 return str.replace(reg, _rules[c][i][1]);
5997 }
5998 }
5999 }
6000
6001 return null;
6002 };
6003 /** Turn a singular noun into a plural
6004 * assume the given string is singular
6005 */
6006
6007
6008 var pluralize = function pluralize() {
6009 var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
6010 var world = arguments.length > 1 ? arguments[1] : undefined;
6011 var irregulars = world.irregulars.nouns; // check irregulars list
6012
6013 if (irregulars.hasOwnProperty(str)) {
6014 return irregulars[str];
6015 } //we have some rules to try-out
6016
6017
6018 var plural = trySuffix(str);
6019
6020 if (plural !== null) {
6021 return plural;
6022 } //like 'church'
6023
6024
6025 if (addE.test(str)) {
6026 return str + 'es';
6027 } // ¯\_(ツ)_/¯
6028
6029
6030 return str + 's';
6031 };
6032
6033 var toPlural = pluralize;
6034
6035 //patterns for turning 'dwarves' to 'dwarf'
6036 var _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'],
6037 [/(eas)es$/i, '$1e'], //diseases
6038 [/(..[aeiou]s)es$/i, '$1'], //geniouses
6039 [/(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, '']];
6040
6041 var invertObj = function invertObj(obj) {
6042 return Object.keys(obj).reduce(function (h, k) {
6043 h[obj[k]] = k;
6044 return h;
6045 }, {});
6046 };
6047
6048 var toSingular = function toSingular(str, world) {
6049 var irregulars = world.irregulars.nouns;
6050 var invert = invertObj(irregulars); //(not very efficient)
6051 // check irregulars list
6052
6053 if (invert.hasOwnProperty(str)) {
6054 return invert[str];
6055 } // go through our regexes
6056
6057
6058 for (var i = 0; i < _rules$1.length; i++) {
6059 if (_rules$1[i][0].test(str) === true) {
6060 str = str.replace(_rules$1[i][0], _rules$1[i][1]);
6061 return str;
6062 }
6063 }
6064
6065 return str;
6066 };
6067
6068 var toSingular_1 = toSingular;
6069
6070 //rules for turning a verb into infinitive form
6071 var rules = {
6072 Participle: [{
6073 reg: /own$/i,
6074 to: 'ow'
6075 }, {
6076 reg: /(.)un([g|k])$/i,
6077 to: '$1in$2'
6078 }],
6079 Actor: [{
6080 reg: /(er)er$/i,
6081 to: '$1'
6082 }],
6083 PresentTense: [{
6084 reg: /(..)(ies)$/i,
6085 to: '$1y'
6086 }, {
6087 reg: /(tch|sh)es$/i,
6088 to: '$1'
6089 }, {
6090 reg: /(ss|zz)es$/i,
6091 to: '$1'
6092 }, {
6093 reg: /([tzlshicgrvdnkmu])es$/i,
6094 to: '$1e'
6095 }, {
6096 reg: /(n[dtk]|c[kt]|[eo]n|i[nl]|er|a[ytrl])s$/i,
6097 to: '$1'
6098 }, {
6099 reg: /(ow)s$/i,
6100 to: '$1'
6101 }, {
6102 reg: /(op)s$/i,
6103 to: '$1'
6104 }, {
6105 reg: /([eirs])ts$/i,
6106 to: '$1t'
6107 }, {
6108 reg: /(ll)s$/i,
6109 to: '$1'
6110 }, {
6111 reg: /(el)s$/i,
6112 to: '$1'
6113 }, {
6114 reg: /(ip)es$/i,
6115 to: '$1e'
6116 }, {
6117 reg: /ss$/i,
6118 to: 'ss'
6119 }, {
6120 reg: /s$/i,
6121 to: ''
6122 }],
6123 Gerund: [{
6124 //popping -> pop
6125 reg: /(..)(p|d|t|g){2}ing$/i,
6126 to: '$1$2'
6127 }, {
6128 //fuzzing -> fuzz
6129 reg: /(ll|ss|zz)ing$/i,
6130 to: '$1'
6131 }, {
6132 reg: /([^aeiou])ying$/i,
6133 to: '$1y'
6134 }, {
6135 reg: /([^ae]i.)ing$/i,
6136 to: '$1e'
6137 }, {
6138 //eating, reading
6139 reg: /(ea[dklnrtv])ing$/i,
6140 to: '$1'
6141 }, {
6142 //washing -> wash
6143 reg: /(ch|sh)ing$/i,
6144 to: '$1'
6145 }, //soft-e forms:
6146 {
6147 //z : hazing (not buzzing)
6148 reg: /(z)ing$/i,
6149 to: '$1e'
6150 }, {
6151 //a : baking, undulating
6152 reg: /(a[gdkvtc])ing$/i,
6153 to: '$1e'
6154 }, {
6155 //u : conjuring, tubing
6156 reg: /(u[rtcbn])ing$/i,
6157 to: '$1e'
6158 }, {
6159 //o : forboding, poking, hoping, boring (not hooping)
6160 reg: /([^o]o[bdknprv])ing$/i,
6161 to: '$1e'
6162 }, {
6163 //ling : tingling, wrinkling, circling, scrambling, bustling
6164 reg: /([tbckg]l)ing$/i,
6165 //dp
6166 to: '$1e'
6167 }, {
6168 //cing : bouncing, denouncing
6169 reg: /(c|s)ing$/i,
6170 //dp
6171 to: '$1e'
6172 }, // {
6173 // //soft-e :
6174 // reg: /([ua]s|[dr]g|z|o[rlsp]|cre)ing$/i,
6175 // to: '$1e',
6176 // },
6177 {
6178 //fallback
6179 reg: /(..)ing$/i,
6180 to: '$1'
6181 }],
6182 PastTense: [{
6183 reg: /(ued)$/i,
6184 to: 'ue'
6185 }, {
6186 reg: /a([^aeiouy])ed$/i,
6187 to: 'a$1e'
6188 }, {
6189 reg: /([aeiou]zz)ed$/i,
6190 to: '$1'
6191 }, {
6192 reg: /(e|i)lled$/i,
6193 to: '$1ll'
6194 }, {
6195 reg: /(.)(sh|ch)ed$/i,
6196 to: '$1$2'
6197 }, {
6198 reg: /(tl|gl)ed$/i,
6199 to: '$1e'
6200 }, {
6201 reg: /(um?pt?)ed$/i,
6202 to: '$1'
6203 }, {
6204 reg: /(ss)ed$/i,
6205 to: '$1'
6206 }, {
6207 reg: /pped$/i,
6208 to: 'p'
6209 }, {
6210 reg: /tted$/i,
6211 to: 't'
6212 }, {
6213 reg: /(..)gged$/i,
6214 to: '$1g'
6215 }, {
6216 reg: /(..)lked$/i,
6217 to: '$1lk'
6218 }, {
6219 reg: /([^aeiouy][aeiou])ked$/i,
6220 to: '$1ke'
6221 }, {
6222 reg: /(.[aeiou])led$/i,
6223 to: '$1l'
6224 }, {
6225 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,
6226 to: '$1$2'
6227 }, {
6228 reg: /(.ut)ed$/i,
6229 to: '$1e'
6230 }, {
6231 reg: /(.pt)ed$/i,
6232 to: '$1'
6233 }, {
6234 reg: /(us)ed$/i,
6235 to: '$1e'
6236 }, {
6237 reg: /(dd)ed$/i,
6238 to: '$1'
6239 }, {
6240 reg: /(..[^aeiouy])ed$/i,
6241 to: '$1e'
6242 }, {
6243 reg: /(..)ied$/i,
6244 to: '$1y'
6245 }, {
6246 reg: /(.o)ed$/i,
6247 to: '$1o'
6248 }, {
6249 reg: /(..i)ed$/i,
6250 to: '$1'
6251 }, {
6252 reg: /(.a[^aeiou])ed$/i,
6253 to: '$1'
6254 }, {
6255 //owed, aced
6256 reg: /([aeiou][^aeiou])ed$/i,
6257 to: '$1e'
6258 }, {
6259 reg: /([rl])ew$/i,
6260 to: '$1ow'
6261 }, {
6262 reg: /([pl])t$/i,
6263 to: '$1t'
6264 }]
6265 };
6266 var _transform = rules;
6267
6268 var guessVerb = {
6269 Gerund: ['ing'],
6270 Actor: ['erer'],
6271 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'],
6272 PastTense: ['ed', 'lt', 'nt', 'pt', 'ew', 'ld'],
6273 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']
6274 }; //flip it into a lookup object
6275
6276 guessVerb = Object.keys(guessVerb).reduce(function (h, k) {
6277 guessVerb[k].forEach(function (a) {
6278 return h[a] = k;
6279 });
6280 return h;
6281 }, {});
6282 var _guess = guessVerb;
6283
6284 /** it helps to know what we're conjugating from */
6285
6286 var guessTense = function guessTense(str) {
6287 var three = str.substr(str.length - 3);
6288
6289 if (_guess.hasOwnProperty(three) === true) {
6290 return _guess[three];
6291 }
6292
6293 var two = str.substr(str.length - 2);
6294
6295 if (_guess.hasOwnProperty(two) === true) {
6296 return _guess[two];
6297 }
6298
6299 var one = str.substr(str.length - 1);
6300
6301 if (one === 's') {
6302 return 'PresentTense';
6303 }
6304
6305 return null;
6306 };
6307
6308 var toInfinitive = function toInfinitive(str, world, tense) {
6309 if (!str) {
6310 return '';
6311 } //1. look at known irregulars
6312
6313
6314 if (world.words.hasOwnProperty(str) === true) {
6315 var irregs = world.irregulars.verbs;
6316 var keys = Object.keys(irregs);
6317
6318 for (var i = 0; i < keys.length; i++) {
6319 var forms = Object.keys(irregs[keys[i]]);
6320
6321 for (var o = 0; o < forms.length; o++) {
6322 if (str === irregs[keys[i]][forms[o]]) {
6323 return keys[i];
6324 }
6325 }
6326 }
6327 } // give'r!
6328
6329
6330 tense = tense || guessTense(str);
6331
6332 if (tense && _transform[tense]) {
6333 for (var _i = 0; _i < _transform[tense].length; _i++) {
6334 var rule = _transform[tense][_i];
6335
6336 if (rule.reg.test(str) === true) {
6337 // console.log(rule.reg)
6338 return str.replace(rule.reg, rule.to);
6339 }
6340 }
6341 }
6342
6343 return str;
6344 };
6345
6346 var toInfinitive_1 = toInfinitive;
6347
6348 var irregulars$2 = {
6349 nouns: plurals,
6350 verbs: conjugations_1
6351 }; //these behaviours are configurable & shared across some plugins
6352
6353 var transforms$2 = {
6354 conjugate: conjugate_1,
6355 adjectives: adjectives,
6356 toPlural: toPlural,
6357 toSingular: toSingular_1,
6358 toInfinitive: toInfinitive_1
6359 };
6360 var _isVerbose = false;
6361 /** all configurable linguistic data */
6362
6363 var World = /*#__PURE__*/function () {
6364 function World() {
6365 _classCallCheck(this, World);
6366
6367 // quiet these properties from a console.log
6368 Object.defineProperty(this, 'words', {
6369 enumerable: false,
6370 value: misc$1,
6371 writable: true
6372 });
6373 Object.defineProperty(this, 'hasCompound', {
6374 enumerable: false,
6375 value: {},
6376 writable: true
6377 });
6378 Object.defineProperty(this, 'irregulars', {
6379 enumerable: false,
6380 value: irregulars$2,
6381 writable: true
6382 });
6383 Object.defineProperty(this, 'tags', {
6384 enumerable: false,
6385 value: Object.assign({}, tags),
6386 writable: true
6387 });
6388 Object.defineProperty(this, 'transforms', {
6389 enumerable: false,
6390 value: transforms$2,
6391 writable: true
6392 });
6393 Object.defineProperty(this, 'taggers', {
6394 enumerable: false,
6395 value: [],
6396 writable: true
6397 }); // add our misc word-list
6398 // this.addWords(misc)
6399 // add our compressed data to lexicon
6400
6401 this.unpackWords(_data); // add our irregulars to lexicon
6402
6403 addIrregulars_1(this); // cache our abbreviations for our sentence-parser
6404
6405 Object.defineProperty(this, 'cache', {
6406 enumerable: false,
6407 value: {
6408 abbreviations: this.getByTag('Abbreviation')
6409 }
6410 });
6411 }
6412 /** more logs for debugging */
6413
6414
6415 _createClass(World, [{
6416 key: "verbose",
6417 value: function verbose(bool) {
6418 _isVerbose = bool;
6419 return this;
6420 }
6421 }, {
6422 key: "isVerbose",
6423 value: function isVerbose() {
6424 return _isVerbose;
6425 }
6426 /** get all terms in our lexicon with this tag */
6427
6428 }, {
6429 key: "getByTag",
6430 value: function getByTag(tag) {
6431 var lex = this.words;
6432 var res = {};
6433 var words = Object.keys(lex);
6434
6435 for (var i = 0; i < words.length; i++) {
6436 if (typeof lex[words[i]] === 'string') {
6437 if (lex[words[i]] === tag) {
6438 res[words[i]] = true;
6439 }
6440 } else if (lex[words[i]].some(function (t) {
6441 return t === tag;
6442 })) {
6443 res[words[i]] = true;
6444 }
6445 }
6446
6447 return res;
6448 }
6449 /** augment our lingustic data with new data */
6450
6451 }, {
6452 key: "unpackWords",
6453 value: function unpackWords(lex) {
6454 var tags = Object.keys(lex);
6455
6456 for (var i = 0; i < tags.length; i++) {
6457 var words = Object.keys(efrtUnpack_min(lex[tags[i]]));
6458
6459 for (var w = 0; w < words.length; w++) {
6460 addWords.addWord(words[w], tags[i], this.words); // do some fancier stuff
6461
6462 addWords.addMore(words[w], tags[i], this);
6463 }
6464 }
6465 }
6466 /** put new words into our lexicon, properly */
6467
6468 }, {
6469 key: "addWords",
6470 value: function addWords$1(obj) {
6471 var keys = Object.keys(obj);
6472
6473 for (var i = 0; i < keys.length; i++) {
6474 var word = keys[i].toLowerCase();
6475 addWords.addWord(word, obj[keys[i]], this.words); // do some fancier stuff
6476
6477 addWords.addMore(word, obj[keys[i]], this);
6478 }
6479 }
6480 /** add new custom conjugations */
6481
6482 }, {
6483 key: "addConjugations",
6484 value: function addConjugations(obj) {
6485 Object.assign(this.irregulars.verbs, obj);
6486 return this;
6487 }
6488 /** add new custom plural/singular pairs */
6489
6490 }, {
6491 key: "addPlurals",
6492 value: function addPlurals(obj) {
6493 Object.assign(this.irregulars.nouns, obj);
6494 return this;
6495 }
6496 /** extend the compromise tagset */
6497
6498 }, {
6499 key: "addTags",
6500 value: function addTags(tags) {
6501 tags = Object.assign({}, tags);
6502 this.tags = Object.assign(this.tags, tags); // calculate graph implications for the new tags
6503
6504 this.tags = inference(this.tags);
6505 return this;
6506 }
6507 /** call methods after tagger runs */
6508
6509 }, {
6510 key: "postProcess",
6511 value: function postProcess(fn) {
6512 this.taggers.push(fn);
6513 return this;
6514 }
6515 /** helper method for logging + debugging */
6516
6517 }, {
6518 key: "stats",
6519 value: function stats() {
6520 return {
6521 words: Object.keys(this.words).length,
6522 plurals: Object.keys(this.irregulars.nouns).length,
6523 conjugations: Object.keys(this.irregulars.verbs).length,
6524 compounds: Object.keys(this.hasCompound).length,
6525 postProcessors: this.taggers.length
6526 };
6527 }
6528 }]);
6529
6530 return World;
6531 }(); // ¯\_(:/)_/¯
6532
6533
6534 var clone$1 = function clone(obj) {
6535 return JSON.parse(JSON.stringify(obj));
6536 };
6537 /** produce a deep-copy of all lingustic data */
6538
6539
6540 World.prototype.clone = function () {
6541 var w2 = new World(); // these are simple to copy:
6542
6543 w2.words = Object.assign({}, this.words);
6544 w2.hasCompound = Object.assign({}, this.hasCompound); //these ones are nested:
6545
6546 w2.irregulars = clone$1(this.irregulars);
6547 w2.tags = clone$1(this.tags); // these are functions
6548
6549 w2.transforms = this.transforms;
6550 w2.taggers = this.taggers;
6551 return w2;
6552 };
6553
6554 var World_1 = World;
6555
6556 /** return the root, first document */
6557
6558 var _01Utils$1 = createCommonjsModule(function (module, exports) {
6559 exports.all = function () {
6560 return this.parents()[0] || this;
6561 };
6562 /** return the previous result */
6563
6564
6565 exports.parent = function () {
6566 if (this.from) {
6567 return this.from;
6568 }
6569
6570 return this;
6571 };
6572 /** return a list of all previous results */
6573
6574
6575 exports.parents = function (n) {
6576 var arr = [];
6577
6578 var addParent = function addParent(doc) {
6579 if (doc.from) {
6580 arr.push(doc.from);
6581 addParent(doc.from);
6582 }
6583 };
6584
6585 addParent(this);
6586 arr = arr.reverse();
6587
6588 if (typeof n === 'number') {
6589 return arr[n];
6590 }
6591
6592 return arr;
6593 };
6594 /** deep-copy the document, so that no references remain */
6595
6596
6597 exports.clone = function (doShallow) {
6598 var list = this.list.map(function (ts) {
6599 return ts.clone(doShallow);
6600 });
6601 var tmp = this.buildFrom(list);
6602 return tmp;
6603 };
6604 /** how many seperate terms does the document have? */
6605
6606
6607 exports.wordCount = function () {
6608 return this.list.reduce(function (count, p) {
6609 count += p.wordCount();
6610 return count;
6611 }, 0);
6612 };
6613
6614 exports.wordcount = exports.wordCount;
6615 /** turn on logging for decision-debugging */
6616 // exports.verbose = function(bool) {
6617 // if (bool === undefined) {
6618 // bool = true
6619 // }
6620 // this.world.verbose = bool
6621 // }
6622 });
6623
6624 /** use only the first result(s) */
6625
6626 var _02Accessors = createCommonjsModule(function (module, exports) {
6627 exports.first = function (n) {
6628 if (n === undefined) {
6629 return this.get(0);
6630 }
6631
6632 return this.slice(0, n);
6633 };
6634 /** use only the last result(s) */
6635
6636
6637 exports.last = function (n) {
6638 if (n === undefined) {
6639 return this.get(this.list.length - 1);
6640 }
6641
6642 var end = this.list.length;
6643 return this.slice(end - n, end);
6644 };
6645 /** grab a given subset of the results*/
6646
6647
6648 exports.slice = function (start, end) {
6649 var list = this.list.slice(start, end);
6650 return this.buildFrom(list);
6651 };
6652 /* grab nth result */
6653
6654
6655 exports.eq = function (n) {
6656 var p = this.list[n];
6657
6658 if (p === undefined) {
6659 return this.buildFrom([]);
6660 }
6661
6662 return this.buildFrom([p]);
6663 };
6664
6665 exports.get = exports.eq;
6666 /** grab term[0] for every match */
6667
6668 exports.firstTerms = function () {
6669 return this.match('^.');
6670 };
6671
6672 exports.firstTerm = exports.firstTerms;
6673 /** grab the last term for every match */
6674
6675 exports.lastTerms = function () {
6676 return this.match('.$');
6677 };
6678
6679 exports.lastTerm = exports.lastTerms;
6680 /** return a flat array of term objects */
6681
6682 exports.termList = function (num) {
6683 var arr = []; //'reduce' but faster
6684
6685 for (var i = 0; i < this.list.length; i++) {
6686 var terms = this.list[i].terms();
6687
6688 for (var o = 0; o < terms.length; o++) {
6689 arr.push(terms[o]); //support .termList(4)
6690
6691 if (num !== undefined && arr[num] !== undefined) {
6692 return arr[num];
6693 }
6694 }
6695 }
6696
6697 return arr;
6698 };
6699 /* grab named capture group terms as object */
6700
6701
6702 var getGroups = function getGroups(doc) {
6703 var res = {};
6704 var allGroups = {};
6705
6706 var _loop = function _loop(i) {
6707 var phrase = doc.list[i];
6708 var groups = Object.keys(phrase.groups).map(function (k) {
6709 return phrase.groups[k];
6710 });
6711
6712 for (var j = 0; j < groups.length; j++) {
6713 var _groups$j = groups[j],
6714 group = _groups$j.group,
6715 start = _groups$j.start,
6716 length = _groups$j.length;
6717
6718 if (!allGroups[group]) {
6719 allGroups[group] = [];
6720 }
6721
6722 allGroups[group].push(phrase.buildFrom(start, length));
6723 }
6724 };
6725
6726 for (var i = 0; i < doc.list.length; i++) {
6727 _loop(i);
6728 }
6729
6730 var keys = Object.keys(allGroups);
6731
6732 for (var _i = 0; _i < keys.length; _i++) {
6733 var key = keys[_i];
6734 res[key] = doc.buildFrom(allGroups[key]);
6735 }
6736
6737 return res;
6738 };
6739 /** lookup a named-group, by its name */
6740
6741
6742 var getOneName = function getOneName(doc, name) {
6743 var arr = [];
6744
6745 var _loop2 = function _loop2(i) {
6746 var phrase = doc.list[i];
6747 var keys = Object.keys(phrase.groups);
6748 keys = keys.filter(function (id) {
6749 return phrase.groups[id].group === name;
6750 });
6751 keys.forEach(function (id) {
6752 arr.push(phrase.buildFrom(phrase.groups[id].start, phrase.groups[id].length));
6753 });
6754 };
6755
6756 for (var i = 0; i < doc.list.length; i++) {
6757 _loop2(i);
6758 }
6759
6760 return doc.buildFrom(arr);
6761 };
6762 /** grab named capture group results */
6763
6764
6765 exports.groups = function (target) {
6766 if (target === undefined) {
6767 return getGroups(this);
6768 }
6769
6770 if (typeof target === 'number') {
6771 target = String(target);
6772 }
6773
6774 return getOneName(this, target) || this.buildFrom([]);
6775 };
6776
6777 exports.group = exports.groups;
6778 /** get the full-sentence each phrase belongs to */
6779
6780 exports.sentences = function (n) {
6781 var arr = [];
6782 this.list.forEach(function (p) {
6783 arr.push(p.fullSentence());
6784 });
6785
6786 if (typeof n === 'number') {
6787 return this.buildFrom([arr[n]]);
6788 }
6789
6790 return this.buildFrom(arr);
6791 };
6792
6793 exports.sentence = exports.sentences;
6794 });
6795
6796 // cache the easier conditions up-front
6797 var cacheRequired = function cacheRequired(reg) {
6798 var needTags = [];
6799 var needWords = [];
6800 reg.forEach(function (obj) {
6801 if (obj.optional === true || obj.negative === true) {
6802 return;
6803 }
6804
6805 if (obj.tag !== undefined) {
6806 needTags.push(obj.tag);
6807 }
6808
6809 if (obj.word !== undefined) {
6810 needWords.push(obj.word);
6811 }
6812 });
6813 return {
6814 tags: needTags,
6815 words: needWords
6816 };
6817 }; // try to pre-fail as many matches as possible, without doing them
6818
6819
6820 var failFast$1 = function failFast(doc, regs) {
6821 if (doc._cache && doc._cache.set === true) {
6822 var _cacheRequired = cacheRequired(regs),
6823 words = _cacheRequired.words,
6824 tags = _cacheRequired.tags; //check required words
6825
6826
6827 for (var i = 0; i < words.length; i++) {
6828 if (doc._cache.words[words[i]] === undefined) {
6829 return false;
6830 }
6831 } //check required tags
6832
6833
6834 for (var _i = 0; _i < tags.length; _i++) {
6835 if (doc._cache.tags[tags[_i]] === undefined) {
6836 return false;
6837 }
6838 }
6839 }
6840
6841 return true;
6842 };
6843
6844 var _failFast = failFast$1;
6845
6846 var _03Match = createCommonjsModule(function (module, exports) {
6847 /** return a new Doc, with this one as a parent */
6848 exports.match = function (reg) {
6849 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6850
6851 // support '0' shorthand for named-groups
6852 if (typeof opts === 'string' || typeof opts === 'number' || opts === null) {
6853 opts = {
6854 group: opts
6855 };
6856 } //parse-up the input expression
6857
6858
6859 var regs = matchSyntax(reg, opts);
6860
6861 if (regs.length === 0) {
6862 return this.buildFrom([]);
6863 } //check our cache, if it exists
6864
6865
6866 if (_failFast(this, regs) === false) {
6867 return this.buildFrom([]);
6868 } //try expression on each phrase
6869
6870
6871 var matches = this.list.reduce(function (arr, p) {
6872 return arr.concat(p.match(regs));
6873 }, []); // support returning named groups
6874
6875 if (opts.group !== undefined && opts.group !== null && opts.group !== '') {
6876 return this.buildFrom(matches).groups(opts.group);
6877 }
6878
6879 return this.buildFrom(matches);
6880 };
6881 /** return all results except for this */
6882
6883
6884 exports.not = function (reg) {
6885 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6886 //parse-up the input expression
6887 var regs = matchSyntax(reg, opts); //if it's empty, return them all!
6888
6889 if (regs.length === 0 || _failFast(this, regs) === false) {
6890 return this;
6891 } //try expression on each phrase
6892
6893
6894 var matches = this.list.reduce(function (arr, p) {
6895 return arr.concat(p.not(regs));
6896 }, []);
6897 return this.buildFrom(matches);
6898 };
6899 /** return only the first match */
6900
6901
6902 exports.matchOne = function (reg) {
6903 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6904 var regs = matchSyntax(reg, opts); //check our cache, if it exists
6905
6906 if (_failFast(this, regs) === false) {
6907 return this.buildFrom([]);
6908 }
6909
6910 for (var i = 0; i < this.list.length; i++) {
6911 var match = this.list[i].match(regs, true);
6912 return this.buildFrom(match);
6913 }
6914
6915 return this.buildFrom([]);
6916 };
6917 /** return each current phrase, only if it contains this match */
6918
6919
6920 exports["if"] = function (reg) {
6921 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6922 var regs = matchSyntax(reg, opts); //consult our cache, if it exists
6923
6924 if (_failFast(this, regs) === false) {
6925 return this.buildFrom([]);
6926 }
6927
6928 var found = this.list.filter(function (p) {
6929 return p.has(regs) === true;
6930 });
6931 return this.buildFrom(found);
6932 };
6933 /** Filter-out any current phrases that have this match*/
6934
6935
6936 exports.ifNo = function (reg) {
6937 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6938 var regs = matchSyntax(reg, opts);
6939 var found = this.list.filter(function (p) {
6940 return p.has(regs) === false;
6941 });
6942 return this.buildFrom(found);
6943 };
6944 /**Return a boolean if this match exists */
6945
6946
6947 exports.has = function (reg) {
6948 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6949 var regs = matchSyntax(reg, opts); //consult our cache, if it exists
6950
6951 if (_failFast(this, regs) === false) {
6952 return false;
6953 }
6954
6955 return this.list.some(function (p) {
6956 return p.has(regs) === true;
6957 });
6958 };
6959 /** match any terms after our matches, within the sentence */
6960
6961
6962 exports.lookAhead = function (reg) {
6963 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6964
6965 // find everything afterwards, by default
6966 if (!reg) {
6967 reg = '.*';
6968 }
6969
6970 var regs = matchSyntax(reg, opts);
6971 var matches = [];
6972 this.list.forEach(function (p) {
6973 matches = matches.concat(p.lookAhead(regs));
6974 });
6975 matches = matches.filter(function (p) {
6976 return p;
6977 });
6978 return this.buildFrom(matches);
6979 };
6980
6981 exports.lookAfter = exports.lookAhead;
6982 /** match any terms before our matches, within the sentence */
6983
6984 exports.lookBehind = function (reg) {
6985 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6986
6987 // find everything afterwards, by default
6988 if (!reg) {
6989 reg = '.*';
6990 }
6991
6992 var regs = matchSyntax(reg, opts);
6993 var matches = [];
6994 this.list.forEach(function (p) {
6995 matches = matches.concat(p.lookBehind(regs));
6996 });
6997 matches = matches.filter(function (p) {
6998 return p;
6999 });
7000 return this.buildFrom(matches);
7001 };
7002
7003 exports.lookBefore = exports.lookBehind;
7004 /** return all terms before a match, in each phrase */
7005
7006 exports.before = function (reg) {
7007 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7008 var regs = matchSyntax(reg, opts); //only the phrases we care about
7009
7010 var phrases = this["if"](regs).list;
7011 var befores = phrases.map(function (p) {
7012 var ids = p.terms().map(function (t) {
7013 return t.id;
7014 }); //run the search again
7015
7016 var m = p.match(regs)[0];
7017 var index = ids.indexOf(m.start); //nothing is before a first-term match
7018
7019 if (index === 0 || index === -1) {
7020 return null;
7021 }
7022
7023 return p.buildFrom(p.start, index);
7024 });
7025 befores = befores.filter(function (p) {
7026 return p !== null;
7027 });
7028 return this.buildFrom(befores);
7029 };
7030 /** return all terms after a match, in each phrase */
7031
7032
7033 exports.after = function (reg) {
7034 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7035 var regs = matchSyntax(reg, opts); //only the phrases we care about
7036
7037 var phrases = this["if"](regs).list;
7038 var befores = phrases.map(function (p) {
7039 var terms = p.terms();
7040 var ids = terms.map(function (t) {
7041 return t.id;
7042 }); //run the search again
7043
7044 var m = p.match(regs)[0];
7045 var index = ids.indexOf(m.start); //skip if nothing is after it
7046
7047 if (index === -1 || !terms[index + m.length]) {
7048 return null;
7049 } //create the new phrase, after our match.
7050
7051
7052 var id = terms[index + m.length].id;
7053 var len = p.length - index - m.length;
7054 return p.buildFrom(id, len);
7055 });
7056 befores = befores.filter(function (p) {
7057 return p !== null;
7058 });
7059 return this.buildFrom(befores);
7060 };
7061 /** return only results with this match afterwards */
7062
7063
7064 exports.hasAfter = function (reg) {
7065 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7066 return this.filter(function (doc) {
7067 return doc.lookAfter(reg, opts).found;
7068 });
7069 };
7070 /** return only results with this match before it */
7071
7072
7073 exports.hasBefore = function (reg) {
7074 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7075 return this.filter(function (doc) {
7076 return doc.lookBefore(reg, opts).found;
7077 });
7078 };
7079 });
7080
7081 /** apply a tag, or tags to all terms */
7082 var tagTerms = function tagTerms(tag, doc, safe, reason) {
7083 var tagList = [];
7084
7085 if (typeof tag === 'string') {
7086 tagList = tag.split(' ');
7087 } // doc.parents()[0].reasons.push(reason)
7088 //do indepenent tags for each term:
7089
7090
7091 doc.list.forEach(function (p) {
7092 var terms = p.terms(); // tagSafe - apply only to fitting terms
7093
7094 if (safe === true) {
7095 terms = terms.filter(function (t) {
7096 return t.canBe(tag, doc.world);
7097 });
7098 }
7099
7100 terms.forEach(function (t, i) {
7101 //fancy version:
7102 if (tagList.length > 1) {
7103 if (tagList[i] && tagList[i] !== '.') {
7104 t.tag(tagList[i], reason, doc.world);
7105 }
7106 } else {
7107 //non-fancy version (same tag for all terms)
7108 t.tag(tag, reason, doc.world);
7109 }
7110 });
7111 });
7112 return;
7113 };
7114
7115 var _setTag = tagTerms;
7116
7117 /** Give all terms the given tag */
7118
7119 var tag$1 = function tag(tags, why) {
7120 if (!tags) {
7121 return this;
7122 }
7123
7124 _setTag(tags, this, false, why);
7125 return this;
7126 };
7127 /** Only apply tag to terms if it is consistent with current tags */
7128
7129
7130 var tagSafe$1 = function tagSafe(tags, why) {
7131 if (!tags) {
7132 return this;
7133 }
7134
7135 _setTag(tags, this, true, why);
7136 return this;
7137 };
7138 /** Remove this term from the given terms */
7139
7140
7141 var unTag$1 = function unTag(tags, why) {
7142 var _this = this;
7143
7144 this.list.forEach(function (p) {
7145 p.terms().forEach(function (t) {
7146 return t.unTag(tags, why, _this.world);
7147 });
7148 });
7149 return this;
7150 };
7151 /** return only the terms that can be this tag*/
7152
7153
7154 var canBe$2 = function canBe(tag) {
7155 if (!tag) {
7156 return this;
7157 }
7158
7159 var world = this.world;
7160 var matches = this.list.reduce(function (arr, p) {
7161 return arr.concat(p.canBe(tag, world));
7162 }, []);
7163 return this.buildFrom(matches);
7164 };
7165
7166 var _04Tag = {
7167 tag: tag$1,
7168 tagSafe: tagSafe$1,
7169 unTag: unTag$1,
7170 canBe: canBe$2
7171 };
7172
7173 /* run each phrase through a function, and create a new document */
7174 var map = function map(fn) {
7175 var _this = this;
7176
7177 if (!fn) {
7178 return this;
7179 }
7180
7181 var list = this.list.map(function (p, i) {
7182 var doc = _this.buildFrom([p]);
7183
7184 doc.from = null; //it's not a child/parent
7185
7186 var res = fn(doc, i); // if its a doc, return one result
7187
7188 if (res && res.list && res.list[0]) {
7189 return res.list[0];
7190 }
7191
7192 return res;
7193 }); //remove nulls
7194
7195 list = list.filter(function (x) {
7196 return x;
7197 }); // return an empty response
7198
7199 if (list.length === 0) {
7200 return this.buildFrom(list);
7201 } // if it is not a list of Phrase objects, then don't try to make a Doc object
7202
7203
7204 if (_typeof(list[0]) !== 'object' || list[0].isA !== 'Phrase') {
7205 return list;
7206 }
7207
7208 return this.buildFrom(list);
7209 };
7210 /** run a function on each phrase */
7211
7212
7213 var forEach = function forEach(fn, detachParent) {
7214 var _this2 = this;
7215
7216 if (!fn) {
7217 return this;
7218 }
7219
7220 this.list.forEach(function (p, i) {
7221 var sub = _this2.buildFrom([p]); // if we're doing fancy insertions, we may want to skip updating the parent each time.
7222
7223
7224 if (detachParent === true) {
7225 sub.from = null; //
7226 }
7227
7228 fn(sub, i);
7229 });
7230 return this;
7231 };
7232 /** return only the phrases that return true */
7233
7234
7235 var filter = function filter(fn) {
7236 var _this3 = this;
7237
7238 if (!fn) {
7239 return this;
7240 }
7241
7242 var list = this.list.filter(function (p, i) {
7243 var doc = _this3.buildFrom([p]);
7244
7245 doc.from = null; //it's not a child/parent
7246
7247 return fn(doc, i);
7248 });
7249 return this.buildFrom(list);
7250 };
7251 /** return a document with only the first phrase that matches */
7252
7253
7254 var find = function find(fn) {
7255 var _this4 = this;
7256
7257 if (!fn) {
7258 return this;
7259 }
7260
7261 var phrase = this.list.find(function (p, i) {
7262 var doc = _this4.buildFrom([p]);
7263
7264 doc.from = null; //it's not a child/parent
7265
7266 return fn(doc, i);
7267 });
7268
7269 if (phrase) {
7270 return this.buildFrom([phrase]);
7271 }
7272
7273 return undefined;
7274 };
7275 /** return true or false if there is one matching phrase */
7276
7277
7278 var some = function some(fn) {
7279 var _this5 = this;
7280
7281 if (!fn) {
7282 return this;
7283 }
7284
7285 return this.list.some(function (p, i) {
7286 var doc = _this5.buildFrom([p]);
7287
7288 doc.from = null; //it's not a child/parent
7289
7290 return fn(doc, i);
7291 });
7292 };
7293 /** sample a subset of the results */
7294
7295
7296 var random = function random(n) {
7297 if (!this.found) {
7298 return this;
7299 }
7300
7301 var r = Math.floor(Math.random() * this.list.length);
7302
7303 if (n === undefined) {
7304 var list = [this.list[r]];
7305 return this.buildFrom(list);
7306 } //prevent it from going over the end
7307
7308
7309 if (r + n > this.length) {
7310 r = this.length - n;
7311 r = r < 0 ? 0 : r;
7312 }
7313
7314 return this.slice(r, r + n);
7315 };
7316 /** combine each phrase into a new data-structure */
7317 // exports.reduce = function(fn, h) {
7318 // let list = this.list.reduce((_h, ts) => {
7319 // let doc = this.buildFrom([ts])
7320 // doc.from = null //it's not a child/parent
7321 // return fn(_h, doc)
7322 // }, h)
7323 // return this.buildFrom(list)
7324 // }
7325
7326
7327 var _05Loops = {
7328 map: map,
7329 forEach: forEach,
7330 filter: filter,
7331 find: find,
7332 some: some,
7333 random: random
7334 };
7335
7336 // const tokenize = require('../../01-tokenizer/02-words')
7337 var tokenize = function tokenize(str) {
7338 return str.split(/[ -]/g);
7339 }; // take a list of strings
7340 // look them up in the document
7341
7342
7343 var buildTree = function buildTree(termList) {
7344 var values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
7345 var root = {}; // parse our input
7346
7347 termList.forEach(function (str, i) {
7348 var val = true;
7349
7350 if (values[i] !== undefined) {
7351 val = values[i];
7352 } // some rough normalization
7353
7354
7355 str = (str || '').toLowerCase();
7356 str = str.replace(/[,;.!?]+$/, '');
7357 var arr = tokenize(str).map(function (s) {
7358 return s.trim();
7359 });
7360 root[arr[0]] = root[arr[0]] || {};
7361
7362 if (arr.length === 1) {
7363 root[arr[0]].value = val;
7364 } else {
7365 root[arr[0]].more = root[arr[0]].more || [];
7366 root[arr[0]].more.push({
7367 rest: arr.slice(1),
7368 value: val
7369 });
7370 }
7371 }); // sort by longest-first?
7372 // console.log(JSON.stringify(root, null, 2))
7373
7374 return root;
7375 };
7376
7377 var fastLookup = function fastLookup(termList, values, doc) {
7378 var root = buildTree(termList, values);
7379 var found = []; // each phrase
7380
7381 var _loop = function _loop(i) {
7382 var p = doc.list[i];
7383 var terms = p.terms();
7384 var words = terms.map(function (t) {
7385 return t.reduced;
7386 }); // each word
7387
7388 var _loop2 = function _loop2(w) {
7389 if (root[words[w]] !== undefined) {
7390 // is it a multi-word match?
7391 if (root[words[w]].more !== undefined) {
7392 root[words[w]].more.forEach(function (more) {
7393 // is it too-long?
7394 if (words[w + more.rest.length] === undefined) {
7395 return;
7396 } // compare each subsequent term
7397
7398
7399 var everyTerm = more.rest.every(function (word, r) {
7400 return word === words[w + r + 1];
7401 });
7402
7403 if (everyTerm === true) {
7404 found.push({
7405 id: p.terms()[w].id,
7406 value: more.value,
7407 length: more.rest.length + 1
7408 });
7409 }
7410 });
7411 } // is it a single-word match?
7412
7413
7414 if (root[words[w]].value !== undefined) {
7415 found.push({
7416 id: p.terms()[w].id,
7417 value: root[words[w]].value,
7418 length: 1
7419 });
7420 }
7421 }
7422 };
7423
7424 for (var w = 0; w < words.length; w++) {
7425 _loop2(w);
7426 }
7427 };
7428
7429 for (var i = 0; i < doc.list.length; i++) {
7430 _loop(i);
7431 }
7432
7433 return found;
7434 };
7435
7436 var _lookup = fastLookup;
7437
7438 var _06Lookup = createCommonjsModule(function (module, exports) {
7439 // compare one term and one match
7440 // const doesMatch = function(term, str) {
7441 // if (str === '') {
7442 // return false
7443 // }
7444 // return term.reduced === str || term.implicit === str || term.root === str || term.text.toLowerCase() === str
7445 // }
7446 var isObject = function isObject(obj) {
7447 return obj && Object.prototype.toString.call(obj) === '[object Object]';
7448 };
7449 /** lookup an array of words or phrases */
7450
7451
7452 exports.lookup = function (arr) {
7453 var _this = this;
7454
7455 var values = []; //is it a {key:val} object?
7456
7457 var isObj = isObject(arr);
7458
7459 if (isObj === true) {
7460 arr = Object.keys(arr).map(function (k) {
7461 values.push(arr[k]);
7462 return k;
7463 });
7464 } // support .lookup('foo')
7465
7466
7467 if (typeof arr === 'string') {
7468 arr = [arr];
7469 } //make sure we go fast.
7470
7471
7472 if (this._cache.set !== true) {
7473 this.cache();
7474 }
7475
7476 var found = _lookup(arr, values, this);
7477 var p = this.list[0]; // make object response
7478
7479 if (isObj === true) {
7480 var byVal = {};
7481 found.forEach(function (o) {
7482 byVal[o.value] = byVal[o.value] || [];
7483 byVal[o.value].push(p.buildFrom(o.id, o.length));
7484 });
7485 Object.keys(byVal).forEach(function (k) {
7486 byVal[k] = _this.buildFrom(byVal[k]);
7487 });
7488 return byVal;
7489 } // otherwise, make array response:
7490
7491
7492 found = found.map(function (o) {
7493 return p.buildFrom(o.id, o.length);
7494 });
7495 return this.buildFrom(found);
7496 };
7497
7498 exports.lookUp = exports.lookup;
7499 });
7500
7501 /** freeze the current state of the document, for speed-purposes*/
7502 var cache$1 = function cache(options) {
7503 var _this = this;
7504
7505 options = options || {};
7506 var words = {};
7507 var tags = {};
7508 this._cache.words = words;
7509 this._cache.tags = tags;
7510 this._cache.set = true;
7511 this.list.forEach(function (p, i) {
7512 p.cache = p.cache || {}; //p.terms get cached automatically
7513
7514 var terms = p.terms(); // cache all the terms
7515
7516 terms.forEach(function (t) {
7517 if (words[t.reduced] && !words.hasOwnProperty(t.reduced)) {
7518 return; //skip prototype words
7519 }
7520
7521 words[t.reduced] = words[t.reduced] || [];
7522 words[t.reduced].push(i);
7523 Object.keys(t.tags).forEach(function (tag) {
7524 tags[tag] = tags[tag] || [];
7525 tags[tag].push(i);
7526 }); // cache root-form on Term, too
7527
7528 if (options.root) {
7529 t.setRoot(_this.world);
7530 words[t.root] = [i];
7531 }
7532 });
7533 });
7534 return this;
7535 };
7536 /** un-freezes the current state of the document, so it may be transformed */
7537
7538
7539 var uncache = function uncache() {
7540 this._cache = {};
7541 this.list.forEach(function (p) {
7542 p.cache = {};
7543 }); // do parents too?
7544
7545 this.parents().forEach(function (doc) {
7546 doc._cache = {};
7547 doc.list.forEach(function (p) {
7548 p.cache = {};
7549 });
7550 });
7551 return this;
7552 };
7553
7554 var _07Cache = {
7555 cache: cache$1,
7556 uncache: uncache
7557 };
7558
7559 var titleCase$3 = function titleCase(str) {
7560 return str.charAt(0).toUpperCase() + str.substr(1);
7561 };
7562 /** substitute-in new content */
7563
7564
7565 var replaceWith = function replaceWith(replace) {
7566 var _this = this;
7567
7568 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7569
7570 if (!replace) {
7571 return this["delete"]();
7572 } //support old-style params
7573
7574
7575 if (options === true) {
7576 options = {
7577 keepTags: true
7578 };
7579 }
7580
7581 if (options === false) {
7582 options = {
7583 keepTags: false
7584 };
7585 }
7586
7587 options = options || {}; // clear the cache
7588
7589 this.uncache(); // return this
7590
7591 this.list.forEach(function (p) {
7592 var input = replace; // accept a function for replace
7593
7594 if (typeof replace === 'function') {
7595 input = replace(p);
7596 }
7597
7598 var newPhrases; // accept a Doc object to replace
7599
7600 if (input && _typeof(input) === 'object' && input.isA === 'Doc') {
7601 newPhrases = input.list;
7602
7603 _this.pool().merge(input.pool());
7604 } else if (typeof input === 'string') {
7605 //input is a string
7606 if (options.keepCase !== false && p.terms(0).isTitleCase()) {
7607 input = titleCase$3(input);
7608 }
7609
7610 newPhrases = _01Tokenizer(input, _this.world, _this.pool()); //tag the new phrases
7611
7612 var tmpDoc = _this.buildFrom(newPhrases);
7613
7614 tmpDoc.tagger();
7615 newPhrases = tmpDoc.list;
7616 } else {
7617 return; //don't even bother
7618 } // try to keep its old tags, if appropriate
7619
7620
7621 if (options.keepTags === true) {
7622 var oldTags = p.json({
7623 terms: {
7624 tags: true
7625 }
7626 }).terms;
7627 newPhrases[0].terms().forEach(function (t, i) {
7628 if (oldTags[i]) {
7629 t.tagSafe(oldTags[i].tags, 'keptTag', _this.world);
7630 }
7631 });
7632 }
7633
7634 p.replace(newPhrases[0], _this); //Oneday: support multi-sentence replacements
7635 });
7636 return this;
7637 };
7638 /** search and replace match with new content */
7639
7640
7641 var replace$1 = function replace(match, _replace, options) {
7642 // if there's no 2nd param, use replaceWith
7643 if (_replace === undefined) {
7644 return this.replaceWith(match, options);
7645 }
7646
7647 this.match(match).replaceWith(_replace, options);
7648 return this;
7649 };
7650
7651 var _01Replace = {
7652 replaceWith: replaceWith,
7653 replace: replace$1
7654 };
7655
7656 var _02Insert = createCommonjsModule(function (module, exports) {
7657 var isObject = function isObject(obj) {
7658 return obj && Object.prototype.toString.call(obj) === '[object Object]';
7659 }; // if it's empty, just create the phrase
7660
7661
7662 var makeNew = function makeNew(str, doc) {
7663 var phrase = _01Tokenizer(str, doc.world)[0]; //assume it's one sentence, for now
7664
7665 var tmpDoc = doc.buildFrom([phrase]);
7666 tmpDoc.tagger();
7667 doc.list = tmpDoc.list;
7668 return doc;
7669 };
7670 /** add these new terms to the end*/
7671
7672
7673 exports.append = function () {
7674 var _this = this;
7675
7676 var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
7677
7678 if (!str) {
7679 return this;
7680 } // if it's empty, just create the phrase
7681
7682
7683 if (!this.found) {
7684 return makeNew(str, this);
7685 } // clear the cache
7686
7687
7688 this.uncache(); //add it to end of every phrase
7689
7690 this.list.forEach(function (p) {
7691 //build it
7692 var phrase;
7693
7694 if (isObject(str) && str.isA === 'Doc') {
7695 phrase = str.list[0].clone(); //use the first phrase
7696 } else if (typeof str === 'string') {
7697 phrase = _01Tokenizer(str, _this.world, _this.pool())[0]; //assume it's one sentence, for now
7698 } //tag it
7699
7700
7701 var tmpDoc = _this.buildFrom([phrase]);
7702
7703 tmpDoc.tagger(); // push it onto the end
7704
7705 p.append(phrase, _this);
7706 });
7707 return this;
7708 };
7709
7710 exports.insertAfter = exports.append;
7711 exports.insertAt = exports.append;
7712 /** add these new terms to the front*/
7713
7714 exports.prepend = function (str) {
7715 var _this2 = this;
7716
7717 if (!str) {
7718 return this;
7719 } // if it's empty, just create the phrase
7720
7721
7722 if (!this.found) {
7723 return makeNew(str, this);
7724 } // clear the cache
7725
7726
7727 this.uncache(); //add it to start of every phrase
7728
7729 this.list.forEach(function (p) {
7730 //build it
7731 var phrase;
7732
7733 if (isObject(str) && str.isA === 'Doc') {
7734 phrase = str.list[0].clone(); //use the first phrase
7735 } else if (typeof str === 'string') {
7736 phrase = _01Tokenizer(str, _this2.world, _this2.pool())[0]; //assume it's one sentence, for now
7737 } //tag it
7738
7739
7740 var tmpDoc = _this2.buildFrom([phrase]);
7741
7742 tmpDoc.tagger(); // add it to the start
7743
7744 p.prepend(phrase, _this2);
7745 });
7746 return this;
7747 };
7748
7749 exports.insertBefore = exports.prepend;
7750 /** add these new things to the end*/
7751
7752 exports.concat = function () {
7753 // clear the cache
7754 this.uncache();
7755 var list = this.list.slice(0); //repeat for any number of params
7756
7757 for (var i = 0; i < arguments.length; i++) {
7758 var arg = arguments[i]; //support a fresh string
7759
7760 if (typeof arg === 'string') {
7761 var arr = _01Tokenizer(arg, this.world); //TODO: phrase.tagger()?
7762
7763 list = list.concat(arr);
7764 } else if (arg.isA === 'Doc') {
7765 list = list.concat(arg.list);
7766 } else if (arg.isA === 'Phrase') {
7767 list.push(arg);
7768 }
7769 }
7770
7771 return this.buildFrom(list);
7772 };
7773 /** fully remove these terms from the document */
7774
7775
7776 exports["delete"] = function (match) {
7777 var _this3 = this;
7778
7779 // clear the cache
7780 this.uncache();
7781 var toRemove = this;
7782
7783 if (match) {
7784 toRemove = this.match(match);
7785 }
7786
7787 toRemove.list.forEach(function (phrase) {
7788 return phrase["delete"](_this3);
7789 });
7790 return this;
7791 }; // aliases
7792
7793
7794 exports.remove = exports["delete"];
7795 });
7796
7797 var shouldTrim = {
7798 clean: true,
7799 reduced: true,
7800 root: true
7801 };
7802 /** return the document as text */
7803
7804 var text$1 = function text(options) {
7805 var _this = this;
7806
7807 options = options || {}; //are we showing every phrase?
7808
7809 var showFull = false;
7810
7811 if (this.parents().length === 0) {
7812 showFull = true;
7813 } // cache roots, if necessary
7814
7815
7816 if (options === 'root' || _typeof(options) === 'object' && options.root) {
7817 this.list.forEach(function (p) {
7818 p.terms().forEach(function (t) {
7819 if (t.root === null) {
7820 t.setRoot(_this.world);
7821 }
7822 });
7823 });
7824 }
7825
7826 var txt = this.list.reduce(function (str, p, i) {
7827 var trimPre = !showFull && i === 0;
7828 var trimPost = !showFull && i === _this.list.length - 1;
7829 return str + p.text(options, trimPre, trimPost);
7830 }, ''); // clumsy final trim of leading/trailing whitespace
7831
7832 if (shouldTrim[options] === true || options.reduced === true || options.clean === true || options.root === true) {
7833 txt = txt.trim();
7834 }
7835
7836 return txt;
7837 };
7838
7839 var _01Text = {
7840 text: text$1
7841 };
7842
7843 // get all character startings in doc
7844 var termOffsets = function termOffsets(doc) {
7845 var elapsed = 0;
7846 var index = 0;
7847 var offsets = {};
7848 doc.termList().forEach(function (term) {
7849 offsets[term.id] = {
7850 index: index,
7851 start: elapsed + term.pre.length,
7852 length: term.text.length
7853 };
7854 elapsed += term.pre.length + term.text.length + term.post.length;
7855 index += 1;
7856 });
7857 return offsets;
7858 };
7859
7860 var calcOffset = function calcOffset(doc, result, options) {
7861 // calculate offsets for each term
7862 var offsets = termOffsets(doc.all()); // add index values
7863
7864 if (options.terms.index || options.index) {
7865 result.forEach(function (o) {
7866 o.terms.forEach(function (t) {
7867 t.index = offsets[t.id].index;
7868 });
7869 o.index = o.terms[0].index;
7870 });
7871 } // add offset values
7872
7873
7874 if (options.terms.offset || options.offset) {
7875 result.forEach(function (o) {
7876 o.terms.forEach(function (t) {
7877 t.offset = offsets[t.id] || {};
7878 }); // let len = o.terms.reduce((n, t, i) => {
7879 // n += t.offset.length || 0
7880 // //add whitespace, too
7881 // console.log(t.post)
7882 // return n
7883 // }, 0)
7884 // The offset information for the entire doc starts at (or just before)
7885 // the first term, and is as long as the whole text. The code originally
7886 // copied the entire offset value from terms[0], but since we're now
7887 // overriding 2 of the three fields, it's cleaner to just create an all-
7888 // new object and not pretend it's "just" the same as terms[0].
7889
7890 o.offset = {
7891 index: o.terms[0].offset.index,
7892 start: o.terms[0].offset.start - o.text.indexOf(o.terms[0].text),
7893 length: o.text.length
7894 };
7895 });
7896 }
7897 };
7898
7899 var _offset = calcOffset;
7900
7901 var _02Json = createCommonjsModule(function (module, exports) {
7902 var jsonDefaults = {
7903 text: true,
7904 terms: true,
7905 trim: true
7906 }; //some options have dependents
7907
7908 var setOptions = function setOptions(options) {
7909 options = Object.assign({}, jsonDefaults, options);
7910
7911 if (options.unique) {
7912 options.reduced = true;
7913 } //offset calculation requires these options to be on
7914
7915
7916 if (options.offset) {
7917 options.text = true;
7918
7919 if (!options.terms || options.terms === true) {
7920 options.terms = {};
7921 }
7922
7923 options.terms.offset = true;
7924 }
7925
7926 if (options.index || options.terms.index) {
7927 options.terms = options.terms === true ? {} : options.terms;
7928 options.terms.id = true;
7929 }
7930
7931 return options;
7932 };
7933 /** pull out desired metadata from the document */
7934
7935
7936 exports.json = function () {
7937 var _this = this;
7938
7939 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
7940
7941 //support json(3) format
7942 if (typeof options === 'number' && this.list[options]) {
7943 return this.list[options].json(jsonDefaults);
7944 }
7945
7946 options = setOptions(options); // cache root strings beforehand, if necessary
7947
7948 if (options.root === true) {
7949 this.list.forEach(function (p) {
7950 p.terms().forEach(function (t) {
7951 if (t.root === null) {
7952 t.setRoot(_this.world);
7953 }
7954 });
7955 });
7956 }
7957
7958 var result = this.list.map(function (p) {
7959 return p.json(options, _this.world);
7960 }); // add offset and index data for each term
7961
7962 if (options.terms.offset || options.offset || options.terms.index || options.index) {
7963 _offset(this, result, options);
7964 } // add frequency #s
7965
7966
7967 if (options.frequency || options.freq || options.count) {
7968 var obj = {};
7969 this.list.forEach(function (p) {
7970 var str = p.text('reduced');
7971 obj[str] = obj[str] || 0;
7972 obj[str] += 1;
7973 });
7974 this.list.forEach(function (p, i) {
7975 result[i].count = obj[p.text('reduced')];
7976 });
7977 } // remove duplicates
7978
7979
7980 if (options.unique) {
7981 var already = {};
7982 result = result.filter(function (o) {
7983 if (already[o.reduced] === true) {
7984 return false;
7985 }
7986
7987 already[o.reduced] = true;
7988 return true;
7989 });
7990 }
7991
7992 return result;
7993 }; //aliases
7994
7995
7996 exports.data = exports.json;
7997 });
7998
7999 var _debug = createCommonjsModule(function (module) {
8000 // https://stackoverflow.com/questions/9781218/how-to-change-node-jss-console-font-color
8001 var reset = '\x1b[0m';
8002
8003 var padEnd = function padEnd(str, width) {
8004 str = str.toString();
8005
8006 while (str.length < width) {
8007 str += ' ';
8008 }
8009
8010 return str;
8011 };
8012
8013 function isClientSide() {
8014 return typeof window !== 'undefined' && window.document;
8015 } // some nice colors for client-side debug
8016
8017
8018 var css = {
8019 green: '#7f9c6c',
8020 red: '#914045',
8021 blue: '#6699cc',
8022 magenta: '#6D5685',
8023 cyan: '#2D85A8',
8024 yellow: '#e6d7b3',
8025 black: '#303b50'
8026 };
8027
8028 var logClientSide = function logClientSide(doc) {
8029 var tagset = doc.world.tags;
8030 doc.list.forEach(function (p) {
8031 console.log('\n%c"' + p.text() + '"', 'color: #e6d7b3;');
8032 var terms = p.terms();
8033 terms.forEach(function (t) {
8034 var tags = Object.keys(t.tags);
8035 var text = t.text || '-';
8036
8037 if (t.implicit) {
8038 text = '[' + t.implicit + ']';
8039 }
8040
8041 var word = "'" + text + "'";
8042 word = padEnd(word, 8);
8043 var found = tags.find(function (tag) {
8044 return tagset[tag] && tagset[tag].color;
8045 });
8046 var color = 'steelblue';
8047
8048 if (tagset[found]) {
8049 color = tagset[found].color;
8050 color = css[color];
8051 }
8052
8053 console.log(" ".concat(word, " - %c").concat(tags.join(', ')), "color: ".concat(color || 'steelblue', ";"));
8054 });
8055 });
8056 }; //cheaper than requiring chalk
8057
8058
8059 var cli = {
8060 green: function green(str) {
8061 return '\x1b[32m' + str + reset;
8062 },
8063 red: function red(str) {
8064 return '\x1b[31m' + str + reset;
8065 },
8066 blue: function blue(str) {
8067 return '\x1b[34m' + str + reset;
8068 },
8069 magenta: function magenta(str) {
8070 return '\x1b[35m' + str + reset;
8071 },
8072 cyan: function cyan(str) {
8073 return '\x1b[36m' + str + reset;
8074 },
8075 yellow: function yellow(str) {
8076 return '\x1b[33m' + str + reset;
8077 },
8078 black: function black(str) {
8079 return '\x1b[30m' + str + reset;
8080 }
8081 };
8082
8083 var tagString = function tagString(tags, world) {
8084 tags = tags.map(function (tag) {
8085 if (!world.tags.hasOwnProperty(tag)) {
8086 return tag;
8087 }
8088
8089 var c = world.tags[tag].color || 'blue';
8090 return cli[c](tag);
8091 });
8092 return tags.join(', ');
8093 }; //output some helpful stuff to the console
8094
8095
8096 var debug = function debug(doc) {
8097 if (isClientSide()) {
8098 logClientSide(doc);
8099 return doc;
8100 }
8101
8102 console.log(cli.blue('====='));
8103 doc.list.forEach(function (p) {
8104 console.log(cli.blue(' -----'));
8105 var terms = p.terms();
8106 terms.forEach(function (t) {
8107 var tags = Object.keys(t.tags);
8108 var text = t.text || '-';
8109
8110 if (t.implicit) {
8111 text = '[' + t.implicit + ']';
8112 }
8113
8114 {
8115 text = cli.yellow(text);
8116 }
8117
8118 var word = "'" + text + "'";
8119 word = padEnd(word, 18);
8120 var str = cli.blue(' | ') + word + ' - ' + tagString(tags, doc.world);
8121 console.log(str);
8122 });
8123 });
8124 console.log('');
8125 return doc;
8126 };
8127
8128 module.exports = debug;
8129 });
8130
8131 var topk = function topk(doc) {
8132 var list = doc.json({
8133 text: false,
8134 terms: false,
8135 reduced: true
8136 }); // combine them
8137
8138 var obj = {};
8139 list.forEach(function (o) {
8140 if (!obj[o.reduced]) {
8141 o.count = 0;
8142 obj[o.reduced] = o;
8143 }
8144
8145 obj[o.reduced].count += 1;
8146 });
8147 var arr = Object.keys(obj).map(function (k) {
8148 return obj[k];
8149 }); // sort them
8150
8151 arr.sort(function (a, b) {
8152 if (a.count > b.count) {
8153 return -1;
8154 } else if (a.count < b.count) {
8155 return 1;
8156 }
8157
8158 return 0;
8159 });
8160 return arr;
8161 };
8162
8163 var _topk = topk;
8164
8165 /** pretty-print the current document and its tags */
8166
8167 var debug_1 = function debug_1() {
8168 _debug(this);
8169 return this;
8170 };
8171 /** some named output formats */
8172
8173
8174 var out = function out(method) {
8175 if (method === 'text') {
8176 return this.text();
8177 }
8178
8179 if (method === 'normal') {
8180 return this.text('normal');
8181 }
8182
8183 if (method === 'json') {
8184 return this.json();
8185 }
8186
8187 if (method === 'offset' || method === 'offsets') {
8188 return this.json({
8189 offset: true
8190 });
8191 }
8192
8193 if (method === 'array') {
8194 return this.json({
8195 terms: false
8196 }).map(function (obj) {
8197 return obj.text;
8198 }).filter(function (str) {
8199 return str;
8200 });
8201 }
8202
8203 if (method === 'freq' || method === 'frequency') {
8204 return _topk(this);
8205 }
8206
8207 if (method === 'terms') {
8208 var list = [];
8209 this.json({
8210 text: false,
8211 terms: {
8212 text: true
8213 }
8214 }).forEach(function (obj) {
8215 var terms = obj.terms.map(function (t) {
8216 return t.text;
8217 });
8218 terms = terms.filter(function (t) {
8219 return t;
8220 });
8221 list = list.concat(terms);
8222 });
8223 return list;
8224 }
8225
8226 if (method === 'tags') {
8227 return this.list.map(function (p) {
8228 return p.terms().reduce(function (h, t) {
8229 h[t.clean || t.implicit] = Object.keys(t.tags);
8230 return h;
8231 }, {});
8232 });
8233 }
8234
8235 if (method === 'debug') {
8236 _debug(this);
8237 return this;
8238 }
8239
8240 return this.text();
8241 };
8242
8243 var _03Out = {
8244 debug: debug_1,
8245 out: out
8246 };
8247
8248 var methods$2 = {
8249 /** alphabetical order */
8250 alpha: function alpha(a, b) {
8251 var left = a.text('clean');
8252 var right = b.text('clean');
8253
8254 if (left < right) {
8255 return -1;
8256 }
8257
8258 if (left > right) {
8259 return 1;
8260 }
8261
8262 return 0;
8263 },
8264
8265 /** count the # of characters of each match */
8266 length: function length(a, b) {
8267 var left = a.text().trim().length;
8268 var right = b.text().trim().length;
8269
8270 if (left < right) {
8271 return 1;
8272 }
8273
8274 if (left > right) {
8275 return -1;
8276 }
8277
8278 return 0;
8279 },
8280
8281 /** count the # of terms in each match */
8282 wordCount: function wordCount(a, b) {
8283 var left = a.wordCount();
8284 var right = b.wordCount();
8285
8286 if (left < right) {
8287 return 1;
8288 }
8289
8290 if (left > right) {
8291 return -1;
8292 }
8293
8294 return 0;
8295 }
8296 };
8297 /** sort by # of duplicates in the document*/
8298
8299 var byFreq = function byFreq(doc) {
8300 var counts = {};
8301 var options = {
8302 "case": true,
8303 punctuation: false,
8304 whitespace: true,
8305 unicode: true
8306 };
8307 doc.list.forEach(function (p) {
8308 var str = p.text(options);
8309 counts[str] = counts[str] || 0;
8310 counts[str] += 1;
8311 }); // sort by freq
8312
8313 doc.list.sort(function (a, b) {
8314 var left = counts[a.text(options)];
8315 var right = counts[b.text(options)];
8316
8317 if (left < right) {
8318 return 1;
8319 }
8320
8321 if (left > right) {
8322 return -1;
8323 }
8324
8325 return 0;
8326 });
8327 return doc;
8328 }; // order results 'chronologically', or document-order
8329
8330
8331 var sortSequential = function sortSequential(doc) {
8332 var order = {};
8333 doc.json({
8334 terms: {
8335 offset: true
8336 }
8337 }).forEach(function (o) {
8338 order[o.terms[0].id] = o.terms[0].offset.start;
8339 });
8340 doc.list = doc.list.sort(function (a, b) {
8341 if (order[a.start] > order[b.start]) {
8342 return 1;
8343 } else if (order[a.start] < order[b.start]) {
8344 return -1;
8345 }
8346
8347 return 0;
8348 });
8349 return doc;
8350 }; //aliases
8351
8352
8353 methods$2.alphabetical = methods$2.alpha;
8354 methods$2.wordcount = methods$2.wordCount; // aliases for sequential ordering
8355
8356 var seqNames = {
8357 index: true,
8358 sequence: true,
8359 seq: true,
8360 sequential: true,
8361 chron: true,
8362 chronological: true
8363 };
8364 /** re-arrange the order of the matches (in place) */
8365
8366 var sort = function sort(input) {
8367 input = input || 'alpha'; //do this one up-front
8368
8369 if (input === 'freq' || input === 'frequency' || input === 'topk') {
8370 return byFreq(this);
8371 }
8372
8373 if (seqNames.hasOwnProperty(input)) {
8374 return sortSequential(this);
8375 }
8376
8377 input = methods$2[input] || input; // apply sort method on each phrase
8378
8379 if (typeof input === 'function') {
8380 this.list = this.list.sort(input);
8381 return this;
8382 }
8383
8384 return this;
8385 };
8386 /** reverse the order of the matches, but not the words */
8387
8388
8389 var reverse = function reverse() {
8390 var list = [].concat(this.list);
8391 list = list.reverse();
8392 return this.buildFrom(list);
8393 };
8394 /** remove any duplicate matches */
8395
8396
8397 var unique$4 = function unique() {
8398 var list = [].concat(this.list);
8399 var obj = {};
8400 list = list.filter(function (p) {
8401 var str = p.text('reduced').trim();
8402
8403 if (obj.hasOwnProperty(str) === true) {
8404 return false;
8405 }
8406
8407 obj[str] = true;
8408 return true;
8409 });
8410 return this.buildFrom(list);
8411 };
8412
8413 var _01Sort = {
8414 sort: sort,
8415 reverse: reverse,
8416 unique: unique$4
8417 };
8418
8419 var isPunct = /[\[\]{}⟨⟩:,،、‒–—―…‹›«»‐\-;\/⁄·*\•^†‡°¡¿※№÷׺ª%‰=‱¶§~|‖¦©℗®℠™¤₳฿]/g;
8420 var quotes = /['‘’“”"′″‴]+/g;
8421 var methods$3 = {
8422 // cleanup newlines and extra spaces
8423 whitespace: function whitespace(doc) {
8424 var termArr = doc.list.map(function (ts) {
8425 return ts.terms();
8426 });
8427 termArr.forEach(function (terms, o) {
8428 terms.forEach(function (t, i) {
8429 // keep dashes between words
8430 if (t.hasDash() === true) {
8431 t.post = ' - ';
8432 return;
8433 } // remove existing spaces
8434
8435
8436 t.pre = t.pre.replace(/\s/g, '');
8437 t.post = t.post.replace(/\s/g, ''); //last word? ensure there's a next sentence.
8438
8439 if (terms.length - 1 === i && !termArr[o + 1]) {
8440 return;
8441 } // no extra spaces for contractions
8442
8443
8444 if (t.implicit && Boolean(t.text) === true) {
8445 return;
8446 } // no extra spaces for hyphenated words
8447
8448
8449 if (t.hasHyphen() === true) {
8450 return;
8451 }
8452
8453 t.post += ' ';
8454 });
8455 });
8456 },
8457 punctuation: function punctuation(termList) {
8458 termList.forEach(function (t) {
8459 // space between hyphenated words
8460 if (t.hasHyphen() === true) {
8461 t.post = ' ';
8462 }
8463
8464 t.pre = t.pre.replace(isPunct, '');
8465 t.post = t.post.replace(isPunct, ''); // elipses
8466
8467 t.post = t.post.replace(/\.\.\./, ''); // only allow one exclamation
8468
8469 if (/!/.test(t.post) === true) {
8470 t.post = t.post.replace(/!/g, '');
8471 t.post = '!' + t.post;
8472 } // only allow one question mark
8473
8474
8475 if (/\?/.test(t.post) === true) {
8476 t.post = t.post.replace(/[\?!]*/, '');
8477 t.post = '?' + t.post;
8478 }
8479 });
8480 },
8481 unicode: function unicode(termList) {
8482 termList.forEach(function (t) {
8483 if (t.isImplicit() === true) {
8484 return;
8485 }
8486
8487 t.text = unicode_1(t.text);
8488 });
8489 },
8490 quotations: function quotations(termList) {
8491 termList.forEach(function (t) {
8492 t.post = t.post.replace(quotes, '');
8493 t.pre = t.pre.replace(quotes, '');
8494 });
8495 },
8496 adverbs: function adverbs(doc) {
8497 doc.match('#Adverb').not('(not|nary|seldom|never|barely|almost|basically|so)').remove();
8498 },
8499 // remove the '.' from 'Mrs.' (safely)
8500 abbreviations: function abbreviations(doc) {
8501 doc.list.forEach(function (ts) {
8502 var terms = ts.terms();
8503 terms.forEach(function (t, i) {
8504 if (t.tags.Abbreviation === true && terms[i + 1]) {
8505 t.post = t.post.replace(/^\./, '');
8506 }
8507 });
8508 });
8509 }
8510 };
8511 var _methods = methods$3;
8512
8513 var defaults = {
8514 // light
8515 whitespace: true,
8516 unicode: true,
8517 punctuation: true,
8518 emoji: true,
8519 acronyms: true,
8520 abbreviations: true,
8521 // medium
8522 "case": false,
8523 contractions: false,
8524 parentheses: false,
8525 quotations: false,
8526 adverbs: false,
8527 // heavy (loose legibility)
8528 possessives: false,
8529 verbs: false,
8530 nouns: false,
8531 honorifics: false // pronouns: true,
8532
8533 };
8534 var mapping$1 = {
8535 light: {},
8536 medium: {
8537 "case": true,
8538 contractions: true,
8539 parentheses: true,
8540 quotations: true,
8541 adverbs: true
8542 }
8543 };
8544 mapping$1.heavy = Object.assign({}, mapping$1.medium, {
8545 possessives: true,
8546 verbs: true,
8547 nouns: true,
8548 honorifics: true
8549 });
8550 /** common ways to clean-up the document, and reduce noise */
8551
8552 var normalize = function normalize(options) {
8553 options = options || {}; // support named forms
8554
8555 if (typeof options === 'string') {
8556 options = mapping$1[options] || {};
8557 } // set defaults
8558
8559
8560 options = Object.assign({}, defaults, options); // clear the cache
8561
8562 this.uncache();
8563 var termList = this.termList(); // lowercase things
8564
8565 if (options["case"]) {
8566 this.toLowerCase();
8567 } //whitespace
8568
8569
8570 if (options.whitespace) {
8571 _methods.whitespace(this);
8572 } // unicode: é -> e
8573
8574
8575 if (options.unicode) {
8576 _methods.unicode(termList);
8577 } //punctuation - keep sentence punctation, quotes, parenths
8578
8579
8580 if (options.punctuation) {
8581 _methods.punctuation(termList);
8582 } // remove ':)'
8583
8584
8585 if (options.emoji) {
8586 this.remove('(#Emoji|#Emoticon)');
8587 } // 'f.b.i.' -> 'FBI'
8588
8589
8590 if (options.acronyms) {
8591 this.acronyms().strip(); // .toUpperCase()
8592 } // remove period from abbreviations
8593
8594
8595 if (options.abbreviations) {
8596 _methods.abbreviations(this);
8597 } // --Medium methods--
8598 // `isn't` -> 'is not'
8599
8600
8601 if (options.contraction || options.contractions) {
8602 this.contractions().expand();
8603 } // '(word)' -> 'word'
8604
8605
8606 if (options.parentheses) {
8607 this.parentheses().unwrap();
8608 } // remove "" punctuation
8609
8610
8611 if (options.quotations || options.quotes) {
8612 _methods.quotations(termList);
8613 } // remove any un-necessary adverbs
8614
8615
8616 if (options.adverbs) {
8617 _methods.adverbs(this);
8618 } // --Heavy methods--
8619 // `cory hart's -> cory hart'
8620
8621
8622 if (options.possessive || options.possessives) {
8623 this.possessives().strip();
8624 } // 'he walked' -> 'he walk'
8625
8626
8627 if (options.verbs) {
8628 this.verbs().toInfinitive();
8629 } // 'three dogs' -> 'three dog'
8630
8631
8632 if (options.nouns || options.plurals) {
8633 this.nouns().toSingular();
8634 } // remove 'Mr.' from 'Mr John Smith'
8635
8636
8637 if (options.honorifics) {
8638 this.remove('#Honorific');
8639 }
8640
8641 return this;
8642 };
8643
8644 var _02Normalize = {
8645 normalize: normalize
8646 };
8647
8648 var _03Split = createCommonjsModule(function (module, exports) {
8649 /** return a Document with three parts for every match
8650 * seperate everything before the word, as a new phrase
8651 */
8652 exports.splitOn = function (reg) {
8653 // if there's no match, split parent, instead
8654 if (!reg) {
8655 var parent = this.parent();
8656 return parent.splitOn(this);
8657 } //start looking for a match..
8658
8659
8660 var regs = matchSyntax(reg);
8661 var matches = [];
8662 this.list.forEach(function (p) {
8663 var foundEm = p.match(regs); //no match here, add full sentence
8664
8665 if (foundEm.length === 0) {
8666 matches.push(p);
8667 return;
8668 } // we found something here.
8669
8670
8671 var carry = p;
8672 foundEm.forEach(function (found) {
8673 var parts = carry.splitOn(found); // add em in
8674
8675 if (parts.before) {
8676 matches.push(parts.before);
8677 }
8678
8679 if (parts.match) {
8680 matches.push(parts.match);
8681 } // start matching now on the end
8682
8683
8684 carry = parts.after;
8685 }); // add that last part
8686
8687 if (carry) {
8688 matches.push(carry);
8689 }
8690 });
8691 return this.buildFrom(matches);
8692 };
8693 /** return a Document with two parts for every match
8694 * seperate everything after the word, as a new phrase
8695 */
8696
8697
8698 exports.splitAfter = function (reg) {
8699 // if there's no match, split parent, instead
8700 if (!reg) {
8701 var parent = this.parent();
8702 return parent.splitAfter(this);
8703 } // start looking for our matches
8704
8705
8706 var regs = matchSyntax(reg);
8707 var matches = [];
8708 this.list.forEach(function (p) {
8709 var foundEm = p.match(regs); //no match here, add full sentence
8710
8711 if (foundEm.length === 0) {
8712 matches.push(p);
8713 return;
8714 } // we found something here.
8715
8716
8717 var carry = p;
8718 foundEm.forEach(function (found) {
8719 var parts = carry.splitOn(found); // add em in
8720
8721 if (parts.before && parts.match) {
8722 // merge these two together
8723 parts.before.length += parts.match.length;
8724 matches.push(parts.before);
8725 } else if (parts.match) {
8726 matches.push(parts.match);
8727 } // start matching now on the end
8728
8729
8730 carry = parts.after;
8731 }); // add that last part
8732
8733 if (carry) {
8734 matches.push(carry);
8735 }
8736 });
8737 return this.buildFrom(matches);
8738 };
8739
8740 exports.split = exports.splitAfter; //i guess?
8741
8742 /** return a Document with two parts for every match */
8743
8744 exports.splitBefore = function (reg) {
8745 // if there's no match, split parent, instead
8746 if (!reg) {
8747 var parent = this.parent();
8748 return parent.splitBefore(this);
8749 } //start looking for a match..
8750
8751
8752 var regs = matchSyntax(reg);
8753 var matches = [];
8754 this.list.forEach(function (p) {
8755 var foundEm = p.match(regs); //no match here, add full sentence
8756
8757 if (foundEm.length === 0) {
8758 matches.push(p);
8759 return;
8760 } // we found something here.
8761
8762
8763 var carry = p;
8764 foundEm.forEach(function (found) {
8765 var parts = carry.splitOn(found); // add before part in
8766
8767 if (parts.before) {
8768 matches.push(parts.before);
8769 } // merge match+after
8770
8771
8772 if (parts.match && parts.after) {
8773 parts.match.length += parts.after.length;
8774 } // start matching now on the end
8775
8776
8777 carry = parts.match;
8778 }); // add that last part
8779
8780 if (carry) {
8781 matches.push(carry);
8782 }
8783 });
8784 return this.buildFrom(matches);
8785 };
8786 /** split a document into labeled sections */
8787
8788
8789 exports.segment = function (regs, options) {
8790 regs = regs || {};
8791 options = options || {
8792 text: true
8793 };
8794 var doc = this;
8795 var keys = Object.keys(regs); // split em
8796
8797 keys.forEach(function (k) {
8798 doc = doc.splitOn(k);
8799 }); //add labels for each section
8800
8801 doc.list.forEach(function (p) {
8802 for (var i = 0; i < keys.length; i += 1) {
8803 if (p.has(keys[i])) {
8804 p.segment = regs[keys[i]];
8805 return;
8806 }
8807 }
8808 });
8809 return doc.list.map(function (p) {
8810 var res = p.json(options);
8811 res.segment = p.segment || null;
8812 return res;
8813 });
8814 };
8815 });
8816
8817 var eachTerm = function eachTerm(doc, fn) {
8818 var world = doc.world;
8819 doc.list.forEach(function (p) {
8820 p.terms().forEach(function (t) {
8821 return t[fn](world);
8822 });
8823 });
8824 return doc;
8825 };
8826 /** turn every letter of every term to lower-cse */
8827
8828
8829 var toLowerCase = function toLowerCase() {
8830 return eachTerm(this, 'toLowerCase');
8831 };
8832 /** turn every letter of every term to upper case */
8833
8834
8835 var toUpperCase = function toUpperCase() {
8836 return eachTerm(this, 'toUpperCase');
8837 };
8838 /** upper-case the first letter of each term */
8839
8840
8841 var toTitleCase = function toTitleCase() {
8842 return eachTerm(this, 'toTitleCase');
8843 };
8844 /** remove whitespace and title-case each term */
8845
8846
8847 var toCamelCase = function toCamelCase() {
8848 this.list.forEach(function (p) {
8849 //remove whitespace
8850 var terms = p.terms();
8851 terms.forEach(function (t, i) {
8852 if (i !== 0) {
8853 t.toTitleCase();
8854 }
8855
8856 if (i !== terms.length - 1) {
8857 t.post = '';
8858 }
8859 });
8860 }); // this.tag('#CamelCase', 'toCamelCase')
8861
8862 return this;
8863 };
8864
8865 var _04Case = {
8866 toLowerCase: toLowerCase,
8867 toUpperCase: toUpperCase,
8868 toTitleCase: toTitleCase,
8869 toCamelCase: toCamelCase
8870 };
8871
8872 /** add this punctuation or whitespace before each match: */
8873
8874 var _05Whitespace = createCommonjsModule(function (module, exports) {
8875 exports.pre = function (str, concat) {
8876 if (str === undefined) {
8877 return this.list[0].terms(0).pre;
8878 }
8879
8880 this.list.forEach(function (p) {
8881 var term = p.terms(0);
8882
8883 if (concat === true) {
8884 term.pre += str;
8885 } else {
8886 term.pre = str;
8887 }
8888 });
8889 return this;
8890 };
8891 /** add this punctuation or whitespace after each match: */
8892
8893
8894 exports.post = function (str, concat) {
8895 // return array of post strings
8896 if (str === undefined) {
8897 return this.list.map(function (p) {
8898 var terms = p.terms();
8899 var term = terms[terms.length - 1];
8900 return term.post;
8901 });
8902 } // set post string on all ends
8903
8904
8905 this.list.forEach(function (p) {
8906 var terms = p.terms();
8907 var term = terms[terms.length - 1];
8908
8909 if (concat === true) {
8910 term.post += str;
8911 } else {
8912 term.post = str;
8913 }
8914 });
8915 return this;
8916 };
8917 /** remove start and end whitespace */
8918
8919
8920 exports.trim = function () {
8921 this.list = this.list.map(function (p) {
8922 return p.trim();
8923 });
8924 return this;
8925 };
8926 /** connect words with hyphen, and remove whitespace */
8927
8928
8929 exports.hyphenate = function () {
8930 this.list.forEach(function (p) {
8931 var terms = p.terms(); //remove whitespace
8932
8933 terms.forEach(function (t, i) {
8934 if (i !== 0) {
8935 t.pre = '';
8936 }
8937
8938 if (terms[i + 1]) {
8939 t.post = '-';
8940 }
8941 });
8942 });
8943 return this;
8944 };
8945 /** remove hyphens between words, and set whitespace */
8946
8947
8948 exports.dehyphenate = function () {
8949 var hasHyphen = /(-|–|—)/;
8950 this.list.forEach(function (p) {
8951 var terms = p.terms(); //remove whitespace
8952
8953 terms.forEach(function (t) {
8954 if (hasHyphen.test(t.post)) {
8955 t.post = ' ';
8956 }
8957 });
8958 });
8959 return this;
8960 };
8961
8962 exports.deHyphenate = exports.dehyphenate;
8963 /** add quotations around these matches */
8964
8965 exports.toQuotations = function (start, end) {
8966 start = start || "\"";
8967 end = end || "\"";
8968 this.list.forEach(function (p) {
8969 var terms = p.terms();
8970 terms[0].pre = start + terms[0].pre;
8971 var last = terms[terms.length - 1];
8972 last.post = end + last.post;
8973 });
8974 return this;
8975 };
8976
8977 exports.toQuotation = exports.toQuotations;
8978 /** add brackets around these matches */
8979
8980 exports.toParentheses = function (start, end) {
8981 start = start || "(";
8982 end = end || ")";
8983 this.list.forEach(function (p) {
8984 var terms = p.terms();
8985 terms[0].pre = start + terms[0].pre;
8986 var last = terms[terms.length - 1];
8987 last.post = end + last.post;
8988 });
8989 return this;
8990 };
8991 });
8992
8993 /** make all phrases into one phrase */
8994 var join = function join(str) {
8995 // clear the cache
8996 this.uncache(); // make one large phrase - 'main'
8997
8998 var main = this.list[0];
8999 var before = main.length;
9000 var removed = {};
9001
9002 for (var i = 1; i < this.list.length; i++) {
9003 var p = this.list[i];
9004 removed[p.start] = true;
9005 var term = main.lastTerm(); // add whitespace between them
9006
9007 if (str) {
9008 term.post += str;
9009 } // main -> p
9010
9011
9012 term.next = p.start; // main <- p
9013
9014 p.terms(0).prev = term.id;
9015 main.length += p.length;
9016 main.cache = {};
9017 } // parents are bigger than than their children.
9018 // when we increase a child, we increase their parent too.
9019
9020
9021 var increase = main.length - before;
9022 this.parents().forEach(function (doc) {
9023 // increase length on each effected phrase
9024 doc.list.forEach(function (p) {
9025 var terms = p.terms();
9026
9027 for (var _i = 0; _i < terms.length; _i++) {
9028 if (terms[_i].id === main.start) {
9029 p.length += increase;
9030 break;
9031 }
9032 }
9033
9034 p.cache = {};
9035 }); // remove redundant phrases now
9036
9037 doc.list = doc.list.filter(function (p) {
9038 return removed[p.start] !== true;
9039 });
9040 }); // return one major phrase
9041
9042 return this.buildFrom([main]);
9043 };
9044
9045 var _06Join = {
9046 join: join
9047 };
9048
9049 var postPunct = /[,\)"';:\-–—\.…]/; // const irregulars = {
9050 // 'will not': `won't`,
9051 // 'i am': `i'm`,
9052 // }
9053
9054 var setContraction = function setContraction(m, suffix) {
9055 if (!m.found) {
9056 return;
9057 }
9058
9059 var terms = m.termList(); //avoid any problematic punctuation
9060
9061 for (var i = 0; i < terms.length - 1; i++) {
9062 var t = terms[i];
9063
9064 if (postPunct.test(t.post)) {
9065 return;
9066 }
9067 } // set them as implict
9068
9069
9070 terms.forEach(function (t) {
9071 t.implicit = t.clean;
9072 }); // perform the contraction
9073
9074 terms[0].text += suffix; // clean-up the others
9075
9076 terms.slice(1).forEach(function (t) {
9077 t.text = '';
9078 });
9079
9080 for (var _i = 0; _i < terms.length - 1; _i++) {
9081 var _t = terms[_i];
9082 _t.post = _t.post.replace(/ /, '');
9083 }
9084 };
9085 /** turn 'i am' into i'm */
9086
9087
9088 var contract = function contract() {
9089 var doc = this.not('@hasContraction'); // we are -> we're
9090
9091 var m = doc.match('(we|they|you) are');
9092 setContraction(m, "'re"); // they will -> they'll
9093
9094 m = doc.match('(he|she|they|it|we|you) will');
9095 setContraction(m, "'ll"); // she is -> she's
9096
9097 m = doc.match('(he|she|they|it|we) is');
9098 setContraction(m, "'s"); // spencer is -> spencer's
9099
9100 m = doc.match('#Person is');
9101 setContraction(m, "'s"); // spencer would -> spencer'd
9102
9103 m = doc.match('#Person would');
9104 setContraction(m, "'d"); // would not -> wouldn't
9105
9106 m = doc.match('(is|was|had|would|should|could|do|does|have|has|can) not');
9107 setContraction(m, "n't"); // i have -> i've
9108
9109 m = doc.match('(i|we|they) have');
9110 setContraction(m, "'ve"); // would have -> would've
9111
9112 m = doc.match('(would|should|could) have');
9113 setContraction(m, "'ve"); // i am -> i'm
9114
9115 m = doc.match('i am');
9116 setContraction(m, "'m"); // going to -> gonna
9117
9118 m = doc.match('going to');
9119 return this;
9120 };
9121
9122 var _07Contract = {
9123 contract: contract
9124 };
9125
9126 var methods$4 = Object.assign({}, _01Utils$1, _02Accessors, _03Match, _04Tag, _05Loops, _06Lookup, _07Cache, _01Replace, _02Insert, _01Text, _02Json, _03Out, _01Sort, _02Normalize, _03Split, _04Case, _05Whitespace, _06Join, _07Contract);
9127
9128 var methods$5 = {}; // allow helper methods like .adjectives() and .adverbs()
9129
9130 var 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']];
9131 arr.forEach(function (a) {
9132 methods$5[a[0]] = function (n) {
9133 var m = this.match(a[1]);
9134
9135 if (typeof n === 'number') {
9136 m = m.get(n);
9137 }
9138
9139 return m;
9140 };
9141 }); // aliases
9142
9143 methods$5.emojis = methods$5.emoji;
9144 methods$5.atmentions = methods$5.atMentions;
9145 methods$5.words = methods$5.terms;
9146 /** return anything tagged as a phone number */
9147
9148 methods$5.phoneNumbers = function (n) {
9149 var m = this.splitAfter('@hasComma');
9150 m = m.match('#PhoneNumber+');
9151
9152 if (typeof n === 'number') {
9153 m = m.get(n);
9154 }
9155
9156 return m;
9157 };
9158 /** Deprecated: please use compromise-numbers plugin */
9159
9160
9161 methods$5.money = function (n) {
9162 var m = this.match('#Money #Currency?');
9163
9164 if (typeof n === 'number') {
9165 m = m.get(n);
9166 }
9167
9168 return m;
9169 };
9170 /** return all cities, countries, addresses, and regions */
9171
9172
9173 methods$5.places = function (n) {
9174 // don't split 'paris, france'
9175 var keep = this.match('(#City && @hasComma) (#Region|#Country)'); // but split the other commas
9176
9177 var m = this.not(keep).splitAfter('@hasComma'); // combine them back together
9178
9179 m = m.concat(keep);
9180 m.sort('index');
9181 m = m.match('#Place+');
9182
9183 if (typeof n === 'number') {
9184 m = m.get(n);
9185 }
9186
9187 return m;
9188 };
9189 /** return all schools, businesses and institutions */
9190
9191
9192 methods$5.organizations = function (n) {
9193 var m = this.clauses();
9194 m = m.match('#Organization+');
9195
9196 if (typeof n === 'number') {
9197 m = m.get(n);
9198 }
9199
9200 return m;
9201 }; //combine them with .topics() method
9202
9203
9204 methods$5.entities = function (n) {
9205 var r = this.clauses(); // Find people, places, and organizations
9206
9207 var yup = r.people();
9208 yup = yup.concat(r.places());
9209 yup = yup.concat(r.organizations());
9210 var ignore = ['someone', 'man', 'woman', 'mother', 'brother', 'sister', 'father'];
9211 yup = yup.not(ignore); //return them to normal ordering
9212
9213 yup.sort('sequence'); // yup.unique() //? not sure
9214
9215 if (typeof n === 'number') {
9216 yup = yup.get(n);
9217 }
9218
9219 return yup;
9220 }; //aliases
9221
9222
9223 methods$5.things = methods$5.entities;
9224 methods$5.topics = methods$5.entities;
9225 var _simple = methods$5;
9226
9227 var underOver = /^(under|over)-?/;
9228 /** match a word-sequence, like 'super bowl' in the lexicon */
9229
9230 var tryMultiple = function tryMultiple(terms, t, world) {
9231 var lex = world.words; //try a two-word version
9232
9233 var txt = terms[t].reduced + ' ' + terms[t + 1].reduced;
9234
9235 if (lex[txt] !== undefined && lex.hasOwnProperty(txt) === true) {
9236 terms[t].tag(lex[txt], 'lexicon-two', world);
9237 terms[t + 1].tag(lex[txt], 'lexicon-two', world);
9238 return 1;
9239 } //try a three-word version?
9240
9241
9242 if (t + 2 < terms.length) {
9243 txt += ' ' + terms[t + 2].reduced;
9244
9245 if (lex[txt] !== undefined && lex.hasOwnProperty(txt) === true) {
9246 terms[t].tag(lex[txt], 'lexicon-three', world);
9247 terms[t + 1].tag(lex[txt], 'lexicon-three', world);
9248 terms[t + 2].tag(lex[txt], 'lexicon-three', world);
9249 return 2;
9250 }
9251 } //try a four-word version?
9252
9253
9254 if (t + 3 < terms.length) {
9255 txt += ' ' + terms[t + 3].reduced;
9256
9257 if (lex[txt] !== undefined && lex.hasOwnProperty(txt) === true) {
9258 terms[t].tag(lex[txt], 'lexicon-four', world);
9259 terms[t + 1].tag(lex[txt], 'lexicon-four', world);
9260 terms[t + 2].tag(lex[txt], 'lexicon-four', world);
9261 terms[t + 3].tag(lex[txt], 'lexicon-four', world);
9262 return 3;
9263 }
9264 }
9265
9266 return 0;
9267 };
9268 /** look at each word in our list of known-words */
9269
9270
9271 var checkLexicon = function checkLexicon(terms, world) {
9272 var lex = world.words;
9273 var hasCompound = world.hasCompound; // use reduced?
9274 //go through each term, and check the lexicon
9275
9276 for (var t = 0; t < terms.length; t += 1) {
9277 var str = terms[t].clean; //is it the start of a compound word, like 'super bowl'?
9278
9279 if (hasCompound[str] === true && t + 1 < terms.length) {
9280 var foundWords = tryMultiple(terms, t, world);
9281
9282 if (foundWords > 0) {
9283 t += foundWords; //skip any already-found words
9284
9285 continue;
9286 }
9287 } //try one-word lexicon
9288
9289
9290 if (lex[str] !== undefined && lex.hasOwnProperty(str) === true) {
9291 terms[t].tag(lex[str], 'lexicon', world);
9292 continue;
9293 } // look at reduced version of term, too
9294
9295
9296 if (str !== terms[t].reduced && lex.hasOwnProperty(terms[t].reduced) === true) {
9297 terms[t].tag(lex[terms[t].reduced], 'lexicon', world);
9298 continue;
9299 } // prefix strip: try to match 'take' for 'undertake'
9300
9301
9302 if (underOver.test(str) === true) {
9303 var noPrefix = str.replace(underOver, '');
9304
9305 if (lex.hasOwnProperty(noPrefix) === true) {
9306 terms[t].tag(lex[noPrefix], 'noprefix-lexicon', world);
9307 }
9308 }
9309 }
9310
9311 return terms;
9312 };
9313
9314 var _01Lexicon = checkLexicon;
9315
9316 var apostrophes = /[\'‘’‛‵′`´]$/;
9317 var perSec = /^(m|k|cm|km|m)\/(s|h|hr)$/; // '5 k/m'
9318 //
9319
9320 var checkPunctuation = function checkPunctuation(terms, i, world) {
9321 var term = terms[i]; //check hyphenation
9322 // if (term.post.indexOf('-') !== -1 && terms[i + 1] && terms[i + 1].pre === '') {
9323 // term.tag('Hyphenated', 'has-hyphen', world)
9324 // }
9325 // support 'head-over'
9326 // if (term.hasHyphen() === true) {
9327 // console.log(term.tags)
9328 // }
9329 // console.log(term.hasHyphen(), term.text)
9330 //an end-tick (trailing apostrophe) - flanders', or Carlos'
9331
9332 if (apostrophes.test(term.text)) {
9333 if (!apostrophes.test(term.pre) && !apostrophes.test(term.post) && term.clean.length > 2) {
9334 var endChar = term.clean[term.clean.length - 2]; //flanders'
9335
9336 if (endChar === 's') {
9337 term.tag(['Possessive', 'Noun'], 'end-tick', world);
9338 return;
9339 } //chillin'
9340
9341
9342 if (endChar === 'n') {
9343 term.tag(['Gerund'], 'chillin', world);
9344 }
9345 }
9346 } // '5 km/s'
9347
9348
9349 if (perSec.test(term.text)) {
9350 term.tag('Unit', 'per-sec', world);
9351 } // 'NASA' is, but not 'i REALLY love it.'
9352 // if (term.tags.Noun === true && isAcronym(term, world)) {
9353 // term.tag('Acronym', 'acronym-step', world)
9354 // term.tag('Noun', 'acronym-infer', world)
9355 // } else if (!oneLetterWord.hasOwnProperty(term.text) && oneLetterAcronym.test(term.text)) {
9356 // term.tag('Acronym', 'one-letter-acronym', world)
9357 // term.tag('Noun', 'one-letter-infer', world)
9358 // }
9359
9360 };
9361
9362 var _02Punctuation$1 = checkPunctuation;
9363
9364 //these are regexes applied to t.text, instead of t.clean
9365 // order matters.
9366 var startsWith = [//web tags
9367 [/^[\w\.]+@[\w\.]+\.[a-z]{2,3}$/, 'Email'], //not fancy
9368 [/^#[a-z0-9_\u00C0-\u00FF]{2,}$/, 'HashTag'], [/^@1?[0-9](am|pm)$/i, 'Time'], // @6pm
9369 [/^@1?[0-9]:[0-9]{2}(am|pm)?$/i, 'Time'], // @6:30
9370 [/^@\w{2,}$/, 'AtMention'], //@spencermountain
9371 [/^(https?:\/\/|www\.)\w+\.[a-z]{2,3}/, 'Url'], //with http/www
9372 [/^[\w./]+\.(com|net|gov|org|ly|edu|info|biz|ru|jp|de|in|uk|br)/, 'Url'], //http://mostpopularwebsites.net/top-level-domain
9373 //dates/times
9374 [/^'[0-9]{2}$/, 'Year'], //like '97
9375 [/^[012]?[0-9](:[0-5][0-9])(:[0-5][0-9])$/, 'Time'], //4:32:32
9376 [/^[012]?[0-9](:[0-5][0-9])?(:[0-5][0-9])? ?(am|pm)$/i, 'Time'], //4pm
9377 [/^[012]?[0-9](:[0-5][0-9])(:[0-5][0-9])? ?(am|pm)?$/i, 'Time'], //4:00pm
9378 [/^[PMCE]ST$/, 'Time'], //PST, time zone abbrevs
9379 [/^utc ?[+-]?[0-9]+?$/, 'Time'], //UTC 8+
9380 [/^[a-z0-9]*? o\'?clock$/, 'Time'], //3 oclock
9381 [/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}/i, 'Date'], // 2020-03-02T00:00:00.000Z
9382 [/^[0-9]{1,4}-[0-9]{1,2}-[0-9]{1,4}$/, 'Date'], // 03-02-89
9383 [/^[0-9]{1,4}\/[0-9]{1,2}\/[0-9]{1,4}$/, 'Date'], // 03/02/89
9384 [/^[0-9]{1,4}-[a-z]{2,9}-[0-9]{1,4}$/i, 'Date'], // 03-March-89
9385 //names
9386 [/^ma?c\'.*/, 'LastName'], //mc'adams
9387 [/^o\'[drlkn].*/, 'LastName'], //o'douggan
9388 [/^ma?cd[aeiou]/, 'LastName'], //macdonell - Last patterns https://en.wikipedia.org/wiki/List_of_family_name_affixes
9389 //slang things
9390 [/^(lol)+[sz]$/, 'Expression'], //lol
9391 [/^woo+a*?h?$/, 'Expression'], //whoaa, wooo
9392 [/^(un|de|re)\\-[a-z\u00C0-\u00FF]{2}/, 'Verb'], // [/^(over|under)[a-z]{2,}/, 'Adjective'],
9393 [/^[0-9]{1,4}\.[0-9]{1,2}\.[0-9]{1,4}$/, 'Date'], // 03-02-89
9394 //phone numbers
9395 [/^[0-9]{3}-[0-9]{4}$/, 'PhoneNumber'], //589-3809
9396 [/^(\+?[0-9][ -])?[0-9]{3}[ -]?[0-9]{3}-[0-9]{4}$/, 'PhoneNumber'], //632-589-3809
9397 //money
9398 // currency regex
9399 // /[\$\xA2-\xA5\u058F\u060B\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u17DB\u20A0-\u20BD\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6]
9400 //like $5.30
9401 [/^[-+]?[\$\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$
9402 [/^[-+]?[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
9403 [/^[-+]?[\$£]?[0-9]([0-9,.])+?(usd|eur|jpy|gbp|cad|aud|chf|cny|hkd|nzd|kr|rub)$/i, ['Money', 'Value']], //numbers
9404 // 50 | -50 | 3.23 | 5,999.0 | 10+
9405 [/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?\+?$/, ['Cardinal', 'NumericValue']], [/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?(st|nd|rd|r?th)$/, ['Ordinal', 'NumericValue']], // .73th
9406 [/^\.[0-9]+\+?$/, ['Cardinal', 'NumericValue']], //percent
9407 [/^[-+]?[0-9]+(,[0-9]{3})*(\.[0-9]+)?%\+?$/, ['Percent', 'Cardinal', 'NumericValue']], //7% ..
9408 [/^\.[0-9]+%$/, ['Percent', 'Cardinal', 'NumericValue']], //.7% ..
9409 //fraction
9410 [/^[0-9]{1,4}\/[0-9]{1,4}(st|nd|rd|th)?s?$/, 'Fraction'], //3/2ths
9411 //range
9412 [/^[0-9.]{1,2}[-–][0-9]{1,2}$/, ['Value', 'NumberRange']], //7-8
9413 [/^[0-9.]{1,3}(st|nd|rd|th)?[-–][0-9\.]{1,3}(st|nd|rd|th)?$/, 'NumberRange'], //5-7
9414 //with unit
9415 [/^[0-9.]+([a-z]{1,4})$/, 'Value'] //like 5tbsp
9416 //ordinal
9417 // [/^[0-9][0-9,.]*(st|nd|rd|r?th)$/, ['NumericValue', 'Ordinal']], //like 5th
9418 // [/^[0-9]+(st|nd|rd|th)$/, 'Ordinal'], //like 5th
9419 ];
9420
9421 var romanNumeral = /^[IVXLCDM]{2,}$/;
9422 var 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
9423 //try each of the ^regexes in our list
9424
9425 var checkRegex = function checkRegex(term, world) {
9426 var str = term.text; // do them all!
9427
9428 for (var r = 0; r < startsWith.length; r += 1) {
9429 if (startsWith[r][0].test(str) === true) {
9430 term.tagSafe(startsWith[r][1], 'prefix #' + r, world);
9431 break;
9432 }
9433 } // do some more!
9434 //roman numberals - XVII
9435
9436
9437 if (term.text.length >= 2 && romanNumeral.test(str) && romanNumValid.test(str)) {
9438 term.tag('RomanNumeral', 'xvii', world);
9439 }
9440 };
9441
9442 var _03Prefixes = checkRegex;
9443
9444 //regex suffix patterns and their most common parts of speech,
9445 //built using wordnet, by spencer kelly.
9446 //this mapping shrinks-down the uglified build
9447 var Adj = 'Adjective';
9448 var Inf = 'Infinitive';
9449 var Pres = 'PresentTense';
9450 var Sing = 'Singular';
9451 var Past = 'PastTense';
9452 var Adverb = 'Adverb';
9453 var Exp = 'Expression';
9454 var Actor = 'Actor';
9455 var Verb = 'Verb';
9456 var Noun = 'Noun';
9457 var Last = 'LastName'; //the order here matters.
9458 //regexes indexed by mandated last-character
9459
9460 var endsWith$1 = {
9461 a: [[/.[aeiou]na$/, Noun], [/.[oau][wvl]ska$/, Last], //polish (female)
9462 [/.[^aeiou]ica$/, Sing], [/^([hyj]a)+$/, Exp] //hahah
9463 ],
9464 c: [[/.[^aeiou]ic$/, Adj]],
9465 d: [//==-ed==
9466 //double-consonant
9467 [/[aeiou](pp|ll|ss|ff|gg|tt|rr|bb|nn|mm)ed$/, Past], //popped, planned
9468 //double-vowel
9469 [/.[aeo]{2}[bdgmnprvz]ed$/, Past], //beeped, mooned, veered
9470 //-hed
9471 [/.[aeiou][sg]hed$/, Past], //stashed, sighed
9472 //-rd
9473 [/.[aeiou]red$/, Past], //stored
9474 [/.[aeiou]r?ried$/, Past], //buried
9475 //-led
9476 [/.[bcdgtr]led$/, Past], //startled, rumbled
9477 [/.[aoui]f?led$/, Past], //impaled, stifled
9478 //-sed
9479 [/.[iao]sed$/, Past], //franchised
9480 [/[aeiou]n?[cs]ed$/, Past], //laced, lanced
9481 //-med
9482 [/[aeiou][rl]?[mnf]ed$/, Past], //warmed, attained, engulfed
9483 //-ked
9484 [/[aeiou][ns]?c?ked$/, Past], //hooked, masked
9485 //-ged
9486 [/[aeiou][nl]?ged$/, Past], //engaged
9487 //-ted
9488 [/.[tdbwxz]ed$/, Past], //bribed, boxed
9489 [/[^aeiou][aeiou][tvx]ed$/, Past], //boxed
9490 //-ied
9491 [/.[cdlmnprstv]ied$/, Past], //rallied
9492 [/[^aeiou]ard$/, Sing], //card
9493 [/[aeiou][^aeiou]id$/, Adj], [/.[vrl]id$/, Adj]],
9494 e: [[/.[lnr]ize$/, Inf], [/.[^aeiou]ise$/, Inf], [/.[aeiou]te$/, Inf], [/.[^aeiou][ai]ble$/, Adj], [/.[^aeiou]eable$/, Adj], [/.[ts]ive$/, Adj]],
9495 h: [[/.[^aeiouf]ish$/, Adj], [/.v[iy]ch$/, Last], //east-europe
9496 [/^ug?h+$/, Exp], //uhh
9497 [/^uh[ -]?oh$/, Exp] //uhoh
9498 ],
9499 i: [[/.[oau][wvl]ski$/, Last] //polish (male)
9500 ],
9501 k: [[/^(k){2}$/, Exp] //kkkk
9502 ],
9503 l: [[/.[gl]ial$/, Adj], [/.[^aeiou]ful$/, Adj], [/.[nrtumcd]al$/, Adj], [/.[^aeiou][ei]al$/, Adj]],
9504 m: [[/.[^aeiou]ium$/, Sing], [/[^aeiou]ism$/, Sing], [/^h*u*m+$/, Exp], //mmmmmmm / ummmm / huuuuuummmmmm
9505 [/^\d+ ?[ap]m$/, 'Date']],
9506 n: [[/.[lsrnpb]ian$/, Adj], [/[^aeiou]ician$/, Actor], [/[aeiou][ktrp]in$/, 'Gerund'] // 'cookin', 'hootin'
9507 ],
9508 o: [[/^no+$/, Exp], //noooo
9509 [/^(yo)+$/, Exp], //yoyo
9510 [/^woo+[pt]?$/, Exp] //woo
9511 ],
9512 r: [[/.[bdfklmst]ler$/, 'Noun'], [/[aeiou][pns]er$/, Sing], [/[^i]fer$/, Inf], [/.[^aeiou][ao]pher$/, Actor], [/.[lk]er$/, 'Noun'], [/.ier$/, 'Comparative']],
9513 t: [[/.[di]est$/, 'Superlative'], [/.[icldtgrv]ent$/, Adj], [/[aeiou].*ist$/, Adj], [/^[a-z]et$/, Verb]],
9514 s: [[/.[^aeiou]ises$/, Pres], [/.[rln]ates$/, Pres], [/.[^z]ens$/, Verb], [/.[lstrn]us$/, Sing], [/.[aeiou]sks$/, Pres], //masks
9515 [/.[aeiou]kes$/, Pres], //bakes
9516 [/[aeiou][^aeiou]is$/, Sing], [/[a-z]\'s$/, Noun], [/^yes+$/, Exp] //yessss
9517 ],
9518 v: [[/.[^aeiou][ai][kln]ov$/, Last] //east-europe
9519 ],
9520 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]]
9521 };
9522
9523 //just a foolish lookup of known suffixes
9524 var Adj$1 = 'Adjective';
9525 var Inf$1 = 'Infinitive';
9526 var Pres$1 = 'PresentTense';
9527 var Sing$1 = 'Singular';
9528 var Past$1 = 'PastTense';
9529 var Avb = 'Adverb';
9530 var Plrl = 'Plural';
9531 var Actor$1 = 'Actor';
9532 var Vb = 'Verb';
9533 var Noun$1 = 'Noun';
9534 var Last$1 = 'LastName';
9535 var Modal = 'Modal';
9536 var Place = 'Place'; // find any issues - https://observablehq.com/@spencermountain/suffix-word-lookup
9537
9538 var suffixMap = [null, //0
9539 null, //1
9540 {
9541 //2-letter
9542 ea: Sing$1,
9543 ia: Noun$1,
9544 ic: Adj$1,
9545 ly: Avb,
9546 "'n": Vb,
9547 "'t": Vb
9548 }, {
9549 //3-letter
9550 oed: Past$1,
9551 ued: Past$1,
9552 xed: Past$1,
9553 ' so': Avb,
9554 "'ll": Modal,
9555 "'re": 'Copula',
9556 azy: Adj$1,
9557 eer: Noun$1,
9558 end: Vb,
9559 ped: Past$1,
9560 ffy: Adj$1,
9561 ify: Inf$1,
9562 ing: 'Gerund',
9563 //likely to be converted to Adj after lexicon pass
9564 ize: Inf$1,
9565 lar: Adj$1,
9566 mum: Adj$1,
9567 nes: Pres$1,
9568 nny: Adj$1,
9569 oid: Adj$1,
9570 ous: Adj$1,
9571 que: Adj$1,
9572 rol: Sing$1,
9573 sis: Sing$1,
9574 zes: Pres$1
9575 }, {
9576 //4-letter
9577 amed: Past$1,
9578 aped: Past$1,
9579 ched: Past$1,
9580 lked: Past$1,
9581 nded: Past$1,
9582 cted: Past$1,
9583 dged: Past$1,
9584 akis: Last$1,
9585 //greek
9586 cede: Inf$1,
9587 chuk: Last$1,
9588 //east-europe
9589 czyk: Last$1,
9590 //polish (male)
9591 ects: Pres$1,
9592 ends: Vb,
9593 enko: Last$1,
9594 //east-europe
9595 ette: Sing$1,
9596 fies: Pres$1,
9597 fore: Avb,
9598 gate: Inf$1,
9599 gone: Adj$1,
9600 ices: Plrl,
9601 ints: Plrl,
9602 ines: Plrl,
9603 ions: Plrl,
9604 less: Avb,
9605 llen: Adj$1,
9606 made: Adj$1,
9607 nsen: Last$1,
9608 //norway
9609 oses: Pres$1,
9610 ould: Modal,
9611 some: Adj$1,
9612 sson: Last$1,
9613 //swedish male
9614 tage: Inf$1,
9615 teen: 'Value',
9616 tion: Sing$1,
9617 tive: Adj$1,
9618 tors: Noun$1,
9619 vice: Sing$1
9620 }, {
9621 //5-letter
9622 tized: Past$1,
9623 urned: Past$1,
9624 eased: Past$1,
9625 ances: Plrl,
9626 bound: Adj$1,
9627 ettes: Plrl,
9628 fully: Avb,
9629 ishes: Pres$1,
9630 ities: Plrl,
9631 marek: Last$1,
9632 //polish (male)
9633 nssen: Last$1,
9634 //norway
9635 ology: Noun$1,
9636 ports: Plrl,
9637 rough: Adj$1,
9638 tches: Pres$1,
9639 tieth: 'Ordinal',
9640 tures: Plrl,
9641 wards: Avb,
9642 where: Avb
9643 }, {
9644 //6-letter
9645 auskas: Last$1,
9646 //lithuania
9647 keeper: Actor$1,
9648 logist: Actor$1,
9649 teenth: 'Value'
9650 }, {
9651 //7-letter
9652 opoulos: Last$1,
9653 //greek
9654 borough: Place,
9655 //Hillsborough
9656 sdottir: Last$1 //swedish female
9657
9658 }];
9659
9660 var endRegexs = function endRegexs(term, world) {
9661 var str = term.clean;
9662 var _char = str[str.length - 1];
9663
9664 if (endsWith$1.hasOwnProperty(_char) === true) {
9665 var regs = endsWith$1[_char];
9666
9667 for (var r = 0; r < regs.length; r += 1) {
9668 if (regs[r][0].test(str) === true) {
9669 term.tagSafe(regs[r][1], "endReg ".concat(_char, " #").concat(r), world);
9670 break;
9671 }
9672 }
9673 }
9674 }; //sweep-through all suffixes
9675
9676
9677 var knownSuffixes = function knownSuffixes(term, world) {
9678 var len = term.clean.length;
9679 var max = 7;
9680
9681 if (len <= max) {
9682 max = len - 1;
9683 }
9684
9685 for (var i = max; i > 1; i -= 1) {
9686 var str = term.clean.substr(len - i, len);
9687
9688 if (suffixMap[str.length].hasOwnProperty(str) === true) {
9689 var tag = suffixMap[str.length][str];
9690 term.tagSafe(tag, 'suffix -' + str, world);
9691 break;
9692 }
9693 }
9694 }; //all-the-way-down!
9695
9696
9697 var checkRegex$1 = function checkRegex(term, world) {
9698 knownSuffixes(term, world);
9699 endRegexs(term, world);
9700 };
9701
9702 var _04Suffixes = checkRegex$1;
9703
9704 //just some of the most common emoticons
9705 //faster than
9706 //http://stackoverflow.com/questions/28077049/regex-matching-emoticons
9707 var emoticons = {
9708 ':(': true,
9709 ':)': true,
9710 ':P': true,
9711 ':p': true,
9712 ':O': true,
9713 ':3': true,
9714 ':|': true,
9715 ':/': true,
9716 ':\\': true,
9717 ':$': true,
9718 ':*': true,
9719 ':@': true,
9720 ':-(': true,
9721 ':-)': true,
9722 ':-P': true,
9723 ':-p': true,
9724 ':-O': true,
9725 ':-3': true,
9726 ':-|': true,
9727 ':-/': true,
9728 ':-\\': true,
9729 ':-$': true,
9730 ':-*': true,
9731 ':-@': true,
9732 ':^(': true,
9733 ':^)': true,
9734 ':^P': true,
9735 ':^p': true,
9736 ':^O': true,
9737 ':^3': 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 '$-:': true,
9751 '*-:': true,
9752 ')^:': true,
9753 '(^:': true,
9754 '$^:': true,
9755 '*^:': true,
9756 '<3': true,
9757 '</3': true,
9758 '<\\3': true
9759 };
9760
9761 var emojiReg = /^(\u00a9|\u00ae|[\u2319-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/; //for us, there's three types -
9762 // * ;) - emoticons
9763 // * 🌵 - unicode emoji
9764 // * :smiling_face: - asci-represented emoji
9765 //test for forms like ':woman_tone2:‍:ear_of_rice:'
9766 //https://github.com/Kikobeats/emojis-keywords/blob/master/index.js
9767
9768 var isCommaEmoji = function isCommaEmoji(raw) {
9769 if (raw.charAt(0) === ':') {
9770 //end comma can be last or second-last ':haircut_tone3:‍♀️'
9771 if (raw.match(/:.?$/) === null) {
9772 return false;
9773 } //ensure no spaces
9774
9775
9776 if (raw.match(' ')) {
9777 return false;
9778 } //reasonably sized
9779
9780
9781 if (raw.length > 35) {
9782 return false;
9783 }
9784
9785 return true;
9786 }
9787
9788 return false;
9789 }; //check against emoticon whitelist
9790
9791
9792 var isEmoticon = function isEmoticon(str) {
9793 str = str.replace(/^[:;]/, ':'); //normalize the 'eyes'
9794
9795 return emoticons.hasOwnProperty(str);
9796 };
9797
9798 var tagEmoji = function tagEmoji(term, world) {
9799 var raw = term.pre + term.text + term.post;
9800 raw = raw.trim(); //dont double-up on ending periods
9801
9802 raw = raw.replace(/[.!?,]$/, ''); //test for :keyword: emojis
9803
9804 if (isCommaEmoji(raw) === true) {
9805 term.tag('Emoji', 'comma-emoji', world);
9806 term.text = raw;
9807 term.pre = term.pre.replace(':', '');
9808 term.post = term.post.replace(':', '');
9809 } //test for unicode emojis
9810
9811
9812 if (term.text.match(emojiReg)) {
9813 term.tag('Emoji', 'unicode-emoji', world);
9814 term.text = raw;
9815 } //test for emoticon ':)' emojis
9816
9817
9818 if (isEmoticon(raw) === true) {
9819 term.tag('Emoticon', 'emoticon-emoji', world);
9820 term.text = raw;
9821 }
9822 };
9823
9824 var _05Emoji = tagEmoji;
9825
9826 var steps = {
9827 lexicon: _01Lexicon,
9828 punctuation: _02Punctuation$1,
9829 regex: _03Prefixes,
9830 suffix: _04Suffixes,
9831 emoji: _05Emoji
9832 }; //'lookups' look at a term by itself
9833
9834 var lookups = function lookups(doc, terms) {
9835 var world = doc.world; //our list of known-words
9836
9837 steps.lexicon(terms, world); //try these other methods
9838
9839 for (var i = 0; i < terms.length; i += 1) {
9840 var term = terms[i]; //or maybe some helpful punctuation
9841
9842 steps.punctuation(terms, i, world); //mostly prefix checks
9843
9844 steps.regex(term, world); //maybe we can guess
9845
9846 steps.suffix(term, world); //emoji and emoticons
9847
9848 steps.emoji(term, world);
9849 }
9850
9851 return doc;
9852 };
9853
9854 var _01Init = lookups;
9855
9856 //markov-like stats about co-occurance, for hints about unknown terms
9857 //basically, a little-bit better than the noun-fallback
9858 //just top n-grams from nlp tags, generated from nlp-corpus
9859 //after this word, here's what happens usually
9860 var afterThisWord = {
9861 i: 'Verb',
9862 //44% //i walk..
9863 first: 'Noun',
9864 //50% //first principles..
9865 it: 'Verb',
9866 //33%
9867 there: 'Verb',
9868 //35%
9869 not: 'Verb',
9870 //33%
9871 because: 'Noun',
9872 //31%
9873 "if": 'Noun',
9874 //32%
9875 but: 'Noun',
9876 //26%
9877 who: 'Verb',
9878 //40%
9879 "this": 'Noun',
9880 //37%
9881 his: 'Noun',
9882 //48%
9883 when: 'Noun',
9884 //33%
9885 you: 'Verb',
9886 //35%
9887 very: 'Adjective',
9888 // 39%
9889 old: 'Noun',
9890 //51%
9891 never: 'Verb',
9892 //42%
9893 before: 'Noun' //28%
9894
9895 }; //in advance of this word, this is what happens usually
9896
9897 var beforeThisWord = {
9898 there: 'Verb',
9899 //23% // be there
9900 me: 'Verb',
9901 //31% //see me
9902 man: 'Adjective',
9903 // 80% //quiet man
9904 only: 'Verb',
9905 //27% //sees only
9906 him: 'Verb',
9907 //32% //show him
9908 were: 'Noun',
9909 //48% //we were
9910 took: 'Noun',
9911 //38% //he took
9912 himself: 'Verb',
9913 //31% //see himself
9914 went: 'Noun',
9915 //43% //he went
9916 who: 'Noun',
9917 //47% //person who
9918 jr: 'Person'
9919 }; //following this POS, this is likely
9920
9921 var afterThisPOS = {
9922 Adjective: 'Noun',
9923 //36% //blue dress
9924 Possessive: 'Noun',
9925 //41% //his song
9926 Determiner: 'Noun',
9927 //47%
9928 Adverb: 'Verb',
9929 //20%
9930 Pronoun: 'Verb',
9931 //40%
9932 Value: 'Noun',
9933 //47%
9934 Ordinal: 'Noun',
9935 //53%
9936 Modal: 'Verb',
9937 //35%
9938 Superlative: 'Noun',
9939 //43%
9940 Demonym: 'Noun',
9941 //38%
9942 Honorific: 'Person' //
9943
9944 }; //in advance of this POS, this is likely
9945
9946 var beforeThisPOS = {
9947 Copula: 'Noun',
9948 //44% //spencer is
9949 PastTense: 'Noun',
9950 //33% //spencer walked
9951 Conjunction: 'Noun',
9952 //36%
9953 Modal: 'Noun',
9954 //38%
9955 Pluperfect: 'Noun',
9956 //40%
9957 PerfectTense: 'Verb' //32%
9958
9959 };
9960 var markov = {
9961 beforeThisWord: beforeThisWord,
9962 afterThisWord: afterThisWord,
9963 beforeThisPos: beforeThisPOS,
9964 afterThisPos: afterThisPOS
9965 };
9966
9967 var afterKeys = Object.keys(markov.afterThisPos);
9968 var beforeKeys = Object.keys(markov.beforeThisPos);
9969
9970 var checkNeighbours = function checkNeighbours(terms, world) {
9971 var _loop = function _loop(i) {
9972 var term = terms[i]; //do we still need a tag?
9973
9974 if (term.isKnown() === true) {
9975 return "continue";
9976 } //ok, this term needs a tag.
9977 //look at previous word for clues..
9978
9979
9980 var lastTerm = terms[i - 1];
9981
9982 if (lastTerm) {
9983 // 'foobar term'
9984 if (markov.afterThisWord.hasOwnProperty(lastTerm.clean) === true) {
9985 var tag = markov.afterThisWord[lastTerm.clean];
9986 term.tag(tag, 'after-' + lastTerm.clean, world);
9987 return "continue";
9988 } // 'Tag term'
9989 // (look at previous POS tags for clues..)
9990
9991
9992 var foundTag = afterKeys.find(function (tag) {
9993 return lastTerm.tags[tag];
9994 });
9995
9996 if (foundTag !== undefined) {
9997 var _tag = markov.afterThisPos[foundTag];
9998 term.tag(_tag, 'after-' + foundTag, world);
9999 return "continue";
10000 }
10001 } //look at next word for clues..
10002
10003
10004 var nextTerm = terms[i + 1];
10005
10006 if (nextTerm) {
10007 // 'term foobar'
10008 if (markov.beforeThisWord.hasOwnProperty(nextTerm.clean) === true) {
10009 var _tag2 = markov.beforeThisWord[nextTerm.clean];
10010 term.tag(_tag2, 'before-' + nextTerm.clean, world);
10011 return "continue";
10012 } // 'term Tag'
10013 // (look at next POS tags for clues..)
10014
10015
10016 var _foundTag = beforeKeys.find(function (tag) {
10017 return nextTerm.tags[tag];
10018 });
10019
10020 if (_foundTag !== undefined) {
10021 var _tag3 = markov.beforeThisPos[_foundTag];
10022 term.tag(_tag3, 'before-' + _foundTag, world);
10023 return "continue";
10024 }
10025 }
10026 };
10027
10028 for (var i = 0; i < terms.length; i += 1) {
10029 var _ret = _loop(i);
10030
10031 if (_ret === "continue") continue;
10032 }
10033 };
10034
10035 var _01Neighbours = checkNeighbours;
10036
10037 var titleCase$4 = /^[A-Z][a-z'\u00C0-\u00FF]/;
10038 var hasNumber = /[0-9]/;
10039 /** look for any grammar signals based on capital/lowercase */
10040
10041 var checkCase = function checkCase(doc) {
10042 var world = doc.world;
10043 doc.list.forEach(function (p) {
10044 var terms = p.terms();
10045
10046 for (var i = 1; i < terms.length; i++) {
10047 var term = terms[i];
10048
10049 if (titleCase$4.test(term.text) === true && hasNumber.test(term.text) === false && term.tags.Date === undefined) {
10050 term.tag('ProperNoun', 'titlecase-noun', world);
10051 }
10052 }
10053 });
10054 };
10055
10056 var _02Case = checkCase;
10057
10058 var hasPrefix = /^(re|un)-?[a-z\u00C0-\u00FF]/;
10059 var prefix = /^(re|un)-?/;
10060 /** check 'rewatch' in lexicon as 'watch' */
10061
10062 var checkPrefix = function checkPrefix(terms, world) {
10063 var lex = world.words;
10064 terms.forEach(function (term) {
10065 // skip if we have a good tag already
10066 if (term.isKnown() === true) {
10067 return;
10068 } //does it start with 'un|re'
10069
10070
10071 if (hasPrefix.test(term.clean) === true) {
10072 // look for the root word in the lexicon:
10073 var stem = term.clean.replace(prefix, '');
10074
10075 if (stem && stem.length > 3 && lex[stem] !== undefined && lex.hasOwnProperty(stem) === true) {
10076 term.tag(lex[stem], 'stem-' + stem, world);
10077 }
10078 }
10079 });
10080 };
10081
10082 var _03Stem = checkPrefix;
10083
10084 //similar to plural/singularize rules, but not the same
10085 var 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
10086
10087 var 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
10088 /(^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];
10089 var isPlural_1 = {
10090 isSingular: isSingular,
10091 isPlural: isPlural
10092 };
10093
10094 var noPlurals = ['Uncountable', 'Pronoun', 'Place', 'Value', 'Person', 'Month', 'WeekDay', 'Holiday'];
10095 var notPlural = [/ss$/, /sis$/, /[^aeiou][uo]s$/, /'s$/];
10096 var notSingular = [/i$/, /ae$/];
10097 /** turn nouns into singular/plural */
10098
10099 var checkPlural = function checkPlural(t, world) {
10100 if (t.tags.Noun && !t.tags.Acronym) {
10101 var str = t.clean; //skip existing tags, fast
10102
10103 if (t.tags.Singular || t.tags.Plural) {
10104 return;
10105 } //too short
10106
10107
10108 if (str.length <= 3) {
10109 t.tag('Singular', 'short-singular', world);
10110 return;
10111 } //is it impossible to be plural?
10112
10113
10114 if (noPlurals.find(function (tag) {
10115 return t.tags[tag];
10116 })) {
10117 return;
10118 } // isPlural suffix rules
10119
10120
10121 if (isPlural_1.isPlural.find(function (reg) {
10122 return reg.test(str);
10123 })) {
10124 t.tag('Plural', 'plural-rules', world);
10125 return;
10126 } // isSingular suffix rules
10127
10128
10129 if (isPlural_1.isSingular.find(function (reg) {
10130 return reg.test(str);
10131 })) {
10132 t.tag('Singular', 'singular-rules', world);
10133 return;
10134 } // finally, fallback 'looks plural' rules..
10135
10136
10137 if (/s$/.test(str) === true) {
10138 //avoid anything too sketchy to be plural
10139 if (notPlural.find(function (reg) {
10140 return reg.test(str);
10141 })) {
10142 return;
10143 }
10144
10145 t.tag('Plural', 'plural-fallback', world);
10146 return;
10147 } //avoid anything too sketchy to be singular
10148
10149
10150 if (notSingular.find(function (reg) {
10151 return reg.test(str);
10152 })) {
10153 return;
10154 }
10155
10156 t.tag('Singular', 'singular-fallback', world);
10157 }
10158 };
10159
10160 var _04Plurals = checkPlural;
10161
10162 //nouns that also signal the title of an unknown organization
10163 //todo remove/normalize plural forms
10164 var 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',
10165 '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',
10166 'news', 'news service', 'observatory', 'office', 'oil', 'optical', 'orchestra', 'organization', 'partners', 'partnership', // 'party',
10167 "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'];
10168 var organizations = orgWords.reduce(function (h, str) {
10169 h[str] = 'Noun';
10170 return h;
10171 }, {});
10172
10173 var maybeOrg = function maybeOrg(t) {
10174 //must be a noun
10175 if (!t.tags.Noun) {
10176 return false;
10177 } //can't be these things
10178
10179
10180 if (t.tags.Pronoun || t.tags.Comma || t.tags.Possessive) {
10181 return false;
10182 } //must be one of these
10183
10184
10185 if (t.tags.Organization || t.tags.Acronym || t.tags.Place || t.titleCase()) {
10186 return true;
10187 }
10188
10189 return false;
10190 };
10191
10192 var tagOrgs = function tagOrgs(terms, world) {
10193 for (var i = 0; i < terms.length; i += 1) {
10194 var t = terms[i];
10195
10196 if (organizations[t.clean] !== undefined && organizations.hasOwnProperty(t.clean) === true) {
10197 // look-backward - eg. 'Toronto University'
10198 var lastTerm = terms[i - 1];
10199
10200 if (lastTerm !== undefined && maybeOrg(lastTerm) === true) {
10201 lastTerm.tagSafe('Organization', 'org-word-1', world);
10202 t.tagSafe('Organization', 'org-word-2', world);
10203 continue;
10204 } //look-forward - eg. University of Toronto
10205
10206
10207 var nextTerm = terms[i + 1];
10208
10209 if (nextTerm !== undefined && nextTerm.clean === 'of') {
10210 if (terms[i + 2] && maybeOrg(terms[i + 2])) {
10211 t.tagSafe('Organization', 'org-of-word-1', world);
10212 nextTerm.tagSafe('Organization', 'org-of-word-2', world);
10213 terms[i + 2].tagSafe('Organization', 'org-of-word-3', world);
10214 continue;
10215 }
10216 }
10217 }
10218 }
10219 };
10220
10221 var _05Organizations = tagOrgs;
10222
10223 var oneLetterAcronym$1 = /^[A-Z]('s|,)?$/;
10224 var periodSeperated = /([A-Z]\.){2}[A-Z]?/i;
10225 var oneLetterWord = {
10226 I: true,
10227 A: true
10228 };
10229
10230 var isAcronym$2 = function isAcronym(term, world) {
10231 var str = term.reduced; // a known acronym like fbi
10232
10233 if (term.tags.Acronym) {
10234 return true;
10235 } // if (term.tags.Adverb || term.tags.Verb || term.tags.Value || term.tags.Plural) {
10236 // return false
10237 // }
10238 // known-words, like 'PIZZA' is not an acronym.
10239
10240
10241 if (world.words[str]) {
10242 return false;
10243 } // long capitalized words are not usually either
10244
10245
10246 if (str.length > 5) {
10247 return false;
10248 }
10249
10250 return term.isAcronym();
10251 }; // F.B.I., NBC, - but not 'NO COLLUSION'
10252
10253
10254 var checkAcronym = function checkAcronym(terms, world) {
10255 terms.forEach(function (term) {
10256 //these are not acronyms
10257 if (term.tags.RomanNumeral === true) {
10258 return;
10259 } //period-ones F.D.B.
10260
10261
10262 if (periodSeperated.test(term.text) === true) {
10263 term.tag('Acronym', 'period-acronym', world);
10264 } //non-period ones are harder
10265
10266
10267 if (term.isUpperCase() && isAcronym$2(term, world)) {
10268 term.tag('Acronym', 'acronym-step', world);
10269 term.tag('Noun', 'acronym-infer', world);
10270 } else if (!oneLetterWord.hasOwnProperty(term.text) && oneLetterAcronym$1.test(term.text)) {
10271 term.tag('Acronym', 'one-letter-acronym', world);
10272 term.tag('Noun', 'one-letter-infer', world);
10273 } //if it's a organization,
10274
10275
10276 if (term.tags.Organization && term.text.length <= 3) {
10277 term.tag('Acronym', 'acronym-org', world);
10278 }
10279
10280 if (term.tags.Organization && term.isUpperCase() && term.text.length <= 6) {
10281 term.tag('Acronym', 'acronym-org-case', world);
10282 }
10283 });
10284 };
10285
10286 var _06Acronyms = checkAcronym;
10287
10288 var step = {
10289 neighbours: _01Neighbours,
10290 "case": _02Case,
10291 stem: _03Stem,
10292 plural: _04Plurals,
10293 organizations: _05Organizations,
10294 acronyms: _06Acronyms
10295 }; //
10296
10297 var fallbacks = function fallbacks(doc, terms) {
10298 var world = doc.world; // if it's empty, consult it's neighbours, first
10299
10300 step.neighbours(terms, world); // is there a case-sensitive clue?
10301
10302 step["case"](doc); // check 'rewatch' as 'watch'
10303
10304 step.stem(terms, world); // ... fallback to a noun!
10305
10306 terms.forEach(function (t) {
10307 if (t.isKnown() === false) {
10308 t.tag('Noun', 'noun-fallback', doc.world);
10309 }
10310 }); // turn 'Foo University' into an Org
10311
10312 step.organizations(terms, world); //turn 'FBD' into an acronym
10313
10314 step.acronyms(terms, world); //are the nouns singular or plural?
10315
10316 terms.forEach(function (t) {
10317 step.plural(t, doc.world);
10318 });
10319 return doc;
10320 };
10321
10322 var _02Fallbacks = fallbacks;
10323
10324 var hasNegative = /n't$/;
10325 var irregulars$3 = {
10326 "won't": ['will', 'not'],
10327 wont: ['will', 'not'],
10328 "can't": ['can', 'not'],
10329 cant: ['can', 'not'],
10330 cannot: ['can', 'not'],
10331 "shan't": ['should', 'not'],
10332 dont: ['do', 'not'],
10333 dun: ['do', 'not'] // "ain't" is ambiguous for is/was
10334
10335 }; // either 'is not' or 'are not'
10336
10337 var doAint = function doAint(term, phrase) {
10338 var terms = phrase.terms();
10339 var index = terms.indexOf(term);
10340 var before = terms.slice(0, index); //look for the preceding noun
10341
10342 var noun = before.find(function (t) {
10343 return t.tags.Noun;
10344 });
10345
10346 if (noun && noun.tags.Plural) {
10347 return ['are', 'not'];
10348 }
10349
10350 return ['is', 'not'];
10351 };
10352
10353 var checkNegative = function checkNegative(term, phrase) {
10354 //check named-ones
10355 if (irregulars$3.hasOwnProperty(term.clean) === true) {
10356 return irregulars$3[term.clean];
10357 } //this word needs it's own logic:
10358
10359
10360 if (term.clean === "ain't" || term.clean === 'aint') {
10361 return doAint(term, phrase);
10362 } //try it normally
10363
10364
10365 if (hasNegative.test(term.clean) === true) {
10366 var main = term.clean.replace(hasNegative, '');
10367 return [main, 'not'];
10368 }
10369
10370 return null;
10371 };
10372
10373 var _01Negative = checkNegative;
10374
10375 var 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
10376
10377 var easy = {
10378 ll: 'will',
10379 ve: 'have',
10380 re: 'are',
10381 m: 'am',
10382 "n't": 'not'
10383 }; //
10384
10385 var checkApostrophe = function checkApostrophe(term) {
10386 var parts = term.text.match(contraction);
10387
10388 if (parts === null) {
10389 return null;
10390 }
10391
10392 if (easy.hasOwnProperty(parts[2])) {
10393 return [parts[1], easy[parts[2]]];
10394 }
10395
10396 return null;
10397 };
10398
10399 var _02Simple = checkApostrophe;
10400
10401 var irregulars$4 = {
10402 wanna: ['want', 'to'],
10403 gonna: ['going', 'to'],
10404 im: ['i', 'am'],
10405 alot: ['a', 'lot'],
10406 ive: ['i', 'have'],
10407 imma: ['I', 'will'],
10408 "where'd": ['where', 'did'],
10409 whered: ['where', 'did'],
10410 "when'd": ['when', 'did'],
10411 whend: ['when', 'did'],
10412 // "how'd": ['how', 'did'], //'how would?'
10413 // "what'd": ['what', 'did'], //'what would?'
10414 howd: ['how', 'did'],
10415 whatd: ['what', 'did'],
10416 // "let's": ['let', 'us'], //too weird
10417 //multiple word contractions
10418 dunno: ['do', 'not', 'know'],
10419 brb: ['be', 'right', 'back'],
10420 gtg: ['got', 'to', 'go'],
10421 irl: ['in', 'real', 'life'],
10422 tbh: ['to', 'be', 'honest'],
10423 imo: ['in', 'my', 'opinion'],
10424 til: ['today', 'i', 'learned'],
10425 rn: ['right', 'now'],
10426 twas: ['it', 'was'],
10427 '@': ['at']
10428 }; //
10429
10430 var checkIrregulars = function checkIrregulars(term) {
10431 //check white-list
10432 if (irregulars$4.hasOwnProperty(term.clean)) {
10433 return irregulars$4[term.clean];
10434 }
10435
10436 return null;
10437 };
10438
10439 var _03Irregulars = checkIrregulars;
10440
10441 var hasApostropheS = /([a-z\u00C0-\u00FF]+)[\u0027\u0060\u00B4\u2018\u2019\u201A\u201B\u2032\u2035\u2039\u203A]s$/i;
10442 var banList = {
10443 that: true,
10444 there: true
10445 };
10446 var hereThere = {
10447 here: true,
10448 there: true,
10449 everywhere: true
10450 };
10451
10452 var isPossessive = function isPossessive(term, pool) {
10453 // if we already know it
10454 if (term.tags.Possessive) {
10455 return true;
10456 } //a pronoun can't be possessive - "he's house"
10457
10458
10459 if (term.tags.Pronoun || term.tags.QuestionWord) {
10460 return false;
10461 }
10462
10463 if (banList.hasOwnProperty(term.reduced)) {
10464 return false;
10465 } //if end of sentence, it is possessive - "was spencer's"
10466
10467
10468 var nextTerm = pool.get(term.next);
10469
10470 if (!nextTerm) {
10471 return true;
10472 } //a gerund suggests 'is walking'
10473
10474
10475 if (nextTerm.tags.Verb) {
10476 //fix 'jamie's bite'
10477 if (nextTerm.tags.Infinitive) {
10478 return true;
10479 } //fix 'spencer's runs'
10480
10481
10482 if (nextTerm.tags.PresentTense) {
10483 return true;
10484 }
10485
10486 return false;
10487 } //spencer's house
10488
10489
10490 if (nextTerm.tags.Noun) {
10491 // 'spencer's here'
10492 if (hereThere.hasOwnProperty(nextTerm.reduced) === true) {
10493 return false;
10494 }
10495
10496 return true;
10497 } //rocket's red glare
10498
10499
10500 var twoTerm = pool.get(nextTerm.next);
10501
10502 if (twoTerm && twoTerm.tags.Noun && !twoTerm.tags.Pronoun) {
10503 return true;
10504 } //othwerwise, an adjective suggests 'is good'
10505
10506
10507 if (nextTerm.tags.Adjective || nextTerm.tags.Adverb || nextTerm.tags.Verb) {
10508 return false;
10509 }
10510
10511 return false;
10512 };
10513
10514 var isHas = function isHas(term, phrase) {
10515 var terms = phrase.terms();
10516 var index = terms.indexOf(term);
10517 var after = terms.slice(index + 1, index + 3); //look for a past-tense verb
10518
10519 return after.find(function (t) {
10520 return t.tags.PastTense;
10521 });
10522 };
10523
10524 var checkPossessive = function checkPossessive(term, phrase, world) {
10525 //the rest of 's
10526 var found = term.text.match(hasApostropheS);
10527
10528 if (found !== null) {
10529 //spencer's thing vs spencer-is
10530 if (isPossessive(term, phrase.pool) === true) {
10531 term.tag('#Possessive', 'isPossessive', world);
10532 return null;
10533 } //'spencer is'
10534
10535
10536 if (found !== null) {
10537 if (isHas(term, phrase)) {
10538 return [found[1], 'has'];
10539 }
10540
10541 return [found[1], 'is'];
10542 }
10543 }
10544
10545 return null;
10546 };
10547
10548 var _04Possessive = checkPossessive;
10549
10550 var hasPerfect = /[a-z\u00C0-\u00FF]'d$/;
10551 var useDid = {
10552 how: true,
10553 what: true
10554 };
10555 /** split `i'd` into 'i had', or 'i would' */
10556
10557 var checkPerfect = function checkPerfect(term, phrase) {
10558 if (hasPerfect.test(term.clean)) {
10559 var root = term.clean.replace(/'d$/, ''); //look at the next few words
10560
10561 var terms = phrase.terms();
10562 var index = terms.indexOf(term);
10563 var after = terms.slice(index + 1, index + 4); //is it before a past-tense verb? - 'i'd walked'
10564
10565 for (var i = 0; i < after.length; i++) {
10566 var t = after[i];
10567
10568 if (t.tags.Verb) {
10569 if (t.tags.PastTense) {
10570 return [root, 'had'];
10571 } //what'd you see
10572
10573
10574 if (useDid[root] === true) {
10575 return [root, 'did'];
10576 }
10577
10578 return [root, 'would'];
10579 }
10580 } //otherwise, 'i'd walk'
10581
10582
10583 return [root, 'would'];
10584 }
10585
10586 return null;
10587 };
10588
10589 var _05PerfectTense = checkPerfect;
10590
10591 var 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'
10592
10593 var checkRange = function checkRange(term) {
10594 if (term.tags.PhoneNumber === true) {
10595 return null;
10596 }
10597
10598 var parts = term.text.match(isRange);
10599
10600 if (parts !== null) {
10601 return [parts[1], 'to', parts[2]];
10602 }
10603
10604 return null;
10605 };
10606
10607 var _06Ranges = checkRange;
10608
10609 var 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
10610 // not perfect, but better than nothing, to support matching on french text.
10611
10612 var french = {
10613 l: 'le',
10614 // l'amour
10615 c: 'ce',
10616 // c'est
10617 d: 'de',
10618 // d'amerique
10619 j: 'je',
10620 // j'aime
10621 m: 'me',
10622 // m'appelle
10623 n: 'ne',
10624 // n'est
10625 qu: 'que',
10626 // qu'il
10627 s: 'se',
10628 // s'appelle
10629 t: 'tu' // t'aime
10630
10631 };
10632
10633 var checkFrench = function checkFrench(term) {
10634 var parts = term.text.match(contraction$1);
10635
10636 if (parts === null || french.hasOwnProperty(parts[1]) === false) {
10637 return null;
10638 }
10639
10640 var arr = [french[parts[1]], parts[2]];
10641
10642 if (arr[0] && arr[1]) {
10643 return arr;
10644 }
10645
10646 return null;
10647 };
10648
10649 var _07French = checkFrench;
10650
10651 var isNumber = /^[0-9]+$/;
10652 var isOrdinal = /^[0-9]+(st|nd|rd|th)$/;
10653
10654 var createPhrase = function createPhrase(found, doc) {
10655 //create phrase from ['would', 'not']
10656 var phrase = _01Tokenizer(found.join(' '), doc.world, doc.pool())[0]; //tag it
10657
10658 var terms = phrase.terms();
10659 _01Lexicon(terms, doc.world); //make these terms implicit
10660
10661 terms.forEach(function (t) {
10662 t.implicit = t.text;
10663 t.text = '';
10664 t.clean = ''; // remove whitespace for implicit terms
10665
10666 t.pre = '';
10667 t.post = ''; // tag number-ranges
10668
10669 if (isNumber.test(t.implicit)) {
10670 t.tag('Cardinal', 'num-range', doc.world);
10671 } else if (isOrdinal.test(t.implicit)) {
10672 t.tag('Ordinal', 'ord-range', doc.world);
10673 } else if (Object.keys(t.tags).length === 0) {
10674 t.tags.Noun = true; // if no tag, give it a noun
10675 }
10676 });
10677 return phrase;
10678 };
10679
10680 var contractions = function contractions(doc) {
10681 var world = doc.world;
10682 doc.list.forEach(function (p) {
10683 var terms = p.terms();
10684
10685 for (var i = 0; i < terms.length; i += 1) {
10686 var term = terms[i];
10687 var found = _01Negative(term, p);
10688 found = found || _02Simple(term);
10689 found = found || _03Irregulars(term);
10690 found = found || _04Possessive(term, p, world);
10691 found = found || _05PerfectTense(term, p);
10692 found = found || _06Ranges(term);
10693 found = found || _07French(term); //add them in
10694
10695 if (found !== null) {
10696 var newPhrase = createPhrase(found, doc); // keep tag NumberRange, if we had it
10697
10698 if (p.has('#NumberRange') === true) {
10699 doc.buildFrom([newPhrase]).tag('NumberRange');
10700 } //set text as contraction
10701
10702
10703 var firstTerm = newPhrase.terms(0);
10704 firstTerm.text = term.text; //grab sub-phrase to remove
10705
10706 var match = p.buildFrom(term.id, 1, doc.pool());
10707 match.replace(newPhrase, doc, true);
10708 }
10709 }
10710 });
10711 return doc;
10712 };
10713
10714 var _03Contractions = contractions;
10715
10716 var hasWord = function hasWord(doc, word) {
10717 var arr = doc._cache.words[word] || [];
10718 arr = arr.map(function (i) {
10719 return doc.list[i];
10720 });
10721 return doc.buildFrom(arr);
10722 };
10723
10724 var hasTag = function hasTag(doc, tag) {
10725 var arr = doc._cache.tags[tag] || [];
10726 arr = arr.map(function (i) {
10727 return doc.list[i];
10728 });
10729 return doc.buildFrom(arr);
10730 }; //mostly pos-corections here
10731
10732
10733 var miscCorrection = function miscCorrection(doc) {
10734 //exactly like
10735 var m = hasWord(doc, 'like');
10736 m.match('#Adverb like').notIf('(really|generally|typically|usually|sometimes|often|just) [like]').tag('Adverb', 'adverb-like'); //the orange.
10737
10738 m = hasTag(doc, 'Adjective');
10739 m.match('#Determiner #Adjective$').notIf('(#Comparative|#Superlative)').terms(1).tag('Noun', 'the-adj-1'); // Firstname x (dangerous)
10740
10741 m = hasTag(doc, 'FirstName');
10742 m.match('#FirstName (#Noun|@titleCase)').ifNo('^#Possessive').ifNo('(#Pronoun|#Plural)').ifNo('@hasComma .').lastTerm().tag('#LastName', 'firstname-noun'); //three trains / one train
10743
10744 m = hasTag(doc, 'Value');
10745 m = m.match('#Value #PresentTense').ifNo('#Copula');
10746
10747 if (m.found) {
10748 if (m.has('(one|1)') === true) {
10749 m.terms(1).tag('Singular', 'one-presentTense');
10750 } else {
10751 m.terms(1).tag('Plural', 'value-presentTense');
10752 }
10753 } // well i've been...
10754
10755
10756 doc.match('^(well|so|okay)').tag('Expression', 'well-'); //been walking
10757
10758 m = hasTag(doc, 'Gerund');
10759 m.match("(be|been) (#Adverb|not)+? #Gerund").not('#Verb$').tag('Auxiliary', 'be-walking'); // directive verb - 'use reverse'
10760
10761 doc.match('(try|use|attempt|build|make) #Verb').ifNo('(@hasComma|#Negative|#PhrasalVerb|#Copula|will|be)').lastTerm().tag('#Noun', 'do-verb'); //possessives
10762 //'her match' vs 'let her match'
10763
10764 m = hasTag(doc, 'Possessive');
10765 m = m.match('#Possessive [#Infinitive]', 0);
10766
10767 if (!m.lookBehind('(let|made|make|force|ask)').found) {
10768 m.tag('Noun', 'her-match');
10769 }
10770
10771 return doc;
10772 };
10773
10774 var fixMisc = miscCorrection;
10775
10776 var unique$5 = function unique(arr) {
10777 var obj = {};
10778
10779 for (var i = 0; i < arr.length; i++) {
10780 obj[arr[i]] = true;
10781 }
10782
10783 return Object.keys(obj);
10784 };
10785
10786 var _unique = unique$5;
10787
10788 // order matters
10789 var list = [// ==== Mutliple tags ====
10790 {
10791 match: 'too much',
10792 tag: 'Adverb Adjective',
10793 reason: 'bit-4'
10794 }, // u r cool
10795 {
10796 match: 'u r',
10797 tag: 'Pronoun Copula',
10798 reason: 'u r'
10799 }, //sometimes adverbs - 'pretty good','well above'
10800 {
10801 match: '#Copula (pretty|dead|full|well|sure) (#Adjective|#Noun)',
10802 tag: '#Copula #Adverb #Adjective',
10803 reason: 'sometimes-adverb'
10804 }, //i better ..
10805 {
10806 match: '(#Pronoun|#Person) (had|#Adverb)? [better] #PresentTense',
10807 group: 0,
10808 tag: 'Modal',
10809 reason: 'i-better'
10810 }, //walking is cool
10811 {
10812 match: '[#Gerund] #Adverb? not? #Copula',
10813 group: 0,
10814 tag: 'Activity',
10815 reason: 'gerund-copula'
10816 }, //walking should be fun
10817 {
10818 match: '[#Gerund] #Modal',
10819 group: 0,
10820 tag: 'Activity',
10821 reason: 'gerund-modal'
10822 }, //swear-words as non-expression POS
10823 {
10824 match: 'holy (shit|fuck|hell)',
10825 tag: 'Expression',
10826 reason: 'swears-expression'
10827 }, //Aircraft designer
10828 {
10829 match: '#Noun #Actor',
10830 tag: 'Actor',
10831 reason: 'thing-doer'
10832 }, {
10833 match: '#Conjunction [u]',
10834 group: 0,
10835 tag: 'Pronoun',
10836 reason: 'u-pronoun-2'
10837 }, //'u' as pronoun
10838 {
10839 match: '[u] #Verb',
10840 group: 0,
10841 tag: 'Pronoun',
10842 reason: 'u-pronoun-1'
10843 }, // ==== Determiners ====
10844 {
10845 match: '#Noun [(who|whom)]',
10846 group: 0,
10847 tag: 'Determiner',
10848 reason: 'captain-who'
10849 }, //that car goes
10850 // { match: 'that #Noun [#PresentTense]', group: 0, tag: 'Determiner', reason: 'that-determiner' },
10851 {
10852 match: 'a bit much',
10853 tag: 'Determiner Adverb Adjective',
10854 reason: 'bit-3'
10855 }, // ==== Propositions ====
10856 //all students
10857 {
10858 match: '#Verb #Adverb? #Noun [(that|which)]',
10859 group: 0,
10860 tag: 'Preposition',
10861 reason: 'that-prep'
10862 }, //work, which has been done.
10863 {
10864 match: '@hasComma [which] (#Pronoun|#Verb)',
10865 group: 0,
10866 tag: 'Preposition',
10867 reason: 'which-copula'
10868 }, {
10869 match: '#Copula just [like]',
10870 group: 0,
10871 tag: 'Preposition',
10872 reason: 'like-preposition'
10873 }, //folks like her
10874 {
10875 match: '#Noun [like] #Noun',
10876 group: 0,
10877 tag: 'Preposition',
10878 reason: 'noun-like'
10879 }, //fix for busted-up phrasalVerbs
10880 // { match: '#Noun [#Particle]', group: 0, tag: 'Preposition', reason: 'repair-noPhrasal' },
10881 // ==== Conditions ====
10882 // had he survived,
10883 {
10884 match: '[had] #Noun+ #PastTense',
10885 group: 0,
10886 tag: 'Condition',
10887 reason: 'had-he'
10888 }, // were he to survive
10889 {
10890 match: '[were] #Noun+ to #Infinitive',
10891 group: 0,
10892 tag: 'Condition',
10893 reason: 'were-he'
10894 }, // ==== Questions ====
10895 //the word 'how'
10896 {
10897 match: '^how',
10898 tag: 'QuestionWord',
10899 reason: 'how-question'
10900 }, {
10901 match: '[how] (#Determiner|#Copula|#Modal|#PastTense)',
10902 group: 0,
10903 tag: 'QuestionWord',
10904 reason: 'how-is'
10905 }, // //the word 'which'
10906 {
10907 match: '^which',
10908 tag: 'QuestionWord',
10909 reason: 'which-question'
10910 }, // { match: '[which] . (#Noun)+ #Pronoun', group: 0, tag: 'QuestionWord', reason: 'which-question2' },
10911 // { match: 'which', tag: 'QuestionWord', reason: 'which-question3' },
10912 // ==== Conjunctions ====
10913 {
10914 match: '[so] #Noun',
10915 group: 0,
10916 tag: 'Conjunction',
10917 reason: 'so-conj'
10918 }, //how he is driving
10919 {
10920 match: '[(who|what|where|why|how|when)] #Noun #Copula #Adverb? (#Verb|#Adjective)',
10921 group: 0,
10922 tag: 'Conjunction',
10923 reason: 'how-he-is-x'
10924 } // {
10925 // match: '[(who|what|where|why|how|when)] #Noun #Adverb? #Infinitive not? #Gerund',
10926 // group: 0,
10927 // tag: 'Conjunction',
10928 // reason: 'when-i-go-fishing',
10929 // },
10930 ];
10931 var _01Misc = list;
10932
10933 var _ambig = {
10934 // adverbs than can be adjectives
10935 adverbAdjective: ['dark', 'bright', 'flat', 'light', 'soft', 'pale', 'dead', 'dim', 'faux', 'little', 'wee', 'sheer', 'most', 'near', 'good', 'extra', 'all'],
10936 // names that are dates
10937 personDate: ['april', 'june', 'may', 'jan', 'august', 'eve'],
10938 // names that may be months
10939 personMonth: ['january', 'april', 'may', 'june', 'jan', 'sep'],
10940 // names that are adjectives
10941 personAdjective: ['misty', 'rusty', 'dusty', 'rich', 'randy', 'young'],
10942 // names that are verbs
10943 personVerb: ['pat', 'wade', 'ollie', 'will', 'rob', 'buck', 'bob', 'mark', 'jack'],
10944 // names that are verbs
10945 personPlace: ['darwin', 'hamilton', 'paris', 'alexandria', 'houston', 'kobe', 'santiago', 'salvador', 'sydney', 'victoria'],
10946 // names that are nouns
10947 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']
10948 };
10949
10950 var dates = "(".concat(_ambig.personDate.join('|'), ")");
10951 var list$1 = [// ==== Holiday ====
10952 {
10953 match: '#Holiday (day|eve)',
10954 tag: 'Holiday',
10955 reason: 'holiday-day'
10956 }, // the captain who
10957 // ==== WeekDay ====
10958 // sun the 5th
10959 {
10960 match: '[sun] the #Ordinal',
10961 tag: 'WeekDay',
10962 reason: 'sun-the-5th'
10963 }, //sun feb 2
10964 {
10965 match: '[sun] #Date',
10966 group: 0,
10967 tag: 'WeekDay',
10968 reason: 'sun-feb'
10969 }, //1pm next sun
10970 {
10971 match: '#Date (on|this|next|last|during)? [sun]',
10972 group: 0,
10973 tag: 'WeekDay',
10974 reason: '1pm-sun'
10975 }, //this sat
10976 {
10977 match: "(in|by|before|during|on|until|after|of|within|all) [sat]",
10978 group: 0,
10979 tag: 'WeekDay',
10980 reason: 'sat'
10981 }, {
10982 match: "(in|by|before|during|on|until|after|of|within|all) [wed]",
10983 group: 0,
10984 tag: 'WeekDay',
10985 reason: 'wed'
10986 }, {
10987 match: "(in|by|before|during|on|until|after|of|within|all) [march]",
10988 group: 0,
10989 tag: 'Month',
10990 reason: 'march'
10991 }, //sat november
10992 {
10993 match: '[sat] #Date',
10994 group: 0,
10995 tag: 'WeekDay',
10996 reason: 'sat-feb'
10997 }, // ==== Month ====
10998 //all march
10999 {
11000 match: "#Preposition [(march|may)]",
11001 group: 0,
11002 tag: 'Month',
11003 reason: 'in-month'
11004 }, //this march
11005 {
11006 match: "this [(march|may)]",
11007 group: 0,
11008 tag: 'Month',
11009 reason: 'this-month'
11010 }, {
11011 match: "next [(march|may)]",
11012 group: 0,
11013 tag: 'Month',
11014 reason: 'this-month'
11015 }, {
11016 match: "last [(march|may)]",
11017 group: 0,
11018 tag: 'Month',
11019 reason: 'this-month'
11020 }, // march 5th
11021 {
11022 match: "[(march|may)] the? #Value",
11023 group: 0,
11024 tag: 'Month',
11025 reason: 'march-5th'
11026 }, // 5th of march
11027 {
11028 match: "#Value of? [(march|may)]",
11029 group: 0,
11030 tag: 'Month',
11031 reason: '5th-of-march'
11032 }, // march and feb
11033 {
11034 match: "[(march|may)] .? #Date",
11035 group: 0,
11036 tag: 'Month',
11037 reason: 'march-and-feb'
11038 }, // feb to march
11039 {
11040 match: "#Date .? [(march|may)]",
11041 group: 0,
11042 tag: 'Month',
11043 reason: 'feb-and-march'
11044 }, //quickly march
11045 {
11046 match: "#Adverb [(march|may)]",
11047 group: 0,
11048 tag: 'Verb',
11049 reason: 'quickly-march'
11050 }, //march quickly
11051 {
11052 match: "[(march|may)] #Adverb",
11053 group: 0,
11054 tag: 'Verb',
11055 reason: 'march-quickly'
11056 }, //5th of March
11057 {
11058 match: '#Value of #Month',
11059 tag: 'Date',
11060 reason: 'value-of-month'
11061 }, //5 March
11062 {
11063 match: '#Cardinal #Month',
11064 tag: 'Date',
11065 reason: 'cardinal-month'
11066 }, //march 5 to 7
11067 {
11068 match: '#Month #Value to #Value',
11069 tag: 'Date',
11070 reason: 'value-to-value'
11071 }, //march the 12th
11072 {
11073 match: '#Month the #Value',
11074 tag: 'Date',
11075 reason: 'month-the-value'
11076 }, //june 7
11077 {
11078 match: '(#WeekDay|#Month) #Value',
11079 tag: 'Date',
11080 reason: 'date-value'
11081 }, //7 june
11082 {
11083 match: '#Value (#WeekDay|#Month)',
11084 tag: 'Date',
11085 reason: 'value-date'
11086 }, //may twenty five
11087 {
11088 match: '(#TextValue && #Date) #TextValue',
11089 tag: 'Date',
11090 reason: 'textvalue-date'
11091 }, // in june
11092 {
11093 match: "in [".concat(dates, "]"),
11094 group: 0,
11095 tag: 'Date',
11096 reason: 'in-june'
11097 }, {
11098 match: "during [".concat(dates, "]"),
11099 group: 0,
11100 tag: 'Date',
11101 reason: 'in-june'
11102 }, {
11103 match: "on [".concat(dates, "]"),
11104 group: 0,
11105 tag: 'Date',
11106 reason: 'in-june'
11107 }, {
11108 match: "by [".concat(dates, "]"),
11109 group: 0,
11110 tag: 'Date',
11111 reason: 'by-june'
11112 }, {
11113 match: "after [".concat(dates, "]"),
11114 group: 0,
11115 tag: 'Date',
11116 reason: 'after-june'
11117 }, {
11118 match: "#Date [".concat(dates, "]"),
11119 group: 0,
11120 tag: 'Date',
11121 reason: 'in-june'
11122 }, // june 1992
11123 {
11124 match: "".concat(dates, " #Value"),
11125 tag: 'Date',
11126 reason: 'june-5th'
11127 }, {
11128 match: "".concat(dates, " #Date"),
11129 tag: 'Date',
11130 reason: 'june-5th'
11131 }, // June Smith
11132 {
11133 match: "".concat(dates, " #ProperNoun"),
11134 tag: 'Person',
11135 reason: 'june-smith',
11136 safe: true
11137 }, // june m. Cooper
11138 {
11139 match: "".concat(dates, " #Acronym? (#ProperNoun && !#Month)"),
11140 tag: 'Person',
11141 reason: 'june-smith-jr'
11142 }, // 'second'
11143 {
11144 match: "#Cardinal [second]",
11145 tag: 'Unit',
11146 reason: 'one-second'
11147 }, // second quarter
11148 // { match: `#Ordinal quarter`, tag: 'Date', reason: 'second-quarter' },
11149 // 'aug 20-21'
11150 {
11151 match: "#Month #NumberRange",
11152 tag: 'Date',
11153 reason: 'aug 20-21'
11154 }];
11155 var _02Dates = list$1;
11156
11157 var adjectives$1 = "(".concat(_ambig.personAdjective.join('|'), ")");
11158 var list$2 = [// all fell apart
11159 {
11160 match: '[all] #Determiner? #Noun',
11161 group: 0,
11162 tag: 'Adjective',
11163 reason: 'all-noun'
11164 }, // very rusty
11165 {
11166 match: "#Adverb [".concat(adjectives$1, "]"),
11167 group: 0,
11168 tag: 'Adjective',
11169 reason: 'really-rich'
11170 }, // rusty smith
11171 {
11172 match: "".concat(adjectives$1, " #Person"),
11173 tag: 'Person',
11174 reason: 'randy-smith'
11175 }, // rusty a. smith
11176 {
11177 match: "".concat(adjectives$1, " #Acronym? #ProperNoun"),
11178 tag: 'Person',
11179 reason: 'rusty-smith'
11180 }, //sometimes not-adverbs
11181 {
11182 match: '#Copula [(just|alone)]$',
11183 group: 0,
11184 tag: 'Adjective',
11185 reason: 'not-adverb'
11186 }, //jack is guarded
11187 {
11188 match: '#Singular is #Adverb? [#PastTense$]',
11189 group: 0,
11190 tag: 'Adjective',
11191 reason: 'is-filled'
11192 }, // smoked poutine is
11193 {
11194 match: '[#PastTense] #Singular is',
11195 group: 0,
11196 tag: 'Adjective',
11197 reason: 'smoked-poutine'
11198 }, // baked onions are
11199 {
11200 match: '[#PastTense] #Plural are',
11201 group: 0,
11202 tag: 'Adjective',
11203 reason: 'baked-onions'
11204 }, // well made
11205 {
11206 match: 'well [#PastTense]',
11207 group: 0,
11208 tag: 'Adjective',
11209 reason: 'well-made'
11210 }, // is f*ed up
11211 {
11212 match: '#Copula [fucked up?]',
11213 tag: 'Adjective',
11214 reason: 'swears-adjective'
11215 }, //jack seems guarded
11216 {
11217 match: '#Singular (seems|appears) #Adverb? [#PastTense$]',
11218 group: 0,
11219 tag: 'Adjective',
11220 reason: 'seems-filled'
11221 }, // Gerund-Adjectives - 'amusing, annoying'
11222 //a staggering cost
11223 {
11224 match: '(a|an) [#Gerund]',
11225 group: 0,
11226 tag: 'Adjective',
11227 reason: 'a|an'
11228 }, //as amusing as
11229 {
11230 match: 'as [#Gerund] as',
11231 group: 0,
11232 tag: 'Adjective',
11233 reason: 'as-gerund-as'
11234 }, // more amusing than
11235 {
11236 match: 'more [#Gerund] than',
11237 group: 0,
11238 tag: 'Adjective',
11239 reason: 'more-gerund-than'
11240 }, // very amusing
11241 {
11242 match: '(so|very|extremely) [#Gerund]',
11243 group: 0,
11244 tag: 'Adjective',
11245 reason: 'so-gerund'
11246 }, // it was amusing
11247 {
11248 match: '(it|he|she|everything|something) #Adverb? was #Adverb? [#Gerund]',
11249 group: 0,
11250 tag: 'Adjective',
11251 reason: 'it-was-gerund'
11252 }, // found it amusing
11253 {
11254 match: '(found|found) it #Adverb? [#Gerund]',
11255 group: 0,
11256 tag: 'Adjective',
11257 reason: 'found-it-gerund'
11258 }, // a bit amusing
11259 {
11260 match: 'a (little|bit|wee) bit? [#Gerund]',
11261 group: 0,
11262 tag: 'Adjective',
11263 reason: 'a-bit-gerund'
11264 }, // jury is out - preposition ➔ adjective
11265 {
11266 match: '#Copula #Adjective? [(out|in|through)]$',
11267 group: 0,
11268 tag: 'Adjective',
11269 reason: 'still-out'
11270 }];
11271 var _03Adjective = list$2;
11272
11273 var _04Noun = [// ==== Plural ====
11274 //there are reasons
11275 {
11276 match: 'there (are|were) #Adjective? [#PresentTense]',
11277 group: 0,
11278 tag: 'Plural',
11279 reason: 'there-are'
11280 }, // ==== Singular ====
11281 //the sun
11282 {
11283 match: '#Determiner [sun]',
11284 group: 0,
11285 tag: 'Singular',
11286 reason: 'the-sun'
11287 }, //did a 900, paid a 20
11288 {
11289 match: '#Verb (a|an) [#Value]',
11290 group: 0,
11291 tag: 'Singular',
11292 reason: 'did-a-value'
11293 }, //'the can'
11294 {
11295 match: 'the [(can|will|may)]',
11296 group: 0,
11297 tag: 'Singular',
11298 reason: 'the can'
11299 }, // ==== Possessive ====
11300 //spencer kelly's
11301 {
11302 match: '#FirstName #Acronym? (#Possessive && #LastName)',
11303 tag: 'Possessive',
11304 reason: 'name-poss'
11305 }, //Super Corp's fundraiser
11306 {
11307 match: '#Organization+ #Possessive',
11308 tag: 'Possessive',
11309 reason: 'org-possessive'
11310 }, //Los Angeles's fundraiser
11311 {
11312 match: '#Place+ #Possessive',
11313 tag: 'Possessive',
11314 reason: 'place-possessive'
11315 }, // assign all tasks
11316 {
11317 match: '(#Verb && !#Modal) (all|every|each|most|some|no) [#PresentTense]',
11318 group: 0,
11319 tag: 'Noun',
11320 reason: 'all-presentTense'
11321 }, //the above is clear
11322 {
11323 match: '#Determiner [#Adjective] #Copula',
11324 group: 0,
11325 tag: 'Noun',
11326 reason: 'the-adj-is'
11327 }, //real evil is
11328 {
11329 match: '#Adjective [#Adjective] #Copula',
11330 group: 0,
11331 tag: 'Noun',
11332 reason: 'adj-adj-is'
11333 }, // PresentTense/Noun ambiguities
11334 // big dreams, critical thinking
11335 // have big dreams
11336 {
11337 match: '(had|have|#PastTense) #Adjective [#PresentTense]',
11338 group: 0,
11339 tag: 'Noun',
11340 reason: 'adj-presentTense'
11341 }, // excellent answer spencer
11342 {
11343 match: '^#Adjective [#PresentTense]',
11344 group: 0,
11345 tag: 'Noun',
11346 reason: 'start adj-presentTense'
11347 }, // one big reason
11348 {
11349 match: '#Value #Adjective [#PresentTense]',
11350 group: 0,
11351 tag: 'Noun',
11352 reason: 'one-big-reason'
11353 }, // won widespread support
11354 {
11355 match: '#PastTense #Adjective+ [#PresentTense]',
11356 group: 0,
11357 tag: 'Noun',
11358 reason: 'won-wide-support'
11359 }, // many poses
11360 {
11361 match: '(many|few|several|couple) [#PresentTense]',
11362 group: 0,
11363 tag: 'Noun',
11364 reason: 'many-poses'
11365 }, // very big dreams
11366 {
11367 match: '#Adverb #Adjective [#PresentTense]',
11368 group: 0,
11369 tag: 'Noun',
11370 reason: 'very-big-dream'
11371 }, // good wait staff
11372 {
11373 match: '#Adjective [#Infinitive] #Noun',
11374 group: 0,
11375 tag: 'Noun',
11376 reason: 'good-wait-staff'
11377 }, // adorable little store
11378 {
11379 match: '#Adjective #Adjective [#PresentTense]',
11380 group: 0,
11381 tag: 'Noun',
11382 reason: 'adorable-little-store'
11383 }, // of basic training
11384 {
11385 match: '#Preposition #Adjective [#PresentTense]',
11386 group: 0,
11387 tag: 'Noun',
11388 reason: 'of-basic-training'
11389 }, // early warning
11390 {
11391 match: '#Adjective [#Gerund]',
11392 group: 0,
11393 tag: 'Noun',
11394 reason: 'early-warning'
11395 }, // justifiying higher costs
11396 {
11397 match: '#Gerund #Adverb? #Comparative [#PresentTense]',
11398 group: 0,
11399 tag: 'Noun',
11400 reason: 'higher-costs'
11401 }, // do the dance
11402 {
11403 match: '#Infinitive (this|that|the) [#Infinitive]',
11404 group: 0,
11405 tag: 'Noun',
11406 reason: 'do-this-dance'
11407 }, //his fine
11408 {
11409 match: '(his|her|its) [#Adjective]',
11410 group: 0,
11411 tag: 'Noun',
11412 reason: 'his-fine'
11413 }, //some pressing issues
11414 {
11415 match: 'some [#Verb] #Plural',
11416 group: 0,
11417 tag: 'Noun',
11418 reason: 'determiner6'
11419 }, //'more' is not always an adverb
11420 {
11421 match: 'more #Noun',
11422 tag: 'Noun',
11423 reason: 'more-noun'
11424 }, {
11425 match: '(#Noun && @hasComma) #Noun (and|or) [#PresentTense]',
11426 group: 0,
11427 tag: 'Noun',
11428 reason: 'noun-list'
11429 }, //3 feet
11430 {
11431 match: '(right|rights) of .',
11432 tag: 'Noun',
11433 reason: 'right-of'
11434 }, // a bit
11435 {
11436 match: 'a [bit]',
11437 group: 0,
11438 tag: 'Noun',
11439 reason: 'bit-2'
11440 }, // my first thought
11441 {
11442 match: '#Possessive #Ordinal [#PastTense]',
11443 group: 0,
11444 tag: 'Noun',
11445 reason: 'first-thought'
11446 }, //running-a-show
11447 {
11448 match: '#Gerund #Determiner [#Infinitive]',
11449 group: 0,
11450 tag: 'Noun',
11451 reason: 'running-a-show'
11452 }, //the-only-reason
11453 {
11454 match: '#Determiner #Adverb [#Infinitive]',
11455 group: 0,
11456 tag: 'Noun',
11457 reason: 'the-reason'
11458 }, //the nice swim
11459 {
11460 match: '(the|this|those|these) #Adjective [#Verb]',
11461 group: 0,
11462 tag: 'Noun',
11463 reason: 'the-adj-verb'
11464 }, // the truly nice swim
11465 {
11466 match: '(the|this|those|these) #Adverb #Adjective [#Verb]',
11467 group: 0,
11468 tag: 'Noun',
11469 reason: 'determiner4'
11470 }, //the orange is
11471 {
11472 match: '#Determiner [#Adjective] (#Copula|#PastTense|#Auxiliary)',
11473 group: 0,
11474 tag: 'Noun',
11475 reason: 'the-adj-2'
11476 }, // a stream runs
11477 {
11478 match: '(the|this|a|an) [#Infinitive] #Adverb? #Verb',
11479 group: 0,
11480 tag: 'Noun',
11481 reason: 'determiner5'
11482 }, //the test string
11483 {
11484 match: '#Determiner [#Infinitive] #Noun',
11485 group: 0,
11486 tag: 'Noun',
11487 reason: 'determiner7'
11488 }, //a nice deal
11489 {
11490 match: '#Determiner #Adjective #Adjective? [#Infinitive]',
11491 group: 0,
11492 tag: 'Noun',
11493 reason: 'a-nice-inf'
11494 }, //the wait to vote
11495 {
11496 match: 'the [#Verb] #Preposition .',
11497 group: 0,
11498 tag: 'Noun',
11499 reason: 'determiner1'
11500 }, //a sense of
11501 {
11502 match: '#Determiner [#Verb] of',
11503 group: 0,
11504 tag: 'Noun',
11505 reason: 'the-verb-of'
11506 }, //next career move
11507 {
11508 match: '#Adjective #Noun+ [#Infinitive] #Copula',
11509 group: 0,
11510 tag: 'Noun',
11511 reason: 'career-move'
11512 }, //the threat of force
11513 {
11514 match: '#Determiner #Noun of [#Verb]',
11515 group: 0,
11516 tag: 'Noun',
11517 reason: 'noun-of-noun'
11518 }, //the western line
11519 {
11520 match: '#Determiner [(western|eastern|northern|southern|central)] #Noun',
11521 group: 0,
11522 tag: 'Noun',
11523 reason: 'western-line'
11524 }, //her polling
11525 {
11526 match: '#Possessive [#Gerund]',
11527 group: 0,
11528 tag: 'Noun',
11529 reason: 'her-polling'
11530 }, //her fines
11531 {
11532 match: '(his|her|its) [#PresentTense]',
11533 group: 0,
11534 tag: 'Noun',
11535 reason: 'its-polling'
11536 }, //linear algebra
11537 {
11538 match: '(#Determiner|#Value) [(linear|binary|mobile|lexical|technical|computer|scientific|formal)] #Noun',
11539 group: 0,
11540 tag: 'Noun',
11541 reason: 'technical-noun'
11542 }, // a blown motor
11543 {
11544 match: '(the|those|these|a|an) [#Participle] #Noun',
11545 group: 0,
11546 tag: 'Adjective',
11547 reason: 'blown-motor'
11548 }, // walk the walk
11549 {
11550 match: '(the|those|these|a|an) #Adjective? [#Infinitive]',
11551 group: 0,
11552 tag: 'Noun',
11553 reason: 'det-inf'
11554 }, {
11555 match: '(the|those|these|a|an) #Adjective? [#PresentTense]',
11556 group: 0,
11557 tag: 'Noun',
11558 reason: 'det-pres'
11559 }, {
11560 match: '(the|those|these|a|an) #Adjective? [#PastTense]',
11561 group: 0,
11562 tag: 'Noun',
11563 reason: 'det-past'
11564 }, // this swimming
11565 {
11566 match: '(this|that) [#Gerund]',
11567 group: 0,
11568 tag: 'Noun',
11569 reason: 'this-gerund'
11570 }, // at some point
11571 {
11572 match: 'at some [#Infinitive]',
11573 group: 0,
11574 tag: 'Noun',
11575 reason: 'at-some-inf'
11576 }, //air-flow
11577 {
11578 match: '(#Noun && @hasHyphen) #Verb',
11579 tag: 'Noun',
11580 reason: 'hyphen-verb'
11581 }, //is no walk
11582 {
11583 match: 'is no [#Verb]',
11584 group: 0,
11585 tag: 'Noun',
11586 reason: 'is-no-verb'
11587 }, //different views than
11588 {
11589 match: '[#Verb] than',
11590 group: 0,
11591 tag: 'Noun',
11592 reason: 'correction'
11593 }, // goes to sleep
11594 {
11595 match: '(go|goes|went) to [#Infinitive]',
11596 group: 0,
11597 tag: 'Noun',
11598 reason: 'goes-to-verb'
11599 }, //a great run
11600 // { match: '(a|an) #Adjective [(#Infinitive|#PresentTense)]', tag: 'Noun', reason: 'a|an2' },
11601 //a tv show
11602 {
11603 match: '(a|an) #Noun [#Infinitive]',
11604 group: 0,
11605 tag: 'Noun',
11606 reason: 'a-noun-inf'
11607 }, //do so
11608 {
11609 match: 'do [so]',
11610 group: 0,
11611 tag: 'Noun',
11612 reason: 'so-noun'
11613 }, //is mark hughes
11614 {
11615 match: '#Copula [#Infinitive] #Noun',
11616 group: 0,
11617 tag: 'Noun',
11618 reason: 'is-pres-noun'
11619 }, //
11620 // { match: '[#Infinitive] #Copula', group: 0, tag: 'Noun', reason: 'inf-copula' },
11621 //a close
11622 {
11623 match: '#Determiner #Adverb? [close]',
11624 group: 0,
11625 tag: 'Adjective',
11626 reason: 'a-close'
11627 }, // what the hell
11628 {
11629 match: '#Determiner [(shit|damn|hell)]',
11630 group: 0,
11631 tag: 'Noun',
11632 reason: 'swears-noun'
11633 }, // the staff were
11634 {
11635 match: '(the|these) [#Singular] (were|are)',
11636 group: 0,
11637 tag: 'Plural',
11638 reason: 'singular-were'
11639 }, // running for congress
11640 {
11641 match: '#Gerund #Adjective? for [#Infinitive]',
11642 group: 0,
11643 tag: 'Noun',
11644 reason: 'running-for'
11645 }, // running to work
11646 {
11647 match: '#Gerund #Adjective to [#Infinitive]',
11648 group: 0,
11649 tag: 'Noun',
11650 reason: 'running-to'
11651 }, // any questions for
11652 {
11653 match: '(many|any|some|several) [#PresentTense] for',
11654 group: 0,
11655 tag: 'Noun',
11656 reason: 'any-verbs-for'
11657 }, // have fun
11658 {
11659 match: "(have|had) [#Adjective] #Preposition .",
11660 group: 0,
11661 tag: 'Noun',
11662 reason: 'have-fun'
11663 }, // co-founder
11664 {
11665 match: "co #Noun",
11666 tag: 'Actor',
11667 reason: 'co-noun'
11668 }];
11669
11670 var adjectives$2 = "(".concat(_ambig.adverbAdjective.join('|'), ")");
11671 var _05Adverb = [//still good
11672 {
11673 match: '[still] #Adjective',
11674 group: 0,
11675 tag: 'Adverb',
11676 reason: 'still-advb'
11677 }, //still make
11678 {
11679 match: '[still] #Verb',
11680 group: 0,
11681 tag: 'Adverb',
11682 reason: 'still-verb'
11683 }, // so hot
11684 {
11685 match: '[so] #Adjective',
11686 group: 0,
11687 tag: 'Adverb',
11688 reason: 'so-adv'
11689 }, // way hotter
11690 {
11691 match: '[way] #Comparative',
11692 group: 0,
11693 tag: 'Adverb',
11694 reason: 'way-adj'
11695 }, // way too hot
11696 {
11697 match: '[way] #Adverb #Adjective',
11698 group: 0,
11699 tag: 'Adverb',
11700 reason: 'way-too-adj'
11701 }, // all singing
11702 {
11703 match: '[all] #Verb',
11704 group: 0,
11705 tag: 'Adverb',
11706 reason: 'all-verb'
11707 }, // sing like an angel
11708 {
11709 match: '(#Verb && !#Modal) [like]',
11710 group: 0,
11711 tag: 'Adverb',
11712 reason: 'verb-like'
11713 }, //barely even walk
11714 {
11715 match: '(barely|hardly) even',
11716 tag: 'Adverb',
11717 reason: 'barely-even'
11718 }, //even held
11719 {
11720 match: '[even] #Verb',
11721 group: 0,
11722 tag: 'Adverb',
11723 reason: 'even-walk'
11724 }, // even left
11725 {
11726 match: 'even left',
11727 tag: '#Adverb #Verb',
11728 reason: 'even-left'
11729 }, //cheering hard - dropped -ly's
11730 {
11731 match: '#PresentTense [(hard|quick|long|bright|slow)]',
11732 group: 0,
11733 tag: 'Adverb',
11734 reason: 'lazy-ly'
11735 }, // much appreciated
11736 {
11737 match: '[much] #Adjective',
11738 group: 0,
11739 tag: 'Adverb',
11740 reason: 'bit-1'
11741 }, // is well
11742 {
11743 match: '#Copula [#Adverb]$',
11744 group: 0,
11745 tag: 'Adjective',
11746 reason: 'is-well'
11747 }, // a bit cold
11748 {
11749 match: 'a [(little|bit|wee) bit?] #Adjective',
11750 group: 0,
11751 tag: 'Adverb',
11752 reason: 'a-bit-cold'
11753 }, // dark green
11754 {
11755 match: "[".concat(adjectives$2, "] #Adjective"),
11756 group: 0,
11757 tag: 'Adverb',
11758 reason: 'dark-green'
11759 }, // kinda sparkly
11760 {
11761 match: "#Adverb [#Adverb]$",
11762 group: 0,
11763 tag: 'Adjective',
11764 reason: 'kinda-sparkly'
11765 }, {
11766 match: "#Adverb [#Adverb] (and|or|then)",
11767 group: 0,
11768 tag: 'Adjective',
11769 reason: 'kinda-sparkly-and'
11770 }];
11771
11772 var _06Value = [// ==== PhoneNumber ====
11773 //1 800 ...
11774 {
11775 match: '1 #Value #PhoneNumber',
11776 tag: 'PhoneNumber',
11777 reason: '1-800-Value'
11778 }, //(454) 232-9873
11779 {
11780 match: '#NumericValue #PhoneNumber',
11781 tag: 'PhoneNumber',
11782 reason: '(800) PhoneNumber'
11783 }, // ==== Currency ====
11784 // chinese yuan
11785 {
11786 match: '#Demonym #Currency',
11787 tag: 'Currency',
11788 reason: 'demonym-currency'
11789 }, // ==== Ordinal ====
11790 {
11791 match: '[second] #Noun',
11792 group: 0,
11793 tag: 'Ordinal',
11794 reason: 'second-noun'
11795 }, // ==== Unit ====
11796 //5 yan
11797 {
11798 match: '#Value+ [#Currency]',
11799 group: 0,
11800 tag: 'Unit',
11801 reason: '5-yan'
11802 }, {
11803 match: '#Value [(foot|feet)]',
11804 group: 0,
11805 tag: 'Unit',
11806 reason: 'foot-unit'
11807 }, //minus 7
11808 {
11809 match: '(minus|negative) #Value',
11810 tag: 'Value',
11811 reason: 'minus-value'
11812 }, //5 kg.
11813 {
11814 match: '#Value [#Abbreviation]',
11815 group: 0,
11816 tag: 'Unit',
11817 reason: 'value-abbr'
11818 }, {
11819 match: '#Value [k]',
11820 group: 0,
11821 tag: 'Unit',
11822 reason: 'value-k'
11823 }, {
11824 match: '#Unit an hour',
11825 tag: 'Unit',
11826 reason: 'unit-an-hour'
11827 }, //seven point five
11828 {
11829 match: '#Value (point|decimal) #Value',
11830 tag: 'Value',
11831 reason: 'value-point-value'
11832 }, // ten bucks
11833 {
11834 match: '(#Value|a) [(buck|bucks|grand)]',
11835 group: 0,
11836 tag: 'Currency',
11837 reason: 'value-bucks'
11838 }, //quarter million
11839 {
11840 match: '#Determiner [(half|quarter)] #Ordinal',
11841 group: 0,
11842 tag: 'Value',
11843 reason: 'half-ordinal'
11844 }, {
11845 match: 'a #Value',
11846 tag: 'Value',
11847 reason: 'a-value'
11848 }, // ==== Money ====
11849 {
11850 match: '[#Value+] #Currency',
11851 group: 0,
11852 tag: 'Money',
11853 reason: '15 usd'
11854 }, // thousand and two
11855 {
11856 match: "(hundred|thousand|million|billion|trillion|quadrillion)+ and #Value",
11857 tag: 'Value',
11858 reason: 'magnitude-and-value'
11859 }, //'a/an' can mean 1 - "a hour"
11860 {
11861 match: '!once [(a|an)] (#Duration|hundred|thousand|million|billion|trillion)',
11862 group: 0,
11863 tag: 'Value',
11864 reason: 'a-is-one'
11865 }];
11866
11867 var verbs$1 = "(".concat(_ambig.personVerb.join('|'), ")");
11868 var list$3 = [// adj -> gerund
11869 // amusing his aunt
11870 {
11871 match: '[#Adjective] #Possessive #Noun',
11872 group: 0,
11873 tag: 'Verb',
11874 reason: 'gerund-his-noun'
11875 }, // loving you
11876 {
11877 match: '[#Adjective] (us|you)',
11878 group: 0,
11879 tag: 'Gerund',
11880 reason: 'loving-you'
11881 }, // slowly stunning
11882 {
11883 match: '(slowly|quickly) [#Adjective]',
11884 group: 0,
11885 tag: 'Gerund',
11886 reason: 'slowly-adj'
11887 }, // like
11888 {
11889 match: '(#Modal|i|they|we|do) not? [like]',
11890 group: 0,
11891 tag: 'PresentTense',
11892 reason: 'modal-like'
11893 }, // do not simply like
11894 {
11895 match: 'do (simply|just|really|not)+ [(#Adjective|like)]',
11896 group: 0,
11897 tag: 'Verb',
11898 reason: 'do-simply-like'
11899 }, // does mean
11900 {
11901 match: 'does (#Adverb|not)? [#Adjective]',
11902 group: 0,
11903 tag: 'PresentTense',
11904 reason: 'does-mean'
11905 }, // i mean
11906 {
11907 match: 'i (#Adverb|do)? not? [mean]',
11908 group: 0,
11909 tag: 'PresentTense',
11910 reason: 'i-mean'
11911 }, // { match: '!are (i|you|we) (#Adverb|do)? [#Adjective]', group: 0, tag: 'PresentTense', reason: 'i-mean' },
11912 // ==== Tense ====
11913 //he left
11914 {
11915 match: '#Noun #Adverb? [left]',
11916 group: 0,
11917 tag: 'PastTense',
11918 reason: 'left-verb'
11919 }, //this rocks
11920 {
11921 match: '(this|that) [#Plural]',
11922 group: 0,
11923 tag: 'PresentTense',
11924 reason: 'this-verbs'
11925 }, // ==== Auxiliary ====
11926 //was walking
11927 {
11928 match: "[#Copula (#Adverb|not)+?] (#Gerund|#PastTense)",
11929 group: 0,
11930 tag: 'Auxiliary',
11931 reason: 'copula-walking'
11932 }, //support a splattering of auxillaries before a verb
11933 {
11934 match: "[(has|had) (#Adverb|not)+?] #PastTense",
11935 group: 0,
11936 tag: 'Auxiliary',
11937 reason: 'had-walked'
11938 }, //would walk
11939 {
11940 match: "[#Adverb+? (#Modal|did)+ (#Adverb|not)+?] #Verb",
11941 group: 0,
11942 tag: 'Auxiliary',
11943 reason: 'modal-verb'
11944 }, //would have had
11945 {
11946 match: "[#Modal (#Adverb|not)+? have (#Adverb|not)+? had (#Adverb|not)+?] #Verb",
11947 group: 0,
11948 tag: 'Auxiliary',
11949 reason: 'would-have'
11950 }, //would be walking
11951 // { match: `#Modal (#Adverb|not)+? be (#Adverb|not)+? #Verb`, group: 0, tag: 'Auxiliary', reason: 'would-be' },
11952 //had been walking
11953 // {
11954 // match: `(#Modal|had|has) (#Adverb|not)+? been (#Adverb|not)+? #Verb`,
11955 // group: 0,
11956 // tag: 'Auxiliary',
11957 // reason: 'had-been',
11958 // },
11959 //support a splattering of auxillaries before a verb
11960 {
11961 match: "[(has|had) (#Adverb|not)+?] #PastTense",
11962 group: 0,
11963 tag: 'Auxiliary',
11964 reason: 'had-walked'
11965 }, // will walk
11966 {
11967 match: '[(do|does|will|have|had)] (not|#Adverb)? #Verb',
11968 group: 0,
11969 tag: 'Auxiliary',
11970 reason: 'have-had'
11971 }, // about to go
11972 {
11973 match: '[about to] #Adverb? #Verb',
11974 group: 0,
11975 tag: ['Auxiliary', 'Verb'],
11976 reason: 'about-to'
11977 }, //would be walking
11978 {
11979 match: "#Modal (#Adverb|not)+? be (#Adverb|not)+? #Verb",
11980 group: 0,
11981 tag: 'Auxiliary',
11982 reason: 'would-be'
11983 }, //were being run
11984 {
11985 match: "(were|was) being [#PresentTense]",
11986 group: 0,
11987 tag: 'PastTense',
11988 reason: 'was-being'
11989 }, //have run
11990 // { match: `have #PresentTense`, group: 0, tag: 'PastTense', reason: 'have-vb' },
11991 //would have had
11992 {
11993 match: "[#Modal (#Adverb|not)+? have (#Adverb|not)+? had (#Adverb|not)+?] #Verb",
11994 group: 0,
11995 tag: 'Auxiliary',
11996 reason: 'would-have'
11997 }, //had been walking
11998 {
11999 match: "(#Modal|had|has) (#Adverb|not)+? been (#Adverb|not)+? #Verb",
12000 group: 0,
12001 tag: 'Auxiliary',
12002 reason: 'had-been'
12003 }, // was being driven
12004 {
12005 match: '[(be|being|been)] #Participle',
12006 group: 0,
12007 tag: 'Auxiliary',
12008 reason: 'being-foo'
12009 }, // ==== Phrasal ====
12010 //'foo-up'
12011 {
12012 match: '(#Verb && @hasHyphen) up',
12013 tag: 'PhrasalVerb',
12014 reason: 'foo-up'
12015 }, {
12016 match: '(#Verb && @hasHyphen) off',
12017 tag: 'PhrasalVerb',
12018 reason: 'foo-off'
12019 }, {
12020 match: '(#Verb && @hasHyphen) over',
12021 tag: 'PhrasalVerb',
12022 reason: 'foo-over'
12023 }, {
12024 match: '(#Verb && @hasHyphen) out',
12025 tag: 'PhrasalVerb',
12026 reason: 'foo-out'
12027 }, //fall over
12028 {
12029 match: '#PhrasalVerb [#PhrasalVerb]',
12030 group: 0,
12031 tag: 'Particle',
12032 reason: 'phrasal-particle'
12033 }, //back it up
12034 {
12035 match: '#Verb (him|her|it|us|himself|herself|itself|everything|something) [(up|down)]',
12036 group: 0,
12037 tag: 'Adverb',
12038 reason: 'phrasal-pronoun-advb'
12039 }, // ==== Copula ====
12040 //will be running (not copula)
12041 {
12042 match: '[will #Adverb? not? #Adverb? be] #Gerund',
12043 group: 0,
12044 tag: 'Copula',
12045 reason: 'will-be-copula'
12046 }, //for more complex forms, just tag 'be'
12047 {
12048 match: 'will #Adverb? not? #Adverb? [be] #Adjective',
12049 group: 0,
12050 tag: 'Copula',
12051 reason: 'be-copula'
12052 }, // ==== Infinitive ====
12053 //march to
12054 {
12055 match: '[march] (up|down|back|to|toward)',
12056 group: 0,
12057 tag: 'Infinitive',
12058 reason: 'march-to'
12059 }, //must march
12060 {
12061 match: '#Modal [march]',
12062 group: 0,
12063 tag: 'Infinitive',
12064 reason: 'must-march'
12065 }, //let him glue
12066 {
12067 match: '(let|make|made) (him|her|it|#Person|#Place|#Organization)+ [#Singular] (a|an|the|it)',
12068 group: 0,
12069 tag: 'Infinitive',
12070 reason: 'let-him-glue'
12071 }, //he quickly foo
12072 // { match: '#Noun #Adverb [#Noun]', group: 0, tag: 'Verb', reason: 'quickly-foo' },
12073 //will secure our
12074 {
12075 match: 'will [#Adjective]',
12076 group: 0,
12077 tag: 'Verb',
12078 reason: 'will-adj'
12079 }, //he disguised the thing
12080 {
12081 match: '#Pronoun [#Adjective] #Determiner #Adjective? #Noun',
12082 group: 0,
12083 tag: 'Verb',
12084 reason: 'he-adj-the'
12085 }, //is eager to go
12086 {
12087 match: '#Copula [#Adjective to] #Verb',
12088 group: 0,
12089 tag: 'Verb',
12090 reason: 'adj-to'
12091 }, // open the door
12092 {
12093 match: '[open] #Determiner',
12094 group: 0,
12095 tag: 'Infinitive',
12096 reason: 'open-the'
12097 }, // compromises are possible
12098 {
12099 match: '[#PresentTense] (are|were|was) #Adjective',
12100 group: 0,
12101 tag: 'Plural',
12102 reason: 'compromises-are-possible'
12103 }, // would wade
12104 {
12105 match: "#Modal [".concat(verbs$1, "]"),
12106 group: 0,
12107 tag: 'Verb',
12108 reason: 'would-mark'
12109 }, {
12110 match: "#Adverb [".concat(verbs$1, "]"),
12111 group: 0,
12112 tag: 'Verb',
12113 reason: 'really-mark'
12114 }, //to mark
12115 {
12116 match: '(to|#Modal) [mark]',
12117 group: 0,
12118 tag: 'PresentTense',
12119 reason: 'to-mark'
12120 }, // wade smith
12121 {
12122 match: "".concat(verbs$1, " #Person"),
12123 tag: 'Person',
12124 reason: 'rob-smith'
12125 }, // wade m. Cooper
12126 {
12127 match: "".concat(verbs$1, " #Acronym #ProperNoun"),
12128 tag: 'Person',
12129 reason: 'rob-a-smith'
12130 }, // damn them
12131 {
12132 match: '[shit] (#Determiner|#Possessive|them)',
12133 group: 0,
12134 tag: 'Verb',
12135 reason: 'swear1-verb'
12136 }, {
12137 match: '[damn] (#Determiner|#Possessive|them)',
12138 group: 0,
12139 tag: 'Verb',
12140 reason: 'swear2-verb'
12141 }, {
12142 match: '[fuck] (#Determiner|#Possessive|them)',
12143 group: 0,
12144 tag: 'Verb',
12145 reason: 'swear3-verb'
12146 }];
12147 var _07Verbs = list$3;
12148
12149 var list$4 = [// ==== Region ====
12150 //West Norforlk
12151 {
12152 match: '(west|north|south|east|western|northern|southern|eastern)+ #Place',
12153 tag: 'Region',
12154 reason: 'west-norfolk'
12155 }, //some us-state acronyms (exlude: al, in, la, mo, hi, me, md, ok..)
12156 {
12157 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)]',
12158 group: 0,
12159 tag: 'Region',
12160 reason: 'us-state'
12161 }, //Foo District
12162 {
12163 match: '#ProperNoun+ (district|region|province|county|prefecture|municipality|territory|burough|reservation)',
12164 tag: 'Region',
12165 reason: 'foo-district'
12166 }, //District of Foo
12167 {
12168 match: '(district|region|province|municipality|territory|burough|state) of #ProperNoun',
12169 tag: 'Region',
12170 reason: 'district-of-Foo'
12171 }, // in Foo California
12172 {
12173 match: 'in [#ProperNoun] #Place',
12174 group: 0,
12175 tag: 'Place',
12176 reason: 'propernoun-place'
12177 }, // ==== Address ====
12178 {
12179 match: '#Value #Noun (st|street|rd|road|crescent|cr|way|tr|terrace|avenue|ave)',
12180 tag: 'Address',
12181 reason: 'address-st'
12182 } // in houston
12183 // { match: `in [${places}]`, group: 0, tag: 'Place', reason: 'in-paris' },
12184 // { match: `near [${places}]`, group: 0, tag: 'Place', reason: 'near-paris' },
12185 // { match: `at [${places}]`, group: 0, tag: 'Place', reason: 'at-paris' },
12186 // { match: `from [${places}]`, group: 0, tag: 'Place', reason: 'from-paris' },
12187 // { match: `to [${places}]`, group: 0, tag: 'Place', reason: 'to-paris' },
12188 // { match: `#Place [${places}]`, group: 0, tag: 'Place', reason: 'tokyo-paris' },
12189 // // houston texas
12190 // { match: `[${places}] #Place`, group: 0, tag: 'Place', reason: 'paris-france' },
12191 ];
12192 var _08Place = list$4;
12193
12194 var _09Org = [//John & Joe's
12195 {
12196 match: '#Noun (&|n) #Noun',
12197 tag: 'Organization',
12198 reason: 'Noun-&-Noun'
12199 }, // teachers union of Ontario
12200 {
12201 match: '#Organization of the? #ProperNoun',
12202 tag: 'Organization',
12203 reason: 'org-of-place',
12204 safe: true
12205 }, //walmart USA
12206 {
12207 match: '#Organization #Country',
12208 tag: 'Organization',
12209 reason: 'org-country'
12210 }, //organization
12211 {
12212 match: '#ProperNoun #Organization',
12213 tag: 'Organization',
12214 reason: 'titlecase-org'
12215 }, //FitBit Inc
12216 {
12217 match: '#ProperNoun (ltd|co|inc|dept|assn|bros)',
12218 tag: 'Organization',
12219 reason: 'org-abbrv'
12220 }, // the OCED
12221 {
12222 match: 'the [#Acronym]',
12223 group: 0,
12224 tag: 'Organization',
12225 reason: 'the-acronym',
12226 safe: true
12227 }, // global trade union
12228 {
12229 match: '(world|global|international|national|#Demonym) #Organization',
12230 tag: 'Organization',
12231 reason: 'global-org'
12232 }, // schools
12233 {
12234 match: '#Noun+ (public|private) school',
12235 tag: 'School',
12236 reason: 'noun-public-school'
12237 }];
12238
12239 var nouns$1 = "(".concat(_ambig.personNoun.join('|'), ")");
12240 var months = "(".concat(_ambig.personMonth.join('|'), ")");
12241 var places = "(".concat(_ambig.personPlace.join('|'), ")");
12242 var list$5 = [// ==== Honorific ====
12243 {
12244 match: '[(1st|2nd|first|second)] #Honorific',
12245 group: 0,
12246 tag: 'Honorific',
12247 reason: 'ordinal-honorific'
12248 }, {
12249 match: '[(private|general|major|corporal|lord|lady|secretary|premier)] #Honorific? #Person',
12250 group: 0,
12251 tag: 'Honorific',
12252 reason: 'ambg-honorifics'
12253 }, // ==== FirstNames ====
12254 //is foo Smith
12255 {
12256 match: '#Copula [(#Noun|#PresentTense)] #LastName',
12257 group: 0,
12258 tag: 'FirstName',
12259 reason: 'copula-noun-lastname'
12260 }, //pope francis
12261 {
12262 match: '(lady|queen|sister) #ProperNoun',
12263 tag: 'FemaleName',
12264 reason: 'lady-titlecase',
12265 safe: true
12266 }, {
12267 match: '(king|pope|father) #ProperNoun',
12268 tag: 'MaleName',
12269 reason: 'pope-titlecase',
12270 safe: true
12271 }, //ambiguous-but-common firstnames
12272 {
12273 match: '[(will|may|april|june|said|rob|wade|ray|rusty|drew|miles|jack|chuck|randy|jan|pat|cliff|bill)] #LastName',
12274 group: 0,
12275 tag: 'FirstName',
12276 reason: 'maybe-lastname'
12277 }, // ==== Nickname ====
12278 // Dwayne 'the rock' Johnson
12279 {
12280 match: '#FirstName [#Determiner #Noun] #LastName',
12281 group: 0,
12282 tag: 'NickName',
12283 reason: 'first-noun-last'
12284 }, //my buddy
12285 {
12286 match: '#Possessive [#FirstName]',
12287 group: 0,
12288 tag: 'Person',
12289 reason: 'possessive-name'
12290 }, {
12291 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',
12292 tag: 'Person',
12293 reason: 'titlecase-acronym-titlecase',
12294 safe: true
12295 }, //ludwig van beethovan
12296 {
12297 match: '#Acronym #LastName',
12298 tag: 'Person',
12299 reason: 'acronym-latname',
12300 safe: true
12301 }, //jk rowling
12302 {
12303 match: '#Person (jr|sr|md)',
12304 tag: 'Person',
12305 reason: 'person-honorific'
12306 }, //peter II
12307 {
12308 match: '#Person #Person the? #RomanNumeral',
12309 tag: 'Person',
12310 reason: 'roman-numeral'
12311 }, //'Professor Fink', 'General McCarthy'
12312 {
12313 match: '#FirstName [/^[^aiurck]$/]',
12314 group: 0,
12315 tag: ['Acronym', 'Person'],
12316 reason: 'john-e'
12317 }, //Doctor john smith jr
12318 //general pearson
12319 {
12320 match: '#Honorific #Person',
12321 tag: 'Person',
12322 reason: 'honorific-person'
12323 }, //remove single 'mr'
12324 {
12325 match: '#Honorific #Acronym',
12326 tag: 'Person',
12327 reason: 'Honorific-TitleCase'
12328 }, //j.k Rowling
12329 {
12330 match: '#Noun van der? #Noun',
12331 tag: 'Person',
12332 reason: 'van der noun',
12333 safe: true
12334 }, //king of spain
12335 {
12336 match: '(king|queen|prince|saint|lady) of #Noun',
12337 tag: 'Person',
12338 reason: 'king-of-noun',
12339 safe: true
12340 }, //lady Florence
12341 {
12342 match: '(prince|lady) #Place',
12343 tag: 'Person',
12344 reason: 'lady-place'
12345 }, //saint Foo
12346 {
12347 match: '(king|queen|prince|saint) #ProperNoun',
12348 tag: 'Person',
12349 reason: 'saint-foo'
12350 }, //Foo U Ford
12351 {
12352 match: '[#ProperNoun] #Person',
12353 group: 0,
12354 tag: 'Person',
12355 reason: 'proper-person',
12356 safe: true
12357 }, // al sharpton
12358 {
12359 match: 'al (#Person|#ProperNoun)',
12360 tag: 'Person',
12361 reason: 'al-borlen',
12362 safe: true
12363 }, //ferdinand de almar
12364 {
12365 match: '#FirstName de #Noun',
12366 tag: 'Person',
12367 reason: 'bill-de-noun'
12368 }, //Osama bin Laden
12369 {
12370 match: '#FirstName (bin|al) #Noun',
12371 tag: 'Person',
12372 reason: 'bill-al-noun'
12373 }, //John L. Foo
12374 {
12375 match: '#FirstName #Acronym #ProperNoun',
12376 tag: 'Person',
12377 reason: 'bill-acronym-title'
12378 }, //Andrew Lloyd Webber
12379 {
12380 match: '#FirstName #FirstName #ProperNoun',
12381 tag: 'Person',
12382 reason: 'bill-firstname-title'
12383 }, //Mr Foo
12384 {
12385 match: '#Honorific #FirstName? #ProperNoun',
12386 tag: 'Person',
12387 reason: 'dr-john-Title'
12388 }, //peter the great
12389 {
12390 match: '#FirstName the #Adjective',
12391 tag: 'Person',
12392 reason: 'name-the-great'
12393 }, //very common-but-ambiguous lastnames
12394 {
12395 match: '#FirstName (green|white|brown|hall|young|king|hill|cook|gray|price)',
12396 tag: 'Person',
12397 reason: 'bill-green'
12398 }, // faith smith
12399 {
12400 match: "".concat(nouns$1, " #Person"),
12401 tag: 'Person',
12402 reason: 'ray-smith',
12403 safe: true
12404 }, // faith m. Smith
12405 {
12406 match: "".concat(nouns$1, " #Acronym? #ProperNoun"),
12407 tag: 'Person',
12408 reason: 'ray-a-smith',
12409 safe: true
12410 }, //give to april
12411 {
12412 match: "#Infinitive #Determiner? #Adjective? #Noun? (to|for) [".concat(months, "]"),
12413 group: 0,
12414 tag: 'Person',
12415 reason: 'ambig-person'
12416 }, // remind june
12417 {
12418 match: "#Infinitive [".concat(months, "]"),
12419 group: 0,
12420 tag: 'Person',
12421 reason: 'infinitive-person'
12422 }, // may waits for
12423 // { match: `[${months}] #PresentTense for`, group: 0, tag: 'Person', reason: 'ambig-active-for' },
12424 // may waits to
12425 // { match: `[${months}] #PresentTense to`, group: 0, tag: 'Person', reason: 'ambig-active-to' },
12426 // april will
12427 {
12428 match: "[".concat(months, "] #Modal"),
12429 group: 0,
12430 tag: 'Person',
12431 reason: 'ambig-modal'
12432 }, // may be
12433 {
12434 match: "[may] be",
12435 group: 0,
12436 tag: 'Verb',
12437 reason: 'may-be'
12438 }, // would april
12439 {
12440 match: "#Modal [".concat(months, "]"),
12441 group: 0,
12442 tag: 'Person',
12443 reason: 'modal-ambig'
12444 }, // it is may
12445 {
12446 match: "#Copula [".concat(months, "]"),
12447 group: 0,
12448 tag: 'Person',
12449 reason: 'is-may'
12450 }, // may is
12451 {
12452 match: "[".concat(months, "] #Copula"),
12453 group: 0,
12454 tag: 'Person',
12455 reason: 'may-is'
12456 }, // with april
12457 {
12458 match: "that [".concat(months, "]"),
12459 group: 0,
12460 tag: 'Person',
12461 reason: 'that-month'
12462 }, // with april
12463 {
12464 match: "with [".concat(months, "]"),
12465 group: 0,
12466 tag: 'Person',
12467 reason: 'with-month'
12468 }, // for april
12469 {
12470 match: "for [".concat(months, "]"),
12471 group: 0,
12472 tag: 'Person',
12473 reason: 'for-month'
12474 }, // this april
12475 {
12476 match: "this [".concat(months, "]"),
12477 group: 0,
12478 tag: 'Month',
12479 reason: 'this-may'
12480 }, //maybe not 'this'
12481 // next april
12482 {
12483 match: "next [".concat(months, "]"),
12484 group: 0,
12485 tag: 'Month',
12486 reason: 'next-may'
12487 }, // last april
12488 {
12489 match: "last [".concat(months, "]"),
12490 group: 0,
12491 tag: 'Month',
12492 reason: 'last-may'
12493 }, // wednesday april
12494 {
12495 match: "#Date [".concat(months, "]"),
12496 group: 0,
12497 tag: 'Month',
12498 reason: 'date-may'
12499 }, // may 5th
12500 {
12501 match: "[".concat(months, "] the? #Value"),
12502 group: 0,
12503 tag: 'Month',
12504 reason: 'may-5th'
12505 }, // 5th of may
12506 {
12507 match: "#Value of [".concat(months, "]"),
12508 group: 0,
12509 tag: 'Month',
12510 reason: '5th-of-may'
12511 }, // dick van dyke
12512 {
12513 match: '#ProperNoun (van|al|bin) #ProperNoun',
12514 tag: 'Person',
12515 reason: 'title-van-title',
12516 safe: true
12517 }, //jose de Sucre
12518 {
12519 match: '#ProperNoun (de|du) la? #ProperNoun',
12520 tag: 'Person',
12521 reason: 'title-de-title',
12522 safe: true
12523 }, //Jani K. Smith
12524 {
12525 match: '#Singular #Acronym #LastName',
12526 tag: '#Person',
12527 reason: 'title-acro-noun',
12528 safe: true
12529 }, //John Foo
12530 {
12531 match: '#FirstName (#Noun && #ProperNoun) #ProperNoun?',
12532 tag: 'Person',
12533 reason: 'firstname-titlecase'
12534 }, //Joe K. Sombrero
12535 {
12536 match: '#FirstName #Acronym #Noun',
12537 tag: 'Person',
12538 reason: 'n-acro-noun',
12539 safe: true
12540 }, //Anthony de Marco
12541 {
12542 match: '#FirstName [(de|di|du|van|von) #Person]',
12543 group: 0,
12544 tag: 'LastName',
12545 reason: 'de-firstname'
12546 }, // Paris Berelc
12547 {
12548 match: "[".concat(places, "] (#ProperNoun && !#Place)"),
12549 group: 0,
12550 tag: 'FirstName',
12551 reason: 'place-firstname'
12552 }];
12553 var _10People = list$5;
12554
12555 var matches = [];
12556 matches = matches.concat(_01Misc);
12557 matches = matches.concat(_02Dates);
12558 matches = matches.concat(_03Adjective);
12559 matches = matches.concat(_04Noun);
12560 matches = matches.concat(_05Adverb);
12561 matches = matches.concat(_06Value);
12562 matches = matches.concat(_07Verbs);
12563 matches = matches.concat(_08Place);
12564 matches = matches.concat(_09Org);
12565 matches = matches.concat(_10People); // cache the easier conditions up-front
12566
12567 var cacheRequired$1 = function cacheRequired(reg) {
12568 var needTags = [];
12569 var needWords = [];
12570 reg.forEach(function (obj) {
12571 if (obj.optional === true || obj.negative === true) {
12572 return;
12573 }
12574
12575 if (obj.tag !== undefined) {
12576 needTags.push(obj.tag);
12577 }
12578
12579 if (obj.word !== undefined) {
12580 needWords.push(obj.word);
12581 }
12582 });
12583 return {
12584 tags: _unique(needTags),
12585 words: _unique(needWords)
12586 };
12587 }; // for speed, enumerate (a|b|c) to three matches
12588
12589
12590 var allLists = function allLists(m) {
12591 var more = [];
12592 var lists = m.reg.filter(function (r) {
12593 return r.fastOr !== undefined;
12594 });
12595
12596 if (lists.length === 1) {
12597 var i = m.reg.findIndex(function (r) {
12598 return r.fastOr !== undefined;
12599 });
12600 Object.keys(m.reg[i].fastOr).forEach(function (w) {
12601 var newM = Object.assign({}, m);
12602 newM.reg = newM.reg.slice(0);
12603 newM.reg[i] = Object.assign({}, newM.reg[i]);
12604 newM.reg[i].word = w;
12605 delete newM.reg[i].operator;
12606 delete newM.reg[i].fastOr; // newM.reason += '-' + w
12607
12608 more.push(newM);
12609 });
12610 }
12611
12612 return more;
12613 }; // parse them
12614
12615
12616 var all = [];
12617 matches.forEach(function (m) {
12618 m.reg = matchSyntax(m.match);
12619 var enumerated = allLists(m);
12620
12621 if (enumerated.length > 0) {
12622 all = all.concat(enumerated);
12623 } else {
12624 all.push(m); // console.log(m)
12625 }
12626 });
12627 all.forEach(function (m) {
12628 m.required = cacheRequired$1(m.reg);
12629 return m;
12630 }); // console.log(all.length)
12631 // console.log(all[all.length - 1])
12632
12633 var matches_1 = all;
12634
12635 var hasEvery = function hasEvery(chances) {
12636 if (chances.length === 0) {
12637 return [];
12638 }
12639
12640 var obj = {};
12641 chances.forEach(function (arr) {
12642 arr = _unique(arr);
12643
12644 for (var i = 0; i < arr.length; i++) {
12645 obj[arr[i]] = obj[arr[i]] || 0;
12646 obj[arr[i]] += 1;
12647 }
12648 });
12649 var res = Object.keys(obj);
12650 res = res.filter(function (k) {
12651 return obj[k] === chances.length;
12652 });
12653 res = res.map(function (num) {
12654 return Number(num);
12655 });
12656 return res;
12657 };
12658
12659 var runner = function runner(doc) {
12660 //find phrases to try for each match
12661 matches_1.forEach(function (m) {
12662 var allChances = [];
12663 m.required.words.forEach(function (w) {
12664 allChances.push(doc._cache.words[w] || []);
12665 });
12666 m.required.tags.forEach(function (tag) {
12667 allChances.push(doc._cache.tags[tag] || []);
12668 });
12669 var worthIt = hasEvery(allChances);
12670
12671 if (worthIt.length === 0) {
12672 return;
12673 }
12674
12675 var phrases = worthIt.map(function (index) {
12676 return doc.list[index];
12677 });
12678 var tryDoc = doc.buildFrom(phrases); // phrases getting tagged
12679
12680 var match = tryDoc.match(m.reg, m.group);
12681
12682 if (match.found) {
12683 if (m.safe === true) {
12684 match.tagSafe(m.tag, m.reason);
12685 } else {
12686 match.tag(m.tag, m.reason);
12687 }
12688 }
12689 });
12690 };
12691
12692 var runner_1 = runner; // console.log(hasEvery([[1, 2, 2, 3], [2, 3], []]))
12693
12694 // misc: 40ms
12695 //sequence of match-tag statements to correct mis-tags
12696
12697 var corrections = function corrections(doc) {
12698 runner_1(doc);
12699 fixMisc(doc);
12700 return doc;
12701 };
12702
12703 var _04Correction = corrections;
12704
12705 /** POS-tag all terms in this document */
12706
12707 var tagger = function tagger(doc) {
12708 var terms = doc.termList(); // check against any known-words
12709
12710 doc = _01Init(doc, terms); // everything has gotta be something. ¯\_(:/)_/¯
12711
12712 doc = _02Fallbacks(doc, terms); // support "didn't" & "spencer's"
12713
12714 doc = _03Contractions(doc); //set our cache, to speed things up
12715
12716 doc.cache(); // wiggle-around the results, so they make more sense
12717
12718 doc = _04Correction(doc); // remove our cache, as it's invalidated now
12719
12720 doc.uncache(); // run any user-given tagger functions
12721
12722 doc.world.taggers.forEach(function (fn) {
12723 fn(doc);
12724 });
12725 return doc;
12726 };
12727
12728 var _02Tagger = tagger;
12729
12730 var addMethod = function addMethod(Doc) {
12731 /** */
12732 var Abbreviations = /*#__PURE__*/function (_Doc) {
12733 _inherits(Abbreviations, _Doc);
12734
12735 var _super = _createSuper(Abbreviations);
12736
12737 function Abbreviations() {
12738 _classCallCheck(this, Abbreviations);
12739
12740 return _super.apply(this, arguments);
12741 }
12742
12743 _createClass(Abbreviations, [{
12744 key: "stripPeriods",
12745 value: function stripPeriods() {
12746 this.termList().forEach(function (t) {
12747 if (t.tags.Abbreviation === true && t.next) {
12748 t.post = t.post.replace(/^\./, '');
12749 }
12750
12751 var str = t.text.replace(/\./, '');
12752 t.set(str);
12753 });
12754 return this;
12755 }
12756 }, {
12757 key: "addPeriods",
12758 value: function addPeriods() {
12759 this.termList().forEach(function (t) {
12760 t.post = t.post.replace(/^\./, '');
12761 t.post = '.' + t.post;
12762 });
12763 return this;
12764 }
12765 }]);
12766
12767 return Abbreviations;
12768 }(Doc);
12769
12770 Abbreviations.prototype.unwrap = Abbreviations.prototype.stripPeriods;
12771
12772 Doc.prototype.abbreviations = function (n) {
12773 var match = this.match('#Abbreviation');
12774
12775 if (typeof n === 'number') {
12776 match = match.get(n);
12777 }
12778
12779 return new Abbreviations(match.list, this, this.world);
12780 };
12781
12782 return Doc;
12783 };
12784
12785 var Abbreviations = addMethod;
12786
12787 var hasPeriod = /\./;
12788
12789 var addMethod$1 = function addMethod(Doc) {
12790 /** */
12791 var Acronyms = /*#__PURE__*/function (_Doc) {
12792 _inherits(Acronyms, _Doc);
12793
12794 var _super = _createSuper(Acronyms);
12795
12796 function Acronyms() {
12797 _classCallCheck(this, Acronyms);
12798
12799 return _super.apply(this, arguments);
12800 }
12801
12802 _createClass(Acronyms, [{
12803 key: "stripPeriods",
12804 value: function stripPeriods() {
12805 this.termList().forEach(function (t) {
12806 var str = t.text.replace(/\./g, '');
12807 t.set(str);
12808 });
12809 return this;
12810 }
12811 }, {
12812 key: "addPeriods",
12813 value: function addPeriods() {
12814 this.termList().forEach(function (t) {
12815 var str = t.text.replace(/\./g, '');
12816 str = str.split('').join('.'); // don't add a end-period if there's a sentence-end one
12817
12818 if (hasPeriod.test(t.post) === false) {
12819 str += '.';
12820 }
12821
12822 t.set(str);
12823 });
12824 return this;
12825 }
12826 }]);
12827
12828 return Acronyms;
12829 }(Doc);
12830
12831 Acronyms.prototype.unwrap = Acronyms.prototype.stripPeriods;
12832 Acronyms.prototype.strip = Acronyms.prototype.stripPeriods;
12833
12834 Doc.prototype.acronyms = function (n) {
12835 var match = this.match('#Acronym');
12836
12837 if (typeof n === 'number') {
12838 match = match.get(n);
12839 }
12840
12841 return new Acronyms(match.list, this, this.world);
12842 };
12843
12844 return Doc;
12845 };
12846
12847 var Acronyms = addMethod$1;
12848
12849 var addMethod$2 = function addMethod(Doc) {
12850 /** split into approximate sub-sentence phrases */
12851 Doc.prototype.clauses = function (n) {
12852 // an awkward way to disambiguate a comma use
12853 var commas = this["if"]('@hasComma').notIf('@hasComma @hasComma') //fun, cool...
12854 .notIf('@hasComma . .? (and|or) .') //cool, and fun
12855 .notIf('(#City && @hasComma) #Country') //'toronto, canada'
12856 .notIf('(#WeekDay && @hasComma) #Date') //'tuesday, march 2nd'
12857 .notIf('(#Date && @hasComma) #Year') //'july 6, 1992'
12858 .notIf('@hasComma (too|also)$') //at end of sentence
12859 .match('@hasComma');
12860 var found = this.splitAfter(commas);
12861 var quotes = found.quotations();
12862 found = found.splitOn(quotes);
12863 var parentheses = found.parentheses();
12864 found = found.splitOn(parentheses); // it is cool and it is ..
12865
12866 var conjunctions = found["if"]('#Copula #Adjective #Conjunction (#Pronoun|#Determiner) #Verb').match('#Conjunction');
12867 found = found.splitBefore(conjunctions); // if it is this then that
12868
12869 var condition = found["if"]('if .{2,9} then .').match('then');
12870 found = found.splitBefore(condition); // misc clause partitions
12871
12872 found = found.splitBefore('as well as .');
12873 found = found.splitBefore('such as .');
12874 found = found.splitBefore('in addition to .'); // semicolons, dashes
12875
12876 found = found.splitAfter('@hasSemicolon');
12877 found = found.splitAfter('@hasDash'); // passive voice verb - '.. which was robbed is empty'
12878 // let passive = found.match('#Noun (which|that) (was|is) #Adverb? #PastTense #Adverb?')
12879 // if (passive.found) {
12880 // found = found.splitAfter(passive)
12881 // }
12882 // //which the boy robbed
12883 // passive = found.match('#Noun (which|that) the? #Noun+ #Adverb? #PastTense #Adverb?')
12884 // if (passive.found) {
12885 // found = found.splitAfter(passive)
12886 // }
12887 // does there appear to have relative/subordinate clause still?
12888
12889 var tooLong = found.filter(function (d) {
12890 return d.wordCount() > 5 && d.match('#Verb+').length >= 2;
12891 });
12892
12893 if (tooLong.found) {
12894 var m = tooLong.splitAfter('#Noun .* #Verb .* #Noun+');
12895 found = found.splitOn(m.eq(0));
12896 }
12897
12898 if (typeof n === 'number') {
12899 found = found.get(n);
12900 }
12901
12902 return new Doc(found.list, this, this.world);
12903 };
12904
12905 return Doc;
12906 };
12907
12908 var Clauses = addMethod$2;
12909
12910 var addMethod$3 = function addMethod(Doc) {
12911 /** */
12912 var Contractions = /*#__PURE__*/function (_Doc) {
12913 _inherits(Contractions, _Doc);
12914
12915 var _super = _createSuper(Contractions);
12916
12917 function Contractions(list, from, world) {
12918 var _this;
12919
12920 _classCallCheck(this, Contractions);
12921
12922 _this = _super.call(this, list, from, world);
12923 _this.contracted = null;
12924 return _this;
12925 }
12926 /** turn didn't into 'did not' */
12927
12928
12929 _createClass(Contractions, [{
12930 key: "expand",
12931 value: function expand() {
12932 this.list.forEach(function (p) {
12933 var terms = p.terms(); //change the case?
12934
12935 var isTitlecase = terms[0].isTitleCase();
12936 terms.forEach(function (t, i) {
12937 //use the implicit text
12938 t.set(t.implicit || t.text);
12939 t.implicit = undefined; //add whitespace
12940
12941 if (i < terms.length - 1 && t.post === '') {
12942 t.post += ' ';
12943 }
12944 }); //set titlecase
12945
12946 if (isTitlecase) {
12947 terms[0].toTitleCase();
12948 }
12949 });
12950 return this;
12951 }
12952 }]);
12953
12954 return Contractions;
12955 }(Doc); //find contractable, expanded-contractions
12956 // const findExpanded = r => {
12957 // let remain = r.not('#Contraction')
12958 // let m = remain.match('(#Noun|#QuestionWord) (#Copula|did|do|have|had|could|would|will)')
12959 // m.concat(remain.match('(they|we|you|i) have'))
12960 // m.concat(remain.match('i am'))
12961 // m.concat(remain.match('(#Copula|#Modal|do|does|have|has|can|will) not'))
12962 // return m
12963 // }
12964
12965
12966 Doc.prototype.contractions = function (n) {
12967 //find currently-contracted
12968 var found = this.match('@hasContraction+'); //(may want to split these up)
12969 //todo: split consecutive contractions
12970
12971 if (typeof n === 'number') {
12972 found = found.get(n);
12973 }
12974
12975 return new Contractions(found.list, this, this.world);
12976 }; //aliases
12977
12978
12979 Doc.prototype.expanded = Doc.prototype.isExpanded;
12980 Doc.prototype.contracted = Doc.prototype.isContracted;
12981 return Doc;
12982 };
12983
12984 var Contractions = addMethod$3;
12985
12986 var addMethod$4 = function addMethod(Doc) {
12987 //pull it apart..
12988 var parse = function parse(doc) {
12989 var things = doc.splitAfter('@hasComma').splitOn('(and|or) not?').not('(and|or) not?');
12990 var beforeLast = doc.match('[.] (and|or)', 0);
12991 return {
12992 things: things,
12993 conjunction: doc.match('(and|or) not?'),
12994 beforeLast: beforeLast,
12995 hasOxford: beforeLast.has('@hasComma')
12996 };
12997 };
12998 /** cool, fun, and nice */
12999
13000
13001 var Lists = /*#__PURE__*/function (_Doc) {
13002 _inherits(Lists, _Doc);
13003
13004 var _super = _createSuper(Lists);
13005
13006 function Lists() {
13007 _classCallCheck(this, Lists);
13008
13009 return _super.apply(this, arguments);
13010 }
13011
13012 _createClass(Lists, [{
13013 key: "conjunctions",
13014
13015 /** coordinating conjunction */
13016 value: function conjunctions() {
13017 return this.match('(and|or)');
13018 }
13019 /** split-up by list object */
13020
13021 }, {
13022 key: "parts",
13023 value: function parts() {
13024 return this.splitAfter('@hasComma').splitOn('(and|or) not?');
13025 }
13026 /** remove the conjunction */
13027
13028 }, {
13029 key: "items",
13030 value: function items() {
13031 return parse(this).things;
13032 }
13033 /** add a new unit to the list */
13034
13035 }, {
13036 key: "add",
13037 value: function add(str) {
13038 this.forEach(function (p) {
13039 var beforeLast = parse(p).beforeLast;
13040 beforeLast.append(str); //add a comma to it
13041
13042 beforeLast.termList(0).addPunctuation(',');
13043 });
13044 return this;
13045 }
13046 /** remove any matching unit from the list */
13047
13048 }, {
13049 key: "remove",
13050 value: function remove(match) {
13051 return this.items()["if"](match).remove();
13052 }
13053 /** return only lists that use a serial comma */
13054
13055 }, {
13056 key: "hasOxfordComma",
13057 value: function hasOxfordComma() {
13058 return this.filter(function (doc) {
13059 return parse(doc).hasOxford;
13060 });
13061 }
13062 }, {
13063 key: "addOxfordComma",
13064 value: function addOxfordComma() {
13065 var items = this.items();
13066 var needsComma = items.eq(items.length - 2);
13067
13068 if (needsComma.found && needsComma.has('@hasComma') === false) {
13069 needsComma.post(', ');
13070 }
13071
13072 return this;
13073 }
13074 }, {
13075 key: "removeOxfordComma",
13076 value: function removeOxfordComma() {
13077 var items = this.items();
13078 var needsComma = items.eq(items.length - 2);
13079
13080 if (needsComma.found && needsComma.has('@hasComma') === true) {
13081 needsComma.post(' ');
13082 }
13083
13084 return this;
13085 }
13086 }]);
13087
13088 return Lists;
13089 }(Doc); // aliases
13090
13091
13092 Lists.prototype.things = Lists.prototype.items;
13093
13094 Doc.prototype.lists = function (n) {
13095 var m = this["if"]('@hasComma+ .? (and|or) not? .'); // person-list
13096
13097 var nounList = m.match('(#Noun|#Adjective|#Determiner|#Article)+ #Conjunction not? (#Article|#Determiner)? #Adjective? #Noun+')["if"]('#Noun');
13098 var adjList = m.match('(#Adjective|#Adverb)+ #Conjunction not? #Adverb? #Adjective+');
13099 var verbList = m.match('(#Verb|#Adverb)+ #Conjunction not? #Adverb? #Verb+');
13100 var result = nounList.concat(adjList);
13101 result = result.concat(verbList);
13102 result = result["if"]('@hasComma');
13103
13104 if (typeof n === 'number') {
13105 result = m.get(n);
13106 }
13107
13108 return new Lists(result.list, this, this.world);
13109 };
13110
13111 return Doc;
13112 };
13113
13114 var Lists = addMethod$4;
13115
13116 var noPlural = '(#Pronoun|#Place|#Value|#Person|#Uncountable|#Month|#WeekDay|#Holiday|#Possessive)'; //certain words can't be plural, like 'peace'
13117
13118 var hasPlural = function hasPlural(doc) {
13119 if (doc.has('#Plural') === true) {
13120 return true;
13121 } // these can't be plural
13122
13123
13124 if (doc.has(noPlural) === true) {
13125 return false;
13126 }
13127
13128 return true;
13129 };
13130
13131 var hasPlural_1 = hasPlural;
13132
13133 var irregulars$5 = {
13134 hour: 'an',
13135 heir: 'an',
13136 heirloom: 'an',
13137 honest: 'an',
13138 honour: 'an',
13139 honor: 'an',
13140 uber: 'an' //german u
13141
13142 }; //pronounced letters of acronyms that get a 'an'
13143
13144 var an_acronyms = {
13145 a: true,
13146 e: true,
13147 f: true,
13148 h: true,
13149 i: true,
13150 l: true,
13151 m: true,
13152 n: true,
13153 o: true,
13154 r: true,
13155 s: true,
13156 x: true
13157 }; //'a' regexes
13158
13159 var a_regexs = [/^onc?e/i, //'wu' sound of 'o'
13160 /^u[bcfhjkqrstn][aeiou]/i, // 'yu' sound for hard 'u'
13161 /^eul/i];
13162
13163 var makeArticle = function makeArticle(doc) {
13164 //no 'the john smith', but 'a london hotel'
13165 if (doc.has('#Person') || doc.has('#Place')) {
13166 return '';
13167 } //no a/an if it's plural
13168
13169
13170 if (doc.has('#Plural')) {
13171 return 'the';
13172 }
13173
13174 var str = doc.text('normal').trim(); //explicit irregular forms
13175
13176 if (irregulars$5.hasOwnProperty(str)) {
13177 return irregulars$5[str];
13178 } //spelled-out acronyms
13179
13180
13181 var firstLetter = str.substr(0, 1);
13182
13183 if (doc.has('^@isAcronym') && an_acronyms.hasOwnProperty(firstLetter)) {
13184 return 'an';
13185 } //'a' regexes
13186
13187
13188 for (var i = 0; i < a_regexs.length; i++) {
13189 if (a_regexs[i].test(str)) {
13190 return 'a';
13191 }
13192 } //basic vowel-startings
13193
13194
13195 if (/^[aeiou]/i.test(str)) {
13196 return 'an';
13197 }
13198
13199 return 'a';
13200 };
13201
13202 var getArticle = makeArticle;
13203
13204 //similar to plural/singularize rules, but not the same
13205 var 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
13206
13207 var 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];
13208 var _rules$2 = {
13209 isSingular: isSingular$1,
13210 isPlural: isPlural$1
13211 };
13212
13213 var endS = /s$/; // double-check this term, if it is not plural, or singular.
13214 // (this is a partial copy of ./tagger/fallbacks/plural)
13215 // fallback plural if it ends in an 's'.
13216
13217 var isPlural$2 = function isPlural(str) {
13218 // isSingular suffix rules
13219 if (_rules$2.isSingular.find(function (reg) {
13220 return reg.test(str);
13221 })) {
13222 return false;
13223 } // does it end in an s?
13224
13225
13226 if (endS.test(str) === true) {
13227 return true;
13228 } // is it a plural like 'fungi'?
13229
13230
13231 if (_rules$2.isPlural.find(function (reg) {
13232 return reg.test(str);
13233 })) {
13234 return true;
13235 }
13236
13237 return null;
13238 };
13239
13240 var isPlural_1$1 = isPlural$2;
13241
13242 var exceptions = {
13243 he: 'his',
13244 she: 'hers',
13245 they: 'theirs',
13246 we: 'ours',
13247 i: 'mine',
13248 you: 'yours',
13249 her: 'hers',
13250 their: 'theirs',
13251 our: 'ours',
13252 my: 'mine',
13253 your: 'yours'
13254 }; // turn "David" to "David's"
13255
13256 var toPossessive = function toPossessive(doc) {
13257 var str = doc.text('text').trim(); // exceptions
13258
13259 if (exceptions.hasOwnProperty(str)) {
13260 doc.replaceWith(exceptions[str], true);
13261 doc.tag('Possessive', 'toPossessive');
13262 return;
13263 } // flanders'
13264
13265
13266 if (/s$/.test(str)) {
13267 str += "'";
13268 doc.replaceWith(str, true);
13269 doc.tag('Possessive', 'toPossessive');
13270 return;
13271 } //normal form:
13272
13273
13274 str += "'s";
13275 doc.replaceWith(str, true);
13276 doc.tag('Possessive', 'toPossessive');
13277 return;
13278 };
13279
13280 var toPossessive_1 = toPossessive;
13281
13282 // .nouns() supports some noun-phrase-ish groupings
13283 // pull these apart, if necessary
13284 var parse$1 = function parse(doc) {
13285 var res = {
13286 main: doc
13287 }; //support 'mayor of chicago' as one noun-phrase
13288
13289 if (doc.has('#Noun (of|by|for) .')) {
13290 var m = doc.splitAfter('[#Noun+]', 0);
13291 res.main = m.eq(0);
13292 res.post = m.eq(1);
13293 }
13294
13295 return res;
13296 };
13297
13298 var parse_1 = parse$1;
13299
13300 var methods$6 = {
13301 /** overload the original json with noun information */
13302 json: function json(options) {
13303 var n = null;
13304
13305 if (typeof options === 'number') {
13306 n = options;
13307 options = null;
13308 }
13309
13310 options = options || {
13311 text: true,
13312 normal: true,
13313 trim: true,
13314 terms: true
13315 };
13316 var res = [];
13317 this.forEach(function (doc) {
13318 var json = doc.json(options)[0];
13319 json.article = getArticle(doc);
13320 res.push(json);
13321 });
13322
13323 if (n !== null) {
13324 return res[n];
13325 }
13326
13327 return res;
13328 },
13329
13330 /** get all adjectives describing this noun*/
13331 adjectives: function adjectives() {
13332 var list = this.lookAhead('^(that|who|which)? (was|is|will)? be? #Adverb? #Adjective+');
13333 list = list.concat(this.lookBehind('#Adjective+ #Adverb?$'));
13334 list = list.match('#Adjective');
13335 return list.sort('index');
13336 },
13337 isPlural: function isPlural() {
13338 return this["if"]('#Plural'); //assume tagger has run?
13339 },
13340 hasPlural: function hasPlural() {
13341 return this.filter(function (d) {
13342 return hasPlural_1(d);
13343 });
13344 },
13345 toPlural: function toPlural(agree) {
13346 var _this = this;
13347
13348 var toPlural = this.world.transforms.toPlural;
13349 this.forEach(function (doc) {
13350 if (doc.has('#Plural') || hasPlural_1(doc) === false) {
13351 return;
13352 } // double-check it isn't an un-tagged plural
13353
13354
13355 var main = parse_1(doc).main;
13356 var str = main.text('reduced');
13357
13358 if (!main.has('#Singular') && isPlural_1$1(str) === true) {
13359 return;
13360 }
13361
13362 str = toPlural(str, _this.world);
13363 main.replace(str).tag('#Plural'); // 'an apple' -> 'apples'
13364
13365 if (agree) {
13366 var an = main.lookBefore('(an|a) #Adjective?$').not('#Adjective');
13367
13368 if (an.found === true) {
13369 an.remove();
13370 }
13371 }
13372 });
13373 return this;
13374 },
13375 toSingular: function toSingular(agree) {
13376 var _this2 = this;
13377
13378 var toSingular = this.world.transforms.toSingular;
13379 this.forEach(function (doc) {
13380 if (doc.has('^#Singular+$') || hasPlural_1(doc) === false) {
13381 return;
13382 } // double-check it isn't an un-tagged plural
13383
13384
13385 var main = parse_1(doc).main;
13386 var str = main.text('reduced');
13387
13388 if (!main.has('#Plural') && isPlural_1$1(str) !== true) {
13389 return;
13390 }
13391
13392 str = toSingular(str, _this2.world);
13393 main.replace(str).tag('#Singular'); // add an article
13394
13395 if (agree) {
13396 // 'apples' -> 'an apple'
13397 var start = doc;
13398 var adj = doc.lookBefore('#Adjective');
13399
13400 if (adj.found) {
13401 start = adj;
13402 }
13403
13404 var article = getArticle(start);
13405 start.insertBefore(article);
13406 }
13407 });
13408 return this;
13409 },
13410 toPossessive: function toPossessive() {
13411 this.forEach(function (d) {
13412 toPossessive_1(d);
13413 });
13414 return this;
13415 }
13416 };
13417 var methods_1 = methods$6;
13418
13419 var addMethod$5 = function addMethod(Doc) {
13420 /** */
13421 var Nouns = /*#__PURE__*/function (_Doc) {
13422 _inherits(Nouns, _Doc);
13423
13424 var _super = _createSuper(Nouns);
13425
13426 function Nouns() {
13427 _classCallCheck(this, Nouns);
13428
13429 return _super.apply(this, arguments);
13430 }
13431
13432 return Nouns;
13433 }(Doc); // add-in our methods
13434
13435
13436 Object.assign(Nouns.prototype, methods_1);
13437
13438 Doc.prototype.nouns = function (n) {
13439 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
13440 // don't split 'paris, france'
13441 var keep = this.match('(#City && @hasComma) (#Region|#Country)'); // but split the other commas
13442
13443 var m = this.not(keep).splitAfter('@hasComma'); // combine them back together
13444
13445 m = m.concat(keep); // don't combine over scare-quotes
13446
13447 var quotes = m.quotations();
13448
13449 if (quotes.found) {
13450 m = m.splitOn(quotes.eq(0));
13451 }
13452
13453 m = m.match('#Noun+ (of|by)? the? #Noun+?'); //nouns that we don't want in these results, for weird reasons
13454
13455 if (opts.keep_anaphora !== true) {
13456 m = m.not('#Pronoun');
13457 m = m.not('(there|these)');
13458 m = m.not('(#Month|#WeekDay)'); //allow Durations, Holidays
13459 // //allow possessives like "spencer's", but not generic ones like,
13460
13461 m = m.not('(my|our|your|their|her|his)');
13462 }
13463
13464 m = m.not('(of|for|by|the)$');
13465
13466 if (typeof n === 'number') {
13467 m = m.get(n);
13468 }
13469
13470 return new Nouns(m.list, this, this.world);
13471 };
13472
13473 return Doc;
13474 };
13475
13476 var Nouns = addMethod$5;
13477
13478 var open = /\(/;
13479 var close = /\)/;
13480
13481 var addMethod$6 = function addMethod(Doc) {
13482 /** anything between (these things) */
13483 var Parentheses = /*#__PURE__*/function (_Doc) {
13484 _inherits(Parentheses, _Doc);
13485
13486 var _super = _createSuper(Parentheses);
13487
13488 function Parentheses() {
13489 _classCallCheck(this, Parentheses);
13490
13491 return _super.apply(this, arguments);
13492 }
13493
13494 _createClass(Parentheses, [{
13495 key: "unwrap",
13496
13497 /** remove the parentheses characters */
13498 value: function unwrap() {
13499 this.list.forEach(function (p) {
13500 var first = p.terms(0);
13501 first.pre = first.pre.replace(open, '');
13502 var last = p.lastTerm();
13503 last.post = last.post.replace(close, '');
13504 });
13505 return this;
13506 }
13507 }]);
13508
13509 return Parentheses;
13510 }(Doc);
13511
13512 Doc.prototype.parentheses = function (n) {
13513 var list = [];
13514 this.list.forEach(function (p) {
13515 var terms = p.terms(); //look for opening brackets
13516
13517 for (var i = 0; i < terms.length; i += 1) {
13518 var t = terms[i];
13519
13520 if (open.test(t.pre)) {
13521 //look for the closing bracket..
13522 for (var o = i; o < terms.length; o += 1) {
13523 if (close.test(terms[o].post)) {
13524 var len = o - i + 1;
13525 list.push(p.buildFrom(t.id, len));
13526 i = o;
13527 break;
13528 }
13529 }
13530 }
13531 }
13532 }); //support nth result
13533
13534 if (typeof n === 'number') {
13535 if (list[n]) {
13536 list = [list[n]];
13537 } else {
13538 list = [];
13539 }
13540
13541 return new Parentheses(list, this, this.world);
13542 }
13543
13544 return new Parentheses(list, this, this.world);
13545 };
13546
13547 return Doc;
13548 };
13549
13550 var Parentheses = addMethod$6;
13551
13552 var addMethod$7 = function addMethod(Doc) {
13553 /** */
13554 var Possessives = /*#__PURE__*/function (_Doc) {
13555 _inherits(Possessives, _Doc);
13556
13557 var _super = _createSuper(Possessives);
13558
13559 function Possessives(list, from, world) {
13560 var _this;
13561
13562 _classCallCheck(this, Possessives);
13563
13564 _this = _super.call(this, list, from, world);
13565 _this.contracted = null;
13566 return _this;
13567 }
13568 /** turn didn't into 'did not' */
13569
13570
13571 _createClass(Possessives, [{
13572 key: "strip",
13573 value: function strip() {
13574 this.list.forEach(function (p) {
13575 var terms = p.terms();
13576 terms.forEach(function (t) {
13577 var str = t.text.replace(/'s$/, '');
13578 t.set(str || t.text);
13579 });
13580 });
13581 return this;
13582 }
13583 }]);
13584
13585 return Possessives;
13586 }(Doc); //find contractable, expanded-contractions
13587 // const findExpanded = r => {
13588 // let remain = r.not('#Contraction')
13589 // let m = remain.match('(#Noun|#QuestionWord) (#Copula|did|do|have|had|could|would|will)')
13590 // m.concat(remain.match('(they|we|you|i) have'))
13591 // m.concat(remain.match('i am'))
13592 // m.concat(remain.match('(#Copula|#Modal|do|does|have|has|can|will) not'))
13593 // return m
13594 // }
13595
13596
13597 Doc.prototype.possessives = function (n) {
13598 //find currently-contracted
13599 var found = this.match('#Noun+? #Possessive'); //todo: split consecutive contractions
13600
13601 if (typeof n === 'number') {
13602 found = found.get(n);
13603 }
13604
13605 return new Possessives(found.list, this, this.world);
13606 };
13607
13608 return Doc;
13609 };
13610
13611 var Possessives = addMethod$7;
13612
13613 var pairs = {
13614 "\"": "\"",
13615 // 'StraightDoubleQuotes'
13616 "\uFF02": "\uFF02",
13617 // 'StraightDoubleQuotesWide'
13618 "'": "'",
13619 // 'StraightSingleQuotes'
13620 "\u201C": "\u201D",
13621 // 'CommaDoubleQuotes'
13622 "\u2018": "\u2019",
13623 // 'CommaSingleQuotes'
13624 "\u201F": "\u201D",
13625 // 'CurlyDoubleQuotesReversed'
13626 "\u201B": "\u2019",
13627 // 'CurlySingleQuotesReversed'
13628 "\u201E": "\u201D",
13629 // 'LowCurlyDoubleQuotes'
13630 "\u2E42": "\u201D",
13631 // 'LowCurlyDoubleQuotesReversed'
13632 "\u201A": "\u2019",
13633 // 'LowCurlySingleQuotes'
13634 "\xAB": "\xBB",
13635 // 'AngleDoubleQuotes'
13636 "\u2039": "\u203A",
13637 // 'AngleSingleQuotes'
13638 // Prime 'non quotation'
13639 "\u2035": "\u2032",
13640 // 'PrimeSingleQuotes'
13641 "\u2036": "\u2033",
13642 // 'PrimeDoubleQuotes'
13643 "\u2037": "\u2034",
13644 // 'PrimeTripleQuotes'
13645 // Prime 'quotation' variation
13646 "\u301D": "\u301E",
13647 // 'PrimeDoubleQuotes'
13648 "`": "\xB4",
13649 // 'PrimeSingleQuotes'
13650 "\u301F": "\u301E" // 'LowPrimeDoubleQuotesReversed'
13651
13652 };
13653 var hasOpen = RegExp('(' + Object.keys(pairs).join('|') + ')');
13654
13655 var addMethod$8 = function addMethod(Doc) {
13656 /** "these things" */
13657 var Quotations = /*#__PURE__*/function (_Doc) {
13658 _inherits(Quotations, _Doc);
13659
13660 var _super = _createSuper(Quotations);
13661
13662 function Quotations() {
13663 _classCallCheck(this, Quotations);
13664
13665 return _super.apply(this, arguments);
13666 }
13667
13668 _createClass(Quotations, [{
13669 key: "unwrap",
13670
13671 /** remove the quote characters */
13672 value: function unwrap() {
13673 return this;
13674 }
13675 }]);
13676
13677 return Quotations;
13678 }(Doc);
13679
13680 Doc.prototype.quotations = function (n) {
13681 var list = [];
13682 this.list.forEach(function (p) {
13683 var terms = p.terms(); //look for opening quotes
13684
13685 for (var i = 0; i < terms.length; i += 1) {
13686 var t = terms[i];
13687
13688 if (hasOpen.test(t.pre)) {
13689 var _char = (t.pre.match(hasOpen) || [])[0];
13690 var want = pairs[_char]; // if (!want) {
13691 // console.warn('missing quote char ' + char)
13692 // }
13693 //look for the closing bracket..
13694
13695 for (var o = i; o < terms.length; o += 1) {
13696 if (terms[o].post.indexOf(want) !== -1) {
13697 var len = o - i + 1;
13698 list.push(p.buildFrom(t.id, len));
13699 i = o;
13700 break;
13701 }
13702 }
13703 }
13704 }
13705 }); //support nth result
13706
13707 if (typeof n === 'number') {
13708 if (list[n]) {
13709 list = [list[n]];
13710 } else {
13711 list = [];
13712 }
13713
13714 return new Quotations(list, this, this.world);
13715 }
13716
13717 return new Quotations(list, this, this.world);
13718 }; // alias
13719
13720
13721 Doc.prototype.quotes = Doc.prototype.quotations;
13722 return Doc;
13723 };
13724
13725 var Quotations = addMethod$8;
13726
13727 // walked => walk - turn a verb into it's root form
13728 var toInfinitive$1 = function toInfinitive(parsed, world) {
13729 var verb = parsed.verb; // console.log(parsed)
13730 // verb.debug()
13731 //1. if it's already infinitive
13732
13733 var str = verb.text('reduced');
13734
13735 if (verb.has('#Infinitive')) {
13736 return str;
13737 } // 2. world transform does the heavy-lifting
13738
13739
13740 var tense = null;
13741
13742 if (verb.has('#PastTense')) {
13743 tense = 'PastTense';
13744 } else if (verb.has('#Gerund')) {
13745 tense = 'Gerund';
13746 } else if (verb.has('#PresentTense')) {
13747 tense = 'PresentTense';
13748 } else if (verb.has('#Participle')) {
13749 tense = 'Participle';
13750 } else if (verb.has('#Actor')) {
13751 tense = 'Actor';
13752 }
13753
13754 return world.transforms.toInfinitive(str, world, tense);
13755 };
13756
13757 var toInfinitive_1$1 = toInfinitive$1;
13758
13759 // spencer walks -> singular
13760 // we walk -> plural
13761 // the most-recent noun-phrase, before this verb.
13762 var findNoun = function findNoun(vb) {
13763 var noun = vb.lookBehind('#Noun+').last();
13764 return noun;
13765 }; //sometimes you can tell if a verb is plural/singular, just by the verb
13766 // i am / we were
13767 // othertimes you need its subject 'we walk' vs 'i walk'
13768
13769
13770 var isPlural$3 = function isPlural(parsed) {
13771 var vb = parsed.verb;
13772
13773 if (vb.has('(are|were|does)') || parsed.auxiliary.has('(are|were|does)')) {
13774 return true;
13775 }
13776
13777 if (vb.has('(is|am|do|was)') || parsed.auxiliary.has('(is|am|do|was)')) {
13778 return false;
13779 } //consider its prior noun
13780
13781
13782 var noun = findNoun(vb);
13783
13784 if (noun.has('(we|they|you)')) {
13785 return true;
13786 }
13787
13788 if (noun.has('#Plural')) {
13789 return true;
13790 }
13791
13792 if (noun.has('#Singular')) {
13793 return false;
13794 }
13795
13796 return null;
13797 };
13798
13799 var isPlural_1$2 = isPlural$3;
13800
13801 // #Copula : is -> 'is not'
13802 // #PastTense : walked -> did not walk
13803 // #PresentTense : walks -> does not walk
13804 // #Gerund : walking: -> not walking
13805 // #Infinitive : walk -> do not walk
13806
13807 var toNegative = function toNegative(parsed, world) {
13808 var vb = parsed.verb; // if it's already negative...
13809
13810 if (parsed.negative.found) {
13811 return;
13812 } // would walk -> would not walk
13813
13814
13815 if (parsed.auxiliary.found) {
13816 parsed.auxiliary.eq(0).append('not'); // 'would not have' ➔ 'would not have'
13817
13818 if (parsed.auxiliary.has('#Modal have not')) {
13819 parsed.auxiliary.replace('have not', 'not have');
13820 }
13821
13822 return;
13823 } // is walking -> is not walking
13824
13825
13826 if (vb.has('(#Copula|will|has|had|do)')) {
13827 vb.append('not');
13828 return;
13829 } // walked -> did not walk
13830
13831
13832 if (vb.has('#PastTense')) {
13833 var inf = toInfinitive_1$1(parsed, world);
13834 vb.replaceWith(inf, true);
13835 vb.prepend('did not');
13836 return;
13837 } // walks -> does not walk
13838
13839
13840 if (vb.has('#PresentTense')) {
13841 var _inf = toInfinitive_1$1(parsed, world);
13842
13843 vb.replaceWith(_inf, true);
13844
13845 if (isPlural_1$2(parsed)) {
13846 vb.prepend('do not');
13847 } else {
13848 vb.prepend('does not');
13849 }
13850
13851 return;
13852 } //walking -> not walking
13853
13854
13855 if (vb.has('#Gerund')) {
13856 var _inf2 = toInfinitive_1$1(parsed, world);
13857
13858 vb.replaceWith(_inf2, true);
13859 vb.prepend('not');
13860 return;
13861 } //fallback 1: walk -> does not walk
13862
13863
13864 if (isPlural_1$2(parsed)) {
13865 vb.prepend('does not');
13866 return;
13867 } //fallback 2: walk -> do not walk
13868
13869
13870 vb.prepend('do not');
13871 return;
13872 };
13873
13874 var toNegative_1 = toNegative;
13875
13876 // who/what is doing this verb?
13877 // get the prior verb most-likely doing this action
13878 // (it can not-exist - 'close the door')
13879 var getSubject = function getSubject(vb) {
13880 var behind = vb.lookBehind();
13881 var lastNoun = behind.nouns(null, {
13882 keep_anaphora: true
13883 }).last(); // support 'that' and 'this'
13884
13885 if (!lastNoun.found) {
13886 lastNoun = behind.match('(that|this|each)').last();
13887 lastNoun = lastNoun.tag('#Noun').nouns();
13888 }
13889
13890 return lastNoun;
13891 };
13892
13893 var getSubject_1 = getSubject;
13894
13895 var parseVerb = function parseVerb(vb) {
13896 var parsed = {
13897 adverb: vb.match('#Adverb+'),
13898 // 'really'
13899 negative: vb.match('#Negative'),
13900 // 'not'
13901 auxiliary: vb.match('#Auxiliary+').not('(#Negative|#Adverb)'),
13902 // 'will' of 'will go'
13903 particle: vb.match('#Particle'),
13904 // 'up' of 'pull up'
13905 verb: vb.match('#Verb+').not('(#Adverb|#Negative|#Auxiliary|#Particle)'),
13906 original: vb,
13907 subject: getSubject_1(vb)
13908 }; // fallback, if no verb found
13909
13910 if (!parsed.verb.found) {
13911 // blank-everything
13912 Object.keys(parsed).forEach(function (k) {
13913 parsed[k] = parsed[k].not('.');
13914 }); // it's all the verb
13915
13916 parsed.verb = vb;
13917 return parsed;
13918 } //
13919
13920
13921 if (parsed.adverb && parsed.adverb.found) {
13922 var match = parsed.adverb.text('reduced') + '$';
13923
13924 if (vb.has(match)) {
13925 parsed.adverbAfter = true;
13926 }
13927 }
13928
13929 return parsed;
13930 };
13931
13932 var parse$2 = parseVerb;
13933
13934 /** too many special cases for is/was/will be*/
13935
13936 var toBe = function toBe(parsed) {
13937 var isI = false;
13938 var plural = isPlural_1$2(parsed);
13939 var isNegative = parsed.negative.found; //account for 'i is' -> 'i am' irregular
13940 // if (vb.parent && vb.parent.has('i #Adverb? #Copula')) {
13941 // isI = true;
13942 // }
13943 // 'i look', not 'i looks'
13944
13945 if (parsed.verb.lookBehind('(i|we) (#Adverb|#Verb)?$').found) {
13946 isI = true;
13947 }
13948
13949 var obj = {
13950 PastTense: 'was',
13951 PresentTense: 'is',
13952 FutureTense: 'will be',
13953 Infinitive: 'is',
13954 Gerund: 'being',
13955 Actor: '',
13956 PerfectTense: 'been',
13957 Pluperfect: 'been'
13958 }; //"i is" -> "i am"
13959
13960 if (isI === true) {
13961 obj.PresentTense = 'am';
13962 obj.Infinitive = 'am';
13963 }
13964
13965 if (plural) {
13966 obj.PastTense = 'were';
13967 obj.PresentTense = 'are';
13968 obj.Infinitive = 'are';
13969 }
13970
13971 if (isNegative) {
13972 obj.PastTense += ' not';
13973 obj.PresentTense += ' not';
13974 obj.FutureTense = 'will not be';
13975 obj.Infinitive += ' not';
13976 obj.PerfectTense = 'not ' + obj.PerfectTense;
13977 obj.Pluperfect = 'not ' + obj.Pluperfect;
13978 obj.Gerund = 'not ' + obj.Gerund;
13979 }
13980
13981 return obj;
13982 };
13983
13984 var toBe_1 = toBe;
13985
13986 // 'may/could/should' -> 'may/could/should have'
13987 var doModal = function doModal(parsed) {
13988 var str = parsed.verb.text();
13989 var res = {
13990 PastTense: str + ' have',
13991 PresentTense: str,
13992 FutureTense: str,
13993 Infinitive: str // Gerund: ,
13994 // Actor: '',
13995 // PerfectTense: '',
13996 // Pluperfect: '',
13997
13998 };
13999 return res;
14000 };
14001
14002 var doModal_1 = doModal;
14003
14004 var conjugate$2 = function conjugate(parsed, world) {
14005 var verb = parsed.verb; //special handling of 'is', 'will be', etc.
14006
14007 if (verb.has('#Copula') || verb.out('normal') === 'be' && parsed.auxiliary.has('will')) {
14008 return toBe_1(parsed);
14009 } // special handling of 'are walking'
14010
14011
14012 if (parsed.auxiliary.has('are') && verb.has('#Gerund')) {
14013 var og = parsed.original.clone();
14014 var past = og.clone().replace('are', 'were');
14015 var fut = og.clone().replace('are', 'will be');
14016
14017 var _infinitive = toInfinitive_1$1(parsed, world);
14018
14019 var res = {
14020 PastTense: past.text(),
14021 PresentTense: og.text(),
14022 FutureTense: fut.text(),
14023 Infinitive: _infinitive
14024 };
14025 return res;
14026 } // special handling of 'he could.'
14027
14028
14029 if (verb.has('#Modal')) {
14030 return doModal_1(parsed);
14031 } // dont conjugate imperative form - 'close the door'
14032 // if (parsed.auxiliary.has('do')) {
14033 // let str = parsed.original.text()
14034 // let res = {
14035 // PastTense: str,
14036 // PresentTense: str,
14037 // FutureTense: str,
14038 // Infinitive: str,
14039 // }
14040 // return res
14041 // }
14042
14043
14044 var hasHyphen = parsed.verb.termList(0).hasHyphen();
14045 var infinitive = toInfinitive_1$1(parsed, world);
14046
14047 if (!infinitive) {
14048 return {};
14049 }
14050
14051 var forms = world.transforms.conjugate(infinitive, world);
14052 forms.Infinitive = infinitive; // add particle to phrasal verbs ('fall over')
14053
14054 if (parsed.particle.found) {
14055 var particle = parsed.particle.text();
14056 var space = hasHyphen === true ? '-' : ' ';
14057 Object.keys(forms).forEach(function (k) {
14058 return forms[k] += space + particle;
14059 });
14060 } //put the adverb at the end?
14061 // if (parsed.adverb.found) {
14062 // let adverb = parsed.adverb.text()
14063 // let space = hasHyphen === true ? '-' : ' '
14064 // if (parsed.adverbAfter === true) {
14065 // Object.keys(forms).forEach(k => (forms[k] += space + adverb))
14066 // } else {
14067 // Object.keys(forms).forEach(k => (forms[k] = adverb + space + forms[k]))
14068 // }
14069 // }
14070 //apply negative
14071
14072
14073 var isNegative = parsed.negative.found;
14074
14075 if (isNegative) {
14076 forms.PastTense = 'did not ' + forms.Infinitive;
14077 forms.PresentTense = 'does not ' + forms.Infinitive;
14078 forms.Gerund = 'not ' + forms.Gerund;
14079 } //future Tense is pretty straightforward
14080
14081
14082 if (!forms.FutureTense) {
14083 if (isNegative) {
14084 forms.FutureTense = 'will not ' + forms.Infinitive;
14085 } else {
14086 forms.FutureTense = 'will ' + forms.Infinitive;
14087 }
14088 }
14089
14090 if (isNegative) {
14091 forms.Infinitive = 'not ' + forms.Infinitive;
14092 }
14093
14094 return forms;
14095 };
14096
14097 var conjugate_1$1 = conjugate$2;
14098
14099 // verb-phrases that are orders - 'close the door'
14100 // these should not be conjugated
14101 var isImperative = function isImperative(parsed) {
14102 // do the dishes
14103 if (parsed.auxiliary.has('do')) {
14104 return true;
14105 } // speak the truth
14106 // if (parsed.verb.has('^#Infinitive')) {
14107 // // 'i speak' is not imperative
14108 // if (parsed.subject.has('(i|we|you|they)')) {
14109 // return false
14110 // }
14111 // return true
14112 // }
14113
14114
14115 return false;
14116 }; // // basically, don't conjugate it
14117 // exports.toImperative = function (parsed) {
14118 // let str = parsed.original.text()
14119 // let res = {
14120 // PastTense: str,
14121 // PresentTense: str,
14122 // FutureTense: str,
14123 // Infinitive: str,
14124 // }
14125 // return res
14126 // }
14127
14128
14129 var imperative = {
14130 isImperative: isImperative
14131 };
14132
14133 // if something is 'modal-ish' we are forced to use past-participle
14134 // ('i could drove' is wrong)
14135
14136 var useParticiple = function useParticiple(parsed) {
14137 if (parsed.auxiliary.has('(could|should|would|may|can|must)')) {
14138 return true;
14139 }
14140
14141 if (parsed.auxiliary.has('am .+? being')) {
14142 return true;
14143 }
14144
14145 if (parsed.auxiliary.has('had .+? been')) {
14146 return true;
14147 }
14148
14149 return false;
14150 }; // conjugate 'drive' ➔ 'have driven'
14151
14152
14153 var toParticiple = function toParticiple(parsed, world) {
14154 //is it already a participle?
14155 if (parsed.auxiliary.has('(have|had)') && parsed.verb.has('#Participle')) {
14156 return;
14157 } // try to swap the main verb to its participle form
14158
14159
14160 var obj = conjugate_1$1(parsed, world);
14161 var str = obj.Participle || obj.PastTense;
14162
14163 if (str) {
14164 parsed.verb.replaceWith(str, false);
14165 } // 'am being driven' ➔ 'have been driven'
14166
14167
14168 if (parsed.auxiliary.has('am .+? being')) {
14169 parsed.auxiliary.remove('am');
14170 parsed.auxiliary.replace('being', 'have been');
14171 } // add a 'have'
14172
14173
14174 if (!parsed.auxiliary.has('have')) {
14175 parsed.auxiliary.append('have');
14176 } // tag it as a participle
14177
14178
14179 parsed.verb.tag('Participle', 'toParticiple'); // turn 'i can swim' to -> 'i could swim'
14180
14181 parsed.auxiliary.replace('can', 'could'); //'must be' ➔ 'must have been'
14182
14183 parsed.auxiliary.replace('be have', 'have been'); //'not have' ➔ 'have not'
14184
14185 parsed.auxiliary.replace('not have', 'have not'); // ensure all new words are tagged right
14186
14187 parsed.auxiliary.tag('Auxiliary');
14188 };
14189
14190 var participle = {
14191 useParticiple: useParticiple,
14192 toParticiple: toParticiple
14193 };
14194
14195 var isImperative$1 = imperative.isImperative;
14196 var _toParticiple = participle.toParticiple,
14197 useParticiple$1 = participle.useParticiple; // remove any tense-information in auxiliary verbs
14198
14199 var makeNeutral = function makeNeutral(parsed) {
14200 //remove tense-info from auxiliaries
14201 parsed.auxiliary.remove('(will|are|am|being)');
14202 parsed.auxiliary.remove('(did|does)');
14203 parsed.auxiliary.remove('(had|has|have)'); //our conjugation includes the 'not' and the phrasal-verb particle
14204
14205 parsed.particle.remove();
14206 parsed.negative.remove();
14207 return parsed;
14208 };
14209
14210 var methods$7 = {
14211 /** overload the original json with verb information */
14212 json: function json(options) {
14213 var _this = this;
14214
14215 var n = null;
14216
14217 if (typeof options === 'number') {
14218 n = options;
14219 options = null;
14220 }
14221
14222 options = options || {
14223 text: true,
14224 normal: true,
14225 trim: true,
14226 terms: true
14227 };
14228 var res = [];
14229 this.forEach(function (p) {
14230 var json = p.json(options)[0];
14231 var parsed = parse$2(p);
14232 json.parts = {};
14233 Object.keys(parsed).forEach(function (k) {
14234 if (parsed[k] && parsed[k].isA === 'Doc') {
14235 json.parts[k] = parsed[k].text('normal');
14236 } else {
14237 json.parts[k] = parsed[k];
14238 }
14239 });
14240 json.isNegative = p.has('#Negative');
14241 json.conjugations = conjugate_1$1(parsed, _this.world);
14242 res.push(json);
14243 });
14244
14245 if (n !== null) {
14246 return res[n];
14247 }
14248
14249 return res;
14250 },
14251
14252 /** grab the adverbs describing these verbs */
14253 adverbs: function adverbs() {
14254 var list = []; // look at internal adverbs
14255
14256 this.forEach(function (vb) {
14257 var advb = parse$2(vb).adverb;
14258
14259 if (advb.found) {
14260 list = list.concat(advb.list);
14261 }
14262 }); // look for leading adverbs
14263
14264 var m = this.lookBehind('#Adverb+$');
14265
14266 if (m.found) {
14267 list = m.list.concat(list);
14268 } // look for trailing adverbs
14269
14270
14271 m = this.lookAhead('^#Adverb+');
14272
14273 if (m.found) {
14274 list = list.concat(m.list);
14275 }
14276
14277 return this.buildFrom(list);
14278 },
14279 /// Verb Inflection
14280
14281 /**return verbs like 'we walk' and not 'spencer walks' */
14282 isPlural: function isPlural() {
14283 var _this2 = this;
14284
14285 var list = [];
14286 this.forEach(function (vb) {
14287 var parsed = parse$2(vb);
14288
14289 if (isPlural_1$2(parsed, _this2.world) === true) {
14290 list.push(vb.list[0]);
14291 }
14292 });
14293 return this.buildFrom(list);
14294 },
14295
14296 /** return verbs like 'spencer walks' and not 'we walk' */
14297 isSingular: function isSingular() {
14298 var _this3 = this;
14299
14300 var list = [];
14301 this.forEach(function (vb) {
14302 var parsed = parse$2(vb);
14303
14304 if (isPlural_1$2(parsed, _this3.world) === false) {
14305 list.push(vb.list[0]);
14306 }
14307 });
14308 return this.buildFrom(list);
14309 },
14310 /// Conjugation
14311
14312 /** return all forms of this verb */
14313 conjugate: function conjugate() {
14314 var _this4 = this;
14315
14316 var result = [];
14317 this.forEach(function (vb) {
14318 var parsed = parse$2(vb);
14319
14320 var forms = conjugate_1$1(parsed, _this4.world);
14321
14322 result.push(forms);
14323 });
14324 return result;
14325 },
14326
14327 /** walk ➔ walked*/
14328 toPastTense: function toPastTense() {
14329 var _this5 = this;
14330
14331 this.forEach(function (vb) {
14332 var parsed = parse$2(vb); // should we support 'would swim' ➔ 'would have swam'
14333
14334 if (useParticiple$1(parsed)) {
14335 _toParticiple(parsed, _this5.world);
14336
14337 return;
14338 }
14339
14340 if (isImperative$1(parsed)) {
14341 return;
14342 } // don't conjugate 'to be'
14343
14344
14345 if (vb.has('be') && vb.lookBehind('to$').found) {
14346 return;
14347 } // handle 'is raining' -> 'was raining'
14348
14349
14350 if (parsed.verb.has('#Gerund') && parsed.auxiliary.has('(is|will|was)')) {
14351 vb.replace('is', 'was');
14352 return;
14353 }
14354
14355 var str = conjugate_1$1(parsed, _this5.world).PastTense;
14356
14357 if (str) {
14358 parsed = makeNeutral(parsed);
14359 parsed.verb.replaceWith(str, false); // vb.tag('PastTense')
14360 }
14361 });
14362 return this;
14363 },
14364
14365 /** walk ➔ walks */
14366 toPresentTense: function toPresentTense() {
14367 var _this6 = this;
14368
14369 this.forEach(function (vb) {
14370 var parsed = parse$2(vb);
14371
14372 var obj = conjugate_1$1(parsed, _this6.world);
14373
14374 var str = obj.PresentTense; // 'i look', not 'i looks'
14375
14376 if (vb.lookBehind('(i|we) (#Adverb|#Verb)?$').found) {
14377 str = obj.Infinitive;
14378 }
14379
14380 if (str) {
14381 //awkward support for present-participle form
14382 // -- should we support 'have been swimming' ➔ 'am swimming'
14383 if (parsed.auxiliary.has('(have|had) been')) {
14384 parsed.auxiliary.replace('(have|had) been', 'am being');
14385
14386 if (obj.Particle) {
14387 str = obj.Particle || obj.PastTense;
14388 }
14389
14390 return;
14391 }
14392
14393 parsed.verb.replaceWith(str, false);
14394 parsed.verb.tag('PresentTense');
14395 parsed = makeNeutral(parsed); // avoid 'he would walks'
14396
14397 parsed.auxiliary.remove('#Modal');
14398 }
14399 });
14400 return this;
14401 },
14402
14403 /** walk ➔ will walk*/
14404 toFutureTense: function toFutureTense() {
14405 var _this7 = this;
14406
14407 this.forEach(function (vb) {
14408 var parsed = parse$2(vb); // 'i should drive' is already future-enough
14409
14410 if (useParticiple$1(parsed)) {
14411 return;
14412 }
14413
14414 var str = conjugate_1$1(parsed, _this7.world).FutureTense;
14415
14416 if (str) {
14417 parsed = makeNeutral(parsed); // avoid 'he would will go'
14418
14419 parsed.auxiliary.remove('#Modal');
14420 parsed.verb.replaceWith(str, false);
14421 parsed.verb.tag('FutureTense');
14422 }
14423 });
14424 return this;
14425 },
14426
14427 /** walks ➔ walk */
14428 toInfinitive: function toInfinitive() {
14429 var _this8 = this;
14430
14431 this.forEach(function (vb) {
14432 var parsed = parse$2(vb);
14433
14434 var str = conjugate_1$1(parsed, _this8.world).Infinitive;
14435
14436 if (str) {
14437 vb.replaceWith(str, false);
14438 vb.tag('Infinitive');
14439 }
14440 });
14441 return this;
14442 },
14443
14444 /** walk ➔ walking */
14445 toGerund: function toGerund() {
14446 var _this9 = this;
14447
14448 this.forEach(function (vb) {
14449 var parsed = parse$2(vb);
14450
14451 var str = conjugate_1$1(parsed, _this9.world).Gerund;
14452
14453 if (str) {
14454 vb.replaceWith(str, false);
14455 vb.tag('Gerund');
14456 }
14457 });
14458 return this;
14459 },
14460
14461 /** drive ➔ driven - naked past-participle if it exists, otherwise past-tense */
14462 toParticiple: function toParticiple() {
14463 var _this10 = this;
14464
14465 this.forEach(function (vb) {
14466 var parsed = parse$2(vb);
14467 var noAux = !parsed.auxiliary.found;
14468
14469 _toParticiple(parsed, _this10.world); // dirty trick to ensure our new auxiliary is found
14470
14471
14472 if (noAux) {
14473 parsed.verb.prepend(parsed.auxiliary.text());
14474 parsed.auxiliary.remove();
14475 }
14476 });
14477 return this;
14478 },
14479 /// Negation
14480
14481 /** return only verbs with 'not'*/
14482 isNegative: function isNegative() {
14483 return this["if"]('#Negative');
14484 },
14485
14486 /** return only verbs without 'not'*/
14487 isPositive: function isPositive() {
14488 return this.ifNo('#Negative');
14489 },
14490
14491 /** add a 'not' to these verbs */
14492 toNegative: function toNegative() {
14493 var _this11 = this;
14494
14495 this.list.forEach(function (p) {
14496 var doc = _this11.buildFrom([p]);
14497
14498 var parsed = parse$2(doc);
14499
14500 toNegative_1(parsed, doc.world);
14501 });
14502 return this;
14503 },
14504
14505 /** remove 'not' from these verbs */
14506 toPositive: function toPositive() {
14507 var m = this.match('do not #Verb');
14508
14509 if (m.found) {
14510 m.remove('do not');
14511 }
14512
14513 return this.remove('#Negative');
14514 },
14515
14516 /** who, or what is doing this action? */
14517 subject: function subject() {
14518 var list = [];
14519 this.forEach(function (p) {
14520 var found = getSubject_1(p);
14521
14522 if (found.list[0]) {
14523 list.push(found.list[0]);
14524 }
14525 });
14526 return this.buildFrom(list);
14527 }
14528 };
14529
14530 var addMethod$9 = function addMethod(Doc) {
14531 /** */
14532 var Verbs = /*#__PURE__*/function (_Doc) {
14533 _inherits(Verbs, _Doc);
14534
14535 var _super = _createSuper(Verbs);
14536
14537 function Verbs() {
14538 _classCallCheck(this, Verbs);
14539
14540 return _super.apply(this, arguments);
14541 }
14542
14543 return Verbs;
14544 }(Doc); // add-in our methods
14545
14546
14547 Object.assign(Verbs.prototype, methods$7); // aliases
14548
14549 Verbs.prototype.negate = Verbs.prototype.toNegative;
14550
14551 Doc.prototype.verbs = function (n) {
14552 var match = this.match('(#Adverb|#Auxiliary|#Verb|#Negative|#Particle)+'); // try to ignore leading and trailing adverbs
14553
14554 match = match.not('^#Adverb+');
14555 match = match.not('#Adverb+$'); // handle commas:
14556 // don't split 'really, really'
14557
14558 var keep = match.match('(#Adverb && @hasComma) #Adverb'); // // but split the other commas
14559
14560 var m = match.not(keep).splitAfter('@hasComma'); // i was shocked looking at...
14561
14562 var gerund = m.match('#PastTense #Gerund');
14563
14564 if (!gerund.has('(been|am|#Auxiliary) #Gerund')) {
14565 m = m.splitBefore(gerund.match('#Gerund'));
14566 } // combine them back together
14567
14568
14569 m = m.concat(keep);
14570 m.sort('index'); //handle slashes?
14571 //ensure there's actually a verb
14572
14573 m = m["if"]('#Verb'); // the reason he will is ...
14574
14575 if (m.has('(is|was)$')) {
14576 m = m.splitBefore('(is|was)$');
14577 } //ensure it's not two verbs
14578
14579
14580 if (m.has('#PresentTense #Adverb #PresentTense')) {
14581 m = m.splitBefore('#Adverb #PresentTense');
14582 } //grab (n)th result
14583
14584
14585 if (typeof n === 'number') {
14586 m = m.get(n);
14587 }
14588
14589 var vb = new Verbs(m.list, this, this.world);
14590 return vb;
14591 };
14592
14593 return Doc;
14594 };
14595
14596 var Verbs = addMethod$9;
14597
14598 var addMethod$a = function addMethod(Doc) {
14599 /** */
14600 var People = /*#__PURE__*/function (_Doc) {
14601 _inherits(People, _Doc);
14602
14603 var _super = _createSuper(People);
14604
14605 function People() {
14606 _classCallCheck(this, People);
14607
14608 return _super.apply(this, arguments);
14609 }
14610
14611 return People;
14612 }(Doc);
14613
14614 Doc.prototype.people = function (n) {
14615 var match = this.splitAfter('@hasComma');
14616 match = match.match('#Person+'); //grab (n)th result
14617
14618 if (typeof n === 'number') {
14619 match = match.get(n);
14620 }
14621
14622 return new People(match.list, this, this.world);
14623 };
14624
14625 return Doc;
14626 };
14627
14628 var People = addMethod$a;
14629
14630 var subclass = [Abbreviations, Acronyms, Clauses, Contractions, Lists, Nouns, Parentheses, Possessives, Quotations, Verbs, People];
14631
14632 var extend = function extend(Doc) {
14633 // add basic methods
14634 Object.keys(_simple).forEach(function (k) {
14635 return Doc.prototype[k] = _simple[k];
14636 }); // add subclassed methods
14637
14638 subclass.forEach(function (addFn) {
14639 return addFn(Doc);
14640 });
14641 return Doc;
14642 };
14643
14644 var Subset = extend;
14645
14646 var methods$8 = {
14647 misc: methods$4,
14648 selections: _simple
14649 };
14650 /** a parsed text object */
14651
14652 var Doc = /*#__PURE__*/function () {
14653 function Doc(list, from, world) {
14654 var _this = this;
14655
14656 _classCallCheck(this, Doc);
14657
14658 this.list = list; // this.reasons = []
14659 //quiet these properties in console.logs
14660
14661 Object.defineProperty(this, 'from', {
14662 enumerable: false,
14663 value: from,
14664 writable: true
14665 }); //borrow some missing data from parent
14666
14667 if (world === undefined && from !== undefined) {
14668 world = from.world;
14669 } //'world' getter
14670
14671
14672 Object.defineProperty(this, 'world', {
14673 enumerable: false,
14674 value: world,
14675 writable: true
14676 }); //fast-scans for our data
14677
14678 Object.defineProperty(this, '_cache', {
14679 enumerable: false,
14680 writable: true,
14681 value: {}
14682 }); //'found' getter
14683
14684 Object.defineProperty(this, 'found', {
14685 get: function get() {
14686 return _this.list.length > 0;
14687 }
14688 }); //'length' getter
14689
14690 Object.defineProperty(this, 'length', {
14691 get: function get() {
14692 return _this.list.length;
14693 }
14694 }); // this is way easier than .constructor.name...
14695
14696 Object.defineProperty(this, 'isA', {
14697 get: function get() {
14698 return 'Doc';
14699 }
14700 });
14701 }
14702 /** run part-of-speech tagger on all results*/
14703
14704
14705 _createClass(Doc, [{
14706 key: "tagger",
14707 value: function tagger() {
14708 return _02Tagger(this);
14709 }
14710 /** pool is stored on phrase objects */
14711
14712 }, {
14713 key: "pool",
14714 value: function pool() {
14715 if (this.list.length > 0) {
14716 return this.list[0].pool;
14717 }
14718
14719 return this.all().list[0].pool;
14720 }
14721 }]);
14722
14723 return Doc;
14724 }();
14725 /** create a new Document object */
14726
14727
14728 Doc.prototype.buildFrom = function (list) {
14729 list = list.map(function (p) {
14730 return p.clone(true);
14731 }); // new this.constructor()
14732
14733 var doc = new Doc(list, this, this.world);
14734 return doc;
14735 };
14736 /** create a new Document from plaintext. */
14737
14738
14739 Doc.prototype.fromText = function (str) {
14740 var list = _01Tokenizer(str, this.world, this.pool());
14741 return this.buildFrom(list);
14742 };
14743
14744 Object.assign(Doc.prototype, methods$8.misc);
14745 Object.assign(Doc.prototype, methods$8.selections); //add sub-classes
14746
14747 Subset(Doc); //aliases
14748
14749 var aliases$1 = {
14750 untag: 'unTag',
14751 and: 'match',
14752 notIf: 'ifNo',
14753 only: 'if',
14754 onlyIf: 'if'
14755 };
14756 Object.keys(aliases$1).forEach(function (k) {
14757 return Doc.prototype[k] = Doc.prototype[aliases$1[k]];
14758 });
14759 var Doc_1 = Doc;
14760
14761 var smallTagger = function smallTagger(doc) {
14762 var terms = doc.termList();
14763 _01Lexicon(terms, doc.world); // run any user-given tagger functions
14764
14765 doc.world.taggers.forEach(function (fn) {
14766 fn(doc);
14767 });
14768 return doc;
14769 };
14770
14771 var tiny = smallTagger;
14772
14773 function instance(worldInstance) {
14774 //blast-out our word-lists, just once
14775 var world = worldInstance;
14776 /** parse and tag text into a compromise object */
14777
14778 var nlp = function nlp() {
14779 var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
14780 var lexicon = arguments.length > 1 ? arguments[1] : undefined;
14781
14782 if (lexicon) {
14783 world.addWords(lexicon);
14784 }
14785
14786 var list = _01Tokenizer(text, world);
14787 var doc = new Doc_1(list, null, world);
14788 doc.tagger();
14789 return doc;
14790 };
14791 /** parse text into a compromise object, without running POS-tagging */
14792
14793
14794 nlp.tokenize = function () {
14795 var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
14796 var lexicon = arguments.length > 1 ? arguments[1] : undefined;
14797 var w = world;
14798
14799 if (lexicon) {
14800 w = w.clone();
14801 w.words = {};
14802 w.addWords(lexicon);
14803 }
14804
14805 var list = _01Tokenizer(text, w);
14806 var doc = new Doc_1(list, null, w);
14807
14808 if (lexicon || doc.world.taggers.length > 0) {
14809 tiny(doc);
14810 }
14811
14812 return doc;
14813 };
14814 /** mix in a compromise-plugin */
14815
14816
14817 nlp.extend = function (fn) {
14818 fn(Doc_1, world, this, Phrase_1, Term_1, Pool_1);
14819 return this;
14820 };
14821 /** create a compromise Doc object from .json() results */
14822
14823
14824 nlp.fromJSON = function (json) {
14825 var list = fromJSON_1(json, world);
14826 return new Doc_1(list, null, world);
14827 };
14828 /** make a deep-copy of the library state */
14829
14830
14831 nlp.clone = function () {
14832 return instance(world.clone());
14833 };
14834 /** log our decision-making for debugging */
14835
14836
14837 nlp.verbose = function () {
14838 var bool = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
14839 world.verbose(bool);
14840 return this;
14841 };
14842 /** grab currently-used World object */
14843
14844
14845 nlp.world = function () {
14846 return world;
14847 };
14848 /** pre-parse any match statements */
14849
14850
14851 nlp.parseMatch = function (str, opts) {
14852 return matchSyntax(str, opts);
14853 };
14854 /** current version of the library */
14855
14856
14857 nlp.version = _version; // aliases
14858
14859 nlp["import"] = nlp.load;
14860 nlp.plugin = nlp.extend;
14861 return nlp;
14862 }
14863
14864 var src = instance(new World_1());
14865
14866 return src;
14867
14868})));