|
|
// This file is made from automatically concaterad and filtered node.js scripts.
// ngn4 is open source, and provided under an MIT licence
// See https://github.com/gissleh/ngn4 for more details.
// Copyright (c) 2015 Gisle Aune"use strict";
var algos = {}; var loaders = {};
var grammarUtils = { pick: function(array, randomFunction) { return array[Math.floor(randomFunction() * array.length)]; } }
var algo = { id: "grammar", name: "Grammar",
parseList: function(input, options, lfRules) { var r = { positions: [0], words: [], symbols: {}, size: 0 };
for(var i = 0; i < input.length; ++i) { var group = input[i]; var headers = group.headers; var lines = group.lines;
// Ensure sets exists.
for(var j = 0; j < headers.length; ++j) { var header = headers[j];
if(!r.symbols.hasOwnProperty(header)) { r.symbols[header] = []; } }
// Parse lines to add to sets
for(var j = 0; j < lines.length; ++j) { var tokens = lines[j];
lfRules.learn(tokens.join(''));
for(var k = 0; k < tokens.length; ++k) { var token = tokens[k]; var header = headers[k];
r.symbols[header].push(token); } }
r.words.push({f: headers, l: lines.length}); r.size += lines.length; r.positions.push(r.size); }
for(var i = 0; i < r.words.length; ++i) { var word = r.words[i];
if(word.l > 1) { continue; }
var strikes = 0;
for(var j = 0; j < word.f.length; ++j) { var symbol = word.f[j];
if(r.symbols[symbol].length <= word.l) { ++strikes; } }
if(strikes === word.f.length) { r.words.splice(i, 1); console.error('\tSKIPPED "'+word.f.join(' ')+'" (length <= 1)'); } }
return r; },
initTemp: function(data, options, lfRules) { // Reconstruct samples
var words = data.words; var symbols = data.symbols; var results = []; var indices = {}; var symbolKeys = Object.keys(symbols);
// Set up the indices array
for(var i = 0; i < symbolKeys.length; ++i) { indices[symbolKeys[i]] = 0; }
for(var i = 0; i < words.length; ++i) { var word = words[i];
for(var j = 0; j < word.l; ++j) { var name = "";
for(var k = 0; k < word.f.length; ++k) { var symbol = word.f[k]; var index = indices[symbol]++;
name += symbols[symbol][index]; }
results.push(name); } }
// Enforce lfoverride
if(options.hasOwnProperty('lfOverrides')) { var keys = Object.keys(options.lfOverrides);
for(var i = 0; i < keys.length; ++i) { lfRules.counts[keys[i]] = options.lfOverrides[keys[i]]; } }
return results; },
generate: function(data, randomFunction, lfRules, options, temp) { var word = null; var result = []; var prev = null; var r = Math.floor(randomFunction() * data.size);
for(var i = 0; i < data.words.length; ++i) { if(r < data.positions[i + 1]) { word = data.words[i]; break; } }
if(word === null) { word = data.words[data.words.length - 1]; }
while(result.length < word.f.length) { var i = result.length; var symbol = word.f[i]; var pick = grammarUtils.pick(data.symbols[symbol], randomFunction); var fail = false; var name;
result.push(pick); name = result.join('');
if(!lfRules.check(name)) { fail = true; }
if(!fail && temp.indexOf(name) !== -1) { fail = true; }
if(fail) { if(prev === pick) { prev = null;
// If word's wieght is smaller than symbol count,
// retry with another word. This is to prevent crashing
if(word.l <= word.f.length) { var r = Math.floor(randomFunction() * data.size);
word = null; for(var i = 0; i < data.words.length; ++i) { if(r < data.positions[i + 1]) { word = data.words[i]; break; } }
if(word === null) { word = data.words[data.words.length - 1]; } }
result = []; } else { prev = pick; result.pop(); } } }
return result.join(''); } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
var markovUtils = {}; var runId = 0;
markovUtils.mergeFlags = function(flags, flagsStr) { var result = { lrs: false, lrm: false, lre: false, f2o: false, f3o: false, to2c: false, to2v: false, todc: false, todv: false, lrf: false, as: false }
if(typeof(flags) !== 'string') { var keys = Object.keys(flags); for(var i = 0; i < keys.length; ++i) { result[keys[i]] = flags[keys[i]]; } } else { flagsStr = flags; }
if(typeof(flagsStr) !== 'undefined') { var flagSplit = flagsStr.split(' ');
for(var i = 0; i < flagSplit.length; ++i) { result[flagSplit[i]] = true; } }
return result; }
markovUtils.pick = function(rfunc, array) { return array[Math.floor(rfunc() * array.length)]; }
markovUtils.getArray = function(obj, prop) { if(!obj.hasOwnProperty(prop)) { obj[prop] = []; }
return obj[prop]; }
markovUtils.getIndex = function(obj, prop) { if(!obj.hasOwnProperty(prop)) { obj[prop] = 0; }
return obj[prop]++; }
markovUtils.getRandomLength = function(array, total, randomFunction) { var r = Math.floor(randomFunction() * total);
for(var i = 1; i < array.length; ++i) { r -= array[i];
if(r < 0) { return i + 3; } } // 4 1 3 1
return array.length + 1; }
markovUtils.checkThirdOrder = function(result, option, flags, options) { if(flags.f3o) { return true; }
var vowels; if(options.hasOwnProperty('vowels')) { vowels = options.vowels; } else { vowels = "aeiouy"; }
var prev1 = result[result.length - 1]; var prev2 = result[result.length - 2];
if(flags.todc && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) === -1)) { return true; } if(flags.to2c && (result.length > 2) && (vowels.indexOf(prev1) === -1) && (vowels.indexOf(prev2) === -1)) { return true; } if(flags.todv && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) !== -1)) { return true; } if(flags.to2v && (result.length > 2) && (vowels.indexOf(prev1) !== -1) && (vowels.indexOf(prev2) !== -1)) { return true; }
return false; }
markovUtils.checkNext = function(result, option, length, flags, lrFlag, lfRules, samples) { var next = result + option.ch;
if(flags.as && (next.length == length) && (samples.indexOf(next) !== -1)) { return false; }
if(lrFlag && option.l != length) { return false; }
if(flags.rlf && !lfRules.check(next)) { return false; }
return true; }
/* +-------------------------------------------------+ | GENERATOR FLAGS | +---+--------+------------------------------------+ | X | lrs | Length restriction on start, mid, | | X | lrm | and/or end rules the length of the | | X | lre | rule's source sample | +---+--------+------------------------------------+ | X | f2o | Force 2nd or 3rd order chain. f3o | | X | f3o | override f2o if both are set | +---+--------+------------------------------------+ | X | to2c | Third order on 2 consonants | | X | to2v | and/or vowels | +---+--------+------------------------------------+ | X | todc | Third order on double consonants | | X | todv | and/or vowels | +---+--------+------------------------------------+ | X | rlf | Restrict letter frequency | +---+--------+------------------------------------+ | X | as | Avoid samples being generated | +---+--------+------------------------------------+ */
var algo = { id: "markov", name: "Markov",
parseList: function(input, options, lfRules) { var r = { // Examples after "aeyna"
starts: [], // [{s: 'aey', l: 5}]
mids: {}, // {"ey": [{l: 5, ch: 'n'}], "aey": [{l: 5, ch: 'n'}]}
ends: {}, // {"eyn": [{l: 5, ch: 'a'}]}
lf: [], // [0, 0, 1],
lfTotal: 0 }
// FLAGS
if(!options.hasOwnProperty('flags')) { options.flags = {}; } options.flags = markovUtils.mergeFlags(options.flags, options.flagsStr);
// Parse each sample.
for(var i = 0; i < input.length; ++i) { var sample = input[i]; var l = sample.length;
// The code doesn't work with names shorter than 3 letters.
if(sample.length < 3) { continue; }
// Learn letter frequency rules from sample.
lfRules.learn(sample);
// Length frequency
while(r.lf.length <= sample.length - 3) { r.lf.push(0); } ++r.lf[sample.length - 3]; ++r.lfTotal;
// Beginning
if(sample.length > 4) { r.starts.push({ l: l, s: sample.substring(0, 3) }); } else { r.starts.push({ l: l, s: sample.substring(0, 2) }); }
// Middle
for(var j = 2; j < l - 1; ++j) { var mid = { ch: sample.charAt(j), l: l };
if(j > 2) { markovUtils.getArray(r.mids, sample.substring(j - 3, j)).push(mid); }
markovUtils.getArray(r.mids, sample.substring(j - 2, j)).push(mid); }
// ends
var end = { ch: sample.charAt(l - 1), l: l };
if(sample.length > 4) { markovUtils.getArray(r.ends, sample.substring(l - 4, l - 1)).push(end); }
markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).push(end);
//console.log(sample + ' ' + sample.substring(l - 3, l - 1) + '-' + end.ch + ' ' + markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).length);
}
return r; },
initTemp: function(data, options, lfRules) { // Reconstructs samples for avoid-sample rule
var results = []; var indexMap1 = {}; var indexMap2 = {}; var getIndex = markovUtils.getIndex;
for(var i = 0; i < data.starts.length; ++i) { var start = data.starts[i]; var name = start.s.substring(0, 2); var length = start.l; var key, set, indexMap, index;
for(var j = name.length; j < length; ++j) { set = ((j < length - 1) ? data.mids : data.ends); indexMap = ((j < length - 1) ? indexMap1 : indexMap2);
key = name.substring(name.length - 2);
if(set.hasOwnProperty(key)) { index = getIndex(indexMap, key);
//console.log(index + ' ' + name + ' ' + key + ' ' + (set == data.mids) + ' ' + JSON.stringify(set[key]));
name += set[key][index].ch; } else { console.log(name + ' ' + key + ' ' + length); } }
results.push(name); }
// Enforce lfoverride
if(options.hasOwnProperty('lfOverrides')) { var keys = Object.keys(options.lfOverrides);
for(var i = 0; i < keys.length; ++i) { lfRules.counts[keys[i]] = options.lfOverrides[keys[i]]; } }
return results; },
generate: function(data, randomFunction, lfRules, options, temp) { // INITIALIZE and START
var result = ""; var f = options.flags;
var globalRuns = 0;
while(globalRuns++ < 100) { var runs = 0; var start = markovUtils.pick(randomFunction, data.starts); var length = start.l; var slength = start.s.length; var tight = false;
result = start.s;
// If start shouldn't be length restricted, pick a random length.
if(!f.lrs) { length = markovUtils.getRandomLength(data.lf, data.lfTotal, randomFunction);
if(length <= 4 && slength > 2) { result = start.s.substring(0, 2); } }
// Make the rest of the name, letter by letter.
while(result.length < length) { var key, opts, validOpts;
++runId;
var set = ((result.length < length - 1) ? data.mids : data.ends); var lrFlag = ((result.length < length - 1) ? f.lrm : f.lre);
// ATTEMPT: 3rd order options
if(result.length >= 3 && (!f.f2o || f.f3o)) { key = result.substring(result.length - 3, result.length); opts = set[key];
validOpts = []; if(typeof(opts) !== 'undefined') { for(var i = 0; i < opts.length; ++i) { // If (needs third order AND option fits)
if(markovUtils.checkThirdOrder(result, opts[i], f, options) && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
validOpts.push(opts[i]); } } }
if(validOpts.length > 0) { var opt = markovUtils.pick(randomFunction, validOpts); result += opt.ch;
continue; } }
// ATTEMPT: 2nd order options
if(!f.f3o) { key = result.substring(result.length - 2, result.length); opts = set[key];
validOpts = []; if(typeof(opts) !== 'undefined') { for(var i = 0; i < opts.length; ++i) { if(!markovUtils.checkThirdOrder(result, opts[i], f, options) && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
validOpts.push(opts[i]); } } }
if(validOpts.length > 0) { var opt = markovUtils.pick(randomFunction, validOpts); result += opt.ch;
continue; } }
// LAST RESORT: Cut off the last one and try again
if(result.length > slength) { result = start.s; }
if(++runs > 32) { result = null; break; } }
if(result != null) { return result; } } } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
var algo = { id: "select", name: "Simple Random Selection",
parseList: function(input) { return input; },
initTemp: function(data) { return null; },
generate: function(data, randomFunction) { return data[Math.floor(randomFunction() * data.length)]; } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
var algo = { id: "syllables", name: "Syllable Concateration",
parseList: function(input, options, lfRules) { var r = { positions: [0], groups: [].concat(input), size: 0 };
for(var i = 0; i < r.groups.length; ++i) { var group = r.groups[i];
if(group.headers.length >= 2) { group.weigthMultiplier = parseFloat(group.headers[1]); } else { group.weigthMultiplier = 1; }
if(group.lines.length <= 1) { console.error('SKIPPED "' + group.id + '" (length <= 1)'); r.groups.splice(i, 1); --i;
continue; }
group.width = group.lines[0].length;
for(var j = 0; j < group.lines.length; ++j) { var line = group.lines[j];
if(line.length !== group.width) { console.error(JSON.stringify(group));
throw new Error("The line " + JSON.stringify(line) + " is not as long as the others in the group ("+group.width+"). No non-conformism!. D:<"); }
lfRules.learn(line.join('')); }
var size = group.lines.length * group.width * group.weigthMultiplier;
r.size += size; r.positions.push(r.size); }
return r; },
initTemp: function(data, options, lfRules) { var samples = {};
// Reconstruct samples
for(var i = 0; i < data.groups.length; ++i) { var group = data.groups[i];
for(var j = 0; j < group.lines.length; ++j) { samples[group.lines[j].join('')] = true; } }
// Enforce lfoverride
if(options.hasOwnProperty('lfOverrides')) { var keys = Object.keys(options.lfOverrides);
for(var i = 0; i < keys.length; ++i) { lfRules.counts[keys[i]] = options.lfOverrides[keys[i]]; } }
return samples; },
generate: function(data, randomFunction, lfRules, options, temp) { var rand = randomFunction() * data.size; var group = null;
for(var i = 0; i < data.groups.length - 1; ++i) { if(rand < data.positions[i + 1]) { group = data.groups[i]; break; } }
if(group == null || group == undefined) { group = data.groups[data.groups.length - 1]; }
var optionAsls = true; if(options.hasOwnProperty('asls')) { optionAsls = options.asls; }
var result = []; var lines = group.lines; var prev = null; while(result.length < group.width) { var i = result.length; rand = Math.floor(randomFunction() * group.lines.length); var pick = group.lines[rand][i];
result.push(pick); var fail = false;
// Respect letter frequency rules
if(!lfRules.check(result.join(''))) { fail = true; }
// Avoid same letter syllables
if(!fail && optionAsls && i > 0 && (pick.charAt(0) === result[i - 1].charAt(0))) { fail = true; }
// Avoid samples, but permit close samples.
if(!fail && (i === group.width - 1) && temp.hasOwnProperty(result.join(''))) { fail = true; }
if(fail) { if(pick === prev) { result = [];
if(group.lines.length <= group.width) { var group = null;
for(var i = 0; i < data.groups.length - 1; ++i) { if(rand < data.positions[i + 1]) { group = data.groups[i]; break; } }
if(group == null || group == undefined) { group = data.groups[data.groups.length - 1]; } }
prev = null; } else { prev = pick; result.pop(); } } }
return result.join(''); } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
// This file is made from automatically concaterad and filtered node.js scripts.
// ngn4 is open source, and provided under an MIT licence
// See https://github.com/gissleh/ngn4 for more details.
// Copyright (c) 2015 Gisle Aune"use strict";
var algos = {}; var loaders = {};
var grammarUtils = { pick: function(array, randomFunction) { return array[Math.floor(randomFunction() * array.length)]; } }
var algo = { id: "grammar", name: "Grammar",
parseList: function(input, options, lfRules) { var r = { positions: [0], words: [], symbols: {}, size: 0 };
for(var i = 0; i < input.length; ++i) { var group = input[i]; var headers = group.headers; var lines = group.lines;
// Ensure sets exists.
for(var j = 0; j < headers.length; ++j) { var header = headers[j];
if(!r.symbols.hasOwnProperty(header)) { r.symbols[header] = []; } }
// Parse lines to add to sets
for(var j = 0; j < lines.length; ++j) { var tokens = lines[j];
lfRules.learn(tokens.join(''));
for(var k = 0; k < tokens.length; ++k) { var token = tokens[k]; var header = headers[k];
r.symbols[header].push(token); } }
r.words.push({f: headers, l: lines.length}); r.size += lines.length; r.positions.push(r.size); }
for(var i = 0; i < r.words.length; ++i) { var word = r.words[i];
if(word.l > 1) { continue; }
var strikes = 0;
for(var j = 0; j < word.f.length; ++j) { var symbol = word.f[j];
if(r.symbols[symbol].length <= word.l) { ++strikes; } }
if(strikes === word.f.length) { r.words.splice(i, 1); console.error('\tSKIPPED "'+word.f.join(' ')+'" (length <= 1)'); } }
return r; },
initTemp: function(data, options, lfRules) { // Reconstruct samples
var words = data.words; var symbols = data.symbols; var results = []; var indices = {}; var symbolKeys = Object.keys(symbols);
// Set up the indices array
for(var i = 0; i < symbolKeys.length; ++i) { indices[symbolKeys[i]] = 0; }
for(var i = 0; i < words.length; ++i) { var word = words[i];
for(var j = 0; j < word.l; ++j) { var name = "";
for(var k = 0; k < word.f.length; ++k) { var symbol = word.f[k]; var index = indices[symbol]++;
name += symbols[symbol][index]; }
results.push(name); } }
// Enforce lfoverride
if(options.hasOwnProperty('lfOverrides')) { var keys = Object.keys(options.lfOverrides);
for(var i = 0; i < keys.length; ++i) { lfRules.counts[keys[i]] = options.lfOverrides[keys[i]]; } }
return results; },
generate: function(data, randomFunction, lfRules, options, temp) { var word = null; var result = []; var prev = null; var r = Math.floor(randomFunction() * data.size);
for(var i = 0; i < data.words.length; ++i) { if(r < data.positions[i + 1]) { word = data.words[i]; break; } }
if(word === null) { word = data.words[data.words.length - 1]; }
while(result.length < word.f.length) { var i = result.length; var symbol = word.f[i]; var pick = grammarUtils.pick(data.symbols[symbol], randomFunction); var fail = false; var name;
result.push(pick); name = result.join('');
if(!lfRules.check(name)) { fail = true; }
if(!fail && temp.indexOf(name) !== -1) { fail = true; }
if(fail) { if(prev === pick) { prev = null;
// If word's wieght is smaller than symbol count,
// retry with another word. This is to prevent crashing
if(word.l <= word.f.length) { var r = Math.floor(randomFunction() * data.size);
word = null; for(var i = 0; i < data.words.length; ++i) { if(r < data.positions[i + 1]) { word = data.words[i]; break; } }
if(word === null) { word = data.words[data.words.length - 1]; } }
result = []; } else { prev = pick; result.pop(); } } }
return result.join(''); } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
var markovUtils = {}; var runId = 0;
markovUtils.mergeFlags = function(flags, flagsStr) { var result = { lrs: false, lrm: false, lre: false, f2o: false, f3o: false, to2c: false, to2v: false, todc: false, todv: false, lrf: false, as: false }
if(typeof(flags) !== 'string') { var keys = Object.keys(flags); for(var i = 0; i < keys.length; ++i) { result[keys[i]] = flags[keys[i]]; } } else { flagsStr = flags; }
if(typeof(flagsStr) !== 'undefined') { var flagSplit = flagsStr.split(' ');
for(var i = 0; i < flagSplit.length; ++i) { result[flagSplit[i]] = true; } }
return result; }
markovUtils.pick = function(rfunc, array) { return array[Math.floor(rfunc() * array.length)]; }
markovUtils.getArray = function(obj, prop) { if(!obj.hasOwnProperty(prop)) { obj[prop] = []; }
return obj[prop]; }
markovUtils.getIndex = function(obj, prop) { if(!obj.hasOwnProperty(prop)) { obj[prop] = 0; }
return obj[prop]++; }
markovUtils.getRandomLength = function(array, total, randomFunction) { var r = Math.floor(randomFunction() * total);
for(var i = 1; i < array.length; ++i) { r -= array[i];
if(r < 0) { return i + 3; } } // 4 1 3 1
return array.length + 1; }
markovUtils.checkThirdOrder = function(result, option, flags, options) { if(flags.f3o) { return true; }
var vowels; if(options.hasOwnProperty('vowels')) { vowels = options.vowels; } else { vowels = "aeiouy"; }
var prev1 = result[result.length - 1]; var prev2 = result[result.length - 2];
if(flags.todc && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) === -1)) { return true; } if(flags.to2c && (result.length > 2) && (vowels.indexOf(prev1) === -1) && (vowels.indexOf(prev2) === -1)) { return true; } if(flags.todv && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) !== -1)) { return true; } if(flags.to2v && (result.length > 2) && (vowels.indexOf(prev1) !== -1) && (vowels.indexOf(prev2) !== -1)) { return true; }
return false; }
markovUtils.checkNext = function(result, option, length, flags, lrFlag, lfRules, samples) { var next = result + option.ch;
if(flags.as && (next.length == length) && (samples.indexOf(next) !== -1)) { return false; }
if(lrFlag && option.l != length) { return false; }
if(flags.rlf && !lfRules.check(next)) { return false; }
return true; }
/* +-------------------------------------------------+ | GENERATOR FLAGS | +---+--------+------------------------------------+ | X | lrs | Length restriction on start, mid, | | X | lrm | and/or end rules the length of the | | X | lre | rule's source sample | +---+--------+------------------------------------+ | X | f2o | Force 2nd or 3rd order chain. f3o | | X | f3o | override f2o if both are set | +---+--------+------------------------------------+ | X | to2c | Third order on 2 consonants | | X | to2v | and/or vowels | +---+--------+------------------------------------+ | X | todc | Third order on double consonants | | X | todv | and/or vowels | +---+--------+------------------------------------+ | X | rlf | Restrict letter frequency | +---+--------+------------------------------------+ | X | as | Avoid samples being generated | +---+--------+------------------------------------+ */
var algo = { id: "markov", name: "Markov",
parseList: function(input, options, lfRules) { var r = { // Examples after "aeyna"
starts: [], // [{s: 'aey', l: 5}]
mids: {}, // {"ey": [{l: 5, ch: 'n'}], "aey": [{l: 5, ch: 'n'}]}
ends: {}, // {"eyn": [{l: 5, ch: 'a'}]}
lf: [], // [0, 0, 1],
lfTotal: 0 }
// FLAGS
if(!options.hasOwnProperty('flags')) { options.flags = {}; } options.flags = markovUtils.mergeFlags(options.flags, options.flagsStr);
// Parse each sample.
for(var i = 0; i < input.length; ++i) { var sample = input[i]; var l = sample.length;
// The code doesn't work with names shorter than 3 letters.
if(sample.length < 3) { continue; }
// Learn letter frequency rules from sample.
lfRules.learn(sample);
// Length frequency
while(r.lf.length <= sample.length - 3) { r.lf.push(0); } ++r.lf[sample.length - 3]; ++r.lfTotal;
// Beginning
if(sample.length > 4) { r.starts.push({ l: l, s: sample.substring(0, 3) }); } else { r.starts.push({ l: l, s: sample.substring(0, 2) }); }
// Middle
for(var j = 2; j < l - 1; ++j) { var mid = { ch: sample.charAt(j), l: l };
if(j > 2) { markovUtils.getArray(r.mids, sample.substring(j - 3, j)).push(mid); }
markovUtils.getArray(r.mids, sample.substring(j - 2, j)).push(mid); }
// ends
var end = { ch: sample.charAt(l - 1), l: l };
if(sample.length > 4) { markovUtils.getArray(r.ends, sample.substring(l - 4, l - 1)).push(end); }
markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).push(end);
//console.log(sample + ' ' + sample.substring(l - 3, l - 1) + '-' + end.ch + ' ' + markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).length);
}
return r; },
initTemp: function(data, options, lfRules) { // Reconstructs samples for avoid-sample rule
var results = []; var indexMap1 = {}; var indexMap2 = {}; var getIndex = markovUtils.getIndex;
for(var i = 0; i < data.starts.length; ++i) { var start = data.starts[i]; var name = start.s.substring(0, 2); var length = start.l; var key, set, indexMap, index;
for(var j = name.length; j < length; ++j) { set = ((j < length - 1) ? data.mids : data.ends); indexMap = ((j < length - 1) ? indexMap1 : indexMap2);
key = name.substring(name.length - 2);
if(set.hasOwnProperty(key)) { index = getIndex(indexMap, key);
//console.log(index + ' ' + name + ' ' + key + ' ' + (set == data.mids) + ' ' + JSON.stringify(set[key]));
name += set[key][index].ch; } else { console.log(name + ' ' + key + ' ' + length); } }
results.push(name); }
// Enforce lfoverride
if(options.hasOwnProperty('lfOverrides')) { var keys = Object.keys(options.lfOverrides);
for(var i = 0; i < keys.length; ++i) { lfRules.counts[keys[i]] = options.lfOverrides[keys[i]]; } }
return results; },
generate: function(data, randomFunction, lfRules, options, temp) { // INITIALIZE and START
var result = ""; var f = options.flags;
var globalRuns = 0;
while(globalRuns++ < 100) { var runs = 0; var start = markovUtils.pick(randomFunction, data.starts); var length = start.l; var slength = start.s.length; var tight = false;
result = start.s;
// If start shouldn't be length restricted, pick a random length.
if(!f.lrs) { length = markovUtils.getRandomLength(data.lf, data.lfTotal, randomFunction);
if(length <= 4 && slength > 2) { result = start.s.substring(0, 2); } }
// Make the rest of the name, letter by letter.
while(result.length < length) { var key, opts, validOpts;
++runId;
var set = ((result.length < length - 1) ? data.mids : data.ends); var lrFlag = ((result.length < length - 1) ? f.lrm : f.lre);
// ATTEMPT: 3rd order options
if(result.length >= 3 && (!f.f2o || f.f3o)) { key = result.substring(result.length - 3, result.length); opts = set[key];
validOpts = []; if(typeof(opts) !== 'undefined') { for(var i = 0; i < opts.length; ++i) { // If (needs third order AND option fits)
if(markovUtils.checkThirdOrder(result, opts[i], f, options) && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
validOpts.push(opts[i]); } } }
if(validOpts.length > 0) { var opt = markovUtils.pick(randomFunction, validOpts); result += opt.ch;
continue; } }
// ATTEMPT: 2nd order options
if(!f.f3o) { key = result.substring(result.length - 2, result.length); opts = set[key];
validOpts = []; if(typeof(opts) !== 'undefined') { for(var i = 0; i < opts.length; ++i) { if(!markovUtils.checkThirdOrder(result, opts[i], f, options) && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
validOpts.push(opts[i]); } } }
if(validOpts.length > 0) { var opt = markovUtils.pick(randomFunction, validOpts); result += opt.ch;
continue; } }
// LAST RESORT: Cut off the last one and try again
if(result.length > slength) { result = start.s; }
if(++runs > 32) { result = null; break; } }
if(result != null) { return result; } } } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
var algo = { id: "select", name: "Simple Random Selection",
parseList: function(input) { return input; },
initTemp: function(data) { return null; },
generate: function(data, randomFunction) { return data[Math.floor(randomFunction() * data.length)]; } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
var algo = { id: "syllables", name: "Syllable Concateration",
parseList: function(input, options, lfRules) { var r = { positions: [0], groups: [].concat(input), size: 0 };
for(var i = 0; i < r.groups.length; ++i) { var group = r.groups[i];
if(group.headers.length >= 2) { group.weigthMultiplier = parseFloat(group.headers[1]); } else { group.weigthMultiplier = 1; }
if(group.lines.length <= 1) { console.error('SKIPPED "' + group.id + '" (length <= 1)'); r.groups.splice(i, 1); --i;
continue; }
group.width = group.lines[0].length;
for(var j = 0; j < group.lines.length; ++j) { var line = group.lines[j];
if(line.length !== group.width) { console.error(JSON.stringify(group));
throw new Error("The line " + JSON.stringify(line) + " is not as long as the others in the group ("+group.width+"). No non-conformism!. D:<"); }
lfRules.learn(line.join('')); }
var size = group.lines.length * group.width * group.weigthMultiplier;
r.size += size; r.positions.push(r.size); }
return r; },
initTemp: function(data, options, lfRules) { var samples = {};
// Reconstruct samples
for(var i = 0; i < data.groups.length; ++i) { var group = data.groups[i];
for(var j = 0; j < group.lines.length; ++j) { samples[group.lines[j].join('')] = true; } }
// Enforce lfoverride
if(options.hasOwnProperty('lfOverrides')) { var keys = Object.keys(options.lfOverrides);
for(var i = 0; i < keys.length; ++i) { lfRules.counts[keys[i]] = options.lfOverrides[keys[i]]; } }
return samples; },
generate: function(data, randomFunction, lfRules, options, temp) { var rand = randomFunction() * data.size; var group = null;
for(var i = 0; i < data.groups.length - 1; ++i) { if(rand < data.positions[i + 1]) { group = data.groups[i]; break; } }
if(group == null || group == undefined) { group = data.groups[data.groups.length - 1]; }
var optionAsls = true; if(options.hasOwnProperty('asls')) { optionAsls = options.asls; }
var result = []; var lines = group.lines; var prev = null; while(result.length < group.width) { var i = result.length; rand = Math.floor(randomFunction() * group.lines.length); var pick = group.lines[rand][i];
result.push(pick); var fail = false;
// Respect letter frequency rules
if(!lfRules.check(result.join(''))) { fail = true; }
// Avoid same letter syllables
if(!fail && optionAsls && i > 0 && (pick.charAt(0) === result[i - 1].charAt(0))) { fail = true; }
// Avoid samples, but permit close samples.
if(!fail && (i === group.width - 1) && temp.hasOwnProperty(result.join(''))) { fail = true; }
if(fail) { if(pick === prev) { result = [];
if(group.lines.length <= group.width) { var group = null;
for(var i = 0; i < data.groups.length - 1; ++i) { if(rand < data.positions[i + 1]) { group = data.groups[i]; break; } }
if(group == null || group == undefined) { group = data.groups[data.groups.length - 1]; } }
prev = null; } else { prev = pick; result.pop(); } } }
return result.join(''); } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
var loader = { id: "fullname", name: "Full Name",
load: function(tokens, lists, options) { var skip = 'NONE'; var listIds = options.list; var replaces = null;
// Get skip token (for when you just have a last name)
if(options.hasOwnProperty('skip')) { skip = options.skip[0]; }
// Check if replacements should be done.
if(options.hasOwnProperty('replace')) { replaces = options.replace; }
// Add the tokens to the right list.
for(var i = 0; i < tokens.length; ++i) { var token = tokens[i];
if(token === skip) { continue; }
if(i >= listIds.length) { break; }
token = token.toLowerCase();
if(replaces !== null) { for(var j = 0; j < replaces.length; j += 2) { var fromChars = replaces[j];
while(token.indexOf(fromChars) != -1) { token = token.replace(fromChars, replaces[j + 1]); } } }
var listId = listIds[i];
if(!lists.hasOwnProperty(listId)) { lists[listId] = []; }
lists[listId].push(token); } } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = loader; } else { loaders[loader.id] = loader; }
var nextId = 0;
var loader = { id: "tokens", name: "Tokenized Part",
load: function(tokens, lists, options) { var headers = options.group; var listId = options.list[0]; var groupId = headers; var list = null, group = null;
// Ensure the list exists, and select it.
if(!lists.hasOwnProperty(listId)) { lists[listId] = []; } list = lists[listId];
// Join the name for lowercasing
var name = tokens.join(' ').toLowerCase();
// Before splitting it back up, do replacing if requested.
if(options.hasOwnProperty('replace')) { var replaces = options.replace;
for(var i = 0; i < replaces.length; i += 2) { var fromChars = replaces[i];
while(name.indexOf(fromChars) != -1) { name = name.replace(fromChars, replaces[i + 1]); } }
}
// Split the name again
tokens = name.split(' ');
// Get group name
if(options.hasOwnProperty('idtoken')) { if(options.idtoken === 'ALL') { groupId = headers.join(' '); } else if(options.idtoken === 'ANON') { groupId = '.anonymous' + (nextId++); } else { groupId = headers[parseInt(options.idtoken)]; } }
// Try find group
for(var i = 0; i < list.length; ++i) { if(list[i].id == groupId) { group = list[i]; break; } }
// If unsuccessful, make the group.
if(group === null) { group = { id: groupId, headers: headers, lines: [] }
list.push(group); }
// Add the tokens to the group.
group.lines.push(tokens); } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = loader; } else { loaders[loader.id] = loader; }
// This file is made from automatically concaterad and filtered node.js scripts.
// ngn4 is open source, and provided under an MIT licence
// See https://github.com/gissleh/ngn4 for more details.
// Copyright (c) 2015 Gisle Aune"use strict";
var algos = {}; var loaders = {};
var grammarUtils = { pick: function(array, randomFunction) { return array[Math.floor(randomFunction() * array.length)]; } }
var algo = { id: "grammar", name: "Grammar",
parseList: function(input, options, lfRules) { var r = { positions: [0], words: [], symbols: {}, size: 0 };
for(var i = 0; i < input.length; ++i) { var group = input[i]; var headers = group.headers; var lines = group.lines;
// Ensure sets exists.
for(var j = 0; j < headers.length; ++j) { var header = headers[j];
if(!r.symbols.hasOwnProperty(header)) { r.symbols[header] = []; } }
// Parse lines to add to sets
for(var j = 0; j < lines.length; ++j) { var tokens = lines[j];
lfRules.learn(tokens.join(''));
for(var k = 0; k < tokens.length; ++k) { var token = tokens[k]; var header = headers[k];
r.symbols[header].push(token); } }
r.words.push({f: headers, l: lines.length}); r.size += lines.length; r.positions.push(r.size); }
for(var i = 0; i < r.words.length; ++i) { var word = r.words[i];
if(word.l > 1) { continue; }
var strikes = 0;
for(var j = 0; j < word.f.length; ++j) { var symbol = word.f[j];
if(r.symbols[symbol].length <= word.l) { ++strikes; } }
if(strikes === word.f.length) { r.words.splice(i, 1); console.error('\tSKIPPED "'+word.f.join(' ')+'" (length <= 1)'); } }
return r; },
initTemp: function(data, options, lfRules) { // Reconstruct samples
var words = data.words; var symbols = data.symbols; var results = []; var indices = {}; var symbolKeys = Object.keys(symbols);
// Set up the indices array
for(var i = 0; i < symbolKeys.length; ++i) { indices[symbolKeys[i]] = 0; }
for(var i = 0; i < words.length; ++i) { var word = words[i];
for(var j = 0; j < word.l; ++j) { var name = "";
for(var k = 0; k < word.f.length; ++k) { var symbol = word.f[k]; var index = indices[symbol]++;
name += symbols[symbol][index]; }
results.push(name); } }
// Enforce lfoverride
if(options.hasOwnProperty('lfOverrides')) { var keys = Object.keys(options.lfOverrides);
for(var i = 0; i < keys.length; ++i) { lfRules.counts[keys[i]] = options.lfOverrides[keys[i]]; } }
return results; },
generate: function(data, randomFunction, lfRules, options, temp) { var word = null; var result = []; var prev = null; var r = Math.floor(randomFunction() * data.size);
for(var i = 0; i < data.words.length; ++i) { if(r < data.positions[i + 1]) { word = data.words[i]; break; } }
if(word === null) { word = data.words[data.words.length - 1]; }
while(result.length < word.f.length) { var i = result.length; var symbol = word.f[i]; var pick = grammarUtils.pick(data.symbols[symbol], randomFunction); var fail = false; var name;
result.push(pick); name = result.join('');
if(!lfRules.check(name)) { fail = true; }
if(!fail && temp.indexOf(name) !== -1) { fail = true; }
if(fail) { if(prev === pick) { prev = null;
// If word's wieght is smaller than symbol count,
// retry with another word. This is to prevent crashing
if(word.l <= word.f.length) { var r = Math.floor(randomFunction() * data.size);
word = null; for(var i = 0; i < data.words.length; ++i) { if(r < data.positions[i + 1]) { word = data.words[i]; break; } }
if(word === null) { word = data.words[data.words.length - 1]; } }
result = []; } else { prev = pick; result.pop(); } } }
return result.join(''); } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
var markovUtils = {}; var runId = 0;
markovUtils.mergeFlags = function(flags, flagsStr) { var result = { lrs: false, lrm: false, lre: false, f2o: false, f3o: false, to2c: false, to2v: false, todc: false, todv: false, lrf: false, as: false }
if(typeof(flags) !== 'string') { var keys = Object.keys(flags); for(var i = 0; i < keys.length; ++i) { result[keys[i]] = flags[keys[i]]; } } else { flagsStr = flags; }
if(typeof(flagsStr) !== 'undefined') { var flagSplit = flagsStr.split(' ');
for(var i = 0; i < flagSplit.length; ++i) { result[flagSplit[i]] = true; } }
return result; }
markovUtils.pick = function(rfunc, array) { return array[Math.floor(rfunc() * array.length)]; }
markovUtils.getArray = function(obj, prop) { if(!obj.hasOwnProperty(prop)) { obj[prop] = []; }
return obj[prop]; }
markovUtils.getIndex = function(obj, prop) { if(!obj.hasOwnProperty(prop)) { obj[prop] = 0; }
return obj[prop]++; }
markovUtils.getRandomLength = function(array, total, randomFunction) { var r = Math.floor(randomFunction() * total);
for(var i = 1; i < array.length; ++i) { r -= array[i];
if(r < 0) { return i + 3; } } // 4 1 3 1
return array.length + 1; }
markovUtils.checkThirdOrder = function(result, option, flags, options) { if(flags.f3o) { return true; }
var vowels; if(options.hasOwnProperty('vowels')) { vowels = options.vowels; } else { vowels = "aeiouy"; }
var prev1 = result[result.length - 1]; var prev2 = result[result.length - 2];
if(flags.todc && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) === -1)) { return true; } if(flags.to2c && (result.length > 2) && (vowels.indexOf(prev1) === -1) && (vowels.indexOf(prev2) === -1)) { return true; } if(flags.todv && (result.length > 2) && (prev1 === prev2) && (vowels.indexOf(prev1) !== -1)) { return true; } if(flags.to2v && (result.length > 2) && (vowels.indexOf(prev1) !== -1) && (vowels.indexOf(prev2) !== -1)) { return true; }
return false; }
markovUtils.checkNext = function(result, option, length, flags, lrFlag, lfRules, samples) { var next = result + option.ch;
if(flags.as && (next.length == length) && (samples.indexOf(next) !== -1)) { return false; }
if(lrFlag && option.l != length) { return false; }
if(flags.rlf && !lfRules.check(next)) { return false; }
return true; }
/* +-------------------------------------------------+ | GENERATOR FLAGS | +---+--------+------------------------------------+ | X | lrs | Length restriction on start, mid, | | X | lrm | and/or end rules the length of the | | X | lre | rule's source sample | +---+--------+------------------------------------+ | X | f2o | Force 2nd or 3rd order chain. f3o | | X | f3o | override f2o if both are set | +---+--------+------------------------------------+ | X | to2c | Third order on 2 consonants | | X | to2v | and/or vowels | +---+--------+------------------------------------+ | X | todc | Third order on double consonants | | X | todv | and/or vowels | +---+--------+------------------------------------+ | X | rlf | Restrict letter frequency | +---+--------+------------------------------------+ | X | as | Avoid samples being generated | +---+--------+------------------------------------+ */
var algo = { id: "markov", name: "Markov",
parseList: function(input, options, lfRules) { var r = { // Examples after "aeyna"
starts: [], // [{s: 'aey', l: 5}]
mids: {}, // {"ey": [{l: 5, ch: 'n'}], "aey": [{l: 5, ch: 'n'}]}
ends: {}, // {"eyn": [{l: 5, ch: 'a'}]}
lf: [], // [0, 0, 1],
lfTotal: 0 }
// FLAGS
if(!options.hasOwnProperty('flags')) { options.flags = {}; } options.flags = markovUtils.mergeFlags(options.flags, options.flagsStr);
// Parse each sample.
for(var i = 0; i < input.length; ++i) { var sample = input[i]; var l = sample.length;
// The code doesn't work with names shorter than 3 letters.
if(sample.length < 3) { continue; }
// Learn letter frequency rules from sample.
lfRules.learn(sample);
// Length frequency
while(r.lf.length <= sample.length - 3) { r.lf.push(0); } ++r.lf[sample.length - 3]; ++r.lfTotal;
// Beginning
if(sample.length > 4) { r.starts.push({ l: l, s: sample.substring(0, 3) }); } else { r.starts.push({ l: l, s: sample.substring(0, 2) }); }
// Middle
for(var j = 2; j < l - 1; ++j) { var mid = { ch: sample.charAt(j), l: l };
if(j > 2) { markovUtils.getArray(r.mids, sample.substring(j - 3, j)).push(mid); }
markovUtils.getArray(r.mids, sample.substring(j - 2, j)).push(mid); }
// ends
var end = { ch: sample.charAt(l - 1), l: l };
if(sample.length > 4) { markovUtils.getArray(r.ends, sample.substring(l - 4, l - 1)).push(end); }
markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).push(end);
//console.log(sample + ' ' + sample.substring(l - 3, l - 1) + '-' + end.ch + ' ' + markovUtils.getArray(r.ends, sample.substring(l - 3, l - 1)).length);
}
return r; },
initTemp: function(data, options, lfRules) { // Reconstructs samples for avoid-sample rule
var results = []; var indexMap1 = {}; var indexMap2 = {}; var getIndex = markovUtils.getIndex;
for(var i = 0; i < data.starts.length; ++i) { var start = data.starts[i]; var name = start.s.substring(0, 2); var length = start.l; var key, set, indexMap, index;
for(var j = name.length; j < length; ++j) { set = ((j < length - 1) ? data.mids : data.ends); indexMap = ((j < length - 1) ? indexMap1 : indexMap2);
key = name.substring(name.length - 2);
if(set.hasOwnProperty(key)) { index = getIndex(indexMap, key);
//console.log(index + ' ' + name + ' ' + key + ' ' + (set == data.mids) + ' ' + JSON.stringify(set[key]));
name += set[key][index].ch; } else { console.log(name + ' ' + key + ' ' + length); } }
results.push(name); }
// Enforce lfoverride
if(options.hasOwnProperty('lfOverrides')) { var keys = Object.keys(options.lfOverrides);
for(var i = 0; i < keys.length; ++i) { lfRules.counts[keys[i]] = options.lfOverrides[keys[i]]; } }
return results; },
generate: function(data, randomFunction, lfRules, options, temp) { // INITIALIZE and START
var result = ""; var f = options.flags;
var globalRuns = 0;
while(globalRuns++ < 100) { var runs = 0; var start = markovUtils.pick(randomFunction, data.starts); var length = start.l; var slength = start.s.length; var tight = false;
result = start.s;
// If start shouldn't be length restricted, pick a random length.
if(!f.lrs) { length = markovUtils.getRandomLength(data.lf, data.lfTotal, randomFunction);
if(length <= 4 && slength > 2) { result = start.s.substring(0, 2); } }
// Make the rest of the name, letter by letter.
while(result.length < length) { var key, opts, validOpts;
++runId;
var set = ((result.length < length - 1) ? data.mids : data.ends); var lrFlag = ((result.length < length - 1) ? f.lrm : f.lre);
// ATTEMPT: 3rd order options
if(result.length >= 3 && (!f.f2o || f.f3o)) { key = result.substring(result.length - 3, result.length); opts = set[key];
validOpts = []; if(typeof(opts) !== 'undefined') { for(var i = 0; i < opts.length; ++i) { // If (needs third order AND option fits)
if(markovUtils.checkThirdOrder(result, opts[i], f, options) && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
validOpts.push(opts[i]); } } }
if(validOpts.length > 0) { var opt = markovUtils.pick(randomFunction, validOpts); result += opt.ch;
continue; } }
// ATTEMPT: 2nd order options
if(!f.f3o) { key = result.substring(result.length - 2, result.length); opts = set[key];
validOpts = []; if(typeof(opts) !== 'undefined') { for(var i = 0; i < opts.length; ++i) { if(!markovUtils.checkThirdOrder(result, opts[i], f, options) && markovUtils.checkNext(result, opts[i], length, f, lrFlag, lfRules, temp)) {
validOpts.push(opts[i]); } } }
if(validOpts.length > 0) { var opt = markovUtils.pick(randomFunction, validOpts); result += opt.ch;
continue; } }
// LAST RESORT: Cut off the last one and try again
if(result.length > slength) { result = start.s; }
if(++runs > 32) { result = null; break; } }
if(result != null) { return result; } } } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
var algo = { id: "select", name: "Simple Random Selection",
parseList: function(input) { return input; },
initTemp: function(data) { return null; },
generate: function(data, randomFunction) { return data[Math.floor(randomFunction() * data.length)]; } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
var algo = { id: "syllables", name: "Syllable Concateration",
parseList: function(input, options, lfRules) { var r = { positions: [0], groups: [].concat(input), size: 0 };
for(var i = 0; i < r.groups.length; ++i) { var group = r.groups[i];
if(group.headers.length >= 2) { group.weigthMultiplier = parseFloat(group.headers[1]); } else { group.weigthMultiplier = 1; }
if(group.lines.length <= 1) { console.error('SKIPPED "' + group.id + '" (length <= 1)'); r.groups.splice(i, 1); --i;
continue; }
group.width = group.lines[0].length;
for(var j = 0; j < group.lines.length; ++j) { var line = group.lines[j];
if(line.length !== group.width) { console.error(JSON.stringify(group));
throw new Error("The line " + JSON.stringify(line) + " is not as long as the others in the group ("+group.width+"). No non-conformism!. D:<"); }
lfRules.learn(line.join('')); }
var size = group.lines.length * group.width * group.weigthMultiplier;
r.size += size; r.positions.push(r.size); }
return r; },
initTemp: function(data, options, lfRules) { var samples = {};
// Reconstruct samples
for(var i = 0; i < data.groups.length; ++i) { var group = data.groups[i];
for(var j = 0; j < group.lines.length; ++j) { samples[group.lines[j].join('')] = true; } }
// Enforce lfoverride
if(options.hasOwnProperty('lfOverrides')) { var keys = Object.keys(options.lfOverrides);
for(var i = 0; i < keys.length; ++i) { lfRules.counts[keys[i]] = options.lfOverrides[keys[i]]; } }
return samples; },
generate: function(data, randomFunction, lfRules, options, temp) { var rand = randomFunction() * data.size; var group = null;
for(var i = 0; i < data.groups.length - 1; ++i) { if(rand < data.positions[i + 1]) { group = data.groups[i]; break; } }
if(group == null || group == undefined) { group = data.groups[data.groups.length - 1]; }
var optionAsls = true; if(options.hasOwnProperty('asls')) { optionAsls = options.asls; }
var result = []; var lines = group.lines; var prev = null; while(result.length < group.width) { var i = result.length; rand = Math.floor(randomFunction() * group.lines.length); var pick = group.lines[rand][i];
result.push(pick); var fail = false;
// Respect letter frequency rules
if(!lfRules.check(result.join(''))) { fail = true; }
// Avoid same letter syllables
if(!fail && optionAsls && i > 0 && (pick.charAt(0) === result[i - 1].charAt(0))) { fail = true; }
// Avoid samples, but permit close samples.
if(!fail && (i === group.width - 1) && temp.hasOwnProperty(result.join(''))) { fail = true; }
if(fail) { if(pick === prev) { result = [];
if(group.lines.length <= group.width) { var group = null;
for(var i = 0; i < data.groups.length - 1; ++i) { if(rand < data.positions[i + 1]) { group = data.groups[i]; break; } }
if(group == null || group == undefined) { group = data.groups[data.groups.length - 1]; } }
prev = null; } else { prev = pick; result.pop(); } } }
return result.join(''); } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = algo; } else { algos[algo.id] = algo; }
var loader = { id: "fullname", name: "Full Name",
load: function(tokens, lists, options) { var skip = 'NONE'; var listIds = options.list; var replaces = null;
// Get skip token (for when you just have a last name)
if(options.hasOwnProperty('skip')) { skip = options.skip[0]; }
// Check if replacements should be done.
if(options.hasOwnProperty('replace')) { replaces = options.replace; }
// Add the tokens to the right list.
for(var i = 0; i < tokens.length; ++i) { var token = tokens[i];
if(token === skip) { continue; }
if(i >= listIds.length) { break; }
token = token.toLowerCase();
if(replaces !== null) { for(var j = 0; j < replaces.length; j += 2) { var fromChars = replaces[j];
while(token.indexOf(fromChars) != -1) { token = token.replace(fromChars, replaces[j + 1]); } } }
var listId = listIds[i];
if(!lists.hasOwnProperty(listId)) { lists[listId] = []; }
lists[listId].push(token); } } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = loader; } else { loaders[loader.id] = loader; }
var nextId = 0;
var loader = { id: "tokens", name: "Tokenized Part",
load: function(tokens, lists, options) { var headers = options.group; var listId = options.list[0]; var groupId = headers; var list = null, group = null;
// Ensure the list exists, and select it.
if(!lists.hasOwnProperty(listId)) { lists[listId] = []; } list = lists[listId];
// Join the name for lowercasing
var name = tokens.join(' ').toLowerCase();
// Before splitting it back up, do replacing if requested.
if(options.hasOwnProperty('replace')) { var replaces = options.replace;
for(var i = 0; i < replaces.length; i += 2) { var fromChars = replaces[i];
while(name.indexOf(fromChars) != -1) { name = name.replace(fromChars, replaces[i + 1]); } }
}
// Split the name again
tokens = name.split(' ');
// Get group name
if(options.hasOwnProperty('idtoken')) { if(options.idtoken === 'ALL') { groupId = headers.join(' '); } else if(options.idtoken === 'ANON') { groupId = '.anonymous' + (nextId++); } else { groupId = headers[parseInt(options.idtoken)]; } }
// Try find group
for(var i = 0; i < list.length; ++i) { if(list[i].id == groupId) { group = list[i]; break; } }
// If unsuccessful, make the group.
if(group === null) { group = { id: groupId, headers: headers, lines: [] }
list.push(group); }
// Add the tokens to the group.
group.lines.push(tokens); } }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = loader; } else { loaders[loader.id] = loader; }
function LFRuleSet() { this.counts = {}; this.doubles = {}; }
LFRuleSet.prototype.learn = function(sample) { if(sample instanceof Array) { for(var i = 0; i < sample.length; ++i) { this.learn(sample[i]); } return; }
for(var i = 0; i < sample.length; ++i) { var ch = sample.charAt(i); var count = (sample.split(ch).length - 1);
if(ch == ' ') { continue; }
if(sample[i + 1] == ch) { this.doubles[ch] = true; --count; ++i; }
if(this.counts.hasOwnProperty(ch)) { if(this.counts[ch] < count) { this.counts[ch] = count; } } else { this.counts[ch] = count; } } };
LFRuleSet.prototype.check = function(name) { for(var i = 0; i < name.length; ++i) { var ch = name.charAt(i); var count = (name.split(ch).length - 1);
if((i > 0 && name[i - 1] == ch) || (i < (name.length - 1) && name[i + 1] == ch)) { if(this.doubles.hasOwnProperty(ch)) { --count; ++i; } else { return false; } }
if(ch == ' ') { continue; }
if(this.counts.hasOwnProperty(ch)) { if(count > this.counts[ch]) { return false; } } else { return false; } }
return true; }
LFRuleSet.prototype.export = function() { return { cs: this.counts, ds: this.doubles }; }
LFRuleSet.prototype.import = function(data) { this.counts = data.cs; this.doubles = data.ds; }
LFRuleSet.prototype.getCount = function(letter) { if(this.counts.hasOwnProperty(letter)) { return this.counts[letter]; } else { return 0; } }
LFRuleSet.prototype.isDouble = function(letter) { return this.doubles.hasOwnProperty(letter); }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = LFRuleSet; }
function NameFormat(id, name, formats) { this.id = id; this.name = name; this.partIds = []; this.replaceIds = []; this.offsets = [0];
if(formats instanceof Array) { this.formats = formats; } else { this.formats = [formats]; }
for(var i = 0; i < this.formats.length; ++i) { var format = this.formats[i]; var start = -1;
for(var j = 0; j < format.length; ++j) { var ch = format[j];
if(ch === '{') { start = j + 1; } else if(ch === '}') { var partId = format.substring(start, j); var split = partId.split('|');
if(split.length > 1) { this.partIds.push(split); } else { this.partIds.push(partId); }
this.replaceIds.push('{' + partId + '}'); } }
this.offsets.push(this.partIds.length); } }
NameFormat.prototype.generateParts = function(parts, gender, randomFunction) { var formats = []; var partList = []; var replaces = [];
if(typeof(randomFunction) === 'undefined') { randomFunction = Math.random; }
for(var i = 0; i < this.formats.length; ++i) { var format = this.formats[i]; var offset = this.offsets[i]; var nextOffset = this.offsets[i + 1];
var good = true;
var validParts = []; var validReplaces = [];
for(var j = offset; j < nextOffset; ++j) { var partId = this.partIds[j]; var replaceId = this.replaceIds[j];
if(partId instanceof Array) { partId = partId[Math.floor(randomFunction() * partId.length)]; }
// If a gendered part exists, use it instead (e.g. first.male)
var genderedPartId = partId + '.' + gender; if(parts.hasOwnProperty(genderedPartId)) { partId = genderedPartId; }
// If possible, replace the part.
if(parts.hasOwnProperty(partId)) { validParts.push(parts[partId]); validReplaces.push(replaceId); } else { good = false; break; } }
if(good) { partList.push(validParts); replaces.push(validReplaces); formats.push(format); } }
var r = Math.floor(randomFunction() * partList.length); var result = formats[r]; var sel = partList[r]; var replaces = replaces[r];
for(var i = 0; i < sel.length; ++i) { result = result.replace(replaces[i], sel[i].generate(randomFunction)); }
return result; }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = NameFormat; }
function NameGenerator(/*obj OR id, name*/) { // Initialize
this.genders = null; this.parts = {}; this.formats = {}; this.listIds = {}; this.meta = {};
// id, name arguments
if(arguments.length > 1) { this.id = arguments[0]; this.name = arguments[1];
return; }
var obj = arguments[0];
// object argument
this.id = obj.id; this.name = obj.name; this.genders = obj.genders || ["UNSPECIFIED"];
if(obj.hasOwnProperty('parts')) { var keys = Object.keys(obj.parts); for(var i = 0; i < keys.length; ++i) { this.addPart(keys[i], obj.parts[keys[i]]); } }
if(obj.hasOwnProperty('formats')) { var keys = Object.keys(obj.formats); for(var i = 0; i < keys.length; ++i) { this.addFormat(keys[i], obj.formats[keys[i]]); } }
if(obj.hasOwnProperty('meta')) { this.meta = obj.meta; } }
NameGenerator.prototype.addPart = function(id, args) { this.parts[id] = new NamePart(id, algos[args.algo], args.options, args.format);
if(args.hasOwnProperty('lfRules')) { this.parts[id].lfRules.import(args.lfRules); }
if(args.hasOwnProperty('data')) { this.parts[id].setData(args.data); }
if(args.hasOwnProperty('list')) { this.listIds[id] = args.list; } }
NameGenerator.prototype.addFormat = function(id, args) { this.formats[id] = new NameFormat(id, args.name, args.format); }
NameGenerator.prototype.addListsFromLoader = function(loader) { var keys = Object.keys(this.listIds);
for(var i = 0; i < keys.length; ++i) { var part = this.parts[keys[i]];
if(loader.lists.hasOwnProperty(keys[i])) { part.loadList(loader.lists[keys[i]]); } } }
NameGenerator.prototype.addList = function(listId, listData) { var keys = Object.keys(this.listIds);
for(var i = 0; i < keys.length; ++i) { var part = this.parts[keys[i]];
if(this.listIds[part.id] === listId) { part.loadList(listData); } } }
NameGenerator.prototype.removePart = function(id) { delete this.parts[id]; }
NameGenerator.prototype.removeFormat = function(id) { delete this.formats[id]; }
NameGenerator.prototype.generate = function(formatId, gender, randomFunction) { if(typeof(randomFunction) === 'undefined' || randomFunction === null) { randomFunction = Math.random; }
if(typeof(gender) === 'undefined' || gender == null) { var r = Math.floor(this.genders.length * randomFunction()); gender = this.genders[r].toLowerCase(); } else { gender = gender.toLowerCase(); }
var format, keys;
if(typeof(formatId) === 'undefined' || formatId == null) { keys = Object.keys(this.formats); format = this.formats[keys[0]];
for(var i = 0; i < keys.length; ++i) { var split = keys[i].split('.'); if(split.length > 1 && split[1] === gender) { format = this.formats[keys[i]]; break; } } } else { if(this.formats.hasOwnProperty(formatId + '.' + gender)) { format = this.formats[formatId + '.' + gender] } else { format = this.formats[formatId]; } }
if(typeof(format) === 'undefined') { return null; }
return format.generateParts(this.parts, gender, randomFunction); }
NameGenerator.prototype.export = function() { var r = { id: this.id, name: this.name, genders: this.genders, formats: {}, parts: {}, meta: this.meta };
var keys = Object.keys(this.formats); for(var i = 0; i < keys.length; ++i) { var format = this.formats[keys[i]];
r.formats[keys[i]] = { name: format.name, format: format.formats }; }
keys = Object.keys(this.parts); for(var i = 0; i < keys.length; ++i) { var part = this.parts[keys[i]]; var key = keys[i];
r.parts[key] = { algo: part.algo.id, options: part.options, format: part.format.format, lfRules: part.lfRules.export() };
if(this.listIds.hasOwnProperty(key)) { r.parts[key].list = this.listIds[key]; }
if(part.data !== null) { r.parts[key].data = part.data; } }
return r; }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = NameGenerator; }
function NameGeneratorSet() { this.categoryNames = {}; this.categoryMetaData = {}; this.generators = {}; }
NameGeneratorSet.prototype.setCategoryName = function(id, name) { this.categoryNames[id] = name; }
NameGeneratorSet.prototype.setCategoryMeta = function(id, meta) { this.categoryMetaData[id] = meta; }
NameGeneratorSet.prototype.getMeta = function(id, key, defaultValue) { var catId = id.split('/'); var gen = this.getGenerator(id);
if(typeof(defaultValue) === 'undefined') { defaultValue = null; }
if(gen !== null && gen.meta.hasOwnProperty(key)) { return gen.meta[key]; } else if(this.categoryMetaData.hasOwnProperty(catId)) { var catMeta = this.categoryMetaData[catId]; if(catMeta.hasOwnProperty(key)) { return catMeta[key]; } else { return defaultValue; } } else { return defaultValue; } }
NameGeneratorSet.prototype.getCategoryName = function(id) { if(this.categoryNames.hasOwnProperty(id)) { return this.categoryNames[id]; } else { return null; } }
NameGeneratorSet.prototype.addGenerator = function(id, generator, preload) { if(preload && !(generator instanceof NameGenerator)) { return this.generators[id] = new NameGenerator(generator); } else { return this.generators[id] = generator; } }
NameGeneratorSet.prototype.getGenerator = function(id) { // If no full id is provided, find the first best.
// This is NOT recommended with a multi-category
// generator set.
if(id.indexOf('/') === -1) { // Try every category until one has a generator with
// the requested id.
var categoryKeys = Object.keys(this.categoryNames); for(var i = 0; i < categoryKeys.length; ++i) { var key = categoryKeys[i] + '/' + id;
if(this.generators.hasOwnProperty(key)) { return this.getGenerator(key); } }
// If none can be found, just return null
return null; }
if(this.generators.hasOwnProperty(id)) { // If the generator was previously unloaded, add it
if(!(this.generators[id] instanceof NameGenerator)) { this.generators[id] = new NameGenerator(this.generators[id]); }
return this.generators[id]; }
return null; }
NameGeneratorSet.prototype.export = function() { var r = { categories: this.categoryNames, categoryMetaData: this.categoryMetaData, generators: {} };
var keys = Object.keys(this.generators);
for(var i = 0; i < keys.length; ++i) { r.generators[keys[i]] = this.generators[keys[i]].export(); }
return r; }
NameGeneratorSet.prototype.import = function(obj, preload) { var keys, key;
keys = Object.keys(obj.categories); for(var i = 0; i < keys.length; ++i) { key = keys[i]; this.setCategoryName(key, obj.categories[key]) }
keys = Object.keys(obj.generators); for(var i = 0; i < keys.length; ++i) { key = keys[i]; this.addGenerator(key, obj.generators[key], preload); }
if(typeof(obj.categoryMetaData) === 'object' && obj.categoryMetaData !== null) { keys = Object.keys(obj.categoryMetaData); for(var i = 0; i < keys.length; ++i) { key = keys[i]; this.setCategoryMetaData(key, obj.categoryMetaData[key]) } } }
NameGeneratorSet.prototype.getGeneratorIds = function() { return Object.keys(this.generators); }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = NameGeneratorSet; }
function NamePart(id, algo, options, format) { this.id = id; this.algo = algo; this.options = options; this.data = null; this.lfRules = new LFRuleSet(); this.temp = null;
if(format instanceof PartFormat) { this.format = format; } else { this.format = new PartFormat(format); } }
NamePart.prototype.loadList = function(list) { if(typeof(this.options) === 'undefined') { this.options = {}; }
this.data = this.algo.parseList(list, this.options, this.lfRules); this.temp = this.algo.initTemp(this.data, this.options, this.lfRules); }
NamePart.prototype.setData = function(data) { if(typeof(this.options) === 'undefined') { this.options = {}; }
this.data = data; this.temp = this.algo.initTemp(this.data, this.options, this.lfRules); }
NamePart.prototype.generate = function(randomFunction) { if(this.data == null) { throw new Error("No data provided! Set the 'data' property on part with id \""+this.id+"\" or use loadList(list)"); return; }
if(randomFunction == null || randomFunction == undefined) { randomFunction = Math.random; }
return this.format.apply(this.algo.generate(this.data, randomFunction, this.lfRules, this.options, this.temp)); }
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = NamePart; }
function PartFormat(format) { this.format = format;
while(this.format.length < 2) { this.format += 'a'; }
this.capitalizeFirst = (format[0] === 'A'); this.capitalizeDefault = (format[1] === 'A'); this.capitalizers = {}; this.caseChangers = {}; this.replacers = {}; this.errors = [];
for(var i = 2; i < (format.length - 1); ++i) { var op = format[i + 1]; var ch = format[i];
switch(op) { case 'a': case 'A': this.capitalizers[ch] = (op === 'A'); ++i;
if(i < (format.length - 1) && (format[i + 1] === 'A' || format[i + 1] === 'a')) { this.caseChangers[ch] = (format[i + 1] === 'A' ); ++i; }
break; case 'S': this.replacers[ch] = ' '; ++i; break; case 'R': var r = "";
for(i = i + 2; i < format.length; ++i) { if(format[i] === ';') { break; }
r += format[i]; }
this.replacers[ch] = r;
break; } } }
PartFormat.prototype.apply = function (name) { var result = ""; var replaceNext = null; var capitalizeNext = this.capitalizeFirst; var capitalizeDefault = this.capitalizeDefault; var next = name[0]; var buffer = ""; var nextBuffer = null;
var i = 0; while(i < name.length) { var capitalize = capitalizeNext; var replace = replaceNext; var ch = next; capitalizeNext = capitalizeDefault;
if(this.capitalizers.hasOwnProperty(ch)) { capitalizeNext = this.capitalizers[ch]; }
if(this.replacers.hasOwnProperty(ch)) { replace = this.replacers[ch]; }
if(this.caseChangers.hasOwnProperty(ch)) { capitalizeDefault = this.caseChangers[ch]; }
if(replace !== null) { if(replace.length <= 1) { next = replace; } else { next = replace[0]; nextBuffer = replace.substring(1); }
replaceNext = null; } if(capitalize) { next = next.toUpperCase(); }
result += next;
if(nextBuffer !== null) { buffer = nextBuffer; nextBuffer = null; }
if(buffer.length > 0) { next = buffer[0]; buffer = buffer.substring(1); } else { next = name[i + 1]; ++i; } }
return result; };
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = PartFormat; }
function SampleLoader() { this.lists = {}; }
SampleLoader.prototype.loadFromLines = function (lines) { var loader = null; var options = {}; var prevOption = null;
for(var i = 0; i < lines.length; ++i) { var line = lines[i];
// Replace tabs with spaces
while(line.indexOf('\t') >= 0) { line = line.replace('\t', ' '); }
// Make the carriage-returns go away.
while(line.indexOf('\r') >= 0) { line = line.replace('\r', ''); }
// Remove double-spaces to avoid empty tokens.
while(line.indexOf(' ') >= 0) { line = line.replace(' ', ' '); }
if(line.length === 0 || line === ' ') { continue; }
if(line.charAt(0) === '#') { prevOption = null; continue; }
var tokens = line.trim().split(' ');
if(tokens[0].charAt(0) === '$') { // Return early if $eof is provided, so notes can be kept below
// the useful data.
if(tokens[0] === '$eof') { return; }
var key = tokens[0].substring(1); var value = tokens.splice(1);
if(options.hasOwnProperty(key) && prevOption === key) { options[key] = options[key].concat(value); } else { options[key] = value; }
prevOption = key; } else { //console.log(options);
prevOption = null;
if(loader == null) { loader = loaders[options.loader[0]]; }
loader.load(tokens, this.lists, options); } } };
if(typeof(module) !== 'undefined' && typeof(module.exports) !== 'undefined') { module.exports = SampleLoader; }
|