{"pages":{"play":[{"eval":{"script":"game.checkStatus();"}},{"if":{"condition":"game.message","commands":[{"say":{"label":"<p><eval>mergeObject(game.message, game)<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.message = null;"}}],"elseCommands":[{"eval":{"script":"var newHandMessage = game.getNewHandMessage();"}},{"if":{"condition":"newHandMessage","commands":[{"say":{"label":"<p><eval>newHandMessage<\/eval><\/p>","mode":"instant"}}],"elseCommands":[{"eval":{"script":"if (game.isWinToCumRound()) {\r\n  var winToCumTease = mergeObject(randomString(t.cumRoundWinTease), game);\r\n}"}},{"if":{"condition":"winToCumTease","commands":[{"say":{"label":"<p><eval>winToCumTease<\/eval><\/p>","mode":"instant"}}]}}]}}]}},{"eval":{"script":"var roundTime = game.getRoundTime()"}},{"if":{"condition":"roundTime !== false","commands":[{"timer":{"duration":"$roundTime","isAsync":true,"commands":[{"if":{"condition":"!game.cumRoundAuto || !game.isCumRound() || game.isWinToCumRound()","commands":[{"if":{"condition":"game.isWinToCumRound()","commands":[{"say":{"label":"<p><eval>mergeObject(randomString(t.winToCumTimout), game)<\/eval><\/p>","mode":"autoplay"}},{"eval":{"script":"game.lostFinalRound()"}}],"elseCommands":[{"say":{"label":"<p><eval>randomString(t.hitTimeout)<\/eval><\/p>","mode":"autoplay"}},{"eval":{"script":"game.doRoundPenalty()"}}]}}],"elseCommands":[{"eval":{"script":"if (!game.isLastInCumRound()) g.r++\npages.goto(pages.getCurrentPageId());"}}]}}]}}]}},{"say":{"label":"<p><eval>game.getDealerName()<\/eval><eval>blackjack.getFinalTotalLabel(DEALER)<\/eval>: <eval>blackjack.getCards(DEALER)<\/eval><\/p>","mode":"instant"}},{"say":{"label":"<p>You<eval>blackjack.getFinalTotalLabel(PLAYER)<\/eval>: <eval>blackjack.getCards(PLAYER)<\/eval><\/p>","mode":"instant"}},{"if":{"condition":"blackjack.lastMessage !== null && blackjack.lastWinner !== null","commands":[{"eval":{"script":"if (blackjack.lastWinner === DEALER && game.isWinToCumRound()) {\n  if (blackjack.pstand && blackjack.ppoints < game.winToCumThreshold) {\n    if (DEBUG) console.warn(\"Player chose to stand below threshold.\");\n    blackjack.lastMessage = mergeObject(randomString(t.winToCumStandFail), game); \n    \/\/ Subtract time from timer.\n    game.winToCumStart -= (game.winToCumPenalty * 1000)\n  }\n}"}},{"say":{"label":"<p><eval>blackjack.lastMessage<\/eval><\/p>","mode":"autoplay","allowSkip":true}},{"eval":{"script":"if (blackjack.lastWinner === DEALER) {\n  \/\/ Dealer won\n  if (DEBUG) console.warn('Dealer won')\n  roulette.reset();\n  if (!game.isWinToCumRound()) {\n    callPage('penalty-roulette', function(){\n      \/\/ Restart round on return from penalty\n      blackjack.start();\n    });\n  } else {\n    if (game.winToCumIncAlways) {\n      g.r ++;\n    }\n    blackjack.start(); \/\/ Start new round\n    pages.goto('play');\n  }\n} else {\n  if (DEBUG) console.warn('Start new round')\n  blackjack.start(); \/\/ Start new round\n  pages.goto('play');\n}"}},{"if":{"condition":"game.message","commands":[{"say":{"label":"<p><eval>game.message<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.message = null;"}}]}}]}},{"if":{"condition":"game.winnerA===null","commands":[{"choice":{"options":[{"label":"<eval>game.text('btnRndBack')<\/eval>","commands":[{"eval":{"script":"g.r--\npages.goto('play')"}}],"visible":"$((!game.isCumRound() || !game.useCumRoundAuto()) && (DEBUG || game.allowSkip) && g.r > 1) || (game.isCumRound() && !game.isFirstInCumRound())"},{"label":"<eval>game.text('btnHit')<\/eval>","commands":[{"eval":{"script":"blackjack.hit();"}}],"color":"#0d47a1"},{"label":"<eval>game.text('btnStand')<\/eval>","commands":[{"eval":{"script":"blackjack.stand();"}}],"color":"#880e4f"},{"label":"<eval>game.text('btnRndSkip')<\/eval>","commands":[{"eval":{"script":"g.r++\npages.goto('play')"}}],"visible":"$DEBUG || game.allowSkip || (game.isCumAnyTimeCumRound() && !game.isLastInCumRound() && g.r < g.tr)"},{"label":"<eval>game.text('btnLevelSkip')<\/eval>","commands":[{"eval":{"script":"game.nextLevel()\npages.goto('play')"}}],"visible":"$(DEBUG || game.allowSkip) && !game.isCumRound()"}]}},{"eval":{"script":"pages.goto(pages.getCurrentPageId());"}}]}},{"eval":{"script":"pages.goto('play');\n"}}],"start":[{"if":{"condition":"!window._loadStart","commands":[{"notification.create":{"title":"Loading...","id":"loading"}},{"eval":{"script":"window._loadStart = Notification.get('loading')"}}]}},{"if":{"condition":"!window.setTimeout \/* MPEM::setTimeout v1.7 *\/","commands":[{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-1"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-2"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-3"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-4"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-5"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-6"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-7"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-8"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-9"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-10"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-11"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-12"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-13"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-14"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-15"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-16"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-17"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-18"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-19"}},{"audio.play":{"locator":"file:1-minute-of-silence.mp3","volume":0,"background":true,"id":"timer-20"}},{"eval":{"script":"\/\/ Init native timer emulation\r\n\/*\r\nMPED--author::fapnip\r\nMPED--description::\r\nPolyfill to allow use of setTimeout and setInterval in Eos\r\n\r\nSee:\r\nhttps:\/\/milovana.com\/forum\/viewtopic.php?f=2&t=24006&p=301725\r\n::--description\r\n*\/\r\n\/******************************\r\n *  CHANGE LOG\r\n * ****************************\r\n * \r\n * v1.7\r\n *   - Simplify timer functions\r\n * \r\n * v1.6\r\n *   - Allow re-use of sound end event listener\r\n * \r\n * v1.5\r\n *   - More tweaks to deal with interruptions\r\n * \r\n * v1.4\r\n *   - Further adjustments for JS interpreter interruptions\r\n * \r\n * v1.3\r\n *   - Try to reduce errors in offet counters introduced\r\n *      by pauses between JS interpreter steps\r\n * \r\n * v1.1 - v1.2 \r\n *   - Try to improve performance\r\n * \r\n * v1.0\r\n *   - Initial release\r\n * \r\n *\/\r\n(function() {\r\n  \/\/ var debug = false\r\n  var timers = {}\r\n  var sounds = {}\r\n  var counter = 1\r\n  var timerError = 268 \/\/ Always seems to be around 268ms of error (issue with audio files?)\r\n  var maxTime = 60000 \/\/ Sound is 1 min long, so that's the max\r\n  var i = 1\r\n  var timerPool = []\r\n  \r\n  function listener() {\r\n    var id = this.__id\r\n    var timer = timers[id]\r\n    \/\/ this.stop()\r\n    this.__id = null \/\/ disable id\r\n    if (!timer) return\r\n    var opt = timer._opt\r\n    timerPool.unshift(timer) \/\/ Put timer back in queue\r\n    if ((opt.start + (opt.time * opt.iter)) - Date.now() > 20) {\r\n      \/\/ Not done.  We'll need to run again\r\n      doTimer(opt)\r\n      return\r\n    }\r\n    if (opt.interval) {\r\n      \/\/ Run again\r\n      opt.iter++\r\n      doTimer(opt)\r\n    } else {\r\n      delete timers[id]\r\n    }\r\n    try {\r\n      opt.fn()\r\n    } catch (e) {\r\n      console.error('Error in timer fn', e.toString())\r\n    }\r\n  }\r\n\r\n  var tSound = Sound.get('timer-' + i)\r\n  while (tSound) {\r\n    tSound.stop()\r\n    tSound.seek(maxTime-timerError)\r\n    tSound.play()\r\n    tSound.addEventListener('end', listener)\r\n    sounds[i] = tSound\r\n    var timer = {\r\n      sound: tSound,\r\n      index: i\r\n    }\r\n    timerPool.push(timer)\r\n    i++\r\n    tSound = Sound.get('timer-' + i)\r\n  }\r\n  var poolSize = timerPool.length\r\n\r\n  function doTimer(opt) {\r\n    var id = opt.id\r\n    var timer = timerPool.pop()\r\n    if (!timer) {\r\n      throw \"No timer sounds left in timer pool.  Add more if you need more than \" + poolSize + \" concurrent timers.\"\r\n    }\r\n    timer._opt = opt\r\n    var sound = timer.sound\r\n    sound.__id = id\r\n    timers[id] = timer\r\n    sound.seek(Math.max(1, timerError + (maxTime - Math.min(\r\n      (opt.start + (opt.time * opt.iter)) - Date.now(), \r\n      maxTime - 1000\r\n    ))) \/ 1000)\r\n    sound.play()\r\n    return id\r\n  }\r\n\r\n  function clearTimer(id) {\r\n    var timer = timers[id]\r\n    if (timer) {\r\n      delete timers[id]\r\n      var sound = timer.sound\r\n      sound.__id = null\r\n      sound.stop()\r\n      timerPool.unshift(timer)\r\n    }\r\n  }\r\n\r\n  window.setTimeout = function(fn, time) {\r\n    return doTimer({\r\n      id: counter++,\r\n      time: time || 0, \r\n      iter: 1,\r\n      fn: fn, \r\n      start: Date.now()\r\n      })\r\n  }\r\n\r\n  window.clearTimeout = function(id) {\r\n    return clearTimer(id)\r\n  }\r\n\r\n  window.setInterval = function(fn, time) {\r\n    return doTimer({\r\n      id: counter++,\r\n      time: time || 0, \r\n      iter: 1,\r\n      fn: fn, \r\n      interval: true,\r\n      start: Date.now()\r\n      })\r\n  }\r\n  \r\n  window.clearInterval = function(id) {\r\n    return clearTimer(id)\r\n  }\r\n})()\r\n"}}]}},{"if":{"condition":"!window.SimpleBeats \/* MPEM::SimpleBeats v0.8.3 -- MPED::setTimeout *\/","commands":[{"eval":{"script":"\/\/ Install SimpleBeats\r\n\/*\r\nMPED--author::fapnip\r\nMPED--description::\r\nModule to allow creation of simple metronome patterns.\r\n\r\nSee:\r\nhttps:\/\/milovana.com\/forum\/viewtopic.php?f=2&t=24275&p=307281\r\n::--description\r\n*\/\r\n\/*******************\r\n * Changelog\r\n * *****************\r\n * \r\n * 0.8.3\r\n *   Try to avoid sample play on init\r\n * \r\n * 0.8.2\r\n *   Improve performance of beat eval\r\n * \r\n * 0.0.1 - 0.8.1:\r\n *   Too many changes to list.\r\n * \r\n *\/\r\n(function(){\r\n  if (window.SimpleBeats) return\r\n  var Beats = function(opt) {\r\n    EventTarget.call(this)\r\n    opt = opt || {}\r\n    this._volume = opt.volume || 1\r\n    this._volId = 0\r\n    this.patterns = {}\r\n    this.maxVolume = opt.maxVolume || 1\r\n    this.timeScale = 1\r\n    this.slices = 4\r\n    if (opt.timeScale) this.setRunningTimeScale(opt.timeScale)\r\n    if (opt.bpm) this.setBpm(opt.bpm)\r\n    this.beats = {}\r\n    this.volChangeCount = 0\r\n    this.interval = null\r\n    this.eval = window.eval\r\n  }\r\n  Beats.prototype = Object.create(EventTarget.prototype)\r\n  Object.defineProperty(Beats.prototype, 'constructor', {\r\n    value: Beats,\r\n    enumerable: false,\r\n    writable: true })\r\n  window.SimpleBeats = Beats\r\n  var Sample = function(parent, letter, opts) {\r\n    this.lastUsed = 0\r\n    this.volume = parent._volume || 1\r\n    this.event = opts.event || false\r\n    this.immediate = opts.immediate || false\r\n    this.maxVolume = parent.maxVolume || 1\r\n    this.id = letter\r\n    this.parent = parent\r\n    this.prefix = opts.prefix || '' \r\n    var _this = this\r\n    this.load('beat')\r\n    this.playing = false\r\n    if (this.samples.length) {\r\n      this.samples.forEach(function(s){\r\n        s.stop()\r\n        s.setVolume(0.001)\r\n        s.seek(10\/1000)\r\n        s.play()\r\n        s.stop()\r\n        setTimeout(function(){\r\n          s.setVolume(_this.volume)\r\n        }, 0)\r\n      })\r\n      if (parent.beats[letter]) {\r\n        parent.beats[letter].stop()\r\n      }\r\n      parent.beats[letter] = this\r\n    } else {\r\n      this.volume = 0\r\n    }\r\n  }\r\n  Sample.prototype.load = function (type) {\r\n    var samples = []\r\n    for (var i = 1, l = 5; i <= l; i++) {\r\n      var sample = Sound.get(this.prefix + type + this.id + '-' + i)\r\n      if (sample) {\r\n        samples.push(sample)\r\n      } else {\r\n        break\r\n      }\r\n    }\r\n    this.samples = samples\r\n    if (samples.length) {\r\n      this[type] = true\r\n      this.type = type\r\n      return true\r\n    }\r\n    return false    \r\n  }\r\n  Sample.prototype.stop = function () {\r\n    \/\/ nothing to do?\r\n  }\r\n  Sample.prototype.start = function () {\r\n    if (!this.hasSounds()) return false\r\n    this.setVolume(this.volume)\r\n    var next = this.lastUsed + 1\r\n    if (next >= this.samples.length) next = 0\r\n    var nextSound = this.samples[next]\r\n    var lastSound = this.samples[this.lastUsed]\r\n    lastSound.stop()\r\n    lastSound.seek(0)\r\n    nextSound.play()\r\n    this.lastUsed = next\r\n  }\r\n  Sample.prototype.purgeSamples = function () {\r\n    this.samples.forEach(function(s){\r\n      s.stop()\r\n      s.destroy()\r\n    })\r\n  }\r\n  Sample.prototype.hasSounds = function () {\r\n    return !!this.samples.length\r\n  }\r\n  Sample.prototype.setVolume = function (volume) {\r\n    var _this = this\r\n    this.samples.forEach(function(s) {\r\n      var aVol = Math.round((volume * _this.maxVolume) * 10000) \/ 10000\r\n      if (aVol > 1) aVol = 1\r\n      if (aVol < 0) aVol = 0\r\n      if (s.__volume === aVol) return\r\n      s.setVolume(aVol)\r\n      s.__volume = aVol\r\n      _this.parent.volChangeCount ++\r\n    })\r\n    if (this.samples.length) this.volume = volume\r\n  }\r\n\r\n  Beats.prototype.getVolume = function () {\r\n    return this._volume\r\n  }\r\n\r\n  Beats.prototype.setVolume = function (volume, beatId) {\r\n    return this._setVolume(true, volume, beatId)\r\n  }\r\n  Beats.prototype._setVolume = function (cancelFade, volume, beatId) {\r\n    if (beatId === '_') return\r\n    var ov = volume\r\n    volume = parseFloat(volume)\r\n    var _this = this\r\n    if (isNaN(volume)) {\r\n      console.error('Invalid volume: \"' + ov + '\".  Must be a number between 0 and 1')\r\n      return\r\n    }\r\n    if (volume < 0) {\r\n      volume = 0\r\n    }\r\n    if (volume > 1) {\r\n      volume = 1\r\n    }\r\n    if (beatId) {\r\n      var beat = this.beats[beatId]\r\n      if (!beat) {\r\n        console.error('Unable to set volume for invalid beat sample: ' + beatId)\r\n        return\r\n      }\r\n      beat.setVolume(volume)\r\n    } else {\r\n      this._volId ++\r\n      this._volume = volume\r\n      Object.keys(this.beats).forEach(function(bId){\r\n        _this._setVolume(false, volume, bId)\r\n      })\r\n    }\r\n  }\r\n  \r\n  Beats.prototype.pause = function (name) {\r\n    if (name) {\r\n      if (this.__lastPattern === name) {\r\n        this.stopInterval()\r\n        this._run = false\r\n        this._pause = true\r\n      }\r\n      return\r\n    }\r\n    this.stopInterval()\r\n    this._run = false\r\n    this._pause = true\r\n  }\r\n  Beats.prototype.stopAllSounds = function () {\r\n    var _this = this\r\n    Object.keys(this.beats).forEach(function(b2){\r\n      _this.beats[b2].stop()\r\n    })\r\n  }\r\n  Beats.prototype.isPaused = function () {\r\n    return !this._run && this._pause\r\n  }\r\n  Beats.prototype.isStopped = function () {\r\n    return !this._run && !this._pause\r\n  }\r\n  Beats.prototype.isPlaying = function () {\r\n    return this._run && !this._pause\r\n  }\r\n  Beats.prototype.getBpm = function () {\r\n    if (this._loadOnNext) {\r\n      if (this._loadOnNext.bpm) {\r\n        return Math.round(this._loadOnNext.bpm)\r\n      }\r\n      if (this._loadOnNext.timeScale) {\r\n        return Math.round((1 \/ this._loadOnNext.timeScale) * 60)\r\n      }\r\n    }\r\n    return Math.round((1 \/ this.timeScale) * 60)\r\n  }\r\n  Beats.prototype.bpm = function (bpm, pattern) {\r\n    if (bpm === undefined) {\r\n      return this.getBpm()\r\n    }\r\n    pattern = pattern || this.__lastPattern || '+AF'\r\n    var b = this.get(pattern)\r\n    if (b) {\r\n      b({bpm: bpm})\r\n      return\r\n    }\r\n    b = this.set(pattern, {\r\n      pattern: pattern\r\n    })({bpm: bpm})\r\n  }\r\n  Beats.prototype.play = function (name, opts) {\r\n    if (name) {\r\n      var b = this.get(name)\r\n      if (b) {\r\n        b(opts)\r\n      } else {\r\n        console.error('No beat with name:', name)\r\n      }\r\n      return\r\n    }\r\n    this._run = true\r\n    this._pause = false\r\n    \/\/ this.updateInterval()\r\n    var _this = this\r\n    setTimeout(function() {\r\n      _this.onEachInterval()\r\n    }, 0)\r\n  }\r\n  Beats.prototype.stop = function (name) {\r\n    if (name) {\r\n      if (this.__lastPattern === name) {\r\n        this.stopInterval()\r\n        this._run = false\r\n        this._pause = false\r\n        this._resetIter()\r\n      }\r\n      return\r\n    }\r\n    this.stopInterval()\r\n    this._run = false\r\n    this._pause = false\r\n    this._resetIter()\r\n  }\r\n  Beats.prototype.isRunning = function (name) {\r\n    if (name) {\r\n      return this.__lastPattern === name && this._run && this.interval\r\n    }\r\n    return this._run && this.interval\r\n  }\r\n  Beats.prototype.getPattern = function (name) {\r\n    var currentPattern = this.__lastPattern\r\n    if (this._loadOnNext && this._loadOnNext.pattern) {\r\n      currentPattern = this._loadOnNext.pattern\r\n    }\r\n    if (name) {\r\n      return currentPattern === name\r\n    }\r\n    return currentPattern || false\r\n  }\r\n  Beats.prototype.getCurrentPattern = function (name) {\r\n    return this.getPattern(name)\r\n  }\r\n  Beats.prototype.getBeatIndex = function () {\r\n    return this.__beatIndex\r\n  }\r\n  Beats.prototype.getLoopCount = function () {\r\n    return this.__loopCounter\r\n  }\r\n  Beats.prototype.getCurrentTimeScale = function () {\r\n    return this.timeScale\r\n  }\r\n  Beats.prototype.setRunningTimeScale = function (timeScale) {\r\n    if (isNaN(timeScale) || timeScale <= 0) {\r\n      console.error('Invalid timescale:', timeScale)\r\n      return\r\n    }\r\n    this.timeScale = timeScale\r\n  }\r\n  Beats.prototype.setBpm = function (bpm) {\r\n    var bps = (bpm \/ 60)\r\n    var timeScale = 1 \/ bps\r\n    this.setRunningTimeScale(timeScale)\r\n  }\r\n  Beats.prototype.adjustRunningTimeScale = function (timeScaleChange) {\r\n    var t = Math.max(this.timeScale + timeScaleChange, 0.05)\r\n    this.setRunningTimeScale(t)\r\n  }\r\n  Beats.builderOpts = {\r\n    notificationId: Beats.notificationId,\r\n    sustain: {\r\n      '+': {\r\n      },\r\n      \/\/ '-': {\r\n      \/\/ },\r\n      \/\/ '=': {\r\n      \/\/ },\r\n      \/\/ '~': {\r\n      \/\/ },\r\n      \/\/ '<': {\r\n      \/\/ },\r\n      \/\/ '>': {\r\n      \/\/ },\r\n    },\r\n    beats: {\r\n      _: {\r\n        samples: [],\r\n      },\r\n      \/\/ '^': {\r\n      \/\/   samples: [],\r\n      \/\/   event: true,\r\n      \/\/ },\r\n      \/\/ '!': {\r\n      \/\/   samples: [],\r\n      \/\/   immediate: true,\r\n      \/\/ },\r\n    },\r\n    times: {\r\n      D: {\r\n        count: 8,\r\n      },\r\n      F: {\r\n        count: 4,\r\n      },\r\n      Q: {\r\n        count: 1,\r\n      },\r\n      H: {\r\n        count: 2,\r\n      },\r\n    },\r\n    pattern: '+AF',\r\n  }\r\n\r\n  Beats.prototype.setMaxVolume = function (vol, beatId) {\r\n    if (beatId) {\r\n      var beat = this.beats[beatId]\r\n      if (!beat) {\r\n        console.error('Unable to setMaxVolume.  Unknown beatId: ', beatId)\r\n        return\r\n      }\r\n      beat.maxVolume = vol\r\n      this.setVolume(beat.volume, beatId)\r\n      return\r\n    }\r\n    this.maxVolume = vol\r\n    var _this = this\r\n    Object.keys(this.beats).forEach(function(k) {\r\n      _this.setMaxVolume(vol, k)\r\n    })\r\n  }\r\n\r\n  \/**\r\n   * Load samples\r\n   *\/\r\n  Beats.prototype.loadSamples = function (prefix) {\r\n    prefix = prefix || ''\r\n    var _this = this\r\n    Object.keys(Beats.builderOpts.beats).forEach(function(k){\r\n      _this.beats[k] = new Sample(this, k, Beats.builderOpts.beats[k])\r\n    })\r\n    for (var i = 65; i <= 90; i++) {\r\n      var letter = String.fromCharCode(i)\r\n      new Sample(this, letter, {prefix: prefix})\r\n    }\r\n    for (var i = 97; i <= 122; i++) {\r\n      var letter = String.fromCharCode(i)\r\n      new Sample(this, letter, {prefix: prefix})\r\n    }\r\n    \/\/ console.warn('Loaded beats', this.beats)\r\n  }\r\n\r\n  \/\/ remove all loaded audio samples, purge from memory\r\n  Beats.prototype.purgeSamples = function () {\r\n    var _this = this\r\n    this.beats = Object.keys(_this.beats).reduce(function(r, k){\r\n      var beat = _this.beats[k]\r\n      if (beat && !beat.hasSounds()) {\r\n        \/\/ Keep it\r\n        r[k] = beat\r\n      } else if (beat) {\r\n        \/\/ Purge its sounds\r\n        beat.purgeSamples()\r\n      }\r\n      return r\r\n    }, {})\r\n    \/\/ Purge all patterns, since they're bound to the wrong samples\r\n    this.patterns = {}\r\n  }\r\n\r\n  Beats.prototype.stopInterval = function() {\r\n    if (this.interval) {\r\n      clearInterval(this.interval)\r\n      clearTimeout(this._doNextTimer)\r\n      this.interval = null\r\n    }\r\n  }\r\n\r\n  Beats.prototype.updateInterval = function() {\r\n    if (!this._run) return \r\n    var intervalTime = ((1 * this.timeScale) * 1000) \/ this.slices\r\n    if ((intervalTime !== this.intervalTime) || !this.interval) {\r\n      \/\/ Time scale has changed or interval is not running\r\n      this.intervalTime = intervalTime\r\n      clearInterval(this.interval)\r\n      clearTimeout(this._doNextTimer)\r\n      var _this = this\r\n      this.interval = setInterval(function() {\r\n        _this.onEachInterval()\r\n      }, intervalTime)\r\n    }\r\n  }\r\n\r\n  Beats.prototype.onEachInterval = function() {\r\n    this.__lastBeatTime = Date.now()\r\n    if (this._loadOnNext) {\r\n      if(!this._runConfig(this._loadOnNext)) {\r\n        return\r\n      }\r\n    }\r\n    \/\/ var _this = this\r\n    if (!this._run) return\r\n    if (this.__restCounter > 0) {\r\n      this.__restCounter --\r\n      return\r\n    }\r\n    var iterOpts = this.__iterOpts\r\n    var beatIndex = (this.__beatIndex || 0)\r\n    var didLoop = beatIndex >= iterOpts.length\r\n    if (didLoop) {\r\n      beatIndex = 0\r\n      this.__loopCounter++\r\n    }\r\n    this.__beatIndex = beatIndex + 1\r\n    var iterOpt = iterOpts[beatIndex]\r\n    this.__restCounter = (((iterOpt.count \/ (4 \/ this.slices)) - 1) || 0)\r\n    iterOpt.__beats && iterOpt.__beats.forEach(function(b) {\r\n      b.start()\r\n    })\r\n    if (iterOpt.beatFn) {\r\n      try {\r\n        iterOpt.beatFn.call(this)\r\n      } catch (e) {\r\n        console.error('Error in beat eval:\\n' + iterOpt.beatEval +  '\\n', e.toString())\r\n      }\r\n    }\r\n\r\n    if (didLoop) this.dispatchEvent(new Event('loop'))\r\n\r\n    this.updateInterval()\r\n  }\r\n\r\n  Beats.prototype.set = function (name, opts) {\r\n    var _this = this\r\n    if (typeof opts === 'string') {\r\n      opts = {pattern: opts}\r\n    }\r\n    opts = opts || {}\r\n    var mergedOpts\r\n    Object.keys(Beats.builderOpts).forEach(function(k){\r\n      mergedOpts = mergedOpts || {}\r\n      mergedOpts[k] = opts[k] !== undefined ? opts[k] : Beats.builderOpts[k]\r\n    })\r\n    var iterOpts = []\r\n    var patternArray = mergedOpts.pattern.match(\/.[a-zA-Z_\\^!]+(\\[[^\\]]*?\\]){0,1}([DFQH]|[0-9]+\\.*[0-9]*)(<eval>.*?<\\\/eval>|)\/g);\r\n    if (!patternArray) {\r\n      error = \"Invalid beat pattern (1): \" + mergedOpts.pattern\r\n      console.error(error)\r\n      throw error\r\n    }\r\n    var minCount = 4\r\n    patternArray.forEach(function(p) {\r\n      pa = p.match(\/^([+\\-=~><])([a-zA-Z_\\^!]+)(\\[[^\\]]+\\]){0,1}([DFHQ]|[0-9]+\\.*[0-9]*)(<eval>.*?<\\\/eval>|)$\/);\r\n      if (!pa) {\r\n        error = \"Invalid beat pattern (2): \" + p\r\n        console.error(error)\r\n        throw error\r\n      }\r\n      var sustain = mergedOpts.sustain[pa[1]]\r\n      if (!sustain) {\r\n        var error = \"Invalid start code '\"+pa[1]+\"' in '\" + p + \"'\"\r\n        console.error(error)\r\n        throw error\r\n      }\r\n      var beatCodes = pa[2].split('')\r\n      var beats = beatCodes.reduce(function(a, c){\r\n        var b = _this.beats[c]\r\n        if (!b) {\r\n          var error = \"Invalid sample code '\"+c+\"' in '\" + p \r\n          + \"'.  Valid codes: \" \r\n          + Object.keys(_this.beats).join(',')\r\n          console.error(error, mergedOpts)\r\n          throw error\r\n        }\r\n        a.push(b)\r\n        return a\r\n      }, [])\r\n      var time = mergedOpts.times[pa[4]]\r\n      if (!time) {\r\n        var paScale = parseFloat(pa[4])\r\n        if (isNaN(paScale)) {\r\n          var error = \"Invalid time code '\"+pa[4]+\"' in '\" + p + \"'. Valid codes: \" \r\n          + + \"'.  Valid codes: \" \r\n          + Object.keys(mergedOpts.times).join(',')\r\n          console.error(error)\r\n          throw error\r\n        }\r\n        time = {\r\n          scale: paScale,\r\n          count: 4,\r\n        }\r\n      }\r\n      var beatEval = pa[5]\r\n      var beatFn = null\r\n      beatEval = beatEval\r\n      if (beatEval) {\r\n        beatEval = beatEval.match(\/^<eval>(.*)<\\\/eval>$\/)\r\n        if (beatEval) {\r\n          beatEval = beatEval && beatEval[1]\r\n          if (beatEval && beatEval.trim()) {\r\n            try {\r\n              beatFn = Function(beatEval)\r\n            } catch (e) {\r\n              console.error('Invalid beat eval in: \\n' + beatEval + '\\n'  + e)\r\n            }\r\n          }\r\n        }\r\n      }\r\n      if (time.count < minCount) {\r\n        minCount = time.count\r\n      }\r\n      iterOpts.push({\r\n        iterations: null, \r\n        count: time.count,\r\n        scale: time.scale,\r\n        beatEval: beatEval,\r\n        beatFn: beatFn,\r\n        __sustainCode: pa[1],\r\n        __beatCodes: beatCodes,\r\n        __beatId: pa[3] && pa[3].replace(\/^\\[+|\\]+$\/g, '').trim(),\r\n        __timeCode: pa[4],\r\n        __beats: beats,\r\n      })\r\n    })\r\n    if (minCount < 1) {\r\n      minCount = 1\r\n    }\r\n    var slices = 4 \/ minCount\r\n    function builder(options) {\r\n      if (typeof options === 'number') {\r\n        options = {\r\n          timeScale: options\r\n        }\r\n      }\r\n      options = options || {}\r\n\r\n      var config = {\r\n        iterOpts: iterOpts,\r\n        timeScale: options.timeScale,\r\n        bpm: options.bpm,\r\n        pattern: mergedOpts.pattern,\r\n        slices: slices,\r\n      }\r\n      if (_this._run && _this.interval) {\r\n        \/\/ Currently running\r\n        \/\/ Queue us up for next beat\r\n        _this._loadOnNext = config\r\n        \/\/ Set some stuff now\r\n        if (config.timeScale) {\r\n          _this.setRunningTimeScale(config.timeScale)\r\n        }\r\n        if (config.bpm) {\r\n          _this.setBpm(config.bpm)\r\n        }\r\n        if (config.slices) {\r\n          _this.slices = config.slices\r\n        }\r\n        var newIntervalTime = ((1 * _this.timeScale) * 1000) \/ _this.slices\r\n        var sinceLast = Date.now() - _this.__lastBeatTime\r\n        if (_this.intervalTime !== newIntervalTime && _this.intervalTime - sinceLast > newIntervalTime) {\r\n          _this.stopInterval()\r\n          var doNextIn = newIntervalTime - sinceLast\r\n          if (doNextIn < 0) {\r\n            doNextIn = 0\r\n          }\r\n          \/\/ _this.interval = true \/\/ pretend we're still running\r\n          _this._doNextTimer = setTimeout(function() {\r\n            _this.onEachInterval()\r\n          }, doNextIn)\r\n        }\r\n      } else {\r\n        \/\/ Not running\r\n        \/\/ Run now\r\n        _this._run = true\r\n        _this._pause = false\r\n        _this._runConfig(config)\r\n      }\r\n    }\r\n    builder.pattern = mergedOpts.pattern\r\n    this.patterns[name] = builder\r\n    return builder\r\n  }\r\n\r\n  Beats.prototype._resetIter = function() {\r\n    this.__beatIndex = 0\r\n    this.__loopCounter = 0\r\n    this.__beatIndex2 = 1\r\n    this.__restCounter = 0\r\n  }\r\n\r\n  Beats.prototype._runConfig = function(config, skipCall) {\r\n    this._loadOnNext = null\r\n    \/\/ console.warn('Running SimpleBeats config:', config)\r\n    if (config.timeScale) {\r\n      this.setRunningTimeScale(config.timeScale)\r\n    }\r\n    if (config.bpm) {\r\n      this.setBpm(config.bpm)\r\n    }\r\n    if (config.slices) {\r\n      this.slices = config.slices\r\n    }\r\n    var newIntervalTime = ((1 * this.timeScale) * 1000) \/ this.slices\r\n    if (this._run && this.interval){\r\n      if (this.intervalTime === newIntervalTime\r\n      && this.__lastPattern === config.pattern) {\r\n        \/\/ We're already running this.\r\n        \/\/ console.log('Already running pattern', config.pattern)\r\n        return true\r\n      }\r\n    }\r\n    if (this.__lastPattern !== config.pattern) {\r\n      this._resetIter()\r\n      this.__iterOpts = config.iterOpts\r\n      this.__lastConfig = config\r\n      this.__lastPattern = config.pattern\r\n    }\r\n    \/\/ var osbt = this.__offsetBeatTimers\r\n    \/\/ if (osbt && Object.keys(osbt).length) {\r\n    \/\/   Object.keys(osbt).forEach(function(t) {\r\n    \/\/     clearTimeout(osbt[t])\r\n    \/\/   })\r\n    \/\/   this.__offsetBeatTimers = {}\r\n    \/\/ }\r\n    if (!this._run) {\r\n      \/\/ console.log('Run disable.  Unable to start pattern.', config.pattern)\r\n      return false\r\n    }\r\n    \/\/ this.updateInterval()\r\n    if (!this.interval && !skipCall) {\r\n      var _this = this\r\n      setTimeout(function() {\r\n        _this.onEachInterval()\r\n      }, 0)\r\n    }\r\n    return true\r\n  }\r\n\r\n  Beats.prototype.get = function(name) {\r\n    return this.patterns[name]\r\n  }\r\n})()"}}]}},{"eval":{"script":"loadImagePage('welcome-image')"}},{"eval":{"script":"\/\/ See: \"welcome\" page for what you're looking for\r\nif(game.init()) {\r\n  window._loadStart && window._loadStart.remove()\r\n  pages.goto('welcome')\r\n}"}},{"if":{"condition":"false","commands":[{"eval":{"script":"\/\/ Preload start image using unreachable goto"}},{"goto":{"target":"welcome-image"}}]}}],"instructions":[{"notification.create":{"buttonCommands":[{"goto":{"target":"welcome"}}],"buttonLabel":"Done","id":"instruct-back"}},{"say":{"label":"<p><em><strong>FapJack<\/strong><\/em> is  variation of <em><strong>Blackjack<\/strong><\/em> -- a simple card game where the goal is to get as close as you can to 21 by totaling the values of the cards you&#x27;ve been dealt, without going over.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>Face cards (<strong>J<\/strong>, <strong>Q<\/strong> and <strong>K<\/strong>) are worth <strong>10<\/strong>.  Aces (<strong>A<\/strong>) are worth <strong>1<\/strong> or <strong>11<\/strong>.  All others are their given value.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>All dealt cards are visible to all players, except the dealer&#x27;s first card.  That card only becomes visible at the end of a hand.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>If you&#x27;re dealt 21 exactly at the start of a hand, it&#x27;s called &quot;blackjack&quot;.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>A &quot;blackjack&quot; in FapJack earns you one &quot;rest&quot; point -- something you can use when you&#x27;re about to cum and need a break.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>You start with <eval>game.defaultRests<\/eval> <u><strong>Rests<\/strong><\/u>.  Use them wisely.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>You can <u><strong>Hit<\/strong><\/u> to be dealt another card, or <u><strong>Stand<\/strong><\/u> to continue with the cards you have.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>If you <u><strong>Hit<\/strong><\/u> and go over 21, you lose with a <u><strong>Bust<\/strong><\/u> and the dealer wins.  If you <u><strong>Stand<\/strong><\/u> and the dealer gets closer to 21 than you without a bust, the dealer wins.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>If you lose a hand, you will be required to pay a penalty.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>If you win a round, your dealer will reveal more of herself, until it&#x27;s time to move on to another dealer.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>If you cum, the game is over!<\/p>","mode":"instant"}},{"notification.remove":{"id":"instruct-back"}},{"choice":{"options":[{"label":"Thanks, got it!","commands":[{"goto":{"target":"welcome"}}]},{"label":"Wow, that was dry.","commands":[{"eval":{"script":"game.dryTease = true"}},{"goto":{"target":"instructions-dry"}}],"visible":"$pages.contains('instructions-dry')"},{"label":"Say again?","commands":[{"goto":{"target":"instructions"}}]}]}}],"notification-round":[{"if":{"condition":"!n.round","commands":[{"notification.create":{"id":"round"}},{"eval":{"script":"n.round = true;\ncloseAllBut(['round','roundCum','roundRest']);"}}]}},{"if":{"condition":"!n.roundCum && (g.c < 1 || game.isWinToCumRound()) && !game.isCumAnyTimeCumRound()","commands":[{"notification.create":{"id":"roundCum","buttonCommands":[{"eval":{"script":"n.roundCum = false;\ngame.lostCheck()"}}],"buttonLabel":"Cumming"}},{"eval":{"script":"n.roundCum = true;\ncloseAllBut(['round','roundCum']);"}}]}},{"if":{"condition":"!n.roundRest && (g.c > 0 && !game.isWinToCumRound()) && !game.isCumAnyTimeCumRound()","commands":[{"notification.create":{"id":"roundRest","buttonCommands":[{"eval":{"script":"g.c--;\nn.roundRest=false;\nrest.start();"}}],"buttonLabel":"Rest \/ Cumming"}},{"eval":{"script":"n.roundRest = true;\ncloseAllBut(['round','roundRest']);"}}]}},{"if":{"condition":"!n.roundRest && g.c > 0 && game.isCumAnyTimeCumRound() && !game.isWinToCumRound()","commands":[{"notification.create":{"id":"roundRest","buttonCommands":[{"eval":{"script":"g.c--;\nn.roundRest=false;\nrest.start();"}}],"buttonLabel":"Rest"}},{"eval":{"script":"n.roundRest = true;\nn.roundRestCum = true;\ncloseAllBut(['round','roundRest','roundCumNow']);"}}]}},{"if":{"condition":"!n.roundCumNow && game.isCumAnyTimeCumRound() && !game.isWinToCumRound()","commands":[{"notification.create":{"id":"roundCumNow","buttonCommands":[{"eval":{"script":"game.cumRoundPause()"}}],"buttonLabel":"\u2736 CUM NOW \u2736"}},{"eval":{"script":"n.roundCumNow = true;\ncloseAllBut(['round','roundRest', 'roundCumNow']);"}}],"elseCommands":[{"eval":{"script":"closeAllBut(['round','roundRest', 'roundCum']);"}}]}},{"eval":{"script":"blackjack.updatePlayLabels();\nreturnToCaller(); \/\/ Return to caller"}}],"penalty-roulette":[{"if":{"condition":"!n.penaltyroulette1","commands":[{"notification.create":{"id":"penaltyroulette1","title":"\u2665\u2665  FAP Roulette  \u2665\u2665"}},{"eval":{"script":"n.penaltyroulette1 = true;\ncloseAllBut(['penaltyroulette1','penaltyroulette2']);\nbeats.stopAll();"}}]}},{"if":{"condition":"!n.penaltyroulette2","commands":[{"notification.create":{"id":"penaltyroulette2"}},{"eval":{"script":"n.penaltyroulette2 = true;\ncloseAllBut(['penaltyroulette1','penaltyroulette2']);\nbeats.stopAll();"}}]}},{"if":{"condition":"roulette.prompt","commands":[{"say":{"label":"<p><eval>roulette.prompt<\/eval><\/p>","mode":"instant"}}]}},{"eval":{"script":"(function(){\n  var roulettePage = pages.getCurrentPageId()\n  function cancelRoullete() {\n    closeNotifications(['penaltyroulette1', 'penaltyroulette2'])\n  }\n  var doRoulette = function() {\n    if (roulettePage !== pages.getCurrentPageId()) return cancelRoullete()\n    var time = roulette.timer\n    var penalty = roulette.getRandom()\n    var cont = roulette.len\n    roulette.click()\n    if (cont) {\n      roulette.inc()\n      setTimeout(doRoulette, time)\n    } else {\n      setTimeout(function(){\n          if (roulettePage !== pages.getCurrentPageId()) return cancelRoullete()\n          roulette.run(penalty)\n        }, roulette.endTime())\n    }\n  }\n  doRoulette()\n})()\n"}}],"penalty-edge":[{"eval":{"script":"roulette.beforeStep('edge')"}},{"timer":{"duration":"6h45m","style":"secret","isAsync":true}},{"notification.create":{"buttonCommands":[{"eval":{"script":"if (typeof opt.onEdge === 'function') {\r\n  opt.onEdge(opt)\r\n}"}},{"eval":{"script":"if (!opt.ride) {\n  if (opt.noRest) {\n    returnToCaller();\n  } else {\n    rest.startNoPush(opt.getRestCount(opt));\n  }\n} else {\n  pages.goto(pages.getCurrentPageId() + '-ride');\n}"}}],"buttonLabel":"\u2736 On the EDGE! \u2736","id":"edgePentaltyButton"}},{"eval":{"script":"closeAll();\nvar opt = roulette.opt;\nopt.beforeStart && opt.beforeStart()\nopt.startBeat(opt);\nif (opt.bpm < beats.maxBpm()) {\n  opt.bpm = beats.nextBpm(opt.bpm);\n}\nvar incTimer = opt.getAndIncTimer(opt);"}},{"if":{"condition":"opt.bpm < 300","commands":[]}},{"timer":{"duration":"$incTimer","style":"hidden","isAsync":true,"commands":[{"eval":{"script":"pages.goto(pages.getCurrentPageId());"}}]}},{"say":{"label":"<p><eval>opt.getEdgeMessage(opt)<\/eval><\/p>","mode":"instant"}}],"rest":[{"eval":{"script":"if (rest.fromPenalty) roulette.beforeStep('rest')"}},{"eval":{"script":"beats.stopAll();"}},{"if":{"condition":"!n.cumRest","commands":[{"notification.create":{"buttonCommands":[{"eval":{"script":"closeAllBut();\ngame.cummingNow()"}}],"buttonLabel":"I'm Cumming","id":"cumRest"}},{"eval":{"script":"n.cumRest = true;"}}]}},{"if":{"condition":"!n.endRest","commands":[{"notification.create":{"buttonCommands":[{"eval":{"script":"pages.goto('rest-end');"}}],"buttonLabel":"Done resting.","id":"endRest"}},{"eval":{"script":"n.endRest = true;"}}]}},{"timer":{"duration":"$rest.breatheTotal()","isAsync":true,"commands":[{"eval":{"script":"rest.next();"}}]}},{"if":{"condition":"rest.isFirst()","commands":[{"say":{"label":"<p><eval>rest.startMessage()<\/eval><\/p>","mode":"instant"}}]}},{"say":{"label":"<p><eval>rest.breatheInMessage()<\/eval><\/p>","mode":"instant"}},{"timer":{"duration":"$rest.breatheIn()","style":"hidden","isAsync":true,"commands":[{"say":{"label":"<p><eval>rest.breatheOutMessage()<\/eval><\/p>","mode":"instant"}}]}}],"play-start":[{"eval":{"script":"if (gds && gds.length && !g.df) {\r\n  callPage('game-difficulty-select');\r\n} else if (!g.gm) {\r\n  callPage('game-mode-select');\r\n} else {\r\n  var message = mergeObject(randomString(t.playStart), game);\r\n}"}},{"if":{"condition":"message","commands":[{"say":{"label":"<p><eval>message<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"eval":{"script":"pages.goto('play');"}}],"penalty-edge-ride":[{"eval":{"script":"roulette.beforeStep('edge-ride')"}},{"eval":{"script":"if (needsRoundNotifications()) callPage('notification-round');"}},{"eval":{"script":"var opt = roulette.opt;\nbeats.stopAll();\nvar rideTime = opt.getRideTime(opt);"}},{"timer":{"duration":"$rideTime","isAsync":true,"commands":[{"eval":{"script":"rest.startNoPush(opt.getRestCount(opt))"}}]}},{"say":{"label":"<p><eval>opt.getRideMessage(opt)<\/eval><\/p>","mode":"instant"}},{"if":{"condition":"opt.doContMessage(opt)","commands":[{"timer":{"duration":"$Math.round(rideTime \/ 2)","style":"hidden"}},{"say":{"label":"<p><eval>opt.getRideContMessage(opt)<\/eval><\/p>","mode":"instant"}}]}}],"game-lost":[{"eval":{"script":"closeAll();\nbeats.stopAll();\nif (!loadGameOverImage()) {\n  var message1 = game.text('gameOver1');\n  var message2 = game.text('gameOver2');\n}\n"}},{"if":{"condition":"message1","commands":[{"say":{"label":"<p><eval>message1<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"message2","commands":[{"say":{"label":"<p><eval>message2<\/eval><\/p>","mode":"pause"}}]}},{"goto":{"target":"common-ending"}}],"game-lost-check":[{"eval":{"script":"closeAll()"}},{"eval":{"script":"\/\/ Work-around for EOS bypassing say\/choice prompts on notification timer end \r\n\/\/ We'll set a timer that ends just before the notification timer, and clears it.\r\nvar clearLostCheckTimer = setTimeout(function() {\r\n  closeNotifications('lostcheck')\r\n},\r\n\/\/ Set timeout for 1\/4 second short cancel notification, or whatever lostCheckTimeIssueOffset is set to  \r\n(game.lostCheckTime * 1000) - game.lostCheckTimeIssueOffset\r\n)"}},{"notification.create":{"title":"Oops!","buttonCommands":[{"eval":{"script":"clearTimeout(clearLostCheckTimer)\r\ngame.cancelCumming()"}}],"buttonLabel":"Not Cumming!","timerCommands":[],"timerDuration":"$game.lostCheckTime * 1000","id":"lostcheck"}},{"eval":{"script":"game.cameEarly()"}}],"rest-end":[{"eval":{"script":"closeAllBut();\nrest.end();"}}],"penalty-stroke":[{"eval":{"script":"roulette.beforeStep('stroke')"}},{"eval":{"script":"if (needsRoundNotifications()) callPage('notification-round');"}},{"eval":{"script":"var opt = roulette.opt\r\nopt.beforeStart && opt.beforeStart()\r\nvar prepMessage = opt.getPrepMessage && opt.getPrepMessage(opt);\r\n\/\/ var doneMessage = opt.getDoneMessage && opt.getDoneMessage(opt)"}},{"if":{"condition":"prepMessage","commands":[{"say":{"label":"<p><eval>prepMessage<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"say":{"label":"<p><eval>opt.getMessage(opt)<\/eval><\/p>","mode":"instant"}},{"if":{"condition":"opt.messageDelay(opt)","commands":[{"timer":{"duration":"$opt.messageDelay(opt)","style":"hidden"}}]}},{"eval":{"script":"if (!opt.noBeat) beats.start(opt.bpm);"}},{"timer":{"duration":"$opt.getTime(opt)-100","isAsync":true,"commands":[{"eval":{"script":"beats.stopAll();\nvar doneMessage = opt.getDoneMessage(opt);"}},{"if":{"condition":"doneMessage","commands":[{"say":{"label":"<p><eval>doneMessage<\/eval><\/p>","mode":"autoplay","allowSkip":true}}],"elseCommands":[{"if":{"condition":"opt.messageDelay(opt)","commands":[{"timer":{"duration":"$opt.messageDelay(opt)","style":"hidden"}}]}}]}},{"eval":{"script":"game.message = randomString(t.backToGame);\nreturnToCaller();"}}]}},{"if":{"condition":"opt.allowSkip","commands":[{"eval":{"script":"\/*--auto-magpie-merge:choice:options1 *\/"}},{"choice":{"options":[{"label":"<eval>game.text('btnStrokeDone')<\/eval>","commands":[{"eval":{"script":"beats.stopAll();\nvar doneMessage = opt.getDoneMessage(opt);"}},{"if":{"condition":"doneMessage","commands":[{"say":{"label":"<p><eval>doneMessage<\/eval><\/p>","mode":"autoplay","allowSkip":true}}],"elseCommands":[{"if":{"condition":"opt.messageDelay(opt)","commands":[{"timer":{"duration":"$opt.messageDelay(opt)","style":"hidden"}}]}}]}},{"eval":{"script":"game.message = randomString(t.backToGame);\nreturnToCaller();"}}]}]}}]}}],"instructions-dry":[{"if":{"condition":"game.dryTease","commands":[{"eval":{"script":"game.dryTease = false"}},{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990443"}},{"timer":{"duration":"2s","style":"hidden"}},{"image":{"locator":"gallery:a6068f8e-6608-437f-aefb-a94f5ee782e9\/990458"}},{"say":{"label":"<p>Better?<\/p>","mode":"instant"}}],"elseCommands":[{"say":{"label":"<p>Ready?<\/p>"}}]}},{"choice":{"options":[{"label":"Yes, let's play!","commands":[{"goto":{"target":"play-start"}}]},{"label":"No, I want more!","commands":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990428"}},{"say":{"label":"<p><eval>randomString(t.dryTease)<\/eval><\/p>","mode":"autoplay","allowSkip":true}},{"image":{"locator":"gallery:a6068f8e-6608-437f-aefb-a94f5ee782e9\/990458"}},{"goto":{"target":"instructions-dry"}}]},{"label":"Back to the instructions","commands":[{"goto":{"target":"instructions"}}]},{"label":"Settings","commands":[{"eval":{"script":"callPage('settings')"}}]}]}}],"win":[{"eval":{"script":"if(!game.didStartWinCheck) {\r\n  game.doStartWin()\r\n}"}},{"eval":{"script":"loadWinnerImage()"}},{"eval":{"script":"game.clearState()"}},{"if":{"condition":"message1","commands":[{"say":{"label":"<p><eval>message1<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"message2","commands":[{"say":{"label":"<p><eval>message2<\/eval><\/p>","mode":"pause"}}]}},{"eval":{"script":"game.wonLastGame = true"}},{"goto":{"target":"common-ending"}}],"cum-round":[{"eval":{"script":"closeAllBut();\r\nif (!loadCumRoundImage()) {\r\n  var message1 = game.text(!game.winToCum ? 'cumRound1' : 'cumRoundMustWin1');\r\n  var message2 = game.text(!game.winToCum ? 'cumRound2' : 'cumRoundMustWin2');\r\n  var message3 = game.text(!game.winToCum ? 'cumRound3' : 'cumRoundMustWin3');\r\n}\r\n"}},{"if":{"condition":"message1","commands":[{"say":{"label":"<p><eval>message1<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"message2","commands":[{"say":{"label":"<p><eval>message2<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"message3","commands":[{"say":{"label":"<p><eval>message3<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"game.winToCum","commands":[{"eval":{"script":"\/\/ Get player to edge before entering game\r\nvar p = game.getPenalty('edge'); \/\/ Get the edge penalty object\r\nvar opt = p.optGen(); \/\/ Generate an opt for it\r\nroulette.use = p; \/\/ Tell roulette that it's already selected an edge penalty\r\nroulette.opt = opt; \/\/ Set our edge opt\r\nopt.noRest = true; \/\/ Tell edge penalty not to use rest page after edge\r\n\/\/ Call edge penalty page\r\ncallPage(\r\n  p.page, \/\/ The page from the edge penalty \r\n  \/\/ Tell page call stack to execute this just before returning from penalty page\r\n  function() {\r\n    closeAllBut(); \/\/ Close all open notifications\r\n    game.message = randomString(t.edgeRide); \/\/ Set our initial edge-ride message\r\n    game.winToCumStart = Date.now(); \/\/ Set the start time for winToEdge timer calc.\r\n  }, \r\n  \/\/ Tell page call stack to return to 'play', not the current page.\r\n  'play' \r\n);"}}],"elseCommands":[{"eval":{"script":"closeAllBut();\r\npages.goto('play');"}}]}}],"play-shuffle-notice":[{"eval":{"script":"beats.start(60);\nconsole.log('Shuffle-notice');"}},{"if":{"condition":"!n.shuffle","commands":[{"notification.create":{"title":"SHUFFLING DECK","id":"shuffle"}},{"eval":{"script":"n.shuffle = true"}}]}},{"timer":{"duration":"$game.getShuffleTimer()","style":"hidden"}},{"eval":{"script":"beats.stop(60);"}},{"goto":{"target":"play-shuffle-notice"}}],"settings-beat-volume":[{"eval":{"script":"beats.start(120);"}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"\u21d1 Up","commands":[{"eval":{"script":"game.volumeUp();\npages.goto(pages.getCurrentPageId());"}}]},{"label":"\u21d3 Down","commands":[{"eval":{"script":"game.volumeDown();\npages.goto(pages.getCurrentPageId());"}}]},{"label":"Max","commands":[{"eval":{"script":"game.volumeUp(1);\npages.goto(pages.getCurrentPageId());"}}]},{"label":"Min","commands":[{"eval":{"script":"game.volumeDown(1);\npages.goto(pages.getCurrentPageId());"}}]},{"label":"Reset","commands":[{"eval":{"script":"game.volumeReset();\npages.goto(pages.getCurrentPageId());"}}],"visible":"$game.volume !== settingDefaults.volume"},{"label":"Done","commands":[{"eval":{"script":"beats.stopAll();\nbeats.init();\nbeats.volume();\nsaveSettings();\nreturnToCaller();"}}]}]}}],"melody-image-1-1":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990432"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-2":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990437"}},{"eval":{"script":"\/\/ Per hand config override example\r\ngame.setHandConfigOverride({\r\n  dealerName: 'Not Melody'\r\n});"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-3":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990468"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-4":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990461"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-5":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990410"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-6":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990457"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-7":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990411"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-8":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990444"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-9":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990454"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-10":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990438"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-11":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990433"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-12":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990430"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-13":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990451"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-14":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990452"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-1-15":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990443"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-1":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991228"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-2":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991251"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-3":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991235"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-4":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991261"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-5":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991260"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-6":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991265"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-7":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991266"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-8":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991276"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-9":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991274"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-10":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991272"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-11":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991284"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-12":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991295"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-13":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991301"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-14":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991302"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-2-15":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991318"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-1":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990490"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-2":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990511"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-3":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990506"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-4":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/991428"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-5":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990507"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-6":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990504"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-7":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990515"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-8":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990488"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-9":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990498"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-10":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990519"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-11":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990487"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-12":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990517"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-13":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990492"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-14":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/991427"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-3-15":[{"if":{"condition":"game.cumRoundAlt","commands":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005399"}}],"elseCommands":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/991426"}}]}},{"eval":{"script":"returnToCaller();"}}],"penalty-message":[{"eval":{"script":"roulette.beforeStep('message')"}},{"eval":{"script":"var opt = roulette.opt\nopt.beforeStart && opt.beforeStart()\nvar messageDelay = opt.messageDelay(opt)\nvar message = opt.getMessage(opt);"}},{"if":{"condition":"message","commands":[{"if":{"condition":"messageDelay","commands":[{"say":{"label":"<p><eval>message<\/eval><\/p>","mode":"instant"}},{"if":{"condition":"opt.showTimer","commands":[{"timer":{"duration":"$messageDelay","style":"normal"}}],"elseCommands":[{"timer":{"duration":"$messageDelay","style":"hidden"}}]}}],"elseCommands":[{"say":{"label":"<p><eval>message<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}}]}},{"eval":{"script":"var endMessage = roulette.finish(opt);\n"}},{"if":{"condition":"endMessage","commands":[{"say":{"label":"<p><eval>endMessage<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"eval":{"script":"returnToCaller();"}}],"penalty-message-pass-fail":[{"noop":{"eval":{"script":"if (needsRoundNotifications()) callPage('notification-round');"}}},{"eval":{"script":"roulette.beforeStep('message-pass-fail')"}},{"eval":{"script":"var opt = roulette.opt\nopt.beforeStart && opt.beforeStart()\nvar messageDelay = opt.messageDelay && opt.messageDelay(opt)\nvar message = opt.getMessage && opt.getMessage(opt);\nvar message2 = opt.getMessage2 && opt.getMessage2(opt);"}},{"if":{"condition":"opt.pauseAfterMessage","commands":[{"say":{"label":"<p><eval>message<\/eval><\/p>","mode":"autoplay","allowSkip":true}}],"elseCommands":[{"say":{"label":"<p><eval>message<\/eval><\/p>","mode":"instant"}}]}},{"if":{"condition":"messageDelay","commands":[{"if":{"condition":"opt.showTimer","commands":[{"timer":{"duration":"$messageDelay","style":"normal","isAsync":true,"commands":[{"eval":{"script":"opt.timeout = true;\n(opt.doTimeout && opt.doTimeout(opt)) || (!opt.finished && pages.goto('penalty-message-fail'))"}}]}}],"elseCommands":[{"timer":{"duration":"$messageDelay","style":"hidden","isAsync":true,"commands":[{"eval":{"script":"opt.timeout = true;\n(opt.doTimeout && opt.doTimeout(opt)) || (!opt.finished && pages.goto('penalty-message-fail'))"}}]}}]}}]}},{"if":{"condition":"message2","commands":[{"say":{"label":"<p><eval>message2<\/eval><\/p>","mode":"instant"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"Done!","commands":[{"eval":{"script":"pages.goto('penalty-message-pass');\n"}}],"visible":"$opt.showAltPassButton"},{"label":"I did it!","commands":[{"eval":{"script":"pages.goto('penalty-message-pass');\n"}}],"visible":"$!opt.hidePassButton"},{"label":"I can't do it.","commands":[{"eval":{"script":"pages.goto('penalty-message-fail');"}}],"visible":"$!opt.hideFailButton"}]}}],"penalty-message-pass":[{"eval":{"script":"roulette.beforeStep('message-pass')"}},{"eval":{"script":"if (needsRoundNotifications()) callPage('notification-round');"}},{"eval":{"script":"closeAllBut();\nvar message = roulette.finish(opt);\nvar pauseAfterPassMessage = opt.getAfterPassMessage && opt.getAfterPassMessage();"}},{"if":{"condition":"message","commands":[{"say":{"label":"<p><eval>message<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"pauseAfterPassMessage","commands":[{"say":{"label":"<p><eval>pauseAfterPassMessage<\/eval><\/p>","mode":"instant"}},{"choice":{"options":[{"label":"Okay, I'm ready!","commands":[]},{"label":"Sorry, I can't continue.","commands":[{"goto":{"target":"game-lost"}}]}]}}]}},{"eval":{"script":"returnToCaller();"}}],"penalty-message-fail":[{"eval":{"script":"roulette.beforeStep('message-fail')"}},{"eval":{"script":"if (needsRoundNotifications()) callPage('notification-round');"}},{"eval":{"script":"closeAllBut();\nvar opt = roulette.opt\nvar message =  opt.getFailMessage && opt.getFailMessage(opt);"}},{"if":{"condition":"message","commands":[{"say":{"label":"<p><eval>message<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"eval":{"script":"opt.fail(opt);"}}],"cum-round-pause":[{"eval":{"script":"closeAllBut();\nbeats.start(300);"}},{"timer":{"duration":"5m","style":"hidden","isAsync":true,"commands":[{"eval":{"script":"returnToCaller()"}}]}},{"say":{"label":"<p><eval>game.text(&#39;cumRoundMessage&#39;)<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options1 *\/"}},{"choice":{"options":[{"label":"<eval>game.text('btnCumWin')<\/eval>","commands":[{"eval":{"script":"pullPage();\npages.goto('win');"}}]},{"label":"<eval>game.text('btnCumContinue')<\/eval>","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}],"melody-game-over-1":[{"image":{"locator":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990459"}},{"eval":{"script":"returnToCaller();"}}],"melody-game-over-2":[{"image":{"locator":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991229"}},{"eval":{"script":"returnToCaller();"}}],"melody-game-over-3":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990511"}},{"eval":{"script":"returnToCaller();"}}],"melody-cum-round-softcore":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005406"}},{"eval":{"script":"returnToCaller();"}}],"melody-cum-round-hardcore":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/991426"}},{"eval":{"script":"returnToCaller();"}}],"melody-cum-round-select":[{"image":{"locator":"gallery:a6068f8e-6608-437f-aefb-a94f5ee782e9\/1087408"}},{"eval":{"script":"returnToCaller(); \/\/ Return to caller"}}],"win-check":[{"eval":{"script":"if (!n.cumwin) {\r\n  \/\/ Haven't loaded yet\r\n  if (game.winCheckBpm) {\r\n    if (game.winCheckPattern) {\r\n      game.setPattern(game.winCheckPattern)\r\n    }\r\n    beats.start(game.winCheckBpm)\r\n  } else {\r\n    beats.stopAll()\r\n  }\r\n  closeAll();\r\n}\r\n"}},{"eval":{"script":"if (!loadCumTeaseImage()) {\r\n  \/\/ We've loaded a cumtease image\r\n  if (game.winCheckRefresh) clearRoundImage() \/\/ Clear that image, so next time we load, we refresh it\r\n}\r\n"}},{"if":{"condition":"!n.cumwin","commands":[{"eval":{"script":"\/*--auto-magpie-merge:notification:cumwin1 *\/"}},{"notification.create":{"id":"cumwin","buttonCommands":[{"eval":{"script":"game.doCumWin()"}}],"buttonLabel":"\u2665 I Came! \u2665"}},{"eval":{"script":"n.cumwin = true\r\nvar __cumWinTries = 0"}},{"if":{"condition":"game.cumToWinTimer","commands":[{"eval":{"script":"\/*--auto-magpie-merge:notification:cumwin2 *\/"}},{"notification.create":{"id":"cumwin","buttonCommands":[{"eval":{"script":"game.doCumWin()"}}],"buttonLabel":"\u2665 I Came! \u2665","timerCommands":[{"eval":{"script":"game.doCumWinCheck()"}}],"timerDuration":"$game.getCumTimeRemaining()"}},{"eval":{"script":"\/*--auto-magpie-merge:notification:cumlose *\/"}},{"notification.create":{"id":"cumlose","buttonCommands":[{"eval":{"script":"game.doCumLose()"}}],"buttonLabel":"I Can't"}},{"eval":{"script":"n.cumlose = true"}}]}}]}},{"if":{"condition":"game.winCheckRefresh","commands":[{"timer":{"duration":"$game.winCheckRefresh * 1000","style":"hidden","isAsync":true,"commands":[{"eval":{"script":"pages.goto(pages.getCurrentPageId())"}}]}}]}},{"if":{"condition":"game.cumToWinTimer","commands":[{"if":{"condition":"__cumWinTries < 1","commands":[{"say":{"label":"<p><eval>game.text(&#39;cumToWinStartPrompt&#39;)<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"say":{"label":"<p><eval>game.text(&#39;cumRoundMessage&#39;)<\/eval><\/p>","mode":"instant"}}],"elseCommands":[{"say":{"label":"<p><eval> game.text(&#39;cumRoundMessage&#39;)<\/eval><\/p>","mode":"instant"}}]}},{"eval":{"script":"__cumWinTries ++"}}],"cum-round-select":[{"eval":{"script":"closeAll();\r\nvar sOpts = _selectableOptions(cr)\r\nif (sOpts.length < 2) {\r\n  if (sOpts.length < 1) {\r\n    \/\/ No modes defined\r\n    console.error('No selectable cumRoundModes defined.')\r\n  } else {\r\n    \/\/ We only have one mode.  Use it  \r\n    if (DEBUG) console.warn('Auto-selecting cum-round-mode:', sOpts[0])\r\n    game.setCumRoundAlt(sOpts[0].id);\r\n    \/\/ And get out\r\n    returnToCaller();\r\n  }\r\n}"}},{"eval":{"script":"if (!loadCumRoundSelectImage()) {\r\n  var message1 = game.text('cumRoundSelect1');\r\n  var message2 = game.text('cumRoundSelect2');\r\n}\r\n  "}},{"if":{"condition":"message1","commands":[{"say":{"label":"<p><eval>message1<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"message2","commands":[{"say":{"label":"<p><eval>message2<\/eval><\/p>","mode":"instant"}}]}},{"if":{"condition":"game.cumRoundModeAutoSelectTime","commands":[{"notification.create":{"buttonCommands":[{"eval":{"script":"roulette.useCumRoundModeSelector();\r\npages.goto('penalty-roulette');"}}],"buttonLabel":"Random \ud83c\udfb2","id":"random-select","timerCommands":[{"eval":{"script":"roulette.useCumRoundModeSelector();\r\npages.goto('penalty-roulette');"}}],"timerDuration":"$game.cumRoundModeAutoSelectTime * 1000"}}],"elseCommands":[{"notification.create":{"buttonCommands":[{"eval":{"script":"roulette.useCumRoundModeSelector();\r\npages.goto('penalty-roulette');"}}],"buttonLabel":"Random \ud83c\udfb2","id":"random-select"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options1 *\/"}},{"choice":{"options":[{"label":"<eval>_crt(0)<\/eval>","commands":[{"eval":{"script":"game.setCumRoundAlt(cr[0].id)"}}],"color":"#9c27b0","visible":"$_scr(0)"},{"label":"<eval>_crt(1)<\/eval>","commands":[{"eval":{"script":"game.setCumRoundAlt(cr[1].id)"}}],"color":"#ec407a","visible":"$_scr(1)"},{"label":"<eval>_crt(2)<\/eval>","commands":[{"eval":{"script":"game.setCumRoundAlt(cr[2].id)"}}],"color":"#00796b","visible":"$_scr(2)"},{"label":"<eval>_crt(3)<\/eval>","commands":[{"eval":{"script":"game.setCumRoundAlt(cr[3].id)"}}],"color":"#d84315","visible":"$_scr(3)"},{"label":"<eval>_crt(4)<\/eval>","commands":[{"eval":{"script":"game.setCumRoundAlt(cr[4].id)"}}],"color":"#1565c0","visible":"$_scr(4)"},{"label":"<eval>_crt(5)<\/eval>","commands":[{"eval":{"script":"game.setCumRoundAlt(cr[5].id)"}}],"visible":"$_scr(5)","color":"#1976d2"},{"label":"<eval>_crt(6)<\/eval>","commands":[{"eval":{"script":"game.setCumRoundAlt(cr[6].id)"}}],"visible":"$_scr(6)"},{"label":"<eval>_crt(7)<\/eval>","commands":[{"eval":{"script":"game.setCumRoundAlt(cr[7].id)"}}],"visible":"$_scr(7)"},{"label":"<eval>_crt(8)<\/eval>","commands":[{"eval":{"script":"game.setCumRoundAlt(cr[8].id)"}}],"visible":"$_scr(8)"},{"label":"<eval>_crt(9)<\/eval>","commands":[{"eval":{"script":"game.setCumRoundAlt(cr[9].id)"}}],"visible":"$_scr(9)"}]}},{"notification.remove":{"id":"random-select"}},{"eval":{"script":"returnToCaller(); \/\/ Return to caller"}}],"game-mode-select":[{"eval":{"script":"if (DEBUG) console.log('Selecting gameMode:', gms)\r\ncloseAll();\r\nvar sOpts = _selectableOptions(gms)\r\nif (sOpts.length < 2) {\r\n  if (sOpts.length < 1) {\r\n    \/\/ No modes defined\r\n    console.error('No selectable gameModes defined.')\r\n  } else {\r\n    \/\/ We only have one mode.  Use it  \r\n    if (DEBUG) console.warn('Auto-selecting gameMode:', sOpts[0])\r\n    game.setPlayerGameMode(sOpts[0].id);\r\n    \/\/ And get out\r\n    returnToCaller();\r\n  }\r\n}"}},{"eval":{"script":"loadImagePage(pages.getCurrentPageId() + '-image')"}},{"eval":{"script":"var message1 = game.text('gameModeSelect1');\r\nvar message2 = game.text('gameModeSelect2');\r\n"}},{"if":{"condition":"message1","commands":[{"say":{"label":"<p><eval>message1<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"message2","commands":[{"say":{"label":"<p><eval>message2<\/eval><\/p>","mode":"instant"}}]}},{"if":{"condition":"game.gameModeAutoSelectTime","commands":[{"notification.create":{"buttonCommands":[{"eval":{"script":"roulette.useGameModeSelector();\r\npages.goto('penalty-roulette');"}}],"buttonLabel":"Random \ud83c\udfb2","id":"random-select","timerCommands":[{"eval":{"script":"roulette.useGameModeSelector();\r\npages.goto('penalty-roulette');"}}],"timerDuration":"$game.gameModeAutoSelectTime * 1000"}}],"elseCommands":[{"notification.create":{"buttonCommands":[{"eval":{"script":"roulette.useGameModeSelector();\r\npages.goto('penalty-roulette');"}}],"buttonLabel":"Random \ud83c\udfb2","id":"random-select"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options3 *\/"}},{"choice":{"options":[{"label":"<eval>_gmst(0)<\/eval>","commands":[{"eval":{"script":"game.setPlayerGameMode(gms[0].id)"}}],"color":"#9c27b0","visible":"$_sgms(0)"},{"label":"<eval>_gmst(1)<\/eval>","commands":[{"eval":{"script":"game.setPlayerGameMode(gms[1].id)"}}],"color":"#ec407a","visible":"$_sgms(1)"},{"label":"<eval>_gmst(2)<\/eval>","commands":[{"eval":{"script":"game.setPlayerGameMode(gms[2].id)"}}],"color":"#00796b","visible":"$_sgms(2)"},{"label":"<eval>_gmst(3)<\/eval>","commands":[{"eval":{"script":"game.setPlayerGameMode(gms[3].id)"}}],"color":"#d84315","visible":"$_sgms(3)"},{"label":"<eval>_gmst(4)<\/eval>","commands":[{"eval":{"script":"game.setPlayerGameMode(gms[4].id)"}}],"color":"#1565c0","visible":"$_sgms(4)"},{"label":"<eval>_gmst(5)<\/eval>","commands":[{"eval":{"script":"game.setPlayerGameMode(gms[5].id)"}}],"color":"#0288d1","visible":"$_sgms(5)"},{"label":"<eval>_gmst(6)<\/eval>","commands":[{"eval":{"script":"game.setPlayerGameMode(gms[6].id)"}}],"color":"#6d4c41","visible":"$_sgms(6)"},{"label":"<eval>_gmst(7)<\/eval>","commands":[{"eval":{"script":"game.setPlayerGameMode(gms[7].id)"}}],"color":"#1565c0","visible":"$_sgms(7)"},{"label":"<eval>_gmst(8)<\/eval>","commands":[{"eval":{"script":"game.setPlayerGameMode(gms[8].id)"}}],"color":"#1565c0","visible":"$_sgms(8)"},{"label":"<eval>_gmst(9)<\/eval>","commands":[{"eval":{"script":"game.setPlayerGameMode(gms[9].id)"}}],"color":"#1565c0","visible":"$_sgms(9)"}]}},{"notification.remove":{"id":"random-select"}},{"eval":{"script":"returnToCaller(); \/\/ Return to caller"}}],"melody2-game-over-1":[{"image":{"locator":"gallery:f6d79ef6-da98-4c27-804d-e558f0b5fdf5\/991336"}},{"eval":{"script":"returnToCaller();"}}],"melody2-image-1-1":[{"image":{"locator":"gallery:f6d79ef6-da98-4c27-804d-e558f0b5fdf5\/991368"}},{"eval":{"script":"returnToCaller();"}}],"melody2-image-1-2":[{"image":{"locator":"gallery:f6d79ef6-da98-4c27-804d-e558f0b5fdf5\/991398"}},{"eval":{"script":"returnToCaller();"}}],"melody2-image-1-3":[{"image":{"locator":"gallery:f6d79ef6-da98-4c27-804d-e558f0b5fdf5\/991411"}},{"eval":{"script":"returnToCaller();"}}],"melody2-cum-round-cum":[{"image":{"locator":"gallery:f6d79ef6-da98-4c27-804d-e558f0b5fdf5\/991423"}},{"eval":{"script":"returnToCaller();"}}],"melody-game-over-hardcore":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005385"}},{"eval":{"script":"returnToCaller();"}}],"melody-game-over-softcore":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005372"}},{"eval":{"script":"returnToCaller();"}}],"melody-win-hardcore":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005463"}},{"eval":{"script":"returnToCaller();"}}],"melody-win-softcore":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005386"}},{"eval":{"script":"returnToCaller();"}}],"melody2-game-over-cum":[{"image":{"locator":"gallery:f6d79ef6-da98-4c27-804d-e558f0b5fdf5\/991338"}},{"eval":{"script":"returnToCaller();"}}],"melody2-win-cum":[{"image":{"locator":"gallery:f6d79ef6-da98-4c27-804d-e558f0b5fdf5\/991384"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-1":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/991329"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-2":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990501"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-3":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990510"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-4":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/991327"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-5":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/991426"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-12":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005431"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-11":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005429"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-10":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005428"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-9":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005427"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-8":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005422"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-7":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005420"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-6":[{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/991332"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-13":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005466"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-14":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005445"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-15":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005446"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-16":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005447"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-17":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005450"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-18":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005451"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-19":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005455"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-20":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005454"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-21":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005457"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-22":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005460"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-23":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005461"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-24":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005462"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-25":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005463"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-26":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005465"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-hardcore-27":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005432"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-1":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005355"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-26":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005407"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-25":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005405"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-24":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005406"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-23":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005404"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-22":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005402"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-21":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005401"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-20":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005403"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-19":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005399"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-18":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005398"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-17":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005396"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-16":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005393"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-15":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005392"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-14":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005391"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-13":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005390"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-12":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005388"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-11":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005387"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-10":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005386"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-9":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005383"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-8":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005382"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-7":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005376"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-6":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005375"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-5":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005371"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-4":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005368"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-3":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005363"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-softcore-2":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005365"}},{"eval":{"script":"returnToCaller();"}}],"melody2-image-cum":[{"image":{"locator":"gallery:f6d79ef6-da98-4c27-804d-e558f0b5fdf5\/*"}},{"eval":{"script":"returnToCaller();"}}],"core-config":[{"eval":{"script":"\/\/ Set global values\r\nDEBUG = 2; \/\/ <-- Set this false before release!!!\r\nS_ON = '\u2705'; \/\/ HTML for a setting \"on\" button \r\nS_OFF = '\u2b1c'; \/\/ HTML for a setting \"off\" button\r\nR_ON = '\ud83d\udd35'; \/\/ HTML for a radio \"on\" button \r\nR_OFF = '\u26aa'; \/\/ HTML for a radio \"off\" button"}},{"eval":{"script":"\/\/ Add custom player modifiable \"option\" settings\r\ngame.setSettingOption(\r\n  \/\/ Setting name is '$testPenalty' (custom settings must start with '$')\r\n  '$testPenalty', \r\n  \/\/ Setting definition:\r\n  {\r\n    type: storageTypes.GAME, \/\/ Use this, unless you've created your own\r\n    label: 'Custom Penalty', \/\/ What to display in menu\r\n    textKey: 'CustomPenalty', \/\/ looks for verbiage keys: \r\n    \/\/                      'settingCustomPenaltyEnable' &&\r\n    \/\/                      'settingCustomPenaltyDisable'\r\n    \/\/                       If not found, a simple default is used.\r\n    page: 'settings-options', \/\/ Where to display the selection\r\n    key: '$oTP', \/\/ short key for storage\r\n    defaultValue: false, \/\/ Default value\r\n  },\r\n  \/\/ Display as second item in settings-options page\r\n  \/\/ 0 = 1st, 1 = 2nd, 2 = 3rd, etc.\r\n  1\r\n)\r\n\/\/ NOTE: Remember to add $testPenalty: true, to the showSetting: {...} area\r\n\/\/       in your game.setConfig(...) eval\r\n\r\n\/\/ Add custom player modifiable \"kink\" settings\r\n\/\/ game.setSettingOption(\r\n\/\/   \/\/ Setting name is '$kinkCEI' (custom settings must start with '$')\r\n\/\/   '$kinkCEI', \r\n\/\/   \/\/ Setting definition:\r\n\/\/   {\r\n\/\/     type: storageTypes.GAME, \/\/ Use this, unless you've created your own\r\n\/\/     label: 'CEI', \/\/ What to display in menu\r\n\/\/     icon: '\ud83c\udf4c', \/\/ Set an icon\r\n\/\/     textKey: 'KinksCEI', \/\/ looks for verbiage keys: \r\n\/\/     \/\/                      'settingKinksCEIEnable' &&\r\n\/\/     \/\/                      'settingKinksCEIDisable'\r\n\/\/     page: 'settings-kinks', \/\/ Where to display the selection\r\n\/\/     key: '$kCE', \/\/ short key for storage\r\n\/\/     defaultValue: false, \/\/ Default value\r\n\/\/     show: function() {\r\n\/\/       \/\/ Only show if game is unlocked\r\n\/\/       return game.isUnlocked()\r\n\/\/     }\r\n\/\/   },\r\n\/\/   \/\/ Display before 'kinkCbt' setting\r\n\/\/   'kinkCbt'\r\n\/\/ )\r\n\/\/ NOTE: Remember to add $kinkCEI: true, to the showSetting: {...} area\r\n\/\/       in your game.setConfig(...) eval\r\n\r\n\/\/ If you wanted to add another another settings page:\r\n\/\/ 1. Copy settings-options page, and name it settings-myoptions\r\n\/\/    (replace \"myoptions\" with what you really want.)\r\n\/\/    NOTE: Settings pages MUST start with 'settings-'\r\n\/\/\r\n\/\/ 2. Add a setting option link for it, like:\r\n\/*\r\ngame.setSettingOption(\r\n  \/\/ New setting menu link option\r\n  '$myOptions', \r\n  \/\/ Setting definition:\r\n  {\r\n    type: storageTypes.NONE, \/\/ Use none for links\r\n    label: 'My Options',\r\n    icon: '\ud83c\udfc6', \/\/ Set an icon (optional)\r\n    page: 'settings', \/\/ Display on that main settings page\r\n    target: 'settings-myoptions', \/\/ Link to the new \"My Options\" page\r\n  },\r\n  'volume' \/\/ Add right before the \"Beat Volume\" button.\r\n)\r\n*\/\r\n\/\/  3. Add settings options for your new settings-myoptions page,\r\n\/\/     setting the new option definition's 'page' property to 'settings-myoptions' \r\n\/\/  \r\n\/\/  4. Remember to add $myOptions: true, to the showSetting: {...} area\r\n\/\/     in your game.setConfig(...) eval\r\n\r\n\r\n\/\/ To add custom player modifiable \"option\" settings with\r\n\/\/  radio button selection\r\n\/\/ (Due to limitations in Eos, each radio button setting \r\n\/\/   needs its own target page, 'settings-radio-options-example' \r\n\/\/   in this example. To create a page for a new setting, simply clone  \r\n\/\/   the existing 'settings-radio-options-example' and rename it.  \r\n\/\/   The new target page name MUST start with 'settings-')\r\ngame.setSettingOption(\r\n  \/\/ Setting name is '$testPenalty' (custom settings must start with '$')\r\n  '$testRadioOption', \r\n  \/\/ Setting definition:\r\n  {\r\n    type: storageTypes.GAME, \/\/ Use this, unless you've created your own\r\n    label: 'Favorite', \/\/ What to display in menu\r\n    icon: '\u2764\ufe0f', \/\/ Optional icon\r\n    \/\/                       If not found, a simple default is used.\r\n    page: 'settings-options', \/\/ Where to display the selection\r\n    target: 'settings-radio-options-example', \/\/ Page used to generate radio buttons\r\n    \/\/ Define radio button\r\n    prompt: function(){ \/\/ Optional function to generate setting prompt\r\n      return \"Pick your favorite thing.\"\r\n    },\r\n    options: {\r\n      \/\/ Keep option keys ('tits': in this first example) short.\r\n      \/\/ They take storage space.\r\n      tits: {\r\n        label: 'Tits', \/\/ Label for button\r\n        show: function(o){return true}, \/\/ Optional show\/hide function\r\n        block: function(o){}, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        \/\/ selectMessage: function(o){ \/\/ Optional function to display on select\r\n        \/\/   return \"You've selected <u>\" + o.label + \"<\/u>.\" \r\n        \/\/ },\r\n      },\r\n      ass: {\r\n        label: 'Ass', \/\/ Label for button\r\n        show: function(o){return true}, \/\/ Optional show\/hide function\r\n        block: function(o){\r\n          if (!game.kinkAnal && game.showSetting.kinkAnal) {\r\n            return \"Sorry, you can't select Ass unless you've enabled the Anal kink.\"\r\n          }\r\n        }, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        \/\/ selectMessage: function(o){ \/\/ Optional function to display on select\r\n        \/\/   return \"You've selected <u>\" + o.label + \"<\/u>.\" \r\n        \/\/ },\r\n      },\r\n      pussy: {\r\n        label: 'Pussy', \/\/ Label for button\r\n        show: function(o){return true}, \/\/ Optional show\/hide function\r\n        block: function(o){}, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        \/\/ selectMessage: function(o){ \/\/ Optional function to display on select\r\n        \/\/   return \"You've selected <u>\" + o.label + \"<\/u>.\" \r\n        \/\/ },\r\n      },\r\n      none: {\r\n        label: \"Can't Decide\", \/\/ Label for button\r\n        show: function(o){return true}, \/\/ Optional show\/hide function\r\n        block: function(o){}, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        \/\/ selectMessage: function(o){ \/\/ Optional function to display on select\r\n        \/\/   return \"You've selected <u>\" + o.label + \"<\/u>.\" \r\n        \/\/ },\r\n      },\r\n    },\r\n    key: '$oFav', \/\/ short key for storage\r\n    defaultValue: 'none', \/\/ Default value\r\n  }\r\n  \/\/ Append as last in options (no insert position defined)\r\n)\r\n\/\/ To check key value (tits, ass, etc) in game:\r\n\/\/   if (game.$testRadioOption === 'tits') {\r\n\/\/     pages.goto('the-best-tits-page')\r\n\/\/   }\r\n\/\/ To use object values in game:\r\n\/\/   var favObject = game.getRadioObject('$testRadioOption')\r\n\/\/   var myMessage;\r\n\/\/   if (!favObject || favObject.id === 'none') {\r\n\/\/     myMessage = \"You can't decide what you like best?!\"\r\n\/\/   } else {\r\n\/\/     myMessage = 'So, you like my ' \r\n\/\/                   + favObject.label.toLowerCase()\r\n\/\/                   + '?'\r\n\/\/   }\r\n\/\/ Since our \"Favorite\" option example has a blocker for \"Ass\" that needs\r\n\/\/  kinkAnal to be enebaled, also add a blocker to kinkAnal\r\ngame.setSettingOption(\r\n  'kinkAnal', \r\n  {\r\n    block: function(setting, val) {\r\n      if (!val) {\r\n        var favObject = game.getRadioObject('$testRadioOption') || {}\r\n        if (favObject.id === 'ass') {\r\n          var msg = '<i>' + setting.label + '<\/i> must be enabled when '\r\n           + '<i>' + game.getSettingOption('$testRadioOption').label + '<\/i>'\r\n           + ' is <u>' + favObject.label + '<\/u>'\r\n           console.log(\"Block\", msg)\r\n           return msg\r\n        }\r\n      }\r\n    },\r\n  }\r\n)\r\n\r\n\r\n\/\/ Modify existing setting definitions\r\ngame.setSettingOption(\r\n  \/\/ Change base kinkPrecum setting\r\n  'kinkPrecum', \r\n  \/\/ Setting definition:\r\n  {\r\n    label: 'Precum', \/\/ Have label say \"Precum\" instead of \"Precum CEI\"\r\n    icon: '\ud83d\udca7', \/\/ Set an icon (Doesn't have one bydefault)\r\n  }\r\n)\r\n\r\n\/\/ Add icons to some of the others existing ones\r\ngame.setSettingOption('kinkCbt', {icon: '\ud83d\ude2b'})\r\ngame.setSettingOption('kinkAnal', {icon: '\ud83c\udf51'})\r\n\r\n\/\/ Add verbiage for custom setting\r\ngame.setVerbiage({\r\n  settingKinksCEIEnabled: [\r\n    \"You've <u>enabled<\/u> Cum Eating Intructions.  \" + \r\n    \"You may be told to swing your legs over your head, and cum in your mouth.\"\r\n  ],\r\n  settingKinksCEIDisabled: [\r\n    \"You've <u>disabled<\/u> Cum Eating Intructions.  \" + \r\n    \"You will not be told to cum in your mouth.\"\r\n  ]\r\n})"}},{"eval":{"script":"\/\/ Create custom setting options to override round fap time\r\ngame.setSettingOption(\r\n  \/\/ Setting name is '$testPenalty' (custom settings must start with '$')\r\n  'roundTimeFap', \r\n  \/\/ Setting definition:\r\n  {\r\n    force: true, \/\/ Force this setting to allow use of existing varable\r\n    type: storageTypes.GAME, \/\/ Use this, unless you've created your own\r\n    label: 'Round Time', \/\/ What to display in menu\r\n    icon: '\u23f1\ufe0f', \/\/ Optional icon\r\n    \/\/                       If not found, a simple default is used.\r\n    page: 'settings-options', \/\/ Where to display the selection\r\n    target: 'settings-round-timer', \/\/ Page used to generate radio buttons\r\n    \/\/ Define radio button\r\n    prompt: function(){ \/\/ Optional function to generate setting prompt\r\n      return \"How long will you have to hit\/stand?\"\r\n    },\r\n    integer: true,\r\n    options: {\r\n      \/\/ Keep option keys ('tits': in this first example) short.\r\n      \/\/ They take storage space.\r\n      '10': {\r\n        label: '10 Seconds', \/\/ Label for button\r\n      },\r\n      '20': {\r\n        label: '20 Seconds', \/\/ Label for button\r\n      },\r\n      '30': {\r\n        label: '30 Seconds', \/\/ Label for button\r\n      },\r\n    },\r\n    key: '$rFt', \/\/ short key for storage\r\n    defaultValue: 30, \/\/ Default value\r\n  }\r\n  \/\/ Append as last in options (no insert position defined)\r\n)"}},{"eval":{"script":"\/\/ Add optional audio profile selection setting options\r\ngame.generateSoundOptions([\r\n  {\r\n    \/\/ Define option for --audio-1 page\r\n    label: 'Default'\r\n  },\r\n  {\r\n    \/\/ Define option for --audio-2 page\r\n    label: 'Alternate'\r\n  }\r\n], {\r\n  label: 'Audio Profile', \/\/ Text for setting button\r\n  icon:  '\ud83c\udfb5', \/\/ Optional icon\r\n  page: 'settings-sounds', \/\/ Where to display button\r\n  position: 'volume', \/\/ Insert before volume\r\n})\r\n\r\n\/\/ Add 'Audio Options' menu item\r\ngame.setSettingOption(\r\n  '$soundsMenu', \r\n  \/\/ Setting definition:\r\n  {\r\n    type: storageTypes.NONE,\r\n    label: 'Audio Options', \/\/ What to display in menu\r\n    icon: '\ud83d\udd08',\r\n    page: 'settings', \/\/ Where to display the selection\r\n    target: 'settings-sounds', \/\/\r\n  },\r\n  \/\/ Display before volume setting\r\n  'volume'\r\n)\r\n\r\n\/\/ Add 'Moans' menu item\r\ngame.setSettingOption(\r\n  'enableMoans', \r\n  \/\/ Setting definition:\r\n  {\r\n    force: true, \/\/ Allow setting to control existing game property\r\n    type: storageTypes.GAME,\r\n    label: 'Moans', \/\/ What to display in menu\r\n    icon: '\ud83d\udc44',\r\n    page: 'settings-sounds', \/\/ Where to display the selection\r\n    enableMessage: \"You've <u>enabled<\/u> moans.\" \r\n    + \"  You'll hear me moan throughout the game.[playMoan|moan]\",\r\n    disableMessage: \"Aww, you've <u>disabled<\/u> moans.  I'll keep my mouth shut.[stopMoan|moan]\",\r\n    onExit: function () {\r\n      game.stopMoan('moan')\r\n    },\r\n    key: '$aMns',\r\n    defaultValue: false,\r\n  },\r\n  \/\/ Display before volume setting\r\n  'volume'\r\n)\r\n\r\n\/\/ Move 'volume' menu item to 'Audio Options'\r\ngame.setSettingOption(\r\n  'volume', \r\n  {\r\n    page: 'settings-sounds', \/\/ Where to display the selection\r\n  }\r\n)\r\n"}},{"eval":{"script":"\/\/ Define \"melody\" game mode\r\n\r\nvar gm_melody = {\r\n  \/\/ Game config to apply for \"melody\" game mode\r\n  title: 'Full Game',\r\n  levels: 3, \/\/ 3 levels, plus cum round(s)\r\n  perLevel: 15, \/\/ 15 hands per level\r\n  \/\/ Example round limits (allowes you to truncate rounds)\r\n  \/\/ roundLimits: {\r\n  \/\/   1: 10, \/\/ Limit level 1 to 10 rounds, always\r\n  \/\/   2: function() {return !game.isUnlocked() ? 10 : false}, \/\/ If not unlocked, limit level 2 to 10 rounds\r\n  \/\/ },\r\n  \/\/ Example penaltyOccurrence overrides\r\n  \/\/ valid penalties: edge, edgeRide, stroke, loseRest, precum, anal, cbt, ...\r\n  \/\/ penaltyOccurrence: {\r\n  \/\/   loseRest: function () {\r\n  \/\/     if (game.getLevel() > 1 && game.getRoundIndex() > 2) {\r\n  \/\/       \/\/ Example loseRest prenalty occurrence overide:\r\n  \/\/       \/\/ After the second hand of every level past 1\r\n  \/\/       \/\/ increase loseRest probability to 10 out of (whatever else)\r\n  \/\/       return {\r\n  \/\/         allow: function () {\r\n  \/\/           \/\/ Only enable penalty if player has edged more than\r\n  \/\/           \/\/ once (g.pc.edge.c), and has at least 1 rest point (g.c)\r\n  \/\/           return g.pc.edge.c > 1 && g.c > 0\r\n  \/\/         },\r\n  \/\/         probability: function () {\r\n  \/\/           return 10 \/\/ Increase probabilty\r\n  \/\/         },\r\n  \/\/         enabled: function () {\r\n  \/\/           return true \/\/ Force penalty to be enabled, even if turned off\r\n  \/\/         }\r\n  \/\/       }\r\n  \/\/     }\r\n  \/\/   }\r\n  \/\/ },\r\n  \r\n  \/\/ Example penalty settings calculation override\r\n  penaltyCalc: {\r\n    \/**\r\n     * valid penalties are:\r\n     * 'stroke', 'anal', 'edge', 'edgeRide', 'cbt', 'precum', ...\r\n     *\/\r\n    \/\/ Hook 'stroke' penalty ('anal' works similar)\r\n    'stroke': function(o, level, hand) {\r\n      \/\/ Flip a coin if we're over level 1:\r\n      var doIt = level > 1 && !randomInt(0, 1)\r\n      if (doIt) {\r\n        \/\/ If we're on level 2 or higher,\r\n        \/\/ and we lost a coin toss, \r\n        \/\/ override some settings\r\n        if (DEBUG) console.warn('Fapping the hell out of them.')\r\n        return {\r\n          \/\/ Fap the hell out of them\r\n          faps: randomInt(120, 150), \/\/ Random between 120 and 150\r\n          startBpm: 300, \/\/ Random between 300\r\n          endBpm: 300, \/\/ and 300 bpms (force 300 bpms)\r\n          getMessage: function(opt) {\r\n            return mergeObject(randomString([\r\n              \"This time I'll make you cum!  [faps] turbo faps!!!\",\r\n              \"There's no way you'll get past this!  Stroke [faps] times!!!\"\r\n            ]), opt);\r\n          },\r\n          getDoneMessage: function(opt) {\r\n            return \"Don't tell me you survived that!\"\r\n          },\r\n          getStepImage: function(step, opt) {\r\n            if (step === 'stroke') {\r\n              return 'melody-image-penalty-stroke'\r\n            }\r\n          },\r\n        }\r\n      }\r\n      \/\/ Else, returning nothing will just go with default\r\n    },\r\n    \/\/ Hook 'edgeRide' penalty\r\n    'edgeRide': function(o, level, hand) {\r\n      \/\/ Flip a coin if we're over level 1:\r\n      var doIt = level > 1 && !randomInt(0, 1)\r\n      if (doIt) {\r\n        \/\/ If we're on level 2 or higher,\r\n        \/\/ and we lost a coin toss, \r\n        \/\/ override some settings\r\n        if (DEBUG) console.warn('Riding the hell out of them.')\r\n        return {\r\n          bpm: 300, \/\/ Fap the hell out of them to edge\r\n          rideTime: 40, \/\/ Force a ride of 40 seconds.\r\n          getRideMessage: function(opt) {\r\n            return mergeObject(randomString([\r\n              \"Now hold that edge for [ride] excruciating seconds!\",\r\n              \"Imagine I'm riding your cock while holding that edge for [ride] seconds!\"\r\n            ]), opt);\r\n          },\r\n          getStepImage: function(step, opt) {\r\n            if (step === 'edge-ride') {\r\n              return 'melody-image-penalty-ride'\r\n            }\r\n            if (step === 'rest') {\r\n              return 'melody-image-penalty-ride-rest'\r\n            }\r\n          },\r\n        }\r\n      }\r\n      \/\/ Else, returning nothing will just go with default\r\n    },\r\n  },\r\n  levelConfig: {\r\n    0: {\r\n      \/\/ Defaults for all levels\r\n      dealerName: 'Melody', \/\/ Dealer name defaults to Melody for all levels\r\n    },\r\n    2: {\r\n      \/\/Overrides per given level\r\n      dealerName: 'Melody', \/\/ Override dealer name for level 2\r\n    },\r\n  },\r\n  bpms: [null,90,120,150,180,240], \/\/ BPMs used per game level, 90 for 1, 120 for 2, etc. \r\n  cumRoundModes: {\r\n    \/\/ Up to 10 cum round modes allowed per game mode (try not to use more than 6.  Adjust button colors in cum-round-select)\r\n    'softcore': {\r\n      title: 'Tits & Ass',\r\n      rounds: 26, \/\/ 26 for no-hardcore mode\r\n      \/\/ Optional game settings overrides\r\n      gameSettings: {\r\n        \/\/ Add any applicable game settings you want to override for cum round here\r\n        winToCumTime: 60, \/\/ Must win within 60 seconds\r\n        dealerName: 'Melody', \/\/ Override dealer name\r\n      },\r\n    },\r\n    'hardcore': {\r\n      title: 'Suck & Fuck',\r\n      rounds: 27, \/\/ 27 Images\/Pages for hardcore cum round\r\n      gameSettings: {\r\n        \/\/ Add any applicable game settings you want to override for cum round here\r\n        winToCumTime: 60, \/\/ Must win within 60 seconds\r\n        dealerName: 'Melody', \/\/ Override dealer name\r\n      },\r\n    },\r\n  },\r\n}"}},{"eval":{"script":"\/\/ Define \"melody2\" game mode\r\n\r\nvar gm_melody2 = {\r\n  \/\/ Game config to apply for \"melody2\" game mode\r\n  title: 'Super Short',\r\n  levels: 1, \/\/ 1 levels, plus cum round(s)\r\n  perLevel: 3, \/\/ 3 hands per level\r\n  \/\/ Will apply to all difficulties, since we didn't define applyToDifficulties\r\n  levelConfig: {\r\n    0: {\r\n      \/\/ Defaults for all levels\r\n      roundTimeFap: 5, \/\/ melody2 only gives 5 seconds to hit\/stand\r\n      dealerName: 'Melody', \/\/ Dealer name defaults to Melody for all levels\r\n    }\r\n  },\r\n  \/\/ Melody 2 faps faster in-round in the beginning\r\n  bpms: [null,150,150,150,180,240], \/\/ BPMs used per game level, 90 for 1, 120 for 2, etc. \r\n  cumRoundModes: {\r\n    \/\/ Up to 10 cum round modes allowed per game mode (try not to use more than 6.  Adjust button colors in cum-round-select)\r\n    'cum': {\r\n      title: 'More of Me',\r\n      rounds: 3, \/\/ 3 hands, but will fallback to \"melody2-image-cum\" to load images.\r\n      gameSettings: {\r\n        dealerName: 'Melody', \/\/ Override dealer name for cum round\r\n        winToCumTime: 45, \/\/ Must win within 45 seconds\r\n      }\r\n    },\r\n    'softcore': {\r\n      \/\/ Re-use the 'softcore' cum round from 'melody'\r\n      title: 'Tits & Ass',\r\n      rounds: 26, \/\/ 26 for no-hardcore mode\r\n      \/\/ Optional game settings overrides\r\n      gameSettings: {\r\n        modePath: 'melody', \/\/ We'll load pages like we're in melody mode\r\n        \/\/ Add any applicable game settings you want to override for cum round here\r\n        winToCumTime: 60, \/\/ Must win within 60 seconds\r\n        dealerName: 'Melody', \/\/ Override dealer name\r\n      },\r\n    },\r\n  },\r\n}"}},{"eval":{"script":"\/\/ Set Default Game Configuration\r\n\/\/ NOTE:  It's important to only execute game.setConfig(...) once for \r\n\/\/        default configuration.\r\ngame.setConfig({\r\n\r\n  \/\/ GAME SETTINGS\r\n  volume: 0.5, \/\/ Volume level between zero and 1, but seems to actually be between 0.0 and 0.1? (player modifiable)\r\n  volumeStep: 0.04, \/\/ Amount to change volume on adjustment\r\n  defaultRests: 2, \/\/ Number of rests a player starts with\r\n  numberOfDecks: 1, \/\/ Number of decks to use\r\n  kinkCbt: false, \/\/ Cock Ball torture (player modifiable)\r\n  kinkAnal: false, \/\/ Anal play (player modifiable)\r\n  kinkPrecum: false, \/\/ Precum CEI (player modifiable)\r\n  loseRest: true, \/\/ Enable loseing rest (player modifiable)\r\n  cumRoundAuto: false, \/\/ Advance round automatically (not applicable to winToCum)\r\n  showSetting: {\r\n    volume: true, \/\/ Show beat volume setting\r\n    options: true, \/\/ Show gane options settings\r\n    loseRest: true, \/\/ Show Lose Rest option\r\n    inRoundFapping: true, \/\/ Show In Round Fapping option\r\n    strokePenaltyLimit: true, \/\/ Show Stroke Penalty Limit option\r\n    lossPenalty: true,\r\n    kinks: true, \/\/ Show Kinks setting\r\n    kinkPrecum: true, \/\/ Show Precum CEI kink\r\n    kinkCbt: true, \/\/ Show CBT kink\r\n    kinkAnal: true, \/\/ Show Anal kink\r\n    \/\/ $testPenalty: true, \/\/ Show our custom $testPenalty option setting\r\n    \/\/ $testRadioOption: true, \/\/ Show our example radio options\r\n    $kinkCEI: true, \/\/ Show our custom $kinkCEI kink setting\r\n    roundTimeFap: true,\r\n    audioProfile: true,\r\n    $soundsMenu: true,\r\n    enableMoans: true,\r\n  },\r\n  cumRoundTease: true, \/\/ Encourage to cum in auto-cum round (not applicable to winToCum)\r\n  continousShuffle: false, \/\/ Shuffle cards after each hand, or shuffle after 5 hands.\r\n  winToCum: true, \/\/ Player must win the cum round to cum.\r\n  winToCumTime: 90, \/\/ Time, in seconds, player must win rounds in\r\n  winToCumTimeMin: 8, \/\/ If using cumToWinTimer, minimum time player will get\r\n  cumToWinTimer: true, \/\/ Use time remaining in win to cum round as limit for final cum page\r\n  cumRoundsToWin: 6, \/\/ Number of rounds player must win to cum, if winToCum\r\n  winToCumPenalty: 5, \/\/ Penalty, in seconds, for losing hand by standing below threshold\r\n  winToCumThreshold: 8, \/\/ If player stands below this value, then they're not even trying. Penalize them.\r\n  winToCumIncAlways: true, \/\/ Increment round image even if player loses hand in winToCum mode\r\n  cumRoundModeAutoSelectTime: 10, \/\/ 10 seconds to select cum round mode, else auto select (0 to disable)\r\n  gameModeAutoSelectTime: 10, \/\/ 10 seconds to select game mode, else auto select (0 to disable)\r\n  randomItemHistorySize: 0, \/\/ (Increase to decrease repetition of penalty sleection. 0 to 2 is a good setting)\r\n  dealerName: 'Melody', \/\/ Default dealer's name (can be overriden per level)\r\n  \/\/ GAME MODES\r\n  gameModes: {\r\n    \/\/ Up to 10 game modes (try not to use more than 6.  Adjust button colors in game-mode-select)\r\n    melody: gm_melody, \/\/ use pre-defined game mode (see evals above)\r\n    melody2: gm_melody2, \/\/ use pre-defined game mode (see evals above)\r\n  },\r\n\r\n  \/\/ OTHER GAME SETTINGS\r\n  maxSaveAge: 120, \/\/ How old a saved game state can be, in seconds, to be continued.\r\n  dealerSaftey: 17, \/\/ Dealer will not hit at or past this point.\r\n  rouletteTimerStart: [10, 80], \/\/ Starting ms wait between clicks [nornal, slow]\r\n  rouletteTimerLen: [10, 8], \/\/ How many clicks for penalty roulette [nornal, slow]\r\n  rouletteTimerInc: [0.5, 0.25], \/\/ how much to increase the durration between clicks after each roulette click [nornal, slow]\r\n  rouletteTimerEnd: .5, \/\/ Seconds to wait after penalty roulette ends, and the penalty page is displayed\r\n  roundTimerNoFap: 15, \/\/ Seconds to wait for hit\/stand with no-fap setting\r\n  roundTimeFap: 30, \/\/ Seconds to wait for hit\/stand with fap setting\r\n  roundTimeCum: 30, \/\/ Seconds to wait for hit\/stand in cum round (not in winToCum)\r\n  roundTimeCumAuto: 10, \/\/ Seconds to wait for hit\/stand in cum-auto advance mode (not in winToCum)\r\n  singleLevelImage: false, \/\/ Force use of [gameMode]-image-[level] instead of [gameMode]-image-[level]-[hand]\r\n                           \/\/ (fall-back to single-level image is automatic if descrete or range image page isn't found)\r\n\r\n  \/\/ SETTING THAT MAY GO AWAY OR MAY NO LONGER WORK CORRECTLY\r\n  strokePenaltyLimit: false, \/\/ If true, edge only if not round 1 or cum round (player modifiable)\r\n  inRoundFapping: true, \/\/ Fap durring round. (player modifiable)\r\n  \r\n  \/\/ DEAD GAME SETTINGS THAT PROBABLY DON'T WORK AS YOU WOULD THINK\r\n  shuffleNotice: false, \/\/ If not continousShuffle, show a notice for shufffles (Was fun to make, but too distracting.)\r\n\r\n});"}},{"eval":{"script":"\/\/ Add a simple custom penalty\r\n\/\/ Create a simple \"custom\" penalty that will go to a page of your choice\r\n\/\/ (See setPenaltyOccurrences example in core-config-ulc-exmaple\r\n\/\/      for a more complicated penalty that uses parts of existing penalties.)\r\ngame.setPenaltyOccurrences([\r\n  {\r\n    pf: pf.custom, \/\/ Use \"custom\" penalty factory as base\r\n    o: {\r\n      id: 'testP', \/\/ Keep IDs very short (uses tease storage space)\r\n      title: 'Custom Penalty', \/\/ Keep titles short.  Needs to show in the roulette\r\n      allow: function() {\r\n        \/\/ The difference between allow and enabled is:\r\n        \/\/ enabled:  penalty shows in roulette or not when \"spinning\"\r\n        \/\/ allow:  allow penalty to be selected in roulette\r\n        return true \/\/ Force allow for debugging\r\n      },\r\n    },\r\n    probability: function(){\r\n      return 50 \/\/ Force high probability for debugging\r\n      return 2 \/\/ repeat 2 times in roulette to set probability\r\n    }, \r\n    enabled: function(){\r\n      return game.$testPenalty \/\/ Only include if custom testPenalty setting is enabled\r\n    },\r\n    page: 'penalty-custom-example', \/\/ Name of page you want to show\r\n    \/\/ (See penalty-custom-example page for example of how you should start and end your penalties.)\r\n  \r\n  },\r\n])\r\n"}},{"eval":{"script":"\/\/ Create custom CEI pentaly example, using the precum penalty as a base\r\ngame.setPenaltyOccurrences([\r\n  \/\/ Create CEI using precum penalty factory\r\n  {\r\n    pf: pf.precum, \/\/ Use existing precum penalty factory as base\r\n    o: {\r\n      id: 'cei', \/\/ Keep IDs very short (uses tease storage space)\r\n      title: 'Cum in mouth',\r\n      allow: function() {\r\n        \/\/ The difference between allow and enabled is:\r\n        \/\/ enabled:  penalty shows in roulette or not when \"spinning\"\r\n        \/\/ allow:  allow penalty to be selected in roulette\r\n        return true \/\/ Force allow for debugging\r\n        \/\/ Allow if:\r\n        return game.getLevel() > 1 && \/\/ is in secord level or more\r\n          (\r\n          (g.pc.precum.c > 0 && game.kinkPrecum) \/\/ has hit pre-cum penalty\r\n          ||\r\n          (g.pc.edge.c > 1 && !game.kinkPrecum) \/\/ has edged twice, if precum not enabled\r\n          )\r\n          (Date.now() - (g.pc.cei._t || 0)) >= 300000 \/\/ At least 5 min since last successful CEI\r\n      },\r\n      getMessage: function(opt) {\r\n        closeAllBut('round') \/\/ Hide the cum\/rest button\r\n        beats.start(300); \/\/ Fap like hell\r\n        return mergeObject(randomString(t.eatCum), opt);\r\n      },\r\n      getFailMessage: function(opt) {\r\n        return mergeObject(randomString(opt.timeout ? t.eatCumTimeout : t.eatCumFail), opt);\r\n      },\r\n      messageDelay: function (opt) {\r\n        return 90000; \/\/ ms.   Wait 90 sec. to cum in mouth, or fail.\r\n      },\r\n      showTimer: true,\r\n      finish: function(opt) {\r\n        \/\/ Finished successfully\r\n        g.c ++; \/\/ Add rest point (yeah, badly named)\r\n        g.pc.cei._t = Date.now(); \/\/ Record success time\r\n        return mergeObject(randomString(t.eatCumDone), opt);\r\n      },\r\n      getAfterPassMessage: function(opt) {\r\n        \/\/ Return a message telling player to wait until they're ready\r\n        \/\/ Will trigger pause, waiting for a button press.\r\n        \/\/ Comment out this function, or return false to\r\n        \/\/ disable pause.\r\n        return mergeObject(randomString(t.eatCumPause), opt);\r\n      },\r\n      getStepImage: function(step, opt) {\r\n        if (step === 'message-pass-fail') {\r\n          \/\/ Load an image page for showing CEI example\r\n          return 'melody-image-penalty-cei'\r\n        } else {\r\n          \/\/ Probably on message-pass or message-fail page.\r\n          \/\/ Stop all beats\r\n          beats.stopAll();\r\n          if (step === 'message-pass') {\r\n            \/\/ Show a reward image while player tries to get hard again\r\n            return 'melody-image-penalty-cei-pass'\r\n          }\r\n          \/\/ return -1 to force load of game round image\r\n          return -1 \r\n        }\r\n      },\r\n    },\r\n    probability: function(){\r\n      return 50 \/\/ Force high probability for debugging\r\n      return 2 \/\/ repeat 2 times in roulette to set probability\r\n      }, \r\n    enabled: function(){\r\n      return game.$kinkCEI \/\/ Only include if custom CEI setting is enabled\r\n      }\r\n  },\r\n])\r\n\r\n\/\/ Add verbiage needed for custom penalties\r\ngame.setVerbiage({\r\n  eatCum: [ \/\/ Tell player to cum in mouth\r\n    '<span style=\"color:yellow\">Here\\'s your chance!<\/span><\/p>' \r\n    +\"<p>Get your ass above your head, then cum in your mouth!\",\r\n    \"Hurry! Ass up, point your cock at your mouth, stroke 'till you cum!\",\r\n    \"Time for a treat!<\/p><p>Legs over your head, cum in your mouth!\",\r\n    \"Get in position!<\/p><p>Wank every last drop of cum directly in your mouth!\",\r\n  ],\r\n  eatCumTimeout: [ \/\/ Took too long to eat cum\r\n    \"Sorry, you need to do it quickly!\",\r\n    \"I know you're trying, but I'm in a hurry!\",\r\n    \"Shouldn't take all day to aim and cum!\",\r\n    \"Next time, aim true and wank harder!\",\r\n    \"You need to work fast if you want your reward!\",\r\n  ],\r\n  eatCumFail: [ \/\/ Couldn't eat cum\r\n    \"Aw.  Maybe next time?\",\r\n    \"Don't worry, you'll have another chance!\",\r\n    \"I'm sure you'll do it next time!\",\r\n    \"I know, sometimes the moment just isn't right.\",\r\n    \"You'll do it for me next time, right?\",\r\n  ],\r\n  eatCumDone: [ \/\/ Congratulate player\r\n    \"Yay!  You earn a rest point!\",\r\n    \"Mmmm!  Have another rest point!\",\r\n    \"Good job!  Have another rest point!\",\r\n    \"Yay! Cum-slut power-up! Another rest point for you!\",\r\n  ],\r\n  eatCumPause: [ \/\/ Let player wait to get hard again.\r\n    \"Let me know when you're ready to continue.\",\r\n    \"Savor it for as long as you like.\",\r\n    \"Take your time, but I know you're eager for more!\",\r\n    \"Make sure you clean up your mess.\",\r\n  ],\r\n});\r\n"}},{"eval":{"script":"returnToCaller();"}}],"game-mode-select-image":[{"image":{"locator":"gallery:a6068f8e-6608-437f-aefb-a94f5ee782e9\/1087713"}},{"eval":{"script":"returnToCaller();"}}],"welcome":[{"eval":{"script":"loadImagePage('welcome-image')"}},{"eval":{"script":"var partialGame = game.hasRecentSave();\nvar doAction = function(){pages.goto('play')};"}},{"if":{"condition":"!game.didWelcome","commands":[{"if":{"condition":"DEBUG","commands":[{"say":{"label":"<p>*** THIS IS A DEBUG VERSION OF THE GAME USED FOR DEVELOPMENT ONLY ***<\/p>","mode":"instant"}},{"say":{"label":"<p>*** PLEASE PLAY USING THE RELEASE VERSION ***<\/p>","mode":"pause"}}]}},{"eval":{"script":"game.didWelcome = true"}},{"say":{"label":"<p><eval>game.text(&#39;welcome&#39;)<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"partialGame","commands":[{"say":{"label":"<p><span style=\"color: #ffffff\">Looks like you have a recent partially completed game.<\/span><\/p>","mode":"instant"}},{"say":{"label":"<p>Do you want to finish that one, or start a new one?<\/p>","mode":"instant"}}],"elseCommands":[{"say":{"label":"<p><eval>mergeObject(randomString(t.introBlurb), game)<\/eval><\/p>","mode":"instant"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options1 *\/"}},{"choice":{"options":[{"label":"<u>Let's play!<\/u>","commands":[{"eval":{"script":"\/\/ Initials sounds after click to authorize on some browsers\nbeats.init();\ndoAction = function(){pages.goto('play-start')};"}}],"visible":"$!partialGame"},{"label":"What's <b><i>Blackjack<\/i><\/b> or <b><i>FapJack<\/i><\/b>?","commands":[{"eval":{"script":"\/\/ Initials sounds after click to authorize on some browsers\nbeats.init();\ndoAction = function(){pages.goto('instructions')};"}}],"visible":"$!partialGame"},{"label":"Resume my last game, please!","commands":[{"eval":{"script":"beats.init(); \/\/ Make sure sounds are loaded and working"}},{"eval":{"script":"game.restoreState(); \/\/ Load saved state\ndoAction = function(){pages.goto('play')}; \/\/ Resume game"}}],"visible":"$partialGame"},{"label":"I'd like to start fresh.","commands":[{"eval":{"script":"beats.init(); \/\/ Make sure sounds are loaded and working"}},{"eval":{"script":"game.clearState(); \/\/ Reset game state\ndoAction = function(){pages.goto(pages.getCurrentPageId())}; \/\/ Reload this page\n"}}],"visible":"$partialGame"},{"label":"Settings","commands":[{"eval":{"script":"\/\/ Init sounds after click to authorize on some browsers\nbeats.init();"}},{"eval":{"script":"doAction = function(){callPage('settings');}; \/\/ Go to settings"}}]}]}},{"eval":{"script":"beats.volume(game.volume);\ndoAction();"}}],"core-verbiage":[{"eval":{"script":"\r\n\/\/ Load Default Verbiage\r\n\/\/ Remember to keep it short and sweet!\r\n\/\/ Don't under-estimate how badly the wrong words or too much repetition \r\n\/\/  can ruin the mood.\r\n\/\/ (And don't give FapJack a bad name by making the dealer say stupid crap!)\r\n\/\/ Text is randomly selected from the lists provided.\r\ngame.setVerbiage({\r\n  welcome: [ \/\/ First message the player sees.\r\n    \"Hi!  Welcome to \" + \"FapJack\".italic().bold() + \"!\",\r\n    \"Hey!  Welcome to \" + \"FapJack\".italic().bold() + \"!\",\r\n    \/\/ Good spot to test things, since it's one of the first things you'll see.\r\n    \/\/ \"[dealerBlackjackOpen]Yay! I win with blackjack![dealerBlackjackClose]\",\r\n  ],\r\n  introBlurb: [ \/\/ First message the player sees.\r\n    \/\/ NOTE: with multiple lines from a variable,\r\n    \/\/       don't include the opening and closing <p> tags\r\n    \"<u>The rules are simple:<\/u><\/p>\"\r\n    + \"<p>1. Stroke to the beat at all time.<\/p>\"\r\n    + \"<p>2. Win each round of Blackjack to progress.<\/p>\"\r\n    + \"<p>3. Don't cum until the end, or you lose!\",\r\n  ],\r\n  dryTease: [ \/\/ Player wants to see more after post game instructions tease.\r\n    \"Sorry, that's all until you play!\",\r\n    \"You need to play to see more!\",\r\n    \"Play if you want more!\",\r\n    \"Well, let's play then!\",\r\n    \"Then why don't you play?\"\r\n  ],\r\n  playStart: [\r\n    \"Okay, get ready to stroke!\"\r\n  ],\r\n  \/\/ Message at the start of each new round (not just level)\r\n  \/\/ (each time a player wins a hand, it's a new \"round\".)\r\n  \/\/ (after x rounds, it's a new level )\r\n  dealerRoundIntros: { \r\n    \/\/ No round intros\r\n  },\r\n  bj_p: [ \/\/ Player got blackjack\r\n    \/\/ Wrap in playerBlackjackOpen\/playerBlackjackClose\r\n    \/\/  to make response more noticable as a positive\r\n    \"You got blackjack!  You earn another rest!\".style(game.playerBJStyle, game.playerBJClass),\r\n    \"Blackjack! Another rest point!\".style(game.playerBJStyle, game.playerBJClass),\r\n    \"Yay! blackjack! Have another rest point!\".style(game.playerBJStyle, game.playerBJClass),\r\n  ],\r\n  bj_d: [ \/\/ Dealer got blackjack\r\n    \/\/ Wrap in dealerBlackjackOpen\/dealerBlackjackClose\r\n    \/\/  to make response more noticable as a negative\r\n    \"Blackjack! I win!\".style(game.dealerBJStyle, game.dealerBJClass),\r\n    \"I got blackjack!\".style(game.dealerBJStyle, game.dealerBJClass),\r\n    \"Yay! I win with blackjack!\".style(game.dealerBJStyle, game.dealerBJClass),\r\n  ],\r\n  bust_p: [ \/\/ Player busted\r\n    \"Aw, you busted!\",\r\n    \"Ha, you went bust!\",\r\n    \"Sorry, that's a bust.\",\r\n    \"You went bust!\",\r\n    \"You busted, I win!\",\r\n    \"I win, you busted!\",\r\n  ],\r\n  bust_d: [ \/\/ Dealer busted\r\n    \"Shoot! I busted.\",\r\n    \"Damn! I lost this round!\",\r\n    \"Dangit! Look at my bust!\",\r\n    \"Like my bust?  You win.\",\r\n    \"You like my bust?\",\r\n  ],\r\n  win_p: [ \/\/Player wins\r\n    \"You win with [ppoints]!\",\r\n    \"[ppoints] beats my [dpoints]!\",\r\n    \"Shoot! Your [ppoints] wins!\",\r\n    \"You win, this time!\",\r\n    \"[ppoints] wins over my [dpoints].\",\r\n    \"Great! [ppoints] wins!\",\r\n    \"You win [ppoints] to [dpoints].\",\r\n  ],\r\n  win_d: [ \/\/Dealer wins\r\n    \"I win with [dpoints]!\",\r\n    \"[dpoints] beats your [ppoints]!\",\r\n    \"Yay! My [dpoints] wins!\",\r\n    \"I win this round!\",\r\n    \"Ha! I win with [dpoints].\",\r\n    \"[dpoints] wins over your [ppoints].\",\r\n    \"My [dpoints] wins!\",\r\n    \"I win [dpoints] to [ppoints].\",\r\n  ],\r\n  tie: [ \/\/Round is a tie\r\n    \"It's a tie!  Let's try that again.\",\r\n    \"Tie! One more time...\",\r\n    \"We got same thing! Lets do it again.\",\r\n    \"Look! We match! Do over...\",\r\n  ],\r\n  hitTimeout: [ \/\/Took too long to hit\/stand\r\n    \"I don't have all day!\",\r\n    \"Shouldn't take you that long to decide!\",\r\n    \"Hit or Stand.  It's really not that hard, is it?\",\r\n    \"Sorry, tired of waiting...\",\r\n  ],\r\n  cumRoundMessage: [ \/\/ Ask for cum\r\n    \"Mmmmm... I want your cum!\",\r\n    \/\/ \"I can't wait for all that cum!\",\r\n    \"Please cum for me!\",\r\n    \"CUM NOW!\",\r\n    \"Come on, give me all of it!\",\r\n    \/\/ \"I NEED YOUR CUM!\",\r\n    \/\/ \"Cum all over me!\",\r\n    \/\/ \"I want your CUM!\",\r\n    \"CUM!\",\r\n    \"I want all of your cum!\",\r\n    \/\/ \"I want your cum all over me!\",\r\n    \"Cum for me now!\",\r\n    \"Yes! Cum for me!\",\r\n    \"Give me all of it!\",\r\n    \"Cum for me!\",\r\n    \"Please give me all your cum!\",\r\n    \"Mmmmmm... please give me your cum!\",\r\n  ],\r\n  edge: [ \/\/ Tell player to edge\r\n    \"Get right to the edge, but don't cum!\",\r\n    \"Go on, edge for me!\",\r\n    \"Get as close as you can!\",\r\n    \"Keep stroking until you edge!\",\r\n    \"Get right to the edge for me.  Don't go over!\",\r\n    \"Stroke until you almost explode, but don't!\",\r\n    \"Do what you need to do to reach that edge!\",\r\n  ],\r\n  edgeRide: [ \/\/ Tell player to ride edge\r\n    \"Now ride that edge...[playMoan|moan]\",\r\n    \"Now stay on the edge![playMoan|moan]\",\r\n    \"Keep that edge, but don't lose control![playMoan|moan]\",\r\n    \"Keep edging![playMoan|moan]\",\r\n    \"Mmmmm.  Now ride it![playMoan|moan]\",\r\n    \"Don't lose that edge![playMoan|moan]\",\r\n  ],\r\n  edgeRideCont: [ \/\/ Ecourage player to continue edging\r\n    \"That's it, keep on riding.[playMoan|moan]\",\r\n    \"Just like that... Mmmmm...[playMoan|moan]\",\r\n    \"Stay as close as you can for me...[playMoan|moan]\",\r\n    \"Don't stop riding that edge...[playMoan|moan]\",\r\n    \"Yes, just like that...[playMoan|moan]\",\r\n    \"Keep going...[playMoan|moan]\",\r\n\/\/    \"MMmmmm... I love taste of precum...\",\r\n\/\/    \"That's it, let that precum flow...\",\r\n    \"Get even closer for me...[playMoan|moan]\",\r\n  ],\r\n  strokeTime: [ \/\/ Tell player to stroke\r\n    \"Stroke [faps] times for me!\",\r\n    \"Stroke it [faps] times in [time] seconds!\",\r\n    \"I want [faps] full strokes!\",\r\n    \"Give me [faps] strokes!\",\r\n  ],\r\n  \/\/ analPrep: [ \/\/ Tell player to get ready for anal play\r\n  \/\/   \"Get ready to play with your hole!\",\r\n  \/\/   \"Get your hole ready!\",\r\n  \/\/   \"Put a finger on your ass and be ready!\",\r\n  \/\/   \"Be ready to play with your ass!\",\r\n  \/\/   \"Is your hole ready to play?\",\r\n  \/\/   \"Get ready for anal play!\",\r\n  \/\/ ],\r\n  \/\/ strokeAnalTime: [ \/\/ Tell player to stroke with anal play\r\n  \/\/   \"Slide a finger tip and out while giving me [faps] faps!\",\r\n  \/\/   \"Shove your finger up there while stroking [faps] times!\",\r\n  \/\/   \"Stroke [faps] times while messaging your back door!\",\r\n  \/\/   \"I want [faps] full strokes while wriggling in deep!\",\r\n  \/\/   \"I want [faps] full strokes while fingering your fun-hole!\",\r\n  \/\/   \"Give me [faps] strokes while tapping your bung to the beat!\",\r\n  \/\/ ],\r\n  eatPrecum: [ \/\/ Tell player to eat precum\r\n    \"Milk out that delicious precum and eat it up!\",\r\n    \"Eat every drop of that oozing precum.  Yum!\",\r\n    \"Time for a treat! Slurp up your precum!\",\r\n    \"Dip a finger in your precum and lick it clean! Mmmmm!\",\r\n    \"Gather all that sweet precum and slurp it down!\",\r\n    \"Eat your precum for me?  I'm so jealous!\",\r\n  ],\r\n  eatPrecumTimeout: [ \/\/ Took too long to eat precum\r\n    \"Sorry, you need to gobble it up quickly!\",\r\n    \"I know you want to savor it, but I'm in a hurry!\",\r\n    \"Shouldn't take all day to eat it!\",\r\n    \"Next time, slurp it up fast!\",\r\n    \"You need to eat fast if you want your reward!\",\r\n  ],\r\n  eatPrecumFail: [ \/\/ Couldn't eat precum\r\n    \"Aw.  Maybe next time?\",\r\n    \"Don't worry, you'll another chance!\",\r\n    \"I'm sure you can make more for next time!\",\r\n    \"I know, sometimes the moment just isn't right.\",\r\n  ],\r\n  eatPrecumDone: [ \/\/ Congratulate player for precum\r\n    \"Yay!  You earn a rest point!\",\r\n    \"Mmmm!  Have another rest point!\",\r\n    \"Good job!  Have another rest point!\",\r\n    \"That sweet stuff earned you a rest point!\",\r\n    \"Yay! Precum power-up! Another rest point for you!\",\r\n  ],\r\n  strokeDone: [ \/\/ Player (should have) finished stroking\r\n    \"Wow! You must practice every day!\",\r\n    \"Not that hard, right?\",\r\n    \"Great stroking!\",\r\n    \"Perfect strokes!\",\r\n    \"Hey, you're good at that!\",\r\n  ],\r\n  cbt: [ \/\/ Tell player to stroke\r\n    \"Slap your balls [faps] times!\",\r\n    \"Slap your shaft [faps] times, hard!\",\r\n    \"Give me [faps] hard ball-slaps!\",\r\n    \"Flick the head of your cock [faps] times!\",\r\n    \"Pinch the tip of your cock [faps] times, hard!\",\r\n    \"Flick your balls [faps] times!\",\r\n\/\/    \"Squeeze your balls [faps] times!\",\r\n    \"Squeeze your shaft [faps] times, hard!\",\r\n  ],\r\n  loseRest: [ \/\/ Tell player they lost a rest\r\n    \"Aw, sorry.  You lose a rest.\",\r\n    \"I'll take one rest point, thanks!\",\r\n    \"That cost you one rest point!\",\r\n    \"Sorry, you lost a rest.\",\r\n  ],\r\n  restStart: [ \/\/ We're starting a rest\r\n    \"Okay, time for a little rest.\",\r\n    \"Alright, a short break...\",\r\n    \"Hands off your thing while you take a break!\",\r\n    \"How about a little break?\",\r\n    \"Okay, stop stroking...\",\r\n  ],\r\n  restBreatheIn: [ \/\/ Tell player to breathe in\r\n    \"Breathe in...\",\r\n    \"A deep breath in...\",\r\n    \"And breathe in...\",\r\n    \"Now breathe in...\",\r\n    \"Take a breath in...\",\r\n  ],\r\n  restBreatheOut: [ \/\/ Tell player to breathe out\r\n    \"...and now out.\",\r\n    \"...now out.\",\r\n    \"...and out.\",\r\n    \"...now let it out.\",\r\n  ],\r\n  backToGame: [ \/\/ We're returning to the game after penalty\/rest\/etc.\r\n    \"Now back to the game!\",\r\n    \"Let's get back at it!\",\r\n    \"Time to play!\",\r\n    \"Now let's play!\",\r\n  ],\r\n  gameWon1: [ \r\n    \"Yay!  You won!\",\r\n  ],\r\n  gameWon2: [ \r\n    \"Please come back and play again!\",\r\n  ],\r\n  gameOver1: [\r\n    \"Oh no!  You lost!\",\r\n  ],\r\n  gameOver2: [ \r\n    \"Hope to see you back soon!\",\r\n  ],\r\n  gameLostCheckPrompt: [ \r\n    \"Uh oh!  Can you hold it back?[playMoan|moan]\",\r\n  ],\r\n  gameLostCheckPromptCumAnyTime: [ \r\n    \"Will you try to hold it back?\",\r\n  ],\r\n  cumRound1: [ \/\/ Player has made it to cum round.  First message.\r\n    \"Wow!  You've made it to the cum round!\",\r\n  ],\r\n  cumRound2: [ \/\/ Player has made it to cum round.  Second message.\r\n    \"Cum whenever you like!  You'll win in any case!\",\r\n  ],\r\n  cumRound3: [ \/\/ Player has made it to cum round.  Third message.\r\n  ],\r\n  cumRoundSelect1: [\r\n    \"You're almost there!\"\r\n  ],\r\n  cumRoundSelect2: [\r\n    \"What would you like for your final round?\"\r\n  ],\r\n  cumRoundAutoSelect: [\r\n    \"Yay, [getCumRoundModeTitle]!\",\r\n    \"Looks like you get [getCumRoundModeTitle].\",\r\n  ],\r\n  cumRoundMustWin1: [ \/\/ Player has made it to a must-win cum round.  First message.\r\n    \"Wow!  You've made it to the final round!\",\r\n  ],\r\n  cumRoundMustWin2: [ \/\/ Player has made it to a must-win cum round.  Second message.\r\n    \"Win [cumRoundsToWin] hands before time is up and I may just let you cum.\",\r\n  ],\r\n  cumRoundMustWin3: [ \/\/ Player has made it to a must-win cum round.  Third message.\r\n    \"But first, you need to get to the edge.\",\r\n  ],\r\n  cumRoundWinTease: [ \/\/ If no other message to display, display this durring cum round.\r\n    \"That's it, keep on riding.\",\r\n    \"Ride that edge... Mmmmm...\",\r\n    \"Stay as close as you can for me...\",\r\n    \"Don't stop riding that edge...\",\r\n    \"Don't lose that edge...\",\r\n    \"I want to see your legs shaking... keep edging!\",\r\n    \"Keep riding...\",\r\n    \"Get even closer for me...\",\r\n    \"Only [getWinsNeeded] more hands to win! Keep edging...\",\r\n    \"Hurry, only [getFormattedWinTimeRemaining] left! Hold that edge...\",\r\n  ],\r\n  winToCumTimout: [ \/\/ Player didn't win enough rounds in time\r\n    \"Sorry, you didn't win enough hands in time!\",\r\n    \"Aw, time's up! No cumming this game!\",\r\n    \"So close, right?  Sorry, time's up.\",\r\n    \"Almost! But your time is up.\",\r\n    \"Aw, and I could almost taste it...\",\r\n  ],\r\n  winToCumStandFail: [ \/\/ Player chose to stand below threshold.\r\n    \"You're not even trying.  You lose [winToCumPenalty] seconds for standing below [winToCumThreshold].\",\r\n  ],\r\n  cumToWinStartPrompt: [\r\n    \"Hurry!  You have [getFormattedCumTimeRemaining] to cum!\",\r\n    \"You have only [getFormattedCumTimeRemaining] to cum!  Stroke!\",\r\n  ],\r\n  cumToWinTimeoutMessage1: [  \/\/ Time ran out for the player to cum message #1\r\n    \"Sorry, time's up!  Hands off your thing!\",\r\n    \"That's all the time I could give you. Stop stroking!\",\r\n    \"Stop! Time's up!\",\r\n  ],\r\n  cumToWinTimeoutMessage2: [  \/\/ Time ran out for the player to cum message #2\r\n    \"Did you cum?\",\r\n    \"Were you able to cum?\",\r\n    \"You came, didn't you?\",\r\n  ],\r\n  gameModeSelect1: [\r\n  ],\r\n  gameModeSelect2: [\r\n    \"How would you like to play?\"\r\n  ],\r\n  gameModeAutoSelect: [\r\n    \"Hope you like [getGameModeTitle]!\",\r\n    \"You get [getGameModeTitle].  Enjoy!\",\r\n  ],\r\n  difficultySelect1: [\r\n  ],\r\n  difficultySelect2: [\r\n    \"How long do you want to play?\"\r\n  ],\r\n  difficultyAutoSelect: [\r\n    \"Hope you like [getDifficultyTitle]!\",\r\n    \"You get [getDifficultyTitle].  Enjoy!\",\r\n  ],\r\n  \/\/ SETTINGS verbiage:\r\n  settingInRoundFappingEnabled: [\r\n    \"You've <u>enabled<\/u> in-round fapping.  You'll have \" +\r\n    \"[getRoundTimeInSeconds] seconds to HIT or STAND, while \" + \r\n    \"stroking to the beat.\"\r\n  ],\r\n  settingInRoundFappingDisabled: [\r\n    \"You've <u>disabled<\/u> in-round fapping.  You'll have [getRoundTimeInSeconds] \" +\r\n    \"seconds to HIT or STAND, with no stroking.\"\r\n  ],\r\n  settingStrokePenaltyLimitEnabled: [\r\n    \"You've <u>enabled<\/u> stroke penalty limits.  You will only have stroke penalties in round 1.x and cum rounds.\"\r\n  ],\r\n  settingStrokePenaltyLimitDisabled: [\r\n    \"You've <u>disabled<\/u> stroke penalty limits.  You will have stroke penalties in all rounds.\"\r\n  ],\r\n  settingLoseRestEnabled: [\r\n    \"You've <u>enabled<\/u> Lose Rest. \" +\r\n   \"You may lose rest points if you lose a hand.\"\r\n  ],\r\n  settingLoseRestDisabled: [\r\n    \"You've <u>disabled<\/u> Lose Rest. \" +\r\n   \"You will not lose rest points if you lose a hand.\"\r\n  ],\r\n  settingAutoCumRoundEnabled: [\r\n    \"You've <u>enabled<\/u> Auto cum-round.  \" +\r\n   \"Cum round will auto-advance every [cumRoundFapTime]\" +\r\n    \" seconds, showing a new image to fap to until the end is reached.\"\r\n  ],\r\n  settingAutoCumRoundDisabled: [\r\n    \"You've <u>disabled<\/u> Auto cum-round.  \" +\r\n   \"You must win each hand in the cum round to advance to the next image.\"\r\n  ],\r\n  settingKinksPrecumEnabled: [\r\n    \"You've <u>enabled<\/u> Precum Eating Intructions.  \" + \r\n    \"You may be told to eat your precum.\"\r\n  ],\r\n  settingKinksPrecumDisabled: [\r\n    \"You've <u>disabled<\/u> Precum Eating Intructions.  \" + \r\n    \"You will not be told to eat your precum.\"\r\n  ],\r\n  settingKinksCBTEnabled: [\r\n    \"You've <u>enabled<\/u> Cock & Ball Torture.  \" + \r\n    \"You may be told to flick\/slap\/squeeze your cock or balls.\"\r\n  ],\r\n  settingKinksCBTDisabled: [\r\n    \"You've <u>disabled<\/u> Cock & Ball Torture.  \" + \r\n    \"You will not be told to flick\/slap\/squeeze your cock or balls.\"\r\n  ],\r\n  settingKinksAnalEnabled: [\r\n    \"You've <u>enabled<\/u> anal play.  \" + \r\n    \"You may be told to finger your ass while stroking your cock.<\/p>\" + \r\n    \"<p><i><b>Get your hole lubed and ready!<b><\/i>\"\r\n  ],\r\n  settingKinksAnalDisabled: [\r\n    \"You've <u>disabled<\/u> anal play.  You will not be told to finger your ass.\"\r\n  ],\r\n  \r\n  \/\/ *** New since 1.13 ***\r\n\r\n  settingLossPenaltyLabel: [\r\n    \"Loss Penalty\"\r\n  ],\r\n  settingLossPenaltyIcon: [\r\n    \"\ud83e\udd7a\"\r\n  ],\r\n  settingLossPenaltyPrompt: [\r\n    \"If you lose the final round or cum before winning, what should happen?\"\r\n  ],\r\n\r\n  settingLossPenaltyRuinLabel: [\r\n    \"Ruin\"\r\n  ],\r\n  settingLossPenaltyRuinSelect: [\r\n    \"You've selected <u>[label]<\/u>.\".p() + \r\n    \"You must ruin your orgasim if you lose the final round or cum before winning.\" \r\n  ],\r\n\r\n  settingLossPenaltyDenyLabel: [\r\n    \"Deny\"\r\n  ],\r\n  settingLossPenaltyDenySelect: [\r\n    \"You've selected <u>[label]<\/u>.\".p() + \r\n    \"You will not be allowed to cum if you lose the final round.\".br()\r\n    +\"You must ruin your orgasm if you cum before winning.\"\r\n  ],\r\n\r\n  settingLossPenaltyCeiLabel: [\r\n    \"Eat it\"\r\n  ],\r\n  settingLossPenaltyCeiSelect: [\r\n    \"You've selected <u>[label]<\/u>.\".p() + \r\n    \"You must eat your load in the way instructed if you lose the final round or cum before winning.\" \r\n  ],\r\n\r\n  settingLossPenaltyRandLabel: [\r\n    \"Random\"\r\n  ],\r\n  settingLossPenaltyRandSelect: [\r\n    \"You've selected <u>[label]<\/u>.\".p() + \r\n    \"Your penalty for losing will be randomly selected.[noRandomCieExt]\" \r\n  ],\r\n  noRandomCieExt: [\r\n    \"\".br() + \"(You must select a CEI Kink for \" + \"Eat It\".bold() + \" to be selected.)\" \r\n  ],\r\n  lossPenaltyRandomPrompt: [\r\n    \"Selecting loser penalty...\",\r\n    \"You lose.  Choosing your penalty...\",\r\n  ],\r\n\r\n  \/\/ *** New since 1.14.0 ***\r\n  \r\n  cumTease1: [\r\n    \/\/ \"Get ready to blow your load!\",\r\n  ],\r\n\r\n  cumTease2: [\r\n    \"Get ready to blow your load!\",\r\n    \"It's almost time to cum!  Get ready!\",\r\n  ],\r\n\r\n  settingKinksAnalPrompt: [\r\n    \"Select the toys you'll use for anal play.\",\r\n  ],\r\n\r\n  settingKinksAnalToyEnable: [\r\n    \"You've \" + \"enabled\".underline() + \" [name] for anal play.\".br()\r\n    + \"Make sure it's ready to shove up your ass at a moment's notice.\",\r\n  ],\r\n  settingKinksAnalToyDisable: [\r\n    \"You've \" + \"disabled\".underline() + \" [name] for anal play.\".br()\r\n    + \"You won't be asked to stick it in your hole.\",\r\n  ],\r\n\r\n  analPlugStart: [ \/\/ Tell player to insert their plug toy\r\n    \"Insert your [toyNameLower]!\",\r\n    \"Time to use your [toyNameLower]!\",\r\n    \"Lube up your [toyNameLower] and slide it in!\",\r\n  ],\r\n\r\n  analPlugStartPass: [ \/\/ Tell player to insert their plug toy\r\n    \"Great! Now leave it in while stroking![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n    \"Perfect! Hold it tight while stroking![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n  ],\r\n\r\n  analPlugEnd: [ \/\/ Tell player to pull their plug toy\r\n    \"Remove your [toyNameLower]![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n    \"Pull your [toyNameLower] out![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n  ],\r\n\r\n  analPlugEndPass: [ \/\/ Player pulled thier plug toy\r\n    \"Let your hole relax while stroking!\",\r\n    \"Now back to simple stroking!\",\r\n  ],\r\n\r\n  analDildoStart: [ \/\/ Tell player to insert their dildo toy\r\n    \"Put your [toyNameLower] in your hole!\",\r\n    \"Insert your [toyNameLower]!\",\r\n    \"Lube up your [toyNameLower] and slide it in!\",\r\n  ],\r\n\r\n  analDildoStartPass: [ \/\/ Tell player to insert their dildo toy\r\n    \"That's it... Fuck yourself to the beat![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n    \"Now every time your hear the beat, fuck your hole![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n  ],\r\n\r\n  analDildoEnd: [ \/\/ Tell player to pull their dildo toy\r\n    \"Pull out your [toyNameLower]![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n    \"Pull your [toyNameLower] out![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n  ],\r\n\r\n  analDildoEndPass: [ \/\/ Player pulled thier dildo toy\r\n    \"Let your hole relax while you stroke!\",\r\n    \"Now back to simple stroking!\",\r\n  ],\r\n\r\n  analToyFail: [ \/\/ Player wouldn't use thier toy\r\n    \"Then don't tell me you have a [toyNameLower] to use next time![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n    \"Why did tease me with your [toyNameLower] then?[setPattern|+AF][setRoundBpmDivisor|1]\",\r\n  ],\r\n\r\n  strokePlusAnal: [\r\n    \"Fuck your hole with every 4th beat while you stroke![setPattern|+AF+AF+AF+BF]\",    \r\n    \"Fuck yourself with every 3rd beat while stroking![setPattern|+AF+AF+BF]\",     \r\n    \"Fuck then stroke on every other beat![setPattern|+AF+BF]\",  \r\n    \"Stroke on every beat, but use your [toyNameLower] on every 3rd!\"\r\n    +\"[setPattern|+AF+AF+BF]\",\r\n    \"Stroke to the beat while plunging your [toyNameLower] as deep as you can!\"\r\n    +\"[setPattern|+AF+AF+AF+AF+BF]\",\r\n  ],\r\n\r\n  strokePlusAnalDone: [\r\n    \"Now continue fucking yourself to the beat![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n    \"Keep fucking yourself while we play![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n  ],\r\n\r\n  justAnal: [\r\n    \"Fuck your hole [faps] times to beat![setPattern|+BF]\",    \r\n    \"Push your [toyNameLower] in and out on every beat![setPattern|+BF]\",\r\n    \"Push your [toyNameLower] in on every beat, until it's as deep as you can take it![setPattern|+BF]\",\r\n  ],\r\n\r\n  justAnalDone: [\r\n    \"Great! Now continue fucking yourself to the beat![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n    \"Well done! Keep fucking yourself while we play![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n  ],\r\n\r\n  edgeAnal: [ \/\/ Tell player to edge with anal\r\n    \"Get right to the edge while teasing your ass, but don't cum!\",\r\n    \"Go on, fuck your hole and edge for me!\",\r\n    \"Get as close as you can!\",\r\n    \"Keep stroking and fucking until you edge!\",\r\n    \"Get right to the edge for me.  Don't go over!\",\r\n    \"Stroke until you almost explode, but don't!\",\r\n    \"Do what you need to do to reach that edge!\",\r\n  ],\r\n  edgeAnalRide: [ \/\/ Tell player to ride edge with anal\r\n    \"Now ride that edge...[playMoan|moan]\",\r\n    \"Now stay on the edge![playMoan|moan]\",\r\n    \"Keep that edge, but don't lose control![playMoan|moan]\",\r\n    \"Keep edging![playMoan|moan]\",\r\n    \"Mmmmm.  Now ride it![playMoan|moan]\",\r\n    \"Don't lose that edge![playMoan|moan]\",\r\n  ],\r\n  edgeAnalRideCont: [ \/\/ Ecourage player to continue edging with anal\r\n    \"That's it, keep on riding.[playMoan|moan]\",\r\n    \"Just like that... Mmmmm...[playMoan|moan]\",\r\n    \"Stay as close as you can for me...[playMoan|moan]\",\r\n    \"Don't stop riding that edge...[playMoan|moan]\",\r\n    \"Yes, just like that...[playMoan|moan]\",\r\n    \"Keep going...[playMoan|moan]\",\r\n\/\/    \"MMmmmm... I love taste of precum...\",\r\n\/\/    \"That's it, let that precum flow...\",\r\n    \"Get even closer for me...[playMoan|moan]\",\r\n  ],\r\n\r\n});\r\n"}},{"eval":{"script":"\/\/ Override button verbiage\r\n"}},{"eval":{"script":"\/\/ Load default verbiage overrides for all \"Cum\" rounds\r\nif (game.isCumRound()) {\r\n  game.setVerbiage({\r\n    \/\/  Nothing really different for cum rounds.\r\n    \/\/  Just here as a place holder in-case there is something\r\n    \/\/  you want to override.\r\n  });\r\n}"}},{"eval":{"script":"\/\/ Load default verbiage overrides for all \"Win to Cum\" rounds\r\nif (game.isWinToCumRound()) {\r\n  game.setVerbiage({\r\n    bj_p: [ \/\/ Don't talk about earning rest points if winToCum\r\n      \/\/ \"You got blackjack!  You earn another rest!\",\r\n      \/\/ \"Blackjack! Another rest point!\",\r\n      \/\/ \"Yay! blackjack! Have another rest point!\",\r\n      \"You got blackjack!\",\r\n      \"Blackjack! You win this hand!\",\r\n      \"Yay! blackjack! Way to go!\"\r\n    ]\r\n  });\r\n}"}},{"eval":{"script":"returnToCaller();"}}],"melody-verbiage-1":[{"eval":{"script":"\/\/ Ser verbiage overrides for given level\r\ngame.setVerbiage({\r\n  dealerRoundIntros: { \r\n    1: [\r\n      \"Start stroking!  I'll go a little easy on you, for now.\",\r\n      \"Start stroking!  Don't cum unless I say.\",\r\n      \"Stroke!  Don't worry, I'm easy.\",\r\n    ],\r\n    8: [\r\n      \"Wow, I think I'm going to need to mix things up a bit.\",\r\n    ],\r\n    15: [\r\n      \"There's no way you'll get to the next level!\",\r\n    ]\r\n  },\r\n});\r\n"}},{"eval":{"script":"returnToCaller();"}}],"melody-verbiage-3":[{"eval":{"script":"\/\/ Set verbiage overrides for given level\r\ngame.setVerbiage({\r\n  \/\/ We don't have any verbiage to override.\r\n  \/\/ We actualy don't even have to add this page (melody-verbiage-3) at all\r\n  \/\/ It's just here to illustrate how to override verbiage for multiple \r\n  \/\/ levels\r\n});\r\n"}},{"eval":{"script":"returnToCaller();"}}],"melody-verbiage-hardcore":[{"eval":{"script":"\/\/ Override verbiage for given cum round\r\ngame.setVerbiage({\r\n  \/\/ We don't really have anything to override here,\r\n  \/\/ so we don't even need this page.   It's just here to demonstrate how \r\n  \/\/ if you want to use it.\r\n});\r\n"}},{"eval":{"script":"returnToCaller();"}}],"melody2-inter-1-3":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005363"}},{"say":{"label":"<p>How about an intermission...<\/p>","mode":"pause"}},{"eval":{"script":"returnToCaller();"}}],"game-difficulty-select":[{"eval":{"script":"if (DEBUG) console.log('Selecting game difficulty:', gds)\r\nvar sOpts = _selectableOptions(gds)\r\nif (sOpts.length < 2) {\r\n  if (sOpts.length < 1) {\r\n    \/\/ No modes defined\r\n    console.error('No selectable difficulties defined.')\r\n  } else {\r\n    \/\/ We only have one mode.  Use it  \r\n    if (DEBUG) console.warn('Auto-selecting game difficulty:', sOpts[0])\r\n    game.setPlayerDifficulty(sOpts[0].id);\r\n    \/\/ And get out\r\n    returnToCaller();\r\n  }\r\n}"}},{"eval":{"script":"loadImagePage(pages.getCurrentPageId() + '-image')"}},{"eval":{"script":"var message1 = game.text('difficultySelect1');\r\nvar message2 = game.text('difficultySelect2');\r\n"}},{"if":{"condition":"message1","commands":[{"say":{"label":"<p><eval>message1<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"message2","commands":[{"say":{"label":"<p><eval>message2<\/eval><\/p>","mode":"instant"}}]}},{"if":{"condition":"game.difficultyAutoSelectTime","commands":[{"notification.create":{"buttonCommands":[{"eval":{"script":"roulette.useDifficultySelector();\r\npages.goto('penalty-roulette');"}}],"buttonLabel":"Random \ud83c\udfb2","id":"random-select","timerCommands":[{"eval":{"script":"roulette.useDifficultySelector();\r\npages.goto('penalty-roulette');"}}],"timerDuration":"$game.difficultyAutoSelectTime * 1000"}}],"elseCommands":[{"notification.create":{"buttonCommands":[{"eval":{"script":"roulette.useDifficultySelector();\r\npages.goto('penalty-roulette');"}}],"buttonLabel":"Random \ud83c\udfb2","id":"random-select"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options3 *\/"}},{"choice":{"options":[{"label":"<eval>_gdst(0)<\/eval>","commands":[{"eval":{"script":"game.setPlayerDifficulty(gds[0].id)"}}],"color":"#9c27b0","visible":"$_sgds(0)"},{"label":"<eval>_gdst(1)<\/eval>","commands":[{"eval":{"script":"game.setPlayerDifficulty(gds[1].id)"}}],"color":"#ec407a","visible":"$_sgds(1)"},{"label":"<eval>_gdst(2)<\/eval>","commands":[{"eval":{"script":"game.setPlayerDifficulty(gds[2].id)"}}],"color":"#00796b","visible":"$_sgds(2)"},{"label":"<eval>_gdst(3)<\/eval>","commands":[{"eval":{"script":"game.setPlayerDifficulty(gds[3].id)"}}],"color":"#d84315","visible":"$_sgds(3)"},{"label":"<eval>_gdst(3)<\/eval>","commands":[{"eval":{"script":"game.setPlayerDifficulty(gds[4].id)"}}],"color":"#1565c0","visible":"$_sgds(4)"},{"label":"<eval>_gdst(4)<\/eval>","commands":[{"eval":{"script":"game.setPlayerDifficulty(gds[5].id)"}}],"color":"#0288d1","visible":"$_sgds(5)"},{"label":"<eval>_gdst(5)<\/eval>","commands":[{"eval":{"script":"game.setPlayerDifficulty(gds[6].id)"}}],"color":"#6d4c41","visible":"$_sgds(6)"},{"label":"<eval>_gdst(6)<\/eval>","commands":[{"eval":{"script":"game.setPlayerDifficulty(gds[7].id)"}}],"color":"#1565c0","visible":"$_sgds(7)"},{"label":"<eval>_gdst(7)<\/eval>","commands":[{"eval":{"script":"game.setPlayerDifficulty(gds[8].id)"}}],"color":"#1565c0","visible":"$_sgds(8)"},{"label":"<eval>_gdst(9)<\/eval>","commands":[{"eval":{"script":"game.setPlayerDifficulty(gds[9].id)"}}],"color":"#1565c0","visible":"$_sgds(9)"}]}},{"notification.remove":{"id":"random-select"}},{"eval":{"script":"returnToCaller(); \/\/ Return to caller"}}],"game-difficulty-select-image":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005366"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-penalty-ride":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005455"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-penalty-stroke":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005451"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-penalty-ride-rest":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005457"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-penalty-cei":[{"image":{"locator":"gallery:9ec8abe7-ce8e-433b-a18d-198f8af3e6a1\/*"}},{"eval":{"script":"returnToCaller();"}}],"melody-image-penalty-cei-pass":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005391"}},{"eval":{"script":"returnToCaller();"}}],"settings-kinks":[{"eval":{"script":"\/*--auto-magpie-merge:message:reset1 *\/"}},{"eval":{"script":"var _rsm = currentPageResetMessage()"}},{"eval":{"script":"var _ss = currentPageSettings()"}},{"eval":{"script":"var _ls = currentPageLS()"}},{"if":{"condition":"game.settingMessage","commands":[{"say":{"label":"<p><eval>game.settingMessage<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.settingMessage = null"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>gsLabelOn(_ss[0])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[0])"}}],"visible":"$gsShowOn(_ss[0])"},{"label":"<eval>gsLabelOff(_ss[0])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[0])"}}],"visible":"$gsShowOff(_ss[0])"},{"label":"<eval>gsLabelOn(_ss[1])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[1])"}}],"visible":"$gsShowOn(_ss[1])"},{"label":"<eval>gsLabelOff(_ss[1])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[1])"}}],"visible":"$gsShowOff(_ss[1])"},{"label":"<eval>gsLabelOn(_ss[2])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[2])"}}],"visible":"$gsShowOn(_ss[2])"},{"label":"<eval>gsLabelOff(_ss[2])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[2])"}}],"visible":"$gsShowOff(_ss[2])"},{"label":"<eval>gsLabelOn(_ss[3])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[3])"}}],"visible":"$gsShowOn(_ss[3])"},{"label":"<eval>gsLabelOff(_ss[3])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[3])"}}],"visible":"$gsShowOff(_ss[3])"},{"label":"<eval>gsLabelOn(_ss[4])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[4])"}}],"visible":"$gsShowOn(_ss[4])"},{"label":"<eval>gsLabelOff(_ss[4])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[4])"}}],"visible":"$gsShowOff(_ss[4])"},{"label":"<eval>gsLabelOn(_ss[5])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[5])"}}],"visible":"$gsShowOn(_ss[5])"},{"label":"<eval>gsLabelOff(_ss[5])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[5])"}}],"visible":"$gsShowOff(_ss[5])"},{"label":"<eval>gsLabelOn(_ss[6])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[6])"}}],"visible":"$gsShowOn(_ss[6])"},{"label":"<eval>gsLabelOff(_ss[6])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[6])"}}],"visible":"$gsShowOff(_ss[6])"},{"label":"<eval>gsLabelOn(_ss[7])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[7])"}}],"visible":"$gsShowOn(_ss[7])"},{"label":"<eval>gsLabelOff(_ss[7])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[7])"}}],"visible":"$gsShowOff(_ss[7])"},{"label":"<eval>gsLabelOn(_ss[8])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[8])"}}],"visible":"$gsShowOn(_ss[8])"},{"label":"<eval>gsLabelOff(_ss[8])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[8])"}}],"visible":"$gsShowOff(_ss[8])"},{"label":"<eval>gsLabelOn(_ss[9])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[9])"}}],"visible":"$gsShowOn(_ss[9])"},{"label":"<eval>gsLabelOff(_ss[9])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[9])"}}],"visible":"$gsShowOff(_ss[9])"},{"label":"Reset","commands":[{"eval":{"script":"resetSettings(_ls);\ngame.settingMessage = mergeObject(_rsm, game);\npages.goto(pages.getCurrentPageId());"}}],"visible":"$hasChangedSettings(_ls)"},{"label":"Done","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}],"settings-options":[{"eval":{"script":"\/*--auto-magpie-merge:message:reset1 *\/"}},{"eval":{"script":"var _rsm = currentPageResetMessage()"}},{"eval":{"script":"var _ss = currentPageSettings()"}},{"eval":{"script":"var _ls = currentPageLS()"}},{"if":{"condition":"game.settingMessage","commands":[{"say":{"label":"<p><eval>game.settingMessage<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.settingMessage = null"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>gsLabelOn(_ss[0])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[0])"}}],"visible":"$gsShowOn(_ss[0])"},{"label":"<eval>gsLabelOff(_ss[0])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[0])"}}],"visible":"$gsShowOff(_ss[0])"},{"label":"<eval>gsLabelOn(_ss[1])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[1])"}}],"visible":"$gsShowOn(_ss[1])"},{"label":"<eval>gsLabelOff(_ss[1])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[1])"}}],"visible":"$gsShowOff(_ss[1])"},{"label":"<eval>gsLabelOn(_ss[2])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[2])"}}],"visible":"$gsShowOn(_ss[2])"},{"label":"<eval>gsLabelOff(_ss[2])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[2])"}}],"visible":"$gsShowOff(_ss[2])"},{"label":"<eval>gsLabelOn(_ss[3])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[3])"}}],"visible":"$gsShowOn(_ss[3])"},{"label":"<eval>gsLabelOff(_ss[3])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[3])"}}],"visible":"$gsShowOff(_ss[3])"},{"label":"<eval>gsLabelOn(_ss[4])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[4])"}}],"visible":"$gsShowOn(_ss[4])"},{"label":"<eval>gsLabelOff(_ss[4])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[4])"}}],"visible":"$gsShowOff(_ss[4])"},{"label":"<eval>gsLabelOn(_ss[5])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[5])"}}],"visible":"$gsShowOn(_ss[5])"},{"label":"<eval>gsLabelOff(_ss[5])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[5])"}}],"visible":"$gsShowOff(_ss[5])"},{"label":"<eval>gsLabelOn(_ss[6])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[6])"}}],"visible":"$gsShowOn(_ss[6])"},{"label":"<eval>gsLabelOff(_ss[6])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[6])"}}],"visible":"$gsShowOff(_ss[6])"},{"label":"<eval>gsLabelOn(_ss[7])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[7])"}}],"visible":"$gsShowOn(_ss[7])"},{"label":"<eval>gsLabelOff(_ss[7])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[7])"}}],"visible":"$gsShowOff(_ss[7])"},{"label":"<eval>gsLabelOn(_ss[8])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[8])"}}],"visible":"$gsShowOn(_ss[8])"},{"label":"<eval>gsLabelOff(_ss[8])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[8])"}}],"visible":"$gsShowOff(_ss[8])"},{"label":"<eval>gsLabelOn(_ss[9])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[9])"}}],"visible":"$gsShowOn(_ss[9])"},{"label":"<eval>gsLabelOff(_ss[9])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[9])"}}],"visible":"$gsShowOff(_ss[9])"},{"label":"Reset","commands":[{"eval":{"script":"resetSettings(_ls);\ngame.settingMessage = mergeObject(_rsm, game);\npages.goto(pages.getCurrentPageId());"}}],"visible":"$hasChangedSettings(_ls)"},{"label":"Done","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}],"settings":[{"eval":{"script":"\/*--auto-magpie-merge:message:reset1 *\/"}},{"eval":{"script":"var _rsm = currentPageResetMessage()"}},{"eval":{"script":"var _ss = currentPageSettings()"}},{"eval":{"script":"var _ls = currentPageLS()"}},{"if":{"condition":"game.settingMessage","commands":[{"say":{"label":"<p><eval>game.settingMessage<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.settingMessage = null"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>gsLabelOn(_ss[0])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[0])"}}],"visible":"$gsShowOn(_ss[0])"},{"label":"<eval>gsLabelOff(_ss[0])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[0])"}}],"visible":"$gsShowOff(_ss[0])"},{"label":"<eval>gsLabelOn(_ss[1])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[1])"}}],"visible":"$gsShowOn(_ss[1])"},{"label":"<eval>gsLabelOff(_ss[1])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[1])"}}],"visible":"$gsShowOff(_ss[1])"},{"label":"<eval>gsLabelOn(_ss[2])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[2])"}}],"visible":"$gsShowOn(_ss[2])"},{"label":"<eval>gsLabelOff(_ss[2])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[2])"}}],"visible":"$gsShowOff(_ss[2])"},{"label":"<eval>gsLabelOn(_ss[3])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[3])"}}],"visible":"$gsShowOn(_ss[3])"},{"label":"<eval>gsLabelOff(_ss[3])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[3])"}}],"visible":"$gsShowOff(_ss[3])"},{"label":"<eval>gsLabelOn(_ss[4])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[4])"}}],"visible":"$gsShowOn(_ss[4])"},{"label":"<eval>gsLabelOff(_ss[4])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[4])"}}],"visible":"$gsShowOff(_ss[4])"},{"label":"<eval>gsLabelOn(_ss[5])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[5])"}}],"visible":"$gsShowOn(_ss[5])"},{"label":"<eval>gsLabelOff(_ss[5])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[5])"}}],"visible":"$gsShowOff(_ss[5])"},{"label":"<eval>gsLabelOn(_ss[6])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[6])"}}],"visible":"$gsShowOn(_ss[6])"},{"label":"<eval>gsLabelOff(_ss[6])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[6])"}}],"visible":"$gsShowOff(_ss[6])"},{"label":"<eval>gsLabelOn(_ss[7])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[7])"}}],"visible":"$gsShowOn(_ss[7])"},{"label":"<eval>gsLabelOff(_ss[7])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[7])"}}],"visible":"$gsShowOff(_ss[7])"},{"label":"<eval>gsLabelOn(_ss[8])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[8])"}}],"visible":"$gsShowOn(_ss[8])"},{"label":"<eval>gsLabelOff(_ss[8])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[8])"}}],"visible":"$gsShowOff(_ss[8])"},{"label":"<eval>gsLabelOn(_ss[9])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[9])"}}],"visible":"$gsShowOn(_ss[9])"},{"label":"<eval>gsLabelOff(_ss[9])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[9])"}}],"visible":"$gsShowOff(_ss[9])"},{"label":"Reset","commands":[{"eval":{"script":"resetSettings(_ls);\ngame.settingMessage = mergeObject(_rsm, game);\npages.goto(pages.getCurrentPageId());"}}],"visible":"$hasChangedSettings(_ls)"},{"label":"Done","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}],"penalty-custom-example":[{"eval":{"script":"beats.stopAll() \/\/ Stop all beats"}},{"eval":{"script":"closeAllBut() \/\/ Close all notifications"}},{"say":{"label":"<p>This is an example &quot;custom&quot; penalty.<\/p><p>You can do anything here.<\/p>","mode":"pause"}},{"eval":{"script":"game.message = \"Okay, let's get back to it!\" \/\/ Set return to game message "}},{"eval":{"script":"returnToCaller(); \/\/ Get back to the game"}}],"settings-radio-options-example":[{"eval":{"script":"\/*--auto-magpie-merge:message:reset1 *\/"}},{"eval":{"script":"var _rsm = currentPageResetMessage()"}},{"eval":{"script":"var _ss = currentPageSettings()"}},{"eval":{"script":"var _ls = currentPageLS()"}},{"if":{"condition":"game.settingMessage","commands":[{"say":{"label":"<p><eval>game.settingMessage<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.settingMessage = null"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>gsLabelOn(_ss[0])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[0])"}}],"visible":"$gsShowOn(_ss[0])"},{"label":"<eval>gsLabelOff(_ss[0])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[0])"}}],"visible":"$gsShowOff(_ss[0])"},{"label":"<eval>gsLabelOn(_ss[1])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[1])"}}],"visible":"$gsShowOn(_ss[1])"},{"label":"<eval>gsLabelOff(_ss[1])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[1])"}}],"visible":"$gsShowOff(_ss[1])"},{"label":"<eval>gsLabelOn(_ss[2])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[2])"}}],"visible":"$gsShowOn(_ss[2])"},{"label":"<eval>gsLabelOff(_ss[2])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[2])"}}],"visible":"$gsShowOff(_ss[2])"},{"label":"<eval>gsLabelOn(_ss[3])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[3])"}}],"visible":"$gsShowOn(_ss[3])"},{"label":"<eval>gsLabelOff(_ss[3])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[3])"}}],"visible":"$gsShowOff(_ss[3])"},{"label":"<eval>gsLabelOn(_ss[4])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[4])"}}],"visible":"$gsShowOn(_ss[4])"},{"label":"<eval>gsLabelOff(_ss[4])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[4])"}}],"visible":"$gsShowOff(_ss[4])"},{"label":"<eval>gsLabelOn(_ss[5])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[5])"}}],"visible":"$gsShowOn(_ss[5])"},{"label":"<eval>gsLabelOff(_ss[5])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[5])"}}],"visible":"$gsShowOff(_ss[5])"},{"label":"<eval>gsLabelOn(_ss[6])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[6])"}}],"visible":"$gsShowOn(_ss[6])"},{"label":"<eval>gsLabelOff(_ss[6])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[6])"}}],"visible":"$gsShowOff(_ss[6])"},{"label":"<eval>gsLabelOn(_ss[7])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[7])"}}],"visible":"$gsShowOn(_ss[7])"},{"label":"<eval>gsLabelOff(_ss[7])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[7])"}}],"visible":"$gsShowOff(_ss[7])"},{"label":"<eval>gsLabelOn(_ss[8])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[8])"}}],"visible":"$gsShowOn(_ss[8])"},{"label":"<eval>gsLabelOff(_ss[8])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[8])"}}],"visible":"$gsShowOff(_ss[8])"},{"label":"<eval>gsLabelOn(_ss[9])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[9])"}}],"visible":"$gsShowOn(_ss[9])"},{"label":"<eval>gsLabelOff(_ss[9])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[9])"}}],"visible":"$gsShowOff(_ss[9])"},{"label":"Reset","commands":[{"eval":{"script":"resetSettings(_ls);\ngame.settingMessage = mergeObject(_rsm, game);\npages.goto(pages.getCurrentPageId());"}}],"visible":"$hasChangedSettings(_ls)"},{"label":"Done","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}],"melody2-interp-1-3":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005369"}},{"say":{"label":"<p>How about a post-hand intermission...<\/p>","mode":"pause"}},{"eval":{"script":"returnToCaller();"}}],"melody2-cum-round-select":[{"image":{"locator":"gallery:a6068f8e-6608-437f-aefb-a94f5ee782e9\/1087408"}},{"eval":{"script":"returnToCaller(); \/\/ Return to caller"}}],"welcome-image":[{"image":{"locator":"gallery:a6068f8e-6608-437f-aefb-a94f5ee782e9\/990458"}},{"eval":{"script":"returnToCaller()"}}],"common-ending":[{"end":{}}],"melody-cumtease-softcore":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/*"}},{"eval":{"script":"returnToCaller();"}}],"win-check2":[{"eval":{"script":"var message1 = game.text('cumToWinTimeoutMessage1');\r\nvar message2 = game.text('cumToWinTimeoutMessage2');"}},{"if":{"condition":"message1","commands":[{"say":{"label":"<p><eval>message1<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"message2","commands":[{"say":{"label":"<p><eval>message2<\/eval><\/p>","mode":"instant"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>game.text('btnCumWin')<\/eval>","commands":[{"eval":{"script":"game.doCumWin()"}}]},{"label":"<eval>game.text('btnCumLose')<\/eval>","commands":[{"eval":{"script":"game.doCumLose()"}}],"visible":"$game.cumToWinTimer"}]}}],"---READ-ME---":[{"eval":{"script":"\/\/ !!! Read ALL comments in \"Init Script\" BEFORE YOU START !!!"}}],"settings-round-timer":[{"eval":{"script":"\/*--auto-magpie-merge:message:reset1 *\/"}},{"eval":{"script":"var _rsm = currentPageResetMessage()"}},{"eval":{"script":"var _ss = currentPageSettings()"}},{"eval":{"script":"var _ls = currentPageLS()"}},{"if":{"condition":"game.settingMessage","commands":[{"say":{"label":"<p><eval>game.settingMessage<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.settingMessage = null"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>gsLabelOn(_ss[0])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[0])"}}],"visible":"$gsShowOn(_ss[0])"},{"label":"<eval>gsLabelOff(_ss[0])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[0])"}}],"visible":"$gsShowOff(_ss[0])"},{"label":"<eval>gsLabelOn(_ss[1])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[1])"}}],"visible":"$gsShowOn(_ss[1])"},{"label":"<eval>gsLabelOff(_ss[1])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[1])"}}],"visible":"$gsShowOff(_ss[1])"},{"label":"<eval>gsLabelOn(_ss[2])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[2])"}}],"visible":"$gsShowOn(_ss[2])"},{"label":"<eval>gsLabelOff(_ss[2])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[2])"}}],"visible":"$gsShowOff(_ss[2])"},{"label":"<eval>gsLabelOn(_ss[3])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[3])"}}],"visible":"$gsShowOn(_ss[3])"},{"label":"<eval>gsLabelOff(_ss[3])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[3])"}}],"visible":"$gsShowOff(_ss[3])"},{"label":"<eval>gsLabelOn(_ss[4])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[4])"}}],"visible":"$gsShowOn(_ss[4])"},{"label":"<eval>gsLabelOff(_ss[4])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[4])"}}],"visible":"$gsShowOff(_ss[4])"},{"label":"<eval>gsLabelOn(_ss[5])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[5])"}}],"visible":"$gsShowOn(_ss[5])"},{"label":"<eval>gsLabelOff(_ss[5])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[5])"}}],"visible":"$gsShowOff(_ss[5])"},{"label":"<eval>gsLabelOn(_ss[6])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[6])"}}],"visible":"$gsShowOn(_ss[6])"},{"label":"<eval>gsLabelOff(_ss[6])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[6])"}}],"visible":"$gsShowOff(_ss[6])"},{"label":"<eval>gsLabelOn(_ss[7])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[7])"}}],"visible":"$gsShowOn(_ss[7])"},{"label":"<eval>gsLabelOff(_ss[7])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[7])"}}],"visible":"$gsShowOff(_ss[7])"},{"label":"<eval>gsLabelOn(_ss[8])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[8])"}}],"visible":"$gsShowOn(_ss[8])"},{"label":"<eval>gsLabelOff(_ss[8])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[8])"}}],"visible":"$gsShowOff(_ss[8])"},{"label":"<eval>gsLabelOn(_ss[9])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[9])"}}],"visible":"$gsShowOn(_ss[9])"},{"label":"<eval>gsLabelOff(_ss[9])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[9])"}}],"visible":"$gsShowOff(_ss[9])"},{"label":"Reset","commands":[{"eval":{"script":"resetSettings(_ls);\ngame.settingMessage = mergeObject(_rsm, game);\npages.goto(pages.getCurrentPageId());"}}],"visible":"$hasChangedSettings(_ls)"},{"label":"Done","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}],"settings-sounds":[{"eval":{"script":"\/*--auto-magpie-merge:message:reset1 *\/"}},{"eval":{"script":"var _rsm = currentPageResetMessage()"}},{"eval":{"script":"var _ss = currentPageSettings()"}},{"eval":{"script":"var _ls = currentPageLS()"}},{"if":{"condition":"game.settingMessage","commands":[{"say":{"label":"<p><eval>game.settingMessage<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.settingMessage = null"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>gsLabelOn(_ss[0])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[0])"}}],"visible":"$gsShowOn(_ss[0])"},{"label":"<eval>gsLabelOff(_ss[0])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[0])"}}],"visible":"$gsShowOff(_ss[0])"},{"label":"<eval>gsLabelOn(_ss[1])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[1])"}}],"visible":"$gsShowOn(_ss[1])"},{"label":"<eval>gsLabelOff(_ss[1])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[1])"}}],"visible":"$gsShowOff(_ss[1])"},{"label":"<eval>gsLabelOn(_ss[2])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[2])"}}],"visible":"$gsShowOn(_ss[2])"},{"label":"<eval>gsLabelOff(_ss[2])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[2])"}}],"visible":"$gsShowOff(_ss[2])"},{"label":"<eval>gsLabelOn(_ss[3])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[3])"}}],"visible":"$gsShowOn(_ss[3])"},{"label":"<eval>gsLabelOff(_ss[3])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[3])"}}],"visible":"$gsShowOff(_ss[3])"},{"label":"<eval>gsLabelOn(_ss[4])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[4])"}}],"visible":"$gsShowOn(_ss[4])"},{"label":"<eval>gsLabelOff(_ss[4])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[4])"}}],"visible":"$gsShowOff(_ss[4])"},{"label":"<eval>gsLabelOn(_ss[5])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[5])"}}],"visible":"$gsShowOn(_ss[5])"},{"label":"<eval>gsLabelOff(_ss[5])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[5])"}}],"visible":"$gsShowOff(_ss[5])"},{"label":"<eval>gsLabelOn(_ss[6])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[6])"}}],"visible":"$gsShowOn(_ss[6])"},{"label":"<eval>gsLabelOff(_ss[6])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[6])"}}],"visible":"$gsShowOff(_ss[6])"},{"label":"<eval>gsLabelOn(_ss[7])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[7])"}}],"visible":"$gsShowOn(_ss[7])"},{"label":"<eval>gsLabelOff(_ss[7])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[7])"}}],"visible":"$gsShowOff(_ss[7])"},{"label":"<eval>gsLabelOn(_ss[8])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[8])"}}],"visible":"$gsShowOn(_ss[8])"},{"label":"<eval>gsLabelOff(_ss[8])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[8])"}}],"visible":"$gsShowOff(_ss[8])"},{"label":"<eval>gsLabelOn(_ss[9])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[9])"}}],"visible":"$gsShowOn(_ss[9])"},{"label":"<eval>gsLabelOff(_ss[9])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[9])"}}],"visible":"$gsShowOff(_ss[9])"},{"label":"Reset","commands":[{"eval":{"script":"resetSettings(_ls);\ngame.settingMessage = mergeObject(_rsm, game);\npages.goto(pages.getCurrentPageId());"}}],"visible":"$hasChangedSettings(_ls)"},{"label":"Done","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}],"--audio-1":[{"eval":{"script":"\/*--auto-magpie-merge:audio:loader3 *\/"}},{"if":{"condition":"true","commands":[{"audio.play":{"locator":"file:beat-pop-alt2-a.mp3","id":"beatA-1","volume":0,"background":true}},{"audio.play":{"locator":"file:beat-pop-alt2-a.mp3","id":"beatA-2","volume":0,"background":true}},{"audio.play":{"locator":"file:beat-pop-alt2-b.mp3","id":"beatB-1","volume":0,"background":true}},{"audio.play":{"locator":"file:beat-pop-alt2-b.mp3","id":"beatB-2","volume":0,"background":true}},{"eval":{"script":"game.loadBeats()"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:audio:moans1 *\/"}},{"if":{"condition":"true","commands":[{"audio.play":{"locator":"file:moan-1.mp3","background":true,"id":"moan-1","loops":1,"volume":0}},{"audio.play":{"locator":"file:moan-2.mp3","background":true,"id":"moan-2","loops":1,"volume":0}},{"audio.play":{"locator":"file:moan-3.mp3","background":true,"id":"moan-3","loops":1,"volume":0}},{"audio.play":{"locator":"file:moan-4.mp3","background":true,"id":"moan-4","loops":1,"volume":0}},{"audio.play":{"locator":"file:moan-5.mp3","background":true,"id":"moan-5","loops":1,"volume":0}},{"audio.play":{"locator":"file:moan-6.mp3","background":true,"id":"moan-6","loops":1,"volume":0}},{"eval":{"script":"\/\/ Load all moan sounds\nmoans.set('moan', 1);\nmoans.set('moan', 2);\nmoans.set('moan', 3);\nmoans.set('moan', 4);\nmoans.set('moan', 5);\nmoans.set('moan', 6);"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:audio:effects1 *\/"}},{"if":{"condition":"true","commands":[{"audio.play":{"locator":"file:click.mp3","id":"click-A","background":true,"volume":0}},{"audio.play":{"locator":"file:click.mp3","id":"click-B","background":true,"volume":0}},{"eval":{"script":"roulette.loadSounds()"}}]}},{"eval":{"script":"returnToCaller()"}}],"--audio-2":[{"eval":{"script":"\/*--auto-magpie-merge:audio:loader1 *\/"}},{"if":{"condition":"true","commands":[{"audio.play":{"locator":"file:beat-drum1.mp3","id":"beatA-1","volume":0,"background":true}},{"audio.play":{"locator":"file:beat-drum1.mp3","id":"beatA-2","volume":0,"background":true}},{"audio.play":{"locator":"file:beat-drum2.mp3","id":"beatB-2","volume":0,"background":true}},{"audio.play":{"locator":"file:beat-drum2.mp3","id":"beatB-1","volume":0,"background":true}},{"eval":{"script":"game.loadBeats()"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:audio:moans1 *\/"}},{"if":{"condition":"true","commands":[{"audio.play":{"locator":"file:moan-1.mp3","background":true,"id":"moan-1","loops":1,"volume":0}},{"audio.play":{"locator":"file:moan-2.mp3","background":true,"id":"moan-2","loops":1,"volume":0}},{"audio.play":{"locator":"file:moan-3.mp3","background":true,"id":"moan-3","loops":1,"volume":0}},{"audio.play":{"locator":"file:moan-4.mp3","background":true,"id":"moan-4","loops":1,"volume":0}},{"audio.play":{"locator":"file:moan-5.mp3","background":true,"id":"moan-5","loops":1,"volume":0}},{"audio.play":{"locator":"file:moan-6.mp3","background":true,"id":"moan-6","loops":1,"volume":0}},{"eval":{"script":"\/\/ Load all moan sounds\nmoans.set('moan', 1);\nmoans.set('moan', 2);\nmoans.set('moan', 3);\nmoans.set('moan', 4);\nmoans.set('moan', 5);\nmoans.set('moan', 6);"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:audio:effects1 *\/"}},{"if":{"condition":"true","commands":[{"audio.play":{"locator":"file:click.mp3","id":"click-A","background":true,"volume":0}},{"audio.play":{"locator":"file:click.mp3","id":"click-B","background":true,"volume":0}},{"eval":{"script":"roulette.loadSounds()"}}]}},{"eval":{"script":"returnToCaller()"}}],"settings-beat-profile":[{"eval":{"script":"\/*--auto-magpie-merge:message:reset1 *\/"}},{"eval":{"script":"var _rsm = currentPageResetMessage()"}},{"eval":{"script":"var _ss = currentPageSettings()"}},{"eval":{"script":"var _ls = currentPageLS()"}},{"if":{"condition":"game.settingMessage","commands":[{"say":{"label":"<p><eval>game.settingMessage<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.settingMessage = null"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>gsLabelOn(_ss[0])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[0])"}}],"visible":"$gsShowOn(_ss[0])"},{"label":"<eval>gsLabelOff(_ss[0])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[0])"}}],"visible":"$gsShowOff(_ss[0])"},{"label":"<eval>gsLabelOn(_ss[1])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[1])"}}],"visible":"$gsShowOn(_ss[1])"},{"label":"<eval>gsLabelOff(_ss[1])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[1])"}}],"visible":"$gsShowOff(_ss[1])"},{"label":"<eval>gsLabelOn(_ss[2])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[2])"}}],"visible":"$gsShowOn(_ss[2])"},{"label":"<eval>gsLabelOff(_ss[2])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[2])"}}],"visible":"$gsShowOff(_ss[2])"},{"label":"<eval>gsLabelOn(_ss[3])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[3])"}}],"visible":"$gsShowOn(_ss[3])"},{"label":"<eval>gsLabelOff(_ss[3])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[3])"}}],"visible":"$gsShowOff(_ss[3])"},{"label":"<eval>gsLabelOn(_ss[4])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[4])"}}],"visible":"$gsShowOn(_ss[4])"},{"label":"<eval>gsLabelOff(_ss[4])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[4])"}}],"visible":"$gsShowOff(_ss[4])"},{"label":"<eval>gsLabelOn(_ss[5])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[5])"}}],"visible":"$gsShowOn(_ss[5])"},{"label":"<eval>gsLabelOff(_ss[5])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[5])"}}],"visible":"$gsShowOff(_ss[5])"},{"label":"<eval>gsLabelOn(_ss[6])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[6])"}}],"visible":"$gsShowOn(_ss[6])"},{"label":"<eval>gsLabelOff(_ss[6])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[6])"}}],"visible":"$gsShowOff(_ss[6])"},{"label":"<eval>gsLabelOn(_ss[7])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[7])"}}],"visible":"$gsShowOn(_ss[7])"},{"label":"<eval>gsLabelOff(_ss[7])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[7])"}}],"visible":"$gsShowOff(_ss[7])"},{"label":"<eval>gsLabelOn(_ss[8])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[8])"}}],"visible":"$gsShowOn(_ss[8])"},{"label":"<eval>gsLabelOff(_ss[8])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[8])"}}],"visible":"$gsShowOff(_ss[8])"},{"label":"<eval>gsLabelOn(_ss[9])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[9])"}}],"visible":"$gsShowOn(_ss[9])"},{"label":"<eval>gsLabelOff(_ss[9])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[9])"}}],"visible":"$gsShowOff(_ss[9])"},{"label":"Reset","commands":[{"eval":{"script":"resetSettings(_ls);\ngame.settingMessage = mergeObject(_rsm, game);\npages.goto(pages.getCurrentPageId());"}}],"visible":"$hasChangedSettings(_ls)"},{"label":"Done","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}],"core-config-example":[{"eval":{"script":"\/\/ Set global values\r\nDEBUG = true; \/\/ <-- Set this false before release!!!\r\nS_ON = '\u2705'; \/\/ HTML for a setting \"on\" button \r\nS_OFF = '\u2b1c'; \/\/ HTML for a setting \"off\" button\r\nR_ON = '\ud83d\udd35'; \/\/ HTML for a radio \"on\" button \r\nR_OFF = '\u26aa'; \/\/ HTML for a radio \"off\" button"}},{"eval":{"script":"\/\/ Add custom player modifiable \"option\" settings\r\ngame.setSettingOption(\r\n  \/\/ Setting name is '$testPenalty' (custom settings must start with '$')\r\n  '$testPenalty', \r\n  \/\/ Setting definition:\r\n  {\r\n    type: storageTypes.GAME, \/\/ Use this, unless you've created your own\r\n    label: 'Custom Penalty', \/\/ What to display in menu\r\n    textKey: 'CustomPenalty', \/\/ looks for verbiage keys: \r\n    \/\/                      'settingCustomPenaltyEnable' &&\r\n    \/\/                      'settingCustomPenaltyDisable'\r\n    \/\/                       If not found, a simple default is used.\r\n    page: 'settings-options', \/\/ Where to display the selection\r\n    key: '$oTP', \/\/ short key for storage\r\n    defaultValue: false, \/\/ Default value\r\n  },\r\n  \/\/ Display as second item in settings-options page\r\n  \/\/ 0 = 1st, 1 = 2nd, 2 = 3rd, etc.\r\n  1\r\n)\r\n\/\/ NOTE: Remember to add $testPenalty: true, to the showSetting: {...} area\r\n\/\/       in your game.setConfig(...) eval\r\n\r\n\/\/ Add custom player modifiable \"kink\" settings\r\ngame.setSettingOption(\r\n  \/\/ Setting name is '$kinkCEI' (custom settings must start with '$')\r\n  '$kinkCEI', \r\n  \/\/ Setting definition:\r\n  {\r\n    type: storageTypes.GAME, \/\/ Use this, unless you've created your own\r\n    label: 'CEI', \/\/ What to display in menu\r\n    icon: '\ud83c\udf4c', \/\/ Set an icon\r\n    textKey: 'KinksCEI', \/\/ looks for verbiage keys: \r\n    \/\/                      'settingKinksCEIEnable' &&\r\n    \/\/                      'settingKinksCEIDisable'\r\n    page: 'settings-kinks', \/\/ Where to display the selection\r\n    key: '$kCE', \/\/ short key for storage\r\n    defaultValue: false, \/\/ Default value\r\n    show: function() {\r\n      \/\/ Only show if game is unlocked\r\n      return game.isUnlocked()\r\n    }\r\n  },\r\n  \/\/ Display before 'kinkCbt' setting\r\n  'kinkCbt'\r\n)\r\n\/\/ NOTE: Remember to add $kinkCEI: true, to the showSetting: {...} area\r\n\/\/       in your game.setConfig(...) eval\r\n\r\n\/\/ If you wanted to add another another settings page:\r\n\/\/ 1. Copy settings-options page, and name it settings-myoptions\r\n\/\/    (replace \"myoptions\" with what you really want.)\r\n\/\/    NOTE: Settings pages MUST start with 'settings-'\r\n\/\/\r\n\/\/ 2. Add a setting option link for it, like:\r\n\/*\r\ngame.setSettingOption(\r\n  \/\/ New setting menu link option\r\n  '$myOptions', \r\n  \/\/ Setting definition:\r\n  {\r\n    type: storageTypes.NONE, \/\/ Use none for links\r\n    label: 'My Options',\r\n    icon: '\ud83c\udfc6', \/\/ Set an icon (optional)\r\n    page: 'settings', \/\/ Display on that main settings page\r\n    target: 'settings-myoptions', \/\/ Link to the new \"My Options\" page\r\n  },\r\n  'volume' \/\/ Add right before the \"Beat Volume\" button.\r\n)\r\n*\/\r\n\/\/  3. Add settings options for your new settings-myoptions page,\r\n\/\/     setting the new option definition's 'page' property to 'settings-myoptions' \r\n\/\/  \r\n\/\/  4. Remember to add $myOptions: true, to the showSetting: {...} area\r\n\/\/     in your game.setConfig(...) eval\r\n\r\n\r\n\/\/ To add custom player modifiable \"option\" settings with\r\n\/\/  radio button selection\r\n\/\/ (Due to limitations in Eos, each radio button setting \r\n\/\/   needs its own target page, 'settings-radio-options-example' \r\n\/\/   in this example. To create a page for a new setting, simply clone  \r\n\/\/   the existing 'settings-radio-options-example' and rename it.  \r\n\/\/   The new target page name MUST start with 'settings-')\r\ngame.setSettingOption(\r\n  \/\/ Setting name is '$testPenalty' (custom settings must start with '$')\r\n  '$testRadioOption', \r\n  \/\/ Setting definition:\r\n  {\r\n    type: storageTypes.GAME, \/\/ Use this, unless you've created your own\r\n    label: 'Favorite', \/\/ What to display in menu\r\n    icon: '\u2764\ufe0f', \/\/ Optional icon\r\n    \/\/                       If not found, a simple default is used.\r\n    page: 'settings-options', \/\/ Where to display the selection\r\n    target: 'settings-radio-options-example', \/\/ Page used to generate radio buttons\r\n    \/\/ Define radio button\r\n    prompt: function(){ \/\/ Optional function to generate setting prompt\r\n      return \"Pick your favorite thing.\"\r\n    },\r\n    options: {\r\n      \/\/ Keep option keys ('tits': in this first example) short.\r\n      \/\/ They take storage space.\r\n      tits: {\r\n        label: 'Tits', \/\/ Label for button\r\n        show: function(o){return true}, \/\/ Optional show\/hide function\r\n        block: function(o){}, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        \/\/ selectMessage: function(o){ \/\/ Optional function to display on select\r\n        \/\/   return \"You've selected <u>\" + o.label + \"<\/u>.\" \r\n        \/\/ },\r\n      },\r\n      ass: {\r\n        label: 'Ass', \/\/ Label for button\r\n        show: function(o){return true}, \/\/ Optional show\/hide function\r\n        block: function(o){\r\n          if (!game.kinkAnal && game.showSetting.kinkAnal) {\r\n            return \"Sorry, you can't select Ass unless you've enabled the Anal kink.\"\r\n          }\r\n        }, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        \/\/ selectMessage: function(o){ \/\/ Optional function to display on select\r\n        \/\/   return \"You've selected <u>\" + o.label + \"<\/u>.\" \r\n        \/\/ },\r\n      },\r\n      pussy: {\r\n        label: 'Pussy', \/\/ Label for button\r\n        show: function(o){return true}, \/\/ Optional show\/hide function\r\n        block: function(o){}, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        \/\/ selectMessage: function(o){ \/\/ Optional function to display on select\r\n        \/\/   return \"You've selected <u>\" + o.label + \"<\/u>.\" \r\n        \/\/ },\r\n      },\r\n      none: {\r\n        label: \"Can't Decide\", \/\/ Label for button\r\n        show: function(o){return true}, \/\/ Optional show\/hide function\r\n        block: function(o){}, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        \/\/ selectMessage: function(o){ \/\/ Optional function to display on select\r\n        \/\/   return \"You've selected <u>\" + o.label + \"<\/u>.\" \r\n        \/\/ },\r\n      },\r\n    },\r\n    key: '$oFav', \/\/ short key for storage\r\n    defaultValue: 'none', \/\/ Default value\r\n  }\r\n  \/\/ Append as last in options (no insert position defined)\r\n)\r\n\/\/ To check key value (tits, ass, etc) in game:\r\n\/\/   if (game.$testRadioOption === 'tits') {\r\n\/\/     pages.goto('the-best-tits-page')\r\n\/\/   }\r\n\/\/ To use object values in game:\r\n\/\/   var favObject = game.getRadioObject('$testRadioOption')\r\n\/\/   var myMessage;\r\n\/\/   if (!favObject || favObject.id === 'none') {\r\n\/\/     myMessage = \"You can't decide what you like best?!\"\r\n\/\/   } else {\r\n\/\/     myMessage = 'So, you like my ' \r\n\/\/                   + favObject.label.toLowerCase()\r\n\/\/                   + '?'\r\n\/\/   }\r\n\/\/ Since our \"Favorite\" option example has a blocker for \"Ass\" that needs\r\n\/\/  kinkAnal to be enebaled, also add a blocker to kinkAnal\r\ngame.setSettingOption(\r\n  'kinkAnal', \r\n  {\r\n    block: function(setting, val) {\r\n      if (!val) {\r\n        var favObject = game.getRadioObject('$testRadioOption') || {}\r\n        if (favObject.id === 'ass') {\r\n          var msg = '<i>' + setting.label + '<\/i> must be enabled when '\r\n           + '<i>' + game.getSettingOption('$testRadioOption').label + '<\/i>'\r\n           + ' is <u>' + favObject.label + '<\/u>'\r\n           console.log(\"Block\", msg)\r\n           return msg\r\n        }\r\n      }\r\n    },\r\n  }\r\n)\r\n\r\n\r\n\/\/ Modify existing setting definitions\r\ngame.setSettingOption(\r\n  \/\/ Change base kinkPrecum setting\r\n  'kinkPrecum', \r\n  \/\/ Setting definition:\r\n  {\r\n    label: 'Precum', \/\/ Have label say \"Precum\" instead of \"Precum CEI\"\r\n    icon: '\ud83d\udca7', \/\/ Set an icon (Doesn't have one bydefault)\r\n  }\r\n)\r\n\r\n\/\/ Add icons to some of the others existing ones\r\ngame.setSettingOption('kinkCbt', {icon: '\ud83d\ude2b'})\r\ngame.setSettingOption('kinkAnal', {icon: '\ud83c\udf51'})\r\n\r\n\/\/ Add verbiage for custom setting\r\ngame.setVerbiage({\r\n  settingKinksCEIEnabled: [\r\n    \"You've <u>enabled<\/u> Cum Eating Intructions.  \" + \r\n    \"You may be told to swing your legs over your head, and cum in your mouth.\"\r\n  ],\r\n  settingKinksCEIDisabled: [\r\n    \"You've <u>disabled<\/u> Cum Eating Intructions.  \" + \r\n    \"You will not be told to cum in your mouth.\"\r\n  ]\r\n})"}},{"eval":{"script":"\/\/ Create custom setting options to override round fap time\r\ngame.setSettingOption(\r\n  \/\/ Setting name is '$testPenalty' (custom settings must start with '$')\r\n  'roundTimeFap', \r\n  \/\/ Setting definition:\r\n  {\r\n    force: true, \/\/ Force this setting to allow use of existing varable\r\n    type: storageTypes.GAME, \/\/ Use this, unless you've created your own\r\n    label: 'Round Time', \/\/ What to display in menu\r\n    icon: '\u23f1\ufe0f', \/\/ Optional icon\r\n    \/\/                       If not found, a simple default is used.\r\n    page: 'settings-options', \/\/ Where to display the selection\r\n    target: 'settings-round-timer', \/\/ Page used to generate radio buttons\r\n    \/\/ Define radio button\r\n    prompt: function(){ \/\/ Optional function to generate setting prompt\r\n      return \"How long will you have to hit\/stand?\"\r\n    },\r\n    integer: true,\r\n    options: {\r\n      \/\/ Keep option keys ('tits': in this first example) short.\r\n      \/\/ They take storage space.\r\n      '10': {\r\n        label: '10 Seconds', \/\/ Label for button\r\n      },\r\n      '20': {\r\n        label: '20 Seconds', \/\/ Label for button\r\n      },\r\n      '30': {\r\n        label: '30 Seconds', \/\/ Label for button\r\n      },\r\n    },\r\n    key: '$rFt', \/\/ short key for storage\r\n    defaultValue: 30, \/\/ Default value\r\n  }\r\n  \/\/ Append as last in options (no insert position defined)\r\n)"}},{"eval":{"script":"\/\/ Add optional audio profile selection setting options\r\ngame.generateSoundOptions([\r\n  {\r\n    \/\/ Define option for --audio-1 page\r\n    label: 'Default'\r\n  },\r\n  {\r\n    \/\/ Define option for --audio-2 page\r\n    label: 'Alternate'\r\n  }\r\n], {\r\n  label: 'Audio Profile', \/\/ Text for setting button\r\n  icon:  '\ud83c\udfb5', \/\/ Optional icon\r\n  page: 'settings-sounds', \/\/ Where to display button\r\n  position: 'volume', \/\/ Insert before volume\r\n})\r\n\r\n\/\/ Add 'Audio Options' menu item\r\ngame.setSettingOption(\r\n  '$soundsMenu', \r\n  \/\/ Setting definition:\r\n  {\r\n    type: storageTypes.NONE,\r\n    label: 'Audio Options', \/\/ What to display in menu\r\n    icon: '\ud83d\udd08',\r\n    page: 'settings', \/\/ Where to display the selection\r\n    target: 'settings-sounds', \/\/\r\n  },\r\n  \/\/ Display before volume setting\r\n  'volume'\r\n)\r\n\r\n\/\/ Add 'Moans' menu item\r\ngame.setSettingOption(\r\n  'enableMoans', \r\n  \/\/ Setting definition:\r\n  {\r\n    force: true, \/\/ Allow setting to control existing game property\r\n    type: storageTypes.GAME,\r\n    label: 'Moans', \/\/ What to display in menu\r\n    icon: '\ud83d\udc44',\r\n    page: 'settings-sounds', \/\/ Where to display the selection\r\n    enableMessage: \"You've <u>enabled<\/u> moans.\" \r\n    + \"  You'll hear me moan throughout the game.[playMoan|moan]\",\r\n    disableMessage: \"Aww, you've <u>disabled<\/u> moans.  I'll keep my mouth shut.[stopMoan|moan]\",\r\n    onExit: function () {\r\n      game.stopMoan('moan')\r\n    },\r\n    key: '$aMns',\r\n    defaultValue: false,\r\n  },\r\n  \/\/ Display before volume setting\r\n  'volume'\r\n)\r\n\r\n\/\/ Move 'volume' menu item to 'Audio Options'\r\ngame.setSettingOption(\r\n  'volume', \r\n  {\r\n    page: 'settings-sounds', \/\/ Where to display the selection\r\n  }\r\n)\r\n"}},{"eval":{"script":"\/\/ Define \"melody\" game mode\r\n\r\nvar gm_melody = {\r\n  \/\/ Game config to apply for \"melody\" game mode\r\n  title: 'Full Game',\r\n  levels: 3, \/\/ 3 levels, plus cum round(s)\r\n  perLevel: 15, \/\/ 15 hands per level\r\n  \/\/ Example round limits (allowes you to truncate rounds)\r\n  \/\/ roundLimits: {\r\n  \/\/   1: 10, \/\/ Limit level 1 to 10 rounds, always\r\n  \/\/   2: function() {return !game.isUnlocked() ? 10 : false}, \/\/ If not unlocked, limit level 2 to 10 rounds\r\n  \/\/ },\r\n  \/\/ Example penaltyOccurrence overrides\r\n  \/\/ valid penalties: edge, edgeRide, stroke, loseRest, precum, anal, cbt, ...\r\n  \/\/ penaltyOccurrence: {\r\n  \/\/   loseRest: function () {\r\n  \/\/     if (game.getLevel() > 1 && game.getRoundIndex() > 2) {\r\n  \/\/       \/\/ Example loseRest prenalty occurrence overide:\r\n  \/\/       \/\/ After the second hand of every level past 1\r\n  \/\/       \/\/ increase loseRest probability to 10 out of (whatever else)\r\n  \/\/       return {\r\n  \/\/         allow: function () {\r\n  \/\/           \/\/ Only enable penalty if player has edged more than\r\n  \/\/           \/\/ once (g.pc.edge.c), and has at least 1 rest point (g.c)\r\n  \/\/           return g.pc.edge.c > 1 && g.c > 0\r\n  \/\/         },\r\n  \/\/         probability: function () {\r\n  \/\/           return 10 \/\/ Increase probabilty\r\n  \/\/         },\r\n  \/\/         enabled: function () {\r\n  \/\/           return true \/\/ Force penalty to be enabled, even if turned off\r\n  \/\/         }\r\n  \/\/       }\r\n  \/\/     }\r\n  \/\/   }\r\n  \/\/ },\r\n  \r\n  \/\/ Example penalty settings calculation override\r\n  penaltyCalc: {\r\n    \/**\r\n     * valid penalties are:\r\n     * 'stroke', 'anal', 'edge', 'edgeRide', 'cbt', 'precum', ...\r\n     *\/\r\n    \/\/ Hook 'stroke' penalty ('anal' works similar)\r\n    'stroke': function(o, level, hand) {\r\n      \/\/ Flip a coin if we're over level 1:\r\n      var doIt = level > 1 && !randomInt(0, 1)\r\n      if (doIt) {\r\n        \/\/ If we're on level 2 or higher,\r\n        \/\/ and we lost a coin toss, \r\n        \/\/ override some settings\r\n        if (DEBUG) console.warn('Fapping the hell out of them.')\r\n        return {\r\n          \/\/ Fap the hell out of them\r\n          faps: randomInt(120, 150), \/\/ Random between 120 and 150\r\n          startBpm: 300, \/\/ Random between 300\r\n          endBpm: 300, \/\/ and 300 bpms (force 300 bpms)\r\n          getMessage: function(opt) {\r\n            return mergeObject(randomString([\r\n              \"This time I'll make you cum!  [faps] turbo faps!!!\",\r\n              \"There's no way you'll get past this!  Stroke [faps] times!!!\"\r\n            ]), opt);\r\n          },\r\n          getDoneMessage: function(opt) {\r\n            return \"Don't tell me you survived that!\"\r\n          },\r\n          getStepImage: function(step, opt) {\r\n            if (step === 'stroke') {\r\n              return 'melody-image-penalty-stroke'\r\n            }\r\n          },\r\n        }\r\n      }\r\n      \/\/ Else, returning nothing will just go with default\r\n    },\r\n    \/\/ Hook 'edgeRide' penalty\r\n    'edgeRide': function(o, level, hand) {\r\n      \/\/ Flip a coin if we're over level 1:\r\n      var doIt = level > 1 && !randomInt(0, 1)\r\n      if (doIt) {\r\n        \/\/ If we're on level 2 or higher,\r\n        \/\/ and we lost a coin toss, \r\n        \/\/ override some settings\r\n        if (DEBUG) console.warn('Riding the hell out of them.')\r\n        return {\r\n          bpm: 300, \/\/ Fap the hell out of them to edge\r\n          rideTime: 40, \/\/ Force a ride of 40 seconds.\r\n          getRideMessage: function(opt) {\r\n            return mergeObject(randomString([\r\n              \"Now hold that edge for [ride] excruciating seconds!\",\r\n              \"Imagine I'm riding your cock while holding that edge for [ride] seconds!\"\r\n            ]), opt);\r\n          },\r\n          getStepImage: function(step, opt) {\r\n            if (step === 'edge-ride') {\r\n              return 'melody-image-penalty-ride'\r\n            }\r\n            if (step === 'rest') {\r\n              return 'melody-image-penalty-ride-rest'\r\n            }\r\n          },\r\n        }\r\n      }\r\n      \/\/ Else, returning nothing will just go with default\r\n    },\r\n  },\r\n  levelConfig: {\r\n    0: {\r\n      \/\/ Defaults for all levels\r\n      dealerName: 'Melody', \/\/ Dealer name defaults to Melody for all levels\r\n    },\r\n    2: {\r\n      \/\/Overrides per given level\r\n      dealerName: 'Melody', \/\/ Override dealer name for level 2\r\n    },\r\n  },\r\n  bpms: [null,90,120,150,180,240], \/\/ BPMs used per game level, 90 for 1, 120 for 2, etc. \r\n  cumRoundModes: {\r\n    \/\/ Up to 10 cum round modes allowed per game mode (try not to use more than 6.  Adjust button colors in cum-round-select)\r\n    'softcore': {\r\n      title: 'Tits & Ass',\r\n      rounds: 26, \/\/ 26 for no-hardcore mode\r\n      \/\/ Optional game settings overrides\r\n      gameSettings: {\r\n        \/\/ Add any applicable game settings you want to override for cum round here\r\n        winToCumTime: 60, \/\/ Must win within 60 seconds\r\n        dealerName: 'Melody', \/\/ Override dealer name\r\n      },\r\n    },\r\n    'hardcore': {\r\n      title: 'Suck & Fuck',\r\n      rounds: 27, \/\/ 27 Images\/Pages for hardcore cum round\r\n      gameSettings: {\r\n        \/\/ Add any applicable game settings you want to override for cum round here\r\n        winToCumTime: 60, \/\/ Must win within 60 seconds\r\n        dealerName: 'Melody', \/\/ Override dealer name\r\n      },\r\n    },\r\n  },\r\n}"}},{"eval":{"script":"\/\/ Define \"melody2\" game mode\r\n\r\nvar gm_melody2 = {\r\n  \/\/ Game config to apply for \"melody2\" game mode\r\n  title: 'Super Short',\r\n  levels: 1, \/\/ 1 levels, plus cum round(s)\r\n  perLevel: 3, \/\/ 3 hands per level\r\n  \/\/ Will apply to all difficulties, since we didn't define applyToDifficulties\r\n  levelConfig: {\r\n    0: {\r\n      \/\/ Defaults for all levels\r\n      roundTimeFap: 5, \/\/ melody2 only gives 5 seconds to hit\/stand\r\n      dealerName: 'Melody', \/\/ Dealer name defaults to Melody for all levels\r\n    }\r\n  },\r\n  \/\/ Melody 2 faps faster in-round in the beginning\r\n  bpms: [null,150,150,150,180,240], \/\/ BPMs used per game level, 90 for 1, 120 for 2, etc. \r\n  cumRoundModes: {\r\n    \/\/ Up to 10 cum round modes allowed per game mode (try not to use more than 6.  Adjust button colors in cum-round-select)\r\n    'cum': {\r\n      title: 'More of Me',\r\n      rounds: 3, \/\/ 3 hands, but will fallback to \"melody2-image-cum\" to load images.\r\n      gameSettings: {\r\n        dealerName: 'Melody', \/\/ Override dealer name for cum round\r\n        winToCumTime: 45, \/\/ Must win within 45 seconds\r\n      }\r\n    },\r\n    'softcore': {\r\n      \/\/ Re-use the 'softcore' cum round from 'melody'\r\n      title: 'Tits & Ass',\r\n      rounds: 26, \/\/ 26 for no-hardcore mode\r\n      \/\/ Optional game settings overrides\r\n      gameSettings: {\r\n        modePath: 'melody', \/\/ We'll load pages like we're in melody mode\r\n        \/\/ Add any applicable game settings you want to override for cum round here\r\n        winToCumTime: 60, \/\/ Must win within 60 seconds\r\n        dealerName: 'Melody', \/\/ Override dealer name\r\n      },\r\n    },\r\n  },\r\n}"}},{"eval":{"script":"\/\/ Set Default Game Configuration\r\n\/\/ NOTE:  It's important to only execute game.setConfig(...) once for \r\n\/\/        default configuration.\r\ngame.setConfig({\r\n\r\n  \/\/ GAME SETTINGS\r\n  volume: 0.5, \/\/ Volume level between zero and 1, but seems to actually be between 0.0 and 0.1? (player modifiable)\r\n  volumeStep: 0.04, \/\/ Amount to change volume on adjustment\r\n  defaultRests: 2, \/\/ Number of rests a player starts with\r\n  numberOfDecks: 1, \/\/ Number of decks to use\r\n  kinkCbt: false, \/\/ Cock Ball torture (player modifiable)\r\n  kinkAnal: false, \/\/ Anal play (player modifiable)\r\n  kinkPrecum: false, \/\/ Precum CEI (player modifiable)\r\n  loseRest: true, \/\/ Enable loseing rest (player modifiable)\r\n  cumRoundAuto: false, \/\/ Advance round automatically (not applicable to winToCum)\r\n  showSetting: {\r\n    volume: true, \/\/ Show beat volume setting\r\n    options: true, \/\/ Show gane options settings\r\n    loseRest: true, \/\/ Show Lose Rest option\r\n    inRoundFapping: true, \/\/ Show In Round Fapping option\r\n    strokePenaltyLimit: true, \/\/ Show Stroke Penalty Limit option\r\n    kinks: true, \/\/ Show Kinks setting\r\n    kinkPrecum: true, \/\/ Show Precum CEI kink\r\n    kinkCbt: true, \/\/ Show CBT kink\r\n    kinkAnal: true, \/\/ Show Anal kink\r\n    $testPenalty: true, \/\/ Show our custom $testPenalty option setting\r\n    $testRadioOption: true, \/\/ Show our example radio options\r\n    $kinkCEI: true, \/\/ Show our custom $kinkCEI kink setting\r\n    roundTimeFap: true,\r\n    audioProfile: true,\r\n    $soundsMenu: true,\r\n    enableMoans: true,\r\n  },\r\n  cumRoundTease: true, \/\/ Encourage to cum in auto-cum round (not applicable to winToCum)\r\n  continousShuffle: false, \/\/ Shuffle cards after each hand, or shuffle after 5 hands.\r\n  winToCum: true, \/\/ Player must win the cum round to cum.\r\n  winToCumTime: 90, \/\/ Time, in seconds, player must win rounds in\r\n  winToCumTimeMin: 8, \/\/ If using cumToWinTimer, minimum time player will get\r\n  cumToWinTimer: true, \/\/ Use time remaining in win to cum round as limit for final cum page\r\n  cumRoundsToWin: 6, \/\/ Number of rounds player must win to cum, if winToCum\r\n  winToCumPenalty: 5, \/\/ Penalty, in seconds, for losing hand by standing below threshold\r\n  winToCumThreshold: 8, \/\/ If player stands below this value, then they're not even trying. Penalize them.\r\n  winToCumIncAlways: true, \/\/ Increment round image even if player loses hand in winToCum mode\r\n  cumRoundModeAutoSelectTime: 10, \/\/ 10 seconds to select cum round mode, else auto select (0 to disable)\r\n  gameModeAutoSelectTime: 10, \/\/ 10 seconds to select game mode, else auto select (0 to disable)\r\n  randomItemHistorySize: 0, \/\/ (Increase to decrease repetition of penalty sleection. 0 to 2 is a good setting)\r\n  dealerName: 'Melody', \/\/ Default dealer's name (can be overriden per level)\r\n  \/\/ GAME MODES\r\n  gameModes: {\r\n    \/\/ Up to 10 game modes (try not to use more than 6.  Adjust button colors in game-mode-select)\r\n    melody: gm_melody, \/\/ use pre-defined game mode (see evals above)\r\n    melody2: gm_melody2, \/\/ use pre-defined game mode (see evals above)\r\n  },\r\n\r\n  \/\/ OTHER GAME SETTINGS\r\n  maxSaveAge: 120, \/\/ How old a saved game state can be, in seconds, to be continued.\r\n  dealerSaftey: 17, \/\/ Dealer will not hit at or past this point.\r\n  rouletteTimerStart: [10, 80], \/\/ Starting ms wait between clicks [nornal, slow]\r\n  rouletteTimerLen: [10, 8], \/\/ How many clicks for penalty roulette [nornal, slow]\r\n  rouletteTimerInc: [0.5, 0.25], \/\/ how much to increase the durration between clicks after each roulette click [nornal, slow]\r\n  rouletteTimerEnd: .5, \/\/ Seconds to wait after penalty roulette ends, and the penalty page is displayed\r\n  roundTimerNoFap: 15, \/\/ Seconds to wait for hit\/stand with no-fap setting\r\n  roundTimeFap: 30, \/\/ Seconds to wait for hit\/stand with fap setting\r\n  roundTimeCum: 30, \/\/ Seconds to wait for hit\/stand in cum round (not in winToCum)\r\n  roundTimeCumAuto: 10, \/\/ Seconds to wait for hit\/stand in cum-auto advance mode (not in winToCum)\r\n  singleLevelImage: false, \/\/ Force use of [gameMode]-image-[level] instead of [gameMode]-image-[level]-[hand]\r\n                           \/\/ (fall-back to single-level image is automatic if descrete or range image page isn't found)\r\n\r\n  \/\/ SETTING THAT MAY GO AWAY OR MAY NO LONGER WORK CORRECTLY\r\n  strokePenaltyLimit: false, \/\/ If true, edge only if not round 1 or cum round (player modifiable)\r\n  inRoundFapping: true, \/\/ Fap durring round. (player modifiable)\r\n  \r\n  \/\/ DEAD GAME SETTINGS THAT PROBABLY DON'T WORK AS YOU WOULD THINK\r\n  shuffleNotice: false, \/\/ If not continousShuffle, show a notice for shufffles (Was fun to make, but too distracting.)\r\n\r\n});"}},{"eval":{"script":"\/\/ Add a simple custom penalty\r\n\/\/ Create a simple \"custom\" penalty that will go to a page of your choice\r\n\/\/ (See setPenaltyOccurrences example in core-config-ulc-exmaple\r\n\/\/      for a more complicated penalty that uses parts of existing penalties.)\r\ngame.setPenaltyOccurrences([\r\n  {\r\n    pf: pf.custom, \/\/ Use \"custom\" penalty factory as base\r\n    o: {\r\n      id: 'testP', \/\/ Keep IDs very short (uses tease storage space)\r\n      title: 'Custom Penalty', \/\/ Keep titles short.  Needs to show in the roulette\r\n      allow: function() {\r\n        \/\/ The difference between allow and enabled is:\r\n        \/\/ enabled:  penalty shows in roulette or not when \"spinning\"\r\n        \/\/ allow:  allow penalty to be selected in roulette\r\n        return true \/\/ Force allow for debugging\r\n      },\r\n    },\r\n    probability: function(){\r\n      return 50 \/\/ Force high probability for debugging\r\n      return 2 \/\/ repeat 2 times in roulette to set probability\r\n    }, \r\n    enabled: function(){\r\n      return game.$testPenalty \/\/ Only include if custom testPenalty setting is enabled\r\n    },\r\n    page: 'penalty-custom-example', \/\/ Name of page you want to show\r\n    \/\/ (See penalty-custom-example page for example of how you should start and end your penalties.)\r\n  \r\n  },\r\n])\r\n"}},{"eval":{"script":"\/\/ Create custom CEI pentaly example, using the precum penalty as a base\r\ngame.setPenaltyOccurrences([\r\n  \/\/ Create CEI using precum penalty factory\r\n  {\r\n    pf: pf.precum, \/\/ Use existing precum penalty factory as base\r\n    o: {\r\n      id: 'cei', \/\/ Keep IDs very short (uses tease storage space)\r\n      title: 'Cum in mouth',\r\n      allow: function() {\r\n        \/\/ The difference between allow and enabled is:\r\n        \/\/ enabled:  penalty shows in roulette or not when \"spinning\"\r\n        \/\/ allow:  allow penalty to be selected in roulette\r\n        return true \/\/ Force allow for debugging\r\n        \/\/ Allow if:\r\n        return game.getLevel() > 1 && \/\/ is in secord level or more\r\n          (\r\n          (g.pc.precum.c > 0 && game.kinkPrecum) \/\/ has hit pre-cum penalty\r\n          ||\r\n          (g.pc.edge.c > 1 && !game.kinkPrecum) \/\/ has edged twice, if precum not enabled\r\n          )\r\n          (Date.now() - (g.pc.cei._t || 0)) >= 300000 \/\/ At least 5 min since last successful CEI\r\n      },\r\n      getMessage: function(opt) {\r\n        closeAllBut('round') \/\/ Hide the cum\/rest button\r\n        beats.start(300); \/\/ Fap like hell\r\n        return mergeObject(randomString(t.eatCum), opt);\r\n      },\r\n      getFailMessage: function(opt) {\r\n        return mergeObject(randomString(opt.timeout ? t.eatCumTimeout : t.eatCumFail), opt);\r\n      },\r\n      messageDelay: function (opt) {\r\n        return 90000; \/\/ ms.   Wait 90 sec. to cum in mouth, or fail.\r\n      },\r\n      showTimer: true,\r\n      finish: function(opt) {\r\n        \/\/ Finished successfully\r\n        g.c ++; \/\/ Add rest point (yeah, badly named)\r\n        g.pc.cei._t = Date.now(); \/\/ Record success time\r\n        return mergeObject(randomString(t.eatCumDone), opt);\r\n      },\r\n      getAfterPassMessage: function(opt) {\r\n        \/\/ Return a message telling player to wait until they're ready\r\n        \/\/ Will trigger pause, waiting for a button press.\r\n        \/\/ Comment out this function, or return false to\r\n        \/\/ disable pause.\r\n        return mergeObject(randomString(t.eatCumPause), opt);\r\n      },\r\n      getStepImage: function(step, opt) {\r\n        if (step === 'message-pass-fail') {\r\n          \/\/ Load an image page for showing CEI example\r\n          return 'melody-image-penalty-cei'\r\n        } else {\r\n          \/\/ Probably on message-pass or message-fail page.\r\n          \/\/ Stop all beats\r\n          beats.stopAll();\r\n          if (step === 'message-pass') {\r\n            \/\/ Show a reward image while player tries to get hard again\r\n            return 'melody-image-penalty-cei-pass'\r\n          }\r\n          \/\/ return -1 to force load of game round image\r\n          return -1 \r\n        }\r\n      },\r\n    },\r\n    probability: function(){\r\n      return 50 \/\/ Force high probability for debugging\r\n      return 2 \/\/ repeat 2 times in roulette to set probability\r\n      }, \r\n    enabled: function(){\r\n      return game.$kinkCEI \/\/ Only include if custom CEI setting is enabled\r\n      }\r\n  },\r\n])\r\n\r\n\/\/ Add verbiage needed for custom penalties\r\ngame.setVerbiage({\r\n  eatCum: [ \/\/ Tell player to cum in mouth\r\n    '<span style=\"color:yellow\">Here\\'s your chance!<\/span><\/p>' \r\n    +\"<p>Get your ass above your head, then cum in your mouth!\",\r\n    \"Hurry! Ass up, point your cock at your mouth, stroke 'till you cum!\",\r\n    \"Time for a treat!<\/p><p>Legs over your head, cum in your mouth!\",\r\n    \"Get in position!<\/p><p>Wank every last drop of cum directly in your mouth!\",\r\n  ],\r\n  eatCumTimeout: [ \/\/ Took too long to eat cum\r\n    \"Sorry, you need to do it quickly!\",\r\n    \"I know you're trying, but I'm in a hurry!\",\r\n    \"Shouldn't take all day to aim and cum!\",\r\n    \"Next time, aim true and wank harder!\",\r\n    \"You need to work fast if you want your reward!\",\r\n  ],\r\n  eatCumFail: [ \/\/ Couldn't eat cum\r\n    \"Aw.  Maybe next time?\",\r\n    \"Don't worry, you'll have another chance!\",\r\n    \"I'm sure you'll do it next time!\",\r\n    \"I know, sometimes the moment just isn't right.\",\r\n    \"You'll do it for me next time, right?\",\r\n  ],\r\n  eatCumDone: [ \/\/ Congratulate player\r\n    \"Yay!  You earn a rest point!\",\r\n    \"Mmmm!  Have another rest point!\",\r\n    \"Good job!  Have another rest point!\",\r\n    \"Yay! Cum-slut power-up! Another rest point for you!\",\r\n  ],\r\n  eatCumPause: [ \/\/ Let player wait to get hard again.\r\n    \"Let me know when you're ready to continue.\",\r\n    \"Savor it for as long as you like.\",\r\n    \"Take your time, but I know you're eager for more!\",\r\n    \"Make sure you clean up your mess.\",\r\n  ],\r\n});\r\n"}},{"eval":{"script":"returnToCaller();"}}],"core-verbiage-example":[{"eval":{"script":"\r\n\/\/ Load Default Verbiage\r\n\/\/ Remember to keep it short and sweet!\r\n\/\/ Don't under-estimate how badly the wrong words or too much repetition \r\n\/\/  can ruin the mood.\r\n\/\/ (And don't give FapJack a bad name by making the dealer say stupid crap!)\r\n\/\/ Text is randomly selected from the lists provided.\r\ngame.setVerbiage({\r\n  welcome: [ \/\/ First message the player sees.\r\n    \"Hi!  Welcome to \" + \"FapJack\".italic().bold() + \"!\",\r\n    \"Hey!  Welcome to \" + \"FapJack\".italic().bold() + \"!\",\r\n    \/\/ Good spot to test things, since it's one of the first things you'll see.\r\n    \/\/ \"[dealerBlackjackOpen]Yay! I win with blackjack![dealerBlackjackClose]\",\r\n  ],\r\n  introBlurb: [ \/\/ First message the player sees.\r\n    \/\/ NOTE: with multiple lines from a variable,\r\n    \/\/       don't include the opening and closing <p> tags\r\n    \"<u>The rules are simple:<\/u><\/p>\"\r\n    + \"<p>1. Stroke to the beat at all time.<\/p>\"\r\n    + \"<p>2. Win each round of Blackjack to progress.<\/p>\"\r\n    + \"<p>3. Don't cum until the end, or you lose!\",\r\n  ],\r\n  dryTease: [ \/\/ Player wants to see more after post game instructions tease.\r\n    \"Sorry, that's all until you play!\",\r\n    \"You need to play to see more!\",\r\n    \"Play if you want more!\",\r\n    \"Well, let's play then!\",\r\n    \"Then why don't you play?\"\r\n  ],\r\n  playStart: [\r\n    \"Okay, get ready to stroke!\"\r\n  ],\r\n  \/\/ Message at the start of each new round (not just level)\r\n  \/\/ (each time a player wins a hand, it's a new \"round\".)\r\n  \/\/ (after x rounds, it's a new level )\r\n  dealerRoundIntros: { \r\n    \/\/ No round intros\r\n  },\r\n  bj_p: [ \/\/ Player got blackjack\r\n    \/\/ Wrap in playerBlackjackOpen\/playerBlackjackClose\r\n    \/\/  to make response more noticable as a positive\r\n    \"You got blackjack!  You earn another rest!\".style(game.playerBJStyle, game.playerBJClass),\r\n    \"Blackjack! Another rest point!\".style(game.playerBJStyle, game.playerBJClass),\r\n    \"Yay! blackjack! Have another rest point!\".style(game.playerBJStyle, game.playerBJClass),\r\n  ],\r\n  bj_d: [ \/\/ Dealer got blackjack\r\n    \/\/ Wrap in dealerBlackjackOpen\/dealerBlackjackClose\r\n    \/\/  to make response more noticable as a negative\r\n    \"Blackjack! I win!\".style(game.dealerBJStyle, game.dealerBJClass),\r\n    \"I got blackjack!\".style(game.dealerBJStyle, game.dealerBJClass),\r\n    \"Yay! I win with blackjack!\".style(game.dealerBJStyle, game.dealerBJClass),\r\n  ],\r\n  bust_p: [ \/\/ Player busted\r\n    \"Aw, you busted!\",\r\n    \"Ha, you went bust!\",\r\n    \"Sorry, that's a bust.\",\r\n    \"You went bust!\",\r\n    \"You busted, I win!\",\r\n    \"I win, you busted!\",\r\n  ],\r\n  bust_d: [ \/\/ Dealer busted\r\n    \"Shoot! I busted.\",\r\n    \"Damn! I lost this round!\",\r\n    \"Dangit! Look at my bust!\",\r\n    \"Like my bust?  You win.\",\r\n    \"You like my bust?\",\r\n  ],\r\n  win_p: [ \/\/Player wins\r\n    \"You win with [ppoints]!\",\r\n    \"[ppoints] beats my [dpoints]!\",\r\n    \"Shoot! Your [ppoints] wins!\",\r\n    \"You win, this time!\",\r\n    \"[ppoints] wins over my [dpoints].\",\r\n    \"Great! [ppoints] wins!\",\r\n    \"You win [ppoints] to [dpoints].\",\r\n  ],\r\n  win_d: [ \/\/Dealer wins\r\n    \"I win with [dpoints]!\",\r\n    \"[dpoints] beats your [ppoints]!\",\r\n    \"Yay! My [dpoints] wins!\",\r\n    \"I win this round!\",\r\n    \"Ha! I win with [dpoints].\",\r\n    \"[dpoints] wins over your [ppoints].\",\r\n    \"My [dpoints] wins!\",\r\n    \"I win [dpoints] to [ppoints].\",\r\n  ],\r\n  tie: [ \/\/Round is a tie\r\n    \"It's a tie!  Let's try that again.\",\r\n    \"Tie! One more time...\",\r\n    \"We got same thing! Lets do it again.\",\r\n    \"Look! We match! Do over...\",\r\n  ],\r\n  hitTimeout: [ \/\/Took too long to hit\/stand\r\n    \"I don't have all day!\",\r\n    \"Shouldn't take you that long to decide!\",\r\n    \"Hit or Stand.  It's really not that hard, is it?\",\r\n    \"Sorry, tired of waiting...\",\r\n  ],\r\n  cumRoundMessage: [ \/\/ Ask for cum\r\n    \"Mmmmm... I want your cum!\",\r\n    \/\/ \"I can't wait for all that cum!\",\r\n    \"Please cum for me!\",\r\n    \"CUM NOW!\",\r\n    \"Come on, give me all of it!\",\r\n    \/\/ \"I NEED YOUR CUM!\",\r\n    \/\/ \"Cum all over me!\",\r\n    \/\/ \"I want your CUM!\",\r\n    \"CUM!\",\r\n    \"I want all of your cum!\",\r\n    \/\/ \"I want your cum all over me!\",\r\n    \"Cum for me now!\",\r\n    \"Yes! Cum for me!\",\r\n    \"Give me all of it!\",\r\n    \"Cum for me!\",\r\n    \"Please give me all your cum!\",\r\n    \"Mmmmmm... please give me your cum!\",\r\n  ],\r\n  edge: [ \/\/ Tell player to edge\r\n    \"Get right to the edge, but don't cum!\",\r\n    \"Go on, edge for me!\",\r\n    \"Get as close as you can!\",\r\n    \"Keep stroking until you edge!\",\r\n    \"Get right to the edge for me.  Don't go over!\",\r\n    \"Stroke until you almost explode, but don't!\",\r\n    \"Do what you need to do to reach that edge!\",\r\n  ],\r\n  edgeRide: [ \/\/ Tell player to ride edge\r\n    \"Now ride that edge...[playMoan|moan]\",\r\n    \"Now stay on the edge![playMoan|moan]\",\r\n    \"Keep that edge, but don't lose control![playMoan|moan]\",\r\n    \"Keep edging![playMoan|moan]\",\r\n    \"Mmmmm.  Now ride it![playMoan|moan]\",\r\n    \"Don't lose that edge![playMoan|moan]\",\r\n  ],\r\n  edgeRideCont: [ \/\/ Ecourage player to continue edging\r\n    \"That's it, keep on riding.[playMoan|moan]\",\r\n    \"Just like that... Mmmmm...[playMoan|moan]\",\r\n    \"Stay as close as you can for me...[playMoan|moan]\",\r\n    \"Don't stop riding that edge...[playMoan|moan]\",\r\n    \"Yes, just like that...[playMoan|moan]\",\r\n    \"Keep going...[playMoan|moan]\",\r\n\/\/    \"MMmmmm... I love taste of precum...\",\r\n\/\/    \"That's it, let that precum flow...\",\r\n    \"Get even closer for me...[playMoan|moan]\",\r\n  ],\r\n  strokeTime: [ \/\/ Tell player to stroke\r\n    \"Stroke [faps] times for me!\",\r\n    \"Stroke it [faps] times in [time] seconds!\",\r\n    \"I want [faps] full strokes!\",\r\n    \"Give me [faps] strokes!\",\r\n  ],\r\n  \/\/ analPrep: [ \/\/ Tell player to get ready for anal play\r\n  \/\/   \"Get ready to play with your hole!\",\r\n  \/\/   \"Get your hole ready!\",\r\n  \/\/   \"Put a finger on your ass and be ready!\",\r\n  \/\/   \"Be ready to play with your ass!\",\r\n  \/\/   \"Is your hole ready to play?\",\r\n  \/\/   \"Get ready for anal play!\",\r\n  \/\/ ],\r\n  \/\/ strokeAnalTime: [ \/\/ Tell player to stroke with anal play\r\n  \/\/   \"Slide a finger tip and out while giving me [faps] faps!\",\r\n  \/\/   \"Shove your finger up there while stroking [faps] times!\",\r\n  \/\/   \"Stroke [faps] times while messaging your back door!\",\r\n  \/\/   \"I want [faps] full strokes while wriggling in deep!\",\r\n  \/\/   \"I want [faps] full strokes while fingering your fun-hole!\",\r\n  \/\/   \"Give me [faps] strokes while tapping your bung to the beat!\",\r\n  \/\/ ],\r\n  eatPrecum: [ \/\/ Tell player to eat precum\r\n    \"Milk out that delicious precum and eat it up!\",\r\n    \"Eat every drop of that oozing precum.  Yum!\",\r\n    \"Time for a treat! Slurp up your precum!\",\r\n    \"Dip a finger in your precum and lick it clean! Mmmmm!\",\r\n    \"Gather all that sweet precum and slurp it down!\",\r\n    \"Eat your precum for me?  I'm so jealous!\",\r\n  ],\r\n  eatPrecumTimeout: [ \/\/ Took too long to eat precum\r\n    \"Sorry, you need to gobble it up quickly!\",\r\n    \"I know you want to savor it, but I'm in a hurry!\",\r\n    \"Shouldn't take all day to eat it!\",\r\n    \"Next time, slurp it up fast!\",\r\n    \"You need to eat fast if you want your reward!\",\r\n  ],\r\n  eatPrecumFail: [ \/\/ Couldn't eat precum\r\n    \"Aw.  Maybe next time?\",\r\n    \"Don't worry, you'll another chance!\",\r\n    \"I'm sure you can make more for next time!\",\r\n    \"I know, sometimes the moment just isn't right.\",\r\n  ],\r\n  eatPrecumDone: [ \/\/ Congratulate player for precum\r\n    \"Yay!  You earn a rest point!\",\r\n    \"Mmmm!  Have another rest point!\",\r\n    \"Good job!  Have another rest point!\",\r\n    \"That sweet stuff earned you a rest point!\",\r\n    \"Yay! Precum power-up! Another rest point for you!\",\r\n  ],\r\n  strokeDone: [ \/\/ Player (should have) finished stroking\r\n    \"Wow! You must practice every day!\",\r\n    \"Not that hard, right?\",\r\n    \"Great stroking!\",\r\n    \"Perfect strokes!\",\r\n    \"Hey, you're good at that!\",\r\n  ],\r\n  cbt: [ \/\/ Tell player to stroke\r\n    \"Slap your balls [faps] times!\",\r\n    \"Slap your shaft [faps] times, hard!\",\r\n    \"Give me [faps] hard ball-slaps!\",\r\n    \"Flick the head of your cock [faps] times!\",\r\n    \"Pinch the tip of your cock [faps] times, hard!\",\r\n    \"Flick your balls [faps] times!\",\r\n\/\/    \"Squeeze your balls [faps] times!\",\r\n    \"Squeeze your shaft [faps] times, hard!\",\r\n  ],\r\n  loseRest: [ \/\/ Tell player they lost a rest\r\n    \"Aw, sorry.  You lose a rest.\",\r\n    \"I'll take one rest point, thanks!\",\r\n    \"That cost you one rest point!\",\r\n    \"Sorry, you lost a rest.\",\r\n  ],\r\n  restStart: [ \/\/ We're starting a rest\r\n    \"Okay, time for a little rest.\",\r\n    \"Alright, a short break...\",\r\n    \"Hands off your thing while you take a break!\",\r\n    \"How about a little break?\",\r\n    \"Okay, stop stroking...\",\r\n  ],\r\n  restBreatheIn: [ \/\/ Tell player to breathe in\r\n    \"Breathe in...\",\r\n    \"A deep breath in...\",\r\n    \"And breathe in...\",\r\n    \"Now breathe in...\",\r\n    \"Take a breath in...\",\r\n  ],\r\n  restBreatheOut: [ \/\/ Tell player to breathe out\r\n    \"...and now out.\",\r\n    \"...now out.\",\r\n    \"...and out.\",\r\n    \"...now let it out.\",\r\n  ],\r\n  backToGame: [ \/\/ We're returning to the game after penalty\/rest\/etc.\r\n    \"Now back to the game!\",\r\n    \"Let's get back at it!\",\r\n    \"Time to play!\",\r\n    \"Now let's play!\",\r\n  ],\r\n  gameWon1: [ \r\n    \"Yay!  You won!\",\r\n  ],\r\n  gameWon2: [ \r\n    \"Please come back and play again!\",\r\n  ],\r\n  gameOver1: [\r\n    \"Oh no!  You lost!\",\r\n  ],\r\n  gameOver2: [ \r\n    \"Hope to see you back soon!\",\r\n  ],\r\n  gameLostCheckPrompt: [ \r\n    \"Uh oh!  Can you hold it back?[playMoan|moan]\",\r\n  ],\r\n  gameLostCheckPromptCumAnyTime: [ \r\n    \"Will you try to hold it back?\",\r\n  ],\r\n  cumRound1: [ \/\/ Player has made it to cum round.  First message.\r\n    \"Wow!  You've made it to the cum round!\",\r\n  ],\r\n  cumRound2: [ \/\/ Player has made it to cum round.  Second message.\r\n    \"Cum whenever you like!  You'll win in any case!\",\r\n  ],\r\n  cumRound3: [ \/\/ Player has made it to cum round.  Third message.\r\n  ],\r\n  cumRoundSelect1: [\r\n    \"You're almost there!\"\r\n  ],\r\n  cumRoundSelect2: [\r\n    \"What would you like for your final round?\"\r\n  ],\r\n  cumRoundAutoSelect: [\r\n    \"Yay, [getCumRoundModeTitle]!\",\r\n    \"Looks like you get [getCumRoundModeTitle].\",\r\n  ],\r\n  cumRoundMustWin1: [ \/\/ Player has made it to a must-win cum round.  First message.\r\n    \"Wow!  You've made it to the final round!\",\r\n  ],\r\n  cumRoundMustWin2: [ \/\/ Player has made it to a must-win cum round.  Second message.\r\n    \"Win [cumRoundsToWin] hands before time is up and I may just let you cum.\",\r\n  ],\r\n  cumRoundMustWin3: [ \/\/ Player has made it to a must-win cum round.  Third message.\r\n    \"But first, you need to get to the edge.\",\r\n  ],\r\n  cumRoundWinTease: [ \/\/ If no other message to display, display this durring cum round.\r\n    \"That's it, keep on riding.\",\r\n    \"Ride that edge... Mmmmm...\",\r\n    \"Stay as close as you can for me...\",\r\n    \"Don't stop riding that edge...\",\r\n    \"Don't lose that edge...\",\r\n    \"I want to see your legs shaking... keep edging!\",\r\n    \"Keep riding...\",\r\n    \"Get even closer for me...\",\r\n    \"Only [getWinsNeeded] more hands to win! Keep edging...\",\r\n    \"Hurry, only [getFormattedWinTimeRemaining] left! Hold that edge...\",\r\n  ],\r\n  winToCumTimout: [ \/\/ Player didn't win enough rounds in time\r\n    \"Sorry, you didn't win enough hands in time!\",\r\n    \"Aw, time's up! No cumming this game!\",\r\n    \"So close, right?  Sorry, time's up.\",\r\n    \"Almost! But your time is up.\",\r\n    \"Aw, and I could almost taste it...\",\r\n  ],\r\n  winToCumStandFail: [ \/\/ Player chose to stand below threshold.\r\n    \"You're not even trying.  You lose [winToCumPenalty] seconds for standing below [winToCumThreshold].\",\r\n  ],\r\n  cumToWinStartPrompt: [\r\n    \"Hurry!  You have [getFormattedCumTimeRemaining] to cum!\",\r\n    \"You have only [getFormattedCumTimeRemaining] to cum!  Stroke!\",\r\n  ],\r\n  cumToWinTimeoutMessage1: [  \/\/ Time ran out for the player to cum message #1\r\n    \"Sorry, time's up!  Hands off your thing!\",\r\n    \"That's all the time I could give you. Stop stroking!\",\r\n    \"Stop! Time's up!\",\r\n  ],\r\n  cumToWinTimeoutMessage2: [  \/\/ Time ran out for the player to cum message #2\r\n    \"Did you cum?\",\r\n    \"Were you able to cum?\",\r\n    \"You came, didn't you?\",\r\n  ],\r\n  gameModeSelect1: [\r\n  ],\r\n  gameModeSelect2: [\r\n    \"How would you like to play?\"\r\n  ],\r\n  gameModeAutoSelect: [\r\n    \"Hope you like [getGameModeTitle]!\",\r\n    \"You get [getGameModeTitle].  Enjoy!\",\r\n  ],\r\n  difficultySelect1: [\r\n  ],\r\n  difficultySelect2: [\r\n    \"How long do you want to play?\"\r\n  ],\r\n  difficultyAutoSelect: [\r\n    \"Hope you like [getDifficultyTitle]!\",\r\n    \"You get [getDifficultyTitle].  Enjoy!\",\r\n  ],\r\n  \/\/ SETTINGS verbiage:\r\n  settingInRoundFappingEnabled: [\r\n    \"You've <u>enabled<\/u> in-round fapping.  You'll have \" +\r\n    \"[getRoundTimeInSeconds] seconds to HIT or STAND, while \" + \r\n    \"stroking to the beat.\"\r\n  ],\r\n  settingInRoundFappingDisabled: [\r\n    \"You've <u>disabled<\/u> in-round fapping.  You'll have [getRoundTimeInSeconds] \" +\r\n    \"seconds to HIT or STAND, with no stroking.\"\r\n  ],\r\n  settingStrokePenaltyLimitEnabled: [\r\n    \"You've <u>enabled<\/u> stroke penalty limits.  You will only have stroke penalties in round 1.x and cum rounds.\"\r\n  ],\r\n  settingStrokePenaltyLimitDisabled: [\r\n    \"You've <u>disabled<\/u> stroke penalty limits.  You will have stroke penalties in all rounds.\"\r\n  ],\r\n  settingLoseRestEnabled: [\r\n    \"You've <u>enabled<\/u> Lose Rest. \" +\r\n   \"You may lose rest points if you lose a hand.\"\r\n  ],\r\n  settingLoseRestDisabled: [\r\n    \"You've <u>disabled<\/u> Lose Rest. \" +\r\n   \"You will not lose rest points if you lose a hand.\"\r\n  ],\r\n  settingAutoCumRoundEnabled: [\r\n    \"You've <u>enabled<\/u> Auto cum-round.  \" +\r\n   \"Cum round will auto-advance every [cumRoundFapTime]\" +\r\n    \" seconds, showing a new image to fap to until the end is reached.\"\r\n  ],\r\n  settingAutoCumRoundDisabled: [\r\n    \"You've <u>disabled<\/u> Auto cum-round.  \" +\r\n   \"You must win each hand in the cum round to advance to the next image.\"\r\n  ],\r\n  settingKinksPrecumEnabled: [\r\n    \"You've <u>enabled<\/u> Precum Eating Intructions.  \" + \r\n    \"You may be told to eat your precum.\"\r\n  ],\r\n  settingKinksPrecumDisabled: [\r\n    \"You've <u>disabled<\/u> Precum Eating Intructions.  \" + \r\n    \"You will not be told to eat your precum.\"\r\n  ],\r\n  settingKinksCBTEnabled: [\r\n    \"You've <u>enabled<\/u> Cock & Ball Torture.  \" + \r\n    \"You may be told to flick\/slap\/squeeze your cock or balls.\"\r\n  ],\r\n  settingKinksCBTDisabled: [\r\n    \"You've <u>disabled<\/u> Cock & Ball Torture.  \" + \r\n    \"You will not be told to flick\/slap\/squeeze your cock or balls.\"\r\n  ],\r\n  settingKinksAnalEnabled: [\r\n    \"You've <u>enabled<\/u> anal play.  \" + \r\n    \"You may be told to finger your ass while stroking your cock.<\/p>\" + \r\n    \"<p><i><b>Get your hole lubed and ready!<b><\/i>\"\r\n  ],\r\n  settingKinksAnalDisabled: [\r\n    \"You've <u>disabled<\/u> anal play.  You will not be told to finger your ass.\"\r\n  ],\r\n  \r\n  \/\/ *** New since 1.13 ***\r\n\r\n  settingLossPenaltyLabel: [\r\n    \"Loss Penalty\"\r\n  ],\r\n  settingLossPenaltyIcon: [\r\n    \"\ud83e\udd7a\"\r\n  ],\r\n  settingLossPenaltyPrompt: [\r\n    \"If you lose the final round or cum before winning, what should happen?\"\r\n  ],\r\n\r\n  settingLossPenaltyRuinLabel: [\r\n    \"Ruin\"\r\n  ],\r\n  settingLossPenaltyRuinSelect: [\r\n    \"You've selected <u>[label]<\/u>.\".p() + \r\n    \"You must ruin your orgasim if you lose the final round or cum before winning.\" \r\n  ],\r\n\r\n  settingLossPenaltyDenyLabel: [\r\n    \"Deny\"\r\n  ],\r\n  settingLossPenaltyDenySelect: [\r\n    \"You've selected <u>[label]<\/u>.\".p() + \r\n    \"You will not be allowed to cum if you lose the final round.\".br()\r\n    +\"You must ruin your orgasm if you cum before winning.\"\r\n  ],\r\n\r\n  settingLossPenaltyCeiLabel: [\r\n    \"Eat it\"\r\n  ],\r\n  settingLossPenaltyCeiSelect: [\r\n    \"You've selected <u>[label]<\/u>.\".p() + \r\n    \"You must eat your load in the way instructed if you lose the final round or cum before winning.\" \r\n  ],\r\n\r\n  settingLossPenaltyRandLabel: [\r\n    \"Random\"\r\n  ],\r\n  settingLossPenaltyRandSelect: [\r\n    \"You've selected <u>[label]<\/u>.\".p() + \r\n    \"Your penalty for losing will be randomly selected.[noRandomCieExt]\" \r\n  ],\r\n  noRandomCieExt: [\r\n    \"\".br() + \"(You must select a CEI Kink for \" + \"Eat It\".bold() + \" to be selected.)\" \r\n  ],\r\n  lossPenaltyRandomPrompt: [\r\n    \"Selecting loser penalty...\",\r\n    \"You lose.  Choosing your penalty...\",\r\n  ],\r\n\r\n  \/\/ *** New since 1.14.0 ***\r\n  \r\n  cumTease1: [\r\n    \/\/ \"Get ready to blow your load!\",\r\n  ],\r\n\r\n  cumTease2: [\r\n    \"Get ready to blow your load!\",\r\n    \"It's almost time to cum!  Get ready!\",\r\n  ],\r\n\r\n  settingKinksAnalPrompt: [\r\n    \"Select the toys you'll use for anal play.\",\r\n  ],\r\n\r\n  settingKinksAnalToyEnable: [\r\n    \"You've \" + \"enabled\".underline() + \" [name] for anal play.\".br()\r\n    + \"Make sure it's ready to shove up your ass at a moment's notice.\",\r\n  ],\r\n  settingKinksAnalToyDisable: [\r\n    \"You've \" + \"disabled\".underline() + \" [name] for anal play.\".br()\r\n    + \"You won't be asked to stick it in your hole.\",\r\n  ],\r\n\r\n  analPlugStart: [ \/\/ Tell player to insert their plug toy\r\n    \"Insert your [toyNameLower]!\",\r\n    \"Time to use your [toyNameLower]!\",\r\n    \"Lube up your [toyNameLower] and slide it in!\",\r\n  ],\r\n\r\n  analPlugStartPass: [ \/\/ Tell player to insert their plug toy\r\n    \"Great! Now leave it in while stroking![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n    \"Perfect! Hold it tight while stroking![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n  ],\r\n\r\n  analPlugEnd: [ \/\/ Tell player to pull their plug toy\r\n    \"Remove your [toyNameLower]![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n    \"Pull your [toyNameLower] out![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n  ],\r\n\r\n  analPlugEndPass: [ \/\/ Player pulled thier plug toy\r\n    \"Let your hole relax while stroking!\",\r\n    \"Now back to simple stroking!\",\r\n  ],\r\n\r\n  analDildoStart: [ \/\/ Tell player to insert their dildo toy\r\n    \"Put your [toyNameLower] in your hole!\",\r\n    \"Insert your [toyNameLower]!\",\r\n    \"Lube up your [toyNameLower] and slide it in!\",\r\n  ],\r\n\r\n  analDildoStartPass: [ \/\/ Tell player to insert their dildo toy\r\n    \"That's it... Fuck yourself to the beat![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n    \"Now every time your hear the beat, fuck your hole![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n  ],\r\n\r\n  analDildoEnd: [ \/\/ Tell player to pull their dildo toy\r\n    \"Pull out your [toyNameLower]![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n    \"Pull your [toyNameLower] out![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n  ],\r\n\r\n  analDildoEndPass: [ \/\/ Player pulled thier dildo toy\r\n    \"Let your hole relax while you stroke!\",\r\n    \"Now back to simple stroking!\",\r\n  ],\r\n\r\n  analToyFail: [ \/\/ Player wouldn't use thier toy\r\n    \"Then don't tell me you have a [toyNameLower] to use next time![setPattern|+AF][setRoundBpmDivisor|1]\",\r\n    \"Why did tease me with your [toyNameLower] then?[setPattern|+AF][setRoundBpmDivisor|1]\",\r\n  ],\r\n\r\n  strokePlusAnal: [\r\n    \"Fuck your hole with every 4th beat while you stroke![setPattern|+AF+AF+AF+BF]\",    \r\n    \"Fuck yourself with every 3rd beat while stroking![setPattern|+AF+AF+BF]\",     \r\n    \"Fuck then stroke on every other beat![setPattern|+AF+BF]\",  \r\n    \"Stroke on every beat, but use your [toyNameLower] on every 3rd!\"\r\n    +\"[setPattern|+AF+AF+BF]\",\r\n    \"Stroke to the beat while plunging your [toyNameLower] as deep as you can!\"\r\n    +\"[setPattern|+AF+AF+AF+AF+BF]\",\r\n  ],\r\n\r\n  strokePlusAnalDone: [\r\n    \"Now continue fucking yourself to the beat![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n    \"Keep fucking yourself while we play![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n  ],\r\n\r\n  justAnal: [\r\n    \"Fuck your hole [faps] times to beat![setPattern|+BF]\",    \r\n    \"Push your [toyNameLower] in and out on every beat![setPattern|+BF]\",\r\n    \"Push your [toyNameLower] in on every beat, until it's as deep as you can take it![setPattern|+BF]\",\r\n  ],\r\n\r\n  justAnalDone: [\r\n    \"Great! Now continue fucking yourself to the beat![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n    \"Well done! Keep fucking yourself while we play![setPattern|+BF][setRoundBpmDivisor|2]\",\r\n  ],\r\n\r\n  edgeAnal: [ \/\/ Tell player to edge with anal\r\n    \"Get right to the edge while teasing your ass, but don't cum!\",\r\n    \"Go on, fuck your hole and edge for me!\",\r\n    \"Get as close as you can!\",\r\n    \"Keep stroking and fucking until you edge!\",\r\n    \"Get right to the edge for me.  Don't go over!\",\r\n    \"Stroke until you almost explode, but don't!\",\r\n    \"Do what you need to do to reach that edge!\",\r\n  ],\r\n  edgeAnalRide: [ \/\/ Tell player to ride edge with anal\r\n    \"Now ride that edge...[playMoan|moan]\",\r\n    \"Now stay on the edge![playMoan|moan]\",\r\n    \"Keep that edge, but don't lose control![playMoan|moan]\",\r\n    \"Keep edging![playMoan|moan]\",\r\n    \"Mmmmm.  Now ride it![playMoan|moan]\",\r\n    \"Don't lose that edge![playMoan|moan]\",\r\n  ],\r\n  edgeAnalRideCont: [ \/\/ Ecourage player to continue edging with anal\r\n    \"That's it, keep on riding.[playMoan|moan]\",\r\n    \"Just like that... Mmmmm...[playMoan|moan]\",\r\n    \"Stay as close as you can for me...[playMoan|moan]\",\r\n    \"Don't stop riding that edge...[playMoan|moan]\",\r\n    \"Yes, just like that...[playMoan|moan]\",\r\n    \"Keep going...[playMoan|moan]\",\r\n\/\/    \"MMmmmm... I love taste of precum...\",\r\n\/\/    \"That's it, let that precum flow...\",\r\n    \"Get even closer for me...[playMoan|moan]\",\r\n  ],\r\n\r\n});\r\n"}},{"eval":{"script":"\/\/ Override button verbiage\r\n"}},{"eval":{"script":"\/\/ Load default verbiage overrides for all \"Cum\" rounds\r\nif (game.isCumRound()) {\r\n  game.setVerbiage({\r\n    \/\/  Nothing really different for cum rounds.\r\n    \/\/  Just here as a place holder in-case there is something\r\n    \/\/  you want to override.\r\n  });\r\n}"}},{"eval":{"script":"\/\/ Load default verbiage overrides for all \"Win to Cum\" rounds\r\nif (game.isWinToCumRound()) {\r\n  game.setVerbiage({\r\n    bj_p: [ \/\/ Don't talk about earning rest points if winToCum\r\n      \/\/ \"You got blackjack!  You earn another rest!\",\r\n      \/\/ \"Blackjack! Another rest point!\",\r\n      \/\/ \"Yay! blackjack! Have another rest point!\",\r\n      \"You got blackjack!\",\r\n      \"Blackjack! You win this hand!\",\r\n      \"Yay! blackjack! Way to go!\"\r\n    ]\r\n  });\r\n}"}},{"eval":{"script":"returnToCaller();"}}],"blank":[{"image":{"locator":"file:blank.jpg"}}],"settings-loss-penalty":[{"eval":{"script":"\/*--auto-magpie-merge:message:reset1 *\/"}},{"eval":{"script":"var _rsm = currentPageResetMessage()"}},{"eval":{"script":"var _ss = currentPageSettings()"}},{"eval":{"script":"var _ls = currentPageLS()"}},{"if":{"condition":"game.settingMessage","commands":[{"say":{"label":"<p><eval>game.settingMessage<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.settingMessage = null"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>gsLabelOn(_ss[0])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[0])"}}],"visible":"$gsShowOn(_ss[0])"},{"label":"<eval>gsLabelOff(_ss[0])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[0])"}}],"visible":"$gsShowOff(_ss[0])"},{"label":"<eval>gsLabelOn(_ss[1])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[1])"}}],"visible":"$gsShowOn(_ss[1])"},{"label":"<eval>gsLabelOff(_ss[1])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[1])"}}],"visible":"$gsShowOff(_ss[1])"},{"label":"<eval>gsLabelOn(_ss[2])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[2])"}}],"visible":"$gsShowOn(_ss[2])"},{"label":"<eval>gsLabelOff(_ss[2])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[2])"}}],"visible":"$gsShowOff(_ss[2])"},{"label":"<eval>gsLabelOn(_ss[3])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[3])"}}],"visible":"$gsShowOn(_ss[3])"},{"label":"<eval>gsLabelOff(_ss[3])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[3])"}}],"visible":"$gsShowOff(_ss[3])"},{"label":"<eval>gsLabelOn(_ss[4])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[4])"}}],"visible":"$gsShowOn(_ss[4])"},{"label":"<eval>gsLabelOff(_ss[4])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[4])"}}],"visible":"$gsShowOff(_ss[4])"},{"label":"<eval>gsLabelOn(_ss[5])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[5])"}}],"visible":"$gsShowOn(_ss[5])"},{"label":"<eval>gsLabelOff(_ss[5])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[5])"}}],"visible":"$gsShowOff(_ss[5])"},{"label":"<eval>gsLabelOn(_ss[6])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[6])"}}],"visible":"$gsShowOn(_ss[6])"},{"label":"<eval>gsLabelOff(_ss[6])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[6])"}}],"visible":"$gsShowOff(_ss[6])"},{"label":"<eval>gsLabelOn(_ss[7])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[7])"}}],"visible":"$gsShowOn(_ss[7])"},{"label":"<eval>gsLabelOff(_ss[7])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[7])"}}],"visible":"$gsShowOff(_ss[7])"},{"label":"<eval>gsLabelOn(_ss[8])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[8])"}}],"visible":"$gsShowOn(_ss[8])"},{"label":"<eval>gsLabelOff(_ss[8])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[8])"}}],"visible":"$gsShowOff(_ss[8])"},{"label":"<eval>gsLabelOn(_ss[9])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[9])"}}],"visible":"$gsShowOn(_ss[9])"},{"label":"<eval>gsLabelOff(_ss[9])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[9])"}}],"visible":"$gsShowOff(_ss[9])"},{"label":"Reset","commands":[{"eval":{"script":"resetSettings(_ls);\ngame.settingMessage = mergeObject(_rsm, game);\npages.goto(pages.getCurrentPageId());"}}],"visible":"$hasChangedSettings(_ls)"},{"label":"Done","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}],"game-lost-cei":[{"if":{"condition":"!game.cumCount","commands":[{"image":{"locator":"gallery:9ec8abe7-ce8e-433b-a18d-198f8af3e6a1\/*"}},{"say":{"label":"<p>Get your legs above your head.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>Get to the edge.<\/p>","mode":"autoplay","allowSkip":true}},{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005430"}},{"say":{"label":"<p>Point your cock directly at your open mouth.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>Now cum!<\/p>","mode":"autoplay","allowSkip":true}},{"image":{"locator":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990495"}},{"say":{"label":"<p>Empty every last drop in your mouth.<\/p>","mode":"pause"}},{"eval":{"script":"returnToCaller()"}}],"elseCommands":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005363"}},{"say":{"label":"<p>Hands off your cock!<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>Let it dribble out.<\/p>","mode":"autoplay","allowSkip":true}},{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005387"}},{"say":{"label":"<p>Now lick it up from wherever it landed, and swallow.<\/p>","mode":"pause"}},{"eval":{"script":"returnToCaller()"}}]}}],"game-lost-rand":[{"eval":{"script":"game.doRandomLossPenalty()"}}],"game-lost-deny":[{"if":{"condition":"!game.cumCount","commands":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005372"}},{"say":{"label":"<p>Stop!  Hands off your cock!<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>You don&#39;t get to cum this time!<\/p>","mode":"pause"}},{"eval":{"script":"returnToCaller()"}}],"elseCommands":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005387"}},{"say":{"label":"<p>Hands off your cock!<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>Let it dribble out.<\/p>","mode":"pause"}},{"eval":{"script":"returnToCaller()"}}]}}],"game-lost-ruin":[{"if":{"condition":"!game.cumCount","commands":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005451"}},{"say":{"label":"<p>Get to the edge.<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>Now push yourself just over...<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>Hand off!<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>Let it dribble out...<\/p>","mode":"pause"}},{"eval":{"script":"returnToCaller()"}}],"elseCommands":[{"image":{"locator":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005463"}},{"say":{"label":"<p>Hands off your cock!<\/p>","mode":"autoplay","allowSkip":true}},{"say":{"label":"<p>Let it dribble out.<\/p>","mode":"pause"}},{"eval":{"script":"returnToCaller()"}}]}}],"settings-kinks-anal":[{"eval":{"script":"\/*--auto-magpie-merge:message:reset1 *\/"}},{"eval":{"script":"var _rsm = currentPageResetMessage()"}},{"eval":{"script":"var _ss = currentPageSettings()"}},{"eval":{"script":"var _ls = currentPageLS()"}},{"if":{"condition":"game.settingMessage","commands":[{"say":{"label":"<p><eval>game.settingMessage<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.settingMessage = null"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>gsLabelOn(_ss[0])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[0])"}}],"visible":"$gsShowOn(_ss[0])"},{"label":"<eval>gsLabelOff(_ss[0])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[0])"}}],"visible":"$gsShowOff(_ss[0])"},{"label":"<eval>gsLabelOn(_ss[1])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[1])"}}],"visible":"$gsShowOn(_ss[1])"},{"label":"<eval>gsLabelOff(_ss[1])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[1])"}}],"visible":"$gsShowOff(_ss[1])"},{"label":"<eval>gsLabelOn(_ss[2])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[2])"}}],"visible":"$gsShowOn(_ss[2])"},{"label":"<eval>gsLabelOff(_ss[2])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[2])"}}],"visible":"$gsShowOff(_ss[2])"},{"label":"<eval>gsLabelOn(_ss[3])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[3])"}}],"visible":"$gsShowOn(_ss[3])"},{"label":"<eval>gsLabelOff(_ss[3])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[3])"}}],"visible":"$gsShowOff(_ss[3])"},{"label":"<eval>gsLabelOn(_ss[4])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[4])"}}],"visible":"$gsShowOn(_ss[4])"},{"label":"<eval>gsLabelOff(_ss[4])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[4])"}}],"visible":"$gsShowOff(_ss[4])"},{"label":"<eval>gsLabelOn(_ss[5])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[5])"}}],"visible":"$gsShowOn(_ss[5])"},{"label":"<eval>gsLabelOff(_ss[5])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[5])"}}],"visible":"$gsShowOff(_ss[5])"},{"label":"<eval>gsLabelOn(_ss[6])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[6])"}}],"visible":"$gsShowOn(_ss[6])"},{"label":"<eval>gsLabelOff(_ss[6])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[6])"}}],"visible":"$gsShowOff(_ss[6])"},{"label":"<eval>gsLabelOn(_ss[7])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[7])"}}],"visible":"$gsShowOn(_ss[7])"},{"label":"<eval>gsLabelOff(_ss[7])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[7])"}}],"visible":"$gsShowOff(_ss[7])"},{"label":"<eval>gsLabelOn(_ss[8])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[8])"}}],"visible":"$gsShowOn(_ss[8])"},{"label":"<eval>gsLabelOff(_ss[8])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[8])"}}],"visible":"$gsShowOff(_ss[8])"},{"label":"<eval>gsLabelOn(_ss[9])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[9])"}}],"visible":"$gsShowOn(_ss[9])"},{"label":"<eval>gsLabelOff(_ss[9])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[9])"}}],"visible":"$gsShowOff(_ss[9])"},{"label":"Reset","commands":[{"eval":{"script":"resetSettings(_ls);\ngame.settingMessage = mergeObject(_rsm, game);\npages.goto(pages.getCurrentPageId());"}}],"visible":"$hasChangedSettings(_ls)"},{"label":"Done","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}],"win-tease":[{"eval":{"script":"if (!loadCumTeaseImage()) {\r\n  \/\/ We've loaded a cumtease image\r\n  window.message1 = game.text('cumTease1')\r\n  window.message2 = game.text('cumTease2')\r\n  game.didCumTease = true\r\n  if (game.winCheckTeaseBpm) {\r\n    if (game.winCheckTeasePattern) {\r\n      game.setPattern(game.winCheckTeasePattern)\r\n    }\r\n    beats.start(game.winCheckTeaseBpm)\r\n  } else {\r\n    beats.stopAll()\r\n  }\r\n}"}},{"if":{"condition":"game.winCheckCumSkip","commands":[{"notification.create":{"buttonCommands":[{"eval":{"script":"game.doStartWin()"}}],"buttonLabel":"\ud83d\udc97 I'm ready! \ud83d\udc97","id":"tease-ready"}}],"elseCommands":[]}},{"timer":{"duration":"$game.winCheckCumTease * 1000","isAsync":true,"commands":[{"notification.remove":{"id":"tease-ready"}},{"eval":{"script":"game.doStartWin()"}}]}},{"if":{"condition":"message1","commands":[{"say":{"label":"<p><eval>message1<\/eval><\/p>","mode":"autoplay","allowSkip":true}}]}},{"if":{"condition":"message2","commands":[{"say":{"label":"<p><eval>message2<\/eval><\/p>","mode":"instant"}}]}}],"settings-stroking":[{"eval":{"script":"\/*--auto-magpie-merge:message:reset1 *\/"}},{"eval":{"script":"var _rsm = currentPageResetMessage()"}},{"eval":{"script":"var _ss = currentPageSettings()"}},{"eval":{"script":"var _ls = currentPageLS()"}},{"if":{"condition":"game.settingMessage","commands":[{"say":{"label":"<p><eval>game.settingMessage<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.settingMessage = null"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>gsLabelOn(_ss[0])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[0])"}}],"visible":"$gsShowOn(_ss[0])"},{"label":"<eval>gsLabelOff(_ss[0])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[0])"}}],"visible":"$gsShowOff(_ss[0])"},{"label":"<eval>gsLabelOn(_ss[1])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[1])"}}],"visible":"$gsShowOn(_ss[1])"},{"label":"<eval>gsLabelOff(_ss[1])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[1])"}}],"visible":"$gsShowOff(_ss[1])"},{"label":"<eval>gsLabelOn(_ss[2])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[2])"}}],"visible":"$gsShowOn(_ss[2])"},{"label":"<eval>gsLabelOff(_ss[2])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[2])"}}],"visible":"$gsShowOff(_ss[2])"},{"label":"<eval>gsLabelOn(_ss[3])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[3])"}}],"visible":"$gsShowOn(_ss[3])"},{"label":"<eval>gsLabelOff(_ss[3])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[3])"}}],"visible":"$gsShowOff(_ss[3])"},{"label":"<eval>gsLabelOn(_ss[4])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[4])"}}],"visible":"$gsShowOn(_ss[4])"},{"label":"<eval>gsLabelOff(_ss[4])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[4])"}}],"visible":"$gsShowOff(_ss[4])"},{"label":"<eval>gsLabelOn(_ss[5])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[5])"}}],"visible":"$gsShowOn(_ss[5])"},{"label":"<eval>gsLabelOff(_ss[5])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[5])"}}],"visible":"$gsShowOff(_ss[5])"},{"label":"<eval>gsLabelOn(_ss[6])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[6])"}}],"visible":"$gsShowOn(_ss[6])"},{"label":"<eval>gsLabelOff(_ss[6])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[6])"}}],"visible":"$gsShowOff(_ss[6])"},{"label":"<eval>gsLabelOn(_ss[7])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[7])"}}],"visible":"$gsShowOn(_ss[7])"},{"label":"<eval>gsLabelOff(_ss[7])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[7])"}}],"visible":"$gsShowOff(_ss[7])"},{"label":"<eval>gsLabelOn(_ss[8])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[8])"}}],"visible":"$gsShowOn(_ss[8])"},{"label":"<eval>gsLabelOff(_ss[8])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[8])"}}],"visible":"$gsShowOff(_ss[8])"},{"label":"<eval>gsLabelOn(_ss[9])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[9])"}}],"visible":"$gsShowOn(_ss[9])"},{"label":"<eval>gsLabelOff(_ss[9])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[9])"}}],"visible":"$gsShowOff(_ss[9])"},{"label":"Reset","commands":[{"eval":{"script":"resetSettings(_ls);\ngame.settingMessage = mergeObject(_rsm, game);\npages.goto(pages.getCurrentPageId());"}}],"visible":"$hasChangedSettings(_ls)"},{"label":"Done","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}],"settings-difficulty-level":[{"eval":{"script":"\/*--auto-magpie-merge:message:reset1 *\/"}},{"eval":{"script":"var _rsm = currentPageResetMessage()"}},{"eval":{"script":"var _ss = currentPageSettings()"}},{"eval":{"script":"var _ls = currentPageLS()"}},{"if":{"condition":"game.settingMessage","commands":[{"say":{"label":"<p><eval>game.settingMessage<\/eval><\/p>","mode":"instant"}},{"eval":{"script":"game.settingMessage = null"}}]}},{"eval":{"script":"\/*--auto-magpie-merge:choice:options2 *\/"}},{"choice":{"options":[{"label":"<eval>gsLabelOn(_ss[0])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[0])"}}],"visible":"$gsShowOn(_ss[0])"},{"label":"<eval>gsLabelOff(_ss[0])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[0])"}}],"visible":"$gsShowOff(_ss[0])"},{"label":"<eval>gsLabelOn(_ss[1])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[1])"}}],"visible":"$gsShowOn(_ss[1])"},{"label":"<eval>gsLabelOff(_ss[1])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[1])"}}],"visible":"$gsShowOff(_ss[1])"},{"label":"<eval>gsLabelOn(_ss[2])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[2])"}}],"visible":"$gsShowOn(_ss[2])"},{"label":"<eval>gsLabelOff(_ss[2])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[2])"}}],"visible":"$gsShowOff(_ss[2])"},{"label":"<eval>gsLabelOn(_ss[3])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[3])"}}],"visible":"$gsShowOn(_ss[3])"},{"label":"<eval>gsLabelOff(_ss[3])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[3])"}}],"visible":"$gsShowOff(_ss[3])"},{"label":"<eval>gsLabelOn(_ss[4])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[4])"}}],"visible":"$gsShowOn(_ss[4])"},{"label":"<eval>gsLabelOff(_ss[4])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[4])"}}],"visible":"$gsShowOff(_ss[4])"},{"label":"<eval>gsLabelOn(_ss[5])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[5])"}}],"visible":"$gsShowOn(_ss[5])"},{"label":"<eval>gsLabelOff(_ss[5])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[5])"}}],"visible":"$gsShowOff(_ss[5])"},{"label":"<eval>gsLabelOn(_ss[6])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[6])"}}],"visible":"$gsShowOn(_ss[6])"},{"label":"<eval>gsLabelOff(_ss[6])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[6])"}}],"visible":"$gsShowOff(_ss[6])"},{"label":"<eval>gsLabelOn(_ss[7])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[7])"}}],"visible":"$gsShowOn(_ss[7])"},{"label":"<eval>gsLabelOff(_ss[7])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[7])"}}],"visible":"$gsShowOff(_ss[7])"},{"label":"<eval>gsLabelOn(_ss[8])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[8])"}}],"visible":"$gsShowOn(_ss[8])"},{"label":"<eval>gsLabelOff(_ss[8])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[8])"}}],"visible":"$gsShowOff(_ss[8])"},{"label":"<eval>gsLabelOn(_ss[9])<\/eval>","commands":[{"eval":{"script":"disableSetting(_ss[9])"}}],"visible":"$gsShowOn(_ss[9])"},{"label":"<eval>gsLabelOff(_ss[9])<\/eval>","commands":[{"eval":{"script":"enableSetting(_ss[9])"}}],"visible":"$gsShowOff(_ss[9])"},{"label":"Reset","commands":[{"eval":{"script":"resetSettings(_ls);\ngame.settingMessage = mergeObject(_rsm, game);\npages.goto(pages.getCurrentPageId());"}}],"visible":"$hasChangedSettings(_ls)"},{"label":"Done","commands":[{"eval":{"script":"returnToCaller();"}}]}]}}]},"galleries":{"a0b1e3c8-a627-4b9c-8f78-65d0ff26bc55":{"name":"misc","images":[{"id":990243,"hash":"4fdc20ae26d02843f0bed3c838b4f8caec7f5c3e","size":14499,"width":250,"height":203}]},"eba2f303-dd02-4b9e-923a-8b7d9632a505":{"name":"Melody Marks - The Girl Orgasm - Nubiles","images":[{"id":990403,"hash":"0578c46b5f972cd568db6d0e0137893936394308","size":125399,"width":854,"height":1280},{"id":990404,"hash":"f45a66ecc05be9438fb91415735d048769f0c06a","size":117197,"width":854,"height":1280},{"id":990405,"hash":"db2111d98a7e1882db6c88e0f886a21c40fd8b20","size":119693,"width":854,"height":1280},{"id":990406,"hash":"5d6ec86b28088e113e42920d788ae76bdc03f06a","size":180004,"width":854,"height":1280},{"id":990407,"hash":"0f9c2c9f20f4c7c55dd4751c0505199fe7d8476a","size":139962,"width":854,"height":1280},{"id":990408,"hash":"1b796e849831972e6eb476ecdd032692d9ed9aca","size":126967,"width":854,"height":1280},{"id":990409,"hash":"ce897d37c9f5d61eabb82711dcb84379ffa19eef","size":208799,"width":854,"height":1280},{"id":990410,"hash":"59c18978e5cdd292b67c0cf0edf753d464f90fb2","size":141276,"width":854,"height":1280},{"id":990411,"hash":"88f5a11dfc234cee72df90fe9d94740d46b91801","size":123306,"width":854,"height":1280},{"id":990412,"hash":"0571f1c45dab27c9941568f61eab6387df531cfd","size":115207,"width":854,"height":1280},{"id":990413,"hash":"4a690b6393cd9bbdac23f84e7ab5a401e0e77121","size":116694,"width":854,"height":1280},{"id":990414,"hash":"705ce330d823e0c455b0ab5a92617ed9cfa7cdf6","size":156175,"width":854,"height":1280},{"id":990415,"hash":"3029be5b8a47fc502501f2c5246ae27e00536483","size":99306,"width":854,"height":1280},{"id":990416,"hash":"477f2da9a7d8aeb3c94b0c451a4b0ebb27b17013","size":177173,"width":854,"height":1280},{"id":990417,"hash":"ae92a31654e729cce9970996a840cb9f1943fe21","size":208940,"width":854,"height":1280},{"id":990418,"hash":"a672fae72b83ad020452bd69a65c5b4b2ff43aef","size":115674,"width":1280,"height":854},{"id":990419,"hash":"9495cd2c50cd2b11bf3c318e006d483f03f603c0","size":106726,"width":854,"height":1280},{"id":990420,"hash":"9e50ebc8a2825b270a39c025d71ed502e7583180","size":104615,"width":854,"height":1280},{"id":990421,"hash":"83623ad67cfd48a6e17a29b2c326d66dd14eeaa4","size":104438,"width":854,"height":1280},{"id":990422,"hash":"f3caae7c90ff12fa577380a7375529791492913e","size":115529,"width":854,"height":1280},{"id":990423,"hash":"95652699ab678ebb60098c49a905659488dd7146","size":109822,"width":854,"height":1280},{"id":990424,"hash":"470c5de8e34f0c043a6e050f7e9b1e409bb9b164","size":153546,"width":1280,"height":854},{"id":990425,"hash":"d2e91c274721abbfcc0f5ab5fc4aa1440ed42498","size":113663,"width":854,"height":1280},{"id":990426,"hash":"1d0576fed7dc5113e72bcd004cb3cd4a5a9fc7bf","size":180923,"width":854,"height":1280},{"id":990427,"hash":"8d114c334019abbcd75367e5439d50bf6a79a463","size":128341,"width":854,"height":1280},{"id":990428,"hash":"f64b377004ba0ccadb29c41558776409c4296b19","size":110670,"width":854,"height":1280},{"id":990429,"hash":"cb50112bb137dd331d1dfa6abba0dd8fb48dda9b","size":111040,"width":854,"height":1280},{"id":990430,"hash":"27d094b21707ec5987513986118b753af6133c1a","size":130013,"width":854,"height":1280},{"id":990431,"hash":"f472c6129b9c1ef5eb41c37a130297520a255ca4","size":114324,"width":854,"height":1280},{"id":990432,"hash":"ff532fca730bf466a313ae5c8727e222d0d7ef9b","size":111724,"width":854,"height":1280},{"id":990433,"hash":"9c5a9771c8b5f920636b4375bdef42c75a7f81a4","size":115674,"width":854,"height":1280},{"id":990434,"hash":"2c085151cde2d4876a25368f372c9f9661b75eb7","size":138463,"width":1280,"height":854},{"id":990435,"hash":"4ba84fd3769bffee093c449487cf1c07d1dc8bd1","size":153784,"width":1280,"height":854},{"id":990436,"hash":"027bf80c7167ce8b218cbe32b192b9e3d66204cb","size":120164,"width":854,"height":1280},{"id":990437,"hash":"a4d78184aca3e4a3dbe3aa31d16b245b9b9d3f86","size":117528,"width":854,"height":1280},{"id":990438,"hash":"12133df322cc1f8c18a3cf571a1f7feb717a3a87","size":115309,"width":854,"height":1280},{"id":990439,"hash":"9c7283817f6b8fbc0490a559ad4bcd2618ad5a84","size":112235,"width":854,"height":1280},{"id":990440,"hash":"3354a2e87217502b97b5afcb9a6582880ba2352b","size":90771,"width":1280,"height":854},{"id":990441,"hash":"026479295542edc182d3a06419bccbb031ae50c8","size":125530,"width":854,"height":1280},{"id":990442,"hash":"6e60356541395e56e49644e7e7fc1f45bd75f27c","size":111041,"width":854,"height":1280},{"id":990443,"hash":"d73c75d57b2b41081eb10ffc10ae434973b9ba58","size":161470,"width":1280,"height":854},{"id":990444,"hash":"1b451491c54ed756c349aba1ef50c2ff846c1315","size":122271,"width":854,"height":1280},{"id":990445,"hash":"5e39eb5e6eb16265bf37a2bc02d9dadb1f830b92","size":119303,"width":1280,"height":854},{"id":990446,"hash":"55e24321a66bd5ab27b765f7b3ef384c37404af3","size":130305,"width":1280,"height":854},{"id":990447,"hash":"e2a2e61b0e8f6307fa32d54977256d9fffccee39","size":150590,"width":1280,"height":854},{"id":990448,"hash":"83f96576426b4d0d9784fec999385590fde9c5c4","size":124530,"width":854,"height":1280},{"id":990449,"hash":"d610bea346f15a51290750ca0726fb9b02a94d27","size":131774,"width":1280,"height":854},{"id":990450,"hash":"0d69a46b09c4d0860a1d076b61185102f3f67656","size":120318,"width":854,"height":1280},{"id":990451,"hash":"4fec667b32148e25a8ceba965bdb52fdc5c5c618","size":131097,"width":854,"height":1280},{"id":990452,"hash":"e04b2d9b98a36a826757662e2d2c56fd56e22f18","size":150967,"width":854,"height":1280},{"id":990453,"hash":"9e63d6d150f2bff27a5965e619418013ea71b226","size":119916,"width":854,"height":1280},{"id":990454,"hash":"bc9cdc01502345b6d3f7e81fb7aa5d06a2820f61","size":111100,"width":854,"height":1280},{"id":990455,"hash":"3816d6237dc93715895636ed6310c948689907da","size":156117,"width":1280,"height":854},{"id":990456,"hash":"1de56437c4dcd0fdf16255471dc71b0384d6ecb6","size":111613,"width":854,"height":1280},{"id":990457,"hash":"d1d48180d444aeae23f50459f5a2717d2065299f","size":129672,"width":854,"height":1280},{"id":990458,"hash":"0707e8324f059ef17f972062b41ba67d1fcda7af","size":123735,"width":854,"height":1280},{"id":990459,"hash":"49adfa8f0a970e9a7ca2173e6d3be390c98b0e2b","size":114910,"width":854,"height":1280},{"id":990460,"hash":"e4d4f8a7128bdc18f6f53be9878262425d296a32","size":137262,"width":854,"height":1280},{"id":990461,"hash":"e3fd95d2039d1e3c55c3f51de32f00eab0dc9b04","size":96641,"width":854,"height":1280},{"id":990462,"hash":"af2a58ecdc40a668aae74b6d223d7555e1173873","size":178816,"width":854,"height":1280},{"id":990463,"hash":"ec6637b884be6123b0c67780244698a11c07f71a","size":165410,"width":854,"height":1280},{"id":990464,"hash":"ec3b22cd1dd1af66c6a81b17f51100f5a72497f4","size":123615,"width":854,"height":1280},{"id":990465,"hash":"6ec75875a928b1f62deb6b5a26a72c26b6067619","size":133807,"width":854,"height":1280},{"id":990466,"hash":"61e37646e20d3d24346127149060f7bb11eb27f4","size":124249,"width":854,"height":1280},{"id":990467,"hash":"89053c2b1b23fe330f6c904a2faa3cfb23a4bf24","size":116920,"width":854,"height":1280},{"id":990468,"hash":"de0b95a3a611ea8c60fef3c744886a321bf7395b","size":127210,"width":854,"height":1280},{"id":990469,"hash":"9349173d2b4e964817ee64d7c428a4a8194da183","size":79968,"width":1280,"height":854},{"id":990470,"hash":"e8fe96b5a8d361ea6b798532ff784890a129f998","size":121373,"width":854,"height":1280},{"id":990471,"hash":"ca1dded858801717eb54153ec639bdf261e05a34","size":97582,"width":1280,"height":854},{"id":990472,"hash":"34421d0dfd91a7872cf1c901ad7d772e724e88f4","size":111508,"width":854,"height":1280},{"id":990473,"hash":"eab9cf01758992ace1fe2b431fef5212d3fc52d8","size":118522,"width":854,"height":1280},{"id":990474,"hash":"ddff6e36e0c14f3495b05473d1bd1f82374ee094","size":131203,"width":854,"height":1280},{"id":990475,"hash":"23f38e4738c00c3d2e4b868f2647e0cef61cccd3","size":128743,"width":854,"height":1280}]},"a6068f8e-6608-437f-aefb-a94f5ee782e9":{"name":"welcome","images":[{"id":990458,"hash":"0707e8324f059ef17f972062b41ba67d1fcda7af","size":123735,"width":854,"height":1280},{"id":990486,"hash":"919c8e90f53528f1cfac0b2ebc272bee09977310","size":117517,"width":853,"height":1280},{"id":1087408,"hash":"00bb1a5eb918a2d82d9596b36a2866f17ca1a504","size":382964,"width":2046,"height":1535},{"id":1087713,"hash":"b941c5961cf3e85b09d72702e3441c33dd862949","size":141036,"width":991,"height":743}]},"099cb8f1-074c-4282-a6aa-ab2cb0427a9c":{"name":"Melody Marks - Makes Me Cum","images":[{"id":990487,"hash":"1f6e36095c5dde496c9f327f3ea010e8cbe31fe3","size":103485,"width":853,"height":1280},{"id":990486,"hash":"919c8e90f53528f1cfac0b2ebc272bee09977310","size":117517,"width":853,"height":1280},{"id":990488,"hash":"dd8f14972fb0c2cc07ffdfc5e7cb87291bb0f156","size":79075,"width":853,"height":1280},{"id":990489,"hash":"34166895f175189215419bab11506d825cb44717","size":70412,"width":853,"height":1280},{"id":990490,"hash":"1c106d718e7dd3b816a689352bfc6ceb998a733f","size":87973,"width":853,"height":1280},{"id":990491,"hash":"e87369c7fe234d87c056f23e7032f6874ac0095e","size":123770,"width":853,"height":1280},{"id":990492,"hash":"f9e96c4562b998a1099213fe9d6b274a62fd4358","size":82825,"width":853,"height":1280},{"id":990493,"hash":"8ef88515c905e665f81e25961190189dae91ab61","size":142087,"width":1280,"height":853},{"id":990494,"hash":"a2b7b985e3092610590eb5a51b943ff6da3e6357","size":117188,"width":853,"height":1280},{"id":990495,"hash":"a062c3690cd6209273e7fdff655ed2a698d9d48d","size":111580,"width":853,"height":1280},{"id":990496,"hash":"ca232254a86c3e7016fe817c39dbe9d0e60fffed","size":101279,"width":1280,"height":853},{"id":990497,"hash":"c76cdc2e3dc5f5979edebbb6b7d4b214e95394f6","size":119982,"width":853,"height":1280},{"id":990498,"hash":"d7e227c56ebbeec6b1f7b179e6a1dcf8f452bacc","size":116589,"width":853,"height":1280},{"id":990499,"hash":"7bdef4a6d10e0a0d5984d435ceda0c3a45df572e","size":74528,"width":853,"height":1280},{"id":990500,"hash":"5c3cf988bb007bc955c2b6338911d83bf5f587f1","size":130074,"width":853,"height":1280},{"id":990501,"hash":"cd56e39109350bc677c28a8aa2c819a8904a64dd","size":100829,"width":853,"height":1280},{"id":990502,"hash":"6747b2b819527e43b0b8932843e2e009dfd8416c","size":107025,"width":1280,"height":853},{"id":990503,"hash":"18faec133c5c0be8eedef1b9b8dc052424dadff9","size":97808,"width":853,"height":1280},{"id":990504,"hash":"f3a92541df75cab19801bc4cee8627f923cd5149","size":77444,"width":853,"height":1280},{"id":990505,"hash":"05628681c335cdb1b3badd3f9db6ce82fbdf3ac3","size":75000,"width":853,"height":1280},{"id":990506,"hash":"83c5d454458bdb237d46a3f3111542951f1050cc","size":82210,"width":853,"height":1280},{"id":990507,"hash":"e3e7c41a1e6139f386d28aa17bb9005c9b93726b","size":96138,"width":853,"height":1280},{"id":990508,"hash":"0a7d2bc7dd30adf878bce7ed0c0d53445930d0c9","size":121121,"width":853,"height":1280},{"id":990509,"hash":"dfeec226669b1937895adc434c2e2b6e714be9fb","size":91705,"width":853,"height":1280},{"id":990510,"hash":"8469e7813e862ef4ae0942bba0c5c06aa7cac3df","size":93191,"width":853,"height":1280},{"id":990511,"hash":"6a32762237525c9684e8950122cdf8ae4de8dcce","size":80442,"width":853,"height":1280},{"id":990512,"hash":"70a6112cf742343fdfdf54e0902cd263bda81620","size":121119,"width":853,"height":1280},{"id":990513,"hash":"94e86277853f06f684ca573de3abc99ffa330dbe","size":130805,"width":853,"height":1280},{"id":990514,"hash":"251c3f12eb9d642dc850e47c851bde4610996f70","size":92222,"width":1280,"height":853},{"id":990515,"hash":"a8d7b2b77e070af65059151f2739a340e7ea1560","size":74454,"width":853,"height":1280},{"id":990516,"hash":"ad53a3145b48505ff46e022bdb32caf65d809b95","size":79614,"width":853,"height":1280},{"id":990517,"hash":"9b7e2e4835b4dccf404023d9e7e1bf1cb58c345b","size":88832,"width":853,"height":1280},{"id":990518,"hash":"dbf442f4f9e12e51ec67881cffc11f493b177a42","size":78099,"width":853,"height":1280},{"id":990519,"hash":"04d97c6e5c8ec02aafc44e7344a40d04adfe08b4","size":68257,"width":853,"height":1280},{"id":990520,"hash":"be4386d47efdace3323a662a338f72a8f6044caa","size":131655,"width":853,"height":1280},{"id":990521,"hash":"a88d8fcb6817ca568696e95010f4fe2e940f990c","size":82152,"width":853,"height":1280},{"id":990522,"hash":"31fe62393e48181b9997accff95c8ac9272e93d1","size":129315,"width":853,"height":1280},{"id":990523,"hash":"95d50dc5d2b4f2c12ecfea71514b11bd73180293","size":104652,"width":853,"height":1280},{"id":990524,"hash":"f71c495ca3ed60fdb83ad88520f2b0058feb2fd9","size":108591,"width":1280,"height":853},{"id":990525,"hash":"3f9bb6c0cc253002c4068f459549fa9bb5b129ab","size":89169,"width":853,"height":1280},{"id":991326,"hash":"ecb4651696d03078f4adb180d1fefd550e8c194b","size":94242,"width":853,"height":1280},{"id":991327,"hash":"555f1864435693be4564d1307fe4a15b09b710b2","size":93138,"width":853,"height":1280},{"id":991328,"hash":"258dbd97a707540193fc76429469521221728b6a","size":87236,"width":853,"height":1280},{"id":991329,"hash":"3f883f2cd4e9bc64d418ce2af6b2599a7fdc4140","size":87699,"width":1280,"height":853},{"id":991330,"hash":"ecc4c9bac4cb75dd425640399b9b9012b7f7d6fe","size":99321,"width":853,"height":1280},{"id":991331,"hash":"139477e18b623cf82600cfcd264c3189a8d5c75e","size":95555,"width":853,"height":1280},{"id":991332,"hash":"c0006c288835212afb72ac58e946ddae944f8ab8","size":95811,"width":1280,"height":853},{"id":991333,"hash":"42dba8be18d18c7484604a98d019c37c159ac775","size":116147,"width":1280,"height":853},{"id":991426,"hash":"7a100ef50cff8dacb4e05859f643139f6c0356a6","size":145673,"width":1078,"height":718},{"id":991427,"hash":"6411b73bbea0c88e4abf84e7b0c60e7209089c75","size":88731,"width":853,"height":1280},{"id":991428,"hash":"8f39c55b61354f38d197f3e131671407e7b92fec","size":1109027,"width":2058,"height":3087},{"id":991429,"hash":"f4d027f7b0fe970e877214025fc87fd21e0a2655","size":887966,"width":2862,"height":3612},{"id":991430,"hash":"569ad8d890c4c504ac3ec5acad47daa72b5d5f97","size":964331,"width":3460,"height":3560}]},"3e001079-2e7f-4121-b89e-897379fc6f3c":{"name":"Melody Marks - What She's Got","images":[{"id":991108,"hash":"fc7ebaf0ef55843da29f38e2d9da16f12784e83b","size":86906,"width":854,"height":1280},{"id":991111,"hash":"bd9892f332dd4c99f0be100c4e6351d8a3678fed","size":81005,"width":854,"height":1280},{"id":991112,"hash":"de91847d4436e6746c5434d482d9cf53506cdc1f","size":81926,"width":854,"height":1280},{"id":991113,"hash":"90bd299f541761660e86cf5de19d5b8c9356ef6a","size":82601,"width":854,"height":1280},{"id":991114,"hash":"e3fa21eb3874db6b1eb453938f067e3217342cd6","size":86774,"width":854,"height":1280},{"id":991115,"hash":"3981b0ee7b2b9094d615e759dac12ff48704f0b8","size":73896,"width":854,"height":1280},{"id":991116,"hash":"4aea3629567d6b0caa35004eb3e8d39bd2fe6b5a","size":85038,"width":854,"height":1280},{"id":991117,"hash":"d2644e51ab7e53a185cbecf23af04b91052b063b","size":81204,"width":854,"height":1280},{"id":991118,"hash":"2ff2d87135f7fb3246d4f3431f5080e6bf1e1adc","size":91111,"width":854,"height":1280},{"id":991119,"hash":"e8fba2320e655ea9d546a48aaf001a924077886c","size":79268,"width":854,"height":1280},{"id":991120,"hash":"ccfc24993c58e2d0760c350164c3d910e3acf82a","size":74275,"width":854,"height":1280},{"id":991121,"hash":"0e5030674c27512523c513c87931f382b054d64f","size":74665,"width":854,"height":1280},{"id":991122,"hash":"ca9364b395d8cb6b87514c0736f20d229def9999","size":82977,"width":1280,"height":854},{"id":991123,"hash":"c2b7a56ae4da29e519cc58f3d2fd2ae84209e0b0","size":69648,"width":854,"height":1280},{"id":991124,"hash":"ed2d9f1783819b61804c2bcb4cd0be321589e440","size":79146,"width":1280,"height":854},{"id":991125,"hash":"3248474984779bd327641c3a336984615e417f7e","size":81517,"width":1280,"height":854},{"id":991126,"hash":"1457d5d663ff5486197accf536eebedf7b254c51","size":79557,"width":854,"height":1280},{"id":991127,"hash":"cad81041feda2a99e526cd2b144f44f4b056d67d","size":82797,"width":1280,"height":854},{"id":991128,"hash":"8ece4097faba0cb093718b843fbe3c12746e4b98","size":86721,"width":854,"height":1280},{"id":991129,"hash":"bd486883ad928e9c0cac1653502c0ff655f1f005","size":78229,"width":854,"height":1280},{"id":991103,"hash":"aa1f12318a99c04ab3186485a66dc9e0e6d2a63a","size":83862,"width":854,"height":1280},{"id":991130,"hash":"95b89cb6c41f0dea69c283be10dc8d2cb936f95e","size":76871,"width":854,"height":1280},{"id":991131,"hash":"6b53baa6a3d6b69640a99e7efbac8bab97988234","size":76886,"width":854,"height":1280},{"id":991110,"hash":"8f217012946e07e8e35d9a173a6a61480ed2ea80","size":73475,"width":1280,"height":854},{"id":991132,"hash":"0b3b5ba27f752381c6f8118315255677cfb76845","size":79244,"width":1280,"height":854},{"id":991133,"hash":"e3757c657688f874dadfc0a9517410c1bf76adcb","size":76225,"width":1280,"height":854},{"id":991134,"hash":"7bbb03f8edcd92b89e7c50a6efe37db943cbb5d6","size":84298,"width":1280,"height":854},{"id":991135,"hash":"0b79f4447c9d1c7f850adb39c53c8054c4178a00","size":69800,"width":854,"height":1280},{"id":991136,"hash":"2cdfc6726be99a74895ce4e03fc44550a50f1583","size":93614,"width":1280,"height":854},{"id":991137,"hash":"dfd2b4e1dd016c7526b68fc4088b351c615ca3a7","size":60535,"width":854,"height":1280},{"id":991102,"hash":"cc904bef5d3176a2f596b182e7e10ee1b1427b15","size":84959,"width":1280,"height":854},{"id":991104,"hash":"756e5797db755c221fd0b7de420abaeda6064251","size":86152,"width":1280,"height":854},{"id":991105,"hash":"2e28f124747da9b26aaa209453b90ee5b9dd361d","size":73495,"width":854,"height":1280},{"id":991138,"hash":"fd86a18bda54908bcdcd4c02886d09624cec9b95","size":69759,"width":1280,"height":854},{"id":991139,"hash":"5352acfd89a8455895e8206bb092702c6cf4dabf","size":77305,"width":1280,"height":854},{"id":991140,"hash":"71f729949d5cf999a70072d1c06f2f7dec3cc367","size":85904,"width":854,"height":1280},{"id":991141,"hash":"edb163bf7b1ed63e6442a140565959c65a763835","size":76361,"width":1280,"height":854},{"id":991142,"hash":"1256d0dd9ac571808944b59b9e1429e7b198bbe1","size":67804,"width":1280,"height":854},{"id":991143,"hash":"2e5067e0fcc332e825644885624229fee378b9aa","size":91812,"width":1280,"height":854},{"id":991144,"hash":"b454ad0eda925e9ace8249191f236091f3fe4e83","size":83571,"width":854,"height":1280},{"id":991145,"hash":"b11949debe15a43a68b744c619e61b0307a823f1","size":67350,"width":854,"height":1280},{"id":991146,"hash":"3c280b84d5e67f00b0efefd4abf43e4514eed7d0","size":85540,"width":854,"height":1280},{"id":991147,"hash":"4dcd05da61363546859fd21ffce6628cd78a5717","size":82727,"width":854,"height":1280},{"id":991148,"hash":"99d3dca7f5a8a32402cb3df80e510e8a2dad5748","size":90615,"width":854,"height":1280},{"id":991149,"hash":"03c62a3415f0afbe135e735f2507d603cb2ab472","size":89328,"width":1280,"height":854},{"id":991150,"hash":"2fd6b32e0a8b55d58e8ff5dbb21296ccdae20b65","size":74512,"width":854,"height":1280},{"id":991151,"hash":"8f7a30e2a0b3479fb39a9d4c2efab870b42ee63b","size":77606,"width":854,"height":1280},{"id":991152,"hash":"758a0fbdaebb9967e54edf7a6c485a9ddd0193c3","size":91459,"width":1280,"height":854},{"id":991153,"hash":"643f040152b20e73d0a4df74771c49332d3c497e","size":76314,"width":1280,"height":854},{"id":991154,"hash":"c50e6cc5dc8c837a232d175191326cde0180d72a","size":87024,"width":854,"height":1280},{"id":991155,"hash":"95e58b32d2bcc3f2ccd3f43ffcac4163eb5246ee","size":66756,"width":854,"height":1280},{"id":991156,"hash":"e3faa424fec8b9a1853542c6756714842eb7d8c3","size":71606,"width":854,"height":1280},{"id":991157,"hash":"21d003d3473c6efde62cddb77a520ec697ec0522","size":71102,"width":1280,"height":854},{"id":991158,"hash":"664fafaabf4dffdbe5793aa67f17464e654d58ea","size":74666,"width":1280,"height":854},{"id":991159,"hash":"d5e49228f3dee35070f5ea9aba71d0f246c9cd49","size":73495,"width":1280,"height":854},{"id":991160,"hash":"952e27c07593acebcf3537bd396dbe123eed8f0c","size":75980,"width":854,"height":1280},{"id":991101,"hash":"209af6763a39bab37a6de05a592840e75069d861","size":65410,"width":1280,"height":854},{"id":991106,"hash":"00d924a88e204dde1ff03186a3fbe2cdd9460eb2","size":90369,"width":854,"height":1280},{"id":991107,"hash":"31dca2398ac86e03d9352e4c437ff796e1b5cef2","size":73278,"width":854,"height":1280},{"id":991109,"hash":"8ad1efb366f976b1a2d1d433f1d5265e74095e39","size":82810,"width":1280,"height":854},{"id":991161,"hash":"17ba54672a6c8c4b144b757a2e3721175d95d8df","size":88847,"width":1280,"height":854},{"id":991162,"hash":"31a252b3a7fd5513d0bfde5010aa8b7310c91635","size":86302,"width":1280,"height":854},{"id":991163,"hash":"5301929eed95259ab1642a2cb47272b3ed94ab9f","size":79444,"width":854,"height":1280},{"id":991164,"hash":"14a4456c5d8f8db9b5f658c03b54679d38450400","size":79877,"width":1280,"height":854},{"id":991165,"hash":"38e07eb67ec62dfe61dc5cb6356e2b2b38471e4b","size":84627,"width":854,"height":1280},{"id":991166,"hash":"3f5ede4781bbb4cfec256164e413e9c12b82d49a","size":54572,"width":854,"height":1280},{"id":991167,"hash":"4441d11317ebae951c25c41ff9d66b63d91ec13c","size":93395,"width":1280,"height":854},{"id":991168,"hash":"cdceb141e76445987e66d1dad66ac595ddf6786e","size":81550,"width":854,"height":1280},{"id":991169,"hash":"2d0b20ec4e6ce6898f77ebcc5f0d63c0ba2c3880","size":70504,"width":1280,"height":854},{"id":991170,"hash":"5b7de45d9c2d78bc2f381a089feb8c98a3553b36","size":77689,"width":854,"height":1280},{"id":991171,"hash":"d6e34519801f4a6dc5850e7e1eb02302a5754207","size":70321,"width":854,"height":1280},{"id":991172,"hash":"bfb5110cde291644b817f0add68e7174c8461c15","size":74051,"width":1280,"height":854}]},"ce6e3374-f241-4b94-8e74-877d319f3613":{"name":"Melody Marks - Pleasing Her Pussy","images":[{"id":991173,"hash":"029390c72badd73d9612c541b0e7ed360b166fbc","size":109697,"width":854,"height":1280},{"id":991174,"hash":"e1909916ec8c74d67a0925b640f34172b89516aa","size":89051,"width":854,"height":1280},{"id":991175,"hash":"7425e6a61da01bdc53a18685eecc42e029337f0f","size":105110,"width":854,"height":1280},{"id":991176,"hash":"db135bec6f4b142fd0769fd262427b4db07cf7c5","size":101590,"width":854,"height":1280},{"id":991177,"hash":"561ca217427a458bfd286519906cdccd2dd17c62","size":118454,"width":854,"height":1280},{"id":991178,"hash":"b01884230f7f7475e368f79d01ad411949fcde90","size":112615,"width":1280,"height":854},{"id":991179,"hash":"0a8ace9d5b708ccf80822e6fe36e5797627b717d","size":99872,"width":854,"height":1280},{"id":991180,"hash":"3c729a1eaa46037f8790efdafd6f4d12ba91babe","size":124997,"width":854,"height":1280},{"id":991181,"hash":"d992e0061e88357dd57bab20b0133ec2d0ddf7e8","size":110933,"width":1280,"height":854},{"id":991182,"hash":"e05e977b0c67b7050cca37321be6c37884b8630d","size":104301,"width":854,"height":1280},{"id":991183,"hash":"cc04bf664887f49af6f97f0e6624efabc3b81e0f","size":102816,"width":854,"height":1280},{"id":991184,"hash":"cfeb31f2001126e2be231a503c532c57cc31f74f","size":100519,"width":854,"height":1280},{"id":991185,"hash":"04306fbd4c38339c12c0449e328f8c56192412db","size":102593,"width":854,"height":1280},{"id":991186,"hash":"f6152c56f745f01a3fb507dab2d7a3ca4c024849","size":97452,"width":1280,"height":854},{"id":991187,"hash":"56c5347c117163affd0e4db20c8936706f8cdab6","size":99311,"width":854,"height":1280},{"id":991188,"hash":"279a1335fb27697e9713fab30e19f657182a17c5","size":111679,"width":854,"height":1280},{"id":991189,"hash":"33f9e141891adfea91d949f0ac8f06b172e1f8ef","size":115365,"width":854,"height":1280},{"id":991190,"hash":"8b5087c837391df8c9cae2a52a37095a2e0685c4","size":100457,"width":854,"height":1280},{"id":991191,"hash":"298b1c9bf8516d786d99e568143d9d10c8bd2627","size":104304,"width":854,"height":1280},{"id":991192,"hash":"24df3264d48fe66df059ee57aaa115c3c12b5514","size":105614,"width":1280,"height":854},{"id":991193,"hash":"c089652554d8a302725c6072b2c0a97354db6018","size":114988,"width":1280,"height":854},{"id":991194,"hash":"8df534891d289311a38290175e3296dbe4acdaee","size":99572,"width":854,"height":1280},{"id":991195,"hash":"ca848c798ec1991e12188a6509492bb387995cf0","size":104822,"width":854,"height":1280},{"id":991196,"hash":"6a7d278dbc8ca148b04cd2111c72066e796b5b50","size":95774,"width":854,"height":1280},{"id":991197,"hash":"8b9ec257d18addc26a0f8f540b165d5e68cd6bc6","size":99087,"width":854,"height":1280},{"id":991198,"hash":"f25eb64579c827a521eabc4355babd96d221fb72","size":97980,"width":854,"height":1280},{"id":991199,"hash":"b612cef81c7a72b98282a3725341e4aa699c1f12","size":99321,"width":854,"height":1280},{"id":991200,"hash":"7795c7cf9a5553e586b154ce1bcbf2f7e708481f","size":94217,"width":854,"height":1280},{"id":991201,"hash":"3aee2319bb648e217e0735667bbaf4ce57275c22","size":96909,"width":854,"height":1280},{"id":991202,"hash":"4c223e6c2763107105d294a5e0f02f7cc9012522","size":103816,"width":854,"height":1280},{"id":991203,"hash":"0b253c2486bdbc706d5429b0383bdcc0ed0a298c","size":93307,"width":854,"height":1280},{"id":991204,"hash":"c7c9c0f9253c7ad6017232c77ec882a4e68e3ca1","size":96133,"width":854,"height":1280},{"id":991205,"hash":"f589533ef27cbfda11db398c9af4cd0e4b8da872","size":106328,"width":854,"height":1280},{"id":991206,"hash":"84fc250df74783b6531f275203aa447681e7782c","size":95080,"width":854,"height":1280},{"id":991207,"hash":"b8636d8267050e8ad9e9b9875063787b985c3dd3","size":90917,"width":1280,"height":854},{"id":991208,"hash":"91329902994e73be7edc9049dadc4d8be827b4ba","size":112422,"width":1280,"height":854},{"id":991209,"hash":"3d5a5f53fee02560e9a683242d42caf09ee32ca9","size":83951,"width":854,"height":1280},{"id":991210,"hash":"5bb085e6f73665a01abcfe4ddd7d6d3a8c94e5d5","size":85621,"width":854,"height":1280},{"id":991211,"hash":"0db0a1cddfbf03831f78ccb3c934bb0fb25edb8d","size":91130,"width":854,"height":1280},{"id":991212,"hash":"2512c429a22edde9575df70f53a7c56f359e3451","size":102379,"width":1280,"height":854},{"id":991213,"hash":"56a222c1e0777365a54ba7d28fb4d82eb2d9322c","size":89038,"width":854,"height":1280},{"id":991214,"hash":"60e82ff833090e4f80a842a9cd1005181c94cec9","size":80208,"width":854,"height":1280},{"id":991215,"hash":"4ffdcf2b478c5eddfa4946a251933b56dea5026f","size":93751,"width":854,"height":1280},{"id":991216,"hash":"dab3ce009f7237c28fce93d3317b05b7bd90c3f8","size":97383,"width":854,"height":1280},{"id":991217,"hash":"63be2d83bb6750ea17ac7825e3f175baba81ca7c","size":93572,"width":854,"height":1280},{"id":991218,"hash":"de2875faac721a29eeb37c2d4b76b0c2352111b4","size":92861,"width":854,"height":1280},{"id":991219,"hash":"e39bb67b0a5bc6e06370060df84b57d49de63786","size":88235,"width":854,"height":1280},{"id":991220,"hash":"bafe81a8c80161d2613dd89739532a65735559b3","size":103351,"width":1280,"height":854},{"id":991221,"hash":"cb2479c7f1e618f3c1c162d0bd07770b3caf9e8d","size":85118,"width":854,"height":1280},{"id":991222,"hash":"32f86a1b9b4f2f4756a077faf1ab560b76837d96","size":106296,"width":1280,"height":854},{"id":991223,"hash":"146ad4a90c3fcdd02f5ec55ff2f9a7ea30e44334","size":80070,"width":1280,"height":854},{"id":991224,"hash":"0124212961804b68751cc03c93ee95e6a0172a4e","size":95541,"width":1280,"height":854},{"id":991225,"hash":"e92eb98ad05baa60ca015fbb6c1399d829b3b612","size":77158,"width":854,"height":1280},{"id":991226,"hash":"32d5b5eea7243e3442c371ecf4310253c4128c7e","size":72695,"width":1280,"height":854},{"id":991227,"hash":"ec9261d0791610ab11a6d70debafc7bb1403188c","size":109009,"width":1280,"height":854}]},"e7662537-f8cd-4c15-b2d4-9388178d7b7c":{"name":"Melody Marks - Teen Beauty","images":[{"id":991228,"hash":"2d32fb3127cc3ddf7b9aa6eb41d3926313aeb021","size":96938,"width":854,"height":1280},{"id":991229,"hash":"86f53ffb660ea07f579f5bc9a285ab083859c4d6","size":108730,"width":854,"height":1280},{"id":991230,"hash":"e229c288704a8fa11d92e7d39bfc76d89964abab","size":93404,"width":854,"height":1280},{"id":991231,"hash":"7e51b2795a0b314448673044b3a569f6003599d8","size":94047,"width":1280,"height":854},{"id":991232,"hash":"e904604923f488fe80b97fb30b3e36010ca62291","size":115408,"width":854,"height":1280},{"id":991233,"hash":"038ab73be544c9528b536a6f96275bb743c2168c","size":87820,"width":1280,"height":854},{"id":991234,"hash":"44bb0ba8026d3acfc00e386ee356f3c93e3e7945","size":104719,"width":854,"height":1280},{"id":991235,"hash":"2547d853e98cb566e1bd153ef2fd0c6ba713e792","size":105283,"width":854,"height":1280},{"id":991236,"hash":"3b68ffb9b2311265df8081cfbf66ded13bbe06ca","size":110414,"width":854,"height":1280},{"id":991237,"hash":"5f6e6df9c6037c6bcf6d3f54f458f6127d5cc4df","size":105789,"width":854,"height":1280},{"id":991238,"hash":"69a0a95b99e41fcbc98c40c5eba1588672db3749","size":94670,"width":1280,"height":854},{"id":991239,"hash":"a437d46df693619a1d8ce42f1f26afb89a1c7dd3","size":109261,"width":854,"height":1280},{"id":991240,"hash":"69ea2bd6945543c746845dc500b57e1402e3020c","size":114947,"width":854,"height":1280},{"id":991241,"hash":"865c8dcff4906c472b412bfec1339c645428d4a9","size":103590,"width":854,"height":1280},{"id":991242,"hash":"9b4af8d7a988428ae3b74fb5adaea5fc4d480c7b","size":109377,"width":854,"height":1280},{"id":991243,"hash":"ad9cd81f62889b8ad33e26e70d62dcd0b992061a","size":95749,"width":1280,"height":854},{"id":991244,"hash":"82f5ad5149617ff9627004cccda906d8ce31084f","size":85999,"width":854,"height":1280},{"id":991245,"hash":"946fe843ac3ab14b814a63203616c21dfae3cd98","size":87542,"width":854,"height":1280},{"id":991246,"hash":"d09e15e475b63d30dbe75c6a6398ea8a47a9936d","size":86783,"width":854,"height":1280},{"id":991247,"hash":"41304806cdee106a780eedc73849c1f8bd2a6077","size":102925,"width":854,"height":1280},{"id":991248,"hash":"154fb31c069a41a1400e216afa23c1ad130f61e9","size":91300,"width":854,"height":1280},{"id":991249,"hash":"af3012eeba54476456bd8abb99f8c8f8867f3b44","size":107037,"width":854,"height":1280},{"id":991250,"hash":"ade2719e8e04bfc30cae25e946c34c0db3653219","size":91612,"width":1280,"height":854},{"id":991251,"hash":"af5d0dd4dd20a623cfc93a478e8111cc2a57c6f2","size":113569,"width":854,"height":1280},{"id":991252,"hash":"c75ef1b88d1dc872ede3b84c3a4fffe8cee7d604","size":96281,"width":854,"height":1280},{"id":991253,"hash":"c42ff8fb59f952b165fc6b6eebefa6d9cf9e78d9","size":79525,"width":854,"height":1280},{"id":991254,"hash":"50235562aea74d47a22098d3d08825e932033d9e","size":81740,"width":854,"height":1280},{"id":991255,"hash":"c656354d725730f76e6d715a9ce7a19db87ecffd","size":108679,"width":854,"height":1280},{"id":991256,"hash":"f059e37111b704f7adda19c1d8dc4d3d21dfd90d","size":87886,"width":854,"height":1280},{"id":991257,"hash":"61c141c50cc2b64789ca79a5ee88a9d68a44342d","size":87677,"width":1280,"height":854},{"id":991258,"hash":"a1b005e59667a6777138ffd95c08d8f69eea4fce","size":103140,"width":854,"height":1280},{"id":991259,"hash":"034ebf1773b08111a1760db7d29327c72cacc3e4","size":95990,"width":854,"height":1280},{"id":991260,"hash":"71d0c59e61c459ca13ce8900a0c63fb78b9dcd85","size":94975,"width":854,"height":1280},{"id":991261,"hash":"bbefd150d6b94a2de66417163d27d91c5a926c1f","size":102897,"width":854,"height":1280},{"id":991262,"hash":"493ad2d5a74448bb435ea2e7b4ec4c468d9f16fd","size":112163,"width":854,"height":1280},{"id":991263,"hash":"a5436affec1762ae18a5e1308ab82a920a2da431","size":80904,"width":1280,"height":854},{"id":991264,"hash":"4544cb0b0452031c339a46275fba07eeb26b052e","size":101010,"width":1280,"height":854},{"id":991265,"hash":"d866d330ab0be5517004037e85a6cfb81b88d0d5","size":109734,"width":854,"height":1280},{"id":991266,"hash":"68df7a8cff9177209263426c013fc8c47646f4ad","size":83167,"width":854,"height":1280},{"id":991267,"hash":"5a03df2c5c4e2ff5ef07030972d2fc8f086a341b","size":82394,"width":854,"height":1280},{"id":991268,"hash":"a866e1f331f3a53306f41314668be1bd050a0484","size":75419,"width":854,"height":1280},{"id":991269,"hash":"11b2d87f6e61b29b6546da64457e53dc83fe9e22","size":90866,"width":854,"height":1280},{"id":991270,"hash":"6ae8ef25eeeef0b2aa99c4a458a83904ffcf91e9","size":80273,"width":854,"height":1280},{"id":991271,"hash":"33b9a93d0d5a3ec134eabede6806f17fcaca46b4","size":78216,"width":854,"height":1280},{"id":991272,"hash":"64030da2b578447d69a43b0d1051b34524438215","size":69918,"width":854,"height":1280},{"id":991273,"hash":"ca11242e9fe79ee84af18cf65ace8f72b12fe0c8","size":82015,"width":854,"height":1280},{"id":991274,"hash":"b316eb2290814ecd856946d92c12dcf368bf7ace","size":70565,"width":854,"height":1280},{"id":991275,"hash":"7a6033d8d9ac5e906f530395a305c7c9e85b7a17","size":86855,"width":854,"height":1280},{"id":991276,"hash":"8d404e0d0eddbe516ffaec1b2f408faad3a1c1b0","size":77038,"width":854,"height":1280},{"id":991277,"hash":"ca0a18f4fd54c911b2dbe3bbcf45a412e010b491","size":77316,"width":854,"height":1280},{"id":991278,"hash":"3f43c22a0cd362085c94cc41207e502b047b203e","size":70343,"width":854,"height":1280},{"id":991279,"hash":"1a9da2beeac3e45961695b77853a977e032f72a4","size":66113,"width":1280,"height":854},{"id":991280,"hash":"f39f15c763988d08be92800a002059109a6608b6","size":117087,"width":1280,"height":854},{"id":991281,"hash":"6f8582d3e19ab0f2a174e8d71dcd29c5d4cf84e5","size":75000,"width":1280,"height":854},{"id":991282,"hash":"cffb7801893b544429a26f90d1f7d8c74594dd08","size":99521,"width":1280,"height":854},{"id":991283,"hash":"c2598dc5b04f972f06529b076ab663f992c00db8","size":64866,"width":1280,"height":854},{"id":991284,"hash":"4cbc28d806c574552c1f1765e2d5e857eefb77e9","size":78554,"width":854,"height":1280},{"id":991285,"hash":"ccb2d7ab8d025634c8509949ce572964b26a2e0f","size":67733,"width":854,"height":1280},{"id":991286,"hash":"9965bccc7b54650ef69e8cac4d1a268e83a346d4","size":72919,"width":854,"height":1280},{"id":991287,"hash":"319f6300813d49ee00ef87b1b98db61bee6d3260","size":74684,"width":854,"height":1280},{"id":991288,"hash":"a923db55ee5ba0193041d4f5482ed5117a359b61","size":46406,"width":1280,"height":854},{"id":991289,"hash":"2db57d6973775f451f27c778ef7737c5eac34b83","size":81928,"width":854,"height":1280},{"id":991290,"hash":"0575870a53a9d426cbc02e9e88a45151136d1cad","size":124139,"width":1280,"height":854},{"id":991291,"hash":"ae321742b4928dbb7d6b50f3da40e6112fc20151","size":78511,"width":1280,"height":854},{"id":991292,"hash":"778e218bcd25e0d1cff163b0380149b7b8c40c65","size":68664,"width":1280,"height":854},{"id":991293,"hash":"789dfc35cc1a1ffa5cae25a254814ebe8733f963","size":77720,"width":854,"height":1280},{"id":991294,"hash":"af0342d4a1482ed5d2063fe10fd761db15114124","size":72162,"width":1280,"height":854},{"id":991295,"hash":"346d90b6bbc1d1567be3708186f0a14c21afa962","size":67861,"width":854,"height":1280},{"id":991296,"hash":"f2665d5a6f7f3216d2697e82f03b8ec5e77db211","size":76202,"width":854,"height":1280},{"id":991297,"hash":"e6d52474f8eecc1aac9e51657d2a5c6901c2ec53","size":76388,"width":854,"height":1280},{"id":991298,"hash":"da2334babb10e32b3771659a72b284ee1e8b992f","size":98367,"width":854,"height":1280},{"id":991299,"hash":"64dff1c90c4fa033172bf415886fd4e91c5956d1","size":172472,"width":1280,"height":854},{"id":991300,"hash":"497bd56460cdd94515a272210a4122bdda041e9d","size":128257,"width":1280,"height":854},{"id":991301,"hash":"a7904431824349910a1c9856c799dab1fa18dcdd","size":121122,"width":1280,"height":854},{"id":991302,"hash":"f607e71e47e359c6d72d99c6557756519a1248d1","size":130851,"width":1280,"height":854},{"id":991303,"hash":"6a999a0c01d772aca31579c134b6d7f2f4699e21","size":156141,"width":1280,"height":854},{"id":991304,"hash":"d4e83eba1fc40292c8755aed8593ee2a2a411729","size":140691,"width":1280,"height":854},{"id":991305,"hash":"96118f38fd8fd45bdcca776d05ce2cd413f5f3d9","size":108541,"width":854,"height":1280},{"id":991306,"hash":"e36fc3c3c3848df478c6344927d9dc9cbb0b19e4","size":142554,"width":854,"height":1280},{"id":991307,"hash":"625f854f664fd2a773827dc9906b4a41cbe1d914","size":123493,"width":854,"height":1280},{"id":991308,"hash":"e139d9d8f2b03f38d8bdd7a2f3375f8668b12d96","size":159939,"width":1280,"height":854},{"id":991309,"hash":"a1ad1a17fe8326f5415b8198403dccef1d993f4c","size":113546,"width":1280,"height":854},{"id":991310,"hash":"af42a1ff82b2f4df87e2e374a1822044b582ff85","size":110532,"width":854,"height":1280},{"id":991311,"hash":"129ac67ae97389dc925d2cd45af22b6a972c2349","size":68422,"width":1280,"height":854},{"id":991312,"hash":"22ee05d8f4c49debf1d34825eae1137a761ba454","size":86075,"width":1280,"height":854},{"id":991313,"hash":"8232c42f212b20042bfb1bc338113a8bbd276c0b","size":132566,"width":1280,"height":854},{"id":991314,"hash":"1e2142652cacbc7da0806a9bcf8e6e01f70248f7","size":98140,"width":854,"height":1280},{"id":991315,"hash":"3a2aa7986ca9c23128f5f6e408b436fa62d57aae","size":109674,"width":1280,"height":854},{"id":991316,"hash":"800bfe8f1fe7b3cda16944460ff7c4b43cd7a00e","size":78829,"width":1280,"height":854},{"id":991317,"hash":"4ac7e211e10072008e95f9ad9b65d0a8543e578b","size":82495,"width":1280,"height":854},{"id":991318,"hash":"f4f5f94284967e338e8701040610dc83161f78af","size":151628,"width":1280,"height":854},{"id":991319,"hash":"4737f148c57644ef05582c58c99b8628dbed5251","size":86189,"width":854,"height":1280},{"id":991320,"hash":"ec12538d6c280206eb88ee4ee571896f8d45a96b","size":102610,"width":854,"height":1280},{"id":991321,"hash":"dd75dace83e8a447316474cd8f2f3cd5b6d02ef5","size":73892,"width":854,"height":1280},{"id":991322,"hash":"13c0780da43191d47878e7e6796dfce2b6aadd79","size":93799,"width":854,"height":1280},{"id":991323,"hash":"72e4c480a75259f92f6367c82d89bb28ecf3a97f","size":107153,"width":854,"height":1280},{"id":991324,"hash":"ce5b6ed0be2116b15c9f4616862161dbc2017f97","size":87294,"width":854,"height":1280},{"id":991325,"hash":"ab65ce9873e6b1f17f0e5cf2de62598f9f74b4a1","size":85762,"width":1280,"height":854}]},"f6d79ef6-da98-4c27-804d-e558f0b5fdf5":{"name":"Melody Marks - Teens Love Cream","images":[{"id":991334,"hash":"6d61603d7eeeaad71ac0ac83f5c4859444557b43","size":138264,"width":853,"height":1280},{"id":991335,"hash":"0dad49f486c4f70055a792929e11f3cc36a8614e","size":154835,"width":1280,"height":853},{"id":991336,"hash":"246eee454f4b865694dd8980b2862cc97f4aaf85","size":179569,"width":1280,"height":853},{"id":991337,"hash":"08e1a6214357b46607497915b7ac67a106ab806f","size":152704,"width":853,"height":1280},{"id":991338,"hash":"f2cedfafb3430d411ee6907e01016fef25e11b1f","size":203850,"width":1280,"height":853},{"id":991339,"hash":"9468ca2f34ce22934c9e9bdea6e858b32e1d0b77","size":167191,"width":853,"height":1280},{"id":991340,"hash":"68850f3e3fb475bf2748f96c92a2e85ebeda0f2a","size":139384,"width":853,"height":1280},{"id":991341,"hash":"0fb22e3562f7e6d1ca55d7d743d6452eb9a0e2e3","size":154692,"width":1280,"height":853},{"id":991342,"hash":"a52dbe93f1f6b991c8263c0c3ea688e4d11e5067","size":140393,"width":853,"height":1280},{"id":991343,"hash":"e98dd58428e5eec7784665b79610665b1a463d61","size":190764,"width":1280,"height":853},{"id":991344,"hash":"cf2ceca089bd66fdd5a8714454e1a59e54b33d74","size":214600,"width":1280,"height":853},{"id":991345,"hash":"564be042182ad9b2fc4e1c68d1c83bbf6addf4a9","size":181315,"width":1280,"height":853},{"id":991346,"hash":"4dce003505db880e8f27ae8360c8723456904486","size":159226,"width":1280,"height":853},{"id":991347,"hash":"3019b56ac23f1c0f50920d33308c27f2b5b241af","size":137945,"width":853,"height":1280},{"id":991348,"hash":"c7a0516b93374dec45b2b3b1f2800f955788d58a","size":158002,"width":1280,"height":853},{"id":991349,"hash":"9ae77135f9731e98ff00b236512f2007fdce5e4e","size":158678,"width":1280,"height":853},{"id":991350,"hash":"3590d57e79856500cb539c8e3326316c4a6c81d7","size":143029,"width":853,"height":1280},{"id":991351,"hash":"1fe829d16845b3cea7553b3f27a4e41306118f77","size":224224,"width":1280,"height":853},{"id":991352,"hash":"1d3834d66a8112ad0e1edfbbca115500ac9bae78","size":155865,"width":1280,"height":853},{"id":991353,"hash":"1c24ff85fd23870c06636fd67f7769216c2b2f01","size":150997,"width":1280,"height":853},{"id":991354,"hash":"13c92b24afdfa1c2bac1a0edd252e542295695da","size":131701,"width":853,"height":1280},{"id":991355,"hash":"38922180683b7b1b0480dd9b3127d68ed02c6349","size":158597,"width":853,"height":1280},{"id":991356,"hash":"90e9acca1141ed34c116a9095ba481f2cae48384","size":163176,"width":1280,"height":853},{"id":991357,"hash":"7ea29829c3f9ec793edf40f5e16d0c225379aac2","size":163971,"width":1280,"height":853},{"id":991358,"hash":"3cdf7982861dfcb6ce3bc441f6572c006c0e5941","size":136135,"width":853,"height":1280},{"id":991359,"hash":"007030f576b730c4d947da08c0697e66157171ff","size":155381,"width":1280,"height":853},{"id":991360,"hash":"151aa27c287c331f4989d0ced2a010640ad4232e","size":131918,"width":853,"height":1280},{"id":991361,"hash":"3f58a19587e543ff88573877dc3296a9a1de39ff","size":173770,"width":853,"height":1280},{"id":991362,"hash":"bf9252d0bf69f604ed3db244e54a57e4d6b95130","size":210488,"width":1280,"height":853},{"id":991363,"hash":"162395953a0fd2a025dd0dbff4cd28b87c2bb1b6","size":160439,"width":1280,"height":853},{"id":991364,"hash":"b7e91f780983f7b386cddce4c40baca1df78e708","size":148323,"width":853,"height":1280},{"id":991365,"hash":"5415e4c7499ecee3af0e43fa249cee0a9bbd1f87","size":216723,"width":1280,"height":853},{"id":991366,"hash":"a93b1350718466a8f587cc00af4a94f70c44c8a5","size":140601,"width":853,"height":1280},{"id":991367,"hash":"1792f2dc861cbf45774666e4e7182b7916badba7","size":140913,"width":1280,"height":853},{"id":991368,"hash":"0bb05ecf2034a51228828503656ee39f1ee5d519","size":119242,"width":853,"height":1280},{"id":991369,"hash":"5a185dbaa62a3e20383d6b48b1655a8ad1ccbb0e","size":146941,"width":1280,"height":853},{"id":991370,"hash":"b16014056953c7cdc0972c1c72fd96593fe81e9d","size":132077,"width":853,"height":1280},{"id":991371,"hash":"7000def964e623efd200e0788e51e4738b889a8d","size":186287,"width":1280,"height":853},{"id":991372,"hash":"6c2a2dc0318168ba009e4f86b3676a06f186e35e","size":140602,"width":1280,"height":853},{"id":991373,"hash":"23bd9637c8b5c845e8db0eb2b99cb348a8fd3646","size":136006,"width":853,"height":1280},{"id":991374,"hash":"c68c3c540662f38c65315804c9a5c57b9dbfec7a","size":188892,"width":1280,"height":853},{"id":991375,"hash":"f940cfae93d2a746bf412bb4cb2205a94ede1fcd","size":147801,"width":853,"height":1280},{"id":991376,"hash":"09bf1b71421c64a1dd81365951ae05ac8a36d911","size":116535,"width":853,"height":1280},{"id":991377,"hash":"51653a2edcd09dbd60aae7fc027881cb2dd48a21","size":197119,"width":1280,"height":853},{"id":991378,"hash":"68d58fa4bb851b902bd31f0a18dbb717b7cc4b83","size":158826,"width":853,"height":1280},{"id":991379,"hash":"deada48bfac4a974a7fee1785c91b98145c49eea","size":152697,"width":1280,"height":853},{"id":991380,"hash":"e33523ec132a85dcc37bb72f57e2db2016b73390","size":135089,"width":853,"height":1280},{"id":991381,"hash":"d86c5707f0106186e0e06c7c8e1d692ed01f1bea","size":148675,"width":1280,"height":853},{"id":991382,"hash":"fb80ccaba4ac38d1d8120fc0e94c499f87f78fa3","size":124254,"width":853,"height":1280},{"id":991383,"hash":"cc5d0b9b5ee8dccdd3f17ab98ff2f708150c8af1","size":147334,"width":1280,"height":853},{"id":991384,"hash":"0bee4bdf871f5d75886b4b55df6d17098d3f4cce","size":132455,"width":1280,"height":853},{"id":991385,"hash":"a0d101bfc010a22cd16a6bc472983701d33783b9","size":123481,"width":853,"height":1280},{"id":991386,"hash":"b3a37db986b06100702c4f5ffec142ab384529d1","size":210987,"width":1280,"height":853},{"id":991387,"hash":"10c6a3731b894b8be8035c5faa191d76e895b86c","size":141584,"width":853,"height":1280},{"id":991388,"hash":"b110dfae7bd8d45be45b7b06232d92bd082fa48c","size":132887,"width":1280,"height":853},{"id":991389,"hash":"5b023b7d219b8edeeb3e5eef574921edfd288815","size":125571,"width":853,"height":1280},{"id":991390,"hash":"51cba276018d2703608e63ad510d92ef21f28f7a","size":145197,"width":853,"height":1280},{"id":991391,"hash":"58ac4b80ce55b3b0958728107fa753b4d4b23688","size":200351,"width":1280,"height":853},{"id":991392,"hash":"5a7ad2263b25f5d13beeb92b9e944ca7dcea2cb3","size":174614,"width":1280,"height":853},{"id":991393,"hash":"e249a16b82ea2570299cefbb9bc8f5269c2ffee0","size":156718,"width":853,"height":1280},{"id":991394,"hash":"537a3c3b151bb5ec0844474f78303115727e73f8","size":182462,"width":1280,"height":853},{"id":991395,"hash":"9a6ba918e356b69b8a0f89ccc7ca33ca7e4c55ec","size":154015,"width":853,"height":1280},{"id":991396,"hash":"d6af48043250e48f2b32d3490f1d18615e797500","size":110808,"width":853,"height":1280},{"id":991397,"hash":"fc0adb35240d55ebd4737e7c568c0e46dc2c0abf","size":154358,"width":1280,"height":853},{"id":991398,"hash":"928dc176eb541b3f4e4e2dbae63445d1666e5fb9","size":107979,"width":853,"height":1280},{"id":991399,"hash":"a215a931e2d7f55d2ebe7359a1082eac6fa6e7bb","size":142779,"width":853,"height":1280},{"id":991400,"hash":"e2a3c03ebc13dc30eb305fb07d4c05b72b5d66da","size":113173,"width":853,"height":1280},{"id":991401,"hash":"f97d07899b46d4f4d1ce5924ae8733e829405a90","size":155008,"width":1280,"height":853},{"id":991402,"hash":"18626679bec6327a18dee9369d83999c6d07ea19","size":209183,"width":1280,"height":853},{"id":991403,"hash":"0d02a67c9a08da43b7939150955f7bd0a4d3fa96","size":190263,"width":1280,"height":853},{"id":991404,"hash":"25e9bf33a584012ac39cd718a6cd178b951b1400","size":147865,"width":853,"height":1280},{"id":991405,"hash":"f414ab56f2a56c32d35c1f32db8b99cadc9388ef","size":159798,"width":853,"height":1280},{"id":991406,"hash":"614d6982e3203dfde174a45f63e05fd390a92d4f","size":118898,"width":853,"height":1280},{"id":991407,"hash":"e0281d086573edb6746f159370d64936adccac82","size":119622,"width":853,"height":1280},{"id":991408,"hash":"7e3967f241295f4ae273973003428b7c2d3ebe07","size":143057,"width":1280,"height":853},{"id":991409,"hash":"3bbdd3c70b7c1b0af39b3643a734d3404be93e08","size":190672,"width":1280,"height":853},{"id":991410,"hash":"1d545949111f663242ba703932fce5d64c017d0f","size":153846,"width":1280,"height":853},{"id":991411,"hash":"b3b7ed41dc79730d5e7b9c719ee749c5ceeec453","size":121138,"width":1280,"height":853},{"id":991412,"hash":"a62e960f79cd9e6dedf4d7f10a070787340d2404","size":98378,"width":853,"height":1280},{"id":991413,"hash":"02d45548507a503a81f13e397a47e02936420615","size":100873,"width":853,"height":1280},{"id":991414,"hash":"1de3a972ad289aa90f5269f66a6e08fbced5fa2b","size":134931,"width":1280,"height":853},{"id":991415,"hash":"8c2f2a5d78ed8fa4ee813d5da4b1466f20706bb4","size":132775,"width":1280,"height":853},{"id":991416,"hash":"6d531b595f8dfde7859c5355f0b40054ecc4ba41","size":120137,"width":1280,"height":853},{"id":991417,"hash":"79ac02ac47a3d5b15d6a91e80d37e578398ddadd","size":120352,"width":1280,"height":853},{"id":991418,"hash":"778566f632ca7da687901bd11d607387b9dcef6e","size":117572,"width":853,"height":1280},{"id":991419,"hash":"cf82b66d82e8e9c5999d147aa7d466ac1e90bfa5","size":153236,"width":1280,"height":853},{"id":991420,"hash":"b5ca0fa4b18464665c293db23813dc3aaa9ca858","size":132669,"width":853,"height":1280},{"id":991421,"hash":"6cad4d3f456f8f69582c89db9bc305a4f37672bd","size":161328,"width":1280,"height":853},{"id":991422,"hash":"7d1887a973132c3491a2a388c2c07f43440b6f8c","size":160251,"width":1280,"height":853},{"id":991423,"hash":"5bb7faf6ac2778698104694e192e6492bb191fec","size":123507,"width":853,"height":1280},{"id":991424,"hash":"fbfee32acf3c70f06d8d071b6fcffb2601bcc8bd","size":123936,"width":853,"height":1280},{"id":991425,"hash":"4c77504329d73fa820052de31d5e0526b07cbde0","size":167986,"width":1280,"height":853}]},"5cb4f45b-0809-4e6b-b026-a0432c28956f":{"name":"thumbnail","images":[{"id":992225,"hash":"79a78836e241b4f3a699652d5565edd24e121854","size":692535,"width":2403,"height":2403},{"id":992226,"hash":"7b1c17c72f52e811e3ffc3a87e6ddbe310123702","size":677875,"width":2402,"height":2402}]},"3623f70d-758d-4918-a148-31d28a8d65dd":{"name":"Melody Marks - Dirty Schoolgirl","images":[{"id":1005354,"hash":"69215b423d0bee5fb6a3af4f3e2ccf33316383ec","size":110859,"width":853,"height":1280},{"id":1005355,"hash":"9d4c80b0e6c8c88f0d68e50cfcf3f786b48b7de4","size":122692,"width":853,"height":1280},{"id":1005356,"hash":"2814592dd7d9cf30d8c530bc875483b1db8829c1","size":117407,"width":1280,"height":853},{"id":1005357,"hash":"8183f58653f422ee9be82b0bf7ed0d39b24da042","size":131396,"width":853,"height":1280},{"id":1005358,"hash":"bdd86324312ea7ec0cc6ed2650f17aa11ac33b60","size":123757,"width":853,"height":1280},{"id":1005359,"hash":"63bfb50b227d24be8f40feb8306b0a6af19953b7","size":114222,"width":853,"height":1280},{"id":1005360,"hash":"9b9105be2eb429b77a9030b932e7a06e0ba6790a","size":113646,"width":853,"height":1280},{"id":1005361,"hash":"eda5cac735c5ee016f5c6d9cca4fa9029d2423b3","size":105153,"width":853,"height":1280},{"id":1005362,"hash":"9d41632968121c25fb6abcfcd986ceaf4fe81033","size":103874,"width":853,"height":1280},{"id":1005363,"hash":"57616879a5b3276325fdd8b50d5f855959de73dc","size":105119,"width":1280,"height":853},{"id":1005364,"hash":"997bfb20bc09d03ec7670a538ccbc7004b6f240d","size":107470,"width":1280,"height":853},{"id":1005365,"hash":"1a445d9ec1b717efa56f9bffe4c1c844bd6cdf5a","size":111461,"width":1280,"height":853},{"id":1005366,"hash":"9324bf523be403d396cacb1b2d5464e1d67bb5fa","size":105589,"width":1280,"height":853},{"id":1005367,"hash":"b224cf67c77cfe8258c62119819ebcb1f0ef422d","size":125748,"width":1280,"height":853},{"id":1005368,"hash":"088f95e4c260a8791ca19eaaa89715d0f91f8499","size":130958,"width":1280,"height":853},{"id":1005369,"hash":"a1bb1c8677467774c63e8f4b7cffe793ff01d5e0","size":145225,"width":1280,"height":853},{"id":1005370,"hash":"d207e358194730197da6d86bf46951ee5fe7236f","size":120909,"width":853,"height":1280},{"id":1005371,"hash":"2ad4393a3d3e61e5858b45096536738f12872878","size":130409,"width":853,"height":1280},{"id":1005372,"hash":"4d2e208d35b7bd1c21b453bf4ce86109ca8c31ec","size":127218,"width":1280,"height":853},{"id":1005373,"hash":"e7a9f7e97ca262a175805968919c45df821ab5d2","size":138682,"width":1280,"height":853},{"id":1005374,"hash":"ce40e40e599e6886b704a5ba3d843d70d67a4745","size":66750,"width":1280,"height":853},{"id":1005375,"hash":"49060e32842c9b9c0ace3db502e2d2cbad896b69","size":109871,"width":1280,"height":853},{"id":1005376,"hash":"ff3cde75431d533e7b8473e32322975c75594372","size":95383,"width":1280,"height":853},{"id":1005377,"hash":"7b1ca65336ff6897791b1b7e9d71c87ddd23c132","size":112497,"width":1280,"height":853},{"id":1005378,"hash":"ec110e715762a00d7c3eeafa7b2c259e07bc21bd","size":112637,"width":1280,"height":853},{"id":1005379,"hash":"9b8b045ead6f7f8543b43abcfb8ccc74be40d357","size":126488,"width":1280,"height":853},{"id":1005380,"hash":"c40d7c3815da4d865eff8236dd3f10c5f028da85","size":108413,"width":853,"height":1280},{"id":1005381,"hash":"951d8964ec6a698f9e258da94558426003eee580","size":107606,"width":853,"height":1280},{"id":1005382,"hash":"71e7c877984e77553210bf9c20860bae53d2de65","size":90694,"width":853,"height":1280},{"id":1005383,"hash":"b5231d119cd3dd459e04560d6812b6b6f30fd165","size":90173,"width":853,"height":1280},{"id":1005384,"hash":"5f6d7fecc3a96acf0a168e6479939541db991c30","size":106003,"width":853,"height":1280},{"id":1005385,"hash":"880864c509d5874bdb32156b37183a87c71fd897","size":111640,"width":853,"height":1280},{"id":1005386,"hash":"8d4c6e2650933a8807ea888d9033d9b41960a112","size":123053,"width":853,"height":1280},{"id":1005387,"hash":"8d10010db91c57dc141c447882cde3eed6bcbcd3","size":113810,"width":1280,"height":853},{"id":1005388,"hash":"9fece00231e5b40a067293ebfccaa1ff29d7fab5","size":92908,"width":853,"height":1280},{"id":1005389,"hash":"9789aed8d5010d9a03fc905def07aad52df5a3c8","size":112611,"width":1280,"height":853},{"id":1005390,"hash":"e82cae995a4044ee1744072e3217fc9b1676459c","size":124525,"width":1280,"height":853},{"id":1005391,"hash":"8d732ec969e4f0c0a3c3afb4fac5848095c97bb4","size":96453,"width":1280,"height":853},{"id":1005392,"hash":"cb8915dcec1828ac2020e82f0f546ea0e756729d","size":123587,"width":853,"height":1280},{"id":1005393,"hash":"cfd97dd25e5ea713b0c8206561b3cf9c50a13b44","size":124441,"width":853,"height":1280},{"id":1005394,"hash":"167cf98520475d0d33f3b8609330bef9650189ab","size":127953,"width":1280,"height":853},{"id":1005395,"hash":"db880ef00421b040370d66829dbe16d9b94fe272","size":114745,"width":1280,"height":853},{"id":1005396,"hash":"d31ffd8ddad394df50ee9da2f8b2d5c54eee4734","size":116846,"width":1280,"height":853},{"id":1005397,"hash":"24bca14b3bdc84e6c257db7c98196ccea8e31823","size":114414,"width":1280,"height":853},{"id":1005398,"hash":"6ae3bd8f3d7024bcedbc82051f05b384f998adee","size":142905,"width":853,"height":1280},{"id":1005399,"hash":"ed31e92e3da79b3a4c9a00c76ff3cf2d9d4b4fb3","size":125108,"width":1280,"height":853},{"id":1005400,"hash":"8c3711aaa802f8912d19fc5a0e10ca108f640a99","size":127251,"width":1280,"height":853},{"id":1005401,"hash":"db0e64eded997f6fa5d4416869a72d0adbf363f9","size":125207,"width":1280,"height":853},{"id":1005402,"hash":"769359bbaa0a919f3779dfaea3286de3026396d6","size":139760,"width":1280,"height":853},{"id":1005403,"hash":"b68696823619196f4584fab9f253cb177cfbd80a","size":116455,"width":853,"height":1280},{"id":1005404,"hash":"b58f5f77ae0db3b593a556902ab53331c8222e85","size":114560,"width":853,"height":1280},{"id":1005405,"hash":"729132562e8aa0872d060db040b053a40ff9fdb0","size":66938,"width":1280,"height":853},{"id":1005406,"hash":"5b030c4d1711765fc06986c9b1478c8f0cfa79bd","size":83048,"width":853,"height":1280},{"id":1005407,"hash":"d39b0062a208b000b9aaec5bf2f51be6fcb7ca26","size":119955,"width":1280,"height":853},{"id":1005408,"hash":"09148141499f69a372d6a2d19f1690f573bf69d2","size":156243,"width":1280,"height":853},{"id":1005409,"hash":"572e1c94b10c2fd3660d65df6a14f819dbe1be29","size":158335,"width":1280,"height":853},{"id":1005410,"hash":"187a1d6d352cb8f0c1b117b16cbe4ffcf1648acf","size":195502,"width":1280,"height":853},{"id":1005411,"hash":"f6fd49a61db47b73ca0840e22354149b311c4c51","size":139144,"width":1280,"height":853},{"id":1005412,"hash":"7d12a1c3e343045fc56e7ac129c41abe1bc61cc7","size":199495,"width":1280,"height":853},{"id":1005413,"hash":"f03dec45583e9f7460ed2a5b8ab0542260efd420","size":136294,"width":1280,"height":853},{"id":1005414,"hash":"00d7041df90d7d86749ff0e0c79d1fa38c24f48f","size":186933,"width":1280,"height":853},{"id":1005415,"hash":"47fd924d4ccd5dd4e1009f4634d24ed823e05431","size":205852,"width":1280,"height":853},{"id":1005416,"hash":"b3c120ca7cda99664382c523826dbb3ee220cb04","size":181997,"width":1280,"height":853},{"id":1005417,"hash":"6ec6170a65bc3db8ab0b8bacd4bd4154493a195b","size":188955,"width":1280,"height":853},{"id":1005418,"hash":"81260dcffd205a35664b5bf3378744dadad8eb28","size":135373,"width":1280,"height":853},{"id":1005419,"hash":"823ee1eaccd41e2a0246e990c9537321832c6842","size":166495,"width":1280,"height":853},{"id":1005420,"hash":"7e1973df60150e8aa1953b40daeacbd1fd7da094","size":127622,"width":853,"height":1280},{"id":1005421,"hash":"3fc55f45c482dc36755e8f6587f5d6251b34dad6","size":150243,"width":1280,"height":853},{"id":1005422,"hash":"ff5bbb340faac56cb0b2e7a7046a212788fd6af3","size":152450,"width":853,"height":1280},{"id":1005423,"hash":"8f19744e6152553b588cd205f1035fedf3102bc9","size":177497,"width":1280,"height":853},{"id":1005424,"hash":"3589a2454afb0fa1cb54fa0a944e8a063c68407e","size":177812,"width":1280,"height":853},{"id":1005425,"hash":"c1527d93f54fcdda3e28cc6a4b615806828845b7","size":189128,"width":853,"height":1280},{"id":1005426,"hash":"4718ae6e16dd0c2c2f215a32962d6b8cdb4cb1db","size":180992,"width":1280,"height":853},{"id":1005427,"hash":"735486780363cd9a2441e59c1e81d83971bea72e","size":158983,"width":853,"height":1280},{"id":1005428,"hash":"97c1626a14b2aca65041589dc56229074507de26","size":220727,"width":853,"height":1280},{"id":1005429,"hash":"f72011817230e337ff89eb9ff2de400c8397b28e","size":158601,"width":1280,"height":853},{"id":1005430,"hash":"3572c66052b7ab0a2b0500007870963b08a40884","size":154741,"width":1280,"height":853},{"id":1005431,"hash":"cf2af69eff620910213b306d74baede384c5d1fd","size":199735,"width":853,"height":1280},{"id":1005432,"hash":"1bfbc5399de5d80a61efd122abddd0240a87b070","size":173425,"width":853,"height":1280},{"id":1005433,"hash":"cbd506cc13e4983416d64292fb09d833e45b381a","size":164297,"width":853,"height":1280},{"id":1005434,"hash":"070c83f278a1dccb5cf6a5b4066ff937ffca813d","size":140009,"width":1280,"height":853},{"id":1005435,"hash":"847b72d0e73e189dcd2db5fff40d5efa6dc2d0f5","size":128581,"width":853,"height":1280},{"id":1005436,"hash":"232851f6f1025f6f165190979e908f13d5084c09","size":118886,"width":853,"height":1280},{"id":1005437,"hash":"4c1571477dfb43d5cecd7ff91d4fa9b58f6ddb93","size":119474,"width":1280,"height":853},{"id":1005438,"hash":"de41229333029dbccc377e4115089309225f9ca2","size":137370,"width":1280,"height":853},{"id":1005439,"hash":"aca2c21c52ca3d47d742c72a854413d4864e0fcb","size":136188,"width":1280,"height":853},{"id":1005440,"hash":"dbe452f0eac60e15c7ef97b1112c428cd6ddb56b","size":137853,"width":1280,"height":853},{"id":1005441,"hash":"b52eaa3b2e8dcd78724f672081d9a41fd87d6719","size":118671,"width":1280,"height":853},{"id":1005442,"hash":"a8e69690fa9099629dee99d998a9fb971e972c22","size":112414,"width":1280,"height":853},{"id":1005443,"hash":"cec1eff17a3bdb6127d5ad8b7c3b216f61f471f8","size":100469,"width":853,"height":1280},{"id":1005444,"hash":"a4c467eb5dae90c0beb65a1fe98b3eb1c001717f","size":107243,"width":1280,"height":853},{"id":1005445,"hash":"7a2b82dab876304c0992c38570aa15fbee61f5c7","size":131982,"width":1280,"height":853},{"id":1005446,"hash":"8cf6c86650897fc963757646615681e2dda04cda","size":135134,"width":1280,"height":853},{"id":1005447,"hash":"a0310e142eec14562469730faa5a919be5cf0117","size":107850,"width":1280,"height":853},{"id":1005448,"hash":"5d7234e69c1e2ff2342ad8a01536955efa01602d","size":129460,"width":1280,"height":853},{"id":1005449,"hash":"7f5e4220c5f97ab4f4291175ba6d447737b75cde","size":146712,"width":1280,"height":853},{"id":1005450,"hash":"70636a5ee2075db6bfe228e820d4d91c5d2fcc1f","size":119329,"width":1280,"height":853},{"id":1005451,"hash":"7fb813b541b8c3b09e5025c4fd010cec2af22a31","size":112759,"width":1280,"height":853},{"id":1005452,"hash":"af6b728d3a3895f05886fb63a136f31929089e79","size":132152,"width":853,"height":1280},{"id":1005453,"hash":"41499ecf92c63eb70bec680ee56cbe3c7fee2c4a","size":120840,"width":853,"height":1280},{"id":1005454,"hash":"d40d4d9daf50c6fa610f9fac57abfbbcfcdf7aad","size":116599,"width":1280,"height":853},{"id":1005455,"hash":"38283aaf72020b77e39e62a1532cae4e35022100","size":115391,"width":853,"height":1280},{"id":1005456,"hash":"e9b4958cc736b3a885e0646d6c763710b774b4e4","size":146339,"width":1280,"height":853},{"id":1005457,"hash":"c69a8f03fae37f02da1ff9181e8e42f105b7e28d","size":102809,"width":853,"height":1280},{"id":1005458,"hash":"2fecc23da1e17c351ab1d321bf52f6fb50230b5a","size":104384,"width":1280,"height":853},{"id":1005459,"hash":"e37c1021bdefb728be18a4dea18d3afe36012858","size":128154,"width":1280,"height":853},{"id":1005460,"hash":"d40a88e44634d232ccde77e30d4a5116b2ec2e87","size":137083,"width":853,"height":1280},{"id":1005461,"hash":"9196ee11a00613df5c5cdff1d9d23c0cac269214","size":142705,"width":853,"height":1280},{"id":1005462,"hash":"843a55f4d07984a9073997a11c23a7825f1663ca","size":111601,"width":853,"height":1280},{"id":1005463,"hash":"75085c4102c0e6f956a326c5e3b48fe324aa317f","size":124174,"width":853,"height":1280},{"id":1005464,"hash":"5341cc8067ac80cb1c5fbaba8e7a6692c69c72aa","size":143341,"width":1280,"height":853},{"id":1005465,"hash":"f271f3af43037839f5953a22d6652f8e45bc108d","size":117255,"width":853,"height":1280},{"id":1005466,"hash":"743434d8b87193b734ca427ffe8dd6e92c232f86","size":119636,"width":954,"height":1280}]},"9ec8abe7-ce8e-433b-a18d-198f8af3e6a1":{"name":"cei","images":[{"id":1212379,"hash":"f2e431127ca0e506133df85a3105ad85840a166f","size":108767,"width":1366,"height":2048},{"id":1212380,"hash":"8bbbf70e175a09f8bbe0085b0bc2f07b3e4febd0","size":108657,"width":1366,"height":2048},{"id":1212381,"hash":"5a821f6478ea35431600380a3b22c5aa233b2196","size":316898,"width":1600,"height":1066},{"id":1212382,"hash":"36762d4d4feff7dcb3280aa88f2494d5916425df","size":152831,"width":1066,"height":1600},{"id":1212383,"hash":"e94f0e3a2824656fcc7f2dc14a3838752306dc27","size":824197,"width":2800,"height":1869},{"id":1212384,"hash":"b8407cca74da323ed1f53bb7552c0db3f9be1d9d","size":2454135,"width":5616,"height":3744},{"id":1212385,"hash":"d42ab858354499773d3026552fd4c058abb14106","size":2064295,"width":3744,"height":5616},{"id":1212386,"hash":"b426d1d0f9261c585a2c5d06f940b39f1b3fd9ca","size":2102272,"width":3744,"height":5616},{"id":1212387,"hash":"4f1abc18743e39c9cb5598704c6d775e7efe7d8c","size":1911484,"width":5616,"height":3744},{"id":1212388,"hash":"aae9a8239ea97ad43c0b7487d6c046092d6d9ace","size":2141994,"width":5616,"height":3744},{"id":1212389,"hash":"fd1bffcdb6e80f336fc96088613d2e394061131d","size":421816,"width":1600,"height":1066}]}},"init":"\/********************************\r\n * FapJack v1.16.5\r\n * by: fapnip@milovana\r\n * https:\/\/milovana.com\/forum\/viewtopic.php?f=2&t=23858\r\n ********************************\r\n * Sorry about the spaghetti.  Tough to keep code clean without imports and a proper IDE.\r\n *\r\n * To anyone that ripped this game's code:\r\n * Feel free to use any of this code in your own tease, but be nice and don't claim it as your own.\r\n * It may well be a mess, but it's my mess.\r\n *\r\n * Always base your FapJack games off fapnip's development example game:\r\n * https:\/\/milovana.com\/webteases\/showtease.php?id=47408&key=ae797ac48c\r\n *\r\n *\/\r\n\/*--magpie-warn\r\nNeed help with FapJack?\r\nAsk here!\r\nhttps:\/\/milovana.com\/forum\/viewtopic.php?f=2&t=23858\r\n*\/\r\n\r\n\/*****************\r\n * READ ME\r\n *****************\r\n *\r\n * Unless you're heavily modifying this game (my deepest apologies if you attempt that),\r\n *  >>> you shouldn't change anything in this Init Script. <<<\r\n *\r\n * If you do modify this init script, you'll have a more difficult time updating it with new versions.\r\n *\r\n * Anything you'd normally add to this init script can be placed in an eval in core-config.\r\n *\r\n * Avoid modifying game engine pages (start, play, cum-round-*, penalty-*, settings*, etc.)\r\n *   If there's a feature you need, and you can't implement it using the existing hooks\r\n *   (like with round intermission pages) request the feature in Milovana's forms.\r\n *   You'll have a hell of a time installing future updates if you don't heed this.\r\n *\r\n * !!! Read \"CORE GAME PAGES\", \"REQUIRED GAME PAGES\" and \"INSTALLING UPDATES\", below !!!\r\n *\r\n * Basic usage:\r\n *\r\n *  1.  Edit evals in core-config, setting values in game.setConfig({...}) object, and\r\n *        reviewing\/editing\/removing setting configuration option examples.\r\n *        (See comments in evals for details)\r\n *  2.  Create pages for your game rounds, based on your game settings.  Use existing pages as guide.\r\n *  3.  Edit what the dealer(s) can say in core-verbiage\r\n *\r\n *  See: core-config page for game settings and configuration\r\n *  See: core-verbiage and optional [mode]-verbiage-[level\/cum-mode] pages for verbiage\/language changes\r\n *\r\n *  For round images, see: (first page found is used)\r\n *\r\n *    [mode]-image-[level\/cum-mode]-[hand]        (discrete image loader)\r\n *    [mode]-image-[level\/cum-mode]-[hand]plus    (range image loader ***)\r\n *    [mode]-image-[level\/cum-mode]               (level image loader)\r\n *    [mode]-image                                (mode image loader)\r\n *    round-image                                 (fall-back image loader)\r\n *\r\n *    *** A range image loader page example would be:\r\n *\r\n *    melody-image-1-3plus\r\n *\r\n *     This would be used to load images for any level 1 hand at or above index 3 that does not\r\n *     have a discrete image loader page or a more applicable range loader that would\r\n *     take precedence.\r\n *\r\n *  For (optional) penalty images, see: (first page found is used)\r\n *\r\n *    [mode]-[penaltyId (edge\/stroke\/etc.)]-[level\/cum-mode]-[hand]\r\n *    [mode]-[penaltyId (edge\/stroke\/etc.)]-[level\/cum-mode]-[hand]plus\r\n *    [mode]-[penaltyId (edge\/stroke\/etc.)]-[level\/cum-mode]\r\n *    [mode]-[penaltyId (edge\/stroke\/etc.)]\r\n *    penalty-[penaltyId (edge\/stroke\/etc.)]-image\r\n *    penalty-image\r\n *\r\n *  For game over and win images, see: (first page found is used)\r\n *\r\n *  - Game Over Image Selection\r\n *    [mode]-game-over-[level\/cum-mode]-[hand]\r\n *    [mode]-game-over-[level\/cum-mode]-[hand]plus\r\n *    [mode]-game-over-[level\/cum-mode]\r\n *    [mode]-game-over\r\n *    game-over-image\r\n *\r\n *  - Cum Tease Images (Shows when play can cum)\r\n *    [mode]-cumtease-[level\/cum-mode]-[hand]\r\n *    [mode]-cumtease-[level\/cum-mode]-[hand]plus\r\n *    [mode]-cumtease-[level\/cum-mode]\r\n *    [mode]-cumtease\r\n *    win-cumtease-image\r\n *\r\n *  - Win Game Images (Displayed on win page)\r\n *    [mode]-win-[level\/cum-mode]-[hand]\r\n *    [mode]-win-[level\/cum-mode]-[hand]plus\r\n *    [mode]-win-[level\/cum-mode]\r\n *    [mode]-win\r\n *    win-image\r\n *\r\n *  Cum round entry image:\r\n *\r\n *  - For each cum round mode, you'll need a page to welcome player to the cum round:\r\n *    [mode]-cum-round-[cum-mode]\r\n *\r\n *  Multiple game modes selection image:\r\n *\r\n *  - If you have multiple game modes defined, you'll need to change the image in:\r\n *    game-mode-select-image\r\n *\r\n *  Multiple cum round mode selection image:\r\n *\r\n *  - If you have multiple cum round modes defined for a given game mode, you'll need:\r\n *    [mode]-cum-round-select\r\n *\r\n *  Round intermission pages:\r\n *\r\n *    To interrupt a round, and display another page before the given hand starts,\r\n *    create a page with the name:\r\n *    [mode]-inter-[level\/cum-mode]-[hand]\r\n *\r\n *    To interrupt a round, and display another page after the given hand ends,\r\n *    create a page with the name:\r\n *    [mode]-interp-[level\/cum-mode]-[hand]\r\n *\r\n *    The page will be called before or after the given hand.\r\n *    Once you're done with your intermission, in an eval, execute:\r\n *\r\n *    returnToCaller();\r\n * \r\n * \r\n *  Game loss mode pages (instruct player when they lose):\r\n * \r\n *    There are 4 core game loss mode page examples that when present and enabled\r\n *    will enable that game loss mode as a selectable option for the player:\r\n *    (You will need to modify the content of the example pages to match for tease.)\r\n * \r\n *    game-lost-ruin - Default. Will be forced to ruin if they lose.\r\n *    game-lost-deny - Will be denied if they don't win the final round.  Will be forced to ruin if they cum early.\r\n *    game-lost-cei  - Will be told to cum if they haven't yet, then eat it. (Only if a cei kink is enabled.) \r\n *    game-lost-rand - Will randomize the above on loss. (Don't modify this page.)\r\n * \r\n *    To disable or delete the above pages to disable the setting option(s) for the player.\r\n * \r\n *    To override the core loss mode page per game mode, level\/cum-mode and hand,\r\n *    create page(s) with following patterns, with the first found being used:\r\n * \r\n *    [mode]-game-lost-[loss-mode]-[level\/cum-mode]-[hand]\r\n *    [mode]-game-lost-[loss-mode]-[level\/cum-mode]-[hand]plus\r\n *    [mode]-game-lost-[loss-mode]-[level\/cum-mode]\r\n *    [mode]-game-lost-[loss-mode]\r\n *    game-lost-[loss-mode]\r\n *     \r\n *\r\n *  Verbiage Pages (Changing what the dealer says):\r\n *\r\n *  - To modify what the dealer says globally, modify the evals in:\r\n *\r\n *    core-verbiage\r\n *\r\n *  - To modify what the dealers says per level, create a page:\r\n *\r\n *    [mode]-verbiage-[level\/cum-mode]\r\n *\r\n *    Add an eval action to that page that overrides one or more verbiage keys, like:\r\n *\r\n *    game.setVerbiage({\r\n *      edge: [ \/\/ Tell player to edge\r\n *        \"Get right to the edge, but don't cum!\",\r\n *        \"Go on, \" + \"edge for me!\".bold().color('hotpink'),\r\n *        \"Get as close as you can!\",\r\n *        \"Keep stroking until you edge!\",\r\n *        \"Get right to the edge for me.  Don't go over!\",\r\n *        \"Stroke until you almost explode, but don't!\",\r\n *        \"Do what you need to do to reach that edge!\",\r\n *      ],\r\n *    });\r\n *\r\n *    (See: game.setVerbiage(...) evals in core-verbiage for more examples.)\r\n * \r\n *  Styling Text:\r\n * \r\n *    You can add style (size, color, bold, italic, etc.) to verbiage strings using:\r\n * \r\n *    \"My String\".color([html color code]) \/\/ See: https:\/\/www.w3schools.com\/colors\/colors_names.asp\r\n *                                             and https:\/\/www.w3schools.com\/colors\/colors_hexadecimal.asp\r\n *                                             and https:\/\/htmlcolorcodes.com\/color-picker\/\r\n *    \"My String\".size([decimal size, 1 = 100%, 1.5 = 150%])\r\n *    \"My String\".spacing([decimal size, like 0.2, or 'normal'])\r\n *    \"My String\".italic()\r\n *    \"My String\".bold()\r\n *    \"My String\".underline()\r\n *    \"My String\".br() \/\/ Add line break\r\n *    \"My String\".p() + \"My Next Paragraph\" \/\/ Start new paragraph\r\n * \r\n *    You can combine styles:\r\n * \r\n *    \"My String\".bold().italic().size(1.2).color('hotpink')\r\n * \r\n *  Changing\/Adding metronome sounds\r\n * \r\n *    Metronome sounds are in --audio-x pages.  Follow the existing files as a template.\r\n *\r\n *  Getting info on game state:\r\n *\r\n *    game.getLevel() will return the current level\r\n *    game.getRoundIndex() will return the current hand of the current level\r\n *    game.isCumRound() will return true if the player has reached the \"cum round\"\r\n *    (There are a ton more.  Ask for assistance in Milovana's forums.)\r\n *\r\n *  Creating custom penalties:\r\n *\r\n *    See examples in core-config-example\r\n *\r\n *  Overriding penalty probability, etc.:\r\n *\r\n *    See examples in core-config-example\r\n *\r\n *\/\r\n\r\n\/***************************************************\r\n * CORE GAME PAGES\r\n * *************************************************\r\n * Do not modify any of these pages! ***\r\n * If you need to add something, ask\r\n * in a feature request.\r\n *\r\n * *** NOTE: If an action in a given page is prefixed\r\n *     by an eval containing: --auto-magpie-merge: ...\r\n *     then you can modify ONLY the action that follows\r\n *     the --auto-magpie-merge: eval.\r\n *     (auto-magpie-merge eval prefixes must be in\r\n *      both source and target.\r\n *      DO NOT ADD\/CHANGE --auto-magpie-merge: EVALs!!!\r\n *      DO NOT DELETE THE ACTION following the EVAL!\r\n *      DO NOT ADD AN ACTION!\r\n *      ONLY MODIFY THE EXISTING ACTION!)\r\n *\r\n * *************************************************\r\n *\/\r\n\/*--auto-magpie-code:FapJack_base *\/\r\n\/*--auto-magpie-core:\r\nstart\r\n--audio-*\r\nalternate-game-page-example\r\ncore-config-example\r\ncore-verbiage-example\r\ncum-round\r\ncum-round-pause\r\ncum-round-select\r\ngame-difficulty-select\r\ngame-lost\r\ngame-lost-check\r\ngame-lost-rand\r\ngame-mode-select\r\nnotification-round\r\npenalty*\r\nplay\r\nplay-shuffle-notice\r\nplay-start\r\nrest\r\nrest-end\r\nsettings*\r\nwin\r\nwin-check\r\nwin-check2\r\nwin-tease\r\nwelcome\r\n*\/\r\n\r\n\/*****************************************\r\n * REQUIRED GAME PAGES\r\n * ***************************************\r\n * These pages are required for game to\r\n * function, but you'll likely need to\r\n * modify them to fit your needs.\r\n * ***************************************\r\n *\/\r\n\/*--auto-magpie-required:\r\ncore-config\r\ncore-verbiage\r\ngame-difficulty-select-image\r\ngame-mode-select-image\r\ninstructions\r\nwelcome-image\r\ncommon-ending\r\ngame-lost-cei\r\ngame-lost-ruin\r\ngame-lost-deny\r\n*\/\r\n\r\n\/*********************\r\n * INSTALLING UPDATES\r\n *********************\r\n *\r\n * To merge FapJack updates into an existing FapJack:\r\n *\r\n * 1.  Backup your existing tease. (Very important!)\r\n * 2.  Open FapJack Base in Eos Magpie:\r\n *     https:\/\/codepen.io\/fapnip\/full\/GRjwPXP?id=47408&key=ae797ac48c\r\n * 3.  As the \"target\" tease, enter your tease's URL\r\n * 4.  Review pre-selected items.  (If you've modified this init script,\r\n *                                  auto-update may not work.)\r\n * 5.  Click the big blue download button.\r\n * 6.  Import the downloaded JSON over your tease.\r\n * 7.  If there were changes to core-config-example or core-verbiage-example, check to see if\r\n *      you need to implement any of those changes in your core-config or core-verbiage pages.\r\n *      Review CHANGE LOG to see if there's anything else you may need to do.\r\n *      (Don't modify *-example pages.  They're there for reference only.)\r\n * 8.  Test your tease.  If broken, restore from backup and try again.\r\n *\r\n *\/\r\n\r\n\/*****************\r\n * CHANGE LOG\r\n *****************\r\n * \r\n * 1.16.4\r\n *    - More difficulty level tweaks\r\n * \r\n * 1.16.4\r\n *    - Fix some difficulty level bugs\r\n * \r\n * 1.16.3\r\n *    - More difficulty level tweaks\r\n *    - Adjust penalty stroked to how far advanced in game\r\n *    - Base round BPM on remapped level\r\n * \r\n * 1.16.2\r\n *    - More difficulty level tweaks\r\n * \r\n * 1.16.1\r\n *    - Adjust difficulty levels\r\n * \r\n * 1.16.0\r\n *    - Move stroking options to settings-stroking page\r\n *    - Add Game Difficulty option to control stroke speed, etc.\r\n *    - Add aliasOf setting property to allow linking to same setting from multple places\r\n *    - Alias new \"Game Difficulty\" setting from stroking options as \"Intensity\"\r\n * \r\n * 1.15.6\r\n *    - Update to SimpleBeats 0.8.3 to try to avoid beat playing on init\r\n * \r\n * 1.15.5\r\n *    - Update \"-audio-1\" beat sound to one that works on more devices\r\n *      (Update your -audio-1 page if you used the old \"beat-pop-*\" sounds there.)\r\n * \r\n * 1.15.4\r\n *    - Update timer polyfill\r\n * \r\n * 1.15.3\r\n *    - Destroy Sound instances before loading new audio page.\r\n * \r\n * 1.15.2\r\n *   - Update setTimeout and SimpleBeats\r\n * \r\n * 1.15.1\r\n *   - Tweak some beat settings\r\n * \r\n * 1.15.0\r\n *   - Update mergeObect string field merger to allow more flexible method calling\r\n *   - To help with metronome issues on older devices:\r\n *   -   Update setTimeout polyfill to v1.1\r\n *   -   Use new, simplified, SimpleBeats instead of Beats for dynamic metronome\r\n *   -   Remove TitleAnimator that Beats used, but FapJack didn't need\r\n *   - (Changes are in Init Script and start page)\r\n * \r\n * 1.14.9\r\n *   - Fix volume adjustment (Init Script and settings-beat-volume)\r\n * \r\n * 1.14.8\r\n *   - Add onGameReset hook\r\n *   - Add onSaveState hook\r\n *   - Add onGameRestore hook\r\n *   - Add public setGameState setter\r\n *   - Add public getGameState getter\r\n * \r\n * 1.14.7\r\n *   - Don't use remapped level for penalty option generators\r\n * \r\n * 1.14.6\r\n *   - Fix potential infinite loop in resetToCore\r\n * \r\n * 1.12.17 - 1.14.5\r\n *   - Too many changes to list, too lazy to add\r\n * \r\n * 1.12.17\r\n *   - Set defaults for some settings in Init Script\r\n * \r\n * 1.12.15\r\n *   - Track moan play state\r\n * \r\n * 1.12.14\r\n *   - Add playMoans feature, and ability to call it from verbiage\r\n * \r\n * 1.12.13\r\n *   - Fix incorrect inRoundNoFapTime\r\n * \r\n * 1.12.12\r\n *   - Allow parent setting's reset to realod reset audio profile\r\n * \r\n * 1.12.11\r\n *   - update audio profile example\r\n * \r\n * 1.12.10\r\n *   - Allow Reset to work on audio profiles setting page\r\n * \r\n * 1.12.9\r\n *   - Allow defined audio profile pages and profile page array to differ in length.\r\n * \r\n * 1.12.8\r\n *   - Add audio profiles\r\n * \r\n * 1.12.7\r\n *   - Fix penalty occurrence merging\r\n * \r\n * 1.12.6\r\n *   - Fix hang introduced in 1.12.5\r\n * \r\n * 1.12.5\r\n *   - Fix some bugs in settings\r\n *   - Allow integer options in radio buttons\r\n * \r\n * 1.12.4\r\n *   - Add String.prototyle.style([style], [class])\r\n * \r\n * 1.12.3\r\n *   - Add String.color([html color]), .size(1.2), .spacing(1.2), \r\n *     .bold(), .italic(), .underline(), .br(), .p()\r\n *     for text styling in verbiage strings.\r\n * \r\n * 1.12.2\r\n *   - Allow reloading randomized round image pages\r\n * \r\n * 1.12.1\r\n *   - Fix issue with penalty id resolution\r\n *\r\n * 1.12.0\r\n *   - Unified\/simplified image loaders\r\n *\r\n * 1.11.5\r\n *   - Added  winCheckBpm and winCheckRefresh settings\r\n *   - Modify win-check to refresh cum tease\r\n *   - Added [mode]-cumtease-[cum-mode] image page for cum tease.\r\n *\r\n * 1.11.4\r\n *   - Move buttons to verbiage\r\n *   - Change select page timers\r\n *   - Move sounds to start so they preload when Eos loads tease\r\n *   - Add welcome-image\r\n *\r\n * 1.11.3\r\n *   - Fix issue with resetting a blocked setting\r\n *\r\n * 1.11.2\r\n *   - Update instructions\r\n *   - Fix bug in game.getRadioObject\r\n *   - Add block method to settings\r\n *   - Add example settings blocker (see kinkAnal override in core-config-example)\r\n *\r\n * 1.11.1\r\n *   - Add rouletteBpm game setting to allow overriding sound for bpm.\r\n *\r\n * 1.11.0\r\n *   - Refactor \"mergeObject(randomString(t.verbiageKey), game)\" to \"game.text('verbiageKey')\"\r\n *\r\n * 1.10.14\r\n *   - Fix issue with re-locking game\r\n *\r\n * 1.10.13\r\n *   - When ulp (unlocked) setting is reset, try to rest to locked game config\r\n *   - Fixed bug in random mode select skipper\r\n *\r\n * 1.10.12\r\n *   - Generate titles and show buttons in difficulty\/game\/cumround-select\r\n *     using common methods instead of in-line.\r\n *\r\n * 1.10.11\r\n *   - Add 'alternateGamePage' options to game modes\r\n *\r\n * 1.10.10\r\n *   - Add post-hand intermission pages: [mode]-interp-[level\/cum-mode]-[hand]\r\n *\r\n * 1.10.9\r\n *   - Properly clear random selector button\r\n *\r\n * 1.10.8\r\n *   - Add random selector button to mode select pages\r\n *   - Fix a couple bugs\r\n *\r\n * 1.10.7\r\n *   - Fix bugs\r\n *\r\n * 1.10.6\r\n *   - Add skip\/timer settings\r\n *\r\n * 1.10.5\r\n *   - Add missing game.getRadioObject method\r\n *\r\n * 1.10.4\r\n *   - Add setting radio button selections and examples\r\n *\r\n * 1.10.3\r\n *   - Make setSettingOption index position relative to setting's page\r\n *\r\n * 1.10.2\r\n *   - Automatically generate settings reset message so it doesn't have to be defined.\r\n *   - Add example of how to add a new settings menu page.\r\n *\r\n * 1.10.1\r\n *   - Fix a couple bugs introduced in 1.10.0\r\n *   - Add simple \"penalty-custom-example\", and use example.\r\n *\r\n * 1.10.0\r\n *   - Dynamically build settings pages\r\n *   - Allow easy addition of custom setting options\r\n *   - Allow modification of existing setting option lables\/icons\/placement\r\n *   - Add showSetting game option object for hiding\/showing setting options\r\n *   - Merge existing penalty occurrence definitions instead of replace\r\n *\r\n * 1.9.30\r\n *   - Fix bug in penalty occurrence probability overrides\r\n *\r\n * 1.9.29\r\n *   - Fix some bugs.\r\n *   - Fix penalty limit override examples\r\n *\r\n * 1.9.28\r\n *   - Update auto-magpie instructions\r\n *   - Add penalty limit override examples in core-config-example\r\n *   - Add custom penalty override examples in core-config-example\r\n *\r\n * 1.9.27\r\n *   - Add hooks for setting penalty limits (faps, bpms, etc.)\r\n *   - Implement game difficulty selection\r\n *      (update your game-difficulty-select-image)\r\n *   - Add difficultyAutoSelect, difficultySelect1, difficultySelect2 verbiage\r\n *      (update your core-verbiage!)\r\n *   - Add difficulties game config option.\r\n *      (update your core-config!)\r\n *\r\n * 1.9.26\r\n *   - Add Eos Magpie auto-update\r\n *\r\n * 1.9.25\r\n *   - Change update instructions\r\n *\r\n * 1.9.24\r\n *   - Allow rest to skip all penalties instead of just edge\r\n *\r\n * 1.9.23\r\n *   - Fix image load time timer offset\r\n *\r\n * 1.9.22\r\n *   - Update instructions in Init Script\r\n *\r\n * 1.9.21\r\n *   - Fix core verbiage not being consistently re-loaded between levels\r\n *\r\n * 1.9.20\r\n *   - Fix the way config file loads are detected\r\n *\r\n * 1.9.19\r\n *   - Rename cumToWinTimeMin to winToCumTimeMin, since that's what it's used for\r\n *\r\n * 1.9.18\r\n *   - Add cumToWinTimeMin game setting\r\n *\r\n * 1.9.17\r\n *   - Fix cum round beat issue\r\n *\r\n * 1.9.16\r\n *   - !! You must update your 'play' page !!\r\n *   - Properly save intermission state\r\n *   - Restart cum round from beginning on game restore\r\n *   - Simplify play page, move code to game.checkStatus\r\n *   - Fix potential crash in play loop\r\n *\r\n * 1.9.15\r\n *   - Add Intermission pages:\r\n *      [mode]-inter-[level\/cum-mode]-[hand]\r\n *\r\n * 1.9.14\r\n *   - Update image page use documentation\r\n *\r\n * 1.9.13\r\n *   - Yet more dev mode fixes\r\n *   - Update comments\r\n *\r\n * 1.9.12\r\n *   - More dev mode fixes\r\n *\r\n * 1.9.11\r\n *   - In winToCum rounds, don't count time images take to load against time left\r\n *\r\n * 1.9.10\r\n *   - Fix mode arrays not being reset in development mode\r\n *\r\n * 1.9.9\r\n *   - Restore accidentally removed 'hasChangedSettings' function\r\n *\r\n * 1.9.8\r\n *   - Let user know when we start to attempt the long process of decrypting locked features\r\n *\r\n * 1.9.6\r\n *    - Add penalty occurrence overrides\r\n *\r\n * 1.9.5\r\n *    - Add done button to instructions so you don't have to click through the\r\n *       entire thing if you don't want to.\r\n *\r\n * 1.9.4\r\n *   - Automate fall-back for game over and win images in order of preference:\r\n *      [mode]-game-over-[level\/cum-mode]\r\n *      [mode]-game-over\r\n *      game-over-image\r\n *      [mode]-win-[level\/cum-mode]\r\n *      [mode]-win\r\n *      win-image\r\n *\r\n * 1.9.3\r\n *   - Automate fall-back to image loaders in order of preference:\r\n *      [mode]-image-[level]-[hand]                        (discrete image loader)\r\n *      [mode]-image-[level]-[1 through current-hand]plus  (*** range image loader)\r\n *      [mode]-image-[level]                               (level image loader)\r\n *\r\n *      *** A range image loader page example would be:\r\n *          melody-image-1-3plus\r\n *          This would load images for any level 1 hand at or above index 3 that does not\r\n *          have a discrete image loader page or a more applicable range loader that would\r\n *          take precedence.\r\n *\r\n * 1.9.2\r\n *   - Fix an issue with the verbiage randomizer.\r\n *\r\n * 1.9.1\r\n *   - Added game.setHandConfigOverride({...}) and game.setHandVerbiageOverride({...}) methods\r\n *      to be used in [mode]-image-[level]-[hand] pages, allowing overriding game settings\r\n *      on a per hand basis.  Example:\r\n *      game.setHandConfigOverride({dealerName: 'Different Name'});\r\n *      To override dealer name for a single hand.\r\n *\r\n * 1.9.0\r\n *   - Move game configuration variables to \"core-config\" page\r\n *   - Move verbiage configuration to \"core-verbiage\" and \"[mode]-verbiage-[level\/cum-mode]\" pages\r\n *\r\n * 1.8.1\r\n *   - Added cumToWinTimer game option to enable use of remaining winToCum round time\r\n *      as time limit to cum.\r\n *\r\n * 1.8.0\r\n *   - Reset config to core before loading level config.\r\n *   - Added optional roundLimits option to mode configuration,\r\n *       allowing some levels to be shorter than others.\r\n *   - Validate configuration and image pages before attempting to load them.\r\n *\r\n * 1.7.4\r\n *   - Better adjustment to blackjack win notification class\r\n *\r\n * 1.7.3\r\n *   - Fix an issue with object randomizer\r\n *\r\n * 1.7.2\r\n *   - Adjust class of blackjack win notifications to work on mobile devices\r\n *\r\n * 1.7.1\r\n *   - Move some game getter\/setters\/vars below the game setting area.\r\n *\r\n * 1.7\r\n *   - Adjust penalty probabilities\r\n *\r\n * 1.6\r\n *   - Optimize object randomizer\r\n *\r\n * 1.5 and below\r\n *   - Too many changes to list\r\n *\r\n *\/\r\n\r\n\/*****************\r\n * GLOBALS\r\n *****************\r\n *\/\r\n\r\n\/\/ NOTE: !!! Don't change these values! See: core-config !!!\r\nvar DEBUG = true\r\n\r\nvar S_ON = '\u2705' \/\/ HTML for a setting \"on\" button\r\nvar S_OFF = '\u2b1c' \/\/ HTML for a setting \"off\" button\r\n\r\nvar R_ON = '\ud83d\udd35' \/\/ HTML for a radio \"on\" button\r\nvar R_OFF = '\u26aa' \/\/ HTML for a radio \"off\" button\r\n\r\nvar cr \/\/ Global used by cum-round-select\r\nvar gds \/\/ Global used by game-difficulty-select\r\nvar gms \/\/ Global used by game-mode-select\r\nvar blackjack \/\/ Global used to store blackjack game instance\r\nvar _ss = [] \/\/ used by settings pages\r\n\r\n\/\/ prettier-ignore\r\n{\r\n\/\/ Add a missing 'pages.contains(pageId)' method\r\n\/\/ See: https:\/\/milovana.com\/forum\/viewtopic.php?p=288586#p288586\r\npages.contains||(pages.contains=function(a){var e=pages.isEnabled(a);pages.disable(a);var s=!pages.isEnabled(a);return s&&e&&pages.enable(a),s});\r\n\/\/ MD5 support functions (use: var md5Hash = md5('Input String'))\r\n\/\/ From: Joseph Myers (http:\/\/www.myersdaily.org\/joseph\/javascript\/md5-text.html)\r\nfunction md5cycle(f,h){var i=ff(i=f[0],g=f[1],r=f[2],n=f[3],h[0],7,-680876936),n=ff(n,i,g,r,h[1],12,-389564586),r=ff(r,n,i,g,h[2],17,606105819),g=ff(g,r,n,i,h[3],22,-1044525330);i=ff(i,g,r,n,h[4],7,-176418897),n=ff(n,i,g,r,h[5],12,1200080426),r=ff(r,n,i,g,h[6],17,-1473231341),g=ff(g,r,n,i,h[7],22,-45705983),i=ff(i,g,r,n,h[8],7,1770035416),n=ff(n,i,g,r,h[9],12,-1958414417),r=ff(r,n,i,g,h[10],17,-42063),g=ff(g,r,n,i,h[11],22,-1990404162),i=ff(i,g,r,n,h[12],7,1804603682),n=ff(n,i,g,r,h[13],12,-40341101),r=ff(r,n,i,g,h[14],17,-1502002290),i=gg(i,g=ff(g,r,n,i,h[15],22,1236535329),r,n,h[1],5,-165796510),n=gg(n,i,g,r,h[6],9,-1069501632),r=gg(r,n,i,g,h[11],14,643717713),g=gg(g,r,n,i,h[0],20,-373897302),i=gg(i,g,r,n,h[5],5,-701558691),n=gg(n,i,g,r,h[10],9,38016083),r=gg(r,n,i,g,h[15],14,-660478335),g=gg(g,r,n,i,h[4],20,-405537848),i=gg(i,g,r,n,h[9],5,568446438),n=gg(n,i,g,r,h[14],9,-1019803690),r=gg(r,n,i,g,h[3],14,-187363961),g=gg(g,r,n,i,h[8],20,1163531501),i=gg(i,g,r,n,h[13],5,-1444681467),n=gg(n,i,g,r,h[2],9,-51403784),r=gg(r,n,i,g,h[7],14,1735328473),i=hh(i,g=gg(g,r,n,i,h[12],20,-1926607734),r,n,h[5],4,-378558),n=hh(n,i,g,r,h[8],11,-2022574463),r=hh(r,n,i,g,h[11],16,1839030562),g=hh(g,r,n,i,h[14],23,-35309556),i=hh(i,g,r,n,h[1],4,-1530992060),n=hh(n,i,g,r,h[4],11,1272893353),r=hh(r,n,i,g,h[7],16,-155497632),g=hh(g,r,n,i,h[10],23,-1094730640),i=hh(i,g,r,n,h[13],4,681279174),n=hh(n,i,g,r,h[0],11,-358537222),r=hh(r,n,i,g,h[3],16,-722521979),g=hh(g,r,n,i,h[6],23,76029189),i=hh(i,g,r,n,h[9],4,-640364487),n=hh(n,i,g,r,h[12],11,-421815835),r=hh(r,n,i,g,h[15],16,530742520),i=ii(i,g=hh(g,r,n,i,h[2],23,-995338651),r,n,h[0],6,-198630844),n=ii(n,i,g,r,h[7],10,1126891415),r=ii(r,n,i,g,h[14],15,-1416354905),g=ii(g,r,n,i,h[5],21,-57434055),i=ii(i,g,r,n,h[12],6,1700485571),n=ii(n,i,g,r,h[3],10,-1894986606),r=ii(r,n,i,g,h[10],15,-1051523),g=ii(g,r,n,i,h[1],21,-2054922799),i=ii(i,g,r,n,h[8],6,1873313359),n=ii(n,i,g,r,h[15],10,-30611744),r=ii(r,n,i,g,h[6],15,-1560198380),g=ii(g,r,n,i,h[13],21,1309151649),i=ii(i,g,r,n,h[4],6,-145523070),n=ii(n,i,g,r,h[11],10,-1120210379),r=ii(r,n,i,g,h[2],15,718787259),g=ii(g,r,n,i,h[9],21,-343485551),f[0]=add32(i,f[0]),f[1]=add32(g,f[1]),f[2]=add32(r,f[2]),f[3]=add32(n,f[3])}function cmn(f,h,i,n,r,g){return h=add32(add32(h,f),add32(n,g)),add32(h<<r|h>>>32-r,i)}function ff(f,h,i,n,r,g,t){return cmn(h&i|~h&n,f,h,r,g,t)}function gg(f,h,i,n,r,g,t){return cmn(h&n|i&~n,f,h,r,g,t)}function hh(f,h,i,n,r,g,t){return cmn(h^i^n,f,h,r,g,t)}function ii(f,h,i,n,r,g,t){return cmn(i^(h|~n),f,h,r,g,t)}function md51(f){txt=\"\";for(var h=f.length,i=[1732584193,-271733879,-1732584194,271733878],n=64;n<=f.length;n+=64)md5cycle(i,md5blk(f.substring(n-64,n)));f=f.substring(n-64);var r=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(n=0;n<f.length;n++)r[n>>2]|=f.charCodeAt(n)<<(n%4<<3);if(r[n>>2]|=128<<(n%4<<3),55<n)for(md5cycle(i,r),n=0;n<16;n++)r[n]=0;return r[14]=8*h,md5cycle(i,r),i}function md5blk(f){for(var h=[],i=0;i<64;i+=4)h[i>>2]=f.charCodeAt(i)+(f.charCodeAt(i+1)<<8)+(f.charCodeAt(i+2)<<16)+(f.charCodeAt(i+3)<<24);return h}var hex_chr=\"0123456789abcdef\".split(\"\");function rhex(f){for(var h=\"\",i=0;i<4;i++)h+=hex_chr[f>>8*i+4&15]+hex_chr[f>>8*i&15];return h}function hex(f){for(var h=0;h<f.length;h++)f[h]=rhex(f[h]);return f.join(\"\")}function md5(f){return hex(md51(f))}function add32(f,h){return f+h&4294967295}\r\n}\r\n\r\n\/\/ Add style functions to String\r\nString.prototype.color = function (color) {\r\n  return '<span style=\"color:' +color+ ';\">' + this + '<\/span>'\r\n}\r\n\r\nString.prototype.size = function (size) {\r\n  var sz = isNaN(size) ? size : size + 'em';\r\n  return '<span style=\"font-size:' + sz + ';\">' + this + '<\/span>'\r\n}\r\n\r\nString.prototype.spacing = function (size) {\r\n  var sz = isNaN(size) ? size : size + 'em';\r\n  return '<span style=\"letter-spacing:' + sz + ';\">' + this + '<\/span>'\r\n}\r\n\r\nString.prototype.style = function (style, clazz) {\r\n  style = style ? ' style=\"' + style + '\"' : ''\r\n  clazz = clazz ? ' class=\"' + clazz + '\"' : ''\r\n  return '<span' + clazz + style + '>' + this + '<\/span>'\r\n}\r\n\r\nString.prototype.bold = function () {\r\n  return '<b>' + this + '<\/b>'\r\n}\r\n\r\nString.prototype.italic = function () {\r\n  return '<i>' + this + '<\/i>'\r\n}\r\n\r\nString.prototype.underline = function () {\r\n  return '<u>' + this + '<\/u>'\r\n}\r\n\r\nString.prototype.p = function (style) {\r\n  style = style ? ' style=\"' + style + '\"' : ''\r\n  return this + '<\/p><p' + style + '>'\r\n}\r\n\r\nString.prototype.br = function () {\r\n  return this + '<br>'\r\n}\r\n\r\n\/\/ Object.assign polyfill\r\n'function' != typeof Object.assign &&\r\n  Object.defineProperty(Object, 'assign', {\r\n    value: function(e, t) {\r\n      'use strict'\r\n      if (null == e)\r\n        throw new TypeError('Cannot convert undefined or null to object')\r\n      for (var n = Object(e), r = 1; r < arguments.length; r++) {\r\n        var o = arguments[r]\r\n        if (null != o)\r\n          for (var c in o)\r\n            Object.prototype.hasOwnProperty.call(o, c) && (n[c] = o[c])\r\n      }\r\n      return n\r\n    },\r\n    writable: !0,\r\n    configurable: !0,\r\n  })\r\n\r\n\/\/ Array.prototype.find polyfill\r\nArray.prototype.find ||\r\n  Object.defineProperty(Array.prototype, 'find', {\r\n    value: function(r) {\r\n      if (null == this) throw TypeError('\"this\" is null or not defined')\r\n      var t = Object(this),\r\n        e = t.length >>> 0\r\n      if ('function' != typeof r)\r\n        throw TypeError('predicate must be a function')\r\n      for (var i = arguments[1], o = 0; o < e; ) {\r\n        var n = t[o]\r\n        if (r.call(i, n, o, t)) return n\r\n        o++\r\n      }\r\n    },\r\n    configurable: !0,\r\n    writable: !0,\r\n  })\r\n\r\n\/*****************\r\n * GAME OBJECT\r\n *****************\r\n *\/\r\n\/\/ NOTE: !!! Don't change these values! See: core-config !!!\r\nvar _gameDefaults = {}\r\nvar game = {\r\n  \/\/ GAME SETTINGS HAVE MOVED:\r\n  \/\/ See: core-config page for game settings and configuration\r\n  \/\/ see: core-verbiage and [mode]-verbiage-[level\/cum-mode] pages\r\n\r\n  \/\/ misc. styles \/ HTML generation\r\n  cardButtonClass: 'Button_root__28K_E', \/\/  !!! A new build of EOS may break this !!! This makes cards look like buttons.\r\n  dealerBlackjackOpen: '<span '\r\n        + 'class=\"red eosButton Button_root__28K_E\" ' \r\n        + 'style=\"color: #feffff;\">',\r\n  dealerBlackjackClose: '<\/span>',\r\n  playerBlackjackOpen: '<span '\r\n        + 'class=\"green eosButton Button_root__28K_E\" ' \r\n        + 'style=\"color: #ffffff;\">',\r\n  playerBlackjackClose: '<\/span>',\r\n  dealerBJClass: 'red eosButton Button_root__28K_E',\r\n  dealerBJStyle: 'color: #feffff;',\r\n  playerBJClass: 'green eosButton Button_root__28K_E',\r\n  playerBJStyle: 'color: #ffffff;',\r\n\r\n  \/\/ misc. game state data.  NOT settings.\r\n  \/\/ If you think you need to change these here, you're probably doing it wrong.\r\n  \/\/ Any changes should be in your game.setConfig(...) in core-config.\r\n  lastRound: 1, \/\/ Badly named, should be lastLevel\r\n  lastHand: null, \/\/ Badly names, should be lastRound\r\n  image: null,\r\n  dryTease: false,\r\n  inCumRound: false,\r\n  shuffleTimer: null,\r\n  shuffleCount: null,\r\n  \/\/ rouletteBpm: 60,\r\n  refreshGameMessages: false,\r\n  message: null,\r\n  settingMessage: null,\r\n  \/\/ currentRoundConfig: null,\r\n  loadedCoreConfig: null,\r\n  loadedCoreVerbiage: null,\r\n  _coreConfig: null,\r\n  audioProfile: 1,\r\n  enableMoans: false,\r\n  loadedVerbiage: null,\r\n  cumRoundAlt: null, \/\/ Use alternate images for cum round (player selected)\r\n  gameMode: null, \/\/ Currently selected game mode\r\n  difficulty: null, \/\/ Currently selected difficulty (this is a game mode selector)\r\n  difficultyLevel: '1.0', \/\/ (this is a difficuly level multiplier)\r\n  cameAfterWin: null, \/\/ Player selected that they finished\r\n  dealerName: null,\r\n  playerName: null,\r\n  playerNameDefault: 'sweetie',\r\n  playerNameScoreboard: 'You',\r\n  lossPenalty: 'ruin',\r\n  cumCount: 0,\r\n  modePath: null,\r\n  _gameStarted: false,\r\n  winToCumStart: 0, \/\/ Timestamp player started winToCum\r\n  lastImageLoadTime: 0, \/\/ Time it took last image page to load\r\n  lastIntermissionStart: 0, \/\/ Time we took in last intermission\r\n  lastIntermission: null, \/\/ Last intermission we did\r\n  levels: 3, \/\/ Number of levels (needs image-X pages for each level)\r\n  perLevel: 15, \/\/ Number of rounds per level. Needs an IF game.i()===X action,\r\n  \/\/  and image action controlled under each if,\r\n  \/\/  for each perLevel round in each image-X level page\r\n  \/\/ (simplifies round\/level logic at cost of needing same number of rounds for each level)\r\n  \/\/          1  2   3   4(cum round)\r\n  bpms: [null, 90, 120, 150, 180, 220], \/\/ BPMs used per game level ()\r\n  bpmMax: 320,\r\n  bpmMin: 10,\r\n  slowDevice: true, \/\/ Will be removed eventually.  We always use slowDevice mode now.\r\n  handConfigOverride: null, \/\/ Record round that settings were overridden\r\n  roundTimerNoFap: 15,\r\n  roundTimeFap: 30,\r\n  roundTimeCum: 30,\r\n  roundTimeCumAuto: 10,\r\n  lostCheckTime: 5,\r\n  lostCheckTimeIssueOffset: 125, \/\/ Clear cum cancel Notification timer 1\/8 seconds before it ends \r\n  lossPenaltySelectorTimeout: 3000,\r\n  difficultyAutoSelectTime: 10,\r\n  winCheckBpm: 300, \/\/ 0 to disable\r\n  winCheckPattern: '+AF',\r\n  winCheckTeaseBpm: 300, \/\/ 0 to disable\r\n  winCheckTeasePattern: '+AF',\r\n  winCheckRefresh: 10, \/\/ 0 to disable\r\n  winCheckCumTease: 5, \/\/ 5 second timer for \"get ready to cum\" - 0 to disable\r\n  winCheckCumSkip: true, \/\/ Show \"I'm ready!\" button to allow skipping win tease\r\n  minTimeBetweenAnalSwitch: 120, \/\/ Don't allow anal switch closer than 120 second apart\r\n  didCumTease: false,\r\n  didStartWinCheck: false,\r\n  analToy: null,\r\n  lastAnalToy: null,\r\n  _dildos: [],\r\n  _buttPlugs: [],\r\n  _enabledAnalToys: [],\r\n  hasButtPlugs: function() {\r\n    return game._buttPlugs.length\r\n  },\r\n  hasDildos: function() {\r\n    return game._dildos.length\r\n  },\r\n  hasAnalToys: function() {\r\n    return game._enabledAnalToys.length\r\n  },\r\n  getCurrentAnalToy: function() {\r\n    return game.analToy\r\n  },\r\n  getLastAnalToy: function() {\r\n    return game.analToy || game.lastAnalToy || null\r\n  },\r\n  getLastAnalToyUseTime: function() {\r\n    if (game.analToy) {\r\n      return Date.now() - game.analToy.lastInsert\r\n    } else if (game.lastAnalToy) {\r\n      return game.lastAnalToy.lastUseTime\r\n    } else {\r\n      return 0\r\n    }\r\n  },\r\n  setAnalToy: function(k) {\r\n    if (game.analToy) {\r\n      game.analToy.lastUseTime = Date.now() - game.analToy.lastInsert\r\n    }\r\n    game.analToy = (k && game.analToys[k]) || null\r\n    if (game.analToy) {\r\n      game.lastAnalToy = game.analToy\r\n      game.analToy.lastInsert = Date.now()\r\n    }\r\n    buildPenalties()\r\n  },\r\n  analToys: {\r\n    'f': {\r\n      name: 'Finger',\r\n      icon: '\ud83d\udd95',\r\n      type: 'dildo',\r\n      insertTime: 15, \/\/ 15 seconds to insert\r\n      pullTime: 15, \/\/ 15 seconds to pull\r\n    },\r\n    'd': {\r\n      name: 'Dildo',\r\n      icon: '\ud83e\udd52',\r\n      type: 'dildo',\r\n      insertTime: 15, \/\/ 15 seconds to insert\r\n      pullTime: 15, \/\/ 15 seconds to pull\r\n    },\r\n    'p': {\r\n      name: 'Butt Plug',\r\n      icon: '\ud83c\udf44',\r\n      type: 'plug',\r\n      insertTime: 15, \/\/ 15 seconds to insert\r\n      pullTime: 15, \/\/ 15 seconds to pull\r\n    }\r\n  },\r\n  getEnabledAnalToys: function() {\r\n    var toys = game.analToys\r\n    return Object.keys(toys).reduce(function(a, k){\r\n      var lookupId = 'analToy-' + k\r\n      if (!game[lookupId]) return a\r\n      var toy = toys[k]\r\n      toy.id = k\r\n      toy.lookupId = lookupId\r\n      a.push(toy)\r\n      return a\r\n    }, [])\r\n  },\r\n  clearAnalToy: function() {\r\n    game.setAnalToy(null)\r\n  },\r\n  roundBpmDivisor: 1,\r\n  setRoundBpmDivisor: function(v) {\r\n    var dv = parseFloat(v)\r\n    if (isNaN(dv)) {\r\n      console.error('Unable to setRoundBpmDivisor.  Inavlid Number:', v)\r\n      return\r\n    }\r\n    game.roundBpmDivisor = dv\r\n  },\r\n  getDifficultyLevel: function() {\r\n    var result = Number(game.difficultyLevel)\r\n    if (isNaN(result)) {\r\n      console.error('Invalid difficultyLevel:', game.difficultyLevel)\r\n      return 1\r\n    }\r\n    return result\r\n  },\r\n  \/**\r\n   * adjustment = amount to adjust. 1 = no adjustemnt, 0.5 half of original\r\n   * onlyUpDown = 0 adjust up or down, -1 = adjust down only, 1 = adjust up only\r\n   *\/\r\n  getDifficultyLevelAdjusted: function(adjustment, onlyUpDown) {\r\n    var difficultyLevel = game.getDifficultyLevel()\r\n    if (difficultyLevel < 1 && (!onlyUpDown || onlyUpDown < 0)) {\r\n      var rem = 1 - difficultyLevel\r\n      return 1 - (rem * adjustment)\r\n    }\r\n    if (difficultyLevel > 1 && (!onlyUpDown || onlyUpDown > 0)) {\r\n      var rem = difficultyLevel - 1\r\n      return 1 + (rem * adjustment)\r\n    }\r\n    return difficultyLevel\r\n  },\r\n  noRoundTimer: false,\r\n  noCumRoundTimer: false,\r\n  cbtOpts: {\r\n    noBeat: true,\r\n    minCbt: 2,\r\n    maxCbt: 10,\r\n    timePerFap: 1,\r\n    allowSkip: true,\r\n    minTime: 5,\r\n    maxTime: 10,\r\n  },\r\n  penaltyOccurrence: {},\r\n  lastEdgeTime: null,\r\n  verbiage: {},\r\n    \/\/ OTHER GAME SETTINGS\r\n  maxSaveAge: 120, \/\/ How old a saved game state can be, in seconds, to be continued.\r\n  dealerSaftey: 17, \/\/ Dealer will not hit at or past this point.\r\n  rouletteTimerStart: [10, 80], \/\/ Starting ms wait between clicks [nornal, slow]\r\n  rouletteTimerLen: [10, 8], \/\/ How many clicks for penalty roulette [nornal, slow]\r\n  rouletteTimerInc: [0.5, 0.25], \/\/ how much to increase the durration between clicks after each roulette click [nornal, slow]\r\n  rouletteTimerEnd: .5, \/\/ Seconds to wait after penalty roulette ends, and the penalty page is displayed\r\n  singleLevelImage: false, \/\/ Force use of [gameMode]-image-[level] instead of [gameMode]-image-[level]-[hand]\r\n                           \/\/ (fall-back to single-level image is automatic if descrete or range image page isn't found)\r\n\r\n  \/\/ SETTING THAT MAY GO AWAY OR MAY NO LONGER WORK CORRECTLY\r\n  strokePenaltyLimit: false, \/\/ If true, edge only if not round 1 or cum round (player modifiable)\r\n  inRoundFapping: true, \/\/ Fap durring round. (player modifiable)\r\n  \r\n  \/\/ DEAD GAME SETTINGS THAT PROBABLY DON'T WORK AS YOU WOULD THINK\r\n  shuffleNotice: false, \/\/ If not continousShuffle, show a notice for shufffles (Was fun to make, but too distracting.)\r\n  showSetting: {\r\n    \/\/ Show these in settings menus?\r\n    volume: true,\r\n    options: true,\r\n    loseRest: true,\r\n    cumRoundAuto: false, \/\/ This may not work, and may go away\r\n    inRoundFapping: true, \/\/ This may go away\r\n    strokePenaltyLimit: true, \/\/ This may go away\r\n    lossPenalty: true,\r\n    kinks: true,\r\n    kinkPrecum: true,\r\n    kinkCbt: true,\r\n    kinkAnal: true,\r\n    playerName: false,\r\n    stroking: true,\r\n    strokingSpeedAlias: true,\r\n    difficultyLevel: true,\r\n    ulp: true, \/\/ Feature unlock\r\n  },\r\n  winnerA: undefined, \/\/ used by play page to track state\r\n  difficulties: {\r\n    normal: { title: 'Normal' },\r\n  },\r\n  hasText: function(key) {\r\n    return !!t[key]\r\n  },\r\n  text: function(key, obj) {\r\n    return game.mergeText(game.loadText(key), obj)\r\n  },\r\n  mergeText: function (txt, obj) {\r\n    if (txt) return mergeObject(\r\n      txt,\r\n      obj || game\r\n    )\r\n  },\r\n  loadedAudio: false,\r\n  _beats: null,\r\n  setPattern: function(pattern) {\r\n    beats.setPattern(pattern, true)\r\n  },\r\n  loadBeats: function () {\r\n    var _beats = new SimpleBeats()\r\n    _beats.loadSamples()\r\n    game._beats = _beats\r\n    beats.setPattern('+AF', true)\r\n    game.loadedAudio = true\r\n  },\r\n  loadText: function(key) {\r\n    var txt = t[key]\r\n    if (!txt) {\r\n      console.warn('No verbiage defined for \"' + key + \"'\")\r\n      return\r\n    }\r\n    return typeof txt === 'string' ? txt : randomString(txt)\r\n  },\r\n  \/\/ Game Getters \/ Actions (No settings beyond this point)\r\n  setConfig: function(gameConfig) {\r\n    if (DEBUG) console.warn('Loading game config', gameConfig)\r\n    if (!game._coreConfig) {\r\n      game._coreConfig = gameConfig\r\n    }\r\n    game._setConfigOptions(gameConfig)\r\n    game.resetModeArrays()\r\n    \/\/ game.updateDynamicValues()\r\n  },\r\n  _resetToCore: function() {\r\n    if (window._resettingToCore) return\r\n    window._resettingToCore = true\r\n    if (game._coreConfig) {\r\n      _gameDefaults = {}\r\n      game.setConfig(game._coreConfig)\r\n      \/\/ game.updateDynamicValues()\r\n    }\r\n    window._resettingToCore = false\r\n  },\r\n  setPenaltyOccurrences: function(pos) {\r\n    pos.forEach(function(p) {\r\n      game._setPenaltyOccurrence(p)\r\n    })\r\n    buildPenalties()\r\n  },\r\n  getSettingOption: function(s) {\r\n    return gameSettingStore[s]\r\n  },\r\n  setSettingOption: function(key, setting, atIndex) {\r\n    if (DEBUG) console.warn('Setting Option:', key, setting, atIndex)\r\n    if (!key || !setting) return\r\n    var varType = typeof game.key\r\n    var existingSetting = gameSettingStore[key]\r\n    var sType = (setting || {}).type\r\n    var usedKey =\r\n      setting.key &&\r\n      Object.keys(gameSettingStore).find(function(k) {\r\n        return (\r\n          existingSetting !== gameSettingStore[k] &&\r\n          gameSettingStore[k].key === setting.key\r\n        )\r\n      })\r\n    if (usedKey) {\r\n      console.error(\r\n        'Storage key \"' +\r\n          setting.key +\r\n          '\" already in use by setting \"' +\r\n          usedKey +\r\n          '\".  Unable to ' +\r\n          (existingSetting ? 'modify' : 'add') +\r\n          ' setting: ',\r\n        key\r\n      )\r\n      return\r\n    }\r\n    if (\r\n      'key' in setting &&\r\n      existingSetting &&\r\n      existingSetting.key !== setting.key\r\n    ) {\r\n      console.error('Unbale to modify storage key of existing setting:', key)\r\n      return\r\n    }\r\n    if (!existingSetting) {\r\n      \/\/ Validate new setting\r\n      if ((varType && varType === 'object') || varType === 'function') {\r\n        console.error('\"' + key + '\" is already used or invalid setting name.')\r\n        return\r\n      }\r\n      if (!key.match(\/^\\$\/) && !setting.force) {\r\n        console.error(\r\n          '\"' +\r\n            key +\r\n            '\" does not start with \"$\".  All custom settings must start with $.'\r\n        )\r\n        return\r\n      }\r\n\r\n      if (key.match(\/[^a-z0-9_\\$]\/i)) {\r\n        console.error(\r\n          '\"' +\r\n            key +\r\n            '\" contains invalid characters.  Only underscore and alphanumeric characters are allowed.  ' +\r\n            'Unable to add setting',\r\n          key\r\n        )\r\n        return\r\n      }\r\n      if (key.length < 3) {\r\n        console.error(\r\n          '\"' + key + '\" is under 3 character minimum for setting option names.'\r\n        )\r\n        return\r\n      }\r\n      if (key.length < 3) {\r\n        console.error(\r\n          '\"' + key + '\" is under 3 character minimum for setting option names.'\r\n        )\r\n        return\r\n      }\r\n      if (!setting.label) {\r\n        console.error('No label given for setting: \"' + key + '\".')\r\n        return\r\n      }\r\n      if (!setting.page) {\r\n        console.error('No setting page given for setting: \"' + key + '\".')\r\n        return\r\n      }\r\n      if (!setting.target && !setting.key) {\r\n        console.error(\r\n          'Setting \"' +\r\n            key +\r\n            '\" must provide a \"target\" setting page, or storage \"key\".'\r\n        )\r\n        return\r\n      }\r\n      if (setting.target && setting.key && !setting.options) {\r\n        console.error(\r\n          'Setting \"' +\r\n            key +\r\n            '\" must provide a \"target\" setting page, OR storage \"key\", not both ' +\r\n            '-- unless adding \"options\" for radio button setting.'\r\n        )\r\n        return\r\n      }\r\n\r\n      if (setting.key) {\r\n        if (!setting.key.match(\/^\\$\/)) {\r\n          console.error(\r\n            'Storage key \"' +\r\n              setting.key +\r\n              '\" does not start with \"$\".  All custom storage keys must start with $.  Unable to add setting',\r\n            key\r\n          )\r\n          return\r\n        }\r\n        if (setting.key.match(\/[^a-z0-9_\\$]\/i)) {\r\n          console.error(\r\n            'Storage key \"' +\r\n              setting.key +\r\n              '\" contains invalid characters.  Only underscore and alphanumeric characters are allowed.  Unable to add setting',\r\n            key\r\n          )\r\n          return\r\n        }\r\n        if (setting.key.length > 5) {\r\n          console.error(\r\n            'Storage key \"' +\r\n              setting.key +\r\n              '\" greater than 5 characters.  Keep setting keys as short as possible.  Unable to add setting: ',\r\n            key\r\n          )\r\n          return\r\n        }\r\n        if (setting.defaultValue === undefined) {\r\n          console.error(\r\n            'You must add a valid defaultValue for custom settings.  Unable to add setting: ',\r\n            key\r\n          )\r\n          return\r\n        }\r\n        if (!sType) {\r\n          console.error(\r\n            'You must add a valid storage type for custom settings.  Unable to add setting: ',\r\n            key\r\n          )\r\n          return\r\n        }\r\n      }\r\n    }\r\n\r\n    setting = deepmerge(existingSetting || {}, setting)\r\n\r\n    if (!isNaN(atIndex)) {\r\n      var storeKeys = Object.keys(gameSettingStore)\r\n      var ofPage = storeKeys.filter(function(s) {\r\n        return gameSettingStore[s].page === setting.page\r\n      })\r\n      atIndex = storeKeys.indexOf(ofPage[atIndex])\r\n    }\r\n\r\n    if (atIndex !== undefined) {\r\n      if (DEBUG) console.warn('Inserting Option At:', key, setting, atIndex)\r\n      gameSettingStore = addToObject(gameSettingStore, key, setting, atIndex)\r\n    } else {\r\n      if (DEBUG && !existingSetting)\r\n        console.warn('Appending Option:', key, setting)\r\n      if (DEBUG && existingSetting)\r\n        console.warn('Replacing Option:', key, setting)\r\n      gameSettingStore[key] = setting\r\n    }\r\n    if (!existingSetting) {\r\n      \/\/ settingDefaults[s] = setting.defaultValue\r\n      if (typeof sType.set === 'function') {\r\n        sType.set(key, setting.defaultValue)\r\n      }\r\n    }\r\n  },\r\n  getRadioObject: function(s) {\r\n    var sType = getStorageType(s)\r\n    if (sType && typeof sType.get === 'function') {\r\n      var obj = gameSettingStore[s]\r\n      if (!obj) {\r\n        console.error('Radio setting does not exist: ', s)\r\n        return\r\n      }\r\n      var val = sType.get(s)\r\n      if (!obj.options) {\r\n        console.error('Setting has no options defined: ', s)\r\n      }\r\n      var result = (obj.options || {})[val]\r\n      if (result) {\r\n        result.id = val\r\n      }\r\n      return (obj.options || {})[val]\r\n    }\r\n  },\r\n  _setPenaltyOccurrence: function(po) {\r\n    \/*\r\n    \/\/ Example\r\n    {\r\n      pf: pf.edge, \/\/ Function for generating penalties\r\n      o: { \/\/ Options for penalties\r\n        title: 'Custom Edge',\r\n        id: 'edge', \/\/ UID of penalty\r\n        \/\/ Is it only a tease in the roulette?\r\n        \/\/ (If not allowed, but is enabled, will show in roulette, but\r\n        \/\/  will never select.)\r\n        allow: function() {\r\n          \/\/ Game round over 4, and has more than one sroke penalty\r\n          return  g.r > 3 && g.pc.stroke.c > 1\r\n        },\r\n        \/\/ Other getters\/properties specific to penalty\r\n        ...,\r\n        ...\r\n      },\r\n      \/\/ How often will it appear in the roulette?\r\n      probability: function(){return 5}, \/\/ repeat 5 times to set probability\r\n      \/\/ Will it show in the roulette?\r\n      enabled: function(){return true}, \/\/ Always include\r\n    }\r\n    *\/\r\n    var foundPo = false\r\n    if (!po) {\r\n      console.error('Invalid penalty occurrence', po)\r\n    }\r\n    var poId = po.o.id\r\n    if (!poId) {\r\n      console.error(\"'o.id' not provided for penalty occurrence\", po)\r\n      return\r\n    }\r\n    penaltyOccurrence.forEach(function(p, i) {\r\n      var pid = p.o && p.o.id\r\n      if (pid && poId === pid) {\r\n        if (p.o.replace) {\r\n          if (DEBUG)\r\n            console.warn(\r\n              'Replacing existing \"' + poId + '\" penalty occurrence',\r\n              p,\r\n              'with',\r\n              po\r\n            )\r\n          penaltyOccurrence[i] = po\r\n        } else {\r\n          if (DEBUG)\r\n            console.warn(\r\n              'Overrding values in existing \"' +\r\n                poId +\r\n                '\" penalty occurrence with',\r\n              po\r\n            )\r\n          penaltyOccurrence[i] = deepmerge(penaltyOccurrence[i], po)\r\n        }\r\n        foundPo = true\r\n      }\r\n    })\r\n    if (!foundPo) {\r\n      if (!po.o.title) {\r\n        console.error(\r\n          \"Penalty 'o.title' not provide for penalty occurrence\",\r\n          po\r\n        )\r\n        return\r\n      }\r\n      if (typeof po.pf !== 'function') {\r\n        console.error(\r\n          \"Penalty factory 'pf' function not provide for penalty occurrence\",\r\n          po\r\n        )\r\n        return\r\n      }\r\n      if (!po.o) {\r\n        console.error(\r\n          \"Penalty option 'o' object not provide for penalty occurrence\",\r\n          po\r\n        )\r\n        return\r\n      }\r\n      if (typeof po.probability !== 'function') {\r\n        console.error(\r\n          \"Penalty 'probability' function not provide for penalty occurrence\",\r\n          po\r\n        )\r\n        return\r\n      }\r\n      if (typeof po.enabled !== 'function') {\r\n        console.error(\r\n          \"Penalty 'enabled' function not provide for penalty occurrence\",\r\n          po\r\n        )\r\n        return\r\n      }\r\n      if (typeof po.o.allow !== 'function') {\r\n        console.error(\r\n          \"Penalty 'o.allow' function not provide for penalty occurrence\",\r\n          po\r\n        )\r\n        return\r\n      }\r\n      penaltyOccurrence.push(po)\r\n    }\r\n  },\r\n  cumRoundFapTime: function() {\r\n    return game.useCumRoundAuto() ? game.roundTimeCumAuto : game.roundTimeCum \/\/ Seconds to wait for hit\/stand when in cum round\r\n  },\r\n  inRoundFapTime: function() {\r\n    return game.roundTimeFap \/\/ Seconds to wait for hit\/stand when in cum round\r\n  }, \/\/ Seconds to wait for hit\/stand if in-round fapping enabled\r\n  useSingleLevelImage: function() {\r\n    return game.singleLevelImage\r\n  },\r\n  getCumRoundMode: function() {\r\n    return game.cumRoundModes[game.cumRoundAlt]\r\n  },\r\n  getDifficulty: function() {\r\n    return game.difficulties[game.difficulty] || {}\r\n  },\r\n  getCumRoundModeTitle: function() {\r\n    return game.getCumRoundMode().shortTitle || game.getCumRoundMode().title\r\n  },\r\n  getGameModeTitle: function() {\r\n    return game.getGameMode().shortTitle || game.getGameMode().title\r\n  },\r\n  getDifficultyTitle: function() {\r\n    return game.getDifficulty().shortTitle || game.getDifficulty().title\r\n  },\r\n  isSettingsPage: function(pid) {\r\n    return pid && pid.match(\/^settings($|-)\/) && !pid.match(\/-image$\/)\r\n  },\r\n  settingsImagePage: function(pid) {\r\n    var imagePath = pid + '-image'\r\n    if (pages.contains(imagePath)) {\r\n      return imagePath\r\n    }\r\n    var pathParts = pid.split('-')\r\n    if (!pathParts || pathParts.length < 2 || pathParts[0] !== 'settings') {\r\n      if (pid === 'settings') {\r\n        return game.settingsImagePage('welcome')\r\n      }\r\n      return false\r\n    }\r\n    return game.settingsImagePage(\r\n      pathParts.slice(0, pathParts.length - 1).join('-')\r\n    )\r\n  },\r\n  cumRoundModes: {}, \/\/ Must set game mode for this to work\r\n  lossReturnStackPos: 0,\r\n  cancelCumming: function() {\r\n    if (!isNaN(game.lossReturnStackPos)) {\r\n      while (pageStack.length > game.lossReturnStackPos + 1) {\r\n        pageStack.pop()\r\n      }\r\n      game.cumCount --\r\n      closeAll()\r\n      clearRoundImage()\r\n      returnToCaller()\r\n    }\r\n  },\r\n  cancelCummingTimeout: function() {\r\n    console.error('Cancel cumming timeout')\r\n    \/\/ Nothing to do?\r\n  },\r\n  cumRoundPause: function() {\r\n    callPage('cum-round-pause', false, false)\r\n  },\r\n  lostCheck: function() {\r\n    if (pages.getCurrentPageId().match(\/^penalty\/)) {\r\n      \/\/ We're from a penalty page\r\n      if (roulette.opt && (typeof roulette.opt.onCum === 'function')) {\r\n        if(roulette.opt.onCum(roulette.opt)) {\r\n          \/\/ return\r\n        }\r\n      }\r\n    }\r\n    closeAll()\r\n    game.lossReturnStackPos = pageStack.length\r\n    callPage('game-lost-check', false, false)\r\n  },\r\n  cummingNow: function () {\r\n    if (game.isCumRound()) {\r\n    } else {\r\n      game.lostCheck()\r\n    }\r\n  },\r\n  cameEarly: function() {\r\n    game.cumCount ++\r\n    closeAll()\r\n    if (game.isCumRound() && !game.isWinToCumRound()) {\r\n      game.doStartWin()\r\n    } else {\r\n      callPage(game.getGameLossPage(false), function() {\r\n        closeNotifications('lostcheck')\r\n        setTimeout(function(){game.clearState(false, true)}, 500)\r\n      }, 'game-lost')\r\n    }\r\n  },\r\n  lostFinalRound: function () {\r\n    callPage(game.getGameLossPage(false), function() {\r\n        closeNotifications('lostcheck')\r\n        setTimeout(function(){game.clearState(false, true)}, 500)\r\n      }, 'game-lost');\r\n  },\r\n  doRandomLossPenalty: function () {\r\n      closeAll();\r\n      beats.stopAll();\r\n      roulette.useLossPenaltySelector();\r\n      if (!roulette.other || roulette.other.length < 1) {\r\n        pages.goto('game-lost');\r\n      } else if (roulette.other.length < 2) {\r\n        var opt = roulette.other[0]\r\n        pages.goto(game.getGameLossPage(opt.id))\r\n      } else {\r\n        roulette.prompt = game.text('lossPenaltyRandomPrompt', false)\r\n        pages.goto('penalty-roulette');\r\n      }\r\n  },\r\n  doRoundPenalty: function () {\r\n    roulette.reset();\r\n    callPage('penalty-roulette', false, false);\r\n  },\r\n  getCumRoundModesArray: function() {\r\n    var result = []\r\n    var crms = game.cumRoundModes\r\n    for (var k in crms) {\r\n      var crm = crms[k]\r\n      crm.id = k\r\n      result.push(crm)\r\n    }\r\n    return result\r\n  },\r\n  updateDynamicValues: function () {\r\n    var enabledToys = game.getEnabledAnalToys()\r\n    game._dildos = enabledToys.reduce(function(a, tt){\r\n      if (tt.type === 'dildo') a.push(tt)\r\n      return a\r\n    }, [])\r\n    game._buttPlugs = enabledToys.reduce(function(a, tt){\r\n      if (tt.type === 'plug') a.push(tt)\r\n      return a\r\n    }, [])\r\n    game._enabledAnalToys = enabledToys\r\n  },\r\n  resetModeArrays: function() {\r\n    gds = game.getDifficultiesArray()\r\n    gms = game.getGameModesArray()\r\n    cr = game.getCumRoundModesArray()\r\n    var settings = Object.keys(gameSettingStore).reduce(function(a, k){\r\n      if (!k.match(\/^analToy-[a-zA-Z0-9]+\/)) {\r\n        a[k] = gameSettingStore[k]\r\n      }\r\n      return a\r\n    }, {})\r\n    window.gameSettingStore = settings\r\n    var toys = game.analToys\r\n    Object.keys(toys).forEach(function(k){\r\n      var toy = toys[k]\r\n      var lookupId = 'analToy-' + k\r\n      toy.id = k\r\n      toy.lookupId = lookupId\r\n      if (toy.disabled) return\r\n      settings[lookupId] = {\r\n        type: storageTypes.GAME,\r\n        icon: toy.icon,\r\n        label: toy.name,\r\n        page: 'settings-kinks-anal',\r\n        afterSet: function(val) {\r\n          game.updateDynamicValues()\r\n        },\r\n        enableMessage: function() {\r\n          return game.text('settingKinksAnalToyEnable', toy)\r\n        },\r\n        disableMessage: function() {\r\n          return game.text('settingKinksAnalToyDisable', toy)\r\n        },\r\n        key: 'kT-' + k, \/\/ short key for storage\r\n        defaultValue: false,\r\n      }\r\n      game.showSetting['analToy-' + k] = true\r\n    })\r\n    loadSettings()\r\n  },\r\n  getDifficultiesArray: function() {\r\n    var result = []\r\n    var obj = game.difficulties\r\n    for (var k in obj) {\r\n      var o = obj[k]\r\n      o.id = k\r\n      result.push(o)\r\n    }\r\n    if (!result.length) {\r\n      result.push({ title: 'Normal', id: 'normal' })\r\n    }\r\n    return result\r\n  },\r\n  getGameModesArray: function() {\r\n    var result = []\r\n    var gameModes = game.gameModes\r\n    for (var k in gameModes) {\r\n      var gameMode = gameModes[k]\r\n      gameMode.id = k\r\n      if (\r\n        !gameMode.applyToDifficulties ||\r\n        gameMode.applyToDifficulties.indexOf(game.difficulty) >= 0\r\n      ) {\r\n        result.push(gameMode)\r\n      }\r\n    }\r\n    return result\r\n  },\r\n  inRoundNoFapTime: function() {\r\n    return game.roundTimerNoFap \/\/ Seconds to wait for hit\/stand if in-round fapping disabled\r\n  },\r\n  getRoundImagePath: function(forceFullPath) {\r\n    var imagePathRoot = game.getGameModePath() + 'image'\r\n    var imagePathBase = imagePathRoot + game.getCumRoundPath()\r\n    return game._getImagePath(imagePathRoot, imagePathBase, 'round-image', null, forceFullPath)\r\n  },\r\n  getPenaltyImagePath: function(penaltyId) {\r\n    var imagePathRoot = game.getGameModePath() + penaltyId\r\n    var imagePathBase = imagePathRoot + game.getCumRoundPath()\r\n    return game._getImagePath(\r\n      imagePathRoot,\r\n      imagePathBase,\r\n      'penalty-image',\r\n      'penalty-' + penaltyId + '-image'\r\n    )\r\n  },\r\n  getWinImagePath: function() {\r\n    var imagePathRoot = game.getGameModePath() + 'win'\r\n    var imagePathBase = imagePathRoot + game.getCumRoundPath()\r\n    return game._getImagePath(imagePathRoot, imagePathBase, 'win-image')\r\n  },\r\n  getCumTeaseImagePath: function() {\r\n    var imagePathRoot = game.getGameModePath() + 'cumtease'\r\n    var imagePathBase = imagePathRoot + game.getCumRoundPath()\r\n    return game._getImagePath(\r\n      imagePathRoot,\r\n      imagePathBase,\r\n      'win-cumtease-image'\r\n    )\r\n  },\r\n  getNamedImagePath: function(name) {\r\n    var imagePathRoot = game.getGameModePath() + name\r\n    var imagePathBase = imagePathRoot + game.getCumRoundPath()\r\n    return game._getImagePath(\r\n      imagePathRoot,\r\n      imagePathBase,\r\n      name + '-image'\r\n    )\r\n  },\r\n  getGameOverImagePath: function() {\r\n    var imagePathRoot = game.getGameModePath() + 'game-over'\r\n    var imagePathBase = imagePathRoot + game.getCumRoundPath()\r\n    return game._getImagePath(imagePathRoot, imagePathBase, 'game-over-image')\r\n  },\r\n  _getImagePath: function(imagePathRoot, imagePathBase, fallback, altFallback, forceFullPath) {\r\n    var imagePath =\r\n      imagePathBase + (game.isCumRound() ? '' : '-' + game.getRemapLevel())\r\n    var imageRoundPath = imagePath + '-' + game.getRemapRoundIndex()\r\n    if (forceFullPath) return imageRoundPath\r\n    \/\/ console.warn('Looking for image A', fallback, imageRoundPath)\r\n    if (pages.contains(imageRoundPath) && pages.isEnabled(imageRoundPath)) return imageRoundPath\r\n    \/\/ console.warn('Looking for image B', fallback, imagePath)\r\n    var rangeImage = findNearestRangeImage(imagePath)\r\n    if (rangeImage && pages.isEnabled(rangeImage)) return rangeImage\r\n    \/\/ console.warn('Looking for image C', fallback, imagePath)\r\n    if (pages.contains(imagePath) && pages.isEnabled(imagePath)) return imagePath\r\n    \/\/ console.warn('Looking for image D', fallback, imagePathBase)\r\n    if (pages.contains(imagePathBase) && pages.isEnabled(imagePathBase)) return imagePathBase\r\n    \/\/ console.warn('Looking for image D', fallback, imagePathRoot)\r\n    if (pages.contains(imagePathRoot) && pages.isEnabled(imagePathRoot)) return imagePathRoot\r\n    if (altFallback && pages.contains(altFallback) && pages.isEnabled(altFallback)) return altFallback\r\n    \/\/ console.warn('Looking for image E', fallback, fallback)\r\n    if (pages.contains(fallback) && pages.isEnabled(fallback)) return fallback\r\n    if (DEBUG) {\r\n      console.warn(\r\n        'UNABLE TO FIND APPLICABLE \"' +\r\n          (fallback || '').toUpperCase() +\r\n          '\" PAGE:',\r\n        'FOR LEVEL:' +\r\n          game.getRemapLevel() +\r\n          ', ROUND:' +\r\n          game.getRemapRoundIndex()\r\n      )\r\n      console.log('no:', imageRoundPath)\r\n      console.log('no:', imagePathBase + '-[x]plus')\r\n      console.log('no:', imagePath)\r\n      console.log('no:', imagePathBase)\r\n      console.log('no:', imagePathRoot)\r\n      if (altFallback) console.log('no:', altFallback)\r\n      console.log('no:', fallback)\r\n    }\r\n  },\r\n  doShuffleNotice: function() {\r\n    if (game.continousShuffle || !game.shuffleNotice) return\r\n    beats.stopAll()\r\n    closeAll()\r\n    game.shuffleTimer = 150\r\n    game.shuffleCount = 20\r\n    callPage('play-shuffle-notice', false, false)\r\n  },\r\n  getGameModePath: function() {\r\n    return game.gameMode ? (game.modePath || game.gameMode) + '-' : ''\r\n  },\r\n  getPlayerDifficulty: function() {\r\n    return g.df\r\n  },\r\n  setPlayerDifficulty: function(difficulty) {\r\n    console.log('Setting Player Difficulty', difficulty)\r\n    var gd = gds.find(function(d) {\r\n      return d.id === difficulty\r\n    })\r\n    if (gd && gd.alternateGamePage) {\r\n      clearRoundImage()\r\n      closeAll()\r\n      if (pages.getCurrentPageId() === 'game-difficulty-select') {\r\n        callPage(gd.alternateGamePage)\r\n      } else {\r\n        callPage(gd.alternateGamePage, null, 'game-difficulty-select')\r\n      }\r\n      return\r\n    }\r\n    g.df = difficulty\r\n    game.difficulty = difficulty\r\n    game.resetModeArrays()\r\n  },\r\n  setPlayerGameMode: function(gameMode) {\r\n    var mode = game.gameModes[gameMode]\r\n    if (mode && mode.alternateGamePage) {\r\n      clearRoundImage()\r\n      closeAll()\r\n      if (pages.getCurrentPageId() === 'game-mode-select') {\r\n        callPage(mode.alternateGamePage)\r\n      } else {\r\n        callPage(mode.alternateGamePage, null, 'game-mode-select')\r\n      }\r\n      return\r\n    }\r\n    game.setGameMode(gameMode)\r\n    g.gm = game.gameMode\r\n  },\r\n  getGameMode: function() {\r\n    return game.gameModes[game.gameMode]\r\n  },\r\n  setGameMode: function(gameMode) {\r\n    if (DEBUG) console.warn('Setting Game Mode:', gameMode)\r\n    var mode = game.gameModes[gameMode]\r\n    if (!mode) {\r\n      console.error(\r\n        'Unable to set Game Mode! \"' +\r\n          gameMode +\r\n          '\" is not defined in game.gameModes',\r\n        game.gameModes\r\n      )\r\n      if (game.gameModes[game.gameMode]) {\r\n        \/\/ Fall back to default\/pre-set mode\r\n        game.setGameMode(game.gameMode)\r\n      }\r\n    } else {\r\n      game.gameMode = gameMode\r\n      \/\/ Set mode specific values\r\n      game._setConfigOptions(mode)\r\n      game.setCumRoundAlt(game.cumRoundAlt)\r\n      cr = game.getCumRoundModesArray()\r\n    }\r\n  },\r\n  getCumRounds: function() {\r\n    return game.getCumRoundAltConfig().rounds || 1 \/\/ Number of IF game.i()===X actions in cum round page\r\n    \/\/ (if you have 3 levels, your cum round page would be image-hardcore-4)\r\n  },\r\n  getCumRoundAltConfig: function() {\r\n    return game.cumRoundModes[game.getCumRoundAltMode()] || {}\r\n  },\r\n  getCumRoundAltMode: function() {\r\n    return game.cumRoundAlt\r\n  },\r\n  getCumRoundPath: function() {\r\n    var cumRoundMode = game.isCumRound() && game.getCumRoundAltMode()\r\n    return cumRoundMode ? '-' + cumRoundMode : ''\r\n  },\r\n  setCumRoundAlt: function(altMode) {\r\n    if (DEBUG) console.log('Setting Cum Rount Alt:', altMode)\r\n    if (!game.cumRoundModes[altMode] && altMode !== null) {\r\n      console.error(\r\n        'Unable to set cum round mode! \"' +\r\n          altMode +\r\n          '\" is not defined in game.gameModes.' +\r\n          game.gameMode +\r\n          '.cumRoundModes',\r\n        game.cumRoundModes\r\n      )\r\n    } else {\r\n      game.cumRoundAlt = altMode\r\n    }\r\n  },\r\n  getRoundsWon: function() {\r\n    return g.wc\r\n  },\r\n  getWinsNeeded: function() {\r\n    return game.cumRoundsToWin - g.wc\r\n  },\r\n  getWinTimeRemaining: function() {\r\n    if (game.lastImageLoadTime) {\r\n      if (DEBUG)\r\n        console.log(\r\n          'Offsetting winToCumStart by',\r\n          game.lastImageLoadTime \/ 1000 + 's'\r\n        )\r\n      game.winToCumStart += game.lastImageLoadTime\r\n      game.lastImageLoadTime = 0\r\n    }\r\n    return game.winToCumTime * 1000 - (Date.now() - game.winToCumStart)\r\n  },\r\n  getCumTimeRemaining: function() {\r\n    var result = game.getWinTimeRemaining()\r\n    var minTime = game.cumToWinTimeMin ? game.cumToWinTimeMin * 1000 : 0\r\n    if (result < minTime) {\r\n      result = minTime\r\n    }\r\n    return result\r\n  },\r\n  getFormattedCumTimeRemaining: function() {\r\n    return game.getVerboseTime(game.getCumTimeRemaining())\r\n  },\r\n  getFormattedWinTimeRemaining: function() {\r\n    return game.getVerboseTime(game.getWinTimeRemaining())\r\n  },\r\n  getVerboseTime: function(time) {\r\n    var seconds = Math.floor(time \/ 1000)\r\n    var min = Math.floor(seconds \/ 60)\r\n    var sec = seconds - min * 60\r\n    if (min < 1) {\r\n      return sec + ' seconds'\r\n    } else if (sec < 0) {\r\n      return min + ' minutes'\r\n    } else {\r\n      return min + ' minutes, ' + sec + ' seconds'\r\n    }\r\n  },\r\n  getShuffleTimer: function() {\r\n    var timer = game.shuffleTimer\r\n    game.shuffleTimer = timer \/ 2\r\n    game.shuffleCount--\r\n    if (game.shuffleCount < 1) {\r\n      beats.stopAll()\r\n      closeAll()\r\n      returnToCaller()\r\n    }\r\n    return Math.max(timer, 1)\r\n  },\r\n  getDealerName: function() {\r\n    if (!game.getGameMode())\r\n      console.error(\r\n        'Invalid game.gameMode defined!  Use setGameMode(...) to set game mode!!'\r\n      )\r\n    var name = game.dealerName\r\n    return typeof name === 'function' ? name() : name\r\n  },\r\n  getPlayerName: function() {\r\n    var name = game.playerName\r\n    if (!name) {\r\n      name = game.playerNameDefault\r\n    }\r\n    if (typeof name === 'function') return name()\r\n  },\r\n  getPlayerNameScoreboard: function() {\r\n    var name = game.playerName\r\n    if (!name) {\r\n      name = game.playerNameScoreboard\r\n    }\r\n    if (typeof name === 'function') return name()\r\n  },\r\n  getGameLossPage: function(lossMode) {\r\n    var mode = lossMode || game.lossPenalty || ''\r\n    var lossOpt = gameSettingStore.lossPenalty.options[mode]\r\n    if (!lossOpt || !lossOpt.show()) {\r\n      console.error('Select loss option: ' + mode + ' is invalid or disabled.  Falling back to game-lost page')\r\n      mode = ''\r\n    }\r\n    var pageBase = 'game-lost'\r\n    var page = pageBase + '-' + mode\r\n    \r\n    var lossPathRoot = game.getGameModePath() + page\r\n    var lossPathBase = lossPathRoot + game.getCumRoundPath()\r\n    return game._getImagePath(lossPathRoot, lossPathBase, pageBase, page, false)\r\n\r\n    \/\/ if (mode && pages.contains(page)) {\r\n    \/\/   return page\r\n    \/\/ } else if (mode) {\r\n    \/\/   console.error('Unable to find lose mode page: ' + page, 'Falling back to: ' + pageBase)\r\n    \/\/ }\r\n    \/\/ return pageBase\r\n  },\r\n  _allowFunction: {\r\n    dealerName: true,\r\n    remapHand: true,\r\n    remapLevel: true,\r\n  },\r\n  _merge: {\r\n    showSetting: true,\r\n    verbiage: true,\r\n    cptOpts: true,\r\n    analToys: true,\r\n  },\r\n  _skipConfigProps: {\r\n    show: true,\r\n    hideOption: true,\r\n    _enabledAnalToys: true,\r\n  },\r\n  _setConfigOptions: function(config) {\r\n    Object.keys(config).forEach(function(i) {\r\n      if (game._skipConfigProps[i]) return\r\n      var setting = config[i]\r\n      if (\r\n        !game._allowFunction[i] &&\r\n        typeof game[i] !== 'function' &&\r\n        typeof setting === 'function'\r\n      ) {\r\n        setting = setting()\r\n      }\r\n      if (DEBUG) console.log('Setting game option', i, setting)\r\n      if (game._merge[i]) {\r\n        game[i] = deepmerge(game[i], setting)\r\n        if (DEBUG) console.warn('Deep Merged', i, game[i], setting)\r\n      } else {\r\n        game[i] = setting\r\n      }\r\n      if (!game._gameStarted && !gameSettingStore[i]) _gameDefaults[i] = deepmerge({}, game[i])\r\n    })\r\n    if (!config.penaltyOccurrence) {\r\n      game.penaltyOccurrence = {}\r\n    }\r\n  },\r\n  setHandVerbiageOverride: function(config) {\r\n    if (DEBUG) console.warn('Overriding verbiage for current hand', config)\r\n    game.setVerbiage(config)\r\n    game.handConfigOverride = g.r\r\n  },\r\n  setHandConfigOverride: function(config) {\r\n    if (DEBUG)\r\n      console.warn('Overriding config options for current hand', config)\r\n    game._setConfigOptions(config)\r\n    game.handConfigOverride = g.r\r\n  },\r\n  hasHandConfigOverride: function() {\r\n    return game.handConfigOverride !== null && game.handConfigOverride !== g.r\r\n  },\r\n  clearHandConfigOverride: function() {\r\n    game.handConfigOverride = null\r\n  },\r\n  needCumRoundSelection: function() {\r\n    var result = !game.cumRoundAlt && game.isCumRound()\r\n    if (DEBUG) console.log('Needs cum round selection:', result)\r\n    return result\r\n  },\r\n  getLevel: function() {\r\n    return Math.floor((g.r - 1) \/ game.perLevel) + 1\r\n  },\r\n  getRemapLevel: function() {\r\n    if (typeof game.remapLevel === 'function') {\r\n      var lvl = game.getLevel()\r\n      var result = game.remapLevel(lvl, game.getIndex())\r\n      if (DEBUG && result !== lvl)\r\n        console.warn('Remapped level ' + lvl + ' to ' + result)\r\n      return result\r\n    }\r\n    return game.getLevel()\r\n  },\r\n  getIndex: function() {\r\n    return ((g.r - 1) % game.perLevel) + 1\r\n  },\r\n  getRoundIndex: function() {\r\n    var index = game.getIndex()\r\n    if (game.isCumRound()) {\r\n      index += (game.getLevel() - (game.levels + 1)) * game.perLevel\r\n    }\r\n    return index\r\n  },\r\n  getRemapRoundIndex: function() {\r\n    if (typeof game.remapHand === 'function') {\r\n      var idx = game.getRoundIndex()\r\n      var result = game.remapHand(game.getLevel(), idx)\r\n      if (DEBUG && result !== idx)\r\n        console.warn('Remapped hand ' + idx + ' to ' + result)\r\n      return result\r\n    }\r\n    return game.getRoundIndex()\r\n  },\r\n  getRoundTimeInSeconds: function() {\r\n    if (game.isWinToCumRound()) {\r\n      return Math.floor(game.getWinTimeRemaining() \/ 1000)\r\n    }\r\n    if (!game.isCumRound()) {\r\n      return game.inRoundFapping\r\n        ? game.inRoundFapTime()\r\n        : game.inRoundNoFapTime()\r\n    } else {\r\n      return game.cumRoundFapTime()\r\n    }\r\n  },\r\n  getRoundTime: function() {\r\n    if (game.noRoundTimer) return false\r\n    if (game.noCumRoundTimer && game.isCumRound()) return false\r\n    if (game.isWinToCumRound()) {\r\n      return game.getWinTimeRemaining()\r\n    }\r\n    return game.getRoundTimeInSeconds() * 1000\r\n  },\r\n  getFapInRound: function() {\r\n    return game.inRoundFapping || game.isCumRound()\r\n  },\r\n  nextLevel: function() {\r\n    var rnd = g.r + game.perLevel\r\n    if (rnd > game.perLevel * game.levels) {\r\n      rnd = game.perLevel * game.levels\r\n    }\r\n    g.r = rnd\r\n  },\r\n  i: function() {\r\n    return game.getIndex()\r\n  },\r\n  useCumRoundAuto: function() {\r\n    if (DEBUG) console.log('Auto Cum Round:', game.cumRoundAuto)\r\n    return game.cumRoundAuto && !game.winToCum\r\n  },\r\n  useCumRoundTease: function() {\r\n    return game.cumRoundAuto && game.cumRoundTease && !game.winToCum\r\n  },\r\n  lastPostIntermissionStart: null,\r\n  lastPostIntermission: 0,\r\n  _onNextRound: function() {\r\n    return game._nextPostIntermissionPage !== game._getNextPostInterPage()\r\n  },\r\n  _nextPostIntermissionPage: null,\r\n  _getNextPostInterPage: function() {\r\n    var postInterPathBase =\r\n      game.getGameModePath() + 'interp' + game.getCumRoundPath()\r\n    if (!game.isCumRound()) {\r\n      postInterPathBase += '-' + game.getRemapLevel()\r\n    }\r\n    var index = game.getRemapRoundIndex()\r\n    return postInterPathBase + '-' + index\r\n  },\r\n  _doIntermission: function() {\r\n    var interPathBase =\r\n      game.getGameModePath() + 'inter' + game.getCumRoundPath()\r\n    if (!game.isCumRound()) {\r\n      interPathBase += '-' + game.getRemapLevel()\r\n    }\r\n    var index = game.getRemapRoundIndex()\r\n    var interPath = interPathBase + '-' + index\r\n    game._nextPostIntermissionPage = game._getNextPostInterPage()\r\n    if (game.lastIntermissionStart) {\r\n      \/\/ We're completing an intermission\r\n      g.li = game.lastIntermission \/\/ Store intermission\r\n      if (DEBUG) console.log('Finished Intermission', game.lastIntermission)\r\n      game.saveState() \/\/ save our state\r\n      var interDurration = Date.now() - game.lastIntermissionStart\r\n      if (interDurration > 0) {\r\n        \/\/ If there was a winToCum game going on, offset it by intermission\r\n        game.winToCumStart += interDurration\r\n      }\r\n      game.lastIntermissionStart = 0\r\n    }\r\n    if (pages.contains(interPath) && game.lastIntermission !== interPath) {\r\n      \/\/ Looks like we need to do an intermission\r\n      if (DEBUG) console.log('Running Intermission', interPath)\r\n      game.lastIntermission = interPath\r\n      closeAll() \/\/ close all notifications\r\n      clearRoundImage() \/\/ Assume we'll need to (re)fetch our game image on return\r\n      game.lastIntermissionStart = Date.now() \/\/ Record when we started\r\n      callPage(interPath) \/\/ Call the intermission page\r\n      return true\r\n    }\r\n    return false\r\n  },\r\n  _doPostIntermission: function() {\r\n    if (!game._nextPostIntermissionPage || !game._onNextRound()) return\r\n    var interPath = game._nextPostIntermissionPage\r\n    if (game.lastPostIntermissionStart) {\r\n      \/\/ We're completing an intermission\r\n      g.lpi = game.lastPostIntermission \/\/ Store intermission\r\n      if (DEBUG)\r\n        console.log('Finished Post Intermission', game.lastPostIntermission)\r\n      game.saveState() \/\/ save our state\r\n      var interDuration = Date.now() - game.lastPostIntermissionStart\r\n      if (interDuration > 0) {\r\n        \/\/ If there was a winToCum game going on, offset it by intermission\r\n        game.winToCumStart += interDuration\r\n      }\r\n      game.lastPostIntermissionStart = 0\r\n    }\r\n    if (pages.contains(interPath) && game.lastPostIntermission !== interPath) {\r\n      \/\/ Looks like we need to do an intermission\r\n      if (DEBUG) console.log('Running PostIntermission', interPath)\r\n      game.lastPostIntermission = interPath\r\n      closeAll() \/\/ close all notifications\r\n      clearRoundImage() \/\/ Assume we'll need to (re)fetch our game image on return\r\n      game.lastPostIntermissionStart = Date.now() \/\/ Record when we started\r\n      callPage(interPath) \/\/ Call the intermission page\r\n      return true\r\n    }\r\n    return false\r\n  },\r\n  doStartWin: function() {\r\n    game.didStartWinCheck = true\r\n    beats.stopAll()\r\n    closeAll()\r\n    if (!game.didCumTease) {\r\n      game.didCumTease = true\r\n      pages.goto('win-tease')\r\n    } else if (game.isWinToCumRound() && game.cameAfterWin === null) {\r\n      clearRoundImage()\r\n      pages.goto('win-check')\r\n    } else {\r\n      window.message1 = game.text('gameWon1');\r\n      window.message2 = game.text('gameWon2');\r\n      pages.goto('win')\r\n    }\r\n  },\r\n  doCumWin: function() {\r\n    game.cameAfterWin = true\r\n    closeAll()\r\n    beats.stopAll()\r\n    window.message1 = game.text('gameWon1');\r\n    window.message2 = game.text('gameWon2');\r\n    pages.goto('win')\r\n  },\r\n  doCumWinCheck: function() {\r\n    closeAll()\r\n    beats.stopAll()\r\n    pages.goto('win-check2')\r\n  },\r\n  doCumLose: function() {\r\n    game.cameAfterWin = false\r\n    closeAll()\r\n    beats.stopAll()\r\n    pages.goto(game.getGameLossPage(false))\r\n  },\r\n  checkStatus: function() {\r\n    if (DEBUG) console.log('Checking game status')\r\n    game._gameStarted = true\r\n    \/\/ First save our state\r\n    game.saveState()\r\n\r\n    \/\/ Reset rest mode\r\n    rest.fromPenalty = false\r\n\r\n    \/\/ Set round, if needed\r\n    var roundLimits = game.getGameMode().roundLimits || {}\r\n    var roundLimit = roundLimits[game.getLevel()]\r\n    if (typeof roundLimit === 'function') {\r\n      roundLimit = roundLimit()\r\n    }\r\n    if (roundLimit && game.getIndex() > roundLimit) {\r\n      \/\/ Past round limit.  Advance to next level.\r\n      if (DEBUG)\r\n        console.warn(\r\n          'Past Round limit for Level ' + game.getIndex(),\r\n          roundLimit\r\n        )\r\n      g.r = game.perLevel * game.getLevel() + 1\r\n      if (DEBUG) console.warn('Setting round to:', g.r)\r\n    }\r\n\r\n    \/\/ Check if we need to do a post-round-intermission\r\n    if (game._doPostIntermission()) return\r\n\r\n    \/\/ If we're selecting cum round prompt, do it\r\n    if (game.needCumRoundSelection()) {\r\n      if (DEBUG) console.log('Needs cum round selection')\r\n      beats.stopAll()\r\n      callPage('cum-round-select')\r\n      return\r\n    }\r\n    \/\/ Do some blackjack stuff\r\n    \/\/ Check if we need to start the game\r\n    blackjack.startIfNot()\r\n    \/\/ Check messages\r\n    if (game.refreshGameMessages) {\r\n      game.refreshGameMessages = false\r\n      \/\/ Round config was changed.  Refresh blackjack messages.\r\n      blackjack.check(true)\r\n    }\r\n    \/\/ Has the game ended?\r\n    if (game.isEnd()) {\r\n      if (DEBUG) console.log('Game won')\r\n      game.doStartWin()\r\n      return\r\n    }\r\n    \/\/ Check if we need to do an intermission\r\n    if (game._doIntermission()) return\r\n\r\n    \/\/ Update round config, if needed\r\n    if (game.loadRoundConfig()) {\r\n      \/\/ Round config was changed.  Refresh blackjack messages.\r\n      game.refreshGameMessages = true\r\n      if (DEBUG) console.log('Round config changed')\r\n      return \/\/ Get out, we reloaded some stuff\r\n    }\r\n\r\n    \/\/ Did we just enter the cum round for the first time?\r\n    if (game.isNewCumRound()) {\r\n      if (DEBUG) console.log('Entering cum round')\r\n      pages.goto('cum-round')\r\n      return\r\n    }\r\n    if (DEBUG) console.log('Starting play', g.r)\r\n    \/\/ Check if we just shuffled\r\n    \/\/ if(blackjack.justShuffled()) {\r\n    \/\/   \/\/ Shouldn't do anything at this point, but we'll still call it for now.\r\n    \/\/   if (DEBUG) console.log('Doing shuffle notice')\r\n    \/\/   game.doShuffleNotice()\r\n    \/\/ }\r\n    if (DEBUG) console.log('checking round image and notifications...')\r\n    \/\/ Do we need to load the round image?\r\n    if (loadRoundImage()) {\r\n      \/\/ Yep, round image was just loaded. Get out, since we'll be re-called.\r\n      if (DEBUG) console.log('Loaded round image')\r\n      return\r\n    }\r\n    \/\/ Do we need to load notifications?\r\n    if (needsRoundNotifications()) {\r\n      if (DEBUG) console.log('Loading notifications')\r\n      callPage('notification-round')\r\n      return \/\/ Get out, since we'll be recalled.\r\n    }\r\n    \/\/ Set winner\r\n    game.winnerA = blackjack.check()\r\n\r\n    if (game.isWinToCumRound()) {\r\n      console.log('Stopping all beats')\r\n      beats.stopAll() \/\/ No beats for edge round\r\n    } else {\r\n      console.log('Staring game beat')\r\n      game.startBeat()\r\n    }\r\n    if (!game.message && game.isCumRound() && game.useCumRoundTease()) {\r\n      game.message = randomString(t.cumRoundMessage)\r\n    }\r\n    if (g.r >= g.tr) g.tr = g.r\r\n\r\n    if (DEBUG) console.log('Round \"WinnerA\"', game.winnerA)\r\n\r\n    return true\r\n  },\r\n  isLast: function() {\r\n    return false \/\/ g.r >= game.perLevel * game.levels + game.getCumRounds();\r\n  },\r\n  isFirstInCumRound: function() {\r\n    return g.r === game.perLevel * game.levels + 1\r\n  },\r\n  isLastInCumRound: function() {\r\n    return g.r >= game.perLevel * game.levels + game.getCumRounds()\r\n  },\r\n  isEnd: function() {\r\n    var pastEnd = g.r > game.perLevel * game.levels + game.getCumRounds()\r\n    if (game.isWinToCumRound()) {\r\n      if (game.getWinsNeeded() < 1) {\r\n        return true\r\n      }\r\n      if (pastEnd) {\r\n        \/\/ Wrap around to start of cum round until there's a winner or loser\r\n        g.r = game.perLevel * game.levels + 1\r\n        \/\/ Clear game round in case we're looping the same page\r\n        clearRoundImage()\r\n      }\r\n      return false\r\n    } else {\r\n      return pastEnd\r\n    }\r\n  },\r\n  isNewHand: function() {\r\n    \/\/ Badly named.   Should be isNewRound, but we're using that for level\r\n    if (g.r > game.lastHand || game.lastHand === null) {\r\n      game.lastHand = g.r\r\n      return true\r\n    }\r\n    return false\r\n  },\r\n  getNewHandMessage: function() {\r\n    if (!game.isNewHand()) return false\r\n    var handMessages = t.dealerRoundIntros[game.getRemapRoundIndex()]\r\n    if (!handMessages || !Array.isArray(handMessages)) return false\r\n    return mergeObject(randomString(handMessages), game)\r\n  },\r\n  isNewRound: function() {\r\n    \/\/ Badly named.  Should be isNewLevel\r\n    if (game.lastRound !== game.getLevel()) {\r\n      game.lastRound = game.getLevel()\r\n      \/\/ Re-build penalties on new rounds\r\n      buildPenalties()\r\n      return true\r\n    }\r\n    return false\r\n  },\r\n  isNewCumRound: function() {\r\n    if (DEBUG) console.log('Checking for new cum round...', g.r)\r\n    if (!game.inCumRound && game.isCumRound()) {\r\n      game.inCumRound = true\r\n      return true\r\n    }\r\n    return false\r\n  },\r\n  isCumAnyTimeCumRound: function() {\r\n    return game.isCumRound() && !game.winToCum\r\n  },\r\n  isCumRound: function() {\r\n    return game.getLevel() > game.levels\r\n  },\r\n  isWinToCumRound: function() {\r\n    return game.isCumRound() && game.winToCum\r\n  },\r\n  getRoundBpm: function() {\r\n    return game.bpms[Math.round(game.getLevel())] || game.bpms[game.bpms.length - 1]\r\n  },\r\n  getStrokeStartBpm: function() {\r\n    return Math.min(game.getRoundBpm() + 50, game.bpmMax)\r\n  },\r\n  getStrokeEndBpm: function() {\r\n    return game.getRoundBpm() + 150\r\n  },\r\n  startBeat: function() {\r\n    if (game.getFapInRound()) {\r\n      var bpm = game.getRoundBpm()\r\n      var difficultyLevel = game.getDifficultyLevelAdjusted(0.5)\r\n      bpm = Math.min(Math.round((bpm \/ game.roundBpmDivisor) * difficultyLevel), game.bpmMax)\r\n      if (DEBUG) console.log('Starting level ' + game.getLevel() + ' round beats ', bpm)\r\n      beats.start(bpm)\r\n    } else {\r\n      if (DEBUG) console.log('No round beats', game.inRoundFapping)\r\n      beats.stopAll()\r\n    }\r\n  },\r\n  volumeUp: function(diff) {\r\n    game.volume += diff || game.volumeStep\r\n    if (game.volume > 1) {\r\n      game.volume = 1\r\n    }\r\n    if (DEBUG) console.log(game.volume)\r\n    game.updateVolume()\r\n  },\r\n  volumeDown: function(diff) {\r\n    game.volume -= diff || game.volumeStep\r\n    if (game.volume < 0) {\r\n      game.volume = 0\r\n    }\r\n    if (DEBUG) console.log(game.volume)\r\n    game.updateVolume()\r\n  },\r\n  volumeReset: function() {\r\n    game.volume = settingDefaults.volume\r\n    game.updateVolume()\r\n  },\r\n  updateVolume: function() {\r\n    beats.volume()\r\n    moans.volume()\r\n    roulette.volume()\r\n  },\r\n  \/\/ Save game so user can continue in the case of page reload, etc.\r\n  saveState: function() {\r\n    if (DEBUG) console.log('Saving game state', g)\r\n    g.t = Date.now()\r\n    if (typeof game.onSaveState === 'function') {\r\n      game.onSaveState()\r\n    }\r\n    teaseStorage.setItem('g', g)\r\n  },\r\n  \/\/ Check if there is a recent save state that can be resorted\r\n  hasRecentSave: function() {\r\n    var savedState = teaseStorage.getItem('g')\r\n    return (\r\n      savedState &&\r\n      savedState.t &&\r\n      Date.now() - savedState.t < game.maxSaveAge * 1000\r\n    )\r\n  },\r\n  \/\/ Restore recent save state\r\n  restoreState: function() {\r\n    var savedState = teaseStorage.getItem('g') || {}\r\n    for (var s in savedState) {\r\n      g[s] = savedState[s]\r\n    }\r\n    if (!g.pc) {\r\n      \/\/ Saved before penalty counter was implemented.  Add it.\r\n      g.pc = {}\r\n    }\r\n    if (g.wc === undefined) {\r\n      \/\/ Saved before win count was implemented.  Add it.\r\n      g.wc = 0\r\n    }\r\n    if (g.gm === undefined) {\r\n      \/\/ Saved before gameMode was implemented.  Add it.\r\n      g.gm = null\r\n    }\r\n    if (g.li === undefined) {\r\n      \/\/ Saved before intermission was implemented.  Add it.\r\n      g.li = null\r\n    }\r\n    if (g.lp === undefined) {\r\n      \/\/ Saved before intermission was implemented.  Add it.\r\n      g.lp = null\r\n    }\r\n    game.lastIntermission = g.li\r\n    game.lastPostIntermission = g.lp\r\n    if (g.gm) {\r\n      if (DEBUG) console.log('Restoring Game Mode', g.gm)\r\n      game.setGameMode(g.gm)\r\n      if (game.gameMode !== g.gm) {\r\n        console.error('Invalid saved gameMode:', g.gm)\r\n        g.gm = null\r\n      }\r\n    } else {\r\n      if (DEBUG) console.log('No Game Mode To Restore', g)\r\n    }\r\n    if (game.isCumRound()) {\r\n      \/\/ We're re-entering a cum round.  Start from the top\r\n      g.li = null\r\n      g.lp = null\r\n      game.lastIntermission = null\r\n      game.lastPostIntermission = null\r\n      g.r = game.perLevel * game.levels + 1\r\n      g.wc = 0\r\n    }\r\n    if (!game.difficulties || !game.difficulties[g.df]) {\r\n      g.df = null\r\n    }\r\n    game.difficulty = g.df\r\n    if (typeof game.onGameRestore === 'function') {\r\n      game.onGameRestore()\r\n    }\r\n    setPenaltyCounts()\r\n  },\r\n  getGameState: function(key) {\r\n    return g[key]\r\n  },\r\n  setGameState: function(key, value) {\r\n    return g[key] = value\r\n  },\r\n  \/\/ Remove stored state, reset game\r\n  clearState: function(skipStorage, skipRoundReset) {\r\n    if (DEBUG) console.log('Clearing game state')\r\n    if (!skipStorage) teaseStorage.removeItem('g')\r\n    if (!skipRoundReset) {\r\n      g.r = 1\r\n      g.tr = 1 \/\/ Highest round completed (used in cum round)\r\n      g.c = game.defaultRests\r\n      g.t = null\r\n      g.pc = {}\r\n      g.wc = 0 \/\/ Win count for winToCum\r\n      g.gm = null\r\n      g.li = null \/\/ Last intermission\r\n      g.lp = null \/\/ Last post intermission\r\n      g.df = null \/\/ Difficulty level\r\n      game.difficulty = g.df\r\n      if (typeof game.onGameReset === 'function') {\r\n        game.onGameReset(skipStorage)\r\n      }\r\n      setPenaltyCounts()\r\n      game.resetModeArrays()\r\n    }\r\n  },\r\n  \/\/ Do things that should be done after game settings have changed.\r\n  initGameSettings: function() {\r\n    buildPenalties()\r\n  },\r\n  _soundPages: null,\r\n  getSoundPages: function () {\r\n    if(game._soundPages)return game._soundPages\r\n    var basePage = '--audio-'\r\n    var results = []\r\n    for (var i = 1, l = 5; i <= l; i++) {\r\n      var page = basePage + i\r\n      if (pages.contains(page)) {\r\n        results.push(page)\r\n      } else {\r\n        break\r\n      }\r\n    }\r\n    if (!results.length) {\r\n      console.error('Missing audio definitaions: --audio-1')\r\n    }\r\n    game._soundPages = results\r\n    if (DEBUG) console.log('Found audio pages:', results)\r\n    return results\r\n  },\r\n  _lastAudioProfile: null,\r\n  generateSoundOptions: function (sounds, opts) {\r\n    sounds = sounds || []\r\n    opts = opts || {}\r\n    var soundPages = game.getSoundPages()\r\n    var minLen = Math.min(sounds.length, soundPages.length)\r\n    if (minLen < 2) {\r\n      return\r\n    }\r\n    var options = {}\r\n    for (var i = 0; i < minLen; i++) {\r\n      var soundPage = sounds[i]\r\n      options[i+1 + ''] = {\r\n        label: soundPage.label, \/\/ Label for button\r\n      }\r\n    }\r\n    var label = opts.label || 'Audio Profile'\r\n    game.setSettingOption(\r\n      'audioProfile', \r\n      \/\/ Setting definition:\r\n      {\r\n        force: true, \/\/ Force this setting to allow use of existing varable\r\n        type: storageTypes.GAME, \/\/ Use this, unless you've created your own\r\n        label: opts.label || 'Audio Profile', \/\/ What to display in menu\r\n        icon: opts.icon || '\ud83c\udfb5', \/\/ Optional icon\r\n        \/\/                       If not found, a simple default is used.\r\n        page: opts.page || 'settings', \/\/ Where to display the selection\r\n        target: 'settings-beat-profile', \/\/ Page used to generate radio buttons\r\n        \/\/ Define radio button\r\n        prompt: opts.prompt || function(){ \/\/ Optional function to generate setting prompt\r\n          return \"What's your \" + label + \" preference?\"\r\n        },\r\n        onEnter: function() {\r\n          beats.start(60)\r\n        },\r\n        \r\n        onExit: function() {\r\n          beats.stopAll()\r\n        },\r\n        afterSelect: function(calling) {\r\n          calling = calling || pages.getCurrentPageId()\r\n          return game.loadSounds(calling)\r\n        },\r\n        integer: true,\r\n        options: options,\r\n        key: '$aud', \/\/ short key for storage\r\n        defaultValue: 1, \/\/ Default value\r\n      },\r\n      opts.position\r\n    )\r\n  },\r\n  stopMoan: function(key, index) {\r\n    if (key) {\r\n      moans.stop(key, index)\r\n    } else {\r\n      moans.stopAll()\r\n    }\r\n    return '' \/\/ so verbiage merge can use this\r\n  },\r\n  playMoan: function(key, index, indexEnd, stop) {\r\n    if (!game.enableMoans) return ''\r\n    moans.start(key, index, indexEnd, stop)\r\n    return '' \/\/ so verbiage merge can use this\r\n  },\r\n  loadSounds: function (calling) {\r\n    calling = calling && pages.contains(calling) ? calling : pages.getCurrentPageId()\r\n    if (game._lastAudioProfile === game.audioProfile) {\r\n      if (DEBUG) console.warn('Audio page ' +game.audioProfile + ' already loaded.')\r\n      return false\r\n    }\r\n    \/\/ beats.stopAll()\r\n    moans.stopAll()\r\n    beats.inited = false\r\n    moans.inited = false\r\n    game._lastAudioProfile = game.audioProfile\r\n    var soundPage = game.getSoundPages()[game.audioProfile - 1]\r\n    if (soundPage) {\r\n      \/\/ Destroy all old sounds before we load the audio page\r\n      if (DEBUG) console.warn('Purging moans:', soundPage)\r\n      moans.purge()\r\n      if (DEBUG) console.warn('Purging beats:', soundPage)\r\n      game._beats && game._beats.purgeSamples()\r\n      if (DEBUG) console.warn('Purging clicks:', soundPage)\r\n      roulette.purgeSounds()\r\n      if (DEBUG) console.warn('Loading sound page:', soundPage)\r\n      callPage(soundPage, function() {\r\n        beats.init(true)\r\n        beats.volume()\r\n        moans.init()\r\n        moans.volume()\r\n        roulette.initSounds()\r\n        roulette.volume()\r\n        beats.inited = false\r\n        moans.inited = false\r\n        roulette.soundsInited = false\r\n      }, calling)\r\n      return true\r\n    } else {\r\n      console.error('Unable to load --audio-' + game.audioProfile + ' page.', game.getSoundPages())\r\n    }\r\n    return false\r\n  },\r\n  loadModules: function(page) {\r\n    if (!game.loadedModules) game.loadedModules = []\r\n    if (game.loadedModules[page] || !pages.contains(page)) {\r\n      game.loadedModules[page] = true\r\n      return false\r\n    }\r\n    game.loadedModules[page] = true\r\n    callPage(page)\r\n    return true\r\n  },\r\n  loadCoreConfig: function() {\r\n    var coreConfigPath = 'core-config'\r\n    if (!game.loadedCoreConfig) {\r\n      \/\/ Load rest of config\r\n      if (DEBUG) console.warn('Loading core config page', coreConfigPath)\r\n      game.loadedCoreConfig = coreConfigPath\r\n      if (pages.contains(coreConfigPath)) {\r\n        callPage(coreConfigPath, false, false)\r\n        return true\r\n      } else {\r\n        if (DEBUG) console.error('MISSING CORE CONFIG PAGE:', coreConfigPath)\r\n      }\r\n    }\r\n    return false\r\n  },\r\n  loadCoreVerbiage: function(configCaller) {\r\n    configCaller = configCaller || true\r\n    if (game.loadedCoreVerbiage && configCaller === true) return false\r\n    if (game.loadedCoreVerbiage !== configCaller) {\r\n      \/\/ Load rest of config\r\n      var coreVerbiagePath = 'core-verbiage'\r\n      if (DEBUG) console.warn('Loading core verbiage page', coreVerbiagePath)\r\n      game.loadedCoreVerbiage = configCaller\r\n      if (pages.contains(coreVerbiagePath)) {\r\n        callPage(coreVerbiagePath, false, false)\r\n        return true\r\n      } else {\r\n        if (DEBUG) console.error('MISSING CORE VERBIAGE:', coreVerbiagePath)\r\n      }\r\n    }\r\n    return false\r\n  },\r\n  _getLevelConfig: function(level) {\r\n    if (!game._gameStarted) return {}\r\n    return Object.assign(\r\n      {},\r\n      _gameDefaults,\r\n      (game.getGameMode().levelConfig || {})[0] || {},\r\n      (game.getGameMode().levelConfig || {})[level] || {},\r\n      game.isCumRound()\r\n        ? (game.getCumRoundAltConfig() || {}).gameSettings || {}\r\n        : {}\r\n    )\r\n  },\r\n  _loadLevelConfig: function(level) {\r\n    \/\/ var settings = (game.getGameMode().levelConfig || {})[level] || {}\r\n    \/\/ if (DEBUG && game.getGameMode().levelConfig) console.warn('Level config override:', level, settings);\r\n    if (DEBUG) console.warn('Loading Level config', game._getLevelConfig(level))\r\n    game._setConfigOptions(game._getLevelConfig(level))\r\n  },\r\n  \/\/ Load Round config\r\n  loadRoundConfig: function() {\r\n    var gameLevel = game.getRemapLevel() || 1\r\n    var configPath =\r\n      game.getGameModePath() + 'verbiage' + game.getCumRoundPath()\r\n    if (!game.isCumRound()) configPath += '-' + gameLevel\r\n    if (game.hasHandConfigOverride()) {\r\n      \/\/ round config override has switched to a new level\r\n      \/\/ reset core verbiages\r\n      if (DEBUG)\r\n        console.warn('Hand changed after a hand specific config override')\r\n      game.loadedCoreVerbiage = null\r\n      game.loadedVerbiage = null\r\n      game.clearHandConfigOverride()\r\n    }\r\n    if (game.loadCoreVerbiage(configPath)) {\r\n      \/\/ Needed to re-load core verbiage vars\r\n      \/\/ Load base game settings:\r\n      \/\/ game._loadLevelConfig(0);\r\n      \/\/ Load cum round vars?\r\n      \/\/ if (game.isCumRound()) {\r\n      \/\/   var config = game.getCumRoundAltConfig();\r\n      \/\/   var settings = config.gameSettings || {}\r\n      \/\/   game._setConfigOptions(settings);\r\n      \/\/ } else {\r\n      \/\/   game._loadLevelConfig(game.getRemapLevel());\r\n      \/\/ }\r\n      game._loadLevelConfig(game.getRemapLevel())\r\n      return true\r\n    }\r\n    if (game.loadedVerbiage !== configPath) {\r\n      if (DEBUG) console.warn('loading round config', configPath)\r\n      game.loadedVerbiage = configPath\r\n      game.setVerbiage(game.verbiage)\r\n      if (pages.contains(configPath)) {\r\n        callPage(configPath, false, false)\r\n        return true\r\n      } else {\r\n        if (DEBUG) console.warn('NO ROUND\/LEVEL VERBIAGE:', configPath)\r\n        return false\r\n      }\r\n    } else {\r\n      if (DEBUG) console.log('already did round verbiage', configPath)\r\n      return false\r\n    }\r\n  },\r\n  setVerbiage: function(data) {\r\n    if (DEBUG) console.log('Setting Verbiage', data)\r\n    for (var i in data) {\r\n      t[i] = data[i]\r\n    }\r\n    if (DEBUG) console.log('Set Verbiage', t)\r\n  },\r\n  getPenalty: function(penaltyId) {\r\n    if (DEBUG) console.log('Locating penalty: ', penaltyId)\r\n    for (var i = 0, l = penaltyOccurrence.length; i < l; i++) {\r\n      var p = penaltyOccurrence[i]\r\n      if (p.o.id === penaltyId) {\r\n        if (DEBUG) console.log('Loading penalty: ', penaltyId, p)\r\n        var result = p.pf(p.o)\r\n        if (DEBUG) console.log('Loaded penalty: ', result, p)\r\n        return result\r\n      }\r\n      console.error(\r\n        'Unable to locate penaltyOccurrence instance of: ',\r\n        penaltyId\r\n      )\r\n      return null\r\n    }\r\n  },\r\n  \/\/ Initialize game\r\n  init: function() {\r\n    \/\/ Load any pre-config add-on modules\r\n    if (game.loadModules('modules-pre-config')) return false\r\n    \/\/ Load core config\r\n    if (game.loadCoreConfig()) return false\r\n    if (game.loadCoreVerbiage()) return false\r\n    \/\/ Set game arrays\r\n    gds = game.getDifficultiesArray()\r\n    gms = game.getGameModesArray()\r\n    if (gms[0]) game.setGameMode(gms[0].id) \/\/ Set game mode to first mode by default\r\n    \/\/ Load round config\r\n    \/\/ if (game.loadRoundConfig()) return false;\r\n    \/\/ Load saved settings and generate defaults\r\n    loadSettings()\r\n    \/\/ Load any post-config add-on modules\r\n    if (game.loadModules('modules-post-config')) return false\r\n    if(game.loadSounds()) return false\r\n    \/\/ Set initial game state\r\n    game.clearState(true)\r\n    \/\/ init game from settings\r\n    game.initGameSettings()\r\n    \/\/ Init the blackjack game\r\n    blackjack = new BlackJackGame({\r\n      dealerSaftey: game.dealerSaftey,\r\n      numberOfDecks: game.numberOfDecks,\r\n      cardButtonClass: game.cardButtonClass,\r\n      t: t, \/\/ text for blackjack game\r\n      updatePlayLabels: function() {\r\n        \/\/ Callback to update notification labels\r\n        if (n.round) {\r\n          var round_n = Notification.get('round')\r\n          if (game.isCumRound()) {\r\n            if (game.winToCum) {\r\n              round_n.setTitle(\r\n                'Rounds Won: ' + g.wc + '\/' + game.cumRoundsToWin\r\n              )\r\n            } else {\r\n              round_n.setTitle('Round: CUM!; Rests: ' + g.c)\r\n            }\r\n          } else {\r\n            round_n.setTitle(\r\n              'Round: ' +\r\n                game.getLevel() +\r\n                '.' +\r\n                game.getIndex() +\r\n                '; Rests: ' +\r\n                g.c\r\n            )\r\n          }\r\n        }\r\n      },\r\n      onDealerWin: function(bj) {\r\n        \/\/ Dealer won (not yet implemented)\r\n        if (game.isWinToCumRound()) {\r\n          \/\/ Increment player's win count\r\n          if (blackjack) {\r\n            \/\/ ???\r\n          }\r\n        }\r\n      },\r\n      onPlayerWin: function(bj) {\r\n        \/\/ Player won\r\n        if (game.isWinToCumRound()) {\r\n          \/\/ Increment player's win count\r\n          g.wc++\r\n        }\r\n      },\r\n    })\r\n    return true\r\n  },\r\n}\r\n\r\nfunction _showSelectOption(i, options) {\r\n  var option = options[i]\r\n  var optionHide = option && option.optionHide\r\n  if (typeof optionHide === 'function') {\r\n    optionHide = optionHide()\r\n  }\r\n  var show = option && option.show\r\n  if (typeof show === 'undefined') {\r\n    show = true\r\n  }\r\n  if (typeof show === 'function') {\r\n    show = show()\r\n  }\r\n  return show && option && !optionHide\r\n}\r\n\r\nfunction _selectableOptions(options) {\r\n  return options.filter(function(o) {\r\n    return (\r\n      !o.optionHide || (typeof o.optionHide === 'function' && !o.optionHide())\r\n    )\r\n  })\r\n}\r\n\r\nfunction _sgds(i) {\r\n  return _showSelectOption(i, gds)\r\n}\r\n\r\nfunction _sgms(i) {\r\n  return _showSelectOption(i, gms)\r\n}\r\n\r\nfunction _scr(i) {\r\n  return _showSelectOption(i, cr)\r\n}\r\n\r\nfunction _gdst(i) {\r\n  return gds[i] && gds[i].title\r\n}\r\n\r\nfunction _gmst(i) {\r\n  return gms[i] && gms[i].title\r\n}\r\n\r\nfunction _crt(i) {\r\n  return cr[i] && cr[i].title\r\n}\r\n\r\n\/\/ Storage type handlers\r\nvar storageTypes = {\r\n  \/\/ Storage items we're not going to load\/store for now\r\n  NONE: {\r\n    \/\/ Nothing to do for disabled items\r\n    getKey: function(s) {\r\n      return s\r\n    },\r\n  },\r\n  ALIAS: {\r\n    \/\/ Nothing to do for alias items\r\n    getKey: function(s) {\r\n      return s\r\n    },\r\n  },\r\n  REMOVE: {\r\n    \/\/ Key should be removed from storage\r\n    getKey: function(s) {\r\n      return s\r\n    },\r\n    afterLoad: function(s, val) {\r\n      if (val !== undefined) teaseStorage.removeItem(s)\r\n    },\r\n  },\r\n  \/\/ Values stored in game.x\r\n  GAME: {\r\n    \/\/ Return current setting value\r\n    get: function(s) {\r\n      var val = game[s]\r\n      if (val !== undefined) return val\r\n      var obj = gameSettingStore[s]\r\n      return obj && obj.defaultValue\r\n    },\r\n    \/\/ Replace current setting value\r\n    set: function(s, val, force) {\r\n      var obj = gameSettingStore[s]\r\n      if (!force && obj && typeof obj.block === 'function') {\r\n        var blockMessage = obj.block(obj, val)\r\n        if (blockMessage) return blockMessage\r\n      }\r\n      if (obj.integer) {\r\n        var intVal = parseInt(val, 10)\r\n        if (isNaN(intVal)) {\r\n          console.error('Invalid value for ' + s, val + ' is not an integer.')\r\n          return 'Invalid value.'\r\n        }\r\n        val = intVal\r\n      }\r\n      switch (s) {\r\n        case 'gameMode':\r\n          if (val) {\r\n            game.setGameMode(val)\r\n          }\r\n          break\r\n\r\n        case 'cumRoundAlt':\r\n          if (val) {\r\n            game.setCumRoundAlt(val)\r\n          }\r\n          break\r\n\r\n        case 'ulp':\r\n          if (!val) {\r\n            game._resetToCore()\r\n          }\r\n          game[s] = val\r\n          break\r\n\r\n        default:\r\n          game[s] = val\r\n      }\r\n      if (obj && typeof obj.afterSet === 'function') {\r\n        return obj.afterSet(val)\r\n      }\r\n    },\r\n    \/\/ Return key for storage\r\n    getKey: function(s) {\r\n      \/\/ If you have more than one storage type, prepend with something to avoid namespace conflicts.\r\n      \/\/  like: return 'GAME_' + s;\r\n      return (gameSettingStore[s] && gameSettingStore[s].key) || s\r\n    },\r\n    afterLoad: function(s, val) {\r\n      \/\/ If we've remapped our storage key to a shorter one, clear the old one to save space.\r\n      if (\r\n        val !== undefined &&\r\n        gameSettingStore[s] &&\r\n        gameSettingStore[s].remap &&\r\n        teaseStorage.getItem(s) !== undefined\r\n      ) {\r\n        var key = getStorageTypeKey(s)\r\n        if (DEBUG) console.warn('Remapping storage from', s, 'to', key)\r\n        teaseStorage.removeItem(s)\r\n        teaseStorage.setItem(key, val)\r\n      }\r\n    },\r\n    valueFilter: function(s, val) {\r\n      if (\r\n        val === undefined &&\r\n        gameSettingStore[s] &&\r\n        gameSettingStore[s].remap\r\n      ) {\r\n        val = teaseStorage.getItem(s)\r\n      }\r\n      return val\r\n    },\r\n  },\r\n}\r\n\r\nfunction gsShowOn(s) {\r\n  if (!s) return\r\n  var radioOpt = _getRadioOptionSelector(s)\r\n  if (radioOpt) {\r\n    var opt = radioOpt.option\r\n    if (typeof opt.show === 'function') {\r\n      try {\r\n        if (!opt.show()) return false\r\n      } catch (e) {\r\n        console.error('Invalid show() function in option: ', s)\r\n        throw e\r\n      }\r\n    }\r\n    var setting = radioOpt.setting\r\n    if (setting.integer) {\r\n      return gs(setting.id) === parseInt(opt.id, 10)\r\n    }\r\n    return gs(setting.id) === opt.id\r\n  }\r\n  var obj = resolveSettingFromStore(s)\r\n  if (obj) {\r\n    if (typeof obj.show === 'function' && !obj.show()) {\r\n      return false\r\n    }\r\n    if (!game.showSetting[s]) {\r\n      return false\r\n    }\r\n    if (obj.target) {\r\n      return true\r\n    }\r\n    return !!gs(s)\r\n  }\r\n  return false\r\n}\r\n\r\nfunction gsShowOff(s) {\r\n  if (!s) return\r\n  var radioOpt = _getRadioOptionSelector(s)\r\n  if (radioOpt) {\r\n    var opt = radioOpt.option\r\n    if (typeof opt.show === 'function') {\r\n      if (!opt.show()) return false\r\n    }\r\n    var setting = radioOpt.setting\r\n    if (setting.integer) {\r\n      return gs(setting.id) !== parseInt(opt.id, 10)\r\n    }\r\n    return gs(setting.id) !== opt.id\r\n  }\r\n  var obj = resolveSettingFromStore(s)\r\n  if (obj) {\r\n    if (typeof obj.show === 'function' && !obj.show()) {\r\n      return false\r\n    }\r\n    if (!game.showSetting[s]) {\r\n      return false\r\n    }\r\n    if (obj.target) {\r\n      return false\r\n    }\r\n    return !gs(s)\r\n  }\r\n  return false\r\n}\r\n\r\nfunction gsResolveLabel(o, useAlt) {\r\n  if (!o) return\r\n  if (typeof o.label === 'function') {\r\n    o.label = o.label()\r\n  }\r\n  if (typeof o.altLabel === 'function') {\r\n    o.altLabel = o.altLabel()\r\n  }\r\n  return (useAlt && o.altLabel) || o.label\r\n}\r\n\r\nfunction gsLabelOn(s) {\r\n  if (!s) return\r\n  var radioOpt = _getRadioOptionSelector(s)\r\n  if (radioOpt) {\r\n    var opt = radioOpt.option\r\n    var label = []\r\n    var olabel = gsResolveLabel(opt, true)\r\n    if (typeof opt.icon === 'function') opt.icon = opt.icon()\r\n    label.push(R_ON)\r\n    label.push(olabel)\r\n    if (opt.icon) {\r\n      label.push(opt.icon)\r\n    }\r\n    return label.join(' ')\r\n  }\r\n  var obj = resolveSettingFromStore(s)\r\n  if (obj) {\r\n    var label = []\r\n    var olabel = gsResolveLabel(obj, true)\r\n    if (typeof obj.icon === 'function') obj.icon = obj.icon()\r\n    if (obj.icon) {\r\n      label.push(obj.icon)\r\n    }\r\n    label.push(olabel)\r\n    if (!obj.target) {\r\n      label.push(S_ON)\r\n    }\r\n    if (DEBUG) console.warn('Label On for:', s, label.join(' '))\r\n    return label.join(' ')\r\n  }\r\n  return false\r\n}\r\n\r\nfunction gsLabelOff(s) {\r\n  if (!s) return\r\n  var radioOpt = _getRadioOptionSelector(s)\r\n  var label = []\r\n  if (radioOpt) {\r\n    var opt = radioOpt.option\r\n    var olabel = gsResolveLabel(opt, true)\r\n    if (typeof opt.icon === 'function') opt.icon = opt.icon()\r\n    label.push(R_OFF)\r\n    label.push(olabel)\r\n    if (opt.icon) {\r\n      label.push(opt.icon)\r\n    }\r\n    return label.join(' ')\r\n  }\r\n  var obj = resolveSettingFromStore(s)\r\n  if (obj) {\r\n    var olabel = gsResolveLabel(obj, true)\r\n    if (typeof obj.icon === 'function') obj.icon = obj.icon()\r\n    if (obj.icon) {\r\n      label.push(obj.icon)\r\n    }\r\n    label.push(olabel)\r\n    if (!obj.target) {\r\n      label.push(S_OFF)\r\n    }\r\n    if (DEBUG) console.warn('Label Off for:', s, label.join(' '))\r\n    return label.join(' ')\r\n  }\r\n  return false\r\n}\r\n\r\nfunction enableSetting(s) {\r\n  if (!s) return\r\n  var radioOpt = _getRadioOptionSelector(s)\r\n  if (radioOpt) {\r\n    return _selectRadioSetting(radioOpt)\r\n  }\r\n  var obj = resolveSettingFromStore(s)\r\n  if (obj) {\r\n    if (typeof obj.target === 'string') {\r\n      callPage(obj.target)\r\n      return\r\n    }\r\n    if (typeof obj.enable === 'function') {\r\n      obj.enable()\r\n    } else {\r\n      var textKey = obj.textKey || (obj.label || '').replace(\/[^a-z]\/i, '')\r\n      if (!textKey) {\r\n        console.error('No label or textKey defined for', s)\r\n        textKey = 'undefined'\r\n      }\r\n      var textLookup = 'setting' + textKey + 'Enabled'\r\n      var text = randomString(t[textLookup] || []) || obj.enableMessage\r\n      if (typeof text === 'function') {\r\n        text = text()\r\n      }\r\n      if (!text) {\r\n        if (DEBUG) console.warn('No verbiage defined for', textLookup)\r\n        var label = obj.label || s\r\n        if (typeof label === 'function') label = label()\r\n        text = \"You've <u>enabled<\/u> \" + label\r\n      }\r\n      ss(s, true, text)\r\n    }\r\n  } else {\r\n    console.error('Unknown gameSettingStore:', s)\r\n  }\r\n}\r\n\r\nfunction _getRadioOptionSelector(ref) {\r\n  \/\/ console.error('Getting option selector for', ref)\r\n  var optMatch = ref && ref.match(\/^([^\\.]+?)\\.(.+)$\/)\r\n  if (!optMatch) return\r\n  var s = optMatch[1]\r\n  var o = optMatch[2]\r\n  var obj = resolveSettingFromStore(s)\r\n  if (!obj) return\r\n  obj.id = s\r\n  var opts = obj.options\r\n  if (!opts) return\r\n  var opt = opts[o]\r\n  if (!opt) return\r\n  opt.id = o\r\n  var result = {\r\n    option: opt,\r\n    options: opts,\r\n    setting: obj,\r\n  }\r\n  \/\/ console.error('Found radio options for selector',  ref, result, optMatch)\r\n  return result\r\n}\r\n\r\nfunction _selectRadioSetting(radioOpt) {\r\n  \r\n  var opt = radioOpt.option\r\n  var setting = radioOpt.setting\r\n  if (typeof opt.block === 'function') {\r\n    var blockMessage = opt.block(opt)\r\n    if (blockMessage) {\r\n      game.settingMessage = mergeObject(blockMessage, opt)\r\n      pages.goto(pages.getCurrentPageId())\r\n      return\r\n    }\r\n  }\r\n  var selectMessage = opt.selectMessage\r\n  if (typeof selectMessage === 'function') {\r\n    selectMessage = selectMessage(opt)\r\n  }\r\n  if (!selectMessage) {\r\n    selectMessage =\r\n      \"You've selected <u>\" +\r\n      opt.label +\r\n      '<\/u> for <i>' +\r\n      setting.label +\r\n      '<\/i>'\r\n  }\r\n  ss(setting.id, opt.id, selectMessage)\r\n}\r\n\r\nfunction disableSetting(s) {\r\n  if (!s) return\r\n  var radioOpt = _getRadioOptionSelector(s)\r\n  if (radioOpt) {\r\n    return _selectRadioSetting(radioOpt)\r\n  }\r\n  var obj = resolveSettingFromStore(s)\r\n  if (obj) {\r\n    if (typeof obj.target === 'string') {\r\n      callPage(obj.target)\r\n      return\r\n    }\r\n    if (typeof obj.disable === 'function') {\r\n      obj.disable()\r\n    } else {\r\n      var textKey = obj.textKey || (obj.label || '').replace(\/[^a-z]\/i, '')\r\n      if (!textKey) {\r\n        console.error('No label or textKey defined for', s)\r\n        textKey = 'undefined'\r\n      }\r\n      var textLookup = 'setting' + textKey + 'Disabled'\r\n      var text = randomString(t[textLookup] || []) || obj.disableMessage\r\n      if (typeof text === 'function') {\r\n        text = text()\r\n      }\r\n      if (!text) {\r\n        if (DEBUG) console.warn('No verbiage defined for', textLookup)\r\n        var label = obj.label || s\r\n        if (typeof label === 'function') label = label()\r\n        text = \"You've <u>disabled<\/u> \" + label\r\n      }\r\n      ss(s, false, text)\r\n    }\r\n  } else {\r\n    console.error('Unknown gameSettingStore:', s)\r\n  }\r\n}\r\n\r\nfunction ss(s, value, message) {\r\n  var sType = getStorageType(s)\r\n  var newMessage\r\n  if (sType) {\r\n    if (typeof sType.set === 'function') {\r\n      newMessage = sType.set(s, value)\r\n      saveSettings()\r\n    }\r\n  }\r\n  if (!message) return newMessage\r\n  game.settingMessage = mergeObject(newMessage || message, game)\r\n  var setting = resolveSettingFromStore(s)\r\n  if (setting) {\r\n    var afterSelect = setting.afterSelect\r\n    if (typeof afterSelect === 'function') {\r\n      var result = afterSelect(pages.getCurrentPageId())\r\n      if (result) {\r\n        return\r\n      }\r\n    }\r\n  }\r\n  pages.goto(pages.getCurrentPageId())\r\n}\r\n\r\nfunction gs(s) {\r\n  var sType = getStorageType(s)\r\n  if (sType && typeof sType.get === 'function') {\r\n    return sType.get(s)\r\n  }\r\n  return undefined\r\n}\r\n\r\nfunction currentPageRadioSetting(page) {\r\n  page = page || pages.getCurrentPageId()\r\n  var radioSettings = Object.keys(gameSettingStore).filter(function(s) {\r\n    var setting = resolveSettingFromStore(s)\r\n    if (setting.options && setting.target === page) {\r\n      return true\r\n    }\r\n  })\r\n  if (radioSettings.length) {\r\n    return resolveSettingFromStore(radioSettings[0])\r\n  }\r\n  return null\r\n}\r\n\r\nfunction currentPageSettings(page) {\r\n  page = page || pages.getCurrentPageId()\r\n  var radioSetting = currentPageRadioSetting(page)\r\n  if (radioSetting) {\r\n    var options = radioSetting.options\r\n    var result = Object.keys(options).reduce(function(a, o) {\r\n      var option = options[o]\r\n      option.id = o\r\n      a.push(radioSetting.id + '.' + o)\r\n      return a\r\n    }, [])\r\n    \/\/ console.error('found radioSetting', radioSetting, result)\r\n    return result\r\n  }\r\n  \/\/ console.warn('Settings for page:', Object.keys(gameSettingStore).filter(function(s) {\r\n  \/\/   return gameSettingStore[s].page === page\r\n  \/\/ }))\r\n  return Object.keys(gameSettingStore).filter(function(s) {\r\n    return gameSettingStore[s].page === page\r\n  })\r\n}\r\n\r\nfunction currentPageSetting(page) {\r\n  var matches = Object.keys(gameSettingStore).filter(function(s) {\r\n    return gameSettingStore[s].target === page\r\n  })\r\n  var s = matches[0]\r\n  return resolveSettingFromStore(s)\r\n}\r\n\r\nfunction resolveSettingFromStore(s) {\r\n  var pageSetting = gameSettingStore[s]\r\n  if (!pageSetting) return\r\n  if (pageSetting.aliasOf) {\r\n    alias = pageSetting\r\n    var aliasedSetting = gameSettingStore[pageSetting.aliasOf]\r\n    if (!aliasedSetting) {\r\n      console.error('Unable to resolve setting alias \"' + alias.aliasOf + '\" in \"' + s + '\"' )\r\n      return\r\n    }\r\n    var pageSetting = {}\r\n    s = alias.aliasOf\r\n    gsResolveLabel(alias)\r\n    gsResolveLabel(aliasedSetting)\r\n    Object.keys(aliasedSetting).concat(Object.keys(alias)).forEach(function(k){\r\n      if (k.match(\/^(altLabel|label|page|icon)$\/) && alias[k] !== undefined) {\r\n        pageSetting[k] = alias[k]\r\n      } else {\r\n        pageSetting[k] = aliasedSetting[k]\r\n      }\r\n    })\r\n    \/\/ if (DEBUG) console.warn('Using ALIAS setting:', alias, aliasedSetting, pageSetting)\r\n  } else {\r\n    gsResolveLabel(pageSetting)\r\n  }\r\n  pageSetting.id = s\r\n  return pageSetting\r\n}\r\n\r\nfunction currentPageResetMessage(page) {\r\n  page = page || pages.getCurrentPageId()\r\n  var label\r\n  if (page !== 'settings') {\r\n    var pageSetting = currentPageSetting(page)\r\n    label = ((pageSetting && pageSetting.label) || page)\r\n    if (typeof label === 'function') {\r\n      label = label()\r\n    }\r\n    label = (label || '').toLowerCase() \r\n  } else {\r\n    label = 'all settings'\r\n  }\r\n  return \"You've <u>reset<\/u> \" + label + ' to default.'\r\n}\r\n\r\nfunction currentPageLS(page) {\r\n  page = page || pages.getCurrentPageId()\r\n  if (pages.getCurrentPageId() === 'settings') {\r\n    return \/\/ all settings\r\n  }\r\n  var radioSetting = currentPageRadioSetting(page)\r\n  if (radioSetting) {\r\n    var result = {}\r\n    result[radioSetting.id] = true\r\n    return result\r\n  }\r\n  return currentPageSettings(page).reduce(function(a, s) {\r\n    var setting = resolveSettingFromStore(s)\r\n    a[setting.id] = true\r\n    return a\r\n  }, {})\r\n}\r\n\r\n\/\/ game settings that are stored\/loaded to\/from tease storage\r\nvar gameSettingStore = {\r\n  options: {\r\n    type: storageTypes.NONE,\r\n    icon: '\ud83c\udfae',\r\n    label: 'Options',\r\n    page: 'settings',\r\n    target: 'settings-options',\r\n  },\r\n  difficultyLevel: {\r\n    type: storageTypes.GAME,\r\n    label: 'Game Difficulty',\r\n    icon: '\ud83d\ude30',\r\n    page: 'settings-options',\r\n    target: 'settings-difficulty-level',\r\n    prompt: function(s){\r\n      return mergeObject(\"[label] controls speed of stroking and other elements during the game.\", s)\r\n    },\r\n    options: {\r\n      '0.6': {\r\n        icon: '\ud83d\ude0a',\r\n        label: 'Super Easy',\r\n      },\r\n      '0.75': {\r\n        icon: '\ud83d\ude00',\r\n        label: 'Easy',\r\n      },\r\n      '1.0': {\r\n        icon: '\ud83d\ude01',\r\n        label: 'Normal',\r\n      },\r\n      '1.2': {\r\n        icon: '\ud83d\ude06',\r\n        label: 'Hard',\r\n      },\r\n      '1.6': {\r\n        icon: '\ud83d\ude23',\r\n        label: 'Insane',\r\n      },\r\n    },\r\n    key: 'dl', \/\/ short key for storage\r\n    defaultValue: '1.0', \/\/ Default value\r\n  },\r\n  stroking: {\r\n    type: storageTypes.NONE,\r\n    icon: '\u270a',\r\n    label: 'Stroking Options',\r\n    textKey: 'InRoundFapping',\r\n    page: 'settings-options',\r\n    target: 'settings-stroking',\r\n  },\r\n  loseRest: {\r\n    type: storageTypes.GAME,\r\n    label: 'Lose Rest',\r\n    textKey: 'LoseRest',\r\n    page: 'settings-options',\r\n    key: 'sLR', \/\/ short key for storage\r\n    remap: true, \/\/ remove old, longer key from use\r\n  },\r\n  cumRoundAuto: {\r\n    type: storageTypes.GAME,\r\n    label: 'Auto Cum Round',\r\n    textKey: 'AutoCumRound',\r\n    page: 'settings-options',\r\n    key: 'sCRA', \/\/ short key for storage\r\n    remap: true, \/\/ remove old, longer key from use\r\n  },\r\n  strokingSpeedAlias: {\r\n    type: storageTypes.NONE,\r\n    altLabel: 'Intensity',\r\n    aliasOf: 'difficultyLevel',\r\n    page: 'settings-stroking',\r\n  },\r\n  inRoundFapping: {\r\n    type: storageTypes.GAME,\r\n    label: 'In Round Fapping',\r\n    textKey: 'InRoundFapping',\r\n    page: 'settings-stroking',\r\n    key: 'sIRF', \/\/ short key for storage\r\n    remap: true, \/\/ remove old, longer key from use\r\n  },\r\n  strokePenaltyLimit: {\r\n    type: storageTypes.GAME,\r\n    label: 'Stroke Penalty Limit',\r\n    textKey: 'StrokePenaltyLimit',\r\n    page: 'settings-stroking',\r\n    key: 'sSPL', \/\/ short key for storage\r\n    remap: true, \/\/ remove old, longer key from use\r\n  },\r\n  lossPenalty: {\r\n    type: storageTypes.GAME,\r\n    label: function(){ \r\n      return game.text('settingLossPenaltyLabel')\r\n    }, \/\/ What to display in menu\r\n    icon: function() {\r\n      return game.text('settingLossPenaltyIcon')\r\n    },\r\n    page: 'settings-options', \/\/ Where to display the selection\r\n    target: 'settings-loss-penalty', \/\/ Page used to generate radio buttons\r\n    \/\/ Define radio button\r\n    prompt: function(){ \/\/ Optional function to generate setting prompt\r\n      return game.text('settingLossPenaltyPrompt')\r\n    },\r\n    show: function(o){\r\n      var c = 0\r\n      Object.keys(gameSettingStore.lossPenalty.options).forEach(function(k) {\r\n        if (k === 'rand') return\r\n        var opt = gameSettingStore.lossPenalty.options[k]\r\n        if (opt.show()) c++\r\n      })\r\n      console.warn('lossPenaly enabled:', c)\r\n      return c > 1\r\n    },\r\n    options: {\r\n      \/\/ Keep option keys ('tits': in this first example) short.\r\n      \/\/ They take storage space.\r\n      ruin: {\r\n        label: function(){\r\n          return game.text('settingLossPenaltyRuinLabel')\r\n        },\r\n        show: function(o){\r\n          \/\/ console.warn('ruin enabled:', pages.contains('game-lost-ruin') && pages.isEnabled('game-lost-ruin'))\r\n          return pages.contains('game-lost-ruin') && pages.isEnabled('game-lost-ruin') \r\n          },\r\n        useInRandom: function(o){\r\n          \/\/ console.warn('ruin enabled:', pages.contains('game-lost-ruin') && pages.isEnabled('game-lost-ruin'))\r\n          return pages.contains('game-lost-ruin') && pages.isEnabled('game-lost-ruin') \r\n          },\r\n        block: function(o){}, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        selectMessage: function(o){ \/\/ Optional function to display on select\r\n          return game.text('settingLossPenaltyRuinSelect', o) \r\n        },\r\n      },\r\n      deny: {\r\n        label: function(){\r\n          return game.text('settingLossPenaltyDenyLabel')\r\n        },\r\n        show: function(o){\r\n          \/\/ console.warn('deny enabled:', pages.contains('game-lost-deny') && pages.isEnabled('game-lost-deny'))\r\n          return pages.contains('game-lost-deny') && pages.isEnabled('game-lost-deny')\r\n            && (!game._gameStarted || !game.cumCount || !gameSettingStore.lossPenalty.options.ruin.show())\r\n          },\r\n        useInRandom: function(o){\r\n          \/\/ console.warn('deny enabled:', pages.contains('game-lost-deny') && pages.isEnabled('game-lost-deny'))\r\n          return pages.contains('game-lost-deny') && pages.isEnabled('game-lost-deny')\r\n            && (!game._gameStarted || !game.cumCount || !gameSettingStore.lossPenalty.options.ruin.show())\r\n          },\r\n        block: function(o){}, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        selectMessage: function(o){ \/\/ Optional function to display on select\r\n          return game.text('settingLossPenaltyDenySelect', o) \r\n        },\r\n      },\r\n      cei: {\r\n        label: function(){\r\n          return game.text('settingLossPenaltyCeiLabel')\r\n        },\r\n        show: function(o){\r\n          \/\/ console.warn('cei enabled:', pages.contains('game-lost-cei') && pages.isEnabled('game-lost-cei') && \r\n          \/\/   (game.kinkPrecum || game.kinkCei) )\r\n          return pages.contains('game-lost-cei') && pages.isEnabled('game-lost-cei')\r\n            \/\/ && (game.kinkPrecum || game.kinkCei) \r\n          },\r\n        useInRandom: function(o){\r\n          \/\/ console.warn('cei enabled:', pages.contains('game-lost-cei') && pages.isEnabled('game-lost-cei') && \r\n          \/\/   (game.kinkPrecum || game.kinkCei) )\r\n          return pages.contains('game-lost-cei') && pages.isEnabled('game-lost-cei')\r\n            && (game.kinkPrecum || game.kinkCei) \r\n          },\r\n        block: function(o){}, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        selectMessage: function(o){ \/\/ Optional function to display on select\r\n          return game.text('settingLossPenaltyCeiSelect', o) \r\n        },\r\n      },\r\n      rand: {\r\n        label: function(){ \r\n          return game.text('settingLossPenaltyRandLabel')\r\n        },\r\n        show: function(o){\r\n          return pages.contains('game-lost-rand') && pages.isEnabled('game-lost-rand')\r\n        },\r\n        useInRandom: function(o){\r\n          return false\r\n          },\r\n        block: function(o){}, \/\/ Optional block selection function.\r\n                              \/\/  return string with selection denied message\r\n                              \/\/  or falsey if allowed\r\n        selectMessage: function(o){ \/\/ Optional function to display on select\r\n          return game.text('settingLossPenaltyRandSelect', o) \r\n        },\r\n        noRandomCieExt: function() {\r\n          if (!game.kinkPrecum && !game.kinkCei) {\r\n            return game.text('noRandomCieExt')\r\n          } else {\r\n            return \"\"\r\n          }\r\n        },\r\n      },\r\n    },\r\n    key: 'sLP', \/\/ short key for storage\r\n    defaultValue: 'ruin', \/\/ Default value\r\n  },\r\n  \/\/ preloadRounds: {\r\n  \/\/   type: storageTypes.GAME,\r\n  \/\/   label: 'Preload Round Images',\r\n  \/\/   page: 'settings-options',\r\n  \/\/   enableMessage: \"You've <u>enabled<\/u> Round Image Pre-Loading.  There will be a delay, and flickering at the start of each round.\".p() \r\n  \/\/   + \"This is will help reduced in-round delays on slow inernet connections.\",\r\n  \/\/   diableMessage: \"You've <u>diabled<\/u> Round Image Pre-Loading.\",\r\n  \/\/   key: 'sPL', \/\/ short key for storage\r\n  \/\/   defaultValue: false,\r\n  \/\/ },\r\n  kinks: {\r\n    type: storageTypes.REMOVE, \/\/ Used to store this.  remove it.\r\n    icon: '\ud83d\udc8b',\r\n    label: 'Kinks',\r\n    page: 'settings',\r\n    target: 'settings-kinks',\r\n  },\r\n  kinkPrecum: {\r\n    type: storageTypes.GAME,\r\n    icon: '\ud83d\udca7',\r\n    label: 'Precum CEI',\r\n    textKey: 'KinksPrecum',\r\n    page: 'settings-kinks',\r\n    key: 'kPC', \/\/ short key for storage\r\n    remap: true, \/\/ remove old, longer key from use\r\n  },\r\n  kinkCbt: {\r\n    type: storageTypes.GAME,\r\n    icon: '\ud83d\ude2b',\r\n    label: 'CBT',\r\n    textKey: 'KinksCBT',\r\n    page: 'settings-kinks',\r\n    key: 'kCB', \/\/ short key for storage\r\n    remap: true, \/\/ remove old, longer key from use\r\n  },\r\n  kinkAnal: {\r\n    type: storageTypes.REMOVE,\r\n    icon: '\ud83c\udf51',\r\n    label: 'Anal Play',\r\n    textKey: 'KinksAnal',\r\n    page: 'settings-kinks',\r\n    key: 'kAN', \/\/ short key for storage\r\n    prompt: function(){ \/\/ Optional function to generate setting prompt\r\n      return game.text('settingKinksAnalPrompt')\r\n    },\r\n    target: 'settings-kinks-anal',\r\n  },\r\n  volume: {\r\n    type: storageTypes.GAME,\r\n    icon: '\ud83d\udd08',\r\n    label: 'Beat Volume',\r\n    page: 'settings',\r\n    target: 'settings-beat-volume',\r\n    key: 'vol', \/\/ short key for storage\r\n    remap: true, \/\/ remove old, longer key from use\r\n  },\r\n}\r\n\r\n\/\/ Game state (kept compact for the sake of local storage, and easy of reference)\r\nvar g = {}\r\n\r\n\/\/ Global notification tracking (I would do this differently next time.)\r\n\/\/ (Yes. \"n\" was a really bad name choice for a global variable!)\r\nvar n = {\r\n  round: false,\r\n  roundCum: false,\r\n  roundRest: false,\r\n  penaltyroulette1: false,\r\n  penaltyroulette2: false,\r\n  shuffle: false,\r\n  cumRest: false,\r\n  endRest: false,\r\n}\r\n\r\n\/\/ Check if we need to load the round notifications\r\n\/\/ (What a mess.  Remember not to drink and code.)\r\nfunction needsRoundNotifications() {\r\n  if ((g.c < 1 || game.isWinToCumRound()) && n.roundRest) {\r\n    Notification.get('roundRest').remove()\r\n    n.roundRest = false\r\n  }\r\n  if (g.c > 0 && !game.isWinToCumRound() && n.roundCum) {\r\n    Notification.get('roundCum').remove()\r\n    n.roundCum = false\r\n  }\r\n  if (!game.isCumAnyTimeCumRound() && n.roundCumNow) {\r\n    Notification.get('roundCumNow').remove()\r\n    n.roundCumNow = false\r\n    if (n.roundRest) {\r\n      Notification.get('roundRest').remove()\r\n      n.roundRest = false\r\n    }\r\n  }\r\n  if (game.isCumAnyTimeCumRound() && !n.roundCumNow && n.roundRest) {\r\n    Notification.get('roundRest').remove()\r\n    n.roundRest = false\r\n  }\r\n  return (\r\n    !n.round ||\r\n    ((g.c < 1 || game.isWinToCumRound()) &&\r\n      !n.roundCum &&\r\n      !game.isCumAnyTimeCumRound()) ||\r\n    (g.c > 0 && !game.isWinToCumRound() && !n.roundRest) ||\r\n    (g.c < 1 && !n.roundCumNow && game.isCumAnyTimeCumRound())\r\n  )\r\n}\r\n\r\n\/**\r\n * Verbage (There's also a bunch scattered throughout the pages. Sorry.)\r\n * Each array requres at least one entry.\r\n * The more you add, the less repetition there will be.\r\n * Set in 'core-verbiage' and 'config-x' pages.\r\n * Set using game.setVerbiage({verbiageKey: ['text']})\r\n * Or in game setting objects, verbiage: {verbiageKey: ['text']}\r\n *\/\r\nvar t = {\r\n  \/\/ Did player cum in the win-check round?\r\n  btnCumWin: '\u2665 I Came! \u2665', \/\/ Player came and won\r\n  btnCumLose: \"Can't do it.\", \/\/ Player can't cum in cumToWin mode\r\n  btnCumContinue: 'Continue.', \/\/ Player decided to continue playing instead of winning\r\n  \/\/ Is player cumming too soon?\r\n  btnCummingHold: \"Yes! Let's keep going!\",\r\n  btnCummingLost: 'Nope.',\r\n  \/\/ Play buttons\r\n  btnHit: 'Hit Me!',\r\n  btnStand: 'Stand',\r\n  \/\/ Round skip buttons\r\n  btnRndBack: '<',\r\n  btnRndSkip: '>',\r\n  btnLevelSkip: '>>',\r\n  btnStrokeDone: 'I did it!',\r\n}\r\n\r\n\/**\r\n * Penalty roulette manager object\r\n *\/\r\nvar roulette = {\r\n  use: null,\r\n  opt: {},\r\n  penalty: {},\r\n  timer: null,\r\n  len: null,\r\n  index: null,\r\n  other: null,\r\n  otherKey: null,\r\n  clicks: [],\r\n  prompt: null,\r\n  clearTimeout: null,\r\n  clearTimeoutCounter: 0,\r\n  startClearTimeout: function (time) {\r\n    var myCounter = roulette.clearTimeoutCounter\r\n    roulette.clearTimeout = setTimeout(function() {\r\n      if (myCounter !== roulette.clearTimeoutCounter) return\r\n      closeNotifications(['penaltyroulette1', 'penaltyroulette2'])\r\n    }, time)\r\n  },\r\n  inc: function() {\r\n    var slowDevice = game.slowDevice ? 1 : 0\r\n    roulette.len--\r\n    roulette.timer =\r\n      roulette.timer +\r\n      Math.round(roulette.timer * game.rouletteTimerInc[slowDevice])\r\n    \/\/ roulette.index++;\r\n  },\r\n  endTime: function() {\r\n    return Math.round(game.rouletteTimerEnd * 1000)\r\n  },\r\n  reset: function() {\r\n    var slowDevice = game.slowDevice ? 1 : 0\r\n    roulette.timer = game.rouletteTimerStart[slowDevice]\r\n    roulette.len = game.rouletteTimerLen[slowDevice]\r\n    roulette.use = null\r\n    roulette.index = 0\r\n    roulette.other = null\r\n    roulette.otherKey = null\r\n    roulette.prompt = null\r\n    clearTimeout(roulette.clearTimeout)\r\n    roulette.clearTimeout = null\r\n    roulette.clearTimeoutCounter ++\r\n  },\r\n  finish: function(opt) {\r\n    if (opt) opt.finished = true\r\n    if (opt && typeof opt.finish === 'function') {\r\n      return opt.finish(opt)\r\n    }\r\n  },\r\n  getRandom: function() {\r\n    \/\/ var penalty = randomString(penalties, undefined, undefined, 'penalties');\r\n    var pn = penalties\r\n    var pk = 'penalties'\r\n    var finalSelection = roulette.len < 1\r\n    if (roulette.other) {\r\n      if (!roulette.otherKey) roulette.otherKey = JSON.stringify(roulette.other)\r\n      pn = roulette.other\r\n      pk = roulette.otherKey\r\n    }\r\n    if (finalSelection) {\r\n      pk += '||final'\r\n    }\r\n    var penalty = randomObject(pk, pn, 'id', roulette.other ? 2 : finalSelection ? undefined : 3)\r\n\r\n    if (finalSelection) {\r\n      var i = 0\r\n      while (!penalty.allow(penalty)) {\r\n        \/\/ Restrict to penalties allowed for this round on the last choice\r\n        if (DEBUG) console.warn('Not allowing pentaly', penalty, g)\r\n        var penalty = randomObject(pk, pn, 'id')\r\n        \/\/ penalty = randomString(pn, undefined, undefined, pk);\r\n        i++\r\n        if (i > 100) {\r\n          \/\/ We're stuck in a loop.\r\n          if (DEBUG)\r\n            console.error(\r\n              'Infinite loop detected while selecting penalty. Check your penalty allow functions.'\r\n            )\r\n          break\r\n        }\r\n      }\r\n    }\r\n    var opt = penalty.optGen()\r\n    roulette.use = penalty\r\n    roulette.opt = opt\r\n    var penaltyLabel = mergeObject(penalty.title, opt)\r\n    Notification.get('penaltyroulette2').setTitle(penaltyLabel)\r\n    if (DEBUG) console.log('penaltyLabel', penaltyLabel, roulette.len)\r\n    if (DEBUG && roulette.len < 1)\r\n      console.log('Selected Penalty:', penalty, opt)\r\n    return penalty\r\n  },\r\n  run: function(penalty) {\r\n    roulette.penalty = penalty\r\n    var poid\r\n    if (!roulette.other) {\r\n      poid = penalty.o.altId || penalty.id\r\n      g.pc[poid] = g.pc[poid] || { c: 0, t: 0 }\r\n      g.pc[poid].c++\r\n      g.pc[poid].t = Date.now()\r\n    }\r\n    var penaltyImage = game.getPenaltyImagePath(poid)\r\n    if (penaltyImage) {\r\n      if (DEBUG) console.log('Loading penalty image', penaltyImage)\r\n      game.image = penaltyImage\r\n      callPage(penaltyImage, function() {\r\n        if (DEBUG) console.log('Running penalty page', penalty.page)\r\n        return penalty.page\r\n      })\r\n    } else {\r\n      if (DEBUG) console.log('Running penalty page', penalty.page)\r\n      pages.goto(penalty.page)\r\n    }\r\n  },\r\n  beforeStep: function(step) {\r\n    var opt = roulette.opt\r\n    var thisPage = pages.getCurrentPageId()\r\n    if (thisPage.match(\/^penalty\/)) {\r\n      \/\/ We're from a penalty page\r\n      if (!opt || opt.isCancelled || (opt.isRandomSelect && roulette.use && roulette.use.page !== thisPage)) {\r\n        \/\/ console.error('Cancelling roulette step', thisPage)\r\n        returnToCaller()\r\n        return\r\n      }\r\n    }\r\n    \r\n    rest.fromPenalty = true \/\/ this will get cleared when we restart the play page.\r\n    var penaltyImage\r\n    if (opt && typeof opt.getStepImage === 'function') {\r\n      penaltyImage = opt.getStepImage(step, opt)\r\n      if (\r\n        penaltyImage !== -1 &&\r\n        penaltyImage &&\r\n        loadImagePage(penaltyImage, false, false)\r\n      ) {\r\n        return true\r\n      }\r\n    }\r\n    if (\r\n      ((!penaltyImage && step === 'rest') || penaltyImage === -1) &&\r\n      loadRoundImage()\r\n    )\r\n      return true\r\n    return false\r\n  },\r\n  soundsInited: false,\r\n  loadSounds: function() {\r\n    roulette.clicks = [\r\n      Sound.get('click-A'),\r\n      Sound.get('click-B')\r\n    ]\r\n    roulette.soundsInited = false\r\n    if (DEBUG) console.warn('Loaded clicks', roulette.clicks)\r\n  },\r\n  purgeSounds: function() {\r\n    roulette.clicks.forEach(function(s) {\r\n      if (s) {\r\n        s.stop()\r\n        s.destroy()\r\n      }\r\n    })\r\n    roulette.soundsInited = false\r\n    roulette.clicks = []\r\n  },\r\n  initSounds: function() {\r\n    roulette.clicks.forEach(function(s) {\r\n      if (s) {\r\n        s.setVolume(0.0001)\r\n        s.play()\r\n        s.stop()\r\n      }\r\n    })\r\n    roulette.soundsInited = true\r\n  },\r\n  lastClick: 0,\r\n  volume: function(vol) {\r\n    roulette.clicks.forEach(function(s) {\r\n      if (s) {\r\n        s.setVolume(vol || game.volume)\r\n      }\r\n    })\r\n    roulette.soundsInited = true\r\n  },\r\n  click: function () {\r\n    var i = roulette.lastClick ? 0 : 1\r\n    var clickSound = roulette.clicks[i]\r\n    var lastClickSound = roulette.clicks[roulette.lastClick]\r\n    if (clickSound) {\r\n      if (DEBUG) console.log('Playing click ', i)\r\n      clickSound.play()\r\n    } else {\r\n      console.error('No click to play ', i, roulette.clicks)\r\n    }\r\n    if (lastClickSound) {\r\n      lastClickSound.stop()\r\n    }\r\n    roulette.lastClick = i\r\n  },\r\n  useCumRoundModeSelector: function() {\r\n    if (DEBUG) console.warn('Auto-selecting cumRoundMode')\r\n    var result = []\r\n    for (var i = 0, l = cr.length; i < l; i++) {\r\n      var item = cr[i]\r\n      result.push(\r\n        pf.select({\r\n          id: item.id,\r\n          title: item.shortTitle || item.title,\r\n          data: item,\r\n          finish: function(opt) {\r\n            if (DEBUG) console.warn('Auto-selected cumRoundMode', opt)\r\n            \/\/ Set our cum round mode\r\n            game.setCumRoundAlt(opt.data.id)\r\n            \/\/ Return our message\r\n            return game.text('cumRoundAutoSelect', opt)\r\n          },\r\n        })\r\n      )\r\n    }\r\n    if (DEBUG)\r\n      console.warn('Using Cum Round Selector for penalties', result, cr)\r\n    roulette.reset()\r\n    roulette.other = result\r\n  },\r\n  useRandomSelector: function(options) {\r\n    if (DEBUG) console.warn('Auto-selecting random options', options)\r\n    var result = []\r\n    if (!options || options.length) {\r\n      console.error(\r\n        'Missing array of options, like: [{title: \"Option 1\", action: function(opt){return \"Did \" + opt.title}}, ...]'\r\n      )\r\n    }\r\n    for (var i = 0, l = options.length; i < l; i++) {\r\n      var item = options[i]\r\n      var hideOption = item.hideOption\r\n      if (typeof hideOption === 'function') hideOption = hideOption()\r\n      if (hideOption) continue\r\n      result.push(\r\n        pf.select({\r\n          id: i,\r\n          allow: function(p) {\r\n            return !p.o.data.noRandomSelect\r\n          },\r\n          title: item.shortTitle || item.title,\r\n          data: item,\r\n          finish: function(opt) {\r\n            if (typeof opt.data.action === 'function') {\r\n              return opt.data.action(opt.data)\r\n            }\r\n            console.error('No valid action function passed in:', opt.data)\r\n            return 'Invalid action -- see console.'\r\n          },\r\n        })\r\n      )\r\n    }\r\n    if (DEBUG)\r\n      console.warn('Using roulette for Random Selector', result, options)\r\n    roulette.reset()\r\n    roulette.other = result\r\n  },\r\n  useLossPenaltySelector: function() {\r\n    if (DEBUG) console.warn('Auto-selecting loss penalty')\r\n    var result = []\r\n    var opts = gameSettingStore.lossPenalty.options\r\n    Object.keys(opts).forEach(function(k) {\r\n      if (k === 'rand') return\r\n      var item = opts[k]\r\n      if (item.useInRandom && !item.useInRandom(item)) return\r\n      item.id = k\r\n      if (typeof item.label === 'function') {\r\n        item.label = item.label()\r\n      }\r\n      result.push(\r\n        pf.select({\r\n          id: k,\r\n          title: item.label,\r\n          data: item,\r\n          finish: function(opt) {\r\n            roulette.startClearTimeout(game.lossPenaltySelectorTimeout)\r\n            if (DEBUG) console.warn('Auto-selected loss penalty', opt)\r\n            \/\/ Set our loss penalty\r\n            pages.goto(game.getGameLossPage(opt.data.id))\r\n          },\r\n        })\r\n      )\r\n    })\r\n    if (DEBUG)\r\n      console.warn('Using Random Selector for loss penalty', result, opts)\r\n    roulette.reset()\r\n    roulette.other = result\r\n  },\r\n  useDifficultySelector: function() {\r\n    if (DEBUG) console.warn('Auto-selecting difficulty')\r\n    var result = []\r\n    for (var i = 0, l = gds.length; i < l; i++) {\r\n      var item = gds[i]\r\n      var hideOption = item.hideOption\r\n      if (typeof hideOption === 'function') hideOption = hideOption()\r\n      if (hideOption || item.noRandom) continue \/\/ Skip random selector for this.\r\n      result.push(\r\n        pf.select({\r\n          id: item.id,\r\n          allow: function(p) {\r\n            return !p.o.data.noRandomSelect\r\n          },\r\n          title: item.shortTitle || item.title,\r\n          data: item,\r\n          finish: function(opt) {\r\n            if (DEBUG) console.warn('Auto-selected game difficulty', opt)\r\n            \/\/ Set our game mode\r\n            game.setPlayerDifficulty(opt.data.id)\r\n            \/\/ Return our message\r\n            return game.text('difficultyAutoSelect', opt)\r\n          },\r\n        })\r\n      )\r\n    }\r\n    if (DEBUG)\r\n      console.warn('Using roulette for Difficulty Selector', result, gds)\r\n    roulette.reset()\r\n    roulette.other = result\r\n  },\r\n  useGameModeSelector: function() {\r\n    if (DEBUG) console.warn('Auto-selecting gameMode')\r\n    closeAll()\r\n    var result = []\r\n    for (var i = 0, l = gms.length; i < l; i++) {\r\n      var item = gms[i]\r\n      var hideOption = item.hideOption\r\n      if (typeof hideOption === 'function') hideOption = hideOption()\r\n      if (hideOption || item.noRandom) continue \/\/ Skip random selector for this.\r\n      result.push(\r\n        pf.select({\r\n          id: item.id,\r\n          allow: function(p) {\r\n            return !p.o.data.noRandomSelect\r\n          },\r\n          title: item.shortTitle || item.title,\r\n          data: item,\r\n          finish: function(opt) {\r\n            if (DEBUG) console.warn('Auto-selected gameMode', opt)\r\n            \/\/ Set our game mode\r\n            game.setPlayerGameMode(opt.data.id)\r\n            \/\/ Return our message\r\n            return game.text('gameModeAutoSelect', opt)\r\n          },\r\n        })\r\n      )\r\n    }\r\n    if (DEBUG) console.warn('Using roulette for Game Mode Selector', result, cr)\r\n    roulette.reset()\r\n    roulette.other = result\r\n  },\r\n}\r\n\r\n\/**\r\n * Penalties manager objects\r\n * TODO: Track time to edge, time since last edge, and last rest use history to calculate\r\n *       probable stimulation level (0.0 to 1.0: likely flaccid to probably oozing)\r\n *       and stimulation trend (-1.0 to 1.0: how quickly is moving in either direction),\r\n *       allowing more accurate metrics for determining stroking aggressiveness and rest length.\r\n *       Feedback clearly points to different folks needing dramatically different strokes.\r\n *\/\r\n\r\n\/\/ Penalty factories\r\nvar pf = {\r\n  \/\/ EDGE penalty factory.\r\n  \/\/ Options: {\r\n  \/\/   ride: [true or false], \/\/ true = EDGE & RIDE, false = EDGE\r\n  \/\/   allow: function(){expression that returns true to allow in final selection}\r\n  \/\/ }\r\n  edge: function(o) {\r\n    var oId = o.altId || o.id\r\n    return {\r\n      o: o,\r\n      id: o.id,\r\n      \/\/ What's displayed in the roulette wheel as a tease of what's to come (even if omitted from final)\r\n      title: o.title || (o.ride ? 'EDGE & RIDE [ride]s' : 'EDGE'),\r\n      \/\/ Don't allow final selection unless match this expression\r\n      allow: o.allow,\r\n      \/\/ Method to generate pentalty options object\r\n      optGen:\r\n        o.optGen ||\r\n        function() {\r\n          var rideTime\r\n          var bpm\r\n          var restCount = null\r\n          var prevPattern = beats.currentPattern\r\n          var withAnal = game.analToy && game.analToy.type === 'dildo'\r\n          switch (game.getLevel()) {\r\n            case 1:\r\n              rideTime = randomInt(10, 20)\r\n              bpm = 150\r\n              break\r\n            case 2:\r\n              rideTime = randomInt(15, 30)\r\n              bpm = 180\r\n              break\r\n            \/\/ case 3:\r\n            default:\r\n              rideTime = randomInt(20, 45)\r\n              bpm = 240\r\n              break\r\n          }\r\n\r\n          var calFunc = game.penaltyCalc && game.penaltyCalc[oId]\r\n          var cal = {}\r\n          if (typeof calFunc === 'function') {\r\n            cal = calFunc(o, game.getLevel(), game.getIndex(), o.ride) || {}\r\n            rideTime = cal.rideTime || rideTime\r\n            bpm = cal.bpm || bpm\r\n          }\r\n\r\n          return {\r\n            message: null,\r\n            ride: o.ride ? rideTime : null,\r\n            withAnal: withAnal,\r\n            prevPattern: prevPattern,\r\n            textKey: withAnal ? 'edgeAnal' : 'edge',\r\n            getRideTime:\r\n              cal.getRideTime ||\r\n              function(opt) {\r\n                return opt.ride ? Math.round(opt.ride * 1000) : null\r\n              },\r\n            startTime: Date.now(),\r\n            onEdge:\r\n              cal.onEdge ||\r\n              o.onEdge ||\r\n              function(opt) {\r\n                game.setPattern(opt.prevPattern)\r\n                beats.stopAll()\r\n                game.lastEdgeTime = Date.now() - opt.startTime\r\n              },\r\n            bpm: beats.closestBpm(bpm),\r\n            bpmIncTimer: 8000,\r\n            getRestStart: cal.getRestStart,\r\n            getRestEnd: cal.getRestEnd,\r\n            beforeStart: function() {\r\n              game.setPattern('+AF')\r\n            },\r\n            \/\/ How many breaths for \"free\" post edge rests\r\n            getRestCount:\r\n              cal.getRestCount ||\r\n              function(opt) {\r\n                if (restCount !== null) return restCount\r\n                switch (game.getLevel()) {\r\n                  case 1:\r\n                    return 3\r\n                  case 2:\r\n                    return 2\r\n                  case 3:\r\n                    return 1\r\n                  default:\r\n                    return 0\r\n                }\r\n              },\r\n            getAndIncTimer:\r\n              cal.getAndIncTimer ||\r\n              o.getAndIncTimer ||\r\n              function(opt) {\r\n                \/\/ var timer = opt.bpmIncTimer\r\n                \/\/ opt.bpmIncTimer = Math.round(timer)\r\n                return opt.bpmIncTimer\r\n              },\r\n            startBeat:\r\n              cal.startBeat ||\r\n              o.startBeat ||\r\n              function(opt) {\r\n                beats.start(opt.bpm)\r\n              },\r\n            getEdgeMessage:\r\n              cal.getEdgeMessage ||\r\n              o.getEdgeMessage ||\r\n              function(opt) {\r\n                return game.text(opt.textKey, opt)\r\n              },\r\n            getRideMessage:\r\n              cal.getRideMessage ||\r\n              o.getRideMessage ||\r\n              function(opt) {\r\n                return game.text(opt.textKey + 'Ride', opt)\r\n              },\r\n            getRideContMessage:\r\n              cal.getRideContMessage ||\r\n              o.getRideContMessage ||\r\n              function(opt) {\r\n                return game.text(opt.textKey + 'RideCont', opt)\r\n              },\r\n            doContMessage:\r\n              cal.doContMessage ||\r\n              o.doContMessage ||\r\n              function(opt) {\r\n                return opt.getRideTime(opt) >= 16000 \/\/ Encourage over 16 seconds\r\n              },\r\n            onCum:\r\n              cal.onCum ||\r\n              o.onCum ||\r\n              function(opt) {\r\n                opt.onRest(opt)\r\n              },\r\n            onRest:\r\n              cal.onRest ||\r\n              o.onRest ||\r\n              function(opt) {\r\n                beats.stopAll()\r\n                game.setPattern(opt.prevPattern)\r\n              },\r\n            getStepImage: cal.getStepImage || o.getStepImage,\r\n          }\r\n        },\r\n      page: o.page || 'penalty-edge',\r\n    }\r\n  },\r\n  \/\/ Stroke factory\r\n  stroke: function(o) {\r\n    var oId = o.altId || o.id\r\n    var page = o.page || 'penalty-stroke'\r\n    o.analStroke = !o.anal && game.analToy && game.analToy.type === 'dildo'\r\n    return {\r\n      o: o,\r\n      id: o.id,\r\n      \/\/ What's displayed in the roulette wheel as a tease of what's to come (even if omitted from final)\r\n      title:\r\n        o.title || (o.anal ? '[faps] Penetrations' : o.analStroke ? '[faps] FAPs + Anal' : '[faps] FAPs'),\r\n      \/\/ Don't allow final selection unless match this expression\r\n      allow: o.allow,\r\n      \/\/ Method to generate pentalty options object\r\n      optGen:\r\n        o.optGen ||\r\n        function() {\r\n          var faps\r\n          var startBpm = game.getStrokeStartBpm()\r\n          var endBpm = game.getStrokeEndBpm()\r\n          var toy = game.analToy || {name: 'none'}\r\n          var prevPattern = beats.currentPattern\r\n          \/\/ if (!o.anal) game.setPattern('+AF')\r\n          switch (game.getLevel()) {\r\n            case 1:\r\n              faps = randomInt(20, 40)\r\n              break\r\n            case 2:\r\n              faps = randomInt(25, 60)\r\n              break\r\n            case 3:\r\n              faps = randomInt(30, 80)\r\n              break\r\n            case 4:\r\n              \/\/ startBpm = 240 \/\/ Cum round.  fap the hell out of them\r\n            \/* falls through *\/\r\n            default:\r\n              faps = randomInt(g.c > 2 ? 60 : 30, g.c > 2 ? 120 : 80)\r\n              break\r\n          }\r\n          var calFunc = game.penaltyCalc && game.penaltyCalc[oId]\r\n          var cal = {}\r\n          var difficultyLevel = game.getDifficultyLevel()\r\n          var difficultyLevel2 = game.getDifficultyLevelAdjusted(0.75)\r\n          if (typeof calFunc === 'function') {\r\n            cal = calFunc(o, game.getLevel(), game.getIndex()) || {}\r\n            faps = cal.faps || faps\r\n            startBpm = cal.startBpm || startBpm\r\n            endBpm = cal.endBpm || endBpm\r\n            difficultyLevel = cal.difficultyLevel || difficultyLevel\r\n            difficultyLevel2 = cal.difficultyLevel2 || difficultyLevel2\r\n          }\r\n          var bpm = beats.getRandom(startBpm, endBpm)\r\n          var preBpm = bpm\r\n          var preFaps = faps\r\n          bpm = Math.min(Math.round(bpm * difficultyLevel), game.bpmMax)\r\n          faps = Math.round(faps * difficultyLevel2)\r\n          if (DEBUG) {\r\n            console.log('Level ' + game.getLevel() + ' Stroke penalty BPM:', preBpm + ' ('+startBpm + ' : ' + endBpm+')', ' FAPS:', preFaps)\r\n            if (preBpm !== bpm || preFaps !== faps) {\r\n                console.warn('Adjusted stroke penalty for difficultyLevel:' + difficultyLevel + ' | ' + difficultyLevel2, \r\n                ' BPM: ' + bpm, ' | FAPS: ' + faps)\r\n            }\r\n          }\r\n          if (o.anal) {\r\n            bpm = Math.max(Math.round(bpm \/ 2), 180)\r\n            faps = Math.max(Math.round(faps \/ 2), 4)\r\n          }\r\n          var time = Math.round(faps \/ (bpm \/ 60))\r\n          return {\r\n            message: null,\r\n            toyName: toy.name,\r\n            toyNameLower: toy.name.toLowerCase(),\r\n            time: time,\r\n            faps: faps,\r\n            bpm: bpm,\r\n            anal: o.anal,\r\n            analStroke: o.analStroke,\r\n            prevPattern: prevPattern,\r\n            getTime:\r\n              cal.getTime ||\r\n              o.getTime ||\r\n              function(opt) {\r\n                return opt.time * 1000\r\n              },\r\n            \/\/ getPrepMessage:\r\n            \/\/   cal.getPrepMessage ||\r\n            \/\/   o.getPrepMessage ||\r\n            \/\/   function(opt) {\r\n            \/\/     return mergeObject(\r\n            \/\/       o.anal ? randomString(t.analPrep) : undefined,\r\n            \/\/       opt\r\n            \/\/     )\r\n            \/\/   },\r\n            getMessage:\r\n              cal.getMessage ||\r\n              o.getMessage ||\r\n              function(opt) {\r\n                if (opt.anal) {\r\n                  return game.text('justAnal', opt)\r\n                } else if (opt.analStroke) {\r\n                  return game.text('strokePlusAnal', opt)\r\n                } else {\r\n                  return game.text('strokeTime', opt)\r\n                }\r\n              },\r\n            beforeStart: function() {\r\n              game.setPattern('+AF')\r\n            },\r\n            onCum:\r\n              cal.onCum ||\r\n              o.onCum ||\r\n              function(opt) {\r\n                opt.onRest(opt)\r\n              },\r\n            onRest:\r\n              cal.onRest ||\r\n              o.onRest ||\r\n              function(opt) {\r\n                beats.stopAll()\r\n                game.setPattern(opt.prevPattern)\r\n              },\r\n            messageDelay:\r\n              cal.messageDelay ||\r\n              o.messageDelay ||\r\n              function(opt) {\r\n                return 0 \/\/ ms\r\n              },\r\n            getDoneMessage:\r\n              cal.getDoneMessage ||\r\n              o.getDoneMessage ||\r\n              function(opt) {\r\n                game.setPattern(opt.prevPattern)\r\n                if (o.anal) {\r\n                  return game.text('justAnalDone', opt)\r\n                } else if (opt.analStroke) {\r\n                  return game.text('strokePlusAnalDone', opt)\r\n                } else {\r\n                  return game.text('strokeDone', opt)\r\n                }\r\n              },\r\n            getStepImage: cal.getStepImage || o.getStepImage,\r\n          }\r\n        },\r\n      page: page,\r\n    }\r\n  },\r\n  \/\/ CBT factory\r\n  cbt: function(o) {\r\n    var oId = o.altId || o.id\r\n    return {\r\n      o: o,\r\n      id: o.id,\r\n      \/\/ What's displayed in the roulette wheel as a tease of what's to come (even if omitted from final)\r\n      title: o.title || 'Cock\/Ball Torture',\r\n      \/\/ Don't allow final selection unless match this expression\r\n      allow: o.allow,\r\n      \/\/ Method to generate pentalty options object\r\n      optGen:\r\n        o.optGen ||\r\n        function() {\r\n          var faps\r\n          switch (game.getLevel()) {\r\n            case 1:\r\n              faps = randomInt(2, 3)\r\n              break\r\n            case 2:\r\n              faps = randomInt(2, 5)\r\n              break\r\n            default:\r\n              faps = randomInt(3, 8)\r\n              break\r\n          }\r\n          var calFunc = game.penaltyCalc && game.penaltyCalc[oId]\r\n          var cal = {}\r\n          var timePerFap\r\n          var prevPattern = beats.currentPattern\r\n          if (typeof calFunc === 'function') {\r\n            cal = calFunc(o, game.getLevel(), game.getIndex()) || {}\r\n            faps = cal.faps || faps\r\n            timePerFap = cal.timePerFap || game.cbtOpts.timePerFap || 1\r\n          }\r\n          faps = Math.min(game.cbtOpts.maxCbt, faps)\r\n          faps = Math.max(game.cbtOpts.minCbt, faps)\r\n          var time = Math.round(faps * timePerFap)\r\n          time = Math.min(game.cbtOpts.maxTime, time)\r\n          time = Math.max(game.cbtOpts.minTime, time) || 5\r\n          return {\r\n            message: null,\r\n            time: time,\r\n            faps: faps,\r\n            allowSkip: game.cbtOpts.allowSkip,\r\n            noBeat: game.cbtOpts.noBeat,\r\n            prevPattern: prevPattern,\r\n            getTime:\r\n              cal.getTime ||\r\n              o.getTime ||\r\n              function(opt) {\r\n                return opt.time * 1000\r\n              },\r\n            getMessage:\r\n              cal.getMessage ||\r\n              o.getMessage ||\r\n              function(opt) {\r\n                var messageFunc =\r\n                  game.penaltyMessage &&\r\n                  (game.penaltyMessage[o.id] || game.penaltyMessage['cbt'])\r\n                if (typeof messageFunc === 'function') {\r\n                  var result = messageFunc(\r\n                    opt,\r\n                    game.getLevel(),\r\n                    game.getIndex()\r\n                  )\r\n                  if (result) {\r\n                    return result\r\n                  }\r\n                }\r\n                return game.text('cbt', opt)\r\n              },\r\n            messageDelay:\r\n              cal.messageDelay ||\r\n              o.messageDelay ||\r\n              function(opt) {\r\n                return 1500 \/\/ ms\r\n              },\r\n            getDoneMessage:\r\n              cal.getDoneMessage ||\r\n              o.getDoneMessage ||\r\n              function(opt) {\r\n                return game.text('cbtDone', opt)\r\n              },\r\n            getStepImage: cal.getStepImage || o.getStepImage,\r\n          }\r\n        },\r\n      page: o.page || 'penalty-stroke',\r\n    }\r\n  },\r\n  \/\/ Lose Rest factory\r\n  loseRest: function(o) {\r\n    var oId = o.altId || o.id\r\n    return {\r\n      o: o,\r\n      id: o.id,\r\n      \/\/ What's displayed in the roulette wheel as a tease of what's to come (even if omitted from final)\r\n      title: o.title || 'Lose 1 Rest',\r\n      \/\/ Don't allow final selection unless match this expression\r\n      allow: o.allow,\r\n      \/\/ Method to generate pentalty options object\r\n      optGen:\r\n        o.optGen ||\r\n        function() {\r\n          var messageDelay = 1500\r\n          var calFunc = game.penaltyCalc && game.penaltyCalc[oId]\r\n          var cal = {}\r\n          if (typeof calFunc === 'function') {\r\n            cal = calFunc(o, game.getLevel(), game.getIndex()) || {}\r\n          }\r\n          return {\r\n            getMessage:\r\n              cal.getMessage ||\r\n              o.getMessage ||\r\n              function(opt) {\r\n                return game.text('loseRest', opt)\r\n              },\r\n            messageDelay:\r\n              cal.messageDelay ||\r\n              o.messageDelay ||\r\n              function(opt) {\r\n                return messageDelay \/\/ ms\r\n              },\r\n            finish:\r\n              cal.finish ||\r\n              o.finish ||\r\n              function(opt) {\r\n                g.c--\r\n              },\r\n            getStepImage: cal.getStepImage || o.getStepImage,\r\n          }\r\n        },\r\n      page: o.page || 'penalty-message',\r\n    }\r\n  },\r\n  \/\/ Anal toy insert factory\r\n  analToyStart: function(o) {\r\n    var oId = o.altId || o.id\r\n    return {\r\n      o: o,\r\n      id: o.id,\r\n      \/\/ What's displayed in the roulette wheel as a tease of what's to come (even if omitted from final)\r\n      title: o.title || 'Insert [toyName]',\r\n      \/\/ Don't allow final selection unless match this expression\r\n      allow: o.allow,\r\n      \/\/ Method to generate pentalty options object\r\n      optGen:\r\n        o.optGen ||\r\n        function() {\r\n          var calFunc = game.penaltyCalc && game.penaltyCalc[oId]\r\n          var cal = {}\r\n          if (typeof calFunc === 'function') {\r\n            cal = calFunc(o, game.getLevel(), game.getIndex()) || {}\r\n          }\r\n          var getRandomToy = cal.getRandomToy || o.getRandomToy || function() {\r\n            return game._enabledAnalToys[Math.floor(Math.random() * game._enabledAnalToys.length)]\r\n          }\r\n          var toy = getRandomToy() || {name: 'INVALID'}\r\n          var messageDelay = toy.insertTime || 15\r\n          if (typeof messageDelay === 'function') messageDelay = messageDelay()\r\n          messageDelay = messageDelay * 1000\r\n          return {\r\n            timeout: false,\r\n            toyName: toy.name,\r\n            toyMessageKey: toy.type === 'plug' ? 'analPlug' : 'analDildo',\r\n            toyNameLower: toy.name.toLowerCase(),\r\n            toyId: toy.id,\r\n            getMessage:\r\n              cal.getMessage ||\r\n              o.getMessage ||\r\n              function(opt) {\r\n                return game.text(opt.toyMessageKey + 'Start', opt)\r\n              },\r\n            getFailMessage:\r\n              cal.getFailMessage ||\r\n              o.getFailMessage ||\r\n              function(opt) {\r\n                return game.text('analToyFail', opt)\r\n              },\r\n            messageDelay:\r\n              cal.messageDelay ||\r\n              o.messageDelay ||\r\n              function(opt) {\r\n                return messageDelay \/\/ ms.   Wait 15 seconds to eat precum, or fail.\r\n              },\r\n            showTimer: cal.showTimer || o.showTimer || true,\r\n            fail:\r\n              cal.fail ||\r\n              o.fail ||\r\n              function(opt) {\r\n                \/\/ If fail, choose another\r\n                roulette.reset()\r\n                if (DEBUG)\r\n                  console.log('Running roulette page', 'penalty-roulette')\r\n                pages.goto('penalty-roulette')\r\n              },\r\n            doTimeout:\r\n              cal.doTimeout ||\r\n              o.doTimeout ||\r\n              function(opt) {\r\n                pages.goto('penalty-message-pass')\r\n              },\r\n            finish:\r\n              cal.finish ||\r\n              o.finish ||\r\n              function(opt) {\r\n                game.setAnalToy(opt.toyId)\r\n                \r\n                return game.text(opt.toyMessageKey + 'StartPass', opt)\r\n              },\r\n            getStepImage: cal.getStepImage || o.getStepImage,\r\n            getAfterPassMessage:\r\n              cal.getAfterPassMessage || o.getAfterPassMessage,\r\n          }\r\n        },\r\n      page: o.page || 'penalty-message-pass-fail',\r\n    }\r\n  },\r\n  \/\/ Anal toy pull factory\r\n  analToyEnd: function(o) {\r\n    var oId = o.altId || o.id\r\n    return {\r\n      o: o,\r\n      id: o.id,\r\n      \/\/ What's displayed in the roulette wheel as a tease of what's to come (even if omitted from final)\r\n      title: o.title || 'Remove [toyName]',\r\n      \/\/ Don't allow final selection unless match this expression\r\n      allow: o.allow,\r\n      \/\/ Method to generate pentalty options object\r\n      optGen:\r\n        o.optGen ||\r\n        function() {\r\n          var calFunc = game.penaltyCalc && game.penaltyCalc[oId]\r\n          var cal = {}\r\n          if (typeof calFunc === 'function') {\r\n            cal = calFunc(o, game.getLevel(), game.getIndex()) || {}\r\n          }\r\n          var toy = game.analToy || {name: 'INVALID'}\r\n          var messageDelay = toy.pullTime || 15\r\n          if (typeof messageDelay === 'function') messageDelay = messageDelay()\r\n          messageDelay = messageDelay * 1000\r\n          return {\r\n            timeout: false,\r\n            toyName: toy.name,\r\n            toyMessageKey: toy.type === 'plug' ? 'analPlug' : 'analDildo',\r\n            toyNameLower: toy.name.toLowerCase(),\r\n            hidePassButton: true,\r\n            hideFailButton: true,\r\n            showAltPassButton: true,\r\n            toyId: toy.id,\r\n            getMessage:\r\n              cal.getMessage ||\r\n              o.getMessage ||\r\n              function(opt) {\r\n                return game.text(opt.toyMessageKey + 'End', opt)\r\n              },\r\n            getFailMessage:\r\n              cal.getFailMessage ||\r\n              o.getFailMessage ||\r\n              function(opt) {\r\n                return game.text('analToyFail', opt)\r\n              },\r\n            messageDelay:\r\n              cal.messageDelay ||\r\n              o.messageDelay ||\r\n              function(opt) {\r\n                return messageDelay \/\/ ms.   Wait 15 seconds to eat precum, or fail.\r\n              },\r\n            showTimer: cal.showTimer || o.showTimer || true,\r\n            fail:\r\n              cal.fail ||\r\n              o.fail ||\r\n              function(opt) {\r\n                \/\/ If fail, choose another\r\n                roulette.reset()\r\n                if (DEBUG)\r\n                  console.log('Running roulette page', 'penalty-roulette')\r\n                pages.goto('penalty-roulette')\r\n              },\r\n            doTimeout:\r\n              cal.doTimeout ||\r\n              o.doTimeout ||\r\n              function(opt) {\r\n                pages.goto('penalty-message-pass')\r\n              },\r\n            finish:\r\n              cal.finish ||\r\n              o.finish ||\r\n              function(opt) {\r\n                game.clearAnalToy()\r\n                return game.text(opt.toyMessageKey + 'EndPass', opt)\r\n              },\r\n            getStepImage: cal.getStepImage || o.getStepImage,\r\n            getAfterPassMessage:\r\n              cal.getAfterPassMessage || o.getAfterPassMessage,\r\n          }\r\n        },\r\n      page: o.page || 'penalty-message-pass-fail',\r\n    }\r\n  },\r\n  \/\/ Precum CEI factory\r\n  precum: function(o) {\r\n    var oId = o.altId || o.id\r\n    return {\r\n      o: o,\r\n      id: o.id,\r\n      \/\/ What's displayed in the roulette wheel as a tease of what's to come (even if omitted from final)\r\n      title: o.title || 'Eat Precum',\r\n      \/\/ Don't allow final selection unless match this expression\r\n      allow: o.allow,\r\n      \/\/ Method to generate pentalty options object\r\n      optGen:\r\n        o.optGen ||\r\n        function() {\r\n          var messageDelay = 15000\r\n          var calFunc = game.penaltyCalc && game.penaltyCalc[oId]\r\n          var cal = {}\r\n          if (typeof calFunc === 'function') {\r\n            cal = calFunc(o, game.getLevel(), game.getIndex()) || {}\r\n          }\r\n          return {\r\n            timeout: false,\r\n            getMessage:\r\n              cal.getMessage ||\r\n              o.getMessage ||\r\n              function(opt) {\r\n                return game.text('eatPrecum', opt)\r\n              },\r\n            getFailMessage:\r\n              cal.getFailMessage ||\r\n              o.getFailMessage ||\r\n              function(opt) {\r\n                return mergeObject(\r\n                  randomString(\r\n                    opt.timeout ? t.eatPrecumTimeout : t.eatPrecumFail\r\n                  ),\r\n                  opt\r\n                )\r\n              },\r\n            messageDelay:\r\n              cal.messageDelay ||\r\n              o.messageDelay ||\r\n              function(opt) {\r\n                return messageDelay \/\/ ms.   Wait 15 seconds to eat precum, or fail.\r\n              },\r\n            showTimer: cal.showTimer || o.showTimer || true,\r\n            fail:\r\n              cal.fail ||\r\n              o.fail ||\r\n              function(opt) {\r\n                \/\/ If fail, choose another\r\n                roulette.reset()\r\n                if (DEBUG)\r\n                  console.log('Running roulette page', 'penalty-roulette')\r\n                pages.goto('penalty-roulette')\r\n              },\r\n            finish:\r\n              cal.finish ||\r\n              o.finish ||\r\n              function(opt) {\r\n                g.c++\r\n                return game.text('eatPrecumDone', opt)\r\n              },\r\n            getStepImage: cal.getStepImage || o.getStepImage,\r\n            getAfterPassMessage:\r\n              cal.getAfterPassMessage || o.getAfterPassMessage,\r\n          }\r\n        },\r\n      page: o.page || 'penalty-message-pass-fail',\r\n    }\r\n  },\r\n  \/\/ \"Custom\" Option factory\r\n  custom: function(o) {\r\n    var oId = o.altId || o.id\r\n    return {\r\n      o: o,\r\n      id: o.id,\r\n      \/\/ What's displayed in the roulette wheel as a tease of what's to come (even if omitted from final)\r\n      title: o.title,\r\n      \/\/ Don't allow final selection unless match this expression\r\n      allow:\r\n        o.allow ||\r\n        function() {\r\n          return true \r\n        },\r\n      \/\/ Method to generate pentalty options object\r\n      optGen:\r\n        o.optGen ||\r\n        function() {\r\n          var calFunc = game.penaltyCalc && game.penaltyCalc[oId]\r\n          var cal = {}\r\n          if (typeof calFunc === 'function') {\r\n            cal = calFunc(o, game.getLevel(), game.getIndex()) || {}\r\n          }\r\n          return {\r\n            data: o.data,\r\n            timeout: cal.timeout || o.timeout || false,\r\n            showTimer: cal.showTimer || o.showTimer || false,\r\n            getMessage:\r\n              cal.getMessage ||\r\n              o.message ||\r\n              function(opt) {\r\n                return false\r\n              },\r\n            messageDelay:\r\n              cal.messageDelay ||\r\n              o.messageDelay ||\r\n              function(opt) {\r\n                return 0\r\n              },\r\n            finish: cal.finish || o.finish || function(opt) {},\r\n            getStepImage: cal.getStepImage || o.getStepImage,\r\n          }\r\n        },\r\n      page: o.page || 'penalty-custom-example',\r\n    }\r\n  },\r\n  \/\/ Select Option factory\r\n  select: function(o) {\r\n    var oId = o.altId || o.id\r\n    return {\r\n      o: o,\r\n      id: o.id,\r\n      \/\/ What's displayed in the roulette wheel as a tease of what's to come (even if omitted from final)\r\n      title: o.title,\r\n      \/\/ Don't allow final selection unless match this expression\r\n      allow:\r\n        o.allow ||\r\n        function() {\r\n          return true\r\n        },\r\n      \/\/ Method to generate pentalty options object\r\n      optGen:\r\n        o.optGen ||\r\n        function() {\r\n          var calFunc = game.penaltyCalc && game.penaltyCalc[oId]\r\n          var cal = {}\r\n          if (typeof calFunc === 'function') {\r\n            cal = calFunc(o, game.getLevel(), game.getIndex()) || {}\r\n          }\r\n          return {\r\n            data: o.data,\r\n            isRandomSelect: true,\r\n            timeout: cal.timeout || o.timeout || false,\r\n            showTimer: cal.showTimer || o.showTimer || false,\r\n            getMessage:\r\n              cal.getMessage ||\r\n              o.message ||\r\n              function(opt) {\r\n                return false\r\n              },\r\n            messageDelay:\r\n              cal.messageDelay ||\r\n              o.messageDelay ||\r\n              function(opt) {\r\n                return 0\r\n              },\r\n            finish: cal.finish || o.finish || function(opt) {},\r\n            getStepImage: cal.getStepImage || o.getStepImage,\r\n          }\r\n        },\r\n      page: o.page || 'penalty-message',\r\n    }\r\n  },\r\n}\r\n\r\n\/\/ TODO:  Come up with a better way of setting probability than duplicating items x times.\r\nvar penaltyOccurrence = [\r\n  \/\/ EDGE\r\n  {\r\n    pf: pf.edge,\r\n    o: {\r\n      id: 'edge',\r\n      allow: function() {\r\n        \/\/ Game round over 4, and has more than one sroke penalty\r\n        return g.r > 3 && g.pc.stroke.c > 1\r\n      },\r\n    },\r\n    probability: function() {\r\n      return 5\r\n    }, \/\/ repeat 5 times to set probability\r\n    enabled: function() {\r\n      return true\r\n    }, \/\/ Always include\r\n  },\r\n  \/\/ EDGE & RIDE\r\n  {\r\n    pf: pf.edge,\r\n    o: {\r\n      id: 'edgeRide',\r\n      allow: function() {\r\n        \/\/ Game round over 9, and has more than one sroke penalty\r\n        return g.r > 8 && g.pc.stroke.c > 4, g.pc.edge.c > 1\r\n      },\r\n      ride: true, \/\/ Enable ride edge\r\n    },\r\n    probability: function() {\r\n      return 5\r\n    }, \/\/ repeat 5 times to set probability\r\n    enabled: function() {\r\n      return true\r\n    }, \/\/ Always include\r\n  },\r\n  \/\/ STROKE\r\n  {\r\n    pf: pf.stroke,\r\n    o: {\r\n      id: 'stroke',\r\n      allow: function() {\r\n        return (\r\n          !game.strokePenaltyLimit ||\r\n          game.getLevel() < 2 ||\r\n          game.isCumRound() ||\r\n          g.pc.stroke.c < 2\r\n        )\r\n      },\r\n      ride: true,\r\n    },\r\n    probability: function() {\r\n      return 5\r\n    }, \/\/ repeat 5 times to set probability\r\n    enabled: function() {\r\n      return true\r\n    }, \/\/ Always include\r\n  },\r\n  {\r\n    pf: pf.stroke,\r\n    o: {\r\n      id: 'strokeMore', \/\/ Another copy of stroke to increase it's probability\r\n      altId: 'stroke', \/\/ record use as stroke\r\n      allow: function() {\r\n        return (\r\n          !game.strokePenaltyLimit ||\r\n          game.getLevel() < 2 ||\r\n          game.isCumRound() ||\r\n          g.pc.stroke.c < 2\r\n        )\r\n      },\r\n      ride: true,\r\n    },\r\n    probability: function() {\r\n      return 5\r\n    }, \/\/ repeat 5 times to set probability\r\n    enabled: function() {\r\n      return true\r\n    }, \/\/ Always include\r\n  },\r\n  \/\/ LOSE REST\r\n  {\r\n    pf: pf.loseRest,\r\n    o: {\r\n      id: 'loseRest',\r\n      allow: function() {\r\n        return (\r\n          g.r > 1 &&\r\n          g.pc.stroke.c > 1 &&\r\n          g.c > 0 &&\r\n          roulette.penalty.id !== 'loseRest'\r\n        )\r\n      },\r\n    },\r\n    probability: function() {\r\n      return 1\r\n    }, \/\/ repeat 1 times to set low probability\r\n    enabled: function() {\r\n      return game.loseRest\r\n    }, \/\/ Only include if enabled\r\n  },\r\n  \/\/ PRECUM\r\n  {\r\n    pf: pf.precum,\r\n    o: {\r\n      id: 'precum',\r\n      allow: function() {\r\n        return (\r\n          g.pc.edgeRide.c > g.pc.precum.c && \/\/ has ridden edge at least once more than precum\r\n          Date.now() - g.pc.precum.t >= 120000\r\n        ) \/\/ at leaste 2 minutes since last precum\r\n      },\r\n    },\r\n    probability: function() {\r\n      return 2\r\n    }, \/\/ repeat 2 times to set probability\r\n    enabled: function() {\r\n      return game.kinkPrecum\r\n    }, \/\/ Only include if enabled\r\n  },\r\n  \/\/ ANAL START\r\n  {\r\n    pf: pf.analToyStart, \/\/ Use stroke factory\r\n    o: {\r\n      id: 'anal_s',\r\n      allow: function() {\r\n        return g.r > 5 && g.pc.stroke.c > 2\r\n         && ((Date.now() - g.pc.anal_e.t) \/ 1000) > game.minTimeBetweenAnalSwitch\r\n      },\r\n      anal: true,\r\n    },\r\n    probability: function() {\r\n      return 20\r\n    }, \/\/ repeat 20 times to set highish probability\r\n    enabled: function() {\r\n      return !game.analToy && game._enabledAnalToys.length\r\n    }, \/\/ Only include if enabled\r\n  },\r\n  \/\/ ANAL END\r\n  {\r\n    pf: pf.analToyEnd, \/\/ Use stroke factory\r\n    o: {\r\n      id: 'anal_e',\r\n      allow: function() {\r\n        return g.r > 5 && g.pc.stroke.c > 1\r\n        && ((Date.now() - g.pc.anal_s.t) \/ 1000) > game.minTimeBetweenAnalSwitch\r\n      },\r\n      anal: true,\r\n    },\r\n    probability: function() {\r\n      return 4\r\n    }, \/\/ repeat 4 times to set probability\r\n    enabled: function() {\r\n      return game.analToy && game._enabledAnalToys.length\r\n    }, \/\/ Only include if enabled\r\n  },\r\n  \/\/ ANAL ONLY\r\n  {\r\n    pf: pf.stroke, \/\/ Use stroke factory\r\n    o: {\r\n      id: 'anal',\r\n      allow: function() {\r\n        return g.r > 5 && g.pc.stroke.c > 1 && roulette.penalty.id !== 'anal'\r\n      },\r\n      anal: true,\r\n      \/\/ messageDelay: function(opt) {\r\n      \/\/   return 2000 \/\/ Wait another 2 second to get toy in ass after prepPrompt\r\n      \/\/ },\r\n    },\r\n    probability: function() {\r\n      return 3\r\n    }, \/\/ repeat 3 times to set probability\r\n    enabled: function() {\r\n      return game.analToy && game.analToy.type === 'dildo'\r\n    }, \/\/ Only include if enabled\r\n  },\r\n  \/\/ CBT\r\n  {\r\n    pf: pf.cbt,\r\n    o: {\r\n      id: 'cbt',\r\n      allow: function() {\r\n        return (\r\n          g.r > 2 &&\r\n          g.pc.stroke.c > 1 &&\r\n          roulette.penalty.id !== 'cbt' &&\r\n          (g.pc.edge.c || g.pc.edgeRide.c)\r\n        )\r\n      },\r\n    },\r\n    probability: function() {\r\n      return 3\r\n    }, \/\/ repeat 3 times to set probability\r\n    enabled: function() {\r\n      return game.kinkCbt\r\n    }, \/\/ Only include if enabled\r\n  },\r\n]\r\n\r\nvar penalties = []\r\n\r\n\/**\r\n * Set penalty counts\r\n *\/\r\nfunction setPenaltyCounts() {\r\n  var po = penaltyOccurrence\r\n  if (DEBUG) console.log('Setting penalty counts:', po, g.pc)\r\n  g.pc = g.pc || {}\r\n  for (var i = 0, l = po.length; i < l; i++) {\r\n    var p = po[i]\r\n    var poid = p.o.altId || p.o.id\r\n    g.pc[poid] = g.pc[poid] || { c: 0, t: 0 }\r\n  }\r\n  if (DEBUG) console.log('Set penalty counts:', g.pc)\r\n}\r\n\r\n\/**\r\n * Build the panalties list\r\n *\/\r\nfunction buildPenalties() {\r\n  var po = penaltyOccurrence\r\n  setPenaltyCounts()\r\n  penalties = [] \/\/ reset penalties list\r\n  if (DEBUG) console.log('Building penalties:', po)\r\n  for (var i = 0, l = po.length; i < l; i++) {\r\n    var p = po[i]\r\n    var poId = p.o.altId || p.o.id\r\n    var povf = game.penaltyOccurrence && game.penaltyOccurrence[poId]\r\n    var probability = p.probability\r\n    var enabled = p.enabled\r\n    var allow = null\r\n    if (typeof povf === 'function') {\r\n      var pov = povf()\r\n      probability = (pov && pov.probability) || probability\r\n      enabled = (pov && pov.enabled) || enabled\r\n      allow = (pov && pov.allow) || allow\r\n    }\r\n    if (enabled()) {\r\n      \/\/ Repeate pentaly x times to set its probability\r\n      if (DEBUG) console.log('Adding penalty:', p, po)\r\n      for (var prob = probability(); prob > 0; prob--) {\r\n        var newp = p.pf(p.o)\r\n        newp.allow = allow || newp.allow\r\n        penalties.push(newp)\r\n      }\r\n    } else {\r\n      if (DEBUG) console.log('Skipping penalty', p)\r\n    }\r\n  }\r\n  if (DEBUG) console.log('Built penalties:', penalties)\r\n}\r\n\r\n\/**\r\n * Rest manager object\r\n *\/\r\nvar rest = {\r\n  breathe: null,\r\n  count: null,\r\n  inc: 0,\r\n  breatheTotal: function() {\r\n    return Math.round(rest.breathe * 2 * 1000)\r\n  },\r\n  breatheIn: function() {\r\n    return Math.round(rest.breathe * 1000)\r\n  },\r\n  breatheOut: function() {\r\n    return Math.round(rest.breathe * 1000)\r\n  },\r\n  breatheInMessage: function() {\r\n    return game.text('restBreatheIn', rest)\r\n  },\r\n  breatheOutMessage: function() {\r\n    return game.text('restBreatheOut', rest)\r\n  },\r\n  doneMessage: function() {\r\n    return game.text('backToGame', rest)\r\n  },\r\n  startMessage: function() {\r\n    if (rest.overrideStart) {\r\n      if (typeof rest.overrideStart === 'function') {\r\n        rest.overrideStart = rest.overrideStart()\r\n      }\r\n      var result = rest.overrideStart\r\n      rest.overrideStart = false\r\n      return result\r\n    } else {\r\n      return game.text('restStart', rest)\r\n    }\r\n  },\r\n  isFirst: function() {\r\n    return rest.inc === 0\r\n  },\r\n  isLast: function() {\r\n    return rest.inc + 1 >= rest.count\r\n  },\r\n  next: function() {\r\n    rest.inc++\r\n    if (rest.inc >= rest.count) {\r\n      if (DEBUG) console.log('Running rest next', 'rest-end')\r\n      pages.goto('rest-end')\r\n    } else {\r\n      if (DEBUG) console.log('Running rest next', pages.getCurrentPageId())\r\n      pages.goto(pages.getCurrentPageId())\r\n    }\r\n  },\r\n  end: function() {\r\n    if (rest.overrideDone) {\r\n      if (typeof rest.overrideDone === 'function') {\r\n        rest.overrideDone = rest.overrideDone()\r\n      }\r\n      game.message = rest.overrideDone\r\n      rest.overrideDone = false\r\n    } else {\r\n      game.message = rest.doneMessage()\r\n    }\r\n    rest.overrideStart = false\r\n    returnToCaller()\r\n  },\r\n  setOpts: function(opt) {\r\n    if (typeof opt.getRestStart === 'function') {\r\n      rest.overrideStart = opt.getRestStart(opt)\r\n    }\r\n    if (typeof opt.getRestEnd === 'function') {\r\n      rest.overrideDone = opt.getRestEnd(opt)\r\n    }\r\n  },\r\n  startNoPush: function(count, breathe) {\r\n    rest.start(count, breathe, true)\r\n  },\r\n  start: function(count, breathe, noPush) {\r\n    if (pages.getCurrentPageId().match(\/^penalty\/)) {\r\n      \/\/ We'll want to route back somewhere else...\r\n      if (roulette.opt && (typeof roulette.opt.onRest === 'function')) {\r\n        if(roulette.opt.onRest(roulette.opt)) {\r\n          return\r\n        }\r\n      }\r\n      noPush = true \/\/ Go back to caller...\r\n    }\r\n    beats.stopAll()\r\n    closeAll()\r\n    rest.breathe = breathe || 3\r\n    rest.count = count || 3\r\n    rest.inc = 0\r\n    if (noPush) {\r\n      \/\/ Go straight to rest. rest-end will return to page that called our caller.\r\n      if (DEBUG) console.log('Running rest page, no call', 'rest')\r\n      pages.goto('rest')\r\n    } else {\r\n      \/\/ Push caller.  rest-end will return to caller's page.\r\n      callPage('rest')\r\n    }\r\n  },\r\n}\r\n\r\n\/\/ Am I using this anywhere?  Should be in the game object,\r\n\/\/ but looks like I decided to modify g.r directly everywhere.\r\n\/\/ Why oh why didn't I take the time to build proper prototypes?\r\nfunction incRound() {\r\n  g.r++\r\n}\r\n\r\n\/*****************\r\n * BLACKJACK\r\n *****************\r\n * TODO: take the time to properly define the prototype methods\r\n *\/\r\nvar PLAYER = 0\r\nvar DEALER = 1\r\nvar TIE = 2\r\nfunction BlackJackGame(options) {\r\n  options = options || {}\r\n  options.numberOfDecks = options.numberOfDecks || 1\r\n  options.dealerSaftey = options.dealerSaftey || 17\r\n\r\n  this.hand = 0 \/\/ How many hands have been delt in total\r\n  this.deckHand = 0 \/\/ How many hands have been delt for current deck(s)\r\n  this.lastMessage = null\r\n  this.lastWinner = null\r\n  this.lastBj = false \/\/ Last winner was blackjack\r\n  this.lastTie = false \/\/ Last round was tie\r\n  this.lastDealerChoice = null\r\n  this.lastPlayerChoice = null\r\n  this.incRound = false\r\n  this.shuffled = false\r\n  this.outOfCards = false\r\n  this.started = false\r\n\r\n  this.deck = [] \/\/ The current deck(s) of cards\r\n  this.dealer = [] \/\/ The dealer's current hand\r\n  this.player = [] \/\/ The player's current hand\r\n  this.dpoints = 0 \/\/ The dealer's current points\r\n  this.ppoints = 0 \/\/ The player's current points\r\n  this.dstand = false \/\/ Dealer decided to stand\r\n  this.pstand = false \/\/ Player decided to stand\r\n\r\n  this._card = [\r\n    '?',\r\n    'A',\r\n    '2',\r\n    '3',\r\n    '4',\r\n    '5',\r\n    '6',\r\n    '7',\r\n    '8',\r\n    '9',\r\n    '10',\r\n    'J',\r\n    'Q',\r\n    'K',\r\n  ]\r\n  this._suit = ['&hearts;', '&diams;', '&clubs;', '&spades;', '?'] \/\/ Character for card suit\r\n  this._color = ['red', 'red', 'white', 'white', 'white'] \/\/ HTML color of text on card (can't control background color in EOS)\r\n\r\n  this._options = options\r\n\r\n  this._getCard = function(cardIndex, suitIndex) {\r\n    var color = this._color[suitIndex]\r\n    var card = this._card[cardIndex]\r\n    var suit = this._suit[suitIndex]\r\n    var open = '' \/\/ [\r\n    var close = '' \/\/ ]\r\n    return (\r\n      '<span class=\"' +\r\n      this._options.cardButtonClass +\r\n      '\">' + \/\/ChoiceBubble_button__1Ldsc\r\n      open +\r\n      \/\/ '<span style=\"color:'+color+';\">' + card + '&nbsp;' + suit + '&nbsp;'  + card + '<\/span>' +\r\n      '<span style=\"color:' +\r\n      color +\r\n      ';\">' +\r\n      card +\r\n      '&nbsp;' +\r\n      suit +\r\n      '<\/span>' +\r\n      close +\r\n      '<\/span>'\r\n    )\r\n  }\r\n\r\n  this._shuffle = function(a) {\r\n    var j, x, i\r\n    for (i = a.length - 1; i > 0; i--) {\r\n      j = Math.floor(Math.random() * (i + 1))\r\n      x = a[i]\r\n      a[i] = a[j]\r\n      a[j] = x\r\n    }\r\n    return a\r\n  }\r\n\r\n  this._draw = function(target) {\r\n    \/\/ Get card from deck\r\n    var card = this.deck.pop()\r\n\r\n    if (!card) {\r\n      \/\/ Ran out of cards! (shouldn't get here!)\r\n      console.warn(\r\n        (target ? 'Dealer' : 'Player') +\r\n          ' ran out of cards - ' +\r\n          this._getCard(card.n, card.s)\r\n      )\r\n      this.outOfCards = true\r\n      return\r\n    }\r\n\r\n    \/\/ Set card to target\r\n    if (target) {\r\n      this.dealer.push(card)\r\n    } else {\r\n      this.player.push(card)\r\n    }\r\n\r\n    if (DEBUG) {\r\n      console.log(\r\n        (target ? 'Dealer' : 'Player') +\r\n          ' has drawn - ' +\r\n          this._getCard(card.n, card.s)\r\n      )\r\n    }\r\n  }\r\n\r\n  this._points = function(target) {\r\n    \/\/ Total up player's cards\r\n\r\n    \/\/ Take cards 1-10 at face value\r\n    \/\/ J, Q, K at 10 points\r\n    \/\/ Don't calculate aces yet - They can either be 1 or 11\r\n    var aces = 0,\r\n      points = 0\r\n    var arr = target ? this.dealer : this.player\r\n    for (var id = 0, l = arr.length; id < l; id++) {\r\n      var i = arr[id]\r\n      if (i.n === 1) {\r\n        aces++\r\n      } else if (i.n >= 11 && i.n <= 13) {\r\n        points += 10\r\n      } else {\r\n        points += i.n\r\n      }\r\n    }\r\n\r\n    \/\/ Check aces\r\n    if (aces !== 0) {\r\n      \/\/ Calculate all possible points\r\n      var minmax = []\r\n      for (var elevens = 0; elevens <= aces; elevens++) {\r\n        var calc = points + elevens * 11 + (aces - elevens * 1)\r\n        minmax.push(calc)\r\n      }\r\n\r\n      \/\/ Take safest highest score\r\n      points = minmax[0]\r\n      for (var id = 0, l = minmax.length; id < l; id++) {\r\n        var i = minmax[id]\r\n        if (i > points && i <= 21) {\r\n          points = i\r\n        }\r\n      }\r\n    }\r\n\r\n    \/\/ Set points\r\n    if (target) {\r\n      this.dpoints = points\r\n    } else {\r\n      this.ppoints = points\r\n    }\r\n\r\n    if (DEBUG)\r\n      console.log((target ? 'Dealer' : 'Player') + ' total points - ' + points)\r\n  }\r\n\r\n  this._doHit = function(target) {\r\n    if (DEBUG) console.log('Hitting:', target, target ? 'DEALER' : 'PLAYER')\r\n\r\n    if (target) {\r\n      this.lastDealerChoice = true\r\n    } else {\r\n      this.lastPlayerChoice = true\r\n    }\r\n\r\n    \/\/ Draw new card\r\n    this._draw(target)\r\n    this._points(target)\r\n\r\n    \/\/ If hit 21 exactly, auto-stand\r\n    if (target === PLAYER && this.ppoints === 21 && !this.pstand) {\r\n      this._doStand(PLAYER)\r\n    }\r\n    if (target === DEALER && this.dpoints === 21 && !this.dstand) {\r\n      this._doStand(DEALER)\r\n    }\r\n  }\r\n\r\n  this._doStand = function(target) {\r\n    if (target) {\r\n      this.lastDealerChoice = false\r\n      this.dstand = true\r\n    } else {\r\n      this.lastPlayerChoice = false\r\n      this.pstand = true\r\n    }\r\n  }\r\n\r\n  this._dealerMove = function() {\r\n    \/\/ If at or over saftey, dealer must stand, else hit\r\n    if (this.dpoints >= this._options.dealerSaftey) {\r\n      this._doStand(DEALER)\r\n    } else {\r\n      this._doHit(DEALER)\r\n    }\r\n\r\n    \/\/ Check for winner\r\n    var winner = this.check()\r\n\r\n    \/\/ If no winner, and player is standing, keep going until there's a winner\r\n    if (winner === null && this.pstand) {\r\n      this._dealerMove()\r\n    }\r\n  }\r\n\r\n  \/**\r\n   * Merge some common fields\r\n   *\/\r\n  this._mergeCommon = function(string) {\r\n    return mergeObject(string, {\r\n      ppoints: this.ppoints,\r\n      dpoints: this.dpoints,\r\n      rests: g.c,\r\n    })\r\n  }\r\n\r\n  this.justShuffled = function() {\r\n    if (this.shuffled) {\r\n      this.shuffled = false\r\n      return true\r\n    }\r\n    return false\r\n  }\r\n\r\n  this.getFinalTotalLabel = function(target) {\r\n    var winner = this.check()\r\n    if (winner !== null) {\r\n      return ' (<b>' + (target ? this.dpoints : this.ppoints) + '<\/b>)'\r\n    }\r\n    return ''\r\n  }\r\n\r\n  this.getCards = function(target) {\r\n    var winner = this.check()\r\n    var cards = []\r\n    var arr = target ? this.dealer : this.player\r\n    for (var i = 0, l = arr.length; i < l; i++) {\r\n      var c = arr[i]\r\n      if (i === 0 && target === DEALER && winner === null) {\r\n        cards.push(this._getCard(0, 4)) \/\/ Hide first card for dealer if no winner\r\n      } else {\r\n        cards.push(this._getCard(c.n, c.s))\r\n      }\r\n    }\r\n    return cards.join(' ')\r\n  }\r\n\r\n  this.updatePlayLabels = function() {\r\n    this._options.updatePlayLabels && this._options.updatePlayLabels()\r\n  }\r\n\r\n  this.startIfNot = function() {\r\n    if (!this.started) this.start(true)\r\n  }\r\n\r\n  this.start = function(skipInc) {\r\n    if (DEBUG) console.log('Starting new hand...')\r\n\r\n    this.started = true\r\n\r\n    if (this.incRound) {\r\n      incRound()\r\n      if (this.lastWinner === PLAYER && this.lastBj) {\r\n        if (this._options.blackJackCallback) {\r\n          this._options.blackJackCallback()\r\n        } else {\r\n          g.c++ \/\/ Increment rests\r\n          if (DEBUG) console.log('Incremented rests:', g.c)\r\n        }\r\n      }\r\n      if (typeof this._options.onPlayerWin === 'function') {\r\n        this._options.onPlayerWin()\r\n      }\r\n      this.updatePlayLabels()\r\n    }\r\n\r\n    this.incRound = false\r\n\r\n    var firstHand = !this.hand\r\n\r\n    this.hand++\r\n    this.deckHand++\r\n\r\n    this.dealer = []\r\n    this.player = []\r\n    this.dpoints = 0\r\n    this.ppoints = 0\r\n    this.dstand = false\r\n    this.pstand = false\r\n    this.outOfCards = false\r\n\r\n    this.lastMessage = null\r\n    this.lastWinner = null\r\n    this.lastDealerChoice = null\r\n    this.lastPlayerChoice = null\r\n    this.lastTie = false\r\n    this.lastBj = false\r\n\r\n    var players = 1 \/\/ We always have just one player (plus dealer)\r\n    var handsPerDeck = 6 - players \/\/ Yes, we could just say 5, but this makes it clear what we're doing\r\n\r\n    if (\r\n      this._options.continousShuffle ||\r\n      firstHand ||\r\n      this.deckHand > handsPerDeck * this._options.numberOfDecks\r\n    ) {\r\n      \/\/ Build new deck(s)\r\n      this.deck = []\r\n      for (var dn = 0, l = this._options.numberOfDecks; dn < l; dn++) {\r\n        for (var i = 0; i < 4; i++) {\r\n          for (var j = 1; j < 14; j++) {\r\n            this.deck.push({\r\n              s: i, \/\/ Suit: 0 = Heart, 1 = Diamond, 2 = Club, 3 - Spade\r\n              n: j, \/\/ Number: 1 = Ace, 2-10 = as-is, 11 = Jack, 12 = Queen, 13 = King\r\n            })\r\n          }\r\n        }\r\n      }\r\n\r\n      \/\/ Shuffle deck(s)\r\n      this.deck = this._shuffle(this.deck)\r\n      \/\/ And again\r\n      this.deck = this._shuffle(this.deck)\r\n      \/\/ And one more time\r\n      this.deck = this._shuffle(this.deck)\r\n      this.shuffled = true\r\n\r\n      this.deckHand = 1 \/\/ reset # deck hands (1, not 0. we're past hand inc here.)\r\n\r\n      if (DEBUG) console.warn('Deck shuffled', this.deck)\r\n    }\r\n    if (DEBUG) console.log('Blackjack hand:', this.hand, this.deckHand)\r\n\r\n    \/\/Draw first two cards for player and dealer\r\n    this._draw(PLAYER)\r\n    this._draw(DEALER)\r\n    this._draw(PLAYER)\r\n    this._draw(DEALER)\r\n    this._points(PLAYER)\r\n    this._points(DEALER)\r\n\r\n    \/\/ Check for blackjack\r\n    this.check()\r\n  }\r\n\r\n  this.check = function(forceRefresh) {\r\n    if (this.lastWinner && !forceRefresh) return this.lastWinner\r\n\r\n    var winner = null, \/\/ 0 for player, 1 for dealer, 2 for a tie\r\n      message = null\r\n\r\n    \/\/ Check for out of cards\r\n    if (this.outOfCards) {\r\n      \/\/ Shouldn't ever get here\r\n      winner = PLAYER\r\n      message = 'Oh no!  I ran out of cards!  You win!'\r\n    }\r\n\r\n    \/\/ Check for blackjack\r\n    if (\r\n      winner === null &&\r\n      this.player.length === 2 &&\r\n      this.dealer.length === 2\r\n    ) {\r\n      \/\/ Tie with blackjacks\r\n      if (this.ppoints === 21 && this.dpoints === 21) {\r\n        winner = TIE\r\n        message = this._mergeCommon(randomString(this._options.t.tie))\r\n        this.lastTie = true\r\n      }\r\n      \/\/ Player wins blackjack\r\n      if (winner === null && this.ppoints === 21) {\r\n        this.lastBj = true\r\n        winner = PLAYER\r\n        message = this._mergeCommon(randomString(this._options.t.bj_p))\r\n      }\r\n      \/\/ Dealer wins blackjack\r\n      if (winner === null && this.dpoints === 21) {\r\n        this.lastBj = true\r\n        winner = DEALER\r\n        message = this._mergeCommon(randomString(this._options.t.bj_d))\r\n      }\r\n    }\r\n\r\n    \/\/ Check for bust\r\n    if (winner === null) {\r\n      \/\/ Player gone bust\r\n      if (this.ppoints > 21) {\r\n        winner = DEALER\r\n        message = this._mergeCommon(randomString(this._options.t.bust_p))\r\n      }\r\n      \/\/ Dealer gone bust\r\n      if (this.dpoints > 21) {\r\n        winner = PLAYER\r\n        message = this._mergeCommon(randomString(this._options.t.bust_d))\r\n      }\r\n    }\r\n\r\n    \/\/ Check for winner if both players are standing\r\n    if (winner === null && this.dstand && this.pstand) {\r\n      \/\/ Dealer has more points\r\n      if (this.dpoints > this.ppoints) {\r\n        winner = DEALER\r\n        \/\/@ts-ignore\r\n        message = this._mergeCommon(randomString(this._options.t.win_d))\r\n      }\r\n      \/\/ Player has more points\r\n      else if (this.dpoints < this.ppoints) {\r\n        winner = PLAYER\r\n        message = this._mergeCommon(randomString(this._options.t.win_p))\r\n      }\r\n      \/\/ Tie\r\n      else {\r\n        winner = TIE\r\n        message = this._mergeCommon(randomString(this._options.t.tie))\r\n        this.lastTie = true\r\n      }\r\n    }\r\n\r\n    \/\/ If we have a winner, set incRound trigger\r\n    \/\/ Round will be incremented on next hand.\r\n    if (winner !== null && winner === PLAYER) {\r\n      this.incRound = true\r\n    }\r\n\r\n    this.lastMessage = message\r\n    this.lastWinner = winner\r\n\r\n    \/\/ Update label message\r\n    this.updatePlayLabels()\r\n\r\n    return winner\r\n  }\r\n\r\n  \/\/ Player hits\r\n  this.hit = function() {\r\n    \/\/ Do hit for player\r\n    this._doHit(PLAYER)\r\n\r\n    \/\/ Check for winner\r\n    var winner = this.check()\r\n\r\n    \/\/ If no winner, dealer's move\r\n    if (winner === null && !this.dstand) {\r\n      this._dealerMove()\r\n    }\r\n  }\r\n\r\n  \/\/ Player stands\r\n  this.stand = function() {\r\n    \/\/ Do stand for player\r\n    this._doStand(PLAYER)\r\n\r\n    \/\/ Check for winner\r\n    var winner = null\r\n    if (this.pstand && this.dstand) {\r\n      winner = this.check()\r\n    }\r\n\r\n    \/\/ If no winner, dealer's move\r\n    if (winner === null) {\r\n      this._dealerMove()\r\n    }\r\n  }\r\n\r\n  \/\/ Start the first round\r\n  \/\/ this.start(true);\r\n}\r\n\r\n\/\/ TODO: SimpleBeats should be able to replace this\r\n\/\/       It's now basically just a compatibility wrapper for SimpleBeats.\r\n\/******************\r\n * BEATS\r\n ******************\r\n *\/\r\nvar beats = {\r\n  loaded: false,\r\n  inited: false,\r\n  sounds: {},\r\n  bpms: [],\r\n  currentBpm: 60,\r\n  currentPattern: null,\r\n  setPattern: function (pattern, skipPlay) {\r\n    beats.currentPattern = pattern\r\n    if (skipPlay) return\r\n    game._beats.bpm(beats.currentBpm, beats.currentPattern)\r\n  },\r\n  init: function(skipOthers) {\r\n    if (!beats.inited) {\r\n      game._beats.setVolume(0)\r\n      game._beats.bpm(60, beats.currentPattern)\r\n      setTimeout(function(){\r\n        beats.volume()\r\n      })\r\n      game._beats.stop()\r\n      beats.inited = true\r\n      if (skipOthers) return\r\n      moans.init()\r\n      roulette.initSounds()\r\n      \/\/ do a set timeout to make sure they're working\r\n      if (window.setTimeout) {setTimeout(function(){if (DEBUG) {console.log('setTimeout init')}},1)}\r\n    } else {\r\n      beats.volume()\r\n    }\r\n    moans.volume()\r\n    roulette.volume()\r\n  },\r\n  set: function(bpm) {\r\n   console.warn('beats.set(...) is deprecated')\r\n  },\r\n  volume: function(vol) {\r\n    if (!game._beats) return\r\n    game._beats.setVolume(vol || game.volume)\r\n  },\r\n  start: function(bpm) {\r\n    bpm = parseInt(bpm, 10)\r\n    beats.currentBpm = bpm\r\n    if (!game._beats) return\r\n    beats.setPattern(beats.currentPattern)\r\n  },\r\n  stop: function(bpm) {\r\n    if (!game._beats) return\r\n    if (!bpm) {\r\n      game._beats.stop()\r\n      return\r\n    }\r\n    bpm = parseInt(bpm, 10)\r\n    if (beats.currentBpm === bpm) {\r\n      beats.currentBpm = null\r\n      game._beats.stop()\r\n    }\r\n  },\r\n  stopAll: function() {\r\n    if (!game._beats) return\r\n    game._beats.stop()\r\n    beats.currentBpm = null\r\n  },\r\n  pause: function(bpm) {\r\n    return game._beats.pause()\r\n  },\r\n  getRandom: function(minBpm, maxBpm) {\r\n    return beats.closestBpm(randomInt(minBpm, maxBpm))\r\n  },\r\n  startRandom: function(minBpm, maxBpm) {\r\n    var bpm = beats.getRandom(minBpm, maxBpm)\r\n    beats.start(bpm, false)\r\n    return bpm\r\n  },\r\n  closestBpm: function(bpm) {\r\n    return Math.min(Math.max(Math.round(parseInt(bpm, 10) \/ 5) * 5, beats.minBpm()), beats.maxBpm())\r\n  },\r\n  nextBpm: function(bpm) {\r\n    return beats.closestBpm(bpm + 20)\r\n  },\r\n  minBpm: function() {\r\n    return game.bpmMin\r\n  },\r\n  maxBpm: function() {\r\n    return game.bpmMax\r\n  },\r\n}\r\n\r\n\/******************\r\n * MOANS\r\n ******************\r\n *\/\r\nvar SoundObj = function(opts) {\r\n  this.id = opts.id\r\n  this.audioId = opts.audioId\r\n  this.isPlaying = false\r\n  this._sound = opts.sound\r\n}\r\nSoundObj.prototype.sound = function() {\r\n  return this._sound\r\n  \/\/ return Sound.get(this.audioId)\r\n}\r\nSoundObj.prototype.destroy = function() {\r\n  console.log('Destroying moan sound', this.audioId)\r\n  var sound = this.sound()\r\n  console.log('Destroying moan sound2', this.audioId, sound)\r\n  sound && sound.destroy()\r\n}\r\nSoundObj.prototype.play = function() {\r\n  var sound = this.sound()\r\n  var _this = this\r\n  if (!sound) return\r\n  if (!sound._fjInit) {\r\n    sound._fjInit = true\r\n    sound.addEventListener('end', function() {\r\n      if (DEBUG) console.log('Finished playing moan', _this)\r\n      _this.isPlaying = false\r\n    })\r\n  }\r\n  this.isPlaying = true\r\n  sound.play()\r\n}\r\nSoundObj.prototype.stop = function() {\r\n  this.isPlaying = false\r\n  var sound = this.sound()\r\n  if (!sound) return\r\n  sound.stop()\r\n}\r\n\r\nvar moans = {\r\n  loaded: false,\r\n  inited: false,\r\n  groups: {},\r\n  sounds: {},\r\n  last: [],\r\n  current: null,\r\n  init: function(force) {\r\n    if (!moans.inited || force) {\r\n      moans.volume(0.01)\r\n      moans.startAll()\r\n      moans.stopAll()\r\n      moans.inited = true\r\n    }\r\n  },\r\n  _getGroup: function(key) {\r\n    var groups = moans.groups\r\n    var group = groups[key]\r\n    if (!group) {\r\n      group = {}\r\n      groups[key] = group\r\n    }\r\n    return group\r\n  },\r\n  purge: function() {\r\n    Object.keys(moans.sounds).forEach(function(k){\r\n      var sound = moans.sounds[k]\r\n      sound && sound.destroy()\r\n    })\r\n    moans.sounds = {}\r\n    moans.groups = {}\r\n    moans.last = []\r\n    moans.current = null\r\n    moans.inited = false\r\n    moans.loaded = false\r\n  },\r\n  set: function(key, index, audioId) {\r\n    if (!key) {\r\n      console.error('Invalid moan key', key)\r\n      return\r\n    }\r\n    if (!index || isNaN(index)) {\r\n      console.error('Invalid moan index.  Must be integer > 0', index)\r\n      return\r\n    }\r\n    if (moans.current) moans.stop(current)\r\n    var id = key + '-' + index\r\n    audioId = audioId || id\r\n    var sound = Sound.get(id)\r\n    if (DEBUG) console.warn('Adding moan', id, audioId, sound)\r\n    var moan = new SoundObj({\r\n      id: id,\r\n      audioId: audioId,\r\n      sound: sound,\r\n    })\r\n    if (!moan.sound()) {\r\n      console.error('Invalid moan Audio action identifier', audioId)\r\n      return\r\n    }\r\n    var group = moans._getGroup(key)\r\n    group[index + ''] = moan\r\n    moans.sounds[id + ''] = moan\r\n    moan.sound().stop()\r\n  },\r\n  remove: function(key, index) {\r\n    if (!key) {\r\n      console.error('You must supply a key for moan removal')\r\n      return\r\n    }\r\n    if (!index) {\r\n      console.error('You must supply an index for moan removal')\r\n      return\r\n    }\r\n    var group = moans._getGroup(key)\r\n    delete group[index  +'']\r\n    var sound = moans.sounds[index + '']\r\n    sound && sound.destroy()\r\n    delete moans.sounds[index + '']\r\n  },\r\n  volume: function(vol) {\r\n    Object.keys(moans.sounds).forEach(function(k) {\r\n      moans.sounds[k].sound().setVolume(vol || game.volume)\r\n    })\r\n  },\r\n  start: function(key, index, indexEnd, stop) {\r\n    var group = moans._getGroup(key)\r\n    var currentlyPlaying = Object.keys(group).reduce(function(a, k) {\r\n      var m = group[k]\r\n      if (m && m.isPlaying) {\r\n        a.push(m)\r\n      }\r\n      return a\r\n    }, [])\r\n    if (!stop && currentlyPlaying.length) {\r\n      if (DEBUG) console.log('Skipping play of', key, index, 'Currently playing', currentlyPlaying)\r\n      return false\r\n    }\r\n    if (stop) {\r\n      currentlyPlaying.forEach(function(m) {m.stop()})\r\n    }\r\n    var moan = moans._get(key, index, indexEnd)\r\n    if (moans.current && (stop || moans.current !== moan)) {\r\n      moans.stop(moans.current)\r\n    }\r\n    if (moan) {\r\n      moan.play()\r\n    }\r\n    moans.current = moan\r\n    moans.last.push(moan)\r\n    moans.last = moans.last.slice(-3)\r\n    return moan\r\n  },\r\n  _get: function(key, index, indexEnd) {\r\n    var group = moans._getGroup(key)\r\n    if (!Object.keys(group).length) {\r\n      console.error('No moans defined for key', key, moans.groups)\r\n      return null\r\n    }\r\n    if (index && !indexEnd) {\r\n      var moan = group[index  +'']\r\n      if (!moan) {\r\n        console.error('Unable to find moan in \"' + key + '\" for index', index)\r\n        return null\r\n      }\r\n      return moan\r\n    }\r\n    var indexes = Object.keys(group).sort()\r\n    var len = indexes.length\r\n    var min = 0\r\n    var max = len -1\r\n    if (index) {\r\n      min =  indexes.indexOf(index + '')\r\n      if (min < 0) {\r\n        console.error(\"Minimum index '\" + index + \"' for random moan not found. Using \" + indexes[0], key, group)\r\n        min = 0\r\n      }\r\n    }\r\n    if (indexEnd) {\r\n      max =  indexes.indexOf(indexEnd + '')\r\n      if (max < 0) {\r\n        console.error(\"Maximum index '\" + indexEnd + \"' for random moan not found. Using \" + indexes[len-1], key, group)\r\n        max = len - 1\r\n      }\r\n    }\r\n    if (max < min) {\r\n      console.error(\"Maximum index for random moan cannot be less than minimum. Using \" + indexes[len-1], key, index, indexEnd)\r\n      max = len\r\n    }\r\n    var check = 0\r\n    var moan = group[indexes[randomInt(min, max)]]\r\n    while (indexes.length > 2 && check < 10 && moans.last.indexOf(moan) > -1) {\r\n      \/\/ console.log('Dup moan', moan, moans.last)\r\n      moan = group[indexes[randomInt(min, max)]]\r\n      \/\/ console.log('Checking moan', moan, moans.last)\r\n      check++\r\n      if (check > 5) moans.last.shift()\r\n    }\r\n    \/\/ if (DEBUG) console.log('Using random moan', moan)\r\n    return moan\r\n  },\r\n  stop: function(key, index) {\r\n    if (key && key.sound) {\r\n      \/\/ key is a moan\r\n      key.stop()\r\n      if (moans.current === key) moans.current = null\r\n      return\r\n    }\r\n    if (!index) {\r\n      var group = moans._getGroup(key)\r\n      moans.stopAll(group)\r\n      return\r\n    }\r\n    var moan = moans._get(key, index)\r\n    if (moan) {\r\n      moan.stop()\r\n      if (moans.current === moan) moans.current = null\r\n    }\r\n  },\r\n  startAll: function(group) {\r\n    group = group || moans.sounds\r\n    Object.keys(group).forEach(function(m) {\r\n      group[m].play()\r\n    }) \r\n  },\r\n  stopAll: function(group) {\r\n    group = group || moans.sounds\r\n    Object.keys(group).forEach(function(m) {\r\n      group[m].stop()\r\n      if (moans.current === group[m]) moans.current = null\r\n    })\r\n  },\r\n}\r\n\r\n\/******************\r\n * MISC FUNCTIONS\r\n ******************\r\n *\/\r\n\r\n\/**\r\n * Merge values from an object into a given string.\r\n * For example: if string is \"[a] is a [b] to do.\"\r\n *             and obj is {a: \"this\", b: \"terrible thing\"}\r\n * the result will be:  \"this is a terrible thing to do.\"\r\n *\/\r\nfunction mergeObject(string, obj, counter) {\r\n  counter = counter || 0\r\n  counter ++\r\n  if (counter > 100) {\r\n    console.error('Infinite loop detected getting game text from:', string)\r\n    return string\r\n  }\r\n  if (typeof string !== 'string') {\r\n    if (DEBUG && string !== undefined && isNaN(string)) {\r\n      console.error('\"string\" passed to mergeObject is not a string:', string)\r\n    }\r\n    return string\r\n  }\r\n  var fields = string.match(\/\\[[a-z_\\-\\|0-9_\\+\\!\\$\\#\\.]+\\]\/gim)\r\n  obj = obj || game \/\/ fall back to game if no object provided\r\n  if (fields) {\r\n    var didFields = {}\r\n    for (var i = 0, l = fields.length; i < l; i++) {\r\n      var field = fields[i]\r\n      if (!didFields[field]) {\r\n        didFields[field] = true\r\n        var property = field.replace(\/(^\\[|\\]$)\/gm, '')\r\n        var propertyParts = property.split(\/\\|\/)\r\n        property = propertyParts[0] || property\r\n        var args = propertyParts.slice(1).reduce(function(a, v) {\r\n          a.push(parseArgValue(v))\r\n          return a\r\n        }, [])\r\n        var replace = findProp(property, obj)\r\n        if (replace !== undefined) {\r\n          if (typeof replace === 'function') {\r\n            replace = replace.apply(this, args)\r\n            if (replace === undefined) replace = ''\r\n          }\r\n          replace = mergeObject(replace, obj, counter)\r\n          var index = string.indexOf(field)\r\n          while (index > -1) {\r\n            string = string.replace(field, replace)\r\n            index = string.indexOf(field)\r\n          }\r\n        } else {\r\n          console.error(\r\n            'Unable to find field \"' +\r\n              property +\r\n              '\" in given object, game or global object:',\r\n            obj,\r\n            string\r\n          )\r\n        }\r\n      }\r\n    }\r\n  }\r\n  var evals = string.match(\/<eval>.+?<\\\/eval>\/gim)\r\n  if (evals) {\r\n    for (var i = 0, l = evals.length; i < l; i++) {\r\n      var ev = evals[i]\r\n      var ex = ev.replace(\/(^<eval>|<\\\/eval>$)\/gm, '')\r\n      try {\r\n        var replace = eval(ex)\r\n        string = string.replace(field, replace)\r\n      } catch (e) {\r\n        if (e instanceof SyntaxError) {\r\n          console.error('Invalid eval: \"' + ex + '\" in: ', string, e.message)\r\n        } else {\r\n          console.error('Error in eval: \"' + ex + '\" in: ', string, e.message)\r\n        }\r\n      }\r\n    }\r\n  }\r\n  return string\r\n}\r\n\r\nfunction parseArgValue(p) {\r\n  if (p && p.match(\/^\\$\\$[a-z_]+\/i)) {\r\n    var pv = p.replace(\/^\\$\\$\/, '')\r\n    return mergeObject('[' + pv + ']', game, 0)\r\n  }\r\n  if (p && p.match(\/^\\#\\$[a-z_]+\/i)) {\r\n    var pv = p.replace(\/^\\#\\$\/, '')\r\n    return parseInt(mergeObject('[' + pv + ']', game, 0), 10)\r\n  }\r\n  return p\r\n}\r\nvar __lastFoundPath = []\r\nfunction propInIndex(obj,i) {\r\n  if(obj && obj.hasOwnProperty(i)) {\r\n    __lastFoundPath.push(i)\r\n    return obj[i]\r\n  }\r\n  return undefined\r\n}\r\nfunction findProp(p, obj) {\r\n  if (typeof p !== 'string') {\r\n    return p\r\n  }\r\n  obj = obj || game\r\n  var parts = p.split('.').reduce(function(a, v){\r\n    if (v) a.push(v)\r\n    return a\r\n  }, [])\r\n  if (!parts.length) return p\r\n  var result\r\n  if (game !== obj) {\r\n    __lastFoundPath = []\r\n    result = parts.reduce(propInIndex, obj)\r\n    if (__lastFoundPath.join('.') === p) {\r\n      return result\r\n    }\r\n  }\r\n  __lastFoundPath = []\r\n  result = parts.reduce(propInIndex, game)\r\n  if (__lastFoundPath.join('.') === p) {\r\n    return result\r\n  }\r\n  __lastFoundPath = []\r\n  result = parts.reduce(propInIndex, window)\r\n  if (__lastFoundPath.join('.') === p) {\r\n    return result\r\n  }\r\n  console.error('Unable to find property path \"' + p + '\" in game or global scope')\r\n  return p\r\n}\r\n\r\n\/\/ Object for tracking array use\r\nvar randomStringHistory = {}\r\n\r\n\/**\r\n * Return a random element from the given array, trying to avoid repeating\r\n * elements recently returned for the same array.\r\n *\/\r\nfunction randomString(stringArray, start, end, key) {\r\n  if (typeof stringArray !== 'object') {\r\n    console.error('Invalid object passed to randomString:', stringArray)\r\n    return stringArray\r\n  }\r\n  if (!stringArray.length) {\r\n    return undefined\r\n  }\r\n  if (stringArray.length === 1) {\r\n    return stringArray[0]\r\n  }\r\n  start = Math.min(start || 0, stringArray.length)\r\n  end = end || stringArray.length\r\n  key = key || JSON.stringify(stringArray) \/\/ We don't have Map in EOS\/ES5, so use JSON as key\r\n  var lastResults = randomStringHistory[key] || []\r\n  lastResults = lastResults.slice(0 - Math.floor(stringArray.length \/ 2))\r\n  if (stringArray.length - lastResults.length === 1) {\r\n    \/\/ Randomly eliminate the last option if only 1 option left\r\n    if (Math.floor(Math.random() * 2) == 0)\r\n      lastResults = lastResults.slice(0 - (lastResults.length - 1))\r\n  }\r\n  if (lastResults.length >= end - start) {\r\n    lastResults = []\r\n  }\r\n  \/\/ if (DEBUG) console.log('Randomizing string from', stringArray, lastResults, start, end, key)\r\n  var index = randomInt(start, end - 1)\r\n  while (lastResults.indexOf(index) > -1) {\r\n    \/\/ if (DEBUG) console.log('Randomizing string skipping', index, stringArray[index])\r\n    index = randomInt(start, end - 1)\r\n  }\r\n  \/\/ if (DEBUG) console.log('Randomizing selected', index, stringArray[index])\r\n  lastResults.push(index)\r\n  randomStringHistory[key] = lastResults\r\n  return stringArray[index]\r\n}\r\n\r\nvar randomObjectHistory = []\r\n\r\nfunction isInArray(arr, obj, comp) {\r\n  for (var i = 0, l = arr.legnth; i < l; i++) {\r\n    if (comp(arr[i], obj)) return true\r\n  }\r\n  return false\r\n}\r\n\r\n\/**\r\n * Return random object for array of objects\r\n *\/\r\nfunction randomObject(key, arr, compkey, randomItemHistorySize) {\r\n  var start = 0\r\n  var end = arr.length\r\n  var size = end - start\r\n  var lastResults = randomObjectHistory[key] || []\r\n  lastResults = lastResults.slice(\r\n    0 -\r\n      (randomItemHistorySize === undefined\r\n        ? game.randomItemHistorySize\r\n        : randomItemHistorySize)\r\n  )\r\n  randomObjectHistory[key] = lastResults\r\n  var lastResult = lastResults.length\r\n    ? lastResults[lastResults.length - 1]\r\n    : undefined\r\n  var index = randomInt(start, end - 1)\r\n  var item = arr[index]\r\n  var comp = function(a, b) {\r\n    return a && b && a[compkey] === b[compkey]\r\n  }\r\n  if (DEBUG) console.log('randomObject selection start:', key, arr, lastResults)\r\n  var i = 0\r\n  var loops = 0\r\n  var used = {}\r\n  used[index] = true\r\n  while (comp(item, lastResult) || isInArray(lastResults, item, comp)) {\r\n    if (DEBUG) console.log('Random Object Re-selecting.', item)\r\n    index = randomInt(start, end - 1)\r\n    var i2 = 0\r\n    while (i < size - 1 && used[index]) {\r\n      index = randomInt(start, end - 1)\r\n      i2++\r\n      if (i2 > 10000) {\r\n        if (DEBUG)\r\n          console.error(\r\n            'randomObject index select infinite loop detected.',\r\n            key\r\n          )\r\n        break\r\n      }\r\n    }\r\n    used[index] = true\r\n    item = arr[index]\r\n    i++\r\n    if (i > size) {\r\n      loops++\r\n      if (loops > 1) {\r\n        if (DEBUG)\r\n          console.warn(\r\n            'exausted all randomObject options on second run. Giving up.',\r\n            key\r\n          )\r\n        break\r\n      } else {\r\n        \/\/ try another way\r\n        if (DEBUG)\r\n          console.log(\r\n            'exausted all randomObject options on first run, trying again...',\r\n            key\r\n          )\r\n        lastResults = []\r\n        lastResult = undefined\r\n        \/\/ randomObjectHistory[key] = lastResults\r\n        used = {}\r\n        i = 0\r\n      }\r\n    }\r\n  }\r\n  lastResults.push(item)\r\n  return item\r\n}\r\n\r\n\/**\r\n * Return a random integer between min and max\r\n *\/\r\nfunction randomInt(min, max) {\r\n  return Math.floor(Math.random() * (max - min + 1)) + min\r\n}\r\n\r\n\/\/ Page stack storage\r\nvar pageStack = []\r\n\r\n\/**\r\n * push current page (and given pop callback) on stack an go to given page\r\n * @param {string} [pid] - Page Id to call\r\n * @param {function} [callback=undefined] - Optional callback function\r\n * @param {string} [altReturn=undefined] - Optional alternate page to return to\r\n *\/\r\nfunction callPage(pid, callback, altReturn) {\r\n  var currentPage = altReturn || pages.getCurrentPageId()\r\n  pageStack.push({\r\n    target: pid,\r\n    page: altReturn === -1 ? null : currentPage,\r\n    callback: callback,\r\n  })\r\n  if (DEBUG) console.log('calling page', pid, pageStack)\r\n  pages.goto(pid)\r\n}\r\n\r\n\/**\r\n * pull most recent page from stack\r\n *\/\r\nfunction pullPage() {\r\n  return pageStack.pop()\r\n}\r\n\r\nfunction gotoPulledPage(page) {\r\n  var didCallback = false\r\n  if (page && typeof page.callback === 'function') {\r\n    console.log('Executng pulledPage callback:', page.callback, page)\r\n    var result = page.callback(pages.getCurrentPageId(), page)\r\n    if (typeof result === 'string' && pages.contains(result)) {\r\n      if (DEBUG) console.log('Returning to callback result page', result, page)\r\n      pages.goto(result)\r\n      return\r\n    }\r\n    didCallback = true\r\n  }\r\n  if (!page) {\r\n    console.error(\"Can't pop page. pageStack empty\")\r\n  } else if (!page.page) {\r\n    if (didCallback) {\r\n      console.warn('Skipping null page, using callback instead:', page)\r\n    } else {\r\n      console.error(\"Can't pop page. Invalid page entry:\", page)\r\n    }\r\n  } else {\r\n    \/\/ console.warn('Popping page:', page.page, page);\r\n    if (DEBUG) console.log('Returning to page', page.page, page)\r\n    pages.goto(page.page)\r\n  }\r\n}\r\n\r\n\/**\r\n * pull most recent page from stack, call callback if one was pushed, then go to pushed page\r\n *\/\r\nfunction returnToCaller() {\r\n  gotoPulledPage(pullPage())\r\n}\r\n\r\n\/**\r\n * Close all active, tracked, notifications, execpt those provided, if any\r\n * (This should all have been put in a manager object.  Too late now.)\r\n *\/\r\nfunction closeAll() {\r\n  closeAllBut(undefined)\r\n}\r\n\r\n\/**\r\n * Close all active, tracked, notifications, execpt those provided, if any\r\n * (This should all have been put in a manager object.  Too late now.)\r\n *\/\r\nfunction closeAllBut(arr) {\r\n  var rn = Notification.get('random-select')\r\n  if (rn) rn.remove()\r\n  arr = arr || []\r\n  if (typeof arr === 'string') {\r\n    arr = [arr]\r\n  }\r\n  var obj = {}\r\n  for (var i = 0, l = arr.length; i < l; i++) {\r\n    obj[arr[i]] = true\r\n  }\r\n  for (var nt in n) {\r\n    if (nt && !obj[nt]) {\r\n      var notification = Notification.get(nt)\r\n      if (notification) notification.remove()\r\n      n[nt] = false\r\n    }\r\n  }\r\n}\r\n\r\nfunction closeNotifications(arr) {\r\n  arr = arr || []\r\n  if (typeof arr === 'string') {\r\n    arr = [arr]\r\n  }\r\n  if (DEBUG) console.warn(\"Closing notifications: \", arr)\r\n  arr.forEach(function(nt){\r\n    if (DEBUG) console.warn(\"Closing notification: \", nt)\r\n    var notification = Notification.get(nt)\r\n    if (notification) notification.remove()\r\n    n[nt] = false\r\n  })\r\n}\r\n\r\n\/**\r\n * Clear the name of the last roun image we loaded\r\n * Needed if we load an image not using loadRoundImage\r\n *\/\r\nfunction clearRoundImage() {\r\n  game.image = null\r\n}\r\n\/**\r\n * Call the proper image-x page for the given round, if needed.\r\n * (image-x page should returnToCaller() when it's done.)\r\n *\/\r\nfunction loadImagePage(imagePath, thenDo, thenGoto) {\r\n  if (game.image !== imagePath) {\r\n    if (DEBUG) console.warn('loading image page', imagePath)\r\n    game.image = imagePath\r\n    if (pages.contains(imagePath)) {\r\n      callPage(imagePath, thenDo || false, thenGoto || false)\r\n    } else {\r\n      if (DEBUG) console.error('MISSING IMAGE PAGE:', imagePath)\r\n    }\r\n    return true\r\n  } else {\r\n    if (DEBUG) console.log('already loaded image', imagePath)\r\n    return false\r\n  }\r\n}\r\n\r\nfunction findNearestRangeImage(imagePathBase) {\r\n  for (i = game.getRemapRoundIndex(); i > 0; i--) {\r\n    var rangePage = imagePathBase + '-' + i + 'plus'\r\n    if (pages.contains(rangePage)) {\r\n      return rangePage\r\n    }\r\n  }\r\n  return false\r\n}\r\n\r\nvar _lastImagePageStart = 0\r\n\r\nfunction _afterImageLoad() {\r\n  \/\/ On return from image page, update image load time\r\n  game.lastImageLoadTime = Date.now() - _lastImagePageStart\r\n  if (DEBUG) console.log('Image Load Time', game.lastImageLoadTime \/ 1000 + 's')\r\n}\r\n\r\n\/**\r\n * Call the proper image-x page for the given round, if needed.\r\n * (image-x page should returnToCaller() when it's done.)\r\n *\/\r\nfunction loadRoundImage() {\r\n  var roundPath = game.getRoundImagePath(true)\r\n  var imagePath = game.getRoundImagePath()\r\n  if (!imagePath) return false\r\n  if (game.image !== roundPath) {\r\n    if (DEBUG) console.warn('loading round image', imagePath)\r\n    game.image = roundPath\r\n    _lastImagePageStart = Date.now()\r\n    callPage(imagePath, _afterImageLoad, false)\r\n    return true\r\n  }\r\n  if (DEBUG) console.log('already have round image', imagePath)\r\n  return false\r\n}\r\n\r\n\/**\r\n * Call the proper game-over-x page for the given round, if needed.\r\n * (image-x page should returnToCaller() when it's done.)\r\n *\/\r\nfunction loadGameOverImage() {\r\n  var imagePath = game.getGameOverImagePath()\r\n  if (!imagePath) return false\r\n  if (game.image !== imagePath) {\r\n    if (DEBUG)\r\n      console.warn(\r\n        'loading game-over image ' + (game.isCumRound() ? ' (cum round)' : ''),\r\n        imagePath\r\n      )\r\n    game.image = imagePath\r\n    callPage(imagePath, false, false)\r\n    return true\r\n  }\r\n  if (DEBUG) console.log('already have game-over image', imagePath)\r\n  return false\r\n}\r\n\r\n\/**\r\n * Call the proper [mode]-[name]-[x] image page for the given round, if needed.\r\n * (image-x page should returnToCaller() when it's done.)\r\n *\/\r\nfunction loadNamedImage(name) {\r\n  var imagePath\r\n  for (var i = 0, l = arguments.length; i < l; i++) {\r\n    if (DEBUG) console.log('Looking for named image:', arguments[i])\r\n    imagePath = game.getNamedImagePath(arguments[i])\r\n    if (imagePath) break\r\n  }\r\n  if (!imagePath) return false\r\n  if (game.image !== imagePath) {\r\n    if (DEBUG) {\r\n      console.warn('loading named image:', imagePath)\r\n    }\r\n    game.image = imagePath\r\n    callPage(imagePath, false, false)\r\n    return true\r\n  }\r\n  if (DEBUG) console.log('already have named image', imagePath)\r\n  return false\r\n}\r\n\r\n\/**\r\n * Call the proper cumtease image page for the given round, if needed.\r\n * (image-x page should returnToCaller() when it's done.)\r\n *\/\r\nfunction loadCumTeaseImage() {\r\n  var imagePath = game.getCumTeaseImagePath()\r\n  if (!imagePath) return false\r\n  if (game.image !== imagePath) {\r\n    if (DEBUG)\r\n      console.warn(\r\n        'loading cumtease image ' + (game.isCumRound() ? ' (cum round)' : ''),\r\n        imagePath\r\n      )\r\n    game.image = imagePath\r\n    _lastImagePageStart = Date.now()\r\n    callPage(imagePath, _afterImageLoad, false)\r\n    return true\r\n  }\r\n  if (DEBUG) console.log('already have cumtease image', imagePath)\r\n  return false\r\n}\r\n\r\n\/**\r\n * Call the proper win image page for the given round, if needed.\r\n * (image-x page should returnToCaller() when it's done.)\r\n *\/\r\nfunction loadWinnerImage() {\r\n  var imagePath = game.getWinImagePath()\r\n  if (!imagePath) return false\r\n  if (game.image !== imagePath) {\r\n    if (DEBUG)\r\n      console.warn(\r\n        'loading winner image ' + (game.isCumRound() ? ' (cum round)' : ''),\r\n        imagePath\r\n      )\r\n    game.image = imagePath\r\n    callPage(imagePath, false, false)\r\n    return true\r\n  }\r\n  if (DEBUG) console.log('already have winner image', imagePath)\r\n  return false\r\n}\r\n\r\n\/**\r\n * Call the proper cum-round page for the given round, if needed.\r\n * (image-x page should returnToCaller() when it's done.)\r\n *\/\r\nfunction loadCumRoundSelectImage() {\r\n  var imagePath = game.getGameModePath() + 'cum-round-select'\r\n  if (game.image !== imagePath) {\r\n    if (DEBUG) console.warn('loading cum-round-select image', imagePath)\r\n    game.image = imagePath\r\n    if (pages.contains(imagePath)) {\r\n      callPage(imagePath, false, false)\r\n    } else {\r\n      if (DEBUG) console.warn('MISSING CUM-ROUND SELECT IMAGE PAGE:', imagePath)\r\n    }\r\n    return true\r\n  } else {\r\n    if (DEBUG) console.log('already have cum-round-select image', imagePath)\r\n    return false\r\n  }\r\n}\r\n\r\n\/**\r\n * Call the proper cum-round page for the given round, if needed.\r\n * (image-x page should returnToCaller() when it's done.)\r\n *\/\r\nfunction loadCumRoundImage() {\r\n  var imagePath = game.getGameModePath() + 'cum-round' + game.getCumRoundPath()\r\n  if (game.image !== imagePath) {\r\n    if (DEBUG) console.warn('loading cum-round intro image', imagePath)\r\n    game.image = imagePath\r\n    if (pages.contains(imagePath)) {\r\n      callPage(imagePath, false, false)\r\n    } else {\r\n      if (DEBUG) console.warn('MISSING CUM-ROUND IMAGE PAGE:', imagePath)\r\n    }\r\n    return true\r\n  } else {\r\n    if (DEBUG) console.log('already have cum-round intro image', imagePath)\r\n    return false\r\n  }\r\n}\r\n\r\n\/\/ object to for dynamically generated default setting list\r\nvar settingDefaults = {} \/\/ Leave empty!! It gets auto-generated!\r\n\r\n\/**\r\n * Return storage type object for given setting\r\n *\/\r\nfunction getStorageType(s) {\r\n  return (gameSettingStore[s] || {}).type\r\n}\r\n\r\nfunction getStorageTypeKey(s) {\r\n  var sType = getStorageType(s)\r\n  return sType && typeof sType.getKey === 'function'\r\n    ? sType.getKey(s)\r\n    : function(s) {\r\n        return s\r\n      }\r\n}\r\n\r\n\/**\r\n * Save settings to TeaseStorage\r\n *\/\r\nfunction saveSettings() {\r\n  Object.keys(gameSettingStore).forEach(function(s) {\r\n    var sType = getStorageType(s)\r\n    if (sType) {\r\n      if (typeof sType.get === 'function') {\r\n        var val = sType.get(s)\r\n        var key = getStorageTypeKey(s)\r\n        if (settingDefaults[s] !== undefined && val === settingDefaults[s]) {\r\n          \/\/ Setting is the same as default -- remove from storage \/ don't store\r\n          if (DEBUG) console.log('Clearing saved setting', s, val)\r\n          if (key) teaseStorage.removeItem(key)\r\n        } else {\r\n          \/\/ Store setting value\r\n          if (DEBUG) console.log('Saving saved setting', s, val)\r\n          if (key) {\r\n            if (val !== undefined) {\r\n              teaseStorage.setItem(key, val)\r\n            } else {\r\n              console.error(\r\n                'Setting \"' +\r\n                  s +\r\n                  '\" references undefined value.  Unable to save.'\r\n              )\r\n            }\r\n          } else {\r\n            console.error('Unable to get storage key for', s)\r\n          }\r\n        }\r\n      }\r\n    }\r\n  })\r\n  game.initGameSettings()\r\n}\r\n\r\n\r\n\/**\r\n * Load settings from TeaseStorage\r\n *\/\r\nfunction loadSettings() {\r\n  if (DEBUG) console.warn('Loading saved settings')\r\n  Object.keys(gameSettingStore).forEach(function(s) {\r\n    var sType = getStorageType(s)\r\n    if (sType) {\r\n      var key = getStorageTypeKey(s)\r\n      var val = key && teaseStorage.getItem(key)\r\n      if (typeof sType.valueFilter === 'function') {\r\n        val = sType.valueFilter(s, val)\r\n      }\r\n      if (typeof sType.get === 'function' && settingDefaults[s] === undefined) {\r\n        settingDefaults[s] = sType.get(s) \/\/ Create list of default values before we change load from storage\r\n      }\r\n      if (val !== undefined && typeof sType.set === 'function') {\r\n        if (DEBUG) console.log('Loading saved setting', s, val)\r\n        sType.set(s, val, true)\r\n      }\r\n      if (typeof sType.afterLoad === 'function') {\r\n        sType.afterLoad(s, val)\r\n      }\r\n    }\r\n  })\r\n  if (DEBUG) console.log('Default settings:', settingDefaults)\r\n  \/\/ re-save to clear any previously stored defaults\r\n  saveSettings()\r\n  game.updateDynamicValues()\r\n}\r\n\r\n\/**\r\n * Reset setting to default values\r\n *\/\r\nfunction resetSettings(chk) {\r\n  if (DEBUG) console.log('Resetting to defaults:', settingDefaults, chk)\r\n  for (var s in settingDefaults) {\r\n    if (chk && !chk[s]) continue\r\n    var sType = getStorageType(s)\r\n    if (\r\n      sType &&\r\n      settingDefaults[s] !== undefined &&\r\n      typeof sType.set === 'function'\r\n    ) {\r\n      sType.set(s, settingDefaults[s], !chk)\r\n    }\r\n  }\r\n  saveSettings()\r\n  game.resetModeArrays()\r\n  game.updateDynamicValues()\r\n}\r\n\r\n\/**\r\n * Returns true if player has modified settings from default.\r\n *\/\r\nfunction hasChangedSettings(chk) {\r\n  var keys = Object.keys(settingDefaults)\r\n  for (var i = 0, l = keys.length; i < l; i++) {\r\n    var s = keys[i]\r\n    if (chk && !chk[s]) continue\r\n    var sType = getStorageType(s)\r\n    if (!sType || typeof sType.get !== 'function') continue\r\n    if (\r\n      sType &&\r\n      settingDefaults[s] !== undefined &&\r\n      sType.get(s) !== settingDefaults[s]\r\n    ) {\r\n      if (DEBUG)\r\n        console.log('Setting not default', s, sType.get(s), settingDefaults[s])\r\n      return true\r\n    }\r\n  }\r\n  return false\r\n}\r\n\r\n\/* Hook pages.goto *\/\r\npages._gotoOrig = pages.goto\r\npages.goto = function(pid) {\r\n  if (DEBUG) console.log('Going to page:', pid)\r\n  var currentPage = pages.getCurrentPageId();\r\n  if (game.isSettingsPage(currentPage)) {\r\n    var cps = currentPageSetting(currentPage)\r\n    if (cps) {\r\n      var onExit = cps.onExit\r\n      if (typeof onExit === 'function') {\r\n        onExit()\r\n      }\r\n    }\r\n  }\r\n  if (game.isSettingsPage(pid)) {\r\n    \/\/ Check if we need a settiings image page:\r\n    var imagePath = game.settingsImagePage(pid)\r\n    if (imagePath && game.image !== imagePath) {\r\n      if (DEBUG) console.log('Loading settings image', imagePath)\r\n      game.image = imagePath\r\n      callPage(imagePath, null, pid)\r\n      return\r\n    }\r\n    \/\/ Eos seems to need any variables used in choice button label evals\r\n    \/\/ set before the goto.page('...') is called. (Probably pre-renders the buttons.  Ugh.)\r\n    \/\/ To work-around this, we'll set the _ss var for button names for settings pages\r\n    \/\/ just before we call them.\r\n    \/\/ (If Eos handled evals in choice action labels better, this wouldn't be needed.)\r\n    _ss = currentPageSettings(pid)\r\n    var pageSetting = currentPageSetting(pid)\r\n    if (pageSetting) {\r\n      if (pid !== currentPage) {\r\n        \/\/ Just entering settings page\r\n        var prompt = pageSetting.prompt  \r\n        if (prompt && !game.settingMessage) {\r\n          if (typeof prompt === 'function') {\r\n            prompt = prompt(pageSetting)\r\n          }\r\n          if (prompt) game.settingMessage = prompt\r\n        }\r\n      }\r\n      var preloadCheck = pageSetting.preloadCheck\r\n      if (typeof preloadCheck === 'function') {\r\n        if(preloadCheck(pid)) return\r\n      }\r\n      \/\/ Make sure correct sounds are loaded\r\n      if (game.loadSounds(pid)) {\r\n        return\r\n      }\r\n      var onEnter = pageSetting.onEnter\r\n      if (typeof onEnter === 'function') {\r\n        onEnter()\r\n      }\r\n    }\r\n  }\r\n  return pages._gotoOrig(pid)\r\n}\r\n\r\n\/* simple deepmerge *\/\r\nfunction deepmerge(target, source) {\r\n  if (\r\n    !target ||\r\n    !source ||\r\n    typeof target !== 'object' ||\r\n    typeof source !== 'object'\r\n  )\r\n    return source\r\n  for (var prop in source) {\r\n    if (!source.hasOwnProperty(prop)) continue\r\n    var sourceVal = source[prop]\r\n    if (prop in target) {\r\n      if (\r\n        typeof target[prop] !== 'object' ||\r\n        typeof sourceVal !== 'object' ||\r\n        Array.isArray(sourceVal)\r\n      ) {\r\n        target[prop] = sourceVal\r\n      } else {\r\n        target[prop] = deepmerge(target[prop], sourceVal)\r\n      }\r\n    } else {\r\n      target[prop] = sourceVal\r\n    }\r\n  }\r\n  return target\r\n}\r\n\r\n\/* simple add to object *\/\r\nfunction addToObject(obj, key, value, index) {\r\n  if (typeof index === 'string') {\r\n    var sindex = index\r\n    index = Object.keys(obj).indexOf(sindex)\r\n    if (index < 0) {\r\n      console.error(\r\n        'Unable to find ' + sindex + ' in ',\r\n        obj,\r\n        'Will append instead.',\r\n        value\r\n      )\r\n    }\r\n  }\r\n\r\n  \/\/ Create a temp object and index variable\r\n  var temp = {}\r\n  var i = 0\r\n\r\n  \/\/ Loop through the original object\r\n  for (var prop in obj) {\r\n    if (obj.hasOwnProperty(prop)) {\r\n      \/\/ If the indexes match, add the new item\r\n      if (i === index && key) {\r\n        temp[key] = value\r\n        key = null\r\n      }\r\n\r\n      \/\/ Add the current item in the loop to the temp obj\r\n      if (prop !== key) temp[prop] = obj[prop]\r\n\r\n      \/\/ Increase the count\r\n      i++\r\n    }\r\n  }\r\n\r\n  \/\/ Add to end if we didn't add already\r\n  if (key) {\r\n    temp[key] = value\r\n  }\r\n\r\n  return temp\r\n}\r\n","editor":{"recentImages":[{"type":"gallery","mimeType":"image\/jpeg","galleryId":"eba2f303-dd02-4b9e-923a-8b7d9632a505","url":"gallery:eba2f303-dd02-4b9e-923a-8b7d9632a505\/990430","imageId":990430},{"type":"gallery","mimeType":"image\/jpeg","galleryId":"ce6e3374-f241-4b94-8e74-877d319f3613","url":"gallery:ce6e3374-f241-4b94-8e74-877d319f3613\/991174","imageId":991174},{"type":"gallery","mimeType":"image\/jpeg","galleryId":"099cb8f1-074c-4282-a6aa-ab2cb0427a9c","url":"gallery:099cb8f1-074c-4282-a6aa-ab2cb0427a9c\/990495","imageId":990495},{"type":"gallery","mimeType":"image\/jpeg","galleryId":"3623f70d-758d-4918-a148-31d28a8d65dd","url":"gallery:3623f70d-758d-4918-a148-31d28a8d65dd\/1005430","imageId":1005430},{"type":"gallery","mimeType":"image\/jpeg","galleryId":"9ec8abe7-ce8e-433b-a18d-198f8af3e6a1","url":"gallery:9ec8abe7-ce8e-433b-a18d-198f8af3e6a1\/*"},{"type":"gallery","mimeType":"image\/jpeg","galleryId":"a6068f8e-6608-437f-aefb-a94f5ee782e9","url":"gallery:a6068f8e-6608-437f-aefb-a94f5ee782e9\/990458","imageId":990458},{"type":"gallery","mimeType":"image\/jpeg","galleryId":"a0b1e3c8-a627-4b9c-8f78-65d0ff26bc55","url":"gallery:a0b1e3c8-a627-4b9c-8f78-65d0ff26bc55\/990243","imageId":990243},{"type":"gallery","mimeType":"image\/jpeg","galleryId":"f6d79ef6-da98-4c27-804d-e558f0b5fdf5","url":"gallery:f6d79ef6-da98-4c27-804d-e558f0b5fdf5\/991423","imageId":991423},{"type":"gallery","mimeType":"image\/jpeg","galleryId":"e7662537-f8cd-4c15-b2d4-9388178d7b7c","url":"gallery:e7662537-f8cd-4c15-b2d4-9388178d7b7c\/991229","imageId":991229},{"type":"gallery","mimeType":"image\/jpeg","galleryId":"3e001079-2e7f-4121-b89e-897379fc6f3c","url":"gallery:3e001079-2e7f-4121-b89e-897379fc6f3c\/991108","imageId":991108}]},"modules":{"audio":{},"storage":{},"notification":{}},"files":{"moan-1.mp3":{"id":1257208,"hash":"e7eab17116948f350047513ffe164fd26855c58e","size":25982,"type":"audio\/mpeg"},"moan-2.mp3":{"id":1257209,"hash":"34d937804aa6478432f2a6db6f542fa8d5997945","size":35990,"type":"audio\/mpeg"},"moan-3.mp3":{"id":1257210,"hash":"b090ba9148c1b982ae8ff6aa94b7d663c3d5922e","size":20561,"type":"audio\/mpeg"},"moan-4.mp3":{"id":1257211,"hash":"3cb8ac03503cff04dd8999400d34ae68cdf80e52","size":19727,"type":"audio\/mpeg"},"moan-5.mp3":{"id":1257212,"hash":"5160295e9f2c2d718d59bd118920525c671fab87","size":14562,"type":"audio\/mpeg"},"moan-6.mp3":{"id":1257213,"hash":"a247f35c0ff656682f5bd703601420bad7b2e68d","size":23480,"type":"audio\/mpeg"},"blank.jpg":{"id":1283357,"hash":"4158096e9abc6ccca0df124a4114ea3baababc74","size":799,"type":"image\/jpeg","width":71,"height":49},"1-minute-of-silence.mp3":{"id":1361367,"hash":"1092af7de1d0a7b87c79797d0adb47c8bdf1f91a","size":96246,"type":"audio\/mpeg"},"click.mp3":{"id":1361375,"hash":"74069beac7a86676813fd01c8b5ee016a8d244a6","size":2304,"type":"audio\/mpeg"},"beat-drum1.mp3":{"id":1366337,"hash":"5915e22586cfe3ed5575064ad428672ef633d230","size":8881,"type":"audio\/mpeg"},"beat-tone.mp3":{"id":1397614,"hash":"bb51bdf1e325eda43ba95d357a01f80af3aa3a33","size":2924,"type":"audio\/mpeg"},"beat-wood-block.mp3":{"id":1366336,"hash":"16545f325d4cc813c4a1f61518158c9f4cf0fbcf","size":2506,"type":"audio\/mpeg"},"beat-drum2.mp3":{"id":1397669,"hash":"539b5b60509deb29a322d14e9fe40f01fa7424e5","size":4978,"type":"audio\/mpeg"},"beat-pop-alt2-a.mp3":{"id":1452077,"hash":"ea91c60c0b7b9ca21ef14637348ae52219420018","size":2089,"type":"audio\/mpeg"},"beat-pop-alt2-b.mp3":{"id":1452078,"hash":"10b91c7bdd88a9218d4656883c85f03f5d9c4cbc","size":2089,"type":"audio\/mpeg"}}}