Build Random Song Lyrics Generator Using JavaScript HTML5 CSS3

0Shares

In this tutorial, I will guide you how to create a random song lyrics generator. We will use HTML5, CSS3, and JavaScript to write this software.

You can easily copy/paste or download the complete source code of our random song lyrics generator.

Folder Structure of Random Song Lyrics Generator

  • data
    • dictionary_ENG.js
    • syntax_ENG.dsl
  • bg.jpg
  • config.js
  • generator.js
  • index.html
  • styles.css
  • utils.js

data/dictionary_ENG.js

var adjectives={any:["different","used","important","every","large","available","popular","able","basic","known","various","difficult","several","united","historical","hot","useful","mental","scared","additional","emotional","old","political","similar","healthy","financial","medical","traditional","federal","entire","strong","actual","significant","successful","electrical","expensive","pregnant","intelligent","interesting","poor","happy","responsible","cute","helpful","recent","willing","nice","wonderful","impossible","serious","huge","rare","technical","typical","competitive","critical","electronic","immediate","aware","educational","environmental","global","legal","relevant","accurate","capable","dangerous","dramatic","efficient","powerful","foreign","hungry","practical","psychological","severe","suitable","numerous","sufficient","unusual","consistent","cultural","existing","famous","pure","afraid","obvious","careful","latter","obviously","unhappy","acceptable","aggressive","boring","distinct","eastern","logical","reasonable","strict","successfully","administrative","automatic","civil","former","massive","southern","unfair","visible","alive","angry","desperate","exciting","friendly","lucky","realistic","sorry","ugly","unlikely","anxious","comprehensive","curious","impressive","informal","inner","pleasant","sexual","sudden","terrible","unable","weak","wooden","asleep","confident","conscious","decent","embarrassed","guilty","lonely","mad","nervous","odd","remarkable","substantial","suspicious","tall","tiny"]}
var modal_verbs={any:["might","can","must","could","may","shall","should","will","would"]}
var modal_verbs_to={any:["want","like","love","need","try"]}
var nouns={any:["people","history","way","art","world","information","map","two","family","government","health","system","computer","meat","year","thanks","music","person","reading","method","data","food","understanding","theory","law","bird","literature","problem","software","control","knowledge","power","ability","economics","love","internet","television","science","library","nature","fact","product","idea","temperature","investment","area","society","activity","story","industry","media","thing","oven","community","definition","safety","quality","development","language","management","player","variety","video","week","security","country","exam","movie","organization","equipment","physics","analysis","policy","series","thought","basis","boyfriend","direction","strategy","technology","army","camera","freedom","paper","environment","child","instance","month","truth","marketing","university","writing","article","department","difference","goal","news","audience","fishing","growth","income","marriage","user","combination","failure","meaning","medicine","philosophy","teacher","communication","night","chemistry","disease","disk","energy","nation","road","role","soup","advertising","location","success","addition","apartment","education","math","moment","painting","politics","attention","decision","event","property","shopping","student","wood","competition","distribution","entertainment","office","population","president","unit","category","cigarette","context","introduction","opportunity","performance","driver","flight","length","magazine","newspaper","relationship","teaching","cell","dealer","finding","lake","member","message","phone","scene","appearance","association","concept","customer","death","discussion","housing","inflation","insurance","mood","woman","advice","blood","effort","expression","importance","opinion","payment","reality","responsibility","situation","skill","statement","wealth","application","city","county","depth","estate","foundation","grandmother","heart","perspective","photo","recipe","studio","topic","collection","depression","imagination","passion","percentage","resource","setting","ad","agency","college","connection","criticism","debt","description","memory","patience","secretary","solution","administration","aspect","attitude","director","personality","psychology","recommendation","response","selection","storage","version","alcohol","argument","complaint","contract","emphasis","highway","loss","membership","possession","preparation","steak","union","agreement","cancer","currency","employment","engineering","entry","interaction","mixture","preference","region","republic","tradition","virus","actor","classroom","delivery","device","difficulty","drama","election","engine","football","guidance","hotel","owner","priority","protection","suggestion","tension","variation","anxiety","atmosphere","awareness","bath","bread","candidate","climate","comparison","confusion","construction","elevator","emotion","employee","employer","guest","height","leadership","mall","manager","operation","recording","sample","transportation","charity","cousin","disaster","editor","efficiency","excitement","extent","feedback","guitar","homework","leader","mom","outcome","permission","presentation","promotion","reflection","refrigerator","resolution","revenue","session","singer","tennis","basket","bonus","cabinet","childhood","church","clothes","coffee","dinner","drawing","hair","hearing","initiative","judgment","lab","measurement","mode","mud","orange","poetry","police","possibility","procedure","queen","ratio","relation","restaurant","satisfaction","sector","signature","significance","song","tooth","town","vehicle","volume","wife","accident","airport","appointment","arrival","assumption","baseball","chapter","committee","conversation","database","enthusiasm","error","explanation","farmer","gate","girl","hall","historian","hospital","injury","instruction","maintenance","manufacturer","meal","perception","pie","poem","presence","proposal","reception","replacement","revolution","river","son","speech","tea","village","warning","winner","worker","writer","assistance","breath","buyer","chest","chocolate","conclusion","contribution","cookie","courage","dad","desk","drawer","establishment","examination","garbage","grocery","honey","impression","improvement","independence","insect","inspection","inspector","king","ladder","menu","penalty","piano","potato","profession","professor","quantity","reaction","requirement","salad","sister","supermarket","tongue","weakness","wedding","affair","ambition","analyst","apple","assignment","assistant","bathroom","bedroom","beer","birthday","celebration","championship","cheek","client","consequence","departure","diamond","dirt","ear","fortune","friendship","funeral","gene","girlfriend","hat","indication","intention","lady","midnight","negotiation","obligation","passenger","pizza","platform","poet","pollution","recognition","reputation","shirt","sir","speaker","stranger","surgery","sympathy","tale","throat","trainer","uncle","youth"]}
var verbs={any:["be","have","do","say","get","make","go","see","know","take","think","come","give","look","use","find","want","tell","put","mean","become","leave","work","need","feel","seem","ask","show","try","call","keep","provide","hold","turn","follow","begin","bring","like","going","help","start","run","write","set","move","play","pay","hear","include","believe","allow","meet","lead","live","stand","happen","carry","talk","appear","produce","sit","offer","consider","expect","suggest","let","read","require","continue","lose","add","change","fall","remain","remember","buy","speak","stop","send","receive","decide","win","understand","describe","develop","agree","open","reach","build","involve","spend","return","draw","die","hope","create","walk","sell","wait","cause","pass","lie","accept","watch","raise","base","apply","break","explain","learn","increase","cover","grow","claim","report","support","cut","form","stay","contain","reduce","establish","join","wish","achieve","seek","choose","deal","face","fail","serve","end","kill","occur","drive","represent","rise","discuss","love","pick","place","argue","prove","wear","catch","enjoy","eat","introduce","enter","present","arrive","ensure","point","plan","pull","refer","act","relate","affect","close","identify","manage","thank","compare","announce","obtain","note","forget","indicate","wonder","maintain","publish","suffer","avoid","express","suppose","finish","determine","design","listen","save","tend","treat","control","share","remove","throw","visit","exist","encourage","force","reflect","admit","assume","smile","prepare","replace","fill","improve","mention","fight","intend","miss","discover","drop","hit","push","prevent","refuse","regard","lay","reveal","teach","answer","operate","state","depend","enable","record","check","complete","cost","sound","laugh","realise","extend","arise","notice","define","examine","fit","study","bear","hang","recognise","shake","sign","attend","fly","gain","perform","result","travel","adopt","confirm","protect","demand","stare","imagine","attempt","beat","born","associate","care","marry","collect","voice","employ","issue","release","emerge","mind","aim","deny","mark","shoot","appoint","order","supply","drink","observe","reply","ignore","link","propose","ring","settle","strike","press","respond","arrange","survive","concentrate","lift","approach","cross","test","charge","experience","touch","acquire","commit","demonstrate","grant","prefer","repeat","sleep","threaten","feed","insist","launch","limit","promote","deliver","measure","own","retain","assess","attract","belong","consist","contribute","hide","promise","reject","cry","impose","invite","sing","vary","warn","address","declare","destroy","worry","divide","head","name","stick","nod","recognize","train","attack","clear","combine","handle","influence","realize","recommend","shout","spread","undertake","account","select","climb","contact","recall","secure","step","transfer","welcome","conclude","disappear","display","dress","illustrate","imply","organise","direct","escape","generate","investigate","remind","advise","afford","earn","hand","inform","rely","succeed","approve","burn","fear","vote","conduct","cope","derive","elect","gather","jump","last","match","matter","persuade","ride","shut","blow","estimate","recover","score","slip","count","hate","attach","exercise","house","lean","roll","wash","accompany","accuse","bind","explore","judge","rest","steal","comment","exclude","focus","hurt","stretch","withdraw","back","fix","justify","knock","pursue","switch","appreciate","benefit","lack","list","occupy","permit","surround","abandon","blame","complain","connect","construct","dominate","engage","paint","quote","view","acknowledge","dismiss","incorporate","interpret","proceed","search","separate","stress","alter","analyse","arrest","bother","defend","expand","implement","possess","review","suit","tie","assist","calculate","glance","mix","question","resolve","rule","suspect","wake","appeal","challenge","clean","damage","guess","reckon","restore","restrict","specify","constitute","convert","distinguish","submit","trust","urge","feature","land","locate","predict","preserve","solve","sort","struggle","cast","cook","dance","invest","lock","owe","pour","shift","kick","kiss","light","purchase","race","retire","bend","breathe","celebrate","date","fire","monitor","print","register","resist","behave","comprise","decline","detect","finance","organize","overcome","range","swing","differ","drag","guarantee","oppose","pack","pause","relax","resign","rush","store","waste","compete","expose","found","install","mount","negotiate","sink","split","whisper","assure","award","borrow","bury","capture","deserve","distribute","doubt","enhance","phone","sweep","tackle","advance","cease","concern","emphasise","exceed","qualify","slide","strengthen","transform","favour","grab","lend","participate","perceive","pose","practise","satisfy","scream","smoke","sustain","tear","adapt","adjust","ban","consult","dig","dry","highlight","outline","reinforce","shrug","snap","absorb","amount","block","confine","delay","encounter","entitle","plant","pretend","request","rid","sail","trace","trade","wave","cite","dream","flow","fulfil","lower","process","react","seize","allocate","burst","communicate","defeat","double","exploit","fund","govern","hurry","injure","pray","protest","sigh","smell","stir","swim","undergo","wander","anticipate","collapse","compose","confront","ease","eliminate","evaluate","grin","interview","remark","suspend","weigh","wipe","wrap","attribute","balance","bet","bound","cancel","condemn","convince","correspond","dare","devise","free","gaze","guide","inspire","modify","murder","prompt","reverse","rub","slow","spot","swear","telephone","wind","admire","bite","crash","disturb","greet","hesitate","induce","integrate","knit","line","load","murmur","render","shine","swallow","tap","translate","yield","accommodate","age","assert","await","book","brush","chase","comply","copy","criticise","devote","evolve","flee","forgive","initiate","interrupt","leap","mutter","overlook","risk","shape","spell","squeeze","trap","undermine","witness","beg","drift","echo","emphasize","enforce","exchange","fade","float","freeze","hire","in","object","pop","provoke","recruit","research","sense","situate","stimulate","abolish","administer","allege","command","consume","convey","correct","educate","equip","execute","fetch","frown","invent","march","park","progress","reserve","respect","twist","unite","value","assign","cater","concede","conceive","disclose","envisage","exhibit","export","extract","fancy","inherit","insert","instruct","interfere","isolate","opt","peer","persist","plead","price","regret","regulate","repair","resemble","resume","speed","spin","spring","update","advocate","assemble","boost","breed","cling","commission","conceal","contemplate","criticize","decorate","descend","drain","edit","embrace","excuse","explode","facilitate","flash","fold","function","grasp","incur","intervene","label","please","rescue","strip","tip","upset","advertise","aid","centre","classify","coincide","confess","contract","crack","creep","decrease","deem","dispose","dissolve","dump","endorse","formulate","import","impress","market","reproduce","scatter","schedule","ship","shop","spare","sponsor","stage","suck","sue","tempt","vanish","access","commence","contrast","depict","discharge","draft","enclose","enquire","erect","file","halt","hunt","inspect","omit","originate","praise","precede","relieve","reward","round","seal","signal","smash","spoil","subject","target","taste","tighten","top","tremble","tuck","warm","activate","amend","arouse","bang","bid","bow","campaign","characterise","circulate","clarify","compensate","compile","cool","couple","depart","deprive","desire","diminish","drown","embark","entail","entertain","figure","fling","guard","manufacture","melt","neglect","plunge","project","rain","reassure","rent","revive","sentence","shed","slam","spill","stem","sum","summon","supplement","suppress","surprise","tax","thrust","tour","transmit","transport","weaken","widen","bounce","calm","characterize","chat","clutch","confer","conform","confuse","convict","counter","debate","dedicate","dictate","disagree","effect","flood","forbid","grip","heat","long","manipulate","merge","part","pin","position","prescribe","proclaim","punish","rebuild","regain","sack","strain","stroke","substitute","supervise","term","time","toss","underline","abuse","accumulate","alert","arm","attain","boast","boil","carve","cheer","colour","compel","crawl","crush","curl","deposit","differentiate","dip","dislike","divert","embody","exert","exhaust","fine","frighten","fuck","gasp","honour","inhibit","motivate","multiply","narrow","obey","penetrate","picture","presume","prevail","pronounce","rate","renew","revise","rip","scan","scratch","shiver"]}
var article={singular:{any:["a","the"]},plural:{any:["the"]}}
var personal_pronouns_subject={singular:{first:["I"],second:["you"],third:["he","she","it"]},plural:{first:["we"],second:["you"],third:["they"]}}
var personal_pronouns_object={singular:{first:["me"],second:["you"],third:["him","her","it"]},plural:{first:["us"],second:["you"],third:["them"]}}
var possessive_pronouns={singular:{first:["my"],second:["your"],third:["his","her","its"]},plural:{first:["our"],second:["your"],third:["their"]}}
var indefinite_pronouns={singular:{any:["anybody","anyone","anything","nobody","noone","everybody","everyone","everything"]}}
var demonstrative_pronouns={singular:{any:["this","that"],},plural:{any:["these","those"]}}

var persons=["first","second","third"]
var number=["singular","plural"]
var tenses=["present","future","futureperfect","past","presentperfect","imperfect","conditional","pastconditional","pastperfect","presentprogressive","futureprogressive"]
var genders=["masculine","feminine","neuter"]

var wordTypes={ART: article,NOU: nouns,VRB: verbs,ADJ: adjectives,PPS: personal_pronouns_subject,PPO: personal_pronouns_object,PSP: possessive_pronouns,MVB: modal_verbs,MVT: modal_verbs_to,IDP: indefinite_pronouns,DEP: demonstrative_pronouns}

data/syntax_ENG.dsl

# ---- Syntax documentation----
# each non-comment line in this file represents a sentence structure
# every literal (e.g. XYZ) must have a corresponding field in the generator's wordTypes array, like wordTypes.XYZ, which holds all the applicable words of that type
#
# ---- Special characters ----
#   # line comment
#     (blank space) and (high precedence)
#   | xor (low precedence)
#   ? optional
#   : apply function
# "xyz": xyz as an absolute string (will not be modified)
#
# ============ EXAMPLE ============
#
# ((A|B) C:x D? E F".")
#
# yields an array with 4 sentences
# 
# A x(C) D E F.
# A x(C) E F.
# B x(C) D E F.
# B x(C) E F.

(((ART|DEP|PSP) ADJ? NOU)|PPS|IDP) (VRB:conjugate|MVB:conjugate|(MVT:conjugate VRB)) ((((ART|DEP|PSP) ADJ? NOU)|PPO) ADJ?:adverb)?("."|"!"|"...")
ART ADJ NOU VRB:conjugate

bg.jpg

You can click here to download this image file.

config.js

Here we will use Ultralingua API and Datamuse API to get multilingual translation dictionary and word-finding query engine functionality respectively.

var config = {
    conjugationApiUrl: "http://api.ultralingua.com/api/2.0/conjugations/eng/",
    semanticsApiUrl: "http://api.datamuse.com/words",
    defaultSettings: {
        language: "ENG"
    }
}

generator.js

function generator(initSettings) {
	var settings
	var sentenceStructures

	var initGenerator = function() {
		setSettings(initSettings)
		getDslFile("data/syntax_" + settings.language + ".dsl")
	}

	var addSentenceStructure = function(newSentenceStructure) {
		if(newSentenceStructure instanceof SentenceStructure) {
			sentenceStructures.concat(newSentenceStructure)
		}
	}

	var getSettings = function() {
		return settings
	}

	var setSettings = function(newSettings) {
		if(newSettings && newSettings instanceof GeneratorSettings) {
			settings = newSettings
		} else {
			settings = new GeneratorSettings(config.defaultSettings.language)
		}
	}

	var createSentence = function() {
		return getRandomSentence()
	}

	function conjugate() {
		function getConjugationResult(result) {
			var conjugation = result[0]["conjugations"].filter(function(c) {
				var tenseMatches = c["partofspeech"]["tense"] == sentence.tense
				var personMatches = !c["partofspeech"]["person"] || c["partofspeech"]["person"].indexOf(sentence.person) >= 0
				var numberMatches = !c["partofspeech"]["number"] || c["partofspeech"]["number"].indexOf(sentence.number) >= 0
				return tenseMatches && personMatches && numberMatches
			})
			document.getElementById("lyrics").textContent = conjugation[0]["surfaceform"]
		}

		utils.conjugationApiCall(verb, sentence, getConjugationResult)
	}

	var getRandomWord = function (type, sentence, modifyFunction) {
		if (!type || !wordTypes[type]) {
			var typeKeys = Object.keys(wordTypes)
			type = typeKeys[Math.floor(Math.random() * typeKeys.length)]
		}
		var words = getWordArrayForSentence(wordTypes[type], sentence)
		return words[Math.floor(Math.random() * words.length)]
	}

	function getRandomSentence() {
		var person = persons[Math.floor(Math.random() * persons.length)]
		var personNumber = number[Math.floor(Math.random() * number.length)]
		var tense = tenses[Math.floor(Math.random() * tenses.length)]
		var gender = person == "third" && number == "singular" ? genders[Math.floor(Math.random()*genders.length)] : undefined
		var language = settings.language

		return new Sentence(
			"",
			person,
			personNumber,
			tense,
			gender,
			null,
			language
		)
	}

	function getDslFile(url) {
		var request = new XMLHttpRequest();
		request.open("GET", url, true)
		request.onreadystatechange = function (){
			if(request.readyState === 4) {
				if(request.status === 200 || request.status == 0) {
					parseDsl(request.responseText);
				}
			}
		}
		request.send(null);
	}

	function validateDslLine(line) {
		// #1 parenthesis and quotation
		var parenthesisCount = 0
		if(line.match(/\"/g) && line.match(/\"/g).length % 2 != 0) {
			console.error("DSL validation failed: bad quotation")
			return false
		}
		for(var c in line) {
			if(!line.hasOwnProperty(c)) continue
			if(!line[c].match(/[\w|$|\(|\)|:|\?| |\||\"]/)) {
				var quotationsBefore = line.substring(0, c).match(/\"/g) ? line.substring(0, c).match(/\"/g).length : []
				var quotationsAfter = line.substring(parseInt(c)+1).match(/\"/g) ? line.substring(parseInt(c)+1).match(/\"/g).length : []
				if(quotationsBefore % 2 != 1 || quotationsAfter % 2 != 1) {
					var blanks = ""
					var n = 0
					while(n < c) {
						blanks += " "
						n++
					}
					console.error("DSL validation failed: unexpected character - '" + line[c] + "'\n" + line + "\n" + blanks + "^")
					return false
				}
			}
			if(line[c] == "(") {
				parenthesisCount += 1
			} else if(line[c] == ")") {
				parenthesisCount -= 1
				if(parenthesisCount < 0) {
					console.error("DSL validation failed: bad parenthesis")
					return false
				}
			}
		}
		if(parenthesisCount != 0) {
			console.error("DSL validation failed: bad parenthesis")
			return false
		}
		return true
	}

	function createSentenceStructureFromDslLine(dslLine) {
		var sentenceStructure = new SentenceStructure()

		function resolve(str, subParts) {
			var parenthesisIndex = str.indexOf("(")
			var blankIndex = str.indexOf(" ")
			var pipeIndex = str.indexOf("|")

			if(parenthesisIndex >= 0 && parenthesisIndex < blankIndex) {
				var innerPartClose = str.indexOf(")")
				var innerPartOpen = str.lastIndexOf("(")
				var innerPart = str.substring(innerPartOpen, innerPartClose)
			} else if(blankIndex >= 0 && parenthesisIndex > blankIndex) {
				// var part = 
			} else if(pipeIndex >= 0) {

			}
		}

		var rawParts = resolve(dslLine, [])

		// for(var rawPart of rawParts) {
		// 	var part = new SentenceStructurePart(type, modifyFunction)
		// 	sentenceStructure.addPart(part)
		// }

		addSentenceStructure(sentenceStructure)
	}

	function parseDsl(dslContent) {
		var lines = dslContent.split(/\r?\n/)
		lines = lines.filter(function(line) {
			return line && line.indexOf("#") != 0
		})
		for(var line of lines) {
			if(validateDslLine(line)) {
				var sentenceStructure = createSentenceStructureFromDslLine(line)
				addSentenceStructure(sentenceStructure)
			}
		}
	}

	function getWordArrayForSentence(array, sentence) {
		if(array && sentence) {
			if(array.any) return array.any
			if(array[sentence.number]) {
				if(array[sentence.number].any) return array[sentence.number].any
				else if(array[sentence.number][sentence.person]) return array[sentence.number][sentence.person]
			}
		}
		return null
	}

	initGenerator()

	return {
		getSettings: getSettings,
		setSettings: setSettings,
		createSentence: createSentence,
		addSentenceStructure: addSentenceStructure
	}
}

class Sentence {
	constructor(text, person, number, tense, gender, structure, language) {
		this.text = text
		this.person = person
		this.number = number
		this.tense = tense
		this.gender = gender
		this.structure = structure
		this.language = language
	}
}

class SentenceStructure {
	constructor(parts) {
		this.parts = parts
	}

	addPart(part) {
		part.added = true
		if(this.parts) {
			this.parts = this.parts.concat(part)
		} else {
			this.parts = [part]
		}
	}
}

class SentenceStructurePart {
	constructor(type, modifyFunction) {
		this.type = type
		this.modifyFunction = modifyFunction
		this.added = false
	}
}

class GeneratorSettings {
	constructor(language) {
		this.language = language
	}
}

index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script src="config.js"></script>
        <script src="data/dictionary_ENG.js"></script>
        <script src="utils.js"></script>
        <script src="generator.js"></script>
        <link rel="stylesheet" href="styles.css">
        <link href="https://fonts.googleapis.com/css?family=Thasadith" rel="stylesheet">
    </head>
    <body>
        <div id="background-image"></div>
        <button onClick="generator.createSentence()">Create</button>
        <br>
        <div id="lyrics"></div>
    </body>
    <script>
        var generator;

        (function() {
            generator = generator()
        })()
    </script>
</html>

styles.css

body {
    color: #92caff;
}

* {
    font-family: 'Thasadith', sans-serif;
    font-size: 20px;
}

button {
    background-color: rgba(146, 202, 255, 0.33);
    border: 1px solid rgba(146, 202, 255, 0.5);
    color: #92caff;
    transition: all .2s ease;
    text-shadow: 0 0 10px white;
    box-shadow: 0 0 0 0 rgba(146, 202, 255, 0.5);
}

button:hover,
button:active {
    background-color: rgba(146, 202, 255, 0.5);
    color: white;
    cursor: pointer;
    box-shadow: 0 0 5px 0 rgba(146, 202, 255, 0.5);
}

#background-image {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-image: url(bg.jpg);
    background-size: cover;
    z-index: -999;
}

#lyrics {
    display: inline-block;
    max-width: calc(100% - 20px);
    text-overflow: ellipsis;
    margin: 10px;
    padding: 10px;
    border: 1px solid rgba(255,255,255,.2);
    background-color: rgba(0,0,0,.5);
}

utils.js

var utils = {
    conjugationApiCall: function(verb, sentence, callback) {
        var xmlhttp = new XMLHttpRequest()
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == XMLHttpRequest.DONE) {
               if (xmlhttp.status == 200) {
                   callback(JSON.parse(xmlhttp.response))
               }
            }
        }
        var url = config.conjugationApiUrl + verb + "?tense=" + sentence.tense + "&person=" + sentence.person
        xmlhttp.open("GET", url, true);
        xmlhttp.send();
    }
}

Object.prototype.getAt = function(index) {
    return this[Object.keys(this)[index]]
}

Object.prototype.getKeyAt = function(index) {
    return Object.keys(this)[index]
}
0Shares

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.