Alright guys, I don't know any javascript, but I can read code so I spaghetti hacked together a version that only uses the !markov command and upon using the command generates both a male and a female name, here's the code: var markov = { defaultNamesMale: [ "Your","Male","Names","Here" ], defaultNamesFemale: [ "Your","Female","Names","Here" ], chain_cache: {}, namesets: {}, /** * Helper function to transform a string into an array with a given separator * * @param fullString - the string to convert * @param separator - what separates each word or element (e.g. "," to use the comma as a deliminator) * @return {Array} */ listToArray: function(fullString, separator) { 'use strict'; var fullArray = []; if (fullString !== undefined) { if (fullString.indexOf(separator) === -1) { fullArray.push(fullString); } else { fullArray = fullString.split(separator); } } return fullArray; }, /** * Called from the page ready event */ init: function() { 'use strict'; // Display banner and log activity to the API console log('Markov default namesets loaded.'); markov.namesets = { female: markov.defaultNamesFemale, default: markov.defaultNamesMale}; on("chat:message", markov.handleChatMessage); }, /** * Look to see if the chat message is a markov request, and if so generate a new name * * @param msg */ handleChatMessage: function(msg) { 'use strict'; // This an api directive? if (msg.type === "api") { // convert each word to an element into the words array. var words = markov.listToArray(msg.content, " "); //var playerName = msg. // Is this the !markov request? if (words[0] === '!markov') { var output = ''; var target = playerIsGM(msg.playerid)? 'gm' : '"' + msg.who + '"'; output += '/w "' + target + '" '; var listToUse = ["default"]; var names = listToUse.map(function(list) { return markov.generateName(list).replace(/\s/g, ''); }).join(' '); listToUse = ["female"]; var names2 = listToUse.map(function(list) { return markov.generateName(list).replace(/\s/g, ''); }).join(' '); sendChat("", output + " male: " + names + " female: " + names2); } } }, /** * Create a new name using Markov's logic * * @param languageName - will either be 'default', or the name of the handout that contains the nameset * @return string - the new name, or a message indicating failure. */ generateName: function(languageName) { 'use strict'; if (!markov.namesets[languageName]) { return 'Unknown Language (name-set) or handout notes are not valid: ' + languageName; } // Use markov's logic to generate a name using the names in languageName as a seed var chain = markov.markov_chain(languageName); if (chain) { return markov.markov_name(chain); } return ''; }, /** * <a href="https://en.wikipedia.org/wiki/Markov_chain" rel="nofollow">https://en.wikipedia.org/wiki/Markov_chain</a> * * @param type * @return {*} */ markov_chain: function(type) { 'use strict'; var chain = markov.chain_cache[type]; if (chain) { return chain; } else { var list = markov.namesets[type]; if (list) { chain = markov.construct_chain(list); if (chain) { markov.chain_cache[type] = chain; return chain; } } } return false; }, /** * <a href="https://en.wikipedia.org/wiki/Markov_chain" rel="nofollow">https://en.wikipedia.org/wiki/Markov_chain</a> * * @param list * @return {*} */ construct_chain: function(list) { 'use strict'; var chain = {}; for (var i = 0; i < list.length; i++) { var names = list[i].split(/\s+/); chain = markov.incr_chain(chain, 'parts', names.length); for (var j = 0; j < names.length; j++) { var name = names[j]; chain= markov.incr_chain(chain, 'name_len', name.length); var c = name.substr(0, 1); chain = markov.incr_chain(chain, 'initial', c); var string = name.substr(1); var last_c = c; while (string.length > 0) { c = string.substr(0, 1); chain = markov.incr_chain(chain, last_c, c); string = string.substr(1); last_c = c; } } } return markov.scale_chain(chain); }, /** * <a href="https://en.wikipedia.org/wiki/Markov_chain" rel="nofollow">https://en.wikipedia.org/wiki/Markov_chain</a> * * @param chain * @param key * @param token * @return {*} */ incr_chain: function(chain, key, token) { 'use strict'; if (chain[key]) { if (chain[key][token]) { chain[key][token]++; } else { chain[key][token] = 1; } } else { chain[key]= {}; chain[key][token] = 1; } return chain; }, /** * <a href="https://en.wikipedia.org/wiki/Markov_chain" rel="nofollow">https://en.wikipedia.org/wiki/Markov_chain</a> * * @param chain * @return {*} */ scale_chain: function(chain) { 'use strict'; var table_len = {}; for (var key in chain) { table_len[key] = 0; for (var token in chain[key]) { var count= chain[key][token]; var weighted = Math.floor(Math.pow(count, 1.3)); chain[key][token] = weighted; table_len[key] += weighted; } } chain.table_len = table_len; return chain; }, /** * <a href="https://en.wikipedia.org/wiki/Markov_chain" rel="nofollow">https://en.wikipedia.org/wiki/Markov_chain</a> * * @param chain * @return {string} */ markov_name: function(chain) { 'use strict'; var parts = markov.select_link(chain, 'parts'); var names = []; for (var i = 0; i < parts; i++) { var name_len = markov.select_link(chain, 'name_len'); var c= markov.select_link(chain, 'initial'); var name = c; var last_c= c; while (name.length < name_len) { c = markov.select_link(chain, last_c); name += c; last_c = c; } names.push(name); } return names.join(' '); }, /** * <a href="https://en.wikipedia.org/wiki/Markov_chain" rel="nofollow">https://en.wikipedia.org/wiki/Markov_chain</a> * * @param chain * @param key * @return {*} */ select_link: function(chain, key) { 'use strict'; var len = chain.table_len[key]; var idx = Math.floor(Math.random() * len); var t = 0; for (var token in chain[key]) { t += chain[key][token]; if (idx < t) { return token; } } return '-'; } }; /** * Fire off init when the page loads. */ on("ready", function() { 'use strict'; markov.init(); });