Old ngn4 website
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3360 lines
90 KiB

9 years ago
  1. // This file is made from automatically concaterad and filtered node.js scripts.
  2. // ngn4 is open source, and provided under an MIT licence
  3. // See https://github.com/gissleh/ngn4 for more details.
  4. // Copyright (c) 2015 Gisle Aune"use strict";
  5. var algos = {};
  6. var loaders = {};
  7. var grammarUtils = {
  8. pick: function(array, randomFunction) {
  9. return array[Math.floor(randomFunction() * array.length)];
  10. }
  11. }
  12. var algo = {
  13. id: "grammar",
  14. name: "Grammar",
  15. parseList: function(input, options, lfRules) {
  16. var r = {
  17. positions: [0],
  18. words: [],
  19. symbols: {},
  20. size: 0
  21. };
  22. for(var i = 0; i < input.length; ++i) {
  23. var group = input[i];
  24. var headers = group.headers;
  25. var lines = group.lines;
  26. // Ensure sets exists.
  27. for(var j = 0; j < headers.length; ++j) {
  28. var header = headers[j];
  29. if(!r.symbols.hasOwnProperty(header)) {
  30. r.symbols[header] = [];
  31. }
  32. }
  33. // Parse lines to add to sets
  34. for(var j = 0; j < lines.length; ++j) {
  35. var tokens = lines[j];
  36. lfRules.learn(tokens.join(''));
  37. for(var k = 0; k < tokens.length; ++k) {
  38. var token = tokens[k];
  39. var header = headers[k];
  40. r.symbols[header].push(token);
  41. }
  42. }
  43. r.words.push({f: headers, l: lines.length});
  44. r.size += lines.length;
  45. r.positions.push(r.size);
  46. }
  47. for(var i = 0; i < r.words.length; ++i) {
  48. var word = r.words[i];
  49. if(word.l > 1) {
  50. continue;
  51. }
  52. var strikes = 0;
  53. for(var j = 0; j < word.f.length; ++j) {
  54. var symbol = word.f[j];
  55. if(r.symbols[symbol].length <= word.l) {
  56. ++strikes;
  57. }
  58. }
  59. if(strikes === word.f.length) {
  60. r.words.splice(i, 1);
  61. console.error('\tSKIPPED "'+word.f.join(' ')+'" (length <= 1)');
  62. }
  63. }
  64. return r;
  65. },
  66. initTemp: function(data, options, lfRules) {
  67. // Reconstruct samples
  68. var words = data.words;
  69. var symbols = data.symbols;
  70. var results = [];
  71. var indices = {};
  72. var symbolKeys = Object.keys(symbols);
  73. // Set up the indices array
  74. for(var i = 0; i < symbolKeys.length; ++i) {
  75. indices[symbolKeys[i]] = 0;
  76. }
  77. for(var i = 0; i < words.length; ++i) {
  78. var word = words[i];
  79. for(var j = 0; j < word.l; ++j) {
  80. var name = "";
  81. for(var k = 0; k < word.f.length; ++k) {
  82. var symbol = word.f[k];
  83. var index = indices[symbol]++;
  84. name += symbols[symbol][index];
  85. }
  86. results.push(name);
  87. }
  88. }
  89. // Enforce lfoverride
  90. if(options.hasOwnProperty('lfOverrides')) {
  91. var keys = Object.keys(options.lfOverrides);
  92. for(var i = 0; i < keys.length; ++i) {
  93. lfRules.counts[keys[i]] = options.lfOverrides[keys[i]];
  94. }
  95. }
  96. return results;
  97. },
  98. generate: function(data, randomFunction, lfRules, options, temp) {
  99. var word = null;
  100. var result = [];
  101. var prev = null;
  102. var r = Math.floor(randomFunction() * data.size);
  103. for(var i = 0; i < data.words.length; ++i) {
  104. if(r < data.positions[i + 1]) {
  105. word = data.words[i];
  106. break;
  107. }
  108. }
  109. if(word === null) {
  110. word = data.words[data.words.length - 1];
  111. }
  112. while(result.length < word.f.length) {
  113. var i = result.length;
  114. var symbol = word.f[i];
  115. var pick = grammarUtils.pick(data.symbols[symbol], randomFunction);
  116. var fail = false;
  117. var name;
  118. result.push(pick);
  119. name = result.join('');
  120. if(!lfRules.check(name)) {
  121. fail = true;
  122. }
  123. if(!fail && temp.indexOf(name) !== -1) {
  124. fail = true;
  125. }
  126. if(fail) {
  127. if(prev === pick) {
  128. prev = null;
  129. // If word's wieght is smaller than symbol count,
  130. // retry with another word. This is to prevent crashing
  131. if(word.l <= word.f.length) {
  132. var r = Math.floor(randomFunction() * data.size);
  133. word = null;
  134. for(var i = 0; i < data.words.length; ++i) {
  135. if(r < data.positions[i + 1]) {
  136. word = data.words[i];
  137. break;
  138. }
  139. }
  140. if(word === null) {
  141. word = data.words[data.words.length - 1];
  142. }
  143. }
  144. result = [];
  145. } else {
  146. prev = pick;
  147. result.pop();
  148. }
  149. }
  150. }
  151. return result.join('');
  152. }
  153. }
  154. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  155. module.exports = algo;
  156. } else {
  157. algos[algo.id] = algo;
  158. }
  159. var markovUtils = {};
  160. var runId = 0;
  161. markovUtils.mergeFlags = function(flags, flagsStr) {
  162. var result = {
  163. lrs: false,
  164. lrm: false,
  165. lre: false,
  166. f2o: false,
  167. f3o: false,
  168. to2c: false,
  169. to2v: false,
  170. todc: false,
  171. todv: false,
  172. lrf: false,
  173. as: false
  174. }
  175. if(typeof(flags) !== 'string') {
  176. var keys = Object.keys(flags);
  177. for(var i = 0; i < keys.length; ++i) {
  178. result[keys[i]] = flags[keys[i]];
  179. }
  180. } else {
  181. flagsStr = flags;
  182. }
  183. if(typeof(flagsStr) !== 'undefined') {
  184. var flagSplit = flagsStr.split(' ');
  185. for(var i = 0; i < flagSplit.length; ++i) {
  186. result[flagSplit[i]] = true;
  187. }
  188. }
  189. return result;
  190. }
  191. markovUtils.pick = function(rfunc, array) {
  192. return array[Math.floor(rfunc() * array.length)];
  193. }
  194. markovUtils.getArray = function(obj, prop) {
  195. if(!obj.hasOwnProperty(prop)) {
  196. obj[prop] = [];
  197. }
  198. return obj[prop];
  199. }
  200. markovUtils.getIndex = function(obj, prop) {
  201. if(!obj.hasOwnProperty(prop)) {
  202. obj[prop] = 0;
  203. }
  204. return obj[prop]++;
  205. }
  206. markovUtils.getRandomLength = function(array, total, randomFunction) {
  207. var r = Math.floor(randomFunction() * total);
  208. for(var i = 1; i < array.length; ++i) {
  209. r -= array[i];
  210. if(r < 0) {
  211. return i + 3;
  212. }
  213. }
  214. // 4 1 3 1
  215. return array.length + 1;
  216. }
  217. markovUtils.checkThirdOrder = function(result, option, flags, options) {
  218. if(flags.f3o) {
  219. return true;
  220. }
  221. var vowels;
  222. if(options.hasOwnProperty('vowels')) {
  223. vowels = options.vowels;
  224. } else {
  225. vowels = "aeiouy";
  226. }
  227. var prev1 = result[result.length - 1];
  228. var prev2 = result[result.length - 2];
  229. if(flags.todc && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) === -1)) {
  230. return true;
  231. }
  232. if(flags.to2c && (result.length > 2) && (vowels.indexOf(prev1) === -1) && (vowels.indexOf(prev2) === -1)) {
  233. return true;
  234. }
  235. if(flags.todv && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) !== -1)) {
  236. return true;
  237. }
  238. if(flags.to2v && (result.length > 2) && (vowels.indexOf(prev1) !== -1) && (vowels.indexOf(prev2) !== -1)) {
  239. return true;
  240. }
  241. return false;
  242. }
  243. markovUtils.checkNext = function(result, option, length, flags, lrFlag, lfRules, samples) {
  244. var next = result + option.ch;
  245. if(flags.as && (next.length == length) && (samples.indexOf(next) !== -1)) {
  246. return false;
  247. }
  248. if(lrFlag && option.l != length) {
  249. return false;
  250. }
  251. if(flags.rlf && !lfRules.check(next)) {
  252. return false;
  253. }
  254. return true;
  255. }
  256. /*
  257. +-------------------------------------------------+
  258. | GENERATOR FLAGS |
  259. +---+--------+------------------------------------+
  260. | X | lrs | Length restriction on start, mid, |
  261. | X | lrm | and/or end rules the length of the |
  262. | X | lre | rule's source sample |
  263. +---+--------+------------------------------------+
  264. | X | f2o | Force 2nd or 3rd order chain. f3o |
  265. | X | f3o | override f2o if both are set |
  266. +---+--------+------------------------------------+
  267. | X | to2c | Third order on 2 consonants |
  268. | X | to2v | and/or vowels |
  269. +---+--------+------------------------------------+
  270. | X | todc | Third order on double consonants |
  271. | X | todv | and/or vowels |
  272. +---+--------+------------------------------------+
  273. | X | rlf | Restrict letter frequency |
  274. +---+--------+------------------------------------+
  275. | X | as | Avoid samples being generated |
  276. +---+--------+------------------------------------+
  277. */
  278. var algo = {
  279. id: "markov",
  280. name: "Markov",
  281. parseList: function(input, options, lfRules) {
  282. var r = { // Examples after "aeyna"
  283. starts: [], // [{s: 'aey', l: 5}]
  284. mids: {}, // {"ey": [{l: 5, ch: 'n'}], "aey": [{l: 5, ch: 'n'}]}
  285. ends: {}, // {"eyn": [{l: 5, ch: 'a'}]}
  286. lf: [], // [0, 0, 1],
  287. lfTotal: 0
  288. }
  289. // FLAGS
  290. if(!options.hasOwnProperty('flags')) {
  291. options.flags = {};
  292. }
  293. options.flags = markovUtils.mergeFlags(options.flags, options.flagsStr);
  294. // Parse each sample.
  295. for(var i = 0; i < input.length; ++i) {
  296. var sample = input[i];
  297. var l = sample.length;
  298. // The code doesn't work with names shorter than 3 letters.
  299. if(sample.length < 3) {
  300. continue;
  301. }
  302. // Learn letter frequency rules from sample.
  303. lfRules.learn(sample);
  304. // Length frequency
  305. while(r.lf.length <= sample.length - 3) {
  306. r.lf.push(0);
  307. }
  308. ++r.lf[sample.length - 3];
  309. ++r.lfTotal;
  310. // Beginning
  311. if(sample.length > 4) {
  312. r.starts.push({
  313. l: l,
  314. s: sample.substring(0, 3)
  315. });
  316. } else {
  317. r.starts.push({
  318. l: l,
  319. s: sample.substring(0, 2)
  320. });
  321. }
  322. // Middle
  323. for(var j = 2; j < l - 1; ++j) {
  324. var mid = {
  325. ch: sample.charAt(j),
  326. l: l
  327. };
  328. if(j > 2) {
  329. markovUtils.getArray(r.mids, sample.substring(j - 3, j)).push(mid);
  330. }
  331. markovUtils.getArray(r.mids, sample.substring(j - 2, j)).push(mid);
  332. }
  333. // ends
  334. var end = {
  335. ch: sample.charAt(l - 1),
  336. l: l
  337. };
  338. if(sample.length > 4) {
  339. markovUtils.getArray(r.ends, sample.substring(l - 4, l - 1)).push(end);
  340. }
  341. markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).push(end);
  342. //console.log(sample + ' ' + sample.substring(l - 3, l - 1) + '-' + end.ch + ' ' + markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).length);
  343. }
  344. return r;
  345. },
  346. initTemp: function(data, options, lfRules) {
  347. // Reconstructs samples for avoid-sample rule
  348. var results = [];
  349. var indexMap1 = {};
  350. var indexMap2 = {};
  351. var getIndex = markovUtils.getIndex;
  352. for(var i = 0; i < data.starts.length; ++i) {
  353. var start = data.starts[i];
  354. var name = start.s.substring(0, 2);
  355. var length = start.l;
  356. var key, set, indexMap, index;
  357. for(var j = name.length; j < length; ++j) {
  358. set = ((j < length - 1) ? data.mids : data.ends);
  359. indexMap = ((j < length - 1) ? indexMap1 : indexMap2);
  360. key = name.substring(name.length - 2);
  361. if(set.hasOwnProperty(key)) {
  362. index = getIndex(indexMap, key);
  363. //console.log(index + ' ' + name + ' ' + key + ' ' + (set == data.mids) + ' ' + JSON.stringify(set[key]));
  364. name += set[key][index].ch;
  365. } else {
  366. console.log(name + ' ' + key + ' ' + length);
  367. }
  368. }
  369. results.push(name);
  370. }
  371. // Enforce lfoverride
  372. if(options.hasOwnProperty('lfOverrides')) {
  373. var keys = Object.keys(options.lfOverrides);
  374. for(var i = 0; i < keys.length; ++i) {
  375. lfRules.counts[keys[i]] = options.lfOverrides[keys[i]];
  376. }
  377. }
  378. return results;
  379. },
  380. generate: function(data, randomFunction, lfRules, options, temp) {
  381. // INITIALIZE and START
  382. var result = "";
  383. var f = options.flags;
  384. var globalRuns = 0;
  385. while(globalRuns++ < 100) {
  386. var runs = 0;
  387. var start = markovUtils.pick(randomFunction, data.starts);
  388. var length = start.l;
  389. var slength = start.s.length;
  390. var tight = false;
  391. result = start.s;
  392. // If start shouldn't be length restricted, pick a random length.
  393. if(!f.lrs) {
  394. length = markovUtils.getRandomLength(data.lf, data.lfTotal, randomFunction);
  395. if(length <= 4 && slength > 2) {
  396. result = start.s.substring(0, 2);
  397. }
  398. }
  399. // Make the rest of the name, letter by letter.
  400. while(result.length < length) {
  401. var key, opts, validOpts;
  402. ++runId;
  403. var set = ((result.length < length - 1) ? data.mids : data.ends);
  404. var lrFlag = ((result.length < length - 1) ? f.lrm : f.lre);
  405. // ATTEMPT: 3rd order options
  406. if(result.length >= 3 && (!f.f2o || f.f3o)) {
  407. key = result.substring(result.length - 3, result.length);
  408. opts = set[key];
  409. validOpts = [];
  410. if(typeof(opts) !== 'undefined') {
  411. for(var i = 0; i < opts.length; ++i) {
  412. // If (needs third order AND option fits)
  413. if(markovUtils.checkThirdOrder(result, opts[i], f, options)
  414. && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
  415. validOpts.push(opts[i]);
  416. }
  417. }
  418. }
  419. if(validOpts.length > 0) {
  420. var opt = markovUtils.pick(randomFunction, validOpts);
  421. result += opt.ch;
  422. continue;
  423. }
  424. }
  425. // ATTEMPT: 2nd order options
  426. if(!f.f3o) {
  427. key = result.substring(result.length - 2, result.length);
  428. opts = set[key];
  429. validOpts = [];
  430. if(typeof(opts) !== 'undefined') {
  431. for(var i = 0; i < opts.length; ++i) {
  432. if(!markovUtils.checkThirdOrder(result, opts[i], f, options)
  433. && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
  434. validOpts.push(opts[i]);
  435. }
  436. }
  437. }
  438. if(validOpts.length > 0) {
  439. var opt = markovUtils.pick(randomFunction, validOpts);
  440. result += opt.ch;
  441. continue;
  442. }
  443. }
  444. // LAST RESORT: Cut off the last one and try again
  445. if(result.length > slength) {
  446. result = start.s;
  447. }
  448. if(++runs > 32) {
  449. result = null;
  450. break;
  451. }
  452. }
  453. if(result != null) {
  454. return result;
  455. }
  456. }
  457. }
  458. }
  459. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  460. module.exports = algo;
  461. } else {
  462. algos[algo.id] = algo;
  463. }
  464. var algo = {
  465. id: "select",
  466. name: "Simple Random Selection",
  467. parseList: function(input) {
  468. return input;
  469. },
  470. initTemp: function(data) {
  471. return null;
  472. },
  473. generate: function(data, randomFunction) {
  474. return data[Math.floor(randomFunction() * data.length)];
  475. }
  476. }
  477. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  478. module.exports = algo;
  479. } else {
  480. algos[algo.id] = algo;
  481. }
  482. var algo = {
  483. id: "syllables",
  484. name: "Syllable Concateration",
  485. parseList: function(input, options, lfRules) {
  486. var r = {
  487. positions: [0],
  488. groups: [].concat(input),
  489. size: 0
  490. };
  491. for(var i = 0; i < r.groups.length; ++i) {
  492. var group = r.groups[i];
  493. if(group.headers.length >= 2) {
  494. group.weigthMultiplier = parseFloat(group.headers[1]);
  495. } else {
  496. group.weigthMultiplier = 1;
  497. }
  498. if(group.lines.length <= 1) {
  499. console.error('SKIPPED "' + group.id + '" (length <= 1)');
  500. r.groups.splice(i, 1);
  501. --i;
  502. continue;
  503. }
  504. group.width = group.lines[0].length;
  505. for(var j = 0; j < group.lines.length; ++j) {
  506. var line = group.lines[j];
  507. if(line.length !== group.width) {
  508. console.error(JSON.stringify(group));
  509. throw new Error("The line " + JSON.stringify(line) + " is not as long as the others in the group ("+group.width+"). No non-conformism!. D:<");
  510. }
  511. lfRules.learn(line.join(''));
  512. }
  513. var size = group.lines.length * group.width * group.weigthMultiplier;
  514. r.size += size;
  515. r.positions.push(r.size);
  516. }
  517. return r;
  518. },
  519. initTemp: function(data, options, lfRules) {
  520. var samples = {};
  521. // Reconstruct samples
  522. for(var i = 0; i < data.groups.length; ++i) {
  523. var group = data.groups[i];
  524. for(var j = 0; j < group.lines.length; ++j) {
  525. samples[group.lines[j].join('')] = true;
  526. }
  527. }
  528. // Enforce lfoverride
  529. if(options.hasOwnProperty('lfOverrides')) {
  530. var keys = Object.keys(options.lfOverrides);
  531. for(var i = 0; i < keys.length; ++i) {
  532. lfRules.counts[keys[i]] = options.lfOverrides[keys[i]];
  533. }
  534. }
  535. return samples;
  536. },
  537. generate: function(data, randomFunction, lfRules, options, temp) {
  538. var rand = randomFunction() * data.size;
  539. var group = null;
  540. for(var i = 0; i < data.groups.length - 1; ++i) {
  541. if(rand < data.positions[i + 1]) {
  542. group = data.groups[i];
  543. break;
  544. }
  545. }
  546. if(group == null || group == undefined) {
  547. group = data.groups[data.groups.length - 1];
  548. }
  549. var optionAsls = true;
  550. if(options.hasOwnProperty('asls')) {
  551. optionAsls = options.asls;
  552. }
  553. var result = [];
  554. var lines = group.lines;
  555. var prev = null;
  556. while(result.length < group.width) {
  557. var i = result.length;
  558. rand = Math.floor(randomFunction() * group.lines.length);
  559. var pick = group.lines[rand][i];
  560. result.push(pick);
  561. var fail = false;
  562. // Respect letter frequency rules
  563. if(!lfRules.check(result.join(''))) {
  564. fail = true;
  565. }
  566. // Avoid same letter syllables
  567. if(!fail && optionAsls && i > 0
  568. && (pick.charAt(0) === result[i - 1].charAt(0))) {
  569. fail = true;
  570. }
  571. // Avoid samples, but permit close samples.
  572. if(!fail && (i === group.width - 1) && temp.hasOwnProperty(result.join(''))) {
  573. fail = true;
  574. }
  575. if(fail) {
  576. if(pick === prev) {
  577. result = [];
  578. if(group.lines.length <= group.width) {
  579. var group = null;
  580. for(var i = 0; i < data.groups.length - 1; ++i) {
  581. if(rand < data.positions[i + 1]) {
  582. group = data.groups[i];
  583. break;
  584. }
  585. }
  586. if(group == null || group == undefined) {
  587. group = data.groups[data.groups.length - 1];
  588. }
  589. }
  590. prev = null;
  591. } else {
  592. prev = pick;
  593. result.pop();
  594. }
  595. }
  596. }
  597. return result.join('');
  598. }
  599. }
  600. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  601. module.exports = algo;
  602. } else {
  603. algos[algo.id] = algo;
  604. }
  605. // This file is made from automatically concaterad and filtered node.js scripts.
  606. // ngn4 is open source, and provided under an MIT licence
  607. // See https://github.com/gissleh/ngn4 for more details.
  608. // Copyright (c) 2015 Gisle Aune"use strict";
  609. var algos = {};
  610. var loaders = {};
  611. var grammarUtils = {
  612. pick: function(array, randomFunction) {
  613. return array[Math.floor(randomFunction() * array.length)];
  614. }
  615. }
  616. var algo = {
  617. id: "grammar",
  618. name: "Grammar",
  619. parseList: function(input, options, lfRules) {
  620. var r = {
  621. positions: [0],
  622. words: [],
  623. symbols: {},
  624. size: 0
  625. };
  626. for(var i = 0; i < input.length; ++i) {
  627. var group = input[i];
  628. var headers = group.headers;
  629. var lines = group.lines;
  630. // Ensure sets exists.
  631. for(var j = 0; j < headers.length; ++j) {
  632. var header = headers[j];
  633. if(!r.symbols.hasOwnProperty(header)) {
  634. r.symbols[header] = [];
  635. }
  636. }
  637. // Parse lines to add to sets
  638. for(var j = 0; j < lines.length; ++j) {
  639. var tokens = lines[j];
  640. lfRules.learn(tokens.join(''));
  641. for(var k = 0; k < tokens.length; ++k) {
  642. var token = tokens[k];
  643. var header = headers[k];
  644. r.symbols[header].push(token);
  645. }
  646. }
  647. r.words.push({f: headers, l: lines.length});
  648. r.size += lines.length;
  649. r.positions.push(r.size);
  650. }
  651. for(var i = 0; i < r.words.length; ++i) {
  652. var word = r.words[i];
  653. if(word.l > 1) {
  654. continue;
  655. }
  656. var strikes = 0;
  657. for(var j = 0; j < word.f.length; ++j) {
  658. var symbol = word.f[j];
  659. if(r.symbols[symbol].length <= word.l) {
  660. ++strikes;
  661. }
  662. }
  663. if(strikes === word.f.length) {
  664. r.words.splice(i, 1);
  665. console.error('\tSKIPPED "'+word.f.join(' ')+'" (length <= 1)');
  666. }
  667. }
  668. return r;
  669. },
  670. initTemp: function(data, options, lfRules) {
  671. // Reconstruct samples
  672. var words = data.words;
  673. var symbols = data.symbols;
  674. var results = [];
  675. var indices = {};
  676. var symbolKeys = Object.keys(symbols);
  677. // Set up the indices array
  678. for(var i = 0; i < symbolKeys.length; ++i) {
  679. indices[symbolKeys[i]] = 0;
  680. }
  681. for(var i = 0; i < words.length; ++i) {
  682. var word = words[i];
  683. for(var j = 0; j < word.l; ++j) {
  684. var name = "";
  685. for(var k = 0; k < word.f.length; ++k) {
  686. var symbol = word.f[k];
  687. var index = indices[symbol]++;
  688. name += symbols[symbol][index];
  689. }
  690. results.push(name);
  691. }
  692. }
  693. // Enforce lfoverride
  694. if(options.hasOwnProperty('lfOverrides')) {
  695. var keys = Object.keys(options.lfOverrides);
  696. for(var i = 0; i < keys.length; ++i) {
  697. lfRules.counts[keys[i]] = options.lfOverrides[keys[i]];
  698. }
  699. }
  700. return results;
  701. },
  702. generate: function(data, randomFunction, lfRules, options, temp) {
  703. var word = null;
  704. var result = [];
  705. var prev = null;
  706. var r = Math.floor(randomFunction() * data.size);
  707. for(var i = 0; i < data.words.length; ++i) {
  708. if(r < data.positions[i + 1]) {
  709. word = data.words[i];
  710. break;
  711. }
  712. }
  713. if(word === null) {
  714. word = data.words[data.words.length - 1];
  715. }
  716. while(result.length < word.f.length) {
  717. var i = result.length;
  718. var symbol = word.f[i];
  719. var pick = grammarUtils.pick(data.symbols[symbol], randomFunction);
  720. var fail = false;
  721. var name;
  722. result.push(pick);
  723. name = result.join('');
  724. if(!lfRules.check(name)) {
  725. fail = true;
  726. }
  727. if(!fail && temp.indexOf(name) !== -1) {
  728. fail = true;
  729. }
  730. if(fail) {
  731. if(prev === pick) {
  732. prev = null;
  733. // If word's wieght is smaller than symbol count,
  734. // retry with another word. This is to prevent crashing
  735. if(word.l <= word.f.length) {
  736. var r = Math.floor(randomFunction() * data.size);
  737. word = null;
  738. for(var i = 0; i < data.words.length; ++i) {
  739. if(r < data.positions[i + 1]) {
  740. word = data.words[i];
  741. break;
  742. }
  743. }
  744. if(word === null) {
  745. word = data.words[data.words.length - 1];
  746. }
  747. }
  748. result = [];
  749. } else {
  750. prev = pick;
  751. result.pop();
  752. }
  753. }
  754. }
  755. return result.join('');
  756. }
  757. }
  758. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  759. module.exports = algo;
  760. } else {
  761. algos[algo.id] = algo;
  762. }
  763. var markovUtils = {};
  764. var runId = 0;
  765. markovUtils.mergeFlags = function(flags, flagsStr) {
  766. var result = {
  767. lrs: false,
  768. lrm: false,
  769. lre: false,
  770. f2o: false,
  771. f3o: false,
  772. to2c: false,
  773. to2v: false,
  774. todc: false,
  775. todv: false,
  776. lrf: false,
  777. as: false
  778. }
  779. if(typeof(flags) !== 'string') {
  780. var keys = Object.keys(flags);
  781. for(var i = 0; i < keys.length; ++i) {
  782. result[keys[i]] = flags[keys[i]];
  783. }
  784. } else {
  785. flagsStr = flags;
  786. }
  787. if(typeof(flagsStr) !== 'undefined') {
  788. var flagSplit = flagsStr.split(' ');
  789. for(var i = 0; i < flagSplit.length; ++i) {
  790. result[flagSplit[i]] = true;
  791. }
  792. }
  793. return result;
  794. }
  795. markovUtils.pick = function(rfunc, array) {
  796. return array[Math.floor(rfunc() * array.length)];
  797. }
  798. markovUtils.getArray = function(obj, prop) {
  799. if(!obj.hasOwnProperty(prop)) {
  800. obj[prop] = [];
  801. }
  802. return obj[prop];
  803. }
  804. markovUtils.getIndex = function(obj, prop) {
  805. if(!obj.hasOwnProperty(prop)) {
  806. obj[prop] = 0;
  807. }
  808. return obj[prop]++;
  809. }
  810. markovUtils.getRandomLength = function(array, total, randomFunction) {
  811. var r = Math.floor(randomFunction() * total);
  812. for(var i = 1; i < array.length; ++i) {
  813. r -= array[i];
  814. if(r < 0) {
  815. return i + 3;
  816. }
  817. }
  818. // 4 1 3 1
  819. return array.length + 1;
  820. }
  821. markovUtils.checkThirdOrder = function(result, option, flags, options) {
  822. if(flags.f3o) {
  823. return true;
  824. }
  825. var vowels;
  826. if(options.hasOwnProperty('vowels')) {
  827. vowels = options.vowels;
  828. } else {
  829. vowels = "aeiouy";
  830. }
  831. var prev1 = result[result.length - 1];
  832. var prev2 = result[result.length - 2];
  833. if(flags.todc && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) === -1)) {
  834. return true;
  835. }
  836. if(flags.to2c && (result.length > 2) && (vowels.indexOf(prev1) === -1) && (vowels.indexOf(prev2) === -1)) {
  837. return true;
  838. }
  839. if(flags.todv && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) !== -1)) {
  840. return true;
  841. }
  842. if(flags.to2v && (result.length > 2) && (vowels.indexOf(prev1) !== -1) && (vowels.indexOf(prev2) !== -1)) {
  843. return true;
  844. }
  845. return false;
  846. }
  847. markovUtils.checkNext = function(result, option, length, flags, lrFlag, lfRules, samples) {
  848. var next = result + option.ch;
  849. if(flags.as && (next.length == length) && (samples.indexOf(next) !== -1)) {
  850. return false;
  851. }
  852. if(lrFlag && option.l != length) {
  853. return false;
  854. }
  855. if(flags.rlf && !lfRules.check(next)) {
  856. return false;
  857. }
  858. return true;
  859. }
  860. /*
  861. +-------------------------------------------------+
  862. | GENERATOR FLAGS |
  863. +---+--------+------------------------------------+
  864. | X | lrs | Length restriction on start, mid, |
  865. | X | lrm | and/or end rules the length of the |
  866. | X | lre | rule's source sample |
  867. +---+--------+------------------------------------+
  868. | X | f2o | Force 2nd or 3rd order chain. f3o |
  869. | X | f3o | override f2o if both are set |
  870. +---+--------+------------------------------------+
  871. | X | to2c | Third order on 2 consonants |
  872. | X | to2v | and/or vowels |
  873. +---+--------+------------------------------------+
  874. | X | todc | Third order on double consonants |
  875. | X | todv | and/or vowels |
  876. +---+--------+------------------------------------+
  877. | X | rlf | Restrict letter frequency |
  878. +---+--------+------------------------------------+
  879. | X | as | Avoid samples being generated |
  880. +---+--------+------------------------------------+
  881. */
  882. var algo = {
  883. id: "markov",
  884. name: "Markov",
  885. parseList: function(input, options, lfRules) {
  886. var r = { // Examples after "aeyna"
  887. starts: [], // [{s: 'aey', l: 5}]
  888. mids: {}, // {"ey": [{l: 5, ch: 'n'}], "aey": [{l: 5, ch: 'n'}]}
  889. ends: {}, // {"eyn": [{l: 5, ch: 'a'}]}
  890. lf: [], // [0, 0, 1],
  891. lfTotal: 0
  892. }
  893. // FLAGS
  894. if(!options.hasOwnProperty('flags')) {
  895. options.flags = {};
  896. }
  897. options.flags = markovUtils.mergeFlags(options.flags, options.flagsStr);
  898. // Parse each sample.
  899. for(var i = 0; i < input.length; ++i) {
  900. var sample = input[i];
  901. var l = sample.length;
  902. // The code doesn't work with names shorter than 3 letters.
  903. if(sample.length < 3) {
  904. continue;
  905. }
  906. // Learn letter frequency rules from sample.
  907. lfRules.learn(sample);
  908. // Length frequency
  909. while(r.lf.length <= sample.length - 3) {
  910. r.lf.push(0);
  911. }
  912. ++r.lf[sample.length - 3];
  913. ++r.lfTotal;
  914. // Beginning
  915. if(sample.length > 4) {
  916. r.starts.push({
  917. l: l,
  918. s: sample.substring(0, 3)
  919. });
  920. } else {
  921. r.starts.push({
  922. l: l,
  923. s: sample.substring(0, 2)
  924. });
  925. }
  926. // Middle
  927. for(var j = 2; j < l - 1; ++j) {
  928. var mid = {
  929. ch: sample.charAt(j),
  930. l: l
  931. };
  932. if(j > 2) {
  933. markovUtils.getArray(r.mids, sample.substring(j - 3, j)).push(mid);
  934. }
  935. markovUtils.getArray(r.mids, sample.substring(j - 2, j)).push(mid);
  936. }
  937. // ends
  938. var end = {
  939. ch: sample.charAt(l - 1),
  940. l: l
  941. };
  942. if(sample.length > 4) {
  943. markovUtils.getArray(r.ends, sample.substring(l - 4, l - 1)).push(end);
  944. }
  945. markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).push(end);
  946. //console.log(sample + ' ' + sample.substring(l - 3, l - 1) + '-' + end.ch + ' ' + markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).length);
  947. }
  948. return r;
  949. },
  950. initTemp: function(data, options, lfRules) {
  951. // Reconstructs samples for avoid-sample rule
  952. var results = [];
  953. var indexMap1 = {};
  954. var indexMap2 = {};
  955. var getIndex = markovUtils.getIndex;
  956. for(var i = 0; i < data.starts.length; ++i) {
  957. var start = data.starts[i];
  958. var name = start.s.substring(0, 2);
  959. var length = start.l;
  960. var key, set, indexMap, index;
  961. for(var j = name.length; j < length; ++j) {
  962. set = ((j < length - 1) ? data.mids : data.ends);
  963. indexMap = ((j < length - 1) ? indexMap1 : indexMap2);
  964. key = name.substring(name.length - 2);
  965. if(set.hasOwnProperty(key)) {
  966. index = getIndex(indexMap, key);
  967. //console.log(index + ' ' + name + ' ' + key + ' ' + (set == data.mids) + ' ' + JSON.stringify(set[key]));
  968. name += set[key][index].ch;
  969. } else {
  970. console.log(name + ' ' + key + ' ' + length);
  971. }
  972. }
  973. results.push(name);
  974. }
  975. // Enforce lfoverride
  976. if(options.hasOwnProperty('lfOverrides')) {
  977. var keys = Object.keys(options.lfOverrides);
  978. for(var i = 0; i < keys.length; ++i) {
  979. lfRules.counts[keys[i]] = options.lfOverrides[keys[i]];
  980. }
  981. }
  982. return results;
  983. },
  984. generate: function(data, randomFunction, lfRules, options, temp) {
  985. // INITIALIZE and START
  986. var result = "";
  987. var f = options.flags;
  988. var globalRuns = 0;
  989. while(globalRuns++ < 100) {
  990. var runs = 0;
  991. var start = markovUtils.pick(randomFunction, data.starts);
  992. var length = start.l;
  993. var slength = start.s.length;
  994. var tight = false;
  995. result = start.s;
  996. // If start shouldn't be length restricted, pick a random length.
  997. if(!f.lrs) {
  998. length = markovUtils.getRandomLength(data.lf, data.lfTotal, randomFunction);
  999. if(length <= 4 && slength > 2) {
  1000. result = start.s.substring(0, 2);
  1001. }
  1002. }
  1003. // Make the rest of the name, letter by letter.
  1004. while(result.length < length) {
  1005. var key, opts, validOpts;
  1006. ++runId;
  1007. var set = ((result.length < length - 1) ? data.mids : data.ends);
  1008. var lrFlag = ((result.length < length - 1) ? f.lrm : f.lre);
  1009. // ATTEMPT: 3rd order options
  1010. if(result.length >= 3 && (!f.f2o || f.f3o)) {
  1011. key = result.substring(result.length - 3, result.length);
  1012. opts = set[key];
  1013. validOpts = [];
  1014. if(typeof(opts) !== 'undefined') {
  1015. for(var i = 0; i < opts.length; ++i) {
  1016. // If (needs third order AND option fits)
  1017. if(markovUtils.checkThirdOrder(result, opts[i], f, options)
  1018. && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
  1019. validOpts.push(opts[i]);
  1020. }
  1021. }
  1022. }
  1023. if(validOpts.length > 0) {
  1024. var opt = markovUtils.pick(randomFunction, validOpts);
  1025. result += opt.ch;
  1026. continue;
  1027. }
  1028. }
  1029. // ATTEMPT: 2nd order options
  1030. if(!f.f3o) {
  1031. key = result.substring(result.length - 2, result.length);
  1032. opts = set[key];
  1033. validOpts = [];
  1034. if(typeof(opts) !== 'undefined') {
  1035. for(var i = 0; i < opts.length; ++i) {
  1036. if(!markovUtils.checkThirdOrder(result, opts[i], f, options)
  1037. && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
  1038. validOpts.push(opts[i]);
  1039. }
  1040. }
  1041. }
  1042. if(validOpts.length > 0) {
  1043. var opt = markovUtils.pick(randomFunction, validOpts);
  1044. result += opt.ch;
  1045. continue;
  1046. }
  1047. }
  1048. // LAST RESORT: Cut off the last one and try again
  1049. if(result.length > slength) {
  1050. result = start.s;
  1051. }
  1052. if(++runs > 32) {
  1053. result = null;
  1054. break;
  1055. }
  1056. }
  1057. if(result != null) {
  1058. return result;
  1059. }
  1060. }
  1061. }
  1062. }
  1063. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  1064. module.exports = algo;
  1065. } else {
  1066. algos[algo.id] = algo;
  1067. }
  1068. var algo = {
  1069. id: "select",
  1070. name: "Simple Random Selection",
  1071. parseList: function(input) {
  1072. return input;
  1073. },
  1074. initTemp: function(data) {
  1075. return null;
  1076. },
  1077. generate: function(data, randomFunction) {
  1078. return data[Math.floor(randomFunction() * data.length)];
  1079. }
  1080. }
  1081. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  1082. module.exports = algo;
  1083. } else {
  1084. algos[algo.id] = algo;
  1085. }
  1086. var algo = {
  1087. id: "syllables",
  1088. name: "Syllable Concateration",
  1089. parseList: function(input, options, lfRules) {
  1090. var r = {
  1091. positions: [0],
  1092. groups: [].concat(input),
  1093. size: 0
  1094. };
  1095. for(var i = 0; i < r.groups.length; ++i) {
  1096. var group = r.groups[i];
  1097. if(group.headers.length >= 2) {
  1098. group.weigthMultiplier = parseFloat(group.headers[1]);
  1099. } else {
  1100. group.weigthMultiplier = 1;
  1101. }
  1102. if(group.lines.length <= 1) {
  1103. console.error('SKIPPED "' + group.id + '" (length <= 1)');
  1104. r.groups.splice(i, 1);
  1105. --i;
  1106. continue;
  1107. }
  1108. group.width = group.lines[0].length;
  1109. for(var j = 0; j < group.lines.length; ++j) {
  1110. var line = group.lines[j];
  1111. if(line.length !== group.width) {
  1112. console.error(JSON.stringify(group));
  1113. throw new Error("The line " + JSON.stringify(line) + " is not as long as the others in the group ("+group.width+"). No non-conformism!. D:<");
  1114. }
  1115. lfRules.learn(line.join(''));
  1116. }
  1117. var size = group.lines.length * group.width * group.weigthMultiplier;
  1118. r.size += size;
  1119. r.positions.push(r.size);
  1120. }
  1121. return r;
  1122. },
  1123. initTemp: function(data, options, lfRules) {
  1124. var samples = {};
  1125. // Reconstruct samples
  1126. for(var i = 0; i < data.groups.length; ++i) {
  1127. var group = data.groups[i];
  1128. for(var j = 0; j < group.lines.length; ++j) {
  1129. samples[group.lines[j].join('')] = true;
  1130. }
  1131. }
  1132. // Enforce lfoverride
  1133. if(options.hasOwnProperty('lfOverrides')) {
  1134. var keys = Object.keys(options.lfOverrides);
  1135. for(var i = 0; i < keys.length; ++i) {
  1136. lfRules.counts[keys[i]] = options.lfOverrides[keys[i]];
  1137. }
  1138. }
  1139. return samples;
  1140. },
  1141. generate: function(data, randomFunction, lfRules, options, temp) {
  1142. var rand = randomFunction() * data.size;
  1143. var group = null;
  1144. for(var i = 0; i < data.groups.length - 1; ++i) {
  1145. if(rand < data.positions[i + 1]) {
  1146. group = data.groups[i];
  1147. break;
  1148. }
  1149. }
  1150. if(group == null || group == undefined) {
  1151. group = data.groups[data.groups.length - 1];
  1152. }
  1153. var optionAsls = true;
  1154. if(options.hasOwnProperty('asls')) {
  1155. optionAsls = options.asls;
  1156. }
  1157. var result = [];
  1158. var lines = group.lines;
  1159. var prev = null;
  1160. while(result.length < group.width) {
  1161. var i = result.length;
  1162. rand = Math.floor(randomFunction() * group.lines.length);
  1163. var pick = group.lines[rand][i];
  1164. result.push(pick);
  1165. var fail = false;
  1166. // Respect letter frequency rules
  1167. if(!lfRules.check(result.join(''))) {
  1168. fail = true;
  1169. }
  1170. // Avoid same letter syllables
  1171. if(!fail && optionAsls && i > 0
  1172. && (pick.charAt(0) === result[i - 1].charAt(0))) {
  1173. fail = true;
  1174. }
  1175. // Avoid samples, but permit close samples.
  1176. if(!fail && (i === group.width - 1) && temp.hasOwnProperty(result.join(''))) {
  1177. fail = true;
  1178. }
  1179. if(fail) {
  1180. if(pick === prev) {
  1181. result = [];
  1182. if(group.lines.length <= group.width) {
  1183. var group = null;
  1184. for(var i = 0; i < data.groups.length - 1; ++i) {
  1185. if(rand < data.positions[i + 1]) {
  1186. group = data.groups[i];
  1187. break;
  1188. }
  1189. }
  1190. if(group == null || group == undefined) {
  1191. group = data.groups[data.groups.length - 1];
  1192. }
  1193. }
  1194. prev = null;
  1195. } else {
  1196. prev = pick;
  1197. result.pop();
  1198. }
  1199. }
  1200. }
  1201. return result.join('');
  1202. }
  1203. }
  1204. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  1205. module.exports = algo;
  1206. } else {
  1207. algos[algo.id] = algo;
  1208. }
  1209. var loader = {
  1210. id: "fullname",
  1211. name: "Full Name",
  1212. load: function(tokens, lists, options) {
  1213. var skip = 'NONE';
  1214. var listIds = options.list;
  1215. var replaces = null;
  1216. // Get skip token (for when you just have a last name)
  1217. if(options.hasOwnProperty('skip')) {
  1218. skip = options.skip[0];
  1219. }
  1220. // Check if replacements should be done.
  1221. if(options.hasOwnProperty('replace')) {
  1222. replaces = options.replace;
  1223. }
  1224. // Add the tokens to the right list.
  1225. for(var i = 0; i < tokens.length; ++i) {
  1226. var token = tokens[i];
  1227. if(token === skip) {
  1228. continue;
  1229. }
  1230. if(i >= listIds.length) {
  1231. break;
  1232. }
  1233. token = token.toLowerCase();
  1234. if(replaces !== null) {
  1235. for(var j = 0; j < replaces.length; j += 2) {
  1236. var fromChars = replaces[j];
  1237. while(token.indexOf(fromChars) != -1) {
  1238. token = token.replace(fromChars, replaces[j + 1]);
  1239. }
  1240. }
  1241. }
  1242. var listId = listIds[i];
  1243. if(!lists.hasOwnProperty(listId)) {
  1244. lists[listId] = [];
  1245. }
  1246. lists[listId].push(token);
  1247. }
  1248. }
  1249. }
  1250. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  1251. module.exports = loader;
  1252. } else {
  1253. loaders[loader.id] = loader;
  1254. }
  1255. var nextId = 0;
  1256. var loader = {
  1257. id: "tokens",
  1258. name: "Tokenized Part",
  1259. load: function(tokens, lists, options) {
  1260. var headers = options.group;
  1261. var listId = options.list[0];
  1262. var groupId = headers;
  1263. var list = null, group = null;
  1264. // Ensure the list exists, and select it.
  1265. if(!lists.hasOwnProperty(listId)) {
  1266. lists[listId] = [];
  1267. }
  1268. list = lists[listId];
  1269. // Join the name for lowercasing
  1270. var name = tokens.join(' ').toLowerCase();
  1271. // Before splitting it back up, do replacing if requested.
  1272. if(options.hasOwnProperty('replace')) {
  1273. var replaces = options.replace;
  1274. for(var i = 0; i < replaces.length; i += 2) {
  1275. var fromChars = replaces[i];
  1276. while(name.indexOf(fromChars) != -1) {
  1277. name = name.replace(fromChars, replaces[i + 1]);
  1278. }
  1279. }
  1280. }
  1281. // Split the name again
  1282. tokens = name.split(' ');
  1283. // Get group name
  1284. if(options.hasOwnProperty('idtoken')) {
  1285. if(options.idtoken === 'ALL') {
  1286. groupId = headers.join(' ');
  1287. } else if(options.idtoken === 'ANON') {
  1288. groupId = '.anonymous' + (nextId++);
  1289. } else {
  1290. groupId = headers[parseInt(options.idtoken)];
  1291. }
  1292. }
  1293. // Try find group
  1294. for(var i = 0; i < list.length; ++i) {
  1295. if(list[i].id == groupId) {
  1296. group = list[i];
  1297. break;
  1298. }
  1299. }
  1300. // If unsuccessful, make the group.
  1301. if(group === null) {
  1302. group = {
  1303. id: groupId,
  1304. headers: headers,
  1305. lines: []
  1306. }
  1307. list.push(group);
  1308. }
  1309. // Add the tokens to the group.
  1310. group.lines.push(tokens);
  1311. }
  1312. }
  1313. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  1314. module.exports = loader;
  1315. } else {
  1316. loaders[loader.id] = loader;
  1317. }
  1318. // This file is made from automatically concaterad and filtered node.js scripts.
  1319. // ngn4 is open source, and provided under an MIT licence
  1320. // See https://github.com/gissleh/ngn4 for more details.
  1321. // Copyright (c) 2015 Gisle Aune"use strict";
  1322. var algos = {};
  1323. var loaders = {};
  1324. var grammarUtils = {
  1325. pick: function(array, randomFunction) {
  1326. return array[Math.floor(randomFunction() * array.length)];
  1327. }
  1328. }
  1329. var algo = {
  1330. id: "grammar",
  1331. name: "Grammar",
  1332. parseList: function(input, options, lfRules) {
  1333. var r = {
  1334. positions: [0],
  1335. words: [],
  1336. symbols: {},
  1337. size: 0
  1338. };
  1339. for(var i = 0; i < input.length; ++i) {
  1340. var group = input[i];
  1341. var headers = group.headers;
  1342. var lines = group.lines;
  1343. // Ensure sets exists.
  1344. for(var j = 0; j < headers.length; ++j) {
  1345. var header = headers[j];
  1346. if(!r.symbols.hasOwnProperty(header)) {
  1347. r.symbols[header] = [];
  1348. }
  1349. }
  1350. // Parse lines to add to sets
  1351. for(var j = 0; j < lines.length; ++j) {
  1352. var tokens = lines[j];
  1353. lfRules.learn(tokens.join(''));
  1354. for(var k = 0; k < tokens.length; ++k) {
  1355. var token = tokens[k];
  1356. var header = headers[k];
  1357. r.symbols[header].push(token);
  1358. }
  1359. }
  1360. r.words.push({f: headers, l: lines.length});
  1361. r.size += lines.length;
  1362. r.positions.push(r.size);
  1363. }
  1364. for(var i = 0; i < r.words.length; ++i) {
  1365. var word = r.words[i];
  1366. if(word.l > 1) {
  1367. continue;
  1368. }
  1369. var strikes = 0;
  1370. for(var j = 0; j < word.f.length; ++j) {
  1371. var symbol = word.f[j];
  1372. if(r.symbols[symbol].length <= word.l) {
  1373. ++strikes;
  1374. }
  1375. }
  1376. if(strikes === word.f.length) {
  1377. r.words.splice(i, 1);
  1378. console.error('\tSKIPPED "'+word.f.join(' ')+'" (length <= 1)');
  1379. }
  1380. }
  1381. return r;
  1382. },
  1383. initTemp: function(data, options, lfRules) {
  1384. // Reconstruct samples
  1385. var words = data.words;
  1386. var symbols = data.symbols;
  1387. var results = [];
  1388. var indices = {};
  1389. var symbolKeys = Object.keys(symbols);
  1390. // Set up the indices array
  1391. for(var i = 0; i < symbolKeys.length; ++i) {
  1392. indices[symbolKeys[i]] = 0;
  1393. }
  1394. for(var i = 0; i < words.length; ++i) {
  1395. var word = words[i];
  1396. for(var j = 0; j < word.l; ++j) {
  1397. var name = "";
  1398. for(var k = 0; k < word.f.length; ++k) {
  1399. var symbol = word.f[k];
  1400. var index = indices[symbol]++;
  1401. name += symbols[symbol][index];
  1402. }
  1403. results.push(name);
  1404. }
  1405. }
  1406. // Enforce lfoverride
  1407. if(options.hasOwnProperty('lfOverrides')) {
  1408. var keys = Object.keys(options.lfOverrides);
  1409. for(var i = 0; i < keys.length; ++i) {
  1410. lfRules.counts[keys[i]] = options.lfOverrides[keys[i]];
  1411. }
  1412. }
  1413. return results;
  1414. },
  1415. generate: function(data, randomFunction, lfRules, options, temp) {
  1416. var word = null;
  1417. var result = [];
  1418. var prev = null;
  1419. var r = Math.floor(randomFunction() * data.size);
  1420. for(var i = 0; i < data.words.length; ++i) {
  1421. if(r < data.positions[i + 1]) {
  1422. word = data.words[i];
  1423. break;
  1424. }
  1425. }
  1426. if(word === null) {
  1427. word = data.words[data.words.length - 1];
  1428. }
  1429. while(result.length < word.f.length) {
  1430. var i = result.length;
  1431. var symbol = word.f[i];
  1432. var pick = grammarUtils.pick(data.symbols[symbol], randomFunction);
  1433. var fail = false;
  1434. var name;
  1435. result.push(pick);
  1436. name = result.join('');
  1437. if(!lfRules.check(name)) {
  1438. fail = true;
  1439. }
  1440. if(!fail && temp.indexOf(name) !== -1) {
  1441. fail = true;
  1442. }
  1443. if(fail) {
  1444. if(prev === pick) {
  1445. prev = null;
  1446. // If word's wieght is smaller than symbol count,
  1447. // retry with another word. This is to prevent crashing
  1448. if(word.l <= word.f.length) {
  1449. var r = Math.floor(randomFunction() * data.size);
  1450. word = null;
  1451. for(var i = 0; i < data.words.length; ++i) {
  1452. if(r < data.positions[i + 1]) {
  1453. word = data.words[i];
  1454. break;
  1455. }
  1456. }
  1457. if(word === null) {
  1458. word = data.words[data.words.length - 1];
  1459. }
  1460. }
  1461. result = [];
  1462. } else {
  1463. prev = pick;
  1464. result.pop();
  1465. }
  1466. }
  1467. }
  1468. return result.join('');
  1469. }
  1470. }
  1471. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  1472. module.exports = algo;
  1473. } else {
  1474. algos[algo.id] = algo;
  1475. }
  1476. var markovUtils = {};
  1477. var runId = 0;
  1478. markovUtils.mergeFlags = function(flags, flagsStr) {
  1479. var result = {
  1480. lrs: false,
  1481. lrm: false,
  1482. lre: false,
  1483. f2o: false,
  1484. f3o: false,
  1485. to2c: false,
  1486. to2v: false,
  1487. todc: false,
  1488. todv: false,
  1489. lrf: false,
  1490. as: false
  1491. }
  1492. if(typeof(flags) !== 'string') {
  1493. var keys = Object.keys(flags);
  1494. for(var i = 0; i < keys.length; ++i) {
  1495. result[keys[i]] = flags[keys[i]];
  1496. }
  1497. } else {
  1498. flagsStr = flags;
  1499. }
  1500. if(typeof(flagsStr) !== 'undefined') {
  1501. var flagSplit = flagsStr.split(' ');
  1502. for(var i = 0; i < flagSplit.length; ++i) {
  1503. result[flagSplit[i]] = true;
  1504. }
  1505. }
  1506. return result;
  1507. }
  1508. markovUtils.pick = function(rfunc, array) {
  1509. return array[Math.floor(rfunc() * array.length)];
  1510. }
  1511. markovUtils.getArray = function(obj, prop) {
  1512. if(!obj.hasOwnProperty(prop)) {
  1513. obj[prop] = [];
  1514. }
  1515. return obj[prop];
  1516. }
  1517. markovUtils.getIndex = function(obj, prop) {
  1518. if(!obj.hasOwnProperty(prop)) {
  1519. obj[prop] = 0;
  1520. }
  1521. return obj[prop]++;
  1522. }
  1523. markovUtils.getRandomLength = function(array, total, randomFunction) {
  1524. var r = Math.floor(randomFunction() * total);
  1525. for(var i = 1; i < array.length; ++i) {
  1526. r -= array[i];
  1527. if(r < 0) {
  1528. return i + 3;
  1529. }
  1530. }
  1531. // 4 1 3 1
  1532. return array.length + 1;
  1533. }
  1534. markovUtils.checkThirdOrder = function(result, option, flags, options) {
  1535. if(flags.f3o) {
  1536. return true;
  1537. }
  1538. var vowels;
  1539. if(options.hasOwnProperty('vowels')) {
  1540. vowels = options.vowels;
  1541. } else {
  1542. vowels = "aeiouy";
  1543. }
  1544. var prev1 = result[result.length - 1];
  1545. var prev2 = result[result.length - 2];
  1546. if(flags.todc && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) === -1)) {
  1547. return true;
  1548. }
  1549. if(flags.to2c && (result.length > 2) && (vowels.indexOf(prev1) === -1) && (vowels.indexOf(prev2) === -1)) {
  1550. return true;
  1551. }
  1552. if(flags.todv && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) !== -1)) {
  1553. return true;
  1554. }
  1555. if(flags.to2v && (result.length > 2) && (vowels.indexOf(prev1) !== -1) && (vowels.indexOf(prev2) !== -1)) {
  1556. return true;
  1557. }
  1558. return false;
  1559. }
  1560. markovUtils.checkNext = function(result, option, length, flags, lrFlag, lfRules, samples) {
  1561. var next = result + option.ch;
  1562. if(flags.as && (next.length == length) && (samples.indexOf(next) !== -1)) {
  1563. return false;
  1564. }
  1565. if(lrFlag && option.l != length) {
  1566. return false;
  1567. }
  1568. if(flags.rlf && !lfRules.check(next)) {
  1569. return false;
  1570. }
  1571. return true;
  1572. }
  1573. /*
  1574. +-------------------------------------------------+
  1575. | GENERATOR FLAGS |
  1576. +---+--------+------------------------------------+
  1577. | X | lrs | Length restriction on start, mid, |
  1578. | X | lrm | and/or end rules the length of the |
  1579. | X | lre | rule's source sample |
  1580. +---+--------+------------------------------------+
  1581. | X | f2o | Force 2nd or 3rd order chain. f3o |
  1582. | X | f3o | override f2o if both are set |
  1583. +---+--------+------------------------------------+
  1584. | X | to2c | Third order on 2 consonants |
  1585. | X | to2v | and/or vowels |
  1586. +---+--------+------------------------------------+
  1587. | X | todc | Third order on double consonants |
  1588. | X | todv | and/or vowels |
  1589. +---+--------+------------------------------------+
  1590. | X | rlf | Restrict letter frequency |
  1591. +---+--------+------------------------------------+
  1592. | X | as | Avoid samples being generated |
  1593. +---+--------+------------------------------------+
  1594. */
  1595. var algo = {
  1596. id: "markov",
  1597. name: "Markov",
  1598. parseList: function(input, options, lfRules) {
  1599. var r = { // Examples after "aeyna"
  1600. starts: [], // [{s: 'aey', l: 5}]
  1601. mids: {}, // {"ey": [{l: 5, ch: 'n'}], "aey": [{l: 5, ch: 'n'}]}
  1602. ends: {}, // {"eyn": [{l: 5, ch: 'a'}]}
  1603. lf: [], // [0, 0, 1],
  1604. lfTotal: 0
  1605. }
  1606. // FLAGS
  1607. if(!options.hasOwnProperty('flags')) {
  1608. options.flags = {};
  1609. }
  1610. options.flags = markovUtils.mergeFlags(options.flags, options.flagsStr);
  1611. // Parse each sample.
  1612. for(var i = 0; i < input.length; ++i) {
  1613. var sample = input[i];
  1614. var l = sample.length;
  1615. // The code doesn't work with names shorter than 3 letters.
  1616. if(sample.length < 3) {
  1617. continue;
  1618. }
  1619. // Learn letter frequency rules from sample.
  1620. lfRules.learn(sample);
  1621. // Length frequency
  1622. while(r.lf.length <= sample.length - 3) {
  1623. r.lf.push(0);
  1624. }
  1625. ++r.lf[sample.length - 3];
  1626. ++r.lfTotal;
  1627. // Beginning
  1628. if(sample.length > 4) {
  1629. r.starts.push({
  1630. l: l,
  1631. s: sample.substring(0, 3)
  1632. });
  1633. } else {
  1634. r.starts.push({
  1635. l: l,
  1636. s: sample.substring(0, 2)
  1637. });
  1638. }
  1639. // Middle
  1640. for(var j = 2; j < l - 1; ++j) {
  1641. var mid = {
  1642. ch: sample.charAt(j),
  1643. l: l
  1644. };
  1645. if(j > 2) {
  1646. markovUtils.getArray(r.mids, sample.substring(j - 3, j)).push(mid);
  1647. }
  1648. markovUtils.getArray(r.mids, sample.substring(j - 2, j)).push(mid);
  1649. }
  1650. // ends
  1651. var end = {
  1652. ch: sample.charAt(l - 1),
  1653. l: l
  1654. };
  1655. if(sample.length > 4) {
  1656. markovUtils.getArray(r.ends, sample.substring(l - 4, l - 1)).push(end);
  1657. }
  1658. markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).push(end);
  1659. //console.log(sample + ' ' + sample.substring(l - 3, l - 1) + '-' + end.ch + ' ' + markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).length);
  1660. }
  1661. return r;
  1662. },
  1663. initTemp: function(data, options, lfRules) {
  1664. // Reconstructs samples for avoid-sample rule
  1665. var results = [];
  1666. var indexMap1 = {};
  1667. var indexMap2 = {};
  1668. var getIndex = markovUtils.getIndex;
  1669. for(var i = 0; i < data.starts.length; ++i) {
  1670. var start = data.starts[i];
  1671. var name = start.s.substring(0, 2);
  1672. var length = start.l;
  1673. var key, set, indexMap, index;
  1674. for(var j = name.length; j < length; ++j) {
  1675. set = ((j < length - 1) ? data.mids : data.ends);
  1676. indexMap = ((j < length - 1) ? indexMap1 : indexMap2);
  1677. key = name.substring(name.length - 2);
  1678. if(set.hasOwnProperty(key)) {
  1679. index = getIndex(indexMap, key);
  1680. //console.log(index + ' ' + name + ' ' + key + ' ' + (set == data.mids) + ' ' + JSON.stringify(set[key]));
  1681. name += set[key][index].ch;
  1682. } else {
  1683. console.log(name + ' ' + key + ' ' + length);
  1684. }
  1685. }
  1686. results.push(name);
  1687. }
  1688. // Enforce lfoverride
  1689. if(options.hasOwnProperty('lfOverrides')) {
  1690. var keys = Object.keys(options.lfOverrides);
  1691. for(var i = 0; i < keys.length; ++i) {
  1692. lfRules.counts[keys[i]] = options.lfOverrides[keys[i]];
  1693. }
  1694. }
  1695. return results;
  1696. },
  1697. generate: function(data, randomFunction, lfRules, options, temp) {
  1698. // INITIALIZE and START
  1699. var result = "";
  1700. var f = options.flags;
  1701. var globalRuns = 0;
  1702. while(globalRuns++ < 100) {
  1703. var runs = 0;
  1704. var start = markovUtils.pick(randomFunction, data.starts);
  1705. var length = start.l;
  1706. var slength = start.s.length;
  1707. var tight = false;
  1708. result = start.s;
  1709. // If start shouldn't be length restricted, pick a random length.
  1710. if(!f.lrs) {
  1711. length = markovUtils.getRandomLength(data.lf, data.lfTotal, randomFunction);
  1712. if(length <= 4 && slength > 2) {
  1713. result = start.s.substring(0, 2);
  1714. }
  1715. }
  1716. // Make the rest of the name, letter by letter.
  1717. while(result.length < length) {
  1718. var key, opts, validOpts;
  1719. ++runId;
  1720. var set = ((result.length < length - 1) ? data.mids : data.ends);
  1721. var lrFlag = ((result.length < length - 1) ? f.lrm : f.lre);
  1722. // ATTEMPT: 3rd order options
  1723. if(result.length >= 3 && (!f.f2o || f.f3o)) {
  1724. key = result.substring(result.length - 3, result.length);
  1725. opts = set[key];
  1726. validOpts = [];
  1727. if(typeof(opts) !== 'undefined') {
  1728. for(var i = 0; i < opts.length; ++i) {
  1729. // If (needs third order AND option fits)
  1730. if(markovUtils.checkThirdOrder(result, opts[i], f, options)
  1731. && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
  1732. validOpts.push(opts[i]);
  1733. }
  1734. }
  1735. }
  1736. if(validOpts.length > 0) {
  1737. var opt = markovUtils.pick(randomFunction, validOpts);
  1738. result += opt.ch;
  1739. continue;
  1740. }
  1741. }
  1742. // ATTEMPT: 2nd order options
  1743. if(!f.f3o) {
  1744. key = result.substring(result.length - 2, result.length);
  1745. opts = set[key];
  1746. validOpts = [];
  1747. if(typeof(opts) !== 'undefined') {
  1748. for(var i = 0; i < opts.length; ++i) {
  1749. if(!markovUtils.checkThirdOrder(result, opts[i], f, options)
  1750. && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
  1751. validOpts.push(opts[i]);
  1752. }
  1753. }
  1754. }
  1755. if(validOpts.length > 0) {
  1756. var opt = markovUtils.pick(randomFunction, validOpts);
  1757. result += opt.ch;
  1758. continue;
  1759. }
  1760. }
  1761. // LAST RESORT: Cut off the last one and try again
  1762. if(result.length > slength) {
  1763. result = start.s;
  1764. }
  1765. if(++runs > 32) {
  1766. result = null;
  1767. break;
  1768. }
  1769. }
  1770. if(result != null) {
  1771. return result;
  1772. }
  1773. }
  1774. }
  1775. }
  1776. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  1777. module.exports = algo;
  1778. } else {
  1779. algos[algo.id] = algo;
  1780. }
  1781. var algo = {
  1782. id: "select",
  1783. name: "Simple Random Selection",
  1784. parseList: function(input) {
  1785. return input;
  1786. },
  1787. initTemp: function(data) {
  1788. return null;
  1789. },
  1790. generate: function(data, randomFunction) {
  1791. return data[Math.floor(randomFunction() * data.length)];
  1792. }
  1793. }
  1794. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  1795. module.exports = algo;
  1796. } else {
  1797. algos[algo.id] = algo;
  1798. }
  1799. var algo = {
  1800. id: "syllables",
  1801. name: "Syllable Concateration",
  1802. parseList: function(input, options, lfRules) {
  1803. var r = {
  1804. positions: [0],
  1805. groups: [].concat(input),
  1806. size: 0
  1807. };
  1808. for(var i = 0; i < r.groups.length; ++i) {
  1809. var group = r.groups[i];
  1810. if(group.headers.length >= 2) {
  1811. group.weigthMultiplier = parseFloat(group.headers[1]);
  1812. } else {
  1813. group.weigthMultiplier = 1;
  1814. }
  1815. if(group.lines.length <= 1) {
  1816. console.error('SKIPPED "' + group.id + '" (length <= 1)');
  1817. r.groups.splice(i, 1);
  1818. --i;
  1819. continue;
  1820. }
  1821. group.width = group.lines[0].length;
  1822. for(var j = 0; j < group.lines.length; ++j) {
  1823. var line = group.lines[j];
  1824. if(line.length !== group.width) {
  1825. console.error(JSON.stringify(group));
  1826. throw new Error("The line " + JSON.stringify(line) + " is not as long as the others in the group ("+group.width+"). No non-conformism!. D:<");
  1827. }
  1828. lfRules.learn(line.join(''));
  1829. }
  1830. var size = group.lines.length * group.width * group.weigthMultiplier;
  1831. r.size += size;
  1832. r.positions.push(r.size);
  1833. }
  1834. return r;
  1835. },
  1836. initTemp: function(data, options, lfRules) {
  1837. var samples = {};
  1838. // Reconstruct samples
  1839. for(var i = 0; i < data.groups.length; ++i) {
  1840. var group = data.groups[i];
  1841. for(var j = 0; j < group.lines.length; ++j) {
  1842. samples[group.lines[j].join('')] = true;
  1843. }
  1844. }
  1845. // Enforce lfoverride
  1846. if(options.hasOwnProperty('lfOverrides')) {
  1847. var keys = Object.keys(options.lfOverrides);
  1848. for(var i = 0; i < keys.length; ++i) {
  1849. lfRules.counts[keys[i]] = options.lfOverrides[keys[i]];
  1850. }
  1851. }
  1852. return samples;
  1853. },
  1854. generate: function(data, randomFunction, lfRules, options, temp) {
  1855. var rand = randomFunction() * data.size;
  1856. var group = null;
  1857. for(var i = 0; i < data.groups.length - 1; ++i) {
  1858. if(rand < data.positions[i + 1]) {
  1859. group = data.groups[i];
  1860. break;
  1861. }
  1862. }
  1863. if(group == null || group == undefined) {
  1864. group = data.groups[data.groups.length - 1];
  1865. }
  1866. var optionAsls = true;
  1867. if(options.hasOwnProperty('asls')) {
  1868. optionAsls = options.asls;
  1869. }
  1870. var result = [];
  1871. var lines = group.lines;
  1872. var prev = null;
  1873. while(result.length < group.width) {
  1874. var i = result.length;
  1875. rand = Math.floor(randomFunction() * group.lines.length);
  1876. var pick = group.lines[rand][i];
  1877. result.push(pick);
  1878. var fail = false;
  1879. // Respect letter frequency rules
  1880. if(!lfRules.check(result.join(''))) {
  1881. fail = true;
  1882. }
  1883. // Avoid same letter syllables
  1884. if(!fail && optionAsls && i > 0
  1885. && (pick.charAt(0) === result[i - 1].charAt(0))) {
  1886. fail = true;
  1887. }
  1888. // Avoid samples, but permit close samples.
  1889. if(!fail && (i === group.width - 1) && temp.hasOwnProperty(result.join(''))) {
  1890. fail = true;
  1891. }
  1892. if(fail) {
  1893. if(pick === prev) {
  1894. result = [];
  1895. if(group.lines.length <= group.width) {
  1896. var group = null;
  1897. for(var i = 0; i < data.groups.length - 1; ++i) {
  1898. if(rand < data.positions[i + 1]) {
  1899. group = data.groups[i];
  1900. break;
  1901. }
  1902. }
  1903. if(group == null || group == undefined) {
  1904. group = data.groups[data.groups.length - 1];
  1905. }
  1906. }
  1907. prev = null;
  1908. } else {
  1909. prev = pick;
  1910. result.pop();
  1911. }
  1912. }
  1913. }
  1914. return result.join('');
  1915. }
  1916. }
  1917. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  1918. module.exports = algo;
  1919. } else {
  1920. algos[algo.id] = algo;
  1921. }
  1922. var loader = {
  1923. id: "fullname",
  1924. name: "Full Name",
  1925. load: function(tokens, lists, options) {
  1926. var skip = 'NONE';
  1927. var listIds = options.list;
  1928. var replaces = null;
  1929. // Get skip token (for when you just have a last name)
  1930. if(options.hasOwnProperty('skip')) {
  1931. skip = options.skip[0];
  1932. }
  1933. // Check if replacements should be done.
  1934. if(options.hasOwnProperty('replace')) {
  1935. replaces = options.replace;
  1936. }
  1937. // Add the tokens to the right list.
  1938. for(var i = 0; i < tokens.length; ++i) {
  1939. var token = tokens[i];
  1940. if(token === skip) {
  1941. continue;
  1942. }
  1943. if(i >= listIds.length) {
  1944. break;
  1945. }
  1946. token = token.toLowerCase();
  1947. if(replaces !== null) {
  1948. for(var j = 0; j < replaces.length; j += 2) {
  1949. var fromChars = replaces[j];
  1950. while(token.indexOf(fromChars) != -1) {
  1951. token = token.replace(fromChars, replaces[j + 1]);
  1952. }
  1953. }
  1954. }
  1955. var listId = listIds[i];
  1956. if(!lists.hasOwnProperty(listId)) {
  1957. lists[listId] = [];
  1958. }
  1959. lists[listId].push(token);
  1960. }
  1961. }
  1962. }
  1963. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  1964. module.exports = loader;
  1965. } else {
  1966. loaders[loader.id] = loader;
  1967. }
  1968. var nextId = 0;
  1969. var loader = {
  1970. id: "tokens",
  1971. name: "Tokenized Part",
  1972. load: function(tokens, lists, options) {
  1973. var headers = options.group;
  1974. var listId = options.list[0];
  1975. var groupId = headers;
  1976. var list = null, group = null;
  1977. // Ensure the list exists, and select it.
  1978. if(!lists.hasOwnProperty(listId)) {
  1979. lists[listId] = [];
  1980. }
  1981. list = lists[listId];
  1982. // Join the name for lowercasing
  1983. var name = tokens.join(' ').toLowerCase();
  1984. // Before splitting it back up, do replacing if requested.
  1985. if(options.hasOwnProperty('replace')) {
  1986. var replaces = options.replace;
  1987. for(var i = 0; i < replaces.length; i += 2) {
  1988. var fromChars = replaces[i];
  1989. while(name.indexOf(fromChars) != -1) {
  1990. name = name.replace(fromChars, replaces[i + 1]);
  1991. }
  1992. }
  1993. }
  1994. // Split the name again
  1995. tokens = name.split(' ');
  1996. // Get group name
  1997. if(options.hasOwnProperty('idtoken')) {
  1998. if(options.idtoken === 'ALL') {
  1999. groupId = headers.join(' ');
  2000. } else if(options.idtoken === 'ANON') {
  2001. groupId = '.anonymous' + (nextId++);
  2002. } else {
  2003. groupId = headers[parseInt(options.idtoken)];
  2004. }
  2005. }
  2006. // Try find group
  2007. for(var i = 0; i < list.length; ++i) {
  2008. if(list[i].id == groupId) {
  2009. group = list[i];
  2010. break;
  2011. }
  2012. }
  2013. // If unsuccessful, make the group.
  2014. if(group === null) {
  2015. group = {
  2016. id: groupId,
  2017. headers: headers,
  2018. lines: []
  2019. }
  2020. list.push(group);
  2021. }
  2022. // Add the tokens to the group.
  2023. group.lines.push(tokens);
  2024. }
  2025. }
  2026. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  2027. module.exports = loader;
  2028. } else {
  2029. loaders[loader.id] = loader;
  2030. }
  2031. function LFRuleSet() {
  2032. this.counts = {};
  2033. this.doubles = {};
  2034. }
  2035. LFRuleSet.prototype.learn = function(sample) {
  2036. if(sample instanceof Array) {
  2037. for(var i = 0; i < sample.length; ++i) {
  2038. this.learn(sample[i]);
  2039. }
  2040. return;
  2041. }
  2042. for(var i = 0; i < sample.length; ++i) {
  2043. var ch = sample.charAt(i);
  2044. var count = (sample.split(ch).length - 1);
  2045. if(ch == ' ') {
  2046. continue;
  2047. }
  2048. if(sample[i + 1] == ch) {
  2049. this.doubles[ch] = true;
  2050. --count;
  2051. ++i;
  2052. }
  2053. if(this.counts.hasOwnProperty(ch)) {
  2054. if(this.counts[ch] < count) {
  2055. this.counts[ch] = count;
  2056. }
  2057. } else {
  2058. this.counts[ch] = count;
  2059. }
  2060. }
  2061. };
  2062. LFRuleSet.prototype.check = function(name) {
  2063. for(var i = 0; i < name.length; ++i) {
  2064. var ch = name.charAt(i);
  2065. var count = (name.split(ch).length - 1);
  2066. if((i > 0 && name[i - 1] == ch) || (i < (name.length - 1) && name[i + 1] == ch)) {
  2067. if(this.doubles.hasOwnProperty(ch)) {
  2068. --count;
  2069. ++i;
  2070. } else {
  2071. return false;
  2072. }
  2073. }
  2074. if(ch == ' ') {
  2075. continue;
  2076. }
  2077. if(this.counts.hasOwnProperty(ch)) {
  2078. if(count > this.counts[ch]) {
  2079. return false;
  2080. }
  2081. } else {
  2082. return false;
  2083. }
  2084. }
  2085. return true;
  2086. }
  2087. LFRuleSet.prototype.export = function() {
  2088. return {
  2089. cs: this.counts,
  2090. ds: this.doubles
  2091. };
  2092. }
  2093. LFRuleSet.prototype.import = function(data) {
  2094. this.counts = data.cs;
  2095. this.doubles = data.ds;
  2096. }
  2097. LFRuleSet.prototype.getCount = function(letter) {
  2098. if(this.counts.hasOwnProperty(letter)) {
  2099. return this.counts[letter];
  2100. } else {
  2101. return 0;
  2102. }
  2103. }
  2104. LFRuleSet.prototype.isDouble = function(letter) {
  2105. return this.doubles.hasOwnProperty(letter);
  2106. }
  2107. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  2108. module.exports = LFRuleSet;
  2109. }
  2110. function NameFormat(id, name, formats) {
  2111. this.id = id;
  2112. this.name = name;
  2113. this.partIds = [];
  2114. this.replaceIds = [];
  2115. this.offsets = [0];
  2116. if(formats instanceof Array) {
  2117. this.formats = formats;
  2118. } else {
  2119. this.formats = [formats];
  2120. }
  2121. for(var i = 0; i < this.formats.length; ++i) {
  2122. var format = this.formats[i];
  2123. var start = -1;
  2124. for(var j = 0; j < format.length; ++j) {
  2125. var ch = format[j];
  2126. if(ch === '{') {
  2127. start = j + 1;
  2128. } else if(ch === '}') {
  2129. var partId = format.substring(start, j);
  2130. var split = partId.split('|');
  2131. if(split.length > 1) {
  2132. this.partIds.push(split);
  2133. } else {
  2134. this.partIds.push(partId);
  2135. }
  2136. this.replaceIds.push('{' + partId + '}');
  2137. }
  2138. }
  2139. this.offsets.push(this.partIds.length);
  2140. }
  2141. }
  2142. NameFormat.prototype.generateParts = function(parts, gender, randomFunction) {
  2143. var formats = [];
  2144. var partList = [];
  2145. var replaces = [];
  2146. if(typeof(randomFunction) === 'undefined') {
  2147. randomFunction = Math.random;
  2148. }
  2149. for(var i = 0; i < this.formats.length; ++i) {
  2150. var format = this.formats[i];
  2151. var offset = this.offsets[i];
  2152. var nextOffset = this.offsets[i + 1];
  2153. var good = true;
  2154. var validParts = [];
  2155. var validReplaces = [];
  2156. for(var j = offset; j < nextOffset; ++j) {
  2157. var partId = this.partIds[j];
  2158. var replaceId = this.replaceIds[j];
  2159. if(partId instanceof Array) {
  2160. partId = partId[Math.floor(randomFunction() * partId.length)];
  2161. }
  2162. // If a gendered part exists, use it instead (e.g. first.male)
  2163. var genderedPartId = partId + '.' + gender;
  2164. if(parts.hasOwnProperty(genderedPartId)) {
  2165. partId = genderedPartId;
  2166. }
  2167. // If possible, replace the part.
  2168. if(parts.hasOwnProperty(partId)) {
  2169. validParts.push(parts[partId]);
  2170. validReplaces.push(replaceId);
  2171. } else {
  2172. good = false;
  2173. break;
  2174. }
  2175. }
  2176. if(good) {
  2177. partList.push(validParts);
  2178. replaces.push(validReplaces);
  2179. formats.push(format);
  2180. }
  2181. }
  2182. var r = Math.floor(randomFunction() * partList.length);
  2183. var result = formats[r];
  2184. var sel = partList[r];
  2185. var replaces = replaces[r];
  2186. for(var i = 0; i < sel.length; ++i) {
  2187. result = result.replace(replaces[i], sel[i].generate(randomFunction));
  2188. }
  2189. return result;
  2190. }
  2191. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  2192. module.exports = NameFormat;
  2193. }
  2194. function NameGenerator(/*obj OR id, name*/) {
  2195. // Initialize
  2196. this.genders = null;
  2197. this.parts = {};
  2198. this.formats = {};
  2199. this.listIds = {};
  2200. this.meta = {};
  2201. // id, name arguments
  2202. if(arguments.length > 1) {
  2203. this.id = arguments[0];
  2204. this.name = arguments[1];
  2205. return;
  2206. }
  2207. var obj = arguments[0];
  2208. // object argument
  2209. this.id = obj.id;
  2210. this.name = obj.name;
  2211. this.genders = obj.genders || ["UNSPECIFIED"];
  2212. if(obj.hasOwnProperty('parts')) {
  2213. var keys = Object.keys(obj.parts);
  2214. for(var i = 0; i < keys.length; ++i) {
  2215. this.addPart(keys[i], obj.parts[keys[i]]);
  2216. }
  2217. }
  2218. if(obj.hasOwnProperty('formats')) {
  2219. var keys = Object.keys(obj.formats);
  2220. for(var i = 0; i < keys.length; ++i) {
  2221. this.addFormat(keys[i], obj.formats[keys[i]]);
  2222. }
  2223. }
  2224. if(obj.hasOwnProperty('meta')) {
  2225. this.meta = obj.meta;
  2226. }
  2227. }
  2228. NameGenerator.prototype.addPart = function(id, args) {
  2229. this.parts[id] = new NamePart(id, algos[args.algo], args.options, args.format);
  2230. if(args.hasOwnProperty('lfRules')) {
  2231. this.parts[id].lfRules.import(args.lfRules);
  2232. }
  2233. if(args.hasOwnProperty('data')) {
  2234. this.parts[id].setData(args.data);
  2235. }
  2236. if(args.hasOwnProperty('list')) {
  2237. this.listIds[id] = args.list;
  2238. }
  2239. }
  2240. NameGenerator.prototype.addFormat = function(id, args) {
  2241. this.formats[id] = new NameFormat(id, args.name, args.format);
  2242. }
  2243. NameGenerator.prototype.addListsFromLoader = function(loader) {
  2244. var keys = Object.keys(this.listIds);
  2245. for(var i = 0; i < keys.length; ++i) {
  2246. var part = this.parts[keys[i]];
  2247. if(loader.lists.hasOwnProperty(keys[i])) {
  2248. part.loadList(loader.lists[keys[i]]);
  2249. }
  2250. }
  2251. }
  2252. NameGenerator.prototype.addList = function(listId, listData) {
  2253. var keys = Object.keys(this.listIds);
  2254. for(var i = 0; i < keys.length; ++i) {
  2255. var part = this.parts[keys[i]];
  2256. if(this.listIds[part.id] === listId) {
  2257. part.loadList(listData);
  2258. }
  2259. }
  2260. }
  2261. NameGenerator.prototype.removePart = function(id) {
  2262. delete this.parts[id];
  2263. }
  2264. NameGenerator.prototype.removeFormat = function(id) {
  2265. delete this.formats[id];
  2266. }
  2267. NameGenerator.prototype.generate = function(formatId, gender, randomFunction) {
  2268. if(typeof(randomFunction) === 'undefined' || randomFunction === null) {
  2269. randomFunction = Math.random;
  2270. }
  2271. if(typeof(gender) === 'undefined' || gender == null) {
  2272. var r = Math.floor(this.genders.length * randomFunction());
  2273. gender = this.genders[r].toLowerCase();
  2274. } else {
  2275. gender = gender.toLowerCase();
  2276. }
  2277. var format, keys;
  2278. if(typeof(formatId) === 'undefined' || formatId == null) {
  2279. keys = Object.keys(this.formats);
  2280. format = this.formats[keys[0]];
  2281. for(var i = 0; i < keys.length; ++i) {
  2282. var split = keys[i].split('.');
  2283. if(split.length > 1 && split[1] === gender) {
  2284. format = this.formats[keys[i]];
  2285. break;
  2286. }
  2287. }
  2288. } else {
  2289. if(this.formats.hasOwnProperty(formatId + '.' + gender)) {
  2290. format = this.formats[formatId + '.' + gender]
  2291. } else {
  2292. format = this.formats[formatId];
  2293. }
  2294. }
  2295. if(typeof(format) === 'undefined') {
  2296. return null;
  2297. }
  2298. return format.generateParts(this.parts, gender, randomFunction);
  2299. }
  2300. NameGenerator.prototype.export = function() {
  2301. var r = {
  2302. id: this.id,
  2303. name: this.name,
  2304. genders: this.genders,
  2305. formats: {},
  2306. parts: {},
  2307. meta: this.meta
  2308. };
  2309. var keys = Object.keys(this.formats);
  2310. for(var i = 0; i < keys.length; ++i) {
  2311. var format = this.formats[keys[i]];
  2312. r.formats[keys[i]] = {
  2313. name: format.name,
  2314. format: format.formats
  2315. };
  2316. }
  2317. keys = Object.keys(this.parts);
  2318. for(var i = 0; i < keys.length; ++i) {
  2319. var part = this.parts[keys[i]];
  2320. var key = keys[i];
  2321. r.parts[key] = {
  2322. algo: part.algo.id,
  2323. options: part.options,
  2324. format: part.format.format,
  2325. lfRules: part.lfRules.export()
  2326. };
  2327. if(this.listIds.hasOwnProperty(key)) {
  2328. r.parts[key].list = this.listIds[key];
  2329. }
  2330. if(part.data !== null) {
  2331. r.parts[key].data = part.data;
  2332. }
  2333. }
  2334. return r;
  2335. }
  2336. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  2337. module.exports = NameGenerator;
  2338. }
  2339. function NameGeneratorSet() {
  2340. this.categoryNames = {};
  2341. this.categoryMetaData = {};
  2342. this.generators = {};
  2343. }
  2344. NameGeneratorSet.prototype.setCategoryName = function(id, name) {
  2345. this.categoryNames[id] = name;
  2346. }
  2347. NameGeneratorSet.prototype.setCategoryMeta = function(id, meta) {
  2348. this.categoryMetaData[id] = meta;
  2349. }
  2350. NameGeneratorSet.prototype.getMeta = function(id, key, defaultValue) {
  2351. var catId = id.split('/');
  2352. var gen = this.getGenerator(id);
  2353. if(typeof(defaultValue) === 'undefined') {
  2354. defaultValue = null;
  2355. }
  2356. if(gen !== null && gen.meta.hasOwnProperty(key)) {
  2357. return gen.meta[key];
  2358. } else if(this.categoryMetaData.hasOwnProperty(catId)) {
  2359. var catMeta = this.categoryMetaData[catId];
  2360. if(catMeta.hasOwnProperty(key)) {
  2361. return catMeta[key];
  2362. } else {
  2363. return defaultValue;
  2364. }
  2365. } else {
  2366. return defaultValue;
  2367. }
  2368. }
  2369. NameGeneratorSet.prototype.getCategoryName = function(id) {
  2370. if(this.categoryNames.hasOwnProperty(id)) {
  2371. return this.categoryNames[id];
  2372. } else {
  2373. return null;
  2374. }
  2375. }
  2376. NameGeneratorSet.prototype.addGenerator = function(id, generator, preload) {
  2377. if(preload && !(generator instanceof NameGenerator)) {
  2378. return this.generators[id] = new NameGenerator(generator);
  2379. } else {
  2380. return this.generators[id] = generator;
  2381. }
  2382. }
  2383. NameGeneratorSet.prototype.getGenerator = function(id) {
  2384. // If no full id is provided, find the first best.
  2385. // This is NOT recommended with a multi-category
  2386. // generator set.
  2387. if(id.indexOf('/') === -1) {
  2388. // Try every category until one has a generator with
  2389. // the requested id.
  2390. var categoryKeys = Object.keys(this.categoryNames);
  2391. for(var i = 0; i < categoryKeys.length; ++i) {
  2392. var key = categoryKeys[i] + '/' + id;
  2393. if(this.generators.hasOwnProperty(key)) {
  2394. return this.getGenerator(key);
  2395. }
  2396. }
  2397. // If none can be found, just return null
  2398. return null;
  2399. }
  2400. if(this.generators.hasOwnProperty(id)) {
  2401. // If the generator was previously unloaded, add it
  2402. if(!(this.generators[id] instanceof NameGenerator)) {
  2403. this.generators[id] = new NameGenerator(this.generators[id]);
  2404. }
  2405. return this.generators[id];
  2406. }
  2407. return null;
  2408. }
  2409. NameGeneratorSet.prototype.export = function() {
  2410. var r = {
  2411. categories: this.categoryNames,
  2412. categoryMetaData: this.categoryMetaData,
  2413. generators: {}
  2414. };
  2415. var keys = Object.keys(this.generators);
  2416. for(var i = 0; i < keys.length; ++i) {
  2417. r.generators[keys[i]] = this.generators[keys[i]].export();
  2418. }
  2419. return r;
  2420. }
  2421. NameGeneratorSet.prototype.import = function(obj, preload) {
  2422. var keys, key;
  2423. keys = Object.keys(obj.categories);
  2424. for(var i = 0; i < keys.length; ++i) {
  2425. key = keys[i];
  2426. this.setCategoryName(key, obj.categories[key])
  2427. }
  2428. keys = Object.keys(obj.generators);
  2429. for(var i = 0; i < keys.length; ++i) {
  2430. key = keys[i];
  2431. this.addGenerator(key, obj.generators[key], preload);
  2432. }
  2433. if(typeof(obj.categoryMetaData) === 'object' && obj.categoryMetaData !== null) {
  2434. keys = Object.keys(obj.categoryMetaData);
  2435. for(var i = 0; i < keys.length; ++i) {
  2436. key = keys[i];
  2437. this.setCategoryMetaData(key, obj.categoryMetaData[key])
  2438. }
  2439. }
  2440. }
  2441. NameGeneratorSet.prototype.getGeneratorIds = function() {
  2442. return Object.keys(this.generators);
  2443. }
  2444. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  2445. module.exports = NameGeneratorSet;
  2446. }
  2447. function NamePart(id, algo, options, format) {
  2448. this.id = id;
  2449. this.algo = algo;
  2450. this.options = options;
  2451. this.data = null;
  2452. this.lfRules = new LFRuleSet();
  2453. this.temp = null;
  2454. if(format instanceof PartFormat) {
  2455. this.format = format;
  2456. } else {
  2457. this.format = new PartFormat(format);
  2458. }
  2459. }
  2460. NamePart.prototype.loadList = function(list) {
  2461. if(typeof(this.options) === 'undefined') {
  2462. this.options = {};
  2463. }
  2464. this.data = this.algo.parseList(list, this.options, this.lfRules);
  2465. this.temp = this.algo.initTemp(this.data, this.options, this.lfRules);
  2466. }
  2467. NamePart.prototype.setData = function(data) {
  2468. if(typeof(this.options) === 'undefined') {
  2469. this.options = {};
  2470. }
  2471. this.data = data;
  2472. this.temp = this.algo.initTemp(this.data, this.options, this.lfRules);
  2473. }
  2474. NamePart.prototype.generate = function(randomFunction) {
  2475. if(this.data == null) {
  2476. throw new Error("No data provided! Set the 'data' property on part with id \""+this.id+"\" or use loadList(list)");
  2477. return;
  2478. }
  2479. if(randomFunction == null || randomFunction == undefined) {
  2480. randomFunction = Math.random;
  2481. }
  2482. return this.format.apply(this.algo.generate(this.data, randomFunction, this.lfRules, this.options, this.temp));
  2483. }
  2484. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  2485. module.exports = NamePart;
  2486. }
  2487. function PartFormat(format) {
  2488. this.format = format;
  2489. while(this.format.length < 2) {
  2490. this.format += 'a';
  2491. }
  2492. this.capitalizeFirst = (format[0] === 'A');
  2493. this.capitalizeDefault = (format[1] === 'A');
  2494. this.capitalizers = {};
  2495. this.caseChangers = {};
  2496. this.replacers = {};
  2497. this.errors = [];
  2498. for(var i = 2; i < (format.length - 1); ++i) {
  2499. var op = format[i + 1];
  2500. var ch = format[i];
  2501. switch(op) {
  2502. case 'a': case 'A':
  2503. this.capitalizers[ch] = (op === 'A');
  2504. ++i;
  2505. if(i < (format.length - 1) && (format[i + 1] === 'A' || format[i + 1] === 'a')) {
  2506. this.caseChangers[ch] = (format[i + 1] === 'A' );
  2507. ++i;
  2508. }
  2509. break;
  2510. case 'S':
  2511. this.replacers[ch] = ' ';
  2512. ++i;
  2513. break;
  2514. case 'R':
  2515. var r = "";
  2516. for(i = i + 2; i < format.length; ++i) {
  2517. if(format[i] === ';') {
  2518. break;
  2519. }
  2520. r += format[i];
  2521. }
  2522. this.replacers[ch] = r;
  2523. break;
  2524. }
  2525. }
  2526. }
  2527. PartFormat.prototype.apply = function (name) {
  2528. var result = "";
  2529. var replaceNext = null;
  2530. var capitalizeNext = this.capitalizeFirst;
  2531. var capitalizeDefault = this.capitalizeDefault;
  2532. var next = name[0];
  2533. var buffer = "";
  2534. var nextBuffer = null;
  2535. var i = 0;
  2536. while(i < name.length) {
  2537. var capitalize = capitalizeNext;
  2538. var replace = replaceNext;
  2539. var ch = next;
  2540. capitalizeNext = capitalizeDefault;
  2541. if(this.capitalizers.hasOwnProperty(ch)) {
  2542. capitalizeNext = this.capitalizers[ch];
  2543. }
  2544. if(this.replacers.hasOwnProperty(ch)) {
  2545. replace = this.replacers[ch];
  2546. }
  2547. if(this.caseChangers.hasOwnProperty(ch)) {
  2548. capitalizeDefault = this.caseChangers[ch];
  2549. }
  2550. if(replace !== null) {
  2551. if(replace.length <= 1) {
  2552. next = replace;
  2553. } else {
  2554. next = replace[0];
  2555. nextBuffer = replace.substring(1);
  2556. }
  2557. replaceNext = null;
  2558. }
  2559. if(capitalize) {
  2560. next = next.toUpperCase();
  2561. }
  2562. result += next;
  2563. if(nextBuffer !== null) {
  2564. buffer = nextBuffer;
  2565. nextBuffer = null;
  2566. }
  2567. if(buffer.length > 0) {
  2568. next = buffer[0];
  2569. buffer = buffer.substring(1);
  2570. } else {
  2571. next = name[i + 1];
  2572. ++i;
  2573. }
  2574. }
  2575. return result;
  2576. };
  2577. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  2578. module.exports = PartFormat;
  2579. }
  2580. function SampleLoader() {
  2581. this.lists = {};
  2582. }
  2583. SampleLoader.prototype.loadFromLines = function (lines) {
  2584. var loader = null;
  2585. var options = {};
  2586. var prevOption = null;
  2587. for(var i = 0; i < lines.length; ++i) {
  2588. var line = lines[i];
  2589. // Replace tabs with spaces
  2590. while(line.indexOf('\t') >= 0) {
  2591. line = line.replace('\t', ' ');
  2592. }
  2593. // Make the carriage-returns go away.
  2594. while(line.indexOf('\r') >= 0) {
  2595. line = line.replace('\r', '');
  2596. }
  2597. // Remove double-spaces to avoid empty tokens.
  2598. while(line.indexOf(' ') >= 0) {
  2599. line = line.replace(' ', ' ');
  2600. }
  2601. if(line.length === 0 || line === ' ') {
  2602. continue;
  2603. }
  2604. if(line.charAt(0) === '#') {
  2605. prevOption = null;
  2606. continue;
  2607. }
  2608. var tokens = line.trim().split(' ');
  2609. if(tokens[0].charAt(0) === '$') {
  2610. // Return early if $eof is provided, so notes can be kept below
  2611. // the useful data.
  2612. if(tokens[0] === '$eof') {
  2613. return;
  2614. }
  2615. var key = tokens[0].substring(1);
  2616. var value = tokens.splice(1);
  2617. if(options.hasOwnProperty(key) && prevOption === key) {
  2618. options[key] = options[key].concat(value);
  2619. } else {
  2620. options[key] = value;
  2621. }
  2622. prevOption = key;
  2623. } else {
  2624. //console.log(options);
  2625. prevOption = null;
  2626. if(loader == null) {
  2627. loader = loaders[options.loader[0]];
  2628. }
  2629. loader.load(tokens, this.lists, options);
  2630. }
  2631. }
  2632. };
  2633. if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') {
  2634. module.exports = SampleLoader;
  2635. }