{\n\t"origin": [\n\t\t"#soda# #concept# #flavor#",\n\t\t"#soda# #terribleflavor#",\n\t\t"Mountain Dew #concept# Blast",\n\t\t"#soda# #terribleflavor# #flavor#"\n\t],\n\t"soda": [\n\t\t"Mountain Dew",\n\t\t"Coca Cola",\n\t\t"Pepsi",\n\t\t"Fanta",\n\t\t"Crush",\n\t\t"Tab",\n\t\t"Jones Soda",\n\t\t"Slice",\n\t\t"Faygo",\n\t\t"Izze",\n\t\t"7 Up",\n\t\t"Sprite",\n\t\t"Schweppes",\n\t\t"Dr Pepper",\n\t\t"Mello Yello",\n\t\t"Zevia",\n\t\t"Hansen's",\n\t\t"Mr. Pibb",\n\t\t"Ramune"\n\t],\n\t"concept": [\n\t\t"Space",\n\t\t"Architecture",\n\t\t"Adventure",\n\t\t"Algorithm",\n\t\t"Artificial Intelligence",\n\t\t"Authenticity",\n\t\t"Bravery",\n\t\t"Civility",\n\t\t"Competition",\n\t\t"Control",\n\t\t"Cool",\n\t\t"Economy",\n\t\t"Empathy",\n\t\t"Ethics",\n\t\t"Freedom",\n\t\t"Family",\n\t\t"Government",\n\t\t"Humility",\n\t\t"Idealism",\n\t\t"Improvisation",\n\t\t"Magic",\n\t\t"Quality",\n\t\t"Realism",\n\t\t"Random",\n\t\t"Self-Fulfillment",\n\t\t"Universe",\n\t\t"Absolute",\n\t\t"Avant-garde",\n\t\t"Belief",\n\t\t"Being",\n\t\t"Beauty",\n\t\t"Camp",\n\t\t"Choice",\n\t\t"Class",\n\t\t"Concept",\n\t\t"Construct",\n\t\t"Creativity",\n\t\t"Cute",\n\t\t"Discourse",\n\t\t"Ecstasy",\n\t\t"Entity",\n\t\t"Eroticism",\n\t\t"Free Will",\n\t\t"Idea",\n\t\t"Infinity",\n\t\t"Intuition",\n\t\t"Judgement",\n\t\t"Justice",\n\t\t"Just War",\n\t\t"Knowledge",\n\t\t"Logic",\n\t\t"Love",\n\t\t"Notion",\n\t\t"Object",\n\t\t"Panopticon",\n\t\t"Passions",\n\t\t"Paradox",\n\t\t"Peace",\n\t\t"Pattern",\n\t\t"Qualia",\n\t\t"Rationality",\n\t\t"Reason",\n\t\t"Simulacrum",\n\t\t"Sublime",\n\t\t"Subject",\n\t\t"Symbol",\n\t\t"Syntax",\n\t\t"Suffering",\n\t\t"Thought",\n\t\t"Transcendent",\n\t\t"Truth",\n\t\t"Trust",\n\t\t"Universal",\n\t\t"Utility",\n\t\t"Virtual",\n\t\t"Virtue",\n\t\t"Value",\n\t\t"Wrong",\n\t\t"Zeitgeist",\n\t\t"Symbol",\n\t\t"Abstract",\n\t\t"Conceptual"\n\t],\n\t"flavor": [\n\t\t"Abiu",\n\t\t"Açaí",\n\t\t"Acerola",\n\t\t"Akebi",\n\t\t"Ackee",\n\t\t"African Cherry Orange",\n\t\t"American Mayapple",\n\t\t"Apple",\n\t\t"Apricot",\n\t\t"Aratiles",\n\t\t"Araza",\n\t\t"Atis",\n\t\t"Avocado",\n\t\t"Banana",\n\t\t"Bilberry",\n\t\t"Blackberry",\n\t\t"Blackcurrant",\n\t\t"Black Sapote",\n\t\t"Blueberry",\n\t\t"Boysenberry",\n\t\t"Breadfruit",\n\t\t"Buddha's Hand",\n\t\t"Cacao",\n\t\t"Cactus Pear",\n\t\t"Canistel",\n\t\t"Catmon",\n\t\t"Cempedak",\n\t\t"Cherimoya",\n\t\t"Cherry",\n\t\t"Chico Fruit",\n\t\t"Cloudberry",\n\t\t"Coco De Mer",\n\t\t"Coconut",\n\t\t"Crab Apple",\n\t\t"Cranberry",\n\t\t"Currant",\n\t\t"Damson",\n\t\t"Date",\n\t\t"Dragonfruit",\n\t\t"Durian",\n\t\t"Elderberry",\n\t\t"Feijoa",\n\t\t"Fig",\n\t\t"Finger Lime",\n\t\t"Gac Fruit",\n\t\t"Goji Berry",\n\t\t"Gooseberry",\n\t\t"Grape",\n\t\t"Raisin",\n\t\t"Grapefruit",\n\t\t"Grewia Asiatica",\n\t\t"Guava",\n\t\t"Guyabano",\n\t\t"Hala Fruit",\n\t\t"Honeyberry",\n\t\t"Huckleberry",\n\t\t"Jabuticaba",\n\t\t"Jackfruit",\n\t\t"Jambul",\n\t\t"Japanese Plum",\n\t\t"Jostaberry",\n\t\t"Jujube",\n\t\t"Juniper Berry",\n\t\t"Kaffir Lime",\n\t\t"Kiwano",\n\t\t"Kiwifruit",\n\t\t"Kumquat",\n\t\t"Lanzones",\n\t\t"Lemon",\n\t\t"Lime",\n\t\t"Loganberry",\n\t\t"Longan",\n\t\t"Loquat",\n\t\t"Lulo",\n\t\t"Lychee",\n\t\t"Magellan Barberry",\n\t\t"Macopa",\n\t\t"Mamey Apple",\n\t\t"Mamey Sapote",\n\t\t"Mango",\n\t\t"Mangosteen",\n\t\t"Marionberry",\n\t\t"Medlar",\n\t\t"Melon",\n\t\t"Cantaloupe",\n\t\t"Galia Melon",\n\t\t"Honeydew",\n\t\t"Mouse Melon",\n\t\t"Musk Melon",\n\t\t"Watermelon",\n\t\t"Miracle Fruit",\n\t\t"Momordica Fruit",\n\t\t"Monstera Deliciosa",\n\t\t"Mulberry",\n\t\t"Nance",\n\t\t"Nectarine",\n\t\t"Orange",\n\t\t"Blood Orange",\n\t\t"Clementine",\n\t\t"Mandarine",\n\t\t"Tangerine",\n\t\t"Papaya",\n\t\t"Passionfruit",\n\t\t"Pawpaw",\n\t\t"Peach",\n\t\t"Pear",\n\t\t"Persimmon",\n\t\t"Plantain",\n\t\t"Plum",\n\t\t"Prune",\n\t\t"Pineapple",\n\t\t"Pineberry",\n\t\t"Plumcot",\n\t\t"Pomegranate",\n\t\t"Pomelo",\n\t\t"Purple Mangosteen",\n\t\t"Quince",\n\t\t"Raspberry",\n\t\t"Salmonberry",\n\t\t"Rambutan",\n\t\t"Redcurrant",\n\t\t"Rose Apple",\n\t\t"Salal Berry",\n\t\t"Salak",\n\t\t"Santol",\n\t\t"Sampaloc",\n\t\t"Sapodilla",\n\t\t"Sapote",\n\t\t"Sarguelas",\n\t\t"Satsuma",\n\t\t"Soursop",\n\t\t"Star Apple",\n\t\t"Star Fruit",\n\t\t"Strawberry",\n\t\t"Surinam Cherry",\n\t\t"Tamarillo",\n\t\t"Tamarind",\n\t\t"Tangelo",\n\t\t"Tayberry",\n\t\t"Tambis",\n\t\t"Thimbleberry",\n\t\t"Ugli Fruit",\n\t\t"White Currant",\n\t\t"White Sapote",\n\t\t"Ximenia",\n\t\t"Yuzu"\n\t],\n\t"terribleflavor": [\n\t\t"Trout",\n\t\t"Curry ",\n\t\t"Garlic ",\n\t\t"Cayene",\n\t\t"Celery ",\n\t\t"Blue Cheese ",\n\t\t"Cheese ",\n\t\t"Chilli ",\n\t\t"Chive ",\n\t\t"Garlic ",\n\t\t"Lemongrass ",\n\t\t"Onion ",\n\t\t"Peanut ",\n\t\t"Peanut Butter ",\n\t\t"Pistacho ",\n\t\t"Smoke ",\n\t\t"Sour Cream ",\n\t\t"Sweetcorn ",\n\t\t"Nut",\n\t\t"Almond ",\n\t\t"Chestnut ",\n\t\t"Hazelnut ",\n\t\t"Peanut ",\n\t\t"Peanut Butter ",\n\t\t"Pistacho ",\n\t\t"Walnut ",\n\t\t"Bacon ",\n\t\t"Beef ",\n\t\t"Chicken ",\n\t\t"Octopus ",\n\t\t"Rabbit ",\n\t\t"White Fish ",\n\t\t"Fish Oil ",\n\t\t"Basil ",\n\t\t"Bunspice ",\n\t\t"Capsicum ",\n\t\t"Cardamom ",\n\t\t"Cassia ",\n\t\t"Cayene pepper ",\n\t\t"Chilli ",\n\t\t"Chive ",\n\t\t"Cinnamon ",\n\t\t"Clove ",\n\t\t"Dill ",\n\t\t"Ginger ",\n\t\t"Licorice",\n\t\t"Nutmeg",\n\t\t"Bell Pepper",\n\t\t"Carolina Reaper",\n\t\t"Chile Pepper",\n\t\t"Corn Kernel",\n\t\t"Cucumber",\n\t\t"Eggplant",\n\t\t"Jalapeño",\n\t\t"Olive",\n\t\t"Pea",\n\t\t"Pumpkin",\n\t\t"Squash",\n\t\t"Tomato",\n\t\t"Zucchini",\n\t\t"Artichoke",\n\t\t"Aubergine",\n\t\t"Asparagus",\n\t\t"Broccoflower",\n\t\t"Broccoli",\n\t\t"Brussels Sprouts",\n\t\t"Cabbage",\n\t\t"Kohlrabi",\n\t\t"Savoy Cabbage",\n\t\t"Red Cabbage",\n\t\t"Cauliflower",\n\t\t"Celery",\n\t\t"Endive",\n\t\t"Fiddleheads",\n\t\t"Frisee",\n\t\t"Fennel",\n\t\t"Greens",\n\t\t"Arugula",\n\t\t"Bok Choy",\n\t\t"Chard",\n\t\t"Collard Greens",\n\t\t"Kale",\n\t\t"Lettuce",\n\t\t"Mustard Greens",\n\t\t"Spinach",\n\t\t"Herbs",\n\t\t"Anise",\n\t\t"Basil",\n\t\t"Caraway",\n\t\t"Coriander",\n\t\t"Chamomile",\n\t\t"Daikon",\n\t\t"Dill",\n\t\t"Fennel",\n\t\t"Lavender",\n\t\t"Cymbopogon",\n\t\t"Marjoram",\n\t\t"Oregano",\n\t\t"Parsley",\n\t\t"Rosemary",\n\t\t"Thyme",\n\t\t"Legumes",\n\t\t"Alfalfa Sprouts",\n\t\t"Azuki Beans",\n\t\t"Bean Sprouts",\n\t\t"Black Beans",\n\t\t"Black-eyed Peas",\n\t\t"Borlotti Bean",\n\t\t"Broad Beans",\n\t\t"Chickpea",\n\t\t"Green Beans",\n\t\t"Kidney Beans",\n\t\t"Lentils",\n\t\t"Lima Beans Or Butter Bean",\n\t\t"Mung Beans",\n\t\t"Navy Beans",\n\t\t"Peanuts",\n\t\t"Pinto Beans",\n\t\t"Runner Beans",\n\t\t"Split Peas",\n\t\t"Soy Beans",\n\t\t"Peas",\n\t\t"Mange Tout Or Snap Peas",\n\t\t"Mushrooms",\n\t\t"Nettles",\n\t\t"New Zealand Spinach",\n\t\t"Okra",\n\t\t"Onions",\n\t\t"Chives",\n\t\t"Garlic",\n\t\t"Leek",\n\t\t"Onion",\n\t\t"Shallot",\n\t\t"Scallion",\n\t\t"Peppers",\n\t\t"Bell Pepper",\n\t\t"Chili Pepper",\n\t\t"Jalapeño",\n\t\t"Habanero",\n\t\t"Paprika",\n\t\t"Tabasco Pepper",\n\t\t"Cayenne Pepper",\n\t\t"Radicchio",\n\t\t"Rhubarb",\n\t\t"Root Vegetables",\n\t\t"Beetroot",\n\t\t"Mangelwurzel",\n\t\t"Carrot",\n\t\t"Celeriac",\n\t\t"Corms",\n\t\t"Eddoe",\n\t\t"Konjac",\n\t\t"Taro",\n\t\t"Water Chestnut",\n\t\t"Ginger",\n\t\t"Parsnip",\n\t\t"Rutabaga",\n\t\t"Radish",\n\t\t"Wasabi",\n\t\t"Horseradish",\n\t\t"Daikon Or White Radish",\n\t\t"Tubers",\n\t\t"Jicama",\n\t\t"Jerusalem Artichoke",\n\t\t"Potato",\n\t\t"Sweet Potato",\n\t\t"Yam",\n\t\t"Turnip",\n\t\t"Salsify",\n\t\t"Skirret",\n\t\t"Sweetcorn",\n\t\t"Topinambur",\n\t\t"Squashes",\n\t\t"Acorn Squash",\n\t\t"Bitter Melon",\n\t\t"Butternut Squash",\n\t\t"Banana Squash",\n\t\t"Courgette",\n\t\t"Cucumber",\n\t\t"Delicata",\n\t\t"Gem Squash",\n\t\t"Hubbard Squash",\n\t\t"Marrow",\n\t\t"Spaghetti Squash",\n\t\t"Tat Soi",\n\t\t"Watercress"\n\t]\n}
v.2016-09-05
//requires jquery\n\n// input: an array of objects\n//\t\t a property that each of those object have\n// output: an array of the properties of all the objects\nwindow.skimObjectArray = function(objectArray, property){\n\tconsole.log("skimObjectArray(", "objectArray", objectArray, "property", property, ")")\n\tvar values = [];\n\n\tfor (var i = 0; i < objectArray.length; i++) {\n\t\tvar thingToAdd = objectArray[i][property];\n\t\tif(typeof thingToAdd === "object"){\n\t\t\t// i hope to god this works\n\t\t\tthingToAdd = objectArray[i][property].join("\sn")\n\t\t}\n\t\tvalues.push( thingToAdd );\n\t};\n\n\tvalues = values.join("\sn");\n\tvalues = values.split("\sn")\n\n\treturn values;\n}\n\nStory.prototype.appendCorpora = function(){\n\tvar corporaToAppend = tale.lookup("tags", "corpus");\n\tif(!corporaToAppend.length) return;\n\n\tfor(var i in corporaToAppend){\n\t\tvar currentPassage = corporaToAppend[i].title;\n\n\t\t// the rules are the concatenation of each symbol in this passage\n\t\tvar rules = [];\n\t\tvar lines = tale.passages[currentPassage].text.split("\sn")\n\t\tfor(var j in lines){\n\t\t\tvar line = lines[j];\n\t\t\tvar location = line.split("#");\n\t\t\tconsole.log("location: ", location);\n\t\t\tvar corpusLocation = location[0];\n\n\t\t\t// fetch me that sweet sweet boy\n\t\t\tvar corpus = $.ajax({\n\t\t\t\tdataType: "json",\n\t\t\t\turl: corpusLocation,\n\t\t\t\tasync: false\n\t\t\t});\n\t\t\tcorpus = corpus.responseJSON;\n\n\t\t\t// drill down to the array we want\n\t\t\tfor (var i = 1; i < location.length; i++) {\n\t\t\t\tconsole.log("corpus: ", corpus);\n\t\t\t\t// if there's a ! at the beginning of a location, skim the objArray for that property\n\t\t\t\tif(location[i][0] === "!"){\n\t\t\t\t\tcorpus = skimObjectArray(corpus, location[i].substring(1));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tcorpus = corpus[ location[i] ]\n\t\t\t};\n\n\t\t\tconsole.log("corpus: ", corpus);\n\t\t\t// add this into the symbol-in-progress\n\t\t\trules = rules.concat(corpus);\n\t\t\tconsole.log("rules: ", rules)\n\t\t}\n\n\t\t// the name of this symbol is the name of the passage\n\t\tvar finalJSON = "{ \s"" + currentPassage + "\s": " + JSON.stringify(rules) + " }";\n\n\t\t// save our dark deeds to the passage\n\t\ttale.passages[currentPassage].text = finalJSON;\n\n\t\t//tag this as JSON so it gets appended in the next step\n\t\ttale.passages[currentPassage].tags.push("JSON")\n\t}\n\n\tconsole.log("corpora loaded")\n}\n\nStory.prototype.appendJSON = function() {\n\tvar JSONtoAppend = tale.lookup("tags", "JSON");\n\tif(!JSONtoAppend.length) return;\n\n\tfor(i in JSONtoAppend){\n\t\tvar newJSON = JSON.parse(JSONtoAppend[i].text);\n\t\t$.extend(this.data, newJSON);\n\t}\n\tconsole.log("JSON appended");\n}\n\nfunction Story(){\n\tvar grammars = tale.lookup("tags", "grammar", "title");\n\tthis.data = {};\n\n\tvar links = /(\s[\s[\sb)(.+?)(\sb\s]\s])/g;\n\tvar sublinks = /([^\s[\s]]+)*(.+)/\n\n\tfunction convertSyntax(match, p1, p2, p3){\n\t\t// If a passage is invoked that's tagged as a grammar, change Twine links into Tracery symbols.\n\t\t// e.g.: [[animal]] => #animal#\n\t\t// e.g.: [[animal][capitalize]] => #animal.capitalize#\n\n\t\t// p1 is left brackets, p3 is right brackets\n\t\tvar targetLink = p2.split("][")[0];\n\t\tvar modifiers = p2.split("][").slice(1, p2.length).join(".");\n\t\tmodifiers = modifiers?("." + modifiers):"";\n\t\t\n\t\tvar trace = "#" + targetLink + modifiers + "#";\n\t\t\n\t\tvar linkIsGrammar = false;\n\t\tvar tags = tale.get(targetLink).tags\n\t\tfor(var i = 0; i < tags.length; i++){\n\t\t\tif(tags[i] == "grammar" || tags[i] == "corpus"){\n\t\t\t\tlinkIsGrammar = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn linkIsGrammar?trace:match;\n\t}\n\n\tfor(var i in grammars){\n\t\tif(grammars[i] == undefined) continue;\n\n\t\t// Passage names become grammar names, Passage text becomes grammar text. \n\t\tvar newSymbol = grammars[i].title\n\t\tvar newText = grammars[i].text\n\n\t\tvar link = /(\s[\s[\sb)(.+?)(\sb\s]\s])/g;\n\t\tnewText = newText.replace(link, convertSyntax);\n\t\t// Get everything that's being linked to.\n\n\t\tthis.data[newSymbol] = newText.split('\sn');\n\t}\n\n\tthis.appendCorpora();\n\tthis.appendJSON();\n\tconsole.log("Story: ", this);\n}\nStory.prototype.constructor = Story;\n\n// Append this to the tale object because I don't know where else to put it.\nTale.prototype.story = new Story();\n\nStory.prototype.toHTML = function() {\n\tvar output = [];\n\tvar tab = " ";\n\tvar beg = '\sn' + tab + "\s"<span class=\s"grammarContents\s">{{{"\n\tvar end = "}}}</span>\s""\n\n\tfor(var i in this.data){\n\t\tvar gram = "<span class=\s"grammarTitle\s">\s"" + i + "\s"</span>: [";\n\t\tgram += beg + this.data[i].join(end + ',' + beg) + end;\n\t\tgram += "]";\n\t\toutput.push(gram);\n\t}\n\treturn "{\sn" + output.join(",\sn") + "\sn}";\n}\n\nTale.prototype.JSONtoTwee = function() {\n\tvar JSONtoConvert = tale.lookup("tags", "JSON");\n\tvar combinedJSON = ""\n\n\tfor (var i in JSONtoConvert){\n\t\tcombinedJSON += JSONtoConvert[i].text;\n\t}\n\n\t// Note the {{{}}} delimiters in textPost. This is intended for display in Twine, so\n\t// if you're just running these raw they aren't necessary.\n\tvar regex = {titlesPre: /\st"(.+)": \s[/g, titlesPost: "<br>:: $1 [grammar]",\n\t\t\t\t textPre: /\st*"(.+)",*(?:\sn\st)?(?:\s],)*\sn/g, textPost: "{{{$1}}}<br>"}\n\n\tvar tweeOutput = combinedJSON.replace(regex.titlesPre, regex.titlesPost);\n\ttweeOutput = tweeOutput.replace(regex.textPre, regex.textPost);\n\ttweeOutput = tweeOutput.replace(/({\sn)|(]\sn})/g, "")\n\n\treturn tweeOutput;\n}
window.tracery = {\n utilities : {}\n};\n\n(function () {/**\n * @author Kate Compton\n */\n\nfunction inQuotes(s) {\n return '"' + s + '"';\n};\n\nfunction parseAction(action) {\n return action;\n};\n\n// tag format\n// a thing to expand, plus actions\n\nfunction parseTag(tag) {\n var errors = [];\n var prefxns = [];\n var postfxns = [];\n\n var lvl = 0;\n var start = 0;\n\n var inPre = true;\n\n var symbol,\n mods;\n\n function nonAction(end) {\n if (start !== end) {\n var section = tag.substring(start, end);\n if (!inPre) {\n errors.push("multiple possible expansion symbols in tag!" + tag);\n } else {\n inPre = false;\n var split = section.split(".");\n symbol = split[0];\n mods = split.slice(1, split.length);\n }\n\n }\n start = end;\n };\n\n for (var i = 0; i < tag.length; i++) {\n var c = tag.charAt(i);\n\n switch(c) {\n case '[':\n if (lvl === 0) {\n nonAction(i);\n }\n\n lvl++;\n break;\n case ']':\n lvl--;\n if (lvl === 0) {\n var section = tag.substring(start + 1, i);\n if (inPre)\n prefxns.push(parseAction(section));\n else\n postfxns.push(parseAction(section));\n start = i + 1;\n }\n break;\n\n default:\n if (lvl === 0) {\n\n }\n break;\n\n }\n }\n nonAction(i);\n\n if (lvl > 0) {\n var error = "Too many '[' in rule " + inQuotes(tag);\n errors.push(error);\n\n }\n\n if (lvl < 0) {\n var error = "Too many ']' in rule " + inQuotes(tag);\n errors.push(error);\n\n }\n\n return {\n preActions : prefxns,\n postActions : postfxns,\n symbol : symbol,\n mods : mods,\n raw : tag,\n errors : errors,\n };\n};\n\n// Split a rule into sections\nfunction parseRule(rule) {\n var sections = [];\n var errors = [];\n if (!( typeof rule == 'string' || rule instanceof String)) {\n errors.push("Cannot parse non-string rule " + rule);\n sections.errors = errors;\n return sections;\n }\n\n if (rule.length === 0) {\n return [];\n }\n\n var lvl = 0;\n var start = 0;\n var inTag = false;\n\n function createSection(end) {\n var section = rule.substring(start, end);\n if (section.length > 0) {\n if (inTag)\n sections.push(parseTag(section));\n else\n sections.push(section);\n }\n inTag = !inTag;\n start = end + 1;\n\n }\n\n for (var i = 0; i < rule.length; i++) {\n var c = rule.charAt(i);\n\n switch(c) {\n case '[':\n lvl++;\n break;\n case ']':\n lvl--;\n break;\n case '#':\n if (lvl === 0) {\n createSection(i);\n }\n break;\n default:\n break;\n\n }\n\n }\n\n if (lvl > 0) {\n var error = "Too many '[' in rule " + inQuotes(rule);\n errors.push(error);\n\n }\n\n if (lvl < 0) {\n var error = "Too many ']' in rule " + inQuotes(rule);\n errors.push(error);\n\n }\n\n if (inTag) {\n var error = "Odd number of '#' in rule " + inQuotes(rule);\n errors.push(error);\n }\n\n createSection(rule.length);\n sections.errors = errors;\n return sections;\n};\n\nfunction testParse(rule, shouldFail) {\n console.log("-------");\n console.log("Test parse rule: " + inQuotes(rule) + " " + shouldFail);\n var parsed = parseRule(rule);\n if (parsed.errors && parsed.errors.length > 0) {\n for (var i = 0; i < parsed.errors.length; i++) {\n console.log(parsed.errors[i]);\n }\n }\n \n\n}\n\nfunction testParseTag(tag, shouldFail) {\n console.log("-------");\n console.log("Test parse tag: " + inQuotes(tag) + " " + shouldFail);\n var parsed = parseTag(tag);\n if (parsed.errors && parsed.errors.length > 0) {\n for (var i = 0; i < parsed.errors.length; i++) {\n console.log(parsed.errors[i]);\n }\n }\n}\n\ntracery.testParse = testParse;\ntracery.testParseTag = testParseTag;\ntracery.parseRule = parseRule;\ntracery.parseTag = parseTag;\n\n\nfunction spacer(size) {\n var s = "";\n for (var i = 0; i < size * 3; i++) {\n s += " ";\n }\n return s;\n}\n\n/* Simple JavaScript Inheritance\n * By John Resig http://ejohn.org/\n * MIT Licensed.\n */\n\nfunction extend(destination, source) {\n for (var k in source) {\n if (source.hasOwnProperty(k)) {\n destination[k] = source[k];\n }\n }\n return destination;\n}\n\n// Inspired by base2 and Prototype\n(function() {\n var initializing = false,\n fnTest = /xyz/.test(function() { xyz;\n }) ? /\sb_super\sb/ : /.*/;\n\n // The base Class implementation (does nothing)\n this.Class = function() {\n };\n\n // Create a new Class that inherits from this class\n Class.extend = function(prop) {\n var _super = this.prototype;\n\n // Instantiate a base class (but only create the instance,\n // don't run the init constructor)\n initializing = true;\n var prototype = new this();\n initializing = false;\n\n // Copy the properties over onto the new prototype\n for (var name in prop) {\n // Check if we're overwriting an existing function\n prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn) {\n return function() {\n var tmp = this._super;\n\n // Add a new ._super() method that is the same method\n // but on the super-class\n this._super = _super[name];\n\n // The method only need to be bound temporarily, so we\n // remove it when we're done executing\n var ret = fn.apply(this, arguments);\n this._super = tmp;\n\n return ret;\n };\n })(name, prop[name]) : prop[name];\n }\n\n // The dummy class constructor\n function Class() {\n // All construction is actually done in the init method\n if (!initializing && this.init)\n this.init.apply(this, arguments);\n }\n\n // Populate our constructed prototype object\n Class.prototype = prototype;\n\n // Enforce the constructor to be what we expect\n Class.prototype.constructor = Class;\n\n // And make this class extendable\n Class.extend = arguments.callee;\n\n return Class;\n };\n})();\n\n/**\n * @author Kate\n */\n\nvar Rule = function(raw) {\n this.raw = raw;\n this.sections = parseRule(raw);\n\n};\n\nRule.prototype.getParsed = function() {\n if (!this.sections)\n this.sections = parseRule(raw);\n\n return this.sections;\n};\n\nRule.prototype.toString = function() {\n return this.raw;\n};\n\nRule.prototype.toJSONString = function() {\n return this.raw;\n};\n\n/**\n * @author Kate\n */\n\nvar RuleWeighting = Object.freeze({\n RED : 0,\n GREEN : 1,\n BLUE : 2\n});\n\nvar RuleSet = function(rules) {\n // is the rules obj an array? A RuleSet, or a string?\n if (rules.constructor === Array) {\n // make a copy\n rules = rules.slice(0, rules.length);\n } else if (rules.prototype === RuleSet) {\n // clone\n } else if ( typeof rules == 'string' || rules instanceof String) {\n var args = Array.prototype.slice.call(arguments);\n rules = args;\n } else {\n console.log(rules);\n throw ("creating ruleset with unknown object type!");\n }\n\n // create rules and their use counts\n\n this.rules = rules;\n this.parseAll();\n\n this.uses = [];\n this.startUses = [];\n this.totalUses = 0;\n for (var i = 0; i < this.rules.length; i++) {\n this.uses[i] = 0;\n this.startUses[i] = this.uses[i];\n this.totalUses += this.uses[i];\n }\n\n};\n\n//========================================================\n// Iterating over rules\n\nRuleSet.prototype.parseAll = function(fxn) {\n for (var i = 0; i < this.rules.length; i++) {\n if (this.rules[i].prototype !== Rule)\n this.rules[i] = new Rule(this.rules[i]);\n }\n\n};\n\n//========================================================\n// Iterating over rules\n\nRuleSet.prototype.mapRules = function(fxn) {\n return this.rules.map(function(rule, index) {\n return fxn(rule, index);\n });\n};\n\nRuleSet.prototype.applyToRules = function(fxn) {\n for (var i = 0; i < this.rules.length; i++) {\n fxn(this.rules[i], i);\n }\n};\n//========================================================\nRuleSet.prototype.get = function() {\n var index = this.getIndex();\n\n return this.rules[index];\n};\n\nRuleSet.prototype.getRandomIndex = function() {\n return Math.floor(this.uses.length * Math.random());\n};\n\nRuleSet.prototype.getIndex = function() {\n // Weighted distribution\n // Imagine a bar of length 1, how to divide the length\n // s.t. a random dist will result in the dist we want?\n\n var index = this.getRandomIndex();\n // What if the uses determine the chance of rerolling?\n\n var median = this.totalUses / this.uses.length;\n\n var count = 0;\n while (this.uses[index] > median && count < 20) {\n index = this.getRandomIndex();\n count++;\n }\n\n // reroll more likely if index is too much higher\n\n return index;\n};\n\nRuleSet.prototype.decayUses = function(pct) {\n this.totalUses = 0;\n for (var i = 0; i < this.uses; i++) {\n\n this.uses[index] *= 1 - pct;\n this.totalUses += this.uses[index];\n }\n};\n\nRuleSet.prototype.testRandom = function() {\n console.log("Test random");\n var counts = [];\n for (var i = 0; i < this.uses.length; i++) {\n counts[i] = 0;\n }\n\n var testCount = 10 * this.uses.length;\n for (var i = 0; i < testCount; i++) {\n\n var index = this.getIndex();\n this.uses[index] += 1;\n\n counts[index]++;\n this.decayUses(.1);\n }\n\n for (var i = 0; i < this.uses.length; i++) {\n console.log(i + ":\st" + counts[i] + " \st" + this.uses[i]);\n }\n};\n\nRuleSet.prototype.getSaveRules = function() {\n var jsonRules = this.rules.map(function(rule) {\n return rule.toJSONString();\n });\n\n return jsonRules;\n};\n\n/**\n * @author Kate Compton\n */\n\nvar Action = function(node, raw) {\n\n this.node = node;\n this.grammar = node.grammar;\n this.raw = raw;\n\n};\n\nAction.prototype.activate = function() {\n\n var node = this.node;\n node.actions.push(this);\n\n // replace any hashtags\n this.amended = this.grammar.flatten(this.raw);\n\n var parsed = parseTag(this.amended);\n var subActionRaw = parsed.preActions;\n if (subActionRaw && subActionRaw.length > 0) {\n this.subactions = subActionRaw.map(function(action) {\n return new Action(node, action);\n });\n\n }\n\n if (parsed.symbol) {\n var split = parsed.symbol.split(":");\n\n if (split.length === 2) {\n this.push = {\n symbol : split[0],\n\n // split into multiple rules\n rules : split[1].split(","),\n };\n // push\n node.grammar.pushRules(this.push.symbol, this.push.rules);\n\n } else\n throw ("Unknown action: " + parsed.symbol);\n }\n\n if (this.subactions) {\n for (var i = 0; i < this.subactions.length; i++) {\n this.subactions[i].activate();\n }\n }\n\n};\n\nAction.prototype.deactivate = function() {\n if (this.subactions) {\n for (var i = 0; i < this.subactions.length; i++) {\n this.subactions[i].deactivate();\n }\n }\n\n if (this.push) {\n this.node.grammar.popRules(this.push.symbol, this.push.rules);\n }\n};\n\n/**\n * @author Kate Compton\n */\n\nvar isConsonant = function(c) {\n c = c.toLowerCase();\n switch(c) {\n case 'a':\n return false;\n case 'e':\n return false;\n case 'i':\n return false;\n case 'o':\n return false;\n case 'u':\n return false;\n\n }\n return true;\n};\n\nfunction endsWithConY(s) {\n if (s.charAt(s.length - 1) === 'y') {\n return isConsonant(s.charAt(s.length - 2));\n }\n return false;\n};\n\nvar universalModifiers = {\n capitalizeAll : function(s) {\n return s.replace(/(?:^|\ss)\sS/g, function(a) {\n return a.toUpperCase();\n });\n\n },\n\n capitalize : function(s) {\n return s.charAt(0).toUpperCase() + s.slice(1);\n\n },\n\n inQuotes : function(s) {\n return '"' + s + '"';\n },\n\n comma : function(s) {\n var last = s.charAt(s.length - 1);\n if (last === ",")\n return s;\n if (last === ".")\n return s;\n if (last === "?")\n return s;\n if (last === "!")\n return s;\n return s + ",";\n },\n\n beeSpeak : function(s) {\n // s = s.replace("s", "zzz");\n\n s = s.replace(/s/, 'zzz');\n return s;\n },\n\n a : function(s) {\n if (!isConsonant(s.charAt()))\n return "an " + s;\n return "a " + s;\n\n },\n\n s : function(s) {\n\n var last = s.charAt(s.length - 1);\n\n switch(last) {\n case 'y':\n\n // rays, convoys\n if (!isConsonant(s.charAt(s.length - 2))) {\n return s + "s";\n }\n // harpies, cries\n else {\n return s.slice(0, s.length - 1) + "ies";\n }\n break;\n\n // oxen, boxen, foxen\n case 'x':\n return s.slice(0, s.length - 1) + "en";\n case 'z':\n return s.slice(0, s.length - 1) + "es";\n case 'h':\n return s.slice(0, s.length - 1) + "es";\n\n default:\n return s + "s";\n };\n\n },\n\n ed : function(s) {\n\n var index = s.indexOf(" ");\n var s = s;\n var rest = "";\n if (index > 0) {\n rest = s.substring(index, s.length);\n s = s.substring(0, index);\n\n }\n\n var last = s.charAt(s.length - 1);\n\n switch(last) {\n case 'y':\n\n // rays, convoys\n if (isConsonant(s.charAt(s.length - 2))) {\n return s.slice(0, s.length - 1) + "ied" + rest;\n\n }\n // harpies, cries\n else {\n return s + "ed" + rest;\n }\n break;\n case 'e':\n return s + "d" + rest;\n\n break;\n\n default:\n return s + "ed" + rest;\n };\n }\n};\n/**\n * @author Kate Compton\n */\n\n// A tracery expansion node\nvar nodeCount = 0;\n\nvar ExpansionNode = Class.extend({\n init : function() {\n this.depth = 0;\n this.id = nodeCount;\n nodeCount++;\n this.childText = "[[UNEXPANDED]]";\n },\n\n setParent : function(parent) {\n if (parent) {\n this.depth = parent.depth + 1;\n this.parent = parent;\n this.grammar = parent.grammar;\n }\n },\n\n expand : function() {\n // do nothing\n return "???";\n },\n\n expandChildren : function() {\n\n if (this.children) {\n this.childText = "";\n for (var i = 0; i < this.children.length; i++) {\n this.children[i].expand();\n this.childText += this.children[i].finalText;\n }\n this.finalText = this.childText;\n }\n\n },\n\n createChildrenFromSections : function(sections) {\n var root = this;\n this.children = sections.map(function(section) {\n\n if ( typeof section == 'string' || section instanceof String) {\n // Plaintext\n return new TextNode(root, section);\n } else {\n return new TagNode(root, section);\n }\n });\n }\n});\n\nvar RootNode = ExpansionNode.extend({\n init : function(grammar, rawRule) {\n this._super();\n this.grammar = grammar;\n this.parsedRule = parseRule(rawRule);\n },\n\n expand : function() {\n var root = this;\n this.createChildrenFromSections(this.parsedRule);\n\n // expand the children\n this.expandChildren();\n },\n});\n\nvar TagNode = ExpansionNode.extend({\n init : function(parent, parsedTag) {\n this._super();\n\n if (!(parsedTag !== null && typeof parsedTag === 'object')) {\n if ( typeof parsedTag == 'string' || parsedTag instanceof String) {\n console.warn("Can't make tagNode from unparsed string!");\n parsedTag = parseTag(parsedTag);\n\n } else {\n console.log("Unknown tagNode input: ", parsedTag);\n throw ("Can't make tagNode from strange tag!");\n\n }\n }\n\n this.setParent(parent);\n $.extend(this, parsedTag);\n },\n\n expand : function() {\n if (tracery.outputExpansionTrace)\n console.log(r.sections);\n\n this.rule = this.grammar.getRule(this.symbol);\n\n this.actions = [];\n\n // Parse the rule if it hasn't been already\n this.createChildrenFromSections(this.rule.getParsed());\n\n // Do any pre-expansion actions!\n for (var i = 0; i < this.preActions.length; i++) {\n var action = new Action(this, this.preActions[i]);\n action.activate();\n }\n\n // Map each child section to a node\n if (!this.rule.sections)\n console.log(this.rule);\n\n this.expandChildren();\n\n for (var i = 0; i < this.actions.length; i++) {\n\n this.actions[i].deactivate();\n }\n\n this.finalText = this.childText;\n for (var i = 0; i < this.mods.length; i++) {\n this.finalText = this.grammar.applyMod(this.mods[i], this.finalText);\n }\n\n },\n\n toLabel : function() {\n return this.symbol;\n },\n toString : function() {\n return "TagNode '" + this.symbol + "' mods:" + this.mods + ", preactions:" + this.preActions + ", postactions" + this.postActions;\n }\n});\n\nvar TextNode = ExpansionNode.extend({\n isLeaf : true,\n init : function(parent, text) {\n this._super();\n\n this.setParent(parent);\n\n this.text = text;\n\n this.finalText = text;\n },\n expand : function() {\n // do nothing\n },\n\n toLabel : function() {\n return this.text;\n }\n});\n\n/**\n * @author Kate Compton\n */\n\nfunction Symbol(grammar, key) {\n this.grammar = grammar;\n this.key = key;\n this.currentRules = undefined;\n this.ruleSets = [];\n\n};\n\nSymbol.prototype.loadFrom = function(rules) {\n\n rules = this.wrapRules(rules);\n this.baseRules = rules;\n\n this.ruleSets.push(rules);\n this.currentRules = this.ruleSets[this.ruleSets.length - 1];\n\n};\n\n//========================================================\n// Iterating over rules\n\nSymbol.prototype.mapRules = function(fxn) {\n\n return this.currentRules.mapRules(fxn);\n};\n\nSymbol.prototype.applyToRules = function(fxn) {\n this.currentRules.applyToRules(fxn);\n};\n\n//==================================================\n// Rule pushpops\nSymbol.prototype.wrapRules = function(rules) {\n if (rules.prototype !== RuleSet) {\n if (Array.isArray(rules)) {\n return new RuleSet(rules);\n } else if ( typeof rules == 'string' || rules instanceof String) {\n return new RuleSet(rules);\n } else {\n throw ("Unknown rules type: " + rules);\n }\n }\n // already a ruleset\n return rules;\n};\n\nSymbol.prototype.pushRules = function(rules) {\n rules = this.wrapRules(rules);\n this.ruleSets.push(rules);\n this.currentRules = this.ruleSets[this.ruleSets.length - 1];\n};\n\nSymbol.prototype.popRules = function() {\n var exRules = this.ruleSets.pop();\n\n if (this.ruleSets.length === 0) {\n //console.warn("No more rules for " + this + "!");\n }\n this.currentRules = this.ruleSets[this.ruleSets.length - 1];\n};\n\n// Clear everything and set the rules\nSymbol.prototype.setRules = function(rules) {\n\n rules = this.wrapRules(rules);\n this.ruleSets = [rules];\n this.currentRules = rules;\n\n};\n\nSymbol.prototype.addRule = function(rule) {\n this.currentRules.addRule(seed);\n};\n\n//========================================================\n// selection\n\nSymbol.prototype.select = function() {\n this.isSelected = true;\n\n};\n\nSymbol.prototype.deselect = function() {\n this.isSelected = false;\n};\n\n//==================================================\n// Getters\n\nSymbol.prototype.getRule = function(seed) {\n return this.currentRules.get(seed);\n};\n\n//==================================================\n\nSymbol.prototype.toString = function() {\n return this.key + ": " + this.currentRules + "(overlaying " + (this.ruleSets.length - 1) + ")";\n};\nSymbol.prototype.toJSON = function() {\n\n var rules = this.baseRules.rules.map(function(rule) {\n return '"' + rule.raw + '"';\n });\n return '"' + this.key + '"' + ": [" + rules.join(", ") + "]";\n};\n\nSymbol.prototype.toHTML = function(useSpans) {\n var keySpan = '"' + this.key + '"';\n if (useSpans)\n keySpan = "<span class='symbol symbol_" + this.key + "'>" + keySpan + "</span>";\n\n var rules = this.baseRules.rules.map(function(rule) {\n var s = '"' + rule.raw + '"';\n if (useSpans)\n s = "<span class='rule'>" + s + "</span>";\n return s;\n });\n return keySpan + ": [" + rules.join(", ") + "]";\n};\n\n/**\n * @author Kate Compton\n */\n\nfunction Grammar() {\n this.clear();\n};\n\nGrammar.prototype.clear = function() {\n // Symbol library\n this.symbols = {};\n \n this.errors = [];\n \n // Modifier library\n this.modifiers = {};\n\n // add the universal mods\n for (var mod in universalModifiers) {\n if (universalModifiers.hasOwnProperty(mod))\n this.modifiers[mod] = universalModifiers[mod];\n }\n};\n//========================================================\n// Loading\n\nGrammar.prototype.loadFrom = function(obj) {\n var symbolSrc;\n\n this.clear();\n\n if (obj.symbols !== undefined) {\n symbolSrc = obj.symbols;\n } else {\n symbolSrc = obj;\n }\n\n // get all json keys\n var keys = Object.keys(symbolSrc);\n\n this.symbolNames = [];\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i];\n this.symbolNames.push(key);\n\n this.symbols[key] = new Symbol(this, key);\n this.symbols[key].loadFrom(symbolSrc[key]);\n }\n\n};\n\nGrammar.prototype.toHTML = function(useSpans) {\n // get all json keys\n var keys = Object.keys(this.symbols);\n\n this.symbolNames = [];\n\n var lines = [];\n\n var count = 0;\n for (var i = 0; i < keys.length; i++) {\n\n var key = keys[i];\n var symbol = this.symbols[key];\n\n if (symbol && symbol.baseRules) {\n\n lines.push(" " + this.symbols[key].toHTML(useSpans));\n\n }\n };\n\n var s;\n s = lines.join(",</p><p>");\n s = "{<p>" + s + "</p>}";\n return s;\n};\n\nGrammar.prototype.toJSON = function() {\n // get all json keys\n var keys = Object.keys(this.symbols);\n\n this.symbolNames = [];\n\n var lines = [];\n\n var count = 0;\n for (var i = 0; i < keys.length; i++) {\n\n var key = keys[i];\n var symbol = this.symbols[key];\n\n if (symbol && symbol.baseRules) {\n\n lines.push(" " + this.symbols[key].toJSON());\n\n }\n };\n\n var s;\n s = lines.join(",\sn");\n s = "{\sn" + s + "\sn}";\n return s;\n};\n\n//========================================================\n// selection\n\nGrammar.prototype.select = function() {\n this.isSelected = true;\n};\n\nGrammar.prototype.deselect = function() {\n this.isSelected = false;\n};\n\n//========================================================\n// Iterating over symbols\n\nGrammar.prototype.mapSymbols = function(fxn) {\n var symbols = this.symbols;\n return this.symbolNames.map(function(name) {\n return fxn(symbols[name], name);\n });\n};\n\nGrammar.prototype.applyToSymbols = function(fxn) {\n for (var i = 0; i < this.symbolNames.length; i++) {\n var key = this.symbolNames[i];\n fxn(this.symbols[key], key);\n }\n};\n\n//========================================================\nGrammar.prototype.addOrGetSymbol = function(key) {\n if (this.symbols[key] === undefined)\n this.symbols[key] = new Symbol(key);\n\n return this.symbols[key];\n};\n\nGrammar.prototype.pushRules = function(key, rules) {\n var symbol = this.addOrGetSymbol(key);\n symbol.pushRules(rules);\n};\n\nGrammar.prototype.popRules = function(key, rules) {\n var symbol = this.addOrGetSymbol(key);\n var popped = symbol.popRules();\n\n if (symbol.ruleSets.length === 0) {\n // remove symbol\n this.symbols[key] = undefined;\n }\n};\n\nGrammar.prototype.applyMod = function(modName, text) {\n if (!this.modifiers[modName]) {\n console.log(this.modifiers);\n throw ("Unknown mod: " + modName);\n }\n return this.modifiers[modName](text);\n};\n\n//============================================================\nGrammar.prototype.getRule = function(key, seed) {\n var symbol = this.symbols[key];\n if (symbol === undefined) {\n var r = new Rule("{{" + key + "}}");\n\n r.error = "Missing symbol " + key;\n return r;\n }\n\n var rule = symbol.getRule();\n if (rule === undefined) {\n var r = new Rule("[" + key + "]");\n console.log(r.sections);\n r.error = "Symbol " + key + " has no rule";\n return r;\n }\n\n return rule;\n};\n\n//============================================================\n// Expansions\nGrammar.prototype.expand = function(raw) {\n\n // Start a new tree\n var root = new RootNode(this, raw);\n\n root.expand();\n\n return root;\n};\n\nGrammar.prototype.flatten = function(raw) {\n\n // Start a new tree\n var root = new RootNode(this, raw);\n\n root.expand();\n\n return root.childText;\n};\n\n//===============\n\nGrammar.prototype.analyze = function() {\n this.symbolNames = [];\n for (var name in this.symbols) {\n if (this.symbols.hasOwnProperty(name)) {\n this.symbolNames.push(name);\n }\n }\n\n // parse every rule\n\n for (var i = 0; i < this.symbolNames.length; i++) {\n var key = this.symbolNames[i];\n var symbol = this.symbols[key];\n // parse all\n for (var j = 0; j < symbol.baseRules.length; j++) {\n var rule = symbol.baseRules[j];\n rule.parsed = tracery.parse(rule.raw);\n // console.log(rule);\n\n }\n }\n\n};\n\nGrammar.prototype.selectSymbol = function(key) {\n console.log(this);\n var symbol = this.get(key);\n};\n/**\n * @author Kate Compton\n\n */\n\ntracery.createGrammar = function(obj) {\n var grammar = new Grammar();\n grammar.loadFrom(obj);\n return grammar;\n};\n\ntracery.test = function() {\n\n console.log("==========================================");\n console.log("test tracery");\n\n // good\n tracery.testParse("", false);\n tracery.testParse("fooo", false);\n tracery.testParse("####", false);\n tracery.testParse("#[]#[]##", false);\n tracery.testParse("#someSymbol# and #someOtherSymbol#", false);\n tracery.testParse("#someOtherSymbol.cap.pluralize#", false);\n tracery.testParse("#[#do some things#]symbol.mod[someotherthings[and a function]]#", false);\n tracery.testParse("#[fxn][fxn][fxn[subfxn]]symbol[[fxn]]#", false);\n tracery.testParse("#[fxn][#fxn#][fxn[#subfxn#]]symbol[[fxn]]#", false);\n tracery.testParse("#hero# ate some #color# #animal.s#", false);\n tracery.testParseTag("[action]symbol.mod1.mod2[postAction]", false);\n\n // bad\n tracery.testParse("#someSymbol# and #someOtherSymbol", true);\n tracery.testParse("#[fxn][fxn][fxn[subfxn]]symbol[fxn]]#", true);\n\n // bad\n tracery.testParseTag("stuff[action]symbol.mod1.mod2[postAction]", true);\n tracery.testParseTag("[action]symbol.mod1.mod2[postAction]stuff", true);\n\n tracery.testParse("#hero# ate some #color# #animal.s#", true);\n tracery.testParse("#[#setPronouns#][#setOccupation#][hero:#name#]story#", true);\n\n};\n \n})();
jquery:on\nhash:off\nbookmark:on\nmodernizr:off\nundo:on\nobfuscate:off\nexitprompt:off\nblankcss:off\n
<<silently>>\nUses the parameter if one was passed. Then, checks for the $symbol variable. If neither is present, uses "origin". Clears $symbol at the end.\n\n<<if parameter(0)>>\n\t<<set $symbol to parameter(0)>>\n<<else>><<if $symbol>>\n\tNo need to do anything.\n<<else>>\n\t<<set $symbol to "origin">>\n<<endif>><<endif>>\n\n<<endsilently>><<print console.log("trace " + $symbol)>><<print tale.grammar.flatten("#" + $symbol + "#")>><<forget $symbol>>
// Returns an array of traces, each different from the one preceding it unless retrace() maxes out attempts.\n\nwindow.traceArray = function(symbol, num){\n\tvar output = [];\n\toutput.push( trace(symbol) );\n\n\tfor (var i = 1; i < num; i++) {\n\t\toutput.push( retrace(symbol, output[i-1]) );\n\t};\n\n\treturn output;\n}
<<twineceryInit>>\n<<traceryInit>>
String.prototype.contains = function(substring){\n\tif (substring.constructor === Array){\n\t\tfor (var i = 0; i < substring.length; i++){\n\t\t\tif(this.contains(substring[i])){\n\t\t\t\treturn substring[i]; // Non-empty string evaluates to true\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t} else {\n\t\treturn this.indexOf(substring) > 0;\n\t}\n}
// Returns a new version of a given expansion.\nwindow.retrace = function(symbol, old, maxAttempts){\n\tif(maxAttempts === undefined){\n\t\tmaxAttempts = 32;\n\t}\n\tif(!(maxAttempts > 1)){\n\t\tmaxAttempts = 1;\n\t}\n\t\n\tvar output = "", attempts = 0;\n\tdo{\n\t\toutput = trace(symbol);\n\t\tattempts++;\n\t}while(output == old && attempts < maxAttempts)\n\n//\tconsole.log("retrace:"\n//\t\t\t\t+ "\sn\stold: " + old\n//\t\t\t\t+ "\sn\stnew: " + output\n//\t\t\t\t+ "\sn\stattempts: " + attempts)\n\treturn output;\n}
<<tracelink "origin">>\n
body {\n margin: 2%;\n}\n#passages{\n margin: 0;\n padding: 0;\n border: 0;\n width:96%;\n margin: auto;\n}\n.passage {\n font-size:6em; \n color: #888;\n text-shadow: #888 0 0 0.05em;\n}\n@media screen and (max-width: 960px) {\n .passage {\n font-size: 4em;\n }\n}\n@media screen and (max-width: 640px) {\n .passage {\n font-size: 3em;\n }\n}\na.internalLink, a.externalLink {\n color: #eee;\n text-shadow: #eee 0 0 0.07em;\n}\na.internalLink:hover, a.externalLink:hover {\n color: #fff;\n text-decoration: none;\n text-shadow: #fff 0 0 0.09em;\n}\n#sidebar {\n\tdisplay:none;\n}\nbody\n{\n background-color: #F40009;\n}
window.grammar = function(rule){\n\treturn tale.get(rule).text.split('\sn');\n}
// Expands a symbol and returns the output.\nwindow.trace = function(symbol){\n\tif(symbol === undefined){\n\t\tsymbol = "origin";\n\t}\n\tif(tale.grammar === undefined){\n\t\tconsole.log("Couldn't find the grammar object.");\n\t\treturn "ERROR: Grammar object not found.";\n\t}\n\n\tvar output = tale.grammar.flatten("#" + symbol + "#")\t\n//\tconsole.log(symbol + " expands to:\sn" + output);\n\treturn output;\n}
// This is a slightly modified version of Leon Arnott's cyclinglink macro.\n\nversion.extensions.tracelinkMacro = {\n\tmajor: 0,\n\tminor: 1,\n\trevision: 0\n};\nmacros.tracelink = {\n\thandler: function(a, b, c) {\n\t\tvar rl = "traceLink";\n\n\t\tfunction toggleText(w) {\n\t\t\tw.classList.remove("traceLinkInit");\n\t\t\tw.classList.toggle(rl + "Enabled");\n\t\t\tw.classList.toggle(rl + "Disabled");\n\t\t\tw.style.display = ((w.style.display == "none") ? "inline" : "none")\n\t\t}\n\t\tswitch (c[c.length - 1]) {\n\t\t\tcase "end":\n\t\t\t\tvar end = true;\n\t\t\t\tc.pop();\n\t\t\t\tbreak;\n\t\t\tcase "out":\n\t\t\t\tvar out = true;\n\t\t\t\tc.pop();\n\t\t\t\tbreak\n\t\t}\n\t\tvar v = "";\n\t\tif (c.length && c[0][0] == "$") {\n\t\t\tv = c[0].slice(1);\n\t\t\tc.shift()\n\t\t}\n\t\tvar h = state.history[0].variables;\n\t\tif (out && h[v] === "") {\n\t\t\treturn\n\t\t}\n\t\tvar l = Wikifier.createInternalLink(a, null);\n\t\tl.className = "internalLink cyclingLink";\n\t\tl.setAttribute("data-cycle", 0);\n\n\t\t// Prebake a bunch of traces and use those as our links to cycle through.\n\t\tc = traceArray(c[0], 64);\n\n\t\tfor (var i = 0; i < c.length; i++) {\n\t\t\tvar on = (i == Math.max(c.indexOf(h[v]), 0));\n\t\t\tvar d = insertElement(null, "span", null, "traceLinkInit traceLink" + ((on) ? "En" : "Dis") + "abled");\n\t\t\tif (on) {\n\t\t\t\th[v] = c[i];\n\t\t\t\tl.setAttribute("data-cycle", i)\n\t\t\t} else {\n\t\t\t\td.style.display = "none"\n\t\t\t}\n\t\t\tinsertText(d, c[i]);\n\t\t\tif (on && end && i == c.length - 1) {\n\t\t\t\tl.parentNode.replaceChild(d, l)\n\t\t\t} else {\n\t\t\t\tl.appendChild(d)\n\t\t\t}\n\t\t}\n\t\tl.onclick = function() {\n\t\t\tvar t = this.childNodes;\n\t\t\tvar u = this.getAttribute("data-cycle") - 0;\n\t\t\tvar m = t.length;\n\t\t\ttoggleText(t[u]);\n\t\t\tu = (u + 1);\n\t\t\tif (!(out && u == m)) {\n\t\t\t\tu %= m;\n\t\t\t\tif (v) {\n\t\t\t\t\th[v] = c[u]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\th[v] = ""\n\t\t\t}\n\t\t\tif ((end || out) && u == m - (end ? 1 : 0)) {\n\t\t\t\tif (end) {\n\t\t\t\t\tvar n = this.removeChild(t[u]);\n\t\t\t\t\tn.className = rl + "End";\n\t\t\t\t\tn.style.display = "inline";\n\t\t\t\t\tthis.parentNode.replaceChild(n, this)\n\t\t\t\t} else {\n\t\t\t\t\tthis.parentNode.removeChild(this);\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttoggleText(t[u]);\n\t\t\tthis.setAttribute("data-cycle", u)\n\t\t}\n\t}\n};
Bad Soda Generator
Nora Reed with Tracery/Twine help from Vin Tanner
<<if !tale.grammar>>\n\t<<if tracery>>\n\t\t<<set tale.grammar = tracery.createGrammar(tale.story.data)>>\n\t\t<<print console.log("grammar: ", tale.grammar)>>\n\t<<else>>\n\t\t<<print console.log("grammar instantiation failed")>>\n\t<<endif>>\n<<endif>>