Index: frontend/node_modules/thunky/.travis.yml
===================================================================
--- frontend/node_modules/thunky/.travis.yml	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/thunky/.travis.yml	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,6 @@
+language: node_js
+node_js:
+  - '0.10'
+  - '0.12'
+  - '4.0'
+  - '6.0'
Index: frontend/node_modules/thunky/LICENSE
===================================================================
--- frontend/node_modules/thunky/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/thunky/LICENSE	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Mathias Buus
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
Index: frontend/node_modules/thunky/README.md
===================================================================
--- frontend/node_modules/thunky/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/thunky/README.md	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,97 @@
+# thunky
+
+Delay the evaluation of a paramless async function and cache the result (see [thunk](http://en.wikipedia.org/wiki/Thunk_%28functional_programming%29)).
+
+```
+npm install thunky
+```
+
+[![build status](http://img.shields.io/travis/mafintosh/thunky.svg?style=flat)](http://travis-ci.org/mafintosh/thunky)
+
+## Example
+
+Let's make a simple function that returns a random number 1 second after it is called for the first time
+
+``` js
+var thunky = require('thunky')
+
+var test = thunky(function (callback) { // the inner function should only accept a callback
+  console.log('waiting 1s and returning random number')
+  setTimeout(function () {
+    callback(Math.random())
+  }, 1000)
+})
+
+test(function (num) {  // inner function is called the first time we call test
+  console.log(num) // prints random number
+})
+
+test(function (num) {  // subsequent calls waits for the first call to finish and return the same value
+  console.log(num) // prints the same random number as above
+})
+```
+
+## Lazy evaluation
+
+Thunky makes it easy to implement a lazy evaluation pattern.
+
+``` js
+var getDb = thunky(function (callback) {
+  db.open(myConnectionString, callback)
+})
+
+var queryDb = function (query, callback) {
+  getDb(function (err, db) {
+    if (err) return callback(err)
+    db.query(query, callback)
+  })
+}
+
+queryDb('some query', function (err, result) { ... } )
+
+queryDb('some other query', function (err, result) { ... } )
+```
+
+The first time `getDb` is called it will try do open a connection to the database.
+Any subsequent calls will just wait for the first call to complete and then call your callback.
+
+A nice property of this pattern is that it *easily* allows us to pass any error caused by `getDb` to the `queryDb` callback.
+
+## Error → No caching
+
+If the thunk callback is called with an `Error` object as the first argument it will not cache the result
+
+``` js
+var fails = thunky(function (callback) {
+  console.log('returning an error')
+  callback(new Error('bad stuff'))
+})
+
+fails(function (err) { // inner function is called
+  console.log(err)
+});
+
+fails(function (err) { // inner function is called again as it returned an error before
+  console.log(err)
+})
+```
+
+## Promise version
+
+A promise version is available as well
+
+``` js
+var thunkyp = require('thunky/promise')
+
+var ready = thunkyp(async function () {
+  // ... do async stuff
+  return 42
+})
+
+// same semantics as the callback version
+await ready()
+```
+
+## License
+
+MIT
Index: frontend/node_modules/thunky/index.js
===================================================================
--- frontend/node_modules/thunky/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/thunky/index.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,55 @@
+'use strict'
+
+var nextTick = nextTickArgs
+process.nextTick(upgrade, 42) // pass 42 and see if upgrade is called with it
+
+module.exports = thunky
+
+function thunky (fn) {
+  var state = run
+  return thunk
+
+  function thunk (callback) {
+    state(callback || noop)
+  }
+
+  function run (callback) {
+    var stack = [callback]
+    state = wait
+    fn(done)
+
+    function wait (callback) {
+      stack.push(callback)
+    }
+
+    function done (err) {
+      var args = arguments
+      state = isError(err) ? run : finished
+      while (stack.length) finished(stack.shift())
+
+      function finished (callback) {
+        nextTick(apply, callback, args)
+      }
+    }
+  }
+}
+
+function isError (err) { // inlined from util so this works in the browser
+  return Object.prototype.toString.call(err) === '[object Error]'
+}
+
+function noop () {}
+
+function apply (callback, args) {
+  callback.apply(null, args)
+}
+
+function upgrade (val) {
+  if (val === 42) nextTick = process.nextTick
+}
+
+function nextTickArgs (fn, a, b) {
+  process.nextTick(function () {
+    fn(a, b)
+  })
+}
Index: frontend/node_modules/thunky/package.json
===================================================================
--- frontend/node_modules/thunky/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/thunky/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,32 @@
+{
+  "name": "thunky",
+  "version": "1.1.0",
+  "description": "delay the evaluation of a paramless async function and cache the result",
+  "main": "index.js",
+  "devDependencies": {
+    "standard": "^12.0.1",
+    "tape": "^4.9.1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/mafintosh/thunky.git"
+  },
+  "scripts": {
+    "test": "standard && tape test.js"
+  },
+  "keywords": [
+    "memo",
+    "thunk",
+    "async",
+    "lazy",
+    "control",
+    "flow",
+    "cache"
+  ],
+  "author": "Mathias Buus Madsen <mathiasbuus@gmail.com>",
+  "bugs": {
+    "url": "https://github.com/mafintosh/thunky/issues"
+  },
+  "homepage": "https://github.com/mafintosh/thunky#readme",
+  "license": "MIT"
+}
Index: frontend/node_modules/thunky/promise.js
===================================================================
--- frontend/node_modules/thunky/promise.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/thunky/promise.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,20 @@
+module.exports = thunkyp
+
+function thunkyp (fn) {
+  let running = null
+
+  return ready
+
+  function ready () {
+    if (running) return running
+    const p = fn()
+    if (!(p instanceof Promise)) running = Promise.resolve(p)
+    else running = p
+    running.catch(onerror)
+    return running
+  }
+
+  function onerror () {
+    running = null
+  }
+}
Index: frontend/node_modules/thunky/test.js
===================================================================
--- frontend/node_modules/thunky/test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/thunky/test.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,122 @@
+var tape = require('tape')
+var thunky = require('./')
+
+tape('run only once', function (t) {
+  t.plan(3)
+
+  var ran = 0
+  var run = thunky(function (cb) {
+    ran++
+    cb()
+  })
+
+  run(function () {
+    t.same(ran, 1, 'ran once')
+  })
+  run(function () {
+    t.same(ran, 1, 'ran once')
+  })
+  run(function () {
+    t.same(ran, 1, 'ran once')
+  })
+})
+
+tape('run only once async', function (t) {
+  t.plan(3)
+
+  var ran = 0
+  var run = thunky(function (cb) {
+    process.nextTick(function () {
+      ran++
+      cb()
+    })
+  })
+
+  run(function () {
+    t.same(ran, 1, 'ran once')
+  })
+  run(function () {
+    t.same(ran, 1, 'ran once')
+  })
+  run(function () {
+    t.same(ran, 1, 'ran once')
+  })
+})
+
+tape('re-run on error', function (t) {
+  t.plan(3)
+
+  var ran = 0
+  var run = thunky(function (cb) {
+    ran++
+    cb(new Error('stop'))
+  })
+
+  run(function () {
+    t.same(ran, 1, 'ran once')
+    run(function () {
+      t.same(ran, 2, 'ran once')
+      run(function () {
+        t.same(ran, 3, 'ran once')
+      })
+    })
+  })
+})
+
+tape('pass arguments', function (t) {
+  t.plan(6)
+
+  var ran = 0
+  var run = thunky(function (fn) {
+    ran++
+    fn({ hello: 'world' })
+  })
+
+  run(function (val) {
+    t.same(ran, 1, 'ran once')
+    t.same(val, { hello: 'world' })
+    run(function (val) {
+      t.same(ran, 1, 'ran once')
+      t.same(val, { hello: 'world' })
+      run(function (val) {
+        t.same(ran, 1, 'ran once')
+        t.same(val, { hello: 'world' })
+      })
+    })
+  })
+})
+
+tape('callback is optional', function (t) {
+  t.plan(2)
+
+  var ran = 0
+  var run = thunky(function (fn) {
+    ran++
+    fn({ hello: 'world' })
+  })
+
+  run()
+  run(function (val) {
+    t.same(ran, 1, 'ran once')
+    t.same(val, { hello: 'world' })
+  })
+})
+
+tape('always async', function (t) {
+  t.plan(2)
+
+  var run = thunky(function (cb) {
+    process.nextTick(cb)
+  })
+
+  var sync = true
+  run(function () {
+    t.ok(!sync, 'not sync')
+    var innerSync = true
+    run(function () {
+      t.ok(!innerSync, 'not sync')
+    })
+    innerSync = false
+  })
+  sync = false
+})
