diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 48e341a0954d5f8c2accf3a6731be28e5bb9c0de..0000000000000000000000000000000000000000
--- a/package-lock.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "lockfileVersion": 1
-}
diff --git a/pinsisApp/src/app/data-api.service.ts b/pinsisApp/src/app/data-api.service.ts
index cfe20a150eebea9fe04aff98d63e9d7db84e5ea7..3610292a617492512f5a85a8010a9c251b451186 100644
--- a/pinsisApp/src/app/data-api.service.ts
+++ b/pinsisApp/src/app/data-api.service.ts
@@ -1,5 +1,5 @@
 // This file is part of the project Pinsis-Portal.
-//  Copyright (C),2018, by C3SL(Centro de Computação Científica e 
+//  Copyright (C),2018, by C3SL(Centro de Computação Científica e
 //  Software Live)
 
 //  This program is free software: you can redistribute it and/or modify
@@ -26,7 +26,7 @@ declare var da: any;
 
 @Injectable()
 export class DataApiService {
-    
+
     //Agent
     public getAgentById(id,agents){
         var hospital = null;
@@ -37,7 +37,7 @@ export class DataApiService {
         }
         return hospital;
     }
-    
+
     public loadAgents(callback, countie = null){
         var url = environment.webserviceUrl+"/api/data/listAgents";
         if(countie)
@@ -47,30 +47,30 @@ export class DataApiService {
         });
     }
     //
-    
-    
+
+
     //Uses
-    
-    
-    
+
+
+
     /*
     config format:
     {
-        "type": string 
+        "type": string
         "y1": int, "y2": int, "m1": int,
         "m2": int, "d1": int, "d2": int
     }
     type field must be 'day' or 'month' and its default value is 'day'
-    
-    
+
+
     1 and 2 represents the intervale between dates (from 1 to 2)
     d = day; m = month; y = year;
-    
+
     To use day, its necessary set month, and to use month its
     necessary to use year
     If this fields are invalid or omited, all entries will be returned
     */
-    
+
     public loadData(callback, config){
         var type = "agentusesday";
 
@@ -80,40 +80,40 @@ export class DataApiService {
         });
     }
     //
-    
-    
-    
+
+
+
     //Geolocation
     private cacheStates = null;
     public loadStates(callback){
         var da = this;
-        
+
         if(da.cacheStates != null){
             callback(this.cacheStates);
             return;
         }
-        
+
         $.getJSON(environment.webserviceUrl+"/geolocation/states.json", function(result){
             var features = result.states;
             da.cacheStates = features;
             callback(features);
         });
     }
-    
+
     public selectCountiesFromState(state, callback){
         $.getJSON(environment.webserviceUrl+"/geolocation/"+state+"-cities.json",function(result){
             var features = result.counties;
             callback(features);
         });
     }
-    
+
     public selectStateFeature(state, callback){
         $.getJSON(environment.webserviceUrl+"/geolocation/"+state+".json",function(x){
             callback(x);
         });
     }
     //
-  
+
 
     constructor() { }
 
diff --git a/server/models/database.js b/server/models/database.js
new file mode 100644
index 0000000000000000000000000000000000000000..e61214e271de2fcb77ddd7237b265162736b1390
--- /dev/null
+++ b/server/models/database.js
@@ -0,0 +1,31 @@
+const pg = require('pg');
+var pgtools = require('pgtools');
+
+
+pgtools.createdb({
+user: 'postgres',
+host: '127.0.0.1',
+password: '123',
+port: '5432'},
+'machines', function (err, res) {
+  if (err) {
+    console.error(err);
+    process.exit(-1);
+  }
+  console.log(res);
+}
+
+);
+
+// pool.query("CREATE TABLE machine(numeroSerie SERIAL PRIMARY KEY )", (err, res) => {
+// console.log(err, res);
+// pool.end();
+// });
+
+// , localizacao point NOT NULL,
+// ala VARCHAR(40) NOT NULL, estado VARCHAR(40), manutencao DATE
+
+// pool.query("SELECT PacienteRegistro FROM Paciente", (err, res) => {
+// console.log(err, res);
+// pool.end();
+// });
diff --git a/server/models/user.js b/server/models/user.js
index 3f087e95ba47d5fad8eac69c476ad08f0fa52708..a0d5ef1f1d4886b099cfe2ca329509668678f148 100644
--- a/server/models/user.js
+++ b/server/models/user.js
@@ -3,7 +3,7 @@ var bcrypt = require('bcrypt');
 
 const Schema = mongoose.Schema;
 const userSchema = new Schema({
-    email: String,
+    email: {type:String, unique: true},
     password: String,
 
 });
diff --git a/server/node_modules/.bin/createdbjs b/server/node_modules/.bin/createdbjs
new file mode 120000
index 0000000000000000000000000000000000000000..48a5d3fd0f7f46c6fb1471495e9d8bac916b2311
--- /dev/null
+++ b/server/node_modules/.bin/createdbjs
@@ -0,0 +1 @@
+../pgtools/createdb.js
\ No newline at end of file
diff --git a/server/node_modules/.bin/dropdbjs b/server/node_modules/.bin/dropdbjs
new file mode 120000
index 0000000000000000000000000000000000000000..bfc03195caaa29599f571bb4cd7c497634fe4440
--- /dev/null
+++ b/server/node_modules/.bin/dropdbjs
@@ -0,0 +1 @@
+../pgtools/dropdb.js
\ No newline at end of file
diff --git a/server/node_modules/.bin/window-size b/server/node_modules/.bin/window-size
new file mode 120000
index 0000000000000000000000000000000000000000..e84c8ece5967a2a8ab7744981263af8a74044aa5
--- /dev/null
+++ b/server/node_modules/.bin/window-size
@@ -0,0 +1 @@
+../window-size/cli.js
\ No newline at end of file
diff --git a/server/node_modules/buffer-writer/.travis.yml b/server/node_modules/buffer-writer/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8e59bb395072feedc4e63ee8d86250fa389ad427
--- /dev/null
+++ b/server/node_modules/buffer-writer/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+  - 4
+  - 6
+  - 8
+  - 10
+  - 11
diff --git a/server/node_modules/buffer-writer/LICENSE b/server/node_modules/buffer-writer/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..72dc60d84b692387206266939bc34656bcba1e15
--- /dev/null
+++ b/server/node_modules/buffer-writer/LICENSE
@@ -0,0 +1,19 @@
+The MIT License (MIT)
+
+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.
diff --git a/server/node_modules/buffer-writer/README.md b/server/node_modules/buffer-writer/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..81eccc0588eae24237b14657de8e9ada80818e7e
--- /dev/null
+++ b/server/node_modules/buffer-writer/README.md
@@ -0,0 +1,48 @@
+# buffer-writer
+
+[![Build Status](https://secure.travis-ci.org/brianc/node-buffer-writer.png?branch=master)](http://travis-ci.org/brianc/node-buffer-writer)
+
+Fast & efficient buffer writer used to keep memory usage low by internally recycling a single large buffer.
+
+Used as the binary protocol writer in [node-postgres](https://github.com/brianc/node-postgres)
+
+Since postgres requires big endian encoding, this only writes big endian numbers for now, but can & probably will easily be extended to write little endian as well.
+
+I'll admit this has a few postgres specific things I might need to take out in the future, such as `addHeader`
+
+## api
+
+`var writer = new (require('buffer-writer')());`
+
+### writer.addInt32(num)
+
+Writes a 4-byte big endian binary encoded number to the end of the buffer.
+
+### writer.addInt16(num)
+
+Writes a 2-byte big endian binary encoded number to the end of the buffer.
+
+### writer.addCString(string)
+
+Writes a string to the buffer `utf8` encoded and adds a null character (`\0`) at the end.
+
+### var buffer = writer.addHeader(char)
+
+Writes the 5 byte PostgreSQL required header to the beginning of the buffer. (1 byte for character, 1 BE Int32 for length of the buffer)
+
+### var buffer = writer.join()
+
+Collects all data in the writer and joins it into a single, new buffer.
+
+### var buffer = writer.flush(char)
+
+Writes the 5 byte postgres required message header, collects all data in the writer and joins it into a single, new buffer, and then resets the writer.
+
+## thoughts
+
+This is kind of node-postgres specific.  If you're interested in using this for a more general purpose thing, lemme know.
+I would love to work with you on getting this more reusable for your needs.
+
+## license
+
+MIT
diff --git a/server/node_modules/buffer-writer/index.js b/server/node_modules/buffer-writer/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..f3c119e0255c22a551d10246bcc3d6b7c4d22b00
--- /dev/null
+++ b/server/node_modules/buffer-writer/index.js
@@ -0,0 +1,129 @@
+//binary data writer tuned for creating
+//postgres message packets as effeciently as possible by reusing the
+//same buffer to avoid memcpy and limit memory allocations
+var Writer = module.exports = function (size) {
+  this.size = size || 1024;
+  this.buffer = Buffer.alloc(this.size + 5);
+  this.offset = 5;
+  this.headerPosition = 0;
+};
+
+//resizes internal buffer if not enough size left
+Writer.prototype._ensure = function (size) {
+  var remaining = this.buffer.length - this.offset;
+  if (remaining < size) {
+    var oldBuffer = this.buffer;
+    // exponential growth factor of around ~ 1.5
+    // https://stackoverflow.com/questions/2269063/buffer-growth-strategy
+    var newSize = oldBuffer.length + (oldBuffer.length >> 1) + size;
+    this.buffer = Buffer.alloc(newSize);
+    oldBuffer.copy(this.buffer);
+  }
+};
+
+Writer.prototype.addInt32 = function (num) {
+  this._ensure(4);
+  this.buffer[this.offset++] = (num >>> 24 & 0xFF);
+  this.buffer[this.offset++] = (num >>> 16 & 0xFF);
+  this.buffer[this.offset++] = (num >>> 8 & 0xFF);
+  this.buffer[this.offset++] = (num >>> 0 & 0xFF);
+  return this;
+};
+
+Writer.prototype.addInt16 = function (num) {
+  this._ensure(2);
+  this.buffer[this.offset++] = (num >>> 8 & 0xFF);
+  this.buffer[this.offset++] = (num >>> 0 & 0xFF);
+  return this;
+};
+
+//for versions of node requiring 'length' as 3rd argument to buffer.write
+var writeString = function (buffer, string, offset, len) {
+  buffer.write(string, offset, len);
+};
+
+//overwrite function for older versions of node
+if (Buffer.prototype.write.length === 3) {
+  writeString = function (buffer, string, offset, len) {
+    buffer.write(string, offset);
+  };
+}
+
+Writer.prototype.addCString = function (string) {
+  //just write a 0 for empty or null strings
+  if (!string) {
+    this._ensure(1);
+  } else {
+    var len = Buffer.byteLength(string);
+    this._ensure(len + 1); //+1 for null terminator
+    writeString(this.buffer, string, this.offset, len);
+    this.offset += len;
+  }
+
+  this.buffer[this.offset++] = 0; // null terminator
+  return this;
+};
+
+Writer.prototype.addChar = function (c) {
+  this._ensure(1);
+  writeString(this.buffer, c, this.offset, 1);
+  this.offset++;
+  return this;
+};
+
+Writer.prototype.addString = function (string) {
+  string = string || "";
+  var len = Buffer.byteLength(string);
+  this._ensure(len);
+  this.buffer.write(string, this.offset);
+  this.offset += len;
+  return this;
+};
+
+Writer.prototype.getByteLength = function () {
+  return this.offset - 5;
+};
+
+Writer.prototype.add = function (otherBuffer) {
+  this._ensure(otherBuffer.length);
+  otherBuffer.copy(this.buffer, this.offset);
+  this.offset += otherBuffer.length;
+  return this;
+};
+
+Writer.prototype.clear = function () {
+  this.offset = 5;
+  this.headerPosition = 0;
+  this.lastEnd = 0;
+};
+
+//appends a header block to all the written data since the last
+//subsequent header or to the beginning if there is only one data block
+Writer.prototype.addHeader = function (code, last) {
+  var origOffset = this.offset;
+  this.offset = this.headerPosition;
+  this.buffer[this.offset++] = code;
+  //length is everything in this packet minus the code
+  this.addInt32(origOffset - (this.headerPosition + 1));
+  //set next header position
+  this.headerPosition = origOffset;
+  //make space for next header
+  this.offset = origOffset;
+  if (!last) {
+    this._ensure(5);
+    this.offset += 5;
+  }
+};
+
+Writer.prototype.join = function (code) {
+  if (code) {
+    this.addHeader(code, true);
+  }
+  return this.buffer.slice(code ? 0 : 5, this.offset);
+};
+
+Writer.prototype.flush = function (code) {
+  var result = this.join(code);
+  this.clear();
+  return result;
+};
diff --git a/server/node_modules/buffer-writer/package.json b/server/node_modules/buffer-writer/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..e95ab47c4da68dcfd964c48e222c7b27b19c58a9
--- /dev/null
+++ b/server/node_modules/buffer-writer/package.json
@@ -0,0 +1,57 @@
+{
+  "_from": "buffer-writer@2.0.0",
+  "_id": "buffer-writer@2.0.0",
+  "_inBundle": false,
+  "_integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==",
+  "_location": "/buffer-writer",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "buffer-writer@2.0.0",
+    "name": "buffer-writer",
+    "escapedName": "buffer-writer",
+    "rawSpec": "2.0.0",
+    "saveSpec": null,
+    "fetchSpec": "2.0.0"
+  },
+  "_requiredBy": [
+    "/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
+  "_shasum": "ce7eb81a38f7829db09c873f2fbb792c0c98ec04",
+  "_spec": "buffer-writer@2.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg",
+  "author": {
+    "name": "Brian M. Carlson"
+  },
+  "bugs": {
+    "url": "https://github.com/brianc/node-buffer-writer/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "a fast, efficient buffer writer",
+  "devDependencies": {
+    "mocha": "5.2.0"
+  },
+  "engines": {
+    "node": ">=4"
+  },
+  "homepage": "https://github.com/brianc/node-buffer-writer#readme",
+  "keywords": [
+    "buffer",
+    "writer",
+    "builder"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "buffer-writer",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianc/node-buffer-writer.git"
+  },
+  "scripts": {
+    "test": "mocha --throw-deprecation"
+  },
+  "version": "2.0.0"
+}
diff --git a/server/node_modules/buffer-writer/test/mocha.opts b/server/node_modules/buffer-writer/test/mocha.opts
new file mode 100644
index 0000000000000000000000000000000000000000..5efaf24d77060047c39188760c36970e10af6f3d
--- /dev/null
+++ b/server/node_modules/buffer-writer/test/mocha.opts
@@ -0,0 +1 @@
+--ui tdd
diff --git a/server/node_modules/buffer-writer/test/writer-tests.js b/server/node_modules/buffer-writer/test/writer-tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..ded91c8608da2bb8f9ce6673fe67e2441cc82a5f
--- /dev/null
+++ b/server/node_modules/buffer-writer/test/writer-tests.js
@@ -0,0 +1,218 @@
+var Writer = require(__dirname + "/../");
+
+var assert = require('assert');
+var util = require('util');
+
+assert.equalBuffers = function (actual, expected) {
+  var spit = function (actual, expected) {
+    console.log("");
+    console.log("actual " + util.inspect(actual));
+    console.log("expect " + util.inspect(expected));
+    console.log("");
+  };
+  if (actual.length != expected.length) {
+    spit(actual, expected);
+    assert.strictEqual(actual.length, expected.length);
+  }
+  for (var i = 0; i < actual.length; i++) {
+    if (actual[i] != expected[i]) {
+      spit(actual, expected);
+    }
+    assert.strictEqual(actual[i], expected[i]);
+  }
+};
+
+suite('adding int32', function () {
+  var testAddingInt32 = function (int, expectedBuffer) {
+    test('writes ' + int, function () {
+      var subject = new Writer();
+      var result = subject.addInt32(int).join();
+      assert.equalBuffers(result, expectedBuffer);
+    });
+  };
+
+  testAddingInt32(0, [0, 0, 0, 0]);
+  testAddingInt32(1, [0, 0, 0, 1]);
+  testAddingInt32(256, [0, 0, 1, 0]);
+  test('writes largest int32', function () {
+    //todo need to find largest int32 when I have internet access
+    return false;
+  });
+
+  test('writing multiple int32s', function () {
+    var subject = new Writer();
+    var result = subject.addInt32(1).addInt32(10).addInt32(0).join();
+    assert.equalBuffers(result, [0, 0, 0, 1, 0, 0, 0, 0x0a, 0, 0, 0, 0]);
+  });
+
+  suite('having to resize the buffer', function () {
+    test('after resize correct result returned', function () {
+      var subject = new Writer(10);
+      subject.addInt32(1).addInt32(1).addInt32(1);
+      assert.equalBuffers(subject.join(), [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]);
+    });
+  });
+});
+
+suite('int16', function () {
+  test('writes 0', function () {
+    var subject = new Writer();
+    var result = subject.addInt16(0).join();
+    assert.equalBuffers(result, [0, 0]);
+  });
+
+  test('writes 400', function () {
+    var subject = new Writer();
+    var result = subject.addInt16(400).join();
+    assert.equalBuffers(result, [1, 0x90]);
+  });
+
+  test('writes many', function () {
+    var subject = new Writer();
+    var result = subject.addInt16(0).addInt16(1).addInt16(2).join();
+    assert.equalBuffers(result, [0, 0, 0, 1, 0, 2]);
+  });
+
+  test('resizes if internal buffer fills up', function () {
+    var subject = new Writer(3);
+    var result = subject.addInt16(2).addInt16(3).join();
+    assert.equalBuffers(result, [0, 2, 0, 3]);
+  });
+
+});
+
+suite('cString', function () {
+  test('writes empty cstring', function () {
+    var subject = new Writer();
+    var result = subject.addCString().join();
+    assert.equalBuffers(result, [0]);
+  });
+
+  test('writes two empty cstrings', function () {
+    var subject = new Writer();
+    var result = subject.addCString("").addCString("").join();
+    assert.equalBuffers(result, [0, 0]);
+  });
+
+
+  test('writes non-empty cstring', function () {
+    var subject = new Writer();
+    var result = subject.addCString("!!!").join();
+    assert.equalBuffers(result, [33, 33, 33, 0]);
+  });
+
+  test('resizes if reached end', function () {
+    var subject = new Writer(3);
+    var result = subject.addCString("!!!").join();
+    assert.equalBuffers(result, [33, 33, 33, 0]);
+  });
+
+  test('writes multiple cstrings', function () {
+    var subject = new Writer();
+    var result = subject.addCString("!").addCString("!").join();
+    assert.equalBuffers(result, [33, 0, 33, 0]);
+  });
+
+});
+
+test('writes char', function () {
+  var subject = new Writer(2);
+  var result = subject.addChar('a').addChar('b').addChar('c').join();
+  assert.equalBuffers(result, [0x61, 0x62, 0x63]);
+});
+
+test('gets correct byte length', function () {
+  var subject = new Writer(5);
+  assert.strictEqual(subject.getByteLength(), 0);
+  subject.addInt32(0);
+  assert.strictEqual(subject.getByteLength(), 4);
+  subject.addCString("!");
+  assert.strictEqual(subject.getByteLength(), 6);
+});
+
+test('can add arbitrary buffer to the end', function () {
+  var subject = new Writer(4);
+  subject.addCString("!!!")
+  var result = subject.add(Buffer.from("@@@")).join();
+  assert.equalBuffers(result, [33, 33, 33, 0, 0x40, 0x40, 0x40]);
+});
+
+suite('can write normal string', function () {
+  var subject = new Writer(4);
+  var result = subject.addString("!").join();
+  assert.equalBuffers(result, [33]);
+  test('can write cString too', function () {
+    var result = subject.addCString("!").join();
+    assert.equalBuffers(result, [33, 33, 0]);
+  });
+  test('can resize', function () {
+    var result = subject.addString("!!").join();
+    assert.equalBuffers(result, [33, 33, 0, 33, 33]);
+  });
+});
+
+
+suite('clearing', function () {
+  var subject = new Writer();
+  subject.addCString("@!!#!#");
+  subject.addInt32(10401);
+  test('clears', function () {
+    subject.clear();
+    assert.equalBuffers(subject.join(), []);
+  });
+  test('writing more', function () {
+    var joinedResult = subject.addCString("!").addInt32(9).addInt16(2).join();
+    assert.equalBuffers(joinedResult, [33, 0, 0, 0, 0, 9, 0, 2]);
+  });
+  test('returns result', function () {
+    var flushedResult = subject.flush();
+    assert.equalBuffers(flushedResult, [33, 0, 0, 0, 0, 9, 0, 2])
+  });
+  test('clears the writer', function () {
+    assert.equalBuffers(subject.join(), [])
+    assert.equalBuffers(subject.flush(), [])
+  });
+});
+
+test("resizing to much larger", function () {
+  var subject = new Writer(2);
+  var string = "!!!!!!!!";
+  var result = subject.addCString(string).flush();
+  assert.equalBuffers(result, [33, 33, 33, 33, 33, 33, 33, 33, 0]);
+});
+
+suite("flush", function () {
+  test('added as a hex code to a full writer', function () {
+    var subject = new Writer(2);
+    var result = subject.addCString("!").flush(0x50);
+    assert.equalBuffers(result, [0x50, 0, 0, 0, 6, 33, 0]);
+  });
+
+  test('added as a hex code to a non-full writer', function () {
+    var subject = new Writer(10).addCString("!");
+    var joinedResult = subject.join(0x50);
+    var result = subject.flush(0x50);
+    assert.equalBuffers(result, [0x50, 0, 0, 0, 6, 33, 0]);
+  });
+
+  test('added as a hex code to a buffer which requires resizing', function () {
+    var result = new Writer(2).addCString("!!!!!!!!").flush(0x50);
+    assert.equalBuffers(result, [0x50, 0, 0, 0, 0x0D, 33, 33, 33, 33, 33, 33, 33, 33, 0]);
+  });
+});
+
+suite("header", function () {
+  test('adding two packets with headers', function () {
+    var subject = new Writer(10).addCString("!");
+    subject.addHeader(0x50);
+    subject.addCString("!!");
+    subject.addHeader(0x40);
+    subject.addCString("!");
+    var result = subject.flush(0x10);
+    assert.equalBuffers(result, [0x50, 0, 0, 0, 6, 33, 0, 0x40, 0, 0, 0, 7, 33, 33, 0, 0x10, 0, 0, 0, 6, 33, 0]);
+  });
+});
+
+
+
+
diff --git a/server/node_modules/camelcase/index.js b/server/node_modules/camelcase/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..5670f73f2bbac9b7b063ef656aa22a202eedfcbd
--- /dev/null
+++ b/server/node_modules/camelcase/index.js
@@ -0,0 +1,56 @@
+'use strict';
+
+function preserveCamelCase(str) {
+	var isLastCharLower = false;
+
+	for (var i = 0; i < str.length; i++) {
+		var c = str.charAt(i);
+
+		if (isLastCharLower && (/[a-zA-Z]/).test(c) && c.toUpperCase() === c) {
+			str = str.substr(0, i) + '-' + str.substr(i);
+			isLastCharLower = false;
+			i++;
+		} else {
+			isLastCharLower = (c.toLowerCase() === c);
+		}
+	}
+
+	return str;
+}
+
+module.exports = function () {
+	var str = [].map.call(arguments, function (str) {
+		return str.trim();
+	}).filter(function (str) {
+		return str.length;
+	}).join('-');
+
+	if (!str.length) {
+		return '';
+	}
+
+	if (str.length === 1) {
+		return str.toLowerCase();
+	}
+
+	if (!(/[_.\- ]+/).test(str)) {
+		if (str === str.toUpperCase()) {
+			return str.toLowerCase();
+		}
+
+		if (str[0] !== str[0].toLowerCase()) {
+			return str[0].toLowerCase() + str.slice(1);
+		}
+
+		return str;
+	}
+
+	str = preserveCamelCase(str);
+
+	return str
+	.replace(/^[_.\- ]+/, '')
+	.toLowerCase()
+	.replace(/[_.\- ]+(\w|$)/g, function (m, p1) {
+		return p1.toUpperCase();
+	});
+};
diff --git a/server/node_modules/camelcase/license b/server/node_modules/camelcase/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/camelcase/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/camelcase/package.json b/server/node_modules/camelcase/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..89c0a39c56d81de3f9d760cb4bcf4a767ac5e523
--- /dev/null
+++ b/server/node_modules/camelcase/package.json
@@ -0,0 +1,71 @@
+{
+  "_from": "camelcase@^3.0.0",
+  "_id": "camelcase@3.0.0",
+  "_inBundle": false,
+  "_integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
+  "_location": "/camelcase",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "camelcase@^3.0.0",
+    "name": "camelcase",
+    "escapedName": "camelcase",
+    "rawSpec": "^3.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^3.0.0"
+  },
+  "_requiredBy": [
+    "/yargs-parser"
+  ],
+  "_resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+  "_shasum": "32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a",
+  "_spec": "camelcase@^3.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs-parser",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "http://sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/camelcase/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Convert a dash/dot/underscore/space separated string to camelCase: foo-bar → fooBar",
+  "devDependencies": {
+    "ava": "*",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/camelcase#readme",
+  "keywords": [
+    "camelcase",
+    "camel-case",
+    "camel",
+    "case",
+    "dash",
+    "hyphen",
+    "dot",
+    "underscore",
+    "separator",
+    "string",
+    "text",
+    "convert"
+  ],
+  "license": "MIT",
+  "name": "camelcase",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/camelcase.git"
+  },
+  "scripts": {
+    "test": "xo && ava"
+  },
+  "version": "3.0.0"
+}
diff --git a/server/node_modules/camelcase/readme.md b/server/node_modules/camelcase/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..080b2a10391bc93be0e67eae1ba2deb1305a9035
--- /dev/null
+++ b/server/node_modules/camelcase/readme.md
@@ -0,0 +1,57 @@
+# camelcase [![Build Status](https://travis-ci.org/sindresorhus/camelcase.svg?branch=master)](https://travis-ci.org/sindresorhus/camelcase)
+
+> Convert a dash/dot/underscore/space separated string to camelCase: `foo-bar` → `fooBar`
+
+
+## Install
+
+```
+$ npm install --save camelcase
+```
+
+
+## Usage
+
+```js
+const camelCase = require('camelcase');
+
+camelCase('foo-bar');
+//=> 'fooBar'
+
+camelCase('foo_bar');
+//=> 'fooBar'
+
+camelCase('Foo-Bar');
+//=> 'fooBar'
+
+camelCase('--foo.bar');
+//=> 'fooBar'
+
+camelCase('__foo__bar__');
+//=> 'fooBar'
+
+camelCase('foo bar');
+//=> 'fooBar'
+
+console.log(process.argv[3]);
+//=> '--foo-bar'
+camelCase(process.argv[3]);
+//=> 'fooBar'
+
+camelCase('foo', 'bar');
+//=> 'fooBar'
+
+camelCase('__foo__', '--bar');
+//=> 'fooBar'
+```
+
+
+## Related
+
+- [decamelize](https://github.com/sindresorhus/decamelize) - The inverse of this module
+- [uppercamelcase](https://github.com/SamVerschueren/uppercamelcase) - Like this module, but to PascalCase instead of camelCase
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/cliui/CHANGELOG.md b/server/node_modules/cliui/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..ef6a35ef41e91b84c88ab5d3c26b572d1f302249
--- /dev/null
+++ b/server/node_modules/cliui/CHANGELOG.md
@@ -0,0 +1,15 @@
+# Change Log
+
+All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+<a name="3.2.0"></a>
+# [3.2.0](https://github.com/yargs/cliui/compare/v3.1.2...v3.2.0) (2016-04-11)
+
+
+### Bug Fixes
+
+* reduces tarball size ([acc6c33](https://github.com/yargs/cliui/commit/acc6c33))
+
+### Features
+
+* adds standard-version for release management ([ff84e32](https://github.com/yargs/cliui/commit/ff84e32))
diff --git a/server/node_modules/cliui/LICENSE.txt b/server/node_modules/cliui/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c7e27478a3eff8862ca150f10d1b93a5ac866af2
--- /dev/null
+++ b/server/node_modules/cliui/LICENSE.txt
@@ -0,0 +1,14 @@
+Copyright (c) 2015, Contributors
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice
+appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
+LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/server/node_modules/cliui/README.md b/server/node_modules/cliui/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..028392c2633c853de20fca579ed1996e6cf07baf
--- /dev/null
+++ b/server/node_modules/cliui/README.md
@@ -0,0 +1,110 @@
+# cliui
+
+[![Build Status](https://travis-ci.org/yargs/cliui.svg)](https://travis-ci.org/yargs/cliui)
+[![Coverage Status](https://coveralls.io/repos/yargs/cliui/badge.svg?branch=)](https://coveralls.io/r/yargs/cliui?branch=)
+[![NPM version](https://img.shields.io/npm/v/cliui.svg)](https://www.npmjs.com/package/cliui)
+[![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version)
+
+easily create complex multi-column command-line-interfaces.
+
+## Example
+
+```js
+var ui = require('cliui')({
+  width: 80
+})
+
+ui.div('Usage: $0 [command] [options]')
+
+ui.div({
+  text: 'Options:',
+  padding: [2, 0, 2, 0]
+})
+
+ui.div(
+  {
+    text: "-f, --file",
+    width: 20,
+    padding: [0, 4, 0, 4]
+  },
+  {
+    text: "the file to load." +
+      chalk.green("(if this description is long it wraps).")
+    ,
+    width: 20
+  },
+  {
+    text: chalk.red("[required]"),
+    align: 'right'
+  }
+)
+
+console.log(ui.toString())
+```
+
+<img width="500" src="screenshot.png">
+
+## Layout DSL
+
+cliui exposes a simple layout DSL:
+
+If you create a single `ui.row`, passing a string rather than an
+object:
+
+* `\n`: characters will be interpreted as new rows.
+* `\t`: characters will be interpreted as new columns.
+* `\s`: characters will be interpreted as padding.
+
+**as an example...**
+
+```js
+var ui = require('./')({
+  width: 60
+})
+
+ui.div(
+  'Usage: node ./bin/foo.js\n' +
+  '  <regex>\t  provide a regex\n' +
+  '  <glob>\t  provide a glob\t [required]'
+)
+
+console.log(ui.toString())
+```
+
+**will output:**
+
+```shell
+Usage: node ./bin/foo.js
+  <regex>  provide a regex
+  <glob>   provide a glob          [required]
+```
+
+## Methods
+
+```js
+cliui = require('cliui')
+```
+
+### cliui({width: integer})
+
+Specify the maximum width of the UI being generated.
+
+### cliui({wrap: boolean})
+
+Enable or disable the wrapping of text in a column.
+
+### cliui.div(column, column, column)
+
+Create a row with any number of columns, a column
+can either be a string, or an object with the following
+options:
+
+* **width:** the width of a column.
+* **align:** alignment, `right` or `center`.
+* **padding:** `[top, right, bottom, left]`.
+* **border:** should a border be placed around the div?
+
+### cliui.span(column, column, column)
+
+Similar to `div`, except the next row will be appended without
+a new line being created.
diff --git a/server/node_modules/cliui/index.js b/server/node_modules/cliui/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..e501e78fd79864da87e883fd071c26c7728cab86
--- /dev/null
+++ b/server/node_modules/cliui/index.js
@@ -0,0 +1,316 @@
+var stringWidth = require('string-width')
+var stripAnsi = require('strip-ansi')
+var wrap = require('wrap-ansi')
+var align = {
+  right: alignRight,
+  center: alignCenter
+}
+var top = 0
+var right = 1
+var bottom = 2
+var left = 3
+
+function UI (opts) {
+  this.width = opts.width
+  this.wrap = opts.wrap
+  this.rows = []
+}
+
+UI.prototype.span = function () {
+  var cols = this.div.apply(this, arguments)
+  cols.span = true
+}
+
+UI.prototype.div = function () {
+  if (arguments.length === 0) this.div('')
+  if (this.wrap && this._shouldApplyLayoutDSL.apply(this, arguments)) {
+    return this._applyLayoutDSL(arguments[0])
+  }
+
+  var cols = []
+
+  for (var i = 0, arg; (arg = arguments[i]) !== undefined; i++) {
+    if (typeof arg === 'string') cols.push(this._colFromString(arg))
+    else cols.push(arg)
+  }
+
+  this.rows.push(cols)
+  return cols
+}
+
+UI.prototype._shouldApplyLayoutDSL = function () {
+  return arguments.length === 1 && typeof arguments[0] === 'string' &&
+    /[\t\n]/.test(arguments[0])
+}
+
+UI.prototype._applyLayoutDSL = function (str) {
+  var _this = this
+  var rows = str.split('\n')
+  var leftColumnWidth = 0
+
+  // simple heuristic for layout, make sure the
+  // second column lines up along the left-hand.
+  // don't allow the first column to take up more
+  // than 50% of the screen.
+  rows.forEach(function (row) {
+    var columns = row.split('\t')
+    if (columns.length > 1 && stringWidth(columns[0]) > leftColumnWidth) {
+      leftColumnWidth = Math.min(
+        Math.floor(_this.width * 0.5),
+        stringWidth(columns[0])
+      )
+    }
+  })
+
+  // generate a table:
+  //  replacing ' ' with padding calculations.
+  //  using the algorithmically generated width.
+  rows.forEach(function (row) {
+    var columns = row.split('\t')
+    _this.div.apply(_this, columns.map(function (r, i) {
+      return {
+        text: r.trim(),
+        padding: _this._measurePadding(r),
+        width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
+      }
+    }))
+  })
+
+  return this.rows[this.rows.length - 1]
+}
+
+UI.prototype._colFromString = function (str) {
+  return {
+    text: str,
+    padding: this._measurePadding(str)
+  }
+}
+
+UI.prototype._measurePadding = function (str) {
+  // measure padding without ansi escape codes
+  var noAnsi = stripAnsi(str)
+  return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length]
+}
+
+UI.prototype.toString = function () {
+  var _this = this
+  var lines = []
+
+  _this.rows.forEach(function (row, i) {
+    _this.rowToString(row, lines)
+  })
+
+  // don't display any lines with the
+  // hidden flag set.
+  lines = lines.filter(function (line) {
+    return !line.hidden
+  })
+
+  return lines.map(function (line) {
+    return line.text
+  }).join('\n')
+}
+
+UI.prototype.rowToString = function (row, lines) {
+  var _this = this
+  var padding
+  var rrows = this._rasterize(row)
+  var str = ''
+  var ts
+  var width
+  var wrapWidth
+
+  rrows.forEach(function (rrow, r) {
+    str = ''
+    rrow.forEach(function (col, c) {
+      ts = '' // temporary string used during alignment/padding.
+      width = row[c].width // the width with padding.
+      wrapWidth = _this._negatePadding(row[c]) // the width without padding.
+
+      ts += col
+
+      for (var i = 0; i < wrapWidth - stringWidth(col); i++) {
+        ts += ' '
+      }
+
+      // align the string within its column.
+      if (row[c].align && row[c].align !== 'left' && _this.wrap) {
+        ts = align[row[c].align](ts, wrapWidth)
+        if (stringWidth(ts) < wrapWidth) ts += new Array(width - stringWidth(ts)).join(' ')
+      }
+
+      // apply border and padding to string.
+      padding = row[c].padding || [0, 0, 0, 0]
+      if (padding[left]) str += new Array(padding[left] + 1).join(' ')
+      str += addBorder(row[c], ts, '| ')
+      str += ts
+      str += addBorder(row[c], ts, ' |')
+      if (padding[right]) str += new Array(padding[right] + 1).join(' ')
+
+      // if prior row is span, try to render the
+      // current row on the prior line.
+      if (r === 0 && lines.length > 0) {
+        str = _this._renderInline(str, lines[lines.length - 1])
+      }
+    })
+
+    // remove trailing whitespace.
+    lines.push({
+      text: str.replace(/ +$/, ''),
+      span: row.span
+    })
+  })
+
+  return lines
+}
+
+function addBorder (col, ts, style) {
+  if (col.border) {
+    if (/[.']-+[.']/.test(ts)) return ''
+    else if (ts.trim().length) return style
+    else return '  '
+  }
+  return ''
+}
+
+// if the full 'source' can render in
+// the target line, do so.
+UI.prototype._renderInline = function (source, previousLine) {
+  var leadingWhitespace = source.match(/^ */)[0].length
+  var target = previousLine.text
+  var targetTextWidth = stringWidth(target.trimRight())
+
+  if (!previousLine.span) return source
+
+  // if we're not applying wrapping logic,
+  // just always append to the span.
+  if (!this.wrap) {
+    previousLine.hidden = true
+    return target + source
+  }
+
+  if (leadingWhitespace < targetTextWidth) return source
+
+  previousLine.hidden = true
+
+  return target.trimRight() + new Array(leadingWhitespace - targetTextWidth + 1).join(' ') + source.trimLeft()
+}
+
+UI.prototype._rasterize = function (row) {
+  var _this = this
+  var i
+  var rrow
+  var rrows = []
+  var widths = this._columnWidths(row)
+  var wrapped
+
+  // word wrap all columns, and create
+  // a data-structure that is easy to rasterize.
+  row.forEach(function (col, c) {
+    // leave room for left and right padding.
+    col.width = widths[c]
+    if (_this.wrap) wrapped = wrap(col.text, _this._negatePadding(col), {hard: true}).split('\n')
+    else wrapped = col.text.split('\n')
+
+    if (col.border) {
+      wrapped.unshift('.' + new Array(_this._negatePadding(col) + 3).join('-') + '.')
+      wrapped.push("'" + new Array(_this._negatePadding(col) + 3).join('-') + "'")
+    }
+
+    // add top and bottom padding.
+    if (col.padding) {
+      for (i = 0; i < (col.padding[top] || 0); i++) wrapped.unshift('')
+      for (i = 0; i < (col.padding[bottom] || 0); i++) wrapped.push('')
+    }
+
+    wrapped.forEach(function (str, r) {
+      if (!rrows[r]) rrows.push([])
+
+      rrow = rrows[r]
+
+      for (var i = 0; i < c; i++) {
+        if (rrow[i] === undefined) rrow.push('')
+      }
+      rrow.push(str)
+    })
+  })
+
+  return rrows
+}
+
+UI.prototype._negatePadding = function (col) {
+  var wrapWidth = col.width
+  if (col.padding) wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0)
+  if (col.border) wrapWidth -= 4
+  return wrapWidth
+}
+
+UI.prototype._columnWidths = function (row) {
+  var _this = this
+  var widths = []
+  var unset = row.length
+  var unsetWidth
+  var remainingWidth = this.width
+
+  // column widths can be set in config.
+  row.forEach(function (col, i) {
+    if (col.width) {
+      unset--
+      widths[i] = col.width
+      remainingWidth -= col.width
+    } else {
+      widths[i] = undefined
+    }
+  })
+
+  // any unset widths should be calculated.
+  if (unset) unsetWidth = Math.floor(remainingWidth / unset)
+  widths.forEach(function (w, i) {
+    if (!_this.wrap) widths[i] = row[i].width || stringWidth(row[i].text)
+    else if (w === undefined) widths[i] = Math.max(unsetWidth, _minWidth(row[i]))
+  })
+
+  return widths
+}
+
+// calculates the minimum width of
+// a column, based on padding preferences.
+function _minWidth (col) {
+  var padding = col.padding || []
+  var minWidth = 1 + (padding[left] || 0) + (padding[right] || 0)
+  if (col.border) minWidth += 4
+  return minWidth
+}
+
+function alignRight (str, width) {
+  str = str.trim()
+  var padding = ''
+  var strWidth = stringWidth(str)
+
+  if (strWidth < width) {
+    padding = new Array(width - strWidth + 1).join(' ')
+  }
+
+  return padding + str
+}
+
+function alignCenter (str, width) {
+  str = str.trim()
+  var padding = ''
+  var strWidth = stringWidth(str.trim())
+
+  if (strWidth < width) {
+    padding = new Array(parseInt((width - strWidth) / 2, 10) + 1).join(' ')
+  }
+
+  return padding + str
+}
+
+module.exports = function (opts) {
+  opts = opts || {}
+
+  return new UI({
+    width: (opts || {}).width || 80,
+    wrap: typeof opts.wrap === 'boolean' ? opts.wrap : true
+  })
+}
diff --git a/server/node_modules/cliui/package.json b/server/node_modules/cliui/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..518fbcdcd61fa78dec96ac77423a9570b4e3f80e
--- /dev/null
+++ b/server/node_modules/cliui/package.json
@@ -0,0 +1,96 @@
+{
+  "_from": "cliui@^3.2.0",
+  "_id": "cliui@3.2.0",
+  "_inBundle": false,
+  "_integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+  "_location": "/cliui",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "cliui@^3.2.0",
+    "name": "cliui",
+    "escapedName": "cliui",
+    "rawSpec": "^3.2.0",
+    "saveSpec": null,
+    "fetchSpec": "^3.2.0"
+  },
+  "_requiredBy": [
+    "/yargs"
+  ],
+  "_resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+  "_shasum": "120601537a916d29940f934da3b48d585a39213d",
+  "_spec": "cliui@^3.2.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "Ben Coe",
+    "email": "ben@npmjs.com"
+  },
+  "bugs": {
+    "url": "https://github.com/yargs/cliui/issues"
+  },
+  "bundleDependencies": false,
+  "config": {
+    "blanket": {
+      "pattern": [
+        "index.js"
+      ],
+      "data-cover-never": [
+        "node_modules",
+        "test"
+      ],
+      "output-reporter": "spec"
+    }
+  },
+  "dependencies": {
+    "string-width": "^1.0.1",
+    "strip-ansi": "^3.0.1",
+    "wrap-ansi": "^2.0.0"
+  },
+  "deprecated": false,
+  "description": "easily create complex multi-column command-line-interfaces",
+  "devDependencies": {
+    "chai": "^3.5.0",
+    "chalk": "^1.1.2",
+    "coveralls": "^2.11.8",
+    "mocha": "^2.4.5",
+    "nyc": "^6.4.0",
+    "standard": "^6.0.8",
+    "standard-version": "^2.1.2"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/yargs/cliui#readme",
+  "keywords": [
+    "cli",
+    "command-line",
+    "layout",
+    "design",
+    "console",
+    "wrap",
+    "table"
+  ],
+  "license": "ISC",
+  "main": "index.js",
+  "name": "cliui",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/yargs/cliui.git"
+  },
+  "scripts": {
+    "coverage": "nyc --reporter=text-lcov mocha | coveralls",
+    "pretest": "standard",
+    "test": "nyc mocha",
+    "version": "standard-version"
+  },
+  "standard": {
+    "ignore": [
+      "**/example/**"
+    ],
+    "globals": [
+      "it"
+    ]
+  },
+  "version": "3.2.0"
+}
diff --git a/server/node_modules/decamelize/index.js b/server/node_modules/decamelize/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..8d5bab7e4672ffd15fba27ce1a68235453e89417
--- /dev/null
+++ b/server/node_modules/decamelize/index.js
@@ -0,0 +1,13 @@
+'use strict';
+module.exports = function (str, sep) {
+	if (typeof str !== 'string') {
+		throw new TypeError('Expected a string');
+	}
+
+	sep = typeof sep === 'undefined' ? '_' : sep;
+
+	return str
+		.replace(/([a-z\d])([A-Z])/g, '$1' + sep + '$2')
+		.replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + sep + '$2')
+		.toLowerCase();
+};
diff --git a/server/node_modules/decamelize/license b/server/node_modules/decamelize/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/decamelize/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/decamelize/package.json b/server/node_modules/decamelize/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..b72a0e07459e06aacaea32757305c077ec57996a
--- /dev/null
+++ b/server/node_modules/decamelize/package.json
@@ -0,0 +1,70 @@
+{
+  "_from": "decamelize@^1.1.1",
+  "_id": "decamelize@1.2.0",
+  "_inBundle": false,
+  "_integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+  "_location": "/decamelize",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "decamelize@^1.1.1",
+    "name": "decamelize",
+    "escapedName": "decamelize",
+    "rawSpec": "^1.1.1",
+    "saveSpec": null,
+    "fetchSpec": "^1.1.1"
+  },
+  "_requiredBy": [
+    "/yargs"
+  ],
+  "_resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+  "_shasum": "f6534d15148269b20352e7bee26f501f9a191290",
+  "_spec": "decamelize@^1.1.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/decamelize/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Convert a camelized string into a lowercased one with a custom separator: unicornRainbow → unicorn_rainbow",
+  "devDependencies": {
+    "ava": "*",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/decamelize#readme",
+  "keywords": [
+    "decamelize",
+    "decamelcase",
+    "camelcase",
+    "lowercase",
+    "case",
+    "dash",
+    "hyphen",
+    "string",
+    "str",
+    "text",
+    "convert"
+  ],
+  "license": "MIT",
+  "name": "decamelize",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/decamelize.git"
+  },
+  "scripts": {
+    "test": "xo && ava"
+  },
+  "version": "1.2.0"
+}
diff --git a/server/node_modules/decamelize/readme.md b/server/node_modules/decamelize/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..624c7ee5ed05661479ccf9def1b03a3411f9d6fd
--- /dev/null
+++ b/server/node_modules/decamelize/readme.md
@@ -0,0 +1,48 @@
+# decamelize [![Build Status](https://travis-ci.org/sindresorhus/decamelize.svg?branch=master)](https://travis-ci.org/sindresorhus/decamelize)
+
+> Convert a camelized string into a lowercased one with a custom separator<br>
+> Example: `unicornRainbow` → `unicorn_rainbow`
+
+
+## Install
+
+```
+$ npm install --save decamelize
+```
+
+
+## Usage
+
+```js
+const decamelize = require('decamelize');
+
+decamelize('unicornRainbow');
+//=> 'unicorn_rainbow'
+
+decamelize('unicornRainbow', '-');
+//=> 'unicorn-rainbow'
+```
+
+
+## API
+
+### decamelize(input, [separator])
+
+#### input
+
+Type: `string`
+
+#### separator
+
+Type: `string`<br>
+Default: `_`
+
+
+## Related
+
+See [`camelcase`](https://github.com/sindresorhus/camelcase) for the inverse.
+
+
+## License
+
+MIT © [Sindre Sorhus](https://sindresorhus.com)
diff --git a/server/node_modules/error-ex/LICENSE b/server/node_modules/error-ex/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..0a5f461a6930323a7ca4e0acfd28043323805316
--- /dev/null
+++ b/server/node_modules/error-ex/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 JD Ballard
+
+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.
diff --git a/server/node_modules/error-ex/README.md b/server/node_modules/error-ex/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..97f744af897251dbbd71f1e0c79944c066bed994
--- /dev/null
+++ b/server/node_modules/error-ex/README.md
@@ -0,0 +1,144 @@
+# node-error-ex [![Travis-CI.org Build Status](https://img.shields.io/travis/Qix-/node-error-ex.svg?style=flat-square)](https://travis-ci.org/Qix-/node-error-ex) [![Coveralls.io Coverage Rating](https://img.shields.io/coveralls/Qix-/node-error-ex.svg?style=flat-square)](https://coveralls.io/r/Qix-/node-error-ex)
+> Easily subclass and customize new Error types
+
+## Examples
+To include in your project:
+```javascript
+var errorEx = require('error-ex');
+```
+
+To create an error message type with a specific name (note, that `ErrorFn.name`
+will not reflect this):
+```javascript
+var JSONError = errorEx('JSONError');
+
+var err = new JSONError('error');
+err.name; //-> JSONError
+throw err; //-> JSONError: error
+```
+
+To add a stack line:
+```javascript
+var JSONError = errorEx('JSONError', {fileName: errorEx.line('in %s')});
+
+var err = new JSONError('error')
+err.fileName = '/a/b/c/foo.json';
+throw err; //-> (line 2)-> in /a/b/c/foo.json
+```
+
+To append to the error message:
+```javascript
+var JSONError = errorEx('JSONError', {fileName: errorEx.append('in %s')});
+
+var err = new JSONError('error');
+err.fileName = '/a/b/c/foo.json';
+throw err; //-> JSONError: error in /a/b/c/foo.json
+```
+
+## API
+
+#### `errorEx([name], [properties])`
+Creates a new ErrorEx error type
+
+- `name`: the name of the new type (appears in the error message upon throw;
+  defaults to `Error.name`)
+- `properties`: if supplied, used as a key/value dictionary of properties to
+  use when building up the stack message. Keys are property names that are
+  looked up on the error message, and then passed to function values.
+	- `line`: if specified and is a function, return value is added as a stack
+    entry (error-ex will indent for you). Passed the property value given
+    the key.
+  - `stack`: if specified and is a function, passed the value of the property
+    using the key, and the raw stack lines as a second argument. Takes no
+    return value (but the stack can be modified directly).
+  - `message`: if specified and is a function, return value is used as new
+    `.message` value upon get. Passed the property value of the property named
+    by key, and the existing message is passed as the second argument as an
+    array of lines (suitable for multi-line messages).
+
+Returns a constructor (Function) that can be used just like the regular Error
+constructor.
+
+```javascript
+var errorEx = require('error-ex');
+
+var BasicError = errorEx();
+
+var NamedError = errorEx('NamedError');
+
+// --
+
+var AdvancedError = errorEx('AdvancedError', {
+	foo: {
+		line: function (value, stack) {
+			if (value) {
+				return 'bar ' + value;
+			}
+			return null;
+		}
+	}
+}
+
+var err = new AdvancedError('hello, world');
+err.foo = 'baz';
+throw err;
+
+/*
+	AdvancedError: hello, world
+	    bar baz
+	    at tryReadme() (readme.js:20:1)
+*/
+```
+
+#### `errorEx.line(str)`
+Creates a stack line using a delimiter
+
+> This is a helper function. It is to be used in lieu of writing a value object
+> for `properties` values.
+
+- `str`: The string to create
+  - Use the delimiter `%s` to specify where in the string the value should go
+
+```javascript
+var errorEx = require('error-ex');
+
+var FileError = errorEx('FileError', {fileName: errorEx.line('in %s')});
+
+var err = new FileError('problem reading file');
+err.fileName = '/a/b/c/d/foo.js';
+throw err;
+
+/*
+	FileError: problem reading file
+	    in /a/b/c/d/foo.js
+	    at tryReadme() (readme.js:7:1)
+*/
+```
+
+#### `errorEx.append(str)`
+Appends to the `error.message` string
+
+> This is a helper function. It is to be used in lieu of writing a value object
+> for `properties` values.
+
+- `str`: The string to append
+  - Use the delimiter `%s` to specify where in the string the value should go
+
+```javascript
+var errorEx = require('error-ex');
+
+var SyntaxError = errorEx('SyntaxError', {fileName: errorEx.append('in %s')});
+
+var err = new SyntaxError('improper indentation');
+err.fileName = '/a/b/c/d/foo.js';
+throw err;
+
+/*
+	SyntaxError: improper indentation in /a/b/c/d/foo.js
+	    at tryReadme() (readme.js:7:1)
+*/
+```
+
+## License
+Licensed under the [MIT License](http://opensource.org/licenses/MIT).
+You can find a copy of it in [LICENSE](LICENSE).
diff --git a/server/node_modules/error-ex/index.js b/server/node_modules/error-ex/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..4fb20b4879fa3c238ce3cb07ab6fbae2cd5ff451
--- /dev/null
+++ b/server/node_modules/error-ex/index.js
@@ -0,0 +1,141 @@
+'use strict';
+
+var util = require('util');
+var isArrayish = require('is-arrayish');
+
+var errorEx = function errorEx(name, properties) {
+	if (!name || name.constructor !== String) {
+		properties = name || {};
+		name = Error.name;
+	}
+
+	var errorExError = function ErrorEXError(message) {
+		if (!this) {
+			return new ErrorEXError(message);
+		}
+
+		message = message instanceof Error
+			? message.message
+			: (message || this.message);
+
+		Error.call(this, message);
+		Error.captureStackTrace(this, errorExError);
+
+		this.name = name;
+
+		Object.defineProperty(this, 'message', {
+			configurable: true,
+			enumerable: false,
+			get: function () {
+				var newMessage = message.split(/\r?\n/g);
+
+				for (var key in properties) {
+					if (!properties.hasOwnProperty(key)) {
+						continue;
+					}
+
+					var modifier = properties[key];
+
+					if ('message' in modifier) {
+						newMessage = modifier.message(this[key], newMessage) || newMessage;
+						if (!isArrayish(newMessage)) {
+							newMessage = [newMessage];
+						}
+					}
+				}
+
+				return newMessage.join('\n');
+			},
+			set: function (v) {
+				message = v;
+			}
+		});
+
+		var overwrittenStack = null;
+
+		var stackDescriptor = Object.getOwnPropertyDescriptor(this, 'stack');
+		var stackGetter = stackDescriptor.get;
+		var stackValue = stackDescriptor.value;
+		delete stackDescriptor.value;
+		delete stackDescriptor.writable;
+
+		stackDescriptor.set = function (newstack) {
+			overwrittenStack = newstack;
+		};
+
+		stackDescriptor.get = function () {
+			var stack = (overwrittenStack || ((stackGetter)
+				? stackGetter.call(this)
+				: stackValue)).split(/\r?\n+/g);
+
+			// starting in Node 7, the stack builder caches the message.
+			// just replace it.
+			if (!overwrittenStack) {
+				stack[0] = this.name + ': ' + this.message;
+			}
+
+			var lineCount = 1;
+			for (var key in properties) {
+				if (!properties.hasOwnProperty(key)) {
+					continue;
+				}
+
+				var modifier = properties[key];
+
+				if ('line' in modifier) {
+					var line = modifier.line(this[key]);
+					if (line) {
+						stack.splice(lineCount++, 0, '    ' + line);
+					}
+				}
+
+				if ('stack' in modifier) {
+					modifier.stack(this[key], stack);
+				}
+			}
+
+			return stack.join('\n');
+		};
+
+		Object.defineProperty(this, 'stack', stackDescriptor);
+	};
+
+	if (Object.setPrototypeOf) {
+		Object.setPrototypeOf(errorExError.prototype, Error.prototype);
+		Object.setPrototypeOf(errorExError, Error);
+	} else {
+		util.inherits(errorExError, Error);
+	}
+
+	return errorExError;
+};
+
+errorEx.append = function (str, def) {
+	return {
+		message: function (v, message) {
+			v = v || def;
+
+			if (v) {
+				message[0] += ' ' + str.replace('%s', v.toString());
+			}
+
+			return message;
+		}
+	};
+};
+
+errorEx.line = function (str, def) {
+	return {
+		line: function (v) {
+			v = v || def;
+
+			if (v) {
+				return str.replace('%s', v.toString());
+			}
+
+			return null;
+		}
+	};
+};
+
+module.exports = errorEx;
diff --git a/server/node_modules/error-ex/package.json b/server/node_modules/error-ex/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..f18c9aecc88a25b0253fca70cb1fbe6b110de630
--- /dev/null
+++ b/server/node_modules/error-ex/package.json
@@ -0,0 +1,86 @@
+{
+  "_from": "error-ex@^1.2.0",
+  "_id": "error-ex@1.3.2",
+  "_inBundle": false,
+  "_integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+  "_location": "/error-ex",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "error-ex@^1.2.0",
+    "name": "error-ex",
+    "escapedName": "error-ex",
+    "rawSpec": "^1.2.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.2.0"
+  },
+  "_requiredBy": [
+    "/parse-json"
+  ],
+  "_resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+  "_shasum": "b4ac40648107fdcdcfae242f428bea8a14d4f1bf",
+  "_spec": "error-ex@^1.2.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/parse-json",
+  "bugs": {
+    "url": "https://github.com/qix-/node-error-ex/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "is-arrayish": "^0.2.1"
+  },
+  "deprecated": false,
+  "description": "Easy error subclassing and stack customization",
+  "devDependencies": {
+    "coffee-script": "^1.9.3",
+    "coveralls": "^2.11.2",
+    "istanbul": "^0.3.17",
+    "mocha": "^2.2.5",
+    "should": "^7.0.1",
+    "xo": "^0.7.1"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/qix-/node-error-ex#readme",
+  "keywords": [
+    "error",
+    "errors",
+    "extend",
+    "extending",
+    "extension",
+    "subclass",
+    "stack",
+    "custom"
+  ],
+  "license": "MIT",
+  "maintainers": [
+    {
+      "name": "Josh Junon",
+      "email": "i.am.qix@gmail.com",
+      "url": "github.com/qix-"
+    },
+    {
+      "name": "Sindre Sorhus",
+      "email": "sindresorhus@gmail.com",
+      "url": "sindresorhus.com"
+    }
+  ],
+  "name": "error-ex",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/qix-/node-error-ex.git"
+  },
+  "scripts": {
+    "pretest": "xo",
+    "test": "mocha --compilers coffee:coffee-script/register"
+  },
+  "version": "1.3.2",
+  "xo": {
+    "rules": {
+      "operator-linebreak": [
+        0
+      ]
+    }
+  }
+}
diff --git a/server/node_modules/find-up/index.js b/server/node_modules/find-up/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..7ff0e2b78df22ab6a40994881087661f577b100f
--- /dev/null
+++ b/server/node_modules/find-up/index.js
@@ -0,0 +1,53 @@
+'use strict';
+var path = require('path');
+var pathExists = require('path-exists');
+var Promise = require('pinkie-promise');
+
+function splitPath(x) {
+	return path.resolve(x || '').split(path.sep);
+}
+
+function join(parts, filename) {
+	return path.resolve(parts.join(path.sep) + path.sep, filename);
+}
+
+module.exports = function (filename, opts) {
+	opts = opts || {};
+
+	var parts = splitPath(opts.cwd);
+
+	return new Promise(function (resolve) {
+		(function find() {
+			var fp = join(parts, filename);
+
+			pathExists(fp).then(function (exists) {
+				if (exists) {
+					resolve(fp);
+				} else if (parts.pop()) {
+					find();
+				} else {
+					resolve(null);
+				}
+			});
+		})();
+	});
+};
+
+module.exports.sync = function (filename, opts) {
+	opts = opts || {};
+
+	var parts = splitPath(opts.cwd);
+	var len = parts.length;
+
+	while (len--) {
+		var fp = join(parts, filename);
+
+		if (pathExists.sync(fp)) {
+			return fp;
+		}
+
+		parts.pop();
+	}
+
+	return null;
+};
diff --git a/server/node_modules/find-up/license b/server/node_modules/find-up/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/find-up/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/find-up/package.json b/server/node_modules/find-up/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..600b8de4e75ffea0b1e5dc39e45bcae3b7f62a8a
--- /dev/null
+++ b/server/node_modules/find-up/package.json
@@ -0,0 +1,83 @@
+{
+  "_from": "find-up@^1.0.0",
+  "_id": "find-up@1.1.2",
+  "_inBundle": false,
+  "_integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+  "_location": "/find-up",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "find-up@^1.0.0",
+    "name": "find-up",
+    "escapedName": "find-up",
+    "rawSpec": "^1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.0"
+  },
+  "_requiredBy": [
+    "/read-pkg-up"
+  ],
+  "_resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+  "_shasum": "6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f",
+  "_spec": "find-up@^1.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/read-pkg-up",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/find-up/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "path-exists": "^2.0.0",
+    "pinkie-promise": "^2.0.0"
+  },
+  "deprecated": false,
+  "description": "Find a file by walking up parent directories",
+  "devDependencies": {
+    "ava": "*",
+    "tempfile": "^1.1.1",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/find-up#readme",
+  "keywords": [
+    "find",
+    "up",
+    "find-up",
+    "findup",
+    "look-up",
+    "look",
+    "file",
+    "search",
+    "match",
+    "package",
+    "resolve",
+    "parent",
+    "parents",
+    "folder",
+    "directory",
+    "dir",
+    "walk",
+    "walking",
+    "path"
+  ],
+  "license": "MIT",
+  "name": "find-up",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/find-up.git"
+  },
+  "scripts": {
+    "test": "xo && ava"
+  },
+  "version": "1.1.2"
+}
diff --git a/server/node_modules/find-up/readme.md b/server/node_modules/find-up/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..9ea0611c385cc6190e7b2bd2bd1a1b60e594a5f8
--- /dev/null
+++ b/server/node_modules/find-up/readme.md
@@ -0,0 +1,72 @@
+# find-up [![Build Status](https://travis-ci.org/sindresorhus/find-up.svg?branch=master)](https://travis-ci.org/sindresorhus/find-up)
+
+> Find a file by walking up parent directories
+
+
+## Install
+
+```
+$ npm install --save find-up
+```
+
+
+## Usage
+
+```
+/
+└── Users
+    └── sindresorhus
+        ├── unicorn.png
+        └── foo
+            └── bar
+                ├── baz
+                └── example.js
+```
+
+```js
+// example.js
+const findUp = require('find-up');
+
+findUp('unicorn.png').then(filepath => {
+	console.log(filepath);
+	//=> '/Users/sindresorhus/unicorn.png'
+});
+```
+
+
+## API
+
+### findUp(filename, [options])
+
+Returns a promise for the filepath or `null`.
+
+### findUp.sync(filename, [options])
+
+Returns a filepath or `null`.
+
+#### filename
+
+Type: `string`
+
+Filename of the file to find.
+
+#### options
+
+##### cwd
+
+Type: `string`  
+Default: `process.cwd()`
+
+Directory to start from.
+
+
+## Related
+
+- [find-up-cli](https://github.com/sindresorhus/find-up-cli) - CLI for this module
+- [pkg-up](https://github.com/sindresorhus/pkg-up) - Find the closest package.json file
+- [pkg-dir](https://github.com/sindresorhus/pkg-dir) - Find the root directory of an npm package
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/generic-pool/.eslintrc.js b/server/node_modules/generic-pool/.eslintrc.js
new file mode 100644
index 0000000000000000000000000000000000000000..614c34465fdfa37100ec20dd6e879fe732e94396
--- /dev/null
+++ b/server/node_modules/generic-pool/.eslintrc.js
@@ -0,0 +1,6 @@
+module.exports = {
+    "extends": "standard",
+    "plugins": [
+        "standard"
+    ]
+};
\ No newline at end of file
diff --git a/server/node_modules/generic-pool/.npmignore b/server/node_modules/generic-pool/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..fcb718bb46996c79655d08c1a47d03afb234281e
--- /dev/null
+++ b/server/node_modules/generic-pool/.npmignore
@@ -0,0 +1,4 @@
+fabfile.pyc
+node-pool.iml
+node-pool.tmproj
+node_modules
diff --git a/server/node_modules/generic-pool/.travis.yml b/server/node_modules/generic-pool/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f5ad22e67ea978ea3d928d40657bc8096fe9ad17
--- /dev/null
+++ b/server/node_modules/generic-pool/.travis.yml
@@ -0,0 +1,21 @@
+language: node_js
+node_js:
+  - "0.6"
+  - "0.8"
+  - "0.10"
+  - "0.12"
+  - "4"
+  - "5"
+
+install:
+  - make install
+  - make lint-install
+
+script:
+  - make lint
+  - make test
+
+sudo: false
+
+matrix:
+  fast_finish: true
diff --git a/server/node_modules/generic-pool/CHANGELOG.md b/server/node_modules/generic-pool/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..8d25d60ae95dfb3f631f9cb4ef894b417f3b56c0
--- /dev/null
+++ b/server/node_modules/generic-pool/CHANGELOG.md
@@ -0,0 +1,127 @@
+# Change Log
+
+## [2.4.3] - October 15 2016
+- Use domain.bind to preserve domain context (@LewisJEllis)
+
+## [2.4.2] - March 26 2016
+- Travis now runs and fails lint checks (@kevinburke)
+- fixed bug #128 where using async validation incorrectly tracked resource state (@johnjdooley and @robfyfe)
+- fixed broken readme example that had aged badly
+
+## [2.4.1] - February 20 2016
+- Documented previously created/fixed bug #122 (thanks @jasonrhodes)
+- Improved Makefile and test runner docs thanks (@kevinburke)
+- fixed bug documented in #121 where pool could make incorrect decisions about which resources were eligible for removal. (thanks @mikemorris)
+
+## [2.4.0] - January 18 2016
+- Merged #118 - closes #110 - optional eslinting for test and lib using "standard" ruleset
+- Merged #114 - closes #113 - "classes" now used internally instead of object literals and exports support being called as a constructor (along with old factory behaviour) (contributed by @felixfbecker)
+- Move history from README.md to CHANGELOG.md and reformat
+- Closes #122 - fixes trapped connection bug when destroying a connection while others are in use
+
+## [2.3.1] - January 7 2016
+- Documentation fixes and widened number of nodejs versions tested on travis
+
+## [2.3.0] - January 1 2016
+- Merged #105 - allow asynchronous validate functions (contributed by @felipou)
+
+## [2.2.2] - December 13 2015
+- Merged #106 - fix condition where non "resource pool" created objects could be returned to the pool. (contributed by @devzer01)
+
+## [2.2.1] - October 30 2015
+- Merged #104 - fix #103 - condition where pool can create > specified max number of connections (contributed by @devzer01)
+
+## [2.2.0] - March 26 2015
+- Merged #92 - add getMaxPoolSize function (contributed by platypusMaximus)
+
+## [2.1.1] - July 5 2015
+- fix README error about priority queueing (spotted by @kmdm)
+
+## [2.1.0] - June 19 2014
+- Merged #72 - Add optional returnToHead flag, if true, resources are returned to head of queue (stack like behaviour) upon release (contributed by calibr), also see #68 for further discussion.
+
+## [2.0.4] - July 27 2013
+- Merged #64 - Fix for not removing idle objects (contributed by PiotrWpl)
+
+## [2.0.3] - January 16 2013
+- Merged #56/#57 - Add optional refreshIdle flag. If false, idle resources at the pool minimum will not be destroyed/re-created. (contributed by wshaver)
+- Merged #54 - Factory can be asked to validate pooled objects (contributed by tikonen)
+
+## [2.0.2] - October 22 2012
+- Fix #51, #48 - createResource() should check for null clientCb in err case (contributed by pooyasencha)
+- Merged #52 - fix bug of infinite wait when create object aync error (contributed by windyrobin)
+- Merged #53 - change the position of dispense and callback to ensure the time order (contributed by windyrobin)
+
+## [2.0.1] - August 29 2012
+- Fix #44 - leak of 'err' and 'obj' in createResource()
+- Add devDependencies block to package.json
+- Add travis-ci.org integration
+
+## [2.0.0] - July 31 2012
+- Non-backwards compatible change: remove adjustCallback
+  - acquire() callback must accept two params: (err, obj)
+- Add optional 'min' param to factory object that specifies minimum number of resources to keep in pool
+- Merged #38 (package.json/Makefile changes - contributed by strk)
+
+## [1.0.12] - June 27 2012
+- Merged #37 (Clear remove idle timer after destroyAllNow - contributed by dougwilson)
+
+## [1.0.11] - June 17 2012
+- Merged #36 ("pooled" method to perform function decoration for pooled methods - contributed by cosbynator)
+
+## [1.0.10] - May 3 2012
+- Merged #35 (Remove client from availbleObjects on destroy(client) - contributed by blax)
+
+## [1.0.9] - Dec 18 2011
+- Merged #25 (add getName() - contributed by BryanDonovan)
+- Merged #27 (remove sys import - contributed by botker)
+- Merged #26 (log levels - contributed by JoeZ99)
+
+## [1.0.8] - Nov 16 2011
+- Merged #21 (add getter methods to see pool size, etc. - contributed by BryanDonovan)
+
+## [1.0.7] - Oct 17 2011
+- Merged #19 (prevent release on the same obj twice - contributed by tkrynski)
+- Merged #20 (acquire() returns boolean indicating whether pool is full - contributed by tilgovi)
+
+## [1.0.6] - May 23 2011
+- Merged #13 (support error variable in acquire callback - contributed by tmcw)
+  - Note: This change is backwards compatible.  But new code should use the two parameter callback format in pool.create() functions from now on.
+- Merged #15 (variable scope issue in dispense() - contributed by eevans)
+
+## [1.0.5] - Apr 20 2011
+- Merged #12 (ability to drain pool - contributed by gdusbabek)
+
+## [1.0.4] - Jan 25 2011
+- Fixed #6 (objects reaped with undefined timeouts)
+- Fixed #7 (objectTimeout issue)
+
+## [1.0.3] - Dec 9 2010
+- Added priority queueing (thanks to sylvinus)
+- Contributions from Poetro
+  - Name changes to match conventions described here: http://en.wikipedia.org/wiki/Object_pool_pattern
+    - borrow() renamed to acquire()
+    - returnToPool() renamed to release()
+  - destroy() removed from public interface
+  - added JsDoc comments
+  - Priority queueing enhancements
+
+## [1.0.2] - Nov 9 2010
+- First NPM release
+
+[unreleased]: https://github.com/coopernurse/node-pool/compare/v2.4.2...HEAD
+[2.4.2]: https://github.com/coopernurse/node-pool/compare/v2.4.1...v2.4.2
+[2.4.1]: https://github.com/coopernurse/node-pool/compare/v2.4.0...v2.4.1
+[2.4.0]: https://github.com/coopernurse/node-pool/compare/v2.3.1...v2.4.0
+[2.3.1]: https://github.com/coopernurse/node-pool/compare/v2.3.0...v2.3.1
+[2.3.0]: https://github.com/coopernurse/node-pool/compare/v2.2.2...v2.3.0
+[2.2.2]: https://github.com/coopernurse/node-pool/compare/v2.2.1...v2.2.2
+[2.2.1]: https://github.com/coopernurse/node-pool/compare/v2.2.0...v2.2.1
+[2.2.0]: https://github.com/coopernurse/node-pool/compare/v2.1.1...v2.2.0
+[2.1.1]: https://github.com/coopernurse/node-pool/compare/v2.1.0...v2.1.1
+[2.1.0]: https://github.com/coopernurse/node-pool/compare/v2.0.4...v2.1.0
+[2.0.4]: https://github.com/coopernurse/node-pool/compare/v2.0.3...v2.0.4
+[2.0.3]: https://github.com/coopernurse/node-pool/compare/v2.0.2...v2.0.3
+[2.0.2]: https://github.com/coopernurse/node-pool/compare/v2.0.1...v2.0.2
+[2.0.1]: https://github.com/coopernurse/node-pool/compare/v2.0.0...v2.0.1
+[2.0.0]: https://github.com/coopernurse/node-pool/compare/v1.0.12...v2.0.0
diff --git a/server/node_modules/generic-pool/Makefile b/server/node_modules/generic-pool/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..daf2ff31c9be0518fb1922bd00e5383ec27ba576
--- /dev/null
+++ b/server/node_modules/generic-pool/Makefile
@@ -0,0 +1,31 @@
+.PHONY: all clean install check test lint-install lint
+
+INCOMPATIBLE_ESLINT_VERSIONS=$(shell node --version | egrep 'v0.[2-9]' | cut -d '.' -f 1-2)
+
+all:
+
+clean:
+	rm -rf node_modules
+
+install:
+	npm install
+
+check:
+	npm test
+
+test:
+	npm test
+
+lint-install:
+ifeq ($(INCOMPATIBLE_ESLINT_VERSIONS),)
+	npm run lint-install
+else
+	@echo "Lint not available on $(INCOMPATIBLE_ESLINT_VERSIONS)"
+endif
+
+lint:
+ifeq ($(INCOMPATIBLE_ESLINT_VERSIONS),)
+	npm run lint
+else
+	@echo "Lint not available on $(INCOMPATIBLE_ESLINT_VERSIONS)"
+endif
diff --git a/server/node_modules/generic-pool/README.md b/server/node_modules/generic-pool/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f647b46b87938bf08131ea4a347edc5931b40456
--- /dev/null
+++ b/server/node_modules/generic-pool/README.md
@@ -0,0 +1,298 @@
+[![build status](https://secure.travis-ci.org/coopernurse/node-pool.png)](http://travis-ci.org/coopernurse/node-pool)
+
+# About
+
+  Generic resource pool.  Can be used to reuse or throttle expensive resources such as
+  database connections.
+
+## Installation
+
+    $ npm install generic-pool
+
+## History
+
+The history has been moved to the [CHANGELOG](CHANGELOG.md)
+
+## Example
+
+### Step 1 - Create pool using a factory object
+
+```js
+// Create a MySQL connection pool with
+// a max of 10 connections, a min of 2, and a 30 second max idle time
+var Pool = require('generic-pool').Pool;
+var mysql = require('mysql'); // v2.10.x
+
+var pool = new Pool({
+    name     : 'mysql',
+    create   : function(callback) {
+        var c = mysql.createConnection({
+                user: 'scott',
+                password: 'tiger',
+                database:'mydb'
+        })
+
+        // parameter order: err, resource
+        callback(null, c);
+    },
+    destroy  : function(client) { client.end(); },
+    max      : 10,
+    // optional. if you set this, make sure to drain() (see step 3)
+    min      : 2,
+    // specifies how long a resource can stay idle in pool before being removed
+    idleTimeoutMillis : 30000,
+     // if true, logs via console.log - can also be a function
+    log : true
+});
+```
+
+### Step 2 - Use pool in your code to acquire/release resources
+
+```js
+// acquire connection - callback function is called
+// once a resource becomes available
+pool.acquire(function(err, client) {
+    if (err) {
+        // handle error - this is generally the err from your
+        // factory.create function
+    }
+    else {
+        client.query("select * from foo", [], function() {
+            // return object back to pool
+            pool.release(client);
+        });
+    }
+});
+```
+
+### Step 3 - Drain pool during shutdown (optional)
+
+If you are shutting down a long-lived process, you may notice
+that node fails to exit for 30 seconds or so.  This is a side
+effect of the idleTimeoutMillis behavior -- the pool has a
+setTimeout() call registered that is in the event loop queue, so
+node won't terminate until all resources have timed out, and the pool
+stops trying to manage them.
+
+This behavior will be more problematic when you set factory.min > 0,
+as the pool will never become empty, and the setTimeout calls will
+never end.
+
+In these cases, use the pool.drain() function.  This sets the pool
+into a "draining" state which will gracefully wait until all
+idle resources have timed out.  For example, you can call:
+
+```js
+// Only call this once in your application -- at the point you want
+// to shutdown and stop using this pool.
+pool.drain(function() {
+    pool.destroyAllNow();
+});
+```
+
+If you do this, your node process will exit gracefully.
+
+
+## Documentation
+
+    Pool() accepts an object with these slots:
+
+                  name : name of pool (string, optional)
+                create : function that returns a new resource
+                           should call callback() with the created resource
+               destroy : function that accepts a resource and destroys it
+                   max : maximum number of resources to create at any given time
+                         optional (default=1)
+                   min : minimum number of resources to keep in pool at any given time
+                         if this is set >= max, the pool will silently set the min
+                         to factory.max - 1 (Note: min==max case is expected to change in v3 release)
+                         optional (default=0)
+           refreshIdle : boolean that specifies whether idle resources at or below the min threshold
+                         should be destroyed/re-created.  optional (default=true)
+     idleTimeoutMillis : max milliseconds a resource can go unused before it should be destroyed
+                         (default 30000)
+    reapIntervalMillis : frequency to check for idle resources (default 1000),
+          returnToHead : boolean, if true the most recently released resources will be the first to be allocated.
+                         This in effect turns the pool's behaviour from a queue into a stack. optional (default false)
+         priorityRange : int between 1 and x - if set, borrowers can specify their
+                         relative priority in the queue if no resources are available.
+                         see example.  (default 1)
+              validate : function that accepts a pooled resource and returns true if the resource
+                         is OK to use, or false if the object is invalid.  Invalid objects will be destroyed.
+                         This function is called in acquire() before returning a resource from the pool.
+                         Optional.  Default function always returns true.
+         validateAsync : Asynchronous validate function. Receives a callback function as its second argument,
+                         which should be called with a single boolean argument being true if the item is still
+                         valid and false if it should be removed from the pool. Called before item is acquired
+                         from pool. Default is undefined. Only one of validate/validateAsync may be specified
+                   log : true/false or function -
+                           If a log is a function, it will be called with two parameters:
+                                                    - log string
+                                                    - log level ('verbose', 'info', 'warn', 'error')
+                           Else if log is true, verbose log info will be sent to console.log()
+                           Else internal log messages be ignored (this is the default)
+
+## Priority Queueing
+
+The pool now supports optional priority queueing.  This becomes relevant when no resources
+are available and the caller has to wait. `acquire()` accepts an optional priority int which
+specifies the caller's relative position in the queue.
+
+```js
+ // create pool with priorityRange of 3
+ // borrowers can specify a priority 0 to 2
+ var pool = new Pool({
+     name     : 'mysql',
+     create   : function(callback) {
+         // do something
+     },
+     destroy  : function(client) {
+         // cleanup.  omitted for this example
+     },
+     max      : 10,
+     idleTimeoutMillis : 30000,
+     priorityRange : 3
+ });
+
+ // acquire connection - no priority - will go at front of line (same as high priority)
+ pool.acquire(function(err, client) {
+     pool.release(client);
+ });
+
+ // acquire connection - high priority - will go into front slot
+ pool.acquire(function(err, client) {
+     pool.release(client);
+ }, 0);
+
+ // acquire connection - medium priority - will go into middle slot
+ pool.acquire(function(err, client) {
+     pool.release(client);
+ }, 1);
+
+ // etc..
+```
+
+## Draining
+
+If you know would like to terminate all the resources in your pool before
+their timeouts have been reached, you can use `destroyAllNow()` in conjunction
+with `drain()`:
+
+```js
+pool.drain(function() {
+    pool.destroyAllNow();
+});
+```
+
+One side-effect of calling `drain()` is that subsequent calls to `acquire()`
+will throw an Error.
+
+## Pooled function decoration
+
+To transparently handle object acquisition for a function,
+one can use `pooled()`:
+
+```js
+var privateFn, publicFn;
+publicFn = pool.pooled(privateFn = function(client, arg, cb) {
+    // Do something with the client and arg. Client is auto-released when cb is called
+    cb(null, arg);
+});
+```
+
+Keeping both private and public versions of each function allows for pooled
+functions to call other pooled functions with the same member. This is a handy
+pattern for database transactions:
+
+```js
+var privateTop, privateBottom, publicTop, publicBottom;
+publicBottom = pool.pooled(privateBottom = function(client, arg, cb) {
+    //Use client, assumed auto-release
+});
+
+publicTop = pool.pooled(privateTop = function(client, cb) {
+    // e.g., open a database transaction
+    privateBottom(client, "arg", function(err, retVal) {
+        if(err) { return cb(err); }
+        // e.g., close a transaction
+        cb();
+    });
+});
+```
+
+## Pool info
+
+The following functions will let you get information about the pool:
+
+```js
+// returns factory.name for this pool
+pool.getName()
+
+// returns number of resources in the pool regardless of
+// whether they are free or in use
+pool.getPoolSize()
+
+// returns number of unused resources in the pool
+pool.availableObjectsCount()
+
+// returns number of callers waiting to acquire a resource
+pool.waitingClientsCount()
+
+// returns number of maxixmum number of resources allowed by ppol
+pool.getMaxPoolSize()
+
+// returns number of minimum number of resources allowed by ppol
+pool.getMinPoolSize()
+
+```
+
+## Run Tests
+
+    $ npm install expresso
+    $ npm test
+
+The test runner runs every test in parallel, so tests cannot safely share
+resources. If a test fails, its thrown assertion error may bubble up and halt
+execution/cause failures in other running tests; these are spurious. If you
+have a failing test, try running it in isolation until you get it to pass.
+
+The individual tests "wait" by repeatedly checking the condition in the
+`beforeExit` callback. The test is marked as "passed" if the `beforeExit`
+callback runs successfully. Generally, this is accomplished by counting the
+number of assertions and checking that all of the test's assertions have been
+asserted.
+
+## Linting
+
+We use eslint and the `standard` ruleset. At the moment linting is not done as part of the test suite but this will probably change in the future. You should ideally lint your code before making any PR's patches etc.
+
+Becuase the linting tools require nodejs >= `0.10` but we test against `0.8` and `0.6` installation of the tools is done via `npm run lint-install`. Some kind of optionalDevDependencies would be great!
+
+    $ npm run lint-install
+    $ npm run lint
+
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2010-2016 James Cooper &lt;james@bitmechanic.com&gt;
+
+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.
diff --git a/server/node_modules/generic-pool/fabfile.py b/server/node_modules/generic-pool/fabfile.py
new file mode 100644
index 0000000000000000000000000000000000000000..becfc465857b150f9e448267b3cf6d9388302286
--- /dev/null
+++ b/server/node_modules/generic-pool/fabfile.py
@@ -0,0 +1,27 @@
+#
+#   dependencies:
+#      fabric (apt-get install fabric)
+#      node-jslint (http://github.com/reid/node-jslint)
+#      expresso (or replace with whatever node.js test tool you're using)
+#
+
+from fabric.api import local
+import os, os.path
+
+def test():
+    local('expresso -I lib test/*', capture=False)
+
+def jslint():
+    ignore = [ "/lib-cov/" ]
+    for root, subFolders, files in os.walk("."):
+        for file in files:
+            if file.endswith(".js"):
+                filename = os.path.join(root,file)
+                processFile = True
+                for i in ignore:
+                    if filename.find(i) != -1:
+                        processFile = False
+                if processFile:
+                    print filename
+                    local('jslint %s' % filename, capture=False)
+
diff --git a/server/node_modules/generic-pool/lib/generic-pool.js b/server/node_modules/generic-pool/lib/generic-pool.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b847b0ed389acf39d08256428eaf827962d99fc
--- /dev/null
+++ b/server/node_modules/generic-pool/lib/generic-pool.js
@@ -0,0 +1,568 @@
+/**
+ * @class
+ * @private
+ */
+function PriorityQueue (size) {
+  if (!(this instanceof PriorityQueue)) {
+    return new PriorityQueue()
+  }
+
+  this._size = size
+  this._slots = null
+  this._total = null
+
+  // initialize arrays to hold queue elements
+  size = Math.max(+size | 0, 1)
+  this._slots = []
+  for (var i = 0; i < size; i += 1) {
+    this._slots.push([])
+  }
+}
+
+PriorityQueue.prototype.size = function size () {
+  if (this._total === null) {
+    this._total = 0
+    for (var i = 0; i < this._size; i += 1) {
+      this._total += this._slots[i].length
+    }
+  }
+  return this._total
+}
+
+PriorityQueue.prototype.enqueue = function enqueue (obj, priority) {
+  var priorityOrig
+
+  // Convert to integer with a default value of 0.
+  priority = priority && +priority | 0 || 0
+
+  // Clear cache for total.
+  this._total = null
+  if (priority) {
+    priorityOrig = priority
+    if (priority < 0 || priority >= this._size) {
+      priority = (this._size - 1)
+      // put obj at the end of the line
+      console.error('invalid priority: ' + priorityOrig + ' must be between 0 and ' + priority)
+    }
+  }
+
+  this._slots[priority].push(obj)
+}
+
+PriorityQueue.prototype.dequeue = function dequeue (callback) {
+  var obj = null
+  // Clear cache for total.
+  this._total = null
+  for (var i = 0, sl = this._slots.length; i < sl; i += 1) {
+    if (this._slots[i].length) {
+      obj = this._slots[i].shift()
+      break
+    }
+  }
+  return obj
+}
+
+function doWhileAsync (conditionFn, iterateFn, callbackFn) {
+  var next = function () {
+    if (conditionFn()) {
+      iterateFn(next)
+    } else {
+      callbackFn()
+    }
+  }
+  next()
+}
+
+/**
+ * Generate an Object pool with a specified `factory`.
+ *
+ * @class
+ * @param {Object} factory
+ *   Factory to be used for generating and destorying the items.
+ * @param {String} factory.name
+ *   Name of the factory. Serves only logging purposes.
+ * @param {Function} factory.create
+ *   Should create the item to be acquired,
+ *   and call it's first callback argument with the generated item as it's argument.
+ * @param {Function} factory.destroy
+ *   Should gently close any resources that the item is using.
+ *   Called before the items is destroyed.
+ * @param {Function} factory.validate
+ *   Should return true if connection is still valid and false
+ *   If it should be removed from pool. Called before item is
+ *   acquired from pool.
+ * @param {Function} factory.validateAsync
+ *   Asynchronous validate function. Receives a callback function
+ *   as its second argument, that should be called with a single
+ *   boolean argument being true if the item is still valid and false
+ *   if it should be removed from pool. Called before item is
+ *   acquired from pool. Only one of validate/validateAsync may be specified
+ * @param {Number} factory.max
+ *   Maximum number of items that can exist at the same time.  Default: 1.
+ *   Any further acquire requests will be pushed to the waiting list.
+ * @param {Number} factory.min
+ *   Minimum number of items in pool (including in-use). Default: 0.
+ *   When the pool is created, or a resource destroyed, this minimum will
+ *   be checked. If the pool resource count is below the minimum, a new
+ *   resource will be created and added to the pool.
+ * @param {Number} factory.idleTimeoutMillis
+ *   Delay in milliseconds after the idle items in the pool will be destroyed.
+ *   And idle item is that is not acquired yet. Waiting items doesn't count here.
+ * @param {Number} factory.reapIntervalMillis
+ *   Cleanup is scheduled in every `factory.reapIntervalMillis` milliseconds.
+ * @param {Boolean|Function} factory.log
+ *   Whether the pool should log activity. If function is specified,
+ *   that will be used instead. The function expects the arguments msg, loglevel
+ * @param {Number} factory.priorityRange
+ *   The range from 1 to be treated as a valid priority
+ * @param {RefreshIdle} factory.refreshIdle
+ *   Should idle resources be destroyed and recreated every idleTimeoutMillis? Default: true.
+ * @param {Bool} [factory.returnToHead=false]
+ *   Returns released object to head of available objects list
+ */
+function Pool (factory) {
+  if (!(this instanceof Pool)) {
+    return new Pool(factory)
+  }
+
+  if (factory.validate && factory.validateAsync) {
+    throw new Error('Only one of validate or validateAsync may be specified')
+  }
+
+  // defaults
+  factory.idleTimeoutMillis = factory.idleTimeoutMillis || 30000
+  factory.returnToHead = factory.returnToHead || false
+  factory.refreshIdle = ('refreshIdle' in factory) ? factory.refreshIdle : true
+  factory.reapInterval = factory.reapIntervalMillis || 1000
+  factory.priorityRange = factory.priorityRange || 1
+  factory.validate = factory.validate || function () { return true }
+
+  factory.max = parseInt(factory.max, 10)
+  factory.min = parseInt(factory.min, 10)
+
+  factory.max = Math.max(isNaN(factory.max) ? 1 : factory.max, 1)
+  factory.min = Math.min(isNaN(factory.min) ? 0 : factory.min, factory.max - 1)
+
+  this._factory = factory
+  this._inUseObjects = []
+  this._draining = false
+  this._waitingClients = new PriorityQueue(factory.priorityRange)
+  this._availableObjects = []
+  this._count = 0
+  this._removeIdleTimer = null
+  this._removeIdleScheduled = false
+
+  // create initial resources (if factory.min > 0)
+  this._ensureMinimum()
+}
+
+/**
+ * logs to console or user defined log function
+ * @private
+ * @param {string} str
+ * @param {string} level
+ */
+Pool.prototype._log = function log (str, level) {
+  if (typeof this._factory.log === 'function') {
+    this._factory.log(str, level)
+  } else if (this._factory.log) {
+    console.log(level.toUpperCase() + ' pool ' + this._factory.name + ' - ' + str)
+  }
+}
+
+/**
+ * Request the client to be destroyed. The factory's destroy handler
+ * will also be called.
+ *
+ * This should be called within an acquire() block as an alternative to release().
+ *
+ * @param {Object} obj
+ *   The acquired item to be destoyed.
+ */
+Pool.prototype.destroy = function destroy (obj) {
+  this._count -= 1
+  if (this._count < 0) this._count = 0
+  this._availableObjects = this._availableObjects.filter(function (objWithTimeout) {
+    return (objWithTimeout.obj !== obj)
+  })
+
+  this._inUseObjects = this._inUseObjects.filter(function (objInUse) {
+    return (objInUse !== obj)
+  })
+
+  this._factory.destroy(obj)
+
+  this._ensureMinimum()
+}
+
+/**
+ * Checks and removes the available (idle) clients that have timed out.
+ * @private
+ */
+Pool.prototype._removeIdle = function removeIdle () {
+  var toRemove = []
+  var now = new Date().getTime()
+  var i
+  var al
+  var tr
+  var timeout
+
+  this._removeIdleScheduled = false
+
+  // Go through the available (idle) items,
+  // check if they have timed out
+  for (i = 0, al = this._availableObjects.length; i < al && (this._factory.refreshIdle && (this._count - this._factory.min > toRemove.length)); i += 1) {
+    timeout = this._availableObjects[i].timeout
+    if (now >= timeout) {
+      // Client timed out, so destroy it.
+      this._log('removeIdle() destroying obj - now:' + now + ' timeout:' + timeout, 'verbose')
+      toRemove.push(this._availableObjects[i].obj)
+    }
+  }
+
+  for (i = 0, tr = toRemove.length; i < tr; i += 1) {
+    this.destroy(toRemove[i])
+  }
+
+  // Replace the available items with the ones to keep.
+  al = this._availableObjects.length
+
+  if (al > 0) {
+    this._log('this._availableObjects.length=' + al, 'verbose')
+    this._scheduleRemoveIdle()
+  } else {
+    this._log('removeIdle() all objects removed', 'verbose')
+  }
+}
+
+/**
+ * Schedule removal of idle items in the pool.
+ *
+ * More schedules cannot run concurrently.
+ */
+Pool.prototype._scheduleRemoveIdle = function scheduleRemoveIdle () {
+  var self = this
+  if (!this._removeIdleScheduled) {
+    this._removeIdleScheduled = true
+    this._removeIdleTimer = setTimeout(function () {
+      self._removeIdle()
+    }, this._factory.reapInterval)
+  }
+}
+
+/**
+ * Try to get a new client to work, and clean up pool unused (idle) items.
+ *
+ *  - If there are available clients waiting, shift the first one out (LIFO),
+ *    and call its callback.
+ *  - If there are no waiting clients, try to create one if it won't exceed
+ *    the maximum number of clients.
+ *  - If creating a new client would exceed the maximum, add the client to
+ *    the wait list.
+ * @private
+ */
+Pool.prototype._dispense = function dispense () {
+  var self = this
+  var objWithTimeout = null
+  var err = null
+  var clientCb = null
+  var waitingCount = this._waitingClients.size()
+
+  this._log('dispense() clients=' + waitingCount + ' available=' + this._availableObjects.length, 'info')
+  if (waitingCount > 0) {
+    if (this._factory.validateAsync) {
+      doWhileAsync(function () {
+        return self._availableObjects.length > 0
+      }, function (next) {
+        self._log('dispense() - reusing obj', 'verbose')
+        objWithTimeout = self._availableObjects[0]
+
+        self._factory.validateAsync(objWithTimeout.obj, function (valid) {
+          if (!valid) {
+            self.destroy(objWithTimeout.obj)
+            next()
+          } else {
+            self._availableObjects.shift()
+            self._inUseObjects.push(objWithTimeout.obj)
+            clientCb = self._waitingClients.dequeue()
+            clientCb(err, objWithTimeout.obj)
+          }
+        })
+      }, function () {
+        if (self._count < self._factory.max) {
+          self._createResource()
+        }
+      })
+
+      return
+    }
+
+    while (this._availableObjects.length > 0) {
+      this._log('dispense() - reusing obj', 'verbose')
+      objWithTimeout = this._availableObjects[0]
+      if (!this._factory.validate(objWithTimeout.obj)) {
+        this.destroy(objWithTimeout.obj)
+        continue
+      }
+      this._availableObjects.shift()
+      this._inUseObjects.push(objWithTimeout.obj)
+      clientCb = this._waitingClients.dequeue()
+      return clientCb(err, objWithTimeout.obj)
+    }
+    if (this._count < this._factory.max) {
+      this._createResource()
+    }
+  }
+}
+
+/**
+ * @private
+ */
+Pool.prototype._createResource = function _createResource () {
+  this._count += 1
+  this._log('createResource() - creating obj - count=' + this._count + ' min=' + this._factory.min + ' max=' + this._factory.max, 'verbose')
+  var self = this
+  this._factory.create(function () {
+    var err, obj
+    var clientCb = self._waitingClients.dequeue()
+    if (arguments.length > 1) {
+      err = arguments[0]
+      obj = arguments[1]
+    } else {
+      err = (arguments[0] instanceof Error) ? arguments[0] : null
+      obj = (arguments[0] instanceof Error) ? null : arguments[0]
+    }
+    if (err) {
+      self._count -= 1
+      if (self._count < 0) self._count = 0
+      if (clientCb) {
+        clientCb(err, obj)
+      }
+      process.nextTick(function () {
+        self._dispense()
+      })
+    } else {
+      self._inUseObjects.push(obj)
+      if (clientCb) {
+        clientCb(err, obj)
+      } else {
+        self.release(obj)
+      }
+    }
+  })
+}
+
+/**
+ * @private
+ */
+Pool.prototype._ensureMinimum = function _ensureMinimum () {
+  var i, diff
+  if (!this._draining && (this._count < this._factory.min)) {
+    diff = this._factory.min - this._count
+    for (i = 0; i < diff; i++) {
+      this._createResource()
+    }
+  }
+}
+
+/**
+ * Request a new client. The callback will be called,
+ * when a new client will be availabe, passing the client to it.
+ *
+ * @param {Function} callback
+ *   Callback function to be called after the acquire is successful.
+ *   The function will receive the acquired item as the first parameter.
+ *
+ * @param {Number} priority
+ *   Optional.  Integer between 0 and (priorityRange - 1).  Specifies the priority
+ *   of the caller if there are no available resources.  Lower numbers mean higher
+ *   priority.
+ *
+ * @returns {boolean} `true` if the pool is not fully utilized, `false` otherwise.
+ */
+Pool.prototype.acquire = function acquire (callback, priority) {
+  if (this._draining) {
+    throw new Error('pool is draining and cannot accept work')
+  }
+  if (process.domain) {
+    callback = process.domain.bind(callback)
+  }
+  this._waitingClients.enqueue(callback, priority)
+  this._dispense()
+  return (this._count < this._factory.max)
+}
+
+/**
+ * @deprecated
+ */
+Pool.prototype.borrow = function borrow (callback, priority) {
+  this._log('borrow() is deprecated. use acquire() instead', 'warn')
+  this.acquire(callback, priority)
+}
+
+/**
+ * Return the client to the pool, in case it is no longer required.
+ *
+ * @param {Object} obj
+ *   The acquired object to be put back to the pool.
+ */
+Pool.prototype.release = function release (obj) {
+  // check to see if this object has already been released (i.e., is back in the pool of this._availableObjects)
+  if (this._availableObjects.some(function (objWithTimeout) { return (objWithTimeout.obj === obj) })) {
+    this._log('release called twice for the same resource: ' + (new Error().stack), 'error')
+    return
+  }
+
+  // check to see if this object exists in the `in use` list and remove it
+  var index = this._inUseObjects.indexOf(obj)
+  if (index < 0) {
+    this._log('attempt to release an invalid resource: ' + (new Error().stack), 'error')
+    return
+  }
+
+  // this._log("return to pool")
+  this._inUseObjects.splice(index, 1)
+  var objWithTimeout = { obj: obj, timeout: (new Date().getTime() + this._factory.idleTimeoutMillis) }
+  if (this._factory.returnToHead) {
+    this._availableObjects.splice(0, 0, objWithTimeout)
+  } else {
+    this._availableObjects.push(objWithTimeout)
+  }
+  this._log('timeout: ' + objWithTimeout.timeout, 'verbose')
+  this._dispense()
+  this._scheduleRemoveIdle()
+}
+
+/**
+ * @deprecated
+ */
+Pool.prototype.returnToPool = function returnToPool (obj) {
+  this._log('returnToPool() is deprecated. use release() instead', 'warn')
+  this.release(obj)
+}
+
+/**
+ * Disallow any new requests and let the request backlog dissapate.
+ *
+ * @param {Function} callback
+ *   Optional. Callback invoked when all work is done and all clients have been
+ *   released.
+ */
+Pool.prototype.drain = function drain (callback) {
+  this._log('draining', 'info')
+
+  // disable the ability to put more work on the queue.
+  this._draining = true
+
+  var self = this
+  var check = function () {
+    if (self._waitingClients.size() > 0) {
+      // wait until all client requests have been satisfied.
+      setTimeout(check, 100)
+    } else if (self._availableObjects.length !== self._count) {
+      // wait until all objects have been released.
+      setTimeout(check, 100)
+    } else if (callback) {
+      callback()
+    }
+  }
+  check()
+}
+
+/**
+ * Forcibly destroys all clients regardless of timeout.  Intended to be
+ * invoked as part of a drain.  Does not prevent the creation of new
+ * clients as a result of subsequent calls to acquire.
+ *
+ * Note that if factory.min > 0, the pool will destroy all idle resources
+ * in the pool, but replace them with newly created resources up to the
+ * specified factory.min value.  If this is not desired, set factory.min
+ * to zero before calling destroyAllNow()
+ *
+ * @param {Function} callback
+ *   Optional. Callback invoked after all existing clients are destroyed.
+ */
+Pool.prototype.destroyAllNow = function destroyAllNow (callback) {
+  this._log('force destroying all objects', 'info')
+  var willDie = this._availableObjects
+  this._availableObjects = []
+  var obj = willDie.shift()
+  while (obj !== null && obj !== undefined) {
+    this.destroy(obj.obj)
+    obj = willDie.shift()
+  }
+  this._removeIdleScheduled = false
+  clearTimeout(this._removeIdleTimer)
+  if (callback) {
+    callback()
+  }
+}
+
+/**
+ * Decorates a function to use a acquired client from the object pool when called.
+ *
+ * @param {Function} decorated
+ *   The decorated function, accepting a client as the first argument and
+ *   (optionally) a callback as the final argument.
+ *
+ * @param {Number} priority
+ *   Optional.  Integer between 0 and (priorityRange - 1).  Specifies the priority
+ *   of the caller if there are no available resources.  Lower numbers mean higher
+ *   priority.
+ */
+Pool.prototype.pooled = function pooled (decorated, priority) {
+  var self = this
+  return function () {
+    var callerArgs = arguments
+    var callerCallback = callerArgs[callerArgs.length - 1]
+    var callerHasCallback = typeof callerCallback === 'function'
+    self.acquire(function (err, client) {
+      if (err) {
+        if (callerHasCallback) {
+          callerCallback(err)
+        }
+        return
+      }
+
+      var args = [client].concat(Array.prototype.slice.call(callerArgs, 0, callerHasCallback ? -1 : undefined))
+      args.push(function () {
+        self.release(client)
+        if (callerHasCallback) {
+          callerCallback.apply(null, arguments)
+        }
+      })
+
+      decorated.apply(null, args)
+    }, priority)
+  }
+}
+
+Pool.prototype.getPoolSize = function getPoolSize () {
+  return this._count
+}
+
+Pool.prototype.getName = function getName () {
+  return this._factory.name
+}
+
+Pool.prototype.availableObjectsCount = function availableObjectsCount () {
+  return this._availableObjects.length
+}
+
+Pool.prototype.inUseObjectsCount = function inUseObjectsCount () {
+  return this._inUseObjects.length
+}
+
+Pool.prototype.waitingClientsCount = function waitingClientsCount () {
+  return this._waitingClients.size()
+}
+
+Pool.prototype.getMaxPoolSize = function getMaxPoolSize () {
+  return this._factory.max
+}
+
+Pool.prototype.getMinPoolSize = function getMinPoolSize () {
+  return this._factory.min
+}
+
+exports.Pool = Pool
diff --git a/server/node_modules/generic-pool/package.json b/server/node_modules/generic-pool/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..7c80c13c8985667915d8f1342f7c72f57e2803b2
--- /dev/null
+++ b/server/node_modules/generic-pool/package.json
@@ -0,0 +1,110 @@
+{
+  "_from": "generic-pool@2.4.3",
+  "_id": "generic-pool@2.4.3",
+  "_inBundle": false,
+  "_integrity": "sha1-eAw29p360FpaBF3Te+etyhGk9v8=",
+  "_location": "/generic-pool",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "generic-pool@2.4.3",
+    "name": "generic-pool",
+    "escapedName": "generic-pool",
+    "rawSpec": "2.4.3",
+    "saveSpec": null,
+    "fetchSpec": "2.4.3"
+  },
+  "_requiredBy": [
+    "/pgtools/pg-pool"
+  ],
+  "_resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-2.4.3.tgz",
+  "_shasum": "780c36f69dfad05a5a045dd37be7adca11a4f6ff",
+  "_spec": "generic-pool@2.4.3",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgtools/node_modules/pg-pool",
+  "author": {
+    "name": "James Cooper",
+    "email": "james@bitmechanic.com"
+  },
+  "bugs": {
+    "url": "https://github.com/coopernurse/node-pool/issues"
+  },
+  "bundleDependencies": false,
+  "contributors": [
+    {
+      "name": "James Cooper",
+      "email": "james@bitmechanic.com"
+    },
+    {
+      "name": "Peter Galiba",
+      "email": "poetro@poetro.hu",
+      "url": "http://poetro.hu/"
+    },
+    {
+      "name": "Gary Dusbabek"
+    },
+    {
+      "name": "Tom MacWright",
+      "url": "http://www.developmentseed.org/"
+    },
+    {
+      "name": "Douglas Christopher Wilson",
+      "email": "doug@somethingdoug.com",
+      "url": "http://somethingdoug.com/"
+    },
+    {
+      "name": "calibr"
+    },
+    {
+      "name": "Justin Robinson",
+      "email": "jrobinson@redventures.com"
+    },
+    {
+      "name": "Nayana Hettiarachchi",
+      "email": "nayana@corp-gems.com"
+    },
+    {
+      "name": "Felipe Machado",
+      "email": "felipou@gmail.com"
+    },
+    {
+      "name": "Felix Becker",
+      "email": "felix.b@outlook.com"
+    },
+    {
+      "name": "sandfox",
+      "email": "james.butler@sandfox.co.uk"
+    },
+    {
+      "name": "Lewis J Ellis",
+      "email": "me@lewisjellis.com"
+    }
+  ],
+  "deprecated": false,
+  "description": "Generic resource pooling for Node.JS",
+  "devDependencies": {
+    "expresso": ">0.0.0"
+  },
+  "engines": {
+    "node": ">= 0.2.0"
+  },
+  "homepage": "https://github.com/coopernurse/node-pool#readme",
+  "keywords": [
+    "pool",
+    "pooling",
+    "throttle"
+  ],
+  "license": "MIT",
+  "main": "lib/generic-pool.js",
+  "name": "generic-pool",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/coopernurse/node-pool.git"
+  },
+  "scripts": {
+    "lint": "eslint lib test",
+    "lint-install": "npm install eslint@^1.10.2 eslint-config-standard@^4.4.0 eslint-plugin-standard@^1.3.1",
+    "test": "expresso test/*.js"
+  },
+  "version": "2.4.3"
+}
diff --git a/server/node_modules/generic-pool/test/generic-pool.test.js b/server/node_modules/generic-pool/test/generic-pool.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..66fe8321764f857026c4e5c9a32c87e585201729
--- /dev/null
+++ b/server/node_modules/generic-pool/test/generic-pool.test.js
@@ -0,0 +1,797 @@
+var assert = require('assert')
+var poolModule = require('..')
+
+module.exports = {
+  'expands to max limit': function (beforeExit) {
+    var createCount = 0
+    var destroyCount = 0
+    var borrowCount = 0
+
+    var factory = {
+      name: 'test1',
+      create: function (callback) {
+        callback(null, { count: ++createCount })
+      },
+      destroy: function (client) { destroyCount++ },
+      max: 2,
+      idleTimeoutMillis: 100
+    }
+
+    var pool = poolModule.Pool(factory)
+
+    for (var i = 0; i < 10; i++) {
+      var full = !pool.acquire(function () {
+        return function (err, obj) {
+          assert.ifError(err)
+          assert.equal(typeof obj.count, 'number')
+          setTimeout(function () {
+            borrowCount++
+            pool.release(obj)
+          }, 100)
+        }
+      }())
+      assert.ok((i < 1) ^ full)
+    }
+
+    beforeExit(function () {
+      assert.equal(0, factory.min)
+      assert.equal(2, createCount)
+      assert.equal(2, destroyCount)
+      assert.equal(10, borrowCount)
+    })
+  },
+
+  'respects min limit': function (beforeExit) {
+    var createCount = 0
+    var destroyCount = 0
+
+    var pool = poolModule.Pool({
+      name: 'test-min',
+      create: function (callback) {
+        callback(null, { count: ++createCount })
+      },
+      destroy: function (client) { destroyCount++ },
+      min: 1,
+      max: 2,
+      idleTimeoutMillis: 100
+    })
+
+    pool.drain(function () {
+      pool.destroyAllNow()
+    })
+
+    beforeExit(function () {
+      assert.equal(0, pool.availableObjectsCount())
+      assert.equal(1, createCount)
+      assert.equal(1, destroyCount)
+    })
+  },
+
+  'min and max limit defaults': function (beforeExit) {
+    var factory = {
+      name: 'test-limit-defaults',
+      create: function (callback) { callback(null, {}) },
+      destroy: function (client) {},
+      idleTimeoutMillis: 100
+    }
+    var pool = poolModule.Pool(factory)
+
+    beforeExit(function () {
+      assert.equal(1, pool.getMaxPoolSize())
+      assert.equal(0, pool.getMinPoolSize())
+    })
+  },
+
+  'malformed min and max limits are ignored': function (beforeExit) {
+    var factory = {
+      name: 'test-limit-defaults2',
+      create: function (callback) { callback(null, {}) },
+      destroy: function (client) {},
+      idleTimeoutMillis: 100,
+      min: 'asf',
+      max: []
+    }
+    var pool = poolModule.Pool(factory)
+
+    beforeExit(function () {
+      assert.equal(1, pool.getMaxPoolSize())
+      assert.equal(0, pool.getMinPoolSize())
+    })
+  },
+
+  'min greater than max sets to max minus one': function (beforeExit) {
+    var factory = {
+      name: 'test-limit-defaults3',
+      create: function (callback) { callback(null, {}) },
+      destroy: function (client) {},
+      idleTimeoutMillis: 100,
+      min: 5,
+      max: 3
+    }
+    var pool = poolModule.Pool(factory)
+    pool.drain(function () {
+      pool.destroyAllNow()
+    })
+
+    beforeExit(function () {
+      assert.equal(3, pool.getMaxPoolSize())
+      assert.equal(2, pool.getMinPoolSize())
+    })
+  },
+
+  'supports priority on borrow': function (beforeExit) {
+    var borrowTimeLow = 0
+    var borrowTimeHigh = 0
+    var borrowCount = 0
+    var i
+
+    var pool = poolModule.Pool({
+      name: 'test2',
+      create: function (callback) { callback() },
+      destroy: function (client) {},
+      max: 1,
+      idleTimeoutMillis: 100,
+      priorityRange: 2
+    })
+
+    for (i = 0; i < 10; i++) {
+      pool.acquire((function (err, obj) {
+        return function () {
+          setTimeout(function () {
+            assert.ifError(err)
+            var t = new Date().getTime()
+            if (t > borrowTimeLow) { borrowTimeLow = t }
+            borrowCount++
+            pool.release(obj)
+          }, 50)
+        }
+      }()), 1)
+    }
+
+    for (i = 0; i < 10; i++) {
+      pool.acquire((function (obj) {
+        return function () {
+          setTimeout(function () {
+            var t = new Date().getTime()
+            if (t > borrowTimeHigh) { borrowTimeHigh = t }
+            borrowCount++
+            pool.release(obj)
+          }, 50)
+        }
+      }()), 0)
+    }
+
+    beforeExit(function () {
+      assert.equal(20, borrowCount)
+      assert.equal(true, borrowTimeLow > borrowTimeHigh)
+    })
+  },
+
+  'removes correct object on reap': function (beforeExit) {
+    var destroyed = []
+    var clientCount = 0
+
+    var pool = poolModule.Pool({
+      name: 'test3',
+      create: function (callback) { callback(null, { id: ++clientCount }) },
+      destroy: function (client) { destroyed.push(client.id) },
+      max: 2,
+      idleTimeoutMillis: 100
+    })
+
+    pool.acquire(function (err, client) {
+      assert.ifError(err)
+      assert.equal(typeof client.id, 'number')
+      // should be removed second
+      setTimeout(function () { pool.release(client) }, 5)
+    })
+    pool.acquire(function (err, client) {
+      assert.ifError(err)
+      assert.equal(typeof client.id, 'number')
+      // should be removed first
+      pool.release(client)
+    })
+
+    setTimeout(function () {}, 102)
+
+    beforeExit(function () {
+      assert.equal(2, destroyed[0])
+      assert.equal(1, destroyed[1])
+    })
+  },
+
+  'tests drain': function (beforeExit) {
+    var created = 0
+    var destroyed = 0
+    var count = 5
+    var acquired = 0
+
+    var pool = poolModule.Pool({
+      name: 'test4',
+      create: function (callback) { callback(null, {id: ++created}) },
+      destroy: function (client) { destroyed += 1 },
+      max: 2,
+      idletimeoutMillis: 300000
+    })
+
+    for (var i = 0; i < count; i++) {
+      pool.acquire(function (err, client) {
+        assert.ifError(err)
+        acquired += 1
+        assert.equal(typeof client.id, 'number')
+        setTimeout(function () { pool.release(client) }, 250)
+      })
+    }
+
+    assert.notEqual(count, acquired)
+    pool.drain(function () {
+      assert.equal(count, acquired)
+      // short circuit the absurdly long timeouts above.
+      pool.destroyAllNow()
+      beforeExit(function () {})
+    })
+
+    // subsequent calls to acquire should return an error.
+    assert.throws(function () {
+      pool.acquire(function (client) {})
+    }, Error)
+  },
+
+  'handle creation errors': function (beforeExit) {
+    var created = 0
+    var pool = poolModule.Pool({
+      name: 'test6',
+      create: function (callback) {
+        if (created < 5) {
+          callback(new Error('Error occurred.'))
+        } else {
+          callback({ id: created })
+        }
+        created++
+      },
+      destroy: function (client) {},
+      max: 1,
+      idleTimeoutMillis: 1000
+    })
+    // ensure that creation errors do not populate the pool.
+    for (var i = 0; i < 5; i++) {
+      pool.acquire(function (err, client) {
+        assert.ok(err instanceof Error)
+        assert.ok(client === null)
+      })
+    }
+
+    var called = false
+    pool.acquire(function (err, client) {
+      assert.ok(err === null)
+      assert.equal(typeof client.id, 'number')
+      called = true
+    })
+    beforeExit(function () {
+      assert.ok(called)
+      assert.equal(pool.waitingClientsCount(), 0)
+    })
+  },
+
+  'handle creation errors for delayed creates': function (beforeExit) {
+    var created = 0
+    var pool = poolModule.Pool({
+      name: 'test6',
+      create: function (callback) {
+        if (created < 5) {
+          setTimeout(function () {
+            callback(new Error('Error occurred.'))
+          }, 0)
+        } else {
+          setTimeout(function () {
+            callback({ id: created })
+          }, 0)
+        }
+        created++
+      },
+      destroy: function (client) {},
+      max: 1,
+      idleTimeoutMillis: 1000
+    })
+    // ensure that creation errors do not populate the pool.
+    for (var i = 0; i < 5; i++) {
+      pool.acquire(function (err, client) {
+        assert.ok(err instanceof Error)
+        assert.ok(client === null)
+      })
+    }
+    var called = false
+    pool.acquire(function (err, client) {
+      assert.ok(err === null)
+      assert.equal(typeof client.id, 'number')
+      called = true
+    })
+    beforeExit(function () {
+      assert.ok(called)
+      assert.equal(pool.waitingClientsCount(), 0)
+    })
+  },
+
+  'pooled decorator should acquire and release': function (beforeExit) {
+    var assertion_count = 0
+    var destroyed_count = 0
+    var pool = poolModule.Pool({
+      name: 'test1',
+      create: function (callback) { callback({id: Math.floor(Math.random() * 1000)}) },
+      destroy: function (client) { destroyed_count += 1 },
+      max: 1,
+      idleTimeoutMillis: 100
+    })
+
+    var pooledFn = pool.pooled(function (client, cb) {
+      assert.equal(typeof client.id, 'number')
+      assert.equal(pool.getPoolSize(), 1)
+      assertion_count += 2
+      cb()
+    })
+
+    assert.equal(pool.getPoolSize(), 0)
+    assertion_count += 1
+
+    pooledFn(function (err) {
+      if (err) { throw err }
+      assert.ok(true)
+      assertion_count += 1
+    })
+
+    beforeExit(function () {
+      assert.equal(assertion_count, 4)
+      assert.equal(destroyed_count, 1)
+    })
+  },
+
+  'pooled decorator should pass arguments and return values': function (beforeExit) {
+    var assertion_count = 0
+    var pool = poolModule.Pool({
+      name: 'test1',
+      create: function (callback) { callback({id: Math.floor(Math.random() * 1000)}) },
+      destroy: function (client) {},
+      max: 1,
+      idleTimeoutMillis: 100
+    })
+
+    var pooledFn = pool.pooled(function (client, arg1, arg2, cb) {
+      assert.equal(arg1, 'First argument')
+      assert.equal(arg2, 'Second argument')
+      assertion_count += 2
+      cb(null, 'First return', 'Second return')
+    })
+
+    pooledFn('First argument', 'Second argument', function (err, retVal1, retVal2) {
+      if (err) { throw err }
+      assert.equal(retVal1, 'First return')
+      assert.equal(retVal2, 'Second return')
+      assertion_count += 2
+    })
+
+    beforeExit(function () {
+      assert.equal(assertion_count, 4)
+    })
+  },
+
+  'pooled decorator should allow undefined callback': function (beforeExit) {
+    var assertion_count = 0
+    var pool = poolModule.Pool({
+      name: 'test1',
+      create: function (callback) { callback({id: Math.floor(Math.random() * 1000)}) },
+      destroy: function (client) {},
+      max: 1,
+      idleTimeoutMillis: 100
+    })
+
+    var pooledFn = pool.pooled(function (client, arg, cb) {
+      assert.equal(arg, 'Arg!')
+      assertion_count += 1
+      cb()
+    })
+
+    pooledFn('Arg!')
+
+    beforeExit(function () {
+      assert.equal(pool.getPoolSize(), 0)
+      assert.equal(assertion_count, 1)
+    })
+  },
+
+  'pooled decorator should forward pool errors': function (beforeExit) {
+    var assertion_count = 0
+    var pool = poolModule.Pool({
+      name: 'test1',
+      create: function (callback) { callback(new Error('Pool error')) },
+      destroy: function (client) {},
+      max: 1,
+      idleTimeoutMillis: 100
+    })
+
+    var pooledFn = pool.pooled(function (cb) {
+      assert.ok(false, "Pooled function shouldn't be called due to a pool error")
+    })
+
+    pooledFn(function (err, obj) {
+      assert.equal(err.message, 'Pool error')
+      assertion_count += 1
+    })
+
+    beforeExit(function () {
+      assert.equal(assertion_count, 1)
+    })
+  },
+
+  'getPoolSize': function (beforeExit) {
+    var assertion_count = 0
+    var pool = poolModule.Pool({
+      name: 'test1',
+      create: function (callback) { callback({id: Math.floor(Math.random() * 1000)}) },
+      destroy: function (client) {},
+      max: 2,
+      idleTimeoutMillis: 100
+    })
+
+    assert.equal(pool.getPoolSize(), 0)
+    assertion_count += 1
+    pool.acquire(function (err, obj1) {
+      if (err) { throw err }
+      assert.equal(pool.getPoolSize(), 1)
+      assertion_count += 1
+      pool.acquire(function (err, obj2) {
+        if (err) { throw err }
+        assert.equal(pool.getPoolSize(), 2)
+        assertion_count += 1
+
+        pool.release(obj1)
+        pool.release(obj2)
+
+        pool.acquire(function (err, obj3) {
+          if (err) { throw err }
+          // should still be 2
+          assert.equal(pool.getPoolSize(), 2)
+          assertion_count += 1
+          pool.release(obj3)
+        })
+      })
+    })
+
+    beforeExit(function () {
+      assert.equal(assertion_count, 4)
+    })
+  },
+
+  'availableObjectsCount': function (beforeExit) {
+    var assertion_count = 0
+    var pool = poolModule.Pool({
+      name: 'test1',
+      create: function (callback) { callback({id: Math.floor(Math.random() * 1000)}) },
+      destroy: function (client) {},
+      max: 2,
+      idleTimeoutMillis: 100
+    })
+
+    assert.equal(pool.availableObjectsCount(), 0)
+    assertion_count += 1
+    pool.acquire(function (err, obj1) {
+      if (err) { throw err }
+      assert.equal(pool.availableObjectsCount(), 0)
+      assertion_count += 1
+
+      pool.acquire(function (err, obj2) {
+        if (err) { throw err }
+        assert.equal(pool.availableObjectsCount(), 0)
+        assertion_count += 1
+
+        pool.release(obj1)
+        assert.equal(pool.availableObjectsCount(), 1)
+        assertion_count += 1
+
+        pool.release(obj2)
+        assert.equal(pool.availableObjectsCount(), 2)
+        assertion_count += 1
+
+        pool.acquire(function (err, obj3) {
+          if (err) { throw err }
+          assert.equal(pool.availableObjectsCount(), 1)
+          assertion_count += 1
+          pool.release(obj3)
+
+          assert.equal(pool.availableObjectsCount(), 2)
+          assertion_count += 1
+        })
+      })
+    })
+
+    beforeExit(function () {
+      assert.equal(assertion_count, 7)
+    })
+  },
+
+  'logPassesLogLevel': function (beforeExit) {
+    var loglevels = {'verbose': 0, 'info': 1, 'warn': 2, 'error': 3}
+    var logmessages = {verbose: [], info: [], warn: [], error: []}
+    var factory = {
+      name: 'test1',
+      create: function (callback) { callback(null, {id: Math.floor(Math.random() * 1000)}) },
+      destroy: function (client) {},
+      max: 2,
+      idleTimeoutMillis: 100,
+      log: function (msg, level) { testlog(msg, level) }
+    }
+    var testlog = function (msg, level) {
+      assert.ok(level in loglevels)
+      logmessages[level].push(msg)
+    }
+    var pool = poolModule.Pool(factory)
+
+    var pool2 = poolModule.Pool({
+      name: 'testNoLog',
+      create: function (callback) { callback(null, {id: Math.floor(Math.random() * 1000)}) },
+      destroy: function (client) {},
+      max: 2,
+      idleTimeoutMillis: 100
+    })
+    assert.equal(pool2.getName(), 'testNoLog')
+
+    pool.acquire(function (err, obj) {
+      assert.ifError(err)
+      assert.equal(logmessages.verbose[0], 'createResource() - creating obj - count=1 min=0 max=2')
+      assert.equal(logmessages.info[0], 'dispense() clients=1 available=0')
+      logmessages.info = []
+      logmessages.verbose = []
+      pool2.borrow(function (err, obj) {
+        assert.ifError(err)
+        assert.equal(logmessages.info.length, 0)
+        assert.equal(logmessages.verbose.length, 0)
+        assert.equal(logmessages.warn.length, 0)
+      })
+    })
+  },
+
+  'removes from available objects on destroy': function (beforeExit) {
+    var destroyCalled = false
+    var factory = {
+      name: 'test',
+      create: function (callback) { callback(null, {}) },
+      destroy: function (client) { destroyCalled = true },
+      max: 2,
+      idleTimeoutMillis: 100
+    }
+
+    var pool = poolModule.Pool(factory)
+    pool.acquire(function (err, obj) {
+      assert.ifError(err)
+      pool.destroy(obj)
+    })
+    assert.equal(destroyCalled, true)
+    assert.equal(pool.availableObjectsCount(), 0)
+  },
+
+  'removes from available objects on validation failure': function (beforeExit) {
+    var destroyCalled = false
+    var validateCalled = false
+    var count = 0
+    var factory = {
+      name: 'test',
+      create: function (callback) { callback(null, {count: count++}) },
+      destroy: function (client) { destroyCalled = client.count },
+      validate: function (client) { validateCalled = true; return client.count > 0 },
+      max: 2,
+      idleTimeoutMillis: 100
+    }
+
+    var pool = poolModule.Pool(factory)
+    pool.acquire(function (err, obj) {
+      assert.ifError(err)
+      pool.release(obj)
+      assert.equal(obj.count, 0)
+
+      pool.acquire(function (err, obj) {
+        assert.ifError(err)
+        pool.release(obj)
+        assert.equal(obj.count, 1)
+      })
+    })
+    assert.equal(validateCalled, true)
+    assert.equal(destroyCalled, 0)
+    assert.equal(pool.availableObjectsCount(), 1)
+  },
+
+  'removes from available objects on async validation failure': function (beforeExit) {
+    var destroyCalled = false
+    var validateCalled = false
+    var count = 0
+    var factory = {
+      name: 'test',
+      create: function (callback) { callback(null, {count: count++}) },
+      destroy: function (client) { destroyCalled = client.count },
+      validateAsync: function (client, callback) { validateCalled = true; callback(client.count > 0) },
+      max: 2,
+      idleTimeoutMillis: 100
+    }
+
+    var pool = poolModule.Pool(factory)
+    pool.acquire(function (err, obj) {
+      assert.ifError(err)
+      pool.release(obj)
+      assert.equal(obj.count, 0)
+
+      pool.acquire(function (err, obj) {
+        assert.ifError(err)
+        pool.release(obj)
+        assert.equal(obj.count, 1)
+      })
+    })
+    assert.equal(validateCalled, true)
+    assert.equal(destroyCalled, 0)
+    assert.equal(pool.availableObjectsCount(), 1)
+  },
+
+  'error on setting both validate functions': function (beforeExit) {
+    var noop = function () {}
+    var factory = {
+      name: 'test',
+      create: noop,
+      destroy: noop,
+      validate: noop,
+      validateAsync: noop
+    }
+
+    try {
+      poolModule.Pool(factory)
+    } catch (err) {
+      assert.equal(err.message, 'Only one of validate or validateAsync may be specified')
+    }
+  },
+
+  'do schedule again if error occured when creating new Objects async': function (beforeExit) {
+    var factory = {
+      name: 'test',
+      create: function (callback) {
+        process.nextTick(function () {
+          var err = new Error('Create Error')
+          callback(err)
+        })
+      },
+      destroy: function (client) {},
+      max: 1,
+      idleTimeoutMillis: 100
+    }
+
+    var getFlag = 0
+    var pool = poolModule.Pool(factory)
+    pool.acquire(function () {})
+    pool.acquire(function (err, obj) {
+      getFlag = 1
+      assert(err)
+      assert.equal(pool.availableObjectsCount(), 0)
+    })
+
+    beforeExit(function () {
+      assert.equal(getFlag, 1)
+    })
+  },
+
+  'returns only valid object to the pool': function (beforeExit) {
+    var pool = poolModule.Pool({
+      name: 'test',
+      create: function (callback) {
+        process.nextTick(function () {
+          callback(null, { id: 'validId' })
+        })
+      },
+      destroy: function (client) {},
+      max: 1,
+      idleTimeoutMillis: 100
+    })
+
+    pool.acquire(function (err, obj) {
+      assert.ifError(err)
+      assert.equal(pool.availableObjectsCount(), 0)
+      assert.equal(pool.inUseObjectsCount(), 1)
+
+      // Invalid release
+      pool.release({})
+      assert.equal(pool.availableObjectsCount(), 0)
+      assert.equal(pool.inUseObjectsCount(), 1)
+
+      // Valid release
+      pool.release(obj)
+      assert.equal(pool.availableObjectsCount(), 1)
+      assert.equal(pool.inUseObjectsCount(), 0)
+    })
+  },
+
+  'validate acquires object from the pool': function (beforeExit) {
+    var pool = poolModule.Pool({
+      name: 'test',
+      create: function (callback) {
+        process.nextTick(function () {
+          callback(null, { id: 'validId' })
+        })
+      },
+      validate: function (resource) {
+        return true
+      },
+      destroy: function (client) {},
+      max: 1,
+      idleTimeoutMillis: 100
+    })
+
+    pool.acquire(function (err, obj) {
+      assert.ifError(err)
+      assert.equal(pool.availableObjectsCount(), 0)
+      assert.equal(pool.inUseObjectsCount(), 1)
+    })
+  },
+
+  'validateAsync acquires object from the pool': function (beforeExit) {
+    var pool = poolModule.Pool({
+      name: 'test',
+      create: function (callback) {
+        process.nextTick(function () {
+          callback(null, { id: 'validId' })
+        })
+      },
+      validateAsync: function (resource, callback) {
+        callback(true)
+      },
+      destroy: function (client) {},
+      max: 1,
+      idleTimeoutMillis: 100
+    })
+
+    pool.acquire(function (err, obj) {
+      assert.ifError(err)
+      assert.equal(pool.availableObjectsCount(), 0)
+      assert.equal(pool.inUseObjectsCount(), 1)
+    })
+  },
+
+  'domain context is preserved on acquire callback': function (beforeExit) {
+    var assertion_count = 0
+    var pool = poolModule.Pool({
+      name: 'test',
+      create: function (cb) {
+        cb(null, {})
+      },
+      destroy: function (client) {},
+      max: 2,
+      idleTimeoutMillis: 1000
+    })
+
+    // bail on old node versions because domains didn't exist until v0.8
+    if (process.version < 'v0.8') {
+      return
+    }
+
+    var domain = require('domain')
+
+    function check (index) {
+      var wrapDomain = domain.create()
+      wrapDomain.index = index
+
+      wrapDomain.run(function () {
+        pool.acquire(function (err, client) {
+          assert.ifError(err)
+          assert.equal(domain.active.index, index)
+          assertion_count++
+          setTimeout(function () {
+            pool.release(client)
+          }, 50)
+        })
+      })
+    }
+
+    // first two will work even without domain binding
+    check(1)
+    check(2)
+    // third and on will fail without domain binding
+    check(3)
+
+    beforeExit(function () {
+      assert.equal(assertion_count, 3)
+    })
+  }
+}
diff --git a/server/node_modules/get-caller-file/LICENSE.md b/server/node_modules/get-caller-file/LICENSE.md
new file mode 100644
index 0000000000000000000000000000000000000000..bf3e1c071bae44a0eb1a91fc1c16e1d1d55b5bc8
--- /dev/null
+++ b/server/node_modules/get-caller-file/LICENSE.md
@@ -0,0 +1,6 @@
+ISC License (ISC)
+Copyright 2018 Stefan Penner
+
+Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/server/node_modules/get-caller-file/README.md b/server/node_modules/get-caller-file/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..194492736bc4fee17e3551f3fe8a03d09650685e
--- /dev/null
+++ b/server/node_modules/get-caller-file/README.md
@@ -0,0 +1,4 @@
+# get-caller-file
+
+[![Build Status](https://travis-ci.org/stefanpenner/get-caller-file.svg?branch=master)](https://travis-ci.org/stefanpenner/get-caller-file)
+[![Build status](https://ci.appveyor.com/api/projects/status/ol2q94g1932cy14a/branch/master?svg=true)](https://ci.appveyor.com/project/embercli/get-caller-file/branch/master)
diff --git a/server/node_modules/get-caller-file/index.js b/server/node_modules/get-caller-file/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..03e7dfc39b0408ade4a763be18a5d94325100acd
--- /dev/null
+++ b/server/node_modules/get-caller-file/index.js
@@ -0,0 +1,20 @@
+'use strict';
+
+// Call this function in a another function to find out the file from
+// which that function was called from. (Inspects the v8 stack trace)
+//
+// Inspired by http://stackoverflow.com/questions/13227489
+
+module.exports = function getCallerFile(_position) {
+  var oldPrepareStackTrace = Error.prepareStackTrace;
+  Error.prepareStackTrace = function(err, stack) { return stack; };
+  var stack = new Error().stack;
+  Error.prepareStackTrace = oldPrepareStackTrace;
+
+  var position = _position ? _position : 2;
+
+  // stack[0] holds this file
+  // stack[1] holds where this function was called
+  // stack[2] holds the file we're interested in
+  return stack[position] ? stack[position].getFileName() : undefined;
+};
diff --git a/server/node_modules/get-caller-file/package.json b/server/node_modules/get-caller-file/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..9628cb033a01ed98246b9ceeb623cce292af70e8
--- /dev/null
+++ b/server/node_modules/get-caller-file/package.json
@@ -0,0 +1,58 @@
+{
+  "_from": "get-caller-file@^1.0.1",
+  "_id": "get-caller-file@1.0.3",
+  "_inBundle": false,
+  "_integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+  "_location": "/get-caller-file",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "get-caller-file@^1.0.1",
+    "name": "get-caller-file",
+    "escapedName": "get-caller-file",
+    "rawSpec": "^1.0.1",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.1"
+  },
+  "_requiredBy": [
+    "/yargs"
+  ],
+  "_resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+  "_shasum": "f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a",
+  "_spec": "get-caller-file@^1.0.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "Stefan Penner"
+  },
+  "bugs": {
+    "url": "https://github.com/stefanpenner/get-caller-file/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "[![Build Status](https://travis-ci.org/stefanpenner/get-caller-file.svg?branch=master)](https://travis-ci.org/stefanpenner/get-caller-file) [![Build status](https://ci.appveyor.com/api/projects/status/ol2q94g1932cy14a/branch/master?svg=true)](https://ci.appveyor.com/project/embercli/get-caller-file/branch/master)",
+  "devDependencies": {
+    "chai": "^4.1.2",
+    "ensure-posix-path": "^1.0.1",
+    "mocha": "^5.2.0"
+  },
+  "directories": {
+    "test": "tests"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/stefanpenner/get-caller-file#readme",
+  "license": "ISC",
+  "main": "index.js",
+  "name": "get-caller-file",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/stefanpenner/get-caller-file.git"
+  },
+  "scripts": {
+    "test": "mocha test",
+    "test:debug": "mocha test"
+  },
+  "version": "1.0.3"
+}
diff --git a/server/node_modules/graceful-fs/LICENSE b/server/node_modules/graceful-fs/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..9d2c8036969bedd4ea9041a1e154306d7424662c
--- /dev/null
+++ b/server/node_modules/graceful-fs/LICENSE
@@ -0,0 +1,15 @@
+The ISC License
+
+Copyright (c) Isaac Z. Schlueter, Ben Noordhuis, and Contributors
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/server/node_modules/graceful-fs/README.md b/server/node_modules/graceful-fs/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..5273a50ad6a52c665903443c81aaec5ad4e0dbc3
--- /dev/null
+++ b/server/node_modules/graceful-fs/README.md
@@ -0,0 +1,133 @@
+# graceful-fs
+
+graceful-fs functions as a drop-in replacement for the fs module,
+making various improvements.
+
+The improvements are meant to normalize behavior across different
+platforms and environments, and to make filesystem access more
+resilient to errors.
+
+## Improvements over [fs module](https://nodejs.org/api/fs.html)
+
+* Queues up `open` and `readdir` calls, and retries them once
+  something closes if there is an EMFILE error from too many file
+  descriptors.
+* fixes `lchmod` for Node versions prior to 0.6.2.
+* implements `fs.lutimes` if possible. Otherwise it becomes a noop.
+* ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or
+  `lchown` if the user isn't root.
+* makes `lchmod` and `lchown` become noops, if not available.
+* retries reading a file if `read` results in EAGAIN error.
+
+On Windows, it retries renaming a file for up to one second if `EACCESS`
+or `EPERM` error occurs, likely because antivirus software has locked
+the directory.
+
+## USAGE
+
+```javascript
+// use just like fs
+var fs = require('graceful-fs')
+
+// now go and do stuff with it...
+fs.readFileSync('some-file-or-whatever')
+```
+
+## Global Patching
+
+If you want to patch the global fs module (or any other fs-like
+module) you can do this:
+
+```javascript
+// Make sure to read the caveat below.
+var realFs = require('fs')
+var gracefulFs = require('graceful-fs')
+gracefulFs.gracefulify(realFs)
+```
+
+This should only ever be done at the top-level application layer, in
+order to delay on EMFILE errors from any fs-using dependencies.  You
+should **not** do this in a library, because it can cause unexpected
+delays in other parts of the program.
+
+## Changes
+
+This module is fairly stable at this point, and used by a lot of
+things.  That being said, because it implements a subtle behavior
+change in a core part of the node API, even modest changes can be
+extremely breaking, and the versioning is thus biased towards
+bumping the major when in doubt.
+
+The main change between major versions has been switching between
+providing a fully-patched `fs` module vs monkey-patching the node core
+builtin, and the approach by which a non-monkey-patched `fs` was
+created.
+
+The goal is to trade `EMFILE` errors for slower fs operations.  So, if
+you try to open a zillion files, rather than crashing, `open`
+operations will be queued up and wait for something else to `close`.
+
+There are advantages to each approach.  Monkey-patching the fs means
+that no `EMFILE` errors can possibly occur anywhere in your
+application, because everything is using the same core `fs` module,
+which is patched.  However, it can also obviously cause undesirable
+side-effects, especially if the module is loaded multiple times.
+
+Implementing a separate-but-identical patched `fs` module is more
+surgical (and doesn't run the risk of patching multiple times), but
+also imposes the challenge of keeping in sync with the core module.
+
+The current approach loads the `fs` module, and then creates a
+lookalike object that has all the same methods, except a few that are
+patched.  It is safe to use in all versions of Node from 0.8 through
+7.0.
+
+### v4
+
+* Do not monkey-patch the fs module.  This module may now be used as a
+  drop-in dep, and users can opt into monkey-patching the fs builtin
+  if their app requires it.
+
+### v3
+
+* Monkey-patch fs, because the eval approach no longer works on recent
+  node.
+* fixed possible type-error throw if rename fails on windows
+* verify that we *never* get EMFILE errors
+* Ignore ENOSYS from chmod/chown
+* clarify that graceful-fs must be used as a drop-in
+
+### v2.1.0
+
+* Use eval rather than monkey-patching fs.
+* readdir: Always sort the results
+* win32: requeue a file if error has an OK status
+
+### v2.0
+
+* A return to monkey patching
+* wrap process.cwd
+
+### v1.1
+
+* wrap readFile
+* Wrap fs.writeFile.
+* readdir protection
+* Don't clobber the fs builtin
+* Handle fs.read EAGAIN errors by trying again
+* Expose the curOpen counter
+* No-op lchown/lchmod if not implemented
+* fs.rename patch only for win32
+* Patch fs.rename to handle AV software on Windows
+* Close #4 Chown should not fail on einval or eperm if non-root
+* Fix isaacs/fstream#1 Only wrap fs one time
+* Fix #3 Start at 1024 max files, then back off on EMFILE
+* lutimes that doens't blow up on Linux
+* A full on-rewrite using a queue instead of just swallowing the EMFILE error
+* Wrap Read/Write streams as well
+
+### 1.0
+
+* Update engines for node 0.6
+* Be lstat-graceful on Windows
+* first
diff --git a/server/node_modules/graceful-fs/clone.js b/server/node_modules/graceful-fs/clone.js
new file mode 100644
index 0000000000000000000000000000000000000000..028356c96ed53635ba5291f16773ed556cb61983
--- /dev/null
+++ b/server/node_modules/graceful-fs/clone.js
@@ -0,0 +1,19 @@
+'use strict'
+
+module.exports = clone
+
+function clone (obj) {
+  if (obj === null || typeof obj !== 'object')
+    return obj
+
+  if (obj instanceof Object)
+    var copy = { __proto__: obj.__proto__ }
+  else
+    var copy = Object.create(null)
+
+  Object.getOwnPropertyNames(obj).forEach(function (key) {
+    Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key))
+  })
+
+  return copy
+}
diff --git a/server/node_modules/graceful-fs/graceful-fs.js b/server/node_modules/graceful-fs/graceful-fs.js
new file mode 100644
index 0000000000000000000000000000000000000000..8c75ee259e091162e77974efb218735337dfae8a
--- /dev/null
+++ b/server/node_modules/graceful-fs/graceful-fs.js
@@ -0,0 +1,346 @@
+var fs = require('fs')
+var polyfills = require('./polyfills.js')
+var legacy = require('./legacy-streams.js')
+var clone = require('./clone.js')
+
+var util = require('util')
+
+/* istanbul ignore next - node 0.x polyfill */
+var gracefulQueue
+var previousSymbol
+
+/* istanbul ignore else - node 0.x polyfill */
+if (typeof Symbol === 'function' && typeof Symbol.for === 'function') {
+  gracefulQueue = Symbol.for('graceful-fs.queue')
+  // This is used in testing by future versions
+  previousSymbol = Symbol.for('graceful-fs.previous')
+} else {
+  gracefulQueue = '___graceful-fs.queue'
+  previousSymbol = '___graceful-fs.previous'
+}
+
+function noop () {}
+
+var debug = noop
+if (util.debuglog)
+  debug = util.debuglog('gfs4')
+else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || ''))
+  debug = function() {
+    var m = util.format.apply(util, arguments)
+    m = 'GFS4: ' + m.split(/\n/).join('\nGFS4: ')
+    console.error(m)
+  }
+
+// Once time initialization
+if (!global[gracefulQueue]) {
+  // This queue can be shared by multiple loaded instances
+  var queue = []
+  Object.defineProperty(global, gracefulQueue, {
+    get: function() {
+      return queue
+    }
+  })
+
+  // Patch fs.close/closeSync to shared queue version, because we need
+  // to retry() whenever a close happens *anywhere* in the program.
+  // This is essential when multiple graceful-fs instances are
+  // in play at the same time.
+  fs.close = (function (fs$close) {
+    function close (fd, cb) {
+      return fs$close.call(fs, fd, function (err) {
+        // This function uses the graceful-fs shared queue
+        if (!err) {
+          retry()
+        }
+
+        if (typeof cb === 'function')
+          cb.apply(this, arguments)
+      })
+    }
+
+    Object.defineProperty(close, previousSymbol, {
+      value: fs$close
+    })
+    return close
+  })(fs.close)
+
+  fs.closeSync = (function (fs$closeSync) {
+    function closeSync (fd) {
+      // This function uses the graceful-fs shared queue
+      fs$closeSync.apply(fs, arguments)
+      retry()
+    }
+
+    Object.defineProperty(closeSync, previousSymbol, {
+      value: fs$closeSync
+    })
+    return closeSync
+  })(fs.closeSync)
+
+  if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) {
+    process.on('exit', function() {
+      debug(global[gracefulQueue])
+      require('assert').equal(global[gracefulQueue].length, 0)
+    })
+  }
+}
+
+module.exports = patch(clone(fs))
+if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
+    module.exports = patch(fs)
+    fs.__patched = true;
+}
+
+function patch (fs) {
+  // Everything that references the open() function needs to be in here
+  polyfills(fs)
+  fs.gracefulify = patch
+
+  fs.createReadStream = createReadStream
+  fs.createWriteStream = createWriteStream
+  var fs$readFile = fs.readFile
+  fs.readFile = readFile
+  function readFile (path, options, cb) {
+    if (typeof options === 'function')
+      cb = options, options = null
+
+    return go$readFile(path, options, cb)
+
+    function go$readFile (path, options, cb) {
+      return fs$readFile(path, options, function (err) {
+        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
+          enqueue([go$readFile, [path, options, cb]])
+        else {
+          if (typeof cb === 'function')
+            cb.apply(this, arguments)
+          retry()
+        }
+      })
+    }
+  }
+
+  var fs$writeFile = fs.writeFile
+  fs.writeFile = writeFile
+  function writeFile (path, data, options, cb) {
+    if (typeof options === 'function')
+      cb = options, options = null
+
+    return go$writeFile(path, data, options, cb)
+
+    function go$writeFile (path, data, options, cb) {
+      return fs$writeFile(path, data, options, function (err) {
+        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
+          enqueue([go$writeFile, [path, data, options, cb]])
+        else {
+          if (typeof cb === 'function')
+            cb.apply(this, arguments)
+          retry()
+        }
+      })
+    }
+  }
+
+  var fs$appendFile = fs.appendFile
+  if (fs$appendFile)
+    fs.appendFile = appendFile
+  function appendFile (path, data, options, cb) {
+    if (typeof options === 'function')
+      cb = options, options = null
+
+    return go$appendFile(path, data, options, cb)
+
+    function go$appendFile (path, data, options, cb) {
+      return fs$appendFile(path, data, options, function (err) {
+        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
+          enqueue([go$appendFile, [path, data, options, cb]])
+        else {
+          if (typeof cb === 'function')
+            cb.apply(this, arguments)
+          retry()
+        }
+      })
+    }
+  }
+
+  var fs$readdir = fs.readdir
+  fs.readdir = readdir
+  function readdir (path, options, cb) {
+    var args = [path]
+    if (typeof options !== 'function') {
+      args.push(options)
+    } else {
+      cb = options
+    }
+    args.push(go$readdir$cb)
+
+    return go$readdir(args)
+
+    function go$readdir$cb (err, files) {
+      if (files && files.sort)
+        files.sort()
+
+      if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
+        enqueue([go$readdir, [args]])
+
+      else {
+        if (typeof cb === 'function')
+          cb.apply(this, arguments)
+        retry()
+      }
+    }
+  }
+
+  function go$readdir (args) {
+    return fs$readdir.apply(fs, args)
+  }
+
+  if (process.version.substr(0, 4) === 'v0.8') {
+    var legStreams = legacy(fs)
+    ReadStream = legStreams.ReadStream
+    WriteStream = legStreams.WriteStream
+  }
+
+  var fs$ReadStream = fs.ReadStream
+  if (fs$ReadStream) {
+    ReadStream.prototype = Object.create(fs$ReadStream.prototype)
+    ReadStream.prototype.open = ReadStream$open
+  }
+
+  var fs$WriteStream = fs.WriteStream
+  if (fs$WriteStream) {
+    WriteStream.prototype = Object.create(fs$WriteStream.prototype)
+    WriteStream.prototype.open = WriteStream$open
+  }
+
+  Object.defineProperty(fs, 'ReadStream', {
+    get: function () {
+      return ReadStream
+    },
+    set: function (val) {
+      ReadStream = val
+    },
+    enumerable: true,
+    configurable: true
+  })
+  Object.defineProperty(fs, 'WriteStream', {
+    get: function () {
+      return WriteStream
+    },
+    set: function (val) {
+      WriteStream = val
+    },
+    enumerable: true,
+    configurable: true
+  })
+
+  // legacy names
+  var FileReadStream = ReadStream
+  Object.defineProperty(fs, 'FileReadStream', {
+    get: function () {
+      return FileReadStream
+    },
+    set: function (val) {
+      FileReadStream = val
+    },
+    enumerable: true,
+    configurable: true
+  })
+  var FileWriteStream = WriteStream
+  Object.defineProperty(fs, 'FileWriteStream', {
+    get: function () {
+      return FileWriteStream
+    },
+    set: function (val) {
+      FileWriteStream = val
+    },
+    enumerable: true,
+    configurable: true
+  })
+
+  function ReadStream (path, options) {
+    if (this instanceof ReadStream)
+      return fs$ReadStream.apply(this, arguments), this
+    else
+      return ReadStream.apply(Object.create(ReadStream.prototype), arguments)
+  }
+
+  function ReadStream$open () {
+    var that = this
+    open(that.path, that.flags, that.mode, function (err, fd) {
+      if (err) {
+        if (that.autoClose)
+          that.destroy()
+
+        that.emit('error', err)
+      } else {
+        that.fd = fd
+        that.emit('open', fd)
+        that.read()
+      }
+    })
+  }
+
+  function WriteStream (path, options) {
+    if (this instanceof WriteStream)
+      return fs$WriteStream.apply(this, arguments), this
+    else
+      return WriteStream.apply(Object.create(WriteStream.prototype), arguments)
+  }
+
+  function WriteStream$open () {
+    var that = this
+    open(that.path, that.flags, that.mode, function (err, fd) {
+      if (err) {
+        that.destroy()
+        that.emit('error', err)
+      } else {
+        that.fd = fd
+        that.emit('open', fd)
+      }
+    })
+  }
+
+  function createReadStream (path, options) {
+    return new fs.ReadStream(path, options)
+  }
+
+  function createWriteStream (path, options) {
+    return new fs.WriteStream(path, options)
+  }
+
+  var fs$open = fs.open
+  fs.open = open
+  function open (path, flags, mode, cb) {
+    if (typeof mode === 'function')
+      cb = mode, mode = null
+
+    return go$open(path, flags, mode, cb)
+
+    function go$open (path, flags, mode, cb) {
+      return fs$open(path, flags, mode, function (err, fd) {
+        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
+          enqueue([go$open, [path, flags, mode, cb]])
+        else {
+          if (typeof cb === 'function')
+            cb.apply(this, arguments)
+          retry()
+        }
+      })
+    }
+  }
+
+  return fs
+}
+
+function enqueue (elem) {
+  debug('ENQUEUE', elem[0].name, elem[1])
+  global[gracefulQueue].push(elem)
+}
+
+function retry () {
+  var elem = global[gracefulQueue].shift()
+  if (elem) {
+    debug('RETRY', elem[0].name, elem[1])
+    elem[0].apply(null, elem[1])
+  }
+}
diff --git a/server/node_modules/graceful-fs/legacy-streams.js b/server/node_modules/graceful-fs/legacy-streams.js
new file mode 100644
index 0000000000000000000000000000000000000000..d617b50fc0832dcce4ba05f7a7200938438ead90
--- /dev/null
+++ b/server/node_modules/graceful-fs/legacy-streams.js
@@ -0,0 +1,118 @@
+var Stream = require('stream').Stream
+
+module.exports = legacy
+
+function legacy (fs) {
+  return {
+    ReadStream: ReadStream,
+    WriteStream: WriteStream
+  }
+
+  function ReadStream (path, options) {
+    if (!(this instanceof ReadStream)) return new ReadStream(path, options);
+
+    Stream.call(this);
+
+    var self = this;
+
+    this.path = path;
+    this.fd = null;
+    this.readable = true;
+    this.paused = false;
+
+    this.flags = 'r';
+    this.mode = 438; /*=0666*/
+    this.bufferSize = 64 * 1024;
+
+    options = options || {};
+
+    // Mixin options into this
+    var keys = Object.keys(options);
+    for (var index = 0, length = keys.length; index < length; index++) {
+      var key = keys[index];
+      this[key] = options[key];
+    }
+
+    if (this.encoding) this.setEncoding(this.encoding);
+
+    if (this.start !== undefined) {
+      if ('number' !== typeof this.start) {
+        throw TypeError('start must be a Number');
+      }
+      if (this.end === undefined) {
+        this.end = Infinity;
+      } else if ('number' !== typeof this.end) {
+        throw TypeError('end must be a Number');
+      }
+
+      if (this.start > this.end) {
+        throw new Error('start must be <= end');
+      }
+
+      this.pos = this.start;
+    }
+
+    if (this.fd !== null) {
+      process.nextTick(function() {
+        self._read();
+      });
+      return;
+    }
+
+    fs.open(this.path, this.flags, this.mode, function (err, fd) {
+      if (err) {
+        self.emit('error', err);
+        self.readable = false;
+        return;
+      }
+
+      self.fd = fd;
+      self.emit('open', fd);
+      self._read();
+    })
+  }
+
+  function WriteStream (path, options) {
+    if (!(this instanceof WriteStream)) return new WriteStream(path, options);
+
+    Stream.call(this);
+
+    this.path = path;
+    this.fd = null;
+    this.writable = true;
+
+    this.flags = 'w';
+    this.encoding = 'binary';
+    this.mode = 438; /*=0666*/
+    this.bytesWritten = 0;
+
+    options = options || {};
+
+    // Mixin options into this
+    var keys = Object.keys(options);
+    for (var index = 0, length = keys.length; index < length; index++) {
+      var key = keys[index];
+      this[key] = options[key];
+    }
+
+    if (this.start !== undefined) {
+      if ('number' !== typeof this.start) {
+        throw TypeError('start must be a Number');
+      }
+      if (this.start < 0) {
+        throw new Error('start must be >= zero');
+      }
+
+      this.pos = this.start;
+    }
+
+    this.busy = false;
+    this._queue = [];
+
+    if (this.fd === null) {
+      this._open = fs.open;
+      this._queue.push([this._open, this.path, this.flags, this.mode, undefined]);
+      this.flush();
+    }
+  }
+}
diff --git a/server/node_modules/graceful-fs/package.json b/server/node_modules/graceful-fs/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..01b2033491a9c4dd1432d34c39c681ad54e56c9b
--- /dev/null
+++ b/server/node_modules/graceful-fs/package.json
@@ -0,0 +1,80 @@
+{
+  "_from": "graceful-fs@^4.1.2",
+  "_id": "graceful-fs@4.2.3",
+  "_inBundle": false,
+  "_integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
+  "_location": "/graceful-fs",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "graceful-fs@^4.1.2",
+    "name": "graceful-fs",
+    "escapedName": "graceful-fs",
+    "rawSpec": "^4.1.2",
+    "saveSpec": null,
+    "fetchSpec": "^4.1.2"
+  },
+  "_requiredBy": [
+    "/load-json-file",
+    "/path-type"
+  ],
+  "_resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
+  "_shasum": "4a12ff1b60376ef09862c2093edd908328be8423",
+  "_spec": "graceful-fs@^4.1.2",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/load-json-file",
+  "bugs": {
+    "url": "https://github.com/isaacs/node-graceful-fs/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "A drop-in replacement for fs, making various improvements.",
+  "devDependencies": {
+    "import-fresh": "^2.0.0",
+    "mkdirp": "^0.5.0",
+    "rimraf": "^2.2.8",
+    "tap": "^12.7.0"
+  },
+  "directories": {
+    "test": "test"
+  },
+  "files": [
+    "fs.js",
+    "graceful-fs.js",
+    "legacy-streams.js",
+    "polyfills.js",
+    "clone.js"
+  ],
+  "homepage": "https://github.com/isaacs/node-graceful-fs#readme",
+  "keywords": [
+    "fs",
+    "module",
+    "reading",
+    "retry",
+    "retries",
+    "queue",
+    "error",
+    "errors",
+    "handling",
+    "EMFILE",
+    "EAGAIN",
+    "EINVAL",
+    "EPERM",
+    "EACCESS"
+  ],
+  "license": "ISC",
+  "main": "graceful-fs.js",
+  "name": "graceful-fs",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/isaacs/node-graceful-fs.git"
+  },
+  "scripts": {
+    "postpublish": "git push origin --follow-tags",
+    "postversion": "npm publish",
+    "preversion": "npm test",
+    "test": "node test.js | tap -"
+  },
+  "version": "4.2.3"
+}
diff --git a/server/node_modules/graceful-fs/polyfills.js b/server/node_modules/graceful-fs/polyfills.js
new file mode 100644
index 0000000000000000000000000000000000000000..a5808d23f132e254a428570e7f24de7e9d7cc78a
--- /dev/null
+++ b/server/node_modules/graceful-fs/polyfills.js
@@ -0,0 +1,342 @@
+var constants = require('constants')
+
+var origCwd = process.cwd
+var cwd = null
+
+var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform
+
+process.cwd = function() {
+  if (!cwd)
+    cwd = origCwd.call(process)
+  return cwd
+}
+try {
+  process.cwd()
+} catch (er) {}
+
+var chdir = process.chdir
+process.chdir = function(d) {
+  cwd = null
+  chdir.call(process, d)
+}
+
+module.exports = patch
+
+function patch (fs) {
+  // (re-)implement some things that are known busted or missing.
+
+  // lchmod, broken prior to 0.6.2
+  // back-port the fix here.
+  if (constants.hasOwnProperty('O_SYMLINK') &&
+      process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
+    patchLchmod(fs)
+  }
+
+  // lutimes implementation, or no-op
+  if (!fs.lutimes) {
+    patchLutimes(fs)
+  }
+
+  // https://github.com/isaacs/node-graceful-fs/issues/4
+  // Chown should not fail on einval or eperm if non-root.
+  // It should not fail on enosys ever, as this just indicates
+  // that a fs doesn't support the intended operation.
+
+  fs.chown = chownFix(fs.chown)
+  fs.fchown = chownFix(fs.fchown)
+  fs.lchown = chownFix(fs.lchown)
+
+  fs.chmod = chmodFix(fs.chmod)
+  fs.fchmod = chmodFix(fs.fchmod)
+  fs.lchmod = chmodFix(fs.lchmod)
+
+  fs.chownSync = chownFixSync(fs.chownSync)
+  fs.fchownSync = chownFixSync(fs.fchownSync)
+  fs.lchownSync = chownFixSync(fs.lchownSync)
+
+  fs.chmodSync = chmodFixSync(fs.chmodSync)
+  fs.fchmodSync = chmodFixSync(fs.fchmodSync)
+  fs.lchmodSync = chmodFixSync(fs.lchmodSync)
+
+  fs.stat = statFix(fs.stat)
+  fs.fstat = statFix(fs.fstat)
+  fs.lstat = statFix(fs.lstat)
+
+  fs.statSync = statFixSync(fs.statSync)
+  fs.fstatSync = statFixSync(fs.fstatSync)
+  fs.lstatSync = statFixSync(fs.lstatSync)
+
+  // if lchmod/lchown do not exist, then make them no-ops
+  if (!fs.lchmod) {
+    fs.lchmod = function (path, mode, cb) {
+      if (cb) process.nextTick(cb)
+    }
+    fs.lchmodSync = function () {}
+  }
+  if (!fs.lchown) {
+    fs.lchown = function (path, uid, gid, cb) {
+      if (cb) process.nextTick(cb)
+    }
+    fs.lchownSync = function () {}
+  }
+
+  // on Windows, A/V software can lock the directory, causing this
+  // to fail with an EACCES or EPERM if the directory contains newly
+  // created files.  Try again on failure, for up to 60 seconds.
+
+  // Set the timeout this long because some Windows Anti-Virus, such as Parity
+  // bit9, may lock files for up to a minute, causing npm package install
+  // failures. Also, take care to yield the scheduler. Windows scheduling gives
+  // CPU to a busy looping process, which can cause the program causing the lock
+  // contention to be starved of CPU by node, so the contention doesn't resolve.
+  if (platform === "win32") {
+    fs.rename = (function (fs$rename) { return function (from, to, cb) {
+      var start = Date.now()
+      var backoff = 0;
+      fs$rename(from, to, function CB (er) {
+        if (er
+            && (er.code === "EACCES" || er.code === "EPERM")
+            && Date.now() - start < 60000) {
+          setTimeout(function() {
+            fs.stat(to, function (stater, st) {
+              if (stater && stater.code === "ENOENT")
+                fs$rename(from, to, CB);
+              else
+                cb(er)
+            })
+          }, backoff)
+          if (backoff < 100)
+            backoff += 10;
+          return;
+        }
+        if (cb) cb(er)
+      })
+    }})(fs.rename)
+  }
+
+  // if read() returns EAGAIN, then just try it again.
+  fs.read = (function (fs$read) {
+    function read (fd, buffer, offset, length, position, callback_) {
+      var callback
+      if (callback_ && typeof callback_ === 'function') {
+        var eagCounter = 0
+        callback = function (er, _, __) {
+          if (er && er.code === 'EAGAIN' && eagCounter < 10) {
+            eagCounter ++
+            return fs$read.call(fs, fd, buffer, offset, length, position, callback)
+          }
+          callback_.apply(this, arguments)
+        }
+      }
+      return fs$read.call(fs, fd, buffer, offset, length, position, callback)
+    }
+
+    // This ensures `util.promisify` works as it does for native `fs.read`.
+    read.__proto__ = fs$read
+    return read
+  })(fs.read)
+
+  fs.readSync = (function (fs$readSync) { return function (fd, buffer, offset, length, position) {
+    var eagCounter = 0
+    while (true) {
+      try {
+        return fs$readSync.call(fs, fd, buffer, offset, length, position)
+      } catch (er) {
+        if (er.code === 'EAGAIN' && eagCounter < 10) {
+          eagCounter ++
+          continue
+        }
+        throw er
+      }
+    }
+  }})(fs.readSync)
+
+  function patchLchmod (fs) {
+    fs.lchmod = function (path, mode, callback) {
+      fs.open( path
+             , constants.O_WRONLY | constants.O_SYMLINK
+             , mode
+             , function (err, fd) {
+        if (err) {
+          if (callback) callback(err)
+          return
+        }
+        // prefer to return the chmod error, if one occurs,
+        // but still try to close, and report closing errors if they occur.
+        fs.fchmod(fd, mode, function (err) {
+          fs.close(fd, function(err2) {
+            if (callback) callback(err || err2)
+          })
+        })
+      })
+    }
+
+    fs.lchmodSync = function (path, mode) {
+      var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode)
+
+      // prefer to return the chmod error, if one occurs,
+      // but still try to close, and report closing errors if they occur.
+      var threw = true
+      var ret
+      try {
+        ret = fs.fchmodSync(fd, mode)
+        threw = false
+      } finally {
+        if (threw) {
+          try {
+            fs.closeSync(fd)
+          } catch (er) {}
+        } else {
+          fs.closeSync(fd)
+        }
+      }
+      return ret
+    }
+  }
+
+  function patchLutimes (fs) {
+    if (constants.hasOwnProperty("O_SYMLINK")) {
+      fs.lutimes = function (path, at, mt, cb) {
+        fs.open(path, constants.O_SYMLINK, function (er, fd) {
+          if (er) {
+            if (cb) cb(er)
+            return
+          }
+          fs.futimes(fd, at, mt, function (er) {
+            fs.close(fd, function (er2) {
+              if (cb) cb(er || er2)
+            })
+          })
+        })
+      }
+
+      fs.lutimesSync = function (path, at, mt) {
+        var fd = fs.openSync(path, constants.O_SYMLINK)
+        var ret
+        var threw = true
+        try {
+          ret = fs.futimesSync(fd, at, mt)
+          threw = false
+        } finally {
+          if (threw) {
+            try {
+              fs.closeSync(fd)
+            } catch (er) {}
+          } else {
+            fs.closeSync(fd)
+          }
+        }
+        return ret
+      }
+
+    } else {
+      fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) }
+      fs.lutimesSync = function () {}
+    }
+  }
+
+  function chmodFix (orig) {
+    if (!orig) return orig
+    return function (target, mode, cb) {
+      return orig.call(fs, target, mode, function (er) {
+        if (chownErOk(er)) er = null
+        if (cb) cb.apply(this, arguments)
+      })
+    }
+  }
+
+  function chmodFixSync (orig) {
+    if (!orig) return orig
+    return function (target, mode) {
+      try {
+        return orig.call(fs, target, mode)
+      } catch (er) {
+        if (!chownErOk(er)) throw er
+      }
+    }
+  }
+
+
+  function chownFix (orig) {
+    if (!orig) return orig
+    return function (target, uid, gid, cb) {
+      return orig.call(fs, target, uid, gid, function (er) {
+        if (chownErOk(er)) er = null
+        if (cb) cb.apply(this, arguments)
+      })
+    }
+  }
+
+  function chownFixSync (orig) {
+    if (!orig) return orig
+    return function (target, uid, gid) {
+      try {
+        return orig.call(fs, target, uid, gid)
+      } catch (er) {
+        if (!chownErOk(er)) throw er
+      }
+    }
+  }
+
+  function statFix (orig) {
+    if (!orig) return orig
+    // Older versions of Node erroneously returned signed integers for
+    // uid + gid.
+    return function (target, options, cb) {
+      if (typeof options === 'function') {
+        cb = options
+        options = null
+      }
+      function callback (er, stats) {
+        if (stats) {
+          if (stats.uid < 0) stats.uid += 0x100000000
+          if (stats.gid < 0) stats.gid += 0x100000000
+        }
+        if (cb) cb.apply(this, arguments)
+      }
+      return options ? orig.call(fs, target, options, callback)
+        : orig.call(fs, target, callback)
+    }
+  }
+
+  function statFixSync (orig) {
+    if (!orig) return orig
+    // Older versions of Node erroneously returned signed integers for
+    // uid + gid.
+    return function (target, options) {
+      var stats = options ? orig.call(fs, target, options)
+        : orig.call(fs, target)
+      if (stats.uid < 0) stats.uid += 0x100000000
+      if (stats.gid < 0) stats.gid += 0x100000000
+      return stats;
+    }
+  }
+
+  // ENOSYS means that the fs doesn't support the op. Just ignore
+  // that, because it doesn't matter.
+  //
+  // if there's no getuid, or if getuid() is something other
+  // than 0, and the error is EINVAL or EPERM, then just ignore
+  // it.
+  //
+  // This specific case is a silent failure in cp, install, tar,
+  // and most other unix tools that manage permissions.
+  //
+  // When running as root, or if other types of errors are
+  // encountered, then it's strict.
+  function chownErOk (er) {
+    if (!er)
+      return true
+
+    if (er.code === "ENOSYS")
+      return true
+
+    var nonroot = !process.getuid || process.getuid() !== 0
+    if (nonroot) {
+      if (er.code === "EINVAL" || er.code === "EPERM")
+        return true
+    }
+
+    return false
+  }
+}
diff --git a/server/node_modules/hosted-git-info/CHANGELOG.md b/server/node_modules/hosted-git-info/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..479f24b6414eb7898e42f6f5d75726a83d72de70
--- /dev/null
+++ b/server/node_modules/hosted-git-info/CHANGELOG.md
@@ -0,0 +1,115 @@
+# Change Log
+
+All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+<a name="2.8.5"></a>
+## [2.8.5](https://github.com/npm/hosted-git-info/compare/v2.8.4...v2.8.5) (2019-10-07)
+
+
+### Bug Fixes
+
+* updated pathmatch for gitlab ([e8325b5](https://github.com/npm/hosted-git-info/commit/e8325b5)), closes [#51](https://github.com/npm/hosted-git-info/issues/51)
+* updated pathmatch for gitlab ([ffe056f](https://github.com/npm/hosted-git-info/commit/ffe056f))
+
+
+
+<a name="2.8.4"></a>
+## [2.8.4](https://github.com/npm/hosted-git-info/compare/v2.8.3...v2.8.4) (2019-08-12)
+
+
+
+<a name="2.8.3"></a>
+## [2.8.3](https://github.com/npm/hosted-git-info/compare/v2.8.2...v2.8.3) (2019-08-12)
+
+
+
+<a name="2.8.2"></a>
+## [2.8.2](https://github.com/npm/hosted-git-info/compare/v2.8.1...v2.8.2) (2019-08-05)
+
+
+### Bug Fixes
+
+* http protocol use sshurl by default ([3b1d629](https://github.com/npm/hosted-git-info/commit/3b1d629)), closes [#48](https://github.com/npm/hosted-git-info/issues/48)
+
+
+
+<a name="2.8.1"></a>
+## [2.8.1](https://github.com/npm/hosted-git-info/compare/v2.8.0...v2.8.1) (2019-08-05)
+
+
+### Bug Fixes
+
+* ignore noCommittish on tarball url generation ([5d4a8d7](https://github.com/npm/hosted-git-info/commit/5d4a8d7))
+* use gist tarball url that works for anonymous gists ([1692435](https://github.com/npm/hosted-git-info/commit/1692435))
+
+
+
+<a name="2.8.0"></a>
+# [2.8.0](https://github.com/npm/hosted-git-info/compare/v2.7.1...v2.8.0) (2019-08-05)
+
+
+### Bug Fixes
+
+* Allow slashes in gitlab project section ([bbcf7b2](https://github.com/npm/hosted-git-info/commit/bbcf7b2)), closes [#46](https://github.com/npm/hosted-git-info/issues/46) [#43](https://github.com/npm/hosted-git-info/issues/43)
+* **git-host:** disallow URI-encoded slash (%2F) in `path` ([3776fa5](https://github.com/npm/hosted-git-info/commit/3776fa5)), closes [#44](https://github.com/npm/hosted-git-info/issues/44)
+* **gitlab:** Do not URL encode slashes in project name for GitLab https URL ([cbf04f9](https://github.com/npm/hosted-git-info/commit/cbf04f9)), closes [#47](https://github.com/npm/hosted-git-info/issues/47)
+* do not allow invalid gist urls ([d5cf830](https://github.com/npm/hosted-git-info/commit/d5cf830))
+* **cache:** Switch to lru-cache to save ourselves from unlimited memory consumption ([e518222](https://github.com/npm/hosted-git-info/commit/e518222)), closes [#38](https://github.com/npm/hosted-git-info/issues/38)
+
+
+### Features
+
+* give these objects a name ([60abaea](https://github.com/npm/hosted-git-info/commit/60abaea))
+
+
+
+<a name="2.7.1"></a>
+## [2.7.1](https://github.com/npm/hosted-git-info/compare/v2.7.0...v2.7.1) (2018-07-07)
+
+
+### Bug Fixes
+
+* **index:** Guard against non-string types ([5bc580d](https://github.com/npm/hosted-git-info/commit/5bc580d))
+* **parse:** Crash on strings that parse to having no host ([c931482](https://github.com/npm/hosted-git-info/commit/c931482)), closes [#35](https://github.com/npm/hosted-git-info/issues/35)
+
+
+
+<a name="2.7.0"></a>
+# [2.7.0](https://github.com/npm/hosted-git-info/compare/v2.6.1...v2.7.0) (2018-07-06)
+
+
+### Bug Fixes
+
+* **github tarball:** update github tarballtemplate ([6efd582](https://github.com/npm/hosted-git-info/commit/6efd582)), closes [#34](https://github.com/npm/hosted-git-info/issues/34)
+* **gitlab docs:** switched to lowercase anchors for readmes ([701bcd1](https://github.com/npm/hosted-git-info/commit/701bcd1))
+
+
+### Features
+
+* **all:** Support www. prefixes on hostnames ([3349575](https://github.com/npm/hosted-git-info/commit/3349575)), closes [#32](https://github.com/npm/hosted-git-info/issues/32)
+
+
+
+<a name="2.6.1"></a>
+## [2.6.1](https://github.com/npm/hosted-git-info/compare/v2.6.0...v2.6.1) (2018-06-25)
+
+### Bug Fixes
+
+* **Revert:** "compat: remove Object.assign fallback ([#25](https://github.com/npm/hosted-git-info/issues/25))" ([cce5a62](https://github.com/npm/hosted-git-info/commit/cce5a62))
+* **Revert:** "git-host: fix forgotten extend()" ([a815ec9](https://github.com/npm/hosted-git-info/commit/a815ec9))
+
+
+
+<a name="2.6.0"></a>
+# [2.6.0](https://github.com/npm/hosted-git-info/compare/v2.5.0...v2.6.0) (2018-03-07)
+
+
+### Bug Fixes
+
+* **compat:** remove Object.assign fallback ([#25](https://github.com/npm/hosted-git-info/issues/25)) ([627ab55](https://github.com/npm/hosted-git-info/commit/627ab55))
+* **git-host:** fix forgotten extend() ([eba1f7b](https://github.com/npm/hosted-git-info/commit/eba1f7b))
+
+
+### Features
+
+* **browse:** fragment support for browse() ([#28](https://github.com/npm/hosted-git-info/issues/28)) ([cd5e5bb](https://github.com/npm/hosted-git-info/commit/cd5e5bb))
diff --git a/server/node_modules/hosted-git-info/LICENSE b/server/node_modules/hosted-git-info/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..45055763dc838d98e35b6f3bd9a94bf15218a16d
--- /dev/null
+++ b/server/node_modules/hosted-git-info/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2015, Rebecca Turner
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/server/node_modules/hosted-git-info/README.md b/server/node_modules/hosted-git-info/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7b723f6b9e2134a2cdc2399868b000adf502d270
--- /dev/null
+++ b/server/node_modules/hosted-git-info/README.md
@@ -0,0 +1,133 @@
+# hosted-git-info
+
+This will let you identify and transform various git hosts URLs between
+protocols.  It also can tell you what the URL is for the raw path for
+particular file for direct access without git.
+
+## Example
+
+```javascript
+var hostedGitInfo = require("hosted-git-info")
+var info = hostedGitInfo.fromUrl("git@github.com:npm/hosted-git-info.git", opts)
+/* info looks like:
+{
+  type: "github",
+  domain: "github.com",
+  user: "npm",
+  project: "hosted-git-info"
+}
+*/
+```
+
+If the URL can't be matched with a git host, `null` will be returned.  We
+can match git, ssh and https urls.  Additionally, we can match ssh connect
+strings (`git@github.com:npm/hosted-git-info`) and shortcuts (eg,
+`github:npm/hosted-git-info`).  Github specifically, is detected in the case
+of a third, unprefixed, form: `npm/hosted-git-info`.
+
+If it does match, the returned object has properties of:
+
+* info.type -- The short name of the service
+* info.domain -- The domain for git protocol use
+* info.user -- The name of the user/org on the git host
+* info.project -- The name of the project on the git host
+
+## Version Contract
+
+The major version will be bumped any time…
+
+* The constructor stops accepting URLs that it previously accepted.
+* A method is removed.
+* A method can no longer accept the number and type of arguments it previously accepted.
+* A method can return a different type than it currently returns.
+
+Implications:
+
+* I do not consider the specific format of the urls returned from, say
+  `.https()` to be a part of the contract.  The contract is that it will
+  return a string that can be used to fetch the repo via HTTPS.  But what
+  that string looks like, specifically, can change.
+* Dropping support for a hosted git provider would constitute a breaking
+  change.
+
+## Usage
+
+### var info = hostedGitInfo.fromUrl(gitSpecifier[, options])
+
+* *gitSpecifer* is a URL of a git repository or a SCP-style specifier of one.
+* *options* is an optional object. It can have the following properties:
+  * *noCommittish* — If true then committishes won't be included in generated URLs.
+  * *noGitPlus* — If true then `git+` won't be prefixed on URLs.
+
+## Methods
+
+All of the methods take the same options as the `fromUrl` factory.  Options
+provided to a method override those provided to the constructor.
+
+* info.file(path, opts)
+
+Given the path of a file relative to the repository, returns a URL for
+directly fetching it from the githost.  If no committish was set then
+`master` will be used as the default.
+
+For example `hostedGitInfo.fromUrl("git@github.com:npm/hosted-git-info.git#v1.0.0").file("package.json")`
+would return `https://raw.githubusercontent.com/npm/hosted-git-info/v1.0.0/package.json`
+
+* info.shortcut(opts)
+
+eg, `github:npm/hosted-git-info`
+
+* info.browse(path, fragment, opts)
+
+eg, `https://github.com/npm/hosted-git-info/tree/v1.2.0`,
+`https://github.com/npm/hosted-git-info/tree/v1.2.0/package.json`,
+`https://github.com/npm/hosted-git-info/tree/v1.2.0/REAMDE.md#supported-hosts`
+
+* info.bugs(opts)
+
+eg, `https://github.com/npm/hosted-git-info/issues`
+
+* info.docs(opts)
+
+eg, `https://github.com/npm/hosted-git-info/tree/v1.2.0#readme`
+
+* info.https(opts)
+
+eg, `git+https://github.com/npm/hosted-git-info.git`
+
+* info.sshurl(opts)
+
+eg, `git+ssh://git@github.com/npm/hosted-git-info.git`
+
+* info.ssh(opts)
+
+eg, `git@github.com:npm/hosted-git-info.git`
+
+* info.path(opts)
+
+eg, `npm/hosted-git-info`
+
+* info.tarball(opts)
+
+eg, `https://github.com/npm/hosted-git-info/archive/v1.2.0.tar.gz`
+
+* info.getDefaultRepresentation()
+
+Returns the default output type. The default output type is based on the
+string you passed in to be parsed
+
+* info.toString(opts)
+
+Uses the getDefaultRepresentation to call one of the other methods to get a URL for
+this resource. As such `hostedGitInfo.fromUrl(url).toString()` will give
+you a normalized version of the URL that still uses the same protocol.
+
+Shortcuts will still be returned as shortcuts, but the special case github
+form of `org/project` will be normalized to `github:org/project`.
+
+SSH connect strings will be normalized into `git+ssh` URLs.
+
+## Supported hosts
+
+Currently this supports Github, Bitbucket and Gitlab. Pull requests for
+additional hosts welcome.
diff --git a/server/node_modules/hosted-git-info/git-host-info.js b/server/node_modules/hosted-git-info/git-host-info.js
new file mode 100644
index 0000000000000000000000000000000000000000..8147e3348f5e8060d997e9066a73db052a6f492b
--- /dev/null
+++ b/server/node_modules/hosted-git-info/git-host-info.js
@@ -0,0 +1,79 @@
+'use strict'
+
+var gitHosts = module.exports = {
+  github: {
+    // First two are insecure and generally shouldn't be used any more, but
+    // they are still supported.
+    'protocols': [ 'git', 'http', 'git+ssh', 'git+https', 'ssh', 'https' ],
+    'domain': 'github.com',
+    'treepath': 'tree',
+    'filetemplate': 'https://{auth@}raw.githubusercontent.com/{user}/{project}/{committish}/{path}',
+    'bugstemplate': 'https://{domain}/{user}/{project}/issues',
+    'gittemplate': 'git://{auth@}{domain}/{user}/{project}.git{#committish}',
+    'tarballtemplate': 'https://codeload.{domain}/{user}/{project}/tar.gz/{committish}'
+  },
+  bitbucket: {
+    'protocols': [ 'git+ssh', 'git+https', 'ssh', 'https' ],
+    'domain': 'bitbucket.org',
+    'treepath': 'src',
+    'tarballtemplate': 'https://{domain}/{user}/{project}/get/{committish}.tar.gz'
+  },
+  gitlab: {
+    'protocols': [ 'git+ssh', 'git+https', 'ssh', 'https' ],
+    'domain': 'gitlab.com',
+    'treepath': 'tree',
+    'bugstemplate': 'https://{domain}/{user}/{project}/issues',
+    'httpstemplate': 'git+https://{auth@}{domain}/{user}/{projectPath}.git{#committish}',
+    'tarballtemplate': 'https://{domain}/{user}/{project}/repository/archive.tar.gz?ref={committish}',
+    'pathmatch': /^[/]([^/]+)[/]((?!.*(\/-\/|\/repository\/archive\.tar\.gz\?=.*|\/repository\/[^/]+\/archive.tar.gz$)).*?)(?:[.]git|[/])?$/
+  },
+  gist: {
+    'protocols': [ 'git', 'git+ssh', 'git+https', 'ssh', 'https' ],
+    'domain': 'gist.github.com',
+    'pathmatch': /^[/](?:([^/]+)[/])?([a-z0-9]{32,})(?:[.]git)?$/,
+    'filetemplate': 'https://gist.githubusercontent.com/{user}/{project}/raw{/committish}/{path}',
+    'bugstemplate': 'https://{domain}/{project}',
+    'gittemplate': 'git://{domain}/{project}.git{#committish}',
+    'sshtemplate': 'git@{domain}:/{project}.git{#committish}',
+    'sshurltemplate': 'git+ssh://git@{domain}/{project}.git{#committish}',
+    'browsetemplate': 'https://{domain}/{project}{/committish}',
+    'browsefiletemplate': 'https://{domain}/{project}{/committish}{#path}',
+    'docstemplate': 'https://{domain}/{project}{/committish}',
+    'httpstemplate': 'git+https://{domain}/{project}.git{#committish}',
+    'shortcuttemplate': '{type}:{project}{#committish}',
+    'pathtemplate': '{project}{#committish}',
+    'tarballtemplate': 'https://codeload.github.com/gist/{project}/tar.gz/{committish}',
+    'hashformat': function (fragment) {
+      return 'file-' + formatHashFragment(fragment)
+    }
+  }
+}
+
+var gitHostDefaults = {
+  'sshtemplate': 'git@{domain}:{user}/{project}.git{#committish}',
+  'sshurltemplate': 'git+ssh://git@{domain}/{user}/{project}.git{#committish}',
+  'browsetemplate': 'https://{domain}/{user}/{project}{/tree/committish}',
+  'browsefiletemplate': 'https://{domain}/{user}/{project}/{treepath}/{committish}/{path}{#fragment}',
+  'docstemplate': 'https://{domain}/{user}/{project}{/tree/committish}#readme',
+  'httpstemplate': 'git+https://{auth@}{domain}/{user}/{project}.git{#committish}',
+  'filetemplate': 'https://{domain}/{user}/{project}/raw/{committish}/{path}',
+  'shortcuttemplate': '{type}:{user}/{project}{#committish}',
+  'pathtemplate': '{user}/{project}{#committish}',
+  'pathmatch': /^[/]([^/]+)[/]([^/]+?)(?:[.]git|[/])?$/,
+  'hashformat': formatHashFragment
+}
+
+Object.keys(gitHosts).forEach(function (name) {
+  Object.keys(gitHostDefaults).forEach(function (key) {
+    if (gitHosts[name][key]) return
+    gitHosts[name][key] = gitHostDefaults[key]
+  })
+  gitHosts[name].protocols_re = RegExp('^(' +
+    gitHosts[name].protocols.map(function (protocol) {
+      return protocol.replace(/([\\+*{}()[\]$^|])/g, '\\$1')
+    }).join('|') + '):$')
+})
+
+function formatHashFragment (fragment) {
+  return fragment.toLowerCase().replace(/^\W+|\/|\W+$/g, '').replace(/\W+/g, '-')
+}
diff --git a/server/node_modules/hosted-git-info/git-host.js b/server/node_modules/hosted-git-info/git-host.js
new file mode 100644
index 0000000000000000000000000000000000000000..9616fbaa6b4af0781e21a867269fcc2d31f9b14a
--- /dev/null
+++ b/server/node_modules/hosted-git-info/git-host.js
@@ -0,0 +1,156 @@
+'use strict'
+var gitHosts = require('./git-host-info.js')
+/* eslint-disable node/no-deprecated-api */
+
+// copy-pasta util._extend from node's source, to avoid pulling
+// the whole util module into peoples' webpack bundles.
+/* istanbul ignore next */
+var extend = Object.assign || function _extend (target, source) {
+  // Don't do anything if source isn't an object
+  if (source === null || typeof source !== 'object') return target
+
+  var keys = Object.keys(source)
+  var i = keys.length
+  while (i--) {
+    target[keys[i]] = source[keys[i]]
+  }
+  return target
+}
+
+module.exports = GitHost
+function GitHost (type, user, auth, project, committish, defaultRepresentation, opts) {
+  var gitHostInfo = this
+  gitHostInfo.type = type
+  Object.keys(gitHosts[type]).forEach(function (key) {
+    gitHostInfo[key] = gitHosts[type][key]
+  })
+  gitHostInfo.user = user
+  gitHostInfo.auth = auth
+  gitHostInfo.project = project
+  gitHostInfo.committish = committish
+  gitHostInfo.default = defaultRepresentation
+  gitHostInfo.opts = opts || {}
+}
+
+GitHost.prototype.hash = function () {
+  return this.committish ? '#' + this.committish : ''
+}
+
+GitHost.prototype._fill = function (template, opts) {
+  if (!template) return
+  var vars = extend({}, opts)
+  vars.path = vars.path ? vars.path.replace(/^[/]+/g, '') : ''
+  opts = extend(extend({}, this.opts), opts)
+  var self = this
+  Object.keys(this).forEach(function (key) {
+    if (self[key] != null && vars[key] == null) vars[key] = self[key]
+  })
+  var rawAuth = vars.auth
+  var rawcommittish = vars.committish
+  var rawFragment = vars.fragment
+  var rawPath = vars.path
+  var rawProject = vars.project
+  Object.keys(vars).forEach(function (key) {
+    var value = vars[key]
+    if ((key === 'path' || key === 'project') && typeof value === 'string') {
+      vars[key] = value.split('/').map(function (pathComponent) {
+        return encodeURIComponent(pathComponent)
+      }).join('/')
+    } else {
+      vars[key] = encodeURIComponent(value)
+    }
+  })
+  vars['auth@'] = rawAuth ? rawAuth + '@' : ''
+  vars['#fragment'] = rawFragment ? '#' + this.hashformat(rawFragment) : ''
+  vars.fragment = vars.fragment ? vars.fragment : ''
+  vars['#path'] = rawPath ? '#' + this.hashformat(rawPath) : ''
+  vars['/path'] = vars.path ? '/' + vars.path : ''
+  vars.projectPath = rawProject.split('/').map(encodeURIComponent).join('/')
+  if (opts.noCommittish) {
+    vars['#committish'] = ''
+    vars['/tree/committish'] = ''
+    vars['/committish'] = ''
+    vars.committish = ''
+  } else {
+    vars['#committish'] = rawcommittish ? '#' + rawcommittish : ''
+    vars['/tree/committish'] = vars.committish
+      ? '/' + vars.treepath + '/' + vars.committish
+      : ''
+    vars['/committish'] = vars.committish ? '/' + vars.committish : ''
+    vars.committish = vars.committish || 'master'
+  }
+  var res = template
+  Object.keys(vars).forEach(function (key) {
+    res = res.replace(new RegExp('[{]' + key + '[}]', 'g'), vars[key])
+  })
+  if (opts.noGitPlus) {
+    return res.replace(/^git[+]/, '')
+  } else {
+    return res
+  }
+}
+
+GitHost.prototype.ssh = function (opts) {
+  return this._fill(this.sshtemplate, opts)
+}
+
+GitHost.prototype.sshurl = function (opts) {
+  return this._fill(this.sshurltemplate, opts)
+}
+
+GitHost.prototype.browse = function (P, F, opts) {
+  if (typeof P === 'string') {
+    if (typeof F !== 'string') {
+      opts = F
+      F = null
+    }
+    return this._fill(this.browsefiletemplate, extend({
+      fragment: F,
+      path: P
+    }, opts))
+  } else {
+    return this._fill(this.browsetemplate, P)
+  }
+}
+
+GitHost.prototype.docs = function (opts) {
+  return this._fill(this.docstemplate, opts)
+}
+
+GitHost.prototype.bugs = function (opts) {
+  return this._fill(this.bugstemplate, opts)
+}
+
+GitHost.prototype.https = function (opts) {
+  return this._fill(this.httpstemplate, opts)
+}
+
+GitHost.prototype.git = function (opts) {
+  return this._fill(this.gittemplate, opts)
+}
+
+GitHost.prototype.shortcut = function (opts) {
+  return this._fill(this.shortcuttemplate, opts)
+}
+
+GitHost.prototype.path = function (opts) {
+  return this._fill(this.pathtemplate, opts)
+}
+
+GitHost.prototype.tarball = function (opts_) {
+  var opts = extend({}, opts_, { noCommittish: false })
+  return this._fill(this.tarballtemplate, opts)
+}
+
+GitHost.prototype.file = function (P, opts) {
+  return this._fill(this.filetemplate, extend({ path: P }, opts))
+}
+
+GitHost.prototype.getDefaultRepresentation = function () {
+  return this.default
+}
+
+GitHost.prototype.toString = function (opts) {
+  if (this.default && typeof this[this.default] === 'function') return this[this.default](opts)
+  return this.sshurl(opts)
+}
diff --git a/server/node_modules/hosted-git-info/index.js b/server/node_modules/hosted-git-info/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..fc959cb0434c82120d686c0f4c5c1e87ff7fc95b
--- /dev/null
+++ b/server/node_modules/hosted-git-info/index.js
@@ -0,0 +1,125 @@
+'use strict'
+var url = require('url')
+var gitHosts = require('./git-host-info.js')
+var GitHost = module.exports = require('./git-host.js')
+
+var protocolToRepresentationMap = {
+  'git+ssh:': 'sshurl',
+  'git+https:': 'https',
+  'ssh:': 'sshurl',
+  'git:': 'git'
+}
+
+function protocolToRepresentation (protocol) {
+  return protocolToRepresentationMap[protocol] || protocol.slice(0, -1)
+}
+
+var authProtocols = {
+  'git:': true,
+  'https:': true,
+  'git+https:': true,
+  'http:': true,
+  'git+http:': true
+}
+
+var cache = {}
+
+module.exports.fromUrl = function (giturl, opts) {
+  if (typeof giturl !== 'string') return
+  var key = giturl + JSON.stringify(opts || {})
+
+  if (!(key in cache)) {
+    cache[key] = fromUrl(giturl, opts)
+  }
+
+  return cache[key]
+}
+
+function fromUrl (giturl, opts) {
+  if (giturl == null || giturl === '') return
+  var url = fixupUnqualifiedGist(
+    isGitHubShorthand(giturl) ? 'github:' + giturl : giturl
+  )
+  var parsed = parseGitUrl(url)
+  var shortcutMatch = url.match(new RegExp('^([^:]+):(?:(?:[^@:]+(?:[^@]+)?@)?([^/]*))[/](.+?)(?:[.]git)?($|#)'))
+  var matches = Object.keys(gitHosts).map(function (gitHostName) {
+    try {
+      var gitHostInfo = gitHosts[gitHostName]
+      var auth = null
+      if (parsed.auth && authProtocols[parsed.protocol]) {
+        auth = decodeURIComponent(parsed.auth)
+      }
+      var committish = parsed.hash ? decodeURIComponent(parsed.hash.substr(1)) : null
+      var user = null
+      var project = null
+      var defaultRepresentation = null
+      if (shortcutMatch && shortcutMatch[1] === gitHostName) {
+        user = shortcutMatch[2] && decodeURIComponent(shortcutMatch[2])
+        project = decodeURIComponent(shortcutMatch[3])
+        defaultRepresentation = 'shortcut'
+      } else {
+        if (parsed.host && parsed.host !== gitHostInfo.domain && parsed.host.replace(/^www[.]/, '') !== gitHostInfo.domain) return
+        if (!gitHostInfo.protocols_re.test(parsed.protocol)) return
+        if (!parsed.path) return
+        var pathmatch = gitHostInfo.pathmatch
+        var matched = parsed.path.match(pathmatch)
+        if (!matched) return
+        /* istanbul ignore else */
+        if (matched[1] !== null && matched[1] !== undefined) {
+          user = decodeURIComponent(matched[1].replace(/^:/, ''))
+        }
+        project = decodeURIComponent(matched[2])
+        defaultRepresentation = protocolToRepresentation(parsed.protocol)
+      }
+      return new GitHost(gitHostName, user, auth, project, committish, defaultRepresentation, opts)
+    } catch (ex) {
+      /* istanbul ignore else */
+      if (ex instanceof URIError) {
+      } else throw ex
+    }
+  }).filter(function (gitHostInfo) { return gitHostInfo })
+  if (matches.length !== 1) return
+  return matches[0]
+}
+
+function isGitHubShorthand (arg) {
+  // Note: This does not fully test the git ref format.
+  // See https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
+  //
+  // The only way to do this properly would be to shell out to
+  // git-check-ref-format, and as this is a fast sync function,
+  // we don't want to do that.  Just let git fail if it turns
+  // out that the commit-ish is invalid.
+  // GH usernames cannot start with . or -
+  return /^[^:@%/\s.-][^:@%/\s]*[/][^:@\s/%]+(?:#.*)?$/.test(arg)
+}
+
+function fixupUnqualifiedGist (giturl) {
+  // necessary for round-tripping gists
+  var parsed = url.parse(giturl)
+  if (parsed.protocol === 'gist:' && parsed.host && !parsed.path) {
+    return parsed.protocol + '/' + parsed.host
+  } else {
+    return giturl
+  }
+}
+
+function parseGitUrl (giturl) {
+  var matched = giturl.match(/^([^@]+)@([^:/]+):[/]?((?:[^/]+[/])?[^/]+?)(?:[.]git)?(#.*)?$/)
+  if (!matched) return url.parse(giturl)
+  return {
+    protocol: 'git+ssh:',
+    slashes: true,
+    auth: matched[1],
+    host: matched[2],
+    port: null,
+    hostname: matched[2],
+    hash: matched[4],
+    search: null,
+    query: null,
+    pathname: '/' + matched[3],
+    path: '/' + matched[3],
+    href: 'git+ssh://' + matched[1] + '@' + matched[2] +
+          '/' + matched[3] + (matched[4] || '')
+  }
+}
diff --git a/server/node_modules/hosted-git-info/package.json b/server/node_modules/hosted-git-info/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..eeff7c1e9a428f2cc472d0fb4020b6c862d91400
--- /dev/null
+++ b/server/node_modules/hosted-git-info/package.json
@@ -0,0 +1,69 @@
+{
+  "_from": "hosted-git-info@^2.1.4",
+  "_id": "hosted-git-info@2.8.5",
+  "_inBundle": false,
+  "_integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
+  "_location": "/hosted-git-info",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "hosted-git-info@^2.1.4",
+    "name": "hosted-git-info",
+    "escapedName": "hosted-git-info",
+    "rawSpec": "^2.1.4",
+    "saveSpec": null,
+    "fetchSpec": "^2.1.4"
+  },
+  "_requiredBy": [
+    "/normalize-package-data"
+  ],
+  "_resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
+  "_shasum": "759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c",
+  "_spec": "hosted-git-info@^2.1.4",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/normalize-package-data",
+  "author": {
+    "name": "Rebecca Turner",
+    "email": "me@re-becca.org",
+    "url": "http://re-becca.org"
+  },
+  "bugs": {
+    "url": "https://github.com/npm/hosted-git-info/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Provides metadata and conversions from repository urls for Github, Bitbucket and Gitlab",
+  "devDependencies": {
+    "standard": "^11.0.1",
+    "standard-version": "^4.4.0",
+    "tap": "^12.7.0"
+  },
+  "files": [
+    "index.js",
+    "git-host.js",
+    "git-host-info.js"
+  ],
+  "homepage": "https://github.com/npm/hosted-git-info",
+  "keywords": [
+    "git",
+    "github",
+    "bitbucket",
+    "gitlab"
+  ],
+  "license": "ISC",
+  "main": "index.js",
+  "name": "hosted-git-info",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/npm/hosted-git-info.git"
+  },
+  "scripts": {
+    "postrelease": "npm publish --tag=ancient-legacy-fixes && git push --follow-tags",
+    "prerelease": "npm t",
+    "pretest": "standard",
+    "release": "standard-version -s",
+    "test": "tap -J --100 --no-esm test/*.js",
+    "test:coverage": "tap --coverage-report=html -J --100 --no-esm test/*.js"
+  },
+  "version": "2.8.5"
+}
diff --git a/server/node_modules/invert-kv/index.js b/server/node_modules/invert-kv/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..61e21961128f716cab2753826bbb61dbf491f4e2
--- /dev/null
+++ b/server/node_modules/invert-kv/index.js
@@ -0,0 +1,15 @@
+'use strict';
+module.exports = function (obj) {
+	if (typeof obj !== 'object') {
+		throw new TypeError('Expected an object');
+	}
+
+	var ret = {};
+
+	for (var key in obj) {
+		var val = obj[key];
+		ret[val] = key;
+	}
+
+	return ret;
+};
diff --git a/server/node_modules/invert-kv/package.json b/server/node_modules/invert-kv/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..ebc0e5e69fa32af680b8336a2a3f181829bf08b3
--- /dev/null
+++ b/server/node_modules/invert-kv/package.json
@@ -0,0 +1,65 @@
+{
+  "_from": "invert-kv@^1.0.0",
+  "_id": "invert-kv@1.0.0",
+  "_inBundle": false,
+  "_integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
+  "_location": "/invert-kv",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "invert-kv@^1.0.0",
+    "name": "invert-kv",
+    "escapedName": "invert-kv",
+    "rawSpec": "^1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.0"
+  },
+  "_requiredBy": [
+    "/lcid"
+  ],
+  "_resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+  "_shasum": "104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6",
+  "_spec": "invert-kv@^1.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/lcid",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "http://sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/invert-kv/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Invert the key/value of an object. Example: {foo: 'bar'} → {bar: 'foo'}",
+  "devDependencies": {
+    "mocha": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/invert-kv#readme",
+  "keywords": [
+    "object",
+    "obj",
+    "key",
+    "value",
+    "val",
+    "kv",
+    "invert"
+  ],
+  "license": "MIT",
+  "name": "invert-kv",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/invert-kv.git"
+  },
+  "scripts": {
+    "test": "mocha"
+  },
+  "version": "1.0.0"
+}
diff --git a/server/node_modules/invert-kv/readme.md b/server/node_modules/invert-kv/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..039fc7cfa25b015ceefc639935023a4b85dfbe16
--- /dev/null
+++ b/server/node_modules/invert-kv/readme.md
@@ -0,0 +1,25 @@
+# invert-kv [![Build Status](https://travis-ci.org/sindresorhus/invert-kv.svg?branch=master)](https://travis-ci.org/sindresorhus/invert-kv)
+
+> Invert the key/value of an object. Example: `{foo: 'bar'}` → `{bar: 'foo'}`
+
+
+## Install
+
+```sh
+$ npm install --save invert-kv
+```
+
+
+## Usage
+
+```js
+var invertKv = require('invert-kv');
+
+invertKv({foo: 'bar', unicorn: 'rainbow'});
+//=> {bar: 'foo', rainbow: 'unicorn'}
+```
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/is-arrayish/.editorconfig b/server/node_modules/is-arrayish/.editorconfig
new file mode 100644
index 0000000000000000000000000000000000000000..4c017f8ad214943ae5b33bb361a6c2d89a0a72fa
--- /dev/null
+++ b/server/node_modules/is-arrayish/.editorconfig
@@ -0,0 +1,18 @@
+root = true
+
+[*]
+indent_style = tab
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.coffee]
+indent_style = space
+
+[{package.json,*.yml}]
+indent_style = space
+indent_size = 2
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/server/node_modules/is-arrayish/.istanbul.yml b/server/node_modules/is-arrayish/.istanbul.yml
new file mode 100644
index 0000000000000000000000000000000000000000..19fbec32b851dba9b1d32506d6e9a191b0eb24c2
--- /dev/null
+++ b/server/node_modules/is-arrayish/.istanbul.yml
@@ -0,0 +1,4 @@
+instrumentation:
+  excludes:
+    - test.js
+    - test/**/*
diff --git a/server/node_modules/is-arrayish/.npmignore b/server/node_modules/is-arrayish/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..8d5eacb3ef6d5369abebd00d5e589cacdc9e0f0b
--- /dev/null
+++ b/server/node_modules/is-arrayish/.npmignore
@@ -0,0 +1,5 @@
+/coverage/
+/test.js
+/test/
+*.sw[a-p]
+/node_modules/
diff --git a/server/node_modules/is-arrayish/.travis.yml b/server/node_modules/is-arrayish/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5a0424350edc7e4c8b4657c79f30261eb6eb1c64
--- /dev/null
+++ b/server/node_modules/is-arrayish/.travis.yml
@@ -0,0 +1,17 @@
+language: node_js
+
+script:
+  - node_modules/.bin/istanbul cover node_modules/.bin/_mocha -- --compilers coffee:coffee-script/register
+  - cat coverage/lcov.info | node_modules/.bin/coveralls
+node_js:
+  - "0.10"
+  - "0.11"
+  - "0.12"
+  - "iojs"
+os:
+  - linux
+  - osx
+
+notifications:
+  slack:
+    secure: oOt8QGzdrPDsTMcyahtIq5Q+0U1iwfgJgFCxBLsomQ0bpIMn+y5m4viJydA2UinHPGc944HS3LMZS9iKQyv+DjTgbhUyNXqeVjtxCwRe37f5rKQlXVvdfmjHk2kln4H8DcK3r5Qd/+2hd9BeMsp2GImTrkRSud1CZQlhhe5IgZOboSoWpGVMMy1iazWT06tAtiB2LRVhmsdUaFZDWAhGZ+UAvCPf+mnBOAylIj+U0GDrofhfTi25RK0gddG2f/p2M1HCu49O6wECGWkt2hVei233DkNJyLLLJVcvmhf+aXkV5TjMyaoxh/HdcV4DrA7KvYuWmWWKsINa9hlwAsdd/FYmJ6PjRkKWas2JoQ1C+qOzDxyQvn3CaUZFKD99pdsq0rBBZujqXQKZZ/hWb/CE74BI6fKmqQkiEPaD/7uADj04FEg6HVBZaMCyauOaK5b3VC97twbALZ1qVxYV6mU+zSEvnUbpnjjvRO0fSl9ZHA+rzkW73kX3GmHY0wAozEZbSy7QLuZlQ2QtHmBLr+APaGMdL1sFF9qFfzqKy0WDbSE0WS6hpAEJpTsjYmeBrnI8UmK3m++iEgyQPvZoH9LhUT+ek7XIfHZMe04BmC6wuO24/RfpmR6bQK9VMarFCYlBiWxg/z30vkP0KTpUi3o/cqFm7/Noxc0i2LVqM3E0Sy4=
diff --git a/server/node_modules/is-arrayish/LICENSE b/server/node_modules/is-arrayish/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..0a5f461a6930323a7ca4e0acfd28043323805316
--- /dev/null
+++ b/server/node_modules/is-arrayish/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 JD Ballard
+
+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.
diff --git a/server/node_modules/is-arrayish/README.md b/server/node_modules/is-arrayish/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7d360724c01518ad6ad60766838d2ef3625e50f4
--- /dev/null
+++ b/server/node_modules/is-arrayish/README.md
@@ -0,0 +1,16 @@
+# node-is-arrayish [![Travis-CI.org Build Status](https://img.shields.io/travis/Qix-/node-is-arrayish.svg?style=flat-square)](https://travis-ci.org/Qix-/node-is-arrayish) [![Coveralls.io Coverage Rating](https://img.shields.io/coveralls/Qix-/node-is-arrayish.svg?style=flat-square)](https://coveralls.io/r/Qix-/node-is-arrayish)
+> Determines if an object can be used like an Array
+
+## Example
+```javascript
+var isArrayish = require('is-arrayish');
+
+isArrayish([]); // true
+isArrayish({__proto__: []}); // true
+isArrayish({}); // false
+isArrayish({length:10}); // false
+```
+
+## License
+Licensed under the [MIT License](http://opensource.org/licenses/MIT).
+You can find a copy of it in [LICENSE](LICENSE).
diff --git a/server/node_modules/is-arrayish/index.js b/server/node_modules/is-arrayish/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b971868b6668b0397bf90d446476c8468901c52
--- /dev/null
+++ b/server/node_modules/is-arrayish/index.js
@@ -0,0 +1,10 @@
+'use strict';
+
+module.exports = function isArrayish(obj) {
+	if (!obj) {
+		return false;
+	}
+
+	return obj instanceof Array || Array.isArray(obj) ||
+		(obj.length >= 0 && obj.splice instanceof Function);
+};
diff --git a/server/node_modules/is-arrayish/package.json b/server/node_modules/is-arrayish/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..4f76d0267fb18f765c15ac0a069c5bc30a3d4e4c
--- /dev/null
+++ b/server/node_modules/is-arrayish/package.json
@@ -0,0 +1,66 @@
+{
+  "_from": "is-arrayish@^0.2.1",
+  "_id": "is-arrayish@0.2.1",
+  "_inBundle": false,
+  "_integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+  "_location": "/is-arrayish",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "is-arrayish@^0.2.1",
+    "name": "is-arrayish",
+    "escapedName": "is-arrayish",
+    "rawSpec": "^0.2.1",
+    "saveSpec": null,
+    "fetchSpec": "^0.2.1"
+  },
+  "_requiredBy": [
+    "/error-ex"
+  ],
+  "_resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+  "_shasum": "77c99840527aa8ecb1a8ba697b80645a7a926a9d",
+  "_spec": "is-arrayish@^0.2.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/error-ex",
+  "author": {
+    "name": "Qix",
+    "url": "http://github.com/qix-"
+  },
+  "bugs": {
+    "url": "https://github.com/qix-/node-is-arrayish/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Determines if an object can be used as an array",
+  "devDependencies": {
+    "coffee-script": "^1.9.3",
+    "coveralls": "^2.11.2",
+    "istanbul": "^0.3.17",
+    "mocha": "^2.2.5",
+    "should": "^7.0.1",
+    "xo": "^0.6.1"
+  },
+  "homepage": "https://github.com/qix-/node-is-arrayish#readme",
+  "keywords": [
+    "is",
+    "array",
+    "duck",
+    "type",
+    "arrayish",
+    "similar",
+    "proto",
+    "prototype",
+    "type"
+  ],
+  "license": "MIT",
+  "name": "is-arrayish",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/qix-/node-is-arrayish.git"
+  },
+  "scripts": {
+    "pretest": "xo",
+    "test": "mocha --compilers coffee:coffee-script/register"
+  },
+  "version": "0.2.1"
+}
diff --git a/server/node_modules/is-utf8/LICENSE b/server/node_modules/is-utf8/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..2c8d4b9990f16b58aaebbd6d83e8e3628e851c27
--- /dev/null
+++ b/server/node_modules/is-utf8/LICENSE
@@ -0,0 +1,9 @@
+The MIT License (MIT)
+
+Copyright (C) 2014 Wei Fanzhe
+
+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.
diff --git a/server/node_modules/is-utf8/README.md b/server/node_modules/is-utf8/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..b62ddde1c42fe44a98a1848eeb88d40e1e12b16d
--- /dev/null
+++ b/server/node_modules/is-utf8/README.md
@@ -0,0 +1,16 @@
+#utf8 detector
+
+Detect if a Buffer is utf8 encoded. 
+It need The minimum amount of bytes is 4.
+
+
+```javascript
+    var fs = require('fs');
+    var isUtf8 = require('is-utf8');
+    var ansi = fs.readFileSync('ansi.txt');
+    var utf8 = fs.readFileSync('utf8.txt');
+    
+    console.log('ansi.txt is utf8: '+isUtf8(ansi)); //false
+    console.log('utf8.txt is utf8: '+isUtf8(utf8)); //true
+```
+    
diff --git a/server/node_modules/is-utf8/is-utf8.js b/server/node_modules/is-utf8/is-utf8.js
new file mode 100644
index 0000000000000000000000000000000000000000..8a5f15d13602b8afaa84fc337fb4d4577eeda11d
--- /dev/null
+++ b/server/node_modules/is-utf8/is-utf8.js
@@ -0,0 +1,76 @@
+
+exports = module.exports = function(bytes)
+{
+    var i = 0;
+    while(i < bytes.length)
+    {
+        if(     (// ASCII
+                    bytes[i] == 0x09 ||
+                    bytes[i] == 0x0A ||
+                    bytes[i] == 0x0D ||
+                    (0x20 <= bytes[i] && bytes[i] <= 0x7E)
+                )
+          ) {
+              i += 1;
+              continue;
+          }
+
+        if(     (// non-overlong 2-byte
+                    (0xC2 <= bytes[i] && bytes[i] <= 0xDF) &&
+                    (0x80 <= bytes[i+1] && bytes[i+1] <= 0xBF)
+                )
+          ) {
+              i += 2;
+              continue;
+          }
+
+        if(     (// excluding overlongs
+                    bytes[i] == 0xE0 &&
+                    (0xA0 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
+                    (0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF)
+                ) ||
+                (// straight 3-byte
+                 ((0xE1 <= bytes[i] && bytes[i] <= 0xEC) ||
+                  bytes[i] == 0xEE ||
+                  bytes[i] == 0xEF) &&
+                 (0x80 <= bytes[i + 1] && bytes[i+1] <= 0xBF) &&
+                 (0x80 <= bytes[i+2] && bytes[i+2] <= 0xBF)
+                ) ||
+                (// excluding surrogates
+                 bytes[i] == 0xED &&
+                 (0x80 <= bytes[i+1] && bytes[i+1] <= 0x9F) &&
+                 (0x80 <= bytes[i+2] && bytes[i+2] <= 0xBF)
+                )
+          ) {
+              i += 3;
+              continue;
+          }
+
+        if(     (// planes 1-3
+                    bytes[i] == 0xF0 &&
+                    (0x90 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
+                    (0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
+                    (0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
+                ) ||
+                (// planes 4-15
+                 (0xF1 <= bytes[i] && bytes[i] <= 0xF3) &&
+                 (0x80 <= bytes[i + 1] && bytes[i + 1] <= 0xBF) &&
+                 (0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
+                 (0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
+                ) ||
+                (// plane 16
+                 bytes[i] == 0xF4 &&
+                 (0x80 <= bytes[i + 1] && bytes[i + 1] <= 0x8F) &&
+                 (0x80 <= bytes[i + 2] && bytes[i + 2] <= 0xBF) &&
+                 (0x80 <= bytes[i + 3] && bytes[i + 3] <= 0xBF)
+                )
+          ) {
+              i += 4;
+              continue;
+          }
+
+        return false;
+    }
+
+    return true;
+}
diff --git a/server/node_modules/is-utf8/package.json b/server/node_modules/is-utf8/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..678bce3a3905c809592e719b8da33c933aba7518
--- /dev/null
+++ b/server/node_modules/is-utf8/package.json
@@ -0,0 +1,53 @@
+{
+  "_from": "is-utf8@^0.2.0",
+  "_id": "is-utf8@0.2.1",
+  "_inBundle": false,
+  "_integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+  "_location": "/is-utf8",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "is-utf8@^0.2.0",
+    "name": "is-utf8",
+    "escapedName": "is-utf8",
+    "rawSpec": "^0.2.0",
+    "saveSpec": null,
+    "fetchSpec": "^0.2.0"
+  },
+  "_requiredBy": [
+    "/strip-bom"
+  ],
+  "_resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+  "_shasum": "4b0da1442104d1b336340e80797e865cf39f7d72",
+  "_spec": "is-utf8@^0.2.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/strip-bom",
+  "author": {
+    "name": "wayfind"
+  },
+  "bugs": {
+    "url": "https://github.com/wayfind/is-utf8/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Detect if a buffer is utf8 encoded.",
+  "files": [
+    "is-utf8.js"
+  ],
+  "homepage": "https://github.com/wayfind/is-utf8#readme",
+  "keywords": [
+    "utf8",
+    "charset"
+  ],
+  "license": "MIT",
+  "main": "is-utf8.js",
+  "name": "is-utf8",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/wayfind/is-utf8.git"
+  },
+  "scripts": {
+    "test": "node test.js"
+  },
+  "version": "0.2.1"
+}
diff --git a/server/node_modules/js-string-escape/CHANGELOG.md b/server/node_modules/js-string-escape/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..4318bf933300f95e7e2244e169f4b5d709c5cf5c
--- /dev/null
+++ b/server/node_modules/js-string-escape/CHANGELOG.md
@@ -0,0 +1,13 @@
+# master
+
+# 1.0.1
+
+* Exclude unused files from npm distribution
+
+# 1.0.0
+
+* No change; version bumped to indicate that this package is considered stable
+
+# 0.0.1
+
+* Initial release
diff --git a/server/node_modules/js-string-escape/LICENSE b/server/node_modules/js-string-escape/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..4ce04998167c2f1822aae8ea859e3b683b00d544
--- /dev/null
+++ b/server/node_modules/js-string-escape/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Jo Liss
+
+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.
diff --git a/server/node_modules/js-string-escape/README.md b/server/node_modules/js-string-escape/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..3147c1b346e8f31afa67cef24989e53bbcd69242
--- /dev/null
+++ b/server/node_modules/js-string-escape/README.md
@@ -0,0 +1,44 @@
+# js-string-escape
+
+[![Build Status](https://travis-ci.org/joliss/js-string-escape.png?branch=master)](https://travis-ci.org/joliss/js-string-escape)
+
+Escape any string to be a valid JavaScript string literal between double
+quotes or single quotes.
+
+## Installation
+
+```
+npm install js-string-escape
+```
+
+## Example
+
+If you need to generate JavaScript output, this library will help you safely
+put arbitrary data in JavaScript strings:
+
+```js
+jsStringEscape = require('js-string-escape')
+
+console.log('"' + jsStringEscape('Quotes (\", \'), newlines (\n), etc.') + '"')
+// => "Quotes (\", \'), newlines (\n), etc."
+```
+
+In other words, given any string `s`, the following invariants hold:
+
+```js
+eval('"' + jsStringEscape(s) + '"') === s
+eval("'" + jsStringEscape(s) + "'") === s
+```
+
+These `eval` expressions are safe with untrusted strings `s`.
+
+Non-strings will be cast to strings.
+
+## Compliance
+
+This library has been checked against [ECMAScript
+5.1](http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4) and tested
+against all Unicode code points.
+
+Note that the returned string is not necessarily valid JSON, since JSON
+disallows control characters, and `\'` is illegal in JSON.
diff --git a/server/node_modules/js-string-escape/index.js b/server/node_modules/js-string-escape/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..256fdf4dc90ee1c998aada1f473350ed2bd8a8b2
--- /dev/null
+++ b/server/node_modules/js-string-escape/index.js
@@ -0,0 +1,22 @@
+module.exports = function (string) {
+  return ('' + string).replace(/["'\\\n\r\u2028\u2029]/g, function (character) {
+    // Escape all characters not included in SingleStringCharacters and
+    // DoubleStringCharacters on
+    // http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
+    switch (character) {
+      case '"':
+      case "'":
+      case '\\':
+        return '\\' + character
+      // Four possible LineTerminator characters need to be escaped:
+      case '\n':
+        return '\\n'
+      case '\r':
+        return '\\r'
+      case '\u2028':
+        return '\\u2028'
+      case '\u2029':
+        return '\\u2029'
+    }
+  })
+}
diff --git a/server/node_modules/js-string-escape/package.json b/server/node_modules/js-string-escape/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..adcee5f6f969a7b2beab5d3b4f10dba44e2aea80
--- /dev/null
+++ b/server/node_modules/js-string-escape/package.json
@@ -0,0 +1,70 @@
+{
+  "_from": "js-string-escape@1.0.1",
+  "_id": "js-string-escape@1.0.1",
+  "_inBundle": false,
+  "_integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=",
+  "_location": "/js-string-escape",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "js-string-escape@1.0.1",
+    "name": "js-string-escape",
+    "escapedName": "js-string-escape",
+    "rawSpec": "1.0.1",
+    "saveSpec": null,
+    "fetchSpec": "1.0.1"
+  },
+  "_requiredBy": [
+    "/pgtools/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",
+  "_shasum": "e2625badbc0d67c7533e9edc1068c587ae4137ef",
+  "_spec": "js-string-escape@1.0.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgtools/node_modules/pg",
+  "author": {
+    "name": "Jo Liss",
+    "email": "joliss42@gmail.com"
+  },
+  "bugs": {
+    "url": "https://github.com/joliss/js-string-escape/issues"
+  },
+  "bundleDependencies": false,
+  "contributors": [
+    {
+      "name": "Mathias Bynens",
+      "url": "http://mathiasbynens.be/"
+    }
+  ],
+  "deprecated": false,
+  "description": "Escape strings for use as JavaScript string literals",
+  "devDependencies": {
+    "punycode": "~> 1.2.1",
+    "tap": "~> 0.4.2"
+  },
+  "engines": {
+    "node": ">= 0.8"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/joliss/js-string-escape#readme",
+  "keywords": [
+    "string",
+    "escape",
+    "backslash",
+    "javascript",
+    "ecmascript"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "js-string-escape",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/joliss/js-string-escape.git"
+  },
+  "scripts": {
+    "test": "tap test"
+  },
+  "version": "1.0.1"
+}
diff --git a/server/node_modules/lcid/index.js b/server/node_modules/lcid/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..69bd3d231e0594197c8f30c33f17b7e98985b1d6
--- /dev/null
+++ b/server/node_modules/lcid/index.js
@@ -0,0 +1,22 @@
+'use strict';
+var invertKv = require('invert-kv');
+var all = require('./lcid.json');
+var inverted = invertKv(all);
+
+exports.from = function (lcidCode) {
+	if (typeof lcidCode !== 'number') {
+		throw new TypeError('Expected a number');
+	}
+
+	return inverted[lcidCode];
+};
+
+exports.to = function (localeId) {
+	if (typeof localeId !== 'string') {
+		throw new TypeError('Expected a string');
+	}
+
+	return all[localeId];
+};
+
+exports.all = all;
diff --git a/server/node_modules/lcid/lcid.json b/server/node_modules/lcid/lcid.json
new file mode 100644
index 0000000000000000000000000000000000000000..9c89f6a496548d7856ecf0a91d0897d5f641dacc
--- /dev/null
+++ b/server/node_modules/lcid/lcid.json
@@ -0,0 +1,203 @@
+{
+	"af_ZA": 1078,
+	"am_ET": 1118,
+	"ar_AE": 14337,
+	"ar_BH": 15361,
+	"ar_DZ": 5121,
+	"ar_EG": 3073,
+	"ar_IQ": 2049,
+	"ar_JO": 11265,
+	"ar_KW": 13313,
+	"ar_LB": 12289,
+	"ar_LY": 4097,
+	"ar_MA": 6145,
+	"ar_OM": 8193,
+	"ar_QA": 16385,
+	"ar_SA": 1025,
+	"ar_SY": 10241,
+	"ar_TN": 7169,
+	"ar_YE": 9217,
+	"arn_CL": 1146,
+	"as_IN": 1101,
+	"az_AZ": 2092,
+	"ba_RU": 1133,
+	"be_BY": 1059,
+	"bg_BG": 1026,
+	"bn_IN": 1093,
+	"bo_BT": 2129,
+	"bo_CN": 1105,
+	"br_FR": 1150,
+	"bs_BA": 8218,
+	"ca_ES": 1027,
+	"co_FR": 1155,
+	"cs_CZ": 1029,
+	"cy_GB": 1106,
+	"da_DK": 1030,
+	"de_AT": 3079,
+	"de_CH": 2055,
+	"de_DE": 1031,
+	"de_LI": 5127,
+	"de_LU": 4103,
+	"div_MV": 1125,
+	"dsb_DE": 2094,
+	"el_GR": 1032,
+	"en_AU": 3081,
+	"en_BZ": 10249,
+	"en_CA": 4105,
+	"en_CB": 9225,
+	"en_GB": 2057,
+	"en_IE": 6153,
+	"en_IN": 18441,
+	"en_JA": 8201,
+	"en_MY": 17417,
+	"en_NZ": 5129,
+	"en_PH": 13321,
+	"en_TT": 11273,
+	"en_US": 1033,
+	"en_ZA": 7177,
+	"en_ZW": 12297,
+	"es_AR": 11274,
+	"es_BO": 16394,
+	"es_CL": 13322,
+	"es_CO": 9226,
+	"es_CR": 5130,
+	"es_DO": 7178,
+	"es_EC": 12298,
+	"es_ES": 3082,
+	"es_GT": 4106,
+	"es_HN": 18442,
+	"es_MX": 2058,
+	"es_NI": 19466,
+	"es_PA": 6154,
+	"es_PE": 10250,
+	"es_PR": 20490,
+	"es_PY": 15370,
+	"es_SV": 17418,
+	"es_UR": 14346,
+	"es_US": 21514,
+	"es_VE": 8202,
+	"et_EE": 1061,
+	"eu_ES": 1069,
+	"fa_IR": 1065,
+	"fi_FI": 1035,
+	"fil_PH": 1124,
+	"fo_FO": 1080,
+	"fr_BE": 2060,
+	"fr_CA": 3084,
+	"fr_CH": 4108,
+	"fr_FR": 1036,
+	"fr_LU": 5132,
+	"fr_MC": 6156,
+	"fy_NL": 1122,
+	"ga_IE": 2108,
+	"gbz_AF": 1164,
+	"gl_ES": 1110,
+	"gsw_FR": 1156,
+	"gu_IN": 1095,
+	"ha_NG": 1128,
+	"he_IL": 1037,
+	"hi_IN": 1081,
+	"hr_BA": 4122,
+	"hr_HR": 1050,
+	"hu_HU": 1038,
+	"hy_AM": 1067,
+	"id_ID": 1057,
+	"ii_CN": 1144,
+	"is_IS": 1039,
+	"it_CH": 2064,
+	"it_IT": 1040,
+	"iu_CA": 2141,
+	"ja_JP": 1041,
+	"ka_GE": 1079,
+	"kh_KH": 1107,
+	"kk_KZ": 1087,
+	"kl_GL": 1135,
+	"kn_IN": 1099,
+	"ko_KR": 1042,
+	"kok_IN": 1111,
+	"ky_KG": 1088,
+	"lb_LU": 1134,
+	"lo_LA": 1108,
+	"lt_LT": 1063,
+	"lv_LV": 1062,
+	"mi_NZ": 1153,
+	"mk_MK": 1071,
+	"ml_IN": 1100,
+	"mn_CN": 2128,
+	"mn_MN": 1104,
+	"moh_CA": 1148,
+	"mr_IN": 1102,
+	"ms_BN": 2110,
+	"ms_MY": 1086,
+	"mt_MT": 1082,
+	"my_MM": 1109,
+	"nb_NO": 1044,
+	"ne_NP": 1121,
+	"nl_BE": 2067,
+	"nl_NL": 1043,
+	"nn_NO": 2068,
+	"ns_ZA": 1132,
+	"oc_FR": 1154,
+	"or_IN": 1096,
+	"pa_IN": 1094,
+	"pl_PL": 1045,
+	"ps_AF": 1123,
+	"pt_BR": 1046,
+	"pt_PT": 2070,
+	"qut_GT": 1158,
+	"quz_BO": 1131,
+	"quz_EC": 2155,
+	"quz_PE": 3179,
+	"rm_CH": 1047,
+	"ro_RO": 1048,
+	"ru_RU": 1049,
+	"rw_RW": 1159,
+	"sa_IN": 1103,
+	"sah_RU": 1157,
+	"se_FI": 3131,
+	"se_NO": 1083,
+	"se_SE": 2107,
+	"si_LK": 1115,
+	"sk_SK": 1051,
+	"sl_SI": 1060,
+	"sma_NO": 6203,
+	"sma_SE": 7227,
+	"smj_NO": 4155,
+	"smj_SE": 5179,
+	"smn_FI": 9275,
+	"sms_FI": 8251,
+	"sq_AL": 1052,
+	"sr_BA": 7194,
+	"sr_SP": 3098,
+	"sv_FI": 2077,
+	"sv_SE": 1053,
+	"sw_KE": 1089,
+	"syr_SY": 1114,
+	"ta_IN": 1097,
+	"te_IN": 1098,
+	"tg_TJ": 1064,
+	"th_TH": 1054,
+	"tk_TM": 1090,
+	"tmz_DZ": 2143,
+	"tn_ZA": 1074,
+	"tr_TR": 1055,
+	"tt_RU": 1092,
+	"ug_CN": 1152,
+	"uk_UA": 1058,
+	"ur_IN": 2080,
+	"ur_PK": 1056,
+	"uz_UZ": 2115,
+	"vi_VN": 1066,
+	"wen_DE": 1070,
+	"wo_SN": 1160,
+	"xh_ZA": 1076,
+	"yo_NG": 1130,
+	"zh_CHS": 4,
+	"zh_CHT": 31748,
+	"zh_CN": 2052,
+	"zh_HK": 3076,
+	"zh_MO": 5124,
+	"zh_SG": 4100,
+	"zh_TW": 1028,
+	"zu_ZA": 1077
+}
diff --git a/server/node_modules/lcid/license b/server/node_modules/lcid/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/lcid/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/lcid/package.json b/server/node_modules/lcid/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..03989ff78640486f5471ed103a7e01890522739d
--- /dev/null
+++ b/server/node_modules/lcid/package.json
@@ -0,0 +1,78 @@
+{
+  "_from": "lcid@^1.0.0",
+  "_id": "lcid@1.0.0",
+  "_inBundle": false,
+  "_integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+  "_location": "/lcid",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "lcid@^1.0.0",
+    "name": "lcid",
+    "escapedName": "lcid",
+    "rawSpec": "^1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.0"
+  },
+  "_requiredBy": [
+    "/os-locale"
+  ],
+  "_resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+  "_shasum": "308accafa0bc483a3867b4b6f2b9506251d1b835",
+  "_spec": "lcid@^1.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/os-locale",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/lcid/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "invert-kv": "^1.0.0"
+  },
+  "deprecated": false,
+  "description": "Mapping between standard locale identifiers and Windows locale identifiers (LCID)",
+  "devDependencies": {
+    "ava": "0.0.4"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js",
+    "lcid.json"
+  ],
+  "homepage": "https://github.com/sindresorhus/lcid#readme",
+  "keywords": [
+    "lcid",
+    "locale",
+    "string",
+    "str",
+    "id",
+    "identifier",
+    "windows",
+    "language",
+    "lang",
+    "map",
+    "mapping",
+    "convert",
+    "json",
+    "bcp47",
+    "ietf",
+    "tag"
+  ],
+  "license": "MIT",
+  "name": "lcid",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/lcid.git"
+  },
+  "scripts": {
+    "test": "node test.js"
+  },
+  "version": "1.0.0"
+}
diff --git a/server/node_modules/lcid/readme.md b/server/node_modules/lcid/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..bee4a7016697888d0eb98fa895f1eb5e9104a5dd
--- /dev/null
+++ b/server/node_modules/lcid/readme.md
@@ -0,0 +1,35 @@
+# lcid [![Build Status](https://travis-ci.org/sindresorhus/lcid.svg?branch=master)](https://travis-ci.org/sindresorhus/lcid)
+
+> Mapping between [standard locale identifiers](http://en.wikipedia.org/wiki/Locale) and [Windows locale identifiers (LCID)](http://en.wikipedia.org/wiki/Locale#Specifics_for_Microsoft_platforms)
+
+Based on the [mapping](https://github.com/python/cpython/blob/be2a1a76fa43bb1ea1b3577bb5bdd506a2e90e37/Lib/locale.py#L1395-L1604) used in the Python standard library.
+
+The mapping itself is just a [JSON file](lcid.json) and can be used wherever.
+
+
+## Install
+
+```
+$ npm install --save lcid
+```
+
+
+## Usage
+
+```js
+var lcid = require('lcid');
+
+lcid.from(1044);
+//=> 'nb_NO'
+
+lcid.to('nb_NO');
+//=> 1044
+
+lcid.all;
+//=> {'af_ZA': 1078, ...}
+```
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/load-json-file/index.js b/server/node_modules/load-json-file/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..96d4d9f6f887714e90f8b05ba3d2c7f891ff8dc9
--- /dev/null
+++ b/server/node_modules/load-json-file/index.js
@@ -0,0 +1,21 @@
+'use strict';
+var path = require('path');
+var fs = require('graceful-fs');
+var stripBom = require('strip-bom');
+var parseJson = require('parse-json');
+var Promise = require('pinkie-promise');
+var pify = require('pify');
+
+function parse(x, fp) {
+	return parseJson(stripBom(x), path.relative(process.cwd(), fp));
+}
+
+module.exports = function (fp) {
+	return pify(fs.readFile, Promise)(fp, 'utf8').then(function (data) {
+		return parse(data, fp);
+	});
+};
+
+module.exports.sync = function (fp) {
+	return parse(fs.readFileSync(fp, 'utf8'), fp);
+};
diff --git a/server/node_modules/load-json-file/license b/server/node_modules/load-json-file/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/load-json-file/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/load-json-file/package.json b/server/node_modules/load-json-file/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..f7dd5a3a28933e79b78e90f0cc902dcb7463479c
--- /dev/null
+++ b/server/node_modules/load-json-file/package.json
@@ -0,0 +1,78 @@
+{
+  "_from": "load-json-file@^1.0.0",
+  "_id": "load-json-file@1.1.0",
+  "_inBundle": false,
+  "_integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+  "_location": "/load-json-file",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "load-json-file@^1.0.0",
+    "name": "load-json-file",
+    "escapedName": "load-json-file",
+    "rawSpec": "^1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.0"
+  },
+  "_requiredBy": [
+    "/read-pkg"
+  ],
+  "_resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+  "_shasum": "956905708d58b4bab4c2261b04f59f31c99374c0",
+  "_spec": "load-json-file@^1.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/read-pkg",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/load-json-file/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "graceful-fs": "^4.1.2",
+    "parse-json": "^2.2.0",
+    "pify": "^2.0.0",
+    "pinkie-promise": "^2.0.0",
+    "strip-bom": "^2.0.0"
+  },
+  "deprecated": false,
+  "description": "Read and parse a JSON file",
+  "devDependencies": {
+    "ava": "*",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/load-json-file#readme",
+  "keywords": [
+    "json",
+    "read",
+    "parse",
+    "file",
+    "fs",
+    "graceful",
+    "load"
+  ],
+  "license": "MIT",
+  "name": "load-json-file",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/load-json-file.git"
+  },
+  "scripts": {
+    "test": "xo && ava"
+  },
+  "version": "1.1.0",
+  "xo": {
+    "ignores": [
+      "test.js"
+    ]
+  }
+}
diff --git a/server/node_modules/load-json-file/readme.md b/server/node_modules/load-json-file/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..fa982b5493cb1eb60c0787a504b2c99628805022
--- /dev/null
+++ b/server/node_modules/load-json-file/readme.md
@@ -0,0 +1,45 @@
+# load-json-file [![Build Status](https://travis-ci.org/sindresorhus/load-json-file.svg?branch=master)](https://travis-ci.org/sindresorhus/load-json-file)
+
+> Read and parse a JSON file
+
+[Strips UTF-8 BOM](https://github.com/sindresorhus/strip-bom), uses [`graceful-fs`](https://github.com/isaacs/node-graceful-fs), and throws more [helpful JSON errors](https://github.com/sindresorhus/parse-json).
+
+
+## Install
+
+```
+$ npm install --save load-json-file
+```
+
+
+## Usage
+
+```js
+const loadJsonFile = require('load-json-file');
+
+loadJsonFile('foo.json').then(json => {
+	console.log(json);
+	//=> {foo: true}
+});
+```
+
+
+## API
+
+### loadJsonFile(filepath)
+
+Returns a promise that resolves to the parsed JSON.
+
+### loadJsonFile.sync(filepath)
+
+Returns the parsed JSON.
+
+
+## Related
+
+- [write-json-file](https://github.com/sindresorhus/write-json-file) - Stringify and write JSON to a file atomically
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/lodash.assign/LICENSE b/server/node_modules/lodash.assign/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e0c69d56032d1562a06c0caa8ab8b278efded3c0
--- /dev/null
+++ b/server/node_modules/lodash.assign/LICENSE
@@ -0,0 +1,47 @@
+Copyright jQuery Foundation and other contributors <https://jquery.org/>
+
+Based on Underscore.js, copyright Jeremy Ashkenas,
+DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
+
+This software consists of voluntary contributions made by many
+individuals. For exact contribution history, see the revision history
+available at https://github.com/lodash/lodash
+
+The following license applies to all parts of this software except as
+documented below:
+
+====
+
+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.
+
+====
+
+Copyright and related rights for sample code are waived via CC0. Sample
+code is defined as all source code displayed within the prose of the
+documentation.
+
+CC0: http://creativecommons.org/publicdomain/zero/1.0/
+
+====
+
+Files located in the node_modules and vendor directories are externally
+maintained libraries used by this software which have their own
+licenses; we recommend you read them, as their terms may differ from the
+terms above.
diff --git a/server/node_modules/lodash.assign/README.md b/server/node_modules/lodash.assign/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6bce2d6bdde22c872486d7ee93abd103c20b9dac
--- /dev/null
+++ b/server/node_modules/lodash.assign/README.md
@@ -0,0 +1,18 @@
+# lodash.assign v4.2.0
+
+The [lodash](https://lodash.com/) method `_.assign` exported as a [Node.js](https://nodejs.org/) module.
+
+## Installation
+
+Using npm:
+```bash
+$ {sudo -H} npm i -g npm
+$ npm i --save lodash.assign
+```
+
+In Node.js:
+```js
+var assign = require('lodash.assign');
+```
+
+See the [documentation](https://lodash.com/docs#assign) or [package source](https://github.com/lodash/lodash/blob/4.2.0-npm-packages/lodash.assign) for more details.
diff --git a/server/node_modules/lodash.assign/index.js b/server/node_modules/lodash.assign/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b007bc781c512b87336a19d2f5eabd3a64e7853
--- /dev/null
+++ b/server/node_modules/lodash.assign/index.js
@@ -0,0 +1,637 @@
+/**
+ * lodash (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+/** Used as references for various `Number` constants. */
+var MAX_SAFE_INTEGER = 9007199254740991;
+
+/** `Object#toString` result references. */
+var argsTag = '[object Arguments]',
+    funcTag = '[object Function]',
+    genTag = '[object GeneratorFunction]';
+
+/** Used to detect unsigned integer values. */
+var reIsUint = /^(?:0|[1-9]\d*)$/;
+
+/**
+ * A faster alternative to `Function#apply`, this function invokes `func`
+ * with the `this` binding of `thisArg` and the arguments of `args`.
+ *
+ * @private
+ * @param {Function} func The function to invoke.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {Array} args The arguments to invoke `func` with.
+ * @returns {*} Returns the result of `func`.
+ */
+function apply(func, thisArg, args) {
+  switch (args.length) {
+    case 0: return func.call(thisArg);
+    case 1: return func.call(thisArg, args[0]);
+    case 2: return func.call(thisArg, args[0], args[1]);
+    case 3: return func.call(thisArg, args[0], args[1], args[2]);
+  }
+  return func.apply(thisArg, args);
+}
+
+/**
+ * The base implementation of `_.times` without support for iteratee shorthands
+ * or max array length checks.
+ *
+ * @private
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the array of results.
+ */
+function baseTimes(n, iteratee) {
+  var index = -1,
+      result = Array(n);
+
+  while (++index < n) {
+    result[index] = iteratee(index);
+  }
+  return result;
+}
+
+/**
+ * Creates a unary function that invokes `func` with its argument transformed.
+ *
+ * @private
+ * @param {Function} func The function to wrap.
+ * @param {Function} transform The argument transform.
+ * @returns {Function} Returns the new function.
+ */
+function overArg(func, transform) {
+  return function(arg) {
+    return func(transform(arg));
+  };
+}
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objectToString = objectProto.toString;
+
+/** Built-in value references. */
+var propertyIsEnumerable = objectProto.propertyIsEnumerable;
+
+/* Built-in method references for those with the same name as other `lodash` methods. */
+var nativeKeys = overArg(Object.keys, Object),
+    nativeMax = Math.max;
+
+/** Detect if properties shadowing those on `Object.prototype` are non-enumerable. */
+var nonEnumShadows = !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf');
+
+/**
+ * Creates an array of the enumerable property names of the array-like `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @param {boolean} inherited Specify returning inherited property names.
+ * @returns {Array} Returns the array of property names.
+ */
+function arrayLikeKeys(value, inherited) {
+  // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
+  // Safari 9 makes `arguments.length` enumerable in strict mode.
+  var result = (isArray(value) || isArguments(value))
+    ? baseTimes(value.length, String)
+    : [];
+
+  var length = result.length,
+      skipIndexes = !!length;
+
+  for (var key in value) {
+    if ((inherited || hasOwnProperty.call(value, key)) &&
+        !(skipIndexes && (key == 'length' || isIndex(key, length)))) {
+      result.push(key);
+    }
+  }
+  return result;
+}
+
+/**
+ * Assigns `value` to `key` of `object` if the existing value is not equivalent
+ * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * @private
+ * @param {Object} object The object to modify.
+ * @param {string} key The key of the property to assign.
+ * @param {*} value The value to assign.
+ */
+function assignValue(object, key, value) {
+  var objValue = object[key];
+  if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
+      (value === undefined && !(key in object))) {
+    object[key] = value;
+  }
+}
+
+/**
+ * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+function baseKeys(object) {
+  if (!isPrototype(object)) {
+    return nativeKeys(object);
+  }
+  var result = [];
+  for (var key in Object(object)) {
+    if (hasOwnProperty.call(object, key) && key != 'constructor') {
+      result.push(key);
+    }
+  }
+  return result;
+}
+
+/**
+ * The base implementation of `_.rest` which doesn't validate or coerce arguments.
+ *
+ * @private
+ * @param {Function} func The function to apply a rest parameter to.
+ * @param {number} [start=func.length-1] The start position of the rest parameter.
+ * @returns {Function} Returns the new function.
+ */
+function baseRest(func, start) {
+  start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
+  return function() {
+    var args = arguments,
+        index = -1,
+        length = nativeMax(args.length - start, 0),
+        array = Array(length);
+
+    while (++index < length) {
+      array[index] = args[start + index];
+    }
+    index = -1;
+    var otherArgs = Array(start + 1);
+    while (++index < start) {
+      otherArgs[index] = args[index];
+    }
+    otherArgs[start] = array;
+    return apply(func, this, otherArgs);
+  };
+}
+
+/**
+ * Copies properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy properties from.
+ * @param {Array} props The property identifiers to copy.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @param {Function} [customizer] The function to customize copied values.
+ * @returns {Object} Returns `object`.
+ */
+function copyObject(source, props, object, customizer) {
+  object || (object = {});
+
+  var index = -1,
+      length = props.length;
+
+  while (++index < length) {
+    var key = props[index];
+
+    var newValue = customizer
+      ? customizer(object[key], source[key], key, object, source)
+      : undefined;
+
+    assignValue(object, key, newValue === undefined ? source[key] : newValue);
+  }
+  return object;
+}
+
+/**
+ * Creates a function like `_.assign`.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @returns {Function} Returns the new assigner function.
+ */
+function createAssigner(assigner) {
+  return baseRest(function(object, sources) {
+    var index = -1,
+        length = sources.length,
+        customizer = length > 1 ? sources[length - 1] : undefined,
+        guard = length > 2 ? sources[2] : undefined;
+
+    customizer = (assigner.length > 3 && typeof customizer == 'function')
+      ? (length--, customizer)
+      : undefined;
+
+    if (guard && isIterateeCall(sources[0], sources[1], guard)) {
+      customizer = length < 3 ? undefined : customizer;
+      length = 1;
+    }
+    object = Object(object);
+    while (++index < length) {
+      var source = sources[index];
+      if (source) {
+        assigner(object, source, index, customizer);
+      }
+    }
+    return object;
+  });
+}
+
+/**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+function isIndex(value, length) {
+  length = length == null ? MAX_SAFE_INTEGER : length;
+  return !!length &&
+    (typeof value == 'number' || reIsUint.test(value)) &&
+    (value > -1 && value % 1 == 0 && value < length);
+}
+
+/**
+ * Checks if the given arguments are from an iteratee call.
+ *
+ * @private
+ * @param {*} value The potential iteratee value argument.
+ * @param {*} index The potential iteratee index or key argument.
+ * @param {*} object The potential iteratee object argument.
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
+ *  else `false`.
+ */
+function isIterateeCall(value, index, object) {
+  if (!isObject(object)) {
+    return false;
+  }
+  var type = typeof index;
+  if (type == 'number'
+        ? (isArrayLike(object) && isIndex(index, object.length))
+        : (type == 'string' && index in object)
+      ) {
+    return eq(object[index], value);
+  }
+  return false;
+}
+
+/**
+ * Checks if `value` is likely a prototype object.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
+ */
+function isPrototype(value) {
+  var Ctor = value && value.constructor,
+      proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
+
+  return value === proto;
+}
+
+/**
+ * Performs a
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * comparison between two values to determine if they are equivalent.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'a': 1 };
+ * var other = { 'a': 1 };
+ *
+ * _.eq(object, object);
+ * // => true
+ *
+ * _.eq(object, other);
+ * // => false
+ *
+ * _.eq('a', 'a');
+ * // => true
+ *
+ * _.eq('a', Object('a'));
+ * // => false
+ *
+ * _.eq(NaN, NaN);
+ * // => true
+ */
+function eq(value, other) {
+  return value === other || (value !== value && other !== other);
+}
+
+/**
+ * Checks if `value` is likely an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+ *  else `false`.
+ * @example
+ *
+ * _.isArguments(function() { return arguments; }());
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+function isArguments(value) {
+  // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
+  return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
+    (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
+}
+
+/**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * _.isArray(document.body.children);
+ * // => false
+ *
+ * _.isArray('abc');
+ * // => false
+ *
+ * _.isArray(_.noop);
+ * // => false
+ */
+var isArray = Array.isArray;
+
+/**
+ * Checks if `value` is array-like. A value is considered array-like if it's
+ * not a function and has a `value.length` that's an integer greater than or
+ * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ * @example
+ *
+ * _.isArrayLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLike(document.body.children);
+ * // => true
+ *
+ * _.isArrayLike('abc');
+ * // => true
+ *
+ * _.isArrayLike(_.noop);
+ * // => false
+ */
+function isArrayLike(value) {
+  return value != null && isLength(value.length) && !isFunction(value);
+}
+
+/**
+ * This method is like `_.isArrayLike` except that it also checks if `value`
+ * is an object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array-like object,
+ *  else `false`.
+ * @example
+ *
+ * _.isArrayLikeObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLikeObject(document.body.children);
+ * // => true
+ *
+ * _.isArrayLikeObject('abc');
+ * // => false
+ *
+ * _.isArrayLikeObject(_.noop);
+ * // => false
+ */
+function isArrayLikeObject(value) {
+  return isObjectLike(value) && isArrayLike(value);
+}
+
+/**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a function, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+function isFunction(value) {
+  // The use of `Object#toString` avoids issues with the `typeof` operator
+  // in Safari 8-9 which returns 'object' for typed array and other constructors.
+  var tag = isObject(value) ? objectToString.call(value) : '';
+  return tag == funcTag || tag == genTag;
+}
+
+/**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This method is loosely based on
+ * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ * @example
+ *
+ * _.isLength(3);
+ * // => true
+ *
+ * _.isLength(Number.MIN_VALUE);
+ * // => false
+ *
+ * _.isLength(Infinity);
+ * // => false
+ *
+ * _.isLength('3');
+ * // => false
+ */
+function isLength(value) {
+  return typeof value == 'number' &&
+    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+}
+
+/**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+function isObject(value) {
+  var type = typeof value;
+  return !!value && (type == 'object' || type == 'function');
+}
+
+/**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+function isObjectLike(value) {
+  return !!value && typeof value == 'object';
+}
+
+/**
+ * Assigns own enumerable string keyed properties of source objects to the
+ * destination object. Source objects are applied from left to right.
+ * Subsequent sources overwrite property assignments of previous sources.
+ *
+ * **Note:** This method mutates `object` and is loosely based on
+ * [`Object.assign`](https://mdn.io/Object/assign).
+ *
+ * @static
+ * @memberOf _
+ * @since 0.10.0
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @returns {Object} Returns `object`.
+ * @see _.assignIn
+ * @example
+ *
+ * function Foo() {
+ *   this.a = 1;
+ * }
+ *
+ * function Bar() {
+ *   this.c = 3;
+ * }
+ *
+ * Foo.prototype.b = 2;
+ * Bar.prototype.d = 4;
+ *
+ * _.assign({ 'a': 0 }, new Foo, new Bar);
+ * // => { 'a': 1, 'c': 3 }
+ */
+var assign = createAssigner(function(object, source) {
+  if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) {
+    copyObject(source, keys(source), object);
+    return;
+  }
+  for (var key in source) {
+    if (hasOwnProperty.call(source, key)) {
+      assignValue(object, key, source[key]);
+    }
+  }
+});
+
+/**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @since 0.1.0
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ *   this.a = 1;
+ *   this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+function keys(object) {
+  return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
+}
+
+module.exports = assign;
diff --git a/server/node_modules/lodash.assign/package.json b/server/node_modules/lodash.assign/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..c6253368fdde21c65ea9eeba3c5cd029f003a39b
--- /dev/null
+++ b/server/node_modules/lodash.assign/package.json
@@ -0,0 +1,70 @@
+{
+  "_from": "lodash.assign@^4.2.0",
+  "_id": "lodash.assign@4.2.0",
+  "_inBundle": false,
+  "_integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=",
+  "_location": "/lodash.assign",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "lodash.assign@^4.2.0",
+    "name": "lodash.assign",
+    "escapedName": "lodash.assign",
+    "rawSpec": "^4.2.0",
+    "saveSpec": null,
+    "fetchSpec": "^4.2.0"
+  },
+  "_requiredBy": [
+    "/yargs",
+    "/yargs-parser"
+  ],
+  "_resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
+  "_shasum": "0d99f3ccd7a6d261d19bdaeb9245005d285808e7",
+  "_spec": "lodash.assign@^4.2.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "John-David Dalton",
+    "email": "john.david.dalton@gmail.com",
+    "url": "http://allyoucanleet.com/"
+  },
+  "bugs": {
+    "url": "https://github.com/lodash/lodash/issues"
+  },
+  "bundleDependencies": false,
+  "contributors": [
+    {
+      "name": "John-David Dalton",
+      "email": "john.david.dalton@gmail.com",
+      "url": "http://allyoucanleet.com/"
+    },
+    {
+      "name": "Blaine Bublitz",
+      "email": "blaine.bublitz@gmail.com",
+      "url": "https://github.com/phated"
+    },
+    {
+      "name": "Mathias Bynens",
+      "email": "mathias@qiwi.be",
+      "url": "https://mathiasbynens.be/"
+    }
+  ],
+  "deprecated": false,
+  "description": "The lodash method `_.assign` exported as a module.",
+  "homepage": "https://lodash.com/",
+  "icon": "https://lodash.com/icon.svg",
+  "keywords": [
+    "lodash-modularized",
+    "assign"
+  ],
+  "license": "MIT",
+  "name": "lodash.assign",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/lodash/lodash.git"
+  },
+  "scripts": {
+    "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\""
+  },
+  "version": "4.2.0"
+}
diff --git a/server/node_modules/normalize-package-data/AUTHORS b/server/node_modules/normalize-package-data/AUTHORS
new file mode 100644
index 0000000000000000000000000000000000000000..66282ba1d11971a599d7a65b19756d8111489c2c
--- /dev/null
+++ b/server/node_modules/normalize-package-data/AUTHORS
@@ -0,0 +1,4 @@
+# Names sorted by how much code was originally theirs.
+Isaac Z. Schlueter <i@izs.me>
+Meryn Stol <merynstol@gmail.com>
+Robert Kowalski <rok@kowalski.gd>
diff --git a/server/node_modules/normalize-package-data/LICENSE b/server/node_modules/normalize-package-data/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..6ed662cd5d14de47fc0a0b1835d93986c5004fe5
--- /dev/null
+++ b/server/node_modules/normalize-package-data/LICENSE
@@ -0,0 +1,30 @@
+This package contains code originally written by Isaac Z. Schlueter.
+Used with permission.
+
+Copyright (c) Meryn Stol ("Author")
+All rights reserved.
+
+The BSD License
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/server/node_modules/normalize-package-data/README.md b/server/node_modules/normalize-package-data/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d2bd7bc7ff60628582817aee5b49663504ba85d6
--- /dev/null
+++ b/server/node_modules/normalize-package-data/README.md
@@ -0,0 +1,106 @@
+# normalize-package-data [![Build Status](https://travis-ci.org/npm/normalize-package-data.png?branch=master)](https://travis-ci.org/npm/normalize-package-data)
+
+normalize-package-data exports a function that normalizes package metadata. This data is typically found in a package.json file, but in principle could come from any source - for example the npm registry.
+
+normalize-package-data is used by [read-package-json](https://npmjs.org/package/read-package-json) to normalize the data it reads from a package.json file. In turn, read-package-json is used by [npm](https://npmjs.org/package/npm) and various npm-related tools.
+
+## Installation
+
+```
+npm install normalize-package-data
+```
+
+## Usage
+
+Basic usage is really simple. You call the function that normalize-package-data exports. Let's call it `normalizeData`.
+
+```javascript
+normalizeData = require('normalize-package-data')
+packageData = require("./package.json")
+normalizeData(packageData)
+// packageData is now normalized
+```
+
+#### Strict mode
+
+You may activate strict validation by passing true as the second argument.
+
+```javascript
+normalizeData = require('normalize-package-data')
+packageData = require("./package.json")
+normalizeData(packageData, true)
+// packageData is now normalized
+```
+
+If strict mode is activated, only Semver 2.0 version strings are accepted. Otherwise, Semver 1.0 strings are accepted as well. Packages must have a name, and the name field must not have contain leading or trailing whitespace.
+
+#### Warnings
+
+Optionally, you may pass a "warning" function. It gets called whenever the `normalizeData` function encounters something that doesn't look right. It indicates less than perfect input data.
+
+```javascript
+normalizeData = require('normalize-package-data')
+packageData = require("./package.json")
+warnFn = function(msg) { console.error(msg) }
+normalizeData(packageData, warnFn)
+// packageData is now normalized. Any number of warnings may have been logged.
+```
+
+You may combine strict validation with warnings by passing `true` as the second argument, and `warnFn` as third.
+
+When `private` field is set to `true`, warnings will be suppressed.
+
+### Potential exceptions
+
+If the supplied data has an invalid name or version vield, `normalizeData` will throw an error. Depending on where you call `normalizeData`, you may want to catch these errors so can pass them to a callback.
+
+## What normalization (currently) entails
+
+* The value of `name` field gets trimmed (unless in strict mode).
+* The value of the `version` field gets cleaned by `semver.clean`. See [documentation for the semver module](https://github.com/isaacs/node-semver).
+* If `name` and/or `version` fields are missing, they are set to empty strings.
+* If `files` field is not an array, it will be removed.
+* If `bin` field is a string, then `bin` field will become an object with `name` set to the value of the `name` field, and `bin` set to the original string value.
+* If `man` field is a string, it will become an array with the original string as its sole member.
+* If `keywords` field is string, it is considered to be a list of keywords separated by one or more white-space characters. It gets converted to an array by splitting on `\s+`.
+* All people fields (`author`, `maintainers`, `contributors`) get converted into objects with name, email and url properties.
+* If `bundledDependencies` field (a typo) exists and `bundleDependencies` field does not, `bundledDependencies` will get renamed to `bundleDependencies`.
+* If the value of any of the dependencies fields  (`dependencies`, `devDependencies`, `optionalDependencies`) is a string, it gets converted into an object with familiar `name=>value` pairs.
+* The values in `optionalDependencies` get added to `dependencies`. The `optionalDependencies` array is left untouched.
+* As of v2: Dependencies that point at known hosted git providers (currently: github, bitbucket, gitlab) will have their URLs canonicalized, but protocols will be preserved.
+* As of v2: Dependencies that use shortcuts for hosted git providers (`org/proj`, `github:org/proj`, `bitbucket:org/proj`, `gitlab:org/proj`, `gist:docid`) will have the shortcut left in place. (In the case of github, the `org/proj` form will be expanded to `github:org/proj`.) THIS MARKS A BREAKING CHANGE FROM V1, where the shorcut was previously expanded to a URL.
+* If `description` field does not exist, but `readme` field does, then (more or less) the first paragraph of text that's found in the readme is taken as value for `description`.
+* If `repository` field is a string, it will become an object with `url` set to the original string value, and `type` set to `"git"`.
+* If `repository.url` is not a valid url, but in the style of "[owner-name]/[repo-name]", `repository.url` will be set to git+https://github.com/[owner-name]/[repo-name].git
+* If `bugs` field is a string, the value of `bugs` field is changed into an object with `url` set to the original string value.
+* If `bugs` field does not exist, but `repository` field points to a repository hosted on GitHub, the value of the `bugs` field gets set to an url in the form of https://github.com/[owner-name]/[repo-name]/issues . If the repository field points to a GitHub Gist repo url, the associated http url is chosen.
+* If `bugs` field is an object, the resulting value only has email and url properties. If email and url properties are not strings, they are ignored. If no valid values for either email or url is found, bugs field will be removed.
+* If `homepage` field is not a string, it will be removed.
+* If the url in the `homepage` field does not specify a protocol, then http is assumed. For example, `myproject.org` will be changed to `http://myproject.org`.
+* If `homepage` field does not exist, but `repository` field points to a repository hosted on GitHub, the value of the `homepage` field gets set to an url in the form of https://github.com/[owner-name]/[repo-name]#readme . If the repository field points to a GitHub Gist repo url, the associated http url is chosen.
+
+### Rules for name field
+
+If `name` field is given, the value of the name field must be a string. The string may not:
+
+* start with a period.
+* contain the following characters: `/@\s+%`
+* contain any characters that would need to be encoded for use in urls.
+* resemble the word `node_modules` or `favicon.ico` (case doesn't matter).
+
+### Rules for version field
+
+If `version` field is given, the value of the version field must be a valid *semver* string, as determined by the `semver.valid` method. See [documentation for the semver module](https://github.com/isaacs/node-semver).
+
+### Rules for license field
+
+The `license` field should be a valid *SPDX license expression* or one of the special values allowed by [validate-npm-package-license](https://npmjs.com/package/validate-npm-package-license). See [documentation for the license field in package.json](https://docs.npmjs.com/files/package.json#license).
+
+## Credits
+
+This package contains code based on read-package-json written by Isaac Z. Schlueter. Used with permisson.
+
+## License
+
+normalize-package-data is released under the [BSD 2-Clause License](http://opensource.org/licenses/MIT).  
+Copyright (c) 2013 Meryn Stol  
diff --git a/server/node_modules/normalize-package-data/lib/extract_description.js b/server/node_modules/normalize-package-data/lib/extract_description.js
new file mode 100644
index 0000000000000000000000000000000000000000..83f10aa0a79066d6b8809eeccce6f8e8c228a7d5
--- /dev/null
+++ b/server/node_modules/normalize-package-data/lib/extract_description.js
@@ -0,0 +1,14 @@
+module.exports = extractDescription
+
+// Extracts description from contents of a readme file in markdown format
+function extractDescription (d) {
+  if (!d) return;
+  if (d === "ERROR: No README data found!") return;
+  // the first block of text before the first heading
+  // that isn't the first line heading
+  d = d.trim().split('\n')
+  for (var s = 0; d[s] && d[s].trim().match(/^(#|$)/); s ++);
+  var l = d.length
+  for (var e = s + 1; e < l && d[e].trim(); e ++);
+  return d.slice(s, e).join(' ').trim()
+}
diff --git a/server/node_modules/normalize-package-data/lib/fixer.js b/server/node_modules/normalize-package-data/lib/fixer.js
new file mode 100644
index 0000000000000000000000000000000000000000..27682e9611afd2d6b30469c3d4f4e3972f873d22
--- /dev/null
+++ b/server/node_modules/normalize-package-data/lib/fixer.js
@@ -0,0 +1,418 @@
+var semver = require("semver")
+var validateLicense = require('validate-npm-package-license');
+var hostedGitInfo = require("hosted-git-info")
+var isBuiltinModule = require("resolve").isCore
+var depTypes = ["dependencies","devDependencies","optionalDependencies"]
+var extractDescription = require("./extract_description")
+var url = require("url")
+var typos = require("./typos.json")
+
+var fixer = module.exports = {
+  // default warning function
+  warn: function() {},
+
+  fixRepositoryField: function(data) {
+    if (data.repositories) {
+      this.warn("repositories");
+      data.repository = data.repositories[0]
+    }
+    if (!data.repository) return this.warn("missingRepository")
+    if (typeof data.repository === "string") {
+      data.repository = {
+        type: "git",
+        url: data.repository
+      }
+    }
+    var r = data.repository.url || ""
+    if (r) {
+      var hosted = hostedGitInfo.fromUrl(r)
+      if (hosted) {
+        r = data.repository.url
+          = hosted.getDefaultRepresentation() == "shortcut" ? hosted.https() : hosted.toString()
+      }
+    }
+
+    if (r.match(/github.com\/[^\/]+\/[^\/]+\.git\.git$/)) {
+      this.warn("brokenGitUrl", r)
+    }
+  }
+
+, fixTypos: function(data) {
+    Object.keys(typos.topLevel).forEach(function (d) {
+      if (data.hasOwnProperty(d)) {
+        this.warn("typo", d, typos.topLevel[d])
+      }
+    }, this)
+  }
+
+, fixScriptsField: function(data) {
+    if (!data.scripts) return
+    if (typeof data.scripts !== "object") {
+      this.warn("nonObjectScripts")
+      delete data.scripts
+      return
+    }
+    Object.keys(data.scripts).forEach(function (k) {
+      if (typeof data.scripts[k] !== "string") {
+        this.warn("nonStringScript")
+        delete data.scripts[k]
+      } else if (typos.script[k] && !data.scripts[typos.script[k]]) {
+        this.warn("typo", k, typos.script[k], "scripts")
+      }
+    }, this)
+  }
+
+, fixFilesField: function(data) {
+    var files = data.files
+    if (files && !Array.isArray(files)) {
+      this.warn("nonArrayFiles")
+      delete data.files
+    } else if (data.files) {
+      data.files = data.files.filter(function(file) {
+        if (!file || typeof file !== "string") {
+          this.warn("invalidFilename", file)
+          return false
+        } else {
+          return true
+        }
+      }, this)
+    }
+  }
+
+, fixBinField: function(data) {
+    if (!data.bin) return;
+    if (typeof data.bin === "string") {
+      var b = {}
+      var match
+      if (match = data.name.match(/^@[^/]+[/](.*)$/)) {
+        b[match[1]] = data.bin
+      } else {
+        b[data.name] = data.bin
+      }
+      data.bin = b
+    }
+  }
+
+, fixManField: function(data) {
+    if (!data.man) return;
+    if (typeof data.man === "string") {
+      data.man = [ data.man ]
+    }
+  }
+, fixBundleDependenciesField: function(data) {
+    var bdd = "bundledDependencies"
+    var bd = "bundleDependencies"
+    if (data[bdd] && !data[bd]) {
+      data[bd] = data[bdd]
+      delete data[bdd]
+    }
+    if (data[bd] && !Array.isArray(data[bd])) {
+      this.warn("nonArrayBundleDependencies")
+      delete data[bd]
+    } else if (data[bd]) {
+      data[bd] = data[bd].filter(function(bd) {
+        if (!bd || typeof bd !== 'string') {
+          this.warn("nonStringBundleDependency", bd)
+          return false
+        } else {
+          if (!data.dependencies) {
+            data.dependencies = {}
+          }
+          if (!data.dependencies.hasOwnProperty(bd)) {
+            this.warn("nonDependencyBundleDependency", bd)
+            data.dependencies[bd] = "*"
+          }
+          return true
+        }
+      }, this)
+    }
+  }
+
+, fixDependencies: function(data, strict) {
+    var loose = !strict
+    objectifyDeps(data, this.warn)
+    addOptionalDepsToDeps(data, this.warn)
+    this.fixBundleDependenciesField(data)
+
+    ;['dependencies','devDependencies'].forEach(function(deps) {
+      if (!(deps in data)) return
+      if (!data[deps] || typeof data[deps] !== "object") {
+        this.warn("nonObjectDependencies", deps)
+        delete data[deps]
+        return
+      }
+      Object.keys(data[deps]).forEach(function (d) {
+        var r = data[deps][d]
+        if (typeof r !== 'string') {
+          this.warn("nonStringDependency", d, JSON.stringify(r))
+          delete data[deps][d]
+        }
+        var hosted = hostedGitInfo.fromUrl(data[deps][d])
+        if (hosted) data[deps][d] = hosted.toString()
+      }, this)
+    }, this)
+  }
+
+, fixModulesField: function (data) {
+    if (data.modules) {
+      this.warn("deprecatedModules")
+      delete data.modules
+    }
+  }
+
+, fixKeywordsField: function (data) {
+    if (typeof data.keywords === "string") {
+      data.keywords = data.keywords.split(/,\s+/)
+    }
+    if (data.keywords && !Array.isArray(data.keywords)) {
+      delete data.keywords
+      this.warn("nonArrayKeywords")
+    } else if (data.keywords) {
+      data.keywords = data.keywords.filter(function(kw) {
+        if (typeof kw !== "string" || !kw) {
+          this.warn("nonStringKeyword");
+          return false
+        } else {
+          return true
+        }
+      }, this)
+    }
+  }
+
+, fixVersionField: function(data, strict) {
+    // allow "loose" semver 1.0 versions in non-strict mode
+    // enforce strict semver 2.0 compliance in strict mode
+    var loose = !strict
+    if (!data.version) {
+      data.version = ""
+      return true
+    }
+    if (!semver.valid(data.version, loose)) {
+      throw new Error('Invalid version: "'+ data.version + '"')
+    }
+    data.version = semver.clean(data.version, loose)
+    return true
+  }
+
+, fixPeople: function(data) {
+    modifyPeople(data, unParsePerson)
+    modifyPeople(data, parsePerson)
+  }
+
+, fixNameField: function(data, options) {
+    if (typeof options === "boolean") options = {strict: options}
+    else if (typeof options === "undefined") options = {}
+    var strict = options.strict
+    if (!data.name && !strict) {
+      data.name = ""
+      return
+    }
+    if (typeof data.name !== "string") {
+      throw new Error("name field must be a string.")
+    }
+    if (!strict)
+      data.name = data.name.trim()
+    ensureValidName(data.name, strict, options.allowLegacyCase)
+    if (isBuiltinModule(data.name))
+      this.warn("conflictingName", data.name)
+  }
+
+
+, fixDescriptionField: function (data) {
+    if (data.description && typeof data.description !== 'string') {
+      this.warn("nonStringDescription")
+      delete data.description
+    }
+    if (data.readme && !data.description)
+      data.description = extractDescription(data.readme)
+      if(data.description === undefined) delete data.description;
+    if (!data.description) this.warn("missingDescription")
+  }
+
+, fixReadmeField: function (data) {
+    if (!data.readme) {
+      this.warn("missingReadme")
+      data.readme = "ERROR: No README data found!"
+    }
+  }
+
+, fixBugsField: function(data) {
+    if (!data.bugs && data.repository && data.repository.url) {
+      var hosted = hostedGitInfo.fromUrl(data.repository.url)
+      if(hosted && hosted.bugs()) {
+        data.bugs = {url: hosted.bugs()}
+      }
+    }
+    else if(data.bugs) {
+      var emailRe = /^.+@.*\..+$/
+      if(typeof data.bugs == "string") {
+        if(emailRe.test(data.bugs))
+          data.bugs = {email:data.bugs}
+        else if(url.parse(data.bugs).protocol)
+          data.bugs = {url: data.bugs}
+        else
+          this.warn("nonEmailUrlBugsString")
+      }
+      else {
+        bugsTypos(data.bugs, this.warn)
+        var oldBugs = data.bugs
+        data.bugs = {}
+        if(oldBugs.url) {
+          if(typeof(oldBugs.url) == "string" && url.parse(oldBugs.url).protocol)
+            data.bugs.url = oldBugs.url
+          else
+            this.warn("nonUrlBugsUrlField")
+        }
+        if(oldBugs.email) {
+          if(typeof(oldBugs.email) == "string" && emailRe.test(oldBugs.email))
+            data.bugs.email = oldBugs.email
+          else
+            this.warn("nonEmailBugsEmailField")
+        }
+      }
+      if(!data.bugs.email && !data.bugs.url) {
+        delete data.bugs
+        this.warn("emptyNormalizedBugs")
+      }
+    }
+  }
+
+, fixHomepageField: function(data) {
+    if (!data.homepage && data.repository && data.repository.url) {
+      var hosted = hostedGitInfo.fromUrl(data.repository.url)
+      if (hosted && hosted.docs()) data.homepage = hosted.docs()
+    }
+    if (!data.homepage) return
+
+    if(typeof data.homepage !== "string") {
+      this.warn("nonUrlHomepage")
+      return delete data.homepage
+    }
+    if(!url.parse(data.homepage).protocol) {
+      data.homepage = "http://" + data.homepage
+    }
+  }
+
+, fixLicenseField: function(data) {
+    if (!data.license) {
+      return this.warn("missingLicense")
+    } else{
+      if (
+        typeof(data.license) !== 'string' ||
+        data.license.length < 1 ||
+        data.license.trim() === ''
+      ) {
+        this.warn("invalidLicense")
+      } else {
+        if (!validateLicense(data.license).validForNewPackages)
+          this.warn("invalidLicense")
+      }
+    }
+  }
+}
+
+function isValidScopedPackageName(spec) {
+  if (spec.charAt(0) !== '@') return false
+
+  var rest = spec.slice(1).split('/')
+  if (rest.length !== 2) return false
+
+  return rest[0] && rest[1] &&
+    rest[0] === encodeURIComponent(rest[0]) &&
+    rest[1] === encodeURIComponent(rest[1])
+}
+
+function isCorrectlyEncodedName(spec) {
+  return !spec.match(/[\/@\s\+%:]/) &&
+    spec === encodeURIComponent(spec)
+}
+
+function ensureValidName (name, strict, allowLegacyCase) {
+  if (name.charAt(0) === "." ||
+      !(isValidScopedPackageName(name) || isCorrectlyEncodedName(name)) ||
+      (strict && (!allowLegacyCase) && name !== name.toLowerCase()) ||
+      name.toLowerCase() === "node_modules" ||
+      name.toLowerCase() === "favicon.ico") {
+        throw new Error("Invalid name: " + JSON.stringify(name))
+  }
+}
+
+function modifyPeople (data, fn) {
+  if (data.author) data.author = fn(data.author)
+  ;["maintainers", "contributors"].forEach(function (set) {
+    if (!Array.isArray(data[set])) return;
+    data[set] = data[set].map(fn)
+  })
+  return data
+}
+
+function unParsePerson (person) {
+  if (typeof person === "string") return person
+  var name = person.name || ""
+  var u = person.url || person.web
+  var url = u ? (" ("+u+")") : ""
+  var e = person.email || person.mail
+  var email = e ? (" <"+e+">") : ""
+  return name+email+url
+}
+
+function parsePerson (person) {
+  if (typeof person !== "string") return person
+  var name = person.match(/^([^\(<]+)/)
+  var url = person.match(/\(([^\)]+)\)/)
+  var email = person.match(/<([^>]+)>/)
+  var obj = {}
+  if (name && name[0].trim()) obj.name = name[0].trim()
+  if (email) obj.email = email[1];
+  if (url) obj.url = url[1];
+  return obj
+}
+
+function addOptionalDepsToDeps (data, warn) {
+  var o = data.optionalDependencies
+  if (!o) return;
+  var d = data.dependencies || {}
+  Object.keys(o).forEach(function (k) {
+    d[k] = o[k]
+  })
+  data.dependencies = d
+}
+
+function depObjectify (deps, type, warn) {
+  if (!deps) return {}
+  if (typeof deps === "string") {
+    deps = deps.trim().split(/[\n\r\s\t ,]+/)
+  }
+  if (!Array.isArray(deps)) return deps
+  warn("deprecatedArrayDependencies", type)
+  var o = {}
+  deps.filter(function (d) {
+    return typeof d === "string"
+  }).forEach(function(d) {
+    d = d.trim().split(/(:?[@\s><=])/)
+    var dn = d.shift()
+    var dv = d.join("")
+    dv = dv.trim()
+    dv = dv.replace(/^@/, "")
+    o[dn] = dv
+  })
+  return o
+}
+
+function objectifyDeps (data, warn) {
+  depTypes.forEach(function (type) {
+    if (!data[type]) return;
+    data[type] = depObjectify(data[type], type, warn)
+  })
+}
+
+function bugsTypos(bugs, warn) {
+  if (!bugs) return
+  Object.keys(bugs).forEach(function (k) {
+    if (typos.bugs[k]) {
+      warn("typo", k, typos.bugs[k], "bugs")
+      bugs[typos.bugs[k]] = bugs[k]
+      delete bugs[k]
+    }
+  })
+}
diff --git a/server/node_modules/normalize-package-data/lib/make_warning.js b/server/node_modules/normalize-package-data/lib/make_warning.js
new file mode 100644
index 0000000000000000000000000000000000000000..4ac74ad7cb25c3fb984570f873b9d4418099a92a
--- /dev/null
+++ b/server/node_modules/normalize-package-data/lib/make_warning.js
@@ -0,0 +1,23 @@
+var util = require("util")
+var messages = require("./warning_messages.json")
+
+module.exports = function() {
+  var args = Array.prototype.slice.call(arguments, 0)
+  var warningName = args.shift()
+  if (warningName == "typo") {
+    return makeTypoWarning.apply(null,args)
+  }
+  else {
+    var msgTemplate = messages[warningName] ? messages[warningName] : warningName + ": '%s'"
+    args.unshift(msgTemplate)
+    return util.format.apply(null, args)
+  }
+}
+
+function makeTypoWarning (providedName, probableName, field) {
+  if (field) {
+    providedName = field + "['" + providedName + "']"
+    probableName = field + "['" + probableName + "']"
+  }
+  return util.format(messages.typo, providedName, probableName)
+}
diff --git a/server/node_modules/normalize-package-data/lib/normalize.js b/server/node_modules/normalize-package-data/lib/normalize.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd1bfef123103a2c81aaf3b1405b392fdd8e8e0d
--- /dev/null
+++ b/server/node_modules/normalize-package-data/lib/normalize.js
@@ -0,0 +1,39 @@
+module.exports = normalize
+
+var fixer = require("./fixer")
+normalize.fixer = fixer
+
+var makeWarning = require("./make_warning")
+
+var fieldsToFix = ['name','version','description','repository','modules','scripts'
+                  ,'files','bin','man','bugs','keywords','readme','homepage','license']
+var otherThingsToFix = ['dependencies','people', 'typos']
+
+var thingsToFix = fieldsToFix.map(function(fieldName) {
+  return ucFirst(fieldName) + "Field"
+})
+// two ways to do this in CoffeeScript on only one line, sub-70 chars:
+// thingsToFix = fieldsToFix.map (name) -> ucFirst(name) + "Field"
+// thingsToFix = (ucFirst(name) + "Field" for name in fieldsToFix)
+thingsToFix = thingsToFix.concat(otherThingsToFix)
+
+function normalize (data, warn, strict) {
+  if(warn === true) warn = null, strict = true
+  if(!strict) strict = false
+  if(!warn || data.private) warn = function(msg) { /* noop */ }
+
+  if (data.scripts &&
+      data.scripts.install === "node-gyp rebuild" &&
+      !data.scripts.preinstall) {
+    data.gypfile = true
+  }
+  fixer.warn = function() { warn(makeWarning.apply(null, arguments)) }
+  thingsToFix.forEach(function(thingName) {
+    fixer["fix" + ucFirst(thingName)](data, strict)
+  })
+  data._id = data.name + "@" + data.version
+}
+
+function ucFirst (string) {
+  return string.charAt(0).toUpperCase() + string.slice(1);
+}
diff --git a/server/node_modules/normalize-package-data/lib/safe_format.js b/server/node_modules/normalize-package-data/lib/safe_format.js
new file mode 100644
index 0000000000000000000000000000000000000000..b07f1006d1ad299d3e33a9bae4ffd681f166cf2f
--- /dev/null
+++ b/server/node_modules/normalize-package-data/lib/safe_format.js
@@ -0,0 +1,9 @@
+var util = require('util')
+
+module.exports = function() {
+  var args = Array.prototype.slice.call(arguments, 0)
+  args.forEach(function(arg) {
+    if (!arg) throw new TypeError('Bad arguments.')
+  })
+  return util.format.apply(null, arguments)
+}
diff --git a/server/node_modules/normalize-package-data/lib/typos.json b/server/node_modules/normalize-package-data/lib/typos.json
new file mode 100644
index 0000000000000000000000000000000000000000..7f9dd283b30ff3602a3d317f67b61ea1bb10b797
--- /dev/null
+++ b/server/node_modules/normalize-package-data/lib/typos.json
@@ -0,0 +1,25 @@
+{
+  "topLevel": {
+    "dependancies": "dependencies"
+   ,"dependecies": "dependencies"
+   ,"depdenencies": "dependencies"
+   ,"devEependencies": "devDependencies"
+   ,"depends": "dependencies"
+   ,"dev-dependencies": "devDependencies"
+   ,"devDependences": "devDependencies"
+   ,"devDepenencies": "devDependencies"
+   ,"devdependencies": "devDependencies"
+   ,"repostitory": "repository"
+   ,"repo": "repository"
+   ,"prefereGlobal": "preferGlobal"
+   ,"hompage": "homepage"
+   ,"hampage": "homepage"
+   ,"autohr": "author"
+   ,"autor": "author"
+   ,"contributers": "contributors"
+   ,"publicationConfig": "publishConfig"
+   ,"script": "scripts"
+  },
+  "bugs": { "web": "url", "name": "url" },
+  "script": { "server": "start", "tests": "test" }
+}
diff --git a/server/node_modules/normalize-package-data/lib/warning_messages.json b/server/node_modules/normalize-package-data/lib/warning_messages.json
new file mode 100644
index 0000000000000000000000000000000000000000..4890f506ed965a88030b278a0108bc41d4140d4c
--- /dev/null
+++ b/server/node_modules/normalize-package-data/lib/warning_messages.json
@@ -0,0 +1,30 @@
+{
+  "repositories": "'repositories' (plural) Not supported. Please pick one as the 'repository' field"
+  ,"missingRepository": "No repository field."
+  ,"brokenGitUrl": "Probably broken git url: %s"
+  ,"nonObjectScripts": "scripts must be an object"
+  ,"nonStringScript": "script values must be string commands"
+  ,"nonArrayFiles": "Invalid 'files' member"
+  ,"invalidFilename": "Invalid filename in 'files' list: %s"
+  ,"nonArrayBundleDependencies": "Invalid 'bundleDependencies' list. Must be array of package names"
+  ,"nonStringBundleDependency": "Invalid bundleDependencies member: %s"
+  ,"nonDependencyBundleDependency": "Non-dependency in bundleDependencies: %s"
+  ,"nonObjectDependencies": "%s field must be an object"
+  ,"nonStringDependency": "Invalid dependency: %s %s"
+  ,"deprecatedArrayDependencies": "specifying %s as array is deprecated"
+  ,"deprecatedModules": "modules field is deprecated"
+  ,"nonArrayKeywords": "keywords should be an array of strings"
+  ,"nonStringKeyword": "keywords should be an array of strings"
+  ,"conflictingName": "%s is also the name of a node core module."
+  ,"nonStringDescription": "'description' field should be a string"
+  ,"missingDescription": "No description"
+  ,"missingReadme": "No README data"
+  ,"missingLicense": "No license field."
+  ,"nonEmailUrlBugsString": "Bug string field must be url, email, or {email,url}"
+  ,"nonUrlBugsUrlField": "bugs.url field must be a string url. Deleted."
+  ,"nonEmailBugsEmailField": "bugs.email field must be a string email. Deleted."
+  ,"emptyNormalizedBugs": "Normalized value of bugs field is an empty object. Deleted."
+  ,"nonUrlHomepage": "homepage field must be a string url. Deleted."
+  ,"invalidLicense": "license should be a valid SPDX license expression"
+  ,"typo": "%s should probably be %s."
+}
diff --git a/server/node_modules/normalize-package-data/package.json b/server/node_modules/normalize-package-data/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..a86d39cbeba5d85462babc25f04c824289a6c197
--- /dev/null
+++ b/server/node_modules/normalize-package-data/package.json
@@ -0,0 +1,77 @@
+{
+  "_from": "normalize-package-data@^2.3.2",
+  "_id": "normalize-package-data@2.5.0",
+  "_inBundle": false,
+  "_integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+  "_location": "/normalize-package-data",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "normalize-package-data@^2.3.2",
+    "name": "normalize-package-data",
+    "escapedName": "normalize-package-data",
+    "rawSpec": "^2.3.2",
+    "saveSpec": null,
+    "fetchSpec": "^2.3.2"
+  },
+  "_requiredBy": [
+    "/read-pkg"
+  ],
+  "_resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+  "_shasum": "e66db1838b200c1dfc233225d12cb36520e234a8",
+  "_spec": "normalize-package-data@^2.3.2",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/read-pkg",
+  "author": {
+    "name": "Meryn Stol",
+    "email": "merynstol@gmail.com"
+  },
+  "bugs": {
+    "url": "https://github.com/npm/normalize-package-data/issues"
+  },
+  "bundleDependencies": false,
+  "contributors": [
+    {
+      "name": "Isaac Z. Schlueter",
+      "email": "i@izs.me"
+    },
+    {
+      "name": "Meryn Stol",
+      "email": "merynstol@gmail.com"
+    },
+    {
+      "name": "Robert Kowalski",
+      "email": "rok@kowalski.gd"
+    }
+  ],
+  "dependencies": {
+    "hosted-git-info": "^2.1.4",
+    "resolve": "^1.10.0",
+    "semver": "2 || 3 || 4 || 5",
+    "validate-npm-package-license": "^3.0.1"
+  },
+  "deprecated": false,
+  "description": "Normalizes data that can be found in package.json files.",
+  "devDependencies": {
+    "async": "^2.6.1",
+    "tap": "^12.4.0",
+    "underscore": "^1.8.3"
+  },
+  "files": [
+    "lib/*.js",
+    "lib/*.json",
+    "AUTHORS"
+  ],
+  "homepage": "https://github.com/npm/normalize-package-data#readme",
+  "license": "BSD-2-Clause",
+  "main": "lib/normalize.js",
+  "name": "normalize-package-data",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/npm/normalize-package-data.git"
+  },
+  "scripts": {
+    "test": "tap test/*.js"
+  },
+  "version": "2.5.0"
+}
diff --git a/server/node_modules/os-locale/index.js b/server/node_modules/os-locale/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..2c8a0065de6f4a48b438ce652183f2d377d18480
--- /dev/null
+++ b/server/node_modules/os-locale/index.js
@@ -0,0 +1,127 @@
+'use strict';
+var childProcess = require('child_process');
+var execFileSync = childProcess.execFileSync;
+var lcid = require('lcid');
+var defaultOpts = {spawn: true};
+var cache;
+
+function fallback() {
+	cache = 'en_US';
+	return cache;
+}
+
+function getEnvLocale(env) {
+	env = env || process.env;
+	var ret = env.LC_ALL || env.LC_MESSAGES || env.LANG || env.LANGUAGE;
+	cache = getLocale(ret);
+	return ret;
+}
+
+function parseLocale(x) {
+	var env = x.split('\n').reduce(function (env, def) {
+		def = def.split('=');
+		env[def[0]] = def[1];
+		return env;
+	}, {});
+	return getEnvLocale(env);
+}
+
+function getLocale(str) {
+	return (str && str.replace(/[.:].*/, '')) || fallback();
+}
+
+module.exports = function (opts, cb) {
+	if (typeof opts === 'function') {
+		cb = opts;
+		opts = defaultOpts;
+	} else {
+		opts = opts || defaultOpts;
+	}
+
+	if (cache || getEnvLocale() || opts.spawn === false) {
+		setImmediate(cb, null, cache);
+		return;
+	}
+
+	var getAppleLocale = function () {
+		childProcess.execFile('defaults', ['read', '-g', 'AppleLocale'], function (err, stdout) {
+			if (err) {
+				fallback();
+				return;
+			}
+
+			cache = stdout.trim() || fallback();
+			cb(null, cache);
+		});
+	};
+
+	if (process.platform === 'win32') {
+		childProcess.execFile('wmic', ['os', 'get', 'locale'], function (err, stdout) {
+			if (err) {
+				fallback();
+				return;
+			}
+
+			var lcidCode = parseInt(stdout.replace('Locale', ''), 16);
+			cache = lcid.from(lcidCode) || fallback();
+			cb(null, cache);
+		});
+	} else {
+		childProcess.execFile('locale', function (err, stdout) {
+			if (err) {
+				fallback();
+				return;
+			}
+
+			var res = parseLocale(stdout);
+
+			if (!res && process.platform === 'darwin') {
+				getAppleLocale();
+				return;
+			}
+
+			cache = getLocale(res);
+			cb(null, cache);
+		});
+	}
+};
+
+module.exports.sync = function (opts) {
+	opts = opts || defaultOpts;
+
+	if (cache || getEnvLocale() || !execFileSync || opts.spawn === false) {
+		return cache;
+	}
+
+	if (process.platform === 'win32') {
+		var stdout;
+
+		try {
+			stdout = execFileSync('wmic', ['os', 'get', 'locale'], {encoding: 'utf8'});
+		} catch (err) {
+			return fallback();
+		}
+
+		var lcidCode = parseInt(stdout.replace('Locale', ''), 16);
+		cache = lcid.from(lcidCode) || fallback();
+		return cache;
+	}
+
+	var res;
+
+	try {
+		res = parseLocale(execFileSync('locale', {encoding: 'utf8'}));
+	} catch (err) {}
+
+	if (!res && process.platform === 'darwin') {
+		try {
+			cache = execFileSync('defaults', ['read', '-g', 'AppleLocale'], {encoding: 'utf8'}).trim() || fallback();
+			return cache;
+		} catch (err) {
+			return fallback();
+		}
+	}
+
+	cache = getLocale(res);
+	return cache;
+};
diff --git a/server/node_modules/os-locale/license b/server/node_modules/os-locale/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/os-locale/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/os-locale/package.json b/server/node_modules/os-locale/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..9a3c0237beb77d1b15112a876e23622aa24ff1d0
--- /dev/null
+++ b/server/node_modules/os-locale/package.json
@@ -0,0 +1,75 @@
+{
+  "_from": "os-locale@^1.4.0",
+  "_id": "os-locale@1.4.0",
+  "_inBundle": false,
+  "_integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+  "_location": "/os-locale",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "os-locale@^1.4.0",
+    "name": "os-locale",
+    "escapedName": "os-locale",
+    "rawSpec": "^1.4.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.4.0"
+  },
+  "_requiredBy": [
+    "/yargs"
+  ],
+  "_resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+  "_shasum": "20f9f17ae29ed345e8bde583b13d2009803c14d9",
+  "_spec": "os-locale@^1.4.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/os-locale/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "lcid": "^1.0.0"
+  },
+  "deprecated": false,
+  "description": "Get the system locale",
+  "devDependencies": {
+    "ava": "*",
+    "require-uncached": "^1.0.2",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/os-locale#readme",
+  "keywords": [
+    "locale",
+    "lang",
+    "language",
+    "system",
+    "os",
+    "string",
+    "str",
+    "user",
+    "country",
+    "id",
+    "identifier",
+    "region"
+  ],
+  "license": "MIT",
+  "name": "os-locale",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/os-locale.git"
+  },
+  "scripts": {
+    "test": "xo && ava"
+  },
+  "version": "1.4.0"
+}
diff --git a/server/node_modules/os-locale/readme.md b/server/node_modules/os-locale/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..b80a0bd0b4e6445aba7b43647e58d1a8e4041540
--- /dev/null
+++ b/server/node_modules/os-locale/readme.md
@@ -0,0 +1,47 @@
+# os-locale [![Build Status](https://travis-ci.org/sindresorhus/os-locale.svg?branch=master)](https://travis-ci.org/sindresorhus/os-locale)
+
+> Get the system [locale](http://en.wikipedia.org/wiki/Locale)
+
+Useful for localizing your module or app.
+
+POSIX systems: The returned locale refers to the [`LC_MESSAGE`](http://www.gnu.org/software/libc/manual/html_node/Locale-Categories.html#Locale-Categories) category, suitable for selecting the language used in the user interface for message translation.
+
+
+## Install
+
+```
+$ npm install --save os-locale
+```
+
+
+## Usage
+
+```js
+var osLocale = require('os-locale');
+
+osLocale(function (err, locale) {
+	console.log(locale);
+	//=> 'en_US'
+});
+```
+
+
+## API
+
+### osLocale([options], callback(error, locale))
+
+### osLocale.sync([options])
+
+Returns the locale.
+
+#### options.spawn
+
+Type: `boolean`  
+Default: `true`
+
+Set to `false` to avoid spawning subprocesses and instead only resolve the locale from environment variables.
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/packet-reader/.travis.yml b/server/node_modules/packet-reader/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ac2e9eeb3e6bec7921aca4b3edb8e9cf3c1114db
--- /dev/null
+++ b/server/node_modules/packet-reader/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+
+node_js: "10"
+matrix:
+  include:
+    - node_js: "4"
+    - node_js: "6"
+    - node_js: "8"
diff --git a/server/node_modules/packet-reader/README.md b/server/node_modules/packet-reader/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..5ae3ef85967cbcc7df776c6d2aaf9e4a927fb651
--- /dev/null
+++ b/server/node_modules/packet-reader/README.md
@@ -0,0 +1,87 @@
+node-packet-reader
+==================
+
+Handy little well tested module for reading length-prefixed binary packets.
+
+Since buffers come off a socket in randomly sized chunks you can't expect them to cleanly
+break on packet boundaries.  This module allows you to push buffers in and read
+full packets out the other side, so you can get to parsing right away and not have
+to manage concatenating partial buffers and searching through them for packets.
+
+## install
+
+` $ npm install packet-reader `
+
+## example
+
+```js
+var Reader = require('packet-reader')
+
+var reader = new Reader()
+//assuming you have a socket emitting `data` events
+socket.on('data', function(buffer) {
+  reader.addChunk(buffer)
+  var packet = reader.read()
+  while(packet) {
+    //do something with fully parsed packet
+  }
+})
+```
+
+
+here's a more full featured example:
+
+let's assume our "packet" for our protocol is 32-bit Big Endian length-prefixed strings
+so a "hello world" packet would look something like [length, string]
+`[0, 0, 0 0x0B, h, e, l, l, o, w, o, r, l, d]`
+
+```js
+var Transform = require('stream').Transform
+var Reader = require('packet-reader')
+var reader = new Reader()
+var parser = new Transform()
+parser._transform = function(chunk, encoding, cb) {
+  reader.addChunk(chunk)
+  var packet = reader.read()
+  while(packet) {
+    this.push(packet.toString('utf8'))
+    packet = reader.read()
+  }
+  cb()
+}
+
+var server = net.createServer(function(socket) {
+  socket.pipe(parser).pipe(stdout)
+})
+
+```
+
+There are a few config options for setting optional pre-length padding byte.  Read the tests for details.
+
+## License
+
+MIT
+
+Copyright 2015 Brian M. Carlson
+All rights reserved.
+
+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.
diff --git a/server/node_modules/packet-reader/index.js b/server/node_modules/packet-reader/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..5e97e2175fff3f7969425f69122b9e8d10075470
--- /dev/null
+++ b/server/node_modules/packet-reader/index.js
@@ -0,0 +1,65 @@
+var assert = require('assert')
+
+var Reader = module.exports = function(options) {
+  //TODO - remove for version 1.0
+  if(typeof options == 'number') {
+    options = { headerSize: options }
+  }
+  options = options || {}
+  this.offset = 0
+  this.lastChunk = false
+  this.chunk = null
+  this.chunkLength = 0
+  this.headerSize = options.headerSize || 0
+  this.lengthPadding = options.lengthPadding || 0
+  this.header = null
+  assert(this.headerSize < 2, 'pre-length header of more than 1 byte length not currently supported')
+}
+
+Reader.prototype.addChunk = function(chunk) {
+  if (!this.chunk || this.offset === this.chunkLength) {
+    this.chunk = chunk
+    this.chunkLength = chunk.length
+    this.offset = 0
+    return
+  }
+
+  var newChunkLength = chunk.length
+  var newLength = this.chunkLength + newChunkLength
+
+  if (newLength > this.chunk.length) {
+    var newBufferLength = this.chunk.length * 2
+    while (newLength >= newBufferLength) {
+      newBufferLength *= 2
+    }
+    var newBuffer = Buffer.alloc(newBufferLength)
+    this.chunk.copy(newBuffer)
+    this.chunk = newBuffer
+  }
+  chunk.copy(this.chunk, this.chunkLength)
+  this.chunkLength = newLength
+}
+
+Reader.prototype.read = function() {
+  if(this.chunkLength < (this.headerSize + 4 + this.offset)) {
+    return false
+  }
+
+  if(this.headerSize) {
+    this.header = this.chunk[this.offset]
+  }
+
+  //read length of next item
+  var length = this.chunk.readUInt32BE(this.offset + this.headerSize) + this.lengthPadding
+
+  //next item spans more chunks than we have
+  var remaining = this.chunkLength - (this.offset + 4 + this.headerSize)
+  if(length > remaining) {
+    return false
+  }
+
+  this.offset += (this.headerSize + 4)
+  var result = this.chunk.slice(this.offset, this.offset + length)
+  this.offset += length
+  return result
+}
diff --git a/server/node_modules/packet-reader/package.json b/server/node_modules/packet-reader/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..4802d68e9ee318d5ae837d0eda166fb72649c313
--- /dev/null
+++ b/server/node_modules/packet-reader/package.json
@@ -0,0 +1,52 @@
+{
+  "_from": "packet-reader@1.0.0",
+  "_id": "packet-reader@1.0.0",
+  "_inBundle": false,
+  "_integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==",
+  "_location": "/packet-reader",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "packet-reader@1.0.0",
+    "name": "packet-reader",
+    "escapedName": "packet-reader",
+    "rawSpec": "1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "1.0.0"
+  },
+  "_requiredBy": [
+    "/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
+  "_shasum": "9238e5480dedabacfe1fe3f2771063f164157d74",
+  "_spec": "packet-reader@1.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg",
+  "author": {
+    "name": "Brian M. Carlson"
+  },
+  "bugs": {
+    "url": "https://github.com/brianc/node-packet-reader/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Read binary packets...",
+  "devDependencies": {
+    "mocha": "~1.21.5"
+  },
+  "directories": {
+    "test": "test"
+  },
+  "homepage": "https://github.com/brianc/node-packet-reader",
+  "license": "MIT",
+  "main": "index.js",
+  "name": "packet-reader",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianc/node-packet-reader.git"
+  },
+  "scripts": {
+    "test": "mocha"
+  },
+  "version": "1.0.0"
+}
diff --git a/server/node_modules/packet-reader/test/index.js b/server/node_modules/packet-reader/test/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..0e2eedbfd60827a2caec8454de7dc3341d917d1a
--- /dev/null
+++ b/server/node_modules/packet-reader/test/index.js
@@ -0,0 +1,148 @@
+var assert = require('assert')
+var Reader = require('../')
+describe('packet-reader', function() {
+  beforeEach(function() {
+    this.reader = new Reader(1)
+  })
+
+  it('reads perfect 1 length buffer', function() {
+    this.reader.addChunk(Buffer.from([0, 0, 0, 0, 1, 1]))
+    var result = this.reader.read()
+    assert.equal(result.length, 1)
+    assert.equal(result[0], 1)
+    assert.strictEqual(false, this.reader.read())
+  })
+
+  it('reads perfect longer buffer', function() {
+    this.reader.addChunk(Buffer.from([0, 0, 0, 0, 4, 1, 2, 3, 4]))
+    var result = this.reader.read()
+    assert.equal(result.length, 4)
+    assert.strictEqual(false, this.reader.read())
+  })
+
+  it('reads two parts', function() {
+    this.reader.addChunk(Buffer.from([0, 0, 0, 0, 1]))
+    var result = this.reader.read()
+    assert.strictEqual(false, result)
+    this.reader.addChunk(Buffer.from([2]))
+    var result = this.reader.read()
+    assert.equal(result.length, 1, 'should return 1 length buffer')
+    assert.equal(result[0], 2)
+    assert.strictEqual(this.reader.read(), false)
+  })
+
+  it('reads multi-part', function() {
+    this.reader.addChunk(Buffer.from([0, 0, 0, 0, 16]))
+    assert.equal(false, this.reader.read())
+    this.reader.addChunk(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]))
+    assert.equal(false, this.reader.read())
+    this.reader.addChunk(Buffer.from([9, 10, 11, 12, 13, 14, 15, 16]))
+    var result = this.reader.read()
+    assert.equal(result.length, 16)
+  })
+
+  it('resets internal buffer at end of packet', function() {
+    this.reader.addChunk(Buffer.from([0, 0, 0, 0, 16]))
+    this.reader.addChunk(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]))
+    this.reader.addChunk(Buffer.from([9, 10, 11, 12, 13, 14, 15, 16]))
+    var result = this.reader.read()
+    assert.equal(result.length, 16)
+
+    var newChunk = Buffer.from([0, 0, 0, 0, 16])
+    this.reader.addChunk(newChunk)
+    assert.equal(this.reader.offset, 0, 'should have been reset to 0.')
+    assert.strictEqual(this.reader.chunk, newChunk)
+  })
+
+  it('reads multiple messages from single chunk', function() {
+    this.reader.addChunk(Buffer.from([0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 2, 1, 2]))
+    var result = this.reader.read()
+    assert.equal(result.length, 1, 'should have 1 length buffer')
+    assert.equal(result[0], 1)
+    var result = this.reader.read()
+    assert.equal(result.length, 2, 'should have 2 length buffer but was ' + result.length)
+    assert.equal(result[0], 1)
+    assert.equal(result[1], 2)
+    assert.strictEqual(false, this.reader.read())
+  })
+
+  it('reads 1 and a split', function() {
+    this.reader.addChunk(Buffer.from([0, 0, 0, 0, 1, 1, 0, 0]))//, 0, 0, 2, 1, 2]))
+    var result = this.reader.read()
+    assert.equal(result.length, 1, 'should have 1 length buffer')
+    assert.equal(result[0], 1)
+    var result = this.reader.read()
+    assert.strictEqual(result, false)
+
+    this.reader.addChunk(Buffer.from([0, 0, 2, 1, 2]))
+    var result = this.reader.read()
+    assert.equal(result.length, 2, 'should have 2 length buffer but was ' + result.length)
+    assert.equal(result[0], 1)
+    assert.equal(result[1], 2)
+    assert.strictEqual(false, this.reader.read())
+  })
+})
+
+describe('variable length header', function() {
+  beforeEach(function() {
+    this.reader = new Reader()
+  })
+
+  it('reads double message buffers', function() {
+    this.reader.addChunk(Buffer.from([
+                                0, 0, 0, 1, 1,
+                                0, 0, 0, 2, 1, 2]))
+    var result = this.reader.read()
+    assert(result)
+    assert.equal(result.length, 1)
+    assert.equal(result[0], 1)
+    result = this.reader.read()
+    assert(result)
+    assert.equal(result.length, 2)
+    assert.equal(result[0], 1)
+    assert.equal(result[1], 2)
+    assert.strictEqual(this.reader.read(), false)
+  })
+})
+
+describe('1 length code', function() {
+  beforeEach(function() {
+    this.reader = new Reader(1)
+  })
+
+  it('reads code', function() {
+    this.reader.addChunk(Buffer.from([9, 0, 0, 0, 1, 1]))
+    var result = this.reader.read()
+    assert(result)
+    assert.equal(this.reader.header, 9)
+    assert.equal(result.length, 1)
+    assert.equal(result[0], 1)
+  })
+
+  it('is set on uncompleted read', function() {
+    assert.equal(this.reader.header, null)
+    this.reader.addChunk(Buffer.from([2, 0, 0, 0, 1]))
+    assert.strictEqual(this.reader.read(), false)
+    assert.equal(this.reader.header, 2)
+  })
+})
+
+describe('postgres style packet', function() {
+  beforeEach(function() {
+    this.reader = new Reader({
+      headerSize: 1,
+      lengthPadding: -4
+    })
+  })
+
+  it('reads with padded length', function() {
+    this.reader.addChunk(Buffer.from([1, 0, 0, 0, 8, 0, 0, 2, 0]))
+    var result = this.reader.read()
+    assert(result)
+    assert.equal(result.length, 4)
+    assert.equal(result[0], 0)
+    assert.equal(result[1], 0)
+    assert.equal(result[2], 2)
+    assert.equal(result[3], 0)
+  })
+})
diff --git a/server/node_modules/parse-json/index.js b/server/node_modules/parse-json/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..04add8ae27353ada9750afa453a79ceb0b1d419c
--- /dev/null
+++ b/server/node_modules/parse-json/index.js
@@ -0,0 +1,35 @@
+'use strict';
+var errorEx = require('error-ex');
+var fallback = require('./vendor/parse');
+
+var JSONError = errorEx('JSONError', {
+	fileName: errorEx.append('in %s')
+});
+
+module.exports = function (x, reviver, filename) {
+	if (typeof reviver === 'string') {
+		filename = reviver;
+		reviver = null;
+	}
+
+	try {
+		try {
+			return JSON.parse(x, reviver);
+		} catch (err) {
+			fallback.parse(x, {
+				mode: 'json',
+				reviver: reviver
+			});
+
+			throw err;
+		}
+	} catch (err) {
+		var jsonErr = new JSONError(err);
+
+		if (filename) {
+			jsonErr.fileName = filename;
+		}
+
+		throw jsonErr;
+	}
+};
diff --git a/server/node_modules/parse-json/license b/server/node_modules/parse-json/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/parse-json/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/parse-json/package.json b/server/node_modules/parse-json/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..23afa25e832403056510d390279801a56b9da1e8
--- /dev/null
+++ b/server/node_modules/parse-json/package.json
@@ -0,0 +1,78 @@
+{
+  "_from": "parse-json@^2.2.0",
+  "_id": "parse-json@2.2.0",
+  "_inBundle": false,
+  "_integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+  "_location": "/parse-json",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "parse-json@^2.2.0",
+    "name": "parse-json",
+    "escapedName": "parse-json",
+    "rawSpec": "^2.2.0",
+    "saveSpec": null,
+    "fetchSpec": "^2.2.0"
+  },
+  "_requiredBy": [
+    "/load-json-file"
+  ],
+  "_resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+  "_shasum": "f480f40434ef80741f8469099f8dea18f55a4dc9",
+  "_spec": "parse-json@^2.2.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/load-json-file",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/parse-json/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "error-ex": "^1.2.0"
+  },
+  "deprecated": false,
+  "description": "Parse JSON with more helpful errors",
+  "devDependencies": {
+    "ava": "0.0.4",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js",
+    "vendor"
+  ],
+  "homepage": "https://github.com/sindresorhus/parse-json#readme",
+  "keywords": [
+    "parse",
+    "json",
+    "graceful",
+    "error",
+    "message",
+    "humanize",
+    "friendly",
+    "helpful",
+    "string",
+    "str"
+  ],
+  "license": "MIT",
+  "name": "parse-json",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/parse-json.git"
+  },
+  "scripts": {
+    "test": "xo && node test.js"
+  },
+  "version": "2.2.0",
+  "xo": {
+    "ignores": [
+      "vendor/**"
+    ]
+  }
+}
diff --git a/server/node_modules/parse-json/readme.md b/server/node_modules/parse-json/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..ca96e60a69999b2fb6e95d9e079edf710a1232af
--- /dev/null
+++ b/server/node_modules/parse-json/readme.md
@@ -0,0 +1,83 @@
+# parse-json [![Build Status](https://travis-ci.org/sindresorhus/parse-json.svg?branch=master)](https://travis-ci.org/sindresorhus/parse-json)
+
+> Parse JSON with more helpful errors
+
+
+## Install
+
+```
+$ npm install --save parse-json
+```
+
+
+## Usage
+
+```js
+var parseJson = require('parse-json');
+var json = '{\n\t"foo": true,\n}';
+
+
+JSON.parse(json);
+/*
+undefined:3
+}
+^
+SyntaxError: Unexpected token }
+*/
+
+
+parseJson(json);
+/*
+JSONError: Trailing comma in object at 3:1
+}
+^
+*/
+
+
+parseJson(json, 'foo.json');
+/*
+JSONError: Trailing comma in object at 3:1 in foo.json
+}
+^
+*/
+
+
+// you can also add the filename at a later point
+try {
+	parseJson(json);
+} catch (err) {
+	err.fileName = 'foo.json';
+	throw err;
+}
+/*
+JSONError: Trailing comma in object at 3:1 in foo.json
+}
+^
+*/
+```
+
+## API
+
+### parseJson(input, [reviver], [filename])
+
+#### input
+
+Type: `string`
+
+#### reviver
+
+Type: `function`
+
+Prescribes how the value originally produced by parsing is transformed, before being returned. See [`JSON.parse` docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter
+) for more.
+
+#### filename
+
+Type: `string`
+
+Filename displayed in the error message.
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/parse-json/vendor/parse.js b/server/node_modules/parse-json/vendor/parse.js
new file mode 100644
index 0000000000000000000000000000000000000000..5f9fe998610d0fda32546a9d16f3d9b71d1287a8
--- /dev/null
+++ b/server/node_modules/parse-json/vendor/parse.js
@@ -0,0 +1,752 @@
+/*
+ * Author: Alex Kocharin <alex@kocharin.ru>
+ * GIT: https://github.com/rlidwka/jju
+ * License: WTFPL, grab your copy here: http://www.wtfpl.net/txt/copying/
+ */
+
+// RTFM: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
+
+var Uni = require('./unicode')
+
+function isHexDigit(x) {
+  return (x >= '0' && x <= '9')
+      || (x >= 'A' && x <= 'F')
+      || (x >= 'a' && x <= 'f')
+}
+
+function isOctDigit(x) {
+  return x >= '0' && x <= '7'
+}
+
+function isDecDigit(x) {
+  return x >= '0' && x <= '9'
+}
+
+var unescapeMap = {
+  '\'': '\'',
+  '"' : '"',
+  '\\': '\\',
+  'b' : '\b',
+  'f' : '\f',
+  'n' : '\n',
+  'r' : '\r',
+  't' : '\t',
+  'v' : '\v',
+  '/' : '/',
+}
+
+function formatError(input, msg, position, lineno, column, json5) {
+  var result = msg + ' at ' + (lineno + 1) + ':' + (column + 1)
+    , tmppos = position - column - 1
+    , srcline = ''
+    , underline = ''
+
+  var isLineTerminator = json5 ? Uni.isLineTerminator : Uni.isLineTerminatorJSON
+
+  // output no more than 70 characters before the wrong ones
+  if (tmppos < position - 70) {
+    tmppos = position - 70
+  }
+
+  while (1) {
+    var chr = input[++tmppos]
+
+    if (isLineTerminator(chr) || tmppos === input.length) {
+      if (position >= tmppos) {
+        // ending line error, so show it after the last char
+        underline += '^'
+      }
+      break
+    }
+    srcline += chr
+
+    if (position === tmppos) {
+      underline += '^'
+    } else if (position > tmppos) {
+      underline += input[tmppos] === '\t' ? '\t' : ' '
+    }
+
+    // output no more than 78 characters on the string
+    if (srcline.length > 78) break
+  }
+
+  return result + '\n' + srcline + '\n' + underline
+}
+
+function parse(input, options) {
+  // parse as a standard JSON mode
+  var json5 = !(options.mode === 'json' || options.legacy)
+  var isLineTerminator = json5 ? Uni.isLineTerminator : Uni.isLineTerminatorJSON
+  var isWhiteSpace = json5 ? Uni.isWhiteSpace : Uni.isWhiteSpaceJSON
+
+  var length = input.length
+    , lineno = 0
+    , linestart = 0
+    , position = 0
+    , stack = []
+
+  var tokenStart = function() {}
+  var tokenEnd = function(v) {return v}
+
+  /* tokenize({
+       raw: '...',
+       type: 'whitespace'|'comment'|'key'|'literal'|'separator'|'newline',
+       value: 'number'|'string'|'whatever',
+       path: [...],
+     })
+  */
+  if (options._tokenize) {
+    ;(function() {
+      var start = null
+      tokenStart = function() {
+        if (start !== null) throw Error('internal error, token overlap')
+        start = position
+      }
+
+      tokenEnd = function(v, type) {
+        if (start != position) {
+          var hash = {
+            raw: input.substr(start, position-start),
+            type: type,
+            stack: stack.slice(0),
+          }
+          if (v !== undefined) hash.value = v
+          options._tokenize.call(null, hash)
+        }
+        start = null
+        return v
+      }
+    })()
+  }
+
+  function fail(msg) {
+    var column = position - linestart
+
+    if (!msg) {
+      if (position < length) {
+        var token = '\'' +
+          JSON
+            .stringify(input[position])
+            .replace(/^"|"$/g, '')
+            .replace(/'/g, "\\'")
+            .replace(/\\"/g, '"')
+          + '\''
+
+        if (!msg) msg = 'Unexpected token ' + token
+      } else {
+        if (!msg) msg = 'Unexpected end of input'
+      }
+    }
+
+    var error = SyntaxError(formatError(input, msg, position, lineno, column, json5))
+    error.row = lineno + 1
+    error.column = column + 1
+    throw error
+  }
+
+  function newline(chr) {
+    // account for <cr><lf>
+    if (chr === '\r' && input[position] === '\n') position++
+    linestart = position
+    lineno++
+  }
+
+  function parseGeneric() {
+    var result
+
+    while (position < length) {
+      tokenStart()
+      var chr = input[position++]
+
+      if (chr === '"' || (chr === '\'' && json5)) {
+        return tokenEnd(parseString(chr), 'literal')
+
+      } else if (chr === '{') {
+        tokenEnd(undefined, 'separator')
+        return parseObject()
+
+      } else if (chr === '[') {
+        tokenEnd(undefined, 'separator')
+        return parseArray()
+
+      } else if (chr === '-'
+             ||  chr === '.'
+             ||  isDecDigit(chr)
+                 //           + number       Infinity          NaN
+             ||  (json5 && (chr === '+' || chr === 'I' || chr === 'N'))
+      ) {
+        return tokenEnd(parseNumber(), 'literal')
+
+      } else if (chr === 'n') {
+        parseKeyword('null')
+        return tokenEnd(null, 'literal')
+
+      } else if (chr === 't') {
+        parseKeyword('true')
+        return tokenEnd(true, 'literal')
+
+      } else if (chr === 'f') {
+        parseKeyword('false')
+        return tokenEnd(false, 'literal')
+
+      } else {
+        position--
+        return tokenEnd(undefined)
+      }
+    }
+  }
+
+  function parseKey() {
+    var result
+
+    while (position < length) {
+      tokenStart()
+      var chr = input[position++]
+
+      if (chr === '"' || (chr === '\'' && json5)) {
+        return tokenEnd(parseString(chr), 'key')
+
+      } else if (chr === '{') {
+        tokenEnd(undefined, 'separator')
+        return parseObject()
+
+      } else if (chr === '[') {
+        tokenEnd(undefined, 'separator')
+        return parseArray()
+
+      } else if (chr === '.'
+             ||  isDecDigit(chr)
+      ) {
+        return tokenEnd(parseNumber(true), 'key')
+
+      } else if (json5
+             &&  Uni.isIdentifierStart(chr) || (chr === '\\' && input[position] === 'u')) {
+        // unicode char or a unicode sequence
+        var rollback = position - 1
+        var result = parseIdentifier()
+
+        if (result === undefined) {
+          position = rollback
+          return tokenEnd(undefined)
+        } else {
+          return tokenEnd(result, 'key')
+        }
+
+      } else {
+        position--
+        return tokenEnd(undefined)
+      }
+    }
+  }
+
+  function skipWhiteSpace() {
+    tokenStart()
+    while (position < length) {
+      var chr = input[position++]
+
+      if (isLineTerminator(chr)) {
+        position--
+        tokenEnd(undefined, 'whitespace')
+        tokenStart()
+        position++
+        newline(chr)
+        tokenEnd(undefined, 'newline')
+        tokenStart()
+
+      } else if (isWhiteSpace(chr)) {
+        // nothing
+
+      } else if (chr === '/'
+             && json5
+             && (input[position] === '/' || input[position] === '*')
+      ) {
+        position--
+        tokenEnd(undefined, 'whitespace')
+        tokenStart()
+        position++
+        skipComment(input[position++] === '*')
+        tokenEnd(undefined, 'comment')
+        tokenStart()
+
+      } else {
+        position--
+        break
+      }
+    }
+    return tokenEnd(undefined, 'whitespace')
+  }
+
+  function skipComment(multi) {
+    while (position < length) {
+      var chr = input[position++]
+
+      if (isLineTerminator(chr)) {
+        // LineTerminator is an end of singleline comment
+        if (!multi) {
+          // let parent function deal with newline
+          position--
+          return
+        }
+
+        newline(chr)
+
+      } else if (chr === '*' && multi) {
+        // end of multiline comment
+        if (input[position] === '/') {
+          position++
+          return
+        }
+
+      } else {
+        // nothing
+      }
+    }
+
+    if (multi) {
+      fail('Unclosed multiline comment')
+    }
+  }
+
+  function parseKeyword(keyword) {
+    // keyword[0] is not checked because it should've checked earlier
+    var _pos = position
+    var len = keyword.length
+    for (var i=1; i<len; i++) {
+      if (position >= length || keyword[i] != input[position]) {
+        position = _pos-1
+        fail()
+      }
+      position++
+    }
+  }
+
+  function parseObject() {
+    var result = options.null_prototype ? Object.create(null) : {}
+      , empty_object = {}
+      , is_non_empty = false
+
+    while (position < length) {
+      skipWhiteSpace()
+      var item1 = parseKey()
+      skipWhiteSpace()
+      tokenStart()
+      var chr = input[position++]
+      tokenEnd(undefined, 'separator')
+
+      if (chr === '}' && item1 === undefined) {
+        if (!json5 && is_non_empty) {
+          position--
+          fail('Trailing comma in object')
+        }
+        return result
+
+      } else if (chr === ':' && item1 !== undefined) {
+        skipWhiteSpace()
+        stack.push(item1)
+        var item2 = parseGeneric()
+        stack.pop()
+
+        if (item2 === undefined) fail('No value found for key ' + item1)
+        if (typeof(item1) !== 'string') {
+          if (!json5 || typeof(item1) !== 'number') {
+            fail('Wrong key type: ' + item1)
+          }
+        }
+
+        if ((item1 in empty_object || empty_object[item1] != null) && options.reserved_keys !== 'replace') {
+          if (options.reserved_keys === 'throw') {
+            fail('Reserved key: ' + item1)
+          } else {
+            // silently ignore it
+          }
+        } else {
+          if (typeof(options.reviver) === 'function') {
+            item2 = options.reviver.call(null, item1, item2)
+          }
+
+          if (item2 !== undefined) {
+            is_non_empty = true
+            Object.defineProperty(result, item1, {
+              value: item2,
+              enumerable: true,
+              configurable: true,
+              writable: true,
+            })
+          }
+        }
+
+        skipWhiteSpace()
+
+        tokenStart()
+        var chr = input[position++]
+        tokenEnd(undefined, 'separator')
+
+        if (chr === ',') {
+          continue
+
+        } else if (chr === '}') {
+          return result
+
+        } else {
+          fail()
+        }
+
+      } else {
+        position--
+        fail()
+      }
+    }
+
+    fail()
+  }
+
+  function parseArray() {
+    var result = []
+
+    while (position < length) {
+      skipWhiteSpace()
+      stack.push(result.length)
+      var item = parseGeneric()
+      stack.pop()
+      skipWhiteSpace()
+      tokenStart()
+      var chr = input[position++]
+      tokenEnd(undefined, 'separator')
+
+      if (item !== undefined) {
+        if (typeof(options.reviver) === 'function') {
+          item = options.reviver.call(null, String(result.length), item)
+        }
+        if (item === undefined) {
+          result.length++
+          item = true // hack for check below, not included into result
+        } else {
+          result.push(item)
+        }
+      }
+
+      if (chr === ',') {
+        if (item === undefined) {
+          fail('Elisions are not supported')
+        }
+
+      } else if (chr === ']') {
+        if (!json5 && item === undefined && result.length) {
+          position--
+          fail('Trailing comma in array')
+        }
+        return result
+
+      } else {
+        position--
+        fail()
+      }
+    }
+  }
+
+  function parseNumber() {
+    // rewind because we don't know first char
+    position--
+
+    var start = position
+      , chr = input[position++]
+      , t
+
+    var to_num = function(is_octal) {
+      var str = input.substr(start, position - start)
+
+      if (is_octal) {
+        var result = parseInt(str.replace(/^0o?/, ''), 8)
+      } else {
+        var result = Number(str)
+      }
+
+      if (Number.isNaN(result)) {
+        position--
+        fail('Bad numeric literal - "' + input.substr(start, position - start + 1) + '"')
+      } else if (!json5 && !str.match(/^-?(0|[1-9][0-9]*)(\.[0-9]+)?(e[+-]?[0-9]+)?$/i)) {
+        // additional restrictions imposed by json
+        position--
+        fail('Non-json numeric literal - "' + input.substr(start, position - start + 1) + '"')
+      } else {
+        return result
+      }
+    }
+
+    // ex: -5982475.249875e+29384
+    //     ^ skipping this
+    if (chr === '-' || (chr === '+' && json5)) chr = input[position++]
+
+    if (chr === 'N' && json5) {
+      parseKeyword('NaN')
+      return NaN
+    }
+
+    if (chr === 'I' && json5) {
+      parseKeyword('Infinity')
+
+      // returning +inf or -inf
+      return to_num()
+    }
+
+    if (chr >= '1' && chr <= '9') {
+      // ex: -5982475.249875e+29384
+      //        ^^^ skipping these
+      while (position < length && isDecDigit(input[position])) position++
+      chr = input[position++]
+    }
+
+    // special case for leading zero: 0.123456
+    if (chr === '0') {
+      chr = input[position++]
+
+      //             new syntax, "0o777"           old syntax, "0777"
+      var is_octal = chr === 'o' || chr === 'O' || isOctDigit(chr)
+      var is_hex = chr === 'x' || chr === 'X'
+
+      if (json5 && (is_octal || is_hex)) {
+        while (position < length
+           &&  (is_hex ? isHexDigit : isOctDigit)( input[position] )
+        ) position++
+
+        var sign = 1
+        if (input[start] === '-') {
+          sign = -1
+          start++
+        } else if (input[start] === '+') {
+          start++
+        }
+
+        return sign * to_num(is_octal)
+      }
+    }
+
+    if (chr === '.') {
+      // ex: -5982475.249875e+29384
+      //                ^^^ skipping these
+      while (position < length && isDecDigit(input[position])) position++
+      chr = input[position++]
+    }
+
+    if (chr === 'e' || chr === 'E') {
+      chr = input[position++]
+      if (chr === '-' || chr === '+') position++
+      // ex: -5982475.249875e+29384
+      //                       ^^^ skipping these
+      while (position < length && isDecDigit(input[position])) position++
+      chr = input[position++]
+    }
+
+    // we have char in the buffer, so count for it
+    position--
+    return to_num()
+  }
+
+  function parseIdentifier() {
+    // rewind because we don't know first char
+    position--
+
+    var result = ''
+
+    while (position < length) {
+      var chr = input[position++]
+
+      if (chr === '\\'
+      &&  input[position] === 'u'
+      &&  isHexDigit(input[position+1])
+      &&  isHexDigit(input[position+2])
+      &&  isHexDigit(input[position+3])
+      &&  isHexDigit(input[position+4])
+      ) {
+        // UnicodeEscapeSequence
+        chr = String.fromCharCode(parseInt(input.substr(position+1, 4), 16))
+        position += 5
+      }
+
+      if (result.length) {
+        // identifier started
+        if (Uni.isIdentifierPart(chr)) {
+          result += chr
+        } else {
+          position--
+          return result
+        }
+
+      } else {
+        if (Uni.isIdentifierStart(chr)) {
+          result += chr
+        } else {
+          return undefined
+        }
+      }
+    }
+
+    fail()
+  }
+
+  function parseString(endChar) {
+    // 7.8.4 of ES262 spec
+    var result = ''
+
+    while (position < length) {
+      var chr = input[position++]
+
+      if (chr === endChar) {
+        return result
+
+      } else if (chr === '\\') {
+        if (position >= length) fail()
+        chr = input[position++]
+
+        if (unescapeMap[chr] && (json5 || (chr != 'v' && chr != "'"))) {
+          result += unescapeMap[chr]
+
+        } else if (json5 && isLineTerminator(chr)) {
+          // line continuation
+          newline(chr)
+
+        } else if (chr === 'u' || (chr === 'x' && json5)) {
+          // unicode/character escape sequence
+          var off = chr === 'u' ? 4 : 2
+
+          // validation for \uXXXX
+          for (var i=0; i<off; i++) {
+            if (position >= length) fail()
+            if (!isHexDigit(input[position])) fail('Bad escape sequence')
+            position++
+          }
+
+          result += String.fromCharCode(parseInt(input.substr(position-off, off), 16))
+        } else if (json5 && isOctDigit(chr)) {
+          if (chr < '4' && isOctDigit(input[position]) && isOctDigit(input[position+1])) {
+            // three-digit octal
+            var digits = 3
+          } else if (isOctDigit(input[position])) {
+            // two-digit octal
+            var digits = 2
+          } else {
+            var digits = 1
+          }
+          position += digits - 1
+          result += String.fromCharCode(parseInt(input.substr(position-digits, digits), 8))
+          /*if (!isOctDigit(input[position])) {
+            // \0 is allowed still
+            result += '\0'
+          } else {
+            fail('Octal literals are not supported')
+          }*/
+
+        } else if (json5) {
+          // \X -> x
+          result += chr
+
+        } else {
+          position--
+          fail()
+        }
+
+      } else if (isLineTerminator(chr)) {
+        fail()
+
+      } else {
+        if (!json5 && chr.charCodeAt(0) < 32) {
+          position--
+          fail('Unexpected control character')
+        }
+
+        // SourceCharacter but not one of " or \ or LineTerminator
+        result += chr
+      }
+    }
+
+    fail()
+  }
+
+  skipWhiteSpace()
+  var return_value = parseGeneric()
+  if (return_value !== undefined || position < length) {
+    skipWhiteSpace()
+
+    if (position >= length) {
+      if (typeof(options.reviver) === 'function') {
+        return_value = options.reviver.call(null, '', return_value)
+      }
+      return return_value
+    } else {
+      fail()
+    }
+
+  } else {
+    if (position) {
+      fail('No data, only a whitespace')
+    } else {
+      fail('No data, empty input')
+    }
+  }
+}
+
+/*
+ * parse(text, options)
+ * or
+ * parse(text, reviver)
+ *
+ * where:
+ * text - string
+ * options - object
+ * reviver - function
+ */
+module.exports.parse = function parseJSON(input, options) {
+  // support legacy functions
+  if (typeof(options) === 'function') {
+    options = {
+      reviver: options
+    }
+  }
+
+  if (input === undefined) {
+    // parse(stringify(x)) should be equal x
+    // with JSON functions it is not 'cause of undefined
+    // so we're fixing it
+    return undefined
+  }
+
+  // JSON.parse compat
+  if (typeof(input) !== 'string') input = String(input)
+  if (options == null) options = {}
+  if (options.reserved_keys == null) options.reserved_keys = 'ignore'
+
+  if (options.reserved_keys === 'throw' || options.reserved_keys === 'ignore') {
+    if (options.null_prototype == null) {
+      options.null_prototype = true
+    }
+  }
+
+  try {
+    return parse(input, options)
+  } catch(err) {
+    // jju is a recursive parser, so JSON.parse("{{{{{{{") could blow up the stack
+    //
+    // this catch is used to skip all those internal calls
+    if (err instanceof SyntaxError && err.row != null && err.column != null) {
+      var old_err = err
+      err = SyntaxError(old_err.message)
+      err.column = old_err.column
+      err.row = old_err.row
+    }
+    throw err
+  }
+}
+
+module.exports.tokenize = function tokenizeJSON(input, options) {
+  if (options == null) options = {}
+
+  options._tokenize = function(smth) {
+    if (options._addstack) smth.stack.unshift.apply(smth.stack, options._addstack)
+    tokens.push(smth)
+  }
+
+  var tokens = []
+  tokens.data = module.exports.parse(input, options)
+  return tokens
+}
+
diff --git a/server/node_modules/parse-json/vendor/unicode.js b/server/node_modules/parse-json/vendor/unicode.js
new file mode 100644
index 0000000000000000000000000000000000000000..1a29143c2d6b1c50e1efc805241ee0c5e9b603fa
--- /dev/null
+++ b/server/node_modules/parse-json/vendor/unicode.js
@@ -0,0 +1,71 @@
+
+// This is autogenerated with esprima tools, see:
+// https://github.com/ariya/esprima/blob/master/esprima.js
+//
+// PS: oh God, I hate Unicode
+
+// ECMAScript 5.1/Unicode v6.3.0 NonAsciiIdentifierStart:
+
+var Uni = module.exports
+
+module.exports.isWhiteSpace = function isWhiteSpace(x) {
+  // section 7.2, table 2
+  return x === '\u0020'
+      || x === '\u00A0'
+      || x === '\uFEFF' // <-- this is not a Unicode WS, only a JS one
+      || (x >= '\u0009' && x <= '\u000D') // 9 A B C D
+
+      // + whitespace characters from unicode, category Zs
+      || x === '\u1680'
+      || x === '\u180E'
+      || (x >= '\u2000' && x <= '\u200A') // 0 1 2 3 4 5 6 7 8 9 A
+      || x === '\u2028'
+      || x === '\u2029'
+      || x === '\u202F'
+      || x === '\u205F'
+      || x === '\u3000'
+}
+
+module.exports.isWhiteSpaceJSON = function isWhiteSpaceJSON(x) {
+  return x === '\u0020'
+      || x === '\u0009'
+      || x === '\u000A'
+      || x === '\u000D'
+}
+
+module.exports.isLineTerminator = function isLineTerminator(x) {
+  // ok, here is the part when JSON is wrong
+  // section 7.3, table 3
+  return x === '\u000A'
+      || x === '\u000D'
+      || x === '\u2028'
+      || x === '\u2029'
+}
+
+module.exports.isLineTerminatorJSON = function isLineTerminatorJSON(x) {
+  return x === '\u000A'
+      || x === '\u000D'
+}
+
+module.exports.isIdentifierStart = function isIdentifierStart(x) {
+  return x === '$'
+      || x === '_'
+      || (x >= 'A' && x <= 'Z')
+      || (x >= 'a' && x <= 'z')
+      || (x >= '\u0080' && Uni.NonAsciiIdentifierStart.test(x))
+}
+
+module.exports.isIdentifierPart = function isIdentifierPart(x) {
+  return x === '$'
+      || x === '_'
+      || (x >= 'A' && x <= 'Z')
+      || (x >= 'a' && x <= 'z')
+      || (x >= '0' && x <= '9') // <-- addition to Start
+      || (x >= '\u0080' && Uni.NonAsciiIdentifierPart.test(x))
+}
+
+module.exports.NonAsciiIdentifierStart = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/
+
+// ECMAScript 5.1/Unicode v6.3.0 NonAsciiIdentifierPart:
+
+module.exports.NonAsciiIdentifierPart = /[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/
diff --git a/server/node_modules/path-exists/index.js b/server/node_modules/path-exists/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..a7e680a7635969bbe5bc16853aebf9b56b508bfa
--- /dev/null
+++ b/server/node_modules/path-exists/index.js
@@ -0,0 +1,24 @@
+'use strict';
+var fs = require('fs');
+var Promise = require('pinkie-promise');
+
+module.exports = function (fp) {
+	var fn = typeof fs.access === 'function' ? fs.access : fs.stat;
+
+	return new Promise(function (resolve) {
+		fn(fp, function (err) {
+			resolve(!err);
+		});
+	});
+};
+
+module.exports.sync = function (fp) {
+	var fn = typeof fs.accessSync === 'function' ? fs.accessSync : fs.statSync;
+
+	try {
+		fn(fp);
+		return true;
+	} catch (err) {
+		return false;
+	}
+};
diff --git a/server/node_modules/path-exists/license b/server/node_modules/path-exists/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/path-exists/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/path-exists/package.json b/server/node_modules/path-exists/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..5d614e4893ef86263b547b691de45cbb36d81bc6
--- /dev/null
+++ b/server/node_modules/path-exists/package.json
@@ -0,0 +1,72 @@
+{
+  "_from": "path-exists@^2.0.0",
+  "_id": "path-exists@2.1.0",
+  "_inBundle": false,
+  "_integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+  "_location": "/path-exists",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "path-exists@^2.0.0",
+    "name": "path-exists",
+    "escapedName": "path-exists",
+    "rawSpec": "^2.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^2.0.0"
+  },
+  "_requiredBy": [
+    "/find-up"
+  ],
+  "_resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+  "_shasum": "0feb6c64f0fc518d9a754dd5efb62c7022761f4b",
+  "_spec": "path-exists@^2.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/find-up",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/path-exists/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "pinkie-promise": "^2.0.0"
+  },
+  "deprecated": false,
+  "description": "Check if a path exists",
+  "devDependencies": {
+    "ava": "*",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/path-exists#readme",
+  "keywords": [
+    "path",
+    "exists",
+    "exist",
+    "file",
+    "filepath",
+    "fs",
+    "filesystem",
+    "file-system",
+    "access",
+    "stat"
+  ],
+  "license": "MIT",
+  "name": "path-exists",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/path-exists.git"
+  },
+  "scripts": {
+    "test": "xo && ava"
+  },
+  "version": "2.1.0"
+}
diff --git a/server/node_modules/path-exists/readme.md b/server/node_modules/path-exists/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..8fbcd68df1c2ca330871b853f9f61979b45456b4
--- /dev/null
+++ b/server/node_modules/path-exists/readme.md
@@ -0,0 +1,45 @@
+# path-exists [![Build Status](https://travis-ci.org/sindresorhus/path-exists.svg?branch=master)](https://travis-ci.org/sindresorhus/path-exists)
+
+> Check if a path exists
+
+Because [`fs.exists()`](https://nodejs.org/api/fs.html#fs_fs_exists_path_callback) is being [deprecated](https://github.com/iojs/io.js/issues/103), but there's still a genuine use-case of being able to check if a path exists for other purposes than doing IO with it.
+
+Never use this before handling a file though:
+
+> In particular, checking if a file exists before opening it is an anti-pattern that leaves you vulnerable to race conditions: another process may remove the file between the calls to `fs.exists()` and `fs.open()`. Just open the file and handle the error when it's not there.
+
+
+## Install
+
+```
+$ npm install --save path-exists
+```
+
+
+## Usage
+
+```js
+// foo.js
+var pathExists = require('path-exists');
+
+pathExists('foo.js').then(function (exists) {
+	console.log(exists);
+	//=> true
+});
+```
+
+
+## API
+
+### pathExists(path)
+
+Returns a promise that resolves to a boolean of whether the path exists.
+
+### pathExists.sync(path)
+
+Returns a boolean of whether the path exists.
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/path-parse/.travis.yml b/server/node_modules/path-parse/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dae31da968ba1f1a670dc8364de5a79d7621a732
--- /dev/null
+++ b/server/node_modules/path-parse/.travis.yml
@@ -0,0 +1,9 @@
+language: node_js
+node_js:
+  - "0.12"
+  - "0.11"
+  - "0.10"
+  - "0.10.12"
+  - "0.8"
+  - "0.6"
+  - "iojs"
diff --git a/server/node_modules/path-parse/LICENSE b/server/node_modules/path-parse/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..810f3dbea83b538626b466a1aa3d60ed8cf27281
--- /dev/null
+++ b/server/node_modules/path-parse/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Javier Blanco
+
+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.
diff --git a/server/node_modules/path-parse/README.md b/server/node_modules/path-parse/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..05097f86aef364d88bab44fac2ce01c2d825ada9
--- /dev/null
+++ b/server/node_modules/path-parse/README.md
@@ -0,0 +1,42 @@
+# path-parse [![Build Status](https://travis-ci.org/jbgutierrez/path-parse.svg?branch=master)](https://travis-ci.org/jbgutierrez/path-parse)
+
+> Node.js [`path.parse(pathString)`](https://nodejs.org/api/path.html#path_path_parse_pathstring) [ponyfill](https://ponyfill.com).
+
+## Install
+
+```
+$ npm install --save path-parse
+```
+
+## Usage
+
+```js
+var pathParse = require('path-parse');
+
+pathParse('/home/user/dir/file.txt');
+//=> {
+//       root : "/",
+//       dir : "/home/user/dir",
+//       base : "file.txt",
+//       ext : ".txt",
+//       name : "file"
+//   }
+```
+
+## API
+
+See [`path.parse(pathString)`](https://nodejs.org/api/path.html#path_path_parse_pathstring) docs.
+
+### pathParse(path)
+
+### pathParse.posix(path)
+
+The Posix specific version.
+
+### pathParse.win32(path)
+
+The Windows specific version.
+
+## License
+
+MIT © [Javier Blanco](http://jbgutierrez.info)
diff --git a/server/node_modules/path-parse/index.js b/server/node_modules/path-parse/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..3b7601fe494eede58912791441c070040394702a
--- /dev/null
+++ b/server/node_modules/path-parse/index.js
@@ -0,0 +1,93 @@
+'use strict';
+
+var isWindows = process.platform === 'win32';
+
+// Regex to split a windows path into three parts: [*, device, slash,
+// tail] windows-only
+var splitDeviceRe =
+    /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/;
+
+// Regex to split the tail part of the above into [*, dir, basename, ext]
+var splitTailRe =
+    /^([\s\S]*?)((?:\.{1,2}|[^\\\/]+?|)(\.[^.\/\\]*|))(?:[\\\/]*)$/;
+
+var win32 = {};
+
+// Function to split a filename into [root, dir, basename, ext]
+function win32SplitPath(filename) {
+  // Separate device+slash from tail
+  var result = splitDeviceRe.exec(filename),
+      device = (result[1] || '') + (result[2] || ''),
+      tail = result[3] || '';
+  // Split the tail into dir, basename and extension
+  var result2 = splitTailRe.exec(tail),
+      dir = result2[1],
+      basename = result2[2],
+      ext = result2[3];
+  return [device, dir, basename, ext];
+}
+
+win32.parse = function(pathString) {
+  if (typeof pathString !== 'string') {
+    throw new TypeError(
+        "Parameter 'pathString' must be a string, not " + typeof pathString
+    );
+  }
+  var allParts = win32SplitPath(pathString);
+  if (!allParts || allParts.length !== 4) {
+    throw new TypeError("Invalid path '" + pathString + "'");
+  }
+  return {
+    root: allParts[0],
+    dir: allParts[0] + allParts[1].slice(0, -1),
+    base: allParts[2],
+    ext: allParts[3],
+    name: allParts[2].slice(0, allParts[2].length - allParts[3].length)
+  };
+};
+
+
+
+// Split a filename into [root, dir, basename, ext], unix version
+// 'root' is just a slash, or nothing.
+var splitPathRe =
+    /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+var posix = {};
+
+
+function posixSplitPath(filename) {
+  return splitPathRe.exec(filename).slice(1);
+}
+
+
+posix.parse = function(pathString) {
+  if (typeof pathString !== 'string') {
+    throw new TypeError(
+        "Parameter 'pathString' must be a string, not " + typeof pathString
+    );
+  }
+  var allParts = posixSplitPath(pathString);
+  if (!allParts || allParts.length !== 4) {
+    throw new TypeError("Invalid path '" + pathString + "'");
+  }
+  allParts[1] = allParts[1] || '';
+  allParts[2] = allParts[2] || '';
+  allParts[3] = allParts[3] || '';
+
+  return {
+    root: allParts[0],
+    dir: allParts[0] + allParts[1].slice(0, -1),
+    base: allParts[2],
+    ext: allParts[3],
+    name: allParts[2].slice(0, allParts[2].length - allParts[3].length)
+  };
+};
+
+
+if (isWindows)
+  module.exports = win32.parse;
+else /* posix */
+  module.exports = posix.parse;
+
+module.exports.posix = posix.parse;
+module.exports.win32 = win32.parse;
diff --git a/server/node_modules/path-parse/package.json b/server/node_modules/path-parse/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..145ebb7b3142e82436837a0f6416faf8f187e093
--- /dev/null
+++ b/server/node_modules/path-parse/package.json
@@ -0,0 +1,61 @@
+{
+  "_from": "path-parse@^1.0.6",
+  "_id": "path-parse@1.0.6",
+  "_inBundle": false,
+  "_integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+  "_location": "/path-parse",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "path-parse@^1.0.6",
+    "name": "path-parse",
+    "escapedName": "path-parse",
+    "rawSpec": "^1.0.6",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.6"
+  },
+  "_requiredBy": [
+    "/resolve"
+  ],
+  "_resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+  "_shasum": "d62dbb5679405d72c4737ec58600e9ddcf06d24c",
+  "_spec": "path-parse@^1.0.6",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/resolve",
+  "author": {
+    "name": "Javier Blanco",
+    "email": "http://jbgutierrez.info"
+  },
+  "bugs": {
+    "url": "https://github.com/jbgutierrez/path-parse/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Node.js path.parse() ponyfill",
+  "homepage": "https://github.com/jbgutierrez/path-parse#readme",
+  "keywords": [
+    "path",
+    "paths",
+    "file",
+    "dir",
+    "parse",
+    "built-in",
+    "util",
+    "utils",
+    "core",
+    "ponyfill",
+    "polyfill",
+    "shim"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "path-parse",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/jbgutierrez/path-parse.git"
+  },
+  "scripts": {
+    "test": "node test.js"
+  },
+  "version": "1.0.6"
+}
diff --git a/server/node_modules/path-parse/test.js b/server/node_modules/path-parse/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..0b30c123936395a13bf126f8682b719e22487d0f
--- /dev/null
+++ b/server/node_modules/path-parse/test.js
@@ -0,0 +1,77 @@
+var assert = require('assert');
+var pathParse = require('./index');
+
+var winParseTests = [
+  [{ root: 'C:\\', dir: 'C:\\path\\dir', base: 'index.html', ext: '.html', name: 'index' }, 'C:\\path\\dir\\index.html'],
+  [{ root: 'C:\\', dir: 'C:\\another_path\\DIR\\1\\2\\33', base: 'index', ext: '', name: 'index' }, 'C:\\another_path\\DIR\\1\\2\\33\\index'],
+  [{ root: '', dir: 'another_path\\DIR with spaces\\1\\2\\33', base: 'index', ext: '', name: 'index' }, 'another_path\\DIR with spaces\\1\\2\\33\\index'],
+  [{ root: '\\', dir: '\\foo', base: 'C:', ext: '', name: 'C:' }, '\\foo\\C:'],
+  [{ root: '', dir: '', base: 'file', ext: '', name: 'file' }, 'file'],
+  [{ root: '', dir: '.', base: 'file', ext: '', name: 'file' }, '.\\file'],
+
+  // unc
+  [{ root: '\\\\server\\share\\', dir: '\\\\server\\share\\', base: 'file_path', ext: '', name: 'file_path' }, '\\\\server\\share\\file_path'],
+  [{ root: '\\\\server two\\shared folder\\', dir: '\\\\server two\\shared folder\\', base: 'file path.zip', ext: '.zip', name: 'file path' }, '\\\\server two\\shared folder\\file path.zip'],
+  [{ root: '\\\\teela\\admin$\\', dir: '\\\\teela\\admin$\\', base: 'system32', ext: '', name: 'system32' }, '\\\\teela\\admin$\\system32'],
+  [{ root: '\\\\?\\UNC\\', dir: '\\\\?\\UNC\\server', base: 'share', ext: '', name: 'share' }, '\\\\?\\UNC\\server\\share']
+];
+
+var winSpecialCaseFormatTests = [
+  [{dir: 'some\\dir'}, 'some\\dir\\'],
+  [{base: 'index.html'}, 'index.html'],
+  [{}, '']
+];
+
+var unixParseTests = [
+  [{ root: '/', dir: '/home/user/dir', base: 'file.txt', ext: '.txt', name: 'file' }, '/home/user/dir/file.txt'],
+  [{ root: '/', dir: '/home/user/a dir', base: 'another File.zip', ext: '.zip', name: 'another File' }, '/home/user/a dir/another File.zip'],
+  [{ root: '/', dir: '/home/user/a dir/', base: 'another&File.', ext: '.', name: 'another&File' }, '/home/user/a dir//another&File.'],
+  [{ root: '/', dir: '/home/user/a$$$dir/', base: 'another File.zip', ext: '.zip', name: 'another File' }, '/home/user/a$$$dir//another File.zip'],
+  [{ root: '', dir: 'user/dir', base: 'another File.zip', ext: '.zip', name: 'another File' }, 'user/dir/another File.zip'],
+  [{ root: '', dir: '', base: 'file', ext: '', name: 'file' }, 'file'],
+  [{ root: '', dir: '', base: '.\\file', ext: '', name: '.\\file' }, '.\\file'],
+  [{ root: '', dir: '.', base: 'file', ext: '', name: 'file' }, './file'],
+  [{ root: '', dir: '', base: 'C:\\foo', ext: '', name: 'C:\\foo' }, 'C:\\foo']
+];
+
+var unixSpecialCaseFormatTests = [
+  [{dir: 'some/dir'}, 'some/dir/'],
+  [{base: 'index.html'}, 'index.html'],
+  [{}, '']
+];
+
+var errors = [
+  {input: null, message: /Parameter 'pathString' must be a string, not/},
+  {input: {}, message: /Parameter 'pathString' must be a string, not object/},
+  {input: true, message: /Parameter 'pathString' must be a string, not boolean/},
+  {input: 1, message: /Parameter 'pathString' must be a string, not number/},
+  {input: undefined, message: /Parameter 'pathString' must be a string, not undefined/},
+];
+
+checkParseFormat(pathParse.win32, winParseTests);
+checkParseFormat(pathParse.posix, unixParseTests);
+checkErrors(pathParse.win32);
+checkErrors(pathParse.posix);
+
+function checkErrors(parse) {
+  errors.forEach(function(errorCase) {
+    try {
+      parse(errorCase.input);
+    } catch(err) {
+      assert.ok(err instanceof TypeError);
+      assert.ok(
+        errorCase.message.test(err.message),
+        'expected ' + errorCase.message + ' to match ' + err.message
+      );
+      return;
+    }
+
+    assert.fail('should have thrown');
+  });
+}
+
+function checkParseFormat(parse, testCases) {
+  testCases.forEach(function(testCase) {
+    assert.deepEqual(parse(testCase[1]), testCase[0]);
+  });
+}
diff --git a/server/node_modules/path-type/index.js b/server/node_modules/path-type/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..207a1d19cc5eb129958fafa6235d7d4f630154e0
--- /dev/null
+++ b/server/node_modules/path-type/index.js
@@ -0,0 +1,29 @@
+'use strict';
+var fs = require('graceful-fs');
+var Promise = require('pinkie-promise');
+var pify = require('pify');
+
+function type(fn, fn2, fp) {
+	if (typeof fp !== 'string') {
+		return Promise.reject(new TypeError('Expected a string'));
+	}
+
+	return pify(fs[fn], Promise)(fp).then(function (stats) {
+		return stats[fn2]();
+	});
+}
+
+function typeSync(fn, fn2, fp) {
+	if (typeof fp !== 'string') {
+		throw new TypeError('Expected a string');
+	}
+
+	return fs[fn](fp)[fn2]();
+}
+
+exports.file = type.bind(null, 'stat', 'isFile');
+exports.dir = type.bind(null, 'stat', 'isDirectory');
+exports.symlink = type.bind(null, 'lstat', 'isSymbolicLink');
+exports.fileSync = typeSync.bind(null, 'statSync', 'isFile');
+exports.dirSync = typeSync.bind(null, 'statSync', 'isDirectory');
+exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink');
diff --git a/server/node_modules/path-type/license b/server/node_modules/path-type/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/path-type/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/path-type/package.json b/server/node_modules/path-type/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..9d51e3fe5e541081f9c3a33dd13b3bd73f771af5
--- /dev/null
+++ b/server/node_modules/path-type/package.json
@@ -0,0 +1,84 @@
+{
+  "_from": "path-type@^1.0.0",
+  "_id": "path-type@1.1.0",
+  "_inBundle": false,
+  "_integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+  "_location": "/path-type",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "path-type@^1.0.0",
+    "name": "path-type",
+    "escapedName": "path-type",
+    "rawSpec": "^1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.0"
+  },
+  "_requiredBy": [
+    "/read-pkg"
+  ],
+  "_resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+  "_shasum": "59c44f7ee491da704da415da5a4070ba4f8fe441",
+  "_spec": "path-type@^1.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/read-pkg",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/path-type/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "graceful-fs": "^4.1.2",
+    "pify": "^2.0.0",
+    "pinkie-promise": "^2.0.0"
+  },
+  "deprecated": false,
+  "description": "Check if a path is a file, directory, or symlink",
+  "devDependencies": {
+    "ava": "*",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/path-type#readme",
+  "keywords": [
+    "path",
+    "fs",
+    "type",
+    "is",
+    "check",
+    "directory",
+    "dir",
+    "file",
+    "filepath",
+    "symlink",
+    "symbolic",
+    "link",
+    "stat",
+    "stats",
+    "filesystem"
+  ],
+  "license": "MIT",
+  "name": "path-type",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/path-type.git"
+  },
+  "scripts": {
+    "test": "xo && ava"
+  },
+  "version": "1.1.0",
+  "xo": {
+    "ignores": [
+      "test.js"
+    ]
+  }
+}
diff --git a/server/node_modules/path-type/readme.md b/server/node_modules/path-type/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..eac12d609ed3f7d3b77e3f125ff50a54f2ef6260
--- /dev/null
+++ b/server/node_modules/path-type/readme.md
@@ -0,0 +1,42 @@
+# path-type [![Build Status](https://travis-ci.org/sindresorhus/path-type.svg?branch=master)](https://travis-ci.org/sindresorhus/path-type)
+
+> Check if a path is a file, directory, or symlink
+
+
+## Install
+
+```
+$ npm install --save path-type
+```
+
+
+## Usage
+
+```js
+var pathType = require('path-type');
+
+pathType.file('package.json').then(function (isFile) {
+	console.log(isFile);
+	//=> true
+})
+```
+
+
+## API
+
+### .file(path)
+### .dir(path)
+### .symlink(path)
+
+Returns a promise that resolves to a boolean of whether the path is the checked type.
+
+### .fileSync(path)
+### .dirSync(path)
+### .symlinkSync(path)
+
+Returns a boolean of whether the path is the checked type.
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/pg-connection-string/.npmignore b/server/node_modules/pg-connection-string/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..da23d0d4bab05054b5ff73fe4d5910e17a6b278b
--- /dev/null
+++ b/server/node_modules/pg-connection-string/.npmignore
@@ -0,0 +1,25 @@
+# Logs
+logs
+*.log
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directory
+# Deployed apps should consider commenting this line out:
+# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
+node_modules
diff --git a/server/node_modules/pg-connection-string/.travis.yml b/server/node_modules/pg-connection-string/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..244b7e88e3273cafcfbd3a5499518859581d03d2
--- /dev/null
+++ b/server/node_modules/pg-connection-string/.travis.yml
@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+  - '0.10'
diff --git a/server/node_modules/pg-connection-string/LICENSE b/server/node_modules/pg-connection-string/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..b068a6cb2fe19df24ba034c3d27d78de8cd93ec7
--- /dev/null
+++ b/server/node_modules/pg-connection-string/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Iced Development
+
+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.
\ No newline at end of file
diff --git a/server/node_modules/pg-connection-string/README.md b/server/node_modules/pg-connection-string/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..49862702bac44b34647a453d73188a89ce04c0f9
--- /dev/null
+++ b/server/node_modules/pg-connection-string/README.md
@@ -0,0 +1,18 @@
+pg-connection-string
+====================
+
+[![Build Status](https://travis-ci.org/iceddev/pg-connection-string.svg?branch=master)](https://travis-ci.org/iceddev/pg-connection-string)
+
+Functions for dealing with a PostgresSQL connection string
+
+`parse` method taken from [node-postgres](https://github.com/brianc/node-postgres.git)
+Copyright (c) 2010-2014 Brian Carlson (brian.m.carlson@gmail.com)
+MIT License
+
+## Usage
+
+```js
+var parse = require('pg-connection-string').parse;
+
+var config = parse('postgres://someuser:somepassword@somehost:381/sometable')
+```
diff --git a/server/node_modules/pg-connection-string/index.js b/server/node_modules/pg-connection-string/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac2fd64c18e0b8c844504204e14fc24df3fe5aa5
--- /dev/null
+++ b/server/node_modules/pg-connection-string/index.js
@@ -0,0 +1,62 @@
+'use strict';
+
+var url = require('url');
+
+//Parse method copied from https://github.com/brianc/node-postgres
+//Copyright (c) 2010-2014 Brian Carlson (brian.m.carlson@gmail.com)
+//MIT License
+
+//parses a connection string
+function parse(str) {
+  var config;
+  //unix socket
+  if(str.charAt(0) === '/') {
+    config = str.split(' ');
+    return { host: config[0], database: config[1] };
+  }
+  // url parse expects spaces encoded as %20
+  if(/ |%[^a-f0-9]|%[a-f0-9][^a-f0-9]/i.test(str)) {
+    str = encodeURI(str).replace(/\%25(\d\d)/g, "%$1");
+  }
+  var result = url.parse(str, true);
+  config = {};
+
+  if (result.query.application_name) {
+    config.application_name = result.query.application_name;
+  }
+  if (result.query.fallback_application_name) {
+    config.fallback_application_name = result.query.fallback_application_name;
+  }
+
+  config.port = result.port;
+  if(result.protocol == 'socket:') {
+    config.host = decodeURI(result.pathname);
+    config.database = result.query.db;
+    config.client_encoding = result.query.encoding;
+    return config;
+  }
+  config.host = result.hostname;
+
+  // result.pathname is not always guaranteed to have a '/' prefix (e.g. relative urls)
+  // only strip the slash if it is present.
+  var pathname = result.pathname;
+  if (pathname && pathname.charAt(0) === '/') {
+    pathname = result.pathname.slice(1) || null;
+  }
+  config.database = pathname && decodeURI(pathname);
+
+  var auth = (result.auth || ':').split(':');
+  config.user = auth[0];
+  config.password = auth.splice(1).join(':');
+
+  var ssl = result.query.ssl;
+  if (ssl === 'true' || ssl === '1') {
+    config.ssl = true;
+  }
+
+  return config;
+}
+
+module.exports = {
+  parse: parse
+};
diff --git a/server/node_modules/pg-connection-string/package.json b/server/node_modules/pg-connection-string/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..848a8cf949a93c8f897f5e2211db3530bf92dc62
--- /dev/null
+++ b/server/node_modules/pg-connection-string/package.json
@@ -0,0 +1,58 @@
+{
+  "_from": "pg-connection-string@0.1.3",
+  "_id": "pg-connection-string@0.1.3",
+  "_inBundle": false,
+  "_integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=",
+  "_location": "/pg-connection-string",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "pg-connection-string@0.1.3",
+    "name": "pg-connection-string",
+    "escapedName": "pg-connection-string",
+    "rawSpec": "0.1.3",
+    "saveSpec": null,
+    "fetchSpec": "0.1.3"
+  },
+  "_requiredBy": [
+    "/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz",
+  "_shasum": "da1847b20940e42ee1492beaf65d49d91b245df7",
+  "_spec": "pg-connection-string@0.1.3",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg",
+  "author": {
+    "name": "Blaine Bublitz",
+    "email": "blaine@iceddev.com",
+    "url": "http://iceddev.com/"
+  },
+  "bugs": {
+    "url": "https://github.com/iceddev/pg-connection-string/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "Functions for dealing with a PostgresSQL connection string",
+  "devDependencies": {
+    "tap": "^0.4.11"
+  },
+  "homepage": "https://github.com/iceddev/pg-connection-string",
+  "keywords": [
+    "pg",
+    "connection",
+    "string",
+    "parse"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "pg-connection-string",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/iceddev/pg-connection-string.git"
+  },
+  "scripts": {
+    "test": "tap ./test"
+  },
+  "version": "0.1.3"
+}
diff --git a/server/node_modules/pg-connection-string/test/parse.js b/server/node_modules/pg-connection-string/test/parse.js
new file mode 100644
index 0000000000000000000000000000000000000000..c1494c31ee5967fa3d98137e2ffafef7c560df12
--- /dev/null
+++ b/server/node_modules/pg-connection-string/test/parse.js
@@ -0,0 +1,126 @@
+'use strict';
+
+var test = require('tap').test;
+
+var parse = require('../').parse;
+
+test('using connection string in client constructor', function(t){
+  var subject = parse('postgres://brian:pw@boom:381/lala');
+  t.equal(subject.user,'brian');
+  t.equal(subject.password, 'pw');
+  t.equal(subject.host, 'boom');
+  t.equal(subject.port, '381');
+  t.equal(subject.database, 'lala');
+  t.end();
+});
+
+test('escape spaces if present', function(t){
+  var subject = parse('postgres://localhost/post gres');
+  t.equal(subject.database, 'post gres');
+  t.end();
+});
+
+test('do not double escape spaces', function(t){
+  var subject = parse('postgres://localhost/post%20gres');
+  t.equal(subject.database, 'post gres');
+  t.end();
+});
+
+test('initializing with unix domain socket', function(t){
+  var subject = parse('/var/run/');
+  t.equal(subject.host, '/var/run/');
+  t.end();
+});
+
+test('initializing with unix domain socket and a specific database, the simple way', function(t){
+  var subject = parse('/var/run/ mydb');
+  t.equal(subject.host, '/var/run/');
+  t.equal(subject.database, 'mydb');
+  t.end();
+});
+
+test('initializing with unix domain socket, the health way', function(t){
+  var subject = parse('socket:/some path/?db=my[db]&encoding=utf8');
+  t.equal(subject.host, '/some path/');
+  t.equal(subject.database, 'my[db]', 'must to be escaped and unescaped trough "my%5Bdb%5D"');
+  t.equal(subject.client_encoding, 'utf8');
+  t.end();
+});
+
+test('initializing with unix domain socket, the escaped health way', function(t){
+  var subject = parse('socket:/some%20path/?db=my%2Bdb&encoding=utf8');
+  t.equal(subject.host, '/some path/');
+  t.equal(subject.database, 'my+db');
+  t.equal(subject.client_encoding, 'utf8');
+  t.end();
+});
+
+test('password contains  < and/or >  characters', function(t){
+  var sourceConfig = {
+    user:'brian',
+    password: 'hello<ther>e',
+    port: 5432,
+    host: 'localhost',
+    database: 'postgres'
+  };
+  var connectionString = 'postgres://' + sourceConfig.user + ':' + sourceConfig.password + '@' + sourceConfig.host + ':' + sourceConfig.port + '/' + sourceConfig.database;
+  var subject = parse(connectionString);
+  t.equal(subject.password, sourceConfig.password);
+  t.end();
+});
+
+test('password contains colons', function(t){
+  var sourceConfig = {
+    user:'brian',
+    password: 'hello:pass:world',
+    port: 5432,
+    host: 'localhost',
+    database: 'postgres'
+  };
+  var connectionString = 'postgres://' + sourceConfig.user + ':' + sourceConfig.password + '@' + sourceConfig.host + ':' + sourceConfig.port + '/' + sourceConfig.database;
+  var subject = parse(connectionString);
+  t.equal(subject.password, sourceConfig.password);
+  t.end();
+});
+
+test('username or password contains weird characters', function(t){
+  var strang = 'pg://my f%irst name:is&%awesome!@localhost:9000';
+  var subject = parse(strang);
+  t.equal(subject.user, 'my f%irst name');
+  t.equal(subject.password, 'is&%awesome!');
+  t.equal(subject.host, 'localhost');
+  t.end();
+});
+
+test('url is properly encoded', function(t){
+  var encoded = 'pg://bi%25na%25%25ry%20:s%40f%23@localhost/%20u%2520rl';
+  var subject = parse(encoded);
+  t.equal(subject.user, 'bi%na%%ry ');
+  t.equal(subject.password, 's@f#');
+  t.equal(subject.host, 'localhost');
+  t.equal(subject.database, ' u%20rl');
+  t.end();
+});
+
+test('relative url sets database', function(t){
+  var relative = 'different_db_on_default_host';
+  var subject = parse(relative);
+  t.equal(subject.database, 'different_db_on_default_host');
+  t.end();
+});
+
+test('no pathname returns null database', function (t) {
+  var subject = parse('pg://myhost');
+  t.equal(subject.host, 'myhost');
+  t.type(subject.database, 'null');
+
+  t.end();
+});
+
+test('pathname of "/" returns null database', function (t) {
+  var subject = parse('pg://myhost/');
+  t.equal(subject.host, 'myhost');
+  t.type(subject.database, 'null');
+
+  t.end();
+});
diff --git a/server/node_modules/pg-int8/LICENSE b/server/node_modules/pg-int8/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..c56c9731c140788997e7a389194eaf1c6f0fcc48
--- /dev/null
+++ b/server/node_modules/pg-int8/LICENSE
@@ -0,0 +1,13 @@
+Copyright © 2017, Charmander <~@charmander.me>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/server/node_modules/pg-int8/README.md b/server/node_modules/pg-int8/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ef2e6084317fb61ce1a62c198134099eec895981
--- /dev/null
+++ b/server/node_modules/pg-int8/README.md
@@ -0,0 +1,16 @@
+[![Build status][ci image]][ci]
+
+64-bit big-endian signed integer-to-string conversion designed for [pg][].
+
+```js
+const readInt8 = require('pg-int8');
+
+readInt8(Buffer.from([0, 1, 2, 3, 4, 5, 6, 7]))
+// '283686952306183'
+```
+
+
+  [pg]: https://github.com/brianc/node-postgres
+
+  [ci]: https://travis-ci.org/charmander/pg-int8
+  [ci image]: https://api.travis-ci.org/charmander/pg-int8.svg
diff --git a/server/node_modules/pg-int8/index.js b/server/node_modules/pg-int8/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..db7797503d7f3e2110fa76ab2ac9b8c8834a0289
--- /dev/null
+++ b/server/node_modules/pg-int8/index.js
@@ -0,0 +1,100 @@
+'use strict';
+
+// selected so (BASE - 1) * 0x100000000 + 0xffffffff is a safe integer
+var BASE = 1000000;
+
+function readInt8(buffer) {
+	var high = buffer.readInt32BE(0);
+	var low = buffer.readUInt32BE(4);
+	var sign = '';
+
+	if (high < 0) {
+		high = ~high + (low === 0);
+		low = (~low + 1) >>> 0;
+		sign = '-';
+	}
+
+	var result = '';
+	var carry;
+	var t;
+	var digits;
+	var pad;
+	var l;
+	var i;
+
+	{
+		carry = high % BASE;
+		high = high / BASE >>> 0;
+
+		t = 0x100000000 * carry + low;
+		low = t / BASE >>> 0;
+		digits = '' + (t - BASE * low);
+
+		if (low === 0 && high === 0) {
+			return sign + digits + result;
+		}
+
+		pad = '';
+		l = 6 - digits.length;
+
+		for (i = 0; i < l; i++) {
+			pad += '0';
+		}
+
+		result = pad + digits + result;
+	}
+
+	{
+		carry = high % BASE;
+		high = high / BASE >>> 0;
+
+		t = 0x100000000 * carry + low;
+		low = t / BASE >>> 0;
+		digits = '' + (t - BASE * low);
+
+		if (low === 0 && high === 0) {
+			return sign + digits + result;
+		}
+
+		pad = '';
+		l = 6 - digits.length;
+
+		for (i = 0; i < l; i++) {
+			pad += '0';
+		}
+
+		result = pad + digits + result;
+	}
+
+	{
+		carry = high % BASE;
+		high = high / BASE >>> 0;
+
+		t = 0x100000000 * carry + low;
+		low = t / BASE >>> 0;
+		digits = '' + (t - BASE * low);
+
+		if (low === 0 && high === 0) {
+			return sign + digits + result;
+		}
+
+		pad = '';
+		l = 6 - digits.length;
+
+		for (i = 0; i < l; i++) {
+			pad += '0';
+		}
+
+		result = pad + digits + result;
+	}
+
+	{
+		carry = high % BASE;
+		t = 0x100000000 * carry + low;
+		digits = '' + t % BASE;
+
+		return sign + digits + result;
+	}
+}
+
+module.exports = readInt8;
diff --git a/server/node_modules/pg-int8/package.json b/server/node_modules/pg-int8/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..30f5123466d09cb9f408fbc1edfeb287f85f511a
--- /dev/null
+++ b/server/node_modules/pg-int8/package.json
@@ -0,0 +1,52 @@
+{
+  "_from": "pg-int8@1.0.1",
+  "_id": "pg-int8@1.0.1",
+  "_inBundle": false,
+  "_integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
+  "_location": "/pg-int8",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "pg-int8@1.0.1",
+    "name": "pg-int8",
+    "escapedName": "pg-int8",
+    "rawSpec": "1.0.1",
+    "saveSpec": null,
+    "fetchSpec": "1.0.1"
+  },
+  "_requiredBy": [
+    "/pg-types"
+  ],
+  "_resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
+  "_shasum": "943bd463bf5b71b4170115f80f8efc9a0c0eb78c",
+  "_spec": "pg-int8@1.0.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg-types",
+  "bugs": {
+    "url": "https://github.com/charmander/pg-int8/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "64-bit big-endian signed integer-to-string conversion",
+  "devDependencies": {
+    "@charmander/eslint-config-base": "1.0.2",
+    "tap": "10.7.3"
+  },
+  "engines": {
+    "node": ">=4.0.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/charmander/pg-int8#readme",
+  "license": "ISC",
+  "name": "pg-int8",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/charmander/pg-int8.git"
+  },
+  "scripts": {
+    "test": "tap test"
+  },
+  "version": "1.0.1"
+}
diff --git a/server/node_modules/pg-pool/.travis.yml b/server/node_modules/pg-pool/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0deb0216c7364aa6cdfe04efc5cd9a864a0dbbfa
--- /dev/null
+++ b/server/node_modules/pg-pool/.travis.yml
@@ -0,0 +1,17 @@
+language: node_js
+
+matrix:
+  include:
+    - node_js: "4"
+      addons:
+        postgresql: "9.1"
+      dist: precise
+    - node_js: "6"
+      addons:
+        postgresql: "9.4"
+    - node_js: "8"
+      addons:
+        postgresql: "9.6"
+    - node_js: "10"
+      addons:
+        postgresql: "9.6"
diff --git a/server/node_modules/pg-pool/LICENSE b/server/node_modules/pg-pool/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..4e9058148e75f05ca4125f34eff371d08c014f6b
--- /dev/null
+++ b/server/node_modules/pg-pool/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Brian M. Carlson
+
+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.
diff --git a/server/node_modules/pg-pool/Makefile b/server/node_modules/pg-pool/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..8a76314266b58ab46a4c2717b19eb6a3e1962941
--- /dev/null
+++ b/server/node_modules/pg-pool/Makefile
@@ -0,0 +1,14 @@
+.PHONY: jshint test publish-patch test
+
+test:
+	npm test
+
+patch: test
+	npm version patch -m "Bump version"
+	git push origin master --tags
+	npm publish
+
+minor: test
+	npm version minor -m "Bump version"
+	git push origin master --tags
+	npm publish
diff --git a/server/node_modules/pg-pool/README.md b/server/node_modules/pg-pool/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a02fa32cce9e54f256eac9f8324e3289fa1d4203
--- /dev/null
+++ b/server/node_modules/pg-pool/README.md
@@ -0,0 +1,351 @@
+# pg-pool
+[![Build Status](https://travis-ci.org/brianc/node-pg-pool.svg?branch=master)](https://travis-ci.org/brianc/node-pg-pool)
+
+A connection pool for node-postgres
+
+## install
+```sh
+npm i pg-pool pg
+```
+
+## use
+
+### create
+
+to use pg-pool you must first create an instance of a pool
+
+```js
+var Pool = require('pg-pool')
+
+// by default the pool uses the same
+// configuration as whatever `pg` version you have installed
+var pool = new Pool()
+
+// you can pass properties to the pool
+// these properties are passed unchanged to both the node-postgres Client constructor
+// and the node-pool (https://github.com/coopernurse/node-pool) constructor
+// allowing you to fully configure the behavior of both
+var pool2 = new Pool({
+  database: 'postgres',
+  user: 'brianc',
+  password: 'secret!',
+  port: 5432,
+  ssl: true,
+  max: 20, // set pool max size to 20
+  min: 4, // set min pool size to 4
+  idleTimeoutMillis: 1000, // close idle clients after 1 second
+  connectionTimeoutMillis: 1000, // return an error after 1 second if connection could not be established
+})
+
+//you can supply a custom client constructor
+//if you want to use the native postgres client
+var NativeClient = require('pg').native.Client
+var nativePool = new Pool({ Client: NativeClient })
+
+//you can even pool pg-native clients directly
+var PgNativeClient = require('pg-native')
+var pgNativePool = new Pool({ Client: PgNativeClient })
+```
+
+##### Note:
+The Pool constructor does not support passing a Database URL as the parameter. To use pg-pool on heroku, for example, you need to parse the URL into a config object. Here is an example of how to parse a Database URL.
+
+```js
+const Pool = require('pg-pool');
+const url = require('url')
+
+const params = url.parse(process.env.DATABASE_URL);
+const auth = params.auth.split(':');
+
+const config = {
+  user: auth[0],
+  password: auth[1],
+  host: params.hostname,
+  port: params.port,
+  database: params.pathname.split('/')[1],
+  ssl: true
+};
+
+const pool = new Pool(config);
+
+/*
+  Transforms, 'progres://DBuser:secret@DBHost:#####/myDB', into
+  config = {
+    user: 'DBuser',
+    password: 'secret',
+    host: 'DBHost',
+    port: '#####',
+    database: 'myDB',
+    ssl: true
+  }
+*/
+``` 
+
+### acquire clients with a promise
+
+pg-pool supports a fully promise-based api for acquiring clients
+
+```js
+var pool = new Pool()
+pool.connect().then(client => {
+  client.query('select $1::text as name', ['pg-pool']).then(res => {
+    client.release()
+    console.log('hello from', res.rows[0].name)
+  })
+  .catch(e => {
+    client.release()
+    console.error('query error', e.message, e.stack)
+  })
+})
+```
+
+### plays nice with async/await
+
+this ends up looking much nicer if you're using [co](https://github.com/tj/co) or async/await:
+
+```js
+// with async/await
+(async () => {
+  var pool = new Pool()
+  var client = await pool.connect()
+  try {
+    var result = await client.query('select $1::text as name', ['brianc'])
+    console.log('hello from', result.rows[0])
+  } finally {
+    client.release()
+  }
+})().catch(e => console.error(e.message, e.stack))
+
+// with co
+co(function * () {
+  var client = yield pool.connect()
+  try {
+    var result = yield client.query('select $1::text as name', ['brianc'])
+    console.log('hello from', result.rows[0])
+  } finally {
+    client.release()
+  }
+}).catch(e => console.error(e.message, e.stack))
+```
+
+### your new favorite helper method
+
+because its so common to just run a query and return the client to the pool afterward pg-pool has this built-in:
+
+```js
+var pool = new Pool()
+var time = await pool.query('SELECT NOW()')
+var name = await pool.query('select $1::text as name', ['brianc'])
+console.log(name.rows[0].name, 'says hello at', time.rows[0].name)
+```
+
+you can also use a callback here if you'd like:
+
+```js
+var pool = new Pool()
+pool.query('SELECT $1::text as name', ['brianc'], function (err, res) {
+  console.log(res.rows[0].name) // brianc
+})
+```
+
+__pro tip:__ unless you need to run a transaction (which requires a single client for multiple queries) or you
+have some other edge case like [streaming rows](https://github.com/brianc/node-pg-query-stream) or using a [cursor](https://github.com/brianc/node-pg-cursor)
+you should almost always just use `pool.query`.  Its easy, it does the right thing :tm:, and wont ever forget to return
+clients back to the pool after the query is done.
+
+### drop-in backwards compatible
+
+pg-pool still and will always support the traditional callback api for acquiring a client.  This is the exact API node-postgres has shipped with for years:
+
+```js
+var pool = new Pool()
+pool.connect((err, client, done) => {
+  if (err) return done(err)
+
+  client.query('SELECT $1::text as name', ['pg-pool'], (err, res) => {
+    done()
+    if (err) {
+      return console.error('query error', e.message, e.stack)
+    }
+    console.log('hello from', res.rows[0].name)
+  })
+})
+```
+
+### shut it down
+
+When you are finished with the pool if all the clients are idle the pool will close them after `config.idleTimeoutMillis` and your app
+will shutdown gracefully.  If you don't want to wait for the timeout you can end the pool as follows:
+
+```js
+var pool = new Pool()
+var client = await pool.connect()
+console.log(await client.query('select now()'))
+client.release()
+await pool.end()
+```
+
+### a note on instances
+
+The pool should be a __long-lived object__ in your application.  Generally you'll want to instantiate one pool when your app starts up and use the same instance of the pool throughout the lifetime of your application.  If you are frequently creating a new pool within your code you likely don't have your pool initialization code in the correct place.  Example:
+
+```js
+// assume this is a file in your program at ./your-app/lib/db.js
+
+// correct usage: create the pool and let it live
+// 'globally' here, controlling access to it through exported methods
+var pool = new pg.Pool()
+
+// this is the right way to export the query method
+module.exports.query = (text, values) => {
+  console.log('query:', text, values)
+  return pool.query(text, values)
+}
+
+// this would be the WRONG way to export the connect method
+module.exports.connect = () => {
+  // notice how we would be creating a pool instance here
+  // every time we called 'connect' to get a new client?
+  // that's a bad thing & results in creating an unbounded
+  // number of pools & therefore connections
+  var aPool = new pg.Pool()
+  return aPool.connect()
+}
+```
+
+### events
+
+Every instance of a `Pool` is an event emitter.  These instances emit the following events:
+
+#### error
+
+Emitted whenever an idle client in the pool encounters an error.  This is common when your PostgreSQL server shuts down, reboots, or a network partition otherwise causes it to become unavailable while your pool has connected clients.
+
+Example:
+
+```js
+const Pool = require('pg-pool')
+const pool = new Pool()
+
+// attach an error handler to the pool for when a connected, idle client
+// receives an error by being disconnected, etc
+pool.on('error', function(error, client) {
+  // handle this in the same way you would treat process.on('uncaughtException')
+  // it is supplied the error as well as the idle client which received the error
+})
+```
+
+#### connect
+
+Fired whenever the pool creates a __new__ `pg.Client` instance and successfully connects it to the backend.
+
+Example:
+
+```js
+const Pool = require('pg-pool')
+const pool = new Pool()
+
+var count = 0
+
+pool.on('connect', client => {
+  client.count = count++
+})
+
+pool
+  .connect()
+  .then(client => {
+    return client
+      .query('SELECT $1::int AS "clientCount"', [client.count])
+      .then(res => console.log(res.rows[0].clientCount)) // outputs 0
+      .then(() => client)
+  })
+  .then(client => client.release())
+
+```
+
+#### acquire
+
+Fired whenever the a client is acquired from the pool
+
+Example:
+
+This allows you to count the number of clients which have ever been acquired from the pool.
+
+```js
+var Pool = require('pg-pool')
+var pool = new Pool()
+
+var acquireCount = 0
+pool.on('acquire', function (client) {
+  acquireCount++
+})
+
+var connectCount = 0
+pool.on('connect', function () {
+  connectCount++
+})
+
+for (var i = 0; i < 200; i++) {
+  pool.query('SELECT NOW()')
+}
+
+setTimeout(function () {
+  console.log('connect count:', connectCount) // output: connect count: 10
+  console.log('acquire count:', acquireCount) // output: acquire count: 200
+}, 100)
+
+```
+
+### environment variables
+
+pg-pool & node-postgres support some of the same environment variables as `psql` supports.  The most common are:
+
+```
+PGDATABASE=my_db
+PGUSER=username
+PGPASSWORD="my awesome password"
+PGPORT=5432
+PGSSLMODE=require
+```
+
+Usually I will export these into my local environment via a `.env` file with environment settings or export them in `~/.bash_profile` or something similar.  This way I get configurability which works with both the postgres suite of tools (`psql`, `pg_dump`, `pg_restore`) and node, I can vary the environment variables locally and in production, and it supports the concept of a [12-factor app](http://12factor.net/) out of the box.
+
+## bring your own promise
+
+In versions of node `<=0.12.x` there is no native promise implementation available globally.  You can polyfill the promise globally like this:
+
+```js
+// first run `npm install promise-polyfill --save
+if (typeof Promise == 'undefined') {
+  global.Promise = require('promise-polyfill')
+}
+```
+
+You can use any other promise implementation you'd like.  The pool also allows you to configure the promise implementation on a per-pool level:
+
+```js
+var bluebirdPool = new Pool({
+  Promise: require('bluebird')
+})
+```
+
+__please note:__ in node `<=0.12.x` the pool will throw if you do not provide a promise constructor in one of the two ways mentioned above.  In node `>=4.0.0` the pool will use the native promise implementation by default; however, the two methods above still allow you to "bring your own."
+
+## tests
+
+To run tests clone the repo, `npm i` in the working dir, and then run `npm test`
+
+## contributions
+
+I love contributions.  Please make sure they have tests, and submit a PR.  If you're not sure if the issue is worth it or will be accepted it never hurts to open an issue to begin the conversation.  If you're interested in keeping up with node-postgres releated stuff, you can follow me on twitter at [@briancarlson](https://twitter.com/briancarlson) - I generally announce any noteworthy updates there.
+
+## license
+
+The MIT License (MIT)
+Copyright (c) 2016 Brian M. Carlson
+
+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.
diff --git a/server/node_modules/pg-pool/index.js b/server/node_modules/pg-pool/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..e93cc96c9e7164c0795f9dfd57f969c99ed071dd
--- /dev/null
+++ b/server/node_modules/pg-pool/index.js
@@ -0,0 +1,366 @@
+'use strict'
+const EventEmitter = require('events').EventEmitter
+
+const NOOP = function () { }
+
+const removeWhere = (list, predicate) => {
+  const i = list.findIndex(predicate)
+
+  return i === -1
+    ? undefined
+    : list.splice(i, 1)[0]
+}
+
+class IdleItem {
+  constructor (client, idleListener, timeoutId) {
+    this.client = client
+    this.idleListener = idleListener
+    this.timeoutId = timeoutId
+  }
+}
+
+class PendingItem {
+  constructor (callback) {
+    this.callback = callback
+  }
+}
+
+function throwOnRelease () {
+  throw new Error('Release called on client which has already been released to the pool.')
+}
+
+function promisify (Promise, callback) {
+  if (callback) {
+    return { callback: callback, result: undefined }
+  }
+  let rej
+  let res
+  const cb = function (err, client) {
+    err ? rej(err) : res(client)
+  }
+  const result = new Promise(function (resolve, reject) {
+    res = resolve
+    rej = reject
+  })
+  return { callback: cb, result: result }
+}
+
+function makeIdleListener (pool, client) {
+  return function idleListener (err) {
+    err.client = client
+
+    client.removeListener('error', idleListener)
+    client.on('error', () => {
+      pool.log('additional client error after disconnection due to error', err)
+    })
+    pool._remove(client)
+    // TODO - document that once the pool emits an error
+    // the client has already been closed & purged and is unusable
+    pool.emit('error', err, client)
+  }
+}
+
+class Pool extends EventEmitter {
+  constructor (options, Client) {
+    super()
+    this.options = Object.assign({}, options)
+    this.options.max = this.options.max || this.options.poolSize || 10
+    this.log = this.options.log || function () { }
+    this.Client = this.options.Client || Client || require('pg').Client
+    this.Promise = this.options.Promise || global.Promise
+
+    if (typeof this.options.idleTimeoutMillis === 'undefined') {
+      this.options.idleTimeoutMillis = 10000
+    }
+
+    this._clients = []
+    this._idle = []
+    this._pendingQueue = []
+    this._endCallback = undefined
+    this.ending = false
+    this.ended = false
+  }
+
+  _isFull () {
+    return this._clients.length >= this.options.max
+  }
+
+  _pulseQueue () {
+    this.log('pulse queue')
+    if (this.ended) {
+      this.log('pulse queue ended')
+      return
+    }
+    if (this.ending) {
+      this.log('pulse queue on ending')
+      if (this._idle.length) {
+        this._idle.slice().map(item => {
+          this._remove(item.client)
+        })
+      }
+      if (!this._clients.length) {
+        this.ended = true
+        this._endCallback()
+      }
+      return
+    }
+    // if we don't have any waiting, do nothing
+    if (!this._pendingQueue.length) {
+      this.log('no queued requests')
+      return
+    }
+    // if we don't have any idle clients and we have no more room do nothing
+    if (!this._idle.length && this._isFull()) {
+      return
+    }
+    const pendingItem = this._pendingQueue.shift()
+    if (this._idle.length) {
+      const idleItem = this._idle.pop()
+      clearTimeout(idleItem.timeoutId)
+      const client = idleItem.client
+      const idleListener = idleItem.idleListener
+
+      return this._acquireClient(client, pendingItem, idleListener, false)
+    }
+    if (!this._isFull()) {
+      return this.newClient(pendingItem)
+    }
+    throw new Error('unexpected condition')
+  }
+
+  _remove (client) {
+    const removed = removeWhere(
+      this._idle,
+      item => item.client === client
+    )
+
+    if (removed !== undefined) {
+      clearTimeout(removed.timeoutId)
+    }
+
+    this._clients = this._clients.filter(c => c !== client)
+    client.end()
+    this.emit('remove', client)
+  }
+
+  connect (cb) {
+    if (this.ending) {
+      const err = new Error('Cannot use a pool after calling end on the pool')
+      return cb ? cb(err) : this.Promise.reject(err)
+    }
+
+    const response = promisify(this.Promise, cb)
+    const result = response.result
+
+    // if we don't have to connect a new client, don't do so
+    if (this._clients.length >= this.options.max || this._idle.length) {
+      // if we have idle clients schedule a pulse immediately
+      if (this._idle.length) {
+        process.nextTick(() => this._pulseQueue())
+      }
+
+      if (!this.options.connectionTimeoutMillis) {
+        this._pendingQueue.push(new PendingItem(response.callback))
+        return result
+      }
+
+      const queueCallback = (err, res, done) => {
+        clearTimeout(tid)
+        response.callback(err, res, done)
+      }
+
+      const pendingItem = new PendingItem(queueCallback)
+
+      // set connection timeout on checking out an existing client
+      const tid = setTimeout(() => {
+        // remove the callback from pending waiters because
+        // we're going to call it with a timeout error
+        removeWhere(this._pendingQueue, (i) => i.callback === queueCallback)
+        pendingItem.timedOut = true
+        response.callback(new Error('timeout exceeded when trying to connect'))
+      }, this.options.connectionTimeoutMillis)
+
+      this._pendingQueue.push(pendingItem)
+      return result
+    }
+
+    this.newClient(new PendingItem(response.callback))
+
+    return result
+  }
+
+  newClient (pendingItem) {
+    const client = new this.Client(this.options)
+    this._clients.push(client)
+    const idleListener = makeIdleListener(this, client)
+
+    this.log('checking client timeout')
+
+    // connection timeout logic
+    let tid
+    let timeoutHit = false
+    if (this.options.connectionTimeoutMillis) {
+      tid = setTimeout(() => {
+        this.log('ending client due to timeout')
+        timeoutHit = true
+        // force kill the node driver, and let libpq do its teardown
+        client.connection ? client.connection.stream.destroy() : client.end()
+      }, this.options.connectionTimeoutMillis)
+    }
+
+    this.log('connecting new client')
+    client.connect((err) => {
+      if (tid) {
+        clearTimeout(tid)
+      }
+      client.on('error', idleListener)
+      if (err) {
+        this.log('client failed to connect', err)
+        // remove the dead client from our list of clients
+        this._clients = this._clients.filter(c => c !== client)
+        if (timeoutHit) {
+          err.message = 'Connection terminated due to connection timeout'
+        }
+
+        // this client won’t be released, so move on immediately
+        this._pulseQueue()
+
+        if (!pendingItem.timedOut) {
+          pendingItem.callback(err, undefined, NOOP)
+        }
+      } else {
+        this.log('new client connected')
+
+        return this._acquireClient(client, pendingItem, idleListener, true)
+      }
+    })
+  }
+
+  // acquire a client for a pending work item
+  _acquireClient (client, pendingItem, idleListener, isNew) {
+    if (isNew) {
+      this.emit('connect', client)
+    }
+
+    this.emit('acquire', client)
+
+    let released = false
+
+    client.release = (err) => {
+      if (released) {
+        throwOnRelease()
+      }
+
+      released = true
+      this._release(client, idleListener, err)
+    }
+
+    client.removeListener('error', idleListener)
+
+    if (!pendingItem.timedOut) {
+      if (isNew && this.options.verify) {
+        this.options.verify(client, (err) => {
+          if (err) {
+            client.release(err)
+            return pendingItem.callback(err, undefined, NOOP)
+          }
+
+          pendingItem.callback(undefined, client, client.release)
+        })
+      } else {
+        pendingItem.callback(undefined, client, client.release)
+      }
+    } else {
+      if (isNew && this.options.verify) {
+        this.options.verify(client, client.release)
+      } else {
+        client.release()
+      }
+    }
+  }
+
+  // release a client back to the poll, include an error
+  // to remove it from the pool
+  _release (client, idleListener, err) {
+    client.on('error', idleListener)
+
+    if (err || this.ending) {
+      this._remove(client)
+      this._pulseQueue()
+      return
+    }
+
+    // idle timeout
+    let tid
+    if (this.options.idleTimeoutMillis) {
+      tid = setTimeout(() => {
+        this.log('remove idle client')
+        this._remove(client)
+      }, this.options.idleTimeoutMillis)
+    }
+
+    this._idle.push(new IdleItem(client, idleListener, tid))
+    this._pulseQueue()
+  }
+
+  query (text, values, cb) {
+    // guard clause against passing a function as the first parameter
+    if (typeof text === 'function') {
+      const response = promisify(this.Promise, text)
+      setImmediate(function () {
+        return response.callback(new Error('Passing a function as the first parameter to pool.query is not supported'))
+      })
+      return response.result
+    }
+
+    // allow plain text query without values
+    if (typeof values === 'function') {
+      cb = values
+      values = undefined
+    }
+    const response = promisify(this.Promise, cb)
+    cb = response.callback
+    this.connect((err, client) => {
+      if (err) {
+        return cb(err)
+      }
+      this.log('dispatching query')
+      client.query(text, values, (err, res) => {
+        this.log('query dispatched')
+        client.release(err)
+        if (err) {
+          return cb(err)
+        } else {
+          return cb(undefined, res)
+        }
+      })
+    })
+    return response.result
+  }
+
+  end (cb) {
+    this.log('ending')
+    if (this.ending) {
+      const err = new Error('Called end on pool more than once')
+      return cb ? cb(err) : this.Promise.reject(err)
+    }
+    this.ending = true
+    const promised = promisify(this.Promise, cb)
+    this._endCallback = promised.callback
+    this._pulseQueue()
+    return promised.result
+  }
+
+  get waitingCount () {
+    return this._pendingQueue.length
+  }
+
+  get idleCount () {
+    return this._idle.length
+  }
+
+  get totalCount () {
+    return this._clients.length
+  }
+}
+module.exports = Pool
diff --git a/server/node_modules/pg-pool/package.json b/server/node_modules/pg-pool/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..15f370d0c36040d4665ed4972a643ada9c5ce2ff
--- /dev/null
+++ b/server/node_modules/pg-pool/package.json
@@ -0,0 +1,70 @@
+{
+  "_from": "pg-pool@^2.0.4",
+  "_id": "pg-pool@2.0.7",
+  "_inBundle": false,
+  "_integrity": "sha512-UiJyO5B9zZpu32GSlP0tXy8J2NsJ9EFGFfz5v6PSbdz/1hBLX1rNiiy5+mAm5iJJYwfCv4A0EBcQLGWwjbpzZw==",
+  "_location": "/pg-pool",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "pg-pool@^2.0.4",
+    "name": "pg-pool",
+    "escapedName": "pg-pool",
+    "rawSpec": "^2.0.4",
+    "saveSpec": null,
+    "fetchSpec": "^2.0.4"
+  },
+  "_requiredBy": [
+    "/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.7.tgz",
+  "_shasum": "f14ecab83507941062c313df23f6adcd9fd0ce54",
+  "_spec": "pg-pool@^2.0.4",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg",
+  "author": {
+    "name": "Brian M. Carlson"
+  },
+  "bugs": {
+    "url": "https://github.com/brianc/node-pg-pool/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "Connection pool for node-postgres",
+  "devDependencies": {
+    "bluebird": "3.4.1",
+    "co": "4.6.0",
+    "expect.js": "0.3.1",
+    "lodash": "^4.17.11",
+    "mocha": "^5.2.0",
+    "pg": "*",
+    "pg-cursor": "^1.3.0",
+    "standard": "7.1.2",
+    "standard-format": "^2.2.4"
+  },
+  "directories": {
+    "test": "test"
+  },
+  "homepage": "https://github.com/brianc/node-pg-pool#readme",
+  "keywords": [
+    "pg",
+    "postgres",
+    "pool",
+    "database"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "pg-pool",
+  "peerDependencies": {
+    "pg": ">5.0"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianc/node-pg-pool.git"
+  },
+  "scripts": {
+    "test": " node_modules/.bin/mocha && node_modules/.bin/standard"
+  },
+  "version": "2.0.7"
+}
diff --git a/server/node_modules/pg-pool/test/bring-your-own-promise.js b/server/node_modules/pg-pool/test/bring-your-own-promise.js
new file mode 100644
index 0000000000000000000000000000000000000000..f7fe3bde93bc9b1a777b9951f2615308598eb9df
--- /dev/null
+++ b/server/node_modules/pg-pool/test/bring-your-own-promise.js
@@ -0,0 +1,36 @@
+'use strict'
+const co = require('co')
+const expect = require('expect.js')
+
+const describe = require('mocha').describe
+const it = require('mocha').it
+const BluebirdPromise = require('bluebird')
+
+const Pool = require('../')
+
+const checkType = promise => {
+  expect(promise).to.be.a(BluebirdPromise)
+  return promise.catch(e => undefined)
+}
+
+describe('Bring your own promise', function () {
+  it('uses supplied promise for operations', co.wrap(function * () {
+    const pool = new Pool({ Promise: BluebirdPromise })
+    const client1 = yield checkType(pool.connect())
+    client1.release()
+    yield checkType(pool.query('SELECT NOW()'))
+    const client2 = yield checkType(pool.connect())
+    // TODO - make sure pg supports BYOP as well
+    client2.release()
+    yield checkType(pool.end())
+  }))
+
+  it('uses promises in errors', co.wrap(function * () {
+    const pool = new Pool({ Promise: BluebirdPromise, port: 48484 })
+    yield checkType(pool.connect())
+    yield checkType(pool.end())
+    yield checkType(pool.connect())
+    yield checkType(pool.query())
+    yield checkType(pool.end())
+  }))
+})
diff --git a/server/node_modules/pg-pool/test/connection-strings.js b/server/node_modules/pg-pool/test/connection-strings.js
new file mode 100644
index 0000000000000000000000000000000000000000..7013f28da88294a4f735d7b8a5b9b3b7e942e788
--- /dev/null
+++ b/server/node_modules/pg-pool/test/connection-strings.js
@@ -0,0 +1,30 @@
+const expect = require('expect.js')
+const describe = require('mocha').describe
+const it = require('mocha').it
+const Pool = require('../')
+
+describe('Connection strings', function () {
+  it('pool delegates connectionString property to client', function (done) {
+    const connectionString = 'postgres://foo:bar@baz:1234/xur'
+
+    const pool = new Pool({
+      // use a fake client so we can check we're passed the connectionString
+      Client: function (args) {
+        expect(args.connectionString).to.equal(connectionString)
+        return {
+          connect: function (cb) {
+            cb(new Error('testing'))
+          },
+          on: function () { }
+        }
+      },
+      connectionString: connectionString
+    })
+
+    pool.connect(function (err, client) {
+      expect(err).to.not.be(undefined)
+      done()
+    })
+  })
+})
+
diff --git a/server/node_modules/pg-pool/test/connection-timeout.js b/server/node_modules/pg-pool/test/connection-timeout.js
new file mode 100644
index 0000000000000000000000000000000000000000..8151354cc5b964a17801d7a94c2b3521259bd56b
--- /dev/null
+++ b/server/node_modules/pg-pool/test/connection-timeout.js
@@ -0,0 +1,224 @@
+'use strict'
+const net = require('net')
+const co = require('co')
+const expect = require('expect.js')
+
+const describe = require('mocha').describe
+const it = require('mocha').it
+const before = require('mocha').before
+const after = require('mocha').after
+
+const Pool = require('../')
+
+describe('connection timeout', () => {
+  const connectionFailure = new Error('Temporary connection failure')
+
+  before((done) => {
+    this.server = net.createServer((socket) => {
+      socket.on('data', () => {
+        // discard any buffered data or the server wont terminate
+      })
+    })
+
+    this.server.listen(() => {
+      this.port = this.server.address().port
+      done()
+    })
+  })
+
+  after((done) => {
+    this.server.close(done)
+  })
+
+  it('should callback with an error if timeout is passed', (done) => {
+    const pool = new Pool({ connectionTimeoutMillis: 10, port: this.port })
+    pool.connect((err, client, release) => {
+      expect(err).to.be.an(Error)
+      expect(err.message).to.contain('timeout')
+      expect(client).to.equal(undefined)
+      expect(pool.idleCount).to.equal(0)
+      done()
+    })
+  })
+
+  it('should reject promise with an error if timeout is passed', (done) => {
+    const pool = new Pool({ connectionTimeoutMillis: 10, port: this.port })
+    pool.connect().catch(err => {
+      expect(err).to.be.an(Error)
+      expect(err.message).to.contain('timeout')
+      expect(pool.idleCount).to.equal(0)
+      done()
+    })
+  })
+
+  it('should handle multiple timeouts', co.wrap(function * () {
+    const errors = []
+    const pool = new Pool({ connectionTimeoutMillis: 1, port: this.port })
+    for (var i = 0; i < 15; i++) {
+      try {
+        yield pool.connect()
+      } catch (e) {
+        errors.push(e)
+      }
+    }
+    expect(errors).to.have.length(15)
+  }.bind(this)))
+
+  it('should timeout on checkout of used connection', (done) => {
+    const pool = new Pool({ connectionTimeoutMillis: 100, max: 1 })
+    pool.connect((err, client, release) => {
+      expect(err).to.be(undefined)
+      expect(client).to.not.be(undefined)
+      pool.connect((err, client) => {
+        expect(err).to.be.an(Error)
+        expect(client).to.be(undefined)
+        release()
+        pool.end(done)
+      })
+    })
+  })
+
+  it('should not break further pending checkouts on a timeout', (done) => {
+    const pool = new Pool({ connectionTimeoutMillis: 200, max: 1 })
+    pool.connect((err, client, releaseOuter) => {
+      expect(err).to.be(undefined)
+
+      pool.connect((err, client) => {
+        expect(err).to.be.an(Error)
+        expect(client).to.be(undefined)
+        releaseOuter()
+      })
+
+      setTimeout(() => {
+        pool.connect((err, client, releaseInner) => {
+          expect(err).to.be(undefined)
+          expect(client).to.not.be(undefined)
+          releaseInner()
+          pool.end(done)
+        })
+      }, 100)
+    })
+  })
+
+  it('should timeout on query if all clients are busy', (done) => {
+    const pool = new Pool({ connectionTimeoutMillis: 100, max: 1 })
+    pool.connect((err, client, release) => {
+      expect(err).to.be(undefined)
+      expect(client).to.not.be(undefined)
+      pool.query('select now()', (err, result) => {
+        expect(err).to.be.an(Error)
+        expect(result).to.be(undefined)
+        release()
+        pool.end(done)
+      })
+    })
+  })
+
+  it('should recover from timeout errors', (done) => {
+    const pool = new Pool({ connectionTimeoutMillis: 100, max: 1 })
+    pool.connect((err, client, release) => {
+      expect(err).to.be(undefined)
+      expect(client).to.not.be(undefined)
+      pool.query('select now()', (err, result) => {
+        expect(err).to.be.an(Error)
+        expect(result).to.be(undefined)
+        release()
+        pool.query('select $1::text as name', ['brianc'], (err, res) => {
+          expect(err).to.be(undefined)
+          expect(res.rows).to.have.length(1)
+          pool.end(done)
+        })
+      })
+    })
+  })
+
+  it('continues processing after a connection failure', (done) => {
+    const Client = require('pg').Client
+    const orgConnect = Client.prototype.connect
+    let called = false
+
+    Client.prototype.connect = function (cb) {
+      // Simulate a failure on first call
+      if (!called) {
+        called = true
+
+        return setTimeout(() => {
+          cb(connectionFailure)
+        }, 100)
+      }
+      // And pass-through the second call
+      orgConnect.call(this, cb)
+    }
+
+    const pool = new Pool({
+      Client: Client,
+      connectionTimeoutMillis: 1000,
+      max: 1
+    })
+
+    pool.connect((err, client, release) => {
+      expect(err).to.be(connectionFailure)
+
+      pool.query('select $1::text as name', ['brianc'], (err, res) => {
+        expect(err).to.be(undefined)
+        expect(res.rows).to.have.length(1)
+        pool.end(done)
+      })
+    })
+  })
+
+  it('releases newly connected clients if the queued already timed out', (done) => {
+    const Client = require('pg').Client
+
+    const orgConnect = Client.prototype.connect
+
+    let connection = 0
+
+    Client.prototype.connect = function (cb) {
+      // Simulate a failure on first call
+      if (connection === 0) {
+        connection++
+
+        return setTimeout(() => {
+          cb(connectionFailure)
+        }, 300)
+      }
+
+      // And second connect taking > connection timeout
+      if (connection === 1) {
+        connection++
+
+        return setTimeout(() => {
+          orgConnect.call(this, cb)
+        }, 1000)
+      }
+
+      orgConnect.call(this, cb)
+    }
+
+    const pool = new Pool({
+      Client: Client,
+      connectionTimeoutMillis: 1000,
+      max: 1
+    })
+
+    // Direct connect
+    pool.connect((err, client, release) => {
+      expect(err).to.be(connectionFailure)
+    })
+
+    // Queued
+    let called = 0
+    pool.connect((err, client, release) => {
+      // Verify the callback is only called once
+      expect(called++).to.be(0)
+      expect(err).to.be.an(Error)
+
+      pool.query('select $1::text as name', ['brianc'], (err, res) => {
+        expect(err).to.be(undefined)
+        expect(res.rows).to.have.length(1)
+        pool.end(done)
+      })
+    })
+  })
+})
diff --git a/server/node_modules/pg-pool/test/ending.js b/server/node_modules/pg-pool/test/ending.js
new file mode 100644
index 0000000000000000000000000000000000000000..1956b13f6117f22d155418f0f66c72a6c7b030c6
--- /dev/null
+++ b/server/node_modules/pg-pool/test/ending.js
@@ -0,0 +1,34 @@
+'use strict'
+const co = require('co')
+const expect = require('expect.js')
+
+const describe = require('mocha').describe
+const it = require('mocha').it
+
+const Pool = require('../')
+
+describe('pool ending', () => {
+  it('ends without being used', (done) => {
+    const pool = new Pool()
+    pool.end(done)
+  })
+
+  it('ends with a promise', () => {
+    return new Pool().end()
+  })
+
+  it('ends with clients', co.wrap(function * () {
+    const pool = new Pool()
+    const res = yield pool.query('SELECT $1::text as name', ['brianc'])
+    expect(res.rows[0].name).to.equal('brianc')
+    return pool.end()
+  }))
+
+  it('allows client to finish', co.wrap(function * () {
+    const pool = new Pool()
+    const query = pool.query('SELECT $1::text as name', ['brianc'])
+    yield pool.end()
+    const res = yield query
+    expect(res.rows[0].name).to.equal('brianc')
+  }))
+})
diff --git a/server/node_modules/pg-pool/test/error-handling.js b/server/node_modules/pg-pool/test/error-handling.js
new file mode 100644
index 0000000000000000000000000000000000000000..1e416683826f4c84f08259fe75e05146afae96c2
--- /dev/null
+++ b/server/node_modules/pg-pool/test/error-handling.js
@@ -0,0 +1,229 @@
+'use strict'
+const net = require('net')
+const co = require('co')
+const expect = require('expect.js')
+
+const describe = require('mocha').describe
+const it = require('mocha').it
+
+const Pool = require('../')
+
+describe('pool error handling', function () {
+  it('Should complete these queries without dying', function (done) {
+    const pool = new Pool()
+    let errors = 0
+    let shouldGet = 0
+    function runErrorQuery () {
+      shouldGet++
+      return new Promise(function (resolve, reject) {
+        pool.query("SELECT 'asd'+1 ").then(function (res) {
+          reject(res) // this should always error
+        }).catch(function (err) {
+          errors++
+          resolve(err)
+        })
+      })
+    }
+    const ps = []
+    for (let i = 0; i < 5; i++) {
+      ps.push(runErrorQuery())
+    }
+    Promise.all(ps).then(function () {
+      expect(shouldGet).to.eql(errors)
+      pool.end(done)
+    })
+  })
+
+  describe('calling release more than once', () => {
+    it('should throw each time', co.wrap(function * () {
+      const pool = new Pool()
+      const client = yield pool.connect()
+      client.release()
+      expect(() => client.release()).to.throwError()
+      expect(() => client.release()).to.throwError()
+      return yield pool.end()
+    }))
+
+    it('should throw each time with callbacks', function (done) {
+      const pool = new Pool()
+
+      pool.connect(function (err, client, clientDone) {
+        expect(err).not.to.be.an(Error)
+        clientDone()
+
+        expect(() => clientDone()).to.throwError()
+        expect(() => clientDone()).to.throwError()
+
+        pool.end(done)
+      })
+    })
+  })
+
+  describe('calling connect after end', () => {
+    it('should return an error', function * () {
+      const pool = new Pool()
+      const res = yield pool.query('SELECT $1::text as name', ['hi'])
+      expect(res.rows[0].name).to.equal('hi')
+      const wait = pool.end()
+      pool.query('select now()')
+      yield wait
+      expect(() => pool.query('select now()')).to.reject()
+    })
+  })
+
+  describe('using an ended pool', () => {
+    it('rejects all additional promises', (done) => {
+      const pool = new Pool()
+      const promises = []
+      pool.end()
+        .then(() => {
+          const squash = promise => promise.catch(e => 'okay!')
+          promises.push(squash(pool.connect()))
+          promises.push(squash(pool.query('SELECT NOW()')))
+          promises.push(squash(pool.end()))
+          Promise.all(promises).then(res => {
+            expect(res).to.eql(['okay!', 'okay!', 'okay!'])
+            done()
+          })
+        })
+    })
+
+    it('returns an error on all additional callbacks', (done) => {
+      const pool = new Pool()
+      pool.end(() => {
+        pool.query('SELECT *', (err) => {
+          expect(err).to.be.an(Error)
+          pool.connect((err) => {
+            expect(err).to.be.an(Error)
+            pool.end((err) => {
+              expect(err).to.be.an(Error)
+              done()
+            })
+          })
+        })
+      })
+    })
+  })
+
+  describe('error from idle client', () => {
+    it('removes client from pool', co.wrap(function * () {
+      const pool = new Pool()
+      const client = yield pool.connect()
+      expect(pool.totalCount).to.equal(1)
+      expect(pool.waitingCount).to.equal(0)
+      expect(pool.idleCount).to.equal(0)
+      client.release()
+      yield new Promise((resolve, reject) => {
+        process.nextTick(() => {
+          let poolError
+          pool.once('error', (err) => {
+            poolError = err
+          })
+
+          let clientError
+          client.once('error', (err) => {
+            clientError = err
+          })
+
+          client.emit('error', new Error('expected'))
+
+          expect(clientError.message).to.equal('expected')
+          expect(poolError.message).to.equal('expected')
+          expect(pool.idleCount).to.equal(0)
+          expect(pool.totalCount).to.equal(0)
+          pool.end().then(resolve, reject)
+        })
+      })
+    }))
+  })
+
+  describe('error from in-use client', () => {
+    it('keeps the client in the pool', co.wrap(function * () {
+      const pool = new Pool()
+      const client = yield pool.connect()
+      expect(pool.totalCount).to.equal(1)
+      expect(pool.waitingCount).to.equal(0)
+      expect(pool.idleCount).to.equal(0)
+
+      yield new Promise((resolve, reject) => {
+        process.nextTick(() => {
+          let poolError
+          pool.once('error', (err) => {
+            poolError = err
+          })
+
+          let clientError
+          client.once('error', (err) => {
+            clientError = err
+          })
+
+          client.emit('error', new Error('expected'))
+
+          expect(clientError.message).to.equal('expected')
+          expect(poolError).not.to.be.ok()
+          expect(pool.idleCount).to.equal(0)
+          expect(pool.totalCount).to.equal(1)
+          client.release()
+          pool.end().then(resolve, reject)
+        })
+      })
+    }))
+  })
+
+  describe('passing a function to pool.query', () => {
+    it('calls back with error', (done) => {
+      const pool = new Pool()
+      console.log('passing fn to query')
+      pool.query((err) => {
+        expect(err).to.be.an(Error)
+        pool.end(done)
+      })
+    })
+  })
+
+  describe('pool with lots of errors', () => {
+    it('continues to work and provide new clients', co.wrap(function * () {
+      const pool = new Pool({ max: 1 })
+      const errors = []
+      for (var i = 0; i < 20; i++) {
+        try {
+          yield pool.query('invalid sql')
+        } catch (err) {
+          errors.push(err)
+        }
+      }
+      expect(errors).to.have.length(20)
+      expect(pool.idleCount).to.equal(0)
+      expect(pool.query).to.be.a(Function)
+      const res = yield pool.query('SELECT $1::text as name', ['brianc'])
+      expect(res.rows).to.have.length(1)
+      expect(res.rows[0].name).to.equal('brianc')
+      return pool.end()
+    }))
+  })
+
+  it('should continue with queued items after a connection failure', (done) => {
+    const closeServer = net.createServer((socket) => {
+      socket.destroy()
+    }).unref()
+
+    closeServer.listen(() => {
+      const pool = new Pool({ max: 1, port: closeServer.address().port })
+      pool.connect((err) => {
+        expect(err).to.be.an(Error)
+        if (err.errno) {
+          expect(err.errno).to.be('ECONNRESET')
+        }
+      })
+      pool.connect((err) => {
+        expect(err).to.be.an(Error)
+        if (err.errno) {
+          expect(err.errno).to.be('ECONNRESET')
+        }
+        closeServer.close(() => {
+          pool.end(done)
+        })
+      })
+    })
+  })
+})
diff --git a/server/node_modules/pg-pool/test/events.js b/server/node_modules/pg-pool/test/events.js
new file mode 100644
index 0000000000000000000000000000000000000000..a2da48100b389a5e26c6f94852deed2f7cbc2114
--- /dev/null
+++ b/server/node_modules/pg-pool/test/events.js
@@ -0,0 +1,86 @@
+'use strict'
+
+const expect = require('expect.js')
+const EventEmitter = require('events').EventEmitter
+const describe = require('mocha').describe
+const it = require('mocha').it
+const Pool = require('../')
+
+describe('events', function () {
+  it('emits connect before callback', function (done) {
+    const pool = new Pool()
+    let emittedClient = false
+    pool.on('connect', function (client) {
+      emittedClient = client
+    })
+
+    pool.connect(function (err, client, release) {
+      if (err) return done(err)
+      release()
+      pool.end()
+      expect(client).to.be(emittedClient)
+      done()
+    })
+  })
+
+  it('emits "connect" only with a successful connection', function () {
+    const pool = new Pool({
+      // This client will always fail to connect
+      Client: mockClient({
+        connect: function (cb) {
+          process.nextTick(() => {
+            cb(new Error('bad news'))
+          })
+        }
+      })
+    })
+    pool.on('connect', function () {
+      throw new Error('should never get here')
+    })
+    return pool.connect().catch(e => expect(e.message).to.equal('bad news'))
+  })
+
+  it('emits acquire every time a client is acquired', function (done) {
+    const pool = new Pool()
+    let acquireCount = 0
+    pool.on('acquire', function (client) {
+      expect(client).to.be.ok()
+      acquireCount++
+    })
+    for (let i = 0; i < 10; i++) {
+      pool.connect(function (err, client, release) {
+        if (err) return done(err)
+        release()
+      })
+      pool.query('SELECT now()')
+    }
+    setTimeout(function () {
+      expect(acquireCount).to.be(20)
+      pool.end(done)
+    }, 100)
+  })
+
+  it('emits error and client if an idle client in the pool hits an error', function (done) {
+    const pool = new Pool()
+    pool.connect(function (err, client) {
+      expect(err).to.equal(undefined)
+      client.release()
+      setImmediate(function () {
+        client.emit('error', new Error('problem'))
+      })
+      pool.once('error', function (err, errClient) {
+        expect(err.message).to.equal('problem')
+        expect(errClient).to.equal(client)
+        done()
+      })
+    })
+  })
+})
+
+function mockClient (methods) {
+  return function () {
+    const client = new EventEmitter()
+    Object.assign(client, methods)
+    return client
+  }
+}
diff --git a/server/node_modules/pg-pool/test/idle-timeout.js b/server/node_modules/pg-pool/test/idle-timeout.js
new file mode 100644
index 0000000000000000000000000000000000000000..a24ab7b06e1bb75785af2912df9a8e2bdcbdc30b
--- /dev/null
+++ b/server/node_modules/pg-pool/test/idle-timeout.js
@@ -0,0 +1,79 @@
+'use strict'
+const co = require('co')
+const expect = require('expect.js')
+
+const describe = require('mocha').describe
+const it = require('mocha').it
+
+const Pool = require('../')
+
+const wait = time => new Promise((resolve) => setTimeout(resolve, time))
+
+describe('idle timeout', () => {
+  it('should timeout and remove the client', (done) => {
+    const pool = new Pool({ idleTimeoutMillis: 10 })
+    pool.query('SELECT NOW()')
+    pool.on('remove', () => {
+      expect(pool.idleCount).to.equal(0)
+      expect(pool.totalCount).to.equal(0)
+      done()
+    })
+  })
+
+  it('times out and removes clients when others are also removed', co.wrap(function * () {
+    const pool = new Pool({ idleTimeoutMillis: 10 })
+    const clientA = yield pool.connect()
+    const clientB = yield pool.connect()
+    clientA.release()
+    clientB.release(new Error())
+
+    const removal = new Promise((resolve) => {
+      pool.on('remove', () => {
+        expect(pool.idleCount).to.equal(0)
+        expect(pool.totalCount).to.equal(0)
+        resolve()
+      })
+    })
+
+    const timeout = wait(100).then(() =>
+      Promise.reject(new Error('Idle timeout failed to occur')))
+
+    try {
+      yield Promise.race([removal, timeout])
+    } finally {
+      pool.end()
+    }
+  }))
+
+  it('can remove idle clients and recreate them', co.wrap(function * () {
+    const pool = new Pool({ idleTimeoutMillis: 1 })
+    const results = []
+    for (var i = 0; i < 20; i++) {
+      let query = pool.query('SELECT NOW()')
+      expect(pool.idleCount).to.equal(0)
+      expect(pool.totalCount).to.equal(1)
+      results.push(yield query)
+      yield wait(2)
+      expect(pool.idleCount).to.equal(0)
+      expect(pool.totalCount).to.equal(0)
+    }
+    expect(results).to.have.length(20)
+  }))
+
+  it('does not time out clients which are used', co.wrap(function * () {
+    const pool = new Pool({ idleTimeoutMillis: 1 })
+    const results = []
+    for (var i = 0; i < 20; i++) {
+      let client = yield pool.connect()
+      expect(pool.totalCount).to.equal(1)
+      expect(pool.idleCount).to.equal(0)
+      yield wait(10)
+      results.push(yield client.query('SELECT NOW()'))
+      client.release()
+      expect(pool.idleCount).to.equal(1)
+      expect(pool.totalCount).to.equal(1)
+    }
+    expect(results).to.have.length(20)
+    return pool.end()
+  }))
+})
diff --git a/server/node_modules/pg-pool/test/index.js b/server/node_modules/pg-pool/test/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..010d99c564f092ea4124b812c4bbbd92e7c9d93a
--- /dev/null
+++ b/server/node_modules/pg-pool/test/index.js
@@ -0,0 +1,229 @@
+'use strict'
+const expect = require('expect.js')
+const _ = require('lodash')
+
+const describe = require('mocha').describe
+const it = require('mocha').it
+
+const Pool = require('../')
+
+describe('pool', function () {
+  describe('with callbacks', function () {
+    it('works totally unconfigured', function (done) {
+      const pool = new Pool()
+      pool.connect(function (err, client, release) {
+        if (err) return done(err)
+        client.query('SELECT NOW()', function (err, res) {
+          release()
+          if (err) return done(err)
+          expect(res.rows).to.have.length(1)
+          pool.end(done)
+        })
+      })
+    })
+
+    it('passes props to clients', function (done) {
+      const pool = new Pool({ binary: true })
+      pool.connect(function (err, client, release) {
+        release()
+        if (err) return done(err)
+        expect(client.binary).to.eql(true)
+        pool.end(done)
+      })
+    })
+
+    it('can run a query with a callback without parameters', function (done) {
+      const pool = new Pool()
+      pool.query('SELECT 1 as num', function (err, res) {
+        expect(res.rows[0]).to.eql({ num: 1 })
+        pool.end(function () {
+          done(err)
+        })
+      })
+    })
+
+    it('can run a query with a callback', function (done) {
+      const pool = new Pool()
+      pool.query('SELECT $1::text as name', ['brianc'], function (err, res) {
+        expect(res.rows[0]).to.eql({ name: 'brianc' })
+        pool.end(function () {
+          done(err)
+        })
+      })
+    })
+
+    it('passes connection errors to callback', function (done) {
+      const pool = new Pool({ port: 53922 })
+      pool.query('SELECT $1::text as name', ['brianc'], function (err, res) {
+        expect(res).to.be(undefined)
+        expect(err).to.be.an(Error)
+        // a connection error should not polute the pool with a dead client
+        expect(pool.totalCount).to.equal(0)
+        pool.end(function (err) {
+          done(err)
+        })
+      })
+    })
+
+    it('does not pass client to error callback', function (done) {
+      const pool = new Pool({ port: 58242 })
+      pool.connect(function (err, client, release) {
+        expect(err).to.be.an(Error)
+        expect(client).to.be(undefined)
+        expect(release).to.be.a(Function)
+        pool.end(done)
+      })
+    })
+
+    it('removes client if it errors in background', function (done) {
+      const pool = new Pool()
+      pool.connect(function (err, client, release) {
+        release()
+        if (err) return done(err)
+        client.testString = 'foo'
+        setTimeout(function () {
+          client.emit('error', new Error('on purpose'))
+        }, 10)
+      })
+      pool.on('error', function (err) {
+        expect(err.message).to.be('on purpose')
+        expect(err.client).to.not.be(undefined)
+        expect(err.client.testString).to.be('foo')
+        err.client.connection.stream.on('end', function () {
+          pool.end(done)
+        })
+      })
+    })
+
+    it('should not change given options', function (done) {
+      const options = { max: 10 }
+      const pool = new Pool(options)
+      pool.connect(function (err, client, release) {
+        release()
+        if (err) return done(err)
+        expect(options).to.eql({ max: 10 })
+        pool.end(done)
+      })
+    })
+
+    it('does not create promises when connecting', function (done) {
+      const pool = new Pool()
+      const returnValue = pool.connect(function (err, client, release) {
+        release()
+        if (err) return done(err)
+        pool.end(done)
+      })
+      expect(returnValue).to.be(undefined)
+    })
+
+    it('does not create promises when querying', function (done) {
+      const pool = new Pool()
+      const returnValue = pool.query('SELECT 1 as num', function (err) {
+        pool.end(function () {
+          done(err)
+        })
+      })
+      expect(returnValue).to.be(undefined)
+    })
+
+    it('does not create promises when ending', function (done) {
+      const pool = new Pool()
+      const returnValue = pool.end(done)
+      expect(returnValue).to.be(undefined)
+    })
+
+    it('never calls callback syncronously', function (done) {
+      const pool = new Pool()
+      pool.connect((err, client) => {
+        if (err) throw err
+        client.release()
+        setImmediate(() => {
+          let called = false
+          pool.connect((err, client) => {
+            if (err) throw err
+            called = true
+            client.release()
+            setImmediate(() => {
+              pool.end(done)
+            })
+          })
+          expect(called).to.equal(false)
+        })
+      })
+    })
+  })
+
+  describe('with promises', function () {
+    it('connects, queries, and disconnects', function () {
+      const pool = new Pool()
+      return pool.connect().then(function (client) {
+        return client.query('select $1::text as name', ['hi']).then(function (res) {
+          expect(res.rows).to.eql([{ name: 'hi' }])
+          client.release()
+          return pool.end()
+        })
+      })
+    })
+
+    it('executes a query directly', () => {
+      const pool = new Pool()
+      return pool
+        .query('SELECT $1::text as name', ['hi'])
+        .then(res => {
+          expect(res.rows).to.have.length(1)
+          expect(res.rows[0].name).to.equal('hi')
+          return pool.end()
+        })
+    })
+
+    it('properly pools clients', function () {
+      const pool = new Pool({ poolSize: 9 })
+      const promises = _.times(30, function () {
+        return pool.connect().then(function (client) {
+          return client.query('select $1::text as name', ['hi']).then(function (res) {
+            client.release()
+            return res
+          })
+        })
+      })
+      return Promise.all(promises).then(function (res) {
+        expect(res).to.have.length(30)
+        expect(pool.totalCount).to.be(9)
+        return pool.end()
+      })
+    })
+
+    it('supports just running queries', function () {
+      const pool = new Pool({ poolSize: 9 })
+      const text = 'select $1::text as name'
+      const values = ['hi']
+      const query = { text: text, values: values }
+      const promises = _.times(30, () => pool.query(query))
+      return Promise.all(promises).then(function (queries) {
+        expect(queries).to.have.length(30)
+        return pool.end()
+      })
+    })
+
+    it('recovers from query errors', function () {
+      const pool = new Pool()
+
+      const errors = []
+      const promises = _.times(30, () => {
+        return pool.query('SELECT asldkfjasldkf')
+          .catch(function (e) {
+            errors.push(e)
+          })
+      })
+      return Promise.all(promises).then(() => {
+        expect(errors).to.have.length(30)
+        expect(pool.totalCount).to.equal(0)
+        expect(pool.idleCount).to.equal(0)
+        return pool.query('SELECT $1::text as name', ['hi']).then(function (res) {
+          expect(res.rows).to.eql([{ name: 'hi' }])
+          return pool.end()
+        })
+      })
+    })
+  })
+})
diff --git a/server/node_modules/pg-pool/test/logging.js b/server/node_modules/pg-pool/test/logging.js
new file mode 100644
index 0000000000000000000000000000000000000000..839603b7859f431876536ac272f13ce361a9d709
--- /dev/null
+++ b/server/node_modules/pg-pool/test/logging.js
@@ -0,0 +1,20 @@
+const expect = require('expect.js')
+
+const describe = require('mocha').describe
+const it = require('mocha').it
+
+const Pool = require('../')
+
+describe('logging', function () {
+  it('logs to supplied log function if given', function () {
+    const messages = []
+    const log = function (msg) {
+      messages.push(msg)
+    }
+    const pool = new Pool({ log: log })
+    return pool.query('SELECT NOW()').then(function () {
+      expect(messages.length).to.be.greaterThan(0)
+      return pool.end()
+    })
+  })
+})
diff --git a/server/node_modules/pg-pool/test/mocha.opts b/server/node_modules/pg-pool/test/mocha.opts
new file mode 100644
index 0000000000000000000000000000000000000000..eb0ba600d2a1784554a957299eea569ef4c7b727
--- /dev/null
+++ b/server/node_modules/pg-pool/test/mocha.opts
@@ -0,0 +1,3 @@
+--require test/setup.js
+--bail
+--timeout 10000
diff --git a/server/node_modules/pg-pool/test/setup.js b/server/node_modules/pg-pool/test/setup.js
new file mode 100644
index 0000000000000000000000000000000000000000..cf75b7a67e5f11e0370abd731adcd23b35ad3eb9
--- /dev/null
+++ b/server/node_modules/pg-pool/test/setup.js
@@ -0,0 +1,10 @@
+const crash = reason => {
+  process.on(reason, err => {
+    console.error(reason, err.stack)
+    process.exit(-1)
+  })
+}
+
+crash('unhandledRejection')
+crash('uncaughtError')
+crash('warning')
diff --git a/server/node_modules/pg-pool/test/sizing.js b/server/node_modules/pg-pool/test/sizing.js
new file mode 100644
index 0000000000000000000000000000000000000000..b310b3d356e68c0527d3d7485ad14f52a81b93a3
--- /dev/null
+++ b/server/node_modules/pg-pool/test/sizing.js
@@ -0,0 +1,50 @@
+const expect = require('expect.js')
+const co = require('co')
+const _ = require('lodash')
+
+const describe = require('mocha').describe
+const it = require('mocha').it
+
+const Pool = require('../')
+
+describe('pool size of 1', () => {
+  it('can create a single client and use it once', co.wrap(function * () {
+    const pool = new Pool({ max: 1 })
+    expect(pool.waitingCount).to.equal(0)
+    const client = yield pool.connect()
+    const res = yield client.query('SELECT $1::text as name', ['hi'])
+    expect(res.rows[0].name).to.equal('hi')
+    client.release()
+    pool.end()
+  }))
+
+  it('can create a single client and use it multiple times', co.wrap(function * () {
+    const pool = new Pool({ max: 1 })
+    expect(pool.waitingCount).to.equal(0)
+    const client = yield pool.connect()
+    const wait = pool.connect()
+    expect(pool.waitingCount).to.equal(1)
+    client.release()
+    const client2 = yield wait
+    expect(client).to.equal(client2)
+    client2.release()
+    return yield pool.end()
+  }))
+
+  it('can only send 1 query at a time', co.wrap(function * () {
+    const pool = new Pool({ max: 1 })
+
+    // the query text column name changed in PostgreSQL 9.2
+    const versionResult = yield pool.query('SHOW server_version_num')
+    const version = parseInt(versionResult.rows[0].server_version_num, 10)
+    const queryColumn = version < 90200 ? 'current_query' : 'query'
+
+    const queryText = 'SELECT COUNT(*) as counts FROM pg_stat_activity WHERE ' + queryColumn + ' = $1'
+    const queries = _.times(20, () =>
+      pool.query(queryText, [queryText]))
+    const results = yield Promise.all(queries)
+    const counts = results.map(res => parseInt(res.rows[0].counts, 10))
+    expect(counts).to.eql(_.times(20, i => 1))
+    return yield pool.end()
+  }))
+})
diff --git a/server/node_modules/pg-pool/test/submittable.js b/server/node_modules/pg-pool/test/submittable.js
new file mode 100644
index 0000000000000000000000000000000000000000..7a1574d46243d5047fe952840644005f59b878af
--- /dev/null
+++ b/server/node_modules/pg-pool/test/submittable.js
@@ -0,0 +1,19 @@
+'use strict'
+const Cursor = require('pg-cursor')
+const expect = require('expect.js')
+const describe = require('mocha').describe
+const it = require('mocha').it
+
+const Pool = require('../')
+
+describe('submittle', () => {
+  it('is returned from the query method', false, (done) => {
+    const pool = new Pool()
+    const cursor = pool.query(new Cursor('SELECT * from generate_series(0, 1000)'))
+    cursor.read((err, rows) => {
+      expect(err).to.be(undefined)
+      expect(!!rows).to.be.ok()
+      cursor.close(done)
+    })
+  })
+})
diff --git a/server/node_modules/pg-pool/test/timeout.js b/server/node_modules/pg-pool/test/timeout.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/pg-pool/test/verify.js b/server/node_modules/pg-pool/test/verify.js
new file mode 100644
index 0000000000000000000000000000000000000000..667dea9ff6142bf8f88ad75babe916eaa6bcc4f5
--- /dev/null
+++ b/server/node_modules/pg-pool/test/verify.js
@@ -0,0 +1,25 @@
+'use strict'
+const expect = require('expect.js')
+
+const describe = require('mocha').describe
+const it = require('mocha').it
+
+const Pool = require('../')
+
+describe('verify', () => {
+  it('verifies a client with a callback', false, (done) => {
+    const pool = new Pool({
+      verify: (client, cb) => {
+        client.release()
+        cb(new Error('nope'))
+      }
+    })
+
+    pool.connect((err, client) => {
+      expect(err).to.be.an(Error)
+      expect(err.message).to.be('nope')
+      pool.end()
+      done()
+    })
+  })
+})
diff --git a/server/node_modules/pg-types/.travis.yml b/server/node_modules/pg-types/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..dd6b03329631e37cfdd94f331dd9ce449c9e162b
--- /dev/null
+++ b/server/node_modules/pg-types/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+  - '4'
+  - 'lts/*'
+  - 'node'
+env:
+  - PGUSER=postgres
diff --git a/server/node_modules/pg-types/Makefile b/server/node_modules/pg-types/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d7ec83d549a9b4dc8c4815471b3323c4995eaaa2
--- /dev/null
+++ b/server/node_modules/pg-types/Makefile
@@ -0,0 +1,14 @@
+.PHONY: publish-patch test
+
+test:
+	npm test
+
+patch: test
+	npm version patch -m "Bump version"
+	git push origin master --tags
+	npm publish
+
+minor: test
+	npm version minor -m "Bump version"
+	git push origin master --tags
+	npm publish
diff --git a/server/node_modules/pg-types/README.md b/server/node_modules/pg-types/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..54a3f2c6b9335154c5c64520f46b7a88dc4675dc
--- /dev/null
+++ b/server/node_modules/pg-types/README.md
@@ -0,0 +1,75 @@
+# pg-types
+
+This is the code that turns all the raw text from postgres into JavaScript types for [node-postgres](https://github.com/brianc/node-postgres.git)
+
+## use
+
+This module is consumed and exported from the root `pg` object of node-postgres.  To access it, do the following:
+
+```js
+var types = require('pg').types
+```
+
+Generally what you'll want to do is override how a specific data-type is parsed and turned into a JavaScript type.  By default the PostgreSQL backend server returns everything as strings.  Every data type corresponds to a unique `OID` within the server, and these `OIDs` are sent back with the query response.  So, you need to match a particluar `OID` to a function you'd like to use to take the raw text input and produce a valid JavaScript object as a result. `null` values are never parsed.
+
+Let's do something I commonly like to do on projects: return 64-bit integers `(int8)` as JavaScript integers.  Because JavaScript doesn't have support for 64-bit integers node-postgres cannot confidently parse `int8` data type results as numbers because if you have a _huge_ number it will overflow and the result you'd get back from node-postgres would not be the result in the datbase.  That would be a __very bad thing__ so node-postgres just returns `int8` results as strings and leaves the parsing up to you.  Let's say that you know you don't and wont ever have numbers greater than `int4` in your database, but you're tired of recieving results from the `COUNT(*)` function as strings (because that function returns `int8`).  You would do this:
+
+```js
+var types = require('pg').types
+types.setTypeParser(20, function(val) {
+  return parseInt(val)
+})
+```
+
+__boom__: now you get numbers instead of strings.
+
+Just as another example -- not saying this is a good idea -- let's say you want to return all dates from your database as [moment](http://momentjs.com/docs/) objects.  Okay, do this:
+
+```js
+var types = require('pg').types
+var moment = require('moment')
+var parseFn = function(val) {
+   return val === null ? null : moment(val)
+}
+types.setTypeParser(types.builtins.TIMESTAMPTZ, parseFn)
+types.setTypeParser(types.builtins.TIMESTAMP, parseFn)
+```
+_note: I've never done that with my dates, and I'm not 100% sure moment can parse all the date strings returned from postgres.  It's just an example!_
+
+If you're thinking "gee, this seems pretty handy, but how can I get a list of all the OIDs in the database and what they correspond to?!?!?!" worry not:
+
+```bash
+$ psql -c "select typname, oid, typarray from pg_type order by oid"
+```
+
+If you want to find out the OID of a specific type:
+
+```bash
+$ psql -c "select typname, oid, typarray from pg_type where typname = 'daterange' order by oid"
+```
+
+:smile:
+
+## license
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Brian M. Carlson
+
+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.
diff --git a/server/node_modules/pg-types/index.d.ts b/server/node_modules/pg-types/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4bebcbe686d7768fb55353700aaf68341da0270a
--- /dev/null
+++ b/server/node_modules/pg-types/index.d.ts
@@ -0,0 +1,137 @@
+export enum TypeId {
+    BOOL = 16,
+    BYTEA = 17,
+    CHAR = 18,
+    INT8 = 20,
+    INT2 = 21,
+    INT4 = 23,
+    REGPROC = 24,
+    TEXT = 25,
+    OID = 26,
+    TID = 27,
+    XID = 28,
+    CID = 29,
+    JSON = 114,
+    XML = 142,
+    PG_NODE_TREE = 194,
+    SMGR = 210,
+    PATH = 602,
+    POLYGON = 604,
+    CIDR = 650,
+    FLOAT4 = 700,
+    FLOAT8 = 701,
+    ABSTIME = 702,
+    RELTIME = 703,
+    TINTERVAL = 704,
+    CIRCLE = 718,
+    MACADDR8 = 774,
+    MONEY = 790,
+    MACADDR = 829,
+    INET = 869,
+    ACLITEM = 1033,
+    BPCHAR = 1042,
+    VARCHAR = 1043,
+    DATE = 1082,
+    TIME = 1083,
+    TIMESTAMP = 1114,
+    TIMESTAMPTZ = 1184,
+    INTERVAL = 1186,
+    TIMETZ = 1266,
+    BIT = 1560,
+    VARBIT = 1562,
+    NUMERIC = 1700,
+    REFCURSOR = 1790,
+    REGPROCEDURE = 2202,
+    REGOPER = 2203,
+    REGOPERATOR = 2204,
+    REGCLASS = 2205,
+    REGTYPE = 2206,
+    UUID = 2950,
+    TXID_SNAPSHOT = 2970,
+    PG_LSN = 3220,
+    PG_NDISTINCT = 3361,
+    PG_DEPENDENCIES = 3402,
+    TSVECTOR = 3614,
+    TSQUERY = 3615,
+    GTSVECTOR = 3642,
+    REGCONFIG = 3734,
+    REGDICTIONARY = 3769,
+    JSONB = 3802,
+    REGNAMESPACE = 4089,
+    REGROLE = 4096
+}
+
+export type builtinsTypes =
+    'BOOL' |
+    'BYTEA' |
+    'CHAR' |
+    'INT8' |
+    'INT2' |
+    'INT4' |
+    'REGPROC' |
+    'TEXT' |
+    'OID' |
+    'TID' |
+    'XID' |
+    'CID' |
+    'JSON' |
+    'XML' |
+    'PG_NODE_TREE' |
+    'SMGR' |
+    'PATH' |
+    'POLYGON' |
+    'CIDR' |
+    'FLOAT4' |
+    'FLOAT8' |
+    'ABSTIME' |
+    'RELTIME' |
+    'TINTERVAL' |
+    'CIRCLE' |
+    'MACADDR8' |
+    'MONEY' |
+    'MACADDR' |
+    'INET' |
+    'ACLITEM' |
+    'BPCHAR' |
+    'VARCHAR' |
+    'DATE' |
+    'TIME' |
+    'TIMESTAMP' |
+    'TIMESTAMPTZ' |
+    'INTERVAL' |
+    'TIMETZ' |
+    'BIT' |
+    'VARBIT' |
+    'NUMERIC' |
+    'REFCURSOR' |
+    'REGPROCEDURE' |
+    'REGOPER' |
+    'REGOPERATOR' |
+    'REGCLASS' |
+    'REGTYPE' |
+    'UUID' |
+    'TXID_SNAPSHOT' |
+    'PG_LSN' |
+    'PG_NDISTINCT' |
+    'PG_DEPENDENCIES' |
+    'TSVECTOR' |
+    'TSQUERY' |
+    'GTSVECTOR' |
+    'REGCONFIG' |
+    'REGDICTIONARY' |
+    'JSONB' |
+    'REGNAMESPACE' |
+    'REGROLE';
+
+export type TypesBuiltins = {[key in builtinsTypes]: TypeId};
+
+export type TypeFormat = 'text' | 'binary';
+
+export const builtins: TypesBuiltins;
+
+export function setTypeParser (id: TypeId, parseFn: ((value: string) => any)): void;
+export function setTypeParser (id: TypeId, format: TypeFormat, parseFn: (value: string) => any): void;
+
+export const getTypeParser: (id: TypeId, format?: TypeFormat) => any
+
+export const arrayParser: (source: string, transform: (entry: any) => any) => any[];
diff --git a/server/node_modules/pg-types/index.js b/server/node_modules/pg-types/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..952d8c279d7834c64598e96c01260ab01665e5c3
--- /dev/null
+++ b/server/node_modules/pg-types/index.js
@@ -0,0 +1,47 @@
+var textParsers = require('./lib/textParsers');
+var binaryParsers = require('./lib/binaryParsers');
+var arrayParser = require('./lib/arrayParser');
+var builtinTypes = require('./lib/builtins');
+
+exports.getTypeParser = getTypeParser;
+exports.setTypeParser = setTypeParser;
+exports.arrayParser = arrayParser;
+exports.builtins = builtinTypes;
+
+var typeParsers = {
+  text: {},
+  binary: {}
+};
+
+//the empty parse function
+function noParse (val) {
+  return String(val);
+};
+
+//returns a function used to convert a specific type (specified by
+//oid) into a result javascript type
+//note: the oid can be obtained via the following sql query:
+//SELECT oid FROM pg_type WHERE typname = 'TYPE_NAME_HERE';
+function getTypeParser (oid, format) {
+  format = format || 'text';
+  if (!typeParsers[format]) {
+    return noParse;
+  }
+  return typeParsers[format][oid] || noParse;
+};
+
+function setTypeParser (oid, format, parseFn) {
+  if(typeof format == 'function') {
+    parseFn = format;
+    format = 'text';
+  }
+  typeParsers[format][oid] = parseFn;
+};
+
+textParsers.init(function(oid, converter) {
+  typeParsers.text[oid] = converter;
+});
+
+binaryParsers.init(function(oid, converter) {
+  typeParsers.binary[oid] = converter;
+});
diff --git a/server/node_modules/pg-types/index.test-d.ts b/server/node_modules/pg-types/index.test-d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d530e6efc77837317b412d10c4d1e7322e244a41
--- /dev/null
+++ b/server/node_modules/pg-types/index.test-d.ts
@@ -0,0 +1,21 @@
+import * as types from '.';
+import { expectType } from 'tsd';
+
+// builtins
+expectType<types.TypesBuiltins>(types.builtins);
+
+// getTypeParser
+const noParse = types.getTypeParser(types.builtins.NUMERIC, 'text');
+const numericParser = types.getTypeParser(types.builtins.NUMERIC, 'binary');
+expectType<string>(noParse('noParse'));
+expectType<number>(numericParser([200, 1, 0, 15]));
+
+// getArrayParser 
+const value = types.arrayParser('{1,2,3}', (num) => parseInt(num));
+expectType<number[]>(value);
+
+//setTypeParser
+types.setTypeParser(types.builtins.INT8, parseInt);
+types.setTypeParser(types.builtins.FLOAT8, parseFloat);
+types.setTypeParser(types.builtins.FLOAT8, 'binary', (data) => data[0]);
+types.setTypeParser(types.builtins.FLOAT8, 'text', parseFloat);
diff --git a/server/node_modules/pg-types/lib/arrayParser.js b/server/node_modules/pg-types/lib/arrayParser.js
new file mode 100644
index 0000000000000000000000000000000000000000..81ccffbc85659d2a101f624b7e3ec220c00ecbaa
--- /dev/null
+++ b/server/node_modules/pg-types/lib/arrayParser.js
@@ -0,0 +1,11 @@
+var array = require('postgres-array');
+
+module.exports = {
+  create: function (source, transform) {
+    return {
+      parse: function() {
+        return array.parse(source, transform);
+      }
+    };
+  }
+};
diff --git a/server/node_modules/pg-types/lib/binaryParsers.js b/server/node_modules/pg-types/lib/binaryParsers.js
new file mode 100644
index 0000000000000000000000000000000000000000..e12c2f46365148c3e50646ce41264124c4c756d1
--- /dev/null
+++ b/server/node_modules/pg-types/lib/binaryParsers.js
@@ -0,0 +1,257 @@
+var parseInt64 = require('pg-int8');
+
+var parseBits = function(data, bits, offset, invert, callback) {
+  offset = offset || 0;
+  invert = invert || false;
+  callback = callback || function(lastValue, newValue, bits) { return (lastValue * Math.pow(2, bits)) + newValue; };
+  var offsetBytes = offset >> 3;
+
+  var inv = function(value) {
+    if (invert) {
+      return ~value & 0xff;
+    }
+
+    return value;
+  };
+
+  // read first (maybe partial) byte
+  var mask = 0xff;
+  var firstBits = 8 - (offset % 8);
+  if (bits < firstBits) {
+    mask = (0xff << (8 - bits)) & 0xff;
+    firstBits = bits;
+  }
+
+  if (offset) {
+    mask = mask >> (offset % 8);
+  }
+
+  var result = 0;
+  if ((offset % 8) + bits >= 8) {
+    result = callback(0, inv(data[offsetBytes]) & mask, firstBits);
+  }
+
+  // read bytes
+  var bytes = (bits + offset) >> 3;
+  for (var i = offsetBytes + 1; i < bytes; i++) {
+    result = callback(result, inv(data[i]), 8);
+  }
+
+  // bits to read, that are not a complete byte
+  var lastBits = (bits + offset) % 8;
+  if (lastBits > 0) {
+    result = callback(result, inv(data[bytes]) >> (8 - lastBits), lastBits);
+  }
+
+  return result;
+};
+
+var parseFloatFromBits = function(data, precisionBits, exponentBits) {
+  var bias = Math.pow(2, exponentBits - 1) - 1;
+  var sign = parseBits(data, 1);
+  var exponent = parseBits(data, exponentBits, 1);
+
+  if (exponent === 0) {
+    return 0;
+  }
+
+  // parse mantissa
+  var precisionBitsCounter = 1;
+  var parsePrecisionBits = function(lastValue, newValue, bits) {
+    if (lastValue === 0) {
+      lastValue = 1;
+    }
+
+    for (var i = 1; i <= bits; i++) {
+      precisionBitsCounter /= 2;
+      if ((newValue & (0x1 << (bits - i))) > 0) {
+        lastValue += precisionBitsCounter;
+      }
+    }
+
+    return lastValue;
+  };
+
+  var mantissa = parseBits(data, precisionBits, exponentBits + 1, false, parsePrecisionBits);
+
+  // special cases
+  if (exponent == (Math.pow(2, exponentBits + 1) - 1)) {
+    if (mantissa === 0) {
+      return (sign === 0) ? Infinity : -Infinity;
+    }
+
+    return NaN;
+  }
+
+  // normale number
+  return ((sign === 0) ? 1 : -1) * Math.pow(2, exponent - bias) * mantissa;
+};
+
+var parseInt16 = function(value) {
+  if (parseBits(value, 1) == 1) {
+    return -1 * (parseBits(value, 15, 1, true) + 1);
+  }
+
+  return parseBits(value, 15, 1);
+};
+
+var parseInt32 = function(value) {
+  if (parseBits(value, 1) == 1) {
+    return -1 * (parseBits(value, 31, 1, true) + 1);
+  }
+
+  return parseBits(value, 31, 1);
+};
+
+var parseFloat32 = function(value) {
+  return parseFloatFromBits(value, 23, 8);
+};
+
+var parseFloat64 = function(value) {
+  return parseFloatFromBits(value, 52, 11);
+};
+
+var parseNumeric = function(value) {
+  var sign = parseBits(value, 16, 32);
+  if (sign == 0xc000) {
+    return NaN;
+  }
+
+  var weight = Math.pow(10000, parseBits(value, 16, 16));
+  var result = 0;
+
+  var digits = [];
+  var ndigits = parseBits(value, 16);
+  for (var i = 0; i < ndigits; i++) {
+    result += parseBits(value, 16, 64 + (16 * i)) * weight;
+    weight /= 10000;
+  }
+
+  var scale = Math.pow(10, parseBits(value, 16, 48));
+  return ((sign === 0) ? 1 : -1) * Math.round(result * scale) / scale;
+};
+
+var parseDate = function(isUTC, value) {
+  var sign = parseBits(value, 1);
+  var rawValue = parseBits(value, 63, 1);
+
+  // discard usecs and shift from 2000 to 1970
+  var result = new Date((((sign === 0) ? 1 : -1) * rawValue / 1000) + 946684800000);
+
+  if (!isUTC) {
+    result.setTime(result.getTime() + result.getTimezoneOffset() * 60000);
+  }
+
+  // add microseconds to the date
+  result.usec = rawValue % 1000;
+  result.getMicroSeconds = function() {
+    return this.usec;
+  };
+  result.setMicroSeconds = function(value) {
+    this.usec = value;
+  };
+  result.getUTCMicroSeconds = function() {
+    return this.usec;
+  };
+
+  return result;
+};
+
+var parseArray = function(value) {
+  var dim = parseBits(value, 32);
+
+  var flags = parseBits(value, 32, 32);
+  var elementType = parseBits(value, 32, 64);
+
+  var offset = 96;
+  var dims = [];
+  for (var i = 0; i < dim; i++) {
+    // parse dimension
+    dims[i] = parseBits(value, 32, offset);
+    offset += 32;
+
+    // ignore lower bounds
+    offset += 32;
+  }
+
+  var parseElement = function(elementType) {
+    // parse content length
+    var length = parseBits(value, 32, offset);
+    offset += 32;
+
+    // parse null values
+    if (length == 0xffffffff) {
+      return null;
+    }
+
+    var result;
+    if ((elementType == 0x17) || (elementType == 0x14)) {
+      // int/bigint
+      result = parseBits(value, length * 8, offset);
+      offset += length * 8;
+      return result;
+    }
+    else if (elementType == 0x19) {
+      // string
+      result = value.toString(this.encoding, offset >> 3, (offset += (length << 3)) >> 3);
+      return result;
+    }
+    else {
+      console.log("ERROR: ElementType not implemented: " + elementType);
+    }
+  };
+
+  var parse = function(dimension, elementType) {
+    var array = [];
+    var i;
+
+    if (dimension.length > 1) {
+      var count = dimension.shift();
+      for (i = 0; i < count; i++) {
+        array[i] = parse(dimension, elementType);
+      }
+      dimension.unshift(count);
+    }
+    else {
+      for (i = 0; i < dimension[0]; i++) {
+        array[i] = parseElement(elementType);
+      }
+    }
+
+    return array;
+  };
+
+  return parse(dims, elementType);
+};
+
+var parseText = function(value) {
+  return value.toString('utf8');
+};
+
+var parseBool = function(value) {
+  if(value === null) return null;
+  return (parseBits(value, 8) > 0);
+};
+
+var init = function(register) {
+  register(20, parseInt64);
+  register(21, parseInt16);
+  register(23, parseInt32);
+  register(26, parseInt32);
+  register(1700, parseNumeric);
+  register(700, parseFloat32);
+  register(701, parseFloat64);
+  register(16, parseBool);
+  register(1114, parseDate.bind(null, false));
+  register(1184, parseDate.bind(null, true));
+  register(1000, parseArray);
+  register(1007, parseArray);
+  register(1016, parseArray);
+  register(1008, parseArray);
+  register(1009, parseArray);
+  register(25, parseText);
+};
+
+module.exports = {
+  init: init
+};
diff --git a/server/node_modules/pg-types/lib/builtins.js b/server/node_modules/pg-types/lib/builtins.js
new file mode 100644
index 0000000000000000000000000000000000000000..f0c134a8abbce39244fe46b09dd861006196eb68
--- /dev/null
+++ b/server/node_modules/pg-types/lib/builtins.js
@@ -0,0 +1,73 @@
+/**
+ * Following query was used to generate this file:
+
+ SELECT json_object_agg(UPPER(PT.typname), PT.oid::int4 ORDER BY pt.oid)
+ FROM pg_type PT
+ WHERE typnamespace = (SELECT pgn.oid FROM pg_namespace pgn WHERE nspname = 'pg_catalog') -- Take only builting Postgres types with stable OID (extension types are not guaranted to be stable)
+ AND typtype = 'b' -- Only basic types
+ AND typelem = 0 -- Ignore aliases
+ AND typisdefined -- Ignore undefined types
+ */
+
+module.exports = {
+    BOOL: 16,
+    BYTEA: 17,
+    CHAR: 18,
+    INT8: 20,
+    INT2: 21,
+    INT4: 23,
+    REGPROC: 24,
+    TEXT: 25,
+    OID: 26,
+    TID: 27,
+    XID: 28,
+    CID: 29,
+    JSON: 114,
+    XML: 142,
+    PG_NODE_TREE: 194,
+    SMGR: 210,
+    PATH: 602,
+    POLYGON: 604,
+    CIDR: 650,
+    FLOAT4: 700,
+    FLOAT8: 701,
+    ABSTIME: 702,
+    RELTIME: 703,
+    TINTERVAL: 704,
+    CIRCLE: 718,
+    MACADDR8: 774,
+    MONEY: 790,
+    MACADDR: 829,
+    INET: 869,
+    ACLITEM: 1033,
+    BPCHAR: 1042,
+    VARCHAR: 1043,
+    DATE: 1082,
+    TIME: 1083,
+    TIMESTAMP: 1114,
+    TIMESTAMPTZ: 1184,
+    INTERVAL: 1186,
+    TIMETZ: 1266,
+    BIT: 1560,
+    VARBIT: 1562,
+    NUMERIC: 1700,
+    REFCURSOR: 1790,
+    REGPROCEDURE: 2202,
+    REGOPER: 2203,
+    REGOPERATOR: 2204,
+    REGCLASS: 2205,
+    REGTYPE: 2206,
+    UUID: 2950,
+    TXID_SNAPSHOT: 2970,
+    PG_LSN: 3220,
+    PG_NDISTINCT: 3361,
+    PG_DEPENDENCIES: 3402,
+    TSVECTOR: 3614,
+    TSQUERY: 3615,
+    GTSVECTOR: 3642,
+    REGCONFIG: 3734,
+    REGDICTIONARY: 3769,
+    JSONB: 3802,
+    REGNAMESPACE: 4089,
+    REGROLE: 4096
+};
diff --git a/server/node_modules/pg-types/lib/textParsers.js b/server/node_modules/pg-types/lib/textParsers.js
new file mode 100644
index 0000000000000000000000000000000000000000..b1218bfe26499c98c3a62d9f8e8c041c3106fc7d
--- /dev/null
+++ b/server/node_modules/pg-types/lib/textParsers.js
@@ -0,0 +1,215 @@
+var array = require('postgres-array')
+var arrayParser = require('./arrayParser');
+var parseDate = require('postgres-date');
+var parseInterval = require('postgres-interval');
+var parseByteA = require('postgres-bytea');
+
+function allowNull (fn) {
+  return function nullAllowed (value) {
+    if (value === null) return value
+    return fn(value)
+  }
+}
+
+function parseBool (value) {
+  if (value === null) return value
+  return value === 'TRUE' ||
+    value === 't' ||
+    value === 'true' ||
+    value === 'y' ||
+    value === 'yes' ||
+    value === 'on' ||
+    value === '1';
+}
+
+function parseBoolArray (value) {
+  if (!value) return null
+  return array.parse(value, parseBool)
+}
+
+function parseBaseTenInt (string) {
+  return parseInt(string, 10)
+}
+
+function parseIntegerArray (value) {
+  if (!value) return null
+  return array.parse(value, allowNull(parseBaseTenInt))
+}
+
+function parseBigIntegerArray (value) {
+  if (!value) return null
+  return array.parse(value, allowNull(function (entry) {
+    return parseBigInteger(entry).trim()
+  }))
+}
+
+var parsePointArray = function(value) {
+  if(!value) { return null; }
+  var p = arrayParser.create(value, function(entry) {
+    if(entry !== null) {
+      entry = parsePoint(entry);
+    }
+    return entry;
+  });
+
+  return p.parse();
+};
+
+var parseFloatArray = function(value) {
+  if(!value) { return null; }
+  var p = arrayParser.create(value, function(entry) {
+    if(entry !== null) {
+      entry = parseFloat(entry);
+    }
+    return entry;
+  });
+
+  return p.parse();
+};
+
+var parseStringArray = function(value) {
+  if(!value) { return null; }
+
+  var p = arrayParser.create(value);
+  return p.parse();
+};
+
+var parseDateArray = function(value) {
+  if (!value) { return null; }
+
+  var p = arrayParser.create(value, function(entry) {
+    if (entry !== null) {
+      entry = parseDate(entry);
+    }
+    return entry;
+  });
+
+  return p.parse();
+};
+
+var parseIntervalArray = function(value) {
+  if (!value) { return null; }
+
+  var p = arrayParser.create(value, function(entry) {
+    if (entry !== null) {
+      entry = parseInterval(entry);
+    }
+    return entry;
+  });
+
+  return p.parse();
+};
+
+var parseByteAArray = function(value) {
+  if (!value) { return null; }
+
+  return array.parse(value, allowNull(parseByteA));
+};
+
+var parseInteger = function(value) {
+  return parseInt(value, 10);
+};
+
+var parseBigInteger = function(value) {
+  var valStr = String(value);
+  if (/^\d+$/.test(valStr)) { return valStr; }
+  return value;
+};
+
+var parseJsonArray = function(value) {
+  if (!value) { return null; }
+
+  return array.parse(value, allowNull(JSON.parse));
+};
+
+var parsePoint = function(value) {
+  if (value[0] !== '(') { return null; }
+
+  value = value.substring( 1, value.length - 1 ).split(',');
+
+  return {
+    x: parseFloat(value[0])
+  , y: parseFloat(value[1])
+  };
+};
+
+var parseCircle = function(value) {
+  if (value[0] !== '<' && value[1] !== '(') { return null; }
+
+  var point = '(';
+  var radius = '';
+  var pointParsed = false;
+  for (var i = 2; i < value.length - 1; i++){
+    if (!pointParsed) {
+      point += value[i];
+    }
+
+    if (value[i] === ')') {
+      pointParsed = true;
+      continue;
+    } else if (!pointParsed) {
+      continue;
+    }
+
+    if (value[i] === ','){
+      continue;
+    }
+
+    radius += value[i];
+  }
+  var result = parsePoint(point);
+  result.radius = parseFloat(radius);
+
+  return result;
+};
+
+var init = function(register) {
+  register(20, parseBigInteger); // int8
+  register(21, parseInteger); // int2
+  register(23, parseInteger); // int4
+  register(26, parseInteger); // oid
+  register(700, parseFloat); // float4/real
+  register(701, parseFloat); // float8/double
+  register(16, parseBool);
+  register(1082, parseDate); // date
+  register(1114, parseDate); // timestamp without timezone
+  register(1184, parseDate); // timestamp
+  register(600, parsePoint); // point
+  register(651, parseStringArray); // cidr[]
+  register(718, parseCircle); // circle
+  register(1000, parseBoolArray);
+  register(1001, parseByteAArray);
+  register(1005, parseIntegerArray); // _int2
+  register(1007, parseIntegerArray); // _int4
+  register(1028, parseIntegerArray); // oid[]
+  register(1016, parseBigIntegerArray); // _int8
+  register(1017, parsePointArray); // point[]
+  register(1021, parseFloatArray); // _float4
+  register(1022, parseFloatArray); // _float8
+  register(1231, parseFloatArray); // _numeric
+  register(1014, parseStringArray); //char
+  register(1015, parseStringArray); //varchar
+  register(1008, parseStringArray);
+  register(1009, parseStringArray);
+  register(1040, parseStringArray); // macaddr[]
+  register(1041, parseStringArray); // inet[]
+  register(1115, parseDateArray); // timestamp without time zone[]
+  register(1182, parseDateArray); // _date
+  register(1185, parseDateArray); // timestamp with time zone[]
+  register(1186, parseInterval);
+  register(1187, parseIntervalArray);
+  register(17, parseByteA);
+  register(114, JSON.parse.bind(JSON)); // json
+  register(3802, JSON.parse.bind(JSON)); // jsonb
+  register(199, parseJsonArray); // json[]
+  register(3807, parseJsonArray); // jsonb[]
+  register(3907, parseStringArray); // numrange[]
+  register(2951, parseStringArray); // uuid[]
+  register(791, parseStringArray); // money[]
+  register(1183, parseStringArray); // time[]
+  register(1270, parseStringArray); // timetz[]
+};
+
+module.exports = {
+  init: init
+};
diff --git a/server/node_modules/pg-types/package.json b/server/node_modules/pg-types/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..98c03cd33a0e4f07c5e80e2fea20e72002f458b7
--- /dev/null
+++ b/server/node_modules/pg-types/package.json
@@ -0,0 +1,69 @@
+{
+  "_from": "pg-types@^2.1.0",
+  "_id": "pg-types@2.2.0",
+  "_inBundle": false,
+  "_integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
+  "_location": "/pg-types",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "pg-types@^2.1.0",
+    "name": "pg-types",
+    "escapedName": "pg-types",
+    "rawSpec": "^2.1.0",
+    "saveSpec": null,
+    "fetchSpec": "^2.1.0"
+  },
+  "_requiredBy": [
+    "/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
+  "_shasum": "2d0250d636454f7cfa3b6ae0382fdfa8063254a3",
+  "_spec": "pg-types@^2.1.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg",
+  "author": {
+    "name": "Brian M. Carlson"
+  },
+  "bugs": {
+    "url": "https://github.com/brianc/node-pg-types/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "pg-int8": "1.0.1",
+    "postgres-array": "~2.0.0",
+    "postgres-bytea": "~1.0.0",
+    "postgres-date": "~1.0.4",
+    "postgres-interval": "^1.1.0"
+  },
+  "deprecated": false,
+  "description": "Query result type converters for node-postgres",
+  "devDependencies": {
+    "if-node-version": "^1.1.1",
+    "pff": "^1.0.0",
+    "tap-spec": "^4.0.0",
+    "tape": "^4.0.0",
+    "tsd": "^0.7.4"
+  },
+  "engines": {
+    "node": ">=4"
+  },
+  "homepage": "https://github.com/brianc/node-pg-types",
+  "keywords": [
+    "postgres",
+    "PostgreSQL",
+    "pg"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "pg-types",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianc/node-pg-types.git"
+  },
+  "scripts": {
+    "test": "tape test/*.js | tap-spec && npm run test-ts",
+    "test-ts": "if-node-version '>= 8' tsd"
+  },
+  "version": "2.2.0"
+}
diff --git a/server/node_modules/pg-types/test/index.js b/server/node_modules/pg-types/test/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..b7d05cd68f12a893a4d69c7063b9415efd60ed6c
--- /dev/null
+++ b/server/node_modules/pg-types/test/index.js
@@ -0,0 +1,24 @@
+
+var test = require('tape')
+var printf = require('pff')
+var getTypeParser = require('../').getTypeParser
+var types = require('./types')
+
+test('types', function (t) {
+  Object.keys(types).forEach(function (typeName) {
+    var type = types[typeName]
+    t.test(typeName, function (t) {
+      var parser = getTypeParser(type.id, type.format)
+      type.tests.forEach(function (tests) {
+        var input = tests[0]
+        var expected = tests[1]
+        var result = parser(input)
+        if (typeof expected === 'function') {
+          return expected(t, result)
+        }
+        t.equal(result, expected)
+      })
+      t.end()
+    })
+  })
+})
diff --git a/server/node_modules/pg-types/test/types.js b/server/node_modules/pg-types/test/types.js
new file mode 100644
index 0000000000000000000000000000000000000000..af708a5c34867f7c11ded35aca111ba108efd4df
--- /dev/null
+++ b/server/node_modules/pg-types/test/types.js
@@ -0,0 +1,597 @@
+'use strict'
+
+exports['string/varchar'] = {
+  format: 'text',
+  id: 1043,
+  tests: [
+    ['bang', 'bang']
+  ]
+}
+
+exports['integer/int4'] = {
+  format: 'text',
+  id: 23,
+  tests: [
+    ['2147483647', 2147483647]
+  ]
+}
+
+exports['smallint/int2'] = {
+  format: 'text',
+  id: 21,
+  tests: [
+    ['32767', 32767]
+  ]
+}
+
+exports['bigint/int8'] = {
+  format: 'text',
+  id: 20,
+  tests: [
+    ['9223372036854775807', '9223372036854775807']
+  ]
+}
+
+exports.oid = {
+  format: 'text',
+  id: 26,
+  tests: [
+    ['103', 103]
+  ]
+}
+
+var bignum = '31415926535897932384626433832795028841971693993751058.16180339887498948482045868343656381177203091798057628'
+exports.numeric = {
+  format: 'text',
+  id: 1700,
+  tests: [
+    [bignum, bignum]
+  ]
+}
+
+exports['real/float4'] = {
+  format: 'text',
+  id: 700,
+  tests: [
+    ['123.456', 123.456]
+  ]
+}
+
+exports['double precision / float 8'] = {
+  format: 'text',
+  id: 701,
+  tests: [
+    ['12345678.12345678', 12345678.12345678]
+  ]
+}
+
+exports.boolean = {
+  format: 'text',
+  id: 16,
+  tests: [
+    ['TRUE', true],
+    ['t', true],
+    ['true', true],
+    ['y', true],
+    ['yes', true],
+    ['on', true],
+    ['1', true],
+    ['f', false],
+    [null, null]
+  ]
+}
+
+exports.timestamptz = {
+  format: 'text',
+  id: 1184,
+  tests: [
+    [
+      '2010-10-31 14:54:13.74-05:30',
+      dateEquals(2010, 9, 31, 20, 24, 13, 740)
+    ],
+    [
+      '2011-01-23 22:05:00.68-06',
+       dateEquals(2011, 0, 24, 4, 5, 0, 680)
+    ],
+    [
+      '2010-10-30 14:11:12.730838Z',
+      dateEquals(2010, 9, 30, 14, 11, 12, 730)
+    ],
+    [
+      '2010-10-30 13:10:01+05',
+      dateEquals(2010, 9, 30, 8, 10, 1, 0)
+    ]
+  ]
+}
+
+exports.timestamp = {
+  format: 'text',
+  id: 1114,
+  tests: [
+    [
+      '2010-10-31 00:00:00',
+      function (t, value) {
+        t.equal(
+          value.toUTCString(),
+          new Date(2010, 9, 31, 0, 0, 0, 0, 0).toUTCString()
+        )
+        t.equal(
+          value.toString(),
+          new Date(2010, 9, 31, 0, 0, 0, 0, 0, 0).toString()
+        )
+      }
+    ]
+  ]
+}
+
+exports.date = {
+  format: 'text',
+  id: 1082,
+  tests: [
+    ['2010-10-31', function (t, value) {
+      var now = new Date(2010, 9, 31)
+      dateEquals(
+        2010,
+        now.getUTCMonth(),
+        now.getUTCDate(),
+        now.getUTCHours(), 0, 0, 0)(t, value)
+      t.equal(value.getHours(), now.getHours())
+    }]
+  ]
+}
+
+exports.inet = {
+  format: 'text',
+  id: 869,
+  tests: [
+    ['8.8.8.8', '8.8.8.8'],
+    ['2001:4860:4860::8888', '2001:4860:4860::8888'],
+    ['127.0.0.1', '127.0.0.1'],
+    ['fd00:1::40e', 'fd00:1::40e'],
+    ['1.2.3.4', '1.2.3.4']
+  ]
+}
+
+exports.cidr = {
+  format: 'text',
+  id: 650,
+  tests: [
+    ['172.16.0.0/12', '172.16.0.0/12'],
+    ['fe80::/10', 'fe80::/10'],
+    ['fc00::/7', 'fc00::/7'],
+    ['192.168.0.0/24', '192.168.0.0/24'],
+    ['10.0.0.0/8', '10.0.0.0/8']
+  ]
+}
+
+exports.macaddr = {
+  format: 'text',
+  id: 829,
+  tests: [
+    ['08:00:2b:01:02:03', '08:00:2b:01:02:03'],
+    ['16:10:9f:0d:66:00', '16:10:9f:0d:66:00']
+  ]
+}
+
+exports.numrange = {
+  format: 'text',
+  id: 3906,
+  tests: [
+    ['[,]', '[,]'],
+    ['(,)', '(,)'],
+    ['(,]', '(,]'],
+    ['[1,)', '[1,)'],
+    ['[,1]', '[,1]'],
+    ['(1,2)', '(1,2)'],
+    ['(1,20.5]', '(1,20.5]']
+  ]
+}
+
+exports.interval = {
+  format: 'text',
+  id: 1186,
+  tests: [
+    ['01:02:03', function (t, value) {
+      t.equal(value.toPostgres(), '3 seconds 2 minutes 1 hours')
+      t.deepEqual(value, {hours: 1, minutes: 2, seconds: 3})
+    }],
+    ['01:02:03.456', function (t, value) {
+      t.deepEqual(value, {hours: 1, minutes:2, seconds: 3, milliseconds: 456})
+    }],
+    ['1 year -32 days', function (t, value) {
+      t.equal(value.toPostgres(), '-32 days 1 years')
+      t.deepEqual(value, {years: 1, days: -32})
+    }],
+    ['1 day -00:00:03', function (t, value) {
+      t.equal(value.toPostgres(), '-3 seconds 1 days')
+      t.deepEqual(value, {days: 1, seconds: -3})
+    }]
+  ]
+}
+
+exports.bytea = {
+  format: 'text',
+  id: 17,
+  tests: [
+    ['foo\\000\\200\\\\\\377', function (t, value) {
+      var buffer = new Buffer([102, 111, 111, 0, 128, 92, 255])
+      t.ok(buffer.equals(value))
+    }],
+    ['', function (t, value) {
+      var buffer = new Buffer(0)
+      t.ok(buffer.equals(value))
+    }]
+  ]
+}
+
+exports['array/boolean'] = {
+    format: 'text',
+    id: 1000,
+    tests: [
+        ['{true,false}', function (t, value) {
+            t.deepEqual(value, [true, false])
+        }]
+    ]
+}
+
+exports['array/char'] = {
+  format: 'text',
+  id: 1014,
+  tests: [
+    ['{foo,bar}', function (t, value) {
+      t.deepEqual(value, ['foo', 'bar'])
+    }]
+  ]
+}
+
+exports['array/varchar'] = {
+  format: 'text',
+  id: 1015,
+  tests: [
+    ['{foo,bar}', function (t, value) {
+      t.deepEqual(value, ['foo', 'bar'])
+    }]
+  ]
+}
+
+exports['array/text'] = {
+  format: 'text',
+  id: 1008,
+  tests: [
+    ['{foo}', function (t, value) {
+      t.deepEqual(value, ['foo'])
+    }]
+  ]
+}
+
+exports['array/bytea'] = {
+  format: 'text',
+  id: 1001,
+  tests: [
+    ['{"\\\\x00000000"}', function (t, value) {
+      var buffer = new Buffer('00000000', 'hex')
+      t.ok(Array.isArray(value))
+      t.equal(value.length, 1)
+      t.ok(buffer.equals(value[0]))
+    }],
+    ['{NULL,"\\\\x4e554c4c"}', function (t, value) {
+      var buffer = new Buffer('4e554c4c', 'hex')
+      t.ok(Array.isArray(value))
+      t.equal(value.length, 2)
+      t.equal(value[0], null)
+      t.ok(buffer.equals(value[1]))
+    }],
+  ]
+}
+
+exports['array/numeric'] = {
+  format: 'text',
+  id: 1231,
+  tests: [
+    ['{1.2,3.4}', function (t, value) {
+      t.deepEqual(value, [1.2, 3.4])
+    }]
+  ]
+}
+
+exports['array/int2'] = {
+  format: 'text',
+  id: 1005,
+  tests: [
+    ['{-32768, -32767, 32766, 32767}', function (t, value) {
+      t.deepEqual(value, [-32768, -32767, 32766, 32767])
+    }]
+  ]
+}
+
+exports['array/int4'] = {
+  format: 'text',
+  id: 1005,
+  tests: [
+    ['{-2147483648, -2147483647, 2147483646, 2147483647}', function (t, value) {
+      t.deepEqual(value, [-2147483648, -2147483647, 2147483646, 2147483647])
+    }]
+  ]
+}
+
+exports['array/int8'] = {
+  format: 'text',
+  id: 1016,
+  tests: [
+    [
+      '{-9223372036854775808, -9223372036854775807, 9223372036854775806, 9223372036854775807}',
+      function (t, value) {
+        t.deepEqual(value, [
+          '-9223372036854775808',
+          '-9223372036854775807',
+          '9223372036854775806',
+          '9223372036854775807'
+        ])
+      }
+    ]
+  ]
+}
+
+exports['array/json'] = {
+  format: 'text',
+  id: 199,
+  tests: [
+    [
+      '{{1,2},{[3],"[4,5]"},{null,NULL}}',
+      function (t, value) {
+        t.deepEqual(value, [
+          [1, 2],
+          [[3], [4, 5]],
+          [null, null],
+        ])
+      }
+    ]
+  ]
+}
+
+exports['array/jsonb'] = {
+  format: 'text',
+  id: 3807,
+  tests: exports['array/json'].tests
+}
+
+exports['array/point'] = {
+  format: 'text',
+  id: 1017,
+  tests: [
+    ['{"(25.1,50.5)","(10.1,40)"}', function (t, value) {
+      t.deepEqual(value, [{x: 25.1, y: 50.5}, {x: 10.1, y: 40}])
+    }]
+  ]
+}
+
+exports['array/oid'] = {
+  format: 'text',
+  id: 1028,
+  tests: [
+    ['{25864,25860}', function (t, value) {
+      t.deepEqual(value, [25864, 25860])
+    }]
+  ]
+}
+
+exports['array/float4'] = {
+  format: 'text',
+  id: 1021,
+  tests: [
+    ['{1.2, 3.4}', function (t, value) {
+      t.deepEqual(value, [1.2, 3.4])
+    }]
+  ]
+}
+
+exports['array/float8'] = {
+  format: 'text',
+  id: 1022,
+  tests: [
+    ['{-12345678.1234567, 12345678.12345678}', function (t, value) {
+      t.deepEqual(value, [-12345678.1234567, 12345678.12345678])
+    }]
+  ]
+}
+
+exports['array/date'] = {
+  format: 'text',
+  id: 1182,
+  tests: [
+    ['{2014-01-01,2015-12-31}', function (t, value) {
+      var expecteds = [new Date(2014, 0, 1), new Date(2015, 11, 31)]
+      t.equal(value.length, 2)
+      value.forEach(function (date, index) {
+        var expected = expecteds[index]
+        dateEquals(
+          expected.getUTCFullYear(),
+          expected.getUTCMonth(),
+          expected.getUTCDate(),
+          expected.getUTCHours(), 0, 0, 0)(t, date)
+      })
+    }]
+  ]
+}
+
+exports['array/interval'] = {
+  format: 'text',
+  id: 1187,
+  tests: [
+    ['{01:02:03,1 day -00:00:03}', function (t, value) {
+      var expecteds = [{hours: 1, minutes: 2, seconds: 3},
+                       {days: 1, seconds: -3}]
+      t.equal(value.length, 2)
+      t.deepEqual(value, expecteds);
+    }]
+  ]
+}
+
+exports['array/inet'] = {
+  format: 'text',
+  id: 1041,
+  tests: [
+    ['{8.8.8.8}', function (t, value) {
+      t.deepEqual(value, ['8.8.8.8']);
+    }],
+    ['{2001:4860:4860::8888}', function (t, value) {
+      t.deepEqual(value, ['2001:4860:4860::8888']);
+    }],
+    ['{127.0.0.1,fd00:1::40e,1.2.3.4}', function (t, value) {
+      t.deepEqual(value, ['127.0.0.1', 'fd00:1::40e', '1.2.3.4']);
+    }]
+  ]
+}
+
+exports['array/cidr'] = {
+  format: 'text',
+  id: 651,
+  tests: [
+    ['{172.16.0.0/12}', function (t, value) {
+      t.deepEqual(value, ['172.16.0.0/12']);
+    }],
+    ['{fe80::/10}', function (t, value) {
+      t.deepEqual(value, ['fe80::/10']);
+    }],
+    ['{10.0.0.0/8,fc00::/7,192.168.0.0/24}', function (t, value) {
+      t.deepEqual(value, ['10.0.0.0/8', 'fc00::/7', '192.168.0.0/24']);
+    }]
+  ]
+}
+
+exports['array/macaddr'] = {
+  format: 'text',
+  id: 1040,
+  tests: [
+    ['{08:00:2b:01:02:03,16:10:9f:0d:66:00}', function (t, value) {
+      t.deepEqual(value, ['08:00:2b:01:02:03', '16:10:9f:0d:66:00']);
+    }]
+  ]
+}
+
+exports['array/numrange'] = {
+  format: 'text',
+  id: 3907,
+  tests: [
+    ['{"[1,2]","(4.5,8)","[10,40)","(-21.2,60.3]"}', function (t, value) {
+      t.deepEqual(value, ['[1,2]', '(4.5,8)', '[10,40)', '(-21.2,60.3]']);
+    }],
+    ['{"[,20]","[3,]","[,]","(,35)","(1,)","(,)"}', function (t, value) {
+      t.deepEqual(value, ['[,20]', '[3,]', '[,]', '(,35)', '(1,)', '(,)']);
+    }],
+    ['{"[,20)","[3,)","[,)","[,35)","[1,)","[,)"}', function (t, value) {
+      t.deepEqual(value, ['[,20)', '[3,)', '[,)', '[,35)', '[1,)', '[,)']);
+    }]
+  ]
+}
+
+exports['binary-string/varchar'] = {
+  format: 'binary',
+  id: 1043,
+  tests: [
+    ['bang', 'bang']
+  ]
+}
+
+exports['binary-integer/int4'] = {
+  format: 'binary',
+  id: 23,
+  tests: [
+    [[0, 0, 0, 100], 100]
+  ]
+}
+
+exports['binary-smallint/int2'] = {
+  format: 'binary',
+  id: 21,
+  tests: [
+    [[0, 101], 101]
+  ]
+}
+
+exports['binary-bigint/int8'] = {
+  format: 'binary',
+  id: 20,
+  tests: [
+    [new Buffer([0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), '9223372036854775807']
+  ]
+}
+
+exports['binary-oid'] = {
+  format: 'binary',
+  id: 26,
+  tests: [
+    [[0, 0, 0, 103], 103]
+  ]
+}
+
+exports['binary-numeric'] = {
+  format: 'binary',
+  id: 1700,
+  tests: [
+    [
+      [0, 2, 0, 0, 0, 0, 0, hex('0x64'), 0, 12, hex('0xd'), hex('0x48'), 0, 0, 0, 0],
+      12.34
+    ]
+  ]
+}
+
+exports['binary-real/float4'] = {
+  format: 'binary',
+  id: 700,
+  tests: [
+    [['0x41', '0x48', '0x00', '0x00'].map(hex), 12.5]
+  ]
+}
+
+exports['binary-boolean'] = {
+  format: 'binary',
+  id: 16,
+  tests: [
+    [[1], true],
+    [[0], false],
+    [null, null]
+  ]
+}
+
+exports['binary-string'] = {
+  format: 'binary',
+  id: 25,
+  tests: [
+    [
+      new Buffer(['0x73', '0x6c', '0x61', '0x64', '0x64', '0x61'].map(hex)),
+      'sladda'
+    ]
+  ]
+}
+
+exports.point = {
+  format: 'text',
+  id: 600,
+  tests: [
+    ['(25.1,50.5)', function (t, value) {
+      t.deepEqual(value, {x: 25.1, y: 50.5})
+    }]
+  ]
+}
+
+exports.circle = {
+  format: 'text',
+  id: 718,
+  tests: [
+    ['<(25,10),5>', function (t, value) {
+      t.deepEqual(value, {x: 25, y: 10, radius: 5})
+    }]
+  ]
+}
+
+function hex (string) {
+  return parseInt(string, 16)
+}
+
+function dateEquals () {
+  var timestamp = Date.UTC.apply(Date, arguments)
+  return function (t, value) {
+    t.equal(value.toUTCString(), new Date(timestamp).toUTCString())
+  }
+}
diff --git a/server/node_modules/pg/.eslintrc b/server/node_modules/pg/.eslintrc
new file mode 100644
index 0000000000000000000000000000000000000000..43aee6027ecdb5ee7afbd1dfa8c2db90595541fd
--- /dev/null
+++ b/server/node_modules/pg/.eslintrc
@@ -0,0 +1,19 @@
+{
+  "plugins": [
+    "node"
+  ],
+  "extends": [
+    "standard",
+    "eslint:recommended",
+    "plugin:node/recommended"
+  ],
+  "parserOptions": {
+    "ecmaVersion": 2017
+  },
+  "env": {
+    "node": true,
+    "es6": true
+  },
+  "rules": {
+  }
+}
diff --git a/server/node_modules/pg/CHANGELOG.md b/server/node_modules/pg/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..7792612f97d5023f39a4ab05a35598342c1a1382
--- /dev/null
+++ b/server/node_modules/pg/CHANGELOG.md
@@ -0,0 +1,332 @@
+All major and minor releases are briefly explained below.
+
+For richer information consult the commit log on github with referenced pull requests.
+
+We do not include break-fix version release in this file.
+
+### 7.12.0
+
+- Add support for [async password lookup](https://github.com/brianc/node-postgres/pull/1926).
+
+### 7.11.0
+
+- Add support for [connection_timeout](https://github.com/brianc/node-postgres/pull/1847/files#diff-5391bde944956870128be1136e7bc176R63) and [keepalives_idle](https://github.com/brianc/node-postgres/pull/1847).
+
+### 7.10.0
+
+- Add support for [per-query types](https://github.com/brianc/node-postgres/pull/1825).
+
+### 7.9.0
+
+- Add support for [sasl/scram authentication](https://github.com/brianc/node-postgres/pull/1835).
+
+### 7.8.0
+
+- Add support for passing [secureOptions](https://github.com/brianc/node-postgres/pull/1804) SSL config.
+- Upgrade [pg-types](https://github.com/brianc/node-postgres/pull/1806) to 2.0.
+
+### 7.7.0
+
+- Add support for configurable [query timeout](https://github.com/brianc/node-postgres/pull/1760) on a client level.
+
+### 7.6.0
+
+- Add support for ["bring your own promise"](https://github.com/brianc/node-postgres/pull/1518)
+
+### 7.5.0
+
+- Better [error message](https://github.com/brianc/node-postgres/commit/11a4793452d618c53e019416cc886ad38deb1aa7) when passing `null` or `undefined` to `client.query`.
+- Better [error handling](https://github.com/brianc/node-postgres/pull/1503) on queued queries.
+
+### 7.4.0
+
+- Add support for [Uint8Array](https://github.com/brianc/node-postgres/pull/1448) values.
+
+### 7.3.0
+
+- Add support for [statement timeout](https://github.com/brianc/node-postgres/pull/1436).
+
+### 7.2.0
+
+- Pinned pg-pool and pg-types to a tighter semver range. This is likely not a noticeable change for you unless you were specifically installing older versions of those libraries for some reason, but making it a minor bump here just in case it could cause any confusion.
+
+### 7.1.0
+
+#### Enhancements
+
+- [You can now supply both a connection string and additional config options to clients.](https://github.com/brianc/node-postgres/pull/1363)
+
+### 7.0.0
+
+#### Breaking Changes
+
+- Drop support for node < `4.x`.
+- Remove `pg.connect` `pg.end` and `pg.cancel` singleton methods.
+- `Client#connect(callback)` now returns `undefined`. It used to return an event emitter.
+- Upgrade [pg-pool](https://github.com/brianc/node-pg-pool) to `2.x`.
+- Upgrade [pg-native](https://github.com/brianc/node-pg-native) to `2.x`.
+- Standardize error message fields between JS and native driver. The only breaking changes were in the native driver as its field names were brought into alignment with the existing JS driver field names.
+- Result from multi-statement text queries such as `SELECT 1; SELECT 2;` are now returned as an array of results instead of a single result with 1 array containing rows from both queries.
+
+[Please see here for a migration guide](https://node-postgres.com/guides/upgrading)
+
+#### Enhancements
+
+- Overhauled documentation: [https://node-postgres.com](https://node-postgres.com).
+- Add `Client#connect() => Promise<void>` and `Client#end() => Promise<void>` calls. Promises are now returned from all async methods on clients _if and only if_ no callback was supplied to the method.
+- Add `connectionTimeoutMillis` to pg-pool.
+
+### v6.2.0
+
+- Add support for [parsing `replicationStart` messages](https://github.com/brianc/node-postgres/pull/1271/files).
+
+### v6.1.0
+
+- Add optional callback parameter to the pure JavaScript `client.end` method. The native client already supported this.
+
+### v6.0.0
+
+#### Breaking Changes
+
+- Remove `pg.pools`. There is still a reference kept to the pools created & tracked by `pg.connect` but it has been renamed, is considered private, and should not be used. Accessing this API directly was uncommon and was _supposed_ to be private but was incorrectly documented on the wiki. Therefore, it is a breaking change of an (unintentionally) public interface to remove it by renaming it & making it private. Eventually `pg.connect` itself will be deprecated in favor of instantiating pools directly via `new pg.Pool()` so this property should become completely moot at some point. In the mean time...check out the new features...
+
+#### New features
+
+- Replace internal pooling code with [pg-pool](https://github.com/brianc/node-pg-pool). This is the first step in eventually deprecating and removing the singleton `pg.connect`. The pg-pool constructor is exported from node-postgres at `require('pg').Pool`. It provides a backwards compatible interface with `pg.connect` as well as a promise based interface & additional niceties.
+
+You can now create an instance of a pool and don't have to rely on the `pg` singleton for anything:
+
+```
+var pg = require('pg')
+
+var pool = new pg.Pool()
+
+// your friendly neighborhood pool interface, without the singleton
+pool.connect(function(err, client, done) {
+  // ...
+})
+```
+
+Promise support & other goodness lives now in [pg-pool](https://github.com/brianc/node-pg-pool).
+
+**Please** read the readme at [pg-pool](https://github.com/brianc/node-pg-pool) for the full api.
+
+- Included support for tcp keep alive. Enable it as follows:
+
+```js
+var client = new Client({ keepAlive: true });
+```
+
+This should help with backends incorrectly considering idle clients to be dead and prematurely disconnecting them.
+
+### v5.1.0
+
+- Make the query object returned from `client.query` implement the promise interface. This is the first step towards promisifying more of the node-postgres api.
+
+Example:
+
+```js
+var client = new Client();
+client.connect();
+client.query("SELECT $1::text as name", ["brianc"]).then(function(res) {
+  console.log("hello from", res.rows[0]);
+  client.end();
+});
+```
+
+### v5.0.0
+
+#### Breaking Changes
+
+- `require('pg').native` now returns null if the native bindings cannot be found; previously, this threw an exception.
+
+#### New Features
+
+- better error message when passing `undefined` as a query parameter
+- support for `defaults.connectionString`
+- support for `returnToHead` being passed to [generic pool](https://github.com/coopernurse/node-pool)
+
+### v4.5.0
+
+- Add option to parse JS date objects in query parameters as [UTC](https://github.com/brianc/node-postgres/pull/943)
+
+### v4.4.0
+
+- Warn to `stderr` if a named query exceeds 63 characters which is the max length supported by postgres.
+
+### v4.3.0
+
+- Unpin `pg-types` semver. Allow it to float against `pg-types@1.x`.
+
+### v4.2.0
+
+- Support for additional error fields in postgres >= 9.3 if available.
+
+### v4.1.0
+
+- Allow type parser overrides on a [per-client basis](https://github.com/brianc/node-postgres/pull/679)
+
+### v4.0.0
+
+- Make [native bindings](https://github.com/brianc/node-pg-native.git) an optional install with `npm install pg-native`
+- No longer surround query result callback with `try/catch` block.
+- Remove built in COPY IN / COPY OUT support - better implementations provided by [pg-copy-streams](https://github.com/brianc/node-pg-copy-streams.git) and [pg-native](https://github.com/brianc/node-pg-native.git)
+
+### v3.6.0
+
+- Include support for (parsing JSONB)[https://github.com/brianc/node-pg-types/pull/13] (supported in postgres 9.4)
+
+### v3.5.0
+
+- Include support for parsing boolean arrays
+
+### v3.4.0
+
+- Include port as connection parameter to [unix sockets](https://github.com/brianc/node-postgres/pull/604)
+- Better support for odd [date parsing](https://github.com/brianc/node-pg-types/pull/8)
+
+### v3.2.0
+
+- Add support for parsing [date arrays](https://github.com/brianc/node-pg-types/pull/3)
+- Expose array parsers on [pg.types](https://github.com/brianc/node-pg-types/pull/2)
+- Allow [pool](https://github.com/brianc/node-postgres/pull/591) to be configured
+
+### v3.1.0
+
+- Add [count of the number of times a client has been checked out from the pool](https://github.com/brianc/node-postgres/pull/556)
+- Emit `end` from `pg` object [when a pool is drained](https://github.com/brianc/node-postgres/pull/571)
+
+### v3.0.0
+
+#### Breaking changes
+
+- [Parse the DATE PostgreSQL type as local time](https://github.com/brianc/node-postgres/pull/514)
+
+After [some discussion](https://github.com/brianc/node-postgres/issues/510) it was decided node-postgres was non-compliant in how it was handling DATE results. They were being converted to UTC, but the PostgreSQL documentation specifies they should be returned in the client timezone. This is a breaking change, and if you use the `date` type you might want to examine your code and make sure nothing is impacted.
+
+- [Fix possible numeric precision loss on numeric & int8 arrays](https://github.com/brianc/node-postgres/pull/501)
+
+pg@v2.0 included changes to not convert large integers into their JavaScript number representation because of possibility for numeric precision loss. The same types in arrays were not taken into account. This fix applies the same type of type-coercion rules to arrays of those types, so there will be no more possible numeric loss on an array of very large int8s for example. This is a breaking change because now a return type from a query of `int8[]` will contain _string_ representations
+of the integers. Use your favorite JavaScript bignum module to represent them without precision loss, or punch over the type converter to return the old style arrays again.
+
+- [Fix to input array of dates being improperly converted to utc](https://github.com/benesch/node-postgres/commit/c41eedc3e01e5527a3d5c242fa1896f02ef0b261#diff-7172adb1fec2457a2700ed29008a8e0aR108)
+
+Single `date` parameters were properly sent to the PostgreSQL server properly in local time, but an input array of dates was being changed into utc dates. This is a violation of what PostgreSQL expects. Small breaking change, but none-the-less something you should check out if you are inserting an array of dates.
+
+- [Query no longer emits `end` event if it ends due to an error](https://github.com/brianc/node-postgres/commit/357b64d70431ec5ca721eb45a63b082c18e6ffa3)
+
+This is a small change to bring the semantics of query more in line with other EventEmitters. The tests all passed after this change, but I suppose it could still be a breaking change in certain use cases. If you are doing clever things with the `end` and `error` events of a query object you might want to check to make sure its still behaving normally, though it is most likely not an issue.
+
+#### New features
+
+- [Supercharge `prepareValue`](https://github.com/brianc/node-postgres/pull/555)
+
+The long & short of it is now any object you supply in the list of query values will be inspected for a `.toPostgres` method. If the method is present it will be called and its result used as the raw text value sent to PostgreSQL for that value. This allows the same type of custom type coercion on query parameters as was previously afforded to query result values.
+
+- [Domain aware connection pool](https://github.com/brianc/node-postgres/pull/531)
+
+If domains are active node-postgres will honor them and do everything it can to ensure all callbacks are properly fired in the active domain. If you have tried to use domains with node-postgres (or many other modules which pool long lived event emitters) you may have run into an issue where the active domain changes before and after a callback. This has been a longstanding footgun within node-postgres and I am happy to get it fixed.
+
+- [Disconnected clients now removed from pool](https://github.com/brianc/node-postgres/pull/543)
+
+Avoids a scenario where your pool could fill up with disconnected & unusable clients.
+
+- [Break type parsing code into separate module](https://github.com/brianc/node-postgres/pull/541)
+
+To provide better documentation and a clearer explanation of how to override the query result parsing system we broke the type converters [into their own module](https://github.com/brianc/node-pg-types). There is still work around removing the 'global-ness' of the type converters so each query or connection can return types differently, but this is a good first step and allow a lot more obvious way to return int8 results as JavaScript numbers, for example
+
+### v2.11.0
+
+- Add support for [application_name](https://github.com/brianc/node-postgres/pull/497)
+
+### v2.10.0
+
+- Add support for [the password file](http://www.postgresql.org/docs/9.3/static/libpq-pgpass.html)
+
+### v2.9.0
+
+- Add better support for [unix domain socket](https://github.com/brianc/node-postgres/pull/487) connections
+
+### v2.8.0
+
+- Add support for parsing JSON[] and UUID[] result types
+
+### v2.7.0
+
+- Use single row mode in native bindings when available [@rpedela]
+  - reduces memory consumption when handling row values in 'row' event
+- Automatically bind buffer type parameters as binary [@eugeneware]
+
+### v2.6.0
+
+- Respect PGSSLMODE environment variable
+
+### v2.5.0
+
+- Ability to opt-in to int8 parsing via `pg.defaults.parseInt8 = true`
+
+### v2.4.0
+
+- Use eval in the result set parser to increase performance
+
+### v2.3.0
+
+- Remove built-in support for binary Int64 parsing.
+  _Due to the low usage & required compiled dependency this will be pushed into a 3rd party add-on_
+
+### v2.2.0
+
+- [Add support for excapeLiteral and escapeIdentifier in both JavaScript and the native bindings](https://github.com/brianc/node-postgres/pull/396)
+
+### v2.1.0
+
+- Add support for SSL connections in JavaScript driver
+- this means you can connect to heroku postgres from your local machine without the native bindings!
+- [Add field metadata to result object](https://github.com/brianc/node-postgres/blob/master/test/integration/client/row-description-on-results-tests.js)
+- [Add ability for rows to be returned as arrays instead of objects](https://github.com/brianc/node-postgres/blob/master/test/integration/client/results-as-array-tests.js)
+
+### v2.0.0
+
+- Properly handle various PostgreSQL to JavaScript type conversions to avoid data loss:
+
+```
+PostgreSQL | pg@v2.0 JavaScript | pg@v1.0 JavaScript
+--------------------------------|----------------
+float4     | number (float)     | string
+float8     | number (float)     | string
+int8       | string             | number (int)
+numeric    | string             | number (float)
+decimal    | string             | number (float)
+```
+
+For more information see https://github.com/brianc/node-postgres/pull/353
+If you are unhappy with these changes you can always [override the built in type parsing fairly easily](https://github.com/brianc/node-pg-parse-float).
+
+### v1.3.0
+
+- Make client_encoding configurable and optional
+
+### v1.2.0
+
+- return field metadata on result object: access via result.fields[i].name/dataTypeID
+
+### v1.1.0
+
+- built in support for `JSON` data type for PostgreSQL Server @ v9.2.0 or greater
+
+### v1.0.0
+
+- remove deprecated functionality
+  - Callback function passed to `pg.connect` now **requires** 3 arguments
+  - Client#pauseDrain() / Client#resumeDrain removed
+  - numeric, decimal, and float data types no longer parsed into float before being returned. Will be returned from query results as `String`
+
+### v0.15.0
+
+- client now emits `end` when disconnected from back-end server
+- if client is disconnected in the middle of a query, query receives an error
+
+### v0.14.0
+
+- add deprecation warnings in prep for v1.0
+- fix read/write failures in native module under node v0.9.x
diff --git a/server/node_modules/pg/LICENSE b/server/node_modules/pg/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..389a2783c14a3f00e1d2f6e9634c8c5bfc0bdb34
--- /dev/null
+++ b/server/node_modules/pg/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2010 - 2019 Brian Carlson
+
+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.
diff --git a/server/node_modules/pg/Makefile b/server/node_modules/pg/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..52d0545d389b5e556d75a0e3f53a417dd4689591
--- /dev/null
+++ b/server/node_modules/pg/Makefile
@@ -0,0 +1,67 @@
+SHELL := /bin/sh
+
+connectionString=postgres://
+
+params := $(connectionString)
+
+node-command := xargs -n 1 -I file node file $(params)
+
+.PHONY : test test-connection test-integration bench test-native \
+	 lint publish test-missing-native update-npm
+
+all:
+	npm install
+
+help:
+	@echo "make test-all [connectionString=postgres://<your connection string>]"
+
+test: test-unit
+
+test-all: lint test-missing-native test-unit test-integration test-native
+
+
+update-npm:
+	@npm i npm --global
+
+bench:
+	@find benchmark -name "*-bench.js" | $(node-command)
+
+test-unit:
+	@find test/unit -name "*-tests.js" | $(node-command)
+
+test-connection:
+	@echo "***Testing connection***"
+	@node script/create-test-tables.js $(params)
+
+test-missing-native:
+	@echo "***Testing optional native install***"
+	@rm -rf node_modules/pg-native
+	@rm -rf node_modules/libpq
+	@node test/native/missing-native.js
+	@rm -rf node_modules/pg-native
+	@rm -rf node_modules/libpq
+
+node_modules/pg-native/index.js:
+	@npm i --no-save pg-native
+
+test-native: node_modules/pg-native/index.js test-connection
+	@echo "***Testing native bindings***"
+	@find test/native -name "*-tests.js" | $(node-command)
+	@find test/integration -name "*-tests.js" | $(node-command) native
+
+test-integration: test-connection
+	@echo "***Testing Pure Javascript***"
+	@find test/integration -name "*-tests.js" | $(node-command)
+
+test-binary: test-connection
+	@echo "***Testing Pure Javascript (binary)***"
+	@find test/integration -name "*-tests.js" | $(node-command) binary
+
+test-pool:
+	@find test/integration/connection-pool -name "*.js" | $(node-command) binary
+
+lint:
+	@echo "***Starting lint***"
+	node -e "process.exit(Number(process.versions.node.split('.')[0]) < 8 ? 0 : 1)" \
+	  && echo "***Skipping lint (node version too old)***" \
+	  || node_modules/.bin/eslint lib
diff --git a/server/node_modules/pg/README.md b/server/node_modules/pg/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..60cef5306dab6f5e8320cf2c57b5ac4b4d366f5e
--- /dev/null
+++ b/server/node_modules/pg/README.md
@@ -0,0 +1,88 @@
+# node-postgres
+
+[![Build Status](https://secure.travis-ci.org/brianc/node-postgres.svg?branch=master)](http://travis-ci.org/brianc/node-postgres)
+[![Dependency Status](https://david-dm.org/brianc/node-postgres.svg)](https://david-dm.org/brianc/node-postgres)
+<span class="badge-npmversion"><a href="https://npmjs.org/package/pg" title="View this project on NPM"><img src="https://img.shields.io/npm/v/pg.svg" alt="NPM version" /></a></span>
+<span class="badge-npmdownloads"><a href="https://npmjs.org/package/pg" title="View this project on NPM"><img src="https://img.shields.io/npm/dm/pg.svg" alt="NPM downloads" /></a></span>
+
+Non-blocking PostgreSQL client for Node.js.  Pure JavaScript and optional native libpq bindings.
+
+## Install
+
+```sh
+$ npm install pg
+```
+
+---
+## :star: [Documentation](https://node-postgres.com) :star:
+
+
+### Features
+
+* Pure JavaScript client and native libpq bindings share _the same API_
+* Connection pooling
+* Extensible JS<->PostgreSQL data-type coercion
+* Supported PostgreSQL features
+  * Parameterized queries
+  * Named statements with query plan caching
+  * Async notifications with `LISTEN/NOTIFY`
+  * Bulk import & export with `COPY TO/COPY FROM`
+
+### Extras
+
+node-postgres is by design pretty light on abstractions.  These are some handy modules we've been using over the years to complete the picture.
+The entire list can be found on our [wiki](https://github.com/brianc/node-postgres/wiki/Extras).
+
+## Support
+
+node-postgres is free software.  If you encounter a bug with the library please open an issue on the [GitHub repo](https://github.com/brianc/node-postgres). If you have questions unanswered by the documentation please open an issue pointing out how the documentation was unclear & I will do my best to make it better!
+
+When you open an issue please provide:
+- version of Node
+- version of Postgres
+- smallest possible snippet of code to reproduce the problem
+
+You can also follow me [@briancarlson](https://twitter.com/briancarlson) if that's your thing. I try to always announce noteworthy changes & developments with node-postgres on Twitter.
+
+### Professional Support
+
+I offer professional support for node-postgres.  I provide implementation, training, and many years of expertise on how to build applications with Node, Express, PostgreSQL, and React/Redux.  Please contact me at [brian.m.carlson@gmail.com](mailto:brian.m.carlson@gmail.com) to discuss how I can help your company be more successful!
+
+### Sponsorship :star:
+
+If you are benefiting from node-postgres and would like to help keep the project financially sustainable please visit Brian Carlson's [Patreon page](https://www.patreon.com/node_postgres).
+
+## Contributing
+
+__:heart: contributions!__
+
+I will __happily__ accept your pull request if it:
+- __has tests__
+- looks reasonable
+- does not break backwards compatibility
+
+## Troubleshooting and FAQ
+
+The causes and solutions to common errors can be found among the [Frequently Asked Questions (FAQ)](https://github.com/brianc/node-postgres/wiki/FAQ)
+
+## License
+
+Copyright (c) 2010-2019 Brian Carlson (brian.m.carlson@gmail.com)
+
+ 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.
diff --git a/server/node_modules/pg/SPONSORS.md b/server/node_modules/pg/SPONSORS.md
new file mode 100644
index 0000000000000000000000000000000000000000..29aae9e02701245b7d685e5bdbfc83d19420e6b0
--- /dev/null
+++ b/server/node_modules/pg/SPONSORS.md
@@ -0,0 +1,25 @@
+node-postgres is made possible by the helpful contributors from the community well as the following generous supporters on [Patreon](https://www.patreon.com/node_postgres).
+
+# Leaders
+
+- [MadKudu](https://www.madkudu.com) - [@madkudu](https://twitter.com/madkudu)
+- [Third Iron](https://thirdiron.com/)
+- [Timescale](https://timescale.com)
+
+# Supporters
+
+- John Fawcett
+- Lalit Kapoor [@lalitkapoor](https://twitter.com/lalitkapoor)
+- Paul Frazee [@pfrazee](https://twitter.com/pfrazee)
+- Rein Petersen
+- Arnaud Benhamdine [@abenhamdine](https://twitter.com/abenhamdine)
+- Matthew Welke
+- Matthew Weber
+- Andrea De Simon
+- Todd Kennedy
+- Alexander Robson
+- Benjie Gillam
+- David Hanson
+- Franklin Davenport
+- [Eventbot](https://geteventbot.com/)
+- Chuck T
diff --git a/server/node_modules/pg/lib/client.js b/server/node_modules/pg/lib/client.js
new file mode 100644
index 0000000000000000000000000000000000000000..cca5e66e8c8dfdfaaa150b98a9159b36a1d50ce5
--- /dev/null
+++ b/server/node_modules/pg/lib/client.js
@@ -0,0 +1,561 @@
+'use strict'
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var EventEmitter = require('events').EventEmitter
+var util = require('util')
+var utils = require('./utils')
+var sasl = require('./sasl')
+var pgPass = require('pgpass')
+var TypeOverrides = require('./type-overrides')
+
+var ConnectionParameters = require('./connection-parameters')
+var Query = require('./query')
+var defaults = require('./defaults')
+var Connection = require('./connection')
+
+var Client = function (config) {
+  EventEmitter.call(this)
+
+  this.connectionParameters = new ConnectionParameters(config)
+  this.user = this.connectionParameters.user
+  this.database = this.connectionParameters.database
+  this.port = this.connectionParameters.port
+  this.host = this.connectionParameters.host
+  this.password = this.connectionParameters.password
+  this.replication = this.connectionParameters.replication
+
+  var c = config || {}
+
+  this._Promise = c.Promise || global.Promise
+  this._types = new TypeOverrides(c.types)
+  this._ending = false
+  this._connecting = false
+  this._connected = false
+  this._connectionError = false
+  this._queryable = true
+
+  this.connection = c.connection || new Connection({
+    stream: c.stream,
+    ssl: this.connectionParameters.ssl,
+    keepAlive: c.keepAlive || false,
+    keepAliveInitialDelayMillis: c.keepAliveInitialDelayMillis || 0,
+    encoding: this.connectionParameters.client_encoding || 'utf8'
+  })
+  this.queryQueue = []
+  this.binary = c.binary || defaults.binary
+  this.processID = null
+  this.secretKey = null
+  this.ssl = this.connectionParameters.ssl || false
+  this._connectionTimeoutMillis = c.connectionTimeoutMillis || 0
+}
+
+util.inherits(Client, EventEmitter)
+
+Client.prototype._errorAllQueries = function (err) {
+  const enqueueError = (query) => {
+    process.nextTick(() => {
+      query.handleError(err, this.connection)
+    })
+  }
+
+  if (this.activeQuery) {
+    enqueueError(this.activeQuery)
+    this.activeQuery = null
+  }
+
+  this.queryQueue.forEach(enqueueError)
+  this.queryQueue.length = 0
+}
+
+Client.prototype._connect = function (callback) {
+  var self = this
+  var con = this.connection
+  if (this._connecting || this._connected) {
+    const err = new Error('Client has already been connected. You cannot reuse a client.')
+    process.nextTick(() => {
+      callback(err)
+    })
+    return
+  }
+  this._connecting = true
+
+  var connectionTimeoutHandle
+  if (this._connectionTimeoutMillis > 0) {
+    connectionTimeoutHandle = setTimeout(() => {
+      con._ending = true
+      con.stream.destroy(new Error('timeout expired'))
+    }, this._connectionTimeoutMillis)
+  }
+
+  if (this.host && this.host.indexOf('/') === 0) {
+    con.connect(this.host + '/.s.PGSQL.' + this.port)
+  } else {
+    con.connect(this.port, this.host)
+  }
+
+  // once connection is established send startup message
+  con.on('connect', function () {
+    if (self.ssl) {
+      con.requestSsl()
+    } else {
+      con.startup(self.getStartupConf())
+    }
+  })
+
+  con.on('sslconnect', function () {
+    con.startup(self.getStartupConf())
+  })
+
+  function checkPgPass (cb) {
+    return function (msg) {
+      if (typeof self.password === 'function') {
+        self._Promise.resolve()
+          .then(() => self.password())
+          .then(pass => {
+            if (pass !== undefined) {
+              if (typeof pass !== 'string') {
+                con.emit('error', new TypeError('Password must be a string'))
+                return
+              }
+              self.connectionParameters.password = self.password = pass
+            } else {
+              self.connectionParameters.password = self.password = null
+            }
+            cb(msg)
+          }).catch(err => {
+            con.emit('error', err)
+          })
+      } else if (self.password !== null) {
+        cb(msg)
+      } else {
+        pgPass(self.connectionParameters, function (pass) {
+          if (undefined !== pass) {
+            self.connectionParameters.password = self.password = pass
+          }
+          cb(msg)
+        })
+      }
+    }
+  }
+
+  // password request handling
+  con.on('authenticationCleartextPassword', checkPgPass(function () {
+    con.password(self.password)
+  }))
+
+  // password request handling
+  con.on('authenticationMD5Password', checkPgPass(function (msg) {
+    con.password(utils.postgresMd5PasswordHash(self.user, self.password, msg.salt))
+  }))
+
+  // password request handling (SASL)
+  var saslSession
+  con.on('authenticationSASL', checkPgPass(function (msg) {
+    saslSession = sasl.startSession(msg.mechanisms)
+
+    con.sendSASLInitialResponseMessage(saslSession.mechanism, saslSession.response)
+  }))
+
+  // password request handling (SASL)
+  con.on('authenticationSASLContinue', function (msg) {
+    sasl.continueSession(saslSession, self.password, msg.data)
+
+    con.sendSCRAMClientFinalMessage(saslSession.response)
+  })
+
+  // password request handling (SASL)
+  con.on('authenticationSASLFinal', function (msg) {
+    sasl.finalizeSession(saslSession, msg.data)
+
+    saslSession = null
+  })
+
+  con.once('backendKeyData', function (msg) {
+    self.processID = msg.processID
+    self.secretKey = msg.secretKey
+  })
+
+  const connectingErrorHandler = (err) => {
+    if (this._connectionError) {
+      return
+    }
+    this._connectionError = true
+    clearTimeout(connectionTimeoutHandle)
+    if (callback) {
+      return callback(err)
+    }
+    this.emit('error', err)
+  }
+
+  const connectedErrorHandler = (err) => {
+    this._queryable = false
+    this._errorAllQueries(err)
+    this.emit('error', err)
+  }
+
+  const connectedErrorMessageHandler = (msg) => {
+    const activeQuery = this.activeQuery
+
+    if (!activeQuery) {
+      connectedErrorHandler(msg)
+      return
+    }
+
+    this.activeQuery = null
+    activeQuery.handleError(msg, con)
+  }
+
+  con.on('error', connectingErrorHandler)
+  con.on('errorMessage', connectingErrorHandler)
+
+  // hook up query handling events to connection
+  // after the connection initially becomes ready for queries
+  con.once('readyForQuery', function () {
+    self._connecting = false
+    self._connected = true
+    self._attachListeners(con)
+    con.removeListener('error', connectingErrorHandler)
+    con.removeListener('errorMessage', connectingErrorHandler)
+    con.on('error', connectedErrorHandler)
+    con.on('errorMessage', connectedErrorMessageHandler)
+    clearTimeout(connectionTimeoutHandle)
+
+    // process possible callback argument to Client#connect
+    if (callback) {
+      callback(null, self)
+      // remove callback for proper error handling
+      // after the connect event
+      callback = null
+    }
+    self.emit('connect')
+  })
+
+  con.on('readyForQuery', function () {
+    var activeQuery = self.activeQuery
+    self.activeQuery = null
+    self.readyForQuery = true
+    if (activeQuery) {
+      activeQuery.handleReadyForQuery(con)
+    }
+    self._pulseQueryQueue()
+  })
+
+  con.once('end', () => {
+    const error = this._ending
+      ? new Error('Connection terminated')
+      : new Error('Connection terminated unexpectedly')
+
+    this._errorAllQueries(error)
+
+    if (!this._ending) {
+      // if the connection is ended without us calling .end()
+      // on this client then we have an unexpected disconnection
+      // treat this as an error unless we've already emitted an error
+      // during connection.
+      if (this._connecting && !this._connectionError) {
+        if (callback) {
+          callback(error)
+        } else {
+          connectedErrorHandler(error)
+        }
+      } else if (!this._connectionError) {
+        connectedErrorHandler(error)
+      }
+    }
+
+    process.nextTick(() => {
+      this.emit('end')
+    })
+  })
+
+  con.on('notice', function (msg) {
+    self.emit('notice', msg)
+  })
+}
+
+Client.prototype.connect = function (callback) {
+  if (callback) {
+    this._connect(callback)
+    return
+  }
+
+  return new this._Promise((resolve, reject) => {
+    this._connect((error) => {
+      if (error) {
+        reject(error)
+      } else {
+        resolve()
+      }
+    })
+  })
+}
+
+Client.prototype._attachListeners = function (con) {
+  const self = this
+  // delegate rowDescription to active query
+  con.on('rowDescription', function (msg) {
+    self.activeQuery.handleRowDescription(msg)
+  })
+
+  // delegate dataRow to active query
+  con.on('dataRow', function (msg) {
+    self.activeQuery.handleDataRow(msg)
+  })
+
+  // delegate portalSuspended to active query
+  // eslint-disable-next-line no-unused-vars
+  con.on('portalSuspended', function (msg) {
+    self.activeQuery.handlePortalSuspended(con)
+  })
+
+  // delegate emptyQuery to active query
+  // eslint-disable-next-line no-unused-vars
+  con.on('emptyQuery', function (msg) {
+    self.activeQuery.handleEmptyQuery(con)
+  })
+
+  // delegate commandComplete to active query
+  con.on('commandComplete', function (msg) {
+    self.activeQuery.handleCommandComplete(msg, con)
+  })
+
+  // if a prepared statement has a name and properly parses
+  // we track that its already been executed so we don't parse
+  // it again on the same client
+  // eslint-disable-next-line no-unused-vars
+  con.on('parseComplete', function (msg) {
+    if (self.activeQuery.name) {
+      con.parsedStatements[self.activeQuery.name] = self.activeQuery.text
+    }
+  })
+
+  // eslint-disable-next-line no-unused-vars
+  con.on('copyInResponse', function (msg) {
+    self.activeQuery.handleCopyInResponse(self.connection)
+  })
+
+  con.on('copyData', function (msg) {
+    self.activeQuery.handleCopyData(msg, self.connection)
+  })
+
+  con.on('notification', function (msg) {
+    self.emit('notification', msg)
+  })
+}
+
+Client.prototype.getStartupConf = function () {
+  var params = this.connectionParameters
+
+  var data = {
+    user: params.user,
+    database: params.database
+  }
+
+  var appName = params.application_name || params.fallback_application_name
+  if (appName) {
+    data.application_name = appName
+  }
+  if (params.replication) {
+    data.replication = '' + params.replication
+  }
+  if (params.statement_timeout) {
+    data.statement_timeout = String(parseInt(params.statement_timeout, 10))
+  }
+
+  return data
+}
+
+Client.prototype.cancel = function (client, query) {
+  if (client.activeQuery === query) {
+    var con = this.connection
+
+    if (this.host && this.host.indexOf('/') === 0) {
+      con.connect(this.host + '/.s.PGSQL.' + this.port)
+    } else {
+      con.connect(this.port, this.host)
+    }
+
+    // once connection is established send cancel message
+    con.on('connect', function () {
+      con.cancel(client.processID, client.secretKey)
+    })
+  } else if (client.queryQueue.indexOf(query) !== -1) {
+    client.queryQueue.splice(client.queryQueue.indexOf(query), 1)
+  }
+}
+
+Client.prototype.setTypeParser = function (oid, format, parseFn) {
+  return this._types.setTypeParser(oid, format, parseFn)
+}
+
+Client.prototype.getTypeParser = function (oid, format) {
+  return this._types.getTypeParser(oid, format)
+}
+
+// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
+Client.prototype.escapeIdentifier = function (str) {
+  return '"' + str.replace(/"/g, '""') + '"'
+}
+
+// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
+Client.prototype.escapeLiteral = function (str) {
+  var hasBackslash = false
+  var escaped = '\''
+
+  for (var i = 0; i < str.length; i++) {
+    var c = str[i]
+    if (c === '\'') {
+      escaped += c + c
+    } else if (c === '\\') {
+      escaped += c + c
+      hasBackslash = true
+    } else {
+      escaped += c
+    }
+  }
+
+  escaped += '\''
+
+  if (hasBackslash === true) {
+    escaped = ' E' + escaped
+  }
+
+  return escaped
+}
+
+Client.prototype._pulseQueryQueue = function () {
+  if (this.readyForQuery === true) {
+    this.activeQuery = this.queryQueue.shift()
+    if (this.activeQuery) {
+      this.readyForQuery = false
+      this.hasExecuted = true
+
+      const queryError = this.activeQuery.submit(this.connection)
+      if (queryError) {
+        process.nextTick(() => {
+          this.activeQuery.handleError(queryError, this.connection)
+          this.readyForQuery = true
+          this._pulseQueryQueue()
+        })
+      }
+    } else if (this.hasExecuted) {
+      this.activeQuery = null
+      this.emit('drain')
+    }
+  }
+}
+
+Client.prototype.query = function (config, values, callback) {
+  // can take in strings, config object or query object
+  var query
+  var result
+  var readTimeout
+  var readTimeoutTimer
+  var queryCallback
+
+  if (config === null || config === undefined) {
+    throw new TypeError('Client was passed a null or undefined query')
+  } else if (typeof config.submit === 'function') {
+    readTimeout = config.query_timeout || this.connectionParameters.query_timeout
+    result = query = config
+    if (typeof values === 'function') {
+      query.callback = query.callback || values
+    }
+  } else {
+    readTimeout = this.connectionParameters.query_timeout
+    query = new Query(config, values, callback)
+    if (!query.callback) {
+      result = new this._Promise((resolve, reject) => {
+        query.callback = (err, res) => err ? reject(err) : resolve(res)
+      })
+    }
+  }
+
+  if (readTimeout) {
+    queryCallback = query.callback
+
+    readTimeoutTimer = setTimeout(() => {
+      var error = new Error('Query read timeout')
+
+      process.nextTick(() => {
+        query.handleError(error, this.connection)
+      })
+
+      queryCallback(error)
+
+      // we already returned an error,
+      // just do nothing if query completes
+      query.callback = () => {}
+
+      // Remove from queue
+      var index = this.queryQueue.indexOf(query)
+      if (index > -1) {
+        this.queryQueue.splice(index, 1)
+      }
+
+      this._pulseQueryQueue()
+    }, readTimeout)
+
+    query.callback = (err, res) => {
+      clearTimeout(readTimeoutTimer)
+      queryCallback(err, res)
+    }
+  }
+
+  if (this.binary && !query.binary) {
+    query.binary = true
+  }
+
+  if (query._result && !query._result._types) {
+    query._result._types = this._types
+  }
+
+  if (!this._queryable) {
+    process.nextTick(() => {
+      query.handleError(new Error('Client has encountered a connection error and is not queryable'), this.connection)
+    })
+    return result
+  }
+
+  if (this._ending) {
+    process.nextTick(() => {
+      query.handleError(new Error('Client was closed and is not queryable'), this.connection)
+    })
+    return result
+  }
+
+  this.queryQueue.push(query)
+  this._pulseQueryQueue()
+  return result
+}
+
+Client.prototype.end = function (cb) {
+  this._ending = true
+
+  if (this.activeQuery) {
+    // if we have an active query we need to force a disconnect
+    // on the socket - otherwise a hung query could block end forever
+    this.connection.stream.destroy()
+  } else {
+    this.connection.end()
+  }
+
+  if (cb) {
+    this.connection.once('end', cb)
+  } else {
+    return new this._Promise((resolve) => {
+      this.connection.once('end', resolve)
+    })
+  }
+}
+
+// expose a Query constructor
+Client.Query = Query
+
+module.exports = Client
diff --git a/server/node_modules/pg/lib/connection-parameters.js b/server/node_modules/pg/lib/connection-parameters.js
new file mode 100644
index 0000000000000000000000000000000000000000..00ea76111accd00748f5e79cc00d754ceb3df3f3
--- /dev/null
+++ b/server/node_modules/pg/lib/connection-parameters.js
@@ -0,0 +1,137 @@
+'use strict'
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var dns = require('dns')
+
+var defaults = require('./defaults')
+
+var parse = require('pg-connection-string').parse // parses a connection string
+
+var val = function (key, config, envVar) {
+  if (envVar === undefined) {
+    envVar = process.env['PG' + key.toUpperCase()]
+  } else if (envVar === false) {
+    // do nothing ... use false
+  } else {
+    envVar = process.env[envVar]
+  }
+
+  return config[key] ||
+    envVar ||
+    defaults[key]
+}
+
+var useSsl = function () {
+  switch (process.env.PGSSLMODE) {
+    case 'disable':
+      return false
+    case 'prefer':
+    case 'require':
+    case 'verify-ca':
+    case 'verify-full':
+      return true
+  }
+  return defaults.ssl
+}
+
+var ConnectionParameters = function (config) {
+  // if a string is passed, it is a raw connection string so we parse it into a config
+  config = typeof config === 'string' ? parse(config) : config || {}
+
+  // if the config has a connectionString defined, parse IT into the config we use
+  // this will override other default values with what is stored in connectionString
+  if (config.connectionString) {
+    config = Object.assign({}, config, parse(config.connectionString))
+  }
+
+  this.user = val('user', config)
+  this.database = val('database', config)
+  this.port = parseInt(val('port', config), 10)
+  this.host = val('host', config)
+  this.password = val('password', config)
+  this.binary = val('binary', config)
+  this.ssl = typeof config.ssl === 'undefined' ? useSsl() : config.ssl
+  this.client_encoding = val('client_encoding', config)
+  this.replication = val('replication', config)
+  // a domain socket begins with '/'
+  this.isDomainSocket = (!(this.host || '').indexOf('/'))
+
+  this.application_name = val('application_name', config, 'PGAPPNAME')
+  this.fallback_application_name = val('fallback_application_name', config, false)
+  this.statement_timeout = val('statement_timeout', config, false)
+  this.query_timeout = val('query_timeout', config, false)
+
+  if (config.connectionTimeoutMillis === undefined) {
+    this.connect_timeout = process.env.PGCONNECT_TIMEOUT || 0
+  } else {
+    this.connect_timeout = Math.floor(config.connectionTimeoutMillis / 1000)
+  }
+
+  if (config.keepAlive === false) {
+    this.keepalives = 0
+  } else if (config.keepAlive === true) {
+    this.keepalives = 1
+  }
+
+  if (typeof config.keepAliveInitialDelayMillis === 'number') {
+    this.keepalives_idle = Math.floor(config.keepAliveInitialDelayMillis / 1000)
+  }
+}
+
+// Convert arg to a string, surround in single quotes, and escape single quotes and backslashes
+var quoteParamValue = function (value) {
+  return "'" + ('' + value).replace(/\\/g, '\\\\').replace(/'/g, "\\'") + "'"
+}
+
+var add = function (params, config, paramName) {
+  var value = config[paramName]
+  if (value !== undefined && value !== null) {
+    params.push(paramName + '=' + quoteParamValue(value))
+  }
+}
+
+ConnectionParameters.prototype.getLibpqConnectionString = function (cb) {
+  var params = []
+  add(params, this, 'user')
+  add(params, this, 'password')
+  add(params, this, 'port')
+  add(params, this, 'application_name')
+  add(params, this, 'fallback_application_name')
+  add(params, this, 'connect_timeout')
+
+  var ssl = typeof this.ssl === 'object' ? this.ssl : this.ssl ? { sslmode: this.ssl } : {}
+  add(params, ssl, 'sslmode')
+  add(params, ssl, 'sslca')
+  add(params, ssl, 'sslkey')
+  add(params, ssl, 'sslcert')
+  add(params, ssl, 'sslrootcert')
+
+  if (this.database) {
+    params.push('dbname=' + quoteParamValue(this.database))
+  }
+  if (this.replication) {
+    params.push('replication=' + quoteParamValue(this.replication))
+  }
+  if (this.host) {
+    params.push('host=' + quoteParamValue(this.host))
+  }
+  if (this.isDomainSocket) {
+    return cb(null, params.join(' '))
+  }
+  if (this.client_encoding) {
+    params.push('client_encoding=' + quoteParamValue(this.client_encoding))
+  }
+  dns.lookup(this.host, function (err, address) {
+    if (err) return cb(err, null)
+    params.push('hostaddr=' + quoteParamValue(address))
+    return cb(null, params.join(' '))
+  })
+}
+
+module.exports = ConnectionParameters
diff --git a/server/node_modules/pg/lib/connection.js b/server/node_modules/pg/lib/connection.js
new file mode 100644
index 0000000000000000000000000000000000000000..48d65d25fb34073b59a2578b0be2faaf88aa8177
--- /dev/null
+++ b/server/node_modules/pg/lib/connection.js
@@ -0,0 +1,705 @@
+'use strict'
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var net = require('net')
+var EventEmitter = require('events').EventEmitter
+var util = require('util')
+
+var Writer = require('buffer-writer')
+var Reader = require('packet-reader')
+
+var TEXT_MODE = 0
+var BINARY_MODE = 1
+var Connection = function (config) {
+  EventEmitter.call(this)
+  config = config || {}
+  this.stream = config.stream || new net.Socket()
+  this._keepAlive = config.keepAlive
+  this._keepAliveInitialDelayMillis = config.keepAliveInitialDelayMillis
+  this.lastBuffer = false
+  this.lastOffset = 0
+  this.buffer = null
+  this.offset = null
+  this.encoding = config.encoding || 'utf8'
+  this.parsedStatements = {}
+  this.writer = new Writer()
+  this.ssl = config.ssl || false
+  this._ending = false
+  this._mode = TEXT_MODE
+  this._emitMessage = false
+  this._reader = new Reader({
+    headerSize: 1,
+    lengthPadding: -4
+  })
+  var self = this
+  this.on('newListener', function (eventName) {
+    if (eventName === 'message') {
+      self._emitMessage = true
+    }
+  })
+}
+
+util.inherits(Connection, EventEmitter)
+
+Connection.prototype.connect = function (port, host) {
+  var self = this
+
+  if (this.stream.readyState === 'closed') {
+    this.stream.connect(port, host)
+  } else if (this.stream.readyState === 'open') {
+    this.emit('connect')
+  }
+
+  this.stream.on('connect', function () {
+    if (self._keepAlive) {
+      self.stream.setKeepAlive(true, self._keepAliveInitialDelayMillis)
+    }
+    self.emit('connect')
+  })
+
+  const reportStreamError = function (error) {
+    // don't raise ECONNRESET errors - they can & should be ignored
+    // during disconnect
+    if (self._ending && error.code === 'ECONNRESET') {
+      return
+    }
+    self.emit('error', error)
+  }
+  this.stream.on('error', reportStreamError)
+
+  this.stream.on('close', function () {
+    self.emit('end')
+  })
+
+  if (!this.ssl) {
+    return this.attachListeners(this.stream)
+  }
+
+  this.stream.once('data', function (buffer) {
+    var responseCode = buffer.toString('utf8')
+    switch (responseCode) {
+      case 'N': // Server does not support SSL connections
+        return self.emit('error', new Error('The server does not support SSL connections'))
+      case 'S': // Server supports SSL connections, continue with a secure connection
+        break
+      default: // Any other response byte, including 'E' (ErrorResponse) indicating a server error
+        return self.emit('error', new Error('There was an error establishing an SSL connection'))
+    }
+    var tls = require('tls')
+    self.stream = tls.connect({
+      socket: self.stream,
+      servername: host,
+      checkServerIdentity: self.ssl.checkServerIdentity || tls.checkServerIdentity,
+      rejectUnauthorized: self.ssl.rejectUnauthorized,
+      ca: self.ssl.ca,
+      pfx: self.ssl.pfx,
+      key: self.ssl.key,
+      passphrase: self.ssl.passphrase,
+      cert: self.ssl.cert,
+      secureOptions: self.ssl.secureOptions,
+      NPNProtocols: self.ssl.NPNProtocols
+    })
+    self.attachListeners(self.stream)
+    self.stream.on('error', reportStreamError)
+
+    self.emit('sslconnect')
+  })
+}
+
+Connection.prototype.attachListeners = function (stream) {
+  var self = this
+  stream.on('data', function (buff) {
+    self._reader.addChunk(buff)
+    var packet = self._reader.read()
+    while (packet) {
+      var msg = self.parseMessage(packet)
+      var eventName = msg.name === 'error' ? 'errorMessage' : msg.name
+      if (self._emitMessage) {
+        self.emit('message', msg)
+      }
+      self.emit(eventName, msg)
+      packet = self._reader.read()
+    }
+  })
+  stream.on('end', function () {
+    self.emit('end')
+  })
+}
+
+Connection.prototype.requestSsl = function () {
+  var bodyBuffer = this.writer
+    .addInt16(0x04D2)
+    .addInt16(0x162F).flush()
+
+  var length = bodyBuffer.length + 4
+
+  var buffer = new Writer()
+    .addInt32(length)
+    .add(bodyBuffer)
+    .join()
+  this.stream.write(buffer)
+}
+
+Connection.prototype.startup = function (config) {
+  var writer = this.writer
+    .addInt16(3)
+    .addInt16(0)
+
+  Object.keys(config).forEach(function (key) {
+    var val = config[key]
+    writer.addCString(key).addCString(val)
+  })
+
+  writer.addCString('client_encoding').addCString("'utf-8'")
+
+  var bodyBuffer = writer.addCString('').flush()
+  // this message is sent without a code
+
+  var length = bodyBuffer.length + 4
+
+  var buffer = new Writer()
+    .addInt32(length)
+    .add(bodyBuffer)
+    .join()
+  this.stream.write(buffer)
+}
+
+Connection.prototype.cancel = function (processID, secretKey) {
+  var bodyBuffer = this.writer
+    .addInt16(1234)
+    .addInt16(5678)
+    .addInt32(processID)
+    .addInt32(secretKey)
+    .flush()
+
+  var length = bodyBuffer.length + 4
+
+  var buffer = new Writer()
+    .addInt32(length)
+    .add(bodyBuffer)
+    .join()
+  this.stream.write(buffer)
+}
+
+Connection.prototype.password = function (password) {
+  // 0x70 = 'p'
+  this._send(0x70, this.writer.addCString(password))
+}
+
+Connection.prototype.sendSASLInitialResponseMessage = function (mechanism, initialResponse) {
+  // 0x70 = 'p'
+  this.writer
+    .addCString(mechanism)
+    .addInt32(Buffer.byteLength(initialResponse))
+    .addString(initialResponse)
+
+  this._send(0x70)
+}
+
+Connection.prototype.sendSCRAMClientFinalMessage = function (additionalData) {
+  // 0x70 = 'p'
+  this.writer
+    .addString(additionalData)
+
+  this._send(0x70)
+}
+
+Connection.prototype._send = function (code, more) {
+  if (!this.stream.writable) {
+    return false
+  }
+  if (more === true) {
+    this.writer.addHeader(code)
+  } else {
+    return this.stream.write(this.writer.flush(code))
+  }
+}
+
+Connection.prototype.query = function (text) {
+  // 0x51 = Q
+  this.stream.write(this.writer.addCString(text).flush(0x51))
+}
+
+// send parse message
+// "more" === true to buffer the message until flush() is called
+Connection.prototype.parse = function (query, more) {
+  // expect something like this:
+  // { name: 'queryName',
+  //   text: 'select * from blah',
+  //   types: ['int8', 'bool'] }
+
+  // normalize missing query names to allow for null
+  query.name = query.name || ''
+  if (query.name.length > 63) {
+    /* eslint-disable no-console */
+    console.error('Warning! Postgres only supports 63 characters for query names.')
+    console.error('You supplied %s (%s)', query.name, query.name.length)
+    console.error('This can cause conflicts and silent errors executing queries')
+    /* eslint-enable no-console */
+  }
+  // normalize null type array
+  query.types = query.types || []
+  var len = query.types.length
+  var buffer = this.writer
+    .addCString(query.name) // name of query
+    .addCString(query.text) // actual query text
+    .addInt16(len)
+  for (var i = 0; i < len; i++) {
+    buffer.addInt32(query.types[i])
+  }
+
+  var code = 0x50
+  this._send(code, more)
+}
+
+// send bind message
+// "more" === true to buffer the message until flush() is called
+Connection.prototype.bind = function (config, more) {
+  // normalize config
+  config = config || {}
+  config.portal = config.portal || ''
+  config.statement = config.statement || ''
+  config.binary = config.binary || false
+  var values = config.values || []
+  var len = values.length
+  var useBinary = false
+  for (var j = 0; j < len; j++) { useBinary |= values[j] instanceof Buffer }
+  var buffer = this.writer
+    .addCString(config.portal)
+    .addCString(config.statement)
+  if (!useBinary) { buffer.addInt16(0) } else {
+    buffer.addInt16(len)
+    for (j = 0; j < len; j++) { buffer.addInt16(values[j] instanceof Buffer) }
+  }
+  buffer.addInt16(len)
+  for (var i = 0; i < len; i++) {
+    var val = values[i]
+    if (val === null || typeof val === 'undefined') {
+      buffer.addInt32(-1)
+    } else if (val instanceof Buffer) {
+      buffer.addInt32(val.length)
+      buffer.add(val)
+    } else {
+      buffer.addInt32(Buffer.byteLength(val))
+      buffer.addString(val)
+    }
+  }
+
+  if (config.binary) {
+    buffer.addInt16(1) // format codes to use binary
+    buffer.addInt16(1)
+  } else {
+    buffer.addInt16(0) // format codes to use text
+  }
+  // 0x42 = 'B'
+  this._send(0x42, more)
+}
+
+// send execute message
+// "more" === true to buffer the message until flush() is called
+Connection.prototype.execute = function (config, more) {
+  config = config || {}
+  config.portal = config.portal || ''
+  config.rows = config.rows || ''
+  this.writer
+    .addCString(config.portal)
+    .addInt32(config.rows)
+
+  // 0x45 = 'E'
+  this._send(0x45, more)
+}
+
+var emptyBuffer = Buffer.alloc(0)
+
+Connection.prototype.flush = function () {
+  // 0x48 = 'H'
+  this.writer.add(emptyBuffer)
+  this._send(0x48)
+}
+
+Connection.prototype.sync = function () {
+  // clear out any pending data in the writer
+  this.writer.flush(0)
+
+  this.writer.add(emptyBuffer)
+  this._ending = true
+  this._send(0x53)
+}
+
+const END_BUFFER = Buffer.from([0x58, 0x00, 0x00, 0x00, 0x04])
+
+Connection.prototype.end = function () {
+  // 0x58 = 'X'
+  this.writer.add(emptyBuffer)
+  this._ending = true
+  return this.stream.write(END_BUFFER, () => {
+    this.stream.end()
+  })
+}
+
+Connection.prototype.close = function (msg, more) {
+  this.writer.addCString(msg.type + (msg.name || ''))
+  this._send(0x43, more)
+}
+
+Connection.prototype.describe = function (msg, more) {
+  this.writer.addCString(msg.type + (msg.name || ''))
+  this._send(0x44, more)
+}
+
+Connection.prototype.sendCopyFromChunk = function (chunk) {
+  this.stream.write(this.writer.add(chunk).flush(0x64))
+}
+
+Connection.prototype.endCopyFrom = function () {
+  this.stream.write(this.writer.add(emptyBuffer).flush(0x63))
+}
+
+Connection.prototype.sendCopyFail = function (msg) {
+  // this.stream.write(this.writer.add(emptyBuffer).flush(0x66));
+  this.writer.addCString(msg)
+  this._send(0x66)
+}
+
+var Message = function (name, length) {
+  this.name = name
+  this.length = length
+}
+
+Connection.prototype.parseMessage = function (buffer) {
+  this.offset = 0
+  var length = buffer.length + 4
+  switch (this._reader.header) {
+    case 0x52: // R
+      return this.parseR(buffer, length)
+
+    case 0x53: // S
+      return this.parseS(buffer, length)
+
+    case 0x4b: // K
+      return this.parseK(buffer, length)
+
+    case 0x43: // C
+      return this.parseC(buffer, length)
+
+    case 0x5a: // Z
+      return this.parseZ(buffer, length)
+
+    case 0x54: // T
+      return this.parseT(buffer, length)
+
+    case 0x44: // D
+      return this.parseD(buffer, length)
+
+    case 0x45: // E
+      return this.parseE(buffer, length)
+
+    case 0x4e: // N
+      return this.parseN(buffer, length)
+
+    case 0x31: // 1
+      return new Message('parseComplete', length)
+
+    case 0x32: // 2
+      return new Message('bindComplete', length)
+
+    case 0x33: // 3
+      return new Message('closeComplete', length)
+
+    case 0x41: // A
+      return this.parseA(buffer, length)
+
+    case 0x6e: // n
+      return new Message('noData', length)
+
+    case 0x49: // I
+      return new Message('emptyQuery', length)
+
+    case 0x73: // s
+      return new Message('portalSuspended', length)
+
+    case 0x47: // G
+      return this.parseG(buffer, length)
+
+    case 0x48: // H
+      return this.parseH(buffer, length)
+
+    case 0x57: // W
+      return new Message('replicationStart', length)
+
+    case 0x63: // c
+      return new Message('copyDone', length)
+
+    case 0x64: // d
+      return this.parsed(buffer, length)
+  }
+}
+
+Connection.prototype.parseR = function (buffer, length) {
+  var code = this.parseInt32(buffer)
+
+  var msg = new Message('authenticationOk', length)
+
+  switch (code) {
+    case 0: // AuthenticationOk
+      return msg
+    case 3: // AuthenticationCleartextPassword
+      if (msg.length === 8) {
+        msg.name = 'authenticationCleartextPassword'
+        return msg
+      }
+      break
+    case 5: // AuthenticationMD5Password
+      if (msg.length === 12) {
+        msg.name = 'authenticationMD5Password'
+        msg.salt = Buffer.alloc(4)
+        buffer.copy(msg.salt, 0, this.offset, this.offset + 4)
+        this.offset += 4
+        return msg
+      }
+
+      break
+    case 10: // AuthenticationSASL
+      msg.name = 'authenticationSASL'
+      msg.mechanisms = []
+      do {
+        var mechanism = this.parseCString(buffer)
+
+        if (mechanism) {
+          msg.mechanisms.push(mechanism)
+        }
+      } while (mechanism)
+
+      return msg
+    case 11: // AuthenticationSASLContinue
+      msg.name = 'authenticationSASLContinue'
+      msg.data = this.readString(buffer, length - 4)
+
+      return msg
+    case 12: // AuthenticationSASLFinal
+      msg.name = 'authenticationSASLFinal'
+      msg.data = this.readString(buffer, length - 4)
+
+      return msg
+  }
+
+  throw new Error('Unknown authenticationOk message type' + util.inspect(msg))
+}
+
+Connection.prototype.parseS = function (buffer, length) {
+  var msg = new Message('parameterStatus', length)
+  msg.parameterName = this.parseCString(buffer)
+  msg.parameterValue = this.parseCString(buffer)
+  return msg
+}
+
+Connection.prototype.parseK = function (buffer, length) {
+  var msg = new Message('backendKeyData', length)
+  msg.processID = this.parseInt32(buffer)
+  msg.secretKey = this.parseInt32(buffer)
+  return msg
+}
+
+Connection.prototype.parseC = function (buffer, length) {
+  var msg = new Message('commandComplete', length)
+  msg.text = this.parseCString(buffer)
+  return msg
+}
+
+Connection.prototype.parseZ = function (buffer, length) {
+  var msg = new Message('readyForQuery', length)
+  msg.name = 'readyForQuery'
+  msg.status = this.readString(buffer, 1)
+  return msg
+}
+
+var ROW_DESCRIPTION = 'rowDescription'
+Connection.prototype.parseT = function (buffer, length) {
+  var msg = new Message(ROW_DESCRIPTION, length)
+  msg.fieldCount = this.parseInt16(buffer)
+  var fields = []
+  for (var i = 0; i < msg.fieldCount; i++) {
+    fields.push(this.parseField(buffer))
+  }
+  msg.fields = fields
+  return msg
+}
+
+var Field = function () {
+  this.name = null
+  this.tableID = null
+  this.columnID = null
+  this.dataTypeID = null
+  this.dataTypeSize = null
+  this.dataTypeModifier = null
+  this.format = null
+}
+
+var FORMAT_TEXT = 'text'
+var FORMAT_BINARY = 'binary'
+Connection.prototype.parseField = function (buffer) {
+  var field = new Field()
+  field.name = this.parseCString(buffer)
+  field.tableID = this.parseInt32(buffer)
+  field.columnID = this.parseInt16(buffer)
+  field.dataTypeID = this.parseInt32(buffer)
+  field.dataTypeSize = this.parseInt16(buffer)
+  field.dataTypeModifier = this.parseInt32(buffer)
+  if (this.parseInt16(buffer) === TEXT_MODE) {
+    this._mode = TEXT_MODE
+    field.format = FORMAT_TEXT
+  } else {
+    this._mode = BINARY_MODE
+    field.format = FORMAT_BINARY
+  }
+  return field
+}
+
+var DATA_ROW = 'dataRow'
+var DataRowMessage = function (length, fieldCount) {
+  this.name = DATA_ROW
+  this.length = length
+  this.fieldCount = fieldCount
+  this.fields = []
+}
+
+// extremely hot-path code
+Connection.prototype.parseD = function (buffer, length) {
+  var fieldCount = this.parseInt16(buffer)
+  var msg = new DataRowMessage(length, fieldCount)
+  for (var i = 0; i < fieldCount; i++) {
+    msg.fields.push(this._readValue(buffer))
+  }
+  return msg
+}
+
+// extremely hot-path code
+Connection.prototype._readValue = function (buffer) {
+  var length = this.parseInt32(buffer)
+  if (length === -1) return null
+  if (this._mode === TEXT_MODE) {
+    return this.readString(buffer, length)
+  }
+  return this.readBytes(buffer, length)
+}
+
+// parses error
+Connection.prototype.parseE = function (buffer, length) {
+  var fields = {}
+  var msg, item
+  var input = new Message('error', length)
+  var fieldType = this.readString(buffer, 1)
+  while (fieldType !== '\0') {
+    fields[fieldType] = this.parseCString(buffer)
+    fieldType = this.readString(buffer, 1)
+  }
+  if (input.name === 'error') {
+    // the msg is an Error instance
+    msg = new Error(fields.M)
+    for (item in input) {
+      // copy input properties to the error
+      if (Object.prototype.hasOwnProperty.call(input, item)) {
+        msg[item] = input[item]
+      }
+    }
+  } else {
+    // the msg is an object literal
+    msg = input
+    msg.message = fields.M
+  }
+  msg.severity = fields.S
+  msg.code = fields.C
+  msg.detail = fields.D
+  msg.hint = fields.H
+  msg.position = fields.P
+  msg.internalPosition = fields.p
+  msg.internalQuery = fields.q
+  msg.where = fields.W
+  msg.schema = fields.s
+  msg.table = fields.t
+  msg.column = fields.c
+  msg.dataType = fields.d
+  msg.constraint = fields.n
+  msg.file = fields.F
+  msg.line = fields.L
+  msg.routine = fields.R
+  return msg
+}
+
+// same thing, different name
+Connection.prototype.parseN = function (buffer, length) {
+  var msg = this.parseE(buffer, length)
+  msg.name = 'notice'
+  return msg
+}
+
+Connection.prototype.parseA = function (buffer, length) {
+  var msg = new Message('notification', length)
+  msg.processId = this.parseInt32(buffer)
+  msg.channel = this.parseCString(buffer)
+  msg.payload = this.parseCString(buffer)
+  return msg
+}
+
+Connection.prototype.parseG = function (buffer, length) {
+  var msg = new Message('copyInResponse', length)
+  return this.parseGH(buffer, msg)
+}
+
+Connection.prototype.parseH = function (buffer, length) {
+  var msg = new Message('copyOutResponse', length)
+  return this.parseGH(buffer, msg)
+}
+
+Connection.prototype.parseGH = function (buffer, msg) {
+  var isBinary = buffer[this.offset] !== 0
+  this.offset++
+  msg.binary = isBinary
+  var columnCount = this.parseInt16(buffer)
+  msg.columnTypes = []
+  for (var i = 0; i < columnCount; i++) {
+    msg.columnTypes.push(this.parseInt16(buffer))
+  }
+  return msg
+}
+
+Connection.prototype.parsed = function (buffer, length) {
+  var msg = new Message('copyData', length)
+  msg.chunk = this.readBytes(buffer, msg.length - 4)
+  return msg
+}
+
+Connection.prototype.parseInt32 = function (buffer) {
+  var value = buffer.readInt32BE(this.offset)
+  this.offset += 4
+  return value
+}
+
+Connection.prototype.parseInt16 = function (buffer) {
+  var value = buffer.readInt16BE(this.offset)
+  this.offset += 2
+  return value
+}
+
+Connection.prototype.readString = function (buffer, length) {
+  return buffer.toString(this.encoding, this.offset, (this.offset += length))
+}
+
+Connection.prototype.readBytes = function (buffer, length) {
+  return buffer.slice(this.offset, (this.offset += length))
+}
+
+Connection.prototype.parseCString = function (buffer) {
+  var start = this.offset
+  var end = buffer.indexOf(0, start)
+  this.offset = end + 1
+  return buffer.toString(this.encoding, start, end)
+}
+// end parsing methods
+module.exports = Connection
diff --git a/server/node_modules/pg/lib/defaults.js b/server/node_modules/pg/lib/defaults.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd1bf6de6b5f841d062bb49830e32ce8ab8239c8
--- /dev/null
+++ b/server/node_modules/pg/lib/defaults.js
@@ -0,0 +1,81 @@
+'use strict'
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+module.exports = {
+  // database host. defaults to localhost
+  host: 'localhost',
+
+  // database user's name
+  user: process.platform === 'win32' ? process.env.USERNAME : process.env.USER,
+
+  // name of database to connect
+  database: process.platform === 'win32' ? process.env.USERNAME : process.env.USER,
+
+  // database user's password
+  password: null,
+
+  // a Postgres connection string to be used instead of setting individual connection items
+  // NOTE:  Setting this value will cause it to override any other value (such as database or user) defined
+  // in the defaults object.
+  connectionString: undefined,
+
+  // database port
+  port: 5432,
+
+  // number of rows to return at a time from a prepared statement's
+  // portal. 0 will return all rows at once
+  rows: 0,
+
+  // binary result mode
+  binary: false,
+
+  // Connection pool options - see https://github.com/brianc/node-pg-pool
+
+  // number of connections to use in connection pool
+  // 0 will disable connection pooling
+  max: 10,
+
+  // max milliseconds a client can go unused before it is removed
+  // from the pool and destroyed
+  idleTimeoutMillis: 30000,
+
+  client_encoding: '',
+
+  ssl: false,
+
+  application_name: undefined,
+
+  fallback_application_name: undefined,
+
+  parseInputDatesAsUTC: false,
+
+  // max milliseconds any query using this connection will execute for before timing out in error.
+  // false=unlimited
+  statement_timeout: false,
+
+  // max milliseconds to wait for query to complete (client side)
+  query_timeout: false,
+
+  connect_timeout: 0,
+
+  keepalives: 1,
+
+  keepalives_idle: 0
+}
+
+var pgTypes = require('pg-types')
+// save default parsers
+var parseBigInteger = pgTypes.getTypeParser(20, 'text')
+var parseBigIntegerArray = pgTypes.getTypeParser(1016, 'text')
+
+// parse int8 so you can get your count values as actual numbers
+module.exports.__defineSetter__('parseInt8', function (val) {
+  pgTypes.setTypeParser(20, 'text', val ? pgTypes.getTypeParser(23, 'text') : parseBigInteger)
+  pgTypes.setTypeParser(1016, 'text', val ? pgTypes.getTypeParser(1007, 'text') : parseBigIntegerArray)
+})
diff --git a/server/node_modules/pg/lib/index.js b/server/node_modules/pg/lib/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e000a378249feb513b1915e7335fe5d9ea24774
--- /dev/null
+++ b/server/node_modules/pg/lib/index.js
@@ -0,0 +1,59 @@
+'use strict'
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var util = require('util')
+var Client = require('./client')
+var defaults = require('./defaults')
+var Connection = require('./connection')
+var Pool = require('pg-pool')
+
+const poolFactory = (Client) => {
+  var BoundPool = function (options) {
+    var config = Object.assign({ Client: Client }, options)
+    return new Pool(config)
+  }
+
+  util.inherits(BoundPool, Pool)
+
+  return BoundPool
+}
+
+var PG = function (clientConstructor) {
+  this.defaults = defaults
+  this.Client = clientConstructor
+  this.Query = this.Client.Query
+  this.Pool = poolFactory(this.Client)
+  this._pools = []
+  this.Connection = Connection
+  this.types = require('pg-types')
+}
+
+if (typeof process.env.NODE_PG_FORCE_NATIVE !== 'undefined') {
+  module.exports = new PG(require('./native'))
+} else {
+  module.exports = new PG(Client)
+
+  // lazy require native module...the native module may not have installed
+  module.exports.__defineGetter__('native', function () {
+    delete module.exports.native
+    var native = null
+    try {
+      native = new PG(require('./native'))
+    } catch (err) {
+      if (err.code !== 'MODULE_NOT_FOUND') {
+        throw err
+      }
+      /* eslint-disable no-console */
+      console.error(err.message)
+      /* eslint-enable no-console */
+    }
+    module.exports.native = native
+    return native
+  })
+}
diff --git a/server/node_modules/pg/lib/native/client.js b/server/node_modules/pg/lib/native/client.js
new file mode 100644
index 0000000000000000000000000000000000000000..6859bc2cc83c9fb62ddae3457bd4945e8ca0a2c9
--- /dev/null
+++ b/server/node_modules/pg/lib/native/client.js
@@ -0,0 +1,295 @@
+'use strict'
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+// eslint-disable-next-line
+var Native = require('pg-native')
+var TypeOverrides = require('../type-overrides')
+var semver = require('semver')
+var pkg = require('../../package.json')
+var assert = require('assert')
+var EventEmitter = require('events').EventEmitter
+var util = require('util')
+var ConnectionParameters = require('../connection-parameters')
+
+var msg = 'Version >= ' + pkg.minNativeVersion + ' of pg-native required.'
+assert(semver.gte(Native.version, pkg.minNativeVersion), msg)
+
+var NativeQuery = require('./query')
+
+var Client = module.exports = function (config) {
+  EventEmitter.call(this)
+  config = config || {}
+
+  this._Promise = config.Promise || global.Promise
+  this._types = new TypeOverrides(config.types)
+
+  this.native = new Native({
+    types: this._types
+  })
+
+  this._queryQueue = []
+  this._ending = false
+  this._connecting = false
+  this._connected = false
+  this._queryable = true
+
+  // keep these on the object for legacy reasons
+  // for the time being. TODO: deprecate all this jazz
+  var cp = this.connectionParameters = new ConnectionParameters(config)
+  this.user = cp.user
+  this.password = cp.password
+  this.database = cp.database
+  this.host = cp.host
+  this.port = cp.port
+
+  // a hash to hold named queries
+  this.namedQueries = {}
+}
+
+Client.Query = NativeQuery
+
+util.inherits(Client, EventEmitter)
+
+Client.prototype._errorAllQueries = function (err) {
+  const enqueueError = (query) => {
+    process.nextTick(() => {
+      query.native = this.native
+      query.handleError(err)
+    })
+  }
+
+  if (this._hasActiveQuery()) {
+    enqueueError(this._activeQuery)
+    this._activeQuery = null
+  }
+
+  this._queryQueue.forEach(enqueueError)
+  this._queryQueue.length = 0
+}
+
+// connect to the backend
+// pass an optional callback to be called once connected
+// or with an error if there was a connection error
+Client.prototype._connect = function (cb) {
+  var self = this
+
+  if (this._connecting) {
+    process.nextTick(() => cb(new Error('Client has already been connected. You cannot reuse a client.')))
+    return
+  }
+
+  this._connecting = true
+
+  this.connectionParameters.getLibpqConnectionString(function (err, conString) {
+    if (err) return cb(err)
+    self.native.connect(conString, function (err) {
+      if (err) return cb(err)
+
+      // set internal states to connected
+      self._connected = true
+
+      // handle connection errors from the native layer
+      self.native.on('error', function (err) {
+        self._queryable = false
+        self._errorAllQueries(err)
+        self.emit('error', err)
+      })
+
+      self.native.on('notification', function (msg) {
+        self.emit('notification', {
+          channel: msg.relname,
+          payload: msg.extra
+        })
+      })
+
+      // signal we are connected now
+      self.emit('connect')
+      self._pulseQueryQueue(true)
+
+      cb()
+    })
+  })
+}
+
+Client.prototype.connect = function (callback) {
+  if (callback) {
+    this._connect(callback)
+    return
+  }
+
+  return new this._Promise((resolve, reject) => {
+    this._connect((error) => {
+      if (error) {
+        reject(error)
+      } else {
+        resolve()
+      }
+    })
+  })
+}
+
+// send a query to the server
+// this method is highly overloaded to take
+// 1) string query, optional array of parameters, optional function callback
+// 2) object query with {
+//    string query
+//    optional array values,
+//    optional function callback instead of as a separate parameter
+//    optional string name to name & cache the query plan
+//    optional string rowMode = 'array' for an array of results
+//  }
+Client.prototype.query = function (config, values, callback) {
+  var query
+  var result
+  var readTimeout
+  var readTimeoutTimer
+  var queryCallback
+
+  if (config === null || config === undefined) {
+    throw new TypeError('Client was passed a null or undefined query')
+  } else if (typeof config.submit === 'function') {
+    readTimeout = config.query_timeout || this.connectionParameters.query_timeout
+    result = query = config
+    // accept query(new Query(...), (err, res) => { }) style
+    if (typeof values === 'function') {
+      config.callback = values
+    }
+  } else {
+    readTimeout = this.connectionParameters.query_timeout
+    query = new NativeQuery(config, values, callback)
+    if (!query.callback) {
+      let resolveOut, rejectOut
+      result = new this._Promise((resolve, reject) => {
+        resolveOut = resolve
+        rejectOut = reject
+      })
+      query.callback = (err, res) => err ? rejectOut(err) : resolveOut(res)
+    }
+  }
+
+  if (readTimeout) {
+    queryCallback = query.callback
+
+    readTimeoutTimer = setTimeout(() => {
+      var error = new Error('Query read timeout')
+
+      process.nextTick(() => {
+        query.handleError(error, this.connection)
+      })
+
+      queryCallback(error)
+
+      // we already returned an error,
+      // just do nothing if query completes
+      query.callback = () => {}
+
+      // Remove from queue
+      var index = this._queryQueue.indexOf(query)
+      if (index > -1) {
+        this._queryQueue.splice(index, 1)
+      }
+
+      this._pulseQueryQueue()
+    }, readTimeout)
+
+    query.callback = (err, res) => {
+      clearTimeout(readTimeoutTimer)
+      queryCallback(err, res)
+    }
+  }
+
+  if (!this._queryable) {
+    query.native = this.native
+    process.nextTick(() => {
+      query.handleError(new Error('Client has encountered a connection error and is not queryable'))
+    })
+    return result
+  }
+
+  if (this._ending) {
+    query.native = this.native
+    process.nextTick(() => {
+      query.handleError(new Error('Client was closed and is not queryable'))
+    })
+    return result
+  }
+
+  this._queryQueue.push(query)
+  this._pulseQueryQueue()
+  return result
+}
+
+// disconnect from the backend server
+Client.prototype.end = function (cb) {
+  var self = this
+
+  this._ending = true
+
+  if (!this._connected) {
+    this.once('connect', this.end.bind(this, cb))
+  }
+  var result
+  if (!cb) {
+    result = new this._Promise(function (resolve, reject) {
+      cb = (err) => err ? reject(err) : resolve()
+    })
+  }
+  this.native.end(function () {
+    self._errorAllQueries(new Error('Connection terminated'))
+
+    process.nextTick(() => {
+      self.emit('end')
+      if (cb) cb()
+    })
+  })
+  return result
+}
+
+Client.prototype._hasActiveQuery = function () {
+  return this._activeQuery && this._activeQuery.state !== 'error' && this._activeQuery.state !== 'end'
+}
+
+Client.prototype._pulseQueryQueue = function (initialConnection) {
+  if (!this._connected) {
+    return
+  }
+  if (this._hasActiveQuery()) {
+    return
+  }
+  var query = this._queryQueue.shift()
+  if (!query) {
+    if (!initialConnection) {
+      this.emit('drain')
+    }
+    return
+  }
+  this._activeQuery = query
+  query.submit(this)
+  var self = this
+  query.once('_done', function () {
+    self._pulseQueryQueue()
+  })
+}
+
+// attempt to cancel an in-progress query
+Client.prototype.cancel = function (query) {
+  if (this._activeQuery === query) {
+    this.native.cancel(function () {})
+  } else if (this._queryQueue.indexOf(query) !== -1) {
+    this._queryQueue.splice(this._queryQueue.indexOf(query), 1)
+  }
+}
+
+Client.prototype.setTypeParser = function (oid, format, parseFn) {
+  return this._types.setTypeParser(oid, format, parseFn)
+}
+
+Client.prototype.getTypeParser = function (oid, format) {
+  return this._types.getTypeParser(oid, format)
+}
diff --git a/server/node_modules/pg/lib/native/index.js b/server/node_modules/pg/lib/native/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..eead422a3a65d871f6d419293534cdbe1187e908
--- /dev/null
+++ b/server/node_modules/pg/lib/native/index.js
@@ -0,0 +1,2 @@
+'use strict'
+module.exports = require('./client')
diff --git a/server/node_modules/pg/lib/native/query.js b/server/node_modules/pg/lib/native/query.js
new file mode 100644
index 0000000000000000000000000000000000000000..0c83e27e354d6748428f72eaae41b1267d5550d1
--- /dev/null
+++ b/server/node_modules/pg/lib/native/query.js
@@ -0,0 +1,167 @@
+'use strict'
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var EventEmitter = require('events').EventEmitter
+var util = require('util')
+var utils = require('../utils')
+
+var NativeQuery = module.exports = function (config, values, callback) {
+  EventEmitter.call(this)
+  config = utils.normalizeQueryConfig(config, values, callback)
+  this.text = config.text
+  this.values = config.values
+  this.name = config.name
+  this.callback = config.callback
+  this.state = 'new'
+  this._arrayMode = config.rowMode === 'array'
+
+  // if the 'row' event is listened for
+  // then emit them as they come in
+  // without setting singleRowMode to true
+  // this has almost no meaning because libpq
+  // reads all rows into memory befor returning any
+  this._emitRowEvents = false
+  this.on('newListener', function (event) {
+    if (event === 'row') this._emitRowEvents = true
+  }.bind(this))
+}
+
+util.inherits(NativeQuery, EventEmitter)
+
+var errorFieldMap = {
+  /* eslint-disable quote-props */
+  'sqlState': 'code',
+  'statementPosition': 'position',
+  'messagePrimary': 'message',
+  'context': 'where',
+  'schemaName': 'schema',
+  'tableName': 'table',
+  'columnName': 'column',
+  'dataTypeName': 'dataType',
+  'constraintName': 'constraint',
+  'sourceFile': 'file',
+  'sourceLine': 'line',
+  'sourceFunction': 'routine'
+}
+
+NativeQuery.prototype.handleError = function (err) {
+  // copy pq error fields into the error object
+  var fields = this.native.pq.resultErrorFields()
+  if (fields) {
+    for (var key in fields) {
+      var normalizedFieldName = errorFieldMap[key] || key
+      err[normalizedFieldName] = fields[key]
+    }
+  }
+  if (this.callback) {
+    this.callback(err)
+  } else {
+    this.emit('error', err)
+  }
+  this.state = 'error'
+}
+
+NativeQuery.prototype.then = function (onSuccess, onFailure) {
+  return this._getPromise().then(onSuccess, onFailure)
+}
+
+NativeQuery.prototype.catch = function (callback) {
+  return this._getPromise().catch(callback)
+}
+
+NativeQuery.prototype._getPromise = function () {
+  if (this._promise) return this._promise
+  this._promise = new Promise(function (resolve, reject) {
+    this._once('end', resolve)
+    this._once('error', reject)
+  }.bind(this))
+  return this._promise
+}
+
+NativeQuery.prototype.submit = function (client) {
+  this.state = 'running'
+  var self = this
+  this.native = client.native
+  client.native.arrayMode = this._arrayMode
+
+  var after = function (err, rows, results) {
+    client.native.arrayMode = false
+    setImmediate(function () {
+      self.emit('_done')
+    })
+
+    // handle possible query error
+    if (err) {
+      return self.handleError(err)
+    }
+
+    // emit row events for each row in the result
+    if (self._emitRowEvents) {
+      if (results.length > 1) {
+        rows.forEach((rowOfRows, i) => {
+          rowOfRows.forEach(row => {
+            self.emit('row', row, results[i])
+          })
+        })
+      } else {
+        rows.forEach(function (row) {
+          self.emit('row', row, results)
+        })
+      }
+    }
+
+    // handle successful result
+    self.state = 'end'
+    self.emit('end', results)
+    if (self.callback) {
+      self.callback(null, results)
+    }
+  }
+
+  if (process.domain) {
+    after = process.domain.bind(after)
+  }
+
+  // named query
+  if (this.name) {
+    if (this.name.length > 63) {
+      /* eslint-disable no-console */
+      console.error('Warning! Postgres only supports 63 characters for query names.')
+      console.error('You supplied %s (%s)', this.name, this.name.length)
+      console.error('This can cause conflicts and silent errors executing queries')
+      /* eslint-enable no-console */
+    }
+    var values = (this.values || []).map(utils.prepareValue)
+
+    // check if the client has already executed this named query
+    // if so...just execute it again - skip the planning phase
+    if (client.namedQueries[this.name]) {
+      if (this.text && client.namedQueries[this.name] !== this.text) {
+        const err = new Error(`Prepared statements must be unique - '${this.name}' was used for a different statement`)
+        return after(err)
+      }
+      return client.native.execute(this.name, values, after)
+    }
+    // plan the named query the first time, then execute it
+    return client.native.prepare(this.name, this.text, values.length, function (err) {
+      if (err) return after(err)
+      client.namedQueries[self.name] = self.text
+      return self.native.execute(self.name, values, after)
+    })
+  } else if (this.values) {
+    if (!Array.isArray(this.values)) {
+      const err = new Error('Query values must be an array')
+      return after(err)
+    }
+    var vals = this.values.map(utils.prepareValue)
+    client.native.query(this.text, vals, after)
+  } else {
+    client.native.query(this.text, after)
+  }
+}
diff --git a/server/node_modules/pg/lib/query.js b/server/node_modules/pg/lib/query.js
new file mode 100644
index 0000000000000000000000000000000000000000..250e8950d00e134e179c1f099c5ca6b0caaa2b51
--- /dev/null
+++ b/server/node_modules/pg/lib/query.js
@@ -0,0 +1,229 @@
+'use strict'
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var EventEmitter = require('events').EventEmitter
+var util = require('util')
+
+var Result = require('./result')
+var utils = require('./utils')
+
+var Query = function (config, values, callback) {
+  // use of "new" optional
+  if (!(this instanceof Query)) { return new Query(config, values, callback) }
+
+  config = utils.normalizeQueryConfig(config, values, callback)
+
+  this.text = config.text
+  this.values = config.values
+  this.rows = config.rows
+  this.types = config.types
+  this.name = config.name
+  this.binary = config.binary
+  // use unique portal name each time
+  this.portal = config.portal || ''
+  this.callback = config.callback
+  this._rowMode = config.rowMode
+  if (process.domain && config.callback) {
+    this.callback = process.domain.bind(config.callback)
+  }
+  this._result = new Result(this._rowMode, this.types)
+
+  // potential for multiple results
+  this._results = this._result
+  this.isPreparedStatement = false
+  this._canceledDueToError = false
+  this._promise = null
+  EventEmitter.call(this)
+}
+
+util.inherits(Query, EventEmitter)
+
+Query.prototype.requiresPreparation = function () {
+  // named queries must always be prepared
+  if (this.name) { return true }
+  // always prepare if there are max number of rows expected per
+  // portal execution
+  if (this.rows) { return true }
+  // don't prepare empty text queries
+  if (!this.text) { return false }
+  // prepare if there are values
+  if (!this.values) { return false }
+  return this.values.length > 0
+}
+
+Query.prototype._checkForMultirow = function () {
+  // if we already have a result with a command property
+  // then we've already executed one query in a multi-statement simple query
+  // turn our results into an array of results
+  if (this._result.command) {
+    if (!Array.isArray(this._results)) {
+      this._results = [this._result]
+    }
+    this._result = new Result(this._rowMode, this.types)
+    this._results.push(this._result)
+  }
+}
+
+// associates row metadata from the supplied
+// message with this query object
+// metadata used when parsing row results
+Query.prototype.handleRowDescription = function (msg) {
+  this._checkForMultirow()
+  this._result.addFields(msg.fields)
+  this._accumulateRows = this.callback || !this.listeners('row').length
+}
+
+Query.prototype.handleDataRow = function (msg) {
+  var row
+
+  if (this._canceledDueToError) {
+    return
+  }
+
+  try {
+    row = this._result.parseRow(msg.fields)
+  } catch (err) {
+    this._canceledDueToError = err
+    return
+  }
+
+  this.emit('row', row, this._result)
+  if (this._accumulateRows) {
+    this._result.addRow(row)
+  }
+}
+
+Query.prototype.handleCommandComplete = function (msg, con) {
+  this._checkForMultirow()
+  this._result.addCommandComplete(msg)
+  // need to sync after each command complete of a prepared statement
+  if (this.isPreparedStatement) {
+    con.sync()
+  }
+}
+
+// if a named prepared statement is created with empty query text
+// the backend will send an emptyQuery message but *not* a command complete message
+// execution on the connection will hang until the backend receives a sync message
+Query.prototype.handleEmptyQuery = function (con) {
+  if (this.isPreparedStatement) {
+    con.sync()
+  }
+}
+
+Query.prototype.handleReadyForQuery = function (con) {
+  if (this._canceledDueToError) {
+    return this.handleError(this._canceledDueToError, con)
+  }
+  if (this.callback) {
+    this.callback(null, this._results)
+  }
+  this.emit('end', this._results)
+}
+
+Query.prototype.handleError = function (err, connection) {
+  // need to sync after error during a prepared statement
+  if (this.isPreparedStatement) {
+    connection.sync()
+  }
+  if (this._canceledDueToError) {
+    err = this._canceledDueToError
+    this._canceledDueToError = false
+  }
+  // if callback supplied do not emit error event as uncaught error
+  // events will bubble up to node process
+  if (this.callback) {
+    return this.callback(err)
+  }
+  this.emit('error', err)
+}
+
+Query.prototype.submit = function (connection) {
+  if (typeof this.text !== 'string' && typeof this.name !== 'string') {
+    return new Error('A query must have either text or a name. Supplying neither is unsupported.')
+  }
+  const previous = connection.parsedStatements[this.name]
+  if (this.text && previous && this.text !== previous) {
+    return new Error(`Prepared statements must be unique - '${this.name}' was used for a different statement`)
+  }
+  if (this.values && !Array.isArray(this.values)) {
+    return new Error('Query values must be an array')
+  }
+  if (this.requiresPreparation()) {
+    this.prepare(connection)
+  } else {
+    connection.query(this.text)
+  }
+  return null
+}
+
+Query.prototype.hasBeenParsed = function (connection) {
+  return this.name && connection.parsedStatements[this.name]
+}
+
+Query.prototype.handlePortalSuspended = function (connection) {
+  this._getRows(connection, this.rows)
+}
+
+Query.prototype._getRows = function (connection, rows) {
+  connection.execute({
+    portal: this.portal,
+    rows: rows
+  }, true)
+  connection.flush()
+}
+
+Query.prototype.prepare = function (connection) {
+  var self = this
+  // prepared statements need sync to be called after each command
+  // complete or when an error is encountered
+  this.isPreparedStatement = true
+  // TODO refactor this poor encapsulation
+  if (!this.hasBeenParsed(connection)) {
+    connection.parse({
+      text: self.text,
+      name: self.name,
+      types: self.types
+    }, true)
+  }
+
+  if (self.values) {
+    try {
+      self.values = self.values.map(utils.prepareValue)
+    } catch (err) {
+      this.handleError(err, connection)
+      return
+    }
+  }
+
+  // http://developer.postgresql.org/pgdocs/postgres/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
+  connection.bind({
+    portal: self.portal,
+    statement: self.name,
+    values: self.values,
+    binary: self.binary
+  }, true)
+
+  connection.describe({
+    type: 'P',
+    name: self.portal || ''
+  }, true)
+
+  this._getRows(connection, this.rows)
+}
+
+Query.prototype.handleCopyInResponse = function (connection) {
+  connection.sendCopyFail('No source stream defined')
+}
+
+// eslint-disable-next-line no-unused-vars
+Query.prototype.handleCopyData = function (msg, connection) {
+  // noop
+}
+module.exports = Query
diff --git a/server/node_modules/pg/lib/result.js b/server/node_modules/pg/lib/result.js
new file mode 100644
index 0000000000000000000000000000000000000000..088298bc4f75cc0196f6561b57b7ed2e3f681db2
--- /dev/null
+++ b/server/node_modules/pg/lib/result.js
@@ -0,0 +1,103 @@
+'use strict'
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var types = require('pg-types')
+
+// result object returned from query
+// in the 'end' event and also
+// passed as second argument to provided callback
+var Result = function (rowMode, types) {
+  this.command = null
+  this.rowCount = null
+  this.oid = null
+  this.rows = []
+  this.fields = []
+  this._parsers = []
+  this._types = types
+  this.RowCtor = null
+  this.rowAsArray = rowMode === 'array'
+  if (this.rowAsArray) {
+    this.parseRow = this._parseRowAsArray
+  }
+}
+
+var matchRegexp = /^([A-Za-z]+)(?: (\d+))?(?: (\d+))?/
+
+// adds a command complete message
+Result.prototype.addCommandComplete = function (msg) {
+  var match
+  if (msg.text) {
+    // pure javascript
+    match = matchRegexp.exec(msg.text)
+  } else {
+    // native bindings
+    match = matchRegexp.exec(msg.command)
+  }
+  if (match) {
+    this.command = match[1]
+    if (match[3]) {
+      // COMMMAND OID ROWS
+      this.oid = parseInt(match[2], 10)
+      this.rowCount = parseInt(match[3], 10)
+    } else if (match[2]) {
+      // COMMAND ROWS
+      this.rowCount = parseInt(match[2], 10)
+    }
+  }
+}
+
+Result.prototype._parseRowAsArray = function (rowData) {
+  var row = []
+  for (var i = 0, len = rowData.length; i < len; i++) {
+    var rawValue = rowData[i]
+    if (rawValue !== null) {
+      row.push(this._parsers[i](rawValue))
+    } else {
+      row.push(null)
+    }
+  }
+  return row
+}
+
+Result.prototype.parseRow = function (rowData) {
+  var row = {}
+  for (var i = 0, len = rowData.length; i < len; i++) {
+    var rawValue = rowData[i]
+    var field = this.fields[i].name
+    if (rawValue !== null) {
+      row[field] = this._parsers[i](rawValue)
+    } else {
+      row[field] = null
+    }
+  }
+  return row
+}
+
+Result.prototype.addRow = function (row) {
+  this.rows.push(row)
+}
+
+Result.prototype.addFields = function (fieldDescriptions) {
+  // clears field definitions
+  // multiple query statements in 1 action can result in multiple sets
+  // of rowDescriptions...eg: 'select NOW(); select 1::int;'
+  // you need to reset the fields
+  if (this.fields.length) {
+    this.fields = []
+    this._parsers = []
+  }
+  for (var i = 0; i < fieldDescriptions.length; i++) {
+    var desc = fieldDescriptions[i]
+    this.fields.push(desc)
+    var parser = (this._types || types).getTypeParser(desc.dataTypeID, desc.format || 'text')
+    this._parsers.push(parser)
+  }
+}
+
+module.exports = Result
diff --git a/server/node_modules/pg/lib/sasl.js b/server/node_modules/pg/lib/sasl.js
new file mode 100644
index 0000000000000000000000000000000000000000..39c24bb33a24d99e3375956a8d65d69fef510d28
--- /dev/null
+++ b/server/node_modules/pg/lib/sasl.js
@@ -0,0 +1,147 @@
+'use strict'
+const crypto = require('crypto')
+
+function startSession (mechanisms) {
+  if (mechanisms.indexOf('SCRAM-SHA-256') === -1) {
+    throw new Error('SASL: Only mechanism SCRAM-SHA-256 is currently supported')
+  }
+
+  const clientNonce = crypto.randomBytes(18).toString('base64')
+
+  return {
+    mechanism: 'SCRAM-SHA-256',
+    clientNonce,
+    response: 'n,,n=*,r=' + clientNonce,
+    message: 'SASLInitialResponse'
+  }
+}
+
+function continueSession (session, password, serverData) {
+  if (session.message !== 'SASLInitialResponse') {
+    throw new Error('SASL: Last message was not SASLInitialResponse')
+  }
+
+  const sv = extractVariablesFromFirstServerMessage(serverData)
+
+  if (!sv.nonce.startsWith(session.clientNonce)) {
+    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: server nonce does not start with client nonce')
+  }
+
+  var saltBytes = Buffer.from(sv.salt, 'base64')
+
+  var saltedPassword = Hi(password, saltBytes, sv.iteration)
+
+  var clientKey = createHMAC(saltedPassword, 'Client Key')
+  var storedKey = crypto.createHash('sha256').update(clientKey).digest()
+
+  var clientFirstMessageBare = 'n=*,r=' + session.clientNonce
+  var serverFirstMessage = 'r=' + sv.nonce + ',s=' + sv.salt + ',i=' + sv.iteration
+
+  var clientFinalMessageWithoutProof = 'c=biws,r=' + sv.nonce
+
+  var authMessage = clientFirstMessageBare + ',' + serverFirstMessage + ',' + clientFinalMessageWithoutProof
+
+  var clientSignature = createHMAC(storedKey, authMessage)
+  var clientProofBytes = xorBuffers(clientKey, clientSignature)
+  var clientProof = clientProofBytes.toString('base64')
+
+  var serverKey = createHMAC(saltedPassword, 'Server Key')
+  var serverSignatureBytes = createHMAC(serverKey, authMessage)
+
+  session.message = 'SASLResponse'
+  session.serverSignature = serverSignatureBytes.toString('base64')
+  session.response = clientFinalMessageWithoutProof + ',p=' + clientProof
+}
+
+function finalizeSession (session, serverData) {
+  if (session.message !== 'SASLResponse') {
+    throw new Error('SASL: Last message was not SASLResponse')
+  }
+
+  var serverSignature
+
+  String(serverData).split(',').forEach(function (part) {
+    switch (part[0]) {
+      case 'v':
+        serverSignature = part.substr(2)
+        break
+    }
+  })
+
+  if (serverSignature !== session.serverSignature) {
+    throw new Error('SASL: SCRAM-SERVER-FINAL-MESSAGE: server signature does not match')
+  }
+}
+
+function extractVariablesFromFirstServerMessage (data) {
+  var nonce, salt, iteration
+
+  String(data).split(',').forEach(function (part) {
+    switch (part[0]) {
+      case 'r':
+        nonce = part.substr(2)
+        break
+      case 's':
+        salt = part.substr(2)
+        break
+      case 'i':
+        iteration = parseInt(part.substr(2), 10)
+        break
+    }
+  })
+
+  if (!nonce) {
+    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing')
+  }
+
+  if (!salt) {
+    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: salt missing')
+  }
+
+  if (!iteration) {
+    throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: iteration missing')
+  }
+
+  return {
+    nonce,
+    salt,
+    iteration
+  }
+}
+
+function xorBuffers (a, b) {
+  if (!Buffer.isBuffer(a)) a = Buffer.from(a)
+  if (!Buffer.isBuffer(b)) b = Buffer.from(b)
+  var res = []
+  if (a.length > b.length) {
+    for (var i = 0; i < b.length; i++) {
+      res.push(a[i] ^ b[i])
+    }
+  } else {
+    for (var j = 0; j < a.length; j++) {
+      res.push(a[j] ^ b[j])
+    }
+  }
+  return Buffer.from(res)
+}
+
+function createHMAC (key, msg) {
+  return crypto.createHmac('sha256', key).update(msg).digest()
+}
+
+function Hi (password, saltBytes, iterations) {
+  var ui1 = createHMAC(password, Buffer.concat([saltBytes, Buffer.from([0, 0, 0, 1])]))
+  var ui = ui1
+  for (var i = 0; i < iterations - 1; i++) {
+    ui1 = createHMAC(password, ui1)
+    ui = xorBuffers(ui, ui1)
+  }
+
+  return ui
+}
+
+module.exports = {
+  startSession,
+  continueSession,
+  finalizeSession
+}
diff --git a/server/node_modules/pg/lib/type-overrides.js b/server/node_modules/pg/lib/type-overrides.js
new file mode 100644
index 0000000000000000000000000000000000000000..54394406298408460166a3190d8ce7390570d5fb
--- /dev/null
+++ b/server/node_modules/pg/lib/type-overrides.js
@@ -0,0 +1,39 @@
+'use strict'
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var types = require('pg-types')
+
+function TypeOverrides (userTypes) {
+  this._types = userTypes || types
+  this.text = {}
+  this.binary = {}
+}
+
+TypeOverrides.prototype.getOverrides = function (format) {
+  switch (format) {
+    case 'text': return this.text
+    case 'binary': return this.binary
+    default: return {}
+  }
+}
+
+TypeOverrides.prototype.setTypeParser = function (oid, format, parseFn) {
+  if (typeof format === 'function') {
+    parseFn = format
+    format = 'text'
+  }
+  this.getOverrides(format)[oid] = parseFn
+}
+
+TypeOverrides.prototype.getTypeParser = function (oid, format) {
+  format = format || 'text'
+  return this.getOverrides(format)[oid] || this._types.getTypeParser(oid, format)
+}
+
+module.exports = TypeOverrides
diff --git a/server/node_modules/pg/lib/utils.js b/server/node_modules/pg/lib/utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..879949f0c35a6036142f7ba3f824fc3546451a96
--- /dev/null
+++ b/server/node_modules/pg/lib/utils.js
@@ -0,0 +1,177 @@
+'use strict'
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+const crypto = require('crypto')
+
+const defaults = require('./defaults')
+
+function escapeElement (elementRepresentation) {
+  var escaped = elementRepresentation
+    .replace(/\\/g, '\\\\')
+    .replace(/"/g, '\\"')
+
+  return '"' + escaped + '"'
+}
+
+// convert a JS array to a postgres array literal
+// uses comma separator so won't work for types like box that use
+// a different array separator.
+function arrayString (val) {
+  var result = '{'
+  for (var i = 0; i < val.length; i++) {
+    if (i > 0) {
+      result = result + ','
+    }
+    if (val[i] === null || typeof val[i] === 'undefined') {
+      result = result + 'NULL'
+    } else if (Array.isArray(val[i])) {
+      result = result + arrayString(val[i])
+    } else if (val[i] instanceof Buffer) {
+      result += '\\\\x' + val[i].toString('hex')
+    } else {
+      result += escapeElement(prepareValue(val[i]))
+    }
+  }
+  result = result + '}'
+  return result
+}
+
+// converts values from javascript types
+// to their 'raw' counterparts for use as a postgres parameter
+// note: you can override this function to provide your own conversion mechanism
+// for complex types, etc...
+var prepareValue = function (val, seen) {
+  if (val instanceof Buffer) {
+    return val
+  }
+  if (ArrayBuffer.isView(val)) {
+    var buf = Buffer.from(val.buffer, val.byteOffset, val.byteLength)
+    if (buf.length === val.byteLength) {
+      return buf
+    }
+    return buf.slice(val.byteOffset, val.byteOffset + val.byteLength) // Node.js v4 does not support those Buffer.from params
+  }
+  if (val instanceof Date) {
+    if (defaults.parseInputDatesAsUTC) {
+      return dateToStringUTC(val)
+    } else {
+      return dateToString(val)
+    }
+  }
+  if (Array.isArray(val)) {
+    return arrayString(val)
+  }
+  if (val === null || typeof val === 'undefined') {
+    return null
+  }
+  if (typeof val === 'object') {
+    return prepareObject(val, seen)
+  }
+  return val.toString()
+}
+
+function prepareObject (val, seen) {
+  if (val && typeof val.toPostgres === 'function') {
+    seen = seen || []
+    if (seen.indexOf(val) !== -1) {
+      throw new Error('circular reference detected while preparing "' + val + '" for query')
+    }
+    seen.push(val)
+
+    return prepareValue(val.toPostgres(prepareValue), seen)
+  }
+  return JSON.stringify(val)
+}
+
+function pad (number, digits) {
+  number = '' + number
+  while (number.length < digits) { number = '0' + number }
+  return number
+}
+
+function dateToString (date) {
+  var offset = -date.getTimezoneOffset()
+
+  var year = date.getFullYear()
+  var isBCYear = year < 1
+  if (isBCYear) year = Math.abs(year) + 1 // negative years are 1 off their BC representation
+
+  var ret = pad(year, 4) + '-' +
+    pad(date.getMonth() + 1, 2) + '-' +
+    pad(date.getDate(), 2) + 'T' +
+    pad(date.getHours(), 2) + ':' +
+    pad(date.getMinutes(), 2) + ':' +
+    pad(date.getSeconds(), 2) + '.' +
+    pad(date.getMilliseconds(), 3)
+
+  if (offset < 0) {
+    ret += '-'
+    offset *= -1
+  } else { ret += '+' }
+
+  ret += pad(Math.floor(offset / 60), 2) + ':' + pad(offset % 60, 2)
+  if (isBCYear) ret += ' BC'
+  return ret
+}
+
+function dateToStringUTC (date) {
+  var year = date.getUTCFullYear()
+  var isBCYear = year < 1
+  if (isBCYear) year = Math.abs(year) + 1 // negative years are 1 off their BC representation
+
+  var ret = pad(year, 4) + '-' +
+    pad(date.getUTCMonth() + 1, 2) + '-' +
+    pad(date.getUTCDate(), 2) + 'T' +
+    pad(date.getUTCHours(), 2) + ':' +
+    pad(date.getUTCMinutes(), 2) + ':' +
+    pad(date.getUTCSeconds(), 2) + '.' +
+    pad(date.getUTCMilliseconds(), 3)
+
+  ret += '+00:00'
+  if (isBCYear) ret += ' BC'
+  return ret
+}
+
+function normalizeQueryConfig (config, values, callback) {
+  // can take in strings or config objects
+  config = (typeof (config) === 'string') ? { text: config } : config
+  if (values) {
+    if (typeof values === 'function') {
+      config.callback = values
+    } else {
+      config.values = values
+    }
+  }
+  if (callback) {
+    config.callback = callback
+  }
+  return config
+}
+
+const md5 = function (string) {
+  return crypto.createHash('md5').update(string, 'utf-8').digest('hex')
+}
+
+// See AuthenticationMD5Password at https://www.postgresql.org/docs/current/static/protocol-flow.html
+const postgresMd5PasswordHash = function (user, password, salt) {
+  var inner = md5(password + user)
+  var outer = md5(Buffer.concat([Buffer.from(inner), salt]))
+  return 'md5' + outer
+}
+
+module.exports = {
+  prepareValue: function prepareValueWrapper (value) {
+    // this ensures that extra arguments do not get passed into prepareValue
+    // by accident, eg: from calling values.map(utils.prepareValue)
+    return prepareValue(value)
+  },
+  normalizeQueryConfig,
+  postgresMd5PasswordHash,
+  md5
+}
diff --git a/server/node_modules/pg/node_modules/.bin/semver b/server/node_modules/pg/node_modules/.bin/semver
new file mode 120000
index 0000000000000000000000000000000000000000..317eb293d8e125968256d4819f26caf2343475c4
--- /dev/null
+++ b/server/node_modules/pg/node_modules/.bin/semver
@@ -0,0 +1 @@
+../semver/bin/semver
\ No newline at end of file
diff --git a/server/node_modules/pg/node_modules/semver/.npmignore b/server/node_modules/pg/node_modules/semver/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..7300fbc79a748cd2ac71e493030bcb9f828ac67d
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/.npmignore
@@ -0,0 +1 @@
+# nada
diff --git a/server/node_modules/pg/node_modules/semver/LICENSE b/server/node_modules/pg/node_modules/semver/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..0c44ae716db8f353760831bbf55af8e2d0b63630
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) Isaac Z. Schlueter ("Author")
+All rights reserved.
+
+The BSD License
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/server/node_modules/pg/node_modules/semver/Makefile b/server/node_modules/pg/node_modules/semver/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..71af0e9750cd0aba158bd9dfd77fbdb6c8d765f3
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/Makefile
@@ -0,0 +1,24 @@
+files =  semver.browser.js \
+         semver.min.js \
+				 semver.browser.js.gz \
+				 semver.min.js.gz
+
+all: $(files)
+
+clean:
+	rm -f $(files)
+
+semver.browser.js: head.js.txt semver.js foot.js.txt
+	( cat head.js.txt; \
+		cat semver.js | \
+			egrep -v '^ *\/\* nomin \*\/' | \
+			perl -pi -e 's/debug\([^\)]+\)//g'; \
+		cat foot.js.txt ) > semver.browser.js
+
+semver.min.js: semver.browser.js
+	uglifyjs -m <semver.browser.js >semver.min.js
+
+%.gz: %
+	gzip --stdout -9 <$< >$@
+
+.PHONY: all clean
diff --git a/server/node_modules/pg/node_modules/semver/README.md b/server/node_modules/pg/node_modules/semver/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..b5e35ff0b5bd955f3985ffacf06a40e3639979cc
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/README.md
@@ -0,0 +1,303 @@
+semver(1) -- The semantic versioner for npm
+===========================================
+
+## Usage
+
+    $ npm install semver
+
+    semver.valid('1.2.3') // '1.2.3'
+    semver.valid('a.b.c') // null
+    semver.clean('  =v1.2.3   ') // '1.2.3'
+    semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true
+    semver.gt('1.2.3', '9.8.7') // false
+    semver.lt('1.2.3', '9.8.7') // true
+
+As a command-line utility:
+
+    $ semver -h
+
+    Usage: semver <version> [<version> [...]] [-r <range> | -i <inc> | --preid <identifier> | -l | -rv]
+    Test if version(s) satisfy the supplied range(s), and sort them.
+
+    Multiple versions or ranges may be supplied, unless increment
+    option is specified.  In that case, only a single version may
+    be used, and it is incremented by the specified level
+
+    Program exits successfully if any valid version satisfies
+    all supplied ranges, and prints all satisfying versions.
+
+    If no versions are valid, or ranges are not satisfied,
+    then exits failure.
+
+    Versions are printed in ascending order, so supplying
+    multiple versions to the utility will just sort them.
+
+## Versions
+
+A "version" is described by the `v2.0.0` specification found at
+<http://semver.org/>.
+
+A leading `"="` or `"v"` character is stripped off and ignored.
+
+## Ranges
+
+A `version range` is a set of `comparators` which specify versions
+that satisfy the range.
+
+A `comparator` is composed of an `operator` and a `version`.  The set
+of primitive `operators` is:
+
+* `<` Less than
+* `<=` Less than or equal to
+* `>` Greater than
+* `>=` Greater than or equal to
+* `=` Equal.  If no operator is specified, then equality is assumed,
+  so this operator is optional, but MAY be included.
+
+For example, the comparator `>=1.2.7` would match the versions
+`1.2.7`, `1.2.8`, `2.5.3`, and `1.3.9`, but not the versions `1.2.6`
+or `1.1.0`.
+
+Comparators can be joined by whitespace to form a `comparator set`,
+which is satisfied by the **intersection** of all of the comparators
+it includes.
+
+A range is composed of one or more comparator sets, joined by `||`.  A
+version matches a range if and only if every comparator in at least
+one of the `||`-separated comparator sets is satisfied by the version.
+
+For example, the range `>=1.2.7 <1.3.0` would match the versions
+`1.2.7`, `1.2.8`, and `1.2.99`, but not the versions `1.2.6`, `1.3.0`,
+or `1.1.0`.
+
+The range `1.2.7 || >=1.2.9 <2.0.0` would match the versions `1.2.7`,
+`1.2.9`, and `1.4.6`, but not the versions `1.2.8` or `2.0.0`.
+
+### Prerelease Tags
+
+If a version has a prerelease tag (for example, `1.2.3-alpha.3`) then
+it will only be allowed to satisfy comparator sets if at least one
+comparator with the same `[major, minor, patch]` tuple also has a
+prerelease tag.
+
+For example, the range `>1.2.3-alpha.3` would be allowed to match the
+version `1.2.3-alpha.7`, but it would *not* be satisfied by
+`3.4.5-alpha.9`, even though `3.4.5-alpha.9` is technically "greater
+than" `1.2.3-alpha.3` according to the SemVer sort rules.  The version
+range only accepts prerelease tags on the `1.2.3` version.  The
+version `3.4.5` *would* satisfy the range, because it does not have a
+prerelease flag, and `3.4.5` is greater than `1.2.3-alpha.7`.
+
+The purpose for this behavior is twofold.  First, prerelease versions
+frequently are updated very quickly, and contain many breaking changes
+that are (by the author's design) not yet fit for public consumption.
+Therefore, by default, they are excluded from range matching
+semantics.
+
+Second, a user who has opted into using a prerelease version has
+clearly indicated the intent to use *that specific* set of
+alpha/beta/rc versions.  By including a prerelease tag in the range,
+the user is indicating that they are aware of the risk.  However, it
+is still not appropriate to assume that they have opted into taking a
+similar risk on the *next* set of prerelease versions.
+
+#### Prerelease Identifiers
+
+The method `.inc` takes an additional `identifier` string argument that
+will append the value of the string as a prerelease identifier:
+
+```javascript
+> semver.inc('1.2.3', 'pre', 'beta')
+'1.2.4-beta.0'
+```
+
+command-line example:
+
+```shell
+$ semver 1.2.3 -i prerelease --preid beta
+1.2.4-beta.0
+```
+
+Which then can be used to increment further:
+
+```shell
+$ semver 1.2.4-beta.0 -i prerelease
+1.2.4-beta.1
+```
+
+### Advanced Range Syntax
+
+Advanced range syntax desugars to primitive comparators in
+deterministic ways.
+
+Advanced ranges may be combined in the same way as primitive
+comparators using white space or `||`.
+
+#### Hyphen Ranges `X.Y.Z - A.B.C`
+
+Specifies an inclusive set.
+
+* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`
+
+If a partial version is provided as the first version in the inclusive
+range, then the missing pieces are replaced with zeroes.
+
+* `1.2 - 2.3.4` := `>=1.2.0 <=2.3.4`
+
+If a partial version is provided as the second version in the
+inclusive range, then all versions that start with the supplied parts
+of the tuple are accepted, but nothing that would be greater than the
+provided tuple parts.
+
+* `1.2.3 - 2.3` := `>=1.2.3 <2.4.0`
+* `1.2.3 - 2` := `>=1.2.3 <3.0.0`
+
+#### X-Ranges `1.2.x` `1.X` `1.2.*` `*`
+
+Any of `X`, `x`, or `*` may be used to "stand in" for one of the
+numeric values in the `[major, minor, patch]` tuple.
+
+* `*` := `>=0.0.0` (Any version satisfies)
+* `1.x` := `>=1.0.0 <2.0.0` (Matching major version)
+* `1.2.x` := `>=1.2.0 <1.3.0` (Matching major and minor versions)
+
+A partial version range is treated as an X-Range, so the special
+character is in fact optional.
+
+* `""` (empty string) := `*` := `>=0.0.0`
+* `1` := `1.x.x` := `>=1.0.0 <2.0.0`
+* `1.2` := `1.2.x` := `>=1.2.0 <1.3.0`
+
+#### Tilde Ranges `~1.2.3` `~1.2` `~1`
+
+Allows patch-level changes if a minor version is specified on the
+comparator.  Allows minor-level changes if not.
+
+* `~1.2.3` := `>=1.2.3 <1.(2+1).0` := `>=1.2.3 <1.3.0`
+* `~1.2` := `>=1.2.0 <1.(2+1).0` := `>=1.2.0 <1.3.0` (Same as `1.2.x`)
+* `~1` := `>=1.0.0 <(1+1).0.0` := `>=1.0.0 <2.0.0` (Same as `1.x`)
+* `~0.2.3` := `>=0.2.3 <0.(2+1).0` := `>=0.2.3 <0.3.0`
+* `~0.2` := `>=0.2.0 <0.(2+1).0` := `>=0.2.0 <0.3.0` (Same as `0.2.x`)
+* `~0` := `>=0.0.0 <(0+1).0.0` := `>=0.0.0 <1.0.0` (Same as `0.x`)
+* `~1.2.3-beta.2` := `>=1.2.3-beta.2 <1.3.0` Note that prereleases in
+  the `1.2.3` version will be allowed, if they are greater than or
+  equal to `beta.2`.  So, `1.2.3-beta.4` would be allowed, but
+  `1.2.4-beta.2` would not, because it is a prerelease of a
+  different `[major, minor, patch]` tuple.
+
+#### Caret Ranges `^1.2.3` `^0.2.5` `^0.0.4`
+
+Allows changes that do not modify the left-most non-zero digit in the
+`[major, minor, patch]` tuple.  In other words, this allows patch and
+minor updates for versions `1.0.0` and above, patch updates for
+versions `0.X >=0.1.0`, and *no* updates for versions `0.0.X`.
+
+Many authors treat a `0.x` version as if the `x` were the major
+"breaking-change" indicator.
+
+Caret ranges are ideal when an author may make breaking changes
+between `0.2.4` and `0.3.0` releases, which is a common practice.
+However, it presumes that there will *not* be breaking changes between
+`0.2.4` and `0.2.5`.  It allows for changes that are presumed to be
+additive (but non-breaking), according to commonly observed practices.
+
+* `^1.2.3` := `>=1.2.3 <2.0.0`
+* `^0.2.3` := `>=0.2.3 <0.3.0`
+* `^0.0.3` := `>=0.0.3 <0.0.4`
+* `^1.2.3-beta.2` := `>=1.2.3-beta.2 <2.0.0` Note that prereleases in
+  the `1.2.3` version will be allowed, if they are greater than or
+  equal to `beta.2`.  So, `1.2.3-beta.4` would be allowed, but
+  `1.2.4-beta.2` would not, because it is a prerelease of a
+  different `[major, minor, patch]` tuple.
+* `^0.0.3-beta` := `>=0.0.3-beta <0.0.4`  Note that prereleases in the
+  `0.0.3` version *only* will be allowed, if they are greater than or
+  equal to `beta`.  So, `0.0.3-pr.2` would be allowed.
+
+When parsing caret ranges, a missing `patch` value desugars to the
+number `0`, but will allow flexibility within that value, even if the
+major and minor versions are both `0`.
+
+* `^1.2.x` := `>=1.2.0 <2.0.0`
+* `^0.0.x` := `>=0.0.0 <0.1.0`
+* `^0.0` := `>=0.0.0 <0.1.0`
+
+A missing `minor` and `patch` values will desugar to zero, but also
+allow flexibility within those values, even if the major version is
+zero.
+
+* `^1.x` := `>=1.0.0 <2.0.0`
+* `^0.x` := `>=0.0.0 <1.0.0`
+
+## Functions
+
+All methods and classes take a final `loose` boolean argument that, if
+true, will be more forgiving about not-quite-valid semver strings.
+The resulting output will always be 100% strict, of course.
+
+Strict-mode Comparators and Ranges will be strict about the SemVer
+strings that they parse.
+
+* `valid(v)`: Return the parsed version, or null if it's not valid.
+* `inc(v, release)`: Return the version incremented by the release
+  type (`major`,   `premajor`, `minor`, `preminor`, `patch`,
+  `prepatch`, or `prerelease`), or null if it's not valid
+  * `premajor` in one call will bump the version up to the next major
+    version and down to a prerelease of that major version.
+    `preminor`, and `prepatch` work the same way.
+  * If called from a non-prerelease version, the `prerelease` will work the
+    same as `prepatch`. It increments the patch version, then makes a
+    prerelease. If the input version is already a prerelease it simply
+    increments it.
+* `major(v)`: Return the major version number.
+* `minor(v)`: Return the minor version number.
+* `patch(v)`: Return the patch version number.
+
+### Comparison
+
+* `gt(v1, v2)`: `v1 > v2`
+* `gte(v1, v2)`: `v1 >= v2`
+* `lt(v1, v2)`: `v1 < v2`
+* `lte(v1, v2)`: `v1 <= v2`
+* `eq(v1, v2)`: `v1 == v2` This is true if they're logically equivalent,
+  even if they're not the exact same string.  You already know how to
+  compare strings.
+* `neq(v1, v2)`: `v1 != v2` The opposite of `eq`.
+* `cmp(v1, comparator, v2)`: Pass in a comparison string, and it'll call
+  the corresponding function above.  `"==="` and `"!=="` do simple
+  string comparison, but are included for completeness.  Throws if an
+  invalid comparison string is provided.
+* `compare(v1, v2)`: Return `0` if `v1 == v2`, or `1` if `v1` is greater, or `-1` if
+  `v2` is greater.  Sorts in ascending order if passed to `Array.sort()`.
+* `rcompare(v1, v2)`: The reverse of compare.  Sorts an array of versions
+  in descending order when passed to `Array.sort()`.
+* `diff(v1, v2)`: Returns difference between two versions by the release type
+  (`major`, `premajor`, `minor`, `preminor`, `patch`, `prepatch`, or `prerelease`),
+  or null if the versions are the same.
+
+
+### Ranges
+
+* `validRange(range)`: Return the valid range or null if it's not valid
+* `satisfies(version, range)`: Return true if the version satisfies the
+  range.
+* `maxSatisfying(versions, range)`: Return the highest version in the list
+  that satisfies the range, or `null` if none of them do.
+* `gtr(version, range)`: Return `true` if version is greater than all the
+  versions possible in the range.
+* `ltr(version, range)`: Return `true` if version is less than all the
+  versions possible in the range.
+* `outside(version, range, hilo)`: Return true if the version is outside
+  the bounds of the range in either the high or low direction.  The
+  `hilo` argument must be either the string `'>'` or `'<'`.  (This is
+  the function called by `gtr` and `ltr`.)
+
+Note that, since ranges may be non-contiguous, a version might not be
+greater than a range, less than a range, *or* satisfy a range!  For
+example, the range `1.2 <1.2.9 || >2.0.0` would have a hole from `1.2.9`
+until `2.0.0`, so the version `1.2.10` would not be greater than the
+range (because `2.0.1` satisfies, which is higher), nor less than the
+range (since `1.2.8` satisfies, which is lower), and it also does not
+satisfy the range.
+
+If you want to know if a version satisfies or does not satisfy a
+range, use the `satisfies(version, range)` function.
diff --git a/server/node_modules/pg/node_modules/semver/bin/semver b/server/node_modules/pg/node_modules/semver/bin/semver
new file mode 100755
index 0000000000000000000000000000000000000000..c5f2e857e8279083438589cfb06427997b6a5618
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/bin/semver
@@ -0,0 +1,133 @@
+#!/usr/bin/env node
+// Standalone semver comparison program.
+// Exits successfully and prints matching version(s) if
+// any supplied version is valid and passes all tests.
+
+var argv = process.argv.slice(2)
+  , versions = []
+  , range = []
+  , gt = []
+  , lt = []
+  , eq = []
+  , inc = null
+  , version = require("../package.json").version
+  , loose = false
+  , identifier = undefined
+  , semver = require("../semver")
+  , reverse = false
+
+main()
+
+function main () {
+  if (!argv.length) return help()
+  while (argv.length) {
+    var a = argv.shift()
+    var i = a.indexOf('=')
+    if (i !== -1) {
+      a = a.slice(0, i)
+      argv.unshift(a.slice(i + 1))
+    }
+    switch (a) {
+      case "-rv": case "-rev": case "--rev": case "--reverse":
+        reverse = true
+        break
+      case "-l": case "--loose":
+        loose = true
+        break
+      case "-v": case "--version":
+        versions.push(argv.shift())
+        break
+      case "-i": case "--inc": case "--increment":
+        switch (argv[0]) {
+          case "major": case "minor": case "patch": case "prerelease":
+          case "premajor": case "preminor": case "prepatch":
+            inc = argv.shift()
+            break
+          default:
+            inc = "patch"
+            break
+        }
+        break
+      case "--preid":
+        identifier = argv.shift()
+        break
+      case "-r": case "--range":
+        range.push(argv.shift())
+        break
+      case "-h": case "--help": case "-?":
+        return help()
+      default:
+        versions.push(a)
+        break
+    }
+  }
+
+  versions = versions.filter(function (v) {
+    return semver.valid(v, loose)
+  })
+  if (!versions.length) return fail()
+  if (inc && (versions.length !== 1 || range.length))
+    return failInc()
+
+  for (var i = 0, l = range.length; i < l ; i ++) {
+    versions = versions.filter(function (v) {
+      return semver.satisfies(v, range[i], loose)
+    })
+    if (!versions.length) return fail()
+  }
+  return success(versions)
+}
+
+function failInc () {
+  console.error("--inc can only be used on a single version with no range")
+  fail()
+}
+
+function fail () { process.exit(1) }
+
+function success () {
+  var compare = reverse ? "rcompare" : "compare"
+  versions.sort(function (a, b) {
+    return semver[compare](a, b, loose)
+  }).map(function (v) {
+    return semver.clean(v, loose)
+  }).map(function (v) {
+    return inc ? semver.inc(v, inc, loose, identifier) : v
+  }).forEach(function (v,i,_) { console.log(v) })
+}
+
+function help () {
+  console.log(["SemVer " + version
+              ,""
+              ,"A JavaScript implementation of the http://semver.org/ specification"
+              ,"Copyright Isaac Z. Schlueter"
+              ,""
+              ,"Usage: semver [options] <version> [<version> [...]]"
+              ,"Prints valid versions sorted by SemVer precedence"
+              ,""
+              ,"Options:"
+              ,"-r --range <range>"
+              ,"        Print versions that match the specified range."
+              ,""
+              ,"-i --increment [<level>]"
+              ,"        Increment a version by the specified level.  Level can"
+              ,"        be one of: major, minor, patch, premajor, preminor,"
+              ,"        prepatch, or prerelease.  Default level is 'patch'."
+              ,"        Only one version may be specified."
+              ,""
+              ,"--preid <identifier>"
+              ,"        Identifier to be used to prefix premajor, preminor,"
+              ,"        prepatch or prerelease version increments."
+              ,""
+              ,"-l --loose"
+              ,"        Interpret versions and ranges loosely"
+              ,""
+              ,"Program exits successfully if any valid version satisfies"
+              ,"all supplied ranges, and prints all satisfying versions."
+              ,""
+              ,"If no satisfying versions are found, then exits failure."
+              ,""
+              ,"Versions are printed in ascending order, so supplying"
+              ,"multiple versions to the utility will just sort them."
+              ].join("\n"))
+}
diff --git a/server/node_modules/pg/node_modules/semver/foot.js.txt b/server/node_modules/pg/node_modules/semver/foot.js.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8f83c20f8ed5a6476875e9cc61b2a82812fa500f
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/foot.js.txt
@@ -0,0 +1,6 @@
+
+})(
+  typeof exports === 'object' ? exports :
+  typeof define === 'function' && define.amd ? {} :
+  semver = {}
+);
diff --git a/server/node_modules/pg/node_modules/semver/head.js.txt b/server/node_modules/pg/node_modules/semver/head.js.txt
new file mode 100644
index 0000000000000000000000000000000000000000..65368651777d286654883ff03b6dc5d49c7bba4e
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/head.js.txt
@@ -0,0 +1,2 @@
+;(function(exports) {
+
diff --git a/server/node_modules/pg/node_modules/semver/package.json b/server/node_modules/pg/node_modules/semver/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..142a2b8fab7ab15a016708f8606106c706722da2
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/package.json
@@ -0,0 +1,53 @@
+{
+  "_from": "semver@4.3.2",
+  "_id": "semver@4.3.2",
+  "_inBundle": false,
+  "_integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=",
+  "_location": "/pg/semver",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "semver@4.3.2",
+    "name": "semver",
+    "escapedName": "semver",
+    "rawSpec": "4.3.2",
+    "saveSpec": null,
+    "fetchSpec": "4.3.2"
+  },
+  "_requiredBy": [
+    "/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz",
+  "_shasum": "c7a07158a80bedd052355b770d82d6640f803be7",
+  "_spec": "semver@4.3.2",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg",
+  "bin": {
+    "semver": "./bin/semver"
+  },
+  "browser": "semver.browser.js",
+  "bugs": {
+    "url": "https://github.com/npm/node-semver/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "The semantic version parser used by npm.",
+  "devDependencies": {
+    "tap": "0.x >=0.0.4",
+    "uglify-js": "~2.3.6"
+  },
+  "homepage": "https://github.com/npm/node-semver#readme",
+  "license": "BSD",
+  "main": "semver.js",
+  "min": "semver.min.js",
+  "name": "semver",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/npm/node-semver.git"
+  },
+  "scripts": {
+    "prepublish": "make",
+    "test": "tap test/*.js"
+  },
+  "version": "4.3.2"
+}
diff --git a/server/node_modules/pg/node_modules/semver/semver.browser.js b/server/node_modules/pg/node_modules/semver/semver.browser.js
new file mode 100644
index 0000000000000000000000000000000000000000..250885a7e7ed3906544c84796ee53cb9ee703177
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/semver.browser.js
@@ -0,0 +1,1187 @@
+;(function(exports) {
+
+// export the class if we are in a Node-like system.
+if (typeof module === 'object' && module.exports === exports)
+  exports = module.exports = SemVer;
+
+// The debug function is excluded entirely from the minified version.
+
+// Note: this is the semver.org version of the spec that it implements
+// Not necessarily the package version of this code.
+exports.SEMVER_SPEC_VERSION = '2.0.0';
+
+var MAX_LENGTH = 256;
+var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
+
+// The actual regexps go on exports.re
+var re = exports.re = [];
+var src = exports.src = [];
+var R = 0;
+
+// The following Regular Expressions can be used for tokenizing,
+// validating, and parsing SemVer version strings.
+
+// ## Numeric Identifier
+// A single `0`, or a non-zero digit followed by zero or more digits.
+
+var NUMERICIDENTIFIER = R++;
+src[NUMERICIDENTIFIER] = '0|[1-9]\\d*';
+var NUMERICIDENTIFIERLOOSE = R++;
+src[NUMERICIDENTIFIERLOOSE] = '[0-9]+';
+
+
+// ## Non-numeric Identifier
+// Zero or more digits, followed by a letter or hyphen, and then zero or
+// more letters, digits, or hyphens.
+
+var NONNUMERICIDENTIFIER = R++;
+src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*';
+
+
+// ## Main Version
+// Three dot-separated numeric identifiers.
+
+var MAINVERSION = R++;
+src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' +
+                   '(' + src[NUMERICIDENTIFIER] + ')\\.' +
+                   '(' + src[NUMERICIDENTIFIER] + ')';
+
+var MAINVERSIONLOOSE = R++;
+src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
+                        '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
+                        '(' + src[NUMERICIDENTIFIERLOOSE] + ')';
+
+// ## Pre-release Version Identifier
+// A numeric identifier, or a non-numeric identifier.
+
+var PRERELEASEIDENTIFIER = R++;
+src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] +
+                            '|' + src[NONNUMERICIDENTIFIER] + ')';
+
+var PRERELEASEIDENTIFIERLOOSE = R++;
+src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] +
+                                 '|' + src[NONNUMERICIDENTIFIER] + ')';
+
+
+// ## Pre-release Version
+// Hyphen, followed by one or more dot-separated pre-release version
+// identifiers.
+
+var PRERELEASE = R++;
+src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] +
+                  '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))';
+
+var PRERELEASELOOSE = R++;
+src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] +
+                       '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))';
+
+// ## Build Metadata Identifier
+// Any combination of digits, letters, or hyphens.
+
+var BUILDIDENTIFIER = R++;
+src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+';
+
+// ## Build Metadata
+// Plus sign, followed by one or more period-separated build metadata
+// identifiers.
+
+var BUILD = R++;
+src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] +
+             '(?:\\.' + src[BUILDIDENTIFIER] + ')*))';
+
+
+// ## Full Version String
+// A main version, followed optionally by a pre-release version and
+// build metadata.
+
+// Note that the only major, minor, patch, and pre-release sections of
+// the version string are capturing groups.  The build metadata is not a
+// capturing group, because it should not ever be used in version
+// comparison.
+
+var FULL = R++;
+var FULLPLAIN = 'v?' + src[MAINVERSION] +
+                src[PRERELEASE] + '?' +
+                src[BUILD] + '?';
+
+src[FULL] = '^' + FULLPLAIN + '$';
+
+// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
+// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
+// common in the npm registry.
+var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] +
+                 src[PRERELEASELOOSE] + '?' +
+                 src[BUILD] + '?';
+
+var LOOSE = R++;
+src[LOOSE] = '^' + LOOSEPLAIN + '$';
+
+var GTLT = R++;
+src[GTLT] = '((?:<|>)?=?)';
+
+// Something like "2.*" or "1.2.x".
+// Note that "x.x" is a valid xRange identifer, meaning "any version"
+// Only the first item is strictly required.
+var XRANGEIDENTIFIERLOOSE = R++;
+src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*';
+var XRANGEIDENTIFIER = R++;
+src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*';
+
+var XRANGEPLAIN = R++;
+src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:' + src[PRERELEASE] + ')?' +
+                   src[BUILD] + '?' +
+                   ')?)?';
+
+var XRANGEPLAINLOOSE = R++;
+src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:' + src[PRERELEASELOOSE] + ')?' +
+                        src[BUILD] + '?' +
+                        ')?)?';
+
+var XRANGE = R++;
+src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$';
+var XRANGELOOSE = R++;
+src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$';
+
+// Tilde ranges.
+// Meaning is "reasonably at or greater than"
+var LONETILDE = R++;
+src[LONETILDE] = '(?:~>?)';
+
+var TILDETRIM = R++;
+src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+';
+re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g');
+var tildeTrimReplace = '$1~';
+
+var TILDE = R++;
+src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$';
+var TILDELOOSE = R++;
+src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$';
+
+// Caret ranges.
+// Meaning is "at least and backwards compatible with"
+var LONECARET = R++;
+src[LONECARET] = '(?:\\^)';
+
+var CARETTRIM = R++;
+src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+';
+re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g');
+var caretTrimReplace = '$1^';
+
+var CARET = R++;
+src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$';
+var CARETLOOSE = R++;
+src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$';
+
+// A simple gt/lt/eq thing, or just "" to indicate "any version"
+var COMPARATORLOOSE = R++;
+src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$';
+var COMPARATOR = R++;
+src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$';
+
+
+// An expression to strip any whitespace between the gtlt and the thing
+// it modifies, so that `> 1.2.3` ==> `>1.2.3`
+var COMPARATORTRIM = R++;
+src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] +
+                      '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')';
+
+// this one has to use the /g flag
+re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g');
+var comparatorTrimReplace = '$1$2$3';
+
+
+// Something like `1.2.3 - 1.2.4`
+// Note that these all use the loose form, because they'll be
+// checked against either the strict or loose comparator form
+// later.
+var HYPHENRANGE = R++;
+src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' +
+                   '\\s+-\\s+' +
+                   '(' + src[XRANGEPLAIN] + ')' +
+                   '\\s*$';
+
+var HYPHENRANGELOOSE = R++;
+src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' +
+                        '\\s+-\\s+' +
+                        '(' + src[XRANGEPLAINLOOSE] + ')' +
+                        '\\s*$';
+
+// Star ranges basically just allow anything at all.
+var STAR = R++;
+src[STAR] = '(<|>)?=?\\s*\\*';
+
+// Compile to actual regexp objects.
+// All are flag-free, unless they were created above with a flag.
+for (var i = 0; i < R; i++) {
+  ;
+  if (!re[i])
+    re[i] = new RegExp(src[i]);
+}
+
+exports.parse = parse;
+function parse(version, loose) {
+  if (version.length > MAX_LENGTH)
+    return null;
+
+  var r = loose ? re[LOOSE] : re[FULL];
+  if (!r.test(version))
+    return null;
+
+  try {
+    return new SemVer(version, loose);
+  } catch (er) {
+    return null;
+  }
+}
+
+exports.valid = valid;
+function valid(version, loose) {
+  var v = parse(version, loose);
+  return v ? v.version : null;
+}
+
+
+exports.clean = clean;
+function clean(version, loose) {
+  var s = parse(version.trim().replace(/^[=v]+/, ''), loose);
+  return s ? s.version : null;
+}
+
+exports.SemVer = SemVer;
+
+function SemVer(version, loose) {
+  if (version instanceof SemVer) {
+    if (version.loose === loose)
+      return version;
+    else
+      version = version.version;
+  } else if (typeof version !== 'string') {
+    throw new TypeError('Invalid Version: ' + version);
+  }
+
+  if (version.length > MAX_LENGTH)
+    throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters')
+
+  if (!(this instanceof SemVer))
+    return new SemVer(version, loose);
+
+  ;
+  this.loose = loose;
+  var m = version.trim().match(loose ? re[LOOSE] : re[FULL]);
+
+  if (!m)
+    throw new TypeError('Invalid Version: ' + version);
+
+  this.raw = version;
+
+  // these are actually numbers
+  this.major = +m[1];
+  this.minor = +m[2];
+  this.patch = +m[3];
+
+  if (this.major > MAX_SAFE_INTEGER || this.major < 0)
+    throw new TypeError('Invalid major version')
+
+  if (this.minor > MAX_SAFE_INTEGER || this.minor < 0)
+    throw new TypeError('Invalid minor version')
+
+  if (this.patch > MAX_SAFE_INTEGER || this.patch < 0)
+    throw new TypeError('Invalid patch version')
+
+  // numberify any prerelease numeric ids
+  if (!m[4])
+    this.prerelease = [];
+  else
+    this.prerelease = m[4].split('.').map(function(id) {
+      return (/^[0-9]+$/.test(id)) ? +id : id;
+    });
+
+  this.build = m[5] ? m[5].split('.') : [];
+  this.format();
+}
+
+SemVer.prototype.format = function() {
+  this.version = this.major + '.' + this.minor + '.' + this.patch;
+  if (this.prerelease.length)
+    this.version += '-' + this.prerelease.join('.');
+  return this.version;
+};
+
+SemVer.prototype.inspect = function() {
+  return '<SemVer "' + this + '">';
+};
+
+SemVer.prototype.toString = function() {
+  return this.version;
+};
+
+SemVer.prototype.compare = function(other) {
+  ;
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  return this.compareMain(other) || this.comparePre(other);
+};
+
+SemVer.prototype.compareMain = function(other) {
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  return compareIdentifiers(this.major, other.major) ||
+         compareIdentifiers(this.minor, other.minor) ||
+         compareIdentifiers(this.patch, other.patch);
+};
+
+SemVer.prototype.comparePre = function(other) {
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  // NOT having a prerelease is > having one
+  if (this.prerelease.length && !other.prerelease.length)
+    return -1;
+  else if (!this.prerelease.length && other.prerelease.length)
+    return 1;
+  else if (!this.prerelease.length && !other.prerelease.length)
+    return 0;
+
+  var i = 0;
+  do {
+    var a = this.prerelease[i];
+    var b = other.prerelease[i];
+    ;
+    if (a === undefined && b === undefined)
+      return 0;
+    else if (b === undefined)
+      return 1;
+    else if (a === undefined)
+      return -1;
+    else if (a === b)
+      continue;
+    else
+      return compareIdentifiers(a, b);
+  } while (++i);
+};
+
+// preminor will bump the version up to the next minor release, and immediately
+// down to pre-release. premajor and prepatch work the same way.
+SemVer.prototype.inc = function(release, identifier) {
+  switch (release) {
+    case 'premajor':
+      this.prerelease.length = 0;
+      this.patch = 0;
+      this.minor = 0;
+      this.major++;
+      this.inc('pre', identifier);
+      break;
+    case 'preminor':
+      this.prerelease.length = 0;
+      this.patch = 0;
+      this.minor++;
+      this.inc('pre', identifier);
+      break;
+    case 'prepatch':
+      // If this is already a prerelease, it will bump to the next version
+      // drop any prereleases that might already exist, since they are not
+      // relevant at this point.
+      this.prerelease.length = 0;
+      this.inc('patch', identifier);
+      this.inc('pre', identifier);
+      break;
+    // If the input is a non-prerelease version, this acts the same as
+    // prepatch.
+    case 'prerelease':
+      if (this.prerelease.length === 0)
+        this.inc('patch', identifier);
+      this.inc('pre', identifier);
+      break;
+
+    case 'major':
+      // If this is a pre-major version, bump up to the same major version.
+      // Otherwise increment major.
+      // 1.0.0-5 bumps to 1.0.0
+      // 1.1.0 bumps to 2.0.0
+      if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0)
+        this.major++;
+      this.minor = 0;
+      this.patch = 0;
+      this.prerelease = [];
+      break;
+    case 'minor':
+      // If this is a pre-minor version, bump up to the same minor version.
+      // Otherwise increment minor.
+      // 1.2.0-5 bumps to 1.2.0
+      // 1.2.1 bumps to 1.3.0
+      if (this.patch !== 0 || this.prerelease.length === 0)
+        this.minor++;
+      this.patch = 0;
+      this.prerelease = [];
+      break;
+    case 'patch':
+      // If this is not a pre-release version, it will increment the patch.
+      // If it is a pre-release it will bump up to the same patch version.
+      // 1.2.0-5 patches to 1.2.0
+      // 1.2.0 patches to 1.2.1
+      if (this.prerelease.length === 0)
+        this.patch++;
+      this.prerelease = [];
+      break;
+    // This probably shouldn't be used publicly.
+    // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
+    case 'pre':
+      if (this.prerelease.length === 0)
+        this.prerelease = [0];
+      else {
+        var i = this.prerelease.length;
+        while (--i >= 0) {
+          if (typeof this.prerelease[i] === 'number') {
+            this.prerelease[i]++;
+            i = -2;
+          }
+        }
+        if (i === -1) // didn't increment anything
+          this.prerelease.push(0);
+      }
+      if (identifier) {
+        // 1.2.0-beta.1 bumps to 1.2.0-beta.2,
+        // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
+        if (this.prerelease[0] === identifier) {
+          if (isNaN(this.prerelease[1]))
+            this.prerelease = [identifier, 0];
+        } else
+          this.prerelease = [identifier, 0];
+      }
+      break;
+
+    default:
+      throw new Error('invalid increment argument: ' + release);
+  }
+  this.format();
+  return this;
+};
+
+exports.inc = inc;
+function inc(version, release, loose, identifier) {
+  if (typeof(loose) === 'string') {
+    identifier = loose;
+    loose = undefined;
+  }
+
+  try {
+    return new SemVer(version, loose).inc(release, identifier).version;
+  } catch (er) {
+    return null;
+  }
+}
+
+exports.diff = diff;
+function diff(version1, version2) {
+  if (eq(version1, version2)) {
+    return null;
+  } else {
+    var v1 = parse(version1);
+    var v2 = parse(version2);
+    if (v1.prerelease.length || v2.prerelease.length) {
+      for (var key in v1) {
+        if (key === 'major' || key === 'minor' || key === 'patch') {
+          if (v1[key] !== v2[key]) {
+            return 'pre'+key;
+          }
+        }
+      }
+      return 'prerelease';
+    }
+    for (var key in v1) {
+      if (key === 'major' || key === 'minor' || key === 'patch') {
+        if (v1[key] !== v2[key]) {
+          return key;
+        }
+      }
+    }
+  }
+}
+
+exports.compareIdentifiers = compareIdentifiers;
+
+var numeric = /^[0-9]+$/;
+function compareIdentifiers(a, b) {
+  var anum = numeric.test(a);
+  var bnum = numeric.test(b);
+
+  if (anum && bnum) {
+    a = +a;
+    b = +b;
+  }
+
+  return (anum && !bnum) ? -1 :
+         (bnum && !anum) ? 1 :
+         a < b ? -1 :
+         a > b ? 1 :
+         0;
+}
+
+exports.rcompareIdentifiers = rcompareIdentifiers;
+function rcompareIdentifiers(a, b) {
+  return compareIdentifiers(b, a);
+}
+
+exports.major = major;
+function major(a, loose) {
+  return new SemVer(a, loose).major;
+}
+
+exports.minor = minor;
+function minor(a, loose) {
+  return new SemVer(a, loose).minor;
+}
+
+exports.patch = patch;
+function patch(a, loose) {
+  return new SemVer(a, loose).patch;
+}
+
+exports.compare = compare;
+function compare(a, b, loose) {
+  return new SemVer(a, loose).compare(b);
+}
+
+exports.compareLoose = compareLoose;
+function compareLoose(a, b) {
+  return compare(a, b, true);
+}
+
+exports.rcompare = rcompare;
+function rcompare(a, b, loose) {
+  return compare(b, a, loose);
+}
+
+exports.sort = sort;
+function sort(list, loose) {
+  return list.sort(function(a, b) {
+    return exports.compare(a, b, loose);
+  });
+}
+
+exports.rsort = rsort;
+function rsort(list, loose) {
+  return list.sort(function(a, b) {
+    return exports.rcompare(a, b, loose);
+  });
+}
+
+exports.gt = gt;
+function gt(a, b, loose) {
+  return compare(a, b, loose) > 0;
+}
+
+exports.lt = lt;
+function lt(a, b, loose) {
+  return compare(a, b, loose) < 0;
+}
+
+exports.eq = eq;
+function eq(a, b, loose) {
+  return compare(a, b, loose) === 0;
+}
+
+exports.neq = neq;
+function neq(a, b, loose) {
+  return compare(a, b, loose) !== 0;
+}
+
+exports.gte = gte;
+function gte(a, b, loose) {
+  return compare(a, b, loose) >= 0;
+}
+
+exports.lte = lte;
+function lte(a, b, loose) {
+  return compare(a, b, loose) <= 0;
+}
+
+exports.cmp = cmp;
+function cmp(a, op, b, loose) {
+  var ret;
+  switch (op) {
+    case '===':
+      if (typeof a === 'object') a = a.version;
+      if (typeof b === 'object') b = b.version;
+      ret = a === b;
+      break;
+    case '!==':
+      if (typeof a === 'object') a = a.version;
+      if (typeof b === 'object') b = b.version;
+      ret = a !== b;
+      break;
+    case '': case '=': case '==': ret = eq(a, b, loose); break;
+    case '!=': ret = neq(a, b, loose); break;
+    case '>': ret = gt(a, b, loose); break;
+    case '>=': ret = gte(a, b, loose); break;
+    case '<': ret = lt(a, b, loose); break;
+    case '<=': ret = lte(a, b, loose); break;
+    default: throw new TypeError('Invalid operator: ' + op);
+  }
+  return ret;
+}
+
+exports.Comparator = Comparator;
+function Comparator(comp, loose) {
+  if (comp instanceof Comparator) {
+    if (comp.loose === loose)
+      return comp;
+    else
+      comp = comp.value;
+  }
+
+  if (!(this instanceof Comparator))
+    return new Comparator(comp, loose);
+
+  ;
+  this.loose = loose;
+  this.parse(comp);
+
+  if (this.semver === ANY)
+    this.value = '';
+  else
+    this.value = this.operator + this.semver.version;
+
+  ;
+}
+
+var ANY = {};
+Comparator.prototype.parse = function(comp) {
+  var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR];
+  var m = comp.match(r);
+
+  if (!m)
+    throw new TypeError('Invalid comparator: ' + comp);
+
+  this.operator = m[1];
+  if (this.operator === '=')
+    this.operator = '';
+
+  // if it literally is just '>' or '' then allow anything.
+  if (!m[2])
+    this.semver = ANY;
+  else
+    this.semver = new SemVer(m[2], this.loose);
+};
+
+Comparator.prototype.inspect = function() {
+  return '<SemVer Comparator "' + this + '">';
+};
+
+Comparator.prototype.toString = function() {
+  return this.value;
+};
+
+Comparator.prototype.test = function(version) {
+  ;
+
+  if (this.semver === ANY)
+    return true;
+
+  if (typeof version === 'string')
+    version = new SemVer(version, this.loose);
+
+  return cmp(version, this.operator, this.semver, this.loose);
+};
+
+
+exports.Range = Range;
+function Range(range, loose) {
+  if ((range instanceof Range) && range.loose === loose)
+    return range;
+
+  if (!(this instanceof Range))
+    return new Range(range, loose);
+
+  this.loose = loose;
+
+  // First, split based on boolean or ||
+  this.raw = range;
+  this.set = range.split(/\s*\|\|\s*/).map(function(range) {
+    return this.parseRange(range.trim());
+  }, this).filter(function(c) {
+    // throw out any that are not relevant for whatever reason
+    return c.length;
+  });
+
+  if (!this.set.length) {
+    throw new TypeError('Invalid SemVer Range: ' + range);
+  }
+
+  this.format();
+}
+
+Range.prototype.inspect = function() {
+  return '<SemVer Range "' + this.range + '">';
+};
+
+Range.prototype.format = function() {
+  this.range = this.set.map(function(comps) {
+    return comps.join(' ').trim();
+  }).join('||').trim();
+  return this.range;
+};
+
+Range.prototype.toString = function() {
+  return this.range;
+};
+
+Range.prototype.parseRange = function(range) {
+  var loose = this.loose;
+  range = range.trim();
+  ;
+  // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
+  var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE];
+  range = range.replace(hr, hyphenReplace);
+  ;
+  // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
+  range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace);
+  ;
+
+  // `~ 1.2.3` => `~1.2.3`
+  range = range.replace(re[TILDETRIM], tildeTrimReplace);
+
+  // `^ 1.2.3` => `^1.2.3`
+  range = range.replace(re[CARETTRIM], caretTrimReplace);
+
+  // normalize spaces
+  range = range.split(/\s+/).join(' ');
+
+  // At this point, the range is completely trimmed and
+  // ready to be split into comparators.
+
+  var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR];
+  var set = range.split(' ').map(function(comp) {
+    return parseComparator(comp, loose);
+  }).join(' ').split(/\s+/);
+  if (this.loose) {
+    // in loose mode, throw out any that are not valid comparators
+    set = set.filter(function(comp) {
+      return !!comp.match(compRe);
+    });
+  }
+  set = set.map(function(comp) {
+    return new Comparator(comp, loose);
+  });
+
+  return set;
+};
+
+// Mostly just for testing and legacy API reasons
+exports.toComparators = toComparators;
+function toComparators(range, loose) {
+  return new Range(range, loose).set.map(function(comp) {
+    return comp.map(function(c) {
+      return c.value;
+    }).join(' ').trim().split(' ');
+  });
+}
+
+// comprised of xranges, tildes, stars, and gtlt's at this point.
+// already replaced the hyphen ranges
+// turn into a set of JUST comparators.
+function parseComparator(comp, loose) {
+  ;
+  comp = replaceCarets(comp, loose);
+  ;
+  comp = replaceTildes(comp, loose);
+  ;
+  comp = replaceXRanges(comp, loose);
+  ;
+  comp = replaceStars(comp, loose);
+  ;
+  return comp;
+}
+
+function isX(id) {
+  return !id || id.toLowerCase() === 'x' || id === '*';
+}
+
+// ~, ~> --> * (any, kinda silly)
+// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
+// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
+// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
+// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
+// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
+function replaceTildes(comp, loose) {
+  return comp.trim().split(/\s+/).map(function(comp) {
+    return replaceTilde(comp, loose);
+  }).join(' ');
+}
+
+function replaceTilde(comp, loose) {
+  var r = loose ? re[TILDELOOSE] : re[TILDE];
+  return comp.replace(r, function(_, M, m, p, pr) {
+    ;
+    var ret;
+
+    if (isX(M))
+      ret = '';
+    else if (isX(m))
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    else if (isX(p))
+      // ~1.2 == >=1.2.0- <1.3.0-
+      ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+    else if (pr) {
+      ;
+      if (pr.charAt(0) !== '-')
+        pr = '-' + pr;
+      ret = '>=' + M + '.' + m + '.' + p + pr +
+            ' <' + M + '.' + (+m + 1) + '.0';
+    } else
+      // ~1.2.3 == >=1.2.3 <1.3.0
+      ret = '>=' + M + '.' + m + '.' + p +
+            ' <' + M + '.' + (+m + 1) + '.0';
+
+    ;
+    return ret;
+  });
+}
+
+// ^ --> * (any, kinda silly)
+// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
+// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
+// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
+// ^1.2.3 --> >=1.2.3 <2.0.0
+// ^1.2.0 --> >=1.2.0 <2.0.0
+function replaceCarets(comp, loose) {
+  return comp.trim().split(/\s+/).map(function(comp) {
+    return replaceCaret(comp, loose);
+  }).join(' ');
+}
+
+function replaceCaret(comp, loose) {
+  ;
+  var r = loose ? re[CARETLOOSE] : re[CARET];
+  return comp.replace(r, function(_, M, m, p, pr) {
+    ;
+    var ret;
+
+    if (isX(M))
+      ret = '';
+    else if (isX(m))
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    else if (isX(p)) {
+      if (M === '0')
+        ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+      else
+        ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0';
+    } else if (pr) {
+      ;
+      if (pr.charAt(0) !== '-')
+        pr = '-' + pr;
+      if (M === '0') {
+        if (m === '0')
+          ret = '>=' + M + '.' + m + '.' + p + pr +
+                ' <' + M + '.' + m + '.' + (+p + 1);
+        else
+          ret = '>=' + M + '.' + m + '.' + p + pr +
+                ' <' + M + '.' + (+m + 1) + '.0';
+      } else
+        ret = '>=' + M + '.' + m + '.' + p + pr +
+              ' <' + (+M + 1) + '.0.0';
+    } else {
+      ;
+      if (M === '0') {
+        if (m === '0')
+          ret = '>=' + M + '.' + m + '.' + p +
+                ' <' + M + '.' + m + '.' + (+p + 1);
+        else
+          ret = '>=' + M + '.' + m + '.' + p +
+                ' <' + M + '.' + (+m + 1) + '.0';
+      } else
+        ret = '>=' + M + '.' + m + '.' + p +
+              ' <' + (+M + 1) + '.0.0';
+    }
+
+    ;
+    return ret;
+  });
+}
+
+function replaceXRanges(comp, loose) {
+  ;
+  return comp.split(/\s+/).map(function(comp) {
+    return replaceXRange(comp, loose);
+  }).join(' ');
+}
+
+function replaceXRange(comp, loose) {
+  comp = comp.trim();
+  var r = loose ? re[XRANGELOOSE] : re[XRANGE];
+  return comp.replace(r, function(ret, gtlt, M, m, p, pr) {
+    ;
+    var xM = isX(M);
+    var xm = xM || isX(m);
+    var xp = xm || isX(p);
+    var anyX = xp;
+
+    if (gtlt === '=' && anyX)
+      gtlt = '';
+
+    if (xM) {
+      if (gtlt === '>' || gtlt === '<') {
+        // nothing is allowed
+        ret = '<0.0.0';
+      } else {
+        // nothing is forbidden
+        ret = '*';
+      }
+    } else if (gtlt && anyX) {
+      // replace X with 0
+      if (xm)
+        m = 0;
+      if (xp)
+        p = 0;
+
+      if (gtlt === '>') {
+        // >1 => >=2.0.0
+        // >1.2 => >=1.3.0
+        // >1.2.3 => >= 1.2.4
+        gtlt = '>=';
+        if (xm) {
+          M = +M + 1;
+          m = 0;
+          p = 0;
+        } else if (xp) {
+          m = +m + 1;
+          p = 0;
+        }
+      } else if (gtlt === '<=') {
+        // <=0.7.x is actually <0.8.0, since any 0.7.x should
+        // pass.  Similarly, <=7.x is actually <8.0.0, etc.
+        gtlt = '<'
+        if (xm)
+          M = +M + 1
+        else
+          m = +m + 1
+      }
+
+      ret = gtlt + M + '.' + m + '.' + p;
+    } else if (xm) {
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    } else if (xp) {
+      ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+    }
+
+    ;
+
+    return ret;
+  });
+}
+
+// Because * is AND-ed with everything else in the comparator,
+// and '' means "any version", just remove the *s entirely.
+function replaceStars(comp, loose) {
+  ;
+  // Looseness is ignored here.  star is always as loose as it gets!
+  return comp.trim().replace(re[STAR], '');
+}
+
+// This function is passed to string.replace(re[HYPHENRANGE])
+// M, m, patch, prerelease, build
+// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
+// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
+// 1.2 - 3.4 => >=1.2.0 <3.5.0
+function hyphenReplace($0,
+                       from, fM, fm, fp, fpr, fb,
+                       to, tM, tm, tp, tpr, tb) {
+
+  if (isX(fM))
+    from = '';
+  else if (isX(fm))
+    from = '>=' + fM + '.0.0';
+  else if (isX(fp))
+    from = '>=' + fM + '.' + fm + '.0';
+  else
+    from = '>=' + from;
+
+  if (isX(tM))
+    to = '';
+  else if (isX(tm))
+    to = '<' + (+tM + 1) + '.0.0';
+  else if (isX(tp))
+    to = '<' + tM + '.' + (+tm + 1) + '.0';
+  else if (tpr)
+    to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr;
+  else
+    to = '<=' + to;
+
+  return (from + ' ' + to).trim();
+}
+
+
+// if ANY of the sets match ALL of its comparators, then pass
+Range.prototype.test = function(version) {
+  if (!version)
+    return false;
+
+  if (typeof version === 'string')
+    version = new SemVer(version, this.loose);
+
+  for (var i = 0; i < this.set.length; i++) {
+    if (testSet(this.set[i], version))
+      return true;
+  }
+  return false;
+};
+
+function testSet(set, version) {
+  for (var i = 0; i < set.length; i++) {
+    if (!set[i].test(version))
+      return false;
+  }
+
+  if (version.prerelease.length) {
+    // Find the set of versions that are allowed to have prereleases
+    // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
+    // That should allow `1.2.3-pr.2` to pass.
+    // However, `1.2.4-alpha.notready` should NOT be allowed,
+    // even though it's within the range set by the comparators.
+    for (var i = 0; i < set.length; i++) {
+      ;
+      if (set[i].semver === ANY)
+        return true;
+
+      if (set[i].semver.prerelease.length > 0) {
+        var allowed = set[i].semver;
+        if (allowed.major === version.major &&
+            allowed.minor === version.minor &&
+            allowed.patch === version.patch)
+          return true;
+      }
+    }
+
+    // Version has a -pre, but it's not one of the ones we like.
+    return false;
+  }
+
+  return true;
+}
+
+exports.satisfies = satisfies;
+function satisfies(version, range, loose) {
+  try {
+    range = new Range(range, loose);
+  } catch (er) {
+    return false;
+  }
+  return range.test(version);
+}
+
+exports.maxSatisfying = maxSatisfying;
+function maxSatisfying(versions, range, loose) {
+  return versions.filter(function(version) {
+    return satisfies(version, range, loose);
+  }).sort(function(a, b) {
+    return rcompare(a, b, loose);
+  })[0] || null;
+}
+
+exports.validRange = validRange;
+function validRange(range, loose) {
+  try {
+    // Return '*' instead of '' so that truthiness works.
+    // This will throw if it's invalid anyway
+    return new Range(range, loose).range || '*';
+  } catch (er) {
+    return null;
+  }
+}
+
+// Determine if version is less than all the versions possible in the range
+exports.ltr = ltr;
+function ltr(version, range, loose) {
+  return outside(version, range, '<', loose);
+}
+
+// Determine if version is greater than all the versions possible in the range.
+exports.gtr = gtr;
+function gtr(version, range, loose) {
+  return outside(version, range, '>', loose);
+}
+
+exports.outside = outside;
+function outside(version, range, hilo, loose) {
+  version = new SemVer(version, loose);
+  range = new Range(range, loose);
+
+  var gtfn, ltefn, ltfn, comp, ecomp;
+  switch (hilo) {
+    case '>':
+      gtfn = gt;
+      ltefn = lte;
+      ltfn = lt;
+      comp = '>';
+      ecomp = '>=';
+      break;
+    case '<':
+      gtfn = lt;
+      ltefn = gte;
+      ltfn = gt;
+      comp = '<';
+      ecomp = '<=';
+      break;
+    default:
+      throw new TypeError('Must provide a hilo val of "<" or ">"');
+  }
+
+  // If it satisifes the range it is not outside
+  if (satisfies(version, range, loose)) {
+    return false;
+  }
+
+  // From now on, variable terms are as if we're in "gtr" mode.
+  // but note that everything is flipped for the "ltr" function.
+
+  for (var i = 0; i < range.set.length; ++i) {
+    var comparators = range.set[i];
+
+    var high = null;
+    var low = null;
+
+    comparators.forEach(function(comparator) {
+      high = high || comparator;
+      low = low || comparator;
+      if (gtfn(comparator.semver, high.semver, loose)) {
+        high = comparator;
+      } else if (ltfn(comparator.semver, low.semver, loose)) {
+        low = comparator;
+      }
+    });
+
+    // If the edge version comparator has a operator then our version
+    // isn't outside it
+    if (high.operator === comp || high.operator === ecomp) {
+      return false;
+    }
+
+    // If the lowest version comparator has an operator and our version
+    // is less than it then it isn't higher than the range
+    if ((!low.operator || low.operator === comp) &&
+        ltefn(version, low.semver)) {
+      return false;
+    } else if (low.operator === ecomp && ltfn(version, low.semver)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Use the define() function if we're in AMD land
+if (typeof define === 'function' && define.amd)
+  define(exports);
+
+})(
+  typeof exports === 'object' ? exports :
+  typeof define === 'function' && define.amd ? {} :
+  semver = {}
+);
diff --git a/server/node_modules/pg/node_modules/semver/semver.browser.js.gz b/server/node_modules/pg/node_modules/semver/semver.browser.js.gz
new file mode 100644
index 0000000000000000000000000000000000000000..6a8cf09559b126dbaa32606c11ae43c302a9d1b5
Binary files /dev/null and b/server/node_modules/pg/node_modules/semver/semver.browser.js.gz differ
diff --git a/server/node_modules/pg/node_modules/semver/semver.js b/server/node_modules/pg/node_modules/semver/semver.js
new file mode 100644
index 0000000000000000000000000000000000000000..d265b568edfaefcdfd12ae6f44243d746cca636e
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/semver.js
@@ -0,0 +1,1191 @@
+// export the class if we are in a Node-like system.
+if (typeof module === 'object' && module.exports === exports)
+  exports = module.exports = SemVer;
+
+// The debug function is excluded entirely from the minified version.
+/* nomin */ var debug;
+/* nomin */ if (typeof process === 'object' &&
+    /* nomin */ process.env &&
+    /* nomin */ process.env.NODE_DEBUG &&
+    /* nomin */ /\bsemver\b/i.test(process.env.NODE_DEBUG))
+  /* nomin */ debug = function() {
+    /* nomin */ var args = Array.prototype.slice.call(arguments, 0);
+    /* nomin */ args.unshift('SEMVER');
+    /* nomin */ console.log.apply(console, args);
+    /* nomin */ };
+/* nomin */ else
+  /* nomin */ debug = function() {};
+
+// Note: this is the semver.org version of the spec that it implements
+// Not necessarily the package version of this code.
+exports.SEMVER_SPEC_VERSION = '2.0.0';
+
+var MAX_LENGTH = 256;
+var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
+
+// The actual regexps go on exports.re
+var re = exports.re = [];
+var src = exports.src = [];
+var R = 0;
+
+// The following Regular Expressions can be used for tokenizing,
+// validating, and parsing SemVer version strings.
+
+// ## Numeric Identifier
+// A single `0`, or a non-zero digit followed by zero or more digits.
+
+var NUMERICIDENTIFIER = R++;
+src[NUMERICIDENTIFIER] = '0|[1-9]\\d*';
+var NUMERICIDENTIFIERLOOSE = R++;
+src[NUMERICIDENTIFIERLOOSE] = '[0-9]+';
+
+
+// ## Non-numeric Identifier
+// Zero or more digits, followed by a letter or hyphen, and then zero or
+// more letters, digits, or hyphens.
+
+var NONNUMERICIDENTIFIER = R++;
+src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*';
+
+
+// ## Main Version
+// Three dot-separated numeric identifiers.
+
+var MAINVERSION = R++;
+src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' +
+                   '(' + src[NUMERICIDENTIFIER] + ')\\.' +
+                   '(' + src[NUMERICIDENTIFIER] + ')';
+
+var MAINVERSIONLOOSE = R++;
+src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
+                        '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
+                        '(' + src[NUMERICIDENTIFIERLOOSE] + ')';
+
+// ## Pre-release Version Identifier
+// A numeric identifier, or a non-numeric identifier.
+
+var PRERELEASEIDENTIFIER = R++;
+src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] +
+                            '|' + src[NONNUMERICIDENTIFIER] + ')';
+
+var PRERELEASEIDENTIFIERLOOSE = R++;
+src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] +
+                                 '|' + src[NONNUMERICIDENTIFIER] + ')';
+
+
+// ## Pre-release Version
+// Hyphen, followed by one or more dot-separated pre-release version
+// identifiers.
+
+var PRERELEASE = R++;
+src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] +
+                  '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))';
+
+var PRERELEASELOOSE = R++;
+src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] +
+                       '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))';
+
+// ## Build Metadata Identifier
+// Any combination of digits, letters, or hyphens.
+
+var BUILDIDENTIFIER = R++;
+src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+';
+
+// ## Build Metadata
+// Plus sign, followed by one or more period-separated build metadata
+// identifiers.
+
+var BUILD = R++;
+src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] +
+             '(?:\\.' + src[BUILDIDENTIFIER] + ')*))';
+
+
+// ## Full Version String
+// A main version, followed optionally by a pre-release version and
+// build metadata.
+
+// Note that the only major, minor, patch, and pre-release sections of
+// the version string are capturing groups.  The build metadata is not a
+// capturing group, because it should not ever be used in version
+// comparison.
+
+var FULL = R++;
+var FULLPLAIN = 'v?' + src[MAINVERSION] +
+                src[PRERELEASE] + '?' +
+                src[BUILD] + '?';
+
+src[FULL] = '^' + FULLPLAIN + '$';
+
+// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
+// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
+// common in the npm registry.
+var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] +
+                 src[PRERELEASELOOSE] + '?' +
+                 src[BUILD] + '?';
+
+var LOOSE = R++;
+src[LOOSE] = '^' + LOOSEPLAIN + '$';
+
+var GTLT = R++;
+src[GTLT] = '((?:<|>)?=?)';
+
+// Something like "2.*" or "1.2.x".
+// Note that "x.x" is a valid xRange identifer, meaning "any version"
+// Only the first item is strictly required.
+var XRANGEIDENTIFIERLOOSE = R++;
+src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*';
+var XRANGEIDENTIFIER = R++;
+src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*';
+
+var XRANGEPLAIN = R++;
+src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:' + src[PRERELEASE] + ')?' +
+                   src[BUILD] + '?' +
+                   ')?)?';
+
+var XRANGEPLAINLOOSE = R++;
+src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:' + src[PRERELEASELOOSE] + ')?' +
+                        src[BUILD] + '?' +
+                        ')?)?';
+
+var XRANGE = R++;
+src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$';
+var XRANGELOOSE = R++;
+src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$';
+
+// Tilde ranges.
+// Meaning is "reasonably at or greater than"
+var LONETILDE = R++;
+src[LONETILDE] = '(?:~>?)';
+
+var TILDETRIM = R++;
+src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+';
+re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g');
+var tildeTrimReplace = '$1~';
+
+var TILDE = R++;
+src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$';
+var TILDELOOSE = R++;
+src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$';
+
+// Caret ranges.
+// Meaning is "at least and backwards compatible with"
+var LONECARET = R++;
+src[LONECARET] = '(?:\\^)';
+
+var CARETTRIM = R++;
+src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+';
+re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g');
+var caretTrimReplace = '$1^';
+
+var CARET = R++;
+src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$';
+var CARETLOOSE = R++;
+src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$';
+
+// A simple gt/lt/eq thing, or just "" to indicate "any version"
+var COMPARATORLOOSE = R++;
+src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$';
+var COMPARATOR = R++;
+src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$';
+
+
+// An expression to strip any whitespace between the gtlt and the thing
+// it modifies, so that `> 1.2.3` ==> `>1.2.3`
+var COMPARATORTRIM = R++;
+src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] +
+                      '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')';
+
+// this one has to use the /g flag
+re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g');
+var comparatorTrimReplace = '$1$2$3';
+
+
+// Something like `1.2.3 - 1.2.4`
+// Note that these all use the loose form, because they'll be
+// checked against either the strict or loose comparator form
+// later.
+var HYPHENRANGE = R++;
+src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' +
+                   '\\s+-\\s+' +
+                   '(' + src[XRANGEPLAIN] + ')' +
+                   '\\s*$';
+
+var HYPHENRANGELOOSE = R++;
+src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' +
+                        '\\s+-\\s+' +
+                        '(' + src[XRANGEPLAINLOOSE] + ')' +
+                        '\\s*$';
+
+// Star ranges basically just allow anything at all.
+var STAR = R++;
+src[STAR] = '(<|>)?=?\\s*\\*';
+
+// Compile to actual regexp objects.
+// All are flag-free, unless they were created above with a flag.
+for (var i = 0; i < R; i++) {
+  debug(i, src[i]);
+  if (!re[i])
+    re[i] = new RegExp(src[i]);
+}
+
+exports.parse = parse;
+function parse(version, loose) {
+  if (version.length > MAX_LENGTH)
+    return null;
+
+  var r = loose ? re[LOOSE] : re[FULL];
+  if (!r.test(version))
+    return null;
+
+  try {
+    return new SemVer(version, loose);
+  } catch (er) {
+    return null;
+  }
+}
+
+exports.valid = valid;
+function valid(version, loose) {
+  var v = parse(version, loose);
+  return v ? v.version : null;
+}
+
+
+exports.clean = clean;
+function clean(version, loose) {
+  var s = parse(version.trim().replace(/^[=v]+/, ''), loose);
+  return s ? s.version : null;
+}
+
+exports.SemVer = SemVer;
+
+function SemVer(version, loose) {
+  if (version instanceof SemVer) {
+    if (version.loose === loose)
+      return version;
+    else
+      version = version.version;
+  } else if (typeof version !== 'string') {
+    throw new TypeError('Invalid Version: ' + version);
+  }
+
+  if (version.length > MAX_LENGTH)
+    throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters')
+
+  if (!(this instanceof SemVer))
+    return new SemVer(version, loose);
+
+  debug('SemVer', version, loose);
+  this.loose = loose;
+  var m = version.trim().match(loose ? re[LOOSE] : re[FULL]);
+
+  if (!m)
+    throw new TypeError('Invalid Version: ' + version);
+
+  this.raw = version;
+
+  // these are actually numbers
+  this.major = +m[1];
+  this.minor = +m[2];
+  this.patch = +m[3];
+
+  if (this.major > MAX_SAFE_INTEGER || this.major < 0)
+    throw new TypeError('Invalid major version')
+
+  if (this.minor > MAX_SAFE_INTEGER || this.minor < 0)
+    throw new TypeError('Invalid minor version')
+
+  if (this.patch > MAX_SAFE_INTEGER || this.patch < 0)
+    throw new TypeError('Invalid patch version')
+
+  // numberify any prerelease numeric ids
+  if (!m[4])
+    this.prerelease = [];
+  else
+    this.prerelease = m[4].split('.').map(function(id) {
+      return (/^[0-9]+$/.test(id)) ? +id : id;
+    });
+
+  this.build = m[5] ? m[5].split('.') : [];
+  this.format();
+}
+
+SemVer.prototype.format = function() {
+  this.version = this.major + '.' + this.minor + '.' + this.patch;
+  if (this.prerelease.length)
+    this.version += '-' + this.prerelease.join('.');
+  return this.version;
+};
+
+SemVer.prototype.inspect = function() {
+  return '<SemVer "' + this + '">';
+};
+
+SemVer.prototype.toString = function() {
+  return this.version;
+};
+
+SemVer.prototype.compare = function(other) {
+  debug('SemVer.compare', this.version, this.loose, other);
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  return this.compareMain(other) || this.comparePre(other);
+};
+
+SemVer.prototype.compareMain = function(other) {
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  return compareIdentifiers(this.major, other.major) ||
+         compareIdentifiers(this.minor, other.minor) ||
+         compareIdentifiers(this.patch, other.patch);
+};
+
+SemVer.prototype.comparePre = function(other) {
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  // NOT having a prerelease is > having one
+  if (this.prerelease.length && !other.prerelease.length)
+    return -1;
+  else if (!this.prerelease.length && other.prerelease.length)
+    return 1;
+  else if (!this.prerelease.length && !other.prerelease.length)
+    return 0;
+
+  var i = 0;
+  do {
+    var a = this.prerelease[i];
+    var b = other.prerelease[i];
+    debug('prerelease compare', i, a, b);
+    if (a === undefined && b === undefined)
+      return 0;
+    else if (b === undefined)
+      return 1;
+    else if (a === undefined)
+      return -1;
+    else if (a === b)
+      continue;
+    else
+      return compareIdentifiers(a, b);
+  } while (++i);
+};
+
+// preminor will bump the version up to the next minor release, and immediately
+// down to pre-release. premajor and prepatch work the same way.
+SemVer.prototype.inc = function(release, identifier) {
+  switch (release) {
+    case 'premajor':
+      this.prerelease.length = 0;
+      this.patch = 0;
+      this.minor = 0;
+      this.major++;
+      this.inc('pre', identifier);
+      break;
+    case 'preminor':
+      this.prerelease.length = 0;
+      this.patch = 0;
+      this.minor++;
+      this.inc('pre', identifier);
+      break;
+    case 'prepatch':
+      // If this is already a prerelease, it will bump to the next version
+      // drop any prereleases that might already exist, since they are not
+      // relevant at this point.
+      this.prerelease.length = 0;
+      this.inc('patch', identifier);
+      this.inc('pre', identifier);
+      break;
+    // If the input is a non-prerelease version, this acts the same as
+    // prepatch.
+    case 'prerelease':
+      if (this.prerelease.length === 0)
+        this.inc('patch', identifier);
+      this.inc('pre', identifier);
+      break;
+
+    case 'major':
+      // If this is a pre-major version, bump up to the same major version.
+      // Otherwise increment major.
+      // 1.0.0-5 bumps to 1.0.0
+      // 1.1.0 bumps to 2.0.0
+      if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0)
+        this.major++;
+      this.minor = 0;
+      this.patch = 0;
+      this.prerelease = [];
+      break;
+    case 'minor':
+      // If this is a pre-minor version, bump up to the same minor version.
+      // Otherwise increment minor.
+      // 1.2.0-5 bumps to 1.2.0
+      // 1.2.1 bumps to 1.3.0
+      if (this.patch !== 0 || this.prerelease.length === 0)
+        this.minor++;
+      this.patch = 0;
+      this.prerelease = [];
+      break;
+    case 'patch':
+      // If this is not a pre-release version, it will increment the patch.
+      // If it is a pre-release it will bump up to the same patch version.
+      // 1.2.0-5 patches to 1.2.0
+      // 1.2.0 patches to 1.2.1
+      if (this.prerelease.length === 0)
+        this.patch++;
+      this.prerelease = [];
+      break;
+    // This probably shouldn't be used publicly.
+    // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
+    case 'pre':
+      if (this.prerelease.length === 0)
+        this.prerelease = [0];
+      else {
+        var i = this.prerelease.length;
+        while (--i >= 0) {
+          if (typeof this.prerelease[i] === 'number') {
+            this.prerelease[i]++;
+            i = -2;
+          }
+        }
+        if (i === -1) // didn't increment anything
+          this.prerelease.push(0);
+      }
+      if (identifier) {
+        // 1.2.0-beta.1 bumps to 1.2.0-beta.2,
+        // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
+        if (this.prerelease[0] === identifier) {
+          if (isNaN(this.prerelease[1]))
+            this.prerelease = [identifier, 0];
+        } else
+          this.prerelease = [identifier, 0];
+      }
+      break;
+
+    default:
+      throw new Error('invalid increment argument: ' + release);
+  }
+  this.format();
+  return this;
+};
+
+exports.inc = inc;
+function inc(version, release, loose, identifier) {
+  if (typeof(loose) === 'string') {
+    identifier = loose;
+    loose = undefined;
+  }
+
+  try {
+    return new SemVer(version, loose).inc(release, identifier).version;
+  } catch (er) {
+    return null;
+  }
+}
+
+exports.diff = diff;
+function diff(version1, version2) {
+  if (eq(version1, version2)) {
+    return null;
+  } else {
+    var v1 = parse(version1);
+    var v2 = parse(version2);
+    if (v1.prerelease.length || v2.prerelease.length) {
+      for (var key in v1) {
+        if (key === 'major' || key === 'minor' || key === 'patch') {
+          if (v1[key] !== v2[key]) {
+            return 'pre'+key;
+          }
+        }
+      }
+      return 'prerelease';
+    }
+    for (var key in v1) {
+      if (key === 'major' || key === 'minor' || key === 'patch') {
+        if (v1[key] !== v2[key]) {
+          return key;
+        }
+      }
+    }
+  }
+}
+
+exports.compareIdentifiers = compareIdentifiers;
+
+var numeric = /^[0-9]+$/;
+function compareIdentifiers(a, b) {
+  var anum = numeric.test(a);
+  var bnum = numeric.test(b);
+
+  if (anum && bnum) {
+    a = +a;
+    b = +b;
+  }
+
+  return (anum && !bnum) ? -1 :
+         (bnum && !anum) ? 1 :
+         a < b ? -1 :
+         a > b ? 1 :
+         0;
+}
+
+exports.rcompareIdentifiers = rcompareIdentifiers;
+function rcompareIdentifiers(a, b) {
+  return compareIdentifiers(b, a);
+}
+
+exports.major = major;
+function major(a, loose) {
+  return new SemVer(a, loose).major;
+}
+
+exports.minor = minor;
+function minor(a, loose) {
+  return new SemVer(a, loose).minor;
+}
+
+exports.patch = patch;
+function patch(a, loose) {
+  return new SemVer(a, loose).patch;
+}
+
+exports.compare = compare;
+function compare(a, b, loose) {
+  return new SemVer(a, loose).compare(b);
+}
+
+exports.compareLoose = compareLoose;
+function compareLoose(a, b) {
+  return compare(a, b, true);
+}
+
+exports.rcompare = rcompare;
+function rcompare(a, b, loose) {
+  return compare(b, a, loose);
+}
+
+exports.sort = sort;
+function sort(list, loose) {
+  return list.sort(function(a, b) {
+    return exports.compare(a, b, loose);
+  });
+}
+
+exports.rsort = rsort;
+function rsort(list, loose) {
+  return list.sort(function(a, b) {
+    return exports.rcompare(a, b, loose);
+  });
+}
+
+exports.gt = gt;
+function gt(a, b, loose) {
+  return compare(a, b, loose) > 0;
+}
+
+exports.lt = lt;
+function lt(a, b, loose) {
+  return compare(a, b, loose) < 0;
+}
+
+exports.eq = eq;
+function eq(a, b, loose) {
+  return compare(a, b, loose) === 0;
+}
+
+exports.neq = neq;
+function neq(a, b, loose) {
+  return compare(a, b, loose) !== 0;
+}
+
+exports.gte = gte;
+function gte(a, b, loose) {
+  return compare(a, b, loose) >= 0;
+}
+
+exports.lte = lte;
+function lte(a, b, loose) {
+  return compare(a, b, loose) <= 0;
+}
+
+exports.cmp = cmp;
+function cmp(a, op, b, loose) {
+  var ret;
+  switch (op) {
+    case '===':
+      if (typeof a === 'object') a = a.version;
+      if (typeof b === 'object') b = b.version;
+      ret = a === b;
+      break;
+    case '!==':
+      if (typeof a === 'object') a = a.version;
+      if (typeof b === 'object') b = b.version;
+      ret = a !== b;
+      break;
+    case '': case '=': case '==': ret = eq(a, b, loose); break;
+    case '!=': ret = neq(a, b, loose); break;
+    case '>': ret = gt(a, b, loose); break;
+    case '>=': ret = gte(a, b, loose); break;
+    case '<': ret = lt(a, b, loose); break;
+    case '<=': ret = lte(a, b, loose); break;
+    default: throw new TypeError('Invalid operator: ' + op);
+  }
+  return ret;
+}
+
+exports.Comparator = Comparator;
+function Comparator(comp, loose) {
+  if (comp instanceof Comparator) {
+    if (comp.loose === loose)
+      return comp;
+    else
+      comp = comp.value;
+  }
+
+  if (!(this instanceof Comparator))
+    return new Comparator(comp, loose);
+
+  debug('comparator', comp, loose);
+  this.loose = loose;
+  this.parse(comp);
+
+  if (this.semver === ANY)
+    this.value = '';
+  else
+    this.value = this.operator + this.semver.version;
+
+  debug('comp', this);
+}
+
+var ANY = {};
+Comparator.prototype.parse = function(comp) {
+  var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR];
+  var m = comp.match(r);
+
+  if (!m)
+    throw new TypeError('Invalid comparator: ' + comp);
+
+  this.operator = m[1];
+  if (this.operator === '=')
+    this.operator = '';
+
+  // if it literally is just '>' or '' then allow anything.
+  if (!m[2])
+    this.semver = ANY;
+  else
+    this.semver = new SemVer(m[2], this.loose);
+};
+
+Comparator.prototype.inspect = function() {
+  return '<SemVer Comparator "' + this + '">';
+};
+
+Comparator.prototype.toString = function() {
+  return this.value;
+};
+
+Comparator.prototype.test = function(version) {
+  debug('Comparator.test', version, this.loose);
+
+  if (this.semver === ANY)
+    return true;
+
+  if (typeof version === 'string')
+    version = new SemVer(version, this.loose);
+
+  return cmp(version, this.operator, this.semver, this.loose);
+};
+
+
+exports.Range = Range;
+function Range(range, loose) {
+  if ((range instanceof Range) && range.loose === loose)
+    return range;
+
+  if (!(this instanceof Range))
+    return new Range(range, loose);
+
+  this.loose = loose;
+
+  // First, split based on boolean or ||
+  this.raw = range;
+  this.set = range.split(/\s*\|\|\s*/).map(function(range) {
+    return this.parseRange(range.trim());
+  }, this).filter(function(c) {
+    // throw out any that are not relevant for whatever reason
+    return c.length;
+  });
+
+  if (!this.set.length) {
+    throw new TypeError('Invalid SemVer Range: ' + range);
+  }
+
+  this.format();
+}
+
+Range.prototype.inspect = function() {
+  return '<SemVer Range "' + this.range + '">';
+};
+
+Range.prototype.format = function() {
+  this.range = this.set.map(function(comps) {
+    return comps.join(' ').trim();
+  }).join('||').trim();
+  return this.range;
+};
+
+Range.prototype.toString = function() {
+  return this.range;
+};
+
+Range.prototype.parseRange = function(range) {
+  var loose = this.loose;
+  range = range.trim();
+  debug('range', range, loose);
+  // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
+  var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE];
+  range = range.replace(hr, hyphenReplace);
+  debug('hyphen replace', range);
+  // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
+  range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace);
+  debug('comparator trim', range, re[COMPARATORTRIM]);
+
+  // `~ 1.2.3` => `~1.2.3`
+  range = range.replace(re[TILDETRIM], tildeTrimReplace);
+
+  // `^ 1.2.3` => `^1.2.3`
+  range = range.replace(re[CARETTRIM], caretTrimReplace);
+
+  // normalize spaces
+  range = range.split(/\s+/).join(' ');
+
+  // At this point, the range is completely trimmed and
+  // ready to be split into comparators.
+
+  var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR];
+  var set = range.split(' ').map(function(comp) {
+    return parseComparator(comp, loose);
+  }).join(' ').split(/\s+/);
+  if (this.loose) {
+    // in loose mode, throw out any that are not valid comparators
+    set = set.filter(function(comp) {
+      return !!comp.match(compRe);
+    });
+  }
+  set = set.map(function(comp) {
+    return new Comparator(comp, loose);
+  });
+
+  return set;
+};
+
+// Mostly just for testing and legacy API reasons
+exports.toComparators = toComparators;
+function toComparators(range, loose) {
+  return new Range(range, loose).set.map(function(comp) {
+    return comp.map(function(c) {
+      return c.value;
+    }).join(' ').trim().split(' ');
+  });
+}
+
+// comprised of xranges, tildes, stars, and gtlt's at this point.
+// already replaced the hyphen ranges
+// turn into a set of JUST comparators.
+function parseComparator(comp, loose) {
+  debug('comp', comp);
+  comp = replaceCarets(comp, loose);
+  debug('caret', comp);
+  comp = replaceTildes(comp, loose);
+  debug('tildes', comp);
+  comp = replaceXRanges(comp, loose);
+  debug('xrange', comp);
+  comp = replaceStars(comp, loose);
+  debug('stars', comp);
+  return comp;
+}
+
+function isX(id) {
+  return !id || id.toLowerCase() === 'x' || id === '*';
+}
+
+// ~, ~> --> * (any, kinda silly)
+// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
+// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
+// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
+// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
+// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
+function replaceTildes(comp, loose) {
+  return comp.trim().split(/\s+/).map(function(comp) {
+    return replaceTilde(comp, loose);
+  }).join(' ');
+}
+
+function replaceTilde(comp, loose) {
+  var r = loose ? re[TILDELOOSE] : re[TILDE];
+  return comp.replace(r, function(_, M, m, p, pr) {
+    debug('tilde', comp, _, M, m, p, pr);
+    var ret;
+
+    if (isX(M))
+      ret = '';
+    else if (isX(m))
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    else if (isX(p))
+      // ~1.2 == >=1.2.0- <1.3.0-
+      ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+    else if (pr) {
+      debug('replaceTilde pr', pr);
+      if (pr.charAt(0) !== '-')
+        pr = '-' + pr;
+      ret = '>=' + M + '.' + m + '.' + p + pr +
+            ' <' + M + '.' + (+m + 1) + '.0';
+    } else
+      // ~1.2.3 == >=1.2.3 <1.3.0
+      ret = '>=' + M + '.' + m + '.' + p +
+            ' <' + M + '.' + (+m + 1) + '.0';
+
+    debug('tilde return', ret);
+    return ret;
+  });
+}
+
+// ^ --> * (any, kinda silly)
+// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
+// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
+// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
+// ^1.2.3 --> >=1.2.3 <2.0.0
+// ^1.2.0 --> >=1.2.0 <2.0.0
+function replaceCarets(comp, loose) {
+  return comp.trim().split(/\s+/).map(function(comp) {
+    return replaceCaret(comp, loose);
+  }).join(' ');
+}
+
+function replaceCaret(comp, loose) {
+  debug('caret', comp, loose);
+  var r = loose ? re[CARETLOOSE] : re[CARET];
+  return comp.replace(r, function(_, M, m, p, pr) {
+    debug('caret', comp, _, M, m, p, pr);
+    var ret;
+
+    if (isX(M))
+      ret = '';
+    else if (isX(m))
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    else if (isX(p)) {
+      if (M === '0')
+        ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+      else
+        ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0';
+    } else if (pr) {
+      debug('replaceCaret pr', pr);
+      if (pr.charAt(0) !== '-')
+        pr = '-' + pr;
+      if (M === '0') {
+        if (m === '0')
+          ret = '>=' + M + '.' + m + '.' + p + pr +
+                ' <' + M + '.' + m + '.' + (+p + 1);
+        else
+          ret = '>=' + M + '.' + m + '.' + p + pr +
+                ' <' + M + '.' + (+m + 1) + '.0';
+      } else
+        ret = '>=' + M + '.' + m + '.' + p + pr +
+              ' <' + (+M + 1) + '.0.0';
+    } else {
+      debug('no pr');
+      if (M === '0') {
+        if (m === '0')
+          ret = '>=' + M + '.' + m + '.' + p +
+                ' <' + M + '.' + m + '.' + (+p + 1);
+        else
+          ret = '>=' + M + '.' + m + '.' + p +
+                ' <' + M + '.' + (+m + 1) + '.0';
+      } else
+        ret = '>=' + M + '.' + m + '.' + p +
+              ' <' + (+M + 1) + '.0.0';
+    }
+
+    debug('caret return', ret);
+    return ret;
+  });
+}
+
+function replaceXRanges(comp, loose) {
+  debug('replaceXRanges', comp, loose);
+  return comp.split(/\s+/).map(function(comp) {
+    return replaceXRange(comp, loose);
+  }).join(' ');
+}
+
+function replaceXRange(comp, loose) {
+  comp = comp.trim();
+  var r = loose ? re[XRANGELOOSE] : re[XRANGE];
+  return comp.replace(r, function(ret, gtlt, M, m, p, pr) {
+    debug('xRange', comp, ret, gtlt, M, m, p, pr);
+    var xM = isX(M);
+    var xm = xM || isX(m);
+    var xp = xm || isX(p);
+    var anyX = xp;
+
+    if (gtlt === '=' && anyX)
+      gtlt = '';
+
+    if (xM) {
+      if (gtlt === '>' || gtlt === '<') {
+        // nothing is allowed
+        ret = '<0.0.0';
+      } else {
+        // nothing is forbidden
+        ret = '*';
+      }
+    } else if (gtlt && anyX) {
+      // replace X with 0
+      if (xm)
+        m = 0;
+      if (xp)
+        p = 0;
+
+      if (gtlt === '>') {
+        // >1 => >=2.0.0
+        // >1.2 => >=1.3.0
+        // >1.2.3 => >= 1.2.4
+        gtlt = '>=';
+        if (xm) {
+          M = +M + 1;
+          m = 0;
+          p = 0;
+        } else if (xp) {
+          m = +m + 1;
+          p = 0;
+        }
+      } else if (gtlt === '<=') {
+        // <=0.7.x is actually <0.8.0, since any 0.7.x should
+        // pass.  Similarly, <=7.x is actually <8.0.0, etc.
+        gtlt = '<'
+        if (xm)
+          M = +M + 1
+        else
+          m = +m + 1
+      }
+
+      ret = gtlt + M + '.' + m + '.' + p;
+    } else if (xm) {
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    } else if (xp) {
+      ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+    }
+
+    debug('xRange return', ret);
+
+    return ret;
+  });
+}
+
+// Because * is AND-ed with everything else in the comparator,
+// and '' means "any version", just remove the *s entirely.
+function replaceStars(comp, loose) {
+  debug('replaceStars', comp, loose);
+  // Looseness is ignored here.  star is always as loose as it gets!
+  return comp.trim().replace(re[STAR], '');
+}
+
+// This function is passed to string.replace(re[HYPHENRANGE])
+// M, m, patch, prerelease, build
+// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
+// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
+// 1.2 - 3.4 => >=1.2.0 <3.5.0
+function hyphenReplace($0,
+                       from, fM, fm, fp, fpr, fb,
+                       to, tM, tm, tp, tpr, tb) {
+
+  if (isX(fM))
+    from = '';
+  else if (isX(fm))
+    from = '>=' + fM + '.0.0';
+  else if (isX(fp))
+    from = '>=' + fM + '.' + fm + '.0';
+  else
+    from = '>=' + from;
+
+  if (isX(tM))
+    to = '';
+  else if (isX(tm))
+    to = '<' + (+tM + 1) + '.0.0';
+  else if (isX(tp))
+    to = '<' + tM + '.' + (+tm + 1) + '.0';
+  else if (tpr)
+    to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr;
+  else
+    to = '<=' + to;
+
+  return (from + ' ' + to).trim();
+}
+
+
+// if ANY of the sets match ALL of its comparators, then pass
+Range.prototype.test = function(version) {
+  if (!version)
+    return false;
+
+  if (typeof version === 'string')
+    version = new SemVer(version, this.loose);
+
+  for (var i = 0; i < this.set.length; i++) {
+    if (testSet(this.set[i], version))
+      return true;
+  }
+  return false;
+};
+
+function testSet(set, version) {
+  for (var i = 0; i < set.length; i++) {
+    if (!set[i].test(version))
+      return false;
+  }
+
+  if (version.prerelease.length) {
+    // Find the set of versions that are allowed to have prereleases
+    // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
+    // That should allow `1.2.3-pr.2` to pass.
+    // However, `1.2.4-alpha.notready` should NOT be allowed,
+    // even though it's within the range set by the comparators.
+    for (var i = 0; i < set.length; i++) {
+      debug(set[i].semver);
+      if (set[i].semver === ANY)
+        return true;
+
+      if (set[i].semver.prerelease.length > 0) {
+        var allowed = set[i].semver;
+        if (allowed.major === version.major &&
+            allowed.minor === version.minor &&
+            allowed.patch === version.patch)
+          return true;
+      }
+    }
+
+    // Version has a -pre, but it's not one of the ones we like.
+    return false;
+  }
+
+  return true;
+}
+
+exports.satisfies = satisfies;
+function satisfies(version, range, loose) {
+  try {
+    range = new Range(range, loose);
+  } catch (er) {
+    return false;
+  }
+  return range.test(version);
+}
+
+exports.maxSatisfying = maxSatisfying;
+function maxSatisfying(versions, range, loose) {
+  return versions.filter(function(version) {
+    return satisfies(version, range, loose);
+  }).sort(function(a, b) {
+    return rcompare(a, b, loose);
+  })[0] || null;
+}
+
+exports.validRange = validRange;
+function validRange(range, loose) {
+  try {
+    // Return '*' instead of '' so that truthiness works.
+    // This will throw if it's invalid anyway
+    return new Range(range, loose).range || '*';
+  } catch (er) {
+    return null;
+  }
+}
+
+// Determine if version is less than all the versions possible in the range
+exports.ltr = ltr;
+function ltr(version, range, loose) {
+  return outside(version, range, '<', loose);
+}
+
+// Determine if version is greater than all the versions possible in the range.
+exports.gtr = gtr;
+function gtr(version, range, loose) {
+  return outside(version, range, '>', loose);
+}
+
+exports.outside = outside;
+function outside(version, range, hilo, loose) {
+  version = new SemVer(version, loose);
+  range = new Range(range, loose);
+
+  var gtfn, ltefn, ltfn, comp, ecomp;
+  switch (hilo) {
+    case '>':
+      gtfn = gt;
+      ltefn = lte;
+      ltfn = lt;
+      comp = '>';
+      ecomp = '>=';
+      break;
+    case '<':
+      gtfn = lt;
+      ltefn = gte;
+      ltfn = gt;
+      comp = '<';
+      ecomp = '<=';
+      break;
+    default:
+      throw new TypeError('Must provide a hilo val of "<" or ">"');
+  }
+
+  // If it satisifes the range it is not outside
+  if (satisfies(version, range, loose)) {
+    return false;
+  }
+
+  // From now on, variable terms are as if we're in "gtr" mode.
+  // but note that everything is flipped for the "ltr" function.
+
+  for (var i = 0; i < range.set.length; ++i) {
+    var comparators = range.set[i];
+
+    var high = null;
+    var low = null;
+
+    comparators.forEach(function(comparator) {
+      high = high || comparator;
+      low = low || comparator;
+      if (gtfn(comparator.semver, high.semver, loose)) {
+        high = comparator;
+      } else if (ltfn(comparator.semver, low.semver, loose)) {
+        low = comparator;
+      }
+    });
+
+    // If the edge version comparator has a operator then our version
+    // isn't outside it
+    if (high.operator === comp || high.operator === ecomp) {
+      return false;
+    }
+
+    // If the lowest version comparator has an operator and our version
+    // is less than it then it isn't higher than the range
+    if ((!low.operator || low.operator === comp) &&
+        ltefn(version, low.semver)) {
+      return false;
+    } else if (low.operator === ecomp && ltfn(version, low.semver)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Use the define() function if we're in AMD land
+if (typeof define === 'function' && define.amd)
+  define(exports);
diff --git a/server/node_modules/pg/node_modules/semver/semver.min.js b/server/node_modules/pg/node_modules/semver/semver.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..abe2d81843bca8233fc8bd43b1d267aaa6e99b0d
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/semver.min.js
@@ -0,0 +1 @@
+(function(e){if(typeof module==="object"&&module.exports===e)e=module.exports=K;e.SEMVER_SPEC_VERSION="2.0.0";var r=256;var t=Number.MAX_SAFE_INTEGER||9007199254740991;var n=e.re=[];var i=e.src=[];var s=0;var o=s++;i[o]="0|[1-9]\\d*";var a=s++;i[a]="[0-9]+";var f=s++;i[f]="\\d*[a-zA-Z-][a-zA-Z0-9-]*";var u=s++;i[u]="("+i[o]+")\\."+"("+i[o]+")\\."+"("+i[o]+")";var l=s++;i[l]="("+i[a]+")\\."+"("+i[a]+")\\."+"("+i[a]+")";var h=s++;i[h]="(?:"+i[o]+"|"+i[f]+")";var p=s++;i[p]="(?:"+i[a]+"|"+i[f]+")";var c=s++;i[c]="(?:-("+i[h]+"(?:\\."+i[h]+")*))";var v=s++;i[v]="(?:-?("+i[p]+"(?:\\."+i[p]+")*))";var m=s++;i[m]="[0-9A-Za-z-]+";var g=s++;i[g]="(?:\\+("+i[m]+"(?:\\."+i[m]+")*))";var w=s++;var y="v?"+i[u]+i[c]+"?"+i[g]+"?";i[w]="^"+y+"$";var d="[v=\\s]*"+i[l]+i[v]+"?"+i[g]+"?";var j=s++;i[j]="^"+d+"$";var b=s++;i[b]="((?:<|>)?=?)";var E=s++;i[E]=i[a]+"|x|X|\\*";var $=s++;i[$]=i[o]+"|x|X|\\*";var k=s++;i[k]="[v=\\s]*("+i[$]+")"+"(?:\\.("+i[$]+")"+"(?:\\.("+i[$]+")"+"(?:"+i[c]+")?"+i[g]+"?"+")?)?";var R=s++;i[R]="[v=\\s]*("+i[E]+")"+"(?:\\.("+i[E]+")"+"(?:\\.("+i[E]+")"+"(?:"+i[v]+")?"+i[g]+"?"+")?)?";var S=s++;i[S]="^"+i[b]+"\\s*"+i[k]+"$";var x=s++;i[x]="^"+i[b]+"\\s*"+i[R]+"$";var I=s++;i[I]="(?:~>?)";var T=s++;i[T]="(\\s*)"+i[I]+"\\s+";n[T]=new RegExp(i[T],"g");var V="$1~";var A=s++;i[A]="^"+i[I]+i[k]+"$";var C=s++;i[C]="^"+i[I]+i[R]+"$";var M=s++;i[M]="(?:\\^)";var N=s++;i[N]="(\\s*)"+i[M]+"\\s+";n[N]=new RegExp(i[N],"g");var _="$1^";var z=s++;i[z]="^"+i[M]+i[k]+"$";var P=s++;i[P]="^"+i[M]+i[R]+"$";var X=s++;i[X]="^"+i[b]+"\\s*("+d+")$|^$";var Z=s++;i[Z]="^"+i[b]+"\\s*("+y+")$|^$";var q=s++;i[q]="(\\s*)"+i[b]+"\\s*("+d+"|"+i[k]+")";n[q]=new RegExp(i[q],"g");var L="$1$2$3";var F=s++;i[F]="^\\s*("+i[k]+")"+"\\s+-\\s+"+"("+i[k]+")"+"\\s*$";var G=s++;i[G]="^\\s*("+i[R]+")"+"\\s+-\\s+"+"("+i[R]+")"+"\\s*$";var O=s++;i[O]="(<|>)?=?\\s*\\*";for(var B=0;B<s;B++){if(!n[B])n[B]=new RegExp(i[B])}e.parse=D;function D(e,t){if(e.length>r)return null;var i=t?n[j]:n[w];if(!i.test(e))return null;try{return new K(e,t)}catch(s){return null}}e.valid=H;function H(e,r){var t=D(e,r);return t?t.version:null}e.clean=J;function J(e,r){var t=D(e.trim().replace(/^[=v]+/,""),r);return t?t.version:null}e.SemVer=K;function K(e,i){if(e instanceof K){if(e.loose===i)return e;else e=e.version}else if(typeof e!=="string"){throw new TypeError("Invalid Version: "+e)}if(e.length>r)throw new TypeError("version is longer than "+r+" characters");if(!(this instanceof K))return new K(e,i);this.loose=i;var s=e.trim().match(i?n[j]:n[w]);if(!s)throw new TypeError("Invalid Version: "+e);this.raw=e;this.major=+s[1];this.minor=+s[2];this.patch=+s[3];if(this.major>t||this.major<0)throw new TypeError("Invalid major version");if(this.minor>t||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>t||this.patch<0)throw new TypeError("Invalid patch version");if(!s[4])this.prerelease=[];else this.prerelease=s[4].split(".").map(function(e){return/^[0-9]+$/.test(e)?+e:e});this.build=s[5]?s[5].split("."):[];this.format()}K.prototype.format=function(){this.version=this.major+"."+this.minor+"."+this.patch;if(this.prerelease.length)this.version+="-"+this.prerelease.join(".");return this.version};K.prototype.inspect=function(){return'<SemVer "'+this+'">'};K.prototype.toString=function(){return this.version};K.prototype.compare=function(e){if(!(e instanceof K))e=new K(e,this.loose);return this.compareMain(e)||this.comparePre(e)};K.prototype.compareMain=function(e){if(!(e instanceof K))e=new K(e,this.loose);return Y(this.major,e.major)||Y(this.minor,e.minor)||Y(this.patch,e.patch)};K.prototype.comparePre=function(e){if(!(e instanceof K))e=new K(e,this.loose);if(this.prerelease.length&&!e.prerelease.length)return-1;else if(!this.prerelease.length&&e.prerelease.length)return 1;else if(!this.prerelease.length&&!e.prerelease.length)return 0;var r=0;do{var t=this.prerelease[r];var n=e.prerelease[r];if(t===undefined&&n===undefined)return 0;else if(n===undefined)return 1;else if(t===undefined)return-1;else if(t===n)continue;else return Y(t,n)}while(++r)};K.prototype.inc=function(e,r){switch(e){case"premajor":this.prerelease.length=0;this.patch=0;this.minor=0;this.major++;this.inc("pre",r);break;case"preminor":this.prerelease.length=0;this.patch=0;this.minor++;this.inc("pre",r);break;case"prepatch":this.prerelease.length=0;this.inc("patch",r);this.inc("pre",r);break;case"prerelease":if(this.prerelease.length===0)this.inc("patch",r);this.inc("pre",r);break;case"major":if(this.minor!==0||this.patch!==0||this.prerelease.length===0)this.major++;this.minor=0;this.patch=0;this.prerelease=[];break;case"minor":if(this.patch!==0||this.prerelease.length===0)this.minor++;this.patch=0;this.prerelease=[];break;case"patch":if(this.prerelease.length===0)this.patch++;this.prerelease=[];break;case"pre":if(this.prerelease.length===0)this.prerelease=[0];else{var t=this.prerelease.length;while(--t>=0){if(typeof this.prerelease[t]==="number"){this.prerelease[t]++;t=-2}}if(t===-1)this.prerelease.push(0)}if(r){if(this.prerelease[0]===r){if(isNaN(this.prerelease[1]))this.prerelease=[r,0]}else this.prerelease=[r,0]}break;default:throw new Error("invalid increment argument: "+e)}this.format();return this};e.inc=Q;function Q(e,r,t,n){if(typeof t==="string"){n=t;t=undefined}try{return new K(e,t).inc(r,n).version}catch(i){return null}}e.diff=U;function U(e,r){if(hr(e,r)){return null}else{var t=D(e);var n=D(r);if(t.prerelease.length||n.prerelease.length){for(var i in t){if(i==="major"||i==="minor"||i==="patch"){if(t[i]!==n[i]){return"pre"+i}}}return"prerelease"}for(var i in t){if(i==="major"||i==="minor"||i==="patch"){if(t[i]!==n[i]){return i}}}}}e.compareIdentifiers=Y;var W=/^[0-9]+$/;function Y(e,r){var t=W.test(e);var n=W.test(r);if(t&&n){e=+e;r=+r}return t&&!n?-1:n&&!t?1:e<r?-1:e>r?1:0}e.rcompareIdentifiers=er;function er(e,r){return Y(r,e)}e.major=rr;function rr(e,r){return new K(e,r).major}e.minor=tr;function tr(e,r){return new K(e,r).minor}e.patch=nr;function nr(e,r){return new K(e,r).patch}e.compare=ir;function ir(e,r,t){return new K(e,t).compare(r)}e.compareLoose=sr;function sr(e,r){return ir(e,r,true)}e.rcompare=or;function or(e,r,t){return ir(r,e,t)}e.sort=ar;function ar(r,t){return r.sort(function(r,n){return e.compare(r,n,t)})}e.rsort=fr;function fr(r,t){return r.sort(function(r,n){return e.rcompare(r,n,t)})}e.gt=ur;function ur(e,r,t){return ir(e,r,t)>0}e.lt=lr;function lr(e,r,t){return ir(e,r,t)<0}e.eq=hr;function hr(e,r,t){return ir(e,r,t)===0}e.neq=pr;function pr(e,r,t){return ir(e,r,t)!==0}e.gte=cr;function cr(e,r,t){return ir(e,r,t)>=0}e.lte=vr;function vr(e,r,t){return ir(e,r,t)<=0}e.cmp=mr;function mr(e,r,t,n){var i;switch(r){case"===":if(typeof e==="object")e=e.version;if(typeof t==="object")t=t.version;i=e===t;break;case"!==":if(typeof e==="object")e=e.version;if(typeof t==="object")t=t.version;i=e!==t;break;case"":case"=":case"==":i=hr(e,t,n);break;case"!=":i=pr(e,t,n);break;case">":i=ur(e,t,n);break;case">=":i=cr(e,t,n);break;case"<":i=lr(e,t,n);break;case"<=":i=vr(e,t,n);break;default:throw new TypeError("Invalid operator: "+r)}return i}e.Comparator=gr;function gr(e,r){if(e instanceof gr){if(e.loose===r)return e;else e=e.value}if(!(this instanceof gr))return new gr(e,r);this.loose=r;this.parse(e);if(this.semver===wr)this.value="";else this.value=this.operator+this.semver.version}var wr={};gr.prototype.parse=function(e){var r=this.loose?n[X]:n[Z];var t=e.match(r);if(!t)throw new TypeError("Invalid comparator: "+e);this.operator=t[1];if(this.operator==="=")this.operator="";if(!t[2])this.semver=wr;else this.semver=new K(t[2],this.loose)};gr.prototype.inspect=function(){return'<SemVer Comparator "'+this+'">'};gr.prototype.toString=function(){return this.value};gr.prototype.test=function(e){if(this.semver===wr)return true;if(typeof e==="string")e=new K(e,this.loose);return mr(e,this.operator,this.semver,this.loose)};e.Range=yr;function yr(e,r){if(e instanceof yr&&e.loose===r)return e;if(!(this instanceof yr))return new yr(e,r);this.loose=r;this.raw=e;this.set=e.split(/\s*\|\|\s*/).map(function(e){return this.parseRange(e.trim())},this).filter(function(e){return e.length});if(!this.set.length){throw new TypeError("Invalid SemVer Range: "+e)}this.format()}yr.prototype.inspect=function(){return'<SemVer Range "'+this.range+'">'};yr.prototype.format=function(){this.range=this.set.map(function(e){return e.join(" ").trim()}).join("||").trim();return this.range};yr.prototype.toString=function(){return this.range};yr.prototype.parseRange=function(e){var r=this.loose;e=e.trim();var t=r?n[G]:n[F];e=e.replace(t,Tr);e=e.replace(n[q],L);e=e.replace(n[T],V);e=e.replace(n[N],_);e=e.split(/\s+/).join(" ");var i=r?n[X]:n[Z];var s=e.split(" ").map(function(e){return jr(e,r)}).join(" ").split(/\s+/);if(this.loose){s=s.filter(function(e){return!!e.match(i)})}s=s.map(function(e){return new gr(e,r)});return s};e.toComparators=dr;function dr(e,r){return new yr(e,r).set.map(function(e){return e.map(function(e){return e.value}).join(" ").trim().split(" ")})}function jr(e,r){e=kr(e,r);e=Er(e,r);e=Sr(e,r);e=Ir(e,r);return e}function br(e){return!e||e.toLowerCase()==="x"||e==="*"}function Er(e,r){return e.trim().split(/\s+/).map(function(e){return $r(e,r)}).join(" ")}function $r(e,r){var t=r?n[C]:n[A];return e.replace(t,function(e,r,t,n,i){var s;if(br(r))s="";else if(br(t))s=">="+r+".0.0 <"+(+r+1)+".0.0";else if(br(n))s=">="+r+"."+t+".0 <"+r+"."+(+t+1)+".0";else if(i){if(i.charAt(0)!=="-")i="-"+i;s=">="+r+"."+t+"."+n+i+" <"+r+"."+(+t+1)+".0"}else s=">="+r+"."+t+"."+n+" <"+r+"."+(+t+1)+".0";return s})}function kr(e,r){return e.trim().split(/\s+/).map(function(e){return Rr(e,r)}).join(" ")}function Rr(e,r){var t=r?n[P]:n[z];return e.replace(t,function(e,r,t,n,i){var s;if(br(r))s="";else if(br(t))s=">="+r+".0.0 <"+(+r+1)+".0.0";else if(br(n)){if(r==="0")s=">="+r+"."+t+".0 <"+r+"."+(+t+1)+".0";else s=">="+r+"."+t+".0 <"+(+r+1)+".0.0"}else if(i){if(i.charAt(0)!=="-")i="-"+i;if(r==="0"){if(t==="0")s=">="+r+"."+t+"."+n+i+" <"+r+"."+t+"."+(+n+1);else s=">="+r+"."+t+"."+n+i+" <"+r+"."+(+t+1)+".0"}else s=">="+r+"."+t+"."+n+i+" <"+(+r+1)+".0.0"}else{if(r==="0"){if(t==="0")s=">="+r+"."+t+"."+n+" <"+r+"."+t+"."+(+n+1);else s=">="+r+"."+t+"."+n+" <"+r+"."+(+t+1)+".0"}else s=">="+r+"."+t+"."+n+" <"+(+r+1)+".0.0"}return s})}function Sr(e,r){return e.split(/\s+/).map(function(e){return xr(e,r)}).join(" ")}function xr(e,r){e=e.trim();var t=r?n[x]:n[S];return e.replace(t,function(e,r,t,n,i,s){var o=br(t);var a=o||br(n);var f=a||br(i);var u=f;if(r==="="&&u)r="";if(o){if(r===">"||r==="<"){e="<0.0.0"}else{e="*"}}else if(r&&u){if(a)n=0;if(f)i=0;if(r===">"){r=">=";if(a){t=+t+1;n=0;i=0}else if(f){n=+n+1;i=0}}else if(r==="<="){r="<";if(a)t=+t+1;else n=+n+1}e=r+t+"."+n+"."+i}else if(a){e=">="+t+".0.0 <"+(+t+1)+".0.0"}else if(f){e=">="+t+"."+n+".0 <"+t+"."+(+n+1)+".0"}return e})}function Ir(e,r){return e.trim().replace(n[O],"")}function Tr(e,r,t,n,i,s,o,a,f,u,l,h,p){if(br(t))r="";else if(br(n))r=">="+t+".0.0";else if(br(i))r=">="+t+"."+n+".0";else r=">="+r;if(br(f))a="";else if(br(u))a="<"+(+f+1)+".0.0";else if(br(l))a="<"+f+"."+(+u+1)+".0";else if(h)a="<="+f+"."+u+"."+l+"-"+h;else a="<="+a;return(r+" "+a).trim()}yr.prototype.test=function(e){if(!e)return false;if(typeof e==="string")e=new K(e,this.loose);for(var r=0;r<this.set.length;r++){if(Vr(this.set[r],e))return true}return false};function Vr(e,r){for(var t=0;t<e.length;t++){if(!e[t].test(r))return false}if(r.prerelease.length){for(var t=0;t<e.length;t++){if(e[t].semver===wr)return true;if(e[t].semver.prerelease.length>0){var n=e[t].semver;if(n.major===r.major&&n.minor===r.minor&&n.patch===r.patch)return true}}return false}return true}e.satisfies=Ar;function Ar(e,r,t){try{r=new yr(r,t)}catch(n){return false}return r.test(e)}e.maxSatisfying=Cr;function Cr(e,r,t){return e.filter(function(e){return Ar(e,r,t)}).sort(function(e,r){return or(e,r,t)})[0]||null}e.validRange=Mr;function Mr(e,r){try{return new yr(e,r).range||"*"}catch(t){return null}}e.ltr=Nr;function Nr(e,r,t){return zr(e,r,"<",t)}e.gtr=_r;function _r(e,r,t){return zr(e,r,">",t)}e.outside=zr;function zr(e,r,t,n){e=new K(e,n);r=new yr(r,n);var i,s,o,a,f;switch(t){case">":i=ur;s=vr;o=lr;a=">";f=">=";break;case"<":i=lr;s=cr;o=ur;a="<";f="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(Ar(e,r,n)){return false}for(var u=0;u<r.set.length;++u){var l=r.set[u];var h=null;var p=null;l.forEach(function(e){h=h||e;p=p||e;if(i(e.semver,h.semver,n)){h=e}else if(o(e.semver,p.semver,n)){p=e}});if(h.operator===a||h.operator===f){return false}if((!p.operator||p.operator===a)&&s(e,p.semver)){return false}else if(p.operator===f&&o(e,p.semver)){return false}}return true}if(typeof define==="function"&&define.amd)define(e)})(typeof exports==="object"?exports:typeof define==="function"&&define.amd?{}:semver={});
\ No newline at end of file
diff --git a/server/node_modules/pg/node_modules/semver/semver.min.js.gz b/server/node_modules/pg/node_modules/semver/semver.min.js.gz
new file mode 100644
index 0000000000000000000000000000000000000000..fbe42dd59317b9d6b5a1690aa68e1d9dc0392857
Binary files /dev/null and b/server/node_modules/pg/node_modules/semver/semver.min.js.gz differ
diff --git a/server/node_modules/pg/node_modules/semver/test/amd.js b/server/node_modules/pg/node_modules/semver/test/amd.js
new file mode 100644
index 0000000000000000000000000000000000000000..a6041341b37ee943f41d875cbb4a4d34d5b587d2
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/test/amd.js
@@ -0,0 +1,15 @@
+var tap = require('tap');
+var test = tap.test;
+
+test('amd', function(t) {
+  global.define = define;
+  define.amd = true;
+  var defined = null;
+  function define(stuff) {
+    defined = stuff;
+  }
+  var fromRequire = require('../');
+  t.ok(defined, 'amd function called');
+  t.equal(fromRequire, defined, 'amd stuff same as require stuff');
+  t.end();
+});
diff --git a/server/node_modules/pg/node_modules/semver/test/big-numbers.js b/server/node_modules/pg/node_modules/semver/test/big-numbers.js
new file mode 100644
index 0000000000000000000000000000000000000000..692aa241461213f0fb2786019fd0b2e7fe4d1114
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/test/big-numbers.js
@@ -0,0 +1,24 @@
+var test = require('tap').test
+var semver = require('../')
+
+test('long version is too long', function (t) {
+  var v = '1.2.' + new Array(256).join('1')
+  t.throws(function () {
+    new semver.SemVer(v)
+  })
+  t.equal(semver.valid(v, false), null)
+  t.equal(semver.valid(v, true), null)
+  t.equal(semver.inc(v, 'patch'), null)
+  t.end()
+})
+
+test('big number is like too long version', function (t) {
+  var v = '1.2.' + new Array(100).join('1')
+  t.throws(function () {
+    new semver.SemVer(v)
+  })
+  t.equal(semver.valid(v, false), null)
+  t.equal(semver.valid(v, true), null)
+  t.equal(semver.inc(v, 'patch'), null)
+  t.end()
+})
diff --git a/server/node_modules/pg/node_modules/semver/test/clean.js b/server/node_modules/pg/node_modules/semver/test/clean.js
new file mode 100644
index 0000000000000000000000000000000000000000..9e268de950ce8cf6bebf19423a657fb10c59e157
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/test/clean.js
@@ -0,0 +1,29 @@
+var tap = require('tap');
+var test = tap.test;
+var semver = require('../semver.js');
+var clean = semver.clean;
+
+test('\nclean tests', function(t) {
+	// [range, version]
+	// Version should be detectable despite extra characters
+	[
+		['1.2.3', '1.2.3'],
+		[' 1.2.3 ', '1.2.3'],
+		[' 1.2.3-4 ', '1.2.3-4'],
+		[' 1.2.3-pre ', '1.2.3-pre'],
+		['  =v1.2.3   ', '1.2.3'],
+		['v1.2.3', '1.2.3'],
+		[' v1.2.3 ', '1.2.3'],
+		['\t1.2.3', '1.2.3'],
+		['>1.2.3', null],
+		['~1.2.3', null],
+		['<=1.2.3', null],
+		['1.2.x', null]
+	].forEach(function(tuple) {
+			var range = tuple[0];
+			var version = tuple[1];
+			var msg = 'clean(' + range + ') = ' + version;
+			t.equal(clean(range), version, msg);
+		});
+	t.end();
+});
diff --git a/server/node_modules/pg/node_modules/semver/test/gtr.js b/server/node_modules/pg/node_modules/semver/test/gtr.js
new file mode 100644
index 0000000000000000000000000000000000000000..bbb87896c64fbbb1c66892ac36c2f43121794ab1
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/test/gtr.js
@@ -0,0 +1,173 @@
+var tap = require('tap');
+var test = tap.test;
+var semver = require('../semver.js');
+var gtr = semver.gtr;
+
+test('\ngtr tests', function(t) {
+  // [range, version, loose]
+  // Version should be greater than range
+  [
+    ['~1.2.2', '1.3.0'],
+    ['~0.6.1-1', '0.7.1-1'],
+    ['1.0.0 - 2.0.0', '2.0.1'],
+    ['1.0.0', '1.0.1-beta1'],
+    ['1.0.0', '2.0.0'],
+    ['<=2.0.0', '2.1.1'],
+    ['<=2.0.0', '3.2.9'],
+    ['<2.0.0', '2.0.0'],
+    ['0.1.20 || 1.2.4', '1.2.5'],
+    ['2.x.x', '3.0.0'],
+    ['1.2.x', '1.3.0'],
+    ['1.2.x || 2.x', '3.0.0'],
+    ['2.*.*', '5.0.1'],
+    ['1.2.*', '1.3.3'],
+    ['1.2.* || 2.*', '4.0.0'],
+    ['2', '3.0.0'],
+    ['2.3', '2.4.2'],
+    ['~2.4', '2.5.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.5.5'],
+    ['~>3.2.1', '3.3.0'], // >=3.2.1 <3.3.0
+    ['~1', '2.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '2.2.4'],
+    ['~> 1', '3.2.3'],
+    ['~1.0', '1.1.2'], // >=1.0.0 <1.1.0
+    ['~ 1.0', '1.1.0'],
+    ['<1.2', '1.2.0'],
+    ['< 1.2', '1.2.1'],
+    ['1', '2.0.0beta', true],
+    ['~v0.5.4-pre', '0.6.0'],
+    ['~v0.5.4-pre', '0.6.1-pre'],
+    ['=0.7.x', '0.8.0'],
+    ['=0.7.x', '0.8.0-asdf'],
+    ['<0.7.x', '0.7.0'],
+    ['~1.2.2', '1.3.0'],
+    ['1.0.0 - 2.0.0', '2.2.3'],
+    ['1.0.0', '1.0.1'],
+    ['<=2.0.0', '3.0.0'],
+    ['<=2.0.0', '2.9999.9999'],
+    ['<=2.0.0', '2.2.9'],
+    ['<2.0.0', '2.9999.9999'],
+    ['<2.0.0', '2.2.9'],
+    ['2.x.x', '3.1.3'],
+    ['1.2.x', '1.3.3'],
+    ['1.2.x || 2.x', '3.1.3'],
+    ['2.*.*', '3.1.3'],
+    ['1.2.*', '1.3.3'],
+    ['1.2.* || 2.*', '3.1.3'],
+    ['2', '3.1.2'],
+    ['2.3', '2.4.1'],
+    ['~2.4', '2.5.0'], // >=2.4.0 <2.5.0
+    ['~>3.2.1', '3.3.2'], // >=3.2.1 <3.3.0
+    ['~1', '2.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '2.2.3'],
+    ['~1.0', '1.1.0'], // >=1.0.0 <1.1.0
+    ['<1', '1.0.0'],
+    ['1', '2.0.0beta', true],
+    ['<1', '1.0.0beta', true],
+    ['< 1', '1.0.0beta', true],
+    ['=0.7.x', '0.8.2'],
+    ['<0.7.x', '0.7.2']
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = 'gtr(' + version + ', ' + range + ', ' + loose + ')';
+    t.ok(gtr(version, range, loose), msg);
+  });
+  t.end();
+});
+
+test('\nnegative gtr tests', function(t) {
+  // [range, version, loose]
+  // Version should NOT be greater than range
+  [
+    ['~0.6.1-1', '0.6.1-1'],
+    ['1.0.0 - 2.0.0', '1.2.3'],
+    ['1.0.0 - 2.0.0', '0.9.9'],
+    ['1.0.0', '1.0.0'],
+    ['>=*', '0.2.4'],
+    ['', '1.0.0', true],
+    ['*', '1.2.3'],
+    ['*', 'v1.2.3-foo'],
+    ['>=1.0.0', '1.0.0'],
+    ['>=1.0.0', '1.0.1'],
+    ['>=1.0.0', '1.1.0'],
+    ['>1.0.0', '1.0.1'],
+    ['>1.0.0', '1.1.0'],
+    ['<=2.0.0', '2.0.0'],
+    ['<=2.0.0', '1.9999.9999'],
+    ['<=2.0.0', '0.2.9'],
+    ['<2.0.0', '1.9999.9999'],
+    ['<2.0.0', '0.2.9'],
+    ['>= 1.0.0', '1.0.0'],
+    ['>=  1.0.0', '1.0.1'],
+    ['>=   1.0.0', '1.1.0'],
+    ['> 1.0.0', '1.0.1'],
+    ['>  1.0.0', '1.1.0'],
+    ['<=   2.0.0', '2.0.0'],
+    ['<= 2.0.0', '1.9999.9999'],
+    ['<=  2.0.0', '0.2.9'],
+    ['<    2.0.0', '1.9999.9999'],
+    ['<\t2.0.0', '0.2.9'],
+    ['>=0.1.97', 'v0.1.97'],
+    ['>=0.1.97', '0.1.97'],
+    ['0.1.20 || 1.2.4', '1.2.4'],
+    ['0.1.20 || >1.2.4', '1.2.4'],
+    ['0.1.20 || 1.2.4', '1.2.3'],
+    ['0.1.20 || 1.2.4', '0.1.20'],
+    ['>=0.2.3 || <0.0.1', '0.0.0'],
+    ['>=0.2.3 || <0.0.1', '0.2.3'],
+    ['>=0.2.3 || <0.0.1', '0.2.4'],
+    ['||', '1.3.4'],
+    ['2.x.x', '2.1.3'],
+    ['1.2.x', '1.2.3'],
+    ['1.2.x || 2.x', '2.1.3'],
+    ['1.2.x || 2.x', '1.2.3'],
+    ['x', '1.2.3'],
+    ['2.*.*', '2.1.3'],
+    ['1.2.*', '1.2.3'],
+    ['1.2.* || 2.*', '2.1.3'],
+    ['1.2.* || 2.*', '1.2.3'],
+    ['1.2.* || 2.*', '1.2.3'],
+    ['*', '1.2.3'],
+    ['2', '2.1.2'],
+    ['2.3', '2.3.1'],
+    ['~2.4', '2.4.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.4.5'],
+    ['~>3.2.1', '3.2.2'], // >=3.2.1 <3.3.0
+    ['~1', '1.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '1.2.3'],
+    ['~> 1', '1.2.3'],
+    ['~1.0', '1.0.2'], // >=1.0.0 <1.1.0
+    ['~ 1.0', '1.0.2'],
+    ['>=1', '1.0.0'],
+    ['>= 1', '1.0.0'],
+    ['<1.2', '1.1.1'],
+    ['< 1.2', '1.1.1'],
+    ['1', '1.0.0beta', true],
+    ['~v0.5.4-pre', '0.5.5'],
+    ['~v0.5.4-pre', '0.5.4'],
+    ['=0.7.x', '0.7.2'],
+    ['>=0.7.x', '0.7.2'],
+    ['=0.7.x', '0.7.0-asdf'],
+    ['>=0.7.x', '0.7.0-asdf'],
+    ['<=0.7.x', '0.6.2'],
+    ['>0.2.3 >0.2.4 <=0.2.5', '0.2.5'],
+    ['>=0.2.3 <=0.2.4', '0.2.4'],
+    ['1.0.0 - 2.0.0', '2.0.0'],
+    ['^1', '0.0.0-0'],
+    ['^3.0.0', '2.0.0'],
+    ['^1.0.0 || ~2.0.1', '2.0.0'],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '3.2.0'],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '1.0.0beta', true],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '5.0.0-0', true],
+    ['^0.1.0 || ~3.0.1 || >4 <=5.0.0', '3.5.0']
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = '!gtr(' + version + ', ' + range + ', ' + loose + ')';
+    t.notOk(gtr(version, range, loose), msg);
+  });
+  t.end();
+});
diff --git a/server/node_modules/pg/node_modules/semver/test/index.js b/server/node_modules/pg/node_modules/semver/test/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..926d560fe0a5fd3b9c643e6ba8ac248ea2ab4dc2
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/test/index.js
@@ -0,0 +1,684 @@
+'use strict';
+
+var tap = require('tap');
+var test = tap.test;
+var semver = require('../semver.js');
+var eq = semver.eq;
+var gt = semver.gt;
+var lt = semver.lt;
+var neq = semver.neq;
+var cmp = semver.cmp;
+var gte = semver.gte;
+var lte = semver.lte;
+var satisfies = semver.satisfies;
+var validRange = semver.validRange;
+var inc = semver.inc;
+var diff = semver.diff;
+var replaceStars = semver.replaceStars;
+var toComparators = semver.toComparators;
+var SemVer = semver.SemVer;
+var Range = semver.Range;
+
+test('\ncomparison tests', function(t) {
+  // [version1, version2]
+  // version1 should be greater than version2
+  [['0.0.0', '0.0.0-foo'],
+    ['0.0.1', '0.0.0'],
+    ['1.0.0', '0.9.9'],
+    ['0.10.0', '0.9.0'],
+    ['0.99.0', '0.10.0'],
+    ['2.0.0', '1.2.3'],
+    ['v0.0.0', '0.0.0-foo', true],
+    ['v0.0.1', '0.0.0', true],
+    ['v1.0.0', '0.9.9', true],
+    ['v0.10.0', '0.9.0', true],
+    ['v0.99.0', '0.10.0', true],
+    ['v2.0.0', '1.2.3', true],
+    ['0.0.0', 'v0.0.0-foo', true],
+    ['0.0.1', 'v0.0.0', true],
+    ['1.0.0', 'v0.9.9', true],
+    ['0.10.0', 'v0.9.0', true],
+    ['0.99.0', 'v0.10.0', true],
+    ['2.0.0', 'v1.2.3', true],
+    ['1.2.3', '1.2.3-asdf'],
+    ['1.2.3', '1.2.3-4'],
+    ['1.2.3', '1.2.3-4-foo'],
+    ['1.2.3-5-foo', '1.2.3-5'],
+    ['1.2.3-5', '1.2.3-4'],
+    ['1.2.3-5-foo', '1.2.3-5-Foo'],
+    ['3.0.0', '2.7.2+asdf'],
+    ['1.2.3-a.10', '1.2.3-a.5'],
+    ['1.2.3-a.b', '1.2.3-a.5'],
+    ['1.2.3-a.b', '1.2.3-a'],
+    ['1.2.3-a.b.c.10.d.5', '1.2.3-a.b.c.5.d.100'],
+    ['1.2.3-r2', '1.2.3-r100'],
+    ['1.2.3-r100', '1.2.3-R2']
+  ].forEach(function(v) {
+    var v0 = v[0];
+    var v1 = v[1];
+    var loose = v[2];
+    t.ok(gt(v0, v1, loose), "gt('" + v0 + "', '" + v1 + "')");
+    t.ok(lt(v1, v0, loose), "lt('" + v1 + "', '" + v0 + "')");
+    t.ok(!gt(v1, v0, loose), "!gt('" + v1 + "', '" + v0 + "')");
+    t.ok(!lt(v0, v1, loose), "!lt('" + v0 + "', '" + v1 + "')");
+    t.ok(eq(v0, v0, loose), "eq('" + v0 + "', '" + v0 + "')");
+    t.ok(eq(v1, v1, loose), "eq('" + v1 + "', '" + v1 + "')");
+    t.ok(neq(v0, v1, loose), "neq('" + v0 + "', '" + v1 + "')");
+    t.ok(cmp(v1, '==', v1, loose), "cmp('" + v1 + "' == '" + v1 + "')");
+    t.ok(cmp(v0, '>=', v1, loose), "cmp('" + v0 + "' >= '" + v1 + "')");
+    t.ok(cmp(v1, '<=', v0, loose), "cmp('" + v1 + "' <= '" + v0 + "')");
+    t.ok(cmp(v0, '!=', v1, loose), "cmp('" + v0 + "' != '" + v1 + "')");
+  });
+  t.end();
+});
+
+test('\nequality tests', function(t) {
+  // [version1, version2]
+  // version1 should be equivalent to version2
+  [['1.2.3', 'v1.2.3', true],
+    ['1.2.3', '=1.2.3', true],
+    ['1.2.3', 'v 1.2.3', true],
+    ['1.2.3', '= 1.2.3', true],
+    ['1.2.3', ' v1.2.3', true],
+    ['1.2.3', ' =1.2.3', true],
+    ['1.2.3', ' v 1.2.3', true],
+    ['1.2.3', ' = 1.2.3', true],
+    ['1.2.3-0', 'v1.2.3-0', true],
+    ['1.2.3-0', '=1.2.3-0', true],
+    ['1.2.3-0', 'v 1.2.3-0', true],
+    ['1.2.3-0', '= 1.2.3-0', true],
+    ['1.2.3-0', ' v1.2.3-0', true],
+    ['1.2.3-0', ' =1.2.3-0', true],
+    ['1.2.3-0', ' v 1.2.3-0', true],
+    ['1.2.3-0', ' = 1.2.3-0', true],
+    ['1.2.3-1', 'v1.2.3-1', true],
+    ['1.2.3-1', '=1.2.3-1', true],
+    ['1.2.3-1', 'v 1.2.3-1', true],
+    ['1.2.3-1', '= 1.2.3-1', true],
+    ['1.2.3-1', ' v1.2.3-1', true],
+    ['1.2.3-1', ' =1.2.3-1', true],
+    ['1.2.3-1', ' v 1.2.3-1', true],
+    ['1.2.3-1', ' = 1.2.3-1', true],
+    ['1.2.3-beta', 'v1.2.3-beta', true],
+    ['1.2.3-beta', '=1.2.3-beta', true],
+    ['1.2.3-beta', 'v 1.2.3-beta', true],
+    ['1.2.3-beta', '= 1.2.3-beta', true],
+    ['1.2.3-beta', ' v1.2.3-beta', true],
+    ['1.2.3-beta', ' =1.2.3-beta', true],
+    ['1.2.3-beta', ' v 1.2.3-beta', true],
+    ['1.2.3-beta', ' = 1.2.3-beta', true],
+    ['1.2.3-beta+build', ' = 1.2.3-beta+otherbuild', true],
+    ['1.2.3+build', ' = 1.2.3+otherbuild', true],
+    ['1.2.3-beta+build', '1.2.3-beta+otherbuild'],
+    ['1.2.3+build', '1.2.3+otherbuild'],
+    ['  v1.2.3+build', '1.2.3+otherbuild']
+  ].forEach(function(v) {
+    var v0 = v[0];
+    var v1 = v[1];
+    var loose = v[2];
+    t.ok(eq(v0, v1, loose), "eq('" + v0 + "', '" + v1 + "')");
+    t.ok(!neq(v0, v1, loose), "!neq('" + v0 + "', '" + v1 + "')");
+    t.ok(cmp(v0, '==', v1, loose), 'cmp(' + v0 + '==' + v1 + ')');
+    t.ok(!cmp(v0, '!=', v1, loose), '!cmp(' + v0 + '!=' + v1 + ')');
+    t.ok(!cmp(v0, '===', v1, loose), '!cmp(' + v0 + '===' + v1 + ')');
+    t.ok(cmp(v0, '!==', v1, loose), 'cmp(' + v0 + '!==' + v1 + ')');
+    t.ok(!gt(v0, v1, loose), "!gt('" + v0 + "', '" + v1 + "')");
+    t.ok(gte(v0, v1, loose), "gte('" + v0 + "', '" + v1 + "')");
+    t.ok(!lt(v0, v1, loose), "!lt('" + v0 + "', '" + v1 + "')");
+    t.ok(lte(v0, v1, loose), "lte('" + v0 + "', '" + v1 + "')");
+  });
+  t.end();
+});
+
+
+test('\nrange tests', function(t) {
+  // [range, version]
+  // version should be included by range
+  [['1.0.0 - 2.0.0', '1.2.3'],
+    ['^1.2.3+build', '1.2.3'],
+    ['^1.2.3+build', '1.3.0'],
+    ['1.2.3-pre+asdf - 2.4.3-pre+asdf', '1.2.3'],
+    ['1.2.3pre+asdf - 2.4.3-pre+asdf', '1.2.3', true],
+    ['1.2.3-pre+asdf - 2.4.3pre+asdf', '1.2.3', true],
+    ['1.2.3pre+asdf - 2.4.3pre+asdf', '1.2.3', true],
+    ['1.2.3-pre+asdf - 2.4.3-pre+asdf', '1.2.3-pre.2'],
+    ['1.2.3-pre+asdf - 2.4.3-pre+asdf', '2.4.3-alpha'],
+    ['1.2.3+asdf - 2.4.3+asdf', '1.2.3'],
+    ['1.0.0', '1.0.0'],
+    ['>=*', '0.2.4'],
+    ['', '1.0.0'],
+    ['*', '1.2.3'],
+    ['*', 'v1.2.3-foo', true],
+    ['>=1.0.0', '1.0.0'],
+    ['>=1.0.0', '1.0.1'],
+    ['>=1.0.0', '1.1.0'],
+    ['>1.0.0', '1.0.1'],
+    ['>1.0.0', '1.1.0'],
+    ['<=2.0.0', '2.0.0'],
+    ['<=2.0.0', '1.9999.9999'],
+    ['<=2.0.0', '0.2.9'],
+    ['<2.0.0', '1.9999.9999'],
+    ['<2.0.0', '0.2.9'],
+    ['>= 1.0.0', '1.0.0'],
+    ['>=  1.0.0', '1.0.1'],
+    ['>=   1.0.0', '1.1.0'],
+    ['> 1.0.0', '1.0.1'],
+    ['>  1.0.0', '1.1.0'],
+    ['<=   2.0.0', '2.0.0'],
+    ['<= 2.0.0', '1.9999.9999'],
+    ['<=  2.0.0', '0.2.9'],
+    ['<    2.0.0', '1.9999.9999'],
+    ['<\t2.0.0', '0.2.9'],
+    ['>=0.1.97', 'v0.1.97', true],
+    ['>=0.1.97', '0.1.97'],
+    ['0.1.20 || 1.2.4', '1.2.4'],
+    ['>=0.2.3 || <0.0.1', '0.0.0'],
+    ['>=0.2.3 || <0.0.1', '0.2.3'],
+    ['>=0.2.3 || <0.0.1', '0.2.4'],
+    ['||', '1.3.4'],
+    ['2.x.x', '2.1.3'],
+    ['1.2.x', '1.2.3'],
+    ['1.2.x || 2.x', '2.1.3'],
+    ['1.2.x || 2.x', '1.2.3'],
+    ['x', '1.2.3'],
+    ['2.*.*', '2.1.3'],
+    ['1.2.*', '1.2.3'],
+    ['1.2.* || 2.*', '2.1.3'],
+    ['1.2.* || 2.*', '1.2.3'],
+    ['*', '1.2.3'],
+    ['2', '2.1.2'],
+    ['2.3', '2.3.1'],
+    ['~2.4', '2.4.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.4.5'],
+    ['~>3.2.1', '3.2.2'], // >=3.2.1 <3.3.0,
+    ['~1', '1.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '1.2.3'],
+    ['~> 1', '1.2.3'],
+    ['~1.0', '1.0.2'], // >=1.0.0 <1.1.0,
+    ['~ 1.0', '1.0.2'],
+    ['~ 1.0.3', '1.0.12'],
+    ['>=1', '1.0.0'],
+    ['>= 1', '1.0.0'],
+    ['<1.2', '1.1.1'],
+    ['< 1.2', '1.1.1'],
+    ['~v0.5.4-pre', '0.5.5'],
+    ['~v0.5.4-pre', '0.5.4'],
+    ['=0.7.x', '0.7.2'],
+    ['<=0.7.x', '0.7.2'],
+    ['>=0.7.x', '0.7.2'],
+    ['<=0.7.x', '0.6.2'],
+    ['~1.2.1 >=1.2.3', '1.2.3'],
+    ['~1.2.1 =1.2.3', '1.2.3'],
+    ['~1.2.1 1.2.3', '1.2.3'],
+    ['~1.2.1 >=1.2.3 1.2.3', '1.2.3'],
+    ['~1.2.1 1.2.3 >=1.2.3', '1.2.3'],
+    ['~1.2.1 1.2.3', '1.2.3'],
+    ['>=1.2.1 1.2.3', '1.2.3'],
+    ['1.2.3 >=1.2.1', '1.2.3'],
+    ['>=1.2.3 >=1.2.1', '1.2.3'],
+    ['>=1.2.1 >=1.2.3', '1.2.3'],
+    ['>=1.2', '1.2.8'],
+    ['^1.2.3', '1.8.1'],
+    ['^0.1.2', '0.1.2'],
+    ['^0.1', '0.1.2'],
+    ['^1.2', '1.4.2'],
+    ['^1.2 ^1', '1.4.2'],
+    ['^1.2.3-alpha', '1.2.3-pre'],
+    ['^1.2.0-alpha', '1.2.0-pre'],
+    ['^0.0.1-alpha', '0.0.1-beta']
+  ].forEach(function(v) {
+    var range = v[0];
+    var ver = v[1];
+    var loose = v[2];
+    t.ok(satisfies(ver, range, loose), range + ' satisfied by ' + ver);
+  });
+  t.end();
+});
+
+test('\nnegative range tests', function(t) {
+  // [range, version]
+  // version should not be included by range
+  [['1.0.0 - 2.0.0', '2.2.3'],
+    ['1.2.3+asdf - 2.4.3+asdf', '1.2.3-pre.2'],
+    ['1.2.3+asdf - 2.4.3+asdf', '2.4.3-alpha'],
+    ['^1.2.3+build', '2.0.0'],
+    ['^1.2.3+build', '1.2.0'],
+    ['^1.2.3', '1.2.3-pre'],
+    ['^1.2', '1.2.0-pre'],
+    ['>1.2', '1.3.0-beta'],
+    ['<=1.2.3', '1.2.3-beta'],
+    ['^1.2.3', '1.2.3-beta'],
+    ['=0.7.x', '0.7.0-asdf'],
+    ['>=0.7.x', '0.7.0-asdf'],
+    ['1', '1.0.0beta', true],
+    ['<1', '1.0.0beta', true],
+    ['< 1', '1.0.0beta', true],
+    ['1.0.0', '1.0.1'],
+    ['>=1.0.0', '0.0.0'],
+    ['>=1.0.0', '0.0.1'],
+    ['>=1.0.0', '0.1.0'],
+    ['>1.0.0', '0.0.1'],
+    ['>1.0.0', '0.1.0'],
+    ['<=2.0.0', '3.0.0'],
+    ['<=2.0.0', '2.9999.9999'],
+    ['<=2.0.0', '2.2.9'],
+    ['<2.0.0', '2.9999.9999'],
+    ['<2.0.0', '2.2.9'],
+    ['>=0.1.97', 'v0.1.93', true],
+    ['>=0.1.97', '0.1.93'],
+    ['0.1.20 || 1.2.4', '1.2.3'],
+    ['>=0.2.3 || <0.0.1', '0.0.3'],
+    ['>=0.2.3 || <0.0.1', '0.2.2'],
+    ['2.x.x', '1.1.3'],
+    ['2.x.x', '3.1.3'],
+    ['1.2.x', '1.3.3'],
+    ['1.2.x || 2.x', '3.1.3'],
+    ['1.2.x || 2.x', '1.1.3'],
+    ['2.*.*', '1.1.3'],
+    ['2.*.*', '3.1.3'],
+    ['1.2.*', '1.3.3'],
+    ['1.2.* || 2.*', '3.1.3'],
+    ['1.2.* || 2.*', '1.1.3'],
+    ['2', '1.1.2'],
+    ['2.3', '2.4.1'],
+    ['~2.4', '2.5.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.3.9'],
+    ['~>3.2.1', '3.3.2'], // >=3.2.1 <3.3.0
+    ['~>3.2.1', '3.2.0'], // >=3.2.1 <3.3.0
+    ['~1', '0.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '2.2.3'],
+    ['~1.0', '1.1.0'], // >=1.0.0 <1.1.0
+    ['<1', '1.0.0'],
+    ['>=1.2', '1.1.1'],
+    ['1', '2.0.0beta', true],
+    ['~v0.5.4-beta', '0.5.4-alpha'],
+    ['=0.7.x', '0.8.2'],
+    ['>=0.7.x', '0.6.2'],
+    ['<0.7.x', '0.7.2'],
+    ['<1.2.3', '1.2.3-beta'],
+    ['=1.2.3', '1.2.3-beta'],
+    ['>1.2', '1.2.8'],
+    ['^1.2.3', '2.0.0-alpha'],
+    ['^1.2.3', '1.2.2'],
+    ['^1.2', '1.1.9'],
+    // invalid ranges never satisfied!
+    ['blerg', '1.2.3'],
+    ['git+https://user:password0123@github.com/foo', '123.0.0', true],
+    ['^1.2.3', '2.0.0-pre']
+  ].forEach(function(v) {
+    var range = v[0];
+    var ver = v[1];
+    var loose = v[2];
+    var found = satisfies(ver, range, loose);
+    t.ok(!found, ver + ' not satisfied by ' + range);
+  });
+  t.end();
+});
+
+test('\nincrement versions test', function(t) {
+//  [version, inc, result, identifier]
+//  inc(version, inc) -> result
+  [['1.2.3', 'major', '2.0.0'],
+    ['1.2.3', 'minor', '1.3.0'],
+    ['1.2.3', 'patch', '1.2.4'],
+    ['1.2.3tag', 'major', '2.0.0', true],
+    ['1.2.3-tag', 'major', '2.0.0'],
+    ['1.2.3', 'fake', null],
+    ['1.2.0-0', 'patch', '1.2.0'],
+    ['fake', 'major', null],
+    ['1.2.3-4', 'major', '2.0.0'],
+    ['1.2.3-4', 'minor', '1.3.0'],
+    ['1.2.3-4', 'patch', '1.2.3'],
+    ['1.2.3-alpha.0.beta', 'major', '2.0.0'],
+    ['1.2.3-alpha.0.beta', 'minor', '1.3.0'],
+    ['1.2.3-alpha.0.beta', 'patch', '1.2.3'],
+    ['1.2.4', 'prerelease', '1.2.5-0'],
+    ['1.2.3-0', 'prerelease', '1.2.3-1'],
+    ['1.2.3-alpha.0', 'prerelease', '1.2.3-alpha.1'],
+    ['1.2.3-alpha.1', 'prerelease', '1.2.3-alpha.2'],
+    ['1.2.3-alpha.2', 'prerelease', '1.2.3-alpha.3'],
+    ['1.2.3-alpha.0.beta', 'prerelease', '1.2.3-alpha.1.beta'],
+    ['1.2.3-alpha.1.beta', 'prerelease', '1.2.3-alpha.2.beta'],
+    ['1.2.3-alpha.2.beta', 'prerelease', '1.2.3-alpha.3.beta'],
+    ['1.2.3-alpha.10.0.beta', 'prerelease', '1.2.3-alpha.10.1.beta'],
+    ['1.2.3-alpha.10.1.beta', 'prerelease', '1.2.3-alpha.10.2.beta'],
+    ['1.2.3-alpha.10.2.beta', 'prerelease', '1.2.3-alpha.10.3.beta'],
+    ['1.2.3-alpha.10.beta.0', 'prerelease', '1.2.3-alpha.10.beta.1'],
+    ['1.2.3-alpha.10.beta.1', 'prerelease', '1.2.3-alpha.10.beta.2'],
+    ['1.2.3-alpha.10.beta.2', 'prerelease', '1.2.3-alpha.10.beta.3'],
+    ['1.2.3-alpha.9.beta', 'prerelease', '1.2.3-alpha.10.beta'],
+    ['1.2.3-alpha.10.beta', 'prerelease', '1.2.3-alpha.11.beta'],
+    ['1.2.3-alpha.11.beta', 'prerelease', '1.2.3-alpha.12.beta'],
+    ['1.2.0', 'prepatch', '1.2.1-0'],
+    ['1.2.0-1', 'prepatch', '1.2.1-0'],
+    ['1.2.0', 'preminor', '1.3.0-0'],
+    ['1.2.3-1', 'preminor', '1.3.0-0'],
+    ['1.2.0', 'premajor', '2.0.0-0'],
+    ['1.2.3-1', 'premajor', '2.0.0-0'],
+    ['1.2.0-1', 'minor', '1.2.0'],
+    ['1.0.0-1', 'major', '1.0.0'],
+
+    ['1.2.3', 'major', '2.0.0', false, 'dev'],
+    ['1.2.3', 'minor', '1.3.0', false, 'dev'],
+    ['1.2.3', 'patch', '1.2.4', false, 'dev'],
+    ['1.2.3tag', 'major', '2.0.0', true, 'dev'],
+    ['1.2.3-tag', 'major', '2.0.0', false, 'dev'],
+    ['1.2.3', 'fake', null, false, 'dev'],
+    ['1.2.0-0', 'patch', '1.2.0', false, 'dev'],
+    ['fake', 'major', null, false, 'dev'],
+    ['1.2.3-4', 'major', '2.0.0', false, 'dev'],
+    ['1.2.3-4', 'minor', '1.3.0', false, 'dev'],
+    ['1.2.3-4', 'patch', '1.2.3', false, 'dev'],
+    ['1.2.3-alpha.0.beta', 'major', '2.0.0', false, 'dev'],
+    ['1.2.3-alpha.0.beta', 'minor', '1.3.0', false, 'dev'],
+    ['1.2.3-alpha.0.beta', 'patch', '1.2.3', false, 'dev'],
+    ['1.2.4', 'prerelease', '1.2.5-dev.0', false, 'dev'],
+    ['1.2.3-0', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.0', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.0', 'prerelease', '1.2.3-alpha.1', false, 'alpha'],
+    ['1.2.3-alpha.0.beta', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.0.beta', 'prerelease', '1.2.3-alpha.1.beta', false, 'alpha'],
+    ['1.2.3-alpha.10.0.beta', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.10.0.beta', 'prerelease', '1.2.3-alpha.10.1.beta', false, 'alpha'],
+    ['1.2.3-alpha.10.1.beta', 'prerelease', '1.2.3-alpha.10.2.beta', false, 'alpha'],
+    ['1.2.3-alpha.10.2.beta', 'prerelease', '1.2.3-alpha.10.3.beta', false, 'alpha'],
+    ['1.2.3-alpha.10.beta.0', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.10.beta.0', 'prerelease', '1.2.3-alpha.10.beta.1', false, 'alpha'],
+    ['1.2.3-alpha.10.beta.1', 'prerelease', '1.2.3-alpha.10.beta.2', false, 'alpha'],
+    ['1.2.3-alpha.10.beta.2', 'prerelease', '1.2.3-alpha.10.beta.3', false, 'alpha'],
+    ['1.2.3-alpha.9.beta', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.9.beta', 'prerelease', '1.2.3-alpha.10.beta', false, 'alpha'],
+    ['1.2.3-alpha.10.beta', 'prerelease', '1.2.3-alpha.11.beta', false, 'alpha'],
+    ['1.2.3-alpha.11.beta', 'prerelease', '1.2.3-alpha.12.beta', false, 'alpha'],
+    ['1.2.0', 'prepatch', '1.2.1-dev.0', 'dev'],
+    ['1.2.0-1', 'prepatch', '1.2.1-dev.0', 'dev'],
+    ['1.2.0', 'preminor', '1.3.0-dev.0', 'dev'],
+    ['1.2.3-1', 'preminor', '1.3.0-dev.0', 'dev'],
+    ['1.2.0', 'premajor', '2.0.0-dev.0', 'dev'],
+    ['1.2.3-1', 'premajor', '2.0.0-dev.0', 'dev'],
+    ['1.2.0-1', 'minor', '1.2.0', 'dev'],
+    ['1.0.0-1', 'major', '1.0.0', 'dev'],
+    ['1.2.3-dev.bar', 'prerelease', '1.2.3-dev.0', false, 'dev']
+
+  ].forEach(function(v) {
+    var pre = v[0];
+    var what = v[1];
+    var wanted = v[2];
+    var loose = v[3];
+    var id = v[4];
+    var found = inc(pre, what, loose, id);
+    var cmd = 'inc(' + pre + ', ' + what + ', ' + id + ')';
+    t.equal(found, wanted, cmd + ' === ' + wanted);
+  });
+
+  t.end();
+});
+
+test('\ndiff versions test', function(t) {
+//  [version1, version2, result]
+//  diff(version1, version2) -> result
+  [['1.2.3', '0.2.3', 'major'],
+    ['1.4.5', '0.2.3', 'major'],
+    ['1.2.3', '2.0.0-pre', 'premajor'],
+    ['1.2.3', '1.3.3', 'minor'],
+    ['1.0.1', '1.1.0-pre', 'preminor'],
+    ['1.2.3', '1.2.4', 'patch'],
+    ['1.2.3', '1.2.4-pre', 'prepatch'],
+    ['0.0.1', '0.0.1-pre', 'prerelease'],
+    ['0.0.1', '0.0.1-pre-2', 'prerelease'],
+    ['1.1.0', '1.1.0-pre', 'prerelease'],
+    ['1.1.0-pre-1', '1.1.0-pre-2', 'prerelease'],
+    ['1.0.0', '1.0.0', null]
+
+  ].forEach(function(v) {
+    var version1 = v[0];
+    var version2 = v[1];
+    var wanted = v[2];
+    var found = diff(version1, version2);
+    var cmd = 'diff(' + version1 + ', ' + version2 + ')';
+    t.equal(found, wanted, cmd + ' === ' + wanted);
+  });
+
+  t.end();
+});
+
+test('\nvalid range test', function(t) {
+  // [range, result]
+  // validRange(range) -> result
+  // translate ranges into their canonical form
+  [['1.0.0 - 2.0.0', '>=1.0.0 <=2.0.0'],
+    ['1.0.0', '1.0.0'],
+    ['>=*', '*'],
+    ['', '*'],
+    ['*', '*'],
+    ['*', '*'],
+    ['>=1.0.0', '>=1.0.0'],
+    ['>1.0.0', '>1.0.0'],
+    ['<=2.0.0', '<=2.0.0'],
+    ['1', '>=1.0.0 <2.0.0'],
+    ['<=2.0.0', '<=2.0.0'],
+    ['<=2.0.0', '<=2.0.0'],
+    ['<2.0.0', '<2.0.0'],
+    ['<2.0.0', '<2.0.0'],
+    ['>= 1.0.0', '>=1.0.0'],
+    ['>=  1.0.0', '>=1.0.0'],
+    ['>=   1.0.0', '>=1.0.0'],
+    ['> 1.0.0', '>1.0.0'],
+    ['>  1.0.0', '>1.0.0'],
+    ['<=   2.0.0', '<=2.0.0'],
+    ['<= 2.0.0', '<=2.0.0'],
+    ['<=  2.0.0', '<=2.0.0'],
+    ['<    2.0.0', '<2.0.0'],
+    ['<	2.0.0', '<2.0.0'],
+    ['>=0.1.97', '>=0.1.97'],
+    ['>=0.1.97', '>=0.1.97'],
+    ['0.1.20 || 1.2.4', '0.1.20||1.2.4'],
+    ['>=0.2.3 || <0.0.1', '>=0.2.3||<0.0.1'],
+    ['>=0.2.3 || <0.0.1', '>=0.2.3||<0.0.1'],
+    ['>=0.2.3 || <0.0.1', '>=0.2.3||<0.0.1'],
+    ['||', '||'],
+    ['2.x.x', '>=2.0.0 <3.0.0'],
+    ['1.2.x', '>=1.2.0 <1.3.0'],
+    ['1.2.x || 2.x', '>=1.2.0 <1.3.0||>=2.0.0 <3.0.0'],
+    ['1.2.x || 2.x', '>=1.2.0 <1.3.0||>=2.0.0 <3.0.0'],
+    ['x', '*'],
+    ['2.*.*', '>=2.0.0 <3.0.0'],
+    ['1.2.*', '>=1.2.0 <1.3.0'],
+    ['1.2.* || 2.*', '>=1.2.0 <1.3.0||>=2.0.0 <3.0.0'],
+    ['*', '*'],
+    ['2', '>=2.0.0 <3.0.0'],
+    ['2.3', '>=2.3.0 <2.4.0'],
+    ['~2.4', '>=2.4.0 <2.5.0'],
+    ['~2.4', '>=2.4.0 <2.5.0'],
+    ['~>3.2.1', '>=3.2.1 <3.3.0'],
+    ['~1', '>=1.0.0 <2.0.0'],
+    ['~>1', '>=1.0.0 <2.0.0'],
+    ['~> 1', '>=1.0.0 <2.0.0'],
+    ['~1.0', '>=1.0.0 <1.1.0'],
+    ['~ 1.0', '>=1.0.0 <1.1.0'],
+    ['^0', '>=0.0.0 <1.0.0'],
+    ['^ 1', '>=1.0.0 <2.0.0'],
+    ['^0.1', '>=0.1.0 <0.2.0'],
+    ['^1.0', '>=1.0.0 <2.0.0'],
+    ['^1.2', '>=1.2.0 <2.0.0'],
+    ['^0.0.1', '>=0.0.1 <0.0.2'],
+    ['^0.0.1-beta', '>=0.0.1-beta <0.0.2'],
+    ['^0.1.2', '>=0.1.2 <0.2.0'],
+    ['^1.2.3', '>=1.2.3 <2.0.0'],
+    ['^1.2.3-beta.4', '>=1.2.3-beta.4 <2.0.0'],
+    ['<1', '<1.0.0'],
+    ['< 1', '<1.0.0'],
+    ['>=1', '>=1.0.0'],
+    ['>= 1', '>=1.0.0'],
+    ['<1.2', '<1.2.0'],
+    ['< 1.2', '<1.2.0'],
+    ['1', '>=1.0.0 <2.0.0'],
+    ['>01.02.03', '>1.2.3', true],
+    ['>01.02.03', null],
+    ['~1.2.3beta', '>=1.2.3-beta <1.3.0', true],
+    ['~1.2.3beta', null],
+    ['^ 1.2 ^ 1', '>=1.2.0 <2.0.0 >=1.0.0 <2.0.0']
+  ].forEach(function(v) {
+    var pre = v[0];
+    var wanted = v[1];
+    var loose = v[2];
+    var found = validRange(pre, loose);
+
+    t.equal(found, wanted, 'validRange(' + pre + ') === ' + wanted);
+  });
+
+  t.end();
+});
+
+test('\ncomparators test', function(t) {
+  // [range, comparators]
+  // turn range into a set of individual comparators
+  [['1.0.0 - 2.0.0', [['>=1.0.0', '<=2.0.0']]],
+    ['1.0.0', [['1.0.0']]],
+    ['>=*', [['']]],
+    ['', [['']]],
+    ['*', [['']]],
+    ['*', [['']]],
+    ['>=1.0.0', [['>=1.0.0']]],
+    ['>=1.0.0', [['>=1.0.0']]],
+    ['>=1.0.0', [['>=1.0.0']]],
+    ['>1.0.0', [['>1.0.0']]],
+    ['>1.0.0', [['>1.0.0']]],
+    ['<=2.0.0', [['<=2.0.0']]],
+    ['1', [['>=1.0.0', '<2.0.0']]],
+    ['<=2.0.0', [['<=2.0.0']]],
+    ['<=2.0.0', [['<=2.0.0']]],
+    ['<2.0.0', [['<2.0.0']]],
+    ['<2.0.0', [['<2.0.0']]],
+    ['>= 1.0.0', [['>=1.0.0']]],
+    ['>=  1.0.0', [['>=1.0.0']]],
+    ['>=   1.0.0', [['>=1.0.0']]],
+    ['> 1.0.0', [['>1.0.0']]],
+    ['>  1.0.0', [['>1.0.0']]],
+    ['<=   2.0.0', [['<=2.0.0']]],
+    ['<= 2.0.0', [['<=2.0.0']]],
+    ['<=  2.0.0', [['<=2.0.0']]],
+    ['<    2.0.0', [['<2.0.0']]],
+    ['<\t2.0.0', [['<2.0.0']]],
+    ['>=0.1.97', [['>=0.1.97']]],
+    ['>=0.1.97', [['>=0.1.97']]],
+    ['0.1.20 || 1.2.4', [['0.1.20'], ['1.2.4']]],
+    ['>=0.2.3 || <0.0.1', [['>=0.2.3'], ['<0.0.1']]],
+    ['>=0.2.3 || <0.0.1', [['>=0.2.3'], ['<0.0.1']]],
+    ['>=0.2.3 || <0.0.1', [['>=0.2.3'], ['<0.0.1']]],
+    ['||', [[''], ['']]],
+    ['2.x.x', [['>=2.0.0', '<3.0.0']]],
+    ['1.2.x', [['>=1.2.0', '<1.3.0']]],
+    ['1.2.x || 2.x', [['>=1.2.0', '<1.3.0'], ['>=2.0.0', '<3.0.0']]],
+    ['1.2.x || 2.x', [['>=1.2.0', '<1.3.0'], ['>=2.0.0', '<3.0.0']]],
+    ['x', [['']]],
+    ['2.*.*', [['>=2.0.0', '<3.0.0']]],
+    ['1.2.*', [['>=1.2.0', '<1.3.0']]],
+    ['1.2.* || 2.*', [['>=1.2.0', '<1.3.0'], ['>=2.0.0', '<3.0.0']]],
+    ['1.2.* || 2.*', [['>=1.2.0', '<1.3.0'], ['>=2.0.0', '<3.0.0']]],
+    ['*', [['']]],
+    ['2', [['>=2.0.0', '<3.0.0']]],
+    ['2.3', [['>=2.3.0', '<2.4.0']]],
+    ['~2.4', [['>=2.4.0', '<2.5.0']]],
+    ['~2.4', [['>=2.4.0', '<2.5.0']]],
+    ['~>3.2.1', [['>=3.2.1', '<3.3.0']]],
+    ['~1', [['>=1.0.0', '<2.0.0']]],
+    ['~>1', [['>=1.0.0', '<2.0.0']]],
+    ['~> 1', [['>=1.0.0', '<2.0.0']]],
+    ['~1.0', [['>=1.0.0', '<1.1.0']]],
+    ['~ 1.0', [['>=1.0.0', '<1.1.0']]],
+    ['~ 1.0.3', [['>=1.0.3', '<1.1.0']]],
+    ['~> 1.0.3', [['>=1.0.3', '<1.1.0']]],
+    ['<1', [['<1.0.0']]],
+    ['< 1', [['<1.0.0']]],
+    ['>=1', [['>=1.0.0']]],
+    ['>= 1', [['>=1.0.0']]],
+    ['<1.2', [['<1.2.0']]],
+    ['< 1.2', [['<1.2.0']]],
+    ['1', [['>=1.0.0', '<2.0.0']]],
+    ['1 2', [['>=1.0.0', '<2.0.0', '>=2.0.0', '<3.0.0']]],
+    ['1.2 - 3.4.5', [['>=1.2.0', '<=3.4.5']]],
+    ['1.2.3 - 3.4', [['>=1.2.3', '<3.5.0']]],
+    ['1.2.3 - 3', [['>=1.2.3', '<4.0.0']]],
+    ['>*', [['<0.0.0']]],
+    ['<*', [['<0.0.0']]]
+  ].forEach(function(v) {
+    var pre = v[0];
+    var wanted = v[1];
+    var found = toComparators(v[0]);
+    var jw = JSON.stringify(wanted);
+    t.equivalent(found, wanted, 'toComparators(' + pre + ') === ' + jw);
+  });
+
+  t.end();
+});
+
+test('\ninvalid version numbers', function(t) {
+  ['1.2.3.4',
+   'NOT VALID',
+   1.2,
+   null,
+   'Infinity.NaN.Infinity'
+  ].forEach(function(v) {
+    t.throws(function() {
+      new SemVer(v);
+    }, {name:'TypeError', message:'Invalid Version: ' + v});
+  });
+
+  t.end();
+});
+
+test('\nstrict vs loose version numbers', function(t) {
+  [['=1.2.3', '1.2.3'],
+    ['01.02.03', '1.2.3'],
+    ['1.2.3-beta.01', '1.2.3-beta.1'],
+    ['   =1.2.3', '1.2.3'],
+    ['1.2.3foo', '1.2.3-foo']
+  ].forEach(function(v) {
+    var loose = v[0];
+    var strict = v[1];
+    t.throws(function() {
+      new SemVer(loose);
+    });
+    var lv = new SemVer(loose, true);
+    t.equal(lv.version, strict);
+    t.ok(eq(loose, strict, true));
+    t.throws(function() {
+      eq(loose, strict);
+    });
+    t.throws(function() {
+      new SemVer(strict).compare(loose);
+    });
+  });
+  t.end();
+});
+
+test('\nstrict vs loose ranges', function(t) {
+  [['>=01.02.03', '>=1.2.3'],
+    ['~1.02.03beta', '>=1.2.3-beta <1.3.0']
+  ].forEach(function(v) {
+    var loose = v[0];
+    var comps = v[1];
+    t.throws(function() {
+      new Range(loose);
+    });
+    t.equal(new Range(loose, true).range, comps);
+  });
+  t.end();
+});
+
+test('\nmax satisfying', function(t) {
+  [[['1.2.3', '1.2.4'], '1.2', '1.2.4'],
+    [['1.2.4', '1.2.3'], '1.2', '1.2.4'],
+    [['1.2.3', '1.2.4', '1.2.5', '1.2.6'], '~1.2.3', '1.2.6'],
+    [['1.1.0', '1.2.0', '1.2.1', '1.3.0', '2.0.0b1', '2.0.0b2', '2.0.0b3', '2.0.0', '2.1.0'], '~2.0.0', '2.0.0', true]
+  ].forEach(function(v) {
+    var versions = v[0];
+    var range = v[1];
+    var expect = v[2];
+    var loose = v[3];
+    var actual = semver.maxSatisfying(versions, range, loose);
+    t.equal(actual, expect);
+  });
+  t.end();
+});
diff --git a/server/node_modules/pg/node_modules/semver/test/ltr.js b/server/node_modules/pg/node_modules/semver/test/ltr.js
new file mode 100644
index 0000000000000000000000000000000000000000..ecd1387ddfe053e4120d4e6b2cbcb7030f29f281
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/test/ltr.js
@@ -0,0 +1,181 @@
+var tap = require('tap');
+var test = tap.test;
+var semver = require('../semver.js');
+var ltr = semver.ltr;
+
+test('\nltr tests', function(t) {
+  // [range, version, loose]
+  // Version should be less than range
+  [
+    ['~1.2.2', '1.2.1'],
+    ['~0.6.1-1', '0.6.1-0'],
+    ['1.0.0 - 2.0.0', '0.0.1'],
+    ['1.0.0-beta.2', '1.0.0-beta.1'],
+    ['1.0.0', '0.0.0'],
+    ['>=2.0.0', '1.1.1'],
+    ['>=2.0.0', '1.2.9'],
+    ['>2.0.0', '2.0.0'],
+    ['0.1.20 || 1.2.4', '0.1.5'],
+    ['2.x.x', '1.0.0'],
+    ['1.2.x', '1.1.0'],
+    ['1.2.x || 2.x', '1.0.0'],
+    ['2.*.*', '1.0.1'],
+    ['1.2.*', '1.1.3'],
+    ['1.2.* || 2.*', '1.1.9999'],
+    ['2', '1.0.0'],
+    ['2.3', '2.2.2'],
+    ['~2.4', '2.3.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.3.5'],
+    ['~>3.2.1', '3.2.0'], // >=3.2.1 <3.3.0
+    ['~1', '0.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '0.2.4'],
+    ['~> 1', '0.2.3'],
+    ['~1.0', '0.1.2'], // >=1.0.0 <1.1.0
+    ['~ 1.0', '0.1.0'],
+    ['>1.2', '1.2.0'],
+    ['> 1.2', '1.2.1'],
+    ['1', '0.0.0beta', true],
+    ['~v0.5.4-pre', '0.5.4-alpha'],
+    ['~v0.5.4-pre', '0.5.4-alpha'],
+    ['=0.7.x', '0.6.0'],
+    ['=0.7.x', '0.6.0-asdf'],
+    ['>=0.7.x', '0.6.0'],
+    ['~1.2.2', '1.2.1'],
+    ['1.0.0 - 2.0.0', '0.2.3'],
+    ['1.0.0', '0.0.1'],
+    ['>=2.0.0', '1.0.0'],
+    ['>=2.0.0', '1.9999.9999'],
+    ['>=2.0.0', '1.2.9'],
+    ['>2.0.0', '2.0.0'],
+    ['>2.0.0', '1.2.9'],
+    ['2.x.x', '1.1.3'],
+    ['1.2.x', '1.1.3'],
+    ['1.2.x || 2.x', '1.1.3'],
+    ['2.*.*', '1.1.3'],
+    ['1.2.*', '1.1.3'],
+    ['1.2.* || 2.*', '1.1.3'],
+    ['2', '1.9999.9999'],
+    ['2.3', '2.2.1'],
+    ['~2.4', '2.3.0'], // >=2.4.0 <2.5.0
+    ['~>3.2.1', '2.3.2'], // >=3.2.1 <3.3.0
+    ['~1', '0.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '0.2.3'],
+    ['~1.0', '0.0.0'], // >=1.0.0 <1.1.0
+    ['>1', '1.0.0'],
+    ['2', '1.0.0beta', true],
+    ['>1', '1.0.0beta', true],
+    ['> 1', '1.0.0beta', true],
+    ['=0.7.x', '0.6.2'],
+    ['=0.7.x', '0.7.0-asdf'],
+    ['^1', '1.0.0-0'],
+    ['>=0.7.x', '0.7.0-asdf'],
+    ['1', '1.0.0beta', true],
+    ['>=0.7.x', '0.6.2']
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = 'ltr(' + version + ', ' + range + ', ' + loose + ')';
+    t.ok(ltr(version, range, loose), msg);
+  });
+  t.end();
+});
+
+test('\nnegative ltr tests', function(t) {
+  // [range, version, loose]
+  // Version should NOT be greater than range
+  [
+    ['~ 1.0', '1.1.0'],
+    ['~0.6.1-1', '0.6.1-1'],
+    ['1.0.0 - 2.0.0', '1.2.3'],
+    ['1.0.0 - 2.0.0', '2.9.9'],
+    ['1.0.0', '1.0.0'],
+    ['>=*', '0.2.4'],
+    ['', '1.0.0', true],
+    ['*', '1.2.3'],
+    ['*', 'v1.2.3-foo'],
+    ['>=1.0.0', '1.0.0'],
+    ['>=1.0.0', '1.0.1'],
+    ['>=1.0.0', '1.1.0'],
+    ['>1.0.0', '1.0.1'],
+    ['>1.0.0', '1.1.0'],
+    ['<=2.0.0', '2.0.0'],
+    ['<=2.0.0', '1.9999.9999'],
+    ['<=2.0.0', '0.2.9'],
+    ['<2.0.0', '1.9999.9999'],
+    ['<2.0.0', '0.2.9'],
+    ['>= 1.0.0', '1.0.0'],
+    ['>=  1.0.0', '1.0.1'],
+    ['>=   1.0.0', '1.1.0'],
+    ['> 1.0.0', '1.0.1'],
+    ['>  1.0.0', '1.1.0'],
+    ['<=   2.0.0', '2.0.0'],
+    ['<= 2.0.0', '1.9999.9999'],
+    ['<=  2.0.0', '0.2.9'],
+    ['<    2.0.0', '1.9999.9999'],
+    ['<\t2.0.0', '0.2.9'],
+    ['>=0.1.97', 'v0.1.97'],
+    ['>=0.1.97', '0.1.97'],
+    ['0.1.20 || 1.2.4', '1.2.4'],
+    ['0.1.20 || >1.2.4', '1.2.4'],
+    ['0.1.20 || 1.2.4', '1.2.3'],
+    ['0.1.20 || 1.2.4', '0.1.20'],
+    ['>=0.2.3 || <0.0.1', '0.0.0'],
+    ['>=0.2.3 || <0.0.1', '0.2.3'],
+    ['>=0.2.3 || <0.0.1', '0.2.4'],
+    ['||', '1.3.4'],
+    ['2.x.x', '2.1.3'],
+    ['1.2.x', '1.2.3'],
+    ['1.2.x || 2.x', '2.1.3'],
+    ['1.2.x || 2.x', '1.2.3'],
+    ['x', '1.2.3'],
+    ['2.*.*', '2.1.3'],
+    ['1.2.*', '1.2.3'],
+    ['1.2.* || 2.*', '2.1.3'],
+    ['1.2.* || 2.*', '1.2.3'],
+    ['1.2.* || 2.*', '1.2.3'],
+    ['*', '1.2.3'],
+    ['2', '2.1.2'],
+    ['2.3', '2.3.1'],
+    ['~2.4', '2.4.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.4.5'],
+    ['~>3.2.1', '3.2.2'], // >=3.2.1 <3.3.0
+    ['~1', '1.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '1.2.3'],
+    ['~> 1', '1.2.3'],
+    ['~1.0', '1.0.2'], // >=1.0.0 <1.1.0
+    ['~ 1.0', '1.0.2'],
+    ['>=1', '1.0.0'],
+    ['>= 1', '1.0.0'],
+    ['<1.2', '1.1.1'],
+    ['< 1.2', '1.1.1'],
+    ['~v0.5.4-pre', '0.5.5'],
+    ['~v0.5.4-pre', '0.5.4'],
+    ['=0.7.x', '0.7.2'],
+    ['>=0.7.x', '0.7.2'],
+    ['<=0.7.x', '0.6.2'],
+    ['>0.2.3 >0.2.4 <=0.2.5', '0.2.5'],
+    ['>=0.2.3 <=0.2.4', '0.2.4'],
+    ['1.0.0 - 2.0.0', '2.0.0'],
+    ['^3.0.0', '4.0.0'],
+    ['^1.0.0 || ~2.0.1', '2.0.0'],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '3.2.0'],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '1.0.0beta', true],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '5.0.0-0', true],
+    ['^0.1.0 || ~3.0.1 || >4 <=5.0.0', '3.5.0'],
+    ['^1.0.0alpha', '1.0.0beta', true],
+    ['~1.0.0alpha', '1.0.0beta', true],
+    ['^1.0.0-alpha', '1.0.0beta', true],
+    ['~1.0.0-alpha', '1.0.0beta', true],
+    ['^1.0.0-alpha', '1.0.0-beta'],
+    ['~1.0.0-alpha', '1.0.0-beta'],
+    ['=0.1.0', '1.0.0']
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = '!ltr(' + version + ', ' + range + ', ' + loose + ')';
+    t.notOk(ltr(version, range, loose), msg);
+  });
+  t.end();
+});
diff --git a/server/node_modules/pg/node_modules/semver/test/major-minor-patch.js b/server/node_modules/pg/node_modules/semver/test/major-minor-patch.js
new file mode 100644
index 0000000000000000000000000000000000000000..e9d4039c8be6294ba9ac51f134214bbb7d682f8e
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/test/major-minor-patch.js
@@ -0,0 +1,72 @@
+var tap = require('tap');
+var test = tap.test;
+var semver = require('../semver.js');
+
+test('\nmajor tests', function(t) {
+  // [range, version]
+  // Version should be detectable despite extra characters
+  [
+    ['1.2.3', 1],
+    [' 1.2.3 ', 1],
+    [' 2.2.3-4 ', 2],
+    [' 3.2.3-pre ', 3],
+    ['v5.2.3', 5],
+    [' v8.2.3 ', 8],
+    ['\t13.2.3', 13],
+    ['=21.2.3', 21, true],
+    ['v=34.2.3', 34, true]
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = 'major(' + range + ') = ' + version;
+    t.equal(semver.major(range, loose), version, msg);
+  });
+  t.end();
+});
+
+test('\nminor tests', function(t) {
+  // [range, version]
+  // Version should be detectable despite extra characters
+  [
+    ['1.1.3', 1],
+    [' 1.1.3 ', 1],
+    [' 1.2.3-4 ', 2],
+    [' 1.3.3-pre ', 3],
+    ['v1.5.3', 5],
+    [' v1.8.3 ', 8],
+    ['\t1.13.3', 13],
+    ['=1.21.3', 21, true],
+    ['v=1.34.3', 34, true]
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = 'minor(' + range + ') = ' + version;
+    t.equal(semver.minor(range, loose), version, msg);
+  });
+  t.end();
+});
+
+test('\npatch tests', function(t) {
+  // [range, version]
+  // Version should be detectable despite extra characters
+  [
+    ['1.2.1', 1],
+    [' 1.2.1 ', 1],
+    [' 1.2.2-4 ', 2],
+    [' 1.2.3-pre ', 3],
+    ['v1.2.5', 5],
+    [' v1.2.8 ', 8],
+    ['\t1.2.13', 13],
+    ['=1.2.21', 21, true],
+    ['v=1.2.34', 34, true]
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = 'patch(' + range + ') = ' + version;
+    t.equal(semver.patch(range, loose), version, msg);
+  });
+  t.end();
+});
diff --git a/server/node_modules/pg/node_modules/semver/test/no-module.js b/server/node_modules/pg/node_modules/semver/test/no-module.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b50873f1383b83c53a348f51da3eb1040ebbbe7
--- /dev/null
+++ b/server/node_modules/pg/node_modules/semver/test/no-module.js
@@ -0,0 +1,19 @@
+var tap = require('tap');
+var test = tap.test;
+
+test('no module system', function(t) {
+  var fs = require('fs');
+  var vm = require('vm');
+  var head = fs.readFileSync(require.resolve('../head.js.txt'), 'utf8');
+  var src = fs.readFileSync(require.resolve('../'), 'utf8');
+  var foot = fs.readFileSync(require.resolve('../foot.js.txt'), 'utf8');
+  vm.runInThisContext(head + src + foot, 'semver.js');
+
+  // just some basic poking to see if it did some stuff
+  t.type(global.semver, 'object');
+  t.type(global.semver.SemVer, 'function');
+  t.type(global.semver.Range, 'function');
+  t.ok(global.semver.satisfies('1.2.3', '1.2'));
+  t.end();
+});
+
diff --git a/server/node_modules/pg/package.json b/server/node_modules/pg/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..e70eab61e8db8eb7260e69f3c618b1241ffdb5e1
--- /dev/null
+++ b/server/node_modules/pg/package.json
@@ -0,0 +1,82 @@
+{
+  "_from": "pg",
+  "_id": "pg@7.12.1",
+  "_inBundle": false,
+  "_integrity": "sha512-l1UuyfEvoswYfcUe6k+JaxiN+5vkOgYcVSbSuw3FvdLqDbaoa2RJo1zfJKfPsSYPFVERd4GHvX3s2PjG1asSDA==",
+  "_location": "/pg",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "tag",
+    "registry": true,
+    "raw": "pg",
+    "name": "pg",
+    "escapedName": "pg",
+    "rawSpec": "",
+    "saveSpec": null,
+    "fetchSpec": "latest"
+  },
+  "_requiredBy": [
+    "#USER",
+    "/"
+  ],
+  "_resolved": "https://registry.npmjs.org/pg/-/pg-7.12.1.tgz",
+  "_shasum": "880636d46d2efbe0968e64e9fe0eeece8ef72a7e",
+  "_spec": "pg",
+  "_where": "/home/dante/Documents/pinsis-portal/server",
+  "author": {
+    "name": "Brian Carlson",
+    "email": "brian.m.carlson@gmail.com"
+  },
+  "bugs": {
+    "url": "https://github.com/brianc/node-postgres/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "buffer-writer": "2.0.0",
+    "packet-reader": "1.0.0",
+    "pg-connection-string": "0.1.3",
+    "pg-pool": "^2.0.4",
+    "pg-types": "^2.1.0",
+    "pgpass": "1.x",
+    "semver": "4.3.2"
+  },
+  "deprecated": false,
+  "description": "PostgreSQL client - pure javascript & libpq with the same API",
+  "devDependencies": {
+    "async": "0.9.0",
+    "bluebird": "3.5.2",
+    "co": "4.6.0",
+    "eslint": "^6.0.1",
+    "eslint-config-standard": "^13.0.1",
+    "eslint-plugin-import": "^2.18.1",
+    "eslint-plugin-node": "^9.1.0",
+    "eslint-plugin-promise": "^4.2.1",
+    "eslint-plugin-standard": "^4.0.0",
+    "pg-copy-streams": "0.3.0"
+  },
+  "engines": {
+    "node": ">= 4.5.0"
+  },
+  "homepage": "http://github.com/brianc/node-postgres",
+  "keywords": [
+    "database",
+    "libpq",
+    "pg",
+    "postgre",
+    "postgres",
+    "postgresql",
+    "rdbms"
+  ],
+  "license": "MIT",
+  "main": "./lib",
+  "minNativeVersion": "2.0.0",
+  "name": "pg",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianc/node-postgres.git"
+  },
+  "scripts": {
+    "test": "make test-all"
+  },
+  "version": "7.12.1"
+}
diff --git a/server/node_modules/pgpass/.npmignore b/server/node_modules/pgpass/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..e68f07b6775798beacce945283820c5a2cf92e3f
--- /dev/null
+++ b/server/node_modules/pgpass/.npmignore
@@ -0,0 +1,10 @@
+node_modules/
+*~
+#*
+lib-cov/
+coverage.*
+npm-debug.log
+
+.jshintrc
+.travis.yml
+test/
diff --git a/server/node_modules/pgpass/README.md b/server/node_modules/pgpass/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a97af3379090aebaee943abf98a0c95c426811fe
--- /dev/null
+++ b/server/node_modules/pgpass/README.md
@@ -0,0 +1,74 @@
+# pgpass
+
+[![Build Status](https://travis-ci.org/hoegaarden/pgpass.png?branch=master)](https://travis-ci.org/hoegaarden/pgpass)
+
+## Install
+
+```sh
+npm install pgpass
+```
+
+## Usage
+```js
+var pgPass = require('pgpass');
+
+var connInfo = {
+  'host' : 'pgserver' ,
+  'user' : 'the_user_name' ,
+};
+
+pgPass(connInfo, function(pass){
+  conn_info.password = pass;
+  // connect to postgresql server
+});
+```
+
+## Description
+
+This module tries to read the `~/.pgpass` file (or the equivalent for windows systems). If the environment variable `PGPASSFILE` is set, this file is used instead. If everything goes right, the password from said file is passed to the callback; if the password cannot be read `undefined` is passed to the callback.
+
+Cases where `undefined` is returned:
+
+- the environment variable `PGPASSWORD` is set
+- the file cannot be read (wrong permissions, no such file, ...)
+- for non windows systems: the file is write-/readable by the group or by other users
+- there is no matching line for the given connection info
+
+There should be no need to use this module directly; it is already included in `node-postgresq`.
+
+## Configuration
+
+The module reads the environment variable `PGPASS_NO_DEESCAPE` to decide if the the read tokens from the password file should be de-escaped or not. Default is to do de-escaping. For further information on this see [this commit](https://github.com/postgres/postgres/commit/8d15e3ec4fcb735875a8a70a09ec0c62153c3329).
+
+
+## Tests
+
+There are tests in `./test/`; including linting and coverage testing. Running `npm test` runs:
+
+- `jshint`
+- `mocha` tests
+- `jscoverage` and `mocha -R html-cov`
+
+You can see the coverage report in `coverage.html`.
+
+
+## Development, Patches, Bugs, ...
+
+If you find Bugs or have improvments, please feel free to open a issue on github. If you provide a pull request, I'm more than happy to merge them, just make sure to add tests for your changes.
+
+## Links
+
+- https://github.com/hoegaarden/node-pgpass
+- http://www.postgresql.org/docs/current/static/libpq-pgpass.html
+- https://wiki.postgresql.org/wiki/Pgpass
+- https://github.com/postgres/postgres/blob/master/src/interfaces/libpq/fe-connect.c
+
+## License
+
+Copyright (c) 2013-2016 Hannes Hörl
+
+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.
\ No newline at end of file
diff --git a/server/node_modules/pgpass/lib/helper.js b/server/node_modules/pgpass/lib/helper.js
new file mode 100644
index 0000000000000000000000000000000000000000..6abea0e611f9a712be7c725ef144eed55f68e7b2
--- /dev/null
+++ b/server/node_modules/pgpass/lib/helper.js
@@ -0,0 +1,233 @@
+'use strict';
+
+var path = require('path')
+  , Stream = require('stream').Stream
+  , Split = require('split')
+  , util = require('util')
+  , defaultPort = 5432
+  , isWin = (process.platform === 'win32')
+  , warnStream = process.stderr
+;
+
+
+var S_IRWXG = 56     //    00070(8)
+  , S_IRWXO = 7      //    00007(8)
+  , S_IFMT  = 61440  // 00170000(8)
+  , S_IFREG = 32768  //  0100000(8)
+;
+function isRegFile(mode) {
+    return ((mode & S_IFMT) == S_IFREG);
+}
+
+var fieldNames = [ 'host', 'port', 'database', 'user', 'password' ];
+var nrOfFields = fieldNames.length;
+var passKey = fieldNames[ nrOfFields -1 ];
+
+
+function warn() {
+    var isWritable = (
+        warnStream instanceof Stream &&
+          true === warnStream.writable
+    );
+
+    if (isWritable) {
+        var args = Array.prototype.slice.call(arguments).concat("\n");
+        warnStream.write( util.format.apply(util, args) );
+    }
+}
+
+
+Object.defineProperty(module.exports, 'isWin', {
+    get : function() {
+        return isWin;
+    } ,
+    set : function(val) {
+        isWin = val;
+    }
+});
+
+
+module.exports.warnTo = function(stream) {
+    var old = warnStream;
+    warnStream = stream;
+    return old;
+};
+
+module.exports.getFileName = function(env){
+    env = env || process.env;
+    var file = env.PGPASSFILE || (
+        isWin ?
+          path.join( env.APPDATA , 'postgresql', 'pgpass.conf' ) :
+          path.join( env.HOME, '.pgpass' )
+    );
+    return file;
+};
+
+module.exports.usePgPass = function(stats, fname) {
+    if (Object.prototype.hasOwnProperty.call(process.env, 'PGPASSWORD')) {
+        return false;
+    }
+
+    if (isWin) {
+        return true;
+    }
+
+    fname = fname || '<unkn>';
+
+    if (! isRegFile(stats.mode)) {
+        warn('WARNING: password file "%s" is not a plain file', fname);
+        return false;
+    }
+
+    if (stats.mode & (S_IRWXG | S_IRWXO)) {
+        /* If password file is insecure, alert the user and ignore it. */
+        warn('WARNING: password file "%s" has group or world access; permissions should be u=rw (0600) or less', fname);
+        return false;
+    }
+
+    return true;
+};
+
+
+var matcher = module.exports.match = function(connInfo, entry) {
+    return fieldNames.slice(0, -1).reduce(function(prev, field, idx){
+        if (idx == 1) {
+            // the port
+            if ( Number( connInfo[field] || defaultPort ) === Number( entry[field] ) ) {
+                return prev && true;
+            }
+        }
+        return prev && (
+            entry[field] === '*' ||
+              entry[field] === connInfo[field]
+        );
+    }, true);
+};
+
+
+module.exports.getPassword = function(connInfo, stream, cb) {
+    var pass;
+    var lineStream = stream.pipe(new Split());
+
+    function onLine(line) {
+        var entry = parseLine(line);
+        if (entry && isValidEntry(entry) && matcher(connInfo, entry)) {
+            pass = entry[passKey];
+            lineStream.end(); // -> calls onEnd(), but pass is set now
+        }
+    }
+
+    var onEnd = function() {
+        stream.destroy();
+        cb(pass);
+    };
+
+    var onErr = function(err) {
+        stream.destroy();
+        warn('WARNING: error on reading file: %s', err);
+        cb(undefined);
+    };
+
+    stream.on('error', onErr);
+    lineStream
+        .on('data', onLine)
+        .on('end', onEnd)
+        .on('error', onErr)
+    ;
+
+};
+
+
+var parseLine = module.exports.parseLine = function(line) {
+    if (line.length < 11 || line.match(/^\s+#/)) {
+        return null;
+    }
+
+    var curChar = '';
+    var prevChar = '';
+    var fieldIdx = 0;
+    var startIdx = 0;
+    var endIdx = 0;
+    var obj = {};
+    var isLastField = false;
+    var addToObj = function(idx, i0, i1) {
+        var field = line.substring(i0, i1);
+
+        if (! Object.hasOwnProperty.call(process.env, 'PGPASS_NO_DEESCAPE')) {
+            field = field.replace(/\\([:\\])/g, '$1');
+        }
+
+        obj[ fieldNames[idx] ] = field;
+    };
+
+    for (var i = 0 ; i < line.length-1 ; i += 1) {
+        curChar = line.charAt(i+1);
+        prevChar = line.charAt(i);
+
+        isLastField = (fieldIdx == nrOfFields-1);
+
+        if (isLastField) {
+            addToObj(fieldIdx, startIdx);
+            break;
+        }
+
+        if (i >= 0 && curChar == ':' && prevChar !== '\\') {
+            addToObj(fieldIdx, startIdx, i+1);
+
+            startIdx = i+2;
+            fieldIdx += 1;
+        }
+    }
+
+    obj = ( Object.keys(obj).length === nrOfFields ) ? obj : null;
+
+    return obj;
+};
+
+
+var isValidEntry = module.exports.isValidEntry = function(entry){
+    var rules = {
+        // host
+        0 : function(x){
+            return x.length > 0;
+        } ,
+        // port
+        1 : function(x){
+            if (x === '*') {
+                return true;
+            }
+            x = Number(x);
+            return (
+                isFinite(x) &&
+                  x > 0 &&
+                  x < 9007199254740992 &&
+                  Math.floor(x) === x
+            );
+        } ,
+        // database
+        2 : function(x){
+            return x.length > 0;
+        } ,
+        // username
+        3 : function(x){
+            return x.length > 0;
+        } ,
+        // password
+        4 : function(x){
+            return x.length > 0;
+        }
+    };
+
+    for (var idx = 0 ; idx < fieldNames.length ; idx += 1) {
+        var rule = rules[idx];
+        var value = entry[ fieldNames[idx] ] || '';
+
+        var res = rule(value);
+        if (!res) {
+            return false;
+        }
+    }
+
+    return true;
+};
+
diff --git a/server/node_modules/pgpass/lib/index.js b/server/node_modules/pgpass/lib/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..ecfcf308efd59d0ac4330dcbf505bac7f5847acf
--- /dev/null
+++ b/server/node_modules/pgpass/lib/index.js
@@ -0,0 +1,23 @@
+'use strict';
+
+var path = require('path')
+  , fs = require('fs')
+  , helper = require('./helper.js')
+;
+
+
+module.exports = function(connInfo, cb) {
+    var file = helper.getFileName();
+    
+    fs.stat(file, function(err, stat){
+        if (err || !helper.usePgPass(stat, file)) {
+            return cb(undefined);
+        }
+
+        var st = fs.createReadStream(file);
+
+        helper.getPassword(connInfo, st, cb);
+    });
+};
+
+module.exports.warnTo = helper.warnTo;
diff --git a/server/node_modules/pgpass/package.json b/server/node_modules/pgpass/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..ced5424b1171b4465e08d76315e7f3bb1988901c
--- /dev/null
+++ b/server/node_modules/pgpass/package.json
@@ -0,0 +1,71 @@
+{
+  "_from": "pgpass@1.x",
+  "_id": "pgpass@1.0.2",
+  "_inBundle": false,
+  "_integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=",
+  "_location": "/pgpass",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "pgpass@1.x",
+    "name": "pgpass",
+    "escapedName": "pgpass",
+    "rawSpec": "1.x",
+    "saveSpec": null,
+    "fetchSpec": "1.x"
+  },
+  "_requiredBy": [
+    "/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz",
+  "_shasum": "2a7bb41b6065b67907e91da1b07c1847c877b306",
+  "_spec": "pgpass@1.x",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg",
+  "author": {
+    "name": "Hannes Hörl",
+    "email": "hannes.hoerl+pgpass@snowreporter.com"
+  },
+  "bugs": {
+    "url": "https://github.com/hoegaarden/pgpass/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "split": "^1.0.0"
+  },
+  "deprecated": false,
+  "description": "Module for reading .pgpass",
+  "devDependencies": {
+    "jscoverage": "^0.6.0",
+    "jshint": "^2.9.2",
+    "mocha": "^2.5.3",
+    "pg": "^4.5.6",
+    "pg-escape": "^0.2.0",
+    "pg-native": "^1.10.0",
+    "resumer": "0.0.0",
+    "tmp": "0.0.28",
+    "which": "^1.2.10"
+  },
+  "homepage": "https://github.com/hoegaarden/pgpass#readme",
+  "keywords": [
+    "postgres",
+    "pg",
+    "pgpass",
+    "password",
+    "postgresql"
+  ],
+  "license": "MIT",
+  "main": "lib/index",
+  "name": "pgpass",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/hoegaarden/pgpass.git"
+  },
+  "scripts": {
+    "coverage": "rm -rf -- lib-cov ; jscoverage lib lib-cov && mocha --recursive -R html-cov > coverage.html",
+    "hint": "jshint --verbose lib test",
+    "pretest": "chmod 600 ./test/_pgpass",
+    "test": "npm run hint && mocha --recursive -R list && npm run coverage"
+  },
+  "version": "1.0.2"
+}
diff --git a/server/node_modules/pgtools/.npmignore b/server/node_modules/pgtools/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..62adae57832a2afcbde83fbdf8bef349ab0dbf36
--- /dev/null
+++ b/server/node_modules/pgtools/.npmignore
@@ -0,0 +1,3 @@
+.DS_Store
+node_modules
+.nyc_output
diff --git a/server/node_modules/pgtools/.travis.yml b/server/node_modules/pgtools/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b15794065ddeed27769996e27fa754073d01cfc9
--- /dev/null
+++ b/server/node_modules/pgtools/.travis.yml
@@ -0,0 +1,10 @@
+language: node_js
+node_js:
+  - "5"
+  - "6"
+  - "node"
+services:
+  - postgresql
+env:
+  - PG_CONNECTION_STRING="postgres://postgres@localhost"
+after_success: npm run coverage
diff --git a/server/node_modules/pgtools/CHANGELOG.md b/server/node_modules/pgtools/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..f904c53b72b7c0497fffbbc0a71c012a3744c0a9
--- /dev/null
+++ b/server/node_modules/pgtools/CHANGELOG.md
@@ -0,0 +1,56 @@
+# Change Log
+
+All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+<a name="0.3.0"></a>
+# [0.3.0](https://github.com/olalonde/pgtools/compare/v0.2.3...v0.3.0) (2017-07-24)
+
+
+### Features
+
+* allow password to be provided via CLI ([#18](https://github.com/olalonde/pgtools/issues/18)) ([3c0d313](https://github.com/olalonde/pgtools/commit/3c0d313))
+
+
+
+<a name="0.2.3"></a>
+## [0.2.3](https://github.com/olalonde/pgtools/compare/v0.2.2...v0.2.3) (2016-11-27)
+
+
+### Bug Fixes
+
+* an object was being thrown rather than an Error ([#11](https://github.com/olalonde/pgtools/issues/11)) ([ec2972c](https://github.com/olalonde/pgtools/commit/ec2972c))
+
+
+
+<a name="0.2.2"></a>
+## [0.2.2](https://github.com/olalonde/pgtools/compare/v0.2.1...v0.2.2) (2016-09-24)
+
+
+### Bug Fixes
+
+* dropdbjs was pointing to the ./createdb.js script ([#9](https://github.com/olalonde/pgtools/issues/9)) ([0dc497e](https://github.com/olalonde/pgtools/commit/0dc497e))
+
+
+
+<a name="0.2.1"></a>
+## [0.2.1](https://github.com/olalonde/pgtools/compare/v0.2.0...v0.2.1) (2016-09-24)
+
+
+### Bug Fixes
+
+* non-pg error not handled properly ([#8](https://github.com/olalonde/pgtools/issues/8)) ([a4a7594](https://github.com/olalonde/pgtools/commit/a4a7594))
+
+
+
+<a name="0.2.0"></a>
+# [0.2.0](https://github.com/olalonde/pgtools/compare/v0.1.1...v0.2.0) (2016-09-14)
+
+
+### Bug Fixes
+
+* the git URL should point to pgtools not createdb ([33de02d](https://github.com/olalonde/pgtools/commit/33de02d))
+
+
+### Features
+
+* implemented createdb and dropdb bins ([#6](https://github.com/olalonde/pgtools/issues/6)) ([d596f96](https://github.com/olalonde/pgtools/commit/d596f96))
diff --git a/server/node_modules/pgtools/LICENSE b/server/node_modules/pgtools/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..44db3cc092ba3212b39c631aa938b67d20fe8f86
--- /dev/null
+++ b/server/node_modules/pgtools/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Olivier Lalonde <olalonde@gmail.com>, Benjamin E. Coe and contributors
+
+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.
diff --git a/server/node_modules/pgtools/README.md b/server/node_modules/pgtools/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7ecf5259a0bccc5d48b2df62802edb7b04232e8b
--- /dev/null
+++ b/server/node_modules/pgtools/README.md
@@ -0,0 +1,98 @@
+# pgtools
+
+[![Build
+Status](https://travis-ci.org/olalonde/pgtools.svg?branch=master)](https://travis-ci.org/olalonde/pgtools)
+[![Coverage Status](https://coveralls.io/repos/github/olalonde/pgtools/badge.svg?branch=master)](https://coveralls.io/github/olalonde/pgtools?branch=master)
+[![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version)
+
+
+Pure Node.js implementation of PostgreSQL's
+[createdb](http://www.postgresql.org/docs/9.4/static/app-createdb.html)
+and
+[dropdb](http://www.postgresql.org/docs/9.4/static/app-dropdb.html)
+tools.
+
+Only supports connection options and database name at the moment.
+
+## Install
+
+```bash
+npm install --save -g pgtools
+```
+
+## CLI Example
+
+```bash
+createdbjs my_awesome_db --user=admin --pasword=admin
+```
+
+## Programatic Example
+
+```javascript
+var pgtools = require('pgtools');
+
+// This can also be a connection string
+// (in which case the database part is ignored and replaced with postgres)
+
+const config = {
+  user: 'postgres',
+  password: 'some pass',
+  port: 5432,
+  host: 'localhost'
+}
+
+pgtools.createdb(config, 'test-db', function (err, res) {
+  if (err) {
+    console.error(err);
+    process.exit(-1);
+  }
+  console.log(res);
+
+  pgtools.dropdb(config, 'test-db', function (err, res) {
+    if (err) {
+      console.error(err);
+      process.exit(-1);
+    }
+    console.log(res);
+  });
+});
+// a promise API is also available if cb is omitted
+```
+
+# Usage
+
+`pgtools.createdb(config, dbname [, cb(err)])`
+
+`pgtools.dropdb(config, dbname [, cb(err)])`
+
+* _object_ __config__
+
+    An object with user, password, port, and host properties. This can
+    also be a node-postgres compatible connection string.
+
+* _string_ __dbname__
+
+    The name of the database to create.
+
+* _function_ __cb__
+
+    A callback that takes an error argument. If cb is omitted the
+    function will return a Promise.
+
+## Bins
+
+`pgtools` installs two useful binaries:
+
+* `createdbjs`: which emulates pgtools' `createdb` functionality.
+* `dropdbjs`: which emulates pgtools' `dropdb` functionality.
+
+## Releasing
+
+Rather than manually running `npm version <patch|minor|major>`, instead run:
+
+```
+npm run release
+```
+
+This will automatically generating a CHANGELOG, and bump your package version
+based on [the angular commit format](https://github.com/conventional-changelog/conventional-changelog-angular/blob/master/convention.md).
diff --git a/server/node_modules/pgtools/createdb.js b/server/node_modules/pgtools/createdb.js
new file mode 100755
index 0000000000000000000000000000000000000000..020dd634d8023641de92e5b8638bcbc06d59701a
--- /dev/null
+++ b/server/node_modules/pgtools/createdb.js
@@ -0,0 +1,21 @@
+#!/usr/bin/env node
+var createdb = require('./').createdb;
+var yargs = require('./lib/build-yargs')()
+var argv = yargs.argv;
+
+createdb({
+  host: argv.host,
+  port: argv.port,
+  user: argv.user,
+  password: argv.password
+}, argv._[0], function (err, res) {
+  if (err) die(err, argv)
+  else if (!argv.silent) console.log('created database "' + argv._[0] + '"')
+})
+
+function die (err, argv) {
+  if (err) {
+    if (!argv.silent) console.log(err.pgErr ? err.pgErr.toString() : err.toString());
+    process.exit(-1);
+  }
+}
diff --git a/server/node_modules/pgtools/docker-compose.yml b/server/node_modules/pgtools/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9ba8fe8f2c2289bb1a500218d9376f752e70c183
--- /dev/null
+++ b/server/node_modules/pgtools/docker-compose.yml
@@ -0,0 +1,15 @@
+db:
+  image: postgres:9.3
+  ports:
+    - "5432:5432"
+
+dbcreate:
+  image: postgres:9.3
+  links:
+    - db
+  command: >
+    /bin/bash -c "
+      while ! psql --host=db --username=postgres; do sleep 1; done;
+      psql --host=db --username=postgres -c 'DROP DATABASE \"pgtools-test\";';
+      psql --host=db --username=postgres -c 'CREATE DATABASE \"pgtools-test\";';
+    "
diff --git a/server/node_modules/pgtools/dropdb.js b/server/node_modules/pgtools/dropdb.js
new file mode 100755
index 0000000000000000000000000000000000000000..aac1abdb3d7c0398a35880617acaafafbdf7bdae
--- /dev/null
+++ b/server/node_modules/pgtools/dropdb.js
@@ -0,0 +1,21 @@
+#!/usr/bin/env node
+var dropdb = require('./').dropdb;
+var yargs = require('./lib/build-yargs')()
+var argv = yargs.argv;
+
+dropdb({
+  host: argv.host,
+  port: argv.port,
+  user: argv.user,
+  password: argv.password
+}, argv._[0], function (err, res) {
+  if (err) die(err, argv)
+  else if (!argv.silent) console.log('dropped database "' + argv._[0] + '"')
+})
+
+function die (err, argv) {
+  if (err) {
+    if (!argv.silent) console.log(err.pgErr ? err.pgErr.toString() : err.toString());
+    process.exit(-1);
+  }
+}
diff --git a/server/node_modules/pgtools/index.js b/server/node_modules/pgtools/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..061b0b5a4f98368d3888c42c7e2d18b1d307ca21
--- /dev/null
+++ b/server/node_modules/pgtools/index.js
@@ -0,0 +1,78 @@
+const BPromise = require('bluebird');
+const parse = require('pg-connection-string').parse;
+const pg = require('pg');
+const Client = pg.Client;
+const ADMIN_DB = 'postgres'
+
+var errors = {
+  '42P04': {
+    name: 'duplicate_database',
+    message: 'Attempted to create a duplicate database.'
+  },
+  '3D000': {
+    name: 'invalid_catalog_name',
+    message: 'Attempted to drop a database that does not exist.'
+  },
+  '23505': {
+    name: 'unique_violation',
+    message: 'Attempted to create a database concurrently.'
+  },
+  '55006': {
+    name: 'drop_database_in_use',
+    message: 'Attempted to drop a database that is being accessed by other users'
+  }
+};
+
+function PgError(pgErr) {
+  var message = (errors[pgErr.code] ? errors[pgErr.code].message : 'Postgres error.') + ' Cause: ' + pgErr.message;
+  var error = Error.call(this, message);
+  this.message = error.message;
+
+  this.name = errors[pgErr.code] ? errors[pgErr.code].name : 'PgError';
+
+  this.stack = error.stack;
+  this.pgErr = pgErr;
+}
+PgError.prototype = Object.create(Error.prototype);
+
+function createOrDropDatabase(action) {
+  action = action.toUpperCase();
+  return function (opts, dbName, cb) {
+    var config
+    if (typeof opts === 'string') {
+      config = parse(opts);
+      config.database = ADMIN_DB;
+    } else {
+      if (!opts.database) {
+        opts.database = ADMIN_DB;
+      }
+      config = opts;
+    }
+    return new BPromise(function (resolve, reject) {
+      var client = new Client(config);
+      //disconnect client when all queries are finished
+      client.on('drain', client.end.bind(client));
+      client.on('error', function (err) {
+        reject(err);
+      });
+      client.connect();
+
+      var escapedDbName = dbName.replace(/\"/g, '""');
+      var sql = action + ' DATABASE "' + escapedDbName + '"';
+      client.query(sql, function (pgErr, res) {
+        var err;
+        if (pgErr) {
+          err = new PgError(pgErr);
+          reject(err);
+          return
+        }
+        resolve(res);
+      });
+    }).nodeify(cb);
+  };
+};
+
+module.exports = {
+  createdb: createOrDropDatabase('create'),
+  dropdb: createOrDropDatabase('drop')
+};
diff --git a/server/node_modules/pgtools/lib/build-yargs.js b/server/node_modules/pgtools/lib/build-yargs.js
new file mode 100644
index 0000000000000000000000000000000000000000..e1312f091f07281d5ad218c75c72df0c0c917bda
--- /dev/null
+++ b/server/node_modules/pgtools/lib/build-yargs.js
@@ -0,0 +1,29 @@
+module.exports = function () {
+  return require('yargs')
+    .usage('$0 [options] <dbname>')
+    .option('host', {
+      alias: 'h',
+      default: '127.0.0.1',
+      describe: 'database server host or socket directory'
+    })
+    .option('port', {
+      alias: 'p',
+      default: 5432,
+      describe: 'database server port'
+    })
+    .option('user', {
+      alias: 'u',
+      default: 'postgres',
+      describe: 'user name to connect as'
+    })
+    .option('password', {
+      describe: 'password to use when connecting'
+    })
+    .option('silent', {
+      default: false,
+      describe: 'should we output to stdout'
+    })
+    .demand(1, 'you must provide a database name')
+    .help()
+    .version()
+}
diff --git a/server/node_modules/pgtools/node_modules/.bin/semver b/server/node_modules/pgtools/node_modules/.bin/semver
new file mode 120000
index 0000000000000000000000000000000000000000..317eb293d8e125968256d4819f26caf2343475c4
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/.bin/semver
@@ -0,0 +1 @@
+../semver/bin/semver
\ No newline at end of file
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/.npmignore b/server/node_modules/pgtools/node_modules/buffer-writer/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..9f60d21b6ffe657237ed6e34e75b3dd4061e4db2
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/.npmignore
@@ -0,0 +1,2 @@
+benchmark/versions/
+node_modules
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/.travis.yml b/server/node_modules/pgtools/node_modules/buffer-writer/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ed178f635116c920e2030bb38151649f3c4dfc00
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+  - 0.8
+  - 0.9
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/LICENSE b/server/node_modules/pgtools/node_modules/buffer-writer/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..72dc60d84b692387206266939bc34656bcba1e15
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/LICENSE
@@ -0,0 +1,19 @@
+The MIT License (MIT)
+
+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.
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/README.md b/server/node_modules/pgtools/node_modules/buffer-writer/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..81eccc0588eae24237b14657de8e9ada80818e7e
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/README.md
@@ -0,0 +1,48 @@
+# buffer-writer
+
+[![Build Status](https://secure.travis-ci.org/brianc/node-buffer-writer.png?branch=master)](http://travis-ci.org/brianc/node-buffer-writer)
+
+Fast & efficient buffer writer used to keep memory usage low by internally recycling a single large buffer.
+
+Used as the binary protocol writer in [node-postgres](https://github.com/brianc/node-postgres)
+
+Since postgres requires big endian encoding, this only writes big endian numbers for now, but can & probably will easily be extended to write little endian as well.
+
+I'll admit this has a few postgres specific things I might need to take out in the future, such as `addHeader`
+
+## api
+
+`var writer = new (require('buffer-writer')());`
+
+### writer.addInt32(num)
+
+Writes a 4-byte big endian binary encoded number to the end of the buffer.
+
+### writer.addInt16(num)
+
+Writes a 2-byte big endian binary encoded number to the end of the buffer.
+
+### writer.addCString(string)
+
+Writes a string to the buffer `utf8` encoded and adds a null character (`\0`) at the end.
+
+### var buffer = writer.addHeader(char)
+
+Writes the 5 byte PostgreSQL required header to the beginning of the buffer. (1 byte for character, 1 BE Int32 for length of the buffer)
+
+### var buffer = writer.join()
+
+Collects all data in the writer and joins it into a single, new buffer.
+
+### var buffer = writer.flush(char)
+
+Writes the 5 byte postgres required message header, collects all data in the writer and joins it into a single, new buffer, and then resets the writer.
+
+## thoughts
+
+This is kind of node-postgres specific.  If you're interested in using this for a more general purpose thing, lemme know.
+I would love to work with you on getting this more reusable for your needs.
+
+## license
+
+MIT
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/index.js b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..69d8f4b4e9a3747570fab55c68cbf80f876a4a35
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/index.js
@@ -0,0 +1,86 @@
+var fs = require('fs');
+var path = require('path');
+
+var bench = require('bench');
+var async = require('async');
+var rmdir = require('rmdir');
+var ok = require('okay');
+var cloned = require('cloned');
+cloned.workingDir = __dirname + '/versions';
+
+exports.compare = {
+  'math': function() {
+    var two = 1 + 1;
+  },
+  'another': function() {
+    var yay = 2 + 2;
+  }
+};
+
+var clone = function(rev, cb) {
+  var outputDir = path.join(cloned.workingDir, rev);
+  console.log(outputDir)
+  if(fs.existsSync(outputDir)) {
+    return cb(null, {
+      rev: rev,
+      dir: outputDir
+    });
+  }
+  console.log('cloning version ' + rev);
+  cloned(rev, ok(cb, function(dir) {
+    console.log('cloned version ' + rev + ' to ' + dir);
+    cb(null, {
+      rev: rev,
+      dir: dir
+    });
+  }));
+};
+
+var versions = [
+  'ef599d3'
+];
+
+var scripts = fs.readdirSync(__dirname).filter(function(x) {
+  return x.indexOf('benchmark') > 0;
+});
+
+if(process.argv[2]) {
+  scripts = [process.argv[2]]
+}
+
+
+var run = function() {
+  async.map(versions, clone, function(err, results) {
+    if(err) throw err;
+    exports.compare = { };
+    var suites = [];
+    scripts.forEach(function(script) {
+      for(var i = 0; i < results.length; i++) {
+        var result = results[i];
+        var benchPath = path.join(result.dir, 'benchmark', script);
+        var suite = {};
+        suites.push(suite);
+        if(fs.existsSync(benchPath)) {
+          var bench = require(benchPath);
+          suite[script + '@' + result.rev] = bench;
+        } else {
+          console.log('%s missing at revision %s', benchPath, result.rev);
+        }
+      }
+      suite[script + '@HEAD'] = require(__dirname + '/' + script);
+    });
+    var compare = function(suite, cb) {
+      console.log('running...')
+      bench.compare(suite, null, null, null, function(err, data) {
+        if(err) return cb(err);
+        bench.show(data);
+        cb(null);
+      });
+    }
+    async.eachSeries(suites, compare, function(err, res) {
+      console.log('all suites done')
+    })
+  });
+};
+
+run();
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/int-16-benchmark.js b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/int-16-benchmark.js
new file mode 100644
index 0000000000000000000000000000000000000000..4a4e676bc4e9a9cc73030119e5d8f34a2d83fe94
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/int-16-benchmark.js
@@ -0,0 +1,31 @@
+var Writer = require(__dirname + '/../');
+
+module.exports = function() {
+  var writer = new Writer();
+  writer.addInt16(-100000000);
+  writer.addInt16(-1000);
+  writer.addInt16(-1);
+  writer.addInt16(0);
+  writer.addInt16(1);
+  writer.addInt16(1000);
+  writer.addInt16(1000000000);
+  writer.addInt16(-100000000);
+  writer.addInt16(-100000000);
+  writer.addInt16(-1000);
+  writer.addInt16(-1);
+  writer.addInt16(0);
+  writer.addInt16(1);
+  writer.addInt16(1000);
+  writer.addInt16(1000000000);
+  writer.addInt16(-1000);
+  writer.addInt16(-1);
+  writer.addInt16(0);
+  writer.addInt16(1);
+  writer.addInt16(1000);
+  writer.addInt16(1000000000);
+};
+
+if(!module.parent) {
+  module.exports();
+  console.log('benchmark ok');
+}
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/int-32-benchmark.js b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/int-32-benchmark.js
new file mode 100644
index 0000000000000000000000000000000000000000..bff4ace220db1741d0112ad7009d99e96b9e39e2
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/int-32-benchmark.js
@@ -0,0 +1,17 @@
+var Writer = require(__dirname + '/../');
+
+module.exports = function() {
+  var writer = new Writer();
+  writer.addInt32(-10000000000000);
+  writer.addInt32(-1000);
+  writer.addInt32(-1);
+  writer.addInt32(0);
+  writer.addInt32(1);
+  writer.addInt32(1000);
+  writer.addInt32(10000000000000);
+};
+
+if(!module.parent) {
+  module.exports();
+  console.log('benchmark ok');
+}
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/join-benchmark.js b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/join-benchmark.js
new file mode 100644
index 0000000000000000000000000000000000000000..49e4238b3c028ce59a05e83001b78666683eda90
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/join-benchmark.js
@@ -0,0 +1,16 @@
+var Writer = require(__dirname + '/../');
+
+var writer = new Writer();
+writer.addCString('hello');
+writer.addCString('something else, really');
+writer.addInt32(38013);
+writer.addCString('and that\'s all she wrote, folks\n...\n...not really');
+
+module.exports = function() {
+  writer.join(0x50);
+};
+
+if(!module.parent) {
+  module.exports();
+  console.log('benchmark ok');
+}
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/resize-benchmark.js b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/resize-benchmark.js
new file mode 100644
index 0000000000000000000000000000000000000000..384556674d1ada9d240db85b4c6f735c17fd9389
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/resize-benchmark.js
@@ -0,0 +1,23 @@
+var Writer = require(__dirname + '/../');
+
+var string = "";
+for(var i = 0; i < 10; i++) {
+  string += 'Once upon a time long ago there lived a little programming language named JavaScript';
+}
+
+module.exports = function() {
+  var writer = new Writer(4);
+  writer.addCString(string);
+  writer.addCString(string);
+  writer.addCString(string);
+  writer.addCString(string);
+  writer.addCString(string);
+  writer.addCString(string);
+  writer.addCString(string);
+  writer.addCString(string);
+};
+
+if(!module.parent) {
+  module.exports();
+  console.log('benchmark ok');
+}
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/small-benchmark.js b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/small-benchmark.js
new file mode 100644
index 0000000000000000000000000000000000000000..1c129f3370204e05e9b30f6bc165893e4dda0ff2
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/benchmark/small-benchmark.js
@@ -0,0 +1,14 @@
+var Writer = require(__dirname + '/../');
+
+module.exports = function() {
+  var writer = new Writer();
+  writer.addInt32(10);
+  writer.addInt16(5);
+  writer.addCString('test');
+  writer.flush('X');
+};
+
+if(!module.parent) {
+  module.exports();
+  console.log('benchmark ok');
+}
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/index.js b/server/node_modules/pgtools/node_modules/buffer-writer/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..d4b463e061ce987b56c125ea927f3d01908a4909
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/index.js
@@ -0,0 +1,129 @@
+//binary data writer tuned for creating
+//postgres message packets as effeciently as possible by reusing the
+//same buffer to avoid memcpy and limit memory allocations
+var Writer = module.exports = function(size) {
+  this.size = size || 1024;
+  this.buffer = Buffer(this.size + 5);
+  this.offset = 5;
+  this.headerPosition = 0;
+};
+
+//resizes internal buffer if not enough size left
+Writer.prototype._ensure = function(size) {
+  var remaining = this.buffer.length - this.offset;
+  if(remaining < size) {
+    var oldBuffer = this.buffer;
+    // exponential growth factor of around ~ 1.5
+    // https://stackoverflow.com/questions/2269063/buffer-growth-strategy
+    var newSize = oldBuffer.length + (oldBuffer.length >> 1) + size;
+    this.buffer = new Buffer(newSize);
+    oldBuffer.copy(this.buffer);
+  }
+};
+
+Writer.prototype.addInt32 = function(num) {
+  this._ensure(4);
+  this.buffer[this.offset++] = (num >>> 24 & 0xFF);
+  this.buffer[this.offset++] = (num >>> 16 & 0xFF);
+  this.buffer[this.offset++] = (num >>>  8 & 0xFF);
+  this.buffer[this.offset++] = (num >>>  0 & 0xFF);
+  return this;
+};
+
+Writer.prototype.addInt16 = function(num) {
+  this._ensure(2);
+  this.buffer[this.offset++] = (num >>>  8 & 0xFF);
+  this.buffer[this.offset++] = (num >>>  0 & 0xFF);
+  return this;
+};
+
+//for versions of node requiring 'length' as 3rd argument to buffer.write
+var writeString = function(buffer, string, offset, len) {
+  buffer.write(string, offset, len);
+};
+
+//overwrite function for older versions of node
+if(Buffer.prototype.write.length === 3) {
+  writeString = function(buffer, string, offset, len) {
+    buffer.write(string, offset);
+  };
+}
+
+Writer.prototype.addCString = function(string) {
+  //just write a 0 for empty or null strings
+  if(!string) {
+    this._ensure(1);
+  } else {
+    var len = Buffer.byteLength(string);
+    this._ensure(len + 1); //+1 for null terminator
+    writeString(this.buffer, string, this.offset, len);
+    this.offset += len;
+  }
+
+  this.buffer[this.offset++] = 0; // null terminator
+  return this;
+};
+
+Writer.prototype.addChar = function(c) {
+  this._ensure(1);
+  writeString(this.buffer, c, this.offset, 1);
+  this.offset++;
+  return this;
+};
+
+Writer.prototype.addString = function(string) {
+  string = string || "";
+  var len = Buffer.byteLength(string);
+  this._ensure(len);
+  this.buffer.write(string, this.offset);
+  this.offset += len;
+  return this;
+};
+
+Writer.prototype.getByteLength = function() {
+  return this.offset - 5;
+};
+
+Writer.prototype.add = function(otherBuffer) {
+  this._ensure(otherBuffer.length);
+  otherBuffer.copy(this.buffer, this.offset);
+  this.offset += otherBuffer.length;
+  return this;
+};
+
+Writer.prototype.clear = function() {
+  this.offset = 5;
+  this.headerPosition = 0;
+  this.lastEnd = 0;
+};
+
+//appends a header block to all the written data since the last
+//subsequent header or to the beginning if there is only one data block
+Writer.prototype.addHeader = function(code, last) {
+  var origOffset = this.offset;
+  this.offset = this.headerPosition;
+  this.buffer[this.offset++] = code;
+  //length is everything in this packet minus the code
+  this.addInt32(origOffset - (this.headerPosition+1));
+  //set next header position
+  this.headerPosition = origOffset;
+  //make space for next header
+  this.offset = origOffset;
+  if(!last) {
+    this._ensure(5);
+    this.offset += 5;
+  }
+};
+
+Writer.prototype.join = function(code) {
+  if(code) {
+    this.addHeader(code, true);
+  }
+  return this.buffer.slice(code ? 0 : 5, this.offset);
+};
+
+Writer.prototype.flush = function(code) {
+  var result = this.join(code);
+  this.clear();
+  return result;
+};
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/package.json b/server/node_modules/pgtools/node_modules/buffer-writer/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..06ede0f4882026867d922dfab903fdd364475d35
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/package.json
@@ -0,0 +1,61 @@
+{
+  "_from": "buffer-writer@1.0.1",
+  "_id": "buffer-writer@1.0.1",
+  "_inBundle": false,
+  "_integrity": "sha1-Iqk2kB4wKa/NdUfrRIfOtpejvwg=",
+  "_location": "/pgtools/buffer-writer",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "buffer-writer@1.0.1",
+    "name": "buffer-writer",
+    "escapedName": "buffer-writer",
+    "rawSpec": "1.0.1",
+    "saveSpec": null,
+    "fetchSpec": "1.0.1"
+  },
+  "_requiredBy": [
+    "/pgtools/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.1.tgz",
+  "_shasum": "22a936901e3029afcd7547eb4487ceb697a3bf08",
+  "_spec": "buffer-writer@1.0.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgtools/node_modules/pg",
+  "author": {
+    "name": "Brian M. Carlson"
+  },
+  "bugs": {
+    "url": "https://github.com/brianc/node-buffer-writer/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "a fast, efficient buffer writer",
+  "devDependencies": {
+    "async": "~0.2.6",
+    "bench": "~0.3.5",
+    "benchmark": "~1.0.0",
+    "cloned": "0.0.1",
+    "microtime": "~0.3.3",
+    "mocha": "~1.8.1",
+    "okay": "0.0.2",
+    "rmdir": "~1.0.0"
+  },
+  "homepage": "https://github.com/brianc/node-buffer-writer#readme",
+  "keywords": [
+    "buffer",
+    "writer",
+    "builder"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "buffer-writer",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianc/node-buffer-writer.git"
+  },
+  "scripts": {
+    "test": "mocha"
+  },
+  "version": "1.0.1"
+}
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/test/mocha.opts b/server/node_modules/pgtools/node_modules/buffer-writer/test/mocha.opts
new file mode 100644
index 0000000000000000000000000000000000000000..5efaf24d77060047c39188760c36970e10af6f3d
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/test/mocha.opts
@@ -0,0 +1 @@
+--ui tdd
diff --git a/server/node_modules/pgtools/node_modules/buffer-writer/test/writer-tests.js b/server/node_modules/pgtools/node_modules/buffer-writer/test/writer-tests.js
new file mode 100644
index 0000000000000000000000000000000000000000..685298a3b97640286a33a493699615cf0fca49d0
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/buffer-writer/test/writer-tests.js
@@ -0,0 +1,218 @@
+var Writer = require(__dirname + "/../");
+
+var assert = require('assert');
+var util = require('util');
+
+assert.equalBuffers = function(actual, expected) {
+  var spit = function(actual, expected) {
+    console.log("");
+    console.log("actual " + util.inspect(actual));
+    console.log("expect " + util.inspect(expected));
+    console.log("");
+  };
+  if(actual.length != expected.length) {
+    spit(actual, expected);
+    assert.equal(actual.length, expected.length);
+  }
+  for(var i = 0; i < actual.length; i++) {
+    if(actual[i] != expected[i]) {
+      spit(actual, expected);
+    }
+    assert.equal(actual[i],expected[i]);
+  }
+};
+
+suite('adding int32', function() {
+  var testAddingInt32 = function(int, expectedBuffer) {
+    test('writes ' + int, function() {
+      var subject = new Writer();
+      var result = subject.addInt32(int).join();
+      assert.equalBuffers(result, expectedBuffer);
+    });
+  };
+
+  testAddingInt32(0, [0, 0, 0, 0]);
+  testAddingInt32(1, [0, 0, 0, 1]);
+  testAddingInt32(256, [0, 0, 1, 0]);
+  test('writes largest int32', function() {
+    //todo need to find largest int32 when I have internet access
+    return false;
+  });
+
+  test('writing multiple int32s', function() {
+    var subject = new Writer();
+    var result = subject.addInt32(1).addInt32(10).addInt32(0).join();
+    assert.equalBuffers(result, [0, 0, 0, 1, 0, 0, 0, 0x0a, 0, 0, 0, 0]);
+  });
+
+  suite('having to resize the buffer', function() {
+    test('after resize correct result returned', function() {
+      var subject = new Writer(10);
+      subject.addInt32(1).addInt32(1).addInt32(1);
+      assert.equalBuffers(subject.join(), [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]);
+    });
+  });
+});
+
+suite('int16', function() {
+  test('writes 0', function() {
+    var subject = new Writer();
+    var result = subject.addInt16(0).join();
+    assert.equalBuffers(result, [0,0]);
+  });
+
+  test('writes 400', function() {
+    var subject = new Writer();
+    var result = subject.addInt16(400).join();
+    assert.equalBuffers(result, [1, 0x90]);
+  });
+
+  test('writes many', function() {
+    var subject = new Writer();
+    var result = subject.addInt16(0).addInt16(1).addInt16(2).join();
+    assert.equalBuffers(result, [0, 0, 0, 1, 0, 2]);
+  });
+
+  test('resizes if internal buffer fills up', function() {
+    var subject = new Writer(3);
+    var result = subject.addInt16(2).addInt16(3).join();
+    assert.equalBuffers(result, [0, 2, 0, 3]);
+  });
+
+});
+
+suite('cString', function() {
+  test('writes empty cstring', function() {
+    var subject = new Writer();
+    var result = subject.addCString().join();
+    assert.equalBuffers(result, [0]);
+  });
+  
+  test('writes two empty cstrings', function() {
+    var subject = new Writer();
+    var result = subject.addCString("").addCString("").join();
+    assert.equalBuffers(result, [0, 0]);
+  });
+
+
+  test('writes non-empty cstring', function() {
+    var subject = new Writer();
+    var result = subject.addCString("!!!").join();
+    assert.equalBuffers(result, [33, 33, 33, 0]);
+  });
+
+  test('resizes if reached end', function() {
+    var subject = new Writer(3);
+    var result = subject.addCString("!!!").join();
+    assert.equalBuffers(result, [33, 33, 33, 0]);
+  });
+
+  test('writes multiple cstrings', function() {
+    var subject = new Writer();
+    var result = subject.addCString("!").addCString("!").join();
+    assert.equalBuffers(result, [33, 0, 33, 0]);
+  });
+
+});
+
+test('writes char', function() {
+  var subject = new Writer(2);
+  var result = subject.addChar('a').addChar('b').addChar('c').join();
+  assert.equalBuffers(result, [0x61, 0x62, 0x63]);
+});
+
+test('gets correct byte length', function() {
+  var subject = new Writer(5);
+  assert.equal(subject.getByteLength(), 0);
+  subject.addInt32(0);
+  assert.equal(subject.getByteLength(), 4);
+  subject.addCString("!");
+  assert.equal(subject.getByteLength(), 6);
+});
+
+test('can add arbitrary buffer to the end', function() {
+  var subject = new Writer(4);
+  subject.addCString("!!!")
+  var result = subject.add(Buffer("@@@")).join();
+  assert.equalBuffers(result, [33, 33, 33, 0, 0x40, 0x40, 0x40]);
+});
+
+suite('can write normal string', function() {
+  var subject = new Writer(4);
+  var result = subject.addString("!").join();
+  assert.equalBuffers(result, [33]);
+  test('can write cString too', function() {
+    var result = subject.addCString("!").join();
+    assert.equalBuffers(result, [33, 33, 0]);
+  });
+  test('can resize', function() {
+    var result = subject.addString("!!").join();
+    assert.equalBuffers(result, [33, 33, 0, 33, 33]);
+  });
+});
+
+
+suite('clearing', function() {
+  var subject = new Writer();
+  subject.addCString("@!!#!#");
+  subject.addInt32(10401);
+  test('clears', function() {
+    subject.clear();
+    assert.equalBuffers(subject.join(), []);
+  });
+  test('writing more', function() {
+    var joinedResult = subject.addCString("!").addInt32(9).addInt16(2).join();
+    assert.equalBuffers(joinedResult, [33, 0, 0, 0, 0, 9, 0, 2]);
+  });
+  test('returns result', function() {
+    var flushedResult = subject.flush();
+    assert.equalBuffers(flushedResult, [33, 0, 0, 0, 0, 9, 0, 2])
+  });
+  test('clears the writer', function() {
+    assert.equalBuffers(subject.join(), [])
+    assert.equalBuffers(subject.flush(), [])
+  });
+});
+
+test("resizing to much larger", function() {
+  var subject = new Writer(2);
+  var string = "!!!!!!!!";
+  var result = subject.addCString(string).flush();
+  assert.equalBuffers(result, [33, 33, 33, 33, 33, 33, 33, 33, 0]);
+});
+
+suite("flush", function() {
+  test('added as a hex code to a full writer', function() {
+    var subject = new Writer(2);
+    var result = subject.addCString("!").flush(0x50);
+    assert.equalBuffers(result, [0x50, 0, 0, 0, 6, 33, 0]);
+  });
+
+  test('added as a hex code to a non-full writer', function() {
+    var subject = new Writer(10).addCString("!");
+    var joinedResult = subject.join(0x50);
+    var result = subject.flush(0x50);
+    assert.equalBuffers(result, [0x50, 0, 0, 0, 6, 33, 0]);
+  });
+
+  test('added as a hex code to a buffer which requires resizing', function() {
+    var result = new Writer(2).addCString("!!!!!!!!").flush(0x50);
+    assert.equalBuffers(result, [0x50, 0, 0, 0, 0x0D, 33, 33, 33, 33, 33, 33, 33, 33, 0]);
+  });
+});
+
+suite("header", function() {
+  test('adding two packets with headers', function() {
+    var subject = new Writer(10).addCString("!");
+    subject.addHeader(0x50);
+    subject.addCString("!!");
+    subject.addHeader(0x40);
+    subject.addCString("!");
+    var result = subject.flush(0x10);
+    assert.equalBuffers(result, [0x50, 0, 0, 0, 6, 33, 0, 0x40, 0, 0, 0, 7, 33, 33, 0, 0x10, 0, 0, 0, 6, 33, 0 ]);
+  });
+});
+
+
+
+
diff --git a/server/node_modules/pgtools/node_modules/object-assign/index.js b/server/node_modules/pgtools/node_modules/object-assign/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..508504840dc61d5f821497e057e68e3000b21c41
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/object-assign/index.js
@@ -0,0 +1,83 @@
+'use strict';
+/* eslint-disable no-unused-vars */
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+var propIsEnumerable = Object.prototype.propertyIsEnumerable;
+
+function toObject(val) {
+	if (val === null || val === undefined) {
+		throw new TypeError('Object.assign cannot be called with null or undefined');
+	}
+
+	return Object(val);
+}
+
+function shouldUseNative() {
+	try {
+		if (!Object.assign) {
+			return false;
+		}
+
+		// Detect buggy property enumeration order in older V8 versions.
+
+		// https://bugs.chromium.org/p/v8/issues/detail?id=4118
+		var test1 = new String('abc');  // eslint-disable-line
+		test1[5] = 'de';
+		if (Object.getOwnPropertyNames(test1)[0] === '5') {
+			return false;
+		}
+
+		// https://bugs.chromium.org/p/v8/issues/detail?id=3056
+		var test2 = {};
+		for (var i = 0; i < 10; i++) {
+			test2['_' + String.fromCharCode(i)] = i;
+		}
+		var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
+			return test2[n];
+		});
+		if (order2.join('') !== '0123456789') {
+			return false;
+		}
+
+		// https://bugs.chromium.org/p/v8/issues/detail?id=3056
+		var test3 = {};
+		'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
+			test3[letter] = letter;
+		});
+		if (Object.keys(Object.assign({}, test3)).join('') !==
+				'abcdefghijklmnopqrst') {
+			return false;
+		}
+
+		return true;
+	} catch (e) {
+		// We don't expect any of the above to throw, but better to be safe.
+		return false;
+	}
+}
+
+module.exports = shouldUseNative() ? Object.assign : function (target, source) {
+	var from;
+	var to = toObject(target);
+	var symbols;
+
+	for (var s = 1; s < arguments.length; s++) {
+		from = Object(arguments[s]);
+
+		for (var key in from) {
+			if (hasOwnProperty.call(from, key)) {
+				to[key] = from[key];
+			}
+		}
+
+		if (Object.getOwnPropertySymbols) {
+			symbols = Object.getOwnPropertySymbols(from);
+			for (var i = 0; i < symbols.length; i++) {
+				if (propIsEnumerable.call(from, symbols[i])) {
+					to[symbols[i]] = from[symbols[i]];
+				}
+			}
+		}
+	}
+
+	return to;
+};
diff --git a/server/node_modules/pgtools/node_modules/object-assign/license b/server/node_modules/pgtools/node_modules/object-assign/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/object-assign/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/pgtools/node_modules/object-assign/package.json b/server/node_modules/pgtools/node_modules/object-assign/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..ea468d1cd335e158c21b1572b95899bfcdc84c34
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/object-assign/package.json
@@ -0,0 +1,74 @@
+{
+  "_from": "object-assign@4.1.0",
+  "_id": "object-assign@4.1.0",
+  "_inBundle": false,
+  "_integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=",
+  "_location": "/pgtools/object-assign",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "object-assign@4.1.0",
+    "name": "object-assign",
+    "escapedName": "object-assign",
+    "rawSpec": "4.1.0",
+    "saveSpec": null,
+    "fetchSpec": "4.1.0"
+  },
+  "_requiredBy": [
+    "/pgtools/pg-pool"
+  ],
+  "_resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz",
+  "_shasum": "7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0",
+  "_spec": "object-assign@4.1.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgtools/node_modules/pg-pool",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/object-assign/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "ES2015 Object.assign() ponyfill",
+  "devDependencies": {
+    "lodash": "^4.8.2",
+    "matcha": "^0.7.0",
+    "mocha": "*",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/object-assign#readme",
+  "keywords": [
+    "object",
+    "assign",
+    "extend",
+    "properties",
+    "es2015",
+    "ecmascript",
+    "harmony",
+    "ponyfill",
+    "prollyfill",
+    "polyfill",
+    "shim",
+    "browser"
+  ],
+  "license": "MIT",
+  "name": "object-assign",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/object-assign.git"
+  },
+  "scripts": {
+    "bench": "matcha bench.js",
+    "test": "xo && mocha"
+  },
+  "version": "4.1.0"
+}
diff --git a/server/node_modules/pgtools/node_modules/object-assign/readme.md b/server/node_modules/pgtools/node_modules/object-assign/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..13c097734cfd18fcc07587940321aa7cb8ef3b20
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/object-assign/readme.md
@@ -0,0 +1,56 @@
+# object-assign [![Build Status](https://travis-ci.org/sindresorhus/object-assign.svg?branch=master)](https://travis-ci.org/sindresorhus/object-assign)
+
+> ES2015 [`Object.assign()`](http://www.2ality.com/2014/01/object-assign.html) ponyfill
+
+> Ponyfill: A polyfill that doesn't overwrite the native method
+
+
+## Install
+
+```
+$ npm install --save object-assign
+```
+
+
+## Usage
+
+```js
+const objectAssign = require('object-assign');
+
+objectAssign({foo: 0}, {bar: 1});
+//=> {foo: 0, bar: 1}
+
+// multiple sources
+objectAssign({foo: 0}, {bar: 1}, {baz: 2});
+//=> {foo: 0, bar: 1, baz: 2}
+
+// overwrites equal keys
+objectAssign({foo: 0}, {foo: 1}, {foo: 2});
+//=> {foo: 2}
+
+// ignores null and undefined sources
+objectAssign({foo: 0}, null, {bar: 1}, undefined);
+//=> {foo: 0, bar: 1}
+```
+
+
+## API
+
+### objectAssign(target, source, [source, ...])
+
+Assigns enumerable own properties of `source` objects to the `target` object and returns the `target` object. Additional `source` objects will overwrite previous ones.
+
+
+## Resources
+
+- [ES2015 spec - Object.assign](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign)
+
+
+## Related
+
+- [deep-assign](https://github.com/sindresorhus/deep-assign) - Recursive `Object.assign()`
+
+
+## License
+
+MIT © [Sindre Sorhus](https://sindresorhus.com)
diff --git a/server/node_modules/pgtools/node_modules/packet-reader/.npmignore b/server/node_modules/pgtools/node_modules/packet-reader/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..3c3629e647f5ddf82548912e337bea9826b434af
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/packet-reader/.npmignore
@@ -0,0 +1 @@
+node_modules
diff --git a/server/node_modules/pgtools/node_modules/packet-reader/README.md b/server/node_modules/pgtools/node_modules/packet-reader/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..5ae3ef85967cbcc7df776c6d2aaf9e4a927fb651
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/packet-reader/README.md
@@ -0,0 +1,87 @@
+node-packet-reader
+==================
+
+Handy little well tested module for reading length-prefixed binary packets.
+
+Since buffers come off a socket in randomly sized chunks you can't expect them to cleanly
+break on packet boundaries.  This module allows you to push buffers in and read
+full packets out the other side, so you can get to parsing right away and not have
+to manage concatenating partial buffers and searching through them for packets.
+
+## install
+
+` $ npm install packet-reader `
+
+## example
+
+```js
+var Reader = require('packet-reader')
+
+var reader = new Reader()
+//assuming you have a socket emitting `data` events
+socket.on('data', function(buffer) {
+  reader.addChunk(buffer)
+  var packet = reader.read()
+  while(packet) {
+    //do something with fully parsed packet
+  }
+})
+```
+
+
+here's a more full featured example:
+
+let's assume our "packet" for our protocol is 32-bit Big Endian length-prefixed strings
+so a "hello world" packet would look something like [length, string]
+`[0, 0, 0 0x0B, h, e, l, l, o, w, o, r, l, d]`
+
+```js
+var Transform = require('stream').Transform
+var Reader = require('packet-reader')
+var reader = new Reader()
+var parser = new Transform()
+parser._transform = function(chunk, encoding, cb) {
+  reader.addChunk(chunk)
+  var packet = reader.read()
+  while(packet) {
+    this.push(packet.toString('utf8'))
+    packet = reader.read()
+  }
+  cb()
+}
+
+var server = net.createServer(function(socket) {
+  socket.pipe(parser).pipe(stdout)
+})
+
+```
+
+There are a few config options for setting optional pre-length padding byte.  Read the tests for details.
+
+## License
+
+MIT
+
+Copyright 2015 Brian M. Carlson
+All rights reserved.
+
+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.
diff --git a/server/node_modules/pgtools/node_modules/packet-reader/index.js b/server/node_modules/pgtools/node_modules/packet-reader/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..6ca60fd74f1bbb55a4cd92fa9d0704714369e180
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/packet-reader/index.js
@@ -0,0 +1,65 @@
+var assert = require('assert')
+
+var Reader = module.exports = function(options) {
+  //TODO - remove for version 1.0
+  if(typeof options == 'number') {
+    options = { headerSize: options }
+  }
+  options = options || {}
+  this.offset = 0
+  this.lastChunk = false
+  this.chunk = null
+  this.chunkLength = 0
+  this.headerSize = options.headerSize || 0
+  this.lengthPadding = options.lengthPadding || 0
+  this.header = null
+  assert(this.headerSize < 2, 'pre-length header of more than 1 byte length not currently supported')
+}
+
+Reader.prototype.addChunk = function(chunk) {
+  if (!this.chunk || this.offset === this.chunkLength) {
+    this.chunk = chunk
+    this.chunkLength = chunk.length
+    this.offset = 0
+    return
+  }
+
+  var newChunkLength = chunk.length
+  var newLength = this.chunkLength + newChunkLength
+
+  if (newLength > this.chunk.length) {
+    var newBufferLength = this.chunk.length * 2
+    while (newLength >= newBufferLength) {
+      newBufferLength *= 2
+    }
+    var newBuffer = new Buffer(newBufferLength)
+    this.chunk.copy(newBuffer)
+    this.chunk = newBuffer
+  }
+  chunk.copy(this.chunk, this.chunkLength)
+  this.chunkLength = newLength
+}
+
+Reader.prototype.read = function() {
+  if(this.chunkLength < (this.headerSize + 4 + this.offset)) {
+    return false
+  }
+
+  if(this.headerSize) {
+    this.header = this.chunk[this.offset]
+  }
+
+  //read length of next item
+  var length = this.chunk.readUInt32BE(this.offset + this.headerSize) + this.lengthPadding
+
+  //next item spans more chunks than we have
+  var remaining = this.chunkLength - (this.offset + 4 + this.headerSize)
+  if(length > remaining) {
+    return false
+  }
+
+  this.offset += (this.headerSize + 4)
+  var result = this.chunk.slice(this.offset, this.offset + length)
+  this.offset += length
+  return result
+}
diff --git a/server/node_modules/pgtools/node_modules/packet-reader/package.json b/server/node_modules/pgtools/node_modules/packet-reader/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..abe04d4d10fbe226b9e1380ff8ebf9dc895cdcee
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/packet-reader/package.json
@@ -0,0 +1,52 @@
+{
+  "_from": "packet-reader@0.3.1",
+  "_id": "packet-reader@0.3.1",
+  "_inBundle": false,
+  "_integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc=",
+  "_location": "/pgtools/packet-reader",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "packet-reader@0.3.1",
+    "name": "packet-reader",
+    "escapedName": "packet-reader",
+    "rawSpec": "0.3.1",
+    "saveSpec": null,
+    "fetchSpec": "0.3.1"
+  },
+  "_requiredBy": [
+    "/pgtools/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz",
+  "_shasum": "cd62e60af8d7fea8a705ec4ff990871c46871f27",
+  "_spec": "packet-reader@0.3.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgtools/node_modules/pg",
+  "author": {
+    "name": "Brian M. Carlson"
+  },
+  "bugs": {
+    "url": "https://github.com/brianc/node-packet-reader/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Read binary packets...",
+  "devDependencies": {
+    "mocha": "~1.16.2"
+  },
+  "directories": {
+    "test": "test"
+  },
+  "homepage": "https://github.com/brianc/node-packet-reader",
+  "license": "MIT",
+  "main": "index.js",
+  "name": "packet-reader",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianc/node-packet-reader.git"
+  },
+  "scripts": {
+    "test": "mocha"
+  },
+  "version": "0.3.1"
+}
diff --git a/server/node_modules/pgtools/node_modules/packet-reader/test/index.js b/server/node_modules/pgtools/node_modules/packet-reader/test/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..5bb400da26a109500918f58b5e89aaa50cf6ec44
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/packet-reader/test/index.js
@@ -0,0 +1,148 @@
+var assert = require('assert')
+var Reader = require('../')
+describe('packet-reader', function() {
+  beforeEach(function() {
+    this.reader = new Reader(1)
+  })
+
+  it('reads perfect 1 length buffer', function() {
+    this.reader.addChunk(new Buffer([0, 0, 0, 0, 1, 1]))
+    var result = this.reader.read()
+    assert.equal(result.length, 1)
+    assert.equal(result[0], 1)
+    assert.strictEqual(false, this.reader.read())
+  })
+
+  it('reads perfect longer buffer', function() {
+    this.reader.addChunk(new Buffer([0, 0, 0, 0, 4, 1, 2, 3, 4]))
+    var result = this.reader.read()
+    assert.equal(result.length, 4)
+    assert.strictEqual(false, this.reader.read())
+  })
+
+  it('reads two parts', function() {
+    this.reader.addChunk(new Buffer([0, 0, 0, 0, 1]))
+    var result = this.reader.read()
+    assert.strictEqual(false, result)
+    this.reader.addChunk(new Buffer([2]))
+    var result = this.reader.read()
+    assert.equal(result.length, 1, 'should return 1 length buffer')
+    assert.equal(result[0], 2)
+    assert.strictEqual(this.reader.read(), false)
+  })
+
+  it('reads multi-part', function() {
+    this.reader.addChunk(new Buffer([0, 0, 0, 0, 16]))
+    assert.equal(false, this.reader.read())
+    this.reader.addChunk(new Buffer([1, 2, 3, 4, 5, 6, 7, 8]))
+    assert.equal(false, this.reader.read())
+    this.reader.addChunk(new Buffer([9, 10, 11, 12, 13, 14, 15, 16]))
+    var result = this.reader.read()
+    assert.equal(result.length, 16)
+  })
+
+  it('resets internal buffer at end of packet', function() {
+    this.reader.addChunk(new Buffer([0, 0, 0, 0, 16]))
+    this.reader.addChunk(new Buffer([1, 2, 3, 4, 5, 6, 7, 8]))
+    this.reader.addChunk(new Buffer([9, 10, 11, 12, 13, 14, 15, 16]))
+    var result = this.reader.read()
+    assert.equal(result.length, 16)
+
+    var newChunk = new Buffer([0, 0, 0, 0, 16])
+    this.reader.addChunk(newChunk)
+    assert.equal(this.reader.offset, 0, 'should have been reset to 0.')
+    assert.strictEqual(this.reader.chunk, newChunk)
+  })
+
+  it('reads multiple messages from single chunk', function() {
+    this.reader.addChunk(new Buffer([0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 2, 1, 2]))
+    var result = this.reader.read()
+    assert.equal(result.length, 1, 'should have 1 length buffer')
+    assert.equal(result[0], 1)
+    var result = this.reader.read()
+    assert.equal(result.length, 2, 'should have 2 length buffer but was ' + result.length)
+    assert.equal(result[0], 1)
+    assert.equal(result[1], 2)
+    assert.strictEqual(false, this.reader.read())
+  })
+
+  it('reads 1 and a split', function() {
+    this.reader.addChunk(new Buffer([0, 0, 0, 0, 1, 1, 0, 0]))//, 0, 0, 2, 1, 2]))
+    var result = this.reader.read()
+    assert.equal(result.length, 1, 'should have 1 length buffer')
+    assert.equal(result[0], 1)
+    var result = this.reader.read()
+    assert.strictEqual(result, false)
+
+    this.reader.addChunk(new Buffer([0, 0, 2, 1, 2]))
+    var result = this.reader.read()
+    assert.equal(result.length, 2, 'should have 2 length buffer but was ' + result.length)
+    assert.equal(result[0], 1)
+    assert.equal(result[1], 2)
+    assert.strictEqual(false, this.reader.read())
+  })
+})
+
+describe('variable length header', function() {
+  beforeEach(function() {
+    this.reader = new Reader()
+  })
+
+  it('reads double message buffers', function() {
+    this.reader.addChunk(new Buffer([
+                                0, 0, 0, 1, 1,
+                                0, 0, 0, 2, 1, 2]))
+    var result = this.reader.read()
+    assert(result)
+    assert.equal(result.length, 1)
+    assert.equal(result[0], 1)
+    result = this.reader.read()
+    assert(result)
+    assert.equal(result.length, 2)
+    assert.equal(result[0], 1)
+    assert.equal(result[1], 2)
+    assert.strictEqual(this.reader.read(), false)
+  })
+})
+
+describe('1 length code', function() {
+  beforeEach(function() {
+    this.reader = new Reader(1)
+  })
+
+  it('reads code', function() {
+    this.reader.addChunk(new Buffer([9, 0, 0, 0, 1, 1]))
+    var result = this.reader.read()
+    assert(result)
+    assert.equal(this.reader.header, 9)
+    assert.equal(result.length, 1)
+    assert.equal(result[0], 1)
+  })
+
+  it('is set on uncompleted read', function() {
+    assert.equal(this.reader.header, null)
+    this.reader.addChunk(new Buffer([2, 0, 0, 0, 1]))
+    assert.strictEqual(this.reader.read(), false)
+    assert.equal(this.reader.header, 2)
+  })
+})
+
+describe('postgres style packet', function() {
+  beforeEach(function() {
+    this.reader = new Reader({
+      headerSize: 1,
+      lengthPadding: -4
+    })
+  })
+
+  it('reads with padded length', function() {
+    this.reader.addChunk(new Buffer([1, 0, 0, 0, 8, 0, 0, 2, 0]))
+    var result = this.reader.read()
+    assert(result)
+    assert.equal(result.length, 4)
+    assert.equal(result[0], 0)
+    assert.equal(result[1], 0)
+    assert.equal(result[2], 2)
+    assert.equal(result[3], 0)
+  })
+})
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/.npmignore b/server/node_modules/pgtools/node_modules/pg-pool/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..93f13619916123cf5434dab2ffcc8263c7420af1
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/.npmignore
@@ -0,0 +1,2 @@
+node_modules
+npm-debug.log
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/.travis.yml b/server/node_modules/pgtools/node_modules/pg-pool/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..47358a12a1d188816ebf2ce1e4d564162b6b3ebb
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/.travis.yml
@@ -0,0 +1,13 @@
+language: node_js
+
+matrix:
+  include:
+    - node_js: "4"
+      addons:
+        postgresql: "9.1"
+    - node_js: "6"
+      addons:
+        postgresql: "9.4"
+    - node_js: "8"
+      addons:
+        postgresql: "9.4"
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/LICENSE b/server/node_modules/pgtools/node_modules/pg-pool/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..4e9058148e75f05ca4125f34eff371d08c014f6b
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Brian M. Carlson
+
+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.
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/Makefile b/server/node_modules/pgtools/node_modules/pg-pool/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..8a76314266b58ab46a4c2717b19eb6a3e1962941
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/Makefile
@@ -0,0 +1,14 @@
+.PHONY: jshint test publish-patch test
+
+test:
+	npm test
+
+patch: test
+	npm version patch -m "Bump version"
+	git push origin master --tags
+	npm publish
+
+minor: test
+	npm version minor -m "Bump version"
+	git push origin master --tags
+	npm publish
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/README.md b/server/node_modules/pgtools/node_modules/pg-pool/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..b86447b40f54b9140f4ef94432c9460d83a46b0a
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/README.md
@@ -0,0 +1,350 @@
+# pg-pool
+[![Build Status](https://travis-ci.org/brianc/node-pg-pool.svg?branch=master)](https://travis-ci.org/brianc/node-pg-pool)
+
+A connection pool for node-postgres
+
+## install
+```sh
+npm i pg-pool pg
+```
+
+## use
+
+### create
+
+to use pg-pool you must first create an instance of a pool
+
+```js
+var Pool = require('pg-pool')
+
+//by default the pool uses the same
+//configuration as whatever `pg` version you have installed
+var pool = new Pool()
+
+//you can pass properties to the pool
+//these properties are passed unchanged to both the node-postgres Client constructor
+//and the node-pool (https://github.com/coopernurse/node-pool) constructor
+//allowing you to fully configure the behavior of both
+var pool2 = new Pool({
+  database: 'postgres',
+  user: 'brianc',
+  password: 'secret!',
+  port: 5432,
+  ssl: true,
+  max: 20, //set pool max size to 20
+  min: 4, //set min pool size to 4
+  idleTimeoutMillis: 1000 //close idle clients after 1 second
+})
+
+//you can supply a custom client constructor
+//if you want to use the native postgres client
+var NativeClient = require('pg').native.Client
+var nativePool = new Pool({ Client: NativeClient })
+
+//you can even pool pg-native clients directly
+var PgNativeClient = require('pg-native')
+var pgNativePool = new Pool({ Client: PgNativeClient })
+```
+
+##### Note:
+The Pool constructor does not support passing a Database URL as the parameter. To use pg-pool on heroku, for example, you need to parse the URL into a config object. Here is an example of how to parse a Database URL.
+
+```js
+const Pool = require('pg-pool');
+const url = require('url')
+
+const params = url.parse(process.env.DATABASE_URL);
+const auth = params.auth.split(':');
+
+const config = {
+  user: auth[0],
+  password: auth[1],
+  host: params.hostname,
+  port: params.port,
+  database: params.pathname.split('/')[1],
+  ssl: true
+};
+
+const pool = new Pool(config);
+
+/*
+  Transforms, 'progres://DBuser:secret@DBHost:#####/myDB', into
+  config = {
+    user: 'DBuser',
+    password: 'secret',
+    host: 'DBHost',
+    port: '#####',
+    database: 'myDB',
+    ssl: true
+  }
+*/
+``` 
+
+### acquire clients with a promise
+
+pg-pool supports a fully promise-based api for acquiring clients
+
+```js
+var pool = new Pool()
+pool.connect().then(client => {
+  client.query('select $1::text as name', ['pg-pool']).then(res => {
+    client.release()
+    console.log('hello from', res.rows[0].name)
+  })
+  .catch(e => {
+    client.release()
+    console.error('query error', e.message, e.stack)
+  })
+})
+```
+
+### plays nice with async/await
+
+this ends up looking much nicer if you're using [co](https://github.com/tj/co) or async/await:
+
+```js
+// with async/await
+(async () => {
+  var pool = new Pool()
+  var client = await pool.connect()
+  try {
+    var result = await client.query('select $1::text as name', ['brianc'])
+    console.log('hello from', result.rows[0])
+  } finally {
+    client.release()
+  }
+})().catch(e => console.error(e.message, e.stack))
+
+// with co
+co(function * () {
+  var client = yield pool.connect()
+  try {
+    var result = yield client.query('select $1::text as name', ['brianc'])
+    console.log('hello from', result.rows[0])
+  } finally {
+    client.release()
+  }
+}).catch(e => console.error(e.message, e.stack))
+```
+
+### your new favorite helper method
+
+because its so common to just run a query and return the client to the pool afterward pg-pool has this built-in:
+
+```js
+var pool = new Pool()
+var time = await pool.query('SELECT NOW()')
+var name = await pool.query('select $1::text as name', ['brianc'])
+console.log(name.rows[0].name, 'says hello at', time.rows[0].name)
+```
+
+you can also use a callback here if you'd like:
+
+```js
+var pool = new Pool()
+pool.query('SELECT $1::text as name', ['brianc'], function (err, res) {
+  console.log(res.rows[0].name) // brianc
+})
+```
+
+__pro tip:__ unless you need to run a transaction (which requires a single client for multiple queries) or you
+have some other edge case like [streaming rows](https://github.com/brianc/node-pg-query-stream) or using a [cursor](https://github.com/brianc/node-pg-cursor)
+you should almost always just use `pool.query`.  Its easy, it does the right thing :tm:, and wont ever forget to return
+clients back to the pool after the query is done.
+
+### drop-in backwards compatible
+
+pg-pool still and will always support the traditional callback api for acquiring a client.  This is the exact API node-postgres has shipped with for years:
+
+```js
+var pool = new Pool()
+pool.connect((err, client, done) => {
+  if (err) return done(err)
+
+  client.query('SELECT $1::text as name', ['pg-pool'], (err, res) => {
+    done()
+    if (err) {
+      return console.error('query error', e.message, e.stack)
+    }
+    console.log('hello from', res.rows[0].name)
+  })
+})
+```
+
+### shut it down
+
+When you are finished with the pool if all the clients are idle the pool will close them after `config.idleTimeoutMillis` and your app
+will shutdown gracefully.  If you don't want to wait for the timeout you can end the pool as follows:
+
+```js
+var pool = new Pool()
+var client = await pool.connect()
+console.log(await client.query('select now()'))
+client.release()
+await pool.end()
+```
+
+### a note on instances
+
+The pool should be a __long-lived object__ in your application.  Generally you'll want to instantiate one pool when your app starts up and use the same instance of the pool throughout the lifetime of your application.  If you are frequently creating a new pool within your code you likely don't have your pool initialization code in the correct place.  Example:
+
+```js
+// assume this is a file in your program at ./your-app/lib/db.js
+
+// correct usage: create the pool and let it live
+// 'globally' here, controlling access to it through exported methods
+var pool = new pg.Pool()
+
+// this is the right way to export the query method
+module.exports.query = (text, values) => {
+  console.log('query:', text, values)
+  return pool.query(text, values)
+}
+
+// this would be the WRONG way to export the connect method
+module.exports.connect = () => {
+  // notice how we would be creating a pool instance here
+  // every time we called 'connect' to get a new client?
+  // that's a bad thing & results in creating an unbounded
+  // number of pools & therefore connections
+  var aPool = new pg.Pool()
+  return aPool.connect()
+}
+```
+
+### events
+
+Every instance of a `Pool` is an event emitter.  These instances emit the following events:
+
+#### error
+
+Emitted whenever an idle client in the pool encounters an error.  This is common when your PostgreSQL server shuts down, reboots, or a network partition otherwise causes it to become unavailable while your pool has connected clients.
+
+Example:
+
+```js
+const Pool = require('pg-pool')
+const pool = new Pool()
+
+// attach an error handler to the pool for when a connected, idle client
+// receives an error by being disconnected, etc
+pool.on('error', function(error, client) {
+  // handle this in the same way you would treat process.on('uncaughtException')
+  // it is supplied the error as well as the idle client which received the error
+})
+```
+
+#### connect
+
+Fired whenever the pool creates a __new__ `pg.Client` instance and successfully connects it to the backend.
+
+Example:
+
+```js
+const Pool = require('pg-pool')
+const pool = new Pool()
+
+var count = 0
+
+pool.on('connect', client => {
+  client.count = count++
+})
+
+pool
+  .connect()
+  .then(client => {
+    return client
+      .query('SELECT $1::int AS "clientCount"', [client.count])
+      .then(res => console.log(res.rows[0].clientCount)) // outputs 0
+      .then(() => client)
+  })
+  .then(client => client.release())
+
+```
+
+#### acquire
+
+Fired whenever the a client is acquired from the pool
+
+Example:
+
+This allows you to count the number of clients which have ever been acquired from the pool.
+
+```js
+var Pool = require('pg-pool')
+var pool = new Pool()
+
+var acquireCount = 0
+pool.on('acquire', function (client) {
+  acquireCount++
+})
+
+var connectCount = 0
+pool.on('connect', function () {
+  connectCount++
+})
+
+for (var i = 0; i < 200; i++) {
+  pool.query('SELECT NOW()')
+}
+
+setTimeout(function () {
+  console.log('connect count:', connectCount) // output: connect count: 10
+  console.log('acquire count:', acquireCount) // output: acquire count: 200
+}, 100)
+
+```
+
+### environment variables
+
+pg-pool & node-postgres support some of the same environment variables as `psql` supports.  The most common are:
+
+```
+PGDATABASE=my_db
+PGUSER=username
+PGPASSWORD="my awesome password"
+PGPORT=5432
+PGSSLMODE=require
+```
+
+Usually I will export these into my local environment via a `.env` file with environment settings or export them in `~/.bash_profile` or something similar.  This way I get configurability which works with both the postgres suite of tools (`psql`, `pg_dump`, `pg_restore`) and node, I can vary the environment variables locally and in production, and it supports the concept of a [12-factor app](http://12factor.net/) out of the box.
+
+## bring your own promise
+
+In versions of node `<=0.12.x` there is no native promise implementation available globally.  You can polyfill the promise globally like this:
+
+```js
+// first run `npm install promise-polyfill --save
+if (typeof Promise == 'undefined') {
+  global.Promise = require('promise-polyfill')
+}
+```
+
+You can use any other promise implementation you'd like.  The pool also allows you to configure the promise implementation on a per-pool level:
+
+```js
+var bluebirdPool = new Pool({
+  Promise: require('bluebird')
+})
+```
+
+__please note:__ in node `<=0.12.x` the pool will throw if you do not provide a promise constructor in one of the two ways mentioned above.  In node `>=4.0.0` the pool will use the native promise implementation by default; however, the two methods above still allow you to "bring your own."
+
+## tests
+
+To run tests clone the repo, `npm i` in the working dir, and then run `npm test`
+
+## contributions
+
+I love contributions.  Please make sure they have tests, and submit a PR.  If you're not sure if the issue is worth it or will be accepted it never hurts to open an issue to begin the conversation.  If you're interested in keeping up with node-postgres releated stuff, you can follow me on twitter at [@briancarlson](https://twitter.com/briancarlson) - I generally announce any noteworthy updates there.
+
+## license
+
+The MIT License (MIT)
+Copyright (c) 2016 Brian M. Carlson
+
+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.
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/index.js b/server/node_modules/pgtools/node_modules/pg-pool/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e0f0ce59a1c9a44a777693e8ffd8ef03fdef064
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/index.js
@@ -0,0 +1,174 @@
+var genericPool = require('generic-pool')
+var util = require('util')
+var EventEmitter = require('events').EventEmitter
+var objectAssign = require('object-assign')
+
+// there is a bug in the generic pool where it will not recreate
+// destroyed workers (even if there is waiting work to do) unless
+// there is a min specified. Make sure we keep some connections
+// SEE: https://github.com/coopernurse/node-pool/pull/186
+// SEE: https://github.com/brianc/node-pg-pool/issues/48
+// SEE: https://github.com/strongloop/loopback-connector-postgresql/issues/231
+function _ensureMinimum () {
+  var i, diff, waiting
+  if (this._draining) return
+  waiting = this._waitingClients.size()
+  if (this._factory.min > 0) { // we have positive specified minimum
+    diff = this._factory.min - this._count
+  } else if (waiting > 0) { // we have no minimum, but we do have work to do
+    diff = Math.min(waiting, this._factory.max - this._count)
+  }
+  for (i = 0; i < diff; i++) {
+    this._createResource()
+  }
+};
+
+var Pool = module.exports = function (options, Client) {
+  if (!(this instanceof Pool)) {
+    return new Pool(options, Client)
+  }
+  EventEmitter.call(this)
+  this.options = objectAssign({}, options)
+  this.log = this.options.log || function () { }
+  this.Client = this.options.Client || Client || require('pg').Client
+  this.Promise = this.options.Promise || global.Promise
+
+  this.options.max = this.options.max || this.options.poolSize || 10
+  this.options.create = this.options.create || this._create.bind(this)
+  this.options.destroy = this.options.destroy || this._destroy.bind(this)
+  this.pool = new genericPool.Pool(this.options)
+  // Monkey patch to ensure we always finish our work
+  //  - There is a bug where callbacks go uncalled if min is not set
+  //  - We might still not want a connection to *always* exist
+  //  - but we do want to create up to max connections if we have work
+  //  - still waiting
+  // This should be safe till the version of pg-pool is upgraded
+  // SEE: https://github.com/coopernurse/node-pool/pull/186
+  this.pool._ensureMinimum = _ensureMinimum
+  this.onCreate = this.options.onCreate
+}
+
+util.inherits(Pool, EventEmitter)
+
+Pool.prototype._promise = function (cb, executor) {
+  if (!cb) {
+    return new this.Promise(executor)
+  }
+
+  function resolved (value) {
+    process.nextTick(function () {
+      cb(null, value)
+    })
+  }
+
+  function rejected (error) {
+    process.nextTick(function () {
+      cb(error)
+    })
+  }
+
+  executor(resolved, rejected)
+}
+
+Pool.prototype._promiseNoCallback = function (callback, executor) {
+  return callback
+    ? executor()
+    : new this.Promise(executor)
+}
+
+Pool.prototype._destroy = function (client) {
+  if (client._destroying) return
+  client._destroying = true
+  client.end()
+}
+
+Pool.prototype._create = function (cb) {
+  this.log('connecting new client')
+  var client = new this.Client(this.options)
+
+  client.on('error', function (e) {
+    this.log('connected client error:', e)
+    this.pool.destroy(client)
+    e.client = client
+    this.emit('error', e, client)
+  }.bind(this))
+
+  client.connect(function (err) {
+    if (err) {
+      this.log('client connection error:', err)
+      cb(err, null)
+    } else {
+      this.log('client connected')
+      this.emit('connect', client)
+      cb(null, client)
+    }
+  }.bind(this))
+}
+
+Pool.prototype.connect = function (cb) {
+  return this._promiseNoCallback(cb, function (resolve, reject) {
+    this.log('acquire client begin')
+    this.pool.acquire(function (err, client) {
+      if (err) {
+        this.log('acquire client. error:', err)
+        if (cb) {
+          cb(err, null, function () {})
+        } else {
+          reject(err)
+        }
+        return
+      }
+
+      this.log('acquire client')
+      this.emit('acquire', client)
+
+      client.release = function (err) {
+        delete client.release
+        if (err) {
+          this.log('destroy client. error:', err)
+          this.pool.destroy(client)
+        } else {
+          this.log('release client')
+          this.pool.release(client)
+        }
+      }.bind(this)
+
+      if (cb) {
+        cb(null, client, client.release)
+      } else {
+        resolve(client)
+      }
+    }.bind(this))
+  }.bind(this))
+}
+
+Pool.prototype.take = Pool.prototype.connect
+
+Pool.prototype.query = function (text, values, cb) {
+  if (typeof values === 'function') {
+    cb = values
+    values = undefined
+  }
+
+  return this._promise(cb, function (resolve, reject) {
+    this.connect(function (err, client, done) {
+      if (err) {
+        return reject(err)
+      }
+      client.query(text, values, function (err, res) {
+        done(err)
+        err ? reject(err) : resolve(res)
+      })
+    })
+  }.bind(this))
+}
+
+Pool.prototype.end = function (cb) {
+  this.log('draining pool')
+  return this._promise(cb, function (resolve, reject) {
+    this.pool.drain(function () {
+      this.log('pool drained, calling destroy all now')
+      this.pool.destroyAllNow(resolve)
+    }.bind(this))
+  }.bind(this))
+}
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/package.json b/server/node_modules/pgtools/node_modules/pg-pool/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..76a958ef6ec6943213b04bd350d3d4089ac0bebf
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/package.json
@@ -0,0 +1,68 @@
+{
+  "_from": "pg-pool@1.*",
+  "_id": "pg-pool@1.8.0",
+  "_inBundle": false,
+  "_integrity": "sha1-9+xzgkw3oD8Hb1G/33DjQBR8Tzc=",
+  "_location": "/pgtools/pg-pool",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "pg-pool@1.*",
+    "name": "pg-pool",
+    "escapedName": "pg-pool",
+    "rawSpec": "1.*",
+    "saveSpec": null,
+    "fetchSpec": "1.*"
+  },
+  "_requiredBy": [
+    "/pgtools/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-1.8.0.tgz",
+  "_shasum": "f7ec73824c37a03f076f51bfdf70e340147c4f37",
+  "_spec": "pg-pool@1.*",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgtools/node_modules/pg",
+  "author": {
+    "name": "Brian M. Carlson"
+  },
+  "bugs": {
+    "url": "https://github.com/brianc/node-pg-pool/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "generic-pool": "2.4.3",
+    "object-assign": "4.1.0"
+  },
+  "deprecated": false,
+  "description": "Connection pool for node-postgres",
+  "devDependencies": {
+    "bluebird": "3.4.1",
+    "expect.js": "0.3.1",
+    "lodash": "4.13.1",
+    "mocha": "^2.3.3",
+    "pg": "5.1.0",
+    "standard": "7.1.2",
+    "standard-format": "2.2.1"
+  },
+  "directories": {
+    "test": "test"
+  },
+  "homepage": "https://github.com/brianc/node-pg-pool#readme",
+  "keywords": [
+    "pg",
+    "postgres",
+    "pool",
+    "database"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "pg-pool",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianc/node-pg-pool.git"
+  },
+  "scripts": {
+    "test": "standard && node_modules/.bin/mocha"
+  },
+  "version": "1.8.0"
+}
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/test/connection-strings.js b/server/node_modules/pgtools/node_modules/pg-pool/test/connection-strings.js
new file mode 100644
index 0000000000000000000000000000000000000000..8ee3d074ba518d93aec72d5c89d3936ac5537847
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/test/connection-strings.js
@@ -0,0 +1,30 @@
+var expect = require('expect.js')
+var describe = require('mocha').describe
+var it = require('mocha').it
+var Pool = require('../')
+
+describe('Connection strings', function () {
+  it('pool delegates connectionString property to client', function (done) {
+    var connectionString = 'postgres://foo:bar@baz:1234/xur'
+
+    var pool = new Pool({
+      // use a fake client so we can check we're passed the connectionString
+      Client: function (args) {
+        expect(args.connectionString).to.equal(connectionString)
+        return {
+          connect: function (cb) {
+            cb(new Error('testing'))
+          },
+          on: function () { }
+        }
+      },
+      connectionString: connectionString
+    })
+
+    pool.connect(function (err, client) {
+      expect(err).to.not.be(undefined)
+      done()
+    })
+  })
+})
+
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/test/events.js b/server/node_modules/pgtools/node_modules/pg-pool/test/events.js
new file mode 100644
index 0000000000000000000000000000000000000000..759dff02dae1b2451c9864fedce8a59e79af8caa
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/test/events.js
@@ -0,0 +1,87 @@
+var expect = require('expect.js')
+var EventEmitter = require('events').EventEmitter
+var describe = require('mocha').describe
+var it = require('mocha').it
+var objectAssign = require('object-assign')
+var Pool = require('../')
+
+describe('events', function () {
+  it('emits connect before callback', function (done) {
+    var pool = new Pool()
+    var emittedClient = false
+    pool.on('connect', function (client) {
+      emittedClient = client
+    })
+
+    pool.connect(function (err, client, release) {
+      if (err) return done(err)
+      release()
+      pool.end()
+      expect(client).to.be(emittedClient)
+      done()
+    })
+  })
+
+  it('emits "connect" only with a successful connection', function (done) {
+    var pool = new Pool({
+      // This client will always fail to connect
+      Client: mockClient({
+        connect: function (cb) {
+          process.nextTick(function () { cb(new Error('bad news')) })
+        }
+      })
+    })
+    pool.on('connect', function () {
+      throw new Error('should never get here')
+    })
+    pool._create(function (err) {
+      if (err) done()
+      else done(new Error('expected failure'))
+    })
+  })
+
+  it('emits acquire every time a client is acquired', function (done) {
+    var pool = new Pool()
+    var acquireCount = 0
+    pool.on('acquire', function (client) {
+      expect(client).to.be.ok()
+      acquireCount++
+    })
+    for (var i = 0; i < 10; i++) {
+      pool.connect(function (err, client, release) {
+        err ? done(err) : release()
+        release()
+        if (err) return done(err)
+      })
+      pool.query('SELECT now()')
+    }
+    setTimeout(function () {
+      expect(acquireCount).to.be(20)
+      pool.end(done)
+    }, 40)
+  })
+
+  it('emits error and client if an idle client in the pool hits an error', function (done) {
+    var pool = new Pool()
+    pool.connect(function (err, client) {
+      expect(err).to.equal(null)
+      client.release()
+      setImmediate(function () {
+        client.emit('error', new Error('problem'))
+      })
+      pool.once('error', function (err, errClient) {
+        expect(err.message).to.equal('problem')
+        expect(errClient).to.equal(client)
+        done()
+      })
+    })
+  })
+})
+
+function mockClient (methods) {
+  return function () {
+    var client = new EventEmitter()
+    objectAssign(client, methods)
+    return client
+  }
+}
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/test/index.js b/server/node_modules/pgtools/node_modules/pg-pool/test/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..3f2b99d95b7a7d7b1cccdc5bfb9571095ee3b3e0
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/test/index.js
@@ -0,0 +1,232 @@
+var expect = require('expect.js')
+var _ = require('lodash')
+
+var describe = require('mocha').describe
+var it = require('mocha').it
+var Promise = require('bluebird')
+
+var Pool = require('../')
+
+if (typeof global.Promise === 'undefined') {
+  global.Promise = Promise
+}
+
+describe('pool', function () {
+  it('can be used as a factory function', function () {
+    var pool = Pool()
+    expect(pool instanceof Pool).to.be.ok()
+    expect(typeof pool.connect).to.be('function')
+  })
+
+  describe('with callbacks', function () {
+    it('works totally unconfigured', function (done) {
+      var pool = new Pool()
+      pool.connect(function (err, client, release) {
+        if (err) return done(err)
+        client.query('SELECT NOW()', function (err, res) {
+          release()
+          if (err) return done(err)
+          expect(res.rows).to.have.length(1)
+          pool.end(done)
+        })
+      })
+    })
+
+    it('passes props to clients', function (done) {
+      var pool = new Pool({ binary: true })
+      pool.connect(function (err, client, release) {
+        release()
+        if (err) return done(err)
+        expect(client.binary).to.eql(true)
+        pool.end(done)
+      })
+    })
+
+    it('can run a query with a callback without parameters', function (done) {
+      var pool = new Pool()
+      pool.query('SELECT 1 as num', function (err, res) {
+        expect(res.rows[0]).to.eql({ num: 1 })
+        pool.end(function () {
+          done(err)
+        })
+      })
+    })
+
+    it('can run a query with a callback', function (done) {
+      var pool = new Pool()
+      pool.query('SELECT $1::text as name', ['brianc'], function (err, res) {
+        expect(res.rows[0]).to.eql({ name: 'brianc' })
+        pool.end(function () {
+          done(err)
+        })
+      })
+    })
+
+    it('passes connection errors to callback', function (done) {
+      var pool = new Pool({host: 'no-postgres-server-here.com'})
+      pool.query('SELECT $1::text as name', ['brianc'], function (err, res) {
+        expect(res).to.be(undefined)
+        expect(err).to.be.an(Error)
+        pool.end(function (err) {
+          done(err)
+        })
+      })
+    })
+
+    it('removes client if it errors in background', function (done) {
+      var pool = new Pool()
+      pool.connect(function (err, client, release) {
+        release()
+        if (err) return done(err)
+        client.testString = 'foo'
+        setTimeout(function () {
+          client.emit('error', new Error('on purpose'))
+        }, 10)
+      })
+      pool.on('error', function (err) {
+        expect(err.message).to.be('on purpose')
+        expect(err.client).to.not.be(undefined)
+        expect(err.client.testString).to.be('foo')
+        err.client.connection.stream.on('end', function () {
+          pool.end(done)
+        })
+      })
+    })
+
+    it('should not change given options', function (done) {
+      var options = { max: 10 }
+      var pool = new Pool(options)
+      pool.connect(function (err, client, release) {
+        release()
+        if (err) return done(err)
+        expect(options).to.eql({ max: 10 })
+        pool.end(done)
+      })
+    })
+
+    it('does not create promises when connecting', function (done) {
+      var pool = new Pool()
+      var returnValue = pool.connect(function (err, client, release) {
+        release()
+        if (err) return done(err)
+        pool.end(done)
+      })
+      expect(returnValue).to.be(undefined)
+    })
+
+    it('does not create promises when querying', function (done) {
+      var pool = new Pool()
+      var returnValue = pool.query('SELECT 1 as num', function (err) {
+        pool.end(function () {
+          done(err)
+        })
+      })
+      expect(returnValue).to.be(undefined)
+    })
+
+    it('does not create promises when ending', function (done) {
+      var pool = new Pool()
+      var returnValue = pool.end(done)
+      expect(returnValue).to.be(undefined)
+    })
+  })
+
+  describe('with promises', function () {
+    it('connects and disconnects', function () {
+      var pool = new Pool()
+      return pool.connect().then(function (client) {
+        expect(pool.pool.availableObjectsCount()).to.be(0)
+        return client.query('select $1::text as name', ['hi']).then(function (res) {
+          expect(res.rows).to.eql([{ name: 'hi' }])
+          client.release()
+          expect(pool.pool.getPoolSize()).to.be(1)
+          expect(pool.pool.availableObjectsCount()).to.be(1)
+          return pool.end()
+        })
+      })
+    })
+
+    it('properly pools clients', function () {
+      var pool = new Pool({ poolSize: 9 })
+      return Promise.map(_.times(30), function () {
+        return pool.connect().then(function (client) {
+          return client.query('select $1::text as name', ['hi']).then(function (res) {
+            client.release()
+            return res
+          })
+        })
+      }).then(function (res) {
+        expect(res).to.have.length(30)
+        expect(pool.pool.getPoolSize()).to.be(9)
+        return pool.end()
+      })
+    })
+
+    it('supports just running queries', function () {
+      var pool = new Pool({ poolSize: 9 })
+      return Promise.map(_.times(30), function () {
+        return pool.query('SELECT $1::text as name', ['hi'])
+      }).then(function (queries) {
+        expect(queries).to.have.length(30)
+        expect(pool.pool.getPoolSize()).to.be(9)
+        expect(pool.pool.availableObjectsCount()).to.be(9)
+        return pool.end()
+      })
+    })
+
+    it('recovers from all errors', function () {
+      var pool = new Pool()
+
+      var errors = []
+      return Promise.mapSeries(_.times(30), function () {
+        return pool.query('SELECT asldkfjasldkf')
+          .catch(function (e) {
+            errors.push(e)
+          })
+      }).then(function () {
+        return pool.query('SELECT $1::text as name', ['hi']).then(function (res) {
+          expect(errors).to.have.length(30)
+          expect(res.rows).to.eql([{ name: 'hi' }])
+          return pool.end()
+        })
+      })
+    })
+  })
+})
+
+describe('pool error handling', function () {
+  it('Should complete these queries without dying', function (done) {
+    var pgPool = new Pool()
+    var pool = pgPool.pool
+    pool._factory.max = 1
+    pool._factory.min = null
+    var errors = 0
+    var shouldGet = 0
+    function runErrorQuery () {
+      shouldGet++
+      return new Promise(function (resolve, reject) {
+        pgPool.query("SELECT 'asd'+1 ").then(function (res) {
+          reject(res) // this should always error
+        }).catch(function (err) {
+          errors++
+          resolve(err)
+        })
+      })
+    }
+    var ps = []
+    for (var i = 0; i < 5; i++) {
+      ps.push(runErrorQuery())
+    }
+    Promise.all(ps).then(function () {
+      expect(shouldGet).to.eql(errors)
+      done()
+    })
+  })
+})
+
+process.on('unhandledRejection', function (e) {
+  console.error(e.message, e.stack)
+  setImmediate(function () {
+    throw e
+  })
+})
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/test/logging.js b/server/node_modules/pgtools/node_modules/pg-pool/test/logging.js
new file mode 100644
index 0000000000000000000000000000000000000000..47389a5aa36e010398e10c0a192ce96666801a33
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/test/logging.js
@@ -0,0 +1,20 @@
+var expect = require('expect.js')
+
+var describe = require('mocha').describe
+var it = require('mocha').it
+
+var Pool = require('../')
+
+describe('logging', function () {
+  it('logs to supplied log function if given', function () {
+    var messages = []
+    var log = function (msg) {
+      messages.push(msg)
+    }
+    var pool = new Pool({ log: log })
+    return pool.query('SELECT NOW()').then(function () {
+      expect(messages.length).to.be.greaterThan(0)
+      return pool.end()
+    })
+  })
+})
diff --git a/server/node_modules/pgtools/node_modules/pg-pool/test/mocha.opts b/server/node_modules/pgtools/node_modules/pg-pool/test/mocha.opts
new file mode 100644
index 0000000000000000000000000000000000000000..46e8e69d92ba1b57ee7a6520dd45e67ddf86e63b
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-pool/test/mocha.opts
@@ -0,0 +1,2 @@
+--no-exit
+--bail
diff --git a/server/node_modules/pgtools/node_modules/pg-types/.travis.yml b/server/node_modules/pgtools/node_modules/pg-types/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d569fd576e061874d2be75e209de5d719a8eaf34
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-types/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+  - '0.12'
+  - '4'
+  - 'node'
+env:
+  - PGUSER=postgres
diff --git a/server/node_modules/pgtools/node_modules/pg-types/Makefile b/server/node_modules/pgtools/node_modules/pg-types/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d7ec83d549a9b4dc8c4815471b3323c4995eaaa2
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-types/Makefile
@@ -0,0 +1,14 @@
+.PHONY: publish-patch test
+
+test:
+	npm test
+
+patch: test
+	npm version patch -m "Bump version"
+	git push origin master --tags
+	npm publish
+
+minor: test
+	npm version minor -m "Bump version"
+	git push origin master --tags
+	npm publish
diff --git a/server/node_modules/pgtools/node_modules/pg-types/README.md b/server/node_modules/pgtools/node_modules/pg-types/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..80c7a6d4f5aa2ae3ff6f5ac1e11471e88d7185b0
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-types/README.md
@@ -0,0 +1,77 @@
+# pg-types
+
+This is the code that turns all the raw text from postgres into JavaScript types for [node-postgres](https://github.com/brianc/node-postgres.git)
+
+## use
+
+This module is consumed and exported from the root `pg` object of node-postgres.  To access it, do the following:
+
+```js
+var types = require('pg').types
+```
+
+Generally what you'll want to do is override how a specific data-type is parsed and turned into a JavaScript type.  By default the PostgreSQL backend server returns everything as strings.  Every data type corresponds to a unique `OID` within the server, and these `OIDs` are sent back with the query response.  So, you need to match a particluar `OID` to a function you'd like to use to take the raw text input and produce a valid JavaScript object as a result. `null` values are never parsed.
+
+Let's do something I commonly like to do on projects: return 64-bit integers `(int8)` as JavaScript integers.  Because JavaScript doesn't have support for 64-bit integers node-postgres cannot confidently parse `int8` data type results as numbers because if you have a _huge_ number it will overflow and the result you'd get back from node-postgres would not be the result in the datbase.  That would be a __very bad thing__ so node-postgres just returns `int8` results as strings and leaves the parsing up to you.  Let's say that you know you don't and wont ever have numbers greater than `int4` in your database, but you're tired of recieving results from the `COUNT(*)` function as strings (because that function returns `int8`).  You would do this:
+
+```js
+var types = require('pg').types
+types.setTypeParser(20, function(val) {
+  return parseInt(val)
+})
+```
+
+__boom__: now you get numbers instead of strings.
+
+Just as another example -- not saying this is a good idea -- let's say you want to return all dates from your database as [moment](http://momentjs.com/docs/) objects.  Okay, do this:
+
+```js
+var types = require('pg').types
+var moment = require('moment')
+var TIMESTAMPTZ_OID = 1184
+var TIMESTAMP_OID = 1114
+var parseFn = function(val) {
+   return val === null ? null : moment(val)
+}
+types.setTypeParser(TIMESTAMPTZ_OID, parseFn)
+types.setTypeParser(TIMESTAMP_OID, parseFn)
+```
+_note: I've never done that with my dates, and I'm not 100% sure moment can parse all the date strings returned from postgres.  It's just an example!_
+
+If you're thinking "gee, this seems pretty handy, but how can I get a list of all the OIDs in the database and what they correspond to?!?!?!" worry not:
+
+```bash
+$ psql -c "select typname, oid, typarray from pg_type order by oid"
+```
+
+If you want to find out the OID of a specific type:
+
+```bash
+$ psql -c "select typname, oid, typarray from pg_type where typname = 'daterange' order by oid"
+```
+
+:smile:
+
+## license
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Brian M. Carlson
+
+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.
diff --git a/server/node_modules/pgtools/node_modules/pg-types/index.js b/server/node_modules/pgtools/node_modules/pg-types/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..d820cfec8a9de3ce46919a40aa8665d212fe2b51
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-types/index.js
@@ -0,0 +1,45 @@
+var textParsers = require('./lib/textParsers');
+var binaryParsers = require('./lib/binaryParsers');
+var arrayParser = require('./lib/arrayParser');
+
+exports.getTypeParser = getTypeParser;
+exports.setTypeParser = setTypeParser;
+exports.arrayParser = arrayParser;
+
+var typeParsers = {
+  text: {},
+  binary: {}
+};
+
+//the empty parse function
+function noParse (val) {
+  return String(val);
+};
+
+//returns a function used to convert a specific type (specified by
+//oid) into a result javascript type
+//note: the oid can be obtained via the following sql query:
+//SELECT oid FROM pg_type WHERE typname = 'TYPE_NAME_HERE';
+function getTypeParser (oid, format) {
+  format = format || 'text';
+  if (!typeParsers[format]) {
+    return noParse;
+  }
+  return typeParsers[format][oid] || noParse;
+};
+
+function setTypeParser (oid, format, parseFn) {
+  if(typeof format == 'function') {
+    parseFn = format;
+    format = 'text';
+  }
+  typeParsers[format][oid] = parseFn;
+};
+
+textParsers.init(function(oid, converter) {
+  typeParsers.text[oid] = converter;
+});
+
+binaryParsers.init(function(oid, converter) {
+  typeParsers.binary[oid] = converter;
+});
diff --git a/server/node_modules/pgtools/node_modules/pg-types/lib/arrayParser.js b/server/node_modules/pgtools/node_modules/pg-types/lib/arrayParser.js
new file mode 100644
index 0000000000000000000000000000000000000000..81ccffbc85659d2a101f624b7e3ec220c00ecbaa
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-types/lib/arrayParser.js
@@ -0,0 +1,11 @@
+var array = require('postgres-array');
+
+module.exports = {
+  create: function (source, transform) {
+    return {
+      parse: function() {
+        return array.parse(source, transform);
+      }
+    };
+  }
+};
diff --git a/server/node_modules/pgtools/node_modules/pg-types/lib/binaryParsers.js b/server/node_modules/pgtools/node_modules/pg-types/lib/binaryParsers.js
new file mode 100644
index 0000000000000000000000000000000000000000..e12c2f46365148c3e50646ce41264124c4c756d1
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-types/lib/binaryParsers.js
@@ -0,0 +1,257 @@
+var parseInt64 = require('pg-int8');
+
+var parseBits = function(data, bits, offset, invert, callback) {
+  offset = offset || 0;
+  invert = invert || false;
+  callback = callback || function(lastValue, newValue, bits) { return (lastValue * Math.pow(2, bits)) + newValue; };
+  var offsetBytes = offset >> 3;
+
+  var inv = function(value) {
+    if (invert) {
+      return ~value & 0xff;
+    }
+
+    return value;
+  };
+
+  // read first (maybe partial) byte
+  var mask = 0xff;
+  var firstBits = 8 - (offset % 8);
+  if (bits < firstBits) {
+    mask = (0xff << (8 - bits)) & 0xff;
+    firstBits = bits;
+  }
+
+  if (offset) {
+    mask = mask >> (offset % 8);
+  }
+
+  var result = 0;
+  if ((offset % 8) + bits >= 8) {
+    result = callback(0, inv(data[offsetBytes]) & mask, firstBits);
+  }
+
+  // read bytes
+  var bytes = (bits + offset) >> 3;
+  for (var i = offsetBytes + 1; i < bytes; i++) {
+    result = callback(result, inv(data[i]), 8);
+  }
+
+  // bits to read, that are not a complete byte
+  var lastBits = (bits + offset) % 8;
+  if (lastBits > 0) {
+    result = callback(result, inv(data[bytes]) >> (8 - lastBits), lastBits);
+  }
+
+  return result;
+};
+
+var parseFloatFromBits = function(data, precisionBits, exponentBits) {
+  var bias = Math.pow(2, exponentBits - 1) - 1;
+  var sign = parseBits(data, 1);
+  var exponent = parseBits(data, exponentBits, 1);
+
+  if (exponent === 0) {
+    return 0;
+  }
+
+  // parse mantissa
+  var precisionBitsCounter = 1;
+  var parsePrecisionBits = function(lastValue, newValue, bits) {
+    if (lastValue === 0) {
+      lastValue = 1;
+    }
+
+    for (var i = 1; i <= bits; i++) {
+      precisionBitsCounter /= 2;
+      if ((newValue & (0x1 << (bits - i))) > 0) {
+        lastValue += precisionBitsCounter;
+      }
+    }
+
+    return lastValue;
+  };
+
+  var mantissa = parseBits(data, precisionBits, exponentBits + 1, false, parsePrecisionBits);
+
+  // special cases
+  if (exponent == (Math.pow(2, exponentBits + 1) - 1)) {
+    if (mantissa === 0) {
+      return (sign === 0) ? Infinity : -Infinity;
+    }
+
+    return NaN;
+  }
+
+  // normale number
+  return ((sign === 0) ? 1 : -1) * Math.pow(2, exponent - bias) * mantissa;
+};
+
+var parseInt16 = function(value) {
+  if (parseBits(value, 1) == 1) {
+    return -1 * (parseBits(value, 15, 1, true) + 1);
+  }
+
+  return parseBits(value, 15, 1);
+};
+
+var parseInt32 = function(value) {
+  if (parseBits(value, 1) == 1) {
+    return -1 * (parseBits(value, 31, 1, true) + 1);
+  }
+
+  return parseBits(value, 31, 1);
+};
+
+var parseFloat32 = function(value) {
+  return parseFloatFromBits(value, 23, 8);
+};
+
+var parseFloat64 = function(value) {
+  return parseFloatFromBits(value, 52, 11);
+};
+
+var parseNumeric = function(value) {
+  var sign = parseBits(value, 16, 32);
+  if (sign == 0xc000) {
+    return NaN;
+  }
+
+  var weight = Math.pow(10000, parseBits(value, 16, 16));
+  var result = 0;
+
+  var digits = [];
+  var ndigits = parseBits(value, 16);
+  for (var i = 0; i < ndigits; i++) {
+    result += parseBits(value, 16, 64 + (16 * i)) * weight;
+    weight /= 10000;
+  }
+
+  var scale = Math.pow(10, parseBits(value, 16, 48));
+  return ((sign === 0) ? 1 : -1) * Math.round(result * scale) / scale;
+};
+
+var parseDate = function(isUTC, value) {
+  var sign = parseBits(value, 1);
+  var rawValue = parseBits(value, 63, 1);
+
+  // discard usecs and shift from 2000 to 1970
+  var result = new Date((((sign === 0) ? 1 : -1) * rawValue / 1000) + 946684800000);
+
+  if (!isUTC) {
+    result.setTime(result.getTime() + result.getTimezoneOffset() * 60000);
+  }
+
+  // add microseconds to the date
+  result.usec = rawValue % 1000;
+  result.getMicroSeconds = function() {
+    return this.usec;
+  };
+  result.setMicroSeconds = function(value) {
+    this.usec = value;
+  };
+  result.getUTCMicroSeconds = function() {
+    return this.usec;
+  };
+
+  return result;
+};
+
+var parseArray = function(value) {
+  var dim = parseBits(value, 32);
+
+  var flags = parseBits(value, 32, 32);
+  var elementType = parseBits(value, 32, 64);
+
+  var offset = 96;
+  var dims = [];
+  for (var i = 0; i < dim; i++) {
+    // parse dimension
+    dims[i] = parseBits(value, 32, offset);
+    offset += 32;
+
+    // ignore lower bounds
+    offset += 32;
+  }
+
+  var parseElement = function(elementType) {
+    // parse content length
+    var length = parseBits(value, 32, offset);
+    offset += 32;
+
+    // parse null values
+    if (length == 0xffffffff) {
+      return null;
+    }
+
+    var result;
+    if ((elementType == 0x17) || (elementType == 0x14)) {
+      // int/bigint
+      result = parseBits(value, length * 8, offset);
+      offset += length * 8;
+      return result;
+    }
+    else if (elementType == 0x19) {
+      // string
+      result = value.toString(this.encoding, offset >> 3, (offset += (length << 3)) >> 3);
+      return result;
+    }
+    else {
+      console.log("ERROR: ElementType not implemented: " + elementType);
+    }
+  };
+
+  var parse = function(dimension, elementType) {
+    var array = [];
+    var i;
+
+    if (dimension.length > 1) {
+      var count = dimension.shift();
+      for (i = 0; i < count; i++) {
+        array[i] = parse(dimension, elementType);
+      }
+      dimension.unshift(count);
+    }
+    else {
+      for (i = 0; i < dimension[0]; i++) {
+        array[i] = parseElement(elementType);
+      }
+    }
+
+    return array;
+  };
+
+  return parse(dims, elementType);
+};
+
+var parseText = function(value) {
+  return value.toString('utf8');
+};
+
+var parseBool = function(value) {
+  if(value === null) return null;
+  return (parseBits(value, 8) > 0);
+};
+
+var init = function(register) {
+  register(20, parseInt64);
+  register(21, parseInt16);
+  register(23, parseInt32);
+  register(26, parseInt32);
+  register(1700, parseNumeric);
+  register(700, parseFloat32);
+  register(701, parseFloat64);
+  register(16, parseBool);
+  register(1114, parseDate.bind(null, false));
+  register(1184, parseDate.bind(null, true));
+  register(1000, parseArray);
+  register(1007, parseArray);
+  register(1016, parseArray);
+  register(1008, parseArray);
+  register(1009, parseArray);
+  register(25, parseText);
+};
+
+module.exports = {
+  init: init
+};
diff --git a/server/node_modules/pgtools/node_modules/pg-types/lib/textParsers.js b/server/node_modules/pgtools/node_modules/pg-types/lib/textParsers.js
new file mode 100644
index 0000000000000000000000000000000000000000..9a881e52449d5633ee83c5a2194cdb23c15c7265
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-types/lib/textParsers.js
@@ -0,0 +1,205 @@
+var array = require('postgres-array')
+var arrayParser = require('./arrayParser');
+var parseDate = require('postgres-date');
+var parseInterval = require('postgres-interval');
+var parseByteA = require('postgres-bytea');
+
+function allowNull (fn) {
+  return function nullAllowed (value) {
+    if (value === null) return value
+    return fn(value)
+  }
+}
+
+function parseBool (value) {
+  if (value === null) return value
+  return value === 'TRUE' ||
+    value === 't' ||
+    value === 'true' ||
+    value === 'y' ||
+    value === 'yes' ||
+    value === 'on' ||
+    value === '1';
+}
+
+function parseBoolArray (value) {
+  if (!value) return null
+  return array.parse(value, parseBool)
+}
+
+function parseBaseTenInt (string) {
+  return parseInt(string, 10)
+}
+
+function parseIntegerArray (value) {
+  if (!value) return null
+  return array.parse(value, allowNull(parseBaseTenInt))
+}
+
+function parseBigIntegerArray (value) {
+  if (!value) return null
+  return array.parse(value, allowNull(function (entry) {
+    return parseBigInteger(entry).trim()
+  }))
+}
+
+var parsePointArray = function(value) {
+  if(!value) { return null; }
+  var p = arrayParser.create(value, function(entry) {
+    if(entry !== null) {
+      entry = parsePoint(entry);
+    }
+    return entry;
+  });
+
+  return p.parse();
+};
+
+var parseFloatArray = function(value) {
+  if(!value) { return null; }
+  var p = arrayParser.create(value, function(entry) {
+    if(entry !== null) {
+      entry = parseFloat(entry);
+    }
+    return entry;
+  });
+
+  return p.parse();
+};
+
+var parseStringArray = function(value) {
+  if(!value) { return null; }
+
+  var p = arrayParser.create(value);
+  return p.parse();
+};
+
+var parseDateArray = function(value) {
+  if (!value) { return null; }
+
+  var p = arrayParser.create(value, function(entry) {
+    if (entry !== null) {
+      entry = parseDate(entry);
+    }
+    return entry;
+  });
+
+  return p.parse();
+};
+
+var parseByteAArray = function(value) {
+  if (!value) { return null; }
+
+  return array.parse(value, allowNull(parseByteA));
+};
+
+var parseInteger = function(value) {
+  return parseInt(value, 10);
+};
+
+var parseBigInteger = function(value) {
+  var valStr = String(value);
+  if (/^\d+$/.test(valStr)) { return valStr; }
+  return value;
+};
+
+var parseJsonArray = function(value) {
+  var arr = parseStringArray(value);
+
+  if (!arr) {
+    return arr;
+  }
+
+  return arr.map(function(el) { return JSON.parse(el); });
+};
+
+var parsePoint = function(value) {
+  if (value[0] !== '(') { return null; }
+
+  value = value.substring( 1, value.length - 1 ).split(',');
+
+  return {
+    x: parseFloat(value[0])
+  , y: parseFloat(value[1])
+  };
+};
+
+var parseCircle = function(value) {
+  if (value[0] !== '<' && value[1] !== '(') { return null; }
+
+  var point = '(';
+  var radius = '';
+  var pointParsed = false;
+  for (var i = 2; i < value.length - 1; i++){
+    if (!pointParsed) {
+      point += value[i];
+    }
+
+    if (value[i] === ')') {
+      pointParsed = true;
+      continue;
+    } else if (!pointParsed) {
+      continue;
+    }
+
+    if (value[i] === ','){
+      continue;
+    }
+
+    radius += value[i];
+  }
+  var result = parsePoint(point);
+  result.radius = parseFloat(radius);
+
+  return result;
+};
+
+var init = function(register) {
+  register(20, parseBigInteger); // int8
+  register(21, parseInteger); // int2
+  register(23, parseInteger); // int4
+  register(26, parseInteger); // oid
+  register(700, parseFloat); // float4/real
+  register(701, parseFloat); // float8/double
+  register(16, parseBool);
+  register(1082, parseDate); // date
+  register(1114, parseDate); // timestamp without timezone
+  register(1184, parseDate); // timestamp
+  register(600, parsePoint); // point
+  register(651, parseStringArray); // cidr[]
+  register(718, parseCircle); // circle
+  register(1000, parseBoolArray);
+  register(1001, parseByteAArray);
+  register(1005, parseIntegerArray); // _int2
+  register(1007, parseIntegerArray); // _int4
+  register(1028, parseIntegerArray); // oid[]
+  register(1016, parseBigIntegerArray); // _int8
+  register(1017, parsePointArray); // point[]
+  register(1021, parseFloatArray); // _float4
+  register(1022, parseFloatArray); // _float8
+  register(1231, parseFloatArray); // _numeric
+  register(1014, parseStringArray); //char
+  register(1015, parseStringArray); //varchar
+  register(1008, parseStringArray);
+  register(1009, parseStringArray);
+  register(1040, parseStringArray); // macaddr[]
+  register(1041, parseStringArray); // inet[]
+  register(1115, parseDateArray); // timestamp without time zone[]
+  register(1182, parseDateArray); // _date
+  register(1185, parseDateArray); // timestamp with time zone[]
+  register(1186, parseInterval);
+  register(17, parseByteA);
+  register(114, JSON.parse.bind(JSON)); // json
+  register(3802, JSON.parse.bind(JSON)); // jsonb
+  register(199, parseJsonArray); // json[]
+  register(3807, parseJsonArray); // jsonb[]
+  register(3907, parseStringArray); // numrange[]
+  register(2951, parseStringArray); // uuid[]
+  register(791, parseStringArray); // money[]
+  register(1183, parseStringArray); // time[]
+  register(1270, parseStringArray); // timetz[]
+};
+
+module.exports = {
+  init: init
+};
diff --git a/server/node_modules/pgtools/node_modules/pg-types/package.json b/server/node_modules/pgtools/node_modules/pg-types/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..89b4bbc969944884b4395040a0f133aed9838b06
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-types/package.json
@@ -0,0 +1,63 @@
+{
+  "_from": "pg-types@1.*",
+  "_id": "pg-types@1.13.0",
+  "_inBundle": false,
+  "_integrity": "sha512-lfKli0Gkl/+za/+b6lzENajczwZHc7D5kiUCZfgm914jipD2kIOIvEkAhZ8GrW3/TUoP9w8FHjwpPObBye5KQQ==",
+  "_location": "/pgtools/pg-types",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "pg-types@1.*",
+    "name": "pg-types",
+    "escapedName": "pg-types",
+    "rawSpec": "1.*",
+    "saveSpec": null,
+    "fetchSpec": "1.*"
+  },
+  "_requiredBy": [
+    "/pgtools/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.13.0.tgz",
+  "_shasum": "75f490b8a8abf75f1386ef5ec4455ecf6b345c63",
+  "_spec": "pg-types@1.*",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgtools/node_modules/pg",
+  "author": {
+    "name": "Brian M. Carlson"
+  },
+  "bugs": {
+    "url": "https://github.com/brianc/node-pg-types/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "pg-int8": "1.0.1",
+    "postgres-array": "~1.0.0",
+    "postgres-bytea": "~1.0.0",
+    "postgres-date": "~1.0.0",
+    "postgres-interval": "^1.1.0"
+  },
+  "deprecated": false,
+  "description": "Query result type converters for node-postgres",
+  "devDependencies": {
+    "pff": "^1.0.0",
+    "tap-spec": "^4.0.0",
+    "tape": "^4.0.0"
+  },
+  "homepage": "https://github.com/brianc/node-pg-types",
+  "keywords": [
+    "postgres",
+    "PostgreSQL",
+    "pg"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "pg-types",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianc/node-pg-types.git"
+  },
+  "scripts": {
+    "test": "tape test/*.js | tap-spec"
+  },
+  "version": "1.13.0"
+}
diff --git a/server/node_modules/pgtools/node_modules/pg-types/test/index.js b/server/node_modules/pgtools/node_modules/pg-types/test/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..b7d05cd68f12a893a4d69c7063b9415efd60ed6c
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-types/test/index.js
@@ -0,0 +1,24 @@
+
+var test = require('tape')
+var printf = require('pff')
+var getTypeParser = require('../').getTypeParser
+var types = require('./types')
+
+test('types', function (t) {
+  Object.keys(types).forEach(function (typeName) {
+    var type = types[typeName]
+    t.test(typeName, function (t) {
+      var parser = getTypeParser(type.id, type.format)
+      type.tests.forEach(function (tests) {
+        var input = tests[0]
+        var expected = tests[1]
+        var result = parser(input)
+        if (typeof expected === 'function') {
+          return expected(t, result)
+        }
+        t.equal(result, expected)
+      })
+      t.end()
+    })
+  })
+})
diff --git a/server/node_modules/pgtools/node_modules/pg-types/test/types.js b/server/node_modules/pgtools/node_modules/pg-types/test/types.js
new file mode 100644
index 0000000000000000000000000000000000000000..eddee8cb629f895f24e1c28d26bad2ca1261b63b
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg-types/test/types.js
@@ -0,0 +1,561 @@
+'use strict'
+
+exports['string/varchar'] = {
+  format: 'text',
+  id: 1043,
+  tests: [
+    ['bang', 'bang']
+  ]
+}
+
+exports['integer/int4'] = {
+  format: 'text',
+  id: 23,
+  tests: [
+    ['2147483647', 2147483647]
+  ]
+}
+
+exports['smallint/int2'] = {
+  format: 'text',
+  id: 21,
+  tests: [
+    ['32767', 32767]
+  ]
+}
+
+exports['bigint/int8'] = {
+  format: 'text',
+  id: 20,
+  tests: [
+    ['9223372036854775807', '9223372036854775807']
+  ]
+}
+
+exports.oid = {
+  format: 'text',
+  id: 26,
+  tests: [
+    ['103', 103]
+  ]
+}
+
+var bignum = '31415926535897932384626433832795028841971693993751058.16180339887498948482045868343656381177203091798057628'
+exports.numeric = {
+  format: 'text',
+  id: 1700,
+  tests: [
+    [bignum, bignum]
+  ]
+}
+
+exports['real/float4'] = {
+  format: 'text',
+  id: 700,
+  tests: [
+    ['123.456', 123.456]
+  ]
+}
+
+exports['double precision / float 8'] = {
+  format: 'text',
+  id: 701,
+  tests: [
+    ['12345678.12345678', 12345678.12345678]
+  ]
+}
+
+exports.boolean = {
+  format: 'text',
+  id: 16,
+  tests: [
+    ['TRUE', true],
+    ['t', true],
+    ['true', true],
+    ['y', true],
+    ['yes', true],
+    ['on', true],
+    ['1', true],
+    ['f', false],
+    [null, null]
+  ]
+}
+
+exports.timestamptz = {
+  format: 'text',
+  id: 1184,
+  tests: [
+    [
+      '2010-10-31 14:54:13.74-05:30',
+      dateEquals(2010, 9, 31, 20, 24, 13, 740)
+    ],
+    [
+      '2011-01-23 22:05:00.68-06',
+       dateEquals(2011, 0, 24, 4, 5, 0, 680)
+    ],
+    [
+      '2010-10-30 14:11:12.730838Z',
+      dateEquals(2010, 9, 30, 14, 11, 12, 730)
+    ],
+    [
+      '2010-10-30 13:10:01+05',
+      dateEquals(2010, 9, 30, 8, 10, 1, 0)
+    ]
+  ]
+}
+
+exports.timestamp = {
+  format: 'text',
+  id: 1114,
+  tests: [
+    [
+      '2010-10-31 00:00:00', 
+      function (t, value) {
+        t.equal(
+          value.toUTCString(),
+          new Date(2010, 9, 31, 0, 0, 0, 0, 0).toUTCString()
+        )
+        t.equal(
+          value.toString(),
+          new Date(2010, 9, 31, 0, 0, 0, 0, 0, 0).toString()
+        )
+      }
+    ]
+  ]
+}
+
+exports.date = {
+  format: 'text',
+  id: 1082,
+  tests: [
+    ['2010-10-31', function (t, value) {
+      var now = new Date(2010, 9, 31)
+      dateEquals(
+        2010,
+        now.getUTCMonth(),
+        now.getUTCDate(),
+        now.getUTCHours(), 0, 0, 0)(t, value)
+      t.equal(value.getHours(), now.getHours())
+    }]
+  ]
+}
+
+exports.inet = {
+  format: 'text',
+  id: 869,
+  tests: [
+    ['8.8.8.8', '8.8.8.8'],
+    ['2001:4860:4860::8888', '2001:4860:4860::8888'],
+    ['127.0.0.1', '127.0.0.1'],
+    ['fd00:1::40e', 'fd00:1::40e'],
+    ['1.2.3.4', '1.2.3.4']
+  ]
+}
+
+exports.cidr = {
+  format: 'text',
+  id: 650,
+  tests: [
+    ['172.16.0.0/12', '172.16.0.0/12'],
+    ['fe80::/10', 'fe80::/10'],
+    ['fc00::/7', 'fc00::/7'],
+    ['192.168.0.0/24', '192.168.0.0/24'],
+    ['10.0.0.0/8', '10.0.0.0/8']
+  ]
+}
+
+exports.macaddr = {
+  format: 'text',
+  id: 829,
+  tests: [
+    ['08:00:2b:01:02:03', '08:00:2b:01:02:03'],
+    ['16:10:9f:0d:66:00', '16:10:9f:0d:66:00']
+  ]
+}
+
+exports.numrange = {
+  format: 'text',
+  id: 3906,
+  tests: [
+    ['[,]', '[,]'],
+    ['(,)', '(,)'],
+    ['(,]', '(,]'],
+    ['[1,)', '[1,)'],
+    ['[,1]', '[,1]'],
+    ['(1,2)', '(1,2)'],
+    ['(1,20.5]', '(1,20.5]']
+  ]
+}
+
+exports.interval = {
+  format: 'text',
+  id: 1186,
+  tests: [
+    ['01:02:03', function (t, value) {
+      t.equal(value.toPostgres(), '3 seconds 2 minutes 1 hours')
+      t.deepEqual(value, {hours: 1, minutes: 2, seconds: 3})
+    }],
+    ['01:02:03:456', function (t, value) {
+      t.deepEqual(value, {hours: 1, minutes:2, seconds: 3, milliseconds: 456})
+    }],
+    ['1 year -32 days', function (t, value) {
+      t.equal(value.toPostgres(), '-32 days 1 years')
+      t.deepEqual(value, {years: 1, days: -32})
+    }],
+    ['1 day -00:00:03', function (t, value) {
+      t.equal(value.toPostgres(), '-3 seconds 1 days')
+      t.deepEqual(value, {days: 1, seconds: -3})
+    }]
+  ]
+}
+
+exports.bytea = {
+  format: 'text',
+  id: 17,
+  tests: [
+    ['foo\\000\\200\\\\\\377', function (t, value) {
+      var buffer = new Buffer([102, 111, 111, 0, 128, 92, 255])
+      t.ok(buffer.equals(value))
+    }],
+    ['', function (t, value) {
+      var buffer = new Buffer(0)
+      t.ok(buffer.equals(value))
+    }]
+  ]
+}
+
+exports['array/boolean'] = {
+    format: 'text',
+    id: 1000,
+    tests: [
+        ['{true,false}', function (t, value) {
+            t.deepEqual(value, [true, false])
+        }]
+    ]
+}
+
+exports['array/char'] = {
+  format: 'text',
+  id: 1014,
+  tests: [
+    ['{foo,bar}', function (t, value) {
+      t.deepEqual(value, ['foo', 'bar'])
+    }]
+  ]
+}
+
+exports['array/varchar'] = {
+  format: 'text',
+  id: 1015,
+  tests: [
+    ['{foo,bar}', function (t, value) {
+      t.deepEqual(value, ['foo', 'bar'])
+    }]
+  ]
+}
+
+exports['array/text'] = {
+  format: 'text',
+  id: 1008,
+  tests: [
+    ['{foo}', function (t, value) {
+      t.deepEqual(value, ['foo'])
+    }]
+  ]
+}
+
+exports['array/bytea'] = {
+  format: 'text',
+  id: 1001,
+  tests: [
+    ['{"\\\\x00000000"}', function (t, value) {
+      var buffer = new Buffer('00000000', 'hex')
+      t.ok(Array.isArray(value))
+      t.equal(value.length, 1)
+      t.ok(buffer.equals(value[0]))
+    }],
+    ['{NULL,"\\\\x4e554c4c"}', function (t, value) {
+      var buffer = new Buffer('4e554c4c', 'hex')
+      t.ok(Array.isArray(value))
+      t.equal(value.length, 2)
+      t.equal(value[0], null)
+      t.ok(buffer.equals(value[1]))
+    }],
+  ]
+}
+
+exports['array/numeric'] = {
+  format: 'text',
+  id: 1231,
+  tests: [
+    ['{1.2,3.4}', function (t, value) {
+      t.deepEqual(value, [1.2, 3.4])
+    }]
+  ]
+}
+
+exports['array/int2'] = {
+  format: 'text',
+  id: 1005,
+  tests: [
+    ['{-32768, -32767, 32766, 32767}', function (t, value) {
+      t.deepEqual(value, [-32768, -32767, 32766, 32767])
+    }]
+  ]
+}
+
+exports['array/int4'] = {
+  format: 'text',
+  id: 1005,
+  tests: [
+    ['{-2147483648, -2147483647, 2147483646, 2147483647}', function (t, value) {
+      t.deepEqual(value, [-2147483648, -2147483647, 2147483646, 2147483647])
+    }]
+  ]
+}
+
+exports['array/int8'] = {
+  format: 'text',
+  id: 1016,
+  tests: [
+    [
+      '{-9223372036854775808, -9223372036854775807, 9223372036854775806, 9223372036854775807}',
+      function (t, value) {
+        t.deepEqual(value, [
+          '-9223372036854775808',
+          '-9223372036854775807',
+          '9223372036854775806',
+          '9223372036854775807'
+        ])
+      }
+    ]
+  ]
+}
+
+exports['array/point'] = {
+  format: 'text',
+  id: 1017,
+  tests: [
+    ['{"(25.1,50.5)","(10.1,40)"}', function (t, value) {
+      t.deepEqual(value, [{x: 25.1, y: 50.5}, {x: 10.1, y: 40}])
+    }]
+  ]
+}
+
+exports['array/oid'] = {
+  format: 'text',
+  id: 1028,
+  tests: [
+    ['{25864,25860}', function (t, value) {
+      t.deepEqual(value, [25864, 25860])
+    }]
+  ]
+}
+
+exports['array/float4'] = {
+  format: 'text',
+  id: 1021,
+  tests: [
+    ['{1.2, 3.4}', function (t, value) {
+      t.deepEqual(value, [1.2, 3.4])
+    }]
+  ]
+}
+
+exports['array/float8'] = {
+  format: 'text',
+  id: 1022,
+  tests: [
+    ['{-12345678.1234567, 12345678.12345678}', function (t, value) {
+      t.deepEqual(value, [-12345678.1234567, 12345678.12345678])
+    }]
+  ]
+}
+
+exports['array/date'] = {
+  format: 'text',
+  id: 1182,
+  tests: [
+    ['{2014-01-01,2015-12-31}', function (t, value) {
+      var expecteds = [new Date(2014, 0, 1), new Date(2015, 11, 31)]
+      t.equal(value.length, 2)
+      value.forEach(function (date, index) {
+        var expected = expecteds[index]
+        dateEquals(
+          expected.getUTCFullYear(),
+          expected.getUTCMonth(),
+          expected.getUTCDate(),
+          expected.getUTCHours(), 0, 0, 0)(t, date)
+      })
+    }]
+  ]
+}
+
+exports['array/inet'] = {
+  format: 'text',
+  id: 1041,
+  tests: [
+    ['{8.8.8.8}', function (t, value) {
+      t.deepEqual(value, ['8.8.8.8']);
+    }],
+    ['{2001:4860:4860::8888}', function (t, value) {
+      t.deepEqual(value, ['2001:4860:4860::8888']);
+    }],
+    ['{127.0.0.1,fd00:1::40e,1.2.3.4}', function (t, value) {
+      t.deepEqual(value, ['127.0.0.1', 'fd00:1::40e', '1.2.3.4']);
+    }]
+  ]
+}
+
+exports['array/cidr'] = {
+  format: 'text',
+  id: 651,
+  tests: [
+    ['{172.16.0.0/12}', function (t, value) {
+      t.deepEqual(value, ['172.16.0.0/12']);
+    }],
+    ['{fe80::/10}', function (t, value) {
+      t.deepEqual(value, ['fe80::/10']);
+    }],
+    ['{10.0.0.0/8,fc00::/7,192.168.0.0/24}', function (t, value) {
+      t.deepEqual(value, ['10.0.0.0/8', 'fc00::/7', '192.168.0.0/24']);
+    }]
+  ]
+}
+
+exports['array/macaddr'] = {
+  format: 'text',
+  id: 1040,
+  tests: [
+    ['{08:00:2b:01:02:03,16:10:9f:0d:66:00}', function (t, value) {
+      t.deepEqual(value, ['08:00:2b:01:02:03', '16:10:9f:0d:66:00']);
+    }]
+  ]
+}
+
+exports['array/numrange'] = {
+  format: 'text',
+  id: 3907,
+  tests: [
+    ['{"[1,2]","(4.5,8)","[10,40)","(-21.2,60.3]"}', function (t, value) {
+      t.deepEqual(value, ['[1,2]', '(4.5,8)', '[10,40)', '(-21.2,60.3]']);
+    }],
+    ['{"[,20]","[3,]","[,]","(,35)","(1,)","(,)"}', function (t, value) {
+      t.deepEqual(value, ['[,20]', '[3,]', '[,]', '(,35)', '(1,)', '(,)']);
+    }],
+    ['{"[,20)","[3,)","[,)","[,35)","[1,)","[,)"}', function (t, value) {
+      t.deepEqual(value, ['[,20)', '[3,)', '[,)', '[,35)', '[1,)', '[,)']);
+    }]
+  ]
+}
+
+exports['binary-string/varchar'] = {
+  format: 'binary',
+  id: 1043,
+  tests: [
+    ['bang', 'bang']
+  ]
+}
+
+exports['binary-integer/int4'] = {
+  format: 'binary',
+  id: 23,
+  tests: [
+    [[0, 0, 0, 100], 100]
+  ]
+}
+
+exports['binary-smallint/int2'] = {
+  format: 'binary',
+  id: 21,
+  tests: [
+    [[0, 101], 101]
+  ]
+}
+
+exports['binary-bigint/int8'] = {
+  format: 'binary',
+  id: 20,
+  tests: [
+    [new Buffer([0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), '9223372036854775807']
+  ]
+}
+
+exports['binary-oid'] = {
+  format: 'binary',
+  id: 26,
+  tests: [
+    [[0, 0, 0, 103], 103]
+  ]
+}
+
+exports['binary-numeric'] = {
+  format: 'binary',
+  id: 1700,
+  tests: [
+    [
+      [0, 2, 0, 0, 0, 0, 0, hex('0x64'), 0, 12, hex('0xd'), hex('0x48'), 0, 0, 0, 0],
+      12.34
+    ]
+  ]
+}
+
+exports['binary-real/float4'] = {
+  format: 'binary',
+  id: 700,
+  tests: [
+    [['0x41', '0x48', '0x00', '0x00'].map(hex), 12.5]
+  ]
+}
+
+exports['binary-boolean'] = {
+  format: 'binary',
+  id: 16,
+  tests: [
+    [[1], true],
+    [[0], false],
+    [null, null]
+  ]
+}
+
+exports['binary-string'] = {
+  format: 'binary',
+  id: 25,
+  tests: [
+    [
+      new Buffer(['0x73', '0x6c', '0x61', '0x64', '0x64', '0x61'].map(hex)),
+      'sladda'
+    ]
+  ]
+}
+
+exports.point = {
+  format: 'text',
+  id: 600,
+  tests: [
+    ['(25.1,50.5)', function (t, value) {
+      t.deepEqual(value, {x: 25.1, y: 50.5})
+    }]
+  ]
+}
+
+exports.circle = {
+  format: 'text',
+  id: 718,
+  tests: [
+    ['<(25,10),5>', function (t, value) {
+      t.deepEqual(value, {x: 25, y: 10, radius: 5})
+    }]
+  ]
+}
+
+function hex (string) {
+  return parseInt(string, 16)
+}
+
+function dateEquals () {
+  var timestamp = Date.UTC.apply(Date, arguments)
+  return function (t, value) {
+    t.equal(value.toUTCString(), new Date(timestamp).toUTCString())
+  }
+}
diff --git a/server/node_modules/pgtools/node_modules/pg/.jshintrc b/server/node_modules/pgtools/node_modules/pg/.jshintrc
new file mode 100644
index 0000000000000000000000000000000000000000..c6c11efc5384ee2c37f4dc60cf6e78ee77edc396
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/.jshintrc
@@ -0,0 +1,5 @@
+{
+  "trailing": true,
+  "indent": 2,
+  "evil": true
+}
diff --git a/server/node_modules/pgtools/node_modules/pg/.npmignore b/server/node_modules/pgtools/node_modules/pg/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..b0d737dc339703937465b388c4bce8d95b24b928
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/.npmignore
@@ -0,0 +1,8 @@
+node_modules/
+*.swp
+*.log
+.lock-wscript
+build/
+*~
+test/
+script/
\ No newline at end of file
diff --git a/server/node_modules/pgtools/node_modules/pg/.travis.yml b/server/node_modules/pgtools/node_modules/pg/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..74f1e4c0ce85b052e0e4948e131ff3df7422bcda
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/.travis.yml
@@ -0,0 +1,44 @@
+language: node_js
+sudo: false
+dist: trusty
+before_script:
+  - node script/create-test-tables.js pg://postgres@127.0.0.1:5432/postgres
+env:
+  - CC=clang CXX=clang++ npm_config_clang=1 PGUSER=postgres PGDATABASE=postgres
+
+node_js: "6"
+addons:
+  postgresql: "9.6"
+
+matrix:
+  include:
+    - node_js: "0.10"
+      addons:
+        postgresql: "9.6"
+      env: []
+    - node_js: "0.12"
+      addons:
+        postgresql: "9.6"
+      env: []
+    - node_js: "4"
+      addons:
+        postgresql: "9.6"
+    - node_js: "5"
+      addons:
+        postgresql: "9.6"
+    - node_js: "6"
+      addons:
+        postgresql: "9.1"
+      dist: precise
+    - node_js: "6"
+      addons:
+        postgresql: "9.2"
+    - node_js: "6"
+      addons:
+        postgresql: "9.3"
+    - node_js: "6"
+      addons:
+        postgresql: "9.4"
+    - node_js: "6"
+      addons:
+        postgresql: "9.5"
diff --git a/server/node_modules/pgtools/node_modules/pg/CHANGELOG.md b/server/node_modules/pgtools/node_modules/pg/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..e955bb5237c4edbee51920dac530f91f8b98d8b8
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/CHANGELOG.md
@@ -0,0 +1,246 @@
+All major and minor releases are briefly explained below.
+
+For richer information consult the commit log on github with referenced pull requests.
+
+We do not include break-fix version release in this file.
+
+### v6.4.0
+
+- Add support for passing `client_encoding` as a connection parameter.  Used when decoding strings in the JavaScript driver.  The default is still `utf8`.
+
+### v6.3.0
+
+- Deprecate `pg.connect` `pg.end` and `pg.cancel` - favor using `new pg.Pool()` instead of pg singleton.
+- Deprecate undocumented but possibly used `query.promise()` method. Use the promise returned directly from `client.query` / `pool.query`.
+- Deprecate returning an automatically created query result from `client.query`.  Instead return more idomatic responses for callback/promise methods.
+
+### v6.2.0
+
+- Add support for [parsing `replicationStart` messages](https://github.com/brianc/node-postgres/pull/1271/files).
+
+### v6.1.0
+
+- Add optional callback parameter to the pure JavaScript `client.end` method.  The native client already supported this.
+
+### v6.0.0
+
+#### Breaking Changes
+- Remove `pg.pools`.  There is still a reference kept to the pools created & tracked by `pg.connect` but it has been renamed, is considered private, and should not be used.  Accessing this API directly was uncommon and was _supposed_ to be private but was incorrectly documented on the wiki.  Therefore, it is a breaking change of an (unintentionally) public interface to remove it by renaming it & making it private.  Eventually `pg.connect` itself will be deprecated in favor of instantiating pools directly via `new pg.Pool()` so this property should become completely moot at some point.  In the mean time...check out the new features...
+
+#### New features
+
+- Replace internal pooling code with [pg-pool](https://github.com/brianc/node-pg-pool). This is the first step in eventually deprecating and removing the singleton `pg.connect`.  The pg-pool constructor is exported from node-postgres at `require('pg').Pool`.  It provides a backwards compatible interface with `pg.connect` as well as a promise based interface & additional niceties.
+
+You can now create an instance of a pool and don't have to rely on the `pg` singleton for anything:
+
+```
+var pg = require('pg')
+
+var pool = new pg.Pool()
+
+// your friendly neighboorhood pool interface, without the singleton
+pool.connect(function(err, client, done) {
+  // ...
+})
+```
+
+Promise support & other goodness lives now in [pg-pool](https://github.com/brianc/node-pg-pool).
+
+__Please__ read the readme at [pg-pool](https://github.com/brianc/node-pg-pool) for the full api.
+
+- Included support for tcp keep alive.  Enable it as follows:
+
+```js
+var client = new Client({ keepAlive: true })
+```
+
+This should help with backends incorrectly considering idle clients to be dead and prematurely disconnecting them.
+
+
+### v5.1.0
+- Make the query object returned from `client.query` implement the promise interface. This is the first step towards promisifying more of the node-postgres api.
+
+Example:
+```js
+var client = new Client()
+client.connect()
+client.query('SELECT $1::text as name', ['brianc'])
+  .then(function(res) {
+    console.log('hello from', res.rows[0])
+    client.end()
+  })
+```
+
+### v5.0.0
+
+#### Breaking Changes
+- `require('pg').native` now returns null if the native bindings cannot be found; previously, this threw an exception.
+
+#### New Features
+- better error message when passing `undefined` as a query parameter
+- support for `defaults.connectionString`
+- support for `returnToHead` being passed to [generic pool](https://github.com/coopernurse/node-pool)
+
+### v4.5.0
+- Add option to parse JS date objects in query parameters as [UTC](https://github.com/brianc/node-postgres/pull/943)
+
+### v4.4.0
+- Warn to `stderr` if a named query exceeds 63 characters which is the max lenght supported by postgres.
+
+### v4.3.0
+- Unpin `pg-types` semver. Allow it to float against `pg-types@1.x`.
+
+### v4.2.0
+- Support for additional error fields in postgres >= 9.3 if available.
+
+### v4.1.0
+- Allow type parser overrides on a [per-client basis](https://github.com/brianc/node-postgres/pull/679)
+
+### v4.0.0
+- Make [native bindings](https://github.com/brianc/node-pg-native.git) an optional install with `npm install pg-native`
+- No longer surround query result callback with `try/catch` block.
+- Remove built in COPY IN / COPY OUT support - better implementations provided by [pg-copy-streams](https://github.com/brianc/node-pg-copy-streams.git) and [pg-native](https://github.com/brianc/node-pg-native.git)
+
+### v3.6.0
+- Include support for (parsing JSONB)[https://github.com/brianc/node-pg-types/pull/13] (supported in postgres 9.4)
+
+### v3.5.0
+- Include support for parsing boolean arrays
+
+### v3.4.0
+- Include port as connection parameter to [unix sockets](https://github.com/brianc/node-postgres/pull/604)
+- Better support for odd [date parsing](https://github.com/brianc/node-pg-types/pull/8)
+
+### v3.2.0
+
+- Add support for parsing [date arrays](https://github.com/brianc/node-pg-types/pull/3)
+- Expose array parsers on [pg.types](https://github.com/brianc/node-pg-types/pull/2)
+- Allow [pool](https://github.com/brianc/node-postgres/pull/591) to be configured
+
+
+### v3.1.0
+
+- Add [count of the number of times a client has been checked out from the pool](https://github.com/brianc/node-postgres/pull/556)
+- Emit `end` from `pg` object [when a pool is drained](https://github.com/brianc/node-postgres/pull/571)
+
+### v3.0.0
+
+#### Breaking changes
+- [Parse the DATE PostgreSQL type as local time](https://github.com/brianc/node-postgres/pull/514)
+
+After [some discussion](https://github.com/brianc/node-postgres/issues/510) it was decided node-postgres was non-compliant in how it was handling DATE results.  They were being converted to UTC, but the PostgreSQL documentation specifies they should be returned in the client timezone.  This is a breaking change, and if you use the `date` type you might want to examine your code and make sure nothing is impacted.
+
+- [Fix possible numeric precision loss on numeric & int8 arrays](https://github.com/brianc/node-postgres/pull/501)
+
+pg@v2.0 included changes to not convert large integers into their JavaScript number representation because of possibility for numeric precision loss. The same types in arrays were not taken into account.  This fix applies the same type of type-coercion rules to arrays of those types, so there will be no more possible numeric loss on an array of very large int8s for example. This is a breaking change because now a return type from a query of `int8[]` will contain _string_ representations
+of the integers.  Use your favorite JavaScript bignum module to represent them without precision loss, or punch over the type converter to return the old style arrays again.
+
+- [Fix to input array of dates being improperly converted to utc](https://github.com/benesch/node-postgres/commit/c41eedc3e01e5527a3d5c242fa1896f02ef0b261#diff-7172adb1fec2457a2700ed29008a8e0aR108)
+
+Single `date` parameters were properly sent to the PostgreSQL server properly in local time, but an input array of dates was being changed into utc dates.  This is a violation of what PostgreSQL expects.  Small breaking change, but none-the-less something you should check out if you are inserting an array of dates.
+
+- [Query no longer emits `end` event if it ends due to an error](https://github.com/brianc/node-postgres/commit/357b64d70431ec5ca721eb45a63b082c18e6ffa3)
+
+This is a small change to bring the semantics of query more in line with other EventEmitters. The tests all passed after this change, but I suppose it could still be a breaking change in certain use cases.  If you are doing clever things with the `end` and `error` events of a query object you might want to check to make sure its still behaving normally, though it is most likely not an issue.
+
+#### New features
+- [Supercharge `prepareValue`](https://github.com/brianc/node-postgres/pull/555)
+
+The long & short of it is now any object you supply in the list of query values will be inspected for a `.toPostgres` method.  If the method is present it will be called and its result used as the raw text value sent to PostgreSQL for that value.  This allows the same type of custom type coercion on query parameters as was previously afforded to query result values.
+
+- [Domain aware connection pool](https://github.com/brianc/node-postgres/pull/531)
+
+If domains are active node-postgres will honor them and do everything it can to ensure all callbacks are properly fired in the active domain. If you have tried to use domains with node-postgres (or many other modules which pool long lived event emitters) you may have run into an issue where the active domain changes before and after a callback. This has been a longstanding footgun within node-postgres and I am happy to get it fixed.
+
+- [Disconnected clients now removed from pool](https://github.com/brianc/node-postgres/pull/543)
+
+Avoids a scenario where your pool could fill up with disconnected & unusable clients.
+
+- [Break type parsing code into separate module](https://github.com/brianc/node-postgres/pull/541)
+
+To provide better documentation and a clearer explanation of how to override the query result parsing system we broke the type converters [into their own module](https://github.com/brianc/node-pg-types). There is still work around removing the 'global-ness' of the type converters so each query or connection can return types differently, but this is a good first step and allow a lot more obvious way to return int8 results as JavaScript numbers, for example
+
+### v2.11.0
+- Add support for [application_name](https://github.com/brianc/node-postgres/pull/497)
+
+### v2.10.0
+- Add support for [the password file](http://www.postgresql.org/docs/9.3/static/libpq-pgpass.html)
+
+### v2.9.0
+- Add better support for [unix domain socket](https://github.com/brianc/node-postgres/pull/487) connections
+
+### v2.8.0
+- Add support for parsing JSON[] and UUID[] result types
+
+### v2.7.0
+- Use single row mode in native bindings when available [@rpedela]
+  - reduces memory consumption when handling row values in 'row' event
+- Automatically bind buffer type parameters as binary [@eugeneware]
+
+### v2.6.0
+- Respect PGSSLMODE environment variable
+
+### v2.5.0
+- Ability to opt-in to int8 parsing via `pg.defaults.parseInt8 = true`
+
+### v2.4.0
+- Use eval in the result set parser to increase performance
+
+### v2.3.0
+- Remove built-in support for binary Int64 parsing.
+_Due to the low usage & required compiled dependency this will be pushed into a 3rd party add-on_
+
+### v2.2.0
+- [Add support for excapeLiteral and escapeIdentifier in both JavaScript and the native bindings](https://github.com/brianc/node-postgres/pull/396)
+
+### v2.1.0
+- Add support for SSL connections in JavaScript driver
+ - this means you can connect to heroku postgres from your local machine without the native bindings!
+- [Add field metadata to result object](https://github.com/brianc/node-postgres/blob/master/test/integration/client/row-description-on-results-tests.js)
+- [Add ability for rows to be returned as arrays instead of objects](https://github.com/brianc/node-postgres/blob/master/test/integration/client/results-as-array-tests.js)
+
+### v2.0.0
+
+- Properly handle various PostgreSQL to JavaScript type conversions to avoid data loss:
+
+```
+PostgreSQL | pg@v2.0 JavaScript | pg@v1.0 JavaScript
+--------------------------------|----------------
+float4     | number (float)     | string
+float8     | number (float)     | string
+int8       | string             | number (int)
+numeric    | string             | number (float)
+decimal    | string             | number (float)
+```
+
+For more information see https://github.com/brianc/node-postgres/pull/353
+If you are unhappy with these changes you can always [override the built in type parsing fairly easily](https://github.com/brianc/node-pg-parse-float). 
+
+### v1.3.0
+
+- Make client_encoding configurable and optional
+
+### v1.2.0
+
+- return field metadata on result object: access via result.fields[i].name/dataTypeID
+
+### v1.1.0
+
+- built in support for `JSON` data type for PostgreSQL Server @ v9.2.0 or greater
+
+### v1.0.0
+
+- remove deprecated functionality
+  - Callback function passed to `pg.connect` now __requires__ 3 arguments
+  - Client#pauseDrain() / Client#resumeDrain removed
+  - numeric, decimal, and float data types no longer parsed into float before being returned. Will be returned from query results as `String`
+
+### v0.15.0
+
+- client now emits `end` when disconnected from back-end server
+- if client is disconnected in the middle of a query, query receives an error
+
+### v0.14.0
+
+- add deprecation warnings in prep for v1.0
+- fix read/write failures in native module under node v0.9.x
diff --git a/server/node_modules/pgtools/node_modules/pg/LICENSE b/server/node_modules/pgtools/node_modules/pg/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..a7b546d2d6b27f390041b8c13eee489254497b92
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2010 - 2017 Brian Carlson
+
+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.
diff --git a/server/node_modules/pgtools/node_modules/pg/Makefile b/server/node_modules/pgtools/node_modules/pg/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..4eddd4f105551afa74d57bd2157688b8275fd9b1
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/Makefile
@@ -0,0 +1,63 @@
+SHELL := /bin/sh
+
+connectionString=postgres://
+
+params := $(connectionString)
+
+node-command := xargs -n 1 -I file node file $(params)
+
+.PHONY : test test-connection test-integration bench test-native \
+	 jshint publish test-missing-native update-npm
+
+all:
+	npm install
+
+help:
+	@echo "make test-all [connectionString=postgres://<your connection string>]"
+
+test: test-unit
+
+test-all: jshint test-missing-native test-unit test-integration test-native test-binary
+
+
+update-npm:
+	@npm i npm --global
+
+bench:
+	@find benchmark -name "*-bench.js" | $(node-command)
+
+test-unit:
+	@find test/unit -name "*-tests.js" | $(node-command)
+
+test-connection:
+	@echo "***Testing connection***"
+	@node script/create-test-tables.js $(params)
+
+test-missing-native:
+	@echo "***Testing optional native install***"
+	@rm -rf node_modules/pg-native
+	@node test/native/missing-native.js
+	@rm -rf node_modules/pg-native
+
+node_modules/pg-native/index.js:
+	@npm i pg-native
+
+test-native: node_modules/pg-native/index.js test-connection
+	@echo "***Testing native bindings***"
+	@find test/native -name "*-tests.js" | $(node-command)
+	@find test/integration -name "*-tests.js" | $(node-command) native
+
+test-integration: test-connection
+	@echo "***Testing Pure Javascript***"
+	@find test/integration -name "*-tests.js" | $(node-command)
+
+test-binary: test-connection
+	@echo "***Testing Pure Javascript (binary)***"
+	@find test/integration -name "*-tests.js" | $(node-command) binary
+
+test-pool:
+	@find test/integration/connection-pool -name "*.js" | $(node-command) binary
+
+jshint:
+	@echo "***Starting jshint***"
+	@./node_modules/.bin/jshint lib
diff --git a/server/node_modules/pgtools/node_modules/pg/README.md b/server/node_modules/pgtools/node_modules/pg/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..679b5796d4d80491b997966cbab98569431ec959
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/README.md
@@ -0,0 +1,274 @@
+# node-postgres
+
+[![Build Status](https://secure.travis-ci.org/brianc/node-postgres.svg?branch=master)](http://travis-ci.org/brianc/node-postgres)
+[![Dependency Status](https://david-dm.org/brianc/node-postgres.svg)](https://david-dm.org/brianc/node-postgres)
+<span class="badge-npmversion"><a href="https://npmjs.org/package/pg" title="View this project on NPM"><img src="https://img.shields.io/npm/v/pg.svg" alt="NPM version" /></a></span>
+<span class="badge-npmdownloads"><a href="https://npmjs.org/package/pg" title="View this project on NPM"><img src="https://img.shields.io/npm/dm/pg.svg" alt="NPM downloads" /></a></span>
+
+Non-blocking PostgreSQL client for node.js.  Pure JavaScript and optional native libpq bindings.
+
+## Install
+
+```sh
+$ npm install pg
+```
+
+## Intro & Examples
+
+There are 3 ways of executing queries
+
+1. Passing the query to a pool
+2. Borrowing a client from a pool and executing the query with it
+3. Obtaining an exclusive client and executing the query with it
+
+It is recommended to pass the query to a pool as often as possible. If that isn't possible, because of long and complex transactions for example, borrow a client from a pool. Just remember to initialize the pool only once in your code so you maximize reusability of connections.
+
+### Why pooling?
+
+If you're working on something like a web application which makes frequent queries you'll want to access the PostgreSQL server through a pool of clients.  Why?  For one thing, there is ~20-30 millisecond delay (YMMV) when connecting a new client to the PostgreSQL server because of the startup handshake.  Furthermore, PostgreSQL can support only a limited number of clients...it depends on the amount of ram on your database server, but generally more than 100 clients at a time is a __very bad thing__. :tm: Additionally, PostgreSQL can only execute 1 query at a time per connected client, so pipelining all queries for all requests through a single, long-lived client will likely introduce a bottleneck into your application if you need high concurrency.
+
+With that in mind we can imagine a situation where you have a web server which connects and disconnects a new client for every web request or every query (don't do this!).  If you get only 1 request at a time everything will seem to work fine, though it will be a touch slower due to the connection overhead. Once you get >100 simultaneous requests your web server will attempt to open 100 connections to the PostgreSQL backend and :boom: you'll run out of memory on the PostgreSQL server, your database will become unresponsive, your app will seem to hang, and everything will break. Boooo!
+
+__Good news__: node-postgres ships with built in client pooling.  Client pooling allows your application to use a pool of already connected clients and reuse them for each request to your application.  If your app needs to make more queries than there are available clients in the pool the queries will queue instead of overwhelming your database & causing a cascading failure. :thumbsup:
+
+node-postgres uses [pg-pool](https://github.com/brianc/node-pg-pool.git) to manage pooling. It bundles it and exports it for convenience.  If you want, you can `require('pg-pool')` and use it directly - it's the same as the constructor exported at `pg.Pool`.
+
+It's __highly recommended__ you read the documentation for [pg-pool](https://github.com/brianc/node-pg-pool.git).
+
+[Here is an up & running quickly example](https://github.com/brianc/node-postgres/wiki/Example)
+
+For more information about `config.ssl` check [TLS (SSL) of nodejs](https://nodejs.org/dist/latest-v4.x/docs/api/tls.html)
+
+### Pooling example
+
+Let's create a pool in `./lib/db.js` which will be reused across the whole project
+
+```javascript
+const pg = require('pg');
+
+// create a config to configure both pooling behavior
+// and client options
+// note: all config is optional and the environment variables
+// will be read if the config is not present
+var config = {
+  user: 'foo', //env var: PGUSER
+  database: 'my_db', //env var: PGDATABASE
+  password: 'secret', //env var: PGPASSWORD
+  host: 'localhost', // Server hosting the postgres database
+  port: 5432, //env var: PGPORT
+  max: 10, // max number of clients in the pool
+  idleTimeoutMillis: 30000, // how long a client is allowed to remain idle before being closed
+};
+
+//this initializes a connection pool
+//it will keep idle connections open for 30 seconds
+//and set a limit of maximum 10 idle clients
+const pool = new pg.Pool(config);
+
+pool.on('error', function (err, client) {
+  // if an error is encountered by a client while it sits idle in the pool
+  // the pool itself will emit an error event with both the error and
+  // the client which emitted the original error
+  // this is a rare occurrence but can happen if there is a network partition
+  // between your application and the database, the database restarts, etc.
+  // and so you might want to handle it and at least log it out
+  console.error('idle client error', err.message, err.stack);
+});
+
+//export the query method for passing queries to the pool
+module.exports.query = function (text, values, callback) {
+  console.log('query:', text, values);
+  return pool.query(text, values, callback);
+};
+
+// the pool also supports checking out a client for
+// multiple operations, such as a transaction
+module.exports.connect = function (callback) {
+  return pool.connect(callback);
+};
+```
+
+Now if in `./foo.js` you want to pass a query to the pool
+
+```js
+const pool = require('./lib/db');
+
+//to run a query we just pass it to the pool
+//after we're done nothing has to be taken care of
+//we don't have to return any client to the pool or close a connection
+pool.query('SELECT $1::int AS number', ['2'], function(err, res) {
+  if(err) {
+    return console.error('error running query', err);
+  }
+
+  console.log('number:', res.rows[0].number);
+});
+```
+
+Or if in `./bar.js` you want borrow a client from the pool
+
+```js
+const pool = require('./lib/db');
+
+//ask for a client from the pool
+pool.connect(function(err, client, done) {
+  if(err) {
+    return console.error('error fetching client from pool', err);
+  }
+  
+  //use the client for executing the query
+  client.query('SELECT $1::int AS number', ['1'], function(err, result) {
+    //call `done(err)` to release the client back to the pool (or destroy it if there is an error)
+    done(err);
+
+    if(err) {
+      return console.error('error running query', err);
+    }
+    console.log(result.rows[0].number);
+    //output: 1
+  });
+});
+```
+
+For more examples, including how to use a connection pool with promises and async/await see the [example](https://github.com/brianc/node-postgres/wiki/Example) page in the wiki.
+
+### Obtaining an exclusive client, example
+
+```js
+var pg = require('pg');
+
+// instantiate a new client
+// the client will read connection information from
+// the same environment variables used by postgres cli tools
+var client = new pg.Client();
+
+// connect to our database
+client.connect(function (err) {
+  if (err) throw err;
+
+  // execute a query on our database
+  client.query('SELECT $1::text as name', ['brianc'], function (err, result) {
+    if (err) throw err;
+
+    // just print the result to the console
+    console.log(result.rows[0]); // outputs: { name: 'brianc' }
+
+    // disconnect the client
+    client.end(function (err) {
+      if (err) throw err;
+    });
+  });
+});
+
+```
+
+## [More Documentation](https://github.com/brianc/node-postgres/wiki)
+
+## Native Bindings
+
+To install the [native bindings](https://github.com/brianc/node-pg-native.git):
+
+```sh
+$ npm install pg pg-native
+```
+
+
+node-postgres contains a pure JavaScript protocol implementation which is quite fast, but you can optionally use [native](https://github.com/brianc/node-pg-native) [bindings](https://github.com/brianc/node-libpq) for a 20-30% increase in parsing speed (YMMV). Both versions are adequate for production workloads. I personally use the pure JavaScript implementation because I like knowing what's going on all the way down to the binary on the socket, and it allows for some fancier [use](https://github.com/brianc/node-pg-cursor) [cases](https://github.com/brianc/node-pg-query-stream) which are difficult to do with libpq. :smile:
+
+To use the native bindings, first install [pg-native](https://github.com/brianc/node-pg-native.git).  Once pg-native is installed, simply replace `var pg = require('pg')` with `var pg = require('pg').native`.  Make sure any exported constructors from `pg` are from the native instance.  Example:
+
+```js
+var pg = require('pg').native
+var Pool = require('pg').Pool // bad! this is not bound to the native client
+var Client = require('pg').Client // bad! this is the pure JavaScript client
+
+var pg = require('pg').native
+var Pool = pg.Pool // good! a pool bound to the native client
+var Client = pg.Client // good! this client uses libpq bindings
+```
+
+#### API differences
+
+node-postgres abstracts over the pg-native module to provide the same interface as the pure JavaScript version. Care has been taken to keep the number of api differences between the two modules to a minimum.  
+However, currently some differences remain, especially :
+* the error object in pg-native is different : notably, the information about the postgres error code is not present in field `code` but in the field `sqlState` , and the name of a few other fields is different (see https://github.com/brianc/node-postgres/issues/938, https://github.com/brianc/node-postgres/issues/972).
+So for example, if you rely on error.code in your application, your will have to adapt your code to work with native bindings.
+* the notification object has a few less properties  (see https://github.com/brianc/node-postgres/issues/1045)
+* column objects have less properties (see https://github.com/brianc/node-postgres/issues/988)
+* the modules https://github.com/brianc/node-pg-copy-streams and https://github.com/brianc/node-pg-query-stream do not work with native bindings (you will have to require 'pg' to use them).
+
+Thus, it is recommended you use either the pure JavaScript or native bindings in both development and production and don't mix & match them in the same process - it can get confusing!
+
+## Features
+
+* pure JavaScript client and native libpq bindings share _the same api_
+* connection pooling
+* extensible js<->postgresql data-type coercion
+* supported PostgreSQL features
+  * parameterized queries
+  * named statements with query plan caching
+  * async notifications with `LISTEN/NOTIFY`
+  * bulk import & export with `COPY TO/COPY FROM`
+
+## Extras
+
+node-postgres is by design pretty light on abstractions.  These are some handy modules we've been using over the years to complete the picture.
+Entire list can be found on [wiki](https://github.com/brianc/node-postgres/wiki/Extras)
+
+## Contributing
+
+__:heart: contributions!__
+
+If you need help getting the tests running locally or have any questions about the code when working on a patch please feel free to email me or gchat me.
+
+I will __happily__ accept your pull request if it:
+- __has tests__
+- looks reasonable
+- does not break backwards compatibility
+
+Information about the testing processes is in the [wiki](https://github.com/brianc/node-postgres/wiki/Testing).
+
+Open source belongs to all of us, and we're all invited to participate!
+
+## Troubleshooting and FAQ
+
+The causes and solutions to common errors can be found among the [Frequently Asked Questions(FAQ)](https://github.com/brianc/node-postgres/wiki/FAQ)
+
+## Support
+
+If at all possible when you open an issue please provide
+- version of node
+- version of postgres
+- smallest possible snippet of code to reproduce the problem
+
+Usually I'll pop the code into the repo as a test.  Hopefully the test fails.  Then I make the test pass.  Then everyone's happy!
+
+If you need help or run into _any_ issues getting node-postgres to work on your system please report a bug or contact me directly.  I am usually available via google-talk at my github account public email address.  Remember this is a labor of love, and though I try to get back to everything sometimes life takes priority, and I might take a while.  It helps if you use nice code formatting in your issue, search for existing answers before posting, and come back and close out the issue if you figure out a solution.  The easier you can make it for me, the quicker I'll try and respond to you!
+
+If you need deeper support, have application specific questions, would like to sponsor development, or want consulting around node & postgres please send me an email, I'm always happy to discuss!
+
+I usually tweet about any important status updates or changes to node-postgres on twitter.
+Follow me [@briancarlson](https://twitter.com/briancarlson) to keep up to date.
+
+
+## License
+
+Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+
+ 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.
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/client.js b/server/node_modules/pgtools/node_modules/pg/lib/client.js
new file mode 100644
index 0000000000000000000000000000000000000000..a031eb3e3cfa459ca299b00b146d028f5fd213cf
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/client.js
@@ -0,0 +1,386 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var crypto = require('crypto');
+var EventEmitter = require('events').EventEmitter;
+var util = require('util');
+var pgPass = require('pgpass');
+var TypeOverrides = require('./type-overrides');
+
+var ConnectionParameters = require('./connection-parameters');
+var utils = require('./utils');
+var Query = require('./query');
+var defaults = require('./defaults');
+var Connection = require('./connection');
+
+var Client = function(config) {
+  EventEmitter.call(this);
+
+  this.connectionParameters = new ConnectionParameters(config);
+  this.user = this.connectionParameters.user;
+  this.database = this.connectionParameters.database;
+  this.port = this.connectionParameters.port;
+  this.host = this.connectionParameters.host;
+  this.password = this.connectionParameters.password;
+  this.replication = this.connectionParameters.replication;
+
+  var c = config || {};
+
+  this._types = new TypeOverrides(c.types);
+  this._ending = false;
+  this._connecting = false;
+  this._connectionError = false;
+
+  this.connection = c.connection || new Connection({
+    stream: c.stream,
+    ssl: this.connectionParameters.ssl,
+    keepAlive: c.keepAlive || false,
+    client_encoding: this.connectionParameters.client_encoding || 'utf8',
+  });
+  this.queryQueue = [];
+  this.binary = c.binary || defaults.binary;
+  this.encoding = this.connectionParameters.client_encoding || 'utf8';
+  this.processID = null;
+  this.secretKey = null;
+  this.ssl = this.connectionParameters.ssl || false;
+};
+
+util.inherits(Client, EventEmitter);
+
+Client.prototype.connect = function(callback) {
+  var self = this;
+  var con = this.connection;
+  this._connecting = true;
+
+  if(this.host && this.host.indexOf('/') === 0) {
+    con.connect(this.host + '/.s.PGSQL.' + this.port);
+  } else {
+    con.connect(this.port, this.host);
+  }
+
+
+  //once connection is established send startup message
+  con.on('connect', function() {
+    if(self.ssl) {
+      con.requestSsl();
+    } else {
+      con.startup(self.getStartupConf());
+    }
+  });
+
+  con.on('sslconnect', function() {
+    con.startup(self.getStartupConf());
+  });
+
+  function checkPgPass(cb) {
+    return function(msg) {
+      if (null !== self.password) {
+        cb(msg);
+      } else {
+        pgPass(self.connectionParameters, function(pass){
+          if (undefined !== pass) {
+            self.connectionParameters.password = self.password = pass;
+          }
+          cb(msg);
+        });
+      }
+    };
+  }
+
+  //password request handling
+  con.on('authenticationCleartextPassword', checkPgPass(function() {
+    con.password(self.password);
+  }));
+
+  //password request handling
+  con.on('authenticationMD5Password', checkPgPass(function(msg) {
+    var inner = Client.md5(self.password + self.user);
+    var outer = Client.md5(Buffer.concat([new Buffer(inner), msg.salt]));
+    var md5password = "md5" + outer;
+    con.password(md5password);
+  }));
+
+  con.once('backendKeyData', function(msg) {
+    self.processID = msg.processID;
+    self.secretKey = msg.secretKey;
+  });
+
+  //hook up query handling events to connection
+  //after the connection initially becomes ready for queries
+  con.once('readyForQuery', function() {
+    self._connecting = false;
+
+    //delegate rowDescription to active query
+    con.on('rowDescription', function(msg) {
+      self.activeQuery.handleRowDescription(msg);
+    });
+
+    //delegate dataRow to active query
+    con.on('dataRow', function(msg) {
+      self.activeQuery.handleDataRow(msg);
+    });
+
+    //delegate portalSuspended to active query
+    con.on('portalSuspended', function(msg) {
+      self.activeQuery.handlePortalSuspended(con);
+    });
+
+    //deletagate emptyQuery to active query
+    con.on('emptyQuery', function(msg) {
+      self.activeQuery.handleEmptyQuery(con);
+    });
+
+    //delegate commandComplete to active query
+    con.on('commandComplete', function(msg) {
+      self.activeQuery.handleCommandComplete(msg, con);
+    });
+
+    //if a prepared statement has a name and properly parses
+    //we track that its already been executed so we don't parse
+    //it again on the same client
+    con.on('parseComplete', function(msg) {
+      if(self.activeQuery.name) {
+        con.parsedStatements[self.activeQuery.name] = true;
+      }
+    });
+
+    con.on('copyInResponse', function(msg) {
+      self.activeQuery.handleCopyInResponse(self.connection);
+    });
+
+    con.on('copyData', function (msg) {
+      self.activeQuery.handleCopyData(msg, self.connection);
+    });
+
+    con.on('notification', function(msg) {
+      self.emit('notification', msg);
+    });
+
+    //process possible callback argument to Client#connect
+    if (callback) {
+      callback(null, self);
+      //remove callback for proper error handling
+      //after the connect event
+      callback = null;
+    }
+    self.emit('connect');
+  });
+
+  con.on('readyForQuery', function() {
+    var activeQuery = self.activeQuery;
+    self.activeQuery = null;
+    self.readyForQuery = true;
+    self._pulseQueryQueue();
+    if(activeQuery) {
+      activeQuery.handleReadyForQuery(con);
+    }
+  });
+
+  con.on('error', function(error) {
+    if(this.activeQuery) {
+      var activeQuery = self.activeQuery;
+      this.activeQuery = null;
+      return activeQuery.handleError(error, con);
+    }
+
+    if (this._connecting) {
+      // set a flag indicating we've seen an error during connection
+      // the backend will terminate the connection and we don't want
+      // to throw a second error when the connection is terminated
+      this._connectionError = true;
+    }
+
+    if(!callback) {
+      return this.emit('error', error);
+    }
+
+    con.end(); // make sure ECONNRESET errors don't cause error events
+    callback(error);
+    callback = null;
+  }.bind(this));
+
+  con.once('end', function() {
+    if (callback) {
+      // haven't received a connection message yet!
+      var err = new Error('Connection terminated');
+      callback(err);
+      callback = null;
+      return;
+    }
+    if(this.activeQuery) {
+      var disconnectError = new Error('Connection terminated');
+      this.activeQuery.handleError(disconnectError, con);
+      this.activeQuery = null;
+    }
+    if (!this._ending) {
+      // if the connection is ended without us calling .end()
+      // on this client then we have an unexpected disconnection
+      // treat this as an error unless we've already emitted an error
+      // during connection.
+      if (!this._connectionError) {
+        this.emit('error', new Error('Connection terminated unexpectedly'));
+      }
+    }
+    this.emit('end');
+  }.bind(this));
+
+
+  con.on('notice', function(msg) {
+    self.emit('notice', msg);
+  });
+
+};
+
+Client.prototype.getStartupConf = function() {
+  var params = this.connectionParameters;
+
+  var data = {
+    user: params.user,
+    database: params.database
+  };
+
+  var appName = params.application_name || params.fallback_application_name;
+  if (appName) {
+    data.application_name = appName;
+  }
+  if (params.replication) {
+    data.replication = '' + params.replication;
+  }
+
+  return data;
+};
+
+Client.prototype.cancel = function(client, query) {
+  if(client.activeQuery == query) {
+    var con = this.connection;
+
+    if(this.host && this.host.indexOf('/') === 0) {
+      con.connect(this.host + '/.s.PGSQL.' + this.port);
+    } else {
+      con.connect(this.port, this.host);
+    }
+
+    //once connection is established send cancel message
+    con.on('connect', function() {
+      con.cancel(client.processID, client.secretKey);
+    });
+  } else if(client.queryQueue.indexOf(query) != -1) {
+    client.queryQueue.splice(client.queryQueue.indexOf(query), 1);
+  }
+};
+
+Client.prototype.setTypeParser = function(oid, format, parseFn) {
+  return this._types.setTypeParser(oid, format, parseFn);
+};
+
+Client.prototype.getTypeParser = function(oid, format) {
+  return this._types.getTypeParser(oid, format);
+};
+
+// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
+Client.prototype.escapeIdentifier = function(str) {
+
+  var escaped = '"';
+
+  for(var i = 0; i < str.length; i++) {
+    var c = str[i];
+    if(c === '"') {
+      escaped += c + c;
+    } else {
+      escaped += c;
+    }
+  }
+
+  escaped += '"';
+
+  return escaped;
+};
+
+// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
+Client.prototype.escapeLiteral = function(str) {
+
+  var hasBackslash = false;
+  var escaped = '\'';
+
+  for(var i = 0; i < str.length; i++) {
+    var c = str[i];
+    if(c === '\'') {
+      escaped += c + c;
+    } else if (c === '\\') {
+      escaped += c + c;
+      hasBackslash = true;
+    } else {
+      escaped += c;
+    }
+  }
+
+  escaped += '\'';
+
+  if(hasBackslash === true) {
+    escaped = ' E' + escaped;
+  }
+
+  return escaped;
+};
+
+Client.prototype._pulseQueryQueue = function() {
+  if(this.readyForQuery===true) {
+    this.activeQuery = this.queryQueue.shift();
+    if(this.activeQuery) {
+      this.readyForQuery = false;
+      this.hasExecuted = true;
+      this.activeQuery.submit(this.connection);
+    } else if(this.hasExecuted) {
+      this.activeQuery = null;
+      this.emit('drain');
+    }
+  }
+};
+
+Client.prototype.copyFrom = function (text) {
+  throw new Error("For PostgreSQL COPY TO/COPY FROM support npm install pg-copy-streams");
+};
+
+Client.prototype.copyTo = function (text) {
+  throw new Error("For PostgreSQL COPY TO/COPY FROM support npm install pg-copy-streams");
+};
+
+var DeprecatedEmitterQuery = utils.deprecateEventEmitter(Query);
+
+Client.prototype.query = function(config, values, callback) {
+  //can take in strings, config object or query object
+  var query = (typeof config.submit == 'function') ? config :
+     new DeprecatedEmitterQuery(config, values, callback);
+  if(this.binary && !query.binary) {
+    query.binary = true;
+  }
+  if(query._result) {
+    query._result._getTypeParser = this._types.getTypeParser.bind(this._types);
+  }
+
+  this.queryQueue.push(query);
+  this._pulseQueryQueue();
+  return query;
+};
+
+Client.prototype.end = function(cb) {
+  this._ending = true;
+  this.connection.end();
+  if (cb) {
+    this.connection.once('end', cb);
+  }
+};
+
+Client.md5 = function(string) {
+  return crypto.createHash('md5').update(string, 'utf-8').digest('hex');
+};
+
+// expose a Query constructor
+Client.Query = Query;
+
+module.exports = Client;
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/connection-parameters.js b/server/node_modules/pgtools/node_modules/pg/lib/connection-parameters.js
new file mode 100644
index 0000000000000000000000000000000000000000..e6efa158e164b6ecfa954e7daa59be24d9118f5b
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/connection-parameters.js
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var url = require('url');
+var dns = require('dns');
+
+var defaults = require('./defaults');
+
+var val = function(key, config, envVar) {
+  if (envVar === undefined) {
+    envVar = process.env[ 'PG' + key.toUpperCase() ];
+  } else if (envVar === false) {
+    // do nothing ... use false
+  } else {
+    envVar = process.env[ envVar ];
+  }
+
+  return config[key] ||
+    envVar ||
+    defaults[key];
+};
+
+//parses a connection string
+var parse = require('pg-connection-string').parse;
+
+var useSsl = function() {
+  switch(process.env.PGSSLMODE) {
+  case "disable":
+    return false;
+  case "prefer":
+  case "require":
+  case "verify-ca":
+  case "verify-full":
+    return true;
+  }
+  return defaults.ssl;
+};
+
+var ConnectionParameters = function(config) {
+  //if a string is passed, it is a raw connection string so we parse it into a config
+  config = typeof config == 'string' ? parse(config) : (config || {});
+  //if the config has a connectionString defined, parse IT into the config we use
+  //this will override other default values with what is stored in connectionString
+  if(config.connectionString) {
+    config = parse(config.connectionString);
+  }
+  this.user = val('user', config);
+  this.database = val('database', config);
+  this.port = parseInt(val('port', config), 10);
+  this.host = val('host', config);
+  this.password = val('password', config);
+  this.binary = val('binary', config);
+  this.ssl = typeof config.ssl === 'undefined' ? useSsl() : config.ssl;
+  this.client_encoding = val("client_encoding", config);
+  this.replication = val("replication", config);
+  //a domain socket begins with '/'
+  this.isDomainSocket = (!(this.host||'').indexOf('/'));
+
+  this.application_name = val('application_name', config, 'PGAPPNAME');
+  this.fallback_application_name = val('fallback_application_name', config, false);
+};
+
+// Convert arg to a string, surround in single quotes, and escape single quotes and backslashes
+var quoteParamValue = function(value) {
+  return "'" + ('' + value).replace(/\\/g, "\\\\").replace(/'/g, "\\'") + "'";
+};
+
+var add = function(params, config, paramName) {
+  var value = config[paramName];
+  if(value) {
+    params.push(paramName + "=" + quoteParamValue(value));
+  }
+};
+
+ConnectionParameters.prototype.getLibpqConnectionString = function(cb) {
+  var params = [];
+  add(params, this, 'user');
+  add(params, this, 'password');
+  add(params, this, 'port');
+  add(params, this, 'application_name');
+  add(params, this, 'fallback_application_name');
+
+  var ssl = typeof this.ssl === 'object' ? this.ssl : {sslmode: this.ssl};
+  add(params, ssl, 'sslmode');
+  add(params, ssl, 'sslca');
+  add(params, ssl, 'sslkey');
+  add(params, ssl, 'sslcert');
+  
+  if(this.database) {
+    params.push("dbname=" + quoteParamValue(this.database));
+  }
+  if(this.replication) {
+    params.push("replication=" + quoteParamValue(this.replication));
+  }
+  if(this.host) {
+    params.push("host=" + quoteParamValue(this.host));
+  }
+  if(this.isDomainSocket) {
+    return cb(null, params.join(' '));
+  }
+  if(this.client_encoding) {
+    params.push("client_encoding=" + quoteParamValue(this.client_encoding));
+  }
+  dns.lookup(this.host, function(err, address) {
+    if(err) return cb(err, null);
+    params.push("hostaddr=" + quoteParamValue(address));
+    return cb(null, params.join(' '));
+  });
+};
+
+module.exports = ConnectionParameters;
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/connection.js b/server/node_modules/pgtools/node_modules/pg/lib/connection.js
new file mode 100644
index 0000000000000000000000000000000000000000..0fb874cf5ad0402c97934c89ed60234c8090d4ef
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/connection.js
@@ -0,0 +1,668 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var net = require('net');
+var EventEmitter = require('events').EventEmitter;
+var util = require('util');
+
+var Writer = require('buffer-writer');
+var Reader = require('packet-reader');
+
+var indexOf =
+  'indexOf' in Buffer.prototype ?
+    function indexOf(buffer, value, start) {
+      return buffer.indexOf(value, start);
+    } :
+    function indexOf(buffer, value, start) {
+      for (var i = start, len = buffer.length; i < len; i++) {
+        if (buffer[i] === value) {
+          return i;
+        }
+      }
+
+      return -1;
+    };
+
+var TEXT_MODE = 0;
+var BINARY_MODE = 1;
+var Connection = function(config) {
+  EventEmitter.call(this);
+  config = config || {};
+  this.stream = config.stream || new net.Stream();
+  this._keepAlive = config.keepAlive;
+  this.lastBuffer = false;
+  this.lastOffset = 0;
+  this.buffer = null;
+  this.offset = null;
+  this.encoding = config.client_encoding || 'utf8';
+  this.parsedStatements = {};
+  this.writer = new Writer();
+  this.ssl = config.ssl || false;
+  this._ending = false;
+  this._mode = TEXT_MODE;
+  this._emitMessage = false;
+  this._reader = new Reader({
+    headerSize: 1,
+    lengthPadding: -4
+  });
+  var self = this;
+  this.on('newListener', function(eventName) {
+    if(eventName == 'message') {
+      self._emitMessage = true;
+    }
+  });
+};
+
+util.inherits(Connection, EventEmitter);
+
+Connection.prototype.connect = function(port, host) {
+
+  if(this.stream.readyState === 'closed') {
+    this.stream.connect(port, host);
+  } else if(this.stream.readyState == 'open') {
+    this.emit('connect');
+  }
+
+  var self = this;
+
+  this.stream.on('connect', function() {
+    if (self._keepAlive) {
+      self.stream.setKeepAlive(true);
+    }
+    self.emit('connect');
+  });
+
+  this.stream.on('error', function(error) {
+    //don't raise ECONNRESET errors - they can & should be ignored
+    //during disconnect
+    if(self._ending && error.code == 'ECONNRESET') {
+      return;
+    }
+    self.emit('error', error);
+  });
+
+  this.stream.on('close', function() {
+    self.emit('end');
+  });
+
+  if(!this.ssl) {
+    return this.attachListeners(this.stream);
+  }
+
+  this.stream.once('data', function(buffer) {
+    var responseCode = buffer.toString('utf8');
+    if(responseCode != 'S') {
+      return self.emit('error', new Error('The server does not support SSL connections'));
+    }
+    var tls = require('tls');
+    self.stream = tls.connect({
+      socket: self.stream,
+      servername: host,
+      rejectUnauthorized: self.ssl.rejectUnauthorized,
+      ca: self.ssl.ca,
+      pfx: self.ssl.pfx,
+      key: self.ssl.key,
+      passphrase: self.ssl.passphrase,
+      cert: self.ssl.cert,
+      NPNProtocols: self.ssl.NPNProtocols
+    });
+    self.attachListeners(self.stream);
+    self.emit('sslconnect');
+
+    self.stream.on('error', function(error){
+      self.emit('error', error);
+    });
+  });
+};
+
+Connection.prototype.attachListeners = function(stream) {
+  var self = this;
+  stream.on('data', function(buff) {
+    self._reader.addChunk(buff);
+    var packet = self._reader.read();
+    while(packet) {
+      var msg = self.parseMessage(packet);
+      if(self._emitMessage) {
+        self.emit('message', msg);
+      }
+      self.emit(msg.name, msg);
+      packet = self._reader.read();
+    }
+  });
+  stream.on('end', function() {
+    self.emit('end');
+  });
+};
+
+Connection.prototype.requestSsl = function() {
+  var bodyBuffer = this.writer
+    .addInt16(0x04D2)
+    .addInt16(0x162F).flush();
+
+  var length = bodyBuffer.length + 4;
+
+  var buffer = new Writer()
+    .addInt32(length)
+    .add(bodyBuffer)
+    .join();
+  this.stream.write(buffer);
+};
+
+Connection.prototype.startup = function(config) {
+  var writer = this.writer
+    .addInt16(3)
+    .addInt16(0)
+  ;
+
+  Object.keys(config).forEach(function(key){
+    var val = config[key];
+    writer.addCString(key).addCString(val);
+  });
+
+  writer.addCString('client_encoding').addCString("'utf-8'");
+
+  var bodyBuffer = writer.addCString('').flush();
+  //this message is sent without a code
+
+  var length = bodyBuffer.length + 4;
+
+  var buffer = new Writer()
+    .addInt32(length)
+    .add(bodyBuffer)
+    .join();
+  this.stream.write(buffer);
+};
+
+Connection.prototype.cancel = function(processID, secretKey) {
+  var bodyBuffer = this.writer
+    .addInt16(1234)
+    .addInt16(5678)
+    .addInt32(processID)
+    .addInt32(secretKey)
+    .flush();
+
+  var length = bodyBuffer.length + 4;
+
+  var buffer = new Writer()
+    .addInt32(length)
+    .add(bodyBuffer)
+    .join();
+  this.stream.write(buffer);
+};
+
+Connection.prototype.password = function(password) {
+  //0x70 = 'p'
+  this._send(0x70, this.writer.addCString(password));
+};
+
+Connection.prototype._send = function(code, more) {
+  if(!this.stream.writable) { return false; }
+  if(more === true) {
+    this.writer.addHeader(code);
+  } else {
+    return this.stream.write(this.writer.flush(code));
+  }
+};
+
+Connection.prototype.query = function(text) {
+  //0x51 = Q
+  this.stream.write(this.writer.addCString(text).flush(0x51));
+};
+
+//send parse message
+//"more" === true to buffer the message until flush() is called
+Connection.prototype.parse = function(query, more) {
+  //expect something like this:
+  // { name: 'queryName',
+  //   text: 'select * from blah',
+  //   types: ['int8', 'bool'] }
+
+  //normalize missing query names to allow for null
+  query.name = query.name || '';
+  if (query.name.length > 63) {
+    console.error('Warning! Postgres only supports 63 characters for query names.');
+    console.error('You supplied', query.name, '(', query.name.length, ')');
+    console.error('This can cause conflicts and silent errors executing queries');
+  }
+  //normalize null type array
+  query.types = query.types || [];
+  var len = query.types.length;
+  var buffer = this.writer
+    .addCString(query.name) //name of query
+    .addCString(query.text) //actual query text
+    .addInt16(len);
+  for(var i = 0; i < len; i++) {
+    buffer.addInt32(query.types[i]);
+  }
+
+  var code = 0x50;
+  this._send(code, more);
+};
+
+//send bind message
+//"more" === true to buffer the message until flush() is called
+Connection.prototype.bind = function(config, more) {
+  //normalize config
+  config = config || {};
+  config.portal = config.portal || '';
+  config.statement = config.statement || '';
+  config.binary = config.binary || false;
+  var values = config.values || [];
+  var len = values.length;
+  var useBinary = false;
+  for (var j = 0; j < len; j++)
+    useBinary |= values[j] instanceof Buffer;
+  var buffer = this.writer
+    .addCString(config.portal)
+    .addCString(config.statement);
+  if (!useBinary)
+    buffer.addInt16(0);
+  else {
+    buffer.addInt16(len);
+    for (j = 0; j < len; j++)
+      buffer.addInt16(values[j] instanceof Buffer);
+  }
+  buffer.addInt16(len);
+  for(var i = 0; i < len; i++) {
+    var val = values[i];
+    if(val === null || typeof val === "undefined") {
+      buffer.addInt32(-1);
+    } else if (val instanceof Buffer) {
+      buffer.addInt32(val.length);
+      buffer.add(val);
+    } else {
+      buffer.addInt32(Buffer.byteLength(val));
+      buffer.addString(val);
+    }
+  }
+
+  if(config.binary) {
+    buffer.addInt16(1); // format codes to use binary
+    buffer.addInt16(1);
+  }
+  else {
+    buffer.addInt16(0); // format codes to use text
+  }
+  //0x42 = 'B'
+  this._send(0x42, more);
+};
+
+//send execute message
+//"more" === true to buffer the message until flush() is called
+Connection.prototype.execute = function(config, more) {
+  config = config || {};
+  config.portal = config.portal || '';
+  config.rows = config.rows || '';
+  this.writer
+    .addCString(config.portal)
+    .addInt32(config.rows);
+
+  //0x45 = 'E'
+  this._send(0x45, more);
+};
+
+var emptyBuffer = Buffer(0);
+
+Connection.prototype.flush = function() {
+  //0x48 = 'H'
+  this.writer.add(emptyBuffer);
+  this._send(0x48);
+};
+
+Connection.prototype.sync = function() {
+  //clear out any pending data in the writer
+  this.writer.flush(0);
+
+  this.writer.add(emptyBuffer);
+  this._ending = true;
+  this._send(0x53);
+};
+
+Connection.prototype.end = function() {
+  //0x58 = 'X'
+  this.writer.add(emptyBuffer);
+  this._ending = true;
+  this._send(0x58);
+};
+
+Connection.prototype.close = function(msg, more) {
+  this.writer.addCString(msg.type + (msg.name || ''));
+  this._send(0x43, more);
+};
+
+Connection.prototype.describe = function(msg, more) {
+  this.writer.addCString(msg.type + (msg.name || ''));
+  this._send(0x44, more);
+};
+
+Connection.prototype.sendCopyFromChunk = function (chunk) {
+  this.stream.write(this.writer.add(chunk).flush(0x64));
+};
+
+Connection.prototype.endCopyFrom = function () {
+  this.stream.write(this.writer.add(emptyBuffer).flush(0x63));
+};
+
+Connection.prototype.sendCopyFail = function (msg) {
+  //this.stream.write(this.writer.add(emptyBuffer).flush(0x66));
+  this.writer.addCString(msg);
+  this._send(0x66);
+};
+
+var Message = function(name, length) {
+  this.name = name;
+  this.length = length;
+};
+
+Connection.prototype.parseMessage =  function(buffer) {
+
+  this.offset = 0;
+  var length = buffer.length + 4;
+  switch(this._reader.header)
+  {
+
+  case 0x52: //R
+    return this.parseR(buffer, length);
+
+  case 0x53: //S
+    return this.parseS(buffer, length);
+
+  case 0x4b: //K
+    return this.parseK(buffer, length);
+
+  case 0x43: //C
+    return this.parseC(buffer, length);
+
+  case 0x5a: //Z
+    return this.parseZ(buffer, length);
+
+  case 0x54: //T
+    return this.parseT(buffer, length);
+
+  case 0x44: //D
+    return this.parseD(buffer, length);
+
+  case 0x45: //E
+    return this.parseE(buffer, length);
+
+  case 0x4e: //N
+    return this.parseN(buffer, length);
+
+  case 0x31: //1
+    return new Message('parseComplete', length);
+
+  case 0x32: //2
+    return new Message('bindComplete', length);
+
+  case 0x33: //3
+    return new Message('closeComplete', length);
+
+  case 0x41: //A
+    return this.parseA(buffer, length);
+
+  case 0x6e: //n
+    return new Message('noData', length);
+
+  case 0x49: //I
+    return new Message('emptyQuery', length);
+
+  case 0x73: //s
+    return new Message('portalSuspended', length);
+
+  case 0x47: //G
+    return this.parseG(buffer, length);
+
+  case 0x48: //H
+    return this.parseH(buffer, length);
+
+  case 0x57: //W
+    return new Message('replicationStart', length);
+
+  case 0x63: //c
+    return new Message('copyDone', length);
+
+  case 0x64: //d
+    return this.parsed(buffer, length);
+  }
+};
+
+Connection.prototype.parseR = function(buffer, length) {
+  var code = 0;
+  var msg = new Message('authenticationOk', length);
+  if(msg.length === 8) {
+    code = this.parseInt32(buffer);
+    if(code === 3) {
+      msg.name = 'authenticationCleartextPassword';
+    }
+    return msg;
+  }
+  if(msg.length === 12) {
+    code = this.parseInt32(buffer);
+    if(code === 5) { //md5 required
+      msg.name = 'authenticationMD5Password';
+      msg.salt = new Buffer(4);
+      buffer.copy(msg.salt, 0, this.offset, this.offset + 4);
+      this.offset += 4;
+      return msg;
+    }
+  }
+  throw new Error("Unknown authenticationOk message type" + util.inspect(msg));
+};
+
+Connection.prototype.parseS = function(buffer, length) {
+  var msg = new Message('parameterStatus', length);
+  msg.parameterName = this.parseCString(buffer);
+  msg.parameterValue = this.parseCString(buffer);
+  return msg;
+};
+
+Connection.prototype.parseK = function(buffer, length) {
+  var msg = new Message('backendKeyData', length);
+  msg.processID = this.parseInt32(buffer);
+  msg.secretKey = this.parseInt32(buffer);
+  return msg;
+};
+
+Connection.prototype.parseC = function(buffer, length) {
+  var msg = new Message('commandComplete', length);
+  msg.text = this.parseCString(buffer);
+  return msg;
+};
+
+Connection.prototype.parseZ = function(buffer, length) {
+  var msg = new Message('readyForQuery', length);
+  msg.name = 'readyForQuery';
+  msg.status = this.readString(buffer, 1);
+  return msg;
+};
+
+var ROW_DESCRIPTION = 'rowDescription';
+Connection.prototype.parseT = function(buffer, length) {
+  var msg = new Message(ROW_DESCRIPTION, length);
+  msg.fieldCount = this.parseInt16(buffer);
+  var fields = [];
+  for(var i = 0; i < msg.fieldCount; i++){
+    fields.push(this.parseField(buffer));
+  }
+  msg.fields = fields;
+  return msg;
+};
+
+var Field = function() {
+  this.name = null;
+  this.tableID = null;
+  this.columnID = null;
+  this.dataTypeID = null;
+  this.dataTypeSize = null;
+  this.dataTypeModifier = null;
+  this.format = null;
+};
+
+var FORMAT_TEXT = 'text';
+var FORMAT_BINARY = 'binary';
+Connection.prototype.parseField = function(buffer) {
+  var field = new Field();
+  field.name = this.parseCString(buffer);
+  field.tableID = this.parseInt32(buffer);
+  field.columnID = this.parseInt16(buffer);
+  field.dataTypeID = this.parseInt32(buffer);
+  field.dataTypeSize = this.parseInt16(buffer);
+  field.dataTypeModifier = this.parseInt32(buffer);
+  if(this.parseInt16(buffer) === TEXT_MODE) {
+    this._mode = TEXT_MODE;
+    field.format = FORMAT_TEXT;
+  } else {
+    this._mode = BINARY_MODE;
+    field.format = FORMAT_BINARY;
+  }
+  return field;
+};
+
+var DATA_ROW = 'dataRow';
+var DataRowMessage = function(length, fieldCount) {
+  this.name = DATA_ROW;
+  this.length = length;
+  this.fieldCount = fieldCount;
+  this.fields = [];
+};
+
+
+//extremely hot-path code
+Connection.prototype.parseD = function(buffer, length) {
+  var fieldCount = this.parseInt16(buffer);
+  var msg = new DataRowMessage(length, fieldCount);
+  for(var i = 0; i < fieldCount; i++) {
+    msg.fields.push(this._readValue(buffer));
+  }
+  return msg;
+};
+
+//extremely hot-path code
+Connection.prototype._readValue = function(buffer) {
+  var length = this.parseInt32(buffer);
+  if(length === -1) return null;
+  if(this._mode === TEXT_MODE) {
+    return this.readString(buffer, length);
+  }
+  return this.readBytes(buffer, length);
+};
+
+//parses error
+Connection.prototype.parseE = function(buffer, length) {
+  var fields = {};
+  var msg, item;
+  var input = new Message('error', length);
+  var fieldType = this.readString(buffer, 1);
+  while(fieldType != '\0') {
+    fields[fieldType] = this.parseCString(buffer);
+    fieldType = this.readString(buffer, 1);
+  }
+  if(input.name === 'error') {
+    // the msg is an Error instance
+    msg = new Error(fields.M);
+    for (item in input) {
+      // copy input properties to the error
+      if(input.hasOwnProperty(item)) {
+        msg[item] = input[item];
+      }
+    }
+  } else {
+    // the msg is an object literal
+    msg = input;
+    msg.message = fields.M;
+  }
+  msg.severity = fields.S;
+  msg.code = fields.C;
+  msg.detail = fields.D;
+  msg.hint = fields.H;
+  msg.position = fields.P;
+  msg.internalPosition = fields.p;
+  msg.internalQuery = fields.q;
+  msg.where = fields.W;
+  msg.schema = fields.s;
+  msg.table = fields.t;
+  msg.column = fields.c;
+  msg.dataType = fields.d;
+  msg.constraint = fields.n;
+  msg.file = fields.F;
+  msg.line = fields.L;
+  msg.routine = fields.R;
+  return msg;
+};
+
+//same thing, different name
+Connection.prototype.parseN = function(buffer, length) {
+  var msg = this.parseE(buffer, length);
+  msg.name = 'notice';
+  return msg;
+};
+
+Connection.prototype.parseA = function(buffer, length) {
+  var msg = new Message('notification', length);
+  msg.processId = this.parseInt32(buffer);
+  msg.channel = this.parseCString(buffer);
+  msg.payload = this.parseCString(buffer);
+  return msg;
+};
+
+Connection.prototype.parseG = function (buffer, length) {
+  var msg = new Message('copyInResponse', length);
+  return this.parseGH(buffer, msg);
+};
+
+Connection.prototype.parseH = function(buffer, length) {
+  var msg = new Message('copyOutResponse', length);
+  return this.parseGH(buffer, msg);
+};
+
+Connection.prototype.parseGH = function (buffer, msg) {
+  var isBinary = buffer[this.offset] !== 0;
+  this.offset++;
+  msg.binary = isBinary;
+  var columnCount = this.parseInt16(buffer);
+  msg.columnTypes = [];
+  for(var i = 0; i<columnCount; i++) {
+    msg.columnTypes.push(this.parseInt16(buffer));
+  }
+  return msg;
+};
+
+Connection.prototype.parsed = function (buffer, length) {
+  var msg = new Message('copyData', length);
+  msg.chunk = this.readBytes(buffer, msg.length - 4);
+  return msg;
+};
+
+Connection.prototype.parseInt32 = function(buffer) {
+  var value = buffer.readInt32BE(this.offset, true);
+  this.offset += 4;
+  return value;
+};
+
+Connection.prototype.parseInt16 = function(buffer) {
+  var value = buffer.readInt16BE(this.offset, true);
+  this.offset += 2;
+  return value;
+};
+
+Connection.prototype.readString = function(buffer, length) {
+  return buffer.toString(this.encoding, this.offset, (this.offset += length));
+};
+
+Connection.prototype.readBytes = function(buffer, length) {
+  return buffer.slice(this.offset, this.offset += length);
+};
+
+Connection.prototype.parseCString = function(buffer) {
+  var start = this.offset;
+  var end = indexOf(buffer, 0, start);
+  this.offset = end + 1;
+  return buffer.toString(this.encoding, start, end);
+};
+//end parsing methods
+module.exports = Connection;
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/defaults.js b/server/node_modules/pgtools/node_modules/pg/lib/defaults.js
new file mode 100644
index 0000000000000000000000000000000000000000..b94d33f3c91e296f618a999c69091a9ac033e8ba
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/defaults.js
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var defaults = module.exports = {
+  // database host. defaults to localhost
+  host: 'localhost',
+
+  //database user's name
+  user: process.platform === 'win32' ? process.env.USERNAME : process.env.USER,
+
+  //name of database to connect
+  database: process.platform === 'win32' ? process.env.USERNAME : process.env.USER,
+
+  //database user's password
+  password: null,
+
+  // a Postgres connection string to be used instead of setting individual connection items
+  // NOTE:  Setting this value will cause it to override any other value (such as database or user) defined
+  // in the defaults object.
+  connectionString : undefined,
+
+  //database port
+  port: 5432,
+
+  //number of rows to return at a time from a prepared statement's
+  //portal. 0 will return all rows at once
+  rows: 0,
+
+  // binary result mode
+  binary: false,
+
+  //Connection pool options - see https://github.com/coopernurse/node-pool
+  //number of connections to use in connection pool
+  //0 will disable connection pooling
+  poolSize: 10,
+
+  //max milliseconds a client can go unused before it is removed
+  //from the pool and destroyed
+  poolIdleTimeout: 30000,
+
+  //frequency to check for idle clients within the client pool
+  reapIntervalMillis: 1000,
+
+  //if true the most recently released resources will be the first to be allocated
+  returnToHead: false,
+
+  //pool log function / boolean
+  poolLog: false,
+
+  client_encoding: "",
+
+  ssl: false,
+
+  application_name: undefined,
+  fallback_application_name: undefined,
+
+  parseInputDatesAsUTC: false
+};
+
+var pgTypes = require('pg-types');
+// save default parsers
+var parseBigInteger = pgTypes.getTypeParser(20, 'text');
+var parseBigIntegerArray = pgTypes.getTypeParser(1016, 'text');
+
+//parse int8 so you can get your count values as actual numbers
+module.exports.__defineSetter__("parseInt8", function(val) {
+  pgTypes.setTypeParser(20, 'text', val ? pgTypes.getTypeParser(23, 'text') : parseBigInteger);
+  pgTypes.setTypeParser(1016, 'text', val ? pgTypes.getTypeParser(1007, 'text') : parseBigIntegerArray);
+});
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/index.js b/server/node_modules/pgtools/node_modules/pg/lib/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..17abb5bc85b19b77280505933e0b4adc1969cf8c
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/index.js
@@ -0,0 +1,114 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var EventEmitter = require('events').EventEmitter;
+var util = require('util');
+var Client = require('./client');
+var defaults =  require('./defaults');
+var Connection = require('./connection');
+var ConnectionParameters = require('./connection-parameters');
+var poolFactory = require('./pool-factory');
+
+var PG = function(clientConstructor) {
+  EventEmitter.call(this);
+  this.defaults = defaults;
+  this.Client = clientConstructor;
+  this.Query = this.Client.Query;
+  this.Pool = poolFactory(this.Client);
+  this._pools = [];
+  this.Connection = Connection;
+  this.types = require('pg-types');
+};
+
+util.inherits(PG, EventEmitter);
+
+PG.prototype.end = util.deprecate(function() {
+  var self = this;
+  var keys = Object.keys(this._pools);
+  var count = keys.length;
+  if(count === 0) {
+    self.emit('end');
+  } else {
+    keys.forEach(function(key) {
+      var pool = self._pools[key];
+      delete self._pools[key];
+      pool.pool.drain(function() {
+        pool.pool.destroyAllNow(function() {
+          count--;
+          if(count === 0) {
+            self.emit('end');
+          }
+        });
+      });
+    });
+  }
+}, 'PG.end is deprecated - please see the upgrade guide at https://node-postgres.com/guides/upgrading');
+
+PG.prototype.connect = util.deprecate(function(config, callback) {
+  if(typeof config == "function") {
+    callback = config;
+    config = null;
+  }
+  if (typeof config == 'string') {
+    config = new ConnectionParameters(config);
+  }
+
+  config = config || {};
+
+  //for backwards compatibility
+  config.max = config.max || config.poolSize || defaults.poolSize;
+  config.idleTimeoutMillis = config.idleTimeoutMillis || config.poolIdleTimeout || defaults.poolIdleTimeout;
+  config.log = config.log || config.poolLog || defaults.poolLog;
+
+  var poolName = JSON.stringify(config);
+  this._pools[poolName] = this._pools[poolName] || new this.Pool(config);
+  var pool = this._pools[poolName];
+  if(!pool.listeners('error').length) {
+    //propagate errors up to pg object
+    pool.on('error', function(e) {
+      this.emit('error', e, e.client);
+    }.bind(this));
+  }
+  return pool.connect(callback);
+}, 'PG.connect is deprecated - please see the upgrade guide at https://node-postgres.com/guides/upgrading');
+
+// cancel the query running on the given client
+PG.prototype.cancel = util.deprecate(function(config, client, query) {
+  if(client.native) {
+    return client.cancel(query);
+  }
+  var c = config;
+  //allow for no config to be passed
+  if(typeof c === 'function') {
+    c = defaults;
+  }
+  var cancellingClient = new this.Client(c);
+  cancellingClient.cancel(client, query);
+}, 'PG.cancel is deprecated - use client.cancel instead');
+
+if(typeof process.env.NODE_PG_FORCE_NATIVE != 'undefined') {
+  module.exports = new PG(require('./native'));
+} else {
+  module.exports = new PG(Client);
+
+  //lazy require native module...the native module may not have installed
+  module.exports.__defineGetter__("native", function() {
+    delete module.exports.native;
+    var native = null;
+    try {
+      native = new PG(require('./native'));
+    } catch (err) {
+      if (err.code !== 'MODULE_NOT_FOUND') {
+        throw err;
+      }
+      console.error(err.message);
+    }
+    module.exports.native = native;
+    return native;
+  });
+}
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/native/index.js b/server/node_modules/pgtools/node_modules/pg/lib/native/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..47350098468e9f4dc381d6f38207f6f46253d5d0
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/native/index.js
@@ -0,0 +1,234 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var Native = require('pg-native');
+var TypeOverrides = require('../type-overrides');
+var semver = require('semver');
+var pkg = require('../../package.json');
+var assert = require('assert');
+var EventEmitter = require('events').EventEmitter;
+var util = require('util');
+var ConnectionParameters = require('../connection-parameters');
+
+var msg = 'Version >= ' + pkg.minNativeVersion + ' of pg-native required.';
+assert(semver.gte(Native.version, pkg.minNativeVersion), msg);
+
+var NativeQuery = require('./query');
+
+var Client = module.exports = function(config) {
+  EventEmitter.call(this);
+  config = config || {};
+
+  this._types = new TypeOverrides(config.types);
+
+  this.native = new Native({
+    types: this._types
+  });
+
+  this._queryQueue = [];
+  this._connected = false;
+
+  //keep these on the object for legacy reasons
+  //for the time being. TODO: deprecate all this jazz
+  var cp = this.connectionParameters = new ConnectionParameters(config);
+  this.user = cp.user;
+  this.password = cp.password;
+  this.database = cp.database;
+  this.host = cp.host;
+  this.port = cp.port;
+
+  //a hash to hold named queries
+  this.namedQueries = {};
+};
+
+Client.Query = NativeQuery;
+
+util.inherits(Client, EventEmitter);
+
+//connect to the backend
+//pass an optional callback to be called once connected
+//or with an error if there was a connection error
+//if no callback is passed and there is a connection error
+//the client will emit an error event.
+Client.prototype.connect = function(cb) {
+  var self = this;
+
+  var onError = function(err) {
+    if(cb) return cb(err);
+    return self.emit('error', err);
+  };
+
+  this.connectionParameters.getLibpqConnectionString(function(err, conString) {
+    if(err) return onError(err);
+    self.native.connect(conString, function(err) {
+      if(err) return onError(err);
+
+      //set internal states to connected
+      self._connected = true;
+
+      //handle connection errors from the native layer
+      self.native.on('error', function(err) {
+        //error will be handled by active query
+        if(self._activeQuery && self._activeQuery.state != 'end') {
+          return;
+        }
+        self.emit('error', err);
+      });
+
+      self.native.on('notification', function(msg) {
+        self.emit('notification', {
+          channel: msg.relname,
+          payload: msg.extra
+        });
+      });
+
+      //signal we are connected now
+      self.emit('connect');
+      self._pulseQueryQueue(true);
+
+      //possibly call the optional callback
+      if(cb) cb();
+    });
+  });
+};
+
+//send a query to the server
+//this method is highly overloaded to take
+//1) string query, optional array of parameters, optional function callback
+//2) object query with {
+//    string query
+//    optional array values,
+//    optional function callback instead of as a separate parameter
+//    optional string name to name & cache the query plan
+//    optional string rowMode = 'array' for an array of results
+//  }
+Client.prototype.query = function(config, values, callback) {
+  var query = new NativeQuery(this.native);
+
+  //support query('text', ...) style calls
+  if(typeof config == 'string') {
+    query.text = config;
+  }
+
+  //support passing everything in via a config object
+  if(typeof config == 'object') {
+    query.text = config.text;
+    query.values = config.values;
+    query.name = config.name;
+    query.callback = config.callback;
+    query._arrayMode = config.rowMode == 'array';
+  }
+
+  //support query({...}, function() {}) style calls
+  //& support query(..., ['values'], ...) style calls
+  if(typeof values == 'function') {
+    query.callback = values;
+  }
+  else if(util.isArray(values)) {
+    query.values = values;
+  }
+  if(typeof callback == 'function') {
+    query.callback = callback;
+  }
+
+  this._queryQueue.push(query);
+  this._pulseQueryQueue();
+  return query;
+};
+
+var DeprecatedQuery = require('../utils').deprecateEventEmitter(NativeQuery);
+
+//send a query to the server
+//this method is highly overloaded to take
+//1) string query, optional array of parameters, optional function callback
+//2) object query with {
+//    string query
+//    optional array values,
+//    optional function callback instead of as a separate parameter
+//    optional string name to name & cache the query plan
+//    optional string rowMode = 'array' for an array of results
+//  }
+Client.prototype.query = function(config, values, callback) {
+  if (typeof config.submit == 'function') {
+    // accept query(new Query(...), (err, res) => { }) style
+    if (typeof values == 'function') {
+      config.callback = values;
+    }
+    this._queryQueue.push(config);
+    this._pulseQueryQueue();
+    return config;
+  }
+
+  var query = new DeprecatedQuery(config, values, callback);
+  this._queryQueue.push(query);
+  this._pulseQueryQueue();
+  return query;
+};
+
+//disconnect from the backend server
+Client.prototype.end = function(cb) {
+  var self = this;
+  if(!this._connected) {
+    this.once('connect', this.end.bind(this, cb));
+  }
+  this.native.end(function() {
+    //send an error to the active query
+    if(self._hasActiveQuery()) {
+      var msg = 'Connection terminated';
+      self._queryQueue.length = 0;
+      self._activeQuery.handleError(new Error(msg));
+    }
+    self.emit('end');
+    if(cb) cb();
+  });
+};
+
+Client.prototype._hasActiveQuery = function() {
+  return this._activeQuery && this._activeQuery.state != 'error' && this._activeQuery.state != 'end';
+};
+
+Client.prototype._pulseQueryQueue = function(initialConnection) {
+  if(!this._connected) {
+    return;
+  }
+  if(this._hasActiveQuery()) {
+    return;
+  }
+  var query = this._queryQueue.shift();
+  if(!query) {
+    if(!initialConnection) {
+      this.emit('drain');
+    }
+    return;
+  }
+  this._activeQuery = query;
+  query.submit(this);
+  var self = this;
+  var pulseOnDone = function() {
+    self._pulseQueryQueue();
+    query.removeListener('_done', pulseOnDone);
+  };
+  query._on('_done', pulseOnDone);
+};
+
+//attempt to cancel an in-progress query
+Client.prototype.cancel = function(query) {
+  if(this._activeQuery == query) {
+    this.native.cancel(function() {});
+  } else if (this._queryQueue.indexOf(query) != -1) {
+    this._queryQueue.splice(this._queryQueue.indexOf(query), 1);
+  }
+};
+
+Client.prototype.setTypeParser = function(oid, format, parseFn) {
+  return this._types.setTypeParser(oid, format, parseFn);
+};
+
+Client.prototype.getTypeParser = function(oid, format) {
+  return this._types.getTypeParser(oid, format);
+};
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/native/query.js b/server/node_modules/pgtools/node_modules/pg/lib/native/query.js
new file mode 100644
index 0000000000000000000000000000000000000000..88e19f5f996f416cd91cea99679ee4a5c23e824a
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/native/query.js
@@ -0,0 +1,160 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var EventEmitter = require('events').EventEmitter;
+var util = require('util');
+var utils = require('../utils');
+var NativeResult = require('./result');
+
+var NativeQuery = module.exports = function(config, values, callback) {
+  EventEmitter.call(this);
+  config = utils.normalizeQueryConfig(config, values, callback);
+  this.text = config.text;
+  this.values = config.values;
+  this.name = config.name;
+  this.callback = config.callback;
+  this.state = 'new';
+  this._arrayMode = config.rowMode == 'array';
+
+  //if the 'row' event is listened for
+  //then emit them as they come in
+  //without setting singleRowMode to true
+  //this has almost no meaning because libpq
+  //reads all rows into memory befor returning any
+  this._emitRowEvents = false;
+  this._on('newListener', function(event) {
+    if(event === 'row') this._emitRowEvents = true;
+  }.bind(this));
+};
+
+util.inherits(NativeQuery, EventEmitter);
+
+// TODO - remove in 7.0
+// this maintains backwards compat so someone could instantiate a query
+// manually: `new Query().then()`...
+NativeQuery._on = NativeQuery.on;
+NativeQuery._once = NativeQuery.once;
+
+
+NativeQuery.prototype.then = function(onSuccess, onFailure) {
+  return this._getPromise().then(onSuccess, onFailure);
+};
+
+NativeQuery.prototype.catch = function(callback) {
+  return this._getPromise().catch(callback);
+};
+
+NativeQuery.prototype._getPromise = function() {
+  if (this._promise) return this._promise;
+  this._promise = new Promise(function(resolve, reject) {
+    var onEnd = function (result) {
+      this.removeListener('error', onError);
+      this.removeListener('end', onEnd);
+      resolve(result);
+    };
+    var onError = function (err) {
+      this.removeListener('error', onError);
+      this.removeListener('end', onEnd);
+      reject(err);
+    };
+    this._on('end', onEnd);
+    this._on('error', onError);
+  }.bind(this));
+  return this._promise;
+};
+
+NativeQuery.prototype.promise = util.deprecate(function() {
+  return this._getPromise();
+}, 'Query.promise() is deprecated - see the upgrade guide at https://node-postgres.com/guides/upgrading');
+
+NativeQuery.prototype.handleError = function(err) {
+  var self = this;
+  //copy pq error fields into the error object
+  var fields = self.native.pq.resultErrorFields();
+  if(fields) {
+    for(var key in fields) {
+      err[key] = fields[key];
+    }
+  }
+  if(self.callback) {
+    self.callback(err);
+  } else {
+    self.emit('error', err);
+  }
+  self.state = 'error';
+};
+
+NativeQuery.prototype.submit = function(client) {
+  this.state = 'running';
+  var self = this;
+  self.native = client.native;
+  client.native.arrayMode = this._arrayMode;
+
+  var after = function(err, rows) {
+    client.native.arrayMode = false;
+    setImmediate(function() {
+      self.emit('_done');
+    });
+
+    //handle possible query error
+    if(err) {
+      return self.handleError(err);
+    }
+
+    var result = new NativeResult();
+    result.addCommandComplete(self.native.pq);
+    result.rows = rows;
+
+    //emit row events for each row in the result
+    if(self._emitRowEvents) {
+      rows.forEach(function(row) {
+        self.emit('row', row, result);
+      });
+    }
+
+
+    //handle successful result
+    self.state = 'end';
+    self.emit('end', result);
+    if(self.callback) {
+      self.callback(null, result);
+    }
+  };
+
+  if(process.domain) {
+    after = process.domain.bind(after);
+  }
+
+  //named query
+  if(this.name) {
+    if (this.name.length > 63) {
+      console.error('Warning! Postgres only supports 63 characters for query names.');
+      console.error('You supplied', this.name, '(', this.name.length, ')');
+      console.error('This can cause conflicts and silent errors executing queries');
+    }
+    var values = (this.values||[]).map(utils.prepareValue);
+
+    //check if the client has already executed this named query
+    //if so...just execute it again - skip the planning phase
+    if(client.namedQueries[this.name]) {
+      return this.native.execute(this.name, values, after);
+    }
+    //plan the named query the first time, then execute it
+    return this.native.prepare(this.name, this.text, values.length, function(err) {
+      if(err) return after(err);
+      client.namedQueries[self.name] = true;
+      return self.native.execute(self.name, values, after);
+    });
+  }
+  else if(this.values) {
+    var vals = this.values.map(utils.prepareValue);
+    this.native.query(this.text, vals, after);
+  } else {
+    this.native.query(this.text, after);
+  }
+};
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/native/result.js b/server/node_modules/pgtools/node_modules/pg/lib/native/result.js
new file mode 100644
index 0000000000000000000000000000000000000000..519037316fe72da674f88b005f1d00c816f71b88
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/native/result.js
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var NativeResult = module.exports = function(pq) {
+  this.command = null;
+  this.rowCount = 0;
+  this.rows = null;
+  this.fields = null;
+};
+
+NativeResult.prototype.addCommandComplete = function(pq) {
+  this.command = pq.cmdStatus().split(' ')[0];
+  this.rowCount = parseInt(pq.cmdTuples(), 10);
+  var nfields = pq.nfields();
+  if(nfields < 1) return;
+
+  this.fields = [];
+  for(var i = 0; i < nfields; i++) {
+    this.fields.push({
+      name: pq.fname(i),
+      dataTypeID: pq.ftype(i)
+    });
+  }
+};
+
+NativeResult.prototype.addRow = function(row) {
+  // This is empty to ensure pg code doesn't break when switching to pg-native
+  // pg-native loads all rows into the final result object by default.
+  // This is because libpg loads all rows into memory before passing the result
+  // to pg-native.
+};
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/pool-factory.js b/server/node_modules/pgtools/node_modules/pg/lib/pool-factory.js
new file mode 100644
index 0000000000000000000000000000000000000000..85f0e6a5074391542a89064ca8cffe5f3c0df489
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/pool-factory.js
@@ -0,0 +1,17 @@
+var Client = require('./client');
+var util = require('util');
+var Pool = require('pg-pool');
+
+module.exports = function(Client) {
+  var BoundPool = function(options) {
+    var config = { Client: Client };
+    for (var key in options) {
+      config[key] = options[key];
+    }
+    Pool.call(this, config);
+  };
+
+  util.inherits(BoundPool, Pool);
+
+  return BoundPool;
+};
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/query.js b/server/node_modules/pgtools/node_modules/pg/lib/query.js
new file mode 100644
index 0000000000000000000000000000000000000000..b8f6d77ebaf2484b7ff904801a80ddedf4e78d62
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/query.js
@@ -0,0 +1,238 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var EventEmitter = require('events').EventEmitter;
+var util = require('util');
+
+var Result = require('./result');
+var utils = require('./utils');
+
+var Query = function(config, values, callback) {
+  // use of "new" optional
+  if(!(this instanceof Query)) { return new Query(config, values, callback); }
+
+  config = utils.normalizeQueryConfig(config, values, callback);
+
+  this.text = config.text;
+  this.values = config.values;
+  this.rows = config.rows;
+  this.types = config.types;
+  this.name = config.name;
+  this.binary = config.binary;
+  this.stream = config.stream;
+  //use unique portal name each time
+  this.portal = config.portal || "";
+  this.callback = config.callback;
+  if(process.domain && config.callback) {
+    this.callback = process.domain.bind(config.callback);
+  }
+  this._result = new Result(config.rowMode, config.types);
+  this.isPreparedStatement = false;
+  this._canceledDueToError = false;
+  this._promise = null;
+  EventEmitter.call(this);
+};
+
+util.inherits(Query, EventEmitter);
+
+// TODO - remove in 7.0
+// this maintains backwards compat so someone could instantiate a query
+// manually: `new Query().then()`...
+Query._on = Query.on;
+Query._once = Query.once;
+
+Query.prototype.then = function(onSuccess, onFailure) {
+  return this._getPromise().then(onSuccess, onFailure);
+};
+
+Query.prototype.catch = function(callback) {
+  return this._getPromise().catch(callback);
+};
+
+Query.prototype._getPromise = function () {
+  if (this._promise) return this._promise;
+  this._promise = new Promise(function(resolve, reject) {
+    var onEnd = function (result) {
+      this.removeListener('error', onError);
+      this.removeListener('end', onEnd);
+      resolve(result);
+    };
+    var onError = function (err) {
+      this.removeListener('error', onError);
+      this.removeListener('end', onEnd);
+      reject(err);
+    };
+    this._on('end', onEnd);
+    this._on('error', onError);
+  }.bind(this));
+  return this._promise;
+};
+
+Query.prototype.promise = util.deprecate(function() {
+  return this._getPromise();
+}, 'Query.promise() is deprecated - see the upgrade guide at https://node-postgres.com/guides/upgrading');
+
+Query.prototype.requiresPreparation = function() {
+  //named queries must always be prepared
+  if(this.name) { return true; }
+  //always prepare if there are max number of rows expected per
+  //portal execution
+  if(this.rows) { return true; }
+  //don't prepare empty text queries
+  if(!this.text) { return false; }
+  //prepare if there are values
+  if(!this.values) { return false; }
+  return this.values.length > 0;
+};
+
+
+//associates row metadata from the supplied
+//message with this query object
+//metadata used when parsing row results
+Query.prototype.handleRowDescription = function(msg) {
+  this._result.addFields(msg.fields);
+  this._accumulateRows = this.callback || !this.listeners('row').length;
+};
+
+Query.prototype.handleDataRow = function(msg) {
+  var row;
+
+  if (this._canceledDueToError) {
+    return;
+  }
+
+  try {
+    row = this._result.parseRow(msg.fields);
+  } catch (err) {
+    this._canceledDueToError = err;
+    return;
+  }
+
+  this.emit('row', row, this._result);
+  if (this._accumulateRows) {
+    this._result.addRow(row);
+  }
+};
+
+Query.prototype.handleCommandComplete = function(msg, con) {
+  this._result.addCommandComplete(msg);
+  //need to sync after each command complete of a prepared statement
+  if(this.isPreparedStatement) {
+    con.sync();
+  }
+};
+
+//if a named prepared statement is created with empty query text
+//the backend will send an emptyQuery message but *not* a command complete message
+//execution on the connection will hang until the backend receives a sync message
+Query.prototype.handleEmptyQuery = function(con) {
+  if (this.isPreparedStatement) {
+    con.sync();
+  }
+};
+
+Query.prototype.handleReadyForQuery = function(con) {
+  if(this._canceledDueToError) {
+    return this.handleError(this._canceledDueToError, con);
+  }
+  if(this.callback) {
+    this.callback(null, this._result);
+  }
+  this.emit('end', this._result);
+};
+
+Query.prototype.handleError = function(err, connection) {
+  //need to sync after error during a prepared statement
+  if(this.isPreparedStatement) {
+    connection.sync();
+  }
+  if(this._canceledDueToError) {
+    err = this._canceledDueToError;
+    this._canceledDueToError = false;
+  }
+  //if callback supplied do not emit error event as uncaught error
+  //events will bubble up to node process
+  if(this.callback) {
+    return this.callback(err);
+  }
+  this.emit('error', err);
+};
+
+Query.prototype.submit = function(connection) {
+  if(this.requiresPreparation()) {
+    this.prepare(connection);
+  } else {
+    connection.query(this.text);
+  }
+};
+
+Query.prototype.hasBeenParsed = function(connection) {
+  return this.name && connection.parsedStatements[this.name];
+};
+
+Query.prototype.handlePortalSuspended = function(connection) {
+  this._getRows(connection, this.rows);
+};
+
+Query.prototype._getRows = function(connection, rows) {
+  connection.execute({
+    portal: this.portalName,
+    rows: rows
+  }, true);
+  connection.flush();
+};
+
+Query.prototype.prepare = function(connection) {
+  var self = this;
+  //prepared statements need sync to be called after each command
+  //complete or when an error is encountered
+  this.isPreparedStatement = true;
+  //TODO refactor this poor encapsulation
+  if(!this.hasBeenParsed(connection)) {
+    connection.parse({
+      text: self.text,
+      name: self.name,
+      types: self.types
+    }, true);
+  }
+
+  if(self.values) {
+    self.values = self.values.map(utils.prepareValue);
+  }
+
+  //http://developer.postgresql.org/pgdocs/postgres/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
+  connection.bind({
+    portal: self.portalName,
+    statement: self.name,
+    values: self.values,
+    binary: self.binary
+  }, true);
+
+  connection.describe({
+    type: 'P',
+    name: self.portalName || ""
+  }, true);
+
+  this._getRows(connection, this.rows);
+};
+
+Query.prototype.handleCopyInResponse = function (connection) {
+  if(this.stream) this.stream.startStreamingToConnection(connection);
+  else connection.sendCopyFail('No source stream defined');
+};
+
+Query.prototype.handleCopyData = function (msg, connection) {
+  var chunk = msg.chunk;
+  if(this.stream) {
+    this.stream.handleChunk(chunk);
+  }
+  //if there are no stream (for example when copy to query was sent by
+  //query method instead of copyTo) error will be handled
+  //on copyOutResponse event, so silently ignore this error here
+};
+module.exports = Query;
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/result.js b/server/node_modules/pgtools/node_modules/pg/lib/result.js
new file mode 100644
index 0000000000000000000000000000000000000000..fbf98cdf9804cb516ef43439881ebb8608f129d1
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/result.js
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var types = require('pg-types');
+var escape = require('js-string-escape');
+
+//result object returned from query
+//in the 'end' event and also
+//passed as second argument to provided callback
+var Result = function(rowMode) {
+  this.command = null;
+  this.rowCount = null;
+  this.oid = null;
+  this.rows = [];
+  this.fields = [];
+  this._parsers = [];
+  this.RowCtor = null;
+  this.rowAsArray = rowMode == "array";
+  if(this.rowAsArray) {
+    this.parseRow = this._parseRowAsArray;
+  }
+};
+
+var matchRegexp = /([A-Za-z]+) ?(\d+ )?(\d+)?/;
+
+//adds a command complete message
+Result.prototype.addCommandComplete = function(msg) {
+  var match;
+  if(msg.text) {
+    //pure javascript
+    match = matchRegexp.exec(msg.text);
+  } else {
+    //native bindings
+    match = matchRegexp.exec(msg.command);
+  }
+  if(match) {
+    this.command = match[1];
+    //match 3 will only be existing on insert commands
+    if(match[3]) {
+      //msg.value is from native bindings
+      this.rowCount = parseInt(match[3] || msg.value, 10);
+      this.oid = parseInt(match[2], 10);
+    } else {
+      this.rowCount = parseInt(match[2], 10);
+    }
+  }
+};
+
+Result.prototype._parseRowAsArray = function(rowData) {
+  var row = [];
+  for(var i = 0, len = rowData.length; i < len; i++) {
+    var rawValue = rowData[i];
+    if(rawValue !== null) {
+      row.push(this._parsers[i](rawValue));
+    } else {
+      row.push(null);
+    }
+  }
+  return row;
+};
+
+//rowData is an array of text or binary values
+//this turns the row into a JavaScript object
+Result.prototype.parseRow = function(rowData) {
+  return new this.RowCtor(this._parsers, rowData);
+};
+
+Result.prototype.addRow = function(row) {
+  this.rows.push(row);
+};
+
+var inlineParser = function(fieldName, i) {
+  return "\nthis['" +
+    // fields containing single quotes will break
+    // the evaluated javascript unless they are escaped
+    // see https://github.com/brianc/node-postgres/issues/507
+    // Addendum: However, we need to make sure to replace all
+    // occurences of apostrophes, not just the first one.
+    // See https://github.com/brianc/node-postgres/issues/934
+    escape(fieldName) +
+    "'] = " +
+    "rowData[" + i + "] == null ? null : parsers[" + i + "](rowData[" + i + "]);";
+};
+
+Result.prototype.addFields = function(fieldDescriptions) {
+  //clears field definitions
+  //multiple query statements in 1 action can result in multiple sets
+  //of rowDescriptions...eg: 'select NOW(); select 1::int;'
+  //you need to reset the fields
+  if(this.fields.length) {
+    this.fields = [];
+    this._parsers = [];
+  }
+  var ctorBody = "";
+  for(var i = 0; i < fieldDescriptions.length; i++) {
+    var desc = fieldDescriptions[i];
+    this.fields.push(desc);
+    var parser = this._getTypeParser(desc.dataTypeID, desc.format || 'text');
+    this._parsers.push(parser);
+    //this is some craziness to compile the row result parsing
+    //results in ~60% speedup on large query result sets
+    ctorBody += inlineParser(desc.name, i);
+  }
+  if(!this.rowAsArray) {
+    this.RowCtor = Function("parsers", "rowData", ctorBody);
+  }
+};
+
+Result.prototype._getTypeParser = types.getTypeParser;
+
+module.exports = Result;
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/type-overrides.js b/server/node_modules/pgtools/node_modules/pg/lib/type-overrides.js
new file mode 100644
index 0000000000000000000000000000000000000000..905260898767ddfde3a339dffd6c2e46c0797504
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/type-overrides.js
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var types = require('pg-types');
+
+function TypeOverrides(userTypes) {
+  this._types = userTypes || types;
+  this.text = {};
+  this.binary = {};
+}
+
+TypeOverrides.prototype.getOverrides = function(format) {
+  switch(format) {
+    case 'text': return this.text;
+    case 'binary': return this.binary;
+    default: return {};
+  }
+};
+
+TypeOverrides.prototype.setTypeParser = function(oid, format, parseFn) {
+  if(typeof format == 'function') {
+    parseFn = format;
+    format = 'text';
+  }
+  this.getOverrides(format)[oid] = parseFn;
+};
+
+TypeOverrides.prototype.getTypeParser = function(oid, format) {
+  format = format || 'text';
+  return this.getOverrides(format)[oid] || this._types.getTypeParser(oid, format);
+};
+
+module.exports = TypeOverrides;
diff --git a/server/node_modules/pgtools/node_modules/pg/lib/utils.js b/server/node_modules/pgtools/node_modules/pg/lib/utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..56a45cb06b1912eef976ec2a50bc175fe5d12c31
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/lib/utils.js
@@ -0,0 +1,167 @@
+/**
+ * Copyright (c) 2010-2017 Brian Carlson (brian.m.carlson@gmail.com)
+ * All rights reserved.
+ *
+ * This source code is licensed under the MIT license found in the
+ * README.md file in the root directory of this source tree.
+ */
+
+var util = require('util');
+
+var defaults = require('./defaults');
+
+function escapeElement(elementRepresentation) {
+  var escaped = elementRepresentation
+    .replace(/\\/g, '\\\\')
+    .replace(/"/g, '\\"');
+
+  return '"' + escaped + '"';
+}
+
+// convert a JS array to a postgres array literal
+// uses comma separator so won't work for types like box that use
+// a different array separator.
+function arrayString(val) {
+  var result = '{';
+  for (var i = 0 ; i < val.length; i++) {
+    if(i > 0) {
+      result = result + ',';
+    }
+    if(val[i] === null || typeof val[i] === 'undefined') {
+      result = result + 'NULL';
+    }
+    else if(Array.isArray(val[i])) {
+      result = result + arrayString(val[i]);
+    }
+    else if(val[i] instanceof Buffer) {
+      result += '\\\\x' + val[i].toString('hex');
+    }
+    else
+    {
+      result += escapeElement(prepareValue(val[i]));
+    }
+  }
+  result = result + '}';
+  return result;
+}
+
+//converts values from javascript types
+//to their 'raw' counterparts for use as a postgres parameter
+//note: you can override this function to provide your own conversion mechanism
+//for complex types, etc...
+var prepareValue = function(val, seen) {
+  if (val instanceof Buffer) {
+    return val;
+  }
+  if(val instanceof Date) {
+    if(defaults.parseInputDatesAsUTC) {
+      return dateToStringUTC(val);
+    } else {
+      return dateToString(val);
+    }
+  }
+  if(Array.isArray(val)) {
+    return arrayString(val);
+  }
+  if(val === null || typeof val === 'undefined') {
+    return null;
+  }
+  if(typeof val === 'object') {
+    return prepareObject(val, seen);
+  }
+  return val.toString();
+};
+
+function prepareObject(val, seen) {
+  if(val.toPostgres && typeof val.toPostgres === 'function') {
+    seen = seen || [];
+    if (seen.indexOf(val) !== -1) {
+      throw new Error('circular reference detected while preparing "' + val + '" for query');
+    }
+    seen.push(val);
+
+    return prepareValue(val.toPostgres(prepareValue), seen);
+  }
+  return JSON.stringify(val);
+}
+
+function pad(number, digits) {
+  number = ""  +number;
+  while(number.length < digits)
+    number = "0" + number;
+  return number;
+}
+
+function dateToString(date) {
+
+  var offset = -date.getTimezoneOffset();
+  var ret = pad(date.getFullYear(), 4) + '-' +
+    pad(date.getMonth() + 1, 2) + '-' +
+    pad(date.getDate(), 2) + 'T' +
+    pad(date.getHours(), 2) + ':' +
+    pad(date.getMinutes(), 2) + ':' +
+    pad(date.getSeconds(), 2) + '.' +
+    pad(date.getMilliseconds(), 3);
+
+  if(offset < 0) {
+    ret += "-";
+    offset *= -1;
+  }
+  else
+    ret += "+";
+
+  return ret + pad(Math.floor(offset/60), 2) + ":" + pad(offset%60, 2);
+}
+
+function dateToStringUTC(date) {
+
+  var ret = pad(date.getUTCFullYear(), 4) + '-' +
+      pad(date.getUTCMonth() + 1, 2) + '-' +
+      pad(date.getUTCDate(), 2) + 'T' +
+      pad(date.getUTCHours(), 2) + ':' +
+      pad(date.getUTCMinutes(), 2) + ':' +
+      pad(date.getUTCSeconds(), 2) + '.' +
+      pad(date.getUTCMilliseconds(), 3);
+
+  return ret + "+00:00";
+}
+
+function normalizeQueryConfig (config, values, callback) {
+  //can take in strings or config objects
+  config = (typeof(config) == 'string') ? { text: config } : config;
+  if(values) {
+    if(typeof values === 'function') {
+      config.callback = values;
+    } else {
+      config.values = values;
+    }
+  }
+  if(callback) {
+    config.callback = callback;
+  }
+  return config;
+}
+
+var queryEventEmitterOverloadDeprecationMessage = 'Using the automatically created return value from client.query as an event emitter is deprecated and will be removed in pg@7.0. Please see the upgrade guide at https://node-postgres.com/guides/upgrading';
+
+var deprecateEventEmitter = function(Emitter) {
+  var Result = function () {
+    Emitter.apply(this, arguments);
+  };
+  util.inherits(Result, Emitter);
+  Result.prototype._on = Result.prototype.on;
+  Result.prototype._once = Result.prototype.once;
+  Result.prototype.on = util.deprecate(Result.prototype.on, queryEventEmitterOverloadDeprecationMessage);
+  Result.prototype.once = util.deprecate(Result.prototype.once, queryEventEmitterOverloadDeprecationMessage);
+  return Result;
+};
+
+module.exports = {
+  prepareValue: function prepareValueWrapper (value) {
+    //this ensures that extra arguments do not get passed into prepareValue
+    //by accident, eg: from calling values.map(utils.prepareValue)
+    return prepareValue(value);
+  },
+  normalizeQueryConfig: normalizeQueryConfig,
+  deprecateEventEmitter: deprecateEventEmitter,
+};
diff --git a/server/node_modules/pgtools/node_modules/pg/package.json b/server/node_modules/pgtools/node_modules/pg/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..3610e1d4951a514415951bae7030c89f3947e2ee
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/pg/package.json
@@ -0,0 +1,78 @@
+{
+  "_from": "pg@^6.1.0",
+  "_id": "pg@6.4.2",
+  "_inBundle": false,
+  "_integrity": "sha1-w2QBEGDqx6UHoq4GPrhX7OkQ4n8=",
+  "_location": "/pgtools/pg",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "pg@^6.1.0",
+    "name": "pg",
+    "escapedName": "pg",
+    "rawSpec": "^6.1.0",
+    "saveSpec": null,
+    "fetchSpec": "^6.1.0"
+  },
+  "_requiredBy": [
+    "/pgtools"
+  ],
+  "_resolved": "https://registry.npmjs.org/pg/-/pg-6.4.2.tgz",
+  "_shasum": "c364011060eac7a507a2ae063eb857ece910e27f",
+  "_spec": "pg@^6.1.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgtools",
+  "author": {
+    "name": "Brian Carlson",
+    "email": "brian.m.carlson@gmail.com"
+  },
+  "bugs": {
+    "url": "https://github.com/brianc/node-postgres/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "buffer-writer": "1.0.1",
+    "js-string-escape": "1.0.1",
+    "packet-reader": "0.3.1",
+    "pg-connection-string": "0.1.3",
+    "pg-pool": "1.*",
+    "pg-types": "1.*",
+    "pgpass": "1.*",
+    "semver": "4.3.2"
+  },
+  "deprecated": false,
+  "description": "PostgreSQL client - pure javascript & libpq with the same API",
+  "devDependencies": {
+    "async": "0.9.0",
+    "co": "4.6.0",
+    "jshint": "2.5.2",
+    "lodash": "4.13.1",
+    "pg-copy-streams": "0.3.0",
+    "promise-polyfill": "5.2.1"
+  },
+  "engines": {
+    "node": ">= 0.8.0"
+  },
+  "homepage": "http://github.com/brianc/node-postgres",
+  "keywords": [
+    "postgres",
+    "pg",
+    "libpq",
+    "postgre",
+    "database",
+    "rdbms"
+  ],
+  "license": "MIT",
+  "main": "./lib",
+  "minNativeVersion": "1.7.0",
+  "name": "pg",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/brianc/node-postgres.git"
+  },
+  "scripts": {
+    "changelog": "npm i github-changes && ./node_modules/.bin/github-changes -o brianc -r node-postgres -d pulls -a -v",
+    "test": "make test-all connectionString=postgres://postgres@localhost:5432/postgres"
+  },
+  "version": "6.4.2"
+}
diff --git a/server/node_modules/pgtools/node_modules/postgres-array/index.d.ts b/server/node_modules/pgtools/node_modules/postgres-array/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..88665bd9159c1c7b54aa56f5cf2c4ca1cdf4dd32
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/postgres-array/index.d.ts
@@ -0,0 +1,4 @@
+
+export function parse(source: string): string[];
+export function parse<T>(source: string, transform: (value: string) => T): T[];
+
diff --git a/server/node_modules/pgtools/node_modules/postgres-array/index.js b/server/node_modules/pgtools/node_modules/postgres-array/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..1b2c110456afca6bde7da20268d978d4a37d877c
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/postgres-array/index.js
@@ -0,0 +1,85 @@
+'use strict'
+
+exports.parse = function (source, transform) {
+  return new ArrayParser(source, transform).parse()
+}
+
+function ArrayParser (source, transform) {
+  this.source = source
+  this.transform = transform || identity
+  this.position = 0
+  this.entries = []
+  this.recorded = []
+  this.dimension = 0
+}
+
+ArrayParser.prototype.isEof = function () {
+  return this.position >= this.source.length
+}
+
+ArrayParser.prototype.nextCharacter = function () {
+  var character = this.source[this.position++]
+  if (character === '\\') {
+    return {
+      value: this.source[this.position++],
+      escaped: true
+    }
+  }
+  return {
+    value: character,
+    escaped: false
+  }
+}
+
+ArrayParser.prototype.record = function (character) {
+  this.recorded.push(character)
+}
+
+ArrayParser.prototype.newEntry = function (includeEmpty) {
+  var entry
+  if (this.recorded.length > 0 || includeEmpty) {
+    entry = this.recorded.join('')
+    if (entry === 'NULL' && !includeEmpty) {
+      entry = null
+    }
+    if (entry !== null) entry = this.transform(entry)
+    this.entries.push(entry)
+    this.recorded = []
+  }
+}
+
+ArrayParser.prototype.parse = function (nested) {
+  var character, parser, quote
+  while (!this.isEof()) {
+    character = this.nextCharacter()
+    if (character.value === '{' && !quote) {
+      this.dimension++
+      if (this.dimension > 1) {
+        parser = new ArrayParser(this.source.substr(this.position - 1), this.transform)
+        this.entries.push(parser.parse(true))
+        this.position += parser.position - 2
+      }
+    } else if (character.value === '}' && !quote) {
+      this.dimension--
+      if (!this.dimension) {
+        this.newEntry()
+        if (nested) return this.entries
+      }
+    } else if (character.value === '"' && !character.escaped) {
+      if (quote) this.newEntry(true)
+      quote = !quote
+    } else if (character.value === ',' && !quote) {
+      this.newEntry()
+    } else {
+      this.record(character.value)
+    }
+  }
+  if (this.dimension !== 0) {
+    throw new Error('array dimension not balanced')
+  }
+  return this.entries
+}
+
+function identity (value) {
+  return value
+}
diff --git a/server/node_modules/pgtools/node_modules/postgres-array/license b/server/node_modules/pgtools/node_modules/postgres-array/license
new file mode 100644
index 0000000000000000000000000000000000000000..25c624701389bab54c94982531ea34e8d1702ccf
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/postgres-array/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Ben Drucker <bvdrucker@gmail.com> (bendrucker.me)
+
+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.
diff --git a/server/node_modules/pgtools/node_modules/postgres-array/package.json b/server/node_modules/pgtools/node_modules/postgres-array/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..180c29f8c85c07811eb0cc193f493f0a6c28dac5
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/postgres-array/package.json
@@ -0,0 +1,68 @@
+{
+  "_from": "postgres-array@~1.0.0",
+  "_id": "postgres-array@1.0.3",
+  "_inBundle": false,
+  "_integrity": "sha512-5wClXrAP0+78mcsNX3/ithQ5exKvCyK5lr5NEEEeGwwM6NJdQgzIJBVxLvRW+huFpX92F2QnZ5CcokH0VhK2qQ==",
+  "_location": "/pgtools/postgres-array",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "postgres-array@~1.0.0",
+    "name": "postgres-array",
+    "escapedName": "postgres-array",
+    "rawSpec": "~1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "~1.0.0"
+  },
+  "_requiredBy": [
+    "/pgtools/pg-types"
+  ],
+  "_resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.3.tgz",
+  "_shasum": "c561fc3b266b21451fc6555384f4986d78ec80f5",
+  "_spec": "postgres-array@~1.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgtools/node_modules/pg-types",
+  "author": {
+    "name": "Ben Drucker",
+    "email": "bvdrucker@gmail.com",
+    "url": "bendrucker.me"
+  },
+  "bugs": {
+    "url": "https://github.com/bendrucker/postgres-array/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "Parse postgres array columns",
+  "devDependencies": {
+    "ap": "^0.2.0",
+    "standard": "^4.0.0",
+    "tape": "^4.0.0"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js",
+    "index.d.ts",
+    "readme.md"
+  ],
+  "homepage": "https://github.com/bendrucker/postgres-array#readme",
+  "keywords": [
+    "postgres",
+    "array",
+    "parser"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "postgres-array",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/bendrucker/postgres-array.git"
+  },
+  "scripts": {
+    "test": "standard && tape test.js"
+  },
+  "types": "index.d.ts",
+  "version": "1.0.3"
+}
diff --git a/server/node_modules/pgtools/node_modules/postgres-array/readme.md b/server/node_modules/pgtools/node_modules/postgres-array/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..a054e48cc96f76fed139104fdeef8c71c53b4f49
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/postgres-array/readme.md
@@ -0,0 +1,43 @@
+# postgres-array [![Build Status](https://travis-ci.org/bendrucker/postgres-array.svg?branch=master)](https://travis-ci.org/bendrucker/postgres-array)
+
+> Parse postgres array columns
+
+
+## Install
+
+```
+$ npm install --save postgres-array
+```
+
+
+## Usage
+
+```js
+var postgresArray = require('postgres-array')
+
+postgresArray.parse('{1,2,3}', parseInt);
+//=> [1, 2, 3]
+```
+
+## API
+
+#### `parse(input, [transform])` -> `array`
+
+##### input
+
+*Required*  
+Type: `string`
+
+A Postgres array string.
+
+##### transform
+
+Type: `function`  
+Default: `identity`
+
+A function that transforms non-null values inserted into the array.
+
+
+## License
+
+MIT © [Ben Drucker](http://bendrucker.me)
diff --git a/server/node_modules/pgtools/node_modules/semver/.npmignore b/server/node_modules/pgtools/node_modules/semver/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..7300fbc79a748cd2ac71e493030bcb9f828ac67d
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/.npmignore
@@ -0,0 +1 @@
+# nada
diff --git a/server/node_modules/pgtools/node_modules/semver/LICENSE b/server/node_modules/pgtools/node_modules/semver/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..0c44ae716db8f353760831bbf55af8e2d0b63630
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) Isaac Z. Schlueter ("Author")
+All rights reserved.
+
+The BSD License
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/server/node_modules/pgtools/node_modules/semver/Makefile b/server/node_modules/pgtools/node_modules/semver/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..71af0e9750cd0aba158bd9dfd77fbdb6c8d765f3
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/Makefile
@@ -0,0 +1,24 @@
+files =  semver.browser.js \
+         semver.min.js \
+				 semver.browser.js.gz \
+				 semver.min.js.gz
+
+all: $(files)
+
+clean:
+	rm -f $(files)
+
+semver.browser.js: head.js.txt semver.js foot.js.txt
+	( cat head.js.txt; \
+		cat semver.js | \
+			egrep -v '^ *\/\* nomin \*\/' | \
+			perl -pi -e 's/debug\([^\)]+\)//g'; \
+		cat foot.js.txt ) > semver.browser.js
+
+semver.min.js: semver.browser.js
+	uglifyjs -m <semver.browser.js >semver.min.js
+
+%.gz: %
+	gzip --stdout -9 <$< >$@
+
+.PHONY: all clean
diff --git a/server/node_modules/pgtools/node_modules/semver/README.md b/server/node_modules/pgtools/node_modules/semver/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..b5e35ff0b5bd955f3985ffacf06a40e3639979cc
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/README.md
@@ -0,0 +1,303 @@
+semver(1) -- The semantic versioner for npm
+===========================================
+
+## Usage
+
+    $ npm install semver
+
+    semver.valid('1.2.3') // '1.2.3'
+    semver.valid('a.b.c') // null
+    semver.clean('  =v1.2.3   ') // '1.2.3'
+    semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true
+    semver.gt('1.2.3', '9.8.7') // false
+    semver.lt('1.2.3', '9.8.7') // true
+
+As a command-line utility:
+
+    $ semver -h
+
+    Usage: semver <version> [<version> [...]] [-r <range> | -i <inc> | --preid <identifier> | -l | -rv]
+    Test if version(s) satisfy the supplied range(s), and sort them.
+
+    Multiple versions or ranges may be supplied, unless increment
+    option is specified.  In that case, only a single version may
+    be used, and it is incremented by the specified level
+
+    Program exits successfully if any valid version satisfies
+    all supplied ranges, and prints all satisfying versions.
+
+    If no versions are valid, or ranges are not satisfied,
+    then exits failure.
+
+    Versions are printed in ascending order, so supplying
+    multiple versions to the utility will just sort them.
+
+## Versions
+
+A "version" is described by the `v2.0.0` specification found at
+<http://semver.org/>.
+
+A leading `"="` or `"v"` character is stripped off and ignored.
+
+## Ranges
+
+A `version range` is a set of `comparators` which specify versions
+that satisfy the range.
+
+A `comparator` is composed of an `operator` and a `version`.  The set
+of primitive `operators` is:
+
+* `<` Less than
+* `<=` Less than or equal to
+* `>` Greater than
+* `>=` Greater than or equal to
+* `=` Equal.  If no operator is specified, then equality is assumed,
+  so this operator is optional, but MAY be included.
+
+For example, the comparator `>=1.2.7` would match the versions
+`1.2.7`, `1.2.8`, `2.5.3`, and `1.3.9`, but not the versions `1.2.6`
+or `1.1.0`.
+
+Comparators can be joined by whitespace to form a `comparator set`,
+which is satisfied by the **intersection** of all of the comparators
+it includes.
+
+A range is composed of one or more comparator sets, joined by `||`.  A
+version matches a range if and only if every comparator in at least
+one of the `||`-separated comparator sets is satisfied by the version.
+
+For example, the range `>=1.2.7 <1.3.0` would match the versions
+`1.2.7`, `1.2.8`, and `1.2.99`, but not the versions `1.2.6`, `1.3.0`,
+or `1.1.0`.
+
+The range `1.2.7 || >=1.2.9 <2.0.0` would match the versions `1.2.7`,
+`1.2.9`, and `1.4.6`, but not the versions `1.2.8` or `2.0.0`.
+
+### Prerelease Tags
+
+If a version has a prerelease tag (for example, `1.2.3-alpha.3`) then
+it will only be allowed to satisfy comparator sets if at least one
+comparator with the same `[major, minor, patch]` tuple also has a
+prerelease tag.
+
+For example, the range `>1.2.3-alpha.3` would be allowed to match the
+version `1.2.3-alpha.7`, but it would *not* be satisfied by
+`3.4.5-alpha.9`, even though `3.4.5-alpha.9` is technically "greater
+than" `1.2.3-alpha.3` according to the SemVer sort rules.  The version
+range only accepts prerelease tags on the `1.2.3` version.  The
+version `3.4.5` *would* satisfy the range, because it does not have a
+prerelease flag, and `3.4.5` is greater than `1.2.3-alpha.7`.
+
+The purpose for this behavior is twofold.  First, prerelease versions
+frequently are updated very quickly, and contain many breaking changes
+that are (by the author's design) not yet fit for public consumption.
+Therefore, by default, they are excluded from range matching
+semantics.
+
+Second, a user who has opted into using a prerelease version has
+clearly indicated the intent to use *that specific* set of
+alpha/beta/rc versions.  By including a prerelease tag in the range,
+the user is indicating that they are aware of the risk.  However, it
+is still not appropriate to assume that they have opted into taking a
+similar risk on the *next* set of prerelease versions.
+
+#### Prerelease Identifiers
+
+The method `.inc` takes an additional `identifier` string argument that
+will append the value of the string as a prerelease identifier:
+
+```javascript
+> semver.inc('1.2.3', 'pre', 'beta')
+'1.2.4-beta.0'
+```
+
+command-line example:
+
+```shell
+$ semver 1.2.3 -i prerelease --preid beta
+1.2.4-beta.0
+```
+
+Which then can be used to increment further:
+
+```shell
+$ semver 1.2.4-beta.0 -i prerelease
+1.2.4-beta.1
+```
+
+### Advanced Range Syntax
+
+Advanced range syntax desugars to primitive comparators in
+deterministic ways.
+
+Advanced ranges may be combined in the same way as primitive
+comparators using white space or `||`.
+
+#### Hyphen Ranges `X.Y.Z - A.B.C`
+
+Specifies an inclusive set.
+
+* `1.2.3 - 2.3.4` := `>=1.2.3 <=2.3.4`
+
+If a partial version is provided as the first version in the inclusive
+range, then the missing pieces are replaced with zeroes.
+
+* `1.2 - 2.3.4` := `>=1.2.0 <=2.3.4`
+
+If a partial version is provided as the second version in the
+inclusive range, then all versions that start with the supplied parts
+of the tuple are accepted, but nothing that would be greater than the
+provided tuple parts.
+
+* `1.2.3 - 2.3` := `>=1.2.3 <2.4.0`
+* `1.2.3 - 2` := `>=1.2.3 <3.0.0`
+
+#### X-Ranges `1.2.x` `1.X` `1.2.*` `*`
+
+Any of `X`, `x`, or `*` may be used to "stand in" for one of the
+numeric values in the `[major, minor, patch]` tuple.
+
+* `*` := `>=0.0.0` (Any version satisfies)
+* `1.x` := `>=1.0.0 <2.0.0` (Matching major version)
+* `1.2.x` := `>=1.2.0 <1.3.0` (Matching major and minor versions)
+
+A partial version range is treated as an X-Range, so the special
+character is in fact optional.
+
+* `""` (empty string) := `*` := `>=0.0.0`
+* `1` := `1.x.x` := `>=1.0.0 <2.0.0`
+* `1.2` := `1.2.x` := `>=1.2.0 <1.3.0`
+
+#### Tilde Ranges `~1.2.3` `~1.2` `~1`
+
+Allows patch-level changes if a minor version is specified on the
+comparator.  Allows minor-level changes if not.
+
+* `~1.2.3` := `>=1.2.3 <1.(2+1).0` := `>=1.2.3 <1.3.0`
+* `~1.2` := `>=1.2.0 <1.(2+1).0` := `>=1.2.0 <1.3.0` (Same as `1.2.x`)
+* `~1` := `>=1.0.0 <(1+1).0.0` := `>=1.0.0 <2.0.0` (Same as `1.x`)
+* `~0.2.3` := `>=0.2.3 <0.(2+1).0` := `>=0.2.3 <0.3.0`
+* `~0.2` := `>=0.2.0 <0.(2+1).0` := `>=0.2.0 <0.3.0` (Same as `0.2.x`)
+* `~0` := `>=0.0.0 <(0+1).0.0` := `>=0.0.0 <1.0.0` (Same as `0.x`)
+* `~1.2.3-beta.2` := `>=1.2.3-beta.2 <1.3.0` Note that prereleases in
+  the `1.2.3` version will be allowed, if they are greater than or
+  equal to `beta.2`.  So, `1.2.3-beta.4` would be allowed, but
+  `1.2.4-beta.2` would not, because it is a prerelease of a
+  different `[major, minor, patch]` tuple.
+
+#### Caret Ranges `^1.2.3` `^0.2.5` `^0.0.4`
+
+Allows changes that do not modify the left-most non-zero digit in the
+`[major, minor, patch]` tuple.  In other words, this allows patch and
+minor updates for versions `1.0.0` and above, patch updates for
+versions `0.X >=0.1.0`, and *no* updates for versions `0.0.X`.
+
+Many authors treat a `0.x` version as if the `x` were the major
+"breaking-change" indicator.
+
+Caret ranges are ideal when an author may make breaking changes
+between `0.2.4` and `0.3.0` releases, which is a common practice.
+However, it presumes that there will *not* be breaking changes between
+`0.2.4` and `0.2.5`.  It allows for changes that are presumed to be
+additive (but non-breaking), according to commonly observed practices.
+
+* `^1.2.3` := `>=1.2.3 <2.0.0`
+* `^0.2.3` := `>=0.2.3 <0.3.0`
+* `^0.0.3` := `>=0.0.3 <0.0.4`
+* `^1.2.3-beta.2` := `>=1.2.3-beta.2 <2.0.0` Note that prereleases in
+  the `1.2.3` version will be allowed, if they are greater than or
+  equal to `beta.2`.  So, `1.2.3-beta.4` would be allowed, but
+  `1.2.4-beta.2` would not, because it is a prerelease of a
+  different `[major, minor, patch]` tuple.
+* `^0.0.3-beta` := `>=0.0.3-beta <0.0.4`  Note that prereleases in the
+  `0.0.3` version *only* will be allowed, if they are greater than or
+  equal to `beta`.  So, `0.0.3-pr.2` would be allowed.
+
+When parsing caret ranges, a missing `patch` value desugars to the
+number `0`, but will allow flexibility within that value, even if the
+major and minor versions are both `0`.
+
+* `^1.2.x` := `>=1.2.0 <2.0.0`
+* `^0.0.x` := `>=0.0.0 <0.1.0`
+* `^0.0` := `>=0.0.0 <0.1.0`
+
+A missing `minor` and `patch` values will desugar to zero, but also
+allow flexibility within those values, even if the major version is
+zero.
+
+* `^1.x` := `>=1.0.0 <2.0.0`
+* `^0.x` := `>=0.0.0 <1.0.0`
+
+## Functions
+
+All methods and classes take a final `loose` boolean argument that, if
+true, will be more forgiving about not-quite-valid semver strings.
+The resulting output will always be 100% strict, of course.
+
+Strict-mode Comparators and Ranges will be strict about the SemVer
+strings that they parse.
+
+* `valid(v)`: Return the parsed version, or null if it's not valid.
+* `inc(v, release)`: Return the version incremented by the release
+  type (`major`,   `premajor`, `minor`, `preminor`, `patch`,
+  `prepatch`, or `prerelease`), or null if it's not valid
+  * `premajor` in one call will bump the version up to the next major
+    version and down to a prerelease of that major version.
+    `preminor`, and `prepatch` work the same way.
+  * If called from a non-prerelease version, the `prerelease` will work the
+    same as `prepatch`. It increments the patch version, then makes a
+    prerelease. If the input version is already a prerelease it simply
+    increments it.
+* `major(v)`: Return the major version number.
+* `minor(v)`: Return the minor version number.
+* `patch(v)`: Return the patch version number.
+
+### Comparison
+
+* `gt(v1, v2)`: `v1 > v2`
+* `gte(v1, v2)`: `v1 >= v2`
+* `lt(v1, v2)`: `v1 < v2`
+* `lte(v1, v2)`: `v1 <= v2`
+* `eq(v1, v2)`: `v1 == v2` This is true if they're logically equivalent,
+  even if they're not the exact same string.  You already know how to
+  compare strings.
+* `neq(v1, v2)`: `v1 != v2` The opposite of `eq`.
+* `cmp(v1, comparator, v2)`: Pass in a comparison string, and it'll call
+  the corresponding function above.  `"==="` and `"!=="` do simple
+  string comparison, but are included for completeness.  Throws if an
+  invalid comparison string is provided.
+* `compare(v1, v2)`: Return `0` if `v1 == v2`, or `1` if `v1` is greater, or `-1` if
+  `v2` is greater.  Sorts in ascending order if passed to `Array.sort()`.
+* `rcompare(v1, v2)`: The reverse of compare.  Sorts an array of versions
+  in descending order when passed to `Array.sort()`.
+* `diff(v1, v2)`: Returns difference between two versions by the release type
+  (`major`, `premajor`, `minor`, `preminor`, `patch`, `prepatch`, or `prerelease`),
+  or null if the versions are the same.
+
+
+### Ranges
+
+* `validRange(range)`: Return the valid range or null if it's not valid
+* `satisfies(version, range)`: Return true if the version satisfies the
+  range.
+* `maxSatisfying(versions, range)`: Return the highest version in the list
+  that satisfies the range, or `null` if none of them do.
+* `gtr(version, range)`: Return `true` if version is greater than all the
+  versions possible in the range.
+* `ltr(version, range)`: Return `true` if version is less than all the
+  versions possible in the range.
+* `outside(version, range, hilo)`: Return true if the version is outside
+  the bounds of the range in either the high or low direction.  The
+  `hilo` argument must be either the string `'>'` or `'<'`.  (This is
+  the function called by `gtr` and `ltr`.)
+
+Note that, since ranges may be non-contiguous, a version might not be
+greater than a range, less than a range, *or* satisfy a range!  For
+example, the range `1.2 <1.2.9 || >2.0.0` would have a hole from `1.2.9`
+until `2.0.0`, so the version `1.2.10` would not be greater than the
+range (because `2.0.1` satisfies, which is higher), nor less than the
+range (since `1.2.8` satisfies, which is lower), and it also does not
+satisfy the range.
+
+If you want to know if a version satisfies or does not satisfy a
+range, use the `satisfies(version, range)` function.
diff --git a/server/node_modules/pgtools/node_modules/semver/bin/semver b/server/node_modules/pgtools/node_modules/semver/bin/semver
new file mode 100755
index 0000000000000000000000000000000000000000..c5f2e857e8279083438589cfb06427997b6a5618
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/bin/semver
@@ -0,0 +1,133 @@
+#!/usr/bin/env node
+// Standalone semver comparison program.
+// Exits successfully and prints matching version(s) if
+// any supplied version is valid and passes all tests.
+
+var argv = process.argv.slice(2)
+  , versions = []
+  , range = []
+  , gt = []
+  , lt = []
+  , eq = []
+  , inc = null
+  , version = require("../package.json").version
+  , loose = false
+  , identifier = undefined
+  , semver = require("../semver")
+  , reverse = false
+
+main()
+
+function main () {
+  if (!argv.length) return help()
+  while (argv.length) {
+    var a = argv.shift()
+    var i = a.indexOf('=')
+    if (i !== -1) {
+      a = a.slice(0, i)
+      argv.unshift(a.slice(i + 1))
+    }
+    switch (a) {
+      case "-rv": case "-rev": case "--rev": case "--reverse":
+        reverse = true
+        break
+      case "-l": case "--loose":
+        loose = true
+        break
+      case "-v": case "--version":
+        versions.push(argv.shift())
+        break
+      case "-i": case "--inc": case "--increment":
+        switch (argv[0]) {
+          case "major": case "minor": case "patch": case "prerelease":
+          case "premajor": case "preminor": case "prepatch":
+            inc = argv.shift()
+            break
+          default:
+            inc = "patch"
+            break
+        }
+        break
+      case "--preid":
+        identifier = argv.shift()
+        break
+      case "-r": case "--range":
+        range.push(argv.shift())
+        break
+      case "-h": case "--help": case "-?":
+        return help()
+      default:
+        versions.push(a)
+        break
+    }
+  }
+
+  versions = versions.filter(function (v) {
+    return semver.valid(v, loose)
+  })
+  if (!versions.length) return fail()
+  if (inc && (versions.length !== 1 || range.length))
+    return failInc()
+
+  for (var i = 0, l = range.length; i < l ; i ++) {
+    versions = versions.filter(function (v) {
+      return semver.satisfies(v, range[i], loose)
+    })
+    if (!versions.length) return fail()
+  }
+  return success(versions)
+}
+
+function failInc () {
+  console.error("--inc can only be used on a single version with no range")
+  fail()
+}
+
+function fail () { process.exit(1) }
+
+function success () {
+  var compare = reverse ? "rcompare" : "compare"
+  versions.sort(function (a, b) {
+    return semver[compare](a, b, loose)
+  }).map(function (v) {
+    return semver.clean(v, loose)
+  }).map(function (v) {
+    return inc ? semver.inc(v, inc, loose, identifier) : v
+  }).forEach(function (v,i,_) { console.log(v) })
+}
+
+function help () {
+  console.log(["SemVer " + version
+              ,""
+              ,"A JavaScript implementation of the http://semver.org/ specification"
+              ,"Copyright Isaac Z. Schlueter"
+              ,""
+              ,"Usage: semver [options] <version> [<version> [...]]"
+              ,"Prints valid versions sorted by SemVer precedence"
+              ,""
+              ,"Options:"
+              ,"-r --range <range>"
+              ,"        Print versions that match the specified range."
+              ,""
+              ,"-i --increment [<level>]"
+              ,"        Increment a version by the specified level.  Level can"
+              ,"        be one of: major, minor, patch, premajor, preminor,"
+              ,"        prepatch, or prerelease.  Default level is 'patch'."
+              ,"        Only one version may be specified."
+              ,""
+              ,"--preid <identifier>"
+              ,"        Identifier to be used to prefix premajor, preminor,"
+              ,"        prepatch or prerelease version increments."
+              ,""
+              ,"-l --loose"
+              ,"        Interpret versions and ranges loosely"
+              ,""
+              ,"Program exits successfully if any valid version satisfies"
+              ,"all supplied ranges, and prints all satisfying versions."
+              ,""
+              ,"If no satisfying versions are found, then exits failure."
+              ,""
+              ,"Versions are printed in ascending order, so supplying"
+              ,"multiple versions to the utility will just sort them."
+              ].join("\n"))
+}
diff --git a/server/node_modules/pgtools/node_modules/semver/foot.js.txt b/server/node_modules/pgtools/node_modules/semver/foot.js.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8f83c20f8ed5a6476875e9cc61b2a82812fa500f
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/foot.js.txt
@@ -0,0 +1,6 @@
+
+})(
+  typeof exports === 'object' ? exports :
+  typeof define === 'function' && define.amd ? {} :
+  semver = {}
+);
diff --git a/server/node_modules/pgtools/node_modules/semver/head.js.txt b/server/node_modules/pgtools/node_modules/semver/head.js.txt
new file mode 100644
index 0000000000000000000000000000000000000000..65368651777d286654883ff03b6dc5d49c7bba4e
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/head.js.txt
@@ -0,0 +1,2 @@
+;(function(exports) {
+
diff --git a/server/node_modules/pgtools/node_modules/semver/package.json b/server/node_modules/pgtools/node_modules/semver/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..1674bade37fce6d7cc6250f4a7ef8e43a3f13ecf
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/package.json
@@ -0,0 +1,53 @@
+{
+  "_from": "semver@4.3.2",
+  "_id": "semver@4.3.2",
+  "_inBundle": false,
+  "_integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=",
+  "_location": "/pgtools/semver",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "semver@4.3.2",
+    "name": "semver",
+    "escapedName": "semver",
+    "rawSpec": "4.3.2",
+    "saveSpec": null,
+    "fetchSpec": "4.3.2"
+  },
+  "_requiredBy": [
+    "/pgtools/pg"
+  ],
+  "_resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz",
+  "_shasum": "c7a07158a80bedd052355b770d82d6640f803be7",
+  "_spec": "semver@4.3.2",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgtools/node_modules/pg",
+  "bin": {
+    "semver": "./bin/semver"
+  },
+  "browser": "semver.browser.js",
+  "bugs": {
+    "url": "https://github.com/npm/node-semver/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "The semantic version parser used by npm.",
+  "devDependencies": {
+    "tap": "0.x >=0.0.4",
+    "uglify-js": "~2.3.6"
+  },
+  "homepage": "https://github.com/npm/node-semver#readme",
+  "license": "BSD",
+  "main": "semver.js",
+  "min": "semver.min.js",
+  "name": "semver",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/npm/node-semver.git"
+  },
+  "scripts": {
+    "prepublish": "make",
+    "test": "tap test/*.js"
+  },
+  "version": "4.3.2"
+}
diff --git a/server/node_modules/pgtools/node_modules/semver/semver.browser.js b/server/node_modules/pgtools/node_modules/semver/semver.browser.js
new file mode 100644
index 0000000000000000000000000000000000000000..250885a7e7ed3906544c84796ee53cb9ee703177
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/semver.browser.js
@@ -0,0 +1,1187 @@
+;(function(exports) {
+
+// export the class if we are in a Node-like system.
+if (typeof module === 'object' && module.exports === exports)
+  exports = module.exports = SemVer;
+
+// The debug function is excluded entirely from the minified version.
+
+// Note: this is the semver.org version of the spec that it implements
+// Not necessarily the package version of this code.
+exports.SEMVER_SPEC_VERSION = '2.0.0';
+
+var MAX_LENGTH = 256;
+var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
+
+// The actual regexps go on exports.re
+var re = exports.re = [];
+var src = exports.src = [];
+var R = 0;
+
+// The following Regular Expressions can be used for tokenizing,
+// validating, and parsing SemVer version strings.
+
+// ## Numeric Identifier
+// A single `0`, or a non-zero digit followed by zero or more digits.
+
+var NUMERICIDENTIFIER = R++;
+src[NUMERICIDENTIFIER] = '0|[1-9]\\d*';
+var NUMERICIDENTIFIERLOOSE = R++;
+src[NUMERICIDENTIFIERLOOSE] = '[0-9]+';
+
+
+// ## Non-numeric Identifier
+// Zero or more digits, followed by a letter or hyphen, and then zero or
+// more letters, digits, or hyphens.
+
+var NONNUMERICIDENTIFIER = R++;
+src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*';
+
+
+// ## Main Version
+// Three dot-separated numeric identifiers.
+
+var MAINVERSION = R++;
+src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' +
+                   '(' + src[NUMERICIDENTIFIER] + ')\\.' +
+                   '(' + src[NUMERICIDENTIFIER] + ')';
+
+var MAINVERSIONLOOSE = R++;
+src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
+                        '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
+                        '(' + src[NUMERICIDENTIFIERLOOSE] + ')';
+
+// ## Pre-release Version Identifier
+// A numeric identifier, or a non-numeric identifier.
+
+var PRERELEASEIDENTIFIER = R++;
+src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] +
+                            '|' + src[NONNUMERICIDENTIFIER] + ')';
+
+var PRERELEASEIDENTIFIERLOOSE = R++;
+src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] +
+                                 '|' + src[NONNUMERICIDENTIFIER] + ')';
+
+
+// ## Pre-release Version
+// Hyphen, followed by one or more dot-separated pre-release version
+// identifiers.
+
+var PRERELEASE = R++;
+src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] +
+                  '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))';
+
+var PRERELEASELOOSE = R++;
+src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] +
+                       '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))';
+
+// ## Build Metadata Identifier
+// Any combination of digits, letters, or hyphens.
+
+var BUILDIDENTIFIER = R++;
+src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+';
+
+// ## Build Metadata
+// Plus sign, followed by one or more period-separated build metadata
+// identifiers.
+
+var BUILD = R++;
+src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] +
+             '(?:\\.' + src[BUILDIDENTIFIER] + ')*))';
+
+
+// ## Full Version String
+// A main version, followed optionally by a pre-release version and
+// build metadata.
+
+// Note that the only major, minor, patch, and pre-release sections of
+// the version string are capturing groups.  The build metadata is not a
+// capturing group, because it should not ever be used in version
+// comparison.
+
+var FULL = R++;
+var FULLPLAIN = 'v?' + src[MAINVERSION] +
+                src[PRERELEASE] + '?' +
+                src[BUILD] + '?';
+
+src[FULL] = '^' + FULLPLAIN + '$';
+
+// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
+// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
+// common in the npm registry.
+var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] +
+                 src[PRERELEASELOOSE] + '?' +
+                 src[BUILD] + '?';
+
+var LOOSE = R++;
+src[LOOSE] = '^' + LOOSEPLAIN + '$';
+
+var GTLT = R++;
+src[GTLT] = '((?:<|>)?=?)';
+
+// Something like "2.*" or "1.2.x".
+// Note that "x.x" is a valid xRange identifer, meaning "any version"
+// Only the first item is strictly required.
+var XRANGEIDENTIFIERLOOSE = R++;
+src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*';
+var XRANGEIDENTIFIER = R++;
+src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*';
+
+var XRANGEPLAIN = R++;
+src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:' + src[PRERELEASE] + ')?' +
+                   src[BUILD] + '?' +
+                   ')?)?';
+
+var XRANGEPLAINLOOSE = R++;
+src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:' + src[PRERELEASELOOSE] + ')?' +
+                        src[BUILD] + '?' +
+                        ')?)?';
+
+var XRANGE = R++;
+src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$';
+var XRANGELOOSE = R++;
+src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$';
+
+// Tilde ranges.
+// Meaning is "reasonably at or greater than"
+var LONETILDE = R++;
+src[LONETILDE] = '(?:~>?)';
+
+var TILDETRIM = R++;
+src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+';
+re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g');
+var tildeTrimReplace = '$1~';
+
+var TILDE = R++;
+src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$';
+var TILDELOOSE = R++;
+src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$';
+
+// Caret ranges.
+// Meaning is "at least and backwards compatible with"
+var LONECARET = R++;
+src[LONECARET] = '(?:\\^)';
+
+var CARETTRIM = R++;
+src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+';
+re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g');
+var caretTrimReplace = '$1^';
+
+var CARET = R++;
+src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$';
+var CARETLOOSE = R++;
+src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$';
+
+// A simple gt/lt/eq thing, or just "" to indicate "any version"
+var COMPARATORLOOSE = R++;
+src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$';
+var COMPARATOR = R++;
+src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$';
+
+
+// An expression to strip any whitespace between the gtlt and the thing
+// it modifies, so that `> 1.2.3` ==> `>1.2.3`
+var COMPARATORTRIM = R++;
+src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] +
+                      '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')';
+
+// this one has to use the /g flag
+re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g');
+var comparatorTrimReplace = '$1$2$3';
+
+
+// Something like `1.2.3 - 1.2.4`
+// Note that these all use the loose form, because they'll be
+// checked against either the strict or loose comparator form
+// later.
+var HYPHENRANGE = R++;
+src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' +
+                   '\\s+-\\s+' +
+                   '(' + src[XRANGEPLAIN] + ')' +
+                   '\\s*$';
+
+var HYPHENRANGELOOSE = R++;
+src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' +
+                        '\\s+-\\s+' +
+                        '(' + src[XRANGEPLAINLOOSE] + ')' +
+                        '\\s*$';
+
+// Star ranges basically just allow anything at all.
+var STAR = R++;
+src[STAR] = '(<|>)?=?\\s*\\*';
+
+// Compile to actual regexp objects.
+// All are flag-free, unless they were created above with a flag.
+for (var i = 0; i < R; i++) {
+  ;
+  if (!re[i])
+    re[i] = new RegExp(src[i]);
+}
+
+exports.parse = parse;
+function parse(version, loose) {
+  if (version.length > MAX_LENGTH)
+    return null;
+
+  var r = loose ? re[LOOSE] : re[FULL];
+  if (!r.test(version))
+    return null;
+
+  try {
+    return new SemVer(version, loose);
+  } catch (er) {
+    return null;
+  }
+}
+
+exports.valid = valid;
+function valid(version, loose) {
+  var v = parse(version, loose);
+  return v ? v.version : null;
+}
+
+
+exports.clean = clean;
+function clean(version, loose) {
+  var s = parse(version.trim().replace(/^[=v]+/, ''), loose);
+  return s ? s.version : null;
+}
+
+exports.SemVer = SemVer;
+
+function SemVer(version, loose) {
+  if (version instanceof SemVer) {
+    if (version.loose === loose)
+      return version;
+    else
+      version = version.version;
+  } else if (typeof version !== 'string') {
+    throw new TypeError('Invalid Version: ' + version);
+  }
+
+  if (version.length > MAX_LENGTH)
+    throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters')
+
+  if (!(this instanceof SemVer))
+    return new SemVer(version, loose);
+
+  ;
+  this.loose = loose;
+  var m = version.trim().match(loose ? re[LOOSE] : re[FULL]);
+
+  if (!m)
+    throw new TypeError('Invalid Version: ' + version);
+
+  this.raw = version;
+
+  // these are actually numbers
+  this.major = +m[1];
+  this.minor = +m[2];
+  this.patch = +m[3];
+
+  if (this.major > MAX_SAFE_INTEGER || this.major < 0)
+    throw new TypeError('Invalid major version')
+
+  if (this.minor > MAX_SAFE_INTEGER || this.minor < 0)
+    throw new TypeError('Invalid minor version')
+
+  if (this.patch > MAX_SAFE_INTEGER || this.patch < 0)
+    throw new TypeError('Invalid patch version')
+
+  // numberify any prerelease numeric ids
+  if (!m[4])
+    this.prerelease = [];
+  else
+    this.prerelease = m[4].split('.').map(function(id) {
+      return (/^[0-9]+$/.test(id)) ? +id : id;
+    });
+
+  this.build = m[5] ? m[5].split('.') : [];
+  this.format();
+}
+
+SemVer.prototype.format = function() {
+  this.version = this.major + '.' + this.minor + '.' + this.patch;
+  if (this.prerelease.length)
+    this.version += '-' + this.prerelease.join('.');
+  return this.version;
+};
+
+SemVer.prototype.inspect = function() {
+  return '<SemVer "' + this + '">';
+};
+
+SemVer.prototype.toString = function() {
+  return this.version;
+};
+
+SemVer.prototype.compare = function(other) {
+  ;
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  return this.compareMain(other) || this.comparePre(other);
+};
+
+SemVer.prototype.compareMain = function(other) {
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  return compareIdentifiers(this.major, other.major) ||
+         compareIdentifiers(this.minor, other.minor) ||
+         compareIdentifiers(this.patch, other.patch);
+};
+
+SemVer.prototype.comparePre = function(other) {
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  // NOT having a prerelease is > having one
+  if (this.prerelease.length && !other.prerelease.length)
+    return -1;
+  else if (!this.prerelease.length && other.prerelease.length)
+    return 1;
+  else if (!this.prerelease.length && !other.prerelease.length)
+    return 0;
+
+  var i = 0;
+  do {
+    var a = this.prerelease[i];
+    var b = other.prerelease[i];
+    ;
+    if (a === undefined && b === undefined)
+      return 0;
+    else if (b === undefined)
+      return 1;
+    else if (a === undefined)
+      return -1;
+    else if (a === b)
+      continue;
+    else
+      return compareIdentifiers(a, b);
+  } while (++i);
+};
+
+// preminor will bump the version up to the next minor release, and immediately
+// down to pre-release. premajor and prepatch work the same way.
+SemVer.prototype.inc = function(release, identifier) {
+  switch (release) {
+    case 'premajor':
+      this.prerelease.length = 0;
+      this.patch = 0;
+      this.minor = 0;
+      this.major++;
+      this.inc('pre', identifier);
+      break;
+    case 'preminor':
+      this.prerelease.length = 0;
+      this.patch = 0;
+      this.minor++;
+      this.inc('pre', identifier);
+      break;
+    case 'prepatch':
+      // If this is already a prerelease, it will bump to the next version
+      // drop any prereleases that might already exist, since they are not
+      // relevant at this point.
+      this.prerelease.length = 0;
+      this.inc('patch', identifier);
+      this.inc('pre', identifier);
+      break;
+    // If the input is a non-prerelease version, this acts the same as
+    // prepatch.
+    case 'prerelease':
+      if (this.prerelease.length === 0)
+        this.inc('patch', identifier);
+      this.inc('pre', identifier);
+      break;
+
+    case 'major':
+      // If this is a pre-major version, bump up to the same major version.
+      // Otherwise increment major.
+      // 1.0.0-5 bumps to 1.0.0
+      // 1.1.0 bumps to 2.0.0
+      if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0)
+        this.major++;
+      this.minor = 0;
+      this.patch = 0;
+      this.prerelease = [];
+      break;
+    case 'minor':
+      // If this is a pre-minor version, bump up to the same minor version.
+      // Otherwise increment minor.
+      // 1.2.0-5 bumps to 1.2.0
+      // 1.2.1 bumps to 1.3.0
+      if (this.patch !== 0 || this.prerelease.length === 0)
+        this.minor++;
+      this.patch = 0;
+      this.prerelease = [];
+      break;
+    case 'patch':
+      // If this is not a pre-release version, it will increment the patch.
+      // If it is a pre-release it will bump up to the same patch version.
+      // 1.2.0-5 patches to 1.2.0
+      // 1.2.0 patches to 1.2.1
+      if (this.prerelease.length === 0)
+        this.patch++;
+      this.prerelease = [];
+      break;
+    // This probably shouldn't be used publicly.
+    // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
+    case 'pre':
+      if (this.prerelease.length === 0)
+        this.prerelease = [0];
+      else {
+        var i = this.prerelease.length;
+        while (--i >= 0) {
+          if (typeof this.prerelease[i] === 'number') {
+            this.prerelease[i]++;
+            i = -2;
+          }
+        }
+        if (i === -1) // didn't increment anything
+          this.prerelease.push(0);
+      }
+      if (identifier) {
+        // 1.2.0-beta.1 bumps to 1.2.0-beta.2,
+        // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
+        if (this.prerelease[0] === identifier) {
+          if (isNaN(this.prerelease[1]))
+            this.prerelease = [identifier, 0];
+        } else
+          this.prerelease = [identifier, 0];
+      }
+      break;
+
+    default:
+      throw new Error('invalid increment argument: ' + release);
+  }
+  this.format();
+  return this;
+};
+
+exports.inc = inc;
+function inc(version, release, loose, identifier) {
+  if (typeof(loose) === 'string') {
+    identifier = loose;
+    loose = undefined;
+  }
+
+  try {
+    return new SemVer(version, loose).inc(release, identifier).version;
+  } catch (er) {
+    return null;
+  }
+}
+
+exports.diff = diff;
+function diff(version1, version2) {
+  if (eq(version1, version2)) {
+    return null;
+  } else {
+    var v1 = parse(version1);
+    var v2 = parse(version2);
+    if (v1.prerelease.length || v2.prerelease.length) {
+      for (var key in v1) {
+        if (key === 'major' || key === 'minor' || key === 'patch') {
+          if (v1[key] !== v2[key]) {
+            return 'pre'+key;
+          }
+        }
+      }
+      return 'prerelease';
+    }
+    for (var key in v1) {
+      if (key === 'major' || key === 'minor' || key === 'patch') {
+        if (v1[key] !== v2[key]) {
+          return key;
+        }
+      }
+    }
+  }
+}
+
+exports.compareIdentifiers = compareIdentifiers;
+
+var numeric = /^[0-9]+$/;
+function compareIdentifiers(a, b) {
+  var anum = numeric.test(a);
+  var bnum = numeric.test(b);
+
+  if (anum && bnum) {
+    a = +a;
+    b = +b;
+  }
+
+  return (anum && !bnum) ? -1 :
+         (bnum && !anum) ? 1 :
+         a < b ? -1 :
+         a > b ? 1 :
+         0;
+}
+
+exports.rcompareIdentifiers = rcompareIdentifiers;
+function rcompareIdentifiers(a, b) {
+  return compareIdentifiers(b, a);
+}
+
+exports.major = major;
+function major(a, loose) {
+  return new SemVer(a, loose).major;
+}
+
+exports.minor = minor;
+function minor(a, loose) {
+  return new SemVer(a, loose).minor;
+}
+
+exports.patch = patch;
+function patch(a, loose) {
+  return new SemVer(a, loose).patch;
+}
+
+exports.compare = compare;
+function compare(a, b, loose) {
+  return new SemVer(a, loose).compare(b);
+}
+
+exports.compareLoose = compareLoose;
+function compareLoose(a, b) {
+  return compare(a, b, true);
+}
+
+exports.rcompare = rcompare;
+function rcompare(a, b, loose) {
+  return compare(b, a, loose);
+}
+
+exports.sort = sort;
+function sort(list, loose) {
+  return list.sort(function(a, b) {
+    return exports.compare(a, b, loose);
+  });
+}
+
+exports.rsort = rsort;
+function rsort(list, loose) {
+  return list.sort(function(a, b) {
+    return exports.rcompare(a, b, loose);
+  });
+}
+
+exports.gt = gt;
+function gt(a, b, loose) {
+  return compare(a, b, loose) > 0;
+}
+
+exports.lt = lt;
+function lt(a, b, loose) {
+  return compare(a, b, loose) < 0;
+}
+
+exports.eq = eq;
+function eq(a, b, loose) {
+  return compare(a, b, loose) === 0;
+}
+
+exports.neq = neq;
+function neq(a, b, loose) {
+  return compare(a, b, loose) !== 0;
+}
+
+exports.gte = gte;
+function gte(a, b, loose) {
+  return compare(a, b, loose) >= 0;
+}
+
+exports.lte = lte;
+function lte(a, b, loose) {
+  return compare(a, b, loose) <= 0;
+}
+
+exports.cmp = cmp;
+function cmp(a, op, b, loose) {
+  var ret;
+  switch (op) {
+    case '===':
+      if (typeof a === 'object') a = a.version;
+      if (typeof b === 'object') b = b.version;
+      ret = a === b;
+      break;
+    case '!==':
+      if (typeof a === 'object') a = a.version;
+      if (typeof b === 'object') b = b.version;
+      ret = a !== b;
+      break;
+    case '': case '=': case '==': ret = eq(a, b, loose); break;
+    case '!=': ret = neq(a, b, loose); break;
+    case '>': ret = gt(a, b, loose); break;
+    case '>=': ret = gte(a, b, loose); break;
+    case '<': ret = lt(a, b, loose); break;
+    case '<=': ret = lte(a, b, loose); break;
+    default: throw new TypeError('Invalid operator: ' + op);
+  }
+  return ret;
+}
+
+exports.Comparator = Comparator;
+function Comparator(comp, loose) {
+  if (comp instanceof Comparator) {
+    if (comp.loose === loose)
+      return comp;
+    else
+      comp = comp.value;
+  }
+
+  if (!(this instanceof Comparator))
+    return new Comparator(comp, loose);
+
+  ;
+  this.loose = loose;
+  this.parse(comp);
+
+  if (this.semver === ANY)
+    this.value = '';
+  else
+    this.value = this.operator + this.semver.version;
+
+  ;
+}
+
+var ANY = {};
+Comparator.prototype.parse = function(comp) {
+  var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR];
+  var m = comp.match(r);
+
+  if (!m)
+    throw new TypeError('Invalid comparator: ' + comp);
+
+  this.operator = m[1];
+  if (this.operator === '=')
+    this.operator = '';
+
+  // if it literally is just '>' or '' then allow anything.
+  if (!m[2])
+    this.semver = ANY;
+  else
+    this.semver = new SemVer(m[2], this.loose);
+};
+
+Comparator.prototype.inspect = function() {
+  return '<SemVer Comparator "' + this + '">';
+};
+
+Comparator.prototype.toString = function() {
+  return this.value;
+};
+
+Comparator.prototype.test = function(version) {
+  ;
+
+  if (this.semver === ANY)
+    return true;
+
+  if (typeof version === 'string')
+    version = new SemVer(version, this.loose);
+
+  return cmp(version, this.operator, this.semver, this.loose);
+};
+
+
+exports.Range = Range;
+function Range(range, loose) {
+  if ((range instanceof Range) && range.loose === loose)
+    return range;
+
+  if (!(this instanceof Range))
+    return new Range(range, loose);
+
+  this.loose = loose;
+
+  // First, split based on boolean or ||
+  this.raw = range;
+  this.set = range.split(/\s*\|\|\s*/).map(function(range) {
+    return this.parseRange(range.trim());
+  }, this).filter(function(c) {
+    // throw out any that are not relevant for whatever reason
+    return c.length;
+  });
+
+  if (!this.set.length) {
+    throw new TypeError('Invalid SemVer Range: ' + range);
+  }
+
+  this.format();
+}
+
+Range.prototype.inspect = function() {
+  return '<SemVer Range "' + this.range + '">';
+};
+
+Range.prototype.format = function() {
+  this.range = this.set.map(function(comps) {
+    return comps.join(' ').trim();
+  }).join('||').trim();
+  return this.range;
+};
+
+Range.prototype.toString = function() {
+  return this.range;
+};
+
+Range.prototype.parseRange = function(range) {
+  var loose = this.loose;
+  range = range.trim();
+  ;
+  // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
+  var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE];
+  range = range.replace(hr, hyphenReplace);
+  ;
+  // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
+  range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace);
+  ;
+
+  // `~ 1.2.3` => `~1.2.3`
+  range = range.replace(re[TILDETRIM], tildeTrimReplace);
+
+  // `^ 1.2.3` => `^1.2.3`
+  range = range.replace(re[CARETTRIM], caretTrimReplace);
+
+  // normalize spaces
+  range = range.split(/\s+/).join(' ');
+
+  // At this point, the range is completely trimmed and
+  // ready to be split into comparators.
+
+  var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR];
+  var set = range.split(' ').map(function(comp) {
+    return parseComparator(comp, loose);
+  }).join(' ').split(/\s+/);
+  if (this.loose) {
+    // in loose mode, throw out any that are not valid comparators
+    set = set.filter(function(comp) {
+      return !!comp.match(compRe);
+    });
+  }
+  set = set.map(function(comp) {
+    return new Comparator(comp, loose);
+  });
+
+  return set;
+};
+
+// Mostly just for testing and legacy API reasons
+exports.toComparators = toComparators;
+function toComparators(range, loose) {
+  return new Range(range, loose).set.map(function(comp) {
+    return comp.map(function(c) {
+      return c.value;
+    }).join(' ').trim().split(' ');
+  });
+}
+
+// comprised of xranges, tildes, stars, and gtlt's at this point.
+// already replaced the hyphen ranges
+// turn into a set of JUST comparators.
+function parseComparator(comp, loose) {
+  ;
+  comp = replaceCarets(comp, loose);
+  ;
+  comp = replaceTildes(comp, loose);
+  ;
+  comp = replaceXRanges(comp, loose);
+  ;
+  comp = replaceStars(comp, loose);
+  ;
+  return comp;
+}
+
+function isX(id) {
+  return !id || id.toLowerCase() === 'x' || id === '*';
+}
+
+// ~, ~> --> * (any, kinda silly)
+// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
+// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
+// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
+// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
+// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
+function replaceTildes(comp, loose) {
+  return comp.trim().split(/\s+/).map(function(comp) {
+    return replaceTilde(comp, loose);
+  }).join(' ');
+}
+
+function replaceTilde(comp, loose) {
+  var r = loose ? re[TILDELOOSE] : re[TILDE];
+  return comp.replace(r, function(_, M, m, p, pr) {
+    ;
+    var ret;
+
+    if (isX(M))
+      ret = '';
+    else if (isX(m))
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    else if (isX(p))
+      // ~1.2 == >=1.2.0- <1.3.0-
+      ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+    else if (pr) {
+      ;
+      if (pr.charAt(0) !== '-')
+        pr = '-' + pr;
+      ret = '>=' + M + '.' + m + '.' + p + pr +
+            ' <' + M + '.' + (+m + 1) + '.0';
+    } else
+      // ~1.2.3 == >=1.2.3 <1.3.0
+      ret = '>=' + M + '.' + m + '.' + p +
+            ' <' + M + '.' + (+m + 1) + '.0';
+
+    ;
+    return ret;
+  });
+}
+
+// ^ --> * (any, kinda silly)
+// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
+// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
+// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
+// ^1.2.3 --> >=1.2.3 <2.0.0
+// ^1.2.0 --> >=1.2.0 <2.0.0
+function replaceCarets(comp, loose) {
+  return comp.trim().split(/\s+/).map(function(comp) {
+    return replaceCaret(comp, loose);
+  }).join(' ');
+}
+
+function replaceCaret(comp, loose) {
+  ;
+  var r = loose ? re[CARETLOOSE] : re[CARET];
+  return comp.replace(r, function(_, M, m, p, pr) {
+    ;
+    var ret;
+
+    if (isX(M))
+      ret = '';
+    else if (isX(m))
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    else if (isX(p)) {
+      if (M === '0')
+        ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+      else
+        ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0';
+    } else if (pr) {
+      ;
+      if (pr.charAt(0) !== '-')
+        pr = '-' + pr;
+      if (M === '0') {
+        if (m === '0')
+          ret = '>=' + M + '.' + m + '.' + p + pr +
+                ' <' + M + '.' + m + '.' + (+p + 1);
+        else
+          ret = '>=' + M + '.' + m + '.' + p + pr +
+                ' <' + M + '.' + (+m + 1) + '.0';
+      } else
+        ret = '>=' + M + '.' + m + '.' + p + pr +
+              ' <' + (+M + 1) + '.0.0';
+    } else {
+      ;
+      if (M === '0') {
+        if (m === '0')
+          ret = '>=' + M + '.' + m + '.' + p +
+                ' <' + M + '.' + m + '.' + (+p + 1);
+        else
+          ret = '>=' + M + '.' + m + '.' + p +
+                ' <' + M + '.' + (+m + 1) + '.0';
+      } else
+        ret = '>=' + M + '.' + m + '.' + p +
+              ' <' + (+M + 1) + '.0.0';
+    }
+
+    ;
+    return ret;
+  });
+}
+
+function replaceXRanges(comp, loose) {
+  ;
+  return comp.split(/\s+/).map(function(comp) {
+    return replaceXRange(comp, loose);
+  }).join(' ');
+}
+
+function replaceXRange(comp, loose) {
+  comp = comp.trim();
+  var r = loose ? re[XRANGELOOSE] : re[XRANGE];
+  return comp.replace(r, function(ret, gtlt, M, m, p, pr) {
+    ;
+    var xM = isX(M);
+    var xm = xM || isX(m);
+    var xp = xm || isX(p);
+    var anyX = xp;
+
+    if (gtlt === '=' && anyX)
+      gtlt = '';
+
+    if (xM) {
+      if (gtlt === '>' || gtlt === '<') {
+        // nothing is allowed
+        ret = '<0.0.0';
+      } else {
+        // nothing is forbidden
+        ret = '*';
+      }
+    } else if (gtlt && anyX) {
+      // replace X with 0
+      if (xm)
+        m = 0;
+      if (xp)
+        p = 0;
+
+      if (gtlt === '>') {
+        // >1 => >=2.0.0
+        // >1.2 => >=1.3.0
+        // >1.2.3 => >= 1.2.4
+        gtlt = '>=';
+        if (xm) {
+          M = +M + 1;
+          m = 0;
+          p = 0;
+        } else if (xp) {
+          m = +m + 1;
+          p = 0;
+        }
+      } else if (gtlt === '<=') {
+        // <=0.7.x is actually <0.8.0, since any 0.7.x should
+        // pass.  Similarly, <=7.x is actually <8.0.0, etc.
+        gtlt = '<'
+        if (xm)
+          M = +M + 1
+        else
+          m = +m + 1
+      }
+
+      ret = gtlt + M + '.' + m + '.' + p;
+    } else if (xm) {
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    } else if (xp) {
+      ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+    }
+
+    ;
+
+    return ret;
+  });
+}
+
+// Because * is AND-ed with everything else in the comparator,
+// and '' means "any version", just remove the *s entirely.
+function replaceStars(comp, loose) {
+  ;
+  // Looseness is ignored here.  star is always as loose as it gets!
+  return comp.trim().replace(re[STAR], '');
+}
+
+// This function is passed to string.replace(re[HYPHENRANGE])
+// M, m, patch, prerelease, build
+// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
+// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
+// 1.2 - 3.4 => >=1.2.0 <3.5.0
+function hyphenReplace($0,
+                       from, fM, fm, fp, fpr, fb,
+                       to, tM, tm, tp, tpr, tb) {
+
+  if (isX(fM))
+    from = '';
+  else if (isX(fm))
+    from = '>=' + fM + '.0.0';
+  else if (isX(fp))
+    from = '>=' + fM + '.' + fm + '.0';
+  else
+    from = '>=' + from;
+
+  if (isX(tM))
+    to = '';
+  else if (isX(tm))
+    to = '<' + (+tM + 1) + '.0.0';
+  else if (isX(tp))
+    to = '<' + tM + '.' + (+tm + 1) + '.0';
+  else if (tpr)
+    to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr;
+  else
+    to = '<=' + to;
+
+  return (from + ' ' + to).trim();
+}
+
+
+// if ANY of the sets match ALL of its comparators, then pass
+Range.prototype.test = function(version) {
+  if (!version)
+    return false;
+
+  if (typeof version === 'string')
+    version = new SemVer(version, this.loose);
+
+  for (var i = 0; i < this.set.length; i++) {
+    if (testSet(this.set[i], version))
+      return true;
+  }
+  return false;
+};
+
+function testSet(set, version) {
+  for (var i = 0; i < set.length; i++) {
+    if (!set[i].test(version))
+      return false;
+  }
+
+  if (version.prerelease.length) {
+    // Find the set of versions that are allowed to have prereleases
+    // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
+    // That should allow `1.2.3-pr.2` to pass.
+    // However, `1.2.4-alpha.notready` should NOT be allowed,
+    // even though it's within the range set by the comparators.
+    for (var i = 0; i < set.length; i++) {
+      ;
+      if (set[i].semver === ANY)
+        return true;
+
+      if (set[i].semver.prerelease.length > 0) {
+        var allowed = set[i].semver;
+        if (allowed.major === version.major &&
+            allowed.minor === version.minor &&
+            allowed.patch === version.patch)
+          return true;
+      }
+    }
+
+    // Version has a -pre, but it's not one of the ones we like.
+    return false;
+  }
+
+  return true;
+}
+
+exports.satisfies = satisfies;
+function satisfies(version, range, loose) {
+  try {
+    range = new Range(range, loose);
+  } catch (er) {
+    return false;
+  }
+  return range.test(version);
+}
+
+exports.maxSatisfying = maxSatisfying;
+function maxSatisfying(versions, range, loose) {
+  return versions.filter(function(version) {
+    return satisfies(version, range, loose);
+  }).sort(function(a, b) {
+    return rcompare(a, b, loose);
+  })[0] || null;
+}
+
+exports.validRange = validRange;
+function validRange(range, loose) {
+  try {
+    // Return '*' instead of '' so that truthiness works.
+    // This will throw if it's invalid anyway
+    return new Range(range, loose).range || '*';
+  } catch (er) {
+    return null;
+  }
+}
+
+// Determine if version is less than all the versions possible in the range
+exports.ltr = ltr;
+function ltr(version, range, loose) {
+  return outside(version, range, '<', loose);
+}
+
+// Determine if version is greater than all the versions possible in the range.
+exports.gtr = gtr;
+function gtr(version, range, loose) {
+  return outside(version, range, '>', loose);
+}
+
+exports.outside = outside;
+function outside(version, range, hilo, loose) {
+  version = new SemVer(version, loose);
+  range = new Range(range, loose);
+
+  var gtfn, ltefn, ltfn, comp, ecomp;
+  switch (hilo) {
+    case '>':
+      gtfn = gt;
+      ltefn = lte;
+      ltfn = lt;
+      comp = '>';
+      ecomp = '>=';
+      break;
+    case '<':
+      gtfn = lt;
+      ltefn = gte;
+      ltfn = gt;
+      comp = '<';
+      ecomp = '<=';
+      break;
+    default:
+      throw new TypeError('Must provide a hilo val of "<" or ">"');
+  }
+
+  // If it satisifes the range it is not outside
+  if (satisfies(version, range, loose)) {
+    return false;
+  }
+
+  // From now on, variable terms are as if we're in "gtr" mode.
+  // but note that everything is flipped for the "ltr" function.
+
+  for (var i = 0; i < range.set.length; ++i) {
+    var comparators = range.set[i];
+
+    var high = null;
+    var low = null;
+
+    comparators.forEach(function(comparator) {
+      high = high || comparator;
+      low = low || comparator;
+      if (gtfn(comparator.semver, high.semver, loose)) {
+        high = comparator;
+      } else if (ltfn(comparator.semver, low.semver, loose)) {
+        low = comparator;
+      }
+    });
+
+    // If the edge version comparator has a operator then our version
+    // isn't outside it
+    if (high.operator === comp || high.operator === ecomp) {
+      return false;
+    }
+
+    // If the lowest version comparator has an operator and our version
+    // is less than it then it isn't higher than the range
+    if ((!low.operator || low.operator === comp) &&
+        ltefn(version, low.semver)) {
+      return false;
+    } else if (low.operator === ecomp && ltfn(version, low.semver)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Use the define() function if we're in AMD land
+if (typeof define === 'function' && define.amd)
+  define(exports);
+
+})(
+  typeof exports === 'object' ? exports :
+  typeof define === 'function' && define.amd ? {} :
+  semver = {}
+);
diff --git a/server/node_modules/pgtools/node_modules/semver/semver.browser.js.gz b/server/node_modules/pgtools/node_modules/semver/semver.browser.js.gz
new file mode 100644
index 0000000000000000000000000000000000000000..6a8cf09559b126dbaa32606c11ae43c302a9d1b5
Binary files /dev/null and b/server/node_modules/pgtools/node_modules/semver/semver.browser.js.gz differ
diff --git a/server/node_modules/pgtools/node_modules/semver/semver.js b/server/node_modules/pgtools/node_modules/semver/semver.js
new file mode 100644
index 0000000000000000000000000000000000000000..d265b568edfaefcdfd12ae6f44243d746cca636e
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/semver.js
@@ -0,0 +1,1191 @@
+// export the class if we are in a Node-like system.
+if (typeof module === 'object' && module.exports === exports)
+  exports = module.exports = SemVer;
+
+// The debug function is excluded entirely from the minified version.
+/* nomin */ var debug;
+/* nomin */ if (typeof process === 'object' &&
+    /* nomin */ process.env &&
+    /* nomin */ process.env.NODE_DEBUG &&
+    /* nomin */ /\bsemver\b/i.test(process.env.NODE_DEBUG))
+  /* nomin */ debug = function() {
+    /* nomin */ var args = Array.prototype.slice.call(arguments, 0);
+    /* nomin */ args.unshift('SEMVER');
+    /* nomin */ console.log.apply(console, args);
+    /* nomin */ };
+/* nomin */ else
+  /* nomin */ debug = function() {};
+
+// Note: this is the semver.org version of the spec that it implements
+// Not necessarily the package version of this code.
+exports.SEMVER_SPEC_VERSION = '2.0.0';
+
+var MAX_LENGTH = 256;
+var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
+
+// The actual regexps go on exports.re
+var re = exports.re = [];
+var src = exports.src = [];
+var R = 0;
+
+// The following Regular Expressions can be used for tokenizing,
+// validating, and parsing SemVer version strings.
+
+// ## Numeric Identifier
+// A single `0`, or a non-zero digit followed by zero or more digits.
+
+var NUMERICIDENTIFIER = R++;
+src[NUMERICIDENTIFIER] = '0|[1-9]\\d*';
+var NUMERICIDENTIFIERLOOSE = R++;
+src[NUMERICIDENTIFIERLOOSE] = '[0-9]+';
+
+
+// ## Non-numeric Identifier
+// Zero or more digits, followed by a letter or hyphen, and then zero or
+// more letters, digits, or hyphens.
+
+var NONNUMERICIDENTIFIER = R++;
+src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*';
+
+
+// ## Main Version
+// Three dot-separated numeric identifiers.
+
+var MAINVERSION = R++;
+src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' +
+                   '(' + src[NUMERICIDENTIFIER] + ')\\.' +
+                   '(' + src[NUMERICIDENTIFIER] + ')';
+
+var MAINVERSIONLOOSE = R++;
+src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
+                        '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' +
+                        '(' + src[NUMERICIDENTIFIERLOOSE] + ')';
+
+// ## Pre-release Version Identifier
+// A numeric identifier, or a non-numeric identifier.
+
+var PRERELEASEIDENTIFIER = R++;
+src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] +
+                            '|' + src[NONNUMERICIDENTIFIER] + ')';
+
+var PRERELEASEIDENTIFIERLOOSE = R++;
+src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] +
+                                 '|' + src[NONNUMERICIDENTIFIER] + ')';
+
+
+// ## Pre-release Version
+// Hyphen, followed by one or more dot-separated pre-release version
+// identifiers.
+
+var PRERELEASE = R++;
+src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] +
+                  '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))';
+
+var PRERELEASELOOSE = R++;
+src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] +
+                       '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))';
+
+// ## Build Metadata Identifier
+// Any combination of digits, letters, or hyphens.
+
+var BUILDIDENTIFIER = R++;
+src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+';
+
+// ## Build Metadata
+// Plus sign, followed by one or more period-separated build metadata
+// identifiers.
+
+var BUILD = R++;
+src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] +
+             '(?:\\.' + src[BUILDIDENTIFIER] + ')*))';
+
+
+// ## Full Version String
+// A main version, followed optionally by a pre-release version and
+// build metadata.
+
+// Note that the only major, minor, patch, and pre-release sections of
+// the version string are capturing groups.  The build metadata is not a
+// capturing group, because it should not ever be used in version
+// comparison.
+
+var FULL = R++;
+var FULLPLAIN = 'v?' + src[MAINVERSION] +
+                src[PRERELEASE] + '?' +
+                src[BUILD] + '?';
+
+src[FULL] = '^' + FULLPLAIN + '$';
+
+// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
+// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
+// common in the npm registry.
+var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] +
+                 src[PRERELEASELOOSE] + '?' +
+                 src[BUILD] + '?';
+
+var LOOSE = R++;
+src[LOOSE] = '^' + LOOSEPLAIN + '$';
+
+var GTLT = R++;
+src[GTLT] = '((?:<|>)?=?)';
+
+// Something like "2.*" or "1.2.x".
+// Note that "x.x" is a valid xRange identifer, meaning "any version"
+// Only the first item is strictly required.
+var XRANGEIDENTIFIERLOOSE = R++;
+src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*';
+var XRANGEIDENTIFIER = R++;
+src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*';
+
+var XRANGEPLAIN = R++;
+src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' +
+                   '(?:' + src[PRERELEASE] + ')?' +
+                   src[BUILD] + '?' +
+                   ')?)?';
+
+var XRANGEPLAINLOOSE = R++;
+src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' +
+                        '(?:' + src[PRERELEASELOOSE] + ')?' +
+                        src[BUILD] + '?' +
+                        ')?)?';
+
+var XRANGE = R++;
+src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$';
+var XRANGELOOSE = R++;
+src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$';
+
+// Tilde ranges.
+// Meaning is "reasonably at or greater than"
+var LONETILDE = R++;
+src[LONETILDE] = '(?:~>?)';
+
+var TILDETRIM = R++;
+src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+';
+re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g');
+var tildeTrimReplace = '$1~';
+
+var TILDE = R++;
+src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$';
+var TILDELOOSE = R++;
+src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$';
+
+// Caret ranges.
+// Meaning is "at least and backwards compatible with"
+var LONECARET = R++;
+src[LONECARET] = '(?:\\^)';
+
+var CARETTRIM = R++;
+src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+';
+re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g');
+var caretTrimReplace = '$1^';
+
+var CARET = R++;
+src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$';
+var CARETLOOSE = R++;
+src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$';
+
+// A simple gt/lt/eq thing, or just "" to indicate "any version"
+var COMPARATORLOOSE = R++;
+src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$';
+var COMPARATOR = R++;
+src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$';
+
+
+// An expression to strip any whitespace between the gtlt and the thing
+// it modifies, so that `> 1.2.3` ==> `>1.2.3`
+var COMPARATORTRIM = R++;
+src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] +
+                      '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')';
+
+// this one has to use the /g flag
+re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g');
+var comparatorTrimReplace = '$1$2$3';
+
+
+// Something like `1.2.3 - 1.2.4`
+// Note that these all use the loose form, because they'll be
+// checked against either the strict or loose comparator form
+// later.
+var HYPHENRANGE = R++;
+src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' +
+                   '\\s+-\\s+' +
+                   '(' + src[XRANGEPLAIN] + ')' +
+                   '\\s*$';
+
+var HYPHENRANGELOOSE = R++;
+src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' +
+                        '\\s+-\\s+' +
+                        '(' + src[XRANGEPLAINLOOSE] + ')' +
+                        '\\s*$';
+
+// Star ranges basically just allow anything at all.
+var STAR = R++;
+src[STAR] = '(<|>)?=?\\s*\\*';
+
+// Compile to actual regexp objects.
+// All are flag-free, unless they were created above with a flag.
+for (var i = 0; i < R; i++) {
+  debug(i, src[i]);
+  if (!re[i])
+    re[i] = new RegExp(src[i]);
+}
+
+exports.parse = parse;
+function parse(version, loose) {
+  if (version.length > MAX_LENGTH)
+    return null;
+
+  var r = loose ? re[LOOSE] : re[FULL];
+  if (!r.test(version))
+    return null;
+
+  try {
+    return new SemVer(version, loose);
+  } catch (er) {
+    return null;
+  }
+}
+
+exports.valid = valid;
+function valid(version, loose) {
+  var v = parse(version, loose);
+  return v ? v.version : null;
+}
+
+
+exports.clean = clean;
+function clean(version, loose) {
+  var s = parse(version.trim().replace(/^[=v]+/, ''), loose);
+  return s ? s.version : null;
+}
+
+exports.SemVer = SemVer;
+
+function SemVer(version, loose) {
+  if (version instanceof SemVer) {
+    if (version.loose === loose)
+      return version;
+    else
+      version = version.version;
+  } else if (typeof version !== 'string') {
+    throw new TypeError('Invalid Version: ' + version);
+  }
+
+  if (version.length > MAX_LENGTH)
+    throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters')
+
+  if (!(this instanceof SemVer))
+    return new SemVer(version, loose);
+
+  debug('SemVer', version, loose);
+  this.loose = loose;
+  var m = version.trim().match(loose ? re[LOOSE] : re[FULL]);
+
+  if (!m)
+    throw new TypeError('Invalid Version: ' + version);
+
+  this.raw = version;
+
+  // these are actually numbers
+  this.major = +m[1];
+  this.minor = +m[2];
+  this.patch = +m[3];
+
+  if (this.major > MAX_SAFE_INTEGER || this.major < 0)
+    throw new TypeError('Invalid major version')
+
+  if (this.minor > MAX_SAFE_INTEGER || this.minor < 0)
+    throw new TypeError('Invalid minor version')
+
+  if (this.patch > MAX_SAFE_INTEGER || this.patch < 0)
+    throw new TypeError('Invalid patch version')
+
+  // numberify any prerelease numeric ids
+  if (!m[4])
+    this.prerelease = [];
+  else
+    this.prerelease = m[4].split('.').map(function(id) {
+      return (/^[0-9]+$/.test(id)) ? +id : id;
+    });
+
+  this.build = m[5] ? m[5].split('.') : [];
+  this.format();
+}
+
+SemVer.prototype.format = function() {
+  this.version = this.major + '.' + this.minor + '.' + this.patch;
+  if (this.prerelease.length)
+    this.version += '-' + this.prerelease.join('.');
+  return this.version;
+};
+
+SemVer.prototype.inspect = function() {
+  return '<SemVer "' + this + '">';
+};
+
+SemVer.prototype.toString = function() {
+  return this.version;
+};
+
+SemVer.prototype.compare = function(other) {
+  debug('SemVer.compare', this.version, this.loose, other);
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  return this.compareMain(other) || this.comparePre(other);
+};
+
+SemVer.prototype.compareMain = function(other) {
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  return compareIdentifiers(this.major, other.major) ||
+         compareIdentifiers(this.minor, other.minor) ||
+         compareIdentifiers(this.patch, other.patch);
+};
+
+SemVer.prototype.comparePre = function(other) {
+  if (!(other instanceof SemVer))
+    other = new SemVer(other, this.loose);
+
+  // NOT having a prerelease is > having one
+  if (this.prerelease.length && !other.prerelease.length)
+    return -1;
+  else if (!this.prerelease.length && other.prerelease.length)
+    return 1;
+  else if (!this.prerelease.length && !other.prerelease.length)
+    return 0;
+
+  var i = 0;
+  do {
+    var a = this.prerelease[i];
+    var b = other.prerelease[i];
+    debug('prerelease compare', i, a, b);
+    if (a === undefined && b === undefined)
+      return 0;
+    else if (b === undefined)
+      return 1;
+    else if (a === undefined)
+      return -1;
+    else if (a === b)
+      continue;
+    else
+      return compareIdentifiers(a, b);
+  } while (++i);
+};
+
+// preminor will bump the version up to the next minor release, and immediately
+// down to pre-release. premajor and prepatch work the same way.
+SemVer.prototype.inc = function(release, identifier) {
+  switch (release) {
+    case 'premajor':
+      this.prerelease.length = 0;
+      this.patch = 0;
+      this.minor = 0;
+      this.major++;
+      this.inc('pre', identifier);
+      break;
+    case 'preminor':
+      this.prerelease.length = 0;
+      this.patch = 0;
+      this.minor++;
+      this.inc('pre', identifier);
+      break;
+    case 'prepatch':
+      // If this is already a prerelease, it will bump to the next version
+      // drop any prereleases that might already exist, since they are not
+      // relevant at this point.
+      this.prerelease.length = 0;
+      this.inc('patch', identifier);
+      this.inc('pre', identifier);
+      break;
+    // If the input is a non-prerelease version, this acts the same as
+    // prepatch.
+    case 'prerelease':
+      if (this.prerelease.length === 0)
+        this.inc('patch', identifier);
+      this.inc('pre', identifier);
+      break;
+
+    case 'major':
+      // If this is a pre-major version, bump up to the same major version.
+      // Otherwise increment major.
+      // 1.0.0-5 bumps to 1.0.0
+      // 1.1.0 bumps to 2.0.0
+      if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0)
+        this.major++;
+      this.minor = 0;
+      this.patch = 0;
+      this.prerelease = [];
+      break;
+    case 'minor':
+      // If this is a pre-minor version, bump up to the same minor version.
+      // Otherwise increment minor.
+      // 1.2.0-5 bumps to 1.2.0
+      // 1.2.1 bumps to 1.3.0
+      if (this.patch !== 0 || this.prerelease.length === 0)
+        this.minor++;
+      this.patch = 0;
+      this.prerelease = [];
+      break;
+    case 'patch':
+      // If this is not a pre-release version, it will increment the patch.
+      // If it is a pre-release it will bump up to the same patch version.
+      // 1.2.0-5 patches to 1.2.0
+      // 1.2.0 patches to 1.2.1
+      if (this.prerelease.length === 0)
+        this.patch++;
+      this.prerelease = [];
+      break;
+    // This probably shouldn't be used publicly.
+    // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction.
+    case 'pre':
+      if (this.prerelease.length === 0)
+        this.prerelease = [0];
+      else {
+        var i = this.prerelease.length;
+        while (--i >= 0) {
+          if (typeof this.prerelease[i] === 'number') {
+            this.prerelease[i]++;
+            i = -2;
+          }
+        }
+        if (i === -1) // didn't increment anything
+          this.prerelease.push(0);
+      }
+      if (identifier) {
+        // 1.2.0-beta.1 bumps to 1.2.0-beta.2,
+        // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0
+        if (this.prerelease[0] === identifier) {
+          if (isNaN(this.prerelease[1]))
+            this.prerelease = [identifier, 0];
+        } else
+          this.prerelease = [identifier, 0];
+      }
+      break;
+
+    default:
+      throw new Error('invalid increment argument: ' + release);
+  }
+  this.format();
+  return this;
+};
+
+exports.inc = inc;
+function inc(version, release, loose, identifier) {
+  if (typeof(loose) === 'string') {
+    identifier = loose;
+    loose = undefined;
+  }
+
+  try {
+    return new SemVer(version, loose).inc(release, identifier).version;
+  } catch (er) {
+    return null;
+  }
+}
+
+exports.diff = diff;
+function diff(version1, version2) {
+  if (eq(version1, version2)) {
+    return null;
+  } else {
+    var v1 = parse(version1);
+    var v2 = parse(version2);
+    if (v1.prerelease.length || v2.prerelease.length) {
+      for (var key in v1) {
+        if (key === 'major' || key === 'minor' || key === 'patch') {
+          if (v1[key] !== v2[key]) {
+            return 'pre'+key;
+          }
+        }
+      }
+      return 'prerelease';
+    }
+    for (var key in v1) {
+      if (key === 'major' || key === 'minor' || key === 'patch') {
+        if (v1[key] !== v2[key]) {
+          return key;
+        }
+      }
+    }
+  }
+}
+
+exports.compareIdentifiers = compareIdentifiers;
+
+var numeric = /^[0-9]+$/;
+function compareIdentifiers(a, b) {
+  var anum = numeric.test(a);
+  var bnum = numeric.test(b);
+
+  if (anum && bnum) {
+    a = +a;
+    b = +b;
+  }
+
+  return (anum && !bnum) ? -1 :
+         (bnum && !anum) ? 1 :
+         a < b ? -1 :
+         a > b ? 1 :
+         0;
+}
+
+exports.rcompareIdentifiers = rcompareIdentifiers;
+function rcompareIdentifiers(a, b) {
+  return compareIdentifiers(b, a);
+}
+
+exports.major = major;
+function major(a, loose) {
+  return new SemVer(a, loose).major;
+}
+
+exports.minor = minor;
+function minor(a, loose) {
+  return new SemVer(a, loose).minor;
+}
+
+exports.patch = patch;
+function patch(a, loose) {
+  return new SemVer(a, loose).patch;
+}
+
+exports.compare = compare;
+function compare(a, b, loose) {
+  return new SemVer(a, loose).compare(b);
+}
+
+exports.compareLoose = compareLoose;
+function compareLoose(a, b) {
+  return compare(a, b, true);
+}
+
+exports.rcompare = rcompare;
+function rcompare(a, b, loose) {
+  return compare(b, a, loose);
+}
+
+exports.sort = sort;
+function sort(list, loose) {
+  return list.sort(function(a, b) {
+    return exports.compare(a, b, loose);
+  });
+}
+
+exports.rsort = rsort;
+function rsort(list, loose) {
+  return list.sort(function(a, b) {
+    return exports.rcompare(a, b, loose);
+  });
+}
+
+exports.gt = gt;
+function gt(a, b, loose) {
+  return compare(a, b, loose) > 0;
+}
+
+exports.lt = lt;
+function lt(a, b, loose) {
+  return compare(a, b, loose) < 0;
+}
+
+exports.eq = eq;
+function eq(a, b, loose) {
+  return compare(a, b, loose) === 0;
+}
+
+exports.neq = neq;
+function neq(a, b, loose) {
+  return compare(a, b, loose) !== 0;
+}
+
+exports.gte = gte;
+function gte(a, b, loose) {
+  return compare(a, b, loose) >= 0;
+}
+
+exports.lte = lte;
+function lte(a, b, loose) {
+  return compare(a, b, loose) <= 0;
+}
+
+exports.cmp = cmp;
+function cmp(a, op, b, loose) {
+  var ret;
+  switch (op) {
+    case '===':
+      if (typeof a === 'object') a = a.version;
+      if (typeof b === 'object') b = b.version;
+      ret = a === b;
+      break;
+    case '!==':
+      if (typeof a === 'object') a = a.version;
+      if (typeof b === 'object') b = b.version;
+      ret = a !== b;
+      break;
+    case '': case '=': case '==': ret = eq(a, b, loose); break;
+    case '!=': ret = neq(a, b, loose); break;
+    case '>': ret = gt(a, b, loose); break;
+    case '>=': ret = gte(a, b, loose); break;
+    case '<': ret = lt(a, b, loose); break;
+    case '<=': ret = lte(a, b, loose); break;
+    default: throw new TypeError('Invalid operator: ' + op);
+  }
+  return ret;
+}
+
+exports.Comparator = Comparator;
+function Comparator(comp, loose) {
+  if (comp instanceof Comparator) {
+    if (comp.loose === loose)
+      return comp;
+    else
+      comp = comp.value;
+  }
+
+  if (!(this instanceof Comparator))
+    return new Comparator(comp, loose);
+
+  debug('comparator', comp, loose);
+  this.loose = loose;
+  this.parse(comp);
+
+  if (this.semver === ANY)
+    this.value = '';
+  else
+    this.value = this.operator + this.semver.version;
+
+  debug('comp', this);
+}
+
+var ANY = {};
+Comparator.prototype.parse = function(comp) {
+  var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR];
+  var m = comp.match(r);
+
+  if (!m)
+    throw new TypeError('Invalid comparator: ' + comp);
+
+  this.operator = m[1];
+  if (this.operator === '=')
+    this.operator = '';
+
+  // if it literally is just '>' or '' then allow anything.
+  if (!m[2])
+    this.semver = ANY;
+  else
+    this.semver = new SemVer(m[2], this.loose);
+};
+
+Comparator.prototype.inspect = function() {
+  return '<SemVer Comparator "' + this + '">';
+};
+
+Comparator.prototype.toString = function() {
+  return this.value;
+};
+
+Comparator.prototype.test = function(version) {
+  debug('Comparator.test', version, this.loose);
+
+  if (this.semver === ANY)
+    return true;
+
+  if (typeof version === 'string')
+    version = new SemVer(version, this.loose);
+
+  return cmp(version, this.operator, this.semver, this.loose);
+};
+
+
+exports.Range = Range;
+function Range(range, loose) {
+  if ((range instanceof Range) && range.loose === loose)
+    return range;
+
+  if (!(this instanceof Range))
+    return new Range(range, loose);
+
+  this.loose = loose;
+
+  // First, split based on boolean or ||
+  this.raw = range;
+  this.set = range.split(/\s*\|\|\s*/).map(function(range) {
+    return this.parseRange(range.trim());
+  }, this).filter(function(c) {
+    // throw out any that are not relevant for whatever reason
+    return c.length;
+  });
+
+  if (!this.set.length) {
+    throw new TypeError('Invalid SemVer Range: ' + range);
+  }
+
+  this.format();
+}
+
+Range.prototype.inspect = function() {
+  return '<SemVer Range "' + this.range + '">';
+};
+
+Range.prototype.format = function() {
+  this.range = this.set.map(function(comps) {
+    return comps.join(' ').trim();
+  }).join('||').trim();
+  return this.range;
+};
+
+Range.prototype.toString = function() {
+  return this.range;
+};
+
+Range.prototype.parseRange = function(range) {
+  var loose = this.loose;
+  range = range.trim();
+  debug('range', range, loose);
+  // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
+  var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE];
+  range = range.replace(hr, hyphenReplace);
+  debug('hyphen replace', range);
+  // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`
+  range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace);
+  debug('comparator trim', range, re[COMPARATORTRIM]);
+
+  // `~ 1.2.3` => `~1.2.3`
+  range = range.replace(re[TILDETRIM], tildeTrimReplace);
+
+  // `^ 1.2.3` => `^1.2.3`
+  range = range.replace(re[CARETTRIM], caretTrimReplace);
+
+  // normalize spaces
+  range = range.split(/\s+/).join(' ');
+
+  // At this point, the range is completely trimmed and
+  // ready to be split into comparators.
+
+  var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR];
+  var set = range.split(' ').map(function(comp) {
+    return parseComparator(comp, loose);
+  }).join(' ').split(/\s+/);
+  if (this.loose) {
+    // in loose mode, throw out any that are not valid comparators
+    set = set.filter(function(comp) {
+      return !!comp.match(compRe);
+    });
+  }
+  set = set.map(function(comp) {
+    return new Comparator(comp, loose);
+  });
+
+  return set;
+};
+
+// Mostly just for testing and legacy API reasons
+exports.toComparators = toComparators;
+function toComparators(range, loose) {
+  return new Range(range, loose).set.map(function(comp) {
+    return comp.map(function(c) {
+      return c.value;
+    }).join(' ').trim().split(' ');
+  });
+}
+
+// comprised of xranges, tildes, stars, and gtlt's at this point.
+// already replaced the hyphen ranges
+// turn into a set of JUST comparators.
+function parseComparator(comp, loose) {
+  debug('comp', comp);
+  comp = replaceCarets(comp, loose);
+  debug('caret', comp);
+  comp = replaceTildes(comp, loose);
+  debug('tildes', comp);
+  comp = replaceXRanges(comp, loose);
+  debug('xrange', comp);
+  comp = replaceStars(comp, loose);
+  debug('stars', comp);
+  return comp;
+}
+
+function isX(id) {
+  return !id || id.toLowerCase() === 'x' || id === '*';
+}
+
+// ~, ~> --> * (any, kinda silly)
+// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0
+// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0
+// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0
+// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0
+// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0
+function replaceTildes(comp, loose) {
+  return comp.trim().split(/\s+/).map(function(comp) {
+    return replaceTilde(comp, loose);
+  }).join(' ');
+}
+
+function replaceTilde(comp, loose) {
+  var r = loose ? re[TILDELOOSE] : re[TILDE];
+  return comp.replace(r, function(_, M, m, p, pr) {
+    debug('tilde', comp, _, M, m, p, pr);
+    var ret;
+
+    if (isX(M))
+      ret = '';
+    else if (isX(m))
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    else if (isX(p))
+      // ~1.2 == >=1.2.0- <1.3.0-
+      ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+    else if (pr) {
+      debug('replaceTilde pr', pr);
+      if (pr.charAt(0) !== '-')
+        pr = '-' + pr;
+      ret = '>=' + M + '.' + m + '.' + p + pr +
+            ' <' + M + '.' + (+m + 1) + '.0';
+    } else
+      // ~1.2.3 == >=1.2.3 <1.3.0
+      ret = '>=' + M + '.' + m + '.' + p +
+            ' <' + M + '.' + (+m + 1) + '.0';
+
+    debug('tilde return', ret);
+    return ret;
+  });
+}
+
+// ^ --> * (any, kinda silly)
+// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0
+// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0
+// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0
+// ^1.2.3 --> >=1.2.3 <2.0.0
+// ^1.2.0 --> >=1.2.0 <2.0.0
+function replaceCarets(comp, loose) {
+  return comp.trim().split(/\s+/).map(function(comp) {
+    return replaceCaret(comp, loose);
+  }).join(' ');
+}
+
+function replaceCaret(comp, loose) {
+  debug('caret', comp, loose);
+  var r = loose ? re[CARETLOOSE] : re[CARET];
+  return comp.replace(r, function(_, M, m, p, pr) {
+    debug('caret', comp, _, M, m, p, pr);
+    var ret;
+
+    if (isX(M))
+      ret = '';
+    else if (isX(m))
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    else if (isX(p)) {
+      if (M === '0')
+        ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+      else
+        ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0';
+    } else if (pr) {
+      debug('replaceCaret pr', pr);
+      if (pr.charAt(0) !== '-')
+        pr = '-' + pr;
+      if (M === '0') {
+        if (m === '0')
+          ret = '>=' + M + '.' + m + '.' + p + pr +
+                ' <' + M + '.' + m + '.' + (+p + 1);
+        else
+          ret = '>=' + M + '.' + m + '.' + p + pr +
+                ' <' + M + '.' + (+m + 1) + '.0';
+      } else
+        ret = '>=' + M + '.' + m + '.' + p + pr +
+              ' <' + (+M + 1) + '.0.0';
+    } else {
+      debug('no pr');
+      if (M === '0') {
+        if (m === '0')
+          ret = '>=' + M + '.' + m + '.' + p +
+                ' <' + M + '.' + m + '.' + (+p + 1);
+        else
+          ret = '>=' + M + '.' + m + '.' + p +
+                ' <' + M + '.' + (+m + 1) + '.0';
+      } else
+        ret = '>=' + M + '.' + m + '.' + p +
+              ' <' + (+M + 1) + '.0.0';
+    }
+
+    debug('caret return', ret);
+    return ret;
+  });
+}
+
+function replaceXRanges(comp, loose) {
+  debug('replaceXRanges', comp, loose);
+  return comp.split(/\s+/).map(function(comp) {
+    return replaceXRange(comp, loose);
+  }).join(' ');
+}
+
+function replaceXRange(comp, loose) {
+  comp = comp.trim();
+  var r = loose ? re[XRANGELOOSE] : re[XRANGE];
+  return comp.replace(r, function(ret, gtlt, M, m, p, pr) {
+    debug('xRange', comp, ret, gtlt, M, m, p, pr);
+    var xM = isX(M);
+    var xm = xM || isX(m);
+    var xp = xm || isX(p);
+    var anyX = xp;
+
+    if (gtlt === '=' && anyX)
+      gtlt = '';
+
+    if (xM) {
+      if (gtlt === '>' || gtlt === '<') {
+        // nothing is allowed
+        ret = '<0.0.0';
+      } else {
+        // nothing is forbidden
+        ret = '*';
+      }
+    } else if (gtlt && anyX) {
+      // replace X with 0
+      if (xm)
+        m = 0;
+      if (xp)
+        p = 0;
+
+      if (gtlt === '>') {
+        // >1 => >=2.0.0
+        // >1.2 => >=1.3.0
+        // >1.2.3 => >= 1.2.4
+        gtlt = '>=';
+        if (xm) {
+          M = +M + 1;
+          m = 0;
+          p = 0;
+        } else if (xp) {
+          m = +m + 1;
+          p = 0;
+        }
+      } else if (gtlt === '<=') {
+        // <=0.7.x is actually <0.8.0, since any 0.7.x should
+        // pass.  Similarly, <=7.x is actually <8.0.0, etc.
+        gtlt = '<'
+        if (xm)
+          M = +M + 1
+        else
+          m = +m + 1
+      }
+
+      ret = gtlt + M + '.' + m + '.' + p;
+    } else if (xm) {
+      ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0';
+    } else if (xp) {
+      ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0';
+    }
+
+    debug('xRange return', ret);
+
+    return ret;
+  });
+}
+
+// Because * is AND-ed with everything else in the comparator,
+// and '' means "any version", just remove the *s entirely.
+function replaceStars(comp, loose) {
+  debug('replaceStars', comp, loose);
+  // Looseness is ignored here.  star is always as loose as it gets!
+  return comp.trim().replace(re[STAR], '');
+}
+
+// This function is passed to string.replace(re[HYPHENRANGE])
+// M, m, patch, prerelease, build
+// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5
+// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do
+// 1.2 - 3.4 => >=1.2.0 <3.5.0
+function hyphenReplace($0,
+                       from, fM, fm, fp, fpr, fb,
+                       to, tM, tm, tp, tpr, tb) {
+
+  if (isX(fM))
+    from = '';
+  else if (isX(fm))
+    from = '>=' + fM + '.0.0';
+  else if (isX(fp))
+    from = '>=' + fM + '.' + fm + '.0';
+  else
+    from = '>=' + from;
+
+  if (isX(tM))
+    to = '';
+  else if (isX(tm))
+    to = '<' + (+tM + 1) + '.0.0';
+  else if (isX(tp))
+    to = '<' + tM + '.' + (+tm + 1) + '.0';
+  else if (tpr)
+    to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr;
+  else
+    to = '<=' + to;
+
+  return (from + ' ' + to).trim();
+}
+
+
+// if ANY of the sets match ALL of its comparators, then pass
+Range.prototype.test = function(version) {
+  if (!version)
+    return false;
+
+  if (typeof version === 'string')
+    version = new SemVer(version, this.loose);
+
+  for (var i = 0; i < this.set.length; i++) {
+    if (testSet(this.set[i], version))
+      return true;
+  }
+  return false;
+};
+
+function testSet(set, version) {
+  for (var i = 0; i < set.length; i++) {
+    if (!set[i].test(version))
+      return false;
+  }
+
+  if (version.prerelease.length) {
+    // Find the set of versions that are allowed to have prereleases
+    // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0
+    // That should allow `1.2.3-pr.2` to pass.
+    // However, `1.2.4-alpha.notready` should NOT be allowed,
+    // even though it's within the range set by the comparators.
+    for (var i = 0; i < set.length; i++) {
+      debug(set[i].semver);
+      if (set[i].semver === ANY)
+        return true;
+
+      if (set[i].semver.prerelease.length > 0) {
+        var allowed = set[i].semver;
+        if (allowed.major === version.major &&
+            allowed.minor === version.minor &&
+            allowed.patch === version.patch)
+          return true;
+      }
+    }
+
+    // Version has a -pre, but it's not one of the ones we like.
+    return false;
+  }
+
+  return true;
+}
+
+exports.satisfies = satisfies;
+function satisfies(version, range, loose) {
+  try {
+    range = new Range(range, loose);
+  } catch (er) {
+    return false;
+  }
+  return range.test(version);
+}
+
+exports.maxSatisfying = maxSatisfying;
+function maxSatisfying(versions, range, loose) {
+  return versions.filter(function(version) {
+    return satisfies(version, range, loose);
+  }).sort(function(a, b) {
+    return rcompare(a, b, loose);
+  })[0] || null;
+}
+
+exports.validRange = validRange;
+function validRange(range, loose) {
+  try {
+    // Return '*' instead of '' so that truthiness works.
+    // This will throw if it's invalid anyway
+    return new Range(range, loose).range || '*';
+  } catch (er) {
+    return null;
+  }
+}
+
+// Determine if version is less than all the versions possible in the range
+exports.ltr = ltr;
+function ltr(version, range, loose) {
+  return outside(version, range, '<', loose);
+}
+
+// Determine if version is greater than all the versions possible in the range.
+exports.gtr = gtr;
+function gtr(version, range, loose) {
+  return outside(version, range, '>', loose);
+}
+
+exports.outside = outside;
+function outside(version, range, hilo, loose) {
+  version = new SemVer(version, loose);
+  range = new Range(range, loose);
+
+  var gtfn, ltefn, ltfn, comp, ecomp;
+  switch (hilo) {
+    case '>':
+      gtfn = gt;
+      ltefn = lte;
+      ltfn = lt;
+      comp = '>';
+      ecomp = '>=';
+      break;
+    case '<':
+      gtfn = lt;
+      ltefn = gte;
+      ltfn = gt;
+      comp = '<';
+      ecomp = '<=';
+      break;
+    default:
+      throw new TypeError('Must provide a hilo val of "<" or ">"');
+  }
+
+  // If it satisifes the range it is not outside
+  if (satisfies(version, range, loose)) {
+    return false;
+  }
+
+  // From now on, variable terms are as if we're in "gtr" mode.
+  // but note that everything is flipped for the "ltr" function.
+
+  for (var i = 0; i < range.set.length; ++i) {
+    var comparators = range.set[i];
+
+    var high = null;
+    var low = null;
+
+    comparators.forEach(function(comparator) {
+      high = high || comparator;
+      low = low || comparator;
+      if (gtfn(comparator.semver, high.semver, loose)) {
+        high = comparator;
+      } else if (ltfn(comparator.semver, low.semver, loose)) {
+        low = comparator;
+      }
+    });
+
+    // If the edge version comparator has a operator then our version
+    // isn't outside it
+    if (high.operator === comp || high.operator === ecomp) {
+      return false;
+    }
+
+    // If the lowest version comparator has an operator and our version
+    // is less than it then it isn't higher than the range
+    if ((!low.operator || low.operator === comp) &&
+        ltefn(version, low.semver)) {
+      return false;
+    } else if (low.operator === ecomp && ltfn(version, low.semver)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Use the define() function if we're in AMD land
+if (typeof define === 'function' && define.amd)
+  define(exports);
diff --git a/server/node_modules/pgtools/node_modules/semver/semver.min.js b/server/node_modules/pgtools/node_modules/semver/semver.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..abe2d81843bca8233fc8bd43b1d267aaa6e99b0d
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/semver.min.js
@@ -0,0 +1 @@
+(function(e){if(typeof module==="object"&&module.exports===e)e=module.exports=K;e.SEMVER_SPEC_VERSION="2.0.0";var r=256;var t=Number.MAX_SAFE_INTEGER||9007199254740991;var n=e.re=[];var i=e.src=[];var s=0;var o=s++;i[o]="0|[1-9]\\d*";var a=s++;i[a]="[0-9]+";var f=s++;i[f]="\\d*[a-zA-Z-][a-zA-Z0-9-]*";var u=s++;i[u]="("+i[o]+")\\."+"("+i[o]+")\\."+"("+i[o]+")";var l=s++;i[l]="("+i[a]+")\\."+"("+i[a]+")\\."+"("+i[a]+")";var h=s++;i[h]="(?:"+i[o]+"|"+i[f]+")";var p=s++;i[p]="(?:"+i[a]+"|"+i[f]+")";var c=s++;i[c]="(?:-("+i[h]+"(?:\\."+i[h]+")*))";var v=s++;i[v]="(?:-?("+i[p]+"(?:\\."+i[p]+")*))";var m=s++;i[m]="[0-9A-Za-z-]+";var g=s++;i[g]="(?:\\+("+i[m]+"(?:\\."+i[m]+")*))";var w=s++;var y="v?"+i[u]+i[c]+"?"+i[g]+"?";i[w]="^"+y+"$";var d="[v=\\s]*"+i[l]+i[v]+"?"+i[g]+"?";var j=s++;i[j]="^"+d+"$";var b=s++;i[b]="((?:<|>)?=?)";var E=s++;i[E]=i[a]+"|x|X|\\*";var $=s++;i[$]=i[o]+"|x|X|\\*";var k=s++;i[k]="[v=\\s]*("+i[$]+")"+"(?:\\.("+i[$]+")"+"(?:\\.("+i[$]+")"+"(?:"+i[c]+")?"+i[g]+"?"+")?)?";var R=s++;i[R]="[v=\\s]*("+i[E]+")"+"(?:\\.("+i[E]+")"+"(?:\\.("+i[E]+")"+"(?:"+i[v]+")?"+i[g]+"?"+")?)?";var S=s++;i[S]="^"+i[b]+"\\s*"+i[k]+"$";var x=s++;i[x]="^"+i[b]+"\\s*"+i[R]+"$";var I=s++;i[I]="(?:~>?)";var T=s++;i[T]="(\\s*)"+i[I]+"\\s+";n[T]=new RegExp(i[T],"g");var V="$1~";var A=s++;i[A]="^"+i[I]+i[k]+"$";var C=s++;i[C]="^"+i[I]+i[R]+"$";var M=s++;i[M]="(?:\\^)";var N=s++;i[N]="(\\s*)"+i[M]+"\\s+";n[N]=new RegExp(i[N],"g");var _="$1^";var z=s++;i[z]="^"+i[M]+i[k]+"$";var P=s++;i[P]="^"+i[M]+i[R]+"$";var X=s++;i[X]="^"+i[b]+"\\s*("+d+")$|^$";var Z=s++;i[Z]="^"+i[b]+"\\s*("+y+")$|^$";var q=s++;i[q]="(\\s*)"+i[b]+"\\s*("+d+"|"+i[k]+")";n[q]=new RegExp(i[q],"g");var L="$1$2$3";var F=s++;i[F]="^\\s*("+i[k]+")"+"\\s+-\\s+"+"("+i[k]+")"+"\\s*$";var G=s++;i[G]="^\\s*("+i[R]+")"+"\\s+-\\s+"+"("+i[R]+")"+"\\s*$";var O=s++;i[O]="(<|>)?=?\\s*\\*";for(var B=0;B<s;B++){if(!n[B])n[B]=new RegExp(i[B])}e.parse=D;function D(e,t){if(e.length>r)return null;var i=t?n[j]:n[w];if(!i.test(e))return null;try{return new K(e,t)}catch(s){return null}}e.valid=H;function H(e,r){var t=D(e,r);return t?t.version:null}e.clean=J;function J(e,r){var t=D(e.trim().replace(/^[=v]+/,""),r);return t?t.version:null}e.SemVer=K;function K(e,i){if(e instanceof K){if(e.loose===i)return e;else e=e.version}else if(typeof e!=="string"){throw new TypeError("Invalid Version: "+e)}if(e.length>r)throw new TypeError("version is longer than "+r+" characters");if(!(this instanceof K))return new K(e,i);this.loose=i;var s=e.trim().match(i?n[j]:n[w]);if(!s)throw new TypeError("Invalid Version: "+e);this.raw=e;this.major=+s[1];this.minor=+s[2];this.patch=+s[3];if(this.major>t||this.major<0)throw new TypeError("Invalid major version");if(this.minor>t||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>t||this.patch<0)throw new TypeError("Invalid patch version");if(!s[4])this.prerelease=[];else this.prerelease=s[4].split(".").map(function(e){return/^[0-9]+$/.test(e)?+e:e});this.build=s[5]?s[5].split("."):[];this.format()}K.prototype.format=function(){this.version=this.major+"."+this.minor+"."+this.patch;if(this.prerelease.length)this.version+="-"+this.prerelease.join(".");return this.version};K.prototype.inspect=function(){return'<SemVer "'+this+'">'};K.prototype.toString=function(){return this.version};K.prototype.compare=function(e){if(!(e instanceof K))e=new K(e,this.loose);return this.compareMain(e)||this.comparePre(e)};K.prototype.compareMain=function(e){if(!(e instanceof K))e=new K(e,this.loose);return Y(this.major,e.major)||Y(this.minor,e.minor)||Y(this.patch,e.patch)};K.prototype.comparePre=function(e){if(!(e instanceof K))e=new K(e,this.loose);if(this.prerelease.length&&!e.prerelease.length)return-1;else if(!this.prerelease.length&&e.prerelease.length)return 1;else if(!this.prerelease.length&&!e.prerelease.length)return 0;var r=0;do{var t=this.prerelease[r];var n=e.prerelease[r];if(t===undefined&&n===undefined)return 0;else if(n===undefined)return 1;else if(t===undefined)return-1;else if(t===n)continue;else return Y(t,n)}while(++r)};K.prototype.inc=function(e,r){switch(e){case"premajor":this.prerelease.length=0;this.patch=0;this.minor=0;this.major++;this.inc("pre",r);break;case"preminor":this.prerelease.length=0;this.patch=0;this.minor++;this.inc("pre",r);break;case"prepatch":this.prerelease.length=0;this.inc("patch",r);this.inc("pre",r);break;case"prerelease":if(this.prerelease.length===0)this.inc("patch",r);this.inc("pre",r);break;case"major":if(this.minor!==0||this.patch!==0||this.prerelease.length===0)this.major++;this.minor=0;this.patch=0;this.prerelease=[];break;case"minor":if(this.patch!==0||this.prerelease.length===0)this.minor++;this.patch=0;this.prerelease=[];break;case"patch":if(this.prerelease.length===0)this.patch++;this.prerelease=[];break;case"pre":if(this.prerelease.length===0)this.prerelease=[0];else{var t=this.prerelease.length;while(--t>=0){if(typeof this.prerelease[t]==="number"){this.prerelease[t]++;t=-2}}if(t===-1)this.prerelease.push(0)}if(r){if(this.prerelease[0]===r){if(isNaN(this.prerelease[1]))this.prerelease=[r,0]}else this.prerelease=[r,0]}break;default:throw new Error("invalid increment argument: "+e)}this.format();return this};e.inc=Q;function Q(e,r,t,n){if(typeof t==="string"){n=t;t=undefined}try{return new K(e,t).inc(r,n).version}catch(i){return null}}e.diff=U;function U(e,r){if(hr(e,r)){return null}else{var t=D(e);var n=D(r);if(t.prerelease.length||n.prerelease.length){for(var i in t){if(i==="major"||i==="minor"||i==="patch"){if(t[i]!==n[i]){return"pre"+i}}}return"prerelease"}for(var i in t){if(i==="major"||i==="minor"||i==="patch"){if(t[i]!==n[i]){return i}}}}}e.compareIdentifiers=Y;var W=/^[0-9]+$/;function Y(e,r){var t=W.test(e);var n=W.test(r);if(t&&n){e=+e;r=+r}return t&&!n?-1:n&&!t?1:e<r?-1:e>r?1:0}e.rcompareIdentifiers=er;function er(e,r){return Y(r,e)}e.major=rr;function rr(e,r){return new K(e,r).major}e.minor=tr;function tr(e,r){return new K(e,r).minor}e.patch=nr;function nr(e,r){return new K(e,r).patch}e.compare=ir;function ir(e,r,t){return new K(e,t).compare(r)}e.compareLoose=sr;function sr(e,r){return ir(e,r,true)}e.rcompare=or;function or(e,r,t){return ir(r,e,t)}e.sort=ar;function ar(r,t){return r.sort(function(r,n){return e.compare(r,n,t)})}e.rsort=fr;function fr(r,t){return r.sort(function(r,n){return e.rcompare(r,n,t)})}e.gt=ur;function ur(e,r,t){return ir(e,r,t)>0}e.lt=lr;function lr(e,r,t){return ir(e,r,t)<0}e.eq=hr;function hr(e,r,t){return ir(e,r,t)===0}e.neq=pr;function pr(e,r,t){return ir(e,r,t)!==0}e.gte=cr;function cr(e,r,t){return ir(e,r,t)>=0}e.lte=vr;function vr(e,r,t){return ir(e,r,t)<=0}e.cmp=mr;function mr(e,r,t,n){var i;switch(r){case"===":if(typeof e==="object")e=e.version;if(typeof t==="object")t=t.version;i=e===t;break;case"!==":if(typeof e==="object")e=e.version;if(typeof t==="object")t=t.version;i=e!==t;break;case"":case"=":case"==":i=hr(e,t,n);break;case"!=":i=pr(e,t,n);break;case">":i=ur(e,t,n);break;case">=":i=cr(e,t,n);break;case"<":i=lr(e,t,n);break;case"<=":i=vr(e,t,n);break;default:throw new TypeError("Invalid operator: "+r)}return i}e.Comparator=gr;function gr(e,r){if(e instanceof gr){if(e.loose===r)return e;else e=e.value}if(!(this instanceof gr))return new gr(e,r);this.loose=r;this.parse(e);if(this.semver===wr)this.value="";else this.value=this.operator+this.semver.version}var wr={};gr.prototype.parse=function(e){var r=this.loose?n[X]:n[Z];var t=e.match(r);if(!t)throw new TypeError("Invalid comparator: "+e);this.operator=t[1];if(this.operator==="=")this.operator="";if(!t[2])this.semver=wr;else this.semver=new K(t[2],this.loose)};gr.prototype.inspect=function(){return'<SemVer Comparator "'+this+'">'};gr.prototype.toString=function(){return this.value};gr.prototype.test=function(e){if(this.semver===wr)return true;if(typeof e==="string")e=new K(e,this.loose);return mr(e,this.operator,this.semver,this.loose)};e.Range=yr;function yr(e,r){if(e instanceof yr&&e.loose===r)return e;if(!(this instanceof yr))return new yr(e,r);this.loose=r;this.raw=e;this.set=e.split(/\s*\|\|\s*/).map(function(e){return this.parseRange(e.trim())},this).filter(function(e){return e.length});if(!this.set.length){throw new TypeError("Invalid SemVer Range: "+e)}this.format()}yr.prototype.inspect=function(){return'<SemVer Range "'+this.range+'">'};yr.prototype.format=function(){this.range=this.set.map(function(e){return e.join(" ").trim()}).join("||").trim();return this.range};yr.prototype.toString=function(){return this.range};yr.prototype.parseRange=function(e){var r=this.loose;e=e.trim();var t=r?n[G]:n[F];e=e.replace(t,Tr);e=e.replace(n[q],L);e=e.replace(n[T],V);e=e.replace(n[N],_);e=e.split(/\s+/).join(" ");var i=r?n[X]:n[Z];var s=e.split(" ").map(function(e){return jr(e,r)}).join(" ").split(/\s+/);if(this.loose){s=s.filter(function(e){return!!e.match(i)})}s=s.map(function(e){return new gr(e,r)});return s};e.toComparators=dr;function dr(e,r){return new yr(e,r).set.map(function(e){return e.map(function(e){return e.value}).join(" ").trim().split(" ")})}function jr(e,r){e=kr(e,r);e=Er(e,r);e=Sr(e,r);e=Ir(e,r);return e}function br(e){return!e||e.toLowerCase()==="x"||e==="*"}function Er(e,r){return e.trim().split(/\s+/).map(function(e){return $r(e,r)}).join(" ")}function $r(e,r){var t=r?n[C]:n[A];return e.replace(t,function(e,r,t,n,i){var s;if(br(r))s="";else if(br(t))s=">="+r+".0.0 <"+(+r+1)+".0.0";else if(br(n))s=">="+r+"."+t+".0 <"+r+"."+(+t+1)+".0";else if(i){if(i.charAt(0)!=="-")i="-"+i;s=">="+r+"."+t+"."+n+i+" <"+r+"."+(+t+1)+".0"}else s=">="+r+"."+t+"."+n+" <"+r+"."+(+t+1)+".0";return s})}function kr(e,r){return e.trim().split(/\s+/).map(function(e){return Rr(e,r)}).join(" ")}function Rr(e,r){var t=r?n[P]:n[z];return e.replace(t,function(e,r,t,n,i){var s;if(br(r))s="";else if(br(t))s=">="+r+".0.0 <"+(+r+1)+".0.0";else if(br(n)){if(r==="0")s=">="+r+"."+t+".0 <"+r+"."+(+t+1)+".0";else s=">="+r+"."+t+".0 <"+(+r+1)+".0.0"}else if(i){if(i.charAt(0)!=="-")i="-"+i;if(r==="0"){if(t==="0")s=">="+r+"."+t+"."+n+i+" <"+r+"."+t+"."+(+n+1);else s=">="+r+"."+t+"."+n+i+" <"+r+"."+(+t+1)+".0"}else s=">="+r+"."+t+"."+n+i+" <"+(+r+1)+".0.0"}else{if(r==="0"){if(t==="0")s=">="+r+"."+t+"."+n+" <"+r+"."+t+"."+(+n+1);else s=">="+r+"."+t+"."+n+" <"+r+"."+(+t+1)+".0"}else s=">="+r+"."+t+"."+n+" <"+(+r+1)+".0.0"}return s})}function Sr(e,r){return e.split(/\s+/).map(function(e){return xr(e,r)}).join(" ")}function xr(e,r){e=e.trim();var t=r?n[x]:n[S];return e.replace(t,function(e,r,t,n,i,s){var o=br(t);var a=o||br(n);var f=a||br(i);var u=f;if(r==="="&&u)r="";if(o){if(r===">"||r==="<"){e="<0.0.0"}else{e="*"}}else if(r&&u){if(a)n=0;if(f)i=0;if(r===">"){r=">=";if(a){t=+t+1;n=0;i=0}else if(f){n=+n+1;i=0}}else if(r==="<="){r="<";if(a)t=+t+1;else n=+n+1}e=r+t+"."+n+"."+i}else if(a){e=">="+t+".0.0 <"+(+t+1)+".0.0"}else if(f){e=">="+t+"."+n+".0 <"+t+"."+(+n+1)+".0"}return e})}function Ir(e,r){return e.trim().replace(n[O],"")}function Tr(e,r,t,n,i,s,o,a,f,u,l,h,p){if(br(t))r="";else if(br(n))r=">="+t+".0.0";else if(br(i))r=">="+t+"."+n+".0";else r=">="+r;if(br(f))a="";else if(br(u))a="<"+(+f+1)+".0.0";else if(br(l))a="<"+f+"."+(+u+1)+".0";else if(h)a="<="+f+"."+u+"."+l+"-"+h;else a="<="+a;return(r+" "+a).trim()}yr.prototype.test=function(e){if(!e)return false;if(typeof e==="string")e=new K(e,this.loose);for(var r=0;r<this.set.length;r++){if(Vr(this.set[r],e))return true}return false};function Vr(e,r){for(var t=0;t<e.length;t++){if(!e[t].test(r))return false}if(r.prerelease.length){for(var t=0;t<e.length;t++){if(e[t].semver===wr)return true;if(e[t].semver.prerelease.length>0){var n=e[t].semver;if(n.major===r.major&&n.minor===r.minor&&n.patch===r.patch)return true}}return false}return true}e.satisfies=Ar;function Ar(e,r,t){try{r=new yr(r,t)}catch(n){return false}return r.test(e)}e.maxSatisfying=Cr;function Cr(e,r,t){return e.filter(function(e){return Ar(e,r,t)}).sort(function(e,r){return or(e,r,t)})[0]||null}e.validRange=Mr;function Mr(e,r){try{return new yr(e,r).range||"*"}catch(t){return null}}e.ltr=Nr;function Nr(e,r,t){return zr(e,r,"<",t)}e.gtr=_r;function _r(e,r,t){return zr(e,r,">",t)}e.outside=zr;function zr(e,r,t,n){e=new K(e,n);r=new yr(r,n);var i,s,o,a,f;switch(t){case">":i=ur;s=vr;o=lr;a=">";f=">=";break;case"<":i=lr;s=cr;o=ur;a="<";f="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(Ar(e,r,n)){return false}for(var u=0;u<r.set.length;++u){var l=r.set[u];var h=null;var p=null;l.forEach(function(e){h=h||e;p=p||e;if(i(e.semver,h.semver,n)){h=e}else if(o(e.semver,p.semver,n)){p=e}});if(h.operator===a||h.operator===f){return false}if((!p.operator||p.operator===a)&&s(e,p.semver)){return false}else if(p.operator===f&&o(e,p.semver)){return false}}return true}if(typeof define==="function"&&define.amd)define(e)})(typeof exports==="object"?exports:typeof define==="function"&&define.amd?{}:semver={});
\ No newline at end of file
diff --git a/server/node_modules/pgtools/node_modules/semver/semver.min.js.gz b/server/node_modules/pgtools/node_modules/semver/semver.min.js.gz
new file mode 100644
index 0000000000000000000000000000000000000000..fbe42dd59317b9d6b5a1690aa68e1d9dc0392857
Binary files /dev/null and b/server/node_modules/pgtools/node_modules/semver/semver.min.js.gz differ
diff --git a/server/node_modules/pgtools/node_modules/semver/test/amd.js b/server/node_modules/pgtools/node_modules/semver/test/amd.js
new file mode 100644
index 0000000000000000000000000000000000000000..a6041341b37ee943f41d875cbb4a4d34d5b587d2
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/test/amd.js
@@ -0,0 +1,15 @@
+var tap = require('tap');
+var test = tap.test;
+
+test('amd', function(t) {
+  global.define = define;
+  define.amd = true;
+  var defined = null;
+  function define(stuff) {
+    defined = stuff;
+  }
+  var fromRequire = require('../');
+  t.ok(defined, 'amd function called');
+  t.equal(fromRequire, defined, 'amd stuff same as require stuff');
+  t.end();
+});
diff --git a/server/node_modules/pgtools/node_modules/semver/test/big-numbers.js b/server/node_modules/pgtools/node_modules/semver/test/big-numbers.js
new file mode 100644
index 0000000000000000000000000000000000000000..692aa241461213f0fb2786019fd0b2e7fe4d1114
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/test/big-numbers.js
@@ -0,0 +1,24 @@
+var test = require('tap').test
+var semver = require('../')
+
+test('long version is too long', function (t) {
+  var v = '1.2.' + new Array(256).join('1')
+  t.throws(function () {
+    new semver.SemVer(v)
+  })
+  t.equal(semver.valid(v, false), null)
+  t.equal(semver.valid(v, true), null)
+  t.equal(semver.inc(v, 'patch'), null)
+  t.end()
+})
+
+test('big number is like too long version', function (t) {
+  var v = '1.2.' + new Array(100).join('1')
+  t.throws(function () {
+    new semver.SemVer(v)
+  })
+  t.equal(semver.valid(v, false), null)
+  t.equal(semver.valid(v, true), null)
+  t.equal(semver.inc(v, 'patch'), null)
+  t.end()
+})
diff --git a/server/node_modules/pgtools/node_modules/semver/test/clean.js b/server/node_modules/pgtools/node_modules/semver/test/clean.js
new file mode 100644
index 0000000000000000000000000000000000000000..9e268de950ce8cf6bebf19423a657fb10c59e157
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/test/clean.js
@@ -0,0 +1,29 @@
+var tap = require('tap');
+var test = tap.test;
+var semver = require('../semver.js');
+var clean = semver.clean;
+
+test('\nclean tests', function(t) {
+	// [range, version]
+	// Version should be detectable despite extra characters
+	[
+		['1.2.3', '1.2.3'],
+		[' 1.2.3 ', '1.2.3'],
+		[' 1.2.3-4 ', '1.2.3-4'],
+		[' 1.2.3-pre ', '1.2.3-pre'],
+		['  =v1.2.3   ', '1.2.3'],
+		['v1.2.3', '1.2.3'],
+		[' v1.2.3 ', '1.2.3'],
+		['\t1.2.3', '1.2.3'],
+		['>1.2.3', null],
+		['~1.2.3', null],
+		['<=1.2.3', null],
+		['1.2.x', null]
+	].forEach(function(tuple) {
+			var range = tuple[0];
+			var version = tuple[1];
+			var msg = 'clean(' + range + ') = ' + version;
+			t.equal(clean(range), version, msg);
+		});
+	t.end();
+});
diff --git a/server/node_modules/pgtools/node_modules/semver/test/gtr.js b/server/node_modules/pgtools/node_modules/semver/test/gtr.js
new file mode 100644
index 0000000000000000000000000000000000000000..bbb87896c64fbbb1c66892ac36c2f43121794ab1
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/test/gtr.js
@@ -0,0 +1,173 @@
+var tap = require('tap');
+var test = tap.test;
+var semver = require('../semver.js');
+var gtr = semver.gtr;
+
+test('\ngtr tests', function(t) {
+  // [range, version, loose]
+  // Version should be greater than range
+  [
+    ['~1.2.2', '1.3.0'],
+    ['~0.6.1-1', '0.7.1-1'],
+    ['1.0.0 - 2.0.0', '2.0.1'],
+    ['1.0.0', '1.0.1-beta1'],
+    ['1.0.0', '2.0.0'],
+    ['<=2.0.0', '2.1.1'],
+    ['<=2.0.0', '3.2.9'],
+    ['<2.0.0', '2.0.0'],
+    ['0.1.20 || 1.2.4', '1.2.5'],
+    ['2.x.x', '3.0.0'],
+    ['1.2.x', '1.3.0'],
+    ['1.2.x || 2.x', '3.0.0'],
+    ['2.*.*', '5.0.1'],
+    ['1.2.*', '1.3.3'],
+    ['1.2.* || 2.*', '4.0.0'],
+    ['2', '3.0.0'],
+    ['2.3', '2.4.2'],
+    ['~2.4', '2.5.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.5.5'],
+    ['~>3.2.1', '3.3.0'], // >=3.2.1 <3.3.0
+    ['~1', '2.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '2.2.4'],
+    ['~> 1', '3.2.3'],
+    ['~1.0', '1.1.2'], // >=1.0.0 <1.1.0
+    ['~ 1.0', '1.1.0'],
+    ['<1.2', '1.2.0'],
+    ['< 1.2', '1.2.1'],
+    ['1', '2.0.0beta', true],
+    ['~v0.5.4-pre', '0.6.0'],
+    ['~v0.5.4-pre', '0.6.1-pre'],
+    ['=0.7.x', '0.8.0'],
+    ['=0.7.x', '0.8.0-asdf'],
+    ['<0.7.x', '0.7.0'],
+    ['~1.2.2', '1.3.0'],
+    ['1.0.0 - 2.0.0', '2.2.3'],
+    ['1.0.0', '1.0.1'],
+    ['<=2.0.0', '3.0.0'],
+    ['<=2.0.0', '2.9999.9999'],
+    ['<=2.0.0', '2.2.9'],
+    ['<2.0.0', '2.9999.9999'],
+    ['<2.0.0', '2.2.9'],
+    ['2.x.x', '3.1.3'],
+    ['1.2.x', '1.3.3'],
+    ['1.2.x || 2.x', '3.1.3'],
+    ['2.*.*', '3.1.3'],
+    ['1.2.*', '1.3.3'],
+    ['1.2.* || 2.*', '3.1.3'],
+    ['2', '3.1.2'],
+    ['2.3', '2.4.1'],
+    ['~2.4', '2.5.0'], // >=2.4.0 <2.5.0
+    ['~>3.2.1', '3.3.2'], // >=3.2.1 <3.3.0
+    ['~1', '2.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '2.2.3'],
+    ['~1.0', '1.1.0'], // >=1.0.0 <1.1.0
+    ['<1', '1.0.0'],
+    ['1', '2.0.0beta', true],
+    ['<1', '1.0.0beta', true],
+    ['< 1', '1.0.0beta', true],
+    ['=0.7.x', '0.8.2'],
+    ['<0.7.x', '0.7.2']
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = 'gtr(' + version + ', ' + range + ', ' + loose + ')';
+    t.ok(gtr(version, range, loose), msg);
+  });
+  t.end();
+});
+
+test('\nnegative gtr tests', function(t) {
+  // [range, version, loose]
+  // Version should NOT be greater than range
+  [
+    ['~0.6.1-1', '0.6.1-1'],
+    ['1.0.0 - 2.0.0', '1.2.3'],
+    ['1.0.0 - 2.0.0', '0.9.9'],
+    ['1.0.0', '1.0.0'],
+    ['>=*', '0.2.4'],
+    ['', '1.0.0', true],
+    ['*', '1.2.3'],
+    ['*', 'v1.2.3-foo'],
+    ['>=1.0.0', '1.0.0'],
+    ['>=1.0.0', '1.0.1'],
+    ['>=1.0.0', '1.1.0'],
+    ['>1.0.0', '1.0.1'],
+    ['>1.0.0', '1.1.0'],
+    ['<=2.0.0', '2.0.0'],
+    ['<=2.0.0', '1.9999.9999'],
+    ['<=2.0.0', '0.2.9'],
+    ['<2.0.0', '1.9999.9999'],
+    ['<2.0.0', '0.2.9'],
+    ['>= 1.0.0', '1.0.0'],
+    ['>=  1.0.0', '1.0.1'],
+    ['>=   1.0.0', '1.1.0'],
+    ['> 1.0.0', '1.0.1'],
+    ['>  1.0.0', '1.1.0'],
+    ['<=   2.0.0', '2.0.0'],
+    ['<= 2.0.0', '1.9999.9999'],
+    ['<=  2.0.0', '0.2.9'],
+    ['<    2.0.0', '1.9999.9999'],
+    ['<\t2.0.0', '0.2.9'],
+    ['>=0.1.97', 'v0.1.97'],
+    ['>=0.1.97', '0.1.97'],
+    ['0.1.20 || 1.2.4', '1.2.4'],
+    ['0.1.20 || >1.2.4', '1.2.4'],
+    ['0.1.20 || 1.2.4', '1.2.3'],
+    ['0.1.20 || 1.2.4', '0.1.20'],
+    ['>=0.2.3 || <0.0.1', '0.0.0'],
+    ['>=0.2.3 || <0.0.1', '0.2.3'],
+    ['>=0.2.3 || <0.0.1', '0.2.4'],
+    ['||', '1.3.4'],
+    ['2.x.x', '2.1.3'],
+    ['1.2.x', '1.2.3'],
+    ['1.2.x || 2.x', '2.1.3'],
+    ['1.2.x || 2.x', '1.2.3'],
+    ['x', '1.2.3'],
+    ['2.*.*', '2.1.3'],
+    ['1.2.*', '1.2.3'],
+    ['1.2.* || 2.*', '2.1.3'],
+    ['1.2.* || 2.*', '1.2.3'],
+    ['1.2.* || 2.*', '1.2.3'],
+    ['*', '1.2.3'],
+    ['2', '2.1.2'],
+    ['2.3', '2.3.1'],
+    ['~2.4', '2.4.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.4.5'],
+    ['~>3.2.1', '3.2.2'], // >=3.2.1 <3.3.0
+    ['~1', '1.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '1.2.3'],
+    ['~> 1', '1.2.3'],
+    ['~1.0', '1.0.2'], // >=1.0.0 <1.1.0
+    ['~ 1.0', '1.0.2'],
+    ['>=1', '1.0.0'],
+    ['>= 1', '1.0.0'],
+    ['<1.2', '1.1.1'],
+    ['< 1.2', '1.1.1'],
+    ['1', '1.0.0beta', true],
+    ['~v0.5.4-pre', '0.5.5'],
+    ['~v0.5.4-pre', '0.5.4'],
+    ['=0.7.x', '0.7.2'],
+    ['>=0.7.x', '0.7.2'],
+    ['=0.7.x', '0.7.0-asdf'],
+    ['>=0.7.x', '0.7.0-asdf'],
+    ['<=0.7.x', '0.6.2'],
+    ['>0.2.3 >0.2.4 <=0.2.5', '0.2.5'],
+    ['>=0.2.3 <=0.2.4', '0.2.4'],
+    ['1.0.0 - 2.0.0', '2.0.0'],
+    ['^1', '0.0.0-0'],
+    ['^3.0.0', '2.0.0'],
+    ['^1.0.0 || ~2.0.1', '2.0.0'],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '3.2.0'],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '1.0.0beta', true],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '5.0.0-0', true],
+    ['^0.1.0 || ~3.0.1 || >4 <=5.0.0', '3.5.0']
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = '!gtr(' + version + ', ' + range + ', ' + loose + ')';
+    t.notOk(gtr(version, range, loose), msg);
+  });
+  t.end();
+});
diff --git a/server/node_modules/pgtools/node_modules/semver/test/index.js b/server/node_modules/pgtools/node_modules/semver/test/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..926d560fe0a5fd3b9c643e6ba8ac248ea2ab4dc2
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/test/index.js
@@ -0,0 +1,684 @@
+'use strict';
+
+var tap = require('tap');
+var test = tap.test;
+var semver = require('../semver.js');
+var eq = semver.eq;
+var gt = semver.gt;
+var lt = semver.lt;
+var neq = semver.neq;
+var cmp = semver.cmp;
+var gte = semver.gte;
+var lte = semver.lte;
+var satisfies = semver.satisfies;
+var validRange = semver.validRange;
+var inc = semver.inc;
+var diff = semver.diff;
+var replaceStars = semver.replaceStars;
+var toComparators = semver.toComparators;
+var SemVer = semver.SemVer;
+var Range = semver.Range;
+
+test('\ncomparison tests', function(t) {
+  // [version1, version2]
+  // version1 should be greater than version2
+  [['0.0.0', '0.0.0-foo'],
+    ['0.0.1', '0.0.0'],
+    ['1.0.0', '0.9.9'],
+    ['0.10.0', '0.9.0'],
+    ['0.99.0', '0.10.0'],
+    ['2.0.0', '1.2.3'],
+    ['v0.0.0', '0.0.0-foo', true],
+    ['v0.0.1', '0.0.0', true],
+    ['v1.0.0', '0.9.9', true],
+    ['v0.10.0', '0.9.0', true],
+    ['v0.99.0', '0.10.0', true],
+    ['v2.0.0', '1.2.3', true],
+    ['0.0.0', 'v0.0.0-foo', true],
+    ['0.0.1', 'v0.0.0', true],
+    ['1.0.0', 'v0.9.9', true],
+    ['0.10.0', 'v0.9.0', true],
+    ['0.99.0', 'v0.10.0', true],
+    ['2.0.0', 'v1.2.3', true],
+    ['1.2.3', '1.2.3-asdf'],
+    ['1.2.3', '1.2.3-4'],
+    ['1.2.3', '1.2.3-4-foo'],
+    ['1.2.3-5-foo', '1.2.3-5'],
+    ['1.2.3-5', '1.2.3-4'],
+    ['1.2.3-5-foo', '1.2.3-5-Foo'],
+    ['3.0.0', '2.7.2+asdf'],
+    ['1.2.3-a.10', '1.2.3-a.5'],
+    ['1.2.3-a.b', '1.2.3-a.5'],
+    ['1.2.3-a.b', '1.2.3-a'],
+    ['1.2.3-a.b.c.10.d.5', '1.2.3-a.b.c.5.d.100'],
+    ['1.2.3-r2', '1.2.3-r100'],
+    ['1.2.3-r100', '1.2.3-R2']
+  ].forEach(function(v) {
+    var v0 = v[0];
+    var v1 = v[1];
+    var loose = v[2];
+    t.ok(gt(v0, v1, loose), "gt('" + v0 + "', '" + v1 + "')");
+    t.ok(lt(v1, v0, loose), "lt('" + v1 + "', '" + v0 + "')");
+    t.ok(!gt(v1, v0, loose), "!gt('" + v1 + "', '" + v0 + "')");
+    t.ok(!lt(v0, v1, loose), "!lt('" + v0 + "', '" + v1 + "')");
+    t.ok(eq(v0, v0, loose), "eq('" + v0 + "', '" + v0 + "')");
+    t.ok(eq(v1, v1, loose), "eq('" + v1 + "', '" + v1 + "')");
+    t.ok(neq(v0, v1, loose), "neq('" + v0 + "', '" + v1 + "')");
+    t.ok(cmp(v1, '==', v1, loose), "cmp('" + v1 + "' == '" + v1 + "')");
+    t.ok(cmp(v0, '>=', v1, loose), "cmp('" + v0 + "' >= '" + v1 + "')");
+    t.ok(cmp(v1, '<=', v0, loose), "cmp('" + v1 + "' <= '" + v0 + "')");
+    t.ok(cmp(v0, '!=', v1, loose), "cmp('" + v0 + "' != '" + v1 + "')");
+  });
+  t.end();
+});
+
+test('\nequality tests', function(t) {
+  // [version1, version2]
+  // version1 should be equivalent to version2
+  [['1.2.3', 'v1.2.3', true],
+    ['1.2.3', '=1.2.3', true],
+    ['1.2.3', 'v 1.2.3', true],
+    ['1.2.3', '= 1.2.3', true],
+    ['1.2.3', ' v1.2.3', true],
+    ['1.2.3', ' =1.2.3', true],
+    ['1.2.3', ' v 1.2.3', true],
+    ['1.2.3', ' = 1.2.3', true],
+    ['1.2.3-0', 'v1.2.3-0', true],
+    ['1.2.3-0', '=1.2.3-0', true],
+    ['1.2.3-0', 'v 1.2.3-0', true],
+    ['1.2.3-0', '= 1.2.3-0', true],
+    ['1.2.3-0', ' v1.2.3-0', true],
+    ['1.2.3-0', ' =1.2.3-0', true],
+    ['1.2.3-0', ' v 1.2.3-0', true],
+    ['1.2.3-0', ' = 1.2.3-0', true],
+    ['1.2.3-1', 'v1.2.3-1', true],
+    ['1.2.3-1', '=1.2.3-1', true],
+    ['1.2.3-1', 'v 1.2.3-1', true],
+    ['1.2.3-1', '= 1.2.3-1', true],
+    ['1.2.3-1', ' v1.2.3-1', true],
+    ['1.2.3-1', ' =1.2.3-1', true],
+    ['1.2.3-1', ' v 1.2.3-1', true],
+    ['1.2.3-1', ' = 1.2.3-1', true],
+    ['1.2.3-beta', 'v1.2.3-beta', true],
+    ['1.2.3-beta', '=1.2.3-beta', true],
+    ['1.2.3-beta', 'v 1.2.3-beta', true],
+    ['1.2.3-beta', '= 1.2.3-beta', true],
+    ['1.2.3-beta', ' v1.2.3-beta', true],
+    ['1.2.3-beta', ' =1.2.3-beta', true],
+    ['1.2.3-beta', ' v 1.2.3-beta', true],
+    ['1.2.3-beta', ' = 1.2.3-beta', true],
+    ['1.2.3-beta+build', ' = 1.2.3-beta+otherbuild', true],
+    ['1.2.3+build', ' = 1.2.3+otherbuild', true],
+    ['1.2.3-beta+build', '1.2.3-beta+otherbuild'],
+    ['1.2.3+build', '1.2.3+otherbuild'],
+    ['  v1.2.3+build', '1.2.3+otherbuild']
+  ].forEach(function(v) {
+    var v0 = v[0];
+    var v1 = v[1];
+    var loose = v[2];
+    t.ok(eq(v0, v1, loose), "eq('" + v0 + "', '" + v1 + "')");
+    t.ok(!neq(v0, v1, loose), "!neq('" + v0 + "', '" + v1 + "')");
+    t.ok(cmp(v0, '==', v1, loose), 'cmp(' + v0 + '==' + v1 + ')');
+    t.ok(!cmp(v0, '!=', v1, loose), '!cmp(' + v0 + '!=' + v1 + ')');
+    t.ok(!cmp(v0, '===', v1, loose), '!cmp(' + v0 + '===' + v1 + ')');
+    t.ok(cmp(v0, '!==', v1, loose), 'cmp(' + v0 + '!==' + v1 + ')');
+    t.ok(!gt(v0, v1, loose), "!gt('" + v0 + "', '" + v1 + "')");
+    t.ok(gte(v0, v1, loose), "gte('" + v0 + "', '" + v1 + "')");
+    t.ok(!lt(v0, v1, loose), "!lt('" + v0 + "', '" + v1 + "')");
+    t.ok(lte(v0, v1, loose), "lte('" + v0 + "', '" + v1 + "')");
+  });
+  t.end();
+});
+
+
+test('\nrange tests', function(t) {
+  // [range, version]
+  // version should be included by range
+  [['1.0.0 - 2.0.0', '1.2.3'],
+    ['^1.2.3+build', '1.2.3'],
+    ['^1.2.3+build', '1.3.0'],
+    ['1.2.3-pre+asdf - 2.4.3-pre+asdf', '1.2.3'],
+    ['1.2.3pre+asdf - 2.4.3-pre+asdf', '1.2.3', true],
+    ['1.2.3-pre+asdf - 2.4.3pre+asdf', '1.2.3', true],
+    ['1.2.3pre+asdf - 2.4.3pre+asdf', '1.2.3', true],
+    ['1.2.3-pre+asdf - 2.4.3-pre+asdf', '1.2.3-pre.2'],
+    ['1.2.3-pre+asdf - 2.4.3-pre+asdf', '2.4.3-alpha'],
+    ['1.2.3+asdf - 2.4.3+asdf', '1.2.3'],
+    ['1.0.0', '1.0.0'],
+    ['>=*', '0.2.4'],
+    ['', '1.0.0'],
+    ['*', '1.2.3'],
+    ['*', 'v1.2.3-foo', true],
+    ['>=1.0.0', '1.0.0'],
+    ['>=1.0.0', '1.0.1'],
+    ['>=1.0.0', '1.1.0'],
+    ['>1.0.0', '1.0.1'],
+    ['>1.0.0', '1.1.0'],
+    ['<=2.0.0', '2.0.0'],
+    ['<=2.0.0', '1.9999.9999'],
+    ['<=2.0.0', '0.2.9'],
+    ['<2.0.0', '1.9999.9999'],
+    ['<2.0.0', '0.2.9'],
+    ['>= 1.0.0', '1.0.0'],
+    ['>=  1.0.0', '1.0.1'],
+    ['>=   1.0.0', '1.1.0'],
+    ['> 1.0.0', '1.0.1'],
+    ['>  1.0.0', '1.1.0'],
+    ['<=   2.0.0', '2.0.0'],
+    ['<= 2.0.0', '1.9999.9999'],
+    ['<=  2.0.0', '0.2.9'],
+    ['<    2.0.0', '1.9999.9999'],
+    ['<\t2.0.0', '0.2.9'],
+    ['>=0.1.97', 'v0.1.97', true],
+    ['>=0.1.97', '0.1.97'],
+    ['0.1.20 || 1.2.4', '1.2.4'],
+    ['>=0.2.3 || <0.0.1', '0.0.0'],
+    ['>=0.2.3 || <0.0.1', '0.2.3'],
+    ['>=0.2.3 || <0.0.1', '0.2.4'],
+    ['||', '1.3.4'],
+    ['2.x.x', '2.1.3'],
+    ['1.2.x', '1.2.3'],
+    ['1.2.x || 2.x', '2.1.3'],
+    ['1.2.x || 2.x', '1.2.3'],
+    ['x', '1.2.3'],
+    ['2.*.*', '2.1.3'],
+    ['1.2.*', '1.2.3'],
+    ['1.2.* || 2.*', '2.1.3'],
+    ['1.2.* || 2.*', '1.2.3'],
+    ['*', '1.2.3'],
+    ['2', '2.1.2'],
+    ['2.3', '2.3.1'],
+    ['~2.4', '2.4.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.4.5'],
+    ['~>3.2.1', '3.2.2'], // >=3.2.1 <3.3.0,
+    ['~1', '1.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '1.2.3'],
+    ['~> 1', '1.2.3'],
+    ['~1.0', '1.0.2'], // >=1.0.0 <1.1.0,
+    ['~ 1.0', '1.0.2'],
+    ['~ 1.0.3', '1.0.12'],
+    ['>=1', '1.0.0'],
+    ['>= 1', '1.0.0'],
+    ['<1.2', '1.1.1'],
+    ['< 1.2', '1.1.1'],
+    ['~v0.5.4-pre', '0.5.5'],
+    ['~v0.5.4-pre', '0.5.4'],
+    ['=0.7.x', '0.7.2'],
+    ['<=0.7.x', '0.7.2'],
+    ['>=0.7.x', '0.7.2'],
+    ['<=0.7.x', '0.6.2'],
+    ['~1.2.1 >=1.2.3', '1.2.3'],
+    ['~1.2.1 =1.2.3', '1.2.3'],
+    ['~1.2.1 1.2.3', '1.2.3'],
+    ['~1.2.1 >=1.2.3 1.2.3', '1.2.3'],
+    ['~1.2.1 1.2.3 >=1.2.3', '1.2.3'],
+    ['~1.2.1 1.2.3', '1.2.3'],
+    ['>=1.2.1 1.2.3', '1.2.3'],
+    ['1.2.3 >=1.2.1', '1.2.3'],
+    ['>=1.2.3 >=1.2.1', '1.2.3'],
+    ['>=1.2.1 >=1.2.3', '1.2.3'],
+    ['>=1.2', '1.2.8'],
+    ['^1.2.3', '1.8.1'],
+    ['^0.1.2', '0.1.2'],
+    ['^0.1', '0.1.2'],
+    ['^1.2', '1.4.2'],
+    ['^1.2 ^1', '1.4.2'],
+    ['^1.2.3-alpha', '1.2.3-pre'],
+    ['^1.2.0-alpha', '1.2.0-pre'],
+    ['^0.0.1-alpha', '0.0.1-beta']
+  ].forEach(function(v) {
+    var range = v[0];
+    var ver = v[1];
+    var loose = v[2];
+    t.ok(satisfies(ver, range, loose), range + ' satisfied by ' + ver);
+  });
+  t.end();
+});
+
+test('\nnegative range tests', function(t) {
+  // [range, version]
+  // version should not be included by range
+  [['1.0.0 - 2.0.0', '2.2.3'],
+    ['1.2.3+asdf - 2.4.3+asdf', '1.2.3-pre.2'],
+    ['1.2.3+asdf - 2.4.3+asdf', '2.4.3-alpha'],
+    ['^1.2.3+build', '2.0.0'],
+    ['^1.2.3+build', '1.2.0'],
+    ['^1.2.3', '1.2.3-pre'],
+    ['^1.2', '1.2.0-pre'],
+    ['>1.2', '1.3.0-beta'],
+    ['<=1.2.3', '1.2.3-beta'],
+    ['^1.2.3', '1.2.3-beta'],
+    ['=0.7.x', '0.7.0-asdf'],
+    ['>=0.7.x', '0.7.0-asdf'],
+    ['1', '1.0.0beta', true],
+    ['<1', '1.0.0beta', true],
+    ['< 1', '1.0.0beta', true],
+    ['1.0.0', '1.0.1'],
+    ['>=1.0.0', '0.0.0'],
+    ['>=1.0.0', '0.0.1'],
+    ['>=1.0.0', '0.1.0'],
+    ['>1.0.0', '0.0.1'],
+    ['>1.0.0', '0.1.0'],
+    ['<=2.0.0', '3.0.0'],
+    ['<=2.0.0', '2.9999.9999'],
+    ['<=2.0.0', '2.2.9'],
+    ['<2.0.0', '2.9999.9999'],
+    ['<2.0.0', '2.2.9'],
+    ['>=0.1.97', 'v0.1.93', true],
+    ['>=0.1.97', '0.1.93'],
+    ['0.1.20 || 1.2.4', '1.2.3'],
+    ['>=0.2.3 || <0.0.1', '0.0.3'],
+    ['>=0.2.3 || <0.0.1', '0.2.2'],
+    ['2.x.x', '1.1.3'],
+    ['2.x.x', '3.1.3'],
+    ['1.2.x', '1.3.3'],
+    ['1.2.x || 2.x', '3.1.3'],
+    ['1.2.x || 2.x', '1.1.3'],
+    ['2.*.*', '1.1.3'],
+    ['2.*.*', '3.1.3'],
+    ['1.2.*', '1.3.3'],
+    ['1.2.* || 2.*', '3.1.3'],
+    ['1.2.* || 2.*', '1.1.3'],
+    ['2', '1.1.2'],
+    ['2.3', '2.4.1'],
+    ['~2.4', '2.5.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.3.9'],
+    ['~>3.2.1', '3.3.2'], // >=3.2.1 <3.3.0
+    ['~>3.2.1', '3.2.0'], // >=3.2.1 <3.3.0
+    ['~1', '0.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '2.2.3'],
+    ['~1.0', '1.1.0'], // >=1.0.0 <1.1.0
+    ['<1', '1.0.0'],
+    ['>=1.2', '1.1.1'],
+    ['1', '2.0.0beta', true],
+    ['~v0.5.4-beta', '0.5.4-alpha'],
+    ['=0.7.x', '0.8.2'],
+    ['>=0.7.x', '0.6.2'],
+    ['<0.7.x', '0.7.2'],
+    ['<1.2.3', '1.2.3-beta'],
+    ['=1.2.3', '1.2.3-beta'],
+    ['>1.2', '1.2.8'],
+    ['^1.2.3', '2.0.0-alpha'],
+    ['^1.2.3', '1.2.2'],
+    ['^1.2', '1.1.9'],
+    // invalid ranges never satisfied!
+    ['blerg', '1.2.3'],
+    ['git+https://user:password0123@github.com/foo', '123.0.0', true],
+    ['^1.2.3', '2.0.0-pre']
+  ].forEach(function(v) {
+    var range = v[0];
+    var ver = v[1];
+    var loose = v[2];
+    var found = satisfies(ver, range, loose);
+    t.ok(!found, ver + ' not satisfied by ' + range);
+  });
+  t.end();
+});
+
+test('\nincrement versions test', function(t) {
+//  [version, inc, result, identifier]
+//  inc(version, inc) -> result
+  [['1.2.3', 'major', '2.0.0'],
+    ['1.2.3', 'minor', '1.3.0'],
+    ['1.2.3', 'patch', '1.2.4'],
+    ['1.2.3tag', 'major', '2.0.0', true],
+    ['1.2.3-tag', 'major', '2.0.0'],
+    ['1.2.3', 'fake', null],
+    ['1.2.0-0', 'patch', '1.2.0'],
+    ['fake', 'major', null],
+    ['1.2.3-4', 'major', '2.0.0'],
+    ['1.2.3-4', 'minor', '1.3.0'],
+    ['1.2.3-4', 'patch', '1.2.3'],
+    ['1.2.3-alpha.0.beta', 'major', '2.0.0'],
+    ['1.2.3-alpha.0.beta', 'minor', '1.3.0'],
+    ['1.2.3-alpha.0.beta', 'patch', '1.2.3'],
+    ['1.2.4', 'prerelease', '1.2.5-0'],
+    ['1.2.3-0', 'prerelease', '1.2.3-1'],
+    ['1.2.3-alpha.0', 'prerelease', '1.2.3-alpha.1'],
+    ['1.2.3-alpha.1', 'prerelease', '1.2.3-alpha.2'],
+    ['1.2.3-alpha.2', 'prerelease', '1.2.3-alpha.3'],
+    ['1.2.3-alpha.0.beta', 'prerelease', '1.2.3-alpha.1.beta'],
+    ['1.2.3-alpha.1.beta', 'prerelease', '1.2.3-alpha.2.beta'],
+    ['1.2.3-alpha.2.beta', 'prerelease', '1.2.3-alpha.3.beta'],
+    ['1.2.3-alpha.10.0.beta', 'prerelease', '1.2.3-alpha.10.1.beta'],
+    ['1.2.3-alpha.10.1.beta', 'prerelease', '1.2.3-alpha.10.2.beta'],
+    ['1.2.3-alpha.10.2.beta', 'prerelease', '1.2.3-alpha.10.3.beta'],
+    ['1.2.3-alpha.10.beta.0', 'prerelease', '1.2.3-alpha.10.beta.1'],
+    ['1.2.3-alpha.10.beta.1', 'prerelease', '1.2.3-alpha.10.beta.2'],
+    ['1.2.3-alpha.10.beta.2', 'prerelease', '1.2.3-alpha.10.beta.3'],
+    ['1.2.3-alpha.9.beta', 'prerelease', '1.2.3-alpha.10.beta'],
+    ['1.2.3-alpha.10.beta', 'prerelease', '1.2.3-alpha.11.beta'],
+    ['1.2.3-alpha.11.beta', 'prerelease', '1.2.3-alpha.12.beta'],
+    ['1.2.0', 'prepatch', '1.2.1-0'],
+    ['1.2.0-1', 'prepatch', '1.2.1-0'],
+    ['1.2.0', 'preminor', '1.3.0-0'],
+    ['1.2.3-1', 'preminor', '1.3.0-0'],
+    ['1.2.0', 'premajor', '2.0.0-0'],
+    ['1.2.3-1', 'premajor', '2.0.0-0'],
+    ['1.2.0-1', 'minor', '1.2.0'],
+    ['1.0.0-1', 'major', '1.0.0'],
+
+    ['1.2.3', 'major', '2.0.0', false, 'dev'],
+    ['1.2.3', 'minor', '1.3.0', false, 'dev'],
+    ['1.2.3', 'patch', '1.2.4', false, 'dev'],
+    ['1.2.3tag', 'major', '2.0.0', true, 'dev'],
+    ['1.2.3-tag', 'major', '2.0.0', false, 'dev'],
+    ['1.2.3', 'fake', null, false, 'dev'],
+    ['1.2.0-0', 'patch', '1.2.0', false, 'dev'],
+    ['fake', 'major', null, false, 'dev'],
+    ['1.2.3-4', 'major', '2.0.0', false, 'dev'],
+    ['1.2.3-4', 'minor', '1.3.0', false, 'dev'],
+    ['1.2.3-4', 'patch', '1.2.3', false, 'dev'],
+    ['1.2.3-alpha.0.beta', 'major', '2.0.0', false, 'dev'],
+    ['1.2.3-alpha.0.beta', 'minor', '1.3.0', false, 'dev'],
+    ['1.2.3-alpha.0.beta', 'patch', '1.2.3', false, 'dev'],
+    ['1.2.4', 'prerelease', '1.2.5-dev.0', false, 'dev'],
+    ['1.2.3-0', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.0', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.0', 'prerelease', '1.2.3-alpha.1', false, 'alpha'],
+    ['1.2.3-alpha.0.beta', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.0.beta', 'prerelease', '1.2.3-alpha.1.beta', false, 'alpha'],
+    ['1.2.3-alpha.10.0.beta', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.10.0.beta', 'prerelease', '1.2.3-alpha.10.1.beta', false, 'alpha'],
+    ['1.2.3-alpha.10.1.beta', 'prerelease', '1.2.3-alpha.10.2.beta', false, 'alpha'],
+    ['1.2.3-alpha.10.2.beta', 'prerelease', '1.2.3-alpha.10.3.beta', false, 'alpha'],
+    ['1.2.3-alpha.10.beta.0', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.10.beta.0', 'prerelease', '1.2.3-alpha.10.beta.1', false, 'alpha'],
+    ['1.2.3-alpha.10.beta.1', 'prerelease', '1.2.3-alpha.10.beta.2', false, 'alpha'],
+    ['1.2.3-alpha.10.beta.2', 'prerelease', '1.2.3-alpha.10.beta.3', false, 'alpha'],
+    ['1.2.3-alpha.9.beta', 'prerelease', '1.2.3-dev.0', false, 'dev'],
+    ['1.2.3-alpha.9.beta', 'prerelease', '1.2.3-alpha.10.beta', false, 'alpha'],
+    ['1.2.3-alpha.10.beta', 'prerelease', '1.2.3-alpha.11.beta', false, 'alpha'],
+    ['1.2.3-alpha.11.beta', 'prerelease', '1.2.3-alpha.12.beta', false, 'alpha'],
+    ['1.2.0', 'prepatch', '1.2.1-dev.0', 'dev'],
+    ['1.2.0-1', 'prepatch', '1.2.1-dev.0', 'dev'],
+    ['1.2.0', 'preminor', '1.3.0-dev.0', 'dev'],
+    ['1.2.3-1', 'preminor', '1.3.0-dev.0', 'dev'],
+    ['1.2.0', 'premajor', '2.0.0-dev.0', 'dev'],
+    ['1.2.3-1', 'premajor', '2.0.0-dev.0', 'dev'],
+    ['1.2.0-1', 'minor', '1.2.0', 'dev'],
+    ['1.0.0-1', 'major', '1.0.0', 'dev'],
+    ['1.2.3-dev.bar', 'prerelease', '1.2.3-dev.0', false, 'dev']
+
+  ].forEach(function(v) {
+    var pre = v[0];
+    var what = v[1];
+    var wanted = v[2];
+    var loose = v[3];
+    var id = v[4];
+    var found = inc(pre, what, loose, id);
+    var cmd = 'inc(' + pre + ', ' + what + ', ' + id + ')';
+    t.equal(found, wanted, cmd + ' === ' + wanted);
+  });
+
+  t.end();
+});
+
+test('\ndiff versions test', function(t) {
+//  [version1, version2, result]
+//  diff(version1, version2) -> result
+  [['1.2.3', '0.2.3', 'major'],
+    ['1.4.5', '0.2.3', 'major'],
+    ['1.2.3', '2.0.0-pre', 'premajor'],
+    ['1.2.3', '1.3.3', 'minor'],
+    ['1.0.1', '1.1.0-pre', 'preminor'],
+    ['1.2.3', '1.2.4', 'patch'],
+    ['1.2.3', '1.2.4-pre', 'prepatch'],
+    ['0.0.1', '0.0.1-pre', 'prerelease'],
+    ['0.0.1', '0.0.1-pre-2', 'prerelease'],
+    ['1.1.0', '1.1.0-pre', 'prerelease'],
+    ['1.1.0-pre-1', '1.1.0-pre-2', 'prerelease'],
+    ['1.0.0', '1.0.0', null]
+
+  ].forEach(function(v) {
+    var version1 = v[0];
+    var version2 = v[1];
+    var wanted = v[2];
+    var found = diff(version1, version2);
+    var cmd = 'diff(' + version1 + ', ' + version2 + ')';
+    t.equal(found, wanted, cmd + ' === ' + wanted);
+  });
+
+  t.end();
+});
+
+test('\nvalid range test', function(t) {
+  // [range, result]
+  // validRange(range) -> result
+  // translate ranges into their canonical form
+  [['1.0.0 - 2.0.0', '>=1.0.0 <=2.0.0'],
+    ['1.0.0', '1.0.0'],
+    ['>=*', '*'],
+    ['', '*'],
+    ['*', '*'],
+    ['*', '*'],
+    ['>=1.0.0', '>=1.0.0'],
+    ['>1.0.0', '>1.0.0'],
+    ['<=2.0.0', '<=2.0.0'],
+    ['1', '>=1.0.0 <2.0.0'],
+    ['<=2.0.0', '<=2.0.0'],
+    ['<=2.0.0', '<=2.0.0'],
+    ['<2.0.0', '<2.0.0'],
+    ['<2.0.0', '<2.0.0'],
+    ['>= 1.0.0', '>=1.0.0'],
+    ['>=  1.0.0', '>=1.0.0'],
+    ['>=   1.0.0', '>=1.0.0'],
+    ['> 1.0.0', '>1.0.0'],
+    ['>  1.0.0', '>1.0.0'],
+    ['<=   2.0.0', '<=2.0.0'],
+    ['<= 2.0.0', '<=2.0.0'],
+    ['<=  2.0.0', '<=2.0.0'],
+    ['<    2.0.0', '<2.0.0'],
+    ['<	2.0.0', '<2.0.0'],
+    ['>=0.1.97', '>=0.1.97'],
+    ['>=0.1.97', '>=0.1.97'],
+    ['0.1.20 || 1.2.4', '0.1.20||1.2.4'],
+    ['>=0.2.3 || <0.0.1', '>=0.2.3||<0.0.1'],
+    ['>=0.2.3 || <0.0.1', '>=0.2.3||<0.0.1'],
+    ['>=0.2.3 || <0.0.1', '>=0.2.3||<0.0.1'],
+    ['||', '||'],
+    ['2.x.x', '>=2.0.0 <3.0.0'],
+    ['1.2.x', '>=1.2.0 <1.3.0'],
+    ['1.2.x || 2.x', '>=1.2.0 <1.3.0||>=2.0.0 <3.0.0'],
+    ['1.2.x || 2.x', '>=1.2.0 <1.3.0||>=2.0.0 <3.0.0'],
+    ['x', '*'],
+    ['2.*.*', '>=2.0.0 <3.0.0'],
+    ['1.2.*', '>=1.2.0 <1.3.0'],
+    ['1.2.* || 2.*', '>=1.2.0 <1.3.0||>=2.0.0 <3.0.0'],
+    ['*', '*'],
+    ['2', '>=2.0.0 <3.0.0'],
+    ['2.3', '>=2.3.0 <2.4.0'],
+    ['~2.4', '>=2.4.0 <2.5.0'],
+    ['~2.4', '>=2.4.0 <2.5.0'],
+    ['~>3.2.1', '>=3.2.1 <3.3.0'],
+    ['~1', '>=1.0.0 <2.0.0'],
+    ['~>1', '>=1.0.0 <2.0.0'],
+    ['~> 1', '>=1.0.0 <2.0.0'],
+    ['~1.0', '>=1.0.0 <1.1.0'],
+    ['~ 1.0', '>=1.0.0 <1.1.0'],
+    ['^0', '>=0.0.0 <1.0.0'],
+    ['^ 1', '>=1.0.0 <2.0.0'],
+    ['^0.1', '>=0.1.0 <0.2.0'],
+    ['^1.0', '>=1.0.0 <2.0.0'],
+    ['^1.2', '>=1.2.0 <2.0.0'],
+    ['^0.0.1', '>=0.0.1 <0.0.2'],
+    ['^0.0.1-beta', '>=0.0.1-beta <0.0.2'],
+    ['^0.1.2', '>=0.1.2 <0.2.0'],
+    ['^1.2.3', '>=1.2.3 <2.0.0'],
+    ['^1.2.3-beta.4', '>=1.2.3-beta.4 <2.0.0'],
+    ['<1', '<1.0.0'],
+    ['< 1', '<1.0.0'],
+    ['>=1', '>=1.0.0'],
+    ['>= 1', '>=1.0.0'],
+    ['<1.2', '<1.2.0'],
+    ['< 1.2', '<1.2.0'],
+    ['1', '>=1.0.0 <2.0.0'],
+    ['>01.02.03', '>1.2.3', true],
+    ['>01.02.03', null],
+    ['~1.2.3beta', '>=1.2.3-beta <1.3.0', true],
+    ['~1.2.3beta', null],
+    ['^ 1.2 ^ 1', '>=1.2.0 <2.0.0 >=1.0.0 <2.0.0']
+  ].forEach(function(v) {
+    var pre = v[0];
+    var wanted = v[1];
+    var loose = v[2];
+    var found = validRange(pre, loose);
+
+    t.equal(found, wanted, 'validRange(' + pre + ') === ' + wanted);
+  });
+
+  t.end();
+});
+
+test('\ncomparators test', function(t) {
+  // [range, comparators]
+  // turn range into a set of individual comparators
+  [['1.0.0 - 2.0.0', [['>=1.0.0', '<=2.0.0']]],
+    ['1.0.0', [['1.0.0']]],
+    ['>=*', [['']]],
+    ['', [['']]],
+    ['*', [['']]],
+    ['*', [['']]],
+    ['>=1.0.0', [['>=1.0.0']]],
+    ['>=1.0.0', [['>=1.0.0']]],
+    ['>=1.0.0', [['>=1.0.0']]],
+    ['>1.0.0', [['>1.0.0']]],
+    ['>1.0.0', [['>1.0.0']]],
+    ['<=2.0.0', [['<=2.0.0']]],
+    ['1', [['>=1.0.0', '<2.0.0']]],
+    ['<=2.0.0', [['<=2.0.0']]],
+    ['<=2.0.0', [['<=2.0.0']]],
+    ['<2.0.0', [['<2.0.0']]],
+    ['<2.0.0', [['<2.0.0']]],
+    ['>= 1.0.0', [['>=1.0.0']]],
+    ['>=  1.0.0', [['>=1.0.0']]],
+    ['>=   1.0.0', [['>=1.0.0']]],
+    ['> 1.0.0', [['>1.0.0']]],
+    ['>  1.0.0', [['>1.0.0']]],
+    ['<=   2.0.0', [['<=2.0.0']]],
+    ['<= 2.0.0', [['<=2.0.0']]],
+    ['<=  2.0.0', [['<=2.0.0']]],
+    ['<    2.0.0', [['<2.0.0']]],
+    ['<\t2.0.0', [['<2.0.0']]],
+    ['>=0.1.97', [['>=0.1.97']]],
+    ['>=0.1.97', [['>=0.1.97']]],
+    ['0.1.20 || 1.2.4', [['0.1.20'], ['1.2.4']]],
+    ['>=0.2.3 || <0.0.1', [['>=0.2.3'], ['<0.0.1']]],
+    ['>=0.2.3 || <0.0.1', [['>=0.2.3'], ['<0.0.1']]],
+    ['>=0.2.3 || <0.0.1', [['>=0.2.3'], ['<0.0.1']]],
+    ['||', [[''], ['']]],
+    ['2.x.x', [['>=2.0.0', '<3.0.0']]],
+    ['1.2.x', [['>=1.2.0', '<1.3.0']]],
+    ['1.2.x || 2.x', [['>=1.2.0', '<1.3.0'], ['>=2.0.0', '<3.0.0']]],
+    ['1.2.x || 2.x', [['>=1.2.0', '<1.3.0'], ['>=2.0.0', '<3.0.0']]],
+    ['x', [['']]],
+    ['2.*.*', [['>=2.0.0', '<3.0.0']]],
+    ['1.2.*', [['>=1.2.0', '<1.3.0']]],
+    ['1.2.* || 2.*', [['>=1.2.0', '<1.3.0'], ['>=2.0.0', '<3.0.0']]],
+    ['1.2.* || 2.*', [['>=1.2.0', '<1.3.0'], ['>=2.0.0', '<3.0.0']]],
+    ['*', [['']]],
+    ['2', [['>=2.0.0', '<3.0.0']]],
+    ['2.3', [['>=2.3.0', '<2.4.0']]],
+    ['~2.4', [['>=2.4.0', '<2.5.0']]],
+    ['~2.4', [['>=2.4.0', '<2.5.0']]],
+    ['~>3.2.1', [['>=3.2.1', '<3.3.0']]],
+    ['~1', [['>=1.0.0', '<2.0.0']]],
+    ['~>1', [['>=1.0.0', '<2.0.0']]],
+    ['~> 1', [['>=1.0.0', '<2.0.0']]],
+    ['~1.0', [['>=1.0.0', '<1.1.0']]],
+    ['~ 1.0', [['>=1.0.0', '<1.1.0']]],
+    ['~ 1.0.3', [['>=1.0.3', '<1.1.0']]],
+    ['~> 1.0.3', [['>=1.0.3', '<1.1.0']]],
+    ['<1', [['<1.0.0']]],
+    ['< 1', [['<1.0.0']]],
+    ['>=1', [['>=1.0.0']]],
+    ['>= 1', [['>=1.0.0']]],
+    ['<1.2', [['<1.2.0']]],
+    ['< 1.2', [['<1.2.0']]],
+    ['1', [['>=1.0.0', '<2.0.0']]],
+    ['1 2', [['>=1.0.0', '<2.0.0', '>=2.0.0', '<3.0.0']]],
+    ['1.2 - 3.4.5', [['>=1.2.0', '<=3.4.5']]],
+    ['1.2.3 - 3.4', [['>=1.2.3', '<3.5.0']]],
+    ['1.2.3 - 3', [['>=1.2.3', '<4.0.0']]],
+    ['>*', [['<0.0.0']]],
+    ['<*', [['<0.0.0']]]
+  ].forEach(function(v) {
+    var pre = v[0];
+    var wanted = v[1];
+    var found = toComparators(v[0]);
+    var jw = JSON.stringify(wanted);
+    t.equivalent(found, wanted, 'toComparators(' + pre + ') === ' + jw);
+  });
+
+  t.end();
+});
+
+test('\ninvalid version numbers', function(t) {
+  ['1.2.3.4',
+   'NOT VALID',
+   1.2,
+   null,
+   'Infinity.NaN.Infinity'
+  ].forEach(function(v) {
+    t.throws(function() {
+      new SemVer(v);
+    }, {name:'TypeError', message:'Invalid Version: ' + v});
+  });
+
+  t.end();
+});
+
+test('\nstrict vs loose version numbers', function(t) {
+  [['=1.2.3', '1.2.3'],
+    ['01.02.03', '1.2.3'],
+    ['1.2.3-beta.01', '1.2.3-beta.1'],
+    ['   =1.2.3', '1.2.3'],
+    ['1.2.3foo', '1.2.3-foo']
+  ].forEach(function(v) {
+    var loose = v[0];
+    var strict = v[1];
+    t.throws(function() {
+      new SemVer(loose);
+    });
+    var lv = new SemVer(loose, true);
+    t.equal(lv.version, strict);
+    t.ok(eq(loose, strict, true));
+    t.throws(function() {
+      eq(loose, strict);
+    });
+    t.throws(function() {
+      new SemVer(strict).compare(loose);
+    });
+  });
+  t.end();
+});
+
+test('\nstrict vs loose ranges', function(t) {
+  [['>=01.02.03', '>=1.2.3'],
+    ['~1.02.03beta', '>=1.2.3-beta <1.3.0']
+  ].forEach(function(v) {
+    var loose = v[0];
+    var comps = v[1];
+    t.throws(function() {
+      new Range(loose);
+    });
+    t.equal(new Range(loose, true).range, comps);
+  });
+  t.end();
+});
+
+test('\nmax satisfying', function(t) {
+  [[['1.2.3', '1.2.4'], '1.2', '1.2.4'],
+    [['1.2.4', '1.2.3'], '1.2', '1.2.4'],
+    [['1.2.3', '1.2.4', '1.2.5', '1.2.6'], '~1.2.3', '1.2.6'],
+    [['1.1.0', '1.2.0', '1.2.1', '1.3.0', '2.0.0b1', '2.0.0b2', '2.0.0b3', '2.0.0', '2.1.0'], '~2.0.0', '2.0.0', true]
+  ].forEach(function(v) {
+    var versions = v[0];
+    var range = v[1];
+    var expect = v[2];
+    var loose = v[3];
+    var actual = semver.maxSatisfying(versions, range, loose);
+    t.equal(actual, expect);
+  });
+  t.end();
+});
diff --git a/server/node_modules/pgtools/node_modules/semver/test/ltr.js b/server/node_modules/pgtools/node_modules/semver/test/ltr.js
new file mode 100644
index 0000000000000000000000000000000000000000..ecd1387ddfe053e4120d4e6b2cbcb7030f29f281
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/test/ltr.js
@@ -0,0 +1,181 @@
+var tap = require('tap');
+var test = tap.test;
+var semver = require('../semver.js');
+var ltr = semver.ltr;
+
+test('\nltr tests', function(t) {
+  // [range, version, loose]
+  // Version should be less than range
+  [
+    ['~1.2.2', '1.2.1'],
+    ['~0.6.1-1', '0.6.1-0'],
+    ['1.0.0 - 2.0.0', '0.0.1'],
+    ['1.0.0-beta.2', '1.0.0-beta.1'],
+    ['1.0.0', '0.0.0'],
+    ['>=2.0.0', '1.1.1'],
+    ['>=2.0.0', '1.2.9'],
+    ['>2.0.0', '2.0.0'],
+    ['0.1.20 || 1.2.4', '0.1.5'],
+    ['2.x.x', '1.0.0'],
+    ['1.2.x', '1.1.0'],
+    ['1.2.x || 2.x', '1.0.0'],
+    ['2.*.*', '1.0.1'],
+    ['1.2.*', '1.1.3'],
+    ['1.2.* || 2.*', '1.1.9999'],
+    ['2', '1.0.0'],
+    ['2.3', '2.2.2'],
+    ['~2.4', '2.3.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.3.5'],
+    ['~>3.2.1', '3.2.0'], // >=3.2.1 <3.3.0
+    ['~1', '0.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '0.2.4'],
+    ['~> 1', '0.2.3'],
+    ['~1.0', '0.1.2'], // >=1.0.0 <1.1.0
+    ['~ 1.0', '0.1.0'],
+    ['>1.2', '1.2.0'],
+    ['> 1.2', '1.2.1'],
+    ['1', '0.0.0beta', true],
+    ['~v0.5.4-pre', '0.5.4-alpha'],
+    ['~v0.5.4-pre', '0.5.4-alpha'],
+    ['=0.7.x', '0.6.0'],
+    ['=0.7.x', '0.6.0-asdf'],
+    ['>=0.7.x', '0.6.0'],
+    ['~1.2.2', '1.2.1'],
+    ['1.0.0 - 2.0.0', '0.2.3'],
+    ['1.0.0', '0.0.1'],
+    ['>=2.0.0', '1.0.0'],
+    ['>=2.0.0', '1.9999.9999'],
+    ['>=2.0.0', '1.2.9'],
+    ['>2.0.0', '2.0.0'],
+    ['>2.0.0', '1.2.9'],
+    ['2.x.x', '1.1.3'],
+    ['1.2.x', '1.1.3'],
+    ['1.2.x || 2.x', '1.1.3'],
+    ['2.*.*', '1.1.3'],
+    ['1.2.*', '1.1.3'],
+    ['1.2.* || 2.*', '1.1.3'],
+    ['2', '1.9999.9999'],
+    ['2.3', '2.2.1'],
+    ['~2.4', '2.3.0'], // >=2.4.0 <2.5.0
+    ['~>3.2.1', '2.3.2'], // >=3.2.1 <3.3.0
+    ['~1', '0.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '0.2.3'],
+    ['~1.0', '0.0.0'], // >=1.0.0 <1.1.0
+    ['>1', '1.0.0'],
+    ['2', '1.0.0beta', true],
+    ['>1', '1.0.0beta', true],
+    ['> 1', '1.0.0beta', true],
+    ['=0.7.x', '0.6.2'],
+    ['=0.7.x', '0.7.0-asdf'],
+    ['^1', '1.0.0-0'],
+    ['>=0.7.x', '0.7.0-asdf'],
+    ['1', '1.0.0beta', true],
+    ['>=0.7.x', '0.6.2']
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = 'ltr(' + version + ', ' + range + ', ' + loose + ')';
+    t.ok(ltr(version, range, loose), msg);
+  });
+  t.end();
+});
+
+test('\nnegative ltr tests', function(t) {
+  // [range, version, loose]
+  // Version should NOT be greater than range
+  [
+    ['~ 1.0', '1.1.0'],
+    ['~0.6.1-1', '0.6.1-1'],
+    ['1.0.0 - 2.0.0', '1.2.3'],
+    ['1.0.0 - 2.0.0', '2.9.9'],
+    ['1.0.0', '1.0.0'],
+    ['>=*', '0.2.4'],
+    ['', '1.0.0', true],
+    ['*', '1.2.3'],
+    ['*', 'v1.2.3-foo'],
+    ['>=1.0.0', '1.0.0'],
+    ['>=1.0.0', '1.0.1'],
+    ['>=1.0.0', '1.1.0'],
+    ['>1.0.0', '1.0.1'],
+    ['>1.0.0', '1.1.0'],
+    ['<=2.0.0', '2.0.0'],
+    ['<=2.0.0', '1.9999.9999'],
+    ['<=2.0.0', '0.2.9'],
+    ['<2.0.0', '1.9999.9999'],
+    ['<2.0.0', '0.2.9'],
+    ['>= 1.0.0', '1.0.0'],
+    ['>=  1.0.0', '1.0.1'],
+    ['>=   1.0.0', '1.1.0'],
+    ['> 1.0.0', '1.0.1'],
+    ['>  1.0.0', '1.1.0'],
+    ['<=   2.0.0', '2.0.0'],
+    ['<= 2.0.0', '1.9999.9999'],
+    ['<=  2.0.0', '0.2.9'],
+    ['<    2.0.0', '1.9999.9999'],
+    ['<\t2.0.0', '0.2.9'],
+    ['>=0.1.97', 'v0.1.97'],
+    ['>=0.1.97', '0.1.97'],
+    ['0.1.20 || 1.2.4', '1.2.4'],
+    ['0.1.20 || >1.2.4', '1.2.4'],
+    ['0.1.20 || 1.2.4', '1.2.3'],
+    ['0.1.20 || 1.2.4', '0.1.20'],
+    ['>=0.2.3 || <0.0.1', '0.0.0'],
+    ['>=0.2.3 || <0.0.1', '0.2.3'],
+    ['>=0.2.3 || <0.0.1', '0.2.4'],
+    ['||', '1.3.4'],
+    ['2.x.x', '2.1.3'],
+    ['1.2.x', '1.2.3'],
+    ['1.2.x || 2.x', '2.1.3'],
+    ['1.2.x || 2.x', '1.2.3'],
+    ['x', '1.2.3'],
+    ['2.*.*', '2.1.3'],
+    ['1.2.*', '1.2.3'],
+    ['1.2.* || 2.*', '2.1.3'],
+    ['1.2.* || 2.*', '1.2.3'],
+    ['1.2.* || 2.*', '1.2.3'],
+    ['*', '1.2.3'],
+    ['2', '2.1.2'],
+    ['2.3', '2.3.1'],
+    ['~2.4', '2.4.0'], // >=2.4.0 <2.5.0
+    ['~2.4', '2.4.5'],
+    ['~>3.2.1', '3.2.2'], // >=3.2.1 <3.3.0
+    ['~1', '1.2.3'], // >=1.0.0 <2.0.0
+    ['~>1', '1.2.3'],
+    ['~> 1', '1.2.3'],
+    ['~1.0', '1.0.2'], // >=1.0.0 <1.1.0
+    ['~ 1.0', '1.0.2'],
+    ['>=1', '1.0.0'],
+    ['>= 1', '1.0.0'],
+    ['<1.2', '1.1.1'],
+    ['< 1.2', '1.1.1'],
+    ['~v0.5.4-pre', '0.5.5'],
+    ['~v0.5.4-pre', '0.5.4'],
+    ['=0.7.x', '0.7.2'],
+    ['>=0.7.x', '0.7.2'],
+    ['<=0.7.x', '0.6.2'],
+    ['>0.2.3 >0.2.4 <=0.2.5', '0.2.5'],
+    ['>=0.2.3 <=0.2.4', '0.2.4'],
+    ['1.0.0 - 2.0.0', '2.0.0'],
+    ['^3.0.0', '4.0.0'],
+    ['^1.0.0 || ~2.0.1', '2.0.0'],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '3.2.0'],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '1.0.0beta', true],
+    ['^0.1.0 || ~3.0.1 || 5.0.0', '5.0.0-0', true],
+    ['^0.1.0 || ~3.0.1 || >4 <=5.0.0', '3.5.0'],
+    ['^1.0.0alpha', '1.0.0beta', true],
+    ['~1.0.0alpha', '1.0.0beta', true],
+    ['^1.0.0-alpha', '1.0.0beta', true],
+    ['~1.0.0-alpha', '1.0.0beta', true],
+    ['^1.0.0-alpha', '1.0.0-beta'],
+    ['~1.0.0-alpha', '1.0.0-beta'],
+    ['=0.1.0', '1.0.0']
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = '!ltr(' + version + ', ' + range + ', ' + loose + ')';
+    t.notOk(ltr(version, range, loose), msg);
+  });
+  t.end();
+});
diff --git a/server/node_modules/pgtools/node_modules/semver/test/major-minor-patch.js b/server/node_modules/pgtools/node_modules/semver/test/major-minor-patch.js
new file mode 100644
index 0000000000000000000000000000000000000000..e9d4039c8be6294ba9ac51f134214bbb7d682f8e
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/test/major-minor-patch.js
@@ -0,0 +1,72 @@
+var tap = require('tap');
+var test = tap.test;
+var semver = require('../semver.js');
+
+test('\nmajor tests', function(t) {
+  // [range, version]
+  // Version should be detectable despite extra characters
+  [
+    ['1.2.3', 1],
+    [' 1.2.3 ', 1],
+    [' 2.2.3-4 ', 2],
+    [' 3.2.3-pre ', 3],
+    ['v5.2.3', 5],
+    [' v8.2.3 ', 8],
+    ['\t13.2.3', 13],
+    ['=21.2.3', 21, true],
+    ['v=34.2.3', 34, true]
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = 'major(' + range + ') = ' + version;
+    t.equal(semver.major(range, loose), version, msg);
+  });
+  t.end();
+});
+
+test('\nminor tests', function(t) {
+  // [range, version]
+  // Version should be detectable despite extra characters
+  [
+    ['1.1.3', 1],
+    [' 1.1.3 ', 1],
+    [' 1.2.3-4 ', 2],
+    [' 1.3.3-pre ', 3],
+    ['v1.5.3', 5],
+    [' v1.8.3 ', 8],
+    ['\t1.13.3', 13],
+    ['=1.21.3', 21, true],
+    ['v=1.34.3', 34, true]
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = 'minor(' + range + ') = ' + version;
+    t.equal(semver.minor(range, loose), version, msg);
+  });
+  t.end();
+});
+
+test('\npatch tests', function(t) {
+  // [range, version]
+  // Version should be detectable despite extra characters
+  [
+    ['1.2.1', 1],
+    [' 1.2.1 ', 1],
+    [' 1.2.2-4 ', 2],
+    [' 1.2.3-pre ', 3],
+    ['v1.2.5', 5],
+    [' v1.2.8 ', 8],
+    ['\t1.2.13', 13],
+    ['=1.2.21', 21, true],
+    ['v=1.2.34', 34, true]
+  ].forEach(function(tuple) {
+    var range = tuple[0];
+    var version = tuple[1];
+    var loose = tuple[2] || false;
+    var msg = 'patch(' + range + ') = ' + version;
+    t.equal(semver.patch(range, loose), version, msg);
+  });
+  t.end();
+});
diff --git a/server/node_modules/pgtools/node_modules/semver/test/no-module.js b/server/node_modules/pgtools/node_modules/semver/test/no-module.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b50873f1383b83c53a348f51da3eb1040ebbbe7
--- /dev/null
+++ b/server/node_modules/pgtools/node_modules/semver/test/no-module.js
@@ -0,0 +1,19 @@
+var tap = require('tap');
+var test = tap.test;
+
+test('no module system', function(t) {
+  var fs = require('fs');
+  var vm = require('vm');
+  var head = fs.readFileSync(require.resolve('../head.js.txt'), 'utf8');
+  var src = fs.readFileSync(require.resolve('../'), 'utf8');
+  var foot = fs.readFileSync(require.resolve('../foot.js.txt'), 'utf8');
+  vm.runInThisContext(head + src + foot, 'semver.js');
+
+  // just some basic poking to see if it did some stuff
+  t.type(global.semver, 'object');
+  t.type(global.semver.SemVer, 'function');
+  t.type(global.semver.Range, 'function');
+  t.ok(global.semver.satisfies('1.2.3', '1.2'));
+  t.end();
+});
+
diff --git a/server/node_modules/pgtools/package.json b/server/node_modules/pgtools/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..1f86bf327d84dbff290ceffb928b5fe605296a3e
--- /dev/null
+++ b/server/node_modules/pgtools/package.json
@@ -0,0 +1,82 @@
+{
+  "_from": "pgtools",
+  "_id": "pgtools@0.3.0",
+  "_inBundle": false,
+  "_integrity": "sha512-8NxDCJ8xJ6hOp9hVNZqxi+TZl7hM1Jc8pQyj8DlAbyaWnk5OsGwf3gB/UyDODdOguiim9QzbzPsslp//apO+Uw==",
+  "_location": "/pgtools",
+  "_phantomChildren": {
+    "generic-pool": "2.4.3",
+    "js-string-escape": "1.0.1",
+    "pg-connection-string": "0.1.3",
+    "pg-int8": "1.0.1",
+    "pgpass": "1.0.2",
+    "postgres-bytea": "1.0.0",
+    "postgres-date": "1.0.4",
+    "postgres-interval": "1.2.0"
+  },
+  "_requested": {
+    "type": "tag",
+    "registry": true,
+    "raw": "pgtools",
+    "name": "pgtools",
+    "escapedName": "pgtools",
+    "rawSpec": "",
+    "saveSpec": null,
+    "fetchSpec": "latest"
+  },
+  "_requiredBy": [
+    "#USER",
+    "/"
+  ],
+  "_resolved": "https://registry.npmjs.org/pgtools/-/pgtools-0.3.0.tgz",
+  "_shasum": "ee7decf4183ada28299c63df71e1e73c95b5bc53",
+  "_spec": "pgtools",
+  "_where": "/home/dante/Documents/pinsis-portal/server",
+  "author": {
+    "name": "Olivier Lalonde",
+    "email": "olalonde@gmail.com"
+  },
+  "bin": {
+    "createdbjs": "./createdb.js",
+    "dropdbjs": "./dropdb.js"
+  },
+  "bugs": {
+    "url": "https://github.com/olalonde/pgtools/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "bluebird": "^3.3.5",
+    "pg": "^6.1.0",
+    "pg-connection-string": "^0.1.3",
+    "yargs": "^5.0.0"
+  },
+  "deprecated": false,
+  "description": "Pure Node.js implementation of PostgreSQL's createdb and dropdb tools",
+  "devDependencies": {
+    "coveralls": "^2.11.12",
+    "nyc": "^11.0.3",
+    "standard-version": "^4.2.0"
+  },
+  "homepage": "https://github.com/olalonde/pgtools#readme",
+  "keywords": [
+    "postgres",
+    "postrgresql",
+    "createdb",
+    "dropdb",
+    "knex"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "pgtools",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/olalonde/pgtools.git"
+  },
+  "scripts": {
+    "coverage": "nyc report --reporter=text-lcov | coveralls",
+    "docker": "docker-compose up dbcreate && docker-compose up -d db",
+    "release": "standard-version",
+    "test": "nyc node test.js"
+  },
+  "version": "0.3.0"
+}
diff --git a/server/node_modules/pgtools/test.js b/server/node_modules/pgtools/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..311fb8fd7c4ddd62375b3df59f3000560a1b05e8
--- /dev/null
+++ b/server/node_modules/pgtools/test.js
@@ -0,0 +1,44 @@
+var createdb = require('./').createdb;
+var dropdb = require('./').dropdb;
+
+function die (err) {
+  if (err) {
+    console.error(err);
+    process.exit(-1);
+  }
+}
+
+var config = process.env.PG_CONNECTION_STRING || {
+  host: process.env.DB_HOST || '127.0.0.1',
+  user: process.env.DB_USER || 'postgres',
+}
+
+dropdb(config, 'pgtools-test', function (err, res) {
+  // ignore errors in case test was never run before
+  createdb(config, 'pgtools-test', function (err, res) {
+    die(err);
+    createdb(config, 'pgtools-test', function (err, res) {
+      if (!err
+        || !(err instanceof Error)
+        || !err.message
+        || err.name !== 'duplicate_database'
+      ) {
+        die('Creating an existing database should return an error');
+      }
+      dropdb(config, 'pgtools-test', function (err, res) {
+        die(err);
+        dropdb(config, 'pgtools-test', function (err, res) {
+          if (!err
+            || !(err instanceof Error)
+            || !err.message
+            || err.name !== 'invalid_catalog_name'
+          ) {
+            die('Dropping an nonexistent database should return an error');
+          }
+          console.log('tests pass');
+          process.exit();
+        });
+      });
+    });
+  });
+});
diff --git a/server/node_modules/pify/index.js b/server/node_modules/pify/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..7c720ebee88727c284b6e7e56687d11ce59a0ea1
--- /dev/null
+++ b/server/node_modules/pify/index.js
@@ -0,0 +1,68 @@
+'use strict';
+
+var processFn = function (fn, P, opts) {
+	return function () {
+		var that = this;
+		var args = new Array(arguments.length);
+
+		for (var i = 0; i < arguments.length; i++) {
+			args[i] = arguments[i];
+		}
+
+		return new P(function (resolve, reject) {
+			args.push(function (err, result) {
+				if (err) {
+					reject(err);
+				} else if (opts.multiArgs) {
+					var results = new Array(arguments.length - 1);
+
+					for (var i = 1; i < arguments.length; i++) {
+						results[i - 1] = arguments[i];
+					}
+
+					resolve(results);
+				} else {
+					resolve(result);
+				}
+			});
+
+			fn.apply(that, args);
+		});
+	};
+};
+
+var pify = module.exports = function (obj, P, opts) {
+	if (typeof P !== 'function') {
+		opts = P;
+		P = Promise;
+	}
+
+	opts = opts || {};
+	opts.exclude = opts.exclude || [/.+Sync$/];
+
+	var filter = function (key) {
+		var match = function (pattern) {
+			return typeof pattern === 'string' ? key === pattern : pattern.test(key);
+		};
+
+		return opts.include ? opts.include.some(match) : !opts.exclude.some(match);
+	};
+
+	var ret = typeof obj === 'function' ? function () {
+		if (opts.excludeMain) {
+			return obj.apply(this, arguments);
+		}
+
+		return processFn(obj, P, opts).apply(this, arguments);
+	} : {};
+
+	return Object.keys(obj).reduce(function (ret, key) {
+		var x = obj[key];
+
+		ret[key] = typeof x === 'function' && filter(key) ? processFn(x, P, opts) : x;
+
+		return ret;
+	}, ret);
+};
+
+pify.all = pify;
diff --git a/server/node_modules/pify/license b/server/node_modules/pify/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/pify/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/pify/package.json b/server/node_modules/pify/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..b8836a4cf3fd24fc6ee403e1b719457b553c1518
--- /dev/null
+++ b/server/node_modules/pify/package.json
@@ -0,0 +1,81 @@
+{
+  "_from": "pify@^2.0.0",
+  "_id": "pify@2.3.0",
+  "_inBundle": false,
+  "_integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+  "_location": "/pify",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "pify@^2.0.0",
+    "name": "pify",
+    "escapedName": "pify",
+    "rawSpec": "^2.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^2.0.0"
+  },
+  "_requiredBy": [
+    "/load-json-file",
+    "/path-type"
+  ],
+  "_resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+  "_shasum": "ed141a6ac043a849ea588498e7dca8b15330e90c",
+  "_spec": "pify@^2.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/load-json-file",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/pify/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Promisify a callback-style function",
+  "devDependencies": {
+    "ava": "*",
+    "pinkie-promise": "^1.0.0",
+    "v8-natives": "0.0.2",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/pify#readme",
+  "keywords": [
+    "promise",
+    "promises",
+    "promisify",
+    "denodify",
+    "denodeify",
+    "callback",
+    "cb",
+    "node",
+    "then",
+    "thenify",
+    "convert",
+    "transform",
+    "wrap",
+    "wrapper",
+    "bind",
+    "to",
+    "async",
+    "es2015"
+  ],
+  "license": "MIT",
+  "name": "pify",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/pify.git"
+  },
+  "scripts": {
+    "optimization-test": "node --allow-natives-syntax optimization-test.js",
+    "test": "xo && ava && npm run optimization-test"
+  },
+  "version": "2.3.0"
+}
diff --git a/server/node_modules/pify/readme.md b/server/node_modules/pify/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..c79ca8bf643927e9106b2c64ecd87d8bdabaf309
--- /dev/null
+++ b/server/node_modules/pify/readme.md
@@ -0,0 +1,119 @@
+# pify [![Build Status](https://travis-ci.org/sindresorhus/pify.svg?branch=master)](https://travis-ci.org/sindresorhus/pify)
+
+> Promisify a callback-style function
+
+
+## Install
+
+```
+$ npm install --save pify
+```
+
+
+## Usage
+
+```js
+const fs = require('fs');
+const pify = require('pify');
+
+// promisify a single function
+
+pify(fs.readFile)('package.json', 'utf8').then(data => {
+	console.log(JSON.parse(data).name);
+	//=> 'pify'
+});
+
+// or promisify all methods in a module
+
+pify(fs).readFile('package.json', 'utf8').then(data => {
+	console.log(JSON.parse(data).name);
+	//=> 'pify'
+});
+```
+
+
+## API
+
+### pify(input, [promiseModule], [options])
+
+Returns a promise wrapped version of the supplied function or module.
+
+#### input
+
+Type: `function`, `object`
+
+Callback-style function or module whose methods you want to promisify.
+
+#### promiseModule
+
+Type: `function`
+
+Custom promise module to use instead of the native one.
+
+Check out [`pinkie-promise`](https://github.com/floatdrop/pinkie-promise) if you need a tiny promise polyfill.
+
+#### options
+
+##### multiArgs
+
+Type: `boolean`  
+Default: `false`
+
+By default, the promisified function will only return the second argument from the callback, which works fine for most APIs. This option can be useful for modules like `request` that return multiple arguments. Turning this on will make it return an array of all arguments from the callback, excluding the error argument, instead of just the second argument.
+
+```js
+const request = require('request');
+const pify = require('pify');
+
+pify(request, {multiArgs: true})('https://sindresorhus.com').then(result => {
+	const [httpResponse, body] = result;
+});
+```
+
+##### include
+
+Type: `array` of (`string`|`regex`)
+
+Methods in a module to promisify. Remaining methods will be left untouched.
+
+##### exclude
+
+Type: `array` of (`string`|`regex`)  
+Default: `[/.+Sync$/]`
+
+Methods in a module **not** to promisify. Methods with names ending with `'Sync'` are excluded by default.
+
+##### excludeMain
+
+Type: `boolean`  
+Default: `false`
+
+By default, if given module is a function itself, this function will be promisified. Turn this option on if you want to promisify only methods of the module.
+
+```js
+const pify = require('pify');
+
+function fn() {
+	return true;
+}
+
+fn.method = (data, callback) => {
+	setImmediate(() => {
+		callback(data, null);
+	});
+};
+
+// promisify methods but not fn()
+const promiseFn = pify(fn, {excludeMain: true});
+
+if (promiseFn()) {
+	promiseFn.method('hi').then(data => {
+		console.log(data);
+	});
+}
+```
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/pinkie-promise/index.js b/server/node_modules/pinkie-promise/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..777377a1f777b166a5b116e1a87f99d21fbea75d
--- /dev/null
+++ b/server/node_modules/pinkie-promise/index.js
@@ -0,0 +1,3 @@
+'use strict';
+
+module.exports = typeof Promise === 'function' ? Promise : require('pinkie');
diff --git a/server/node_modules/pinkie-promise/license b/server/node_modules/pinkie-promise/license
new file mode 100644
index 0000000000000000000000000000000000000000..1aeb74fd25e1715d8129a1babc8113f7c4deb7e3
--- /dev/null
+++ b/server/node_modules/pinkie-promise/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Vsevolod Strukchinsky <floatdrop@gmail.com> (github.com/floatdrop)
+
+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.
diff --git a/server/node_modules/pinkie-promise/package.json b/server/node_modules/pinkie-promise/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..a9c0fab050e2ed3db854dfc2f7dca43ac0845ec8
--- /dev/null
+++ b/server/node_modules/pinkie-promise/package.json
@@ -0,0 +1,70 @@
+{
+  "_from": "pinkie-promise@^2.0.0",
+  "_id": "pinkie-promise@2.0.1",
+  "_inBundle": false,
+  "_integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+  "_location": "/pinkie-promise",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "pinkie-promise@^2.0.0",
+    "name": "pinkie-promise",
+    "escapedName": "pinkie-promise",
+    "rawSpec": "^2.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^2.0.0"
+  },
+  "_requiredBy": [
+    "/find-up",
+    "/load-json-file",
+    "/path-exists",
+    "/path-type"
+  ],
+  "_resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+  "_shasum": "2135d6dfa7a358c069ac9b178776288228450ffa",
+  "_spec": "pinkie-promise@^2.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/find-up",
+  "author": {
+    "name": "Vsevolod Strukchinsky",
+    "email": "floatdrop@gmail.com",
+    "url": "github.com/floatdrop"
+  },
+  "bugs": {
+    "url": "https://github.com/floatdrop/pinkie-promise/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "pinkie": "^2.0.0"
+  },
+  "deprecated": false,
+  "description": "ES2015 Promise ponyfill",
+  "devDependencies": {
+    "mocha": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/floatdrop/pinkie-promise#readme",
+  "keywords": [
+    "promise",
+    "promises",
+    "es2015",
+    "es6",
+    "polyfill",
+    "ponyfill"
+  ],
+  "license": "MIT",
+  "name": "pinkie-promise",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/floatdrop/pinkie-promise.git"
+  },
+  "scripts": {
+    "test": "mocha"
+  },
+  "version": "2.0.1"
+}
diff --git a/server/node_modules/pinkie-promise/readme.md b/server/node_modules/pinkie-promise/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..78477f4297d677bbfa9579042216bf797284e922
--- /dev/null
+++ b/server/node_modules/pinkie-promise/readme.md
@@ -0,0 +1,28 @@
+# pinkie-promise [![Build Status](https://travis-ci.org/floatdrop/pinkie-promise.svg?branch=master)](https://travis-ci.org/floatdrop/pinkie-promise)
+
+> [ES2015 Promise](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-objects) ponyfill
+
+Module exports global Promise object (if available) or [`pinkie`](http://github.com/floatdrop/pinkie) Promise polyfill.
+
+## Install
+
+```
+$ npm install --save pinkie-promise
+```
+
+## Usage
+
+```js
+var Promise = require('pinkie-promise');
+
+new Promise(function (resolve) { resolve('unicorns'); });
+//=> Promise { 'unicorns' }
+```
+
+## Related
+
+- [pify](https://github.com/sindresorhus/pify) - Promisify a callback-style function
+
+## License
+
+MIT © [Vsevolod Strukchinsky](http://github.com/floatdrop)
diff --git a/server/node_modules/pinkie/index.js b/server/node_modules/pinkie/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..14ce1bfe3d4918cf790b4f247d9f536f3a8eb3c2
--- /dev/null
+++ b/server/node_modules/pinkie/index.js
@@ -0,0 +1,292 @@
+'use strict';
+
+var PENDING = 'pending';
+var SETTLED = 'settled';
+var FULFILLED = 'fulfilled';
+var REJECTED = 'rejected';
+var NOOP = function () {};
+var isNode = typeof global !== 'undefined' && typeof global.process !== 'undefined' && typeof global.process.emit === 'function';
+
+var asyncSetTimer = typeof setImmediate === 'undefined' ? setTimeout : setImmediate;
+var asyncQueue = [];
+var asyncTimer;
+
+function asyncFlush() {
+	// run promise callbacks
+	for (var i = 0; i < asyncQueue.length; i++) {
+		asyncQueue[i][0](asyncQueue[i][1]);
+	}
+
+	// reset async asyncQueue
+	asyncQueue = [];
+	asyncTimer = false;
+}
+
+function asyncCall(callback, arg) {
+	asyncQueue.push([callback, arg]);
+
+	if (!asyncTimer) {
+		asyncTimer = true;
+		asyncSetTimer(asyncFlush, 0);
+	}
+}
+
+function invokeResolver(resolver, promise) {
+	function resolvePromise(value) {
+		resolve(promise, value);
+	}
+
+	function rejectPromise(reason) {
+		reject(promise, reason);
+	}
+
+	try {
+		resolver(resolvePromise, rejectPromise);
+	} catch (e) {
+		rejectPromise(e);
+	}
+}
+
+function invokeCallback(subscriber) {
+	var owner = subscriber.owner;
+	var settled = owner._state;
+	var value = owner._data;
+	var callback = subscriber[settled];
+	var promise = subscriber.then;
+
+	if (typeof callback === 'function') {
+		settled = FULFILLED;
+		try {
+			value = callback(value);
+		} catch (e) {
+			reject(promise, e);
+		}
+	}
+
+	if (!handleThenable(promise, value)) {
+		if (settled === FULFILLED) {
+			resolve(promise, value);
+		}
+
+		if (settled === REJECTED) {
+			reject(promise, value);
+		}
+	}
+}
+
+function handleThenable(promise, value) {
+	var resolved;
+
+	try {
+		if (promise === value) {
+			throw new TypeError('A promises callback cannot return that same promise.');
+		}
+
+		if (value && (typeof value === 'function' || typeof value === 'object')) {
+			// then should be retrieved only once
+			var then = value.then;
+
+			if (typeof then === 'function') {
+				then.call(value, function (val) {
+					if (!resolved) {
+						resolved = true;
+
+						if (value === val) {
+							fulfill(promise, val);
+						} else {
+							resolve(promise, val);
+						}
+					}
+				}, function (reason) {
+					if (!resolved) {
+						resolved = true;
+
+						reject(promise, reason);
+					}
+				});
+
+				return true;
+			}
+		}
+	} catch (e) {
+		if (!resolved) {
+			reject(promise, e);
+		}
+
+		return true;
+	}
+
+	return false;
+}
+
+function resolve(promise, value) {
+	if (promise === value || !handleThenable(promise, value)) {
+		fulfill(promise, value);
+	}
+}
+
+function fulfill(promise, value) {
+	if (promise._state === PENDING) {
+		promise._state = SETTLED;
+		promise._data = value;
+
+		asyncCall(publishFulfillment, promise);
+	}
+}
+
+function reject(promise, reason) {
+	if (promise._state === PENDING) {
+		promise._state = SETTLED;
+		promise._data = reason;
+
+		asyncCall(publishRejection, promise);
+	}
+}
+
+function publish(promise) {
+	promise._then = promise._then.forEach(invokeCallback);
+}
+
+function publishFulfillment(promise) {
+	promise._state = FULFILLED;
+	publish(promise);
+}
+
+function publishRejection(promise) {
+	promise._state = REJECTED;
+	publish(promise);
+	if (!promise._handled && isNode) {
+		global.process.emit('unhandledRejection', promise._data, promise);
+	}
+}
+
+function notifyRejectionHandled(promise) {
+	global.process.emit('rejectionHandled', promise);
+}
+
+/**
+ * @class
+ */
+function Promise(resolver) {
+	if (typeof resolver !== 'function') {
+		throw new TypeError('Promise resolver ' + resolver + ' is not a function');
+	}
+
+	if (this instanceof Promise === false) {
+		throw new TypeError('Failed to construct \'Promise\': Please use the \'new\' operator, this object constructor cannot be called as a function.');
+	}
+
+	this._then = [];
+
+	invokeResolver(resolver, this);
+}
+
+Promise.prototype = {
+	constructor: Promise,
+
+	_state: PENDING,
+	_then: null,
+	_data: undefined,
+	_handled: false,
+
+	then: function (onFulfillment, onRejection) {
+		var subscriber = {
+			owner: this,
+			then: new this.constructor(NOOP),
+			fulfilled: onFulfillment,
+			rejected: onRejection
+		};
+
+		if ((onRejection || onFulfillment) && !this._handled) {
+			this._handled = true;
+			if (this._state === REJECTED && isNode) {
+				asyncCall(notifyRejectionHandled, this);
+			}
+		}
+
+		if (this._state === FULFILLED || this._state === REJECTED) {
+			// already resolved, call callback async
+			asyncCall(invokeCallback, subscriber);
+		} else {
+			// subscribe
+			this._then.push(subscriber);
+		}
+
+		return subscriber.then;
+	},
+
+	catch: function (onRejection) {
+		return this.then(null, onRejection);
+	}
+};
+
+Promise.all = function (promises) {
+	if (!Array.isArray(promises)) {
+		throw new TypeError('You must pass an array to Promise.all().');
+	}
+
+	return new Promise(function (resolve, reject) {
+		var results = [];
+		var remaining = 0;
+
+		function resolver(index) {
+			remaining++;
+			return function (value) {
+				results[index] = value;
+				if (!--remaining) {
+					resolve(results);
+				}
+			};
+		}
+
+		for (var i = 0, promise; i < promises.length; i++) {
+			promise = promises[i];
+
+			if (promise && typeof promise.then === 'function') {
+				promise.then(resolver(i), reject);
+			} else {
+				results[i] = promise;
+			}
+		}
+
+		if (!remaining) {
+			resolve(results);
+		}
+	});
+};
+
+Promise.race = function (promises) {
+	if (!Array.isArray(promises)) {
+		throw new TypeError('You must pass an array to Promise.race().');
+	}
+
+	return new Promise(function (resolve, reject) {
+		for (var i = 0, promise; i < promises.length; i++) {
+			promise = promises[i];
+
+			if (promise && typeof promise.then === 'function') {
+				promise.then(resolve, reject);
+			} else {
+				resolve(promise);
+			}
+		}
+	});
+};
+
+Promise.resolve = function (value) {
+	if (value && typeof value === 'object' && value.constructor === Promise) {
+		return value;
+	}
+
+	return new Promise(function (resolve) {
+		resolve(value);
+	});
+};
+
+Promise.reject = function (reason) {
+	return new Promise(function (resolve, reject) {
+		reject(reason);
+	});
+};
+
+module.exports = Promise;
diff --git a/server/node_modules/pinkie/license b/server/node_modules/pinkie/license
new file mode 100644
index 0000000000000000000000000000000000000000..1aeb74fd25e1715d8129a1babc8113f7c4deb7e3
--- /dev/null
+++ b/server/node_modules/pinkie/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Vsevolod Strukchinsky <floatdrop@gmail.com> (github.com/floatdrop)
+
+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.
diff --git a/server/node_modules/pinkie/package.json b/server/node_modules/pinkie/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..03f883318ada0e712a44b6ac6fad20ccabb83ccc
--- /dev/null
+++ b/server/node_modules/pinkie/package.json
@@ -0,0 +1,68 @@
+{
+  "_from": "pinkie@^2.0.0",
+  "_id": "pinkie@2.0.4",
+  "_inBundle": false,
+  "_integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+  "_location": "/pinkie",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "pinkie@^2.0.0",
+    "name": "pinkie",
+    "escapedName": "pinkie",
+    "rawSpec": "^2.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^2.0.0"
+  },
+  "_requiredBy": [
+    "/pinkie-promise"
+  ],
+  "_resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+  "_shasum": "72556b80cfa0d48a974e80e77248e80ed4f7f870",
+  "_spec": "pinkie@^2.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pinkie-promise",
+  "author": {
+    "name": "Vsevolod Strukchinsky",
+    "email": "floatdrop@gmail.com",
+    "url": "github.com/floatdrop"
+  },
+  "bugs": {
+    "url": "https://github.com/floatdrop/pinkie/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Itty bitty little widdle twinkie pinkie ES2015 Promise implementation",
+  "devDependencies": {
+    "core-assert": "^0.1.1",
+    "coveralls": "^2.11.4",
+    "mocha": "*",
+    "nyc": "^3.2.2",
+    "promises-aplus-tests": "*",
+    "xo": "^0.10.1"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/floatdrop/pinkie#readme",
+  "keywords": [
+    "promise",
+    "promises",
+    "es2015",
+    "es6"
+  ],
+  "license": "MIT",
+  "name": "pinkie",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/floatdrop/pinkie.git"
+  },
+  "scripts": {
+    "coverage": "nyc report --reporter=text-lcov | coveralls",
+    "test": "xo && nyc mocha"
+  },
+  "version": "2.0.4"
+}
diff --git a/server/node_modules/pinkie/readme.md b/server/node_modules/pinkie/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..1565f95889661b0d3f28573d36e64a0fe251b291
--- /dev/null
+++ b/server/node_modules/pinkie/readme.md
@@ -0,0 +1,83 @@
+<h1 align="center">
+	<br>
+	<img width="256" src="media/logo.png" alt="pinkie">
+	<br>
+	<br>
+</h1>
+
+> Itty bitty little widdle twinkie pinkie [ES2015 Promise](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-objects) implementation
+
+[![Build Status](https://travis-ci.org/floatdrop/pinkie.svg?branch=master)](https://travis-ci.org/floatdrop/pinkie)  [![Coverage Status](https://coveralls.io/repos/floatdrop/pinkie/badge.svg?branch=master&service=github)](https://coveralls.io/github/floatdrop/pinkie?branch=master)
+
+There are [tons of Promise implementations](https://github.com/promises-aplus/promises-spec/blob/master/implementations.md#standalone) out there, but all of them focus on browser compatibility and are often bloated with functionality.
+
+This module is an exact Promise specification polyfill (like [native-promise-only](https://github.com/getify/native-promise-only)), but in Node.js land (it should be browserify-able though).
+
+
+## Install
+
+```
+$ npm install --save pinkie
+```
+
+
+## Usage
+
+```js
+var fs = require('fs');
+var Promise = require('pinkie');
+
+new Promise(function (resolve, reject) {
+	fs.readFile('foo.json', 'utf8', function (err, data) {
+		if (err) {
+			reject(err);
+			return;
+		}
+
+		resolve(data);
+	});
+});
+//=> Promise
+```
+
+
+### API
+
+`pinkie` exports bare [ES2015 Promise](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-objects) implementation and polyfills [Node.js rejection events](https://nodejs.org/api/process.html#process_event_unhandledrejection). In case you forgot:
+
+#### new Promise(executor)
+
+Returns new instance of `Promise`.
+
+##### executor
+
+*Required*  
+Type: `function`
+
+Function with two arguments `resolve` and `reject`. The first argument fulfills the promise, the second argument rejects it.
+
+#### pinkie.all(promises)
+
+Returns a promise that resolves when all of the promises in the `promises` Array argument have resolved.
+
+#### pinkie.race(promises)
+
+Returns a promise that resolves or rejects as soon as one of the promises in the `promises` Array resolves or rejects, with the value or reason from that promise.
+
+#### pinkie.reject(reason)
+
+Returns a Promise object that is rejected with the given `reason`.
+
+#### pinkie.resolve(value)
+
+Returns a Promise object that is resolved with the given `value`. If the `value` is a thenable (i.e. has a then method), the returned promise will "follow" that thenable, adopting its eventual state; otherwise the returned promise will be fulfilled with the `value`.
+
+
+## Related
+
+- [pinkie-promise](https://github.com/floatdrop/pinkie-promise) - Returns the native Promise or this module
+
+
+## License
+
+MIT © [Vsevolod Strukchinsky](http://github.com/floatdrop)
diff --git a/server/node_modules/postgres-array/index.d.ts b/server/node_modules/postgres-array/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..88665bd9159c1c7b54aa56f5cf2c4ca1cdf4dd32
--- /dev/null
+++ b/server/node_modules/postgres-array/index.d.ts
@@ -0,0 +1,4 @@
+
+export function parse(source: string): string[];
+export function parse<T>(source: string, transform: (value: string) => T): T[];
+
diff --git a/server/node_modules/postgres-array/index.js b/server/node_modules/postgres-array/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..18bfd163612aee7ad7c4256a555c675069b821c2
--- /dev/null
+++ b/server/node_modules/postgres-array/index.js
@@ -0,0 +1,97 @@
+'use strict'
+
+exports.parse = function (source, transform) {
+  return new ArrayParser(source, transform).parse()
+}
+
+class ArrayParser {
+  constructor (source, transform) {
+    this.source = source
+    this.transform = transform || identity
+    this.position = 0
+    this.entries = []
+    this.recorded = []
+    this.dimension = 0
+  }
+
+  isEof () {
+    return this.position >= this.source.length
+  }
+
+  nextCharacter () {
+    var character = this.source[this.position++]
+    if (character === '\\') {
+      return {
+        value: this.source[this.position++],
+        escaped: true
+      }
+    }
+    return {
+      value: character,
+      escaped: false
+    }
+  }
+
+  record (character) {
+    this.recorded.push(character)
+  }
+
+  newEntry (includeEmpty) {
+    var entry
+    if (this.recorded.length > 0 || includeEmpty) {
+      entry = this.recorded.join('')
+      if (entry === 'NULL' && !includeEmpty) {
+        entry = null
+      }
+      if (entry !== null) entry = this.transform(entry)
+      this.entries.push(entry)
+      this.recorded = []
+    }
+  }
+
+  consumeDimensions () {
+    if (this.source[0] === '[') {
+      while (!this.isEof()) {
+        var char = this.nextCharacter()
+        if (char.value === '=') break
+      }
+    }
+  }
+
+  parse (nested) {
+    var character, parser, quote
+    this.consumeDimensions()
+    while (!this.isEof()) {
+      character = this.nextCharacter()
+      if (character.value === '{' && !quote) {
+        this.dimension++
+        if (this.dimension > 1) {
+          parser = new ArrayParser(this.source.substr(this.position - 1), this.transform)
+          this.entries.push(parser.parse(true))
+          this.position += parser.position - 2
+        }
+      } else if (character.value === '}' && !quote) {
+        this.dimension--
+        if (!this.dimension) {
+          this.newEntry()
+          if (nested) return this.entries
+        }
+      } else if (character.value === '"' && !character.escaped) {
+        if (quote) this.newEntry(true)
+        quote = !quote
+      } else if (character.value === ',' && !quote) {
+        this.newEntry()
+      } else {
+        this.record(character.value)
+      }
+    }
+    if (this.dimension !== 0) {
+      throw new Error('array dimension not balanced')
+    }
+    return this.entries
+  }
+}
+
+function identity (value) {
+  return value
+}
diff --git a/server/node_modules/postgres-array/license b/server/node_modules/postgres-array/license
new file mode 100644
index 0000000000000000000000000000000000000000..25c624701389bab54c94982531ea34e8d1702ccf
--- /dev/null
+++ b/server/node_modules/postgres-array/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Ben Drucker <bvdrucker@gmail.com> (bendrucker.me)
+
+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.
diff --git a/server/node_modules/postgres-array/package.json b/server/node_modules/postgres-array/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..feb459b77deb1c9b81884ecdad8a48a4f4f91b18
--- /dev/null
+++ b/server/node_modules/postgres-array/package.json
@@ -0,0 +1,67 @@
+{
+  "_from": "postgres-array@~2.0.0",
+  "_id": "postgres-array@2.0.0",
+  "_inBundle": false,
+  "_integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
+  "_location": "/postgres-array",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "postgres-array@~2.0.0",
+    "name": "postgres-array",
+    "escapedName": "postgres-array",
+    "rawSpec": "~2.0.0",
+    "saveSpec": null,
+    "fetchSpec": "~2.0.0"
+  },
+  "_requiredBy": [
+    "/pg-types"
+  ],
+  "_resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
+  "_shasum": "48f8fce054fbc69671999329b8834b772652d82e",
+  "_spec": "postgres-array@~2.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg-types",
+  "author": {
+    "name": "Ben Drucker",
+    "email": "bvdrucker@gmail.com",
+    "url": "bendrucker.me"
+  },
+  "bugs": {
+    "url": "https://github.com/bendrucker/postgres-array/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "Parse postgres array columns",
+  "devDependencies": {
+    "standard": "^12.0.1",
+    "tape": "^4.0.0"
+  },
+  "engines": {
+    "node": ">=4"
+  },
+  "files": [
+    "index.js",
+    "index.d.ts",
+    "readme.md"
+  ],
+  "homepage": "https://github.com/bendrucker/postgres-array#readme",
+  "keywords": [
+    "postgres",
+    "array",
+    "parser"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "postgres-array",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/bendrucker/postgres-array.git"
+  },
+  "scripts": {
+    "test": "standard && tape test.js"
+  },
+  "types": "index.d.ts",
+  "version": "2.0.0"
+}
diff --git a/server/node_modules/postgres-array/readme.md b/server/node_modules/postgres-array/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..b74b369df932ed5b7e45a66a522901f62a8ba8f1
--- /dev/null
+++ b/server/node_modules/postgres-array/readme.md
@@ -0,0 +1,43 @@
+# postgres-array [![Build Status](https://travis-ci.org/bendrucker/postgres-array.svg?branch=master)](https://travis-ci.org/bendrucker/postgres-array)
+
+> Parse postgres array columns
+
+
+## Install
+
+```
+$ npm install --save postgres-array
+```
+
+
+## Usage
+
+```js
+var postgresArray = require('postgres-array')
+
+postgresArray.parse('{1,2,3}', (value) => parseInt(value, 10))
+//=> [1, 2, 3]
+```
+
+## API
+
+#### `parse(input, [transform])` -> `array`
+
+##### input
+
+*Required*  
+Type: `string`
+
+A Postgres array string.
+
+##### transform
+
+Type: `function`  
+Default: `identity`
+
+A function that transforms non-null values inserted into the array.
+
+
+## License
+
+MIT © [Ben Drucker](http://bendrucker.me)
diff --git a/server/node_modules/postgres-bytea/index.js b/server/node_modules/postgres-bytea/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..d1107a01742c7be3fed2b1f8967221d0d6a58033
--- /dev/null
+++ b/server/node_modules/postgres-bytea/index.js
@@ -0,0 +1,31 @@
+'use strict'
+
+module.exports = function parseBytea (input) {
+  if (/^\\x/.test(input)) {
+    // new 'hex' style response (pg >9.0)
+    return new Buffer(input.substr(2), 'hex')
+  }
+  var output = ''
+  var i = 0
+  while (i < input.length) {
+    if (input[i] !== '\\') {
+      output += input[i]
+      ++i
+    } else {
+      if (/[0-7]{3}/.test(input.substr(i + 1, 3))) {
+        output += String.fromCharCode(parseInt(input.substr(i + 1, 3), 8))
+        i += 4
+      } else {
+        var backslashes = 1
+        while (i + backslashes < input.length && input[i + backslashes] === '\\') {
+          backslashes++
+        }
+        for (var k = 0; k < Math.floor(backslashes / 2); ++k) {
+          output += '\\'
+        }
+        i += Math.floor(backslashes / 2) * 2
+      }
+    }
+  }
+  return new Buffer(output, 'binary')
+}
diff --git a/server/node_modules/postgres-bytea/license b/server/node_modules/postgres-bytea/license
new file mode 100644
index 0000000000000000000000000000000000000000..25c624701389bab54c94982531ea34e8d1702ccf
--- /dev/null
+++ b/server/node_modules/postgres-bytea/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Ben Drucker <bvdrucker@gmail.com> (bendrucker.me)
+
+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.
diff --git a/server/node_modules/postgres-bytea/package.json b/server/node_modules/postgres-bytea/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..8cc5fe8bad303fa753ea30bef81fb029e0c20a16
--- /dev/null
+++ b/server/node_modules/postgres-bytea/package.json
@@ -0,0 +1,66 @@
+{
+  "_from": "postgres-bytea@~1.0.0",
+  "_id": "postgres-bytea@1.0.0",
+  "_inBundle": false,
+  "_integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=",
+  "_location": "/postgres-bytea",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "postgres-bytea@~1.0.0",
+    "name": "postgres-bytea",
+    "escapedName": "postgres-bytea",
+    "rawSpec": "~1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "~1.0.0"
+  },
+  "_requiredBy": [
+    "/pg-types"
+  ],
+  "_resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
+  "_shasum": "027b533c0aa890e26d172d47cf9ccecc521acd35",
+  "_spec": "postgres-bytea@~1.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg-types",
+  "author": {
+    "name": "Ben Drucker",
+    "email": "bvdrucker@gmail.com",
+    "url": "bendrucker.me"
+  },
+  "bugs": {
+    "url": "https://github.com/bendrucker/postgres-bytea/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "Postgres bytea parser",
+  "devDependencies": {
+    "standard": "^4.0.0",
+    "tape": "^4.0.0"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js",
+    "readme.md"
+  ],
+  "homepage": "https://github.com/bendrucker/postgres-bytea#readme",
+  "keywords": [
+    "bytea",
+    "postgres",
+    "binary",
+    "parser"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "postgres-bytea",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/bendrucker/postgres-bytea.git"
+  },
+  "scripts": {
+    "test": "standard && tape test.js"
+  },
+  "version": "1.0.0"
+}
diff --git a/server/node_modules/postgres-bytea/readme.md b/server/node_modules/postgres-bytea/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..4939c3be4bbd31d5212b8fa8b5cf6d7a4ecec5b8
--- /dev/null
+++ b/server/node_modules/postgres-bytea/readme.md
@@ -0,0 +1,34 @@
+# postgres-bytea [![Build Status](https://travis-ci.org/bendrucker/postgres-bytea.svg?branch=master)](https://travis-ci.org/bendrucker/postgres-bytea)
+
+> Postgres bytea parser
+
+
+## Install
+
+```
+$ npm install --save postgres-bytea
+```
+
+
+## Usage
+
+```js
+var bytea = require('postgres-bytea');
+bytea('\\000\\100\\200')
+//=> buffer
+```
+
+## API
+
+#### `bytea(input)` -> `buffer`
+
+##### input
+
+*Required*  
+Type: `string`
+
+A Postgres bytea binary string.
+
+## License
+
+MIT © [Ben Drucker](http://bendrucker.me)
diff --git a/server/node_modules/postgres-date/index.js b/server/node_modules/postgres-date/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..1f03c457cf353554231fe3ed2334082292f778a5
--- /dev/null
+++ b/server/node_modules/postgres-date/index.js
@@ -0,0 +1,110 @@
+'use strict'
+
+var DATE_TIME = /(\d{1,})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})(\.\d{1,})?.*?( BC)?$/
+var DATE = /^(\d{1,})-(\d{2})-(\d{2})( BC)?$/
+var TIME_ZONE = /([Z+-])(\d{2})?:?(\d{2})?:?(\d{2})?/
+var INFINITY = /^-?infinity$/
+
+module.exports = function parseDate (isoDate) {
+  if (INFINITY.test(isoDate)) {
+    // Capitalize to Infinity before passing to Number
+    return Number(isoDate.replace('i', 'I'))
+  }
+  var matches = DATE_TIME.exec(isoDate)
+
+  if (!matches) {
+    // Force YYYY-MM-DD dates to be parsed as local time
+    return getDate(isoDate) || null
+  }
+
+  var isBC = !!matches[8]
+  var year = parseInt(matches[1], 10)
+  if (isBC) {
+    year = bcYearToNegativeYear(year)
+  }
+
+  var month = parseInt(matches[2], 10) - 1
+  var day = matches[3]
+  var hour = parseInt(matches[4], 10)
+  var minute = parseInt(matches[5], 10)
+  var second = parseInt(matches[6], 10)
+
+  var ms = matches[7]
+  ms = ms ? 1000 * parseFloat(ms) : 0
+
+  var date
+  var offset = timeZoneOffset(isoDate)
+  if (offset != null) {
+    date = new Date(Date.UTC(year, month, day, hour, minute, second, ms))
+
+    // Account for years from 0 to 99 being interpreted as 1900-1999
+    // by Date.UTC / the multi-argument form of the Date constructor
+    if (is0To99(year)) {
+      date.setUTCFullYear(year)
+    }
+
+    date.setTime(date.getTime() - offset)
+  } else {
+    date = new Date(year, month, day, hour, minute, second, ms)
+
+    if (is0To99(year)) {
+      date.setFullYear(year)
+    }
+  }
+
+  return date
+}
+
+function getDate (isoDate) {
+  var matches = DATE.exec(isoDate)
+  if (!matches) {
+    return
+  }
+
+  var year = parseInt(matches[1], 10)
+  var isBC = !!matches[4]
+  if (isBC) {
+    year = bcYearToNegativeYear(year)
+  }
+
+  var month = parseInt(matches[2], 10) - 1
+  var day = matches[3]
+  // YYYY-MM-DD will be parsed as local time
+  var date = new Date(year, month, day)
+
+  if (is0To99(year)) {
+    date.setFullYear(year)
+  }
+
+  return date
+}
+
+// match timezones:
+// Z (UTC)
+// -05
+// +06:30
+function timeZoneOffset (isoDate) {
+  var zone = TIME_ZONE.exec(isoDate.split(' ')[1])
+  if (!zone) return
+  var type = zone[1]
+
+  if (type === 'Z') {
+    return 0
+  }
+  var sign = type === '-' ? -1 : 1
+  var offset = parseInt(zone[2], 10) * 3600 +
+    parseInt(zone[3] || 0, 10) * 60 +
+    parseInt(zone[4] || 0, 10)
+
+  return offset * sign * 1000
+}
+
+function bcYearToNegativeYear (year) {
+  // Account for numerical difference between representations of BC years
+  // See: https://github.com/bendrucker/postgres-date/issues/5
+  return -(year - 1)
+}
+
+function is0To99 (num) {
+  return num >= 0 && num < 100
+}
diff --git a/server/node_modules/postgres-date/license b/server/node_modules/postgres-date/license
new file mode 100644
index 0000000000000000000000000000000000000000..25c624701389bab54c94982531ea34e8d1702ccf
--- /dev/null
+++ b/server/node_modules/postgres-date/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Ben Drucker <bvdrucker@gmail.com> (bendrucker.me)
+
+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.
diff --git a/server/node_modules/postgres-date/package.json b/server/node_modules/postgres-date/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..68b228a937248284811c27ed85aee4be6d46f5fb
--- /dev/null
+++ b/server/node_modules/postgres-date/package.json
@@ -0,0 +1,65 @@
+{
+  "_from": "postgres-date@~1.0.4",
+  "_id": "postgres-date@1.0.4",
+  "_inBundle": false,
+  "_integrity": "sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA==",
+  "_location": "/postgres-date",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "postgres-date@~1.0.4",
+    "name": "postgres-date",
+    "escapedName": "postgres-date",
+    "rawSpec": "~1.0.4",
+    "saveSpec": null,
+    "fetchSpec": "~1.0.4"
+  },
+  "_requiredBy": [
+    "/pg-types"
+  ],
+  "_resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.4.tgz",
+  "_shasum": "1c2728d62ef1bff49abdd35c1f86d4bdf118a728",
+  "_spec": "postgres-date@~1.0.4",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg-types",
+  "author": {
+    "name": "Ben Drucker",
+    "email": "bvdrucker@gmail.com",
+    "url": "bendrucker.me"
+  },
+  "bugs": {
+    "url": "https://github.com/bendrucker/postgres-date/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "Postgres date column parser",
+  "devDependencies": {
+    "standard": "^12.0.1",
+    "tape": "^4.0.0"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js",
+    "readme.md"
+  ],
+  "homepage": "https://github.com/bendrucker/postgres-date#readme",
+  "keywords": [
+    "postgres",
+    "date",
+    "parser"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "postgres-date",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/bendrucker/postgres-date.git"
+  },
+  "scripts": {
+    "test": "standard && tape test.js"
+  },
+  "version": "1.0.4"
+}
diff --git a/server/node_modules/postgres-date/readme.md b/server/node_modules/postgres-date/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..aeb7a5c0a9506ff42b7ab34ba2dee43f235be779
--- /dev/null
+++ b/server/node_modules/postgres-date/readme.md
@@ -0,0 +1,34 @@
+# postgres-date [![Build Status](https://travis-ci.org/bendrucker/postgres-date.svg?branch=master)](https://travis-ci.org/bendrucker/postgres-date) [![Greenkeeper badge](https://badges.greenkeeper.io/bendrucker/postgres-date.svg)](https://greenkeeper.io/)
+
+> Postgres date column parser
+
+
+## Install
+
+```
+$ npm install --save postgres-date
+```
+
+
+## Usage
+
+```js
+var parse = require('postgres-date')
+parse('2011-01-23 22:15:51Z')
+// => 2011-01-23T22:15:51.000Z
+```
+
+## API
+
+#### `parse(isoDate)` -> `date`
+
+##### isoDate
+
+*Required*  
+Type: `string`
+
+A date string from Postgres.
+
+## License
+
+MIT © [Ben Drucker](http://bendrucker.me)
diff --git a/server/node_modules/postgres-interval/index.d.ts b/server/node_modules/postgres-interval/index.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f82b4c3762b4e0c0d91ca242461a695d9dbd4949
--- /dev/null
+++ b/server/node_modules/postgres-interval/index.d.ts
@@ -0,0 +1,20 @@
+declare namespace PostgresInterval {
+  export interface IPostgresInterval {
+    years?: number;
+    months?: number;
+    days?: number;
+    hours?: number;
+    minutes?: number;
+    seconds?: number;
+    milliseconds?: number;
+
+    toPostgres(): string;
+
+    toISO(): string;
+    toISOString(): string;
+  }
+}
+
+declare function PostgresInterval(raw: string): PostgresInterval.IPostgresInterval;
+
+export = PostgresInterval;
diff --git a/server/node_modules/postgres-interval/index.js b/server/node_modules/postgres-interval/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..8ecca800af389b47fc7a1ebdaf0feb4e27f150a4
--- /dev/null
+++ b/server/node_modules/postgres-interval/index.js
@@ -0,0 +1,125 @@
+'use strict'
+
+var extend = require('xtend/mutable')
+
+module.exports = PostgresInterval
+
+function PostgresInterval (raw) {
+  if (!(this instanceof PostgresInterval)) {
+    return new PostgresInterval(raw)
+  }
+  extend(this, parse(raw))
+}
+var properties = ['seconds', 'minutes', 'hours', 'days', 'months', 'years']
+PostgresInterval.prototype.toPostgres = function () {
+  var filtered = properties.filter(this.hasOwnProperty, this)
+
+  // In addition to `properties`, we need to account for fractions of seconds.
+  if (this.milliseconds && filtered.indexOf('seconds') < 0) {
+    filtered.push('seconds')
+  }
+
+  if (filtered.length === 0) return '0'
+  return filtered
+    .map(function (property) {
+      var value = this[property] || 0
+
+      // Account for fractional part of seconds,
+      // remove trailing zeroes.
+      if (property === 'seconds' && this.milliseconds) {
+        value = (value + this.milliseconds / 1000).toFixed(6).replace(/\.?0+$/, '')
+      }
+
+      return value + ' ' + property
+    }, this)
+    .join(' ')
+}
+
+var propertiesISOEquivalent = {
+  years: 'Y',
+  months: 'M',
+  days: 'D',
+  hours: 'H',
+  minutes: 'M',
+  seconds: 'S'
+}
+var dateProperties = ['years', 'months', 'days']
+var timeProperties = ['hours', 'minutes', 'seconds']
+// according to ISO 8601
+PostgresInterval.prototype.toISOString = PostgresInterval.prototype.toISO = function () {
+  var datePart = dateProperties
+    .map(buildProperty, this)
+    .join('')
+
+  var timePart = timeProperties
+    .map(buildProperty, this)
+    .join('')
+
+  return 'P' + datePart + 'T' + timePart
+
+  function buildProperty (property) {
+    var value = this[property] || 0
+
+    // Account for fractional part of seconds,
+    // remove trailing zeroes.
+    if (property === 'seconds' && this.milliseconds) {
+      value = (value + this.milliseconds / 1000).toFixed(6).replace(/0+$/, '')
+    }
+
+    return value + propertiesISOEquivalent[property]
+  }
+}
+
+var NUMBER = '([+-]?\\d+)'
+var YEAR = NUMBER + '\\s+years?'
+var MONTH = NUMBER + '\\s+mons?'
+var DAY = NUMBER + '\\s+days?'
+var TIME = '([+-])?([\\d]*):(\\d\\d):(\\d\\d)\\.?(\\d{1,6})?'
+var INTERVAL = new RegExp([YEAR, MONTH, DAY, TIME].map(function (regexString) {
+  return '(' + regexString + ')?'
+})
+  .join('\\s*'))
+
+// Positions of values in regex match
+var positions = {
+  years: 2,
+  months: 4,
+  days: 6,
+  hours: 9,
+  minutes: 10,
+  seconds: 11,
+  milliseconds: 12
+}
+// We can use negative time
+var negatives = ['hours', 'minutes', 'seconds', 'milliseconds']
+
+function parseMilliseconds (fraction) {
+  // add omitted zeroes
+  var microseconds = fraction + '000000'.slice(fraction.length)
+  return parseInt(microseconds, 10) / 1000
+}
+
+function parse (interval) {
+  if (!interval) return {}
+  var matches = INTERVAL.exec(interval)
+  var isNegative = matches[8] === '-'
+  return Object.keys(positions)
+    .reduce(function (parsed, property) {
+      var position = positions[property]
+      var value = matches[position]
+      // no empty string
+      if (!value) return parsed
+      // milliseconds are actually microseconds (up to 6 digits)
+      // with omitted trailing zeroes.
+      value = property === 'milliseconds'
+        ? parseMilliseconds(value)
+        : parseInt(value, 10)
+      // no zeros
+      if (!value) return parsed
+      if (isNegative && ~negatives.indexOf(property)) {
+        value *= -1
+      }
+      parsed[property] = value
+      return parsed
+    }, {})
+}
diff --git a/server/node_modules/postgres-interval/license b/server/node_modules/postgres-interval/license
new file mode 100644
index 0000000000000000000000000000000000000000..25c624701389bab54c94982531ea34e8d1702ccf
--- /dev/null
+++ b/server/node_modules/postgres-interval/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Ben Drucker <bvdrucker@gmail.com> (bendrucker.me)
+
+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.
diff --git a/server/node_modules/postgres-interval/package.json b/server/node_modules/postgres-interval/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..12ce61152bc2056db924cd537b41c1edd277249b
--- /dev/null
+++ b/server/node_modules/postgres-interval/package.json
@@ -0,0 +1,68 @@
+{
+  "_from": "postgres-interval@^1.1.0",
+  "_id": "postgres-interval@1.2.0",
+  "_inBundle": false,
+  "_integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
+  "_location": "/postgres-interval",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "postgres-interval@^1.1.0",
+    "name": "postgres-interval",
+    "escapedName": "postgres-interval",
+    "rawSpec": "^1.1.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.1.0"
+  },
+  "_requiredBy": [
+    "/pg-types"
+  ],
+  "_resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
+  "_shasum": "b460c82cb1587507788819a06aa0fffdb3544695",
+  "_spec": "postgres-interval@^1.1.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pg-types",
+  "author": {
+    "name": "Ben Drucker",
+    "email": "bvdrucker@gmail.com",
+    "url": "bendrucker.me"
+  },
+  "bugs": {
+    "url": "https://github.com/bendrucker/postgres-interval/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "xtend": "^4.0.0"
+  },
+  "deprecated": false,
+  "description": "Parse Postgres interval columns",
+  "devDependencies": {
+    "standard": "^12.0.1",
+    "tape": "^4.0.0"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js",
+    "index.d.ts",
+    "readme.md"
+  ],
+  "homepage": "https://github.com/bendrucker/postgres-interval#readme",
+  "keywords": [
+    "postgres",
+    "interval",
+    "parser"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "postgres-interval",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/bendrucker/postgres-interval.git"
+  },
+  "scripts": {
+    "test": "standard && tape test.js"
+  },
+  "version": "1.2.0"
+}
diff --git a/server/node_modules/postgres-interval/readme.md b/server/node_modules/postgres-interval/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..53cda4ade18c8f47aeb411c0659e0ea204ce1992
--- /dev/null
+++ b/server/node_modules/postgres-interval/readme.md
@@ -0,0 +1,48 @@
+# postgres-interval [![Build Status](https://travis-ci.org/bendrucker/postgres-interval.svg?branch=master)](https://travis-ci.org/bendrucker/postgres-interval) [![Greenkeeper badge](https://badges.greenkeeper.io/bendrucker/postgres-interval.svg)](https://greenkeeper.io/)
+
+> Parse Postgres interval columns
+
+
+## Install
+
+```
+$ npm install --save postgres-interval
+```
+
+
+## Usage
+
+```js
+var parse = require('postgres-interval')
+var interval = parse('01:02:03')
+//=> {hours: 1, minutes: 2, seconds: 3}
+interval.toPostgres()
+// 3 seconds 2 minutes 1 hours
+interval.toISO()
+// P0Y0M0DT1H2M3S
+```
+
+## API
+
+#### `parse(pgInterval)` -> `interval`
+
+##### pgInterval
+
+*Required*  
+Type: `string`
+
+A Postgres interval string.
+
+#### `interval.toPostgres()` -> `string`
+
+Returns an interval string. This allows the interval object to be passed into prepared statements.
+
+#### `interval.toISOString()` -> `string`
+
+Returns an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601#Durations) compliant string.
+
+Also available as `interval.toISO()` for backwards compatibility.
+
+## License
+
+MIT © [Ben Drucker](http://bendrucker.me)
diff --git a/server/node_modules/ramda/CHANGELOG.md b/server/node_modules/ramda/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..cf75f9a1233bf7382d0141a3dcdf05457b3ed504
--- /dev/null
+++ b/server/node_modules/ramda/CHANGELOG.md
@@ -0,0 +1,6 @@
+# Changelog
+
+See the [upgrade guides][1].
+
+
+[1]: https://github.com/ramda/ramda/issues?q=label%3A%22upgrade+guide%22
diff --git a/server/node_modules/ramda/LICENSE.txt b/server/node_modules/ramda/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7eb3353f74ac9ff78374576ca2acd7e0db98a535
--- /dev/null
+++ b/server/node_modules/ramda/LICENSE.txt
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013-2018 Scott Sauyet and Michael Hurley
+
+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.
diff --git a/server/node_modules/ramda/README.md b/server/node_modules/ramda/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..37ba888dcaee119e5ecf29e76145786c738df7d4
--- /dev/null
+++ b/server/node_modules/ramda/README.md
@@ -0,0 +1,247 @@
+Ramda
+=============
+
+A practical functional library for JavaScript programmers.
+
+[![Build Status](https://travis-ci.org/ramda/ramda.svg?branch=master)](https://travis-ci.org/ramda/ramda)
+[![npm module](https://badge.fury.io/js/ramda.svg)](https://www.npmjs.org/package/ramda)
+[![dependencies](https://david-dm.org/ramda/ramda.svg)](https://david-dm.org/ramda/ramda)
+[![Gitter](https://badges.gitter.im/Join_Chat.svg)](https://gitter.im/ramda/ramda?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+
+
+Why Ramda?
+----------
+
+<img src="https://ramdajs.com/ramdaFilled_200x235.png" 
+     width="170" height="190" align="right" hspace="12" />
+
+There are already several excellent libraries with a functional flavor. Typically, they are meant to be general-purpose toolkits, suitable for working in multiple paradigms. Ramda has a more focused goal. We wanted a library designed specifically for a functional programming style, one that makes it easy to create functional pipelines, one that never mutates user data. 
+
+
+
+What's Different?
+-----------------
+
+The primary distinguishing features of Ramda are:
+
+* Ramda emphasizes a purer functional style. Immutability and side-effect free functions 
+  are at the heart of its design philosophy. This can help you get the job done with simple, 
+  elegant code.
+
+* Ramda functions are automatically curried. This allows you to easily build up new functions 
+  from old ones simply by not supplying the final parameters.
+
+* The parameters to Ramda functions are arranged to make it convenient for currying. The data 
+  to be operated on is generally supplied last.
+
+The last two points together make it very easy to build functions as sequences of simpler functions, each of which transforms the data and passes it along to the next. Ramda is designed to support this style of coding.
+
+
+
+Introductions
+-------------
+
+* [Introducing Ramda](http://buzzdecafe.github.io/code/2014/05/16/introducing-ramda) by Buzz de Cafe
+* [Why Ramda?](http://fr.umio.us/why-ramda/) by Scott Sauyet
+* [Favoring Curry](http://fr.umio.us/favoring-curry/) by Scott Sauyet
+* [Why Curry Helps](https://hughfdjackson.com/javascript/why-curry-helps/) by Hugh Jackson
+* [Hey Underscore, You're Doing It Wrong!](https://www.youtube.com/watch?v=m3svKOdZijA&app=desktop) by Brian Lonsdorf
+* [Thinking in Ramda](http://randycoulman.com/blog/categories/thinking-in-ramda) by Randy Coulman
+
+
+
+Philosophy
+----------
+Using Ramda should feel much like just using JavaScript.
+It is practical, functional JavaScript. We're not introducing
+lambda expressions in strings, we're not borrowing consed 
+lists, we're not porting over all of the Clojure functions.
+
+Our basic data structures are plain JavaScript objects, and our
+usual collections are JavaScript arrays. We also keep other
+native features of JavaScript, such as functions as objects
+with properties.
+
+Functional programming is in good part about immutable objects and 
+side-effect free functions. While Ramda does not *enforce* this, it
+enables such style to be as frictionless as possible.
+
+We aim for an implementation both clean and elegant, but the API is king.
+We sacrifice a great deal of implementation elegance for even a slightly
+cleaner API.
+
+Last but not least, Ramda strives for performance. A reliable and quick
+implementation wins over any notions of functional purity.
+
+
+
+Installation
+------------
+
+To use with node:
+
+```bash
+$ npm install ramda
+```
+
+Then in the console:
+
+```javascript
+const R = require('ramda');
+```
+
+To use directly in the browser:
+
+```html
+<script src="path/to/yourCopyOf/ramda.js"></script>
+```
+
+or the minified version:
+
+```html
+<script src="path/to/yourCopyOf/ramda.min.js"></script>
+```
+
+or from a CDN, either cdnjs:
+
+```html
+<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
+```
+
+or one of the below links from [jsDelivr](http://jsdelivr.com):
+
+```html
+<script src="//cdn.jsdelivr.net/npm/ramda@0.25.0/dist/ramda.min.js"></script>
+<script src="//cdn.jsdelivr.net/npm/ramda@0.25/dist/ramda.min.js"></script>
+<script src="//cdn.jsdelivr.net/npm/ramda@latest/dist/ramda.min.js"></script>
+```
+
+(note that using `latest` is taking a significant risk that ramda API changes could break your code.)
+
+These script tags add the variable `R` on the browser's global scope.
+
+Or you can inject ramda into virtually any unsuspecting website using [the bookmarklet](https://github.com/ramda/ramda/blob/master/BOOKMARKLET.md).
+
+**Note for versions > 0.25**
+Ramda versions > 0.25 don't have a default export.
+So instead of `import R from 'ramda';`, one has to use `import * as R from 'ramda';`
+Or better yet, import only the required functions via `import { functionName } from 'ramda';`
+
+### Build
+
+`npm run build` creates `es`, `src` directories and updates both __dist/ramda.js__ and __dist/ramda.min.js__
+
+#### Partial Builds
+
+It is possible to build Ramda with a subset of the functionality to reduce its file size. Ramda's build system supports this with command line flags. For example if you're using `R.compose`, `R.reduce`, and `R.filter` you can create a partial build with:
+
+    npm run --silent partial-build compose reduce filter > dist/ramda.custom.js
+
+This requires having Node/io.js installed and ramda's dependencies installed (just use `npm install` before running partial build). 
+
+
+
+Documentation
+-------------
+
+Please review the [API documentation](https://ramdajs.com/docs/).
+
+Also available is our [Cookbook](https://github.com/ramda/ramda/wiki/Cookbook) of functions built from Ramda that you may find useful.
+
+
+The Name
+--------
+
+Ok, so we like sheep.  That's all.  It's a short name, not already 
+taken.  It could as easily have been `eweda`, but then we would be 
+forced to say _eweda lamb!_, and no one wants that.  For non-English 
+speakers, lambs are baby sheep, ewes are female sheep, and rams are male 
+sheep.  So perhaps ramda is a grown-up lambda... but probably not.
+
+
+
+
+Running The Test Suite
+----------------------
+
+**Console:**
+
+To run the test suite from the console, you need to have `mocha` installed:
+
+    npm install -g mocha
+
+Then from the root of the project, you can just call
+
+    mocha
+
+Alternately, if you've installed the dependencies, via:
+
+    npm install
+
+then you can run the tests (and get detailed output) by running:
+
+    npm test
+
+**Browser:**
+
+You can use [testem](https://github.com/airportyh/testem) to
+test across different browsers (or even headlessly), with livereloading of
+tests. Install testem (`npm install -g testem`) and run `testem`. Open the
+link provided in your browser and you will see the results in your terminal.
+
+If you have _PhantomJS_ installed, you can run `testem -l phantomjs` to run the
+tests completely headlessly.
+
+
+Usage
+-----------------
+
+For `v0.25` and up, import the whole library or pick ES modules directly from the library:
+
+```js
+import * as R from 'ramda'
+
+const {identity} = R
+R.map(identity, [1, 2, 3])
+```
+
+Destructuring imports from ramda *does not necessarily prevent importing the entire library*. You can manually cherry-pick methods like the following, which would only grab the parts necessary for `identity` to work:
+
+```js
+import identity from 'ramda/src/identity'
+
+identity()
+```
+
+Manually cherry picking methods is cumbersome, however. Most bundlers like Webpack and Rollup offer tree-shaking as a way to drop unused Ramda code and reduce bundle size, but their performance varies, discussed [here](https://github.com/scabbiaza/ramda-webpack-tree-shaking-examples). Here is a summary of the optimal setup based on what technology you are using:
+
+1. Webpack + Babel - use [`babel-plugin-ramda`](https://github.com/megawac/babel-plugin-ramda) to automatically cherry pick methods. Discussion [here](http://www.andrewsouthpaw.com/2018/01/19/ramda-tree-shaking-not-supported-out-of-the-box/), example [here](https://github.com/AndrewSouthpaw/ramda-webpack-tree-shaking-examples/blob/master/07-webpack-babel-plugin-ramda/package.json)
+1. Webpack only - use `UglifyJS` plugin for treeshaking along with the `ModuleConcatenationPlugin`. Discussion [here](https://github.com/ramda/ramda/issues/2355), with an example setup [here](https://github.com/scabbiaza/ramda-webpack-tree-shaking-examples/blob/master/06-webpack-scope-hoisted/webpack.config.js)
+1. Rollup - does a fine job properly treeshaking, no special work needed; example [here](https://github.com/scabbiaza/ramda-webpack-tree-shaking-examples/blob/master/07-rollup-ramda-tree-shaking/rollup.config.js)
+
+
+Typings
+-----------------
+
+- [TypeScript](https://github.com/types/npm-ramda/)
+- [Flow](https://github.com/flowtype/flow-typed/tree/master/definitions/npm/ramda_v0.x.x)
+
+
+
+
+Translations
+-----------------
+
+- [Chinese(中文)](http://ramda.cn/)
+- [Ukrainian(Українська)](https://github.com/ivanzusko/ramda)
+- [Russian(Русский)](https://github.com/Guck111/ramda)
+
+
+
+Acknowledgements
+-----------------
+
+Thanks to [J. C. Phillipps](http://www.jcphillipps.com) for the Ramda logo.
+Ramda logo artwork &copy; 2014 J. C. Phillipps. Licensed Creative Commons 
+[CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/).
diff --git a/server/node_modules/ramda/dist/ramda.js b/server/node_modules/ramda/dist/ramda.js
new file mode 100644
index 0000000000000000000000000000000000000000..a9ee868253bf462f1a4a680fdf6677b71ece5ae6
--- /dev/null
+++ b/server/node_modules/ramda/dist/ramda.js
@@ -0,0 +1,9643 @@
+//  Ramda v0.26.1
+//  https://github.com/ramda/ramda
+//  (c) 2013-2018 Scott Sauyet, Michael Hurley, and David Chambers
+//  Ramda may be freely distributed under the MIT license.
+
+(function (global, factory) {
+	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+	typeof define === 'function' && define.amd ? define(['exports'], factory) :
+	(factory((global.R = {})));
+}(this, (function (exports) { 'use strict';
+
+/**
+ * A function that always returns `false`. Any passed in parameters are ignored.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig * -> Boolean
+ * @param {*}
+ * @return {Boolean}
+ * @see R.T
+ * @example
+ *
+ *      R.F(); //=> false
+ */
+var F = function() {return false;};
+
+/**
+ * A function that always returns `true`. Any passed in parameters are ignored.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig * -> Boolean
+ * @param {*}
+ * @return {Boolean}
+ * @see R.F
+ * @example
+ *
+ *      R.T(); //=> true
+ */
+var T = function() {return true;};
+
+/**
+ * A special placeholder value used to specify "gaps" within curried functions,
+ * allowing partial application of any combination of arguments, regardless of
+ * their positions.
+ *
+ * If `g` is a curried ternary function and `_` is `R.__`, the following are
+ * equivalent:
+ *
+ *   - `g(1, 2, 3)`
+ *   - `g(_, 2, 3)(1)`
+ *   - `g(_, _, 3)(1)(2)`
+ *   - `g(_, _, 3)(1, 2)`
+ *   - `g(_, 2, _)(1, 3)`
+ *   - `g(_, 2)(1)(3)`
+ *   - `g(_, 2)(1, 3)`
+ *   - `g(_, 2)(_, 3)(1)`
+ *
+ * @name __
+ * @constant
+ * @memberOf R
+ * @since v0.6.0
+ * @category Function
+ * @example
+ *
+ *      const greet = R.replace('{name}', R.__, 'Hello, {name}!');
+ *      greet('Alice'); //=> 'Hello, Alice!'
+ */
+var __ = {'@@functional/placeholder': true};
+
+function _isPlaceholder(a) {
+  return a != null &&
+         typeof a === 'object' &&
+         a['@@functional/placeholder'] === true;
+}
+
+/**
+ * Optimized internal one-arity curry function.
+ *
+ * @private
+ * @category Function
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+function _curry1(fn) {
+  return function f1(a) {
+    if (arguments.length === 0 || _isPlaceholder(a)) {
+      return f1;
+    } else {
+      return fn.apply(this, arguments);
+    }
+  };
+}
+
+/**
+ * Optimized internal two-arity curry function.
+ *
+ * @private
+ * @category Function
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+function _curry2(fn) {
+  return function f2(a, b) {
+    switch (arguments.length) {
+      case 0:
+        return f2;
+      case 1:
+        return _isPlaceholder(a)
+          ? f2
+          : _curry1(function(_b) { return fn(a, _b); });
+      default:
+        return _isPlaceholder(a) && _isPlaceholder(b)
+          ? f2
+          : _isPlaceholder(a)
+            ? _curry1(function(_a) { return fn(_a, b); })
+            : _isPlaceholder(b)
+              ? _curry1(function(_b) { return fn(a, _b); })
+              : fn(a, b);
+    }
+  };
+}
+
+/**
+ * Adds two values.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a
+ * @param {Number} b
+ * @return {Number}
+ * @see R.subtract
+ * @example
+ *
+ *      R.add(2, 3);       //=>  5
+ *      R.add(7)(10);      //=> 17
+ */
+var add = _curry2(function add(a, b) {
+  return Number(a) + Number(b);
+});
+
+/**
+ * Private `concat` function to merge two array-like objects.
+ *
+ * @private
+ * @param {Array|Arguments} [set1=[]] An array-like object.
+ * @param {Array|Arguments} [set2=[]] An array-like object.
+ * @return {Array} A new, merged array.
+ * @example
+ *
+ *      _concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3]
+ */
+function _concat(set1, set2) {
+  set1 = set1 || [];
+  set2 = set2 || [];
+  var idx;
+  var len1 = set1.length;
+  var len2 = set2.length;
+  var result = [];
+
+  idx = 0;
+  while (idx < len1) {
+    result[result.length] = set1[idx];
+    idx += 1;
+  }
+  idx = 0;
+  while (idx < len2) {
+    result[result.length] = set2[idx];
+    idx += 1;
+  }
+  return result;
+}
+
+function _arity(n, fn) {
+  /* eslint-disable no-unused-vars */
+  switch (n) {
+    case 0: return function() { return fn.apply(this, arguments); };
+    case 1: return function(a0) { return fn.apply(this, arguments); };
+    case 2: return function(a0, a1) { return fn.apply(this, arguments); };
+    case 3: return function(a0, a1, a2) { return fn.apply(this, arguments); };
+    case 4: return function(a0, a1, a2, a3) { return fn.apply(this, arguments); };
+    case 5: return function(a0, a1, a2, a3, a4) { return fn.apply(this, arguments); };
+    case 6: return function(a0, a1, a2, a3, a4, a5) { return fn.apply(this, arguments); };
+    case 7: return function(a0, a1, a2, a3, a4, a5, a6) { return fn.apply(this, arguments); };
+    case 8: return function(a0, a1, a2, a3, a4, a5, a6, a7) { return fn.apply(this, arguments); };
+    case 9: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8) { return fn.apply(this, arguments); };
+    case 10: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { return fn.apply(this, arguments); };
+    default: throw new Error('First argument to _arity must be a non-negative integer no greater than ten');
+  }
+}
+
+/**
+ * Internal curryN function.
+ *
+ * @private
+ * @category Function
+ * @param {Number} length The arity of the curried function.
+ * @param {Array} received An array of arguments received thus far.
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+function _curryN(length, received, fn) {
+  return function() {
+    var combined = [];
+    var argsIdx = 0;
+    var left = length;
+    var combinedIdx = 0;
+    while (combinedIdx < received.length || argsIdx < arguments.length) {
+      var result;
+      if (combinedIdx < received.length &&
+          (!_isPlaceholder(received[combinedIdx]) ||
+           argsIdx >= arguments.length)) {
+        result = received[combinedIdx];
+      } else {
+        result = arguments[argsIdx];
+        argsIdx += 1;
+      }
+      combined[combinedIdx] = result;
+      if (!_isPlaceholder(result)) {
+        left -= 1;
+      }
+      combinedIdx += 1;
+    }
+    return left <= 0
+      ? fn.apply(this, combined)
+      : _arity(left, _curryN(length, combined, fn));
+  };
+}
+
+/**
+ * Returns a curried equivalent of the provided function, with the specified
+ * arity. The curried function has two unusual capabilities. First, its
+ * arguments needn't be provided one at a time. If `g` is `R.curryN(3, f)`, the
+ * following are equivalent:
+ *
+ *   - `g(1)(2)(3)`
+ *   - `g(1)(2, 3)`
+ *   - `g(1, 2)(3)`
+ *   - `g(1, 2, 3)`
+ *
+ * Secondly, the special placeholder value [`R.__`](#__) may be used to specify
+ * "gaps", allowing partial application of any combination of arguments,
+ * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__),
+ * the following are equivalent:
+ *
+ *   - `g(1, 2, 3)`
+ *   - `g(_, 2, 3)(1)`
+ *   - `g(_, _, 3)(1)(2)`
+ *   - `g(_, _, 3)(1, 2)`
+ *   - `g(_, 2)(1)(3)`
+ *   - `g(_, 2)(1, 3)`
+ *   - `g(_, 2)(_, 3)(1)`
+ *
+ * @func
+ * @memberOf R
+ * @since v0.5.0
+ * @category Function
+ * @sig Number -> (* -> a) -> (* -> a)
+ * @param {Number} length The arity for the returned function.
+ * @param {Function} fn The function to curry.
+ * @return {Function} A new, curried function.
+ * @see R.curry
+ * @example
+ *
+ *      const sumArgs = (...args) => R.sum(args);
+ *
+ *      const curriedAddFourNumbers = R.curryN(4, sumArgs);
+ *      const f = curriedAddFourNumbers(1, 2);
+ *      const g = f(3);
+ *      g(4); //=> 10
+ */
+var curryN = _curry2(function curryN(length, fn) {
+  if (length === 1) {
+    return _curry1(fn);
+  }
+  return _arity(length, _curryN(length, [], fn));
+});
+
+/**
+ * Creates a new list iteration function from an existing one by adding two new
+ * parameters to its callback function: the current index, and the entire list.
+ *
+ * This would turn, for instance, [`R.map`](#map) function into one that
+ * more closely resembles `Array.prototype.map`. Note that this will only work
+ * for functions in which the iteration callback function is the first
+ * parameter, and where the list is the last parameter. (This latter might be
+ * unimportant if the list parameter is not used.)
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category Function
+ * @category List
+ * @sig ((a ... -> b) ... -> [a] -> *) -> ((a ..., Int, [a] -> b) ... -> [a] -> *)
+ * @param {Function} fn A list iteration function that does not pass index or list to its callback
+ * @return {Function} An altered list iteration function that passes (item, index, list) to its callback
+ * @example
+ *
+ *      const mapIndexed = R.addIndex(R.map);
+ *      mapIndexed((val, idx) => idx + '-' + val, ['f', 'o', 'o', 'b', 'a', 'r']);
+ *      //=> ['0-f', '1-o', '2-o', '3-b', '4-a', '5-r']
+ */
+var addIndex = _curry1(function addIndex(fn) {
+  return curryN(fn.length, function() {
+    var idx = 0;
+    var origFn = arguments[0];
+    var list = arguments[arguments.length - 1];
+    var args = Array.prototype.slice.call(arguments, 0);
+    args[0] = function() {
+      var result = origFn.apply(this, _concat(arguments, [idx, list]));
+      idx += 1;
+      return result;
+    };
+    return fn.apply(this, args);
+  });
+});
+
+/**
+ * Optimized internal three-arity curry function.
+ *
+ * @private
+ * @category Function
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+function _curry3(fn) {
+  return function f3(a, b, c) {
+    switch (arguments.length) {
+      case 0:
+        return f3;
+      case 1:
+        return _isPlaceholder(a)
+          ? f3
+          : _curry2(function(_b, _c) { return fn(a, _b, _c); });
+      case 2:
+        return _isPlaceholder(a) && _isPlaceholder(b)
+          ? f3
+          : _isPlaceholder(a)
+            ? _curry2(function(_a, _c) { return fn(_a, b, _c); })
+            : _isPlaceholder(b)
+              ? _curry2(function(_b, _c) { return fn(a, _b, _c); })
+              : _curry1(function(_c) { return fn(a, b, _c); });
+      default:
+        return _isPlaceholder(a) && _isPlaceholder(b) && _isPlaceholder(c)
+          ? f3
+          : _isPlaceholder(a) && _isPlaceholder(b)
+            ? _curry2(function(_a, _b) { return fn(_a, _b, c); })
+            : _isPlaceholder(a) && _isPlaceholder(c)
+              ? _curry2(function(_a, _c) { return fn(_a, b, _c); })
+              : _isPlaceholder(b) && _isPlaceholder(c)
+                ? _curry2(function(_b, _c) { return fn(a, _b, _c); })
+                : _isPlaceholder(a)
+                  ? _curry1(function(_a) { return fn(_a, b, c); })
+                  : _isPlaceholder(b)
+                    ? _curry1(function(_b) { return fn(a, _b, c); })
+                    : _isPlaceholder(c)
+                      ? _curry1(function(_c) { return fn(a, b, _c); })
+                      : fn(a, b, c);
+    }
+  };
+}
+
+/**
+ * Applies a function to the value at the given index of an array, returning a
+ * new copy of the array with the element at the given index replaced with the
+ * result of the function application.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig Number -> (a -> a) -> [a] -> [a]
+ * @param {Number} idx The index.
+ * @param {Function} fn The function to apply.
+ * @param {Array|Arguments} list An array-like object whose value
+ *        at the supplied index will be replaced.
+ * @return {Array} A copy of the supplied array-like object with
+ *         the element at index `idx` replaced with the value
+ *         returned by applying `fn` to the existing element.
+ * @see R.update
+ * @example
+ *
+ *      R.adjust(1, R.toUpper, ['a', 'b', 'c', 'd']);      //=> ['a', 'B', 'c', 'd']
+ *      R.adjust(-1, R.toUpper, ['a', 'b', 'c', 'd']);     //=> ['a', 'b', 'c', 'D']
+ * @symb R.adjust(-1, f, [a, b]) = [a, f(b)]
+ * @symb R.adjust(0, f, [a, b]) = [f(a), b]
+ */
+var adjust = _curry3(function adjust(idx, fn, list) {
+  if (idx >= list.length || idx < -list.length) {
+    return list;
+  }
+  var start = idx < 0 ? list.length : 0;
+  var _idx = start + idx;
+  var _list = _concat(list);
+  _list[_idx] = fn(list[_idx]);
+  return _list;
+});
+
+/**
+ * Tests whether or not an object is an array.
+ *
+ * @private
+ * @param {*} val The object to test.
+ * @return {Boolean} `true` if `val` is an array, `false` otherwise.
+ * @example
+ *
+ *      _isArray([]); //=> true
+ *      _isArray(null); //=> false
+ *      _isArray({}); //=> false
+ */
+var _isArray = Array.isArray || function _isArray(val) {
+  return (val != null &&
+          val.length >= 0 &&
+          Object.prototype.toString.call(val) === '[object Array]');
+};
+
+function _isTransformer(obj) {
+  return obj != null && typeof obj['@@transducer/step'] === 'function';
+}
+
+/**
+ * Returns a function that dispatches with different strategies based on the
+ * object in list position (last argument). If it is an array, executes [fn].
+ * Otherwise, if it has a function with one of the given method names, it will
+ * execute that function (functor case). Otherwise, if it is a transformer,
+ * uses transducer [xf] to return a new transformer (transducer case).
+ * Otherwise, it will default to executing [fn].
+ *
+ * @private
+ * @param {Array} methodNames properties to check for a custom implementation
+ * @param {Function} xf transducer to initialize if object is transformer
+ * @param {Function} fn default ramda implementation
+ * @return {Function} A function that dispatches on object in list position
+ */
+function _dispatchable(methodNames, xf, fn) {
+  return function() {
+    if (arguments.length === 0) {
+      return fn();
+    }
+    var args = Array.prototype.slice.call(arguments, 0);
+    var obj = args.pop();
+    if (!_isArray(obj)) {
+      var idx = 0;
+      while (idx < methodNames.length) {
+        if (typeof obj[methodNames[idx]] === 'function') {
+          return obj[methodNames[idx]].apply(obj, args);
+        }
+        idx += 1;
+      }
+      if (_isTransformer(obj)) {
+        var transducer = xf.apply(null, args);
+        return transducer(obj);
+      }
+    }
+    return fn.apply(this, arguments);
+  };
+}
+
+function _reduced(x) {
+  return x && x['@@transducer/reduced'] ? x :
+    {
+      '@@transducer/value': x,
+      '@@transducer/reduced': true
+    };
+}
+
+var _xfBase = {
+  init: function() {
+    return this.xf['@@transducer/init']();
+  },
+  result: function(result) {
+    return this.xf['@@transducer/result'](result);
+  }
+};
+
+function XAll(f, xf) {
+  this.xf = xf;
+  this.f = f;
+  this.all = true;
+}
+XAll.prototype['@@transducer/init'] = _xfBase.init;
+XAll.prototype['@@transducer/result'] = function(result) {
+  if (this.all) {
+    result = this.xf['@@transducer/step'](result, true);
+  }
+  return this.xf['@@transducer/result'](result);
+};
+XAll.prototype['@@transducer/step'] = function(result, input) {
+  if (!this.f(input)) {
+    this.all = false;
+    result = _reduced(this.xf['@@transducer/step'](result, false));
+  }
+  return result;
+};
+
+var _xall = _curry2(function _xall(f, xf) { return new XAll(f, xf); });
+
+/**
+ * Returns `true` if all elements of the list match the predicate, `false` if
+ * there are any that don't.
+ *
+ * Dispatches to the `all` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Boolean
+ * @param {Function} fn The predicate function.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if the predicate is satisfied by every element, `false`
+ *         otherwise.
+ * @see R.any, R.none, R.transduce
+ * @example
+ *
+ *      const equals3 = R.equals(3);
+ *      R.all(equals3)([3, 3, 3, 3]); //=> true
+ *      R.all(equals3)([3, 3, 1, 3]); //=> false
+ */
+var all = _curry2(_dispatchable(['all'], _xall, function all(fn, list) {
+  var idx = 0;
+  while (idx < list.length) {
+    if (!fn(list[idx])) {
+      return false;
+    }
+    idx += 1;
+  }
+  return true;
+}));
+
+/**
+ * Returns the larger of its two arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> a
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.maxBy, R.min
+ * @example
+ *
+ *      R.max(789, 123); //=> 789
+ *      R.max('a', 'b'); //=> 'b'
+ */
+var max = _curry2(function max(a, b) { return b > a ? b : a; });
+
+function _map(fn, functor) {
+  var idx = 0;
+  var len = functor.length;
+  var result = Array(len);
+  while (idx < len) {
+    result[idx] = fn(functor[idx]);
+    idx += 1;
+  }
+  return result;
+}
+
+function _isString(x) {
+  return Object.prototype.toString.call(x) === '[object String]';
+}
+
+/**
+ * Tests whether or not an object is similar to an array.
+ *
+ * @private
+ * @category Type
+ * @category List
+ * @sig * -> Boolean
+ * @param {*} x The object to test.
+ * @return {Boolean} `true` if `x` has a numeric length property and extreme indices defined; `false` otherwise.
+ * @example
+ *
+ *      _isArrayLike([]); //=> true
+ *      _isArrayLike(true); //=> false
+ *      _isArrayLike({}); //=> false
+ *      _isArrayLike({length: 10}); //=> false
+ *      _isArrayLike({0: 'zero', 9: 'nine', length: 10}); //=> true
+ */
+var _isArrayLike = _curry1(function isArrayLike(x) {
+  if (_isArray(x)) { return true; }
+  if (!x) { return false; }
+  if (typeof x !== 'object') { return false; }
+  if (_isString(x)) { return false; }
+  if (x.nodeType === 1) { return !!x.length; }
+  if (x.length === 0) { return true; }
+  if (x.length > 0) {
+    return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1);
+  }
+  return false;
+});
+
+function XWrap(fn) {
+  this.f = fn;
+}
+XWrap.prototype['@@transducer/init'] = function() {
+  throw new Error('init not implemented on XWrap');
+};
+XWrap.prototype['@@transducer/result'] = function(acc) { return acc; };
+XWrap.prototype['@@transducer/step'] = function(acc, x) {
+  return this.f(acc, x);
+};
+
+function _xwrap(fn) { return new XWrap(fn); }
+
+/**
+ * Creates a function that is bound to a context.
+ * Note: `R.bind` does not provide the additional argument-binding capabilities of
+ * [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category Function
+ * @category Object
+ * @sig (* -> *) -> {*} -> (* -> *)
+ * @param {Function} fn The function to bind to context
+ * @param {Object} thisObj The context to bind `fn` to
+ * @return {Function} A function that will execute in the context of `thisObj`.
+ * @see R.partial
+ * @example
+ *
+ *      const log = R.bind(console.log, console);
+ *      R.pipe(R.assoc('a', 2), R.tap(log), R.assoc('a', 3))({a: 1}); //=> {a: 3}
+ *      // logs {a: 2}
+ * @symb R.bind(f, o)(a, b) = f.call(o, a, b)
+ */
+var bind = _curry2(function bind(fn, thisObj) {
+  return _arity(fn.length, function() {
+    return fn.apply(thisObj, arguments);
+  });
+});
+
+function _arrayReduce(xf, acc, list) {
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    acc = xf['@@transducer/step'](acc, list[idx]);
+    if (acc && acc['@@transducer/reduced']) {
+      acc = acc['@@transducer/value'];
+      break;
+    }
+    idx += 1;
+  }
+  return xf['@@transducer/result'](acc);
+}
+
+function _iterableReduce(xf, acc, iter) {
+  var step = iter.next();
+  while (!step.done) {
+    acc = xf['@@transducer/step'](acc, step.value);
+    if (acc && acc['@@transducer/reduced']) {
+      acc = acc['@@transducer/value'];
+      break;
+    }
+    step = iter.next();
+  }
+  return xf['@@transducer/result'](acc);
+}
+
+function _methodReduce(xf, acc, obj, methodName) {
+  return xf['@@transducer/result'](obj[methodName](bind(xf['@@transducer/step'], xf), acc));
+}
+
+var symIterator = (typeof Symbol !== 'undefined') ? Symbol.iterator : '@@iterator';
+
+function _reduce(fn, acc, list) {
+  if (typeof fn === 'function') {
+    fn = _xwrap(fn);
+  }
+  if (_isArrayLike(list)) {
+    return _arrayReduce(fn, acc, list);
+  }
+  if (typeof list['fantasy-land/reduce'] === 'function') {
+    return _methodReduce(fn, acc, list, 'fantasy-land/reduce');
+  }
+  if (list[symIterator] != null) {
+    return _iterableReduce(fn, acc, list[symIterator]());
+  }
+  if (typeof list.next === 'function') {
+    return _iterableReduce(fn, acc, list);
+  }
+  if (typeof list.reduce === 'function') {
+    return _methodReduce(fn, acc, list, 'reduce');
+  }
+
+  throw new TypeError('reduce: list must be array or iterable');
+}
+
+function XMap(f, xf) {
+  this.xf = xf;
+  this.f = f;
+}
+XMap.prototype['@@transducer/init'] = _xfBase.init;
+XMap.prototype['@@transducer/result'] = _xfBase.result;
+XMap.prototype['@@transducer/step'] = function(result, input) {
+  return this.xf['@@transducer/step'](result, this.f(input));
+};
+
+var _xmap = _curry2(function _xmap(f, xf) { return new XMap(f, xf); });
+
+function _has(prop, obj) {
+  return Object.prototype.hasOwnProperty.call(obj, prop);
+}
+
+var toString = Object.prototype.toString;
+var _isArguments = (function() {
+  return toString.call(arguments) === '[object Arguments]' ?
+    function _isArguments(x) { return toString.call(x) === '[object Arguments]'; } :
+    function _isArguments(x) { return _has('callee', x); };
+}());
+
+// cover IE < 9 keys issues
+var hasEnumBug = !({toString: null}).propertyIsEnumerable('toString');
+var nonEnumerableProps = [
+  'constructor', 'valueOf', 'isPrototypeOf', 'toString',
+  'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'
+];
+// Safari bug
+var hasArgsEnumBug = (function() {
+  'use strict';
+  return arguments.propertyIsEnumerable('length');
+}());
+
+var contains = function contains(list, item) {
+  var idx = 0;
+  while (idx < list.length) {
+    if (list[idx] === item) {
+      return true;
+    }
+    idx += 1;
+  }
+  return false;
+};
+
+/**
+ * Returns a list containing the names of all the enumerable own properties of
+ * the supplied object.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {k: v} -> [k]
+ * @param {Object} obj The object to extract properties from
+ * @return {Array} An array of the object's own properties.
+ * @see R.keysIn, R.values
+ * @example
+ *
+ *      R.keys({a: 1, b: 2, c: 3}); //=> ['a', 'b', 'c']
+ */
+var keys = typeof Object.keys === 'function' && !hasArgsEnumBug ?
+  _curry1(function keys(obj) {
+    return Object(obj) !== obj ? [] : Object.keys(obj);
+  }) :
+  _curry1(function keys(obj) {
+    if (Object(obj) !== obj) {
+      return [];
+    }
+    var prop, nIdx;
+    var ks = [];
+    var checkArgsLength = hasArgsEnumBug && _isArguments(obj);
+    for (prop in obj) {
+      if (_has(prop, obj) && (!checkArgsLength || prop !== 'length')) {
+        ks[ks.length] = prop;
+      }
+    }
+    if (hasEnumBug) {
+      nIdx = nonEnumerableProps.length - 1;
+      while (nIdx >= 0) {
+        prop = nonEnumerableProps[nIdx];
+        if (_has(prop, obj) && !contains(ks, prop)) {
+          ks[ks.length] = prop;
+        }
+        nIdx -= 1;
+      }
+    }
+    return ks;
+  });
+
+/**
+ * Takes a function and
+ * a [functor](https://github.com/fantasyland/fantasy-land#functor),
+ * applies the function to each of the functor's values, and returns
+ * a functor of the same shape.
+ *
+ * Ramda provides suitable `map` implementations for `Array` and `Object`,
+ * so this function may be applied to `[1, 2, 3]` or `{x: 1, y: 2, z: 3}`.
+ *
+ * Dispatches to the `map` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * Also treats functions as functors and will compose them together.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Functor f => (a -> b) -> f a -> f b
+ * @param {Function} fn The function to be called on every element of the input `list`.
+ * @param {Array} list The list to be iterated over.
+ * @return {Array} The new list.
+ * @see R.transduce, R.addIndex
+ * @example
+ *
+ *      const double = x => x * 2;
+ *
+ *      R.map(double, [1, 2, 3]); //=> [2, 4, 6]
+ *
+ *      R.map(double, {x: 1, y: 2, z: 3}); //=> {x: 2, y: 4, z: 6}
+ * @symb R.map(f, [a, b]) = [f(a), f(b)]
+ * @symb R.map(f, { x: a, y: b }) = { x: f(a), y: f(b) }
+ * @symb R.map(f, functor_o) = functor_o.map(f)
+ */
+var map = _curry2(_dispatchable(['fantasy-land/map', 'map'], _xmap, function map(fn, functor) {
+  switch (Object.prototype.toString.call(functor)) {
+    case '[object Function]':
+      return curryN(functor.length, function() {
+        return fn.call(this, functor.apply(this, arguments));
+      });
+    case '[object Object]':
+      return _reduce(function(acc, key) {
+        acc[key] = fn(functor[key]);
+        return acc;
+      }, {}, keys(functor));
+    default:
+      return _map(fn, functor);
+  }
+}));
+
+/**
+ * Retrieve the value at a given path.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> {a} -> a | Undefined
+ * @param {Array} path The path to use.
+ * @param {Object} obj The object to retrieve the nested property from.
+ * @return {*} The data at `path`.
+ * @see R.prop
+ * @example
+ *
+ *      R.path(['a', 'b'], {a: {b: 2}}); //=> 2
+ *      R.path(['a', 'b'], {c: {b: 2}}); //=> undefined
+ */
+var path = _curry2(function path(paths, obj) {
+  var val = obj;
+  var idx = 0;
+  while (idx < paths.length) {
+    if (val == null) {
+      return;
+    }
+    val = val[paths[idx]];
+    idx += 1;
+  }
+  return val;
+});
+
+/**
+ * Returns a function that when supplied an object returns the indicated
+ * property of that object, if it exists.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig s -> {s: a} -> a | Undefined
+ * @param {String} p The property name
+ * @param {Object} obj The object to query
+ * @return {*} The value at `obj.p`.
+ * @see R.path
+ * @example
+ *
+ *      R.prop('x', {x: 100}); //=> 100
+ *      R.prop('x', {}); //=> undefined
+ *      R.compose(R.inc, R.prop('x'))({ x: 3 }) //=> 4
+ */
+
+var prop = _curry2(function prop(p, obj) { return path([p], obj); });
+
+/**
+ * Returns a new list by plucking the same named property off all objects in
+ * the list supplied.
+ *
+ * `pluck` will work on
+ * any [functor](https://github.com/fantasyland/fantasy-land#functor) in
+ * addition to arrays, as it is equivalent to `R.map(R.prop(k), f)`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Functor f => k -> f {k: v} -> f v
+ * @param {Number|String} key The key name to pluck off of each object.
+ * @param {Array} f The array or functor to consider.
+ * @return {Array} The list of values for the given key.
+ * @see R.props
+ * @example
+ *
+ *      var getAges = R.pluck('age');
+ *      getAges([{name: 'fred', age: 29}, {name: 'wilma', age: 27}]); //=> [29, 27]
+ *
+ *      R.pluck(0, [[1, 2], [3, 4]]);               //=> [1, 3]
+ *      R.pluck('val', {a: {val: 3}, b: {val: 5}}); //=> {a: 3, b: 5}
+ * @symb R.pluck('x', [{x: 1, y: 2}, {x: 3, y: 4}, {x: 5, y: 6}]) = [1, 3, 5]
+ * @symb R.pluck(0, [[1, 2], [3, 4], [5, 6]]) = [1, 3, 5]
+ */
+var pluck = _curry2(function pluck(p, list) {
+  return map(prop(p), list);
+});
+
+/**
+ * Returns a single item by iterating through the list, successively calling
+ * the iterator function and passing it an accumulator value and the current
+ * value from the array, and then passing the result to the next call.
+ *
+ * The iterator function receives two values: *(acc, value)*. It may use
+ * [`R.reduced`](#reduced) to shortcut the iteration.
+ *
+ * The arguments' order of [`reduceRight`](#reduceRight)'s iterator function
+ * is *(value, acc)*.
+ *
+ * Note: `R.reduce` does not skip deleted or unassigned indices (sparse
+ * arrays), unlike the native `Array.prototype.reduce` method. For more details
+ * on this behavior, see:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description
+ *
+ * Dispatches to the `reduce` method of the third argument, if present. When
+ * doing so, it is up to the user to handle the [`R.reduced`](#reduced)
+ * shortcuting, as this is not implemented by `reduce`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, b) -> a) -> a -> [b] -> a
+ * @param {Function} fn The iterator function. Receives two values, the accumulator and the
+ *        current element from the array.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduced, R.addIndex, R.reduceRight
+ * @example
+ *
+ *      R.reduce(R.subtract, 0, [1, 2, 3, 4]) // => ((((0 - 1) - 2) - 3) - 4) = -10
+ *      //          -               -10
+ *      //         / \              / \
+ *      //        -   4           -6   4
+ *      //       / \              / \
+ *      //      -   3   ==>     -3   3
+ *      //     / \              / \
+ *      //    -   2           -1   2
+ *      //   / \              / \
+ *      //  0   1            0   1
+ *
+ * @symb R.reduce(f, a, [b, c, d]) = f(f(f(a, b), c), d)
+ */
+var reduce = _curry3(_reduce);
+
+/**
+ * Takes a list of predicates and returns a predicate that returns true for a
+ * given list of arguments if every one of the provided predicates is satisfied
+ * by those arguments.
+ *
+ * The function returned is a curried function whose arity matches that of the
+ * highest-arity predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Logic
+ * @sig [(*... -> Boolean)] -> (*... -> Boolean)
+ * @param {Array} predicates An array of predicates to check
+ * @return {Function} The combined predicate
+ * @see R.anyPass
+ * @example
+ *
+ *      const isQueen = R.propEq('rank', 'Q');
+ *      const isSpade = R.propEq('suit', '♠︎');
+ *      const isQueenOfSpades = R.allPass([isQueen, isSpade]);
+ *
+ *      isQueenOfSpades({rank: 'Q', suit: '♣︎'}); //=> false
+ *      isQueenOfSpades({rank: 'Q', suit: '♠︎'}); //=> true
+ */
+var allPass = _curry1(function allPass(preds) {
+  return curryN(reduce(max, 0, pluck('length', preds)), function() {
+    var idx = 0;
+    var len = preds.length;
+    while (idx < len) {
+      if (!preds[idx].apply(this, arguments)) {
+        return false;
+      }
+      idx += 1;
+    }
+    return true;
+  });
+});
+
+/**
+ * Returns a function that always returns the given value. Note that for
+ * non-primitives the value returned is a reference to the original value.
+ *
+ * This function is known as `const`, `constant`, or `K` (for K combinator) in
+ * other languages and libraries.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig a -> (* -> a)
+ * @param {*} val The value to wrap in a function
+ * @return {Function} A Function :: * -> val.
+ * @example
+ *
+ *      const t = R.always('Tee');
+ *      t(); //=> 'Tee'
+ */
+var always = _curry1(function always(val) {
+  return function() {
+    return val;
+  };
+});
+
+/**
+ * Returns `true` if both arguments are `true`; `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig a -> b -> a | b
+ * @param {Any} a
+ * @param {Any} b
+ * @return {Any} the first argument if it is falsy, otherwise the second argument.
+ * @see R.both
+ * @example
+ *
+ *      R.and(true, true); //=> true
+ *      R.and(true, false); //=> false
+ *      R.and(false, true); //=> false
+ *      R.and(false, false); //=> false
+ */
+var and = _curry2(function and(a, b) {
+  return a && b;
+});
+
+function XAny(f, xf) {
+  this.xf = xf;
+  this.f = f;
+  this.any = false;
+}
+XAny.prototype['@@transducer/init'] = _xfBase.init;
+XAny.prototype['@@transducer/result'] = function(result) {
+  if (!this.any) {
+    result = this.xf['@@transducer/step'](result, false);
+  }
+  return this.xf['@@transducer/result'](result);
+};
+XAny.prototype['@@transducer/step'] = function(result, input) {
+  if (this.f(input)) {
+    this.any = true;
+    result = _reduced(this.xf['@@transducer/step'](result, true));
+  }
+  return result;
+};
+
+var _xany = _curry2(function _xany(f, xf) { return new XAny(f, xf); });
+
+/**
+ * Returns `true` if at least one of the elements of the list match the predicate,
+ * `false` otherwise.
+ *
+ * Dispatches to the `any` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Boolean
+ * @param {Function} fn The predicate function.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if the predicate is satisfied by at least one element, `false`
+ *         otherwise.
+ * @see R.all, R.none, R.transduce
+ * @example
+ *
+ *      const lessThan0 = R.flip(R.lt)(0);
+ *      const lessThan2 = R.flip(R.lt)(2);
+ *      R.any(lessThan0)([1, 2]); //=> false
+ *      R.any(lessThan2)([1, 2]); //=> true
+ */
+var any = _curry2(_dispatchable(['any'], _xany, function any(fn, list) {
+  var idx = 0;
+  while (idx < list.length) {
+    if (fn(list[idx])) {
+      return true;
+    }
+    idx += 1;
+  }
+  return false;
+}));
+
+/**
+ * Takes a list of predicates and returns a predicate that returns true for a
+ * given list of arguments if at least one of the provided predicates is
+ * satisfied by those arguments.
+ *
+ * The function returned is a curried function whose arity matches that of the
+ * highest-arity predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Logic
+ * @sig [(*... -> Boolean)] -> (*... -> Boolean)
+ * @param {Array} predicates An array of predicates to check
+ * @return {Function} The combined predicate
+ * @see R.allPass
+ * @example
+ *
+ *      const isClub = R.propEq('suit', '♣');
+ *      const isSpade = R.propEq('suit', 'â™ ');
+ *      const isBlackCard = R.anyPass([isClub, isSpade]);
+ *
+ *      isBlackCard({rank: '10', suit: '♣'}); //=> true
+ *      isBlackCard({rank: 'Q', suit: 'â™ '}); //=> true
+ *      isBlackCard({rank: 'Q', suit: '♦'}); //=> false
+ */
+var anyPass = _curry1(function anyPass(preds) {
+  return curryN(reduce(max, 0, pluck('length', preds)), function() {
+    var idx = 0;
+    var len = preds.length;
+    while (idx < len) {
+      if (preds[idx].apply(this, arguments)) {
+        return true;
+      }
+      idx += 1;
+    }
+    return false;
+  });
+});
+
+/**
+ * ap applies a list of functions to a list of values.
+ *
+ * Dispatches to the `ap` method of the second argument, if present. Also
+ * treats curried functions as applicatives.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Function
+ * @sig [a -> b] -> [a] -> [b]
+ * @sig Apply f => f (a -> b) -> f a -> f b
+ * @sig (r -> a -> b) -> (r -> a) -> (r -> b)
+ * @param {*} applyF
+ * @param {*} applyX
+ * @return {*}
+ * @example
+ *
+ *      R.ap([R.multiply(2), R.add(3)], [1,2,3]); //=> [2, 4, 6, 4, 5, 6]
+ *      R.ap([R.concat('tasty '), R.toUpper], ['pizza', 'salad']); //=> ["tasty pizza", "tasty salad", "PIZZA", "SALAD"]
+ *
+ *      // R.ap can also be used as S combinator
+ *      // when only two functions are passed
+ *      R.ap(R.concat, R.toUpper)('Ramda') //=> 'RamdaRAMDA'
+ * @symb R.ap([f, g], [a, b]) = [f(a), f(b), g(a), g(b)]
+ */
+var ap = _curry2(function ap(applyF, applyX) {
+  return (
+    typeof applyX['fantasy-land/ap'] === 'function'
+      ? applyX['fantasy-land/ap'](applyF)
+      : typeof applyF.ap === 'function'
+        ? applyF.ap(applyX)
+        : typeof applyF === 'function'
+          ? function(x) { return applyF(x)(applyX(x)); }
+          : _reduce(function(acc, f) { return _concat(acc, map(f, applyX)); }, [], applyF)
+  );
+});
+
+function _aperture(n, list) {
+  var idx = 0;
+  var limit = list.length - (n - 1);
+  var acc = new Array(limit >= 0 ? limit : 0);
+  while (idx < limit) {
+    acc[idx] = Array.prototype.slice.call(list, idx, idx + n);
+    idx += 1;
+  }
+  return acc;
+}
+
+function XAperture(n, xf) {
+  this.xf = xf;
+  this.pos = 0;
+  this.full = false;
+  this.acc = new Array(n);
+}
+XAperture.prototype['@@transducer/init'] = _xfBase.init;
+XAperture.prototype['@@transducer/result'] = function(result) {
+  this.acc = null;
+  return this.xf['@@transducer/result'](result);
+};
+XAperture.prototype['@@transducer/step'] = function(result, input) {
+  this.store(input);
+  return this.full ? this.xf['@@transducer/step'](result, this.getCopy()) : result;
+};
+XAperture.prototype.store = function(input) {
+  this.acc[this.pos] = input;
+  this.pos += 1;
+  if (this.pos === this.acc.length) {
+    this.pos = 0;
+    this.full = true;
+  }
+};
+XAperture.prototype.getCopy = function() {
+  return _concat(Array.prototype.slice.call(this.acc, this.pos),
+    Array.prototype.slice.call(this.acc, 0, this.pos)
+  );
+};
+
+var _xaperture = _curry2(function _xaperture(n, xf) { return new XAperture(n, xf); });
+
+/**
+ * Returns a new list, composed of n-tuples of consecutive elements. If `n` is
+ * greater than the length of the list, an empty list is returned.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig Number -> [a] -> [[a]]
+ * @param {Number} n The size of the tuples to create
+ * @param {Array} list The list to split into `n`-length tuples
+ * @return {Array} The resulting list of `n`-length tuples
+ * @see R.transduce
+ * @example
+ *
+ *      R.aperture(2, [1, 2, 3, 4, 5]); //=> [[1, 2], [2, 3], [3, 4], [4, 5]]
+ *      R.aperture(3, [1, 2, 3, 4, 5]); //=> [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
+ *      R.aperture(7, [1, 2, 3, 4, 5]); //=> []
+ */
+var aperture = _curry2(_dispatchable([], _xaperture, _aperture));
+
+/**
+ * Returns a new list containing the contents of the given list, followed by
+ * the given element.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> [a]
+ * @param {*} el The element to add to the end of the new list.
+ * @param {Array} list The list of elements to add a new item to.
+ *        list.
+ * @return {Array} A new list containing the elements of the old list followed by `el`.
+ * @see R.prepend
+ * @example
+ *
+ *      R.append('tests', ['write', 'more']); //=> ['write', 'more', 'tests']
+ *      R.append('tests', []); //=> ['tests']
+ *      R.append(['tests'], ['write', 'more']); //=> ['write', 'more', ['tests']]
+ */
+var append = _curry2(function append(el, list) {
+  return _concat(list, [el]);
+});
+
+/**
+ * Applies function `fn` to the argument list `args`. This is useful for
+ * creating a fixed-arity function from a variadic function. `fn` should be a
+ * bound function if context is significant.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Function
+ * @sig (*... -> a) -> [*] -> a
+ * @param {Function} fn The function which will be called with `args`
+ * @param {Array} args The arguments to call `fn` with
+ * @return {*} result The result, equivalent to `fn(...args)`
+ * @see R.call, R.unapply
+ * @example
+ *
+ *      const nums = [1, 2, 3, -99, 42, 6, 7];
+ *      R.apply(Math.max, nums); //=> 42
+ * @symb R.apply(f, [a, b, c]) = f(a, b, c)
+ */
+var apply = _curry2(function apply(fn, args) {
+  return fn.apply(this, args);
+});
+
+/**
+ * Returns a list of all the enumerable own properties of the supplied object.
+ * Note that the order of the output array is not guaranteed across different
+ * JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {k: v} -> [v]
+ * @param {Object} obj The object to extract values from
+ * @return {Array} An array of the values of the object's own properties.
+ * @see R.valuesIn, R.keys
+ * @example
+ *
+ *      R.values({a: 1, b: 2, c: 3}); //=> [1, 2, 3]
+ */
+var values = _curry1(function values(obj) {
+  var props = keys(obj);
+  var len = props.length;
+  var vals = [];
+  var idx = 0;
+  while (idx < len) {
+    vals[idx] = obj[props[idx]];
+    idx += 1;
+  }
+  return vals;
+});
+
+// Use custom mapValues function to avoid issues with specs that include a "map" key and R.map
+// delegating calls to .map
+function mapValues(fn, obj) {
+  return keys(obj).reduce(function(acc, key) {
+    acc[key] = fn(obj[key]);
+    return acc;
+  }, {});
+}
+
+/**
+ * Given a spec object recursively mapping properties to functions, creates a
+ * function producing an object of the same structure, by mapping each property
+ * to the result of calling its associated function with the supplied arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Function
+ * @sig {k: ((a, b, ..., m) -> v)} -> ((a, b, ..., m) -> {k: v})
+ * @param {Object} spec an object recursively mapping properties to functions for
+ *        producing the values for these properties.
+ * @return {Function} A function that returns an object of the same structure
+ * as `spec', with each property set to the value returned by calling its
+ * associated function with the supplied arguments.
+ * @see R.converge, R.juxt
+ * @example
+ *
+ *      const getMetrics = R.applySpec({
+ *        sum: R.add,
+ *        nested: { mul: R.multiply }
+ *      });
+ *      getMetrics(2, 4); // => { sum: 6, nested: { mul: 8 } }
+ * @symb R.applySpec({ x: f, y: { z: g } })(a, b) = { x: f(a, b), y: { z: g(a, b) } }
+ */
+var applySpec = _curry1(function applySpec(spec) {
+  spec = mapValues(
+    function(v) { return typeof v == 'function' ? v : applySpec(v); },
+    spec
+  );
+
+  return curryN(
+    reduce(max, 0, pluck('length', values(spec))),
+    function() {
+      var args = arguments;
+      return mapValues(function(f) { return apply(f, args); }, spec);
+    });
+});
+
+/**
+ * Takes a value and applies a function to it.
+ *
+ * This function is also known as the `thrush` combinator.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.25.0
+ * @category Function
+ * @sig a -> (a -> b) -> b
+ * @param {*} x The value
+ * @param {Function} f The function to apply
+ * @return {*} The result of applying `f` to `x`
+ * @example
+ *
+ *      const t42 = R.applyTo(42);
+ *      t42(R.identity); //=> 42
+ *      t42(R.add(1)); //=> 43
+ */
+var applyTo = _curry2(function applyTo(x, f) { return f(x); });
+
+/**
+ * Makes an ascending comparator function out of a function that returns a value
+ * that can be compared with `<` and `>`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Function
+ * @sig Ord b => (a -> b) -> a -> a -> Number
+ * @param {Function} fn A function of arity one that returns a value that can be compared
+ * @param {*} a The first item to be compared.
+ * @param {*} b The second item to be compared.
+ * @return {Number} `-1` if fn(a) < fn(b), `1` if fn(b) < fn(a), otherwise `0`
+ * @see R.descend
+ * @example
+ *
+ *      const byAge = R.ascend(R.prop('age'));
+ *      const people = [
+ *        { name: 'Emma', age: 70 },
+ *        { name: 'Peter', age: 78 },
+ *        { name: 'Mikhail', age: 62 },
+ *      ];
+ *      const peopleByYoungestFirst = R.sort(byAge, people);
+ *        //=> [{ name: 'Mikhail', age: 62 },{ name: 'Emma', age: 70 }, { name: 'Peter', age: 78 }]
+ */
+var ascend = _curry3(function ascend(fn, a, b) {
+  var aa = fn(a);
+  var bb = fn(b);
+  return aa < bb ? -1 : aa > bb ? 1 : 0;
+});
+
+/**
+ * Makes a shallow clone of an object, setting or overriding the specified
+ * property with the given value. Note that this copies and flattens prototype
+ * properties onto the new object as well. All non-primitive properties are
+ * copied by reference.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @sig String -> a -> {k: v} -> {k: v}
+ * @param {String} prop The property name to set
+ * @param {*} val The new value
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object equivalent to the original except for the changed property.
+ * @see R.dissoc, R.pick
+ * @example
+ *
+ *      R.assoc('c', 3, {a: 1, b: 2}); //=> {a: 1, b: 2, c: 3}
+ */
+var assoc = _curry3(function assoc(prop, val, obj) {
+  var result = {};
+  for (var p in obj) {
+    result[p] = obj[p];
+  }
+  result[prop] = val;
+  return result;
+});
+
+/**
+ * Determine if the passed argument is an integer.
+ *
+ * @private
+ * @param {*} n
+ * @category Type
+ * @return {Boolean}
+ */
+var _isInteger = Number.isInteger || function _isInteger(n) {
+  return (n << 0) === n;
+};
+
+/**
+ * Checks if the input value is `null` or `undefined`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Type
+ * @sig * -> Boolean
+ * @param {*} x The value to test.
+ * @return {Boolean} `true` if `x` is `undefined` or `null`, otherwise `false`.
+ * @example
+ *
+ *      R.isNil(null); //=> true
+ *      R.isNil(undefined); //=> true
+ *      R.isNil(0); //=> false
+ *      R.isNil([]); //=> false
+ */
+var isNil = _curry1(function isNil(x) { return x == null; });
+
+/**
+ * Makes a shallow clone of an object, setting or overriding the nodes required
+ * to create the given path, and placing the specific value at the tail end of
+ * that path. Note that this copies and flattens prototype properties onto the
+ * new object as well. All non-primitive properties are copied by reference.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> a -> {a} -> {a}
+ * @param {Array} path the path to set
+ * @param {*} val The new value
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object equivalent to the original except along the specified path.
+ * @see R.dissocPath
+ * @example
+ *
+ *      R.assocPath(['a', 'b', 'c'], 42, {a: {b: {c: 0}}}); //=> {a: {b: {c: 42}}}
+ *
+ *      // Any missing or non-object keys in path will be overridden
+ *      R.assocPath(['a', 'b', 'c'], 42, {a: 5}); //=> {a: {b: {c: 42}}}
+ */
+var assocPath = _curry3(function assocPath(path, val, obj) {
+  if (path.length === 0) {
+    return val;
+  }
+  var idx = path[0];
+  if (path.length > 1) {
+    var nextObj = (!isNil(obj) && _has(idx, obj)) ? obj[idx] : _isInteger(path[1]) ? [] : {};
+    val = assocPath(Array.prototype.slice.call(path, 1), val, nextObj);
+  }
+  if (_isInteger(idx) && _isArray(obj)) {
+    var arr = [].concat(obj);
+    arr[idx] = val;
+    return arr;
+  } else {
+    return assoc(idx, val, obj);
+  }
+});
+
+/**
+ * Wraps a function of any arity (including nullary) in a function that accepts
+ * exactly `n` parameters. Any extraneous parameters will not be passed to the
+ * supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig Number -> (* -> a) -> (* -> a)
+ * @param {Number} n The desired arity of the new function.
+ * @param {Function} fn The function to wrap.
+ * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
+ *         arity `n`.
+ * @see R.binary, R.unary
+ * @example
+ *
+ *      const takesTwoArgs = (a, b) => [a, b];
+ *
+ *      takesTwoArgs.length; //=> 2
+ *      takesTwoArgs(1, 2); //=> [1, 2]
+ *
+ *      const takesOneArg = R.nAry(1, takesTwoArgs);
+ *      takesOneArg.length; //=> 1
+ *      // Only `n` arguments are passed to the wrapped function
+ *      takesOneArg(1, 2); //=> [1, undefined]
+ * @symb R.nAry(0, f)(a, b) = f()
+ * @symb R.nAry(1, f)(a, b) = f(a)
+ * @symb R.nAry(2, f)(a, b) = f(a, b)
+ */
+var nAry = _curry2(function nAry(n, fn) {
+  switch (n) {
+    case 0: return function() {return fn.call(this);};
+    case 1: return function(a0) {return fn.call(this, a0);};
+    case 2: return function(a0, a1) {return fn.call(this, a0, a1);};
+    case 3: return function(a0, a1, a2) {return fn.call(this, a0, a1, a2);};
+    case 4: return function(a0, a1, a2, a3) {return fn.call(this, a0, a1, a2, a3);};
+    case 5: return function(a0, a1, a2, a3, a4) {return fn.call(this, a0, a1, a2, a3, a4);};
+    case 6: return function(a0, a1, a2, a3, a4, a5) {return fn.call(this, a0, a1, a2, a3, a4, a5);};
+    case 7: return function(a0, a1, a2, a3, a4, a5, a6) {return fn.call(this, a0, a1, a2, a3, a4, a5, a6);};
+    case 8: return function(a0, a1, a2, a3, a4, a5, a6, a7) {return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7);};
+    case 9: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8) {return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7, a8);};
+    case 10: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);};
+    default: throw new Error('First argument to nAry must be a non-negative integer no greater than ten');
+  }
+});
+
+/**
+ * Wraps a function of any arity (including nullary) in a function that accepts
+ * exactly 2 parameters. Any extraneous parameters will not be passed to the
+ * supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Function
+ * @sig (* -> c) -> (a, b -> c)
+ * @param {Function} fn The function to wrap.
+ * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
+ *         arity 2.
+ * @see R.nAry, R.unary
+ * @example
+ *
+ *      const takesThreeArgs = function(a, b, c) {
+ *        return [a, b, c];
+ *      };
+ *      takesThreeArgs.length; //=> 3
+ *      takesThreeArgs(1, 2, 3); //=> [1, 2, 3]
+ *
+ *      const takesTwoArgs = R.binary(takesThreeArgs);
+ *      takesTwoArgs.length; //=> 2
+ *      // Only 2 arguments are passed to the wrapped function
+ *      takesTwoArgs(1, 2, 3); //=> [1, 2, undefined]
+ * @symb R.binary(f)(a, b, c) = f(a, b)
+ */
+var binary = _curry1(function binary(fn) {
+  return nAry(2, fn);
+});
+
+function _isFunction(x) {
+  return Object.prototype.toString.call(x) === '[object Function]';
+}
+
+/**
+ * "lifts" a function to be the specified arity, so that it may "map over" that
+ * many lists, Functions or other objects that satisfy the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Function
+ * @sig Number -> (*... -> *) -> ([*]... -> [*])
+ * @param {Function} fn The function to lift into higher context
+ * @return {Function} The lifted function.
+ * @see R.lift, R.ap
+ * @example
+ *
+ *      const madd3 = R.liftN(3, (...args) => R.sum(args));
+ *      madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
+ */
+var liftN = _curry2(function liftN(arity, fn) {
+  var lifted = curryN(arity, fn);
+  return curryN(arity, function() {
+    return _reduce(ap, map(lifted, arguments[0]), Array.prototype.slice.call(arguments, 1));
+  });
+});
+
+/**
+ * "lifts" a function of arity > 1 so that it may "map over" a list, Function or other
+ * object that satisfies the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Function
+ * @sig (*... -> *) -> ([*]... -> [*])
+ * @param {Function} fn The function to lift into higher context
+ * @return {Function} The lifted function.
+ * @see R.liftN
+ * @example
+ *
+ *      const madd3 = R.lift((a, b, c) => a + b + c);
+ *
+ *      madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
+ *
+ *      const madd5 = R.lift((a, b, c, d, e) => a + b + c + d + e);
+ *
+ *      madd5([1,2], [3], [4, 5], [6], [7, 8]); //=> [21, 22, 22, 23, 22, 23, 23, 24]
+ */
+var lift = _curry1(function lift(fn) {
+  return liftN(fn.length, fn);
+});
+
+/**
+ * A function which calls the two provided functions and returns the `&&`
+ * of the results.
+ * It returns the result of the first function if it is false-y and the result
+ * of the second function otherwise. Note that this is short-circuited,
+ * meaning that the second function will not be invoked if the first returns a
+ * false-y value.
+ *
+ * In addition to functions, `R.both` also accepts any fantasy-land compatible
+ * applicative functor.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category Logic
+ * @sig (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
+ * @param {Function} f A predicate
+ * @param {Function} g Another predicate
+ * @return {Function} a function that applies its arguments to `f` and `g` and `&&`s their outputs together.
+ * @see R.and
+ * @example
+ *
+ *      const gt10 = R.gt(R.__, 10)
+ *      const lt20 = R.lt(R.__, 20)
+ *      const f = R.both(gt10, lt20);
+ *      f(15); //=> true
+ *      f(30); //=> false
+ *
+ *      R.both(Maybe.Just(false), Maybe.Just(55)); // => Maybe.Just(false)
+ *      R.both([false, false, 'a'], [11]); //=> [false, false, 11]
+ */
+var both = _curry2(function both(f, g) {
+  return _isFunction(f) ?
+    function _both() {
+      return f.apply(this, arguments) && g.apply(this, arguments);
+    } :
+    lift(and)(f, g);
+});
+
+/**
+ * Returns a curried equivalent of the provided function. The curried function
+ * has two unusual capabilities. First, its arguments needn't be provided one
+ * at a time. If `f` is a ternary function and `g` is `R.curry(f)`, the
+ * following are equivalent:
+ *
+ *   - `g(1)(2)(3)`
+ *   - `g(1)(2, 3)`
+ *   - `g(1, 2)(3)`
+ *   - `g(1, 2, 3)`
+ *
+ * Secondly, the special placeholder value [`R.__`](#__) may be used to specify
+ * "gaps", allowing partial application of any combination of arguments,
+ * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__),
+ * the following are equivalent:
+ *
+ *   - `g(1, 2, 3)`
+ *   - `g(_, 2, 3)(1)`
+ *   - `g(_, _, 3)(1)(2)`
+ *   - `g(_, _, 3)(1, 2)`
+ *   - `g(_, 2)(1)(3)`
+ *   - `g(_, 2)(1, 3)`
+ *   - `g(_, 2)(_, 3)(1)`
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (* -> a) -> (* -> a)
+ * @param {Function} fn The function to curry.
+ * @return {Function} A new, curried function.
+ * @see R.curryN, R.partial
+ * @example
+ *
+ *      const addFourNumbers = (a, b, c, d) => a + b + c + d;
+ *
+ *      const curriedAddFourNumbers = R.curry(addFourNumbers);
+ *      const f = curriedAddFourNumbers(1, 2);
+ *      const g = f(3);
+ *      g(4); //=> 10
+ */
+var curry = _curry1(function curry(fn) {
+  return curryN(fn.length, fn);
+});
+
+/**
+ * Returns the result of calling its first argument with the remaining
+ * arguments. This is occasionally useful as a converging function for
+ * [`R.converge`](#converge): the first branch can produce a function while the
+ * remaining branches produce values to be passed to that function as its
+ * arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig (*... -> a),*... -> a
+ * @param {Function} fn The function to apply to the remaining arguments.
+ * @param {...*} args Any number of positional arguments.
+ * @return {*}
+ * @see R.apply
+ * @example
+ *
+ *      R.call(R.add, 1, 2); //=> 3
+ *
+ *      const indentN = R.pipe(R.repeat(' '),
+ *                           R.join(''),
+ *                           R.replace(/^(?!$)/gm));
+ *
+ *      const format = R.converge(R.call, [
+ *                                  R.pipe(R.prop('indent'), indentN),
+ *                                  R.prop('value')
+ *                              ]);
+ *
+ *      format({indent: 2, value: 'foo\nbar\nbaz\n'}); //=> '  foo\n  bar\n  baz\n'
+ * @symb R.call(f, a, b) = f(a, b)
+ */
+var call = curry(function call(fn) {
+  return fn.apply(this, Array.prototype.slice.call(arguments, 1));
+});
+
+/**
+ * `_makeFlat` is a helper function that returns a one-level or fully recursive
+ * function based on the flag passed in.
+ *
+ * @private
+ */
+function _makeFlat(recursive) {
+  return function flatt(list) {
+    var value, jlen, j;
+    var result = [];
+    var idx = 0;
+    var ilen = list.length;
+
+    while (idx < ilen) {
+      if (_isArrayLike(list[idx])) {
+        value = recursive ? flatt(list[idx]) : list[idx];
+        j = 0;
+        jlen = value.length;
+        while (j < jlen) {
+          result[result.length] = value[j];
+          j += 1;
+        }
+      } else {
+        result[result.length] = list[idx];
+      }
+      idx += 1;
+    }
+    return result;
+  };
+}
+
+function _forceReduced(x) {
+  return {
+    '@@transducer/value': x,
+    '@@transducer/reduced': true
+  };
+}
+
+var preservingReduced = function(xf) {
+  return {
+    '@@transducer/init': _xfBase.init,
+    '@@transducer/result': function(result) {
+      return xf['@@transducer/result'](result);
+    },
+    '@@transducer/step': function(result, input) {
+      var ret = xf['@@transducer/step'](result, input);
+      return ret['@@transducer/reduced'] ? _forceReduced(ret) : ret;
+    }
+  };
+};
+
+var _flatCat = function _xcat(xf) {
+  var rxf = preservingReduced(xf);
+  return {
+    '@@transducer/init': _xfBase.init,
+    '@@transducer/result': function(result) {
+      return rxf['@@transducer/result'](result);
+    },
+    '@@transducer/step': function(result, input) {
+      return !_isArrayLike(input) ? _reduce(rxf, result, [input]) : _reduce(rxf, result, input);
+    }
+  };
+};
+
+var _xchain = _curry2(function _xchain(f, xf) {
+  return map(f, _flatCat(xf));
+});
+
+/**
+ * `chain` maps a function over a list and concatenates the results. `chain`
+ * is also known as `flatMap` in some libraries.
+ *
+ * Dispatches to the `chain` method of the second argument, if present,
+ * according to the [FantasyLand Chain spec](https://github.com/fantasyland/fantasy-land#chain).
+ *
+ * If second argument is a function, `chain(f, g)(x)` is equivalent to `f(g(x), x)`.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig Chain m => (a -> m b) -> m a -> m b
+ * @param {Function} fn The function to map with
+ * @param {Array} list The list to map over
+ * @return {Array} The result of flat-mapping `list` with `fn`
+ * @example
+ *
+ *      const duplicate = n => [n, n];
+ *      R.chain(duplicate, [1, 2, 3]); //=> [1, 1, 2, 2, 3, 3]
+ *
+ *      R.chain(R.append, R.head)([1, 2, 3]); //=> [1, 2, 3, 1]
+ */
+var chain = _curry2(_dispatchable(['fantasy-land/chain', 'chain'], _xchain, function chain(fn, monad) {
+  if (typeof monad === 'function') {
+    return function(x) { return fn(monad(x))(x); };
+  }
+  return _makeFlat(false)(map(fn, monad));
+}));
+
+/**
+ * Restricts a number to be within a range.
+ *
+ * Also works for other ordered types such as Strings and Dates.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Relation
+ * @sig Ord a => a -> a -> a -> a
+ * @param {Number} minimum The lower limit of the clamp (inclusive)
+ * @param {Number} maximum The upper limit of the clamp (inclusive)
+ * @param {Number} value Value to be clamped
+ * @return {Number} Returns `minimum` when `val < minimum`, `maximum` when `val > maximum`, returns `val` otherwise
+ * @example
+ *
+ *      R.clamp(1, 10, -5) // => 1
+ *      R.clamp(1, 10, 15) // => 10
+ *      R.clamp(1, 10, 4)  // => 4
+ */
+var clamp = _curry3(function clamp(min, max, value) {
+  if (min > max) {
+    throw new Error('min must not be greater than max in clamp(min, max, value)');
+  }
+  return value < min
+    ? min
+    : value > max
+      ? max
+      : value;
+});
+
+function _cloneRegExp(pattern) {
+  return new RegExp(pattern.source, (pattern.global     ? 'g' : '') +
+                                    (pattern.ignoreCase ? 'i' : '') +
+                                    (pattern.multiline  ? 'm' : '') +
+                                    (pattern.sticky     ? 'y' : '') +
+                                    (pattern.unicode    ? 'u' : ''));
+}
+
+/**
+ * Gives a single-word string description of the (native) type of a value,
+ * returning such answers as 'Object', 'Number', 'Array', or 'Null'. Does not
+ * attempt to distinguish user Object types any further, reporting them all as
+ * 'Object'.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Type
+ * @sig (* -> {*}) -> String
+ * @param {*} val The value to test
+ * @return {String}
+ * @example
+ *
+ *      R.type({}); //=> "Object"
+ *      R.type(1); //=> "Number"
+ *      R.type(false); //=> "Boolean"
+ *      R.type('s'); //=> "String"
+ *      R.type(null); //=> "Null"
+ *      R.type([]); //=> "Array"
+ *      R.type(/[A-z]/); //=> "RegExp"
+ *      R.type(() => {}); //=> "Function"
+ *      R.type(undefined); //=> "Undefined"
+ */
+var type = _curry1(function type(val) {
+  return val === null
+    ? 'Null'
+    : val === undefined
+      ? 'Undefined'
+      : Object.prototype.toString.call(val).slice(8, -1);
+});
+
+/**
+ * Copies an object.
+ *
+ * @private
+ * @param {*} value The value to be copied
+ * @param {Array} refFrom Array containing the source references
+ * @param {Array} refTo Array containing the copied source references
+ * @param {Boolean} deep Whether or not to perform deep cloning.
+ * @return {*} The copied value.
+ */
+function _clone(value, refFrom, refTo, deep) {
+  var copy = function copy(copiedValue) {
+    var len = refFrom.length;
+    var idx = 0;
+    while (idx < len) {
+      if (value === refFrom[idx]) {
+        return refTo[idx];
+      }
+      idx += 1;
+    }
+    refFrom[idx + 1] = value;
+    refTo[idx + 1] = copiedValue;
+    for (var key in value) {
+      copiedValue[key] = deep ?
+        _clone(value[key], refFrom, refTo, true) : value[key];
+    }
+    return copiedValue;
+  };
+  switch (type(value)) {
+    case 'Object':  return copy({});
+    case 'Array':   return copy([]);
+    case 'Date':    return new Date(value.valueOf());
+    case 'RegExp':  return _cloneRegExp(value);
+    default:        return value;
+  }
+}
+
+/**
+ * Creates a deep copy of the value which may contain (nested) `Array`s and
+ * `Object`s, `Number`s, `String`s, `Boolean`s and `Date`s. `Function`s are
+ * assigned by reference rather than copied
+ *
+ * Dispatches to a `clone` method if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {*} -> {*}
+ * @param {*} value The object or array to clone
+ * @return {*} A deeply cloned copy of `val`
+ * @example
+ *
+ *      const objects = [{}, {}, {}];
+ *      const objectsClone = R.clone(objects);
+ *      objects === objectsClone; //=> false
+ *      objects[0] === objectsClone[0]; //=> false
+ */
+var clone = _curry1(function clone(value) {
+  return value != null && typeof value.clone === 'function' ?
+    value.clone() :
+    _clone(value, [], [], true);
+});
+
+/**
+ * Makes a comparator function out of a function that reports whether the first
+ * element is less than the second.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((a, b) -> Boolean) -> ((a, b) -> Number)
+ * @param {Function} pred A predicate function of arity two which will return `true` if the first argument
+ * is less than the second, `false` otherwise
+ * @return {Function} A Function :: a -> b -> Int that returns `-1` if a < b, `1` if b < a, otherwise `0`
+ * @example
+ *
+ *      const byAge = R.comparator((a, b) => a.age < b.age);
+ *      const people = [
+ *        { name: 'Emma', age: 70 },
+ *        { name: 'Peter', age: 78 },
+ *        { name: 'Mikhail', age: 62 },
+ *      ];
+ *      const peopleByIncreasingAge = R.sort(byAge, people);
+ *        //=> [{ name: 'Mikhail', age: 62 },{ name: 'Emma', age: 70 }, { name: 'Peter', age: 78 }]
+ */
+var comparator = _curry1(function comparator(pred) {
+  return function(a, b) {
+    return pred(a, b) ? -1 : pred(b, a) ? 1 : 0;
+  };
+});
+
+/**
+ * A function that returns the `!` of its argument. It will return `true` when
+ * passed false-y value, and `false` when passed a truth-y one.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig * -> Boolean
+ * @param {*} a any value
+ * @return {Boolean} the logical inverse of passed argument.
+ * @see R.complement
+ * @example
+ *
+ *      R.not(true); //=> false
+ *      R.not(false); //=> true
+ *      R.not(0); //=> true
+ *      R.not(1); //=> false
+ */
+var not = _curry1(function not(a) {
+  return !a;
+});
+
+/**
+ * Takes a function `f` and returns a function `g` such that if called with the same arguments
+ * when `f` returns a "truthy" value, `g` returns `false` and when `f` returns a "falsy" value `g` returns `true`.
+ *
+ * `R.complement` may be applied to any functor
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category Logic
+ * @sig (*... -> *) -> (*... -> Boolean)
+ * @param {Function} f
+ * @return {Function}
+ * @see R.not
+ * @example
+ *
+ *      const isNotNil = R.complement(R.isNil);
+ *      isNil(null); //=> true
+ *      isNotNil(null); //=> false
+ *      isNil(7); //=> false
+ *      isNotNil(7); //=> true
+ */
+var complement = lift(not);
+
+function _pipe(f, g) {
+  return function() {
+    return g.call(this, f.apply(this, arguments));
+  };
+}
+
+/**
+ * This checks whether a function has a [methodname] function. If it isn't an
+ * array it will execute that function otherwise it will default to the ramda
+ * implementation.
+ *
+ * @private
+ * @param {Function} fn ramda implemtation
+ * @param {String} methodname property to check for a custom implementation
+ * @return {Object} Whatever the return value of the method is.
+ */
+function _checkForMethod(methodname, fn) {
+  return function() {
+    var length = arguments.length;
+    if (length === 0) {
+      return fn();
+    }
+    var obj = arguments[length - 1];
+    return (_isArray(obj) || typeof obj[methodname] !== 'function') ?
+      fn.apply(this, arguments) :
+      obj[methodname].apply(obj, Array.prototype.slice.call(arguments, 0, length - 1));
+  };
+}
+
+/**
+ * Returns the elements of the given list or string (or object with a `slice`
+ * method) from `fromIndex` (inclusive) to `toIndex` (exclusive).
+ *
+ * Dispatches to the `slice` method of the third argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.4
+ * @category List
+ * @sig Number -> Number -> [a] -> [a]
+ * @sig Number -> Number -> String -> String
+ * @param {Number} fromIndex The start index (inclusive).
+ * @param {Number} toIndex The end index (exclusive).
+ * @param {*} list
+ * @return {*}
+ * @example
+ *
+ *      R.slice(1, 3, ['a', 'b', 'c', 'd']);        //=> ['b', 'c']
+ *      R.slice(1, Infinity, ['a', 'b', 'c', 'd']); //=> ['b', 'c', 'd']
+ *      R.slice(0, -1, ['a', 'b', 'c', 'd']);       //=> ['a', 'b', 'c']
+ *      R.slice(-3, -1, ['a', 'b', 'c', 'd']);      //=> ['b', 'c']
+ *      R.slice(0, 3, 'ramda');                     //=> 'ram'
+ */
+var slice = _curry3(_checkForMethod('slice', function slice(fromIndex, toIndex, list) {
+  return Array.prototype.slice.call(list, fromIndex, toIndex);
+}));
+
+/**
+ * Returns all but the first element of the given list or string (or object
+ * with a `tail` method).
+ *
+ * Dispatches to the `slice` method of the first argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a]
+ * @sig String -> String
+ * @param {*} list
+ * @return {*}
+ * @see R.head, R.init, R.last
+ * @example
+ *
+ *      R.tail([1, 2, 3]);  //=> [2, 3]
+ *      R.tail([1, 2]);     //=> [2]
+ *      R.tail([1]);        //=> []
+ *      R.tail([]);         //=> []
+ *
+ *      R.tail('abc');  //=> 'bc'
+ *      R.tail('ab');   //=> 'b'
+ *      R.tail('a');    //=> ''
+ *      R.tail('');     //=> ''
+ */
+var tail = _curry1(_checkForMethod('tail', slice(1, Infinity)));
+
+/**
+ * Performs left-to-right function composition. The leftmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * In some libraries this function is named `sequence`.
+ *
+ * **Note:** The result of pipe is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)) -> ((a, b, ..., n) -> z)
+ * @param {...Function} functions
+ * @return {Function}
+ * @see R.compose
+ * @example
+ *
+ *      const f = R.pipe(Math.pow, R.negate, R.inc);
+ *
+ *      f(3, 4); // -(3^4) + 1
+ * @symb R.pipe(f, g, h)(a, b) = h(g(f(a, b)))
+ */
+function pipe() {
+  if (arguments.length === 0) {
+    throw new Error('pipe requires at least one argument');
+  }
+  return _arity(
+    arguments[0].length,
+    reduce(_pipe, arguments[0], tail(arguments))
+  );
+}
+
+/**
+ * Returns a new list or string with the elements or characters in reverse
+ * order.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a]
+ * @sig String -> String
+ * @param {Array|String} list
+ * @return {Array|String}
+ * @example
+ *
+ *      R.reverse([1, 2, 3]);  //=> [3, 2, 1]
+ *      R.reverse([1, 2]);     //=> [2, 1]
+ *      R.reverse([1]);        //=> [1]
+ *      R.reverse([]);         //=> []
+ *
+ *      R.reverse('abc');      //=> 'cba'
+ *      R.reverse('ab');       //=> 'ba'
+ *      R.reverse('a');        //=> 'a'
+ *      R.reverse('');         //=> ''
+ */
+var reverse = _curry1(function reverse(list) {
+  return _isString(list)
+    ? list.split('').reverse().join('')
+    : Array.prototype.slice.call(list, 0).reverse();
+});
+
+/**
+ * Performs right-to-left function composition. The rightmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * **Note:** The result of compose is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)) -> ((a, b, ..., n) -> z)
+ * @param {...Function} ...functions The functions to compose
+ * @return {Function}
+ * @see R.pipe
+ * @example
+ *
+ *      const classyGreeting = (firstName, lastName) => "The name's " + lastName + ", " + firstName + " " + lastName
+ *      const yellGreeting = R.compose(R.toUpper, classyGreeting);
+ *      yellGreeting('James', 'Bond'); //=> "THE NAME'S BOND, JAMES BOND"
+ *
+ *      R.compose(Math.abs, R.add(1), R.multiply(2))(-4) //=> 7
+ *
+ * @symb R.compose(f, g, h)(a, b) = f(g(h(a, b)))
+ */
+function compose() {
+  if (arguments.length === 0) {
+    throw new Error('compose requires at least one argument');
+  }
+  return pipe.apply(this, reverse(arguments));
+}
+
+/**
+ * Returns the right-to-left Kleisli composition of the provided functions,
+ * each of which must return a value of a type supported by [`chain`](#chain).
+ *
+ * `R.composeK(h, g, f)` is equivalent to `R.compose(R.chain(h), R.chain(g), f)`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Function
+ * @sig Chain m => ((y -> m z), (x -> m y), ..., (a -> m b)) -> (a -> m z)
+ * @param {...Function} ...functions The functions to compose
+ * @return {Function}
+ * @see R.pipeK
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *       //  get :: String -> Object -> Maybe *
+ *       const get = R.curry((propName, obj) => Maybe(obj[propName]))
+ *
+ *       //  getStateCode :: Maybe String -> Maybe String
+ *       const getStateCode = R.composeK(
+ *         R.compose(Maybe.of, R.toUpper),
+ *         get('state'),
+ *         get('address'),
+ *         get('user'),
+ *       );
+ *       getStateCode({"user":{"address":{"state":"ny"}}}); //=> Maybe.Just("NY")
+ *       getStateCode({}); //=> Maybe.Nothing()
+ * @symb R.composeK(f, g, h)(a) = R.chain(f, R.chain(g, h(a)))
+ */
+function composeK() {
+  if (arguments.length === 0) {
+    throw new Error('composeK requires at least one argument');
+  }
+  var init = Array.prototype.slice.call(arguments);
+  var last = init.pop();
+  return compose(compose.apply(this, map(chain, init)), last);
+}
+
+function _pipeP(f, g) {
+  return function() {
+    var ctx = this;
+    return f.apply(ctx, arguments).then(function(x) {
+      return g.call(ctx, x);
+    });
+  };
+}
+
+/**
+ * Performs left-to-right composition of one or more Promise-returning
+ * functions. The leftmost function may have any arity; the remaining functions
+ * must be unary.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((a -> Promise b), (b -> Promise c), ..., (y -> Promise z)) -> (a -> Promise z)
+ * @param {...Function} functions
+ * @return {Function}
+ * @see R.composeP
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      //  followersForUser :: String -> Promise [User]
+ *      const followersForUser = R.pipeP(db.getUserById, db.getFollowers);
+ */
+function pipeP() {
+  if (arguments.length === 0) {
+    throw new Error('pipeP requires at least one argument');
+  }
+  return _arity(
+    arguments[0].length,
+    reduce(_pipeP, arguments[0], tail(arguments))
+  );
+}
+
+/**
+ * Performs right-to-left composition of one or more Promise-returning
+ * functions. The rightmost function may have any arity; the remaining
+ * functions must be unary.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((y -> Promise z), (x -> Promise y), ..., (a -> Promise b)) -> (a -> Promise z)
+ * @param {...Function} functions The functions to compose
+ * @return {Function}
+ * @see R.pipeP
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      const db = {
+ *        users: {
+ *          JOE: {
+ *            name: 'Joe',
+ *            followers: ['STEVE', 'SUZY']
+ *          }
+ *        }
+ *      }
+ *
+ *      // We'll pretend to do a db lookup which returns a promise
+ *      const lookupUser = (userId) => Promise.resolve(db.users[userId])
+ *      const lookupFollowers = (user) => Promise.resolve(user.followers)
+ *      lookupUser('JOE').then(lookupFollowers)
+ *
+ *      //  followersForUser :: String -> Promise [UserId]
+ *      const followersForUser = R.composeP(lookupFollowers, lookupUser);
+ *      followersForUser('JOE').then(followers => console.log('Followers:', followers))
+ *      // Followers: ["STEVE","SUZY"]
+ */
+function composeP() {
+  if (arguments.length === 0) {
+    throw new Error('composeP requires at least one argument');
+  }
+  return pipeP.apply(this, reverse(arguments));
+}
+
+/**
+ * Returns the nth element of the given list or string. If n is negative the
+ * element at index length + n is returned.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> [a] -> a | Undefined
+ * @sig Number -> String -> String
+ * @param {Number} offset
+ * @param {*} list
+ * @return {*}
+ * @example
+ *
+ *      const list = ['foo', 'bar', 'baz', 'quux'];
+ *      R.nth(1, list); //=> 'bar'
+ *      R.nth(-1, list); //=> 'quux'
+ *      R.nth(-99, list); //=> undefined
+ *
+ *      R.nth(2, 'abc'); //=> 'c'
+ *      R.nth(3, 'abc'); //=> ''
+ * @symb R.nth(-1, [a, b, c]) = c
+ * @symb R.nth(0, [a, b, c]) = a
+ * @symb R.nth(1, [a, b, c]) = b
+ */
+var nth = _curry2(function nth(offset, list) {
+  var idx = offset < 0 ? list.length + offset : offset;
+  return _isString(list) ? list.charAt(idx) : list[idx];
+});
+
+/**
+ * Returns the first element of the given list or string. In some libraries
+ * this function is named `first`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> a | Undefined
+ * @sig String -> String
+ * @param {Array|String} list
+ * @return {*}
+ * @see R.tail, R.init, R.last
+ * @example
+ *
+ *      R.head(['fi', 'fo', 'fum']); //=> 'fi'
+ *      R.head([]); //=> undefined
+ *
+ *      R.head('abc'); //=> 'a'
+ *      R.head(''); //=> ''
+ */
+var head = nth(0);
+
+function _identity(x) { return x; }
+
+/**
+ * A function that does nothing but return the parameter supplied to it. Good
+ * as a default or placeholder function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig a -> a
+ * @param {*} x The value to return.
+ * @return {*} The input value, `x`.
+ * @example
+ *
+ *      R.identity(1); //=> 1
+ *
+ *      const obj = {};
+ *      R.identity(obj) === obj; //=> true
+ * @symb R.identity(a) = a
+ */
+var identity = _curry1(_identity);
+
+/**
+ * Performs left-to-right function composition using transforming function. The leftmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * **Note:** The result of pipeWith is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig ((* -> *), [((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)]) -> ((a, b, ..., n) -> z)
+ * @param {...Function} functions
+ * @return {Function}
+ * @see R.composeWith, R.pipe
+ * @example
+ *
+ *      const pipeWhileNotNil = R.pipeWith((f, res) => R.isNil(res) ? res : f(res));
+ *      const f = pipeWhileNotNil([Math.pow, R.negate, R.inc])
+ *
+ *      f(3, 4); // -(3^4) + 1
+ * @symb R.pipeWith(f)([g, h, i])(...args) = f(i, f(h, f(g, ...args)))
+ */
+var pipeWith = _curry2(function pipeWith(xf, list) {
+  if (list.length <= 0) {
+    return identity;
+  }
+
+  var headList = head(list);
+  var tailList = tail(list);
+
+  return _arity(headList.length, function() {
+    return _reduce(
+      function(result, f) {
+        return xf.call(this, f, result);
+      },
+      headList.apply(this, arguments),
+      tailList
+    );
+  });
+});
+
+/**
+ * Performs right-to-left function composition using transforming function. The rightmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * **Note:** The result of compose is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig ((* -> *), [(y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)]) -> ((a, b, ..., n) -> z)
+ * @param {...Function} ...functions The functions to compose
+ * @return {Function}
+ * @see R.compose, R.pipeWith
+ * @example
+ *
+ *      const composeWhileNotNil = R.composeWith((f, res) => R.isNil(res) ? res : f(res));
+ *
+ *      composeWhileNotNil([R.inc, R.prop('age')])({age: 1}) //=> 2
+ *      composeWhileNotNil([R.inc, R.prop('age')])({}) //=> undefined
+ *
+ * @symb R.composeWith(f)([g, h, i])(...args) = f(g, f(h, f(i, ...args)))
+ */
+var composeWith = _curry2(function composeWith(xf, list) {
+  return pipeWith.apply(this, [xf, reverse(list)]);
+});
+
+function _arrayFromIterator(iter) {
+  var list = [];
+  var next;
+  while (!(next = iter.next()).done) {
+    list.push(next.value);
+  }
+  return list;
+}
+
+function _includesWith(pred, x, list) {
+  var idx = 0;
+  var len = list.length;
+
+  while (idx < len) {
+    if (pred(x, list[idx])) {
+      return true;
+    }
+    idx += 1;
+  }
+  return false;
+}
+
+function _functionName(f) {
+  // String(x => x) evaluates to "x => x", so the pattern may not match.
+  var match = String(f).match(/^function (\w*)/);
+  return match == null ? '' : match[1];
+}
+
+// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+function _objectIs(a, b) {
+  // SameValue algorithm
+  if (a === b) { // Steps 1-5, 7-10
+    // Steps 6.b-6.e: +0 != -0
+    return a !== 0 || 1 / a === 1 / b;
+  } else {
+    // Step 6.a: NaN == NaN
+    return a !== a && b !== b;
+  }
+}
+
+var _objectIs$1 = typeof Object.is === 'function' ? Object.is : _objectIs;
+
+/**
+ * private _uniqContentEquals function.
+ * That function is checking equality of 2 iterator contents with 2 assumptions
+ * - iterators lengths are the same
+ * - iterators values are unique
+ *
+ * false-positive result will be returned for comparision of, e.g.
+ * - [1,2,3] and [1,2,3,4]
+ * - [1,1,1] and [1,2,3]
+ * */
+
+function _uniqContentEquals(aIterator, bIterator, stackA, stackB) {
+  var a = _arrayFromIterator(aIterator);
+  var b = _arrayFromIterator(bIterator);
+
+  function eq(_a, _b) {
+    return _equals(_a, _b, stackA.slice(), stackB.slice());
+  }
+
+  // if *a* array contains any element that is not included in *b*
+  return !_includesWith(function(b, aItem) {
+    return !_includesWith(eq, aItem, b);
+  }, b, a);
+}
+
+function _equals(a, b, stackA, stackB) {
+  if (_objectIs$1(a, b)) {
+    return true;
+  }
+
+  var typeA = type(a);
+
+  if (typeA !== type(b)) {
+    return false;
+  }
+
+  if (a == null || b == null) {
+    return false;
+  }
+
+  if (typeof a['fantasy-land/equals'] === 'function' || typeof b['fantasy-land/equals'] === 'function') {
+    return typeof a['fantasy-land/equals'] === 'function' && a['fantasy-land/equals'](b) &&
+      typeof b['fantasy-land/equals'] === 'function' && b['fantasy-land/equals'](a);
+  }
+
+  if (typeof a.equals === 'function' || typeof b.equals === 'function') {
+    return typeof a.equals === 'function' && a.equals(b) &&
+      typeof b.equals === 'function' && b.equals(a);
+  }
+
+  switch (typeA) {
+    case 'Arguments':
+    case 'Array':
+    case 'Object':
+      if (typeof a.constructor === 'function' &&
+        _functionName(a.constructor) === 'Promise') {
+        return a === b;
+      }
+      break;
+    case 'Boolean':
+    case 'Number':
+    case 'String':
+      if (!(typeof a === typeof b && _objectIs$1(a.valueOf(), b.valueOf()))) {
+        return false;
+      }
+      break;
+    case 'Date':
+      if (!_objectIs$1(a.valueOf(), b.valueOf())) {
+        return false;
+      }
+      break;
+    case 'Error':
+      return a.name === b.name && a.message === b.message;
+    case 'RegExp':
+      if (!(a.source === b.source &&
+          a.global === b.global &&
+          a.ignoreCase === b.ignoreCase &&
+          a.multiline === b.multiline &&
+          a.sticky === b.sticky &&
+          a.unicode === b.unicode)) {
+        return false;
+      }
+      break;
+  }
+
+  var idx = stackA.length - 1;
+  while (idx >= 0) {
+    if (stackA[idx] === a) {
+      return stackB[idx] === b;
+    }
+    idx -= 1;
+  }
+
+  switch (typeA) {
+    case 'Map':
+      if (a.size !== b.size) {
+        return false;
+      }
+
+      return _uniqContentEquals(a.entries(), b.entries(), stackA.concat([a]), stackB.concat([b]));
+    case 'Set':
+      if (a.size !== b.size) {
+        return false;
+      }
+
+      return _uniqContentEquals(a.values(), b.values(), stackA.concat([a]), stackB.concat([b]));
+    case 'Arguments':
+    case 'Array':
+    case 'Object':
+    case 'Boolean':
+    case 'Number':
+    case 'String':
+    case 'Date':
+    case 'Error':
+    case 'RegExp':
+    case 'Int8Array':
+    case 'Uint8Array':
+    case 'Uint8ClampedArray':
+    case 'Int16Array':
+    case 'Uint16Array':
+    case 'Int32Array':
+    case 'Uint32Array':
+    case 'Float32Array':
+    case 'Float64Array':
+    case 'ArrayBuffer':
+      break;
+    default:
+      // Values of other types are only equal if identical.
+      return false;
+  }
+
+  var keysA = keys(a);
+  if (keysA.length !== keys(b).length) {
+    return false;
+  }
+
+  var extendedStackA = stackA.concat([a]);
+  var extendedStackB = stackB.concat([b]);
+
+  idx = keysA.length - 1;
+  while (idx >= 0) {
+    var key = keysA[idx];
+    if (!(_has(key, b) && _equals(b[key], a[key], extendedStackA, extendedStackB))) {
+      return false;
+    }
+    idx -= 1;
+  }
+  return true;
+}
+
+/**
+ * Returns `true` if its arguments are equivalent, `false` otherwise. Handles
+ * cyclical data structures.
+ *
+ * Dispatches symmetrically to the `equals` methods of both arguments, if
+ * present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category Relation
+ * @sig a -> b -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @example
+ *
+ *      R.equals(1, 1); //=> true
+ *      R.equals(1, '1'); //=> false
+ *      R.equals([1, 2, 3], [1, 2, 3]); //=> true
+ *
+ *      const a = {}; a.v = a;
+ *      const b = {}; b.v = b;
+ *      R.equals(a, b); //=> true
+ */
+var equals = _curry2(function equals(a, b) {
+  return _equals(a, b, [], []);
+});
+
+function _indexOf(list, a, idx) {
+  var inf, item;
+  // Array.prototype.indexOf doesn't exist below IE9
+  if (typeof list.indexOf === 'function') {
+    switch (typeof a) {
+      case 'number':
+        if (a === 0) {
+          // manually crawl the list to distinguish between +0 and -0
+          inf = 1 / a;
+          while (idx < list.length) {
+            item = list[idx];
+            if (item === 0 && 1 / item === inf) {
+              return idx;
+            }
+            idx += 1;
+          }
+          return -1;
+        } else if (a !== a) {
+          // NaN
+          while (idx < list.length) {
+            item = list[idx];
+            if (typeof item === 'number' && item !== item) {
+              return idx;
+            }
+            idx += 1;
+          }
+          return -1;
+        }
+        // non-zero numbers can utilise Set
+        return list.indexOf(a, idx);
+
+      // all these types can utilise Set
+      case 'string':
+      case 'boolean':
+      case 'function':
+      case 'undefined':
+        return list.indexOf(a, idx);
+
+      case 'object':
+        if (a === null) {
+          // null can utilise Set
+          return list.indexOf(a, idx);
+        }
+    }
+  }
+  // anything else not covered above, defer to R.equals
+  while (idx < list.length) {
+    if (equals(list[idx], a)) {
+      return idx;
+    }
+    idx += 1;
+  }
+  return -1;
+}
+
+function _includes(a, list) {
+  return _indexOf(list, a, 0) >= 0;
+}
+
+function _quote(s) {
+  var escaped = s
+    .replace(/\\/g, '\\\\')
+    .replace(/[\b]/g, '\\b')  // \b matches word boundary; [\b] matches backspace
+    .replace(/\f/g, '\\f')
+    .replace(/\n/g, '\\n')
+    .replace(/\r/g, '\\r')
+    .replace(/\t/g, '\\t')
+    .replace(/\v/g, '\\v')
+    .replace(/\0/g, '\\0');
+
+  return '"' + escaped.replace(/"/g, '\\"') + '"';
+}
+
+/**
+ * Polyfill from <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString>.
+ */
+var pad = function pad(n) { return (n < 10 ? '0' : '') + n; };
+
+var _toISOString = typeof Date.prototype.toISOString === 'function' ?
+  function _toISOString(d) {
+    return d.toISOString();
+  } :
+  function _toISOString(d) {
+    return (
+      d.getUTCFullYear() + '-' +
+      pad(d.getUTCMonth() + 1) + '-' +
+      pad(d.getUTCDate()) + 'T' +
+      pad(d.getUTCHours()) + ':' +
+      pad(d.getUTCMinutes()) + ':' +
+      pad(d.getUTCSeconds()) + '.' +
+      (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 'Z'
+    );
+  };
+
+function _complement(f) {
+  return function() {
+    return !f.apply(this, arguments);
+  };
+}
+
+function _filter(fn, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [];
+
+  while (idx < len) {
+    if (fn(list[idx])) {
+      result[result.length] = list[idx];
+    }
+    idx += 1;
+  }
+  return result;
+}
+
+function _isObject(x) {
+  return Object.prototype.toString.call(x) === '[object Object]';
+}
+
+function XFilter(f, xf) {
+  this.xf = xf;
+  this.f = f;
+}
+XFilter.prototype['@@transducer/init'] = _xfBase.init;
+XFilter.prototype['@@transducer/result'] = _xfBase.result;
+XFilter.prototype['@@transducer/step'] = function(result, input) {
+  return this.f(input) ? this.xf['@@transducer/step'](result, input) : result;
+};
+
+var _xfilter = _curry2(function _xfilter(f, xf) { return new XFilter(f, xf); });
+
+/**
+ * Takes a predicate and a `Filterable`, and returns a new filterable of the
+ * same type containing the members of the given filterable which satisfy the
+ * given predicate. Filterable objects include plain objects or any object
+ * that has a filter method such as `Array`.
+ *
+ * Dispatches to the `filter` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Filterable f => (a -> Boolean) -> f a -> f a
+ * @param {Function} pred
+ * @param {Array} filterable
+ * @return {Array} Filterable
+ * @see R.reject, R.transduce, R.addIndex
+ * @example
+ *
+ *      const isEven = n => n % 2 === 0;
+ *
+ *      R.filter(isEven, [1, 2, 3, 4]); //=> [2, 4]
+ *
+ *      R.filter(isEven, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4}
+ */
+var filter = _curry2(_dispatchable(['filter'], _xfilter, function(pred, filterable) {
+  return (
+    _isObject(filterable) ?
+      _reduce(function(acc, key) {
+        if (pred(filterable[key])) {
+          acc[key] = filterable[key];
+        }
+        return acc;
+      }, {}, keys(filterable)) :
+    // else
+      _filter(pred, filterable)
+  );
+}));
+
+/**
+ * The complement of [`filter`](#filter).
+ *
+ * Acts as a transducer if a transformer is given in list position. Filterable
+ * objects include plain objects or any object that has a filter method such
+ * as `Array`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Filterable f => (a -> Boolean) -> f a -> f a
+ * @param {Function} pred
+ * @param {Array} filterable
+ * @return {Array}
+ * @see R.filter, R.transduce, R.addIndex
+ * @example
+ *
+ *      const isOdd = (n) => n % 2 === 1;
+ *
+ *      R.reject(isOdd, [1, 2, 3, 4]); //=> [2, 4]
+ *
+ *      R.reject(isOdd, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4}
+ */
+var reject = _curry2(function reject(pred, filterable) {
+  return filter(_complement(pred), filterable);
+});
+
+function _toString(x, seen) {
+  var recur = function recur(y) {
+    var xs = seen.concat([x]);
+    return _includes(y, xs) ? '<Circular>' : _toString(y, xs);
+  };
+
+  //  mapPairs :: (Object, [String]) -> [String]
+  var mapPairs = function(obj, keys$$1) {
+    return _map(function(k) { return _quote(k) + ': ' + recur(obj[k]); }, keys$$1.slice().sort());
+  };
+
+  switch (Object.prototype.toString.call(x)) {
+    case '[object Arguments]':
+      return '(function() { return arguments; }(' + _map(recur, x).join(', ') + '))';
+    case '[object Array]':
+      return '[' + _map(recur, x).concat(mapPairs(x, reject(function(k) { return /^\d+$/.test(k); }, keys(x)))).join(', ') + ']';
+    case '[object Boolean]':
+      return typeof x === 'object' ? 'new Boolean(' + recur(x.valueOf()) + ')' : x.toString();
+    case '[object Date]':
+      return 'new Date(' + (isNaN(x.valueOf()) ? recur(NaN) : _quote(_toISOString(x))) + ')';
+    case '[object Null]':
+      return 'null';
+    case '[object Number]':
+      return typeof x === 'object' ? 'new Number(' + recur(x.valueOf()) + ')' : 1 / x === -Infinity ? '-0' : x.toString(10);
+    case '[object String]':
+      return typeof x === 'object' ? 'new String(' + recur(x.valueOf()) + ')' : _quote(x);
+    case '[object Undefined]':
+      return 'undefined';
+    default:
+      if (typeof x.toString === 'function') {
+        var repr = x.toString();
+        if (repr !== '[object Object]') {
+          return repr;
+        }
+      }
+      return '{' + mapPairs(x, keys(x)).join(', ') + '}';
+  }
+}
+
+/**
+ * Returns the string representation of the given value. `eval`'ing the output
+ * should result in a value equivalent to the input value. Many of the built-in
+ * `toString` methods do not satisfy this requirement.
+ *
+ * If the given value is an `[object Object]` with a `toString` method other
+ * than `Object.prototype.toString`, this method is invoked with no arguments
+ * to produce the return value. This means user-defined constructor functions
+ * can provide a suitable `toString` method. For example:
+ *
+ *     function Point(x, y) {
+ *       this.x = x;
+ *       this.y = y;
+ *     }
+ *
+ *     Point.prototype.toString = function() {
+ *       return 'new Point(' + this.x + ', ' + this.y + ')';
+ *     };
+ *
+ *     R.toString(new Point(1, 2)); //=> 'new Point(1, 2)'
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category String
+ * @sig * -> String
+ * @param {*} val
+ * @return {String}
+ * @example
+ *
+ *      R.toString(42); //=> '42'
+ *      R.toString('abc'); //=> '"abc"'
+ *      R.toString([1, 2, 3]); //=> '[1, 2, 3]'
+ *      R.toString({foo: 1, bar: 2, baz: 3}); //=> '{"bar": 2, "baz": 3, "foo": 1}'
+ *      R.toString(new Date('2001-02-03T04:05:06Z')); //=> 'new Date("2001-02-03T04:05:06.000Z")'
+ */
+var toString$1 = _curry1(function toString(val) { return _toString(val, []); });
+
+/**
+ * Returns the result of concatenating the given lists or strings.
+ *
+ * Note: `R.concat` expects both arguments to be of the same type,
+ * unlike the native `Array.prototype.concat` method. It will throw
+ * an error if you `concat` an Array with a non-Array value.
+ *
+ * Dispatches to the `concat` method of the first argument, if present.
+ * Can also concatenate two members of a [fantasy-land
+ * compatible semigroup](https://github.com/fantasyland/fantasy-land#semigroup).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a] -> [a]
+ * @sig String -> String -> String
+ * @param {Array|String} firstList The first list
+ * @param {Array|String} secondList The second list
+ * @return {Array|String} A list consisting of the elements of `firstList` followed by the elements of
+ * `secondList`.
+ *
+ * @example
+ *
+ *      R.concat('ABC', 'DEF'); // 'ABCDEF'
+ *      R.concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3]
+ *      R.concat([], []); //=> []
+ */
+var concat = _curry2(function concat(a, b) {
+  if (_isArray(a)) {
+    if (_isArray(b)) {
+      return a.concat(b);
+    }
+    throw new TypeError(toString$1(b) + ' is not an array');
+  }
+  if (_isString(a)) {
+    if (_isString(b)) {
+      return a + b;
+    }
+    throw new TypeError(toString$1(b) + ' is not a string');
+  }
+  if (a != null && _isFunction(a['fantasy-land/concat'])) {
+    return a['fantasy-land/concat'](b);
+  }
+  if (a != null && _isFunction(a.concat)) {
+    return a.concat(b);
+  }
+  throw new TypeError(toString$1(a) + ' does not have a method named "concat" or "fantasy-land/concat"');
+});
+
+/**
+ * Returns a function, `fn`, which encapsulates `if/else, if/else, ...` logic.
+ * `R.cond` takes a list of [predicate, transformer] pairs. All of the arguments
+ * to `fn` are applied to each of the predicates in turn until one returns a
+ * "truthy" value, at which point `fn` returns the result of applying its
+ * arguments to the corresponding transformer. If none of the predicates
+ * matches, `fn` returns undefined.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category Logic
+ * @sig [[(*... -> Boolean),(*... -> *)]] -> (*... -> *)
+ * @param {Array} pairs A list of [predicate, transformer]
+ * @return {Function}
+ * @see R.ifElse, R.unless, R.when
+ * @example
+ *
+ *      const fn = R.cond([
+ *        [R.equals(0),   R.always('water freezes at 0°C')],
+ *        [R.equals(100), R.always('water boils at 100°C')],
+ *        [R.T,           temp => 'nothing special happens at ' + temp + '°C']
+ *      ]);
+ *      fn(0); //=> 'water freezes at 0°C'
+ *      fn(50); //=> 'nothing special happens at 50°C'
+ *      fn(100); //=> 'water boils at 100°C'
+ */
+var cond = _curry1(function cond(pairs) {
+  var arity = reduce(
+    max,
+    0,
+    map(function(pair) { return pair[0].length; }, pairs)
+  );
+  return _arity(arity, function() {
+    var idx = 0;
+    while (idx < pairs.length) {
+      if (pairs[idx][0].apply(this, arguments)) {
+        return pairs[idx][1].apply(this, arguments);
+      }
+      idx += 1;
+    }
+  });
+});
+
+/**
+ * Wraps a constructor function inside a curried function that can be called
+ * with the same arguments and returns the same type. The arity of the function
+ * returned is specified to allow using variadic constructor functions.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.0
+ * @category Function
+ * @sig Number -> (* -> {*}) -> (* -> {*})
+ * @param {Number} n The arity of the constructor function.
+ * @param {Function} Fn The constructor function to wrap.
+ * @return {Function} A wrapped, curried constructor function.
+ * @example
+ *
+ *      // Variadic Constructor function
+ *      function Salad() {
+ *        this.ingredients = arguments;
+ *      }
+ *
+ *      Salad.prototype.recipe = function() {
+ *        const instructions = R.map(ingredient => 'Add a dollop of ' + ingredient, this.ingredients);
+ *        return R.join('\n', instructions);
+ *      };
+ *
+ *      const ThreeLayerSalad = R.constructN(3, Salad);
+ *
+ *      // Notice we no longer need the 'new' keyword, and the constructor is curried for 3 arguments.
+ *      const salad = ThreeLayerSalad('Mayonnaise')('Potato Chips')('Ketchup');
+ *
+ *      console.log(salad.recipe());
+ *      // Add a dollop of Mayonnaise
+ *      // Add a dollop of Potato Chips
+ *      // Add a dollop of Ketchup
+ */
+var constructN = _curry2(function constructN(n, Fn) {
+  if (n > 10) {
+    throw new Error('Constructor with greater than ten arguments');
+  }
+  if (n === 0) {
+    return function() { return new Fn(); };
+  }
+  return curry(nAry(n, function($0, $1, $2, $3, $4, $5, $6, $7, $8, $9) {
+    switch (arguments.length) {
+      case  1: return new Fn($0);
+      case  2: return new Fn($0, $1);
+      case  3: return new Fn($0, $1, $2);
+      case  4: return new Fn($0, $1, $2, $3);
+      case  5: return new Fn($0, $1, $2, $3, $4);
+      case  6: return new Fn($0, $1, $2, $3, $4, $5);
+      case  7: return new Fn($0, $1, $2, $3, $4, $5, $6);
+      case  8: return new Fn($0, $1, $2, $3, $4, $5, $6, $7);
+      case  9: return new Fn($0, $1, $2, $3, $4, $5, $6, $7, $8);
+      case 10: return new Fn($0, $1, $2, $3, $4, $5, $6, $7, $8, $9);
+    }
+  }));
+});
+
+/**
+ * Wraps a constructor function inside a curried function that can be called
+ * with the same arguments and returns the same type.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (* -> {*}) -> (* -> {*})
+ * @param {Function} fn The constructor function to wrap.
+ * @return {Function} A wrapped, curried constructor function.
+ * @see R.invoker
+ * @example
+ *
+ *      // Constructor function
+ *      function Animal(kind) {
+ *        this.kind = kind;
+ *      };
+ *      Animal.prototype.sighting = function() {
+ *        return "It's a " + this.kind + "!";
+ *      }
+ *
+ *      const AnimalConstructor = R.construct(Animal)
+ *
+ *      // Notice we no longer need the 'new' keyword:
+ *      AnimalConstructor('Pig'); //=> {"kind": "Pig", "sighting": function (){...}};
+ *
+ *      const animalTypes = ["Lion", "Tiger", "Bear"];
+ *      const animalSighting = R.invoker(0, 'sighting');
+ *      const sightNewAnimal = R.compose(animalSighting, AnimalConstructor);
+ *      R.map(sightNewAnimal, animalTypes); //=> ["It's a Lion!", "It's a Tiger!", "It's a Bear!"]
+ */
+var construct = _curry1(function construct(Fn) {
+  return constructN(Fn.length, Fn);
+});
+
+/**
+ * Returns `true` if the specified value is equal, in [`R.equals`](#equals)
+ * terms, to at least one element of the given list; `false` otherwise.
+ * Works also with strings.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Boolean
+ * @param {Object} a The item to compare against.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if an equivalent item is in the list, `false` otherwise.
+ * @see R.includes
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      R.contains(3, [1, 2, 3]); //=> true
+ *      R.contains(4, [1, 2, 3]); //=> false
+ *      R.contains({ name: 'Fred' }, [{ name: 'Fred' }]); //=> true
+ *      R.contains([42], [[42]]); //=> true
+ *      R.contains('ba', 'banana'); //=>true
+ */
+var contains$1 = _curry2(_includes);
+
+/**
+ * Accepts a converging function and a list of branching functions and returns
+ * a new function. The arity of the new function is the same as the arity of
+ * the longest branching function. When invoked, this new function is applied
+ * to some arguments, and each branching function is applied to those same
+ * arguments. The results of each branching function are passed as arguments
+ * to the converging function to produce the return value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.2
+ * @category Function
+ * @sig ((x1, x2, ...) -> z) -> [((a, b, ...) -> x1), ((a, b, ...) -> x2), ...] -> (a -> b -> ... -> z)
+ * @param {Function} after A function. `after` will be invoked with the return values of
+ *        `fn1` and `fn2` as its arguments.
+ * @param {Array} functions A list of functions.
+ * @return {Function} A new function.
+ * @see R.useWith
+ * @example
+ *
+ *      const average = R.converge(R.divide, [R.sum, R.length])
+ *      average([1, 2, 3, 4, 5, 6, 7]) //=> 4
+ *
+ *      const strangeConcat = R.converge(R.concat, [R.toUpper, R.toLower])
+ *      strangeConcat("Yodel") //=> "YODELyodel"
+ *
+ * @symb R.converge(f, [g, h])(a, b) = f(g(a, b), h(a, b))
+ */
+var converge = _curry2(function converge(after, fns) {
+  return curryN(reduce(max, 0, pluck('length', fns)), function() {
+    var args = arguments;
+    var context = this;
+    return after.apply(context, _map(function(fn) {
+      return fn.apply(context, args);
+    }, fns));
+  });
+});
+
+function XReduceBy(valueFn, valueAcc, keyFn, xf) {
+  this.valueFn = valueFn;
+  this.valueAcc = valueAcc;
+  this.keyFn = keyFn;
+  this.xf = xf;
+  this.inputs = {};
+}
+XReduceBy.prototype['@@transducer/init'] = _xfBase.init;
+XReduceBy.prototype['@@transducer/result'] = function(result) {
+  var key;
+  for (key in this.inputs) {
+    if (_has(key, this.inputs)) {
+      result = this.xf['@@transducer/step'](result, this.inputs[key]);
+      if (result['@@transducer/reduced']) {
+        result = result['@@transducer/value'];
+        break;
+      }
+    }
+  }
+  this.inputs = null;
+  return this.xf['@@transducer/result'](result);
+};
+XReduceBy.prototype['@@transducer/step'] = function(result, input) {
+  var key = this.keyFn(input);
+  this.inputs[key] = this.inputs[key] || [key, this.valueAcc];
+  this.inputs[key][1] = this.valueFn(this.inputs[key][1], input);
+  return result;
+};
+
+var _xreduceBy = _curryN(4, [],
+  function _xreduceBy(valueFn, valueAcc, keyFn, xf) {
+    return new XReduceBy(valueFn, valueAcc, keyFn, xf);
+  }
+);
+
+/**
+ * Groups the elements of the list according to the result of calling
+ * the String-returning function `keyFn` on each element and reduces the elements
+ * of each group to a single value via the reducer function `valueFn`.
+ *
+ * This function is basically a more general [`groupBy`](#groupBy) function.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category List
+ * @sig ((a, b) -> a) -> a -> (b -> String) -> [b] -> {String: a}
+ * @param {Function} valueFn The function that reduces the elements of each group to a single
+ *        value. Receives two values, accumulator for a particular group and the current element.
+ * @param {*} acc The (initial) accumulator value for each group.
+ * @param {Function} keyFn The function that maps the list's element into a key.
+ * @param {Array} list The array to group.
+ * @return {Object} An object with the output of `keyFn` for keys, mapped to the output of
+ *         `valueFn` for elements which produced that key when passed to `keyFn`.
+ * @see R.groupBy, R.reduce
+ * @example
+ *
+ *      const groupNames = (acc, {name}) => acc.concat(name)
+ *      const toGrade = ({score}) =>
+ *        score < 65 ? 'F' :
+ *        score < 70 ? 'D' :
+ *        score < 80 ? 'C' :
+ *        score < 90 ? 'B' : 'A'
+ *
+ *      var students = [
+ *        {name: 'Abby', score: 83},
+ *        {name: 'Bart', score: 62},
+ *        {name: 'Curt', score: 88},
+ *        {name: 'Dora', score: 92},
+ *      ]
+ *
+ *      reduceBy(groupNames, [], toGrade, students)
+ *      //=> {"A": ["Dora"], "B": ["Abby", "Curt"], "F": ["Bart"]}
+ */
+var reduceBy = _curryN(4, [], _dispatchable([], _xreduceBy,
+  function reduceBy(valueFn, valueAcc, keyFn, list) {
+    return _reduce(function(acc, elt) {
+      var key = keyFn(elt);
+      acc[key] = valueFn(_has(key, acc) ? acc[key] : valueAcc, elt);
+      return acc;
+    }, {}, list);
+  }));
+
+/**
+ * Counts the elements of a list according to how many match each value of a
+ * key generated by the supplied function. Returns an object mapping the keys
+ * produced by `fn` to the number of occurrences in the list. Note that all
+ * keys are coerced to strings because of how JavaScript objects work.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig (a -> String) -> [a] -> {*}
+ * @param {Function} fn The function used to map values to keys.
+ * @param {Array} list The list to count elements from.
+ * @return {Object} An object mapping keys to number of occurrences in the list.
+ * @example
+ *
+ *      const numbers = [1.0, 1.1, 1.2, 2.0, 3.0, 2.2];
+ *      R.countBy(Math.floor)(numbers);    //=> {'1': 3, '2': 2, '3': 1}
+ *
+ *      const letters = ['a', 'b', 'A', 'a', 'B', 'c'];
+ *      R.countBy(R.toLower)(letters);   //=> {'a': 3, 'b': 2, 'c': 1}
+ */
+var countBy = reduceBy(function(acc, elem) { return acc + 1; }, 0);
+
+/**
+ * Decrements its argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Math
+ * @sig Number -> Number
+ * @param {Number} n
+ * @return {Number} n - 1
+ * @see R.inc
+ * @example
+ *
+ *      R.dec(42); //=> 41
+ */
+var dec = add(-1);
+
+/**
+ * Returns the second argument if it is not `null`, `undefined` or `NaN`;
+ * otherwise the first argument is returned.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Logic
+ * @sig a -> b -> a | b
+ * @param {a} default The default value.
+ * @param {b} val `val` will be returned instead of `default` unless `val` is `null`, `undefined` or `NaN`.
+ * @return {*} The second value if it is not `null`, `undefined` or `NaN`, otherwise the default value
+ * @example
+ *
+ *      const defaultTo42 = R.defaultTo(42);
+ *
+ *      defaultTo42(null);  //=> 42
+ *      defaultTo42(undefined);  //=> 42
+ *      defaultTo42(false);  //=> false
+ *      defaultTo42('Ramda');  //=> 'Ramda'
+ *      // parseInt('string') results in NaN
+ *      defaultTo42(parseInt('string')); //=> 42
+ */
+var defaultTo = _curry2(function defaultTo(d, v) {
+  return v == null || v !== v ? d : v;
+});
+
+/**
+ * Makes a descending comparator function out of a function that returns a value
+ * that can be compared with `<` and `>`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Function
+ * @sig Ord b => (a -> b) -> a -> a -> Number
+ * @param {Function} fn A function of arity one that returns a value that can be compared
+ * @param {*} a The first item to be compared.
+ * @param {*} b The second item to be compared.
+ * @return {Number} `-1` if fn(a) > fn(b), `1` if fn(b) > fn(a), otherwise `0`
+ * @see R.ascend
+ * @example
+ *
+ *      const byAge = R.descend(R.prop('age'));
+ *      const people = [
+ *        { name: 'Emma', age: 70 },
+ *        { name: 'Peter', age: 78 },
+ *        { name: 'Mikhail', age: 62 },
+ *      ];
+ *      const peopleByOldestFirst = R.sort(byAge, people);
+ *        //=> [{ name: 'Peter', age: 78 }, { name: 'Emma', age: 70 }, { name: 'Mikhail', age: 62 }]
+ */
+var descend = _curry3(function descend(fn, a, b) {
+  var aa = fn(a);
+  var bb = fn(b);
+  return aa > bb ? -1 : aa < bb ? 1 : 0;
+});
+
+function _Set() {
+  /* globals Set */
+  this._nativeSet = typeof Set === 'function' ? new Set() : null;
+  this._items = {};
+}
+
+// until we figure out why jsdoc chokes on this
+// @param item The item to add to the Set
+// @returns {boolean} true if the item did not exist prior, otherwise false
+//
+_Set.prototype.add = function(item) {
+  return !hasOrAdd(item, true, this);
+};
+
+//
+// @param item The item to check for existence in the Set
+// @returns {boolean} true if the item exists in the Set, otherwise false
+//
+_Set.prototype.has = function(item) {
+  return hasOrAdd(item, false, this);
+};
+
+//
+// Combines the logic for checking whether an item is a member of the set and
+// for adding a new item to the set.
+//
+// @param item       The item to check or add to the Set instance.
+// @param shouldAdd  If true, the item will be added to the set if it doesn't
+//                   already exist.
+// @param set        The set instance to check or add to.
+// @return {boolean} true if the item already existed, otherwise false.
+//
+function hasOrAdd(item, shouldAdd, set) {
+  var type = typeof item;
+  var prevSize, newSize;
+  switch (type) {
+    case 'string':
+    case 'number':
+      // distinguish between +0 and -0
+      if (item === 0 && 1 / item === -Infinity) {
+        if (set._items['-0']) {
+          return true;
+        } else {
+          if (shouldAdd) {
+            set._items['-0'] = true;
+          }
+          return false;
+        }
+      }
+      // these types can all utilise the native Set
+      if (set._nativeSet !== null) {
+        if (shouldAdd) {
+          prevSize = set._nativeSet.size;
+          set._nativeSet.add(item);
+          newSize = set._nativeSet.size;
+          return newSize === prevSize;
+        } else {
+          return set._nativeSet.has(item);
+        }
+      } else {
+        if (!(type in set._items)) {
+          if (shouldAdd) {
+            set._items[type] = {};
+            set._items[type][item] = true;
+          }
+          return false;
+        } else if (item in set._items[type]) {
+          return true;
+        } else {
+          if (shouldAdd) {
+            set._items[type][item] = true;
+          }
+          return false;
+        }
+      }
+
+    case 'boolean':
+      // set._items['boolean'] holds a two element array
+      // representing [ falseExists, trueExists ]
+      if (type in set._items) {
+        var bIdx = item ? 1 : 0;
+        if (set._items[type][bIdx]) {
+          return true;
+        } else {
+          if (shouldAdd) {
+            set._items[type][bIdx] = true;
+          }
+          return false;
+        }
+      } else {
+        if (shouldAdd) {
+          set._items[type] = item ? [false, true] : [true, false];
+        }
+        return false;
+      }
+
+    case 'function':
+      // compare functions for reference equality
+      if (set._nativeSet !== null) {
+        if (shouldAdd) {
+          prevSize = set._nativeSet.size;
+          set._nativeSet.add(item);
+          newSize = set._nativeSet.size;
+          return newSize === prevSize;
+        } else {
+          return set._nativeSet.has(item);
+        }
+      } else {
+        if (!(type in set._items)) {
+          if (shouldAdd) {
+            set._items[type] = [item];
+          }
+          return false;
+        }
+        if (!_includes(item, set._items[type])) {
+          if (shouldAdd) {
+            set._items[type].push(item);
+          }
+          return false;
+        }
+        return true;
+      }
+
+    case 'undefined':
+      if (set._items[type]) {
+        return true;
+      } else {
+        if (shouldAdd) {
+          set._items[type] = true;
+        }
+        return false;
+      }
+
+    case 'object':
+      if (item === null) {
+        if (!set._items['null']) {
+          if (shouldAdd) {
+            set._items['null'] = true;
+          }
+          return false;
+        }
+        return true;
+      }
+    /* falls through */
+    default:
+      // reduce the search size of heterogeneous sets by creating buckets
+      // for each type.
+      type = Object.prototype.toString.call(item);
+      if (!(type in set._items)) {
+        if (shouldAdd) {
+          set._items[type] = [item];
+        }
+        return false;
+      }
+      // scan through all previously applied items
+      if (!_includes(item, set._items[type])) {
+        if (shouldAdd) {
+          set._items[type].push(item);
+        }
+        return false;
+      }
+      return true;
+  }
+}
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements in the first list not
+ * contained in the second list. Objects and Arrays are compared in terms of
+ * value equality, not reference equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` that are not in `list2`.
+ * @see R.differenceWith, R.symmetricDifference, R.symmetricDifferenceWith, R.without
+ * @example
+ *
+ *      R.difference([1,2,3,4], [7,6,5,4,3]); //=> [1,2]
+ *      R.difference([7,6,5,4,3], [1,2,3,4]); //=> [7,6,5]
+ *      R.difference([{a: 1}, {b: 2}], [{a: 1}, {c: 3}]) //=> [{b: 2}]
+ */
+var difference = _curry2(function difference(first, second) {
+  var out = [];
+  var idx = 0;
+  var firstLen = first.length;
+  var secondLen = second.length;
+  var toFilterOut = new _Set();
+
+  for (var i = 0; i < secondLen; i += 1) {
+    toFilterOut.add(second[i]);
+  }
+
+  while (idx < firstLen) {
+    if (toFilterOut.add(first[idx])) {
+      out[out.length] = first[idx];
+    }
+    idx += 1;
+  }
+  return out;
+});
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements in the first list not
+ * contained in the second list. Duplication is determined according to the
+ * value returned by applying the supplied predicate to two list elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig ((a, a) -> Boolean) -> [a] -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` that are not in `list2`.
+ * @see R.difference, R.symmetricDifference, R.symmetricDifferenceWith
+ * @example
+ *
+ *      const cmp = (x, y) => x.a === y.a;
+ *      const l1 = [{a: 1}, {a: 2}, {a: 3}];
+ *      const l2 = [{a: 3}, {a: 4}];
+ *      R.differenceWith(cmp, l1, l2); //=> [{a: 1}, {a: 2}]
+ */
+var differenceWith = _curry3(function differenceWith(pred, first, second) {
+  var out = [];
+  var idx = 0;
+  var firstLen = first.length;
+  while (idx < firstLen) {
+    if (!_includesWith(pred, first[idx], second) &&
+        !_includesWith(pred, first[idx], out)) {
+      out.push(first[idx]);
+    }
+    idx += 1;
+  }
+  return out;
+});
+
+/**
+ * Returns a new object that does not contain a `prop` property.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Object
+ * @sig String -> {k: v} -> {k: v}
+ * @param {String} prop The name of the property to dissociate
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object equivalent to the original but without the specified property
+ * @see R.assoc, R.omit
+ * @example
+ *
+ *      R.dissoc('b', {a: 1, b: 2, c: 3}); //=> {a: 1, c: 3}
+ */
+var dissoc = _curry2(function dissoc(prop, obj) {
+  var result = {};
+  for (var p in obj) {
+    result[p] = obj[p];
+  }
+  delete result[prop];
+  return result;
+});
+
+/**
+ * Removes the sub-list of `list` starting at index `start` and containing
+ * `count` elements. _Note that this is not destructive_: it returns a copy of
+ * the list with the changes.
+ * <small>No lists have been harmed in the application of this function.</small>
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.2
+ * @category List
+ * @sig Number -> Number -> [a] -> [a]
+ * @param {Number} start The position to start removing elements
+ * @param {Number} count The number of elements to remove
+ * @param {Array} list The list to remove from
+ * @return {Array} A new Array with `count` elements from `start` removed.
+ * @see R.without
+ * @example
+ *
+ *      R.remove(2, 3, [1,2,3,4,5,6,7,8]); //=> [1,2,6,7,8]
+ */
+var remove = _curry3(function remove(start, count, list) {
+  var result = Array.prototype.slice.call(list, 0);
+  result.splice(start, count);
+  return result;
+});
+
+/**
+ * Returns a new copy of the array with the element at the provided index
+ * replaced with the given value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig Number -> a -> [a] -> [a]
+ * @param {Number} idx The index to update.
+ * @param {*} x The value to exist at the given index of the returned array.
+ * @param {Array|Arguments} list The source array-like object to be updated.
+ * @return {Array} A copy of `list` with the value at index `idx` replaced with `x`.
+ * @see R.adjust
+ * @example
+ *
+ *      R.update(1, '_', ['a', 'b', 'c']);      //=> ['a', '_', 'c']
+ *      R.update(-1, '_', ['a', 'b', 'c']);     //=> ['a', 'b', '_']
+ * @symb R.update(-1, a, [b, c]) = [b, a]
+ * @symb R.update(0, a, [b, c]) = [a, c]
+ * @symb R.update(1, a, [b, c]) = [b, a]
+ */
+var update = _curry3(function update(idx, x, list) {
+  return adjust(idx, always(x), list);
+});
+
+/**
+ * Makes a shallow clone of an object, omitting the property at the given path.
+ * Note that this copies and flattens prototype properties onto the new object
+ * as well. All non-primitive properties are copied by reference.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.11.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> {k: v} -> {k: v}
+ * @param {Array} path The path to the value to omit
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object without the property at path
+ * @see R.assocPath
+ * @example
+ *
+ *      R.dissocPath(['a', 'b', 'c'], {a: {b: {c: 42}}}); //=> {a: {b: {}}}
+ */
+var dissocPath = _curry2(function dissocPath(path, obj) {
+  switch (path.length) {
+    case 0:
+      return obj;
+    case 1:
+      return _isInteger(path[0]) && _isArray(obj) ? remove(path[0], 1, obj) : dissoc(path[0], obj);
+    default:
+      var head = path[0];
+      var tail = Array.prototype.slice.call(path, 1);
+      if (obj[head] == null) {
+        return obj;
+      } else if (_isInteger(head) && _isArray(obj)) {
+        return update(head, dissocPath(tail, obj[head]), obj);
+      } else {
+        return assoc(head, dissocPath(tail, obj[head]), obj);
+      }
+  }
+});
+
+/**
+ * Divides two numbers. Equivalent to `a / b`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The first value.
+ * @param {Number} b The second value.
+ * @return {Number} The result of `a / b`.
+ * @see R.multiply
+ * @example
+ *
+ *      R.divide(71, 100); //=> 0.71
+ *
+ *      const half = R.divide(R.__, 2);
+ *      half(42); //=> 21
+ *
+ *      const reciprocal = R.divide(1);
+ *      reciprocal(4);   //=> 0.25
+ */
+var divide = _curry2(function divide(a, b) { return a / b; });
+
+function XDrop(n, xf) {
+  this.xf = xf;
+  this.n = n;
+}
+XDrop.prototype['@@transducer/init'] = _xfBase.init;
+XDrop.prototype['@@transducer/result'] = _xfBase.result;
+XDrop.prototype['@@transducer/step'] = function(result, input) {
+  if (this.n > 0) {
+    this.n -= 1;
+    return result;
+  }
+  return this.xf['@@transducer/step'](result, input);
+};
+
+var _xdrop = _curry2(function _xdrop(n, xf) { return new XDrop(n, xf); });
+
+/**
+ * Returns all but the first `n` elements of the given list, string, or
+ * transducer/transformer (or object with a `drop` method).
+ *
+ * Dispatches to the `drop` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n
+ * @param {*} list
+ * @return {*} A copy of list without the first `n` elements
+ * @see R.take, R.transduce, R.dropLast, R.dropWhile
+ * @example
+ *
+ *      R.drop(1, ['foo', 'bar', 'baz']); //=> ['bar', 'baz']
+ *      R.drop(2, ['foo', 'bar', 'baz']); //=> ['baz']
+ *      R.drop(3, ['foo', 'bar', 'baz']); //=> []
+ *      R.drop(4, ['foo', 'bar', 'baz']); //=> []
+ *      R.drop(3, 'ramda');               //=> 'da'
+ */
+var drop = _curry2(_dispatchable(['drop'], _xdrop, function drop(n, xs) {
+  return slice(Math.max(0, n), Infinity, xs);
+}));
+
+function XTake(n, xf) {
+  this.xf = xf;
+  this.n = n;
+  this.i = 0;
+}
+XTake.prototype['@@transducer/init'] = _xfBase.init;
+XTake.prototype['@@transducer/result'] = _xfBase.result;
+XTake.prototype['@@transducer/step'] = function(result, input) {
+  this.i += 1;
+  var ret = this.n === 0 ? result : this.xf['@@transducer/step'](result, input);
+  return this.n >= 0 && this.i >= this.n ? _reduced(ret) : ret;
+};
+
+var _xtake = _curry2(function _xtake(n, xf) { return new XTake(n, xf); });
+
+/**
+ * Returns the first `n` elements of the given list, string, or
+ * transducer/transformer (or object with a `take` method).
+ *
+ * Dispatches to the `take` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n
+ * @param {*} list
+ * @return {*}
+ * @see R.drop
+ * @example
+ *
+ *      R.take(1, ['foo', 'bar', 'baz']); //=> ['foo']
+ *      R.take(2, ['foo', 'bar', 'baz']); //=> ['foo', 'bar']
+ *      R.take(3, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.take(4, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.take(3, 'ramda');               //=> 'ram'
+ *
+ *      const personnel = [
+ *        'Dave Brubeck',
+ *        'Paul Desmond',
+ *        'Eugene Wright',
+ *        'Joe Morello',
+ *        'Gerry Mulligan',
+ *        'Bob Bates',
+ *        'Joe Dodge',
+ *        'Ron Crotty'
+ *      ];
+ *
+ *      const takeFive = R.take(5);
+ *      takeFive(personnel);
+ *      //=> ['Dave Brubeck', 'Paul Desmond', 'Eugene Wright', 'Joe Morello', 'Gerry Mulligan']
+ * @symb R.take(-1, [a, b]) = [a, b]
+ * @symb R.take(0, [a, b]) = []
+ * @symb R.take(1, [a, b]) = [a]
+ * @symb R.take(2, [a, b]) = [a, b]
+ */
+var take = _curry2(_dispatchable(['take'], _xtake, function take(n, xs) {
+  return slice(0, n < 0 ? Infinity : n, xs);
+}));
+
+function dropLast$2(n, xs) {
+  return take(n < xs.length ? xs.length - n : 0, xs);
+}
+
+function XDropLast(n, xf) {
+  this.xf = xf;
+  this.pos = 0;
+  this.full = false;
+  this.acc = new Array(n);
+}
+XDropLast.prototype['@@transducer/init'] = _xfBase.init;
+XDropLast.prototype['@@transducer/result'] =  function(result) {
+  this.acc = null;
+  return this.xf['@@transducer/result'](result);
+};
+XDropLast.prototype['@@transducer/step'] = function(result, input) {
+  if (this.full) {
+    result = this.xf['@@transducer/step'](result, this.acc[this.pos]);
+  }
+  this.store(input);
+  return result;
+};
+XDropLast.prototype.store = function(input) {
+  this.acc[this.pos] = input;
+  this.pos += 1;
+  if (this.pos === this.acc.length) {
+    this.pos = 0;
+    this.full = true;
+  }
+};
+
+var _xdropLast = _curry2(function _xdropLast(n, xf) { return new XDropLast(n, xf); });
+
+/**
+ * Returns a list containing all but the last `n` elements of the given `list`.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n The number of elements of `list` to skip.
+ * @param {Array} list The list of elements to consider.
+ * @return {Array} A copy of the list with only the first `list.length - n` elements
+ * @see R.takeLast, R.drop, R.dropWhile, R.dropLastWhile
+ * @example
+ *
+ *      R.dropLast(1, ['foo', 'bar', 'baz']); //=> ['foo', 'bar']
+ *      R.dropLast(2, ['foo', 'bar', 'baz']); //=> ['foo']
+ *      R.dropLast(3, ['foo', 'bar', 'baz']); //=> []
+ *      R.dropLast(4, ['foo', 'bar', 'baz']); //=> []
+ *      R.dropLast(3, 'ramda');               //=> 'ra'
+ */
+var dropLast = _curry2(_dispatchable([], _xdropLast, dropLast$2));
+
+function dropLastWhile$2(pred, xs) {
+  var idx = xs.length - 1;
+  while (idx >= 0 && pred(xs[idx])) {
+    idx -= 1;
+  }
+  return slice(0, idx + 1, xs);
+}
+
+function XDropLastWhile(fn, xf) {
+  this.f = fn;
+  this.retained = [];
+  this.xf = xf;
+}
+XDropLastWhile.prototype['@@transducer/init'] = _xfBase.init;
+XDropLastWhile.prototype['@@transducer/result'] = function(result) {
+  this.retained = null;
+  return this.xf['@@transducer/result'](result);
+};
+XDropLastWhile.prototype['@@transducer/step'] = function(result, input) {
+  return this.f(input)
+    ? this.retain(result, input)
+    : this.flush(result, input);
+};
+XDropLastWhile.prototype.flush = function(result, input) {
+  result = _reduce(
+    this.xf['@@transducer/step'],
+    result,
+    this.retained
+  );
+  this.retained = [];
+  return this.xf['@@transducer/step'](result, input);
+};
+XDropLastWhile.prototype.retain = function(result, input) {
+  this.retained.push(input);
+  return result;
+};
+
+var _xdropLastWhile = _curry2(function _xdropLastWhile(fn, xf) { return new XDropLastWhile(fn, xf); });
+
+/**
+ * Returns a new list excluding all the tailing elements of a given list which
+ * satisfy the supplied predicate function. It passes each value from the right
+ * to the supplied predicate function, skipping elements until the predicate
+ * function returns a `falsy` value. The predicate function is applied to one argument:
+ * *(value)*.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} predicate The function to be called on each element
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array without any trailing elements that return `falsy` values from the `predicate`.
+ * @see R.takeLastWhile, R.addIndex, R.drop, R.dropWhile
+ * @example
+ *
+ *      const lteThree = x => x <= 3;
+ *
+ *      R.dropLastWhile(lteThree, [1, 2, 3, 4, 3, 2, 1]); //=> [1, 2, 3, 4]
+ *
+ *      R.dropLastWhile(x => x !== 'd' , 'Ramda'); //=> 'Ramd'
+ */
+var dropLastWhile = _curry2(_dispatchable([], _xdropLastWhile, dropLastWhile$2));
+
+function XDropRepeatsWith(pred, xf) {
+  this.xf = xf;
+  this.pred = pred;
+  this.lastValue = undefined;
+  this.seenFirstValue = false;
+}
+
+XDropRepeatsWith.prototype['@@transducer/init'] = _xfBase.init;
+XDropRepeatsWith.prototype['@@transducer/result'] = _xfBase.result;
+XDropRepeatsWith.prototype['@@transducer/step'] = function(result, input) {
+  var sameAsLast = false;
+  if (!this.seenFirstValue) {
+    this.seenFirstValue = true;
+  } else if (this.pred(this.lastValue, input)) {
+    sameAsLast = true;
+  }
+  this.lastValue = input;
+  return sameAsLast ? result : this.xf['@@transducer/step'](result, input);
+};
+
+var _xdropRepeatsWith = _curry2(function _xdropRepeatsWith(pred, xf) { return new XDropRepeatsWith(pred, xf); });
+
+/**
+ * Returns the last element of the given list or string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.4
+ * @category List
+ * @sig [a] -> a | Undefined
+ * @sig String -> String
+ * @param {*} list
+ * @return {*}
+ * @see R.init, R.head, R.tail
+ * @example
+ *
+ *      R.last(['fi', 'fo', 'fum']); //=> 'fum'
+ *      R.last([]); //=> undefined
+ *
+ *      R.last('abc'); //=> 'c'
+ *      R.last(''); //=> ''
+ */
+var last = nth(-1);
+
+/**
+ * Returns a new list without any consecutively repeating elements. Equality is
+ * determined by applying the supplied predicate to each pair of consecutive elements. The
+ * first element in a series of equal elements will be preserved.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig ((a, a) -> Boolean) -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list The array to consider.
+ * @return {Array} `list` without repeating elements.
+ * @see R.transduce
+ * @example
+ *
+ *      const l = [1, -1, 1, 3, 4, -4, -4, -5, 5, 3, 3];
+ *      R.dropRepeatsWith(R.eqBy(Math.abs), l); //=> [1, 3, 4, -5, 3]
+ */
+var dropRepeatsWith = _curry2(_dispatchable([], _xdropRepeatsWith, function dropRepeatsWith(pred, list) {
+  var result = [];
+  var idx = 1;
+  var len = list.length;
+  if (len !== 0) {
+    result[0] = list[0];
+    while (idx < len) {
+      if (!pred(last(result), list[idx])) {
+        result[result.length] = list[idx];
+      }
+      idx += 1;
+    }
+  }
+  return result;
+}));
+
+/**
+ * Returns a new list without any consecutively repeating elements.
+ * [`R.equals`](#equals) is used to determine equality.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig [a] -> [a]
+ * @param {Array} list The array to consider.
+ * @return {Array} `list` without repeating elements.
+ * @see R.transduce
+ * @example
+ *
+ *     R.dropRepeats([1, 1, 1, 2, 3, 4, 4, 2, 2]); //=> [1, 2, 3, 4, 2]
+ */
+var dropRepeats = _curry1(
+  _dispatchable([], _xdropRepeatsWith(equals), dropRepeatsWith(equals))
+);
+
+function XDropWhile(f, xf) {
+  this.xf = xf;
+  this.f = f;
+}
+XDropWhile.prototype['@@transducer/init'] = _xfBase.init;
+XDropWhile.prototype['@@transducer/result'] = _xfBase.result;
+XDropWhile.prototype['@@transducer/step'] = function(result, input) {
+  if (this.f) {
+    if (this.f(input)) {
+      return result;
+    }
+    this.f = null;
+  }
+  return this.xf['@@transducer/step'](result, input);
+};
+
+var _xdropWhile = _curry2(function _xdropWhile(f, xf) { return new XDropWhile(f, xf); });
+
+/**
+ * Returns a new list excluding the leading elements of a given list which
+ * satisfy the supplied predicate function. It passes each value to the supplied
+ * predicate function, skipping elements while the predicate function returns
+ * `true`. The predicate function is applied to one argument: *(value)*.
+ *
+ * Dispatches to the `dropWhile` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} fn The function called per iteration.
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array.
+ * @see R.takeWhile, R.transduce, R.addIndex
+ * @example
+ *
+ *      const lteTwo = x => x <= 2;
+ *
+ *      R.dropWhile(lteTwo, [1, 2, 3, 4, 3, 2, 1]); //=> [3, 4, 3, 2, 1]
+ *
+ *      R.dropWhile(x => x !== 'd' , 'Ramda'); //=> 'da'
+ */
+var dropWhile = _curry2(_dispatchable(['dropWhile'], _xdropWhile, function dropWhile(pred, xs) {
+  var idx = 0;
+  var len = xs.length;
+  while (idx < len && pred(xs[idx])) {
+    idx += 1;
+  }
+  return slice(idx, Infinity, xs);
+}));
+
+/**
+ * Returns `true` if one or both of its arguments are `true`. Returns `false`
+ * if both arguments are `false`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig a -> b -> a | b
+ * @param {Any} a
+ * @param {Any} b
+ * @return {Any} the first argument if truthy, otherwise the second argument.
+ * @see R.either
+ * @example
+ *
+ *      R.or(true, true); //=> true
+ *      R.or(true, false); //=> true
+ *      R.or(false, true); //=> true
+ *      R.or(false, false); //=> false
+ */
+var or = _curry2(function or(a, b) {
+  return a || b;
+});
+
+/**
+ * A function wrapping calls to the two functions in an `||` operation,
+ * returning the result of the first function if it is truth-y and the result
+ * of the second function otherwise. Note that this is short-circuited,
+ * meaning that the second function will not be invoked if the first returns a
+ * truth-y value.
+ *
+ * In addition to functions, `R.either` also accepts any fantasy-land compatible
+ * applicative functor.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category Logic
+ * @sig (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
+ * @param {Function} f a predicate
+ * @param {Function} g another predicate
+ * @return {Function} a function that applies its arguments to `f` and `g` and `||`s their outputs together.
+ * @see R.or
+ * @example
+ *
+ *      const gt10 = x => x > 10;
+ *      const even = x => x % 2 === 0;
+ *      const f = R.either(gt10, even);
+ *      f(101); //=> true
+ *      f(8); //=> true
+ *
+ *      R.either(Maybe.Just(false), Maybe.Just(55)); // => Maybe.Just(55)
+ *      R.either([false, false, 'a'], [11]) // => [11, 11, "a"]
+ */
+var either = _curry2(function either(f, g) {
+  return _isFunction(f) ?
+    function _either() {
+      return f.apply(this, arguments) || g.apply(this, arguments);
+    } :
+    lift(or)(f, g);
+});
+
+/**
+ * Returns the empty value of its argument's type. Ramda defines the empty
+ * value of Array (`[]`), Object (`{}`), String (`''`), and Arguments. Other
+ * types are supported if they define `<Type>.empty`,
+ * `<Type>.prototype.empty` or implement the
+ * [FantasyLand Monoid spec](https://github.com/fantasyland/fantasy-land#monoid).
+ *
+ * Dispatches to the `empty` method of the first argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Function
+ * @sig a -> a
+ * @param {*} x
+ * @return {*}
+ * @example
+ *
+ *      R.empty(Just(42));      //=> Nothing()
+ *      R.empty([1, 2, 3]);     //=> []
+ *      R.empty('unicorns');    //=> ''
+ *      R.empty({x: 1, y: 2});  //=> {}
+ */
+var empty = _curry1(function empty(x) {
+  return (
+    (x != null && typeof x['fantasy-land/empty'] === 'function')
+      ? x['fantasy-land/empty']()
+      : (x != null && x.constructor != null && typeof x.constructor['fantasy-land/empty'] === 'function')
+        ? x.constructor['fantasy-land/empty']()
+        : (x != null && typeof x.empty === 'function')
+          ? x.empty()
+          : (x != null && x.constructor != null && typeof x.constructor.empty === 'function')
+            ? x.constructor.empty()
+            : _isArray(x)
+              ? []
+              : _isString(x)
+                ? ''
+                : _isObject(x)
+                  ? {}
+                  : _isArguments(x)
+                    ? (function() { return arguments; }())
+                    : void 0  // else
+  );
+});
+
+/**
+ * Returns a new list containing the last `n` elements of the given list.
+ * If `n > list.length`, returns a list of `list.length` elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n The number of elements to return.
+ * @param {Array} xs The collection to consider.
+ * @return {Array}
+ * @see R.dropLast
+ * @example
+ *
+ *      R.takeLast(1, ['foo', 'bar', 'baz']); //=> ['baz']
+ *      R.takeLast(2, ['foo', 'bar', 'baz']); //=> ['bar', 'baz']
+ *      R.takeLast(3, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.takeLast(4, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.takeLast(3, 'ramda');               //=> 'mda'
+ */
+var takeLast = _curry2(function takeLast(n, xs) {
+  return drop(n >= 0 ? xs.length - n : 0, xs);
+});
+
+/**
+ * Checks if a list ends with the provided sublist.
+ *
+ * Similarly, checks if a string ends with the provided substring.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category List
+ * @sig [a] -> [a] -> Boolean
+ * @sig String -> String -> Boolean
+ * @param {*} suffix
+ * @param {*} list
+ * @return {Boolean}
+ * @see R.startsWith
+ * @example
+ *
+ *      R.endsWith('c', 'abc')                //=> true
+ *      R.endsWith('b', 'abc')                //=> false
+ *      R.endsWith(['c'], ['a', 'b', 'c'])    //=> true
+ *      R.endsWith(['b'], ['a', 'b', 'c'])    //=> false
+ */
+var endsWith = _curry2(function(suffix, list) {
+  return equals(takeLast(suffix.length, list), suffix);
+});
+
+/**
+ * Takes a function and two values in its domain and returns `true` if the
+ * values map to the same value in the codomain; `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Relation
+ * @sig (a -> b) -> a -> a -> Boolean
+ * @param {Function} f
+ * @param {*} x
+ * @param {*} y
+ * @return {Boolean}
+ * @example
+ *
+ *      R.eqBy(Math.abs, 5, -5); //=> true
+ */
+var eqBy = _curry3(function eqBy(f, x, y) {
+  return equals(f(x), f(y));
+});
+
+/**
+ * Reports whether two objects have the same value, in [`R.equals`](#equals)
+ * terms, for the specified property. Useful as a curried predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig k -> {k: v} -> {k: v} -> Boolean
+ * @param {String} prop The name of the property to compare
+ * @param {Object} obj1
+ * @param {Object} obj2
+ * @return {Boolean}
+ *
+ * @example
+ *
+ *      const o1 = { a: 1, b: 2, c: 3, d: 4 };
+ *      const o2 = { a: 10, b: 20, c: 3, d: 40 };
+ *      R.eqProps('a', o1, o2); //=> false
+ *      R.eqProps('c', o1, o2); //=> true
+ */
+var eqProps = _curry3(function eqProps(prop, obj1, obj2) {
+  return equals(obj1[prop], obj2[prop]);
+});
+
+/**
+ * Creates a new object by recursively evolving a shallow copy of `object`,
+ * according to the `transformation` functions. All non-primitive properties
+ * are copied by reference.
+ *
+ * A `transformation` function will not be invoked if its corresponding key
+ * does not exist in the evolved object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig {k: (v -> v)} -> {k: v} -> {k: v}
+ * @param {Object} transformations The object specifying transformation functions to apply
+ *        to the object.
+ * @param {Object} object The object to be transformed.
+ * @return {Object} The transformed object.
+ * @example
+ *
+ *      const tomato = {firstName: '  Tomato ', data: {elapsed: 100, remaining: 1400}, id:123};
+ *      const transformations = {
+ *        firstName: R.trim,
+ *        lastName: R.trim, // Will not get invoked.
+ *        data: {elapsed: R.add(1), remaining: R.add(-1)}
+ *      };
+ *      R.evolve(transformations, tomato); //=> {firstName: 'Tomato', data: {elapsed: 101, remaining: 1399}, id:123}
+ */
+var evolve = _curry2(function evolve(transformations, object) {
+  var result = object instanceof Array ? [] : {};
+  var transformation, key, type;
+  for (key in object) {
+    transformation = transformations[key];
+    type = typeof transformation;
+    result[key] = type === 'function'
+      ? transformation(object[key])
+      : transformation && type === 'object'
+        ? evolve(transformation, object[key])
+        : object[key];
+  }
+  return result;
+});
+
+function XFind(f, xf) {
+  this.xf = xf;
+  this.f = f;
+  this.found = false;
+}
+XFind.prototype['@@transducer/init'] = _xfBase.init;
+XFind.prototype['@@transducer/result'] = function(result) {
+  if (!this.found) {
+    result = this.xf['@@transducer/step'](result, void 0);
+  }
+  return this.xf['@@transducer/result'](result);
+};
+XFind.prototype['@@transducer/step'] = function(result, input) {
+  if (this.f(input)) {
+    this.found = true;
+    result = _reduced(this.xf['@@transducer/step'](result, input));
+  }
+  return result;
+};
+
+var _xfind = _curry2(function _xfind(f, xf) { return new XFind(f, xf); });
+
+/**
+ * Returns the first element of the list which matches the predicate, or
+ * `undefined` if no element matches.
+ *
+ * Dispatches to the `find` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> a | undefined
+ * @param {Function} fn The predicate function used to determine if the element is the
+ *        desired one.
+ * @param {Array} list The array to consider.
+ * @return {Object} The element found, or `undefined`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1}, {a: 2}, {a: 3}];
+ *      R.find(R.propEq('a', 2))(xs); //=> {a: 2}
+ *      R.find(R.propEq('a', 4))(xs); //=> undefined
+ */
+var find = _curry2(_dispatchable(['find'], _xfind, function find(fn, list) {
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    if (fn(list[idx])) {
+      return list[idx];
+    }
+    idx += 1;
+  }
+}));
+
+function XFindIndex(f, xf) {
+  this.xf = xf;
+  this.f = f;
+  this.idx = -1;
+  this.found = false;
+}
+XFindIndex.prototype['@@transducer/init'] = _xfBase.init;
+XFindIndex.prototype['@@transducer/result'] = function(result) {
+  if (!this.found) {
+    result = this.xf['@@transducer/step'](result, -1);
+  }
+  return this.xf['@@transducer/result'](result);
+};
+XFindIndex.prototype['@@transducer/step'] = function(result, input) {
+  this.idx += 1;
+  if (this.f(input)) {
+    this.found = true;
+    result = _reduced(this.xf['@@transducer/step'](result, this.idx));
+  }
+  return result;
+};
+
+var _xfindIndex = _curry2(function _xfindIndex(f, xf) { return new XFindIndex(f, xf); });
+
+/**
+ * Returns the index of the first element of the list which matches the
+ * predicate, or `-1` if no element matches.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Number
+ * @param {Function} fn The predicate function used to determine if the element is the
+ * desired one.
+ * @param {Array} list The array to consider.
+ * @return {Number} The index of the element found, or `-1`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1}, {a: 2}, {a: 3}];
+ *      R.findIndex(R.propEq('a', 2))(xs); //=> 1
+ *      R.findIndex(R.propEq('a', 4))(xs); //=> -1
+ */
+var findIndex = _curry2(_dispatchable([], _xfindIndex, function findIndex(fn, list) {
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    if (fn(list[idx])) {
+      return idx;
+    }
+    idx += 1;
+  }
+  return -1;
+}));
+
+function XFindLast(f, xf) {
+  this.xf = xf;
+  this.f = f;
+}
+XFindLast.prototype['@@transducer/init'] = _xfBase.init;
+XFindLast.prototype['@@transducer/result'] = function(result) {
+  return this.xf['@@transducer/result'](this.xf['@@transducer/step'](result, this.last));
+};
+XFindLast.prototype['@@transducer/step'] = function(result, input) {
+  if (this.f(input)) {
+    this.last = input;
+  }
+  return result;
+};
+
+var _xfindLast = _curry2(function _xfindLast(f, xf) { return new XFindLast(f, xf); });
+
+/**
+ * Returns the last element of the list which matches the predicate, or
+ * `undefined` if no element matches.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> a | undefined
+ * @param {Function} fn The predicate function used to determine if the element is the
+ * desired one.
+ * @param {Array} list The array to consider.
+ * @return {Object} The element found, or `undefined`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1, b: 0}, {a:1, b: 1}];
+ *      R.findLast(R.propEq('a', 1))(xs); //=> {a: 1, b: 1}
+ *      R.findLast(R.propEq('a', 4))(xs); //=> undefined
+ */
+var findLast = _curry2(_dispatchable([], _xfindLast, function findLast(fn, list) {
+  var idx = list.length - 1;
+  while (idx >= 0) {
+    if (fn(list[idx])) {
+      return list[idx];
+    }
+    idx -= 1;
+  }
+}));
+
+function XFindLastIndex(f, xf) {
+  this.xf = xf;
+  this.f = f;
+  this.idx = -1;
+  this.lastIdx = -1;
+}
+XFindLastIndex.prototype['@@transducer/init'] = _xfBase.init;
+XFindLastIndex.prototype['@@transducer/result'] = function(result) {
+  return this.xf['@@transducer/result'](this.xf['@@transducer/step'](result, this.lastIdx));
+};
+XFindLastIndex.prototype['@@transducer/step'] = function(result, input) {
+  this.idx += 1;
+  if (this.f(input)) {
+    this.lastIdx = this.idx;
+  }
+  return result;
+};
+
+var _xfindLastIndex = _curry2(function _xfindLastIndex(f, xf) { return new XFindLastIndex(f, xf); });
+
+/**
+ * Returns the index of the last element of the list which matches the
+ * predicate, or `-1` if no element matches.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Number
+ * @param {Function} fn The predicate function used to determine if the element is the
+ * desired one.
+ * @param {Array} list The array to consider.
+ * @return {Number} The index of the element found, or `-1`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1, b: 0}, {a:1, b: 1}];
+ *      R.findLastIndex(R.propEq('a', 1))(xs); //=> 1
+ *      R.findLastIndex(R.propEq('a', 4))(xs); //=> -1
+ */
+var findLastIndex = _curry2(_dispatchable([], _xfindLastIndex, function findLastIndex(fn, list) {
+  var idx = list.length - 1;
+  while (idx >= 0) {
+    if (fn(list[idx])) {
+      return idx;
+    }
+    idx -= 1;
+  }
+  return -1;
+}));
+
+/**
+ * Returns a new list by pulling every item out of it (and all its sub-arrays)
+ * and putting them in a new array, depth-first.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [b]
+ * @param {Array} list The array to consider.
+ * @return {Array} The flattened list.
+ * @see R.unnest
+ * @example
+ *
+ *      R.flatten([1, 2, [3, 4], 5, [6, [7, 8, [9, [10, 11], 12]]]]);
+ *      //=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+ */
+var flatten = _curry1(_makeFlat(true));
+
+/**
+ * Returns a new function much like the supplied one, except that the first two
+ * arguments' order is reversed.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((a, b, c, ...) -> z) -> (b -> a -> c -> ... -> z)
+ * @param {Function} fn The function to invoke with its first two parameters reversed.
+ * @return {*} The result of invoking `fn` with its first two parameters' order reversed.
+ * @example
+ *
+ *      const mergeThree = (a, b, c) => [].concat(a, b, c);
+ *
+ *      mergeThree(1, 2, 3); //=> [1, 2, 3]
+ *
+ *      R.flip(mergeThree)(1, 2, 3); //=> [2, 1, 3]
+ * @symb R.flip(f)(a, b, c) = f(b, a, c)
+ */
+var flip = _curry1(function flip(fn) {
+  return curryN(fn.length, function(a, b) {
+    var args = Array.prototype.slice.call(arguments, 0);
+    args[0] = b;
+    args[1] = a;
+    return fn.apply(this, args);
+  });
+});
+
+/**
+ * Iterate over an input `list`, calling a provided function `fn` for each
+ * element in the list.
+ *
+ * `fn` receives one argument: *(value)*.
+ *
+ * Note: `R.forEach` does not skip deleted or unassigned indices (sparse
+ * arrays), unlike the native `Array.prototype.forEach` method. For more
+ * details on this behavior, see:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description
+ *
+ * Also note that, unlike `Array.prototype.forEach`, Ramda's `forEach` returns
+ * the original array. In some libraries this function is named `each`.
+ *
+ * Dispatches to the `forEach` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> *) -> [a] -> [a]
+ * @param {Function} fn The function to invoke. Receives one argument, `value`.
+ * @param {Array} list The list to iterate over.
+ * @return {Array} The original list.
+ * @see R.addIndex
+ * @example
+ *
+ *      const printXPlusFive = x => console.log(x + 5);
+ *      R.forEach(printXPlusFive, [1, 2, 3]); //=> [1, 2, 3]
+ *      // logs 6
+ *      // logs 7
+ *      // logs 8
+ * @symb R.forEach(f, [a, b, c]) = [a, b, c]
+ */
+var forEach = _curry2(_checkForMethod('forEach', function forEach(fn, list) {
+  var len = list.length;
+  var idx = 0;
+  while (idx < len) {
+    fn(list[idx]);
+    idx += 1;
+  }
+  return list;
+}));
+
+/**
+ * Iterate over an input `object`, calling a provided function `fn` for each
+ * key and value in the object.
+ *
+ * `fn` receives three argument: *(value, key, obj)*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Object
+ * @sig ((a, String, StrMap a) -> Any) -> StrMap a -> StrMap a
+ * @param {Function} fn The function to invoke. Receives three argument, `value`, `key`, `obj`.
+ * @param {Object} obj The object to iterate over.
+ * @return {Object} The original object.
+ * @example
+ *
+ *      const printKeyConcatValue = (value, key) => console.log(key + ':' + value);
+ *      R.forEachObjIndexed(printKeyConcatValue, {x: 1, y: 2}); //=> {x: 1, y: 2}
+ *      // logs x:1
+ *      // logs y:2
+ * @symb R.forEachObjIndexed(f, {x: a, y: b}) = {x: a, y: b}
+ */
+var forEachObjIndexed = _curry2(function forEachObjIndexed(fn, obj) {
+  var keyList = keys(obj);
+  var idx = 0;
+  while (idx < keyList.length) {
+    var key = keyList[idx];
+    fn(obj[key], key, obj);
+    idx += 1;
+  }
+  return obj;
+});
+
+/**
+ * Creates a new object from a list key-value pairs. If a key appears in
+ * multiple pairs, the rightmost pair is included in the object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig [[k,v]] -> {k: v}
+ * @param {Array} pairs An array of two-element arrays that will be the keys and values of the output object.
+ * @return {Object} The object made by pairing up `keys` and `values`.
+ * @see R.toPairs, R.pair
+ * @example
+ *
+ *      R.fromPairs([['a', 1], ['b', 2], ['c', 3]]); //=> {a: 1, b: 2, c: 3}
+ */
+var fromPairs = _curry1(function fromPairs(pairs) {
+  var result = {};
+  var idx = 0;
+  while (idx < pairs.length) {
+    result[pairs[idx][0]] = pairs[idx][1];
+    idx += 1;
+  }
+  return result;
+});
+
+/**
+ * Splits a list into sub-lists stored in an object, based on the result of
+ * calling a String-returning function on each element, and grouping the
+ * results according to values returned.
+ *
+ * Dispatches to the `groupBy` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> String) -> [a] -> {String: [a]}
+ * @param {Function} fn Function :: a -> String
+ * @param {Array} list The array to group
+ * @return {Object} An object with the output of `fn` for keys, mapped to arrays of elements
+ *         that produced that key when passed to `fn`.
+ * @see R.reduceBy, R.transduce
+ * @example
+ *
+ *      const byGrade = R.groupBy(function(student) {
+ *        const score = student.score;
+ *        return score < 65 ? 'F' :
+ *               score < 70 ? 'D' :
+ *               score < 80 ? 'C' :
+ *               score < 90 ? 'B' : 'A';
+ *      });
+ *      const students = [{name: 'Abby', score: 84},
+ *                      {name: 'Eddy', score: 58},
+ *                      // ...
+ *                      {name: 'Jack', score: 69}];
+ *      byGrade(students);
+ *      // {
+ *      //   'A': [{name: 'Dianne', score: 99}],
+ *      //   'B': [{name: 'Abby', score: 84}]
+ *      //   // ...,
+ *      //   'F': [{name: 'Eddy', score: 58}]
+ *      // }
+ */
+var groupBy = _curry2(_checkForMethod('groupBy', reduceBy(function(acc, item) {
+  if (acc == null) {
+    acc = [];
+  }
+  acc.push(item);
+  return acc;
+}, null)));
+
+/**
+ * Takes a list and returns a list of lists where each sublist's elements are
+ * all satisfied pairwise comparison according to the provided function.
+ * Only adjacent elements are passed to the comparison function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.21.0
+ * @category List
+ * @sig ((a, a) → Boolean) → [a] → [[a]]
+ * @param {Function} fn Function for determining whether two given (adjacent)
+ *        elements should be in the same group
+ * @param {Array} list The array to group. Also accepts a string, which will be
+ *        treated as a list of characters.
+ * @return {List} A list that contains sublists of elements,
+ *         whose concatenations are equal to the original list.
+ * @example
+ *
+ * R.groupWith(R.equals, [0, 1, 1, 2, 3, 5, 8, 13, 21])
+ * //=> [[0], [1, 1], [2], [3], [5], [8], [13], [21]]
+ *
+ * R.groupWith((a, b) => a + 1 === b, [0, 1, 1, 2, 3, 5, 8, 13, 21])
+ * //=> [[0, 1], [1, 2, 3], [5], [8], [13], [21]]
+ *
+ * R.groupWith((a, b) => a % 2 === b % 2, [0, 1, 1, 2, 3, 5, 8, 13, 21])
+ * //=> [[0], [1, 1], [2], [3, 5], [8], [13, 21]]
+ *
+ * R.groupWith(R.eqBy(isVowel), 'aestiou')
+ * //=> ['ae', 'st', 'iou']
+ */
+var groupWith = _curry2(function(fn, list) {
+  var res = [];
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    var nextidx = idx + 1;
+    while (nextidx < len && fn(list[nextidx - 1], list[nextidx])) {
+      nextidx += 1;
+    }
+    res.push(list.slice(idx, nextidx));
+    idx = nextidx;
+  }
+  return res;
+});
+
+/**
+ * Returns `true` if the first argument is greater than the second; `false`
+ * otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @see R.lt
+ * @example
+ *
+ *      R.gt(2, 1); //=> true
+ *      R.gt(2, 2); //=> false
+ *      R.gt(2, 3); //=> false
+ *      R.gt('a', 'z'); //=> false
+ *      R.gt('z', 'a'); //=> true
+ */
+var gt = _curry2(function gt(a, b) { return a > b; });
+
+/**
+ * Returns `true` if the first argument is greater than or equal to the second;
+ * `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {Number} a
+ * @param {Number} b
+ * @return {Boolean}
+ * @see R.lte
+ * @example
+ *
+ *      R.gte(2, 1); //=> true
+ *      R.gte(2, 2); //=> true
+ *      R.gte(2, 3); //=> false
+ *      R.gte('a', 'z'); //=> false
+ *      R.gte('z', 'a'); //=> true
+ */
+var gte = _curry2(function gte(a, b) { return a >= b; });
+
+/**
+ * Returns whether or not a path exists in an object. Only the object's
+ * own properties are checked.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.26.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> {a} -> Boolean
+ * @param {Array} path The path to use.
+ * @param {Object} obj The object to check the path in.
+ * @return {Boolean} Whether the path exists.
+ * @see R.has
+ * @example
+ *
+ *      R.hasPath(['a', 'b'], {a: {b: 2}});         // => true
+ *      R.hasPath(['a', 'b'], {a: {b: undefined}}); // => true
+ *      R.hasPath(['a', 'b'], {a: {c: 2}});         // => false
+ *      R.hasPath(['a', 'b'], {});                  // => false
+ */
+var hasPath = _curry2(function hasPath(_path, obj) {
+  if (_path.length === 0) {
+    return false;
+  }
+  var val = obj;
+  var idx = 0;
+  while (idx < _path.length) {
+    if (_has(_path[idx], val)) {
+      val = val[_path[idx]];
+      idx += 1;
+    } else {
+      return false;
+    }
+  }
+  return true;
+});
+
+/**
+ * Returns whether or not an object has an own property with the specified name
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Object
+ * @sig s -> {s: x} -> Boolean
+ * @param {String} prop The name of the property to check for.
+ * @param {Object} obj The object to query.
+ * @return {Boolean} Whether the property exists.
+ * @example
+ *
+ *      const hasName = R.has('name');
+ *      hasName({name: 'alice'});   //=> true
+ *      hasName({name: 'bob'});     //=> true
+ *      hasName({});                //=> false
+ *
+ *      const point = {x: 0, y: 0};
+ *      const pointHas = R.has(R.__, point);
+ *      pointHas('x');  //=> true
+ *      pointHas('y');  //=> true
+ *      pointHas('z');  //=> false
+ */
+var has = _curry2(function has(prop, obj) {
+  return hasPath([prop], obj);
+});
+
+/**
+ * Returns whether or not an object or its prototype chain has a property with
+ * the specified name
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Object
+ * @sig s -> {s: x} -> Boolean
+ * @param {String} prop The name of the property to check for.
+ * @param {Object} obj The object to query.
+ * @return {Boolean} Whether the property exists.
+ * @example
+ *
+ *      function Rectangle(width, height) {
+ *        this.width = width;
+ *        this.height = height;
+ *      }
+ *      Rectangle.prototype.area = function() {
+ *        return this.width * this.height;
+ *      };
+ *
+ *      const square = new Rectangle(2, 2);
+ *      R.hasIn('width', square);  //=> true
+ *      R.hasIn('area', square);  //=> true
+ */
+var hasIn = _curry2(function hasIn(prop, obj) {
+  return prop in obj;
+});
+
+/**
+ * Returns true if its arguments are identical, false otherwise. Values are
+ * identical if they reference the same memory. `NaN` is identical to `NaN`;
+ * `0` and `-0` are not identical.
+ *
+ * Note this is merely a curried version of ES6 `Object.is`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category Relation
+ * @sig a -> a -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @example
+ *
+ *      const o = {};
+ *      R.identical(o, o); //=> true
+ *      R.identical(1, 1); //=> true
+ *      R.identical(1, '1'); //=> false
+ *      R.identical([], []); //=> false
+ *      R.identical(0, -0); //=> false
+ *      R.identical(NaN, NaN); //=> true
+ */
+var identical = _curry2(_objectIs$1);
+
+/**
+ * Creates a function that will process either the `onTrue` or the `onFalse`
+ * function depending upon the result of the `condition` predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Logic
+ * @sig (*... -> Boolean) -> (*... -> *) -> (*... -> *) -> (*... -> *)
+ * @param {Function} condition A predicate function
+ * @param {Function} onTrue A function to invoke when the `condition` evaluates to a truthy value.
+ * @param {Function} onFalse A function to invoke when the `condition` evaluates to a falsy value.
+ * @return {Function} A new function that will process either the `onTrue` or the `onFalse`
+ *                    function depending upon the result of the `condition` predicate.
+ * @see R.unless, R.when, R.cond
+ * @example
+ *
+ *      const incCount = R.ifElse(
+ *        R.has('count'),
+ *        R.over(R.lensProp('count'), R.inc),
+ *        R.assoc('count', 1)
+ *      );
+ *      incCount({});           //=> { count: 1 }
+ *      incCount({ count: 1 }); //=> { count: 2 }
+ */
+var ifElse = _curry3(function ifElse(condition, onTrue, onFalse) {
+  return curryN(Math.max(condition.length, onTrue.length, onFalse.length),
+    function _ifElse() {
+      return condition.apply(this, arguments) ? onTrue.apply(this, arguments) : onFalse.apply(this, arguments);
+    }
+  );
+});
+
+/**
+ * Increments its argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Math
+ * @sig Number -> Number
+ * @param {Number} n
+ * @return {Number} n + 1
+ * @see R.dec
+ * @example
+ *
+ *      R.inc(42); //=> 43
+ */
+var inc = add(1);
+
+/**
+ * Returns `true` if the specified value is equal, in [`R.equals`](#equals)
+ * terms, to at least one element of the given list; `false` otherwise.
+ * Works also with strings.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Boolean
+ * @param {Object} a The item to compare against.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if an equivalent item is in the list, `false` otherwise.
+ * @see R.any
+ * @example
+ *
+ *      R.includes(3, [1, 2, 3]); //=> true
+ *      R.includes(4, [1, 2, 3]); //=> false
+ *      R.includes({ name: 'Fred' }, [{ name: 'Fred' }]); //=> true
+ *      R.includes([42], [[42]]); //=> true
+ *      R.includes('ba', 'banana'); //=>true
+ */
+var includes = _curry2(_includes);
+
+/**
+ * Given a function that generates a key, turns a list of objects into an
+ * object indexing the objects by the given key. Note that if multiple
+ * objects generate the same value for the indexing key only the last value
+ * will be included in the generated object.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (a -> String) -> [{k: v}] -> {k: {k: v}}
+ * @param {Function} fn Function :: a -> String
+ * @param {Array} array The array of objects to index
+ * @return {Object} An object indexing each array element by the given property.
+ * @example
+ *
+ *      const list = [{id: 'xyz', title: 'A'}, {id: 'abc', title: 'B'}];
+ *      R.indexBy(R.prop('id'), list);
+ *      //=> {abc: {id: 'abc', title: 'B'}, xyz: {id: 'xyz', title: 'A'}}
+ */
+var indexBy = reduceBy(function(acc, elem) { return elem; }, null);
+
+/**
+ * Returns the position of the first occurrence of an item in an array, or -1
+ * if the item is not included in the array. [`R.equals`](#equals) is used to
+ * determine equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Number
+ * @param {*} target The item to find.
+ * @param {Array} xs The array to search in.
+ * @return {Number} the index of the target, or -1 if the target is not found.
+ * @see R.lastIndexOf
+ * @example
+ *
+ *      R.indexOf(3, [1,2,3,4]); //=> 2
+ *      R.indexOf(10, [1,2,3,4]); //=> -1
+ */
+var indexOf = _curry2(function indexOf(target, xs) {
+  return typeof xs.indexOf === 'function' && !_isArray(xs) ?
+    xs.indexOf(target) :
+    _indexOf(xs, target, 0);
+});
+
+/**
+ * Returns all but the last element of the given list or string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category List
+ * @sig [a] -> [a]
+ * @sig String -> String
+ * @param {*} list
+ * @return {*}
+ * @see R.last, R.head, R.tail
+ * @example
+ *
+ *      R.init([1, 2, 3]);  //=> [1, 2]
+ *      R.init([1, 2]);     //=> [1]
+ *      R.init([1]);        //=> []
+ *      R.init([]);         //=> []
+ *
+ *      R.init('abc');  //=> 'ab'
+ *      R.init('ab');   //=> 'a'
+ *      R.init('a');    //=> ''
+ *      R.init('');     //=> ''
+ */
+var init = slice(0, -1);
+
+/**
+ * Takes a predicate `pred`, a list `xs`, and a list `ys`, and returns a list
+ * `xs'` comprising each of the elements of `xs` which is equal to one or more
+ * elements of `ys` according to `pred`.
+ *
+ * `pred` must be a binary function expecting an element from each list.
+ *
+ * `xs`, `ys`, and `xs'` are treated as sets, semantically, so ordering should
+ * not be significant, but since `xs'` is ordered the implementation guarantees
+ * that its values are in the same order as they appear in `xs`. Duplicates are
+ * not removed, so `xs'` may contain duplicates if `xs` contains duplicates.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Relation
+ * @sig ((a, b) -> Boolean) -> [a] -> [b] -> [a]
+ * @param {Function} pred
+ * @param {Array} xs
+ * @param {Array} ys
+ * @return {Array}
+ * @see R.intersection
+ * @example
+ *
+ *      R.innerJoin(
+ *        (record, id) => record.id === id,
+ *        [{id: 824, name: 'Richie Furay'},
+ *         {id: 956, name: 'Dewey Martin'},
+ *         {id: 313, name: 'Bruce Palmer'},
+ *         {id: 456, name: 'Stephen Stills'},
+ *         {id: 177, name: 'Neil Young'}],
+ *        [177, 456, 999]
+ *      );
+ *      //=> [{id: 456, name: 'Stephen Stills'}, {id: 177, name: 'Neil Young'}]
+ */
+var innerJoin = _curry3(function innerJoin(pred, xs, ys) {
+  return _filter(function(x) { return _includesWith(pred, x, ys); }, xs);
+});
+
+/**
+ * Inserts the supplied element into the list, at the specified `index`. _Note that
+
+ * this is not destructive_: it returns a copy of the list with the changes.
+ * <small>No lists have been harmed in the application of this function.</small>
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.2
+ * @category List
+ * @sig Number -> a -> [a] -> [a]
+ * @param {Number} index The position to insert the element
+ * @param {*} elt The element to insert into the Array
+ * @param {Array} list The list to insert into
+ * @return {Array} A new Array with `elt` inserted at `index`.
+ * @example
+ *
+ *      R.insert(2, 'x', [1,2,3,4]); //=> [1,2,'x',3,4]
+ */
+var insert = _curry3(function insert(idx, elt, list) {
+  idx = idx < list.length && idx >= 0 ? idx : list.length;
+  var result = Array.prototype.slice.call(list, 0);
+  result.splice(idx, 0, elt);
+  return result;
+});
+
+/**
+ * Inserts the sub-list into the list, at the specified `index`. _Note that this is not
+ * destructive_: it returns a copy of the list with the changes.
+ * <small>No lists have been harmed in the application of this function.</small>
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category List
+ * @sig Number -> [a] -> [a] -> [a]
+ * @param {Number} index The position to insert the sub-list
+ * @param {Array} elts The sub-list to insert into the Array
+ * @param {Array} list The list to insert the sub-list into
+ * @return {Array} A new Array with `elts` inserted starting at `index`.
+ * @example
+ *
+ *      R.insertAll(2, ['x','y','z'], [1,2,3,4]); //=> [1,2,'x','y','z',3,4]
+ */
+var insertAll = _curry3(function insertAll(idx, elts, list) {
+  idx = idx < list.length && idx >= 0 ? idx : list.length;
+  return [].concat(
+    Array.prototype.slice.call(list, 0, idx),
+    elts,
+    Array.prototype.slice.call(list, idx)
+  );
+});
+
+/**
+ * Returns a new list containing only one copy of each element in the original
+ * list, based upon the value returned by applying the supplied function to
+ * each list element. Prefers the first item if the supplied function produces
+ * the same value on two items. [`R.equals`](#equals) is used for comparison.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig (a -> b) -> [a] -> [a]
+ * @param {Function} fn A function used to produce a value to use during comparisons.
+ * @param {Array} list The array to consider.
+ * @return {Array} The list of unique items.
+ * @example
+ *
+ *      R.uniqBy(Math.abs, [-1, -5, 2, 10, 1, 2]); //=> [-1, -5, 2, 10]
+ */
+var uniqBy = _curry2(function uniqBy(fn, list) {
+  var set = new _Set();
+  var result = [];
+  var idx = 0;
+  var appliedItem, item;
+
+  while (idx < list.length) {
+    item = list[idx];
+    appliedItem = fn(item);
+    if (set.add(appliedItem)) {
+      result.push(item);
+    }
+    idx += 1;
+  }
+  return result;
+});
+
+/**
+ * Returns a new list containing only one copy of each element in the original
+ * list. [`R.equals`](#equals) is used to determine equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a]
+ * @param {Array} list The array to consider.
+ * @return {Array} The list of unique items.
+ * @example
+ *
+ *      R.uniq([1, 1, 2, 1]); //=> [1, 2]
+ *      R.uniq([1, '1']);     //=> [1, '1']
+ *      R.uniq([[42], [42]]); //=> [[42]]
+ */
+var uniq = uniqBy(identity);
+
+/**
+ * Combines two lists into a set (i.e. no duplicates) composed of those
+ * elements common to both lists.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The list of elements found in both `list1` and `list2`.
+ * @see R.innerJoin
+ * @example
+ *
+ *      R.intersection([1,2,3,4], [7,6,5,4,3]); //=> [4, 3]
+ */
+var intersection = _curry2(function intersection(list1, list2) {
+  var lookupList, filteredList;
+  if (list1.length > list2.length) {
+    lookupList = list1;
+    filteredList = list2;
+  } else {
+    lookupList = list2;
+    filteredList = list1;
+  }
+  return uniq(_filter(flip(_includes)(lookupList), filteredList));
+});
+
+/**
+ * Creates a new list with the separator interposed between elements.
+ *
+ * Dispatches to the `intersperse` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig a -> [a] -> [a]
+ * @param {*} separator The element to add to the list.
+ * @param {Array} list The list to be interposed.
+ * @return {Array} The new list.
+ * @example
+ *
+ *      R.intersperse('a', ['b', 'n', 'n', 's']); //=> ['b', 'a', 'n', 'a', 'n', 'a', 's']
+ */
+var intersperse = _curry2(_checkForMethod('intersperse', function intersperse(separator, list) {
+  var out = [];
+  var idx = 0;
+  var length = list.length;
+  while (idx < length) {
+    if (idx === length - 1) {
+      out.push(list[idx]);
+    } else {
+      out.push(list[idx], separator);
+    }
+    idx += 1;
+  }
+  return out;
+}));
+
+// Based on https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
+function _objectAssign(target) {
+  if (target == null) {
+    throw new TypeError('Cannot convert undefined or null to object');
+  }
+
+  var output = Object(target);
+  var idx = 1;
+  var length = arguments.length;
+  while (idx < length) {
+    var source = arguments[idx];
+    if (source != null) {
+      for (var nextKey in source) {
+        if (_has(nextKey, source)) {
+          output[nextKey] = source[nextKey];
+        }
+      }
+    }
+    idx += 1;
+  }
+  return output;
+}
+
+var _objectAssign$1 = typeof Object.assign === 'function' ? Object.assign : _objectAssign;
+
+/**
+ * Creates an object containing a single key:value pair.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Object
+ * @sig String -> a -> {String:a}
+ * @param {String} key
+ * @param {*} val
+ * @return {Object}
+ * @see R.pair
+ * @example
+ *
+ *      const matchPhrases = R.compose(
+ *        R.objOf('must'),
+ *        R.map(R.objOf('match_phrase'))
+ *      );
+ *      matchPhrases(['foo', 'bar', 'baz']); //=> {must: [{match_phrase: 'foo'}, {match_phrase: 'bar'}, {match_phrase: 'baz'}]}
+ */
+var objOf = _curry2(function objOf(key, val) {
+  var obj = {};
+  obj[key] = val;
+  return obj;
+});
+
+var _stepCatArray = {
+  '@@transducer/init': Array,
+  '@@transducer/step': function(xs, x) {
+    xs.push(x);
+    return xs;
+  },
+  '@@transducer/result': _identity
+};
+var _stepCatString = {
+  '@@transducer/init': String,
+  '@@transducer/step': function(a, b) { return a + b; },
+  '@@transducer/result': _identity
+};
+var _stepCatObject = {
+  '@@transducer/init': Object,
+  '@@transducer/step': function(result, input) {
+    return _objectAssign$1(
+      result,
+      _isArrayLike(input) ? objOf(input[0], input[1]) : input
+    );
+  },
+  '@@transducer/result': _identity
+};
+
+function _stepCat(obj) {
+  if (_isTransformer(obj)) {
+    return obj;
+  }
+  if (_isArrayLike(obj)) {
+    return _stepCatArray;
+  }
+  if (typeof obj === 'string') {
+    return _stepCatString;
+  }
+  if (typeof obj === 'object') {
+    return _stepCatObject;
+  }
+  throw new Error('Cannot create transformer for ' + obj);
+}
+
+/**
+ * Transforms the items of the list with the transducer and appends the
+ * transformed items to the accumulator using an appropriate iterator function
+ * based on the accumulator type.
+ *
+ * The accumulator can be an array, string, object or a transformer. Iterated
+ * items will be appended to arrays and concatenated to strings. Objects will
+ * be merged directly or 2-item arrays will be merged as key, value pairs.
+ *
+ * The accumulator can also be a transformer object that provides a 2-arity
+ * reducing iterator function, step, 0-arity initial value function, init, and
+ * 1-arity result extraction function result. The step function is used as the
+ * iterator function in reduce. The result function is used to convert the
+ * final accumulator into the return type and in most cases is R.identity. The
+ * init function is used to provide the initial accumulator.
+ *
+ * The iteration is performed with [`R.reduce`](#reduce) after initializing the
+ * transducer.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig a -> (b -> b) -> [c] -> a
+ * @param {*} acc The initial accumulator value.
+ * @param {Function} xf The transducer function. Receives a transformer and returns a transformer.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.transduce
+ * @example
+ *
+ *      const numbers = [1, 2, 3, 4];
+ *      const transducer = R.compose(R.map(R.add(1)), R.take(2));
+ *
+ *      R.into([], transducer, numbers); //=> [2, 3]
+ *
+ *      const intoArray = R.into([]);
+ *      intoArray(transducer, numbers); //=> [2, 3]
+ */
+var into = _curry3(function into(acc, xf, list) {
+  return _isTransformer(acc) ?
+    _reduce(xf(acc), acc['@@transducer/init'](), list) :
+    _reduce(xf(_stepCat(acc)), _clone(acc, [], [], false), list);
+});
+
+/**
+ * Same as [`R.invertObj`](#invertObj), however this accounts for objects with
+ * duplicate values by putting the values into an array.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig {s: x} -> {x: [ s, ... ]}
+ * @param {Object} obj The object or array to invert
+ * @return {Object} out A new object with keys in an array.
+ * @see R.invertObj
+ * @example
+ *
+ *      const raceResultsByFirstName = {
+ *        first: 'alice',
+ *        second: 'jake',
+ *        third: 'alice',
+ *      };
+ *      R.invert(raceResultsByFirstName);
+ *      //=> { 'alice': ['first', 'third'], 'jake':['second'] }
+ */
+var invert = _curry1(function invert(obj) {
+  var props = keys(obj);
+  var len = props.length;
+  var idx = 0;
+  var out = {};
+
+  while (idx < len) {
+    var key = props[idx];
+    var val = obj[key];
+    var list = _has(val, out) ? out[val] : (out[val] = []);
+    list[list.length] = key;
+    idx += 1;
+  }
+  return out;
+});
+
+/**
+ * Returns a new object with the keys of the given object as values, and the
+ * values of the given object, which are coerced to strings, as keys. Note
+ * that the last key found is preferred when handling the same value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig {s: x} -> {x: s}
+ * @param {Object} obj The object or array to invert
+ * @return {Object} out A new object
+ * @see R.invert
+ * @example
+ *
+ *      const raceResults = {
+ *        first: 'alice',
+ *        second: 'jake'
+ *      };
+ *      R.invertObj(raceResults);
+ *      //=> { 'alice': 'first', 'jake':'second' }
+ *
+ *      // Alternatively:
+ *      const raceResults = ['alice', 'jake'];
+ *      R.invertObj(raceResults);
+ *      //=> { 'alice': '0', 'jake':'1' }
+ */
+var invertObj = _curry1(function invertObj(obj) {
+  var props = keys(obj);
+  var len = props.length;
+  var idx = 0;
+  var out = {};
+
+  while (idx < len) {
+    var key = props[idx];
+    out[obj[key]] = key;
+    idx += 1;
+  }
+  return out;
+});
+
+/**
+ * Turns a named method with a specified arity into a function that can be
+ * called directly supplied with arguments and a target object.
+ *
+ * The returned function is curried and accepts `arity + 1` parameters where
+ * the final parameter is the target object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig Number -> String -> (a -> b -> ... -> n -> Object -> *)
+ * @param {Number} arity Number of arguments the returned function should take
+ *        before the target object.
+ * @param {String} method Name of the method to call.
+ * @return {Function} A new curried function.
+ * @see R.construct
+ * @example
+ *
+ *      const sliceFrom = R.invoker(1, 'slice');
+ *      sliceFrom(6, 'abcdefghijklm'); //=> 'ghijklm'
+ *      const sliceFrom6 = R.invoker(2, 'slice')(6);
+ *      sliceFrom6(8, 'abcdefghijklm'); //=> 'gh'
+ * @symb R.invoker(0, 'method')(o) = o['method']()
+ * @symb R.invoker(1, 'method')(a, o) = o['method'](a)
+ * @symb R.invoker(2, 'method')(a, b, o) = o['method'](a, b)
+ */
+var invoker = _curry2(function invoker(arity, method) {
+  return curryN(arity + 1, function() {
+    var target = arguments[arity];
+    if (target != null && _isFunction(target[method])) {
+      return target[method].apply(target, Array.prototype.slice.call(arguments, 0, arity));
+    }
+    throw new TypeError(toString$1(target) + ' does not have a method named "' + method + '"');
+  });
+});
+
+/**
+ * See if an object (`val`) is an instance of the supplied constructor. This
+ * function will check up the inheritance chain, if any.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Type
+ * @sig (* -> {*}) -> a -> Boolean
+ * @param {Object} ctor A constructor
+ * @param {*} val The value to test
+ * @return {Boolean}
+ * @example
+ *
+ *      R.is(Object, {}); //=> true
+ *      R.is(Number, 1); //=> true
+ *      R.is(Object, 1); //=> false
+ *      R.is(String, 's'); //=> true
+ *      R.is(String, new String('')); //=> true
+ *      R.is(Object, new String('')); //=> true
+ *      R.is(Object, 's'); //=> false
+ *      R.is(Number, {}); //=> false
+ */
+var is = _curry2(function is(Ctor, val) {
+  return val != null && val.constructor === Ctor || val instanceof Ctor;
+});
+
+/**
+ * Returns `true` if the given value is its type's empty value; `false`
+ * otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig a -> Boolean
+ * @param {*} x
+ * @return {Boolean}
+ * @see R.empty
+ * @example
+ *
+ *      R.isEmpty([1, 2, 3]);   //=> false
+ *      R.isEmpty([]);          //=> true
+ *      R.isEmpty('');          //=> true
+ *      R.isEmpty(null);        //=> false
+ *      R.isEmpty({});          //=> true
+ *      R.isEmpty({length: 0}); //=> false
+ */
+var isEmpty = _curry1(function isEmpty(x) {
+  return x != null && equals(x, empty(x));
+});
+
+/**
+ * Returns a string made by inserting the `separator` between each element and
+ * concatenating all the elements into a single string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig String -> [a] -> String
+ * @param {Number|String} separator The string used to separate the elements.
+ * @param {Array} xs The elements to join into a string.
+ * @return {String} str The string made by concatenating `xs` with `separator`.
+ * @see R.split
+ * @example
+ *
+ *      const spacer = R.join(' ');
+ *      spacer(['a', 2, 3.4]);   //=> 'a 2 3.4'
+ *      R.join('|', [1, 2, 3]);    //=> '1|2|3'
+ */
+var join = invoker(1, 'join');
+
+/**
+ * juxt applies a list of functions to a list of values.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Function
+ * @sig [(a, b, ..., m) -> n] -> ((a, b, ..., m) -> [n])
+ * @param {Array} fns An array of functions
+ * @return {Function} A function that returns a list of values after applying each of the original `fns` to its parameters.
+ * @see R.applySpec
+ * @example
+ *
+ *      const getRange = R.juxt([Math.min, Math.max]);
+ *      getRange(3, 4, 9, -3); //=> [-3, 9]
+ * @symb R.juxt([f, g, h])(a, b) = [f(a, b), g(a, b), h(a, b)]
+ */
+var juxt = _curry1(function juxt(fns) {
+  return converge(function() { return Array.prototype.slice.call(arguments, 0); }, fns);
+});
+
+/**
+ * Returns a list containing the names of all the properties of the supplied
+ * object, including prototype properties.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Object
+ * @sig {k: v} -> [k]
+ * @param {Object} obj The object to extract properties from
+ * @return {Array} An array of the object's own and prototype properties.
+ * @see R.keys, R.valuesIn
+ * @example
+ *
+ *      const F = function() { this.x = 'X'; };
+ *      F.prototype.y = 'Y';
+ *      const f = new F();
+ *      R.keysIn(f); //=> ['x', 'y']
+ */
+var keysIn = _curry1(function keysIn(obj) {
+  var prop;
+  var ks = [];
+  for (prop in obj) {
+    ks[ks.length] = prop;
+  }
+  return ks;
+});
+
+/**
+ * Returns the position of the last occurrence of an item in an array, or -1 if
+ * the item is not included in the array. [`R.equals`](#equals) is used to
+ * determine equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Number
+ * @param {*} target The item to find.
+ * @param {Array} xs The array to search in.
+ * @return {Number} the index of the target, or -1 if the target is not found.
+ * @see R.indexOf
+ * @example
+ *
+ *      R.lastIndexOf(3, [-1,3,3,0,1,2,3,4]); //=> 6
+ *      R.lastIndexOf(10, [1,2,3,4]); //=> -1
+ */
+var lastIndexOf = _curry2(function lastIndexOf(target, xs) {
+  if (typeof xs.lastIndexOf === 'function' && !_isArray(xs)) {
+    return xs.lastIndexOf(target);
+  } else {
+    var idx = xs.length - 1;
+    while (idx >= 0) {
+      if (equals(xs[idx], target)) {
+        return idx;
+      }
+      idx -= 1;
+    }
+    return -1;
+  }
+});
+
+function _isNumber(x) {
+  return Object.prototype.toString.call(x) === '[object Number]';
+}
+
+/**
+ * Returns the number of elements in the array by returning `list.length`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig [a] -> Number
+ * @param {Array} list The array to inspect.
+ * @return {Number} The length of the array.
+ * @example
+ *
+ *      R.length([]); //=> 0
+ *      R.length([1, 2, 3]); //=> 3
+ */
+var length = _curry1(function length(list) {
+  return list != null && _isNumber(list.length) ? list.length : NaN;
+});
+
+/**
+ * Returns a lens for the given getter and setter functions. The getter "gets"
+ * the value of the focus; the setter "sets" the value of the focus. The setter
+ * should not mutate the data structure.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig (s -> a) -> ((a, s) -> s) -> Lens s a
+ * @param {Function} getter
+ * @param {Function} setter
+ * @return {Lens}
+ * @see R.view, R.set, R.over, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const xLens = R.lens(R.prop('x'), R.assoc('x'));
+ *
+ *      R.view(xLens, {x: 1, y: 2});            //=> 1
+ *      R.set(xLens, 4, {x: 1, y: 2});          //=> {x: 4, y: 2}
+ *      R.over(xLens, R.negate, {x: 1, y: 2});  //=> {x: -1, y: 2}
+ */
+var lens = _curry2(function lens(getter, setter) {
+  return function(toFunctorFn) {
+    return function(target) {
+      return map(
+        function(focus) {
+          return setter(focus, target);
+        },
+        toFunctorFn(getter(target))
+      );
+    };
+  };
+});
+
+/**
+ * Returns a lens whose focus is the specified index.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Number -> Lens s a
+ * @param {Number} n
+ * @return {Lens}
+ * @see R.view, R.set, R.over
+ * @example
+ *
+ *      const headLens = R.lensIndex(0);
+ *
+ *      R.view(headLens, ['a', 'b', 'c']);            //=> 'a'
+ *      R.set(headLens, 'x', ['a', 'b', 'c']);        //=> ['x', 'b', 'c']
+ *      R.over(headLens, R.toUpper, ['a', 'b', 'c']); //=> ['A', 'b', 'c']
+ */
+var lensIndex = _curry1(function lensIndex(n) {
+  return lens(nth(n), update(n));
+});
+
+/**
+ * Returns a lens whose focus is the specified path.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig [Idx] -> Lens s a
+ * @param {Array} path The path to use.
+ * @return {Lens}
+ * @see R.view, R.set, R.over
+ * @example
+ *
+ *      const xHeadYLens = R.lensPath(['x', 0, 'y']);
+ *
+ *      R.view(xHeadYLens, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
+ *      //=> 2
+ *      R.set(xHeadYLens, 1, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
+ *      //=> {x: [{y: 1, z: 3}, {y: 4, z: 5}]}
+ *      R.over(xHeadYLens, R.negate, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
+ *      //=> {x: [{y: -2, z: 3}, {y: 4, z: 5}]}
+ */
+var lensPath = _curry1(function lensPath(p) {
+  return lens(path(p), assocPath(p));
+});
+
+/**
+ * Returns a lens whose focus is the specified property.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig String -> Lens s a
+ * @param {String} k
+ * @return {Lens}
+ * @see R.view, R.set, R.over
+ * @example
+ *
+ *      const xLens = R.lensProp('x');
+ *
+ *      R.view(xLens, {x: 1, y: 2});            //=> 1
+ *      R.set(xLens, 4, {x: 1, y: 2});          //=> {x: 4, y: 2}
+ *      R.over(xLens, R.negate, {x: 1, y: 2});  //=> {x: -1, y: 2}
+ */
+var lensProp = _curry1(function lensProp(k) {
+  return lens(prop(k), assoc(k));
+});
+
+/**
+ * Returns `true` if the first argument is less than the second; `false`
+ * otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @see R.gt
+ * @example
+ *
+ *      R.lt(2, 1); //=> false
+ *      R.lt(2, 2); //=> false
+ *      R.lt(2, 3); //=> true
+ *      R.lt('a', 'z'); //=> true
+ *      R.lt('z', 'a'); //=> false
+ */
+var lt = _curry2(function lt(a, b) { return a < b; });
+
+/**
+ * Returns `true` if the first argument is less than or equal to the second;
+ * `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {Number} a
+ * @param {Number} b
+ * @return {Boolean}
+ * @see R.gte
+ * @example
+ *
+ *      R.lte(2, 1); //=> false
+ *      R.lte(2, 2); //=> true
+ *      R.lte(2, 3); //=> true
+ *      R.lte('a', 'z'); //=> true
+ *      R.lte('z', 'a'); //=> false
+ */
+var lte = _curry2(function lte(a, b) { return a <= b; });
+
+/**
+ * The `mapAccum` function behaves like a combination of map and reduce; it
+ * applies a function to each element of a list, passing an accumulating
+ * parameter from left to right, and returning a final value of this
+ * accumulator together with the new list.
+ *
+ * The iterator function receives two arguments, *acc* and *value*, and should
+ * return a tuple *[acc, value]*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig ((acc, x) -> (acc, y)) -> acc -> [x] -> (acc, [y])
+ * @param {Function} fn The function to be called on every element of the input `list`.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.scan, R.addIndex, R.mapAccumRight
+ * @example
+ *
+ *      const digits = ['1', '2', '3', '4'];
+ *      const appender = (a, b) => [a + b, a + b];
+ *
+ *      R.mapAccum(appender, 0, digits); //=> ['01234', ['01', '012', '0123', '01234']]
+ * @symb R.mapAccum(f, a, [b, c, d]) = [
+ *   f(f(f(a, b)[0], c)[0], d)[0],
+ *   [
+ *     f(a, b)[1],
+ *     f(f(a, b)[0], c)[1],
+ *     f(f(f(a, b)[0], c)[0], d)[1]
+ *   ]
+ * ]
+ */
+var mapAccum = _curry3(function mapAccum(fn, acc, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [];
+  var tuple = [acc];
+  while (idx < len) {
+    tuple = fn(tuple[0], list[idx]);
+    result[idx] = tuple[1];
+    idx += 1;
+  }
+  return [tuple[0], result];
+});
+
+/**
+ * The `mapAccumRight` function behaves like a combination of map and reduce; it
+ * applies a function to each element of a list, passing an accumulating
+ * parameter from right to left, and returning a final value of this
+ * accumulator together with the new list.
+ *
+ * Similar to [`mapAccum`](#mapAccum), except moves through the input list from
+ * the right to the left.
+ *
+ * The iterator function receives two arguments, *acc* and *value*, and should
+ * return a tuple *[acc, value]*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig ((acc, x) -> (acc, y)) -> acc -> [x] -> (acc, [y])
+ * @param {Function} fn The function to be called on every element of the input `list`.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.addIndex, R.mapAccum
+ * @example
+ *
+ *      const digits = ['1', '2', '3', '4'];
+ *      const appender = (a, b) => [b + a, b + a];
+ *
+ *      R.mapAccumRight(appender, 5, digits); //=> ['12345', ['12345', '2345', '345', '45']]
+ * @symb R.mapAccumRight(f, a, [b, c, d]) = [
+ *   f(f(f(a, d)[0], c)[0], b)[0],
+ *   [
+ *     f(a, d)[1],
+ *     f(f(a, d)[0], c)[1],
+ *     f(f(f(a, d)[0], c)[0], b)[1]
+ *   ]
+ * ]
+ */
+var mapAccumRight = _curry3(function mapAccumRight(fn, acc, list) {
+  var idx = list.length - 1;
+  var result = [];
+  var tuple = [acc];
+  while (idx >= 0) {
+    tuple = fn(tuple[0], list[idx]);
+    result[idx] = tuple[1];
+    idx -= 1;
+  }
+  return [tuple[0], result];
+});
+
+/**
+ * An Object-specific version of [`map`](#map). The function is applied to three
+ * arguments: *(value, key, obj)*. If only the value is significant, use
+ * [`map`](#map) instead.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig ((*, String, Object) -> *) -> Object -> Object
+ * @param {Function} fn
+ * @param {Object} obj
+ * @return {Object}
+ * @see R.map
+ * @example
+ *
+ *      const xyz = { x: 1, y: 2, z: 3 };
+ *      const prependKeyAndDouble = (num, key, obj) => key + (num * 2);
+ *
+ *      R.mapObjIndexed(prependKeyAndDouble, xyz); //=> { x: 'x2', y: 'y4', z: 'z6' }
+ */
+var mapObjIndexed = _curry2(function mapObjIndexed(fn, obj) {
+  return _reduce(function(acc, key) {
+    acc[key] = fn(obj[key], key, obj);
+    return acc;
+  }, {}, keys(obj));
+});
+
+/**
+ * Tests a regular expression against a String. Note that this function will
+ * return an empty array when there are no matches. This differs from
+ * [`String.prototype.match`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match)
+ * which returns `null` when there are no matches.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category String
+ * @sig RegExp -> String -> [String | Undefined]
+ * @param {RegExp} rx A regular expression.
+ * @param {String} str The string to match against
+ * @return {Array} The list of matches or empty array.
+ * @see R.test
+ * @example
+ *
+ *      R.match(/([a-z]a)/g, 'bananas'); //=> ['ba', 'na', 'na']
+ *      R.match(/a/, 'b'); //=> []
+ *      R.match(/a/, null); //=> TypeError: null does not have a method named "match"
+ */
+var match = _curry2(function match(rx, str) {
+  return str.match(rx) || [];
+});
+
+/**
+ * `mathMod` behaves like the modulo operator should mathematically, unlike the
+ * `%` operator (and by extension, [`R.modulo`](#modulo)). So while
+ * `-17 % 5` is `-2`, `mathMod(-17, 5)` is `3`. `mathMod` requires Integer
+ * arguments, and returns NaN when the modulus is zero or negative.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} m The dividend.
+ * @param {Number} p the modulus.
+ * @return {Number} The result of `b mod a`.
+ * @see R.modulo
+ * @example
+ *
+ *      R.mathMod(-17, 5);  //=> 3
+ *      R.mathMod(17, 5);   //=> 2
+ *      R.mathMod(17, -5);  //=> NaN
+ *      R.mathMod(17, 0);   //=> NaN
+ *      R.mathMod(17.2, 5); //=> NaN
+ *      R.mathMod(17, 5.3); //=> NaN
+ *
+ *      const clock = R.mathMod(R.__, 12);
+ *      clock(15); //=> 3
+ *      clock(24); //=> 0
+ *
+ *      const seventeenMod = R.mathMod(17);
+ *      seventeenMod(3);  //=> 2
+ *      seventeenMod(4);  //=> 1
+ *      seventeenMod(10); //=> 7
+ */
+var mathMod = _curry2(function mathMod(m, p) {
+  if (!_isInteger(m)) { return NaN; }
+  if (!_isInteger(p) || p < 1) { return NaN; }
+  return ((m % p) + p) % p;
+});
+
+/**
+ * Takes a function and two values, and returns whichever value produces the
+ * larger result when passed to the provided function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Relation
+ * @sig Ord b => (a -> b) -> a -> a -> a
+ * @param {Function} f
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.max, R.minBy
+ * @example
+ *
+ *      //  square :: Number -> Number
+ *      const square = n => n * n;
+ *
+ *      R.maxBy(square, -3, 2); //=> -3
+ *
+ *      R.reduce(R.maxBy(square), 0, [3, -5, 4, 1, -2]); //=> -5
+ *      R.reduce(R.maxBy(square), 0, []); //=> 0
+ */
+var maxBy = _curry3(function maxBy(f, a, b) {
+  return f(b) > f(a) ? b : a;
+});
+
+/**
+ * Adds together all the elements of a list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list An array of numbers
+ * @return {Number} The sum of all the numbers in the list.
+ * @see R.reduce
+ * @example
+ *
+ *      R.sum([2,4,6,8,100,1]); //=> 121
+ */
+var sum = reduce(add, 0);
+
+/**
+ * Returns the mean of the given list of numbers.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list
+ * @return {Number}
+ * @see R.median
+ * @example
+ *
+ *      R.mean([2, 7, 9]); //=> 6
+ *      R.mean([]); //=> NaN
+ */
+var mean = _curry1(function mean(list) {
+  return sum(list) / list.length;
+});
+
+/**
+ * Returns the median of the given list of numbers.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list
+ * @return {Number}
+ * @see R.mean
+ * @example
+ *
+ *      R.median([2, 9, 7]); //=> 7
+ *      R.median([7, 2, 10, 9]); //=> 8
+ *      R.median([]); //=> NaN
+ */
+var median = _curry1(function median(list) {
+  var len = list.length;
+  if (len === 0) {
+    return NaN;
+  }
+  var width = 2 - len % 2;
+  var idx = (len - width) / 2;
+  return mean(Array.prototype.slice.call(list, 0).sort(function(a, b) {
+    return a < b ? -1 : a > b ? 1 : 0;
+  }).slice(idx, idx + width));
+});
+
+/**
+ * Creates a new function that, when invoked, caches the result of calling `fn`
+ * for a given argument set and returns the result. Subsequent calls to the
+ * memoized `fn` with the same argument set will not result in an additional
+ * call to `fn`; instead, the cached result for that set of arguments will be
+ * returned.
+ *
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Function
+ * @sig (*... -> String) -> (*... -> a) -> (*... -> a)
+ * @param {Function} fn The function to generate the cache key.
+ * @param {Function} fn The function to memoize.
+ * @return {Function} Memoized version of `fn`.
+ * @example
+ *
+ *      let count = 0;
+ *      const factorial = R.memoizeWith(R.identity, n => {
+ *        count += 1;
+ *        return R.product(R.range(1, n + 1));
+ *      });
+ *      factorial(5); //=> 120
+ *      factorial(5); //=> 120
+ *      factorial(5); //=> 120
+ *      count; //=> 1
+ */
+var memoizeWith = _curry2(function memoizeWith(mFn, fn) {
+  var cache = {};
+  return _arity(fn.length, function() {
+    var key = mFn.apply(this, arguments);
+    if (!_has(key, cache)) {
+      cache[key] = fn.apply(this, arguments);
+    }
+    return cache[key];
+  });
+});
+
+/**
+ * Create a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects,
+ * the value from the second object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {k: v} -> {k: v} -> {k: v}
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeRight, R.mergeDeepRight, R.mergeWith, R.mergeWithKey
+ * @deprecated
+ * @example
+ *
+ *      R.merge({ 'name': 'fred', 'age': 10 }, { 'age': 40 });
+ *      //=> { 'name': 'fred', 'age': 40 }
+ *
+ *      const withDefaults = R.merge({x: 0, y: 0});
+ *      withDefaults({y: 2}); //=> {x: 0, y: 2}
+ * @symb R.merge(a, b) = {...a, ...b}
+ */
+var merge = _curry2(function merge(l, r) {
+  return _objectAssign$1({}, l, r);
+});
+
+/**
+ * Merges a list of objects together into one object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig [{k: v}] -> {k: v}
+ * @param {Array} list An array of objects
+ * @return {Object} A merged object.
+ * @see R.reduce
+ * @example
+ *
+ *      R.mergeAll([{foo:1},{bar:2},{baz:3}]); //=> {foo:1,bar:2,baz:3}
+ *      R.mergeAll([{foo:1},{foo:2},{bar:2}]); //=> {foo:2,bar:2}
+ * @symb R.mergeAll([{ x: 1 }, { y: 2 }, { z: 3 }]) = { x: 1, y: 2, z: 3 }
+ */
+var mergeAll = _curry1(function mergeAll(list) {
+  return _objectAssign$1.apply(null, [{}].concat(list));
+});
+
+/**
+ * Creates a new object with the own properties of the two provided objects. If
+ * a key exists in both objects, the provided function is applied to the key
+ * and the values associated with the key in each object, with the result being
+ * used as the value associated with the key in the returned object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Object
+ * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeDeepWithKey, R.merge, R.mergeWith
+ * @example
+ *
+ *      let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r
+ *      R.mergeWithKey(concatValues,
+ *                     { a: true, thing: 'foo', values: [10, 20] },
+ *                     { b: true, thing: 'bar', values: [15, 35] });
+ *      //=> { a: true, b: true, thing: 'bar', values: [10, 20, 15, 35] }
+ * @symb R.mergeWithKey(f, { x: 1, y: 2 }, { y: 5, z: 3 }) = { x: 1, y: f('y', 2, 5), z: 3 }
+ */
+var mergeWithKey = _curry3(function mergeWithKey(fn, l, r) {
+  var result = {};
+  var k;
+
+  for (k in l) {
+    if (_has(k, l)) {
+      result[k] = _has(k, r) ? fn(k, l[k], r[k]) : l[k];
+    }
+  }
+
+  for (k in r) {
+    if (_has(k, r) && !(_has(k, result))) {
+      result[k] = r[k];
+    }
+  }
+
+  return result;
+});
+
+/**
+ * Creates a new object with the own properties of the two provided objects.
+ * If a key exists in both objects:
+ * - and both associated values are also objects then the values will be
+ *   recursively merged.
+ * - otherwise the provided function is applied to the key and associated values
+ *   using the resulting value as the new value associated with the key.
+ * If a key only exists in one object, the value will be associated with the key
+ * of the resulting object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.mergeWithKey, R.mergeDeepWith
+ * @example
+ *
+ *      let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r
+ *      R.mergeDeepWithKey(concatValues,
+ *                         { a: true, c: { thing: 'foo', values: [10, 20] }},
+ *                         { b: true, c: { thing: 'bar', values: [15, 35] }});
+ *      //=> { a: true, b: true, c: { thing: 'bar', values: [10, 20, 15, 35] }}
+ */
+var mergeDeepWithKey = _curry3(function mergeDeepWithKey(fn, lObj, rObj) {
+  return mergeWithKey(function(k, lVal, rVal) {
+    if (_isObject(lVal) && _isObject(rVal)) {
+      return mergeDeepWithKey(fn, lVal, rVal);
+    } else {
+      return fn(k, lVal, rVal);
+    }
+  }, lObj, rObj);
+});
+
+/**
+ * Creates a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects:
+ * - and both values are objects, the two values will be recursively merged
+ * - otherwise the value from the first object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig {a} -> {a} -> {a}
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.merge, R.mergeDeepRight, R.mergeDeepWith, R.mergeDeepWithKey
+ * @example
+ *
+ *      R.mergeDeepLeft({ name: 'fred', age: 10, contact: { email: 'moo@example.com' }},
+ *                      { age: 40, contact: { email: 'baa@example.com' }});
+ *      //=> { name: 'fred', age: 10, contact: { email: 'moo@example.com' }}
+ */
+var mergeDeepLeft = _curry2(function mergeDeepLeft(lObj, rObj) {
+  return mergeDeepWithKey(function(k, lVal, rVal) {
+    return lVal;
+  }, lObj, rObj);
+});
+
+/**
+ * Creates a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects:
+ * - and both values are objects, the two values will be recursively merged
+ * - otherwise the value from the second object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig {a} -> {a} -> {a}
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.merge, R.mergeDeepLeft, R.mergeDeepWith, R.mergeDeepWithKey
+ * @example
+ *
+ *      R.mergeDeepRight({ name: 'fred', age: 10, contact: { email: 'moo@example.com' }},
+ *                       { age: 40, contact: { email: 'baa@example.com' }});
+ *      //=> { name: 'fred', age: 40, contact: { email: 'baa@example.com' }}
+ */
+var mergeDeepRight = _curry2(function mergeDeepRight(lObj, rObj) {
+  return mergeDeepWithKey(function(k, lVal, rVal) {
+    return rVal;
+  }, lObj, rObj);
+});
+
+/**
+ * Creates a new object with the own properties of the two provided objects.
+ * If a key exists in both objects:
+ * - and both associated values are also objects then the values will be
+ *   recursively merged.
+ * - otherwise the provided function is applied to associated values using the
+ *   resulting value as the new value associated with the key.
+ * If a key only exists in one object, the value will be associated with the key
+ * of the resulting object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig ((a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.mergeWith, R.mergeDeepWithKey
+ * @example
+ *
+ *      R.mergeDeepWith(R.concat,
+ *                      { a: true, c: { values: [10, 20] }},
+ *                      { b: true, c: { values: [15, 35] }});
+ *      //=> { a: true, b: true, c: { values: [10, 20, 15, 35] }}
+ */
+var mergeDeepWith = _curry3(function mergeDeepWith(fn, lObj, rObj) {
+  return mergeDeepWithKey(function(k, lVal, rVal) {
+    return fn(lVal, rVal);
+  }, lObj, rObj);
+});
+
+/**
+ * Create a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects,
+ * the value from the first object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @category Object
+ * @sig {k: v} -> {k: v} -> {k: v}
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeRight, R.mergeDeepLeft, R.mergeWith, R.mergeWithKey
+ * @example
+ *
+ *      R.mergeLeft({ 'age': 40 }, { 'name': 'fred', 'age': 10 });
+ *      //=> { 'name': 'fred', 'age': 40 }
+ *
+ *      const resetToDefault = R.mergeLeft({x: 0});
+ *      resetToDefault({x: 5, y: 2}); //=> {x: 0, y: 2}
+ * @symb R.mergeLeft(a, b) = {...b, ...a}
+ */
+var mergeLeft = _curry2(function mergeLeft(l, r) {
+  return _objectAssign$1({}, r, l);
+});
+
+/**
+ * Create a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects,
+ * the value from the second object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @category Object
+ * @sig {k: v} -> {k: v} -> {k: v}
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeLeft, R.mergeDeepRight, R.mergeWith, R.mergeWithKey
+ * @example
+ *
+ *      R.mergeRight({ 'name': 'fred', 'age': 10 }, { 'age': 40 });
+ *      //=> { 'name': 'fred', 'age': 40 }
+ *
+ *      const withDefaults = R.mergeRight({x: 0, y: 0});
+ *      withDefaults({y: 2}); //=> {x: 0, y: 2}
+ * @symb R.mergeRight(a, b) = {...a, ...b}
+ */
+var mergeRight = _curry2(function mergeRight(l, r) {
+  return _objectAssign$1({}, l, r);
+});
+
+/**
+ * Creates a new object with the own properties of the two provided objects. If
+ * a key exists in both objects, the provided function is applied to the values
+ * associated with the key in each object, with the result being used as the
+ * value associated with the key in the returned object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Object
+ * @sig ((a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeDeepWith, R.merge, R.mergeWithKey
+ * @example
+ *
+ *      R.mergeWith(R.concat,
+ *                  { a: true, values: [10, 20] },
+ *                  { b: true, values: [15, 35] });
+ *      //=> { a: true, b: true, values: [10, 20, 15, 35] }
+ */
+var mergeWith = _curry3(function mergeWith(fn, l, r) {
+  return mergeWithKey(function(_, _l, _r) {
+    return fn(_l, _r);
+  }, l, r);
+});
+
+/**
+ * Returns the smaller of its two arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> a
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.minBy, R.max
+ * @example
+ *
+ *      R.min(789, 123); //=> 123
+ *      R.min('a', 'b'); //=> 'a'
+ */
+var min = _curry2(function min(a, b) { return b < a ? b : a; });
+
+/**
+ * Takes a function and two values, and returns whichever value produces the
+ * smaller result when passed to the provided function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Relation
+ * @sig Ord b => (a -> b) -> a -> a -> a
+ * @param {Function} f
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.min, R.maxBy
+ * @example
+ *
+ *      //  square :: Number -> Number
+ *      const square = n => n * n;
+ *
+ *      R.minBy(square, -3, 2); //=> 2
+ *
+ *      R.reduce(R.minBy(square), Infinity, [3, -5, 4, 1, -2]); //=> 1
+ *      R.reduce(R.minBy(square), Infinity, []); //=> Infinity
+ */
+var minBy = _curry3(function minBy(f, a, b) {
+  return f(b) < f(a) ? b : a;
+});
+
+/**
+ * Divides the first parameter by the second and returns the remainder. Note
+ * that this function preserves the JavaScript-style behavior for modulo. For
+ * mathematical modulo see [`mathMod`](#mathMod).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The value to the divide.
+ * @param {Number} b The pseudo-modulus
+ * @return {Number} The result of `b % a`.
+ * @see R.mathMod
+ * @example
+ *
+ *      R.modulo(17, 3); //=> 2
+ *      // JS behavior:
+ *      R.modulo(-17, 3); //=> -2
+ *      R.modulo(17, -3); //=> 2
+ *
+ *      const isOdd = R.modulo(R.__, 2);
+ *      isOdd(42); //=> 0
+ *      isOdd(21); //=> 1
+ */
+var modulo = _curry2(function modulo(a, b) { return a % b; });
+
+/**
+ * Move an item, at index `from`, to index `to`, in a list of elements.
+ * A new list will be created containing the new elements order.
+ *
+ * @func
+ * @memberOf R
+ * @category List
+ * @sig Number -> Number -> [a] -> [a]
+ * @param {Number} from The source index
+ * @param {Number} to The destination index
+ * @param {Array} list The list which will serve to realise the move
+ * @return {Array} The new list reordered
+ * @example
+ *
+ *      R.move(0, 2, ['a', 'b', 'c', 'd', 'e', 'f']); //=> ['b', 'c', 'a', 'd', 'e', 'f']
+ *      R.move(-1, 0, ['a', 'b', 'c', 'd', 'e', 'f']); //=> ['f', 'a', 'b', 'c', 'd', 'e'] list rotation
+ */
+var move = _curry3(function(from, to, list) {
+  var length = list.length;
+  var result = list.slice();
+  var positiveFrom = from < 0 ? length + from : from;
+  var positiveTo = to < 0 ? length + to : to;
+  var item = result.splice(positiveFrom, 1);
+
+  return positiveFrom < 0 || positiveFrom >= list.length
+      || positiveTo   < 0 || positiveTo   >= list.length
+    ? list
+    : []
+      .concat(result.slice(0, positiveTo))
+      .concat(item)
+      .concat(result.slice(positiveTo, list.length));
+});
+
+/**
+ * Multiplies two numbers. Equivalent to `a * b` but curried.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The first value.
+ * @param {Number} b The second value.
+ * @return {Number} The result of `a * b`.
+ * @see R.divide
+ * @example
+ *
+ *      const double = R.multiply(2);
+ *      const triple = R.multiply(3);
+ *      double(3);       //=>  6
+ *      triple(4);       //=> 12
+ *      R.multiply(2, 5);  //=> 10
+ */
+var multiply = _curry2(function multiply(a, b) { return a * b; });
+
+/**
+ * Negates its argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Math
+ * @sig Number -> Number
+ * @param {Number} n
+ * @return {Number}
+ * @example
+ *
+ *      R.negate(42); //=> -42
+ */
+var negate = _curry1(function negate(n) { return -n; });
+
+/**
+ * Returns `true` if no elements of the list match the predicate, `false`
+ * otherwise.
+ *
+ * Dispatches to the `all` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Boolean
+ * @param {Function} fn The predicate function.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if the predicate is not satisfied by every element, `false` otherwise.
+ * @see R.all, R.any
+ * @example
+ *
+ *      const isEven = n => n % 2 === 0;
+ *      const isOdd = n => n % 2 === 1;
+ *
+ *      R.none(isEven, [1, 3, 5, 7, 9, 11]); //=> true
+ *      R.none(isOdd, [1, 3, 5, 7, 8, 11]); //=> false
+ */
+var none = _curry2(function none(fn, input) {
+  return all(_complement(fn), input);
+});
+
+/**
+ * Returns a function which returns its nth argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig Number -> *... -> *
+ * @param {Number} n
+ * @return {Function}
+ * @example
+ *
+ *      R.nthArg(1)('a', 'b', 'c'); //=> 'b'
+ *      R.nthArg(-1)('a', 'b', 'c'); //=> 'c'
+ * @symb R.nthArg(-1)(a, b, c) = c
+ * @symb R.nthArg(0)(a, b, c) = a
+ * @symb R.nthArg(1)(a, b, c) = b
+ */
+var nthArg = _curry1(function nthArg(n) {
+  var arity = n < 0 ? 1 : n + 1;
+  return curryN(arity, function() {
+    return nth(n, arguments);
+  });
+});
+
+/**
+ * `o` is a curried composition function that returns a unary function.
+ * Like [`compose`](#compose), `o` performs right-to-left function composition.
+ * Unlike [`compose`](#compose), the rightmost function passed to `o` will be
+ * invoked with only one argument. Also, unlike [`compose`](#compose), `o` is
+ * limited to accepting only 2 unary functions. The name o was chosen because
+ * of its similarity to the mathematical composition operator ∘.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Function
+ * @sig (b -> c) -> (a -> b) -> a -> c
+ * @param {Function} f
+ * @param {Function} g
+ * @return {Function}
+ * @see R.compose, R.pipe
+ * @example
+ *
+ *      const classyGreeting = name => "The name's " + name.last + ", " + name.first + " " + name.last
+ *      const yellGreeting = R.o(R.toUpper, classyGreeting);
+ *      yellGreeting({first: 'James', last: 'Bond'}); //=> "THE NAME'S BOND, JAMES BOND"
+ *
+ *      R.o(R.multiply(10), R.add(10))(-4) //=> 60
+ *
+ * @symb R.o(f, g, x) = f(g(x))
+ */
+var o = _curry3(function o(f, g, x) {
+  return f(g(x));
+});
+
+function _of(x) { return [x]; }
+
+/**
+ * Returns a singleton array containing the value provided.
+ *
+ * Note this `of` is different from the ES6 `of`; See
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/of
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Function
+ * @sig a -> [a]
+ * @param {*} x any value
+ * @return {Array} An array wrapping `x`.
+ * @example
+ *
+ *      R.of(null); //=> [null]
+ *      R.of([42]); //=> [[42]]
+ */
+var of = _curry1(_of);
+
+/**
+ * Returns a partial copy of an object omitting the keys specified.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [String] -> {String: *} -> {String: *}
+ * @param {Array} names an array of String property names to omit from the new object
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with properties from `names` not on it.
+ * @see R.pick
+ * @example
+ *
+ *      R.omit(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, c: 3}
+ */
+var omit = _curry2(function omit(names, obj) {
+  var result = {};
+  var index = {};
+  var idx = 0;
+  var len = names.length;
+
+  while (idx < len) {
+    index[names[idx]] = 1;
+    idx += 1;
+  }
+
+  for (var prop in obj) {
+    if (!index.hasOwnProperty(prop)) {
+      result[prop] = obj[prop];
+    }
+  }
+  return result;
+});
+
+/**
+ * Accepts a function `fn` and returns a function that guards invocation of
+ * `fn` such that `fn` can only ever be called once, no matter how many times
+ * the returned function is invoked. The first value calculated is returned in
+ * subsequent invocations.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (a... -> b) -> (a... -> b)
+ * @param {Function} fn The function to wrap in a call-only-once wrapper.
+ * @return {Function} The wrapped function.
+ * @example
+ *
+ *      const addOneOnce = R.once(x => x + 1);
+ *      addOneOnce(10); //=> 11
+ *      addOneOnce(addOneOnce(50)); //=> 11
+ */
+var once = _curry1(function once(fn) {
+  var called = false;
+  var result;
+  return _arity(fn.length, function() {
+    if (called) {
+      return result;
+    }
+    called = true;
+    result = fn.apply(this, arguments);
+    return result;
+  });
+});
+
+function _assertPromise(name, p) {
+  if (p == null || !_isFunction(p.then)) {
+    throw new TypeError('`' + name + '` expected a Promise, received ' + _toString(p, []));
+  }
+}
+
+/**
+ * Returns the result of applying the onFailure function to the value inside
+ * a failed promise. This is useful for handling rejected promises
+ * inside function compositions.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig (e -> b) -> (Promise e a) -> (Promise e b)
+ * @sig (e -> (Promise f b)) -> (Promise e a) -> (Promise f b)
+ * @param {Function} onFailure The function to apply. Can return a value or a promise of a value.
+ * @param {Promise} p
+ * @return {Promise} The result of calling `p.then(null, onFailure)`
+ * @see R.then
+ * @example
+ *
+ *      var failedFetch = (id) => Promise.reject('bad ID');
+ *      var useDefault = () => ({ firstName: 'Bob', lastName: 'Loblaw' })
+ *
+ *      //recoverFromFailure :: String -> Promise ({firstName, lastName})
+ *      var recoverFromFailure = R.pipe(
+ *        failedFetch,
+ *        R.otherwise(useDefault),
+ *        R.then(R.pick(['firstName', 'lastName'])),
+ *      );
+ *      recoverFromFailure(12345).then(console.log)
+ */
+var otherwise = _curry2(function otherwise(f, p) {
+  _assertPromise('otherwise', p);
+
+  return p.then(null, f);
+});
+
+// `Identity` is a functor that holds a single value, where `map` simply
+// transforms the held value with the provided function.
+var Identity = function(x) {
+  return {value: x, map: function(f) { return Identity(f(x)); }};
+};
+
+
+/**
+ * Returns the result of "setting" the portion of the given data structure
+ * focused by the given lens to the result of applying the given function to
+ * the focused value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Lens s a -> (a -> a) -> s -> s
+ * @param {Lens} lens
+ * @param {*} v
+ * @param {*} x
+ * @return {*}
+ * @see R.prop, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const headLens = R.lensIndex(0);
+ *
+ *      R.over(headLens, R.toUpper, ['foo', 'bar', 'baz']); //=> ['FOO', 'bar', 'baz']
+ */
+var over = _curry3(function over(lens, f, x) {
+  // The value returned by the getter function is first transformed with `f`,
+  // then set as the value of an `Identity`. This is then mapped over with the
+  // setter function of the lens.
+  return lens(function(y) { return Identity(f(y)); })(x).value;
+});
+
+/**
+ * Takes two arguments, `fst` and `snd`, and returns `[fst, snd]`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category List
+ * @sig a -> b -> (a,b)
+ * @param {*} fst
+ * @param {*} snd
+ * @return {Array}
+ * @see R.objOf, R.of
+ * @example
+ *
+ *      R.pair('foo', 'bar'); //=> ['foo', 'bar']
+ */
+var pair = _curry2(function pair(fst, snd) { return [fst, snd]; });
+
+function _createPartialApplicator(concat) {
+  return _curry2(function(fn, args) {
+    return _arity(Math.max(0, fn.length - args.length), function() {
+      return fn.apply(this, concat(args, arguments));
+    });
+  });
+}
+
+/**
+ * Takes a function `f` and a list of arguments, and returns a function `g`.
+ * When applied, `g` returns the result of applying `f` to the arguments
+ * provided initially followed by the arguments provided to `g`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((a, b, c, ..., n) -> x) -> [a, b, c, ...] -> ((d, e, f, ..., n) -> x)
+ * @param {Function} f
+ * @param {Array} args
+ * @return {Function}
+ * @see R.partialRight, R.curry
+ * @example
+ *
+ *      const multiply2 = (a, b) => a * b;
+ *      const double = R.partial(multiply2, [2]);
+ *      double(2); //=> 4
+ *
+ *      const greet = (salutation, title, firstName, lastName) =>
+ *        salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
+ *
+ *      const sayHello = R.partial(greet, ['Hello']);
+ *      const sayHelloToMs = R.partial(sayHello, ['Ms.']);
+ *      sayHelloToMs('Jane', 'Jones'); //=> 'Hello, Ms. Jane Jones!'
+ * @symb R.partial(f, [a, b])(c, d) = f(a, b, c, d)
+ */
+var partial = _createPartialApplicator(_concat);
+
+/**
+ * Takes a function `f` and a list of arguments, and returns a function `g`.
+ * When applied, `g` returns the result of applying `f` to the arguments
+ * provided to `g` followed by the arguments provided initially.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((a, b, c, ..., n) -> x) -> [d, e, f, ..., n] -> ((a, b, c, ...) -> x)
+ * @param {Function} f
+ * @param {Array} args
+ * @return {Function}
+ * @see R.partial
+ * @example
+ *
+ *      const greet = (salutation, title, firstName, lastName) =>
+ *        salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
+ *
+ *      const greetMsJaneJones = R.partialRight(greet, ['Ms.', 'Jane', 'Jones']);
+ *
+ *      greetMsJaneJones('Hello'); //=> 'Hello, Ms. Jane Jones!'
+ * @symb R.partialRight(f, [a, b])(c, d) = f(c, d, a, b)
+ */
+var partialRight = _createPartialApplicator(flip(_concat));
+
+/**
+ * Takes a predicate and a list or other `Filterable` object and returns the
+ * pair of filterable objects of the same type of elements which do and do not
+ * satisfy, the predicate, respectively. Filterable objects include plain objects or any object
+ * that has a filter method such as `Array`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.4
+ * @category List
+ * @sig Filterable f => (a -> Boolean) -> f a -> [f a, f a]
+ * @param {Function} pred A predicate to determine which side the element belongs to.
+ * @param {Array} filterable the list (or other filterable) to partition.
+ * @return {Array} An array, containing first the subset of elements that satisfy the
+ *         predicate, and second the subset of elements that do not satisfy.
+ * @see R.filter, R.reject
+ * @example
+ *
+ *      R.partition(R.includes('s'), ['sss', 'ttt', 'foo', 'bars']);
+ *      // => [ [ 'sss', 'bars' ],  [ 'ttt', 'foo' ] ]
+ *
+ *      R.partition(R.includes('s'), { a: 'sss', b: 'ttt', foo: 'bars' });
+ *      // => [ { a: 'sss', foo: 'bars' }, { b: 'ttt' }  ]
+ */
+var partition = juxt([filter, reject]);
+
+/**
+ * Determines whether a nested path on an object has a specific value, in
+ * [`R.equals`](#equals) terms. Most likely used to filter a list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Relation
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> a -> {a} -> Boolean
+ * @param {Array} path The path of the nested property to use
+ * @param {*} val The value to compare the nested property with
+ * @param {Object} obj The object to check the nested property in
+ * @return {Boolean} `true` if the value equals the nested object property,
+ *         `false` otherwise.
+ * @example
+ *
+ *      const user1 = { address: { zipCode: 90210 } };
+ *      const user2 = { address: { zipCode: 55555 } };
+ *      const user3 = { name: 'Bob' };
+ *      const users = [ user1, user2, user3 ];
+ *      const isFamous = R.pathEq(['address', 'zipCode'], 90210);
+ *      R.filter(isFamous, users); //=> [ user1 ]
+ */
+var pathEq = _curry3(function pathEq(_path, val, obj) {
+  return equals(path(_path, obj), val);
+});
+
+/**
+ * If the given, non-null object has a value at the given path, returns the
+ * value at that path. Otherwise returns the provided default value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig a -> [Idx] -> {a} -> a
+ * @param {*} d The default value.
+ * @param {Array} p The path to use.
+ * @param {Object} obj The object to retrieve the nested property from.
+ * @return {*} The data at `path` of the supplied object or the default value.
+ * @example
+ *
+ *      R.pathOr('N/A', ['a', 'b'], {a: {b: 2}}); //=> 2
+ *      R.pathOr('N/A', ['a', 'b'], {c: {b: 2}}); //=> "N/A"
+ */
+var pathOr = _curry3(function pathOr(d, p, obj) {
+  return defaultTo(d, path(p, obj));
+});
+
+/**
+ * Returns `true` if the specified object property at given path satisfies the
+ * given predicate; `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Logic
+ * @typedefn Idx = String | Int
+ * @sig (a -> Boolean) -> [Idx] -> {a} -> Boolean
+ * @param {Function} pred
+ * @param {Array} propPath
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.propSatisfies, R.path
+ * @example
+ *
+ *      R.pathSatisfies(y => y > 0, ['x', 'y'], {x: {y: 2}}); //=> true
+ */
+var pathSatisfies = _curry3(function pathSatisfies(pred, propPath, obj) {
+  return propPath.length > 0 && pred(path(propPath, obj));
+});
+
+/**
+ * Returns a partial copy of an object containing only the keys specified. If
+ * the key does not exist, the property is ignored.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [k] -> {k: v} -> {k: v}
+ * @param {Array} names an array of String property names to copy onto a new object
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with only properties from `names` on it.
+ * @see R.omit, R.props
+ * @example
+ *
+ *      R.pick(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4}
+ *      R.pick(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1}
+ */
+var pick = _curry2(function pick(names, obj) {
+  var result = {};
+  var idx = 0;
+  while (idx < names.length) {
+    if (names[idx] in obj) {
+      result[names[idx]] = obj[names[idx]];
+    }
+    idx += 1;
+  }
+  return result;
+});
+
+/**
+ * Similar to `pick` except that this one includes a `key: undefined` pair for
+ * properties that don't exist.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [k] -> {k: v} -> {k: v}
+ * @param {Array} names an array of String property names to copy onto a new object
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with only properties from `names` on it.
+ * @see R.pick
+ * @example
+ *
+ *      R.pickAll(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4}
+ *      R.pickAll(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, e: undefined, f: undefined}
+ */
+var pickAll = _curry2(function pickAll(names, obj) {
+  var result = {};
+  var idx = 0;
+  var len = names.length;
+  while (idx < len) {
+    var name = names[idx];
+    result[name] = obj[name];
+    idx += 1;
+  }
+  return result;
+});
+
+/**
+ * Returns a partial copy of an object containing only the keys that satisfy
+ * the supplied predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @sig ((v, k) -> Boolean) -> {k: v} -> {k: v}
+ * @param {Function} pred A predicate to determine whether or not a key
+ *        should be included on the output object.
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with only properties that satisfy `pred`
+ *         on it.
+ * @see R.pick, R.filter
+ * @example
+ *
+ *      const isUpperCase = (val, key) => key.toUpperCase() === key;
+ *      R.pickBy(isUpperCase, {a: 1, b: 2, A: 3, B: 4}); //=> {A: 3, B: 4}
+ */
+var pickBy = _curry2(function pickBy(test, obj) {
+  var result = {};
+  for (var prop in obj) {
+    if (test(obj[prop], prop, obj)) {
+      result[prop] = obj[prop];
+    }
+  }
+  return result;
+});
+
+/**
+ * Returns the left-to-right Kleisli composition of the provided functions,
+ * each of which must return a value of a type supported by [`chain`](#chain).
+ *
+ * `R.pipeK(f, g, h)` is equivalent to `R.pipe(f, R.chain(g), R.chain(h))`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Function
+ * @sig Chain m => ((a -> m b), (b -> m c), ..., (y -> m z)) -> (a -> m z)
+ * @param {...Function}
+ * @return {Function}
+ * @see R.composeK
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      //  parseJson :: String -> Maybe *
+ *      //  get :: String -> Object -> Maybe *
+ *
+ *      //  getStateCode :: Maybe String -> Maybe String
+ *      const getStateCode = R.pipeK(
+ *        parseJson,
+ *        get('user'),
+ *        get('address'),
+ *        get('state'),
+ *        R.compose(Maybe.of, R.toUpper)
+ *      );
+ *
+ *      getStateCode('{"user":{"address":{"state":"ny"}}}');
+ *      //=> Just('NY')
+ *      getStateCode('[Invalid JSON]');
+ *      //=> Nothing()
+ * @symb R.pipeK(f, g, h)(a) = R.chain(h, R.chain(g, f(a)))
+ */
+function pipeK() {
+  if (arguments.length === 0) {
+    throw new Error('pipeK requires at least one argument');
+  }
+  return composeK.apply(this, reverse(arguments));
+}
+
+/**
+ * Returns a new list with the given element at the front, followed by the
+ * contents of the list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> [a]
+ * @param {*} el The item to add to the head of the output list.
+ * @param {Array} list The array to add to the tail of the output list.
+ * @return {Array} A new array.
+ * @see R.append
+ * @example
+ *
+ *      R.prepend('fee', ['fi', 'fo', 'fum']); //=> ['fee', 'fi', 'fo', 'fum']
+ */
+var prepend = _curry2(function prepend(el, list) {
+  return _concat([el], list);
+});
+
+/**
+ * Multiplies together all the elements of a list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list An array of numbers
+ * @return {Number} The product of all the numbers in the list.
+ * @see R.reduce
+ * @example
+ *
+ *      R.product([2,4,6,8,100,1]); //=> 38400
+ */
+var product = reduce(multiply, 1);
+
+/**
+ * Accepts a function `fn` and a list of transformer functions and returns a
+ * new curried function. When the new function is invoked, it calls the
+ * function `fn` with parameters consisting of the result of calling each
+ * supplied handler on successive arguments to the new function.
+ *
+ * If more arguments are passed to the returned function than transformer
+ * functions, those arguments are passed directly to `fn` as additional
+ * parameters. If you expect additional arguments that don't need to be
+ * transformed, although you can ignore them, it's best to pass an identity
+ * function so that the new function reports the correct arity.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((x1, x2, ...) -> z) -> [(a -> x1), (b -> x2), ...] -> (a -> b -> ... -> z)
+ * @param {Function} fn The function to wrap.
+ * @param {Array} transformers A list of transformer functions
+ * @return {Function} The wrapped function.
+ * @see R.converge
+ * @example
+ *
+ *      R.useWith(Math.pow, [R.identity, R.identity])(3, 4); //=> 81
+ *      R.useWith(Math.pow, [R.identity, R.identity])(3)(4); //=> 81
+ *      R.useWith(Math.pow, [R.dec, R.inc])(3, 4); //=> 32
+ *      R.useWith(Math.pow, [R.dec, R.inc])(3)(4); //=> 32
+ * @symb R.useWith(f, [g, h])(a, b) = f(g(a), h(b))
+ */
+var useWith = _curry2(function useWith(fn, transformers) {
+  return curryN(transformers.length, function() {
+    var args = [];
+    var idx = 0;
+    while (idx < transformers.length) {
+      args.push(transformers[idx].call(this, arguments[idx]));
+      idx += 1;
+    }
+    return fn.apply(this, args.concat(Array.prototype.slice.call(arguments, transformers.length)));
+  });
+});
+
+/**
+ * Reasonable analog to SQL `select` statement.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @category Relation
+ * @sig [k] -> [{k: v}] -> [{k: v}]
+ * @param {Array} props The property names to project
+ * @param {Array} objs The objects to query
+ * @return {Array} An array of objects with just the `props` properties.
+ * @example
+ *
+ *      const abby = {name: 'Abby', age: 7, hair: 'blond', grade: 2};
+ *      const fred = {name: 'Fred', age: 12, hair: 'brown', grade: 7};
+ *      const kids = [abby, fred];
+ *      R.project(['name', 'grade'], kids); //=> [{name: 'Abby', grade: 2}, {name: 'Fred', grade: 7}]
+ */
+var project = useWith(_map, [pickAll, identity]); // passing `identity` gives correct arity
+
+/**
+ * Returns `true` if the specified object property is equal, in
+ * [`R.equals`](#equals) terms, to the given value; `false` otherwise.
+ * You can test multiple properties with [`R.whereEq`](#whereEq).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig String -> a -> Object -> Boolean
+ * @param {String} name
+ * @param {*} val
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.whereEq, R.propSatisfies, R.equals
+ * @example
+ *
+ *      const abby = {name: 'Abby', age: 7, hair: 'blond'};
+ *      const fred = {name: 'Fred', age: 12, hair: 'brown'};
+ *      const rusty = {name: 'Rusty', age: 10, hair: 'brown'};
+ *      const alois = {name: 'Alois', age: 15, disposition: 'surly'};
+ *      const kids = [abby, fred, rusty, alois];
+ *      const hasBrownHair = R.propEq('hair', 'brown');
+ *      R.filter(hasBrownHair, kids); //=> [fred, rusty]
+ */
+var propEq = _curry3(function propEq(name, val, obj) {
+  return equals(val, obj[name]);
+});
+
+/**
+ * Returns `true` if the specified object property is of the given type;
+ * `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Type
+ * @sig Type -> String -> Object -> Boolean
+ * @param {Function} type
+ * @param {String} name
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.is, R.propSatisfies
+ * @example
+ *
+ *      R.propIs(Number, 'x', {x: 1, y: 2});  //=> true
+ *      R.propIs(Number, 'x', {x: 'foo'});    //=> false
+ *      R.propIs(Number, 'x', {});            //=> false
+ */
+var propIs = _curry3(function propIs(type, name, obj) {
+  return is(type, obj[name]);
+});
+
+/**
+ * If the given, non-null object has an own property with the specified name,
+ * returns the value of that property. Otherwise returns the provided default
+ * value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category Object
+ * @sig a -> String -> Object -> a
+ * @param {*} val The default value.
+ * @param {String} p The name of the property to return.
+ * @param {Object} obj The object to query.
+ * @return {*} The value of given property of the supplied object or the default value.
+ * @example
+ *
+ *      const alice = {
+ *        name: 'ALICE',
+ *        age: 101
+ *      };
+ *      const favorite = R.prop('favoriteLibrary');
+ *      const favoriteWithDefault = R.propOr('Ramda', 'favoriteLibrary');
+ *
+ *      favorite(alice);  //=> undefined
+ *      favoriteWithDefault(alice);  //=> 'Ramda'
+ */
+var propOr = _curry3(function propOr(val, p, obj) {
+  return pathOr(val, [p], obj);
+});
+
+/**
+ * Returns `true` if the specified object property satisfies the given
+ * predicate; `false` otherwise. You can test multiple properties with
+ * [`R.where`](#where).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Logic
+ * @sig (a -> Boolean) -> String -> {String: a} -> Boolean
+ * @param {Function} pred
+ * @param {String} name
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.where, R.propEq, R.propIs
+ * @example
+ *
+ *      R.propSatisfies(x => x > 0, 'x', {x: 1, y: 2}); //=> true
+ */
+var propSatisfies = _curry3(function propSatisfies(pred, name, obj) {
+  return pred(obj[name]);
+});
+
+/**
+ * Acts as multiple `prop`: array of keys in, array of values out. Preserves
+ * order.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [k] -> {k: v} -> [v]
+ * @param {Array} ps The property names to fetch
+ * @param {Object} obj The object to query
+ * @return {Array} The corresponding values or partially applied function.
+ * @example
+ *
+ *      R.props(['x', 'y'], {x: 1, y: 2}); //=> [1, 2]
+ *      R.props(['c', 'a', 'b'], {b: 2, a: 1}); //=> [undefined, 1, 2]
+ *
+ *      const fullName = R.compose(R.join(' '), R.props(['first', 'last']));
+ *      fullName({last: 'Bullet-Tooth', age: 33, first: 'Tony'}); //=> 'Tony Bullet-Tooth'
+ */
+var props = _curry2(function props(ps, obj) {
+  var len = ps.length;
+  var out = [];
+  var idx = 0;
+
+  while (idx < len) {
+    out[idx] = obj[ps[idx]];
+    idx += 1;
+  }
+
+  return out;
+});
+
+/**
+ * Returns a list of numbers from `from` (inclusive) to `to` (exclusive).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> Number -> [Number]
+ * @param {Number} from The first number in the list.
+ * @param {Number} to One more than the last number in the list.
+ * @return {Array} The list of numbers in the set `[a, b)`.
+ * @example
+ *
+ *      R.range(1, 5);    //=> [1, 2, 3, 4]
+ *      R.range(50, 53);  //=> [50, 51, 52]
+ */
+var range = _curry2(function range(from, to) {
+  if (!(_isNumber(from) && _isNumber(to))) {
+    throw new TypeError('Both arguments to range must be numbers');
+  }
+  var result = [];
+  var n = from;
+  while (n < to) {
+    result.push(n);
+    n += 1;
+  }
+  return result;
+});
+
+/**
+ * Returns a single item by iterating through the list, successively calling
+ * the iterator function and passing it an accumulator value and the current
+ * value from the array, and then passing the result to the next call.
+ *
+ * Similar to [`reduce`](#reduce), except moves through the input list from the
+ * right to the left.
+ *
+ * The iterator function receives two values: *(value, acc)*, while the arguments'
+ * order of `reduce`'s iterator function is *(acc, value)*.
+ *
+ * Note: `R.reduceRight` does not skip deleted or unassigned indices (sparse
+ * arrays), unlike the native `Array.prototype.reduceRight` method. For more details
+ * on this behavior, see:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight#Description
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, b) -> b) -> b -> [a] -> b
+ * @param {Function} fn The iterator function. Receives two values, the current element from the array
+ *        and the accumulator.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduce, R.addIndex
+ * @example
+ *
+ *      R.reduceRight(R.subtract, 0, [1, 2, 3, 4]) // => (1 - (2 - (3 - (4 - 0)))) = -2
+ *      //    -               -2
+ *      //   / \              / \
+ *      //  1   -            1   3
+ *      //     / \              / \
+ *      //    2   -     ==>    2  -1
+ *      //       / \              / \
+ *      //      3   -            3   4
+ *      //         / \              / \
+ *      //        4   0            4   0
+ *
+ * @symb R.reduceRight(f, a, [b, c, d]) = f(b, f(c, f(d, a)))
+ */
+var reduceRight = _curry3(function reduceRight(fn, acc, list) {
+  var idx = list.length - 1;
+  while (idx >= 0) {
+    acc = fn(list[idx], acc);
+    idx -= 1;
+  }
+  return acc;
+});
+
+/**
+ * Like [`reduce`](#reduce), `reduceWhile` returns a single item by iterating
+ * through the list, successively calling the iterator function. `reduceWhile`
+ * also takes a predicate that is evaluated before each step. If the predicate
+ * returns `false`, it "short-circuits" the iteration and returns the current
+ * value of the accumulator.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.22.0
+ * @category List
+ * @sig ((a, b) -> Boolean) -> ((a, b) -> a) -> a -> [b] -> a
+ * @param {Function} pred The predicate. It is passed the accumulator and the
+ *        current element.
+ * @param {Function} fn The iterator function. Receives two values, the
+ *        accumulator and the current element.
+ * @param {*} a The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduce, R.reduced
+ * @example
+ *
+ *      const isOdd = (acc, x) => x % 2 === 1;
+ *      const xs = [1, 3, 5, 60, 777, 800];
+ *      R.reduceWhile(isOdd, R.add, 0, xs); //=> 9
+ *
+ *      const ys = [2, 4, 6]
+ *      R.reduceWhile(isOdd, R.add, 111, ys); //=> 111
+ */
+var reduceWhile = _curryN(4, [], function _reduceWhile(pred, fn, a, list) {
+  return _reduce(function(acc, x) {
+    return pred(acc, x) ? fn(acc, x) : _reduced(acc);
+  }, a, list);
+});
+
+/**
+ * Returns a value wrapped to indicate that it is the final value of the reduce
+ * and transduce functions. The returned value should be considered a black
+ * box: the internal structure is not guaranteed to be stable.
+ *
+ * Note: this optimization is only available to the below functions:
+ * - [`reduce`](#reduce)
+ * - [`reduceWhile`](#reduceWhile)
+ * - [`transduce`](#transduce)
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category List
+ * @sig a -> *
+ * @param {*} x The final value of the reduce.
+ * @return {*} The wrapped value.
+ * @see R.reduce, R.reduceWhile, R.transduce
+ * @example
+ *
+ *     R.reduce(
+ *       (acc, item) => item > 3 ? R.reduced(acc) : acc.concat(item),
+ *       [],
+ *       [1, 2, 3, 4, 5]) // [1, 2, 3]
+ */
+var reduced = _curry1(_reduced);
+
+/**
+ * Calls an input function `n` times, returning an array containing the results
+ * of those function calls.
+ *
+ * `fn` is passed one argument: The current value of `n`, which begins at `0`
+ * and is gradually incremented to `n - 1`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.3
+ * @category List
+ * @sig (Number -> a) -> Number -> [a]
+ * @param {Function} fn The function to invoke. Passed one argument, the current value of `n`.
+ * @param {Number} n A value between `0` and `n - 1`. Increments after each function call.
+ * @return {Array} An array containing the return values of all calls to `fn`.
+ * @see R.repeat
+ * @example
+ *
+ *      R.times(R.identity, 5); //=> [0, 1, 2, 3, 4]
+ * @symb R.times(f, 0) = []
+ * @symb R.times(f, 1) = [f(0)]
+ * @symb R.times(f, 2) = [f(0), f(1)]
+ */
+var times = _curry2(function times(fn, n) {
+  var len = Number(n);
+  var idx = 0;
+  var list;
+
+  if (len < 0 || isNaN(len)) {
+    throw new RangeError('n must be a non-negative number');
+  }
+  list = new Array(len);
+  while (idx < len) {
+    list[idx] = fn(idx);
+    idx += 1;
+  }
+  return list;
+});
+
+/**
+ * Returns a fixed list of size `n` containing a specified identical value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig a -> n -> [a]
+ * @param {*} value The value to repeat.
+ * @param {Number} n The desired size of the output list.
+ * @return {Array} A new array containing `n` `value`s.
+ * @see R.times
+ * @example
+ *
+ *      R.repeat('hi', 5); //=> ['hi', 'hi', 'hi', 'hi', 'hi']
+ *
+ *      const obj = {};
+ *      const repeatedObjs = R.repeat(obj, 5); //=> [{}, {}, {}, {}, {}]
+ *      repeatedObjs[0] === repeatedObjs[1]; //=> true
+ * @symb R.repeat(a, 0) = []
+ * @symb R.repeat(a, 1) = [a]
+ * @symb R.repeat(a, 2) = [a, a]
+ */
+var repeat = _curry2(function repeat(value, n) {
+  return times(always(value), n);
+});
+
+/**
+ * Replace a substring or regex match in a string with a replacement.
+ *
+ * The first two parameters correspond to the parameters of the
+ * `String.prototype.replace()` function, so the second parameter can also be a
+ * function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category String
+ * @sig RegExp|String -> String -> String -> String
+ * @param {RegExp|String} pattern A regular expression or a substring to match.
+ * @param {String} replacement The string to replace the matches with.
+ * @param {String} str The String to do the search and replacement in.
+ * @return {String} The result.
+ * @example
+ *
+ *      R.replace('foo', 'bar', 'foo foo foo'); //=> 'bar foo foo'
+ *      R.replace(/foo/, 'bar', 'foo foo foo'); //=> 'bar foo foo'
+ *
+ *      // Use the "g" (global) flag to replace all occurrences:
+ *      R.replace(/foo/g, 'bar', 'foo foo foo'); //=> 'bar bar bar'
+ */
+var replace = _curry3(function replace(regex, replacement, str) {
+  return str.replace(regex, replacement);
+});
+
+/**
+ * Scan is similar to [`reduce`](#reduce), but returns a list of successively
+ * reduced values from the left
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig ((a, b) -> a) -> a -> [b] -> [a]
+ * @param {Function} fn The iterator function. Receives two values, the accumulator and the
+ *        current element from the array
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {Array} A list of all intermediately reduced values.
+ * @see R.reduce, R.mapAccum
+ * @example
+ *
+ *      const numbers = [1, 2, 3, 4];
+ *      const factorials = R.scan(R.multiply, 1, numbers); //=> [1, 1, 2, 6, 24]
+ * @symb R.scan(f, a, [b, c]) = [a, f(a, b), f(f(a, b), c)]
+ */
+var scan = _curry3(function scan(fn, acc, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [acc];
+  while (idx < len) {
+    acc = fn(acc, list[idx]);
+    result[idx + 1] = acc;
+    idx += 1;
+  }
+  return result;
+});
+
+/**
+ * Transforms a [Traversable](https://github.com/fantasyland/fantasy-land#traversable)
+ * of [Applicative](https://github.com/fantasyland/fantasy-land#applicative) into an
+ * Applicative of Traversable.
+ *
+ * Dispatches to the `sequence` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (Applicative f, Traversable t) => (a -> f a) -> t (f a) -> f (t a)
+ * @param {Function} of
+ * @param {*} traversable
+ * @return {*}
+ * @see R.traverse
+ * @example
+ *
+ *      R.sequence(Maybe.of, [Just(1), Just(2), Just(3)]);   //=> Just([1, 2, 3])
+ *      R.sequence(Maybe.of, [Just(1), Just(2), Nothing()]); //=> Nothing()
+ *
+ *      R.sequence(R.of, Just([1, 2, 3])); //=> [Just(1), Just(2), Just(3)]
+ *      R.sequence(R.of, Nothing());       //=> [Nothing()]
+ */
+var sequence = _curry2(function sequence(of, traversable) {
+  return typeof traversable.sequence === 'function' ?
+    traversable.sequence(of) :
+    reduceRight(
+      function(x, acc) { return ap(map(prepend, x), acc); },
+      of([]),
+      traversable
+    );
+});
+
+/**
+ * Returns the result of "setting" the portion of the given data structure
+ * focused by the given lens to the given value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Lens s a -> a -> s -> s
+ * @param {Lens} lens
+ * @param {*} v
+ * @param {*} x
+ * @return {*}
+ * @see R.prop, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const xLens = R.lensProp('x');
+ *
+ *      R.set(xLens, 4, {x: 1, y: 2});  //=> {x: 4, y: 2}
+ *      R.set(xLens, 8, {x: 1, y: 2});  //=> {x: 8, y: 2}
+ */
+var set = _curry3(function set(lens, v, x) {
+  return over(lens, always(v), x);
+});
+
+/**
+ * Returns a copy of the list, sorted according to the comparator function,
+ * which should accept two values at a time and return a negative number if the
+ * first value is smaller, a positive number if it's larger, and zero if they
+ * are equal. Please note that this is a **copy** of the list. It does not
+ * modify the original.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, a) -> Number) -> [a] -> [a]
+ * @param {Function} comparator A sorting function :: a -> b -> Int
+ * @param {Array} list The list to sort
+ * @return {Array} a new array with its elements sorted by the comparator function.
+ * @example
+ *
+ *      const diff = function(a, b) { return a - b; };
+ *      R.sort(diff, [4,2,7,5]); //=> [2, 4, 5, 7]
+ */
+var sort = _curry2(function sort(comparator, list) {
+  return Array.prototype.slice.call(list, 0).sort(comparator);
+});
+
+/**
+ * Sorts the list according to the supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord b => (a -> b) -> [a] -> [a]
+ * @param {Function} fn
+ * @param {Array} list The list to sort.
+ * @return {Array} A new list sorted by the keys generated by `fn`.
+ * @example
+ *
+ *      const sortByFirstItem = R.sortBy(R.prop(0));
+ *      const pairs = [[-1, 1], [-2, 2], [-3, 3]];
+ *      sortByFirstItem(pairs); //=> [[-3, 3], [-2, 2], [-1, 1]]
+ *
+ *      const sortByNameCaseInsensitive = R.sortBy(R.compose(R.toLower, R.prop('name')));
+ *      const alice = {
+ *        name: 'ALICE',
+ *        age: 101
+ *      };
+ *      const bob = {
+ *        name: 'Bob',
+ *        age: -10
+ *      };
+ *      const clara = {
+ *        name: 'clara',
+ *        age: 314.159
+ *      };
+ *      const people = [clara, bob, alice];
+ *      sortByNameCaseInsensitive(people); //=> [alice, bob, clara]
+ */
+var sortBy = _curry2(function sortBy(fn, list) {
+  return Array.prototype.slice.call(list, 0).sort(function(a, b) {
+    var aa = fn(a);
+    var bb = fn(b);
+    return aa < bb ? -1 : aa > bb ? 1 : 0;
+  });
+});
+
+/**
+ * Sorts a list according to a list of comparators.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Relation
+ * @sig [(a, a) -> Number] -> [a] -> [a]
+ * @param {Array} functions A list of comparator functions.
+ * @param {Array} list The list to sort.
+ * @return {Array} A new list sorted according to the comarator functions.
+ * @example
+ *
+ *      const alice = {
+ *        name: 'alice',
+ *        age: 40
+ *      };
+ *      const bob = {
+ *        name: 'bob',
+ *        age: 30
+ *      };
+ *      const clara = {
+ *        name: 'clara',
+ *        age: 40
+ *      };
+ *      const people = [clara, bob, alice];
+ *      const ageNameSort = R.sortWith([
+ *        R.descend(R.prop('age')),
+ *        R.ascend(R.prop('name'))
+ *      ]);
+ *      ageNameSort(people); //=> [alice, clara, bob]
+ */
+var sortWith = _curry2(function sortWith(fns, list) {
+  return Array.prototype.slice.call(list, 0).sort(function(a, b) {
+    var result = 0;
+    var i = 0;
+    while (result === 0 && i < fns.length) {
+      result = fns[i](a, b);
+      i += 1;
+    }
+    return result;
+  });
+});
+
+/**
+ * Splits a string into an array of strings based on the given
+ * separator.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category String
+ * @sig (String | RegExp) -> String -> [String]
+ * @param {String|RegExp} sep The pattern.
+ * @param {String} str The string to separate into an array.
+ * @return {Array} The array of strings from `str` separated by `str`.
+ * @see R.join
+ * @example
+ *
+ *      const pathComponents = R.split('/');
+ *      R.tail(pathComponents('/usr/local/bin/node')); //=> ['usr', 'local', 'bin', 'node']
+ *
+ *      R.split('.', 'a.b.c.xyz.d'); //=> ['a', 'b', 'c', 'xyz', 'd']
+ */
+var split = invoker(1, 'split');
+
+/**
+ * Splits a given list or string at a given index.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig Number -> [a] -> [[a], [a]]
+ * @sig Number -> String -> [String, String]
+ * @param {Number} index The index where the array/string is split.
+ * @param {Array|String} array The array/string to be split.
+ * @return {Array}
+ * @example
+ *
+ *      R.splitAt(1, [1, 2, 3]);          //=> [[1], [2, 3]]
+ *      R.splitAt(5, 'hello world');      //=> ['hello', ' world']
+ *      R.splitAt(-1, 'foobar');          //=> ['fooba', 'r']
+ */
+var splitAt = _curry2(function splitAt(index, array) {
+  return [slice(0, index, array), slice(index, length(array), array)];
+});
+
+/**
+ * Splits a collection into slices of the specified length.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig Number -> [a] -> [[a]]
+ * @sig Number -> String -> [String]
+ * @param {Number} n
+ * @param {Array} list
+ * @return {Array}
+ * @example
+ *
+ *      R.splitEvery(3, [1, 2, 3, 4, 5, 6, 7]); //=> [[1, 2, 3], [4, 5, 6], [7]]
+ *      R.splitEvery(3, 'foobarbaz'); //=> ['foo', 'bar', 'baz']
+ */
+var splitEvery = _curry2(function splitEvery(n, list) {
+  if (n <= 0) {
+    throw new Error('First argument to splitEvery must be a positive integer');
+  }
+  var result = [];
+  var idx = 0;
+  while (idx < list.length) {
+    result.push(slice(idx, idx += n, list));
+  }
+  return result;
+});
+
+/**
+ * Takes a list and a predicate and returns a pair of lists with the following properties:
+ *
+ *  - the result of concatenating the two output lists is equivalent to the input list;
+ *  - none of the elements of the first output list satisfies the predicate; and
+ *  - if the second output list is non-empty, its first element satisfies the predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [[a], [a]]
+ * @param {Function} pred The predicate that determines where the array is split.
+ * @param {Array} list The array to be split.
+ * @return {Array}
+ * @example
+ *
+ *      R.splitWhen(R.equals(2), [1, 2, 3, 1, 2, 3]);   //=> [[1], [2, 3, 1, 2, 3]]
+ */
+var splitWhen = _curry2(function splitWhen(pred, list) {
+  var idx = 0;
+  var len = list.length;
+  var prefix = [];
+
+  while (idx < len && !pred(list[idx])) {
+    prefix.push(list[idx]);
+    idx += 1;
+  }
+
+  return [prefix, Array.prototype.slice.call(list, idx)];
+});
+
+/**
+ * Checks if a list starts with the provided sublist.
+ *
+ * Similarly, checks if a string starts with the provided substring.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category List
+ * @sig [a] -> [a] -> Boolean
+ * @sig String -> String -> Boolean
+ * @param {*} prefix
+ * @param {*} list
+ * @return {Boolean}
+ * @see R.endsWith
+ * @example
+ *
+ *      R.startsWith('a', 'abc')                //=> true
+ *      R.startsWith('b', 'abc')                //=> false
+ *      R.startsWith(['a'], ['a', 'b', 'c'])    //=> true
+ *      R.startsWith(['b'], ['a', 'b', 'c'])    //=> false
+ */
+var startsWith = _curry2(function(prefix, list) {
+  return equals(take(prefix.length, list), prefix);
+});
+
+/**
+ * Subtracts its second argument from its first argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The first value.
+ * @param {Number} b The second value.
+ * @return {Number} The result of `a - b`.
+ * @see R.add
+ * @example
+ *
+ *      R.subtract(10, 8); //=> 2
+ *
+ *      const minus5 = R.subtract(R.__, 5);
+ *      minus5(17); //=> 12
+ *
+ *      const complementaryAngle = R.subtract(90);
+ *      complementaryAngle(30); //=> 60
+ *      complementaryAngle(72); //=> 18
+ */
+var subtract = _curry2(function subtract(a, b) {
+  return Number(a) - Number(b);
+});
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements contained in the first or
+ * second list, but not both.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` or `list2`, but not both.
+ * @see R.symmetricDifferenceWith, R.difference, R.differenceWith
+ * @example
+ *
+ *      R.symmetricDifference([1,2,3,4], [7,6,5,4,3]); //=> [1,2,7,6,5]
+ *      R.symmetricDifference([7,6,5,4,3], [1,2,3,4]); //=> [7,6,5,1,2]
+ */
+var symmetricDifference = _curry2(function symmetricDifference(list1, list2) {
+  return concat(difference(list1, list2), difference(list2, list1));
+});
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements contained in the first or
+ * second list, but not both. Duplication is determined according to the value
+ * returned by applying the supplied predicate to two list elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Relation
+ * @sig ((a, a) -> Boolean) -> [a] -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` or `list2`, but not both.
+ * @see R.symmetricDifference, R.difference, R.differenceWith
+ * @example
+ *
+ *      const eqA = R.eqBy(R.prop('a'));
+ *      const l1 = [{a: 1}, {a: 2}, {a: 3}, {a: 4}];
+ *      const l2 = [{a: 3}, {a: 4}, {a: 5}, {a: 6}];
+ *      R.symmetricDifferenceWith(eqA, l1, l2); //=> [{a: 1}, {a: 2}, {a: 5}, {a: 6}]
+ */
+var symmetricDifferenceWith = _curry3(function symmetricDifferenceWith(pred, list1, list2) {
+  return concat(differenceWith(pred, list1, list2), differenceWith(pred, list2, list1));
+});
+
+/**
+ * Returns a new list containing the last `n` elements of a given list, passing
+ * each value to the supplied predicate function, and terminating when the
+ * predicate function returns `false`. Excludes the element that caused the
+ * predicate function to fail. The predicate function is passed one argument:
+ * *(value)*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} fn The function called per iteration.
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array.
+ * @see R.dropLastWhile, R.addIndex
+ * @example
+ *
+ *      const isNotOne = x => x !== 1;
+ *
+ *      R.takeLastWhile(isNotOne, [1, 2, 3, 4]); //=> [2, 3, 4]
+ *
+ *      R.takeLastWhile(x => x !== 'R' , 'Ramda'); //=> 'amda'
+ */
+var takeLastWhile = _curry2(function takeLastWhile(fn, xs) {
+  var idx = xs.length - 1;
+  while (idx >= 0 && fn(xs[idx])) {
+    idx -= 1;
+  }
+  return slice(idx + 1, Infinity, xs);
+});
+
+function XTakeWhile(f, xf) {
+  this.xf = xf;
+  this.f = f;
+}
+XTakeWhile.prototype['@@transducer/init'] = _xfBase.init;
+XTakeWhile.prototype['@@transducer/result'] = _xfBase.result;
+XTakeWhile.prototype['@@transducer/step'] = function(result, input) {
+  return this.f(input) ? this.xf['@@transducer/step'](result, input) : _reduced(result);
+};
+
+var _xtakeWhile = _curry2(function _xtakeWhile(f, xf) { return new XTakeWhile(f, xf); });
+
+/**
+ * Returns a new list containing the first `n` elements of a given list,
+ * passing each value to the supplied predicate function, and terminating when
+ * the predicate function returns `false`. Excludes the element that caused the
+ * predicate function to fail. The predicate function is passed one argument:
+ * *(value)*.
+ *
+ * Dispatches to the `takeWhile` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} fn The function called per iteration.
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array.
+ * @see R.dropWhile, R.transduce, R.addIndex
+ * @example
+ *
+ *      const isNotFour = x => x !== 4;
+ *
+ *      R.takeWhile(isNotFour, [1, 2, 3, 4, 3, 2, 1]); //=> [1, 2, 3]
+ *
+ *      R.takeWhile(x => x !== 'd' , 'Ramda'); //=> 'Ram'
+ */
+var takeWhile = _curry2(_dispatchable(['takeWhile'], _xtakeWhile, function takeWhile(fn, xs) {
+  var idx = 0;
+  var len = xs.length;
+  while (idx < len && fn(xs[idx])) {
+    idx += 1;
+  }
+  return slice(0, idx, xs);
+}));
+
+function XTap(f, xf) {
+  this.xf = xf;
+  this.f = f;
+}
+XTap.prototype['@@transducer/init'] = _xfBase.init;
+XTap.prototype['@@transducer/result'] = _xfBase.result;
+XTap.prototype['@@transducer/step'] = function(result, input) {
+  this.f(input);
+  return this.xf['@@transducer/step'](result, input);
+};
+
+var _xtap = _curry2(function _xtap(f, xf) { return new XTap(f, xf); });
+
+/**
+ * Runs the given function with the supplied object, then returns the object.
+ *
+ * Acts as a transducer if a transformer is given as second parameter.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (a -> *) -> a -> a
+ * @param {Function} fn The function to call with `x`. The return value of `fn` will be thrown away.
+ * @param {*} x
+ * @return {*} `x`.
+ * @example
+ *
+ *      const sayX = x => console.log('x is ' + x);
+ *      R.tap(sayX, 100); //=> 100
+ *      // logs 'x is 100'
+ * @symb R.tap(f, a) = a
+ */
+var tap = _curry2(_dispatchable([], _xtap, function tap(fn, x) {
+  fn(x);
+  return x;
+}));
+
+function _isRegExp(x) {
+  return Object.prototype.toString.call(x) === '[object RegExp]';
+}
+
+/**
+ * Determines whether a given string matches a given regular expression.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category String
+ * @sig RegExp -> String -> Boolean
+ * @param {RegExp} pattern
+ * @param {String} str
+ * @return {Boolean}
+ * @see R.match
+ * @example
+ *
+ *      R.test(/^x/, 'xyz'); //=> true
+ *      R.test(/^y/, 'xyz'); //=> false
+ */
+var test = _curry2(function test(pattern, str) {
+  if (!_isRegExp(pattern)) {
+    throw new TypeError('‘test’ requires a value of type RegExp as its first argument; received ' + toString$1(pattern));
+  }
+  return _cloneRegExp(pattern).test(str);
+});
+
+/**
+ * Returns the result of applying the onSuccess function to the value inside
+ * a successfully resolved promise. This is useful for working with promises
+ * inside function compositions.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig (a -> b) -> (Promise e a) -> (Promise e b)
+ * @sig (a -> (Promise e b)) -> (Promise e a) -> (Promise e b)
+ * @param {Function} onSuccess The function to apply. Can return a value or a promise of a value.
+ * @param {Promise} p
+ * @return {Promise} The result of calling `p.then(onSuccess)`
+ * @see R.otherwise
+ * @example
+ *
+ *      var makeQuery = (email) => ({ query: { email }});
+ *
+ *      //getMemberName :: String -> Promise ({firstName, lastName})
+ *      var getMemberName = R.pipe(
+ *        makeQuery,
+ *        fetchMember,
+ *        R.then(R.pick(['firstName', 'lastName']))
+ *      );
+ */
+var then = _curry2(function then(f, p) {
+  _assertPromise('then', p);
+
+  return p.then(f);
+});
+
+/**
+ * The lower case version of a string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category String
+ * @sig String -> String
+ * @param {String} str The string to lower case.
+ * @return {String} The lower case version of `str`.
+ * @see R.toUpper
+ * @example
+ *
+ *      R.toLower('XYZ'); //=> 'xyz'
+ */
+var toLower = invoker(0, 'toLowerCase');
+
+/**
+ * Converts an object into an array of key, value arrays. Only the object's
+ * own properties are used.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.0
+ * @category Object
+ * @sig {String: *} -> [[String,*]]
+ * @param {Object} obj The object to extract from
+ * @return {Array} An array of key, value arrays from the object's own properties.
+ * @see R.fromPairs
+ * @example
+ *
+ *      R.toPairs({a: 1, b: 2, c: 3}); //=> [['a', 1], ['b', 2], ['c', 3]]
+ */
+var toPairs = _curry1(function toPairs(obj) {
+  var pairs = [];
+  for (var prop in obj) {
+    if (_has(prop, obj)) {
+      pairs[pairs.length] = [prop, obj[prop]];
+    }
+  }
+  return pairs;
+});
+
+/**
+ * Converts an object into an array of key, value arrays. The object's own
+ * properties and prototype properties are used. Note that the order of the
+ * output array is not guaranteed to be consistent across different JS
+ * platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.0
+ * @category Object
+ * @sig {String: *} -> [[String,*]]
+ * @param {Object} obj The object to extract from
+ * @return {Array} An array of key, value arrays from the object's own
+ *         and prototype properties.
+ * @example
+ *
+ *      const F = function() { this.x = 'X'; };
+ *      F.prototype.y = 'Y';
+ *      const f = new F();
+ *      R.toPairsIn(f); //=> [['x','X'], ['y','Y']]
+ */
+var toPairsIn = _curry1(function toPairsIn(obj) {
+  var pairs = [];
+  for (var prop in obj) {
+    pairs[pairs.length] = [prop, obj[prop]];
+  }
+  return pairs;
+});
+
+/**
+ * The upper case version of a string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category String
+ * @sig String -> String
+ * @param {String} str The string to upper case.
+ * @return {String} The upper case version of `str`.
+ * @see R.toLower
+ * @example
+ *
+ *      R.toUpper('abc'); //=> 'ABC'
+ */
+var toUpper = invoker(0, 'toUpperCase');
+
+/**
+ * Initializes a transducer using supplied iterator function. Returns a single
+ * item by iterating through the list, successively calling the transformed
+ * iterator function and passing it an accumulator value and the current value
+ * from the array, and then passing the result to the next call.
+ *
+ * The iterator function receives two values: *(acc, value)*. It will be
+ * wrapped as a transformer to initialize the transducer. A transformer can be
+ * passed directly in place of an iterator function. In both cases, iteration
+ * may be stopped early with the [`R.reduced`](#reduced) function.
+ *
+ * A transducer is a function that accepts a transformer and returns a
+ * transformer and can be composed directly.
+ *
+ * A transformer is an an object that provides a 2-arity reducing iterator
+ * function, step, 0-arity initial value function, init, and 1-arity result
+ * extraction function, result. The step function is used as the iterator
+ * function in reduce. The result function is used to convert the final
+ * accumulator into the return type and in most cases is
+ * [`R.identity`](#identity). The init function can be used to provide an
+ * initial accumulator, but is ignored by transduce.
+ *
+ * The iteration is performed with [`R.reduce`](#reduce) after initializing the transducer.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig (c -> c) -> ((a, b) -> a) -> a -> [b] -> a
+ * @param {Function} xf The transducer function. Receives a transformer and returns a transformer.
+ * @param {Function} fn The iterator function. Receives two values, the accumulator and the
+ *        current element from the array. Wrapped as transformer, if necessary, and used to
+ *        initialize the transducer
+ * @param {*} acc The initial accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduce, R.reduced, R.into
+ * @example
+ *
+ *      const numbers = [1, 2, 3, 4];
+ *      const transducer = R.compose(R.map(R.add(1)), R.take(2));
+ *      R.transduce(transducer, R.flip(R.append), [], numbers); //=> [2, 3]
+ *
+ *      const isOdd = (x) => x % 2 === 1;
+ *      const firstOddTransducer = R.compose(R.filter(isOdd), R.take(1));
+ *      R.transduce(firstOddTransducer, R.flip(R.append), [], R.range(0, 100)); //=> [1]
+ */
+var transduce = curryN(4, function transduce(xf, fn, acc, list) {
+  return _reduce(xf(typeof fn === 'function' ? _xwrap(fn) : fn), acc, list);
+});
+
+/**
+ * Transposes the rows and columns of a 2D list.
+ * When passed a list of `n` lists of length `x`,
+ * returns a list of `x` lists of length `n`.
+ *
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig [[a]] -> [[a]]
+ * @param {Array} list A 2D list
+ * @return {Array} A 2D list
+ * @example
+ *
+ *      R.transpose([[1, 'a'], [2, 'b'], [3, 'c']]) //=> [[1, 2, 3], ['a', 'b', 'c']]
+ *      R.transpose([[1, 2, 3], ['a', 'b', 'c']]) //=> [[1, 'a'], [2, 'b'], [3, 'c']]
+ *
+ *      // If some of the rows are shorter than the following rows, their elements are skipped:
+ *      R.transpose([[10, 11], [20], [], [30, 31, 32]]) //=> [[10, 20, 30], [11, 31], [32]]
+ * @symb R.transpose([[a], [b], [c]]) = [a, b, c]
+ * @symb R.transpose([[a, b], [c, d]]) = [[a, c], [b, d]]
+ * @symb R.transpose([[a, b], [c]]) = [[a, c], [b]]
+ */
+var transpose = _curry1(function transpose(outerlist) {
+  var i = 0;
+  var result = [];
+  while (i < outerlist.length) {
+    var innerlist = outerlist[i];
+    var j = 0;
+    while (j < innerlist.length) {
+      if (typeof result[j] === 'undefined') {
+        result[j] = [];
+      }
+      result[j].push(innerlist[j]);
+      j += 1;
+    }
+    i += 1;
+  }
+  return result;
+});
+
+/**
+ * Maps an [Applicative](https://github.com/fantasyland/fantasy-land#applicative)-returning
+ * function over a [Traversable](https://github.com/fantasyland/fantasy-land#traversable),
+ * then uses [`sequence`](#sequence) to transform the resulting Traversable of Applicative
+ * into an Applicative of Traversable.
+ *
+ * Dispatches to the `traverse` method of the third argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (Applicative f, Traversable t) => (a -> f a) -> (a -> f b) -> t a -> f (t b)
+ * @param {Function} of
+ * @param {Function} f
+ * @param {*} traversable
+ * @return {*}
+ * @see R.sequence
+ * @example
+ *
+ *      // Returns `Maybe.Nothing` if the given divisor is `0`
+ *      const safeDiv = n => d => d === 0 ? Maybe.Nothing() : Maybe.Just(n / d)
+ *
+ *      R.traverse(Maybe.of, safeDiv(10), [2, 4, 5]); //=> Maybe.Just([5, 2.5, 2])
+ *      R.traverse(Maybe.of, safeDiv(10), [2, 0, 5]); //=> Maybe.Nothing
+ */
+var traverse = _curry3(function traverse(of, f, traversable) {
+  return typeof traversable['fantasy-land/traverse'] === 'function' ?
+    traversable['fantasy-land/traverse'](f, of) :
+    sequence(of, map(f, traversable));
+});
+
+var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' +
+         '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' +
+         '\u2029\uFEFF';
+var zeroWidth = '\u200b';
+var hasProtoTrim = (typeof String.prototype.trim === 'function');
+/**
+ * Removes (strips) whitespace from both ends of the string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category String
+ * @sig String -> String
+ * @param {String} str The string to trim.
+ * @return {String} Trimmed version of `str`.
+ * @example
+ *
+ *      R.trim('   xyz  '); //=> 'xyz'
+ *      R.map(R.trim, R.split(',', 'x, y, z')); //=> ['x', 'y', 'z']
+ */
+var trim = !hasProtoTrim || (ws.trim() || !zeroWidth.trim()) ?
+  _curry1(function trim(str) {
+    var beginRx = new RegExp('^[' + ws + '][' + ws + ']*');
+    var endRx = new RegExp('[' + ws + '][' + ws + ']*$');
+    return str.replace(beginRx, '').replace(endRx, '');
+  }) :
+  _curry1(function trim(str) {
+    return str.trim();
+  });
+
+/**
+ * `tryCatch` takes two functions, a `tryer` and a `catcher`. The returned
+ * function evaluates the `tryer`; if it does not throw, it simply returns the
+ * result. If the `tryer` *does* throw, the returned function evaluates the
+ * `catcher` function and returns its result. Note that for effective
+ * composition with this function, both the `tryer` and `catcher` functions
+ * must return the same type of results.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Function
+ * @sig (...x -> a) -> ((e, ...x) -> a) -> (...x -> a)
+ * @param {Function} tryer The function that may throw.
+ * @param {Function} catcher The function that will be evaluated if `tryer` throws.
+ * @return {Function} A new function that will catch exceptions and send then to the catcher.
+ * @example
+ *
+ *      R.tryCatch(R.prop('x'), R.F)({x: true}); //=> true
+ *      R.tryCatch(() => { throw 'foo'}, R.always('catched'))('bar') // => 'catched'
+ *      R.tryCatch(R.times(R.identity), R.always([]))('s') // => []
+ `` */
+var tryCatch = _curry2(function _tryCatch(tryer, catcher) {
+  return _arity(tryer.length, function() {
+    try {
+      return tryer.apply(this, arguments);
+    } catch (e) {
+      return catcher.apply(this, _concat([e], arguments));
+    }
+  });
+});
+
+/**
+ * Takes a function `fn`, which takes a single array argument, and returns a
+ * function which:
+ *
+ *   - takes any number of positional arguments;
+ *   - passes these arguments to `fn` as an array; and
+ *   - returns the result.
+ *
+ * In other words, `R.unapply` derives a variadic function from a function which
+ * takes an array. `R.unapply` is the inverse of [`R.apply`](#apply).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Function
+ * @sig ([*...] -> a) -> (*... -> a)
+ * @param {Function} fn
+ * @return {Function}
+ * @see R.apply
+ * @example
+ *
+ *      R.unapply(JSON.stringify)(1, 2, 3); //=> '[1,2,3]'
+ * @symb R.unapply(f)(a, b) = f([a, b])
+ */
+var unapply = _curry1(function unapply(fn) {
+  return function() {
+    return fn(Array.prototype.slice.call(arguments, 0));
+  };
+});
+
+/**
+ * Wraps a function of any arity (including nullary) in a function that accepts
+ * exactly 1 parameter. Any extraneous parameters will not be passed to the
+ * supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Function
+ * @sig (* -> b) -> (a -> b)
+ * @param {Function} fn The function to wrap.
+ * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
+ *         arity 1.
+ * @see R.binary, R.nAry
+ * @example
+ *
+ *      const takesTwoArgs = function(a, b) {
+ *        return [a, b];
+ *      };
+ *      takesTwoArgs.length; //=> 2
+ *      takesTwoArgs(1, 2); //=> [1, 2]
+ *
+ *      const takesOneArg = R.unary(takesTwoArgs);
+ *      takesOneArg.length; //=> 1
+ *      // Only 1 argument is passed to the wrapped function
+ *      takesOneArg(1, 2); //=> [1, undefined]
+ * @symb R.unary(f)(a, b, c) = f(a)
+ */
+var unary = _curry1(function unary(fn) {
+  return nAry(1, fn);
+});
+
+/**
+ * Returns a function of arity `n` from a (manually) curried function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Function
+ * @sig Number -> (a -> b) -> (a -> c)
+ * @param {Number} length The arity for the returned function.
+ * @param {Function} fn The function to uncurry.
+ * @return {Function} A new function.
+ * @see R.curry
+ * @example
+ *
+ *      const addFour = a => b => c => d => a + b + c + d;
+ *
+ *      const uncurriedAddFour = R.uncurryN(4, addFour);
+ *      uncurriedAddFour(1, 2, 3, 4); //=> 10
+ */
+var uncurryN = _curry2(function uncurryN(depth, fn) {
+  return curryN(depth, function() {
+    var currentDepth = 1;
+    var value = fn;
+    var idx = 0;
+    var endIdx;
+    while (currentDepth <= depth && typeof value === 'function') {
+      endIdx = currentDepth === depth ? arguments.length : idx + value.length;
+      value = value.apply(this, Array.prototype.slice.call(arguments, idx, endIdx));
+      currentDepth += 1;
+      idx = endIdx;
+    }
+    return value;
+  });
+});
+
+/**
+ * Builds a list from a seed value. Accepts an iterator function, which returns
+ * either false to stop iteration or an array of length 2 containing the value
+ * to add to the resulting list and the seed to be used in the next call to the
+ * iterator function.
+ *
+ * The iterator function receives one argument: *(seed)*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig (a -> [b]) -> * -> [b]
+ * @param {Function} fn The iterator function. receives one argument, `seed`, and returns
+ *        either false to quit iteration or an array of length two to proceed. The element
+ *        at index 0 of this array will be added to the resulting array, and the element
+ *        at index 1 will be passed to the next call to `fn`.
+ * @param {*} seed The seed value.
+ * @return {Array} The final list.
+ * @example
+ *
+ *      const f = n => n > 50 ? false : [-n, n + 10];
+ *      R.unfold(f, 10); //=> [-10, -20, -30, -40, -50]
+ * @symb R.unfold(f, x) = [f(x)[0], f(f(x)[1])[0], f(f(f(x)[1])[1])[0], ...]
+ */
+var unfold = _curry2(function unfold(fn, seed) {
+  var pair = fn(seed);
+  var result = [];
+  while (pair && pair.length) {
+    result[result.length] = pair[0];
+    pair = fn(pair[1]);
+  }
+  return result;
+});
+
+/**
+ * Combines two lists into a set (i.e. no duplicates) composed of the elements
+ * of each list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} as The first list.
+ * @param {Array} bs The second list.
+ * @return {Array} The first and second lists concatenated, with
+ *         duplicates removed.
+ * @example
+ *
+ *      R.union([1, 2, 3], [2, 3, 4]); //=> [1, 2, 3, 4]
+ */
+var union = _curry2(compose(uniq, _concat));
+
+/**
+ * Returns a new list containing only one copy of each element in the original
+ * list, based upon the value returned by applying the supplied predicate to
+ * two list elements. Prefers the first item if two items compare equal based
+ * on the predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category List
+ * @sig ((a, a) -> Boolean) -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list The array to consider.
+ * @return {Array} The list of unique items.
+ * @example
+ *
+ *      const strEq = R.eqBy(String);
+ *      R.uniqWith(strEq)([1, '1', 2, 1]); //=> [1, 2]
+ *      R.uniqWith(strEq)([{}, {}]);       //=> [{}]
+ *      R.uniqWith(strEq)([1, '1', 1]);    //=> [1]
+ *      R.uniqWith(strEq)(['1', 1, 1]);    //=> ['1']
+ */
+var uniqWith = _curry2(function uniqWith(pred, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [];
+  var item;
+  while (idx < len) {
+    item = list[idx];
+    if (!_includesWith(pred, item, result)) {
+      result[result.length] = item;
+    }
+    idx += 1;
+  }
+  return result;
+});
+
+/**
+ * Combines two lists into a set (i.e. no duplicates) composed of the elements
+ * of each list. Duplication is determined according to the value returned by
+ * applying the supplied predicate to two list elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig ((a, a) -> Boolean) -> [*] -> [*] -> [*]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The first and second lists concatenated, with
+ *         duplicates removed.
+ * @see R.union
+ * @example
+ *
+ *      const l1 = [{a: 1}, {a: 2}];
+ *      const l2 = [{a: 1}, {a: 4}];
+ *      R.unionWith(R.eqBy(R.prop('a')), l1, l2); //=> [{a: 1}, {a: 2}, {a: 4}]
+ */
+var unionWith = _curry3(function unionWith(pred, list1, list2) {
+  return uniqWith(pred, _concat(list1, list2));
+});
+
+/**
+ * Tests the final argument by passing it to the given predicate function. If
+ * the predicate is not satisfied, the function will return the result of
+ * calling the `whenFalseFn` function with the same argument. If the predicate
+ * is satisfied, the argument is returned as is.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Logic
+ * @sig (a -> Boolean) -> (a -> a) -> a -> a
+ * @param {Function} pred        A predicate function
+ * @param {Function} whenFalseFn A function to invoke when the `pred` evaluates
+ *                               to a falsy value.
+ * @param {*}        x           An object to test with the `pred` function and
+ *                               pass to `whenFalseFn` if necessary.
+ * @return {*} Either `x` or the result of applying `x` to `whenFalseFn`.
+ * @see R.ifElse, R.when, R.cond
+ * @example
+ *
+ *      let safeInc = R.unless(R.isNil, R.inc);
+ *      safeInc(null); //=> null
+ *      safeInc(1); //=> 2
+ */
+var unless = _curry3(function unless(pred, whenFalseFn, x) {
+  return pred(x) ? x : whenFalseFn(x);
+});
+
+/**
+ * Shorthand for `R.chain(R.identity)`, which removes one level of nesting from
+ * any [Chain](https://github.com/fantasyland/fantasy-land#chain).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig Chain c => c (c a) -> c a
+ * @param {*} list
+ * @return {*}
+ * @see R.flatten, R.chain
+ * @example
+ *
+ *      R.unnest([1, [2], [[3]]]); //=> [1, 2, [3]]
+ *      R.unnest([[1, 2], [3, 4], [5, 6]]); //=> [1, 2, 3, 4, 5, 6]
+ */
+var unnest = chain(_identity);
+
+/**
+ * Takes a predicate, a transformation function, and an initial value,
+ * and returns a value of the same type as the initial value.
+ * It does so by applying the transformation until the predicate is satisfied,
+ * at which point it returns the satisfactory value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Logic
+ * @sig (a -> Boolean) -> (a -> a) -> a -> a
+ * @param {Function} pred A predicate function
+ * @param {Function} fn The iterator function
+ * @param {*} init Initial value
+ * @return {*} Final value that satisfies predicate
+ * @example
+ *
+ *      R.until(R.gt(R.__, 100), R.multiply(2))(1) // => 128
+ */
+var until = _curry3(function until(pred, fn, init) {
+  var val = init;
+  while (!pred(val)) {
+    val = fn(val);
+  }
+  return val;
+});
+
+/**
+ * Returns a list of all the properties, including prototype properties, of the
+ * supplied object.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Object
+ * @sig {k: v} -> [v]
+ * @param {Object} obj The object to extract values from
+ * @return {Array} An array of the values of the object's own and prototype properties.
+ * @see R.values, R.keysIn
+ * @example
+ *
+ *      const F = function() { this.x = 'X'; };
+ *      F.prototype.y = 'Y';
+ *      const f = new F();
+ *      R.valuesIn(f); //=> ['X', 'Y']
+ */
+var valuesIn = _curry1(function valuesIn(obj) {
+  var prop;
+  var vs = [];
+  for (prop in obj) {
+    vs[vs.length] = obj[prop];
+  }
+  return vs;
+});
+
+// `Const` is a functor that effectively ignores the function given to `map`.
+var Const = function(x) {
+  return {value: x, 'fantasy-land/map': function() { return this; }};
+};
+
+/**
+ * Returns a "view" of the given data structure, determined by the given lens.
+ * The lens's focus determines which portion of the data structure is visible.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Lens s a -> s -> a
+ * @param {Lens} lens
+ * @param {*} x
+ * @return {*}
+ * @see R.prop, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const xLens = R.lensProp('x');
+ *
+ *      R.view(xLens, {x: 1, y: 2});  //=> 1
+ *      R.view(xLens, {x: 4, y: 2});  //=> 4
+ */
+var view = _curry2(function view(lens, x) {
+  // Using `Const` effectively ignores the setter function of the `lens`,
+  // leaving the value returned by the getter function unmodified.
+  return lens(Const)(x).value;
+});
+
+/**
+ * Tests the final argument by passing it to the given predicate function. If
+ * the predicate is satisfied, the function will return the result of calling
+ * the `whenTrueFn` function with the same argument. If the predicate is not
+ * satisfied, the argument is returned as is.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Logic
+ * @sig (a -> Boolean) -> (a -> a) -> a -> a
+ * @param {Function} pred       A predicate function
+ * @param {Function} whenTrueFn A function to invoke when the `condition`
+ *                              evaluates to a truthy value.
+ * @param {*}        x          An object to test with the `pred` function and
+ *                              pass to `whenTrueFn` if necessary.
+ * @return {*} Either `x` or the result of applying `x` to `whenTrueFn`.
+ * @see R.ifElse, R.unless, R.cond
+ * @example
+ *
+ *      // truncate :: String -> String
+ *      const truncate = R.when(
+ *        R.propSatisfies(R.gt(R.__, 10), 'length'),
+ *        R.pipe(R.take(10), R.append('…'), R.join(''))
+ *      );
+ *      truncate('12345');         //=> '12345'
+ *      truncate('0123456789ABC'); //=> '0123456789…'
+ */
+var when = _curry3(function when(pred, whenTrueFn, x) {
+  return pred(x) ? whenTrueFn(x) : x;
+});
+
+/**
+ * Takes a spec object and a test object; returns true if the test satisfies
+ * the spec. Each of the spec's own properties must be a predicate function.
+ * Each predicate is applied to the value of the corresponding property of the
+ * test object. `where` returns true if all the predicates return true, false
+ * otherwise.
+ *
+ * `where` is well suited to declaratively expressing constraints for other
+ * functions such as [`filter`](#filter) and [`find`](#find).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category Object
+ * @sig {String: (* -> Boolean)} -> {String: *} -> Boolean
+ * @param {Object} spec
+ * @param {Object} testObj
+ * @return {Boolean}
+ * @see R.propSatisfies, R.whereEq
+ * @example
+ *
+ *      // pred :: Object -> Boolean
+ *      const pred = R.where({
+ *        a: R.equals('foo'),
+ *        b: R.complement(R.equals('bar')),
+ *        x: R.gt(R.__, 10),
+ *        y: R.lt(R.__, 20)
+ *      });
+ *
+ *      pred({a: 'foo', b: 'xxx', x: 11, y: 19}); //=> true
+ *      pred({a: 'xxx', b: 'xxx', x: 11, y: 19}); //=> false
+ *      pred({a: 'foo', b: 'bar', x: 11, y: 19}); //=> false
+ *      pred({a: 'foo', b: 'xxx', x: 10, y: 19}); //=> false
+ *      pred({a: 'foo', b: 'xxx', x: 11, y: 20}); //=> false
+ */
+var where = _curry2(function where(spec, testObj) {
+  for (var prop in spec) {
+    if (_has(prop, spec) && !spec[prop](testObj[prop])) {
+      return false;
+    }
+  }
+  return true;
+});
+
+/**
+ * Takes a spec object and a test object; returns true if the test satisfies
+ * the spec, false otherwise. An object satisfies the spec if, for each of the
+ * spec's own properties, accessing that property of the object gives the same
+ * value (in [`R.equals`](#equals) terms) as accessing that property of the
+ * spec.
+ *
+ * `whereEq` is a specialization of [`where`](#where).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Object
+ * @sig {String: *} -> {String: *} -> Boolean
+ * @param {Object} spec
+ * @param {Object} testObj
+ * @return {Boolean}
+ * @see R.propEq, R.where
+ * @example
+ *
+ *      // pred :: Object -> Boolean
+ *      const pred = R.whereEq({a: 1, b: 2});
+ *
+ *      pred({a: 1});              //=> false
+ *      pred({a: 1, b: 2});        //=> true
+ *      pred({a: 1, b: 2, c: 3});  //=> true
+ *      pred({a: 1, b: 1});        //=> false
+ */
+var whereEq = _curry2(function whereEq(spec, testObj) {
+  return where(map(equals, spec), testObj);
+});
+
+/**
+ * Returns a new list without values in the first argument.
+ * [`R.equals`](#equals) is used to determine equality.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig [a] -> [a] -> [a]
+ * @param {Array} list1 The values to be removed from `list2`.
+ * @param {Array} list2 The array to remove values from.
+ * @return {Array} The new array without values in `list1`.
+ * @see R.transduce, R.difference, R.remove
+ * @example
+ *
+ *      R.without([1, 2], [1, 2, 1, 3, 4]); //=> [3, 4]
+ */
+var without = _curry2(function(xs, list) {
+  return reject(flip(_includes)(xs), list);
+});
+
+/**
+ * Creates a new list out of the two supplied by creating each possible pair
+ * from the lists.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [b] -> [[a,b]]
+ * @param {Array} as The first list.
+ * @param {Array} bs The second list.
+ * @return {Array} The list made by combining each possible pair from
+ *         `as` and `bs` into pairs (`[a, b]`).
+ * @example
+ *
+ *      R.xprod([1, 2], ['a', 'b']); //=> [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
+ * @symb R.xprod([a, b], [c, d]) = [[a, c], [a, d], [b, c], [b, d]]
+ */
+var xprod = _curry2(function xprod(a, b) { // = xprodWith(prepend); (takes about 3 times as long...)
+  var idx = 0;
+  var ilen = a.length;
+  var j;
+  var jlen = b.length;
+  var result = [];
+  while (idx < ilen) {
+    j = 0;
+    while (j < jlen) {
+      result[result.length] = [a[idx], b[j]];
+      j += 1;
+    }
+    idx += 1;
+  }
+  return result;
+});
+
+/**
+ * Creates a new list out of the two supplied by pairing up equally-positioned
+ * items from both lists. The returned list is truncated to the length of the
+ * shorter of the two input lists.
+ * Note: `zip` is equivalent to `zipWith(function(a, b) { return [a, b] })`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [b] -> [[a,b]]
+ * @param {Array} list1 The first array to consider.
+ * @param {Array} list2 The second array to consider.
+ * @return {Array} The list made by pairing up same-indexed elements of `list1` and `list2`.
+ * @example
+ *
+ *      R.zip([1, 2, 3], ['a', 'b', 'c']); //=> [[1, 'a'], [2, 'b'], [3, 'c']]
+ * @symb R.zip([a, b, c], [d, e, f]) = [[a, d], [b, e], [c, f]]
+ */
+var zip = _curry2(function zip(a, b) {
+  var rv = [];
+  var idx = 0;
+  var len = Math.min(a.length, b.length);
+  while (idx < len) {
+    rv[idx] = [a[idx], b[idx]];
+    idx += 1;
+  }
+  return rv;
+});
+
+/**
+ * Creates a new object out of a list of keys and a list of values.
+ * Key/value pairing is truncated to the length of the shorter of the two lists.
+ * Note: `zipObj` is equivalent to `pipe(zip, fromPairs)`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig [String] -> [*] -> {String: *}
+ * @param {Array} keys The array that will be properties on the output object.
+ * @param {Array} values The list of values on the output object.
+ * @return {Object} The object made by pairing up same-indexed elements of `keys` and `values`.
+ * @example
+ *
+ *      R.zipObj(['a', 'b', 'c'], [1, 2, 3]); //=> {a: 1, b: 2, c: 3}
+ */
+var zipObj = _curry2(function zipObj(keys, values) {
+  var idx = 0;
+  var len = Math.min(keys.length, values.length);
+  var out = {};
+  while (idx < len) {
+    out[keys[idx]] = values[idx];
+    idx += 1;
+  }
+  return out;
+});
+
+/**
+ * Creates a new list out of the two supplied by applying the function to each
+ * equally-positioned pair in the lists. The returned list is truncated to the
+ * length of the shorter of the two input lists.
+ *
+ * @function
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, b) -> c) -> [a] -> [b] -> [c]
+ * @param {Function} fn The function used to combine the two elements into one value.
+ * @param {Array} list1 The first array to consider.
+ * @param {Array} list2 The second array to consider.
+ * @return {Array} The list made by combining same-indexed elements of `list1` and `list2`
+ *         using `fn`.
+ * @example
+ *
+ *      const f = (x, y) => {
+ *        // ...
+ *      };
+ *      R.zipWith(f, [1, 2, 3], ['a', 'b', 'c']);
+ *      //=> [f(1, 'a'), f(2, 'b'), f(3, 'c')]
+ * @symb R.zipWith(fn, [a, b, c], [d, e, f]) = [fn(a, d), fn(b, e), fn(c, f)]
+ */
+var zipWith = _curry3(function zipWith(fn, a, b) {
+  var rv = [];
+  var idx = 0;
+  var len = Math.min(a.length, b.length);
+  while (idx < len) {
+    rv[idx] = fn(a[idx], b[idx]);
+    idx += 1;
+  }
+  return rv;
+});
+
+/**
+ * Creates a thunk out of a function. A thunk delays a calculation until
+ * its result is needed, providing lazy evaluation of arguments.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig ((a, b, ..., j) -> k) -> (a, b, ..., j) -> (() -> k)
+ * @param {Function} fn A function to wrap in a thunk
+ * @return {Function} Expects arguments for `fn` and returns a new function
+ *  that, when called, applies those arguments to `fn`.
+ * @see R.partial, R.partialRight
+ * @example
+ *
+ *      R.thunkify(R.identity)(42)(); //=> 42
+ *      R.thunkify((a, b) => a + b)(25, 17)(); //=> 42
+ */
+var thunkify = _curry1(function thunkify(fn) {
+  return curryN(fn.length, function createThunk() {
+    var fnArgs = arguments;
+    return function invokeThunk() {
+      return fn.apply(this, fnArgs);
+    };
+  });
+});
+
+exports.F = F;
+exports.T = T;
+exports.__ = __;
+exports.add = add;
+exports.addIndex = addIndex;
+exports.adjust = adjust;
+exports.all = all;
+exports.allPass = allPass;
+exports.always = always;
+exports.and = and;
+exports.any = any;
+exports.anyPass = anyPass;
+exports.ap = ap;
+exports.aperture = aperture;
+exports.append = append;
+exports.apply = apply;
+exports.applySpec = applySpec;
+exports.applyTo = applyTo;
+exports.ascend = ascend;
+exports.assoc = assoc;
+exports.assocPath = assocPath;
+exports.binary = binary;
+exports.bind = bind;
+exports.both = both;
+exports.call = call;
+exports.chain = chain;
+exports.clamp = clamp;
+exports.clone = clone;
+exports.comparator = comparator;
+exports.complement = complement;
+exports.compose = compose;
+exports.composeK = composeK;
+exports.composeP = composeP;
+exports.composeWith = composeWith;
+exports.concat = concat;
+exports.cond = cond;
+exports.construct = construct;
+exports.constructN = constructN;
+exports.contains = contains$1;
+exports.converge = converge;
+exports.countBy = countBy;
+exports.curry = curry;
+exports.curryN = curryN;
+exports.dec = dec;
+exports.defaultTo = defaultTo;
+exports.descend = descend;
+exports.difference = difference;
+exports.differenceWith = differenceWith;
+exports.dissoc = dissoc;
+exports.dissocPath = dissocPath;
+exports.divide = divide;
+exports.drop = drop;
+exports.dropLast = dropLast;
+exports.dropLastWhile = dropLastWhile;
+exports.dropRepeats = dropRepeats;
+exports.dropRepeatsWith = dropRepeatsWith;
+exports.dropWhile = dropWhile;
+exports.either = either;
+exports.empty = empty;
+exports.endsWith = endsWith;
+exports.eqBy = eqBy;
+exports.eqProps = eqProps;
+exports.equals = equals;
+exports.evolve = evolve;
+exports.filter = filter;
+exports.find = find;
+exports.findIndex = findIndex;
+exports.findLast = findLast;
+exports.findLastIndex = findLastIndex;
+exports.flatten = flatten;
+exports.flip = flip;
+exports.forEach = forEach;
+exports.forEachObjIndexed = forEachObjIndexed;
+exports.fromPairs = fromPairs;
+exports.groupBy = groupBy;
+exports.groupWith = groupWith;
+exports.gt = gt;
+exports.gte = gte;
+exports.has = has;
+exports.hasIn = hasIn;
+exports.hasPath = hasPath;
+exports.head = head;
+exports.identical = identical;
+exports.identity = identity;
+exports.ifElse = ifElse;
+exports.inc = inc;
+exports.includes = includes;
+exports.indexBy = indexBy;
+exports.indexOf = indexOf;
+exports.init = init;
+exports.innerJoin = innerJoin;
+exports.insert = insert;
+exports.insertAll = insertAll;
+exports.intersection = intersection;
+exports.intersperse = intersperse;
+exports.into = into;
+exports.invert = invert;
+exports.invertObj = invertObj;
+exports.invoker = invoker;
+exports.is = is;
+exports.isEmpty = isEmpty;
+exports.isNil = isNil;
+exports.join = join;
+exports.juxt = juxt;
+exports.keys = keys;
+exports.keysIn = keysIn;
+exports.last = last;
+exports.lastIndexOf = lastIndexOf;
+exports.length = length;
+exports.lens = lens;
+exports.lensIndex = lensIndex;
+exports.lensPath = lensPath;
+exports.lensProp = lensProp;
+exports.lift = lift;
+exports.liftN = liftN;
+exports.lt = lt;
+exports.lte = lte;
+exports.map = map;
+exports.mapAccum = mapAccum;
+exports.mapAccumRight = mapAccumRight;
+exports.mapObjIndexed = mapObjIndexed;
+exports.match = match;
+exports.mathMod = mathMod;
+exports.max = max;
+exports.maxBy = maxBy;
+exports.mean = mean;
+exports.median = median;
+exports.memoizeWith = memoizeWith;
+exports.merge = merge;
+exports.mergeAll = mergeAll;
+exports.mergeDeepLeft = mergeDeepLeft;
+exports.mergeDeepRight = mergeDeepRight;
+exports.mergeDeepWith = mergeDeepWith;
+exports.mergeDeepWithKey = mergeDeepWithKey;
+exports.mergeLeft = mergeLeft;
+exports.mergeRight = mergeRight;
+exports.mergeWith = mergeWith;
+exports.mergeWithKey = mergeWithKey;
+exports.min = min;
+exports.minBy = minBy;
+exports.modulo = modulo;
+exports.move = move;
+exports.multiply = multiply;
+exports.nAry = nAry;
+exports.negate = negate;
+exports.none = none;
+exports.not = not;
+exports.nth = nth;
+exports.nthArg = nthArg;
+exports.o = o;
+exports.objOf = objOf;
+exports.of = of;
+exports.omit = omit;
+exports.once = once;
+exports.or = or;
+exports.otherwise = otherwise;
+exports.over = over;
+exports.pair = pair;
+exports.partial = partial;
+exports.partialRight = partialRight;
+exports.partition = partition;
+exports.path = path;
+exports.pathEq = pathEq;
+exports.pathOr = pathOr;
+exports.pathSatisfies = pathSatisfies;
+exports.pick = pick;
+exports.pickAll = pickAll;
+exports.pickBy = pickBy;
+exports.pipe = pipe;
+exports.pipeK = pipeK;
+exports.pipeP = pipeP;
+exports.pipeWith = pipeWith;
+exports.pluck = pluck;
+exports.prepend = prepend;
+exports.product = product;
+exports.project = project;
+exports.prop = prop;
+exports.propEq = propEq;
+exports.propIs = propIs;
+exports.propOr = propOr;
+exports.propSatisfies = propSatisfies;
+exports.props = props;
+exports.range = range;
+exports.reduce = reduce;
+exports.reduceBy = reduceBy;
+exports.reduceRight = reduceRight;
+exports.reduceWhile = reduceWhile;
+exports.reduced = reduced;
+exports.reject = reject;
+exports.remove = remove;
+exports.repeat = repeat;
+exports.replace = replace;
+exports.reverse = reverse;
+exports.scan = scan;
+exports.sequence = sequence;
+exports.set = set;
+exports.slice = slice;
+exports.sort = sort;
+exports.sortBy = sortBy;
+exports.sortWith = sortWith;
+exports.split = split;
+exports.splitAt = splitAt;
+exports.splitEvery = splitEvery;
+exports.splitWhen = splitWhen;
+exports.startsWith = startsWith;
+exports.subtract = subtract;
+exports.sum = sum;
+exports.symmetricDifference = symmetricDifference;
+exports.symmetricDifferenceWith = symmetricDifferenceWith;
+exports.tail = tail;
+exports.take = take;
+exports.takeLast = takeLast;
+exports.takeLastWhile = takeLastWhile;
+exports.takeWhile = takeWhile;
+exports.tap = tap;
+exports.test = test;
+exports.then = then;
+exports.times = times;
+exports.toLower = toLower;
+exports.toPairs = toPairs;
+exports.toPairsIn = toPairsIn;
+exports.toString = toString$1;
+exports.toUpper = toUpper;
+exports.transduce = transduce;
+exports.transpose = transpose;
+exports.traverse = traverse;
+exports.trim = trim;
+exports.tryCatch = tryCatch;
+exports.type = type;
+exports.unapply = unapply;
+exports.unary = unary;
+exports.uncurryN = uncurryN;
+exports.unfold = unfold;
+exports.union = union;
+exports.unionWith = unionWith;
+exports.uniq = uniq;
+exports.uniqBy = uniqBy;
+exports.uniqWith = uniqWith;
+exports.unless = unless;
+exports.unnest = unnest;
+exports.until = until;
+exports.update = update;
+exports.useWith = useWith;
+exports.values = values;
+exports.valuesIn = valuesIn;
+exports.view = view;
+exports.when = when;
+exports.where = where;
+exports.whereEq = whereEq;
+exports.without = without;
+exports.xprod = xprod;
+exports.zip = zip;
+exports.zipObj = zipObj;
+exports.zipWith = zipWith;
+exports.thunkify = thunkify;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+})));
diff --git a/server/node_modules/ramda/dist/ramda.min.js b/server/node_modules/ramda/dist/ramda.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..bc38cfa2f57bf7a8de54d91aceedad6382e9017b
--- /dev/null
+++ b/server/node_modules/ramda/dist/ramda.min.js
@@ -0,0 +1 @@
+!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.R={})}(this,function(t){"use strict";function n(t){return null!=t&&"object"==typeof t&&!0===t["@@functional/placeholder"]}function r(t){return function r(e){return 0===arguments.length||n(e)?r:t.apply(this,arguments)}}function e(t){return function e(u,i){switch(arguments.length){case 0:return e;case 1:return n(u)?e:r(function(n){return t(u,n)});default:return n(u)&&n(i)?e:n(u)?r(function(n){return t(n,i)}):n(i)?r(function(n){return t(u,n)}):t(u,i)}}}var u=e(function(t,n){return+t+ +n});function i(t,n){var r,e=(t=t||[]).length,u=(n=n||[]).length,i=[];for(r=0;e>r;)i[i.length]=t[r],r+=1;for(r=0;u>r;)i[i.length]=n[r],r+=1;return i}function o(t,n){switch(t){case 0:return function(){return n.apply(this,arguments)};case 1:return function(t){return n.apply(this,arguments)};case 2:return function(t,r){return n.apply(this,arguments)};case 3:return function(t,r,e){return n.apply(this,arguments)};case 4:return function(t,r,e,u){return n.apply(this,arguments)};case 5:return function(t,r,e,u,i){return n.apply(this,arguments)};case 6:return function(t,r,e,u,i,o){return n.apply(this,arguments)};case 7:return function(t,r,e,u,i,o,c){return n.apply(this,arguments)};case 8:return function(t,r,e,u,i,o,c,a){return n.apply(this,arguments)};case 9:return function(t,r,e,u,i,o,c,a,s){return n.apply(this,arguments)};case 10:return function(t,r,e,u,i,o,c,a,s,f){return n.apply(this,arguments)};default:throw Error("First argument to _arity must be a non-negative integer no greater than ten")}}function c(t,r,e){return function(){for(var u=[],i=0,a=t,s=0;r.length>s||arguments.length>i;){var f;s>=r.length||n(r[s])&&arguments.length>i?(f=arguments[i],i+=1):f=r[s],u[s]=f,n(f)||(a-=1),s+=1}return a>0?o(a,c(t,u,e)):e.apply(this,u)}}var a=e(function(t,n){return 1===t?r(n):o(t,c(t,[],n))}),s=r(function(t){return a(t.length,function(){var n=0,r=arguments[0],e=arguments[arguments.length-1],u=Array.prototype.slice.call(arguments,0);return u[0]=function(){var t=r.apply(this,i(arguments,[n,e]));return n+=1,t},t.apply(this,u)})});function f(t){return function u(i,o,c){switch(arguments.length){case 0:return u;case 1:return n(i)?u:e(function(n,r){return t(i,n,r)});case 2:return n(i)&&n(o)?u:n(i)?e(function(n,r){return t(n,o,r)}):n(o)?e(function(n,r){return t(i,n,r)}):r(function(n){return t(i,o,n)});default:return n(i)&&n(o)&&n(c)?u:n(i)&&n(o)?e(function(n,r){return t(n,r,c)}):n(i)&&n(c)?e(function(n,r){return t(n,o,r)}):n(o)&&n(c)?e(function(n,r){return t(i,n,r)}):n(i)?r(function(n){return t(n,o,c)}):n(o)?r(function(n){return t(i,n,c)}):n(c)?r(function(n){return t(i,o,n)}):t(i,o,c)}}}var l=f(function(t,n,r){if(t>=r.length||-r.length>t)return r;var e=(0>t?r.length:0)+t,u=i(r);return u[e]=n(r[e]),u}),p=Array.isArray||function(t){return null!=t&&t.length>=0&&"[object Array]"===Object.prototype.toString.call(t)};function h(t){return null!=t&&"function"==typeof t["@@transducer/step"]}function y(t,n,r){return function(){if(0===arguments.length)return r();var e=Array.prototype.slice.call(arguments,0),u=e.pop();if(!p(u)){for(var i=0;t.length>i;){if("function"==typeof u[t[i]])return u[t[i]].apply(u,e);i+=1}if(h(u))return n.apply(null,e)(u)}return r.apply(this,arguments)}}function d(t){return t&&t["@@transducer/reduced"]?t:{"@@transducer/value":t,"@@transducer/reduced":!0}}var g={init:function(){return this.xf["@@transducer/init"]()},result:function(t){return this.xf["@@transducer/result"](t)}};function v(t,n){this.xf=n,this.f=t,this.all=!0}v.prototype["@@transducer/init"]=g.init,v.prototype["@@transducer/result"]=function(t){return this.all&&(t=this.xf["@@transducer/step"](t,!0)),this.xf["@@transducer/result"](t)},v.prototype["@@transducer/step"]=function(t,n){return this.f(n)||(this.all=!1,t=d(this.xf["@@transducer/step"](t,!1))),t};var m=e(function(t,n){return new v(t,n)}),b=e(y(["all"],m,function(t,n){for(var r=0;n.length>r;){if(!t(n[r]))return!1;r+=1}return!0})),x=e(function(t,n){return n>t?n:t});function w(t,n){for(var r=0,e=n.length,u=Array(e);e>r;)u[r]=t(n[r]),r+=1;return u}function j(t){return"[object String]"===Object.prototype.toString.call(t)}var A=r(function(t){return!!p(t)||!!t&&("object"==typeof t&&(!j(t)&&(1===t.nodeType?!!t.length:0===t.length||t.length>0&&(t.hasOwnProperty(0)&&t.hasOwnProperty(t.length-1)))))});function O(t){this.f=t}function S(t){return new O(t)}O.prototype["@@transducer/init"]=function(){throw Error("init not implemented on XWrap")},O.prototype["@@transducer/result"]=function(t){return t},O.prototype["@@transducer/step"]=function(t,n){return this.f(t,n)};var E=e(function(t,n){return o(t.length,function(){return t.apply(n,arguments)})});function _(t,n,r){for(var e=r.next();!e.done;){if((n=t["@@transducer/step"](n,e.value))&&n["@@transducer/reduced"]){n=n["@@transducer/value"];break}e=r.next()}return t["@@transducer/result"](n)}function q(t,n,r,e){return t["@@transducer/result"](r[e](E(t["@@transducer/step"],t),n))}var k="undefined"!=typeof Symbol?Symbol.iterator:"@@iterator";function N(t,n,r){if("function"==typeof t&&(t=S(t)),A(r))return function(t,n,r){for(var e=0,u=r.length;u>e;){if((n=t["@@transducer/step"](n,r[e]))&&n["@@transducer/reduced"]){n=n["@@transducer/value"];break}e+=1}return t["@@transducer/result"](n)}(t,n,r);if("function"==typeof r["fantasy-land/reduce"])return q(t,n,r,"fantasy-land/reduce");if(null!=r[k])return _(t,n,r[k]());if("function"==typeof r.next)return _(t,n,r);if("function"==typeof r.reduce)return q(t,n,r,"reduce");throw new TypeError("reduce: list must be array or iterable")}function W(t,n){this.xf=n,this.f=t}W.prototype["@@transducer/init"]=g.init,W.prototype["@@transducer/result"]=g.result,W.prototype["@@transducer/step"]=function(t,n){return this.xf["@@transducer/step"](t,this.f(n))};var I=e(function(t,n){return new W(t,n)});function P(t,n){return Object.prototype.hasOwnProperty.call(n,t)}var T=Object.prototype.toString,C=function(){return"[object Arguments]"===T.call(arguments)?function(t){return"[object Arguments]"===T.call(t)}:function(t){return P("callee",t)}}(),B=!{toString:null}.propertyIsEnumerable("toString"),F=["constructor","valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"],R=function(){return arguments.propertyIsEnumerable("length")}(),U=function(t,n){for(var r=0;t.length>r;){if(t[r]===n)return!0;r+=1}return!1},D=r("function"!=typeof Object.keys||R?function(t){if(Object(t)!==t)return[];var n,r,e=[],u=R&&C(t);for(n in t)!P(n,t)||u&&"length"===n||(e[e.length]=n);if(B)for(r=F.length-1;r>=0;)P(n=F[r],t)&&!U(e,n)&&(e[e.length]=n),r-=1;return e}:function(t){return Object(t)!==t?[]:Object.keys(t)}),z=e(y(["fantasy-land/map","map"],I,function(t,n){switch(Object.prototype.toString.call(n)){case"[object Function]":return a(n.length,function(){return t.call(this,n.apply(this,arguments))});case"[object Object]":return N(function(r,e){return r[e]=t(n[e]),r},{},D(n));default:return w(t,n)}})),M=e(function(t,n){for(var r=n,e=0;t.length>e;){if(null==r)return;r=r[t[e]],e+=1}return r}),L=e(function(t,n){return M([t],n)}),K=e(function(t,n){return z(L(t),n)}),V=f(N),$=r(function(t){return a(V(x,0,K("length",t)),function(){for(var n=0,r=t.length;r>n;){if(!t[n].apply(this,arguments))return!1;n+=1}return!0})}),H=r(function(t){return function(){return t}}),J=e(function(t,n){return t&&n});function X(t,n){this.xf=n,this.f=t,this.any=!1}X.prototype["@@transducer/init"]=g.init,X.prototype["@@transducer/result"]=function(t){return this.any||(t=this.xf["@@transducer/step"](t,!1)),this.xf["@@transducer/result"](t)},X.prototype["@@transducer/step"]=function(t,n){return this.f(n)&&(this.any=!0,t=d(this.xf["@@transducer/step"](t,!0))),t};var Y=e(function(t,n){return new X(t,n)}),Z=e(y(["any"],Y,function(t,n){for(var r=0;n.length>r;){if(t(n[r]))return!0;r+=1}return!1})),G=r(function(t){return a(V(x,0,K("length",t)),function(){for(var n=0,r=t.length;r>n;){if(t[n].apply(this,arguments))return!0;n+=1}return!1})}),Q=e(function(t,n){return"function"==typeof n["fantasy-land/ap"]?n["fantasy-land/ap"](t):"function"==typeof t.ap?t.ap(n):"function"==typeof t?function(r){return t(r)(n(r))}:N(function(t,r){return i(t,z(r,n))},[],t)});function tt(t,n){this.xf=n,this.pos=0,this.full=!1,this.acc=Array(t)}tt.prototype["@@transducer/init"]=g.init,tt.prototype["@@transducer/result"]=function(t){return this.acc=null,this.xf["@@transducer/result"](t)},tt.prototype["@@transducer/step"]=function(t,n){return this.store(n),this.full?this.xf["@@transducer/step"](t,this.getCopy()):t},tt.prototype.store=function(t){this.acc[this.pos]=t,this.pos+=1,this.pos===this.acc.length&&(this.pos=0,this.full=!0)},tt.prototype.getCopy=function(){return i(Array.prototype.slice.call(this.acc,this.pos),Array.prototype.slice.call(this.acc,0,this.pos))};var nt=e(function(t,n){return new tt(t,n)}),rt=e(y([],nt,function(t,n){for(var r=0,e=n.length-(t-1),u=Array(0>e?0:e);e>r;)u[r]=Array.prototype.slice.call(n,r,r+t),r+=1;return u})),et=e(function(t,n){return i(n,[t])}),ut=e(function(t,n){return t.apply(this,n)}),it=r(function(t){for(var n=D(t),r=n.length,e=[],u=0;r>u;)e[u]=t[n[u]],u+=1;return e});function ot(t,n){return D(n).reduce(function(r,e){return r[e]=t(n[e]),r},{})}var ct=r(function t(n){return n=ot(function(n){return"function"==typeof n?n:t(n)},n),a(V(x,0,K("length",it(n))),function(){var t=arguments;return ot(function(n){return ut(n,t)},n)})}),at=e(function(t,n){return n(t)}),st=f(function(t,n,r){var e=t(n),u=t(r);return u>e?-1:e>u?1:0}),ft=f(function(t,n,r){var e={};for(var u in r)e[u]=r[u];return e[t]=n,e}),lt=Number.isInteger||function(t){return t<<0===t},pt=r(function(t){return null==t}),ht=f(function t(n,r,e){if(0===n.length)return r;var u=n[0];if(n.length>1){var i=!pt(e)&&P(u,e)?e[u]:lt(n[1])?[]:{};r=t(Array.prototype.slice.call(n,1),r,i)}if(lt(u)&&p(e)){var o=[].concat(e);return o[u]=r,o}return ft(u,r,e)}),yt=e(function(t,n){switch(t){case 0:return function(){return n.call(this)};case 1:return function(t){return n.call(this,t)};case 2:return function(t,r){return n.call(this,t,r)};case 3:return function(t,r,e){return n.call(this,t,r,e)};case 4:return function(t,r,e,u){return n.call(this,t,r,e,u)};case 5:return function(t,r,e,u,i){return n.call(this,t,r,e,u,i)};case 6:return function(t,r,e,u,i,o){return n.call(this,t,r,e,u,i,o)};case 7:return function(t,r,e,u,i,o,c){return n.call(this,t,r,e,u,i,o,c)};case 8:return function(t,r,e,u,i,o,c,a){return n.call(this,t,r,e,u,i,o,c,a)};case 9:return function(t,r,e,u,i,o,c,a,s){return n.call(this,t,r,e,u,i,o,c,a,s)};case 10:return function(t,r,e,u,i,o,c,a,s,f){return n.call(this,t,r,e,u,i,o,c,a,s,f)};default:throw Error("First argument to nAry must be a non-negative integer no greater than ten")}}),dt=r(function(t){return yt(2,t)});function gt(t){return"[object Function]"===Object.prototype.toString.call(t)}var vt=e(function(t,n){var r=a(t,n);return a(t,function(){return N(Q,z(r,arguments[0]),Array.prototype.slice.call(arguments,1))})}),mt=r(function(t){return vt(t.length,t)}),bt=e(function(t,n){return gt(t)?function(){return t.apply(this,arguments)&&n.apply(this,arguments)}:mt(J)(t,n)}),xt=r(function(t){return a(t.length,t)}),wt=xt(function(t){return t.apply(this,Array.prototype.slice.call(arguments,1))});function jt(t){return function n(r){for(var e,u,i,o=[],c=0,a=r.length;a>c;){if(A(r[c]))for(i=0,u=(e=t?n(r[c]):r[c]).length;u>i;)o[o.length]=e[i],i+=1;else o[o.length]=r[c];c+=1}return o}}var At=function(t){var n=function(t){return{"@@transducer/init":g.init,"@@transducer/result":function(n){return t["@@transducer/result"](n)},"@@transducer/step":function(n,r){var e=t["@@transducer/step"](n,r);return e["@@transducer/reduced"]?{"@@transducer/value":e,"@@transducer/reduced":!0}:e}}}(t);return{"@@transducer/init":g.init,"@@transducer/result":function(t){return n["@@transducer/result"](t)},"@@transducer/step":function(t,r){return A(r)?N(n,t,r):N(n,t,[r])}}},Ot=e(function(t,n){return z(t,At(n))}),St=e(y(["fantasy-land/chain","chain"],Ot,function(t,n){return"function"==typeof n?function(r){return t(n(r))(r)}:jt(!1)(z(t,n))})),Et=f(function(t,n,r){if(t>n)throw Error("min must not be greater than max in clamp(min, max, value)");return t>r?t:r>n?n:r});function _t(t){return RegExp(t.source,(t.global?"g":"")+(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.sticky?"y":"")+(t.unicode?"u":""))}var qt=r(function(t){return null===t?"Null":void 0===t?"Undefined":Object.prototype.toString.call(t).slice(8,-1)});function kt(t,n,r,e){var u=function(u){for(var i=n.length,o=0;i>o;){if(t===n[o])return r[o];o+=1}for(var c in n[o+1]=t,r[o+1]=u,t)u[c]=e?kt(t[c],n,r,!0):t[c];return u};switch(qt(t)){case"Object":return u({});case"Array":return u([]);case"Date":return new Date(t.valueOf());case"RegExp":return _t(t);default:return t}}var Nt=r(function(t){return null!=t&&"function"==typeof t.clone?t.clone():kt(t,[],[],!0)}),Wt=r(function(t){return function(n,r){return t(n,r)?-1:t(r,n)?1:0}}),It=r(function(t){return!t}),Pt=mt(It);function Tt(t,n){return function(){return n.call(this,t.apply(this,arguments))}}function Ct(t,n){return function(){var r=arguments.length;if(0===r)return n();var e=arguments[r-1];return p(e)||"function"!=typeof e[t]?n.apply(this,arguments):e[t].apply(e,Array.prototype.slice.call(arguments,0,r-1))}}var Bt=f(Ct("slice",function(t,n,r){return Array.prototype.slice.call(r,t,n)})),Ft=r(Ct("tail",Bt(1,1/0)));function Rt(){if(0===arguments.length)throw Error("pipe requires at least one argument");return o(arguments[0].length,V(Tt,arguments[0],Ft(arguments)))}var Ut=r(function(t){return j(t)?t.split("").reverse().join(""):Array.prototype.slice.call(t,0).reverse()});function Dt(){if(0===arguments.length)throw Error("compose requires at least one argument");return Rt.apply(this,Ut(arguments))}function zt(){if(0===arguments.length)throw Error("composeK requires at least one argument");var t=Array.prototype.slice.call(arguments),n=t.pop();return Dt(Dt.apply(this,z(St,t)),n)}function Mt(t,n){return function(){var r=this;return t.apply(r,arguments).then(function(t){return n.call(r,t)})}}function Lt(){if(0===arguments.length)throw Error("pipeP requires at least one argument");return o(arguments[0].length,V(Mt,arguments[0],Ft(arguments)))}var Kt=e(function(t,n){var r=0>t?n.length+t:t;return j(n)?n.charAt(r):n[r]}),Vt=Kt(0);function $t(t){return t}var Ht=r($t),Jt=e(function(t,n){if(0>=n.length)return Ht;var r=Vt(n),e=Ft(n);return o(r.length,function(){return N(function(n,r){return t.call(this,r,n)},r.apply(this,arguments),e)})}),Xt=e(function(t,n){return Jt.call(this,t,Ut(n))});function Yt(t){for(var n,r=[];!(n=t.next()).done;)r.push(n.value);return r}function Zt(t,n,r){for(var e=0,u=r.length;u>e;){if(t(n,r[e]))return!0;e+=1}return!1}var Gt="function"==typeof Object.is?Object.is:function(t,n){return t===n?0!==t||1/t==1/n:t!=t&&n!=n};function Qt(t,n,r,e){var u=Yt(t);function i(t,n){return tn(t,n,r.slice(),e.slice())}return!Zt(function(t,n){return!Zt(i,n,t)},Yt(n),u)}function tn(t,n,r,e){if(Gt(t,n))return!0;var u,i=qt(t);if(i!==qt(n))return!1;if(null==t||null==n)return!1;if("function"==typeof t["fantasy-land/equals"]||"function"==typeof n["fantasy-land/equals"])return"function"==typeof t["fantasy-land/equals"]&&t["fantasy-land/equals"](n)&&"function"==typeof n["fantasy-land/equals"]&&n["fantasy-land/equals"](t);if("function"==typeof t.equals||"function"==typeof n.equals)return"function"==typeof t.equals&&t.equals(n)&&"function"==typeof n.equals&&n.equals(t);switch(i){case"Arguments":case"Array":case"Object":if("function"==typeof t.constructor&&"Promise"===(null==(u=(t.constructor+"").match(/^function (\w*)/))?"":u[1]))return t===n;break;case"Boolean":case"Number":case"String":if(typeof t!=typeof n||!Gt(t.valueOf(),n.valueOf()))return!1;break;case"Date":if(!Gt(t.valueOf(),n.valueOf()))return!1;break;case"Error":return t.name===n.name&&t.message===n.message;case"RegExp":if(t.source!==n.source||t.global!==n.global||t.ignoreCase!==n.ignoreCase||t.multiline!==n.multiline||t.sticky!==n.sticky||t.unicode!==n.unicode)return!1}for(var o=r.length-1;o>=0;){if(r[o]===t)return e[o]===n;o-=1}switch(i){case"Map":return t.size===n.size&&Qt(t.entries(),n.entries(),r.concat([t]),e.concat([n]));case"Set":return t.size===n.size&&Qt(t.values(),n.values(),r.concat([t]),e.concat([n]));case"Arguments":case"Array":case"Object":case"Boolean":case"Number":case"String":case"Date":case"Error":case"RegExp":case"Int8Array":case"Uint8Array":case"Uint8ClampedArray":case"Int16Array":case"Uint16Array":case"Int32Array":case"Uint32Array":case"Float32Array":case"Float64Array":case"ArrayBuffer":break;default:return!1}var c=D(t);if(c.length!==D(n).length)return!1;var a=r.concat([t]),s=e.concat([n]);for(o=c.length-1;o>=0;){var f=c[o];if(!P(f,n)||!tn(n[f],t[f],a,s))return!1;o-=1}return!0}var nn=e(function(t,n){return tn(t,n,[],[])});function rn(t,n,r){var e,u;if("function"==typeof t.indexOf)switch(typeof n){case"number":if(0===n){for(e=1/n;t.length>r;){if(0===(u=t[r])&&1/u===e)return r;r+=1}return-1}if(n!=n){for(;t.length>r;){if("number"==typeof(u=t[r])&&u!=u)return r;r+=1}return-1}return t.indexOf(n,r);case"string":case"boolean":case"function":case"undefined":return t.indexOf(n,r);case"object":if(null===n)return t.indexOf(n,r)}for(;t.length>r;){if(nn(t[r],n))return r;r+=1}return-1}function en(t,n){return rn(n,t,0)>=0}function un(t){return'"'+t.replace(/\\/g,"\\\\").replace(/[\b]/g,"\\b").replace(/\f/g,"\\f").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t").replace(/\v/g,"\\v").replace(/\0/g,"\\0").replace(/"/g,'\\"')+'"'}var on=function(t){return(10>t?"0":"")+t},cn="function"==typeof Date.prototype.toISOString?function(t){return t.toISOString()}:function(t){return t.getUTCFullYear()+"-"+on(t.getUTCMonth()+1)+"-"+on(t.getUTCDate())+"T"+on(t.getUTCHours())+":"+on(t.getUTCMinutes())+":"+on(t.getUTCSeconds())+"."+(t.getUTCMilliseconds()/1e3).toFixed(3).slice(2,5)+"Z"};function an(t){return function(){return!t.apply(this,arguments)}}function sn(t,n){for(var r=0,e=n.length,u=[];e>r;)t(n[r])&&(u[u.length]=n[r]),r+=1;return u}function fn(t){return"[object Object]"===Object.prototype.toString.call(t)}function ln(t,n){this.xf=n,this.f=t}ln.prototype["@@transducer/init"]=g.init,ln.prototype["@@transducer/result"]=g.result,ln.prototype["@@transducer/step"]=function(t,n){return this.f(n)?this.xf["@@transducer/step"](t,n):t};var pn=e(function(t,n){return new ln(t,n)}),hn=e(y(["filter"],pn,function(t,n){return fn(n)?N(function(r,e){return t(n[e])&&(r[e]=n[e]),r},{},D(n)):sn(t,n)})),yn=e(function(t,n){return hn(an(t),n)});function dn(t,n){var r=function(r){var e=n.concat([t]);return en(r,e)?"<Circular>":dn(r,e)},e=function(t,n){return w(function(n){return un(n)+": "+r(t[n])},n.slice().sort())};switch(Object.prototype.toString.call(t)){case"[object Arguments]":return"(function() { return arguments; }("+w(r,t).join(", ")+"))";case"[object Array]":return"["+w(r,t).concat(e(t,yn(function(t){return/^\d+$/.test(t)},D(t)))).join(", ")+"]";case"[object Boolean]":return"object"==typeof t?"new Boolean("+r(t.valueOf())+")":""+t;case"[object Date]":return"new Date("+(isNaN(t.valueOf())?r(NaN):un(cn(t)))+")";case"[object Null]":return"null";case"[object Number]":return"object"==typeof t?"new Number("+r(t.valueOf())+")":1/t==-1/0?"-0":t.toString(10);case"[object String]":return"object"==typeof t?"new String("+r(t.valueOf())+")":un(t);case"[object Undefined]":return"undefined";default:if("function"==typeof t.toString){var u=""+t;if("[object Object]"!==u)return u}return"{"+e(t,D(t)).join(", ")+"}"}}var gn=r(function(t){return dn(t,[])}),vn=e(function(t,n){if(p(t)){if(p(n))return t.concat(n);throw new TypeError(gn(n)+" is not an array")}if(j(t)){if(j(n))return t+n;throw new TypeError(gn(n)+" is not a string")}if(null!=t&&gt(t["fantasy-land/concat"]))return t["fantasy-land/concat"](n);if(null!=t&&gt(t.concat))return t.concat(n);throw new TypeError(gn(t)+' does not have a method named "concat" or "fantasy-land/concat"')}),mn=r(function(t){return o(V(x,0,z(function(t){return t[0].length},t)),function(){for(var n=0;t.length>n;){if(t[n][0].apply(this,arguments))return t[n][1].apply(this,arguments);n+=1}})}),bn=e(function(t,n){if(t>10)throw Error("Constructor with greater than ten arguments");return 0===t?function(){return new n}:xt(yt(t,function(t,r,e,u,i,o,c,a,s,f){switch(arguments.length){case 1:return new n(t);case 2:return new n(t,r);case 3:return new n(t,r,e);case 4:return new n(t,r,e,u);case 5:return new n(t,r,e,u,i);case 6:return new n(t,r,e,u,i,o);case 7:return new n(t,r,e,u,i,o,c);case 8:return new n(t,r,e,u,i,o,c,a);case 9:return new n(t,r,e,u,i,o,c,a,s);case 10:return new n(t,r,e,u,i,o,c,a,s,f)}}))}),xn=r(function(t){return bn(t.length,t)}),wn=e(en),jn=e(function(t,n){return a(V(x,0,K("length",n)),function(){var r=arguments,e=this;return t.apply(e,w(function(t){return t.apply(e,r)},n))})});function An(t,n,r,e){this.valueFn=t,this.valueAcc=n,this.keyFn=r,this.xf=e,this.inputs={}}An.prototype["@@transducer/init"]=g.init,An.prototype["@@transducer/result"]=function(t){var n;for(n in this.inputs)if(P(n,this.inputs)&&(t=this.xf["@@transducer/step"](t,this.inputs[n]))["@@transducer/reduced"]){t=t["@@transducer/value"];break}return this.inputs=null,this.xf["@@transducer/result"](t)},An.prototype["@@transducer/step"]=function(t,n){var r=this.keyFn(n);return this.inputs[r]=this.inputs[r]||[r,this.valueAcc],this.inputs[r][1]=this.valueFn(this.inputs[r][1],n),t};var On=c(4,[],function(t,n,r,e){return new An(t,n,r,e)}),Sn=c(4,[],y([],On,function(t,n,r,e){return N(function(e,u){var i=r(u);return e[i]=t(P(i,e)?e[i]:n,u),e},{},e)})),En=Sn(function(t,n){return t+1},0),_n=u(-1),qn=e(function(t,n){return null==n||n!=n?t:n}),kn=f(function(t,n,r){var e=t(n),u=t(r);return e>u?-1:u>e?1:0});function Nn(){this._nativeSet="function"==typeof Set?new Set:null,this._items={}}function Wn(t,n,r){var e,u=typeof t;switch(u){case"string":case"number":return 0===t&&1/t==-1/0?!!r._items["-0"]||(n&&(r._items["-0"]=!0),!1):null!==r._nativeSet?n?(e=r._nativeSet.size,r._nativeSet.add(t),r._nativeSet.size===e):r._nativeSet.has(t):u in r._items?t in r._items[u]||(n&&(r._items[u][t]=!0),!1):(n&&(r._items[u]={},r._items[u][t]=!0),!1);case"boolean":if(u in r._items){var i=t?1:0;return!!r._items[u][i]||(n&&(r._items[u][i]=!0),!1)}return n&&(r._items[u]=t?[!1,!0]:[!0,!1]),!1;case"function":return null!==r._nativeSet?n?(e=r._nativeSet.size,r._nativeSet.add(t),r._nativeSet.size===e):r._nativeSet.has(t):u in r._items?!!en(t,r._items[u])||(n&&r._items[u].push(t),!1):(n&&(r._items[u]=[t]),!1);case"undefined":return!!r._items[u]||(n&&(r._items[u]=!0),!1);case"object":if(null===t)return!!r._items.null||(n&&(r._items.null=!0),!1);default:return(u=Object.prototype.toString.call(t))in r._items?!!en(t,r._items[u])||(n&&r._items[u].push(t),!1):(n&&(r._items[u]=[t]),!1)}}Nn.prototype.add=function(t){return!Wn(t,!0,this)},Nn.prototype.has=function(t){return Wn(t,!1,this)};var In=e(function(t,n){for(var r=[],e=0,u=t.length,i=n.length,o=new Nn,c=0;i>c;c+=1)o.add(n[c]);for(;u>e;)o.add(t[e])&&(r[r.length]=t[e]),e+=1;return r}),Pn=f(function(t,n,r){for(var e=[],u=0,i=n.length;i>u;)Zt(t,n[u],r)||Zt(t,n[u],e)||e.push(n[u]),u+=1;return e}),Tn=e(function(t,n){var r={};for(var e in n)r[e]=n[e];return delete r[t],r}),Cn=f(function(t,n,r){var e=Array.prototype.slice.call(r,0);return e.splice(t,n),e}),Bn=f(function(t,n,r){return l(t,H(n),r)}),Fn=e(function t(n,r){switch(n.length){case 0:return r;case 1:return lt(n[0])&&p(r)?Cn(n[0],1,r):Tn(n[0],r);default:var e=n[0],u=Array.prototype.slice.call(n,1);return null==r[e]?r:lt(e)&&p(r)?Bn(e,t(u,r[e]),r):ft(e,t(u,r[e]),r)}}),Rn=e(function(t,n){return t/n});function Un(t,n){this.xf=n,this.n=t}Un.prototype["@@transducer/init"]=g.init,Un.prototype["@@transducer/result"]=g.result,Un.prototype["@@transducer/step"]=function(t,n){return this.n>0?(this.n-=1,t):this.xf["@@transducer/step"](t,n)};var Dn=e(function(t,n){return new Un(t,n)}),zn=e(y(["drop"],Dn,function(t,n){return Bt(Math.max(0,t),1/0,n)}));function Mn(t,n){this.xf=n,this.n=t,this.i=0}Mn.prototype["@@transducer/init"]=g.init,Mn.prototype["@@transducer/result"]=g.result,Mn.prototype["@@transducer/step"]=function(t,n){this.i+=1;var r=0===this.n?t:this.xf["@@transducer/step"](t,n);return 0>this.n||this.n>this.i?r:d(r)};var Ln=e(function(t,n){return new Mn(t,n)}),Kn=e(y(["take"],Ln,function(t,n){return Bt(0,0>t?1/0:t,n)}));function Vn(t,n){this.xf=n,this.pos=0,this.full=!1,this.acc=Array(t)}Vn.prototype["@@transducer/init"]=g.init,Vn.prototype["@@transducer/result"]=function(t){return this.acc=null,this.xf["@@transducer/result"](t)},Vn.prototype["@@transducer/step"]=function(t,n){return this.full&&(t=this.xf["@@transducer/step"](t,this.acc[this.pos])),this.store(n),t},Vn.prototype.store=function(t){this.acc[this.pos]=t,this.pos+=1,this.pos===this.acc.length&&(this.pos=0,this.full=!0)};var $n=e(function(t,n){return new Vn(t,n)}),Hn=e(y([],$n,function(t,n){return Kn(n.length>t?n.length-t:0,n)}));function Jn(t,n){this.f=t,this.retained=[],this.xf=n}Jn.prototype["@@transducer/init"]=g.init,Jn.prototype["@@transducer/result"]=function(t){return this.retained=null,this.xf["@@transducer/result"](t)},Jn.prototype["@@transducer/step"]=function(t,n){return this.f(n)?this.retain(t,n):this.flush(t,n)},Jn.prototype.flush=function(t,n){return t=N(this.xf["@@transducer/step"],t,this.retained),this.retained=[],this.xf["@@transducer/step"](t,n)},Jn.prototype.retain=function(t,n){return this.retained.push(n),t};var Xn=e(function(t,n){return new Jn(t,n)}),Yn=e(y([],Xn,function(t,n){for(var r=n.length-1;r>=0&&t(n[r]);)r-=1;return Bt(0,r+1,n)}));function Zn(t,n){this.xf=n,this.pred=t,this.lastValue=void 0,this.seenFirstValue=!1}Zn.prototype["@@transducer/init"]=g.init,Zn.prototype["@@transducer/result"]=g.result,Zn.prototype["@@transducer/step"]=function(t,n){var r=!1;return this.seenFirstValue?this.pred(this.lastValue,n)&&(r=!0):this.seenFirstValue=!0,this.lastValue=n,r?t:this.xf["@@transducer/step"](t,n)};var Gn=e(function(t,n){return new Zn(t,n)}),Qn=Kt(-1),tr=e(y([],Gn,function(t,n){var r=[],e=1,u=n.length;if(0!==u)for(r[0]=n[0];u>e;)t(Qn(r),n[e])||(r[r.length]=n[e]),e+=1;return r})),nr=r(y([],Gn(nn),tr(nn)));function rr(t,n){this.xf=n,this.f=t}rr.prototype["@@transducer/init"]=g.init,rr.prototype["@@transducer/result"]=g.result,rr.prototype["@@transducer/step"]=function(t,n){if(this.f){if(this.f(n))return t;this.f=null}return this.xf["@@transducer/step"](t,n)};var er=e(function(t,n){return new rr(t,n)}),ur=e(y(["dropWhile"],er,function(t,n){for(var r=0,e=n.length;e>r&&t(n[r]);)r+=1;return Bt(r,1/0,n)})),ir=e(function(t,n){return t||n}),or=e(function(t,n){return gt(t)?function(){return t.apply(this,arguments)||n.apply(this,arguments)}:mt(ir)(t,n)}),cr=r(function(t){return null!=t&&"function"==typeof t["fantasy-land/empty"]?t["fantasy-land/empty"]():null!=t&&null!=t.constructor&&"function"==typeof t.constructor["fantasy-land/empty"]?t.constructor["fantasy-land/empty"]():null!=t&&"function"==typeof t.empty?t.empty():null!=t&&null!=t.constructor&&"function"==typeof t.constructor.empty?t.constructor.empty():p(t)?[]:j(t)?"":fn(t)?{}:C(t)?function(){return arguments}():void 0}),ar=e(function(t,n){return zn(0>t?0:n.length-t,n)}),sr=e(function(t,n){return nn(ar(t.length,n),t)}),fr=f(function(t,n,r){return nn(t(n),t(r))}),lr=f(function(t,n,r){return nn(n[t],r[t])}),pr=e(function t(n,r){var e,u,i,o=r instanceof Array?[]:{};for(u in r)o[u]="function"===(i=typeof(e=n[u]))?e(r[u]):e&&"object"===i?t(e,r[u]):r[u];return o});function hr(t,n){this.xf=n,this.f=t,this.found=!1}hr.prototype["@@transducer/init"]=g.init,hr.prototype["@@transducer/result"]=function(t){return this.found||(t=this.xf["@@transducer/step"](t,void 0)),this.xf["@@transducer/result"](t)},hr.prototype["@@transducer/step"]=function(t,n){return this.f(n)&&(this.found=!0,t=d(this.xf["@@transducer/step"](t,n))),t};var yr=e(function(t,n){return new hr(t,n)}),dr=e(y(["find"],yr,function(t,n){for(var r=0,e=n.length;e>r;){if(t(n[r]))return n[r];r+=1}}));function gr(t,n){this.xf=n,this.f=t,this.idx=-1,this.found=!1}gr.prototype["@@transducer/init"]=g.init,gr.prototype["@@transducer/result"]=function(t){return this.found||(t=this.xf["@@transducer/step"](t,-1)),this.xf["@@transducer/result"](t)},gr.prototype["@@transducer/step"]=function(t,n){return this.idx+=1,this.f(n)&&(this.found=!0,t=d(this.xf["@@transducer/step"](t,this.idx))),t};var vr=e(function(t,n){return new gr(t,n)}),mr=e(y([],vr,function(t,n){for(var r=0,e=n.length;e>r;){if(t(n[r]))return r;r+=1}return-1}));function br(t,n){this.xf=n,this.f=t}br.prototype["@@transducer/init"]=g.init,br.prototype["@@transducer/result"]=function(t){return this.xf["@@transducer/result"](this.xf["@@transducer/step"](t,this.last))},br.prototype["@@transducer/step"]=function(t,n){return this.f(n)&&(this.last=n),t};var xr=e(function(t,n){return new br(t,n)}),wr=e(y([],xr,function(t,n){for(var r=n.length-1;r>=0;){if(t(n[r]))return n[r];r-=1}}));function jr(t,n){this.xf=n,this.f=t,this.idx=-1,this.lastIdx=-1}jr.prototype["@@transducer/init"]=g.init,jr.prototype["@@transducer/result"]=function(t){return this.xf["@@transducer/result"](this.xf["@@transducer/step"](t,this.lastIdx))},jr.prototype["@@transducer/step"]=function(t,n){return this.idx+=1,this.f(n)&&(this.lastIdx=this.idx),t};var Ar=e(function(t,n){return new jr(t,n)}),Or=e(y([],Ar,function(t,n){for(var r=n.length-1;r>=0;){if(t(n[r]))return r;r-=1}return-1})),Sr=r(jt(!0)),Er=r(function(t){return a(t.length,function(n,r){var e=Array.prototype.slice.call(arguments,0);return e[0]=r,e[1]=n,t.apply(this,e)})}),_r=e(Ct("forEach",function(t,n){for(var r=n.length,e=0;r>e;)t(n[e]),e+=1;return n})),qr=e(function(t,n){for(var r=D(n),e=0;r.length>e;){var u=r[e];t(n[u],u,n),e+=1}return n}),kr=r(function(t){for(var n={},r=0;t.length>r;)n[t[r][0]]=t[r][1],r+=1;return n}),Nr=e(Ct("groupBy",Sn(function(t,n){return null==t&&(t=[]),t.push(n),t},null))),Wr=e(function(t,n){for(var r=[],e=0,u=n.length;u>e;){for(var i=e+1;u>i&&t(n[i-1],n[i]);)i+=1;r.push(n.slice(e,i)),e=i}return r}),Ir=e(function(t,n){return t>n}),Pr=e(function(t,n){return t>=n}),Tr=e(function(t,n){if(0===t.length)return!1;for(var r=n,e=0;t.length>e;){if(!P(t[e],r))return!1;r=r[t[e]],e+=1}return!0}),Cr=e(function(t,n){return Tr([t],n)}),Br=e(function(t,n){return t in n}),Fr=e(Gt),Rr=f(function(t,n,r){return a(Math.max(t.length,n.length,r.length),function(){return t.apply(this,arguments)?n.apply(this,arguments):r.apply(this,arguments)})}),Ur=u(1),Dr=e(en),zr=Sn(function(t,n){return n},null),Mr=e(function(t,n){return"function"!=typeof n.indexOf||p(n)?rn(n,t,0):n.indexOf(t)}),Lr=Bt(0,-1),Kr=f(function(t,n,r){return sn(function(n){return Zt(t,n,r)},n)}),Vr=f(function(t,n,r){t=r.length>t&&t>=0?t:r.length;var e=Array.prototype.slice.call(r,0);return e.splice(t,0,n),e}),$r=f(function(t,n,r){return[].concat(Array.prototype.slice.call(r,0,t=r.length>t&&t>=0?t:r.length),n,Array.prototype.slice.call(r,t))}),Hr=e(function(t,n){for(var r,e,u=new Nn,i=[],o=0;n.length>o;)r=t(e=n[o]),u.add(r)&&i.push(e),o+=1;return i}),Jr=Hr(Ht),Xr=e(function(t,n){var r,e;return t.length>n.length?(r=t,e=n):(r=n,e=t),Jr(sn(Er(en)(r),e))}),Yr=e(Ct("intersperse",function(t,n){for(var r=[],e=0,u=n.length;u>e;)e===u-1?r.push(n[e]):r.push(n[e],t),e+=1;return r}));var Zr="function"==typeof Object.assign?Object.assign:function(t){if(null==t)throw new TypeError("Cannot convert undefined or null to object");for(var n=Object(t),r=1,e=arguments.length;e>r;){var u=arguments[r];if(null!=u)for(var i in u)P(i,u)&&(n[i]=u[i]);r+=1}return n},Gr=e(function(t,n){var r={};return r[t]=n,r}),Qr={"@@transducer/init":Array,"@@transducer/step":function(t,n){return t.push(n),t},"@@transducer/result":$t},te={"@@transducer/init":String,"@@transducer/step":function(t,n){return t+n},"@@transducer/result":$t},ne={"@@transducer/init":Object,"@@transducer/step":function(t,n){return Zr(t,A(n)?Gr(n[0],n[1]):n)},"@@transducer/result":$t};var re=f(function(t,n,r){return h(t)?N(n(t),t["@@transducer/init"](),r):N(n(function(t){if(h(t))return t;if(A(t))return Qr;if("string"==typeof t)return te;if("object"==typeof t)return ne;throw Error("Cannot create transformer for "+t)}(t)),kt(t,[],[],!1),r)}),ee=r(function(t){for(var n=D(t),r=n.length,e=0,u={};r>e;){var i=n[e],o=t[i],c=P(o,u)?u[o]:u[o]=[];c[c.length]=i,e+=1}return u}),ue=r(function(t){for(var n=D(t),r=n.length,e=0,u={};r>e;){var i=n[e];u[t[i]]=i,e+=1}return u}),ie=e(function(t,n){return a(t+1,function(){var r=arguments[t];if(null!=r&&gt(r[n]))return r[n].apply(r,Array.prototype.slice.call(arguments,0,t));throw new TypeError(gn(r)+' does not have a method named "'+n+'"')})}),oe=e(function(t,n){return null!=n&&n.constructor===t||n instanceof t}),ce=r(function(t){return null!=t&&nn(t,cr(t))}),ae=ie(1,"join"),se=r(function(t){return jn(function(){return Array.prototype.slice.call(arguments,0)},t)}),fe=r(function(t){var n,r=[];for(n in t)r[r.length]=n;return r}),le=e(function(t,n){if("function"!=typeof n.lastIndexOf||p(n)){for(var r=n.length-1;r>=0;){if(nn(n[r],t))return r;r-=1}return-1}return n.lastIndexOf(t)});function pe(t){return"[object Number]"===Object.prototype.toString.call(t)}var he=r(function(t){return null!=t&&pe(t.length)?t.length:NaN}),ye=e(function(t,n){return function(r){return function(e){return z(function(t){return n(t,e)},r(t(e)))}}}),de=r(function(t){return ye(Kt(t),Bn(t))}),ge=r(function(t){return ye(M(t),ht(t))}),ve=r(function(t){return ye(L(t),ft(t))}),me=e(function(t,n){return n>t}),be=e(function(t,n){return n>=t}),xe=f(function(t,n,r){for(var e=0,u=r.length,i=[],o=[n];u>e;)o=t(o[0],r[e]),i[e]=o[1],e+=1;return[o[0],i]}),we=f(function(t,n,r){for(var e=r.length-1,u=[],i=[n];e>=0;)i=t(i[0],r[e]),u[e]=i[1],e-=1;return[i[0],u]}),je=e(function(t,n){return N(function(r,e){return r[e]=t(n[e],e,n),r},{},D(n))}),Ae=e(function(t,n){return n.match(t)||[]}),Oe=e(function(t,n){return lt(t)?!lt(n)||1>n?NaN:(t%n+n)%n:NaN}),Se=f(function(t,n,r){return t(r)>t(n)?r:n}),Ee=V(u,0),_e=r(function(t){return Ee(t)/t.length}),qe=r(function(t){var n=t.length;if(0===n)return NaN;var r=2-n%2,e=(n-r)/2;return _e(Array.prototype.slice.call(t,0).sort(function(t,n){return n>t?-1:t>n?1:0}).slice(e,e+r))}),ke=e(function(t,n){var r={};return o(n.length,function(){var e=t.apply(this,arguments);return P(e,r)||(r[e]=n.apply(this,arguments)),r[e]})}),Ne=e(function(t,n){return Zr({},t,n)}),We=r(function(t){return Zr.apply(null,[{}].concat(t))}),Ie=f(function(t,n,r){var e,u={};for(e in n)P(e,n)&&(u[e]=P(e,r)?t(e,n[e],r[e]):n[e]);for(e in r)P(e,r)&&!P(e,u)&&(u[e]=r[e]);return u}),Pe=f(function t(n,r,e){return Ie(function(r,e,u){return fn(e)&&fn(u)?t(n,e,u):n(r,e,u)},r,e)}),Te=e(function(t,n){return Pe(function(t,n,r){return n},t,n)}),Ce=e(function(t,n){return Pe(function(t,n,r){return r},t,n)}),Be=f(function(t,n,r){return Pe(function(n,r,e){return t(r,e)},n,r)}),Fe=e(function(t,n){return Zr({},n,t)}),Re=e(function(t,n){return Zr({},t,n)}),Ue=f(function(t,n,r){return Ie(function(n,r,e){return t(r,e)},n,r)}),De=e(function(t,n){return t>n?n:t}),ze=f(function(t,n,r){return t(r)<t(n)?r:n}),Me=e(function(t,n){return t%n}),Le=f(function(t,n,r){var e=r.length,u=r.slice(),i=0>t?e+t:t,o=0>n?e+n:n,c=u.splice(i,1);return 0>i||i>=r.length||0>o||o>=r.length?r:[].concat(u.slice(0,o)).concat(c).concat(u.slice(o,r.length))}),Ke=e(function(t,n){return t*n}),Ve=r(function(t){return-t}),$e=e(function(t,n){return b(an(t),n)}),He=r(function(t){return a(0>t?1:t+1,function(){return Kt(t,arguments)})}),Je=f(function(t,n,r){return t(n(r))});var Xe=r(function(t){return[t]}),Ye=e(function(t,n){for(var r={},e={},u=0,i=t.length;i>u;)e[t[u]]=1,u+=1;for(var o in n)e.hasOwnProperty(o)||(r[o]=n[o]);return r}),Ze=r(function(t){var n,r=!1;return o(t.length,function(){return r?n:(r=!0,n=t.apply(this,arguments))})});function Ge(t,n){if(null==n||!gt(n.then))throw new TypeError("`"+t+"` expected a Promise, received "+dn(n,[]))}var Qe=e(function(t,n){return Ge("otherwise",n),n.then(null,t)}),tu=function(t){return{value:t,map:function(n){return tu(n(t))}}},nu=f(function(t,n,r){return t(function(t){return tu(n(t))})(r).value}),ru=e(function(t,n){return[t,n]});function eu(t){return e(function(n,r){return o(Math.max(0,n.length-r.length),function(){return n.apply(this,t(r,arguments))})})}var uu=eu(i),iu=eu(Er(i)),ou=se([hn,yn]),cu=f(function(t,n,r){return nn(M(t,r),n)}),au=f(function(t,n,r){return qn(t,M(n,r))}),su=f(function(t,n,r){return n.length>0&&t(M(n,r))}),fu=e(function(t,n){for(var r={},e=0;t.length>e;)t[e]in n&&(r[t[e]]=n[t[e]]),e+=1;return r}),lu=e(function(t,n){for(var r={},e=0,u=t.length;u>e;){var i=t[e];r[i]=n[i],e+=1}return r}),pu=e(function(t,n){var r={};for(var e in n)t(n[e],e,n)&&(r[e]=n[e]);return r});var hu=e(function(t,n){return i([t],n)}),yu=V(Ke,1),du=e(function(t,n){return a(n.length,function(){for(var r=[],e=0;n.length>e;)r.push(n[e].call(this,arguments[e])),e+=1;return t.apply(this,r.concat(Array.prototype.slice.call(arguments,n.length)))})}),gu=du(w,[lu,Ht]),vu=f(function(t,n,r){return nn(n,r[t])}),mu=f(function(t,n,r){return oe(t,r[n])}),bu=f(function(t,n,r){return au(t,[n],r)}),xu=f(function(t,n,r){return t(r[n])}),wu=e(function(t,n){for(var r=t.length,e=[],u=0;r>u;)e[u]=n[t[u]],u+=1;return e}),ju=e(function(t,n){if(!pe(t)||!pe(n))throw new TypeError("Both arguments to range must be numbers");for(var r=[],e=t;n>e;)r.push(e),e+=1;return r}),Au=f(function(t,n,r){for(var e=r.length-1;e>=0;)n=t(r[e],n),e-=1;return n}),Ou=c(4,[],function(t,n,r,e){return N(function(r,e){return t(r,e)?n(r,e):d(r)},r,e)}),Su=r(d),Eu=e(function(t,n){var r,e=+n,u=0;if(0>e||isNaN(e))throw new RangeError("n must be a non-negative number");for(r=Array(e);e>u;)r[u]=t(u),u+=1;return r}),_u=e(function(t,n){return Eu(H(t),n)}),qu=f(function(t,n,r){return r.replace(t,n)}),ku=f(function(t,n,r){for(var e=0,u=r.length,i=[n];u>e;)n=t(n,r[e]),i[e+1]=n,e+=1;return i}),Nu=e(function(t,n){return"function"==typeof n.sequence?n.sequence(t):Au(function(t,n){return Q(z(hu,t),n)},t([]),n)}),Wu=f(function(t,n,r){return nu(t,H(n),r)}),Iu=e(function(t,n){return Array.prototype.slice.call(n,0).sort(t)}),Pu=e(function(t,n){return Array.prototype.slice.call(n,0).sort(function(n,r){var e=t(n),u=t(r);return u>e?-1:e>u?1:0})}),Tu=e(function(t,n){return Array.prototype.slice.call(n,0).sort(function(n,r){for(var e=0,u=0;0===e&&t.length>u;)e=t[u](n,r),u+=1;return e})}),Cu=ie(1,"split"),Bu=e(function(t,n){return[Bt(0,t,n),Bt(t,he(n),n)]}),Fu=e(function(t,n){if(0>=t)throw Error("First argument to splitEvery must be a positive integer");for(var r=[],e=0;n.length>e;)r.push(Bt(e,e+=t,n));return r}),Ru=e(function(t,n){for(var r=0,e=n.length,u=[];e>r&&!t(n[r]);)u.push(n[r]),r+=1;return[u,Array.prototype.slice.call(n,r)]}),Uu=e(function(t,n){return nn(Kn(t.length,n),t)}),Du=e(function(t,n){return+t-+n}),zu=e(function(t,n){return vn(In(t,n),In(n,t))}),Mu=f(function(t,n,r){return vn(Pn(t,n,r),Pn(t,r,n))}),Lu=e(function(t,n){for(var r=n.length-1;r>=0&&t(n[r]);)r-=1;return Bt(r+1,1/0,n)});function Ku(t,n){this.xf=n,this.f=t}Ku.prototype["@@transducer/init"]=g.init,Ku.prototype["@@transducer/result"]=g.result,Ku.prototype["@@transducer/step"]=function(t,n){return this.f(n)?this.xf["@@transducer/step"](t,n):d(t)};var Vu=e(function(t,n){return new Ku(t,n)}),$u=e(y(["takeWhile"],Vu,function(t,n){for(var r=0,e=n.length;e>r&&t(n[r]);)r+=1;return Bt(0,r,n)}));function Hu(t,n){this.xf=n,this.f=t}Hu.prototype["@@transducer/init"]=g.init,Hu.prototype["@@transducer/result"]=g.result,Hu.prototype["@@transducer/step"]=function(t,n){return this.f(n),this.xf["@@transducer/step"](t,n)};var Ju=e(function(t,n){return new Hu(t,n)}),Xu=e(y([],Ju,function(t,n){return t(n),n}));var Yu=e(function(t,n){if("[object RegExp]"!==Object.prototype.toString.call(t))throw new TypeError("‘test’ requires a value of type RegExp as its first argument; received "+gn(t));return _t(t).test(n)}),Zu=e(function(t,n){return Ge("then",n),n.then(t)}),Gu=ie(0,"toLowerCase"),Qu=r(function(t){var n=[];for(var r in t)P(r,t)&&(n[n.length]=[r,t[r]]);return n}),ti=r(function(t){var n=[];for(var r in t)n[n.length]=[r,t[r]];return n}),ni=ie(0,"toUpperCase"),ri=a(4,function(t,n,r,e){return N(t("function"==typeof n?S(n):n),r,e)}),ei=r(function(t){for(var n=0,r=[];t.length>n;){for(var e=t[n],u=0;e.length>u;)void 0===r[u]&&(r[u]=[]),r[u].push(e[u]),u+=1;n+=1}return r}),ui=f(function(t,n,r){return"function"==typeof r["fantasy-land/traverse"]?r["fantasy-land/traverse"](n,t):Nu(t,z(n,r))}),ii="\t\n\v\f\r   ᠎              \u2028\u2029\ufeff",oi=!("function"==typeof String.prototype.trim)||ii.trim()?r(function(t){var n=RegExp("^["+ii+"]["+ii+"]*"),r=RegExp("["+ii+"]["+ii+"]*$");return t.replace(n,"").replace(r,"")}):r(function(t){return t.trim()}),ci=e(function(t,n){return o(t.length,function(){try{return t.apply(this,arguments)}catch(t){return n.apply(this,i([t],arguments))}})}),ai=r(function(t){return function(){return t(Array.prototype.slice.call(arguments,0))}}),si=r(function(t){return yt(1,t)}),fi=e(function(t,n){return a(t,function(){for(var r,e=1,u=n,i=0;t>=e&&"function"==typeof u;)u=u.apply(this,Array.prototype.slice.call(arguments,i,r=e===t?arguments.length:i+u.length)),e+=1,i=r;return u})}),li=e(function(t,n){for(var r=t(n),e=[];r&&r.length;)e[e.length]=r[0],r=t(r[1]);return e}),pi=e(Dt(Jr,i)),hi=e(function(t,n){for(var r,e=0,u=n.length,i=[];u>e;)Zt(t,r=n[e],i)||(i[i.length]=r),e+=1;return i}),yi=f(function(t,n,r){return hi(t,i(n,r))}),di=f(function(t,n,r){return t(r)?r:n(r)}),gi=St($t),vi=f(function(t,n,r){for(var e=r;!t(e);)e=n(e);return e}),mi=r(function(t){var n,r=[];for(n in t)r[r.length]=t[n];return r}),bi=function(t){return{value:t,"fantasy-land/map":function(){return this}}},xi=e(function(t,n){return t(bi)(n).value}),wi=f(function(t,n,r){return t(r)?n(r):r}),ji=e(function(t,n){for(var r in t)if(P(r,t)&&!t[r](n[r]))return!1;return!0}),Ai=e(function(t,n){return ji(z(nn,t),n)}),Oi=e(function(t,n){return yn(Er(en)(t),n)}),Si=e(function(t,n){for(var r,e=0,u=t.length,i=n.length,o=[];u>e;){for(r=0;i>r;)o[o.length]=[t[e],n[r]],r+=1;e+=1}return o}),Ei=e(function(t,n){for(var r=[],e=0,u=Math.min(t.length,n.length);u>e;)r[e]=[t[e],n[e]],e+=1;return r}),_i=e(function(t,n){for(var r=0,e=Math.min(t.length,n.length),u={};e>r;)u[t[r]]=n[r],r+=1;return u}),qi=f(function(t,n,r){for(var e=[],u=0,i=Math.min(n.length,r.length);i>u;)e[u]=t(n[u],r[u]),u+=1;return e}),ki=r(function(t){return a(t.length,function(){var n=arguments;return function(){return t.apply(this,n)}})});t.F=function(){return!1},t.T=function(){return!0},t.__={"@@functional/placeholder":!0},t.add=u,t.addIndex=s,t.adjust=l,t.all=b,t.allPass=$,t.always=H,t.and=J,t.any=Z,t.anyPass=G,t.ap=Q,t.aperture=rt,t.append=et,t.apply=ut,t.applySpec=ct,t.applyTo=at,t.ascend=st,t.assoc=ft,t.assocPath=ht,t.binary=dt,t.bind=E,t.both=bt,t.call=wt,t.chain=St,t.clamp=Et,t.clone=Nt,t.comparator=Wt,t.complement=Pt,t.compose=Dt,t.composeK=zt,t.composeP=function(){if(0===arguments.length)throw Error("composeP requires at least one argument");return Lt.apply(this,Ut(arguments))},t.composeWith=Xt,t.concat=vn,t.cond=mn,t.construct=xn,t.constructN=bn,t.contains=wn,t.converge=jn,t.countBy=En,t.curry=xt,t.curryN=a,t.dec=_n,t.defaultTo=qn,t.descend=kn,t.difference=In,t.differenceWith=Pn,t.dissoc=Tn,t.dissocPath=Fn,t.divide=Rn,t.drop=zn,t.dropLast=Hn,t.dropLastWhile=Yn,t.dropRepeats=nr,t.dropRepeatsWith=tr,t.dropWhile=ur,t.either=or,t.empty=cr,t.endsWith=sr,t.eqBy=fr,t.eqProps=lr,t.equals=nn,t.evolve=pr,t.filter=hn,t.find=dr,t.findIndex=mr,t.findLast=wr,t.findLastIndex=Or,t.flatten=Sr,t.flip=Er,t.forEach=_r,t.forEachObjIndexed=qr,t.fromPairs=kr,t.groupBy=Nr,t.groupWith=Wr,t.gt=Ir,t.gte=Pr,t.has=Cr,t.hasIn=Br,t.hasPath=Tr,t.head=Vt,t.identical=Fr,t.identity=Ht,t.ifElse=Rr,t.inc=Ur,t.includes=Dr,t.indexBy=zr,t.indexOf=Mr,t.init=Lr,t.innerJoin=Kr,t.insert=Vr,t.insertAll=$r,t.intersection=Xr,t.intersperse=Yr,t.into=re,t.invert=ee,t.invertObj=ue,t.invoker=ie,t.is=oe,t.isEmpty=ce,t.isNil=pt,t.join=ae,t.juxt=se,t.keys=D,t.keysIn=fe,t.last=Qn,t.lastIndexOf=le,t.length=he,t.lens=ye,t.lensIndex=de,t.lensPath=ge,t.lensProp=ve,t.lift=mt,t.liftN=vt,t.lt=me,t.lte=be,t.map=z,t.mapAccum=xe,t.mapAccumRight=we,t.mapObjIndexed=je,t.match=Ae,t.mathMod=Oe,t.max=x,t.maxBy=Se,t.mean=_e,t.median=qe,t.memoizeWith=ke,t.merge=Ne,t.mergeAll=We,t.mergeDeepLeft=Te,t.mergeDeepRight=Ce,t.mergeDeepWith=Be,t.mergeDeepWithKey=Pe,t.mergeLeft=Fe,t.mergeRight=Re,t.mergeWith=Ue,t.mergeWithKey=Ie,t.min=De,t.minBy=ze,t.modulo=Me,t.move=Le,t.multiply=Ke,t.nAry=yt,t.negate=Ve,t.none=$e,t.not=It,t.nth=Kt,t.nthArg=He,t.o=Je,t.objOf=Gr,t.of=Xe,t.omit=Ye,t.once=Ze,t.or=ir,t.otherwise=Qe,t.over=nu,t.pair=ru,t.partial=uu,t.partialRight=iu,t.partition=ou,t.path=M,t.pathEq=cu,t.pathOr=au,t.pathSatisfies=su,t.pick=fu,t.pickAll=lu,t.pickBy=pu,t.pipe=Rt,t.pipeK=function(){if(0===arguments.length)throw Error("pipeK requires at least one argument");return zt.apply(this,Ut(arguments))},t.pipeP=Lt,t.pipeWith=Jt,t.pluck=K,t.prepend=hu,t.product=yu,t.project=gu,t.prop=L,t.propEq=vu,t.propIs=mu,t.propOr=bu,t.propSatisfies=xu,t.props=wu,t.range=ju,t.reduce=V,t.reduceBy=Sn,t.reduceRight=Au,t.reduceWhile=Ou,t.reduced=Su,t.reject=yn,t.remove=Cn,t.repeat=_u,t.replace=qu,t.reverse=Ut,t.scan=ku,t.sequence=Nu,t.set=Wu,t.slice=Bt,t.sort=Iu,t.sortBy=Pu,t.sortWith=Tu,t.split=Cu,t.splitAt=Bu,t.splitEvery=Fu,t.splitWhen=Ru,t.startsWith=Uu,t.subtract=Du,t.sum=Ee,t.symmetricDifference=zu,t.symmetricDifferenceWith=Mu,t.tail=Ft,t.take=Kn,t.takeLast=ar,t.takeLastWhile=Lu,t.takeWhile=$u,t.tap=Xu,t.test=Yu,t.then=Zu,t.times=Eu,t.toLower=Gu,t.toPairs=Qu,t.toPairsIn=ti,t.toString=gn,t.toUpper=ni,t.transduce=ri,t.transpose=ei,t.traverse=ui,t.trim=oi,t.tryCatch=ci,t.type=qt,t.unapply=ai,t.unary=si,t.uncurryN=fi,t.unfold=li,t.union=pi,t.unionWith=yi,t.uniq=Jr,t.uniqBy=Hr,t.uniqWith=hi,t.unless=di,t.unnest=gi,t.until=vi,t.update=Bn,t.useWith=du,t.values=it,t.valuesIn=mi,t.view=xi,t.when=wi,t.where=ji,t.whereEq=Ai,t.without=Oi,t.xprod=Si,t.zip=Ei,t.zipObj=_i,t.zipWith=qi,t.thunkify=ki,Object.defineProperty(t,"__esModule",{value:!0})});
diff --git a/server/node_modules/ramda/es/F.js b/server/node_modules/ramda/es/F.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e42b4a62fbddd81f1b51853565a484a438c555d
--- /dev/null
+++ b/server/node_modules/ramda/es/F.js
@@ -0,0 +1,21 @@
+
+
+/**
+ * A function that always returns `false`. Any passed in parameters are ignored.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig * -> Boolean
+ * @param {*}
+ * @return {Boolean}
+ * @see R.T
+ * @example
+ *
+ *      R.F(); //=> false
+ */
+var F = function () {
+  return false;
+};
+export default F;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/T.js b/server/node_modules/ramda/es/T.js
new file mode 100644
index 0000000000000000000000000000000000000000..ae7aa272cb63db6b89b997c0e48842476797e670
--- /dev/null
+++ b/server/node_modules/ramda/es/T.js
@@ -0,0 +1,21 @@
+
+
+/**
+ * A function that always returns `true`. Any passed in parameters are ignored.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig * -> Boolean
+ * @param {*}
+ * @return {Boolean}
+ * @see R.F
+ * @example
+ *
+ *      R.T(); //=> true
+ */
+var T = function () {
+  return true;
+};
+export default T;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/__.js b/server/node_modules/ramda/es/__.js
new file mode 100644
index 0000000000000000000000000000000000000000..e89fbdd71e95b85078bc3a4ca02622be44d629d9
--- /dev/null
+++ b/server/node_modules/ramda/es/__.js
@@ -0,0 +1,28 @@
+/**
+ * A special placeholder value used to specify "gaps" within curried functions,
+ * allowing partial application of any combination of arguments, regardless of
+ * their positions.
+ *
+ * If `g` is a curried ternary function and `_` is `R.__`, the following are
+ * equivalent:
+ *
+ *   - `g(1, 2, 3)`
+ *   - `g(_, 2, 3)(1)`
+ *   - `g(_, _, 3)(1)(2)`
+ *   - `g(_, _, 3)(1, 2)`
+ *   - `g(_, 2, _)(1, 3)`
+ *   - `g(_, 2)(1)(3)`
+ *   - `g(_, 2)(1, 3)`
+ *   - `g(_, 2)(_, 3)(1)`
+ *
+ * @name __
+ * @constant
+ * @memberOf R
+ * @since v0.6.0
+ * @category Function
+ * @example
+ *
+ *      const greet = R.replace('{name}', R.__, 'Hello, {name}!');
+ *      greet('Alice'); //=> 'Hello, Alice!'
+ */
+export default { '@@functional/placeholder': true };
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/add.js b/server/node_modules/ramda/es/add.js
new file mode 100644
index 0000000000000000000000000000000000000000..2dbeffb017d491051bf029bf7b30ffe38838332e
--- /dev/null
+++ b/server/node_modules/ramda/es/add.js
@@ -0,0 +1,23 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Adds two values.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a
+ * @param {Number} b
+ * @return {Number}
+ * @see R.subtract
+ * @example
+ *
+ *      R.add(2, 3);       //=>  5
+ *      R.add(7)(10);      //=> 17
+ */
+var add = /*#__PURE__*/_curry2(function add(a, b) {
+  return Number(a) + Number(b);
+});
+export default add;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/addIndex.js b/server/node_modules/ramda/es/addIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..fab619a088a2ae192ee554e4b7d988502fb25514
--- /dev/null
+++ b/server/node_modules/ramda/es/addIndex.js
@@ -0,0 +1,43 @@
+import _concat from './internal/_concat.js';
+import _curry1 from './internal/_curry1.js';
+import curryN from './curryN.js';
+
+/**
+ * Creates a new list iteration function from an existing one by adding two new
+ * parameters to its callback function: the current index, and the entire list.
+ *
+ * This would turn, for instance, [`R.map`](#map) function into one that
+ * more closely resembles `Array.prototype.map`. Note that this will only work
+ * for functions in which the iteration callback function is the first
+ * parameter, and where the list is the last parameter. (This latter might be
+ * unimportant if the list parameter is not used.)
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category Function
+ * @category List
+ * @sig ((a ... -> b) ... -> [a] -> *) -> ((a ..., Int, [a] -> b) ... -> [a] -> *)
+ * @param {Function} fn A list iteration function that does not pass index or list to its callback
+ * @return {Function} An altered list iteration function that passes (item, index, list) to its callback
+ * @example
+ *
+ *      const mapIndexed = R.addIndex(R.map);
+ *      mapIndexed((val, idx) => idx + '-' + val, ['f', 'o', 'o', 'b', 'a', 'r']);
+ *      //=> ['0-f', '1-o', '2-o', '3-b', '4-a', '5-r']
+ */
+var addIndex = /*#__PURE__*/_curry1(function addIndex(fn) {
+  return curryN(fn.length, function () {
+    var idx = 0;
+    var origFn = arguments[0];
+    var list = arguments[arguments.length - 1];
+    var args = Array.prototype.slice.call(arguments, 0);
+    args[0] = function () {
+      var result = origFn.apply(this, _concat(arguments, [idx, list]));
+      idx += 1;
+      return result;
+    };
+    return fn.apply(this, args);
+  });
+});
+export default addIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/adjust.js b/server/node_modules/ramda/es/adjust.js
new file mode 100644
index 0000000000000000000000000000000000000000..c87093d7264c7e6fac4f805ecbbbb6449c8804c7
--- /dev/null
+++ b/server/node_modules/ramda/es/adjust.js
@@ -0,0 +1,39 @@
+import _concat from './internal/_concat.js';
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Applies a function to the value at the given index of an array, returning a
+ * new copy of the array with the element at the given index replaced with the
+ * result of the function application.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig Number -> (a -> a) -> [a] -> [a]
+ * @param {Number} idx The index.
+ * @param {Function} fn The function to apply.
+ * @param {Array|Arguments} list An array-like object whose value
+ *        at the supplied index will be replaced.
+ * @return {Array} A copy of the supplied array-like object with
+ *         the element at index `idx` replaced with the value
+ *         returned by applying `fn` to the existing element.
+ * @see R.update
+ * @example
+ *
+ *      R.adjust(1, R.toUpper, ['a', 'b', 'c', 'd']);      //=> ['a', 'B', 'c', 'd']
+ *      R.adjust(-1, R.toUpper, ['a', 'b', 'c', 'd']);     //=> ['a', 'b', 'c', 'D']
+ * @symb R.adjust(-1, f, [a, b]) = [a, f(b)]
+ * @symb R.adjust(0, f, [a, b]) = [f(a), b]
+ */
+var adjust = /*#__PURE__*/_curry3(function adjust(idx, fn, list) {
+  if (idx >= list.length || idx < -list.length) {
+    return list;
+  }
+  var start = idx < 0 ? list.length : 0;
+  var _idx = start + idx;
+  var _list = _concat(list);
+  _list[_idx] = fn(list[_idx]);
+  return _list;
+});
+export default adjust;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/all.js b/server/node_modules/ramda/es/all.js
new file mode 100644
index 0000000000000000000000000000000000000000..dfc819631b4e3ddfd6ca3505edd200ceb9cff425
--- /dev/null
+++ b/server/node_modules/ramda/es/all.js
@@ -0,0 +1,39 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xall from './internal/_xall.js';
+
+/**
+ * Returns `true` if all elements of the list match the predicate, `false` if
+ * there are any that don't.
+ *
+ * Dispatches to the `all` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Boolean
+ * @param {Function} fn The predicate function.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if the predicate is satisfied by every element, `false`
+ *         otherwise.
+ * @see R.any, R.none, R.transduce
+ * @example
+ *
+ *      const equals3 = R.equals(3);
+ *      R.all(equals3)([3, 3, 3, 3]); //=> true
+ *      R.all(equals3)([3, 3, 1, 3]); //=> false
+ */
+var all = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['all'], _xall, function all(fn, list) {
+  var idx = 0;
+  while (idx < list.length) {
+    if (!fn(list[idx])) {
+      return false;
+    }
+    idx += 1;
+  }
+  return true;
+}));
+export default all;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/allPass.js b/server/node_modules/ramda/es/allPass.js
new file mode 100644
index 0000000000000000000000000000000000000000..28fbad3cad92b8ee104e59f60f16e9fa0fe8ed21
--- /dev/null
+++ b/server/node_modules/ramda/es/allPass.js
@@ -0,0 +1,45 @@
+import _curry1 from './internal/_curry1.js';
+import curryN from './curryN.js';
+import max from './max.js';
+import pluck from './pluck.js';
+import reduce from './reduce.js';
+
+/**
+ * Takes a list of predicates and returns a predicate that returns true for a
+ * given list of arguments if every one of the provided predicates is satisfied
+ * by those arguments.
+ *
+ * The function returned is a curried function whose arity matches that of the
+ * highest-arity predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Logic
+ * @sig [(*... -> Boolean)] -> (*... -> Boolean)
+ * @param {Array} predicates An array of predicates to check
+ * @return {Function} The combined predicate
+ * @see R.anyPass
+ * @example
+ *
+ *      const isQueen = R.propEq('rank', 'Q');
+ *      const isSpade = R.propEq('suit', '♠︎');
+ *      const isQueenOfSpades = R.allPass([isQueen, isSpade]);
+ *
+ *      isQueenOfSpades({rank: 'Q', suit: '♣︎'}); //=> false
+ *      isQueenOfSpades({rank: 'Q', suit: '♠︎'}); //=> true
+ */
+var allPass = /*#__PURE__*/_curry1(function allPass(preds) {
+  return curryN(reduce(max, 0, pluck('length', preds)), function () {
+    var idx = 0;
+    var len = preds.length;
+    while (idx < len) {
+      if (!preds[idx].apply(this, arguments)) {
+        return false;
+      }
+      idx += 1;
+    }
+    return true;
+  });
+});
+export default allPass;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/always.js b/server/node_modules/ramda/es/always.js
new file mode 100644
index 0000000000000000000000000000000000000000..7b139919d69b3dc6133c295f487bce38e7cf5825
--- /dev/null
+++ b/server/node_modules/ramda/es/always.js
@@ -0,0 +1,27 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Returns a function that always returns the given value. Note that for
+ * non-primitives the value returned is a reference to the original value.
+ *
+ * This function is known as `const`, `constant`, or `K` (for K combinator) in
+ * other languages and libraries.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig a -> (* -> a)
+ * @param {*} val The value to wrap in a function
+ * @return {Function} A Function :: * -> val.
+ * @example
+ *
+ *      const t = R.always('Tee');
+ *      t(); //=> 'Tee'
+ */
+var always = /*#__PURE__*/_curry1(function always(val) {
+  return function () {
+    return val;
+  };
+});
+export default always;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/and.js b/server/node_modules/ramda/es/and.js
new file mode 100644
index 0000000000000000000000000000000000000000..5eef104f9a1ff34686fde987ac899d6e6527ac9a
--- /dev/null
+++ b/server/node_modules/ramda/es/and.js
@@ -0,0 +1,25 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns `true` if both arguments are `true`; `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig a -> b -> a | b
+ * @param {Any} a
+ * @param {Any} b
+ * @return {Any} the first argument if it is falsy, otherwise the second argument.
+ * @see R.both
+ * @example
+ *
+ *      R.and(true, true); //=> true
+ *      R.and(true, false); //=> false
+ *      R.and(false, true); //=> false
+ *      R.and(false, false); //=> false
+ */
+var and = /*#__PURE__*/_curry2(function and(a, b) {
+  return a && b;
+});
+export default and;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/any.js b/server/node_modules/ramda/es/any.js
new file mode 100644
index 0000000000000000000000000000000000000000..e664bb14ad846e64535d0d20c427f26c0c0a3fda
--- /dev/null
+++ b/server/node_modules/ramda/es/any.js
@@ -0,0 +1,40 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xany from './internal/_xany.js';
+
+/**
+ * Returns `true` if at least one of the elements of the list match the predicate,
+ * `false` otherwise.
+ *
+ * Dispatches to the `any` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Boolean
+ * @param {Function} fn The predicate function.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if the predicate is satisfied by at least one element, `false`
+ *         otherwise.
+ * @see R.all, R.none, R.transduce
+ * @example
+ *
+ *      const lessThan0 = R.flip(R.lt)(0);
+ *      const lessThan2 = R.flip(R.lt)(2);
+ *      R.any(lessThan0)([1, 2]); //=> false
+ *      R.any(lessThan2)([1, 2]); //=> true
+ */
+var any = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['any'], _xany, function any(fn, list) {
+  var idx = 0;
+  while (idx < list.length) {
+    if (fn(list[idx])) {
+      return true;
+    }
+    idx += 1;
+  }
+  return false;
+}));
+export default any;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/anyPass.js b/server/node_modules/ramda/es/anyPass.js
new file mode 100644
index 0000000000000000000000000000000000000000..072d1305036706e56f4e22c56136d4fc257f77ff
--- /dev/null
+++ b/server/node_modules/ramda/es/anyPass.js
@@ -0,0 +1,46 @@
+import _curry1 from './internal/_curry1.js';
+import curryN from './curryN.js';
+import max from './max.js';
+import pluck from './pluck.js';
+import reduce from './reduce.js';
+
+/**
+ * Takes a list of predicates and returns a predicate that returns true for a
+ * given list of arguments if at least one of the provided predicates is
+ * satisfied by those arguments.
+ *
+ * The function returned is a curried function whose arity matches that of the
+ * highest-arity predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Logic
+ * @sig [(*... -> Boolean)] -> (*... -> Boolean)
+ * @param {Array} predicates An array of predicates to check
+ * @return {Function} The combined predicate
+ * @see R.allPass
+ * @example
+ *
+ *      const isClub = R.propEq('suit', '♣');
+ *      const isSpade = R.propEq('suit', 'â™ ');
+ *      const isBlackCard = R.anyPass([isClub, isSpade]);
+ *
+ *      isBlackCard({rank: '10', suit: '♣'}); //=> true
+ *      isBlackCard({rank: 'Q', suit: 'â™ '}); //=> true
+ *      isBlackCard({rank: 'Q', suit: '♦'}); //=> false
+ */
+var anyPass = /*#__PURE__*/_curry1(function anyPass(preds) {
+  return curryN(reduce(max, 0, pluck('length', preds)), function () {
+    var idx = 0;
+    var len = preds.length;
+    while (idx < len) {
+      if (preds[idx].apply(this, arguments)) {
+        return true;
+      }
+      idx += 1;
+    }
+    return false;
+  });
+});
+export default anyPass;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/ap.js b/server/node_modules/ramda/es/ap.js
new file mode 100644
index 0000000000000000000000000000000000000000..a26e27a129c083000ef67d23c03fec37f2921ba5
--- /dev/null
+++ b/server/node_modules/ramda/es/ap.js
@@ -0,0 +1,39 @@
+import _concat from './internal/_concat.js';
+import _curry2 from './internal/_curry2.js';
+import _reduce from './internal/_reduce.js';
+import map from './map.js';
+
+/**
+ * ap applies a list of functions to a list of values.
+ *
+ * Dispatches to the `ap` method of the second argument, if present. Also
+ * treats curried functions as applicatives.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Function
+ * @sig [a -> b] -> [a] -> [b]
+ * @sig Apply f => f (a -> b) -> f a -> f b
+ * @sig (r -> a -> b) -> (r -> a) -> (r -> b)
+ * @param {*} applyF
+ * @param {*} applyX
+ * @return {*}
+ * @example
+ *
+ *      R.ap([R.multiply(2), R.add(3)], [1,2,3]); //=> [2, 4, 6, 4, 5, 6]
+ *      R.ap([R.concat('tasty '), R.toUpper], ['pizza', 'salad']); //=> ["tasty pizza", "tasty salad", "PIZZA", "SALAD"]
+ *
+ *      // R.ap can also be used as S combinator
+ *      // when only two functions are passed
+ *      R.ap(R.concat, R.toUpper)('Ramda') //=> 'RamdaRAMDA'
+ * @symb R.ap([f, g], [a, b]) = [f(a), f(b), g(a), g(b)]
+ */
+var ap = /*#__PURE__*/_curry2(function ap(applyF, applyX) {
+  return typeof applyX['fantasy-land/ap'] === 'function' ? applyX['fantasy-land/ap'](applyF) : typeof applyF.ap === 'function' ? applyF.ap(applyX) : typeof applyF === 'function' ? function (x) {
+    return applyF(x)(applyX(x));
+  } : _reduce(function (acc, f) {
+    return _concat(acc, map(f, applyX));
+  }, [], applyF);
+});
+export default ap;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/aperture.js b/server/node_modules/ramda/es/aperture.js
new file mode 100644
index 0000000000000000000000000000000000000000..55b10160c46362c06f70bf7e2bc169eecfd1651f
--- /dev/null
+++ b/server/node_modules/ramda/es/aperture.js
@@ -0,0 +1,28 @@
+import _aperture from './internal/_aperture.js';
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xaperture from './internal/_xaperture.js';
+
+/**
+ * Returns a new list, composed of n-tuples of consecutive elements. If `n` is
+ * greater than the length of the list, an empty list is returned.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig Number -> [a] -> [[a]]
+ * @param {Number} n The size of the tuples to create
+ * @param {Array} list The list to split into `n`-length tuples
+ * @return {Array} The resulting list of `n`-length tuples
+ * @see R.transduce
+ * @example
+ *
+ *      R.aperture(2, [1, 2, 3, 4, 5]); //=> [[1, 2], [2, 3], [3, 4], [4, 5]]
+ *      R.aperture(3, [1, 2, 3, 4, 5]); //=> [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
+ *      R.aperture(7, [1, 2, 3, 4, 5]); //=> []
+ */
+var aperture = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xaperture, _aperture));
+export default aperture;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/append.js b/server/node_modules/ramda/es/append.js
new file mode 100644
index 0000000000000000000000000000000000000000..8ce4e88c90ffc83cc1610f820ae76e23e9fe2f94
--- /dev/null
+++ b/server/node_modules/ramda/es/append.js
@@ -0,0 +1,27 @@
+import _concat from './internal/_concat.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns a new list containing the contents of the given list, followed by
+ * the given element.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> [a]
+ * @param {*} el The element to add to the end of the new list.
+ * @param {Array} list The list of elements to add a new item to.
+ *        list.
+ * @return {Array} A new list containing the elements of the old list followed by `el`.
+ * @see R.prepend
+ * @example
+ *
+ *      R.append('tests', ['write', 'more']); //=> ['write', 'more', 'tests']
+ *      R.append('tests', []); //=> ['tests']
+ *      R.append(['tests'], ['write', 'more']); //=> ['write', 'more', ['tests']]
+ */
+var append = /*#__PURE__*/_curry2(function append(el, list) {
+  return _concat(list, [el]);
+});
+export default append;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/apply.js b/server/node_modules/ramda/es/apply.js
new file mode 100644
index 0000000000000000000000000000000000000000..997e90131bbd23799ca570ac92f457d6107f6803
--- /dev/null
+++ b/server/node_modules/ramda/es/apply.js
@@ -0,0 +1,26 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Applies function `fn` to the argument list `args`. This is useful for
+ * creating a fixed-arity function from a variadic function. `fn` should be a
+ * bound function if context is significant.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Function
+ * @sig (*... -> a) -> [*] -> a
+ * @param {Function} fn The function which will be called with `args`
+ * @param {Array} args The arguments to call `fn` with
+ * @return {*} result The result, equivalent to `fn(...args)`
+ * @see R.call, R.unapply
+ * @example
+ *
+ *      const nums = [1, 2, 3, -99, 42, 6, 7];
+ *      R.apply(Math.max, nums); //=> 42
+ * @symb R.apply(f, [a, b, c]) = f(a, b, c)
+ */
+var apply = /*#__PURE__*/_curry2(function apply(fn, args) {
+  return fn.apply(this, args);
+});
+export default apply;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/applySpec.js b/server/node_modules/ramda/es/applySpec.js
new file mode 100644
index 0000000000000000000000000000000000000000..a0a9abede21021223745bf1243326b74c606a6eb
--- /dev/null
+++ b/server/node_modules/ramda/es/applySpec.js
@@ -0,0 +1,56 @@
+import _curry1 from './internal/_curry1.js';
+import apply from './apply.js';
+import curryN from './curryN.js';
+import max from './max.js';
+import pluck from './pluck.js';
+import reduce from './reduce.js';
+import keys from './keys.js';
+import values from './values.js';
+
+// Use custom mapValues function to avoid issues with specs that include a "map" key and R.map
+// delegating calls to .map
+function mapValues(fn, obj) {
+  return keys(obj).reduce(function (acc, key) {
+    acc[key] = fn(obj[key]);
+    return acc;
+  }, {});
+}
+
+/**
+ * Given a spec object recursively mapping properties to functions, creates a
+ * function producing an object of the same structure, by mapping each property
+ * to the result of calling its associated function with the supplied arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Function
+ * @sig {k: ((a, b, ..., m) -> v)} -> ((a, b, ..., m) -> {k: v})
+ * @param {Object} spec an object recursively mapping properties to functions for
+ *        producing the values for these properties.
+ * @return {Function} A function that returns an object of the same structure
+ * as `spec', with each property set to the value returned by calling its
+ * associated function with the supplied arguments.
+ * @see R.converge, R.juxt
+ * @example
+ *
+ *      const getMetrics = R.applySpec({
+ *        sum: R.add,
+ *        nested: { mul: R.multiply }
+ *      });
+ *      getMetrics(2, 4); // => { sum: 6, nested: { mul: 8 } }
+ * @symb R.applySpec({ x: f, y: { z: g } })(a, b) = { x: f(a, b), y: { z: g(a, b) } }
+ */
+var applySpec = /*#__PURE__*/_curry1(function applySpec(spec) {
+  spec = mapValues(function (v) {
+    return typeof v == 'function' ? v : applySpec(v);
+  }, spec);
+
+  return curryN(reduce(max, 0, pluck('length', values(spec))), function () {
+    var args = arguments;
+    return mapValues(function (f) {
+      return apply(f, args);
+    }, spec);
+  });
+});
+export default applySpec;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/applyTo.js b/server/node_modules/ramda/es/applyTo.js
new file mode 100644
index 0000000000000000000000000000000000000000..727f87a3ff685f4755f444189aa4faea8bb494b9
--- /dev/null
+++ b/server/node_modules/ramda/es/applyTo.js
@@ -0,0 +1,25 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Takes a value and applies a function to it.
+ *
+ * This function is also known as the `thrush` combinator.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.25.0
+ * @category Function
+ * @sig a -> (a -> b) -> b
+ * @param {*} x The value
+ * @param {Function} f The function to apply
+ * @return {*} The result of applying `f` to `x`
+ * @example
+ *
+ *      const t42 = R.applyTo(42);
+ *      t42(R.identity); //=> 42
+ *      t42(R.add(1)); //=> 43
+ */
+var applyTo = /*#__PURE__*/_curry2(function applyTo(x, f) {
+  return f(x);
+});
+export default applyTo;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/ascend.js b/server/node_modules/ramda/es/ascend.js
new file mode 100644
index 0000000000000000000000000000000000000000..9e28eefb96ee10ce93ee14f5fa21215f0f9871bf
--- /dev/null
+++ b/server/node_modules/ramda/es/ascend.js
@@ -0,0 +1,33 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Makes an ascending comparator function out of a function that returns a value
+ * that can be compared with `<` and `>`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Function
+ * @sig Ord b => (a -> b) -> a -> a -> Number
+ * @param {Function} fn A function of arity one that returns a value that can be compared
+ * @param {*} a The first item to be compared.
+ * @param {*} b The second item to be compared.
+ * @return {Number} `-1` if fn(a) < fn(b), `1` if fn(b) < fn(a), otherwise `0`
+ * @see R.descend
+ * @example
+ *
+ *      const byAge = R.ascend(R.prop('age'));
+ *      const people = [
+ *        { name: 'Emma', age: 70 },
+ *        { name: 'Peter', age: 78 },
+ *        { name: 'Mikhail', age: 62 },
+ *      ];
+ *      const peopleByYoungestFirst = R.sort(byAge, people);
+ *        //=> [{ name: 'Mikhail', age: 62 },{ name: 'Emma', age: 70 }, { name: 'Peter', age: 78 }]
+ */
+var ascend = /*#__PURE__*/_curry3(function ascend(fn, a, b) {
+  var aa = fn(a);
+  var bb = fn(b);
+  return aa < bb ? -1 : aa > bb ? 1 : 0;
+});
+export default ascend;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/assoc.js b/server/node_modules/ramda/es/assoc.js
new file mode 100644
index 0000000000000000000000000000000000000000..3088b04d82d275230aecc73a077faaf9ad72a4eb
--- /dev/null
+++ b/server/node_modules/ramda/es/assoc.js
@@ -0,0 +1,31 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Makes a shallow clone of an object, setting or overriding the specified
+ * property with the given value. Note that this copies and flattens prototype
+ * properties onto the new object as well. All non-primitive properties are
+ * copied by reference.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @sig String -> a -> {k: v} -> {k: v}
+ * @param {String} prop The property name to set
+ * @param {*} val The new value
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object equivalent to the original except for the changed property.
+ * @see R.dissoc, R.pick
+ * @example
+ *
+ *      R.assoc('c', 3, {a: 1, b: 2}); //=> {a: 1, b: 2, c: 3}
+ */
+var assoc = /*#__PURE__*/_curry3(function assoc(prop, val, obj) {
+  var result = {};
+  for (var p in obj) {
+    result[p] = obj[p];
+  }
+  result[prop] = val;
+  return result;
+});
+export default assoc;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/assocPath.js b/server/node_modules/ramda/es/assocPath.js
new file mode 100644
index 0000000000000000000000000000000000000000..84620c302eb0de9e65bc3eb09a702a894cb22847
--- /dev/null
+++ b/server/node_modules/ramda/es/assocPath.js
@@ -0,0 +1,49 @@
+import _curry3 from './internal/_curry3.js';
+import _has from './internal/_has.js';
+import _isArray from './internal/_isArray.js';
+import _isInteger from './internal/_isInteger.js';
+import assoc from './assoc.js';
+import isNil from './isNil.js';
+
+/**
+ * Makes a shallow clone of an object, setting or overriding the nodes required
+ * to create the given path, and placing the specific value at the tail end of
+ * that path. Note that this copies and flattens prototype properties onto the
+ * new object as well. All non-primitive properties are copied by reference.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> a -> {a} -> {a}
+ * @param {Array} path the path to set
+ * @param {*} val The new value
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object equivalent to the original except along the specified path.
+ * @see R.dissocPath
+ * @example
+ *
+ *      R.assocPath(['a', 'b', 'c'], 42, {a: {b: {c: 0}}}); //=> {a: {b: {c: 42}}}
+ *
+ *      // Any missing or non-object keys in path will be overridden
+ *      R.assocPath(['a', 'b', 'c'], 42, {a: 5}); //=> {a: {b: {c: 42}}}
+ */
+var assocPath = /*#__PURE__*/_curry3(function assocPath(path, val, obj) {
+  if (path.length === 0) {
+    return val;
+  }
+  var idx = path[0];
+  if (path.length > 1) {
+    var nextObj = !isNil(obj) && _has(idx, obj) ? obj[idx] : _isInteger(path[1]) ? [] : {};
+    val = assocPath(Array.prototype.slice.call(path, 1), val, nextObj);
+  }
+  if (_isInteger(idx) && _isArray(obj)) {
+    var arr = [].concat(obj);
+    arr[idx] = val;
+    return arr;
+  } else {
+    return assoc(idx, val, obj);
+  }
+});
+export default assocPath;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/binary.js b/server/node_modules/ramda/es/binary.js
new file mode 100644
index 0000000000000000000000000000000000000000..796e44445462514ee6f32f522283e3b0769607f4
--- /dev/null
+++ b/server/node_modules/ramda/es/binary.js
@@ -0,0 +1,35 @@
+import _curry1 from './internal/_curry1.js';
+import nAry from './nAry.js';
+
+/**
+ * Wraps a function of any arity (including nullary) in a function that accepts
+ * exactly 2 parameters. Any extraneous parameters will not be passed to the
+ * supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Function
+ * @sig (* -> c) -> (a, b -> c)
+ * @param {Function} fn The function to wrap.
+ * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
+ *         arity 2.
+ * @see R.nAry, R.unary
+ * @example
+ *
+ *      const takesThreeArgs = function(a, b, c) {
+ *        return [a, b, c];
+ *      };
+ *      takesThreeArgs.length; //=> 3
+ *      takesThreeArgs(1, 2, 3); //=> [1, 2, 3]
+ *
+ *      const takesTwoArgs = R.binary(takesThreeArgs);
+ *      takesTwoArgs.length; //=> 2
+ *      // Only 2 arguments are passed to the wrapped function
+ *      takesTwoArgs(1, 2, 3); //=> [1, 2, undefined]
+ * @symb R.binary(f)(a, b, c) = f(a, b)
+ */
+var binary = /*#__PURE__*/_curry1(function binary(fn) {
+  return nAry(2, fn);
+});
+export default binary;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/bind.js b/server/node_modules/ramda/es/bind.js
new file mode 100644
index 0000000000000000000000000000000000000000..3e4940cceee3128fe4f2a8733cbdcf62438e6c4e
--- /dev/null
+++ b/server/node_modules/ramda/es/bind.js
@@ -0,0 +1,31 @@
+import _arity from './internal/_arity.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Creates a function that is bound to a context.
+ * Note: `R.bind` does not provide the additional argument-binding capabilities of
+ * [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category Function
+ * @category Object
+ * @sig (* -> *) -> {*} -> (* -> *)
+ * @param {Function} fn The function to bind to context
+ * @param {Object} thisObj The context to bind `fn` to
+ * @return {Function} A function that will execute in the context of `thisObj`.
+ * @see R.partial
+ * @example
+ *
+ *      const log = R.bind(console.log, console);
+ *      R.pipe(R.assoc('a', 2), R.tap(log), R.assoc('a', 3))({a: 1}); //=> {a: 3}
+ *      // logs {a: 2}
+ * @symb R.bind(f, o)(a, b) = f.call(o, a, b)
+ */
+var bind = /*#__PURE__*/_curry2(function bind(fn, thisObj) {
+  return _arity(fn.length, function () {
+    return fn.apply(thisObj, arguments);
+  });
+});
+export default bind;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/both.js b/server/node_modules/ramda/es/both.js
new file mode 100644
index 0000000000000000000000000000000000000000..ec570eb11be0dc94b918bb0e0d72fd88fb61b163
--- /dev/null
+++ b/server/node_modules/ramda/es/both.js
@@ -0,0 +1,42 @@
+import _curry2 from './internal/_curry2.js';
+import _isFunction from './internal/_isFunction.js';
+import and from './and.js';
+import lift from './lift.js';
+
+/**
+ * A function which calls the two provided functions and returns the `&&`
+ * of the results.
+ * It returns the result of the first function if it is false-y and the result
+ * of the second function otherwise. Note that this is short-circuited,
+ * meaning that the second function will not be invoked if the first returns a
+ * false-y value.
+ *
+ * In addition to functions, `R.both` also accepts any fantasy-land compatible
+ * applicative functor.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category Logic
+ * @sig (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
+ * @param {Function} f A predicate
+ * @param {Function} g Another predicate
+ * @return {Function} a function that applies its arguments to `f` and `g` and `&&`s their outputs together.
+ * @see R.and
+ * @example
+ *
+ *      const gt10 = R.gt(R.__, 10)
+ *      const lt20 = R.lt(R.__, 20)
+ *      const f = R.both(gt10, lt20);
+ *      f(15); //=> true
+ *      f(30); //=> false
+ *
+ *      R.both(Maybe.Just(false), Maybe.Just(55)); // => Maybe.Just(false)
+ *      R.both([false, false, 'a'], [11]); //=> [false, false, 11]
+ */
+var both = /*#__PURE__*/_curry2(function both(f, g) {
+  return _isFunction(f) ? function _both() {
+    return f.apply(this, arguments) && g.apply(this, arguments);
+  } : lift(and)(f, g);
+});
+export default both;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/call.js b/server/node_modules/ramda/es/call.js
new file mode 100644
index 0000000000000000000000000000000000000000..79901c00cd0ee030fe8937fd7d6cd422b1190886
--- /dev/null
+++ b/server/node_modules/ramda/es/call.js
@@ -0,0 +1,38 @@
+import curry from './curry.js';
+
+/**
+ * Returns the result of calling its first argument with the remaining
+ * arguments. This is occasionally useful as a converging function for
+ * [`R.converge`](#converge): the first branch can produce a function while the
+ * remaining branches produce values to be passed to that function as its
+ * arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig (*... -> a),*... -> a
+ * @param {Function} fn The function to apply to the remaining arguments.
+ * @param {...*} args Any number of positional arguments.
+ * @return {*}
+ * @see R.apply
+ * @example
+ *
+ *      R.call(R.add, 1, 2); //=> 3
+ *
+ *      const indentN = R.pipe(R.repeat(' '),
+ *                           R.join(''),
+ *                           R.replace(/^(?!$)/gm));
+ *
+ *      const format = R.converge(R.call, [
+ *                                  R.pipe(R.prop('indent'), indentN),
+ *                                  R.prop('value')
+ *                              ]);
+ *
+ *      format({indent: 2, value: 'foo\nbar\nbaz\n'}); //=> '  foo\n  bar\n  baz\n'
+ * @symb R.call(f, a, b) = f(a, b)
+ */
+var call = /*#__PURE__*/curry(function call(fn) {
+  return fn.apply(this, Array.prototype.slice.call(arguments, 1));
+});
+export default call;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/chain.js b/server/node_modules/ramda/es/chain.js
new file mode 100644
index 0000000000000000000000000000000000000000..9a8398ff14bb2fa20da6ab2ce110f1454a0a9966
--- /dev/null
+++ b/server/node_modules/ramda/es/chain.js
@@ -0,0 +1,41 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _makeFlat from './internal/_makeFlat.js';
+import _xchain from './internal/_xchain.js';
+import map from './map.js';
+
+/**
+ * `chain` maps a function over a list and concatenates the results. `chain`
+ * is also known as `flatMap` in some libraries.
+ *
+ * Dispatches to the `chain` method of the second argument, if present,
+ * according to the [FantasyLand Chain spec](https://github.com/fantasyland/fantasy-land#chain).
+ *
+ * If second argument is a function, `chain(f, g)(x)` is equivalent to `f(g(x), x)`.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig Chain m => (a -> m b) -> m a -> m b
+ * @param {Function} fn The function to map with
+ * @param {Array} list The list to map over
+ * @return {Array} The result of flat-mapping `list` with `fn`
+ * @example
+ *
+ *      const duplicate = n => [n, n];
+ *      R.chain(duplicate, [1, 2, 3]); //=> [1, 1, 2, 2, 3, 3]
+ *
+ *      R.chain(R.append, R.head)([1, 2, 3]); //=> [1, 2, 3, 1]
+ */
+var chain = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/chain', 'chain'], _xchain, function chain(fn, monad) {
+  if (typeof monad === 'function') {
+    return function (x) {
+      return fn(monad(x))(x);
+    };
+  }
+  return _makeFlat(false)(map(fn, monad));
+}));
+export default chain;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/clamp.js b/server/node_modules/ramda/es/clamp.js
new file mode 100644
index 0000000000000000000000000000000000000000..4103b2c56d07f8e395a1de80a29a89b9f2d857f5
--- /dev/null
+++ b/server/node_modules/ramda/es/clamp.js
@@ -0,0 +1,29 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Restricts a number to be within a range.
+ *
+ * Also works for other ordered types such as Strings and Dates.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Relation
+ * @sig Ord a => a -> a -> a -> a
+ * @param {Number} minimum The lower limit of the clamp (inclusive)
+ * @param {Number} maximum The upper limit of the clamp (inclusive)
+ * @param {Number} value Value to be clamped
+ * @return {Number} Returns `minimum` when `val < minimum`, `maximum` when `val > maximum`, returns `val` otherwise
+ * @example
+ *
+ *      R.clamp(1, 10, -5) // => 1
+ *      R.clamp(1, 10, 15) // => 10
+ *      R.clamp(1, 10, 4)  // => 4
+ */
+var clamp = /*#__PURE__*/_curry3(function clamp(min, max, value) {
+  if (min > max) {
+    throw new Error('min must not be greater than max in clamp(min, max, value)');
+  }
+  return value < min ? min : value > max ? max : value;
+});
+export default clamp;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/clone.js b/server/node_modules/ramda/es/clone.js
new file mode 100644
index 0000000000000000000000000000000000000000..096e17b8526a4fe8a90a29e59a721710034c8c17
--- /dev/null
+++ b/server/node_modules/ramda/es/clone.js
@@ -0,0 +1,28 @@
+import _clone from './internal/_clone.js';
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Creates a deep copy of the value which may contain (nested) `Array`s and
+ * `Object`s, `Number`s, `String`s, `Boolean`s and `Date`s. `Function`s are
+ * assigned by reference rather than copied
+ *
+ * Dispatches to a `clone` method if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {*} -> {*}
+ * @param {*} value The object or array to clone
+ * @return {*} A deeply cloned copy of `val`
+ * @example
+ *
+ *      const objects = [{}, {}, {}];
+ *      const objectsClone = R.clone(objects);
+ *      objects === objectsClone; //=> false
+ *      objects[0] === objectsClone[0]; //=> false
+ */
+var clone = /*#__PURE__*/_curry1(function clone(value) {
+  return value != null && typeof value.clone === 'function' ? value.clone() : _clone(value, [], [], true);
+});
+export default clone;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/comparator.js b/server/node_modules/ramda/es/comparator.js
new file mode 100644
index 0000000000000000000000000000000000000000..e5dc2a0065730dc716de677ddca3e5e74ce6ab45
--- /dev/null
+++ b/server/node_modules/ramda/es/comparator.js
@@ -0,0 +1,31 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Makes a comparator function out of a function that reports whether the first
+ * element is less than the second.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((a, b) -> Boolean) -> ((a, b) -> Number)
+ * @param {Function} pred A predicate function of arity two which will return `true` if the first argument
+ * is less than the second, `false` otherwise
+ * @return {Function} A Function :: a -> b -> Int that returns `-1` if a < b, `1` if b < a, otherwise `0`
+ * @example
+ *
+ *      const byAge = R.comparator((a, b) => a.age < b.age);
+ *      const people = [
+ *        { name: 'Emma', age: 70 },
+ *        { name: 'Peter', age: 78 },
+ *        { name: 'Mikhail', age: 62 },
+ *      ];
+ *      const peopleByIncreasingAge = R.sort(byAge, people);
+ *        //=> [{ name: 'Mikhail', age: 62 },{ name: 'Emma', age: 70 }, { name: 'Peter', age: 78 }]
+ */
+var comparator = /*#__PURE__*/_curry1(function comparator(pred) {
+  return function (a, b) {
+    return pred(a, b) ? -1 : pred(b, a) ? 1 : 0;
+  };
+});
+export default comparator;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/complement.js b/server/node_modules/ramda/es/complement.js
new file mode 100644
index 0000000000000000000000000000000000000000..a0984334cfb9183419dd721cdb918a14b39339be
--- /dev/null
+++ b/server/node_modules/ramda/es/complement.js
@@ -0,0 +1,27 @@
+import lift from './lift.js';
+import not from './not.js';
+
+/**
+ * Takes a function `f` and returns a function `g` such that if called with the same arguments
+ * when `f` returns a "truthy" value, `g` returns `false` and when `f` returns a "falsy" value `g` returns `true`.
+ *
+ * `R.complement` may be applied to any functor
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category Logic
+ * @sig (*... -> *) -> (*... -> Boolean)
+ * @param {Function} f
+ * @return {Function}
+ * @see R.not
+ * @example
+ *
+ *      const isNotNil = R.complement(R.isNil);
+ *      isNil(null); //=> true
+ *      isNotNil(null); //=> false
+ *      isNil(7); //=> false
+ *      isNotNil(7); //=> true
+ */
+var complement = /*#__PURE__*/lift(not);
+export default complement;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/compose.js b/server/node_modules/ramda/es/compose.js
new file mode 100644
index 0000000000000000000000000000000000000000..228b3fd4134b1b91de784f88b74eb904d9098e5b
--- /dev/null
+++ b/server/node_modules/ramda/es/compose.js
@@ -0,0 +1,33 @@
+import pipe from './pipe.js';
+import reverse from './reverse.js';
+
+/**
+ * Performs right-to-left function composition. The rightmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * **Note:** The result of compose is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)) -> ((a, b, ..., n) -> z)
+ * @param {...Function} ...functions The functions to compose
+ * @return {Function}
+ * @see R.pipe
+ * @example
+ *
+ *      const classyGreeting = (firstName, lastName) => "The name's " + lastName + ", " + firstName + " " + lastName
+ *      const yellGreeting = R.compose(R.toUpper, classyGreeting);
+ *      yellGreeting('James', 'Bond'); //=> "THE NAME'S BOND, JAMES BOND"
+ *
+ *      R.compose(Math.abs, R.add(1), R.multiply(2))(-4) //=> 7
+ *
+ * @symb R.compose(f, g, h)(a, b) = f(g(h(a, b)))
+ */
+export default function compose() {
+  if (arguments.length === 0) {
+    throw new Error('compose requires at least one argument');
+  }
+  return pipe.apply(this, reverse(arguments));
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/composeK.js b/server/node_modules/ramda/es/composeK.js
new file mode 100644
index 0000000000000000000000000000000000000000..b1935f0095832e9c0fa847708afe40dd4c4d17f1
--- /dev/null
+++ b/server/node_modules/ramda/es/composeK.js
@@ -0,0 +1,43 @@
+import chain from './chain.js';
+import compose from './compose.js';
+import map from './map.js';
+
+/**
+ * Returns the right-to-left Kleisli composition of the provided functions,
+ * each of which must return a value of a type supported by [`chain`](#chain).
+ *
+ * `R.composeK(h, g, f)` is equivalent to `R.compose(R.chain(h), R.chain(g), f)`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Function
+ * @sig Chain m => ((y -> m z), (x -> m y), ..., (a -> m b)) -> (a -> m z)
+ * @param {...Function} ...functions The functions to compose
+ * @return {Function}
+ * @see R.pipeK
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *       //  get :: String -> Object -> Maybe *
+ *       const get = R.curry((propName, obj) => Maybe(obj[propName]))
+ *
+ *       //  getStateCode :: Maybe String -> Maybe String
+ *       const getStateCode = R.composeK(
+ *         R.compose(Maybe.of, R.toUpper),
+ *         get('state'),
+ *         get('address'),
+ *         get('user'),
+ *       );
+ *       getStateCode({"user":{"address":{"state":"ny"}}}); //=> Maybe.Just("NY")
+ *       getStateCode({}); //=> Maybe.Nothing()
+ * @symb R.composeK(f, g, h)(a) = R.chain(f, R.chain(g, h(a)))
+ */
+export default function composeK() {
+  if (arguments.length === 0) {
+    throw new Error('composeK requires at least one argument');
+  }
+  var init = Array.prototype.slice.call(arguments);
+  var last = init.pop();
+  return compose(compose.apply(this, map(chain, init)), last);
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/composeP.js b/server/node_modules/ramda/es/composeP.js
new file mode 100644
index 0000000000000000000000000000000000000000..e79e0d5962e4da89376cc5d080929d45cfb486c2
--- /dev/null
+++ b/server/node_modules/ramda/es/composeP.js
@@ -0,0 +1,44 @@
+import pipeP from './pipeP.js';
+import reverse from './reverse.js';
+
+/**
+ * Performs right-to-left composition of one or more Promise-returning
+ * functions. The rightmost function may have any arity; the remaining
+ * functions must be unary.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((y -> Promise z), (x -> Promise y), ..., (a -> Promise b)) -> (a -> Promise z)
+ * @param {...Function} functions The functions to compose
+ * @return {Function}
+ * @see R.pipeP
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      const db = {
+ *        users: {
+ *          JOE: {
+ *            name: 'Joe',
+ *            followers: ['STEVE', 'SUZY']
+ *          }
+ *        }
+ *      }
+ *
+ *      // We'll pretend to do a db lookup which returns a promise
+ *      const lookupUser = (userId) => Promise.resolve(db.users[userId])
+ *      const lookupFollowers = (user) => Promise.resolve(user.followers)
+ *      lookupUser('JOE').then(lookupFollowers)
+ *
+ *      //  followersForUser :: String -> Promise [UserId]
+ *      const followersForUser = R.composeP(lookupFollowers, lookupUser);
+ *      followersForUser('JOE').then(followers => console.log('Followers:', followers))
+ *      // Followers: ["STEVE","SUZY"]
+ */
+export default function composeP() {
+  if (arguments.length === 0) {
+    throw new Error('composeP requires at least one argument');
+  }
+  return pipeP.apply(this, reverse(arguments));
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/composeWith.js b/server/node_modules/ramda/es/composeWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..af9dd963c60853d440f3f62b46ae4e41cbcdaf21
--- /dev/null
+++ b/server/node_modules/ramda/es/composeWith.js
@@ -0,0 +1,30 @@
+import _curry2 from './internal/_curry2.js';
+import pipeWith from './pipeWith.js';
+import reverse from './reverse.js';
+
+/**
+ * Performs right-to-left function composition using transforming function. The rightmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * **Note:** The result of compose is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig ((* -> *), [(y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)]) -> ((a, b, ..., n) -> z)
+ * @param {...Function} ...functions The functions to compose
+ * @return {Function}
+ * @see R.compose, R.pipeWith
+ * @example
+ *
+ *      const composeWhileNotNil = R.composeWith((f, res) => R.isNil(res) ? res : f(res));
+ *
+ *      composeWhileNotNil([R.inc, R.prop('age')])({age: 1}) //=> 2
+ *      composeWhileNotNil([R.inc, R.prop('age')])({}) //=> undefined
+ *
+ * @symb R.composeWith(f)([g, h, i])(...args) = f(g, f(h, f(i, ...args)))
+ */
+var composeWith = /*#__PURE__*/_curry2(function composeWith(xf, list) {
+  return pipeWith.apply(this, [xf, reverse(list)]);
+});
+export default composeWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/concat.js b/server/node_modules/ramda/es/concat.js
new file mode 100644
index 0000000000000000000000000000000000000000..9a5d31388b8158fd5f46a3dc4a45db081a8a94d4
--- /dev/null
+++ b/server/node_modules/ramda/es/concat.js
@@ -0,0 +1,56 @@
+import _curry2 from './internal/_curry2.js';
+import _isArray from './internal/_isArray.js';
+import _isFunction from './internal/_isFunction.js';
+import _isString from './internal/_isString.js';
+import toString from './toString.js';
+
+/**
+ * Returns the result of concatenating the given lists or strings.
+ *
+ * Note: `R.concat` expects both arguments to be of the same type,
+ * unlike the native `Array.prototype.concat` method. It will throw
+ * an error if you `concat` an Array with a non-Array value.
+ *
+ * Dispatches to the `concat` method of the first argument, if present.
+ * Can also concatenate two members of a [fantasy-land
+ * compatible semigroup](https://github.com/fantasyland/fantasy-land#semigroup).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a] -> [a]
+ * @sig String -> String -> String
+ * @param {Array|String} firstList The first list
+ * @param {Array|String} secondList The second list
+ * @return {Array|String} A list consisting of the elements of `firstList` followed by the elements of
+ * `secondList`.
+ *
+ * @example
+ *
+ *      R.concat('ABC', 'DEF'); // 'ABCDEF'
+ *      R.concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3]
+ *      R.concat([], []); //=> []
+ */
+var concat = /*#__PURE__*/_curry2(function concat(a, b) {
+  if (_isArray(a)) {
+    if (_isArray(b)) {
+      return a.concat(b);
+    }
+    throw new TypeError(toString(b) + ' is not an array');
+  }
+  if (_isString(a)) {
+    if (_isString(b)) {
+      return a + b;
+    }
+    throw new TypeError(toString(b) + ' is not a string');
+  }
+  if (a != null && _isFunction(a['fantasy-land/concat'])) {
+    return a['fantasy-land/concat'](b);
+  }
+  if (a != null && _isFunction(a.concat)) {
+    return a.concat(b);
+  }
+  throw new TypeError(toString(a) + ' does not have a method named "concat" or "fantasy-land/concat"');
+});
+export default concat;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/cond.js b/server/node_modules/ramda/es/cond.js
new file mode 100644
index 0000000000000000000000000000000000000000..ea85c1f68b1b69d45e83fd8a5a4a2a6c60f977f8
--- /dev/null
+++ b/server/node_modules/ramda/es/cond.js
@@ -0,0 +1,48 @@
+import _arity from './internal/_arity.js';
+import _curry1 from './internal/_curry1.js';
+import map from './map.js';
+import max from './max.js';
+import reduce from './reduce.js';
+
+/**
+ * Returns a function, `fn`, which encapsulates `if/else, if/else, ...` logic.
+ * `R.cond` takes a list of [predicate, transformer] pairs. All of the arguments
+ * to `fn` are applied to each of the predicates in turn until one returns a
+ * "truthy" value, at which point `fn` returns the result of applying its
+ * arguments to the corresponding transformer. If none of the predicates
+ * matches, `fn` returns undefined.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category Logic
+ * @sig [[(*... -> Boolean),(*... -> *)]] -> (*... -> *)
+ * @param {Array} pairs A list of [predicate, transformer]
+ * @return {Function}
+ * @see R.ifElse, R.unless, R.when
+ * @example
+ *
+ *      const fn = R.cond([
+ *        [R.equals(0),   R.always('water freezes at 0°C')],
+ *        [R.equals(100), R.always('water boils at 100°C')],
+ *        [R.T,           temp => 'nothing special happens at ' + temp + '°C']
+ *      ]);
+ *      fn(0); //=> 'water freezes at 0°C'
+ *      fn(50); //=> 'nothing special happens at 50°C'
+ *      fn(100); //=> 'water boils at 100°C'
+ */
+var cond = /*#__PURE__*/_curry1(function cond(pairs) {
+  var arity = reduce(max, 0, map(function (pair) {
+    return pair[0].length;
+  }, pairs));
+  return _arity(arity, function () {
+    var idx = 0;
+    while (idx < pairs.length) {
+      if (pairs[idx][0].apply(this, arguments)) {
+        return pairs[idx][1].apply(this, arguments);
+      }
+      idx += 1;
+    }
+  });
+});
+export default cond;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/construct.js b/server/node_modules/ramda/es/construct.js
new file mode 100644
index 0000000000000000000000000000000000000000..b201ef19bca2561065ce601ce215c5ff64af3e59
--- /dev/null
+++ b/server/node_modules/ramda/es/construct.js
@@ -0,0 +1,39 @@
+import _curry1 from './internal/_curry1.js';
+import constructN from './constructN.js';
+
+/**
+ * Wraps a constructor function inside a curried function that can be called
+ * with the same arguments and returns the same type.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (* -> {*}) -> (* -> {*})
+ * @param {Function} fn The constructor function to wrap.
+ * @return {Function} A wrapped, curried constructor function.
+ * @see R.invoker
+ * @example
+ *
+ *      // Constructor function
+ *      function Animal(kind) {
+ *        this.kind = kind;
+ *      };
+ *      Animal.prototype.sighting = function() {
+ *        return "It's a " + this.kind + "!";
+ *      }
+ *
+ *      const AnimalConstructor = R.construct(Animal)
+ *
+ *      // Notice we no longer need the 'new' keyword:
+ *      AnimalConstructor('Pig'); //=> {"kind": "Pig", "sighting": function (){...}};
+ *
+ *      const animalTypes = ["Lion", "Tiger", "Bear"];
+ *      const animalSighting = R.invoker(0, 'sighting');
+ *      const sightNewAnimal = R.compose(animalSighting, AnimalConstructor);
+ *      R.map(sightNewAnimal, animalTypes); //=> ["It's a Lion!", "It's a Tiger!", "It's a Bear!"]
+ */
+var construct = /*#__PURE__*/_curry1(function construct(Fn) {
+  return constructN(Fn.length, Fn);
+});
+export default construct;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/constructN.js b/server/node_modules/ramda/es/constructN.js
new file mode 100644
index 0000000000000000000000000000000000000000..2427b689f76f2d57a3ee48ee2fb53faac716aba8
--- /dev/null
+++ b/server/node_modules/ramda/es/constructN.js
@@ -0,0 +1,74 @@
+import _curry2 from './internal/_curry2.js';
+import curry from './curry.js';
+import nAry from './nAry.js';
+
+/**
+ * Wraps a constructor function inside a curried function that can be called
+ * with the same arguments and returns the same type. The arity of the function
+ * returned is specified to allow using variadic constructor functions.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.0
+ * @category Function
+ * @sig Number -> (* -> {*}) -> (* -> {*})
+ * @param {Number} n The arity of the constructor function.
+ * @param {Function} Fn The constructor function to wrap.
+ * @return {Function} A wrapped, curried constructor function.
+ * @example
+ *
+ *      // Variadic Constructor function
+ *      function Salad() {
+ *        this.ingredients = arguments;
+ *      }
+ *
+ *      Salad.prototype.recipe = function() {
+ *        const instructions = R.map(ingredient => 'Add a dollop of ' + ingredient, this.ingredients);
+ *        return R.join('\n', instructions);
+ *      };
+ *
+ *      const ThreeLayerSalad = R.constructN(3, Salad);
+ *
+ *      // Notice we no longer need the 'new' keyword, and the constructor is curried for 3 arguments.
+ *      const salad = ThreeLayerSalad('Mayonnaise')('Potato Chips')('Ketchup');
+ *
+ *      console.log(salad.recipe());
+ *      // Add a dollop of Mayonnaise
+ *      // Add a dollop of Potato Chips
+ *      // Add a dollop of Ketchup
+ */
+var constructN = /*#__PURE__*/_curry2(function constructN(n, Fn) {
+  if (n > 10) {
+    throw new Error('Constructor with greater than ten arguments');
+  }
+  if (n === 0) {
+    return function () {
+      return new Fn();
+    };
+  }
+  return curry(nAry(n, function ($0, $1, $2, $3, $4, $5, $6, $7, $8, $9) {
+    switch (arguments.length) {
+      case 1:
+        return new Fn($0);
+      case 2:
+        return new Fn($0, $1);
+      case 3:
+        return new Fn($0, $1, $2);
+      case 4:
+        return new Fn($0, $1, $2, $3);
+      case 5:
+        return new Fn($0, $1, $2, $3, $4);
+      case 6:
+        return new Fn($0, $1, $2, $3, $4, $5);
+      case 7:
+        return new Fn($0, $1, $2, $3, $4, $5, $6);
+      case 8:
+        return new Fn($0, $1, $2, $3, $4, $5, $6, $7);
+      case 9:
+        return new Fn($0, $1, $2, $3, $4, $5, $6, $7, $8);
+      case 10:
+        return new Fn($0, $1, $2, $3, $4, $5, $6, $7, $8, $9);
+    }
+  }));
+});
+export default constructN;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/contains.js b/server/node_modules/ramda/es/contains.js
new file mode 100644
index 0000000000000000000000000000000000000000..212100c96dcaa8852f0022672e8df40f36fe80d1
--- /dev/null
+++ b/server/node_modules/ramda/es/contains.js
@@ -0,0 +1,28 @@
+import _includes from './internal/_includes.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns `true` if the specified value is equal, in [`R.equals`](#equals)
+ * terms, to at least one element of the given list; `false` otherwise.
+ * Works also with strings.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Boolean
+ * @param {Object} a The item to compare against.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if an equivalent item is in the list, `false` otherwise.
+ * @see R.includes
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      R.contains(3, [1, 2, 3]); //=> true
+ *      R.contains(4, [1, 2, 3]); //=> false
+ *      R.contains({ name: 'Fred' }, [{ name: 'Fred' }]); //=> true
+ *      R.contains([42], [[42]]); //=> true
+ *      R.contains('ba', 'banana'); //=>true
+ */
+var contains = /*#__PURE__*/_curry2(_includes);
+export default contains;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/converge.js b/server/node_modules/ramda/es/converge.js
new file mode 100644
index 0000000000000000000000000000000000000000..17dc849e4d348044dbd953b3a33fb864a71a0ff2
--- /dev/null
+++ b/server/node_modules/ramda/es/converge.js
@@ -0,0 +1,45 @@
+import _curry2 from './internal/_curry2.js';
+import _map from './internal/_map.js';
+import curryN from './curryN.js';
+import max from './max.js';
+import pluck from './pluck.js';
+import reduce from './reduce.js';
+
+/**
+ * Accepts a converging function and a list of branching functions and returns
+ * a new function. The arity of the new function is the same as the arity of
+ * the longest branching function. When invoked, this new function is applied
+ * to some arguments, and each branching function is applied to those same
+ * arguments. The results of each branching function are passed as arguments
+ * to the converging function to produce the return value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.2
+ * @category Function
+ * @sig ((x1, x2, ...) -> z) -> [((a, b, ...) -> x1), ((a, b, ...) -> x2), ...] -> (a -> b -> ... -> z)
+ * @param {Function} after A function. `after` will be invoked with the return values of
+ *        `fn1` and `fn2` as its arguments.
+ * @param {Array} functions A list of functions.
+ * @return {Function} A new function.
+ * @see R.useWith
+ * @example
+ *
+ *      const average = R.converge(R.divide, [R.sum, R.length])
+ *      average([1, 2, 3, 4, 5, 6, 7]) //=> 4
+ *
+ *      const strangeConcat = R.converge(R.concat, [R.toUpper, R.toLower])
+ *      strangeConcat("Yodel") //=> "YODELyodel"
+ *
+ * @symb R.converge(f, [g, h])(a, b) = f(g(a, b), h(a, b))
+ */
+var converge = /*#__PURE__*/_curry2(function converge(after, fns) {
+  return curryN(reduce(max, 0, pluck('length', fns)), function () {
+    var args = arguments;
+    var context = this;
+    return after.apply(context, _map(function (fn) {
+      return fn.apply(context, args);
+    }, fns));
+  });
+});
+export default converge;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/countBy.js b/server/node_modules/ramda/es/countBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..1da99a5406b98ef631067ca0156076e0c5319e71
--- /dev/null
+++ b/server/node_modules/ramda/es/countBy.js
@@ -0,0 +1,30 @@
+import reduceBy from './reduceBy.js';
+
+/**
+ * Counts the elements of a list according to how many match each value of a
+ * key generated by the supplied function. Returns an object mapping the keys
+ * produced by `fn` to the number of occurrences in the list. Note that all
+ * keys are coerced to strings because of how JavaScript objects work.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig (a -> String) -> [a] -> {*}
+ * @param {Function} fn The function used to map values to keys.
+ * @param {Array} list The list to count elements from.
+ * @return {Object} An object mapping keys to number of occurrences in the list.
+ * @example
+ *
+ *      const numbers = [1.0, 1.1, 1.2, 2.0, 3.0, 2.2];
+ *      R.countBy(Math.floor)(numbers);    //=> {'1': 3, '2': 2, '3': 1}
+ *
+ *      const letters = ['a', 'b', 'A', 'a', 'B', 'c'];
+ *      R.countBy(R.toLower)(letters);   //=> {'a': 3, 'b': 2, 'c': 1}
+ */
+var countBy = /*#__PURE__*/reduceBy(function (acc, elem) {
+  return acc + 1;
+}, 0);
+export default countBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/curry.js b/server/node_modules/ramda/es/curry.js
new file mode 100644
index 0000000000000000000000000000000000000000..5e71f72342d1a18e0e5c3c3655bfcc2ceb341399
--- /dev/null
+++ b/server/node_modules/ramda/es/curry.js
@@ -0,0 +1,48 @@
+import _curry1 from './internal/_curry1.js';
+import curryN from './curryN.js';
+
+/**
+ * Returns a curried equivalent of the provided function. The curried function
+ * has two unusual capabilities. First, its arguments needn't be provided one
+ * at a time. If `f` is a ternary function and `g` is `R.curry(f)`, the
+ * following are equivalent:
+ *
+ *   - `g(1)(2)(3)`
+ *   - `g(1)(2, 3)`
+ *   - `g(1, 2)(3)`
+ *   - `g(1, 2, 3)`
+ *
+ * Secondly, the special placeholder value [`R.__`](#__) may be used to specify
+ * "gaps", allowing partial application of any combination of arguments,
+ * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__),
+ * the following are equivalent:
+ *
+ *   - `g(1, 2, 3)`
+ *   - `g(_, 2, 3)(1)`
+ *   - `g(_, _, 3)(1)(2)`
+ *   - `g(_, _, 3)(1, 2)`
+ *   - `g(_, 2)(1)(3)`
+ *   - `g(_, 2)(1, 3)`
+ *   - `g(_, 2)(_, 3)(1)`
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (* -> a) -> (* -> a)
+ * @param {Function} fn The function to curry.
+ * @return {Function} A new, curried function.
+ * @see R.curryN, R.partial
+ * @example
+ *
+ *      const addFourNumbers = (a, b, c, d) => a + b + c + d;
+ *
+ *      const curriedAddFourNumbers = R.curry(addFourNumbers);
+ *      const f = curriedAddFourNumbers(1, 2);
+ *      const g = f(3);
+ *      g(4); //=> 10
+ */
+var curry = /*#__PURE__*/_curry1(function curry(fn) {
+  return curryN(fn.length, fn);
+});
+export default curry;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/curryN.js b/server/node_modules/ramda/es/curryN.js
new file mode 100644
index 0000000000000000000000000000000000000000..4f7065dea3e0d157284e89f4712600c959b6df26
--- /dev/null
+++ b/server/node_modules/ramda/es/curryN.js
@@ -0,0 +1,54 @@
+import _arity from './internal/_arity.js';
+import _curry1 from './internal/_curry1.js';
+import _curry2 from './internal/_curry2.js';
+import _curryN from './internal/_curryN.js';
+
+/**
+ * Returns a curried equivalent of the provided function, with the specified
+ * arity. The curried function has two unusual capabilities. First, its
+ * arguments needn't be provided one at a time. If `g` is `R.curryN(3, f)`, the
+ * following are equivalent:
+ *
+ *   - `g(1)(2)(3)`
+ *   - `g(1)(2, 3)`
+ *   - `g(1, 2)(3)`
+ *   - `g(1, 2, 3)`
+ *
+ * Secondly, the special placeholder value [`R.__`](#__) may be used to specify
+ * "gaps", allowing partial application of any combination of arguments,
+ * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__),
+ * the following are equivalent:
+ *
+ *   - `g(1, 2, 3)`
+ *   - `g(_, 2, 3)(1)`
+ *   - `g(_, _, 3)(1)(2)`
+ *   - `g(_, _, 3)(1, 2)`
+ *   - `g(_, 2)(1)(3)`
+ *   - `g(_, 2)(1, 3)`
+ *   - `g(_, 2)(_, 3)(1)`
+ *
+ * @func
+ * @memberOf R
+ * @since v0.5.0
+ * @category Function
+ * @sig Number -> (* -> a) -> (* -> a)
+ * @param {Number} length The arity for the returned function.
+ * @param {Function} fn The function to curry.
+ * @return {Function} A new, curried function.
+ * @see R.curry
+ * @example
+ *
+ *      const sumArgs = (...args) => R.sum(args);
+ *
+ *      const curriedAddFourNumbers = R.curryN(4, sumArgs);
+ *      const f = curriedAddFourNumbers(1, 2);
+ *      const g = f(3);
+ *      g(4); //=> 10
+ */
+var curryN = /*#__PURE__*/_curry2(function curryN(length, fn) {
+  if (length === 1) {
+    return _curry1(fn);
+  }
+  return _arity(length, _curryN(length, [], fn));
+});
+export default curryN;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/dec.js b/server/node_modules/ramda/es/dec.js
new file mode 100644
index 0000000000000000000000000000000000000000..21323a212802ff42da5afb581df0dd18475ce997
--- /dev/null
+++ b/server/node_modules/ramda/es/dec.js
@@ -0,0 +1,19 @@
+import add from './add.js';
+
+/**
+ * Decrements its argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Math
+ * @sig Number -> Number
+ * @param {Number} n
+ * @return {Number} n - 1
+ * @see R.inc
+ * @example
+ *
+ *      R.dec(42); //=> 41
+ */
+var dec = /*#__PURE__*/add(-1);
+export default dec;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/defaultTo.js b/server/node_modules/ramda/es/defaultTo.js
new file mode 100644
index 0000000000000000000000000000000000000000..6cdb7bff969bdff7cb634d76a86a7b474ee9b13f
--- /dev/null
+++ b/server/node_modules/ramda/es/defaultTo.js
@@ -0,0 +1,29 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns the second argument if it is not `null`, `undefined` or `NaN`;
+ * otherwise the first argument is returned.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Logic
+ * @sig a -> b -> a | b
+ * @param {a} default The default value.
+ * @param {b} val `val` will be returned instead of `default` unless `val` is `null`, `undefined` or `NaN`.
+ * @return {*} The second value if it is not `null`, `undefined` or `NaN`, otherwise the default value
+ * @example
+ *
+ *      const defaultTo42 = R.defaultTo(42);
+ *
+ *      defaultTo42(null);  //=> 42
+ *      defaultTo42(undefined);  //=> 42
+ *      defaultTo42(false);  //=> false
+ *      defaultTo42('Ramda');  //=> 'Ramda'
+ *      // parseInt('string') results in NaN
+ *      defaultTo42(parseInt('string')); //=> 42
+ */
+var defaultTo = /*#__PURE__*/_curry2(function defaultTo(d, v) {
+  return v == null || v !== v ? d : v;
+});
+export default defaultTo;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/descend.js b/server/node_modules/ramda/es/descend.js
new file mode 100644
index 0000000000000000000000000000000000000000..6208dc3c22e98f0c28368e88510f83319f712f16
--- /dev/null
+++ b/server/node_modules/ramda/es/descend.js
@@ -0,0 +1,33 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Makes a descending comparator function out of a function that returns a value
+ * that can be compared with `<` and `>`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Function
+ * @sig Ord b => (a -> b) -> a -> a -> Number
+ * @param {Function} fn A function of arity one that returns a value that can be compared
+ * @param {*} a The first item to be compared.
+ * @param {*} b The second item to be compared.
+ * @return {Number} `-1` if fn(a) > fn(b), `1` if fn(b) > fn(a), otherwise `0`
+ * @see R.ascend
+ * @example
+ *
+ *      const byAge = R.descend(R.prop('age'));
+ *      const people = [
+ *        { name: 'Emma', age: 70 },
+ *        { name: 'Peter', age: 78 },
+ *        { name: 'Mikhail', age: 62 },
+ *      ];
+ *      const peopleByOldestFirst = R.sort(byAge, people);
+ *        //=> [{ name: 'Peter', age: 78 }, { name: 'Emma', age: 70 }, { name: 'Mikhail', age: 62 }]
+ */
+var descend = /*#__PURE__*/_curry3(function descend(fn, a, b) {
+  var aa = fn(a);
+  var bb = fn(b);
+  return aa > bb ? -1 : aa < bb ? 1 : 0;
+});
+export default descend;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/difference.js b/server/node_modules/ramda/es/difference.js
new file mode 100644
index 0000000000000000000000000000000000000000..a4a653a040d21c624dfaaa0376362d7c57738b99
--- /dev/null
+++ b/server/node_modules/ramda/es/difference.js
@@ -0,0 +1,43 @@
+import _curry2 from './internal/_curry2.js';
+import _Set from './internal/_Set.js';
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements in the first list not
+ * contained in the second list. Objects and Arrays are compared in terms of
+ * value equality, not reference equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` that are not in `list2`.
+ * @see R.differenceWith, R.symmetricDifference, R.symmetricDifferenceWith, R.without
+ * @example
+ *
+ *      R.difference([1,2,3,4], [7,6,5,4,3]); //=> [1,2]
+ *      R.difference([7,6,5,4,3], [1,2,3,4]); //=> [7,6,5]
+ *      R.difference([{a: 1}, {b: 2}], [{a: 1}, {c: 3}]) //=> [{b: 2}]
+ */
+var difference = /*#__PURE__*/_curry2(function difference(first, second) {
+  var out = [];
+  var idx = 0;
+  var firstLen = first.length;
+  var secondLen = second.length;
+  var toFilterOut = new _Set();
+
+  for (var i = 0; i < secondLen; i += 1) {
+    toFilterOut.add(second[i]);
+  }
+
+  while (idx < firstLen) {
+    if (toFilterOut.add(first[idx])) {
+      out[out.length] = first[idx];
+    }
+    idx += 1;
+  }
+  return out;
+});
+export default difference;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/differenceWith.js b/server/node_modules/ramda/es/differenceWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b36059f07c9d6862d03e6955b4738a1c1a6fe32
--- /dev/null
+++ b/server/node_modules/ramda/es/differenceWith.js
@@ -0,0 +1,38 @@
+import _includesWith from './internal/_includesWith.js';
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements in the first list not
+ * contained in the second list. Duplication is determined according to the
+ * value returned by applying the supplied predicate to two list elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig ((a, a) -> Boolean) -> [a] -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` that are not in `list2`.
+ * @see R.difference, R.symmetricDifference, R.symmetricDifferenceWith
+ * @example
+ *
+ *      const cmp = (x, y) => x.a === y.a;
+ *      const l1 = [{a: 1}, {a: 2}, {a: 3}];
+ *      const l2 = [{a: 3}, {a: 4}];
+ *      R.differenceWith(cmp, l1, l2); //=> [{a: 1}, {a: 2}]
+ */
+var differenceWith = /*#__PURE__*/_curry3(function differenceWith(pred, first, second) {
+  var out = [];
+  var idx = 0;
+  var firstLen = first.length;
+  while (idx < firstLen) {
+    if (!_includesWith(pred, first[idx], second) && !_includesWith(pred, first[idx], out)) {
+      out.push(first[idx]);
+    }
+    idx += 1;
+  }
+  return out;
+});
+export default differenceWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/dissoc.js b/server/node_modules/ramda/es/dissoc.js
new file mode 100644
index 0000000000000000000000000000000000000000..206284854ccab8b0fb2dc077a69be5d4b37d0095
--- /dev/null
+++ b/server/node_modules/ramda/es/dissoc.js
@@ -0,0 +1,27 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns a new object that does not contain a `prop` property.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Object
+ * @sig String -> {k: v} -> {k: v}
+ * @param {String} prop The name of the property to dissociate
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object equivalent to the original but without the specified property
+ * @see R.assoc, R.omit
+ * @example
+ *
+ *      R.dissoc('b', {a: 1, b: 2, c: 3}); //=> {a: 1, c: 3}
+ */
+var dissoc = /*#__PURE__*/_curry2(function dissoc(prop, obj) {
+  var result = {};
+  for (var p in obj) {
+    result[p] = obj[p];
+  }
+  delete result[prop];
+  return result;
+});
+export default dissoc;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/dissocPath.js b/server/node_modules/ramda/es/dissocPath.js
new file mode 100644
index 0000000000000000000000000000000000000000..bdf85174d786a851a01ebb94e0f8dbef3d3436b3
--- /dev/null
+++ b/server/node_modules/ramda/es/dissocPath.js
@@ -0,0 +1,46 @@
+import _curry2 from './internal/_curry2.js';
+import _isInteger from './internal/_isInteger.js';
+import _isArray from './internal/_isArray.js';
+import assoc from './assoc.js';
+import dissoc from './dissoc.js';
+import remove from './remove.js';
+import update from './update.js';
+
+/**
+ * Makes a shallow clone of an object, omitting the property at the given path.
+ * Note that this copies and flattens prototype properties onto the new object
+ * as well. All non-primitive properties are copied by reference.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.11.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> {k: v} -> {k: v}
+ * @param {Array} path The path to the value to omit
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object without the property at path
+ * @see R.assocPath
+ * @example
+ *
+ *      R.dissocPath(['a', 'b', 'c'], {a: {b: {c: 42}}}); //=> {a: {b: {}}}
+ */
+var dissocPath = /*#__PURE__*/_curry2(function dissocPath(path, obj) {
+  switch (path.length) {
+    case 0:
+      return obj;
+    case 1:
+      return _isInteger(path[0]) && _isArray(obj) ? remove(path[0], 1, obj) : dissoc(path[0], obj);
+    default:
+      var head = path[0];
+      var tail = Array.prototype.slice.call(path, 1);
+      if (obj[head] == null) {
+        return obj;
+      } else if (_isInteger(head) && _isArray(obj)) {
+        return update(head, dissocPath(tail, obj[head]), obj);
+      } else {
+        return assoc(head, dissocPath(tail, obj[head]), obj);
+      }
+  }
+});
+export default dissocPath;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/divide.js b/server/node_modules/ramda/es/divide.js
new file mode 100644
index 0000000000000000000000000000000000000000..52eed42893cc64716d5944a7b4fb4616e72aae47
--- /dev/null
+++ b/server/node_modules/ramda/es/divide.js
@@ -0,0 +1,28 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Divides two numbers. Equivalent to `a / b`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The first value.
+ * @param {Number} b The second value.
+ * @return {Number} The result of `a / b`.
+ * @see R.multiply
+ * @example
+ *
+ *      R.divide(71, 100); //=> 0.71
+ *
+ *      const half = R.divide(R.__, 2);
+ *      half(42); //=> 21
+ *
+ *      const reciprocal = R.divide(1);
+ *      reciprocal(4);   //=> 0.25
+ */
+var divide = /*#__PURE__*/_curry2(function divide(a, b) {
+  return a / b;
+});
+export default divide;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/drop.js b/server/node_modules/ramda/es/drop.js
new file mode 100644
index 0000000000000000000000000000000000000000..fad4d71d3843ebc1cdaef878cfde9b6b59cabc3a
--- /dev/null
+++ b/server/node_modules/ramda/es/drop.js
@@ -0,0 +1,33 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xdrop from './internal/_xdrop.js';
+import slice from './slice.js';
+
+/**
+ * Returns all but the first `n` elements of the given list, string, or
+ * transducer/transformer (or object with a `drop` method).
+ *
+ * Dispatches to the `drop` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n
+ * @param {*} list
+ * @return {*} A copy of list without the first `n` elements
+ * @see R.take, R.transduce, R.dropLast, R.dropWhile
+ * @example
+ *
+ *      R.drop(1, ['foo', 'bar', 'baz']); //=> ['bar', 'baz']
+ *      R.drop(2, ['foo', 'bar', 'baz']); //=> ['baz']
+ *      R.drop(3, ['foo', 'bar', 'baz']); //=> []
+ *      R.drop(4, ['foo', 'bar', 'baz']); //=> []
+ *      R.drop(3, 'ramda');               //=> 'da'
+ */
+var drop = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['drop'], _xdrop, function drop(n, xs) {
+  return slice(Math.max(0, n), Infinity, xs);
+}));
+export default drop;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/dropLast.js b/server/node_modules/ramda/es/dropLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..264dae3a0611911a4993c0df8183439aa7af7338
--- /dev/null
+++ b/server/node_modules/ramda/es/dropLast.js
@@ -0,0 +1,30 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _dropLast from './internal/_dropLast.js';
+import _xdropLast from './internal/_xdropLast.js';
+
+/**
+ * Returns a list containing all but the last `n` elements of the given `list`.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n The number of elements of `list` to skip.
+ * @param {Array} list The list of elements to consider.
+ * @return {Array} A copy of the list with only the first `list.length - n` elements
+ * @see R.takeLast, R.drop, R.dropWhile, R.dropLastWhile
+ * @example
+ *
+ *      R.dropLast(1, ['foo', 'bar', 'baz']); //=> ['foo', 'bar']
+ *      R.dropLast(2, ['foo', 'bar', 'baz']); //=> ['foo']
+ *      R.dropLast(3, ['foo', 'bar', 'baz']); //=> []
+ *      R.dropLast(4, ['foo', 'bar', 'baz']); //=> []
+ *      R.dropLast(3, 'ramda');               //=> 'ra'
+ */
+var dropLast = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xdropLast, _dropLast));
+export default dropLast;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/dropLastWhile.js b/server/node_modules/ramda/es/dropLastWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..0322ae8c74ae4c862d5c35419e7b00000071f06e
--- /dev/null
+++ b/server/node_modules/ramda/es/dropLastWhile.js
@@ -0,0 +1,34 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _dropLastWhile from './internal/_dropLastWhile.js';
+import _xdropLastWhile from './internal/_xdropLastWhile.js';
+
+/**
+ * Returns a new list excluding all the tailing elements of a given list which
+ * satisfy the supplied predicate function. It passes each value from the right
+ * to the supplied predicate function, skipping elements until the predicate
+ * function returns a `falsy` value. The predicate function is applied to one argument:
+ * *(value)*.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} predicate The function to be called on each element
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array without any trailing elements that return `falsy` values from the `predicate`.
+ * @see R.takeLastWhile, R.addIndex, R.drop, R.dropWhile
+ * @example
+ *
+ *      const lteThree = x => x <= 3;
+ *
+ *      R.dropLastWhile(lteThree, [1, 2, 3, 4, 3, 2, 1]); //=> [1, 2, 3, 4]
+ *
+ *      R.dropLastWhile(x => x !== 'd' , 'Ramda'); //=> 'Ramd'
+ */
+var dropLastWhile = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xdropLastWhile, _dropLastWhile));
+export default dropLastWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/dropRepeats.js b/server/node_modules/ramda/es/dropRepeats.js
new file mode 100644
index 0000000000000000000000000000000000000000..b258bb3ae251cbf76f83d571fc437a8bd3bf1cfe
--- /dev/null
+++ b/server/node_modules/ramda/es/dropRepeats.js
@@ -0,0 +1,26 @@
+import _curry1 from './internal/_curry1.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xdropRepeatsWith from './internal/_xdropRepeatsWith.js';
+import dropRepeatsWith from './dropRepeatsWith.js';
+import equals from './equals.js';
+
+/**
+ * Returns a new list without any consecutively repeating elements.
+ * [`R.equals`](#equals) is used to determine equality.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig [a] -> [a]
+ * @param {Array} list The array to consider.
+ * @return {Array} `list` without repeating elements.
+ * @see R.transduce
+ * @example
+ *
+ *     R.dropRepeats([1, 1, 1, 2, 3, 4, 4, 2, 2]); //=> [1, 2, 3, 4, 2]
+ */
+var dropRepeats = /*#__PURE__*/_curry1( /*#__PURE__*/_dispatchable([], /*#__PURE__*/_xdropRepeatsWith(equals), /*#__PURE__*/dropRepeatsWith(equals)));
+export default dropRepeats;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/dropRepeatsWith.js b/server/node_modules/ramda/es/dropRepeatsWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..da25bb66e598313b83aa31e6bf6f0bddc04b111d
--- /dev/null
+++ b/server/node_modules/ramda/es/dropRepeatsWith.js
@@ -0,0 +1,42 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xdropRepeatsWith from './internal/_xdropRepeatsWith.js';
+import last from './last.js';
+
+/**
+ * Returns a new list without any consecutively repeating elements. Equality is
+ * determined by applying the supplied predicate to each pair of consecutive elements. The
+ * first element in a series of equal elements will be preserved.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig ((a, a) -> Boolean) -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list The array to consider.
+ * @return {Array} `list` without repeating elements.
+ * @see R.transduce
+ * @example
+ *
+ *      const l = [1, -1, 1, 3, 4, -4, -4, -5, 5, 3, 3];
+ *      R.dropRepeatsWith(R.eqBy(Math.abs), l); //=> [1, 3, 4, -5, 3]
+ */
+var dropRepeatsWith = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xdropRepeatsWith, function dropRepeatsWith(pred, list) {
+  var result = [];
+  var idx = 1;
+  var len = list.length;
+  if (len !== 0) {
+    result[0] = list[0];
+    while (idx < len) {
+      if (!pred(last(result), list[idx])) {
+        result[result.length] = list[idx];
+      }
+      idx += 1;
+    }
+  }
+  return result;
+}));
+export default dropRepeatsWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/dropWhile.js b/server/node_modules/ramda/es/dropWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..775b50af08cb56a9f39dc7c468def62a4ff7085b
--- /dev/null
+++ b/server/node_modules/ramda/es/dropWhile.js
@@ -0,0 +1,42 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xdropWhile from './internal/_xdropWhile.js';
+import slice from './slice.js';
+
+/**
+ * Returns a new list excluding the leading elements of a given list which
+ * satisfy the supplied predicate function. It passes each value to the supplied
+ * predicate function, skipping elements while the predicate function returns
+ * `true`. The predicate function is applied to one argument: *(value)*.
+ *
+ * Dispatches to the `dropWhile` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} fn The function called per iteration.
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array.
+ * @see R.takeWhile, R.transduce, R.addIndex
+ * @example
+ *
+ *      const lteTwo = x => x <= 2;
+ *
+ *      R.dropWhile(lteTwo, [1, 2, 3, 4, 3, 2, 1]); //=> [3, 4, 3, 2, 1]
+ *
+ *      R.dropWhile(x => x !== 'd' , 'Ramda'); //=> 'da'
+ */
+var dropWhile = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['dropWhile'], _xdropWhile, function dropWhile(pred, xs) {
+  var idx = 0;
+  var len = xs.length;
+  while (idx < len && pred(xs[idx])) {
+    idx += 1;
+  }
+  return slice(idx, Infinity, xs);
+}));
+export default dropWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/either.js b/server/node_modules/ramda/es/either.js
new file mode 100644
index 0000000000000000000000000000000000000000..48a24e8556a7db26e8b7ecf428fc78f490b10414
--- /dev/null
+++ b/server/node_modules/ramda/es/either.js
@@ -0,0 +1,41 @@
+import _curry2 from './internal/_curry2.js';
+import _isFunction from './internal/_isFunction.js';
+import lift from './lift.js';
+import or from './or.js';
+
+/**
+ * A function wrapping calls to the two functions in an `||` operation,
+ * returning the result of the first function if it is truth-y and the result
+ * of the second function otherwise. Note that this is short-circuited,
+ * meaning that the second function will not be invoked if the first returns a
+ * truth-y value.
+ *
+ * In addition to functions, `R.either` also accepts any fantasy-land compatible
+ * applicative functor.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category Logic
+ * @sig (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
+ * @param {Function} f a predicate
+ * @param {Function} g another predicate
+ * @return {Function} a function that applies its arguments to `f` and `g` and `||`s their outputs together.
+ * @see R.or
+ * @example
+ *
+ *      const gt10 = x => x > 10;
+ *      const even = x => x % 2 === 0;
+ *      const f = R.either(gt10, even);
+ *      f(101); //=> true
+ *      f(8); //=> true
+ *
+ *      R.either(Maybe.Just(false), Maybe.Just(55)); // => Maybe.Just(55)
+ *      R.either([false, false, 'a'], [11]) // => [11, 11, "a"]
+ */
+var either = /*#__PURE__*/_curry2(function either(f, g) {
+  return _isFunction(f) ? function _either() {
+    return f.apply(this, arguments) || g.apply(this, arguments);
+  } : lift(or)(f, g);
+});
+export default either;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/empty.js b/server/node_modules/ramda/es/empty.js
new file mode 100644
index 0000000000000000000000000000000000000000..684004d6dcb70934880be22119d1ed1375222c40
--- /dev/null
+++ b/server/node_modules/ramda/es/empty.js
@@ -0,0 +1,36 @@
+import _curry1 from './internal/_curry1.js';
+import _isArguments from './internal/_isArguments.js';
+import _isArray from './internal/_isArray.js';
+import _isObject from './internal/_isObject.js';
+import _isString from './internal/_isString.js';
+
+/**
+ * Returns the empty value of its argument's type. Ramda defines the empty
+ * value of Array (`[]`), Object (`{}`), String (`''`), and Arguments. Other
+ * types are supported if they define `<Type>.empty`,
+ * `<Type>.prototype.empty` or implement the
+ * [FantasyLand Monoid spec](https://github.com/fantasyland/fantasy-land#monoid).
+ *
+ * Dispatches to the `empty` method of the first argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Function
+ * @sig a -> a
+ * @param {*} x
+ * @return {*}
+ * @example
+ *
+ *      R.empty(Just(42));      //=> Nothing()
+ *      R.empty([1, 2, 3]);     //=> []
+ *      R.empty('unicorns');    //=> ''
+ *      R.empty({x: 1, y: 2});  //=> {}
+ */
+var empty = /*#__PURE__*/_curry1(function empty(x) {
+  return x != null && typeof x['fantasy-land/empty'] === 'function' ? x['fantasy-land/empty']() : x != null && x.constructor != null && typeof x.constructor['fantasy-land/empty'] === 'function' ? x.constructor['fantasy-land/empty']() : x != null && typeof x.empty === 'function' ? x.empty() : x != null && x.constructor != null && typeof x.constructor.empty === 'function' ? x.constructor.empty() : _isArray(x) ? [] : _isString(x) ? '' : _isObject(x) ? {} : _isArguments(x) ? function () {
+    return arguments;
+  }() : void 0 // else
+  ;
+});
+export default empty;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/endsWith.js b/server/node_modules/ramda/es/endsWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..ae24700fe3055960b4b091e603eee5d83d571fb0
--- /dev/null
+++ b/server/node_modules/ramda/es/endsWith.js
@@ -0,0 +1,30 @@
+import _curry2 from './internal/_curry2.js';
+import equals from './equals.js';
+import takeLast from './takeLast.js';
+
+/**
+ * Checks if a list ends with the provided sublist.
+ *
+ * Similarly, checks if a string ends with the provided substring.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category List
+ * @sig [a] -> [a] -> Boolean
+ * @sig String -> String -> Boolean
+ * @param {*} suffix
+ * @param {*} list
+ * @return {Boolean}
+ * @see R.startsWith
+ * @example
+ *
+ *      R.endsWith('c', 'abc')                //=> true
+ *      R.endsWith('b', 'abc')                //=> false
+ *      R.endsWith(['c'], ['a', 'b', 'c'])    //=> true
+ *      R.endsWith(['b'], ['a', 'b', 'c'])    //=> false
+ */
+var endsWith = /*#__PURE__*/_curry2(function (suffix, list) {
+  return equals(takeLast(suffix.length, list), suffix);
+});
+export default endsWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/eqBy.js b/server/node_modules/ramda/es/eqBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..be1d1e7a783393320e339ce6d2678c7e87d44ff1
--- /dev/null
+++ b/server/node_modules/ramda/es/eqBy.js
@@ -0,0 +1,24 @@
+import _curry3 from './internal/_curry3.js';
+import equals from './equals.js';
+
+/**
+ * Takes a function and two values in its domain and returns `true` if the
+ * values map to the same value in the codomain; `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Relation
+ * @sig (a -> b) -> a -> a -> Boolean
+ * @param {Function} f
+ * @param {*} x
+ * @param {*} y
+ * @return {Boolean}
+ * @example
+ *
+ *      R.eqBy(Math.abs, 5, -5); //=> true
+ */
+var eqBy = /*#__PURE__*/_curry3(function eqBy(f, x, y) {
+  return equals(f(x), f(y));
+});
+export default eqBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/eqProps.js b/server/node_modules/ramda/es/eqProps.js
new file mode 100644
index 0000000000000000000000000000000000000000..a34f4e3147c5d3023b54be06b376d7768cfa1f72
--- /dev/null
+++ b/server/node_modules/ramda/es/eqProps.js
@@ -0,0 +1,28 @@
+import _curry3 from './internal/_curry3.js';
+import equals from './equals.js';
+
+/**
+ * Reports whether two objects have the same value, in [`R.equals`](#equals)
+ * terms, for the specified property. Useful as a curried predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig k -> {k: v} -> {k: v} -> Boolean
+ * @param {String} prop The name of the property to compare
+ * @param {Object} obj1
+ * @param {Object} obj2
+ * @return {Boolean}
+ *
+ * @example
+ *
+ *      const o1 = { a: 1, b: 2, c: 3, d: 4 };
+ *      const o2 = { a: 10, b: 20, c: 3, d: 40 };
+ *      R.eqProps('a', o1, o2); //=> false
+ *      R.eqProps('c', o1, o2); //=> true
+ */
+var eqProps = /*#__PURE__*/_curry3(function eqProps(prop, obj1, obj2) {
+  return equals(obj1[prop], obj2[prop]);
+});
+export default eqProps;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/equals.js b/server/node_modules/ramda/es/equals.js
new file mode 100644
index 0000000000000000000000000000000000000000..05099ca128b3c10fb89438002e317be6d550789b
--- /dev/null
+++ b/server/node_modules/ramda/es/equals.js
@@ -0,0 +1,32 @@
+import _curry2 from './internal/_curry2.js';
+import _equals from './internal/_equals.js';
+
+/**
+ * Returns `true` if its arguments are equivalent, `false` otherwise. Handles
+ * cyclical data structures.
+ *
+ * Dispatches symmetrically to the `equals` methods of both arguments, if
+ * present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category Relation
+ * @sig a -> b -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @example
+ *
+ *      R.equals(1, 1); //=> true
+ *      R.equals(1, '1'); //=> false
+ *      R.equals([1, 2, 3], [1, 2, 3]); //=> true
+ *
+ *      const a = {}; a.v = a;
+ *      const b = {}; b.v = b;
+ *      R.equals(a, b); //=> true
+ */
+var equals = /*#__PURE__*/_curry2(function equals(a, b) {
+  return _equals(a, b, [], []);
+});
+export default equals;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/evolve.js b/server/node_modules/ramda/es/evolve.js
new file mode 100644
index 0000000000000000000000000000000000000000..eac9f972e193f1e6619da6ed748e24c6cbe554b8
--- /dev/null
+++ b/server/node_modules/ramda/es/evolve.js
@@ -0,0 +1,40 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Creates a new object by recursively evolving a shallow copy of `object`,
+ * according to the `transformation` functions. All non-primitive properties
+ * are copied by reference.
+ *
+ * A `transformation` function will not be invoked if its corresponding key
+ * does not exist in the evolved object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig {k: (v -> v)} -> {k: v} -> {k: v}
+ * @param {Object} transformations The object specifying transformation functions to apply
+ *        to the object.
+ * @param {Object} object The object to be transformed.
+ * @return {Object} The transformed object.
+ * @example
+ *
+ *      const tomato = {firstName: '  Tomato ', data: {elapsed: 100, remaining: 1400}, id:123};
+ *      const transformations = {
+ *        firstName: R.trim,
+ *        lastName: R.trim, // Will not get invoked.
+ *        data: {elapsed: R.add(1), remaining: R.add(-1)}
+ *      };
+ *      R.evolve(transformations, tomato); //=> {firstName: 'Tomato', data: {elapsed: 101, remaining: 1399}, id:123}
+ */
+var evolve = /*#__PURE__*/_curry2(function evolve(transformations, object) {
+  var result = object instanceof Array ? [] : {};
+  var transformation, key, type;
+  for (key in object) {
+    transformation = transformations[key];
+    type = typeof transformation;
+    result[key] = type === 'function' ? transformation(object[key]) : transformation && type === 'object' ? evolve(transformation, object[key]) : object[key];
+  }
+  return result;
+});
+export default evolve;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/filter.js b/server/node_modules/ramda/es/filter.js
new file mode 100644
index 0000000000000000000000000000000000000000..2c00d09ce1e479892f932ea9ca77f27d95c60bf3
--- /dev/null
+++ b/server/node_modules/ramda/es/filter.js
@@ -0,0 +1,46 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _filter from './internal/_filter.js';
+import _isObject from './internal/_isObject.js';
+import _reduce from './internal/_reduce.js';
+import _xfilter from './internal/_xfilter.js';
+import keys from './keys.js';
+
+/**
+ * Takes a predicate and a `Filterable`, and returns a new filterable of the
+ * same type containing the members of the given filterable which satisfy the
+ * given predicate. Filterable objects include plain objects or any object
+ * that has a filter method such as `Array`.
+ *
+ * Dispatches to the `filter` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Filterable f => (a -> Boolean) -> f a -> f a
+ * @param {Function} pred
+ * @param {Array} filterable
+ * @return {Array} Filterable
+ * @see R.reject, R.transduce, R.addIndex
+ * @example
+ *
+ *      const isEven = n => n % 2 === 0;
+ *
+ *      R.filter(isEven, [1, 2, 3, 4]); //=> [2, 4]
+ *
+ *      R.filter(isEven, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4}
+ */
+var filter = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['filter'], _xfilter, function (pred, filterable) {
+  return _isObject(filterable) ? _reduce(function (acc, key) {
+    if (pred(filterable[key])) {
+      acc[key] = filterable[key];
+    }
+    return acc;
+  }, {}, keys(filterable)) :
+  // else
+  _filter(pred, filterable);
+}));
+export default filter;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/find.js b/server/node_modules/ramda/es/find.js
new file mode 100644
index 0000000000000000000000000000000000000000..a7733d688ad0963df819fc0c5a340b40b168e554
--- /dev/null
+++ b/server/node_modules/ramda/es/find.js
@@ -0,0 +1,39 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xfind from './internal/_xfind.js';
+
+/**
+ * Returns the first element of the list which matches the predicate, or
+ * `undefined` if no element matches.
+ *
+ * Dispatches to the `find` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> a | undefined
+ * @param {Function} fn The predicate function used to determine if the element is the
+ *        desired one.
+ * @param {Array} list The array to consider.
+ * @return {Object} The element found, or `undefined`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1}, {a: 2}, {a: 3}];
+ *      R.find(R.propEq('a', 2))(xs); //=> {a: 2}
+ *      R.find(R.propEq('a', 4))(xs); //=> undefined
+ */
+var find = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['find'], _xfind, function find(fn, list) {
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    if (fn(list[idx])) {
+      return list[idx];
+    }
+    idx += 1;
+  }
+}));
+export default find;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/findIndex.js b/server/node_modules/ramda/es/findIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..d222fab1aaa90b7c5a058cfa6955b1daebb12959
--- /dev/null
+++ b/server/node_modules/ramda/es/findIndex.js
@@ -0,0 +1,38 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xfindIndex from './internal/_xfindIndex.js';
+
+/**
+ * Returns the index of the first element of the list which matches the
+ * predicate, or `-1` if no element matches.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Number
+ * @param {Function} fn The predicate function used to determine if the element is the
+ * desired one.
+ * @param {Array} list The array to consider.
+ * @return {Number} The index of the element found, or `-1`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1}, {a: 2}, {a: 3}];
+ *      R.findIndex(R.propEq('a', 2))(xs); //=> 1
+ *      R.findIndex(R.propEq('a', 4))(xs); //=> -1
+ */
+var findIndex = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xfindIndex, function findIndex(fn, list) {
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    if (fn(list[idx])) {
+      return idx;
+    }
+    idx += 1;
+  }
+  return -1;
+}));
+export default findIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/findLast.js b/server/node_modules/ramda/es/findLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..a5c4f404c03df882a7b201684622be37730188f8
--- /dev/null
+++ b/server/node_modules/ramda/es/findLast.js
@@ -0,0 +1,36 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xfindLast from './internal/_xfindLast.js';
+
+/**
+ * Returns the last element of the list which matches the predicate, or
+ * `undefined` if no element matches.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> a | undefined
+ * @param {Function} fn The predicate function used to determine if the element is the
+ * desired one.
+ * @param {Array} list The array to consider.
+ * @return {Object} The element found, or `undefined`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1, b: 0}, {a:1, b: 1}];
+ *      R.findLast(R.propEq('a', 1))(xs); //=> {a: 1, b: 1}
+ *      R.findLast(R.propEq('a', 4))(xs); //=> undefined
+ */
+var findLast = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xfindLast, function findLast(fn, list) {
+  var idx = list.length - 1;
+  while (idx >= 0) {
+    if (fn(list[idx])) {
+      return list[idx];
+    }
+    idx -= 1;
+  }
+}));
+export default findLast;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/findLastIndex.js b/server/node_modules/ramda/es/findLastIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..6615fd7468bf2388b5acde571411004f13fc369f
--- /dev/null
+++ b/server/node_modules/ramda/es/findLastIndex.js
@@ -0,0 +1,37 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xfindLastIndex from './internal/_xfindLastIndex.js';
+
+/**
+ * Returns the index of the last element of the list which matches the
+ * predicate, or `-1` if no element matches.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Number
+ * @param {Function} fn The predicate function used to determine if the element is the
+ * desired one.
+ * @param {Array} list The array to consider.
+ * @return {Number} The index of the element found, or `-1`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1, b: 0}, {a:1, b: 1}];
+ *      R.findLastIndex(R.propEq('a', 1))(xs); //=> 1
+ *      R.findLastIndex(R.propEq('a', 4))(xs); //=> -1
+ */
+var findLastIndex = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xfindLastIndex, function findLastIndex(fn, list) {
+  var idx = list.length - 1;
+  while (idx >= 0) {
+    if (fn(list[idx])) {
+      return idx;
+    }
+    idx -= 1;
+  }
+  return -1;
+}));
+export default findLastIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/flatten.js b/server/node_modules/ramda/es/flatten.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb517d847f2f8e105b8b5e3ea0c02cc91a789d39
--- /dev/null
+++ b/server/node_modules/ramda/es/flatten.js
@@ -0,0 +1,22 @@
+import _curry1 from './internal/_curry1.js';
+import _makeFlat from './internal/_makeFlat.js';
+
+/**
+ * Returns a new list by pulling every item out of it (and all its sub-arrays)
+ * and putting them in a new array, depth-first.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [b]
+ * @param {Array} list The array to consider.
+ * @return {Array} The flattened list.
+ * @see R.unnest
+ * @example
+ *
+ *      R.flatten([1, 2, [3, 4], 5, [6, [7, 8, [9, [10, 11], 12]]]]);
+ *      //=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+ */
+var flatten = /*#__PURE__*/_curry1( /*#__PURE__*/_makeFlat(true));
+export default flatten;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/flip.js b/server/node_modules/ramda/es/flip.js
new file mode 100644
index 0000000000000000000000000000000000000000..0fe2c8e49f0a74d7c46a54d5e19e6ecbe4430c35
--- /dev/null
+++ b/server/node_modules/ramda/es/flip.js
@@ -0,0 +1,32 @@
+import _curry1 from './internal/_curry1.js';
+import curryN from './curryN.js';
+
+/**
+ * Returns a new function much like the supplied one, except that the first two
+ * arguments' order is reversed.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((a, b, c, ...) -> z) -> (b -> a -> c -> ... -> z)
+ * @param {Function} fn The function to invoke with its first two parameters reversed.
+ * @return {*} The result of invoking `fn` with its first two parameters' order reversed.
+ * @example
+ *
+ *      const mergeThree = (a, b, c) => [].concat(a, b, c);
+ *
+ *      mergeThree(1, 2, 3); //=> [1, 2, 3]
+ *
+ *      R.flip(mergeThree)(1, 2, 3); //=> [2, 1, 3]
+ * @symb R.flip(f)(a, b, c) = f(b, a, c)
+ */
+var flip = /*#__PURE__*/_curry1(function flip(fn) {
+  return curryN(fn.length, function (a, b) {
+    var args = Array.prototype.slice.call(arguments, 0);
+    args[0] = b;
+    args[1] = a;
+    return fn.apply(this, args);
+  });
+});
+export default flip;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/forEach.js b/server/node_modules/ramda/es/forEach.js
new file mode 100644
index 0000000000000000000000000000000000000000..c63f4398fd8040a6b3026ddb918883b6cd925877
--- /dev/null
+++ b/server/node_modules/ramda/es/forEach.js
@@ -0,0 +1,47 @@
+import _checkForMethod from './internal/_checkForMethod.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Iterate over an input `list`, calling a provided function `fn` for each
+ * element in the list.
+ *
+ * `fn` receives one argument: *(value)*.
+ *
+ * Note: `R.forEach` does not skip deleted or unassigned indices (sparse
+ * arrays), unlike the native `Array.prototype.forEach` method. For more
+ * details on this behavior, see:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description
+ *
+ * Also note that, unlike `Array.prototype.forEach`, Ramda's `forEach` returns
+ * the original array. In some libraries this function is named `each`.
+ *
+ * Dispatches to the `forEach` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> *) -> [a] -> [a]
+ * @param {Function} fn The function to invoke. Receives one argument, `value`.
+ * @param {Array} list The list to iterate over.
+ * @return {Array} The original list.
+ * @see R.addIndex
+ * @example
+ *
+ *      const printXPlusFive = x => console.log(x + 5);
+ *      R.forEach(printXPlusFive, [1, 2, 3]); //=> [1, 2, 3]
+ *      // logs 6
+ *      // logs 7
+ *      // logs 8
+ * @symb R.forEach(f, [a, b, c]) = [a, b, c]
+ */
+var forEach = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('forEach', function forEach(fn, list) {
+  var len = list.length;
+  var idx = 0;
+  while (idx < len) {
+    fn(list[idx]);
+    idx += 1;
+  }
+  return list;
+}));
+export default forEach;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/forEachObjIndexed.js b/server/node_modules/ramda/es/forEachObjIndexed.js
new file mode 100644
index 0000000000000000000000000000000000000000..fc916026b46b27842c5c40de3f593c3e9b496e2e
--- /dev/null
+++ b/server/node_modules/ramda/es/forEachObjIndexed.js
@@ -0,0 +1,36 @@
+import _curry2 from './internal/_curry2.js';
+import keys from './keys.js';
+
+/**
+ * Iterate over an input `object`, calling a provided function `fn` for each
+ * key and value in the object.
+ *
+ * `fn` receives three argument: *(value, key, obj)*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Object
+ * @sig ((a, String, StrMap a) -> Any) -> StrMap a -> StrMap a
+ * @param {Function} fn The function to invoke. Receives three argument, `value`, `key`, `obj`.
+ * @param {Object} obj The object to iterate over.
+ * @return {Object} The original object.
+ * @example
+ *
+ *      const printKeyConcatValue = (value, key) => console.log(key + ':' + value);
+ *      R.forEachObjIndexed(printKeyConcatValue, {x: 1, y: 2}); //=> {x: 1, y: 2}
+ *      // logs x:1
+ *      // logs y:2
+ * @symb R.forEachObjIndexed(f, {x: a, y: b}) = {x: a, y: b}
+ */
+var forEachObjIndexed = /*#__PURE__*/_curry2(function forEachObjIndexed(fn, obj) {
+  var keyList = keys(obj);
+  var idx = 0;
+  while (idx < keyList.length) {
+    var key = keyList[idx];
+    fn(obj[key], key, obj);
+    idx += 1;
+  }
+  return obj;
+});
+export default forEachObjIndexed;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/fromPairs.js b/server/node_modules/ramda/es/fromPairs.js
new file mode 100644
index 0000000000000000000000000000000000000000..623aa8dd2affeef271a06a34219794f9f3a34e0b
--- /dev/null
+++ b/server/node_modules/ramda/es/fromPairs.js
@@ -0,0 +1,28 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Creates a new object from a list key-value pairs. If a key appears in
+ * multiple pairs, the rightmost pair is included in the object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig [[k,v]] -> {k: v}
+ * @param {Array} pairs An array of two-element arrays that will be the keys and values of the output object.
+ * @return {Object} The object made by pairing up `keys` and `values`.
+ * @see R.toPairs, R.pair
+ * @example
+ *
+ *      R.fromPairs([['a', 1], ['b', 2], ['c', 3]]); //=> {a: 1, b: 2, c: 3}
+ */
+var fromPairs = /*#__PURE__*/_curry1(function fromPairs(pairs) {
+  var result = {};
+  var idx = 0;
+  while (idx < pairs.length) {
+    result[pairs[idx][0]] = pairs[idx][1];
+    idx += 1;
+  }
+  return result;
+});
+export default fromPairs;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/groupBy.js b/server/node_modules/ramda/es/groupBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..c8fed75dc347ba183b88f8ed6d43fe869531994b
--- /dev/null
+++ b/server/node_modules/ramda/es/groupBy.js
@@ -0,0 +1,52 @@
+import _checkForMethod from './internal/_checkForMethod.js';
+import _curry2 from './internal/_curry2.js';
+import reduceBy from './reduceBy.js';
+
+/**
+ * Splits a list into sub-lists stored in an object, based on the result of
+ * calling a String-returning function on each element, and grouping the
+ * results according to values returned.
+ *
+ * Dispatches to the `groupBy` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> String) -> [a] -> {String: [a]}
+ * @param {Function} fn Function :: a -> String
+ * @param {Array} list The array to group
+ * @return {Object} An object with the output of `fn` for keys, mapped to arrays of elements
+ *         that produced that key when passed to `fn`.
+ * @see R.reduceBy, R.transduce
+ * @example
+ *
+ *      const byGrade = R.groupBy(function(student) {
+ *        const score = student.score;
+ *        return score < 65 ? 'F' :
+ *               score < 70 ? 'D' :
+ *               score < 80 ? 'C' :
+ *               score < 90 ? 'B' : 'A';
+ *      });
+ *      const students = [{name: 'Abby', score: 84},
+ *                      {name: 'Eddy', score: 58},
+ *                      // ...
+ *                      {name: 'Jack', score: 69}];
+ *      byGrade(students);
+ *      // {
+ *      //   'A': [{name: 'Dianne', score: 99}],
+ *      //   'B': [{name: 'Abby', score: 84}]
+ *      //   // ...,
+ *      //   'F': [{name: 'Eddy', score: 58}]
+ *      // }
+ */
+var groupBy = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('groupBy', /*#__PURE__*/reduceBy(function (acc, item) {
+  if (acc == null) {
+    acc = [];
+  }
+  acc.push(item);
+  return acc;
+}, null)));
+export default groupBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/groupWith.js b/server/node_modules/ramda/es/groupWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..f1899c84e2491eb12f910ac2d5285da34b771874
--- /dev/null
+++ b/server/node_modules/ramda/es/groupWith.js
@@ -0,0 +1,47 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Takes a list and returns a list of lists where each sublist's elements are
+ * all satisfied pairwise comparison according to the provided function.
+ * Only adjacent elements are passed to the comparison function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.21.0
+ * @category List
+ * @sig ((a, a) → Boolean) → [a] → [[a]]
+ * @param {Function} fn Function for determining whether two given (adjacent)
+ *        elements should be in the same group
+ * @param {Array} list The array to group. Also accepts a string, which will be
+ *        treated as a list of characters.
+ * @return {List} A list that contains sublists of elements,
+ *         whose concatenations are equal to the original list.
+ * @example
+ *
+ * R.groupWith(R.equals, [0, 1, 1, 2, 3, 5, 8, 13, 21])
+ * //=> [[0], [1, 1], [2], [3], [5], [8], [13], [21]]
+ *
+ * R.groupWith((a, b) => a + 1 === b, [0, 1, 1, 2, 3, 5, 8, 13, 21])
+ * //=> [[0, 1], [1, 2, 3], [5], [8], [13], [21]]
+ *
+ * R.groupWith((a, b) => a % 2 === b % 2, [0, 1, 1, 2, 3, 5, 8, 13, 21])
+ * //=> [[0], [1, 1], [2], [3, 5], [8], [13, 21]]
+ *
+ * R.groupWith(R.eqBy(isVowel), 'aestiou')
+ * //=> ['ae', 'st', 'iou']
+ */
+var groupWith = /*#__PURE__*/_curry2(function (fn, list) {
+  var res = [];
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    var nextidx = idx + 1;
+    while (nextidx < len && fn(list[nextidx - 1], list[nextidx])) {
+      nextidx += 1;
+    }
+    res.push(list.slice(idx, nextidx));
+    idx = nextidx;
+  }
+  return res;
+});
+export default groupWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/gt.js b/server/node_modules/ramda/es/gt.js
new file mode 100644
index 0000000000000000000000000000000000000000..e6262f8bc005cadeff6bb60ecc4e8c7ea110fb5a
--- /dev/null
+++ b/server/node_modules/ramda/es/gt.js
@@ -0,0 +1,27 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns `true` if the first argument is greater than the second; `false`
+ * otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @see R.lt
+ * @example
+ *
+ *      R.gt(2, 1); //=> true
+ *      R.gt(2, 2); //=> false
+ *      R.gt(2, 3); //=> false
+ *      R.gt('a', 'z'); //=> false
+ *      R.gt('z', 'a'); //=> true
+ */
+var gt = /*#__PURE__*/_curry2(function gt(a, b) {
+  return a > b;
+});
+export default gt;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/gte.js b/server/node_modules/ramda/es/gte.js
new file mode 100644
index 0000000000000000000000000000000000000000..932649f3cd3454e7d214b1ea7b212537b6a82899
--- /dev/null
+++ b/server/node_modules/ramda/es/gte.js
@@ -0,0 +1,27 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns `true` if the first argument is greater than or equal to the second;
+ * `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {Number} a
+ * @param {Number} b
+ * @return {Boolean}
+ * @see R.lte
+ * @example
+ *
+ *      R.gte(2, 1); //=> true
+ *      R.gte(2, 2); //=> true
+ *      R.gte(2, 3); //=> false
+ *      R.gte('a', 'z'); //=> false
+ *      R.gte('z', 'a'); //=> true
+ */
+var gte = /*#__PURE__*/_curry2(function gte(a, b) {
+  return a >= b;
+});
+export default gte;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/has.js b/server/node_modules/ramda/es/has.js
new file mode 100644
index 0000000000000000000000000000000000000000..a172c3a16caf5b5dcf8f1b3fe3ea7e0d84bf2fb9
--- /dev/null
+++ b/server/node_modules/ramda/es/has.js
@@ -0,0 +1,31 @@
+import _curry2 from './internal/_curry2.js';
+import hasPath from './hasPath.js';
+
+/**
+ * Returns whether or not an object has an own property with the specified name
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Object
+ * @sig s -> {s: x} -> Boolean
+ * @param {String} prop The name of the property to check for.
+ * @param {Object} obj The object to query.
+ * @return {Boolean} Whether the property exists.
+ * @example
+ *
+ *      const hasName = R.has('name');
+ *      hasName({name: 'alice'});   //=> true
+ *      hasName({name: 'bob'});     //=> true
+ *      hasName({});                //=> false
+ *
+ *      const point = {x: 0, y: 0};
+ *      const pointHas = R.has(R.__, point);
+ *      pointHas('x');  //=> true
+ *      pointHas('y');  //=> true
+ *      pointHas('z');  //=> false
+ */
+var has = /*#__PURE__*/_curry2(function has(prop, obj) {
+  return hasPath([prop], obj);
+});
+export default has;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/hasIn.js b/server/node_modules/ramda/es/hasIn.js
new file mode 100644
index 0000000000000000000000000000000000000000..d18fe54a6085f6b58477022de3bfa3a064cf6b7b
--- /dev/null
+++ b/server/node_modules/ramda/es/hasIn.js
@@ -0,0 +1,32 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns whether or not an object or its prototype chain has a property with
+ * the specified name
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Object
+ * @sig s -> {s: x} -> Boolean
+ * @param {String} prop The name of the property to check for.
+ * @param {Object} obj The object to query.
+ * @return {Boolean} Whether the property exists.
+ * @example
+ *
+ *      function Rectangle(width, height) {
+ *        this.width = width;
+ *        this.height = height;
+ *      }
+ *      Rectangle.prototype.area = function() {
+ *        return this.width * this.height;
+ *      };
+ *
+ *      const square = new Rectangle(2, 2);
+ *      R.hasIn('width', square);  //=> true
+ *      R.hasIn('area', square);  //=> true
+ */
+var hasIn = /*#__PURE__*/_curry2(function hasIn(prop, obj) {
+  return prop in obj;
+});
+export default hasIn;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/hasPath.js b/server/node_modules/ramda/es/hasPath.js
new file mode 100644
index 0000000000000000000000000000000000000000..9ef68623fa6ab478dd8d4984d3faf9854454f26c
--- /dev/null
+++ b/server/node_modules/ramda/es/hasPath.js
@@ -0,0 +1,41 @@
+import _curry2 from './internal/_curry2.js';
+import _has from './internal/_has.js';
+
+/**
+ * Returns whether or not a path exists in an object. Only the object's
+ * own properties are checked.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.26.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> {a} -> Boolean
+ * @param {Array} path The path to use.
+ * @param {Object} obj The object to check the path in.
+ * @return {Boolean} Whether the path exists.
+ * @see R.has
+ * @example
+ *
+ *      R.hasPath(['a', 'b'], {a: {b: 2}});         // => true
+ *      R.hasPath(['a', 'b'], {a: {b: undefined}}); // => true
+ *      R.hasPath(['a', 'b'], {a: {c: 2}});         // => false
+ *      R.hasPath(['a', 'b'], {});                  // => false
+ */
+var hasPath = /*#__PURE__*/_curry2(function hasPath(_path, obj) {
+  if (_path.length === 0) {
+    return false;
+  }
+  var val = obj;
+  var idx = 0;
+  while (idx < _path.length) {
+    if (_has(_path[idx], val)) {
+      val = val[_path[idx]];
+      idx += 1;
+    } else {
+      return false;
+    }
+  }
+  return true;
+});
+export default hasPath;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/head.js b/server/node_modules/ramda/es/head.js
new file mode 100644
index 0000000000000000000000000000000000000000..7ec4268f48acabd78662b225ab0be8025b4348cf
--- /dev/null
+++ b/server/node_modules/ramda/es/head.js
@@ -0,0 +1,25 @@
+import nth from './nth.js';
+
+/**
+ * Returns the first element of the given list or string. In some libraries
+ * this function is named `first`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> a | Undefined
+ * @sig String -> String
+ * @param {Array|String} list
+ * @return {*}
+ * @see R.tail, R.init, R.last
+ * @example
+ *
+ *      R.head(['fi', 'fo', 'fum']); //=> 'fi'
+ *      R.head([]); //=> undefined
+ *
+ *      R.head('abc'); //=> 'a'
+ *      R.head(''); //=> ''
+ */
+var head = /*#__PURE__*/nth(0);
+export default head;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/identical.js b/server/node_modules/ramda/es/identical.js
new file mode 100644
index 0000000000000000000000000000000000000000..f427c6b358f627d07bed5ce9f1439816b08fd564
--- /dev/null
+++ b/server/node_modules/ramda/es/identical.js
@@ -0,0 +1,30 @@
+import _objectIs from './internal/_objectIs.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns true if its arguments are identical, false otherwise. Values are
+ * identical if they reference the same memory. `NaN` is identical to `NaN`;
+ * `0` and `-0` are not identical.
+ *
+ * Note this is merely a curried version of ES6 `Object.is`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category Relation
+ * @sig a -> a -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @example
+ *
+ *      const o = {};
+ *      R.identical(o, o); //=> true
+ *      R.identical(1, 1); //=> true
+ *      R.identical(1, '1'); //=> false
+ *      R.identical([], []); //=> false
+ *      R.identical(0, -0); //=> false
+ *      R.identical(NaN, NaN); //=> true
+ */
+var identical = /*#__PURE__*/_curry2(_objectIs);
+export default identical;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/identity.js b/server/node_modules/ramda/es/identity.js
new file mode 100644
index 0000000000000000000000000000000000000000..93720acf34ab6c0ea5e9781282907a717508fbd3
--- /dev/null
+++ b/server/node_modules/ramda/es/identity.js
@@ -0,0 +1,24 @@
+import _curry1 from './internal/_curry1.js';
+import _identity from './internal/_identity.js';
+
+/**
+ * A function that does nothing but return the parameter supplied to it. Good
+ * as a default or placeholder function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig a -> a
+ * @param {*} x The value to return.
+ * @return {*} The input value, `x`.
+ * @example
+ *
+ *      R.identity(1); //=> 1
+ *
+ *      const obj = {};
+ *      R.identity(obj) === obj; //=> true
+ * @symb R.identity(a) = a
+ */
+var identity = /*#__PURE__*/_curry1(_identity);
+export default identity;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/ifElse.js b/server/node_modules/ramda/es/ifElse.js
new file mode 100644
index 0000000000000000000000000000000000000000..9b0fa87472f875c373a70ff5fd2d4f290cf54fc8
--- /dev/null
+++ b/server/node_modules/ramda/es/ifElse.js
@@ -0,0 +1,34 @@
+import _curry3 from './internal/_curry3.js';
+import curryN from './curryN.js';
+
+/**
+ * Creates a function that will process either the `onTrue` or the `onFalse`
+ * function depending upon the result of the `condition` predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Logic
+ * @sig (*... -> Boolean) -> (*... -> *) -> (*... -> *) -> (*... -> *)
+ * @param {Function} condition A predicate function
+ * @param {Function} onTrue A function to invoke when the `condition` evaluates to a truthy value.
+ * @param {Function} onFalse A function to invoke when the `condition` evaluates to a falsy value.
+ * @return {Function} A new function that will process either the `onTrue` or the `onFalse`
+ *                    function depending upon the result of the `condition` predicate.
+ * @see R.unless, R.when, R.cond
+ * @example
+ *
+ *      const incCount = R.ifElse(
+ *        R.has('count'),
+ *        R.over(R.lensProp('count'), R.inc),
+ *        R.assoc('count', 1)
+ *      );
+ *      incCount({});           //=> { count: 1 }
+ *      incCount({ count: 1 }); //=> { count: 2 }
+ */
+var ifElse = /*#__PURE__*/_curry3(function ifElse(condition, onTrue, onFalse) {
+  return curryN(Math.max(condition.length, onTrue.length, onFalse.length), function _ifElse() {
+    return condition.apply(this, arguments) ? onTrue.apply(this, arguments) : onFalse.apply(this, arguments);
+  });
+});
+export default ifElse;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/inc.js b/server/node_modules/ramda/es/inc.js
new file mode 100644
index 0000000000000000000000000000000000000000..030542e99541e282110ada6979f854cd49371f9e
--- /dev/null
+++ b/server/node_modules/ramda/es/inc.js
@@ -0,0 +1,19 @@
+import add from './add.js';
+
+/**
+ * Increments its argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Math
+ * @sig Number -> Number
+ * @param {Number} n
+ * @return {Number} n + 1
+ * @see R.dec
+ * @example
+ *
+ *      R.inc(42); //=> 43
+ */
+var inc = /*#__PURE__*/add(1);
+export default inc;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/includes.js b/server/node_modules/ramda/es/includes.js
new file mode 100644
index 0000000000000000000000000000000000000000..7d3adb1be0875d684d2fa0daa8b2feb2d3ad651e
--- /dev/null
+++ b/server/node_modules/ramda/es/includes.js
@@ -0,0 +1,27 @@
+import _includes from './internal/_includes.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns `true` if the specified value is equal, in [`R.equals`](#equals)
+ * terms, to at least one element of the given list; `false` otherwise.
+ * Works also with strings.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Boolean
+ * @param {Object} a The item to compare against.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if an equivalent item is in the list, `false` otherwise.
+ * @see R.any
+ * @example
+ *
+ *      R.includes(3, [1, 2, 3]); //=> true
+ *      R.includes(4, [1, 2, 3]); //=> false
+ *      R.includes({ name: 'Fred' }, [{ name: 'Fred' }]); //=> true
+ *      R.includes([42], [[42]]); //=> true
+ *      R.includes('ba', 'banana'); //=>true
+ */
+var includes = /*#__PURE__*/_curry2(_includes);
+export default includes;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/index.js b/server/node_modules/ramda/es/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..76fcecc601789e646f775f2d5cab545cd791e039
--- /dev/null
+++ b/server/node_modules/ramda/es/index.js
@@ -0,0 +1,255 @@
+export { default as F } from './F.js';
+export { default as T } from './T.js';
+export { default as __ } from './__.js';
+export { default as add } from './add.js';
+export { default as addIndex } from './addIndex.js';
+export { default as adjust } from './adjust.js';
+export { default as all } from './all.js';
+export { default as allPass } from './allPass.js';
+export { default as always } from './always.js';
+export { default as and } from './and.js';
+export { default as any } from './any.js';
+export { default as anyPass } from './anyPass.js';
+export { default as ap } from './ap.js';
+export { default as aperture } from './aperture.js';
+export { default as append } from './append.js';
+export { default as apply } from './apply.js';
+export { default as applySpec } from './applySpec.js';
+export { default as applyTo } from './applyTo.js';
+export { default as ascend } from './ascend.js';
+export { default as assoc } from './assoc.js';
+export { default as assocPath } from './assocPath.js';
+export { default as binary } from './binary.js';
+export { default as bind } from './bind.js';
+export { default as both } from './both.js';
+export { default as call } from './call.js';
+export { default as chain } from './chain.js';
+export { default as clamp } from './clamp.js';
+export { default as clone } from './clone.js';
+export { default as comparator } from './comparator.js';
+export { default as complement } from './complement.js';
+export { default as compose } from './compose.js';
+export { default as composeK } from './composeK.js';
+export { default as composeP } from './composeP.js';
+export { default as composeWith } from './composeWith.js';
+export { default as concat } from './concat.js';
+export { default as cond } from './cond.js';
+export { default as construct } from './construct.js';
+export { default as constructN } from './constructN.js';
+export { default as contains } from './contains.js';
+export { default as converge } from './converge.js';
+export { default as countBy } from './countBy.js';
+export { default as curry } from './curry.js';
+export { default as curryN } from './curryN.js';
+export { default as dec } from './dec.js';
+export { default as defaultTo } from './defaultTo.js';
+export { default as descend } from './descend.js';
+export { default as difference } from './difference.js';
+export { default as differenceWith } from './differenceWith.js';
+export { default as dissoc } from './dissoc.js';
+export { default as dissocPath } from './dissocPath.js';
+export { default as divide } from './divide.js';
+export { default as drop } from './drop.js';
+export { default as dropLast } from './dropLast.js';
+export { default as dropLastWhile } from './dropLastWhile.js';
+export { default as dropRepeats } from './dropRepeats.js';
+export { default as dropRepeatsWith } from './dropRepeatsWith.js';
+export { default as dropWhile } from './dropWhile.js';
+export { default as either } from './either.js';
+export { default as empty } from './empty.js';
+export { default as endsWith } from './endsWith.js';
+export { default as eqBy } from './eqBy.js';
+export { default as eqProps } from './eqProps.js';
+export { default as equals } from './equals.js';
+export { default as evolve } from './evolve.js';
+export { default as filter } from './filter.js';
+export { default as find } from './find.js';
+export { default as findIndex } from './findIndex.js';
+export { default as findLast } from './findLast.js';
+export { default as findLastIndex } from './findLastIndex.js';
+export { default as flatten } from './flatten.js';
+export { default as flip } from './flip.js';
+export { default as forEach } from './forEach.js';
+export { default as forEachObjIndexed } from './forEachObjIndexed.js';
+export { default as fromPairs } from './fromPairs.js';
+export { default as groupBy } from './groupBy.js';
+export { default as groupWith } from './groupWith.js';
+export { default as gt } from './gt.js';
+export { default as gte } from './gte.js';
+export { default as has } from './has.js';
+export { default as hasIn } from './hasIn.js';
+export { default as hasPath } from './hasPath.js';
+export { default as head } from './head.js';
+export { default as identical } from './identical.js';
+export { default as identity } from './identity.js';
+export { default as ifElse } from './ifElse.js';
+export { default as inc } from './inc.js';
+export { default as includes } from './includes.js';
+export { default as indexBy } from './indexBy.js';
+export { default as indexOf } from './indexOf.js';
+export { default as init } from './init.js';
+export { default as innerJoin } from './innerJoin.js';
+export { default as insert } from './insert.js';
+export { default as insertAll } from './insertAll.js';
+export { default as intersection } from './intersection.js';
+export { default as intersperse } from './intersperse.js';
+export { default as into } from './into.js';
+export { default as invert } from './invert.js';
+export { default as invertObj } from './invertObj.js';
+export { default as invoker } from './invoker.js';
+export { default as is } from './is.js';
+export { default as isEmpty } from './isEmpty.js';
+export { default as isNil } from './isNil.js';
+export { default as join } from './join.js';
+export { default as juxt } from './juxt.js';
+export { default as keys } from './keys.js';
+export { default as keysIn } from './keysIn.js';
+export { default as last } from './last.js';
+export { default as lastIndexOf } from './lastIndexOf.js';
+export { default as length } from './length.js';
+export { default as lens } from './lens.js';
+export { default as lensIndex } from './lensIndex.js';
+export { default as lensPath } from './lensPath.js';
+export { default as lensProp } from './lensProp.js';
+export { default as lift } from './lift.js';
+export { default as liftN } from './liftN.js';
+export { default as lt } from './lt.js';
+export { default as lte } from './lte.js';
+export { default as map } from './map.js';
+export { default as mapAccum } from './mapAccum.js';
+export { default as mapAccumRight } from './mapAccumRight.js';
+export { default as mapObjIndexed } from './mapObjIndexed.js';
+export { default as match } from './match.js';
+export { default as mathMod } from './mathMod.js';
+export { default as max } from './max.js';
+export { default as maxBy } from './maxBy.js';
+export { default as mean } from './mean.js';
+export { default as median } from './median.js';
+export { default as memoizeWith } from './memoizeWith.js';
+export { default as merge } from './merge.js';
+export { default as mergeAll } from './mergeAll.js';
+export { default as mergeDeepLeft } from './mergeDeepLeft.js';
+export { default as mergeDeepRight } from './mergeDeepRight.js';
+export { default as mergeDeepWith } from './mergeDeepWith.js';
+export { default as mergeDeepWithKey } from './mergeDeepWithKey.js';
+export { default as mergeLeft } from './mergeLeft.js';
+export { default as mergeRight } from './mergeRight.js';
+export { default as mergeWith } from './mergeWith.js';
+export { default as mergeWithKey } from './mergeWithKey.js';
+export { default as min } from './min.js';
+export { default as minBy } from './minBy.js';
+export { default as modulo } from './modulo.js';
+export { default as move } from './move.js';
+export { default as multiply } from './multiply.js';
+export { default as nAry } from './nAry.js';
+export { default as negate } from './negate.js';
+export { default as none } from './none.js';
+export { default as not } from './not.js';
+export { default as nth } from './nth.js';
+export { default as nthArg } from './nthArg.js';
+export { default as o } from './o.js';
+export { default as objOf } from './objOf.js';
+export { default as of } from './of.js';
+export { default as omit } from './omit.js';
+export { default as once } from './once.js';
+export { default as or } from './or.js';
+export { default as otherwise } from './otherwise.js';
+export { default as over } from './over.js';
+export { default as pair } from './pair.js';
+export { default as partial } from './partial.js';
+export { default as partialRight } from './partialRight.js';
+export { default as partition } from './partition.js';
+export { default as path } from './path.js';
+export { default as pathEq } from './pathEq.js';
+export { default as pathOr } from './pathOr.js';
+export { default as pathSatisfies } from './pathSatisfies.js';
+export { default as pick } from './pick.js';
+export { default as pickAll } from './pickAll.js';
+export { default as pickBy } from './pickBy.js';
+export { default as pipe } from './pipe.js';
+export { default as pipeK } from './pipeK.js';
+export { default as pipeP } from './pipeP.js';
+export { default as pipeWith } from './pipeWith.js';
+export { default as pluck } from './pluck.js';
+export { default as prepend } from './prepend.js';
+export { default as product } from './product.js';
+export { default as project } from './project.js';
+export { default as prop } from './prop.js';
+export { default as propEq } from './propEq.js';
+export { default as propIs } from './propIs.js';
+export { default as propOr } from './propOr.js';
+export { default as propSatisfies } from './propSatisfies.js';
+export { default as props } from './props.js';
+export { default as range } from './range.js';
+export { default as reduce } from './reduce.js';
+export { default as reduceBy } from './reduceBy.js';
+export { default as reduceRight } from './reduceRight.js';
+export { default as reduceWhile } from './reduceWhile.js';
+export { default as reduced } from './reduced.js';
+export { default as reject } from './reject.js';
+export { default as remove } from './remove.js';
+export { default as repeat } from './repeat.js';
+export { default as replace } from './replace.js';
+export { default as reverse } from './reverse.js';
+export { default as scan } from './scan.js';
+export { default as sequence } from './sequence.js';
+export { default as set } from './set.js';
+export { default as slice } from './slice.js';
+export { default as sort } from './sort.js';
+export { default as sortBy } from './sortBy.js';
+export { default as sortWith } from './sortWith.js';
+export { default as split } from './split.js';
+export { default as splitAt } from './splitAt.js';
+export { default as splitEvery } from './splitEvery.js';
+export { default as splitWhen } from './splitWhen.js';
+export { default as startsWith } from './startsWith.js';
+export { default as subtract } from './subtract.js';
+export { default as sum } from './sum.js';
+export { default as symmetricDifference } from './symmetricDifference.js';
+export { default as symmetricDifferenceWith } from './symmetricDifferenceWith.js';
+export { default as tail } from './tail.js';
+export { default as take } from './take.js';
+export { default as takeLast } from './takeLast.js';
+export { default as takeLastWhile } from './takeLastWhile.js';
+export { default as takeWhile } from './takeWhile.js';
+export { default as tap } from './tap.js';
+export { default as test } from './test.js';
+export { default as then } from './then.js';
+export { default as times } from './times.js';
+export { default as toLower } from './toLower.js';
+export { default as toPairs } from './toPairs.js';
+export { default as toPairsIn } from './toPairsIn.js';
+export { default as toString } from './toString.js';
+export { default as toUpper } from './toUpper.js';
+export { default as transduce } from './transduce.js';
+export { default as transpose } from './transpose.js';
+export { default as traverse } from './traverse.js';
+export { default as trim } from './trim.js';
+export { default as tryCatch } from './tryCatch.js';
+export { default as type } from './type.js';
+export { default as unapply } from './unapply.js';
+export { default as unary } from './unary.js';
+export { default as uncurryN } from './uncurryN.js';
+export { default as unfold } from './unfold.js';
+export { default as union } from './union.js';
+export { default as unionWith } from './unionWith.js';
+export { default as uniq } from './uniq.js';
+export { default as uniqBy } from './uniqBy.js';
+export { default as uniqWith } from './uniqWith.js';
+export { default as unless } from './unless.js';
+export { default as unnest } from './unnest.js';
+export { default as until } from './until.js';
+export { default as update } from './update.js';
+export { default as useWith } from './useWith.js';
+export { default as values } from './values.js';
+export { default as valuesIn } from './valuesIn.js';
+export { default as view } from './view.js';
+export { default as when } from './when.js';
+export { default as where } from './where.js';
+export { default as whereEq } from './whereEq.js';
+export { default as without } from './without.js';
+export { default as xprod } from './xprod.js';
+export { default as zip } from './zip.js';
+export { default as zipObj } from './zipObj.js';
+export { default as zipWith } from './zipWith.js';
+export { default as thunkify } from './thunkify.js';
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/indexBy.js b/server/node_modules/ramda/es/indexBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..09c483e8ac18be2fde8644fcf3839cb3018ec15f
--- /dev/null
+++ b/server/node_modules/ramda/es/indexBy.js
@@ -0,0 +1,28 @@
+import reduceBy from './reduceBy.js';
+
+/**
+ * Given a function that generates a key, turns a list of objects into an
+ * object indexing the objects by the given key. Note that if multiple
+ * objects generate the same value for the indexing key only the last value
+ * will be included in the generated object.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (a -> String) -> [{k: v}] -> {k: {k: v}}
+ * @param {Function} fn Function :: a -> String
+ * @param {Array} array The array of objects to index
+ * @return {Object} An object indexing each array element by the given property.
+ * @example
+ *
+ *      const list = [{id: 'xyz', title: 'A'}, {id: 'abc', title: 'B'}];
+ *      R.indexBy(R.prop('id'), list);
+ *      //=> {abc: {id: 'abc', title: 'B'}, xyz: {id: 'xyz', title: 'A'}}
+ */
+var indexBy = /*#__PURE__*/reduceBy(function (acc, elem) {
+  return elem;
+}, null);
+export default indexBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/indexOf.js b/server/node_modules/ramda/es/indexOf.js
new file mode 100644
index 0000000000000000000000000000000000000000..db83865ecb9800ec054c73510eeb55d41f112892
--- /dev/null
+++ b/server/node_modules/ramda/es/indexOf.js
@@ -0,0 +1,27 @@
+import _curry2 from './internal/_curry2.js';
+import _indexOf from './internal/_indexOf.js';
+import _isArray from './internal/_isArray.js';
+
+/**
+ * Returns the position of the first occurrence of an item in an array, or -1
+ * if the item is not included in the array. [`R.equals`](#equals) is used to
+ * determine equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Number
+ * @param {*} target The item to find.
+ * @param {Array} xs The array to search in.
+ * @return {Number} the index of the target, or -1 if the target is not found.
+ * @see R.lastIndexOf
+ * @example
+ *
+ *      R.indexOf(3, [1,2,3,4]); //=> 2
+ *      R.indexOf(10, [1,2,3,4]); //=> -1
+ */
+var indexOf = /*#__PURE__*/_curry2(function indexOf(target, xs) {
+  return typeof xs.indexOf === 'function' && !_isArray(xs) ? xs.indexOf(target) : _indexOf(xs, target, 0);
+});
+export default indexOf;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/init.js b/server/node_modules/ramda/es/init.js
new file mode 100644
index 0000000000000000000000000000000000000000..163a71c4c6679aa847eeaf780e0543c277d85ffe
--- /dev/null
+++ b/server/node_modules/ramda/es/init.js
@@ -0,0 +1,28 @@
+import slice from './slice.js';
+
+/**
+ * Returns all but the last element of the given list or string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category List
+ * @sig [a] -> [a]
+ * @sig String -> String
+ * @param {*} list
+ * @return {*}
+ * @see R.last, R.head, R.tail
+ * @example
+ *
+ *      R.init([1, 2, 3]);  //=> [1, 2]
+ *      R.init([1, 2]);     //=> [1]
+ *      R.init([1]);        //=> []
+ *      R.init([]);         //=> []
+ *
+ *      R.init('abc');  //=> 'ab'
+ *      R.init('ab');   //=> 'a'
+ *      R.init('a');    //=> ''
+ *      R.init('');     //=> ''
+ */
+var init = /*#__PURE__*/slice(0, -1);
+export default init;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/innerJoin.js b/server/node_modules/ramda/es/innerJoin.js
new file mode 100644
index 0000000000000000000000000000000000000000..785788fadf303c27f257bd38c0382f00e6f27ec5
--- /dev/null
+++ b/server/node_modules/ramda/es/innerJoin.js
@@ -0,0 +1,45 @@
+import _includesWith from './internal/_includesWith.js';
+import _curry3 from './internal/_curry3.js';
+import _filter from './internal/_filter.js';
+
+/**
+ * Takes a predicate `pred`, a list `xs`, and a list `ys`, and returns a list
+ * `xs'` comprising each of the elements of `xs` which is equal to one or more
+ * elements of `ys` according to `pred`.
+ *
+ * `pred` must be a binary function expecting an element from each list.
+ *
+ * `xs`, `ys`, and `xs'` are treated as sets, semantically, so ordering should
+ * not be significant, but since `xs'` is ordered the implementation guarantees
+ * that its values are in the same order as they appear in `xs`. Duplicates are
+ * not removed, so `xs'` may contain duplicates if `xs` contains duplicates.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Relation
+ * @sig ((a, b) -> Boolean) -> [a] -> [b] -> [a]
+ * @param {Function} pred
+ * @param {Array} xs
+ * @param {Array} ys
+ * @return {Array}
+ * @see R.intersection
+ * @example
+ *
+ *      R.innerJoin(
+ *        (record, id) => record.id === id,
+ *        [{id: 824, name: 'Richie Furay'},
+ *         {id: 956, name: 'Dewey Martin'},
+ *         {id: 313, name: 'Bruce Palmer'},
+ *         {id: 456, name: 'Stephen Stills'},
+ *         {id: 177, name: 'Neil Young'}],
+ *        [177, 456, 999]
+ *      );
+ *      //=> [{id: 456, name: 'Stephen Stills'}, {id: 177, name: 'Neil Young'}]
+ */
+var innerJoin = /*#__PURE__*/_curry3(function innerJoin(pred, xs, ys) {
+  return _filter(function (x) {
+    return _includesWith(pred, x, ys);
+  }, xs);
+});
+export default innerJoin;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/insert.js b/server/node_modules/ramda/es/insert.js
new file mode 100644
index 0000000000000000000000000000000000000000..066423e74f1ba6bd3150d7693f3ff9a409e296ee
--- /dev/null
+++ b/server/node_modules/ramda/es/insert.js
@@ -0,0 +1,28 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Inserts the supplied element into the list, at the specified `index`. _Note that
+
+ * this is not destructive_: it returns a copy of the list with the changes.
+ * <small>No lists have been harmed in the application of this function.</small>
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.2
+ * @category List
+ * @sig Number -> a -> [a] -> [a]
+ * @param {Number} index The position to insert the element
+ * @param {*} elt The element to insert into the Array
+ * @param {Array} list The list to insert into
+ * @return {Array} A new Array with `elt` inserted at `index`.
+ * @example
+ *
+ *      R.insert(2, 'x', [1,2,3,4]); //=> [1,2,'x',3,4]
+ */
+var insert = /*#__PURE__*/_curry3(function insert(idx, elt, list) {
+  idx = idx < list.length && idx >= 0 ? idx : list.length;
+  var result = Array.prototype.slice.call(list, 0);
+  result.splice(idx, 0, elt);
+  return result;
+});
+export default insert;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/insertAll.js b/server/node_modules/ramda/es/insertAll.js
new file mode 100644
index 0000000000000000000000000000000000000000..4cbff615abb018bd78e5b92931772c72e5f7b92a
--- /dev/null
+++ b/server/node_modules/ramda/es/insertAll.js
@@ -0,0 +1,25 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Inserts the sub-list into the list, at the specified `index`. _Note that this is not
+ * destructive_: it returns a copy of the list with the changes.
+ * <small>No lists have been harmed in the application of this function.</small>
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category List
+ * @sig Number -> [a] -> [a] -> [a]
+ * @param {Number} index The position to insert the sub-list
+ * @param {Array} elts The sub-list to insert into the Array
+ * @param {Array} list The list to insert the sub-list into
+ * @return {Array} A new Array with `elts` inserted starting at `index`.
+ * @example
+ *
+ *      R.insertAll(2, ['x','y','z'], [1,2,3,4]); //=> [1,2,'x','y','z',3,4]
+ */
+var insertAll = /*#__PURE__*/_curry3(function insertAll(idx, elts, list) {
+  idx = idx < list.length && idx >= 0 ? idx : list.length;
+  return [].concat(Array.prototype.slice.call(list, 0, idx), elts, Array.prototype.slice.call(list, idx));
+});
+export default insertAll;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_Set.js b/server/node_modules/ramda/es/internal/_Set.js
new file mode 100644
index 0000000000000000000000000000000000000000..1627cc8ed227d413cc044ac57f42d80582bc018a
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_Set.js
@@ -0,0 +1,173 @@
+import _includes from './_includes.js';
+
+var _Set = /*#__PURE__*/function () {
+  function _Set() {
+    /* globals Set */
+    this._nativeSet = typeof Set === 'function' ? new Set() : null;
+    this._items = {};
+  }
+
+  // until we figure out why jsdoc chokes on this
+  // @param item The item to add to the Set
+  // @returns {boolean} true if the item did not exist prior, otherwise false
+  //
+  _Set.prototype.add = function (item) {
+    return !hasOrAdd(item, true, this);
+  };
+
+  //
+  // @param item The item to check for existence in the Set
+  // @returns {boolean} true if the item exists in the Set, otherwise false
+  //
+  _Set.prototype.has = function (item) {
+    return hasOrAdd(item, false, this);
+  };
+
+  //
+  // Combines the logic for checking whether an item is a member of the set and
+  // for adding a new item to the set.
+  //
+  // @param item       The item to check or add to the Set instance.
+  // @param shouldAdd  If true, the item will be added to the set if it doesn't
+  //                   already exist.
+  // @param set        The set instance to check or add to.
+  // @return {boolean} true if the item already existed, otherwise false.
+  //
+  return _Set;
+}();
+
+function hasOrAdd(item, shouldAdd, set) {
+  var type = typeof item;
+  var prevSize, newSize;
+  switch (type) {
+    case 'string':
+    case 'number':
+      // distinguish between +0 and -0
+      if (item === 0 && 1 / item === -Infinity) {
+        if (set._items['-0']) {
+          return true;
+        } else {
+          if (shouldAdd) {
+            set._items['-0'] = true;
+          }
+          return false;
+        }
+      }
+      // these types can all utilise the native Set
+      if (set._nativeSet !== null) {
+        if (shouldAdd) {
+          prevSize = set._nativeSet.size;
+          set._nativeSet.add(item);
+          newSize = set._nativeSet.size;
+          return newSize === prevSize;
+        } else {
+          return set._nativeSet.has(item);
+        }
+      } else {
+        if (!(type in set._items)) {
+          if (shouldAdd) {
+            set._items[type] = {};
+            set._items[type][item] = true;
+          }
+          return false;
+        } else if (item in set._items[type]) {
+          return true;
+        } else {
+          if (shouldAdd) {
+            set._items[type][item] = true;
+          }
+          return false;
+        }
+      }
+
+    case 'boolean':
+      // set._items['boolean'] holds a two element array
+      // representing [ falseExists, trueExists ]
+      if (type in set._items) {
+        var bIdx = item ? 1 : 0;
+        if (set._items[type][bIdx]) {
+          return true;
+        } else {
+          if (shouldAdd) {
+            set._items[type][bIdx] = true;
+          }
+          return false;
+        }
+      } else {
+        if (shouldAdd) {
+          set._items[type] = item ? [false, true] : [true, false];
+        }
+        return false;
+      }
+
+    case 'function':
+      // compare functions for reference equality
+      if (set._nativeSet !== null) {
+        if (shouldAdd) {
+          prevSize = set._nativeSet.size;
+          set._nativeSet.add(item);
+          newSize = set._nativeSet.size;
+          return newSize === prevSize;
+        } else {
+          return set._nativeSet.has(item);
+        }
+      } else {
+        if (!(type in set._items)) {
+          if (shouldAdd) {
+            set._items[type] = [item];
+          }
+          return false;
+        }
+        if (!_includes(item, set._items[type])) {
+          if (shouldAdd) {
+            set._items[type].push(item);
+          }
+          return false;
+        }
+        return true;
+      }
+
+    case 'undefined':
+      if (set._items[type]) {
+        return true;
+      } else {
+        if (shouldAdd) {
+          set._items[type] = true;
+        }
+        return false;
+      }
+
+    case 'object':
+      if (item === null) {
+        if (!set._items['null']) {
+          if (shouldAdd) {
+            set._items['null'] = true;
+          }
+          return false;
+        }
+        return true;
+      }
+    /* falls through */
+    default:
+      // reduce the search size of heterogeneous sets by creating buckets
+      // for each type.
+      type = Object.prototype.toString.call(item);
+      if (!(type in set._items)) {
+        if (shouldAdd) {
+          set._items[type] = [item];
+        }
+        return false;
+      }
+      // scan through all previously applied items
+      if (!_includes(item, set._items[type])) {
+        if (shouldAdd) {
+          set._items[type].push(item);
+        }
+        return false;
+      }
+      return true;
+  }
+}
+
+// A simple Set type that honours R.equals semantics
+export default _Set;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_aperture.js b/server/node_modules/ramda/es/internal/_aperture.js
new file mode 100644
index 0000000000000000000000000000000000000000..2bd07415d4a67259a738c1bcfd2be66dfb88820d
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_aperture.js
@@ -0,0 +1,10 @@
+export default function _aperture(n, list) {
+  var idx = 0;
+  var limit = list.length - (n - 1);
+  var acc = new Array(limit >= 0 ? limit : 0);
+  while (idx < limit) {
+    acc[idx] = Array.prototype.slice.call(list, idx, idx + n);
+    idx += 1;
+  }
+  return acc;
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_arity.js b/server/node_modules/ramda/es/internal/_arity.js
new file mode 100644
index 0000000000000000000000000000000000000000..2a051cc9dd6b9678c21cfefec98829a3fa04ac24
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_arity.js
@@ -0,0 +1,51 @@
+export default function _arity(n, fn) {
+  /* eslint-disable no-unused-vars */
+  switch (n) {
+    case 0:
+      return function () {
+        return fn.apply(this, arguments);
+      };
+    case 1:
+      return function (a0) {
+        return fn.apply(this, arguments);
+      };
+    case 2:
+      return function (a0, a1) {
+        return fn.apply(this, arguments);
+      };
+    case 3:
+      return function (a0, a1, a2) {
+        return fn.apply(this, arguments);
+      };
+    case 4:
+      return function (a0, a1, a2, a3) {
+        return fn.apply(this, arguments);
+      };
+    case 5:
+      return function (a0, a1, a2, a3, a4) {
+        return fn.apply(this, arguments);
+      };
+    case 6:
+      return function (a0, a1, a2, a3, a4, a5) {
+        return fn.apply(this, arguments);
+      };
+    case 7:
+      return function (a0, a1, a2, a3, a4, a5, a6) {
+        return fn.apply(this, arguments);
+      };
+    case 8:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7) {
+        return fn.apply(this, arguments);
+      };
+    case 9:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) {
+        return fn.apply(this, arguments);
+      };
+    case 10:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {
+        return fn.apply(this, arguments);
+      };
+    default:
+      throw new Error('First argument to _arity must be a non-negative integer no greater than ten');
+  }
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_arrayFromIterator.js b/server/node_modules/ramda/es/internal/_arrayFromIterator.js
new file mode 100644
index 0000000000000000000000000000000000000000..adf657d9c2c383dd8216c2414deab7d1d0edc45a
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_arrayFromIterator.js
@@ -0,0 +1,8 @@
+export default function _arrayFromIterator(iter) {
+  var list = [];
+  var next;
+  while (!(next = iter.next()).done) {
+    list.push(next.value);
+  }
+  return list;
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_assertPromise.js b/server/node_modules/ramda/es/internal/_assertPromise.js
new file mode 100644
index 0000000000000000000000000000000000000000..e15e2fff2330ef2c57bcd17b562d25d4b4408d89
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_assertPromise.js
@@ -0,0 +1,8 @@
+import _isFunction from './_isFunction.js';
+import _toString from './_toString.js';
+
+export default function _assertPromise(name, p) {
+  if (p == null || !_isFunction(p.then)) {
+    throw new TypeError('`' + name + '` expected a Promise, received ' + _toString(p, []));
+  }
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_checkForMethod.js b/server/node_modules/ramda/es/internal/_checkForMethod.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e3ab6f9f9f26fbda74cddde285dc1133ba2e424
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_checkForMethod.js
@@ -0,0 +1,22 @@
+import _isArray from './_isArray.js';
+
+/**
+ * This checks whether a function has a [methodname] function. If it isn't an
+ * array it will execute that function otherwise it will default to the ramda
+ * implementation.
+ *
+ * @private
+ * @param {Function} fn ramda implemtation
+ * @param {String} methodname property to check for a custom implementation
+ * @return {Object} Whatever the return value of the method is.
+ */
+export default function _checkForMethod(methodname, fn) {
+  return function () {
+    var length = arguments.length;
+    if (length === 0) {
+      return fn();
+    }
+    var obj = arguments[length - 1];
+    return _isArray(obj) || typeof obj[methodname] !== 'function' ? fn.apply(this, arguments) : obj[methodname].apply(obj, Array.prototype.slice.call(arguments, 0, length - 1));
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_clone.js b/server/node_modules/ramda/es/internal/_clone.js
new file mode 100644
index 0000000000000000000000000000000000000000..b14195a28dc55d4b6533ba23b6ad2487ae3d5cdd
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_clone.js
@@ -0,0 +1,43 @@
+import _cloneRegExp from './_cloneRegExp.js';
+import type from '../type.js';
+
+/**
+ * Copies an object.
+ *
+ * @private
+ * @param {*} value The value to be copied
+ * @param {Array} refFrom Array containing the source references
+ * @param {Array} refTo Array containing the copied source references
+ * @param {Boolean} deep Whether or not to perform deep cloning.
+ * @return {*} The copied value.
+ */
+export default function _clone(value, refFrom, refTo, deep) {
+  var copy = function copy(copiedValue) {
+    var len = refFrom.length;
+    var idx = 0;
+    while (idx < len) {
+      if (value === refFrom[idx]) {
+        return refTo[idx];
+      }
+      idx += 1;
+    }
+    refFrom[idx + 1] = value;
+    refTo[idx + 1] = copiedValue;
+    for (var key in value) {
+      copiedValue[key] = deep ? _clone(value[key], refFrom, refTo, true) : value[key];
+    }
+    return copiedValue;
+  };
+  switch (type(value)) {
+    case 'Object':
+      return copy({});
+    case 'Array':
+      return copy([]);
+    case 'Date':
+      return new Date(value.valueOf());
+    case 'RegExp':
+      return _cloneRegExp(value);
+    default:
+      return value;
+  }
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_cloneRegExp.js b/server/node_modules/ramda/es/internal/_cloneRegExp.js
new file mode 100644
index 0000000000000000000000000000000000000000..b0b339eac17d7bf81b5b0c97e13dd91258b00a48
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_cloneRegExp.js
@@ -0,0 +1,3 @@
+export default function _cloneRegExp(pattern) {
+                                  return new RegExp(pattern.source, (pattern.global ? 'g' : '') + (pattern.ignoreCase ? 'i' : '') + (pattern.multiline ? 'm' : '') + (pattern.sticky ? 'y' : '') + (pattern.unicode ? 'u' : ''));
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_complement.js b/server/node_modules/ramda/es/internal/_complement.js
new file mode 100644
index 0000000000000000000000000000000000000000..0f06b0d356b3d09f8bec4e6cd05e5f74dab98ac6
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_complement.js
@@ -0,0 +1,5 @@
+export default function _complement(f) {
+  return function () {
+    return !f.apply(this, arguments);
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_concat.js b/server/node_modules/ramda/es/internal/_concat.js
new file mode 100644
index 0000000000000000000000000000000000000000..d2387acdb103403604ba5045f835133a1eb320e6
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_concat.js
@@ -0,0 +1,31 @@
+/**
+ * Private `concat` function to merge two array-like objects.
+ *
+ * @private
+ * @param {Array|Arguments} [set1=[]] An array-like object.
+ * @param {Array|Arguments} [set2=[]] An array-like object.
+ * @return {Array} A new, merged array.
+ * @example
+ *
+ *      _concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3]
+ */
+export default function _concat(set1, set2) {
+  set1 = set1 || [];
+  set2 = set2 || [];
+  var idx;
+  var len1 = set1.length;
+  var len2 = set2.length;
+  var result = [];
+
+  idx = 0;
+  while (idx < len1) {
+    result[result.length] = set1[idx];
+    idx += 1;
+  }
+  idx = 0;
+  while (idx < len2) {
+    result[result.length] = set2[idx];
+    idx += 1;
+  }
+  return result;
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_createPartialApplicator.js b/server/node_modules/ramda/es/internal/_createPartialApplicator.js
new file mode 100644
index 0000000000000000000000000000000000000000..3f73d822812fd713521ee8b2b2705db0e739f198
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_createPartialApplicator.js
@@ -0,0 +1,10 @@
+import _arity from './_arity.js';
+import _curry2 from './_curry2.js';
+
+export default function _createPartialApplicator(concat) {
+  return _curry2(function (fn, args) {
+    return _arity(Math.max(0, fn.length - args.length), function () {
+      return fn.apply(this, concat(args, arguments));
+    });
+  });
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_curry1.js b/server/node_modules/ramda/es/internal/_curry1.js
new file mode 100644
index 0000000000000000000000000000000000000000..5fa34a68c38ee4b1ddcf2305f25035d11d42cc72
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_curry1.js
@@ -0,0 +1,19 @@
+import _isPlaceholder from './_isPlaceholder.js';
+
+/**
+ * Optimized internal one-arity curry function.
+ *
+ * @private
+ * @category Function
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+export default function _curry1(fn) {
+  return function f1(a) {
+    if (arguments.length === 0 || _isPlaceholder(a)) {
+      return f1;
+    } else {
+      return fn.apply(this, arguments);
+    }
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_curry2.js b/server/node_modules/ramda/es/internal/_curry2.js
new file mode 100644
index 0000000000000000000000000000000000000000..325ba92e64914ee50833e0159df743f1072ae811
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_curry2.js
@@ -0,0 +1,29 @@
+import _curry1 from './_curry1.js';
+import _isPlaceholder from './_isPlaceholder.js';
+
+/**
+ * Optimized internal two-arity curry function.
+ *
+ * @private
+ * @category Function
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+export default function _curry2(fn) {
+  return function f2(a, b) {
+    switch (arguments.length) {
+      case 0:
+        return f2;
+      case 1:
+        return _isPlaceholder(a) ? f2 : _curry1(function (_b) {
+          return fn(a, _b);
+        });
+      default:
+        return _isPlaceholder(a) && _isPlaceholder(b) ? f2 : _isPlaceholder(a) ? _curry1(function (_a) {
+          return fn(_a, b);
+        }) : _isPlaceholder(b) ? _curry1(function (_b) {
+          return fn(a, _b);
+        }) : fn(a, b);
+    }
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_curry3.js b/server/node_modules/ramda/es/internal/_curry3.js
new file mode 100644
index 0000000000000000000000000000000000000000..eaa463c2b17e0efb70731d543637cbd3f410345b
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_curry3.js
@@ -0,0 +1,46 @@
+import _curry1 from './_curry1.js';
+import _curry2 from './_curry2.js';
+import _isPlaceholder from './_isPlaceholder.js';
+
+/**
+ * Optimized internal three-arity curry function.
+ *
+ * @private
+ * @category Function
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+export default function _curry3(fn) {
+  return function f3(a, b, c) {
+    switch (arguments.length) {
+      case 0:
+        return f3;
+      case 1:
+        return _isPlaceholder(a) ? f3 : _curry2(function (_b, _c) {
+          return fn(a, _b, _c);
+        });
+      case 2:
+        return _isPlaceholder(a) && _isPlaceholder(b) ? f3 : _isPlaceholder(a) ? _curry2(function (_a, _c) {
+          return fn(_a, b, _c);
+        }) : _isPlaceholder(b) ? _curry2(function (_b, _c) {
+          return fn(a, _b, _c);
+        }) : _curry1(function (_c) {
+          return fn(a, b, _c);
+        });
+      default:
+        return _isPlaceholder(a) && _isPlaceholder(b) && _isPlaceholder(c) ? f3 : _isPlaceholder(a) && _isPlaceholder(b) ? _curry2(function (_a, _b) {
+          return fn(_a, _b, c);
+        }) : _isPlaceholder(a) && _isPlaceholder(c) ? _curry2(function (_a, _c) {
+          return fn(_a, b, _c);
+        }) : _isPlaceholder(b) && _isPlaceholder(c) ? _curry2(function (_b, _c) {
+          return fn(a, _b, _c);
+        }) : _isPlaceholder(a) ? _curry1(function (_a) {
+          return fn(_a, b, c);
+        }) : _isPlaceholder(b) ? _curry1(function (_b) {
+          return fn(a, _b, c);
+        }) : _isPlaceholder(c) ? _curry1(function (_c) {
+          return fn(a, b, _c);
+        }) : fn(a, b, c);
+    }
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_curryN.js b/server/node_modules/ramda/es/internal/_curryN.js
new file mode 100644
index 0000000000000000000000000000000000000000..7661406be8a518c5770e890f9ae8aeb1ff26a680
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_curryN.js
@@ -0,0 +1,36 @@
+import _arity from './_arity.js';
+import _isPlaceholder from './_isPlaceholder.js';
+
+/**
+ * Internal curryN function.
+ *
+ * @private
+ * @category Function
+ * @param {Number} length The arity of the curried function.
+ * @param {Array} received An array of arguments received thus far.
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+export default function _curryN(length, received, fn) {
+  return function () {
+    var combined = [];
+    var argsIdx = 0;
+    var left = length;
+    var combinedIdx = 0;
+    while (combinedIdx < received.length || argsIdx < arguments.length) {
+      var result;
+      if (combinedIdx < received.length && (!_isPlaceholder(received[combinedIdx]) || argsIdx >= arguments.length)) {
+        result = received[combinedIdx];
+      } else {
+        result = arguments[argsIdx];
+        argsIdx += 1;
+      }
+      combined[combinedIdx] = result;
+      if (!_isPlaceholder(result)) {
+        left -= 1;
+      }
+      combinedIdx += 1;
+    }
+    return left <= 0 ? fn.apply(this, combined) : _arity(left, _curryN(length, combined, fn));
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_dispatchable.js b/server/node_modules/ramda/es/internal/_dispatchable.js
new file mode 100644
index 0000000000000000000000000000000000000000..1b1e4d8cb14817a642651438a7f761818264aa6d
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_dispatchable.js
@@ -0,0 +1,40 @@
+import _isArray from './_isArray.js';
+import _isTransformer from './_isTransformer.js';
+
+/**
+ * Returns a function that dispatches with different strategies based on the
+ * object in list position (last argument). If it is an array, executes [fn].
+ * Otherwise, if it has a function with one of the given method names, it will
+ * execute that function (functor case). Otherwise, if it is a transformer,
+ * uses transducer [xf] to return a new transformer (transducer case).
+ * Otherwise, it will default to executing [fn].
+ *
+ * @private
+ * @param {Array} methodNames properties to check for a custom implementation
+ * @param {Function} xf transducer to initialize if object is transformer
+ * @param {Function} fn default ramda implementation
+ * @return {Function} A function that dispatches on object in list position
+ */
+export default function _dispatchable(methodNames, xf, fn) {
+  return function () {
+    if (arguments.length === 0) {
+      return fn();
+    }
+    var args = Array.prototype.slice.call(arguments, 0);
+    var obj = args.pop();
+    if (!_isArray(obj)) {
+      var idx = 0;
+      while (idx < methodNames.length) {
+        if (typeof obj[methodNames[idx]] === 'function') {
+          return obj[methodNames[idx]].apply(obj, args);
+        }
+        idx += 1;
+      }
+      if (_isTransformer(obj)) {
+        var transducer = xf.apply(null, args);
+        return transducer(obj);
+      }
+    }
+    return fn.apply(this, arguments);
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_dropLast.js b/server/node_modules/ramda/es/internal/_dropLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..0036ba8a5c08fa9b67c2b4d9235f65b43b1e23e4
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_dropLast.js
@@ -0,0 +1,5 @@
+import take from '../take.js';
+
+export default function dropLast(n, xs) {
+  return take(n < xs.length ? xs.length - n : 0, xs);
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_dropLastWhile.js b/server/node_modules/ramda/es/internal/_dropLastWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..43f7728a64f508b36740363c8fb2782923438750
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_dropLastWhile.js
@@ -0,0 +1,9 @@
+import slice from '../slice.js';
+
+export default function dropLastWhile(pred, xs) {
+  var idx = xs.length - 1;
+  while (idx >= 0 && pred(xs[idx])) {
+    idx -= 1;
+  }
+  return slice(0, idx + 1, xs);
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_equals.js b/server/node_modules/ramda/es/internal/_equals.js
new file mode 100644
index 0000000000000000000000000000000000000000..564959cae7c4f7f8ca56d238f02438c828baad78
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_equals.js
@@ -0,0 +1,149 @@
+import _arrayFromIterator from './_arrayFromIterator.js';
+import _includesWith from './_includesWith.js';
+import _functionName from './_functionName.js';
+import _has from './_has.js';
+import _objectIs from './_objectIs.js';
+import keys from '../keys.js';
+import type from '../type.js';
+
+/**
+ * private _uniqContentEquals function.
+ * That function is checking equality of 2 iterator contents with 2 assumptions
+ * - iterators lengths are the same
+ * - iterators values are unique
+ *
+ * false-positive result will be returned for comparision of, e.g.
+ * - [1,2,3] and [1,2,3,4]
+ * - [1,1,1] and [1,2,3]
+ * */
+
+function _uniqContentEquals(aIterator, bIterator, stackA, stackB) {
+  var a = _arrayFromIterator(aIterator);
+  var b = _arrayFromIterator(bIterator);
+
+  function eq(_a, _b) {
+    return _equals(_a, _b, stackA.slice(), stackB.slice());
+  }
+
+  // if *a* array contains any element that is not included in *b*
+  return !_includesWith(function (b, aItem) {
+    return !_includesWith(eq, aItem, b);
+  }, b, a);
+}
+
+export default function _equals(a, b, stackA, stackB) {
+  if (_objectIs(a, b)) {
+    return true;
+  }
+
+  var typeA = type(a);
+
+  if (typeA !== type(b)) {
+    return false;
+  }
+
+  if (a == null || b == null) {
+    return false;
+  }
+
+  if (typeof a['fantasy-land/equals'] === 'function' || typeof b['fantasy-land/equals'] === 'function') {
+    return typeof a['fantasy-land/equals'] === 'function' && a['fantasy-land/equals'](b) && typeof b['fantasy-land/equals'] === 'function' && b['fantasy-land/equals'](a);
+  }
+
+  if (typeof a.equals === 'function' || typeof b.equals === 'function') {
+    return typeof a.equals === 'function' && a.equals(b) && typeof b.equals === 'function' && b.equals(a);
+  }
+
+  switch (typeA) {
+    case 'Arguments':
+    case 'Array':
+    case 'Object':
+      if (typeof a.constructor === 'function' && _functionName(a.constructor) === 'Promise') {
+        return a === b;
+      }
+      break;
+    case 'Boolean':
+    case 'Number':
+    case 'String':
+      if (!(typeof a === typeof b && _objectIs(a.valueOf(), b.valueOf()))) {
+        return false;
+      }
+      break;
+    case 'Date':
+      if (!_objectIs(a.valueOf(), b.valueOf())) {
+        return false;
+      }
+      break;
+    case 'Error':
+      return a.name === b.name && a.message === b.message;
+    case 'RegExp':
+      if (!(a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky && a.unicode === b.unicode)) {
+        return false;
+      }
+      break;
+  }
+
+  var idx = stackA.length - 1;
+  while (idx >= 0) {
+    if (stackA[idx] === a) {
+      return stackB[idx] === b;
+    }
+    idx -= 1;
+  }
+
+  switch (typeA) {
+    case 'Map':
+      if (a.size !== b.size) {
+        return false;
+      }
+
+      return _uniqContentEquals(a.entries(), b.entries(), stackA.concat([a]), stackB.concat([b]));
+    case 'Set':
+      if (a.size !== b.size) {
+        return false;
+      }
+
+      return _uniqContentEquals(a.values(), b.values(), stackA.concat([a]), stackB.concat([b]));
+    case 'Arguments':
+    case 'Array':
+    case 'Object':
+    case 'Boolean':
+    case 'Number':
+    case 'String':
+    case 'Date':
+    case 'Error':
+    case 'RegExp':
+    case 'Int8Array':
+    case 'Uint8Array':
+    case 'Uint8ClampedArray':
+    case 'Int16Array':
+    case 'Uint16Array':
+    case 'Int32Array':
+    case 'Uint32Array':
+    case 'Float32Array':
+    case 'Float64Array':
+    case 'ArrayBuffer':
+      break;
+    default:
+      // Values of other types are only equal if identical.
+      return false;
+  }
+
+  var keysA = keys(a);
+  if (keysA.length !== keys(b).length) {
+    return false;
+  }
+
+  var extendedStackA = stackA.concat([a]);
+  var extendedStackB = stackB.concat([b]);
+
+  idx = keysA.length - 1;
+  while (idx >= 0) {
+    var key = keysA[idx];
+    if (!(_has(key, b) && _equals(b[key], a[key], extendedStackA, extendedStackB))) {
+      return false;
+    }
+    idx -= 1;
+  }
+  return true;
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_filter.js b/server/node_modules/ramda/es/internal/_filter.js
new file mode 100644
index 0000000000000000000000000000000000000000..5f541ee9bfc91baccfcd768d5d9ca456f35904ce
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_filter.js
@@ -0,0 +1,13 @@
+export default function _filter(fn, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [];
+
+  while (idx < len) {
+    if (fn(list[idx])) {
+      result[result.length] = list[idx];
+    }
+    idx += 1;
+  }
+  return result;
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_flatCat.js b/server/node_modules/ramda/es/internal/_flatCat.js
new file mode 100644
index 0000000000000000000000000000000000000000..774deebb3e7ef87a39f6c21baacb0adf35f13f3e
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_flatCat.js
@@ -0,0 +1,32 @@
+import _forceReduced from './_forceReduced.js';
+import _isArrayLike from './_isArrayLike.js';
+import _reduce from './_reduce.js';
+import _xfBase from './_xfBase.js';
+
+var preservingReduced = function (xf) {
+  return {
+    '@@transducer/init': _xfBase.init,
+    '@@transducer/result': function (result) {
+      return xf['@@transducer/result'](result);
+    },
+    '@@transducer/step': function (result, input) {
+      var ret = xf['@@transducer/step'](result, input);
+      return ret['@@transducer/reduced'] ? _forceReduced(ret) : ret;
+    }
+  };
+};
+
+var _flatCat = function _xcat(xf) {
+  var rxf = preservingReduced(xf);
+  return {
+    '@@transducer/init': _xfBase.init,
+    '@@transducer/result': function (result) {
+      return rxf['@@transducer/result'](result);
+    },
+    '@@transducer/step': function (result, input) {
+      return !_isArrayLike(input) ? _reduce(rxf, result, [input]) : _reduce(rxf, result, input);
+    }
+  };
+};
+
+export default _flatCat;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_forceReduced.js b/server/node_modules/ramda/es/internal/_forceReduced.js
new file mode 100644
index 0000000000000000000000000000000000000000..7c59c787b1a1019ecba00af4e97b70812b209ab8
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_forceReduced.js
@@ -0,0 +1,6 @@
+export default function _forceReduced(x) {
+  return {
+    '@@transducer/value': x,
+    '@@transducer/reduced': true
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_functionName.js b/server/node_modules/ramda/es/internal/_functionName.js
new file mode 100644
index 0000000000000000000000000000000000000000..17c7718dbe669bb2253abcac0f53b2d660129adb
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_functionName.js
@@ -0,0 +1,5 @@
+export default function _functionName(f) {
+  // String(x => x) evaluates to "x => x", so the pattern may not match.
+  var match = String(f).match(/^function (\w*)/);
+  return match == null ? '' : match[1];
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_functionsWith.js b/server/node_modules/ramda/es/internal/_functionsWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..46b947f1d84dd33cd431aee875aff9c00f50d981
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_functionsWith.js
@@ -0,0 +1,14 @@
+import _filter from './_filter.js';
+
+/**
+ * @private
+ * @param {Function} fn The strategy for extracting function names from an object
+ * @return {Function} A function that takes an object and returns an array of function names.
+ */
+export default function _functionsWith(fn) {
+  return function (obj) {
+    return _filter(function (key) {
+      return typeof obj[key] === 'function';
+    }, fn(obj));
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_has.js b/server/node_modules/ramda/es/internal/_has.js
new file mode 100644
index 0000000000000000000000000000000000000000..71363cfa777ba6e45de378000b4a71a6b5f56f33
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_has.js
@@ -0,0 +1,3 @@
+export default function _has(prop, obj) {
+  return Object.prototype.hasOwnProperty.call(obj, prop);
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_identity.js b/server/node_modules/ramda/es/internal/_identity.js
new file mode 100644
index 0000000000000000000000000000000000000000..a1e7e4cda8d8db38b0552e597c62e112d65bad04
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_identity.js
@@ -0,0 +1,3 @@
+export default function _identity(x) {
+  return x;
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_includes.js b/server/node_modules/ramda/es/internal/_includes.js
new file mode 100644
index 0000000000000000000000000000000000000000..086ed517a6bb79d0aa297d52ef9f2f897f86a546
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_includes.js
@@ -0,0 +1,5 @@
+import _indexOf from './_indexOf.js';
+
+export default function _includes(a, list) {
+  return _indexOf(list, a, 0) >= 0;
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_includesWith.js b/server/node_modules/ramda/es/internal/_includesWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..5e5ccfd98ef3fadffc35c7b17c84c437098bf8a9
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_includesWith.js
@@ -0,0 +1,12 @@
+export default function _includesWith(pred, x, list) {
+  var idx = 0;
+  var len = list.length;
+
+  while (idx < len) {
+    if (pred(x, list[idx])) {
+      return true;
+    }
+    idx += 1;
+  }
+  return false;
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_indexOf.js b/server/node_modules/ramda/es/internal/_indexOf.js
new file mode 100644
index 0000000000000000000000000000000000000000..7097c5ded20759b481c133f8c61f0ce127f4adcb
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_indexOf.js
@@ -0,0 +1,56 @@
+import equals from '../equals.js';
+
+export default function _indexOf(list, a, idx) {
+  var inf, item;
+  // Array.prototype.indexOf doesn't exist below IE9
+  if (typeof list.indexOf === 'function') {
+    switch (typeof a) {
+      case 'number':
+        if (a === 0) {
+          // manually crawl the list to distinguish between +0 and -0
+          inf = 1 / a;
+          while (idx < list.length) {
+            item = list[idx];
+            if (item === 0 && 1 / item === inf) {
+              return idx;
+            }
+            idx += 1;
+          }
+          return -1;
+        } else if (a !== a) {
+          // NaN
+          while (idx < list.length) {
+            item = list[idx];
+            if (typeof item === 'number' && item !== item) {
+              return idx;
+            }
+            idx += 1;
+          }
+          return -1;
+        }
+        // non-zero numbers can utilise Set
+        return list.indexOf(a, idx);
+
+      // all these types can utilise Set
+      case 'string':
+      case 'boolean':
+      case 'function':
+      case 'undefined':
+        return list.indexOf(a, idx);
+
+      case 'object':
+        if (a === null) {
+          // null can utilise Set
+          return list.indexOf(a, idx);
+        }
+    }
+  }
+  // anything else not covered above, defer to R.equals
+  while (idx < list.length) {
+    if (equals(list[idx], a)) {
+      return idx;
+    }
+    idx += 1;
+  }
+  return -1;
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_isArguments.js b/server/node_modules/ramda/es/internal/_isArguments.js
new file mode 100644
index 0000000000000000000000000000000000000000..11522b98d54f654c68be476f30f36295b0ba0d3f
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_isArguments.js
@@ -0,0 +1,12 @@
+import _has from './_has.js';
+
+var toString = Object.prototype.toString;
+var _isArguments = /*#__PURE__*/function () {
+  return toString.call(arguments) === '[object Arguments]' ? function _isArguments(x) {
+    return toString.call(x) === '[object Arguments]';
+  } : function _isArguments(x) {
+    return _has('callee', x);
+  };
+}();
+
+export default _isArguments;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_isArray.js b/server/node_modules/ramda/es/internal/_isArray.js
new file mode 100644
index 0000000000000000000000000000000000000000..762faf252ece86384d9bc43348cd39449b2ecb18
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_isArray.js
@@ -0,0 +1,15 @@
+/**
+ * Tests whether or not an object is an array.
+ *
+ * @private
+ * @param {*} val The object to test.
+ * @return {Boolean} `true` if `val` is an array, `false` otherwise.
+ * @example
+ *
+ *      _isArray([]); //=> true
+ *      _isArray(null); //=> false
+ *      _isArray({}); //=> false
+ */
+export default Array.isArray || function _isArray(val) {
+  return val != null && val.length >= 0 && Object.prototype.toString.call(val) === '[object Array]';
+};
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_isArrayLike.js b/server/node_modules/ramda/es/internal/_isArrayLike.js
new file mode 100644
index 0000000000000000000000000000000000000000..96ae263fd40c16151bb9740d01b2ea6e0f6be77f
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_isArrayLike.js
@@ -0,0 +1,46 @@
+import _curry1 from './_curry1.js';
+import _isArray from './_isArray.js';
+import _isString from './_isString.js';
+
+/**
+ * Tests whether or not an object is similar to an array.
+ *
+ * @private
+ * @category Type
+ * @category List
+ * @sig * -> Boolean
+ * @param {*} x The object to test.
+ * @return {Boolean} `true` if `x` has a numeric length property and extreme indices defined; `false` otherwise.
+ * @example
+ *
+ *      _isArrayLike([]); //=> true
+ *      _isArrayLike(true); //=> false
+ *      _isArrayLike({}); //=> false
+ *      _isArrayLike({length: 10}); //=> false
+ *      _isArrayLike({0: 'zero', 9: 'nine', length: 10}); //=> true
+ */
+var _isArrayLike = /*#__PURE__*/_curry1(function isArrayLike(x) {
+  if (_isArray(x)) {
+    return true;
+  }
+  if (!x) {
+    return false;
+  }
+  if (typeof x !== 'object') {
+    return false;
+  }
+  if (_isString(x)) {
+    return false;
+  }
+  if (x.nodeType === 1) {
+    return !!x.length;
+  }
+  if (x.length === 0) {
+    return true;
+  }
+  if (x.length > 0) {
+    return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1);
+  }
+  return false;
+});
+export default _isArrayLike;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_isFunction.js b/server/node_modules/ramda/es/internal/_isFunction.js
new file mode 100644
index 0000000000000000000000000000000000000000..4a9281a66821262883bb46d22ef9cf321e7d4316
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_isFunction.js
@@ -0,0 +1,3 @@
+export default function _isFunction(x) {
+  return Object.prototype.toString.call(x) === '[object Function]';
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_isInteger.js b/server/node_modules/ramda/es/internal/_isInteger.js
new file mode 100644
index 0000000000000000000000000000000000000000..64cbfc6676365d42cbb3547625394033f88cab40
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_isInteger.js
@@ -0,0 +1,11 @@
+/**
+ * Determine if the passed argument is an integer.
+ *
+ * @private
+ * @param {*} n
+ * @category Type
+ * @return {Boolean}
+ */
+export default Number.isInteger || function _isInteger(n) {
+  return n << 0 === n;
+};
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_isNumber.js b/server/node_modules/ramda/es/internal/_isNumber.js
new file mode 100644
index 0000000000000000000000000000000000000000..9dc1df270defc5b8d801d35af07c173e99a94702
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_isNumber.js
@@ -0,0 +1,3 @@
+export default function _isNumber(x) {
+  return Object.prototype.toString.call(x) === '[object Number]';
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_isObject.js b/server/node_modules/ramda/es/internal/_isObject.js
new file mode 100644
index 0000000000000000000000000000000000000000..b85dc1576f94583b9b55793a3eb294f778f66367
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_isObject.js
@@ -0,0 +1,3 @@
+export default function _isObject(x) {
+  return Object.prototype.toString.call(x) === '[object Object]';
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_isPlaceholder.js b/server/node_modules/ramda/es/internal/_isPlaceholder.js
new file mode 100644
index 0000000000000000000000000000000000000000..e5098f168e7dc86b91357a06f6d4fbca36e2117e
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_isPlaceholder.js
@@ -0,0 +1,3 @@
+export default function _isPlaceholder(a) {
+       return a != null && typeof a === 'object' && a['@@functional/placeholder'] === true;
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_isRegExp.js b/server/node_modules/ramda/es/internal/_isRegExp.js
new file mode 100644
index 0000000000000000000000000000000000000000..07e7e1e7318f66097459001d7c57b7c950a3d390
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_isRegExp.js
@@ -0,0 +1,3 @@
+export default function _isRegExp(x) {
+  return Object.prototype.toString.call(x) === '[object RegExp]';
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_isString.js b/server/node_modules/ramda/es/internal/_isString.js
new file mode 100644
index 0000000000000000000000000000000000000000..a5985ee0b9ce1d9f5cfe2c2cbd406e86c6b834c6
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_isString.js
@@ -0,0 +1,3 @@
+export default function _isString(x) {
+  return Object.prototype.toString.call(x) === '[object String]';
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_isTransformer.js b/server/node_modules/ramda/es/internal/_isTransformer.js
new file mode 100644
index 0000000000000000000000000000000000000000..cc3ceebbb4c6ccd59f45a9198889fec3d6b8b5fb
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_isTransformer.js
@@ -0,0 +1,3 @@
+export default function _isTransformer(obj) {
+  return obj != null && typeof obj['@@transducer/step'] === 'function';
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_makeFlat.js b/server/node_modules/ramda/es/internal/_makeFlat.js
new file mode 100644
index 0000000000000000000000000000000000000000..988d5fdfd96432e644d630295cbd27d23d2b2325
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_makeFlat.js
@@ -0,0 +1,32 @@
+import _isArrayLike from './_isArrayLike.js';
+
+/**
+ * `_makeFlat` is a helper function that returns a one-level or fully recursive
+ * function based on the flag passed in.
+ *
+ * @private
+ */
+export default function _makeFlat(recursive) {
+  return function flatt(list) {
+    var value, jlen, j;
+    var result = [];
+    var idx = 0;
+    var ilen = list.length;
+
+    while (idx < ilen) {
+      if (_isArrayLike(list[idx])) {
+        value = recursive ? flatt(list[idx]) : list[idx];
+        j = 0;
+        jlen = value.length;
+        while (j < jlen) {
+          result[result.length] = value[j];
+          j += 1;
+        }
+      } else {
+        result[result.length] = list[idx];
+      }
+      idx += 1;
+    }
+    return result;
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_map.js b/server/node_modules/ramda/es/internal/_map.js
new file mode 100644
index 0000000000000000000000000000000000000000..f1f8203e6948e62774e63cdfd3c85682df84b5e3
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_map.js
@@ -0,0 +1,10 @@
+export default function _map(fn, functor) {
+  var idx = 0;
+  var len = functor.length;
+  var result = Array(len);
+  while (idx < len) {
+    result[idx] = fn(functor[idx]);
+    idx += 1;
+  }
+  return result;
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_objectAssign.js b/server/node_modules/ramda/es/internal/_objectAssign.js
new file mode 100644
index 0000000000000000000000000000000000000000..8827390ee4fb76e0260e71bc510f45f7fe158e03
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_objectAssign.js
@@ -0,0 +1,26 @@
+import _has from './_has.js';
+
+// Based on https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
+function _objectAssign(target) {
+  if (target == null) {
+    throw new TypeError('Cannot convert undefined or null to object');
+  }
+
+  var output = Object(target);
+  var idx = 1;
+  var length = arguments.length;
+  while (idx < length) {
+    var source = arguments[idx];
+    if (source != null) {
+      for (var nextKey in source) {
+        if (_has(nextKey, source)) {
+          output[nextKey] = source[nextKey];
+        }
+      }
+    }
+    idx += 1;
+  }
+  return output;
+}
+
+export default typeof Object.assign === 'function' ? Object.assign : _objectAssign;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_objectIs.js b/server/node_modules/ramda/es/internal/_objectIs.js
new file mode 100644
index 0000000000000000000000000000000000000000..6167f8e9c6cbe7e1627e6715d384a372594a2e52
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_objectIs.js
@@ -0,0 +1,14 @@
+// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+function _objectIs(a, b) {
+  // SameValue algorithm
+  if (a === b) {
+    // Steps 1-5, 7-10
+    // Steps 6.b-6.e: +0 != -0
+    return a !== 0 || 1 / a === 1 / b;
+  } else {
+    // Step 6.a: NaN == NaN
+    return a !== a && b !== b;
+  }
+}
+
+export default typeof Object.is === 'function' ? Object.is : _objectIs;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_of.js b/server/node_modules/ramda/es/internal/_of.js
new file mode 100644
index 0000000000000000000000000000000000000000..68ea63a8d4b6a679808302532b644da5a3280733
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_of.js
@@ -0,0 +1,3 @@
+export default function _of(x) {
+  return [x];
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_pipe.js b/server/node_modules/ramda/es/internal/_pipe.js
new file mode 100644
index 0000000000000000000000000000000000000000..01fb7772366772a10c22467b195829e1e86fb20c
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_pipe.js
@@ -0,0 +1,5 @@
+export default function _pipe(f, g) {
+  return function () {
+    return g.call(this, f.apply(this, arguments));
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_pipeP.js b/server/node_modules/ramda/es/internal/_pipeP.js
new file mode 100644
index 0000000000000000000000000000000000000000..a6247647741cde5703f16d87e335208337dbd922
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_pipeP.js
@@ -0,0 +1,8 @@
+export default function _pipeP(f, g) {
+  return function () {
+    var ctx = this;
+    return f.apply(ctx, arguments).then(function (x) {
+      return g.call(ctx, x);
+    });
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_quote.js b/server/node_modules/ramda/es/internal/_quote.js
new file mode 100644
index 0000000000000000000000000000000000000000..10bd8c4468af0b451013481a45f99b7a64da007b
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_quote.js
@@ -0,0 +1,6 @@
+export default function _quote(s) {
+  var escaped = s.replace(/\\/g, '\\\\').replace(/[\b]/g, '\\b') // \b matches word boundary; [\b] matches backspace
+  .replace(/\f/g, '\\f').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t').replace(/\v/g, '\\v').replace(/\0/g, '\\0');
+
+  return '"' + escaped.replace(/"/g, '\\"') + '"';
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_reduce.js b/server/node_modules/ramda/es/internal/_reduce.js
new file mode 100644
index 0000000000000000000000000000000000000000..a3422e6d6917c58e08979fe4bd65019ec3cfb4d0
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_reduce.js
@@ -0,0 +1,59 @@
+import _isArrayLike from './_isArrayLike.js';
+import _xwrap from './_xwrap.js';
+import bind from '../bind.js';
+
+function _arrayReduce(xf, acc, list) {
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    acc = xf['@@transducer/step'](acc, list[idx]);
+    if (acc && acc['@@transducer/reduced']) {
+      acc = acc['@@transducer/value'];
+      break;
+    }
+    idx += 1;
+  }
+  return xf['@@transducer/result'](acc);
+}
+
+function _iterableReduce(xf, acc, iter) {
+  var step = iter.next();
+  while (!step.done) {
+    acc = xf['@@transducer/step'](acc, step.value);
+    if (acc && acc['@@transducer/reduced']) {
+      acc = acc['@@transducer/value'];
+      break;
+    }
+    step = iter.next();
+  }
+  return xf['@@transducer/result'](acc);
+}
+
+function _methodReduce(xf, acc, obj, methodName) {
+  return xf['@@transducer/result'](obj[methodName](bind(xf['@@transducer/step'], xf), acc));
+}
+
+var symIterator = typeof Symbol !== 'undefined' ? Symbol.iterator : '@@iterator';
+
+export default function _reduce(fn, acc, list) {
+  if (typeof fn === 'function') {
+    fn = _xwrap(fn);
+  }
+  if (_isArrayLike(list)) {
+    return _arrayReduce(fn, acc, list);
+  }
+  if (typeof list['fantasy-land/reduce'] === 'function') {
+    return _methodReduce(fn, acc, list, 'fantasy-land/reduce');
+  }
+  if (list[symIterator] != null) {
+    return _iterableReduce(fn, acc, list[symIterator]());
+  }
+  if (typeof list.next === 'function') {
+    return _iterableReduce(fn, acc, list);
+  }
+  if (typeof list.reduce === 'function') {
+    return _methodReduce(fn, acc, list, 'reduce');
+  }
+
+  throw new TypeError('reduce: list must be array or iterable');
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_reduced.js b/server/node_modules/ramda/es/internal/_reduced.js
new file mode 100644
index 0000000000000000000000000000000000000000..0f065ccc04903f9f2297954408094c354b5b6171
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_reduced.js
@@ -0,0 +1,6 @@
+export default function _reduced(x) {
+  return x && x['@@transducer/reduced'] ? x : {
+    '@@transducer/value': x,
+    '@@transducer/reduced': true
+  };
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_stepCat.js b/server/node_modules/ramda/es/internal/_stepCat.js
new file mode 100644
index 0000000000000000000000000000000000000000..f0427ff3dcb51f09af07bde56f45c17d01822354
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_stepCat.js
@@ -0,0 +1,44 @@
+import _objectAssign from './_objectAssign.js';
+import _identity from './_identity.js';
+import _isArrayLike from './_isArrayLike.js';
+import _isTransformer from './_isTransformer.js';
+import objOf from '../objOf.js';
+
+var _stepCatArray = {
+  '@@transducer/init': Array,
+  '@@transducer/step': function (xs, x) {
+    xs.push(x);
+    return xs;
+  },
+  '@@transducer/result': _identity
+};
+var _stepCatString = {
+  '@@transducer/init': String,
+  '@@transducer/step': function (a, b) {
+    return a + b;
+  },
+  '@@transducer/result': _identity
+};
+var _stepCatObject = {
+  '@@transducer/init': Object,
+  '@@transducer/step': function (result, input) {
+    return _objectAssign(result, _isArrayLike(input) ? objOf(input[0], input[1]) : input);
+  },
+  '@@transducer/result': _identity
+};
+
+export default function _stepCat(obj) {
+  if (_isTransformer(obj)) {
+    return obj;
+  }
+  if (_isArrayLike(obj)) {
+    return _stepCatArray;
+  }
+  if (typeof obj === 'string') {
+    return _stepCatString;
+  }
+  if (typeof obj === 'object') {
+    return _stepCatObject;
+  }
+  throw new Error('Cannot create transformer for ' + obj);
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_toISOString.js b/server/node_modules/ramda/es/internal/_toISOString.js
new file mode 100644
index 0000000000000000000000000000000000000000..dbd8119346c302271e6d91d6478c2abdb23b1966
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_toISOString.js
@@ -0,0 +1,14 @@
+/**
+ * Polyfill from <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString>.
+ */
+var pad = function pad(n) {
+  return (n < 10 ? '0' : '') + n;
+};
+
+var _toISOString = typeof Date.prototype.toISOString === 'function' ? function _toISOString(d) {
+  return d.toISOString();
+} : function _toISOString(d) {
+  return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + '.' + (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 'Z';
+};
+
+export default _toISOString;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_toString.js b/server/node_modules/ramda/es/internal/_toString.js
new file mode 100644
index 0000000000000000000000000000000000000000..8cee52e082cef468b2431bd48793640f15c82489
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_toString.js
@@ -0,0 +1,50 @@
+import _includes from './_includes.js';
+import _map from './_map.js';
+import _quote from './_quote.js';
+import _toISOString from './_toISOString.js';
+import keys from '../keys.js';
+import reject from '../reject.js';
+
+export default function _toString(x, seen) {
+  var recur = function recur(y) {
+    var xs = seen.concat([x]);
+    return _includes(y, xs) ? '<Circular>' : _toString(y, xs);
+  };
+
+  //  mapPairs :: (Object, [String]) -> [String]
+  var mapPairs = function (obj, keys) {
+    return _map(function (k) {
+      return _quote(k) + ': ' + recur(obj[k]);
+    }, keys.slice().sort());
+  };
+
+  switch (Object.prototype.toString.call(x)) {
+    case '[object Arguments]':
+      return '(function() { return arguments; }(' + _map(recur, x).join(', ') + '))';
+    case '[object Array]':
+      return '[' + _map(recur, x).concat(mapPairs(x, reject(function (k) {
+        return (/^\d+$/.test(k)
+        );
+      }, keys(x)))).join(', ') + ']';
+    case '[object Boolean]':
+      return typeof x === 'object' ? 'new Boolean(' + recur(x.valueOf()) + ')' : x.toString();
+    case '[object Date]':
+      return 'new Date(' + (isNaN(x.valueOf()) ? recur(NaN) : _quote(_toISOString(x))) + ')';
+    case '[object Null]':
+      return 'null';
+    case '[object Number]':
+      return typeof x === 'object' ? 'new Number(' + recur(x.valueOf()) + ')' : 1 / x === -Infinity ? '-0' : x.toString(10);
+    case '[object String]':
+      return typeof x === 'object' ? 'new String(' + recur(x.valueOf()) + ')' : _quote(x);
+    case '[object Undefined]':
+      return 'undefined';
+    default:
+      if (typeof x.toString === 'function') {
+        var repr = x.toString();
+        if (repr !== '[object Object]') {
+          return repr;
+        }
+      }
+      return '{' + mapPairs(x, keys(x)).join(', ') + '}';
+  }
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xall.js b/server/node_modules/ramda/es/internal/_xall.js
new file mode 100644
index 0000000000000000000000000000000000000000..19f57f7b379dd013876dec447b5528395dd5f004
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xall.js
@@ -0,0 +1,32 @@
+import _curry2 from './_curry2.js';
+import _reduced from './_reduced.js';
+import _xfBase from './_xfBase.js';
+
+var XAll = /*#__PURE__*/function () {
+  function XAll(f, xf) {
+    this.xf = xf;
+    this.f = f;
+    this.all = true;
+  }
+  XAll.prototype['@@transducer/init'] = _xfBase.init;
+  XAll.prototype['@@transducer/result'] = function (result) {
+    if (this.all) {
+      result = this.xf['@@transducer/step'](result, true);
+    }
+    return this.xf['@@transducer/result'](result);
+  };
+  XAll.prototype['@@transducer/step'] = function (result, input) {
+    if (!this.f(input)) {
+      this.all = false;
+      result = _reduced(this.xf['@@transducer/step'](result, false));
+    }
+    return result;
+  };
+
+  return XAll;
+}();
+
+var _xall = /*#__PURE__*/_curry2(function _xall(f, xf) {
+  return new XAll(f, xf);
+});
+export default _xall;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xany.js b/server/node_modules/ramda/es/internal/_xany.js
new file mode 100644
index 0000000000000000000000000000000000000000..70999fd5915e6aae09d5006863f945184969c97e
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xany.js
@@ -0,0 +1,32 @@
+import _curry2 from './_curry2.js';
+import _reduced from './_reduced.js';
+import _xfBase from './_xfBase.js';
+
+var XAny = /*#__PURE__*/function () {
+  function XAny(f, xf) {
+    this.xf = xf;
+    this.f = f;
+    this.any = false;
+  }
+  XAny.prototype['@@transducer/init'] = _xfBase.init;
+  XAny.prototype['@@transducer/result'] = function (result) {
+    if (!this.any) {
+      result = this.xf['@@transducer/step'](result, false);
+    }
+    return this.xf['@@transducer/result'](result);
+  };
+  XAny.prototype['@@transducer/step'] = function (result, input) {
+    if (this.f(input)) {
+      this.any = true;
+      result = _reduced(this.xf['@@transducer/step'](result, true));
+    }
+    return result;
+  };
+
+  return XAny;
+}();
+
+var _xany = /*#__PURE__*/_curry2(function _xany(f, xf) {
+  return new XAny(f, xf);
+});
+export default _xany;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xaperture.js b/server/node_modules/ramda/es/internal/_xaperture.js
new file mode 100644
index 0000000000000000000000000000000000000000..ebf920bdbbb3e503b596087dfd95eb9e0ef36c52
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xaperture.js
@@ -0,0 +1,39 @@
+import _concat from './_concat.js';
+import _curry2 from './_curry2.js';
+import _xfBase from './_xfBase.js';
+
+var XAperture = /*#__PURE__*/function () {
+  function XAperture(n, xf) {
+    this.xf = xf;
+    this.pos = 0;
+    this.full = false;
+    this.acc = new Array(n);
+  }
+  XAperture.prototype['@@transducer/init'] = _xfBase.init;
+  XAperture.prototype['@@transducer/result'] = function (result) {
+    this.acc = null;
+    return this.xf['@@transducer/result'](result);
+  };
+  XAperture.prototype['@@transducer/step'] = function (result, input) {
+    this.store(input);
+    return this.full ? this.xf['@@transducer/step'](result, this.getCopy()) : result;
+  };
+  XAperture.prototype.store = function (input) {
+    this.acc[this.pos] = input;
+    this.pos += 1;
+    if (this.pos === this.acc.length) {
+      this.pos = 0;
+      this.full = true;
+    }
+  };
+  XAperture.prototype.getCopy = function () {
+    return _concat(Array.prototype.slice.call(this.acc, this.pos), Array.prototype.slice.call(this.acc, 0, this.pos));
+  };
+
+  return XAperture;
+}();
+
+var _xaperture = /*#__PURE__*/_curry2(function _xaperture(n, xf) {
+  return new XAperture(n, xf);
+});
+export default _xaperture;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xchain.js b/server/node_modules/ramda/es/internal/_xchain.js
new file mode 100644
index 0000000000000000000000000000000000000000..4ea01aa51b23706fdcec55275d34733cf6e58104
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xchain.js
@@ -0,0 +1,8 @@
+import _curry2 from './_curry2.js';
+import _flatCat from './_flatCat.js';
+import map from '../map.js';
+
+var _xchain = /*#__PURE__*/_curry2(function _xchain(f, xf) {
+  return map(f, _flatCat(xf));
+});
+export default _xchain;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xdrop.js b/server/node_modules/ramda/es/internal/_xdrop.js
new file mode 100644
index 0000000000000000000000000000000000000000..95a2f92f15a4369de52daa27bb64cd5a28f638bc
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xdrop.js
@@ -0,0 +1,25 @@
+import _curry2 from './_curry2.js';
+import _xfBase from './_xfBase.js';
+
+var XDrop = /*#__PURE__*/function () {
+  function XDrop(n, xf) {
+    this.xf = xf;
+    this.n = n;
+  }
+  XDrop.prototype['@@transducer/init'] = _xfBase.init;
+  XDrop.prototype['@@transducer/result'] = _xfBase.result;
+  XDrop.prototype['@@transducer/step'] = function (result, input) {
+    if (this.n > 0) {
+      this.n -= 1;
+      return result;
+    }
+    return this.xf['@@transducer/step'](result, input);
+  };
+
+  return XDrop;
+}();
+
+var _xdrop = /*#__PURE__*/_curry2(function _xdrop(n, xf) {
+  return new XDrop(n, xf);
+});
+export default _xdrop;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xdropLast.js b/server/node_modules/ramda/es/internal/_xdropLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..1fdba1e317c05a6f4f9f6db46e6b2054e34fd682
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xdropLast.js
@@ -0,0 +1,38 @@
+import _curry2 from './_curry2.js';
+import _xfBase from './_xfBase.js';
+
+var XDropLast = /*#__PURE__*/function () {
+  function XDropLast(n, xf) {
+    this.xf = xf;
+    this.pos = 0;
+    this.full = false;
+    this.acc = new Array(n);
+  }
+  XDropLast.prototype['@@transducer/init'] = _xfBase.init;
+  XDropLast.prototype['@@transducer/result'] = function (result) {
+    this.acc = null;
+    return this.xf['@@transducer/result'](result);
+  };
+  XDropLast.prototype['@@transducer/step'] = function (result, input) {
+    if (this.full) {
+      result = this.xf['@@transducer/step'](result, this.acc[this.pos]);
+    }
+    this.store(input);
+    return result;
+  };
+  XDropLast.prototype.store = function (input) {
+    this.acc[this.pos] = input;
+    this.pos += 1;
+    if (this.pos === this.acc.length) {
+      this.pos = 0;
+      this.full = true;
+    }
+  };
+
+  return XDropLast;
+}();
+
+var _xdropLast = /*#__PURE__*/_curry2(function _xdropLast(n, xf) {
+  return new XDropLast(n, xf);
+});
+export default _xdropLast;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xdropLastWhile.js b/server/node_modules/ramda/es/internal/_xdropLastWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..dee2e798b421417172d9680c04861dea3693f93a
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xdropLastWhile.js
@@ -0,0 +1,35 @@
+import _curry2 from './_curry2.js';
+import _reduce from './_reduce.js';
+import _xfBase from './_xfBase.js';
+
+var XDropLastWhile = /*#__PURE__*/function () {
+  function XDropLastWhile(fn, xf) {
+    this.f = fn;
+    this.retained = [];
+    this.xf = xf;
+  }
+  XDropLastWhile.prototype['@@transducer/init'] = _xfBase.init;
+  XDropLastWhile.prototype['@@transducer/result'] = function (result) {
+    this.retained = null;
+    return this.xf['@@transducer/result'](result);
+  };
+  XDropLastWhile.prototype['@@transducer/step'] = function (result, input) {
+    return this.f(input) ? this.retain(result, input) : this.flush(result, input);
+  };
+  XDropLastWhile.prototype.flush = function (result, input) {
+    result = _reduce(this.xf['@@transducer/step'], result, this.retained);
+    this.retained = [];
+    return this.xf['@@transducer/step'](result, input);
+  };
+  XDropLastWhile.prototype.retain = function (result, input) {
+    this.retained.push(input);
+    return result;
+  };
+
+  return XDropLastWhile;
+}();
+
+var _xdropLastWhile = /*#__PURE__*/_curry2(function _xdropLastWhile(fn, xf) {
+  return new XDropLastWhile(fn, xf);
+});
+export default _xdropLastWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xdropRepeatsWith.js b/server/node_modules/ramda/es/internal/_xdropRepeatsWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..d5bf0ff55466bf02a328d191d7c134dd3a985bca
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xdropRepeatsWith.js
@@ -0,0 +1,31 @@
+import _curry2 from './_curry2.js';
+import _xfBase from './_xfBase.js';
+
+var XDropRepeatsWith = /*#__PURE__*/function () {
+  function XDropRepeatsWith(pred, xf) {
+    this.xf = xf;
+    this.pred = pred;
+    this.lastValue = undefined;
+    this.seenFirstValue = false;
+  }
+
+  XDropRepeatsWith.prototype['@@transducer/init'] = _xfBase.init;
+  XDropRepeatsWith.prototype['@@transducer/result'] = _xfBase.result;
+  XDropRepeatsWith.prototype['@@transducer/step'] = function (result, input) {
+    var sameAsLast = false;
+    if (!this.seenFirstValue) {
+      this.seenFirstValue = true;
+    } else if (this.pred(this.lastValue, input)) {
+      sameAsLast = true;
+    }
+    this.lastValue = input;
+    return sameAsLast ? result : this.xf['@@transducer/step'](result, input);
+  };
+
+  return XDropRepeatsWith;
+}();
+
+var _xdropRepeatsWith = /*#__PURE__*/_curry2(function _xdropRepeatsWith(pred, xf) {
+  return new XDropRepeatsWith(pred, xf);
+});
+export default _xdropRepeatsWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xdropWhile.js b/server/node_modules/ramda/es/internal/_xdropWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..16e5c9e88e7b287fe808970c3e5c861829ac3067
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xdropWhile.js
@@ -0,0 +1,27 @@
+import _curry2 from './_curry2.js';
+import _xfBase from './_xfBase.js';
+
+var XDropWhile = /*#__PURE__*/function () {
+  function XDropWhile(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XDropWhile.prototype['@@transducer/init'] = _xfBase.init;
+  XDropWhile.prototype['@@transducer/result'] = _xfBase.result;
+  XDropWhile.prototype['@@transducer/step'] = function (result, input) {
+    if (this.f) {
+      if (this.f(input)) {
+        return result;
+      }
+      this.f = null;
+    }
+    return this.xf['@@transducer/step'](result, input);
+  };
+
+  return XDropWhile;
+}();
+
+var _xdropWhile = /*#__PURE__*/_curry2(function _xdropWhile(f, xf) {
+  return new XDropWhile(f, xf);
+});
+export default _xdropWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xfBase.js b/server/node_modules/ramda/es/internal/_xfBase.js
new file mode 100644
index 0000000000000000000000000000000000000000..97f6e2e7b0c7488d2a2620df737468d6d7e8fe0e
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xfBase.js
@@ -0,0 +1,8 @@
+export default {
+  init: function () {
+    return this.xf['@@transducer/init']();
+  },
+  result: function (result) {
+    return this.xf['@@transducer/result'](result);
+  }
+};
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xfilter.js b/server/node_modules/ramda/es/internal/_xfilter.js
new file mode 100644
index 0000000000000000000000000000000000000000..7af9f87dc0411e4baf1b2eefb2d711b173e3522e
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xfilter.js
@@ -0,0 +1,21 @@
+import _curry2 from './_curry2.js';
+import _xfBase from './_xfBase.js';
+
+var XFilter = /*#__PURE__*/function () {
+  function XFilter(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XFilter.prototype['@@transducer/init'] = _xfBase.init;
+  XFilter.prototype['@@transducer/result'] = _xfBase.result;
+  XFilter.prototype['@@transducer/step'] = function (result, input) {
+    return this.f(input) ? this.xf['@@transducer/step'](result, input) : result;
+  };
+
+  return XFilter;
+}();
+
+var _xfilter = /*#__PURE__*/_curry2(function _xfilter(f, xf) {
+  return new XFilter(f, xf);
+});
+export default _xfilter;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xfind.js b/server/node_modules/ramda/es/internal/_xfind.js
new file mode 100644
index 0000000000000000000000000000000000000000..3018c693526daf8ba4eb31467946f35915e3b302
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xfind.js
@@ -0,0 +1,32 @@
+import _curry2 from './_curry2.js';
+import _reduced from './_reduced.js';
+import _xfBase from './_xfBase.js';
+
+var XFind = /*#__PURE__*/function () {
+  function XFind(f, xf) {
+    this.xf = xf;
+    this.f = f;
+    this.found = false;
+  }
+  XFind.prototype['@@transducer/init'] = _xfBase.init;
+  XFind.prototype['@@transducer/result'] = function (result) {
+    if (!this.found) {
+      result = this.xf['@@transducer/step'](result, void 0);
+    }
+    return this.xf['@@transducer/result'](result);
+  };
+  XFind.prototype['@@transducer/step'] = function (result, input) {
+    if (this.f(input)) {
+      this.found = true;
+      result = _reduced(this.xf['@@transducer/step'](result, input));
+    }
+    return result;
+  };
+
+  return XFind;
+}();
+
+var _xfind = /*#__PURE__*/_curry2(function _xfind(f, xf) {
+  return new XFind(f, xf);
+});
+export default _xfind;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xfindIndex.js b/server/node_modules/ramda/es/internal/_xfindIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..69407458579ff540058d9f7f7495bf7a5a222891
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xfindIndex.js
@@ -0,0 +1,34 @@
+import _curry2 from './_curry2.js';
+import _reduced from './_reduced.js';
+import _xfBase from './_xfBase.js';
+
+var XFindIndex = /*#__PURE__*/function () {
+  function XFindIndex(f, xf) {
+    this.xf = xf;
+    this.f = f;
+    this.idx = -1;
+    this.found = false;
+  }
+  XFindIndex.prototype['@@transducer/init'] = _xfBase.init;
+  XFindIndex.prototype['@@transducer/result'] = function (result) {
+    if (!this.found) {
+      result = this.xf['@@transducer/step'](result, -1);
+    }
+    return this.xf['@@transducer/result'](result);
+  };
+  XFindIndex.prototype['@@transducer/step'] = function (result, input) {
+    this.idx += 1;
+    if (this.f(input)) {
+      this.found = true;
+      result = _reduced(this.xf['@@transducer/step'](result, this.idx));
+    }
+    return result;
+  };
+
+  return XFindIndex;
+}();
+
+var _xfindIndex = /*#__PURE__*/_curry2(function _xfindIndex(f, xf) {
+  return new XFindIndex(f, xf);
+});
+export default _xfindIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xfindLast.js b/server/node_modules/ramda/es/internal/_xfindLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..79a1cb729b2b8fa423be215b37ffafc2c8fd32b0
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xfindLast.js
@@ -0,0 +1,26 @@
+import _curry2 from './_curry2.js';
+import _xfBase from './_xfBase.js';
+
+var XFindLast = /*#__PURE__*/function () {
+  function XFindLast(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XFindLast.prototype['@@transducer/init'] = _xfBase.init;
+  XFindLast.prototype['@@transducer/result'] = function (result) {
+    return this.xf['@@transducer/result'](this.xf['@@transducer/step'](result, this.last));
+  };
+  XFindLast.prototype['@@transducer/step'] = function (result, input) {
+    if (this.f(input)) {
+      this.last = input;
+    }
+    return result;
+  };
+
+  return XFindLast;
+}();
+
+var _xfindLast = /*#__PURE__*/_curry2(function _xfindLast(f, xf) {
+  return new XFindLast(f, xf);
+});
+export default _xfindLast;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xfindLastIndex.js b/server/node_modules/ramda/es/internal/_xfindLastIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..fae8bf80976ee9b365833d862c71648ea4f9c8cc
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xfindLastIndex.js
@@ -0,0 +1,29 @@
+import _curry2 from './_curry2.js';
+import _xfBase from './_xfBase.js';
+
+var XFindLastIndex = /*#__PURE__*/function () {
+  function XFindLastIndex(f, xf) {
+    this.xf = xf;
+    this.f = f;
+    this.idx = -1;
+    this.lastIdx = -1;
+  }
+  XFindLastIndex.prototype['@@transducer/init'] = _xfBase.init;
+  XFindLastIndex.prototype['@@transducer/result'] = function (result) {
+    return this.xf['@@transducer/result'](this.xf['@@transducer/step'](result, this.lastIdx));
+  };
+  XFindLastIndex.prototype['@@transducer/step'] = function (result, input) {
+    this.idx += 1;
+    if (this.f(input)) {
+      this.lastIdx = this.idx;
+    }
+    return result;
+  };
+
+  return XFindLastIndex;
+}();
+
+var _xfindLastIndex = /*#__PURE__*/_curry2(function _xfindLastIndex(f, xf) {
+  return new XFindLastIndex(f, xf);
+});
+export default _xfindLastIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xmap.js b/server/node_modules/ramda/es/internal/_xmap.js
new file mode 100644
index 0000000000000000000000000000000000000000..3f0ec2d506065b8c6995af9e20c6d7e4998a5ca5
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xmap.js
@@ -0,0 +1,21 @@
+import _curry2 from './_curry2.js';
+import _xfBase from './_xfBase.js';
+
+var XMap = /*#__PURE__*/function () {
+  function XMap(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XMap.prototype['@@transducer/init'] = _xfBase.init;
+  XMap.prototype['@@transducer/result'] = _xfBase.result;
+  XMap.prototype['@@transducer/step'] = function (result, input) {
+    return this.xf['@@transducer/step'](result, this.f(input));
+  };
+
+  return XMap;
+}();
+
+var _xmap = /*#__PURE__*/_curry2(function _xmap(f, xf) {
+  return new XMap(f, xf);
+});
+export default _xmap;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xreduceBy.js b/server/node_modules/ramda/es/internal/_xreduceBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..92dee6988466742a368a355fd09c24ae6dd458a6
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xreduceBy.js
@@ -0,0 +1,41 @@
+import _curryN from './_curryN.js';
+import _has from './_has.js';
+import _xfBase from './_xfBase.js';
+
+var XReduceBy = /*#__PURE__*/function () {
+  function XReduceBy(valueFn, valueAcc, keyFn, xf) {
+    this.valueFn = valueFn;
+    this.valueAcc = valueAcc;
+    this.keyFn = keyFn;
+    this.xf = xf;
+    this.inputs = {};
+  }
+  XReduceBy.prototype['@@transducer/init'] = _xfBase.init;
+  XReduceBy.prototype['@@transducer/result'] = function (result) {
+    var key;
+    for (key in this.inputs) {
+      if (_has(key, this.inputs)) {
+        result = this.xf['@@transducer/step'](result, this.inputs[key]);
+        if (result['@@transducer/reduced']) {
+          result = result['@@transducer/value'];
+          break;
+        }
+      }
+    }
+    this.inputs = null;
+    return this.xf['@@transducer/result'](result);
+  };
+  XReduceBy.prototype['@@transducer/step'] = function (result, input) {
+    var key = this.keyFn(input);
+    this.inputs[key] = this.inputs[key] || [key, this.valueAcc];
+    this.inputs[key][1] = this.valueFn(this.inputs[key][1], input);
+    return result;
+  };
+
+  return XReduceBy;
+}();
+
+var _xreduceBy = /*#__PURE__*/_curryN(4, [], function _xreduceBy(valueFn, valueAcc, keyFn, xf) {
+  return new XReduceBy(valueFn, valueAcc, keyFn, xf);
+});
+export default _xreduceBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xtake.js b/server/node_modules/ramda/es/internal/_xtake.js
new file mode 100644
index 0000000000000000000000000000000000000000..73e9dcd32207d5c72bd7c740226dad28501137b1
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xtake.js
@@ -0,0 +1,25 @@
+import _curry2 from './_curry2.js';
+import _reduced from './_reduced.js';
+import _xfBase from './_xfBase.js';
+
+var XTake = /*#__PURE__*/function () {
+  function XTake(n, xf) {
+    this.xf = xf;
+    this.n = n;
+    this.i = 0;
+  }
+  XTake.prototype['@@transducer/init'] = _xfBase.init;
+  XTake.prototype['@@transducer/result'] = _xfBase.result;
+  XTake.prototype['@@transducer/step'] = function (result, input) {
+    this.i += 1;
+    var ret = this.n === 0 ? result : this.xf['@@transducer/step'](result, input);
+    return this.n >= 0 && this.i >= this.n ? _reduced(ret) : ret;
+  };
+
+  return XTake;
+}();
+
+var _xtake = /*#__PURE__*/_curry2(function _xtake(n, xf) {
+  return new XTake(n, xf);
+});
+export default _xtake;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xtakeWhile.js b/server/node_modules/ramda/es/internal/_xtakeWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..fc9088f082cfd1229322bdd00b1456043e21452d
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xtakeWhile.js
@@ -0,0 +1,22 @@
+import _curry2 from './_curry2.js';
+import _reduced from './_reduced.js';
+import _xfBase from './_xfBase.js';
+
+var XTakeWhile = /*#__PURE__*/function () {
+  function XTakeWhile(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XTakeWhile.prototype['@@transducer/init'] = _xfBase.init;
+  XTakeWhile.prototype['@@transducer/result'] = _xfBase.result;
+  XTakeWhile.prototype['@@transducer/step'] = function (result, input) {
+    return this.f(input) ? this.xf['@@transducer/step'](result, input) : _reduced(result);
+  };
+
+  return XTakeWhile;
+}();
+
+var _xtakeWhile = /*#__PURE__*/_curry2(function _xtakeWhile(f, xf) {
+  return new XTakeWhile(f, xf);
+});
+export default _xtakeWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xtap.js b/server/node_modules/ramda/es/internal/_xtap.js
new file mode 100644
index 0000000000000000000000000000000000000000..cd2bdbe0aa491434eafbf019142e866befb5da2a
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xtap.js
@@ -0,0 +1,22 @@
+import _curry2 from './_curry2.js';
+import _xfBase from './_xfBase.js';
+
+var XTap = /*#__PURE__*/function () {
+  function XTap(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XTap.prototype['@@transducer/init'] = _xfBase.init;
+  XTap.prototype['@@transducer/result'] = _xfBase.result;
+  XTap.prototype['@@transducer/step'] = function (result, input) {
+    this.f(input);
+    return this.xf['@@transducer/step'](result, input);
+  };
+
+  return XTap;
+}();
+
+var _xtap = /*#__PURE__*/_curry2(function _xtap(f, xf) {
+  return new XTap(f, xf);
+});
+export default _xtap;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/internal/_xwrap.js b/server/node_modules/ramda/es/internal/_xwrap.js
new file mode 100644
index 0000000000000000000000000000000000000000..12359b52978a11483908d323737f3a222c997562
--- /dev/null
+++ b/server/node_modules/ramda/es/internal/_xwrap.js
@@ -0,0 +1,20 @@
+var XWrap = /*#__PURE__*/function () {
+  function XWrap(fn) {
+    this.f = fn;
+  }
+  XWrap.prototype['@@transducer/init'] = function () {
+    throw new Error('init not implemented on XWrap');
+  };
+  XWrap.prototype['@@transducer/result'] = function (acc) {
+    return acc;
+  };
+  XWrap.prototype['@@transducer/step'] = function (acc, x) {
+    return this.f(acc, x);
+  };
+
+  return XWrap;
+}();
+
+export default function _xwrap(fn) {
+  return new XWrap(fn);
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/intersection.js b/server/node_modules/ramda/es/intersection.js
new file mode 100644
index 0000000000000000000000000000000000000000..c50c4d095f55e9369c94f0654b2ab33ae092f225
--- /dev/null
+++ b/server/node_modules/ramda/es/intersection.js
@@ -0,0 +1,35 @@
+import _includes from './internal/_includes.js';
+import _curry2 from './internal/_curry2.js';
+import _filter from './internal/_filter.js';
+import flip from './flip.js';
+import uniq from './uniq.js';
+
+/**
+ * Combines two lists into a set (i.e. no duplicates) composed of those
+ * elements common to both lists.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The list of elements found in both `list1` and `list2`.
+ * @see R.innerJoin
+ * @example
+ *
+ *      R.intersection([1,2,3,4], [7,6,5,4,3]); //=> [4, 3]
+ */
+var intersection = /*#__PURE__*/_curry2(function intersection(list1, list2) {
+  var lookupList, filteredList;
+  if (list1.length > list2.length) {
+    lookupList = list1;
+    filteredList = list2;
+  } else {
+    lookupList = list2;
+    filteredList = list1;
+  }
+  return uniq(_filter(flip(_includes)(lookupList), filteredList));
+});
+export default intersection;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/intersperse.js b/server/node_modules/ramda/es/intersperse.js
new file mode 100644
index 0000000000000000000000000000000000000000..adbaca396a5408e3624faa13c16ddb92d26d511e
--- /dev/null
+++ b/server/node_modules/ramda/es/intersperse.js
@@ -0,0 +1,35 @@
+import _checkForMethod from './internal/_checkForMethod.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Creates a new list with the separator interposed between elements.
+ *
+ * Dispatches to the `intersperse` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig a -> [a] -> [a]
+ * @param {*} separator The element to add to the list.
+ * @param {Array} list The list to be interposed.
+ * @return {Array} The new list.
+ * @example
+ *
+ *      R.intersperse('a', ['b', 'n', 'n', 's']); //=> ['b', 'a', 'n', 'a', 'n', 'a', 's']
+ */
+var intersperse = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('intersperse', function intersperse(separator, list) {
+  var out = [];
+  var idx = 0;
+  var length = list.length;
+  while (idx < length) {
+    if (idx === length - 1) {
+      out.push(list[idx]);
+    } else {
+      out.push(list[idx], separator);
+    }
+    idx += 1;
+  }
+  return out;
+}));
+export default intersperse;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/into.js b/server/node_modules/ramda/es/into.js
new file mode 100644
index 0000000000000000000000000000000000000000..bfa7fd713d2587b3c0170ab1ea0b379dfe2fa09c
--- /dev/null
+++ b/server/node_modules/ramda/es/into.js
@@ -0,0 +1,49 @@
+import _clone from './internal/_clone.js';
+import _curry3 from './internal/_curry3.js';
+import _isTransformer from './internal/_isTransformer.js';
+import _reduce from './internal/_reduce.js';
+import _stepCat from './internal/_stepCat.js';
+
+/**
+ * Transforms the items of the list with the transducer and appends the
+ * transformed items to the accumulator using an appropriate iterator function
+ * based on the accumulator type.
+ *
+ * The accumulator can be an array, string, object or a transformer. Iterated
+ * items will be appended to arrays and concatenated to strings. Objects will
+ * be merged directly or 2-item arrays will be merged as key, value pairs.
+ *
+ * The accumulator can also be a transformer object that provides a 2-arity
+ * reducing iterator function, step, 0-arity initial value function, init, and
+ * 1-arity result extraction function result. The step function is used as the
+ * iterator function in reduce. The result function is used to convert the
+ * final accumulator into the return type and in most cases is R.identity. The
+ * init function is used to provide the initial accumulator.
+ *
+ * The iteration is performed with [`R.reduce`](#reduce) after initializing the
+ * transducer.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig a -> (b -> b) -> [c] -> a
+ * @param {*} acc The initial accumulator value.
+ * @param {Function} xf The transducer function. Receives a transformer and returns a transformer.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.transduce
+ * @example
+ *
+ *      const numbers = [1, 2, 3, 4];
+ *      const transducer = R.compose(R.map(R.add(1)), R.take(2));
+ *
+ *      R.into([], transducer, numbers); //=> [2, 3]
+ *
+ *      const intoArray = R.into([]);
+ *      intoArray(transducer, numbers); //=> [2, 3]
+ */
+var into = /*#__PURE__*/_curry3(function into(acc, xf, list) {
+  return _isTransformer(acc) ? _reduce(xf(acc), acc['@@transducer/init'](), list) : _reduce(xf(_stepCat(acc)), _clone(acc, [], [], false), list);
+});
+export default into;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/invert.js b/server/node_modules/ramda/es/invert.js
new file mode 100644
index 0000000000000000000000000000000000000000..3d7dea63923aa28abe1962b2ed13523395557476
--- /dev/null
+++ b/server/node_modules/ramda/es/invert.js
@@ -0,0 +1,42 @@
+import _curry1 from './internal/_curry1.js';
+import _has from './internal/_has.js';
+import keys from './keys.js';
+
+/**
+ * Same as [`R.invertObj`](#invertObj), however this accounts for objects with
+ * duplicate values by putting the values into an array.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig {s: x} -> {x: [ s, ... ]}
+ * @param {Object} obj The object or array to invert
+ * @return {Object} out A new object with keys in an array.
+ * @see R.invertObj
+ * @example
+ *
+ *      const raceResultsByFirstName = {
+ *        first: 'alice',
+ *        second: 'jake',
+ *        third: 'alice',
+ *      };
+ *      R.invert(raceResultsByFirstName);
+ *      //=> { 'alice': ['first', 'third'], 'jake':['second'] }
+ */
+var invert = /*#__PURE__*/_curry1(function invert(obj) {
+  var props = keys(obj);
+  var len = props.length;
+  var idx = 0;
+  var out = {};
+
+  while (idx < len) {
+    var key = props[idx];
+    var val = obj[key];
+    var list = _has(val, out) ? out[val] : out[val] = [];
+    list[list.length] = key;
+    idx += 1;
+  }
+  return out;
+});
+export default invert;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/invertObj.js b/server/node_modules/ramda/es/invertObj.js
new file mode 100644
index 0000000000000000000000000000000000000000..905cc6083803843d207b3fa596225c96a1963b1c
--- /dev/null
+++ b/server/node_modules/ramda/es/invertObj.js
@@ -0,0 +1,44 @@
+import _curry1 from './internal/_curry1.js';
+import keys from './keys.js';
+
+/**
+ * Returns a new object with the keys of the given object as values, and the
+ * values of the given object, which are coerced to strings, as keys. Note
+ * that the last key found is preferred when handling the same value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig {s: x} -> {x: s}
+ * @param {Object} obj The object or array to invert
+ * @return {Object} out A new object
+ * @see R.invert
+ * @example
+ *
+ *      const raceResults = {
+ *        first: 'alice',
+ *        second: 'jake'
+ *      };
+ *      R.invertObj(raceResults);
+ *      //=> { 'alice': 'first', 'jake':'second' }
+ *
+ *      // Alternatively:
+ *      const raceResults = ['alice', 'jake'];
+ *      R.invertObj(raceResults);
+ *      //=> { 'alice': '0', 'jake':'1' }
+ */
+var invertObj = /*#__PURE__*/_curry1(function invertObj(obj) {
+  var props = keys(obj);
+  var len = props.length;
+  var idx = 0;
+  var out = {};
+
+  while (idx < len) {
+    var key = props[idx];
+    out[obj[key]] = key;
+    idx += 1;
+  }
+  return out;
+});
+export default invertObj;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/invoker.js b/server/node_modules/ramda/es/invoker.js
new file mode 100644
index 0000000000000000000000000000000000000000..784a965964bd144277235efd133e3f5a94fe3202
--- /dev/null
+++ b/server/node_modules/ramda/es/invoker.js
@@ -0,0 +1,42 @@
+import _curry2 from './internal/_curry2.js';
+import _isFunction from './internal/_isFunction.js';
+import curryN from './curryN.js';
+import toString from './toString.js';
+
+/**
+ * Turns a named method with a specified arity into a function that can be
+ * called directly supplied with arguments and a target object.
+ *
+ * The returned function is curried and accepts `arity + 1` parameters where
+ * the final parameter is the target object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig Number -> String -> (a -> b -> ... -> n -> Object -> *)
+ * @param {Number} arity Number of arguments the returned function should take
+ *        before the target object.
+ * @param {String} method Name of the method to call.
+ * @return {Function} A new curried function.
+ * @see R.construct
+ * @example
+ *
+ *      const sliceFrom = R.invoker(1, 'slice');
+ *      sliceFrom(6, 'abcdefghijklm'); //=> 'ghijklm'
+ *      const sliceFrom6 = R.invoker(2, 'slice')(6);
+ *      sliceFrom6(8, 'abcdefghijklm'); //=> 'gh'
+ * @symb R.invoker(0, 'method')(o) = o['method']()
+ * @symb R.invoker(1, 'method')(a, o) = o['method'](a)
+ * @symb R.invoker(2, 'method')(a, b, o) = o['method'](a, b)
+ */
+var invoker = /*#__PURE__*/_curry2(function invoker(arity, method) {
+  return curryN(arity + 1, function () {
+    var target = arguments[arity];
+    if (target != null && _isFunction(target[method])) {
+      return target[method].apply(target, Array.prototype.slice.call(arguments, 0, arity));
+    }
+    throw new TypeError(toString(target) + ' does not have a method named "' + method + '"');
+  });
+});
+export default invoker;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/is.js b/server/node_modules/ramda/es/is.js
new file mode 100644
index 0000000000000000000000000000000000000000..9853d0250c3d6db829d7518d2e7c0e29e876522a
--- /dev/null
+++ b/server/node_modules/ramda/es/is.js
@@ -0,0 +1,29 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * See if an object (`val`) is an instance of the supplied constructor. This
+ * function will check up the inheritance chain, if any.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Type
+ * @sig (* -> {*}) -> a -> Boolean
+ * @param {Object} ctor A constructor
+ * @param {*} val The value to test
+ * @return {Boolean}
+ * @example
+ *
+ *      R.is(Object, {}); //=> true
+ *      R.is(Number, 1); //=> true
+ *      R.is(Object, 1); //=> false
+ *      R.is(String, 's'); //=> true
+ *      R.is(String, new String('')); //=> true
+ *      R.is(Object, new String('')); //=> true
+ *      R.is(Object, 's'); //=> false
+ *      R.is(Number, {}); //=> false
+ */
+var is = /*#__PURE__*/_curry2(function is(Ctor, val) {
+  return val != null && val.constructor === Ctor || val instanceof Ctor;
+});
+export default is;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/isEmpty.js b/server/node_modules/ramda/es/isEmpty.js
new file mode 100644
index 0000000000000000000000000000000000000000..795de2b829c0b6005a5eedffc6f8100598ac0a44
--- /dev/null
+++ b/server/node_modules/ramda/es/isEmpty.js
@@ -0,0 +1,29 @@
+import _curry1 from './internal/_curry1.js';
+import empty from './empty.js';
+import equals from './equals.js';
+
+/**
+ * Returns `true` if the given value is its type's empty value; `false`
+ * otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig a -> Boolean
+ * @param {*} x
+ * @return {Boolean}
+ * @see R.empty
+ * @example
+ *
+ *      R.isEmpty([1, 2, 3]);   //=> false
+ *      R.isEmpty([]);          //=> true
+ *      R.isEmpty('');          //=> true
+ *      R.isEmpty(null);        //=> false
+ *      R.isEmpty({});          //=> true
+ *      R.isEmpty({length: 0}); //=> false
+ */
+var isEmpty = /*#__PURE__*/_curry1(function isEmpty(x) {
+  return x != null && equals(x, empty(x));
+});
+export default isEmpty;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/isNil.js b/server/node_modules/ramda/es/isNil.js
new file mode 100644
index 0000000000000000000000000000000000000000..a5b5a552254e59503812964c4c990f30c91d6340
--- /dev/null
+++ b/server/node_modules/ramda/es/isNil.js
@@ -0,0 +1,23 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Checks if the input value is `null` or `undefined`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Type
+ * @sig * -> Boolean
+ * @param {*} x The value to test.
+ * @return {Boolean} `true` if `x` is `undefined` or `null`, otherwise `false`.
+ * @example
+ *
+ *      R.isNil(null); //=> true
+ *      R.isNil(undefined); //=> true
+ *      R.isNil(0); //=> false
+ *      R.isNil([]); //=> false
+ */
+var isNil = /*#__PURE__*/_curry1(function isNil(x) {
+  return x == null;
+});
+export default isNil;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/join.js b/server/node_modules/ramda/es/join.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d8f75909300b427132f2a57c610d5e7ca79f735
--- /dev/null
+++ b/server/node_modules/ramda/es/join.js
@@ -0,0 +1,23 @@
+import invoker from './invoker.js';
+
+/**
+ * Returns a string made by inserting the `separator` between each element and
+ * concatenating all the elements into a single string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig String -> [a] -> String
+ * @param {Number|String} separator The string used to separate the elements.
+ * @param {Array} xs The elements to join into a string.
+ * @return {String} str The string made by concatenating `xs` with `separator`.
+ * @see R.split
+ * @example
+ *
+ *      const spacer = R.join(' ');
+ *      spacer(['a', 2, 3.4]);   //=> 'a 2 3.4'
+ *      R.join('|', [1, 2, 3]);    //=> '1|2|3'
+ */
+var join = /*#__PURE__*/invoker(1, 'join');
+export default join;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/juxt.js b/server/node_modules/ramda/es/juxt.js
new file mode 100644
index 0000000000000000000000000000000000000000..f444645f383cad0e34b963b6a4509a9c22cd852e
--- /dev/null
+++ b/server/node_modules/ramda/es/juxt.js
@@ -0,0 +1,26 @@
+import _curry1 from './internal/_curry1.js';
+import converge from './converge.js';
+
+/**
+ * juxt applies a list of functions to a list of values.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Function
+ * @sig [(a, b, ..., m) -> n] -> ((a, b, ..., m) -> [n])
+ * @param {Array} fns An array of functions
+ * @return {Function} A function that returns a list of values after applying each of the original `fns` to its parameters.
+ * @see R.applySpec
+ * @example
+ *
+ *      const getRange = R.juxt([Math.min, Math.max]);
+ *      getRange(3, 4, 9, -3); //=> [-3, 9]
+ * @symb R.juxt([f, g, h])(a, b) = [f(a, b), g(a, b), h(a, b)]
+ */
+var juxt = /*#__PURE__*/_curry1(function juxt(fns) {
+  return converge(function () {
+    return Array.prototype.slice.call(arguments, 0);
+  }, fns);
+});
+export default juxt;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/keys.js b/server/node_modules/ramda/es/keys.js
new file mode 100644
index 0000000000000000000000000000000000000000..825e0ac607ac4da874632bea8585122ebc3dbd12
--- /dev/null
+++ b/server/node_modules/ramda/es/keys.js
@@ -0,0 +1,70 @@
+import _curry1 from './internal/_curry1.js';
+import _has from './internal/_has.js';
+import _isArguments from './internal/_isArguments.js';
+
+// cover IE < 9 keys issues
+var hasEnumBug = ! /*#__PURE__*/{ toString: null }.propertyIsEnumerable('toString');
+var nonEnumerableProps = ['constructor', 'valueOf', 'isPrototypeOf', 'toString', 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
+// Safari bug
+var hasArgsEnumBug = /*#__PURE__*/function () {
+  'use strict';
+
+  return arguments.propertyIsEnumerable('length');
+}();
+
+var contains = function contains(list, item) {
+  var idx = 0;
+  while (idx < list.length) {
+    if (list[idx] === item) {
+      return true;
+    }
+    idx += 1;
+  }
+  return false;
+};
+
+/**
+ * Returns a list containing the names of all the enumerable own properties of
+ * the supplied object.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {k: v} -> [k]
+ * @param {Object} obj The object to extract properties from
+ * @return {Array} An array of the object's own properties.
+ * @see R.keysIn, R.values
+ * @example
+ *
+ *      R.keys({a: 1, b: 2, c: 3}); //=> ['a', 'b', 'c']
+ */
+var keys = typeof Object.keys === 'function' && !hasArgsEnumBug ? /*#__PURE__*/_curry1(function keys(obj) {
+  return Object(obj) !== obj ? [] : Object.keys(obj);
+}) : /*#__PURE__*/_curry1(function keys(obj) {
+  if (Object(obj) !== obj) {
+    return [];
+  }
+  var prop, nIdx;
+  var ks = [];
+  var checkArgsLength = hasArgsEnumBug && _isArguments(obj);
+  for (prop in obj) {
+    if (_has(prop, obj) && (!checkArgsLength || prop !== 'length')) {
+      ks[ks.length] = prop;
+    }
+  }
+  if (hasEnumBug) {
+    nIdx = nonEnumerableProps.length - 1;
+    while (nIdx >= 0) {
+      prop = nonEnumerableProps[nIdx];
+      if (_has(prop, obj) && !contains(ks, prop)) {
+        ks[ks.length] = prop;
+      }
+      nIdx -= 1;
+    }
+  }
+  return ks;
+});
+export default keys;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/keysIn.js b/server/node_modules/ramda/es/keysIn.js
new file mode 100644
index 0000000000000000000000000000000000000000..894da8e2cefa24abd4dc986e3382d43e58d63437
--- /dev/null
+++ b/server/node_modules/ramda/es/keysIn.js
@@ -0,0 +1,32 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Returns a list containing the names of all the properties of the supplied
+ * object, including prototype properties.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Object
+ * @sig {k: v} -> [k]
+ * @param {Object} obj The object to extract properties from
+ * @return {Array} An array of the object's own and prototype properties.
+ * @see R.keys, R.valuesIn
+ * @example
+ *
+ *      const F = function() { this.x = 'X'; };
+ *      F.prototype.y = 'Y';
+ *      const f = new F();
+ *      R.keysIn(f); //=> ['x', 'y']
+ */
+var keysIn = /*#__PURE__*/_curry1(function keysIn(obj) {
+  var prop;
+  var ks = [];
+  for (prop in obj) {
+    ks[ks.length] = prop;
+  }
+  return ks;
+});
+export default keysIn;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/last.js b/server/node_modules/ramda/es/last.js
new file mode 100644
index 0000000000000000000000000000000000000000..aa7026a743ebbba3704eb70233fd7b969fd5c218
--- /dev/null
+++ b/server/node_modules/ramda/es/last.js
@@ -0,0 +1,24 @@
+import nth from './nth.js';
+
+/**
+ * Returns the last element of the given list or string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.4
+ * @category List
+ * @sig [a] -> a | Undefined
+ * @sig String -> String
+ * @param {*} list
+ * @return {*}
+ * @see R.init, R.head, R.tail
+ * @example
+ *
+ *      R.last(['fi', 'fo', 'fum']); //=> 'fum'
+ *      R.last([]); //=> undefined
+ *
+ *      R.last('abc'); //=> 'c'
+ *      R.last(''); //=> ''
+ */
+var last = /*#__PURE__*/nth(-1);
+export default last;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/lastIndexOf.js b/server/node_modules/ramda/es/lastIndexOf.js
new file mode 100644
index 0000000000000000000000000000000000000000..9eaad4de73afb3908514c23a91351a5dd5507598
--- /dev/null
+++ b/server/node_modules/ramda/es/lastIndexOf.js
@@ -0,0 +1,38 @@
+import _curry2 from './internal/_curry2.js';
+import _isArray from './internal/_isArray.js';
+import equals from './equals.js';
+
+/**
+ * Returns the position of the last occurrence of an item in an array, or -1 if
+ * the item is not included in the array. [`R.equals`](#equals) is used to
+ * determine equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Number
+ * @param {*} target The item to find.
+ * @param {Array} xs The array to search in.
+ * @return {Number} the index of the target, or -1 if the target is not found.
+ * @see R.indexOf
+ * @example
+ *
+ *      R.lastIndexOf(3, [-1,3,3,0,1,2,3,4]); //=> 6
+ *      R.lastIndexOf(10, [1,2,3,4]); //=> -1
+ */
+var lastIndexOf = /*#__PURE__*/_curry2(function lastIndexOf(target, xs) {
+  if (typeof xs.lastIndexOf === 'function' && !_isArray(xs)) {
+    return xs.lastIndexOf(target);
+  } else {
+    var idx = xs.length - 1;
+    while (idx >= 0) {
+      if (equals(xs[idx], target)) {
+        return idx;
+      }
+      idx -= 1;
+    }
+    return -1;
+  }
+});
+export default lastIndexOf;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/length.js b/server/node_modules/ramda/es/length.js
new file mode 100644
index 0000000000000000000000000000000000000000..fe8eb076956d0973e5b11807f1958a3e854d9b93
--- /dev/null
+++ b/server/node_modules/ramda/es/length.js
@@ -0,0 +1,22 @@
+import _curry1 from './internal/_curry1.js';
+import _isNumber from './internal/_isNumber.js';
+
+/**
+ * Returns the number of elements in the array by returning `list.length`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig [a] -> Number
+ * @param {Array} list The array to inspect.
+ * @return {Number} The length of the array.
+ * @example
+ *
+ *      R.length([]); //=> 0
+ *      R.length([1, 2, 3]); //=> 3
+ */
+var length = /*#__PURE__*/_curry1(function length(list) {
+  return list != null && _isNumber(list.length) ? list.length : NaN;
+});
+export default length;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/lens.js b/server/node_modules/ramda/es/lens.js
new file mode 100644
index 0000000000000000000000000000000000000000..dd943596daf45c65892344c6e9280b18a98ee2cd
--- /dev/null
+++ b/server/node_modules/ramda/es/lens.js
@@ -0,0 +1,36 @@
+import _curry2 from './internal/_curry2.js';
+import map from './map.js';
+
+/**
+ * Returns a lens for the given getter and setter functions. The getter "gets"
+ * the value of the focus; the setter "sets" the value of the focus. The setter
+ * should not mutate the data structure.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig (s -> a) -> ((a, s) -> s) -> Lens s a
+ * @param {Function} getter
+ * @param {Function} setter
+ * @return {Lens}
+ * @see R.view, R.set, R.over, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const xLens = R.lens(R.prop('x'), R.assoc('x'));
+ *
+ *      R.view(xLens, {x: 1, y: 2});            //=> 1
+ *      R.set(xLens, 4, {x: 1, y: 2});          //=> {x: 4, y: 2}
+ *      R.over(xLens, R.negate, {x: 1, y: 2});  //=> {x: -1, y: 2}
+ */
+var lens = /*#__PURE__*/_curry2(function lens(getter, setter) {
+  return function (toFunctorFn) {
+    return function (target) {
+      return map(function (focus) {
+        return setter(focus, target);
+      }, toFunctorFn(getter(target)));
+    };
+  };
+});
+export default lens;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/lensIndex.js b/server/node_modules/ramda/es/lensIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..a2d964ca7a80b4a79c4b1e4dce04f8989c6301e3
--- /dev/null
+++ b/server/node_modules/ramda/es/lensIndex.js
@@ -0,0 +1,29 @@
+import _curry1 from './internal/_curry1.js';
+import lens from './lens.js';
+import nth from './nth.js';
+import update from './update.js';
+
+/**
+ * Returns a lens whose focus is the specified index.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Number -> Lens s a
+ * @param {Number} n
+ * @return {Lens}
+ * @see R.view, R.set, R.over
+ * @example
+ *
+ *      const headLens = R.lensIndex(0);
+ *
+ *      R.view(headLens, ['a', 'b', 'c']);            //=> 'a'
+ *      R.set(headLens, 'x', ['a', 'b', 'c']);        //=> ['x', 'b', 'c']
+ *      R.over(headLens, R.toUpper, ['a', 'b', 'c']); //=> ['A', 'b', 'c']
+ */
+var lensIndex = /*#__PURE__*/_curry1(function lensIndex(n) {
+  return lens(nth(n), update(n));
+});
+export default lensIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/lensPath.js b/server/node_modules/ramda/es/lensPath.js
new file mode 100644
index 0000000000000000000000000000000000000000..199b35b2292ba4216177aef7873096cb1b84fa78
--- /dev/null
+++ b/server/node_modules/ramda/es/lensPath.js
@@ -0,0 +1,33 @@
+import _curry1 from './internal/_curry1.js';
+import assocPath from './assocPath.js';
+import lens from './lens.js';
+import path from './path.js';
+
+/**
+ * Returns a lens whose focus is the specified path.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig [Idx] -> Lens s a
+ * @param {Array} path The path to use.
+ * @return {Lens}
+ * @see R.view, R.set, R.over
+ * @example
+ *
+ *      const xHeadYLens = R.lensPath(['x', 0, 'y']);
+ *
+ *      R.view(xHeadYLens, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
+ *      //=> 2
+ *      R.set(xHeadYLens, 1, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
+ *      //=> {x: [{y: 1, z: 3}, {y: 4, z: 5}]}
+ *      R.over(xHeadYLens, R.negate, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
+ *      //=> {x: [{y: -2, z: 3}, {y: 4, z: 5}]}
+ */
+var lensPath = /*#__PURE__*/_curry1(function lensPath(p) {
+  return lens(path(p), assocPath(p));
+});
+export default lensPath;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/lensProp.js b/server/node_modules/ramda/es/lensProp.js
new file mode 100644
index 0000000000000000000000000000000000000000..b18f8ed70f1033c0fe6fec3a59fa0d5601951fae
--- /dev/null
+++ b/server/node_modules/ramda/es/lensProp.js
@@ -0,0 +1,29 @@
+import _curry1 from './internal/_curry1.js';
+import assoc from './assoc.js';
+import lens from './lens.js';
+import prop from './prop.js';
+
+/**
+ * Returns a lens whose focus is the specified property.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig String -> Lens s a
+ * @param {String} k
+ * @return {Lens}
+ * @see R.view, R.set, R.over
+ * @example
+ *
+ *      const xLens = R.lensProp('x');
+ *
+ *      R.view(xLens, {x: 1, y: 2});            //=> 1
+ *      R.set(xLens, 4, {x: 1, y: 2});          //=> {x: 4, y: 2}
+ *      R.over(xLens, R.negate, {x: 1, y: 2});  //=> {x: -1, y: 2}
+ */
+var lensProp = /*#__PURE__*/_curry1(function lensProp(k) {
+  return lens(prop(k), assoc(k));
+});
+export default lensProp;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/lift.js b/server/node_modules/ramda/es/lift.js
new file mode 100644
index 0000000000000000000000000000000000000000..58d8d4fae0aa7bff9d17cf3eeafc86b86f011336
--- /dev/null
+++ b/server/node_modules/ramda/es/lift.js
@@ -0,0 +1,29 @@
+import _curry1 from './internal/_curry1.js';
+import liftN from './liftN.js';
+
+/**
+ * "lifts" a function of arity > 1 so that it may "map over" a list, Function or other
+ * object that satisfies the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Function
+ * @sig (*... -> *) -> ([*]... -> [*])
+ * @param {Function} fn The function to lift into higher context
+ * @return {Function} The lifted function.
+ * @see R.liftN
+ * @example
+ *
+ *      const madd3 = R.lift((a, b, c) => a + b + c);
+ *
+ *      madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
+ *
+ *      const madd5 = R.lift((a, b, c, d, e) => a + b + c + d + e);
+ *
+ *      madd5([1,2], [3], [4, 5], [6], [7, 8]); //=> [21, 22, 22, 23, 22, 23, 23, 24]
+ */
+var lift = /*#__PURE__*/_curry1(function lift(fn) {
+  return liftN(fn.length, fn);
+});
+export default lift;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/liftN.js b/server/node_modules/ramda/es/liftN.js
new file mode 100644
index 0000000000000000000000000000000000000000..c2c2be3354bcfdd152610fe4b31f1d37aab63821
--- /dev/null
+++ b/server/node_modules/ramda/es/liftN.js
@@ -0,0 +1,30 @@
+import _curry2 from './internal/_curry2.js';
+import _reduce from './internal/_reduce.js';
+import ap from './ap.js';
+import curryN from './curryN.js';
+import map from './map.js';
+
+/**
+ * "lifts" a function to be the specified arity, so that it may "map over" that
+ * many lists, Functions or other objects that satisfy the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Function
+ * @sig Number -> (*... -> *) -> ([*]... -> [*])
+ * @param {Function} fn The function to lift into higher context
+ * @return {Function} The lifted function.
+ * @see R.lift, R.ap
+ * @example
+ *
+ *      const madd3 = R.liftN(3, (...args) => R.sum(args));
+ *      madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
+ */
+var liftN = /*#__PURE__*/_curry2(function liftN(arity, fn) {
+  var lifted = curryN(arity, fn);
+  return curryN(arity, function () {
+    return _reduce(ap, map(lifted, arguments[0]), Array.prototype.slice.call(arguments, 1));
+  });
+});
+export default liftN;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/lt.js b/server/node_modules/ramda/es/lt.js
new file mode 100644
index 0000000000000000000000000000000000000000..74876203feaa69c73df8d4cbde1517cbf553bc01
--- /dev/null
+++ b/server/node_modules/ramda/es/lt.js
@@ -0,0 +1,27 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns `true` if the first argument is less than the second; `false`
+ * otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @see R.gt
+ * @example
+ *
+ *      R.lt(2, 1); //=> false
+ *      R.lt(2, 2); //=> false
+ *      R.lt(2, 3); //=> true
+ *      R.lt('a', 'z'); //=> true
+ *      R.lt('z', 'a'); //=> false
+ */
+var lt = /*#__PURE__*/_curry2(function lt(a, b) {
+  return a < b;
+});
+export default lt;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/lte.js b/server/node_modules/ramda/es/lte.js
new file mode 100644
index 0000000000000000000000000000000000000000..342cc9148b8b2ae51e6f70f573c0db578fe45dcf
--- /dev/null
+++ b/server/node_modules/ramda/es/lte.js
@@ -0,0 +1,27 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns `true` if the first argument is less than or equal to the second;
+ * `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {Number} a
+ * @param {Number} b
+ * @return {Boolean}
+ * @see R.gte
+ * @example
+ *
+ *      R.lte(2, 1); //=> false
+ *      R.lte(2, 2); //=> true
+ *      R.lte(2, 3); //=> true
+ *      R.lte('a', 'z'); //=> true
+ *      R.lte('z', 'a'); //=> false
+ */
+var lte = /*#__PURE__*/_curry2(function lte(a, b) {
+  return a <= b;
+});
+export default lte;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/map.js b/server/node_modules/ramda/es/map.js
new file mode 100644
index 0000000000000000000000000000000000000000..fe10f26f9ac35cbd7c57f2b446cdd2950459eebc
--- /dev/null
+++ b/server/node_modules/ramda/es/map.js
@@ -0,0 +1,59 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _map from './internal/_map.js';
+import _reduce from './internal/_reduce.js';
+import _xmap from './internal/_xmap.js';
+import curryN from './curryN.js';
+import keys from './keys.js';
+
+/**
+ * Takes a function and
+ * a [functor](https://github.com/fantasyland/fantasy-land#functor),
+ * applies the function to each of the functor's values, and returns
+ * a functor of the same shape.
+ *
+ * Ramda provides suitable `map` implementations for `Array` and `Object`,
+ * so this function may be applied to `[1, 2, 3]` or `{x: 1, y: 2, z: 3}`.
+ *
+ * Dispatches to the `map` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * Also treats functions as functors and will compose them together.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Functor f => (a -> b) -> f a -> f b
+ * @param {Function} fn The function to be called on every element of the input `list`.
+ * @param {Array} list The list to be iterated over.
+ * @return {Array} The new list.
+ * @see R.transduce, R.addIndex
+ * @example
+ *
+ *      const double = x => x * 2;
+ *
+ *      R.map(double, [1, 2, 3]); //=> [2, 4, 6]
+ *
+ *      R.map(double, {x: 1, y: 2, z: 3}); //=> {x: 2, y: 4, z: 6}
+ * @symb R.map(f, [a, b]) = [f(a), f(b)]
+ * @symb R.map(f, { x: a, y: b }) = { x: f(a), y: f(b) }
+ * @symb R.map(f, functor_o) = functor_o.map(f)
+ */
+var map = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/map', 'map'], _xmap, function map(fn, functor) {
+  switch (Object.prototype.toString.call(functor)) {
+    case '[object Function]':
+      return curryN(functor.length, function () {
+        return fn.call(this, functor.apply(this, arguments));
+      });
+    case '[object Object]':
+      return _reduce(function (acc, key) {
+        acc[key] = fn(functor[key]);
+        return acc;
+      }, {}, keys(functor));
+    default:
+      return _map(fn, functor);
+  }
+}));
+export default map;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mapAccum.js b/server/node_modules/ramda/es/mapAccum.js
new file mode 100644
index 0000000000000000000000000000000000000000..48dbf113f6cfa52a5fd81dec4105f8f922bcf8f1
--- /dev/null
+++ b/server/node_modules/ramda/es/mapAccum.js
@@ -0,0 +1,49 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * The `mapAccum` function behaves like a combination of map and reduce; it
+ * applies a function to each element of a list, passing an accumulating
+ * parameter from left to right, and returning a final value of this
+ * accumulator together with the new list.
+ *
+ * The iterator function receives two arguments, *acc* and *value*, and should
+ * return a tuple *[acc, value]*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig ((acc, x) -> (acc, y)) -> acc -> [x] -> (acc, [y])
+ * @param {Function} fn The function to be called on every element of the input `list`.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.scan, R.addIndex, R.mapAccumRight
+ * @example
+ *
+ *      const digits = ['1', '2', '3', '4'];
+ *      const appender = (a, b) => [a + b, a + b];
+ *
+ *      R.mapAccum(appender, 0, digits); //=> ['01234', ['01', '012', '0123', '01234']]
+ * @symb R.mapAccum(f, a, [b, c, d]) = [
+ *   f(f(f(a, b)[0], c)[0], d)[0],
+ *   [
+ *     f(a, b)[1],
+ *     f(f(a, b)[0], c)[1],
+ *     f(f(f(a, b)[0], c)[0], d)[1]
+ *   ]
+ * ]
+ */
+var mapAccum = /*#__PURE__*/_curry3(function mapAccum(fn, acc, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [];
+  var tuple = [acc];
+  while (idx < len) {
+    tuple = fn(tuple[0], list[idx]);
+    result[idx] = tuple[1];
+    idx += 1;
+  }
+  return [tuple[0], result];
+});
+export default mapAccum;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mapAccumRight.js b/server/node_modules/ramda/es/mapAccumRight.js
new file mode 100644
index 0000000000000000000000000000000000000000..ee56c584b9ab60050591a8eede8175d334709283
--- /dev/null
+++ b/server/node_modules/ramda/es/mapAccumRight.js
@@ -0,0 +1,51 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * The `mapAccumRight` function behaves like a combination of map and reduce; it
+ * applies a function to each element of a list, passing an accumulating
+ * parameter from right to left, and returning a final value of this
+ * accumulator together with the new list.
+ *
+ * Similar to [`mapAccum`](#mapAccum), except moves through the input list from
+ * the right to the left.
+ *
+ * The iterator function receives two arguments, *acc* and *value*, and should
+ * return a tuple *[acc, value]*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig ((acc, x) -> (acc, y)) -> acc -> [x] -> (acc, [y])
+ * @param {Function} fn The function to be called on every element of the input `list`.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.addIndex, R.mapAccum
+ * @example
+ *
+ *      const digits = ['1', '2', '3', '4'];
+ *      const appender = (a, b) => [b + a, b + a];
+ *
+ *      R.mapAccumRight(appender, 5, digits); //=> ['12345', ['12345', '2345', '345', '45']]
+ * @symb R.mapAccumRight(f, a, [b, c, d]) = [
+ *   f(f(f(a, d)[0], c)[0], b)[0],
+ *   [
+ *     f(a, d)[1],
+ *     f(f(a, d)[0], c)[1],
+ *     f(f(f(a, d)[0], c)[0], b)[1]
+ *   ]
+ * ]
+ */
+var mapAccumRight = /*#__PURE__*/_curry3(function mapAccumRight(fn, acc, list) {
+  var idx = list.length - 1;
+  var result = [];
+  var tuple = [acc];
+  while (idx >= 0) {
+    tuple = fn(tuple[0], list[idx]);
+    result[idx] = tuple[1];
+    idx -= 1;
+  }
+  return [tuple[0], result];
+});
+export default mapAccumRight;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mapObjIndexed.js b/server/node_modules/ramda/es/mapObjIndexed.js
new file mode 100644
index 0000000000000000000000000000000000000000..79210c46763bb8838f8f696bcb817c4e58dc39c5
--- /dev/null
+++ b/server/node_modules/ramda/es/mapObjIndexed.js
@@ -0,0 +1,32 @@
+import _curry2 from './internal/_curry2.js';
+import _reduce from './internal/_reduce.js';
+import keys from './keys.js';
+
+/**
+ * An Object-specific version of [`map`](#map). The function is applied to three
+ * arguments: *(value, key, obj)*. If only the value is significant, use
+ * [`map`](#map) instead.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig ((*, String, Object) -> *) -> Object -> Object
+ * @param {Function} fn
+ * @param {Object} obj
+ * @return {Object}
+ * @see R.map
+ * @example
+ *
+ *      const xyz = { x: 1, y: 2, z: 3 };
+ *      const prependKeyAndDouble = (num, key, obj) => key + (num * 2);
+ *
+ *      R.mapObjIndexed(prependKeyAndDouble, xyz); //=> { x: 'x2', y: 'y4', z: 'z6' }
+ */
+var mapObjIndexed = /*#__PURE__*/_curry2(function mapObjIndexed(fn, obj) {
+  return _reduce(function (acc, key) {
+    acc[key] = fn(obj[key], key, obj);
+    return acc;
+  }, {}, keys(obj));
+});
+export default mapObjIndexed;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/match.js b/server/node_modules/ramda/es/match.js
new file mode 100644
index 0000000000000000000000000000000000000000..aa020b3c4164eb710c21ef7fe52cae4587c4dec3
--- /dev/null
+++ b/server/node_modules/ramda/es/match.js
@@ -0,0 +1,27 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Tests a regular expression against a String. Note that this function will
+ * return an empty array when there are no matches. This differs from
+ * [`String.prototype.match`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match)
+ * which returns `null` when there are no matches.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category String
+ * @sig RegExp -> String -> [String | Undefined]
+ * @param {RegExp} rx A regular expression.
+ * @param {String} str The string to match against
+ * @return {Array} The list of matches or empty array.
+ * @see R.test
+ * @example
+ *
+ *      R.match(/([a-z]a)/g, 'bananas'); //=> ['ba', 'na', 'na']
+ *      R.match(/a/, 'b'); //=> []
+ *      R.match(/a/, null); //=> TypeError: null does not have a method named "match"
+ */
+var match = /*#__PURE__*/_curry2(function match(rx, str) {
+  return str.match(rx) || [];
+});
+export default match;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mathMod.js b/server/node_modules/ramda/es/mathMod.js
new file mode 100644
index 0000000000000000000000000000000000000000..9230ea21e9803649b8999c4c7bcd78d0f3977bbf
--- /dev/null
+++ b/server/node_modules/ramda/es/mathMod.js
@@ -0,0 +1,46 @@
+import _curry2 from './internal/_curry2.js';
+import _isInteger from './internal/_isInteger.js';
+
+/**
+ * `mathMod` behaves like the modulo operator should mathematically, unlike the
+ * `%` operator (and by extension, [`R.modulo`](#modulo)). So while
+ * `-17 % 5` is `-2`, `mathMod(-17, 5)` is `3`. `mathMod` requires Integer
+ * arguments, and returns NaN when the modulus is zero or negative.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} m The dividend.
+ * @param {Number} p the modulus.
+ * @return {Number} The result of `b mod a`.
+ * @see R.modulo
+ * @example
+ *
+ *      R.mathMod(-17, 5);  //=> 3
+ *      R.mathMod(17, 5);   //=> 2
+ *      R.mathMod(17, -5);  //=> NaN
+ *      R.mathMod(17, 0);   //=> NaN
+ *      R.mathMod(17.2, 5); //=> NaN
+ *      R.mathMod(17, 5.3); //=> NaN
+ *
+ *      const clock = R.mathMod(R.__, 12);
+ *      clock(15); //=> 3
+ *      clock(24); //=> 0
+ *
+ *      const seventeenMod = R.mathMod(17);
+ *      seventeenMod(3);  //=> 2
+ *      seventeenMod(4);  //=> 1
+ *      seventeenMod(10); //=> 7
+ */
+var mathMod = /*#__PURE__*/_curry2(function mathMod(m, p) {
+  if (!_isInteger(m)) {
+    return NaN;
+  }
+  if (!_isInteger(p) || p < 1) {
+    return NaN;
+  }
+  return (m % p + p) % p;
+});
+export default mathMod;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/max.js b/server/node_modules/ramda/es/max.js
new file mode 100644
index 0000000000000000000000000000000000000000..c1d4a775ae36fd67a92ba06a3b617015756fef8c
--- /dev/null
+++ b/server/node_modules/ramda/es/max.js
@@ -0,0 +1,23 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns the larger of its two arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> a
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.maxBy, R.min
+ * @example
+ *
+ *      R.max(789, 123); //=> 789
+ *      R.max('a', 'b'); //=> 'b'
+ */
+var max = /*#__PURE__*/_curry2(function max(a, b) {
+  return b > a ? b : a;
+});
+export default max;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/maxBy.js b/server/node_modules/ramda/es/maxBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..5336f18cb59c6028b329ea2ad1d9a0d44e19c5ac
--- /dev/null
+++ b/server/node_modules/ramda/es/maxBy.js
@@ -0,0 +1,30 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Takes a function and two values, and returns whichever value produces the
+ * larger result when passed to the provided function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Relation
+ * @sig Ord b => (a -> b) -> a -> a -> a
+ * @param {Function} f
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.max, R.minBy
+ * @example
+ *
+ *      //  square :: Number -> Number
+ *      const square = n => n * n;
+ *
+ *      R.maxBy(square, -3, 2); //=> -3
+ *
+ *      R.reduce(R.maxBy(square), 0, [3, -5, 4, 1, -2]); //=> -5
+ *      R.reduce(R.maxBy(square), 0, []); //=> 0
+ */
+var maxBy = /*#__PURE__*/_curry3(function maxBy(f, a, b) {
+  return f(b) > f(a) ? b : a;
+});
+export default maxBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mean.js b/server/node_modules/ramda/es/mean.js
new file mode 100644
index 0000000000000000000000000000000000000000..c32f5408269ce8f8902ef28ce7645f454a752d60
--- /dev/null
+++ b/server/node_modules/ramda/es/mean.js
@@ -0,0 +1,23 @@
+import _curry1 from './internal/_curry1.js';
+import sum from './sum.js';
+
+/**
+ * Returns the mean of the given list of numbers.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list
+ * @return {Number}
+ * @see R.median
+ * @example
+ *
+ *      R.mean([2, 7, 9]); //=> 6
+ *      R.mean([]); //=> NaN
+ */
+var mean = /*#__PURE__*/_curry1(function mean(list) {
+  return sum(list) / list.length;
+});
+export default mean;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/median.js b/server/node_modules/ramda/es/median.js
new file mode 100644
index 0000000000000000000000000000000000000000..cc5510f231a166ebd297d8e2b3b7b2a077ea92e4
--- /dev/null
+++ b/server/node_modules/ramda/es/median.js
@@ -0,0 +1,32 @@
+import _curry1 from './internal/_curry1.js';
+import mean from './mean.js';
+
+/**
+ * Returns the median of the given list of numbers.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list
+ * @return {Number}
+ * @see R.mean
+ * @example
+ *
+ *      R.median([2, 9, 7]); //=> 7
+ *      R.median([7, 2, 10, 9]); //=> 8
+ *      R.median([]); //=> NaN
+ */
+var median = /*#__PURE__*/_curry1(function median(list) {
+  var len = list.length;
+  if (len === 0) {
+    return NaN;
+  }
+  var width = 2 - len % 2;
+  var idx = (len - width) / 2;
+  return mean(Array.prototype.slice.call(list, 0).sort(function (a, b) {
+    return a < b ? -1 : a > b ? 1 : 0;
+  }).slice(idx, idx + width));
+});
+export default median;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/memoizeWith.js b/server/node_modules/ramda/es/memoizeWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..39378dfa6cc7a41e451294798039f9cd8eecf8aa
--- /dev/null
+++ b/server/node_modules/ramda/es/memoizeWith.js
@@ -0,0 +1,43 @@
+import _arity from './internal/_arity.js';
+import _curry2 from './internal/_curry2.js';
+import _has from './internal/_has.js';
+
+/**
+ * Creates a new function that, when invoked, caches the result of calling `fn`
+ * for a given argument set and returns the result. Subsequent calls to the
+ * memoized `fn` with the same argument set will not result in an additional
+ * call to `fn`; instead, the cached result for that set of arguments will be
+ * returned.
+ *
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Function
+ * @sig (*... -> String) -> (*... -> a) -> (*... -> a)
+ * @param {Function} fn The function to generate the cache key.
+ * @param {Function} fn The function to memoize.
+ * @return {Function} Memoized version of `fn`.
+ * @example
+ *
+ *      let count = 0;
+ *      const factorial = R.memoizeWith(R.identity, n => {
+ *        count += 1;
+ *        return R.product(R.range(1, n + 1));
+ *      });
+ *      factorial(5); //=> 120
+ *      factorial(5); //=> 120
+ *      factorial(5); //=> 120
+ *      count; //=> 1
+ */
+var memoizeWith = /*#__PURE__*/_curry2(function memoizeWith(mFn, fn) {
+  var cache = {};
+  return _arity(fn.length, function () {
+    var key = mFn.apply(this, arguments);
+    if (!_has(key, cache)) {
+      cache[key] = fn.apply(this, arguments);
+    }
+    return cache[key];
+  });
+});
+export default memoizeWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/merge.js b/server/node_modules/ramda/es/merge.js
new file mode 100644
index 0000000000000000000000000000000000000000..d5711670b05accdfbfda0a7d56b6240e0a52c2dc
--- /dev/null
+++ b/server/node_modules/ramda/es/merge.js
@@ -0,0 +1,31 @@
+import _objectAssign from './internal/_objectAssign.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Create a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects,
+ * the value from the second object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {k: v} -> {k: v} -> {k: v}
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeRight, R.mergeDeepRight, R.mergeWith, R.mergeWithKey
+ * @deprecated
+ * @example
+ *
+ *      R.merge({ 'name': 'fred', 'age': 10 }, { 'age': 40 });
+ *      //=> { 'name': 'fred', 'age': 40 }
+ *
+ *      const withDefaults = R.merge({x: 0, y: 0});
+ *      withDefaults({y: 2}); //=> {x: 0, y: 2}
+ * @symb R.merge(a, b) = {...a, ...b}
+ */
+var merge = /*#__PURE__*/_curry2(function merge(l, r) {
+  return _objectAssign({}, l, r);
+});
+export default merge;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mergeAll.js b/server/node_modules/ramda/es/mergeAll.js
new file mode 100644
index 0000000000000000000000000000000000000000..23a594b74daf9adde25349930f137e3b4677b58a
--- /dev/null
+++ b/server/node_modules/ramda/es/mergeAll.js
@@ -0,0 +1,24 @@
+import _objectAssign from './internal/_objectAssign.js';
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Merges a list of objects together into one object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig [{k: v}] -> {k: v}
+ * @param {Array} list An array of objects
+ * @return {Object} A merged object.
+ * @see R.reduce
+ * @example
+ *
+ *      R.mergeAll([{foo:1},{bar:2},{baz:3}]); //=> {foo:1,bar:2,baz:3}
+ *      R.mergeAll([{foo:1},{foo:2},{bar:2}]); //=> {foo:2,bar:2}
+ * @symb R.mergeAll([{ x: 1 }, { y: 2 }, { z: 3 }]) = { x: 1, y: 2, z: 3 }
+ */
+var mergeAll = /*#__PURE__*/_curry1(function mergeAll(list) {
+  return _objectAssign.apply(null, [{}].concat(list));
+});
+export default mergeAll;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mergeDeepLeft.js b/server/node_modules/ramda/es/mergeDeepLeft.js
new file mode 100644
index 0000000000000000000000000000000000000000..cfa47e66e81600607c04af741e101cd0c3fe4755
--- /dev/null
+++ b/server/node_modules/ramda/es/mergeDeepLeft.js
@@ -0,0 +1,30 @@
+import _curry2 from './internal/_curry2.js';
+import mergeDeepWithKey from './mergeDeepWithKey.js';
+
+/**
+ * Creates a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects:
+ * - and both values are objects, the two values will be recursively merged
+ * - otherwise the value from the first object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig {a} -> {a} -> {a}
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.merge, R.mergeDeepRight, R.mergeDeepWith, R.mergeDeepWithKey
+ * @example
+ *
+ *      R.mergeDeepLeft({ name: 'fred', age: 10, contact: { email: 'moo@example.com' }},
+ *                      { age: 40, contact: { email: 'baa@example.com' }});
+ *      //=> { name: 'fred', age: 10, contact: { email: 'moo@example.com' }}
+ */
+var mergeDeepLeft = /*#__PURE__*/_curry2(function mergeDeepLeft(lObj, rObj) {
+  return mergeDeepWithKey(function (k, lVal, rVal) {
+    return lVal;
+  }, lObj, rObj);
+});
+export default mergeDeepLeft;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mergeDeepRight.js b/server/node_modules/ramda/es/mergeDeepRight.js
new file mode 100644
index 0000000000000000000000000000000000000000..6eb58944f064bab5b950ccef9f493eefe5e67cf0
--- /dev/null
+++ b/server/node_modules/ramda/es/mergeDeepRight.js
@@ -0,0 +1,30 @@
+import _curry2 from './internal/_curry2.js';
+import mergeDeepWithKey from './mergeDeepWithKey.js';
+
+/**
+ * Creates a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects:
+ * - and both values are objects, the two values will be recursively merged
+ * - otherwise the value from the second object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig {a} -> {a} -> {a}
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.merge, R.mergeDeepLeft, R.mergeDeepWith, R.mergeDeepWithKey
+ * @example
+ *
+ *      R.mergeDeepRight({ name: 'fred', age: 10, contact: { email: 'moo@example.com' }},
+ *                       { age: 40, contact: { email: 'baa@example.com' }});
+ *      //=> { name: 'fred', age: 40, contact: { email: 'baa@example.com' }}
+ */
+var mergeDeepRight = /*#__PURE__*/_curry2(function mergeDeepRight(lObj, rObj) {
+  return mergeDeepWithKey(function (k, lVal, rVal) {
+    return rVal;
+  }, lObj, rObj);
+});
+export default mergeDeepRight;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mergeDeepWith.js b/server/node_modules/ramda/es/mergeDeepWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..7fbe134aeaff7e4eae213148d6c34a9e97f78245
--- /dev/null
+++ b/server/node_modules/ramda/es/mergeDeepWith.js
@@ -0,0 +1,36 @@
+import _curry3 from './internal/_curry3.js';
+import mergeDeepWithKey from './mergeDeepWithKey.js';
+
+/**
+ * Creates a new object with the own properties of the two provided objects.
+ * If a key exists in both objects:
+ * - and both associated values are also objects then the values will be
+ *   recursively merged.
+ * - otherwise the provided function is applied to associated values using the
+ *   resulting value as the new value associated with the key.
+ * If a key only exists in one object, the value will be associated with the key
+ * of the resulting object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig ((a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.mergeWith, R.mergeDeepWithKey
+ * @example
+ *
+ *      R.mergeDeepWith(R.concat,
+ *                      { a: true, c: { values: [10, 20] }},
+ *                      { b: true, c: { values: [15, 35] }});
+ *      //=> { a: true, b: true, c: { values: [10, 20, 15, 35] }}
+ */
+var mergeDeepWith = /*#__PURE__*/_curry3(function mergeDeepWith(fn, lObj, rObj) {
+  return mergeDeepWithKey(function (k, lVal, rVal) {
+    return fn(lVal, rVal);
+  }, lObj, rObj);
+});
+export default mergeDeepWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mergeDeepWithKey.js b/server/node_modules/ramda/es/mergeDeepWithKey.js
new file mode 100644
index 0000000000000000000000000000000000000000..f7af5a43e0cc90f03c4c31f957ec11bfc24ba4fa
--- /dev/null
+++ b/server/node_modules/ramda/es/mergeDeepWithKey.js
@@ -0,0 +1,42 @@
+import _curry3 from './internal/_curry3.js';
+import _isObject from './internal/_isObject.js';
+import mergeWithKey from './mergeWithKey.js';
+
+/**
+ * Creates a new object with the own properties of the two provided objects.
+ * If a key exists in both objects:
+ * - and both associated values are also objects then the values will be
+ *   recursively merged.
+ * - otherwise the provided function is applied to the key and associated values
+ *   using the resulting value as the new value associated with the key.
+ * If a key only exists in one object, the value will be associated with the key
+ * of the resulting object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.mergeWithKey, R.mergeDeepWith
+ * @example
+ *
+ *      let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r
+ *      R.mergeDeepWithKey(concatValues,
+ *                         { a: true, c: { thing: 'foo', values: [10, 20] }},
+ *                         { b: true, c: { thing: 'bar', values: [15, 35] }});
+ *      //=> { a: true, b: true, c: { thing: 'bar', values: [10, 20, 15, 35] }}
+ */
+var mergeDeepWithKey = /*#__PURE__*/_curry3(function mergeDeepWithKey(fn, lObj, rObj) {
+  return mergeWithKey(function (k, lVal, rVal) {
+    if (_isObject(lVal) && _isObject(rVal)) {
+      return mergeDeepWithKey(fn, lVal, rVal);
+    } else {
+      return fn(k, lVal, rVal);
+    }
+  }, lObj, rObj);
+});
+export default mergeDeepWithKey;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mergeLeft.js b/server/node_modules/ramda/es/mergeLeft.js
new file mode 100644
index 0000000000000000000000000000000000000000..fd317c368c0a85f9d74205f41a3a56d40a0257a5
--- /dev/null
+++ b/server/node_modules/ramda/es/mergeLeft.js
@@ -0,0 +1,29 @@
+import _objectAssign from './internal/_objectAssign.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Create a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects,
+ * the value from the first object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @category Object
+ * @sig {k: v} -> {k: v} -> {k: v}
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeRight, R.mergeDeepLeft, R.mergeWith, R.mergeWithKey
+ * @example
+ *
+ *      R.mergeLeft({ 'age': 40 }, { 'name': 'fred', 'age': 10 });
+ *      //=> { 'name': 'fred', 'age': 40 }
+ *
+ *      const resetToDefault = R.mergeLeft({x: 0});
+ *      resetToDefault({x: 5, y: 2}); //=> {x: 0, y: 2}
+ * @symb R.mergeLeft(a, b) = {...b, ...a}
+ */
+var mergeLeft = /*#__PURE__*/_curry2(function mergeLeft(l, r) {
+  return _objectAssign({}, r, l);
+});
+export default mergeLeft;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mergeRight.js b/server/node_modules/ramda/es/mergeRight.js
new file mode 100644
index 0000000000000000000000000000000000000000..37a08e8ee63afe4fc4873aec24846241c5c0ff0a
--- /dev/null
+++ b/server/node_modules/ramda/es/mergeRight.js
@@ -0,0 +1,29 @@
+import _objectAssign from './internal/_objectAssign.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Create a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects,
+ * the value from the second object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @category Object
+ * @sig {k: v} -> {k: v} -> {k: v}
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeLeft, R.mergeDeepRight, R.mergeWith, R.mergeWithKey
+ * @example
+ *
+ *      R.mergeRight({ 'name': 'fred', 'age': 10 }, { 'age': 40 });
+ *      //=> { 'name': 'fred', 'age': 40 }
+ *
+ *      const withDefaults = R.mergeRight({x: 0, y: 0});
+ *      withDefaults({y: 2}); //=> {x: 0, y: 2}
+ * @symb R.mergeRight(a, b) = {...a, ...b}
+ */
+var mergeRight = /*#__PURE__*/_curry2(function mergeRight(l, r) {
+  return _objectAssign({}, l, r);
+});
+export default mergeRight;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mergeWith.js b/server/node_modules/ramda/es/mergeWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..c8d8bf30d49db416adcf4a9891bd92dbd7252697
--- /dev/null
+++ b/server/node_modules/ramda/es/mergeWith.js
@@ -0,0 +1,32 @@
+import _curry3 from './internal/_curry3.js';
+import mergeWithKey from './mergeWithKey.js';
+
+/**
+ * Creates a new object with the own properties of the two provided objects. If
+ * a key exists in both objects, the provided function is applied to the values
+ * associated with the key in each object, with the result being used as the
+ * value associated with the key in the returned object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Object
+ * @sig ((a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeDeepWith, R.merge, R.mergeWithKey
+ * @example
+ *
+ *      R.mergeWith(R.concat,
+ *                  { a: true, values: [10, 20] },
+ *                  { b: true, values: [15, 35] });
+ *      //=> { a: true, b: true, values: [10, 20, 15, 35] }
+ */
+var mergeWith = /*#__PURE__*/_curry3(function mergeWith(fn, l, r) {
+  return mergeWithKey(function (_, _l, _r) {
+    return fn(_l, _r);
+  }, l, r);
+});
+export default mergeWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/mergeWithKey.js b/server/node_modules/ramda/es/mergeWithKey.js
new file mode 100644
index 0000000000000000000000000000000000000000..e0526f5a25b6c7e9623fc3a26abd2b36346ad239
--- /dev/null
+++ b/server/node_modules/ramda/es/mergeWithKey.js
@@ -0,0 +1,47 @@
+import _curry3 from './internal/_curry3.js';
+import _has from './internal/_has.js';
+
+/**
+ * Creates a new object with the own properties of the two provided objects. If
+ * a key exists in both objects, the provided function is applied to the key
+ * and the values associated with the key in each object, with the result being
+ * used as the value associated with the key in the returned object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Object
+ * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeDeepWithKey, R.merge, R.mergeWith
+ * @example
+ *
+ *      let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r
+ *      R.mergeWithKey(concatValues,
+ *                     { a: true, thing: 'foo', values: [10, 20] },
+ *                     { b: true, thing: 'bar', values: [15, 35] });
+ *      //=> { a: true, b: true, thing: 'bar', values: [10, 20, 15, 35] }
+ * @symb R.mergeWithKey(f, { x: 1, y: 2 }, { y: 5, z: 3 }) = { x: 1, y: f('y', 2, 5), z: 3 }
+ */
+var mergeWithKey = /*#__PURE__*/_curry3(function mergeWithKey(fn, l, r) {
+  var result = {};
+  var k;
+
+  for (k in l) {
+    if (_has(k, l)) {
+      result[k] = _has(k, r) ? fn(k, l[k], r[k]) : l[k];
+    }
+  }
+
+  for (k in r) {
+    if (_has(k, r) && !_has(k, result)) {
+      result[k] = r[k];
+    }
+  }
+
+  return result;
+});
+export default mergeWithKey;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/min.js b/server/node_modules/ramda/es/min.js
new file mode 100644
index 0000000000000000000000000000000000000000..ae1e318e7208ff43937a73d3f5bc4bfa51a7c878
--- /dev/null
+++ b/server/node_modules/ramda/es/min.js
@@ -0,0 +1,23 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns the smaller of its two arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> a
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.minBy, R.max
+ * @example
+ *
+ *      R.min(789, 123); //=> 123
+ *      R.min('a', 'b'); //=> 'a'
+ */
+var min = /*#__PURE__*/_curry2(function min(a, b) {
+  return b < a ? b : a;
+});
+export default min;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/minBy.js b/server/node_modules/ramda/es/minBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..ad970439004dd27eb86557ee331190f835822a66
--- /dev/null
+++ b/server/node_modules/ramda/es/minBy.js
@@ -0,0 +1,30 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Takes a function and two values, and returns whichever value produces the
+ * smaller result when passed to the provided function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Relation
+ * @sig Ord b => (a -> b) -> a -> a -> a
+ * @param {Function} f
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.min, R.maxBy
+ * @example
+ *
+ *      //  square :: Number -> Number
+ *      const square = n => n * n;
+ *
+ *      R.minBy(square, -3, 2); //=> 2
+ *
+ *      R.reduce(R.minBy(square), Infinity, [3, -5, 4, 1, -2]); //=> 1
+ *      R.reduce(R.minBy(square), Infinity, []); //=> Infinity
+ */
+var minBy = /*#__PURE__*/_curry3(function minBy(f, a, b) {
+  return f(b) < f(a) ? b : a;
+});
+export default minBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/modulo.js b/server/node_modules/ramda/es/modulo.js
new file mode 100644
index 0000000000000000000000000000000000000000..142c6a95af8218d0fcff4f9d3fd0a0ea7149de5b
--- /dev/null
+++ b/server/node_modules/ramda/es/modulo.js
@@ -0,0 +1,31 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Divides the first parameter by the second and returns the remainder. Note
+ * that this function preserves the JavaScript-style behavior for modulo. For
+ * mathematical modulo see [`mathMod`](#mathMod).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The value to the divide.
+ * @param {Number} b The pseudo-modulus
+ * @return {Number} The result of `b % a`.
+ * @see R.mathMod
+ * @example
+ *
+ *      R.modulo(17, 3); //=> 2
+ *      // JS behavior:
+ *      R.modulo(-17, 3); //=> -2
+ *      R.modulo(17, -3); //=> 2
+ *
+ *      const isOdd = R.modulo(R.__, 2);
+ *      isOdd(42); //=> 0
+ *      isOdd(21); //=> 1
+ */
+var modulo = /*#__PURE__*/_curry2(function modulo(a, b) {
+  return a % b;
+});
+export default modulo;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/move.js b/server/node_modules/ramda/es/move.js
new file mode 100644
index 0000000000000000000000000000000000000000..f3b361f6f24f914c9b69211502065ca24a606ee5
--- /dev/null
+++ b/server/node_modules/ramda/es/move.js
@@ -0,0 +1,30 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Move an item, at index `from`, to index `to`, in a list of elements.
+ * A new list will be created containing the new elements order.
+ *
+ * @func
+ * @memberOf R
+ * @category List
+ * @sig Number -> Number -> [a] -> [a]
+ * @param {Number} from The source index
+ * @param {Number} to The destination index
+ * @param {Array} list The list which will serve to realise the move
+ * @return {Array} The new list reordered
+ * @example
+ *
+ *      R.move(0, 2, ['a', 'b', 'c', 'd', 'e', 'f']); //=> ['b', 'c', 'a', 'd', 'e', 'f']
+ *      R.move(-1, 0, ['a', 'b', 'c', 'd', 'e', 'f']); //=> ['f', 'a', 'b', 'c', 'd', 'e'] list rotation
+ */
+var move = /*#__PURE__*/_curry3(function (from, to, list) {
+  var length = list.length;
+  var result = list.slice();
+  var positiveFrom = from < 0 ? length + from : from;
+  var positiveTo = to < 0 ? length + to : to;
+  var item = result.splice(positiveFrom, 1);
+
+  return positiveFrom < 0 || positiveFrom >= list.length || positiveTo < 0 || positiveTo >= list.length ? list : [].concat(result.slice(0, positiveTo)).concat(item).concat(result.slice(positiveTo, list.length));
+});
+
+export default move;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/multiply.js b/server/node_modules/ramda/es/multiply.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b10d93686ec182a320201788ff7c09d240deac3
--- /dev/null
+++ b/server/node_modules/ramda/es/multiply.js
@@ -0,0 +1,26 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Multiplies two numbers. Equivalent to `a * b` but curried.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The first value.
+ * @param {Number} b The second value.
+ * @return {Number} The result of `a * b`.
+ * @see R.divide
+ * @example
+ *
+ *      const double = R.multiply(2);
+ *      const triple = R.multiply(3);
+ *      double(3);       //=>  6
+ *      triple(4);       //=> 12
+ *      R.multiply(2, 5);  //=> 10
+ */
+var multiply = /*#__PURE__*/_curry2(function multiply(a, b) {
+  return a * b;
+});
+export default multiply;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/nAry.js b/server/node_modules/ramda/es/nAry.js
new file mode 100644
index 0000000000000000000000000000000000000000..4527414684428246bf4bf7ebe026af146e9a7707
--- /dev/null
+++ b/server/node_modules/ramda/es/nAry.js
@@ -0,0 +1,83 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Wraps a function of any arity (including nullary) in a function that accepts
+ * exactly `n` parameters. Any extraneous parameters will not be passed to the
+ * supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig Number -> (* -> a) -> (* -> a)
+ * @param {Number} n The desired arity of the new function.
+ * @param {Function} fn The function to wrap.
+ * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
+ *         arity `n`.
+ * @see R.binary, R.unary
+ * @example
+ *
+ *      const takesTwoArgs = (a, b) => [a, b];
+ *
+ *      takesTwoArgs.length; //=> 2
+ *      takesTwoArgs(1, 2); //=> [1, 2]
+ *
+ *      const takesOneArg = R.nAry(1, takesTwoArgs);
+ *      takesOneArg.length; //=> 1
+ *      // Only `n` arguments are passed to the wrapped function
+ *      takesOneArg(1, 2); //=> [1, undefined]
+ * @symb R.nAry(0, f)(a, b) = f()
+ * @symb R.nAry(1, f)(a, b) = f(a)
+ * @symb R.nAry(2, f)(a, b) = f(a, b)
+ */
+var nAry = /*#__PURE__*/_curry2(function nAry(n, fn) {
+  switch (n) {
+    case 0:
+      return function () {
+        return fn.call(this);
+      };
+    case 1:
+      return function (a0) {
+        return fn.call(this, a0);
+      };
+    case 2:
+      return function (a0, a1) {
+        return fn.call(this, a0, a1);
+      };
+    case 3:
+      return function (a0, a1, a2) {
+        return fn.call(this, a0, a1, a2);
+      };
+    case 4:
+      return function (a0, a1, a2, a3) {
+        return fn.call(this, a0, a1, a2, a3);
+      };
+    case 5:
+      return function (a0, a1, a2, a3, a4) {
+        return fn.call(this, a0, a1, a2, a3, a4);
+      };
+    case 6:
+      return function (a0, a1, a2, a3, a4, a5) {
+        return fn.call(this, a0, a1, a2, a3, a4, a5);
+      };
+    case 7:
+      return function (a0, a1, a2, a3, a4, a5, a6) {
+        return fn.call(this, a0, a1, a2, a3, a4, a5, a6);
+      };
+    case 8:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7) {
+        return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7);
+      };
+    case 9:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) {
+        return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7, a8);
+      };
+    case 10:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {
+        return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+      };
+    default:
+      throw new Error('First argument to nAry must be a non-negative integer no greater than ten');
+  }
+});
+export default nAry;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/negate.js b/server/node_modules/ramda/es/negate.js
new file mode 100644
index 0000000000000000000000000000000000000000..5ca3fe51858ee31a54a3faf262b45dd571d41986
--- /dev/null
+++ b/server/node_modules/ramda/es/negate.js
@@ -0,0 +1,20 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Negates its argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Math
+ * @sig Number -> Number
+ * @param {Number} n
+ * @return {Number}
+ * @example
+ *
+ *      R.negate(42); //=> -42
+ */
+var negate = /*#__PURE__*/_curry1(function negate(n) {
+  return -n;
+});
+export default negate;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/none.js b/server/node_modules/ramda/es/none.js
new file mode 100644
index 0000000000000000000000000000000000000000..971436b8a6780080c0ed3dde0ef03a07ad51b088
--- /dev/null
+++ b/server/node_modules/ramda/es/none.js
@@ -0,0 +1,33 @@
+import _complement from './internal/_complement.js';
+import _curry2 from './internal/_curry2.js';
+import all from './all.js';
+
+/**
+ * Returns `true` if no elements of the list match the predicate, `false`
+ * otherwise.
+ *
+ * Dispatches to the `all` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Boolean
+ * @param {Function} fn The predicate function.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if the predicate is not satisfied by every element, `false` otherwise.
+ * @see R.all, R.any
+ * @example
+ *
+ *      const isEven = n => n % 2 === 0;
+ *      const isOdd = n => n % 2 === 1;
+ *
+ *      R.none(isEven, [1, 3, 5, 7, 9, 11]); //=> true
+ *      R.none(isOdd, [1, 3, 5, 7, 8, 11]); //=> false
+ */
+var none = /*#__PURE__*/_curry2(function none(fn, input) {
+  return all(_complement(fn), input);
+});
+export default none;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/not.js b/server/node_modules/ramda/es/not.js
new file mode 100644
index 0000000000000000000000000000000000000000..8586c1b6a887b3e147d78b8c4489d969fd997d57
--- /dev/null
+++ b/server/node_modules/ramda/es/not.js
@@ -0,0 +1,25 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * A function that returns the `!` of its argument. It will return `true` when
+ * passed false-y value, and `false` when passed a truth-y one.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig * -> Boolean
+ * @param {*} a any value
+ * @return {Boolean} the logical inverse of passed argument.
+ * @see R.complement
+ * @example
+ *
+ *      R.not(true); //=> false
+ *      R.not(false); //=> true
+ *      R.not(0); //=> true
+ *      R.not(1); //=> false
+ */
+var not = /*#__PURE__*/_curry1(function not(a) {
+  return !a;
+});
+export default not;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/nth.js b/server/node_modules/ramda/es/nth.js
new file mode 100644
index 0000000000000000000000000000000000000000..47a76eadf1f54dd458ddd809f0a6894868147529
--- /dev/null
+++ b/server/node_modules/ramda/es/nth.js
@@ -0,0 +1,34 @@
+import _curry2 from './internal/_curry2.js';
+import _isString from './internal/_isString.js';
+
+/**
+ * Returns the nth element of the given list or string. If n is negative the
+ * element at index length + n is returned.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> [a] -> a | Undefined
+ * @sig Number -> String -> String
+ * @param {Number} offset
+ * @param {*} list
+ * @return {*}
+ * @example
+ *
+ *      const list = ['foo', 'bar', 'baz', 'quux'];
+ *      R.nth(1, list); //=> 'bar'
+ *      R.nth(-1, list); //=> 'quux'
+ *      R.nth(-99, list); //=> undefined
+ *
+ *      R.nth(2, 'abc'); //=> 'c'
+ *      R.nth(3, 'abc'); //=> ''
+ * @symb R.nth(-1, [a, b, c]) = c
+ * @symb R.nth(0, [a, b, c]) = a
+ * @symb R.nth(1, [a, b, c]) = b
+ */
+var nth = /*#__PURE__*/_curry2(function nth(offset, list) {
+  var idx = offset < 0 ? list.length + offset : offset;
+  return _isString(list) ? list.charAt(idx) : list[idx];
+});
+export default nth;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/nthArg.js b/server/node_modules/ramda/es/nthArg.js
new file mode 100644
index 0000000000000000000000000000000000000000..c688fcce944e8d1dcb6c53513bfe7ff0ea8b82ea
--- /dev/null
+++ b/server/node_modules/ramda/es/nthArg.js
@@ -0,0 +1,29 @@
+import _curry1 from './internal/_curry1.js';
+import curryN from './curryN.js';
+import nth from './nth.js';
+
+/**
+ * Returns a function which returns its nth argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig Number -> *... -> *
+ * @param {Number} n
+ * @return {Function}
+ * @example
+ *
+ *      R.nthArg(1)('a', 'b', 'c'); //=> 'b'
+ *      R.nthArg(-1)('a', 'b', 'c'); //=> 'c'
+ * @symb R.nthArg(-1)(a, b, c) = c
+ * @symb R.nthArg(0)(a, b, c) = a
+ * @symb R.nthArg(1)(a, b, c) = b
+ */
+var nthArg = /*#__PURE__*/_curry1(function nthArg(n) {
+  var arity = n < 0 ? 1 : n + 1;
+  return curryN(arity, function () {
+    return nth(n, arguments);
+  });
+});
+export default nthArg;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/o.js b/server/node_modules/ramda/es/o.js
new file mode 100644
index 0000000000000000000000000000000000000000..1714dd89079bbb4c6410b0d39dffe4d30a506316
--- /dev/null
+++ b/server/node_modules/ramda/es/o.js
@@ -0,0 +1,33 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * `o` is a curried composition function that returns a unary function.
+ * Like [`compose`](#compose), `o` performs right-to-left function composition.
+ * Unlike [`compose`](#compose), the rightmost function passed to `o` will be
+ * invoked with only one argument. Also, unlike [`compose`](#compose), `o` is
+ * limited to accepting only 2 unary functions. The name o was chosen because
+ * of its similarity to the mathematical composition operator ∘.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Function
+ * @sig (b -> c) -> (a -> b) -> a -> c
+ * @param {Function} f
+ * @param {Function} g
+ * @return {Function}
+ * @see R.compose, R.pipe
+ * @example
+ *
+ *      const classyGreeting = name => "The name's " + name.last + ", " + name.first + " " + name.last
+ *      const yellGreeting = R.o(R.toUpper, classyGreeting);
+ *      yellGreeting({first: 'James', last: 'Bond'}); //=> "THE NAME'S BOND, JAMES BOND"
+ *
+ *      R.o(R.multiply(10), R.add(10))(-4) //=> 60
+ *
+ * @symb R.o(f, g, x) = f(g(x))
+ */
+var o = /*#__PURE__*/_curry3(function o(f, g, x) {
+  return f(g(x));
+});
+export default o;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/objOf.js b/server/node_modules/ramda/es/objOf.js
new file mode 100644
index 0000000000000000000000000000000000000000..b582ffb0a326312322505073b2f8c85923edfb08
--- /dev/null
+++ b/server/node_modules/ramda/es/objOf.js
@@ -0,0 +1,28 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Creates an object containing a single key:value pair.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Object
+ * @sig String -> a -> {String:a}
+ * @param {String} key
+ * @param {*} val
+ * @return {Object}
+ * @see R.pair
+ * @example
+ *
+ *      const matchPhrases = R.compose(
+ *        R.objOf('must'),
+ *        R.map(R.objOf('match_phrase'))
+ *      );
+ *      matchPhrases(['foo', 'bar', 'baz']); //=> {must: [{match_phrase: 'foo'}, {match_phrase: 'bar'}, {match_phrase: 'baz'}]}
+ */
+var objOf = /*#__PURE__*/_curry2(function objOf(key, val) {
+  var obj = {};
+  obj[key] = val;
+  return obj;
+});
+export default objOf;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/of.js b/server/node_modules/ramda/es/of.js
new file mode 100644
index 0000000000000000000000000000000000000000..0187ca5a6640d2faff52b9934896d1e2f0f0fbe0
--- /dev/null
+++ b/server/node_modules/ramda/es/of.js
@@ -0,0 +1,23 @@
+import _curry1 from './internal/_curry1.js';
+import _of from './internal/_of.js';
+
+/**
+ * Returns a singleton array containing the value provided.
+ *
+ * Note this `of` is different from the ES6 `of`; See
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/of
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Function
+ * @sig a -> [a]
+ * @param {*} x any value
+ * @return {Array} An array wrapping `x`.
+ * @example
+ *
+ *      R.of(null); //=> [null]
+ *      R.of([42]); //=> [[42]]
+ */
+var of = /*#__PURE__*/_curry1(_of);
+export default of;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/omit.js b/server/node_modules/ramda/es/omit.js
new file mode 100644
index 0000000000000000000000000000000000000000..5d46d97e01eb14dabad2a9b7f157e991a776dc8e
--- /dev/null
+++ b/server/node_modules/ramda/es/omit.js
@@ -0,0 +1,37 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns a partial copy of an object omitting the keys specified.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [String] -> {String: *} -> {String: *}
+ * @param {Array} names an array of String property names to omit from the new object
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with properties from `names` not on it.
+ * @see R.pick
+ * @example
+ *
+ *      R.omit(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, c: 3}
+ */
+var omit = /*#__PURE__*/_curry2(function omit(names, obj) {
+  var result = {};
+  var index = {};
+  var idx = 0;
+  var len = names.length;
+
+  while (idx < len) {
+    index[names[idx]] = 1;
+    idx += 1;
+  }
+
+  for (var prop in obj) {
+    if (!index.hasOwnProperty(prop)) {
+      result[prop] = obj[prop];
+    }
+  }
+  return result;
+});
+export default omit;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/once.js b/server/node_modules/ramda/es/once.js
new file mode 100644
index 0000000000000000000000000000000000000000..d44fe7e0969d87a27714b171be4aab3af102291f
--- /dev/null
+++ b/server/node_modules/ramda/es/once.js
@@ -0,0 +1,35 @@
+import _arity from './internal/_arity.js';
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Accepts a function `fn` and returns a function that guards invocation of
+ * `fn` such that `fn` can only ever be called once, no matter how many times
+ * the returned function is invoked. The first value calculated is returned in
+ * subsequent invocations.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (a... -> b) -> (a... -> b)
+ * @param {Function} fn The function to wrap in a call-only-once wrapper.
+ * @return {Function} The wrapped function.
+ * @example
+ *
+ *      const addOneOnce = R.once(x => x + 1);
+ *      addOneOnce(10); //=> 11
+ *      addOneOnce(addOneOnce(50)); //=> 11
+ */
+var once = /*#__PURE__*/_curry1(function once(fn) {
+  var called = false;
+  var result;
+  return _arity(fn.length, function () {
+    if (called) {
+      return result;
+    }
+    called = true;
+    result = fn.apply(this, arguments);
+    return result;
+  });
+});
+export default once;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/or.js b/server/node_modules/ramda/es/or.js
new file mode 100644
index 0000000000000000000000000000000000000000..a620eda27cb3a9824c39f236f9188d9eb617d08b
--- /dev/null
+++ b/server/node_modules/ramda/es/or.js
@@ -0,0 +1,26 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns `true` if one or both of its arguments are `true`. Returns `false`
+ * if both arguments are `false`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig a -> b -> a | b
+ * @param {Any} a
+ * @param {Any} b
+ * @return {Any} the first argument if truthy, otherwise the second argument.
+ * @see R.either
+ * @example
+ *
+ *      R.or(true, true); //=> true
+ *      R.or(true, false); //=> true
+ *      R.or(false, true); //=> true
+ *      R.or(false, false); //=> false
+ */
+var or = /*#__PURE__*/_curry2(function or(a, b) {
+  return a || b;
+});
+export default or;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/otherwise.js b/server/node_modules/ramda/es/otherwise.js
new file mode 100644
index 0000000000000000000000000000000000000000..420fc9521c6c78ab7df5a313c442ade11fc79b5f
--- /dev/null
+++ b/server/node_modules/ramda/es/otherwise.js
@@ -0,0 +1,36 @@
+import _curry2 from './internal/_curry2.js';
+import _assertPromise from './internal/_assertPromise.js';
+
+/**
+ * Returns the result of applying the onFailure function to the value inside
+ * a failed promise. This is useful for handling rejected promises
+ * inside function compositions.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig (e -> b) -> (Promise e a) -> (Promise e b)
+ * @sig (e -> (Promise f b)) -> (Promise e a) -> (Promise f b)
+ * @param {Function} onFailure The function to apply. Can return a value or a promise of a value.
+ * @param {Promise} p
+ * @return {Promise} The result of calling `p.then(null, onFailure)`
+ * @see R.then
+ * @example
+ *
+ *      var failedFetch = (id) => Promise.reject('bad ID');
+ *      var useDefault = () => ({ firstName: 'Bob', lastName: 'Loblaw' })
+ *
+ *      //recoverFromFailure :: String -> Promise ({firstName, lastName})
+ *      var recoverFromFailure = R.pipe(
+ *        failedFetch,
+ *        R.otherwise(useDefault),
+ *        R.then(R.pick(['firstName', 'lastName'])),
+ *      );
+ *      recoverFromFailure(12345).then(console.log)
+ */
+var otherwise = /*#__PURE__*/_curry2(function otherwise(f, p) {
+  _assertPromise('otherwise', p);
+
+  return p.then(null, f);
+});
+export default otherwise;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/over.js b/server/node_modules/ramda/es/over.js
new file mode 100644
index 0000000000000000000000000000000000000000..93c4ebc641ee9ff0fe989ff8feec1b76b4224dcf
--- /dev/null
+++ b/server/node_modules/ramda/es/over.js
@@ -0,0 +1,41 @@
+import _curry3 from './internal/_curry3.js';
+
+// `Identity` is a functor that holds a single value, where `map` simply
+// transforms the held value with the provided function.
+var Identity = function (x) {
+  return { value: x, map: function (f) {
+      return Identity(f(x));
+    } };
+};
+
+/**
+ * Returns the result of "setting" the portion of the given data structure
+ * focused by the given lens to the result of applying the given function to
+ * the focused value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Lens s a -> (a -> a) -> s -> s
+ * @param {Lens} lens
+ * @param {*} v
+ * @param {*} x
+ * @return {*}
+ * @see R.prop, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const headLens = R.lensIndex(0);
+ *
+ *      R.over(headLens, R.toUpper, ['foo', 'bar', 'baz']); //=> ['FOO', 'bar', 'baz']
+ */
+var over = /*#__PURE__*/_curry3(function over(lens, f, x) {
+  // The value returned by the getter function is first transformed with `f`,
+  // then set as the value of an `Identity`. This is then mapped over with the
+  // setter function of the lens.
+  return lens(function (y) {
+    return Identity(f(y));
+  })(x).value;
+});
+export default over;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pair.js b/server/node_modules/ramda/es/pair.js
new file mode 100644
index 0000000000000000000000000000000000000000..0c65312203b55bf57cf559cd153c11a8a302e8b8
--- /dev/null
+++ b/server/node_modules/ramda/es/pair.js
@@ -0,0 +1,22 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Takes two arguments, `fst` and `snd`, and returns `[fst, snd]`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category List
+ * @sig a -> b -> (a,b)
+ * @param {*} fst
+ * @param {*} snd
+ * @return {Array}
+ * @see R.objOf, R.of
+ * @example
+ *
+ *      R.pair('foo', 'bar'); //=> ['foo', 'bar']
+ */
+var pair = /*#__PURE__*/_curry2(function pair(fst, snd) {
+  return [fst, snd];
+});
+export default pair;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/partial.js b/server/node_modules/ramda/es/partial.js
new file mode 100644
index 0000000000000000000000000000000000000000..0fe14fcfbe66f78c17d29b5594c7bafea27f29f1
--- /dev/null
+++ b/server/node_modules/ramda/es/partial.js
@@ -0,0 +1,33 @@
+import _concat from './internal/_concat.js';
+import _createPartialApplicator from './internal/_createPartialApplicator.js';
+
+/**
+ * Takes a function `f` and a list of arguments, and returns a function `g`.
+ * When applied, `g` returns the result of applying `f` to the arguments
+ * provided initially followed by the arguments provided to `g`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((a, b, c, ..., n) -> x) -> [a, b, c, ...] -> ((d, e, f, ..., n) -> x)
+ * @param {Function} f
+ * @param {Array} args
+ * @return {Function}
+ * @see R.partialRight, R.curry
+ * @example
+ *
+ *      const multiply2 = (a, b) => a * b;
+ *      const double = R.partial(multiply2, [2]);
+ *      double(2); //=> 4
+ *
+ *      const greet = (salutation, title, firstName, lastName) =>
+ *        salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
+ *
+ *      const sayHello = R.partial(greet, ['Hello']);
+ *      const sayHelloToMs = R.partial(sayHello, ['Ms.']);
+ *      sayHelloToMs('Jane', 'Jones'); //=> 'Hello, Ms. Jane Jones!'
+ * @symb R.partial(f, [a, b])(c, d) = f(a, b, c, d)
+ */
+var partial = /*#__PURE__*/_createPartialApplicator(_concat);
+export default partial;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/partialRight.js b/server/node_modules/ramda/es/partialRight.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5ceef772ec8271774e30ac3e3733206a6314e3a
--- /dev/null
+++ b/server/node_modules/ramda/es/partialRight.js
@@ -0,0 +1,30 @@
+import _concat from './internal/_concat.js';
+import _createPartialApplicator from './internal/_createPartialApplicator.js';
+import flip from './flip.js';
+
+/**
+ * Takes a function `f` and a list of arguments, and returns a function `g`.
+ * When applied, `g` returns the result of applying `f` to the arguments
+ * provided to `g` followed by the arguments provided initially.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((a, b, c, ..., n) -> x) -> [d, e, f, ..., n] -> ((a, b, c, ...) -> x)
+ * @param {Function} f
+ * @param {Array} args
+ * @return {Function}
+ * @see R.partial
+ * @example
+ *
+ *      const greet = (salutation, title, firstName, lastName) =>
+ *        salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
+ *
+ *      const greetMsJaneJones = R.partialRight(greet, ['Ms.', 'Jane', 'Jones']);
+ *
+ *      greetMsJaneJones('Hello'); //=> 'Hello, Ms. Jane Jones!'
+ * @symb R.partialRight(f, [a, b])(c, d) = f(c, d, a, b)
+ */
+var partialRight = /*#__PURE__*/_createPartialApplicator( /*#__PURE__*/flip(_concat));
+export default partialRight;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/partition.js b/server/node_modules/ramda/es/partition.js
new file mode 100644
index 0000000000000000000000000000000000000000..2804a6808b37ce2298e71e49c16d46da82be7540
--- /dev/null
+++ b/server/node_modules/ramda/es/partition.js
@@ -0,0 +1,30 @@
+import filter from './filter.js';
+import juxt from './juxt.js';
+import reject from './reject.js';
+
+/**
+ * Takes a predicate and a list or other `Filterable` object and returns the
+ * pair of filterable objects of the same type of elements which do and do not
+ * satisfy, the predicate, respectively. Filterable objects include plain objects or any object
+ * that has a filter method such as `Array`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.4
+ * @category List
+ * @sig Filterable f => (a -> Boolean) -> f a -> [f a, f a]
+ * @param {Function} pred A predicate to determine which side the element belongs to.
+ * @param {Array} filterable the list (or other filterable) to partition.
+ * @return {Array} An array, containing first the subset of elements that satisfy the
+ *         predicate, and second the subset of elements that do not satisfy.
+ * @see R.filter, R.reject
+ * @example
+ *
+ *      R.partition(R.includes('s'), ['sss', 'ttt', 'foo', 'bars']);
+ *      // => [ [ 'sss', 'bars' ],  [ 'ttt', 'foo' ] ]
+ *
+ *      R.partition(R.includes('s'), { a: 'sss', b: 'ttt', foo: 'bars' });
+ *      // => [ { a: 'sss', foo: 'bars' }, { b: 'ttt' }  ]
+ */
+var partition = /*#__PURE__*/juxt([filter, reject]);
+export default partition;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/path.js b/server/node_modules/ramda/es/path.js
new file mode 100644
index 0000000000000000000000000000000000000000..18bac39530baec08a4650a90c961b0c0ea7925b0
--- /dev/null
+++ b/server/node_modules/ramda/es/path.js
@@ -0,0 +1,33 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Retrieve the value at a given path.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> {a} -> a | Undefined
+ * @param {Array} path The path to use.
+ * @param {Object} obj The object to retrieve the nested property from.
+ * @return {*} The data at `path`.
+ * @see R.prop
+ * @example
+ *
+ *      R.path(['a', 'b'], {a: {b: 2}}); //=> 2
+ *      R.path(['a', 'b'], {c: {b: 2}}); //=> undefined
+ */
+var path = /*#__PURE__*/_curry2(function path(paths, obj) {
+  var val = obj;
+  var idx = 0;
+  while (idx < paths.length) {
+    if (val == null) {
+      return;
+    }
+    val = val[paths[idx]];
+    idx += 1;
+  }
+  return val;
+});
+export default path;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pathEq.js b/server/node_modules/ramda/es/pathEq.js
new file mode 100644
index 0000000000000000000000000000000000000000..0195e728cb2528218491c7f935c1f7c3819848ce
--- /dev/null
+++ b/server/node_modules/ramda/es/pathEq.js
@@ -0,0 +1,32 @@
+import _curry3 from './internal/_curry3.js';
+import equals from './equals.js';
+import path from './path.js';
+
+/**
+ * Determines whether a nested path on an object has a specific value, in
+ * [`R.equals`](#equals) terms. Most likely used to filter a list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Relation
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> a -> {a} -> Boolean
+ * @param {Array} path The path of the nested property to use
+ * @param {*} val The value to compare the nested property with
+ * @param {Object} obj The object to check the nested property in
+ * @return {Boolean} `true` if the value equals the nested object property,
+ *         `false` otherwise.
+ * @example
+ *
+ *      const user1 = { address: { zipCode: 90210 } };
+ *      const user2 = { address: { zipCode: 55555 } };
+ *      const user3 = { name: 'Bob' };
+ *      const users = [ user1, user2, user3 ];
+ *      const isFamous = R.pathEq(['address', 'zipCode'], 90210);
+ *      R.filter(isFamous, users); //=> [ user1 ]
+ */
+var pathEq = /*#__PURE__*/_curry3(function pathEq(_path, val, obj) {
+  return equals(path(_path, obj), val);
+});
+export default pathEq;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pathOr.js b/server/node_modules/ramda/es/pathOr.js
new file mode 100644
index 0000000000000000000000000000000000000000..301cc27109ce50cdd5bf98ed834776a75423bfa7
--- /dev/null
+++ b/server/node_modules/ramda/es/pathOr.js
@@ -0,0 +1,27 @@
+import _curry3 from './internal/_curry3.js';
+import defaultTo from './defaultTo.js';
+import path from './path.js';
+
+/**
+ * If the given, non-null object has a value at the given path, returns the
+ * value at that path. Otherwise returns the provided default value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig a -> [Idx] -> {a} -> a
+ * @param {*} d The default value.
+ * @param {Array} p The path to use.
+ * @param {Object} obj The object to retrieve the nested property from.
+ * @return {*} The data at `path` of the supplied object or the default value.
+ * @example
+ *
+ *      R.pathOr('N/A', ['a', 'b'], {a: {b: 2}}); //=> 2
+ *      R.pathOr('N/A', ['a', 'b'], {c: {b: 2}}); //=> "N/A"
+ */
+var pathOr = /*#__PURE__*/_curry3(function pathOr(d, p, obj) {
+  return defaultTo(d, path(p, obj));
+});
+export default pathOr;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pathSatisfies.js b/server/node_modules/ramda/es/pathSatisfies.js
new file mode 100644
index 0000000000000000000000000000000000000000..efce498b085604004af1c565b73cff67acf88fa0
--- /dev/null
+++ b/server/node_modules/ramda/es/pathSatisfies.js
@@ -0,0 +1,26 @@
+import _curry3 from './internal/_curry3.js';
+import path from './path.js';
+
+/**
+ * Returns `true` if the specified object property at given path satisfies the
+ * given predicate; `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Logic
+ * @typedefn Idx = String | Int
+ * @sig (a -> Boolean) -> [Idx] -> {a} -> Boolean
+ * @param {Function} pred
+ * @param {Array} propPath
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.propSatisfies, R.path
+ * @example
+ *
+ *      R.pathSatisfies(y => y > 0, ['x', 'y'], {x: {y: 2}}); //=> true
+ */
+var pathSatisfies = /*#__PURE__*/_curry3(function pathSatisfies(pred, propPath, obj) {
+  return propPath.length > 0 && pred(path(propPath, obj));
+});
+export default pathSatisfies;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pick.js b/server/node_modules/ramda/es/pick.js
new file mode 100644
index 0000000000000000000000000000000000000000..90caf0b74b006d4ef51c737380b893bfb5c4b0f3
--- /dev/null
+++ b/server/node_modules/ramda/es/pick.js
@@ -0,0 +1,32 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns a partial copy of an object containing only the keys specified. If
+ * the key does not exist, the property is ignored.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [k] -> {k: v} -> {k: v}
+ * @param {Array} names an array of String property names to copy onto a new object
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with only properties from `names` on it.
+ * @see R.omit, R.props
+ * @example
+ *
+ *      R.pick(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4}
+ *      R.pick(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1}
+ */
+var pick = /*#__PURE__*/_curry2(function pick(names, obj) {
+  var result = {};
+  var idx = 0;
+  while (idx < names.length) {
+    if (names[idx] in obj) {
+      result[names[idx]] = obj[names[idx]];
+    }
+    idx += 1;
+  }
+  return result;
+});
+export default pick;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pickAll.js b/server/node_modules/ramda/es/pickAll.js
new file mode 100644
index 0000000000000000000000000000000000000000..ca3638c56395469b8b77e11098a830cb7e3af15f
--- /dev/null
+++ b/server/node_modules/ramda/es/pickAll.js
@@ -0,0 +1,32 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Similar to `pick` except that this one includes a `key: undefined` pair for
+ * properties that don't exist.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [k] -> {k: v} -> {k: v}
+ * @param {Array} names an array of String property names to copy onto a new object
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with only properties from `names` on it.
+ * @see R.pick
+ * @example
+ *
+ *      R.pickAll(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4}
+ *      R.pickAll(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, e: undefined, f: undefined}
+ */
+var pickAll = /*#__PURE__*/_curry2(function pickAll(names, obj) {
+  var result = {};
+  var idx = 0;
+  var len = names.length;
+  while (idx < len) {
+    var name = names[idx];
+    result[name] = obj[name];
+    idx += 1;
+  }
+  return result;
+});
+export default pickAll;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pickBy.js b/server/node_modules/ramda/es/pickBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..2fd11b656d897d511b37956419c5006ca27df3de
--- /dev/null
+++ b/server/node_modules/ramda/es/pickBy.js
@@ -0,0 +1,32 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns a partial copy of an object containing only the keys that satisfy
+ * the supplied predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @sig ((v, k) -> Boolean) -> {k: v} -> {k: v}
+ * @param {Function} pred A predicate to determine whether or not a key
+ *        should be included on the output object.
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with only properties that satisfy `pred`
+ *         on it.
+ * @see R.pick, R.filter
+ * @example
+ *
+ *      const isUpperCase = (val, key) => key.toUpperCase() === key;
+ *      R.pickBy(isUpperCase, {a: 1, b: 2, A: 3, B: 4}); //=> {A: 3, B: 4}
+ */
+var pickBy = /*#__PURE__*/_curry2(function pickBy(test, obj) {
+  var result = {};
+  for (var prop in obj) {
+    if (test(obj[prop], prop, obj)) {
+      result[prop] = obj[prop];
+    }
+  }
+  return result;
+});
+export default pickBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pipe.js b/server/node_modules/ramda/es/pipe.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab9a73584578f1bd268dd467190fb99e39816753
--- /dev/null
+++ b/server/node_modules/ramda/es/pipe.js
@@ -0,0 +1,34 @@
+import _arity from './internal/_arity.js';
+import _pipe from './internal/_pipe.js';
+import reduce from './reduce.js';
+import tail from './tail.js';
+
+/**
+ * Performs left-to-right function composition. The leftmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * In some libraries this function is named `sequence`.
+ *
+ * **Note:** The result of pipe is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)) -> ((a, b, ..., n) -> z)
+ * @param {...Function} functions
+ * @return {Function}
+ * @see R.compose
+ * @example
+ *
+ *      const f = R.pipe(Math.pow, R.negate, R.inc);
+ *
+ *      f(3, 4); // -(3^4) + 1
+ * @symb R.pipe(f, g, h)(a, b) = h(g(f(a, b)))
+ */
+export default function pipe() {
+  if (arguments.length === 0) {
+    throw new Error('pipe requires at least one argument');
+  }
+  return _arity(arguments[0].length, reduce(_pipe, arguments[0], tail(arguments)));
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pipeK.js b/server/node_modules/ramda/es/pipeK.js
new file mode 100644
index 0000000000000000000000000000000000000000..91fe6a1c3e9fd239e81deb55eccc4c8108bb4ad3
--- /dev/null
+++ b/server/node_modules/ramda/es/pipeK.js
@@ -0,0 +1,44 @@
+import composeK from './composeK.js';
+import reverse from './reverse.js';
+
+/**
+ * Returns the left-to-right Kleisli composition of the provided functions,
+ * each of which must return a value of a type supported by [`chain`](#chain).
+ *
+ * `R.pipeK(f, g, h)` is equivalent to `R.pipe(f, R.chain(g), R.chain(h))`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Function
+ * @sig Chain m => ((a -> m b), (b -> m c), ..., (y -> m z)) -> (a -> m z)
+ * @param {...Function}
+ * @return {Function}
+ * @see R.composeK
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      //  parseJson :: String -> Maybe *
+ *      //  get :: String -> Object -> Maybe *
+ *
+ *      //  getStateCode :: Maybe String -> Maybe String
+ *      const getStateCode = R.pipeK(
+ *        parseJson,
+ *        get('user'),
+ *        get('address'),
+ *        get('state'),
+ *        R.compose(Maybe.of, R.toUpper)
+ *      );
+ *
+ *      getStateCode('{"user":{"address":{"state":"ny"}}}');
+ *      //=> Just('NY')
+ *      getStateCode('[Invalid JSON]');
+ *      //=> Nothing()
+ * @symb R.pipeK(f, g, h)(a) = R.chain(h, R.chain(g, f(a)))
+ */
+export default function pipeK() {
+  if (arguments.length === 0) {
+    throw new Error('pipeK requires at least one argument');
+  }
+  return composeK.apply(this, reverse(arguments));
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pipeP.js b/server/node_modules/ramda/es/pipeP.js
new file mode 100644
index 0000000000000000000000000000000000000000..b880927cbdd715342ce217a60865c3c65a175b33
--- /dev/null
+++ b/server/node_modules/ramda/es/pipeP.js
@@ -0,0 +1,30 @@
+import _arity from './internal/_arity.js';
+import _pipeP from './internal/_pipeP.js';
+import reduce from './reduce.js';
+import tail from './tail.js';
+
+/**
+ * Performs left-to-right composition of one or more Promise-returning
+ * functions. The leftmost function may have any arity; the remaining functions
+ * must be unary.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((a -> Promise b), (b -> Promise c), ..., (y -> Promise z)) -> (a -> Promise z)
+ * @param {...Function} functions
+ * @return {Function}
+ * @see R.composeP
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      //  followersForUser :: String -> Promise [User]
+ *      const followersForUser = R.pipeP(db.getUserById, db.getFollowers);
+ */
+export default function pipeP() {
+  if (arguments.length === 0) {
+    throw new Error('pipeP requires at least one argument');
+  }
+  return _arity(arguments[0].length, reduce(_pipeP, arguments[0], tail(arguments)));
+}
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pipeWith.js b/server/node_modules/ramda/es/pipeWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..b5ada8c5f412f0b7da2ff379d89fb5ce53e54c31
--- /dev/null
+++ b/server/node_modules/ramda/es/pipeWith.js
@@ -0,0 +1,43 @@
+import _arity from './internal/_arity.js';
+import _curry2 from './internal/_curry2.js';
+import head from './head.js';
+import _reduce from './internal/_reduce.js';
+import tail from './tail.js';
+import identity from './identity.js';
+
+/**
+ * Performs left-to-right function composition using transforming function. The leftmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * **Note:** The result of pipeWith is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig ((* -> *), [((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)]) -> ((a, b, ..., n) -> z)
+ * @param {...Function} functions
+ * @return {Function}
+ * @see R.composeWith, R.pipe
+ * @example
+ *
+ *      const pipeWhileNotNil = R.pipeWith((f, res) => R.isNil(res) ? res : f(res));
+ *      const f = pipeWhileNotNil([Math.pow, R.negate, R.inc])
+ *
+ *      f(3, 4); // -(3^4) + 1
+ * @symb R.pipeWith(f)([g, h, i])(...args) = f(i, f(h, f(g, ...args)))
+ */
+var pipeWith = /*#__PURE__*/_curry2(function pipeWith(xf, list) {
+  if (list.length <= 0) {
+    return identity;
+  }
+
+  var headList = head(list);
+  var tailList = tail(list);
+
+  return _arity(headList.length, function () {
+    return _reduce(function (result, f) {
+      return xf.call(this, f, result);
+    }, headList.apply(this, arguments), tailList);
+  });
+});
+export default pipeWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/pluck.js b/server/node_modules/ramda/es/pluck.js
new file mode 100644
index 0000000000000000000000000000000000000000..2837daffb8a2e97c2a96533f6829de58227b838b
--- /dev/null
+++ b/server/node_modules/ramda/es/pluck.js
@@ -0,0 +1,35 @@
+import _curry2 from './internal/_curry2.js';
+import map from './map.js';
+import prop from './prop.js';
+
+/**
+ * Returns a new list by plucking the same named property off all objects in
+ * the list supplied.
+ *
+ * `pluck` will work on
+ * any [functor](https://github.com/fantasyland/fantasy-land#functor) in
+ * addition to arrays, as it is equivalent to `R.map(R.prop(k), f)`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Functor f => k -> f {k: v} -> f v
+ * @param {Number|String} key The key name to pluck off of each object.
+ * @param {Array} f The array or functor to consider.
+ * @return {Array} The list of values for the given key.
+ * @see R.props
+ * @example
+ *
+ *      var getAges = R.pluck('age');
+ *      getAges([{name: 'fred', age: 29}, {name: 'wilma', age: 27}]); //=> [29, 27]
+ *
+ *      R.pluck(0, [[1, 2], [3, 4]]);               //=> [1, 3]
+ *      R.pluck('val', {a: {val: 3}, b: {val: 5}}); //=> {a: 3, b: 5}
+ * @symb R.pluck('x', [{x: 1, y: 2}, {x: 3, y: 4}, {x: 5, y: 6}]) = [1, 3, 5]
+ * @symb R.pluck(0, [[1, 2], [3, 4], [5, 6]]) = [1, 3, 5]
+ */
+var pluck = /*#__PURE__*/_curry2(function pluck(p, list) {
+  return map(prop(p), list);
+});
+export default pluck;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/prepend.js b/server/node_modules/ramda/es/prepend.js
new file mode 100644
index 0000000000000000000000000000000000000000..6084a8c4cf283205f9a0faec67cb077a8901a56a
--- /dev/null
+++ b/server/node_modules/ramda/es/prepend.js
@@ -0,0 +1,24 @@
+import _concat from './internal/_concat.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns a new list with the given element at the front, followed by the
+ * contents of the list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> [a]
+ * @param {*} el The item to add to the head of the output list.
+ * @param {Array} list The array to add to the tail of the output list.
+ * @return {Array} A new array.
+ * @see R.append
+ * @example
+ *
+ *      R.prepend('fee', ['fi', 'fo', 'fum']); //=> ['fee', 'fi', 'fo', 'fum']
+ */
+var prepend = /*#__PURE__*/_curry2(function prepend(el, list) {
+  return _concat([el], list);
+});
+export default prepend;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/product.js b/server/node_modules/ramda/es/product.js
new file mode 100644
index 0000000000000000000000000000000000000000..02d576d3b919833d5a114d1a27de55d3cc5c2f66
--- /dev/null
+++ b/server/node_modules/ramda/es/product.js
@@ -0,0 +1,20 @@
+import multiply from './multiply.js';
+import reduce from './reduce.js';
+
+/**
+ * Multiplies together all the elements of a list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list An array of numbers
+ * @return {Number} The product of all the numbers in the list.
+ * @see R.reduce
+ * @example
+ *
+ *      R.product([2,4,6,8,100,1]); //=> 38400
+ */
+var product = /*#__PURE__*/reduce(multiply, 1);
+export default product;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/project.js b/server/node_modules/ramda/es/project.js
new file mode 100644
index 0000000000000000000000000000000000000000..aa11e5ac0c0ffd03ba805378433c3c26594560a1
--- /dev/null
+++ b/server/node_modules/ramda/es/project.js
@@ -0,0 +1,26 @@
+import _map from './internal/_map.js';
+import identity from './identity.js';
+import pickAll from './pickAll.js';
+import useWith from './useWith.js';
+
+/**
+ * Reasonable analog to SQL `select` statement.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @category Relation
+ * @sig [k] -> [{k: v}] -> [{k: v}]
+ * @param {Array} props The property names to project
+ * @param {Array} objs The objects to query
+ * @return {Array} An array of objects with just the `props` properties.
+ * @example
+ *
+ *      const abby = {name: 'Abby', age: 7, hair: 'blond', grade: 2};
+ *      const fred = {name: 'Fred', age: 12, hair: 'brown', grade: 7};
+ *      const kids = [abby, fred];
+ *      R.project(['name', 'grade'], kids); //=> [{name: 'Abby', grade: 2}, {name: 'Fred', grade: 7}]
+ */
+var project = /*#__PURE__*/useWith(_map, [pickAll, identity]); // passing `identity` gives correct arity
+export default project;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/prop.js b/server/node_modules/ramda/es/prop.js
new file mode 100644
index 0000000000000000000000000000000000000000..8191465ef2242c0d598d54115663bcc292144ab0
--- /dev/null
+++ b/server/node_modules/ramda/es/prop.js
@@ -0,0 +1,27 @@
+import _curry2 from './internal/_curry2.js';
+import path from './path.js';
+
+/**
+ * Returns a function that when supplied an object returns the indicated
+ * property of that object, if it exists.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig s -> {s: a} -> a | Undefined
+ * @param {String} p The property name
+ * @param {Object} obj The object to query
+ * @return {*} The value at `obj.p`.
+ * @see R.path
+ * @example
+ *
+ *      R.prop('x', {x: 100}); //=> 100
+ *      R.prop('x', {}); //=> undefined
+ *      R.compose(R.inc, R.prop('x'))({ x: 3 }) //=> 4
+ */
+
+var prop = /*#__PURE__*/_curry2(function prop(p, obj) {
+  return path([p], obj);
+});
+export default prop;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/propEq.js b/server/node_modules/ramda/es/propEq.js
new file mode 100644
index 0000000000000000000000000000000000000000..6ded211a447c7c589a9e6cc076876a029eaee08e
--- /dev/null
+++ b/server/node_modules/ramda/es/propEq.js
@@ -0,0 +1,32 @@
+import _curry3 from './internal/_curry3.js';
+import equals from './equals.js';
+
+/**
+ * Returns `true` if the specified object property is equal, in
+ * [`R.equals`](#equals) terms, to the given value; `false` otherwise.
+ * You can test multiple properties with [`R.whereEq`](#whereEq).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig String -> a -> Object -> Boolean
+ * @param {String} name
+ * @param {*} val
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.whereEq, R.propSatisfies, R.equals
+ * @example
+ *
+ *      const abby = {name: 'Abby', age: 7, hair: 'blond'};
+ *      const fred = {name: 'Fred', age: 12, hair: 'brown'};
+ *      const rusty = {name: 'Rusty', age: 10, hair: 'brown'};
+ *      const alois = {name: 'Alois', age: 15, disposition: 'surly'};
+ *      const kids = [abby, fred, rusty, alois];
+ *      const hasBrownHair = R.propEq('hair', 'brown');
+ *      R.filter(hasBrownHair, kids); //=> [fred, rusty]
+ */
+var propEq = /*#__PURE__*/_curry3(function propEq(name, val, obj) {
+  return equals(val, obj[name]);
+});
+export default propEq;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/propIs.js b/server/node_modules/ramda/es/propIs.js
new file mode 100644
index 0000000000000000000000000000000000000000..71c6939bc476201aee58c371589753aab0898eb3
--- /dev/null
+++ b/server/node_modules/ramda/es/propIs.js
@@ -0,0 +1,27 @@
+import _curry3 from './internal/_curry3.js';
+import is from './is.js';
+
+/**
+ * Returns `true` if the specified object property is of the given type;
+ * `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Type
+ * @sig Type -> String -> Object -> Boolean
+ * @param {Function} type
+ * @param {String} name
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.is, R.propSatisfies
+ * @example
+ *
+ *      R.propIs(Number, 'x', {x: 1, y: 2});  //=> true
+ *      R.propIs(Number, 'x', {x: 'foo'});    //=> false
+ *      R.propIs(Number, 'x', {});            //=> false
+ */
+var propIs = /*#__PURE__*/_curry3(function propIs(type, name, obj) {
+  return is(type, obj[name]);
+});
+export default propIs;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/propOr.js b/server/node_modules/ramda/es/propOr.js
new file mode 100644
index 0000000000000000000000000000000000000000..da6c5f8a49299443ebaa16550aa8cb50422ae094
--- /dev/null
+++ b/server/node_modules/ramda/es/propOr.js
@@ -0,0 +1,33 @@
+import _curry3 from './internal/_curry3.js';
+import pathOr from './pathOr.js';
+
+/**
+ * If the given, non-null object has an own property with the specified name,
+ * returns the value of that property. Otherwise returns the provided default
+ * value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category Object
+ * @sig a -> String -> Object -> a
+ * @param {*} val The default value.
+ * @param {String} p The name of the property to return.
+ * @param {Object} obj The object to query.
+ * @return {*} The value of given property of the supplied object or the default value.
+ * @example
+ *
+ *      const alice = {
+ *        name: 'ALICE',
+ *        age: 101
+ *      };
+ *      const favorite = R.prop('favoriteLibrary');
+ *      const favoriteWithDefault = R.propOr('Ramda', 'favoriteLibrary');
+ *
+ *      favorite(alice);  //=> undefined
+ *      favoriteWithDefault(alice);  //=> 'Ramda'
+ */
+var propOr = /*#__PURE__*/_curry3(function propOr(val, p, obj) {
+  return pathOr(val, [p], obj);
+});
+export default propOr;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/propSatisfies.js b/server/node_modules/ramda/es/propSatisfies.js
new file mode 100644
index 0000000000000000000000000000000000000000..b376eea621c2dcb879aafc0f6f40aea25e7d9ada
--- /dev/null
+++ b/server/node_modules/ramda/es/propSatisfies.js
@@ -0,0 +1,25 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Returns `true` if the specified object property satisfies the given
+ * predicate; `false` otherwise. You can test multiple properties with
+ * [`R.where`](#where).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Logic
+ * @sig (a -> Boolean) -> String -> {String: a} -> Boolean
+ * @param {Function} pred
+ * @param {String} name
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.where, R.propEq, R.propIs
+ * @example
+ *
+ *      R.propSatisfies(x => x > 0, 'x', {x: 1, y: 2}); //=> true
+ */
+var propSatisfies = /*#__PURE__*/_curry3(function propSatisfies(pred, name, obj) {
+  return pred(obj[name]);
+});
+export default propSatisfies;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/props.js b/server/node_modules/ramda/es/props.js
new file mode 100644
index 0000000000000000000000000000000000000000..816f7d277600f81abf9e8924f379a75eb1669077
--- /dev/null
+++ b/server/node_modules/ramda/es/props.js
@@ -0,0 +1,35 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Acts as multiple `prop`: array of keys in, array of values out. Preserves
+ * order.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [k] -> {k: v} -> [v]
+ * @param {Array} ps The property names to fetch
+ * @param {Object} obj The object to query
+ * @return {Array} The corresponding values or partially applied function.
+ * @example
+ *
+ *      R.props(['x', 'y'], {x: 1, y: 2}); //=> [1, 2]
+ *      R.props(['c', 'a', 'b'], {b: 2, a: 1}); //=> [undefined, 1, 2]
+ *
+ *      const fullName = R.compose(R.join(' '), R.props(['first', 'last']));
+ *      fullName({last: 'Bullet-Tooth', age: 33, first: 'Tony'}); //=> 'Tony Bullet-Tooth'
+ */
+var props = /*#__PURE__*/_curry2(function props(ps, obj) {
+  var len = ps.length;
+  var out = [];
+  var idx = 0;
+
+  while (idx < len) {
+    out[idx] = obj[ps[idx]];
+    idx += 1;
+  }
+
+  return out;
+});
+export default props;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/range.js b/server/node_modules/ramda/es/range.js
new file mode 100644
index 0000000000000000000000000000000000000000..39f2356c0224551850284eec9b50632d7bb6e903
--- /dev/null
+++ b/server/node_modules/ramda/es/range.js
@@ -0,0 +1,32 @@
+import _curry2 from './internal/_curry2.js';
+import _isNumber from './internal/_isNumber.js';
+
+/**
+ * Returns a list of numbers from `from` (inclusive) to `to` (exclusive).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> Number -> [Number]
+ * @param {Number} from The first number in the list.
+ * @param {Number} to One more than the last number in the list.
+ * @return {Array} The list of numbers in the set `[a, b)`.
+ * @example
+ *
+ *      R.range(1, 5);    //=> [1, 2, 3, 4]
+ *      R.range(50, 53);  //=> [50, 51, 52]
+ */
+var range = /*#__PURE__*/_curry2(function range(from, to) {
+  if (!(_isNumber(from) && _isNumber(to))) {
+    throw new TypeError('Both arguments to range must be numbers');
+  }
+  var result = [];
+  var n = from;
+  while (n < to) {
+    result.push(n);
+    n += 1;
+  }
+  return result;
+});
+export default range;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/reduce.js b/server/node_modules/ramda/es/reduce.js
new file mode 100644
index 0000000000000000000000000000000000000000..31180f4c80cbb150760865f8524f648d6180ef5f
--- /dev/null
+++ b/server/node_modules/ramda/es/reduce.js
@@ -0,0 +1,51 @@
+import _curry3 from './internal/_curry3.js';
+import _reduce from './internal/_reduce.js';
+
+/**
+ * Returns a single item by iterating through the list, successively calling
+ * the iterator function and passing it an accumulator value and the current
+ * value from the array, and then passing the result to the next call.
+ *
+ * The iterator function receives two values: *(acc, value)*. It may use
+ * [`R.reduced`](#reduced) to shortcut the iteration.
+ *
+ * The arguments' order of [`reduceRight`](#reduceRight)'s iterator function
+ * is *(value, acc)*.
+ *
+ * Note: `R.reduce` does not skip deleted or unassigned indices (sparse
+ * arrays), unlike the native `Array.prototype.reduce` method. For more details
+ * on this behavior, see:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description
+ *
+ * Dispatches to the `reduce` method of the third argument, if present. When
+ * doing so, it is up to the user to handle the [`R.reduced`](#reduced)
+ * shortcuting, as this is not implemented by `reduce`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, b) -> a) -> a -> [b] -> a
+ * @param {Function} fn The iterator function. Receives two values, the accumulator and the
+ *        current element from the array.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduced, R.addIndex, R.reduceRight
+ * @example
+ *
+ *      R.reduce(R.subtract, 0, [1, 2, 3, 4]) // => ((((0 - 1) - 2) - 3) - 4) = -10
+ *      //          -               -10
+ *      //         / \              / \
+ *      //        -   4           -6   4
+ *      //       / \              / \
+ *      //      -   3   ==>     -3   3
+ *      //     / \              / \
+ *      //    -   2           -1   2
+ *      //   / \              / \
+ *      //  0   1            0   1
+ *
+ * @symb R.reduce(f, a, [b, c, d]) = f(f(f(a, b), c), d)
+ */
+var reduce = /*#__PURE__*/_curry3(_reduce);
+export default reduce;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/reduceBy.js b/server/node_modules/ramda/es/reduceBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..d765f59f019dd0bd15e86a00e53d854fc0f0ee8c
--- /dev/null
+++ b/server/node_modules/ramda/es/reduceBy.js
@@ -0,0 +1,55 @@
+import _curryN from './internal/_curryN.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _has from './internal/_has.js';
+import _reduce from './internal/_reduce.js';
+import _xreduceBy from './internal/_xreduceBy.js';
+
+/**
+ * Groups the elements of the list according to the result of calling
+ * the String-returning function `keyFn` on each element and reduces the elements
+ * of each group to a single value via the reducer function `valueFn`.
+ *
+ * This function is basically a more general [`groupBy`](#groupBy) function.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category List
+ * @sig ((a, b) -> a) -> a -> (b -> String) -> [b] -> {String: a}
+ * @param {Function} valueFn The function that reduces the elements of each group to a single
+ *        value. Receives two values, accumulator for a particular group and the current element.
+ * @param {*} acc The (initial) accumulator value for each group.
+ * @param {Function} keyFn The function that maps the list's element into a key.
+ * @param {Array} list The array to group.
+ * @return {Object} An object with the output of `keyFn` for keys, mapped to the output of
+ *         `valueFn` for elements which produced that key when passed to `keyFn`.
+ * @see R.groupBy, R.reduce
+ * @example
+ *
+ *      const groupNames = (acc, {name}) => acc.concat(name)
+ *      const toGrade = ({score}) =>
+ *        score < 65 ? 'F' :
+ *        score < 70 ? 'D' :
+ *        score < 80 ? 'C' :
+ *        score < 90 ? 'B' : 'A'
+ *
+ *      var students = [
+ *        {name: 'Abby', score: 83},
+ *        {name: 'Bart', score: 62},
+ *        {name: 'Curt', score: 88},
+ *        {name: 'Dora', score: 92},
+ *      ]
+ *
+ *      reduceBy(groupNames, [], toGrade, students)
+ *      //=> {"A": ["Dora"], "B": ["Abby", "Curt"], "F": ["Bart"]}
+ */
+var reduceBy = /*#__PURE__*/_curryN(4, [], /*#__PURE__*/_dispatchable([], _xreduceBy, function reduceBy(valueFn, valueAcc, keyFn, list) {
+  return _reduce(function (acc, elt) {
+    var key = keyFn(elt);
+    acc[key] = valueFn(_has(key, acc) ? acc[key] : valueAcc, elt);
+    return acc;
+  }, {}, list);
+}));
+export default reduceBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/reduceRight.js b/server/node_modules/ramda/es/reduceRight.js
new file mode 100644
index 0000000000000000000000000000000000000000..4008ec77214b771f3ccfaa4ae5cc2339b39d334a
--- /dev/null
+++ b/server/node_modules/ramda/es/reduceRight.js
@@ -0,0 +1,53 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Returns a single item by iterating through the list, successively calling
+ * the iterator function and passing it an accumulator value and the current
+ * value from the array, and then passing the result to the next call.
+ *
+ * Similar to [`reduce`](#reduce), except moves through the input list from the
+ * right to the left.
+ *
+ * The iterator function receives two values: *(value, acc)*, while the arguments'
+ * order of `reduce`'s iterator function is *(acc, value)*.
+ *
+ * Note: `R.reduceRight` does not skip deleted or unassigned indices (sparse
+ * arrays), unlike the native `Array.prototype.reduceRight` method. For more details
+ * on this behavior, see:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight#Description
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, b) -> b) -> b -> [a] -> b
+ * @param {Function} fn The iterator function. Receives two values, the current element from the array
+ *        and the accumulator.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduce, R.addIndex
+ * @example
+ *
+ *      R.reduceRight(R.subtract, 0, [1, 2, 3, 4]) // => (1 - (2 - (3 - (4 - 0)))) = -2
+ *      //    -               -2
+ *      //   / \              / \
+ *      //  1   -            1   3
+ *      //     / \              / \
+ *      //    2   -     ==>    2  -1
+ *      //       / \              / \
+ *      //      3   -            3   4
+ *      //         / \              / \
+ *      //        4   0            4   0
+ *
+ * @symb R.reduceRight(f, a, [b, c, d]) = f(b, f(c, f(d, a)))
+ */
+var reduceRight = /*#__PURE__*/_curry3(function reduceRight(fn, acc, list) {
+  var idx = list.length - 1;
+  while (idx >= 0) {
+    acc = fn(list[idx], acc);
+    idx -= 1;
+  }
+  return acc;
+});
+export default reduceRight;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/reduceWhile.js b/server/node_modules/ramda/es/reduceWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..dd1efd4a7b9e9a5fcadab6155b9a5324f3778e62
--- /dev/null
+++ b/server/node_modules/ramda/es/reduceWhile.js
@@ -0,0 +1,39 @@
+import _curryN from './internal/_curryN.js';
+import _reduce from './internal/_reduce.js';
+import _reduced from './internal/_reduced.js';
+
+/**
+ * Like [`reduce`](#reduce), `reduceWhile` returns a single item by iterating
+ * through the list, successively calling the iterator function. `reduceWhile`
+ * also takes a predicate that is evaluated before each step. If the predicate
+ * returns `false`, it "short-circuits" the iteration and returns the current
+ * value of the accumulator.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.22.0
+ * @category List
+ * @sig ((a, b) -> Boolean) -> ((a, b) -> a) -> a -> [b] -> a
+ * @param {Function} pred The predicate. It is passed the accumulator and the
+ *        current element.
+ * @param {Function} fn The iterator function. Receives two values, the
+ *        accumulator and the current element.
+ * @param {*} a The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduce, R.reduced
+ * @example
+ *
+ *      const isOdd = (acc, x) => x % 2 === 1;
+ *      const xs = [1, 3, 5, 60, 777, 800];
+ *      R.reduceWhile(isOdd, R.add, 0, xs); //=> 9
+ *
+ *      const ys = [2, 4, 6]
+ *      R.reduceWhile(isOdd, R.add, 111, ys); //=> 111
+ */
+var reduceWhile = /*#__PURE__*/_curryN(4, [], function _reduceWhile(pred, fn, a, list) {
+  return _reduce(function (acc, x) {
+    return pred(acc, x) ? fn(acc, x) : _reduced(acc);
+  }, a, list);
+});
+export default reduceWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/reduced.js b/server/node_modules/ramda/es/reduced.js
new file mode 100644
index 0000000000000000000000000000000000000000..10ff9b7fa592e6dd910d9f8095c686efc02ad8fa
--- /dev/null
+++ b/server/node_modules/ramda/es/reduced.js
@@ -0,0 +1,30 @@
+import _curry1 from './internal/_curry1.js';
+import _reduced from './internal/_reduced.js';
+
+/**
+ * Returns a value wrapped to indicate that it is the final value of the reduce
+ * and transduce functions. The returned value should be considered a black
+ * box: the internal structure is not guaranteed to be stable.
+ *
+ * Note: this optimization is only available to the below functions:
+ * - [`reduce`](#reduce)
+ * - [`reduceWhile`](#reduceWhile)
+ * - [`transduce`](#transduce)
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category List
+ * @sig a -> *
+ * @param {*} x The final value of the reduce.
+ * @return {*} The wrapped value.
+ * @see R.reduce, R.reduceWhile, R.transduce
+ * @example
+ *
+ *     R.reduce(
+ *       (acc, item) => item > 3 ? R.reduced(acc) : acc.concat(item),
+ *       [],
+ *       [1, 2, 3, 4, 5]) // [1, 2, 3]
+ */
+var reduced = /*#__PURE__*/_curry1(_reduced);
+export default reduced;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/reject.js b/server/node_modules/ramda/es/reject.js
new file mode 100644
index 0000000000000000000000000000000000000000..a7764c9fd5b79c0d7fb55521e58bd0bf499a0d15
--- /dev/null
+++ b/server/node_modules/ramda/es/reject.js
@@ -0,0 +1,32 @@
+import _complement from './internal/_complement.js';
+import _curry2 from './internal/_curry2.js';
+import filter from './filter.js';
+
+/**
+ * The complement of [`filter`](#filter).
+ *
+ * Acts as a transducer if a transformer is given in list position. Filterable
+ * objects include plain objects or any object that has a filter method such
+ * as `Array`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Filterable f => (a -> Boolean) -> f a -> f a
+ * @param {Function} pred
+ * @param {Array} filterable
+ * @return {Array}
+ * @see R.filter, R.transduce, R.addIndex
+ * @example
+ *
+ *      const isOdd = (n) => n % 2 === 1;
+ *
+ *      R.reject(isOdd, [1, 2, 3, 4]); //=> [2, 4]
+ *
+ *      R.reject(isOdd, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4}
+ */
+var reject = /*#__PURE__*/_curry2(function reject(pred, filterable) {
+  return filter(_complement(pred), filterable);
+});
+export default reject;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/remove.js b/server/node_modules/ramda/es/remove.js
new file mode 100644
index 0000000000000000000000000000000000000000..47a9312234fa1687f7ca8568514d5391d3ddeb63
--- /dev/null
+++ b/server/node_modules/ramda/es/remove.js
@@ -0,0 +1,28 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Removes the sub-list of `list` starting at index `start` and containing
+ * `count` elements. _Note that this is not destructive_: it returns a copy of
+ * the list with the changes.
+ * <small>No lists have been harmed in the application of this function.</small>
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.2
+ * @category List
+ * @sig Number -> Number -> [a] -> [a]
+ * @param {Number} start The position to start removing elements
+ * @param {Number} count The number of elements to remove
+ * @param {Array} list The list to remove from
+ * @return {Array} A new Array with `count` elements from `start` removed.
+ * @see R.without
+ * @example
+ *
+ *      R.remove(2, 3, [1,2,3,4,5,6,7,8]); //=> [1,2,6,7,8]
+ */
+var remove = /*#__PURE__*/_curry3(function remove(start, count, list) {
+  var result = Array.prototype.slice.call(list, 0);
+  result.splice(start, count);
+  return result;
+});
+export default remove;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/repeat.js b/server/node_modules/ramda/es/repeat.js
new file mode 100644
index 0000000000000000000000000000000000000000..0083526dc7ce3eb232476e2f8d3591973107fae4
--- /dev/null
+++ b/server/node_modules/ramda/es/repeat.js
@@ -0,0 +1,31 @@
+import _curry2 from './internal/_curry2.js';
+import always from './always.js';
+import times from './times.js';
+
+/**
+ * Returns a fixed list of size `n` containing a specified identical value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig a -> n -> [a]
+ * @param {*} value The value to repeat.
+ * @param {Number} n The desired size of the output list.
+ * @return {Array} A new array containing `n` `value`s.
+ * @see R.times
+ * @example
+ *
+ *      R.repeat('hi', 5); //=> ['hi', 'hi', 'hi', 'hi', 'hi']
+ *
+ *      const obj = {};
+ *      const repeatedObjs = R.repeat(obj, 5); //=> [{}, {}, {}, {}, {}]
+ *      repeatedObjs[0] === repeatedObjs[1]; //=> true
+ * @symb R.repeat(a, 0) = []
+ * @symb R.repeat(a, 1) = [a]
+ * @symb R.repeat(a, 2) = [a, a]
+ */
+var repeat = /*#__PURE__*/_curry2(function repeat(value, n) {
+  return times(always(value), n);
+});
+export default repeat;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/replace.js b/server/node_modules/ramda/es/replace.js
new file mode 100644
index 0000000000000000000000000000000000000000..aa4287b8940e2e9f851bdef5a7434d87ef42928e
--- /dev/null
+++ b/server/node_modules/ramda/es/replace.js
@@ -0,0 +1,30 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Replace a substring or regex match in a string with a replacement.
+ *
+ * The first two parameters correspond to the parameters of the
+ * `String.prototype.replace()` function, so the second parameter can also be a
+ * function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category String
+ * @sig RegExp|String -> String -> String -> String
+ * @param {RegExp|String} pattern A regular expression or a substring to match.
+ * @param {String} replacement The string to replace the matches with.
+ * @param {String} str The String to do the search and replacement in.
+ * @return {String} The result.
+ * @example
+ *
+ *      R.replace('foo', 'bar', 'foo foo foo'); //=> 'bar foo foo'
+ *      R.replace(/foo/, 'bar', 'foo foo foo'); //=> 'bar foo foo'
+ *
+ *      // Use the "g" (global) flag to replace all occurrences:
+ *      R.replace(/foo/g, 'bar', 'foo foo foo'); //=> 'bar bar bar'
+ */
+var replace = /*#__PURE__*/_curry3(function replace(regex, replacement, str) {
+  return str.replace(regex, replacement);
+});
+export default replace;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/reverse.js b/server/node_modules/ramda/es/reverse.js
new file mode 100644
index 0000000000000000000000000000000000000000..b5912fd433c7ae61468d98ae59accdf13f00fa7f
--- /dev/null
+++ b/server/node_modules/ramda/es/reverse.js
@@ -0,0 +1,31 @@
+import _curry1 from './internal/_curry1.js';
+import _isString from './internal/_isString.js';
+
+/**
+ * Returns a new list or string with the elements or characters in reverse
+ * order.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a]
+ * @sig String -> String
+ * @param {Array|String} list
+ * @return {Array|String}
+ * @example
+ *
+ *      R.reverse([1, 2, 3]);  //=> [3, 2, 1]
+ *      R.reverse([1, 2]);     //=> [2, 1]
+ *      R.reverse([1]);        //=> [1]
+ *      R.reverse([]);         //=> []
+ *
+ *      R.reverse('abc');      //=> 'cba'
+ *      R.reverse('ab');       //=> 'ba'
+ *      R.reverse('a');        //=> 'a'
+ *      R.reverse('');         //=> ''
+ */
+var reverse = /*#__PURE__*/_curry1(function reverse(list) {
+  return _isString(list) ? list.split('').reverse().join('') : Array.prototype.slice.call(list, 0).reverse();
+});
+export default reverse;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/scan.js b/server/node_modules/ramda/es/scan.js
new file mode 100644
index 0000000000000000000000000000000000000000..1941b72163176aaee94ac229413cf66ed3cb3f16
--- /dev/null
+++ b/server/node_modules/ramda/es/scan.js
@@ -0,0 +1,35 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Scan is similar to [`reduce`](#reduce), but returns a list of successively
+ * reduced values from the left
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig ((a, b) -> a) -> a -> [b] -> [a]
+ * @param {Function} fn The iterator function. Receives two values, the accumulator and the
+ *        current element from the array
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {Array} A list of all intermediately reduced values.
+ * @see R.reduce, R.mapAccum
+ * @example
+ *
+ *      const numbers = [1, 2, 3, 4];
+ *      const factorials = R.scan(R.multiply, 1, numbers); //=> [1, 1, 2, 6, 24]
+ * @symb R.scan(f, a, [b, c]) = [a, f(a, b), f(f(a, b), c)]
+ */
+var scan = /*#__PURE__*/_curry3(function scan(fn, acc, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [acc];
+  while (idx < len) {
+    acc = fn(acc, list[idx]);
+    result[idx + 1] = acc;
+    idx += 1;
+  }
+  return result;
+});
+export default scan;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/sequence.js b/server/node_modules/ramda/es/sequence.js
new file mode 100644
index 0000000000000000000000000000000000000000..e0be3ca8a3a1054885d6aef51b1e86406a6d9aa5
--- /dev/null
+++ b/server/node_modules/ramda/es/sequence.js
@@ -0,0 +1,36 @@
+import _curry2 from './internal/_curry2.js';
+import ap from './ap.js';
+import map from './map.js';
+import prepend from './prepend.js';
+import reduceRight from './reduceRight.js';
+
+/**
+ * Transforms a [Traversable](https://github.com/fantasyland/fantasy-land#traversable)
+ * of [Applicative](https://github.com/fantasyland/fantasy-land#applicative) into an
+ * Applicative of Traversable.
+ *
+ * Dispatches to the `sequence` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (Applicative f, Traversable t) => (a -> f a) -> t (f a) -> f (t a)
+ * @param {Function} of
+ * @param {*} traversable
+ * @return {*}
+ * @see R.traverse
+ * @example
+ *
+ *      R.sequence(Maybe.of, [Just(1), Just(2), Just(3)]);   //=> Just([1, 2, 3])
+ *      R.sequence(Maybe.of, [Just(1), Just(2), Nothing()]); //=> Nothing()
+ *
+ *      R.sequence(R.of, Just([1, 2, 3])); //=> [Just(1), Just(2), Just(3)]
+ *      R.sequence(R.of, Nothing());       //=> [Nothing()]
+ */
+var sequence = /*#__PURE__*/_curry2(function sequence(of, traversable) {
+  return typeof traversable.sequence === 'function' ? traversable.sequence(of) : reduceRight(function (x, acc) {
+    return ap(map(prepend, x), acc);
+  }, of([]), traversable);
+});
+export default sequence;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/set.js b/server/node_modules/ramda/es/set.js
new file mode 100644
index 0000000000000000000000000000000000000000..95da12e041cba55cb80f64c3fc7539b15b1a3ead
--- /dev/null
+++ b/server/node_modules/ramda/es/set.js
@@ -0,0 +1,30 @@
+import _curry3 from './internal/_curry3.js';
+import always from './always.js';
+import over from './over.js';
+
+/**
+ * Returns the result of "setting" the portion of the given data structure
+ * focused by the given lens to the given value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Lens s a -> a -> s -> s
+ * @param {Lens} lens
+ * @param {*} v
+ * @param {*} x
+ * @return {*}
+ * @see R.prop, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const xLens = R.lensProp('x');
+ *
+ *      R.set(xLens, 4, {x: 1, y: 2});  //=> {x: 4, y: 2}
+ *      R.set(xLens, 8, {x: 1, y: 2});  //=> {x: 8, y: 2}
+ */
+var set = /*#__PURE__*/_curry3(function set(lens, v, x) {
+  return over(lens, always(v), x);
+});
+export default set;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/slice.js b/server/node_modules/ramda/es/slice.js
new file mode 100644
index 0000000000000000000000000000000000000000..ea2042e47a8b1042bb87159f19647eacd1b0fca4
--- /dev/null
+++ b/server/node_modules/ramda/es/slice.js
@@ -0,0 +1,31 @@
+import _checkForMethod from './internal/_checkForMethod.js';
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Returns the elements of the given list or string (or object with a `slice`
+ * method) from `fromIndex` (inclusive) to `toIndex` (exclusive).
+ *
+ * Dispatches to the `slice` method of the third argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.4
+ * @category List
+ * @sig Number -> Number -> [a] -> [a]
+ * @sig Number -> Number -> String -> String
+ * @param {Number} fromIndex The start index (inclusive).
+ * @param {Number} toIndex The end index (exclusive).
+ * @param {*} list
+ * @return {*}
+ * @example
+ *
+ *      R.slice(1, 3, ['a', 'b', 'c', 'd']);        //=> ['b', 'c']
+ *      R.slice(1, Infinity, ['a', 'b', 'c', 'd']); //=> ['b', 'c', 'd']
+ *      R.slice(0, -1, ['a', 'b', 'c', 'd']);       //=> ['a', 'b', 'c']
+ *      R.slice(-3, -1, ['a', 'b', 'c', 'd']);      //=> ['b', 'c']
+ *      R.slice(0, 3, 'ramda');                     //=> 'ram'
+ */
+var slice = /*#__PURE__*/_curry3( /*#__PURE__*/_checkForMethod('slice', function slice(fromIndex, toIndex, list) {
+  return Array.prototype.slice.call(list, fromIndex, toIndex);
+}));
+export default slice;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/sort.js b/server/node_modules/ramda/es/sort.js
new file mode 100644
index 0000000000000000000000000000000000000000..276f27348028b3728e81f96384707155382aabd8
--- /dev/null
+++ b/server/node_modules/ramda/es/sort.js
@@ -0,0 +1,26 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns a copy of the list, sorted according to the comparator function,
+ * which should accept two values at a time and return a negative number if the
+ * first value is smaller, a positive number if it's larger, and zero if they
+ * are equal. Please note that this is a **copy** of the list. It does not
+ * modify the original.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, a) -> Number) -> [a] -> [a]
+ * @param {Function} comparator A sorting function :: a -> b -> Int
+ * @param {Array} list The list to sort
+ * @return {Array} a new array with its elements sorted by the comparator function.
+ * @example
+ *
+ *      const diff = function(a, b) { return a - b; };
+ *      R.sort(diff, [4,2,7,5]); //=> [2, 4, 5, 7]
+ */
+var sort = /*#__PURE__*/_curry2(function sort(comparator, list) {
+  return Array.prototype.slice.call(list, 0).sort(comparator);
+});
+export default sort;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/sortBy.js b/server/node_modules/ramda/es/sortBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..99ba5df370908ed1f0ef72f9e51dd68477705117
--- /dev/null
+++ b/server/node_modules/ramda/es/sortBy.js
@@ -0,0 +1,43 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Sorts the list according to the supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord b => (a -> b) -> [a] -> [a]
+ * @param {Function} fn
+ * @param {Array} list The list to sort.
+ * @return {Array} A new list sorted by the keys generated by `fn`.
+ * @example
+ *
+ *      const sortByFirstItem = R.sortBy(R.prop(0));
+ *      const pairs = [[-1, 1], [-2, 2], [-3, 3]];
+ *      sortByFirstItem(pairs); //=> [[-3, 3], [-2, 2], [-1, 1]]
+ *
+ *      const sortByNameCaseInsensitive = R.sortBy(R.compose(R.toLower, R.prop('name')));
+ *      const alice = {
+ *        name: 'ALICE',
+ *        age: 101
+ *      };
+ *      const bob = {
+ *        name: 'Bob',
+ *        age: -10
+ *      };
+ *      const clara = {
+ *        name: 'clara',
+ *        age: 314.159
+ *      };
+ *      const people = [clara, bob, alice];
+ *      sortByNameCaseInsensitive(people); //=> [alice, bob, clara]
+ */
+var sortBy = /*#__PURE__*/_curry2(function sortBy(fn, list) {
+  return Array.prototype.slice.call(list, 0).sort(function (a, b) {
+    var aa = fn(a);
+    var bb = fn(b);
+    return aa < bb ? -1 : aa > bb ? 1 : 0;
+  });
+});
+export default sortBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/sortWith.js b/server/node_modules/ramda/es/sortWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..14d92f3c67d48c1245c557c98c4959c4ba2a0db7
--- /dev/null
+++ b/server/node_modules/ramda/es/sortWith.js
@@ -0,0 +1,46 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Sorts a list according to a list of comparators.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Relation
+ * @sig [(a, a) -> Number] -> [a] -> [a]
+ * @param {Array} functions A list of comparator functions.
+ * @param {Array} list The list to sort.
+ * @return {Array} A new list sorted according to the comarator functions.
+ * @example
+ *
+ *      const alice = {
+ *        name: 'alice',
+ *        age: 40
+ *      };
+ *      const bob = {
+ *        name: 'bob',
+ *        age: 30
+ *      };
+ *      const clara = {
+ *        name: 'clara',
+ *        age: 40
+ *      };
+ *      const people = [clara, bob, alice];
+ *      const ageNameSort = R.sortWith([
+ *        R.descend(R.prop('age')),
+ *        R.ascend(R.prop('name'))
+ *      ]);
+ *      ageNameSort(people); //=> [alice, clara, bob]
+ */
+var sortWith = /*#__PURE__*/_curry2(function sortWith(fns, list) {
+  return Array.prototype.slice.call(list, 0).sort(function (a, b) {
+    var result = 0;
+    var i = 0;
+    while (result === 0 && i < fns.length) {
+      result = fns[i](a, b);
+      i += 1;
+    }
+    return result;
+  });
+});
+export default sortWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/split.js b/server/node_modules/ramda/es/split.js
new file mode 100644
index 0000000000000000000000000000000000000000..575b824fa3ddf9600d34fd5373a6a0d9d14be15f
--- /dev/null
+++ b/server/node_modules/ramda/es/split.js
@@ -0,0 +1,24 @@
+import invoker from './invoker.js';
+
+/**
+ * Splits a string into an array of strings based on the given
+ * separator.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category String
+ * @sig (String | RegExp) -> String -> [String]
+ * @param {String|RegExp} sep The pattern.
+ * @param {String} str The string to separate into an array.
+ * @return {Array} The array of strings from `str` separated by `str`.
+ * @see R.join
+ * @example
+ *
+ *      const pathComponents = R.split('/');
+ *      R.tail(pathComponents('/usr/local/bin/node')); //=> ['usr', 'local', 'bin', 'node']
+ *
+ *      R.split('.', 'a.b.c.xyz.d'); //=> ['a', 'b', 'c', 'xyz', 'd']
+ */
+var split = /*#__PURE__*/invoker(1, 'split');
+export default split;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/splitAt.js b/server/node_modules/ramda/es/splitAt.js
new file mode 100644
index 0000000000000000000000000000000000000000..cc6fea2348464f57d6cca04320d1b859fa3bfc73
--- /dev/null
+++ b/server/node_modules/ramda/es/splitAt.js
@@ -0,0 +1,26 @@
+import _curry2 from './internal/_curry2.js';
+import length from './length.js';
+import slice from './slice.js';
+
+/**
+ * Splits a given list or string at a given index.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig Number -> [a] -> [[a], [a]]
+ * @sig Number -> String -> [String, String]
+ * @param {Number} index The index where the array/string is split.
+ * @param {Array|String} array The array/string to be split.
+ * @return {Array}
+ * @example
+ *
+ *      R.splitAt(1, [1, 2, 3]);          //=> [[1], [2, 3]]
+ *      R.splitAt(5, 'hello world');      //=> ['hello', ' world']
+ *      R.splitAt(-1, 'foobar');          //=> ['fooba', 'r']
+ */
+var splitAt = /*#__PURE__*/_curry2(function splitAt(index, array) {
+  return [slice(0, index, array), slice(index, length(array), array)];
+});
+export default splitAt;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/splitEvery.js b/server/node_modules/ramda/es/splitEvery.js
new file mode 100644
index 0000000000000000000000000000000000000000..2839db57c143a90ae6125f2d22e1b43e4c25220d
--- /dev/null
+++ b/server/node_modules/ramda/es/splitEvery.js
@@ -0,0 +1,32 @@
+import _curry2 from './internal/_curry2.js';
+import slice from './slice.js';
+
+/**
+ * Splits a collection into slices of the specified length.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig Number -> [a] -> [[a]]
+ * @sig Number -> String -> [String]
+ * @param {Number} n
+ * @param {Array} list
+ * @return {Array}
+ * @example
+ *
+ *      R.splitEvery(3, [1, 2, 3, 4, 5, 6, 7]); //=> [[1, 2, 3], [4, 5, 6], [7]]
+ *      R.splitEvery(3, 'foobarbaz'); //=> ['foo', 'bar', 'baz']
+ */
+var splitEvery = /*#__PURE__*/_curry2(function splitEvery(n, list) {
+  if (n <= 0) {
+    throw new Error('First argument to splitEvery must be a positive integer');
+  }
+  var result = [];
+  var idx = 0;
+  while (idx < list.length) {
+    result.push(slice(idx, idx += n, list));
+  }
+  return result;
+});
+export default splitEvery;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/splitWhen.js b/server/node_modules/ramda/es/splitWhen.js
new file mode 100644
index 0000000000000000000000000000000000000000..e0f3da0ec485dc9760b0c9b3a2c83c36696723bc
--- /dev/null
+++ b/server/node_modules/ramda/es/splitWhen.js
@@ -0,0 +1,34 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Takes a list and a predicate and returns a pair of lists with the following properties:
+ *
+ *  - the result of concatenating the two output lists is equivalent to the input list;
+ *  - none of the elements of the first output list satisfies the predicate; and
+ *  - if the second output list is non-empty, its first element satisfies the predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [[a], [a]]
+ * @param {Function} pred The predicate that determines where the array is split.
+ * @param {Array} list The array to be split.
+ * @return {Array}
+ * @example
+ *
+ *      R.splitWhen(R.equals(2), [1, 2, 3, 1, 2, 3]);   //=> [[1], [2, 3, 1, 2, 3]]
+ */
+var splitWhen = /*#__PURE__*/_curry2(function splitWhen(pred, list) {
+  var idx = 0;
+  var len = list.length;
+  var prefix = [];
+
+  while (idx < len && !pred(list[idx])) {
+    prefix.push(list[idx]);
+    idx += 1;
+  }
+
+  return [prefix, Array.prototype.slice.call(list, idx)];
+});
+export default splitWhen;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/startsWith.js b/server/node_modules/ramda/es/startsWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..884df1f7a6c30b92982687cdc215e9a986d910e8
--- /dev/null
+++ b/server/node_modules/ramda/es/startsWith.js
@@ -0,0 +1,30 @@
+import _curry2 from './internal/_curry2.js';
+import equals from './equals.js';
+import take from './take.js';
+
+/**
+ * Checks if a list starts with the provided sublist.
+ *
+ * Similarly, checks if a string starts with the provided substring.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category List
+ * @sig [a] -> [a] -> Boolean
+ * @sig String -> String -> Boolean
+ * @param {*} prefix
+ * @param {*} list
+ * @return {Boolean}
+ * @see R.endsWith
+ * @example
+ *
+ *      R.startsWith('a', 'abc')                //=> true
+ *      R.startsWith('b', 'abc')                //=> false
+ *      R.startsWith(['a'], ['a', 'b', 'c'])    //=> true
+ *      R.startsWith(['b'], ['a', 'b', 'c'])    //=> false
+ */
+var startsWith = /*#__PURE__*/_curry2(function (prefix, list) {
+  return equals(take(prefix.length, list), prefix);
+});
+export default startsWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/subtract.js b/server/node_modules/ramda/es/subtract.js
new file mode 100644
index 0000000000000000000000000000000000000000..20bc0c032bd0bf59aa58b2ee59c1a1427570656c
--- /dev/null
+++ b/server/node_modules/ramda/es/subtract.js
@@ -0,0 +1,29 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Subtracts its second argument from its first argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The first value.
+ * @param {Number} b The second value.
+ * @return {Number} The result of `a - b`.
+ * @see R.add
+ * @example
+ *
+ *      R.subtract(10, 8); //=> 2
+ *
+ *      const minus5 = R.subtract(R.__, 5);
+ *      minus5(17); //=> 12
+ *
+ *      const complementaryAngle = R.subtract(90);
+ *      complementaryAngle(30); //=> 60
+ *      complementaryAngle(72); //=> 18
+ */
+var subtract = /*#__PURE__*/_curry2(function subtract(a, b) {
+  return Number(a) - Number(b);
+});
+export default subtract;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/sum.js b/server/node_modules/ramda/es/sum.js
new file mode 100644
index 0000000000000000000000000000000000000000..c9ae5df286f53d120fd08a937fa3de430599e89c
--- /dev/null
+++ b/server/node_modules/ramda/es/sum.js
@@ -0,0 +1,20 @@
+import add from './add.js';
+import reduce from './reduce.js';
+
+/**
+ * Adds together all the elements of a list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list An array of numbers
+ * @return {Number} The sum of all the numbers in the list.
+ * @see R.reduce
+ * @example
+ *
+ *      R.sum([2,4,6,8,100,1]); //=> 121
+ */
+var sum = /*#__PURE__*/reduce(add, 0);
+export default sum;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/symmetricDifference.js b/server/node_modules/ramda/es/symmetricDifference.js
new file mode 100644
index 0000000000000000000000000000000000000000..c0858f779e607471b4128d7e250ee3e88ea49d0b
--- /dev/null
+++ b/server/node_modules/ramda/es/symmetricDifference.js
@@ -0,0 +1,26 @@
+import _curry2 from './internal/_curry2.js';
+import concat from './concat.js';
+import difference from './difference.js';
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements contained in the first or
+ * second list, but not both.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` or `list2`, but not both.
+ * @see R.symmetricDifferenceWith, R.difference, R.differenceWith
+ * @example
+ *
+ *      R.symmetricDifference([1,2,3,4], [7,6,5,4,3]); //=> [1,2,7,6,5]
+ *      R.symmetricDifference([7,6,5,4,3], [1,2,3,4]); //=> [7,6,5,1,2]
+ */
+var symmetricDifference = /*#__PURE__*/_curry2(function symmetricDifference(list1, list2) {
+  return concat(difference(list1, list2), difference(list2, list1));
+});
+export default symmetricDifference;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/symmetricDifferenceWith.js b/server/node_modules/ramda/es/symmetricDifferenceWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..4c77a15b109dc1fdc8bfdde99af360b7f01e94f2
--- /dev/null
+++ b/server/node_modules/ramda/es/symmetricDifferenceWith.js
@@ -0,0 +1,30 @@
+import _curry3 from './internal/_curry3.js';
+import concat from './concat.js';
+import differenceWith from './differenceWith.js';
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements contained in the first or
+ * second list, but not both. Duplication is determined according to the value
+ * returned by applying the supplied predicate to two list elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Relation
+ * @sig ((a, a) -> Boolean) -> [a] -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` or `list2`, but not both.
+ * @see R.symmetricDifference, R.difference, R.differenceWith
+ * @example
+ *
+ *      const eqA = R.eqBy(R.prop('a'));
+ *      const l1 = [{a: 1}, {a: 2}, {a: 3}, {a: 4}];
+ *      const l2 = [{a: 3}, {a: 4}, {a: 5}, {a: 6}];
+ *      R.symmetricDifferenceWith(eqA, l1, l2); //=> [{a: 1}, {a: 2}, {a: 5}, {a: 6}]
+ */
+var symmetricDifferenceWith = /*#__PURE__*/_curry3(function symmetricDifferenceWith(pred, list1, list2) {
+  return concat(differenceWith(pred, list1, list2), differenceWith(pred, list2, list1));
+});
+export default symmetricDifferenceWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/tail.js b/server/node_modules/ramda/es/tail.js
new file mode 100644
index 0000000000000000000000000000000000000000..4bdff08f60cc14aea2d93e0df0d24b6c6ebd732a
--- /dev/null
+++ b/server/node_modules/ramda/es/tail.js
@@ -0,0 +1,33 @@
+import _checkForMethod from './internal/_checkForMethod.js';
+import _curry1 from './internal/_curry1.js';
+import slice from './slice.js';
+
+/**
+ * Returns all but the first element of the given list or string (or object
+ * with a `tail` method).
+ *
+ * Dispatches to the `slice` method of the first argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a]
+ * @sig String -> String
+ * @param {*} list
+ * @return {*}
+ * @see R.head, R.init, R.last
+ * @example
+ *
+ *      R.tail([1, 2, 3]);  //=> [2, 3]
+ *      R.tail([1, 2]);     //=> [2]
+ *      R.tail([1]);        //=> []
+ *      R.tail([]);         //=> []
+ *
+ *      R.tail('abc');  //=> 'bc'
+ *      R.tail('ab');   //=> 'b'
+ *      R.tail('a');    //=> ''
+ *      R.tail('');     //=> ''
+ */
+var tail = /*#__PURE__*/_curry1( /*#__PURE__*/_checkForMethod('tail', /*#__PURE__*/slice(1, Infinity)));
+export default tail;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/take.js b/server/node_modules/ramda/es/take.js
new file mode 100644
index 0000000000000000000000000000000000000000..c65dbea25a69e3b4f18d0714db38e0c772be9606
--- /dev/null
+++ b/server/node_modules/ramda/es/take.js
@@ -0,0 +1,52 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xtake from './internal/_xtake.js';
+import slice from './slice.js';
+
+/**
+ * Returns the first `n` elements of the given list, string, or
+ * transducer/transformer (or object with a `take` method).
+ *
+ * Dispatches to the `take` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n
+ * @param {*} list
+ * @return {*}
+ * @see R.drop
+ * @example
+ *
+ *      R.take(1, ['foo', 'bar', 'baz']); //=> ['foo']
+ *      R.take(2, ['foo', 'bar', 'baz']); //=> ['foo', 'bar']
+ *      R.take(3, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.take(4, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.take(3, 'ramda');               //=> 'ram'
+ *
+ *      const personnel = [
+ *        'Dave Brubeck',
+ *        'Paul Desmond',
+ *        'Eugene Wright',
+ *        'Joe Morello',
+ *        'Gerry Mulligan',
+ *        'Bob Bates',
+ *        'Joe Dodge',
+ *        'Ron Crotty'
+ *      ];
+ *
+ *      const takeFive = R.take(5);
+ *      takeFive(personnel);
+ *      //=> ['Dave Brubeck', 'Paul Desmond', 'Eugene Wright', 'Joe Morello', 'Gerry Mulligan']
+ * @symb R.take(-1, [a, b]) = [a, b]
+ * @symb R.take(0, [a, b]) = []
+ * @symb R.take(1, [a, b]) = [a]
+ * @symb R.take(2, [a, b]) = [a, b]
+ */
+var take = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['take'], _xtake, function take(n, xs) {
+  return slice(0, n < 0 ? Infinity : n, xs);
+}));
+export default take;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/takeLast.js b/server/node_modules/ramda/es/takeLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..f614fa27aaa5dccd5d0e66f3cdde406731dde163
--- /dev/null
+++ b/server/node_modules/ramda/es/takeLast.js
@@ -0,0 +1,29 @@
+import _curry2 from './internal/_curry2.js';
+import drop from './drop.js';
+
+/**
+ * Returns a new list containing the last `n` elements of the given list.
+ * If `n > list.length`, returns a list of `list.length` elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n The number of elements to return.
+ * @param {Array} xs The collection to consider.
+ * @return {Array}
+ * @see R.dropLast
+ * @example
+ *
+ *      R.takeLast(1, ['foo', 'bar', 'baz']); //=> ['baz']
+ *      R.takeLast(2, ['foo', 'bar', 'baz']); //=> ['bar', 'baz']
+ *      R.takeLast(3, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.takeLast(4, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.takeLast(3, 'ramda');               //=> 'mda'
+ */
+var takeLast = /*#__PURE__*/_curry2(function takeLast(n, xs) {
+  return drop(n >= 0 ? xs.length - n : 0, xs);
+});
+export default takeLast;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/takeLastWhile.js b/server/node_modules/ramda/es/takeLastWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..07f2c89ee8c74ae044b8bee426a5d86c0f8b65f1
--- /dev/null
+++ b/server/node_modules/ramda/es/takeLastWhile.js
@@ -0,0 +1,36 @@
+import _curry2 from './internal/_curry2.js';
+import slice from './slice.js';
+
+/**
+ * Returns a new list containing the last `n` elements of a given list, passing
+ * each value to the supplied predicate function, and terminating when the
+ * predicate function returns `false`. Excludes the element that caused the
+ * predicate function to fail. The predicate function is passed one argument:
+ * *(value)*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} fn The function called per iteration.
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array.
+ * @see R.dropLastWhile, R.addIndex
+ * @example
+ *
+ *      const isNotOne = x => x !== 1;
+ *
+ *      R.takeLastWhile(isNotOne, [1, 2, 3, 4]); //=> [2, 3, 4]
+ *
+ *      R.takeLastWhile(x => x !== 'R' , 'Ramda'); //=> 'amda'
+ */
+var takeLastWhile = /*#__PURE__*/_curry2(function takeLastWhile(fn, xs) {
+  var idx = xs.length - 1;
+  while (idx >= 0 && fn(xs[idx])) {
+    idx -= 1;
+  }
+  return slice(idx + 1, Infinity, xs);
+});
+export default takeLastWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/takeWhile.js b/server/node_modules/ramda/es/takeWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..795c01c9052407baf8d9799b7a1629edc9a0e61e
--- /dev/null
+++ b/server/node_modules/ramda/es/takeWhile.js
@@ -0,0 +1,43 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xtakeWhile from './internal/_xtakeWhile.js';
+import slice from './slice.js';
+
+/**
+ * Returns a new list containing the first `n` elements of a given list,
+ * passing each value to the supplied predicate function, and terminating when
+ * the predicate function returns `false`. Excludes the element that caused the
+ * predicate function to fail. The predicate function is passed one argument:
+ * *(value)*.
+ *
+ * Dispatches to the `takeWhile` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} fn The function called per iteration.
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array.
+ * @see R.dropWhile, R.transduce, R.addIndex
+ * @example
+ *
+ *      const isNotFour = x => x !== 4;
+ *
+ *      R.takeWhile(isNotFour, [1, 2, 3, 4, 3, 2, 1]); //=> [1, 2, 3]
+ *
+ *      R.takeWhile(x => x !== 'd' , 'Ramda'); //=> 'Ram'
+ */
+var takeWhile = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['takeWhile'], _xtakeWhile, function takeWhile(fn, xs) {
+  var idx = 0;
+  var len = xs.length;
+  while (idx < len && fn(xs[idx])) {
+    idx += 1;
+  }
+  return slice(0, idx, xs);
+}));
+export default takeWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/tap.js b/server/node_modules/ramda/es/tap.js
new file mode 100644
index 0000000000000000000000000000000000000000..0c086a89b732f93f49136e20a3cef79fc5c6fdff
--- /dev/null
+++ b/server/node_modules/ramda/es/tap.js
@@ -0,0 +1,29 @@
+import _curry2 from './internal/_curry2.js';
+import _dispatchable from './internal/_dispatchable.js';
+import _xtap from './internal/_xtap.js';
+
+/**
+ * Runs the given function with the supplied object, then returns the object.
+ *
+ * Acts as a transducer if a transformer is given as second parameter.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (a -> *) -> a -> a
+ * @param {Function} fn The function to call with `x`. The return value of `fn` will be thrown away.
+ * @param {*} x
+ * @return {*} `x`.
+ * @example
+ *
+ *      const sayX = x => console.log('x is ' + x);
+ *      R.tap(sayX, 100); //=> 100
+ *      // logs 'x is 100'
+ * @symb R.tap(f, a) = a
+ */
+var tap = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xtap, function tap(fn, x) {
+  fn(x);
+  return x;
+}));
+export default tap;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/test.js b/server/node_modules/ramda/es/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..7cef253e2ab5c11a74eda185e581a62801652c80
--- /dev/null
+++ b/server/node_modules/ramda/es/test.js
@@ -0,0 +1,29 @@
+import _cloneRegExp from './internal/_cloneRegExp.js';
+import _curry2 from './internal/_curry2.js';
+import _isRegExp from './internal/_isRegExp.js';
+import toString from './toString.js';
+
+/**
+ * Determines whether a given string matches a given regular expression.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category String
+ * @sig RegExp -> String -> Boolean
+ * @param {RegExp} pattern
+ * @param {String} str
+ * @return {Boolean}
+ * @see R.match
+ * @example
+ *
+ *      R.test(/^x/, 'xyz'); //=> true
+ *      R.test(/^y/, 'xyz'); //=> false
+ */
+var test = /*#__PURE__*/_curry2(function test(pattern, str) {
+  if (!_isRegExp(pattern)) {
+    throw new TypeError('‘test’ requires a value of type RegExp as its first argument; received ' + toString(pattern));
+  }
+  return _cloneRegExp(pattern).test(str);
+});
+export default test;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/then.js b/server/node_modules/ramda/es/then.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb410ba3f9f45dad7386b0fb340711e6e135935c
--- /dev/null
+++ b/server/node_modules/ramda/es/then.js
@@ -0,0 +1,34 @@
+import _curry2 from './internal/_curry2.js';
+import _assertPromise from './internal/_assertPromise.js';
+
+/**
+ * Returns the result of applying the onSuccess function to the value inside
+ * a successfully resolved promise. This is useful for working with promises
+ * inside function compositions.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig (a -> b) -> (Promise e a) -> (Promise e b)
+ * @sig (a -> (Promise e b)) -> (Promise e a) -> (Promise e b)
+ * @param {Function} onSuccess The function to apply. Can return a value or a promise of a value.
+ * @param {Promise} p
+ * @return {Promise} The result of calling `p.then(onSuccess)`
+ * @see R.otherwise
+ * @example
+ *
+ *      var makeQuery = (email) => ({ query: { email }});
+ *
+ *      //getMemberName :: String -> Promise ({firstName, lastName})
+ *      var getMemberName = R.pipe(
+ *        makeQuery,
+ *        fetchMember,
+ *        R.then(R.pick(['firstName', 'lastName']))
+ *      );
+ */
+var then = /*#__PURE__*/_curry2(function then(f, p) {
+  _assertPromise('then', p);
+
+  return p.then(f);
+});
+export default then;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/thunkify.js b/server/node_modules/ramda/es/thunkify.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d00e70f9c689b22bd059d8845260f519bb2b1b0
--- /dev/null
+++ b/server/node_modules/ramda/es/thunkify.js
@@ -0,0 +1,30 @@
+import curryN from './curryN.js';
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Creates a thunk out of a function. A thunk delays a calculation until
+ * its result is needed, providing lazy evaluation of arguments.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig ((a, b, ..., j) -> k) -> (a, b, ..., j) -> (() -> k)
+ * @param {Function} fn A function to wrap in a thunk
+ * @return {Function} Expects arguments for `fn` and returns a new function
+ *  that, when called, applies those arguments to `fn`.
+ * @see R.partial, R.partialRight
+ * @example
+ *
+ *      R.thunkify(R.identity)(42)(); //=> 42
+ *      R.thunkify((a, b) => a + b)(25, 17)(); //=> 42
+ */
+var thunkify = /*#__PURE__*/_curry1(function thunkify(fn) {
+  return curryN(fn.length, function createThunk() {
+    var fnArgs = arguments;
+    return function invokeThunk() {
+      return fn.apply(this, fnArgs);
+    };
+  });
+});
+
+export default thunkify;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/times.js b/server/node_modules/ramda/es/times.js
new file mode 100644
index 0000000000000000000000000000000000000000..c7657d6ba103e8f19c020c2eb5fe3942ca2f4c1e
--- /dev/null
+++ b/server/node_modules/ramda/es/times.js
@@ -0,0 +1,41 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Calls an input function `n` times, returning an array containing the results
+ * of those function calls.
+ *
+ * `fn` is passed one argument: The current value of `n`, which begins at `0`
+ * and is gradually incremented to `n - 1`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.3
+ * @category List
+ * @sig (Number -> a) -> Number -> [a]
+ * @param {Function} fn The function to invoke. Passed one argument, the current value of `n`.
+ * @param {Number} n A value between `0` and `n - 1`. Increments after each function call.
+ * @return {Array} An array containing the return values of all calls to `fn`.
+ * @see R.repeat
+ * @example
+ *
+ *      R.times(R.identity, 5); //=> [0, 1, 2, 3, 4]
+ * @symb R.times(f, 0) = []
+ * @symb R.times(f, 1) = [f(0)]
+ * @symb R.times(f, 2) = [f(0), f(1)]
+ */
+var times = /*#__PURE__*/_curry2(function times(fn, n) {
+  var len = Number(n);
+  var idx = 0;
+  var list;
+
+  if (len < 0 || isNaN(len)) {
+    throw new RangeError('n must be a non-negative number');
+  }
+  list = new Array(len);
+  while (idx < len) {
+    list[idx] = fn(idx);
+    idx += 1;
+  }
+  return list;
+});
+export default times;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/toLower.js b/server/node_modules/ramda/es/toLower.js
new file mode 100644
index 0000000000000000000000000000000000000000..1b787bf5538ed45302bd80e32024a95b4c65601a
--- /dev/null
+++ b/server/node_modules/ramda/es/toLower.js
@@ -0,0 +1,19 @@
+import invoker from './invoker.js';
+
+/**
+ * The lower case version of a string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category String
+ * @sig String -> String
+ * @param {String} str The string to lower case.
+ * @return {String} The lower case version of `str`.
+ * @see R.toUpper
+ * @example
+ *
+ *      R.toLower('XYZ'); //=> 'xyz'
+ */
+var toLower = /*#__PURE__*/invoker(0, 'toLowerCase');
+export default toLower;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/toPairs.js b/server/node_modules/ramda/es/toPairs.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac1e8ac654f0a0f8ec6415367a42389225182fff
--- /dev/null
+++ b/server/node_modules/ramda/es/toPairs.js
@@ -0,0 +1,31 @@
+import _curry1 from './internal/_curry1.js';
+import _has from './internal/_has.js';
+
+/**
+ * Converts an object into an array of key, value arrays. Only the object's
+ * own properties are used.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.0
+ * @category Object
+ * @sig {String: *} -> [[String,*]]
+ * @param {Object} obj The object to extract from
+ * @return {Array} An array of key, value arrays from the object's own properties.
+ * @see R.fromPairs
+ * @example
+ *
+ *      R.toPairs({a: 1, b: 2, c: 3}); //=> [['a', 1], ['b', 2], ['c', 3]]
+ */
+var toPairs = /*#__PURE__*/_curry1(function toPairs(obj) {
+  var pairs = [];
+  for (var prop in obj) {
+    if (_has(prop, obj)) {
+      pairs[pairs.length] = [prop, obj[prop]];
+    }
+  }
+  return pairs;
+});
+export default toPairs;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/toPairsIn.js b/server/node_modules/ramda/es/toPairsIn.js
new file mode 100644
index 0000000000000000000000000000000000000000..78b6a1f938220ba6f6ab16827de56dd8d5c48a53
--- /dev/null
+++ b/server/node_modules/ramda/es/toPairsIn.js
@@ -0,0 +1,31 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Converts an object into an array of key, value arrays. The object's own
+ * properties and prototype properties are used. Note that the order of the
+ * output array is not guaranteed to be consistent across different JS
+ * platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.0
+ * @category Object
+ * @sig {String: *} -> [[String,*]]
+ * @param {Object} obj The object to extract from
+ * @return {Array} An array of key, value arrays from the object's own
+ *         and prototype properties.
+ * @example
+ *
+ *      const F = function() { this.x = 'X'; };
+ *      F.prototype.y = 'Y';
+ *      const f = new F();
+ *      R.toPairsIn(f); //=> [['x','X'], ['y','Y']]
+ */
+var toPairsIn = /*#__PURE__*/_curry1(function toPairsIn(obj) {
+  var pairs = [];
+  for (var prop in obj) {
+    pairs[pairs.length] = [prop, obj[prop]];
+  }
+  return pairs;
+});
+export default toPairsIn;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/toString.js b/server/node_modules/ramda/es/toString.js
new file mode 100644
index 0000000000000000000000000000000000000000..80cadcec1bff91ab9c57edebe8b442831f58fed3
--- /dev/null
+++ b/server/node_modules/ramda/es/toString.js
@@ -0,0 +1,43 @@
+import _curry1 from './internal/_curry1.js';
+import _toString from './internal/_toString.js';
+
+/**
+ * Returns the string representation of the given value. `eval`'ing the output
+ * should result in a value equivalent to the input value. Many of the built-in
+ * `toString` methods do not satisfy this requirement.
+ *
+ * If the given value is an `[object Object]` with a `toString` method other
+ * than `Object.prototype.toString`, this method is invoked with no arguments
+ * to produce the return value. This means user-defined constructor functions
+ * can provide a suitable `toString` method. For example:
+ *
+ *     function Point(x, y) {
+ *       this.x = x;
+ *       this.y = y;
+ *     }
+ *
+ *     Point.prototype.toString = function() {
+ *       return 'new Point(' + this.x + ', ' + this.y + ')';
+ *     };
+ *
+ *     R.toString(new Point(1, 2)); //=> 'new Point(1, 2)'
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category String
+ * @sig * -> String
+ * @param {*} val
+ * @return {String}
+ * @example
+ *
+ *      R.toString(42); //=> '42'
+ *      R.toString('abc'); //=> '"abc"'
+ *      R.toString([1, 2, 3]); //=> '[1, 2, 3]'
+ *      R.toString({foo: 1, bar: 2, baz: 3}); //=> '{"bar": 2, "baz": 3, "foo": 1}'
+ *      R.toString(new Date('2001-02-03T04:05:06Z')); //=> 'new Date("2001-02-03T04:05:06.000Z")'
+ */
+var toString = /*#__PURE__*/_curry1(function toString(val) {
+  return _toString(val, []);
+});
+export default toString;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/toUpper.js b/server/node_modules/ramda/es/toUpper.js
new file mode 100644
index 0000000000000000000000000000000000000000..e9340a37b22348e2dda54f3bdc509a5886d2c17d
--- /dev/null
+++ b/server/node_modules/ramda/es/toUpper.js
@@ -0,0 +1,19 @@
+import invoker from './invoker.js';
+
+/**
+ * The upper case version of a string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category String
+ * @sig String -> String
+ * @param {String} str The string to upper case.
+ * @return {String} The upper case version of `str`.
+ * @see R.toLower
+ * @example
+ *
+ *      R.toUpper('abc'); //=> 'ABC'
+ */
+var toUpper = /*#__PURE__*/invoker(0, 'toUpperCase');
+export default toUpper;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/transduce.js b/server/node_modules/ramda/es/transduce.js
new file mode 100644
index 0000000000000000000000000000000000000000..c794aad51f242bc1022ff24023ef3b6650e8230c
--- /dev/null
+++ b/server/node_modules/ramda/es/transduce.js
@@ -0,0 +1,55 @@
+import _reduce from './internal/_reduce.js';
+import _xwrap from './internal/_xwrap.js';
+import curryN from './curryN.js';
+
+/**
+ * Initializes a transducer using supplied iterator function. Returns a single
+ * item by iterating through the list, successively calling the transformed
+ * iterator function and passing it an accumulator value and the current value
+ * from the array, and then passing the result to the next call.
+ *
+ * The iterator function receives two values: *(acc, value)*. It will be
+ * wrapped as a transformer to initialize the transducer. A transformer can be
+ * passed directly in place of an iterator function. In both cases, iteration
+ * may be stopped early with the [`R.reduced`](#reduced) function.
+ *
+ * A transducer is a function that accepts a transformer and returns a
+ * transformer and can be composed directly.
+ *
+ * A transformer is an an object that provides a 2-arity reducing iterator
+ * function, step, 0-arity initial value function, init, and 1-arity result
+ * extraction function, result. The step function is used as the iterator
+ * function in reduce. The result function is used to convert the final
+ * accumulator into the return type and in most cases is
+ * [`R.identity`](#identity). The init function can be used to provide an
+ * initial accumulator, but is ignored by transduce.
+ *
+ * The iteration is performed with [`R.reduce`](#reduce) after initializing the transducer.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig (c -> c) -> ((a, b) -> a) -> a -> [b] -> a
+ * @param {Function} xf The transducer function. Receives a transformer and returns a transformer.
+ * @param {Function} fn The iterator function. Receives two values, the accumulator and the
+ *        current element from the array. Wrapped as transformer, if necessary, and used to
+ *        initialize the transducer
+ * @param {*} acc The initial accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduce, R.reduced, R.into
+ * @example
+ *
+ *      const numbers = [1, 2, 3, 4];
+ *      const transducer = R.compose(R.map(R.add(1)), R.take(2));
+ *      R.transduce(transducer, R.flip(R.append), [], numbers); //=> [2, 3]
+ *
+ *      const isOdd = (x) => x % 2 === 1;
+ *      const firstOddTransducer = R.compose(R.filter(isOdd), R.take(1));
+ *      R.transduce(firstOddTransducer, R.flip(R.append), [], R.range(0, 100)); //=> [1]
+ */
+var transduce = /*#__PURE__*/curryN(4, function transduce(xf, fn, acc, list) {
+  return _reduce(xf(typeof fn === 'function' ? _xwrap(fn) : fn), acc, list);
+});
+export default transduce;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/transpose.js b/server/node_modules/ramda/es/transpose.js
new file mode 100644
index 0000000000000000000000000000000000000000..9d80daa6fa850657ed063741e48c1b57f1988be1
--- /dev/null
+++ b/server/node_modules/ramda/es/transpose.js
@@ -0,0 +1,44 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Transposes the rows and columns of a 2D list.
+ * When passed a list of `n` lists of length `x`,
+ * returns a list of `x` lists of length `n`.
+ *
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig [[a]] -> [[a]]
+ * @param {Array} list A 2D list
+ * @return {Array} A 2D list
+ * @example
+ *
+ *      R.transpose([[1, 'a'], [2, 'b'], [3, 'c']]) //=> [[1, 2, 3], ['a', 'b', 'c']]
+ *      R.transpose([[1, 2, 3], ['a', 'b', 'c']]) //=> [[1, 'a'], [2, 'b'], [3, 'c']]
+ *
+ *      // If some of the rows are shorter than the following rows, their elements are skipped:
+ *      R.transpose([[10, 11], [20], [], [30, 31, 32]]) //=> [[10, 20, 30], [11, 31], [32]]
+ * @symb R.transpose([[a], [b], [c]]) = [a, b, c]
+ * @symb R.transpose([[a, b], [c, d]]) = [[a, c], [b, d]]
+ * @symb R.transpose([[a, b], [c]]) = [[a, c], [b]]
+ */
+var transpose = /*#__PURE__*/_curry1(function transpose(outerlist) {
+  var i = 0;
+  var result = [];
+  while (i < outerlist.length) {
+    var innerlist = outerlist[i];
+    var j = 0;
+    while (j < innerlist.length) {
+      if (typeof result[j] === 'undefined') {
+        result[j] = [];
+      }
+      result[j].push(innerlist[j]);
+      j += 1;
+    }
+    i += 1;
+  }
+  return result;
+});
+export default transpose;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/traverse.js b/server/node_modules/ramda/es/traverse.js
new file mode 100644
index 0000000000000000000000000000000000000000..4527f10ca3d6df57008c23adbee8ac26d3283d62
--- /dev/null
+++ b/server/node_modules/ramda/es/traverse.js
@@ -0,0 +1,34 @@
+import _curry3 from './internal/_curry3.js';
+import map from './map.js';
+import sequence from './sequence.js';
+
+/**
+ * Maps an [Applicative](https://github.com/fantasyland/fantasy-land#applicative)-returning
+ * function over a [Traversable](https://github.com/fantasyland/fantasy-land#traversable),
+ * then uses [`sequence`](#sequence) to transform the resulting Traversable of Applicative
+ * into an Applicative of Traversable.
+ *
+ * Dispatches to the `traverse` method of the third argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (Applicative f, Traversable t) => (a -> f a) -> (a -> f b) -> t a -> f (t b)
+ * @param {Function} of
+ * @param {Function} f
+ * @param {*} traversable
+ * @return {*}
+ * @see R.sequence
+ * @example
+ *
+ *      // Returns `Maybe.Nothing` if the given divisor is `0`
+ *      const safeDiv = n => d => d === 0 ? Maybe.Nothing() : Maybe.Just(n / d)
+ *
+ *      R.traverse(Maybe.of, safeDiv(10), [2, 4, 5]); //=> Maybe.Just([5, 2.5, 2])
+ *      R.traverse(Maybe.of, safeDiv(10), [2, 0, 5]); //=> Maybe.Nothing
+ */
+var traverse = /*#__PURE__*/_curry3(function traverse(of, f, traversable) {
+  return typeof traversable['fantasy-land/traverse'] === 'function' ? traversable['fantasy-land/traverse'](f, of) : sequence(of, map(f, traversable));
+});
+export default traverse;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/trim.js b/server/node_modules/ramda/es/trim.js
new file mode 100644
index 0000000000000000000000000000000000000000..1a84e88d97c22030976c127b6094679d3693f37f
--- /dev/null
+++ b/server/node_modules/ramda/es/trim.js
@@ -0,0 +1,28 @@
+import _curry1 from './internal/_curry1.js';
+
+var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' + '\u2029\uFEFF';
+var zeroWidth = '\u200b';
+var hasProtoTrim = typeof String.prototype.trim === 'function';
+/**
+ * Removes (strips) whitespace from both ends of the string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category String
+ * @sig String -> String
+ * @param {String} str The string to trim.
+ * @return {String} Trimmed version of `str`.
+ * @example
+ *
+ *      R.trim('   xyz  '); //=> 'xyz'
+ *      R.map(R.trim, R.split(',', 'x, y, z')); //=> ['x', 'y', 'z']
+ */
+var trim = !hasProtoTrim || /*#__PURE__*/ws.trim() || ! /*#__PURE__*/zeroWidth.trim() ? /*#__PURE__*/_curry1(function trim(str) {
+  var beginRx = new RegExp('^[' + ws + '][' + ws + ']*');
+  var endRx = new RegExp('[' + ws + '][' + ws + ']*$');
+  return str.replace(beginRx, '').replace(endRx, '');
+}) : /*#__PURE__*/_curry1(function trim(str) {
+  return str.trim();
+});
+export default trim;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/tryCatch.js b/server/node_modules/ramda/es/tryCatch.js
new file mode 100644
index 0000000000000000000000000000000000000000..da08c39481e77909d0202491845133b1c0c91ff1
--- /dev/null
+++ b/server/node_modules/ramda/es/tryCatch.js
@@ -0,0 +1,36 @@
+import _arity from './internal/_arity.js';
+import _concat from './internal/_concat.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * `tryCatch` takes two functions, a `tryer` and a `catcher`. The returned
+ * function evaluates the `tryer`; if it does not throw, it simply returns the
+ * result. If the `tryer` *does* throw, the returned function evaluates the
+ * `catcher` function and returns its result. Note that for effective
+ * composition with this function, both the `tryer` and `catcher` functions
+ * must return the same type of results.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Function
+ * @sig (...x -> a) -> ((e, ...x) -> a) -> (...x -> a)
+ * @param {Function} tryer The function that may throw.
+ * @param {Function} catcher The function that will be evaluated if `tryer` throws.
+ * @return {Function} A new function that will catch exceptions and send then to the catcher.
+ * @example
+ *
+ *      R.tryCatch(R.prop('x'), R.F)({x: true}); //=> true
+ *      R.tryCatch(() => { throw 'foo'}, R.always('catched'))('bar') // => 'catched'
+ *      R.tryCatch(R.times(R.identity), R.always([]))('s') // => []
+ `` */
+var tryCatch = /*#__PURE__*/_curry2(function _tryCatch(tryer, catcher) {
+  return _arity(tryer.length, function () {
+    try {
+      return tryer.apply(this, arguments);
+    } catch (e) {
+      return catcher.apply(this, _concat([e], arguments));
+    }
+  });
+});
+export default tryCatch;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/type.js b/server/node_modules/ramda/es/type.js
new file mode 100644
index 0000000000000000000000000000000000000000..7bb58bebe7c71713009eedf552f0dae43df68d0e
--- /dev/null
+++ b/server/node_modules/ramda/es/type.js
@@ -0,0 +1,31 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Gives a single-word string description of the (native) type of a value,
+ * returning such answers as 'Object', 'Number', 'Array', or 'Null'. Does not
+ * attempt to distinguish user Object types any further, reporting them all as
+ * 'Object'.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Type
+ * @sig (* -> {*}) -> String
+ * @param {*} val The value to test
+ * @return {String}
+ * @example
+ *
+ *      R.type({}); //=> "Object"
+ *      R.type(1); //=> "Number"
+ *      R.type(false); //=> "Boolean"
+ *      R.type('s'); //=> "String"
+ *      R.type(null); //=> "Null"
+ *      R.type([]); //=> "Array"
+ *      R.type(/[A-z]/); //=> "RegExp"
+ *      R.type(() => {}); //=> "Function"
+ *      R.type(undefined); //=> "Undefined"
+ */
+var type = /*#__PURE__*/_curry1(function type(val) {
+  return val === null ? 'Null' : val === undefined ? 'Undefined' : Object.prototype.toString.call(val).slice(8, -1);
+});
+export default type;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/unapply.js b/server/node_modules/ramda/es/unapply.js
new file mode 100644
index 0000000000000000000000000000000000000000..d2e79cab74d3115f2f1e8216e5021bf3e15bada1
--- /dev/null
+++ b/server/node_modules/ramda/es/unapply.js
@@ -0,0 +1,32 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Takes a function `fn`, which takes a single array argument, and returns a
+ * function which:
+ *
+ *   - takes any number of positional arguments;
+ *   - passes these arguments to `fn` as an array; and
+ *   - returns the result.
+ *
+ * In other words, `R.unapply` derives a variadic function from a function which
+ * takes an array. `R.unapply` is the inverse of [`R.apply`](#apply).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Function
+ * @sig ([*...] -> a) -> (*... -> a)
+ * @param {Function} fn
+ * @return {Function}
+ * @see R.apply
+ * @example
+ *
+ *      R.unapply(JSON.stringify)(1, 2, 3); //=> '[1,2,3]'
+ * @symb R.unapply(f)(a, b) = f([a, b])
+ */
+var unapply = /*#__PURE__*/_curry1(function unapply(fn) {
+  return function () {
+    return fn(Array.prototype.slice.call(arguments, 0));
+  };
+});
+export default unapply;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/unary.js b/server/node_modules/ramda/es/unary.js
new file mode 100644
index 0000000000000000000000000000000000000000..e9946f351469255a035d3a53a220a1a932a9e209
--- /dev/null
+++ b/server/node_modules/ramda/es/unary.js
@@ -0,0 +1,35 @@
+import _curry1 from './internal/_curry1.js';
+import nAry from './nAry.js';
+
+/**
+ * Wraps a function of any arity (including nullary) in a function that accepts
+ * exactly 1 parameter. Any extraneous parameters will not be passed to the
+ * supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Function
+ * @sig (* -> b) -> (a -> b)
+ * @param {Function} fn The function to wrap.
+ * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
+ *         arity 1.
+ * @see R.binary, R.nAry
+ * @example
+ *
+ *      const takesTwoArgs = function(a, b) {
+ *        return [a, b];
+ *      };
+ *      takesTwoArgs.length; //=> 2
+ *      takesTwoArgs(1, 2); //=> [1, 2]
+ *
+ *      const takesOneArg = R.unary(takesTwoArgs);
+ *      takesOneArg.length; //=> 1
+ *      // Only 1 argument is passed to the wrapped function
+ *      takesOneArg(1, 2); //=> [1, undefined]
+ * @symb R.unary(f)(a, b, c) = f(a)
+ */
+var unary = /*#__PURE__*/_curry1(function unary(fn) {
+  return nAry(1, fn);
+});
+export default unary;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/uncurryN.js b/server/node_modules/ramda/es/uncurryN.js
new file mode 100644
index 0000000000000000000000000000000000000000..7fb01a7b555d08ce32e60e08998c00ad8821bbd3
--- /dev/null
+++ b/server/node_modules/ramda/es/uncurryN.js
@@ -0,0 +1,38 @@
+import _curry2 from './internal/_curry2.js';
+import curryN from './curryN.js';
+
+/**
+ * Returns a function of arity `n` from a (manually) curried function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Function
+ * @sig Number -> (a -> b) -> (a -> c)
+ * @param {Number} length The arity for the returned function.
+ * @param {Function} fn The function to uncurry.
+ * @return {Function} A new function.
+ * @see R.curry
+ * @example
+ *
+ *      const addFour = a => b => c => d => a + b + c + d;
+ *
+ *      const uncurriedAddFour = R.uncurryN(4, addFour);
+ *      uncurriedAddFour(1, 2, 3, 4); //=> 10
+ */
+var uncurryN = /*#__PURE__*/_curry2(function uncurryN(depth, fn) {
+  return curryN(depth, function () {
+    var currentDepth = 1;
+    var value = fn;
+    var idx = 0;
+    var endIdx;
+    while (currentDepth <= depth && typeof value === 'function') {
+      endIdx = currentDepth === depth ? arguments.length : idx + value.length;
+      value = value.apply(this, Array.prototype.slice.call(arguments, idx, endIdx));
+      currentDepth += 1;
+      idx = endIdx;
+    }
+    return value;
+  });
+});
+export default uncurryN;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/unfold.js b/server/node_modules/ramda/es/unfold.js
new file mode 100644
index 0000000000000000000000000000000000000000..321886a5baafb3e129b1c87b024deaf3e4e0e881
--- /dev/null
+++ b/server/node_modules/ramda/es/unfold.js
@@ -0,0 +1,37 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Builds a list from a seed value. Accepts an iterator function, which returns
+ * either false to stop iteration or an array of length 2 containing the value
+ * to add to the resulting list and the seed to be used in the next call to the
+ * iterator function.
+ *
+ * The iterator function receives one argument: *(seed)*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig (a -> [b]) -> * -> [b]
+ * @param {Function} fn The iterator function. receives one argument, `seed`, and returns
+ *        either false to quit iteration or an array of length two to proceed. The element
+ *        at index 0 of this array will be added to the resulting array, and the element
+ *        at index 1 will be passed to the next call to `fn`.
+ * @param {*} seed The seed value.
+ * @return {Array} The final list.
+ * @example
+ *
+ *      const f = n => n > 50 ? false : [-n, n + 10];
+ *      R.unfold(f, 10); //=> [-10, -20, -30, -40, -50]
+ * @symb R.unfold(f, x) = [f(x)[0], f(f(x)[1])[0], f(f(f(x)[1])[1])[0], ...]
+ */
+var unfold = /*#__PURE__*/_curry2(function unfold(fn, seed) {
+  var pair = fn(seed);
+  var result = [];
+  while (pair && pair.length) {
+    result[result.length] = pair[0];
+    pair = fn(pair[1]);
+  }
+  return result;
+});
+export default unfold;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/union.js b/server/node_modules/ramda/es/union.js
new file mode 100644
index 0000000000000000000000000000000000000000..9ba110bc512faf6ab5d8f3bdc43990ede3554522
--- /dev/null
+++ b/server/node_modules/ramda/es/union.js
@@ -0,0 +1,24 @@
+import _concat from './internal/_concat.js';
+import _curry2 from './internal/_curry2.js';
+import compose from './compose.js';
+import uniq from './uniq.js';
+
+/**
+ * Combines two lists into a set (i.e. no duplicates) composed of the elements
+ * of each list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} as The first list.
+ * @param {Array} bs The second list.
+ * @return {Array} The first and second lists concatenated, with
+ *         duplicates removed.
+ * @example
+ *
+ *      R.union([1, 2, 3], [2, 3, 4]); //=> [1, 2, 3, 4]
+ */
+var union = /*#__PURE__*/_curry2( /*#__PURE__*/compose(uniq, _concat));
+export default union;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/unionWith.js b/server/node_modules/ramda/es/unionWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..7d6d4096cd9907a5b2f686ba3d329143563e1aef
--- /dev/null
+++ b/server/node_modules/ramda/es/unionWith.js
@@ -0,0 +1,30 @@
+import _concat from './internal/_concat.js';
+import _curry3 from './internal/_curry3.js';
+import uniqWith from './uniqWith.js';
+
+/**
+ * Combines two lists into a set (i.e. no duplicates) composed of the elements
+ * of each list. Duplication is determined according to the value returned by
+ * applying the supplied predicate to two list elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig ((a, a) -> Boolean) -> [*] -> [*] -> [*]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The first and second lists concatenated, with
+ *         duplicates removed.
+ * @see R.union
+ * @example
+ *
+ *      const l1 = [{a: 1}, {a: 2}];
+ *      const l2 = [{a: 1}, {a: 4}];
+ *      R.unionWith(R.eqBy(R.prop('a')), l1, l2); //=> [{a: 1}, {a: 2}, {a: 4}]
+ */
+var unionWith = /*#__PURE__*/_curry3(function unionWith(pred, list1, list2) {
+  return uniqWith(pred, _concat(list1, list2));
+});
+export default unionWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/uniq.js b/server/node_modules/ramda/es/uniq.js
new file mode 100644
index 0000000000000000000000000000000000000000..1551e19277ecc60193bd77bfb0da76f61846d75e
--- /dev/null
+++ b/server/node_modules/ramda/es/uniq.js
@@ -0,0 +1,22 @@
+import identity from './identity.js';
+import uniqBy from './uniqBy.js';
+
+/**
+ * Returns a new list containing only one copy of each element in the original
+ * list. [`R.equals`](#equals) is used to determine equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a]
+ * @param {Array} list The array to consider.
+ * @return {Array} The list of unique items.
+ * @example
+ *
+ *      R.uniq([1, 1, 2, 1]); //=> [1, 2]
+ *      R.uniq([1, '1']);     //=> [1, '1']
+ *      R.uniq([[42], [42]]); //=> [[42]]
+ */
+var uniq = /*#__PURE__*/uniqBy(identity);
+export default uniq;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/uniqBy.js b/server/node_modules/ramda/es/uniqBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..b17f6a149c407e5615fc33928fc6d5b36695e74d
--- /dev/null
+++ b/server/node_modules/ramda/es/uniqBy.js
@@ -0,0 +1,38 @@
+import _Set from './internal/_Set.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns a new list containing only one copy of each element in the original
+ * list, based upon the value returned by applying the supplied function to
+ * each list element. Prefers the first item if the supplied function produces
+ * the same value on two items. [`R.equals`](#equals) is used for comparison.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig (a -> b) -> [a] -> [a]
+ * @param {Function} fn A function used to produce a value to use during comparisons.
+ * @param {Array} list The array to consider.
+ * @return {Array} The list of unique items.
+ * @example
+ *
+ *      R.uniqBy(Math.abs, [-1, -5, 2, 10, 1, 2]); //=> [-1, -5, 2, 10]
+ */
+var uniqBy = /*#__PURE__*/_curry2(function uniqBy(fn, list) {
+  var set = new _Set();
+  var result = [];
+  var idx = 0;
+  var appliedItem, item;
+
+  while (idx < list.length) {
+    item = list[idx];
+    appliedItem = fn(item);
+    if (set.add(appliedItem)) {
+      result.push(item);
+    }
+    idx += 1;
+  }
+  return result;
+});
+export default uniqBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/uniqWith.js b/server/node_modules/ramda/es/uniqWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..ad2fa4f713d67a2d9bec6405a84501098d8166f7
--- /dev/null
+++ b/server/node_modules/ramda/es/uniqWith.js
@@ -0,0 +1,40 @@
+import _includesWith from './internal/_includesWith.js';
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Returns a new list containing only one copy of each element in the original
+ * list, based upon the value returned by applying the supplied predicate to
+ * two list elements. Prefers the first item if two items compare equal based
+ * on the predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category List
+ * @sig ((a, a) -> Boolean) -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list The array to consider.
+ * @return {Array} The list of unique items.
+ * @example
+ *
+ *      const strEq = R.eqBy(String);
+ *      R.uniqWith(strEq)([1, '1', 2, 1]); //=> [1, 2]
+ *      R.uniqWith(strEq)([{}, {}]);       //=> [{}]
+ *      R.uniqWith(strEq)([1, '1', 1]);    //=> [1]
+ *      R.uniqWith(strEq)(['1', 1, 1]);    //=> ['1']
+ */
+var uniqWith = /*#__PURE__*/_curry2(function uniqWith(pred, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [];
+  var item;
+  while (idx < len) {
+    item = list[idx];
+    if (!_includesWith(pred, item, result)) {
+      result[result.length] = item;
+    }
+    idx += 1;
+  }
+  return result;
+});
+export default uniqWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/unless.js b/server/node_modules/ramda/es/unless.js
new file mode 100644
index 0000000000000000000000000000000000000000..ed772769913d5be5e86beb3e1a501c94a532b277
--- /dev/null
+++ b/server/node_modules/ramda/es/unless.js
@@ -0,0 +1,30 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Tests the final argument by passing it to the given predicate function. If
+ * the predicate is not satisfied, the function will return the result of
+ * calling the `whenFalseFn` function with the same argument. If the predicate
+ * is satisfied, the argument is returned as is.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Logic
+ * @sig (a -> Boolean) -> (a -> a) -> a -> a
+ * @param {Function} pred        A predicate function
+ * @param {Function} whenFalseFn A function to invoke when the `pred` evaluates
+ *                               to a falsy value.
+ * @param {*}        x           An object to test with the `pred` function and
+ *                               pass to `whenFalseFn` if necessary.
+ * @return {*} Either `x` or the result of applying `x` to `whenFalseFn`.
+ * @see R.ifElse, R.when, R.cond
+ * @example
+ *
+ *      let safeInc = R.unless(R.isNil, R.inc);
+ *      safeInc(null); //=> null
+ *      safeInc(1); //=> 2
+ */
+var unless = /*#__PURE__*/_curry3(function unless(pred, whenFalseFn, x) {
+  return pred(x) ? x : whenFalseFn(x);
+});
+export default unless;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/unnest.js b/server/node_modules/ramda/es/unnest.js
new file mode 100644
index 0000000000000000000000000000000000000000..94e79b4a55272b3f039f68f15bb7ab13d53786fa
--- /dev/null
+++ b/server/node_modules/ramda/es/unnest.js
@@ -0,0 +1,22 @@
+import _identity from './internal/_identity.js';
+import chain from './chain.js';
+
+/**
+ * Shorthand for `R.chain(R.identity)`, which removes one level of nesting from
+ * any [Chain](https://github.com/fantasyland/fantasy-land#chain).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig Chain c => c (c a) -> c a
+ * @param {*} list
+ * @return {*}
+ * @see R.flatten, R.chain
+ * @example
+ *
+ *      R.unnest([1, [2], [[3]]]); //=> [1, 2, [3]]
+ *      R.unnest([[1, 2], [3, 4], [5, 6]]); //=> [1, 2, 3, 4, 5, 6]
+ */
+var unnest = /*#__PURE__*/chain(_identity);
+export default unnest;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/until.js b/server/node_modules/ramda/es/until.js
new file mode 100644
index 0000000000000000000000000000000000000000..215b6f8a779d6c5307011f94e0e13e0dc25f40c5
--- /dev/null
+++ b/server/node_modules/ramda/es/until.js
@@ -0,0 +1,29 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Takes a predicate, a transformation function, and an initial value,
+ * and returns a value of the same type as the initial value.
+ * It does so by applying the transformation until the predicate is satisfied,
+ * at which point it returns the satisfactory value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Logic
+ * @sig (a -> Boolean) -> (a -> a) -> a -> a
+ * @param {Function} pred A predicate function
+ * @param {Function} fn The iterator function
+ * @param {*} init Initial value
+ * @return {*} Final value that satisfies predicate
+ * @example
+ *
+ *      R.until(R.gt(R.__, 100), R.multiply(2))(1) // => 128
+ */
+var until = /*#__PURE__*/_curry3(function until(pred, fn, init) {
+  var val = init;
+  while (!pred(val)) {
+    val = fn(val);
+  }
+  return val;
+});
+export default until;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/update.js b/server/node_modules/ramda/es/update.js
new file mode 100644
index 0000000000000000000000000000000000000000..cd1bbda9254f0e80b300662e3a630989af5e743f
--- /dev/null
+++ b/server/node_modules/ramda/es/update.js
@@ -0,0 +1,30 @@
+import _curry3 from './internal/_curry3.js';
+import adjust from './adjust.js';
+import always from './always.js';
+
+/**
+ * Returns a new copy of the array with the element at the provided index
+ * replaced with the given value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig Number -> a -> [a] -> [a]
+ * @param {Number} idx The index to update.
+ * @param {*} x The value to exist at the given index of the returned array.
+ * @param {Array|Arguments} list The source array-like object to be updated.
+ * @return {Array} A copy of `list` with the value at index `idx` replaced with `x`.
+ * @see R.adjust
+ * @example
+ *
+ *      R.update(1, '_', ['a', 'b', 'c']);      //=> ['a', '_', 'c']
+ *      R.update(-1, '_', ['a', 'b', 'c']);     //=> ['a', 'b', '_']
+ * @symb R.update(-1, a, [b, c]) = [b, a]
+ * @symb R.update(0, a, [b, c]) = [a, c]
+ * @symb R.update(1, a, [b, c]) = [b, a]
+ */
+var update = /*#__PURE__*/_curry3(function update(idx, x, list) {
+  return adjust(idx, always(x), list);
+});
+export default update;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/useWith.js b/server/node_modules/ramda/es/useWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..556a4d8f8045c32c6a938e0720eeb5b929d63ee6
--- /dev/null
+++ b/server/node_modules/ramda/es/useWith.js
@@ -0,0 +1,44 @@
+import _curry2 from './internal/_curry2.js';
+import curryN from './curryN.js';
+
+/**
+ * Accepts a function `fn` and a list of transformer functions and returns a
+ * new curried function. When the new function is invoked, it calls the
+ * function `fn` with parameters consisting of the result of calling each
+ * supplied handler on successive arguments to the new function.
+ *
+ * If more arguments are passed to the returned function than transformer
+ * functions, those arguments are passed directly to `fn` as additional
+ * parameters. If you expect additional arguments that don't need to be
+ * transformed, although you can ignore them, it's best to pass an identity
+ * function so that the new function reports the correct arity.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((x1, x2, ...) -> z) -> [(a -> x1), (b -> x2), ...] -> (a -> b -> ... -> z)
+ * @param {Function} fn The function to wrap.
+ * @param {Array} transformers A list of transformer functions
+ * @return {Function} The wrapped function.
+ * @see R.converge
+ * @example
+ *
+ *      R.useWith(Math.pow, [R.identity, R.identity])(3, 4); //=> 81
+ *      R.useWith(Math.pow, [R.identity, R.identity])(3)(4); //=> 81
+ *      R.useWith(Math.pow, [R.dec, R.inc])(3, 4); //=> 32
+ *      R.useWith(Math.pow, [R.dec, R.inc])(3)(4); //=> 32
+ * @symb R.useWith(f, [g, h])(a, b) = f(g(a), h(b))
+ */
+var useWith = /*#__PURE__*/_curry2(function useWith(fn, transformers) {
+  return curryN(transformers.length, function () {
+    var args = [];
+    var idx = 0;
+    while (idx < transformers.length) {
+      args.push(transformers[idx].call(this, arguments[idx]));
+      idx += 1;
+    }
+    return fn.apply(this, args.concat(Array.prototype.slice.call(arguments, transformers.length)));
+  });
+});
+export default useWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/values.js b/server/node_modules/ramda/es/values.js
new file mode 100644
index 0000000000000000000000000000000000000000..43534a07deeabe25c5329b13f2f755e148171d4c
--- /dev/null
+++ b/server/node_modules/ramda/es/values.js
@@ -0,0 +1,32 @@
+import _curry1 from './internal/_curry1.js';
+import keys from './keys.js';
+
+/**
+ * Returns a list of all the enumerable own properties of the supplied object.
+ * Note that the order of the output array is not guaranteed across different
+ * JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {k: v} -> [v]
+ * @param {Object} obj The object to extract values from
+ * @return {Array} An array of the values of the object's own properties.
+ * @see R.valuesIn, R.keys
+ * @example
+ *
+ *      R.values({a: 1, b: 2, c: 3}); //=> [1, 2, 3]
+ */
+var values = /*#__PURE__*/_curry1(function values(obj) {
+  var props = keys(obj);
+  var len = props.length;
+  var vals = [];
+  var idx = 0;
+  while (idx < len) {
+    vals[idx] = obj[props[idx]];
+    idx += 1;
+  }
+  return vals;
+});
+export default values;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/valuesIn.js b/server/node_modules/ramda/es/valuesIn.js
new file mode 100644
index 0000000000000000000000000000000000000000..5301a87aaa0119667c2e8be3b21a20e98a99bf90
--- /dev/null
+++ b/server/node_modules/ramda/es/valuesIn.js
@@ -0,0 +1,32 @@
+import _curry1 from './internal/_curry1.js';
+
+/**
+ * Returns a list of all the properties, including prototype properties, of the
+ * supplied object.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Object
+ * @sig {k: v} -> [v]
+ * @param {Object} obj The object to extract values from
+ * @return {Array} An array of the values of the object's own and prototype properties.
+ * @see R.values, R.keysIn
+ * @example
+ *
+ *      const F = function() { this.x = 'X'; };
+ *      F.prototype.y = 'Y';
+ *      const f = new F();
+ *      R.valuesIn(f); //=> ['X', 'Y']
+ */
+var valuesIn = /*#__PURE__*/_curry1(function valuesIn(obj) {
+  var prop;
+  var vs = [];
+  for (prop in obj) {
+    vs[vs.length] = obj[prop];
+  }
+  return vs;
+});
+export default valuesIn;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/view.js b/server/node_modules/ramda/es/view.js
new file mode 100644
index 0000000000000000000000000000000000000000..511ad3ed4a1180dd1e25bae633a88391239ee620
--- /dev/null
+++ b/server/node_modules/ramda/es/view.js
@@ -0,0 +1,36 @@
+import _curry2 from './internal/_curry2.js';
+
+// `Const` is a functor that effectively ignores the function given to `map`.
+var Const = function (x) {
+  return { value: x, 'fantasy-land/map': function () {
+      return this;
+    } };
+};
+
+/**
+ * Returns a "view" of the given data structure, determined by the given lens.
+ * The lens's focus determines which portion of the data structure is visible.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Lens s a -> s -> a
+ * @param {Lens} lens
+ * @param {*} x
+ * @return {*}
+ * @see R.prop, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const xLens = R.lensProp('x');
+ *
+ *      R.view(xLens, {x: 1, y: 2});  //=> 1
+ *      R.view(xLens, {x: 4, y: 2});  //=> 4
+ */
+var view = /*#__PURE__*/_curry2(function view(lens, x) {
+  // Using `Const` effectively ignores the setter function of the `lens`,
+  // leaving the value returned by the getter function unmodified.
+  return lens(Const)(x).value;
+});
+export default view;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/when.js b/server/node_modules/ramda/es/when.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac85301247b814b28fa47b2763a9c6c55dde62b2
--- /dev/null
+++ b/server/node_modules/ramda/es/when.js
@@ -0,0 +1,34 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Tests the final argument by passing it to the given predicate function. If
+ * the predicate is satisfied, the function will return the result of calling
+ * the `whenTrueFn` function with the same argument. If the predicate is not
+ * satisfied, the argument is returned as is.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Logic
+ * @sig (a -> Boolean) -> (a -> a) -> a -> a
+ * @param {Function} pred       A predicate function
+ * @param {Function} whenTrueFn A function to invoke when the `condition`
+ *                              evaluates to a truthy value.
+ * @param {*}        x          An object to test with the `pred` function and
+ *                              pass to `whenTrueFn` if necessary.
+ * @return {*} Either `x` or the result of applying `x` to `whenTrueFn`.
+ * @see R.ifElse, R.unless, R.cond
+ * @example
+ *
+ *      // truncate :: String -> String
+ *      const truncate = R.when(
+ *        R.propSatisfies(R.gt(R.__, 10), 'length'),
+ *        R.pipe(R.take(10), R.append('…'), R.join(''))
+ *      );
+ *      truncate('12345');         //=> '12345'
+ *      truncate('0123456789ABC'); //=> '0123456789…'
+ */
+var when = /*#__PURE__*/_curry3(function when(pred, whenTrueFn, x) {
+  return pred(x) ? whenTrueFn(x) : x;
+});
+export default when;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/where.js b/server/node_modules/ramda/es/where.js
new file mode 100644
index 0000000000000000000000000000000000000000..a2f140c52449c78a5bc65c1c6eaa3af0a81f2d0d
--- /dev/null
+++ b/server/node_modules/ramda/es/where.js
@@ -0,0 +1,47 @@
+import _curry2 from './internal/_curry2.js';
+import _has from './internal/_has.js';
+
+/**
+ * Takes a spec object and a test object; returns true if the test satisfies
+ * the spec. Each of the spec's own properties must be a predicate function.
+ * Each predicate is applied to the value of the corresponding property of the
+ * test object. `where` returns true if all the predicates return true, false
+ * otherwise.
+ *
+ * `where` is well suited to declaratively expressing constraints for other
+ * functions such as [`filter`](#filter) and [`find`](#find).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category Object
+ * @sig {String: (* -> Boolean)} -> {String: *} -> Boolean
+ * @param {Object} spec
+ * @param {Object} testObj
+ * @return {Boolean}
+ * @see R.propSatisfies, R.whereEq
+ * @example
+ *
+ *      // pred :: Object -> Boolean
+ *      const pred = R.where({
+ *        a: R.equals('foo'),
+ *        b: R.complement(R.equals('bar')),
+ *        x: R.gt(R.__, 10),
+ *        y: R.lt(R.__, 20)
+ *      });
+ *
+ *      pred({a: 'foo', b: 'xxx', x: 11, y: 19}); //=> true
+ *      pred({a: 'xxx', b: 'xxx', x: 11, y: 19}); //=> false
+ *      pred({a: 'foo', b: 'bar', x: 11, y: 19}); //=> false
+ *      pred({a: 'foo', b: 'xxx', x: 10, y: 19}); //=> false
+ *      pred({a: 'foo', b: 'xxx', x: 11, y: 20}); //=> false
+ */
+var where = /*#__PURE__*/_curry2(function where(spec, testObj) {
+  for (var prop in spec) {
+    if (_has(prop, spec) && !spec[prop](testObj[prop])) {
+      return false;
+    }
+  }
+  return true;
+});
+export default where;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/whereEq.js b/server/node_modules/ramda/es/whereEq.js
new file mode 100644
index 0000000000000000000000000000000000000000..cfbf73f3d330e33e1d56a98badbb3005e44a436a
--- /dev/null
+++ b/server/node_modules/ramda/es/whereEq.js
@@ -0,0 +1,37 @@
+import _curry2 from './internal/_curry2.js';
+import equals from './equals.js';
+import map from './map.js';
+import where from './where.js';
+
+/**
+ * Takes a spec object and a test object; returns true if the test satisfies
+ * the spec, false otherwise. An object satisfies the spec if, for each of the
+ * spec's own properties, accessing that property of the object gives the same
+ * value (in [`R.equals`](#equals) terms) as accessing that property of the
+ * spec.
+ *
+ * `whereEq` is a specialization of [`where`](#where).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Object
+ * @sig {String: *} -> {String: *} -> Boolean
+ * @param {Object} spec
+ * @param {Object} testObj
+ * @return {Boolean}
+ * @see R.propEq, R.where
+ * @example
+ *
+ *      // pred :: Object -> Boolean
+ *      const pred = R.whereEq({a: 1, b: 2});
+ *
+ *      pred({a: 1});              //=> false
+ *      pred({a: 1, b: 2});        //=> true
+ *      pred({a: 1, b: 2, c: 3});  //=> true
+ *      pred({a: 1, b: 1});        //=> false
+ */
+var whereEq = /*#__PURE__*/_curry2(function whereEq(spec, testObj) {
+  return where(map(equals, spec), testObj);
+});
+export default whereEq;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/without.js b/server/node_modules/ramda/es/without.js
new file mode 100644
index 0000000000000000000000000000000000000000..df0cf91415f7bb713645fb144bdb47ccd6bf53cd
--- /dev/null
+++ b/server/node_modules/ramda/es/without.js
@@ -0,0 +1,28 @@
+import _includes from './internal/_includes.js';
+import _curry2 from './internal/_curry2.js';
+import flip from './flip.js';
+import reject from './reject.js';
+
+/**
+ * Returns a new list without values in the first argument.
+ * [`R.equals`](#equals) is used to determine equality.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig [a] -> [a] -> [a]
+ * @param {Array} list1 The values to be removed from `list2`.
+ * @param {Array} list2 The array to remove values from.
+ * @return {Array} The new array without values in `list1`.
+ * @see R.transduce, R.difference, R.remove
+ * @example
+ *
+ *      R.without([1, 2], [1, 2, 1, 3, 4]); //=> [3, 4]
+ */
+var without = /*#__PURE__*/_curry2(function (xs, list) {
+  return reject(flip(_includes)(xs), list);
+});
+export default without;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/xprod.js b/server/node_modules/ramda/es/xprod.js
new file mode 100644
index 0000000000000000000000000000000000000000..548dc49c2bcde6f99aafacdb3e06e0eabc974e3d
--- /dev/null
+++ b/server/node_modules/ramda/es/xprod.js
@@ -0,0 +1,38 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Creates a new list out of the two supplied by creating each possible pair
+ * from the lists.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [b] -> [[a,b]]
+ * @param {Array} as The first list.
+ * @param {Array} bs The second list.
+ * @return {Array} The list made by combining each possible pair from
+ *         `as` and `bs` into pairs (`[a, b]`).
+ * @example
+ *
+ *      R.xprod([1, 2], ['a', 'b']); //=> [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
+ * @symb R.xprod([a, b], [c, d]) = [[a, c], [a, d], [b, c], [b, d]]
+ */
+var xprod = /*#__PURE__*/_curry2(function xprod(a, b) {
+  // = xprodWith(prepend); (takes about 3 times as long...)
+  var idx = 0;
+  var ilen = a.length;
+  var j;
+  var jlen = b.length;
+  var result = [];
+  while (idx < ilen) {
+    j = 0;
+    while (j < jlen) {
+      result[result.length] = [a[idx], b[j]];
+      j += 1;
+    }
+    idx += 1;
+  }
+  return result;
+});
+export default xprod;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/zip.js b/server/node_modules/ramda/es/zip.js
new file mode 100644
index 0000000000000000000000000000000000000000..ffd603d8606a795e369bfc310248d007db8addc0
--- /dev/null
+++ b/server/node_modules/ramda/es/zip.js
@@ -0,0 +1,32 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Creates a new list out of the two supplied by pairing up equally-positioned
+ * items from both lists. The returned list is truncated to the length of the
+ * shorter of the two input lists.
+ * Note: `zip` is equivalent to `zipWith(function(a, b) { return [a, b] })`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [b] -> [[a,b]]
+ * @param {Array} list1 The first array to consider.
+ * @param {Array} list2 The second array to consider.
+ * @return {Array} The list made by pairing up same-indexed elements of `list1` and `list2`.
+ * @example
+ *
+ *      R.zip([1, 2, 3], ['a', 'b', 'c']); //=> [[1, 'a'], [2, 'b'], [3, 'c']]
+ * @symb R.zip([a, b, c], [d, e, f]) = [[a, d], [b, e], [c, f]]
+ */
+var zip = /*#__PURE__*/_curry2(function zip(a, b) {
+  var rv = [];
+  var idx = 0;
+  var len = Math.min(a.length, b.length);
+  while (idx < len) {
+    rv[idx] = [a[idx], b[idx]];
+    idx += 1;
+  }
+  return rv;
+});
+export default zip;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/zipObj.js b/server/node_modules/ramda/es/zipObj.js
new file mode 100644
index 0000000000000000000000000000000000000000..3843e8682e754d4745e6a385974afa21359c117f
--- /dev/null
+++ b/server/node_modules/ramda/es/zipObj.js
@@ -0,0 +1,30 @@
+import _curry2 from './internal/_curry2.js';
+
+/**
+ * Creates a new object out of a list of keys and a list of values.
+ * Key/value pairing is truncated to the length of the shorter of the two lists.
+ * Note: `zipObj` is equivalent to `pipe(zip, fromPairs)`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig [String] -> [*] -> {String: *}
+ * @param {Array} keys The array that will be properties on the output object.
+ * @param {Array} values The list of values on the output object.
+ * @return {Object} The object made by pairing up same-indexed elements of `keys` and `values`.
+ * @example
+ *
+ *      R.zipObj(['a', 'b', 'c'], [1, 2, 3]); //=> {a: 1, b: 2, c: 3}
+ */
+var zipObj = /*#__PURE__*/_curry2(function zipObj(keys, values) {
+  var idx = 0;
+  var len = Math.min(keys.length, values.length);
+  var out = {};
+  while (idx < len) {
+    out[keys[idx]] = values[idx];
+    idx += 1;
+  }
+  return out;
+});
+export default zipObj;
\ No newline at end of file
diff --git a/server/node_modules/ramda/es/zipWith.js b/server/node_modules/ramda/es/zipWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb678650b20c182f19e29fe3a57dc67cabc20e1d
--- /dev/null
+++ b/server/node_modules/ramda/es/zipWith.js
@@ -0,0 +1,37 @@
+import _curry3 from './internal/_curry3.js';
+
+/**
+ * Creates a new list out of the two supplied by applying the function to each
+ * equally-positioned pair in the lists. The returned list is truncated to the
+ * length of the shorter of the two input lists.
+ *
+ * @function
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, b) -> c) -> [a] -> [b] -> [c]
+ * @param {Function} fn The function used to combine the two elements into one value.
+ * @param {Array} list1 The first array to consider.
+ * @param {Array} list2 The second array to consider.
+ * @return {Array} The list made by combining same-indexed elements of `list1` and `list2`
+ *         using `fn`.
+ * @example
+ *
+ *      const f = (x, y) => {
+ *        // ...
+ *      };
+ *      R.zipWith(f, [1, 2, 3], ['a', 'b', 'c']);
+ *      //=> [f(1, 'a'), f(2, 'b'), f(3, 'c')]
+ * @symb R.zipWith(fn, [a, b, c], [d, e, f]) = [fn(a, d), fn(b, e), fn(c, f)]
+ */
+var zipWith = /*#__PURE__*/_curry3(function zipWith(fn, a, b) {
+  var rv = [];
+  var idx = 0;
+  var len = Math.min(a.length, b.length);
+  while (idx < len) {
+    rv[idx] = fn(a[idx], b[idx]);
+    idx += 1;
+  }
+  return rv;
+});
+export default zipWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/package.json b/server/node_modules/ramda/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..5b7b143c49dbda08a293a2c195b9bcf7335f89c0
--- /dev/null
+++ b/server/node_modules/ramda/package.json
@@ -0,0 +1,136 @@
+{
+  "_from": "ramda",
+  "_id": "ramda@0.26.1",
+  "_inBundle": false,
+  "_integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==",
+  "_location": "/ramda",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "tag",
+    "registry": true,
+    "raw": "ramda",
+    "name": "ramda",
+    "escapedName": "ramda",
+    "rawSpec": "",
+    "saveSpec": null,
+    "fetchSpec": "latest"
+  },
+  "_requiredBy": [
+    "#USER",
+    "/"
+  ],
+  "_resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz",
+  "_shasum": "8d41351eb8111c55353617fc3bbffad8e4d35d06",
+  "_spec": "ramda",
+  "_where": "/home/dante/Documents/pinsis-portal/server",
+  "author": {
+    "name": "Scott Sauyet",
+    "email": "scott@sauyet.com",
+    "url": "scott.sauyet.com"
+  },
+  "bugs": {
+    "url": "https://github.com/ramda/ramda/issues"
+  },
+  "bundleDependencies": false,
+  "contributors": [
+    {
+      "name": "Michael Hurley",
+      "email": "mh@buzzdecafe.com",
+      "url": "http://buzzdecafe.com"
+    },
+    {
+      "name": "Scott Sauyet",
+      "email": "scott@sauyet.com",
+      "url": "http://fr.umio.us"
+    },
+    {
+      "name": "David Chambers",
+      "email": "dc@davidchambers.me",
+      "url": "http://davidchambers.me"
+    },
+    {
+      "name": "Graeme Yeates",
+      "email": "yeatesgraeme@gmail.com",
+      "url": "https://github.com/megawac"
+    }
+  ],
+  "dependencies": {},
+  "deprecated": false,
+  "description": "A practical functional library for JavaScript programmers.",
+  "devDependencies": {
+    "babel-cli": "^6.26.0",
+    "babel-plugin-annotate-pure-calls": "^0.2.2",
+    "babel-plugin-import-export-rename": "^1.0.1",
+    "babel-register": "^6.26.0",
+    "babel-types": "^6.26.0",
+    "babelify": "^8.0.0",
+    "benchmark": "~1.0.0",
+    "browserify": "https://api.github.com/repos/browserify/browserify/tarball/9ff7c55cc67a7ddbc64f8e7270bcd75fcc72ce2f",
+    "cli-table": "0.3.x",
+    "cross-env": "^2.0.1",
+    "dox": "latest",
+    "envvar": "1.x.x",
+    "eslint": "^5.9.0",
+    "handlebars": ">=4.0.0",
+    "istanbul": "^0.4.x",
+    "js-yaml": "^3.12.0",
+    "jsverify": "^0.7.3",
+    "mocha": "^5.2.0",
+    "ramda": "0.17.x",
+    "rimraf": "^2.6.2",
+    "rollup": "^0.50.0",
+    "rollup-plugin-terser": "^1.0.1",
+    "sanctuary": "0.7.x",
+    "sinon": "^1.17.4",
+    "testem": "^2.9.0",
+    "xyz": "^3.0.0"
+  },
+  "files": [
+    "es",
+    "src",
+    "dist"
+  ],
+  "homepage": "https://ramdajs.com/",
+  "jsdelivr": "dist/ramda.min.js",
+  "keywords": [
+    "ramda",
+    "functional",
+    "utils",
+    "utilities",
+    "toolkit",
+    "fp",
+    "tacit",
+    "point-free",
+    "curried",
+    "pure",
+    "fantasy-land"
+  ],
+  "license": "MIT",
+  "main": "src/index",
+  "module": "es/index.js",
+  "name": "ramda",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/ramda/ramda.git"
+  },
+  "scripts": {
+    "bench": "scripts/benchRunner",
+    "bookmarklet": "scripts/bookmarklet",
+    "browser_test": "testem ci",
+    "build": "npm run build:es && npm run build:cjs && npm run build:umd && npm run build:umd:min && npm run build:mjs",
+    "build:cjs": "cross-env BABEL_ENV=cjs babel source --out-dir src",
+    "build:es": "cross-env BABEL_ENV=es babel source --out-dir es",
+    "build:mjs": "cross-env BABEL_ENV=es babel source/index.js --out-file src/index.mjs",
+    "build:umd": "cross-env NODE_ENV=development rollup -c -o dist/ramda.js",
+    "build:umd:min": "cross-env NODE_ENV=production rollup -c -o dist/ramda.min.js",
+    "clean": "rimraf es/* src/* dist/* coverage/*",
+    "coverage": "istanbul cover node_modules/.bin/_mocha -- --reporter spec",
+    "lint": "eslint scripts/bookmarklet scripts/*.js source/*.js source/internal/*.js test/*.js test/**/*.js lib/sauce/*.js lib/bench/*.js",
+    "partial-build": "node ./scripts/partialBuild",
+    "prepare": "npm run clean && npm run build",
+    "test": "cross-env BABEL_ENV=cjs mocha --require babel-register --reporter spec"
+  },
+  "sideEffects": false,
+  "unpkg": "dist/ramda.min.js",
+  "version": "0.26.1"
+}
diff --git a/server/node_modules/ramda/src/F.js b/server/node_modules/ramda/src/F.js
new file mode 100644
index 0000000000000000000000000000000000000000..e89af4091a5627bf1d29b43b00c5ef210db227f9
--- /dev/null
+++ b/server/node_modules/ramda/src/F.js
@@ -0,0 +1,21 @@
+
+
+/**
+ * A function that always returns `false`. Any passed in parameters are ignored.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig * -> Boolean
+ * @param {*}
+ * @return {Boolean}
+ * @see R.T
+ * @example
+ *
+ *      R.F(); //=> false
+ */
+var F = function () {
+  return false;
+};
+module.exports = F;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/T.js b/server/node_modules/ramda/src/T.js
new file mode 100644
index 0000000000000000000000000000000000000000..2514b527b87b560f4cd0f334d2c5432ad89b55cf
--- /dev/null
+++ b/server/node_modules/ramda/src/T.js
@@ -0,0 +1,21 @@
+
+
+/**
+ * A function that always returns `true`. Any passed in parameters are ignored.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig * -> Boolean
+ * @param {*}
+ * @return {Boolean}
+ * @see R.F
+ * @example
+ *
+ *      R.T(); //=> true
+ */
+var T = function () {
+  return true;
+};
+module.exports = T;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/__.js b/server/node_modules/ramda/src/__.js
new file mode 100644
index 0000000000000000000000000000000000000000..84011159d53883db090c7a268b68c8e63cbb584a
--- /dev/null
+++ b/server/node_modules/ramda/src/__.js
@@ -0,0 +1,28 @@
+/**
+ * A special placeholder value used to specify "gaps" within curried functions,
+ * allowing partial application of any combination of arguments, regardless of
+ * their positions.
+ *
+ * If `g` is a curried ternary function and `_` is `R.__`, the following are
+ * equivalent:
+ *
+ *   - `g(1, 2, 3)`
+ *   - `g(_, 2, 3)(1)`
+ *   - `g(_, _, 3)(1)(2)`
+ *   - `g(_, _, 3)(1, 2)`
+ *   - `g(_, 2, _)(1, 3)`
+ *   - `g(_, 2)(1)(3)`
+ *   - `g(_, 2)(1, 3)`
+ *   - `g(_, 2)(_, 3)(1)`
+ *
+ * @name __
+ * @constant
+ * @memberOf R
+ * @since v0.6.0
+ * @category Function
+ * @example
+ *
+ *      const greet = R.replace('{name}', R.__, 'Hello, {name}!');
+ *      greet('Alice'); //=> 'Hello, Alice!'
+ */
+module.exports = { '@@functional/placeholder': true };
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/add.js b/server/node_modules/ramda/src/add.js
new file mode 100644
index 0000000000000000000000000000000000000000..eede2d225b7c5043cb9bd2132e83655825ab7ae3
--- /dev/null
+++ b/server/node_modules/ramda/src/add.js
@@ -0,0 +1,25 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Adds two values.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a
+ * @param {Number} b
+ * @return {Number}
+ * @see R.subtract
+ * @example
+ *
+ *      R.add(2, 3);       //=>  5
+ *      R.add(7)(10);      //=> 17
+ */
+
+
+var add = /*#__PURE__*/_curry2(function add(a, b) {
+  return Number(a) + Number(b);
+});
+module.exports = add;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/addIndex.js b/server/node_modules/ramda/src/addIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ce38fd50cbc8585006cb68e2e9a9177470daa72
--- /dev/null
+++ b/server/node_modules/ramda/src/addIndex.js
@@ -0,0 +1,47 @@
+var _concat = /*#__PURE__*/require('./internal/_concat');
+
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+/**
+ * Creates a new list iteration function from an existing one by adding two new
+ * parameters to its callback function: the current index, and the entire list.
+ *
+ * This would turn, for instance, [`R.map`](#map) function into one that
+ * more closely resembles `Array.prototype.map`. Note that this will only work
+ * for functions in which the iteration callback function is the first
+ * parameter, and where the list is the last parameter. (This latter might be
+ * unimportant if the list parameter is not used.)
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category Function
+ * @category List
+ * @sig ((a ... -> b) ... -> [a] -> *) -> ((a ..., Int, [a] -> b) ... -> [a] -> *)
+ * @param {Function} fn A list iteration function that does not pass index or list to its callback
+ * @return {Function} An altered list iteration function that passes (item, index, list) to its callback
+ * @example
+ *
+ *      const mapIndexed = R.addIndex(R.map);
+ *      mapIndexed((val, idx) => idx + '-' + val, ['f', 'o', 'o', 'b', 'a', 'r']);
+ *      //=> ['0-f', '1-o', '2-o', '3-b', '4-a', '5-r']
+ */
+
+
+var addIndex = /*#__PURE__*/_curry1(function addIndex(fn) {
+  return curryN(fn.length, function () {
+    var idx = 0;
+    var origFn = arguments[0];
+    var list = arguments[arguments.length - 1];
+    var args = Array.prototype.slice.call(arguments, 0);
+    args[0] = function () {
+      var result = origFn.apply(this, _concat(arguments, [idx, list]));
+      idx += 1;
+      return result;
+    };
+    return fn.apply(this, args);
+  });
+});
+module.exports = addIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/adjust.js b/server/node_modules/ramda/src/adjust.js
new file mode 100644
index 0000000000000000000000000000000000000000..c47d63fb578f1e64dc166c4ff7c978c3f11a90e8
--- /dev/null
+++ b/server/node_modules/ramda/src/adjust.js
@@ -0,0 +1,42 @@
+var _concat = /*#__PURE__*/require('./internal/_concat');
+
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Applies a function to the value at the given index of an array, returning a
+ * new copy of the array with the element at the given index replaced with the
+ * result of the function application.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig Number -> (a -> a) -> [a] -> [a]
+ * @param {Number} idx The index.
+ * @param {Function} fn The function to apply.
+ * @param {Array|Arguments} list An array-like object whose value
+ *        at the supplied index will be replaced.
+ * @return {Array} A copy of the supplied array-like object with
+ *         the element at index `idx` replaced with the value
+ *         returned by applying `fn` to the existing element.
+ * @see R.update
+ * @example
+ *
+ *      R.adjust(1, R.toUpper, ['a', 'b', 'c', 'd']);      //=> ['a', 'B', 'c', 'd']
+ *      R.adjust(-1, R.toUpper, ['a', 'b', 'c', 'd']);     //=> ['a', 'b', 'c', 'D']
+ * @symb R.adjust(-1, f, [a, b]) = [a, f(b)]
+ * @symb R.adjust(0, f, [a, b]) = [f(a), b]
+ */
+
+
+var adjust = /*#__PURE__*/_curry3(function adjust(idx, fn, list) {
+  if (idx >= list.length || idx < -list.length) {
+    return list;
+  }
+  var start = idx < 0 ? list.length : 0;
+  var _idx = start + idx;
+  var _list = _concat(list);
+  _list[_idx] = fn(list[_idx]);
+  return _list;
+});
+module.exports = adjust;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/all.js b/server/node_modules/ramda/src/all.js
new file mode 100644
index 0000000000000000000000000000000000000000..430aedf005833ffff9bc42985f883f73ed1129da
--- /dev/null
+++ b/server/node_modules/ramda/src/all.js
@@ -0,0 +1,43 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xall = /*#__PURE__*/require('./internal/_xall');
+
+/**
+ * Returns `true` if all elements of the list match the predicate, `false` if
+ * there are any that don't.
+ *
+ * Dispatches to the `all` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Boolean
+ * @param {Function} fn The predicate function.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if the predicate is satisfied by every element, `false`
+ *         otherwise.
+ * @see R.any, R.none, R.transduce
+ * @example
+ *
+ *      const equals3 = R.equals(3);
+ *      R.all(equals3)([3, 3, 3, 3]); //=> true
+ *      R.all(equals3)([3, 3, 1, 3]); //=> false
+ */
+
+
+var all = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['all'], _xall, function all(fn, list) {
+  var idx = 0;
+  while (idx < list.length) {
+    if (!fn(list[idx])) {
+      return false;
+    }
+    idx += 1;
+  }
+  return true;
+}));
+module.exports = all;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/allPass.js b/server/node_modules/ramda/src/allPass.js
new file mode 100644
index 0000000000000000000000000000000000000000..a0e58d08b216ffcd73388c5b1b460ef355ad516c
--- /dev/null
+++ b/server/node_modules/ramda/src/allPass.js
@@ -0,0 +1,51 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+var max = /*#__PURE__*/require('./max');
+
+var pluck = /*#__PURE__*/require('./pluck');
+
+var reduce = /*#__PURE__*/require('./reduce');
+
+/**
+ * Takes a list of predicates and returns a predicate that returns true for a
+ * given list of arguments if every one of the provided predicates is satisfied
+ * by those arguments.
+ *
+ * The function returned is a curried function whose arity matches that of the
+ * highest-arity predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Logic
+ * @sig [(*... -> Boolean)] -> (*... -> Boolean)
+ * @param {Array} predicates An array of predicates to check
+ * @return {Function} The combined predicate
+ * @see R.anyPass
+ * @example
+ *
+ *      const isQueen = R.propEq('rank', 'Q');
+ *      const isSpade = R.propEq('suit', '♠︎');
+ *      const isQueenOfSpades = R.allPass([isQueen, isSpade]);
+ *
+ *      isQueenOfSpades({rank: 'Q', suit: '♣︎'}); //=> false
+ *      isQueenOfSpades({rank: 'Q', suit: '♠︎'}); //=> true
+ */
+
+
+var allPass = /*#__PURE__*/_curry1(function allPass(preds) {
+  return curryN(reduce(max, 0, pluck('length', preds)), function () {
+    var idx = 0;
+    var len = preds.length;
+    while (idx < len) {
+      if (!preds[idx].apply(this, arguments)) {
+        return false;
+      }
+      idx += 1;
+    }
+    return true;
+  });
+});
+module.exports = allPass;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/always.js b/server/node_modules/ramda/src/always.js
new file mode 100644
index 0000000000000000000000000000000000000000..f8c58906b2b420502c356d12aec856d7b011113c
--- /dev/null
+++ b/server/node_modules/ramda/src/always.js
@@ -0,0 +1,29 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Returns a function that always returns the given value. Note that for
+ * non-primitives the value returned is a reference to the original value.
+ *
+ * This function is known as `const`, `constant`, or `K` (for K combinator) in
+ * other languages and libraries.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig a -> (* -> a)
+ * @param {*} val The value to wrap in a function
+ * @return {Function} A Function :: * -> val.
+ * @example
+ *
+ *      const t = R.always('Tee');
+ *      t(); //=> 'Tee'
+ */
+
+
+var always = /*#__PURE__*/_curry1(function always(val) {
+  return function () {
+    return val;
+  };
+});
+module.exports = always;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/and.js b/server/node_modules/ramda/src/and.js
new file mode 100644
index 0000000000000000000000000000000000000000..ff88be7a7282deba96bd9495452c6a4878e81421
--- /dev/null
+++ b/server/node_modules/ramda/src/and.js
@@ -0,0 +1,27 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns `true` if both arguments are `true`; `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig a -> b -> a | b
+ * @param {Any} a
+ * @param {Any} b
+ * @return {Any} the first argument if it is falsy, otherwise the second argument.
+ * @see R.both
+ * @example
+ *
+ *      R.and(true, true); //=> true
+ *      R.and(true, false); //=> false
+ *      R.and(false, true); //=> false
+ *      R.and(false, false); //=> false
+ */
+
+
+var and = /*#__PURE__*/_curry2(function and(a, b) {
+  return a && b;
+});
+module.exports = and;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/any.js b/server/node_modules/ramda/src/any.js
new file mode 100644
index 0000000000000000000000000000000000000000..7be36abef0a423a822eb872bf00e5d5d9c1555b2
--- /dev/null
+++ b/server/node_modules/ramda/src/any.js
@@ -0,0 +1,44 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xany = /*#__PURE__*/require('./internal/_xany');
+
+/**
+ * Returns `true` if at least one of the elements of the list match the predicate,
+ * `false` otherwise.
+ *
+ * Dispatches to the `any` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Boolean
+ * @param {Function} fn The predicate function.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if the predicate is satisfied by at least one element, `false`
+ *         otherwise.
+ * @see R.all, R.none, R.transduce
+ * @example
+ *
+ *      const lessThan0 = R.flip(R.lt)(0);
+ *      const lessThan2 = R.flip(R.lt)(2);
+ *      R.any(lessThan0)([1, 2]); //=> false
+ *      R.any(lessThan2)([1, 2]); //=> true
+ */
+
+
+var any = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['any'], _xany, function any(fn, list) {
+  var idx = 0;
+  while (idx < list.length) {
+    if (fn(list[idx])) {
+      return true;
+    }
+    idx += 1;
+  }
+  return false;
+}));
+module.exports = any;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/anyPass.js b/server/node_modules/ramda/src/anyPass.js
new file mode 100644
index 0000000000000000000000000000000000000000..abf1f66c256ed33e990773c3f492197cfa649d75
--- /dev/null
+++ b/server/node_modules/ramda/src/anyPass.js
@@ -0,0 +1,52 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+var max = /*#__PURE__*/require('./max');
+
+var pluck = /*#__PURE__*/require('./pluck');
+
+var reduce = /*#__PURE__*/require('./reduce');
+
+/**
+ * Takes a list of predicates and returns a predicate that returns true for a
+ * given list of arguments if at least one of the provided predicates is
+ * satisfied by those arguments.
+ *
+ * The function returned is a curried function whose arity matches that of the
+ * highest-arity predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Logic
+ * @sig [(*... -> Boolean)] -> (*... -> Boolean)
+ * @param {Array} predicates An array of predicates to check
+ * @return {Function} The combined predicate
+ * @see R.allPass
+ * @example
+ *
+ *      const isClub = R.propEq('suit', '♣');
+ *      const isSpade = R.propEq('suit', 'â™ ');
+ *      const isBlackCard = R.anyPass([isClub, isSpade]);
+ *
+ *      isBlackCard({rank: '10', suit: '♣'}); //=> true
+ *      isBlackCard({rank: 'Q', suit: 'â™ '}); //=> true
+ *      isBlackCard({rank: 'Q', suit: '♦'}); //=> false
+ */
+
+
+var anyPass = /*#__PURE__*/_curry1(function anyPass(preds) {
+  return curryN(reduce(max, 0, pluck('length', preds)), function () {
+    var idx = 0;
+    var len = preds.length;
+    while (idx < len) {
+      if (preds[idx].apply(this, arguments)) {
+        return true;
+      }
+      idx += 1;
+    }
+    return false;
+  });
+});
+module.exports = anyPass;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/ap.js b/server/node_modules/ramda/src/ap.js
new file mode 100644
index 0000000000000000000000000000000000000000..23ae9b5dce2b088f6d35e31cf90e11e147ace975
--- /dev/null
+++ b/server/node_modules/ramda/src/ap.js
@@ -0,0 +1,44 @@
+var _concat = /*#__PURE__*/require('./internal/_concat');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _reduce = /*#__PURE__*/require('./internal/_reduce');
+
+var map = /*#__PURE__*/require('./map');
+
+/**
+ * ap applies a list of functions to a list of values.
+ *
+ * Dispatches to the `ap` method of the second argument, if present. Also
+ * treats curried functions as applicatives.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Function
+ * @sig [a -> b] -> [a] -> [b]
+ * @sig Apply f => f (a -> b) -> f a -> f b
+ * @sig (r -> a -> b) -> (r -> a) -> (r -> b)
+ * @param {*} applyF
+ * @param {*} applyX
+ * @return {*}
+ * @example
+ *
+ *      R.ap([R.multiply(2), R.add(3)], [1,2,3]); //=> [2, 4, 6, 4, 5, 6]
+ *      R.ap([R.concat('tasty '), R.toUpper], ['pizza', 'salad']); //=> ["tasty pizza", "tasty salad", "PIZZA", "SALAD"]
+ *
+ *      // R.ap can also be used as S combinator
+ *      // when only two functions are passed
+ *      R.ap(R.concat, R.toUpper)('Ramda') //=> 'RamdaRAMDA'
+ * @symb R.ap([f, g], [a, b]) = [f(a), f(b), g(a), g(b)]
+ */
+
+
+var ap = /*#__PURE__*/_curry2(function ap(applyF, applyX) {
+  return typeof applyX['fantasy-land/ap'] === 'function' ? applyX['fantasy-land/ap'](applyF) : typeof applyF.ap === 'function' ? applyF.ap(applyX) : typeof applyF === 'function' ? function (x) {
+    return applyF(x)(applyX(x));
+  } : _reduce(function (acc, f) {
+    return _concat(acc, map(f, applyX));
+  }, [], applyF);
+});
+module.exports = ap;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/aperture.js b/server/node_modules/ramda/src/aperture.js
new file mode 100644
index 0000000000000000000000000000000000000000..7a4cde4e7eb3307859c0001669cc64afa1fce9d2
--- /dev/null
+++ b/server/node_modules/ramda/src/aperture.js
@@ -0,0 +1,33 @@
+var _aperture = /*#__PURE__*/require('./internal/_aperture');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xaperture = /*#__PURE__*/require('./internal/_xaperture');
+
+/**
+ * Returns a new list, composed of n-tuples of consecutive elements. If `n` is
+ * greater than the length of the list, an empty list is returned.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig Number -> [a] -> [[a]]
+ * @param {Number} n The size of the tuples to create
+ * @param {Array} list The list to split into `n`-length tuples
+ * @return {Array} The resulting list of `n`-length tuples
+ * @see R.transduce
+ * @example
+ *
+ *      R.aperture(2, [1, 2, 3, 4, 5]); //=> [[1, 2], [2, 3], [3, 4], [4, 5]]
+ *      R.aperture(3, [1, 2, 3, 4, 5]); //=> [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
+ *      R.aperture(7, [1, 2, 3, 4, 5]); //=> []
+ */
+
+
+var aperture = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xaperture, _aperture));
+module.exports = aperture;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/append.js b/server/node_modules/ramda/src/append.js
new file mode 100644
index 0000000000000000000000000000000000000000..bfe4165a294cb493210858d31f9f5d39db4d6d26
--- /dev/null
+++ b/server/node_modules/ramda/src/append.js
@@ -0,0 +1,30 @@
+var _concat = /*#__PURE__*/require('./internal/_concat');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns a new list containing the contents of the given list, followed by
+ * the given element.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> [a]
+ * @param {*} el The element to add to the end of the new list.
+ * @param {Array} list The list of elements to add a new item to.
+ *        list.
+ * @return {Array} A new list containing the elements of the old list followed by `el`.
+ * @see R.prepend
+ * @example
+ *
+ *      R.append('tests', ['write', 'more']); //=> ['write', 'more', 'tests']
+ *      R.append('tests', []); //=> ['tests']
+ *      R.append(['tests'], ['write', 'more']); //=> ['write', 'more', ['tests']]
+ */
+
+
+var append = /*#__PURE__*/_curry2(function append(el, list) {
+  return _concat(list, [el]);
+});
+module.exports = append;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/apply.js b/server/node_modules/ramda/src/apply.js
new file mode 100644
index 0000000000000000000000000000000000000000..eda7708ea6173f5bb598a91424e9b3a7433fabc1
--- /dev/null
+++ b/server/node_modules/ramda/src/apply.js
@@ -0,0 +1,28 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Applies function `fn` to the argument list `args`. This is useful for
+ * creating a fixed-arity function from a variadic function. `fn` should be a
+ * bound function if context is significant.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Function
+ * @sig (*... -> a) -> [*] -> a
+ * @param {Function} fn The function which will be called with `args`
+ * @param {Array} args The arguments to call `fn` with
+ * @return {*} result The result, equivalent to `fn(...args)`
+ * @see R.call, R.unapply
+ * @example
+ *
+ *      const nums = [1, 2, 3, -99, 42, 6, 7];
+ *      R.apply(Math.max, nums); //=> 42
+ * @symb R.apply(f, [a, b, c]) = f(a, b, c)
+ */
+
+
+var apply = /*#__PURE__*/_curry2(function apply(fn, args) {
+  return fn.apply(this, args);
+});
+module.exports = apply;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/applySpec.js b/server/node_modules/ramda/src/applySpec.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d1e98a7bfbfb919f2bd25e1fc1c4e2927cf67d6
--- /dev/null
+++ b/server/node_modules/ramda/src/applySpec.js
@@ -0,0 +1,65 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var apply = /*#__PURE__*/require('./apply');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+var max = /*#__PURE__*/require('./max');
+
+var pluck = /*#__PURE__*/require('./pluck');
+
+var reduce = /*#__PURE__*/require('./reduce');
+
+var keys = /*#__PURE__*/require('./keys');
+
+var values = /*#__PURE__*/require('./values');
+
+// Use custom mapValues function to avoid issues with specs that include a "map" key and R.map
+// delegating calls to .map
+
+
+function mapValues(fn, obj) {
+  return keys(obj).reduce(function (acc, key) {
+    acc[key] = fn(obj[key]);
+    return acc;
+  }, {});
+}
+
+/**
+ * Given a spec object recursively mapping properties to functions, creates a
+ * function producing an object of the same structure, by mapping each property
+ * to the result of calling its associated function with the supplied arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Function
+ * @sig {k: ((a, b, ..., m) -> v)} -> ((a, b, ..., m) -> {k: v})
+ * @param {Object} spec an object recursively mapping properties to functions for
+ *        producing the values for these properties.
+ * @return {Function} A function that returns an object of the same structure
+ * as `spec', with each property set to the value returned by calling its
+ * associated function with the supplied arguments.
+ * @see R.converge, R.juxt
+ * @example
+ *
+ *      const getMetrics = R.applySpec({
+ *        sum: R.add,
+ *        nested: { mul: R.multiply }
+ *      });
+ *      getMetrics(2, 4); // => { sum: 6, nested: { mul: 8 } }
+ * @symb R.applySpec({ x: f, y: { z: g } })(a, b) = { x: f(a, b), y: { z: g(a, b) } }
+ */
+var applySpec = /*#__PURE__*/_curry1(function applySpec(spec) {
+  spec = mapValues(function (v) {
+    return typeof v == 'function' ? v : applySpec(v);
+  }, spec);
+
+  return curryN(reduce(max, 0, pluck('length', values(spec))), function () {
+    var args = arguments;
+    return mapValues(function (f) {
+      return apply(f, args);
+    }, spec);
+  });
+});
+module.exports = applySpec;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/applyTo.js b/server/node_modules/ramda/src/applyTo.js
new file mode 100644
index 0000000000000000000000000000000000000000..968249c6e5f954536db3e16f082c004636be9f1e
--- /dev/null
+++ b/server/node_modules/ramda/src/applyTo.js
@@ -0,0 +1,27 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Takes a value and applies a function to it.
+ *
+ * This function is also known as the `thrush` combinator.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.25.0
+ * @category Function
+ * @sig a -> (a -> b) -> b
+ * @param {*} x The value
+ * @param {Function} f The function to apply
+ * @return {*} The result of applying `f` to `x`
+ * @example
+ *
+ *      const t42 = R.applyTo(42);
+ *      t42(R.identity); //=> 42
+ *      t42(R.add(1)); //=> 43
+ */
+
+
+var applyTo = /*#__PURE__*/_curry2(function applyTo(x, f) {
+  return f(x);
+});
+module.exports = applyTo;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/ascend.js b/server/node_modules/ramda/src/ascend.js
new file mode 100644
index 0000000000000000000000000000000000000000..f0bab4260de9d38a5a0cf4e6b756c99b9d2bb749
--- /dev/null
+++ b/server/node_modules/ramda/src/ascend.js
@@ -0,0 +1,35 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Makes an ascending comparator function out of a function that returns a value
+ * that can be compared with `<` and `>`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Function
+ * @sig Ord b => (a -> b) -> a -> a -> Number
+ * @param {Function} fn A function of arity one that returns a value that can be compared
+ * @param {*} a The first item to be compared.
+ * @param {*} b The second item to be compared.
+ * @return {Number} `-1` if fn(a) < fn(b), `1` if fn(b) < fn(a), otherwise `0`
+ * @see R.descend
+ * @example
+ *
+ *      const byAge = R.ascend(R.prop('age'));
+ *      const people = [
+ *        { name: 'Emma', age: 70 },
+ *        { name: 'Peter', age: 78 },
+ *        { name: 'Mikhail', age: 62 },
+ *      ];
+ *      const peopleByYoungestFirst = R.sort(byAge, people);
+ *        //=> [{ name: 'Mikhail', age: 62 },{ name: 'Emma', age: 70 }, { name: 'Peter', age: 78 }]
+ */
+
+
+var ascend = /*#__PURE__*/_curry3(function ascend(fn, a, b) {
+  var aa = fn(a);
+  var bb = fn(b);
+  return aa < bb ? -1 : aa > bb ? 1 : 0;
+});
+module.exports = ascend;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/assoc.js b/server/node_modules/ramda/src/assoc.js
new file mode 100644
index 0000000000000000000000000000000000000000..61a50675411913105dc66d42df133057aa0dbe03
--- /dev/null
+++ b/server/node_modules/ramda/src/assoc.js
@@ -0,0 +1,33 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Makes a shallow clone of an object, setting or overriding the specified
+ * property with the given value. Note that this copies and flattens prototype
+ * properties onto the new object as well. All non-primitive properties are
+ * copied by reference.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @sig String -> a -> {k: v} -> {k: v}
+ * @param {String} prop The property name to set
+ * @param {*} val The new value
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object equivalent to the original except for the changed property.
+ * @see R.dissoc, R.pick
+ * @example
+ *
+ *      R.assoc('c', 3, {a: 1, b: 2}); //=> {a: 1, b: 2, c: 3}
+ */
+
+
+var assoc = /*#__PURE__*/_curry3(function assoc(prop, val, obj) {
+  var result = {};
+  for (var p in obj) {
+    result[p] = obj[p];
+  }
+  result[prop] = val;
+  return result;
+});
+module.exports = assoc;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/assocPath.js b/server/node_modules/ramda/src/assocPath.js
new file mode 100644
index 0000000000000000000000000000000000000000..bb8765d83cf62d7d3a2f31f56b2b0c017b76ee52
--- /dev/null
+++ b/server/node_modules/ramda/src/assocPath.js
@@ -0,0 +1,56 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var _has = /*#__PURE__*/require('./internal/_has');
+
+var _isArray = /*#__PURE__*/require('./internal/_isArray');
+
+var _isInteger = /*#__PURE__*/require('./internal/_isInteger');
+
+var assoc = /*#__PURE__*/require('./assoc');
+
+var isNil = /*#__PURE__*/require('./isNil');
+
+/**
+ * Makes a shallow clone of an object, setting or overriding the nodes required
+ * to create the given path, and placing the specific value at the tail end of
+ * that path. Note that this copies and flattens prototype properties onto the
+ * new object as well. All non-primitive properties are copied by reference.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> a -> {a} -> {a}
+ * @param {Array} path the path to set
+ * @param {*} val The new value
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object equivalent to the original except along the specified path.
+ * @see R.dissocPath
+ * @example
+ *
+ *      R.assocPath(['a', 'b', 'c'], 42, {a: {b: {c: 0}}}); //=> {a: {b: {c: 42}}}
+ *
+ *      // Any missing or non-object keys in path will be overridden
+ *      R.assocPath(['a', 'b', 'c'], 42, {a: 5}); //=> {a: {b: {c: 42}}}
+ */
+
+
+var assocPath = /*#__PURE__*/_curry3(function assocPath(path, val, obj) {
+  if (path.length === 0) {
+    return val;
+  }
+  var idx = path[0];
+  if (path.length > 1) {
+    var nextObj = !isNil(obj) && _has(idx, obj) ? obj[idx] : _isInteger(path[1]) ? [] : {};
+    val = assocPath(Array.prototype.slice.call(path, 1), val, nextObj);
+  }
+  if (_isInteger(idx) && _isArray(obj)) {
+    var arr = [].concat(obj);
+    arr[idx] = val;
+    return arr;
+  } else {
+    return assoc(idx, val, obj);
+  }
+});
+module.exports = assocPath;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/binary.js b/server/node_modules/ramda/src/binary.js
new file mode 100644
index 0000000000000000000000000000000000000000..0b279dd3924fabbfee5485ab1644b0c4bb43f587
--- /dev/null
+++ b/server/node_modules/ramda/src/binary.js
@@ -0,0 +1,38 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var nAry = /*#__PURE__*/require('./nAry');
+
+/**
+ * Wraps a function of any arity (including nullary) in a function that accepts
+ * exactly 2 parameters. Any extraneous parameters will not be passed to the
+ * supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Function
+ * @sig (* -> c) -> (a, b -> c)
+ * @param {Function} fn The function to wrap.
+ * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
+ *         arity 2.
+ * @see R.nAry, R.unary
+ * @example
+ *
+ *      const takesThreeArgs = function(a, b, c) {
+ *        return [a, b, c];
+ *      };
+ *      takesThreeArgs.length; //=> 3
+ *      takesThreeArgs(1, 2, 3); //=> [1, 2, 3]
+ *
+ *      const takesTwoArgs = R.binary(takesThreeArgs);
+ *      takesTwoArgs.length; //=> 2
+ *      // Only 2 arguments are passed to the wrapped function
+ *      takesTwoArgs(1, 2, 3); //=> [1, 2, undefined]
+ * @symb R.binary(f)(a, b, c) = f(a, b)
+ */
+
+
+var binary = /*#__PURE__*/_curry1(function binary(fn) {
+  return nAry(2, fn);
+});
+module.exports = binary;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/bind.js b/server/node_modules/ramda/src/bind.js
new file mode 100644
index 0000000000000000000000000000000000000000..aa2241faf7e25132675647dce419681781dabf40
--- /dev/null
+++ b/server/node_modules/ramda/src/bind.js
@@ -0,0 +1,34 @@
+var _arity = /*#__PURE__*/require('./internal/_arity');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Creates a function that is bound to a context.
+ * Note: `R.bind` does not provide the additional argument-binding capabilities of
+ * [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category Function
+ * @category Object
+ * @sig (* -> *) -> {*} -> (* -> *)
+ * @param {Function} fn The function to bind to context
+ * @param {Object} thisObj The context to bind `fn` to
+ * @return {Function} A function that will execute in the context of `thisObj`.
+ * @see R.partial
+ * @example
+ *
+ *      const log = R.bind(console.log, console);
+ *      R.pipe(R.assoc('a', 2), R.tap(log), R.assoc('a', 3))({a: 1}); //=> {a: 3}
+ *      // logs {a: 2}
+ * @symb R.bind(f, o)(a, b) = f.call(o, a, b)
+ */
+
+
+var bind = /*#__PURE__*/_curry2(function bind(fn, thisObj) {
+  return _arity(fn.length, function () {
+    return fn.apply(thisObj, arguments);
+  });
+});
+module.exports = bind;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/both.js b/server/node_modules/ramda/src/both.js
new file mode 100644
index 0000000000000000000000000000000000000000..e89fb3d7e135a0b9535db63ef47d37f3c941e38b
--- /dev/null
+++ b/server/node_modules/ramda/src/both.js
@@ -0,0 +1,47 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _isFunction = /*#__PURE__*/require('./internal/_isFunction');
+
+var and = /*#__PURE__*/require('./and');
+
+var lift = /*#__PURE__*/require('./lift');
+
+/**
+ * A function which calls the two provided functions and returns the `&&`
+ * of the results.
+ * It returns the result of the first function if it is false-y and the result
+ * of the second function otherwise. Note that this is short-circuited,
+ * meaning that the second function will not be invoked if the first returns a
+ * false-y value.
+ *
+ * In addition to functions, `R.both` also accepts any fantasy-land compatible
+ * applicative functor.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category Logic
+ * @sig (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
+ * @param {Function} f A predicate
+ * @param {Function} g Another predicate
+ * @return {Function} a function that applies its arguments to `f` and `g` and `&&`s their outputs together.
+ * @see R.and
+ * @example
+ *
+ *      const gt10 = R.gt(R.__, 10)
+ *      const lt20 = R.lt(R.__, 20)
+ *      const f = R.both(gt10, lt20);
+ *      f(15); //=> true
+ *      f(30); //=> false
+ *
+ *      R.both(Maybe.Just(false), Maybe.Just(55)); // => Maybe.Just(false)
+ *      R.both([false, false, 'a'], [11]); //=> [false, false, 11]
+ */
+
+
+var both = /*#__PURE__*/_curry2(function both(f, g) {
+  return _isFunction(f) ? function _both() {
+    return f.apply(this, arguments) && g.apply(this, arguments);
+  } : lift(and)(f, g);
+});
+module.exports = both;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/call.js b/server/node_modules/ramda/src/call.js
new file mode 100644
index 0000000000000000000000000000000000000000..8412ac865451add9c18602441af870bf49494b22
--- /dev/null
+++ b/server/node_modules/ramda/src/call.js
@@ -0,0 +1,40 @@
+var curry = /*#__PURE__*/require('./curry');
+
+/**
+ * Returns the result of calling its first argument with the remaining
+ * arguments. This is occasionally useful as a converging function for
+ * [`R.converge`](#converge): the first branch can produce a function while the
+ * remaining branches produce values to be passed to that function as its
+ * arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig (*... -> a),*... -> a
+ * @param {Function} fn The function to apply to the remaining arguments.
+ * @param {...*} args Any number of positional arguments.
+ * @return {*}
+ * @see R.apply
+ * @example
+ *
+ *      R.call(R.add, 1, 2); //=> 3
+ *
+ *      const indentN = R.pipe(R.repeat(' '),
+ *                           R.join(''),
+ *                           R.replace(/^(?!$)/gm));
+ *
+ *      const format = R.converge(R.call, [
+ *                                  R.pipe(R.prop('indent'), indentN),
+ *                                  R.prop('value')
+ *                              ]);
+ *
+ *      format({indent: 2, value: 'foo\nbar\nbaz\n'}); //=> '  foo\n  bar\n  baz\n'
+ * @symb R.call(f, a, b) = f(a, b)
+ */
+
+
+var call = /*#__PURE__*/curry(function call(fn) {
+  return fn.apply(this, Array.prototype.slice.call(arguments, 1));
+});
+module.exports = call;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/chain.js b/server/node_modules/ramda/src/chain.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ecb925c4caa58466940cee77c14010e9e4c8078
--- /dev/null
+++ b/server/node_modules/ramda/src/chain.js
@@ -0,0 +1,47 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _makeFlat = /*#__PURE__*/require('./internal/_makeFlat');
+
+var _xchain = /*#__PURE__*/require('./internal/_xchain');
+
+var map = /*#__PURE__*/require('./map');
+
+/**
+ * `chain` maps a function over a list and concatenates the results. `chain`
+ * is also known as `flatMap` in some libraries.
+ *
+ * Dispatches to the `chain` method of the second argument, if present,
+ * according to the [FantasyLand Chain spec](https://github.com/fantasyland/fantasy-land#chain).
+ *
+ * If second argument is a function, `chain(f, g)(x)` is equivalent to `f(g(x), x)`.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig Chain m => (a -> m b) -> m a -> m b
+ * @param {Function} fn The function to map with
+ * @param {Array} list The list to map over
+ * @return {Array} The result of flat-mapping `list` with `fn`
+ * @example
+ *
+ *      const duplicate = n => [n, n];
+ *      R.chain(duplicate, [1, 2, 3]); //=> [1, 1, 2, 2, 3, 3]
+ *
+ *      R.chain(R.append, R.head)([1, 2, 3]); //=> [1, 2, 3, 1]
+ */
+
+
+var chain = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/chain', 'chain'], _xchain, function chain(fn, monad) {
+  if (typeof monad === 'function') {
+    return function (x) {
+      return fn(monad(x))(x);
+    };
+  }
+  return _makeFlat(false)(map(fn, monad));
+}));
+module.exports = chain;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/clamp.js b/server/node_modules/ramda/src/clamp.js
new file mode 100644
index 0000000000000000000000000000000000000000..0eb2fd073dd1a3cc0a04a72857fa6caac767576c
--- /dev/null
+++ b/server/node_modules/ramda/src/clamp.js
@@ -0,0 +1,31 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Restricts a number to be within a range.
+ *
+ * Also works for other ordered types such as Strings and Dates.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Relation
+ * @sig Ord a => a -> a -> a -> a
+ * @param {Number} minimum The lower limit of the clamp (inclusive)
+ * @param {Number} maximum The upper limit of the clamp (inclusive)
+ * @param {Number} value Value to be clamped
+ * @return {Number} Returns `minimum` when `val < minimum`, `maximum` when `val > maximum`, returns `val` otherwise
+ * @example
+ *
+ *      R.clamp(1, 10, -5) // => 1
+ *      R.clamp(1, 10, 15) // => 10
+ *      R.clamp(1, 10, 4)  // => 4
+ */
+
+
+var clamp = /*#__PURE__*/_curry3(function clamp(min, max, value) {
+  if (min > max) {
+    throw new Error('min must not be greater than max in clamp(min, max, value)');
+  }
+  return value < min ? min : value > max ? max : value;
+});
+module.exports = clamp;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/clone.js b/server/node_modules/ramda/src/clone.js
new file mode 100644
index 0000000000000000000000000000000000000000..c03f2ffbc544da5146c9f2ffe77fc032c0251633
--- /dev/null
+++ b/server/node_modules/ramda/src/clone.js
@@ -0,0 +1,31 @@
+var _clone = /*#__PURE__*/require('./internal/_clone');
+
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Creates a deep copy of the value which may contain (nested) `Array`s and
+ * `Object`s, `Number`s, `String`s, `Boolean`s and `Date`s. `Function`s are
+ * assigned by reference rather than copied
+ *
+ * Dispatches to a `clone` method if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {*} -> {*}
+ * @param {*} value The object or array to clone
+ * @return {*} A deeply cloned copy of `val`
+ * @example
+ *
+ *      const objects = [{}, {}, {}];
+ *      const objectsClone = R.clone(objects);
+ *      objects === objectsClone; //=> false
+ *      objects[0] === objectsClone[0]; //=> false
+ */
+
+
+var clone = /*#__PURE__*/_curry1(function clone(value) {
+  return value != null && typeof value.clone === 'function' ? value.clone() : _clone(value, [], [], true);
+});
+module.exports = clone;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/comparator.js b/server/node_modules/ramda/src/comparator.js
new file mode 100644
index 0000000000000000000000000000000000000000..84c8e0dd4415b071e3032acab7d8066f56c2aae8
--- /dev/null
+++ b/server/node_modules/ramda/src/comparator.js
@@ -0,0 +1,33 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Makes a comparator function out of a function that reports whether the first
+ * element is less than the second.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((a, b) -> Boolean) -> ((a, b) -> Number)
+ * @param {Function} pred A predicate function of arity two which will return `true` if the first argument
+ * is less than the second, `false` otherwise
+ * @return {Function} A Function :: a -> b -> Int that returns `-1` if a < b, `1` if b < a, otherwise `0`
+ * @example
+ *
+ *      const byAge = R.comparator((a, b) => a.age < b.age);
+ *      const people = [
+ *        { name: 'Emma', age: 70 },
+ *        { name: 'Peter', age: 78 },
+ *        { name: 'Mikhail', age: 62 },
+ *      ];
+ *      const peopleByIncreasingAge = R.sort(byAge, people);
+ *        //=> [{ name: 'Mikhail', age: 62 },{ name: 'Emma', age: 70 }, { name: 'Peter', age: 78 }]
+ */
+
+
+var comparator = /*#__PURE__*/_curry1(function comparator(pred) {
+  return function (a, b) {
+    return pred(a, b) ? -1 : pred(b, a) ? 1 : 0;
+  };
+});
+module.exports = comparator;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/complement.js b/server/node_modules/ramda/src/complement.js
new file mode 100644
index 0000000000000000000000000000000000000000..c2ba8a09662851915ce28aefaf54aab631f2c8b0
--- /dev/null
+++ b/server/node_modules/ramda/src/complement.js
@@ -0,0 +1,30 @@
+var lift = /*#__PURE__*/require('./lift');
+
+var not = /*#__PURE__*/require('./not');
+
+/**
+ * Takes a function `f` and returns a function `g` such that if called with the same arguments
+ * when `f` returns a "truthy" value, `g` returns `false` and when `f` returns a "falsy" value `g` returns `true`.
+ *
+ * `R.complement` may be applied to any functor
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category Logic
+ * @sig (*... -> *) -> (*... -> Boolean)
+ * @param {Function} f
+ * @return {Function}
+ * @see R.not
+ * @example
+ *
+ *      const isNotNil = R.complement(R.isNil);
+ *      isNil(null); //=> true
+ *      isNotNil(null); //=> false
+ *      isNil(7); //=> false
+ *      isNotNil(7); //=> true
+ */
+
+
+var complement = /*#__PURE__*/lift(not);
+module.exports = complement;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/compose.js b/server/node_modules/ramda/src/compose.js
new file mode 100644
index 0000000000000000000000000000000000000000..cdacf38c4ca85822d0374832d176c0392c565e72
--- /dev/null
+++ b/server/node_modules/ramda/src/compose.js
@@ -0,0 +1,37 @@
+var pipe = /*#__PURE__*/require('./pipe');
+
+var reverse = /*#__PURE__*/require('./reverse');
+
+/**
+ * Performs right-to-left function composition. The rightmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * **Note:** The result of compose is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)) -> ((a, b, ..., n) -> z)
+ * @param {...Function} ...functions The functions to compose
+ * @return {Function}
+ * @see R.pipe
+ * @example
+ *
+ *      const classyGreeting = (firstName, lastName) => "The name's " + lastName + ", " + firstName + " " + lastName
+ *      const yellGreeting = R.compose(R.toUpper, classyGreeting);
+ *      yellGreeting('James', 'Bond'); //=> "THE NAME'S BOND, JAMES BOND"
+ *
+ *      R.compose(Math.abs, R.add(1), R.multiply(2))(-4) //=> 7
+ *
+ * @symb R.compose(f, g, h)(a, b) = f(g(h(a, b)))
+ */
+
+
+function compose() {
+  if (arguments.length === 0) {
+    throw new Error('compose requires at least one argument');
+  }
+  return pipe.apply(this, reverse(arguments));
+}
+module.exports = compose;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/composeK.js b/server/node_modules/ramda/src/composeK.js
new file mode 100644
index 0000000000000000000000000000000000000000..18e47879765a0c73aa928f08e88e9903e2b82ce8
--- /dev/null
+++ b/server/node_modules/ramda/src/composeK.js
@@ -0,0 +1,48 @@
+var chain = /*#__PURE__*/require('./chain');
+
+var compose = /*#__PURE__*/require('./compose');
+
+var map = /*#__PURE__*/require('./map');
+
+/**
+ * Returns the right-to-left Kleisli composition of the provided functions,
+ * each of which must return a value of a type supported by [`chain`](#chain).
+ *
+ * `R.composeK(h, g, f)` is equivalent to `R.compose(R.chain(h), R.chain(g), f)`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Function
+ * @sig Chain m => ((y -> m z), (x -> m y), ..., (a -> m b)) -> (a -> m z)
+ * @param {...Function} ...functions The functions to compose
+ * @return {Function}
+ * @see R.pipeK
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *       //  get :: String -> Object -> Maybe *
+ *       const get = R.curry((propName, obj) => Maybe(obj[propName]))
+ *
+ *       //  getStateCode :: Maybe String -> Maybe String
+ *       const getStateCode = R.composeK(
+ *         R.compose(Maybe.of, R.toUpper),
+ *         get('state'),
+ *         get('address'),
+ *         get('user'),
+ *       );
+ *       getStateCode({"user":{"address":{"state":"ny"}}}); //=> Maybe.Just("NY")
+ *       getStateCode({}); //=> Maybe.Nothing()
+ * @symb R.composeK(f, g, h)(a) = R.chain(f, R.chain(g, h(a)))
+ */
+
+
+function composeK() {
+  if (arguments.length === 0) {
+    throw new Error('composeK requires at least one argument');
+  }
+  var init = Array.prototype.slice.call(arguments);
+  var last = init.pop();
+  return compose(compose.apply(this, map(chain, init)), last);
+}
+module.exports = composeK;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/composeP.js b/server/node_modules/ramda/src/composeP.js
new file mode 100644
index 0000000000000000000000000000000000000000..69c0af61c6fd0e3df7e5aad7f43f8fa4897dd96e
--- /dev/null
+++ b/server/node_modules/ramda/src/composeP.js
@@ -0,0 +1,48 @@
+var pipeP = /*#__PURE__*/require('./pipeP');
+
+var reverse = /*#__PURE__*/require('./reverse');
+
+/**
+ * Performs right-to-left composition of one or more Promise-returning
+ * functions. The rightmost function may have any arity; the remaining
+ * functions must be unary.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((y -> Promise z), (x -> Promise y), ..., (a -> Promise b)) -> (a -> Promise z)
+ * @param {...Function} functions The functions to compose
+ * @return {Function}
+ * @see R.pipeP
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      const db = {
+ *        users: {
+ *          JOE: {
+ *            name: 'Joe',
+ *            followers: ['STEVE', 'SUZY']
+ *          }
+ *        }
+ *      }
+ *
+ *      // We'll pretend to do a db lookup which returns a promise
+ *      const lookupUser = (userId) => Promise.resolve(db.users[userId])
+ *      const lookupFollowers = (user) => Promise.resolve(user.followers)
+ *      lookupUser('JOE').then(lookupFollowers)
+ *
+ *      //  followersForUser :: String -> Promise [UserId]
+ *      const followersForUser = R.composeP(lookupFollowers, lookupUser);
+ *      followersForUser('JOE').then(followers => console.log('Followers:', followers))
+ *      // Followers: ["STEVE","SUZY"]
+ */
+
+
+function composeP() {
+  if (arguments.length === 0) {
+    throw new Error('composeP requires at least one argument');
+  }
+  return pipeP.apply(this, reverse(arguments));
+}
+module.exports = composeP;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/composeWith.js b/server/node_modules/ramda/src/composeWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..9c81b3232ddcb0abbfc26ef60fd0e00e38a3fef7
--- /dev/null
+++ b/server/node_modules/ramda/src/composeWith.js
@@ -0,0 +1,34 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var pipeWith = /*#__PURE__*/require('./pipeWith');
+
+var reverse = /*#__PURE__*/require('./reverse');
+
+/**
+ * Performs right-to-left function composition using transforming function. The rightmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * **Note:** The result of compose is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig ((* -> *), [(y -> z), (x -> y), ..., (o -> p), ((a, b, ..., n) -> o)]) -> ((a, b, ..., n) -> z)
+ * @param {...Function} ...functions The functions to compose
+ * @return {Function}
+ * @see R.compose, R.pipeWith
+ * @example
+ *
+ *      const composeWhileNotNil = R.composeWith((f, res) => R.isNil(res) ? res : f(res));
+ *
+ *      composeWhileNotNil([R.inc, R.prop('age')])({age: 1}) //=> 2
+ *      composeWhileNotNil([R.inc, R.prop('age')])({}) //=> undefined
+ *
+ * @symb R.composeWith(f)([g, h, i])(...args) = f(g, f(h, f(i, ...args)))
+ */
+
+
+var composeWith = /*#__PURE__*/_curry2(function composeWith(xf, list) {
+  return pipeWith.apply(this, [xf, reverse(list)]);
+});
+module.exports = composeWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/concat.js b/server/node_modules/ramda/src/concat.js
new file mode 100644
index 0000000000000000000000000000000000000000..c81eb0a6a353b09bf5ffd46f0122dea3b9d82741
--- /dev/null
+++ b/server/node_modules/ramda/src/concat.js
@@ -0,0 +1,62 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _isArray = /*#__PURE__*/require('./internal/_isArray');
+
+var _isFunction = /*#__PURE__*/require('./internal/_isFunction');
+
+var _isString = /*#__PURE__*/require('./internal/_isString');
+
+var toString = /*#__PURE__*/require('./toString');
+
+/**
+ * Returns the result of concatenating the given lists or strings.
+ *
+ * Note: `R.concat` expects both arguments to be of the same type,
+ * unlike the native `Array.prototype.concat` method. It will throw
+ * an error if you `concat` an Array with a non-Array value.
+ *
+ * Dispatches to the `concat` method of the first argument, if present.
+ * Can also concatenate two members of a [fantasy-land
+ * compatible semigroup](https://github.com/fantasyland/fantasy-land#semigroup).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a] -> [a]
+ * @sig String -> String -> String
+ * @param {Array|String} firstList The first list
+ * @param {Array|String} secondList The second list
+ * @return {Array|String} A list consisting of the elements of `firstList` followed by the elements of
+ * `secondList`.
+ *
+ * @example
+ *
+ *      R.concat('ABC', 'DEF'); // 'ABCDEF'
+ *      R.concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3]
+ *      R.concat([], []); //=> []
+ */
+
+
+var concat = /*#__PURE__*/_curry2(function concat(a, b) {
+  if (_isArray(a)) {
+    if (_isArray(b)) {
+      return a.concat(b);
+    }
+    throw new TypeError(toString(b) + ' is not an array');
+  }
+  if (_isString(a)) {
+    if (_isString(b)) {
+      return a + b;
+    }
+    throw new TypeError(toString(b) + ' is not a string');
+  }
+  if (a != null && _isFunction(a['fantasy-land/concat'])) {
+    return a['fantasy-land/concat'](b);
+  }
+  if (a != null && _isFunction(a.concat)) {
+    return a.concat(b);
+  }
+  throw new TypeError(toString(a) + ' does not have a method named "concat" or "fantasy-land/concat"');
+});
+module.exports = concat;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/cond.js b/server/node_modules/ramda/src/cond.js
new file mode 100644
index 0000000000000000000000000000000000000000..b175e2e6d8c2e6ce051398341d96d664f8a7cf6c
--- /dev/null
+++ b/server/node_modules/ramda/src/cond.js
@@ -0,0 +1,54 @@
+var _arity = /*#__PURE__*/require('./internal/_arity');
+
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var map = /*#__PURE__*/require('./map');
+
+var max = /*#__PURE__*/require('./max');
+
+var reduce = /*#__PURE__*/require('./reduce');
+
+/**
+ * Returns a function, `fn`, which encapsulates `if/else, if/else, ...` logic.
+ * `R.cond` takes a list of [predicate, transformer] pairs. All of the arguments
+ * to `fn` are applied to each of the predicates in turn until one returns a
+ * "truthy" value, at which point `fn` returns the result of applying its
+ * arguments to the corresponding transformer. If none of the predicates
+ * matches, `fn` returns undefined.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category Logic
+ * @sig [[(*... -> Boolean),(*... -> *)]] -> (*... -> *)
+ * @param {Array} pairs A list of [predicate, transformer]
+ * @return {Function}
+ * @see R.ifElse, R.unless, R.when
+ * @example
+ *
+ *      const fn = R.cond([
+ *        [R.equals(0),   R.always('water freezes at 0°C')],
+ *        [R.equals(100), R.always('water boils at 100°C')],
+ *        [R.T,           temp => 'nothing special happens at ' + temp + '°C']
+ *      ]);
+ *      fn(0); //=> 'water freezes at 0°C'
+ *      fn(50); //=> 'nothing special happens at 50°C'
+ *      fn(100); //=> 'water boils at 100°C'
+ */
+
+
+var cond = /*#__PURE__*/_curry1(function cond(pairs) {
+  var arity = reduce(max, 0, map(function (pair) {
+    return pair[0].length;
+  }, pairs));
+  return _arity(arity, function () {
+    var idx = 0;
+    while (idx < pairs.length) {
+      if (pairs[idx][0].apply(this, arguments)) {
+        return pairs[idx][1].apply(this, arguments);
+      }
+      idx += 1;
+    }
+  });
+});
+module.exports = cond;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/construct.js b/server/node_modules/ramda/src/construct.js
new file mode 100644
index 0000000000000000000000000000000000000000..3bf696e507429f6d2a7cbe10c4cb7336adcf69a3
--- /dev/null
+++ b/server/node_modules/ramda/src/construct.js
@@ -0,0 +1,42 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var constructN = /*#__PURE__*/require('./constructN');
+
+/**
+ * Wraps a constructor function inside a curried function that can be called
+ * with the same arguments and returns the same type.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (* -> {*}) -> (* -> {*})
+ * @param {Function} fn The constructor function to wrap.
+ * @return {Function} A wrapped, curried constructor function.
+ * @see R.invoker
+ * @example
+ *
+ *      // Constructor function
+ *      function Animal(kind) {
+ *        this.kind = kind;
+ *      };
+ *      Animal.prototype.sighting = function() {
+ *        return "It's a " + this.kind + "!";
+ *      }
+ *
+ *      const AnimalConstructor = R.construct(Animal)
+ *
+ *      // Notice we no longer need the 'new' keyword:
+ *      AnimalConstructor('Pig'); //=> {"kind": "Pig", "sighting": function (){...}};
+ *
+ *      const animalTypes = ["Lion", "Tiger", "Bear"];
+ *      const animalSighting = R.invoker(0, 'sighting');
+ *      const sightNewAnimal = R.compose(animalSighting, AnimalConstructor);
+ *      R.map(sightNewAnimal, animalTypes); //=> ["It's a Lion!", "It's a Tiger!", "It's a Bear!"]
+ */
+
+
+var construct = /*#__PURE__*/_curry1(function construct(Fn) {
+  return constructN(Fn.length, Fn);
+});
+module.exports = construct;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/constructN.js b/server/node_modules/ramda/src/constructN.js
new file mode 100644
index 0000000000000000000000000000000000000000..9e16ff59f52a9d864fad7cb608bc262cce870c32
--- /dev/null
+++ b/server/node_modules/ramda/src/constructN.js
@@ -0,0 +1,78 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var curry = /*#__PURE__*/require('./curry');
+
+var nAry = /*#__PURE__*/require('./nAry');
+
+/**
+ * Wraps a constructor function inside a curried function that can be called
+ * with the same arguments and returns the same type. The arity of the function
+ * returned is specified to allow using variadic constructor functions.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.0
+ * @category Function
+ * @sig Number -> (* -> {*}) -> (* -> {*})
+ * @param {Number} n The arity of the constructor function.
+ * @param {Function} Fn The constructor function to wrap.
+ * @return {Function} A wrapped, curried constructor function.
+ * @example
+ *
+ *      // Variadic Constructor function
+ *      function Salad() {
+ *        this.ingredients = arguments;
+ *      }
+ *
+ *      Salad.prototype.recipe = function() {
+ *        const instructions = R.map(ingredient => 'Add a dollop of ' + ingredient, this.ingredients);
+ *        return R.join('\n', instructions);
+ *      };
+ *
+ *      const ThreeLayerSalad = R.constructN(3, Salad);
+ *
+ *      // Notice we no longer need the 'new' keyword, and the constructor is curried for 3 arguments.
+ *      const salad = ThreeLayerSalad('Mayonnaise')('Potato Chips')('Ketchup');
+ *
+ *      console.log(salad.recipe());
+ *      // Add a dollop of Mayonnaise
+ *      // Add a dollop of Potato Chips
+ *      // Add a dollop of Ketchup
+ */
+
+
+var constructN = /*#__PURE__*/_curry2(function constructN(n, Fn) {
+  if (n > 10) {
+    throw new Error('Constructor with greater than ten arguments');
+  }
+  if (n === 0) {
+    return function () {
+      return new Fn();
+    };
+  }
+  return curry(nAry(n, function ($0, $1, $2, $3, $4, $5, $6, $7, $8, $9) {
+    switch (arguments.length) {
+      case 1:
+        return new Fn($0);
+      case 2:
+        return new Fn($0, $1);
+      case 3:
+        return new Fn($0, $1, $2);
+      case 4:
+        return new Fn($0, $1, $2, $3);
+      case 5:
+        return new Fn($0, $1, $2, $3, $4);
+      case 6:
+        return new Fn($0, $1, $2, $3, $4, $5);
+      case 7:
+        return new Fn($0, $1, $2, $3, $4, $5, $6);
+      case 8:
+        return new Fn($0, $1, $2, $3, $4, $5, $6, $7);
+      case 9:
+        return new Fn($0, $1, $2, $3, $4, $5, $6, $7, $8);
+      case 10:
+        return new Fn($0, $1, $2, $3, $4, $5, $6, $7, $8, $9);
+    }
+  }));
+});
+module.exports = constructN;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/contains.js b/server/node_modules/ramda/src/contains.js
new file mode 100644
index 0000000000000000000000000000000000000000..a81a62c0f43bc4a363d1ede935b81c530089d826
--- /dev/null
+++ b/server/node_modules/ramda/src/contains.js
@@ -0,0 +1,31 @@
+var _includes = /*#__PURE__*/require('./internal/_includes');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns `true` if the specified value is equal, in [`R.equals`](#equals)
+ * terms, to at least one element of the given list; `false` otherwise.
+ * Works also with strings.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Boolean
+ * @param {Object} a The item to compare against.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if an equivalent item is in the list, `false` otherwise.
+ * @see R.includes
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      R.contains(3, [1, 2, 3]); //=> true
+ *      R.contains(4, [1, 2, 3]); //=> false
+ *      R.contains({ name: 'Fred' }, [{ name: 'Fred' }]); //=> true
+ *      R.contains([42], [[42]]); //=> true
+ *      R.contains('ba', 'banana'); //=>true
+ */
+
+
+var contains = /*#__PURE__*/_curry2(_includes);
+module.exports = contains;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/converge.js b/server/node_modules/ramda/src/converge.js
new file mode 100644
index 0000000000000000000000000000000000000000..0b48fc97c2b28d12d4c974e36a5796d81fcfeba3
--- /dev/null
+++ b/server/node_modules/ramda/src/converge.js
@@ -0,0 +1,52 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _map = /*#__PURE__*/require('./internal/_map');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+var max = /*#__PURE__*/require('./max');
+
+var pluck = /*#__PURE__*/require('./pluck');
+
+var reduce = /*#__PURE__*/require('./reduce');
+
+/**
+ * Accepts a converging function and a list of branching functions and returns
+ * a new function. The arity of the new function is the same as the arity of
+ * the longest branching function. When invoked, this new function is applied
+ * to some arguments, and each branching function is applied to those same
+ * arguments. The results of each branching function are passed as arguments
+ * to the converging function to produce the return value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.2
+ * @category Function
+ * @sig ((x1, x2, ...) -> z) -> [((a, b, ...) -> x1), ((a, b, ...) -> x2), ...] -> (a -> b -> ... -> z)
+ * @param {Function} after A function. `after` will be invoked with the return values of
+ *        `fn1` and `fn2` as its arguments.
+ * @param {Array} functions A list of functions.
+ * @return {Function} A new function.
+ * @see R.useWith
+ * @example
+ *
+ *      const average = R.converge(R.divide, [R.sum, R.length])
+ *      average([1, 2, 3, 4, 5, 6, 7]) //=> 4
+ *
+ *      const strangeConcat = R.converge(R.concat, [R.toUpper, R.toLower])
+ *      strangeConcat("Yodel") //=> "YODELyodel"
+ *
+ * @symb R.converge(f, [g, h])(a, b) = f(g(a, b), h(a, b))
+ */
+
+
+var converge = /*#__PURE__*/_curry2(function converge(after, fns) {
+  return curryN(reduce(max, 0, pluck('length', fns)), function () {
+    var args = arguments;
+    var context = this;
+    return after.apply(context, _map(function (fn) {
+      return fn.apply(context, args);
+    }, fns));
+  });
+});
+module.exports = converge;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/countBy.js b/server/node_modules/ramda/src/countBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..0d86d3172c953ef6a8f3bfe86411b7444ae57838
--- /dev/null
+++ b/server/node_modules/ramda/src/countBy.js
@@ -0,0 +1,32 @@
+var reduceBy = /*#__PURE__*/require('./reduceBy');
+
+/**
+ * Counts the elements of a list according to how many match each value of a
+ * key generated by the supplied function. Returns an object mapping the keys
+ * produced by `fn` to the number of occurrences in the list. Note that all
+ * keys are coerced to strings because of how JavaScript objects work.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig (a -> String) -> [a] -> {*}
+ * @param {Function} fn The function used to map values to keys.
+ * @param {Array} list The list to count elements from.
+ * @return {Object} An object mapping keys to number of occurrences in the list.
+ * @example
+ *
+ *      const numbers = [1.0, 1.1, 1.2, 2.0, 3.0, 2.2];
+ *      R.countBy(Math.floor)(numbers);    //=> {'1': 3, '2': 2, '3': 1}
+ *
+ *      const letters = ['a', 'b', 'A', 'a', 'B', 'c'];
+ *      R.countBy(R.toLower)(letters);   //=> {'a': 3, 'b': 2, 'c': 1}
+ */
+
+
+var countBy = /*#__PURE__*/reduceBy(function (acc, elem) {
+  return acc + 1;
+}, 0);
+module.exports = countBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/curry.js b/server/node_modules/ramda/src/curry.js
new file mode 100644
index 0000000000000000000000000000000000000000..7da379717b2a873d8eb160936b46c8b2b0a91043
--- /dev/null
+++ b/server/node_modules/ramda/src/curry.js
@@ -0,0 +1,51 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+/**
+ * Returns a curried equivalent of the provided function. The curried function
+ * has two unusual capabilities. First, its arguments needn't be provided one
+ * at a time. If `f` is a ternary function and `g` is `R.curry(f)`, the
+ * following are equivalent:
+ *
+ *   - `g(1)(2)(3)`
+ *   - `g(1)(2, 3)`
+ *   - `g(1, 2)(3)`
+ *   - `g(1, 2, 3)`
+ *
+ * Secondly, the special placeholder value [`R.__`](#__) may be used to specify
+ * "gaps", allowing partial application of any combination of arguments,
+ * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__),
+ * the following are equivalent:
+ *
+ *   - `g(1, 2, 3)`
+ *   - `g(_, 2, 3)(1)`
+ *   - `g(_, _, 3)(1)(2)`
+ *   - `g(_, _, 3)(1, 2)`
+ *   - `g(_, 2)(1)(3)`
+ *   - `g(_, 2)(1, 3)`
+ *   - `g(_, 2)(_, 3)(1)`
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (* -> a) -> (* -> a)
+ * @param {Function} fn The function to curry.
+ * @return {Function} A new, curried function.
+ * @see R.curryN, R.partial
+ * @example
+ *
+ *      const addFourNumbers = (a, b, c, d) => a + b + c + d;
+ *
+ *      const curriedAddFourNumbers = R.curry(addFourNumbers);
+ *      const f = curriedAddFourNumbers(1, 2);
+ *      const g = f(3);
+ *      g(4); //=> 10
+ */
+
+
+var curry = /*#__PURE__*/_curry1(function curry(fn) {
+  return curryN(fn.length, fn);
+});
+module.exports = curry;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/curryN.js b/server/node_modules/ramda/src/curryN.js
new file mode 100644
index 0000000000000000000000000000000000000000..83c5723b2f29f0e3bd2990ed3fd77a0c4aa10be6
--- /dev/null
+++ b/server/node_modules/ramda/src/curryN.js
@@ -0,0 +1,59 @@
+var _arity = /*#__PURE__*/require('./internal/_arity');
+
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _curryN = /*#__PURE__*/require('./internal/_curryN');
+
+/**
+ * Returns a curried equivalent of the provided function, with the specified
+ * arity. The curried function has two unusual capabilities. First, its
+ * arguments needn't be provided one at a time. If `g` is `R.curryN(3, f)`, the
+ * following are equivalent:
+ *
+ *   - `g(1)(2)(3)`
+ *   - `g(1)(2, 3)`
+ *   - `g(1, 2)(3)`
+ *   - `g(1, 2, 3)`
+ *
+ * Secondly, the special placeholder value [`R.__`](#__) may be used to specify
+ * "gaps", allowing partial application of any combination of arguments,
+ * regardless of their positions. If `g` is as above and `_` is [`R.__`](#__),
+ * the following are equivalent:
+ *
+ *   - `g(1, 2, 3)`
+ *   - `g(_, 2, 3)(1)`
+ *   - `g(_, _, 3)(1)(2)`
+ *   - `g(_, _, 3)(1, 2)`
+ *   - `g(_, 2)(1)(3)`
+ *   - `g(_, 2)(1, 3)`
+ *   - `g(_, 2)(_, 3)(1)`
+ *
+ * @func
+ * @memberOf R
+ * @since v0.5.0
+ * @category Function
+ * @sig Number -> (* -> a) -> (* -> a)
+ * @param {Number} length The arity for the returned function.
+ * @param {Function} fn The function to curry.
+ * @return {Function} A new, curried function.
+ * @see R.curry
+ * @example
+ *
+ *      const sumArgs = (...args) => R.sum(args);
+ *
+ *      const curriedAddFourNumbers = R.curryN(4, sumArgs);
+ *      const f = curriedAddFourNumbers(1, 2);
+ *      const g = f(3);
+ *      g(4); //=> 10
+ */
+
+
+var curryN = /*#__PURE__*/_curry2(function curryN(length, fn) {
+  if (length === 1) {
+    return _curry1(fn);
+  }
+  return _arity(length, _curryN(length, [], fn));
+});
+module.exports = curryN;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/dec.js b/server/node_modules/ramda/src/dec.js
new file mode 100644
index 0000000000000000000000000000000000000000..4bf2af1d23a2933b09df5ea79831806887d1a5e8
--- /dev/null
+++ b/server/node_modules/ramda/src/dec.js
@@ -0,0 +1,21 @@
+var add = /*#__PURE__*/require('./add');
+
+/**
+ * Decrements its argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Math
+ * @sig Number -> Number
+ * @param {Number} n
+ * @return {Number} n - 1
+ * @see R.inc
+ * @example
+ *
+ *      R.dec(42); //=> 41
+ */
+
+
+var dec = /*#__PURE__*/add(-1);
+module.exports = dec;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/defaultTo.js b/server/node_modules/ramda/src/defaultTo.js
new file mode 100644
index 0000000000000000000000000000000000000000..22c1e3a645b3f6339a058ffd359efe5919481cd9
--- /dev/null
+++ b/server/node_modules/ramda/src/defaultTo.js
@@ -0,0 +1,31 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns the second argument if it is not `null`, `undefined` or `NaN`;
+ * otherwise the first argument is returned.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Logic
+ * @sig a -> b -> a | b
+ * @param {a} default The default value.
+ * @param {b} val `val` will be returned instead of `default` unless `val` is `null`, `undefined` or `NaN`.
+ * @return {*} The second value if it is not `null`, `undefined` or `NaN`, otherwise the default value
+ * @example
+ *
+ *      const defaultTo42 = R.defaultTo(42);
+ *
+ *      defaultTo42(null);  //=> 42
+ *      defaultTo42(undefined);  //=> 42
+ *      defaultTo42(false);  //=> false
+ *      defaultTo42('Ramda');  //=> 'Ramda'
+ *      // parseInt('string') results in NaN
+ *      defaultTo42(parseInt('string')); //=> 42
+ */
+
+
+var defaultTo = /*#__PURE__*/_curry2(function defaultTo(d, v) {
+  return v == null || v !== v ? d : v;
+});
+module.exports = defaultTo;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/descend.js b/server/node_modules/ramda/src/descend.js
new file mode 100644
index 0000000000000000000000000000000000000000..1608a5167f6e851ecebed0ca04f4dd125a7ffafd
--- /dev/null
+++ b/server/node_modules/ramda/src/descend.js
@@ -0,0 +1,35 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Makes a descending comparator function out of a function that returns a value
+ * that can be compared with `<` and `>`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Function
+ * @sig Ord b => (a -> b) -> a -> a -> Number
+ * @param {Function} fn A function of arity one that returns a value that can be compared
+ * @param {*} a The first item to be compared.
+ * @param {*} b The second item to be compared.
+ * @return {Number} `-1` if fn(a) > fn(b), `1` if fn(b) > fn(a), otherwise `0`
+ * @see R.ascend
+ * @example
+ *
+ *      const byAge = R.descend(R.prop('age'));
+ *      const people = [
+ *        { name: 'Emma', age: 70 },
+ *        { name: 'Peter', age: 78 },
+ *        { name: 'Mikhail', age: 62 },
+ *      ];
+ *      const peopleByOldestFirst = R.sort(byAge, people);
+ *        //=> [{ name: 'Peter', age: 78 }, { name: 'Emma', age: 70 }, { name: 'Mikhail', age: 62 }]
+ */
+
+
+var descend = /*#__PURE__*/_curry3(function descend(fn, a, b) {
+  var aa = fn(a);
+  var bb = fn(b);
+  return aa > bb ? -1 : aa < bb ? 1 : 0;
+});
+module.exports = descend;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/difference.js b/server/node_modules/ramda/src/difference.js
new file mode 100644
index 0000000000000000000000000000000000000000..1085bdf005b3c2f385a70f0f69518bfd954e7859
--- /dev/null
+++ b/server/node_modules/ramda/src/difference.js
@@ -0,0 +1,46 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _Set = /*#__PURE__*/require('./internal/_Set');
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements in the first list not
+ * contained in the second list. Objects and Arrays are compared in terms of
+ * value equality, not reference equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` that are not in `list2`.
+ * @see R.differenceWith, R.symmetricDifference, R.symmetricDifferenceWith, R.without
+ * @example
+ *
+ *      R.difference([1,2,3,4], [7,6,5,4,3]); //=> [1,2]
+ *      R.difference([7,6,5,4,3], [1,2,3,4]); //=> [7,6,5]
+ *      R.difference([{a: 1}, {b: 2}], [{a: 1}, {c: 3}]) //=> [{b: 2}]
+ */
+
+
+var difference = /*#__PURE__*/_curry2(function difference(first, second) {
+  var out = [];
+  var idx = 0;
+  var firstLen = first.length;
+  var secondLen = second.length;
+  var toFilterOut = new _Set();
+
+  for (var i = 0; i < secondLen; i += 1) {
+    toFilterOut.add(second[i]);
+  }
+
+  while (idx < firstLen) {
+    if (toFilterOut.add(first[idx])) {
+      out[out.length] = first[idx];
+    }
+    idx += 1;
+  }
+  return out;
+});
+module.exports = difference;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/differenceWith.js b/server/node_modules/ramda/src/differenceWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..0c2b9b4b1a6858a360e030073e4f015f75e17096
--- /dev/null
+++ b/server/node_modules/ramda/src/differenceWith.js
@@ -0,0 +1,41 @@
+var _includesWith = /*#__PURE__*/require('./internal/_includesWith');
+
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements in the first list not
+ * contained in the second list. Duplication is determined according to the
+ * value returned by applying the supplied predicate to two list elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig ((a, a) -> Boolean) -> [a] -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` that are not in `list2`.
+ * @see R.difference, R.symmetricDifference, R.symmetricDifferenceWith
+ * @example
+ *
+ *      const cmp = (x, y) => x.a === y.a;
+ *      const l1 = [{a: 1}, {a: 2}, {a: 3}];
+ *      const l2 = [{a: 3}, {a: 4}];
+ *      R.differenceWith(cmp, l1, l2); //=> [{a: 1}, {a: 2}]
+ */
+
+
+var differenceWith = /*#__PURE__*/_curry3(function differenceWith(pred, first, second) {
+  var out = [];
+  var idx = 0;
+  var firstLen = first.length;
+  while (idx < firstLen) {
+    if (!_includesWith(pred, first[idx], second) && !_includesWith(pred, first[idx], out)) {
+      out.push(first[idx]);
+    }
+    idx += 1;
+  }
+  return out;
+});
+module.exports = differenceWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/dissoc.js b/server/node_modules/ramda/src/dissoc.js
new file mode 100644
index 0000000000000000000000000000000000000000..361a06c0dbc7b266fcd736b15a35782abc6ba308
--- /dev/null
+++ b/server/node_modules/ramda/src/dissoc.js
@@ -0,0 +1,29 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns a new object that does not contain a `prop` property.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Object
+ * @sig String -> {k: v} -> {k: v}
+ * @param {String} prop The name of the property to dissociate
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object equivalent to the original but without the specified property
+ * @see R.assoc, R.omit
+ * @example
+ *
+ *      R.dissoc('b', {a: 1, b: 2, c: 3}); //=> {a: 1, c: 3}
+ */
+
+
+var dissoc = /*#__PURE__*/_curry2(function dissoc(prop, obj) {
+  var result = {};
+  for (var p in obj) {
+    result[p] = obj[p];
+  }
+  delete result[prop];
+  return result;
+});
+module.exports = dissoc;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/dissocPath.js b/server/node_modules/ramda/src/dissocPath.js
new file mode 100644
index 0000000000000000000000000000000000000000..f190d78d4c4c16bd8efe7befed471337466ee6da
--- /dev/null
+++ b/server/node_modules/ramda/src/dissocPath.js
@@ -0,0 +1,54 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _isInteger = /*#__PURE__*/require('./internal/_isInteger');
+
+var _isArray = /*#__PURE__*/require('./internal/_isArray');
+
+var assoc = /*#__PURE__*/require('./assoc');
+
+var dissoc = /*#__PURE__*/require('./dissoc');
+
+var remove = /*#__PURE__*/require('./remove');
+
+var update = /*#__PURE__*/require('./update');
+
+/**
+ * Makes a shallow clone of an object, omitting the property at the given path.
+ * Note that this copies and flattens prototype properties onto the new object
+ * as well. All non-primitive properties are copied by reference.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.11.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> {k: v} -> {k: v}
+ * @param {Array} path The path to the value to omit
+ * @param {Object} obj The object to clone
+ * @return {Object} A new object without the property at path
+ * @see R.assocPath
+ * @example
+ *
+ *      R.dissocPath(['a', 'b', 'c'], {a: {b: {c: 42}}}); //=> {a: {b: {}}}
+ */
+
+
+var dissocPath = /*#__PURE__*/_curry2(function dissocPath(path, obj) {
+  switch (path.length) {
+    case 0:
+      return obj;
+    case 1:
+      return _isInteger(path[0]) && _isArray(obj) ? remove(path[0], 1, obj) : dissoc(path[0], obj);
+    default:
+      var head = path[0];
+      var tail = Array.prototype.slice.call(path, 1);
+      if (obj[head] == null) {
+        return obj;
+      } else if (_isInteger(head) && _isArray(obj)) {
+        return update(head, dissocPath(tail, obj[head]), obj);
+      } else {
+        return assoc(head, dissocPath(tail, obj[head]), obj);
+      }
+  }
+});
+module.exports = dissocPath;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/divide.js b/server/node_modules/ramda/src/divide.js
new file mode 100644
index 0000000000000000000000000000000000000000..f330a9e2f96c6affcbca72f8e13bbbb602be7b9b
--- /dev/null
+++ b/server/node_modules/ramda/src/divide.js
@@ -0,0 +1,30 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Divides two numbers. Equivalent to `a / b`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The first value.
+ * @param {Number} b The second value.
+ * @return {Number} The result of `a / b`.
+ * @see R.multiply
+ * @example
+ *
+ *      R.divide(71, 100); //=> 0.71
+ *
+ *      const half = R.divide(R.__, 2);
+ *      half(42); //=> 21
+ *
+ *      const reciprocal = R.divide(1);
+ *      reciprocal(4);   //=> 0.25
+ */
+
+
+var divide = /*#__PURE__*/_curry2(function divide(a, b) {
+  return a / b;
+});
+module.exports = divide;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/drop.js b/server/node_modules/ramda/src/drop.js
new file mode 100644
index 0000000000000000000000000000000000000000..19b0f13a606280f6adf273f49832585262f6caba
--- /dev/null
+++ b/server/node_modules/ramda/src/drop.js
@@ -0,0 +1,38 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xdrop = /*#__PURE__*/require('./internal/_xdrop');
+
+var slice = /*#__PURE__*/require('./slice');
+
+/**
+ * Returns all but the first `n` elements of the given list, string, or
+ * transducer/transformer (or object with a `drop` method).
+ *
+ * Dispatches to the `drop` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n
+ * @param {*} list
+ * @return {*} A copy of list without the first `n` elements
+ * @see R.take, R.transduce, R.dropLast, R.dropWhile
+ * @example
+ *
+ *      R.drop(1, ['foo', 'bar', 'baz']); //=> ['bar', 'baz']
+ *      R.drop(2, ['foo', 'bar', 'baz']); //=> ['baz']
+ *      R.drop(3, ['foo', 'bar', 'baz']); //=> []
+ *      R.drop(4, ['foo', 'bar', 'baz']); //=> []
+ *      R.drop(3, 'ramda');               //=> 'da'
+ */
+
+
+var drop = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['drop'], _xdrop, function drop(n, xs) {
+  return slice(Math.max(0, n), Infinity, xs);
+}));
+module.exports = drop;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/dropLast.js b/server/node_modules/ramda/src/dropLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..3a31e995e1fb3136467aca8479d6582e85c926cc
--- /dev/null
+++ b/server/node_modules/ramda/src/dropLast.js
@@ -0,0 +1,35 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _dropLast = /*#__PURE__*/require('./internal/_dropLast');
+
+var _xdropLast = /*#__PURE__*/require('./internal/_xdropLast');
+
+/**
+ * Returns a list containing all but the last `n` elements of the given `list`.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n The number of elements of `list` to skip.
+ * @param {Array} list The list of elements to consider.
+ * @return {Array} A copy of the list with only the first `list.length - n` elements
+ * @see R.takeLast, R.drop, R.dropWhile, R.dropLastWhile
+ * @example
+ *
+ *      R.dropLast(1, ['foo', 'bar', 'baz']); //=> ['foo', 'bar']
+ *      R.dropLast(2, ['foo', 'bar', 'baz']); //=> ['foo']
+ *      R.dropLast(3, ['foo', 'bar', 'baz']); //=> []
+ *      R.dropLast(4, ['foo', 'bar', 'baz']); //=> []
+ *      R.dropLast(3, 'ramda');               //=> 'ra'
+ */
+
+
+var dropLast = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xdropLast, _dropLast));
+module.exports = dropLast;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/dropLastWhile.js b/server/node_modules/ramda/src/dropLastWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..3a6864adc82434fcb14ae95d5bc18d2f69e8354f
--- /dev/null
+++ b/server/node_modules/ramda/src/dropLastWhile.js
@@ -0,0 +1,39 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _dropLastWhile = /*#__PURE__*/require('./internal/_dropLastWhile');
+
+var _xdropLastWhile = /*#__PURE__*/require('./internal/_xdropLastWhile');
+
+/**
+ * Returns a new list excluding all the tailing elements of a given list which
+ * satisfy the supplied predicate function. It passes each value from the right
+ * to the supplied predicate function, skipping elements until the predicate
+ * function returns a `falsy` value. The predicate function is applied to one argument:
+ * *(value)*.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} predicate The function to be called on each element
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array without any trailing elements that return `falsy` values from the `predicate`.
+ * @see R.takeLastWhile, R.addIndex, R.drop, R.dropWhile
+ * @example
+ *
+ *      const lteThree = x => x <= 3;
+ *
+ *      R.dropLastWhile(lteThree, [1, 2, 3, 4, 3, 2, 1]); //=> [1, 2, 3, 4]
+ *
+ *      R.dropLastWhile(x => x !== 'd' , 'Ramda'); //=> 'Ramd'
+ */
+
+
+var dropLastWhile = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xdropLastWhile, _dropLastWhile));
+module.exports = dropLastWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/dropRepeats.js b/server/node_modules/ramda/src/dropRepeats.js
new file mode 100644
index 0000000000000000000000000000000000000000..427f8f47f8bd959b53e471c36ece633df9f1c0a1
--- /dev/null
+++ b/server/node_modules/ramda/src/dropRepeats.js
@@ -0,0 +1,32 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xdropRepeatsWith = /*#__PURE__*/require('./internal/_xdropRepeatsWith');
+
+var dropRepeatsWith = /*#__PURE__*/require('./dropRepeatsWith');
+
+var equals = /*#__PURE__*/require('./equals');
+
+/**
+ * Returns a new list without any consecutively repeating elements.
+ * [`R.equals`](#equals) is used to determine equality.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig [a] -> [a]
+ * @param {Array} list The array to consider.
+ * @return {Array} `list` without repeating elements.
+ * @see R.transduce
+ * @example
+ *
+ *     R.dropRepeats([1, 1, 1, 2, 3, 4, 4, 2, 2]); //=> [1, 2, 3, 4, 2]
+ */
+
+
+var dropRepeats = /*#__PURE__*/_curry1( /*#__PURE__*/_dispatchable([], /*#__PURE__*/_xdropRepeatsWith(equals), /*#__PURE__*/dropRepeatsWith(equals)));
+module.exports = dropRepeats;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/dropRepeatsWith.js b/server/node_modules/ramda/src/dropRepeatsWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..9e1a1eca2510071ffdea62ad7b8ae14de0178ff8
--- /dev/null
+++ b/server/node_modules/ramda/src/dropRepeatsWith.js
@@ -0,0 +1,47 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xdropRepeatsWith = /*#__PURE__*/require('./internal/_xdropRepeatsWith');
+
+var last = /*#__PURE__*/require('./last');
+
+/**
+ * Returns a new list without any consecutively repeating elements. Equality is
+ * determined by applying the supplied predicate to each pair of consecutive elements. The
+ * first element in a series of equal elements will be preserved.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig ((a, a) -> Boolean) -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list The array to consider.
+ * @return {Array} `list` without repeating elements.
+ * @see R.transduce
+ * @example
+ *
+ *      const l = [1, -1, 1, 3, 4, -4, -4, -5, 5, 3, 3];
+ *      R.dropRepeatsWith(R.eqBy(Math.abs), l); //=> [1, 3, 4, -5, 3]
+ */
+
+
+var dropRepeatsWith = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xdropRepeatsWith, function dropRepeatsWith(pred, list) {
+  var result = [];
+  var idx = 1;
+  var len = list.length;
+  if (len !== 0) {
+    result[0] = list[0];
+    while (idx < len) {
+      if (!pred(last(result), list[idx])) {
+        result[result.length] = list[idx];
+      }
+      idx += 1;
+    }
+  }
+  return result;
+}));
+module.exports = dropRepeatsWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/dropWhile.js b/server/node_modules/ramda/src/dropWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..f7b4775e4d68b93ccc387883c7459ce353421dd8
--- /dev/null
+++ b/server/node_modules/ramda/src/dropWhile.js
@@ -0,0 +1,47 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xdropWhile = /*#__PURE__*/require('./internal/_xdropWhile');
+
+var slice = /*#__PURE__*/require('./slice');
+
+/**
+ * Returns a new list excluding the leading elements of a given list which
+ * satisfy the supplied predicate function. It passes each value to the supplied
+ * predicate function, skipping elements while the predicate function returns
+ * `true`. The predicate function is applied to one argument: *(value)*.
+ *
+ * Dispatches to the `dropWhile` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} fn The function called per iteration.
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array.
+ * @see R.takeWhile, R.transduce, R.addIndex
+ * @example
+ *
+ *      const lteTwo = x => x <= 2;
+ *
+ *      R.dropWhile(lteTwo, [1, 2, 3, 4, 3, 2, 1]); //=> [3, 4, 3, 2, 1]
+ *
+ *      R.dropWhile(x => x !== 'd' , 'Ramda'); //=> 'da'
+ */
+
+
+var dropWhile = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['dropWhile'], _xdropWhile, function dropWhile(pred, xs) {
+  var idx = 0;
+  var len = xs.length;
+  while (idx < len && pred(xs[idx])) {
+    idx += 1;
+  }
+  return slice(idx, Infinity, xs);
+}));
+module.exports = dropWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/either.js b/server/node_modules/ramda/src/either.js
new file mode 100644
index 0000000000000000000000000000000000000000..28c4155e524ad7686c9525217aa7b170635bca2b
--- /dev/null
+++ b/server/node_modules/ramda/src/either.js
@@ -0,0 +1,46 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _isFunction = /*#__PURE__*/require('./internal/_isFunction');
+
+var lift = /*#__PURE__*/require('./lift');
+
+var or = /*#__PURE__*/require('./or');
+
+/**
+ * A function wrapping calls to the two functions in an `||` operation,
+ * returning the result of the first function if it is truth-y and the result
+ * of the second function otherwise. Note that this is short-circuited,
+ * meaning that the second function will not be invoked if the first returns a
+ * truth-y value.
+ *
+ * In addition to functions, `R.either` also accepts any fantasy-land compatible
+ * applicative functor.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category Logic
+ * @sig (*... -> Boolean) -> (*... -> Boolean) -> (*... -> Boolean)
+ * @param {Function} f a predicate
+ * @param {Function} g another predicate
+ * @return {Function} a function that applies its arguments to `f` and `g` and `||`s their outputs together.
+ * @see R.or
+ * @example
+ *
+ *      const gt10 = x => x > 10;
+ *      const even = x => x % 2 === 0;
+ *      const f = R.either(gt10, even);
+ *      f(101); //=> true
+ *      f(8); //=> true
+ *
+ *      R.either(Maybe.Just(false), Maybe.Just(55)); // => Maybe.Just(55)
+ *      R.either([false, false, 'a'], [11]) // => [11, 11, "a"]
+ */
+
+
+var either = /*#__PURE__*/_curry2(function either(f, g) {
+  return _isFunction(f) ? function _either() {
+    return f.apply(this, arguments) || g.apply(this, arguments);
+  } : lift(or)(f, g);
+});
+module.exports = either;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/empty.js b/server/node_modules/ramda/src/empty.js
new file mode 100644
index 0000000000000000000000000000000000000000..3612aa5533c5d4c0a50f54f3d0c17fc231fb3db4
--- /dev/null
+++ b/server/node_modules/ramda/src/empty.js
@@ -0,0 +1,42 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _isArguments = /*#__PURE__*/require('./internal/_isArguments');
+
+var _isArray = /*#__PURE__*/require('./internal/_isArray');
+
+var _isObject = /*#__PURE__*/require('./internal/_isObject');
+
+var _isString = /*#__PURE__*/require('./internal/_isString');
+
+/**
+ * Returns the empty value of its argument's type. Ramda defines the empty
+ * value of Array (`[]`), Object (`{}`), String (`''`), and Arguments. Other
+ * types are supported if they define `<Type>.empty`,
+ * `<Type>.prototype.empty` or implement the
+ * [FantasyLand Monoid spec](https://github.com/fantasyland/fantasy-land#monoid).
+ *
+ * Dispatches to the `empty` method of the first argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Function
+ * @sig a -> a
+ * @param {*} x
+ * @return {*}
+ * @example
+ *
+ *      R.empty(Just(42));      //=> Nothing()
+ *      R.empty([1, 2, 3]);     //=> []
+ *      R.empty('unicorns');    //=> ''
+ *      R.empty({x: 1, y: 2});  //=> {}
+ */
+
+
+var empty = /*#__PURE__*/_curry1(function empty(x) {
+  return x != null && typeof x['fantasy-land/empty'] === 'function' ? x['fantasy-land/empty']() : x != null && x.constructor != null && typeof x.constructor['fantasy-land/empty'] === 'function' ? x.constructor['fantasy-land/empty']() : x != null && typeof x.empty === 'function' ? x.empty() : x != null && x.constructor != null && typeof x.constructor.empty === 'function' ? x.constructor.empty() : _isArray(x) ? [] : _isString(x) ? '' : _isObject(x) ? {} : _isArguments(x) ? function () {
+    return arguments;
+  }() : void 0 // else
+  ;
+});
+module.exports = empty;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/endsWith.js b/server/node_modules/ramda/src/endsWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..57289de0b639ebd72240504b9f6616180de393e0
--- /dev/null
+++ b/server/node_modules/ramda/src/endsWith.js
@@ -0,0 +1,34 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var equals = /*#__PURE__*/require('./equals');
+
+var takeLast = /*#__PURE__*/require('./takeLast');
+
+/**
+ * Checks if a list ends with the provided sublist.
+ *
+ * Similarly, checks if a string ends with the provided substring.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category List
+ * @sig [a] -> [a] -> Boolean
+ * @sig String -> String -> Boolean
+ * @param {*} suffix
+ * @param {*} list
+ * @return {Boolean}
+ * @see R.startsWith
+ * @example
+ *
+ *      R.endsWith('c', 'abc')                //=> true
+ *      R.endsWith('b', 'abc')                //=> false
+ *      R.endsWith(['c'], ['a', 'b', 'c'])    //=> true
+ *      R.endsWith(['b'], ['a', 'b', 'c'])    //=> false
+ */
+
+
+var endsWith = /*#__PURE__*/_curry2(function (suffix, list) {
+  return equals(takeLast(suffix.length, list), suffix);
+});
+module.exports = endsWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/eqBy.js b/server/node_modules/ramda/src/eqBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..be5fdffd890c9b10e64acd822f0037f8ac964a49
--- /dev/null
+++ b/server/node_modules/ramda/src/eqBy.js
@@ -0,0 +1,27 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var equals = /*#__PURE__*/require('./equals');
+
+/**
+ * Takes a function and two values in its domain and returns `true` if the
+ * values map to the same value in the codomain; `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Relation
+ * @sig (a -> b) -> a -> a -> Boolean
+ * @param {Function} f
+ * @param {*} x
+ * @param {*} y
+ * @return {Boolean}
+ * @example
+ *
+ *      R.eqBy(Math.abs, 5, -5); //=> true
+ */
+
+
+var eqBy = /*#__PURE__*/_curry3(function eqBy(f, x, y) {
+  return equals(f(x), f(y));
+});
+module.exports = eqBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/eqProps.js b/server/node_modules/ramda/src/eqProps.js
new file mode 100644
index 0000000000000000000000000000000000000000..6f674a950a2217e7ed351cd4f7fd580e6e7590ee
--- /dev/null
+++ b/server/node_modules/ramda/src/eqProps.js
@@ -0,0 +1,31 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var equals = /*#__PURE__*/require('./equals');
+
+/**
+ * Reports whether two objects have the same value, in [`R.equals`](#equals)
+ * terms, for the specified property. Useful as a curried predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig k -> {k: v} -> {k: v} -> Boolean
+ * @param {String} prop The name of the property to compare
+ * @param {Object} obj1
+ * @param {Object} obj2
+ * @return {Boolean}
+ *
+ * @example
+ *
+ *      const o1 = { a: 1, b: 2, c: 3, d: 4 };
+ *      const o2 = { a: 10, b: 20, c: 3, d: 40 };
+ *      R.eqProps('a', o1, o2); //=> false
+ *      R.eqProps('c', o1, o2); //=> true
+ */
+
+
+var eqProps = /*#__PURE__*/_curry3(function eqProps(prop, obj1, obj2) {
+  return equals(obj1[prop], obj2[prop]);
+});
+module.exports = eqProps;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/equals.js b/server/node_modules/ramda/src/equals.js
new file mode 100644
index 0000000000000000000000000000000000000000..98522fdd4caf4019934d76e5602ac3b88e6ec101
--- /dev/null
+++ b/server/node_modules/ramda/src/equals.js
@@ -0,0 +1,35 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _equals = /*#__PURE__*/require('./internal/_equals');
+
+/**
+ * Returns `true` if its arguments are equivalent, `false` otherwise. Handles
+ * cyclical data structures.
+ *
+ * Dispatches symmetrically to the `equals` methods of both arguments, if
+ * present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category Relation
+ * @sig a -> b -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @example
+ *
+ *      R.equals(1, 1); //=> true
+ *      R.equals(1, '1'); //=> false
+ *      R.equals([1, 2, 3], [1, 2, 3]); //=> true
+ *
+ *      const a = {}; a.v = a;
+ *      const b = {}; b.v = b;
+ *      R.equals(a, b); //=> true
+ */
+
+
+var equals = /*#__PURE__*/_curry2(function equals(a, b) {
+  return _equals(a, b, [], []);
+});
+module.exports = equals;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/evolve.js b/server/node_modules/ramda/src/evolve.js
new file mode 100644
index 0000000000000000000000000000000000000000..09dd2204abc6d9f3f5ffc8450e906cc28ba69de0
--- /dev/null
+++ b/server/node_modules/ramda/src/evolve.js
@@ -0,0 +1,42 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Creates a new object by recursively evolving a shallow copy of `object`,
+ * according to the `transformation` functions. All non-primitive properties
+ * are copied by reference.
+ *
+ * A `transformation` function will not be invoked if its corresponding key
+ * does not exist in the evolved object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig {k: (v -> v)} -> {k: v} -> {k: v}
+ * @param {Object} transformations The object specifying transformation functions to apply
+ *        to the object.
+ * @param {Object} object The object to be transformed.
+ * @return {Object} The transformed object.
+ * @example
+ *
+ *      const tomato = {firstName: '  Tomato ', data: {elapsed: 100, remaining: 1400}, id:123};
+ *      const transformations = {
+ *        firstName: R.trim,
+ *        lastName: R.trim, // Will not get invoked.
+ *        data: {elapsed: R.add(1), remaining: R.add(-1)}
+ *      };
+ *      R.evolve(transformations, tomato); //=> {firstName: 'Tomato', data: {elapsed: 101, remaining: 1399}, id:123}
+ */
+
+
+var evolve = /*#__PURE__*/_curry2(function evolve(transformations, object) {
+  var result = object instanceof Array ? [] : {};
+  var transformation, key, type;
+  for (key in object) {
+    transformation = transformations[key];
+    type = typeof transformation;
+    result[key] = type === 'function' ? transformation(object[key]) : transformation && type === 'object' ? evolve(transformation, object[key]) : object[key];
+  }
+  return result;
+});
+module.exports = evolve;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/filter.js b/server/node_modules/ramda/src/filter.js
new file mode 100644
index 0000000000000000000000000000000000000000..5d796e4f395e0446cda8fe5e20ced229ef11cc65
--- /dev/null
+++ b/server/node_modules/ramda/src/filter.js
@@ -0,0 +1,54 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _filter = /*#__PURE__*/require('./internal/_filter');
+
+var _isObject = /*#__PURE__*/require('./internal/_isObject');
+
+var _reduce = /*#__PURE__*/require('./internal/_reduce');
+
+var _xfilter = /*#__PURE__*/require('./internal/_xfilter');
+
+var keys = /*#__PURE__*/require('./keys');
+
+/**
+ * Takes a predicate and a `Filterable`, and returns a new filterable of the
+ * same type containing the members of the given filterable which satisfy the
+ * given predicate. Filterable objects include plain objects or any object
+ * that has a filter method such as `Array`.
+ *
+ * Dispatches to the `filter` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Filterable f => (a -> Boolean) -> f a -> f a
+ * @param {Function} pred
+ * @param {Array} filterable
+ * @return {Array} Filterable
+ * @see R.reject, R.transduce, R.addIndex
+ * @example
+ *
+ *      const isEven = n => n % 2 === 0;
+ *
+ *      R.filter(isEven, [1, 2, 3, 4]); //=> [2, 4]
+ *
+ *      R.filter(isEven, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4}
+ */
+
+
+var filter = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['filter'], _xfilter, function (pred, filterable) {
+  return _isObject(filterable) ? _reduce(function (acc, key) {
+    if (pred(filterable[key])) {
+      acc[key] = filterable[key];
+    }
+    return acc;
+  }, {}, keys(filterable)) :
+  // else
+  _filter(pred, filterable);
+}));
+module.exports = filter;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/find.js b/server/node_modules/ramda/src/find.js
new file mode 100644
index 0000000000000000000000000000000000000000..20c5290405b27efc479643264c341dda271a5d29
--- /dev/null
+++ b/server/node_modules/ramda/src/find.js
@@ -0,0 +1,43 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xfind = /*#__PURE__*/require('./internal/_xfind');
+
+/**
+ * Returns the first element of the list which matches the predicate, or
+ * `undefined` if no element matches.
+ *
+ * Dispatches to the `find` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> a | undefined
+ * @param {Function} fn The predicate function used to determine if the element is the
+ *        desired one.
+ * @param {Array} list The array to consider.
+ * @return {Object} The element found, or `undefined`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1}, {a: 2}, {a: 3}];
+ *      R.find(R.propEq('a', 2))(xs); //=> {a: 2}
+ *      R.find(R.propEq('a', 4))(xs); //=> undefined
+ */
+
+
+var find = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['find'], _xfind, function find(fn, list) {
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    if (fn(list[idx])) {
+      return list[idx];
+    }
+    idx += 1;
+  }
+}));
+module.exports = find;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/findIndex.js b/server/node_modules/ramda/src/findIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..6ec2d2e1b8ff430c72de9db33b46eef9d99901a7
--- /dev/null
+++ b/server/node_modules/ramda/src/findIndex.js
@@ -0,0 +1,42 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xfindIndex = /*#__PURE__*/require('./internal/_xfindIndex');
+
+/**
+ * Returns the index of the first element of the list which matches the
+ * predicate, or `-1` if no element matches.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Number
+ * @param {Function} fn The predicate function used to determine if the element is the
+ * desired one.
+ * @param {Array} list The array to consider.
+ * @return {Number} The index of the element found, or `-1`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1}, {a: 2}, {a: 3}];
+ *      R.findIndex(R.propEq('a', 2))(xs); //=> 1
+ *      R.findIndex(R.propEq('a', 4))(xs); //=> -1
+ */
+
+
+var findIndex = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xfindIndex, function findIndex(fn, list) {
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    if (fn(list[idx])) {
+      return idx;
+    }
+    idx += 1;
+  }
+  return -1;
+}));
+module.exports = findIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/findLast.js b/server/node_modules/ramda/src/findLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..5fc63f077ab8145c7520adcd6f0c5348f46e2898
--- /dev/null
+++ b/server/node_modules/ramda/src/findLast.js
@@ -0,0 +1,40 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xfindLast = /*#__PURE__*/require('./internal/_xfindLast');
+
+/**
+ * Returns the last element of the list which matches the predicate, or
+ * `undefined` if no element matches.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> a | undefined
+ * @param {Function} fn The predicate function used to determine if the element is the
+ * desired one.
+ * @param {Array} list The array to consider.
+ * @return {Object} The element found, or `undefined`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1, b: 0}, {a:1, b: 1}];
+ *      R.findLast(R.propEq('a', 1))(xs); //=> {a: 1, b: 1}
+ *      R.findLast(R.propEq('a', 4))(xs); //=> undefined
+ */
+
+
+var findLast = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xfindLast, function findLast(fn, list) {
+  var idx = list.length - 1;
+  while (idx >= 0) {
+    if (fn(list[idx])) {
+      return list[idx];
+    }
+    idx -= 1;
+  }
+}));
+module.exports = findLast;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/findLastIndex.js b/server/node_modules/ramda/src/findLastIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..4edbf7fc56a21f1e389d7283e51fc876b79edc29
--- /dev/null
+++ b/server/node_modules/ramda/src/findLastIndex.js
@@ -0,0 +1,41 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xfindLastIndex = /*#__PURE__*/require('./internal/_xfindLastIndex');
+
+/**
+ * Returns the index of the last element of the list which matches the
+ * predicate, or `-1` if no element matches.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Number
+ * @param {Function} fn The predicate function used to determine if the element is the
+ * desired one.
+ * @param {Array} list The array to consider.
+ * @return {Number} The index of the element found, or `-1`.
+ * @see R.transduce
+ * @example
+ *
+ *      const xs = [{a: 1, b: 0}, {a:1, b: 1}];
+ *      R.findLastIndex(R.propEq('a', 1))(xs); //=> 1
+ *      R.findLastIndex(R.propEq('a', 4))(xs); //=> -1
+ */
+
+
+var findLastIndex = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xfindLastIndex, function findLastIndex(fn, list) {
+  var idx = list.length - 1;
+  while (idx >= 0) {
+    if (fn(list[idx])) {
+      return idx;
+    }
+    idx -= 1;
+  }
+  return -1;
+}));
+module.exports = findLastIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/flatten.js b/server/node_modules/ramda/src/flatten.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac148daa60c3af5efd0aedcac92355572c0e894c
--- /dev/null
+++ b/server/node_modules/ramda/src/flatten.js
@@ -0,0 +1,25 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _makeFlat = /*#__PURE__*/require('./internal/_makeFlat');
+
+/**
+ * Returns a new list by pulling every item out of it (and all its sub-arrays)
+ * and putting them in a new array, depth-first.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [b]
+ * @param {Array} list The array to consider.
+ * @return {Array} The flattened list.
+ * @see R.unnest
+ * @example
+ *
+ *      R.flatten([1, 2, [3, 4], 5, [6, [7, 8, [9, [10, 11], 12]]]]);
+ *      //=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+ */
+
+
+var flatten = /*#__PURE__*/_curry1( /*#__PURE__*/_makeFlat(true));
+module.exports = flatten;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/flip.js b/server/node_modules/ramda/src/flip.js
new file mode 100644
index 0000000000000000000000000000000000000000..ffb1cca93f8b16d996a5bb703f95229891563045
--- /dev/null
+++ b/server/node_modules/ramda/src/flip.js
@@ -0,0 +1,35 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+/**
+ * Returns a new function much like the supplied one, except that the first two
+ * arguments' order is reversed.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((a, b, c, ...) -> z) -> (b -> a -> c -> ... -> z)
+ * @param {Function} fn The function to invoke with its first two parameters reversed.
+ * @return {*} The result of invoking `fn` with its first two parameters' order reversed.
+ * @example
+ *
+ *      const mergeThree = (a, b, c) => [].concat(a, b, c);
+ *
+ *      mergeThree(1, 2, 3); //=> [1, 2, 3]
+ *
+ *      R.flip(mergeThree)(1, 2, 3); //=> [2, 1, 3]
+ * @symb R.flip(f)(a, b, c) = f(b, a, c)
+ */
+
+
+var flip = /*#__PURE__*/_curry1(function flip(fn) {
+  return curryN(fn.length, function (a, b) {
+    var args = Array.prototype.slice.call(arguments, 0);
+    args[0] = b;
+    args[1] = a;
+    return fn.apply(this, args);
+  });
+});
+module.exports = flip;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/forEach.js b/server/node_modules/ramda/src/forEach.js
new file mode 100644
index 0000000000000000000000000000000000000000..07f67a1eb443902aafb4a5b5e0aba22d925d8f7d
--- /dev/null
+++ b/server/node_modules/ramda/src/forEach.js
@@ -0,0 +1,50 @@
+var _checkForMethod = /*#__PURE__*/require('./internal/_checkForMethod');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Iterate over an input `list`, calling a provided function `fn` for each
+ * element in the list.
+ *
+ * `fn` receives one argument: *(value)*.
+ *
+ * Note: `R.forEach` does not skip deleted or unassigned indices (sparse
+ * arrays), unlike the native `Array.prototype.forEach` method. For more
+ * details on this behavior, see:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description
+ *
+ * Also note that, unlike `Array.prototype.forEach`, Ramda's `forEach` returns
+ * the original array. In some libraries this function is named `each`.
+ *
+ * Dispatches to the `forEach` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig (a -> *) -> [a] -> [a]
+ * @param {Function} fn The function to invoke. Receives one argument, `value`.
+ * @param {Array} list The list to iterate over.
+ * @return {Array} The original list.
+ * @see R.addIndex
+ * @example
+ *
+ *      const printXPlusFive = x => console.log(x + 5);
+ *      R.forEach(printXPlusFive, [1, 2, 3]); //=> [1, 2, 3]
+ *      // logs 6
+ *      // logs 7
+ *      // logs 8
+ * @symb R.forEach(f, [a, b, c]) = [a, b, c]
+ */
+
+
+var forEach = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('forEach', function forEach(fn, list) {
+  var len = list.length;
+  var idx = 0;
+  while (idx < len) {
+    fn(list[idx]);
+    idx += 1;
+  }
+  return list;
+}));
+module.exports = forEach;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/forEachObjIndexed.js b/server/node_modules/ramda/src/forEachObjIndexed.js
new file mode 100644
index 0000000000000000000000000000000000000000..c12e355a1714b6af59ec245ee93017d6b21b402c
--- /dev/null
+++ b/server/node_modules/ramda/src/forEachObjIndexed.js
@@ -0,0 +1,39 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var keys = /*#__PURE__*/require('./keys');
+
+/**
+ * Iterate over an input `object`, calling a provided function `fn` for each
+ * key and value in the object.
+ *
+ * `fn` receives three argument: *(value, key, obj)*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Object
+ * @sig ((a, String, StrMap a) -> Any) -> StrMap a -> StrMap a
+ * @param {Function} fn The function to invoke. Receives three argument, `value`, `key`, `obj`.
+ * @param {Object} obj The object to iterate over.
+ * @return {Object} The original object.
+ * @example
+ *
+ *      const printKeyConcatValue = (value, key) => console.log(key + ':' + value);
+ *      R.forEachObjIndexed(printKeyConcatValue, {x: 1, y: 2}); //=> {x: 1, y: 2}
+ *      // logs x:1
+ *      // logs y:2
+ * @symb R.forEachObjIndexed(f, {x: a, y: b}) = {x: a, y: b}
+ */
+
+
+var forEachObjIndexed = /*#__PURE__*/_curry2(function forEachObjIndexed(fn, obj) {
+  var keyList = keys(obj);
+  var idx = 0;
+  while (idx < keyList.length) {
+    var key = keyList[idx];
+    fn(obj[key], key, obj);
+    idx += 1;
+  }
+  return obj;
+});
+module.exports = forEachObjIndexed;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/fromPairs.js b/server/node_modules/ramda/src/fromPairs.js
new file mode 100644
index 0000000000000000000000000000000000000000..1d8767e97ead18f763c217bcff96df0fc665ce94
--- /dev/null
+++ b/server/node_modules/ramda/src/fromPairs.js
@@ -0,0 +1,30 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Creates a new object from a list key-value pairs. If a key appears in
+ * multiple pairs, the rightmost pair is included in the object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig [[k,v]] -> {k: v}
+ * @param {Array} pairs An array of two-element arrays that will be the keys and values of the output object.
+ * @return {Object} The object made by pairing up `keys` and `values`.
+ * @see R.toPairs, R.pair
+ * @example
+ *
+ *      R.fromPairs([['a', 1], ['b', 2], ['c', 3]]); //=> {a: 1, b: 2, c: 3}
+ */
+
+
+var fromPairs = /*#__PURE__*/_curry1(function fromPairs(pairs) {
+  var result = {};
+  var idx = 0;
+  while (idx < pairs.length) {
+    result[pairs[idx][0]] = pairs[idx][1];
+    idx += 1;
+  }
+  return result;
+});
+module.exports = fromPairs;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/groupBy.js b/server/node_modules/ramda/src/groupBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..070c867e05d0c3b98a678d50d959a885e9aa5fd1
--- /dev/null
+++ b/server/node_modules/ramda/src/groupBy.js
@@ -0,0 +1,56 @@
+var _checkForMethod = /*#__PURE__*/require('./internal/_checkForMethod');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var reduceBy = /*#__PURE__*/require('./reduceBy');
+
+/**
+ * Splits a list into sub-lists stored in an object, based on the result of
+ * calling a String-returning function on each element, and grouping the
+ * results according to values returned.
+ *
+ * Dispatches to the `groupBy` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> String) -> [a] -> {String: [a]}
+ * @param {Function} fn Function :: a -> String
+ * @param {Array} list The array to group
+ * @return {Object} An object with the output of `fn` for keys, mapped to arrays of elements
+ *         that produced that key when passed to `fn`.
+ * @see R.reduceBy, R.transduce
+ * @example
+ *
+ *      const byGrade = R.groupBy(function(student) {
+ *        const score = student.score;
+ *        return score < 65 ? 'F' :
+ *               score < 70 ? 'D' :
+ *               score < 80 ? 'C' :
+ *               score < 90 ? 'B' : 'A';
+ *      });
+ *      const students = [{name: 'Abby', score: 84},
+ *                      {name: 'Eddy', score: 58},
+ *                      // ...
+ *                      {name: 'Jack', score: 69}];
+ *      byGrade(students);
+ *      // {
+ *      //   'A': [{name: 'Dianne', score: 99}],
+ *      //   'B': [{name: 'Abby', score: 84}]
+ *      //   // ...,
+ *      //   'F': [{name: 'Eddy', score: 58}]
+ *      // }
+ */
+
+
+var groupBy = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('groupBy', /*#__PURE__*/reduceBy(function (acc, item) {
+  if (acc == null) {
+    acc = [];
+  }
+  acc.push(item);
+  return acc;
+}, null)));
+module.exports = groupBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/groupWith.js b/server/node_modules/ramda/src/groupWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..5aefbe1ff77fde1a7de9642fe8a6d429d39c94d8
--- /dev/null
+++ b/server/node_modules/ramda/src/groupWith.js
@@ -0,0 +1,49 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Takes a list and returns a list of lists where each sublist's elements are
+ * all satisfied pairwise comparison according to the provided function.
+ * Only adjacent elements are passed to the comparison function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.21.0
+ * @category List
+ * @sig ((a, a) → Boolean) → [a] → [[a]]
+ * @param {Function} fn Function for determining whether two given (adjacent)
+ *        elements should be in the same group
+ * @param {Array} list The array to group. Also accepts a string, which will be
+ *        treated as a list of characters.
+ * @return {List} A list that contains sublists of elements,
+ *         whose concatenations are equal to the original list.
+ * @example
+ *
+ * R.groupWith(R.equals, [0, 1, 1, 2, 3, 5, 8, 13, 21])
+ * //=> [[0], [1, 1], [2], [3], [5], [8], [13], [21]]
+ *
+ * R.groupWith((a, b) => a + 1 === b, [0, 1, 1, 2, 3, 5, 8, 13, 21])
+ * //=> [[0, 1], [1, 2, 3], [5], [8], [13], [21]]
+ *
+ * R.groupWith((a, b) => a % 2 === b % 2, [0, 1, 1, 2, 3, 5, 8, 13, 21])
+ * //=> [[0], [1, 1], [2], [3, 5], [8], [13, 21]]
+ *
+ * R.groupWith(R.eqBy(isVowel), 'aestiou')
+ * //=> ['ae', 'st', 'iou']
+ */
+
+
+var groupWith = /*#__PURE__*/_curry2(function (fn, list) {
+  var res = [];
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    var nextidx = idx + 1;
+    while (nextidx < len && fn(list[nextidx - 1], list[nextidx])) {
+      nextidx += 1;
+    }
+    res.push(list.slice(idx, nextidx));
+    idx = nextidx;
+  }
+  return res;
+});
+module.exports = groupWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/gt.js b/server/node_modules/ramda/src/gt.js
new file mode 100644
index 0000000000000000000000000000000000000000..ce788502c929cb4441d7ff662b1ec0843328ebb6
--- /dev/null
+++ b/server/node_modules/ramda/src/gt.js
@@ -0,0 +1,29 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns `true` if the first argument is greater than the second; `false`
+ * otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @see R.lt
+ * @example
+ *
+ *      R.gt(2, 1); //=> true
+ *      R.gt(2, 2); //=> false
+ *      R.gt(2, 3); //=> false
+ *      R.gt('a', 'z'); //=> false
+ *      R.gt('z', 'a'); //=> true
+ */
+
+
+var gt = /*#__PURE__*/_curry2(function gt(a, b) {
+  return a > b;
+});
+module.exports = gt;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/gte.js b/server/node_modules/ramda/src/gte.js
new file mode 100644
index 0000000000000000000000000000000000000000..4ef2178d6aa3abea5740cd76a19fb36b90641572
--- /dev/null
+++ b/server/node_modules/ramda/src/gte.js
@@ -0,0 +1,29 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns `true` if the first argument is greater than or equal to the second;
+ * `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {Number} a
+ * @param {Number} b
+ * @return {Boolean}
+ * @see R.lte
+ * @example
+ *
+ *      R.gte(2, 1); //=> true
+ *      R.gte(2, 2); //=> true
+ *      R.gte(2, 3); //=> false
+ *      R.gte('a', 'z'); //=> false
+ *      R.gte('z', 'a'); //=> true
+ */
+
+
+var gte = /*#__PURE__*/_curry2(function gte(a, b) {
+  return a >= b;
+});
+module.exports = gte;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/has.js b/server/node_modules/ramda/src/has.js
new file mode 100644
index 0000000000000000000000000000000000000000..fb86689f30b9d9361906bc781491539ce31c85d4
--- /dev/null
+++ b/server/node_modules/ramda/src/has.js
@@ -0,0 +1,34 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var hasPath = /*#__PURE__*/require('./hasPath');
+
+/**
+ * Returns whether or not an object has an own property with the specified name
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Object
+ * @sig s -> {s: x} -> Boolean
+ * @param {String} prop The name of the property to check for.
+ * @param {Object} obj The object to query.
+ * @return {Boolean} Whether the property exists.
+ * @example
+ *
+ *      const hasName = R.has('name');
+ *      hasName({name: 'alice'});   //=> true
+ *      hasName({name: 'bob'});     //=> true
+ *      hasName({});                //=> false
+ *
+ *      const point = {x: 0, y: 0};
+ *      const pointHas = R.has(R.__, point);
+ *      pointHas('x');  //=> true
+ *      pointHas('y');  //=> true
+ *      pointHas('z');  //=> false
+ */
+
+
+var has = /*#__PURE__*/_curry2(function has(prop, obj) {
+  return hasPath([prop], obj);
+});
+module.exports = has;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/hasIn.js b/server/node_modules/ramda/src/hasIn.js
new file mode 100644
index 0000000000000000000000000000000000000000..2eb7809f1d393768d2039684ee42b774b8d87a02
--- /dev/null
+++ b/server/node_modules/ramda/src/hasIn.js
@@ -0,0 +1,34 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns whether or not an object or its prototype chain has a property with
+ * the specified name
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Object
+ * @sig s -> {s: x} -> Boolean
+ * @param {String} prop The name of the property to check for.
+ * @param {Object} obj The object to query.
+ * @return {Boolean} Whether the property exists.
+ * @example
+ *
+ *      function Rectangle(width, height) {
+ *        this.width = width;
+ *        this.height = height;
+ *      }
+ *      Rectangle.prototype.area = function() {
+ *        return this.width * this.height;
+ *      };
+ *
+ *      const square = new Rectangle(2, 2);
+ *      R.hasIn('width', square);  //=> true
+ *      R.hasIn('area', square);  //=> true
+ */
+
+
+var hasIn = /*#__PURE__*/_curry2(function hasIn(prop, obj) {
+  return prop in obj;
+});
+module.exports = hasIn;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/hasPath.js b/server/node_modules/ramda/src/hasPath.js
new file mode 100644
index 0000000000000000000000000000000000000000..bbfd29034f6d5404c2268d38c251646cbc21671b
--- /dev/null
+++ b/server/node_modules/ramda/src/hasPath.js
@@ -0,0 +1,44 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _has = /*#__PURE__*/require('./internal/_has');
+
+/**
+ * Returns whether or not a path exists in an object. Only the object's
+ * own properties are checked.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.26.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> {a} -> Boolean
+ * @param {Array} path The path to use.
+ * @param {Object} obj The object to check the path in.
+ * @return {Boolean} Whether the path exists.
+ * @see R.has
+ * @example
+ *
+ *      R.hasPath(['a', 'b'], {a: {b: 2}});         // => true
+ *      R.hasPath(['a', 'b'], {a: {b: undefined}}); // => true
+ *      R.hasPath(['a', 'b'], {a: {c: 2}});         // => false
+ *      R.hasPath(['a', 'b'], {});                  // => false
+ */
+
+
+var hasPath = /*#__PURE__*/_curry2(function hasPath(_path, obj) {
+  if (_path.length === 0) {
+    return false;
+  }
+  var val = obj;
+  var idx = 0;
+  while (idx < _path.length) {
+    if (_has(_path[idx], val)) {
+      val = val[_path[idx]];
+      idx += 1;
+    } else {
+      return false;
+    }
+  }
+  return true;
+});
+module.exports = hasPath;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/head.js b/server/node_modules/ramda/src/head.js
new file mode 100644
index 0000000000000000000000000000000000000000..08655a1cb218f7a1af25a4170bab7ea7cdaba155
--- /dev/null
+++ b/server/node_modules/ramda/src/head.js
@@ -0,0 +1,27 @@
+var nth = /*#__PURE__*/require('./nth');
+
+/**
+ * Returns the first element of the given list or string. In some libraries
+ * this function is named `first`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> a | Undefined
+ * @sig String -> String
+ * @param {Array|String} list
+ * @return {*}
+ * @see R.tail, R.init, R.last
+ * @example
+ *
+ *      R.head(['fi', 'fo', 'fum']); //=> 'fi'
+ *      R.head([]); //=> undefined
+ *
+ *      R.head('abc'); //=> 'a'
+ *      R.head(''); //=> ''
+ */
+
+
+var head = /*#__PURE__*/nth(0);
+module.exports = head;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/identical.js b/server/node_modules/ramda/src/identical.js
new file mode 100644
index 0000000000000000000000000000000000000000..5af7162f2d2aa44130109529167a00a41789ef31
--- /dev/null
+++ b/server/node_modules/ramda/src/identical.js
@@ -0,0 +1,33 @@
+var _objectIs = /*#__PURE__*/require('./internal/_objectIs');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns true if its arguments are identical, false otherwise. Values are
+ * identical if they reference the same memory. `NaN` is identical to `NaN`;
+ * `0` and `-0` are not identical.
+ *
+ * Note this is merely a curried version of ES6 `Object.is`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category Relation
+ * @sig a -> a -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @example
+ *
+ *      const o = {};
+ *      R.identical(o, o); //=> true
+ *      R.identical(1, 1); //=> true
+ *      R.identical(1, '1'); //=> false
+ *      R.identical([], []); //=> false
+ *      R.identical(0, -0); //=> false
+ *      R.identical(NaN, NaN); //=> true
+ */
+
+
+var identical = /*#__PURE__*/_curry2(_objectIs);
+module.exports = identical;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/identity.js b/server/node_modules/ramda/src/identity.js
new file mode 100644
index 0000000000000000000000000000000000000000..365a4716f0032ce94a7c9998315508b800ade6a6
--- /dev/null
+++ b/server/node_modules/ramda/src/identity.js
@@ -0,0 +1,27 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _identity = /*#__PURE__*/require('./internal/_identity');
+
+/**
+ * A function that does nothing but return the parameter supplied to it. Good
+ * as a default or placeholder function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig a -> a
+ * @param {*} x The value to return.
+ * @return {*} The input value, `x`.
+ * @example
+ *
+ *      R.identity(1); //=> 1
+ *
+ *      const obj = {};
+ *      R.identity(obj) === obj; //=> true
+ * @symb R.identity(a) = a
+ */
+
+
+var identity = /*#__PURE__*/_curry1(_identity);
+module.exports = identity;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/ifElse.js b/server/node_modules/ramda/src/ifElse.js
new file mode 100644
index 0000000000000000000000000000000000000000..94e3208ad0b66499d5bee10b77db0a4c463e742c
--- /dev/null
+++ b/server/node_modules/ramda/src/ifElse.js
@@ -0,0 +1,37 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+/**
+ * Creates a function that will process either the `onTrue` or the `onFalse`
+ * function depending upon the result of the `condition` predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Logic
+ * @sig (*... -> Boolean) -> (*... -> *) -> (*... -> *) -> (*... -> *)
+ * @param {Function} condition A predicate function
+ * @param {Function} onTrue A function to invoke when the `condition` evaluates to a truthy value.
+ * @param {Function} onFalse A function to invoke when the `condition` evaluates to a falsy value.
+ * @return {Function} A new function that will process either the `onTrue` or the `onFalse`
+ *                    function depending upon the result of the `condition` predicate.
+ * @see R.unless, R.when, R.cond
+ * @example
+ *
+ *      const incCount = R.ifElse(
+ *        R.has('count'),
+ *        R.over(R.lensProp('count'), R.inc),
+ *        R.assoc('count', 1)
+ *      );
+ *      incCount({});           //=> { count: 1 }
+ *      incCount({ count: 1 }); //=> { count: 2 }
+ */
+
+
+var ifElse = /*#__PURE__*/_curry3(function ifElse(condition, onTrue, onFalse) {
+  return curryN(Math.max(condition.length, onTrue.length, onFalse.length), function _ifElse() {
+    return condition.apply(this, arguments) ? onTrue.apply(this, arguments) : onFalse.apply(this, arguments);
+  });
+});
+module.exports = ifElse;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/inc.js b/server/node_modules/ramda/src/inc.js
new file mode 100644
index 0000000000000000000000000000000000000000..0e4fdafe92597d926a1573adea86ea37654d0687
--- /dev/null
+++ b/server/node_modules/ramda/src/inc.js
@@ -0,0 +1,21 @@
+var add = /*#__PURE__*/require('./add');
+
+/**
+ * Increments its argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Math
+ * @sig Number -> Number
+ * @param {Number} n
+ * @return {Number} n + 1
+ * @see R.dec
+ * @example
+ *
+ *      R.inc(42); //=> 43
+ */
+
+
+var inc = /*#__PURE__*/add(1);
+module.exports = inc;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/includes.js b/server/node_modules/ramda/src/includes.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac4a3ff2c4b47be1bdf12f4dc6c3995250d071d2
--- /dev/null
+++ b/server/node_modules/ramda/src/includes.js
@@ -0,0 +1,30 @@
+var _includes = /*#__PURE__*/require('./internal/_includes');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns `true` if the specified value is equal, in [`R.equals`](#equals)
+ * terms, to at least one element of the given list; `false` otherwise.
+ * Works also with strings.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Boolean
+ * @param {Object} a The item to compare against.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if an equivalent item is in the list, `false` otherwise.
+ * @see R.any
+ * @example
+ *
+ *      R.includes(3, [1, 2, 3]); //=> true
+ *      R.includes(4, [1, 2, 3]); //=> false
+ *      R.includes({ name: 'Fred' }, [{ name: 'Fred' }]); //=> true
+ *      R.includes([42], [[42]]); //=> true
+ *      R.includes('ba', 'banana'); //=>true
+ */
+
+
+var includes = /*#__PURE__*/_curry2(_includes);
+module.exports = includes;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/index.js b/server/node_modules/ramda/src/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..08acf7f52a069e594354d4c9891ac8c07772c832
--- /dev/null
+++ b/server/node_modules/ramda/src/index.js
@@ -0,0 +1,256 @@
+module.exports = {};
+module.exports.F = /*#__PURE__*/require('./F');
+module.exports.T = /*#__PURE__*/require('./T');
+module.exports.__ = /*#__PURE__*/require('./__');
+module.exports.add = /*#__PURE__*/require('./add');
+module.exports.addIndex = /*#__PURE__*/require('./addIndex');
+module.exports.adjust = /*#__PURE__*/require('./adjust');
+module.exports.all = /*#__PURE__*/require('./all');
+module.exports.allPass = /*#__PURE__*/require('./allPass');
+module.exports.always = /*#__PURE__*/require('./always');
+module.exports.and = /*#__PURE__*/require('./and');
+module.exports.any = /*#__PURE__*/require('./any');
+module.exports.anyPass = /*#__PURE__*/require('./anyPass');
+module.exports.ap = /*#__PURE__*/require('./ap');
+module.exports.aperture = /*#__PURE__*/require('./aperture');
+module.exports.append = /*#__PURE__*/require('./append');
+module.exports.apply = /*#__PURE__*/require('./apply');
+module.exports.applySpec = /*#__PURE__*/require('./applySpec');
+module.exports.applyTo = /*#__PURE__*/require('./applyTo');
+module.exports.ascend = /*#__PURE__*/require('./ascend');
+module.exports.assoc = /*#__PURE__*/require('./assoc');
+module.exports.assocPath = /*#__PURE__*/require('./assocPath');
+module.exports.binary = /*#__PURE__*/require('./binary');
+module.exports.bind = /*#__PURE__*/require('./bind');
+module.exports.both = /*#__PURE__*/require('./both');
+module.exports.call = /*#__PURE__*/require('./call');
+module.exports.chain = /*#__PURE__*/require('./chain');
+module.exports.clamp = /*#__PURE__*/require('./clamp');
+module.exports.clone = /*#__PURE__*/require('./clone');
+module.exports.comparator = /*#__PURE__*/require('./comparator');
+module.exports.complement = /*#__PURE__*/require('./complement');
+module.exports.compose = /*#__PURE__*/require('./compose');
+module.exports.composeK = /*#__PURE__*/require('./composeK');
+module.exports.composeP = /*#__PURE__*/require('./composeP');
+module.exports.composeWith = /*#__PURE__*/require('./composeWith');
+module.exports.concat = /*#__PURE__*/require('./concat');
+module.exports.cond = /*#__PURE__*/require('./cond');
+module.exports.construct = /*#__PURE__*/require('./construct');
+module.exports.constructN = /*#__PURE__*/require('./constructN');
+module.exports.contains = /*#__PURE__*/require('./contains');
+module.exports.converge = /*#__PURE__*/require('./converge');
+module.exports.countBy = /*#__PURE__*/require('./countBy');
+module.exports.curry = /*#__PURE__*/require('./curry');
+module.exports.curryN = /*#__PURE__*/require('./curryN');
+module.exports.dec = /*#__PURE__*/require('./dec');
+module.exports.defaultTo = /*#__PURE__*/require('./defaultTo');
+module.exports.descend = /*#__PURE__*/require('./descend');
+module.exports.difference = /*#__PURE__*/require('./difference');
+module.exports.differenceWith = /*#__PURE__*/require('./differenceWith');
+module.exports.dissoc = /*#__PURE__*/require('./dissoc');
+module.exports.dissocPath = /*#__PURE__*/require('./dissocPath');
+module.exports.divide = /*#__PURE__*/require('./divide');
+module.exports.drop = /*#__PURE__*/require('./drop');
+module.exports.dropLast = /*#__PURE__*/require('./dropLast');
+module.exports.dropLastWhile = /*#__PURE__*/require('./dropLastWhile');
+module.exports.dropRepeats = /*#__PURE__*/require('./dropRepeats');
+module.exports.dropRepeatsWith = /*#__PURE__*/require('./dropRepeatsWith');
+module.exports.dropWhile = /*#__PURE__*/require('./dropWhile');
+module.exports.either = /*#__PURE__*/require('./either');
+module.exports.empty = /*#__PURE__*/require('./empty');
+module.exports.endsWith = /*#__PURE__*/require('./endsWith');
+module.exports.eqBy = /*#__PURE__*/require('./eqBy');
+module.exports.eqProps = /*#__PURE__*/require('./eqProps');
+module.exports.equals = /*#__PURE__*/require('./equals');
+module.exports.evolve = /*#__PURE__*/require('./evolve');
+module.exports.filter = /*#__PURE__*/require('./filter');
+module.exports.find = /*#__PURE__*/require('./find');
+module.exports.findIndex = /*#__PURE__*/require('./findIndex');
+module.exports.findLast = /*#__PURE__*/require('./findLast');
+module.exports.findLastIndex = /*#__PURE__*/require('./findLastIndex');
+module.exports.flatten = /*#__PURE__*/require('./flatten');
+module.exports.flip = /*#__PURE__*/require('./flip');
+module.exports.forEach = /*#__PURE__*/require('./forEach');
+module.exports.forEachObjIndexed = /*#__PURE__*/require('./forEachObjIndexed');
+module.exports.fromPairs = /*#__PURE__*/require('./fromPairs');
+module.exports.groupBy = /*#__PURE__*/require('./groupBy');
+module.exports.groupWith = /*#__PURE__*/require('./groupWith');
+module.exports.gt = /*#__PURE__*/require('./gt');
+module.exports.gte = /*#__PURE__*/require('./gte');
+module.exports.has = /*#__PURE__*/require('./has');
+module.exports.hasIn = /*#__PURE__*/require('./hasIn');
+module.exports.hasPath = /*#__PURE__*/require('./hasPath');
+module.exports.head = /*#__PURE__*/require('./head');
+module.exports.identical = /*#__PURE__*/require('./identical');
+module.exports.identity = /*#__PURE__*/require('./identity');
+module.exports.ifElse = /*#__PURE__*/require('./ifElse');
+module.exports.inc = /*#__PURE__*/require('./inc');
+module.exports.includes = /*#__PURE__*/require('./includes');
+module.exports.indexBy = /*#__PURE__*/require('./indexBy');
+module.exports.indexOf = /*#__PURE__*/require('./indexOf');
+module.exports.init = /*#__PURE__*/require('./init');
+module.exports.innerJoin = /*#__PURE__*/require('./innerJoin');
+module.exports.insert = /*#__PURE__*/require('./insert');
+module.exports.insertAll = /*#__PURE__*/require('./insertAll');
+module.exports.intersection = /*#__PURE__*/require('./intersection');
+module.exports.intersperse = /*#__PURE__*/require('./intersperse');
+module.exports.into = /*#__PURE__*/require('./into');
+module.exports.invert = /*#__PURE__*/require('./invert');
+module.exports.invertObj = /*#__PURE__*/require('./invertObj');
+module.exports.invoker = /*#__PURE__*/require('./invoker');
+module.exports.is = /*#__PURE__*/require('./is');
+module.exports.isEmpty = /*#__PURE__*/require('./isEmpty');
+module.exports.isNil = /*#__PURE__*/require('./isNil');
+module.exports.join = /*#__PURE__*/require('./join');
+module.exports.juxt = /*#__PURE__*/require('./juxt');
+module.exports.keys = /*#__PURE__*/require('./keys');
+module.exports.keysIn = /*#__PURE__*/require('./keysIn');
+module.exports.last = /*#__PURE__*/require('./last');
+module.exports.lastIndexOf = /*#__PURE__*/require('./lastIndexOf');
+module.exports.length = /*#__PURE__*/require('./length');
+module.exports.lens = /*#__PURE__*/require('./lens');
+module.exports.lensIndex = /*#__PURE__*/require('./lensIndex');
+module.exports.lensPath = /*#__PURE__*/require('./lensPath');
+module.exports.lensProp = /*#__PURE__*/require('./lensProp');
+module.exports.lift = /*#__PURE__*/require('./lift');
+module.exports.liftN = /*#__PURE__*/require('./liftN');
+module.exports.lt = /*#__PURE__*/require('./lt');
+module.exports.lte = /*#__PURE__*/require('./lte');
+module.exports.map = /*#__PURE__*/require('./map');
+module.exports.mapAccum = /*#__PURE__*/require('./mapAccum');
+module.exports.mapAccumRight = /*#__PURE__*/require('./mapAccumRight');
+module.exports.mapObjIndexed = /*#__PURE__*/require('./mapObjIndexed');
+module.exports.match = /*#__PURE__*/require('./match');
+module.exports.mathMod = /*#__PURE__*/require('./mathMod');
+module.exports.max = /*#__PURE__*/require('./max');
+module.exports.maxBy = /*#__PURE__*/require('./maxBy');
+module.exports.mean = /*#__PURE__*/require('./mean');
+module.exports.median = /*#__PURE__*/require('./median');
+module.exports.memoizeWith = /*#__PURE__*/require('./memoizeWith');
+module.exports.merge = /*#__PURE__*/require('./merge');
+module.exports.mergeAll = /*#__PURE__*/require('./mergeAll');
+module.exports.mergeDeepLeft = /*#__PURE__*/require('./mergeDeepLeft');
+module.exports.mergeDeepRight = /*#__PURE__*/require('./mergeDeepRight');
+module.exports.mergeDeepWith = /*#__PURE__*/require('./mergeDeepWith');
+module.exports.mergeDeepWithKey = /*#__PURE__*/require('./mergeDeepWithKey');
+module.exports.mergeLeft = /*#__PURE__*/require('./mergeLeft');
+module.exports.mergeRight = /*#__PURE__*/require('./mergeRight');
+module.exports.mergeWith = /*#__PURE__*/require('./mergeWith');
+module.exports.mergeWithKey = /*#__PURE__*/require('./mergeWithKey');
+module.exports.min = /*#__PURE__*/require('./min');
+module.exports.minBy = /*#__PURE__*/require('./minBy');
+module.exports.modulo = /*#__PURE__*/require('./modulo');
+module.exports.move = /*#__PURE__*/require('./move');
+module.exports.multiply = /*#__PURE__*/require('./multiply');
+module.exports.nAry = /*#__PURE__*/require('./nAry');
+module.exports.negate = /*#__PURE__*/require('./negate');
+module.exports.none = /*#__PURE__*/require('./none');
+module.exports.not = /*#__PURE__*/require('./not');
+module.exports.nth = /*#__PURE__*/require('./nth');
+module.exports.nthArg = /*#__PURE__*/require('./nthArg');
+module.exports.o = /*#__PURE__*/require('./o');
+module.exports.objOf = /*#__PURE__*/require('./objOf');
+module.exports.of = /*#__PURE__*/require('./of');
+module.exports.omit = /*#__PURE__*/require('./omit');
+module.exports.once = /*#__PURE__*/require('./once');
+module.exports.or = /*#__PURE__*/require('./or');
+module.exports.otherwise = /*#__PURE__*/require('./otherwise');
+module.exports.over = /*#__PURE__*/require('./over');
+module.exports.pair = /*#__PURE__*/require('./pair');
+module.exports.partial = /*#__PURE__*/require('./partial');
+module.exports.partialRight = /*#__PURE__*/require('./partialRight');
+module.exports.partition = /*#__PURE__*/require('./partition');
+module.exports.path = /*#__PURE__*/require('./path');
+module.exports.pathEq = /*#__PURE__*/require('./pathEq');
+module.exports.pathOr = /*#__PURE__*/require('./pathOr');
+module.exports.pathSatisfies = /*#__PURE__*/require('./pathSatisfies');
+module.exports.pick = /*#__PURE__*/require('./pick');
+module.exports.pickAll = /*#__PURE__*/require('./pickAll');
+module.exports.pickBy = /*#__PURE__*/require('./pickBy');
+module.exports.pipe = /*#__PURE__*/require('./pipe');
+module.exports.pipeK = /*#__PURE__*/require('./pipeK');
+module.exports.pipeP = /*#__PURE__*/require('./pipeP');
+module.exports.pipeWith = /*#__PURE__*/require('./pipeWith');
+module.exports.pluck = /*#__PURE__*/require('./pluck');
+module.exports.prepend = /*#__PURE__*/require('./prepend');
+module.exports.product = /*#__PURE__*/require('./product');
+module.exports.project = /*#__PURE__*/require('./project');
+module.exports.prop = /*#__PURE__*/require('./prop');
+module.exports.propEq = /*#__PURE__*/require('./propEq');
+module.exports.propIs = /*#__PURE__*/require('./propIs');
+module.exports.propOr = /*#__PURE__*/require('./propOr');
+module.exports.propSatisfies = /*#__PURE__*/require('./propSatisfies');
+module.exports.props = /*#__PURE__*/require('./props');
+module.exports.range = /*#__PURE__*/require('./range');
+module.exports.reduce = /*#__PURE__*/require('./reduce');
+module.exports.reduceBy = /*#__PURE__*/require('./reduceBy');
+module.exports.reduceRight = /*#__PURE__*/require('./reduceRight');
+module.exports.reduceWhile = /*#__PURE__*/require('./reduceWhile');
+module.exports.reduced = /*#__PURE__*/require('./reduced');
+module.exports.reject = /*#__PURE__*/require('./reject');
+module.exports.remove = /*#__PURE__*/require('./remove');
+module.exports.repeat = /*#__PURE__*/require('./repeat');
+module.exports.replace = /*#__PURE__*/require('./replace');
+module.exports.reverse = /*#__PURE__*/require('./reverse');
+module.exports.scan = /*#__PURE__*/require('./scan');
+module.exports.sequence = /*#__PURE__*/require('./sequence');
+module.exports.set = /*#__PURE__*/require('./set');
+module.exports.slice = /*#__PURE__*/require('./slice');
+module.exports.sort = /*#__PURE__*/require('./sort');
+module.exports.sortBy = /*#__PURE__*/require('./sortBy');
+module.exports.sortWith = /*#__PURE__*/require('./sortWith');
+module.exports.split = /*#__PURE__*/require('./split');
+module.exports.splitAt = /*#__PURE__*/require('./splitAt');
+module.exports.splitEvery = /*#__PURE__*/require('./splitEvery');
+module.exports.splitWhen = /*#__PURE__*/require('./splitWhen');
+module.exports.startsWith = /*#__PURE__*/require('./startsWith');
+module.exports.subtract = /*#__PURE__*/require('./subtract');
+module.exports.sum = /*#__PURE__*/require('./sum');
+module.exports.symmetricDifference = /*#__PURE__*/require('./symmetricDifference');
+module.exports.symmetricDifferenceWith = /*#__PURE__*/require('./symmetricDifferenceWith');
+module.exports.tail = /*#__PURE__*/require('./tail');
+module.exports.take = /*#__PURE__*/require('./take');
+module.exports.takeLast = /*#__PURE__*/require('./takeLast');
+module.exports.takeLastWhile = /*#__PURE__*/require('./takeLastWhile');
+module.exports.takeWhile = /*#__PURE__*/require('./takeWhile');
+module.exports.tap = /*#__PURE__*/require('./tap');
+module.exports.test = /*#__PURE__*/require('./test');
+module.exports.then = /*#__PURE__*/require('./then');
+module.exports.times = /*#__PURE__*/require('./times');
+module.exports.toLower = /*#__PURE__*/require('./toLower');
+module.exports.toPairs = /*#__PURE__*/require('./toPairs');
+module.exports.toPairsIn = /*#__PURE__*/require('./toPairsIn');
+module.exports.toString = /*#__PURE__*/require('./toString');
+module.exports.toUpper = /*#__PURE__*/require('./toUpper');
+module.exports.transduce = /*#__PURE__*/require('./transduce');
+module.exports.transpose = /*#__PURE__*/require('./transpose');
+module.exports.traverse = /*#__PURE__*/require('./traverse');
+module.exports.trim = /*#__PURE__*/require('./trim');
+module.exports.tryCatch = /*#__PURE__*/require('./tryCatch');
+module.exports.type = /*#__PURE__*/require('./type');
+module.exports.unapply = /*#__PURE__*/require('./unapply');
+module.exports.unary = /*#__PURE__*/require('./unary');
+module.exports.uncurryN = /*#__PURE__*/require('./uncurryN');
+module.exports.unfold = /*#__PURE__*/require('./unfold');
+module.exports.union = /*#__PURE__*/require('./union');
+module.exports.unionWith = /*#__PURE__*/require('./unionWith');
+module.exports.uniq = /*#__PURE__*/require('./uniq');
+module.exports.uniqBy = /*#__PURE__*/require('./uniqBy');
+module.exports.uniqWith = /*#__PURE__*/require('./uniqWith');
+module.exports.unless = /*#__PURE__*/require('./unless');
+module.exports.unnest = /*#__PURE__*/require('./unnest');
+module.exports.until = /*#__PURE__*/require('./until');
+module.exports.update = /*#__PURE__*/require('./update');
+module.exports.useWith = /*#__PURE__*/require('./useWith');
+module.exports.values = /*#__PURE__*/require('./values');
+module.exports.valuesIn = /*#__PURE__*/require('./valuesIn');
+module.exports.view = /*#__PURE__*/require('./view');
+module.exports.when = /*#__PURE__*/require('./when');
+module.exports.where = /*#__PURE__*/require('./where');
+module.exports.whereEq = /*#__PURE__*/require('./whereEq');
+module.exports.without = /*#__PURE__*/require('./without');
+module.exports.xprod = /*#__PURE__*/require('./xprod');
+module.exports.zip = /*#__PURE__*/require('./zip');
+module.exports.zipObj = /*#__PURE__*/require('./zipObj');
+module.exports.zipWith = /*#__PURE__*/require('./zipWith');
+module.exports.thunkify = /*#__PURE__*/require('./thunkify');
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/index.mjs b/server/node_modules/ramda/src/index.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..83ab2df7827a9638d6203d3ef27e491489016587
--- /dev/null
+++ b/server/node_modules/ramda/src/index.mjs
@@ -0,0 +1,255 @@
+export { default as F } from './F.js';
+export { default as T } from './T.js';
+export { default as __ } from './__.js';
+export { default as add } from './add.js';
+export { default as addIndex } from './addIndex.js';
+export { default as adjust } from './adjust.js';
+export { default as all } from './all.js';
+export { default as allPass } from './allPass.js';
+export { default as always } from './always.js';
+export { default as and } from './and.js';
+export { default as any } from './any.js';
+export { default as anyPass } from './anyPass.js';
+export { default as ap } from './ap.js';
+export { default as aperture } from './aperture.js';
+export { default as append } from './append.js';
+export { default as apply } from './apply.js';
+export { default as applySpec } from './applySpec.js';
+export { default as applyTo } from './applyTo.js';
+export { default as ascend } from './ascend.js';
+export { default as assoc } from './assoc.js';
+export { default as assocPath } from './assocPath.js';
+export { default as binary } from './binary.js';
+export { default as bind } from './bind.js';
+export { default as both } from './both.js';
+export { default as call } from './call.js';
+export { default as chain } from './chain.js';
+export { default as clamp } from './clamp.js';
+export { default as clone } from './clone.js';
+export { default as comparator } from './comparator.js';
+export { default as complement } from './complement.js';
+export { default as compose } from './compose.js';
+export { default as composeK } from './composeK.js';
+export { default as composeP } from './composeP.js';
+export { default as composeWith } from './composeWith.js';
+export { default as concat } from './concat.js';
+export { default as cond } from './cond.js';
+export { default as construct } from './construct.js';
+export { default as constructN } from './constructN.js';
+export { default as contains } from './contains.js';
+export { default as converge } from './converge.js';
+export { default as countBy } from './countBy.js';
+export { default as curry } from './curry.js';
+export { default as curryN } from './curryN.js';
+export { default as dec } from './dec.js';
+export { default as defaultTo } from './defaultTo.js';
+export { default as descend } from './descend.js';
+export { default as difference } from './difference.js';
+export { default as differenceWith } from './differenceWith.js';
+export { default as dissoc } from './dissoc.js';
+export { default as dissocPath } from './dissocPath.js';
+export { default as divide } from './divide.js';
+export { default as drop } from './drop.js';
+export { default as dropLast } from './dropLast.js';
+export { default as dropLastWhile } from './dropLastWhile.js';
+export { default as dropRepeats } from './dropRepeats.js';
+export { default as dropRepeatsWith } from './dropRepeatsWith.js';
+export { default as dropWhile } from './dropWhile.js';
+export { default as either } from './either.js';
+export { default as empty } from './empty.js';
+export { default as endsWith } from './endsWith.js';
+export { default as eqBy } from './eqBy.js';
+export { default as eqProps } from './eqProps.js';
+export { default as equals } from './equals.js';
+export { default as evolve } from './evolve.js';
+export { default as filter } from './filter.js';
+export { default as find } from './find.js';
+export { default as findIndex } from './findIndex.js';
+export { default as findLast } from './findLast.js';
+export { default as findLastIndex } from './findLastIndex.js';
+export { default as flatten } from './flatten.js';
+export { default as flip } from './flip.js';
+export { default as forEach } from './forEach.js';
+export { default as forEachObjIndexed } from './forEachObjIndexed.js';
+export { default as fromPairs } from './fromPairs.js';
+export { default as groupBy } from './groupBy.js';
+export { default as groupWith } from './groupWith.js';
+export { default as gt } from './gt.js';
+export { default as gte } from './gte.js';
+export { default as has } from './has.js';
+export { default as hasIn } from './hasIn.js';
+export { default as hasPath } from './hasPath.js';
+export { default as head } from './head.js';
+export { default as identical } from './identical.js';
+export { default as identity } from './identity.js';
+export { default as ifElse } from './ifElse.js';
+export { default as inc } from './inc.js';
+export { default as includes } from './includes.js';
+export { default as indexBy } from './indexBy.js';
+export { default as indexOf } from './indexOf.js';
+export { default as init } from './init.js';
+export { default as innerJoin } from './innerJoin.js';
+export { default as insert } from './insert.js';
+export { default as insertAll } from './insertAll.js';
+export { default as intersection } from './intersection.js';
+export { default as intersperse } from './intersperse.js';
+export { default as into } from './into.js';
+export { default as invert } from './invert.js';
+export { default as invertObj } from './invertObj.js';
+export { default as invoker } from './invoker.js';
+export { default as is } from './is.js';
+export { default as isEmpty } from './isEmpty.js';
+export { default as isNil } from './isNil.js';
+export { default as join } from './join.js';
+export { default as juxt } from './juxt.js';
+export { default as keys } from './keys.js';
+export { default as keysIn } from './keysIn.js';
+export { default as last } from './last.js';
+export { default as lastIndexOf } from './lastIndexOf.js';
+export { default as length } from './length.js';
+export { default as lens } from './lens.js';
+export { default as lensIndex } from './lensIndex.js';
+export { default as lensPath } from './lensPath.js';
+export { default as lensProp } from './lensProp.js';
+export { default as lift } from './lift.js';
+export { default as liftN } from './liftN.js';
+export { default as lt } from './lt.js';
+export { default as lte } from './lte.js';
+export { default as map } from './map.js';
+export { default as mapAccum } from './mapAccum.js';
+export { default as mapAccumRight } from './mapAccumRight.js';
+export { default as mapObjIndexed } from './mapObjIndexed.js';
+export { default as match } from './match.js';
+export { default as mathMod } from './mathMod.js';
+export { default as max } from './max.js';
+export { default as maxBy } from './maxBy.js';
+export { default as mean } from './mean.js';
+export { default as median } from './median.js';
+export { default as memoizeWith } from './memoizeWith.js';
+export { default as merge } from './merge.js';
+export { default as mergeAll } from './mergeAll.js';
+export { default as mergeDeepLeft } from './mergeDeepLeft.js';
+export { default as mergeDeepRight } from './mergeDeepRight.js';
+export { default as mergeDeepWith } from './mergeDeepWith.js';
+export { default as mergeDeepWithKey } from './mergeDeepWithKey.js';
+export { default as mergeLeft } from './mergeLeft.js';
+export { default as mergeRight } from './mergeRight.js';
+export { default as mergeWith } from './mergeWith.js';
+export { default as mergeWithKey } from './mergeWithKey.js';
+export { default as min } from './min.js';
+export { default as minBy } from './minBy.js';
+export { default as modulo } from './modulo.js';
+export { default as move } from './move.js';
+export { default as multiply } from './multiply.js';
+export { default as nAry } from './nAry.js';
+export { default as negate } from './negate.js';
+export { default as none } from './none.js';
+export { default as not } from './not.js';
+export { default as nth } from './nth.js';
+export { default as nthArg } from './nthArg.js';
+export { default as o } from './o.js';
+export { default as objOf } from './objOf.js';
+export { default as of } from './of.js';
+export { default as omit } from './omit.js';
+export { default as once } from './once.js';
+export { default as or } from './or.js';
+export { default as otherwise } from './otherwise.js';
+export { default as over } from './over.js';
+export { default as pair } from './pair.js';
+export { default as partial } from './partial.js';
+export { default as partialRight } from './partialRight.js';
+export { default as partition } from './partition.js';
+export { default as path } from './path.js';
+export { default as pathEq } from './pathEq.js';
+export { default as pathOr } from './pathOr.js';
+export { default as pathSatisfies } from './pathSatisfies.js';
+export { default as pick } from './pick.js';
+export { default as pickAll } from './pickAll.js';
+export { default as pickBy } from './pickBy.js';
+export { default as pipe } from './pipe.js';
+export { default as pipeK } from './pipeK.js';
+export { default as pipeP } from './pipeP.js';
+export { default as pipeWith } from './pipeWith.js';
+export { default as pluck } from './pluck.js';
+export { default as prepend } from './prepend.js';
+export { default as product } from './product.js';
+export { default as project } from './project.js';
+export { default as prop } from './prop.js';
+export { default as propEq } from './propEq.js';
+export { default as propIs } from './propIs.js';
+export { default as propOr } from './propOr.js';
+export { default as propSatisfies } from './propSatisfies.js';
+export { default as props } from './props.js';
+export { default as range } from './range.js';
+export { default as reduce } from './reduce.js';
+export { default as reduceBy } from './reduceBy.js';
+export { default as reduceRight } from './reduceRight.js';
+export { default as reduceWhile } from './reduceWhile.js';
+export { default as reduced } from './reduced.js';
+export { default as reject } from './reject.js';
+export { default as remove } from './remove.js';
+export { default as repeat } from './repeat.js';
+export { default as replace } from './replace.js';
+export { default as reverse } from './reverse.js';
+export { default as scan } from './scan.js';
+export { default as sequence } from './sequence.js';
+export { default as set } from './set.js';
+export { default as slice } from './slice.js';
+export { default as sort } from './sort.js';
+export { default as sortBy } from './sortBy.js';
+export { default as sortWith } from './sortWith.js';
+export { default as split } from './split.js';
+export { default as splitAt } from './splitAt.js';
+export { default as splitEvery } from './splitEvery.js';
+export { default as splitWhen } from './splitWhen.js';
+export { default as startsWith } from './startsWith.js';
+export { default as subtract } from './subtract.js';
+export { default as sum } from './sum.js';
+export { default as symmetricDifference } from './symmetricDifference.js';
+export { default as symmetricDifferenceWith } from './symmetricDifferenceWith.js';
+export { default as tail } from './tail.js';
+export { default as take } from './take.js';
+export { default as takeLast } from './takeLast.js';
+export { default as takeLastWhile } from './takeLastWhile.js';
+export { default as takeWhile } from './takeWhile.js';
+export { default as tap } from './tap.js';
+export { default as test } from './test.js';
+export { default as then } from './then.js';
+export { default as times } from './times.js';
+export { default as toLower } from './toLower.js';
+export { default as toPairs } from './toPairs.js';
+export { default as toPairsIn } from './toPairsIn.js';
+export { default as toString } from './toString.js';
+export { default as toUpper } from './toUpper.js';
+export { default as transduce } from './transduce.js';
+export { default as transpose } from './transpose.js';
+export { default as traverse } from './traverse.js';
+export { default as trim } from './trim.js';
+export { default as tryCatch } from './tryCatch.js';
+export { default as type } from './type.js';
+export { default as unapply } from './unapply.js';
+export { default as unary } from './unary.js';
+export { default as uncurryN } from './uncurryN.js';
+export { default as unfold } from './unfold.js';
+export { default as union } from './union.js';
+export { default as unionWith } from './unionWith.js';
+export { default as uniq } from './uniq.js';
+export { default as uniqBy } from './uniqBy.js';
+export { default as uniqWith } from './uniqWith.js';
+export { default as unless } from './unless.js';
+export { default as unnest } from './unnest.js';
+export { default as until } from './until.js';
+export { default as update } from './update.js';
+export { default as useWith } from './useWith.js';
+export { default as values } from './values.js';
+export { default as valuesIn } from './valuesIn.js';
+export { default as view } from './view.js';
+export { default as when } from './when.js';
+export { default as where } from './where.js';
+export { default as whereEq } from './whereEq.js';
+export { default as without } from './without.js';
+export { default as xprod } from './xprod.js';
+export { default as zip } from './zip.js';
+export { default as zipObj } from './zipObj.js';
+export { default as zipWith } from './zipWith.js';
+export { default as thunkify } from './thunkify.js';
diff --git a/server/node_modules/ramda/src/indexBy.js b/server/node_modules/ramda/src/indexBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..18abfa6d5a268fd63065745d046019cafca04373
--- /dev/null
+++ b/server/node_modules/ramda/src/indexBy.js
@@ -0,0 +1,30 @@
+var reduceBy = /*#__PURE__*/require('./reduceBy');
+
+/**
+ * Given a function that generates a key, turns a list of objects into an
+ * object indexing the objects by the given key. Note that if multiple
+ * objects generate the same value for the indexing key only the last value
+ * will be included in the generated object.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (a -> String) -> [{k: v}] -> {k: {k: v}}
+ * @param {Function} fn Function :: a -> String
+ * @param {Array} array The array of objects to index
+ * @return {Object} An object indexing each array element by the given property.
+ * @example
+ *
+ *      const list = [{id: 'xyz', title: 'A'}, {id: 'abc', title: 'B'}];
+ *      R.indexBy(R.prop('id'), list);
+ *      //=> {abc: {id: 'abc', title: 'B'}, xyz: {id: 'xyz', title: 'A'}}
+ */
+
+
+var indexBy = /*#__PURE__*/reduceBy(function (acc, elem) {
+  return elem;
+}, null);
+module.exports = indexBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/indexOf.js b/server/node_modules/ramda/src/indexOf.js
new file mode 100644
index 0000000000000000000000000000000000000000..0c80d510b33b89abede0fc8341c030d617d44fdc
--- /dev/null
+++ b/server/node_modules/ramda/src/indexOf.js
@@ -0,0 +1,31 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _indexOf = /*#__PURE__*/require('./internal/_indexOf');
+
+var _isArray = /*#__PURE__*/require('./internal/_isArray');
+
+/**
+ * Returns the position of the first occurrence of an item in an array, or -1
+ * if the item is not included in the array. [`R.equals`](#equals) is used to
+ * determine equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Number
+ * @param {*} target The item to find.
+ * @param {Array} xs The array to search in.
+ * @return {Number} the index of the target, or -1 if the target is not found.
+ * @see R.lastIndexOf
+ * @example
+ *
+ *      R.indexOf(3, [1,2,3,4]); //=> 2
+ *      R.indexOf(10, [1,2,3,4]); //=> -1
+ */
+
+
+var indexOf = /*#__PURE__*/_curry2(function indexOf(target, xs) {
+  return typeof xs.indexOf === 'function' && !_isArray(xs) ? xs.indexOf(target) : _indexOf(xs, target, 0);
+});
+module.exports = indexOf;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/init.js b/server/node_modules/ramda/src/init.js
new file mode 100644
index 0000000000000000000000000000000000000000..81c56038d6960f0ee4ea3764d5c5aa7f014ad0ce
--- /dev/null
+++ b/server/node_modules/ramda/src/init.js
@@ -0,0 +1,30 @@
+var slice = /*#__PURE__*/require('./slice');
+
+/**
+ * Returns all but the last element of the given list or string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category List
+ * @sig [a] -> [a]
+ * @sig String -> String
+ * @param {*} list
+ * @return {*}
+ * @see R.last, R.head, R.tail
+ * @example
+ *
+ *      R.init([1, 2, 3]);  //=> [1, 2]
+ *      R.init([1, 2]);     //=> [1]
+ *      R.init([1]);        //=> []
+ *      R.init([]);         //=> []
+ *
+ *      R.init('abc');  //=> 'ab'
+ *      R.init('ab');   //=> 'a'
+ *      R.init('a');    //=> ''
+ *      R.init('');     //=> ''
+ */
+
+
+var init = /*#__PURE__*/slice(0, -1);
+module.exports = init;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/innerJoin.js b/server/node_modules/ramda/src/innerJoin.js
new file mode 100644
index 0000000000000000000000000000000000000000..5004fe951b04a7353002b74646e63a4449c2c473
--- /dev/null
+++ b/server/node_modules/ramda/src/innerJoin.js
@@ -0,0 +1,49 @@
+var _includesWith = /*#__PURE__*/require('./internal/_includesWith');
+
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var _filter = /*#__PURE__*/require('./internal/_filter');
+
+/**
+ * Takes a predicate `pred`, a list `xs`, and a list `ys`, and returns a list
+ * `xs'` comprising each of the elements of `xs` which is equal to one or more
+ * elements of `ys` according to `pred`.
+ *
+ * `pred` must be a binary function expecting an element from each list.
+ *
+ * `xs`, `ys`, and `xs'` are treated as sets, semantically, so ordering should
+ * not be significant, but since `xs'` is ordered the implementation guarantees
+ * that its values are in the same order as they appear in `xs`. Duplicates are
+ * not removed, so `xs'` may contain duplicates if `xs` contains duplicates.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Relation
+ * @sig ((a, b) -> Boolean) -> [a] -> [b] -> [a]
+ * @param {Function} pred
+ * @param {Array} xs
+ * @param {Array} ys
+ * @return {Array}
+ * @see R.intersection
+ * @example
+ *
+ *      R.innerJoin(
+ *        (record, id) => record.id === id,
+ *        [{id: 824, name: 'Richie Furay'},
+ *         {id: 956, name: 'Dewey Martin'},
+ *         {id: 313, name: 'Bruce Palmer'},
+ *         {id: 456, name: 'Stephen Stills'},
+ *         {id: 177, name: 'Neil Young'}],
+ *        [177, 456, 999]
+ *      );
+ *      //=> [{id: 456, name: 'Stephen Stills'}, {id: 177, name: 'Neil Young'}]
+ */
+
+
+var innerJoin = /*#__PURE__*/_curry3(function innerJoin(pred, xs, ys) {
+  return _filter(function (x) {
+    return _includesWith(pred, x, ys);
+  }, xs);
+});
+module.exports = innerJoin;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/insert.js b/server/node_modules/ramda/src/insert.js
new file mode 100644
index 0000000000000000000000000000000000000000..c0125e7dd9af200521d49a4a7174cfe9dbc8fbad
--- /dev/null
+++ b/server/node_modules/ramda/src/insert.js
@@ -0,0 +1,30 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Inserts the supplied element into the list, at the specified `index`. _Note that
+
+ * this is not destructive_: it returns a copy of the list with the changes.
+ * <small>No lists have been harmed in the application of this function.</small>
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.2
+ * @category List
+ * @sig Number -> a -> [a] -> [a]
+ * @param {Number} index The position to insert the element
+ * @param {*} elt The element to insert into the Array
+ * @param {Array} list The list to insert into
+ * @return {Array} A new Array with `elt` inserted at `index`.
+ * @example
+ *
+ *      R.insert(2, 'x', [1,2,3,4]); //=> [1,2,'x',3,4]
+ */
+
+
+var insert = /*#__PURE__*/_curry3(function insert(idx, elt, list) {
+  idx = idx < list.length && idx >= 0 ? idx : list.length;
+  var result = Array.prototype.slice.call(list, 0);
+  result.splice(idx, 0, elt);
+  return result;
+});
+module.exports = insert;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/insertAll.js b/server/node_modules/ramda/src/insertAll.js
new file mode 100644
index 0000000000000000000000000000000000000000..146096103a86abe4380efa41f8cccd4c3241df5e
--- /dev/null
+++ b/server/node_modules/ramda/src/insertAll.js
@@ -0,0 +1,27 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Inserts the sub-list into the list, at the specified `index`. _Note that this is not
+ * destructive_: it returns a copy of the list with the changes.
+ * <small>No lists have been harmed in the application of this function.</small>
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category List
+ * @sig Number -> [a] -> [a] -> [a]
+ * @param {Number} index The position to insert the sub-list
+ * @param {Array} elts The sub-list to insert into the Array
+ * @param {Array} list The list to insert the sub-list into
+ * @return {Array} A new Array with `elts` inserted starting at `index`.
+ * @example
+ *
+ *      R.insertAll(2, ['x','y','z'], [1,2,3,4]); //=> [1,2,'x','y','z',3,4]
+ */
+
+
+var insertAll = /*#__PURE__*/_curry3(function insertAll(idx, elts, list) {
+  idx = idx < list.length && idx >= 0 ? idx : list.length;
+  return [].concat(Array.prototype.slice.call(list, 0, idx), elts, Array.prototype.slice.call(list, idx));
+});
+module.exports = insertAll;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_Set.js b/server/node_modules/ramda/src/internal/_Set.js
new file mode 100644
index 0000000000000000000000000000000000000000..9c08287c56e41af848ad13150d3aea868cdfb93b
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_Set.js
@@ -0,0 +1,174 @@
+var _includes = /*#__PURE__*/require('./_includes');
+
+var _Set = /*#__PURE__*/function () {
+
+  function _Set() {
+    /* globals Set */
+    this._nativeSet = typeof Set === 'function' ? new Set() : null;
+    this._items = {};
+  }
+
+  // until we figure out why jsdoc chokes on this
+  // @param item The item to add to the Set
+  // @returns {boolean} true if the item did not exist prior, otherwise false
+  //
+  _Set.prototype.add = function (item) {
+    return !hasOrAdd(item, true, this);
+  };
+
+  //
+  // @param item The item to check for existence in the Set
+  // @returns {boolean} true if the item exists in the Set, otherwise false
+  //
+  _Set.prototype.has = function (item) {
+    return hasOrAdd(item, false, this);
+  };
+
+  //
+  // Combines the logic for checking whether an item is a member of the set and
+  // for adding a new item to the set.
+  //
+  // @param item       The item to check or add to the Set instance.
+  // @param shouldAdd  If true, the item will be added to the set if it doesn't
+  //                   already exist.
+  // @param set        The set instance to check or add to.
+  // @return {boolean} true if the item already existed, otherwise false.
+  //
+  return _Set;
+}();
+
+function hasOrAdd(item, shouldAdd, set) {
+  var type = typeof item;
+  var prevSize, newSize;
+  switch (type) {
+    case 'string':
+    case 'number':
+      // distinguish between +0 and -0
+      if (item === 0 && 1 / item === -Infinity) {
+        if (set._items['-0']) {
+          return true;
+        } else {
+          if (shouldAdd) {
+            set._items['-0'] = true;
+          }
+          return false;
+        }
+      }
+      // these types can all utilise the native Set
+      if (set._nativeSet !== null) {
+        if (shouldAdd) {
+          prevSize = set._nativeSet.size;
+          set._nativeSet.add(item);
+          newSize = set._nativeSet.size;
+          return newSize === prevSize;
+        } else {
+          return set._nativeSet.has(item);
+        }
+      } else {
+        if (!(type in set._items)) {
+          if (shouldAdd) {
+            set._items[type] = {};
+            set._items[type][item] = true;
+          }
+          return false;
+        } else if (item in set._items[type]) {
+          return true;
+        } else {
+          if (shouldAdd) {
+            set._items[type][item] = true;
+          }
+          return false;
+        }
+      }
+
+    case 'boolean':
+      // set._items['boolean'] holds a two element array
+      // representing [ falseExists, trueExists ]
+      if (type in set._items) {
+        var bIdx = item ? 1 : 0;
+        if (set._items[type][bIdx]) {
+          return true;
+        } else {
+          if (shouldAdd) {
+            set._items[type][bIdx] = true;
+          }
+          return false;
+        }
+      } else {
+        if (shouldAdd) {
+          set._items[type] = item ? [false, true] : [true, false];
+        }
+        return false;
+      }
+
+    case 'function':
+      // compare functions for reference equality
+      if (set._nativeSet !== null) {
+        if (shouldAdd) {
+          prevSize = set._nativeSet.size;
+          set._nativeSet.add(item);
+          newSize = set._nativeSet.size;
+          return newSize === prevSize;
+        } else {
+          return set._nativeSet.has(item);
+        }
+      } else {
+        if (!(type in set._items)) {
+          if (shouldAdd) {
+            set._items[type] = [item];
+          }
+          return false;
+        }
+        if (!_includes(item, set._items[type])) {
+          if (shouldAdd) {
+            set._items[type].push(item);
+          }
+          return false;
+        }
+        return true;
+      }
+
+    case 'undefined':
+      if (set._items[type]) {
+        return true;
+      } else {
+        if (shouldAdd) {
+          set._items[type] = true;
+        }
+        return false;
+      }
+
+    case 'object':
+      if (item === null) {
+        if (!set._items['null']) {
+          if (shouldAdd) {
+            set._items['null'] = true;
+          }
+          return false;
+        }
+        return true;
+      }
+    /* falls through */
+    default:
+      // reduce the search size of heterogeneous sets by creating buckets
+      // for each type.
+      type = Object.prototype.toString.call(item);
+      if (!(type in set._items)) {
+        if (shouldAdd) {
+          set._items[type] = [item];
+        }
+        return false;
+      }
+      // scan through all previously applied items
+      if (!_includes(item, set._items[type])) {
+        if (shouldAdd) {
+          set._items[type].push(item);
+        }
+        return false;
+      }
+      return true;
+  }
+}
+
+// A simple Set type that honours R.equals semantics
+module.exports = _Set;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_aperture.js b/server/node_modules/ramda/src/internal/_aperture.js
new file mode 100644
index 0000000000000000000000000000000000000000..86aed40f9acdba86a9f617c512fda4b4c3746da3
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_aperture.js
@@ -0,0 +1,11 @@
+function _aperture(n, list) {
+  var idx = 0;
+  var limit = list.length - (n - 1);
+  var acc = new Array(limit >= 0 ? limit : 0);
+  while (idx < limit) {
+    acc[idx] = Array.prototype.slice.call(list, idx, idx + n);
+    idx += 1;
+  }
+  return acc;
+}
+module.exports = _aperture;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_arity.js b/server/node_modules/ramda/src/internal/_arity.js
new file mode 100644
index 0000000000000000000000000000000000000000..8dc1c73ab3878618d7605259bf45b545d6221f73
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_arity.js
@@ -0,0 +1,52 @@
+function _arity(n, fn) {
+  /* eslint-disable no-unused-vars */
+  switch (n) {
+    case 0:
+      return function () {
+        return fn.apply(this, arguments);
+      };
+    case 1:
+      return function (a0) {
+        return fn.apply(this, arguments);
+      };
+    case 2:
+      return function (a0, a1) {
+        return fn.apply(this, arguments);
+      };
+    case 3:
+      return function (a0, a1, a2) {
+        return fn.apply(this, arguments);
+      };
+    case 4:
+      return function (a0, a1, a2, a3) {
+        return fn.apply(this, arguments);
+      };
+    case 5:
+      return function (a0, a1, a2, a3, a4) {
+        return fn.apply(this, arguments);
+      };
+    case 6:
+      return function (a0, a1, a2, a3, a4, a5) {
+        return fn.apply(this, arguments);
+      };
+    case 7:
+      return function (a0, a1, a2, a3, a4, a5, a6) {
+        return fn.apply(this, arguments);
+      };
+    case 8:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7) {
+        return fn.apply(this, arguments);
+      };
+    case 9:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) {
+        return fn.apply(this, arguments);
+      };
+    case 10:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {
+        return fn.apply(this, arguments);
+      };
+    default:
+      throw new Error('First argument to _arity must be a non-negative integer no greater than ten');
+  }
+}
+module.exports = _arity;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_arrayFromIterator.js b/server/node_modules/ramda/src/internal/_arrayFromIterator.js
new file mode 100644
index 0000000000000000000000000000000000000000..a75cfc2d1d002e8129e156447b1bd1f257aed92b
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_arrayFromIterator.js
@@ -0,0 +1,9 @@
+function _arrayFromIterator(iter) {
+  var list = [];
+  var next;
+  while (!(next = iter.next()).done) {
+    list.push(next.value);
+  }
+  return list;
+}
+module.exports = _arrayFromIterator;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_assertPromise.js b/server/node_modules/ramda/src/internal/_assertPromise.js
new file mode 100644
index 0000000000000000000000000000000000000000..def2f6d915d665e516f858cc6a0e8c270574bbf6
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_assertPromise.js
@@ -0,0 +1,10 @@
+var _isFunction = /*#__PURE__*/require('./_isFunction');
+
+var _toString = /*#__PURE__*/require('./_toString');
+
+function _assertPromise(name, p) {
+  if (p == null || !_isFunction(p.then)) {
+    throw new TypeError('`' + name + '` expected a Promise, received ' + _toString(p, []));
+  }
+}
+module.exports = _assertPromise;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_checkForMethod.js b/server/node_modules/ramda/src/internal/_checkForMethod.js
new file mode 100644
index 0000000000000000000000000000000000000000..6494d812e771cf2b739db8a0e1a9bdf1979f03ae
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_checkForMethod.js
@@ -0,0 +1,25 @@
+var _isArray = /*#__PURE__*/require('./_isArray');
+
+/**
+ * This checks whether a function has a [methodname] function. If it isn't an
+ * array it will execute that function otherwise it will default to the ramda
+ * implementation.
+ *
+ * @private
+ * @param {Function} fn ramda implemtation
+ * @param {String} methodname property to check for a custom implementation
+ * @return {Object} Whatever the return value of the method is.
+ */
+
+
+function _checkForMethod(methodname, fn) {
+  return function () {
+    var length = arguments.length;
+    if (length === 0) {
+      return fn();
+    }
+    var obj = arguments[length - 1];
+    return _isArray(obj) || typeof obj[methodname] !== 'function' ? fn.apply(this, arguments) : obj[methodname].apply(obj, Array.prototype.slice.call(arguments, 0, length - 1));
+  };
+}
+module.exports = _checkForMethod;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_clone.js b/server/node_modules/ramda/src/internal/_clone.js
new file mode 100644
index 0000000000000000000000000000000000000000..965cfba94b10fb097358291beb01dc23f45a5197
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_clone.js
@@ -0,0 +1,47 @@
+var _cloneRegExp = /*#__PURE__*/require('./_cloneRegExp');
+
+var type = /*#__PURE__*/require('../type');
+
+/**
+ * Copies an object.
+ *
+ * @private
+ * @param {*} value The value to be copied
+ * @param {Array} refFrom Array containing the source references
+ * @param {Array} refTo Array containing the copied source references
+ * @param {Boolean} deep Whether or not to perform deep cloning.
+ * @return {*} The copied value.
+ */
+
+
+function _clone(value, refFrom, refTo, deep) {
+  var copy = function copy(copiedValue) {
+    var len = refFrom.length;
+    var idx = 0;
+    while (idx < len) {
+      if (value === refFrom[idx]) {
+        return refTo[idx];
+      }
+      idx += 1;
+    }
+    refFrom[idx + 1] = value;
+    refTo[idx + 1] = copiedValue;
+    for (var key in value) {
+      copiedValue[key] = deep ? _clone(value[key], refFrom, refTo, true) : value[key];
+    }
+    return copiedValue;
+  };
+  switch (type(value)) {
+    case 'Object':
+      return copy({});
+    case 'Array':
+      return copy([]);
+    case 'Date':
+      return new Date(value.valueOf());
+    case 'RegExp':
+      return _cloneRegExp(value);
+    default:
+      return value;
+  }
+}
+module.exports = _clone;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_cloneRegExp.js b/server/node_modules/ramda/src/internal/_cloneRegExp.js
new file mode 100644
index 0000000000000000000000000000000000000000..47c073554ff40a1fb1216ccf628a35d842685aa3
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_cloneRegExp.js
@@ -0,0 +1,4 @@
+function _cloneRegExp(pattern) {
+                                  return new RegExp(pattern.source, (pattern.global ? 'g' : '') + (pattern.ignoreCase ? 'i' : '') + (pattern.multiline ? 'm' : '') + (pattern.sticky ? 'y' : '') + (pattern.unicode ? 'u' : ''));
+}
+module.exports = _cloneRegExp;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_complement.js b/server/node_modules/ramda/src/internal/_complement.js
new file mode 100644
index 0000000000000000000000000000000000000000..d4206fc4a40aa03865f520e9ebd1956b1424b72d
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_complement.js
@@ -0,0 +1,6 @@
+function _complement(f) {
+  return function () {
+    return !f.apply(this, arguments);
+  };
+}
+module.exports = _complement;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_concat.js b/server/node_modules/ramda/src/internal/_concat.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ceba35d97900a72501a89fe59a66d76cdb416c4
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_concat.js
@@ -0,0 +1,32 @@
+/**
+ * Private `concat` function to merge two array-like objects.
+ *
+ * @private
+ * @param {Array|Arguments} [set1=[]] An array-like object.
+ * @param {Array|Arguments} [set2=[]] An array-like object.
+ * @return {Array} A new, merged array.
+ * @example
+ *
+ *      _concat([4, 5, 6], [1, 2, 3]); //=> [4, 5, 6, 1, 2, 3]
+ */
+function _concat(set1, set2) {
+  set1 = set1 || [];
+  set2 = set2 || [];
+  var idx;
+  var len1 = set1.length;
+  var len2 = set2.length;
+  var result = [];
+
+  idx = 0;
+  while (idx < len1) {
+    result[result.length] = set1[idx];
+    idx += 1;
+  }
+  idx = 0;
+  while (idx < len2) {
+    result[result.length] = set2[idx];
+    idx += 1;
+  }
+  return result;
+}
+module.exports = _concat;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_createPartialApplicator.js b/server/node_modules/ramda/src/internal/_createPartialApplicator.js
new file mode 100644
index 0000000000000000000000000000000000000000..4a859f8a02e58a50b4becff72d3df95503b1f3ed
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_createPartialApplicator.js
@@ -0,0 +1,12 @@
+var _arity = /*#__PURE__*/require('./_arity');
+
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+function _createPartialApplicator(concat) {
+  return _curry2(function (fn, args) {
+    return _arity(Math.max(0, fn.length - args.length), function () {
+      return fn.apply(this, concat(args, arguments));
+    });
+  });
+}
+module.exports = _createPartialApplicator;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_curry1.js b/server/node_modules/ramda/src/internal/_curry1.js
new file mode 100644
index 0000000000000000000000000000000000000000..da975f895116bb35304c67d8bcd7e5f2455a5fa6
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_curry1.js
@@ -0,0 +1,22 @@
+var _isPlaceholder = /*#__PURE__*/require('./_isPlaceholder');
+
+/**
+ * Optimized internal one-arity curry function.
+ *
+ * @private
+ * @category Function
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+
+
+function _curry1(fn) {
+  return function f1(a) {
+    if (arguments.length === 0 || _isPlaceholder(a)) {
+      return f1;
+    } else {
+      return fn.apply(this, arguments);
+    }
+  };
+}
+module.exports = _curry1;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_curry2.js b/server/node_modules/ramda/src/internal/_curry2.js
new file mode 100644
index 0000000000000000000000000000000000000000..716f8e61d96b148dc9c9f7eaf1ee135896654a5e
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_curry2.js
@@ -0,0 +1,33 @@
+var _curry1 = /*#__PURE__*/require('./_curry1');
+
+var _isPlaceholder = /*#__PURE__*/require('./_isPlaceholder');
+
+/**
+ * Optimized internal two-arity curry function.
+ *
+ * @private
+ * @category Function
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+
+
+function _curry2(fn) {
+  return function f2(a, b) {
+    switch (arguments.length) {
+      case 0:
+        return f2;
+      case 1:
+        return _isPlaceholder(a) ? f2 : _curry1(function (_b) {
+          return fn(a, _b);
+        });
+      default:
+        return _isPlaceholder(a) && _isPlaceholder(b) ? f2 : _isPlaceholder(a) ? _curry1(function (_a) {
+          return fn(_a, b);
+        }) : _isPlaceholder(b) ? _curry1(function (_b) {
+          return fn(a, _b);
+        }) : fn(a, b);
+    }
+  };
+}
+module.exports = _curry2;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_curry3.js b/server/node_modules/ramda/src/internal/_curry3.js
new file mode 100644
index 0000000000000000000000000000000000000000..621371b9d15a97f2d532c1d93d268d5d7426666a
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_curry3.js
@@ -0,0 +1,51 @@
+var _curry1 = /*#__PURE__*/require('./_curry1');
+
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _isPlaceholder = /*#__PURE__*/require('./_isPlaceholder');
+
+/**
+ * Optimized internal three-arity curry function.
+ *
+ * @private
+ * @category Function
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+
+
+function _curry3(fn) {
+  return function f3(a, b, c) {
+    switch (arguments.length) {
+      case 0:
+        return f3;
+      case 1:
+        return _isPlaceholder(a) ? f3 : _curry2(function (_b, _c) {
+          return fn(a, _b, _c);
+        });
+      case 2:
+        return _isPlaceholder(a) && _isPlaceholder(b) ? f3 : _isPlaceholder(a) ? _curry2(function (_a, _c) {
+          return fn(_a, b, _c);
+        }) : _isPlaceholder(b) ? _curry2(function (_b, _c) {
+          return fn(a, _b, _c);
+        }) : _curry1(function (_c) {
+          return fn(a, b, _c);
+        });
+      default:
+        return _isPlaceholder(a) && _isPlaceholder(b) && _isPlaceholder(c) ? f3 : _isPlaceholder(a) && _isPlaceholder(b) ? _curry2(function (_a, _b) {
+          return fn(_a, _b, c);
+        }) : _isPlaceholder(a) && _isPlaceholder(c) ? _curry2(function (_a, _c) {
+          return fn(_a, b, _c);
+        }) : _isPlaceholder(b) && _isPlaceholder(c) ? _curry2(function (_b, _c) {
+          return fn(a, _b, _c);
+        }) : _isPlaceholder(a) ? _curry1(function (_a) {
+          return fn(_a, b, c);
+        }) : _isPlaceholder(b) ? _curry1(function (_b) {
+          return fn(a, _b, c);
+        }) : _isPlaceholder(c) ? _curry1(function (_c) {
+          return fn(a, b, _c);
+        }) : fn(a, b, c);
+    }
+  };
+}
+module.exports = _curry3;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_curryN.js b/server/node_modules/ramda/src/internal/_curryN.js
new file mode 100644
index 0000000000000000000000000000000000000000..b1cb5b4f95a9b44a098b66b2a3f3259245b9d47c
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_curryN.js
@@ -0,0 +1,40 @@
+var _arity = /*#__PURE__*/require('./_arity');
+
+var _isPlaceholder = /*#__PURE__*/require('./_isPlaceholder');
+
+/**
+ * Internal curryN function.
+ *
+ * @private
+ * @category Function
+ * @param {Number} length The arity of the curried function.
+ * @param {Array} received An array of arguments received thus far.
+ * @param {Function} fn The function to curry.
+ * @return {Function} The curried function.
+ */
+
+
+function _curryN(length, received, fn) {
+  return function () {
+    var combined = [];
+    var argsIdx = 0;
+    var left = length;
+    var combinedIdx = 0;
+    while (combinedIdx < received.length || argsIdx < arguments.length) {
+      var result;
+      if (combinedIdx < received.length && (!_isPlaceholder(received[combinedIdx]) || argsIdx >= arguments.length)) {
+        result = received[combinedIdx];
+      } else {
+        result = arguments[argsIdx];
+        argsIdx += 1;
+      }
+      combined[combinedIdx] = result;
+      if (!_isPlaceholder(result)) {
+        left -= 1;
+      }
+      combinedIdx += 1;
+    }
+    return left <= 0 ? fn.apply(this, combined) : _arity(left, _curryN(length, combined, fn));
+  };
+}
+module.exports = _curryN;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_dispatchable.js b/server/node_modules/ramda/src/internal/_dispatchable.js
new file mode 100644
index 0000000000000000000000000000000000000000..04f0bdc2a8d1566a9311da99c9bd22346f5252d2
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_dispatchable.js
@@ -0,0 +1,44 @@
+var _isArray = /*#__PURE__*/require('./_isArray');
+
+var _isTransformer = /*#__PURE__*/require('./_isTransformer');
+
+/**
+ * Returns a function that dispatches with different strategies based on the
+ * object in list position (last argument). If it is an array, executes [fn].
+ * Otherwise, if it has a function with one of the given method names, it will
+ * execute that function (functor case). Otherwise, if it is a transformer,
+ * uses transducer [xf] to return a new transformer (transducer case).
+ * Otherwise, it will default to executing [fn].
+ *
+ * @private
+ * @param {Array} methodNames properties to check for a custom implementation
+ * @param {Function} xf transducer to initialize if object is transformer
+ * @param {Function} fn default ramda implementation
+ * @return {Function} A function that dispatches on object in list position
+ */
+
+
+function _dispatchable(methodNames, xf, fn) {
+  return function () {
+    if (arguments.length === 0) {
+      return fn();
+    }
+    var args = Array.prototype.slice.call(arguments, 0);
+    var obj = args.pop();
+    if (!_isArray(obj)) {
+      var idx = 0;
+      while (idx < methodNames.length) {
+        if (typeof obj[methodNames[idx]] === 'function') {
+          return obj[methodNames[idx]].apply(obj, args);
+        }
+        idx += 1;
+      }
+      if (_isTransformer(obj)) {
+        var transducer = xf.apply(null, args);
+        return transducer(obj);
+      }
+    }
+    return fn.apply(this, arguments);
+  };
+}
+module.exports = _dispatchable;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_dropLast.js b/server/node_modules/ramda/src/internal/_dropLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..4e1f33429d13669e71f5df35e4c6d37543be6ec3
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_dropLast.js
@@ -0,0 +1,6 @@
+var take = /*#__PURE__*/require('../take');
+
+function dropLast(n, xs) {
+  return take(n < xs.length ? xs.length - n : 0, xs);
+}
+module.exports = dropLast;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_dropLastWhile.js b/server/node_modules/ramda/src/internal/_dropLastWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e81ec1b138dd3670ff6b13e8a0c74ea0e896411
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_dropLastWhile.js
@@ -0,0 +1,10 @@
+var slice = /*#__PURE__*/require('../slice');
+
+function dropLastWhile(pred, xs) {
+  var idx = xs.length - 1;
+  while (idx >= 0 && pred(xs[idx])) {
+    idx -= 1;
+  }
+  return slice(0, idx + 1, xs);
+}
+module.exports = dropLastWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_equals.js b/server/node_modules/ramda/src/internal/_equals.js
new file mode 100644
index 0000000000000000000000000000000000000000..aa611b898eb5dc7f0a7b077170d9161564cec15d
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_equals.js
@@ -0,0 +1,156 @@
+var _arrayFromIterator = /*#__PURE__*/require('./_arrayFromIterator');
+
+var _includesWith = /*#__PURE__*/require('./_includesWith');
+
+var _functionName = /*#__PURE__*/require('./_functionName');
+
+var _has = /*#__PURE__*/require('./_has');
+
+var _objectIs = /*#__PURE__*/require('./_objectIs');
+
+var keys = /*#__PURE__*/require('../keys');
+
+var type = /*#__PURE__*/require('../type');
+
+/**
+ * private _uniqContentEquals function.
+ * That function is checking equality of 2 iterator contents with 2 assumptions
+ * - iterators lengths are the same
+ * - iterators values are unique
+ *
+ * false-positive result will be returned for comparision of, e.g.
+ * - [1,2,3] and [1,2,3,4]
+ * - [1,1,1] and [1,2,3]
+ * */
+
+function _uniqContentEquals(aIterator, bIterator, stackA, stackB) {
+  var a = _arrayFromIterator(aIterator);
+  var b = _arrayFromIterator(bIterator);
+
+  function eq(_a, _b) {
+    return _equals(_a, _b, stackA.slice(), stackB.slice());
+  }
+
+  // if *a* array contains any element that is not included in *b*
+  return !_includesWith(function (b, aItem) {
+    return !_includesWith(eq, aItem, b);
+  }, b, a);
+}
+
+function _equals(a, b, stackA, stackB) {
+  if (_objectIs(a, b)) {
+    return true;
+  }
+
+  var typeA = type(a);
+
+  if (typeA !== type(b)) {
+    return false;
+  }
+
+  if (a == null || b == null) {
+    return false;
+  }
+
+  if (typeof a['fantasy-land/equals'] === 'function' || typeof b['fantasy-land/equals'] === 'function') {
+    return typeof a['fantasy-land/equals'] === 'function' && a['fantasy-land/equals'](b) && typeof b['fantasy-land/equals'] === 'function' && b['fantasy-land/equals'](a);
+  }
+
+  if (typeof a.equals === 'function' || typeof b.equals === 'function') {
+    return typeof a.equals === 'function' && a.equals(b) && typeof b.equals === 'function' && b.equals(a);
+  }
+
+  switch (typeA) {
+    case 'Arguments':
+    case 'Array':
+    case 'Object':
+      if (typeof a.constructor === 'function' && _functionName(a.constructor) === 'Promise') {
+        return a === b;
+      }
+      break;
+    case 'Boolean':
+    case 'Number':
+    case 'String':
+      if (!(typeof a === typeof b && _objectIs(a.valueOf(), b.valueOf()))) {
+        return false;
+      }
+      break;
+    case 'Date':
+      if (!_objectIs(a.valueOf(), b.valueOf())) {
+        return false;
+      }
+      break;
+    case 'Error':
+      return a.name === b.name && a.message === b.message;
+    case 'RegExp':
+      if (!(a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline && a.sticky === b.sticky && a.unicode === b.unicode)) {
+        return false;
+      }
+      break;
+  }
+
+  var idx = stackA.length - 1;
+  while (idx >= 0) {
+    if (stackA[idx] === a) {
+      return stackB[idx] === b;
+    }
+    idx -= 1;
+  }
+
+  switch (typeA) {
+    case 'Map':
+      if (a.size !== b.size) {
+        return false;
+      }
+
+      return _uniqContentEquals(a.entries(), b.entries(), stackA.concat([a]), stackB.concat([b]));
+    case 'Set':
+      if (a.size !== b.size) {
+        return false;
+      }
+
+      return _uniqContentEquals(a.values(), b.values(), stackA.concat([a]), stackB.concat([b]));
+    case 'Arguments':
+    case 'Array':
+    case 'Object':
+    case 'Boolean':
+    case 'Number':
+    case 'String':
+    case 'Date':
+    case 'Error':
+    case 'RegExp':
+    case 'Int8Array':
+    case 'Uint8Array':
+    case 'Uint8ClampedArray':
+    case 'Int16Array':
+    case 'Uint16Array':
+    case 'Int32Array':
+    case 'Uint32Array':
+    case 'Float32Array':
+    case 'Float64Array':
+    case 'ArrayBuffer':
+      break;
+    default:
+      // Values of other types are only equal if identical.
+      return false;
+  }
+
+  var keysA = keys(a);
+  if (keysA.length !== keys(b).length) {
+    return false;
+  }
+
+  var extendedStackA = stackA.concat([a]);
+  var extendedStackB = stackB.concat([b]);
+
+  idx = keysA.length - 1;
+  while (idx >= 0) {
+    var key = keysA[idx];
+    if (!(_has(key, b) && _equals(b[key], a[key], extendedStackA, extendedStackB))) {
+      return false;
+    }
+    idx -= 1;
+  }
+  return true;
+}
+module.exports = _equals;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_filter.js b/server/node_modules/ramda/src/internal/_filter.js
new file mode 100644
index 0000000000000000000000000000000000000000..6eeabb02a2b53e218bdafa789f95f2e0c24eb94c
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_filter.js
@@ -0,0 +1,14 @@
+function _filter(fn, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [];
+
+  while (idx < len) {
+    if (fn(list[idx])) {
+      result[result.length] = list[idx];
+    }
+    idx += 1;
+  }
+  return result;
+}
+module.exports = _filter;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_flatCat.js b/server/node_modules/ramda/src/internal/_flatCat.js
new file mode 100644
index 0000000000000000000000000000000000000000..6017a1b2cfc31c6e3b498ebdb6dda6edf63e4cc5
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_flatCat.js
@@ -0,0 +1,35 @@
+var _forceReduced = /*#__PURE__*/require('./_forceReduced');
+
+var _isArrayLike = /*#__PURE__*/require('./_isArrayLike');
+
+var _reduce = /*#__PURE__*/require('./_reduce');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var preservingReduced = function (xf) {
+  return {
+    '@@transducer/init': _xfBase.init,
+    '@@transducer/result': function (result) {
+      return xf['@@transducer/result'](result);
+    },
+    '@@transducer/step': function (result, input) {
+      var ret = xf['@@transducer/step'](result, input);
+      return ret['@@transducer/reduced'] ? _forceReduced(ret) : ret;
+    }
+  };
+};
+
+var _flatCat = function _xcat(xf) {
+  var rxf = preservingReduced(xf);
+  return {
+    '@@transducer/init': _xfBase.init,
+    '@@transducer/result': function (result) {
+      return rxf['@@transducer/result'](result);
+    },
+    '@@transducer/step': function (result, input) {
+      return !_isArrayLike(input) ? _reduce(rxf, result, [input]) : _reduce(rxf, result, input);
+    }
+  };
+};
+
+module.exports = _flatCat;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_forceReduced.js b/server/node_modules/ramda/src/internal/_forceReduced.js
new file mode 100644
index 0000000000000000000000000000000000000000..71fdc4b45e9c15facc090a718d60b81be06f6853
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_forceReduced.js
@@ -0,0 +1,7 @@
+function _forceReduced(x) {
+  return {
+    '@@transducer/value': x,
+    '@@transducer/reduced': true
+  };
+}
+module.exports = _forceReduced;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_functionName.js b/server/node_modules/ramda/src/internal/_functionName.js
new file mode 100644
index 0000000000000000000000000000000000000000..55ac1cd84d9d7df96dcd6dd4dc018c508e981497
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_functionName.js
@@ -0,0 +1,6 @@
+function _functionName(f) {
+  // String(x => x) evaluates to "x => x", so the pattern may not match.
+  var match = String(f).match(/^function (\w*)/);
+  return match == null ? '' : match[1];
+}
+module.exports = _functionName;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_functionsWith.js b/server/node_modules/ramda/src/internal/_functionsWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..33ea6b986fff8b5a593d832eec339d68097c72a4
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_functionsWith.js
@@ -0,0 +1,17 @@
+var _filter = /*#__PURE__*/require('./_filter');
+
+/**
+ * @private
+ * @param {Function} fn The strategy for extracting function names from an object
+ * @return {Function} A function that takes an object and returns an array of function names.
+ */
+
+
+function _functionsWith(fn) {
+  return function (obj) {
+    return _filter(function (key) {
+      return typeof obj[key] === 'function';
+    }, fn(obj));
+  };
+}
+module.exports = _functionsWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_has.js b/server/node_modules/ramda/src/internal/_has.js
new file mode 100644
index 0000000000000000000000000000000000000000..40c109259436a926d0e7e51b24349f8872c05a04
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_has.js
@@ -0,0 +1,4 @@
+function _has(prop, obj) {
+  return Object.prototype.hasOwnProperty.call(obj, prop);
+}
+module.exports = _has;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_identity.js b/server/node_modules/ramda/src/internal/_identity.js
new file mode 100644
index 0000000000000000000000000000000000000000..27b6c42e0909dbfb6b8ab85fd532db63175633fd
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_identity.js
@@ -0,0 +1,4 @@
+function _identity(x) {
+  return x;
+}
+module.exports = _identity;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_includes.js b/server/node_modules/ramda/src/internal/_includes.js
new file mode 100644
index 0000000000000000000000000000000000000000..45dcadad1a7a4de95b69169114a1843f0cdfc07e
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_includes.js
@@ -0,0 +1,6 @@
+var _indexOf = /*#__PURE__*/require('./_indexOf');
+
+function _includes(a, list) {
+  return _indexOf(list, a, 0) >= 0;
+}
+module.exports = _includes;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_includesWith.js b/server/node_modules/ramda/src/internal/_includesWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..55d0210b4ed71c106d04190be1ebdc8c3f2e1e26
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_includesWith.js
@@ -0,0 +1,13 @@
+function _includesWith(pred, x, list) {
+  var idx = 0;
+  var len = list.length;
+
+  while (idx < len) {
+    if (pred(x, list[idx])) {
+      return true;
+    }
+    idx += 1;
+  }
+  return false;
+}
+module.exports = _includesWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_indexOf.js b/server/node_modules/ramda/src/internal/_indexOf.js
new file mode 100644
index 0000000000000000000000000000000000000000..26261c3d527a5acd41dae5de768539375bc59783
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_indexOf.js
@@ -0,0 +1,57 @@
+var equals = /*#__PURE__*/require('../equals');
+
+function _indexOf(list, a, idx) {
+  var inf, item;
+  // Array.prototype.indexOf doesn't exist below IE9
+  if (typeof list.indexOf === 'function') {
+    switch (typeof a) {
+      case 'number':
+        if (a === 0) {
+          // manually crawl the list to distinguish between +0 and -0
+          inf = 1 / a;
+          while (idx < list.length) {
+            item = list[idx];
+            if (item === 0 && 1 / item === inf) {
+              return idx;
+            }
+            idx += 1;
+          }
+          return -1;
+        } else if (a !== a) {
+          // NaN
+          while (idx < list.length) {
+            item = list[idx];
+            if (typeof item === 'number' && item !== item) {
+              return idx;
+            }
+            idx += 1;
+          }
+          return -1;
+        }
+        // non-zero numbers can utilise Set
+        return list.indexOf(a, idx);
+
+      // all these types can utilise Set
+      case 'string':
+      case 'boolean':
+      case 'function':
+      case 'undefined':
+        return list.indexOf(a, idx);
+
+      case 'object':
+        if (a === null) {
+          // null can utilise Set
+          return list.indexOf(a, idx);
+        }
+    }
+  }
+  // anything else not covered above, defer to R.equals
+  while (idx < list.length) {
+    if (equals(list[idx], a)) {
+      return idx;
+    }
+    idx += 1;
+  }
+  return -1;
+}
+module.exports = _indexOf;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_isArguments.js b/server/node_modules/ramda/src/internal/_isArguments.js
new file mode 100644
index 0000000000000000000000000000000000000000..3dc9b5add14a3d3855638fab11968dfe305dc12e
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_isArguments.js
@@ -0,0 +1,12 @@
+var _has = /*#__PURE__*/require('./_has');
+
+var toString = Object.prototype.toString;
+var _isArguments = /*#__PURE__*/function () {
+  return toString.call(arguments) === '[object Arguments]' ? function _isArguments(x) {
+    return toString.call(x) === '[object Arguments]';
+  } : function _isArguments(x) {
+    return _has('callee', x);
+  };
+}();
+
+module.exports = _isArguments;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_isArray.js b/server/node_modules/ramda/src/internal/_isArray.js
new file mode 100644
index 0000000000000000000000000000000000000000..fc8bcc3a113b3971e4290331fd2f4087d7d86473
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_isArray.js
@@ -0,0 +1,15 @@
+/**
+ * Tests whether or not an object is an array.
+ *
+ * @private
+ * @param {*} val The object to test.
+ * @return {Boolean} `true` if `val` is an array, `false` otherwise.
+ * @example
+ *
+ *      _isArray([]); //=> true
+ *      _isArray(null); //=> false
+ *      _isArray({}); //=> false
+ */
+module.exports = Array.isArray || function _isArray(val) {
+  return val != null && val.length >= 0 && Object.prototype.toString.call(val) === '[object Array]';
+};
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_isArrayLike.js b/server/node_modules/ramda/src/internal/_isArrayLike.js
new file mode 100644
index 0000000000000000000000000000000000000000..e523c38a9256354e97a13d7d5e784d8d568a0d91
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_isArrayLike.js
@@ -0,0 +1,50 @@
+var _curry1 = /*#__PURE__*/require('./_curry1');
+
+var _isArray = /*#__PURE__*/require('./_isArray');
+
+var _isString = /*#__PURE__*/require('./_isString');
+
+/**
+ * Tests whether or not an object is similar to an array.
+ *
+ * @private
+ * @category Type
+ * @category List
+ * @sig * -> Boolean
+ * @param {*} x The object to test.
+ * @return {Boolean} `true` if `x` has a numeric length property and extreme indices defined; `false` otherwise.
+ * @example
+ *
+ *      _isArrayLike([]); //=> true
+ *      _isArrayLike(true); //=> false
+ *      _isArrayLike({}); //=> false
+ *      _isArrayLike({length: 10}); //=> false
+ *      _isArrayLike({0: 'zero', 9: 'nine', length: 10}); //=> true
+ */
+
+
+var _isArrayLike = /*#__PURE__*/_curry1(function isArrayLike(x) {
+  if (_isArray(x)) {
+    return true;
+  }
+  if (!x) {
+    return false;
+  }
+  if (typeof x !== 'object') {
+    return false;
+  }
+  if (_isString(x)) {
+    return false;
+  }
+  if (x.nodeType === 1) {
+    return !!x.length;
+  }
+  if (x.length === 0) {
+    return true;
+  }
+  if (x.length > 0) {
+    return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1);
+  }
+  return false;
+});
+module.exports = _isArrayLike;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_isFunction.js b/server/node_modules/ramda/src/internal/_isFunction.js
new file mode 100644
index 0000000000000000000000000000000000000000..bef31f7ee68d9199a5f3ac23869025b7f37db361
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_isFunction.js
@@ -0,0 +1,4 @@
+function _isFunction(x) {
+  return Object.prototype.toString.call(x) === '[object Function]';
+}
+module.exports = _isFunction;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_isInteger.js b/server/node_modules/ramda/src/internal/_isInteger.js
new file mode 100644
index 0000000000000000000000000000000000000000..458977fd99c537c69e46f36a82a868744cd90b1b
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_isInteger.js
@@ -0,0 +1,11 @@
+/**
+ * Determine if the passed argument is an integer.
+ *
+ * @private
+ * @param {*} n
+ * @category Type
+ * @return {Boolean}
+ */
+module.exports = Number.isInteger || function _isInteger(n) {
+  return n << 0 === n;
+};
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_isNumber.js b/server/node_modules/ramda/src/internal/_isNumber.js
new file mode 100644
index 0000000000000000000000000000000000000000..cff9266315c9a80b846a06218d2e2e4f99c41f49
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_isNumber.js
@@ -0,0 +1,4 @@
+function _isNumber(x) {
+  return Object.prototype.toString.call(x) === '[object Number]';
+}
+module.exports = _isNumber;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_isObject.js b/server/node_modules/ramda/src/internal/_isObject.js
new file mode 100644
index 0000000000000000000000000000000000000000..308c65e04ee3d03c474ca54ba7a9a558aecd3739
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_isObject.js
@@ -0,0 +1,4 @@
+function _isObject(x) {
+  return Object.prototype.toString.call(x) === '[object Object]';
+}
+module.exports = _isObject;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_isPlaceholder.js b/server/node_modules/ramda/src/internal/_isPlaceholder.js
new file mode 100644
index 0000000000000000000000000000000000000000..aa082820afa3b6fff251f688b93087d6a6ab2c1b
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_isPlaceholder.js
@@ -0,0 +1,4 @@
+function _isPlaceholder(a) {
+       return a != null && typeof a === 'object' && a['@@functional/placeholder'] === true;
+}
+module.exports = _isPlaceholder;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_isRegExp.js b/server/node_modules/ramda/src/internal/_isRegExp.js
new file mode 100644
index 0000000000000000000000000000000000000000..73570e8e3345b0b99f6cd0c1126ec9d6388b69c1
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_isRegExp.js
@@ -0,0 +1,4 @@
+function _isRegExp(x) {
+  return Object.prototype.toString.call(x) === '[object RegExp]';
+}
+module.exports = _isRegExp;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_isString.js b/server/node_modules/ramda/src/internal/_isString.js
new file mode 100644
index 0000000000000000000000000000000000000000..4686d22a2ed83bc042f8709cbeac741cdc6da54b
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_isString.js
@@ -0,0 +1,4 @@
+function _isString(x) {
+  return Object.prototype.toString.call(x) === '[object String]';
+}
+module.exports = _isString;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_isTransformer.js b/server/node_modules/ramda/src/internal/_isTransformer.js
new file mode 100644
index 0000000000000000000000000000000000000000..b2e9e17d32335f71f680a1ffed7ce461f95f64eb
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_isTransformer.js
@@ -0,0 +1,4 @@
+function _isTransformer(obj) {
+  return obj != null && typeof obj['@@transducer/step'] === 'function';
+}
+module.exports = _isTransformer;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_makeFlat.js b/server/node_modules/ramda/src/internal/_makeFlat.js
new file mode 100644
index 0000000000000000000000000000000000000000..7bf8540cfd624b554c5814e73cacba966f157590
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_makeFlat.js
@@ -0,0 +1,35 @@
+var _isArrayLike = /*#__PURE__*/require('./_isArrayLike');
+
+/**
+ * `_makeFlat` is a helper function that returns a one-level or fully recursive
+ * function based on the flag passed in.
+ *
+ * @private
+ */
+
+
+function _makeFlat(recursive) {
+  return function flatt(list) {
+    var value, jlen, j;
+    var result = [];
+    var idx = 0;
+    var ilen = list.length;
+
+    while (idx < ilen) {
+      if (_isArrayLike(list[idx])) {
+        value = recursive ? flatt(list[idx]) : list[idx];
+        j = 0;
+        jlen = value.length;
+        while (j < jlen) {
+          result[result.length] = value[j];
+          j += 1;
+        }
+      } else {
+        result[result.length] = list[idx];
+      }
+      idx += 1;
+    }
+    return result;
+  };
+}
+module.exports = _makeFlat;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_map.js b/server/node_modules/ramda/src/internal/_map.js
new file mode 100644
index 0000000000000000000000000000000000000000..eb723ffbbfe6b6bb0c517a370420d5e40ee7d0d4
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_map.js
@@ -0,0 +1,11 @@
+function _map(fn, functor) {
+  var idx = 0;
+  var len = functor.length;
+  var result = Array(len);
+  while (idx < len) {
+    result[idx] = fn(functor[idx]);
+    idx += 1;
+  }
+  return result;
+}
+module.exports = _map;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_objectAssign.js b/server/node_modules/ramda/src/internal/_objectAssign.js
new file mode 100644
index 0000000000000000000000000000000000000000..056995a525a238f35e192e2c1818ba385520ce63
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_objectAssign.js
@@ -0,0 +1,28 @@
+var _has = /*#__PURE__*/require('./_has');
+
+// Based on https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
+
+
+function _objectAssign(target) {
+  if (target == null) {
+    throw new TypeError('Cannot convert undefined or null to object');
+  }
+
+  var output = Object(target);
+  var idx = 1;
+  var length = arguments.length;
+  while (idx < length) {
+    var source = arguments[idx];
+    if (source != null) {
+      for (var nextKey in source) {
+        if (_has(nextKey, source)) {
+          output[nextKey] = source[nextKey];
+        }
+      }
+    }
+    idx += 1;
+  }
+  return output;
+}
+
+module.exports = typeof Object.assign === 'function' ? Object.assign : _objectAssign;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_objectIs.js b/server/node_modules/ramda/src/internal/_objectIs.js
new file mode 100644
index 0000000000000000000000000000000000000000..0f8b07e88b1305ffdcf480fb8c2b92de709e6bc4
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_objectIs.js
@@ -0,0 +1,14 @@
+// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
+function _objectIs(a, b) {
+  // SameValue algorithm
+  if (a === b) {
+    // Steps 1-5, 7-10
+    // Steps 6.b-6.e: +0 != -0
+    return a !== 0 || 1 / a === 1 / b;
+  } else {
+    // Step 6.a: NaN == NaN
+    return a !== a && b !== b;
+  }
+}
+
+module.exports = typeof Object.is === 'function' ? Object.is : _objectIs;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_of.js b/server/node_modules/ramda/src/internal/_of.js
new file mode 100644
index 0000000000000000000000000000000000000000..0c03648a8c3a23f80d72ae4c67ca904b340883ce
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_of.js
@@ -0,0 +1,4 @@
+function _of(x) {
+  return [x];
+}
+module.exports = _of;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_pipe.js b/server/node_modules/ramda/src/internal/_pipe.js
new file mode 100644
index 0000000000000000000000000000000000000000..e46f8c5b8133ec1530a3c4b6a2f843965dd789e4
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_pipe.js
@@ -0,0 +1,6 @@
+function _pipe(f, g) {
+  return function () {
+    return g.call(this, f.apply(this, arguments));
+  };
+}
+module.exports = _pipe;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_pipeP.js b/server/node_modules/ramda/src/internal/_pipeP.js
new file mode 100644
index 0000000000000000000000000000000000000000..3e2a9d60ec72cb7e6a4ae34d6e0d0d49b5cb9844
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_pipeP.js
@@ -0,0 +1,9 @@
+function _pipeP(f, g) {
+  return function () {
+    var ctx = this;
+    return f.apply(ctx, arguments).then(function (x) {
+      return g.call(ctx, x);
+    });
+  };
+}
+module.exports = _pipeP;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_quote.js b/server/node_modules/ramda/src/internal/_quote.js
new file mode 100644
index 0000000000000000000000000000000000000000..5717ae45a4d0646c9d4b6cede71057e4fda91fb3
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_quote.js
@@ -0,0 +1,7 @@
+function _quote(s) {
+  var escaped = s.replace(/\\/g, '\\\\').replace(/[\b]/g, '\\b') // \b matches word boundary; [\b] matches backspace
+  .replace(/\f/g, '\\f').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t').replace(/\v/g, '\\v').replace(/\0/g, '\\0');
+
+  return '"' + escaped.replace(/"/g, '\\"') + '"';
+}
+module.exports = _quote;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_reduce.js b/server/node_modules/ramda/src/internal/_reduce.js
new file mode 100644
index 0000000000000000000000000000000000000000..451ee97364be5015bf495c2b6edcf8a55bd290b0
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_reduce.js
@@ -0,0 +1,62 @@
+var _isArrayLike = /*#__PURE__*/require('./_isArrayLike');
+
+var _xwrap = /*#__PURE__*/require('./_xwrap');
+
+var bind = /*#__PURE__*/require('../bind');
+
+function _arrayReduce(xf, acc, list) {
+  var idx = 0;
+  var len = list.length;
+  while (idx < len) {
+    acc = xf['@@transducer/step'](acc, list[idx]);
+    if (acc && acc['@@transducer/reduced']) {
+      acc = acc['@@transducer/value'];
+      break;
+    }
+    idx += 1;
+  }
+  return xf['@@transducer/result'](acc);
+}
+
+function _iterableReduce(xf, acc, iter) {
+  var step = iter.next();
+  while (!step.done) {
+    acc = xf['@@transducer/step'](acc, step.value);
+    if (acc && acc['@@transducer/reduced']) {
+      acc = acc['@@transducer/value'];
+      break;
+    }
+    step = iter.next();
+  }
+  return xf['@@transducer/result'](acc);
+}
+
+function _methodReduce(xf, acc, obj, methodName) {
+  return xf['@@transducer/result'](obj[methodName](bind(xf['@@transducer/step'], xf), acc));
+}
+
+var symIterator = typeof Symbol !== 'undefined' ? Symbol.iterator : '@@iterator';
+
+function _reduce(fn, acc, list) {
+  if (typeof fn === 'function') {
+    fn = _xwrap(fn);
+  }
+  if (_isArrayLike(list)) {
+    return _arrayReduce(fn, acc, list);
+  }
+  if (typeof list['fantasy-land/reduce'] === 'function') {
+    return _methodReduce(fn, acc, list, 'fantasy-land/reduce');
+  }
+  if (list[symIterator] != null) {
+    return _iterableReduce(fn, acc, list[symIterator]());
+  }
+  if (typeof list.next === 'function') {
+    return _iterableReduce(fn, acc, list);
+  }
+  if (typeof list.reduce === 'function') {
+    return _methodReduce(fn, acc, list, 'reduce');
+  }
+
+  throw new TypeError('reduce: list must be array or iterable');
+}
+module.exports = _reduce;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_reduced.js b/server/node_modules/ramda/src/internal/_reduced.js
new file mode 100644
index 0000000000000000000000000000000000000000..db75e6c1b3d5ee26b5857192ba7688e020d0f19a
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_reduced.js
@@ -0,0 +1,7 @@
+function _reduced(x) {
+  return x && x['@@transducer/reduced'] ? x : {
+    '@@transducer/value': x,
+    '@@transducer/reduced': true
+  };
+}
+module.exports = _reduced;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_stepCat.js b/server/node_modules/ramda/src/internal/_stepCat.js
new file mode 100644
index 0000000000000000000000000000000000000000..5c605adb45c95b86b727144f654baaf037b47fd1
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_stepCat.js
@@ -0,0 +1,49 @@
+var _objectAssign = /*#__PURE__*/require('./_objectAssign');
+
+var _identity = /*#__PURE__*/require('./_identity');
+
+var _isArrayLike = /*#__PURE__*/require('./_isArrayLike');
+
+var _isTransformer = /*#__PURE__*/require('./_isTransformer');
+
+var objOf = /*#__PURE__*/require('../objOf');
+
+var _stepCatArray = {
+  '@@transducer/init': Array,
+  '@@transducer/step': function (xs, x) {
+    xs.push(x);
+    return xs;
+  },
+  '@@transducer/result': _identity
+};
+var _stepCatString = {
+  '@@transducer/init': String,
+  '@@transducer/step': function (a, b) {
+    return a + b;
+  },
+  '@@transducer/result': _identity
+};
+var _stepCatObject = {
+  '@@transducer/init': Object,
+  '@@transducer/step': function (result, input) {
+    return _objectAssign(result, _isArrayLike(input) ? objOf(input[0], input[1]) : input);
+  },
+  '@@transducer/result': _identity
+};
+
+function _stepCat(obj) {
+  if (_isTransformer(obj)) {
+    return obj;
+  }
+  if (_isArrayLike(obj)) {
+    return _stepCatArray;
+  }
+  if (typeof obj === 'string') {
+    return _stepCatString;
+  }
+  if (typeof obj === 'object') {
+    return _stepCatObject;
+  }
+  throw new Error('Cannot create transformer for ' + obj);
+}
+module.exports = _stepCat;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_toISOString.js b/server/node_modules/ramda/src/internal/_toISOString.js
new file mode 100644
index 0000000000000000000000000000000000000000..3c1da8a7f4c8ba20de6b6adbaff4eb351765716c
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_toISOString.js
@@ -0,0 +1,14 @@
+/**
+ * Polyfill from <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString>.
+ */
+var pad = function pad(n) {
+  return (n < 10 ? '0' : '') + n;
+};
+
+var _toISOString = typeof Date.prototype.toISOString === 'function' ? function _toISOString(d) {
+  return d.toISOString();
+} : function _toISOString(d) {
+  return d.getUTCFullYear() + '-' + pad(d.getUTCMonth() + 1) + '-' + pad(d.getUTCDate()) + 'T' + pad(d.getUTCHours()) + ':' + pad(d.getUTCMinutes()) + ':' + pad(d.getUTCSeconds()) + '.' + (d.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 'Z';
+};
+
+module.exports = _toISOString;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_toString.js b/server/node_modules/ramda/src/internal/_toString.js
new file mode 100644
index 0000000000000000000000000000000000000000..3b8086d16b94c85b5c82ce5dd26db46f61cdb93b
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_toString.js
@@ -0,0 +1,56 @@
+var _includes = /*#__PURE__*/require('./_includes');
+
+var _map = /*#__PURE__*/require('./_map');
+
+var _quote = /*#__PURE__*/require('./_quote');
+
+var _toISOString = /*#__PURE__*/require('./_toISOString');
+
+var keys = /*#__PURE__*/require('../keys');
+
+var reject = /*#__PURE__*/require('../reject');
+
+function _toString(x, seen) {
+  var recur = function recur(y) {
+    var xs = seen.concat([x]);
+    return _includes(y, xs) ? '<Circular>' : _toString(y, xs);
+  };
+
+  //  mapPairs :: (Object, [String]) -> [String]
+  var mapPairs = function (obj, keys) {
+    return _map(function (k) {
+      return _quote(k) + ': ' + recur(obj[k]);
+    }, keys.slice().sort());
+  };
+
+  switch (Object.prototype.toString.call(x)) {
+    case '[object Arguments]':
+      return '(function() { return arguments; }(' + _map(recur, x).join(', ') + '))';
+    case '[object Array]':
+      return '[' + _map(recur, x).concat(mapPairs(x, reject(function (k) {
+        return (/^\d+$/.test(k)
+        );
+      }, keys(x)))).join(', ') + ']';
+    case '[object Boolean]':
+      return typeof x === 'object' ? 'new Boolean(' + recur(x.valueOf()) + ')' : x.toString();
+    case '[object Date]':
+      return 'new Date(' + (isNaN(x.valueOf()) ? recur(NaN) : _quote(_toISOString(x))) + ')';
+    case '[object Null]':
+      return 'null';
+    case '[object Number]':
+      return typeof x === 'object' ? 'new Number(' + recur(x.valueOf()) + ')' : 1 / x === -Infinity ? '-0' : x.toString(10);
+    case '[object String]':
+      return typeof x === 'object' ? 'new String(' + recur(x.valueOf()) + ')' : _quote(x);
+    case '[object Undefined]':
+      return 'undefined';
+    default:
+      if (typeof x.toString === 'function') {
+        var repr = x.toString();
+        if (repr !== '[object Object]') {
+          return repr;
+        }
+      }
+      return '{' + mapPairs(x, keys(x)).join(', ') + '}';
+  }
+}
+module.exports = _toString;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xall.js b/server/node_modules/ramda/src/internal/_xall.js
new file mode 100644
index 0000000000000000000000000000000000000000..db108008adba9c4804feefce8626865b1e7dc314
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xall.js
@@ -0,0 +1,35 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _reduced = /*#__PURE__*/require('./_reduced');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XAll = /*#__PURE__*/function () {
+
+  function XAll(f, xf) {
+    this.xf = xf;
+    this.f = f;
+    this.all = true;
+  }
+  XAll.prototype['@@transducer/init'] = _xfBase.init;
+  XAll.prototype['@@transducer/result'] = function (result) {
+    if (this.all) {
+      result = this.xf['@@transducer/step'](result, true);
+    }
+    return this.xf['@@transducer/result'](result);
+  };
+  XAll.prototype['@@transducer/step'] = function (result, input) {
+    if (!this.f(input)) {
+      this.all = false;
+      result = _reduced(this.xf['@@transducer/step'](result, false));
+    }
+    return result;
+  };
+
+  return XAll;
+}();
+
+var _xall = /*#__PURE__*/_curry2(function _xall(f, xf) {
+  return new XAll(f, xf);
+});
+module.exports = _xall;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xany.js b/server/node_modules/ramda/src/internal/_xany.js
new file mode 100644
index 0000000000000000000000000000000000000000..8fce297c7c2e8b8416c2703f7ddef0ca3f39abcc
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xany.js
@@ -0,0 +1,35 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _reduced = /*#__PURE__*/require('./_reduced');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XAny = /*#__PURE__*/function () {
+
+  function XAny(f, xf) {
+    this.xf = xf;
+    this.f = f;
+    this.any = false;
+  }
+  XAny.prototype['@@transducer/init'] = _xfBase.init;
+  XAny.prototype['@@transducer/result'] = function (result) {
+    if (!this.any) {
+      result = this.xf['@@transducer/step'](result, false);
+    }
+    return this.xf['@@transducer/result'](result);
+  };
+  XAny.prototype['@@transducer/step'] = function (result, input) {
+    if (this.f(input)) {
+      this.any = true;
+      result = _reduced(this.xf['@@transducer/step'](result, true));
+    }
+    return result;
+  };
+
+  return XAny;
+}();
+
+var _xany = /*#__PURE__*/_curry2(function _xany(f, xf) {
+  return new XAny(f, xf);
+});
+module.exports = _xany;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xaperture.js b/server/node_modules/ramda/src/internal/_xaperture.js
new file mode 100644
index 0000000000000000000000000000000000000000..1433ff95b4ef2b36d52def482295da041ee9efcc
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xaperture.js
@@ -0,0 +1,42 @@
+var _concat = /*#__PURE__*/require('./_concat');
+
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XAperture = /*#__PURE__*/function () {
+
+  function XAperture(n, xf) {
+    this.xf = xf;
+    this.pos = 0;
+    this.full = false;
+    this.acc = new Array(n);
+  }
+  XAperture.prototype['@@transducer/init'] = _xfBase.init;
+  XAperture.prototype['@@transducer/result'] = function (result) {
+    this.acc = null;
+    return this.xf['@@transducer/result'](result);
+  };
+  XAperture.prototype['@@transducer/step'] = function (result, input) {
+    this.store(input);
+    return this.full ? this.xf['@@transducer/step'](result, this.getCopy()) : result;
+  };
+  XAperture.prototype.store = function (input) {
+    this.acc[this.pos] = input;
+    this.pos += 1;
+    if (this.pos === this.acc.length) {
+      this.pos = 0;
+      this.full = true;
+    }
+  };
+  XAperture.prototype.getCopy = function () {
+    return _concat(Array.prototype.slice.call(this.acc, this.pos), Array.prototype.slice.call(this.acc, 0, this.pos));
+  };
+
+  return XAperture;
+}();
+
+var _xaperture = /*#__PURE__*/_curry2(function _xaperture(n, xf) {
+  return new XAperture(n, xf);
+});
+module.exports = _xaperture;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xchain.js b/server/node_modules/ramda/src/internal/_xchain.js
new file mode 100644
index 0000000000000000000000000000000000000000..77e7eeba989a97df9ef30343e3595e2f80d273f7
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xchain.js
@@ -0,0 +1,10 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _flatCat = /*#__PURE__*/require('./_flatCat');
+
+var map = /*#__PURE__*/require('../map');
+
+var _xchain = /*#__PURE__*/_curry2(function _xchain(f, xf) {
+  return map(f, _flatCat(xf));
+});
+module.exports = _xchain;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xdrop.js b/server/node_modules/ramda/src/internal/_xdrop.js
new file mode 100644
index 0000000000000000000000000000000000000000..08133b3ab87d8d712e1027135f858a52fa210c51
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xdrop.js
@@ -0,0 +1,27 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XDrop = /*#__PURE__*/function () {
+
+  function XDrop(n, xf) {
+    this.xf = xf;
+    this.n = n;
+  }
+  XDrop.prototype['@@transducer/init'] = _xfBase.init;
+  XDrop.prototype['@@transducer/result'] = _xfBase.result;
+  XDrop.prototype['@@transducer/step'] = function (result, input) {
+    if (this.n > 0) {
+      this.n -= 1;
+      return result;
+    }
+    return this.xf['@@transducer/step'](result, input);
+  };
+
+  return XDrop;
+}();
+
+var _xdrop = /*#__PURE__*/_curry2(function _xdrop(n, xf) {
+  return new XDrop(n, xf);
+});
+module.exports = _xdrop;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xdropLast.js b/server/node_modules/ramda/src/internal/_xdropLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..10625e5edcef9a463a244147b5006d5dbec81932
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xdropLast.js
@@ -0,0 +1,40 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XDropLast = /*#__PURE__*/function () {
+
+  function XDropLast(n, xf) {
+    this.xf = xf;
+    this.pos = 0;
+    this.full = false;
+    this.acc = new Array(n);
+  }
+  XDropLast.prototype['@@transducer/init'] = _xfBase.init;
+  XDropLast.prototype['@@transducer/result'] = function (result) {
+    this.acc = null;
+    return this.xf['@@transducer/result'](result);
+  };
+  XDropLast.prototype['@@transducer/step'] = function (result, input) {
+    if (this.full) {
+      result = this.xf['@@transducer/step'](result, this.acc[this.pos]);
+    }
+    this.store(input);
+    return result;
+  };
+  XDropLast.prototype.store = function (input) {
+    this.acc[this.pos] = input;
+    this.pos += 1;
+    if (this.pos === this.acc.length) {
+      this.pos = 0;
+      this.full = true;
+    }
+  };
+
+  return XDropLast;
+}();
+
+var _xdropLast = /*#__PURE__*/_curry2(function _xdropLast(n, xf) {
+  return new XDropLast(n, xf);
+});
+module.exports = _xdropLast;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xdropLastWhile.js b/server/node_modules/ramda/src/internal/_xdropLastWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..1f3e6b7b0f922d5408c59b5fa40f1b4f856e034c
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xdropLastWhile.js
@@ -0,0 +1,38 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _reduce = /*#__PURE__*/require('./_reduce');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XDropLastWhile = /*#__PURE__*/function () {
+
+  function XDropLastWhile(fn, xf) {
+    this.f = fn;
+    this.retained = [];
+    this.xf = xf;
+  }
+  XDropLastWhile.prototype['@@transducer/init'] = _xfBase.init;
+  XDropLastWhile.prototype['@@transducer/result'] = function (result) {
+    this.retained = null;
+    return this.xf['@@transducer/result'](result);
+  };
+  XDropLastWhile.prototype['@@transducer/step'] = function (result, input) {
+    return this.f(input) ? this.retain(result, input) : this.flush(result, input);
+  };
+  XDropLastWhile.prototype.flush = function (result, input) {
+    result = _reduce(this.xf['@@transducer/step'], result, this.retained);
+    this.retained = [];
+    return this.xf['@@transducer/step'](result, input);
+  };
+  XDropLastWhile.prototype.retain = function (result, input) {
+    this.retained.push(input);
+    return result;
+  };
+
+  return XDropLastWhile;
+}();
+
+var _xdropLastWhile = /*#__PURE__*/_curry2(function _xdropLastWhile(fn, xf) {
+  return new XDropLastWhile(fn, xf);
+});
+module.exports = _xdropLastWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xdropRepeatsWith.js b/server/node_modules/ramda/src/internal/_xdropRepeatsWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e1ae7c638ab1d7527551fb07feb0235c5a30afd
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xdropRepeatsWith.js
@@ -0,0 +1,33 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XDropRepeatsWith = /*#__PURE__*/function () {
+
+  function XDropRepeatsWith(pred, xf) {
+    this.xf = xf;
+    this.pred = pred;
+    this.lastValue = undefined;
+    this.seenFirstValue = false;
+  }
+
+  XDropRepeatsWith.prototype['@@transducer/init'] = _xfBase.init;
+  XDropRepeatsWith.prototype['@@transducer/result'] = _xfBase.result;
+  XDropRepeatsWith.prototype['@@transducer/step'] = function (result, input) {
+    var sameAsLast = false;
+    if (!this.seenFirstValue) {
+      this.seenFirstValue = true;
+    } else if (this.pred(this.lastValue, input)) {
+      sameAsLast = true;
+    }
+    this.lastValue = input;
+    return sameAsLast ? result : this.xf['@@transducer/step'](result, input);
+  };
+
+  return XDropRepeatsWith;
+}();
+
+var _xdropRepeatsWith = /*#__PURE__*/_curry2(function _xdropRepeatsWith(pred, xf) {
+  return new XDropRepeatsWith(pred, xf);
+});
+module.exports = _xdropRepeatsWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xdropWhile.js b/server/node_modules/ramda/src/internal/_xdropWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..33b13061186d18f46f967a919243ee0f5ab11dcc
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xdropWhile.js
@@ -0,0 +1,29 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XDropWhile = /*#__PURE__*/function () {
+
+  function XDropWhile(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XDropWhile.prototype['@@transducer/init'] = _xfBase.init;
+  XDropWhile.prototype['@@transducer/result'] = _xfBase.result;
+  XDropWhile.prototype['@@transducer/step'] = function (result, input) {
+    if (this.f) {
+      if (this.f(input)) {
+        return result;
+      }
+      this.f = null;
+    }
+    return this.xf['@@transducer/step'](result, input);
+  };
+
+  return XDropWhile;
+}();
+
+var _xdropWhile = /*#__PURE__*/_curry2(function _xdropWhile(f, xf) {
+  return new XDropWhile(f, xf);
+});
+module.exports = _xdropWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xfBase.js b/server/node_modules/ramda/src/internal/_xfBase.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb1dfeec4c5873be582c4cb9f7a8d40ce229c1f3
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xfBase.js
@@ -0,0 +1,8 @@
+module.exports = {
+  init: function () {
+    return this.xf['@@transducer/init']();
+  },
+  result: function (result) {
+    return this.xf['@@transducer/result'](result);
+  }
+};
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xfilter.js b/server/node_modules/ramda/src/internal/_xfilter.js
new file mode 100644
index 0000000000000000000000000000000000000000..bdafc43695b03be7b6e99f2551062816918b8cdc
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xfilter.js
@@ -0,0 +1,23 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XFilter = /*#__PURE__*/function () {
+
+  function XFilter(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XFilter.prototype['@@transducer/init'] = _xfBase.init;
+  XFilter.prototype['@@transducer/result'] = _xfBase.result;
+  XFilter.prototype['@@transducer/step'] = function (result, input) {
+    return this.f(input) ? this.xf['@@transducer/step'](result, input) : result;
+  };
+
+  return XFilter;
+}();
+
+var _xfilter = /*#__PURE__*/_curry2(function _xfilter(f, xf) {
+  return new XFilter(f, xf);
+});
+module.exports = _xfilter;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xfind.js b/server/node_modules/ramda/src/internal/_xfind.js
new file mode 100644
index 0000000000000000000000000000000000000000..df85db131abc3dc47f6a17cc5c8afd8a5bfc25c9
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xfind.js
@@ -0,0 +1,35 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _reduced = /*#__PURE__*/require('./_reduced');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XFind = /*#__PURE__*/function () {
+
+  function XFind(f, xf) {
+    this.xf = xf;
+    this.f = f;
+    this.found = false;
+  }
+  XFind.prototype['@@transducer/init'] = _xfBase.init;
+  XFind.prototype['@@transducer/result'] = function (result) {
+    if (!this.found) {
+      result = this.xf['@@transducer/step'](result, void 0);
+    }
+    return this.xf['@@transducer/result'](result);
+  };
+  XFind.prototype['@@transducer/step'] = function (result, input) {
+    if (this.f(input)) {
+      this.found = true;
+      result = _reduced(this.xf['@@transducer/step'](result, input));
+    }
+    return result;
+  };
+
+  return XFind;
+}();
+
+var _xfind = /*#__PURE__*/_curry2(function _xfind(f, xf) {
+  return new XFind(f, xf);
+});
+module.exports = _xfind;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xfindIndex.js b/server/node_modules/ramda/src/internal/_xfindIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..269a65f375e9e03bc73fc99618d8e3a86c3985cd
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xfindIndex.js
@@ -0,0 +1,37 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _reduced = /*#__PURE__*/require('./_reduced');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XFindIndex = /*#__PURE__*/function () {
+
+  function XFindIndex(f, xf) {
+    this.xf = xf;
+    this.f = f;
+    this.idx = -1;
+    this.found = false;
+  }
+  XFindIndex.prototype['@@transducer/init'] = _xfBase.init;
+  XFindIndex.prototype['@@transducer/result'] = function (result) {
+    if (!this.found) {
+      result = this.xf['@@transducer/step'](result, -1);
+    }
+    return this.xf['@@transducer/result'](result);
+  };
+  XFindIndex.prototype['@@transducer/step'] = function (result, input) {
+    this.idx += 1;
+    if (this.f(input)) {
+      this.found = true;
+      result = _reduced(this.xf['@@transducer/step'](result, this.idx));
+    }
+    return result;
+  };
+
+  return XFindIndex;
+}();
+
+var _xfindIndex = /*#__PURE__*/_curry2(function _xfindIndex(f, xf) {
+  return new XFindIndex(f, xf);
+});
+module.exports = _xfindIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xfindLast.js b/server/node_modules/ramda/src/internal/_xfindLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..15686e3fcc1d1def873bd1b1d72658e3ae017c4f
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xfindLast.js
@@ -0,0 +1,28 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XFindLast = /*#__PURE__*/function () {
+
+  function XFindLast(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XFindLast.prototype['@@transducer/init'] = _xfBase.init;
+  XFindLast.prototype['@@transducer/result'] = function (result) {
+    return this.xf['@@transducer/result'](this.xf['@@transducer/step'](result, this.last));
+  };
+  XFindLast.prototype['@@transducer/step'] = function (result, input) {
+    if (this.f(input)) {
+      this.last = input;
+    }
+    return result;
+  };
+
+  return XFindLast;
+}();
+
+var _xfindLast = /*#__PURE__*/_curry2(function _xfindLast(f, xf) {
+  return new XFindLast(f, xf);
+});
+module.exports = _xfindLast;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xfindLastIndex.js b/server/node_modules/ramda/src/internal/_xfindLastIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..2d5f947cc5bdc529c3947a90503dead098de217c
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xfindLastIndex.js
@@ -0,0 +1,31 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XFindLastIndex = /*#__PURE__*/function () {
+
+  function XFindLastIndex(f, xf) {
+    this.xf = xf;
+    this.f = f;
+    this.idx = -1;
+    this.lastIdx = -1;
+  }
+  XFindLastIndex.prototype['@@transducer/init'] = _xfBase.init;
+  XFindLastIndex.prototype['@@transducer/result'] = function (result) {
+    return this.xf['@@transducer/result'](this.xf['@@transducer/step'](result, this.lastIdx));
+  };
+  XFindLastIndex.prototype['@@transducer/step'] = function (result, input) {
+    this.idx += 1;
+    if (this.f(input)) {
+      this.lastIdx = this.idx;
+    }
+    return result;
+  };
+
+  return XFindLastIndex;
+}();
+
+var _xfindLastIndex = /*#__PURE__*/_curry2(function _xfindLastIndex(f, xf) {
+  return new XFindLastIndex(f, xf);
+});
+module.exports = _xfindLastIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xmap.js b/server/node_modules/ramda/src/internal/_xmap.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d602db98b41c868a191d3dca8d2e14f86bd2966
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xmap.js
@@ -0,0 +1,23 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XMap = /*#__PURE__*/function () {
+
+  function XMap(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XMap.prototype['@@transducer/init'] = _xfBase.init;
+  XMap.prototype['@@transducer/result'] = _xfBase.result;
+  XMap.prototype['@@transducer/step'] = function (result, input) {
+    return this.xf['@@transducer/step'](result, this.f(input));
+  };
+
+  return XMap;
+}();
+
+var _xmap = /*#__PURE__*/_curry2(function _xmap(f, xf) {
+  return new XMap(f, xf);
+});
+module.exports = _xmap;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xreduceBy.js b/server/node_modules/ramda/src/internal/_xreduceBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..0d26df10f624ce1385c6ab900e814ffa4e31e7a8
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xreduceBy.js
@@ -0,0 +1,44 @@
+var _curryN = /*#__PURE__*/require('./_curryN');
+
+var _has = /*#__PURE__*/require('./_has');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XReduceBy = /*#__PURE__*/function () {
+
+  function XReduceBy(valueFn, valueAcc, keyFn, xf) {
+    this.valueFn = valueFn;
+    this.valueAcc = valueAcc;
+    this.keyFn = keyFn;
+    this.xf = xf;
+    this.inputs = {};
+  }
+  XReduceBy.prototype['@@transducer/init'] = _xfBase.init;
+  XReduceBy.prototype['@@transducer/result'] = function (result) {
+    var key;
+    for (key in this.inputs) {
+      if (_has(key, this.inputs)) {
+        result = this.xf['@@transducer/step'](result, this.inputs[key]);
+        if (result['@@transducer/reduced']) {
+          result = result['@@transducer/value'];
+          break;
+        }
+      }
+    }
+    this.inputs = null;
+    return this.xf['@@transducer/result'](result);
+  };
+  XReduceBy.prototype['@@transducer/step'] = function (result, input) {
+    var key = this.keyFn(input);
+    this.inputs[key] = this.inputs[key] || [key, this.valueAcc];
+    this.inputs[key][1] = this.valueFn(this.inputs[key][1], input);
+    return result;
+  };
+
+  return XReduceBy;
+}();
+
+var _xreduceBy = /*#__PURE__*/_curryN(4, [], function _xreduceBy(valueFn, valueAcc, keyFn, xf) {
+  return new XReduceBy(valueFn, valueAcc, keyFn, xf);
+});
+module.exports = _xreduceBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xtake.js b/server/node_modules/ramda/src/internal/_xtake.js
new file mode 100644
index 0000000000000000000000000000000000000000..2a85c5bfbe861f4bdf7b393a3cfde72bc6771f5f
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xtake.js
@@ -0,0 +1,28 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _reduced = /*#__PURE__*/require('./_reduced');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XTake = /*#__PURE__*/function () {
+
+  function XTake(n, xf) {
+    this.xf = xf;
+    this.n = n;
+    this.i = 0;
+  }
+  XTake.prototype['@@transducer/init'] = _xfBase.init;
+  XTake.prototype['@@transducer/result'] = _xfBase.result;
+  XTake.prototype['@@transducer/step'] = function (result, input) {
+    this.i += 1;
+    var ret = this.n === 0 ? result : this.xf['@@transducer/step'](result, input);
+    return this.n >= 0 && this.i >= this.n ? _reduced(ret) : ret;
+  };
+
+  return XTake;
+}();
+
+var _xtake = /*#__PURE__*/_curry2(function _xtake(n, xf) {
+  return new XTake(n, xf);
+});
+module.exports = _xtake;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xtakeWhile.js b/server/node_modules/ramda/src/internal/_xtakeWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..b663926821eca8bd19ec14d11feaf4909026ba58
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xtakeWhile.js
@@ -0,0 +1,25 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _reduced = /*#__PURE__*/require('./_reduced');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XTakeWhile = /*#__PURE__*/function () {
+
+  function XTakeWhile(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XTakeWhile.prototype['@@transducer/init'] = _xfBase.init;
+  XTakeWhile.prototype['@@transducer/result'] = _xfBase.result;
+  XTakeWhile.prototype['@@transducer/step'] = function (result, input) {
+    return this.f(input) ? this.xf['@@transducer/step'](result, input) : _reduced(result);
+  };
+
+  return XTakeWhile;
+}();
+
+var _xtakeWhile = /*#__PURE__*/_curry2(function _xtakeWhile(f, xf) {
+  return new XTakeWhile(f, xf);
+});
+module.exports = _xtakeWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xtap.js b/server/node_modules/ramda/src/internal/_xtap.js
new file mode 100644
index 0000000000000000000000000000000000000000..e290211068a89e2d6a5a1db26b08326dc0717f0b
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xtap.js
@@ -0,0 +1,24 @@
+var _curry2 = /*#__PURE__*/require('./_curry2');
+
+var _xfBase = /*#__PURE__*/require('./_xfBase');
+
+var XTap = /*#__PURE__*/function () {
+
+  function XTap(f, xf) {
+    this.xf = xf;
+    this.f = f;
+  }
+  XTap.prototype['@@transducer/init'] = _xfBase.init;
+  XTap.prototype['@@transducer/result'] = _xfBase.result;
+  XTap.prototype['@@transducer/step'] = function (result, input) {
+    this.f(input);
+    return this.xf['@@transducer/step'](result, input);
+  };
+
+  return XTap;
+}();
+
+var _xtap = /*#__PURE__*/_curry2(function _xtap(f, xf) {
+  return new XTap(f, xf);
+});
+module.exports = _xtap;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/internal/_xwrap.js b/server/node_modules/ramda/src/internal/_xwrap.js
new file mode 100644
index 0000000000000000000000000000000000000000..87e325f5bdbfad86f1104c31c009720dc9f1ada8
--- /dev/null
+++ b/server/node_modules/ramda/src/internal/_xwrap.js
@@ -0,0 +1,21 @@
+var XWrap = /*#__PURE__*/function () {
+  function XWrap(fn) {
+    this.f = fn;
+  }
+  XWrap.prototype['@@transducer/init'] = function () {
+    throw new Error('init not implemented on XWrap');
+  };
+  XWrap.prototype['@@transducer/result'] = function (acc) {
+    return acc;
+  };
+  XWrap.prototype['@@transducer/step'] = function (acc, x) {
+    return this.f(acc, x);
+  };
+
+  return XWrap;
+}();
+
+function _xwrap(fn) {
+  return new XWrap(fn);
+}
+module.exports = _xwrap;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/intersection.js b/server/node_modules/ramda/src/intersection.js
new file mode 100644
index 0000000000000000000000000000000000000000..8201df541e39527febefd27406248e464b745999
--- /dev/null
+++ b/server/node_modules/ramda/src/intersection.js
@@ -0,0 +1,41 @@
+var _includes = /*#__PURE__*/require('./internal/_includes');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _filter = /*#__PURE__*/require('./internal/_filter');
+
+var flip = /*#__PURE__*/require('./flip');
+
+var uniq = /*#__PURE__*/require('./uniq');
+
+/**
+ * Combines two lists into a set (i.e. no duplicates) composed of those
+ * elements common to both lists.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The list of elements found in both `list1` and `list2`.
+ * @see R.innerJoin
+ * @example
+ *
+ *      R.intersection([1,2,3,4], [7,6,5,4,3]); //=> [4, 3]
+ */
+
+
+var intersection = /*#__PURE__*/_curry2(function intersection(list1, list2) {
+  var lookupList, filteredList;
+  if (list1.length > list2.length) {
+    lookupList = list1;
+    filteredList = list2;
+  } else {
+    lookupList = list2;
+    filteredList = list1;
+  }
+  return uniq(_filter(flip(_includes)(lookupList), filteredList));
+});
+module.exports = intersection;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/intersperse.js b/server/node_modules/ramda/src/intersperse.js
new file mode 100644
index 0000000000000000000000000000000000000000..a858362c16d38d90ed8eb2e70d19834f82431e5e
--- /dev/null
+++ b/server/node_modules/ramda/src/intersperse.js
@@ -0,0 +1,38 @@
+var _checkForMethod = /*#__PURE__*/require('./internal/_checkForMethod');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Creates a new list with the separator interposed between elements.
+ *
+ * Dispatches to the `intersperse` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig a -> [a] -> [a]
+ * @param {*} separator The element to add to the list.
+ * @param {Array} list The list to be interposed.
+ * @return {Array} The new list.
+ * @example
+ *
+ *      R.intersperse('a', ['b', 'n', 'n', 's']); //=> ['b', 'a', 'n', 'a', 'n', 'a', 's']
+ */
+
+
+var intersperse = /*#__PURE__*/_curry2( /*#__PURE__*/_checkForMethod('intersperse', function intersperse(separator, list) {
+  var out = [];
+  var idx = 0;
+  var length = list.length;
+  while (idx < length) {
+    if (idx === length - 1) {
+      out.push(list[idx]);
+    } else {
+      out.push(list[idx], separator);
+    }
+    idx += 1;
+  }
+  return out;
+}));
+module.exports = intersperse;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/into.js b/server/node_modules/ramda/src/into.js
new file mode 100644
index 0000000000000000000000000000000000000000..67cb3f2584c9304f70bd7571cca3fd6d4eeaa6db
--- /dev/null
+++ b/server/node_modules/ramda/src/into.js
@@ -0,0 +1,55 @@
+var _clone = /*#__PURE__*/require('./internal/_clone');
+
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var _isTransformer = /*#__PURE__*/require('./internal/_isTransformer');
+
+var _reduce = /*#__PURE__*/require('./internal/_reduce');
+
+var _stepCat = /*#__PURE__*/require('./internal/_stepCat');
+
+/**
+ * Transforms the items of the list with the transducer and appends the
+ * transformed items to the accumulator using an appropriate iterator function
+ * based on the accumulator type.
+ *
+ * The accumulator can be an array, string, object or a transformer. Iterated
+ * items will be appended to arrays and concatenated to strings. Objects will
+ * be merged directly or 2-item arrays will be merged as key, value pairs.
+ *
+ * The accumulator can also be a transformer object that provides a 2-arity
+ * reducing iterator function, step, 0-arity initial value function, init, and
+ * 1-arity result extraction function result. The step function is used as the
+ * iterator function in reduce. The result function is used to convert the
+ * final accumulator into the return type and in most cases is R.identity. The
+ * init function is used to provide the initial accumulator.
+ *
+ * The iteration is performed with [`R.reduce`](#reduce) after initializing the
+ * transducer.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig a -> (b -> b) -> [c] -> a
+ * @param {*} acc The initial accumulator value.
+ * @param {Function} xf The transducer function. Receives a transformer and returns a transformer.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.transduce
+ * @example
+ *
+ *      const numbers = [1, 2, 3, 4];
+ *      const transducer = R.compose(R.map(R.add(1)), R.take(2));
+ *
+ *      R.into([], transducer, numbers); //=> [2, 3]
+ *
+ *      const intoArray = R.into([]);
+ *      intoArray(transducer, numbers); //=> [2, 3]
+ */
+
+
+var into = /*#__PURE__*/_curry3(function into(acc, xf, list) {
+  return _isTransformer(acc) ? _reduce(xf(acc), acc['@@transducer/init'](), list) : _reduce(xf(_stepCat(acc)), _clone(acc, [], [], false), list);
+});
+module.exports = into;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/invert.js b/server/node_modules/ramda/src/invert.js
new file mode 100644
index 0000000000000000000000000000000000000000..a9f00e1f6d0fe4d9df796d3899dbc52b922a627c
--- /dev/null
+++ b/server/node_modules/ramda/src/invert.js
@@ -0,0 +1,46 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _has = /*#__PURE__*/require('./internal/_has');
+
+var keys = /*#__PURE__*/require('./keys');
+
+/**
+ * Same as [`R.invertObj`](#invertObj), however this accounts for objects with
+ * duplicate values by putting the values into an array.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig {s: x} -> {x: [ s, ... ]}
+ * @param {Object} obj The object or array to invert
+ * @return {Object} out A new object with keys in an array.
+ * @see R.invertObj
+ * @example
+ *
+ *      const raceResultsByFirstName = {
+ *        first: 'alice',
+ *        second: 'jake',
+ *        third: 'alice',
+ *      };
+ *      R.invert(raceResultsByFirstName);
+ *      //=> { 'alice': ['first', 'third'], 'jake':['second'] }
+ */
+
+
+var invert = /*#__PURE__*/_curry1(function invert(obj) {
+  var props = keys(obj);
+  var len = props.length;
+  var idx = 0;
+  var out = {};
+
+  while (idx < len) {
+    var key = props[idx];
+    var val = obj[key];
+    var list = _has(val, out) ? out[val] : out[val] = [];
+    list[list.length] = key;
+    idx += 1;
+  }
+  return out;
+});
+module.exports = invert;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/invertObj.js b/server/node_modules/ramda/src/invertObj.js
new file mode 100644
index 0000000000000000000000000000000000000000..c375161333d084da8be35bbc11a510ca51410dfe
--- /dev/null
+++ b/server/node_modules/ramda/src/invertObj.js
@@ -0,0 +1,47 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var keys = /*#__PURE__*/require('./keys');
+
+/**
+ * Returns a new object with the keys of the given object as values, and the
+ * values of the given object, which are coerced to strings, as keys. Note
+ * that the last key found is preferred when handling the same value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig {s: x} -> {x: s}
+ * @param {Object} obj The object or array to invert
+ * @return {Object} out A new object
+ * @see R.invert
+ * @example
+ *
+ *      const raceResults = {
+ *        first: 'alice',
+ *        second: 'jake'
+ *      };
+ *      R.invertObj(raceResults);
+ *      //=> { 'alice': 'first', 'jake':'second' }
+ *
+ *      // Alternatively:
+ *      const raceResults = ['alice', 'jake'];
+ *      R.invertObj(raceResults);
+ *      //=> { 'alice': '0', 'jake':'1' }
+ */
+
+
+var invertObj = /*#__PURE__*/_curry1(function invertObj(obj) {
+  var props = keys(obj);
+  var len = props.length;
+  var idx = 0;
+  var out = {};
+
+  while (idx < len) {
+    var key = props[idx];
+    out[obj[key]] = key;
+    idx += 1;
+  }
+  return out;
+});
+module.exports = invertObj;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/invoker.js b/server/node_modules/ramda/src/invoker.js
new file mode 100644
index 0000000000000000000000000000000000000000..28559b153c7b06086e77ee8d3cfaed2a2b4b11bf
--- /dev/null
+++ b/server/node_modules/ramda/src/invoker.js
@@ -0,0 +1,47 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _isFunction = /*#__PURE__*/require('./internal/_isFunction');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+var toString = /*#__PURE__*/require('./toString');
+
+/**
+ * Turns a named method with a specified arity into a function that can be
+ * called directly supplied with arguments and a target object.
+ *
+ * The returned function is curried and accepts `arity + 1` parameters where
+ * the final parameter is the target object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig Number -> String -> (a -> b -> ... -> n -> Object -> *)
+ * @param {Number} arity Number of arguments the returned function should take
+ *        before the target object.
+ * @param {String} method Name of the method to call.
+ * @return {Function} A new curried function.
+ * @see R.construct
+ * @example
+ *
+ *      const sliceFrom = R.invoker(1, 'slice');
+ *      sliceFrom(6, 'abcdefghijklm'); //=> 'ghijklm'
+ *      const sliceFrom6 = R.invoker(2, 'slice')(6);
+ *      sliceFrom6(8, 'abcdefghijklm'); //=> 'gh'
+ * @symb R.invoker(0, 'method')(o) = o['method']()
+ * @symb R.invoker(1, 'method')(a, o) = o['method'](a)
+ * @symb R.invoker(2, 'method')(a, b, o) = o['method'](a, b)
+ */
+
+
+var invoker = /*#__PURE__*/_curry2(function invoker(arity, method) {
+  return curryN(arity + 1, function () {
+    var target = arguments[arity];
+    if (target != null && _isFunction(target[method])) {
+      return target[method].apply(target, Array.prototype.slice.call(arguments, 0, arity));
+    }
+    throw new TypeError(toString(target) + ' does not have a method named "' + method + '"');
+  });
+});
+module.exports = invoker;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/is.js b/server/node_modules/ramda/src/is.js
new file mode 100644
index 0000000000000000000000000000000000000000..14db6695ae6b7a14be7164e6a213df6aa1954da0
--- /dev/null
+++ b/server/node_modules/ramda/src/is.js
@@ -0,0 +1,31 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * See if an object (`val`) is an instance of the supplied constructor. This
+ * function will check up the inheritance chain, if any.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Type
+ * @sig (* -> {*}) -> a -> Boolean
+ * @param {Object} ctor A constructor
+ * @param {*} val The value to test
+ * @return {Boolean}
+ * @example
+ *
+ *      R.is(Object, {}); //=> true
+ *      R.is(Number, 1); //=> true
+ *      R.is(Object, 1); //=> false
+ *      R.is(String, 's'); //=> true
+ *      R.is(String, new String('')); //=> true
+ *      R.is(Object, new String('')); //=> true
+ *      R.is(Object, 's'); //=> false
+ *      R.is(Number, {}); //=> false
+ */
+
+
+var is = /*#__PURE__*/_curry2(function is(Ctor, val) {
+  return val != null && val.constructor === Ctor || val instanceof Ctor;
+});
+module.exports = is;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/isEmpty.js b/server/node_modules/ramda/src/isEmpty.js
new file mode 100644
index 0000000000000000000000000000000000000000..907d37bff392224c0227ae55d2cfe10e84d698eb
--- /dev/null
+++ b/server/node_modules/ramda/src/isEmpty.js
@@ -0,0 +1,33 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var empty = /*#__PURE__*/require('./empty');
+
+var equals = /*#__PURE__*/require('./equals');
+
+/**
+ * Returns `true` if the given value is its type's empty value; `false`
+ * otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig a -> Boolean
+ * @param {*} x
+ * @return {Boolean}
+ * @see R.empty
+ * @example
+ *
+ *      R.isEmpty([1, 2, 3]);   //=> false
+ *      R.isEmpty([]);          //=> true
+ *      R.isEmpty('');          //=> true
+ *      R.isEmpty(null);        //=> false
+ *      R.isEmpty({});          //=> true
+ *      R.isEmpty({length: 0}); //=> false
+ */
+
+
+var isEmpty = /*#__PURE__*/_curry1(function isEmpty(x) {
+  return x != null && equals(x, empty(x));
+});
+module.exports = isEmpty;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/isNil.js b/server/node_modules/ramda/src/isNil.js
new file mode 100644
index 0000000000000000000000000000000000000000..3dfddf0027834a43673e661156ba908aa50927a3
--- /dev/null
+++ b/server/node_modules/ramda/src/isNil.js
@@ -0,0 +1,25 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Checks if the input value is `null` or `undefined`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Type
+ * @sig * -> Boolean
+ * @param {*} x The value to test.
+ * @return {Boolean} `true` if `x` is `undefined` or `null`, otherwise `false`.
+ * @example
+ *
+ *      R.isNil(null); //=> true
+ *      R.isNil(undefined); //=> true
+ *      R.isNil(0); //=> false
+ *      R.isNil([]); //=> false
+ */
+
+
+var isNil = /*#__PURE__*/_curry1(function isNil(x) {
+  return x == null;
+});
+module.exports = isNil;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/join.js b/server/node_modules/ramda/src/join.js
new file mode 100644
index 0000000000000000000000000000000000000000..c0dc3ffb8753e482e55792cf1f5ac3fbfe1fde2c
--- /dev/null
+++ b/server/node_modules/ramda/src/join.js
@@ -0,0 +1,25 @@
+var invoker = /*#__PURE__*/require('./invoker');
+
+/**
+ * Returns a string made by inserting the `separator` between each element and
+ * concatenating all the elements into a single string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig String -> [a] -> String
+ * @param {Number|String} separator The string used to separate the elements.
+ * @param {Array} xs The elements to join into a string.
+ * @return {String} str The string made by concatenating `xs` with `separator`.
+ * @see R.split
+ * @example
+ *
+ *      const spacer = R.join(' ');
+ *      spacer(['a', 2, 3.4]);   //=> 'a 2 3.4'
+ *      R.join('|', [1, 2, 3]);    //=> '1|2|3'
+ */
+
+
+var join = /*#__PURE__*/invoker(1, 'join');
+module.exports = join;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/juxt.js b/server/node_modules/ramda/src/juxt.js
new file mode 100644
index 0000000000000000000000000000000000000000..a954f301df306a86c94ebe68d18a6063da959ee7
--- /dev/null
+++ b/server/node_modules/ramda/src/juxt.js
@@ -0,0 +1,29 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var converge = /*#__PURE__*/require('./converge');
+
+/**
+ * juxt applies a list of functions to a list of values.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Function
+ * @sig [(a, b, ..., m) -> n] -> ((a, b, ..., m) -> [n])
+ * @param {Array} fns An array of functions
+ * @return {Function} A function that returns a list of values after applying each of the original `fns` to its parameters.
+ * @see R.applySpec
+ * @example
+ *
+ *      const getRange = R.juxt([Math.min, Math.max]);
+ *      getRange(3, 4, 9, -3); //=> [-3, 9]
+ * @symb R.juxt([f, g, h])(a, b) = [f(a, b), g(a, b), h(a, b)]
+ */
+
+
+var juxt = /*#__PURE__*/_curry1(function juxt(fns) {
+  return converge(function () {
+    return Array.prototype.slice.call(arguments, 0);
+  }, fns);
+});
+module.exports = juxt;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/keys.js b/server/node_modules/ramda/src/keys.js
new file mode 100644
index 0000000000000000000000000000000000000000..b618a59d9ff871a7804d1fd1f6522db19eca06b0
--- /dev/null
+++ b/server/node_modules/ramda/src/keys.js
@@ -0,0 +1,74 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _has = /*#__PURE__*/require('./internal/_has');
+
+var _isArguments = /*#__PURE__*/require('./internal/_isArguments');
+
+// cover IE < 9 keys issues
+
+
+var hasEnumBug = ! /*#__PURE__*/{ toString: null }.propertyIsEnumerable('toString');
+var nonEnumerableProps = ['constructor', 'valueOf', 'isPrototypeOf', 'toString', 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
+// Safari bug
+var hasArgsEnumBug = /*#__PURE__*/function () {
+  'use strict';
+
+  return arguments.propertyIsEnumerable('length');
+}();
+
+var contains = function contains(list, item) {
+  var idx = 0;
+  while (idx < list.length) {
+    if (list[idx] === item) {
+      return true;
+    }
+    idx += 1;
+  }
+  return false;
+};
+
+/**
+ * Returns a list containing the names of all the enumerable own properties of
+ * the supplied object.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {k: v} -> [k]
+ * @param {Object} obj The object to extract properties from
+ * @return {Array} An array of the object's own properties.
+ * @see R.keysIn, R.values
+ * @example
+ *
+ *      R.keys({a: 1, b: 2, c: 3}); //=> ['a', 'b', 'c']
+ */
+var keys = typeof Object.keys === 'function' && !hasArgsEnumBug ? /*#__PURE__*/_curry1(function keys(obj) {
+  return Object(obj) !== obj ? [] : Object.keys(obj);
+}) : /*#__PURE__*/_curry1(function keys(obj) {
+  if (Object(obj) !== obj) {
+    return [];
+  }
+  var prop, nIdx;
+  var ks = [];
+  var checkArgsLength = hasArgsEnumBug && _isArguments(obj);
+  for (prop in obj) {
+    if (_has(prop, obj) && (!checkArgsLength || prop !== 'length')) {
+      ks[ks.length] = prop;
+    }
+  }
+  if (hasEnumBug) {
+    nIdx = nonEnumerableProps.length - 1;
+    while (nIdx >= 0) {
+      prop = nonEnumerableProps[nIdx];
+      if (_has(prop, obj) && !contains(ks, prop)) {
+        ks[ks.length] = prop;
+      }
+      nIdx -= 1;
+    }
+  }
+  return ks;
+});
+module.exports = keys;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/keysIn.js b/server/node_modules/ramda/src/keysIn.js
new file mode 100644
index 0000000000000000000000000000000000000000..47c52efcbf0a8cb150ea68e4622bdb56e857f013
--- /dev/null
+++ b/server/node_modules/ramda/src/keysIn.js
@@ -0,0 +1,34 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Returns a list containing the names of all the properties of the supplied
+ * object, including prototype properties.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Object
+ * @sig {k: v} -> [k]
+ * @param {Object} obj The object to extract properties from
+ * @return {Array} An array of the object's own and prototype properties.
+ * @see R.keys, R.valuesIn
+ * @example
+ *
+ *      const F = function() { this.x = 'X'; };
+ *      F.prototype.y = 'Y';
+ *      const f = new F();
+ *      R.keysIn(f); //=> ['x', 'y']
+ */
+
+
+var keysIn = /*#__PURE__*/_curry1(function keysIn(obj) {
+  var prop;
+  var ks = [];
+  for (prop in obj) {
+    ks[ks.length] = prop;
+  }
+  return ks;
+});
+module.exports = keysIn;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/last.js b/server/node_modules/ramda/src/last.js
new file mode 100644
index 0000000000000000000000000000000000000000..5efb2a7f35053938d15a392c92dfb85562c00922
--- /dev/null
+++ b/server/node_modules/ramda/src/last.js
@@ -0,0 +1,26 @@
+var nth = /*#__PURE__*/require('./nth');
+
+/**
+ * Returns the last element of the given list or string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.4
+ * @category List
+ * @sig [a] -> a | Undefined
+ * @sig String -> String
+ * @param {*} list
+ * @return {*}
+ * @see R.init, R.head, R.tail
+ * @example
+ *
+ *      R.last(['fi', 'fo', 'fum']); //=> 'fum'
+ *      R.last([]); //=> undefined
+ *
+ *      R.last('abc'); //=> 'c'
+ *      R.last(''); //=> ''
+ */
+
+
+var last = /*#__PURE__*/nth(-1);
+module.exports = last;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/lastIndexOf.js b/server/node_modules/ramda/src/lastIndexOf.js
new file mode 100644
index 0000000000000000000000000000000000000000..e8a0065a9ae9adf0324c710f2eadbcbc1c25dcf8
--- /dev/null
+++ b/server/node_modules/ramda/src/lastIndexOf.js
@@ -0,0 +1,42 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _isArray = /*#__PURE__*/require('./internal/_isArray');
+
+var equals = /*#__PURE__*/require('./equals');
+
+/**
+ * Returns the position of the last occurrence of an item in an array, or -1 if
+ * the item is not included in the array. [`R.equals`](#equals) is used to
+ * determine equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> Number
+ * @param {*} target The item to find.
+ * @param {Array} xs The array to search in.
+ * @return {Number} the index of the target, or -1 if the target is not found.
+ * @see R.indexOf
+ * @example
+ *
+ *      R.lastIndexOf(3, [-1,3,3,0,1,2,3,4]); //=> 6
+ *      R.lastIndexOf(10, [1,2,3,4]); //=> -1
+ */
+
+
+var lastIndexOf = /*#__PURE__*/_curry2(function lastIndexOf(target, xs) {
+  if (typeof xs.lastIndexOf === 'function' && !_isArray(xs)) {
+    return xs.lastIndexOf(target);
+  } else {
+    var idx = xs.length - 1;
+    while (idx >= 0) {
+      if (equals(xs[idx], target)) {
+        return idx;
+      }
+      idx -= 1;
+    }
+    return -1;
+  }
+});
+module.exports = lastIndexOf;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/length.js b/server/node_modules/ramda/src/length.js
new file mode 100644
index 0000000000000000000000000000000000000000..e7dc01aac13506ab019cc1861e01295593c00cd6
--- /dev/null
+++ b/server/node_modules/ramda/src/length.js
@@ -0,0 +1,25 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _isNumber = /*#__PURE__*/require('./internal/_isNumber');
+
+/**
+ * Returns the number of elements in the array by returning `list.length`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig [a] -> Number
+ * @param {Array} list The array to inspect.
+ * @return {Number} The length of the array.
+ * @example
+ *
+ *      R.length([]); //=> 0
+ *      R.length([1, 2, 3]); //=> 3
+ */
+
+
+var length = /*#__PURE__*/_curry1(function length(list) {
+  return list != null && _isNumber(list.length) ? list.length : NaN;
+});
+module.exports = length;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/lens.js b/server/node_modules/ramda/src/lens.js
new file mode 100644
index 0000000000000000000000000000000000000000..441c9736218784551a678a08459319ac09272e9e
--- /dev/null
+++ b/server/node_modules/ramda/src/lens.js
@@ -0,0 +1,39 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var map = /*#__PURE__*/require('./map');
+
+/**
+ * Returns a lens for the given getter and setter functions. The getter "gets"
+ * the value of the focus; the setter "sets" the value of the focus. The setter
+ * should not mutate the data structure.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig (s -> a) -> ((a, s) -> s) -> Lens s a
+ * @param {Function} getter
+ * @param {Function} setter
+ * @return {Lens}
+ * @see R.view, R.set, R.over, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const xLens = R.lens(R.prop('x'), R.assoc('x'));
+ *
+ *      R.view(xLens, {x: 1, y: 2});            //=> 1
+ *      R.set(xLens, 4, {x: 1, y: 2});          //=> {x: 4, y: 2}
+ *      R.over(xLens, R.negate, {x: 1, y: 2});  //=> {x: -1, y: 2}
+ */
+
+
+var lens = /*#__PURE__*/_curry2(function lens(getter, setter) {
+  return function (toFunctorFn) {
+    return function (target) {
+      return map(function (focus) {
+        return setter(focus, target);
+      }, toFunctorFn(getter(target)));
+    };
+  };
+});
+module.exports = lens;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/lensIndex.js b/server/node_modules/ramda/src/lensIndex.js
new file mode 100644
index 0000000000000000000000000000000000000000..705377e686e53dc5198c2c1d8a5d000d127938a7
--- /dev/null
+++ b/server/node_modules/ramda/src/lensIndex.js
@@ -0,0 +1,34 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var lens = /*#__PURE__*/require('./lens');
+
+var nth = /*#__PURE__*/require('./nth');
+
+var update = /*#__PURE__*/require('./update');
+
+/**
+ * Returns a lens whose focus is the specified index.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Number -> Lens s a
+ * @param {Number} n
+ * @return {Lens}
+ * @see R.view, R.set, R.over
+ * @example
+ *
+ *      const headLens = R.lensIndex(0);
+ *
+ *      R.view(headLens, ['a', 'b', 'c']);            //=> 'a'
+ *      R.set(headLens, 'x', ['a', 'b', 'c']);        //=> ['x', 'b', 'c']
+ *      R.over(headLens, R.toUpper, ['a', 'b', 'c']); //=> ['A', 'b', 'c']
+ */
+
+
+var lensIndex = /*#__PURE__*/_curry1(function lensIndex(n) {
+  return lens(nth(n), update(n));
+});
+module.exports = lensIndex;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/lensPath.js b/server/node_modules/ramda/src/lensPath.js
new file mode 100644
index 0000000000000000000000000000000000000000..68c46f12b55e96953747ca41dd08af4639027ecd
--- /dev/null
+++ b/server/node_modules/ramda/src/lensPath.js
@@ -0,0 +1,38 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var assocPath = /*#__PURE__*/require('./assocPath');
+
+var lens = /*#__PURE__*/require('./lens');
+
+var path = /*#__PURE__*/require('./path');
+
+/**
+ * Returns a lens whose focus is the specified path.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig [Idx] -> Lens s a
+ * @param {Array} path The path to use.
+ * @return {Lens}
+ * @see R.view, R.set, R.over
+ * @example
+ *
+ *      const xHeadYLens = R.lensPath(['x', 0, 'y']);
+ *
+ *      R.view(xHeadYLens, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
+ *      //=> 2
+ *      R.set(xHeadYLens, 1, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
+ *      //=> {x: [{y: 1, z: 3}, {y: 4, z: 5}]}
+ *      R.over(xHeadYLens, R.negate, {x: [{y: 2, z: 3}, {y: 4, z: 5}]});
+ *      //=> {x: [{y: -2, z: 3}, {y: 4, z: 5}]}
+ */
+
+
+var lensPath = /*#__PURE__*/_curry1(function lensPath(p) {
+  return lens(path(p), assocPath(p));
+});
+module.exports = lensPath;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/lensProp.js b/server/node_modules/ramda/src/lensProp.js
new file mode 100644
index 0000000000000000000000000000000000000000..abe18ce3f6b8851de9869b587ccc855da4ee21aa
--- /dev/null
+++ b/server/node_modules/ramda/src/lensProp.js
@@ -0,0 +1,34 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var assoc = /*#__PURE__*/require('./assoc');
+
+var lens = /*#__PURE__*/require('./lens');
+
+var prop = /*#__PURE__*/require('./prop');
+
+/**
+ * Returns a lens whose focus is the specified property.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig String -> Lens s a
+ * @param {String} k
+ * @return {Lens}
+ * @see R.view, R.set, R.over
+ * @example
+ *
+ *      const xLens = R.lensProp('x');
+ *
+ *      R.view(xLens, {x: 1, y: 2});            //=> 1
+ *      R.set(xLens, 4, {x: 1, y: 2});          //=> {x: 4, y: 2}
+ *      R.over(xLens, R.negate, {x: 1, y: 2});  //=> {x: -1, y: 2}
+ */
+
+
+var lensProp = /*#__PURE__*/_curry1(function lensProp(k) {
+  return lens(prop(k), assoc(k));
+});
+module.exports = lensProp;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/lift.js b/server/node_modules/ramda/src/lift.js
new file mode 100644
index 0000000000000000000000000000000000000000..26356d73b187fc40813cbd4dab70dae26663912e
--- /dev/null
+++ b/server/node_modules/ramda/src/lift.js
@@ -0,0 +1,32 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var liftN = /*#__PURE__*/require('./liftN');
+
+/**
+ * "lifts" a function of arity > 1 so that it may "map over" a list, Function or other
+ * object that satisfies the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Function
+ * @sig (*... -> *) -> ([*]... -> [*])
+ * @param {Function} fn The function to lift into higher context
+ * @return {Function} The lifted function.
+ * @see R.liftN
+ * @example
+ *
+ *      const madd3 = R.lift((a, b, c) => a + b + c);
+ *
+ *      madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
+ *
+ *      const madd5 = R.lift((a, b, c, d, e) => a + b + c + d + e);
+ *
+ *      madd5([1,2], [3], [4, 5], [6], [7, 8]); //=> [21, 22, 22, 23, 22, 23, 23, 24]
+ */
+
+
+var lift = /*#__PURE__*/_curry1(function lift(fn) {
+  return liftN(fn.length, fn);
+});
+module.exports = lift;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/liftN.js b/server/node_modules/ramda/src/liftN.js
new file mode 100644
index 0000000000000000000000000000000000000000..c58c097ab356b63efa9e36f694deb3284ebeea10
--- /dev/null
+++ b/server/node_modules/ramda/src/liftN.js
@@ -0,0 +1,36 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _reduce = /*#__PURE__*/require('./internal/_reduce');
+
+var ap = /*#__PURE__*/require('./ap');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+var map = /*#__PURE__*/require('./map');
+
+/**
+ * "lifts" a function to be the specified arity, so that it may "map over" that
+ * many lists, Functions or other objects that satisfy the [FantasyLand Apply spec](https://github.com/fantasyland/fantasy-land#apply).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Function
+ * @sig Number -> (*... -> *) -> ([*]... -> [*])
+ * @param {Function} fn The function to lift into higher context
+ * @return {Function} The lifted function.
+ * @see R.lift, R.ap
+ * @example
+ *
+ *      const madd3 = R.liftN(3, (...args) => R.sum(args));
+ *      madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
+ */
+
+
+var liftN = /*#__PURE__*/_curry2(function liftN(arity, fn) {
+  var lifted = curryN(arity, fn);
+  return curryN(arity, function () {
+    return _reduce(ap, map(lifted, arguments[0]), Array.prototype.slice.call(arguments, 1));
+  });
+});
+module.exports = liftN;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/lt.js b/server/node_modules/ramda/src/lt.js
new file mode 100644
index 0000000000000000000000000000000000000000..12c0b49870c44189f5b1791e6c4e49c674e299a9
--- /dev/null
+++ b/server/node_modules/ramda/src/lt.js
@@ -0,0 +1,29 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns `true` if the first argument is less than the second; `false`
+ * otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {*} a
+ * @param {*} b
+ * @return {Boolean}
+ * @see R.gt
+ * @example
+ *
+ *      R.lt(2, 1); //=> false
+ *      R.lt(2, 2); //=> false
+ *      R.lt(2, 3); //=> true
+ *      R.lt('a', 'z'); //=> true
+ *      R.lt('z', 'a'); //=> false
+ */
+
+
+var lt = /*#__PURE__*/_curry2(function lt(a, b) {
+  return a < b;
+});
+module.exports = lt;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/lte.js b/server/node_modules/ramda/src/lte.js
new file mode 100644
index 0000000000000000000000000000000000000000..af260dcdb7b23aeeb528061cc032606283942829
--- /dev/null
+++ b/server/node_modules/ramda/src/lte.js
@@ -0,0 +1,29 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns `true` if the first argument is less than or equal to the second;
+ * `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> Boolean
+ * @param {Number} a
+ * @param {Number} b
+ * @return {Boolean}
+ * @see R.gte
+ * @example
+ *
+ *      R.lte(2, 1); //=> false
+ *      R.lte(2, 2); //=> true
+ *      R.lte(2, 3); //=> true
+ *      R.lte('a', 'z'); //=> true
+ *      R.lte('z', 'a'); //=> false
+ */
+
+
+var lte = /*#__PURE__*/_curry2(function lte(a, b) {
+  return a <= b;
+});
+module.exports = lte;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/map.js b/server/node_modules/ramda/src/map.js
new file mode 100644
index 0000000000000000000000000000000000000000..8618e68e1b30fba4698f3b7ab88c9d0b869d4728
--- /dev/null
+++ b/server/node_modules/ramda/src/map.js
@@ -0,0 +1,67 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _map = /*#__PURE__*/require('./internal/_map');
+
+var _reduce = /*#__PURE__*/require('./internal/_reduce');
+
+var _xmap = /*#__PURE__*/require('./internal/_xmap');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+var keys = /*#__PURE__*/require('./keys');
+
+/**
+ * Takes a function and
+ * a [functor](https://github.com/fantasyland/fantasy-land#functor),
+ * applies the function to each of the functor's values, and returns
+ * a functor of the same shape.
+ *
+ * Ramda provides suitable `map` implementations for `Array` and `Object`,
+ * so this function may be applied to `[1, 2, 3]` or `{x: 1, y: 2, z: 3}`.
+ *
+ * Dispatches to the `map` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * Also treats functions as functors and will compose them together.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Functor f => (a -> b) -> f a -> f b
+ * @param {Function} fn The function to be called on every element of the input `list`.
+ * @param {Array} list The list to be iterated over.
+ * @return {Array} The new list.
+ * @see R.transduce, R.addIndex
+ * @example
+ *
+ *      const double = x => x * 2;
+ *
+ *      R.map(double, [1, 2, 3]); //=> [2, 4, 6]
+ *
+ *      R.map(double, {x: 1, y: 2, z: 3}); //=> {x: 2, y: 4, z: 6}
+ * @symb R.map(f, [a, b]) = [f(a), f(b)]
+ * @symb R.map(f, { x: a, y: b }) = { x: f(a), y: f(b) }
+ * @symb R.map(f, functor_o) = functor_o.map(f)
+ */
+
+
+var map = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['fantasy-land/map', 'map'], _xmap, function map(fn, functor) {
+  switch (Object.prototype.toString.call(functor)) {
+    case '[object Function]':
+      return curryN(functor.length, function () {
+        return fn.call(this, functor.apply(this, arguments));
+      });
+    case '[object Object]':
+      return _reduce(function (acc, key) {
+        acc[key] = fn(functor[key]);
+        return acc;
+      }, {}, keys(functor));
+    default:
+      return _map(fn, functor);
+  }
+}));
+module.exports = map;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mapAccum.js b/server/node_modules/ramda/src/mapAccum.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd83ff09b31a26d02c7e4a22b74e2a52779ac0a0
--- /dev/null
+++ b/server/node_modules/ramda/src/mapAccum.js
@@ -0,0 +1,51 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * The `mapAccum` function behaves like a combination of map and reduce; it
+ * applies a function to each element of a list, passing an accumulating
+ * parameter from left to right, and returning a final value of this
+ * accumulator together with the new list.
+ *
+ * The iterator function receives two arguments, *acc* and *value*, and should
+ * return a tuple *[acc, value]*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig ((acc, x) -> (acc, y)) -> acc -> [x] -> (acc, [y])
+ * @param {Function} fn The function to be called on every element of the input `list`.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.scan, R.addIndex, R.mapAccumRight
+ * @example
+ *
+ *      const digits = ['1', '2', '3', '4'];
+ *      const appender = (a, b) => [a + b, a + b];
+ *
+ *      R.mapAccum(appender, 0, digits); //=> ['01234', ['01', '012', '0123', '01234']]
+ * @symb R.mapAccum(f, a, [b, c, d]) = [
+ *   f(f(f(a, b)[0], c)[0], d)[0],
+ *   [
+ *     f(a, b)[1],
+ *     f(f(a, b)[0], c)[1],
+ *     f(f(f(a, b)[0], c)[0], d)[1]
+ *   ]
+ * ]
+ */
+
+
+var mapAccum = /*#__PURE__*/_curry3(function mapAccum(fn, acc, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [];
+  var tuple = [acc];
+  while (idx < len) {
+    tuple = fn(tuple[0], list[idx]);
+    result[idx] = tuple[1];
+    idx += 1;
+  }
+  return [tuple[0], result];
+});
+module.exports = mapAccum;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mapAccumRight.js b/server/node_modules/ramda/src/mapAccumRight.js
new file mode 100644
index 0000000000000000000000000000000000000000..02f7ddf443c547bafe03745b9d16ba4e784c7ed3
--- /dev/null
+++ b/server/node_modules/ramda/src/mapAccumRight.js
@@ -0,0 +1,53 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * The `mapAccumRight` function behaves like a combination of map and reduce; it
+ * applies a function to each element of a list, passing an accumulating
+ * parameter from right to left, and returning a final value of this
+ * accumulator together with the new list.
+ *
+ * Similar to [`mapAccum`](#mapAccum), except moves through the input list from
+ * the right to the left.
+ *
+ * The iterator function receives two arguments, *acc* and *value*, and should
+ * return a tuple *[acc, value]*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig ((acc, x) -> (acc, y)) -> acc -> [x] -> (acc, [y])
+ * @param {Function} fn The function to be called on every element of the input `list`.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.addIndex, R.mapAccum
+ * @example
+ *
+ *      const digits = ['1', '2', '3', '4'];
+ *      const appender = (a, b) => [b + a, b + a];
+ *
+ *      R.mapAccumRight(appender, 5, digits); //=> ['12345', ['12345', '2345', '345', '45']]
+ * @symb R.mapAccumRight(f, a, [b, c, d]) = [
+ *   f(f(f(a, d)[0], c)[0], b)[0],
+ *   [
+ *     f(a, d)[1],
+ *     f(f(a, d)[0], c)[1],
+ *     f(f(f(a, d)[0], c)[0], b)[1]
+ *   ]
+ * ]
+ */
+
+
+var mapAccumRight = /*#__PURE__*/_curry3(function mapAccumRight(fn, acc, list) {
+  var idx = list.length - 1;
+  var result = [];
+  var tuple = [acc];
+  while (idx >= 0) {
+    tuple = fn(tuple[0], list[idx]);
+    result[idx] = tuple[1];
+    idx -= 1;
+  }
+  return [tuple[0], result];
+});
+module.exports = mapAccumRight;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mapObjIndexed.js b/server/node_modules/ramda/src/mapObjIndexed.js
new file mode 100644
index 0000000000000000000000000000000000000000..1b155ddb823c0f09db8ff76d66ee8791e0df588a
--- /dev/null
+++ b/server/node_modules/ramda/src/mapObjIndexed.js
@@ -0,0 +1,36 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _reduce = /*#__PURE__*/require('./internal/_reduce');
+
+var keys = /*#__PURE__*/require('./keys');
+
+/**
+ * An Object-specific version of [`map`](#map). The function is applied to three
+ * arguments: *(value, key, obj)*. If only the value is significant, use
+ * [`map`](#map) instead.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Object
+ * @sig ((*, String, Object) -> *) -> Object -> Object
+ * @param {Function} fn
+ * @param {Object} obj
+ * @return {Object}
+ * @see R.map
+ * @example
+ *
+ *      const xyz = { x: 1, y: 2, z: 3 };
+ *      const prependKeyAndDouble = (num, key, obj) => key + (num * 2);
+ *
+ *      R.mapObjIndexed(prependKeyAndDouble, xyz); //=> { x: 'x2', y: 'y4', z: 'z6' }
+ */
+
+
+var mapObjIndexed = /*#__PURE__*/_curry2(function mapObjIndexed(fn, obj) {
+  return _reduce(function (acc, key) {
+    acc[key] = fn(obj[key], key, obj);
+    return acc;
+  }, {}, keys(obj));
+});
+module.exports = mapObjIndexed;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/match.js b/server/node_modules/ramda/src/match.js
new file mode 100644
index 0000000000000000000000000000000000000000..01b5d1b0556ccecc185325b1fda36e37b605a079
--- /dev/null
+++ b/server/node_modules/ramda/src/match.js
@@ -0,0 +1,29 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Tests a regular expression against a String. Note that this function will
+ * return an empty array when there are no matches. This differs from
+ * [`String.prototype.match`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match)
+ * which returns `null` when there are no matches.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category String
+ * @sig RegExp -> String -> [String | Undefined]
+ * @param {RegExp} rx A regular expression.
+ * @param {String} str The string to match against
+ * @return {Array} The list of matches or empty array.
+ * @see R.test
+ * @example
+ *
+ *      R.match(/([a-z]a)/g, 'bananas'); //=> ['ba', 'na', 'na']
+ *      R.match(/a/, 'b'); //=> []
+ *      R.match(/a/, null); //=> TypeError: null does not have a method named "match"
+ */
+
+
+var match = /*#__PURE__*/_curry2(function match(rx, str) {
+  return str.match(rx) || [];
+});
+module.exports = match;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mathMod.js b/server/node_modules/ramda/src/mathMod.js
new file mode 100644
index 0000000000000000000000000000000000000000..f3fc25efdf04e18897f3815a10bc6f5c6a3d6f2d
--- /dev/null
+++ b/server/node_modules/ramda/src/mathMod.js
@@ -0,0 +1,49 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _isInteger = /*#__PURE__*/require('./internal/_isInteger');
+
+/**
+ * `mathMod` behaves like the modulo operator should mathematically, unlike the
+ * `%` operator (and by extension, [`R.modulo`](#modulo)). So while
+ * `-17 % 5` is `-2`, `mathMod(-17, 5)` is `3`. `mathMod` requires Integer
+ * arguments, and returns NaN when the modulus is zero or negative.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} m The dividend.
+ * @param {Number} p the modulus.
+ * @return {Number} The result of `b mod a`.
+ * @see R.modulo
+ * @example
+ *
+ *      R.mathMod(-17, 5);  //=> 3
+ *      R.mathMod(17, 5);   //=> 2
+ *      R.mathMod(17, -5);  //=> NaN
+ *      R.mathMod(17, 0);   //=> NaN
+ *      R.mathMod(17.2, 5); //=> NaN
+ *      R.mathMod(17, 5.3); //=> NaN
+ *
+ *      const clock = R.mathMod(R.__, 12);
+ *      clock(15); //=> 3
+ *      clock(24); //=> 0
+ *
+ *      const seventeenMod = R.mathMod(17);
+ *      seventeenMod(3);  //=> 2
+ *      seventeenMod(4);  //=> 1
+ *      seventeenMod(10); //=> 7
+ */
+
+
+var mathMod = /*#__PURE__*/_curry2(function mathMod(m, p) {
+  if (!_isInteger(m)) {
+    return NaN;
+  }
+  if (!_isInteger(p) || p < 1) {
+    return NaN;
+  }
+  return (m % p + p) % p;
+});
+module.exports = mathMod;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/max.js b/server/node_modules/ramda/src/max.js
new file mode 100644
index 0000000000000000000000000000000000000000..a6f1bca8986526be6e9f4577f17cde7c05dbe38a
--- /dev/null
+++ b/server/node_modules/ramda/src/max.js
@@ -0,0 +1,25 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns the larger of its two arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> a
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.maxBy, R.min
+ * @example
+ *
+ *      R.max(789, 123); //=> 789
+ *      R.max('a', 'b'); //=> 'b'
+ */
+
+
+var max = /*#__PURE__*/_curry2(function max(a, b) {
+  return b > a ? b : a;
+});
+module.exports = max;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/maxBy.js b/server/node_modules/ramda/src/maxBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..89a4a2869b138f9c49ee5d4ca9a91fc3859577ba
--- /dev/null
+++ b/server/node_modules/ramda/src/maxBy.js
@@ -0,0 +1,32 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Takes a function and two values, and returns whichever value produces the
+ * larger result when passed to the provided function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Relation
+ * @sig Ord b => (a -> b) -> a -> a -> a
+ * @param {Function} f
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.max, R.minBy
+ * @example
+ *
+ *      //  square :: Number -> Number
+ *      const square = n => n * n;
+ *
+ *      R.maxBy(square, -3, 2); //=> -3
+ *
+ *      R.reduce(R.maxBy(square), 0, [3, -5, 4, 1, -2]); //=> -5
+ *      R.reduce(R.maxBy(square), 0, []); //=> 0
+ */
+
+
+var maxBy = /*#__PURE__*/_curry3(function maxBy(f, a, b) {
+  return f(b) > f(a) ? b : a;
+});
+module.exports = maxBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mean.js b/server/node_modules/ramda/src/mean.js
new file mode 100644
index 0000000000000000000000000000000000000000..47c033669301821d72dc71c1d489d3d72b1ee0e9
--- /dev/null
+++ b/server/node_modules/ramda/src/mean.js
@@ -0,0 +1,26 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var sum = /*#__PURE__*/require('./sum');
+
+/**
+ * Returns the mean of the given list of numbers.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list
+ * @return {Number}
+ * @see R.median
+ * @example
+ *
+ *      R.mean([2, 7, 9]); //=> 6
+ *      R.mean([]); //=> NaN
+ */
+
+
+var mean = /*#__PURE__*/_curry1(function mean(list) {
+  return sum(list) / list.length;
+});
+module.exports = mean;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/median.js b/server/node_modules/ramda/src/median.js
new file mode 100644
index 0000000000000000000000000000000000000000..596621bcb3c4e41f6875783bea308230dedcdfef
--- /dev/null
+++ b/server/node_modules/ramda/src/median.js
@@ -0,0 +1,35 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var mean = /*#__PURE__*/require('./mean');
+
+/**
+ * Returns the median of the given list of numbers.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list
+ * @return {Number}
+ * @see R.mean
+ * @example
+ *
+ *      R.median([2, 9, 7]); //=> 7
+ *      R.median([7, 2, 10, 9]); //=> 8
+ *      R.median([]); //=> NaN
+ */
+
+
+var median = /*#__PURE__*/_curry1(function median(list) {
+  var len = list.length;
+  if (len === 0) {
+    return NaN;
+  }
+  var width = 2 - len % 2;
+  var idx = (len - width) / 2;
+  return mean(Array.prototype.slice.call(list, 0).sort(function (a, b) {
+    return a < b ? -1 : a > b ? 1 : 0;
+  }).slice(idx, idx + width));
+});
+module.exports = median;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/memoizeWith.js b/server/node_modules/ramda/src/memoizeWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..5e364b8a272c6b6d00363e10fa182a6e60d6b67f
--- /dev/null
+++ b/server/node_modules/ramda/src/memoizeWith.js
@@ -0,0 +1,47 @@
+var _arity = /*#__PURE__*/require('./internal/_arity');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _has = /*#__PURE__*/require('./internal/_has');
+
+/**
+ * Creates a new function that, when invoked, caches the result of calling `fn`
+ * for a given argument set and returns the result. Subsequent calls to the
+ * memoized `fn` with the same argument set will not result in an additional
+ * call to `fn`; instead, the cached result for that set of arguments will be
+ * returned.
+ *
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Function
+ * @sig (*... -> String) -> (*... -> a) -> (*... -> a)
+ * @param {Function} fn The function to generate the cache key.
+ * @param {Function} fn The function to memoize.
+ * @return {Function} Memoized version of `fn`.
+ * @example
+ *
+ *      let count = 0;
+ *      const factorial = R.memoizeWith(R.identity, n => {
+ *        count += 1;
+ *        return R.product(R.range(1, n + 1));
+ *      });
+ *      factorial(5); //=> 120
+ *      factorial(5); //=> 120
+ *      factorial(5); //=> 120
+ *      count; //=> 1
+ */
+
+
+var memoizeWith = /*#__PURE__*/_curry2(function memoizeWith(mFn, fn) {
+  var cache = {};
+  return _arity(fn.length, function () {
+    var key = mFn.apply(this, arguments);
+    if (!_has(key, cache)) {
+      cache[key] = fn.apply(this, arguments);
+    }
+    return cache[key];
+  });
+});
+module.exports = memoizeWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/merge.js b/server/node_modules/ramda/src/merge.js
new file mode 100644
index 0000000000000000000000000000000000000000..f5479bfb60ee1e5d58d378a4a25e463429dc3935
--- /dev/null
+++ b/server/node_modules/ramda/src/merge.js
@@ -0,0 +1,34 @@
+var _objectAssign = /*#__PURE__*/require('./internal/_objectAssign');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Create a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects,
+ * the value from the second object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {k: v} -> {k: v} -> {k: v}
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeRight, R.mergeDeepRight, R.mergeWith, R.mergeWithKey
+ * @deprecated
+ * @example
+ *
+ *      R.merge({ 'name': 'fred', 'age': 10 }, { 'age': 40 });
+ *      //=> { 'name': 'fred', 'age': 40 }
+ *
+ *      const withDefaults = R.merge({x: 0, y: 0});
+ *      withDefaults({y: 2}); //=> {x: 0, y: 2}
+ * @symb R.merge(a, b) = {...a, ...b}
+ */
+
+
+var merge = /*#__PURE__*/_curry2(function merge(l, r) {
+  return _objectAssign({}, l, r);
+});
+module.exports = merge;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mergeAll.js b/server/node_modules/ramda/src/mergeAll.js
new file mode 100644
index 0000000000000000000000000000000000000000..d34d27651cdb1cf3d823b67f6b25143295ea7a93
--- /dev/null
+++ b/server/node_modules/ramda/src/mergeAll.js
@@ -0,0 +1,27 @@
+var _objectAssign = /*#__PURE__*/require('./internal/_objectAssign');
+
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Merges a list of objects together into one object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig [{k: v}] -> {k: v}
+ * @param {Array} list An array of objects
+ * @return {Object} A merged object.
+ * @see R.reduce
+ * @example
+ *
+ *      R.mergeAll([{foo:1},{bar:2},{baz:3}]); //=> {foo:1,bar:2,baz:3}
+ *      R.mergeAll([{foo:1},{foo:2},{bar:2}]); //=> {foo:2,bar:2}
+ * @symb R.mergeAll([{ x: 1 }, { y: 2 }, { z: 3 }]) = { x: 1, y: 2, z: 3 }
+ */
+
+
+var mergeAll = /*#__PURE__*/_curry1(function mergeAll(list) {
+  return _objectAssign.apply(null, [{}].concat(list));
+});
+module.exports = mergeAll;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mergeDeepLeft.js b/server/node_modules/ramda/src/mergeDeepLeft.js
new file mode 100644
index 0000000000000000000000000000000000000000..d7f49ea77933a5d41b82a20ebeb40f0a1c72829c
--- /dev/null
+++ b/server/node_modules/ramda/src/mergeDeepLeft.js
@@ -0,0 +1,33 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var mergeDeepWithKey = /*#__PURE__*/require('./mergeDeepWithKey');
+
+/**
+ * Creates a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects:
+ * - and both values are objects, the two values will be recursively merged
+ * - otherwise the value from the first object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig {a} -> {a} -> {a}
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.merge, R.mergeDeepRight, R.mergeDeepWith, R.mergeDeepWithKey
+ * @example
+ *
+ *      R.mergeDeepLeft({ name: 'fred', age: 10, contact: { email: 'moo@example.com' }},
+ *                      { age: 40, contact: { email: 'baa@example.com' }});
+ *      //=> { name: 'fred', age: 10, contact: { email: 'moo@example.com' }}
+ */
+
+
+var mergeDeepLeft = /*#__PURE__*/_curry2(function mergeDeepLeft(lObj, rObj) {
+  return mergeDeepWithKey(function (k, lVal, rVal) {
+    return lVal;
+  }, lObj, rObj);
+});
+module.exports = mergeDeepLeft;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mergeDeepRight.js b/server/node_modules/ramda/src/mergeDeepRight.js
new file mode 100644
index 0000000000000000000000000000000000000000..f06d40111b7752563e67496ccadd1720dce319dd
--- /dev/null
+++ b/server/node_modules/ramda/src/mergeDeepRight.js
@@ -0,0 +1,33 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var mergeDeepWithKey = /*#__PURE__*/require('./mergeDeepWithKey');
+
+/**
+ * Creates a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects:
+ * - and both values are objects, the two values will be recursively merged
+ * - otherwise the value from the second object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig {a} -> {a} -> {a}
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.merge, R.mergeDeepLeft, R.mergeDeepWith, R.mergeDeepWithKey
+ * @example
+ *
+ *      R.mergeDeepRight({ name: 'fred', age: 10, contact: { email: 'moo@example.com' }},
+ *                       { age: 40, contact: { email: 'baa@example.com' }});
+ *      //=> { name: 'fred', age: 40, contact: { email: 'baa@example.com' }}
+ */
+
+
+var mergeDeepRight = /*#__PURE__*/_curry2(function mergeDeepRight(lObj, rObj) {
+  return mergeDeepWithKey(function (k, lVal, rVal) {
+    return rVal;
+  }, lObj, rObj);
+});
+module.exports = mergeDeepRight;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mergeDeepWith.js b/server/node_modules/ramda/src/mergeDeepWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..cf85deeb785f74c4c7b2b8552e340d461ac9c855
--- /dev/null
+++ b/server/node_modules/ramda/src/mergeDeepWith.js
@@ -0,0 +1,39 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var mergeDeepWithKey = /*#__PURE__*/require('./mergeDeepWithKey');
+
+/**
+ * Creates a new object with the own properties of the two provided objects.
+ * If a key exists in both objects:
+ * - and both associated values are also objects then the values will be
+ *   recursively merged.
+ * - otherwise the provided function is applied to associated values using the
+ *   resulting value as the new value associated with the key.
+ * If a key only exists in one object, the value will be associated with the key
+ * of the resulting object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig ((a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.mergeWith, R.mergeDeepWithKey
+ * @example
+ *
+ *      R.mergeDeepWith(R.concat,
+ *                      { a: true, c: { values: [10, 20] }},
+ *                      { b: true, c: { values: [15, 35] }});
+ *      //=> { a: true, b: true, c: { values: [10, 20, 15, 35] }}
+ */
+
+
+var mergeDeepWith = /*#__PURE__*/_curry3(function mergeDeepWith(fn, lObj, rObj) {
+  return mergeDeepWithKey(function (k, lVal, rVal) {
+    return fn(lVal, rVal);
+  }, lObj, rObj);
+});
+module.exports = mergeDeepWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mergeDeepWithKey.js b/server/node_modules/ramda/src/mergeDeepWithKey.js
new file mode 100644
index 0000000000000000000000000000000000000000..8492bd04bd5a408e55dd48e5bcf671540e64bb48
--- /dev/null
+++ b/server/node_modules/ramda/src/mergeDeepWithKey.js
@@ -0,0 +1,46 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var _isObject = /*#__PURE__*/require('./internal/_isObject');
+
+var mergeWithKey = /*#__PURE__*/require('./mergeWithKey');
+
+/**
+ * Creates a new object with the own properties of the two provided objects.
+ * If a key exists in both objects:
+ * - and both associated values are also objects then the values will be
+ *   recursively merged.
+ * - otherwise the provided function is applied to the key and associated values
+ *   using the resulting value as the new value associated with the key.
+ * If a key only exists in one object, the value will be associated with the key
+ * of the resulting object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Object
+ * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} lObj
+ * @param {Object} rObj
+ * @return {Object}
+ * @see R.mergeWithKey, R.mergeDeepWith
+ * @example
+ *
+ *      let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r
+ *      R.mergeDeepWithKey(concatValues,
+ *                         { a: true, c: { thing: 'foo', values: [10, 20] }},
+ *                         { b: true, c: { thing: 'bar', values: [15, 35] }});
+ *      //=> { a: true, b: true, c: { thing: 'bar', values: [10, 20, 15, 35] }}
+ */
+
+
+var mergeDeepWithKey = /*#__PURE__*/_curry3(function mergeDeepWithKey(fn, lObj, rObj) {
+  return mergeWithKey(function (k, lVal, rVal) {
+    if (_isObject(lVal) && _isObject(rVal)) {
+      return mergeDeepWithKey(fn, lVal, rVal);
+    } else {
+      return fn(k, lVal, rVal);
+    }
+  }, lObj, rObj);
+});
+module.exports = mergeDeepWithKey;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mergeLeft.js b/server/node_modules/ramda/src/mergeLeft.js
new file mode 100644
index 0000000000000000000000000000000000000000..703afd7134509d7b6e84d1433d9c806f5be61448
--- /dev/null
+++ b/server/node_modules/ramda/src/mergeLeft.js
@@ -0,0 +1,32 @@
+var _objectAssign = /*#__PURE__*/require('./internal/_objectAssign');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Create a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects,
+ * the value from the first object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @category Object
+ * @sig {k: v} -> {k: v} -> {k: v}
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeRight, R.mergeDeepLeft, R.mergeWith, R.mergeWithKey
+ * @example
+ *
+ *      R.mergeLeft({ 'age': 40 }, { 'name': 'fred', 'age': 10 });
+ *      //=> { 'name': 'fred', 'age': 40 }
+ *
+ *      const resetToDefault = R.mergeLeft({x: 0});
+ *      resetToDefault({x: 5, y: 2}); //=> {x: 0, y: 2}
+ * @symb R.mergeLeft(a, b) = {...b, ...a}
+ */
+
+
+var mergeLeft = /*#__PURE__*/_curry2(function mergeLeft(l, r) {
+  return _objectAssign({}, r, l);
+});
+module.exports = mergeLeft;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mergeRight.js b/server/node_modules/ramda/src/mergeRight.js
new file mode 100644
index 0000000000000000000000000000000000000000..ec32cca02f9493cf509ce1c504ff10869c792383
--- /dev/null
+++ b/server/node_modules/ramda/src/mergeRight.js
@@ -0,0 +1,32 @@
+var _objectAssign = /*#__PURE__*/require('./internal/_objectAssign');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Create a new object with the own properties of the first object merged with
+ * the own properties of the second object. If a key exists in both objects,
+ * the value from the second object will be used.
+ *
+ * @func
+ * @memberOf R
+ * @category Object
+ * @sig {k: v} -> {k: v} -> {k: v}
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeLeft, R.mergeDeepRight, R.mergeWith, R.mergeWithKey
+ * @example
+ *
+ *      R.mergeRight({ 'name': 'fred', 'age': 10 }, { 'age': 40 });
+ *      //=> { 'name': 'fred', 'age': 40 }
+ *
+ *      const withDefaults = R.mergeRight({x: 0, y: 0});
+ *      withDefaults({y: 2}); //=> {x: 0, y: 2}
+ * @symb R.mergeRight(a, b) = {...a, ...b}
+ */
+
+
+var mergeRight = /*#__PURE__*/_curry2(function mergeRight(l, r) {
+  return _objectAssign({}, l, r);
+});
+module.exports = mergeRight;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mergeWith.js b/server/node_modules/ramda/src/mergeWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..f67cfee4dd989d873aa7cfe4f755a22ada28c738
--- /dev/null
+++ b/server/node_modules/ramda/src/mergeWith.js
@@ -0,0 +1,35 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var mergeWithKey = /*#__PURE__*/require('./mergeWithKey');
+
+/**
+ * Creates a new object with the own properties of the two provided objects. If
+ * a key exists in both objects, the provided function is applied to the values
+ * associated with the key in each object, with the result being used as the
+ * value associated with the key in the returned object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Object
+ * @sig ((a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeDeepWith, R.merge, R.mergeWithKey
+ * @example
+ *
+ *      R.mergeWith(R.concat,
+ *                  { a: true, values: [10, 20] },
+ *                  { b: true, values: [15, 35] });
+ *      //=> { a: true, b: true, values: [10, 20, 15, 35] }
+ */
+
+
+var mergeWith = /*#__PURE__*/_curry3(function mergeWith(fn, l, r) {
+  return mergeWithKey(function (_, _l, _r) {
+    return fn(_l, _r);
+  }, l, r);
+});
+module.exports = mergeWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/mergeWithKey.js b/server/node_modules/ramda/src/mergeWithKey.js
new file mode 100644
index 0000000000000000000000000000000000000000..121176f9c6dbab17abdf744bb51d25c6e8509779
--- /dev/null
+++ b/server/node_modules/ramda/src/mergeWithKey.js
@@ -0,0 +1,50 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var _has = /*#__PURE__*/require('./internal/_has');
+
+/**
+ * Creates a new object with the own properties of the two provided objects. If
+ * a key exists in both objects, the provided function is applied to the key
+ * and the values associated with the key in each object, with the result being
+ * used as the value associated with the key in the returned object.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Object
+ * @sig ((String, a, a) -> a) -> {a} -> {a} -> {a}
+ * @param {Function} fn
+ * @param {Object} l
+ * @param {Object} r
+ * @return {Object}
+ * @see R.mergeDeepWithKey, R.merge, R.mergeWith
+ * @example
+ *
+ *      let concatValues = (k, l, r) => k == 'values' ? R.concat(l, r) : r
+ *      R.mergeWithKey(concatValues,
+ *                     { a: true, thing: 'foo', values: [10, 20] },
+ *                     { b: true, thing: 'bar', values: [15, 35] });
+ *      //=> { a: true, b: true, thing: 'bar', values: [10, 20, 15, 35] }
+ * @symb R.mergeWithKey(f, { x: 1, y: 2 }, { y: 5, z: 3 }) = { x: 1, y: f('y', 2, 5), z: 3 }
+ */
+
+
+var mergeWithKey = /*#__PURE__*/_curry3(function mergeWithKey(fn, l, r) {
+  var result = {};
+  var k;
+
+  for (k in l) {
+    if (_has(k, l)) {
+      result[k] = _has(k, r) ? fn(k, l[k], r[k]) : l[k];
+    }
+  }
+
+  for (k in r) {
+    if (_has(k, r) && !_has(k, result)) {
+      result[k] = r[k];
+    }
+  }
+
+  return result;
+});
+module.exports = mergeWithKey;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/min.js b/server/node_modules/ramda/src/min.js
new file mode 100644
index 0000000000000000000000000000000000000000..035428043abf7600270a2814d35cbde23b7e5edb
--- /dev/null
+++ b/server/node_modules/ramda/src/min.js
@@ -0,0 +1,25 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns the smaller of its two arguments.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord a => a -> a -> a
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.minBy, R.max
+ * @example
+ *
+ *      R.min(789, 123); //=> 123
+ *      R.min('a', 'b'); //=> 'a'
+ */
+
+
+var min = /*#__PURE__*/_curry2(function min(a, b) {
+  return b < a ? b : a;
+});
+module.exports = min;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/minBy.js b/server/node_modules/ramda/src/minBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..d5f4a428b76b6e7713de68284fbe2651936162d5
--- /dev/null
+++ b/server/node_modules/ramda/src/minBy.js
@@ -0,0 +1,32 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Takes a function and two values, and returns whichever value produces the
+ * smaller result when passed to the provided function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Relation
+ * @sig Ord b => (a -> b) -> a -> a -> a
+ * @param {Function} f
+ * @param {*} a
+ * @param {*} b
+ * @return {*}
+ * @see R.min, R.maxBy
+ * @example
+ *
+ *      //  square :: Number -> Number
+ *      const square = n => n * n;
+ *
+ *      R.minBy(square, -3, 2); //=> 2
+ *
+ *      R.reduce(R.minBy(square), Infinity, [3, -5, 4, 1, -2]); //=> 1
+ *      R.reduce(R.minBy(square), Infinity, []); //=> Infinity
+ */
+
+
+var minBy = /*#__PURE__*/_curry3(function minBy(f, a, b) {
+  return f(b) < f(a) ? b : a;
+});
+module.exports = minBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/modulo.js b/server/node_modules/ramda/src/modulo.js
new file mode 100644
index 0000000000000000000000000000000000000000..af1a35a80725e056217b7e664c66741a3b5ee020
--- /dev/null
+++ b/server/node_modules/ramda/src/modulo.js
@@ -0,0 +1,33 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Divides the first parameter by the second and returns the remainder. Note
+ * that this function preserves the JavaScript-style behavior for modulo. For
+ * mathematical modulo see [`mathMod`](#mathMod).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The value to the divide.
+ * @param {Number} b The pseudo-modulus
+ * @return {Number} The result of `b % a`.
+ * @see R.mathMod
+ * @example
+ *
+ *      R.modulo(17, 3); //=> 2
+ *      // JS behavior:
+ *      R.modulo(-17, 3); //=> -2
+ *      R.modulo(17, -3); //=> 2
+ *
+ *      const isOdd = R.modulo(R.__, 2);
+ *      isOdd(42); //=> 0
+ *      isOdd(21); //=> 1
+ */
+
+
+var modulo = /*#__PURE__*/_curry2(function modulo(a, b) {
+  return a % b;
+});
+module.exports = modulo;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/move.js b/server/node_modules/ramda/src/move.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e62ba3ef81e926cbe496b5ec67b9d03393a8276
--- /dev/null
+++ b/server/node_modules/ramda/src/move.js
@@ -0,0 +1,32 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Move an item, at index `from`, to index `to`, in a list of elements.
+ * A new list will be created containing the new elements order.
+ *
+ * @func
+ * @memberOf R
+ * @category List
+ * @sig Number -> Number -> [a] -> [a]
+ * @param {Number} from The source index
+ * @param {Number} to The destination index
+ * @param {Array} list The list which will serve to realise the move
+ * @return {Array} The new list reordered
+ * @example
+ *
+ *      R.move(0, 2, ['a', 'b', 'c', 'd', 'e', 'f']); //=> ['b', 'c', 'a', 'd', 'e', 'f']
+ *      R.move(-1, 0, ['a', 'b', 'c', 'd', 'e', 'f']); //=> ['f', 'a', 'b', 'c', 'd', 'e'] list rotation
+ */
+
+
+var move = /*#__PURE__*/_curry3(function (from, to, list) {
+  var length = list.length;
+  var result = list.slice();
+  var positiveFrom = from < 0 ? length + from : from;
+  var positiveTo = to < 0 ? length + to : to;
+  var item = result.splice(positiveFrom, 1);
+
+  return positiveFrom < 0 || positiveFrom >= list.length || positiveTo < 0 || positiveTo >= list.length ? list : [].concat(result.slice(0, positiveTo)).concat(item).concat(result.slice(positiveTo, list.length));
+});
+
+module.exports = move;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/multiply.js b/server/node_modules/ramda/src/multiply.js
new file mode 100644
index 0000000000000000000000000000000000000000..2d640607c9d2e7936493ee5edf1d9ade99857d36
--- /dev/null
+++ b/server/node_modules/ramda/src/multiply.js
@@ -0,0 +1,28 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Multiplies two numbers. Equivalent to `a * b` but curried.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The first value.
+ * @param {Number} b The second value.
+ * @return {Number} The result of `a * b`.
+ * @see R.divide
+ * @example
+ *
+ *      const double = R.multiply(2);
+ *      const triple = R.multiply(3);
+ *      double(3);       //=>  6
+ *      triple(4);       //=> 12
+ *      R.multiply(2, 5);  //=> 10
+ */
+
+
+var multiply = /*#__PURE__*/_curry2(function multiply(a, b) {
+  return a * b;
+});
+module.exports = multiply;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/nAry.js b/server/node_modules/ramda/src/nAry.js
new file mode 100644
index 0000000000000000000000000000000000000000..b7607b9bbd3aff0fd27a9eabc40ff1038245b8fd
--- /dev/null
+++ b/server/node_modules/ramda/src/nAry.js
@@ -0,0 +1,85 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Wraps a function of any arity (including nullary) in a function that accepts
+ * exactly `n` parameters. Any extraneous parameters will not be passed to the
+ * supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig Number -> (* -> a) -> (* -> a)
+ * @param {Number} n The desired arity of the new function.
+ * @param {Function} fn The function to wrap.
+ * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
+ *         arity `n`.
+ * @see R.binary, R.unary
+ * @example
+ *
+ *      const takesTwoArgs = (a, b) => [a, b];
+ *
+ *      takesTwoArgs.length; //=> 2
+ *      takesTwoArgs(1, 2); //=> [1, 2]
+ *
+ *      const takesOneArg = R.nAry(1, takesTwoArgs);
+ *      takesOneArg.length; //=> 1
+ *      // Only `n` arguments are passed to the wrapped function
+ *      takesOneArg(1, 2); //=> [1, undefined]
+ * @symb R.nAry(0, f)(a, b) = f()
+ * @symb R.nAry(1, f)(a, b) = f(a)
+ * @symb R.nAry(2, f)(a, b) = f(a, b)
+ */
+
+
+var nAry = /*#__PURE__*/_curry2(function nAry(n, fn) {
+  switch (n) {
+    case 0:
+      return function () {
+        return fn.call(this);
+      };
+    case 1:
+      return function (a0) {
+        return fn.call(this, a0);
+      };
+    case 2:
+      return function (a0, a1) {
+        return fn.call(this, a0, a1);
+      };
+    case 3:
+      return function (a0, a1, a2) {
+        return fn.call(this, a0, a1, a2);
+      };
+    case 4:
+      return function (a0, a1, a2, a3) {
+        return fn.call(this, a0, a1, a2, a3);
+      };
+    case 5:
+      return function (a0, a1, a2, a3, a4) {
+        return fn.call(this, a0, a1, a2, a3, a4);
+      };
+    case 6:
+      return function (a0, a1, a2, a3, a4, a5) {
+        return fn.call(this, a0, a1, a2, a3, a4, a5);
+      };
+    case 7:
+      return function (a0, a1, a2, a3, a4, a5, a6) {
+        return fn.call(this, a0, a1, a2, a3, a4, a5, a6);
+      };
+    case 8:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7) {
+        return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7);
+      };
+    case 9:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7, a8) {
+        return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7, a8);
+      };
+    case 10:
+      return function (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) {
+        return fn.call(this, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+      };
+    default:
+      throw new Error('First argument to nAry must be a non-negative integer no greater than ten');
+  }
+});
+module.exports = nAry;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/negate.js b/server/node_modules/ramda/src/negate.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab8cac36c3de7bd851ce6ae53ac0189523011320
--- /dev/null
+++ b/server/node_modules/ramda/src/negate.js
@@ -0,0 +1,22 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Negates its argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Math
+ * @sig Number -> Number
+ * @param {Number} n
+ * @return {Number}
+ * @example
+ *
+ *      R.negate(42); //=> -42
+ */
+
+
+var negate = /*#__PURE__*/_curry1(function negate(n) {
+  return -n;
+});
+module.exports = negate;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/none.js b/server/node_modules/ramda/src/none.js
new file mode 100644
index 0000000000000000000000000000000000000000..b5eeb77814e4670c19f6b951dd66d38673b5c829
--- /dev/null
+++ b/server/node_modules/ramda/src/none.js
@@ -0,0 +1,37 @@
+var _complement = /*#__PURE__*/require('./internal/_complement');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var all = /*#__PURE__*/require('./all');
+
+/**
+ * Returns `true` if no elements of the list match the predicate, `false`
+ * otherwise.
+ *
+ * Dispatches to the `all` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> Boolean
+ * @param {Function} fn The predicate function.
+ * @param {Array} list The array to consider.
+ * @return {Boolean} `true` if the predicate is not satisfied by every element, `false` otherwise.
+ * @see R.all, R.any
+ * @example
+ *
+ *      const isEven = n => n % 2 === 0;
+ *      const isOdd = n => n % 2 === 1;
+ *
+ *      R.none(isEven, [1, 3, 5, 7, 9, 11]); //=> true
+ *      R.none(isOdd, [1, 3, 5, 7, 8, 11]); //=> false
+ */
+
+
+var none = /*#__PURE__*/_curry2(function none(fn, input) {
+  return all(_complement(fn), input);
+});
+module.exports = none;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/not.js b/server/node_modules/ramda/src/not.js
new file mode 100644
index 0000000000000000000000000000000000000000..37df36b21acf3a6d0d7dfa34f996236e55341eea
--- /dev/null
+++ b/server/node_modules/ramda/src/not.js
@@ -0,0 +1,27 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * A function that returns the `!` of its argument. It will return `true` when
+ * passed false-y value, and `false` when passed a truth-y one.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig * -> Boolean
+ * @param {*} a any value
+ * @return {Boolean} the logical inverse of passed argument.
+ * @see R.complement
+ * @example
+ *
+ *      R.not(true); //=> false
+ *      R.not(false); //=> true
+ *      R.not(0); //=> true
+ *      R.not(1); //=> false
+ */
+
+
+var not = /*#__PURE__*/_curry1(function not(a) {
+  return !a;
+});
+module.exports = not;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/nth.js b/server/node_modules/ramda/src/nth.js
new file mode 100644
index 0000000000000000000000000000000000000000..05d7cb7fc8ca24215bb157c0cf19a8a7309c4a60
--- /dev/null
+++ b/server/node_modules/ramda/src/nth.js
@@ -0,0 +1,37 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _isString = /*#__PURE__*/require('./internal/_isString');
+
+/**
+ * Returns the nth element of the given list or string. If n is negative the
+ * element at index length + n is returned.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> [a] -> a | Undefined
+ * @sig Number -> String -> String
+ * @param {Number} offset
+ * @param {*} list
+ * @return {*}
+ * @example
+ *
+ *      const list = ['foo', 'bar', 'baz', 'quux'];
+ *      R.nth(1, list); //=> 'bar'
+ *      R.nth(-1, list); //=> 'quux'
+ *      R.nth(-99, list); //=> undefined
+ *
+ *      R.nth(2, 'abc'); //=> 'c'
+ *      R.nth(3, 'abc'); //=> ''
+ * @symb R.nth(-1, [a, b, c]) = c
+ * @symb R.nth(0, [a, b, c]) = a
+ * @symb R.nth(1, [a, b, c]) = b
+ */
+
+
+var nth = /*#__PURE__*/_curry2(function nth(offset, list) {
+  var idx = offset < 0 ? list.length + offset : offset;
+  return _isString(list) ? list.charAt(idx) : list[idx];
+});
+module.exports = nth;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/nthArg.js b/server/node_modules/ramda/src/nthArg.js
new file mode 100644
index 0000000000000000000000000000000000000000..263272cd50a2f0544730f53a524d76036b6e3bd0
--- /dev/null
+++ b/server/node_modules/ramda/src/nthArg.js
@@ -0,0 +1,33 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+var nth = /*#__PURE__*/require('./nth');
+
+/**
+ * Returns a function which returns its nth argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category Function
+ * @sig Number -> *... -> *
+ * @param {Number} n
+ * @return {Function}
+ * @example
+ *
+ *      R.nthArg(1)('a', 'b', 'c'); //=> 'b'
+ *      R.nthArg(-1)('a', 'b', 'c'); //=> 'c'
+ * @symb R.nthArg(-1)(a, b, c) = c
+ * @symb R.nthArg(0)(a, b, c) = a
+ * @symb R.nthArg(1)(a, b, c) = b
+ */
+
+
+var nthArg = /*#__PURE__*/_curry1(function nthArg(n) {
+  var arity = n < 0 ? 1 : n + 1;
+  return curryN(arity, function () {
+    return nth(n, arguments);
+  });
+});
+module.exports = nthArg;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/o.js b/server/node_modules/ramda/src/o.js
new file mode 100644
index 0000000000000000000000000000000000000000..872556d9de665cea47c4bf1bb791358a4ad68ae1
--- /dev/null
+++ b/server/node_modules/ramda/src/o.js
@@ -0,0 +1,35 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * `o` is a curried composition function that returns a unary function.
+ * Like [`compose`](#compose), `o` performs right-to-left function composition.
+ * Unlike [`compose`](#compose), the rightmost function passed to `o` will be
+ * invoked with only one argument. Also, unlike [`compose`](#compose), `o` is
+ * limited to accepting only 2 unary functions. The name o was chosen because
+ * of its similarity to the mathematical composition operator ∘.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category Function
+ * @sig (b -> c) -> (a -> b) -> a -> c
+ * @param {Function} f
+ * @param {Function} g
+ * @return {Function}
+ * @see R.compose, R.pipe
+ * @example
+ *
+ *      const classyGreeting = name => "The name's " + name.last + ", " + name.first + " " + name.last
+ *      const yellGreeting = R.o(R.toUpper, classyGreeting);
+ *      yellGreeting({first: 'James', last: 'Bond'}); //=> "THE NAME'S BOND, JAMES BOND"
+ *
+ *      R.o(R.multiply(10), R.add(10))(-4) //=> 60
+ *
+ * @symb R.o(f, g, x) = f(g(x))
+ */
+
+
+var o = /*#__PURE__*/_curry3(function o(f, g, x) {
+  return f(g(x));
+});
+module.exports = o;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/objOf.js b/server/node_modules/ramda/src/objOf.js
new file mode 100644
index 0000000000000000000000000000000000000000..b27be0517d91a3328f9473a92c9bb076006ccf7c
--- /dev/null
+++ b/server/node_modules/ramda/src/objOf.js
@@ -0,0 +1,30 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Creates an object containing a single key:value pair.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Object
+ * @sig String -> a -> {String:a}
+ * @param {String} key
+ * @param {*} val
+ * @return {Object}
+ * @see R.pair
+ * @example
+ *
+ *      const matchPhrases = R.compose(
+ *        R.objOf('must'),
+ *        R.map(R.objOf('match_phrase'))
+ *      );
+ *      matchPhrases(['foo', 'bar', 'baz']); //=> {must: [{match_phrase: 'foo'}, {match_phrase: 'bar'}, {match_phrase: 'baz'}]}
+ */
+
+
+var objOf = /*#__PURE__*/_curry2(function objOf(key, val) {
+  var obj = {};
+  obj[key] = val;
+  return obj;
+});
+module.exports = objOf;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/of.js b/server/node_modules/ramda/src/of.js
new file mode 100644
index 0000000000000000000000000000000000000000..5f981b61f4ee63deb7e0215bdb748fe08fb14db9
--- /dev/null
+++ b/server/node_modules/ramda/src/of.js
@@ -0,0 +1,26 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _of = /*#__PURE__*/require('./internal/_of');
+
+/**
+ * Returns a singleton array containing the value provided.
+ *
+ * Note this `of` is different from the ES6 `of`; See
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/of
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category Function
+ * @sig a -> [a]
+ * @param {*} x any value
+ * @return {Array} An array wrapping `x`.
+ * @example
+ *
+ *      R.of(null); //=> [null]
+ *      R.of([42]); //=> [[42]]
+ */
+
+
+var of = /*#__PURE__*/_curry1(_of);
+module.exports = of;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/omit.js b/server/node_modules/ramda/src/omit.js
new file mode 100644
index 0000000000000000000000000000000000000000..8a5b15c81186c1ba015d96e214b54e8c0a68ed38
--- /dev/null
+++ b/server/node_modules/ramda/src/omit.js
@@ -0,0 +1,39 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns a partial copy of an object omitting the keys specified.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [String] -> {String: *} -> {String: *}
+ * @param {Array} names an array of String property names to omit from the new object
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with properties from `names` not on it.
+ * @see R.pick
+ * @example
+ *
+ *      R.omit(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, c: 3}
+ */
+
+
+var omit = /*#__PURE__*/_curry2(function omit(names, obj) {
+  var result = {};
+  var index = {};
+  var idx = 0;
+  var len = names.length;
+
+  while (idx < len) {
+    index[names[idx]] = 1;
+    idx += 1;
+  }
+
+  for (var prop in obj) {
+    if (!index.hasOwnProperty(prop)) {
+      result[prop] = obj[prop];
+    }
+  }
+  return result;
+});
+module.exports = omit;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/once.js b/server/node_modules/ramda/src/once.js
new file mode 100644
index 0000000000000000000000000000000000000000..e366bd84c5eb09b73a72ac9c51e0965ec2f0f9ac
--- /dev/null
+++ b/server/node_modules/ramda/src/once.js
@@ -0,0 +1,38 @@
+var _arity = /*#__PURE__*/require('./internal/_arity');
+
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Accepts a function `fn` and returns a function that guards invocation of
+ * `fn` such that `fn` can only ever be called once, no matter how many times
+ * the returned function is invoked. The first value calculated is returned in
+ * subsequent invocations.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (a... -> b) -> (a... -> b)
+ * @param {Function} fn The function to wrap in a call-only-once wrapper.
+ * @return {Function} The wrapped function.
+ * @example
+ *
+ *      const addOneOnce = R.once(x => x + 1);
+ *      addOneOnce(10); //=> 11
+ *      addOneOnce(addOneOnce(50)); //=> 11
+ */
+
+
+var once = /*#__PURE__*/_curry1(function once(fn) {
+  var called = false;
+  var result;
+  return _arity(fn.length, function () {
+    if (called) {
+      return result;
+    }
+    called = true;
+    result = fn.apply(this, arguments);
+    return result;
+  });
+});
+module.exports = once;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/or.js b/server/node_modules/ramda/src/or.js
new file mode 100644
index 0000000000000000000000000000000000000000..9d1c8e2c198147251a41056bc2d2e858b58cccea
--- /dev/null
+++ b/server/node_modules/ramda/src/or.js
@@ -0,0 +1,28 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns `true` if one or both of its arguments are `true`. Returns `false`
+ * if both arguments are `false`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Logic
+ * @sig a -> b -> a | b
+ * @param {Any} a
+ * @param {Any} b
+ * @return {Any} the first argument if truthy, otherwise the second argument.
+ * @see R.either
+ * @example
+ *
+ *      R.or(true, true); //=> true
+ *      R.or(true, false); //=> true
+ *      R.or(false, true); //=> true
+ *      R.or(false, false); //=> false
+ */
+
+
+var or = /*#__PURE__*/_curry2(function or(a, b) {
+  return a || b;
+});
+module.exports = or;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/otherwise.js b/server/node_modules/ramda/src/otherwise.js
new file mode 100644
index 0000000000000000000000000000000000000000..5222c83e1adfccf62677e0ed30453d54fd8fb9ca
--- /dev/null
+++ b/server/node_modules/ramda/src/otherwise.js
@@ -0,0 +1,39 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _assertPromise = /*#__PURE__*/require('./internal/_assertPromise');
+
+/**
+ * Returns the result of applying the onFailure function to the value inside
+ * a failed promise. This is useful for handling rejected promises
+ * inside function compositions.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig (e -> b) -> (Promise e a) -> (Promise e b)
+ * @sig (e -> (Promise f b)) -> (Promise e a) -> (Promise f b)
+ * @param {Function} onFailure The function to apply. Can return a value or a promise of a value.
+ * @param {Promise} p
+ * @return {Promise} The result of calling `p.then(null, onFailure)`
+ * @see R.then
+ * @example
+ *
+ *      var failedFetch = (id) => Promise.reject('bad ID');
+ *      var useDefault = () => ({ firstName: 'Bob', lastName: 'Loblaw' })
+ *
+ *      //recoverFromFailure :: String -> Promise ({firstName, lastName})
+ *      var recoverFromFailure = R.pipe(
+ *        failedFetch,
+ *        R.otherwise(useDefault),
+ *        R.then(R.pick(['firstName', 'lastName'])),
+ *      );
+ *      recoverFromFailure(12345).then(console.log)
+ */
+
+
+var otherwise = /*#__PURE__*/_curry2(function otherwise(f, p) {
+  _assertPromise('otherwise', p);
+
+  return p.then(null, f);
+});
+module.exports = otherwise;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/over.js b/server/node_modules/ramda/src/over.js
new file mode 100644
index 0000000000000000000000000000000000000000..14f20f1e6748b70c36ed09c2f3fb995b5d7bf49c
--- /dev/null
+++ b/server/node_modules/ramda/src/over.js
@@ -0,0 +1,43 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+// `Identity` is a functor that holds a single value, where `map` simply
+// transforms the held value with the provided function.
+
+
+var Identity = function (x) {
+  return { value: x, map: function (f) {
+      return Identity(f(x));
+    } };
+};
+
+/**
+ * Returns the result of "setting" the portion of the given data structure
+ * focused by the given lens to the result of applying the given function to
+ * the focused value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Lens s a -> (a -> a) -> s -> s
+ * @param {Lens} lens
+ * @param {*} v
+ * @param {*} x
+ * @return {*}
+ * @see R.prop, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const headLens = R.lensIndex(0);
+ *
+ *      R.over(headLens, R.toUpper, ['foo', 'bar', 'baz']); //=> ['FOO', 'bar', 'baz']
+ */
+var over = /*#__PURE__*/_curry3(function over(lens, f, x) {
+  // The value returned by the getter function is first transformed with `f`,
+  // then set as the value of an `Identity`. This is then mapped over with the
+  // setter function of the lens.
+  return lens(function (y) {
+    return Identity(f(y));
+  })(x).value;
+});
+module.exports = over;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pair.js b/server/node_modules/ramda/src/pair.js
new file mode 100644
index 0000000000000000000000000000000000000000..425d63dd94fa68c482385e80dddd19f36c23341f
--- /dev/null
+++ b/server/node_modules/ramda/src/pair.js
@@ -0,0 +1,24 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Takes two arguments, `fst` and `snd`, and returns `[fst, snd]`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category List
+ * @sig a -> b -> (a,b)
+ * @param {*} fst
+ * @param {*} snd
+ * @return {Array}
+ * @see R.objOf, R.of
+ * @example
+ *
+ *      R.pair('foo', 'bar'); //=> ['foo', 'bar']
+ */
+
+
+var pair = /*#__PURE__*/_curry2(function pair(fst, snd) {
+  return [fst, snd];
+});
+module.exports = pair;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/partial.js b/server/node_modules/ramda/src/partial.js
new file mode 100644
index 0000000000000000000000000000000000000000..0ff8b140120b7dd2322d999f4d0d824b9d01799e
--- /dev/null
+++ b/server/node_modules/ramda/src/partial.js
@@ -0,0 +1,36 @@
+var _concat = /*#__PURE__*/require('./internal/_concat');
+
+var _createPartialApplicator = /*#__PURE__*/require('./internal/_createPartialApplicator');
+
+/**
+ * Takes a function `f` and a list of arguments, and returns a function `g`.
+ * When applied, `g` returns the result of applying `f` to the arguments
+ * provided initially followed by the arguments provided to `g`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((a, b, c, ..., n) -> x) -> [a, b, c, ...] -> ((d, e, f, ..., n) -> x)
+ * @param {Function} f
+ * @param {Array} args
+ * @return {Function}
+ * @see R.partialRight, R.curry
+ * @example
+ *
+ *      const multiply2 = (a, b) => a * b;
+ *      const double = R.partial(multiply2, [2]);
+ *      double(2); //=> 4
+ *
+ *      const greet = (salutation, title, firstName, lastName) =>
+ *        salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
+ *
+ *      const sayHello = R.partial(greet, ['Hello']);
+ *      const sayHelloToMs = R.partial(sayHello, ['Ms.']);
+ *      sayHelloToMs('Jane', 'Jones'); //=> 'Hello, Ms. Jane Jones!'
+ * @symb R.partial(f, [a, b])(c, d) = f(a, b, c, d)
+ */
+
+
+var partial = /*#__PURE__*/_createPartialApplicator(_concat);
+module.exports = partial;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/partialRight.js b/server/node_modules/ramda/src/partialRight.js
new file mode 100644
index 0000000000000000000000000000000000000000..8b2ff03d1c1d7ea6f900ef5bc3565abd4585db99
--- /dev/null
+++ b/server/node_modules/ramda/src/partialRight.js
@@ -0,0 +1,34 @@
+var _concat = /*#__PURE__*/require('./internal/_concat');
+
+var _createPartialApplicator = /*#__PURE__*/require('./internal/_createPartialApplicator');
+
+var flip = /*#__PURE__*/require('./flip');
+
+/**
+ * Takes a function `f` and a list of arguments, and returns a function `g`.
+ * When applied, `g` returns the result of applying `f` to the arguments
+ * provided to `g` followed by the arguments provided initially.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((a, b, c, ..., n) -> x) -> [d, e, f, ..., n] -> ((a, b, c, ...) -> x)
+ * @param {Function} f
+ * @param {Array} args
+ * @return {Function}
+ * @see R.partial
+ * @example
+ *
+ *      const greet = (salutation, title, firstName, lastName) =>
+ *        salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
+ *
+ *      const greetMsJaneJones = R.partialRight(greet, ['Ms.', 'Jane', 'Jones']);
+ *
+ *      greetMsJaneJones('Hello'); //=> 'Hello, Ms. Jane Jones!'
+ * @symb R.partialRight(f, [a, b])(c, d) = f(c, d, a, b)
+ */
+
+
+var partialRight = /*#__PURE__*/_createPartialApplicator( /*#__PURE__*/flip(_concat));
+module.exports = partialRight;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/partition.js b/server/node_modules/ramda/src/partition.js
new file mode 100644
index 0000000000000000000000000000000000000000..a16aa8e39a2cecaf44120a357411a54d634ba2fa
--- /dev/null
+++ b/server/node_modules/ramda/src/partition.js
@@ -0,0 +1,34 @@
+var filter = /*#__PURE__*/require('./filter');
+
+var juxt = /*#__PURE__*/require('./juxt');
+
+var reject = /*#__PURE__*/require('./reject');
+
+/**
+ * Takes a predicate and a list or other `Filterable` object and returns the
+ * pair of filterable objects of the same type of elements which do and do not
+ * satisfy, the predicate, respectively. Filterable objects include plain objects or any object
+ * that has a filter method such as `Array`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.4
+ * @category List
+ * @sig Filterable f => (a -> Boolean) -> f a -> [f a, f a]
+ * @param {Function} pred A predicate to determine which side the element belongs to.
+ * @param {Array} filterable the list (or other filterable) to partition.
+ * @return {Array} An array, containing first the subset of elements that satisfy the
+ *         predicate, and second the subset of elements that do not satisfy.
+ * @see R.filter, R.reject
+ * @example
+ *
+ *      R.partition(R.includes('s'), ['sss', 'ttt', 'foo', 'bars']);
+ *      // => [ [ 'sss', 'bars' ],  [ 'ttt', 'foo' ] ]
+ *
+ *      R.partition(R.includes('s'), { a: 'sss', b: 'ttt', foo: 'bars' });
+ *      // => [ { a: 'sss', foo: 'bars' }, { b: 'ttt' }  ]
+ */
+
+
+var partition = /*#__PURE__*/juxt([filter, reject]);
+module.exports = partition;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/path.js b/server/node_modules/ramda/src/path.js
new file mode 100644
index 0000000000000000000000000000000000000000..ea477c0ebfc95ab1109c4492fc34da643638005b
--- /dev/null
+++ b/server/node_modules/ramda/src/path.js
@@ -0,0 +1,35 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Retrieve the value at a given path.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> {a} -> a | Undefined
+ * @param {Array} path The path to use.
+ * @param {Object} obj The object to retrieve the nested property from.
+ * @return {*} The data at `path`.
+ * @see R.prop
+ * @example
+ *
+ *      R.path(['a', 'b'], {a: {b: 2}}); //=> 2
+ *      R.path(['a', 'b'], {c: {b: 2}}); //=> undefined
+ */
+
+
+var path = /*#__PURE__*/_curry2(function path(paths, obj) {
+  var val = obj;
+  var idx = 0;
+  while (idx < paths.length) {
+    if (val == null) {
+      return;
+    }
+    val = val[paths[idx]];
+    idx += 1;
+  }
+  return val;
+});
+module.exports = path;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pathEq.js b/server/node_modules/ramda/src/pathEq.js
new file mode 100644
index 0000000000000000000000000000000000000000..285bb96c37bfe876d00eb9e3bceec10dafd034ef
--- /dev/null
+++ b/server/node_modules/ramda/src/pathEq.js
@@ -0,0 +1,36 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var equals = /*#__PURE__*/require('./equals');
+
+var path = /*#__PURE__*/require('./path');
+
+/**
+ * Determines whether a nested path on an object has a specific value, in
+ * [`R.equals`](#equals) terms. Most likely used to filter a list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category Relation
+ * @typedefn Idx = String | Int
+ * @sig [Idx] -> a -> {a} -> Boolean
+ * @param {Array} path The path of the nested property to use
+ * @param {*} val The value to compare the nested property with
+ * @param {Object} obj The object to check the nested property in
+ * @return {Boolean} `true` if the value equals the nested object property,
+ *         `false` otherwise.
+ * @example
+ *
+ *      const user1 = { address: { zipCode: 90210 } };
+ *      const user2 = { address: { zipCode: 55555 } };
+ *      const user3 = { name: 'Bob' };
+ *      const users = [ user1, user2, user3 ];
+ *      const isFamous = R.pathEq(['address', 'zipCode'], 90210);
+ *      R.filter(isFamous, users); //=> [ user1 ]
+ */
+
+
+var pathEq = /*#__PURE__*/_curry3(function pathEq(_path, val, obj) {
+  return equals(path(_path, obj), val);
+});
+module.exports = pathEq;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pathOr.js b/server/node_modules/ramda/src/pathOr.js
new file mode 100644
index 0000000000000000000000000000000000000000..8cc1abe89ad11f5ec29927caf0fdd79ba013f59c
--- /dev/null
+++ b/server/node_modules/ramda/src/pathOr.js
@@ -0,0 +1,31 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var defaultTo = /*#__PURE__*/require('./defaultTo');
+
+var path = /*#__PURE__*/require('./path');
+
+/**
+ * If the given, non-null object has a value at the given path, returns the
+ * value at that path. Otherwise returns the provided default value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Object
+ * @typedefn Idx = String | Int
+ * @sig a -> [Idx] -> {a} -> a
+ * @param {*} d The default value.
+ * @param {Array} p The path to use.
+ * @param {Object} obj The object to retrieve the nested property from.
+ * @return {*} The data at `path` of the supplied object or the default value.
+ * @example
+ *
+ *      R.pathOr('N/A', ['a', 'b'], {a: {b: 2}}); //=> 2
+ *      R.pathOr('N/A', ['a', 'b'], {c: {b: 2}}); //=> "N/A"
+ */
+
+
+var pathOr = /*#__PURE__*/_curry3(function pathOr(d, p, obj) {
+  return defaultTo(d, path(p, obj));
+});
+module.exports = pathOr;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pathSatisfies.js b/server/node_modules/ramda/src/pathSatisfies.js
new file mode 100644
index 0000000000000000000000000000000000000000..1289cc5fba8fabde3f031617ce7d6da3fd2e3859
--- /dev/null
+++ b/server/node_modules/ramda/src/pathSatisfies.js
@@ -0,0 +1,29 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var path = /*#__PURE__*/require('./path');
+
+/**
+ * Returns `true` if the specified object property at given path satisfies the
+ * given predicate; `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Logic
+ * @typedefn Idx = String | Int
+ * @sig (a -> Boolean) -> [Idx] -> {a} -> Boolean
+ * @param {Function} pred
+ * @param {Array} propPath
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.propSatisfies, R.path
+ * @example
+ *
+ *      R.pathSatisfies(y => y > 0, ['x', 'y'], {x: {y: 2}}); //=> true
+ */
+
+
+var pathSatisfies = /*#__PURE__*/_curry3(function pathSatisfies(pred, propPath, obj) {
+  return propPath.length > 0 && pred(path(propPath, obj));
+});
+module.exports = pathSatisfies;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pick.js b/server/node_modules/ramda/src/pick.js
new file mode 100644
index 0000000000000000000000000000000000000000..aa704d980653d89739ccbd6ac3dc6842be5b88f3
--- /dev/null
+++ b/server/node_modules/ramda/src/pick.js
@@ -0,0 +1,34 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns a partial copy of an object containing only the keys specified. If
+ * the key does not exist, the property is ignored.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [k] -> {k: v} -> {k: v}
+ * @param {Array} names an array of String property names to copy onto a new object
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with only properties from `names` on it.
+ * @see R.omit, R.props
+ * @example
+ *
+ *      R.pick(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4}
+ *      R.pick(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1}
+ */
+
+
+var pick = /*#__PURE__*/_curry2(function pick(names, obj) {
+  var result = {};
+  var idx = 0;
+  while (idx < names.length) {
+    if (names[idx] in obj) {
+      result[names[idx]] = obj[names[idx]];
+    }
+    idx += 1;
+  }
+  return result;
+});
+module.exports = pick;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pickAll.js b/server/node_modules/ramda/src/pickAll.js
new file mode 100644
index 0000000000000000000000000000000000000000..75322df41b3742dc870c1ea5536cd5c51f41918d
--- /dev/null
+++ b/server/node_modules/ramda/src/pickAll.js
@@ -0,0 +1,34 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Similar to `pick` except that this one includes a `key: undefined` pair for
+ * properties that don't exist.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [k] -> {k: v} -> {k: v}
+ * @param {Array} names an array of String property names to copy onto a new object
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with only properties from `names` on it.
+ * @see R.pick
+ * @example
+ *
+ *      R.pickAll(['a', 'd'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, d: 4}
+ *      R.pickAll(['a', 'e', 'f'], {a: 1, b: 2, c: 3, d: 4}); //=> {a: 1, e: undefined, f: undefined}
+ */
+
+
+var pickAll = /*#__PURE__*/_curry2(function pickAll(names, obj) {
+  var result = {};
+  var idx = 0;
+  var len = names.length;
+  while (idx < len) {
+    var name = names[idx];
+    result[name] = obj[name];
+    idx += 1;
+  }
+  return result;
+});
+module.exports = pickAll;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pickBy.js b/server/node_modules/ramda/src/pickBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..9853bb5fd6c277868c2ff1d8240093d11dbce8ef
--- /dev/null
+++ b/server/node_modules/ramda/src/pickBy.js
@@ -0,0 +1,34 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns a partial copy of an object containing only the keys that satisfy
+ * the supplied predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Object
+ * @sig ((v, k) -> Boolean) -> {k: v} -> {k: v}
+ * @param {Function} pred A predicate to determine whether or not a key
+ *        should be included on the output object.
+ * @param {Object} obj The object to copy from
+ * @return {Object} A new object with only properties that satisfy `pred`
+ *         on it.
+ * @see R.pick, R.filter
+ * @example
+ *
+ *      const isUpperCase = (val, key) => key.toUpperCase() === key;
+ *      R.pickBy(isUpperCase, {a: 1, b: 2, A: 3, B: 4}); //=> {A: 3, B: 4}
+ */
+
+
+var pickBy = /*#__PURE__*/_curry2(function pickBy(test, obj) {
+  var result = {};
+  for (var prop in obj) {
+    if (test(obj[prop], prop, obj)) {
+      result[prop] = obj[prop];
+    }
+  }
+  return result;
+});
+module.exports = pickBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pipe.js b/server/node_modules/ramda/src/pipe.js
new file mode 100644
index 0000000000000000000000000000000000000000..b74afe54f43df581df7550de79e99301da8d111b
--- /dev/null
+++ b/server/node_modules/ramda/src/pipe.js
@@ -0,0 +1,40 @@
+var _arity = /*#__PURE__*/require('./internal/_arity');
+
+var _pipe = /*#__PURE__*/require('./internal/_pipe');
+
+var reduce = /*#__PURE__*/require('./reduce');
+
+var tail = /*#__PURE__*/require('./tail');
+
+/**
+ * Performs left-to-right function composition. The leftmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * In some libraries this function is named `sequence`.
+ *
+ * **Note:** The result of pipe is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)) -> ((a, b, ..., n) -> z)
+ * @param {...Function} functions
+ * @return {Function}
+ * @see R.compose
+ * @example
+ *
+ *      const f = R.pipe(Math.pow, R.negate, R.inc);
+ *
+ *      f(3, 4); // -(3^4) + 1
+ * @symb R.pipe(f, g, h)(a, b) = h(g(f(a, b)))
+ */
+
+
+function pipe() {
+  if (arguments.length === 0) {
+    throw new Error('pipe requires at least one argument');
+  }
+  return _arity(arguments[0].length, reduce(_pipe, arguments[0], tail(arguments)));
+}
+module.exports = pipe;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pipeK.js b/server/node_modules/ramda/src/pipeK.js
new file mode 100644
index 0000000000000000000000000000000000000000..c02f0678bcfdb980cbb43cf7edbbc613c3c76a77
--- /dev/null
+++ b/server/node_modules/ramda/src/pipeK.js
@@ -0,0 +1,48 @@
+var composeK = /*#__PURE__*/require('./composeK');
+
+var reverse = /*#__PURE__*/require('./reverse');
+
+/**
+ * Returns the left-to-right Kleisli composition of the provided functions,
+ * each of which must return a value of a type supported by [`chain`](#chain).
+ *
+ * `R.pipeK(f, g, h)` is equivalent to `R.pipe(f, R.chain(g), R.chain(h))`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Function
+ * @sig Chain m => ((a -> m b), (b -> m c), ..., (y -> m z)) -> (a -> m z)
+ * @param {...Function}
+ * @return {Function}
+ * @see R.composeK
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      //  parseJson :: String -> Maybe *
+ *      //  get :: String -> Object -> Maybe *
+ *
+ *      //  getStateCode :: Maybe String -> Maybe String
+ *      const getStateCode = R.pipeK(
+ *        parseJson,
+ *        get('user'),
+ *        get('address'),
+ *        get('state'),
+ *        R.compose(Maybe.of, R.toUpper)
+ *      );
+ *
+ *      getStateCode('{"user":{"address":{"state":"ny"}}}');
+ *      //=> Just('NY')
+ *      getStateCode('[Invalid JSON]');
+ *      //=> Nothing()
+ * @symb R.pipeK(f, g, h)(a) = R.chain(h, R.chain(g, f(a)))
+ */
+
+
+function pipeK() {
+  if (arguments.length === 0) {
+    throw new Error('pipeK requires at least one argument');
+  }
+  return composeK.apply(this, reverse(arguments));
+}
+module.exports = pipeK;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pipeP.js b/server/node_modules/ramda/src/pipeP.js
new file mode 100644
index 0000000000000000000000000000000000000000..27be5530909d2dbbe754033e08676970489983ef
--- /dev/null
+++ b/server/node_modules/ramda/src/pipeP.js
@@ -0,0 +1,36 @@
+var _arity = /*#__PURE__*/require('./internal/_arity');
+
+var _pipeP = /*#__PURE__*/require('./internal/_pipeP');
+
+var reduce = /*#__PURE__*/require('./reduce');
+
+var tail = /*#__PURE__*/require('./tail');
+
+/**
+ * Performs left-to-right composition of one or more Promise-returning
+ * functions. The leftmost function may have any arity; the remaining functions
+ * must be unary.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category Function
+ * @sig ((a -> Promise b), (b -> Promise c), ..., (y -> Promise z)) -> (a -> Promise z)
+ * @param {...Function} functions
+ * @return {Function}
+ * @see R.composeP
+ * @deprecated since v0.26.0
+ * @example
+ *
+ *      //  followersForUser :: String -> Promise [User]
+ *      const followersForUser = R.pipeP(db.getUserById, db.getFollowers);
+ */
+
+
+function pipeP() {
+  if (arguments.length === 0) {
+    throw new Error('pipeP requires at least one argument');
+  }
+  return _arity(arguments[0].length, reduce(_pipeP, arguments[0], tail(arguments)));
+}
+module.exports = pipeP;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pipeWith.js b/server/node_modules/ramda/src/pipeWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..ee2ad2d8544c75cb8bc7f82e00a01cc42e60f8e6
--- /dev/null
+++ b/server/node_modules/ramda/src/pipeWith.js
@@ -0,0 +1,50 @@
+var _arity = /*#__PURE__*/require('./internal/_arity');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var head = /*#__PURE__*/require('./head');
+
+var _reduce = /*#__PURE__*/require('./internal/_reduce');
+
+var tail = /*#__PURE__*/require('./tail');
+
+var identity = /*#__PURE__*/require('./identity');
+
+/**
+ * Performs left-to-right function composition using transforming function. The leftmost function may have
+ * any arity; the remaining functions must be unary.
+ *
+ * **Note:** The result of pipeWith is not automatically curried.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig ((* -> *), [((a, b, ..., n) -> o), (o -> p), ..., (x -> y), (y -> z)]) -> ((a, b, ..., n) -> z)
+ * @param {...Function} functions
+ * @return {Function}
+ * @see R.composeWith, R.pipe
+ * @example
+ *
+ *      const pipeWhileNotNil = R.pipeWith((f, res) => R.isNil(res) ? res : f(res));
+ *      const f = pipeWhileNotNil([Math.pow, R.negate, R.inc])
+ *
+ *      f(3, 4); // -(3^4) + 1
+ * @symb R.pipeWith(f)([g, h, i])(...args) = f(i, f(h, f(g, ...args)))
+ */
+
+
+var pipeWith = /*#__PURE__*/_curry2(function pipeWith(xf, list) {
+  if (list.length <= 0) {
+    return identity;
+  }
+
+  var headList = head(list);
+  var tailList = tail(list);
+
+  return _arity(headList.length, function () {
+    return _reduce(function (result, f) {
+      return xf.call(this, f, result);
+    }, headList.apply(this, arguments), tailList);
+  });
+});
+module.exports = pipeWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/pluck.js b/server/node_modules/ramda/src/pluck.js
new file mode 100644
index 0000000000000000000000000000000000000000..c52ae9b9df27818e4763f47ec0cd18af854a7dcb
--- /dev/null
+++ b/server/node_modules/ramda/src/pluck.js
@@ -0,0 +1,39 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var map = /*#__PURE__*/require('./map');
+
+var prop = /*#__PURE__*/require('./prop');
+
+/**
+ * Returns a new list by plucking the same named property off all objects in
+ * the list supplied.
+ *
+ * `pluck` will work on
+ * any [functor](https://github.com/fantasyland/fantasy-land#functor) in
+ * addition to arrays, as it is equivalent to `R.map(R.prop(k), f)`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Functor f => k -> f {k: v} -> f v
+ * @param {Number|String} key The key name to pluck off of each object.
+ * @param {Array} f The array or functor to consider.
+ * @return {Array} The list of values for the given key.
+ * @see R.props
+ * @example
+ *
+ *      var getAges = R.pluck('age');
+ *      getAges([{name: 'fred', age: 29}, {name: 'wilma', age: 27}]); //=> [29, 27]
+ *
+ *      R.pluck(0, [[1, 2], [3, 4]]);               //=> [1, 3]
+ *      R.pluck('val', {a: {val: 3}, b: {val: 5}}); //=> {a: 3, b: 5}
+ * @symb R.pluck('x', [{x: 1, y: 2}, {x: 3, y: 4}, {x: 5, y: 6}]) = [1, 3, 5]
+ * @symb R.pluck(0, [[1, 2], [3, 4], [5, 6]]) = [1, 3, 5]
+ */
+
+
+var pluck = /*#__PURE__*/_curry2(function pluck(p, list) {
+  return map(prop(p), list);
+});
+module.exports = pluck;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/prepend.js b/server/node_modules/ramda/src/prepend.js
new file mode 100644
index 0000000000000000000000000000000000000000..2742c22c3e0886dbdf80840c77c5541bd4764a23
--- /dev/null
+++ b/server/node_modules/ramda/src/prepend.js
@@ -0,0 +1,27 @@
+var _concat = /*#__PURE__*/require('./internal/_concat');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns a new list with the given element at the front, followed by the
+ * contents of the list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig a -> [a] -> [a]
+ * @param {*} el The item to add to the head of the output list.
+ * @param {Array} list The array to add to the tail of the output list.
+ * @return {Array} A new array.
+ * @see R.append
+ * @example
+ *
+ *      R.prepend('fee', ['fi', 'fo', 'fum']); //=> ['fee', 'fi', 'fo', 'fum']
+ */
+
+
+var prepend = /*#__PURE__*/_curry2(function prepend(el, list) {
+  return _concat([el], list);
+});
+module.exports = prepend;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/product.js b/server/node_modules/ramda/src/product.js
new file mode 100644
index 0000000000000000000000000000000000000000..5e1d07e1c8dc6b076d3fcbb4995b8b79925b2372
--- /dev/null
+++ b/server/node_modules/ramda/src/product.js
@@ -0,0 +1,23 @@
+var multiply = /*#__PURE__*/require('./multiply');
+
+var reduce = /*#__PURE__*/require('./reduce');
+
+/**
+ * Multiplies together all the elements of a list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list An array of numbers
+ * @return {Number} The product of all the numbers in the list.
+ * @see R.reduce
+ * @example
+ *
+ *      R.product([2,4,6,8,100,1]); //=> 38400
+ */
+
+
+var product = /*#__PURE__*/reduce(multiply, 1);
+module.exports = product;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/project.js b/server/node_modules/ramda/src/project.js
new file mode 100644
index 0000000000000000000000000000000000000000..58d9ccbf63d01093cc7f56a19b2102ed1004f504
--- /dev/null
+++ b/server/node_modules/ramda/src/project.js
@@ -0,0 +1,31 @@
+var _map = /*#__PURE__*/require('./internal/_map');
+
+var identity = /*#__PURE__*/require('./identity');
+
+var pickAll = /*#__PURE__*/require('./pickAll');
+
+var useWith = /*#__PURE__*/require('./useWith');
+
+/**
+ * Reasonable analog to SQL `select` statement.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @category Relation
+ * @sig [k] -> [{k: v}] -> [{k: v}]
+ * @param {Array} props The property names to project
+ * @param {Array} objs The objects to query
+ * @return {Array} An array of objects with just the `props` properties.
+ * @example
+ *
+ *      const abby = {name: 'Abby', age: 7, hair: 'blond', grade: 2};
+ *      const fred = {name: 'Fred', age: 12, hair: 'brown', grade: 7};
+ *      const kids = [abby, fred];
+ *      R.project(['name', 'grade'], kids); //=> [{name: 'Abby', grade: 2}, {name: 'Fred', grade: 7}]
+ */
+
+
+var project = /*#__PURE__*/useWith(_map, [pickAll, identity]); // passing `identity` gives correct arity
+module.exports = project;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/prop.js b/server/node_modules/ramda/src/prop.js
new file mode 100644
index 0000000000000000000000000000000000000000..bbf02c16b441dc764d8838184155446087fffc09
--- /dev/null
+++ b/server/node_modules/ramda/src/prop.js
@@ -0,0 +1,28 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var path = /*#__PURE__*/require('./path');
+
+/**
+ * Returns a function that when supplied an object returns the indicated
+ * property of that object, if it exists.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig s -> {s: a} -> a | Undefined
+ * @param {String} p The property name
+ * @param {Object} obj The object to query
+ * @return {*} The value at `obj.p`.
+ * @see R.path
+ * @example
+ *
+ *      R.prop('x', {x: 100}); //=> 100
+ *      R.prop('x', {}); //=> undefined
+ *      R.compose(R.inc, R.prop('x'))({ x: 3 }) //=> 4
+ */
+
+var prop = /*#__PURE__*/_curry2(function prop(p, obj) {
+  return path([p], obj);
+});
+module.exports = prop;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/propEq.js b/server/node_modules/ramda/src/propEq.js
new file mode 100644
index 0000000000000000000000000000000000000000..c0214b912730aefe90384b1e8321204ec423402e
--- /dev/null
+++ b/server/node_modules/ramda/src/propEq.js
@@ -0,0 +1,35 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var equals = /*#__PURE__*/require('./equals');
+
+/**
+ * Returns `true` if the specified object property is equal, in
+ * [`R.equals`](#equals) terms, to the given value; `false` otherwise.
+ * You can test multiple properties with [`R.whereEq`](#whereEq).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig String -> a -> Object -> Boolean
+ * @param {String} name
+ * @param {*} val
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.whereEq, R.propSatisfies, R.equals
+ * @example
+ *
+ *      const abby = {name: 'Abby', age: 7, hair: 'blond'};
+ *      const fred = {name: 'Fred', age: 12, hair: 'brown'};
+ *      const rusty = {name: 'Rusty', age: 10, hair: 'brown'};
+ *      const alois = {name: 'Alois', age: 15, disposition: 'surly'};
+ *      const kids = [abby, fred, rusty, alois];
+ *      const hasBrownHair = R.propEq('hair', 'brown');
+ *      R.filter(hasBrownHair, kids); //=> [fred, rusty]
+ */
+
+
+var propEq = /*#__PURE__*/_curry3(function propEq(name, val, obj) {
+  return equals(val, obj[name]);
+});
+module.exports = propEq;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/propIs.js b/server/node_modules/ramda/src/propIs.js
new file mode 100644
index 0000000000000000000000000000000000000000..c8b730e88d882981aa22ce960300ebb7dd2fbe84
--- /dev/null
+++ b/server/node_modules/ramda/src/propIs.js
@@ -0,0 +1,30 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var is = /*#__PURE__*/require('./is');
+
+/**
+ * Returns `true` if the specified object property is of the given type;
+ * `false` otherwise.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Type
+ * @sig Type -> String -> Object -> Boolean
+ * @param {Function} type
+ * @param {String} name
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.is, R.propSatisfies
+ * @example
+ *
+ *      R.propIs(Number, 'x', {x: 1, y: 2});  //=> true
+ *      R.propIs(Number, 'x', {x: 'foo'});    //=> false
+ *      R.propIs(Number, 'x', {});            //=> false
+ */
+
+
+var propIs = /*#__PURE__*/_curry3(function propIs(type, name, obj) {
+  return is(type, obj[name]);
+});
+module.exports = propIs;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/propOr.js b/server/node_modules/ramda/src/propOr.js
new file mode 100644
index 0000000000000000000000000000000000000000..26b6d04833d5b29b4ec0c817eba0ec62af3b8767
--- /dev/null
+++ b/server/node_modules/ramda/src/propOr.js
@@ -0,0 +1,36 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var pathOr = /*#__PURE__*/require('./pathOr');
+
+/**
+ * If the given, non-null object has an own property with the specified name,
+ * returns the value of that property. Otherwise returns the provided default
+ * value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category Object
+ * @sig a -> String -> Object -> a
+ * @param {*} val The default value.
+ * @param {String} p The name of the property to return.
+ * @param {Object} obj The object to query.
+ * @return {*} The value of given property of the supplied object or the default value.
+ * @example
+ *
+ *      const alice = {
+ *        name: 'ALICE',
+ *        age: 101
+ *      };
+ *      const favorite = R.prop('favoriteLibrary');
+ *      const favoriteWithDefault = R.propOr('Ramda', 'favoriteLibrary');
+ *
+ *      favorite(alice);  //=> undefined
+ *      favoriteWithDefault(alice);  //=> 'Ramda'
+ */
+
+
+var propOr = /*#__PURE__*/_curry3(function propOr(val, p, obj) {
+  return pathOr(val, [p], obj);
+});
+module.exports = propOr;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/propSatisfies.js b/server/node_modules/ramda/src/propSatisfies.js
new file mode 100644
index 0000000000000000000000000000000000000000..7afc7a3f3435222d4fb12629d5d91002c265642e
--- /dev/null
+++ b/server/node_modules/ramda/src/propSatisfies.js
@@ -0,0 +1,27 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Returns `true` if the specified object property satisfies the given
+ * predicate; `false` otherwise. You can test multiple properties with
+ * [`R.where`](#where).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Logic
+ * @sig (a -> Boolean) -> String -> {String: a} -> Boolean
+ * @param {Function} pred
+ * @param {String} name
+ * @param {*} obj
+ * @return {Boolean}
+ * @see R.where, R.propEq, R.propIs
+ * @example
+ *
+ *      R.propSatisfies(x => x > 0, 'x', {x: 1, y: 2}); //=> true
+ */
+
+
+var propSatisfies = /*#__PURE__*/_curry3(function propSatisfies(pred, name, obj) {
+  return pred(obj[name]);
+});
+module.exports = propSatisfies;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/props.js b/server/node_modules/ramda/src/props.js
new file mode 100644
index 0000000000000000000000000000000000000000..911b325fd54aa28fd7ef01c5c2ed07704fa7e37d
--- /dev/null
+++ b/server/node_modules/ramda/src/props.js
@@ -0,0 +1,37 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Acts as multiple `prop`: array of keys in, array of values out. Preserves
+ * order.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig [k] -> {k: v} -> [v]
+ * @param {Array} ps The property names to fetch
+ * @param {Object} obj The object to query
+ * @return {Array} The corresponding values or partially applied function.
+ * @example
+ *
+ *      R.props(['x', 'y'], {x: 1, y: 2}); //=> [1, 2]
+ *      R.props(['c', 'a', 'b'], {b: 2, a: 1}); //=> [undefined, 1, 2]
+ *
+ *      const fullName = R.compose(R.join(' '), R.props(['first', 'last']));
+ *      fullName({last: 'Bullet-Tooth', age: 33, first: 'Tony'}); //=> 'Tony Bullet-Tooth'
+ */
+
+
+var props = /*#__PURE__*/_curry2(function props(ps, obj) {
+  var len = ps.length;
+  var out = [];
+  var idx = 0;
+
+  while (idx < len) {
+    out[idx] = obj[ps[idx]];
+    idx += 1;
+  }
+
+  return out;
+});
+module.exports = props;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/range.js b/server/node_modules/ramda/src/range.js
new file mode 100644
index 0000000000000000000000000000000000000000..f551823322642ab4f9f5fcb211a8dbf551d497d9
--- /dev/null
+++ b/server/node_modules/ramda/src/range.js
@@ -0,0 +1,35 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _isNumber = /*#__PURE__*/require('./internal/_isNumber');
+
+/**
+ * Returns a list of numbers from `from` (inclusive) to `to` (exclusive).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> Number -> [Number]
+ * @param {Number} from The first number in the list.
+ * @param {Number} to One more than the last number in the list.
+ * @return {Array} The list of numbers in the set `[a, b)`.
+ * @example
+ *
+ *      R.range(1, 5);    //=> [1, 2, 3, 4]
+ *      R.range(50, 53);  //=> [50, 51, 52]
+ */
+
+
+var range = /*#__PURE__*/_curry2(function range(from, to) {
+  if (!(_isNumber(from) && _isNumber(to))) {
+    throw new TypeError('Both arguments to range must be numbers');
+  }
+  var result = [];
+  var n = from;
+  while (n < to) {
+    result.push(n);
+    n += 1;
+  }
+  return result;
+});
+module.exports = range;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/reduce.js b/server/node_modules/ramda/src/reduce.js
new file mode 100644
index 0000000000000000000000000000000000000000..7ebdeec235cfd34e54b57818f12bf357c5202ddf
--- /dev/null
+++ b/server/node_modules/ramda/src/reduce.js
@@ -0,0 +1,54 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var _reduce = /*#__PURE__*/require('./internal/_reduce');
+
+/**
+ * Returns a single item by iterating through the list, successively calling
+ * the iterator function and passing it an accumulator value and the current
+ * value from the array, and then passing the result to the next call.
+ *
+ * The iterator function receives two values: *(acc, value)*. It may use
+ * [`R.reduced`](#reduced) to shortcut the iteration.
+ *
+ * The arguments' order of [`reduceRight`](#reduceRight)'s iterator function
+ * is *(value, acc)*.
+ *
+ * Note: `R.reduce` does not skip deleted or unassigned indices (sparse
+ * arrays), unlike the native `Array.prototype.reduce` method. For more details
+ * on this behavior, see:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#Description
+ *
+ * Dispatches to the `reduce` method of the third argument, if present. When
+ * doing so, it is up to the user to handle the [`R.reduced`](#reduced)
+ * shortcuting, as this is not implemented by `reduce`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, b) -> a) -> a -> [b] -> a
+ * @param {Function} fn The iterator function. Receives two values, the accumulator and the
+ *        current element from the array.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduced, R.addIndex, R.reduceRight
+ * @example
+ *
+ *      R.reduce(R.subtract, 0, [1, 2, 3, 4]) // => ((((0 - 1) - 2) - 3) - 4) = -10
+ *      //          -               -10
+ *      //         / \              / \
+ *      //        -   4           -6   4
+ *      //       / \              / \
+ *      //      -   3   ==>     -3   3
+ *      //     / \              / \
+ *      //    -   2           -1   2
+ *      //   / \              / \
+ *      //  0   1            0   1
+ *
+ * @symb R.reduce(f, a, [b, c, d]) = f(f(f(a, b), c), d)
+ */
+
+
+var reduce = /*#__PURE__*/_curry3(_reduce);
+module.exports = reduce;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/reduceBy.js b/server/node_modules/ramda/src/reduceBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..81898bfd4a16d7308e4abbef8328a6ee990aad09
--- /dev/null
+++ b/server/node_modules/ramda/src/reduceBy.js
@@ -0,0 +1,61 @@
+var _curryN = /*#__PURE__*/require('./internal/_curryN');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _has = /*#__PURE__*/require('./internal/_has');
+
+var _reduce = /*#__PURE__*/require('./internal/_reduce');
+
+var _xreduceBy = /*#__PURE__*/require('./internal/_xreduceBy');
+
+/**
+ * Groups the elements of the list according to the result of calling
+ * the String-returning function `keyFn` on each element and reduces the elements
+ * of each group to a single value via the reducer function `valueFn`.
+ *
+ * This function is basically a more general [`groupBy`](#groupBy) function.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category List
+ * @sig ((a, b) -> a) -> a -> (b -> String) -> [b] -> {String: a}
+ * @param {Function} valueFn The function that reduces the elements of each group to a single
+ *        value. Receives two values, accumulator for a particular group and the current element.
+ * @param {*} acc The (initial) accumulator value for each group.
+ * @param {Function} keyFn The function that maps the list's element into a key.
+ * @param {Array} list The array to group.
+ * @return {Object} An object with the output of `keyFn` for keys, mapped to the output of
+ *         `valueFn` for elements which produced that key when passed to `keyFn`.
+ * @see R.groupBy, R.reduce
+ * @example
+ *
+ *      const groupNames = (acc, {name}) => acc.concat(name)
+ *      const toGrade = ({score}) =>
+ *        score < 65 ? 'F' :
+ *        score < 70 ? 'D' :
+ *        score < 80 ? 'C' :
+ *        score < 90 ? 'B' : 'A'
+ *
+ *      var students = [
+ *        {name: 'Abby', score: 83},
+ *        {name: 'Bart', score: 62},
+ *        {name: 'Curt', score: 88},
+ *        {name: 'Dora', score: 92},
+ *      ]
+ *
+ *      reduceBy(groupNames, [], toGrade, students)
+ *      //=> {"A": ["Dora"], "B": ["Abby", "Curt"], "F": ["Bart"]}
+ */
+
+
+var reduceBy = /*#__PURE__*/_curryN(4, [], /*#__PURE__*/_dispatchable([], _xreduceBy, function reduceBy(valueFn, valueAcc, keyFn, list) {
+  return _reduce(function (acc, elt) {
+    var key = keyFn(elt);
+    acc[key] = valueFn(_has(key, acc) ? acc[key] : valueAcc, elt);
+    return acc;
+  }, {}, list);
+}));
+module.exports = reduceBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/reduceRight.js b/server/node_modules/ramda/src/reduceRight.js
new file mode 100644
index 0000000000000000000000000000000000000000..0c4419696763553a0b16a4ce3dcf255489e0b280
--- /dev/null
+++ b/server/node_modules/ramda/src/reduceRight.js
@@ -0,0 +1,55 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Returns a single item by iterating through the list, successively calling
+ * the iterator function and passing it an accumulator value and the current
+ * value from the array, and then passing the result to the next call.
+ *
+ * Similar to [`reduce`](#reduce), except moves through the input list from the
+ * right to the left.
+ *
+ * The iterator function receives two values: *(value, acc)*, while the arguments'
+ * order of `reduce`'s iterator function is *(acc, value)*.
+ *
+ * Note: `R.reduceRight` does not skip deleted or unassigned indices (sparse
+ * arrays), unlike the native `Array.prototype.reduceRight` method. For more details
+ * on this behavior, see:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight#Description
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, b) -> b) -> b -> [a] -> b
+ * @param {Function} fn The iterator function. Receives two values, the current element from the array
+ *        and the accumulator.
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduce, R.addIndex
+ * @example
+ *
+ *      R.reduceRight(R.subtract, 0, [1, 2, 3, 4]) // => (1 - (2 - (3 - (4 - 0)))) = -2
+ *      //    -               -2
+ *      //   / \              / \
+ *      //  1   -            1   3
+ *      //     / \              / \
+ *      //    2   -     ==>    2  -1
+ *      //       / \              / \
+ *      //      3   -            3   4
+ *      //         / \              / \
+ *      //        4   0            4   0
+ *
+ * @symb R.reduceRight(f, a, [b, c, d]) = f(b, f(c, f(d, a)))
+ */
+
+
+var reduceRight = /*#__PURE__*/_curry3(function reduceRight(fn, acc, list) {
+  var idx = list.length - 1;
+  while (idx >= 0) {
+    acc = fn(list[idx], acc);
+    idx -= 1;
+  }
+  return acc;
+});
+module.exports = reduceRight;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/reduceWhile.js b/server/node_modules/ramda/src/reduceWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..7a01a34540985c8f990f326ac8ebe7c4ec55b088
--- /dev/null
+++ b/server/node_modules/ramda/src/reduceWhile.js
@@ -0,0 +1,43 @@
+var _curryN = /*#__PURE__*/require('./internal/_curryN');
+
+var _reduce = /*#__PURE__*/require('./internal/_reduce');
+
+var _reduced = /*#__PURE__*/require('./internal/_reduced');
+
+/**
+ * Like [`reduce`](#reduce), `reduceWhile` returns a single item by iterating
+ * through the list, successively calling the iterator function. `reduceWhile`
+ * also takes a predicate that is evaluated before each step. If the predicate
+ * returns `false`, it "short-circuits" the iteration and returns the current
+ * value of the accumulator.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.22.0
+ * @category List
+ * @sig ((a, b) -> Boolean) -> ((a, b) -> a) -> a -> [b] -> a
+ * @param {Function} pred The predicate. It is passed the accumulator and the
+ *        current element.
+ * @param {Function} fn The iterator function. Receives two values, the
+ *        accumulator and the current element.
+ * @param {*} a The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduce, R.reduced
+ * @example
+ *
+ *      const isOdd = (acc, x) => x % 2 === 1;
+ *      const xs = [1, 3, 5, 60, 777, 800];
+ *      R.reduceWhile(isOdd, R.add, 0, xs); //=> 9
+ *
+ *      const ys = [2, 4, 6]
+ *      R.reduceWhile(isOdd, R.add, 111, ys); //=> 111
+ */
+
+
+var reduceWhile = /*#__PURE__*/_curryN(4, [], function _reduceWhile(pred, fn, a, list) {
+  return _reduce(function (acc, x) {
+    return pred(acc, x) ? fn(acc, x) : _reduced(acc);
+  }, a, list);
+});
+module.exports = reduceWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/reduced.js b/server/node_modules/ramda/src/reduced.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ccb5ef1d36f5db9daf392a075cb7f09d4141d29
--- /dev/null
+++ b/server/node_modules/ramda/src/reduced.js
@@ -0,0 +1,33 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _reduced = /*#__PURE__*/require('./internal/_reduced');
+
+/**
+ * Returns a value wrapped to indicate that it is the final value of the reduce
+ * and transduce functions. The returned value should be considered a black
+ * box: the internal structure is not guaranteed to be stable.
+ *
+ * Note: this optimization is only available to the below functions:
+ * - [`reduce`](#reduce)
+ * - [`reduceWhile`](#reduceWhile)
+ * - [`transduce`](#transduce)
+ *
+ * @func
+ * @memberOf R
+ * @since v0.15.0
+ * @category List
+ * @sig a -> *
+ * @param {*} x The final value of the reduce.
+ * @return {*} The wrapped value.
+ * @see R.reduce, R.reduceWhile, R.transduce
+ * @example
+ *
+ *     R.reduce(
+ *       (acc, item) => item > 3 ? R.reduced(acc) : acc.concat(item),
+ *       [],
+ *       [1, 2, 3, 4, 5]) // [1, 2, 3]
+ */
+
+
+var reduced = /*#__PURE__*/_curry1(_reduced);
+module.exports = reduced;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/reject.js b/server/node_modules/ramda/src/reject.js
new file mode 100644
index 0000000000000000000000000000000000000000..a690d4edcce3fe658493f8a53c5b89af03903845
--- /dev/null
+++ b/server/node_modules/ramda/src/reject.js
@@ -0,0 +1,36 @@
+var _complement = /*#__PURE__*/require('./internal/_complement');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var filter = /*#__PURE__*/require('./filter');
+
+/**
+ * The complement of [`filter`](#filter).
+ *
+ * Acts as a transducer if a transformer is given in list position. Filterable
+ * objects include plain objects or any object that has a filter method such
+ * as `Array`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Filterable f => (a -> Boolean) -> f a -> f a
+ * @param {Function} pred
+ * @param {Array} filterable
+ * @return {Array}
+ * @see R.filter, R.transduce, R.addIndex
+ * @example
+ *
+ *      const isOdd = (n) => n % 2 === 1;
+ *
+ *      R.reject(isOdd, [1, 2, 3, 4]); //=> [2, 4]
+ *
+ *      R.reject(isOdd, {a: 1, b: 2, c: 3, d: 4}); //=> {b: 2, d: 4}
+ */
+
+
+var reject = /*#__PURE__*/_curry2(function reject(pred, filterable) {
+  return filter(_complement(pred), filterable);
+});
+module.exports = reject;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/remove.js b/server/node_modules/ramda/src/remove.js
new file mode 100644
index 0000000000000000000000000000000000000000..3794414855ce57d77cf39b5d0d46b425aa83139f
--- /dev/null
+++ b/server/node_modules/ramda/src/remove.js
@@ -0,0 +1,30 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Removes the sub-list of `list` starting at index `start` and containing
+ * `count` elements. _Note that this is not destructive_: it returns a copy of
+ * the list with the changes.
+ * <small>No lists have been harmed in the application of this function.</small>
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.2
+ * @category List
+ * @sig Number -> Number -> [a] -> [a]
+ * @param {Number} start The position to start removing elements
+ * @param {Number} count The number of elements to remove
+ * @param {Array} list The list to remove from
+ * @return {Array} A new Array with `count` elements from `start` removed.
+ * @see R.without
+ * @example
+ *
+ *      R.remove(2, 3, [1,2,3,4,5,6,7,8]); //=> [1,2,6,7,8]
+ */
+
+
+var remove = /*#__PURE__*/_curry3(function remove(start, count, list) {
+  var result = Array.prototype.slice.call(list, 0);
+  result.splice(start, count);
+  return result;
+});
+module.exports = remove;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/repeat.js b/server/node_modules/ramda/src/repeat.js
new file mode 100644
index 0000000000000000000000000000000000000000..9eae4a2b6c0f9e4f9336c2e4637948048349f1a6
--- /dev/null
+++ b/server/node_modules/ramda/src/repeat.js
@@ -0,0 +1,35 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var always = /*#__PURE__*/require('./always');
+
+var times = /*#__PURE__*/require('./times');
+
+/**
+ * Returns a fixed list of size `n` containing a specified identical value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category List
+ * @sig a -> n -> [a]
+ * @param {*} value The value to repeat.
+ * @param {Number} n The desired size of the output list.
+ * @return {Array} A new array containing `n` `value`s.
+ * @see R.times
+ * @example
+ *
+ *      R.repeat('hi', 5); //=> ['hi', 'hi', 'hi', 'hi', 'hi']
+ *
+ *      const obj = {};
+ *      const repeatedObjs = R.repeat(obj, 5); //=> [{}, {}, {}, {}, {}]
+ *      repeatedObjs[0] === repeatedObjs[1]; //=> true
+ * @symb R.repeat(a, 0) = []
+ * @symb R.repeat(a, 1) = [a]
+ * @symb R.repeat(a, 2) = [a, a]
+ */
+
+
+var repeat = /*#__PURE__*/_curry2(function repeat(value, n) {
+  return times(always(value), n);
+});
+module.exports = repeat;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/replace.js b/server/node_modules/ramda/src/replace.js
new file mode 100644
index 0000000000000000000000000000000000000000..3b15075f0078ec1893b396b04be24dbe16894789
--- /dev/null
+++ b/server/node_modules/ramda/src/replace.js
@@ -0,0 +1,32 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Replace a substring or regex match in a string with a replacement.
+ *
+ * The first two parameters correspond to the parameters of the
+ * `String.prototype.replace()` function, so the second parameter can also be a
+ * function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.7.0
+ * @category String
+ * @sig RegExp|String -> String -> String -> String
+ * @param {RegExp|String} pattern A regular expression or a substring to match.
+ * @param {String} replacement The string to replace the matches with.
+ * @param {String} str The String to do the search and replacement in.
+ * @return {String} The result.
+ * @example
+ *
+ *      R.replace('foo', 'bar', 'foo foo foo'); //=> 'bar foo foo'
+ *      R.replace(/foo/, 'bar', 'foo foo foo'); //=> 'bar foo foo'
+ *
+ *      // Use the "g" (global) flag to replace all occurrences:
+ *      R.replace(/foo/g, 'bar', 'foo foo foo'); //=> 'bar bar bar'
+ */
+
+
+var replace = /*#__PURE__*/_curry3(function replace(regex, replacement, str) {
+  return str.replace(regex, replacement);
+});
+module.exports = replace;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/reverse.js b/server/node_modules/ramda/src/reverse.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6c3e4f14da9045d9f2fc9f90c12daacd99e8848
--- /dev/null
+++ b/server/node_modules/ramda/src/reverse.js
@@ -0,0 +1,34 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _isString = /*#__PURE__*/require('./internal/_isString');
+
+/**
+ * Returns a new list or string with the elements or characters in reverse
+ * order.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a]
+ * @sig String -> String
+ * @param {Array|String} list
+ * @return {Array|String}
+ * @example
+ *
+ *      R.reverse([1, 2, 3]);  //=> [3, 2, 1]
+ *      R.reverse([1, 2]);     //=> [2, 1]
+ *      R.reverse([1]);        //=> [1]
+ *      R.reverse([]);         //=> []
+ *
+ *      R.reverse('abc');      //=> 'cba'
+ *      R.reverse('ab');       //=> 'ba'
+ *      R.reverse('a');        //=> 'a'
+ *      R.reverse('');         //=> ''
+ */
+
+
+var reverse = /*#__PURE__*/_curry1(function reverse(list) {
+  return _isString(list) ? list.split('').reverse().join('') : Array.prototype.slice.call(list, 0).reverse();
+});
+module.exports = reverse;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/scan.js b/server/node_modules/ramda/src/scan.js
new file mode 100644
index 0000000000000000000000000000000000000000..707612144975a436f255e53932779236b4db1305
--- /dev/null
+++ b/server/node_modules/ramda/src/scan.js
@@ -0,0 +1,37 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Scan is similar to [`reduce`](#reduce), but returns a list of successively
+ * reduced values from the left
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig ((a, b) -> a) -> a -> [b] -> [a]
+ * @param {Function} fn The iterator function. Receives two values, the accumulator and the
+ *        current element from the array
+ * @param {*} acc The accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {Array} A list of all intermediately reduced values.
+ * @see R.reduce, R.mapAccum
+ * @example
+ *
+ *      const numbers = [1, 2, 3, 4];
+ *      const factorials = R.scan(R.multiply, 1, numbers); //=> [1, 1, 2, 6, 24]
+ * @symb R.scan(f, a, [b, c]) = [a, f(a, b), f(f(a, b), c)]
+ */
+
+
+var scan = /*#__PURE__*/_curry3(function scan(fn, acc, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [acc];
+  while (idx < len) {
+    acc = fn(acc, list[idx]);
+    result[idx + 1] = acc;
+    idx += 1;
+  }
+  return result;
+});
+module.exports = scan;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/sequence.js b/server/node_modules/ramda/src/sequence.js
new file mode 100644
index 0000000000000000000000000000000000000000..8a09b8f2176e85fce3f7f674803653baf53effa0
--- /dev/null
+++ b/server/node_modules/ramda/src/sequence.js
@@ -0,0 +1,42 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var ap = /*#__PURE__*/require('./ap');
+
+var map = /*#__PURE__*/require('./map');
+
+var prepend = /*#__PURE__*/require('./prepend');
+
+var reduceRight = /*#__PURE__*/require('./reduceRight');
+
+/**
+ * Transforms a [Traversable](https://github.com/fantasyland/fantasy-land#traversable)
+ * of [Applicative](https://github.com/fantasyland/fantasy-land#applicative) into an
+ * Applicative of Traversable.
+ *
+ * Dispatches to the `sequence` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (Applicative f, Traversable t) => (a -> f a) -> t (f a) -> f (t a)
+ * @param {Function} of
+ * @param {*} traversable
+ * @return {*}
+ * @see R.traverse
+ * @example
+ *
+ *      R.sequence(Maybe.of, [Just(1), Just(2), Just(3)]);   //=> Just([1, 2, 3])
+ *      R.sequence(Maybe.of, [Just(1), Just(2), Nothing()]); //=> Nothing()
+ *
+ *      R.sequence(R.of, Just([1, 2, 3])); //=> [Just(1), Just(2), Just(3)]
+ *      R.sequence(R.of, Nothing());       //=> [Nothing()]
+ */
+
+
+var sequence = /*#__PURE__*/_curry2(function sequence(of, traversable) {
+  return typeof traversable.sequence === 'function' ? traversable.sequence(of) : reduceRight(function (x, acc) {
+    return ap(map(prepend, x), acc);
+  }, of([]), traversable);
+});
+module.exports = sequence;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/set.js b/server/node_modules/ramda/src/set.js
new file mode 100644
index 0000000000000000000000000000000000000000..c7293735cc6527c67a18eb20a8b68b55662f3098
--- /dev/null
+++ b/server/node_modules/ramda/src/set.js
@@ -0,0 +1,34 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var always = /*#__PURE__*/require('./always');
+
+var over = /*#__PURE__*/require('./over');
+
+/**
+ * Returns the result of "setting" the portion of the given data structure
+ * focused by the given lens to the given value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Lens s a -> a -> s -> s
+ * @param {Lens} lens
+ * @param {*} v
+ * @param {*} x
+ * @return {*}
+ * @see R.prop, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const xLens = R.lensProp('x');
+ *
+ *      R.set(xLens, 4, {x: 1, y: 2});  //=> {x: 4, y: 2}
+ *      R.set(xLens, 8, {x: 1, y: 2});  //=> {x: 8, y: 2}
+ */
+
+
+var set = /*#__PURE__*/_curry3(function set(lens, v, x) {
+  return over(lens, always(v), x);
+});
+module.exports = set;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/slice.js b/server/node_modules/ramda/src/slice.js
new file mode 100644
index 0000000000000000000000000000000000000000..c84622813e1fdba4aec28aa0474846700785dfe2
--- /dev/null
+++ b/server/node_modules/ramda/src/slice.js
@@ -0,0 +1,34 @@
+var _checkForMethod = /*#__PURE__*/require('./internal/_checkForMethod');
+
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Returns the elements of the given list or string (or object with a `slice`
+ * method) from `fromIndex` (inclusive) to `toIndex` (exclusive).
+ *
+ * Dispatches to the `slice` method of the third argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.4
+ * @category List
+ * @sig Number -> Number -> [a] -> [a]
+ * @sig Number -> Number -> String -> String
+ * @param {Number} fromIndex The start index (inclusive).
+ * @param {Number} toIndex The end index (exclusive).
+ * @param {*} list
+ * @return {*}
+ * @example
+ *
+ *      R.slice(1, 3, ['a', 'b', 'c', 'd']);        //=> ['b', 'c']
+ *      R.slice(1, Infinity, ['a', 'b', 'c', 'd']); //=> ['b', 'c', 'd']
+ *      R.slice(0, -1, ['a', 'b', 'c', 'd']);       //=> ['a', 'b', 'c']
+ *      R.slice(-3, -1, ['a', 'b', 'c', 'd']);      //=> ['b', 'c']
+ *      R.slice(0, 3, 'ramda');                     //=> 'ram'
+ */
+
+
+var slice = /*#__PURE__*/_curry3( /*#__PURE__*/_checkForMethod('slice', function slice(fromIndex, toIndex, list) {
+  return Array.prototype.slice.call(list, fromIndex, toIndex);
+}));
+module.exports = slice;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/sort.js b/server/node_modules/ramda/src/sort.js
new file mode 100644
index 0000000000000000000000000000000000000000..e4365f7e8949b5754fe5d9d07263a239dffa5714
--- /dev/null
+++ b/server/node_modules/ramda/src/sort.js
@@ -0,0 +1,28 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns a copy of the list, sorted according to the comparator function,
+ * which should accept two values at a time and return a negative number if the
+ * first value is smaller, a positive number if it's larger, and zero if they
+ * are equal. Please note that this is a **copy** of the list. It does not
+ * modify the original.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, a) -> Number) -> [a] -> [a]
+ * @param {Function} comparator A sorting function :: a -> b -> Int
+ * @param {Array} list The list to sort
+ * @return {Array} a new array with its elements sorted by the comparator function.
+ * @example
+ *
+ *      const diff = function(a, b) { return a - b; };
+ *      R.sort(diff, [4,2,7,5]); //=> [2, 4, 5, 7]
+ */
+
+
+var sort = /*#__PURE__*/_curry2(function sort(comparator, list) {
+  return Array.prototype.slice.call(list, 0).sort(comparator);
+});
+module.exports = sort;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/sortBy.js b/server/node_modules/ramda/src/sortBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..3ee1eefd6536fe6993581570ef75a3c187b74b45
--- /dev/null
+++ b/server/node_modules/ramda/src/sortBy.js
@@ -0,0 +1,45 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Sorts the list according to the supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig Ord b => (a -> b) -> [a] -> [a]
+ * @param {Function} fn
+ * @param {Array} list The list to sort.
+ * @return {Array} A new list sorted by the keys generated by `fn`.
+ * @example
+ *
+ *      const sortByFirstItem = R.sortBy(R.prop(0));
+ *      const pairs = [[-1, 1], [-2, 2], [-3, 3]];
+ *      sortByFirstItem(pairs); //=> [[-3, 3], [-2, 2], [-1, 1]]
+ *
+ *      const sortByNameCaseInsensitive = R.sortBy(R.compose(R.toLower, R.prop('name')));
+ *      const alice = {
+ *        name: 'ALICE',
+ *        age: 101
+ *      };
+ *      const bob = {
+ *        name: 'Bob',
+ *        age: -10
+ *      };
+ *      const clara = {
+ *        name: 'clara',
+ *        age: 314.159
+ *      };
+ *      const people = [clara, bob, alice];
+ *      sortByNameCaseInsensitive(people); //=> [alice, bob, clara]
+ */
+
+
+var sortBy = /*#__PURE__*/_curry2(function sortBy(fn, list) {
+  return Array.prototype.slice.call(list, 0).sort(function (a, b) {
+    var aa = fn(a);
+    var bb = fn(b);
+    return aa < bb ? -1 : aa > bb ? 1 : 0;
+  });
+});
+module.exports = sortBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/sortWith.js b/server/node_modules/ramda/src/sortWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..bcc3ab79e3739eedcd6f49e31c3bf6beb12a0c46
--- /dev/null
+++ b/server/node_modules/ramda/src/sortWith.js
@@ -0,0 +1,48 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Sorts a list according to a list of comparators.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.23.0
+ * @category Relation
+ * @sig [(a, a) -> Number] -> [a] -> [a]
+ * @param {Array} functions A list of comparator functions.
+ * @param {Array} list The list to sort.
+ * @return {Array} A new list sorted according to the comarator functions.
+ * @example
+ *
+ *      const alice = {
+ *        name: 'alice',
+ *        age: 40
+ *      };
+ *      const bob = {
+ *        name: 'bob',
+ *        age: 30
+ *      };
+ *      const clara = {
+ *        name: 'clara',
+ *        age: 40
+ *      };
+ *      const people = [clara, bob, alice];
+ *      const ageNameSort = R.sortWith([
+ *        R.descend(R.prop('age')),
+ *        R.ascend(R.prop('name'))
+ *      ]);
+ *      ageNameSort(people); //=> [alice, clara, bob]
+ */
+
+
+var sortWith = /*#__PURE__*/_curry2(function sortWith(fns, list) {
+  return Array.prototype.slice.call(list, 0).sort(function (a, b) {
+    var result = 0;
+    var i = 0;
+    while (result === 0 && i < fns.length) {
+      result = fns[i](a, b);
+      i += 1;
+    }
+    return result;
+  });
+});
+module.exports = sortWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/split.js b/server/node_modules/ramda/src/split.js
new file mode 100644
index 0000000000000000000000000000000000000000..a5dedc7e999c132acd3a58d23032c5b8938019b0
--- /dev/null
+++ b/server/node_modules/ramda/src/split.js
@@ -0,0 +1,26 @@
+var invoker = /*#__PURE__*/require('./invoker');
+
+/**
+ * Splits a string into an array of strings based on the given
+ * separator.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category String
+ * @sig (String | RegExp) -> String -> [String]
+ * @param {String|RegExp} sep The pattern.
+ * @param {String} str The string to separate into an array.
+ * @return {Array} The array of strings from `str` separated by `str`.
+ * @see R.join
+ * @example
+ *
+ *      const pathComponents = R.split('/');
+ *      R.tail(pathComponents('/usr/local/bin/node')); //=> ['usr', 'local', 'bin', 'node']
+ *
+ *      R.split('.', 'a.b.c.xyz.d'); //=> ['a', 'b', 'c', 'xyz', 'd']
+ */
+
+
+var split = /*#__PURE__*/invoker(1, 'split');
+module.exports = split;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/splitAt.js b/server/node_modules/ramda/src/splitAt.js
new file mode 100644
index 0000000000000000000000000000000000000000..048b9ec0061e5325a2f468e1209ceb5f7bfe84b8
--- /dev/null
+++ b/server/node_modules/ramda/src/splitAt.js
@@ -0,0 +1,30 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var length = /*#__PURE__*/require('./length');
+
+var slice = /*#__PURE__*/require('./slice');
+
+/**
+ * Splits a given list or string at a given index.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig Number -> [a] -> [[a], [a]]
+ * @sig Number -> String -> [String, String]
+ * @param {Number} index The index where the array/string is split.
+ * @param {Array|String} array The array/string to be split.
+ * @return {Array}
+ * @example
+ *
+ *      R.splitAt(1, [1, 2, 3]);          //=> [[1], [2, 3]]
+ *      R.splitAt(5, 'hello world');      //=> ['hello', ' world']
+ *      R.splitAt(-1, 'foobar');          //=> ['fooba', 'r']
+ */
+
+
+var splitAt = /*#__PURE__*/_curry2(function splitAt(index, array) {
+  return [slice(0, index, array), slice(index, length(array), array)];
+});
+module.exports = splitAt;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/splitEvery.js b/server/node_modules/ramda/src/splitEvery.js
new file mode 100644
index 0000000000000000000000000000000000000000..48b87e455b4657b346ced768ba541a971743d5bf
--- /dev/null
+++ b/server/node_modules/ramda/src/splitEvery.js
@@ -0,0 +1,35 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var slice = /*#__PURE__*/require('./slice');
+
+/**
+ * Splits a collection into slices of the specified length.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig Number -> [a] -> [[a]]
+ * @sig Number -> String -> [String]
+ * @param {Number} n
+ * @param {Array} list
+ * @return {Array}
+ * @example
+ *
+ *      R.splitEvery(3, [1, 2, 3, 4, 5, 6, 7]); //=> [[1, 2, 3], [4, 5, 6], [7]]
+ *      R.splitEvery(3, 'foobarbaz'); //=> ['foo', 'bar', 'baz']
+ */
+
+
+var splitEvery = /*#__PURE__*/_curry2(function splitEvery(n, list) {
+  if (n <= 0) {
+    throw new Error('First argument to splitEvery must be a positive integer');
+  }
+  var result = [];
+  var idx = 0;
+  while (idx < list.length) {
+    result.push(slice(idx, idx += n, list));
+  }
+  return result;
+});
+module.exports = splitEvery;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/splitWhen.js b/server/node_modules/ramda/src/splitWhen.js
new file mode 100644
index 0000000000000000000000000000000000000000..29d9fdfff8f89d5e0e2600a6f8892168ff43a8e9
--- /dev/null
+++ b/server/node_modules/ramda/src/splitWhen.js
@@ -0,0 +1,36 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Takes a list and a predicate and returns a pair of lists with the following properties:
+ *
+ *  - the result of concatenating the two output lists is equivalent to the input list;
+ *  - none of the elements of the first output list satisfies the predicate; and
+ *  - if the second output list is non-empty, its first element satisfies the predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [[a], [a]]
+ * @param {Function} pred The predicate that determines where the array is split.
+ * @param {Array} list The array to be split.
+ * @return {Array}
+ * @example
+ *
+ *      R.splitWhen(R.equals(2), [1, 2, 3, 1, 2, 3]);   //=> [[1], [2, 3, 1, 2, 3]]
+ */
+
+
+var splitWhen = /*#__PURE__*/_curry2(function splitWhen(pred, list) {
+  var idx = 0;
+  var len = list.length;
+  var prefix = [];
+
+  while (idx < len && !pred(list[idx])) {
+    prefix.push(list[idx]);
+    idx += 1;
+  }
+
+  return [prefix, Array.prototype.slice.call(list, idx)];
+});
+module.exports = splitWhen;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/startsWith.js b/server/node_modules/ramda/src/startsWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..14a0e980e14f4dd912fe6aea9e1164157841fe41
--- /dev/null
+++ b/server/node_modules/ramda/src/startsWith.js
@@ -0,0 +1,34 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var equals = /*#__PURE__*/require('./equals');
+
+var take = /*#__PURE__*/require('./take');
+
+/**
+ * Checks if a list starts with the provided sublist.
+ *
+ * Similarly, checks if a string starts with the provided substring.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.24.0
+ * @category List
+ * @sig [a] -> [a] -> Boolean
+ * @sig String -> String -> Boolean
+ * @param {*} prefix
+ * @param {*} list
+ * @return {Boolean}
+ * @see R.endsWith
+ * @example
+ *
+ *      R.startsWith('a', 'abc')                //=> true
+ *      R.startsWith('b', 'abc')                //=> false
+ *      R.startsWith(['a'], ['a', 'b', 'c'])    //=> true
+ *      R.startsWith(['b'], ['a', 'b', 'c'])    //=> false
+ */
+
+
+var startsWith = /*#__PURE__*/_curry2(function (prefix, list) {
+  return equals(take(prefix.length, list), prefix);
+});
+module.exports = startsWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/subtract.js b/server/node_modules/ramda/src/subtract.js
new file mode 100644
index 0000000000000000000000000000000000000000..ec67050040c51c1cf9144daea3c3ef007c4421ea
--- /dev/null
+++ b/server/node_modules/ramda/src/subtract.js
@@ -0,0 +1,31 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Subtracts its second argument from its first argument.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig Number -> Number -> Number
+ * @param {Number} a The first value.
+ * @param {Number} b The second value.
+ * @return {Number} The result of `a - b`.
+ * @see R.add
+ * @example
+ *
+ *      R.subtract(10, 8); //=> 2
+ *
+ *      const minus5 = R.subtract(R.__, 5);
+ *      minus5(17); //=> 12
+ *
+ *      const complementaryAngle = R.subtract(90);
+ *      complementaryAngle(30); //=> 60
+ *      complementaryAngle(72); //=> 18
+ */
+
+
+var subtract = /*#__PURE__*/_curry2(function subtract(a, b) {
+  return Number(a) - Number(b);
+});
+module.exports = subtract;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/sum.js b/server/node_modules/ramda/src/sum.js
new file mode 100644
index 0000000000000000000000000000000000000000..71976d00e326dc926607ac4b7351c43e0cb1410e
--- /dev/null
+++ b/server/node_modules/ramda/src/sum.js
@@ -0,0 +1,23 @@
+var add = /*#__PURE__*/require('./add');
+
+var reduce = /*#__PURE__*/require('./reduce');
+
+/**
+ * Adds together all the elements of a list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Math
+ * @sig [Number] -> Number
+ * @param {Array} list An array of numbers
+ * @return {Number} The sum of all the numbers in the list.
+ * @see R.reduce
+ * @example
+ *
+ *      R.sum([2,4,6,8,100,1]); //=> 121
+ */
+
+
+var sum = /*#__PURE__*/reduce(add, 0);
+module.exports = sum;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/symmetricDifference.js b/server/node_modules/ramda/src/symmetricDifference.js
new file mode 100644
index 0000000000000000000000000000000000000000..46521bb5a46c380ff622dbc02660fefbbc857c0b
--- /dev/null
+++ b/server/node_modules/ramda/src/symmetricDifference.js
@@ -0,0 +1,30 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var concat = /*#__PURE__*/require('./concat');
+
+var difference = /*#__PURE__*/require('./difference');
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements contained in the first or
+ * second list, but not both.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` or `list2`, but not both.
+ * @see R.symmetricDifferenceWith, R.difference, R.differenceWith
+ * @example
+ *
+ *      R.symmetricDifference([1,2,3,4], [7,6,5,4,3]); //=> [1,2,7,6,5]
+ *      R.symmetricDifference([7,6,5,4,3], [1,2,3,4]); //=> [7,6,5,1,2]
+ */
+
+
+var symmetricDifference = /*#__PURE__*/_curry2(function symmetricDifference(list1, list2) {
+  return concat(difference(list1, list2), difference(list2, list1));
+});
+module.exports = symmetricDifference;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/symmetricDifferenceWith.js b/server/node_modules/ramda/src/symmetricDifferenceWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..cd54bd381b89019afdbf6e83290e88b5552ac240
--- /dev/null
+++ b/server/node_modules/ramda/src/symmetricDifferenceWith.js
@@ -0,0 +1,34 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var concat = /*#__PURE__*/require('./concat');
+
+var differenceWith = /*#__PURE__*/require('./differenceWith');
+
+/**
+ * Finds the set (i.e. no duplicates) of all elements contained in the first or
+ * second list, but not both. Duplication is determined according to the value
+ * returned by applying the supplied predicate to two list elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category Relation
+ * @sig ((a, a) -> Boolean) -> [a] -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The elements in `list1` or `list2`, but not both.
+ * @see R.symmetricDifference, R.difference, R.differenceWith
+ * @example
+ *
+ *      const eqA = R.eqBy(R.prop('a'));
+ *      const l1 = [{a: 1}, {a: 2}, {a: 3}, {a: 4}];
+ *      const l2 = [{a: 3}, {a: 4}, {a: 5}, {a: 6}];
+ *      R.symmetricDifferenceWith(eqA, l1, l2); //=> [{a: 1}, {a: 2}, {a: 5}, {a: 6}]
+ */
+
+
+var symmetricDifferenceWith = /*#__PURE__*/_curry3(function symmetricDifferenceWith(pred, list1, list2) {
+  return concat(differenceWith(pred, list1, list2), differenceWith(pred, list2, list1));
+});
+module.exports = symmetricDifferenceWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/tail.js b/server/node_modules/ramda/src/tail.js
new file mode 100644
index 0000000000000000000000000000000000000000..3840892eb7a543e6b910c218f61ca281f8e18edb
--- /dev/null
+++ b/server/node_modules/ramda/src/tail.js
@@ -0,0 +1,37 @@
+var _checkForMethod = /*#__PURE__*/require('./internal/_checkForMethod');
+
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var slice = /*#__PURE__*/require('./slice');
+
+/**
+ * Returns all but the first element of the given list or string (or object
+ * with a `tail` method).
+ *
+ * Dispatches to the `slice` method of the first argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a]
+ * @sig String -> String
+ * @param {*} list
+ * @return {*}
+ * @see R.head, R.init, R.last
+ * @example
+ *
+ *      R.tail([1, 2, 3]);  //=> [2, 3]
+ *      R.tail([1, 2]);     //=> [2]
+ *      R.tail([1]);        //=> []
+ *      R.tail([]);         //=> []
+ *
+ *      R.tail('abc');  //=> 'bc'
+ *      R.tail('ab');   //=> 'b'
+ *      R.tail('a');    //=> ''
+ *      R.tail('');     //=> ''
+ */
+
+
+var tail = /*#__PURE__*/_curry1( /*#__PURE__*/_checkForMethod('tail', /*#__PURE__*/slice(1, Infinity)));
+module.exports = tail;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/take.js b/server/node_modules/ramda/src/take.js
new file mode 100644
index 0000000000000000000000000000000000000000..2e365043981a5359f72e509444312d882dba0834
--- /dev/null
+++ b/server/node_modules/ramda/src/take.js
@@ -0,0 +1,57 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xtake = /*#__PURE__*/require('./internal/_xtake');
+
+var slice = /*#__PURE__*/require('./slice');
+
+/**
+ * Returns the first `n` elements of the given list, string, or
+ * transducer/transformer (or object with a `take` method).
+ *
+ * Dispatches to the `take` method of the second argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n
+ * @param {*} list
+ * @return {*}
+ * @see R.drop
+ * @example
+ *
+ *      R.take(1, ['foo', 'bar', 'baz']); //=> ['foo']
+ *      R.take(2, ['foo', 'bar', 'baz']); //=> ['foo', 'bar']
+ *      R.take(3, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.take(4, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.take(3, 'ramda');               //=> 'ram'
+ *
+ *      const personnel = [
+ *        'Dave Brubeck',
+ *        'Paul Desmond',
+ *        'Eugene Wright',
+ *        'Joe Morello',
+ *        'Gerry Mulligan',
+ *        'Bob Bates',
+ *        'Joe Dodge',
+ *        'Ron Crotty'
+ *      ];
+ *
+ *      const takeFive = R.take(5);
+ *      takeFive(personnel);
+ *      //=> ['Dave Brubeck', 'Paul Desmond', 'Eugene Wright', 'Joe Morello', 'Gerry Mulligan']
+ * @symb R.take(-1, [a, b]) = [a, b]
+ * @symb R.take(0, [a, b]) = []
+ * @symb R.take(1, [a, b]) = [a]
+ * @symb R.take(2, [a, b]) = [a, b]
+ */
+
+
+var take = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['take'], _xtake, function take(n, xs) {
+  return slice(0, n < 0 ? Infinity : n, xs);
+}));
+module.exports = take;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/takeLast.js b/server/node_modules/ramda/src/takeLast.js
new file mode 100644
index 0000000000000000000000000000000000000000..983788c387b442dd5650678e30e6685ce2ee914f
--- /dev/null
+++ b/server/node_modules/ramda/src/takeLast.js
@@ -0,0 +1,32 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var drop = /*#__PURE__*/require('./drop');
+
+/**
+ * Returns a new list containing the last `n` elements of the given list.
+ * If `n > list.length`, returns a list of `list.length` elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig Number -> [a] -> [a]
+ * @sig Number -> String -> String
+ * @param {Number} n The number of elements to return.
+ * @param {Array} xs The collection to consider.
+ * @return {Array}
+ * @see R.dropLast
+ * @example
+ *
+ *      R.takeLast(1, ['foo', 'bar', 'baz']); //=> ['baz']
+ *      R.takeLast(2, ['foo', 'bar', 'baz']); //=> ['bar', 'baz']
+ *      R.takeLast(3, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.takeLast(4, ['foo', 'bar', 'baz']); //=> ['foo', 'bar', 'baz']
+ *      R.takeLast(3, 'ramda');               //=> 'mda'
+ */
+
+
+var takeLast = /*#__PURE__*/_curry2(function takeLast(n, xs) {
+  return drop(n >= 0 ? xs.length - n : 0, xs);
+});
+module.exports = takeLast;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/takeLastWhile.js b/server/node_modules/ramda/src/takeLastWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..3360b01867ba61874b76dfba83933d7b5c40a0b0
--- /dev/null
+++ b/server/node_modules/ramda/src/takeLastWhile.js
@@ -0,0 +1,39 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var slice = /*#__PURE__*/require('./slice');
+
+/**
+ * Returns a new list containing the last `n` elements of a given list, passing
+ * each value to the supplied predicate function, and terminating when the
+ * predicate function returns `false`. Excludes the element that caused the
+ * predicate function to fail. The predicate function is passed one argument:
+ * *(value)*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} fn The function called per iteration.
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array.
+ * @see R.dropLastWhile, R.addIndex
+ * @example
+ *
+ *      const isNotOne = x => x !== 1;
+ *
+ *      R.takeLastWhile(isNotOne, [1, 2, 3, 4]); //=> [2, 3, 4]
+ *
+ *      R.takeLastWhile(x => x !== 'R' , 'Ramda'); //=> 'amda'
+ */
+
+
+var takeLastWhile = /*#__PURE__*/_curry2(function takeLastWhile(fn, xs) {
+  var idx = xs.length - 1;
+  while (idx >= 0 && fn(xs[idx])) {
+    idx -= 1;
+  }
+  return slice(idx + 1, Infinity, xs);
+});
+module.exports = takeLastWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/takeWhile.js b/server/node_modules/ramda/src/takeWhile.js
new file mode 100644
index 0000000000000000000000000000000000000000..f646646bbd3ea0b9adc5a6554087564c3b66f4d5
--- /dev/null
+++ b/server/node_modules/ramda/src/takeWhile.js
@@ -0,0 +1,48 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xtakeWhile = /*#__PURE__*/require('./internal/_xtakeWhile');
+
+var slice = /*#__PURE__*/require('./slice');
+
+/**
+ * Returns a new list containing the first `n` elements of a given list,
+ * passing each value to the supplied predicate function, and terminating when
+ * the predicate function returns `false`. Excludes the element that caused the
+ * predicate function to fail. The predicate function is passed one argument:
+ * *(value)*.
+ *
+ * Dispatches to the `takeWhile` method of the second argument, if present.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig (a -> Boolean) -> [a] -> [a]
+ * @sig (a -> Boolean) -> String -> String
+ * @param {Function} fn The function called per iteration.
+ * @param {Array} xs The collection to iterate over.
+ * @return {Array} A new array.
+ * @see R.dropWhile, R.transduce, R.addIndex
+ * @example
+ *
+ *      const isNotFour = x => x !== 4;
+ *
+ *      R.takeWhile(isNotFour, [1, 2, 3, 4, 3, 2, 1]); //=> [1, 2, 3]
+ *
+ *      R.takeWhile(x => x !== 'd' , 'Ramda'); //=> 'Ram'
+ */
+
+
+var takeWhile = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable(['takeWhile'], _xtakeWhile, function takeWhile(fn, xs) {
+  var idx = 0;
+  var len = xs.length;
+  while (idx < len && fn(xs[idx])) {
+    idx += 1;
+  }
+  return slice(0, idx, xs);
+}));
+module.exports = takeWhile;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/tap.js b/server/node_modules/ramda/src/tap.js
new file mode 100644
index 0000000000000000000000000000000000000000..3e9f3459c057dcd91361d3df94631da2be18d0d7
--- /dev/null
+++ b/server/node_modules/ramda/src/tap.js
@@ -0,0 +1,33 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _dispatchable = /*#__PURE__*/require('./internal/_dispatchable');
+
+var _xtap = /*#__PURE__*/require('./internal/_xtap');
+
+/**
+ * Runs the given function with the supplied object, then returns the object.
+ *
+ * Acts as a transducer if a transformer is given as second parameter.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig (a -> *) -> a -> a
+ * @param {Function} fn The function to call with `x`. The return value of `fn` will be thrown away.
+ * @param {*} x
+ * @return {*} `x`.
+ * @example
+ *
+ *      const sayX = x => console.log('x is ' + x);
+ *      R.tap(sayX, 100); //=> 100
+ *      // logs 'x is 100'
+ * @symb R.tap(f, a) = a
+ */
+
+
+var tap = /*#__PURE__*/_curry2( /*#__PURE__*/_dispatchable([], _xtap, function tap(fn, x) {
+  fn(x);
+  return x;
+}));
+module.exports = tap;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/test.js b/server/node_modules/ramda/src/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..e450b3a570730194277e01dc568b8d953ac9859a
--- /dev/null
+++ b/server/node_modules/ramda/src/test.js
@@ -0,0 +1,34 @@
+var _cloneRegExp = /*#__PURE__*/require('./internal/_cloneRegExp');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _isRegExp = /*#__PURE__*/require('./internal/_isRegExp');
+
+var toString = /*#__PURE__*/require('./toString');
+
+/**
+ * Determines whether a given string matches a given regular expression.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category String
+ * @sig RegExp -> String -> Boolean
+ * @param {RegExp} pattern
+ * @param {String} str
+ * @return {Boolean}
+ * @see R.match
+ * @example
+ *
+ *      R.test(/^x/, 'xyz'); //=> true
+ *      R.test(/^y/, 'xyz'); //=> false
+ */
+
+
+var test = /*#__PURE__*/_curry2(function test(pattern, str) {
+  if (!_isRegExp(pattern)) {
+    throw new TypeError('‘test’ requires a value of type RegExp as its first argument; received ' + toString(pattern));
+  }
+  return _cloneRegExp(pattern).test(str);
+});
+module.exports = test;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/then.js b/server/node_modules/ramda/src/then.js
new file mode 100644
index 0000000000000000000000000000000000000000..b2d9405e6b29c41a53d860030f0c84a9e2712c0e
--- /dev/null
+++ b/server/node_modules/ramda/src/then.js
@@ -0,0 +1,37 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _assertPromise = /*#__PURE__*/require('./internal/_assertPromise');
+
+/**
+ * Returns the result of applying the onSuccess function to the value inside
+ * a successfully resolved promise. This is useful for working with promises
+ * inside function compositions.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig (a -> b) -> (Promise e a) -> (Promise e b)
+ * @sig (a -> (Promise e b)) -> (Promise e a) -> (Promise e b)
+ * @param {Function} onSuccess The function to apply. Can return a value or a promise of a value.
+ * @param {Promise} p
+ * @return {Promise} The result of calling `p.then(onSuccess)`
+ * @see R.otherwise
+ * @example
+ *
+ *      var makeQuery = (email) => ({ query: { email }});
+ *
+ *      //getMemberName :: String -> Promise ({firstName, lastName})
+ *      var getMemberName = R.pipe(
+ *        makeQuery,
+ *        fetchMember,
+ *        R.then(R.pick(['firstName', 'lastName']))
+ *      );
+ */
+
+
+var then = /*#__PURE__*/_curry2(function then(f, p) {
+  _assertPromise('then', p);
+
+  return p.then(f);
+});
+module.exports = then;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/thunkify.js b/server/node_modules/ramda/src/thunkify.js
new file mode 100644
index 0000000000000000000000000000000000000000..9353dc50fa8d1538e81e57f9bd2a72d344c25bcd
--- /dev/null
+++ b/server/node_modules/ramda/src/thunkify.js
@@ -0,0 +1,33 @@
+var curryN = /*#__PURE__*/require('./curryN');
+
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Creates a thunk out of a function. A thunk delays a calculation until
+ * its result is needed, providing lazy evaluation of arguments.
+ *
+ * @func
+ * @memberOf R
+ * @category Function
+ * @sig ((a, b, ..., j) -> k) -> (a, b, ..., j) -> (() -> k)
+ * @param {Function} fn A function to wrap in a thunk
+ * @return {Function} Expects arguments for `fn` and returns a new function
+ *  that, when called, applies those arguments to `fn`.
+ * @see R.partial, R.partialRight
+ * @example
+ *
+ *      R.thunkify(R.identity)(42)(); //=> 42
+ *      R.thunkify((a, b) => a + b)(25, 17)(); //=> 42
+ */
+
+
+var thunkify = /*#__PURE__*/_curry1(function thunkify(fn) {
+  return curryN(fn.length, function createThunk() {
+    var fnArgs = arguments;
+    return function invokeThunk() {
+      return fn.apply(this, fnArgs);
+    };
+  });
+});
+
+module.exports = thunkify;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/times.js b/server/node_modules/ramda/src/times.js
new file mode 100644
index 0000000000000000000000000000000000000000..56204dce0be98e223d0fef035a713937e1125b5f
--- /dev/null
+++ b/server/node_modules/ramda/src/times.js
@@ -0,0 +1,43 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Calls an input function `n` times, returning an array containing the results
+ * of those function calls.
+ *
+ * `fn` is passed one argument: The current value of `n`, which begins at `0`
+ * and is gradually incremented to `n - 1`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.3
+ * @category List
+ * @sig (Number -> a) -> Number -> [a]
+ * @param {Function} fn The function to invoke. Passed one argument, the current value of `n`.
+ * @param {Number} n A value between `0` and `n - 1`. Increments after each function call.
+ * @return {Array} An array containing the return values of all calls to `fn`.
+ * @see R.repeat
+ * @example
+ *
+ *      R.times(R.identity, 5); //=> [0, 1, 2, 3, 4]
+ * @symb R.times(f, 0) = []
+ * @symb R.times(f, 1) = [f(0)]
+ * @symb R.times(f, 2) = [f(0), f(1)]
+ */
+
+
+var times = /*#__PURE__*/_curry2(function times(fn, n) {
+  var len = Number(n);
+  var idx = 0;
+  var list;
+
+  if (len < 0 || isNaN(len)) {
+    throw new RangeError('n must be a non-negative number');
+  }
+  list = new Array(len);
+  while (idx < len) {
+    list[idx] = fn(idx);
+    idx += 1;
+  }
+  return list;
+});
+module.exports = times;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/toLower.js b/server/node_modules/ramda/src/toLower.js
new file mode 100644
index 0000000000000000000000000000000000000000..5bd5229532baec491efff89087f77f4f749ef1df
--- /dev/null
+++ b/server/node_modules/ramda/src/toLower.js
@@ -0,0 +1,21 @@
+var invoker = /*#__PURE__*/require('./invoker');
+
+/**
+ * The lower case version of a string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category String
+ * @sig String -> String
+ * @param {String} str The string to lower case.
+ * @return {String} The lower case version of `str`.
+ * @see R.toUpper
+ * @example
+ *
+ *      R.toLower('XYZ'); //=> 'xyz'
+ */
+
+
+var toLower = /*#__PURE__*/invoker(0, 'toLowerCase');
+module.exports = toLower;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/toPairs.js b/server/node_modules/ramda/src/toPairs.js
new file mode 100644
index 0000000000000000000000000000000000000000..b83de95846080bec82bd9d64a047ae5aa1f8c5a6
--- /dev/null
+++ b/server/node_modules/ramda/src/toPairs.js
@@ -0,0 +1,34 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _has = /*#__PURE__*/require('./internal/_has');
+
+/**
+ * Converts an object into an array of key, value arrays. Only the object's
+ * own properties are used.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.0
+ * @category Object
+ * @sig {String: *} -> [[String,*]]
+ * @param {Object} obj The object to extract from
+ * @return {Array} An array of key, value arrays from the object's own properties.
+ * @see R.fromPairs
+ * @example
+ *
+ *      R.toPairs({a: 1, b: 2, c: 3}); //=> [['a', 1], ['b', 2], ['c', 3]]
+ */
+
+
+var toPairs = /*#__PURE__*/_curry1(function toPairs(obj) {
+  var pairs = [];
+  for (var prop in obj) {
+    if (_has(prop, obj)) {
+      pairs[pairs.length] = [prop, obj[prop]];
+    }
+  }
+  return pairs;
+});
+module.exports = toPairs;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/toPairsIn.js b/server/node_modules/ramda/src/toPairsIn.js
new file mode 100644
index 0000000000000000000000000000000000000000..fba93cb50168d563948092916b738baed7a5a302
--- /dev/null
+++ b/server/node_modules/ramda/src/toPairsIn.js
@@ -0,0 +1,33 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Converts an object into an array of key, value arrays. The object's own
+ * properties and prototype properties are used. Note that the order of the
+ * output array is not guaranteed to be consistent across different JS
+ * platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.4.0
+ * @category Object
+ * @sig {String: *} -> [[String,*]]
+ * @param {Object} obj The object to extract from
+ * @return {Array} An array of key, value arrays from the object's own
+ *         and prototype properties.
+ * @example
+ *
+ *      const F = function() { this.x = 'X'; };
+ *      F.prototype.y = 'Y';
+ *      const f = new F();
+ *      R.toPairsIn(f); //=> [['x','X'], ['y','Y']]
+ */
+
+
+var toPairsIn = /*#__PURE__*/_curry1(function toPairsIn(obj) {
+  var pairs = [];
+  for (var prop in obj) {
+    pairs[pairs.length] = [prop, obj[prop]];
+  }
+  return pairs;
+});
+module.exports = toPairsIn;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/toString.js b/server/node_modules/ramda/src/toString.js
new file mode 100644
index 0000000000000000000000000000000000000000..d4257d749e66e783d9f40c78bdb33cd9b33457a5
--- /dev/null
+++ b/server/node_modules/ramda/src/toString.js
@@ -0,0 +1,46 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var _toString = /*#__PURE__*/require('./internal/_toString');
+
+/**
+ * Returns the string representation of the given value. `eval`'ing the output
+ * should result in a value equivalent to the input value. Many of the built-in
+ * `toString` methods do not satisfy this requirement.
+ *
+ * If the given value is an `[object Object]` with a `toString` method other
+ * than `Object.prototype.toString`, this method is invoked with no arguments
+ * to produce the return value. This means user-defined constructor functions
+ * can provide a suitable `toString` method. For example:
+ *
+ *     function Point(x, y) {
+ *       this.x = x;
+ *       this.y = y;
+ *     }
+ *
+ *     Point.prototype.toString = function() {
+ *       return 'new Point(' + this.x + ', ' + this.y + ')';
+ *     };
+ *
+ *     R.toString(new Point(1, 2)); //=> 'new Point(1, 2)'
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category String
+ * @sig * -> String
+ * @param {*} val
+ * @return {String}
+ * @example
+ *
+ *      R.toString(42); //=> '42'
+ *      R.toString('abc'); //=> '"abc"'
+ *      R.toString([1, 2, 3]); //=> '[1, 2, 3]'
+ *      R.toString({foo: 1, bar: 2, baz: 3}); //=> '{"bar": 2, "baz": 3, "foo": 1}'
+ *      R.toString(new Date('2001-02-03T04:05:06Z')); //=> 'new Date("2001-02-03T04:05:06.000Z")'
+ */
+
+
+var toString = /*#__PURE__*/_curry1(function toString(val) {
+  return _toString(val, []);
+});
+module.exports = toString;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/toUpper.js b/server/node_modules/ramda/src/toUpper.js
new file mode 100644
index 0000000000000000000000000000000000000000..b29585cd7b6619d9374f2a3830cd46e6d4a83064
--- /dev/null
+++ b/server/node_modules/ramda/src/toUpper.js
@@ -0,0 +1,21 @@
+var invoker = /*#__PURE__*/require('./invoker');
+
+/**
+ * The upper case version of a string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.9.0
+ * @category String
+ * @sig String -> String
+ * @param {String} str The string to upper case.
+ * @return {String} The upper case version of `str`.
+ * @see R.toLower
+ * @example
+ *
+ *      R.toUpper('abc'); //=> 'ABC'
+ */
+
+
+var toUpper = /*#__PURE__*/invoker(0, 'toUpperCase');
+module.exports = toUpper;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/transduce.js b/server/node_modules/ramda/src/transduce.js
new file mode 100644
index 0000000000000000000000000000000000000000..7b2d3b47e52217d56982b507e885e69bc0c0157f
--- /dev/null
+++ b/server/node_modules/ramda/src/transduce.js
@@ -0,0 +1,59 @@
+var _reduce = /*#__PURE__*/require('./internal/_reduce');
+
+var _xwrap = /*#__PURE__*/require('./internal/_xwrap');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+/**
+ * Initializes a transducer using supplied iterator function. Returns a single
+ * item by iterating through the list, successively calling the transformed
+ * iterator function and passing it an accumulator value and the current value
+ * from the array, and then passing the result to the next call.
+ *
+ * The iterator function receives two values: *(acc, value)*. It will be
+ * wrapped as a transformer to initialize the transducer. A transformer can be
+ * passed directly in place of an iterator function. In both cases, iteration
+ * may be stopped early with the [`R.reduced`](#reduced) function.
+ *
+ * A transducer is a function that accepts a transformer and returns a
+ * transformer and can be composed directly.
+ *
+ * A transformer is an an object that provides a 2-arity reducing iterator
+ * function, step, 0-arity initial value function, init, and 1-arity result
+ * extraction function, result. The step function is used as the iterator
+ * function in reduce. The result function is used to convert the final
+ * accumulator into the return type and in most cases is
+ * [`R.identity`](#identity). The init function can be used to provide an
+ * initial accumulator, but is ignored by transduce.
+ *
+ * The iteration is performed with [`R.reduce`](#reduce) after initializing the transducer.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.12.0
+ * @category List
+ * @sig (c -> c) -> ((a, b) -> a) -> a -> [b] -> a
+ * @param {Function} xf The transducer function. Receives a transformer and returns a transformer.
+ * @param {Function} fn The iterator function. Receives two values, the accumulator and the
+ *        current element from the array. Wrapped as transformer, if necessary, and used to
+ *        initialize the transducer
+ * @param {*} acc The initial accumulator value.
+ * @param {Array} list The list to iterate over.
+ * @return {*} The final, accumulated value.
+ * @see R.reduce, R.reduced, R.into
+ * @example
+ *
+ *      const numbers = [1, 2, 3, 4];
+ *      const transducer = R.compose(R.map(R.add(1)), R.take(2));
+ *      R.transduce(transducer, R.flip(R.append), [], numbers); //=> [2, 3]
+ *
+ *      const isOdd = (x) => x % 2 === 1;
+ *      const firstOddTransducer = R.compose(R.filter(isOdd), R.take(1));
+ *      R.transduce(firstOddTransducer, R.flip(R.append), [], R.range(0, 100)); //=> [1]
+ */
+
+
+var transduce = /*#__PURE__*/curryN(4, function transduce(xf, fn, acc, list) {
+  return _reduce(xf(typeof fn === 'function' ? _xwrap(fn) : fn), acc, list);
+});
+module.exports = transduce;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/transpose.js b/server/node_modules/ramda/src/transpose.js
new file mode 100644
index 0000000000000000000000000000000000000000..d6888762c0b20e92dfe22df1c385fcd11afefe61
--- /dev/null
+++ b/server/node_modules/ramda/src/transpose.js
@@ -0,0 +1,46 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Transposes the rows and columns of a 2D list.
+ * When passed a list of `n` lists of length `x`,
+ * returns a list of `x` lists of length `n`.
+ *
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig [[a]] -> [[a]]
+ * @param {Array} list A 2D list
+ * @return {Array} A 2D list
+ * @example
+ *
+ *      R.transpose([[1, 'a'], [2, 'b'], [3, 'c']]) //=> [[1, 2, 3], ['a', 'b', 'c']]
+ *      R.transpose([[1, 2, 3], ['a', 'b', 'c']]) //=> [[1, 'a'], [2, 'b'], [3, 'c']]
+ *
+ *      // If some of the rows are shorter than the following rows, their elements are skipped:
+ *      R.transpose([[10, 11], [20], [], [30, 31, 32]]) //=> [[10, 20, 30], [11, 31], [32]]
+ * @symb R.transpose([[a], [b], [c]]) = [a, b, c]
+ * @symb R.transpose([[a, b], [c, d]]) = [[a, c], [b, d]]
+ * @symb R.transpose([[a, b], [c]]) = [[a, c], [b]]
+ */
+
+
+var transpose = /*#__PURE__*/_curry1(function transpose(outerlist) {
+  var i = 0;
+  var result = [];
+  while (i < outerlist.length) {
+    var innerlist = outerlist[i];
+    var j = 0;
+    while (j < innerlist.length) {
+      if (typeof result[j] === 'undefined') {
+        result[j] = [];
+      }
+      result[j].push(innerlist[j]);
+      j += 1;
+    }
+    i += 1;
+  }
+  return result;
+});
+module.exports = transpose;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/traverse.js b/server/node_modules/ramda/src/traverse.js
new file mode 100644
index 0000000000000000000000000000000000000000..3808cd88d9cce1abffc03ca5af4c6ff1f1062e1a
--- /dev/null
+++ b/server/node_modules/ramda/src/traverse.js
@@ -0,0 +1,38 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var map = /*#__PURE__*/require('./map');
+
+var sequence = /*#__PURE__*/require('./sequence');
+
+/**
+ * Maps an [Applicative](https://github.com/fantasyland/fantasy-land#applicative)-returning
+ * function over a [Traversable](https://github.com/fantasyland/fantasy-land#traversable),
+ * then uses [`sequence`](#sequence) to transform the resulting Traversable of Applicative
+ * into an Applicative of Traversable.
+ *
+ * Dispatches to the `traverse` method of the third argument, if present.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig (Applicative f, Traversable t) => (a -> f a) -> (a -> f b) -> t a -> f (t b)
+ * @param {Function} of
+ * @param {Function} f
+ * @param {*} traversable
+ * @return {*}
+ * @see R.sequence
+ * @example
+ *
+ *      // Returns `Maybe.Nothing` if the given divisor is `0`
+ *      const safeDiv = n => d => d === 0 ? Maybe.Nothing() : Maybe.Just(n / d)
+ *
+ *      R.traverse(Maybe.of, safeDiv(10), [2, 4, 5]); //=> Maybe.Just([5, 2.5, 2])
+ *      R.traverse(Maybe.of, safeDiv(10), [2, 0, 5]); //=> Maybe.Nothing
+ */
+
+
+var traverse = /*#__PURE__*/_curry3(function traverse(of, f, traversable) {
+  return typeof traversable['fantasy-land/traverse'] === 'function' ? traversable['fantasy-land/traverse'](f, of) : sequence(of, map(f, traversable));
+});
+module.exports = traverse;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/trim.js b/server/node_modules/ramda/src/trim.js
new file mode 100644
index 0000000000000000000000000000000000000000..01668932573f0738504c5fa9a0a48cc293325a2a
--- /dev/null
+++ b/server/node_modules/ramda/src/trim.js
@@ -0,0 +1,28 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' + '\u2029\uFEFF';
+var zeroWidth = '\u200b';
+var hasProtoTrim = typeof String.prototype.trim === 'function';
+/**
+ * Removes (strips) whitespace from both ends of the string.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.6.0
+ * @category String
+ * @sig String -> String
+ * @param {String} str The string to trim.
+ * @return {String} Trimmed version of `str`.
+ * @example
+ *
+ *      R.trim('   xyz  '); //=> 'xyz'
+ *      R.map(R.trim, R.split(',', 'x, y, z')); //=> ['x', 'y', 'z']
+ */
+var trim = !hasProtoTrim || /*#__PURE__*/ws.trim() || ! /*#__PURE__*/zeroWidth.trim() ? /*#__PURE__*/_curry1(function trim(str) {
+  var beginRx = new RegExp('^[' + ws + '][' + ws + ']*');
+  var endRx = new RegExp('[' + ws + '][' + ws + ']*$');
+  return str.replace(beginRx, '').replace(endRx, '');
+}) : /*#__PURE__*/_curry1(function trim(str) {
+  return str.trim();
+});
+module.exports = trim;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/tryCatch.js b/server/node_modules/ramda/src/tryCatch.js
new file mode 100644
index 0000000000000000000000000000000000000000..63f1f809453bf45c2fec66864b299aa35f63e88d
--- /dev/null
+++ b/server/node_modules/ramda/src/tryCatch.js
@@ -0,0 +1,40 @@
+var _arity = /*#__PURE__*/require('./internal/_arity');
+
+var _concat = /*#__PURE__*/require('./internal/_concat');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * `tryCatch` takes two functions, a `tryer` and a `catcher`. The returned
+ * function evaluates the `tryer`; if it does not throw, it simply returns the
+ * result. If the `tryer` *does* throw, the returned function evaluates the
+ * `catcher` function and returns its result. Note that for effective
+ * composition with this function, both the `tryer` and `catcher` functions
+ * must return the same type of results.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Function
+ * @sig (...x -> a) -> ((e, ...x) -> a) -> (...x -> a)
+ * @param {Function} tryer The function that may throw.
+ * @param {Function} catcher The function that will be evaluated if `tryer` throws.
+ * @return {Function} A new function that will catch exceptions and send then to the catcher.
+ * @example
+ *
+ *      R.tryCatch(R.prop('x'), R.F)({x: true}); //=> true
+ *      R.tryCatch(() => { throw 'foo'}, R.always('catched'))('bar') // => 'catched'
+ *      R.tryCatch(R.times(R.identity), R.always([]))('s') // => []
+ `` */
+
+
+var tryCatch = /*#__PURE__*/_curry2(function _tryCatch(tryer, catcher) {
+  return _arity(tryer.length, function () {
+    try {
+      return tryer.apply(this, arguments);
+    } catch (e) {
+      return catcher.apply(this, _concat([e], arguments));
+    }
+  });
+});
+module.exports = tryCatch;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/type.js b/server/node_modules/ramda/src/type.js
new file mode 100644
index 0000000000000000000000000000000000000000..4aa311fa8d13d12e57b318ba9946984d8fef591d
--- /dev/null
+++ b/server/node_modules/ramda/src/type.js
@@ -0,0 +1,33 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Gives a single-word string description of the (native) type of a value,
+ * returning such answers as 'Object', 'Number', 'Array', or 'Null'. Does not
+ * attempt to distinguish user Object types any further, reporting them all as
+ * 'Object'.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Type
+ * @sig (* -> {*}) -> String
+ * @param {*} val The value to test
+ * @return {String}
+ * @example
+ *
+ *      R.type({}); //=> "Object"
+ *      R.type(1); //=> "Number"
+ *      R.type(false); //=> "Boolean"
+ *      R.type('s'); //=> "String"
+ *      R.type(null); //=> "Null"
+ *      R.type([]); //=> "Array"
+ *      R.type(/[A-z]/); //=> "RegExp"
+ *      R.type(() => {}); //=> "Function"
+ *      R.type(undefined); //=> "Undefined"
+ */
+
+
+var type = /*#__PURE__*/_curry1(function type(val) {
+  return val === null ? 'Null' : val === undefined ? 'Undefined' : Object.prototype.toString.call(val).slice(8, -1);
+});
+module.exports = type;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/unapply.js b/server/node_modules/ramda/src/unapply.js
new file mode 100644
index 0000000000000000000000000000000000000000..79f8e9675c5a53e5ba7faeda5709ed75a3cbcf85
--- /dev/null
+++ b/server/node_modules/ramda/src/unapply.js
@@ -0,0 +1,34 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Takes a function `fn`, which takes a single array argument, and returns a
+ * function which:
+ *
+ *   - takes any number of positional arguments;
+ *   - passes these arguments to `fn` as an array; and
+ *   - returns the result.
+ *
+ * In other words, `R.unapply` derives a variadic function from a function which
+ * takes an array. `R.unapply` is the inverse of [`R.apply`](#apply).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.8.0
+ * @category Function
+ * @sig ([*...] -> a) -> (*... -> a)
+ * @param {Function} fn
+ * @return {Function}
+ * @see R.apply
+ * @example
+ *
+ *      R.unapply(JSON.stringify)(1, 2, 3); //=> '[1,2,3]'
+ * @symb R.unapply(f)(a, b) = f([a, b])
+ */
+
+
+var unapply = /*#__PURE__*/_curry1(function unapply(fn) {
+  return function () {
+    return fn(Array.prototype.slice.call(arguments, 0));
+  };
+});
+module.exports = unapply;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/unary.js b/server/node_modules/ramda/src/unary.js
new file mode 100644
index 0000000000000000000000000000000000000000..f4f5053c4f50c3767630cae40592b7536962d5b9
--- /dev/null
+++ b/server/node_modules/ramda/src/unary.js
@@ -0,0 +1,38 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var nAry = /*#__PURE__*/require('./nAry');
+
+/**
+ * Wraps a function of any arity (including nullary) in a function that accepts
+ * exactly 1 parameter. Any extraneous parameters will not be passed to the
+ * supplied function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Function
+ * @sig (* -> b) -> (a -> b)
+ * @param {Function} fn The function to wrap.
+ * @return {Function} A new function wrapping `fn`. The new function is guaranteed to be of
+ *         arity 1.
+ * @see R.binary, R.nAry
+ * @example
+ *
+ *      const takesTwoArgs = function(a, b) {
+ *        return [a, b];
+ *      };
+ *      takesTwoArgs.length; //=> 2
+ *      takesTwoArgs(1, 2); //=> [1, 2]
+ *
+ *      const takesOneArg = R.unary(takesTwoArgs);
+ *      takesOneArg.length; //=> 1
+ *      // Only 1 argument is passed to the wrapped function
+ *      takesOneArg(1, 2); //=> [1, undefined]
+ * @symb R.unary(f)(a, b, c) = f(a)
+ */
+
+
+var unary = /*#__PURE__*/_curry1(function unary(fn) {
+  return nAry(1, fn);
+});
+module.exports = unary;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/uncurryN.js b/server/node_modules/ramda/src/uncurryN.js
new file mode 100644
index 0000000000000000000000000000000000000000..10ef5986a0b016badcfee0cc6d9cc7de03cd738f
--- /dev/null
+++ b/server/node_modules/ramda/src/uncurryN.js
@@ -0,0 +1,41 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+/**
+ * Returns a function of arity `n` from a (manually) curried function.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Function
+ * @sig Number -> (a -> b) -> (a -> c)
+ * @param {Number} length The arity for the returned function.
+ * @param {Function} fn The function to uncurry.
+ * @return {Function} A new function.
+ * @see R.curry
+ * @example
+ *
+ *      const addFour = a => b => c => d => a + b + c + d;
+ *
+ *      const uncurriedAddFour = R.uncurryN(4, addFour);
+ *      uncurriedAddFour(1, 2, 3, 4); //=> 10
+ */
+
+
+var uncurryN = /*#__PURE__*/_curry2(function uncurryN(depth, fn) {
+  return curryN(depth, function () {
+    var currentDepth = 1;
+    var value = fn;
+    var idx = 0;
+    var endIdx;
+    while (currentDepth <= depth && typeof value === 'function') {
+      endIdx = currentDepth === depth ? arguments.length : idx + value.length;
+      value = value.apply(this, Array.prototype.slice.call(arguments, idx, endIdx));
+      currentDepth += 1;
+      idx = endIdx;
+    }
+    return value;
+  });
+});
+module.exports = uncurryN;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/unfold.js b/server/node_modules/ramda/src/unfold.js
new file mode 100644
index 0000000000000000000000000000000000000000..abbbf2dcb21aca7899e6eb6000ae1cbd2b6337e3
--- /dev/null
+++ b/server/node_modules/ramda/src/unfold.js
@@ -0,0 +1,39 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Builds a list from a seed value. Accepts an iterator function, which returns
+ * either false to stop iteration or an array of length 2 containing the value
+ * to add to the resulting list and the seed to be used in the next call to the
+ * iterator function.
+ *
+ * The iterator function receives one argument: *(seed)*.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.10.0
+ * @category List
+ * @sig (a -> [b]) -> * -> [b]
+ * @param {Function} fn The iterator function. receives one argument, `seed`, and returns
+ *        either false to quit iteration or an array of length two to proceed. The element
+ *        at index 0 of this array will be added to the resulting array, and the element
+ *        at index 1 will be passed to the next call to `fn`.
+ * @param {*} seed The seed value.
+ * @return {Array} The final list.
+ * @example
+ *
+ *      const f = n => n > 50 ? false : [-n, n + 10];
+ *      R.unfold(f, 10); //=> [-10, -20, -30, -40, -50]
+ * @symb R.unfold(f, x) = [f(x)[0], f(f(x)[1])[0], f(f(f(x)[1])[1])[0], ...]
+ */
+
+
+var unfold = /*#__PURE__*/_curry2(function unfold(fn, seed) {
+  var pair = fn(seed);
+  var result = [];
+  while (pair && pair.length) {
+    result[result.length] = pair[0];
+    pair = fn(pair[1]);
+  }
+  return result;
+});
+module.exports = unfold;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/union.js b/server/node_modules/ramda/src/union.js
new file mode 100644
index 0000000000000000000000000000000000000000..da0efbb53d1d75ce515a5a63d66eb511a41ed041
--- /dev/null
+++ b/server/node_modules/ramda/src/union.js
@@ -0,0 +1,29 @@
+var _concat = /*#__PURE__*/require('./internal/_concat');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var compose = /*#__PURE__*/require('./compose');
+
+var uniq = /*#__PURE__*/require('./uniq');
+
+/**
+ * Combines two lists into a set (i.e. no duplicates) composed of the elements
+ * of each list.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig [*] -> [*] -> [*]
+ * @param {Array} as The first list.
+ * @param {Array} bs The second list.
+ * @return {Array} The first and second lists concatenated, with
+ *         duplicates removed.
+ * @example
+ *
+ *      R.union([1, 2, 3], [2, 3, 4]); //=> [1, 2, 3, 4]
+ */
+
+
+var union = /*#__PURE__*/_curry2( /*#__PURE__*/compose(uniq, _concat));
+module.exports = union;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/unionWith.js b/server/node_modules/ramda/src/unionWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..e1898d026ef84a480e26b564856d99ba2142dd12
--- /dev/null
+++ b/server/node_modules/ramda/src/unionWith.js
@@ -0,0 +1,34 @@
+var _concat = /*#__PURE__*/require('./internal/_concat');
+
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var uniqWith = /*#__PURE__*/require('./uniqWith');
+
+/**
+ * Combines two lists into a set (i.e. no duplicates) composed of the elements
+ * of each list. Duplication is determined according to the value returned by
+ * applying the supplied predicate to two list elements.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Relation
+ * @sig ((a, a) -> Boolean) -> [*] -> [*] -> [*]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list1 The first list.
+ * @param {Array} list2 The second list.
+ * @return {Array} The first and second lists concatenated, with
+ *         duplicates removed.
+ * @see R.union
+ * @example
+ *
+ *      const l1 = [{a: 1}, {a: 2}];
+ *      const l2 = [{a: 1}, {a: 4}];
+ *      R.unionWith(R.eqBy(R.prop('a')), l1, l2); //=> [{a: 1}, {a: 2}, {a: 4}]
+ */
+
+
+var unionWith = /*#__PURE__*/_curry3(function unionWith(pred, list1, list2) {
+  return uniqWith(pred, _concat(list1, list2));
+});
+module.exports = unionWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/uniq.js b/server/node_modules/ramda/src/uniq.js
new file mode 100644
index 0000000000000000000000000000000000000000..6939f1377d19abe88dd2a6e89f415bded68a7bd0
--- /dev/null
+++ b/server/node_modules/ramda/src/uniq.js
@@ -0,0 +1,25 @@
+var identity = /*#__PURE__*/require('./identity');
+
+var uniqBy = /*#__PURE__*/require('./uniqBy');
+
+/**
+ * Returns a new list containing only one copy of each element in the original
+ * list. [`R.equals`](#equals) is used to determine equality.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [a]
+ * @param {Array} list The array to consider.
+ * @return {Array} The list of unique items.
+ * @example
+ *
+ *      R.uniq([1, 1, 2, 1]); //=> [1, 2]
+ *      R.uniq([1, '1']);     //=> [1, '1']
+ *      R.uniq([[42], [42]]); //=> [[42]]
+ */
+
+
+var uniq = /*#__PURE__*/uniqBy(identity);
+module.exports = uniq;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/uniqBy.js b/server/node_modules/ramda/src/uniqBy.js
new file mode 100644
index 0000000000000000000000000000000000000000..b3ebbd9fa3f08c1b95ac813f6f84cab0c81bd9ad
--- /dev/null
+++ b/server/node_modules/ramda/src/uniqBy.js
@@ -0,0 +1,41 @@
+var _Set = /*#__PURE__*/require('./internal/_Set');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns a new list containing only one copy of each element in the original
+ * list, based upon the value returned by applying the supplied function to
+ * each list element. Prefers the first item if the supplied function produces
+ * the same value on two items. [`R.equals`](#equals) is used for comparison.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category List
+ * @sig (a -> b) -> [a] -> [a]
+ * @param {Function} fn A function used to produce a value to use during comparisons.
+ * @param {Array} list The array to consider.
+ * @return {Array} The list of unique items.
+ * @example
+ *
+ *      R.uniqBy(Math.abs, [-1, -5, 2, 10, 1, 2]); //=> [-1, -5, 2, 10]
+ */
+
+
+var uniqBy = /*#__PURE__*/_curry2(function uniqBy(fn, list) {
+  var set = new _Set();
+  var result = [];
+  var idx = 0;
+  var appliedItem, item;
+
+  while (idx < list.length) {
+    item = list[idx];
+    appliedItem = fn(item);
+    if (set.add(appliedItem)) {
+      result.push(item);
+    }
+    idx += 1;
+  }
+  return result;
+});
+module.exports = uniqBy;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/uniqWith.js b/server/node_modules/ramda/src/uniqWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..e4a8301ba833ff9c239d4caf1a9083ac52326d9a
--- /dev/null
+++ b/server/node_modules/ramda/src/uniqWith.js
@@ -0,0 +1,43 @@
+var _includesWith = /*#__PURE__*/require('./internal/_includesWith');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Returns a new list containing only one copy of each element in the original
+ * list, based upon the value returned by applying the supplied predicate to
+ * two list elements. Prefers the first item if two items compare equal based
+ * on the predicate.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category List
+ * @sig ((a, a) -> Boolean) -> [a] -> [a]
+ * @param {Function} pred A predicate used to test whether two items are equal.
+ * @param {Array} list The array to consider.
+ * @return {Array} The list of unique items.
+ * @example
+ *
+ *      const strEq = R.eqBy(String);
+ *      R.uniqWith(strEq)([1, '1', 2, 1]); //=> [1, 2]
+ *      R.uniqWith(strEq)([{}, {}]);       //=> [{}]
+ *      R.uniqWith(strEq)([1, '1', 1]);    //=> [1]
+ *      R.uniqWith(strEq)(['1', 1, 1]);    //=> ['1']
+ */
+
+
+var uniqWith = /*#__PURE__*/_curry2(function uniqWith(pred, list) {
+  var idx = 0;
+  var len = list.length;
+  var result = [];
+  var item;
+  while (idx < len) {
+    item = list[idx];
+    if (!_includesWith(pred, item, result)) {
+      result[result.length] = item;
+    }
+    idx += 1;
+  }
+  return result;
+});
+module.exports = uniqWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/unless.js b/server/node_modules/ramda/src/unless.js
new file mode 100644
index 0000000000000000000000000000000000000000..c29c1d4a899f56307ee9ceaddbd92e6c72ca9d83
--- /dev/null
+++ b/server/node_modules/ramda/src/unless.js
@@ -0,0 +1,32 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Tests the final argument by passing it to the given predicate function. If
+ * the predicate is not satisfied, the function will return the result of
+ * calling the `whenFalseFn` function with the same argument. If the predicate
+ * is satisfied, the argument is returned as is.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Logic
+ * @sig (a -> Boolean) -> (a -> a) -> a -> a
+ * @param {Function} pred        A predicate function
+ * @param {Function} whenFalseFn A function to invoke when the `pred` evaluates
+ *                               to a falsy value.
+ * @param {*}        x           An object to test with the `pred` function and
+ *                               pass to `whenFalseFn` if necessary.
+ * @return {*} Either `x` or the result of applying `x` to `whenFalseFn`.
+ * @see R.ifElse, R.when, R.cond
+ * @example
+ *
+ *      let safeInc = R.unless(R.isNil, R.inc);
+ *      safeInc(null); //=> null
+ *      safeInc(1); //=> 2
+ */
+
+
+var unless = /*#__PURE__*/_curry3(function unless(pred, whenFalseFn, x) {
+  return pred(x) ? x : whenFalseFn(x);
+});
+module.exports = unless;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/unnest.js b/server/node_modules/ramda/src/unnest.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6fa38a1ba5302801c05f7a0abcb34eb6f4cf36b
--- /dev/null
+++ b/server/node_modules/ramda/src/unnest.js
@@ -0,0 +1,25 @@
+var _identity = /*#__PURE__*/require('./internal/_identity');
+
+var chain = /*#__PURE__*/require('./chain');
+
+/**
+ * Shorthand for `R.chain(R.identity)`, which removes one level of nesting from
+ * any [Chain](https://github.com/fantasyland/fantasy-land#chain).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig Chain c => c (c a) -> c a
+ * @param {*} list
+ * @return {*}
+ * @see R.flatten, R.chain
+ * @example
+ *
+ *      R.unnest([1, [2], [[3]]]); //=> [1, 2, [3]]
+ *      R.unnest([[1, 2], [3, 4], [5, 6]]); //=> [1, 2, 3, 4, 5, 6]
+ */
+
+
+var unnest = /*#__PURE__*/chain(_identity);
+module.exports = unnest;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/until.js b/server/node_modules/ramda/src/until.js
new file mode 100644
index 0000000000000000000000000000000000000000..41969596c9296dcee4c105afe7c72a00aec1d892
--- /dev/null
+++ b/server/node_modules/ramda/src/until.js
@@ -0,0 +1,31 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Takes a predicate, a transformation function, and an initial value,
+ * and returns a value of the same type as the initial value.
+ * It does so by applying the transformation until the predicate is satisfied,
+ * at which point it returns the satisfactory value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.20.0
+ * @category Logic
+ * @sig (a -> Boolean) -> (a -> a) -> a -> a
+ * @param {Function} pred A predicate function
+ * @param {Function} fn The iterator function
+ * @param {*} init Initial value
+ * @return {*} Final value that satisfies predicate
+ * @example
+ *
+ *      R.until(R.gt(R.__, 100), R.multiply(2))(1) // => 128
+ */
+
+
+var until = /*#__PURE__*/_curry3(function until(pred, fn, init) {
+  var val = init;
+  while (!pred(val)) {
+    val = fn(val);
+  }
+  return val;
+});
+module.exports = until;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/update.js b/server/node_modules/ramda/src/update.js
new file mode 100644
index 0000000000000000000000000000000000000000..0b8450fa12fbd74bb005972473bf6a0da1d48f5f
--- /dev/null
+++ b/server/node_modules/ramda/src/update.js
@@ -0,0 +1,34 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+var adjust = /*#__PURE__*/require('./adjust');
+
+var always = /*#__PURE__*/require('./always');
+
+/**
+ * Returns a new copy of the array with the element at the provided index
+ * replaced with the given value.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category List
+ * @sig Number -> a -> [a] -> [a]
+ * @param {Number} idx The index to update.
+ * @param {*} x The value to exist at the given index of the returned array.
+ * @param {Array|Arguments} list The source array-like object to be updated.
+ * @return {Array} A copy of `list` with the value at index `idx` replaced with `x`.
+ * @see R.adjust
+ * @example
+ *
+ *      R.update(1, '_', ['a', 'b', 'c']);      //=> ['a', '_', 'c']
+ *      R.update(-1, '_', ['a', 'b', 'c']);     //=> ['a', 'b', '_']
+ * @symb R.update(-1, a, [b, c]) = [b, a]
+ * @symb R.update(0, a, [b, c]) = [a, c]
+ * @symb R.update(1, a, [b, c]) = [b, a]
+ */
+
+
+var update = /*#__PURE__*/_curry3(function update(idx, x, list) {
+  return adjust(idx, always(x), list);
+});
+module.exports = update;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/useWith.js b/server/node_modules/ramda/src/useWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..042829c732cf2aa49863d6c66dfb2f1bdd92b18c
--- /dev/null
+++ b/server/node_modules/ramda/src/useWith.js
@@ -0,0 +1,47 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var curryN = /*#__PURE__*/require('./curryN');
+
+/**
+ * Accepts a function `fn` and a list of transformer functions and returns a
+ * new curried function. When the new function is invoked, it calls the
+ * function `fn` with parameters consisting of the result of calling each
+ * supplied handler on successive arguments to the new function.
+ *
+ * If more arguments are passed to the returned function than transformer
+ * functions, those arguments are passed directly to `fn` as additional
+ * parameters. If you expect additional arguments that don't need to be
+ * transformed, although you can ignore them, it's best to pass an identity
+ * function so that the new function reports the correct arity.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Function
+ * @sig ((x1, x2, ...) -> z) -> [(a -> x1), (b -> x2), ...] -> (a -> b -> ... -> z)
+ * @param {Function} fn The function to wrap.
+ * @param {Array} transformers A list of transformer functions
+ * @return {Function} The wrapped function.
+ * @see R.converge
+ * @example
+ *
+ *      R.useWith(Math.pow, [R.identity, R.identity])(3, 4); //=> 81
+ *      R.useWith(Math.pow, [R.identity, R.identity])(3)(4); //=> 81
+ *      R.useWith(Math.pow, [R.dec, R.inc])(3, 4); //=> 32
+ *      R.useWith(Math.pow, [R.dec, R.inc])(3)(4); //=> 32
+ * @symb R.useWith(f, [g, h])(a, b) = f(g(a), h(b))
+ */
+
+
+var useWith = /*#__PURE__*/_curry2(function useWith(fn, transformers) {
+  return curryN(transformers.length, function () {
+    var args = [];
+    var idx = 0;
+    while (idx < transformers.length) {
+      args.push(transformers[idx].call(this, arguments[idx]));
+      idx += 1;
+    }
+    return fn.apply(this, args.concat(Array.prototype.slice.call(arguments, transformers.length)));
+  });
+});
+module.exports = useWith;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/values.js b/server/node_modules/ramda/src/values.js
new file mode 100644
index 0000000000000000000000000000000000000000..b32dba7d17103b957d92f86d1c32391f04768e9c
--- /dev/null
+++ b/server/node_modules/ramda/src/values.js
@@ -0,0 +1,35 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+var keys = /*#__PURE__*/require('./keys');
+
+/**
+ * Returns a list of all the enumerable own properties of the supplied object.
+ * Note that the order of the output array is not guaranteed across different
+ * JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category Object
+ * @sig {k: v} -> [v]
+ * @param {Object} obj The object to extract values from
+ * @return {Array} An array of the values of the object's own properties.
+ * @see R.valuesIn, R.keys
+ * @example
+ *
+ *      R.values({a: 1, b: 2, c: 3}); //=> [1, 2, 3]
+ */
+
+
+var values = /*#__PURE__*/_curry1(function values(obj) {
+  var props = keys(obj);
+  var len = props.length;
+  var vals = [];
+  var idx = 0;
+  while (idx < len) {
+    vals[idx] = obj[props[idx]];
+    idx += 1;
+  }
+  return vals;
+});
+module.exports = values;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/valuesIn.js b/server/node_modules/ramda/src/valuesIn.js
new file mode 100644
index 0000000000000000000000000000000000000000..ced66361734f5b62a9460e4f405f0c92dac7ffa6
--- /dev/null
+++ b/server/node_modules/ramda/src/valuesIn.js
@@ -0,0 +1,34 @@
+var _curry1 = /*#__PURE__*/require('./internal/_curry1');
+
+/**
+ * Returns a list of all the properties, including prototype properties, of the
+ * supplied object.
+ * Note that the order of the output array is not guaranteed to be consistent
+ * across different JS platforms.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.2.0
+ * @category Object
+ * @sig {k: v} -> [v]
+ * @param {Object} obj The object to extract values from
+ * @return {Array} An array of the values of the object's own and prototype properties.
+ * @see R.values, R.keysIn
+ * @example
+ *
+ *      const F = function() { this.x = 'X'; };
+ *      F.prototype.y = 'Y';
+ *      const f = new F();
+ *      R.valuesIn(f); //=> ['X', 'Y']
+ */
+
+
+var valuesIn = /*#__PURE__*/_curry1(function valuesIn(obj) {
+  var prop;
+  var vs = [];
+  for (prop in obj) {
+    vs[vs.length] = obj[prop];
+  }
+  return vs;
+});
+module.exports = valuesIn;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/view.js b/server/node_modules/ramda/src/view.js
new file mode 100644
index 0000000000000000000000000000000000000000..2cb33b82d08f9514b54263a025a4c2ef80ab8ddb
--- /dev/null
+++ b/server/node_modules/ramda/src/view.js
@@ -0,0 +1,38 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+// `Const` is a functor that effectively ignores the function given to `map`.
+
+
+var Const = function (x) {
+  return { value: x, 'fantasy-land/map': function () {
+      return this;
+    } };
+};
+
+/**
+ * Returns a "view" of the given data structure, determined by the given lens.
+ * The lens's focus determines which portion of the data structure is visible.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.16.0
+ * @category Object
+ * @typedefn Lens s a = Functor f => (a -> f a) -> s -> f s
+ * @sig Lens s a -> s -> a
+ * @param {Lens} lens
+ * @param {*} x
+ * @return {*}
+ * @see R.prop, R.lensIndex, R.lensProp
+ * @example
+ *
+ *      const xLens = R.lensProp('x');
+ *
+ *      R.view(xLens, {x: 1, y: 2});  //=> 1
+ *      R.view(xLens, {x: 4, y: 2});  //=> 4
+ */
+var view = /*#__PURE__*/_curry2(function view(lens, x) {
+  // Using `Const` effectively ignores the setter function of the `lens`,
+  // leaving the value returned by the getter function unmodified.
+  return lens(Const)(x).value;
+});
+module.exports = view;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/when.js b/server/node_modules/ramda/src/when.js
new file mode 100644
index 0000000000000000000000000000000000000000..9c674900dc084af0787b2faeeeb6360e192c08de
--- /dev/null
+++ b/server/node_modules/ramda/src/when.js
@@ -0,0 +1,36 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Tests the final argument by passing it to the given predicate function. If
+ * the predicate is satisfied, the function will return the result of calling
+ * the `whenTrueFn` function with the same argument. If the predicate is not
+ * satisfied, the argument is returned as is.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.18.0
+ * @category Logic
+ * @sig (a -> Boolean) -> (a -> a) -> a -> a
+ * @param {Function} pred       A predicate function
+ * @param {Function} whenTrueFn A function to invoke when the `condition`
+ *                              evaluates to a truthy value.
+ * @param {*}        x          An object to test with the `pred` function and
+ *                              pass to `whenTrueFn` if necessary.
+ * @return {*} Either `x` or the result of applying `x` to `whenTrueFn`.
+ * @see R.ifElse, R.unless, R.cond
+ * @example
+ *
+ *      // truncate :: String -> String
+ *      const truncate = R.when(
+ *        R.propSatisfies(R.gt(R.__, 10), 'length'),
+ *        R.pipe(R.take(10), R.append('…'), R.join(''))
+ *      );
+ *      truncate('12345');         //=> '12345'
+ *      truncate('0123456789ABC'); //=> '0123456789…'
+ */
+
+
+var when = /*#__PURE__*/_curry3(function when(pred, whenTrueFn, x) {
+  return pred(x) ? whenTrueFn(x) : x;
+});
+module.exports = when;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/where.js b/server/node_modules/ramda/src/where.js
new file mode 100644
index 0000000000000000000000000000000000000000..54fd7391d6385533149e67b669d7cbd1b7c23204
--- /dev/null
+++ b/server/node_modules/ramda/src/where.js
@@ -0,0 +1,50 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var _has = /*#__PURE__*/require('./internal/_has');
+
+/**
+ * Takes a spec object and a test object; returns true if the test satisfies
+ * the spec. Each of the spec's own properties must be a predicate function.
+ * Each predicate is applied to the value of the corresponding property of the
+ * test object. `where` returns true if all the predicates return true, false
+ * otherwise.
+ *
+ * `where` is well suited to declaratively expressing constraints for other
+ * functions such as [`filter`](#filter) and [`find`](#find).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.1
+ * @category Object
+ * @sig {String: (* -> Boolean)} -> {String: *} -> Boolean
+ * @param {Object} spec
+ * @param {Object} testObj
+ * @return {Boolean}
+ * @see R.propSatisfies, R.whereEq
+ * @example
+ *
+ *      // pred :: Object -> Boolean
+ *      const pred = R.where({
+ *        a: R.equals('foo'),
+ *        b: R.complement(R.equals('bar')),
+ *        x: R.gt(R.__, 10),
+ *        y: R.lt(R.__, 20)
+ *      });
+ *
+ *      pred({a: 'foo', b: 'xxx', x: 11, y: 19}); //=> true
+ *      pred({a: 'xxx', b: 'xxx', x: 11, y: 19}); //=> false
+ *      pred({a: 'foo', b: 'bar', x: 11, y: 19}); //=> false
+ *      pred({a: 'foo', b: 'xxx', x: 10, y: 19}); //=> false
+ *      pred({a: 'foo', b: 'xxx', x: 11, y: 20}); //=> false
+ */
+
+
+var where = /*#__PURE__*/_curry2(function where(spec, testObj) {
+  for (var prop in spec) {
+    if (_has(prop, spec) && !spec[prop](testObj[prop])) {
+      return false;
+    }
+  }
+  return true;
+});
+module.exports = where;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/whereEq.js b/server/node_modules/ramda/src/whereEq.js
new file mode 100644
index 0000000000000000000000000000000000000000..1fe4c78c9eb32cf0a90fdd3aa3a1b59e2144866f
--- /dev/null
+++ b/server/node_modules/ramda/src/whereEq.js
@@ -0,0 +1,42 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var equals = /*#__PURE__*/require('./equals');
+
+var map = /*#__PURE__*/require('./map');
+
+var where = /*#__PURE__*/require('./where');
+
+/**
+ * Takes a spec object and a test object; returns true if the test satisfies
+ * the spec, false otherwise. An object satisfies the spec if, for each of the
+ * spec's own properties, accessing that property of the object gives the same
+ * value (in [`R.equals`](#equals) terms) as accessing that property of the
+ * spec.
+ *
+ * `whereEq` is a specialization of [`where`](#where).
+ *
+ * @func
+ * @memberOf R
+ * @since v0.14.0
+ * @category Object
+ * @sig {String: *} -> {String: *} -> Boolean
+ * @param {Object} spec
+ * @param {Object} testObj
+ * @return {Boolean}
+ * @see R.propEq, R.where
+ * @example
+ *
+ *      // pred :: Object -> Boolean
+ *      const pred = R.whereEq({a: 1, b: 2});
+ *
+ *      pred({a: 1});              //=> false
+ *      pred({a: 1, b: 2});        //=> true
+ *      pred({a: 1, b: 2, c: 3});  //=> true
+ *      pred({a: 1, b: 1});        //=> false
+ */
+
+
+var whereEq = /*#__PURE__*/_curry2(function whereEq(spec, testObj) {
+  return where(map(equals, spec), testObj);
+});
+module.exports = whereEq;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/without.js b/server/node_modules/ramda/src/without.js
new file mode 100644
index 0000000000000000000000000000000000000000..dd23dcadb31343b57d0f0223d3968f1bf43330db
--- /dev/null
+++ b/server/node_modules/ramda/src/without.js
@@ -0,0 +1,33 @@
+var _includes = /*#__PURE__*/require('./internal/_includes');
+
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+var flip = /*#__PURE__*/require('./flip');
+
+var reject = /*#__PURE__*/require('./reject');
+
+/**
+ * Returns a new list without values in the first argument.
+ * [`R.equals`](#equals) is used to determine equality.
+ *
+ * Acts as a transducer if a transformer is given in list position.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.19.0
+ * @category List
+ * @sig [a] -> [a] -> [a]
+ * @param {Array} list1 The values to be removed from `list2`.
+ * @param {Array} list2 The array to remove values from.
+ * @return {Array} The new array without values in `list1`.
+ * @see R.transduce, R.difference, R.remove
+ * @example
+ *
+ *      R.without([1, 2], [1, 2, 1, 3, 4]); //=> [3, 4]
+ */
+
+
+var without = /*#__PURE__*/_curry2(function (xs, list) {
+  return reject(flip(_includes)(xs), list);
+});
+module.exports = without;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/xprod.js b/server/node_modules/ramda/src/xprod.js
new file mode 100644
index 0000000000000000000000000000000000000000..f6af9c5081556848d1c505ce274cdd8b82f647b8
--- /dev/null
+++ b/server/node_modules/ramda/src/xprod.js
@@ -0,0 +1,40 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Creates a new list out of the two supplied by creating each possible pair
+ * from the lists.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [b] -> [[a,b]]
+ * @param {Array} as The first list.
+ * @param {Array} bs The second list.
+ * @return {Array} The list made by combining each possible pair from
+ *         `as` and `bs` into pairs (`[a, b]`).
+ * @example
+ *
+ *      R.xprod([1, 2], ['a', 'b']); //=> [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
+ * @symb R.xprod([a, b], [c, d]) = [[a, c], [a, d], [b, c], [b, d]]
+ */
+
+
+var xprod = /*#__PURE__*/_curry2(function xprod(a, b) {
+  // = xprodWith(prepend); (takes about 3 times as long...)
+  var idx = 0;
+  var ilen = a.length;
+  var j;
+  var jlen = b.length;
+  var result = [];
+  while (idx < ilen) {
+    j = 0;
+    while (j < jlen) {
+      result[result.length] = [a[idx], b[j]];
+      j += 1;
+    }
+    idx += 1;
+  }
+  return result;
+});
+module.exports = xprod;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/zip.js b/server/node_modules/ramda/src/zip.js
new file mode 100644
index 0000000000000000000000000000000000000000..39df0ab2995e35b0cf09d833bc7936c0960df1b6
--- /dev/null
+++ b/server/node_modules/ramda/src/zip.js
@@ -0,0 +1,34 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Creates a new list out of the two supplied by pairing up equally-positioned
+ * items from both lists. The returned list is truncated to the length of the
+ * shorter of the two input lists.
+ * Note: `zip` is equivalent to `zipWith(function(a, b) { return [a, b] })`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig [a] -> [b] -> [[a,b]]
+ * @param {Array} list1 The first array to consider.
+ * @param {Array} list2 The second array to consider.
+ * @return {Array} The list made by pairing up same-indexed elements of `list1` and `list2`.
+ * @example
+ *
+ *      R.zip([1, 2, 3], ['a', 'b', 'c']); //=> [[1, 'a'], [2, 'b'], [3, 'c']]
+ * @symb R.zip([a, b, c], [d, e, f]) = [[a, d], [b, e], [c, f]]
+ */
+
+
+var zip = /*#__PURE__*/_curry2(function zip(a, b) {
+  var rv = [];
+  var idx = 0;
+  var len = Math.min(a.length, b.length);
+  while (idx < len) {
+    rv[idx] = [a[idx], b[idx]];
+    idx += 1;
+  }
+  return rv;
+});
+module.exports = zip;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/zipObj.js b/server/node_modules/ramda/src/zipObj.js
new file mode 100644
index 0000000000000000000000000000000000000000..0607980d1a6f8d9af79ece586b9d92c79df8450f
--- /dev/null
+++ b/server/node_modules/ramda/src/zipObj.js
@@ -0,0 +1,32 @@
+var _curry2 = /*#__PURE__*/require('./internal/_curry2');
+
+/**
+ * Creates a new object out of a list of keys and a list of values.
+ * Key/value pairing is truncated to the length of the shorter of the two lists.
+ * Note: `zipObj` is equivalent to `pipe(zip, fromPairs)`.
+ *
+ * @func
+ * @memberOf R
+ * @since v0.3.0
+ * @category List
+ * @sig [String] -> [*] -> {String: *}
+ * @param {Array} keys The array that will be properties on the output object.
+ * @param {Array} values The list of values on the output object.
+ * @return {Object} The object made by pairing up same-indexed elements of `keys` and `values`.
+ * @example
+ *
+ *      R.zipObj(['a', 'b', 'c'], [1, 2, 3]); //=> {a: 1, b: 2, c: 3}
+ */
+
+
+var zipObj = /*#__PURE__*/_curry2(function zipObj(keys, values) {
+  var idx = 0;
+  var len = Math.min(keys.length, values.length);
+  var out = {};
+  while (idx < len) {
+    out[keys[idx]] = values[idx];
+    idx += 1;
+  }
+  return out;
+});
+module.exports = zipObj;
\ No newline at end of file
diff --git a/server/node_modules/ramda/src/zipWith.js b/server/node_modules/ramda/src/zipWith.js
new file mode 100644
index 0000000000000000000000000000000000000000..d4c3576a9166a838090c275e5a7a4680d6da0524
--- /dev/null
+++ b/server/node_modules/ramda/src/zipWith.js
@@ -0,0 +1,39 @@
+var _curry3 = /*#__PURE__*/require('./internal/_curry3');
+
+/**
+ * Creates a new list out of the two supplied by applying the function to each
+ * equally-positioned pair in the lists. The returned list is truncated to the
+ * length of the shorter of the two input lists.
+ *
+ * @function
+ * @memberOf R
+ * @since v0.1.0
+ * @category List
+ * @sig ((a, b) -> c) -> [a] -> [b] -> [c]
+ * @param {Function} fn The function used to combine the two elements into one value.
+ * @param {Array} list1 The first array to consider.
+ * @param {Array} list2 The second array to consider.
+ * @return {Array} The list made by combining same-indexed elements of `list1` and `list2`
+ *         using `fn`.
+ * @example
+ *
+ *      const f = (x, y) => {
+ *        // ...
+ *      };
+ *      R.zipWith(f, [1, 2, 3], ['a', 'b', 'c']);
+ *      //=> [f(1, 'a'), f(2, 'b'), f(3, 'c')]
+ * @symb R.zipWith(fn, [a, b, c], [d, e, f]) = [fn(a, d), fn(b, e), fn(c, f)]
+ */
+
+
+var zipWith = /*#__PURE__*/_curry3(function zipWith(fn, a, b) {
+  var rv = [];
+  var idx = 0;
+  var len = Math.min(a.length, b.length);
+  while (idx < len) {
+    rv[idx] = fn(a[idx], b[idx]);
+    idx += 1;
+  }
+  return rv;
+});
+module.exports = zipWith;
\ No newline at end of file
diff --git a/server/node_modules/read-pkg-up/index.js b/server/node_modules/read-pkg-up/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..beb3d483245413c069064659d3353582e6faa847
--- /dev/null
+++ b/server/node_modules/read-pkg-up/index.js
@@ -0,0 +1,31 @@
+'use strict';
+var findUp = require('find-up');
+var readPkg = require('read-pkg');
+
+module.exports = function (opts) {
+	return findUp('package.json', opts).then(function (fp) {
+		if (!fp) {
+			return {};
+		}
+
+		return readPkg(fp, opts).then(function (pkg) {
+			return {
+				pkg: pkg,
+				path: fp
+			};
+		});
+	});
+};
+
+module.exports.sync = function (opts) {
+	var fp = findUp.sync('package.json', opts);
+
+	if (!fp) {
+		return {};
+	}
+
+	return {
+		pkg: readPkg.sync(fp, opts),
+		path: fp
+	};
+};
diff --git a/server/node_modules/read-pkg-up/license b/server/node_modules/read-pkg-up/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/read-pkg-up/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/read-pkg-up/package.json b/server/node_modules/read-pkg-up/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..c2c15cb09797d3b698f2354c745acc86eb579f7a
--- /dev/null
+++ b/server/node_modules/read-pkg-up/package.json
@@ -0,0 +1,91 @@
+{
+  "_from": "read-pkg-up@^1.0.1",
+  "_id": "read-pkg-up@1.0.1",
+  "_inBundle": false,
+  "_integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+  "_location": "/read-pkg-up",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "read-pkg-up@^1.0.1",
+    "name": "read-pkg-up",
+    "escapedName": "read-pkg-up",
+    "rawSpec": "^1.0.1",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.1"
+  },
+  "_requiredBy": [
+    "/yargs"
+  ],
+  "_resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+  "_shasum": "9d63c13276c065918d57f002a57f40a1b643fb02",
+  "_spec": "read-pkg-up@^1.0.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/read-pkg-up/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "find-up": "^1.0.0",
+    "read-pkg": "^1.0.0"
+  },
+  "deprecated": false,
+  "description": "Read the closest package.json file",
+  "devDependencies": {
+    "ava": "*",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/read-pkg-up#readme",
+  "keywords": [
+    "json",
+    "read",
+    "parse",
+    "file",
+    "fs",
+    "graceful",
+    "load",
+    "pkg",
+    "package",
+    "find",
+    "up",
+    "find-up",
+    "findup",
+    "look-up",
+    "look",
+    "file",
+    "search",
+    "match",
+    "package",
+    "resolve",
+    "parent",
+    "parents",
+    "folder",
+    "directory",
+    "dir",
+    "walk",
+    "walking",
+    "path"
+  ],
+  "license": "MIT",
+  "name": "read-pkg-up",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/read-pkg-up.git"
+  },
+  "scripts": {
+    "test": "xo && ava"
+  },
+  "version": "1.0.1"
+}
diff --git a/server/node_modules/read-pkg-up/readme.md b/server/node_modules/read-pkg-up/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..dbd88f3106806f060f8510fe814b4e3a9834c865
--- /dev/null
+++ b/server/node_modules/read-pkg-up/readme.md
@@ -0,0 +1,79 @@
+# read-pkg-up [![Build Status](https://travis-ci.org/sindresorhus/read-pkg-up.svg?branch=master)](https://travis-ci.org/sindresorhus/read-pkg-up)
+
+> Read the closest package.json file
+
+
+## Why
+
+- [Finds the closest package.json](https://github.com/sindresorhus/find-up)
+- [Gracefully handles filesystem issues](https://github.com/isaacs/node-graceful-fs)
+- [Strips UTF-8 BOM](https://github.com/sindresorhus/strip-bom)
+- [Throws more helpful JSON errors](https://github.com/sindresorhus/parse-json)
+- [Normalizes the data](https://github.com/npm/normalize-package-data#what-normalization-currently-entails)
+
+
+## Install
+
+```
+$ npm install --save read-pkg-up
+```
+
+
+## Usage
+
+```js
+var readPkgUp = require('read-pkg-up');
+
+readPkgUp().then(function (result) {
+	console.log(result);
+	/*
+	{
+		pkg: {
+			name: 'awesome-package',
+			version: '1.0.0',
+			...
+		},
+		path: '/Users/sindresorhus/dev/awesome-package'
+	}
+	*/
+});
+```
+
+
+## API
+
+### readPkgUp([options])
+
+Returns a promise that resolves to a result object.
+
+### readPkgUp.sync([options])
+
+Returns a result object.
+
+#### options
+
+##### cwd
+
+Type: `string`  
+Default: `.`
+
+Directory to start looking for a package.json file.
+
+##### normalize
+
+Type: `boolean`  
+Default: `true`
+
+[Normalize](https://github.com/npm/normalize-package-data#what-normalization-currently-entails) the package data.
+
+
+## Related
+
+- [read-pkg](https://github.com/sindresorhus/read-pkg) - Read a package.json file
+- [find-up](https://github.com/sindresorhus/find-up) - Find a file by walking up parent directories
+- [pkg-conf](https://github.com/sindresorhus/pkg-conf) - Get namespaced config from the closest package.json
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/read-pkg/index.js b/server/node_modules/read-pkg/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..c5c3afa8ed3b15eee4a1311a9d4d5d9b20461992
--- /dev/null
+++ b/server/node_modules/read-pkg/index.js
@@ -0,0 +1,48 @@
+'use strict';
+var path = require('path');
+var loadJsonFile = require('load-json-file');
+var normalizePackageData = require('normalize-package-data');
+var pathType = require('path-type');
+
+module.exports = function (fp, opts) {
+	if (typeof fp !== 'string') {
+		opts = fp;
+		fp = '.';
+	}
+
+	opts = opts || {};
+
+	return pathType.dir(fp)
+		.then(function (isDir) {
+			if (isDir) {
+				fp = path.join(fp, 'package.json');
+			}
+
+			return loadJsonFile(fp);
+		})
+		.then(function (x) {
+			if (opts.normalize !== false) {
+				normalizePackageData(x);
+			}
+
+			return x;
+		});
+};
+
+module.exports.sync = function (fp, opts) {
+	if (typeof fp !== 'string') {
+		opts = fp;
+		fp = '.';
+	}
+
+	opts = opts || {};
+	fp = pathType.dirSync(fp) ? path.join(fp, 'package.json') : fp;
+
+	var x = loadJsonFile.sync(fp);
+
+	if (opts.normalize !== false) {
+		normalizePackageData(x);
+	}
+
+	return x;
+};
diff --git a/server/node_modules/read-pkg/license b/server/node_modules/read-pkg/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/read-pkg/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/read-pkg/package.json b/server/node_modules/read-pkg/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..91a2c2ff4e0ec89f94b43ebd3dcc6a16b3e03b8d
--- /dev/null
+++ b/server/node_modules/read-pkg/package.json
@@ -0,0 +1,74 @@
+{
+  "_from": "read-pkg@^1.0.0",
+  "_id": "read-pkg@1.1.0",
+  "_inBundle": false,
+  "_integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+  "_location": "/read-pkg",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "read-pkg@^1.0.0",
+    "name": "read-pkg",
+    "escapedName": "read-pkg",
+    "rawSpec": "^1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.0"
+  },
+  "_requiredBy": [
+    "/read-pkg-up"
+  ],
+  "_resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+  "_shasum": "f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28",
+  "_spec": "read-pkg@^1.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/read-pkg-up",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/read-pkg/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "load-json-file": "^1.0.0",
+    "normalize-package-data": "^2.3.2",
+    "path-type": "^1.0.0"
+  },
+  "deprecated": false,
+  "description": "Read a package.json file",
+  "devDependencies": {
+    "ava": "*",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/read-pkg#readme",
+  "keywords": [
+    "json",
+    "read",
+    "parse",
+    "file",
+    "fs",
+    "graceful",
+    "load",
+    "pkg",
+    "package",
+    "normalize"
+  ],
+  "license": "MIT",
+  "name": "read-pkg",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/read-pkg.git"
+  },
+  "scripts": {
+    "test": "xo && ava"
+  },
+  "version": "1.1.0"
+}
diff --git a/server/node_modules/read-pkg/readme.md b/server/node_modules/read-pkg/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..9a0d4cc45d984e7ac1641eb6b123b70371ebdc27
--- /dev/null
+++ b/server/node_modules/read-pkg/readme.md
@@ -0,0 +1,79 @@
+# read-pkg [![Build Status](https://travis-ci.org/sindresorhus/read-pkg.svg?branch=master)](https://travis-ci.org/sindresorhus/read-pkg)
+
+> Read a package.json file
+
+
+## Why
+
+- [Gracefully handles filesystem issues](https://github.com/isaacs/node-graceful-fs)
+- [Strips UTF-8 BOM](https://github.com/sindresorhus/strip-bom)
+- [Throws more helpful JSON errors](https://github.com/sindresorhus/parse-json)
+- [Normalizes the data](https://github.com/npm/normalize-package-data#what-normalization-currently-entails)
+
+
+## Install
+
+```
+$ npm install --save read-pkg
+```
+
+
+## Usage
+
+```js
+var readPkg = require('read-pkg');
+
+readPkg().then(function (pkg) {
+	console.log(pkg);
+	//=> {name: 'read-pkg', ...}
+});
+
+readPkg(__dirname).then(function (pkg) {
+	console.log(pkg);
+	//=> {name: 'read-pkg', ...}
+});
+
+readPkg(path.join('unicorn', 'package.json')).then(function (pkg) {
+	console.log(pkg);
+	//=> {name: 'read-pkg', ...}
+});
+```
+
+
+## API
+
+### readPkg([path], [options])
+
+Returns a promise that resolves to the parsed JSON.
+
+### readPkg.sync([path], [options])
+
+Returns the parsed JSON.
+
+#### path
+
+Type: `string`  
+Default: `.`
+
+Path to a `package.json` file or its directory.
+
+#### options
+
+##### normalize
+
+Type: `boolean`  
+Default: `true`
+
+[Normalize](https://github.com/npm/normalize-package-data#what-normalization-currently-entails) the package data.
+
+
+## Related
+
+- [read-pkg-up](https://github.com/sindresorhus/read-pkg-up) - Read the closest package.json file
+- [write-pkg](https://github.com/sindresorhus/write-pkg) - Write a `package.json` file
+- [load-json-file](https://github.com/sindresorhus/load-json-file) - Read and parse a JSON file
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/require-directory/.jshintrc b/server/node_modules/require-directory/.jshintrc
new file mode 100644
index 0000000000000000000000000000000000000000..e14e4dcbd2975e090c4530273bd94c0a6c7f0ea8
--- /dev/null
+++ b/server/node_modules/require-directory/.jshintrc
@@ -0,0 +1,67 @@
+{
+    "maxerr"        : 50,
+    "bitwise"       : true,
+    "camelcase"     : true,
+    "curly"         : true,
+    "eqeqeq"        : true,
+    "forin"         : true,
+    "immed"         : true,
+    "indent"        : 2,
+    "latedef"       : true,
+    "newcap"        : true,
+    "noarg"         : true,
+    "noempty"       : true,
+    "nonew"         : true,
+    "plusplus"      : true,
+    "quotmark"      : true,
+    "undef"         : true,
+    "unused"        : true,
+    "strict"        : true,
+    "trailing"      : true,
+    "maxparams"     : false,
+    "maxdepth"      : false,
+    "maxstatements" : false,
+    "maxcomplexity" : false,
+    "maxlen"        : false,
+    "asi"           : false,
+    "boss"          : false,
+    "debug"         : false,
+    "eqnull"        : true,
+    "es5"           : false,
+    "esnext"        : false,
+    "moz"           : false,
+    "evil"          : false,
+    "expr"          : true,
+    "funcscope"     : true,
+    "globalstrict"  : true,
+    "iterator"      : true,
+    "lastsemic"     : false,
+    "laxbreak"      : false,
+    "laxcomma"      : false,
+    "loopfunc"      : false,
+    "multistr"      : false,
+    "proto"         : false,
+    "scripturl"     : false,
+    "smarttabs"     : false,
+    "shadow"        : false,
+    "sub"           : false,
+    "supernew"      : false,
+    "validthis"     : false,
+    "browser"       : true,
+    "couch"         : false,
+    "devel"         : true,
+    "dojo"          : false,
+    "jquery"        : false,
+    "mootools"      : false,
+    "node"          : true,
+    "nonstandard"   : false,
+    "prototypejs"   : false,
+    "rhino"         : false,
+    "worker"        : false,
+    "wsh"           : false,
+    "yui"           : false,
+    "nomen"         : true,
+    "onevar"        : true,
+    "passfail"      : false,
+    "white"         : true
+}
diff --git a/server/node_modules/require-directory/.npmignore b/server/node_modules/require-directory/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..47cf365a0785e36c20eb55314ee0c06016fea193
--- /dev/null
+++ b/server/node_modules/require-directory/.npmignore
@@ -0,0 +1 @@
+test/**
diff --git a/server/node_modules/require-directory/.travis.yml b/server/node_modules/require-directory/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..20fd86b6a5bee335c75b4efea34312ff7f3a039e
--- /dev/null
+++ b/server/node_modules/require-directory/.travis.yml
@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+  - 0.10
diff --git a/server/node_modules/require-directory/LICENSE b/server/node_modules/require-directory/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..a70f253aa4b5c79aa850d0848e34c83f6681d3e9
--- /dev/null
+++ b/server/node_modules/require-directory/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2011 Troy Goode <troygoode@gmail.com>
+
+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.
diff --git a/server/node_modules/require-directory/README.markdown b/server/node_modules/require-directory/README.markdown
new file mode 100644
index 0000000000000000000000000000000000000000..926a063ed1f8973ae7fc7888b2769fce1d6e072d
--- /dev/null
+++ b/server/node_modules/require-directory/README.markdown
@@ -0,0 +1,184 @@
+# require-directory
+
+Recursively iterates over specified directory, `require()`'ing each file, and returning a nested hash structure containing those modules.
+
+**[Follow me (@troygoode) on Twitter!](https://twitter.com/intent/user?screen_name=troygoode)**
+
+[![NPM](https://nodei.co/npm/require-directory.png?downloads=true&stars=true)](https://nodei.co/npm/require-directory/)
+
+[![build status](https://secure.travis-ci.org/troygoode/node-require-directory.png)](http://travis-ci.org/troygoode/node-require-directory)
+
+## How To Use
+
+### Installation (via [npm](https://npmjs.org/package/require-directory))
+
+```bash
+$ npm install require-directory
+```
+
+### Usage
+
+A common pattern in node.js is to include an index file which creates a hash of the files in its current directory. Given a directory structure like so:
+
+* app.js
+* routes/
+  * index.js
+  * home.js
+  * auth/
+    * login.js
+    * logout.js
+    * register.js
+
+`routes/index.js` uses `require-directory` to build the hash (rather than doing so manually) like so:
+
+```javascript
+var requireDirectory = require('require-directory');
+module.exports = requireDirectory(module);
+```
+
+`app.js` references `routes/index.js` like any other module, but it now has a hash/tree of the exports from the `./routes/` directory:
+
+```javascript
+var routes = require('./routes');
+
+// snip
+
+app.get('/', routes.home);
+app.get('/register', routes.auth.register);
+app.get('/login', routes.auth.login);
+app.get('/logout', routes.auth.logout);
+```
+
+The `routes` variable above is the equivalent of this:
+
+```javascript
+var routes = {
+  home: require('routes/home.js'),
+  auth: {
+    login: require('routes/auth/login.js'),
+    logout: require('routes/auth/logout.js'),
+    register: require('routes/auth/register.js')
+  }
+};
+```
+
+*Note that `routes.index` will be `undefined` as you would hope.*
+
+### Specifying Another Directory
+
+You can specify which directory you want to build a tree of (if it isn't the current directory for whatever reason) by passing it as the second parameter. Not specifying the path (`requireDirectory(module)`) is the equivelant of `requireDirectory(module, __dirname)`:
+
+```javascript
+var requireDirectory = require('require-directory');
+module.exports = requireDirectory(module, './some/subdirectory');
+```
+
+For example, in the [example in the Usage section](#usage) we could have avoided creating `routes/index.js` and instead changed the first lines of `app.js` to:
+
+```javascript
+var requireDirectory = require('require-directory');
+var routes = requireDirectory(module, './routes');
+```
+
+## Options
+
+You can pass an options hash to `require-directory` as the 2nd parameter (or 3rd if you're passing the path to another directory as the 2nd parameter already). Here are the available options:
+
+### Whitelisting
+
+Whitelisting (either via RegExp or function) allows you to specify that only certain files be loaded.
+
+```javascript
+var requireDirectory = require('require-directory'),
+  whitelist = /onlyinclude.js$/,
+  hash = requireDirectory(module, {include: whitelist});
+```
+
+```javascript
+var requireDirectory = require('require-directory'),
+  check = function(path){
+    if(/onlyinclude.js$/.test(path)){
+      return true; // don't include
+    }else{
+      return false; // go ahead and include
+    }
+  },
+  hash = requireDirectory(module, {include: check});
+```
+
+### Blacklisting
+
+Blacklisting (either via RegExp or function) allows you to specify that all but certain files should be loaded.
+
+```javascript
+var requireDirectory = require('require-directory'),
+  blacklist = /dontinclude\.js$/,
+  hash = requireDirectory(module, {exclude: blacklist});
+```
+
+```javascript
+var requireDirectory = require('require-directory'),
+  check = function(path){
+    if(/dontinclude\.js$/.test(path)){
+      return false; // don't include
+    }else{
+      return true; // go ahead and include
+    }
+  },
+  hash = requireDirectory(module, {exclude: check});
+```
+
+### Visiting Objects As They're Loaded
+
+`require-directory` takes a function as the `visit` option that will be called for each module that is added to module.exports.
+
+```javascript
+var requireDirectory = require('require-directory'),
+  visitor = function(obj) {
+    console.log(obj); // will be called for every module that is loaded
+  },
+  hash = requireDirectory(module, {visit: visitor});
+```
+
+The visitor can also transform the objects by returning a value:
+
+```javascript
+var requireDirectory = require('require-directory'),
+  visitor = function(obj) {
+    return obj(new Date());
+  },
+  hash = requireDirectory(module, {visit: visitor});
+```
+
+### Renaming Keys
+
+```javascript
+var requireDirectory = require('require-directory'),
+  renamer = function(name) {
+    return name.toUpperCase();
+  },
+  hash = requireDirectory(module, {rename: renamer});
+```
+
+### No Recursion
+
+```javascript
+var requireDirectory = require('require-directory'),
+  hash = requireDirectory(module, {recurse: false});
+```
+
+## Run Unit Tests
+
+```bash
+$ npm run lint
+$ npm test
+```
+
+## License
+
+[MIT License](http://www.opensource.org/licenses/mit-license.php)
+
+## Author
+
+[Troy Goode](https://github.com/TroyGoode) ([troygoode@gmail.com](mailto:troygoode@gmail.com))
+
diff --git a/server/node_modules/require-directory/index.js b/server/node_modules/require-directory/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..cd37da7ea87094123af77bdd3a7ecc4595bf3388
--- /dev/null
+++ b/server/node_modules/require-directory/index.js
@@ -0,0 +1,86 @@
+'use strict';
+
+var fs = require('fs'),
+  join = require('path').join,
+  resolve = require('path').resolve,
+  dirname = require('path').dirname,
+  defaultOptions = {
+    extensions: ['js', 'json', 'coffee'],
+    recurse: true,
+    rename: function (name) {
+      return name;
+    },
+    visit: function (obj) {
+      return obj;
+    }
+  };
+
+function checkFileInclusion(path, filename, options) {
+  return (
+    // verify file has valid extension
+    (new RegExp('\\.(' + options.extensions.join('|') + ')$', 'i').test(filename)) &&
+
+    // if options.include is a RegExp, evaluate it and make sure the path passes
+    !(options.include && options.include instanceof RegExp && !options.include.test(path)) &&
+
+    // if options.include is a function, evaluate it and make sure the path passes
+    !(options.include && typeof options.include === 'function' && !options.include(path, filename)) &&
+
+    // if options.exclude is a RegExp, evaluate it and make sure the path doesn't pass
+    !(options.exclude && options.exclude instanceof RegExp && options.exclude.test(path)) &&
+
+    // if options.exclude is a function, evaluate it and make sure the path doesn't pass
+    !(options.exclude && typeof options.exclude === 'function' && options.exclude(path, filename))
+  );
+}
+
+function requireDirectory(m, path, options) {
+  var retval = {};
+
+  // path is optional
+  if (path && !options && typeof path !== 'string') {
+    options = path;
+    path = null;
+  }
+
+  // default options
+  options = options || {};
+  for (var prop in defaultOptions) {
+    if (typeof options[prop] === 'undefined') {
+      options[prop] = defaultOptions[prop];
+    }
+  }
+
+  // if no path was passed in, assume the equivelant of __dirname from caller
+  // otherwise, resolve path relative to the equivalent of __dirname
+  path = !path ? dirname(m.filename) : resolve(dirname(m.filename), path);
+
+  // get the path of each file in specified directory, append to current tree node, recurse
+  fs.readdirSync(path).forEach(function (filename) {
+    var joined = join(path, filename),
+      files,
+      key,
+      obj;
+
+    if (fs.statSync(joined).isDirectory() && options.recurse) {
+      // this node is a directory; recurse
+      files = requireDirectory(m, joined, options);
+      // exclude empty directories
+      if (Object.keys(files).length) {
+        retval[options.rename(filename, joined, filename)] = files;
+      }
+    } else {
+      if (joined !== m.filename && checkFileInclusion(joined, filename, options)) {
+        // hash node key shouldn't include file extension
+        key = filename.substring(0, filename.lastIndexOf('.'));
+        obj = m.require(joined);
+        retval[options.rename(key, joined, filename)] = options.visit(obj, joined, filename) || obj;
+      }
+    }
+  });
+
+  return retval;
+}
+
+module.exports = requireDirectory;
+module.exports.defaults = defaultOptions;
diff --git a/server/node_modules/require-directory/package.json b/server/node_modules/require-directory/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..d0131e13c647ad17c72c6d0a16b6588c1f78ae2a
--- /dev/null
+++ b/server/node_modules/require-directory/package.json
@@ -0,0 +1,69 @@
+{
+  "_from": "require-directory@^2.1.1",
+  "_id": "require-directory@2.1.1",
+  "_inBundle": false,
+  "_integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+  "_location": "/require-directory",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "require-directory@^2.1.1",
+    "name": "require-directory",
+    "escapedName": "require-directory",
+    "rawSpec": "^2.1.1",
+    "saveSpec": null,
+    "fetchSpec": "^2.1.1"
+  },
+  "_requiredBy": [
+    "/yargs"
+  ],
+  "_resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+  "_shasum": "8c64ad5fd30dab1c976e2344ffe7f792a6a6df42",
+  "_spec": "require-directory@^2.1.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "Troy Goode",
+    "email": "troygoode@gmail.com",
+    "url": "http://github.com/troygoode/"
+  },
+  "bugs": {
+    "url": "http://github.com/troygoode/node-require-directory/issues/"
+  },
+  "bundleDependencies": false,
+  "contributors": [
+    {
+      "name": "Troy Goode",
+      "email": "troygoode@gmail.com",
+      "url": "http://github.com/troygoode/"
+    }
+  ],
+  "deprecated": false,
+  "description": "Recursively iterates over specified directory, require()'ing each file, and returning a nested hash structure containing those modules.",
+  "devDependencies": {
+    "jshint": "^2.6.0",
+    "mocha": "^2.1.0"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "homepage": "https://github.com/troygoode/node-require-directory/",
+  "keywords": [
+    "require",
+    "directory",
+    "library",
+    "recursive"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "require-directory",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/troygoode/node-require-directory.git"
+  },
+  "scripts": {
+    "lint": "jshint index.js test/test.js",
+    "test": "mocha"
+  },
+  "version": "2.1.1"
+}
diff --git a/server/node_modules/require-main-filename/.npmignore b/server/node_modules/require-main-filename/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..6f9fe6badf97deba08bbdf39e081717f7f09f94f
--- /dev/null
+++ b/server/node_modules/require-main-filename/.npmignore
@@ -0,0 +1,3 @@
+node_modules
+.DS_Store
+.nyc_output
diff --git a/server/node_modules/require-main-filename/.travis.yml b/server/node_modules/require-main-filename/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ab61ce77ebe3daf1e44748355122251c080cad4d
--- /dev/null
+++ b/server/node_modules/require-main-filename/.travis.yml
@@ -0,0 +1,8 @@
+language: node_js
+os:
+  - linux
+node_js:
+  - "0.10"
+  - "0.12"
+  - "4.1"
+  - "node"
diff --git a/server/node_modules/require-main-filename/LICENSE.txt b/server/node_modules/require-main-filename/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..836440bef7cf14841c05b0f8635e580c91327fc4
--- /dev/null
+++ b/server/node_modules/require-main-filename/LICENSE.txt
@@ -0,0 +1,14 @@
+Copyright (c) 2016, Contributors
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice
+appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
+LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/server/node_modules/require-main-filename/README.md b/server/node_modules/require-main-filename/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..820d9f58959cdc8b81b2113061d6282c1ed5cd6d
--- /dev/null
+++ b/server/node_modules/require-main-filename/README.md
@@ -0,0 +1,26 @@
+# require-main-filename
+
+[![Build Status](https://travis-ci.org/yargs/require-main-filename.png)](https://travis-ci.org/yargs/require-main-filename)
+[![Coverage Status](https://coveralls.io/repos/yargs/require-main-filename/badge.svg?branch=master)](https://coveralls.io/r/yargs/require-main-filename?branch=master)
+[![NPM version](https://img.shields.io/npm/v/require-main-filename.svg)](https://www.npmjs.com/package/require-main-filename)
+
+`require.main.filename` is great for figuring out the entry
+point for the current application. This can be combined with a module like
+[pkg-conf](https://www.npmjs.com/package/pkg-conf) to, _as if by magic_, load
+top-level configuration.
+
+Unfortunately, `require.main.filename` sometimes fails when an application is
+executed with an alternative process manager, e.g., [iisnode](https://github.com/tjanczuk/iisnode).
+
+`require-main-filename` is a shim that addresses this problem.
+
+## Usage
+
+```js
+var main = require('require-main-filename')()
+// use main as an alternative to require.main.filename.
+```
+
+## License
+
+ISC
diff --git a/server/node_modules/require-main-filename/index.js b/server/node_modules/require-main-filename/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..dca7f0cc1e39468fb80a1874cda3484f61609119
--- /dev/null
+++ b/server/node_modules/require-main-filename/index.js
@@ -0,0 +1,18 @@
+module.exports = function (_require) {
+  _require = _require || require
+  var main = _require.main
+  if (main && isIISNode(main)) return handleIISNode(main)
+  else return main ? main.filename : process.cwd()
+}
+
+function isIISNode (main) {
+  return /\\iisnode\\/.test(main.filename)
+}
+
+function handleIISNode (main) {
+  if (!main.children.length) {
+    return main.filename
+  } else {
+    return main.children[0].filename
+  }
+}
diff --git a/server/node_modules/require-main-filename/package.json b/server/node_modules/require-main-filename/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..e1b60292b9366f21357abd62b80aa01b70d239d6
--- /dev/null
+++ b/server/node_modules/require-main-filename/package.json
@@ -0,0 +1,58 @@
+{
+  "_from": "require-main-filename@^1.0.1",
+  "_id": "require-main-filename@1.0.1",
+  "_inBundle": false,
+  "_integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+  "_location": "/require-main-filename",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "require-main-filename@^1.0.1",
+    "name": "require-main-filename",
+    "escapedName": "require-main-filename",
+    "rawSpec": "^1.0.1",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.1"
+  },
+  "_requiredBy": [
+    "/yargs"
+  ],
+  "_resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+  "_shasum": "97f717b69d48784f5f526a6c5aa8ffdda055a4d1",
+  "_spec": "require-main-filename@^1.0.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "Ben Coe",
+    "email": "ben@npmjs.com"
+  },
+  "bugs": {
+    "url": "https://github.com/yargs/require-main-filename/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "shim for require.main.filename() that works in as many environments as possible",
+  "devDependencies": {
+    "chai": "^3.5.0",
+    "standard": "^6.0.5",
+    "tap": "^5.2.0"
+  },
+  "homepage": "https://github.com/yargs/require-main-filename#readme",
+  "keywords": [
+    "require",
+    "shim",
+    "iisnode"
+  ],
+  "license": "ISC",
+  "main": "index.js",
+  "name": "require-main-filename",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/yargs/require-main-filename.git"
+  },
+  "scripts": {
+    "pretest": "standard",
+    "test": "tap --coverage test.js"
+  },
+  "version": "1.0.1"
+}
diff --git a/server/node_modules/require-main-filename/test.js b/server/node_modules/require-main-filename/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..d89e7dcbaf03d1b84bbbf7196ffa326d18ab7a9c
--- /dev/null
+++ b/server/node_modules/require-main-filename/test.js
@@ -0,0 +1,36 @@
+/* global describe, it */
+
+var requireMainFilename = require('./')
+
+require('tap').mochaGlobals()
+require('chai').should()
+
+describe('require-main-filename', function () {
+  it('returns require.main.filename in normal circumstances', function () {
+    requireMainFilename().should.match(/test\.js/)
+  })
+
+  it('should use children[0].filename when running on iisnode', function () {
+    var main = {
+      filename: 'D:\\Program Files (x86)\\iisnode\\interceptor.js',
+      children: [ {filename: 'D:\\home\\site\\wwwroot\\server.js'} ]
+    }
+    requireMainFilename({
+      main: main
+    }).should.match(/server\.js/)
+  })
+
+  it('should not use children[0] if no children exist', function () {
+    var main = {
+      filename: 'D:\\Program Files (x86)\\iisnode\\interceptor.js',
+      children: []
+    }
+    requireMainFilename({
+      main: main
+    }).should.match(/interceptor\.js/)
+  })
+
+  it('should default to process.cwd() if require.main is undefined', function () {
+    requireMainFilename({}).should.match(/require-main-filename/)
+  })
+})
diff --git a/server/node_modules/resolve/.editorconfig b/server/node_modules/resolve/.editorconfig
new file mode 100644
index 0000000000000000000000000000000000000000..bc228f8269443bf772b437890dde7756a3e8a894
--- /dev/null
+++ b/server/node_modules/resolve/.editorconfig
@@ -0,0 +1,20 @@
+root = true
+
+[*]
+indent_style = tab
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+max_line_length = 150
+
+[CHANGELOG.md]
+indent_style = space
+indent_size = 2
+
+[*.json]
+max_line_length = off
+
+[Makefile]
+max_line_length = off
diff --git a/server/node_modules/resolve/.eslintignore b/server/node_modules/resolve/.eslintignore
new file mode 100644
index 0000000000000000000000000000000000000000..3c3629e647f5ddf82548912e337bea9826b434af
--- /dev/null
+++ b/server/node_modules/resolve/.eslintignore
@@ -0,0 +1 @@
+node_modules
diff --git a/server/node_modules/resolve/.eslintrc b/server/node_modules/resolve/.eslintrc
new file mode 100644
index 0000000000000000000000000000000000000000..a22863c8cbf01bd7715800739835d785b9bc95c5
--- /dev/null
+++ b/server/node_modules/resolve/.eslintrc
@@ -0,0 +1,39 @@
+{
+    "extends": "@ljharb",
+    "root": true,
+    "rules": {
+        "array-bracket-newline": 0,
+        "array-element-newline": 0,
+        "indent": [2, 4],
+        "strict": 0,
+        "complexity": 0,
+        "consistent-return": 0,
+        "curly": 0,
+        "dot-notation": [2, { "allowKeywords": true }],
+        "func-name-matching": 0,
+        "func-style": 0,
+        "global-require": 0,
+        "id-length": [2, { "min": 1, "max": 30 }],
+        "max-lines-per-function": 0,
+        "max-nested-callbacks": 0,
+        "max-params": 0,
+        "max-statements-per-line": [2, { "max": 2 }],
+        "max-statements": 0,
+        "no-magic-numbers": 0,
+        "no-console": 0,
+        "no-shadow": 0,
+        "no-unused-vars": [2, { "vars": "all", "args": "none" }],
+        "no-use-before-define": 0,
+        "object-curly-newline": 0,
+        "operator-linebreak": [2, "before"],
+        "sort-keys": 0,
+    },
+    "overrides": [
+        {
+            "files": "test/resolver/nested_symlinks/mylib/*.js",
+            "rules": {
+                "no-throw-literal": 0,
+            },
+        },
+    ],
+}
diff --git a/server/node_modules/resolve/.travis.yml b/server/node_modules/resolve/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c3ab9abef860fe70cb2c56ef72c3fa6ee08b98ae
--- /dev/null
+++ b/server/node_modules/resolve/.travis.yml
@@ -0,0 +1,308 @@
+language: node_js
+os:
+ - linux
+node_js:
+  - "12.7"
+  - "11.15"
+  - "10.16"
+  - "9.11"
+  - "8.16"
+  - "7.10"
+  - "6.17"
+  - "5.12"
+  - "4.9"
+  - "iojs-v3.3"
+  - "iojs-v2.5"
+  - "iojs-v1.8"
+  - "0.12"
+  - "0.10"
+  - "0.8"
+  - "0.6"
+before_install:
+  - 'case "${TRAVIS_NODE_VERSION}" in 0.*) export NPM_CONFIG_STRICT_SSL=false ;; esac'
+  - 'nvm install-latest-npm'
+install:
+  - 'if [ "${TRAVIS_NODE_VERSION}" = "0.6" ] || [ "${TRAVIS_NODE_VERSION}" = "0.9" ]; then nvm install --latest-npm 0.8 && npm install && nvm use "${TRAVIS_NODE_VERSION}"; else npm install; fi;'
+script:
+  - 'if [ -n "${PRETEST-}" ]; then npm run pretest ; fi'
+  - 'if [ -n "${POSTTEST-}" ]; then npm run posttest ; fi'
+  - 'if [ -n "${COVERAGE-}" ]; then npm run coverage ; fi'
+  - 'if [ -n "${TEST-}" ]; then npm run tests-only ; fi'
+sudo: false
+env:
+  - TEST=true
+matrix:
+  fast_finish: true
+  include:
+    - node_js: "lts/*"
+      env: PRETEST=true
+    - node_js: "lts/*"
+      env: POSTTEST=true
+    - node_js: "12.6"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "12.5"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "12.4"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "12.3"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "12.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "12.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "12.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.14"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.13"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.12"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.11"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.10"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.9"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.8"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.7"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.6"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.5"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.4"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.3"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "11.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.15"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.14"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.13"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.12"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.11"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.10"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.9"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.8"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.7"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.6"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.5"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.4"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.3"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "10.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "9.10"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "9.9"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "9.8"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "9.7"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "9.6"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "9.5"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "9.4"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "9.3"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "9.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "9.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "9.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.15"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.14"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.13"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.12"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.11"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.10"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.9"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.8"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.7"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.6"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.5"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.4"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.3"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "8.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "7.9"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "7.8"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "7.7"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "7.6"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "7.5"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "7.4"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "7.3"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "7.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "7.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "7.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.16"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.15"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.14"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.13"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.12"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.11"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.10"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.9"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.8"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.7"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.6"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.5"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.4"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.3"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "6.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.11"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.10"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.9"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.8"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.7"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.6"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.5"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.4"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.3"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "5.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "4.8"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "4.7"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "4.6"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "4.5"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "4.4"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "4.3"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "4.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "4.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "4.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v3.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v3.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v3.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v2.4"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v2.3"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v2.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v2.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v2.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v1.7"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v1.6"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v1.5"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v1.4"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v1.3"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v1.2"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v1.1"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "iojs-v1.0"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "0.11"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "0.9"
+      env: TEST=true ALLOW_FAILURE=true
+    - node_js: "0.4"
+      env: TEST=true ALLOW_FAILURE=true
+  allow_failures:
+    - os: osx
+    - env: TEST=true ALLOW_FAILURE=true
+    - node_js: "0.6"
diff --git a/server/node_modules/resolve/LICENSE b/server/node_modules/resolve/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..ff4fce28af33a4504d6960856a0bd603860a62e0
--- /dev/null
+++ b/server/node_modules/resolve/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2012 James Halliday
+
+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.
diff --git a/server/node_modules/resolve/appveyor.yml b/server/node_modules/resolve/appveyor.yml
new file mode 100644
index 0000000000000000000000000000000000000000..729e8ea0680a0a26dff7fb4030875aea1b4643be
--- /dev/null
+++ b/server/node_modules/resolve/appveyor.yml
@@ -0,0 +1,53 @@
+version: 1.0.{build}
+skip_branch_with_pr: true
+build: off
+
+environment:
+  matrix:
+    - nodejs_version: "12"
+    - nodejs_version: "11"
+    - nodejs_version: "10"
+    - nodejs_version: "9"
+    - nodejs_version: "8"
+    - nodejs_version: "7"
+    - nodejs_version: "6"
+    - nodejs_version: "5"
+    - nodejs_version: "4"
+    - nodejs_version: "3"
+    - nodejs_version: "2"
+    - nodejs_version: "1"
+    - nodejs_version: "0.12"
+    - nodejs_version: "0.10"
+    - nodejs_version: "0.8"
+    - nodejs_version: "0.6"
+matrix:
+  # fast_finish: true
+  allow_failures:
+    - nodejs_version: "0.8"
+    - nodejs_version: "0.6"
+
+platform:
+  - x86
+  - x64
+
+# Install scripts. (runs after repo cloning)
+install:
+ # Fix symlinks in working copy (see https://github.com/appveyor/ci/issues/650#issuecomment-186592582) / https://github.com/charleskorn/batect/commit/d08986802ec43086902958c4ee7e57ff3e71dbef
+ - git config core.symlinks true
+ - git reset --hard
+ # Get the latest stable version of Node.js or io.js
+ - ps: Install-Product node $env:nodejs_version $env:platform
+ - IF %nodejs_version% EQU 0.6 npm config set strict-ssl false && npm -g install npm@1.3
+ - IF %nodejs_version% EQU 0.8 npm config set strict-ssl false && npm -g install npm@1.4.28 && npm install -g npm@4.5
+ - set PATH=%APPDATA%\npm;%PATH%
+ #- IF %nodejs_version% NEQ 0.6 AND %nodejs_version% NEQ 0.8 npm -g install npm
+ # install modules
+ - npm install
+
+# Post-install test scripts.
+test_script:
+ # Output useful info for debugging.
+ - node --version
+ - npm --version
+ # run tests
+ - npm run tests-only
diff --git a/server/node_modules/resolve/example/async.js b/server/node_modules/resolve/example/async.js
new file mode 100644
index 0000000000000000000000000000000000000000..20e65dc281dbaa3947a1c5d1b1a0bc94167c2073
--- /dev/null
+++ b/server/node_modules/resolve/example/async.js
@@ -0,0 +1,5 @@
+var resolve = require('../');
+resolve('tap', { basedir: __dirname }, function (err, res) {
+    if (err) console.error(err);
+    else console.log(res);
+});
diff --git a/server/node_modules/resolve/example/sync.js b/server/node_modules/resolve/example/sync.js
new file mode 100644
index 0000000000000000000000000000000000000000..54b2cc1004223d114e38bbd46fe9a0f5b73ca7e2
--- /dev/null
+++ b/server/node_modules/resolve/example/sync.js
@@ -0,0 +1,3 @@
+var resolve = require('../');
+var res = resolve.sync('tap', { basedir: __dirname });
+console.log(res);
diff --git a/server/node_modules/resolve/index.js b/server/node_modules/resolve/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..eb6ba89e6c210c4e20436cc6f94b8ca88c6e5da3
--- /dev/null
+++ b/server/node_modules/resolve/index.js
@@ -0,0 +1,8 @@
+var core = require('./lib/core');
+var async = require('./lib/async');
+async.core = core;
+async.isCore = function isCore(x) { return core[x]; };
+async.sync = require('./lib/sync');
+
+exports = async;
+module.exports = async;
diff --git a/server/node_modules/resolve/lib/async.js b/server/node_modules/resolve/lib/async.js
new file mode 100644
index 0000000000000000000000000000000000000000..004b2798baf0c20bd239b97b2a1aaea2b90a3a5f
--- /dev/null
+++ b/server/node_modules/resolve/lib/async.js
@@ -0,0 +1,271 @@
+var core = require('./core');
+var fs = require('fs');
+var path = require('path');
+var caller = require('./caller.js');
+var nodeModulesPaths = require('./node-modules-paths.js');
+var normalizeOptions = require('./normalize-options.js');
+
+var defaultIsFile = function isFile(file, cb) {
+    fs.stat(file, function (err, stat) {
+        if (!err) {
+            return cb(null, stat.isFile() || stat.isFIFO());
+        }
+        if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false);
+        return cb(err);
+    });
+};
+
+var defaultIsDir = function isDirectory(dir, cb) {
+    fs.stat(dir, function (err, stat) {
+        if (!err) {
+            return cb(null, stat.isDirectory());
+        }
+        if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false);
+        return cb(err);
+    });
+};
+
+var maybeUnwrapSymlink = function maybeUnwrapSymlink(x, opts, cb) {
+    if (opts && opts.preserveSymlinks === false) {
+        fs.realpath(x, function (realPathErr, realPath) {
+            if (realPathErr && realPathErr.code !== 'ENOENT') cb(realPathErr);
+            else cb(null, realPathErr ? x : realPath);
+        });
+    } else {
+        cb(null, x);
+    }
+};
+
+module.exports = function resolve(x, options, callback) {
+    var cb = callback;
+    var opts = options;
+    if (typeof options === 'function') {
+        cb = opts;
+        opts = {};
+    }
+    if (typeof x !== 'string') {
+        var err = new TypeError('Path must be a string.');
+        return process.nextTick(function () {
+            cb(err);
+        });
+    }
+
+    opts = normalizeOptions(x, opts);
+
+    var isFile = opts.isFile || defaultIsFile;
+    var isDirectory = opts.isDirectory || defaultIsDir;
+    var readFile = opts.readFile || fs.readFile;
+
+    var extensions = opts.extensions || ['.js'];
+    var basedir = opts.basedir || path.dirname(caller());
+    var parent = opts.filename || basedir;
+
+    opts.paths = opts.paths || [];
+
+    // ensure that `basedir` is an absolute path at this point, resolving against the process' current working directory
+    var absoluteStart = path.resolve(basedir);
+
+    maybeUnwrapSymlink(
+        absoluteStart,
+        opts,
+        function (err, realStart) {
+            if (err) cb(err);
+            else init(realStart);
+        }
+    );
+
+    var res;
+    function init(basedir) {
+        if ((/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/).test(x)) {
+            res = path.resolve(basedir, x);
+            if (x === '..' || x.slice(-1) === '/') res += '/';
+            if ((/\/$/).test(x) && res === basedir) {
+                loadAsDirectory(res, opts.package, onfile);
+            } else loadAsFile(res, opts.package, onfile);
+        } else loadNodeModules(x, basedir, function (err, n, pkg) {
+            if (err) cb(err);
+            else if (core[x]) return cb(null, x);
+            else if (n) {
+                return maybeUnwrapSymlink(n, opts, function (err, realN) {
+                    if (err) {
+                        cb(err);
+                    } else {
+                        cb(null, realN, pkg);
+                    }
+                });
+            } else {
+                var moduleError = new Error("Cannot find module '" + x + "' from '" + parent + "'");
+                moduleError.code = 'MODULE_NOT_FOUND';
+                cb(moduleError);
+            }
+        });
+    }
+
+    function onfile(err, m, pkg) {
+        if (err) cb(err);
+        else if (m) cb(null, m, pkg);
+        else loadAsDirectory(res, function (err, d, pkg) {
+            if (err) cb(err);
+            else if (d) {
+                maybeUnwrapSymlink(d, opts, function (err, realD) {
+                    if (err) {
+                        cb(err);
+                    } else {
+                        cb(null, realD, pkg);
+                    }
+                });
+            } else {
+                var moduleError = new Error("Cannot find module '" + x + "' from '" + parent + "'");
+                moduleError.code = 'MODULE_NOT_FOUND';
+                cb(moduleError);
+            }
+        });
+    }
+
+    function loadAsFile(x, thePackage, callback) {
+        var loadAsFilePackage = thePackage;
+        var cb = callback;
+        if (typeof loadAsFilePackage === 'function') {
+            cb = loadAsFilePackage;
+            loadAsFilePackage = undefined;
+        }
+
+        var exts = [''].concat(extensions);
+        load(exts, x, loadAsFilePackage);
+
+        function load(exts, x, loadPackage) {
+            if (exts.length === 0) return cb(null, undefined, loadPackage);
+            var file = x + exts[0];
+
+            var pkg = loadPackage;
+            if (pkg) onpkg(null, pkg);
+            else loadpkg(path.dirname(file), onpkg);
+
+            function onpkg(err, pkg_, dir) {
+                pkg = pkg_;
+                if (err) return cb(err);
+                if (dir && pkg && opts.pathFilter) {
+                    var rfile = path.relative(dir, file);
+                    var rel = rfile.slice(0, rfile.length - exts[0].length);
+                    var r = opts.pathFilter(pkg, x, rel);
+                    if (r) return load(
+                        [''].concat(extensions.slice()),
+                        path.resolve(dir, r),
+                        pkg
+                    );
+                }
+                isFile(file, onex);
+            }
+            function onex(err, ex) {
+                if (err) return cb(err);
+                if (ex) return cb(null, file, pkg);
+                load(exts.slice(1), x, pkg);
+            }
+        }
+    }
+
+    function loadpkg(dir, cb) {
+        if (dir === '' || dir === '/') return cb(null);
+        if (process.platform === 'win32' && (/^\w:[/\\]*$/).test(dir)) {
+            return cb(null);
+        }
+        if ((/[/\\]node_modules[/\\]*$/).test(dir)) return cb(null);
+
+        var pkgfile = path.join(dir, 'package.json');
+        isFile(pkgfile, function (err, ex) {
+            // on err, ex is false
+            if (!ex) return loadpkg(path.dirname(dir), cb);
+
+            readFile(pkgfile, function (err, body) {
+                if (err) cb(err);
+                try { var pkg = JSON.parse(body); } catch (jsonErr) {}
+
+                if (pkg && opts.packageFilter) {
+                    pkg = opts.packageFilter(pkg, pkgfile);
+                }
+                cb(null, pkg, dir);
+            });
+        });
+    }
+
+    function loadAsDirectory(x, loadAsDirectoryPackage, callback) {
+        var cb = callback;
+        var fpkg = loadAsDirectoryPackage;
+        if (typeof fpkg === 'function') {
+            cb = fpkg;
+            fpkg = opts.package;
+        }
+
+        var pkgfile = path.join(x, 'package.json');
+        isFile(pkgfile, function (err, ex) {
+            if (err) return cb(err);
+            if (!ex) return loadAsFile(path.join(x, 'index'), fpkg, cb);
+
+            readFile(pkgfile, function (err, body) {
+                if (err) return cb(err);
+                try {
+                    var pkg = JSON.parse(body);
+                } catch (jsonErr) {}
+
+                if (opts.packageFilter) {
+                    pkg = opts.packageFilter(pkg, pkgfile);
+                }
+
+                if (pkg.main) {
+                    if (typeof pkg.main !== 'string') {
+                        var mainError = new TypeError('package “' + pkg.name + '” `main` must be a string');
+                        mainError.code = 'INVALID_PACKAGE_MAIN';
+                        return cb(mainError);
+                    }
+                    if (pkg.main === '.' || pkg.main === './') {
+                        pkg.main = 'index';
+                    }
+                    loadAsFile(path.resolve(x, pkg.main), pkg, function (err, m, pkg) {
+                        if (err) return cb(err);
+                        if (m) return cb(null, m, pkg);
+                        if (!pkg) return loadAsFile(path.join(x, 'index'), pkg, cb);
+
+                        var dir = path.resolve(x, pkg.main);
+                        loadAsDirectory(dir, pkg, function (err, n, pkg) {
+                            if (err) return cb(err);
+                            if (n) return cb(null, n, pkg);
+                            loadAsFile(path.join(x, 'index'), pkg, cb);
+                        });
+                    });
+                    return;
+                }
+
+                loadAsFile(path.join(x, '/index'), pkg, cb);
+            });
+        });
+    }
+
+    function processDirs(cb, dirs) {
+        if (dirs.length === 0) return cb(null, undefined);
+        var dir = dirs[0];
+
+        isDirectory(dir, isdir);
+
+        function isdir(err, isdir) {
+            if (err) return cb(err);
+            if (!isdir) return processDirs(cb, dirs.slice(1));
+            var file = path.join(dir, x);
+            loadAsFile(file, opts.package, onfile);
+        }
+
+        function onfile(err, m, pkg) {
+            if (err) return cb(err);
+            if (m) return cb(null, m, pkg);
+            loadAsDirectory(path.join(dir, x), opts.package, ondir);
+        }
+
+        function ondir(err, n, pkg) {
+            if (err) return cb(err);
+            if (n) return cb(null, n, pkg);
+            processDirs(cb, dirs.slice(1));
+        }
+    }
+    function loadNodeModules(x, start, cb) {
+        processDirs(cb, nodeModulesPaths(start, opts, x));
+    }
+};
diff --git a/server/node_modules/resolve/lib/caller.js b/server/node_modules/resolve/lib/caller.js
new file mode 100644
index 0000000000000000000000000000000000000000..b14a2804ae828a4c39c9f949611236cd6ef7a45d
--- /dev/null
+++ b/server/node_modules/resolve/lib/caller.js
@@ -0,0 +1,8 @@
+module.exports = function () {
+    // see https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
+    var origPrepareStackTrace = Error.prepareStackTrace;
+    Error.prepareStackTrace = function (_, stack) { return stack; };
+    var stack = (new Error()).stack;
+    Error.prepareStackTrace = origPrepareStackTrace;
+    return stack[2].getFileName();
+};
diff --git a/server/node_modules/resolve/lib/core.js b/server/node_modules/resolve/lib/core.js
new file mode 100644
index 0000000000000000000000000000000000000000..0877650ccad4e81c87852e994c52560f47c73b38
--- /dev/null
+++ b/server/node_modules/resolve/lib/core.js
@@ -0,0 +1,53 @@
+var current = (process.versions && process.versions.node && process.versions.node.split('.')) || [];
+
+function specifierIncluded(specifier) {
+    var parts = specifier.split(' ');
+    var op = parts.length > 1 ? parts[0] : '=';
+    var versionParts = (parts.length > 1 ? parts[1] : parts[0]).split('.');
+
+    for (var i = 0; i < 3; ++i) {
+        var cur = Number(current[i] || 0);
+        var ver = Number(versionParts[i] || 0);
+        if (cur === ver) {
+            continue; // eslint-disable-line no-restricted-syntax, no-continue
+        }
+        if (op === '<') {
+            return cur < ver;
+        } else if (op === '>=') {
+            return cur >= ver;
+        } else {
+            return false;
+        }
+    }
+    return op === '>=';
+}
+
+function matchesRange(range) {
+    var specifiers = range.split(/ ?&& ?/);
+    if (specifiers.length === 0) { return false; }
+    for (var i = 0; i < specifiers.length; ++i) {
+        if (!specifierIncluded(specifiers[i])) { return false; }
+    }
+    return true;
+}
+
+function versionIncluded(specifierValue) {
+    if (typeof specifierValue === 'boolean') { return specifierValue; }
+    if (specifierValue && typeof specifierValue === 'object') {
+        for (var i = 0; i < specifierValue.length; ++i) {
+            if (matchesRange(specifierValue[i])) { return true; }
+        }
+        return false;
+    }
+    return matchesRange(specifierValue);
+}
+
+var data = require('./core.json');
+
+var core = {};
+for (var mod in data) { // eslint-disable-line no-restricted-syntax
+    if (Object.prototype.hasOwnProperty.call(data, mod)) {
+        core[mod] = versionIncluded(data[mod]);
+    }
+}
+module.exports = core;
diff --git a/server/node_modules/resolve/lib/core.json b/server/node_modules/resolve/lib/core.json
new file mode 100644
index 0000000000000000000000000000000000000000..12a6ac7e6c364b5f2609df3acb58b29769de3390
--- /dev/null
+++ b/server/node_modules/resolve/lib/core.json
@@ -0,0 +1,74 @@
+{
+    "assert": true,
+    "async_hooks": ">= 8",
+    "buffer_ieee754": "< 0.9.7",
+    "buffer": true,
+    "child_process": true,
+    "cluster": true,
+    "console": true,
+    "constants": true,
+    "crypto": true,
+    "_debug_agent": ">= 1 && < 8",
+    "_debugger": "< 8",
+    "dgram": true,
+    "dns": true,
+    "domain": true,
+    "events": true,
+    "freelist": "< 6",
+    "fs": true,
+    "fs/promises": ">= 10 && < 10.1",
+    "_http_agent": ">= 0.11.1",
+    "_http_client": ">= 0.11.1",
+    "_http_common": ">= 0.11.1",
+    "_http_incoming": ">= 0.11.1",
+    "_http_outgoing": ">= 0.11.1",
+    "_http_server": ">= 0.11.1",
+    "http": true,
+    "http2": ">= 8.8",
+    "https": true,
+    "inspector": ">= 8.0.0",
+    "_linklist": "< 8",
+    "module": true,
+    "net": true,
+    "node-inspect/lib/_inspect": ">= 7.6.0 && < 12",
+    "node-inspect/lib/internal/inspect_client": ">= 7.6.0 && < 12",
+    "node-inspect/lib/internal/inspect_repl": ">= 7.6.0 && < 12",
+    "os": true,
+    "path": true,
+    "perf_hooks": ">= 8.5",
+    "process": ">= 1",
+    "punycode": true,
+    "querystring": true,
+    "readline": true,
+    "repl": true,
+    "smalloc": ">= 0.11.5 && < 3",
+    "_stream_duplex": ">= 0.9.4",
+    "_stream_transform": ">= 0.9.4",
+    "_stream_wrap": ">= 1.4.1",
+    "_stream_passthrough": ">= 0.9.4",
+    "_stream_readable": ">= 0.9.4",
+    "_stream_writable": ">= 0.9.4",
+    "stream": true,
+    "string_decoder": true,
+    "sys": true,
+    "timers": true,
+    "_tls_common": ">= 0.11.13",
+    "_tls_legacy": ">= 0.11.3 && < 10",
+    "_tls_wrap": ">= 0.11.3",
+    "tls": true,
+    "trace_events": ">= 10",
+    "tty": true,
+    "url": true,
+    "util": true,
+    "v8/tools/arguments": ">= 10 && < 12",
+    "v8/tools/codemap": [">= 4.4.0 && < 5", ">= 5.2.0 && < 12"],
+    "v8/tools/consarray": [">= 4.4.0 && < 5", ">= 5.2.0 && < 12"],
+    "v8/tools/csvparser": [">= 4.4.0 && < 5", ">= 5.2.0 && < 12"],
+    "v8/tools/logreader": [">= 4.4.0 && < 5", ">= 5.2.0 && < 12"],
+    "v8/tools/profile_view": [">= 4.4.0 && < 5", ">= 5.2.0 && < 12"],
+    "v8/tools/splaytree": [">= 4.4.0 && < 5", ">= 5.2.0 && < 12"],
+    "v8": ">= 1",
+    "vm": true,
+    "worker_threads": ">= 11.7",
+    "zlib": true
+}
diff --git a/server/node_modules/resolve/lib/node-modules-paths.js b/server/node_modules/resolve/lib/node-modules-paths.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b43813a7a561ba31474346a2f7d5696b86e88dc
--- /dev/null
+++ b/server/node_modules/resolve/lib/node-modules-paths.js
@@ -0,0 +1,42 @@
+var path = require('path');
+var parse = path.parse || require('path-parse');
+
+var getNodeModulesDirs = function getNodeModulesDirs(absoluteStart, modules) {
+    var prefix = '/';
+    if ((/^([A-Za-z]:)/).test(absoluteStart)) {
+        prefix = '';
+    } else if ((/^\\\\/).test(absoluteStart)) {
+        prefix = '\\\\';
+    }
+
+    var paths = [absoluteStart];
+    var parsed = parse(absoluteStart);
+    while (parsed.dir !== paths[paths.length - 1]) {
+        paths.push(parsed.dir);
+        parsed = parse(parsed.dir);
+    }
+
+    return paths.reduce(function (dirs, aPath) {
+        return dirs.concat(modules.map(function (moduleDir) {
+            return path.resolve(prefix, aPath, moduleDir);
+        }));
+    }, []);
+};
+
+module.exports = function nodeModulesPaths(start, opts, request) {
+    var modules = opts && opts.moduleDirectory
+        ? [].concat(opts.moduleDirectory)
+        : ['node_modules'];
+
+    if (opts && typeof opts.paths === 'function') {
+        return opts.paths(
+            request,
+            start,
+            function () { return getNodeModulesDirs(start, modules); },
+            opts
+        );
+    }
+
+    var dirs = getNodeModulesDirs(start, modules);
+    return opts && opts.paths ? dirs.concat(opts.paths) : dirs;
+};
diff --git a/server/node_modules/resolve/lib/normalize-options.js b/server/node_modules/resolve/lib/normalize-options.js
new file mode 100644
index 0000000000000000000000000000000000000000..4b56904eaea72ba024f96728fff40e1be4af7df0
--- /dev/null
+++ b/server/node_modules/resolve/lib/normalize-options.js
@@ -0,0 +1,10 @@
+module.exports = function (x, opts) {
+    /**
+     * This file is purposefully a passthrough. It's expected that third-party
+     * environments will override it at runtime in order to inject special logic
+     * into `resolve` (by manipulating the options). One such example is the PnP
+     * code path in Yarn.
+     */
+
+    return opts || {};
+};
diff --git a/server/node_modules/resolve/lib/sync.js b/server/node_modules/resolve/lib/sync.js
new file mode 100644
index 0000000000000000000000000000000000000000..e8d83de5b6d3b2d770e950ab7d4f49d30066ba26
--- /dev/null
+++ b/server/node_modules/resolve/lib/sync.js
@@ -0,0 +1,172 @@
+var core = require('./core');
+var fs = require('fs');
+var path = require('path');
+var caller = require('./caller.js');
+var nodeModulesPaths = require('./node-modules-paths.js');
+var normalizeOptions = require('./normalize-options.js');
+
+var defaultIsFile = function isFile(file) {
+    try {
+        var stat = fs.statSync(file);
+    } catch (e) {
+        if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false;
+        throw e;
+    }
+    return stat.isFile() || stat.isFIFO();
+};
+
+var defaultIsDir = function isDirectory(dir) {
+    try {
+        var stat = fs.statSync(dir);
+    } catch (e) {
+        if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false;
+        throw e;
+    }
+    return stat.isDirectory();
+};
+
+var maybeUnwrapSymlink = function maybeUnwrapSymlink(x, opts) {
+    if (opts && opts.preserveSymlinks === false) {
+        try {
+            return fs.realpathSync(x);
+        } catch (realPathErr) {
+            if (realPathErr.code !== 'ENOENT') {
+                throw realPathErr;
+            }
+        }
+    }
+    return x;
+};
+
+module.exports = function (x, options) {
+    if (typeof x !== 'string') {
+        throw new TypeError('Path must be a string.');
+    }
+    var opts = normalizeOptions(x, options);
+
+    var isFile = opts.isFile || defaultIsFile;
+    var readFileSync = opts.readFileSync || fs.readFileSync;
+    var isDirectory = opts.isDirectory || defaultIsDir;
+
+    var extensions = opts.extensions || ['.js'];
+    var basedir = opts.basedir || path.dirname(caller());
+    var parent = opts.filename || basedir;
+
+    opts.paths = opts.paths || [];
+
+    // ensure that `basedir` is an absolute path at this point, resolving against the process' current working directory
+    var absoluteStart = maybeUnwrapSymlink(path.resolve(basedir), opts);
+
+    if ((/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/).test(x)) {
+        var res = path.resolve(absoluteStart, x);
+        if (x === '..' || x.slice(-1) === '/') res += '/';
+        var m = loadAsFileSync(res) || loadAsDirectorySync(res);
+        if (m) return maybeUnwrapSymlink(m, opts);
+    } else if (core[x]) {
+        return x;
+    } else {
+        var n = loadNodeModulesSync(x, absoluteStart);
+        if (n) return maybeUnwrapSymlink(n, opts);
+    }
+
+    if (core[x]) return x;
+
+    var err = new Error("Cannot find module '" + x + "' from '" + parent + "'");
+    err.code = 'MODULE_NOT_FOUND';
+    throw err;
+
+    function loadAsFileSync(x) {
+        var pkg = loadpkg(path.dirname(x));
+
+        if (pkg && pkg.dir && pkg.pkg && opts.pathFilter) {
+            var rfile = path.relative(pkg.dir, x);
+            var r = opts.pathFilter(pkg.pkg, x, rfile);
+            if (r) {
+                x = path.resolve(pkg.dir, r); // eslint-disable-line no-param-reassign
+            }
+        }
+
+        if (isFile(x)) {
+            return x;
+        }
+
+        for (var i = 0; i < extensions.length; i++) {
+            var file = x + extensions[i];
+            if (isFile(file)) {
+                return file;
+            }
+        }
+    }
+
+    function loadpkg(dir) {
+        if (dir === '' || dir === '/') return;
+        if (process.platform === 'win32' && (/^\w:[/\\]*$/).test(dir)) {
+            return;
+        }
+        if ((/[/\\]node_modules[/\\]*$/).test(dir)) return;
+
+        var pkgfile = path.join(dir, 'package.json');
+
+        if (!isFile(pkgfile)) {
+            return loadpkg(path.dirname(dir));
+        }
+
+        var body = readFileSync(pkgfile);
+
+        try {
+            var pkg = JSON.parse(body);
+        } catch (jsonErr) {}
+
+        if (pkg && opts.packageFilter) {
+            pkg = opts.packageFilter(pkg, dir);
+        }
+
+        return { pkg: pkg, dir: dir };
+    }
+
+    function loadAsDirectorySync(x) {
+        var pkgfile = path.join(x, '/package.json');
+        if (isFile(pkgfile)) {
+            try {
+                var body = readFileSync(pkgfile, 'UTF8');
+                var pkg = JSON.parse(body);
+            } catch (e) {}
+
+            if (opts.packageFilter) {
+                pkg = opts.packageFilter(pkg, x);
+            }
+
+            if (pkg.main) {
+                if (typeof pkg.main !== 'string') {
+                    var mainError = new TypeError('package “' + pkg.name + '” `main` must be a string');
+                    mainError.code = 'INVALID_PACKAGE_MAIN';
+                    throw mainError;
+                }
+                if (pkg.main === '.' || pkg.main === './') {
+                    pkg.main = 'index';
+                }
+                try {
+                    var m = loadAsFileSync(path.resolve(x, pkg.main));
+                    if (m) return m;
+                    var n = loadAsDirectorySync(path.resolve(x, pkg.main));
+                    if (n) return n;
+                } catch (e) {}
+            }
+        }
+
+        return loadAsFileSync(path.join(x, '/index'));
+    }
+
+    function loadNodeModulesSync(x, start) {
+        var dirs = nodeModulesPaths(start, opts, x);
+        for (var i = 0; i < dirs.length; i++) {
+            var dir = dirs[i];
+            if (isDirectory(dir)) {
+                var m = loadAsFileSync(path.join(dir, '/', x));
+                if (m) return m;
+                var n = loadAsDirectorySync(path.join(dir, '/', x));
+                if (n) return n;
+            }
+        }
+    }
+};
diff --git a/server/node_modules/resolve/package.json b/server/node_modules/resolve/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..620711b4c76c5c7007c070f61da7918ab8f106cf
--- /dev/null
+++ b/server/node_modules/resolve/package.json
@@ -0,0 +1,72 @@
+{
+  "_from": "resolve@^1.10.0",
+  "_id": "resolve@1.12.0",
+  "_inBundle": false,
+  "_integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
+  "_location": "/resolve",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "resolve@^1.10.0",
+    "name": "resolve",
+    "escapedName": "resolve",
+    "rawSpec": "^1.10.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.10.0"
+  },
+  "_requiredBy": [
+    "/normalize-package-data"
+  ],
+  "_resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
+  "_shasum": "3fc644a35c84a48554609ff26ec52b66fa577df6",
+  "_spec": "resolve@^1.10.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/normalize-package-data",
+  "author": {
+    "name": "James Halliday",
+    "email": "mail@substack.net",
+    "url": "http://substack.net"
+  },
+  "bugs": {
+    "url": "https://github.com/browserify/resolve/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "path-parse": "^1.0.6"
+  },
+  "deprecated": false,
+  "description": "resolve like require.resolve() on behalf of files asynchronously and synchronously",
+  "devDependencies": {
+    "@ljharb/eslint-config": "^13.1.1",
+    "eslint": "^5.16.0",
+    "object-keys": "^1.1.1",
+    "safe-publish-latest": "^1.1.2",
+    "tap": "0.4.13",
+    "tape": "^4.11.0"
+  },
+  "homepage": "https://github.com/browserify/resolve#readme",
+  "keywords": [
+    "resolve",
+    "require",
+    "node",
+    "module"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "resolve",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/browserify/resolve.git"
+  },
+  "scripts": {
+    "lint": "eslint .",
+    "posttest": "npm run test:multirepo",
+    "prepublish": "safe-publish-latest",
+    "pretest": "npm run lint",
+    "pretests-only": "cd ./test/resolver/nested_symlinks && node mylib/sync && node mylib/async",
+    "test": "npm run --silent tests-only",
+    "test:multirepo": "cd ./test/resolver/multirepo && npm install && npm test",
+    "tests-only": "tape test/*.js"
+  },
+  "version": "1.12.0"
+}
diff --git a/server/node_modules/resolve/readme.markdown b/server/node_modules/resolve/readme.markdown
new file mode 100644
index 0000000000000000000000000000000000000000..f1b27063901cb36c07bef1ef5679e83397dc989b
--- /dev/null
+++ b/server/node_modules/resolve/readme.markdown
@@ -0,0 +1,201 @@
+# resolve
+
+implements the [node `require.resolve()`
+algorithm](https://nodejs.org/api/modules.html#modules_all_together)
+such that you can `require.resolve()` on behalf of a file asynchronously and
+synchronously
+
+[![build status](https://secure.travis-ci.org/browserify/node-resolve.png)](http://travis-ci.org/browserify/node-resolve)
+
+# example
+
+asynchronously resolve:
+
+```js
+var resolve = require('resolve');
+resolve('tap', { basedir: __dirname }, function (err, res) {
+    if (err) console.error(err);
+    else console.log(res);
+});
+```
+
+```
+$ node example/async.js
+/home/substack/projects/node-resolve/node_modules/tap/lib/main.js
+```
+
+synchronously resolve:
+
+```js
+var resolve = require('resolve');
+var res = resolve.sync('tap', { basedir: __dirname });
+console.log(res);
+```
+
+```
+$ node example/sync.js
+/home/substack/projects/node-resolve/node_modules/tap/lib/main.js
+```
+
+# methods
+
+```js
+var resolve = require('resolve');
+```
+
+## resolve(id, opts={}, cb)
+
+Asynchronously resolve the module path string `id` into `cb(err, res [, pkg])`, where `pkg` (if defined) is the data from `package.json`.
+
+options are:
+
+* opts.basedir - directory to begin resolving from
+
+* opts.package - `package.json` data applicable to the module being loaded
+
+* opts.extensions - array of file extensions to search in order
+
+* opts.readFile - how to read files asynchronously
+
+* opts.isFile - function to asynchronously test whether a file exists
+
+* opts.isDirectory - function to asynchronously test whether a directory exists
+
+* `opts.packageFilter(pkg, pkgfile)` - transform the parsed package.json contents before looking at the "main" field
+  * pkg - package data
+  * pkgfile - path to package.json
+
+* `opts.pathFilter(pkg, path, relativePath)` - transform a path within a package
+  * pkg - package data
+  * path - the path being resolved
+  * relativePath - the path relative from the package.json location
+  * returns - a relative path that will be joined from the package.json location
+
+* opts.paths - require.paths array to use if nothing is found on the normal `node_modules` recursive walk (probably don't use this)
+
+  For advanced users, `paths` can also be a `opts.paths(request, start, opts)` function
+    * request - the import specifier being resolved
+    * start - lookup path
+    * getNodeModulesDirs - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution
+    * opts - the resolution options
+
+* opts.moduleDirectory - directory (or directories) in which to recursively look for modules. default: `"node_modules"`
+
+* opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving.
+This is the way Node resolves dependencies when executed with the [--preserve-symlinks](https://nodejs.org/api/all.html#cli_preserve_symlinks) flag.
+**Note:** this property is currently `true` by default but it will be changed to
+`false` in the next major version because *Node's resolution algorithm does not preserve symlinks by default*.
+
+default `opts` values:
+
+```js
+{
+    paths: [],
+    basedir: __dirname,
+    extensions: ['.js'],
+    readFile: fs.readFile,
+    isFile: function isFile(file, cb) {
+        fs.stat(file, function (err, stat) {
+            if (!err) {
+                return cb(null, stat.isFile() || stat.isFIFO());
+            }
+            if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false);
+            return cb(err);
+        });
+    },
+    isDirectory: function isDirectory(dir, cb) {
+        fs.stat(dir, function (err, stat) {
+            if (!err) {
+                return cb(null, stat.isDirectory());
+            }
+            if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false);
+            return cb(err);
+        });
+    },
+    moduleDirectory: 'node_modules',
+    preserveSymlinks: true
+}
+```
+
+## resolve.sync(id, opts)
+
+Synchronously resolve the module path string `id`, returning the result and
+throwing an error when `id` can't be resolved.
+
+options are:
+
+* opts.basedir - directory to begin resolving from
+
+* opts.extensions - array of file extensions to search in order
+
+* opts.readFile - how to read files synchronously
+
+* opts.isFile - function to synchronously test whether a file exists
+
+* opts.isDirectory - function to synchronously test whether a directory exists
+
+* `opts.packageFilter(pkg, dir)` - transform the parsed package.json contents before looking at the "main" field
+  * pkg - package data
+  * dir - directory for package.json (Note: the second argument will change to "pkgfile" in v2)
+
+* `opts.pathFilter(pkg, path, relativePath)` - transform a path within a package
+  * pkg - package data
+  * path - the path being resolved
+  * relativePath - the path relative from the package.json location
+  * returns - a relative path that will be joined from the package.json location
+
+* opts.paths - require.paths array to use if nothing is found on the normal `node_modules` recursive walk (probably don't use this)
+
+* opts.moduleDirectory - directory (or directories) in which to recursively look for modules. default: `"node_modules"`
+
+* opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving.
+This is the way Node resolves dependencies when executed with the [--preserve-symlinks](https://nodejs.org/api/all.html#cli_preserve_symlinks) flag.
+**Note:** this property is currently `true` by default but it will be changed to
+`false` in the next major version because *Node's resolution algorithm does not preserve symlinks by default*.
+
+default `opts` values:
+
+```js
+{
+    paths: [],
+    basedir: __dirname,
+    extensions: ['.js'],
+    readFileSync: fs.readFileSync,
+    isFile: function isFile(file) {
+        try {
+            var stat = fs.statSync(file);
+        } catch (e) {
+            if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false;
+            throw e;
+        }
+        return stat.isFile() || stat.isFIFO();
+    },
+    isDirectory: function isDirectory(dir) {
+        try {
+            var stat = fs.statSync(dir);
+        } catch (e) {
+            if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false;
+            throw e;
+        }
+        return stat.isDirectory();
+    },
+    moduleDirectory: 'node_modules',
+    preserveSymlinks: true
+}
+```
+
+## resolve.isCore(pkg)
+
+Return whether a package is in core.
+
+# install
+
+With [npm](https://npmjs.org) do:
+
+```sh
+npm install resolve
+```
+
+# license
+
+MIT
diff --git a/server/node_modules/resolve/test/.eslintrc b/server/node_modules/resolve/test/.eslintrc
new file mode 100644
index 0000000000000000000000000000000000000000..ddd262df503c7222d8ff465130b32e689899ef9f
--- /dev/null
+++ b/server/node_modules/resolve/test/.eslintrc
@@ -0,0 +1,5 @@
+{
+    "rules": {
+        "max-lines": 0
+    }
+}
diff --git a/server/node_modules/resolve/test/core.js b/server/node_modules/resolve/test/core.js
new file mode 100644
index 0000000000000000000000000000000000000000..33d9f329499c6144a5a40c9b07596c713ff3456a
--- /dev/null
+++ b/server/node_modules/resolve/test/core.js
@@ -0,0 +1,82 @@
+var test = require('tape');
+var keys = require('object-keys');
+var resolve = require('../');
+
+test('core modules', function (t) {
+    t.test('isCore()', function (st) {
+        st.ok(resolve.isCore('fs'));
+        st.ok(resolve.isCore('net'));
+        st.ok(resolve.isCore('http'));
+
+        st.ok(!resolve.isCore('seq'));
+        st.ok(!resolve.isCore('../'));
+        st.end();
+    });
+
+    t.test('core list', function (st) {
+        var cores = keys(resolve.core);
+        st.plan(cores.length);
+
+        for (var i = 0; i < cores.length; ++i) {
+            var mod = cores[i];
+            if (resolve.core[mod]) {
+                st.doesNotThrow(
+                    function () { require(mod); }, // eslint-disable-line no-loop-func
+                    mod + ' supported; requiring does not throw'
+                );
+            } else {
+                st.throws(
+                    function () { require(mod); }, // eslint-disable-line no-loop-func
+                    mod + ' not supported; requiring throws'
+                );
+            }
+        }
+
+        st.end();
+    });
+
+    t.test('core via repl module', { skip: !resolve.core.repl }, function (st) {
+        var libs = require('repl')._builtinLibs; // eslint-disable-line no-underscore-dangle
+        if (!libs) {
+            st.skip('module.builtinModules does not exist');
+            return st.end();
+        }
+        for (var i = 0; i < libs.length; ++i) {
+            var mod = libs[i];
+            st.ok(resolve.core[mod], mod + ' is a core module');
+            st.doesNotThrow(
+                function () { require(mod); }, // eslint-disable-line no-loop-func
+                'requiring ' + mod + ' does not throw'
+            );
+        }
+        st.end();
+    });
+
+    t.test('core via builtinModules list', { skip: !resolve.core.module }, function (st) {
+        var libs = require('module').builtinModules;
+        if (!libs) {
+            st.skip('module.builtinModules does not exist');
+            return st.end();
+        }
+        var blacklist = [
+            '_debug_agent',
+            'v8/tools/tickprocessor-driver',
+            'v8/tools/SourceMap',
+            'v8/tools/tickprocessor',
+            'v8/tools/profile'
+        ];
+        for (var i = 0; i < libs.length; ++i) {
+            var mod = libs[i];
+            if (blacklist.indexOf(mod) === -1) {
+                st.ok(resolve.core[mod], mod + ' is a core module');
+                st.doesNotThrow(
+                    function () { require(mod); }, // eslint-disable-line no-loop-func
+                    'requiring ' + mod + ' does not throw'
+                );
+            }
+        }
+        st.end();
+    });
+
+    t.end();
+});
diff --git a/server/node_modules/resolve/test/dotdot.js b/server/node_modules/resolve/test/dotdot.js
new file mode 100644
index 0000000000000000000000000000000000000000..30806659be2ef27d410722636d6f79c8f8e999b0
--- /dev/null
+++ b/server/node_modules/resolve/test/dotdot.js
@@ -0,0 +1,29 @@
+var path = require('path');
+var test = require('tape');
+var resolve = require('../');
+
+test('dotdot', function (t) {
+    t.plan(4);
+    var dir = path.join(__dirname, '/dotdot/abc');
+
+    resolve('..', { basedir: dir }, function (err, res, pkg) {
+        t.ifError(err);
+        t.equal(res, path.join(__dirname, 'dotdot/index.js'));
+    });
+
+    resolve('.', { basedir: dir }, function (err, res, pkg) {
+        t.ifError(err);
+        t.equal(res, path.join(dir, 'index.js'));
+    });
+});
+
+test('dotdot sync', function (t) {
+    t.plan(2);
+    var dir = path.join(__dirname, '/dotdot/abc');
+
+    var a = resolve.sync('..', { basedir: dir });
+    t.equal(a, path.join(__dirname, 'dotdot/index.js'));
+
+    var b = resolve.sync('.', { basedir: dir });
+    t.equal(b, path.join(dir, 'index.js'));
+});
diff --git a/server/node_modules/resolve/test/dotdot/abc/index.js b/server/node_modules/resolve/test/dotdot/abc/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..67f2534ebf90dcc4c2c1c13ce3ab52c41f4d2ed9
--- /dev/null
+++ b/server/node_modules/resolve/test/dotdot/abc/index.js
@@ -0,0 +1,2 @@
+var x = require('..');
+console.log(x);
diff --git a/server/node_modules/resolve/test/dotdot/index.js b/server/node_modules/resolve/test/dotdot/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..643f9fcc6a6a7cf025dcc86559e83d00b993ed96
--- /dev/null
+++ b/server/node_modules/resolve/test/dotdot/index.js
@@ -0,0 +1 @@
+module.exports = 'whatever';
diff --git a/server/node_modules/resolve/test/faulty_basedir.js b/server/node_modules/resolve/test/faulty_basedir.js
new file mode 100644
index 0000000000000000000000000000000000000000..5f2141a67267bceaf743ab292ca8e7bebb2b6bbc
--- /dev/null
+++ b/server/node_modules/resolve/test/faulty_basedir.js
@@ -0,0 +1,29 @@
+var test = require('tape');
+var path = require('path');
+var resolve = require('../');
+
+test('faulty basedir must produce error in windows', { skip: process.platform !== 'win32' }, function (t) {
+    t.plan(1);
+
+    var resolverDir = 'C:\\a\\b\\c\\d';
+
+    resolve('tape/lib/test.js', { basedir: resolverDir }, function (err, res, pkg) {
+        t.equal(!!err, true);
+    });
+});
+
+test('non-existent basedir should not throw when preserveSymlinks is false', function (t) {
+    t.plan(2);
+
+    var opts = {
+        basedir: path.join(path.sep, 'unreal', 'path', 'that', 'does', 'not', 'exist'),
+        preserveSymlinks: false
+    };
+
+    var module = './dotdot/abc';
+
+    resolve(module, opts, function (err, res) {
+        t.equal(err.code, 'MODULE_NOT_FOUND');
+        t.equal(res, undefined);
+    });
+});
diff --git a/server/node_modules/resolve/test/filter.js b/server/node_modules/resolve/test/filter.js
new file mode 100644
index 0000000000000000000000000000000000000000..dfc622a874e1653db7003c35c469210bf71604ed
--- /dev/null
+++ b/server/node_modules/resolve/test/filter.js
@@ -0,0 +1,34 @@
+var path = require('path');
+var test = require('tape');
+var resolve = require('../');
+
+test('filter', function (t) {
+    t.plan(4);
+    var dir = path.join(__dirname, 'resolver');
+    var packageFilterArgs;
+    resolve('./baz', {
+        basedir: dir,
+        packageFilter: function (pkg, pkgfile) {
+            pkg.main = 'doom';
+            packageFilterArgs = [pkg, pkgfile];
+            return pkg;
+        }
+    }, function (err, res, pkg) {
+        if (err) t.fail(err);
+
+        t.equal(res, path.join(dir, 'baz/doom.js'), 'changing the package "main" works');
+
+        var packageData = packageFilterArgs[0];
+        t.equal(pkg, packageData, 'first packageFilter argument is "pkg"');
+        t.equal(packageData.main, 'doom', 'package "main" was altered');
+
+        var packageFile = packageFilterArgs[1];
+        t.equal(
+            packageFile,
+            path.join(dir, 'baz/package.json'),
+            'second packageFilter argument is "pkgfile"'
+        );
+
+        t.end();
+    });
+});
diff --git a/server/node_modules/resolve/test/filter_sync.js b/server/node_modules/resolve/test/filter_sync.js
new file mode 100644
index 0000000000000000000000000000000000000000..064052e160ff1738bfd328a359fcb5cde825407a
--- /dev/null
+++ b/server/node_modules/resolve/test/filter_sync.js
@@ -0,0 +1,26 @@
+var path = require('path');
+var test = require('tape');
+var resolve = require('../');
+
+test('filter', function (t) {
+    var dir = path.join(__dirname, 'resolver');
+    var packageFilterArgs;
+    var res = resolve.sync('./baz', {
+        basedir: dir,
+        packageFilter: function (pkg, dir) {
+            pkg.main = 'doom';
+            packageFilterArgs = [pkg, dir];
+            return pkg;
+        }
+    });
+
+    t.equal(res, path.join(dir, 'baz/doom.js'), 'changing the package "main" works');
+
+    var packageData = packageFilterArgs[0];
+    t.equal(packageData.main, 'doom', 'package "main" was altered');
+
+    var packageFile = packageFilterArgs[1];
+    t.equal(packageFile, path.join(dir, 'baz'), 'second packageFilter argument is "dir"');
+
+    t.end();
+});
diff --git a/server/node_modules/resolve/test/mock.js b/server/node_modules/resolve/test/mock.js
new file mode 100644
index 0000000000000000000000000000000000000000..d4f57a319fb57c2cc14caa0c842c57c6f10d89d7
--- /dev/null
+++ b/server/node_modules/resolve/test/mock.js
@@ -0,0 +1,169 @@
+var path = require('path');
+var test = require('tape');
+var resolve = require('../');
+
+test('mock', function (t) {
+    t.plan(8);
+
+    var files = {};
+    files[path.resolve('/foo/bar/baz.js')] = 'beep';
+
+    var dirs = {};
+    dirs[path.resolve('/foo/bar')] = true;
+
+    function opts(basedir) {
+        return {
+            basedir: path.resolve(basedir),
+            isFile: function (file, cb) {
+                cb(null, Object.prototype.hasOwnProperty.call(files, path.resolve(file)));
+            },
+            isDirectory: function (dir, cb) {
+                cb(null, !!dirs[path.resolve(dir)]);
+            },
+            readFile: function (file, cb) {
+                cb(null, files[path.resolve(file)]);
+            }
+        };
+    }
+
+    resolve('./baz', opts('/foo/bar'), function (err, res, pkg) {
+        if (err) return t.fail(err);
+        t.equal(res, path.resolve('/foo/bar/baz.js'));
+        t.equal(pkg, undefined);
+    });
+
+    resolve('./baz.js', opts('/foo/bar'), function (err, res, pkg) {
+        if (err) return t.fail(err);
+        t.equal(res, path.resolve('/foo/bar/baz.js'));
+        t.equal(pkg, undefined);
+    });
+
+    resolve('baz', opts('/foo/bar'), function (err, res) {
+        t.equal(err.message, "Cannot find module 'baz' from '" + path.resolve('/foo/bar') + "'");
+        t.equal(err.code, 'MODULE_NOT_FOUND');
+    });
+
+    resolve('../baz', opts('/foo/bar'), function (err, res) {
+        t.equal(err.message, "Cannot find module '../baz' from '" + path.resolve('/foo/bar') + "'");
+        t.equal(err.code, 'MODULE_NOT_FOUND');
+    });
+});
+
+test('mock from package', function (t) {
+    t.plan(8);
+
+    var files = {};
+    files[path.resolve('/foo/bar/baz.js')] = 'beep';
+
+    var dirs = {};
+    dirs[path.resolve('/foo/bar')] = true;
+
+    function opts(basedir) {
+        return {
+            basedir: path.resolve(basedir),
+            isFile: function (file, cb) {
+                cb(null, Object.prototype.hasOwnProperty.call(files, file));
+            },
+            isDirectory: function (dir, cb) {
+                cb(null, !!dirs[path.resolve(dir)]);
+            },
+            'package': { main: 'bar' },
+            readFile: function (file, cb) {
+                cb(null, files[file]);
+            }
+        };
+    }
+
+    resolve('./baz', opts('/foo/bar'), function (err, res, pkg) {
+        if (err) return t.fail(err);
+        t.equal(res, path.resolve('/foo/bar/baz.js'));
+        t.equal(pkg && pkg.main, 'bar');
+    });
+
+    resolve('./baz.js', opts('/foo/bar'), function (err, res, pkg) {
+        if (err) return t.fail(err);
+        t.equal(res, path.resolve('/foo/bar/baz.js'));
+        t.equal(pkg && pkg.main, 'bar');
+    });
+
+    resolve('baz', opts('/foo/bar'), function (err, res) {
+        t.equal(err.message, "Cannot find module 'baz' from '" + path.resolve('/foo/bar') + "'");
+        t.equal(err.code, 'MODULE_NOT_FOUND');
+    });
+
+    resolve('../baz', opts('/foo/bar'), function (err, res) {
+        t.equal(err.message, "Cannot find module '../baz' from '" + path.resolve('/foo/bar') + "'");
+        t.equal(err.code, 'MODULE_NOT_FOUND');
+    });
+});
+
+test('mock package', function (t) {
+    t.plan(2);
+
+    var files = {};
+    files[path.resolve('/foo/node_modules/bar/baz.js')] = 'beep';
+    files[path.resolve('/foo/node_modules/bar/package.json')] = JSON.stringify({
+        main: './baz.js'
+    });
+
+    var dirs = {};
+    dirs[path.resolve('/foo')] = true;
+    dirs[path.resolve('/foo/node_modules')] = true;
+
+    function opts(basedir) {
+        return {
+            basedir: path.resolve(basedir),
+            isFile: function (file, cb) {
+                cb(null, Object.prototype.hasOwnProperty.call(files, path.resolve(file)));
+            },
+            isDirectory: function (dir, cb) {
+                cb(null, !!dirs[path.resolve(dir)]);
+            },
+            readFile: function (file, cb) {
+                cb(null, files[path.resolve(file)]);
+            }
+        };
+    }
+
+    resolve('bar', opts('/foo'), function (err, res, pkg) {
+        if (err) return t.fail(err);
+        t.equal(res, path.resolve('/foo/node_modules/bar/baz.js'));
+        t.equal(pkg && pkg.main, './baz.js');
+    });
+});
+
+test('mock package from package', function (t) {
+    t.plan(2);
+
+    var files = {};
+    files[path.resolve('/foo/node_modules/bar/baz.js')] = 'beep';
+    files[path.resolve('/foo/node_modules/bar/package.json')] = JSON.stringify({
+        main: './baz.js'
+    });
+
+    var dirs = {};
+    dirs[path.resolve('/foo')] = true;
+    dirs[path.resolve('/foo/node_modules')] = true;
+
+    function opts(basedir) {
+        return {
+            basedir: path.resolve(basedir),
+            isFile: function (file, cb) {
+                cb(null, Object.prototype.hasOwnProperty.call(files, path.resolve(file)));
+            },
+            isDirectory: function (dir, cb) {
+                cb(null, !!dirs[path.resolve(dir)]);
+            },
+            'package': { main: 'bar' },
+            readFile: function (file, cb) {
+                cb(null, files[path.resolve(file)]);
+            }
+        };
+    }
+
+    resolve('bar', opts('/foo'), function (err, res, pkg) {
+        if (err) return t.fail(err);
+        t.equal(res, path.resolve('/foo/node_modules/bar/baz.js'));
+        t.equal(pkg && pkg.main, './baz.js');
+    });
+});
diff --git a/server/node_modules/resolve/test/mock_sync.js b/server/node_modules/resolve/test/mock_sync.js
new file mode 100644
index 0000000000000000000000000000000000000000..af06ae110faf61fba45a7235fa25af761870035f
--- /dev/null
+++ b/server/node_modules/resolve/test/mock_sync.js
@@ -0,0 +1,80 @@
+var path = require('path');
+var test = require('tape');
+var resolve = require('../');
+
+test('mock', function (t) {
+    t.plan(4);
+
+    var files = {};
+    files[path.resolve('/foo/bar/baz.js')] = 'beep';
+
+    var dirs = {};
+    dirs[path.resolve('/foo/bar')] = true;
+
+    function opts(basedir) {
+        return {
+            basedir: path.resolve(basedir),
+            isFile: function (file) {
+                return Object.prototype.hasOwnProperty.call(files, path.resolve(file));
+            },
+            isDirectory: function (dir) {
+                return !!dirs[path.resolve(dir)];
+            },
+            readFileSync: function (file) {
+                return files[path.resolve(file)];
+            }
+        };
+    }
+
+    t.equal(
+        resolve.sync('./baz', opts('/foo/bar')),
+        path.resolve('/foo/bar/baz.js')
+    );
+
+    t.equal(
+        resolve.sync('./baz.js', opts('/foo/bar')),
+        path.resolve('/foo/bar/baz.js')
+    );
+
+    t.throws(function () {
+        resolve.sync('baz', opts('/foo/bar'));
+    });
+
+    t.throws(function () {
+        resolve.sync('../baz', opts('/foo/bar'));
+    });
+});
+
+test('mock package', function (t) {
+    t.plan(1);
+
+    var files = {};
+    files[path.resolve('/foo/node_modules/bar/baz.js')] = 'beep';
+    files[path.resolve('/foo/node_modules/bar/package.json')] = JSON.stringify({
+        main: './baz.js'
+    });
+
+    var dirs = {};
+    dirs[path.resolve('/foo')] = true;
+    dirs[path.resolve('/foo/node_modules')] = true;
+
+    function opts(basedir) {
+        return {
+            basedir: path.resolve(basedir),
+            isFile: function (file) {
+                return Object.prototype.hasOwnProperty.call(files, path.resolve(file));
+            },
+            isDirectory: function (dir) {
+                return !!dirs[path.resolve(dir)];
+            },
+            readFileSync: function (file) {
+                return files[path.resolve(file)];
+            }
+        };
+    }
+
+    t.equal(
+        resolve.sync('bar', opts('/foo')),
+        path.resolve('/foo/node_modules/bar/baz.js')
+    );
+});
diff --git a/server/node_modules/resolve/test/module_dir.js b/server/node_modules/resolve/test/module_dir.js
new file mode 100644
index 0000000000000000000000000000000000000000..b50e5bb1751d69694deaae36d5f0bc6691498008
--- /dev/null
+++ b/server/node_modules/resolve/test/module_dir.js
@@ -0,0 +1,56 @@
+var path = require('path');
+var test = require('tape');
+var resolve = require('../');
+
+test('moduleDirectory strings', function (t) {
+    t.plan(4);
+    var dir = path.join(__dirname, 'module_dir');
+    var xopts = {
+        basedir: dir,
+        moduleDirectory: 'xmodules'
+    };
+    resolve('aaa', xopts, function (err, res, pkg) {
+        t.ifError(err);
+        t.equal(res, path.join(dir, '/xmodules/aaa/index.js'));
+    });
+
+    var yopts = {
+        basedir: dir,
+        moduleDirectory: 'ymodules'
+    };
+    resolve('aaa', yopts, function (err, res, pkg) {
+        t.ifError(err);
+        t.equal(res, path.join(dir, '/ymodules/aaa/index.js'));
+    });
+});
+
+test('moduleDirectory array', function (t) {
+    t.plan(6);
+    var dir = path.join(__dirname, 'module_dir');
+    var aopts = {
+        basedir: dir,
+        moduleDirectory: ['xmodules', 'ymodules', 'zmodules']
+    };
+    resolve('aaa', aopts, function (err, res, pkg) {
+        t.ifError(err);
+        t.equal(res, path.join(dir, '/xmodules/aaa/index.js'));
+    });
+
+    var bopts = {
+        basedir: dir,
+        moduleDirectory: ['zmodules', 'ymodules', 'xmodules']
+    };
+    resolve('aaa', bopts, function (err, res, pkg) {
+        t.ifError(err);
+        t.equal(res, path.join(dir, '/ymodules/aaa/index.js'));
+    });
+
+    var copts = {
+        basedir: dir,
+        moduleDirectory: ['xmodules', 'ymodules', 'zmodules']
+    };
+    resolve('bbb', copts, function (err, res, pkg) {
+        t.ifError(err);
+        t.equal(res, path.join(dir, '/zmodules/bbb/main.js'));
+    });
+});
diff --git a/server/node_modules/resolve/test/module_dir/xmodules/aaa/index.js b/server/node_modules/resolve/test/module_dir/xmodules/aaa/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..dd7cf7b2d022daae3c3f7628fcfb2f8bf186efac
--- /dev/null
+++ b/server/node_modules/resolve/test/module_dir/xmodules/aaa/index.js
@@ -0,0 +1 @@
+module.exports = function (x) { return x * 100; };
diff --git a/server/node_modules/resolve/test/module_dir/ymodules/aaa/index.js b/server/node_modules/resolve/test/module_dir/ymodules/aaa/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..ef2d4d4bf76e61fdfe16ef406c9752c6435138f3
--- /dev/null
+++ b/server/node_modules/resolve/test/module_dir/ymodules/aaa/index.js
@@ -0,0 +1 @@
+module.exports = function (x) { return x + 100; };
diff --git a/server/node_modules/resolve/test/module_dir/zmodules/bbb/main.js b/server/node_modules/resolve/test/module_dir/zmodules/bbb/main.js
new file mode 100644
index 0000000000000000000000000000000000000000..e8ba629936a7ad11134ac826edfad2379759c7cb
--- /dev/null
+++ b/server/node_modules/resolve/test/module_dir/zmodules/bbb/main.js
@@ -0,0 +1 @@
+module.exports = function (n) { return n * 111; };
diff --git a/server/node_modules/resolve/test/module_dir/zmodules/bbb/package.json b/server/node_modules/resolve/test/module_dir/zmodules/bbb/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..c13b8cf6acfd3344bc2c7969a31d930d933fdf22
--- /dev/null
+++ b/server/node_modules/resolve/test/module_dir/zmodules/bbb/package.json
@@ -0,0 +1,3 @@
+{
+  "main": "main.js"
+}
diff --git a/server/node_modules/resolve/test/node-modules-paths.js b/server/node_modules/resolve/test/node-modules-paths.js
new file mode 100644
index 0000000000000000000000000000000000000000..675441db2ced7b7facac9b7344fe8ea98c16e45b
--- /dev/null
+++ b/server/node_modules/resolve/test/node-modules-paths.js
@@ -0,0 +1,143 @@
+var test = require('tape');
+var path = require('path');
+var parse = path.parse || require('path-parse');
+var keys = require('object-keys');
+
+var nodeModulesPaths = require('../lib/node-modules-paths');
+
+var verifyDirs = function verifyDirs(t, start, dirs, moduleDirectories, paths) {
+    var moduleDirs = [].concat(moduleDirectories || 'node_modules');
+    if (paths) {
+        for (var k = 0; k < paths.length; ++k) {
+            moduleDirs.push(path.basename(paths[k]));
+        }
+    }
+
+    var foundModuleDirs = {};
+    var uniqueDirs = {};
+    var parsedDirs = {};
+    for (var i = 0; i < dirs.length; ++i) {
+        var parsed = parse(dirs[i]);
+        if (!foundModuleDirs[parsed.base]) { foundModuleDirs[parsed.base] = 0; }
+        foundModuleDirs[parsed.base] += 1;
+        parsedDirs[parsed.dir] = true;
+        uniqueDirs[dirs[i]] = true;
+    }
+    t.equal(keys(parsedDirs).length >= start.split(path.sep).length, true, 'there are >= dirs than "start" has');
+    var foundModuleDirNames = keys(foundModuleDirs);
+    t.deepEqual(foundModuleDirNames, moduleDirs, 'all desired module dirs were found');
+    t.equal(keys(uniqueDirs).length, dirs.length, 'all dirs provided were unique');
+
+    var counts = {};
+    for (var j = 0; j < foundModuleDirNames.length; ++j) {
+        counts[foundModuleDirs[j]] = true;
+    }
+    t.equal(keys(counts).length, 1, 'all found module directories had the same count');
+};
+
+test('node-modules-paths', function (t) {
+    t.test('no options', function (t) {
+        var start = path.join(__dirname, 'resolver');
+        var dirs = nodeModulesPaths(start);
+
+        verifyDirs(t, start, dirs);
+
+        t.end();
+    });
+
+    t.test('empty options', function (t) {
+        var start = path.join(__dirname, 'resolver');
+        var dirs = nodeModulesPaths(start, {});
+
+        verifyDirs(t, start, dirs);
+
+        t.end();
+    });
+
+    t.test('with paths=array option', function (t) {
+        var start = path.join(__dirname, 'resolver');
+        var paths = ['a', 'b'];
+        var dirs = nodeModulesPaths(start, { paths: paths });
+
+        verifyDirs(t, start, dirs, null, paths);
+
+        t.end();
+    });
+
+    t.test('with paths=function option', function (t) {
+        var paths = function paths(request, absoluteStart, getNodeModulesDirs, opts) {
+            return getNodeModulesDirs().concat(path.join(absoluteStart, 'not node modules', request));
+        };
+
+        var start = path.join(__dirname, 'resolver');
+        var dirs = nodeModulesPaths(start, { paths: paths }, 'pkg');
+
+        verifyDirs(t, start, dirs, null, [path.join(start, 'not node modules', 'pkg')]);
+
+        t.end();
+    });
+
+    t.test('with paths=function skipping node modules resolution', function (t) {
+        var paths = function paths(request, absoluteStart, getNodeModulesDirs, opts) {
+            return [];
+        };
+        var start = path.join(__dirname, 'resolver');
+        var dirs = nodeModulesPaths(start, { paths: paths });
+        t.deepEqual(dirs, [], 'no node_modules was computed');
+        t.end();
+    });
+
+    t.test('with moduleDirectory option', function (t) {
+        var start = path.join(__dirname, 'resolver');
+        var moduleDirectory = 'not node modules';
+        var dirs = nodeModulesPaths(start, { moduleDirectory: moduleDirectory });
+
+        verifyDirs(t, start, dirs, moduleDirectory);
+
+        t.end();
+    });
+
+    t.test('with 1 moduleDirectory and paths options', function (t) {
+        var start = path.join(__dirname, 'resolver');
+        var paths = ['a', 'b'];
+        var moduleDirectory = 'not node modules';
+        var dirs = nodeModulesPaths(start, { paths: paths, moduleDirectory: moduleDirectory });
+
+        verifyDirs(t, start, dirs, moduleDirectory, paths);
+
+        t.end();
+    });
+
+    t.test('with 1+ moduleDirectory and paths options', function (t) {
+        var start = path.join(__dirname, 'resolver');
+        var paths = ['a', 'b'];
+        var moduleDirectories = ['not node modules', 'other modules'];
+        var dirs = nodeModulesPaths(start, { paths: paths, moduleDirectory: moduleDirectories });
+
+        verifyDirs(t, start, dirs, moduleDirectories, paths);
+
+        t.end();
+    });
+
+    t.test('combine paths correctly on Windows', function (t) {
+        var start = 'C:\\Users\\username\\myProject\\src';
+        var paths = [];
+        var moduleDirectories = ['node_modules', start];
+        var dirs = nodeModulesPaths(start, { paths: paths, moduleDirectory: moduleDirectories });
+
+        t.equal(dirs.indexOf(path.resolve(start)) > -1, true, 'should contain start dir');
+
+        t.end();
+    });
+
+    t.test('combine paths correctly on non-Windows', { skip: process.platform === 'win32' }, function (t) {
+        var start = '/Users/username/git/myProject/src';
+        var paths = [];
+        var moduleDirectories = ['node_modules', '/Users/username/git/myProject/src'];
+        var dirs = nodeModulesPaths(start, { paths: paths, moduleDirectory: moduleDirectories });
+
+        t.equal(dirs.indexOf(path.resolve(start)) > -1, true, 'should contain start dir');
+
+        t.end();
+    });
+});
diff --git a/server/node_modules/resolve/test/node_path.js b/server/node_modules/resolve/test/node_path.js
new file mode 100644
index 0000000000000000000000000000000000000000..d06aa4eafe5b523d118bce692c972bf75ec983a9
--- /dev/null
+++ b/server/node_modules/resolve/test/node_path.js
@@ -0,0 +1,70 @@
+var fs = require('fs');
+var path = require('path');
+var test = require('tape');
+var resolve = require('../');
+
+test('$NODE_PATH', function (t) {
+    t.plan(8);
+
+    var isDir = function (dir, cb) {
+        if (dir === '/node_path' || dir === 'node_path/x') {
+            return cb(null, true);
+        }
+        fs.stat(dir, function (err, stat) {
+            if (!err) {
+                return cb(null, stat.isDirectory());
+            }
+            if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false);
+            return cb(err);
+        });
+    };
+
+    resolve('aaa', {
+        paths: [
+            path.join(__dirname, '/node_path/x'),
+            path.join(__dirname, '/node_path/y')
+        ],
+        basedir: __dirname,
+        isDirectory: isDir
+    }, function (err, res) {
+        t.error(err);
+        t.equal(res, path.join(__dirname, '/node_path/x/aaa/index.js'), 'aaa resolves');
+    });
+
+    resolve('bbb', {
+        paths: [
+            path.join(__dirname, '/node_path/x'),
+            path.join(__dirname, '/node_path/y')
+        ],
+        basedir: __dirname,
+        isDirectory: isDir
+    }, function (err, res) {
+        t.error(err);
+        t.equal(res, path.join(__dirname, '/node_path/y/bbb/index.js'), 'bbb resolves');
+    });
+
+    resolve('ccc', {
+        paths: [
+            path.join(__dirname, '/node_path/x'),
+            path.join(__dirname, '/node_path/y')
+        ],
+        basedir: __dirname,
+        isDirectory: isDir
+    }, function (err, res) {
+        t.error(err);
+        t.equal(res, path.join(__dirname, '/node_path/x/ccc/index.js'), 'ccc resolves');
+    });
+
+    // ensure that relative paths still resolve against the regular `node_modules` correctly
+    resolve('tap', {
+        paths: [
+            'node_path'
+        ],
+        basedir: path.join(__dirname, 'node_path/x'),
+        isDirectory: isDir
+    }, function (err, res) {
+        var root = require('tap/package.json').main;
+        t.error(err);
+        t.equal(res, path.resolve(__dirname, '..', 'node_modules/tap', root), 'tap resolves');
+    });
+});
diff --git a/server/node_modules/resolve/test/node_path/x/aaa/index.js b/server/node_modules/resolve/test/node_path/x/aaa/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..ad70d0bb03f6f433224a681f9055fe9d0a388dfc
--- /dev/null
+++ b/server/node_modules/resolve/test/node_path/x/aaa/index.js
@@ -0,0 +1 @@
+module.exports = 'A';
diff --git a/server/node_modules/resolve/test/node_path/x/ccc/index.js b/server/node_modules/resolve/test/node_path/x/ccc/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..a64132e4c7e52cfea76744d826e99932e994c7c1
--- /dev/null
+++ b/server/node_modules/resolve/test/node_path/x/ccc/index.js
@@ -0,0 +1 @@
+module.exports = 'C';
diff --git a/server/node_modules/resolve/test/node_path/y/bbb/index.js b/server/node_modules/resolve/test/node_path/y/bbb/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d0f32e24368185d6f3c16445f88b902329025d6
--- /dev/null
+++ b/server/node_modules/resolve/test/node_path/y/bbb/index.js
@@ -0,0 +1 @@
+module.exports = 'B';
diff --git a/server/node_modules/resolve/test/node_path/y/ccc/index.js b/server/node_modules/resolve/test/node_path/y/ccc/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..793315e846687e1dd2bae012fc30676b2a421753
--- /dev/null
+++ b/server/node_modules/resolve/test/node_path/y/ccc/index.js
@@ -0,0 +1 @@
+module.exports = 'CY';
diff --git a/server/node_modules/resolve/test/nonstring.js b/server/node_modules/resolve/test/nonstring.js
new file mode 100644
index 0000000000000000000000000000000000000000..ef63c40f9393dc63219d5e3debb7ed6db175c455
--- /dev/null
+++ b/server/node_modules/resolve/test/nonstring.js
@@ -0,0 +1,9 @@
+var test = require('tape');
+var resolve = require('../');
+
+test('nonstring', function (t) {
+    t.plan(1);
+    resolve(555, function (err, res, pkg) {
+        t.ok(err);
+    });
+});
diff --git a/server/node_modules/resolve/test/pathfilter.js b/server/node_modules/resolve/test/pathfilter.js
new file mode 100644
index 0000000000000000000000000000000000000000..16519aeae51c4fb65b8ccdd69f303a2315358ef3
--- /dev/null
+++ b/server/node_modules/resolve/test/pathfilter.js
@@ -0,0 +1,75 @@
+var path = require('path');
+var test = require('tape');
+var resolve = require('../');
+
+var resolverDir = path.join(__dirname, '/pathfilter/deep_ref');
+
+var pathFilterFactory = function (t) {
+    return function (pkg, x, remainder) {
+        t.equal(pkg.version, '1.2.3');
+        t.equal(x, path.join(resolverDir, 'node_modules/deep/ref'));
+        t.equal(remainder, 'ref');
+        return 'alt';
+    };
+};
+
+test('#62: deep module references and the pathFilter', function (t) {
+    t.test('deep/ref.js', function (st) {
+        st.plan(3);
+
+        resolve('deep/ref', { basedir: resolverDir }, function (err, res, pkg) {
+            if (err) st.fail(err);
+
+            st.equal(pkg.version, '1.2.3');
+            st.equal(res, path.join(resolverDir, 'node_modules/deep/ref.js'));
+        });
+
+        var res = resolve.sync('deep/ref', { basedir: resolverDir });
+        st.equal(res, path.join(resolverDir, 'node_modules/deep/ref.js'));
+    });
+
+    t.test('deep/deeper/ref', function (st) {
+        st.plan(4);
+
+        resolve(
+            'deep/deeper/ref',
+            { basedir: resolverDir },
+            function (err, res, pkg) {
+                if (err) t.fail(err);
+                st.notEqual(pkg, undefined);
+                st.equal(pkg.version, '1.2.3');
+                st.equal(res, path.join(resolverDir, 'node_modules/deep/deeper/ref.js'));
+            }
+        );
+
+        var res = resolve.sync(
+            'deep/deeper/ref',
+            { basedir: resolverDir }
+        );
+        st.equal(res, path.join(resolverDir, 'node_modules/deep/deeper/ref.js'));
+    });
+
+    t.test('deep/ref alt', function (st) {
+        st.plan(8);
+
+        var pathFilter = pathFilterFactory(st);
+
+        var res = resolve.sync(
+            'deep/ref',
+            { basedir: resolverDir, pathFilter: pathFilter }
+        );
+        st.equal(res, path.join(resolverDir, 'node_modules/deep/alt.js'));
+
+        resolve(
+            'deep/ref',
+            { basedir: resolverDir, pathFilter: pathFilter },
+            function (err, res, pkg) {
+                if (err) st.fail(err);
+                st.equal(res, path.join(resolverDir, 'node_modules/deep/alt.js'));
+                st.end();
+            }
+        );
+    });
+
+    t.end();
+});
diff --git a/server/node_modules/resolve/test/pathfilter/deep_ref/main.js b/server/node_modules/resolve/test/pathfilter/deep_ref/main.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/precedence.js b/server/node_modules/resolve/test/precedence.js
new file mode 100644
index 0000000000000000000000000000000000000000..2febb598fbc06832ce5b076735cb9f79fb257c7c
--- /dev/null
+++ b/server/node_modules/resolve/test/precedence.js
@@ -0,0 +1,23 @@
+var path = require('path');
+var test = require('tape');
+var resolve = require('../');
+
+test('precedence', function (t) {
+    t.plan(3);
+    var dir = path.join(__dirname, 'precedence/aaa');
+
+    resolve('./', { basedir: dir }, function (err, res, pkg) {
+        t.ifError(err);
+        t.equal(res, path.join(dir, 'index.js'));
+        t.equal(pkg.name, 'resolve');
+    });
+});
+
+test('./ should not load ${dir}.js', function (t) { // eslint-disable-line no-template-curly-in-string
+    t.plan(1);
+    var dir = path.join(__dirname, 'precedence/bbb');
+
+    resolve('./', { basedir: dir }, function (err, res, pkg) {
+        t.ok(err);
+    });
+});
diff --git a/server/node_modules/resolve/test/precedence/aaa.js b/server/node_modules/resolve/test/precedence/aaa.js
new file mode 100644
index 0000000000000000000000000000000000000000..b83a3e7ad98d17536ebc574326276c0fe341b99a
--- /dev/null
+++ b/server/node_modules/resolve/test/precedence/aaa.js
@@ -0,0 +1 @@
+module.exports = 'wtf';
diff --git a/server/node_modules/resolve/test/precedence/aaa/index.js b/server/node_modules/resolve/test/precedence/aaa/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..e0f8f6abf72f7fe517abf6c57fae219b831b1cc9
--- /dev/null
+++ b/server/node_modules/resolve/test/precedence/aaa/index.js
@@ -0,0 +1 @@
+module.exports = 'okok';
diff --git a/server/node_modules/resolve/test/precedence/aaa/main.js b/server/node_modules/resolve/test/precedence/aaa/main.js
new file mode 100644
index 0000000000000000000000000000000000000000..93542a965e0ea4fa1a548dcb4491e1defd73afe0
--- /dev/null
+++ b/server/node_modules/resolve/test/precedence/aaa/main.js
@@ -0,0 +1 @@
+console.log(require('./'));
diff --git a/server/node_modules/resolve/test/precedence/bbb.js b/server/node_modules/resolve/test/precedence/bbb.js
new file mode 100644
index 0000000000000000000000000000000000000000..2298f47fdd16dcc8375b62d1a15109a5833da926
--- /dev/null
+++ b/server/node_modules/resolve/test/precedence/bbb.js
@@ -0,0 +1 @@
+module.exports = '>_<';
diff --git a/server/node_modules/resolve/test/precedence/bbb/main.js b/server/node_modules/resolve/test/precedence/bbb/main.js
new file mode 100644
index 0000000000000000000000000000000000000000..716b81d4bd463f66980f3cb44588b283bfb23edc
--- /dev/null
+++ b/server/node_modules/resolve/test/precedence/bbb/main.js
@@ -0,0 +1 @@
+console.log(require('./')); // should throw
diff --git a/server/node_modules/resolve/test/resolver.js b/server/node_modules/resolve/test/resolver.js
new file mode 100644
index 0000000000000000000000000000000000000000..4552f4fdf13b3e4bcb143d77018f215018b7d929
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver.js
@@ -0,0 +1,418 @@
+var path = require('path');
+var test = require('tape');
+var resolve = require('../');
+
+test('async foo', function (t) {
+    t.plan(12);
+    var dir = path.join(__dirname, 'resolver');
+
+    resolve('./foo', { basedir: dir }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'foo.js'));
+        t.equal(pkg && pkg.name, 'resolve');
+    });
+
+    resolve('./foo.js', { basedir: dir }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'foo.js'));
+        t.equal(pkg && pkg.name, 'resolve');
+    });
+
+    resolve('./foo', { basedir: dir, 'package': { main: 'resolver' } }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'foo.js'));
+        t.equal(pkg && pkg.main, 'resolver');
+    });
+
+    resolve('./foo.js', { basedir: dir, 'package': { main: 'resolver' } }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'foo.js'));
+        t.equal(pkg.main, 'resolver');
+    });
+
+    resolve('./foo', { basedir: dir, filename: path.join(dir, 'baz.js') }, function (err, res) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'foo.js'));
+    });
+
+    resolve('foo', { basedir: dir }, function (err) {
+        t.equal(err.message, "Cannot find module 'foo' from '" + path.resolve(dir) + "'");
+        t.equal(err.code, 'MODULE_NOT_FOUND');
+    });
+
+    // Test that filename is reported as the "from" value when passed.
+    resolve('foo', { basedir: dir, filename: path.join(dir, 'baz.js') }, function (err) {
+        t.equal(err.message, "Cannot find module 'foo' from '" + path.join(dir, 'baz.js') + "'");
+    });
+});
+
+test('bar', function (t) {
+    t.plan(6);
+    var dir = path.join(__dirname, 'resolver');
+
+    resolve('foo', { basedir: dir + '/bar' }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'bar/node_modules/foo/index.js'));
+        t.equal(pkg, undefined);
+    });
+
+    resolve('foo', { basedir: dir + '/bar' }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'bar/node_modules/foo/index.js'));
+        t.equal(pkg, undefined);
+    });
+
+    resolve('foo', { basedir: dir + '/bar', 'package': { main: 'bar' } }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'bar/node_modules/foo/index.js'));
+        t.equal(pkg.main, 'bar');
+    });
+});
+
+test('baz', function (t) {
+    t.plan(4);
+    var dir = path.join(__dirname, 'resolver');
+
+    resolve('./baz', { basedir: dir }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'baz/quux.js'));
+        t.equal(pkg.main, 'quux.js');
+    });
+
+    resolve('./baz', { basedir: dir, 'package': { main: 'resolver' } }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'baz/quux.js'));
+        t.equal(pkg.main, 'quux.js');
+    });
+});
+
+test('biz', function (t) {
+    t.plan(24);
+    var dir = path.join(__dirname, 'resolver/biz/node_modules');
+
+    resolve('./grux', { basedir: dir }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'grux/index.js'));
+        t.equal(pkg, undefined);
+    });
+
+    resolve('./grux', { basedir: dir, 'package': { main: 'biz' } }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'grux/index.js'));
+        t.equal(pkg.main, 'biz');
+    });
+
+    resolve('./garply', { basedir: dir }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'garply/lib/index.js'));
+        t.equal(pkg.main, './lib');
+    });
+
+    resolve('./garply', { basedir: dir, 'package': { main: 'biz' } }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'garply/lib/index.js'));
+        t.equal(pkg.main, './lib');
+    });
+
+    resolve('tiv', { basedir: dir + '/grux' }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'tiv/index.js'));
+        t.equal(pkg, undefined);
+    });
+
+    resolve('tiv', { basedir: dir + '/grux', 'package': { main: 'grux' } }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'tiv/index.js'));
+        t.equal(pkg.main, 'grux');
+    });
+
+    resolve('tiv', { basedir: dir + '/garply' }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'tiv/index.js'));
+        t.equal(pkg, undefined);
+    });
+
+    resolve('tiv', { basedir: dir + '/garply', 'package': { main: './lib' } }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'tiv/index.js'));
+        t.equal(pkg.main, './lib');
+    });
+
+    resolve('grux', { basedir: dir + '/tiv' }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'grux/index.js'));
+        t.equal(pkg, undefined);
+    });
+
+    resolve('grux', { basedir: dir + '/tiv', 'package': { main: 'tiv' } }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'grux/index.js'));
+        t.equal(pkg.main, 'tiv');
+    });
+
+    resolve('garply', { basedir: dir + '/tiv' }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'garply/lib/index.js'));
+        t.equal(pkg.main, './lib');
+    });
+
+    resolve('garply', { basedir: dir + '/tiv', 'package': { main: 'tiv' } }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'garply/lib/index.js'));
+        t.equal(pkg.main, './lib');
+    });
+});
+
+test('quux', function (t) {
+    t.plan(2);
+    var dir = path.join(__dirname, 'resolver/quux');
+
+    resolve('./foo', { basedir: dir, 'package': { main: 'quux' } }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'foo/index.js'));
+        t.equal(pkg.main, 'quux');
+    });
+});
+
+test('normalize', function (t) {
+    t.plan(2);
+    var dir = path.join(__dirname, 'resolver/biz/node_modules/grux');
+
+    resolve('../grux', { basedir: dir }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'index.js'));
+        t.equal(pkg, undefined);
+    });
+});
+
+test('cup', function (t) {
+    t.plan(5);
+    var dir = path.join(__dirname, 'resolver');
+
+    resolve('./cup', { basedir: dir, extensions: ['.js', '.coffee'] }, function (err, res) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'cup.coffee'));
+    });
+
+    resolve('./cup.coffee', { basedir: dir }, function (err, res) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'cup.coffee'));
+    });
+
+    resolve('./cup', { basedir: dir, extensions: ['.js'] }, function (err, res) {
+        t.equal(err.message, "Cannot find module './cup' from '" + path.resolve(dir) + "'");
+        t.equal(err.code, 'MODULE_NOT_FOUND');
+    });
+
+    // Test that filename is reported as the "from" value when passed.
+    resolve('./cup', { basedir: dir, extensions: ['.js'], filename: path.join(dir, 'cupboard.js') }, function (err, res) {
+        t.equal(err.message, "Cannot find module './cup' from '" + path.join(dir, 'cupboard.js') + "'");
+    });
+});
+
+test('mug', function (t) {
+    t.plan(3);
+    var dir = path.join(__dirname, 'resolver');
+
+    resolve('./mug', { basedir: dir }, function (err, res) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'mug.js'));
+    });
+
+    resolve('./mug', { basedir: dir, extensions: ['.coffee', '.js'] }, function (err, res) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, '/mug.coffee'));
+    });
+
+    resolve('./mug', { basedir: dir, extensions: ['.js', '.coffee'] }, function (err, res) {
+        t.equal(res, path.join(dir, '/mug.js'));
+    });
+});
+
+test('other path', function (t) {
+    t.plan(6);
+    var resolverDir = path.join(__dirname, 'resolver');
+    var dir = path.join(resolverDir, 'bar');
+    var otherDir = path.join(resolverDir, 'other_path');
+
+    resolve('root', { basedir: dir, paths: [otherDir] }, function (err, res) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(resolverDir, 'other_path/root.js'));
+    });
+
+    resolve('lib/other-lib', { basedir: dir, paths: [otherDir] }, function (err, res) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(resolverDir, 'other_path/lib/other-lib.js'));
+    });
+
+    resolve('root', { basedir: dir }, function (err, res) {
+        t.equal(err.message, "Cannot find module 'root' from '" + path.resolve(dir) + "'");
+        t.equal(err.code, 'MODULE_NOT_FOUND');
+    });
+
+    resolve('zzz', { basedir: dir, paths: [otherDir] }, function (err, res) {
+        t.equal(err.message, "Cannot find module 'zzz' from '" + path.resolve(dir) + "'");
+        t.equal(err.code, 'MODULE_NOT_FOUND');
+    });
+});
+
+test('incorrect main', function (t) {
+    t.plan(1);
+
+    var resolverDir = path.join(__dirname, 'resolver');
+    var dir = path.join(resolverDir, 'incorrect_main');
+
+    resolve('./incorrect_main', { basedir: resolverDir }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'index.js'));
+    });
+});
+
+test('without basedir', function (t) {
+    t.plan(1);
+
+    var dir = path.join(__dirname, 'resolver/without_basedir');
+    var tester = require(path.join(dir, 'main.js'));
+
+    tester(t, function (err, res, pkg) {
+        if (err) {
+            t.fail(err);
+        } else {
+            t.equal(res, path.join(dir, 'node_modules/mymodule.js'));
+        }
+    });
+});
+
+test('#52 - incorrectly resolves module-paths like "./someFolder/" when there is a file of the same name', function (t) {
+    t.plan(2);
+
+    var dir = path.join(__dirname, 'resolver');
+
+    resolve('./foo', { basedir: path.join(dir, 'same_names') }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'same_names/foo.js'));
+    });
+
+    resolve('./foo/', { basedir: path.join(dir, 'same_names') }, function (err, res, pkg) {
+        if (err) t.fail(err);
+        t.equal(res, path.join(dir, 'same_names/foo/index.js'));
+    });
+});
+
+test('async: #121 - treating an existing file as a dir when no basedir', function (t) {
+    var testFile = path.basename(__filename);
+
+    t.test('sanity check', function (st) {
+        st.plan(1);
+        resolve('./' + testFile, function (err, res, pkg) {
+            if (err) t.fail(err);
+            st.equal(res, __filename, 'sanity check');
+        });
+    });
+
+    t.test('with a fake directory', function (st) {
+        st.plan(4);
+
+        resolve('./' + testFile + '/blah', function (err, res, pkg) {
+            st.ok(err, 'there is an error');
+            st.notOk(res, 'no result');
+
+            st.equal(err && err.code, 'MODULE_NOT_FOUND', 'error code matches require.resolve');
+            st.equal(
+                err && err.message,
+                'Cannot find module \'./' + testFile + '/blah\' from \'' + __dirname + '\'',
+                'can not find nonexistent module'
+            );
+            st.end();
+        });
+    });
+
+    t.end();
+});
+
+test('async dot main', function (t) {
+    var start = new Date();
+    t.plan(3);
+    resolve('./resolver/dot_main', function (err, ret) {
+        t.notOk(err);
+        t.equal(ret, path.join(__dirname, 'resolver/dot_main/index.js'));
+        t.ok(new Date() - start < 50, 'resolve.sync timedout');
+        t.end();
+    });
+});
+
+test('async dot slash main', function (t) {
+    var start = new Date();
+    t.plan(3);
+    resolve('./resolver/dot_slash_main', function (err, ret) {
+        t.notOk(err);
+        t.equal(ret, path.join(__dirname, 'resolver/dot_slash_main/index.js'));
+        t.ok(new Date() - start < 50, 'resolve.sync timedout');
+        t.end();
+    });
+});
+
+test('not a directory', function (t) {
+    t.plan(6);
+    var path = './foo';
+    resolve(path, { basedir: __filename }, function (err, res, pkg) {
+        t.ok(err, 'a non-directory errors');
+        t.equal(arguments.length, 1);
+        t.equal(res, undefined);
+        t.equal(pkg, undefined);
+
+        t.equal(err && err.message, 'Cannot find module \'' + path + '\' from \'' + __filename + '\'');
+        t.equal(err && err.code, 'MODULE_NOT_FOUND');
+    });
+});
+
+test('non-string "main" field in package.json', function (t) {
+    t.plan(5);
+
+    var dir = path.join(__dirname, 'resolver');
+    resolve('./invalid_main', { basedir: dir }, function (err, res, pkg) {
+        t.ok(err, 'errors on non-string main');
+        t.equal(err.message, 'package “invalid main” `main` must be a string');
+        t.equal(err.code, 'INVALID_PACKAGE_MAIN');
+        t.equal(res, undefined, 'res is undefined');
+        t.equal(pkg, undefined, 'pkg is undefined');
+    });
+});
+
+test('non-string "main" field in package.json', function (t) {
+    t.plan(5);
+
+    var dir = path.join(__dirname, 'resolver');
+    resolve('./invalid_main', { basedir: dir }, function (err, res, pkg) {
+        t.ok(err, 'errors on non-string main');
+        t.equal(err.message, 'package “invalid main” `main` must be a string');
+        t.equal(err.code, 'INVALID_PACKAGE_MAIN');
+        t.equal(res, undefined, 'res is undefined');
+        t.equal(pkg, undefined, 'pkg is undefined');
+    });
+});
+
+test('browser field in package.json', function (t) {
+    t.plan(3);
+
+    var dir = path.join(__dirname, 'resolver');
+    resolve(
+        './browser_field',
+        {
+            basedir: dir,
+            packageFilter: function packageFilter(pkg) {
+                if (pkg.browser) {
+                    pkg.main = pkg.browser;
+                    delete pkg.browser;
+                }
+                return pkg;
+            }
+        },
+        function (err, res, pkg) {
+            if (err) t.fail(err);
+            t.equal(res, path.join(dir, 'browser_field', 'b.js'));
+            t.equal(pkg && pkg.main, 'b');
+            t.equal(pkg && pkg.browser, undefined);
+        }
+    );
+});
diff --git a/server/node_modules/resolve/test/resolver/baz/doom.js b/server/node_modules/resolve/test/resolver/baz/doom.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/resolver/baz/package.json b/server/node_modules/resolve/test/resolver/baz/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..c41e4dbf73d9976b49495acf3a4d1de451d852af
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/baz/package.json
@@ -0,0 +1,3 @@
+{
+    "main": "quux.js"
+}
diff --git a/server/node_modules/resolve/test/resolver/baz/quux.js b/server/node_modules/resolve/test/resolver/baz/quux.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd816eaba4ca3be8e4d68cfc0ae9f64b5aa712cc
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/baz/quux.js
@@ -0,0 +1 @@
+module.exports = 1;
diff --git a/server/node_modules/resolve/test/resolver/browser_field/a.js b/server/node_modules/resolve/test/resolver/browser_field/a.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/resolver/browser_field/b.js b/server/node_modules/resolve/test/resolver/browser_field/b.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/resolver/browser_field/package.json b/server/node_modules/resolve/test/resolver/browser_field/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..bf406f0830f8aab6aaec9e3f60f1623fbe6854e6
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/browser_field/package.json
@@ -0,0 +1,5 @@
+{
+  "name": "browser_field",
+  "main": "a",
+  "browser": "b"
+}
diff --git a/server/node_modules/resolve/test/resolver/cup.coffee b/server/node_modules/resolve/test/resolver/cup.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/cup.coffee
@@ -0,0 +1 @@
+
diff --git a/server/node_modules/resolve/test/resolver/dot_main/index.js b/server/node_modules/resolve/test/resolver/dot_main/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd816eaba4ca3be8e4d68cfc0ae9f64b5aa712cc
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/dot_main/index.js
@@ -0,0 +1 @@
+module.exports = 1;
diff --git a/server/node_modules/resolve/test/resolver/dot_main/package.json b/server/node_modules/resolve/test/resolver/dot_main/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..d7f4fc8079f60aaee820b293537b21d488a1bc31
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/dot_main/package.json
@@ -0,0 +1,3 @@
+{
+    "main": "."
+}
diff --git a/server/node_modules/resolve/test/resolver/dot_slash_main/index.js b/server/node_modules/resolve/test/resolver/dot_slash_main/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd816eaba4ca3be8e4d68cfc0ae9f64b5aa712cc
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/dot_slash_main/index.js
@@ -0,0 +1 @@
+module.exports = 1;
diff --git a/server/node_modules/resolve/test/resolver/dot_slash_main/package.json b/server/node_modules/resolve/test/resolver/dot_slash_main/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..f51287b9d1e739a8827578a541e89f7e91450615
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/dot_slash_main/package.json
@@ -0,0 +1,3 @@
+{
+    "main": "./"
+}
diff --git a/server/node_modules/resolve/test/resolver/foo.js b/server/node_modules/resolve/test/resolver/foo.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd816eaba4ca3be8e4d68cfc0ae9f64b5aa712cc
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/foo.js
@@ -0,0 +1 @@
+module.exports = 1;
diff --git a/server/node_modules/resolve/test/resolver/incorrect_main/index.js b/server/node_modules/resolve/test/resolver/incorrect_main/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..bc1fb0a6f4ede17ec05e767ca8ccacbc3015ff70
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/incorrect_main/index.js
@@ -0,0 +1,2 @@
+// this is the actual main file 'index.js', not 'wrong.js' like the package.json would indicate
+module.exports = 1;
diff --git a/server/node_modules/resolve/test/resolver/incorrect_main/package.json b/server/node_modules/resolve/test/resolver/incorrect_main/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..b7188041763f8a94977f173a26c41fdbf5f2effb
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/incorrect_main/package.json
@@ -0,0 +1,3 @@
+{
+    "main": "wrong.js"
+}
diff --git a/server/node_modules/resolve/test/resolver/invalid_main/package.json b/server/node_modules/resolve/test/resolver/invalid_main/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..0cf8279950c380b3fd028ff826e752eeb62ea533
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/invalid_main/package.json
@@ -0,0 +1,7 @@
+{
+  "name": "invalid main",
+  "main": [
+    "why is this a thing",
+    "srsly omg wtf"
+  ]
+}
diff --git a/server/node_modules/resolve/test/resolver/mug.coffee b/server/node_modules/resolve/test/resolver/mug.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/resolver/mug.js b/server/node_modules/resolve/test/resolver/mug.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/resolver/multirepo/lerna.json b/server/node_modules/resolve/test/resolver/multirepo/lerna.json
new file mode 100644
index 0000000000000000000000000000000000000000..d6707ca0cd64d48d212b90abe2e72f24b092572f
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/multirepo/lerna.json
@@ -0,0 +1,6 @@
+{
+  "packages": [
+    "packages/*"
+  ],
+  "version": "0.0.0"
+}
diff --git a/server/node_modules/resolve/test/resolver/multirepo/package.json b/server/node_modules/resolve/test/resolver/multirepo/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..8508f9d2c4a2d7f3dfae7f02aac88f0f38b4ece8
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/multirepo/package.json
@@ -0,0 +1,20 @@
+{
+  "name": "monorepo-symlink-test",
+  "private": true,
+  "version": "0.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "postinstall": "lerna bootstrap",
+    "test": "node packages/package-a"
+  },
+  "author": "",
+  "license": "MIT",
+  "dependencies": {
+    "jquery": "^3.3.1",
+    "resolve": "../../../"
+  },
+  "devDependencies": {
+    "lerna": "^3.4.3"
+  }
+}
diff --git a/server/node_modules/resolve/test/resolver/multirepo/packages/package-a/index.js b/server/node_modules/resolve/test/resolver/multirepo/packages/package-a/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..8875a32df0ffc4eda94bb6c6dd9855ac604820c4
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/multirepo/packages/package-a/index.js
@@ -0,0 +1,35 @@
+'use strict';
+
+var assert = require('assert');
+var path = require('path');
+var resolve = require('resolve');
+
+var basedir = __dirname + '/node_modules/@my-scope/package-b';
+
+var expected = path.join(__dirname, '../../node_modules/jquery/dist/jquery.js');
+
+/*
+ * preserveSymlinks === false
+ * will search NPM package from
+ * - packages/package-b/node_modules
+ * - packages/node_modules
+ * - node_modules
+ */
+assert.equal(resolve.sync('jquery', { basedir: basedir, preserveSymlinks: false }), expected);
+assert.equal(resolve.sync('../../node_modules/jquery', { basedir: basedir, preserveSymlinks: false }), expected);
+
+/*
+ * preserveSymlinks === true
+ * will search NPM package from
+ * - packages/package-a/node_modules/@my-scope/packages/package-b/node_modules
+ * - packages/package-a/node_modules/@my-scope/packages/node_modules
+ * - packages/package-a/node_modules/@my-scope/node_modules
+ * - packages/package-a/node_modules/node_modules
+ * - packages/package-a/node_modules
+ * - packages/node_modules
+ * - node_modules
+ */
+assert.equal(resolve.sync('jquery', { basedir: basedir, preserveSymlinks: true }), expected);
+assert.equal(resolve.sync('../../../../../node_modules/jquery', { basedir: basedir, preserveSymlinks: true }), expected);
+
+console.log(' * all monorepo paths successfully resolved through symlinks');
diff --git a/server/node_modules/resolve/test/resolver/multirepo/packages/package-a/package.json b/server/node_modules/resolve/test/resolver/multirepo/packages/package-a/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..204de51e05878b3451223ba654c5e4a790ef1e51
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/multirepo/packages/package-a/package.json
@@ -0,0 +1,14 @@
+{
+  "name": "@my-scope/package-a",
+  "version": "0.0.0",
+  "private": true,
+  "description": "",
+  "license": "MIT",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: run tests from root\" && exit 1"
+  },
+  "dependencies": {
+    "@my-scope/package-b": "^0.0.0"
+  }
+}
diff --git a/server/node_modules/resolve/test/resolver/multirepo/packages/package-b/index.js b/server/node_modules/resolve/test/resolver/multirepo/packages/package-b/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/resolver/multirepo/packages/package-b/package.json b/server/node_modules/resolve/test/resolver/multirepo/packages/package-b/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..f57c3b5f5e454d3948e1a4bc5aec10fdcd79d8b5
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/multirepo/packages/package-b/package.json
@@ -0,0 +1,14 @@
+{
+  "name": "@my-scope/package-b",
+  "private": true,
+  "version": "0.0.0",
+  "description": "",
+  "license": "MIT",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: run tests from root\" && exit 1"
+  },
+  "dependencies": {
+    "@my-scope/package-a": "^0.0.0"
+  }
+}
diff --git a/server/node_modules/resolve/test/resolver/nested_symlinks/mylib/async.js b/server/node_modules/resolve/test/resolver/nested_symlinks/mylib/async.js
new file mode 100644
index 0000000000000000000000000000000000000000..9b4846a82a77be169097f041f791070732229cb7
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/nested_symlinks/mylib/async.js
@@ -0,0 +1,26 @@
+var a = require.resolve('buffer/').replace(process.cwd(), '$CWD');
+var b;
+var c;
+
+var test = function test() {
+    console.log(a, ': require.resolve, preserveSymlinks ' + (process.execArgv.indexOf('preserve-symlinks') > -1 ? 'true' : 'false'));
+    console.log(b, ': preserveSymlinks true');
+    console.log(c, ': preserveSymlinks false');
+
+    if (a !== b && a !== c) {
+        throw 'async: no match';
+    }
+    console.log('async: success! a matched either b or c\n');
+};
+
+require('resolve')('buffer/', { preserveSymlinks: true }, function (err, result) {
+    if (err) { throw err; }
+    b = result.replace(process.cwd(), '$CWD');
+    if (b && c) { test(); }
+});
+require('resolve')('buffer/', { preserveSymlinks: false }, function (err, result) {
+    if (err) { throw err; }
+    c = result.replace(process.cwd(), '$CWD');
+    if (b && c) { test(); }
+});
+
diff --git a/server/node_modules/resolve/test/resolver/nested_symlinks/mylib/package.json b/server/node_modules/resolve/test/resolver/nested_symlinks/mylib/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..acfe9e9517720ab5532c247052fadb214c5ffef3
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/nested_symlinks/mylib/package.json
@@ -0,0 +1,15 @@
+{
+  "name": "mylib",
+  "version": "0.0.0",
+  "description": "",
+  "private": true,
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [],
+  "author": "",
+  "license": "ISC",
+  "dependencies": {
+    "buffer": "*"
+  }
+}
diff --git a/server/node_modules/resolve/test/resolver/nested_symlinks/mylib/sync.js b/server/node_modules/resolve/test/resolver/nested_symlinks/mylib/sync.js
new file mode 100644
index 0000000000000000000000000000000000000000..3283efc2ec81f8d2a62be9a1fd28a192403ce549
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/nested_symlinks/mylib/sync.js
@@ -0,0 +1,12 @@
+var a = require.resolve('buffer/').replace(process.cwd(), '$CWD');
+var b = require('resolve').sync('buffer/', { preserveSymlinks: true }).replace(process.cwd(), '$CWD');
+var c = require('resolve').sync('buffer/', { preserveSymlinks: false }).replace(process.cwd(), '$CWD');
+
+console.log(a, ': require.resolve, preserveSymlinks ' + (process.execArgv.indexOf('preserve-symlinks') > -1 ? 'true' : 'false'));
+console.log(b, ': preserveSymlinks true');
+console.log(c, ': preserveSymlinks false');
+
+if (a !== b && a !== c) {
+    throw 'sync: no match';
+}
+console.log('sync: success! a matched either b or c\n');
diff --git a/server/node_modules/resolve/test/resolver/other_path/lib/other-lib.js b/server/node_modules/resolve/test/resolver/other_path/lib/other-lib.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/resolver/other_path/root.js b/server/node_modules/resolve/test/resolver/other_path/root.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/resolver/quux/foo/index.js b/server/node_modules/resolve/test/resolver/quux/foo/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd816eaba4ca3be8e4d68cfc0ae9f64b5aa712cc
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/quux/foo/index.js
@@ -0,0 +1 @@
+module.exports = 1;
diff --git a/server/node_modules/resolve/test/resolver/same_names/foo.js b/server/node_modules/resolve/test/resolver/same_names/foo.js
new file mode 100644
index 0000000000000000000000000000000000000000..888cae37af95c51299d735439cf896dc4d5aaafc
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/same_names/foo.js
@@ -0,0 +1 @@
+module.exports = 42;
diff --git a/server/node_modules/resolve/test/resolver/same_names/foo/index.js b/server/node_modules/resolve/test/resolver/same_names/foo/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd816eaba4ca3be8e4d68cfc0ae9f64b5aa712cc
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/same_names/foo/index.js
@@ -0,0 +1 @@
+module.exports = 1;
diff --git a/server/node_modules/resolve/test/resolver/symlinked/_/node_modules/foo.js b/server/node_modules/resolve/test/resolver/symlinked/_/node_modules/foo.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/resolver/symlinked/_/symlink_target/.gitkeep b/server/node_modules/resolve/test/resolver/symlinked/_/symlink_target/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/resolver/symlinked/package/bar.js b/server/node_modules/resolve/test/resolver/symlinked/package/bar.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb1c2c01e753b31f6e550e991a82022f7acf8638
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/symlinked/package/bar.js
@@ -0,0 +1 @@
+module.exports = 'bar';
diff --git a/server/node_modules/resolve/test/resolver/symlinked/package/package.json b/server/node_modules/resolve/test/resolver/symlinked/package/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..8e1b585914a7b46cd21d5d8709ac08bc1fe84962
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/symlinked/package/package.json
@@ -0,0 +1,3 @@
+{
+    "main": "bar.js"
+}
\ No newline at end of file
diff --git a/server/node_modules/resolve/test/resolver/without_basedir/main.js b/server/node_modules/resolve/test/resolver/without_basedir/main.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b31975be69da5efea03fac676afa5f2199831be
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver/without_basedir/main.js
@@ -0,0 +1,5 @@
+var resolve = require('../../../');
+
+module.exports = function (t, cb) {
+    resolve('mymodule', null, cb);
+};
diff --git a/server/node_modules/resolve/test/resolver_sync.js b/server/node_modules/resolve/test/resolver_sync.js
new file mode 100644
index 0000000000000000000000000000000000000000..878e5896c84d4fd9e5c311b6333aa9213bd7c9f2
--- /dev/null
+++ b/server/node_modules/resolve/test/resolver_sync.js
@@ -0,0 +1,329 @@
+var path = require('path');
+var test = require('tape');
+var resolve = require('../');
+
+test('foo', function (t) {
+    var dir = path.join(__dirname, 'resolver');
+
+    t.equal(
+        resolve.sync('./foo', { basedir: dir }),
+        path.join(dir, 'foo.js')
+    );
+
+    t.equal(
+        resolve.sync('./foo.js', { basedir: dir }),
+        path.join(dir, 'foo.js')
+    );
+
+    t.equal(
+        resolve.sync('./foo.js', { basedir: dir, filename: path.join(dir, 'bar.js') }),
+        path.join(dir, 'foo.js')
+    );
+
+    t.throws(function () {
+        resolve.sync('foo', { basedir: dir });
+    });
+
+    // Test that filename is reported as the "from" value when passed.
+    t.throws(
+        function () {
+            resolve.sync('foo', { basedir: dir, filename: path.join(dir, 'bar.js') });
+        },
+        {
+            name: 'Error',
+            message: "Cannot find module 'foo' from '" + path.join(dir, 'bar.js') + "'"
+        }
+    );
+
+    t.end();
+});
+
+test('bar', function (t) {
+    var dir = path.join(__dirname, 'resolver');
+
+    t.equal(
+        resolve.sync('foo', { basedir: path.join(dir, 'bar') }),
+        path.join(dir, 'bar/node_modules/foo/index.js')
+    );
+    t.end();
+});
+
+test('baz', function (t) {
+    var dir = path.join(__dirname, 'resolver');
+
+    t.equal(
+        resolve.sync('./baz', { basedir: dir }),
+        path.join(dir, 'baz/quux.js')
+    );
+    t.end();
+});
+
+test('biz', function (t) {
+    var dir = path.join(__dirname, 'resolver/biz/node_modules');
+    t.equal(
+        resolve.sync('./grux', { basedir: dir }),
+        path.join(dir, 'grux/index.js')
+    );
+
+    t.equal(
+        resolve.sync('tiv', { basedir: path.join(dir, 'grux') }),
+        path.join(dir, 'tiv/index.js')
+    );
+
+    t.equal(
+        resolve.sync('grux', { basedir: path.join(dir, 'tiv') }),
+        path.join(dir, 'grux/index.js')
+    );
+    t.end();
+});
+
+test('normalize', function (t) {
+    var dir = path.join(__dirname, 'resolver/biz/node_modules/grux');
+    t.equal(
+        resolve.sync('../grux', { basedir: dir }),
+        path.join(dir, 'index.js')
+    );
+    t.end();
+});
+
+test('cup', function (t) {
+    var dir = path.join(__dirname, 'resolver');
+    t.equal(
+        resolve.sync('./cup', {
+            basedir: dir,
+            extensions: ['.js', '.coffee']
+        }),
+        path.join(dir, 'cup.coffee')
+    );
+
+    t.equal(
+        resolve.sync('./cup.coffee', { basedir: dir }),
+        path.join(dir, 'cup.coffee')
+    );
+
+    t.throws(function () {
+        resolve.sync('./cup', {
+            basedir: dir,
+            extensions: ['.js']
+        });
+    });
+
+    t.end();
+});
+
+test('mug', function (t) {
+    var dir = path.join(__dirname, 'resolver');
+    t.equal(
+        resolve.sync('./mug', { basedir: dir }),
+        path.join(dir, 'mug.js')
+    );
+
+    t.equal(
+        resolve.sync('./mug', {
+            basedir: dir,
+            extensions: ['.coffee', '.js']
+        }),
+        path.join(dir, 'mug.coffee')
+    );
+
+    t.equal(
+        resolve.sync('./mug', {
+            basedir: dir,
+            extensions: ['.js', '.coffee']
+        }),
+        path.join(dir, 'mug.js')
+    );
+
+    t.end();
+});
+
+test('other path', function (t) {
+    var resolverDir = path.join(__dirname, 'resolver');
+    var dir = path.join(resolverDir, 'bar');
+    var otherDir = path.join(resolverDir, 'other_path');
+
+    t.equal(
+        resolve.sync('root', {
+            basedir: dir,
+            paths: [otherDir]
+        }),
+        path.join(resolverDir, 'other_path/root.js')
+    );
+
+    t.equal(
+        resolve.sync('lib/other-lib', {
+            basedir: dir,
+            paths: [otherDir]
+        }),
+        path.join(resolverDir, 'other_path/lib/other-lib.js')
+    );
+
+    t.throws(function () {
+        resolve.sync('root', { basedir: dir });
+    });
+
+    t.throws(function () {
+        resolve.sync('zzz', {
+            basedir: dir,
+            paths: [otherDir]
+        });
+    });
+
+    t.end();
+});
+
+test('incorrect main', function (t) {
+    var resolverDir = path.join(__dirname, 'resolver');
+    var dir = path.join(resolverDir, 'incorrect_main');
+
+    t.equal(
+        resolve.sync('./incorrect_main', { basedir: resolverDir }),
+        path.join(dir, 'index.js')
+    );
+
+    t.end();
+});
+
+var stubStatSync = function stubStatSync(fn) {
+    var fs = require('fs');
+    var statSync = fs.statSync;
+    try {
+        fs.statSync = function () {
+            throw new EvalError('Unknown Error');
+        };
+        return fn();
+    } finally {
+        fs.statSync = statSync;
+    }
+};
+
+test('#79 - re-throw non ENOENT errors from stat', function (t) {
+    var dir = path.join(__dirname, 'resolver');
+
+    stubStatSync(function () {
+        t.throws(function () {
+            resolve.sync('foo', { basedir: dir });
+        }, /Unknown Error/);
+    });
+
+    t.end();
+});
+
+test('#52 - incorrectly resolves module-paths like "./someFolder/" when there is a file of the same name', function (t) {
+    var dir = path.join(__dirname, 'resolver');
+
+    t.equal(
+        resolve.sync('./foo', { basedir: path.join(dir, 'same_names') }),
+        path.join(dir, 'same_names/foo.js')
+    );
+    t.equal(
+        resolve.sync('./foo/', { basedir: path.join(dir, 'same_names') }),
+        path.join(dir, 'same_names/foo/index.js')
+    );
+    t.end();
+});
+
+test('sync: #121 - treating an existing file as a dir when no basedir', function (t) {
+    var testFile = path.basename(__filename);
+
+    t.test('sanity check', function (st) {
+        st.equal(
+            resolve.sync('./' + testFile),
+            __filename,
+            'sanity check'
+        );
+        st.end();
+    });
+
+    t.test('with a fake directory', function (st) {
+        function run() { return resolve.sync('./' + testFile + '/blah'); }
+
+        st.throws(run, 'throws an error');
+
+        try {
+            run();
+        } catch (e) {
+            st.equal(e.code, 'MODULE_NOT_FOUND', 'error code matches require.resolve');
+            st.equal(
+                e.message,
+                'Cannot find module \'./' + testFile + '/blah\' from \'' + __dirname + '\'',
+                'can not find nonexistent module'
+            );
+        }
+
+        st.end();
+    });
+
+    t.end();
+});
+
+test('sync dot main', function (t) {
+    var start = new Date();
+    t.equal(resolve.sync('./resolver/dot_main'), path.join(__dirname, 'resolver/dot_main/index.js'));
+    t.ok(new Date() - start < 50, 'resolve.sync timedout');
+    t.end();
+});
+
+test('sync dot slash main', function (t) {
+    var start = new Date();
+    t.equal(resolve.sync('./resolver/dot_slash_main'), path.join(__dirname, 'resolver/dot_slash_main/index.js'));
+    t.ok(new Date() - start < 50, 'resolve.sync timedout');
+    t.end();
+});
+
+test('not a directory', function (t) {
+    var path = './foo';
+    try {
+        resolve.sync(path, { basedir: __filename });
+        t.fail();
+    } catch (err) {
+        t.ok(err, 'a non-directory errors');
+        t.equal(err && err.message, 'Cannot find module \'' + path + "' from '" + __filename + "'");
+        t.equal(err && err.code, 'MODULE_NOT_FOUND');
+    }
+    t.end();
+});
+
+test('non-string "main" field in package.json', function (t) {
+    var dir = path.join(__dirname, 'resolver');
+    try {
+        var result = resolve.sync('./invalid_main', { basedir: dir });
+        t.equal(result, undefined, 'result should not exist');
+        t.fail('should not get here');
+    } catch (err) {
+        t.ok(err, 'errors on non-string main');
+        t.equal(err.message, 'package “invalid main” `main` must be a string');
+        t.equal(err.code, 'INVALID_PACKAGE_MAIN');
+    }
+    t.end();
+});
+
+test('non-string "main" field in package.json', function (t) {
+    var dir = path.join(__dirname, 'resolver');
+    try {
+        var result = resolve.sync('./invalid_main', { basedir: dir });
+        t.equal(result, undefined, 'result should not exist');
+        t.fail('should not get here');
+    } catch (err) {
+        t.ok(err, 'errors on non-string main');
+        t.equal(err.message, 'package “invalid main” `main` must be a string');
+        t.equal(err.code, 'INVALID_PACKAGE_MAIN');
+    }
+    t.end();
+});
+
+test('browser field in package.json', function (t) {
+    var dir = path.join(__dirname, 'resolver');
+    var res = resolve.sync('./browser_field', {
+        basedir: dir,
+        packageFilter: function packageFilter(pkg) {
+            if (pkg.browser) {
+                pkg.main = pkg.browser;
+                delete pkg.browser;
+            }
+            return pkg;
+        }
+    });
+    t.equal(res, path.join(dir, 'browser_field', 'b.js'));
+    t.end();
+});
diff --git a/server/node_modules/resolve/test/shadowed_core.js b/server/node_modules/resolve/test/shadowed_core.js
new file mode 100644
index 0000000000000000000000000000000000000000..98c52a760b966a09f99d58b0488f6330f7964ea4
--- /dev/null
+++ b/server/node_modules/resolve/test/shadowed_core.js
@@ -0,0 +1,38 @@
+var test = require('tape');
+var resolve = require('../');
+var path = require('path');
+
+test('shadowed core modules still return core module', function (t) {
+    t.plan(2);
+
+    resolve('util', { basedir: path.join(__dirname, 'shadowed_core') }, function (err, res) {
+        t.ifError(err);
+        t.equal(res, 'util');
+    });
+});
+
+test('shadowed core modules still return core module [sync]', function (t) {
+    t.plan(1);
+
+    var res = resolve.sync('util', { basedir: path.join(__dirname, 'shadowed_core') });
+
+    t.equal(res, 'util');
+});
+
+test('shadowed core modules return shadow when appending `/`', function (t) {
+    t.plan(2);
+
+    resolve('util/', { basedir: path.join(__dirname, 'shadowed_core') }, function (err, res) {
+        t.ifError(err);
+        t.equal(res, path.join(__dirname, 'shadowed_core/node_modules/util/index.js'));
+    });
+});
+
+test('shadowed core modules return shadow when appending `/` [sync]', function (t) {
+    t.plan(1);
+
+    var res = resolve.sync('util/', { basedir: path.join(__dirname, 'shadowed_core') });
+
+    t.equal(res, path.join(__dirname, 'shadowed_core/node_modules/util/index.js'));
+});
+
diff --git a/server/node_modules/resolve/test/shadowed_core/node_modules/util/index.js b/server/node_modules/resolve/test/shadowed_core/node_modules/util/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/server/node_modules/resolve/test/subdirs.js b/server/node_modules/resolve/test/subdirs.js
new file mode 100644
index 0000000000000000000000000000000000000000..b7b8450a9ef231940eca37b8fe951310147a9470
--- /dev/null
+++ b/server/node_modules/resolve/test/subdirs.js
@@ -0,0 +1,13 @@
+var test = require('tape');
+var resolve = require('../');
+var path = require('path');
+
+test('subdirs', function (t) {
+    t.plan(2);
+
+    var dir = path.join(__dirname, '/subdirs');
+    resolve('a/b/c/x.json', { basedir: dir }, function (err, res) {
+        t.ifError(err);
+        t.equal(res, path.join(dir, 'node_modules/a/b/c/x.json'));
+    });
+});
diff --git a/server/node_modules/resolve/test/symlinks.js b/server/node_modules/resolve/test/symlinks.js
new file mode 100644
index 0000000000000000000000000000000000000000..9b5a2548d06864d38552d571662bfc9305e325bb
--- /dev/null
+++ b/server/node_modules/resolve/test/symlinks.js
@@ -0,0 +1,84 @@
+var path = require('path');
+var fs = require('fs');
+var test = require('tape');
+var resolve = require('../');
+
+var symlinkDir = path.join(__dirname, 'resolver', 'symlinked', 'symlink');
+var packageDir = path.join(__dirname, 'resolver', 'symlinked', '_', 'node_modules', 'package');
+try {
+    fs.unlinkSync(symlinkDir);
+} catch (err) {}
+try {
+    fs.unlinkSync(packageDir);
+} catch (err) {}
+try {
+    fs.symlinkSync('./_/symlink_target', symlinkDir, 'dir');
+} catch (err) {
+    // if fails then it is probably on Windows and lets try to create a junction
+    fs.symlinkSync(path.join(__dirname, 'resolver', 'symlinked', '_', 'symlink_target') + '\\', symlinkDir, 'junction');
+}
+try {
+    fs.symlinkSync('../../package', packageDir, 'dir');
+} catch (err) {
+    // if fails then it is probably on Windows and lets try to create a junction
+    fs.symlinkSync(path.join(__dirname, '..', '..', 'package') + '\\', packageDir, 'junction');
+}
+
+test('symlink', function (t) {
+    t.plan(2);
+
+    resolve('foo', { basedir: symlinkDir, preserveSymlinks: false }, function (err, res, pkg) {
+        t.error(err);
+        t.equal(res, path.join(__dirname, 'resolver', 'symlinked', '_', 'node_modules', 'foo.js'));
+    });
+});
+
+test('sync symlink when preserveSymlinks = true', function (t) {
+    t.plan(4);
+
+    resolve('foo', { basedir: symlinkDir }, function (err, res, pkg) {
+        t.ok(err, 'there is an error');
+        t.notOk(res, 'no result');
+
+        t.equal(err && err.code, 'MODULE_NOT_FOUND', 'error code matches require.resolve');
+        t.equal(
+            err && err.message,
+            'Cannot find module \'foo\' from \'' + symlinkDir + '\'',
+            'can not find nonexistent module'
+        );
+    });
+});
+
+test('sync symlink', function (t) {
+    var start = new Date();
+    t.doesNotThrow(function () {
+        t.equal(resolve.sync('foo', { basedir: symlinkDir, preserveSymlinks: false }), path.join(__dirname, 'resolver', 'symlinked', '_', 'node_modules', 'foo.js'));
+    });
+    t.ok(new Date() - start < 50, 'resolve.sync timedout');
+    t.end();
+});
+
+test('sync symlink when preserveSymlinks = true', function (t) {
+    t.throws(function () {
+        resolve.sync('foo', { basedir: symlinkDir });
+    }, /Cannot find module 'foo'/);
+    t.end();
+});
+
+test('sync symlink from node_modules to other dir when preserveSymlinks = false', function (t) {
+    var basedir = path.join(__dirname, 'resolver', 'symlinked', '_');
+    var fn = resolve.sync('package', { basedir: basedir, preserveSymlinks: false });
+
+    t.equal(fn, path.resolve(__dirname, 'resolver/symlinked/package/bar.js'));
+    t.end();
+});
+
+test('async symlink from node_modules to other dir when preserveSymlinks = false', function (t) {
+    t.plan(2);
+    var basedir = path.join(__dirname, 'resolver', 'symlinked', '_');
+    resolve('package', { basedir: basedir, preserveSymlinks: false }, function (err, result) {
+        t.notOk(err, 'no error');
+        t.equal(result, path.resolve(__dirname, 'resolver/symlinked/package/bar.js'));
+        t.end();
+    });
+});
diff --git a/server/node_modules/spdx-correct/LICENSE b/server/node_modules/spdx-correct/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..d645695673349e3947e8e5ae42332d0ac3164cd7
--- /dev/null
+++ b/server/node_modules/spdx-correct/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/server/node_modules/spdx-correct/README.md b/server/node_modules/spdx-correct/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ab388cf9406486c7290beed1f252f0c1a21868c2
--- /dev/null
+++ b/server/node_modules/spdx-correct/README.md
@@ -0,0 +1,14 @@
+```javascript
+var correct = require('spdx-correct')
+var assert = require('assert')
+
+assert.equal(correct('mit'), 'MIT')
+
+assert.equal(correct('Apache 2'), 'Apache-2.0')
+
+assert(correct('No idea what license') === null)
+
+// disable upgrade option
+assert(correct('GPL-3.0'), 'GPL-3.0-or-later')
+assert(correct('GPL-3.0', { upgrade: false }), 'GPL-3.0')
+```
diff --git a/server/node_modules/spdx-correct/index.js b/server/node_modules/spdx-correct/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..8e0e5aeda48b9f3e20aae9c43677d8cbc7925a7b
--- /dev/null
+++ b/server/node_modules/spdx-correct/index.js
@@ -0,0 +1,343 @@
+/*
+Copyright spdx-correct.js contributors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+var parse = require('spdx-expression-parse')
+var spdxLicenseIds = require('spdx-license-ids')
+
+function valid (string) {
+  try {
+    parse(string)
+    return true
+  } catch (error) {
+    return false
+  }
+}
+
+// Common transpositions of license identifier acronyms
+var transpositions = [
+  ['APGL', 'AGPL'],
+  ['Gpl', 'GPL'],
+  ['GLP', 'GPL'],
+  ['APL', 'Apache'],
+  ['ISD', 'ISC'],
+  ['GLP', 'GPL'],
+  ['IST', 'ISC'],
+  ['Claude', 'Clause'],
+  [' or later', '+'],
+  [' International', ''],
+  ['GNU', 'GPL'],
+  ['GUN', 'GPL'],
+  ['+', ''],
+  ['GNU GPL', 'GPL'],
+  ['GNU/GPL', 'GPL'],
+  ['GNU GLP', 'GPL'],
+  ['GNU General Public License', 'GPL'],
+  ['Gnu public license', 'GPL'],
+  ['GNU Public License', 'GPL'],
+  ['GNU GENERAL PUBLIC LICENSE', 'GPL'],
+  ['MTI', 'MIT'],
+  ['Mozilla Public License', 'MPL'],
+  ['WTH', 'WTF'],
+  ['-License', '']
+]
+
+var TRANSPOSED = 0
+var CORRECT = 1
+
+// Simple corrections to nearly valid identifiers.
+var transforms = [
+  // e.g. 'mit'
+  function (argument) {
+    return argument.toUpperCase()
+  },
+  // e.g. 'MIT '
+  function (argument) {
+    return argument.trim()
+  },
+  // e.g. 'M.I.T.'
+  function (argument) {
+    return argument.replace(/\./g, '')
+  },
+  // e.g. 'Apache- 2.0'
+  function (argument) {
+    return argument.replace(/\s+/g, '')
+  },
+  // e.g. 'CC BY 4.0''
+  function (argument) {
+    return argument.replace(/\s+/g, '-')
+  },
+  // e.g. 'LGPLv2.1'
+  function (argument) {
+    return argument.replace('v', '-')
+  },
+  // e.g. 'Apache 2.0'
+  function (argument) {
+    return argument.replace(/,?\s*(\d)/, '-$1')
+  },
+  // e.g. 'GPL 2'
+  function (argument) {
+    return argument.replace(/,?\s*(\d)/, '-$1.0')
+  },
+  // e.g. 'Apache Version 2.0'
+  function (argument) {
+    return argument
+      .replace(/,?\s*(V\.|v\.|V|v|Version|version)\s*(\d)/, '-$2')
+  },
+  // e.g. 'Apache Version 2'
+  function (argument) {
+    return argument
+      .replace(/,?\s*(V\.|v\.|V|v|Version|version)\s*(\d)/, '-$2.0')
+  },
+  // e.g. 'ZLIB'
+  function (argument) {
+    return argument[0].toUpperCase() + argument.slice(1)
+  },
+  // e.g. 'MPL/2.0'
+  function (argument) {
+    return argument.replace('/', '-')
+  },
+  // e.g. 'Apache 2'
+  function (argument) {
+    return argument
+      .replace(/\s*V\s*(\d)/, '-$1')
+      .replace(/(\d)$/, '$1.0')
+  },
+  // e.g. 'GPL-2.0', 'GPL-3.0'
+  function (argument) {
+    if (argument.indexOf('3.0') !== -1) {
+      return argument + '-or-later'
+    } else {
+      return argument + '-only'
+    }
+  },
+  // e.g. 'GPL-2.0-'
+  function (argument) {
+    return argument + 'only'
+  },
+  // e.g. 'GPL2'
+  function (argument) {
+    return argument.replace(/(\d)$/, '-$1.0')
+  },
+  // e.g. 'BSD 3'
+  function (argument) {
+    return argument.replace(/(-| )?(\d)$/, '-$2-Clause')
+  },
+  // e.g. 'BSD clause 3'
+  function (argument) {
+    return argument.replace(/(-| )clause(-| )(\d)/, '-$3-Clause')
+  },
+  // e.g. 'BY-NC-4.0'
+  function (argument) {
+    return 'CC-' + argument
+  },
+  // e.g. 'BY-NC'
+  function (argument) {
+    return 'CC-' + argument + '-4.0'
+  },
+  // e.g. 'Attribution-NonCommercial'
+  function (argument) {
+    return argument
+      .replace('Attribution', 'BY')
+      .replace('NonCommercial', 'NC')
+      .replace('NoDerivatives', 'ND')
+      .replace(/ (\d)/, '-$1')
+      .replace(/ ?International/, '')
+  },
+  // e.g. 'Attribution-NonCommercial'
+  function (argument) {
+    return 'CC-' +
+      argument
+        .replace('Attribution', 'BY')
+        .replace('NonCommercial', 'NC')
+        .replace('NoDerivatives', 'ND')
+        .replace(/ (\d)/, '-$1')
+        .replace(/ ?International/, '') +
+      '-4.0'
+  }
+]
+
+var licensesWithVersions = spdxLicenseIds
+  .map(function (id) {
+    var match = /^(.*)-\d+\.\d+$/.exec(id)
+    return match
+      ? [match[0], match[1]]
+      : [id, null]
+  })
+  .reduce(function (objectMap, item) {
+    var key = item[1]
+    objectMap[key] = objectMap[key] || []
+    objectMap[key].push(item[0])
+    return objectMap
+  }, {})
+
+var licensesWithOneVersion = Object.keys(licensesWithVersions)
+  .map(function makeEntries (key) {
+    return [key, licensesWithVersions[key]]
+  })
+  .filter(function identifySoleVersions (item) {
+    return (
+      // Licenses has just one valid version suffix.
+      item[1].length === 1 &&
+      item[0] !== null &&
+      // APL will be considered Apache, rather than APL-1.0
+      item[0] !== 'APL'
+    )
+  })
+  .map(function createLastResorts (item) {
+    return [item[0], item[1][0]]
+  })
+
+licensesWithVersions = undefined
+
+// If all else fails, guess that strings containing certain substrings
+// meant to identify certain licenses.
+var lastResorts = [
+  ['UNLI', 'Unlicense'],
+  ['WTF', 'WTFPL'],
+  ['2 CLAUSE', 'BSD-2-Clause'],
+  ['2-CLAUSE', 'BSD-2-Clause'],
+  ['3 CLAUSE', 'BSD-3-Clause'],
+  ['3-CLAUSE', 'BSD-3-Clause'],
+  ['AFFERO', 'AGPL-3.0-or-later'],
+  ['AGPL', 'AGPL-3.0-or-later'],
+  ['APACHE', 'Apache-2.0'],
+  ['ARTISTIC', 'Artistic-2.0'],
+  ['Affero', 'AGPL-3.0-or-later'],
+  ['BEER', 'Beerware'],
+  ['BOOST', 'BSL-1.0'],
+  ['BSD', 'BSD-2-Clause'],
+  ['CDDL', 'CDDL-1.1'],
+  ['ECLIPSE', 'EPL-1.0'],
+  ['FUCK', 'WTFPL'],
+  ['GNU', 'GPL-3.0-or-later'],
+  ['LGPL', 'LGPL-3.0-or-later'],
+  ['GPLV1', 'GPL-1.0-only'],
+  ['GPL-1', 'GPL-1.0-only'],
+  ['GPLV2', 'GPL-2.0-only'],
+  ['GPL-2', 'GPL-2.0-only'],
+  ['GPL', 'GPL-3.0-or-later'],
+  ['MIT +NO-FALSE-ATTRIBS', 'MITNFA'],
+  ['MIT', 'MIT'],
+  ['MPL', 'MPL-2.0'],
+  ['X11', 'X11'],
+  ['ZLIB', 'Zlib']
+].concat(licensesWithOneVersion)
+
+var SUBSTRING = 0
+var IDENTIFIER = 1
+
+var validTransformation = function (identifier) {
+  for (var i = 0; i < transforms.length; i++) {
+    var transformed = transforms[i](identifier).trim()
+    if (transformed !== identifier && valid(transformed)) {
+      return transformed
+    }
+  }
+  return null
+}
+
+var validLastResort = function (identifier) {
+  var upperCased = identifier.toUpperCase()
+  for (var i = 0; i < lastResorts.length; i++) {
+    var lastResort = lastResorts[i]
+    if (upperCased.indexOf(lastResort[SUBSTRING]) > -1) {
+      return lastResort[IDENTIFIER]
+    }
+  }
+  return null
+}
+
+var anyCorrection = function (identifier, check) {
+  for (var i = 0; i < transpositions.length; i++) {
+    var transposition = transpositions[i]
+    var transposed = transposition[TRANSPOSED]
+    if (identifier.indexOf(transposed) > -1) {
+      var corrected = identifier.replace(
+        transposed,
+        transposition[CORRECT]
+      )
+      var checked = check(corrected)
+      if (checked !== null) {
+        return checked
+      }
+    }
+  }
+  return null
+}
+
+module.exports = function (identifier, options) {
+  options = options || {}
+  var upgrade = options.upgrade === undefined ? true : !!options.upgrade
+  function postprocess (value) {
+    return upgrade ? upgradeGPLs(value) : value
+  }
+  var validArugment = (
+    typeof identifier === 'string' &&
+    identifier.trim().length !== 0
+  )
+  if (!validArugment) {
+    throw Error('Invalid argument. Expected non-empty string.')
+  }
+  identifier = identifier.trim()
+  if (valid(identifier)) {
+    return postprocess(identifier)
+  }
+  var noPlus = identifier.replace(/\+$/, '').trim()
+  if (valid(noPlus)) {
+    return postprocess(noPlus)
+  }
+  var transformed = validTransformation(identifier)
+  if (transformed !== null) {
+    return postprocess(transformed)
+  }
+  transformed = anyCorrection(identifier, function (argument) {
+    if (valid(argument)) {
+      return argument
+    }
+    return validTransformation(argument)
+  })
+  if (transformed !== null) {
+    return postprocess(transformed)
+  }
+  transformed = validLastResort(identifier)
+  if (transformed !== null) {
+    return postprocess(transformed)
+  }
+  transformed = anyCorrection(identifier, validLastResort)
+  if (transformed !== null) {
+    return postprocess(transformed)
+  }
+  return null
+}
+
+function upgradeGPLs (value) {
+  if ([
+    'GPL-1.0', 'LGPL-1.0', 'AGPL-1.0',
+    'GPL-2.0', 'LGPL-2.0', 'AGPL-2.0',
+    'LGPL-2.1'
+  ].indexOf(value) !== -1) {
+    return value + '-only'
+  } else if ([
+    'GPL-1.0+', 'GPL-2.0+', 'GPL-3.0+',
+    'LGPL-2.0+', 'LGPL-2.1+', 'LGPL-3.0+',
+    'AGPL-1.0+', 'AGPL-3.0+'
+  ].indexOf(value) !== -1) {
+    return value.replace(/\+$/, '-or-later')
+  } else if (['GPL-3.0', 'LGPL-3.0', 'AGPL-3.0'].indexOf(value) !== -1) {
+    return value + '-or-later'
+  } else {
+    return value
+  }
+}
diff --git a/server/node_modules/spdx-correct/package.json b/server/node_modules/spdx-correct/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..dc708d17ab0ca8acf0af1c830c9aa6c7534d6bd2
--- /dev/null
+++ b/server/node_modules/spdx-correct/package.json
@@ -0,0 +1,88 @@
+{
+  "_from": "spdx-correct@^3.0.0",
+  "_id": "spdx-correct@3.1.0",
+  "_inBundle": false,
+  "_integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+  "_location": "/spdx-correct",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "spdx-correct@^3.0.0",
+    "name": "spdx-correct",
+    "escapedName": "spdx-correct",
+    "rawSpec": "^3.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^3.0.0"
+  },
+  "_requiredBy": [
+    "/validate-npm-package-license"
+  ],
+  "_resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+  "_shasum": "fb83e504445268f154b074e218c87c003cd31df4",
+  "_spec": "spdx-correct@^3.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/validate-npm-package-license",
+  "author": {
+    "name": "Kyle E. Mitchell",
+    "email": "kyle@kemitchell.com",
+    "url": "https://kemitchell.com"
+  },
+  "bugs": {
+    "url": "https://github.com/jslicense/spdx-correct.js/issues"
+  },
+  "bundleDependencies": false,
+  "contributors": [
+    {
+      "name": "Kyle E. Mitchell",
+      "email": "kyle@kemitchell.com",
+      "url": "https://kemitchell.com"
+    },
+    {
+      "name": "Christian Zommerfelds",
+      "email": "aero_super@yahoo.com"
+    },
+    {
+      "name": "Tal Einat",
+      "email": "taleinat@gmail.com"
+    },
+    {
+      "name": "Dan Butvinik",
+      "email": "butvinik@outlook.com"
+    }
+  ],
+  "dependencies": {
+    "spdx-expression-parse": "^3.0.0",
+    "spdx-license-ids": "^3.0.0"
+  },
+  "deprecated": false,
+  "description": "correct invalid SPDX expressions",
+  "devDependencies": {
+    "defence-cli": "^2.0.1",
+    "replace-require-self": "^1.0.0",
+    "standard": "^11.0.0",
+    "standard-markdown": "^4.0.2",
+    "tape": "^4.9.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/jslicense/spdx-correct.js#readme",
+  "keywords": [
+    "SPDX",
+    "law",
+    "legal",
+    "license",
+    "metadata"
+  ],
+  "license": "Apache-2.0",
+  "name": "spdx-correct",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/jslicense/spdx-correct.js.git"
+  },
+  "scripts": {
+    "lint": "standard && standard-markdown README.md",
+    "test": "defence README.md | replace-require-self | node && node test.js"
+  },
+  "version": "3.1.0"
+}
diff --git a/server/node_modules/spdx-exceptions/README.md b/server/node_modules/spdx-exceptions/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6c927ecc6911929acfeb11617dd067784105d7bb
--- /dev/null
+++ b/server/node_modules/spdx-exceptions/README.md
@@ -0,0 +1,36 @@
+The package exports an array of strings. Each string is an identifier
+for a license exception under the [Software Package Data Exchange
+(SPDX)][SPDX] software license metadata standard.
+
+[SPDX]: https://spdx.org
+
+## Copyright and Licensing
+
+### SPDX
+
+"SPDX" is a federally registered United States trademark of The Linux
+Foundation Corporation.
+
+From version 2.0 of the [SPDX] specification:
+
+> Copyright © 2010-2015 Linux Foundation and its Contributors. Licensed
+> under the Creative Commons Attribution License 3.0 Unported. All other
+> rights are expressly reserved.
+
+The Linux Foundation and the SPDX working groups are good people. Only
+they decide what "SPDX" means, as a standard and otherwise. I respect
+their work and their rights. You should, too.
+
+### This Package
+
+> I created this package by copying exception identifiers out of the
+> SPDX specification. That work was mechanical, routine, and required no
+> creativity whatsoever. - Kyle Mitchell, package author
+
+United States users concerned about intellectual property may wish to
+discuss the following Supreme Court decisions with their attorneys:
+
+- _Baker v. Selden_, 101 U.S. 99 (1879)
+
+- _Feist Publications, Inc., v. Rural Telephone Service Co._,
+  499 U.S. 340 (1991)
diff --git a/server/node_modules/spdx-exceptions/index.json b/server/node_modules/spdx-exceptions/index.json
new file mode 100644
index 0000000000000000000000000000000000000000..1063ebd2d033f344045409743fc438cf07c2b179
--- /dev/null
+++ b/server/node_modules/spdx-exceptions/index.json
@@ -0,0 +1,34 @@
+[
+  "389-exception",
+  "Autoconf-exception-2.0",
+  "Autoconf-exception-3.0",
+  "Bison-exception-2.2",
+  "Bootloader-exception",
+  "Classpath-exception-2.0",
+  "CLISP-exception-2.0",
+  "DigiRule-FOSS-exception",
+  "eCos-exception-2.0",
+  "Fawkes-Runtime-exception",
+  "FLTK-exception",
+  "Font-exception-2.0",
+  "freertos-exception-2.0",
+  "GCC-exception-2.0",
+  "GCC-exception-3.1",
+  "gnu-javamail-exception",
+  "i2p-gpl-java-exception",
+  "Libtool-exception",
+  "Linux-syscall-note",
+  "LLVM-exception",
+  "LZMA-exception",
+  "mif-exception",
+  "Nokia-Qt-exception-1.1",
+  "OCCT-exception-1.0",
+  "OpenJDK-assembly-exception-1.0",
+  "openvpn-openssl-exception",
+  "PS-or-PDF-font-exception-20170817",
+  "Qt-GPL-exception-1.0",
+  "Qt-LGPL-exception-1.1",
+  "Qwt-exception-1.0",
+  "u-boot-exception-2.0",
+  "WxWindows-exception-3.1"
+]
diff --git a/server/node_modules/spdx-exceptions/package.json b/server/node_modules/spdx-exceptions/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..18b28a31fbcfd445e21658921c8765ce3d46a302
--- /dev/null
+++ b/server/node_modules/spdx-exceptions/package.json
@@ -0,0 +1,49 @@
+{
+  "_from": "spdx-exceptions@^2.1.0",
+  "_id": "spdx-exceptions@2.2.0",
+  "_inBundle": false,
+  "_integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+  "_location": "/spdx-exceptions",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "spdx-exceptions@^2.1.0",
+    "name": "spdx-exceptions",
+    "escapedName": "spdx-exceptions",
+    "rawSpec": "^2.1.0",
+    "saveSpec": null,
+    "fetchSpec": "^2.1.0"
+  },
+  "_requiredBy": [
+    "/spdx-expression-parse"
+  ],
+  "_resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+  "_shasum": "2ea450aee74f2a89bfb94519c07fcd6f41322977",
+  "_spec": "spdx-exceptions@^2.1.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/spdx-expression-parse",
+  "author": {
+    "name": "The Linux Foundation"
+  },
+  "bugs": {
+    "url": "https://github.com/kemitchell/spdx-exceptions.json/issues"
+  },
+  "bundleDependencies": false,
+  "contributors": [
+    {
+      "name": "Kyle E. Mitchell",
+      "email": "kyle@kemitchell.com",
+      "url": "https://kemitchell.com/"
+    }
+  ],
+  "deprecated": false,
+  "description": "list of SPDX standard license exceptions",
+  "homepage": "https://github.com/kemitchell/spdx-exceptions.json#readme",
+  "license": "CC-BY-3.0",
+  "name": "spdx-exceptions",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/kemitchell/spdx-exceptions.json.git"
+  },
+  "version": "2.2.0"
+}
diff --git a/server/node_modules/spdx-exceptions/test.log b/server/node_modules/spdx-exceptions/test.log
new file mode 100644
index 0000000000000000000000000000000000000000..b54b1101171323c3fcf27d1036bcd716c2efabc4
--- /dev/null
+++ b/server/node_modules/spdx-exceptions/test.log
@@ -0,0 +1,8 @@
+up to date in 1.038s
+found 0 vulnerabilities
+
+
+> spdx-exceptions@2.1.0 test /home/kyle/spdx-exceptions.json
+> echo 'Error: no test specified'
+
+Error: no test specified
diff --git a/server/node_modules/spdx-expression-parse/AUTHORS b/server/node_modules/spdx-expression-parse/AUTHORS
new file mode 100644
index 0000000000000000000000000000000000000000..257a76b9484c12a3277f68e5e3efd69f65186c60
--- /dev/null
+++ b/server/node_modules/spdx-expression-parse/AUTHORS
@@ -0,0 +1,4 @@
+C. Scott Ananian <cscott@cscott.net> (http://cscott.net)
+Kyle E. Mitchell <kyle@kemitchell.com> (https://kemitchell.com)
+Shinnosuke Watanabe <snnskwtnb@gmail.com>
+Antoine Motet <antoine.motet@gmail.com>
diff --git a/server/node_modules/spdx-expression-parse/LICENSE b/server/node_modules/spdx-expression-parse/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..831618eaba6c89dff91b5acc6e7327c3fcf33af5
--- /dev/null
+++ b/server/node_modules/spdx-expression-parse/LICENSE
@@ -0,0 +1,22 @@
+The MIT License
+
+Copyright (c) 2015 Kyle E. Mitchell & other authors listed in AUTHORS
+
+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.
diff --git a/server/node_modules/spdx-expression-parse/README.md b/server/node_modules/spdx-expression-parse/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..514895b7d31c86403f34935eb991b1308e601018
--- /dev/null
+++ b/server/node_modules/spdx-expression-parse/README.md
@@ -0,0 +1,91 @@
+This package parses [SPDX license expression](https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60) strings describing license terms, like [package.json license strings](https://docs.npmjs.com/files/package.json#license), into consistently structured ECMAScript objects.  The npm command-line interface depends on this package, as do many automatic license-audit tools.
+
+In a nutshell:
+
+```javascript
+var parse = require('spdx-expression-parse')
+var assert = require('assert')
+
+assert.deepEqual(
+  // Licensed under the terms of the Two-Clause BSD License.
+  parse('BSD-2-Clause'),
+  {license: 'BSD-2-Clause'}
+)
+
+assert.throws(function () {
+  // An invalid SPDX license expression.
+  // Should be `Apache-2.0`.
+  parse('Apache 2')
+})
+
+assert.deepEqual(
+  // Dual licensed under either:
+  // - LGPL 2.1
+  // - a combination of Three-Clause BSD and MIT
+  parse('(LGPL-2.1 OR BSD-3-Clause AND MIT)'),
+  {
+    left: {license: 'LGPL-2.1'},
+    conjunction: 'or',
+    right: {
+      left: {license: 'BSD-3-Clause'},
+      conjunction: 'and',
+      right: {license: 'MIT'}
+    }
+  }
+)
+```
+
+The syntax comes from the [Software Package Data eXchange (SPDX)](https://spdx.org/), a standard from the [Linux Foundation](https://www.linuxfoundation.org) for shareable data about software package license terms.  SPDX aims to make sharing and auditing license data easy, especially for users of open-source software.
+
+The bulk of the SPDX standard describes syntax and semantics of XML metadata files.  This package implements two lightweight, plain-text components of that larger standard:
+
+1.  The [license list](https://spdx.org/licenses), a mapping from specific string identifiers, like `Apache-2.0`, to standard form license texts and bolt-on license exceptions.  The [spdx-license-ids](https://www.npmjs.com/package/spdx-exceptions) and [spdx-exceptions](https://www.npmjs.com/package/spdx-license-ids) packages implement the license list.  `spdx-expression-parse` depends on and `require()`s them.
+
+    Any license identifier from the license list is a valid license expression:
+
+    ```javascript
+    var identifiers = []
+      .concat(require('spdx-license-ids'))
+      .concat(require('spdx-license-ids/deprecated'))
+
+    identifiers.forEach(function (id) {
+      assert.deepEqual(parse(id), {license: id})
+    })
+    ```
+
+    So is any license identifier `WITH` a standardized license exception:
+
+    ```javascript
+    identifiers.forEach(function (id) {
+      require('spdx-exceptions').forEach(function (e) {
+        assert.deepEqual(
+          parse(id + ' WITH ' + e),
+          {license: id, exception: e}
+        )
+      })
+    })
+    ```
+
+2.  The license expression language, for describing simple and complex license terms, like `MIT` for MIT-licensed and `(GPL-2.0 OR Apache-2.0)` for dual-licensing under GPL 2.0 and Apache 2.0.  `spdx-expression-parse` itself implements license expression language, exporting a parser.
+
+    ```javascript
+    assert.deepEqual(
+      // Licensed under a combination of:
+      // - the MIT License AND
+      // - a combination of:
+      //   - LGPL 2.1 (or a later version) AND
+      //   - Three-Clause BSD
+      parse('(MIT AND (LGPL-2.1+ AND BSD-3-Clause))'),
+      {
+        left: {license: 'MIT'},
+        conjunction: 'and',
+        right: {
+          left: {license: 'LGPL-2.1', plus: true},
+          conjunction: 'and',
+          right: {license: 'BSD-3-Clause'}
+        }
+      }
+    )
+    ```
+
+The Linux Foundation and its contributors license the SPDX standard under the terms of [the Creative Commons Attribution License 3.0 Unported (SPDX: "CC-BY-3.0")](http://spdx.org/licenses/CC-BY-3.0).  "SPDX" is a United States federally registered trademark of the Linux Foundation.  The authors of this package license their work under the terms of the MIT License.
diff --git a/server/node_modules/spdx-expression-parse/index.js b/server/node_modules/spdx-expression-parse/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..52fab560aea707a5d7b07bdbe9e8022c379aba0f
--- /dev/null
+++ b/server/node_modules/spdx-expression-parse/index.js
@@ -0,0 +1,8 @@
+'use strict'
+
+var scan = require('./scan')
+var parse = require('./parse')
+
+module.exports = function (source) {
+  return parse(scan(source))
+}
diff --git a/server/node_modules/spdx-expression-parse/package.json b/server/node_modules/spdx-expression-parse/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..e96b1e4992c749cb63675b1e002b471b9dd730db
--- /dev/null
+++ b/server/node_modules/spdx-expression-parse/package.json
@@ -0,0 +1,97 @@
+{
+  "_from": "spdx-expression-parse@^3.0.0",
+  "_id": "spdx-expression-parse@3.0.0",
+  "_inBundle": false,
+  "_integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+  "_location": "/spdx-expression-parse",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "spdx-expression-parse@^3.0.0",
+    "name": "spdx-expression-parse",
+    "escapedName": "spdx-expression-parse",
+    "rawSpec": "^3.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^3.0.0"
+  },
+  "_requiredBy": [
+    "/spdx-correct",
+    "/validate-npm-package-license"
+  ],
+  "_resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+  "_shasum": "99e119b7a5da00e05491c9fa338b7904823b41d0",
+  "_spec": "spdx-expression-parse@^3.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/validate-npm-package-license",
+  "author": {
+    "name": "Kyle E. Mitchell",
+    "email": "kyle@kemitchell.com",
+    "url": "http://kemitchell.com"
+  },
+  "bugs": {
+    "url": "https://github.com/jslicense/spdx-expression-parse.js/issues"
+  },
+  "bundleDependencies": false,
+  "contributors": [
+    {
+      "name": "C. Scott Ananian",
+      "email": "cscott@cscott.net",
+      "url": "http://cscott.net"
+    },
+    {
+      "name": "Kyle E. Mitchell",
+      "email": "kyle@kemitchell.com",
+      "url": "https://kemitchell.com"
+    },
+    {
+      "name": "Shinnosuke Watanabe",
+      "email": "snnskwtnb@gmail.com"
+    },
+    {
+      "name": "Antoine Motet",
+      "email": "antoine.motet@gmail.com"
+    }
+  ],
+  "dependencies": {
+    "spdx-exceptions": "^2.1.0",
+    "spdx-license-ids": "^3.0.0"
+  },
+  "deprecated": false,
+  "description": "parse SPDX license expressions",
+  "devDependencies": {
+    "defence-cli": "^2.0.1",
+    "mocha": "^3.4.2",
+    "replace-require-self": "^1.0.0",
+    "standard": "^10.0.2"
+  },
+  "files": [
+    "AUTHORS",
+    "index.js",
+    "parse.js",
+    "scan.js"
+  ],
+  "homepage": "https://github.com/jslicense/spdx-expression-parse.js#readme",
+  "keywords": [
+    "SPDX",
+    "law",
+    "legal",
+    "license",
+    "metadata",
+    "package",
+    "package.json",
+    "standards"
+  ],
+  "license": "MIT",
+  "name": "spdx-expression-parse",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/jslicense/spdx-expression-parse.js.git"
+  },
+  "scripts": {
+    "lint": "standard",
+    "test": "npm run test:mocha && npm run test:readme",
+    "test:mocha": "mocha test/index.js",
+    "test:readme": "defence -i javascript README.md | replace-require-self | node"
+  },
+  "version": "3.0.0"
+}
diff --git a/server/node_modules/spdx-expression-parse/parse.js b/server/node_modules/spdx-expression-parse/parse.js
new file mode 100644
index 0000000000000000000000000000000000000000..a4a52ce93c7c040236446566f2ea6a387ecb06a4
--- /dev/null
+++ b/server/node_modules/spdx-expression-parse/parse.js
@@ -0,0 +1,138 @@
+'use strict'
+
+// The ABNF grammar in the spec is totally ambiguous.
+//
+// This parser follows the operator precedence defined in the
+// `Order of Precedence and Parentheses` section.
+
+module.exports = function (tokens) {
+  var index = 0
+
+  function hasMore () {
+    return index < tokens.length
+  }
+
+  function token () {
+    return hasMore() ? tokens[index] : null
+  }
+
+  function next () {
+    if (!hasMore()) {
+      throw new Error()
+    }
+    index++
+  }
+
+  function parseOperator (operator) {
+    var t = token()
+    if (t && t.type === 'OPERATOR' && operator === t.string) {
+      next()
+      return t.string
+    }
+  }
+
+  function parseWith () {
+    if (parseOperator('WITH')) {
+      var t = token()
+      if (t && t.type === 'EXCEPTION') {
+        next()
+        return t.string
+      }
+      throw new Error('Expected exception after `WITH`')
+    }
+  }
+
+  function parseLicenseRef () {
+    // TODO: Actually, everything is concatenated into one string
+    // for backward-compatibility but it could be better to return
+    // a nice structure.
+    var begin = index
+    var string = ''
+    var t = token()
+    if (t.type === 'DOCUMENTREF') {
+      next()
+      string += 'DocumentRef-' + t.string + ':'
+      if (!parseOperator(':')) {
+        throw new Error('Expected `:` after `DocumentRef-...`')
+      }
+    }
+    t = token()
+    if (t.type === 'LICENSEREF') {
+      next()
+      string += 'LicenseRef-' + t.string
+      return {license: string}
+    }
+    index = begin
+  }
+
+  function parseLicense () {
+    var t = token()
+    if (t && t.type === 'LICENSE') {
+      next()
+      var node = {license: t.string}
+      if (parseOperator('+')) {
+        node.plus = true
+      }
+      var exception = parseWith()
+      if (exception) {
+        node.exception = exception
+      }
+      return node
+    }
+  }
+
+  function parseParenthesizedExpression () {
+    var left = parseOperator('(')
+    if (!left) {
+      return
+    }
+
+    var expr = parseExpression()
+
+    if (!parseOperator(')')) {
+      throw new Error('Expected `)`')
+    }
+
+    return expr
+  }
+
+  function parseAtom () {
+    return (
+      parseParenthesizedExpression() ||
+      parseLicenseRef() ||
+      parseLicense()
+    )
+  }
+
+  function makeBinaryOpParser (operator, nextParser) {
+    return function parseBinaryOp () {
+      var left = nextParser()
+      if (!left) {
+        return
+      }
+
+      if (!parseOperator(operator)) {
+        return left
+      }
+
+      var right = parseBinaryOp()
+      if (!right) {
+        throw new Error('Expected expression')
+      }
+      return {
+        left: left,
+        conjunction: operator.toLowerCase(),
+        right: right
+      }
+    }
+  }
+
+  var parseAnd = makeBinaryOpParser('AND', parseAtom)
+  var parseExpression = makeBinaryOpParser('OR', parseAnd)
+
+  var node = parseExpression()
+  if (!node || hasMore()) {
+    throw new Error('Syntax error')
+  }
+  return node
+}
diff --git a/server/node_modules/spdx-expression-parse/scan.js b/server/node_modules/spdx-expression-parse/scan.js
new file mode 100644
index 0000000000000000000000000000000000000000..d0567f494b5e597ff8db3684265463ea6f47aff1
--- /dev/null
+++ b/server/node_modules/spdx-expression-parse/scan.js
@@ -0,0 +1,131 @@
+'use strict'
+
+var licenses = []
+  .concat(require('spdx-license-ids'))
+  .concat(require('spdx-license-ids/deprecated'))
+var exceptions = require('spdx-exceptions')
+
+module.exports = function (source) {
+  var index = 0
+
+  function hasMore () {
+    return index < source.length
+  }
+
+  // `value` can be a regexp or a string.
+  // If it is recognized, the matching source string is returned and
+  // the index is incremented. Otherwise `undefined` is returned.
+  function read (value) {
+    if (value instanceof RegExp) {
+      var chars = source.slice(index)
+      var match = chars.match(value)
+      if (match) {
+        index += match[0].length
+        return match[0]
+      }
+    } else {
+      if (source.indexOf(value, index) === index) {
+        index += value.length
+        return value
+      }
+    }
+  }
+
+  function skipWhitespace () {
+    read(/[ ]*/)
+  }
+
+  function operator () {
+    var string
+    var possibilities = ['WITH', 'AND', 'OR', '(', ')', ':', '+']
+    for (var i = 0; i < possibilities.length; i++) {
+      string = read(possibilities[i])
+      if (string) {
+        break
+      }
+    }
+
+    if (string === '+' && index > 1 && source[index - 2] === ' ') {
+      throw new Error('Space before `+`')
+    }
+
+    return string && {
+      type: 'OPERATOR',
+      string: string
+    }
+  }
+
+  function idstring () {
+    return read(/[A-Za-z0-9-.]+/)
+  }
+
+  function expectIdstring () {
+    var string = idstring()
+    if (!string) {
+      throw new Error('Expected idstring at offset ' + index)
+    }
+    return string
+  }
+
+  function documentRef () {
+    if (read('DocumentRef-')) {
+      var string = expectIdstring()
+      return {type: 'DOCUMENTREF', string: string}
+    }
+  }
+
+  function licenseRef () {
+    if (read('LicenseRef-')) {
+      var string = expectIdstring()
+      return {type: 'LICENSEREF', string: string}
+    }
+  }
+
+  function identifier () {
+    var begin = index
+    var string = idstring()
+
+    if (licenses.indexOf(string) !== -1) {
+      return {
+        type: 'LICENSE',
+        string: string
+      }
+    } else if (exceptions.indexOf(string) !== -1) {
+      return {
+        type: 'EXCEPTION',
+        string: string
+      }
+    }
+
+    index = begin
+  }
+
+  // Tries to read the next token. Returns `undefined` if no token is
+  // recognized.
+  function parseToken () {
+    // Ordering matters
+    return (
+      operator() ||
+      documentRef() ||
+      licenseRef() ||
+      identifier()
+    )
+  }
+
+  var tokens = []
+  while (hasMore()) {
+    skipWhitespace()
+    if (!hasMore()) {
+      break
+    }
+
+    var token = parseToken()
+    if (!token) {
+      throw new Error('Unexpected `' + source[index] +
+                      '` at offset ' + index)
+    }
+
+    tokens.push(token)
+  }
+  return tokens
+}
diff --git a/server/node_modules/spdx-license-ids/README.md b/server/node_modules/spdx-license-ids/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..699514d1a28aa58599dba4571a4ef266d2119295
--- /dev/null
+++ b/server/node_modules/spdx-license-ids/README.md
@@ -0,0 +1,52 @@
+# spdx-license-ids
+
+[![npm version](https://img.shields.io/npm/v/spdx-license-ids.svg)](https://www.npmjs.com/package/spdx-license-ids)
+[![Github Actions](https://action-badges.now.sh/shinnn/spdx-license-ids)](https://wdp9fww0r9.execute-api.us-west-2.amazonaws.com/production/results/shinnn/spdx-license-ids)
+
+A list of [SPDX license](https://spdx.org/licenses/) identifiers
+
+## Installation
+
+[Download JSON directly](https://raw.githubusercontent.com/shinnn/spdx-license-ids/master/index.json), or [use](https://docs.npmjs.com/cli/install) [npm](https://docs.npmjs.com/about-npm/):
+
+```
+npm install spdx-license-ids
+```
+
+## [Node.js](https://nodejs.org/) API
+
+### require('spdx-license-ids')
+
+Type: `string[]`
+
+All license IDs except for the currently deprecated ones.
+
+```javascript
+const ids = require('spdx-license-ids');
+//=> ['0BSD', 'AAL', 'ADSL', 'AFL-1.1', 'AFL-1.2', 'AFL-2.0', 'AFL-2.1', 'AFL-3.0', 'AGPL-1.0-only', ...]
+
+ids.includes('BSD-3-Clause'); //=> true
+ids.includes('CC-BY-1.0'); //=> true
+
+ids.includes('GPL-3.0'); //=> false
+```
+
+### require('spdx-license-ids/deprecated')
+
+Type: `string[]`
+
+Deprecated license IDs.
+
+```javascript
+const deprecatedIds = require('spdx-license-ids/deprecated');
+//=> ['AGPL-1.0', 'AGPL-3.0', 'GFDL-1.1', 'GFDL-1.2', 'GFDL-1.3', 'GPL-1.0', 'GPL-2.0', ...]
+
+deprecatedIds.includes('BSD-3-Clause'); //=> false
+deprecatedIds.includes('CC-BY-1.0'); //=> false
+
+deprecatedIds.includes('GPL-3.0'); //=> true
+```
+
+## License
+
+[Creative Commons Zero v1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/deed)
diff --git a/server/node_modules/spdx-license-ids/deprecated.json b/server/node_modules/spdx-license-ids/deprecated.json
new file mode 100644
index 0000000000000000000000000000000000000000..1681f4870d5d962e1d5be6bbbae8d1913e55ef78
--- /dev/null
+++ b/server/node_modules/spdx-license-ids/deprecated.json
@@ -0,0 +1,24 @@
+[
+	"AGPL-1.0",
+	"AGPL-3.0",
+	"GFDL-1.1",
+	"GFDL-1.2",
+	"GFDL-1.3",
+	"GPL-1.0",
+	"GPL-2.0",
+	"GPL-2.0-with-GCC-exception",
+	"GPL-2.0-with-autoconf-exception",
+	"GPL-2.0-with-bison-exception",
+	"GPL-2.0-with-classpath-exception",
+	"GPL-2.0-with-font-exception",
+	"GPL-3.0",
+	"GPL-3.0-with-GCC-exception",
+	"GPL-3.0-with-autoconf-exception",
+	"LGPL-2.0",
+	"LGPL-2.1",
+	"LGPL-3.0",
+	"Nunit",
+	"StandardML-NJ",
+	"eCos-2.0",
+	"wxWindows"
+]
diff --git a/server/node_modules/spdx-license-ids/index.json b/server/node_modules/spdx-license-ids/index.json
new file mode 100644
index 0000000000000000000000000000000000000000..5283c78dc77c311a4160cbfc9a24dab315cfa7a2
--- /dev/null
+++ b/server/node_modules/spdx-license-ids/index.json
@@ -0,0 +1,370 @@
+[
+	"0BSD",
+	"AAL",
+	"ADSL",
+	"AFL-1.1",
+	"AFL-1.2",
+	"AFL-2.0",
+	"AFL-2.1",
+	"AFL-3.0",
+	"AGPL-1.0-only",
+	"AGPL-1.0-or-later",
+	"AGPL-3.0-only",
+	"AGPL-3.0-or-later",
+	"AMDPLPA",
+	"AML",
+	"AMPAS",
+	"ANTLR-PD",
+	"APAFML",
+	"APL-1.0",
+	"APSL-1.0",
+	"APSL-1.1",
+	"APSL-1.2",
+	"APSL-2.0",
+	"Abstyles",
+	"Adobe-2006",
+	"Adobe-Glyph",
+	"Afmparse",
+	"Aladdin",
+	"Apache-1.0",
+	"Apache-1.1",
+	"Apache-2.0",
+	"Artistic-1.0",
+	"Artistic-1.0-Perl",
+	"Artistic-1.0-cl8",
+	"Artistic-2.0",
+	"BSD-1-Clause",
+	"BSD-2-Clause",
+	"BSD-2-Clause-FreeBSD",
+	"BSD-2-Clause-NetBSD",
+	"BSD-2-Clause-Patent",
+	"BSD-3-Clause",
+	"BSD-3-Clause-Attribution",
+	"BSD-3-Clause-Clear",
+	"BSD-3-Clause-LBNL",
+	"BSD-3-Clause-No-Nuclear-License",
+	"BSD-3-Clause-No-Nuclear-License-2014",
+	"BSD-3-Clause-No-Nuclear-Warranty",
+	"BSD-3-Clause-Open-MPI",
+	"BSD-4-Clause",
+	"BSD-4-Clause-UC",
+	"BSD-Protection",
+	"BSD-Source-Code",
+	"BSL-1.0",
+	"Bahyph",
+	"Barr",
+	"Beerware",
+	"BitTorrent-1.0",
+	"BitTorrent-1.1",
+	"BlueOak-1.0.0",
+	"Borceux",
+	"CATOSL-1.1",
+	"CC-BY-1.0",
+	"CC-BY-2.0",
+	"CC-BY-2.5",
+	"CC-BY-3.0",
+	"CC-BY-4.0",
+	"CC-BY-NC-1.0",
+	"CC-BY-NC-2.0",
+	"CC-BY-NC-2.5",
+	"CC-BY-NC-3.0",
+	"CC-BY-NC-4.0",
+	"CC-BY-NC-ND-1.0",
+	"CC-BY-NC-ND-2.0",
+	"CC-BY-NC-ND-2.5",
+	"CC-BY-NC-ND-3.0",
+	"CC-BY-NC-ND-4.0",
+	"CC-BY-NC-SA-1.0",
+	"CC-BY-NC-SA-2.0",
+	"CC-BY-NC-SA-2.5",
+	"CC-BY-NC-SA-3.0",
+	"CC-BY-NC-SA-4.0",
+	"CC-BY-ND-1.0",
+	"CC-BY-ND-2.0",
+	"CC-BY-ND-2.5",
+	"CC-BY-ND-3.0",
+	"CC-BY-ND-4.0",
+	"CC-BY-SA-1.0",
+	"CC-BY-SA-2.0",
+	"CC-BY-SA-2.5",
+	"CC-BY-SA-3.0",
+	"CC-BY-SA-4.0",
+	"CC-PDDC",
+	"CC0-1.0",
+	"CDDL-1.0",
+	"CDDL-1.1",
+	"CDLA-Permissive-1.0",
+	"CDLA-Sharing-1.0",
+	"CECILL-1.0",
+	"CECILL-1.1",
+	"CECILL-2.0",
+	"CECILL-2.1",
+	"CECILL-B",
+	"CECILL-C",
+	"CERN-OHL-1.1",
+	"CERN-OHL-1.2",
+	"CNRI-Jython",
+	"CNRI-Python",
+	"CNRI-Python-GPL-Compatible",
+	"CPAL-1.0",
+	"CPL-1.0",
+	"CPOL-1.02",
+	"CUA-OPL-1.0",
+	"Caldera",
+	"ClArtistic",
+	"Condor-1.1",
+	"Crossword",
+	"CrystalStacker",
+	"Cube",
+	"D-FSL-1.0",
+	"DOC",
+	"DSDP",
+	"Dotseqn",
+	"ECL-1.0",
+	"ECL-2.0",
+	"EFL-1.0",
+	"EFL-2.0",
+	"EPL-1.0",
+	"EPL-2.0",
+	"EUDatagrid",
+	"EUPL-1.0",
+	"EUPL-1.1",
+	"EUPL-1.2",
+	"Entessa",
+	"ErlPL-1.1",
+	"Eurosym",
+	"FSFAP",
+	"FSFUL",
+	"FSFULLR",
+	"FTL",
+	"Fair",
+	"Frameworx-1.0",
+	"FreeImage",
+	"GFDL-1.1-only",
+	"GFDL-1.1-or-later",
+	"GFDL-1.2-only",
+	"GFDL-1.2-or-later",
+	"GFDL-1.3-only",
+	"GFDL-1.3-or-later",
+	"GL2PS",
+	"GPL-1.0-only",
+	"GPL-1.0-or-later",
+	"GPL-2.0-only",
+	"GPL-2.0-or-later",
+	"GPL-3.0-only",
+	"GPL-3.0-or-later",
+	"Giftware",
+	"Glide",
+	"Glulxe",
+	"HPND",
+	"HPND-sell-variant",
+	"HaskellReport",
+	"IBM-pibs",
+	"ICU",
+	"IJG",
+	"IPA",
+	"IPL-1.0",
+	"ISC",
+	"ImageMagick",
+	"Imlib2",
+	"Info-ZIP",
+	"Intel",
+	"Intel-ACPI",
+	"Interbase-1.0",
+	"JPNIC",
+	"JSON",
+	"JasPer-2.0",
+	"LAL-1.2",
+	"LAL-1.3",
+	"LGPL-2.0-only",
+	"LGPL-2.0-or-later",
+	"LGPL-2.1-only",
+	"LGPL-2.1-or-later",
+	"LGPL-3.0-only",
+	"LGPL-3.0-or-later",
+	"LGPLLR",
+	"LPL-1.0",
+	"LPL-1.02",
+	"LPPL-1.0",
+	"LPPL-1.1",
+	"LPPL-1.2",
+	"LPPL-1.3a",
+	"LPPL-1.3c",
+	"Latex2e",
+	"Leptonica",
+	"LiLiQ-P-1.1",
+	"LiLiQ-R-1.1",
+	"LiLiQ-Rplus-1.1",
+	"Libpng",
+	"Linux-OpenIB",
+	"MIT",
+	"MIT-0",
+	"MIT-CMU",
+	"MIT-advertising",
+	"MIT-enna",
+	"MIT-feh",
+	"MITNFA",
+	"MPL-1.0",
+	"MPL-1.1",
+	"MPL-2.0",
+	"MPL-2.0-no-copyleft-exception",
+	"MS-PL",
+	"MS-RL",
+	"MTLL",
+	"MakeIndex",
+	"MirOS",
+	"Motosoto",
+	"Multics",
+	"Mup",
+	"NASA-1.3",
+	"NBPL-1.0",
+	"NCSA",
+	"NGPL",
+	"NLOD-1.0",
+	"NLPL",
+	"NOSL",
+	"NPL-1.0",
+	"NPL-1.1",
+	"NPOSL-3.0",
+	"NRL",
+	"NTP",
+	"Naumen",
+	"Net-SNMP",
+	"NetCDF",
+	"Newsletr",
+	"Nokia",
+	"Noweb",
+	"OCCT-PL",
+	"OCLC-2.0",
+	"ODC-By-1.0",
+	"ODbL-1.0",
+	"OFL-1.0",
+	"OFL-1.1",
+	"OGL-UK-1.0",
+	"OGL-UK-2.0",
+	"OGL-UK-3.0",
+	"OGTSL",
+	"OLDAP-1.1",
+	"OLDAP-1.2",
+	"OLDAP-1.3",
+	"OLDAP-1.4",
+	"OLDAP-2.0",
+	"OLDAP-2.0.1",
+	"OLDAP-2.1",
+	"OLDAP-2.2",
+	"OLDAP-2.2.1",
+	"OLDAP-2.2.2",
+	"OLDAP-2.3",
+	"OLDAP-2.4",
+	"OLDAP-2.5",
+	"OLDAP-2.6",
+	"OLDAP-2.7",
+	"OLDAP-2.8",
+	"OML",
+	"OPL-1.0",
+	"OSET-PL-2.1",
+	"OSL-1.0",
+	"OSL-1.1",
+	"OSL-2.0",
+	"OSL-2.1",
+	"OSL-3.0",
+	"OpenSSL",
+	"PDDL-1.0",
+	"PHP-3.0",
+	"PHP-3.01",
+	"Parity-6.0.0",
+	"Plexus",
+	"PostgreSQL",
+	"Python-2.0",
+	"QPL-1.0",
+	"Qhull",
+	"RHeCos-1.1",
+	"RPL-1.1",
+	"RPL-1.5",
+	"RPSL-1.0",
+	"RSA-MD",
+	"RSCPL",
+	"Rdisc",
+	"Ruby",
+	"SAX-PD",
+	"SCEA",
+	"SGI-B-1.0",
+	"SGI-B-1.1",
+	"SGI-B-2.0",
+	"SHL-0.5",
+	"SHL-0.51",
+	"SISSL",
+	"SISSL-1.2",
+	"SMLNJ",
+	"SMPPL",
+	"SNIA",
+	"SPL-1.0",
+	"SSPL-1.0",
+	"SWL",
+	"Saxpath",
+	"Sendmail",
+	"Sendmail-8.23",
+	"SimPL-2.0",
+	"Sleepycat",
+	"Spencer-86",
+	"Spencer-94",
+	"Spencer-99",
+	"SugarCRM-1.1.3",
+	"TAPR-OHL-1.0",
+	"TCL",
+	"TCP-wrappers",
+	"TMate",
+	"TORQUE-1.1",
+	"TOSL",
+	"TU-Berlin-1.0",
+	"TU-Berlin-2.0",
+	"UPL-1.0",
+	"Unicode-DFS-2015",
+	"Unicode-DFS-2016",
+	"Unicode-TOU",
+	"Unlicense",
+	"VOSTROM",
+	"VSL-1.0",
+	"Vim",
+	"W3C",
+	"W3C-19980720",
+	"W3C-20150513",
+	"WTFPL",
+	"Watcom-1.0",
+	"Wsuipa",
+	"X11",
+	"XFree86-1.1",
+	"XSkat",
+	"Xerox",
+	"Xnet",
+	"YPL-1.0",
+	"YPL-1.1",
+	"ZPL-1.1",
+	"ZPL-2.0",
+	"ZPL-2.1",
+	"Zed",
+	"Zend-2.0",
+	"Zimbra-1.3",
+	"Zimbra-1.4",
+	"Zlib",
+	"blessing",
+	"bzip2-1.0.5",
+	"bzip2-1.0.6",
+	"copyleft-next-0.3.0",
+	"copyleft-next-0.3.1",
+	"curl",
+	"diffmark",
+	"dvipdfm",
+	"eGenix",
+	"gSOAP-1.3b",
+	"gnuplot",
+	"iMatix",
+	"libpng-2.0",
+	"libtiff",
+	"mpich2",
+	"psfrag",
+	"psutils",
+	"xinetd",
+	"xpp",
+	"zlib-acknowledgement"
+]
diff --git a/server/node_modules/spdx-license-ids/package.json b/server/node_modules/spdx-license-ids/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..e048761be262e6515988d82bd2f59d3625383e36
--- /dev/null
+++ b/server/node_modules/spdx-license-ids/package.json
@@ -0,0 +1,75 @@
+{
+  "_from": "spdx-license-ids@^3.0.0",
+  "_id": "spdx-license-ids@3.0.5",
+  "_inBundle": false,
+  "_integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
+  "_location": "/spdx-license-ids",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "spdx-license-ids@^3.0.0",
+    "name": "spdx-license-ids",
+    "escapedName": "spdx-license-ids",
+    "rawSpec": "^3.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^3.0.0"
+  },
+  "_requiredBy": [
+    "/spdx-correct",
+    "/spdx-expression-parse"
+  ],
+  "_resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+  "_shasum": "3694b5804567a458d3c8045842a6358632f62654",
+  "_spec": "spdx-license-ids@^3.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/spdx-correct",
+  "author": {
+    "name": "Shinnosuke Watanabe",
+    "url": "https://github.com/shinnn"
+  },
+  "bugs": {
+    "url": "https://github.com/shinnn/spdx-license-ids/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "A list of SPDX license identifiers",
+  "devDependencies": {
+    "@shinnn/eslint-config": "^6.8.7",
+    "chalk": "^2.4.1",
+    "eslint": "^5.10.0",
+    "get-spdx-license-ids": "^2.1.0",
+    "rmfr": "^2.0.0",
+    "tape": "^4.9.1"
+  },
+  "eslintConfig": {
+    "extends": "@shinnn"
+  },
+  "files": [
+    "deprecated.json",
+    "index.json"
+  ],
+  "homepage": "https://github.com/shinnn/spdx-license-ids#readme",
+  "keywords": [
+    "spdx",
+    "license",
+    "licenses",
+    "id",
+    "identifier",
+    "identifiers",
+    "json",
+    "array",
+    "oss"
+  ],
+  "license": "CC0-1.0",
+  "name": "spdx-license-ids",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/shinnn/spdx-license-ids.git"
+  },
+  "scripts": {
+    "build": "node build.js",
+    "pretest": "eslint .",
+    "test": "node test.js"
+  },
+  "version": "3.0.5"
+}
diff --git a/server/node_modules/split/.npmignore b/server/node_modules/split/.npmignore
new file mode 100644
index 0000000000000000000000000000000000000000..13abef4f588987b2681ffc5f79b38aacd880aca1
--- /dev/null
+++ b/server/node_modules/split/.npmignore
@@ -0,0 +1,3 @@
+node_modules
+node_modules/*
+npm_debug.log
diff --git a/server/node_modules/split/.travis.yml b/server/node_modules/split/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6e5919de39a312330fd1abf64237c4b6ad10c56b
--- /dev/null
+++ b/server/node_modules/split/.travis.yml
@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+  - "0.10"
diff --git a/server/node_modules/split/LICENCE b/server/node_modules/split/LICENCE
new file mode 100644
index 0000000000000000000000000000000000000000..171dd970053ce33587ab3960a61b9cb56a9313d6
--- /dev/null
+++ b/server/node_modules/split/LICENCE
@@ -0,0 +1,22 @@
+Copyright (c) 2011 Dominic Tarr
+
+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.
\ No newline at end of file
diff --git a/server/node_modules/split/examples/pretty.js b/server/node_modules/split/examples/pretty.js
new file mode 100644
index 0000000000000000000000000000000000000000..2e891316edfba21600fd34fed269e454bd921b7b
--- /dev/null
+++ b/server/node_modules/split/examples/pretty.js
@@ -0,0 +1,26 @@
+
+var inspect = require('util').inspect
+var es      = require('event-stream')     //load event-stream
+var split   = require('../')
+
+if(!module.parent) {
+  es.pipe(                            //pipe joins streams together
+    process.openStdin(),              //open stdin
+    split(),                       //split stream to break on newlines
+    es.map(function (data, callback) {//turn this async function into a stream
+      var j 
+      try {
+        j = JSON.parse(data)          //try to parse input into json
+      } catch (err) {
+        return callback(null, data)   //if it fails just pass it anyway
+      }
+      callback(null, inspect(j))      //render it nicely
+    }),
+    process.stdout                    // pipe it to stdout !
+    )
+  }
+  
+// run this
+// 
+// curl -sS registry.npmjs.org/event-stream | node pretty.js 
+//
diff --git a/server/node_modules/split/index.js b/server/node_modules/split/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..d2bbe5dcdbe477a33af2451172776546d5b3d6b8
--- /dev/null
+++ b/server/node_modules/split/index.js
@@ -0,0 +1,63 @@
+//filter will reemit the data if cb(err,pass) pass is truthy
+
+// reduce is more tricky
+// maybe we want to group the reductions or emit progress updates occasionally
+// the most basic reduce just emits one 'data' event after it has recieved 'end'
+
+
+var through = require('through')
+var Decoder = require('string_decoder').StringDecoder
+
+module.exports = split
+
+//TODO pass in a function to map across the lines.
+
+function split (matcher, mapper, options) {
+  var decoder = new Decoder()
+  var soFar = ''
+  var maxLength = options && options.maxLength;
+  var trailing = options && options.trailing === false ? false : true
+  if('function' === typeof matcher)
+    mapper = matcher, matcher = null
+  if (!matcher)
+    matcher = /\r?\n/
+
+  function emit(stream, piece) {
+    if(mapper) {
+      try {
+        piece = mapper(piece)
+      }
+      catch (err) {
+        return stream.emit('error', err)
+      }
+      if('undefined' !== typeof piece)
+        stream.queue(piece)
+    }
+    else
+      stream.queue(piece)
+  }
+
+  function next (stream, buffer) {
+    var pieces = ((soFar != null ? soFar : '') + buffer).split(matcher)
+    soFar = pieces.pop()
+
+    if (maxLength && soFar.length > maxLength)
+      return stream.emit('error', new Error('maximum buffer reached'))
+
+    for (var i = 0; i < pieces.length; i++) {
+      var piece = pieces[i]
+      emit(stream, piece)
+    }
+  }
+
+  return through(function (b) {
+    next(this, decoder.write(b))
+  },
+  function () {
+    if(decoder.end)
+      next(this, decoder.end())
+    if(trailing && soFar != null)
+      emit(this, soFar)
+    this.queue(null)
+  })
+}
diff --git a/server/node_modules/split/package.json b/server/node_modules/split/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..40752ceb0e67ff380a9a0e728455c04fc6064c0d
--- /dev/null
+++ b/server/node_modules/split/package.json
@@ -0,0 +1,62 @@
+{
+  "_from": "split@^1.0.0",
+  "_id": "split@1.0.1",
+  "_inBundle": false,
+  "_integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+  "_location": "/split",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "split@^1.0.0",
+    "name": "split",
+    "escapedName": "split",
+    "rawSpec": "^1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.0"
+  },
+  "_requiredBy": [
+    "/pgpass"
+  ],
+  "_resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+  "_shasum": "605bd9be303aa59fb35f9229fbea0ddec9ea07d9",
+  "_spec": "split@^1.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgpass",
+  "author": {
+    "name": "Dominic Tarr",
+    "email": "dominic.tarr@gmail.com",
+    "url": "http://bit.ly/dominictarr"
+  },
+  "bugs": {
+    "url": "https://github.com/dominictarr/split/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "through": "2"
+  },
+  "deprecated": false,
+  "description": "split a Text Stream into a Line Stream",
+  "devDependencies": {
+    "asynct": "*",
+    "event-stream": "~3.0.2",
+    "it-is": "1",
+    "stream-spec": "~0.2",
+    "string-to-stream": "~1.0.0",
+    "ubelt": "~2.9"
+  },
+  "engines": {
+    "node": "*"
+  },
+  "homepage": "http://github.com/dominictarr/split",
+  "license": "MIT",
+  "name": "split",
+  "optionalDependencies": {},
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/dominictarr/split.git"
+  },
+  "scripts": {
+    "test": "asynct test/"
+  },
+  "version": "1.0.1"
+}
diff --git a/server/node_modules/split/readme.markdown b/server/node_modules/split/readme.markdown
new file mode 100644
index 0000000000000000000000000000000000000000..c2e527d84056b82e3996fe64b7e8e688654348f9
--- /dev/null
+++ b/server/node_modules/split/readme.markdown
@@ -0,0 +1,72 @@
+# Split (matcher)
+
+[![build status](https://secure.travis-ci.org/dominictarr/split.png)](http://travis-ci.org/dominictarr/split)
+
+Break up a stream and reassemble it so that each line is a chunk. matcher may be a `String`, or a `RegExp`
+
+Example, read every line in a file ...
+
+``` js
+  fs.createReadStream(file)
+    .pipe(split())
+    .on('data', function (line) {
+      //each chunk now is a separate line!
+    })
+
+```
+
+`split` takes the same arguments as `string.split` except it defaults to '/\r?\n/' instead of ',', and the optional `limit` parameter is ignored.
+[String#split](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/split)
+
+`split` takes an optional options object on its third argument.
+
+``` js
+  split(matcher, mapper, options)
+```
+
+Valid options:
+
+* maxLength - The maximum buffer length without seeing a newline or `matcher`,
+  if a single line exceeds this, the split stream will emit an error.
+
+``` js
+  split(JSON.parse, null, { maxLength: 2})
+```
+
+* trailing - By default the last buffer not delimited by a newline or `matcher` will be emitted. To prevent this set `options.trailing` to `false`.
+
+``` js
+  split(JSON.parse, null, { trailing: false })
+```
+
+## keep matched splitter
+
+As with `String#split`, if you split by a regular expression with a matching group,
+the matches will be retained in the collection.
+
+```
+stdin
+.pipe(split(/(\r?\n)/))
+... //lines + separators.
+```
+
+
+# NDJ - Newline Delimited Json
+
+`split` accepts a function which transforms each line.
+
+``` js
+fs.createReadStream(file)
+  .pipe(split(JSON.parse))
+  .on('data', function (obj) {
+    //each chunk now is a a js object
+  })
+  .on('error', function (err) {
+    //syntax errors will land here
+    //note, this ends the stream.
+  })
+```
+
+# License
+
+MIT
diff --git a/server/node_modules/split/test/options.asynct.js b/server/node_modules/split/test/options.asynct.js
new file mode 100644
index 0000000000000000000000000000000000000000..3f137d904341805405ee00aa4a612a587adcf905
--- /dev/null
+++ b/server/node_modules/split/test/options.asynct.js
@@ -0,0 +1,46 @@
+var it = require('it-is').style('colour')
+  , split = require('..')
+
+exports ['maximum buffer limit'] = function (test) {
+  var s = split(JSON.parse, null, {
+    maxLength: 2
+  })
+    , caughtError = false
+    , rows = []
+
+  s.on('error', function (err) {
+    caughtError = true
+  })
+
+  s.on('data', function (row) { rows.push(row) })
+
+  s.write('{"a":1}\n{"')
+  s.write('{    "')
+  it(caughtError).equal(true)
+
+  s.end()
+  test.done()
+}
+
+exports ['ignore trailing buffers'] = function (test) {
+  var s = split(JSON.parse, null, {
+    trailing: false
+  })
+    , caughtError = false
+    , rows = []
+
+  s.on('error', function (err) {
+    caughtError = true
+  })
+
+  s.on('data', function (row) { rows.push(row) })
+
+  s.write('{"a":1}\n{"')
+  s.write('{    "')
+  s.end()
+
+  it(caughtError).equal(false)
+  it(rows).deepEqual([ { a: 1 } ])
+
+  test.done()
+}
diff --git a/server/node_modules/split/test/partitioned_unicode.js b/server/node_modules/split/test/partitioned_unicode.js
new file mode 100644
index 0000000000000000000000000000000000000000..aff3d5da5ffc68a50a88279978ebbc35bde05233
--- /dev/null
+++ b/server/node_modules/split/test/partitioned_unicode.js
@@ -0,0 +1,34 @@
+var it = require('it-is').style('colour')
+  , split = require('..')
+
+exports ['split data with partitioned unicode character'] = function (test) {
+  var s = split(/,/g)
+    , caughtError = false
+    , rows = []
+
+  s.on('error', function (err) {
+    caughtError = true
+  })
+ 
+  s.on('data', function (row) { rows.push(row) })
+
+  var x = 'テスト試験今日とても,よい天気で'
+  unicodeData = new Buffer(x);
+
+  // partition of æ—¥
+  piece1 = unicodeData.slice(0, 20);
+  piece2 = unicodeData.slice(20, unicodeData.length);
+
+  s.write(piece1);
+  s.write(piece2);
+
+  s.end()
+
+  it(caughtError).equal(false)
+
+  it(rows).deepEqual(['テスト試験今日とても', 'よい天気で']);
+
+  it(rows).deepEqual(x.split(','))
+
+  test.done()
+}
diff --git a/server/node_modules/split/test/split.asynct.js b/server/node_modules/split/test/split.asynct.js
new file mode 100644
index 0000000000000000000000000000000000000000..a586e120ace0eb56ef4c2eb2639ad22d067bca5a
--- /dev/null
+++ b/server/node_modules/split/test/split.asynct.js
@@ -0,0 +1,137 @@
+var es = require('event-stream')
+  , it = require('it-is').style('colour')
+  , d = require('ubelt')
+  , split = require('..')
+  , join = require('path').join
+  , fs = require('fs')
+  , Stream = require('stream').Stream
+  , Readable = require('stream').Readable
+  , spec = require('stream-spec')
+  , through = require('through')
+  , stringStream = require('string-to-stream')
+
+exports ['split() works like String#split'] = function (test) {
+  var readme = join(__filename)
+    , expected = fs.readFileSync(readme, 'utf-8').split('\n')
+    , cs = split()
+    , actual = []
+    , ended = false
+    , x = spec(cs).through()
+
+  var a = new Stream ()
+
+  a.write = function (l) {
+    actual.push(l.trim())
+  }
+  a.end = function () {
+
+      ended = true
+      expected.forEach(function (v,k) {
+        //String.split will append an empty string ''
+        //if the string ends in a split pattern.
+        //es.split doesn't which was breaking this test.
+        //clearly, appending the empty string is correct.
+        //tests are passing though. which is the current job.
+        if(v)
+          it(actual[k]).like(v)
+      })
+      //give the stream time to close
+      process.nextTick(function () {
+        test.done()
+        x.validate()
+      })
+  }
+  a.writable = true
+
+  fs.createReadStream(readme, {flags: 'r'}).pipe(cs)
+  cs.pipe(a)
+
+}
+
+exports ['split() takes mapper function'] = function (test) {
+  var readme = join(__filename)
+    , expected = fs.readFileSync(readme, 'utf-8').split('\n')
+    , cs = split(function (line) { return line.toUpperCase() })
+    , actual = []
+    , ended = false
+    , x = spec(cs).through()
+
+  var a = new Stream ()
+
+  a.write = function (l) {
+    actual.push(l.trim())
+  }
+  a.end = function () {
+
+      ended = true
+      expected.forEach(function (v,k) {
+        //String.split will append an empty string ''
+        //if the string ends in a split pattern.
+        //es.split doesn't which was breaking this test.
+        //clearly, appending the empty string is correct.
+        //tests are passing though. which is the current job.
+        if(v)
+          it(actual[k]).equal(v.trim().toUpperCase())
+      })
+      //give the stream time to close
+      process.nextTick(function () {
+        test.done()
+        x.validate()
+      })
+  }
+  a.writable = true
+
+  fs.createReadStream(readme, {flags: 'r'}).pipe(cs)
+  cs.pipe(a)
+
+}
+
+exports ['split() works with empty string chunks'] = function (test) {
+  var str = ' foo'
+    , expected = str.split(/[\s]*/).reduce(splitBy(/[\s]*/), [])
+    , cs1 = split(/[\s]*/)
+    , cs2 = split(/[\s]*/)
+    , actual = []
+    , ended = false
+    , x = spec(cs1).through()
+    , y = spec(cs2).through()
+
+  var a = new Stream ()
+
+  a.write = function (l) {
+    actual.push(l.trim())
+  }
+  a.end = function () {
+
+      ended = true
+      expected.forEach(function (v,k) {
+        //String.split will append an empty string ''
+        //if the string ends in a split pattern.
+        //es.split doesn't which was breaking this test.
+        //clearly, appending the empty string is correct.
+        //tests are passing though. which is the current job.
+        if(v)
+          it(actual[k]).like(v)
+      })
+      //give the stream time to close
+      process.nextTick(function () {
+        test.done()
+        x.validate()
+        y.validate()
+      })
+  }
+  a.writable = true
+
+  cs1.pipe(cs2)
+  cs2.pipe(a)
+
+  cs1.write(str)
+  cs1.end()
+
+}
+
+function splitBy (delimiter) {
+  return function (arr, piece) {
+    return arr.concat(piece.split(delimiter))
+  }
+}
diff --git a/server/node_modules/split/test/try_catch.asynct.js b/server/node_modules/split/test/try_catch.asynct.js
new file mode 100644
index 0000000000000000000000000000000000000000..39e49f737b49c00ea59ea5e3bdea90dfecb37af5
--- /dev/null
+++ b/server/node_modules/split/test/try_catch.asynct.js
@@ -0,0 +1,51 @@
+var it = require('it-is').style('colour')
+  , split = require('..')
+
+exports ['emit mapper exceptions as error events'] = function (test) {
+  var s = split(JSON.parse)
+    , caughtError = false
+    , rows = []
+ 
+  s.on('error', function (err) {
+    caughtError = true
+  })
+ 
+  s.on('data', function (row) { rows.push(row) })
+
+  s.write('{"a":1}\n{"')
+  it(caughtError).equal(false)
+  it(rows).deepEqual([ { a: 1 } ])
+
+  s.write('b":2}\n{"c":}\n')
+  it(caughtError).equal(true)
+  it(rows).deepEqual([ { a: 1 }, { b: 2 } ])
+
+  s.end()
+  test.done()
+}
+
+exports ['mapper error events on trailing chunks'] = function (test) {
+  var s = split(JSON.parse)
+    , caughtError = false
+    , rows = []
+ 
+  s.on('error', function (err) {
+    caughtError = true
+  })
+ 
+  s.on('data', function (row) { rows.push(row) })
+
+  s.write('{"a":1}\n{"')
+  it(caughtError).equal(false)
+  it(rows).deepEqual([ { a: 1 } ])
+
+  s.write('b":2}\n{"c":}')
+  it(caughtError).equal(false)
+  it(rows).deepEqual([ { a: 1 }, { b: 2 } ])
+
+  s.end()
+  it(caughtError).equal(true)
+  it(rows).deepEqual([ { a: 1 }, { b: 2 } ])
+
+  test.done()
+}
diff --git a/server/node_modules/strip-bom/index.js b/server/node_modules/strip-bom/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..5695c5c79bcc59e0fbbafe0fa55b3e0c1f036f29
--- /dev/null
+++ b/server/node_modules/strip-bom/index.js
@@ -0,0 +1,17 @@
+'use strict';
+var isUtf8 = require('is-utf8');
+
+module.exports = function (x) {
+	// Catches EFBBBF (UTF-8 BOM) because the buffer-to-string
+	// conversion translates it to FEFF (UTF-16 BOM)
+	if (typeof x === 'string' && x.charCodeAt(0) === 0xFEFF) {
+		return x.slice(1);
+	}
+
+	if (Buffer.isBuffer(x) && isUtf8(x) &&
+		x[0] === 0xEF && x[1] === 0xBB && x[2] === 0xBF) {
+		return x.slice(3);
+	}
+
+	return x;
+};
diff --git a/server/node_modules/strip-bom/license b/server/node_modules/strip-bom/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/strip-bom/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/strip-bom/package.json b/server/node_modules/strip-bom/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..01b7d85f4505fbbe5a344e5bdaa6849a0efd34f3
--- /dev/null
+++ b/server/node_modules/strip-bom/package.json
@@ -0,0 +1,74 @@
+{
+  "_from": "strip-bom@^2.0.0",
+  "_id": "strip-bom@2.0.0",
+  "_inBundle": false,
+  "_integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+  "_location": "/strip-bom",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "strip-bom@^2.0.0",
+    "name": "strip-bom",
+    "escapedName": "strip-bom",
+    "rawSpec": "^2.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^2.0.0"
+  },
+  "_requiredBy": [
+    "/load-json-file"
+  ],
+  "_resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+  "_shasum": "6219a85616520491f35788bdbf1447a99c7e6b0e",
+  "_spec": "strip-bom@^2.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/load-json-file",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/sindresorhus/strip-bom/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "is-utf8": "^0.2.0"
+  },
+  "deprecated": false,
+  "description": "Strip UTF-8 byte order mark (BOM) from a string/buffer",
+  "devDependencies": {
+    "mocha": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/sindresorhus/strip-bom#readme",
+  "keywords": [
+    "bom",
+    "strip",
+    "byte",
+    "mark",
+    "unicode",
+    "utf8",
+    "utf-8",
+    "remove",
+    "delete",
+    "trim",
+    "text",
+    "buffer",
+    "string"
+  ],
+  "license": "MIT",
+  "name": "strip-bom",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/sindresorhus/strip-bom.git"
+  },
+  "scripts": {
+    "test": "mocha"
+  },
+  "version": "2.0.0"
+}
diff --git a/server/node_modules/strip-bom/readme.md b/server/node_modules/strip-bom/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..8ecf258b63294bee0de83dfd7f501649ddbd2019
--- /dev/null
+++ b/server/node_modules/strip-bom/readme.md
@@ -0,0 +1,39 @@
+# strip-bom [![Build Status](https://travis-ci.org/sindresorhus/strip-bom.svg?branch=master)](https://travis-ci.org/sindresorhus/strip-bom)
+
+> Strip UTF-8 [byte order mark](http://en.wikipedia.org/wiki/Byte_order_mark#UTF-8) (BOM) from a string/buffer
+
+From Wikipedia:
+
+> The Unicode Standard permits the BOM in UTF-8, but does not require nor recommend its use. Byte order has no meaning in UTF-8.
+
+
+## Install
+
+```
+$ npm install --save strip-bom
+```
+
+
+## Usage
+
+```js
+var fs = require('fs');
+var stripBom = require('strip-bom');
+
+stripBom('\uFEFFunicorn');
+//=> 'unicorn'
+
+stripBom(fs.readFileSync('unicorn.txt'));
+//=> 'unicorn'
+```
+
+
+## Related
+
+- [strip-bom-cli](https://github.com/sindresorhus/strip-bom-cli) - CLI for this module
+- [strip-bom-stream](https://github.com/sindresorhus/strip-bom-stream) - Stream version of this module
+
+
+## License
+
+MIT © [Sindre Sorhus](http://sindresorhus.com)
diff --git a/server/node_modules/through/.travis.yml b/server/node_modules/through/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c693a939df980990ff280c930c85d9694e903b5b
--- /dev/null
+++ b/server/node_modules/through/.travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+node_js:
+  - 0.6
+  - 0.8
+  - "0.10"
diff --git a/server/node_modules/through/LICENSE.APACHE2 b/server/node_modules/through/LICENSE.APACHE2
new file mode 100644
index 0000000000000000000000000000000000000000..6366c04716fb9e88262da7cf0b5cdfa69dbd2c65
--- /dev/null
+++ b/server/node_modules/through/LICENSE.APACHE2
@@ -0,0 +1,15 @@
+Apache License, Version 2.0
+
+Copyright (c) 2011 Dominic Tarr
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/server/node_modules/through/LICENSE.MIT b/server/node_modules/through/LICENSE.MIT
new file mode 100644
index 0000000000000000000000000000000000000000..6eafbd734a6e062459ba4b3b4a99f8aeb7178664
--- /dev/null
+++ b/server/node_modules/through/LICENSE.MIT
@@ -0,0 +1,24 @@
+The MIT License
+
+Copyright (c) 2011 Dominic Tarr
+
+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.
diff --git a/server/node_modules/through/index.js b/server/node_modules/through/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..ca5fc5901fd8751c04f4b15a0572f5673d959e27
--- /dev/null
+++ b/server/node_modules/through/index.js
@@ -0,0 +1,108 @@
+var Stream = require('stream')
+
+// through
+//
+// a stream that does nothing but re-emit the input.
+// useful for aggregating a series of changing but not ending streams into one stream)
+
+exports = module.exports = through
+through.through = through
+
+//create a readable writable stream.
+
+function through (write, end, opts) {
+  write = write || function (data) { this.queue(data) }
+  end = end || function () { this.queue(null) }
+
+  var ended = false, destroyed = false, buffer = [], _ended = false
+  var stream = new Stream()
+  stream.readable = stream.writable = true
+  stream.paused = false
+
+//  stream.autoPause   = !(opts && opts.autoPause   === false)
+  stream.autoDestroy = !(opts && opts.autoDestroy === false)
+
+  stream.write = function (data) {
+    write.call(this, data)
+    return !stream.paused
+  }
+
+  function drain() {
+    while(buffer.length && !stream.paused) {
+      var data = buffer.shift()
+      if(null === data)
+        return stream.emit('end')
+      else
+        stream.emit('data', data)
+    }
+  }
+
+  stream.queue = stream.push = function (data) {
+//    console.error(ended)
+    if(_ended) return stream
+    if(data === null) _ended = true
+    buffer.push(data)
+    drain()
+    return stream
+  }
+
+  //this will be registered as the first 'end' listener
+  //must call destroy next tick, to make sure we're after any
+  //stream piped from here.
+  //this is only a problem if end is not emitted synchronously.
+  //a nicer way to do this is to make sure this is the last listener for 'end'
+
+  stream.on('end', function () {
+    stream.readable = false
+    if(!stream.writable && stream.autoDestroy)
+      process.nextTick(function () {
+        stream.destroy()
+      })
+  })
+
+  function _end () {
+    stream.writable = false
+    end.call(stream)
+    if(!stream.readable && stream.autoDestroy)
+      stream.destroy()
+  }
+
+  stream.end = function (data) {
+    if(ended) return
+    ended = true
+    if(arguments.length) stream.write(data)
+    _end() // will emit or queue
+    return stream
+  }
+
+  stream.destroy = function () {
+    if(destroyed) return
+    destroyed = true
+    ended = true
+    buffer.length = 0
+    stream.writable = stream.readable = false
+    stream.emit('close')
+    return stream
+  }
+
+  stream.pause = function () {
+    if(stream.paused) return
+    stream.paused = true
+    return stream
+  }
+
+  stream.resume = function () {
+    if(stream.paused) {
+      stream.paused = false
+      stream.emit('resume')
+    }
+    drain()
+    //may have become paused again,
+    //as drain emits 'data'.
+    if(!stream.paused)
+      stream.emit('drain')
+    return stream
+  }
+  return stream
+}
+
diff --git a/server/node_modules/through/package.json b/server/node_modules/through/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..2d09c0c2cf1d0049fd9576405408111b57de83dc
--- /dev/null
+++ b/server/node_modules/through/package.json
@@ -0,0 +1,68 @@
+{
+  "_from": "through@2",
+  "_id": "through@2.3.8",
+  "_inBundle": false,
+  "_integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+  "_location": "/through",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "through@2",
+    "name": "through",
+    "escapedName": "through",
+    "rawSpec": "2",
+    "saveSpec": null,
+    "fetchSpec": "2"
+  },
+  "_requiredBy": [
+    "/split"
+  ],
+  "_resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+  "_shasum": "0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5",
+  "_spec": "through@2",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/split",
+  "author": {
+    "name": "Dominic Tarr",
+    "email": "dominic.tarr@gmail.com",
+    "url": "dominictarr.com"
+  },
+  "bugs": {
+    "url": "https://github.com/dominictarr/through/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "simplified stream construction",
+  "devDependencies": {
+    "from": "~0.1.3",
+    "stream-spec": "~0.3.5",
+    "tape": "~2.3.2"
+  },
+  "homepage": "https://github.com/dominictarr/through",
+  "keywords": [
+    "stream",
+    "streams",
+    "user-streams",
+    "pipe"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "through",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/dominictarr/through.git"
+  },
+  "scripts": {
+    "test": "set -e; for t in test/*.js; do node $t; done"
+  },
+  "testling": {
+    "browsers": [
+      "ie/8..latest",
+      "ff/15..latest",
+      "chrome/20..latest",
+      "safari/5.1..latest"
+    ],
+    "files": "test/*.js"
+  },
+  "version": "2.3.8"
+}
diff --git a/server/node_modules/through/readme.markdown b/server/node_modules/through/readme.markdown
new file mode 100644
index 0000000000000000000000000000000000000000..cb34c8135f53ebf88e78fdffc58c7fbc1979c657
--- /dev/null
+++ b/server/node_modules/through/readme.markdown
@@ -0,0 +1,64 @@
+#through
+
+[![build status](https://secure.travis-ci.org/dominictarr/through.png)](http://travis-ci.org/dominictarr/through)
+[![testling badge](https://ci.testling.com/dominictarr/through.png)](https://ci.testling.com/dominictarr/through)
+
+Easy way to create a `Stream` that is both `readable` and `writable`. 
+
+* Pass in optional `write` and `end` methods.
+* `through` takes care of pause/resume logic if you use `this.queue(data)` instead of `this.emit('data', data)`.
+* Use `this.pause()` and `this.resume()` to manage flow.
+* Check `this.paused` to see current flow state. (`write` always returns `!this.paused`).
+
+This function is the basis for most of the synchronous streams in 
+[event-stream](http://github.com/dominictarr/event-stream).
+
+``` js
+var through = require('through')
+
+through(function write(data) {
+    this.queue(data) //data *must* not be null
+  },
+  function end () { //optional
+    this.queue(null)
+  })
+```
+
+Or, can also be used _without_ buffering on pause, use `this.emit('data', data)`,
+and this.emit('end')
+
+``` js
+var through = require('through')
+
+through(function write(data) {
+    this.emit('data', data)
+    //this.pause() 
+  },
+  function end () { //optional
+    this.emit('end')
+  })
+```
+
+## Extended Options
+
+You will probably not need these 99% of the time.
+
+### autoDestroy=false
+
+By default, `through` emits close when the writable
+and readable side of the stream has ended.
+If that is not desired, set `autoDestroy=false`.
+
+``` js
+var through = require('through')
+
+//like this
+var ts = through(write, end, {autoDestroy: false})
+//or like this
+var ts = through(write, end)
+ts.autoDestroy = false
+```
+
+## License
+
+MIT / Apache2
diff --git a/server/node_modules/through/test/async.js b/server/node_modules/through/test/async.js
new file mode 100644
index 0000000000000000000000000000000000000000..46bdbaebcbc09bac9e2b4534b6e77d31bcb3bbea
--- /dev/null
+++ b/server/node_modules/through/test/async.js
@@ -0,0 +1,28 @@
+var from = require('from')
+var through = require('../')
+
+var tape = require('tape')
+
+tape('simple async example', function (t) {
+ 
+  var n = 0, expected = [1,2,3,4,5], actual = []
+  from(expected)
+  .pipe(through(function(data) {
+    this.pause()
+    n ++
+    setTimeout(function(){
+      console.log('pushing data', data)
+      this.push(data)
+      this.resume()
+    }.bind(this), 300)
+  })).pipe(through(function(data) {
+    console.log('pushing data second time', data);
+    this.push(data)
+  })).on('data', function (d) {
+    actual.push(d)
+  }).on('end', function() {
+    t.deepEqual(actual, expected)
+    t.end()
+  })
+
+})
diff --git a/server/node_modules/through/test/auto-destroy.js b/server/node_modules/through/test/auto-destroy.js
new file mode 100644
index 0000000000000000000000000000000000000000..9a8fd0006f5b807bbd2b0b4f2ac37bb85bc2189d
--- /dev/null
+++ b/server/node_modules/through/test/auto-destroy.js
@@ -0,0 +1,30 @@
+var test = require('tape')
+var through = require('../')
+
+// must emit end before close.
+
+test('end before close', function (assert) {
+  var ts = through()
+  ts.autoDestroy = false
+  var ended = false, closed = false
+
+  ts.on('end', function () {
+    assert.ok(!closed)
+    ended = true
+  })
+  ts.on('close', function () {
+    assert.ok(ended)
+    closed = true
+  })
+
+  ts.write(1)
+  ts.write(2)
+  ts.write(3)
+  ts.end()
+  assert.ok(ended)
+  assert.notOk(closed)
+  ts.destroy()
+  assert.ok(closed)
+  assert.end()
+})
+
diff --git a/server/node_modules/through/test/buffering.js b/server/node_modules/through/test/buffering.js
new file mode 100644
index 0000000000000000000000000000000000000000..b0084bfc6ed5ac3cd4d9916a0b75ff5faa16639b
--- /dev/null
+++ b/server/node_modules/through/test/buffering.js
@@ -0,0 +1,71 @@
+var test = require('tape')
+var through = require('../')
+
+// must emit end before close.
+
+test('buffering', function(assert) {
+  var ts = through(function (data) {
+    this.queue(data)
+  }, function () {
+    this.queue(null)
+  })
+
+  var ended = false,  actual = []
+
+  ts.on('data', actual.push.bind(actual))
+  ts.on('end', function () {
+    ended = true
+  })
+
+  ts.write(1)
+  ts.write(2)
+  ts.write(3)
+  assert.deepEqual(actual, [1, 2, 3])
+  ts.pause()
+  ts.write(4)
+  ts.write(5)
+  ts.write(6)
+  assert.deepEqual(actual, [1, 2, 3])
+  ts.resume()
+  assert.deepEqual(actual, [1, 2, 3, 4, 5, 6])
+  ts.pause()
+  ts.end()
+  assert.ok(!ended)
+  ts.resume()
+  assert.ok(ended)
+  assert.end()
+})
+
+test('buffering has data in queue, when ends', function (assert) {
+
+  /*
+   * If stream ends while paused with data in the queue,
+   * stream should still emit end after all data is written
+   * on resume.
+   */
+
+  var ts = through(function (data) {
+    this.queue(data)
+  }, function () {
+    this.queue(null)
+  })
+
+  var ended = false,  actual = []
+
+  ts.on('data', actual.push.bind(actual))
+  ts.on('end', function () {
+    ended = true
+  })
+
+  ts.pause()
+  ts.write(1)
+  ts.write(2)
+  ts.write(3)
+  ts.end()
+  assert.deepEqual(actual, [], 'no data written yet, still paused')
+  assert.ok(!ended, 'end not emitted yet, still paused')
+  ts.resume()
+  assert.deepEqual(actual, [1, 2, 3], 'resumed, all data should be delivered')
+  assert.ok(ended, 'end should be emitted once all data was delivered')
+  assert.end();
+})
diff --git a/server/node_modules/through/test/end.js b/server/node_modules/through/test/end.js
new file mode 100644
index 0000000000000000000000000000000000000000..fa113f58e0360ab6a78ef5368fc8947bf1c74124
--- /dev/null
+++ b/server/node_modules/through/test/end.js
@@ -0,0 +1,45 @@
+var test = require('tape')
+var through = require('../')
+
+// must emit end before close.
+
+test('end before close', function (assert) {
+  var ts = through()
+  var ended = false, closed = false
+
+  ts.on('end', function () {
+    assert.ok(!closed)
+    ended = true
+  })
+  ts.on('close', function () {
+    assert.ok(ended)
+    closed = true
+  })
+
+  ts.write(1)
+  ts.write(2)
+  ts.write(3)
+  ts.end()
+  assert.ok(ended)
+  assert.ok(closed)
+  assert.end()
+})
+
+test('end only once', function (t) {
+
+  var ts = through()
+  var ended = false, closed = false
+
+  ts.on('end', function () {
+    t.equal(ended, false)
+    ended = true
+  })
+
+  ts.queue(null)
+  ts.queue(null)
+  ts.queue(null)
+
+  ts.resume()
+
+  t.end()
+})
diff --git a/server/node_modules/through/test/index.js b/server/node_modules/through/test/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..96da82f97c74cfd1f1790e5fd0d167a7744deb00
--- /dev/null
+++ b/server/node_modules/through/test/index.js
@@ -0,0 +1,133 @@
+
+var test = require('tape')
+var spec = require('stream-spec')
+var through = require('../')
+
+/*
+  I'm using these two functions, and not streams and pipe
+  so there is less to break. if this test fails it must be
+  the implementation of _through_
+*/
+
+function write(array, stream) {
+  array = array.slice()
+  function next() {
+    while(array.length)
+      if(stream.write(array.shift()) === false)
+        return stream.once('drain', next)
+    
+    stream.end()
+  }
+
+  next()
+}
+
+function read(stream, callback) {
+  var actual = []
+  stream.on('data', function (data) {
+    actual.push(data)
+  })
+  stream.once('end', function () {
+    callback(null, actual)
+  })
+  stream.once('error', function (err) {
+    callback(err)
+  })
+}
+
+test('simple defaults', function(assert) {
+
+  var l = 1000
+    , expected = []
+
+  while(l--) expected.push(l * Math.random())
+
+  var t = through()
+  var s = spec(t).through().pausable()
+
+  read(t, function (err, actual) {
+    assert.ifError(err)
+    assert.deepEqual(actual, expected)
+    assert.end()
+  })
+
+  t.on('close', s.validate)
+
+  write(expected, t)
+});
+
+test('simple functions', function(assert) {
+
+  var l = 1000
+    , expected = [] 
+
+  while(l--) expected.push(l * Math.random())
+
+  var t = through(function (data) {
+      this.emit('data', data*2)
+    }) 
+  var s = spec(t).through().pausable()
+      
+
+  read(t, function (err, actual) {
+    assert.ifError(err)
+    assert.deepEqual(actual, expected.map(function (data) {
+      return data*2
+    }))
+    assert.end()
+  })
+
+  t.on('close', s.validate)
+
+  write(expected, t)
+})
+
+test('pauses', function(assert) {
+
+  var l = 1000
+    , expected = [] 
+
+  while(l--) expected.push(l) //Math.random())
+
+  var t = through()    
+ 
+  var s = spec(t)
+      .through()
+      .pausable()
+
+  t.on('data', function () {
+    if(Math.random() > 0.1) return
+    t.pause()
+    process.nextTick(function () {
+      t.resume()
+    })
+  })
+
+  read(t, function (err, actual) {
+    assert.ifError(err)
+    assert.deepEqual(actual, expected)
+  })
+
+  t.on('close', function () {
+    s.validate()
+    assert.end()
+  })
+
+  write(expected, t)
+})
+
+test('does not soft-end on `undefined`', function(assert) {
+  var stream = through()
+    , count = 0
+
+  stream.on('data', function (data) {
+    count++
+  })
+
+  stream.write(undefined)
+  stream.write(undefined)
+
+  assert.equal(count, 2)
+
+  assert.end()
+})
diff --git a/server/node_modules/validate-npm-package-license/LICENSE b/server/node_modules/validate-npm-package-license/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..d645695673349e3947e8e5ae42332d0ac3164cd7
--- /dev/null
+++ b/server/node_modules/validate-npm-package-license/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/server/node_modules/validate-npm-package-license/README.md b/server/node_modules/validate-npm-package-license/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..702bc7b4f3ba3e14ebae5f622f4d07473b40aba4
--- /dev/null
+++ b/server/node_modules/validate-npm-package-license/README.md
@@ -0,0 +1,113 @@
+validate-npm-package-license
+============================
+
+Give me a string and I'll tell you if it's a valid npm package license string.
+
+```javascript
+var valid = require('validate-npm-package-license');
+```
+
+SPDX license identifiers are valid license strings:
+
+```javascript
+
+var assert = require('assert');
+var validSPDXExpression = {
+  validForNewPackages: true,
+  validForOldPackages: true,
+  spdx: true
+};
+
+assert.deepEqual(valid('MIT'), validSPDXExpression);
+assert.deepEqual(valid('BSD-2-Clause'), validSPDXExpression);
+assert.deepEqual(valid('Apache-2.0'), validSPDXExpression);
+assert.deepEqual(valid('ISC'), validSPDXExpression);
+```
+The function will return a warning and suggestion for nearly-correct license identifiers:
+
+```javascript
+assert.deepEqual(
+  valid('Apache 2.0'),
+  {
+    validForOldPackages: false,
+    validForNewPackages: false,
+    warnings: [
+      'license should be ' +
+      'a valid SPDX license expression (without "LicenseRef"), ' +
+      '"UNLICENSED", or ' +
+      '"SEE LICENSE IN <filename>"',
+      'license is similar to the valid expression "Apache-2.0"'
+    ]
+  }
+);
+```
+
+SPDX expressions are valid, too ...
+
+```javascript
+// Simple SPDX license expression for dual licensing
+assert.deepEqual(
+  valid('(GPL-3.0-only OR BSD-2-Clause)'),
+  validSPDXExpression
+);
+```
+
+... except if they contain `LicenseRef`:
+
+```javascript
+var warningAboutLicenseRef = {
+  validForOldPackages: false,
+  validForNewPackages: false,
+  spdx: true,
+  warnings: [
+    'license should be ' +
+    'a valid SPDX license expression (without "LicenseRef"), ' +
+    '"UNLICENSED", or ' +
+    '"SEE LICENSE IN <filename>"',
+  ]
+};
+
+assert.deepEqual(
+  valid('LicenseRef-Made-Up'),
+  warningAboutLicenseRef
+);
+
+assert.deepEqual(
+  valid('(MIT OR LicenseRef-Made-Up)'),
+  warningAboutLicenseRef
+);
+```
+
+If you can't describe your licensing terms with standardized SPDX identifiers, put the terms in a file in the package and point users there:
+
+```javascript
+assert.deepEqual(
+  valid('SEE LICENSE IN LICENSE.txt'),
+  {
+    validForNewPackages: true,
+    validForOldPackages: true,
+    inFile: 'LICENSE.txt'
+  }
+);
+
+assert.deepEqual(
+  valid('SEE LICENSE IN license.md'),
+  {
+    validForNewPackages: true,
+    validForOldPackages: true,
+    inFile: 'license.md'
+  }
+);
+```
+
+If there aren't any licensing terms, use `UNLICENSED`:
+
+```javascript
+var unlicensed = {
+  validForNewPackages: true,
+  validForOldPackages: true,
+  unlicensed: true
+};
+assert.deepEqual(valid('UNLICENSED'), unlicensed);
+assert.deepEqual(valid('UNLICENCED'), unlicensed);
+```
diff --git a/server/node_modules/validate-npm-package-license/index.js b/server/node_modules/validate-npm-package-license/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..35eaa732559ce27630aabb4274d86f9d1d9c4a1c
--- /dev/null
+++ b/server/node_modules/validate-npm-package-license/index.js
@@ -0,0 +1,86 @@
+var parse = require('spdx-expression-parse');
+var correct = require('spdx-correct');
+
+var genericWarning = (
+  'license should be ' +
+  'a valid SPDX license expression (without "LicenseRef"), ' +
+  '"UNLICENSED", or ' +
+  '"SEE LICENSE IN <filename>"'
+);
+
+var fileReferenceRE = /^SEE LICEN[CS]E IN (.+)$/;
+
+function startsWith(prefix, string) {
+  return string.slice(0, prefix.length) === prefix;
+}
+
+function usesLicenseRef(ast) {
+  if (ast.hasOwnProperty('license')) {
+    var license = ast.license;
+    return (
+      startsWith('LicenseRef', license) ||
+      startsWith('DocumentRef', license)
+    );
+  } else {
+    return (
+      usesLicenseRef(ast.left) ||
+      usesLicenseRef(ast.right)
+    );
+  }
+}
+
+module.exports = function(argument) {
+  var ast;
+
+  try {
+    ast = parse(argument);
+  } catch (e) {
+    var match
+    if (
+      argument === 'UNLICENSED' ||
+      argument === 'UNLICENCED'
+    ) {
+      return {
+        validForOldPackages: true,
+        validForNewPackages: true,
+        unlicensed: true
+      };
+    } else if (match = fileReferenceRE.exec(argument)) {
+      return {
+        validForOldPackages: true,
+        validForNewPackages: true,
+        inFile: match[1]
+      };
+    } else {
+      var result = {
+        validForOldPackages: false,
+        validForNewPackages: false,
+        warnings: [genericWarning]
+      };
+      if (argument.trim().length !== 0) {
+        var corrected = correct(argument);
+        if (corrected) {
+          result.warnings.push(
+            'license is similar to the valid expression "' + corrected + '"'
+          );
+        }
+      }
+      return result;
+    }
+  }
+
+  if (usesLicenseRef(ast)) {
+    return {
+      validForNewPackages: false,
+      validForOldPackages: false,
+      spdx: true,
+      warnings: [genericWarning]
+    };
+  } else {
+    return {
+      validForNewPackages: true,
+      validForOldPackages: true,
+      spdx: true
+    };
+  }
+};
diff --git a/server/node_modules/validate-npm-package-license/package.json b/server/node_modules/validate-npm-package-license/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..1fd37dd044e121163c5c5c61878154cab8798425
--- /dev/null
+++ b/server/node_modules/validate-npm-package-license/package.json
@@ -0,0 +1,67 @@
+{
+  "_from": "validate-npm-package-license@^3.0.1",
+  "_id": "validate-npm-package-license@3.0.4",
+  "_inBundle": false,
+  "_integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+  "_location": "/validate-npm-package-license",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "validate-npm-package-license@^3.0.1",
+    "name": "validate-npm-package-license",
+    "escapedName": "validate-npm-package-license",
+    "rawSpec": "^3.0.1",
+    "saveSpec": null,
+    "fetchSpec": "^3.0.1"
+  },
+  "_requiredBy": [
+    "/normalize-package-data"
+  ],
+  "_resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+  "_shasum": "fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a",
+  "_spec": "validate-npm-package-license@^3.0.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/normalize-package-data",
+  "author": {
+    "name": "Kyle E. Mitchell",
+    "email": "kyle@kemitchell.com",
+    "url": "https://kemitchell.com"
+  },
+  "bugs": {
+    "url": "https://github.com/kemitchell/validate-npm-package-license.js/issues"
+  },
+  "bundleDependencies": false,
+  "contributors": [
+    {
+      "name": "Mark Stacey",
+      "email": "markjstacey@gmail.com"
+    }
+  ],
+  "dependencies": {
+    "spdx-correct": "^3.0.0",
+    "spdx-expression-parse": "^3.0.0"
+  },
+  "deprecated": false,
+  "description": "Give me a string and I'll tell you if it's a valid npm package license string",
+  "devDependencies": {
+    "defence-cli": "^2.0.1",
+    "replace-require-self": "^1.0.0"
+  },
+  "homepage": "https://github.com/kemitchell/validate-npm-package-license.js#readme",
+  "keywords": [
+    "license",
+    "npm",
+    "package",
+    "validation"
+  ],
+  "license": "Apache-2.0",
+  "name": "validate-npm-package-license",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/kemitchell/validate-npm-package-license.js.git"
+  },
+  "scripts": {
+    "test": "defence README.md | replace-require-self | node"
+  },
+  "version": "3.0.4"
+}
diff --git a/server/node_modules/which-module/CHANGELOG.md b/server/node_modules/which-module/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..6c8f5f2940e57335c1b48cab33eea70807612912
--- /dev/null
+++ b/server/node_modules/which-module/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Change Log
+
+All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+<a name="1.0.0"></a>
+# 1.0.0 (2016-06-06)
+
+
+### Features
+
+* initial code ([08074cd](https://github.com/nexdrew/which-module/commit/08074cd))
diff --git a/server/node_modules/which-module/LICENSE b/server/node_modules/which-module/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..ab601b657ea8c63fe2f7ebea228d0ec1caca6c53
--- /dev/null
+++ b/server/node_modules/which-module/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2016, Contributors
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
diff --git a/server/node_modules/which-module/README.md b/server/node_modules/which-module/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a8c4bf8d702f26f467f39d58d6c47ff288b47b2e
--- /dev/null
+++ b/server/node_modules/which-module/README.md
@@ -0,0 +1,55 @@
+# which-module
+
+> Find the module object for something that was require()d
+
+[![Build Status](https://travis-ci.org/nexdrew/which-module.svg?branch=master)](https://travis-ci.org/nexdrew/which-module)
+[![Coverage Status](https://coveralls.io/repos/github/nexdrew/which-module/badge.svg?branch=master)](https://coveralls.io/github/nexdrew/which-module?branch=master)
+[![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version)
+
+Find the `module` object in `require.cache` for something that was `require()`d
+or `import`ed - essentially a reverse `require()` lookup.
+
+Useful for libs that want to e.g. lookup a filename for a module or submodule
+that it did not `require()` itself.
+
+## Install and Usage
+
+```
+npm install --save which-module
+```
+
+```js
+const whichModule = require('which-module')
+
+console.log(whichModule(require('something')))
+// Module {
+//   id: '/path/to/project/node_modules/something/index.js',
+//   exports: [Function],
+//   parent: ...,
+//   filename: '/path/to/project/node_modules/something/index.js',
+//   loaded: true,
+//   children: [],
+//   paths: [ '/path/to/project/node_modules/something/node_modules',
+//            '/path/to/project/node_modules',
+//            '/path/to/node_modules',
+//            '/path/node_modules',
+//            '/node_modules' ] }
+```
+
+## API
+
+### `whichModule(exported)`
+
+Return the [`module` object](https://nodejs.org/api/modules.html#modules_the_module_object),
+if any, that represents the given argument in the `require.cache`.
+
+`exported` can be anything that was previously `require()`d or `import`ed as a
+module, submodule, or dependency - which means `exported` is identical to the
+`module.exports` returned by this method.
+
+If `exported` did not come from the `exports` of a `module` in `require.cache`,
+then this method returns `null`.
+
+## License
+
+ISC © Contributors
diff --git a/server/node_modules/which-module/index.js b/server/node_modules/which-module/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..45559b781813bd2db880efedd55760af7471ac72
--- /dev/null
+++ b/server/node_modules/which-module/index.js
@@ -0,0 +1,9 @@
+'use strict'
+
+module.exports = function whichModule (exported) {
+  for (var i = 0, files = Object.keys(require.cache), mod; i < files.length; i++) {
+    mod = require.cache[files[i]]
+    if (mod.exports === exported) return mod
+  }
+  return null
+}
diff --git a/server/node_modules/which-module/package.json b/server/node_modules/which-module/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..5703b0e1f642167de397c6d234dd01bebe154c04
--- /dev/null
+++ b/server/node_modules/which-module/package.json
@@ -0,0 +1,68 @@
+{
+  "_from": "which-module@^1.0.0",
+  "_id": "which-module@1.0.0",
+  "_inBundle": false,
+  "_integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
+  "_location": "/which-module",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "which-module@^1.0.0",
+    "name": "which-module",
+    "escapedName": "which-module",
+    "rawSpec": "^1.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^1.0.0"
+  },
+  "_requiredBy": [
+    "/yargs"
+  ],
+  "_resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+  "_shasum": "bba63ca861948994ff307736089e3b96026c2a4f",
+  "_spec": "which-module@^1.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "nexdrew"
+  },
+  "bugs": {
+    "url": "https://github.com/nexdrew/which-module/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Find the module object for something that was require()d",
+  "devDependencies": {
+    "ava": "^0.15.2",
+    "coveralls": "^2.11.9",
+    "nyc": "^6.4.4",
+    "standard": "^7.1.2",
+    "standard-version": "^2.3.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/nexdrew/which-module#readme",
+  "keywords": [
+    "which",
+    "module",
+    "exports",
+    "filename",
+    "require",
+    "reverse",
+    "lookup"
+  ],
+  "license": "ISC",
+  "main": "index.js",
+  "name": "which-module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/nexdrew/which-module.git"
+  },
+  "scripts": {
+    "coverage": "nyc report --reporter=text-lcov | coveralls",
+    "pretest": "standard",
+    "release": "standard-version",
+    "test": "nyc ava"
+  },
+  "version": "1.0.0"
+}
diff --git a/server/node_modules/window-size/LICENSE b/server/node_modules/window-size/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..65f90aca8c2fff1b890f31f571aa41ddfc8d9a10
--- /dev/null
+++ b/server/node_modules/window-size/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015, Jon Schlinkert.
+
+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.
diff --git a/server/node_modules/window-size/README.md b/server/node_modules/window-size/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..0985bd6bf9d634ee7655a59a9d9f3f6f1461c289
--- /dev/null
+++ b/server/node_modules/window-size/README.md
@@ -0,0 +1,45 @@
+# window-size [![NPM version](https://badge.fury.io/js/window-size.svg)](http://badge.fury.io/js/window-size)  [![Build Status](https://travis-ci.org/jonschlinkert/window-size.svg)](https://travis-ci.org/jonschlinkert/window-size)
+
+> Reliable way to to get the height and width of the terminal/console in a node.js environment.
+
+## Install
+
+Install with [npm](https://www.npmjs.com/)
+
+```sh
+$ npm i window-size --save
+```
+
+## Usage
+
+```js
+var size = require('window-size');
+size.height; // "25" (rows)
+size.width; // "80" (columns)
+```
+
+## Other projects
+
+* [base-cli](https://www.npmjs.com/package/base-cli): Plugin for base-methods that maps built-in methods to CLI args (also supports methods from a… [more](https://www.npmjs.com/package/base-cli) | [homepage](https://github.com/jonschlinkert/base-cli)
+* [lint-deps](https://www.npmjs.com/package/lint-deps): CLI tool that tells you when dependencies are missing from package.json and offers you a… [more](https://www.npmjs.com/package/lint-deps) | [homepage](https://github.com/jonschlinkert/lint-deps)
+* [yargs](https://www.npmjs.com/package/yargs): Light-weight option parsing with an argv hash. No optstrings attached. | [homepage](https://github.com/bcoe/yargs#readme)
+
+## Contributing
+
+Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/jonschlinkert/window-size/issues/new).
+
+## Author
+
+**Jon Schlinkert**
+
++ [github/jonschlinkert](https://github.com/jonschlinkert)
++ [twitter/jonschlinkert](http://twitter.com/jonschlinkert)
+
+## License
+
+Copyright © 2014-2015 [Jon Schlinkert](https://github.com/jonschlinkert)
+Released under the MIT license.
+
+***
+
+_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on November 15, 2015._
\ No newline at end of file
diff --git a/server/node_modules/window-size/cli.js b/server/node_modules/window-size/cli.js
new file mode 100755
index 0000000000000000000000000000000000000000..dd8d0e57899a75f903c09197b1895b632cc41f6e
--- /dev/null
+++ b/server/node_modules/window-size/cli.js
@@ -0,0 +1,30 @@
+#!/usr/bin/env node
+'use strict';
+var helpText = ['Usage',
+'  $ window-size',
+'',
+'Example',
+'  $ window-size',
+'  height: 40 ',
+'  width : 145',
+''].join('\n');
+
+function showSize () {
+  var size = require('./');
+  console.log('height: ' + size.height);
+  console.log('width : ' + size.width);
+}
+
+if (process.argv.length > 2) {
+  switch (process.argv[2]) {
+    case 'help':
+    case '--help':
+    case '-h':
+      console.log(helpText);
+      break;
+    default:
+      showSize();
+  }
+} else {
+  showSize();
+}
diff --git a/server/node_modules/window-size/index.js b/server/node_modules/window-size/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb9e7cb22e542d46cdd32c6d73257323e5fc1c1e
--- /dev/null
+++ b/server/node_modules/window-size/index.js
@@ -0,0 +1,32 @@
+'use strict';
+
+/*!
+ * window-size <https://github.com/jonschlinkert/window-size>
+ *
+ * Copyright (c) 2014-2015 Jon Schlinkert
+ * Licensed under the MIT license.
+ */
+
+var tty = require('tty');
+
+module.exports = (function () {
+  var width;
+  var height;
+
+  if (tty.isatty(1) && tty.isatty(2)) {
+    if (process.stdout.getWindowSize) {
+      width = process.stdout.getWindowSize(1)[0];
+      height = process.stdout.getWindowSize(1)[1];
+    } else if (tty.getWindowSize) {
+      width = tty.getWindowSize()[1];
+      height = tty.getWindowSize()[0];
+    } else if (process.stdout.columns && process.stdout.rows) {
+      height = process.stdout.rows;
+      width = process.stdout.columns;
+    }
+  } else {
+    Error('window-size could not get size with tty or process.stdout.');
+  }
+
+  return {height: height, width: width};
+})();
diff --git a/server/node_modules/window-size/package.json b/server/node_modules/window-size/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..8160e0db804fd0a92daa2dd428c7cd74e6d67fae
--- /dev/null
+++ b/server/node_modules/window-size/package.json
@@ -0,0 +1,81 @@
+{
+  "_from": "window-size@^0.2.0",
+  "_id": "window-size@0.2.0",
+  "_inBundle": false,
+  "_integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=",
+  "_location": "/window-size",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "window-size@^0.2.0",
+    "name": "window-size",
+    "escapedName": "window-size",
+    "rawSpec": "^0.2.0",
+    "saveSpec": null,
+    "fetchSpec": "^0.2.0"
+  },
+  "_requiredBy": [
+    "/yargs"
+  ],
+  "_resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz",
+  "_shasum": "b4315bb4214a3d7058ebeee892e13fa24d98b075",
+  "_spec": "window-size@^0.2.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "Jon Schlinkert",
+    "url": "https://github.com/jonschlinkert"
+  },
+  "bin": {
+    "window-size": "cli.js"
+  },
+  "bugs": {
+    "url": "https://github.com/jonschlinkert/window-size/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Reliable way to to get the height and width of the terminal/console in a node.js environment.",
+  "devDependencies": {
+    "semistandard": "^7.0.2",
+    "tap": "^2.2.1"
+  },
+  "engines": {
+    "node": ">= 0.10.0"
+  },
+  "files": [
+    "index.js",
+    "cli.js"
+  ],
+  "homepage": "https://github.com/jonschlinkert/window-size",
+  "keywords": [
+    "console",
+    "height",
+    "resize",
+    "size",
+    "terminal",
+    "tty",
+    "width",
+    "window"
+  ],
+  "license": "MIT",
+  "main": "index.js",
+  "name": "window-size",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/jonschlinkert/window-size.git"
+  },
+  "scripts": {
+    "pretest": "semistandard",
+    "test": "tap --coverage test.js"
+  },
+  "verb": {
+    "related": {
+      "list": [
+        "yargs",
+        "lint-deps",
+        "base-cli"
+      ]
+    }
+  },
+  "version": "0.2.0"
+}
diff --git a/server/node_modules/wrap-ansi/index.js b/server/node_modules/wrap-ansi/index.js
new file mode 100755
index 0000000000000000000000000000000000000000..ff625435fa1053df6b90852954617a37929cf0e6
--- /dev/null
+++ b/server/node_modules/wrap-ansi/index.js
@@ -0,0 +1,168 @@
+'use strict';
+var stringWidth = require('string-width');
+var stripAnsi = require('strip-ansi');
+
+var ESCAPES = [
+	'\u001b',
+	'\u009b'
+];
+
+var END_CODE = 39;
+
+var ESCAPE_CODES = {
+	0: 0,
+	1: 22,
+	2: 22,
+	3: 23,
+	4: 24,
+	7: 27,
+	8: 28,
+	9: 29,
+	30: 39,
+	31: 39,
+	32: 39,
+	33: 39,
+	34: 39,
+	35: 39,
+	36: 39,
+	37: 39,
+	90: 39,
+	40: 49,
+	41: 49,
+	42: 49,
+	43: 49,
+	44: 49,
+	45: 49,
+	46: 49,
+	47: 49
+};
+
+function wrapAnsi(code) {
+	return ESCAPES[0] + '[' + code + 'm';
+}
+
+// calculate the length of words split on ' ', ignoring
+// the extra characters added by ansi escape codes.
+function wordLengths(str) {
+	return str.split(' ').map(function (s) {
+		return stringWidth(s);
+	});
+}
+
+// wrap a long word across multiple rows.
+// ansi escape codes do not count towards length.
+function wrapWord(rows, word, cols) {
+	var insideEscape = false;
+	var visible = stripAnsi(rows[rows.length - 1]).length;
+
+	for (var i = 0; i < word.length; i++) {
+		var x = word[i];
+
+		rows[rows.length - 1] += x;
+
+		if (ESCAPES.indexOf(x) !== -1) {
+			insideEscape = true;
+		} else if (insideEscape && x === 'm') {
+			insideEscape = false;
+			continue;
+		}
+
+		if (insideEscape) {
+			continue;
+		}
+
+		visible++;
+
+		if (visible >= cols && i < word.length - 1) {
+			rows.push('');
+			visible = 0;
+		}
+	}
+
+	// it's possible that the last row we copy over is only
+	// ansi escape characters, handle this edge-case.
+	if (!visible && rows[rows.length - 1].length > 0 && rows.length > 1) {
+		rows[rows.length - 2] += rows.pop();
+	}
+}
+
+// the wrap-ansi module can be invoked
+// in either 'hard' or 'soft' wrap mode.
+//
+// 'hard' will never allow a string to take up more
+// than cols characters.
+//
+// 'soft' allows long words to expand past the column length.
+function exec(str, cols, opts) {
+	var options = opts || {};
+
+	var pre = '';
+	var ret = '';
+	var escapeCode;
+
+	var lengths = wordLengths(str);
+	var words = str.split(' ');
+	var rows = [''];
+
+	for (var i = 0, word; (word = words[i]) !== undefined; i++) {
+		var rowLength = stringWidth(rows[rows.length - 1]);
+
+		if (rowLength) {
+			rows[rows.length - 1] += ' ';
+			rowLength++;
+		}
+
+		// in 'hard' wrap mode, the length of a line is
+		// never allowed to extend past 'cols'.
+		if (lengths[i] > cols && options.hard) {
+			if (rowLength) {
+				rows.push('');
+			}
+			wrapWord(rows, word, cols);
+			continue;
+		}
+
+		if (rowLength + lengths[i] > cols && rowLength > 0) {
+			if (options.wordWrap === false && rowLength < cols) {
+				wrapWord(rows, word, cols);
+				continue;
+			}
+
+			rows.push('');
+		}
+
+		rows[rows.length - 1] += word;
+	}
+
+	pre = rows.map(function (r) {
+		return r.trim();
+	}).join('\n');
+
+	for (var j = 0; j < pre.length; j++) {
+		var y = pre[j];
+
+		ret += y;
+
+		if (ESCAPES.indexOf(y) !== -1) {
+			var code = parseFloat(/[0-9][^m]*/.exec(pre.slice(j, j + 4)));
+			escapeCode = code === END_CODE ? null : code;
+		}
+
+		if (escapeCode && ESCAPE_CODES[escapeCode]) {
+			if (pre[j + 1] === '\n') {
+				ret += wrapAnsi(ESCAPE_CODES[escapeCode]);
+			} else if (y === '\n') {
+				ret += wrapAnsi(escapeCode);
+			}
+		}
+	}
+
+	return ret;
+}
+
+// for each line break, invoke the method separately.
+module.exports = function (str, cols, opts) {
+	return String(str).split('\n').map(function (substr) {
+		return exec(substr, cols, opts);
+	}).join('\n');
+};
diff --git a/server/node_modules/wrap-ansi/license b/server/node_modules/wrap-ansi/license
new file mode 100644
index 0000000000000000000000000000000000000000..654d0bfe943437d43242325b1fbcff5f400d84ee
--- /dev/null
+++ b/server/node_modules/wrap-ansi/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
+
+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.
diff --git a/server/node_modules/wrap-ansi/package.json b/server/node_modules/wrap-ansi/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..ecb18015fab7e008110557e8708d3b0c07be710d
--- /dev/null
+++ b/server/node_modules/wrap-ansi/package.json
@@ -0,0 +1,116 @@
+{
+  "_from": "wrap-ansi@^2.0.0",
+  "_id": "wrap-ansi@2.1.0",
+  "_inBundle": false,
+  "_integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+  "_location": "/wrap-ansi",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "wrap-ansi@^2.0.0",
+    "name": "wrap-ansi",
+    "escapedName": "wrap-ansi",
+    "rawSpec": "^2.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^2.0.0"
+  },
+  "_requiredBy": [
+    "/cliui"
+  ],
+  "_resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+  "_shasum": "d8fc3d284dd05794fe84973caecdd1cf824fdd85",
+  "_spec": "wrap-ansi@^2.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/cliui",
+  "author": {
+    "name": "Sindre Sorhus",
+    "email": "sindresorhus@gmail.com",
+    "url": "sindresorhus.com"
+  },
+  "bugs": {
+    "url": "https://github.com/chalk/wrap-ansi/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "string-width": "^1.0.1",
+    "strip-ansi": "^3.0.1"
+  },
+  "deprecated": false,
+  "description": "Wordwrap a string with ANSI escape codes",
+  "devDependencies": {
+    "ava": "^0.16.0",
+    "chalk": "^1.1.0",
+    "coveralls": "^2.11.4",
+    "has-ansi": "^2.0.0",
+    "nyc": "^6.2.1",
+    "strip-ansi": "^3.0.0",
+    "xo": "*"
+  },
+  "engines": {
+    "node": ">=0.10.0"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/chalk/wrap-ansi#readme",
+  "keywords": [
+    "wrap",
+    "break",
+    "wordwrap",
+    "wordbreak",
+    "linewrap",
+    "ansi",
+    "styles",
+    "color",
+    "colour",
+    "colors",
+    "terminal",
+    "console",
+    "cli",
+    "string",
+    "tty",
+    "escape",
+    "formatting",
+    "rgb",
+    "256",
+    "shell",
+    "xterm",
+    "log",
+    "logging",
+    "command-line",
+    "text"
+  ],
+  "license": "MIT",
+  "maintainers": [
+    {
+      "name": "Sindre Sorhus",
+      "email": "sindresorhus@gmail.com",
+      "url": "sindresorhus.com"
+    },
+    {
+      "name": "Joshua Appelman",
+      "email": "jappelman@xebia.com",
+      "url": "jbnicolai.com"
+    },
+    {
+      "name": "JD Ballard",
+      "email": "i.am.qix@gmail.com",
+      "url": "github.com/qix-"
+    },
+    {
+      "name": "Benjamin Coe",
+      "email": "ben@npmjs.com",
+      "url": "github.com/bcoe"
+    }
+  ],
+  "name": "wrap-ansi",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/chalk/wrap-ansi.git"
+  },
+  "scripts": {
+    "coveralls": "nyc report --reporter=text-lcov | coveralls",
+    "test": "xo && nyc ava"
+  },
+  "version": "2.1.0"
+}
diff --git a/server/node_modules/wrap-ansi/readme.md b/server/node_modules/wrap-ansi/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..59fc96bda4c0c689991c8620589c46d19a17c6fc
--- /dev/null
+++ b/server/node_modules/wrap-ansi/readme.md
@@ -0,0 +1,73 @@
+# wrap-ansi [![Build Status](https://travis-ci.org/chalk/wrap-ansi.svg?branch=master)](https://travis-ci.org/chalk/wrap-ansi) [![Coverage Status](https://coveralls.io/repos/github/chalk/wrap-ansi/badge.svg?branch=master)](https://coveralls.io/github/chalk/wrap-ansi?branch=master)
+
+> Wordwrap a string with [ANSI escape codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles)
+
+
+## Install
+
+```
+$ npm install --save wrap-ansi
+```
+
+
+## Usage
+
+```js
+const chalk = require('chalk');
+const wrapAnsi = require('wrap-ansi');
+
+const input = 'The quick brown ' + chalk.red('fox jumped over ') +
+	'the lazy ' + chalk.green('dog and then ran away with the unicorn.');
+
+console.log(wrapAnsi(input, 20));
+```
+
+<img width="331" src="screenshot.png">
+
+
+## API
+
+### wrapAnsi(input, columns, [options])
+
+Wrap words to the specified column width.
+
+#### input
+
+Type: `string`
+
+String with ANSI escape codes. Like one styled by [`chalk`](https://github.com/chalk/chalk).
+
+#### columns
+
+Type: `number`
+
+Number of columns to wrap the text to.
+
+#### options
+
+##### hard
+
+Type: `boolean`<br>
+Default: `false`
+
+By default the wrap is soft, meaning long words may extend past the column width. Setting this to `true` will make it hard wrap at the column width.
+
+##### wordWrap
+
+Type: `boolean`<br>
+Default: `true`
+
+By default, an attempt is made to split words at spaces, ensuring that they don't extend past the configured columns. If wordWrap is `false`, each column will instead be completely filled splitting words as necessary.
+
+
+## Related
+
+- [slice-ansi](https://github.com/chalk/slice-ansi) - Slice a string with ANSI escape codes
+- [cli-truncate](https://github.com/sindresorhus/cli-truncate) - Truncate a string to a specific width in the terminal
+- [chalk](https://github.com/chalk/chalk) - Terminal string styling done right
+- [jsesc](https://github.com/mathiasbynens/jsesc) - Generate ASCII-only output from Unicode strings. Useful for creating test fixtures.
+
+
+## License
+
+MIT © [Sindre Sorhus](https://sindresorhus.com)
diff --git a/server/node_modules/xtend/.jshintrc b/server/node_modules/xtend/.jshintrc
new file mode 100644
index 0000000000000000000000000000000000000000..77887b5f0f2efc24bd55430cb6f95f8a0cad89d8
--- /dev/null
+++ b/server/node_modules/xtend/.jshintrc
@@ -0,0 +1,30 @@
+{
+    "maxdepth": 4,
+    "maxstatements": 200,
+    "maxcomplexity": 12,
+    "maxlen": 80,
+    "maxparams": 5,
+
+    "curly": true,
+    "eqeqeq": true,
+    "immed": true,
+    "latedef": false,
+    "noarg": true,
+    "noempty": true,
+    "nonew": true,
+    "undef": true,
+    "unused": "vars",
+    "trailing": true,
+
+    "quotmark": true,
+    "expr": true,
+    "asi": true,
+
+    "browser": false,
+    "esnext": true,
+    "devel": false,
+    "node": false,
+    "nonstandard": false,
+
+    "predef": ["require", "module", "__dirname", "__filename"]
+}
diff --git a/server/node_modules/xtend/LICENSE b/server/node_modules/xtend/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..0099f4f6c77f40ac409076408ad07449ffe246d3
--- /dev/null
+++ b/server/node_modules/xtend/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+Copyright (c) 2012-2014 Raynos.
+
+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.
diff --git a/server/node_modules/xtend/README.md b/server/node_modules/xtend/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..4a2703cff276b155e89c3abb7b09fbdfe90273f4
--- /dev/null
+++ b/server/node_modules/xtend/README.md
@@ -0,0 +1,32 @@
+# xtend
+
+[![browser support][3]][4]
+
+[![locked](http://badges.github.io/stability-badges/dist/locked.svg)](http://github.com/badges/stability-badges)
+
+Extend like a boss
+
+xtend is a basic utility library which allows you to extend an object by appending all of the properties from each object in a list. When there are identical properties, the right-most property takes precedence.
+
+## Examples
+
+```js
+var extend = require("xtend")
+
+// extend returns a new object. Does not mutate arguments
+var combination = extend({
+    a: "a",
+    b: "c"
+}, {
+    b: "b"
+})
+// { a: "a", b: "b" }
+```
+
+## Stability status: Locked
+
+## MIT Licensed 
+
+
+  [3]: http://ci.testling.com/Raynos/xtend.png
+  [4]: http://ci.testling.com/Raynos/xtend
diff --git a/server/node_modules/xtend/immutable.js b/server/node_modules/xtend/immutable.js
new file mode 100644
index 0000000000000000000000000000000000000000..94889c9de11a181cec153de1713c8ae14ae4cb43
--- /dev/null
+++ b/server/node_modules/xtend/immutable.js
@@ -0,0 +1,19 @@
+module.exports = extend
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+function extend() {
+    var target = {}
+
+    for (var i = 0; i < arguments.length; i++) {
+        var source = arguments[i]
+
+        for (var key in source) {
+            if (hasOwnProperty.call(source, key)) {
+                target[key] = source[key]
+            }
+        }
+    }
+
+    return target
+}
diff --git a/server/node_modules/xtend/mutable.js b/server/node_modules/xtend/mutable.js
new file mode 100644
index 0000000000000000000000000000000000000000..72debede6ca58592fe93b5ab22d434311a76861b
--- /dev/null
+++ b/server/node_modules/xtend/mutable.js
@@ -0,0 +1,17 @@
+module.exports = extend
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+function extend(target) {
+    for (var i = 1; i < arguments.length; i++) {
+        var source = arguments[i]
+
+        for (var key in source) {
+            if (hasOwnProperty.call(source, key)) {
+                target[key] = source[key]
+            }
+        }
+    }
+
+    return target
+}
diff --git a/server/node_modules/xtend/package.json b/server/node_modules/xtend/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..57f0a9b51999b145da6e3d75066b137cf40101d1
--- /dev/null
+++ b/server/node_modules/xtend/package.json
@@ -0,0 +1,86 @@
+{
+  "_from": "xtend@^4.0.0",
+  "_id": "xtend@4.0.2",
+  "_inBundle": false,
+  "_integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+  "_location": "/xtend",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "xtend@^4.0.0",
+    "name": "xtend",
+    "escapedName": "xtend",
+    "rawSpec": "^4.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^4.0.0"
+  },
+  "_requiredBy": [
+    "/postgres-interval"
+  ],
+  "_resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+  "_shasum": "bb72779f5fa465186b1f438f674fa347fdb5db54",
+  "_spec": "xtend@^4.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/postgres-interval",
+  "author": {
+    "name": "Raynos",
+    "email": "raynos2@gmail.com"
+  },
+  "bugs": {
+    "url": "https://github.com/Raynos/xtend/issues",
+    "email": "raynos2@gmail.com"
+  },
+  "bundleDependencies": false,
+  "contributors": [
+    {
+      "name": "Jake Verbaten"
+    },
+    {
+      "name": "Matt Esch"
+    }
+  ],
+  "dependencies": {},
+  "deprecated": false,
+  "description": "extend like a boss",
+  "devDependencies": {
+    "tape": "~1.1.0"
+  },
+  "engines": {
+    "node": ">=0.4"
+  },
+  "homepage": "https://github.com/Raynos/xtend",
+  "keywords": [
+    "extend",
+    "merge",
+    "options",
+    "opts",
+    "object",
+    "array"
+  ],
+  "license": "MIT",
+  "main": "immutable",
+  "name": "xtend",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/Raynos/xtend.git"
+  },
+  "scripts": {
+    "test": "node test"
+  },
+  "testling": {
+    "files": "test.js",
+    "browsers": [
+      "ie/7..latest",
+      "firefox/16..latest",
+      "firefox/nightly",
+      "chrome/22..latest",
+      "chrome/canary",
+      "opera/12..latest",
+      "opera/next",
+      "safari/5.1..latest",
+      "ipad/6.0..latest",
+      "iphone/6.0..latest"
+    ]
+  },
+  "version": "4.0.2"
+}
diff --git a/server/node_modules/xtend/test.js b/server/node_modules/xtend/test.js
new file mode 100644
index 0000000000000000000000000000000000000000..b895b42b3f76804de7ee2ef0231a3343b2f461b3
--- /dev/null
+++ b/server/node_modules/xtend/test.js
@@ -0,0 +1,103 @@
+var test = require("tape")
+var extend = require("./")
+var mutableExtend = require("./mutable")
+
+test("merge", function(assert) {
+    var a = { a: "foo" }
+    var b = { b: "bar" }
+
+    assert.deepEqual(extend(a, b), { a: "foo", b: "bar" })
+    assert.end()
+})
+
+test("replace", function(assert) {
+    var a = { a: "foo" }
+    var b = { a: "bar" }
+
+    assert.deepEqual(extend(a, b), { a: "bar" })
+    assert.end()
+})
+
+test("undefined", function(assert) {
+    var a = { a: undefined }
+    var b = { b: "foo" }
+
+    assert.deepEqual(extend(a, b), { a: undefined, b: "foo" })
+    assert.deepEqual(extend(b, a), { a: undefined, b: "foo" })
+    assert.end()
+})
+
+test("handle 0", function(assert) {
+    var a = { a: "default" }
+    var b = { a: 0 }
+
+    assert.deepEqual(extend(a, b), { a: 0 })
+    assert.deepEqual(extend(b, a), { a: "default" })
+    assert.end()
+})
+
+test("is immutable", function (assert) {
+    var record = {}
+
+    extend(record, { foo: "bar" })
+    assert.equal(record.foo, undefined)
+    assert.end()
+})
+
+test("null as argument", function (assert) {
+    var a = { foo: "bar" }
+    var b = null
+    var c = void 0
+
+    assert.deepEqual(extend(b, a, c), { foo: "bar" })
+    assert.end()
+})
+
+test("mutable", function (assert) {
+    var a = { foo: "bar" }
+
+    mutableExtend(a, { bar: "baz" })
+
+    assert.equal(a.bar, "baz")
+    assert.end()
+})
+
+test("null prototype", function(assert) {
+    var a = { a: "foo" }
+    var b = Object.create(null)
+    b.b = "bar";
+
+    assert.deepEqual(extend(a, b), { a: "foo", b: "bar" })
+    assert.end()
+})
+
+test("null prototype mutable", function (assert) {
+    var a = { foo: "bar" }
+    var b = Object.create(null)
+    b.bar = "baz";
+
+    mutableExtend(a, b)
+
+    assert.equal(a.bar, "baz")
+    assert.end()
+})
+
+test("prototype pollution", function (assert) {
+    var a = {}
+    var maliciousPayload = '{"__proto__":{"oops":"It works!"}}'
+
+    assert.strictEqual(a.oops, undefined)
+    extend({}, maliciousPayload)
+    assert.strictEqual(a.oops, undefined)
+    assert.end()
+})
+
+test("prototype pollution mutable", function (assert) {
+    var a = {}
+    var maliciousPayload = '{"__proto__":{"oops":"It works!"}}'
+
+    assert.strictEqual(a.oops, undefined)
+    mutableExtend({}, maliciousPayload)
+    assert.strictEqual(a.oops, undefined)
+    assert.end()
+})
diff --git a/server/node_modules/y18n/LICENSE b/server/node_modules/y18n/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..3c157f0b9d9bed83163710392914df506bcb15b1
--- /dev/null
+++ b/server/node_modules/y18n/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2015, Contributors
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
diff --git a/server/node_modules/y18n/README.md b/server/node_modules/y18n/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..9859458f20b856bb5a0c6951e89d90f75fcfd059
--- /dev/null
+++ b/server/node_modules/y18n/README.md
@@ -0,0 +1,91 @@
+# y18n
+
+[![Build Status][travis-image]][travis-url]
+[![Coverage Status][coveralls-image]][coveralls-url]
+[![NPM version][npm-image]][npm-url]
+[![js-standard-style][standard-image]][standard-url]
+
+The bare-bones internationalization library used by yargs.
+
+Inspired by [i18n](https://www.npmjs.com/package/i18n).
+
+## Examples
+
+_simple string translation:_
+
+```js
+var __ = require('y18n').__
+
+console.log(__('my awesome string %s', 'foo'))
+```
+
+output:
+
+`my awesome string foo`
+
+_pluralization support:_
+
+```js
+var __n = require('y18n').__n
+
+console.log(__n('one fish %s', '%d fishes %s', 2, 'foo'))
+```
+
+output:
+
+`2 fishes foo`
+
+## JSON Language Files
+
+The JSON language files should be stored in a `./locales` folder.
+File names correspond to locales, e.g., `en.json`, `pirate.json`.
+
+When strings are observed for the first time they will be
+added to the JSON file corresponding to the current locale.
+
+## Methods
+
+### require('y18n')(config)
+
+Create an instance of y18n with the config provided, options include:
+
+* `directory`: the locale directory, default `./locales`.
+* `updateFiles`: should newly observed strings be updated in file, default `true`.
+* `locale`: what locale should be used.
+* `fallbackToLanguage`: should fallback to a language-only file (e.g. `en.json`)
+  be allowed if a file matching the locale does not exist (e.g. `en_US.json`),
+  default `true`.
+
+### y18n.\_\_(str, arg, arg, arg)
+
+Print a localized string, `%s` will be replaced with `arg`s.
+
+### y18n.\_\_n(singularString, pluralString, count, arg, arg, arg)
+
+Print a localized string with appropriate pluralization. If `%d` is provided
+in the string, the `count` will replace this placeholder.
+
+### y18n.setLocale(str)
+
+Set the current locale being used.
+
+### y18n.getLocale()
+
+What locale is currently being used?
+
+### y18n.updateLocale(obj)
+
+Update the current locale with the key value pairs in `obj`.
+
+## License
+
+ISC
+
+[travis-url]: https://travis-ci.org/yargs/y18n
+[travis-image]: https://img.shields.io/travis/yargs/y18n.svg
+[coveralls-url]: https://coveralls.io/github/yargs/y18n
+[coveralls-image]: https://img.shields.io/coveralls/yargs/y18n.svg
+[npm-url]: https://npmjs.org/package/y18n
+[npm-image]: https://img.shields.io/npm/v/y18n.svg
+[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg
+[standard-url]: https://github.com/feross/standard
diff --git a/server/node_modules/y18n/index.js b/server/node_modules/y18n/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..91b159e34298acaae31d9259055207a33f2f5a6f
--- /dev/null
+++ b/server/node_modules/y18n/index.js
@@ -0,0 +1,172 @@
+var fs = require('fs')
+var path = require('path')
+var util = require('util')
+
+function Y18N (opts) {
+  // configurable options.
+  opts = opts || {}
+  this.directory = opts.directory || './locales'
+  this.updateFiles = typeof opts.updateFiles === 'boolean' ? opts.updateFiles : true
+  this.locale = opts.locale || 'en'
+  this.fallbackToLanguage = typeof opts.fallbackToLanguage === 'boolean' ? opts.fallbackToLanguage : true
+
+  // internal stuff.
+  this.cache = {}
+  this.writeQueue = []
+}
+
+Y18N.prototype.__ = function () {
+  var args = Array.prototype.slice.call(arguments)
+  var str = args.shift()
+  var cb = function () {} // start with noop.
+
+  if (typeof args[args.length - 1] === 'function') cb = args.pop()
+  cb = cb || function () {} // noop.
+
+  if (!this.cache[this.locale]) this._readLocaleFile()
+
+  // we've observed a new string, update the language file.
+  if (!this.cache[this.locale][str] && this.updateFiles) {
+    this.cache[this.locale][str] = str
+
+    // include the current directory and locale,
+    // since these values could change before the
+    // write is performed.
+    this._enqueueWrite([this.directory, this.locale, cb])
+  } else {
+    cb()
+  }
+
+  return util.format.apply(util, [this.cache[this.locale][str] || str].concat(args))
+}
+
+Y18N.prototype._enqueueWrite = function (work) {
+  this.writeQueue.push(work)
+  if (this.writeQueue.length === 1) this._processWriteQueue()
+}
+
+Y18N.prototype._processWriteQueue = function () {
+  var _this = this
+  var work = this.writeQueue[0]
+
+  // destructure the enqueued work.
+  var directory = work[0]
+  var locale = work[1]
+  var cb = work[2]
+
+  var languageFile = this._resolveLocaleFile(directory, locale)
+  var serializedLocale = JSON.stringify(this.cache[locale], null, 2)
+
+  fs.writeFile(languageFile, serializedLocale, 'utf-8', function (err) {
+    _this.writeQueue.shift()
+    if (_this.writeQueue.length > 0) _this._processWriteQueue()
+    cb(err)
+  })
+}
+
+Y18N.prototype._readLocaleFile = function () {
+  var localeLookup = {}
+  var languageFile = this._resolveLocaleFile(this.directory, this.locale)
+
+  try {
+    localeLookup = JSON.parse(fs.readFileSync(languageFile, 'utf-8'))
+  } catch (err) {
+    if (err instanceof SyntaxError) {
+      err.message = 'syntax error in ' + languageFile
+    }
+
+    if (err.code === 'ENOENT') localeLookup = {}
+    else throw err
+  }
+
+  this.cache[this.locale] = localeLookup
+}
+
+Y18N.prototype._resolveLocaleFile = function (directory, locale) {
+  var file = path.resolve(directory, './', locale + '.json')
+  if (this.fallbackToLanguage && !this._fileExistsSync(file) && ~locale.lastIndexOf('_')) {
+    // attempt fallback to language only
+    var languageFile = path.resolve(directory, './', locale.split('_')[0] + '.json')
+    if (this._fileExistsSync(languageFile)) file = languageFile
+  }
+  return file
+}
+
+// this only exists because fs.existsSync() "will be deprecated"
+// see https://nodejs.org/api/fs.html#fs_fs_existssync_path
+Y18N.prototype._fileExistsSync = function (file) {
+  try {
+    return fs.statSync(file).isFile()
+  } catch (err) {
+    return false
+  }
+}
+
+Y18N.prototype.__n = function () {
+  var args = Array.prototype.slice.call(arguments)
+  var singular = args.shift()
+  var plural = args.shift()
+  var quantity = args.shift()
+
+  var cb = function () {} // start with noop.
+  if (typeof args[args.length - 1] === 'function') cb = args.pop()
+
+  if (!this.cache[this.locale]) this._readLocaleFile()
+
+  var str = quantity === 1 ? singular : plural
+  if (this.cache[this.locale][singular]) {
+    str = this.cache[this.locale][singular][quantity === 1 ? 'one' : 'other']
+  }
+
+  // we've observed a new string, update the language file.
+  if (!this.cache[this.locale][singular] && this.updateFiles) {
+    this.cache[this.locale][singular] = {
+      one: singular,
+      other: plural
+    }
+
+    // include the current directory and locale,
+    // since these values could change before the
+    // write is performed.
+    this._enqueueWrite([this.directory, this.locale, cb])
+  } else {
+    cb()
+  }
+
+  // if a %d placeholder is provided, add quantity
+  // to the arguments expanded by util.format.
+  var values = [str]
+  if (~str.indexOf('%d')) values.push(quantity)
+
+  return util.format.apply(util, values.concat(args))
+}
+
+Y18N.prototype.setLocale = function (locale) {
+  this.locale = locale
+}
+
+Y18N.prototype.getLocale = function () {
+  return this.locale
+}
+
+Y18N.prototype.updateLocale = function (obj) {
+  if (!this.cache[this.locale]) this._readLocaleFile()
+
+  for (var key in obj) {
+    this.cache[this.locale][key] = obj[key]
+  }
+}
+
+module.exports = function (opts) {
+  var y18n = new Y18N(opts)
+
+  // bind all functions to y18n, so that
+  // they can be used in isolation.
+  for (var key in y18n) {
+    if (typeof y18n[key] === 'function') {
+      y18n[key] = y18n[key].bind(y18n)
+    }
+  }
+
+  return y18n
+}
diff --git a/server/node_modules/y18n/package.json b/server/node_modules/y18n/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..bdb9505104172248e4ad98182cca27d507b6db79
--- /dev/null
+++ b/server/node_modules/y18n/package.json
@@ -0,0 +1,65 @@
+{
+  "_from": "y18n@^3.2.1",
+  "_id": "y18n@3.2.1",
+  "_inBundle": false,
+  "_integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+  "_location": "/y18n",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "y18n@^3.2.1",
+    "name": "y18n",
+    "escapedName": "y18n",
+    "rawSpec": "^3.2.1",
+    "saveSpec": null,
+    "fetchSpec": "^3.2.1"
+  },
+  "_requiredBy": [
+    "/yargs"
+  ],
+  "_resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+  "_shasum": "6d15fba884c08679c0d77e88e7759e811e07fa41",
+  "_spec": "y18n@^3.2.1",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "Ben Coe",
+    "email": "ben@npmjs.com"
+  },
+  "bugs": {
+    "url": "https://github.com/yargs/y18n/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "the bare-bones internationalization library used by yargs",
+  "devDependencies": {
+    "chai": "^3.4.1",
+    "coveralls": "^2.11.6",
+    "mocha": "^2.3.4",
+    "nyc": "^6.1.1",
+    "rimraf": "^2.5.0",
+    "standard": "^5.4.1"
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/yargs/y18n",
+  "keywords": [
+    "i18n",
+    "internationalization",
+    "yargs"
+  ],
+  "license": "ISC",
+  "main": "index.js",
+  "name": "y18n",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/yargs/y18n.git"
+  },
+  "scripts": {
+    "coverage": "nyc report --reporter=text-lcov | coveralls",
+    "pretest": "standard",
+    "test": "nyc mocha"
+  },
+  "version": "3.2.1"
+}
diff --git a/server/node_modules/yargs-parser/CHANGELOG.md b/server/node_modules/yargs-parser/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..49bf34e186d45e528cf1781ca2b3d4b33157986b
--- /dev/null
+++ b/server/node_modules/yargs-parser/CHANGELOG.md
@@ -0,0 +1,83 @@
+# Change Log
+
+All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+<a name="3.2.0"></a>
+# [3.2.0](https://github.com/yargs/yargs-parser/compare/v3.1.0...v3.2.0) (2016-08-13)
+
+
+### Features
+
+* coerce full array instead of each element ([#51](https://github.com/yargs/yargs-parser/issues/51)) ([cc4dc56](https://github.com/yargs/yargs-parser/commit/cc4dc56))
+
+
+
+<a name="3.1.0"></a>
+# [3.1.0](https://github.com/yargs/yargs-parser/compare/v3.0.0...v3.1.0) (2016-08-09)
+
+
+### Bug Fixes
+
+* address pkgConf parsing bug outlined in [#37](https://github.com/yargs/yargs-parser/issues/37) ([#45](https://github.com/yargs/yargs-parser/issues/45)) ([be76ee6](https://github.com/yargs/yargs-parser/commit/be76ee6))
+* better parsing of negative values ([#44](https://github.com/yargs/yargs-parser/issues/44)) ([2e43692](https://github.com/yargs/yargs-parser/commit/2e43692))
+* check aliases when guessing defaults for arguments fixes [#41](https://github.com/yargs/yargs-parser/issues/41) ([#43](https://github.com/yargs/yargs-parser/issues/43)) ([f3e4616](https://github.com/yargs/yargs-parser/commit/f3e4616))
+
+
+### Features
+
+* added coerce option, for providing specialized argument parsing ([#42](https://github.com/yargs/yargs-parser/issues/42)) ([7b49cd2](https://github.com/yargs/yargs-parser/commit/7b49cd2))
+
+
+
+<a name="3.0.0"></a>
+# [3.0.0](https://github.com/yargs/yargs-parser/compare/v2.4.1...v3.0.0) (2016-08-07)
+
+
+### Bug Fixes
+
+* parsing issue with numeric character in group of options ([#19](https://github.com/yargs/yargs-parser/issues/19)) ([f743236](https://github.com/yargs/yargs-parser/commit/f743236))
+* upgraded lodash.assign ([5d7fdf4](https://github.com/yargs/yargs-parser/commit/5d7fdf4))
+
+### BREAKING CHANGES
+
+* subtle change to how values are parsed in a group of single-character arguments.
+* _first released in 3.1.0, better handling of negative values should be considered a breaking change._
+
+
+
+<a name="2.4.1"></a>
+## [2.4.1](https://github.com/yargs/yargs-parser/compare/v2.4.0...v2.4.1) (2016-07-16)
+
+
+### Bug Fixes
+
+* **count:** do not increment a default value ([#39](https://github.com/yargs/yargs-parser/issues/39)) ([b04a189](https://github.com/yargs/yargs-parser/commit/b04a189))
+
+
+
+<a name="2.4.0"></a>
+# [2.4.0](https://github.com/yargs/yargs-parser/compare/v2.3.0...v2.4.0) (2016-04-11)
+
+
+### Features
+
+* **environment:** Support nested options in environment variables ([#26](https://github.com/yargs/yargs-parser/issues/26)) thanks [@elas7](https://github.com/elas7) \o/ ([020778b](https://github.com/yargs/yargs-parser/commit/020778b))
+
+
+
+<a name="2.3.0"></a>
+# [2.3.0](https://github.com/yargs/yargs-parser/compare/v2.2.0...v2.3.0) (2016-04-09)
+
+
+### Bug Fixes
+
+* **boolean:** fix for boolean options with non boolean defaults (#20) ([2dbe86b](https://github.com/yargs/yargs-parser/commit/2dbe86b)), closes [(#20](https://github.com/(/issues/20)
+* **package:** remove tests from tarball ([0353c0d](https://github.com/yargs/yargs-parser/commit/0353c0d))
+* **parsing:** handle calling short option with an empty string as the next value. ([a867165](https://github.com/yargs/yargs-parser/commit/a867165))
+* boolean flag when next value contains the strings 'true' or 'false'. ([69941a6](https://github.com/yargs/yargs-parser/commit/69941a6))
+* update dependencies; add standard-version bin for next release (#24) ([822d9d5](https://github.com/yargs/yargs-parser/commit/822d9d5))
+
+### Features
+
+* **configuration:** Allow to pass configuration objects to yargs-parser ([0780900](https://github.com/yargs/yargs-parser/commit/0780900))
+* **normalize:** allow normalize to work with arrays ([e0eaa1a](https://github.com/yargs/yargs-parser/commit/e0eaa1a))
diff --git a/server/node_modules/yargs-parser/LICENSE.txt b/server/node_modules/yargs-parser/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..836440bef7cf14841c05b0f8635e580c91327fc4
--- /dev/null
+++ b/server/node_modules/yargs-parser/LICENSE.txt
@@ -0,0 +1,14 @@
+Copyright (c) 2016, Contributors
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice
+appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
+LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/server/node_modules/yargs-parser/README.md b/server/node_modules/yargs-parser/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a05cea0276b53c69edec5b51a99395a259e302a0
--- /dev/null
+++ b/server/node_modules/yargs-parser/README.md
@@ -0,0 +1,219 @@
+# yargs-parser
+
+[![Build Status](https://travis-ci.org/yargs/yargs-parser.png)](https://travis-ci.org/yargs/yargs-parser)
+[![Coverage Status](https://coveralls.io/repos/yargs/yargs-parser/badge.svg?branch=)](https://coveralls.io/r/yargs/yargs-parser?branch=master)
+[![NPM version](https://img.shields.io/npm/v/yargs-parser.svg)](https://www.npmjs.com/package/yargs-parser)
+[![Windows Tests](https://img.shields.io/appveyor/ci/bcoe/yargs-parser/master.svg?label=Windows%20Tests)](https://ci.appveyor.com/project/yargs/yargs-parser)
+[![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version)
+
+
+The mighty option parser used by [yargs](https://github.com/yargs/yargs).
+
+visit the [yargs website](http://yargs.js.org/) for more examples, and thorough usage instructions.
+
+<img width="250" src="yargs-logo.png">
+
+## Example
+
+```sh
+npm i yargs-parser --save
+```
+
+```js
+var argv = require('yargs-parser')(process.argv.slice(2))
+console.log(argv)
+```
+
+```sh
+node example.js --foo=33 --bar hello
+{ _: [], foo: 33, bar: 'hello' }
+```
+
+_or parse a string!_
+
+```js
+var argv = require('./')('--foo=99 --bar=33')
+console.log(argv)
+```
+
+```sh
+{ _: [], foo: 99, bar: 33 }
+```
+
+Convert an array of mixed types before passing to `yargs-parser`:
+
+```js
+var parse = require('yargs-parser')
+parse(['-f', 11, '--zoom', 55].join(' '))   // <-- array to string
+parse(['-f', 11, '--zoom', 55].map(String)) // <-- array of strings
+```
+
+## API
+
+### require('yargs-parser')(args, opts={})
+
+Parses command line arguments returning a simple mapping of keys and values.
+
+**expects:**
+
+* `args`: a string or array of strings representing the options to parse.
+* `opts`: provide a set of hints indicating how `args` should be parsed:
+  * `opts.alias`: an object representing the set of aliases for a key: `{alias: {foo: ['f']}}`.
+  * `opts.array`: indicate that keys should be parsed as an array: `{array: ['foo', 'bar']}`.
+  * `opts.boolean`: arguments should be parsed as booleans: `{boolean: ['x', 'y']}`.
+  * `opts.config`: indicate a key that represents a path to a configuration file (this file will be loaded and parsed).
+  * `opts.coerce`: provide a custom synchronous function that returns a coerced value from the argument provided
+    (or throws an error), e.g. `{coerce: {foo: function (arg) {return modifiedArg}}}`.
+  * `opts.count`: indicate a key that should be used as a counter, e.g., `-vvv` = `{v: 3}`.
+  * `opts.default`: provide default values for keys: `{default: {x: 33, y: 'hello world!'}}`.
+  * `opts.envPrefix`: environment variables (`process.env`) with the prefix provided should be parsed.
+  * `opts.narg`: specify that a key requires `n` arguments: `{narg: {x: 2}}`.
+  * `opts.normalize`: `path.normalize()` will be applied to values set to this key.
+  * `opts.string`: keys should be treated as strings (even if they resemble a number `-x 33`).
+  * `opts.configuration`: provide configuration options to the yargs-parser (see: [configuration](#configuration)).
+  * `opts.number`: keys should be treated as numbers.
+
+**returns:**
+
+* `obj`: an object representing the parsed value of `args`
+  * `key/value`: key value pairs for each argument and their aliases.
+  * `_`: an array representing the positional arguments.
+
+### require('yargs-parser').detailed(args, opts={})
+
+Parses a command line string, returning detailed information required by the
+yargs engine.
+
+**expects:**
+
+* `args`: a string or array of strings representing options to parse.
+* `opts`: provide a set of hints indicating how `args`, inputs are identical to `require('yargs-parser')(args, opts={})`.
+
+**returns:**
+
+* `argv`: an object representing the parsed value of `args`
+  * `key/value`: key value pairs for each argument and their aliases.
+  * `_`: an array representing the positional arguments.
+* `error`: populated with an error object if an exception occurred during parsing.
+* `aliases`: the inferred list of aliases built by combining lists in `opts.alias`.
+* `newAliases`: any new aliases added via camel-case expansion.
+* `configuration`: the configuration loaded from the `yargs` stanza in package.json.
+
+<a name="configuration"></a>
+### Configuration
+
+The yargs-parser applies several automated transformations on the keys provided
+in `args`. These features can be turned on and off using the `configuration` field
+of `opts`.
+
+```js
+var parsed = parser(['--no-dice'], {
+  configuration: {
+    'boolean-negation': false
+  }
+})
+```
+
+### short option groups
+
+* default: `true`.
+* key: `short-option-groups`.
+
+Should a group of short-options be treated as boolean flags?
+
+```sh
+node example.js -abc
+{ _: [], a: true, b: true, c: true }
+```
+
+_if disabled:_
+
+```sh
+node example.js -abc
+{ _: [], abc: true }
+```
+
+### camel-case expansion
+
+* default: `true`.
+* key: `camel-case-expansion`.
+
+Should hyphenated arguments be expanded into camel-case aliases?
+
+```sh
+node example.js --foo-bar
+{ _: [], 'foo-bar': true, fooBar: true }
+```
+
+_if disabled:_
+
+```sh
+node example.js --foo-bar
+{ _: [], 'foo-bar': true }
+```
+
+### dot-notation
+
+* default: `true`
+* key: `dot-notation`
+
+Should keys that contain `.` be treated as objects?
+
+```sh
+node example.js --foo.bar
+{ _: [], foo: { bar: true } }
+```
+
+_if disabled:_
+
+```sh
+node example.js --foo.bar
+{ _: [], "foo.bar": true }
+```
+
+### parse numbers
+
+* default: `true`
+* key: 'parse-numbers'
+
+Should keys that look like numbers be treated as such?
+
+```sh
+node example.js --foo=99.3
+{ _: [], foo: 99.3 }
+```
+
+_if disabled:_
+
+```sh
+node example.js --foo=99.3
+{ _: [], foo: "99.3" }
+```
+
+### boolean negation
+
+* default: `true`
+* key: 'boolean-negation'
+
+Should variables prefixed with `--no` be treated as negations?
+
+```sh
+node example.js --no-foo
+{ _: [], foo: false }
+```
+
+_if disabled:_
+
+```sh
+node example.js --no-foo
+{ _: [], "no-foo": true }
+```
+
+## Special Thanks
+
+The yargs project evolves from optimist and minimist. It owes its
+existence to a lot of James Halliday's hard work. Thanks [substack](https://github.com/substack) **beep** **boop** \o/
+
+## License
+
+ISC
diff --git a/server/node_modules/yargs-parser/index.js b/server/node_modules/yargs-parser/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..e2b35b6279d039b5b5b1cb1d2f0fad9b5601b7ad
--- /dev/null
+++ b/server/node_modules/yargs-parser/index.js
@@ -0,0 +1,724 @@
+var assign = require('lodash.assign')
+var camelCase = require('camelcase')
+var path = require('path')
+var tokenizeArgString = require('./lib/tokenize-arg-string')
+var util = require('util')
+
+function parse (args, opts) {
+  if (!opts) opts = {}
+  // allow a string argument to be passed in rather
+  // than an argv array.
+  args = tokenizeArgString(args)
+  // aliases might have transitive relationships, normalize this.
+  var aliases = combineAliases(opts.alias || {})
+  var configuration = assign({}, {
+    'short-option-groups': true,
+    'camel-case-expansion': true,
+    'dot-notation': true,
+    'parse-numbers': true,
+    'boolean-negation': true
+  }, opts.configuration)
+  var defaults = opts.default || {}
+  var configObjects = opts.configObjects || []
+  var envPrefix = opts.envPrefix
+  var newAliases = {}
+  // allow a i18n handler to be passed in, default to a fake one (util.format).
+  var __ = opts.__ || function (str) {
+    return util.format.apply(util, Array.prototype.slice.call(arguments))
+  }
+  var error = null
+  var flags = {
+    aliases: {},
+    arrays: {},
+    bools: {},
+    strings: {},
+    numbers: {},
+    counts: {},
+    normalize: {},
+    configs: {},
+    defaulted: {},
+    nargs: {},
+    coercions: {}
+  }
+  var negative = /^-[0-9]+(\.[0-9]+)?/
+
+  ;[].concat(opts.array).filter(Boolean).forEach(function (key) {
+    flags.arrays[key] = true
+  })
+
+  ;[].concat(opts.boolean).filter(Boolean).forEach(function (key) {
+    flags.bools[key] = true
+  })
+
+  ;[].concat(opts.string).filter(Boolean).forEach(function (key) {
+    flags.strings[key] = true
+  })
+
+  ;[].concat(opts.number).filter(Boolean).forEach(function (key) {
+    flags.numbers[key] = true
+  })
+
+  ;[].concat(opts.count).filter(Boolean).forEach(function (key) {
+    flags.counts[key] = true
+  })
+
+  ;[].concat(opts.normalize).filter(Boolean).forEach(function (key) {
+    flags.normalize[key] = true
+  })
+
+  Object.keys(opts.narg || {}).forEach(function (k) {
+    flags.nargs[k] = opts.narg[k]
+  })
+
+  Object.keys(opts.coerce || {}).forEach(function (k) {
+    flags.coercions[k] = opts.coerce[k]
+  })
+
+  if (Array.isArray(opts.config) || typeof opts.config === 'string') {
+    ;[].concat(opts.config).filter(Boolean).forEach(function (key) {
+      flags.configs[key] = true
+    })
+  } else {
+    Object.keys(opts.config || {}).forEach(function (k) {
+      flags.configs[k] = opts.config[k]
+    })
+  }
+
+  // create a lookup table that takes into account all
+  // combinations of aliases: {f: ['foo'], foo: ['f']}
+  extendAliases(opts.key, aliases, opts.default, flags.arrays)
+
+  // apply default values to all aliases.
+  Object.keys(defaults).forEach(function (key) {
+    (flags.aliases[key] || []).forEach(function (alias) {
+      defaults[alias] = defaults[key]
+    })
+  })
+
+  var argv = { _: [] }
+
+  Object.keys(flags.bools).forEach(function (key) {
+    setArg(key, !(key in defaults) ? false : defaults[key])
+    setDefaulted(key)
+  })
+
+  var notFlags = []
+  if (args.indexOf('--') !== -1) {
+    notFlags = args.slice(args.indexOf('--') + 1)
+    args = args.slice(0, args.indexOf('--'))
+  }
+
+  for (var i = 0; i < args.length; i++) {
+    var arg = args[i]
+    var broken
+    var key
+    var letters
+    var m
+    var next
+    var value
+
+    // -- seperated by =
+    if (arg.match(/^--.+=/) || (
+      !configuration['short-option-groups'] && arg.match(/^-.+=/)
+    )) {
+      // Using [\s\S] instead of . because js doesn't support the
+      // 'dotall' regex modifier. See:
+      // http://stackoverflow.com/a/1068308/13216
+      m = arg.match(/^--?([^=]+)=([\s\S]*)$/)
+
+      // nargs format = '--f=monkey washing cat'
+      if (checkAllAliases(m[1], flags.nargs)) {
+        args.splice(i + 1, 0, m[2])
+        i = eatNargs(i, m[1], args)
+      // arrays format = '--f=a b c'
+      } else if (checkAllAliases(m[1], flags.arrays) && args.length > i + 1) {
+        args.splice(i + 1, 0, m[2])
+        i = eatArray(i, m[1], args)
+      } else {
+        setArg(m[1], m[2])
+      }
+    } else if (arg.match(/^--no-.+/) && configuration['boolean-negation']) {
+      key = arg.match(/^--no-(.+)/)[1]
+      setArg(key, false)
+
+    // -- seperated by space.
+    } else if (arg.match(/^--.+/) || (
+      !configuration['short-option-groups'] && arg.match(/^-.+/)
+    )) {
+      key = arg.match(/^--?(.+)/)[1]
+
+      // nargs format = '--foo a b c'
+      if (checkAllAliases(key, flags.nargs)) {
+        i = eatNargs(i, key, args)
+      // array format = '--foo a b c'
+      } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
+        i = eatArray(i, key, args)
+      } else {
+        next = args[i + 1]
+
+        if (next !== undefined && (!next.match(/^-/) ||
+          next.match(negative)) &&
+          !checkAllAliases(key, flags.bools) &&
+          !checkAllAliases(key, flags.counts)) {
+          setArg(key, next)
+          i++
+        } else if (/^(true|false)$/.test(next)) {
+          setArg(key, next)
+          i++
+        } else {
+          setArg(key, defaultForType(guessType(key, flags)))
+        }
+      }
+
+    // dot-notation flag seperated by '='.
+    } else if (arg.match(/^-.\..+=/)) {
+      m = arg.match(/^-([^=]+)=([\s\S]*)$/)
+      setArg(m[1], m[2])
+
+    // dot-notation flag seperated by space.
+    } else if (arg.match(/^-.\..+/)) {
+      next = args[i + 1]
+      key = arg.match(/^-(.\..+)/)[1]
+
+      if (next !== undefined && !next.match(/^-/) &&
+        !checkAllAliases(key, flags.bools) &&
+        !checkAllAliases(key, flags.counts)) {
+        setArg(key, next)
+        i++
+      } else {
+        setArg(key, defaultForType(guessType(key, flags)))
+      }
+    } else if (arg.match(/^-[^-]+/) && !arg.match(negative)) {
+      letters = arg.slice(1, -1).split('')
+      broken = false
+
+      for (var j = 0; j < letters.length; j++) {
+        next = arg.slice(j + 2)
+
+        if (letters[j + 1] && letters[j + 1] === '=') {
+          value = arg.slice(j + 3)
+          key = letters[j]
+
+          // nargs format = '-f=monkey washing cat'
+          if (checkAllAliases(key, flags.nargs)) {
+            args.splice(i + 1, 0, value)
+            i = eatNargs(i, key, args)
+          // array format = '-f=a b c'
+          } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
+            args.splice(i + 1, 0, value)
+            i = eatArray(i, key, args)
+          } else {
+            setArg(key, value)
+          }
+
+          broken = true
+          break
+        }
+
+        if (next === '-') {
+          setArg(letters[j], next)
+          continue
+        }
+
+        // current letter is an alphabetic character and next value is a number
+        if (/[A-Za-z]/.test(letters[j]) &&
+          /^-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
+          setArg(letters[j], next)
+          broken = true
+          break
+        }
+
+        if (letters[j + 1] && letters[j + 1].match(/\W/)) {
+          setArg(letters[j], next)
+          broken = true
+          break
+        } else {
+          setArg(letters[j], defaultForType(guessType(letters[j], flags)))
+        }
+      }
+
+      key = arg.slice(-1)[0]
+
+      if (!broken && key !== '-') {
+        // nargs format = '-f a b c'
+        if (checkAllAliases(key, flags.nargs)) {
+          i = eatNargs(i, key, args)
+        // array format = '-f a b c'
+        } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
+          i = eatArray(i, key, args)
+        } else {
+          next = args[i + 1]
+
+          if (next !== undefined && (!/^(-|--)[^-]/.test(next) ||
+            next.match(negative)) &&
+            !checkAllAliases(key, flags.bools) &&
+            !checkAllAliases(key, flags.counts)) {
+            setArg(key, next)
+            i++
+          } else if (/^(true|false)$/.test(next)) {
+            setArg(key, next)
+            i++
+          } else {
+            setArg(key, defaultForType(guessType(key, flags)))
+          }
+        }
+      }
+    } else {
+      argv._.push(
+        flags.strings['_'] || !isNumber(arg) ? arg : Number(arg)
+      )
+    }
+  }
+
+  // order of precedence:
+  // 1. command line arg
+  // 2. value from config file
+  // 3. value from config objects
+  // 4. value from env var
+  // 5. configured default value
+  applyEnvVars(argv, true) // special case: check env vars that point to config file
+  setConfig(argv)
+  setConfigObjects()
+  applyEnvVars(argv, false)
+  applyArrayCoercions(argv)
+  applyDefaultsAndAliases(argv, flags.aliases, defaults)
+
+  // for any counts either not in args or without an explicit default, set to 0
+  Object.keys(flags.counts).forEach(function (key) {
+    if (!hasKey(argv, key.split('.'))) setArg(key, 0)
+  })
+
+  notFlags.forEach(function (key) {
+    argv._.push(key)
+  })
+
+  // how many arguments should we consume, based
+  // on the nargs option?
+  function eatNargs (i, key, args) {
+    var toEat = checkAllAliases(key, flags.nargs)
+
+    if (args.length - (i + 1) < toEat) error = Error(__('Not enough arguments following: %s', key))
+
+    for (var ii = i + 1; ii < (toEat + i + 1); ii++) {
+      setArg(key, args[ii])
+    }
+
+    return (i + toEat)
+  }
+
+  // if an option is an array, eat all non-hyphenated arguments
+  // following it... YUM!
+  // e.g., --foo apple banana cat becomes ["apple", "banana", "cat"]
+  function eatArray (i, key, args) {
+    var start = i + 1
+    for (var ii = i + 1; ii < args.length; ii++) {
+      if (/^-/.test(args[ii]) && !negative.test(args[ii])) {
+        if (ii === start) {
+          setArg(key, defaultForType('array'))
+        }
+        break
+      }
+      i = ii
+      setArg(key, args[ii])
+    }
+
+    return i
+  }
+
+  function setArg (key, val) {
+    unsetDefaulted(key)
+
+    // handle parsing boolean arguments --foo=true --bar false.
+    if (checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) {
+      if (typeof val === 'string') val = val === 'true'
+    }
+
+    if (/-/.test(key) && !(flags.aliases[key] && flags.aliases[key].length) && configuration['camel-case-expansion']) {
+      var c = camelCase(key)
+      flags.aliases[key] = [c]
+      newAliases[c] = true
+    }
+
+    var value = val
+    if (!checkAllAliases(key, flags.strings) && !checkAllAliases(key, flags.coercions)) {
+      if (isNumber(val)) value = Number(val)
+      if (!isUndefined(val) && !isNumber(val) && checkAllAliases(key, flags.numbers)) value = NaN
+    }
+
+    // increment a count given as arg (either no value or value parsed as boolean)
+    if (checkAllAliases(key, flags.counts) && (isUndefined(value) || typeof value === 'boolean')) {
+      value = increment
+    }
+
+    // Set normalized value when key is in 'normalize' and in 'arrays'
+    if (checkAllAliases(key, flags.normalize) && checkAllAliases(key, flags.arrays)) {
+      if (Array.isArray(val)) value = val.map(path.normalize)
+      else value = path.normalize(val)
+    }
+
+    var splitKey = key.split('.')
+    setKey(argv, splitKey, value)
+
+    // handle populating aliases of the full key
+    if (flags.aliases[key]) {
+      flags.aliases[key].forEach(function (x) {
+        x = x.split('.')
+        setKey(argv, x, value)
+      })
+    }
+
+    // handle populating aliases of the first element of the dot-notation key
+    if (splitKey.length > 1 && configuration['dot-notation']) {
+      ;(flags.aliases[splitKey[0]] || []).forEach(function (x) {
+        x = x.split('.')
+
+        // expand alias with nested objects in key
+        var a = [].concat(splitKey)
+        a.shift() // nuke the old key.
+        x = x.concat(a)
+
+        setKey(argv, x, value)
+      })
+    }
+
+    // Set normalize getter and setter when key is in 'normalize' but isn't an array
+    if (checkAllAliases(key, flags.normalize) && !checkAllAliases(key, flags.arrays)) {
+      var keys = [key].concat(flags.aliases[key] || [])
+      keys.forEach(function (key) {
+        argv.__defineSetter__(key, function (v) {
+          val = path.normalize(v)
+        })
+
+        argv.__defineGetter__(key, function () {
+          return typeof val === 'string' ? path.normalize(val) : val
+        })
+      })
+    }
+  }
+
+  // set args from config.json file, this should be
+  // applied last so that defaults can be applied.
+  function setConfig (argv) {
+    var configLookup = {}
+
+    // expand defaults/aliases, in-case any happen to reference
+    // the config.json file.
+    applyDefaultsAndAliases(configLookup, flags.aliases, defaults)
+
+    Object.keys(flags.configs).forEach(function (configKey) {
+      var configPath = argv[configKey] || configLookup[configKey]
+      if (configPath) {
+        try {
+          var config = null
+          var resolvedConfigPath = path.resolve(process.cwd(), configPath)
+
+          if (typeof flags.configs[configKey] === 'function') {
+            try {
+              config = flags.configs[configKey](resolvedConfigPath)
+            } catch (e) {
+              config = e
+            }
+            if (config instanceof Error) {
+              error = config
+              return
+            }
+          } else {
+            config = require(resolvedConfigPath)
+          }
+
+          setConfigObject(config)
+        } catch (ex) {
+          if (argv[configKey]) error = Error(__('Invalid JSON config file: %s', configPath))
+        }
+      }
+    })
+  }
+
+  // set args from config object.
+  // it recursively checks nested objects.
+  function setConfigObject (config, prev) {
+    Object.keys(config).forEach(function (key) {
+      var value = config[key]
+      var fullKey = prev ? prev + '.' + key : key
+
+      if (Object.prototype.toString.call(value) === '[object Object]') {
+        // if the value is an object but not an array, check nested object
+        setConfigObject(value, fullKey)
+      } else {
+        // setting arguments via CLI takes precedence over
+        // values within the config file.
+        if (!hasKey(argv, fullKey.split('.')) || (flags.defaulted[fullKey])) {
+          setArg(fullKey, value)
+        }
+      }
+    })
+  }
+
+  // set all config objects passed in opts
+  function setConfigObjects () {
+    if (typeof configObjects === 'undefined') return
+    configObjects.forEach(function (configObject) {
+      setConfigObject(configObject)
+    })
+  }
+
+  function applyEnvVars (argv, configOnly) {
+    if (typeof envPrefix === 'undefined') return
+
+    var prefix = typeof envPrefix === 'string' ? envPrefix : ''
+    Object.keys(process.env).forEach(function (envVar) {
+      if (prefix === '' || envVar.lastIndexOf(prefix, 0) === 0) {
+        // get array of nested keys and convert them to camel case
+        var keys = envVar.split('__').map(function (key, i) {
+          if (i === 0) {
+            key = key.substring(prefix.length)
+          }
+          return camelCase(key)
+        })
+
+        if (((configOnly && flags.configs[keys.join('.')]) || !configOnly) && (!hasKey(argv, keys) || flags.defaulted[keys.join('.')])) {
+          setArg(keys.join('.'), process.env[envVar])
+        }
+      }
+    })
+  }
+
+  function applyArrayCoercions (argv) {
+    var coerce
+    Object.keys(argv).filter(function (key) {
+      return key === '_' || checkAllAliases(key, flags.arrays)
+    }).forEach(function (key) {
+      coerce = checkAllAliases(key, flags.coercions)
+      if (typeof coerce === 'function') {
+        try {
+          argv[key] = coerce(argv[key])
+        } catch (err) {
+          error = err
+        }
+      }
+    })
+  }
+
+  function applyDefaultsAndAliases (obj, aliases, defaults) {
+    Object.keys(defaults).forEach(function (key) {
+      if (!hasKey(obj, key.split('.'))) {
+        setKey(obj, key.split('.'), defaults[key])
+
+        ;(aliases[key] || []).forEach(function (x) {
+          if (hasKey(obj, x.split('.'))) return
+          setKey(obj, x.split('.'), defaults[key])
+        })
+      }
+    })
+  }
+
+  function hasKey (obj, keys) {
+    var o = obj
+
+    if (!configuration['dot-notation']) keys = [keys.join('.')]
+
+    keys.slice(0, -1).forEach(function (key) {
+      o = (o[key] || {})
+    })
+
+    var key = keys[keys.length - 1]
+
+    if (typeof o !== 'object') return false
+    else return key in o
+  }
+
+  function setKey (obj, keys, value) {
+    var o = obj
+
+    if (!configuration['dot-notation']) keys = [keys.join('.')]
+
+    keys.slice(0, -1).forEach(function (key) {
+      if (o[key] === undefined) o[key] = {}
+      o = o[key]
+    })
+
+    var key = keys[keys.length - 1]
+    var coerce = !checkAllAliases(key, flags.arrays) && checkAllAliases(key, flags.coercions)
+    if (typeof coerce === 'function') {
+      try {
+        value = coerce(value)
+      } catch (err) {
+        error = err
+      }
+    }
+
+    if (value === increment) {
+      o[key] = increment(o[key])
+    } else if (o[key] === undefined && checkAllAliases(key, flags.arrays)) {
+      o[key] = Array.isArray(value) ? value : [value]
+    } else if (o[key] === undefined || checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) {
+      o[key] = value
+    } else if (Array.isArray(o[key])) {
+      o[key].push(value)
+    } else {
+      o[key] = [ o[key], value ]
+    }
+  }
+
+  // extend the aliases list with inferred aliases.
+  function extendAliases () {
+    Array.prototype.slice.call(arguments).forEach(function (obj) {
+      Object.keys(obj || {}).forEach(function (key) {
+        // short-circuit if we've already added a key
+        // to the aliases array, for example it might
+        // exist in both 'opts.default' and 'opts.key'.
+        if (flags.aliases[key]) return
+
+        flags.aliases[key] = [].concat(aliases[key] || [])
+        // For "--option-name", also set argv.optionName
+        flags.aliases[key].concat(key).forEach(function (x) {
+          if (/-/.test(x) && configuration['camel-case-expansion']) {
+            var c = camelCase(x)
+            flags.aliases[key].push(c)
+            newAliases[c] = true
+          }
+        })
+        flags.aliases[key].forEach(function (x) {
+          flags.aliases[x] = [key].concat(flags.aliases[key].filter(function (y) {
+            return x !== y
+          }))
+        })
+      })
+    })
+  }
+
+  // check if a flag is set for any of a key's aliases.
+  function checkAllAliases (key, flag) {
+    var isSet = false
+    var toCheck = [].concat(flags.aliases[key] || [], key)
+
+    toCheck.forEach(function (key) {
+      if (flag[key]) isSet = flag[key]
+    })
+
+    return isSet
+  }
+
+  function setDefaulted (key) {
+    [].concat(flags.aliases[key] || [], key).forEach(function (k) {
+      flags.defaulted[k] = true
+    })
+  }
+
+  function unsetDefaulted (key) {
+    [].concat(flags.aliases[key] || [], key).forEach(function (k) {
+      delete flags.defaulted[k]
+    })
+  }
+
+  // return a default value, given the type of a flag.,
+  // e.g., key of type 'string' will default to '', rather than 'true'.
+  function defaultForType (type) {
+    var def = {
+      boolean: true,
+      string: '',
+      number: undefined,
+      array: []
+    }
+
+    return def[type]
+  }
+
+  // given a flag, enforce a default type.
+  function guessType (key, flags) {
+    var type = 'boolean'
+
+    if (checkAllAliases(key, flags.strings)) type = 'string'
+    else if (checkAllAliases(key, flags.numbers)) type = 'number'
+    else if (checkAllAliases(key, flags.arrays)) type = 'array'
+
+    return type
+  }
+
+  function isNumber (x) {
+    if (!configuration['parse-numbers']) return false
+    if (typeof x === 'number') return true
+    if (/^0x[0-9a-f]+$/i.test(x)) return true
+    return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x)
+  }
+
+  function isUndefined (num) {
+    return num === undefined
+  }
+
+  return {
+    argv: argv,
+    error: error,
+    aliases: flags.aliases,
+    newAliases: newAliases,
+    configuration: configuration
+  }
+}
+
+// if any aliases reference each other, we should
+// merge them together.
+function combineAliases (aliases) {
+  var aliasArrays = []
+  var change = true
+  var combined = {}
+
+  // turn alias lookup hash {key: ['alias1', 'alias2']} into
+  // a simple array ['key', 'alias1', 'alias2']
+  Object.keys(aliases).forEach(function (key) {
+    aliasArrays.push(
+      [].concat(aliases[key], key)
+    )
+  })
+
+  // combine arrays until zero changes are
+  // made in an iteration.
+  while (change) {
+    change = false
+    for (var i = 0; i < aliasArrays.length; i++) {
+      for (var ii = i + 1; ii < aliasArrays.length; ii++) {
+        var intersect = aliasArrays[i].filter(function (v) {
+          return aliasArrays[ii].indexOf(v) !== -1
+        })
+
+        if (intersect.length) {
+          aliasArrays[i] = aliasArrays[i].concat(aliasArrays[ii])
+          aliasArrays.splice(ii, 1)
+          change = true
+          break
+        }
+      }
+    }
+  }
+
+  // map arrays back to the hash-lookup (de-dupe while
+  // we're at it).
+  aliasArrays.forEach(function (aliasArray) {
+    aliasArray = aliasArray.filter(function (v, i, self) {
+      return self.indexOf(v) === i
+    })
+    combined[aliasArray.pop()] = aliasArray
+  })
+
+  return combined
+}
+
+// this function should only be called when a count is given as an arg
+// it is NOT called to set a default value
+// thus we can start the count at 1 instead of 0
+function increment (orig) {
+  return orig !== undefined ? orig + 1 : 1
+}
+
+function Parser (args, opts) {
+  var result = parse(args.slice(), opts)
+
+  return result.argv
+}
+
+// parse arguments and return detailed
+// meta information, aliases, etc.
+Parser.detailed = function (args, opts) {
+  return parse(args.slice(), opts)
+}
+
+module.exports = Parser
diff --git a/server/node_modules/yargs-parser/lib/tokenize-arg-string.js b/server/node_modules/yargs-parser/lib/tokenize-arg-string.js
new file mode 100644
index 0000000000000000000000000000000000000000..23d39e1feb7f464bed0dd6e12fb17400695a9970
--- /dev/null
+++ b/server/node_modules/yargs-parser/lib/tokenize-arg-string.js
@@ -0,0 +1,34 @@
+// take an un-split argv string and tokenize it.
+module.exports = function (argString) {
+  if (Array.isArray(argString)) return argString
+
+  var i = 0
+  var c = null
+  var opening = null
+  var args = []
+
+  for (var ii = 0; ii < argString.length; ii++) {
+    c = argString.charAt(ii)
+
+    // split on spaces unless we're in quotes.
+    if (c === ' ' && !opening) {
+      i++
+      continue
+    }
+
+    // don't split the string if we're in matching
+    // opening or closing single and double quotes.
+    if (c === opening) {
+      opening = null
+      continue
+    } else if ((c === "'" || c === '"') && !opening) {
+      opening = c
+      continue
+    }
+
+    if (!args[i]) args[i] = ''
+    args[i] += c
+  }
+
+  return args
+}
diff --git a/server/node_modules/yargs-parser/package.json b/server/node_modules/yargs-parser/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..4aa26ddfab40bf8ccaa1c05d7c3fb758c2872517
--- /dev/null
+++ b/server/node_modules/yargs-parser/package.json
@@ -0,0 +1,76 @@
+{
+  "_from": "yargs-parser@^3.2.0",
+  "_id": "yargs-parser@3.2.0",
+  "_inBundle": false,
+  "_integrity": "sha1-UIE1XRnZ0MjF2BrakIy05tGGZk8=",
+  "_location": "/yargs-parser",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "yargs-parser@^3.2.0",
+    "name": "yargs-parser",
+    "escapedName": "yargs-parser",
+    "rawSpec": "^3.2.0",
+    "saveSpec": null,
+    "fetchSpec": "^3.2.0"
+  },
+  "_requiredBy": [
+    "/yargs"
+  ],
+  "_resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz",
+  "_shasum": "5081355d19d9d0c8c5d81ada908cb4e6d186664f",
+  "_spec": "yargs-parser@^3.2.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/yargs",
+  "author": {
+    "name": "Ben Coe",
+    "email": "ben@npmjs.com"
+  },
+  "bugs": {
+    "url": "https://github.com/yargs/yargs-parser/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "camelcase": "^3.0.0",
+    "lodash.assign": "^4.1.0"
+  },
+  "deprecated": false,
+  "description": "the mighty option parser used by yargs",
+  "devDependencies": {
+    "chai": "^3.5.0",
+    "coveralls": "^2.11.12",
+    "mocha": "^3.0.1",
+    "nyc": "^7.1.0",
+    "standard": "^7.1.0",
+    "standard-version": "^2.1.2"
+  },
+  "files": [
+    "lib",
+    "index.js"
+  ],
+  "homepage": "https://github.com/yargs/yargs-parser#readme",
+  "keywords": [
+    "argument",
+    "parser",
+    "yargs",
+    "command",
+    "cli",
+    "parsing",
+    "option",
+    "args",
+    "argument"
+  ],
+  "license": "ISC",
+  "main": "index.js",
+  "name": "yargs-parser",
+  "repository": {
+    "url": "git+ssh://git@github.com/yargs/yargs-parser.git"
+  },
+  "scripts": {
+    "coverage": "nyc report --reporter=text-lcov | coveralls",
+    "pretest": "standard",
+    "release": "standard-version",
+    "test": "nyc mocha test/*.js"
+  },
+  "version": "3.2.0"
+}
diff --git a/server/node_modules/yargs/CHANGELOG.md b/server/node_modules/yargs/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..ef6312c40b6e46aef4df137e052515600ba5e098
--- /dev/null
+++ b/server/node_modules/yargs/CHANGELOG.md
@@ -0,0 +1,690 @@
+# Change Log
+
+All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+<a name="5.0.0"></a>
+# [5.0.0](https://github.com/yargs/yargs/compare/v4.8.1...v5.0.0) (2016-08-14)
+
+
+### Bug Fixes
+
+* **default:** Remove undocumented alias of default() ([#469](https://github.com/yargs/yargs/issues/469)) ([b8591b2](https://github.com/yargs/yargs/commit/b8591b2))
+* remove deprecated zh.json ([#578](https://github.com/yargs/yargs/issues/578)) ([317c62c](https://github.com/yargs/yargs/commit/317c62c))
+
+
+### Features
+
+* .help() API can now enable implicit help command ([#574](https://github.com/yargs/yargs/issues/574)) ([7645019](https://github.com/yargs/yargs/commit/7645019))
+* **command:** builder function no longer needs to return the yargs instance ([#549](https://github.com/yargs/yargs/issues/549)) ([eaa2873](https://github.com/yargs/yargs/commit/eaa2873))
+* add coerce api ([#586](https://github.com/yargs/yargs/issues/586)) ([1d53ccb](https://github.com/yargs/yargs/commit/1d53ccb))
+* adds recommendCommands() for command suggestions ([#580](https://github.com/yargs/yargs/issues/580)) ([59474dc](https://github.com/yargs/yargs/commit/59474dc))
+* apply .env() globally ([#553](https://github.com/yargs/yargs/issues/553)) ([be65728](https://github.com/yargs/yargs/commit/be65728))
+* apply default builder to command() and apply fail() handlers globally ([#583](https://github.com/yargs/yargs/issues/583)) ([0aaa68b](https://github.com/yargs/yargs/commit/0aaa68b))
+* interpret demand() numbers as relative to executing command ([#582](https://github.com/yargs/yargs/issues/582)) ([927810c](https://github.com/yargs/yargs/commit/927810c))
+* update yargs-parser to version 3.1.0 ([#581](https://github.com/yargs/yargs/issues/581)) ([882a127](https://github.com/yargs/yargs/commit/882a127))
+
+
+### Performance Improvements
+
+* defer requiring most external libs until needed ([#584](https://github.com/yargs/yargs/issues/584)) ([f9b0ed4](https://github.com/yargs/yargs/commit/f9b0ed4))
+
+
+### BREAKING CHANGES
+
+* fail is now applied globally.
+* we now default to an empty builder function when command is executed with no builder.
+* yargs-parser now better handles negative integer values, at the cost of handling numeric option names, e.g., -1 hello 
+* default: removed undocumented `defaults` alias for `default`.
+* introduces a default `help` command which outputs help, as an alternative to a help flag.
+
+
+
+<a name="4.8.1"></a>
+## [4.8.1](https://github.com/yargs/yargs/compare/v4.8.0...v4.8.1) (2016-07-16)
+
+
+### Bug Fixes
+
+* **commandDir:** make dir relative to caller instead of require.main.filename ([#548](https://github.com/yargs/yargs/issues/548)) ([3c2e479](https://github.com/yargs/yargs/commit/3c2e479))
+* add config lookup for .implies() ([#556](https://github.com/yargs/yargs/issues/556)) ([8d7585c](https://github.com/yargs/yargs/commit/8d7585c))
+* cache pkg lookups by path to avoid returning the wrong one ([#552](https://github.com/yargs/yargs/issues/552)) ([fea7e0b](https://github.com/yargs/yargs/commit/fea7e0b))
+* positional arguments were not being handled appropriately by parse() ([#559](https://github.com/yargs/yargs/issues/559)) ([063a866](https://github.com/yargs/yargs/commit/063a866))
+* pull in [@nexdrew](https://github.com/nexdrew)'s fixes to yargs-parser ([#560](https://github.com/yargs/yargs/issues/560)) ([c77c080](https://github.com/yargs/yargs/commit/c77c080)), closes [#560](https://github.com/yargs/yargs/issues/560)
+
+
+
+<a name="4.8.0"></a>
+# [4.8.0](https://github.com/yargs/yargs/compare/v4.7.1...v4.8.0) (2016-07-09)
+
+
+### Bug Fixes
+
+* drop unused camelcase dependency fixes [#516](https://github.com/yargs/yargs/issues/516) ([#525](https://github.com/yargs/yargs/issues/525)) ([365fb9a](https://github.com/yargs/yargs/commit/365fb9a)), closes [#516](https://github.com/yargs/yargs/issues/516) [#525](https://github.com/yargs/yargs/issues/525)
+* fake a tty in tests, so that we can use the new set-blocking ([#512](https://github.com/yargs/yargs/issues/512)) ([a54c742](https://github.com/yargs/yargs/commit/a54c742))
+* ignore invalid package.json during read-pkg-up ([#546](https://github.com/yargs/yargs/issues/546)) ([e058c87](https://github.com/yargs/yargs/commit/e058c87))
+* keep both zh and zh_CN until yargs[@5](https://github.com/5).x ([0f8faa7](https://github.com/yargs/yargs/commit/0f8faa7))
+* lazy-load package.json and cache. get rid of pkg-conf dependency. ([#544](https://github.com/yargs/yargs/issues/544)) ([2609b2e](https://github.com/yargs/yargs/commit/2609b2e))
+* we now respect the order of _ when applying commands ([#537](https://github.com/yargs/yargs/issues/537)) ([ed86b78](https://github.com/yargs/yargs/commit/ed86b78))
+
+
+### Features
+
+* add .commandDir(dir) to API to apply all command modules from a relative directory ([#494](https://github.com/yargs/yargs/issues/494)) ([b299dff](https://github.com/yargs/yargs/commit/b299dff))
+* **command:** derive missing command string from module filename ([#527](https://github.com/yargs/yargs/issues/527)) ([20d4b8a](https://github.com/yargs/yargs/commit/20d4b8a))
+* builder is now optional for a command module ([#545](https://github.com/yargs/yargs/issues/545)) ([8d6ad6e](https://github.com/yargs/yargs/commit/8d6ad6e))
+
+
+
+<a name="4.7.1"></a>
+## [4.7.1](https://github.com/yargs/yargs/compare/v4.7.0...v4.7.1) (2016-05-15)
+
+
+### Bug Fixes
+
+* switch to using `const` rather than `var` ([#499](https://github.com/yargs/yargs/pull/499))
+* make stdout flush on newer versions of Node.js ([#501](https://github.com/yargs/yargs/issues/501)) ([9f8c6f4](https://github.com/yargs/yargs/commit/9f8c6f4))
+
+
+
+<a name="4.7.0"></a>
+# [4.7.0](https://github.com/yargs/yargs/compare/v4.6.0...v4.7.0) (2016-05-02)
+
+
+### Bug Fixes
+
+* **pkgConf:** fix aliases issues in .pkgConf() ([#478](https://github.com/yargs/yargs/issues/478))([b900502](https://github.com/yargs/yargs/commit/b900502))
+
+
+### Features
+
+* **completion:** allow to get completions for any string, not just process.argv ([#470](https://github.com/yargs/yargs/issues/470))([74fcfbc](https://github.com/yargs/yargs/commit/74fcfbc))
+* **configuration:** Allow to directly pass a configuration object to .config() ([#480](https://github.com/yargs/yargs/issues/480))([e0a7e05](https://github.com/yargs/yargs/commit/e0a7e05))
+* **validation:** Add .skipValidation() method ([#471](https://github.com/yargs/yargs/issues/471))([d72badb](https://github.com/yargs/yargs/commit/d72badb))
+
+
+
+<a name="4.6.0"></a>
+# [4.6.0](https://github.com/yargs/yargs/compare/v4.5.0...v4.6.0) (2016-04-11)
+
+
+### Bug Fixes
+
+* **my brand!:** I agree with [@osher](https://github.com/osher) lightweight isn't a huge selling point of ours any longer, see [#468](https://github.com/yargs/yargs/issues/468) ([c46d7e1](https://github.com/yargs/yargs/commit/c46d7e1))
+
+### Features
+
+* switch to standard-version for release management ([f70f801](https://github.com/yargs/yargs/commit/f70f801))
+* upgrade to version of yargs-parser that introduces some slick new features, great work [@elas7](https://github.com/elas7). update cliui, replace win-spawn, replace badge. ([#475](https://github.com/yargs/yargs/issues/475)) ([f915dd4](https://github.com/yargs/yargs/commit/f915dd4))
+
+
+
+<a name="4.5.0"></a>
+# [4.5.0](https://github.com/yargs/yargs/compare/v4.4.0...v4.5.0) (2016-04-05)
+
+
+### Bug Fixes
+
+* **windows:** handle $0 better on Windows platforms ([eb6e03f](https://github.com/yargs/yargs/commit/eb6e03f))
+
+### Features
+
+* **commands:** implemented variadic positional arguments ([51d926e](https://github.com/yargs/yargs/commit/51d926e))
+* **completion:** completion now better handles aliases, and avoids duplicating keys. ([86416c8](https://github.com/yargs/yargs/commit/86416c8))
+* **config:** If invoking .config() without parameters, set a default option ([0413dd1](https://github.com/yargs/yargs/commit/0413dd1))
+* **conventional-changelog:** switching to using conventional-changelog for generating the changelog ([a2b5a2a](https://github.com/yargs/yargs/commit/a2b5a2a))
+
+
+
+### v4.4.0 (2016/04/03 21:10 +07:00)
+
+- [#454](https://github.com/yargs/yargs/pull/454) fix demand() when second argument is an array (@elas7)
+- [#452](https://github.com/yargs/yargs/pull/452) fix code example for `.help()` docs (@maxrimue)
+- [#450](https://github.com/yargs/yargs/pull/450) fix for bash completion trailing space edge-case (@elas7)
+- [#448](https://github.com/yargs/yargs/pull/448) allow a method to be passed to `showHelp`, rather than a log-level (@osher)
+- [#446](https://github.com/yargs/yargs/pull/446) update yargs-parser, y18n, nyc, cliui, pkg-conf (@bcoe)
+- [#436](https://github.com/yargs/yargs/pull/436) the rebase method is only used by tests, do not export it in two places (@elas7)
+- [#428](https://github.com/yargs/yargs/pull/428) initial support for subcommands (@nexdrew)
+
+### v4.3.2 (2016/3/20 15:07 +07:00)
+
+- [#445](https://github.com/yargs/yargs/pull/445) strict mode was failing if no commands were registered (@nexdrew)
+- [#443](https://github.com/yargs/yargs/pull/443) adds Italian translation \o/ (@madrisan)
+- [#441](https://github.com/yargs/yargs/pull/441) remove duplicate keys from array options configuration (@elas7)
+- [#437](https://github.com/yargs/yargs/pull/437) standardize tests for .command() (@lrlna)
+
+### v4.3.0 (2016/3/12 14:19 +07:00)
+
+- [#432](https://github.com/yargs/yargs/pull/432) non-singleton version of yargs (@bcoe)
+- [#422, #425, #420] translations for number (@zkat, @rilut, @maxrimue, @watilde)
+- [#414](https://github.com/yargs/yargs/pull/414) all command options can be defined in module now (@nexdrew)
+
+### v4.2.0 (2016/2/22 11:02 +07:00)
+
+- [#395](https://github.com/yargs/yargs/pull/395) do not reset groups if they contain
+  global keys (@novemberborn)
+- [#393](https://github.com/yargs/yargs/pull/393) use sane default for usage strings (@nexdrew)
+- [#392](https://github.com/yargs/yargs/pull/392) resetting wrap() was causing layout issues
+  with commands (@nexdrew)
+- [#391](https://github.com/yargs/yargs/pull/391) commands were being added multiple times (@nexdrew)
+
+### v4.0.0 (2016/2/14 1:27 +07:00)
+
+- [#384](https://github.com/bcoe/yargs/pull/384) add new number type to yargs (@lrlna, @maxrimue)
+- [#382](https://github.com/bcoe/yargs/pull/382) pass error as extra parameter to fail (@gajus)
+- [#378](https://github.com/bcoe/yargs/pull/378) introduces the pkgConf feature, which tells
+  yargs to load default argument values from a key on a project's package.json (@bcoe)
+- [#376](https://github.com/bcoe/yargs/pull/376) **breaking change**, make help() method signature
+   more consistent with other commands (@maxrimue)
+- [#368](https://github.com/bcoe/yargs/pull/368) **breaking change**, overhaul to command handling API:
+  introducing named positional arguments, commands as modules, introduces the concept of global options (options that don't reset). (@nexdrew, @bcoe).
+- [#364](https://github.com/bcoe/yargs/pull/364) add the slick new yargs website to the package.json (@iarna).
+- [#357](https://github.com/bcoe/yargs/pull/357) .strict() now requires that a valid command is provided (@lrlna)
+- [#356](https://github.com/bcoe/yargs/pull/356) pull the parsing bits of yargs into the separate module yargs-parser. Various parsing options can now be turned on and off using configuration (@bcoe).
+- [#330](https://github.com/bcoe/yargs/pull/330) **breaking change**, fix inconsistencies with `.version()` API. (@maxrimue).
+
+### v3.32.0 (2016/1/14 10:13 +07:00)
+
+- [#344](https://github.com/bcoe/yargs/pull/344) yargs now has a code of conduct and contributor guidelines (@bcoe)
+- [#341](https://github.com/bcoe/yargs/issues/341) Fix edge-case with camel-case arguments (@davibe)
+- [#331](https://github.com/bcoe/yargs/pull/331) Handle parsing a raw argument string (@kellyselden)
+- [#325](https://github.com/bcoe/yargs/pull/325) Tweaks to make tests pass again on Windows (@isaacs)
+- [#321](https://github.com/bcoe/yargs/pull/321) Custom config parsing function (@bcoe)
+
+### v3.31.0 (2015/12/03 10:15 +07:00)
+
+- [#239](https://github.com/bcoe/yargs/pull/239) Pass argv to commands (@bcoe)
+- [#308](https://github.com/bcoe/yargs/pull/308) Yargs now handles environment variables (@nexdrew)
+- [#302](https://github.com/bcoe/yargs/pull/302) Add Indonesian translation (@rilut)
+- [#300](https://github.com/bcoe/yargs/pull/300) Add Turkish translation (@feyzo)
+- [#298](https://github.com/bcoe/yargs/pull/298) Add Norwegian BokmaÌŠl translation (@sindresorhus)
+- [#297](https://github.com/bcoe/yargs/pull/297) Fix for layout of cjk characters (@disjukr)
+- [#296](https://github.com/bcoe/yargs/pull/296) Add Korean translation (@disjukr)
+
+### v3.30.0 (2015/11/13 16:29 +07:00)
+
+- [#293](https://github.com/bcoe/yargs/pull/293) Polish language support (@kamilogorek)
+- [#291](https://github.com/bcoe/yargs/pull/291) fix edge-cases with `.alias()` (@bcoe)
+- [#289](https://github.com/bcoe/yargs/pull/289) group options in custom groups (@bcoe)
+
+### v3.29.0 (2015/10/16 21:51 +07:00)
+
+- [#282](https://github.com/bcoe/yargs/pull/282) completions now accept promises (@LinusU)
+- [#281](https://github.com/bcoe/yargs/pull/281) fix parsing issues with dot notation (@bcoe)
+
+### v3.28.0 (2015/10/16 1:55 +07:00)
+
+- [#277](https://github.com/bcoe/yargs/pull/277) adds support for ansi escape codes (@bcoe)
+
+### v3.27.0 (2015/10/08 1:55 +00:00)
+
+- [#271](https://github.com/bcoe/yargs/pull/273) skips validation for help or version flags with exitProcess(false) (@tepez)
+- [#273](https://github.com/bcoe/yargs/pull/273) implements single output for errors with exitProcess(false) (@nexdrew)
+- [#269](https://github.com/bcoe/yargs/pull/269) verifies single output for errors with exitProcess(false) (@tepez)
+- [#268](https://github.com/bcoe/yargs/pull/268) adds Chinese translation (@qiu8310)
+- [#266](https://github.com/bcoe/yargs/pull/266) adds case for -- after -- in parser test (@geophree)
+
+### v3.26.0 (2015/09/25 2:14 +00:00)
+
+- [#263](https://github.com/bcoe/yargs/pull/263) document count() and option() object keys (@nexdrew)
+- [#259](https://github.com/bcoe/yargs/pull/259) remove util in readme (@38elements)
+- [#258](https://github.com/bcoe/yargs/pull/258) node v4 builds, update deps (@nexdrew)
+- [#257](https://github.com/bcoe/yargs/pull/257) fix spelling errors (@dkoleary88)
+
+### v3.25.0 (2015/09/13 7:38 -07:00)
+
+- [#254](https://github.com/bcoe/yargs/pull/254) adds Japanese translation (@oti)
+- [#253](https://github.com/bcoe/yargs/pull/253) fixes for tests on Windows (@bcoe)
+
+### v3.24.0 (2015/09/04 12:02 +00:00)
+
+- [#248](https://github.com/bcoe/yargs/pull/248) reinstate os-locale, no spawning (@nexdrew)
+- [#249](https://github.com/bcoe/yargs/pull/249) use travis container-based infrastructure (@nexdrew)
+- [#247](https://github.com/bcoe/yargs/pull/247) upgrade standard (@nexdrew)
+
+### v3.23.0 (2015/08/30 23:00 +00:00)
+
+- [#246](https://github.com/bcoe/yargs/pull/246) detect locale based only on environment variables (@bcoe)
+- [#244](https://github.com/bcoe/yargs/pull/244) adds Windows CI testing (@bcoe)
+- [#245](https://github.com/bcoe/yargs/pull/245) adds OSX CI testing (@bcoe, @nexdrew)
+
+### v3.22.0 (2015/08/28 22:26 +00:00)
+- [#242](https://github.com/bcoe/yargs/pull/242) adds detectLocale config option (@bcoe)
+
+### v3.21.1 (2015/08/28 20:58 +00:00)
+- [#240](https://github.com/bcoe/yargs/pull/240) hot-fix for Atom on Windows (@bcoe)
+
+### v3.21.0 (2015/08/21 21:20 +00:00)
+- [#238](https://github.com/bcoe/yargs/pull/238) upgrade camelcase, window-size, chai, mocha (@nexdrew)
+- [#237](https://github.com/bcoe/yargs/pull/237) adds defaultDescription to option() (@nexdrew)
+
+### v3.20.0 (2015/08/20 01:29 +00:00)
+- [#231](https://github.com/bcoe/yargs/pull/231) Merge pull request #231 from bcoe/detect-locale (@sindresorhus)
+- [#235](https://github.com/bcoe/yargs/pull/235) adds german translation to yargs (@maxrimue)
+
+### v3.19.0 (2015/08/14 05:12 +00:00)
+- [#224](https://github.com/bcoe/yargs/pull/224) added Portuguese translation (@codemonkey3045)
+
+### v3.18.1 (2015/08/12 05:53 +00:00)
+
+- [#228](https://github.com/bcoe/yargs/pull/228) notes about embedding yargs in Electron (@etiktin)
+- [#223](https://github.com/bcoe/yargs/pull/223) make booleans work in config files (@sgentle)
+
+### v3.18.0 (2015/08/06 20:05 +00:00)
+- [#222](https://github.com/bcoe/yargs/pull/222) updates fr locale (@nexdrew)
+- [#221](https://github.com/bcoe/yargs/pull/221) adds missing locale strings (@nexdrew)
+- [#220](https://github.com/bcoe/yargs/pull/220) adds es locale (@zkat)
+
+### v3.17.1 (2015/08/02 19:35 +00:00)
+- [#218](https://github.com/bcoe/yargs/pull/218) upgrades nyc (@bcoe)
+
+### v3.17.0 (2015/08/02 18:39 +00:00)
+- [#217](https://github.com/bcoe/yargs/pull/217) sort methods in README.md (@nexdrew)
+- [#215](https://github.com/bcoe/yargs/pull/215) adds fr locale (@LoicMahieu)
+
+### v3.16.0 (2015/07/30 04:35 +00:00)
+- [#210](https://github.com/bcoe/yargs/pull/210) adds i18n support to yargs (@bcoe)
+- [#209](https://github.com/bcoe/yargs/pull/209) adds choices type to yargs (@nexdrew)
+- [#207](https://github.com/bcoe/yargs/pull/207) pretty new shields from shields.io (@SimenB)
+- [#208](https://github.com/bcoe/yargs/pull/208) improvements to README.md (@nexdrew)
+- [#205](https://github.com/bcoe/yargs/pull/205) faster build times on Travis (@ChristianMurphy)
+
+### v3.15.0 (2015/07/06 06:01 +00:00)
+- [#197](https://github.com/bcoe/yargs/pull/197) tweaks to how errors bubble up from parser.js (@bcoe)
+- [#193](https://github.com/bcoe/yargs/pull/193) upgraded nyc, reporting now happens by default (@bcoe)
+
+### v3.14.0 (2015/06/28 02:12 +00:00)
+
+- [#192](https://github.com/bcoe/yargs/pull/192) standard style nits (@bcoe)
+- [#190](https://github.com/bcoe/yargs/pull/190) allow for hidden commands, e.g.,
+  .completion('completion', false) (@tschaub)
+
+### v3.13.0 (2015/06/24 04:12 +00:00)
+
+- [#187](https://github.com/bcoe/yargs/pull/187) completion now behaves differently
+  if it is being run in the context of a command (@tschaub)
+- [#186](https://github.com/bcoe/yargs/pull/186) if no matches are found for a completion
+  default to filename completion (@tschaub)
+
+### v3.12.0 (2015/06/19 03:23 +00:00)
+- [#183](https://github.com/bcoe/yargs/pull/183) don't complete commands if they've already been completed (@tschaub)
+- [#181](https://github.com/bcoe/yargs/pull/181) various fixes for completion. (@bcoe, @tschaub)
+- [#182](https://github.com/bcoe/yargs/pull/182) you can now set a maximum # of of required arguments (@bcoe)
+
+### v3.11.0 (2015/06/15 05:15 +00:00)
+
+- [#173](https://github.com/bcoe/yargs/pull/173) update standard, window-size, chai (@bcoe)
+- [#171](https://github.com/bcoe/yargs/pull/171) a description can now be set
+  when providing a config option. (@5c077yP)
+
+### v3.10.0 (2015/05/29 04:25 +00:00)
+
+- [#165](https://github.com/bcoe/yargs/pull/165) expose yargs.terminalWidth() thanks @ensonic (@bcoe)
+- [#164](https://github.com/bcoe/yargs/pull/164) better array handling thanks @getify (@bcoe)
+
+### v3.9.1 (2015/05/20 05:14 +00:00)
+- [b6662b6](https://github.com/bcoe/yargs/commit/b6662b6774cfeab4876f41ec5e2f67b7698f4e2f) clarify .config() docs (@linclark)
+- [0291360](https://github.com/bcoe/yargs/commit/02913606285ce31ce81d7f12c48d8a3029776ec7) fixed tests, switched to nyc for coverage, fixed security issue, added Lin as collaborator (@bcoe)
+
+### v3.9.0 (2015/05/10 18:32 +00:00)
+- [#157](https://github.com/bcoe/yargs/pull/157) Merge pull request #157 from bcoe/command-yargs. allows handling of command specific arguments. Thanks for the suggestion @ohjames (@bcoe)
+- [#158](https://github.com/bcoe/yargs/pull/158) Merge pull request #158 from kemitchell/spdx-license. Update license format (@kemitchell)
+
+### v3.8.0 (2015/04/24 23:10 +00:00)
+- [#154](https://github.com/bcoe/yargs/pull/154) showHelp's method signature was misleading fixes #153 (@bcoe)
+- [#151](https://github.com/bcoe/yargs/pull/151) refactor yargs' table layout logic to use new helper library (@bcoe)
+- [#150](https://github.com/bcoe/yargs/pull/150) Fix README example in argument requirements (@annonymouse)
+
+### v3.7.2 (2015/04/13 11:52 -07:00)
+
+* [679fbbf](https://github.com/bcoe/yargs/commit/679fbbf55904030ccee8a2635e8e5f46551ab2f0) updated yargs to use the [standard](https://github.com/feross/standard) style guide (agokjr)
+* [22382ee](https://github.com/bcoe/yargs/commit/22382ee9f5b495bc2586c1758cd1091cec3647f9 various bug fixes for $0 (@nylen)
+
+### v3.7.1 (2015/04/10 11:06 -07:00)
+
+* [89e1992](https://github.com/bcoe/yargs/commit/89e1992a004ba73609b5f9ee6890c4060857aba4) detect iojs bin along with node bin. (@bcoe)
+* [755509e](https://github.com/bcoe/yargs/commit/755509ea90041e5f7833bba3b8c5deffe56f0aab) improvements to example documentation in README.md (@rstacruz)
+* [0d2dfc8](https://github.com/bcoe/yargs/commit/0d2dfc822a43418242908ad97ddd5291a1b35dc6) showHelp() no longer requires that .argv has been called (@bcoe)
+
+### v3.7.0 (2015/04/04 02:29 -07:00)
+
+* [56cbe2d](https://github.com/bcoe/yargs/commit/56cbe2ddd33dc176dcbf97ba40559864a9f114e4) make .requiresArg() work with type hints. (@bcoe).
+* [2f5d562](https://github.com/bcoe/yargs/commit/2f5d5624f736741deeedf6a664d57bc4d857bdd0) serialize arrays and objects in usage strings. (@bcoe).
+* [5126304](https://github.com/bcoe/yargs/commit/5126304dd18351fc28f10530616fdd9361e0af98) be more lenient about alias/primary key ordering in chaining API. (@bcoe)
+
+### v3.6.0 (2015/03/21 01:00 +00:00)
+- [4e24e22](https://github.com/bcoe/yargs/commit/4e24e22e6a195e55ab943ede704a0231ac33b99c) support for .js configuration files. (@pirxpilot)
+
+### v3.5.4 (2015/03/12 05:56 +00:00)
+- [c16cc08](https://github.com/bcoe/yargs/commit/c16cc085501155cf7fd853ccdf8584b05ab92b78) message for non-option arguments is now optional, thanks to (@raine)
+
+### v3.5.3 (2015/03/09 06:14 +00:00)
+- [870b428](https://github.com/bcoe/yargs/commit/870b428cf515d560926ca392555b7ad57dba9e3d) completion script was missing in package.json (@bcoe)
+
+### v3.5.2 (2015/03/09 06:11 +00:00)
+- [58a4b24](https://github.com/bcoe/yargs/commit/58a4b2473ebbb326713d522be53e32d3aabb08d2) parse was being called multiple times, resulting in strange behavior (@bcoe)
+
+### v3.5.1 (2015/03/09 04:55 +00:00)
+- [4e588e0](https://github.com/bcoe/yargs/commit/4e588e055afbeb9336533095f051496e3977f515) accidentally left testing logic in (@bcoe)
+
+### v3.5.0 (2015/03/09 04:49 +00:00)
+- [718bacd](https://github.com/bcoe/yargs/commit/718bacd81b9b44f786af76b2afe491fe06274f19) added support for bash completions see #4 (@bcoe)
+- [a192882](https://github.com/bcoe/yargs/commit/a19288270fc431396c42af01125eeb4443664528) downgrade to mocha 2.1.0 until https://github.com/mochajs/mocha/issues/1585 can be sorted out (@bcoe)
+
+### v3.4.7 (2015/03/09 04:09 +00:00)
+- [9845e5c](https://github.com/bcoe/yargs/commit/9845e5c1a9c684ba0be3f0bfb40e7b62ab49d9c8) the Argv singleton was not being updated when manually parsing arguments, fixes #114 (@bcoe)
+
+### v3.4.6 (2015/03/09 04:01 +00:00)
+- [45b4c80](https://github.com/bcoe/yargs/commit/45b4c80b890d02770b0a94f326695a8a566e8fe9) set placeholders for all keys fixes #115 (@bcoe)
+
+### v3.4.5 (2015/03/01 20:31 +00:00)
+- [a758e0b](https://github.com/bcoe/yargs/commit/a758e0b2556184f067cf3d9c4ef886d39817ebd2) fix for count consuming too many arguments (@bcoe)
+
+### v3.4.4 (2015/02/28 04:52 +00:00)
+- [0476af7](https://github.com/bcoe/yargs/commit/0476af757966acf980d998b45108221d4888cfcb) added nargs feature, allowing you to specify the number of arguments after an option (@bcoe)
+- [092477d](https://github.com/bcoe/yargs/commit/092477d7ab3efbf0ba11cede57f7d8cfc70b024f) updated README with full example of v3.0 API (@bcoe)
+
+### v3.3.3 (2015/02/28 04:23 +00:00)
+- [0c4b769](https://github.com/bcoe/yargs/commit/0c4b769516cd8d93a7c4e5e675628ae0049aa9a8) remove string dependency, which conflicted with other libraries see #106 (@bcoe)
+
+### v3.3.2 (2015/02/28 04:11 +00:00)
+- [2a98906](https://github.com/bcoe/yargs/commit/2a9890675821c0e7a12f146ce008b0562cb8ec9a) add $0 to epilog (@schnittstabil)
+
+### v3.3.1 (2015/02/24 03:28 +00:00)
+- [ad485ce](https://github.com/bcoe/yargs/commit/ad485ce748ebdfce25b88ef9d6e83d97a2f68987) fix for applying defaults to camel-case args (@bcoe)
+
+### v3.3.0 (2015/02/24 00:49 +00:00)
+- [8bfe36d](https://github.com/bcoe/yargs/commit/8bfe36d7fb0f93a799ea3f4c756a7467c320f8c0) fix and document restart() command, as a tool for building nested CLIs (@bcoe)
+
+### v3.2.1 (2015/02/22 05:45 +00:00)
+- [49a6d18](https://github.com/bcoe/yargs/commit/49a6d1822a4ef9b1ea6f90cc366be60912628885) you can now provide a function that generates a default value (@bcoe)
+
+### v3.2.0 (2015/02/22 05:24 +00:00)
+- [7a55886](https://github.com/bcoe/yargs/commit/7a55886c9343cf71a20744ca5cdd56d2ea7412d5) improvements to yargs two-column text layout (@bcoe)
+- [b6ab513](https://github.com/bcoe/yargs/commit/b6ab5136a4c3fa6aa496f6b6360382e403183989) Tweak NPM version badge (@nylen)
+
+### v3.1.0 (2015/02/19 19:37 +00:00)
+- [9bd2379](https://github.com/bcoe/yargs/commit/9bd237921cf1b61fd9f32c0e6d23f572fc225861) version now accepts a function, making it easy to load version #s from a package.json (@bcoe)
+
+### v3.0.4 (2015/02/14 01:40 +00:00)
+- [0b7c19b](https://github.com/bcoe/yargs/commit/0b7c19beaecb747267ca4cc10e5cb2a8550bc4b7) various fixes for dot-notation handling (@bcoe)
+
+### v3.0.3 (2015/02/14 00:59 +00:00)
+- [c3f35e9](https://github.com/bcoe/yargs/commit/c3f35e99bd5a0d278073fcadd95e2d778616cc17) make sure dot-notation is applied to aliases (@bcoe)
+
+### 3.0.2 (2015/02/13 16:50 +00:00)
+- [74c8967](https://github.com/bcoe/yargs/commit/74c8967c340c204a0a7edf8a702b6f46c2705435) document epilog shorthand of epilogue. (@bcoe)
+- [670110f](https://github.com/bcoe/yargs/commit/670110fc01bedc4831b6fec6afac54517d5a71bc) any non-truthy value now causes check to fail see #76 (@bcoe)
+- [0d8f791](https://github.com/bcoe/yargs/commit/0d8f791a33c11ced4cd431ea8d3d3a337d456b56) finished implementing my wish-list of fetures for yargs 3.0. see #88 (@bcoe)
+- [5768447](https://github.com/bcoe/yargs/commit/5768447447c4c8e8304f178846206ce86540f063) fix coverage. (@bcoe)
+- [82e793f](https://github.com/bcoe/yargs/commit/82e793f3f61c41259eaacb67f0796aea2cf2aaa0) detect console width and perform word-wrapping. (@bcoe)
+- [67476b3](https://github.com/bcoe/yargs/commit/67476b37eea07fee55f23f35b9e0c7d76682b86d) refactor two-column table layout so that we can use it for examples and usage (@bcoe)
+- [4724cdf](https://github.com/bcoe/yargs/commit/4724cdfcc8e37ae1ca3dcce9d762f476e9ef4bb4) major refactor of index.js, in prep for 3.x release. (@bcoe)
+
+### v2.3.0 (2015/02/08 20:41 +00:00)
+- [d824620](https://github.com/bcoe/yargs/commit/d824620493df4e63664af1fe320764dd1a9244e6) allow for undefined boolean defaults (@ashi009)
+
+### v2.2.0 (2015/02/08 20:07 +00:00)
+- [d6edd98](https://github.com/bcoe/yargs/commit/d6edd9848826e7389ed1393858c45d03961365fd) in-prep for further refactoring, and a 3.x release I've shuffled some things around and gotten test-coverage to 100%. (@bcoe)
+
+### v2.1.2 (2015/02/08 06:05 +00:00)
+- [d640745](https://github.com/bcoe/yargs/commit/d640745a7b9f8d476e0223879d056d18d9c265c4) switch to path.relative (@bcoe)
+- [3bfd41f](https://github.com/bcoe/yargs/commit/3bfd41ff262a041f29d828b88936a79c63cad594) remove mocha.opts. (@bcoe)
+- [47a2f35](https://github.com/bcoe/yargs/commit/47a2f357091db70903a402d6765501c1d63f15fe) document using .string('_') for string ids. see #56 (@bcoe)
+- [#57](https://github.com/bcoe/yargs/pull/57) Merge pull request #57 from eush77/option-readme (@eush77)
+
+### v2.1.1 (2015/02/06 08:08 +00:00)
+- [01c6c61](https://github.com/bcoe/yargs/commit/01c6c61d67b4ebf88f41f0b32a345ec67f0ac17d) fix for #71, 'newAliases' of undefined (@bcoe)
+
+### v2.1.0 (2015/02/06 07:59 +00:00)
+- [6a1a3fa](https://github.com/bcoe/yargs/commit/6a1a3fa731958e26ccd56885f183dd8985cc828f) try to guess argument types, and apply sensible defaults see #73 (@bcoe)
+
+### v2.0.1 (2015/02/06 07:54 +00:00)
+- [96a06b2](https://github.com/bcoe/yargs/commit/96a06b2650ff1d085a52b7328d8bba614c20cc12) Fix for strange behavior with --sort option, see #51 (@bcoe)
+
+### v2.0.0 (2015/02/06 07:45 +00:00)
+- [0250517](https://github.com/bcoe/yargs/commit/0250517c9643e53f431b824e8ccfa54937414011) - [108fb84](https://github.com/bcoe/yargs/commit/108fb8409a3a63dcaf99d917fe4dfcfaa1de236d) fixed bug with boolean parsing, when bools separated by = see #66 (@bcoe)
+- [a465a59](https://github.com/bcoe/yargs/commit/a465a5915f912715738de890982e4f8395958b10) Add `files` field to the package.json (@shinnn)
+- [31043de](https://github.com/bcoe/yargs/commit/31043de7a38a17c4c97711f1099f5fb164334db3) fix for yargs.argv having the same keys added multiple times see #63 (@bcoe)
+- [2d68c5b](https://github.com/bcoe/yargs/commit/2d68c5b91c976431001c4863ce47c9297850f1ad) Disable process.exit calls using .exitProcess(false) (@cianclarke)
+- [45da9ec](https://github.com/bcoe/yargs/commit/45da9ec4c55a7bd394721bc6a1db0dabad7bc52a) Mention .option in README (@eush77)
+
+### v1.3.2 (2014/10/06 21:56 +00:00)
+- [b8d3472](https://github.com/bcoe/yargs/commit/b8d34725482e5821a3cc809c0df71378f282f526) 1.3.2 (@chevex)
+
+### list (2014/08/30 18:41 +00:00)
+- [fbc777f](https://github.com/bcoe/yargs/commit/fbc777f416eeefd37c84e44d27d7dfc7c1925721) Now that yargs is the successor to optimist, I'm changing the README language to be more universal. Pirate speak isn't very accessible to non-native speakers. (@chevex)
+- [a54d068](https://github.com/bcoe/yargs/commit/a54d0682ae2efc2394d407ab171cc8a8bbd135ea) version output will not print extra newline (@boneskull)
+- [1cef5d6](https://github.com/bcoe/yargs/commit/1cef5d62a9d6d61a3948a49574892e01932cc6ae) Added contributors section to package.json (@chrisn)
+- [cc295c0](https://github.com/bcoe/yargs/commit/cc295c0a80a2de267e0155b60d315fc4b6f7c709) Added 'require' and 'required' as synonyms for 'demand' (@chrisn)
+- [d0bf951](https://github.com/bcoe/yargs/commit/d0bf951d949066b6280101ed606593d079ee15c8) Updating minimist. (@chevex)
+- [c15f8e7](https://github.com/bcoe/yargs/commit/c15f8e7f245b261e542cf205ce4f4313630cbdb4) Fix #31 (bad interaction between camelCase options and strict mode) (@nylen)
+- [d991b9b](https://github.com/bcoe/yargs/commit/d991b9be687a68812dee1e3b185ba64b7778b82d) Added .help() and .version() methods (@chrisn)
+- [e8c8aa4](https://github.com/bcoe/yargs/commit/e8c8aa46268379357cb11e9fc34b8c403037724b) Added .showHelpOnFail() method (@chrisn)
+- [e855af4](https://github.com/bcoe/yargs/commit/e855af4a933ea966b5bbdd3c4c6397a4bac1a053) Allow boolean flag with .demand() (@chrisn)
+- [14dbec2](https://github.com/bcoe/yargs/commit/14dbec24fb7380683198e2b20c4deb8423e64bea) Fixes issue #22. Arguments are no longer printed to the console when using .config. (@chevex)
+- [bef74fc](https://github.com/bcoe/yargs/commit/bef74fcddc1544598a804f80d0a3728459f196bf) Informing users that Yargs is the official optimist successor. (@chevex)
+- [#24](https://github.com/bcoe/yargs/pull/24) Merge pull request #24 from chrisn/strict (@chrisn)
+- [889a2b2](https://github.com/bcoe/yargs/commit/889a2b28eb9768801b05163360a470d0fd6c8b79) Added requiresArg option, for options that require values (@chrisn)
+- [eb16369](https://github.com/bcoe/yargs/commit/eb163692262be1fe80b992fd8803d5923c5a9b18) Added .strict() method, to report error if unknown arguments are given (@chrisn)
+- [0471c3f](https://github.com/bcoe/yargs/commit/0471c3fd999e1ad4e6cded88b8aa02013b66d14f) Changed optimist to yargs in usage-options.js example (@chrisn)
+- [5c88f74](https://github.com/bcoe/yargs/commit/5c88f74e3cf031b17c54b4b6606c83e485ff520e) Change optimist to yargs in examples (@chrisn)
+- [66f12c8](https://github.com/bcoe/yargs/commit/66f12c82ba3c943e4de8ca862980e835da8ecb3a) Fix a couple of bad interactions between aliases and defaults (@nylen)
+- [8fa1d80](https://github.com/bcoe/yargs/commit/8fa1d80f14b03eb1f2898863a61f1d1615bceb50) Document second argument of usage(message, opts) (@Gobie)
+- [56e6528](https://github.com/bcoe/yargs/commit/56e6528cf674ff70d63083fb044ff240f608448e) For "--some-option", also set argv.someOption (@nylen)
+- [ed5f6d3](https://github.com/bcoe/yargs/commit/ed5f6d33f57ad1086b11c91b51100f7c6c7fa8ee) Finished porting unit tests to Mocha. (@chevex)
+
+### v1.0.15 (2014/02/05 23:18 +00:00)
+- [e2b1fc0](https://github.com/bcoe/yargs/commit/e2b1fc0c4a59cf532ae9b01b275e1ef57eeb64d2) 1.0.15 update to badges (@chevex)
+
+### v1.0.14 (2014/02/05 23:17 +00:00)
+- [f33bbb0](https://github.com/bcoe/yargs/commit/f33bbb0f00fe18960f849cc8e15a7428a4cd59b8) Revert "Fixed issue which caused .demand function not to work correctly." (@chevex)
+
+### v1.0.13 (2014/02/05 22:13 +00:00)
+- [6509e5e](https://github.com/bcoe/yargs/commit/6509e5e7dee6ef1a1f60eea104be0faa1a045075) Fixed issue which caused .demand function not to work correctly. (@chevex)
+
+### v1.0.12 (2013/12/13 00:09 +00:00)
+- [05eb267](https://github.com/bcoe/yargs/commit/05eb26741c9ce446b33ff006e5d33221f53eaceb) 1.0.12 (@chevex)
+
+### v1.0.11 (2013/12/13 00:07 +00:00)
+- [c1bde46](https://github.com/bcoe/yargs/commit/c1bde46e37318a68b87d17a50c130c861d6ce4a9) 1.0.11 (@chevex)
+
+### v1.0.10 (2013/12/12 23:57 +00:00)
+- [dfebf81](https://github.com/bcoe/yargs/commit/dfebf8164c25c650701528ee581ca483a99dc21c) Fixed formatting in README (@chevex)
+
+### v1.0.9 (2013/12/12 23:47 +00:00)
+- [0b4e34a](https://github.com/bcoe/yargs/commit/0b4e34af5e6d84a9dbb3bb6d02cd87588031c182) Update README.md (@chevex)
+
+### v1.0.8 (2013/12/06 16:36 +00:00)
+- [#1](https://github.com/bcoe/yargs/pull/1) fix error caused by check() see #1 (@martinheidegger)
+
+### v1.0.7 (2013/11/24 18:01 +00:00)
+- [a247d88](https://github.com/bcoe/yargs/commit/a247d88d6e46644cbb7303c18b1bb678fc132d72) Modified Pirate Joe image. (@chevex)
+
+### v1.0.6 (2013/11/23 19:21 +00:00)
+- [d7f69e1](https://github.com/bcoe/yargs/commit/d7f69e1d34bc929736a8bdccdc724583e21b7eab) Updated Pirate Joe image. (@chevex)
+
+### v1.0.5 (2013/11/23 19:09 +00:00)
+- [ece809c](https://github.com/bcoe/yargs/commit/ece809cf317cc659175e1d66d87f3ca68c2760be) Updated readme notice again. (@chevex)
+
+### v1.0.4 (2013/11/23 19:05 +00:00)
+- [9e81e81](https://github.com/bcoe/yargs/commit/9e81e81654028f83ba86ffc3ac772a0476084e5e) Updated README with a notice about yargs being a fork of optimist and what that implies. (@chevex)
+
+### v1.0.3 (2013/11/23 17:43 +00:00)
+- [65e7a78](https://github.com/bcoe/yargs/commit/65e7a782c86764944d63d084416aba9ee6019c5f) Changed some small wording in README.md. (@chevex)
+- [459e20e](https://github.com/bcoe/yargs/commit/459e20e539b366b85128dd281ccd42221e96c7da) Fix a bug in the options function, when string and boolean options weren't applied to aliases. (@shockone)
+
+### v1.0.2 (2013/11/23 09:46 +00:00)
+- [3d80ebe](https://github.com/bcoe/yargs/commit/3d80ebed866d3799224b6f7d596247186a3898a9) 1.0.2 (@chevex)
+
+### v1.0.1 (2013/11/23 09:39 +00:00)
+- [f80ff36](https://github.com/bcoe/yargs/commit/f80ff3642d580d4b68bf9f5a94277481bd027142) Updated image. (@chevex)
+
+### v1.0.0 (2013/11/23 09:33 +00:00)
+- [54e31d5](https://github.com/bcoe/yargs/commit/54e31d505f820b80af13644e460894b320bf25a3) Rebranded from optimist to yargs in the spirit of the fork :D (@chevex)
+- [4ebb6c5](https://github.com/bcoe/yargs/commit/4ebb6c59f44787db7c24c5b8fe2680f01a23f498) Added documentation for demandCount(). (@chevex)
+- [4561ce6](https://github.com/bcoe/yargs/commit/4561ce66dcffa95f49e8b4449b25b94cd68acb25) Simplified the error messages returned by .check(). (@chevex)
+- [661c678](https://github.com/bcoe/yargs/commit/661c67886f479b16254a830b7e1db3be29e6b7a6) Fixed an issue with demand not accepting a zero value. (@chevex)
+- [731dd3c](https://github.com/bcoe/yargs/commit/731dd3c37624790490bd6df4d5f1da8f4348279e) Add .fail(fn) so death isn't the only option. Should fix issue #39. (@chevex)
+- [fa15417](https://github.com/bcoe/yargs/commit/fa15417ff9e70dace0d726627a5818654824c1d8) Added a few missing 'return self' (@chevex)
+- [e655e4d](https://github.com/bcoe/yargs/commit/e655e4d99d1ae1d3695ef755d51c2de08d669761) Fix showing help in certain JS environments. (@chevex)
+- [a746a31](https://github.com/bcoe/yargs/commit/a746a31cd47c87327028e6ea33762d6187ec5c87) Better string representation of default values. (@chevex)
+- [6134619](https://github.com/bcoe/yargs/commit/6134619a7e90b911d5443230b644c5d447c1a68c) Implies: conditional demands (@chevex)
+- [046b93b](https://github.com/bcoe/yargs/commit/046b93b5d40a27367af4cb29726e4d781d934639) Added support for JSON config files. (@chevex)
+- [a677ec0](https://github.com/bcoe/yargs/commit/a677ec0a0ecccd99c75e571d03323f950688da03) Add .example(cmd, desc) feature. (@chevex)
+- [1bd4375](https://github.com/bcoe/yargs/commit/1bd4375e11327ba1687d4bb6e5e9f3c30c1be2af) Added 'defaults' as alias to 'default' so as to avoid usage of a reserved keyword. (@chevex)
+- [6b753c1](https://github.com/bcoe/yargs/commit/6b753c16ca09e723060e70b773b430323b29c45c) add .normalize(args..) support for normalizing paths (@chevex)
+- [33d7d59](https://github.com/bcoe/yargs/commit/33d7d59341d364f03d3a25f0a55cb99004dbbe4b) Customize error messages with demand(key, msg) (@chevex)
+- [647d37f](https://github.com/bcoe/yargs/commit/647d37f164c20f4bafbf67dd9db6cd6e2cd3b49f) Merge branch 'rewrite-duplicate-test' of github.com:isbadawi/node-optimist (@chevex)
+- [9059d1a](https://github.com/bcoe/yargs/commit/9059d1ad5e8aea686c2a01c89a23efdf929fff2e) Pass aliases object to check functions for greater versatility. (@chevex)
+- [623dc26](https://github.com/bcoe/yargs/commit/623dc26c7331abff2465ef8532e3418996d42fe6) Added ability to count boolean options and rolled minimist library back into project. (@chevex)
+- [49f0dce](https://github.com/bcoe/yargs/commit/49f0dcef35de4db544c3966350d36eb5838703f6) Fixed small typo. (@chevex)
+- [79ec980](https://github.com/bcoe/yargs/commit/79ec9806d9ca6eb0014cfa4b6d1849f4f004baf2) Removed dependency on wordwrap module. (@chevex)
+- [ea14630](https://github.com/bcoe/yargs/commit/ea14630feddd69d1de99dd8c0e08948f4c91f00a) Merge branch 'master' of github.com:chbrown/node-optimist (@chevex)
+- [2b75da2](https://github.com/bcoe/yargs/commit/2b75da2624061e0f4f3107d20303c06ec9054906) Merge branch 'master' of github.com:seanzhou1023/node-optimist (@chevex)
+- [d9bda11](https://github.com/bcoe/yargs/commit/d9bda1116e26f3b40e833ca9ca19263afea53565) Merge branch 'patch-1' of github.com:thefourtheye/node-optimist (@chevex)
+- [d6cc606](https://github.com/bcoe/yargs/commit/d6cc6064a4f1bea38a16a4430b8a1334832fbeff) Renamed README. (@chevex)
+- [9498d3f](https://github.com/bcoe/yargs/commit/9498d3f59acfb5e102826503e681623c3a64b178) Renamed readme and added .gitignore. (@chevex)
+- [bbd1fe3](https://github.com/bcoe/yargs/commit/bbd1fe37fefa366dde0fb3dc44d91fe8b28f57f5) Included examples for ```help``` and ```showHelp``` functions and fixed few formatting issues (@thefourtheye)
+- [37fea04](https://github.com/bcoe/yargs/commit/37fea0470a5796a0294c1dcfff68d8041650e622) .alias({}) behaves differently based on mapping direction when generating descriptions (@chbrown)
+- [855b20d](https://github.com/bcoe/yargs/commit/855b20d0be567ca121d06b30bea64001b74f3d6d) Documented function signatures are useful for dynamically typed languages. (@chbrown)
+
+### 0.6.0 (2013/06/25 08:48 +00:00)
+- [d37bfe0](https://github.com/bcoe/yargs/commit/d37bfe05ae6d295a0ab481efe4881222412791f4) all tests passing using minimist (@substack)
+- [76f1352](https://github.com/bcoe/yargs/commit/76f135270399d01f2bbc621e524a5966e5c422fd) all parse tests now passing (@substack)
+- [a7b6754](https://github.com/bcoe/yargs/commit/a7b6754276c38d1565479a5685c3781aeb947816) using minimist, some tests passing (@substack)
+- [6655688](https://github.com/bcoe/yargs/commit/66556882aa731cbbbe16cc4d42c85740a2e98099) Give credit where its due (@DeadAlready)
+- [602a2a9](https://github.com/bcoe/yargs/commit/602a2a92a459f93704794ad51b115bbb08b535ce) v0.5.3 - Remove wordwrap as dependency (@DeadAlready)
+
+### 0.5.2 (2013/05/31 03:46 +00:00)
+- [4497ca5](https://github.com/bcoe/yargs/commit/4497ca55e332760a37b866ec119ded347ca27a87) fixed the whitespace bug without breaking anything else (@substack)
+- [5a3dd1a](https://github.com/bcoe/yargs/commit/5a3dd1a4e0211a38613c6e02f61328e1031953fa) failing test for whitespace arg (@substack)
+
+### 0.5.1 (2013/05/30 07:17 +00:00)
+- [a20228f](https://github.com/bcoe/yargs/commit/a20228f62a454755dd07f628a7c5759113918327) fix parse() to work with functions before it (@substack)
+- [b13bd4c](https://github.com/bcoe/yargs/commit/b13bd4cac856a9821d42fa173bdb58f089365a7d) failing test for parse() with modifiers (@substack)
+
+### 0.5.0 (2013/05/18 21:59 +00:00)
+- [c474a64](https://github.com/bcoe/yargs/commit/c474a649231527915c222156e3b40806d365a87c) fixes for dash (@substack)
+
+### 0.4.0 (2013/04/13 19:03 +00:00)
+- [dafe3e1](https://github.com/bcoe/yargs/commit/dafe3e18d7c6e7c2d68e06559df0e5cbea3adb14) failing short test (@substack)
+
+### 0.3.7 (2013/04/04 04:07 +00:00)
+- [6c7a0ec](https://github.com/bcoe/yargs/commit/6c7a0ec94ce4199a505f0518b4d6635d4e47cc81) Fix for windows. On windows there is no _ in environment. (@hdf)
+
+### 0.3.6 (2013/04/04 04:04 +00:00)
+- [e72346a](https://github.com/bcoe/yargs/commit/e72346a727b7267af5aa008b418db89970873f05) Add support for newlines in -a="" arguments (@danielbeardsley)
+- [71e1fb5](https://github.com/bcoe/yargs/commit/71e1fb55ea9987110a669ac6ec12338cfff3821c) drop 0.4, add 0.8 to travis (@substack)
+
+### 0.3.5 (2012/10/10 11:09 +00:00)
+- [ee692b3](https://github.com/bcoe/yargs/commit/ee692b37554c70a0bb16389a50a26b66745cbbea) Fix parsing booleans (@vojtajina)
+- [5045122](https://github.com/bcoe/yargs/commit/5045122664c3f5b4805addf1be2148d5856f7ce8) set $0 properly in the tests (@substack)
+
+### 0.3.4 (2012/04/30 06:54 +00:00)
+- [f28c0e6](https://github.com/bcoe/yargs/commit/f28c0e62ca94f6e0bb2e6d82fc3d91a55e69b903) bump for string "true" params (@substack)
+- [8f44aeb](https://github.com/bcoe/yargs/commit/8f44aeb74121ddd689580e2bf74ef86a605e9bf2) Fix failing test for aliased booleans. (@coderarity)
+- [b9f7b61](https://github.com/bcoe/yargs/commit/b9f7b613b1e68e11e6c23fbda9e555a517dcc976) Add failing test for short aliased booleans. (@coderarity)
+
+### 0.3.3 (2012/04/30 06:45 +00:00)
+- [541bac8](https://github.com/bcoe/yargs/commit/541bac8dd787a5f1a5d28f6d8deb1627871705e7) Fixes #37.
+
+### 0.3.2 (2012/04/12 20:28 +00:00)
+- [3a0f014](https://github.com/bcoe/yargs/commit/3a0f014c1451280ac1c9caa1f639d31675586eec) travis badge (@substack)
+- [4fb60bf](https://github.com/bcoe/yargs/commit/4fb60bf17845f4ce3293f8ca49c9a1a7c736cfce) Fix boolean aliases. (@coderarity)
+- [f14dda5](https://github.com/bcoe/yargs/commit/f14dda546efc4fe06ace04d36919bfbb7634f79b) Adjusted package.json to use tap (@jfhbrook)
+- [88e5d32](https://github.com/bcoe/yargs/commit/88e5d32295be6e544c8d355ff84e355af38a1c74) test/usage.js no longer hangs (@jfhbrook)
+- [e1e740c](https://github.com/bcoe/yargs/commit/e1e740c27082f3ce84deca2093d9db2ef735d0e5) two tests for combined boolean/alias opts parsing (@jfhbrook)
+
+### 0.3.1 (2011/12/31 08:44 +00:00)
+- [d09b719](https://github.com/bcoe/yargs/commit/d09b71980ef711b6cf3918cd19beec8257e40e82) If "default" is set to false it was not passed on, fixed. (@wolframkriesing)
+
+### 0.3.0 (2011/12/09 06:03 +00:00)
+- [6e74aa7](https://github.com/bcoe/yargs/commit/6e74aa7b46a65773e20c0cb68d2d336d4a0d553d) bump and documented dot notation (@substack)
+
+### 0.2.7 (2011/10/20 02:25 +00:00)
+- [94adee2](https://github.com/bcoe/yargs/commit/94adee20e17b58d0836f80e8b9cdbe9813800916) argv._ can be told 'Hey! argv._! Don't be messing with my args.', and it WILL obey (@colinta)
+- [c46fdd5](https://github.com/bcoe/yargs/commit/c46fdd56a05410ae4a1e724a4820c82e77ff5469) optimistic critter image (@substack)
+- [5c95c73](https://github.com/bcoe/yargs/commit/5c95c73aedf4c7482bd423e10c545e86d7c8a125) alias options() to option() (@substack)
+- [f7692ea](https://github.com/bcoe/yargs/commit/f7692ea8da342850af819367833abb685fde41d8) [fix] Fix for parsing boolean edge case (@indexzero)
+- [d1f92d1](https://github.com/bcoe/yargs/commit/d1f92d1425bd7f356055e78621b30cdf9741a3c2)
+- [b01bda8](https://github.com/bcoe/yargs/commit/b01bda8d86e455bbf74ce497864cb8ab5b9fb847) [fix test] Update to ensure optimist is aware of default booleans. Associated tests included (@indexzero)
+- [aa753e7](https://github.com/bcoe/yargs/commit/aa753e7c54fb3a12f513769a0ff6d54aa0f63943) [dist test] Update devDependencies in package.json. Update test pathing to be more npm and require.paths future-proof (@indexzero)
+- [7bfce2f](https://github.com/bcoe/yargs/commit/7bfce2f3b3c98e6539e7549d35fbabced7e9341e) s/sys/util/ (@substack)
+- [d420a7a](https://github.com/bcoe/yargs/commit/d420a7a9c890d2cdb11acfaf3ea3f43bc3e39f41) update usage output (@substack)
+- [cf86eed](https://github.com/bcoe/yargs/commit/cf86eede2e5fc7495b6ec15e6d137d9ac814f075) some sage readme protips about parsing rules (@substack)
+- [5da9f7a](https://github.com/bcoe/yargs/commit/5da9f7a5c0e1758ec7c5801fb3e94d3f6e970513) documented all the methods finally (@substack)
+- [8ca6879](https://github.com/bcoe/yargs/commit/8ca6879311224b25933642987300f6a29de5c21b) fenced syntax highlighting (@substack)
+- [b72bacf](https://github.com/bcoe/yargs/commit/b72bacf1d02594778c1935405bc8137eb61761dc) right-alignment of wrapped extra params (@substack)
+- [2b980bf](https://github.com/bcoe/yargs/commit/2b980bf2656b4ee8fc5134dc5f56a48855c35198) now with .wrap() (@substack)
+- [d614f63](https://github.com/bcoe/yargs/commit/d614f639654057d1b7e35e3f5a306e88ec2ad1e4) don't show 'Options:' when there aren't any (@substack)
+- [691eda3](https://github.com/bcoe/yargs/commit/691eda354df97b5a86168317abcbcaabdc08a0fb) failing test for multi-aliasing (@substack)
+- [0826c9f](https://github.com/bcoe/yargs/commit/0826c9f462109feab2bc7a99346d22e72bf774b7) "Options:" > "options:" (@substack)
+- [72f7490](https://github.com/bcoe/yargs/commit/72f749025d01b7f295738ed370a669d885fbada0) [minor] Update formatting for `.showHelp()` (@indexzero)
+- [75aecce](https://github.com/bcoe/yargs/commit/75aeccea74329094072f95800e02c275e7d999aa) options works again, too lazy to write a proper test right now (@substack)
+- [f742e54](https://github.com/bcoe/yargs/commit/f742e5439817c662dc3bd8734ddd6467e6018cfd) line_count_options example, which breaks (@substack)
+- [4ca06b8](https://github.com/bcoe/yargs/commit/4ca06b8b4ea99b5d5714b315a2a8576bee6e5537) line count example (@substack)
+- [eeb8423](https://github.com/bcoe/yargs/commit/eeb8423e0a5ecc9dc3eb1e6df9f3f8c1c88f920b) remove self.argv setting in boolean (@substack)
+- [6903412](https://github.com/bcoe/yargs/commit/69034126804660af9cc20ea7f4457b50338ee3d7) removed camel case for now (@substack)
+- [5a0d88b](https://github.com/bcoe/yargs/commit/5a0d88bf23e9fa79635dd034e2a1aa992acc83cd) remove dead longest checking code (@substack)
+- [d782170](https://github.com/bcoe/yargs/commit/d782170babf7284b1aa34f5350df0dd49c373fa8) .help() too (@substack)
+- [622ec17](https://github.com/bcoe/yargs/commit/622ec17379bb5374fdbb190404c82bc600975791) rm old help generator (@substack)
+- [7c8baac](https://github.com/bcoe/yargs/commit/7c8baac4d66195e9f5158503ea9ebfb61153dab7) nub keys (@substack)
+- [8197785](https://github.com/bcoe/yargs/commit/8197785ad4762465084485b041abd722f69bf344) generate help message based on the previous calls, todo: nub (@substack)
+- [3ffbdc3](https://github.com/bcoe/yargs/commit/3ffbdc33c8f5e83d4ea2ac60575ce119570c7ede) stub out new showHelp, better checks (@substack)
+- [d4e21f5](https://github.com/bcoe/yargs/commit/d4e21f56a4830f7de841900d3c79756fb9886184) let .options() take single options too (@substack)
+- [3c4cf29](https://github.com/bcoe/yargs/commit/3c4cf2901a29bac119cca8e983028d8669230ec6) .options() is now heaps simpler (@substack)
+- [89f0d04](https://github.com/bcoe/yargs/commit/89f0d043cbccd302f10ab30c2069e05d2bf817c9) defaults work again, all tests pass (@substack)
+- [dd87333](https://github.com/bcoe/yargs/commit/dd8733365423006a6e4156372ebb55f98323af58) update test error messages, down to 2 failing tests (@substack)
+- [53f7bc6](https://github.com/bcoe/yargs/commit/53f7bc626b9875f2abdfc5dd7a80bde7f14143a3) fix for bools doubling up, passes the parse test again, others fail (@substack)
+- [2213e2d](https://github.com/bcoe/yargs/commit/2213e2ddc7263226fba717fb041dc3fde9bc2ee4) refactored for an argv getter, failing several tests (@substack)
+- [d1e7379](https://github.com/bcoe/yargs/commit/d1e737970f15c6c006bebdd8917706827ff2f0f2) just rescan for now, alias test passes (@substack)
+- [b2f8c99](https://github.com/bcoe/yargs/commit/b2f8c99cc477a8eb0fdf4cf178e1785b63185cfd) failing alias test (@substack)
+- [d0c0174](https://github.com/bcoe/yargs/commit/d0c0174daa144bfb6dc7290fdc448c393c475e15) .alias() (@substack)
+- [d85f431](https://github.com/bcoe/yargs/commit/d85f431ad7d07b058af3f2a57daa51495576c164) [api] Remove `.describe()` in favor of building upon the existing `.usage()` API (@indexzero)
+- [edbd527](https://github.com/bcoe/yargs/commit/edbd5272a8e213e71acd802782135c7f9699913a) [doc api] Add `.describe()`, `.options()`, and `.showHelp()` methods along with example. (@indexzero)
+- [be4902f](https://github.com/bcoe/yargs/commit/be4902ff0961ae8feb9093f2c0a4066463ded2cf) updates for coffee since it now does argv the node way (@substack)
+- [e24cb23](https://github.com/bcoe/yargs/commit/e24cb23798ee64e53b60815e7fda78b87f42390c) more general coffeescript detection (@substack)
+- [78ac753](https://github.com/bcoe/yargs/commit/78ac753e5d0ec32a96d39d893272afe989e42a4d) Don't trigger the CoffeeScript hack when running under node_g. (@papandreou)
+- [bcfe973](https://github.com/bcoe/yargs/commit/bcfe9731d7f90d4632281b8a52e8d76eb0195ae6) .string() but failing test (@substack)
+- [1987aca](https://github.com/bcoe/yargs/commit/1987aca28c7ba4e8796c07bbc547cb984804c826) test hex strings (@substack)
+- [ef36db3](https://github.com/bcoe/yargs/commit/ef36db32259b0b0d62448dc907c760e5554fb7e7) more keywords (@substack)
+- [cc53c56](https://github.com/bcoe/yargs/commit/cc53c56329960bed6ab077a79798e991711ba01d) Added camelCase function that converts --multi-word-option to camel case (so it becomes argv.multiWordOption). (@papandreou)
+- [60b57da](https://github.com/bcoe/yargs/commit/60b57da36797716e5783a633c6d5c79099016d45) fixed boolean bug by rescanning (@substack)
+- [dff6d07](https://github.com/bcoe/yargs/commit/dff6d078d97f8ac503c7d18dcc7b7a8c364c2883) boolean examples (@substack)
+- [0e380b9](https://github.com/bcoe/yargs/commit/0e380b92c4ef4e3c8dac1da18b5c31d85b1d02c9) boolean() with passing test (@substack)
+- [62644d4](https://github.com/bcoe/yargs/commit/62644d4bffbb8d1bbf0c2baf58a1d14a6359ef07) coffee compatibility with node regex for versions too (@substack)
+- [430fafc](https://github.com/bcoe/yargs/commit/430fafcf1683d23774772826581acff84b456827) argv._ fixed by fixing the coffee detection (@substack)
+- [343b8af](https://github.com/bcoe/yargs/commit/343b8afefd98af274ebe21b5a16b3a949ec5429f) whichNodeArgs test fails too (@substack)
+- [63df2f3](https://github.com/bcoe/yargs/commit/63df2f371f31e63d7f1dec2cbf0022a5f08da9d2) replicated mnot's bug in whichNodeEmpty test (@substack)
+- [35473a4](https://github.com/bcoe/yargs/commit/35473a4d93a45e5e7e512af8bb54ebb532997ae1) test for ./bin usage (@substack)
+- [13df151](https://github.com/bcoe/yargs/commit/13df151e44228eed10e5441c7cd163e086c458a4) don't coerce booleans to numbers (@substack)
+- [85f8007](https://github.com/bcoe/yargs/commit/85f8007e93b8be7124feea64b1f1916d8ba1894a) package bump for automatic number conversion (@substack)
+- [8f17014](https://github.com/bcoe/yargs/commit/8f170141cded4ccc0c6d67a849c5bf996aa29643) updated readme and examples with new auto-numberification goodness (@substack)
+- [73dc901](https://github.com/bcoe/yargs/commit/73dc9011ac968e39b55e19e916084a839391b506) auto number conversion works yay (@substack)
+- [bcec56b](https://github.com/bcoe/yargs/commit/bcec56b3d031e018064cbb691539ccc4f28c14ad) failing test for not-implemented auto numification (@substack)
+- [ebd2844](https://github.com/bcoe/yargs/commit/ebd2844d683feeac583df79af0e5124a7a7db04e) odd that eql doesn't check types careflly (@substack)
+- [fd854b0](https://github.com/bcoe/yargs/commit/fd854b02e512ce854b76386d395672a7969c1bc4) package author + keywords (@substack)
+- [656a1d5](https://github.com/bcoe/yargs/commit/656a1d5a1b7c0e49d72e80cb13f20671d56f76c6) updated readme with .default() stuff (@substack)
+- [cd7f8c5](https://github.com/bcoe/yargs/commit/cd7f8c55f0b82b79b690d14c5f806851236998a1) passing tests for new .default() behavior (@substack)
+- [932725e](https://github.com/bcoe/yargs/commit/932725e39ce65bc91a0385a5fab659a5fa976ac2) new default() thing for setting default key/values (@substack)
+- [4e6c7ab](https://github.com/bcoe/yargs/commit/4e6c7aba6374ac9ebc6259ecf91f13af7bce40e3) test for coffee usage (@substack)
+- [d54ffcc](https://github.com/bcoe/yargs/commit/d54ffccf2a5a905f51ed5108f7c647f35d64ae23) new --key value style with passing tests. NOTE: changes existing behavior (@substack)
+- [ed2a2d5](https://github.com/bcoe/yargs/commit/ed2a2d5d828100ebeef6385c0fb88d146a5cfe9b) package bump for summatix's coffee script fix (@substack)
+- [75a975e](https://github.com/bcoe/yargs/commit/75a975eed8430d28e2a79dc9e6d819ad545f4587) Added support for CoffeeScript (@summatix)
+- [56b2b1d](https://github.com/bcoe/yargs/commit/56b2b1de8d11f8a2b91979d8ae2d6db02d8fe64d) test coverage for the falsy check() usage (@substack)
+- [a4843a9](https://github.com/bcoe/yargs/commit/a4843a9f0e69ffb4afdf6a671d89eb6f218be35d) check bug fixed plus a handy string (@substack)
+- [857bd2d](https://github.com/bcoe/yargs/commit/857bd2db933a5aaa9cfecba0ced2dc9b415f8111) tests for demandCount, back up to 100% coverage (@substack)
+- [073b776](https://github.com/bcoe/yargs/commit/073b7768ebd781668ef05c13f9003aceca2f5c35) call demandCount from demand (@substack)
+- [4bd4b7a](https://github.com/bcoe/yargs/commit/4bd4b7a085c8b6ce1d885a0f486cc9865cee2db1) add demandCount to check for the number of arguments in the _ list (@marshall)
+- [b8689ac](https://github.com/bcoe/yargs/commit/b8689ac68dacf248119d242bba39a41cb0adfa07) Rebase checks. That will be its own module eventually. (@substack)
+- [e688370](https://github.com/bcoe/yargs/commit/e688370b576f0aa733c3f46183df69e1b561668e) a $0 like in perl (@substack)
+- [2e5e196](https://github.com/bcoe/yargs/commit/2e5e1960fc19afb21fb3293752316eaa8bcd3609) usage test hacking around process and console (@substack)
+- [fcc3521](https://github.com/bcoe/yargs/commit/fcc352163fbec6a1dfe8caf47a0df39de24fe016) description pun (@substack)
+- [87a1fe2](https://github.com/bcoe/yargs/commit/87a1fe29037ca2ca5fefda85141aaeb13e8ce761) mit/x11 license (@substack)
+- [8d089d2](https://github.com/bcoe/yargs/commit/8d089d24cd687c0bde3640a96c09b78f884900dd) bool example is more consistent and also shows off short option grouping (@substack)
+- [448d747](https://github.com/bcoe/yargs/commit/448d7473ac68e8e03d8befc9457b0d9e21725be0) start of the readme and examples (@substack)
+- [da74dea](https://github.com/bcoe/yargs/commit/da74dea799a9b59dbf022cbb8001bfdb0d52eec9) more tests for long and short captures (@substack)
+- [ab6387e](https://github.com/bcoe/yargs/commit/ab6387e6769ca4af82ca94c4c67c7319f0d9fcfa) silly bug in the tests with s/not/no/, all tests pass now (@substack)
+- [102496a](https://github.com/bcoe/yargs/commit/102496a319e8e06f6550d828fc2f72992c7d9ecc) hack an instance for process.argv onto Argv so the export can be called to create an instance or used for argv, which is the most common case (@substack)
+- [a01caeb](https://github.com/bcoe/yargs/commit/a01caeb532546d19f68f2b2b87f7036cfe1aaedd) divide example (@substack)
+- [443da55](https://github.com/bcoe/yargs/commit/443da55736acbaf8ff8b04d1b9ce19ab016ddda2) start of the lib with a package.json (@substack)
diff --git a/server/node_modules/yargs/LICENSE b/server/node_modules/yargs/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..747ab114c9535e675a2d5391dc2ae30e9cff19ca
--- /dev/null
+++ b/server/node_modules/yargs/LICENSE
@@ -0,0 +1,22 @@
+Copyright 2010 James Halliday (mail@substack.net)
+Modified work Copyright 2014 Contributors (ben@npmjs.com)
+
+This project is free software released under the MIT/X11 license:
+
+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.
diff --git a/server/node_modules/yargs/README.md b/server/node_modules/yargs/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..fae1dc6054a8a16c44dfa97602b185d926d94411
--- /dev/null
+++ b/server/node_modules/yargs/README.md
@@ -0,0 +1,1739 @@
+  yargs
+========
+
+Yargs be a node.js library fer hearties tryin' ter parse optstrings.
+
+With yargs, ye be havin' a map that leads straight to yer treasure! Treasure of course, being a simple option hash.
+
+[![Build Status][travis-image]][travis-url]
+[![Coverage Status][coveralls-image]][coveralls-url]
+[![NPM version][npm-image]][npm-url]
+[![Windows Tests][windows-image]][windows-url]
+[![js-standard-style][standard-image]][standard-url]
+[![standard-version][standard-version-image]][standard-version-url]
+[![Gitter][gitter-image]][gitter-url]
+
+> Yargs is the official successor to optimist. Please feel free to submit issues and pull requests. If you'd like to contribute and don't know where to start, have a look at [the issue list](https://github.com/yargs/yargs/issues) :)
+
+examples
+========
+
+With yargs, the options be just a hash!
+-------------------------------------------------------------------
+
+plunder.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs').argv;
+
+if (argv.ships > 3 && argv.distance < 53.5) {
+    console.log('Plunder more riffiwobbles!');
+} else {
+    console.log('Retreat from the xupptumblers!');
+}
+````
+
+***
+
+    $ ./plunder.js --ships=4 --distance=22
+    Plunder more riffiwobbles!
+
+    $ ./plunder.js --ships 12 --distance 98.7
+    Retreat from the xupptumblers!
+
+![Joe was one optimistic pirate.](http://i.imgur.com/4WFGVJ9.png)
+
+But don't walk the plank just yet! There be more! You can do short options:
+-------------------------------------------------
+
+short.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs').argv;
+console.log('(%d,%d)', argv.x, argv.y);
+````
+
+***
+
+    $ ./short.js -x 10 -y 21
+    (10,21)
+
+And booleans, both long, short, and even grouped:
+----------------------------------
+
+bool.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs').argv;
+
+if (argv.s) {
+    process.stdout.write(argv.fr ? 'Le perroquet dit: ' : 'The parrot says: ');
+}
+console.log(
+    (argv.fr ? 'couac' : 'squawk') + (argv.p ? '!' : '')
+);
+````
+
+***
+
+    $ ./bool.js -s
+    The parrot says: squawk
+
+    $ ./bool.js -sp
+    The parrot says: squawk!
+
+    $ ./bool.js -sp --fr
+    Le perroquet dit: couac!
+
+And non-hyphenated options too! Just use `argv._`!
+-------------------------------------------------
+
+nonopt.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs').argv;
+console.log('(%d,%d)', argv.x, argv.y);
+console.log(argv._);
+````
+
+***
+
+    $ ./nonopt.js -x 6.82 -y 3.35 rum
+    (6.82,3.35)
+    [ 'rum' ]
+
+    $ ./nonopt.js "me hearties" -x 0.54 yo -y 1.12 ho
+    (0.54,1.12)
+    [ 'me hearties', 'yo', 'ho' ]
+
+Yargs even counts your booleans!
+----------------------------------------------------------------------
+
+count.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs')
+    .count('verbose')
+    .alias('v', 'verbose')
+    .argv;
+
+VERBOSE_LEVEL = argv.verbose;
+
+function WARN()  { VERBOSE_LEVEL >= 0 && console.log.apply(console, arguments); }
+function INFO()  { VERBOSE_LEVEL >= 1 && console.log.apply(console, arguments); }
+function DEBUG() { VERBOSE_LEVEL >= 2 && console.log.apply(console, arguments); }
+
+WARN("Showing only important stuff");
+INFO("Showing semi-important stuff too");
+DEBUG("Extra chatty mode");
+````
+
+***
+    $ node count.js
+    Showing only important stuff
+
+    $ node count.js -v
+    Showing only important stuff
+    Showing semi-important stuff too
+
+    $ node count.js -vv
+    Showing only important stuff
+    Showing semi-important stuff too
+    Extra chatty mode
+
+    $ node count.js -v --verbose
+    Showing only important stuff
+    Showing semi-important stuff too
+    Extra chatty mode
+
+Tell users how to use yer options and make demands.
+-------------------------------------------------
+
+area.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs')
+    .usage('Usage: $0 -w [num] -h [num]')
+    .demand(['w','h'])
+    .argv;
+
+console.log("The area is:", argv.w * argv.h);
+````
+
+***
+
+    $ ./area.js -w 55 -h 11
+    The area is: 605
+
+    $ node ./area.js -w 4.91 -w 2.51
+    Usage: area.js -w [num] -h [num]
+
+    Options:
+      -w  [required]
+      -h  [required]
+
+    Missing required arguments: h
+
+After yer demands have been met, demand more! Ask for non-hyphenated arguments!
+-----------------------------------------
+
+demand_count.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs')
+    .demand(2)
+    .argv;
+console.dir(argv);
+````
+
+***
+
+	$ ./demand_count.js a
+
+	Not enough non-option arguments: got 1, need at least 2
+
+	$ ./demand_count.js a b
+	{ _: [ 'a', 'b' ], '$0': 'demand_count.js' }
+
+	$ ./demand_count.js a b c
+	{ _: [ 'a', 'b', 'c' ], '$0': 'demand_count.js' }
+
+EVEN MORE SHIVER ME TIMBERS!
+------------------
+
+default_singles.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs')
+    .default('x', 10)
+    .default('y', 10)
+    .argv
+;
+console.log(argv.x + argv.y);
+````
+
+***
+
+    $ ./default_singles.js -x 5
+    15
+
+default_hash.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs')
+    .default({ x : 10, y : 10 })
+    .argv
+;
+console.log(argv.x + argv.y);
+````
+
+***
+
+    $ ./default_hash.js -y 7
+    17
+
+And if you really want to get all descriptive about it...
+---------------------------------------------------------
+
+boolean_single.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs')
+    .boolean('v')
+    .argv
+;
+console.dir(argv.v);
+console.dir(argv._);
+````
+
+***
+
+    $ ./boolean_single.js -v "me hearties" yo ho
+    true
+    [ 'me hearties', 'yo', 'ho' ]
+
+
+boolean_double.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs')
+    .boolean(['x','y','z'])
+    .argv
+;
+console.dir([ argv.x, argv.y, argv.z ]);
+console.dir(argv._);
+````
+
+***
+
+    $ ./boolean_double.js -x -z one two three
+    [ true, false, true ]
+    [ 'one', 'two', 'three' ]
+
+Yargs is here to help you...
+---------------------------
+
+Ye can describe parameters fer help messages and set aliases. Yargs figures
+out how ter format a handy help string automatically.
+
+line_count.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs')
+    .usage('Usage: $0 <command> [options]')
+    .command('count', 'Count the lines in a file')
+    .example('$0 count -f foo.js', 'count the lines in the given file')
+    .alias('f', 'file')
+    .nargs('f', 1)
+    .describe('f', 'Load a file')
+    .demand(1, ['f'])
+    .help('h')
+    .alias('h', 'help')
+    .epilog('copyright 2015')
+    .argv;
+
+var fs = require('fs');
+var s = fs.createReadStream(argv.file);
+
+var lines = 0;
+s.on('data', function (buf) {
+    lines += buf.toString().match(/\n/g).length;
+});
+
+s.on('end', function () {
+    console.log(lines);
+});
+````
+
+***
+    $ node line_count.js count
+    Usage: line_count.js <command> [options]
+
+    Commands:
+      count    Count the lines in a file
+
+    Options:
+      -f, --file  Load a file        [required]
+      -h, --help  Show help           [boolean]
+
+    Examples:
+      line_count.js count -f foo.js  count the lines in the given file
+
+    copyright 2015
+
+    Missing required arguments: f
+
+    $ node line_count.js count --file line_count.js
+    26
+
+    $ node line_count.js count -f line_count.js
+    26
+
+methods
+=======
+
+By itself,
+
+````javascript
+require('yargs').argv
+````
+
+will use the `process.argv` array to construct the `argv` object.
+
+You can pass in the `process.argv` yourself:
+
+````javascript
+require('yargs')([ '-x', '1', '-y', '2' ]).argv
+````
+
+or use `.parse()` to do the same thing:
+
+````javascript
+require('yargs').parse([ '-x', '1', '-y', '2' ])
+````
+
+The rest of these methods below come in just before the terminating `.argv`.
+
+<a name="alias"></a>.alias(key, alias)
+------------------
+
+Set key names as equivalent such that updates to a key will propagate to aliases
+and vice-versa.
+
+Optionally `.alias()` can take an object that maps keys to aliases.
+Each key of this object should be the canonical version of the option, and each
+value should be a string or an array of strings.
+
+.argv
+-----
+
+Get the arguments as a plain old object.
+
+Arguments without a corresponding flag show up in the `argv._` array.
+
+The script name or node command is available at `argv.$0` similarly to how `$0`
+works in bash or perl.
+
+If `yargs` is executed in an environment that embeds node and there's no script name (e.g.
+[Electron](http://electron.atom.io/) or [nw.js](http://nwjs.io/)), it will ignore the first parameter since it
+expects it to be the script name. In order to override this behavior, use `.parse(process.argv.slice(1))`
+instead of `.argv` and the first parameter won't be ignored.
+
+<a name="array"></a>.array(key)
+----------
+
+Tell the parser to interpret `key` as an array. If `.array('foo')` is set,
+`--foo foo bar` will be parsed as `['foo', 'bar']` rather than as `'foo'`.
+
+<a name="boolean"></a>.boolean(key)
+-------------
+
+Interpret `key` as a boolean. If a non-flag option follows `key` in
+`process.argv`, that string won't get set as the value of `key`.
+
+`key` will default to `false`, unless a `default(key, undefined)` is
+explicitly set.
+
+If `key` is an array, interpret all the elements as booleans.
+
+.check(fn)
+----------
+
+Check that certain conditions are met in the provided arguments.
+
+`fn` is called with two arguments, the parsed `argv` hash and an array of options and their aliases.
+
+If `fn` throws or returns a non-truthy value, show the thrown error, usage information, and
+exit.
+
+<a name="choices"></a>.choices(key, choices)
+----------------------
+
+Limit valid values for `key` to a predefined set of `choices`, given as an array
+or as an individual value.
+
+```js
+var argv = require('yargs')
+  .alias('i', 'ingredient')
+  .describe('i', 'choose your sandwich ingredients')
+  .choices('i', ['peanut-butter', 'jelly', 'banana', 'pickles'])
+  .help('help')
+  .argv
+```
+
+If this method is called multiple times, all enumerated values will be merged
+together. Choices are generally strings or numbers, and value matching is
+case-sensitive.
+
+Optionally `.choices()` can take an object that maps multiple keys to their
+choices.
+
+Choices can also be specified as `choices` in the object given to `option()`.
+
+```js
+var argv = require('yargs')
+  .option('size', {
+    alias: 's',
+    describe: 'choose a size',
+    choices: ['xs', 's', 'm', 'l', 'xl']
+  })
+  .argv
+```
+
+<a name="coerce"></a>.coerce(key, fn)
+----------------
+
+Provide a synchronous function to coerce or transform the value(s) given on the
+command line for `key`.
+
+The coercion function should accept one argument, representing the parsed value
+from the command line, and should return a new value or throw an error. The
+returned value will be used as the value for `key` (or one of its aliases) in
+`argv`. If the function throws, the error will be treated as a validation
+failure, delegating to either a custom [`.fail()`](#fail) handler or printing
+the error message in the console.
+
+```js
+var argv = require('yargs')
+  .coerce('file', function (arg) {
+    return require('fs').readFileSync(arg, 'utf8')
+  })
+  .argv
+```
+
+Optionally `.coerce()` can take an object that maps several keys to their
+respective coercion function.
+
+```js
+var argv = require('yargs')
+  .coerce({
+    date: Date.parse,
+    json: JSON.parse
+  })
+  .argv
+```
+
+You can also map the same function to several keys at one time. Just pass an
+array of keys as the first argument to `.coerce()`:
+
+```js
+var path = require('path')
+var argv = require('yargs')
+  .coerce(['src', 'dest'], path.resolve)
+  .argv
+```
+
+.command(cmd, desc, [builder], [handler])
+-----------------------------------------
+.command(cmd, desc, [module])
+-----------------------------
+.command(module)
+----------------
+
+Document the commands exposed by your application.
+
+Use `desc` to provide a description for each command your application accepts (the
+values stored in `argv._`).  Set `desc` to `false` to create a hidden command.
+Hidden commands don't show up in the help output and aren't available for
+completion.
+
+Optionally, you can provide a `builder` object to give hints about the
+options that your command accepts:
+
+```js
+yargs.command('get', 'make a get HTTP request', {
+    url: {
+      alias: 'u',
+      default: 'http://yargs.js.org/'
+    }
+  })
+  .help()
+  .argv
+```
+
+Note that commands will not automatically inherit configuration _or_ options
+of their parent context. This means you'll have to re-apply configuration
+if necessary, and make options global manually using the [global](#global) method.
+
+Additionally, the [`help`](#help) and [`version`](#version)
+options (if used) **always** apply globally, just like the
+[`.wrap()`](#wrap) configuration.
+
+`builder` can also be a function. This function is executed
+with a `yargs` instance, and can be used to provide _advanced_ command specific help:
+
+```js
+yargs.command('get', 'make a get HTTP request', function (yargs) {
+    return yargs.option('url', {
+      alias: 'u',
+      default: 'http://yargs.js.org/'
+    })
+  })
+  .help()
+  .argv
+```
+
+You can also provide a handler function, which will be executed with the
+parsed `argv` object:
+
+```js
+yargs
+  .command(
+    'get',
+    'make a get HTTP request',
+    function (yargs) {
+      return yargs.option('u', {
+        alias: 'url',
+        describe: 'the URL to make an HTTP request to'
+      })
+    },
+    function (argv) {
+      console.log(argv.url)
+    }
+  )
+  .help()
+  .argv
+```
+
+### Positional Arguments
+
+Commands can accept _optional_ and _required_ positional arguments. Required
+positional arguments take the form `<foo>`, and optional arguments
+take the form `[bar]`. The parsed positional arguments will be populated in
+`argv`:
+
+```js
+yargs.command('get <source> [proxy]', 'make a get HTTP request')
+  .help()
+  .argv
+```
+
+#### Variadic Positional Arguments
+
+The last positional argument can optionally accept an array of
+values, by using the `..` operator:
+
+```js
+yargs.command('download <url> [files..]', 'download several files')
+  .help()
+  .argv
+```
+
+### Providing a Command Module
+
+For complicated commands you can pull the logic into a module. A module
+simply needs to export:
+
+* `exports.command`: string that executes this command when given on the command line, may contain positional args
+* `exports.describe`: string used as the description for the command in help text, use `false` for a hidden command
+* `exports.builder`: object declaring the options the command accepts, or a function accepting and returning a yargs instance
+* `exports.handler`: a function which will be passed the parsed argv.
+
+```js
+// my-module.js
+exports.command = 'get <source> [proxy]'
+
+exports.describe = 'make a get HTTP request'
+
+exports.builder = {
+  banana: {
+    default: 'cool'
+  },
+  batman: {
+    default: 'sad'
+  }
+}
+
+exports.handler = function (argv) {
+  // do something with argv.
+}
+```
+
+You then register the module like so:
+
+```js
+yargs.command(require('my-module'))
+  .help()
+  .argv
+```
+
+Or if the module does not export `command` and `describe` (or if you just want to override them):
+
+```js
+yargs.command('get <source> [proxy]', 'make a get HTTP request', require('my-module'))
+  .help()
+  .argv
+```
+
+.commandDir(directory, [opts])
+------------------------------
+
+Apply command modules from a directory relative to the module calling this method.
+
+This allows you to organize multiple commands into their own modules under a
+single directory and apply all of them at once instead of calling
+`.command(require('./dir/module'))` multiple times.
+
+By default, it ignores subdirectories. This is so you can use a directory
+structure to represent your command hierarchy, where each command applies its
+subcommands using this method in its builder function. See the example below.
+
+Note that yargs assumes all modules in the given directory are command modules
+and will error if non-command modules are encountered. In this scenario, you
+can either move your module to a different directory or use the `exclude` or
+`visit` option to manually filter it out. More on that below.
+
+`directory` is a relative directory path as a string (required).
+
+`opts` is an options object (optional). The following options are valid:
+
+- `recurse`: boolean, default `false`
+
+    Look for command modules in all subdirectories and apply them as a flattened
+    (non-hierarchical) list.
+
+- `extensions`: array of strings, default `['js']`
+
+    The types of files to look for when requiring command modules.
+
+- `visit`: function
+
+    A synchronous function called for each command module encountered. Accepts
+    `commandObject`, `pathToFile`, and `filename` as arguments. Returns
+    `commandObject` to include the command; any falsy value to exclude/skip it.
+
+- `include`: RegExp or function
+
+    Whitelist certain modules. See [`require-directory` whitelisting](https://www.npmjs.com/package/require-directory#whitelisting) for details.
+
+- `exclude`: RegExp or function
+
+    Blacklist certain modules. See [`require-directory` blacklisting](https://www.npmjs.com/package/require-directory#blacklisting) for details.
+
+### Example command hierarchy using `.commandDir()`
+
+Desired CLI:
+
+```sh
+$ myapp --help
+$ myapp init
+$ myapp remote --help
+$ myapp remote add base http://yargs.js.org
+$ myapp remote prune base
+$ myapp remote prune base fork whatever
+```
+
+Directory structure:
+
+```
+myapp/
+├─ cli.js
+└─ cmds/
+   ├─ init.js
+   ├─ remote.js
+   └─ remote_cmds/
+      ├─ add.js
+      └─ prune.js
+```
+
+cli.js:
+
+```js
+#!/usr/bin/env node
+require('yargs')
+  .commandDir('cmds')
+  .demand(1)
+  .help()
+  .argv
+```
+
+cmds/init.js:
+
+```js
+exports.command = 'init [dir]'
+exports.desc = 'Create an empty repo'
+exports.builder = {
+  dir: {
+    default: '.'
+  }
+}
+exports.handler = function (argv) {
+  console.log('init called for dir', argv.dir)
+}
+```
+
+cmds/remote.js:
+
+```js
+exports.command = 'remote <command>'
+exports.desc = 'Manage set of tracked repos'
+exports.builder = function (yargs) {
+  return yargs.commandDir('remote_cmds')
+}
+exports.handler = function (argv) {}
+```
+
+cmds/remote_cmds/add.js:
+
+```js
+exports.command = 'add <name> <url>'
+exports.desc = 'Add remote named <name> for repo at url <url>'
+exports.builder = {}
+exports.handler = function (argv) {
+  console.log('adding remote %s at url %s', argv.name, argv.url)
+}
+```
+
+cmds/remote_cmds/prune.js:
+
+```js
+exports.command = 'prune <name> [names..]'
+exports.desc = 'Delete tracked branches gone stale for remotes'
+exports.builder = {}
+exports.handler = function (argv) {
+  console.log('pruning remotes %s', [].concat(argv.name).concat(argv.names).join(', '))
+}
+```
+
+.completion([cmd], [description], [fn])
+---------------------------------------
+
+Enable bash-completion shortcuts for commands and options.
+
+`cmd`: When present in `argv._`, will result in the `.bashrc` completion script
+being outputted. To enable bash completions, concat the generated script to your
+`.bashrc` or `.bash_profile`.
+
+`description`: Provide a description in your usage instructions for the command
+that generates bash completion scripts.
+
+`fn`: Rather than relying on yargs' default completion functionality, which
+shiver me timbers is pretty awesome, you can provide your own completion
+method.
+
+If invoked without parameters, `.completion()` will make `completion` the command to output
+the completion script.
+
+```js
+var argv = require('yargs')
+  .completion('completion', function(current, argv) {
+    // 'current' is the current command being completed.
+    // 'argv' is the parsed arguments so far.
+    // simply return an array of completions.
+    return [
+      'foo',
+      'bar'
+    ];
+  })
+  .argv;
+```
+
+You can also provide asynchronous completions.
+
+```js
+var argv = require('yargs')
+  .completion('completion', function(current, argv, done) {
+    setTimeout(function() {
+      done([
+        'apple',
+        'banana'
+      ]);
+    }, 500);
+  })
+  .argv;
+```
+
+But wait, there's more! You can return an asynchronous promise.
+
+```js
+var argv = require('yargs')
+  .completion('completion', function(current, argv, done) {
+    return new Promise(function (resolve, reject) {
+      setTimeout(function () {
+        resolve(['apple', 'banana'])
+      }, 10)
+    })
+  })
+  .argv;
+```
+
+<a name="config"></a>.config([key], [description], [parseFn])
+-------------------------------------------------------------
+.config(object)
+---------------
+
+Tells the parser that if the option specified by `key` is passed in, it
+should be interpreted as a path to a JSON config file. The file is loaded
+and parsed, and its properties are set as arguments.
+
+If invoked without parameters, `.config()` will make `--config` the option to pass the JSON config file.
+
+An optional `description` can be provided to customize the config (`key`) option
+in the usage string.
+
+An optional `parseFn` can be used to provide a custom parser. The parsing
+function must be synchronous, and should return an object containing
+key value pairs or an error.
+
+```js
+var argv = require('yargs')
+  .config('settings', function (configPath) {
+    return JSON.parse(fs.readFileSync(configPath, 'utf-8'))
+  })
+  .argv
+```
+
+You can also pass an explicit configuration `object`, it will be parsed
+and its properties will be set as arguments.
+
+```js
+var argv = require('yargs')
+  .config({foo: 1, bar: 2})
+  .argv
+console.log(argv)
+```
+
+```
+$ node test.js
+{ _: [],
+  foo: 1,
+  bar: 2,
+  '$0': 'test.js' }
+```
+
+<a name="count"></a>.count(key)
+------------
+
+Interpret `key` as a boolean flag, but set its parsed value to the number of
+flag occurrences rather than `true` or `false`. Default value is thus `0`.
+
+<a name="default"></a>.default(key, value, [description])
+---------------------------------------------------------
+.defaults(key, value, [description])
+------------------------------------
+
+**Note:** The `.defaults()` alias is deprecated. It will be
+removed in the next major version.
+
+Set `argv[key]` to `value` if no option was specified in `process.argv`.
+
+Optionally `.default()` can take an object that maps keys to default values.
+
+But wait, there's more! The default value can be a `function` which returns
+a value. The name of the function will be used in the usage string:
+
+```js
+var argv = require('yargs')
+  .default('random', function randomValue() {
+    return Math.random() * 256;
+  }).argv;
+```
+
+Optionally, `description` can also be provided and will take precedence over
+displaying the value in the usage instructions:
+
+```js
+.default('timeout', 60000, '(one-minute)')
+```
+
+<a name="demand"></a>.demand(key, [msg | boolean])
+------------------------------
+.demand(count, [max], [msg])
+------------------------------
+
+If `key` is a string, show the usage information and exit if `key` wasn't
+specified in `process.argv`.
+
+If `key` is a number, demand at least as many non-option arguments, which show
+up in `argv._`. A second number can also optionally be provided, which indicates
+the maximum number of non-option arguments.
+
+If `key` is an array, demand each element.
+
+If a `msg` string is given, it will be printed when the argument is missing,
+instead of the standard error message. This is especially helpful for the non-option arguments in `argv._`.
+
+If a `boolean` value is given, it controls whether the option is demanded;
+this is useful when using `.options()` to specify command line parameters.
+
+A combination of `.demand(1)` and `.strict()` will allow you to require a user to pass at least one command:
+
+```js
+var argv = require('yargs')
+  .command('install', 'tis a mighty fine package to install')
+  .demand(1)
+  .strict()
+  .argv
+```
+
+Similarly, you can require a command and arguments at the same time:
+
+```js
+var argv = require('yargs')
+  .command('install', 'tis a mighty fine package to install')
+  .demand(1, ['w', 'm'])
+  .strict()
+  .argv
+```
+
+<a name="describe"></a>.describe(key, desc)
+--------------------
+
+Describe a `key` for the generated usage information.
+
+Optionally `.describe()` can take an object that maps keys to descriptions.
+
+.detectLocale(boolean)
+-----------
+
+Should yargs attempt to detect the os' locale? Defaults to `true`.
+
+.env([prefix])
+--------------
+
+Tell yargs to parse environment variables matching the given prefix and apply
+them to argv as though they were command line arguments.
+
+Use the "__" separator in the environment variable to indicate nested options.
+(e.g. prefix_nested__foo => nested.foo)
+
+If this method is called with no argument or with an empty string or with `true`,
+then all env vars will be applied to argv.
+
+Program arguments are defined in this order of precedence:
+
+1. Command line args
+2. Config file
+3. Env var
+4. Configured defaults
+
+```js
+var argv = require('yargs')
+  .env('MY_PROGRAM')
+  .option('f', {
+    alias: 'fruit-thing',
+    default: 'apple'
+  })
+  .argv
+console.log(argv)
+```
+
+```
+$ node fruity.js
+{ _: [],
+  f: 'apple',
+  'fruit-thing': 'apple',
+  fruitThing: 'apple',
+  '$0': 'fruity.js' }
+```
+
+```
+$ MY_PROGRAM_FRUIT_THING=banana node fruity.js
+{ _: [],
+  fruitThing: 'banana',
+  f: 'banana',
+  'fruit-thing': 'banana',
+  '$0': 'fruity.js' }
+```
+
+```
+$ MY_PROGRAM_FRUIT_THING=banana node fruity.js -f cat
+{ _: [],
+  f: 'cat',
+  'fruit-thing': 'cat',
+  fruitThing: 'cat',
+  '$0': 'fruity.js' }
+```
+
+Env var parsing is disabled by default, but you can also explicitly disable it
+by calling `.env(false)`, e.g. if you need to undo previous configuration.
+
+.epilog(str)
+------------
+.epilogue(str)
+--------------
+
+A message to print at the end of the usage instructions, e.g.
+
+```js
+var argv = require('yargs')
+  .epilogue('for more information, find our manual at http://example.com');
+```
+
+.example(cmd, desc)
+-------------------
+
+Give some example invocations of your program. Inside `cmd`, the string
+`$0` will get interpolated to the current script name or node command for the
+present script similar to how `$0` works in bash or perl.
+Examples will be printed out as part of the help message.
+
+.exitProcess(enable)
+----------------------------------
+
+By default, yargs exits the process when the user passes a help flag, uses the
+`.version` functionality, or when validation fails. Calling
+`.exitProcess(false)` disables this behavior, enabling further actions after
+yargs have been validated.
+
+<a name="fail"></a>.fail(fn)
+---------
+
+Method to execute when a failure occurs, rather than printing the failure message.
+
+`fn` is called with the failure message that would have been printed and the
+`Error` instance originally thrown, if any.
+
+```js
+var argv = require('yargs')
+  .fail(function (msg, err) {
+    if (err) throw err // preserve stack
+    console.error('You broke it!')
+    console.error(msg)
+    process.exit(1)
+  })
+  .argv
+```
+
+.getCompletion(args, done);
+---------------------------
+
+Allows to programmatically get completion choices for any line.
+
+`args`: An array of the words in the command line to complete.
+
+`done`: The callback to be called with the resulting completions.
+
+For example:
+
+```js
+require('yargs')
+  .option('foobar', {})
+  .option('foobaz', {})
+  .completion()
+  .getCompletion(['./test.js', '--foo'], function (completions) {
+    console.log(completions)
+  })
+```
+
+Outputs the same completion choices as `./test.js --foo`<kbd>TAB</kbd>: `--foobar` and `--foobaz`
+
+<a name="global"></a>.global(globals)
+------------
+
+Indicate that an option (or group of options) should not be reset when a command
+is executed, as an example:
+
+```js
+var argv = require('yargs')
+  .option('a', {
+    alias: 'all',
+    default: true
+  })
+  .option('n', {
+    alias: 'none',
+    default: true
+  })
+  .command('foo', 'foo command', function (yargs) {
+    return yargs.option('b', {
+      alias: 'bar'
+    })
+  })
+  .help('help')
+  .global('a')
+  .argv
+```
+
+If the `foo` command is executed the `all` option will remain, but the `none`
+option will have been eliminated.
+
+`help`, `version`, and `completion` options default to being global.
+
+<a name="group"></a>.group(key(s), groupName)
+--------------------
+
+Given a key, or an array of keys, places options under an alternative heading
+when displaying usage instructions, e.g.,
+
+```js
+var yargs = require('yargs')(['--help'])
+  .help()
+  .group('batman', 'Heroes:')
+  .describe('batman', "world's greatest detective")
+  .wrap(null)
+  .argv
+```
+***
+    Heroes:
+      --batman  world's greatest detective
+
+    Options:
+      --help  Show help  [boolean]
+
+<a name="help"></a>.help()
+-----------------------------------------
+.help([option | boolean])
+-----------------------------------------
+.help([option, [description | boolean]])
+-----------------------------------------
+.help([option, [description, [boolean]]])
+-----------------------------------------
+
+Add an option (e.g. `--help`) and implicit command that displays the usage
+string and exits the process.
+
+If present, the `description` parameter customizes the description of
+the help option in the usage string.
+
+If a boolean argument is provided, it will enable or disable the use of an
+implicit command. The implicit command is enabled by default, but it can be
+disabled by passing `false`.
+
+Note that any multi-char aliases (e.g. `help`) used for the help option will
+also be used for the implicit command. If there are no multi-char aliases (e.g.
+`h`), then all single-char aliases will be used for the command.
+
+If invoked without parameters, `.help()` will use `--help` as the option and
+`help` as the implicit command to trigger help output.
+
+Example:
+
+```js
+var yargs = require("yargs")(['--help'])
+  .usage("$0 -operand1 number -operand2 number -operation [add|subtract]")
+  .help()
+  .argv
+```
+
+Later on, `argv` can be retrieved with `yargs.argv`.
+
+.implies(x, y)
+--------------
+
+Given the key `x` is set, it is required that the key `y` is set.
+
+Optionally `.implies()` can accept an object specifying multiple implications.
+
+.locale()
+---------
+
+Return the locale that yargs is currently using.
+
+By default, yargs will auto-detect the operating system's locale so that
+yargs-generated help content will display in the user's language.
+
+To override this behavior with a static locale, pass the desired locale as a
+string to this method (see below).
+
+.locale(locale)
+---------------
+
+Override the auto-detected locale from the user's operating system with a static
+locale. Note that the OS locale can be modified by setting/exporting the `LC_ALL`
+environment variable.
+
+```js
+var argv = require('yargs')
+  .usage('./$0 - follow ye instructions true')
+  .option('option', {
+    alias: 'o',
+    describe: "'tis a mighty fine option",
+    demand: true
+  })
+  .command('run', "Arrr, ya best be knowin' what yer doin'")
+  .example('$0 run foo', "shiver me timbers, here's an example for ye")
+  .help('help')
+  .wrap(70)
+  .locale('pirate')
+  .argv
+```
+
+***
+
+```shell
+./test.js - follow ye instructions true
+
+Choose yer command:
+  run  Arrr, ya best be knowin' what yer doin'
+
+Options for me hearties!
+  --option, -o  'tis a mighty fine option               [requi-yar-ed]
+  --help        Parlay this here code of conduct             [boolean]
+
+Ex. marks the spot:
+  test.js run foo  shiver me timbers, here's an example for ye
+
+Ye be havin' to set the followin' argument land lubber: option
+```
+
+Locales currently supported:
+
+* **de:** German.
+* **en:** American English.
+* **es:** Spanish.
+* **fr:** French.
+* **id:** Indonesian.
+* **it:** Italian.
+* **ja:** Japanese.
+* **ko:** Korean.
+* **nb:** Norwegian Bokmål.
+* **pirate:** American Pirate.
+* **pl:** Polish.
+* **pt:** Portuguese.
+* **pt_BR:** Brazilian Portuguese.
+* **tr:** Turkish.
+* **zh:** Chinese.
+
+To submit a new translation for yargs:
+
+1. use `./locales/en.json` as a starting point.
+2. submit a pull request with the new locale file.
+
+*The [Microsoft Terminology Search](http://www.microsoft.com/Language/en-US/Search.aspx) can be useful for finding the correct terminology in your locale.*
+
+<a name="nargs"></a>.nargs(key, count)
+-----------
+
+The number of arguments that should be consumed after a key. This can be a
+useful hint to prevent parsing ambiguity. For example:
+
+```js
+var argv = require('yargs')
+  .nargs('token', 1)
+  .parse(['--token', '-my-token']);
+```
+
+parses as:
+
+`{ _: [], token: '-my-token', '$0': 'node test' }`
+
+Optionally `.nargs()` can take an object of `key`/`narg` pairs.
+
+<a name="normalize"></a>.normalize(key)
+---------------
+
+The key provided represents a path and should have `path.normalize()` applied.
+
+<a name="number"></a>.number(key)
+------------
+
+Tell the parser to always interpret `key` as a number.
+
+If `key` is an array, all elements will be parsed as numbers.
+
+If the option is given on the command line without a value, `argv` will be
+populated with `undefined`.
+
+If the value given on the command line cannot be parsed as a number, `argv` will
+be populated with `NaN`.
+
+Note that decimals, hexadecimals, and scientific notation are all accepted.
+
+```js
+var argv = require('yargs')
+  .number('n')
+  .number(['width', 'height'])
+  .argv
+```
+
+.option(key, opt)
+-----------------
+.options(key, opt)
+------------------
+
+Instead of chaining together `.alias().demand().default().describe().string()`, you can specify
+keys in `opt` for each of the chainable methods.
+
+For example:
+
+````javascript
+var argv = require('yargs')
+    .option('f', {
+        alias: 'file',
+        demand: true,
+        default: '/etc/passwd',
+        describe: 'x marks the spot',
+        type: 'string'
+    })
+    .argv
+;
+````
+
+is the same as
+
+````javascript
+var argv = require('yargs')
+    .alias('f', 'file')
+    .demand('f')
+    .default('f', '/etc/passwd')
+    .describe('f', 'x marks the spot')
+    .string('f')
+    .argv
+;
+````
+
+Optionally `.options()` can take an object that maps keys to `opt` parameters.
+
+````javascript
+var argv = require('yargs')
+    .options({
+      'f': {
+        alias: 'file',
+        demand: true,
+        default: '/etc/passwd',
+        describe: 'x marks the spot',
+        type: 'string'
+      }
+    })
+    .argv
+;
+````
+
+Valid `opt` keys include:
+
+- `alias`: string or array of strings, alias(es) for the canonical option key, see [`alias()`](#alias)
+- `array`: boolean, interpret option as an array, see [`array()`](#array)
+- `boolean`: boolean, interpret option as a boolean flag, see [`boolean()`](#boolean)
+- `choices`: value or array of values, limit valid option arguments to a predefined set, see [`choices()`](#choices)
+- `coerce`: function, coerce or transform parsed command line values into another value, see [`coerce()`](#coerce)
+- `config`: boolean, interpret option as a path to a JSON config file, see [`config()`](#config)
+- `configParser`: function, provide a custom config parsing function, see [`config()`](#config)
+- `count`: boolean, interpret option as a count of boolean flags, see [`count()`](#count)
+- `default`: value, set a default value for the option, see [`default()`](#default)
+- `defaultDescription`: string, use this description for the default value in help content, see [`default()`](#default)
+- `demand`/`require`/`required`: boolean or string, demand the option be given, with optional error message, see [`demand()`](#demand)
+- `desc`/`describe`/`description`: string, the option description for help content, see [`describe()`](#describe)
+- `global`: boolean, indicate that this key should not be [reset](#reset) when a command is invoked, see [`global()`](#global)
+- `group`: string, when displaying usage instructions place the option under an alternative group heading, see [`group()`](#group)
+- `nargs`: number, specify how many arguments should be consumed for the option, see [`nargs()`](#nargs)
+- `normalize`: boolean, apply `path.normalize()` to the option, see [`normalize()`](#normalize)
+- `number`: boolean, interpret option as a number, [`number()`](#number)
+- `requiresArg`: boolean, require the option be specified with a value, see [`requiresArg()`](#requiresArg)
+- `skipValidation`: boolean, skips validation if the option is present, see [`skipValidation()`](#skipValidation)
+- `string`: boolean, interpret option as a string, see [`string()`](#string)
+- `type`: one of the following strings
+    - `'array'`: synonymous for `array: true`, see [`array()`](#array)
+    - `'boolean'`: synonymous for `boolean: true`, see [`boolean()`](#boolean)
+    - `'count'`: synonymous for `count: true`, see [`count()`](#count)
+    - `'number'`: synonymous for `number: true`, see [`number()`](#number)
+    - `'string'`: synonymous for `string: true`, see [`string()`](#string)
+
+.parse(args)
+------------
+
+Parse `args` instead of `process.argv`. Returns the `argv` object.
+
+`args` may either be a pre-processed argv array, or a raw argument string.
+
+.pkgConf(key, [cwd])
+------------
+
+Similar to [`config()`](#config), indicates that yargs should interpret the object from the specified key in package.json
+as a configuration object.
+
+`cwd` can optionally be provided, the package.json will be read
+from this location.
+
+.recommendCommands()
+---------------------------
+
+Should yargs provide suggestions regarding similar commands if no matching
+command is found?
+
+.require(key, [msg | boolean])
+------------------------------
+.required(key, [msg | boolean])
+------------------------------
+
+An alias for [`demand()`](#demand). See docs there.
+
+<a name="requiresArg"></a>.requiresArg(key)
+-----------------
+
+Specifies either a single option key (string), or an array of options that
+must be followed by option values. If any option value is missing, show the
+usage information and exit.
+
+The default behavior is to set the value of any key not followed by an
+option value to `true`.
+
+<a name="reset"></a>.reset()
+--------
+
+Reset the argument object built up so far. This is useful for
+creating nested command line interfaces. Use [global](#global)
+to specify keys that should not be reset.
+
+```js
+var yargs = require('yargs')
+  .usage('$0 command')
+  .command('hello', 'hello command')
+  .command('world', 'world command')
+  .demand(1, 'must provide a valid command'),
+  argv = yargs.argv,
+  command = argv._[0];
+
+if (command === 'hello') {
+  yargs.reset()
+    .usage('$0 hello')
+    .help('h')
+    .example('$0 hello', 'print the hello message!')
+    .argv
+
+  console.log('hello!');
+} else if (command === 'world'){
+  yargs.reset()
+    .usage('$0 world')
+    .help('h')
+    .example('$0 world', 'print the world message!')
+    .argv
+
+  console.log('world!');
+} else {
+  yargs.showHelp();
+}
+```
+
+.showCompletionScript()
+----------------------
+
+Generate a bash completion script. Users of your application can install this
+script in their `.bashrc`, and yargs will provide completion shortcuts for
+commands and options.
+
+.showHelp(consoleLevel='error')
+---------------------------
+
+Print the usage data using the [`console`](https://nodejs.org/api/console.html) function `consoleLevel` for printing.
+
+Example:
+
+```js
+var yargs = require("yargs")
+  .usage("$0 -operand1 number -operand2 number -operation [add|subtract]");
+yargs.showHelp(); //prints to stderr using console.error()
+```
+
+Or, to print the usage data to `stdout` instead, you can specify the use of `console.log`:
+
+```js
+yargs.showHelp("log"); //prints to stdout using console.log()
+```
+
+Later on, `argv` can be retrieved with `yargs.argv`.
+
+.showHelpOnFail(enable, [message])
+----------------------------------
+
+By default, yargs outputs a usage string if any error is detected. Use the
+`.showHelpOnFail()` method to customize this behavior. If `enable` is `false`,
+the usage string is not output. If the `message` parameter is present, this
+message is output after the error message.
+
+line_count.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('yargs')
+    .usage('Count the lines in a file.\nUsage: $0 -f <file>')
+    .demand('f')
+    .alias('f', 'file')
+    .describe('f', 'Load a file')
+    .string('f')
+    .showHelpOnFail(false, 'Specify --help for available options')
+    .help('help')
+    .argv;
+
+// etc.
+````
+
+***
+
+```
+$ node line_count.js
+Missing argument value: f
+
+Specify --help for available options
+```
+
+<a name="skipValidation"></a>.skipValidation(key)
+-----------------
+
+Specifies either a single option key (string), or an array of options.
+If any of the options is present, yargs validation is skipped.
+
+.strict()
+---------
+
+Any command-line argument given that is not demanded, or does not have a
+corresponding description, will be reported as an error.
+
+<a name="string"></a>.string(key)
+------------
+
+Tell the parser logic not to interpret `key` as a number or boolean.
+This can be useful if you need to preserve leading zeros in an input.
+
+If `key` is an array, interpret all the elements as strings.
+
+`.string('_')` will result in non-hyphenated arguments being interpreted as strings,
+regardless of whether they resemble numbers.
+
+.updateLocale(obj)
+------------------
+.updateStrings(obj)
+------------------
+
+Override the default strings used by yargs with the key/value
+pairs provided in `obj`:
+
+```js
+var argv = require('yargs')
+  .command('run', 'the run command')
+  .help('help')
+  .updateStrings({
+    'Commands:': 'My Commands -->\n'
+  })
+  .wrap(null)
+  .argv
+```
+
+***
+
+```shell
+My Commands -->
+
+  run  the run command
+
+Options:
+  --help  Show help  [boolean]
+```
+
+If you explicitly specify a `locale()`, you should do so *before* calling
+`updateStrings()`.
+
+.usage(message, [opts])
+---------------------
+
+Set a usage message to show which commands to use. Inside `message`, the string
+`$0` will get interpolated to the current script name or node command for the
+present script similar to how `$0` works in bash or perl.
+
+`opts` is optional and acts like calling `.options(opts)`.
+
+<a name="version"></a>.version([option], [description], [version])
+----------------------------------------
+
+Add an option (e.g. `--version`) that displays the version number (given by the
+`version` parameter) and exits the process.
+
+If no arguments are passed to `version` (`.version()`), yargs will parse the `package.json`
+of your module and use its `version` value. The default value of `option` is `--version`.
+
+You can provide a `function` for version, rather than a string.
+This is useful if you want to use a version stored in a location other than package.json:
+
+```js
+var argv = require('yargs')
+  .version(function() {
+    return require('../lib/version').version;
+  })
+  .argv;
+```
+
+<a name="wrap"></a>.wrap(columns)
+--------------
+
+Format usage output to wrap at `columns` many columns.
+
+By default wrap will be set to `Math.min(80, windowWidth)`. Use `.wrap(null)` to
+specify no column limit (no right-align). Use `.wrap(yargs.terminalWidth())` to
+maximize the width of yargs' usage instructions.
+
+parsing tricks
+==============
+
+stop parsing
+------------
+
+Use `--` to stop parsing flags and stuff the remainder into `argv._`.
+
+    $ node examples/reflect.js -a 1 -b 2 -- -c 3 -d 4
+    { _: [ '-c', '3', '-d', '4' ],
+      a: 1,
+      b: 2,
+      '$0': 'examples/reflect.js' }
+
+negate fields
+-------------
+
+If you want to explicitly set a field to false instead of just leaving it
+undefined or to override a default you can do `--no-key`.
+
+    $ node examples/reflect.js -a --no-b
+    { _: [], a: true, b: false, '$0': 'examples/reflect.js' }
+
+numbers
+-------
+
+Every argument that looks like a number (`!isNaN(Number(arg))`) is converted to
+one. This way you can just `net.createConnection(argv.port)` and you can add
+numbers out of `argv` with `+` without having that mean concatenation,
+which is super frustrating.
+
+duplicates
+----------
+
+If you specify a flag multiple times it will get turned into an array containing
+all the values in order.
+
+    $ node examples/reflect.js -x 5 -x 8 -x 0
+    { _: [], x: [ 5, 8, 0 ], '$0': 'examples/reflect.js' }
+
+dot notation
+------------
+
+When you use dots (`.`s) in argument names, an implicit object path is assumed.
+This lets you organize arguments into nested objects.
+
+    $ node examples/reflect.js --foo.bar.baz=33 --foo.quux=5
+    { _: [],
+      foo: { bar: { baz: 33 }, quux: 5 },
+      '$0': 'examples/reflect.js' }
+
+short numbers
+-------------
+
+Short numeric `-n5` style arguments work too:
+
+    $ node examples/reflect.js -n123 -m456
+    { _: [], n: 123, m: 456, '$0': 'examples/reflect.js' }
+
+installation
+============
+
+With [npm](https://github.com/npm/npm), just do:
+
+    npm install yargs
+
+or clone this project on github:
+
+    git clone http://github.com/yargs/yargs.git
+
+To run the tests with npm, just do:
+
+    npm test
+
+configuration
+=============
+
+Using the `yargs` stanza in your `package.json` you can turn on and off
+some of yargs' parsing features:
+
+```json
+{
+  "yargs": {
+    "short-option-groups": true,
+    "camel-case-expansion": true,
+    "dot-notation": true,
+    "parse-numbers": true,
+    "boolean-negation": true
+  }
+}
+```
+
+See the [yargs-parser](https://github.com/yargs/yargs-parser#configuration) module
+for detailed documentation of this feature.
+
+inspired by
+===========
+
+This module is loosely inspired by Perl's
+[Getopt::Casual](http://search.cpan.org/~photo/Getopt-Casual-0.13.1/Casual.pm).
+
+[travis-url]: https://travis-ci.org/yargs/yargs
+[travis-image]: https://img.shields.io/travis/yargs/yargs/master.svg
+[coveralls-url]: https://coveralls.io/github/yargs/yargs
+[coveralls-image]: https://img.shields.io/coveralls/yargs/yargs.svg
+[npm-url]: https://www.npmjs.com/package/yargs
+[npm-image]: https://img.shields.io/npm/v/yargs.svg
+[windows-url]: https://ci.appveyor.com/project/bcoe/yargs-ljwvf
+[windows-image]: https://img.shields.io/appveyor/ci/bcoe/yargs-ljwvf/master.svg?label=Windows%20Tests
+[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg
+[standard-url]: http://standardjs.com/
+[standard-version-image]: https://img.shields.io/badge/release-standard%20version-brightgreen.svg
+[standard-version-url]: https://github.com/conventional-changelog/standard-version
+[gitter-image]: https://img.shields.io/gitter/room/nwjs/nw.js.svg?maxAge=2592000
+[gitter-url]: https://gitter.im/yargs/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link
diff --git a/server/node_modules/yargs/completion.sh.hbs b/server/node_modules/yargs/completion.sh.hbs
new file mode 100644
index 0000000000000000000000000000000000000000..14445b834e675ec0bba926acdc3f380456757343
--- /dev/null
+++ b/server/node_modules/yargs/completion.sh.hbs
@@ -0,0 +1,28 @@
+###-begin-{{app_name}}-completions-###
+#
+# yargs command completion script
+#
+# Installation: {{app_path}} completion >> ~/.bashrc
+#    or {{app_path}} completion >> ~/.bash_profile on OSX.
+#
+_yargs_completions()
+{
+    local cur_word args type_list
+
+    cur_word="${COMP_WORDS[COMP_CWORD]}"
+    args=("${COMP_WORDS[@]}")
+
+    # ask yargs to generate completions.
+    type_list=$({{app_path}} --get-yargs-completions "${args[@]}")
+
+    COMPREPLY=( $(compgen -W "${type_list}" -- ${cur_word}) )
+
+    # if no match was found, fall back to filename completion
+    if [ ${#COMPREPLY[@]} -eq 0 ]; then
+      COMPREPLY=( $(compgen -f -- "${cur_word}" ) )
+    fi
+
+    return 0
+}
+complete -F _yargs_completions {{app_name}}
+###-end-{{app_name}}-completions-###
diff --git a/server/node_modules/yargs/index.js b/server/node_modules/yargs/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..37450cf7a6a494c76f82fabd96084fe9d7a7efea
--- /dev/null
+++ b/server/node_modules/yargs/index.js
@@ -0,0 +1,31 @@
+// classic singleton yargs API, to use yargs
+// without running as a singleton do:
+// require('yargs/yargs')(process.argv.slice(2))
+const yargs = require('./yargs')
+
+Argv(process.argv.slice(2))
+
+module.exports = Argv
+
+function Argv (processArgs, cwd) {
+  const argv = yargs(processArgs, cwd, require)
+  singletonify(argv)
+  return argv
+}
+
+/*  Hack an instance of Argv with process.argv into Argv
+    so people can do
+    require('yargs')(['--beeble=1','-z','zizzle']).argv
+    to parse a list of args and
+    require('yargs').argv
+    to get a parsed version of process.argv.
+*/
+function singletonify (inst) {
+  Object.keys(inst).forEach(function (key) {
+    if (key === 'argv') {
+      Argv.__defineGetter__(key, inst.__lookupGetter__(key))
+    } else {
+      Argv[key] = typeof inst[key] === 'function' ? inst[key].bind(inst) : inst[key]
+    }
+  })
+}
diff --git a/server/node_modules/yargs/lib/command.js b/server/node_modules/yargs/lib/command.js
new file mode 100644
index 0000000000000000000000000000000000000000..f56bbfafc4418089d007f9793accfe963852c3f2
--- /dev/null
+++ b/server/node_modules/yargs/lib/command.js
@@ -0,0 +1,210 @@
+const path = require('path')
+const inspect = require('util').inspect
+
+// handles parsing positional arguments,
+// and populating argv with said positional
+// arguments.
+module.exports = function (yargs, usage, validation) {
+  const self = {}
+
+  var handlers = {}
+  self.addHandler = function (cmd, description, builder, handler) {
+    if (typeof cmd === 'object') {
+      const commandString = typeof cmd.command === 'string' ? cmd.command : moduleName(cmd)
+      self.addHandler(commandString, extractDesc(cmd), cmd.builder, cmd.handler)
+      return
+    }
+
+    // allow a module to be provided instead of separate builder and handler
+    if (typeof builder === 'object' && builder.builder && typeof builder.handler === 'function') {
+      self.addHandler(cmd, description, builder.builder, builder.handler)
+      return
+    }
+
+    if (description !== false) {
+      usage.command(cmd, description)
+    }
+
+    // we should not register a handler if no
+    // builder is provided, e.g., user will
+    // handle command themselves with '_'.
+    var parsedCommand = parseCommand(cmd)
+    handlers[parsedCommand.cmd] = {
+      original: cmd,
+      handler: handler,
+      builder: builder || {},
+      demanded: parsedCommand.demanded,
+      optional: parsedCommand.optional
+    }
+  }
+
+  self.addDirectory = function (dir, context, req, callerFile, opts) {
+    opts = opts || {}
+    // disable recursion to support nested directories of subcommands
+    if (typeof opts.recurse !== 'boolean') opts.recurse = false
+    // exclude 'json', 'coffee' from require-directory defaults
+    if (!Array.isArray(opts.extensions)) opts.extensions = ['js']
+    // allow consumer to define their own visitor function
+    const parentVisit = typeof opts.visit === 'function' ? opts.visit : function (o) { return o }
+    // call addHandler via visitor function
+    opts.visit = function (obj, joined, filename) {
+      const visited = parentVisit(obj, joined, filename)
+      // allow consumer to skip modules with their own visitor
+      if (visited) {
+        // check for cyclic reference
+        // each command file path should only be seen once per execution
+        if (~context.files.indexOf(joined)) return visited
+        // keep track of visited files in context.files
+        context.files.push(joined)
+        self.addHandler(visited)
+      }
+      return visited
+    }
+    require('require-directory')({ require: req, filename: callerFile }, dir, opts)
+  }
+
+  // lookup module object from require()d command and derive name
+  // if module was not require()d and no name given, throw error
+  function moduleName (obj) {
+    const mod = require('which-module')(obj)
+    if (!mod) throw new Error('No command name given for module: ' + inspect(obj))
+    return commandFromFilename(mod.filename)
+  }
+
+  // derive command name from filename
+  function commandFromFilename (filename) {
+    return path.basename(filename, path.extname(filename))
+  }
+
+  function extractDesc (obj) {
+    for (var keys = ['describe', 'description', 'desc'], i = 0, l = keys.length, test; i < l; i++) {
+      test = obj[keys[i]]
+      if (typeof test === 'string' || typeof test === 'boolean') return test
+    }
+    return false
+  }
+
+  function parseCommand (cmd) {
+    var splitCommand = cmd.split(/\s/)
+    var bregex = /\.*[\][<>]/g
+    var parsedCommand = {
+      cmd: (splitCommand.shift()).replace(bregex, ''),
+      demanded: [],
+      optional: []
+    }
+    splitCommand.forEach(function (cmd, i) {
+      var variadic = false
+      if (/\.+[\]>]/.test(cmd) && i === splitCommand.length - 1) variadic = true
+      if (/^\[/.test(cmd)) {
+        parsedCommand.optional.push({
+          cmd: cmd.replace(bregex, ''),
+          variadic: variadic
+        })
+      } else {
+        parsedCommand.demanded.push({
+          cmd: cmd.replace(bregex, ''),
+          variadic: variadic
+        })
+      }
+    })
+    return parsedCommand
+  }
+
+  self.getCommands = function () {
+    return Object.keys(handlers)
+  }
+
+  self.getCommandHandlers = function () {
+    return handlers
+  }
+
+  self.runCommand = function (command, yargs, parsed) {
+    var argv = parsed.argv
+    var commandHandler = handlers[command]
+    var innerArgv = argv
+    var currentContext = yargs.getContext()
+    var parentCommands = currentContext.commands.slice()
+    currentContext.commands.push(command)
+    if (typeof commandHandler.builder === 'function') {
+      // a function can be provided, which builds
+      // up a yargs chain and possibly returns it.
+      innerArgv = commandHandler.builder(yargs.reset(parsed.aliases))
+      // if the builder function did not yet parse argv with reset yargs
+      // and did not explicitly set a usage() string, then apply the
+      // original command string as usage() for consistent behavior with
+      // options object below
+      if (yargs.parsed === false) {
+        if (typeof yargs.getUsageInstance().getUsage() === 'undefined') {
+          yargs.usage('$0 ' + (parentCommands.length ? parentCommands.join(' ') + ' ' : '') + commandHandler.original)
+        }
+        innerArgv = innerArgv ? innerArgv.argv : yargs.argv
+      } else {
+        innerArgv = yargs.parsed.argv
+      }
+    } else if (typeof commandHandler.builder === 'object') {
+      // as a short hand, an object can instead be provided, specifying
+      // the options that a command takes.
+      innerArgv = yargs.reset(parsed.aliases)
+      innerArgv.usage('$0 ' + (parentCommands.length ? parentCommands.join(' ') + ' ' : '') + commandHandler.original)
+      Object.keys(commandHandler.builder).forEach(function (key) {
+        innerArgv.option(key, commandHandler.builder[key])
+      })
+      innerArgv = innerArgv.argv
+    }
+
+    populatePositional(commandHandler, innerArgv, currentContext, yargs)
+
+    if (commandHandler.handler) {
+      commandHandler.handler(innerArgv)
+    }
+    currentContext.commands.pop()
+    return innerArgv
+  }
+
+  function populatePositional (commandHandler, argv, context, yargs) {
+    argv._ = argv._.slice(context.commands.length) // nuke the current commands
+    var demanded = commandHandler.demanded.slice(0)
+    var optional = commandHandler.optional.slice(0)
+
+    validation.positionalCount(demanded.length, argv._.length)
+
+    while (demanded.length) {
+      var demand = demanded.shift()
+      if (demand.variadic) argv[demand.cmd] = []
+      if (!argv._.length) break
+      if (demand.variadic) argv[demand.cmd] = argv._.splice(0)
+      else argv[demand.cmd] = argv._.shift()
+      postProcessPositional(yargs, argv, demand.cmd)
+    }
+
+    while (optional.length) {
+      var maybe = optional.shift()
+      if (maybe.variadic) argv[maybe.cmd] = []
+      if (!argv._.length) break
+      if (maybe.variadic) argv[maybe.cmd] = argv._.splice(0)
+      else argv[maybe.cmd] = argv._.shift()
+      postProcessPositional(yargs, argv, maybe.cmd)
+    }
+
+    argv._ = context.commands.concat(argv._)
+  }
+
+  // TODO move positional arg logic to yargs-parser and remove this duplication
+  function postProcessPositional (yargs, argv, key) {
+    var coerce = yargs.getOptions().coerce[key]
+    if (typeof coerce === 'function') {
+      try {
+        argv[key] = coerce(argv[key])
+      } catch (err) {
+        yargs.getUsageInstance().fail(err.message, err)
+      }
+    }
+  }
+
+  self.reset = function () {
+    handlers = {}
+    return self
+  }
+
+  return self
+}
diff --git a/server/node_modules/yargs/lib/completion.js b/server/node_modules/yargs/lib/completion.js
new file mode 100644
index 0000000000000000000000000000000000000000..93a936cf6df47ddd04598dca975b059d627a330e
--- /dev/null
+++ b/server/node_modules/yargs/lib/completion.js
@@ -0,0 +1,99 @@
+const fs = require('fs')
+const path = require('path')
+
+// add bash completions to your
+//  yargs-powered applications.
+module.exports = function (yargs, usage, command) {
+  const self = {
+    completionKey: 'get-yargs-completions'
+  }
+
+  // get a list of completion commands.
+  // 'args' is the array of strings from the line to be completed
+  self.getCompletion = function (args, done) {
+    const completions = []
+    const current = args.length ? args[args.length - 1] : ''
+    const argv = yargs.parse(args, true)
+    const aliases = yargs.parsed.aliases
+
+    // a custom completion function can be provided
+    // to completion().
+    if (completionFunction) {
+      if (completionFunction.length < 3) {
+        var result = completionFunction(current, argv)
+
+        // promise based completion function.
+        if (typeof result.then === 'function') {
+          return result.then(function (list) {
+            process.nextTick(function () { done(list) })
+          }).catch(function (err) {
+            process.nextTick(function () { throw err })
+          })
+        }
+
+        // synchronous completion function.
+        return done(result)
+      } else {
+        // asynchronous completion function
+        return completionFunction(current, argv, function (completions) {
+          done(completions)
+        })
+      }
+    }
+
+    var handlers = command.getCommandHandlers()
+    for (var i = 0, ii = args.length; i < ii; ++i) {
+      if (handlers[args[i]] && handlers[args[i]].builder) {
+        return handlers[args[i]].builder(yargs.reset()).argv
+      }
+    }
+
+    if (!current.match(/^-/)) {
+      usage.getCommands().forEach(function (command) {
+        if (args.indexOf(command[0]) === -1) {
+          completions.push(command[0])
+        }
+      })
+    }
+
+    if (current.match(/^-/)) {
+      Object.keys(yargs.getOptions().key).forEach(function (key) {
+        // If the key and its aliases aren't in 'args', add the key to 'completions'
+        var keyAndAliases = [key].concat(aliases[key] || [])
+        var notInArgs = keyAndAliases.every(function (val) {
+          return args.indexOf('--' + val) === -1
+        })
+        if (notInArgs) {
+          completions.push('--' + key)
+        }
+      })
+    }
+
+    done(completions)
+  }
+
+  // generate the completion script to add to your .bashrc.
+  self.generateCompletionScript = function ($0) {
+    var script = fs.readFileSync(
+      path.resolve(__dirname, '../completion.sh.hbs'),
+      'utf-8'
+    )
+    var name = path.basename($0)
+
+    // add ./to applications not yet installed as bin.
+    if ($0.match(/\.js$/)) $0 = './' + $0
+
+    script = script.replace(/{{app_name}}/g, name)
+    return script.replace(/{{app_path}}/g, $0)
+  }
+
+  // register a function to perform your own custom
+  // completions., this function can be either
+  // synchrnous or asynchronous.
+  var completionFunction = null
+  self.registerFunction = function (fn) {
+    completionFunction = fn
+  }
+
+  return self
+}
diff --git a/server/node_modules/yargs/lib/levenshtein.js b/server/node_modules/yargs/lib/levenshtein.js
new file mode 100644
index 0000000000000000000000000000000000000000..6ec216f59dab8e4ee10b3aedaace1abc22dd930f
--- /dev/null
+++ b/server/node_modules/yargs/lib/levenshtein.js
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2011 Andrei Mackenzie
+
+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.
+*/
+
+// levenshtein distance algorithm, pulled from Andrei Mackenzie's MIT licensed.
+// gist, which can be found here: https://gist.github.com/andrei-m/982927
+
+// Compute the edit distance between the two given strings
+module.exports = function (a, b) {
+  if (a.length === 0) return b.length
+  if (b.length === 0) return a.length
+
+  var matrix = []
+
+  // increment along the first column of each row
+  var i
+  for (i = 0; i <= b.length; i++) {
+    matrix[i] = [i]
+  }
+
+  // increment each column in the first row
+  var j
+  for (j = 0; j <= a.length; j++) {
+    matrix[0][j] = j
+  }
+
+  // Fill in the rest of the matrix
+  for (i = 1; i <= b.length; i++) {
+    for (j = 1; j <= a.length; j++) {
+      if (b.charAt(i - 1) === a.charAt(j - 1)) {
+        matrix[i][j] = matrix[i - 1][j - 1]
+      } else {
+        matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
+                                Math.min(matrix[i][j - 1] + 1, // insertion
+                                         matrix[i - 1][j] + 1)) // deletion
+      }
+    }
+  }
+
+  return matrix[b.length][a.length]
+}
diff --git a/server/node_modules/yargs/lib/obj-filter.js b/server/node_modules/yargs/lib/obj-filter.js
new file mode 100644
index 0000000000000000000000000000000000000000..42cb9961eefd2a2ec18b7f1e9820be10d8d72c66
--- /dev/null
+++ b/server/node_modules/yargs/lib/obj-filter.js
@@ -0,0 +1,10 @@
+module.exports = function (original, filter) {
+  const obj = {}
+  filter = filter || function (k, v) { return true }
+  Object.keys(original || {}).forEach(function (key) {
+    if (filter(key, original[key])) {
+      obj[key] = original[key]
+    }
+  })
+  return obj
+}
diff --git a/server/node_modules/yargs/lib/usage.js b/server/node_modules/yargs/lib/usage.js
new file mode 100644
index 0000000000000000000000000000000000000000..169fe6eb2c105db56aeca3c7f33842645bf9cd99
--- /dev/null
+++ b/server/node_modules/yargs/lib/usage.js
@@ -0,0 +1,406 @@
+// this file handles outputting usage instructions,
+// failures, etc. keeps logging in one place.
+const stringWidth = require('string-width')
+const objFilter = require('./obj-filter')
+const setBlocking = require('set-blocking')
+
+module.exports = function (yargs, y18n) {
+  const __ = y18n.__
+  const self = {}
+
+  // methods for ouputting/building failure message.
+  var fails = []
+  self.failFn = function (f) {
+    fails.push(f)
+  }
+
+  var failMessage = null
+  var showHelpOnFail = true
+  self.showHelpOnFail = function (enabled, message) {
+    if (typeof enabled === 'string') {
+      message = enabled
+      enabled = true
+    } else if (typeof enabled === 'undefined') {
+      enabled = true
+    }
+    failMessage = message
+    showHelpOnFail = enabled
+    return self
+  }
+
+  var failureOutput = false
+  self.fail = function (msg, err) {
+    if (fails.length) {
+      for (var i = fails.length - 1; i >= 0; --i) {
+        fails[i](msg, err)
+      }
+    } else {
+      if (yargs.getExitProcess()) setBlocking(true)
+
+      // don't output failure message more than once
+      if (!failureOutput) {
+        failureOutput = true
+        if (showHelpOnFail) yargs.showHelp('error')
+        if (msg) console.error(msg)
+        if (failMessage) {
+          if (msg) console.error('')
+          console.error(failMessage)
+        }
+      }
+      if (yargs.getExitProcess()) {
+        process.exit(1)
+      } else {
+        throw err || new Error(msg)
+      }
+    }
+  }
+
+  // methods for ouputting/building help (usage) message.
+  var usage
+  self.usage = function (msg) {
+    usage = msg
+  }
+  self.getUsage = function () {
+    return usage
+  }
+
+  var examples = []
+  self.example = function (cmd, description) {
+    examples.push([cmd, description || ''])
+  }
+
+  var commands = []
+  self.command = function (cmd, description) {
+    commands.push([cmd, description || ''])
+  }
+  self.getCommands = function () {
+    return commands
+  }
+
+  var descriptions = {}
+  self.describe = function (key, desc) {
+    if (typeof key === 'object') {
+      Object.keys(key).forEach(function (k) {
+        self.describe(k, key[k])
+      })
+    } else {
+      descriptions[key] = desc
+    }
+  }
+  self.getDescriptions = function () {
+    return descriptions
+  }
+
+  var epilog
+  self.epilog = function (msg) {
+    epilog = msg
+  }
+
+  var wrap = windowWidth()
+  self.wrap = function (cols) {
+    wrap = cols
+  }
+
+  var deferY18nLookupPrefix = '__yargsString__:'
+  self.deferY18nLookup = function (str) {
+    return deferY18nLookupPrefix + str
+  }
+
+  var defaultGroup = 'Options:'
+  self.help = function () {
+    normalizeAliases()
+
+    var demanded = yargs.getDemanded()
+    var groups = yargs.getGroups()
+    var options = yargs.getOptions()
+    var keys = Object.keys(
+      Object.keys(descriptions)
+      .concat(Object.keys(demanded))
+      .concat(Object.keys(options.default))
+      .reduce(function (acc, key) {
+        if (key !== '_') acc[key] = true
+        return acc
+      }, {})
+    )
+    var ui = require('cliui')({
+      width: wrap,
+      wrap: !!wrap
+    })
+
+    // the usage string.
+    if (usage) {
+      var u = usage.replace(/\$0/g, yargs.$0)
+      ui.div(u + '\n')
+    }
+
+    // your application's commands, i.e., non-option
+    // arguments populated in '_'.
+    if (commands.length) {
+      ui.div(__('Commands:'))
+
+      commands.forEach(function (command) {
+        ui.div(
+          {text: command[0], padding: [0, 2, 0, 2], width: maxWidth(commands) + 4},
+          {text: command[1]}
+        )
+      })
+
+      ui.div()
+    }
+
+    // perform some cleanup on the keys array, making it
+    // only include top-level keys not their aliases.
+    var aliasKeys = (Object.keys(options.alias) || [])
+      .concat(Object.keys(yargs.parsed.newAliases) || [])
+
+    keys = keys.filter(function (key) {
+      return !yargs.parsed.newAliases[key] && aliasKeys.every(function (alias) {
+        return (options.alias[alias] || []).indexOf(key) === -1
+      })
+    })
+
+    // populate 'Options:' group with any keys that have not
+    // explicitly had a group set.
+    if (!groups[defaultGroup]) groups[defaultGroup] = []
+    addUngroupedKeys(keys, options.alias, groups)
+
+    // display 'Options:' table along with any custom tables:
+    Object.keys(groups).forEach(function (groupName) {
+      if (!groups[groupName].length) return
+
+      ui.div(__(groupName))
+
+      // if we've grouped the key 'f', but 'f' aliases 'foobar',
+      // normalizedKeys should contain only 'foobar'.
+      var normalizedKeys = groups[groupName].map(function (key) {
+        if (~aliasKeys.indexOf(key)) return key
+        for (var i = 0, aliasKey; (aliasKey = aliasKeys[i]) !== undefined; i++) {
+          if (~(options.alias[aliasKey] || []).indexOf(key)) return aliasKey
+        }
+        return key
+      })
+
+      // actually generate the switches string --foo, -f, --bar.
+      var switches = normalizedKeys.reduce(function (acc, key) {
+        acc[key] = [ key ].concat(options.alias[key] || [])
+          .map(function (sw) {
+            return (sw.length > 1 ? '--' : '-') + sw
+          })
+          .join(', ')
+
+        return acc
+      }, {})
+
+      normalizedKeys.forEach(function (key) {
+        var kswitch = switches[key]
+        var desc = descriptions[key] || ''
+        var type = null
+
+        if (~desc.lastIndexOf(deferY18nLookupPrefix)) desc = __(desc.substring(deferY18nLookupPrefix.length))
+
+        if (~options.boolean.indexOf(key)) type = '[' + __('boolean') + ']'
+        if (~options.count.indexOf(key)) type = '[' + __('count') + ']'
+        if (~options.string.indexOf(key)) type = '[' + __('string') + ']'
+        if (~options.normalize.indexOf(key)) type = '[' + __('string') + ']'
+        if (~options.array.indexOf(key)) type = '[' + __('array') + ']'
+        if (~options.number.indexOf(key)) type = '[' + __('number') + ']'
+
+        var extra = [
+          type,
+          demanded[key] ? '[' + __('required') + ']' : null,
+          options.choices && options.choices[key] ? '[' + __('choices:') + ' ' +
+            self.stringifiedValues(options.choices[key]) + ']' : null,
+          defaultString(options.default[key], options.defaultDescription[key])
+        ].filter(Boolean).join(' ')
+
+        ui.span(
+          {text: kswitch, padding: [0, 2, 0, 2], width: maxWidth(switches) + 4},
+          desc
+        )
+
+        if (extra) ui.div({text: extra, padding: [0, 0, 0, 2], align: 'right'})
+        else ui.div()
+      })
+
+      ui.div()
+    })
+
+    // describe some common use-cases for your application.
+    if (examples.length) {
+      ui.div(__('Examples:'))
+
+      examples.forEach(function (example) {
+        example[0] = example[0].replace(/\$0/g, yargs.$0)
+      })
+
+      examples.forEach(function (example) {
+        ui.div(
+          {text: example[0], padding: [0, 2, 0, 2], width: maxWidth(examples) + 4},
+          example[1]
+        )
+      })
+
+      ui.div()
+    }
+
+    // the usage string.
+    if (epilog) {
+      var e = epilog.replace(/\$0/g, yargs.$0)
+      ui.div(e + '\n')
+    }
+
+    return ui.toString()
+  }
+
+  // return the maximum width of a string
+  // in the left-hand column of a table.
+  function maxWidth (table) {
+    var width = 0
+
+    // table might be of the form [leftColumn],
+    // or {key: leftColumn}}
+    if (!Array.isArray(table)) {
+      table = Object.keys(table).map(function (key) {
+        return [table[key]]
+      })
+    }
+
+    table.forEach(function (v) {
+      width = Math.max(stringWidth(v[0]), width)
+    })
+
+    // if we've enabled 'wrap' we should limit
+    // the max-width of the left-column.
+    if (wrap) width = Math.min(width, parseInt(wrap * 0.5, 10))
+
+    return width
+  }
+
+  // make sure any options set for aliases,
+  // are copied to the keys being aliased.
+  function normalizeAliases () {
+    var demanded = yargs.getDemanded()
+    var options = yargs.getOptions()
+
+    ;(Object.keys(options.alias) || []).forEach(function (key) {
+      options.alias[key].forEach(function (alias) {
+        // copy descriptions.
+        if (descriptions[alias]) self.describe(key, descriptions[alias])
+        // copy demanded.
+        if (demanded[alias]) yargs.demand(key, demanded[alias].msg)
+        // type messages.
+        if (~options.boolean.indexOf(alias)) yargs.boolean(key)
+        if (~options.count.indexOf(alias)) yargs.count(key)
+        if (~options.string.indexOf(alias)) yargs.string(key)
+        if (~options.normalize.indexOf(alias)) yargs.normalize(key)
+        if (~options.array.indexOf(alias)) yargs.array(key)
+        if (~options.number.indexOf(alias)) yargs.number(key)
+      })
+    })
+  }
+
+  // given a set of keys, place any keys that are
+  // ungrouped under the 'Options:' grouping.
+  function addUngroupedKeys (keys, aliases, groups) {
+    var groupedKeys = []
+    var toCheck = null
+    Object.keys(groups).forEach(function (group) {
+      groupedKeys = groupedKeys.concat(groups[group])
+    })
+
+    keys.forEach(function (key) {
+      toCheck = [key].concat(aliases[key])
+      if (!toCheck.some(function (k) {
+        return groupedKeys.indexOf(k) !== -1
+      })) {
+        groups[defaultGroup].push(key)
+      }
+    })
+    return groupedKeys
+  }
+
+  self.showHelp = function (level) {
+    if (!level) level = 'error'
+    var emit = typeof level === 'function' ? level : console[ level ]
+    emit(self.help())
+  }
+
+  self.functionDescription = function (fn) {
+    var description = fn.name ? require('decamelize')(fn.name, '-') : __('generated-value')
+    return ['(', description, ')'].join('')
+  }
+
+  self.stringifiedValues = function (values, separator) {
+    var string = ''
+    var sep = separator || ', '
+    var array = [].concat(values)
+
+    if (!values || !array.length) return string
+
+    array.forEach(function (value) {
+      if (string.length) string += sep
+      string += JSON.stringify(value)
+    })
+
+    return string
+  }
+
+  // format the default-value-string displayed in
+  // the right-hand column.
+  function defaultString (value, defaultDescription) {
+    var string = '[' + __('default:') + ' '
+
+    if (value === undefined && !defaultDescription) return null
+
+    if (defaultDescription) {
+      string += defaultDescription
+    } else {
+      switch (typeof value) {
+        case 'string':
+          string += JSON.stringify(value)
+          break
+        case 'object':
+          string += JSON.stringify(value)
+          break
+        default:
+          string += value
+      }
+    }
+
+    return string + ']'
+  }
+
+  // guess the width of the console window, max-width 80.
+  function windowWidth () {
+    const wsize = require('window-size')
+    return wsize.width ? Math.min(80, wsize.width) : null
+  }
+
+  // logic for displaying application version.
+  var version = null
+  self.version = function (ver) {
+    version = ver
+  }
+
+  self.showVersion = function () {
+    if (typeof version === 'function') console.log(version())
+    else console.log(version)
+  }
+
+  self.reset = function (globalLookup) {
+    // do not reset wrap here
+    // do not reset fails here
+    failMessage = null
+    failureOutput = false
+    usage = undefined
+    epilog = undefined
+    examples = []
+    commands = []
+    descriptions = objFilter(descriptions, function (k, v) {
+      return globalLookup[k]
+    })
+    return self
+  }
+
+  return self
+}
diff --git a/server/node_modules/yargs/lib/validation.js b/server/node_modules/yargs/lib/validation.js
new file mode 100644
index 0000000000000000000000000000000000000000..cc453783dacb25ff6e5d7e9450ef272a54f8347b
--- /dev/null
+++ b/server/node_modules/yargs/lib/validation.js
@@ -0,0 +1,303 @@
+const objFilter = require('./obj-filter')
+
+// validation-type-stuff, missing params,
+// bad implications, custom checks.
+module.exports = function (yargs, usage, y18n) {
+  const __ = y18n.__
+  const __n = y18n.__n
+  const self = {}
+
+  // validate appropriate # of non-option
+  // arguments were provided, i.e., '_'.
+  self.nonOptionCount = function (argv) {
+    const demanded = yargs.getDemanded()
+    // don't count currently executing commands
+    const _s = argv._.length - yargs.getContext().commands.length
+
+    if (demanded._ && (_s < demanded._.count || _s > demanded._.max)) {
+      if (demanded._.msg !== undefined) {
+        usage.fail(demanded._.msg)
+      } else if (_s < demanded._.count) {
+        usage.fail(
+          __('Not enough non-option arguments: got %s, need at least %s', _s, demanded._.count)
+        )
+      } else {
+        usage.fail(
+          __('Too many non-option arguments: got %s, maximum of %s', _s, demanded._.max)
+        )
+      }
+    }
+  }
+
+  // validate the appropriate # of <required>
+  // positional arguments were provided:
+  self.positionalCount = function (required, observed) {
+    if (observed < required) {
+      usage.fail(
+        __('Not enough non-option arguments: got %s, need at least %s', observed, required)
+      )
+    }
+  }
+
+  // make sure that any args that require an
+  // value (--foo=bar), have a value.
+  self.missingArgumentValue = function (argv) {
+    const defaultValues = [true, false, '']
+    const options = yargs.getOptions()
+
+    if (options.requiresArg.length > 0) {
+      const missingRequiredArgs = []
+
+      options.requiresArg.forEach(function (key) {
+        const value = argv[key]
+
+        // if a value is explicitly requested,
+        // flag argument as missing if it does not
+        // look like foo=bar was entered.
+        if (~defaultValues.indexOf(value) ||
+          (Array.isArray(value) && !value.length)) {
+          missingRequiredArgs.push(key)
+        }
+      })
+
+      if (missingRequiredArgs.length > 0) {
+        usage.fail(__n(
+          'Missing argument value: %s',
+          'Missing argument values: %s',
+          missingRequiredArgs.length,
+          missingRequiredArgs.join(', ')
+        ))
+      }
+    }
+  }
+
+  // make sure all the required arguments are present.
+  self.requiredArguments = function (argv) {
+    const demanded = yargs.getDemanded()
+    var missing = null
+
+    Object.keys(demanded).forEach(function (key) {
+      if (!argv.hasOwnProperty(key)) {
+        missing = missing || {}
+        missing[key] = demanded[key]
+      }
+    })
+
+    if (missing) {
+      const customMsgs = []
+      Object.keys(missing).forEach(function (key) {
+        const msg = missing[key].msg
+        if (msg && customMsgs.indexOf(msg) < 0) {
+          customMsgs.push(msg)
+        }
+      })
+
+      const customMsg = customMsgs.length ? '\n' + customMsgs.join('\n') : ''
+
+      usage.fail(__n(
+        'Missing required argument: %s',
+        'Missing required arguments: %s',
+        Object.keys(missing).length,
+        Object.keys(missing).join(', ') + customMsg
+      ))
+    }
+  }
+
+  // check for unknown arguments (strict-mode).
+  self.unknownArguments = function (argv, aliases) {
+    const aliasLookup = {}
+    const descriptions = usage.getDescriptions()
+    const demanded = yargs.getDemanded()
+    const commandKeys = yargs.getCommandInstance().getCommands()
+    const unknown = []
+    const currentContext = yargs.getContext()
+
+    Object.keys(aliases).forEach(function (key) {
+      aliases[key].forEach(function (alias) {
+        aliasLookup[alias] = key
+      })
+    })
+
+    Object.keys(argv).forEach(function (key) {
+      if (key !== '$0' && key !== '_' &&
+        !descriptions.hasOwnProperty(key) &&
+        !demanded.hasOwnProperty(key) &&
+        !aliasLookup.hasOwnProperty(key)) {
+        unknown.push(key)
+      }
+    })
+
+    if (commandKeys.length > 0) {
+      argv._.slice(currentContext.commands.length).forEach(function (key) {
+        if (commandKeys.indexOf(key) === -1) {
+          unknown.push(key)
+        }
+      })
+    }
+
+    if (unknown.length > 0) {
+      usage.fail(__n(
+        'Unknown argument: %s',
+        'Unknown arguments: %s',
+        unknown.length,
+        unknown.join(', ')
+      ))
+    }
+  }
+
+  // validate arguments limited to enumerated choices
+  self.limitedChoices = function (argv) {
+    const options = yargs.getOptions()
+    const invalid = {}
+
+    if (!Object.keys(options.choices).length) return
+
+    Object.keys(argv).forEach(function (key) {
+      if (key !== '$0' && key !== '_' &&
+        options.choices.hasOwnProperty(key)) {
+        [].concat(argv[key]).forEach(function (value) {
+          // TODO case-insensitive configurability
+          if (options.choices[key].indexOf(value) === -1) {
+            invalid[key] = (invalid[key] || []).concat(value)
+          }
+        })
+      }
+    })
+
+    const invalidKeys = Object.keys(invalid)
+
+    if (!invalidKeys.length) return
+
+    var msg = __('Invalid values:')
+    invalidKeys.forEach(function (key) {
+      msg += '\n  ' + __(
+        'Argument: %s, Given: %s, Choices: %s',
+        key,
+        usage.stringifiedValues(invalid[key]),
+        usage.stringifiedValues(options.choices[key])
+      )
+    })
+    usage.fail(msg)
+  }
+
+  // custom checks, added using the `check` option on yargs.
+  var checks = []
+  self.check = function (f) {
+    checks.push(f)
+  }
+
+  self.customChecks = function (argv, aliases) {
+    checks.forEach(function (f) {
+      try {
+        const result = f(argv, aliases)
+        if (!result) {
+          usage.fail(__('Argument check failed: %s', f.toString()))
+        } else if (typeof result === 'string') {
+          usage.fail(result)
+        }
+      } catch (err) {
+        usage.fail(err.message ? err.message : err, err)
+      }
+    })
+  }
+
+  // check implications, argument foo implies => argument bar.
+  var implied = {}
+  self.implies = function (key, value) {
+    if (typeof key === 'object') {
+      Object.keys(key).forEach(function (k) {
+        self.implies(k, key[k])
+      })
+    } else {
+      implied[key] = value
+    }
+  }
+  self.getImplied = function () {
+    return implied
+  }
+
+  self.implications = function (argv) {
+    const implyFail = []
+
+    Object.keys(implied).forEach(function (key) {
+      var booleanNegation
+      if (yargs.getOptions().configuration['boolean-negation'] === false) {
+        booleanNegation = false
+      } else {
+        booleanNegation = true
+      }
+      var num
+      const origKey = key
+      var value = implied[key]
+
+      // convert string '1' to number 1
+      num = Number(key)
+      key = isNaN(num) ? key : num
+
+      if (typeof key === 'number') {
+        // check length of argv._
+        key = argv._.length >= key
+      } else if (key.match(/^--no-.+/) && booleanNegation) {
+        // check if key doesn't exist
+        key = key.match(/^--no-(.+)/)[1]
+        key = !argv[key]
+      } else {
+        // check if key exists
+        key = argv[key]
+      }
+
+      num = Number(value)
+      value = isNaN(num) ? value : num
+
+      if (typeof value === 'number') {
+        value = argv._.length >= value
+      } else if (value.match(/^--no-.+/) && booleanNegation) {
+        value = value.match(/^--no-(.+)/)[1]
+        value = !argv[value]
+      } else {
+        value = argv[value]
+      }
+
+      if (key && !value) {
+        implyFail.push(origKey)
+      }
+    })
+
+    if (implyFail.length) {
+      var msg = __('Implications failed:') + '\n'
+
+      implyFail.forEach(function (key) {
+        msg += ('  ' + key + ' -> ' + implied[key])
+      })
+
+      usage.fail(msg)
+    }
+  }
+
+  self.recommendCommands = function (cmd, potentialCommands) {
+    const distance = require('./levenshtein')
+    const threshold = 3 // if it takes more than three edits, let's move on.
+    potentialCommands = potentialCommands.sort(function (a, b) { return b.length - a.length })
+
+    var recommended = null
+    var bestDistance = Infinity
+    for (var i = 0, candidate; (candidate = potentialCommands[i]) !== undefined; i++) {
+      var d = distance(cmd, candidate)
+      if (d <= threshold && d < bestDistance) {
+        bestDistance = d
+        recommended = candidate
+      }
+    }
+    if (recommended) usage.fail(__('Did you mean %s?', recommended))
+  }
+
+  self.reset = function (globalLookup) {
+    implied = objFilter(implied, function (k, v) {
+      return globalLookup[k]
+    })
+    checks = []
+    return self
+  }
+
+  return self
+}
diff --git a/server/node_modules/yargs/locales/de.json b/server/node_modules/yargs/locales/de.json
new file mode 100644
index 0000000000000000000000000000000000000000..86c874c1aa53457b4696dff0fe5ab25189278b5c
--- /dev/null
+++ b/server/node_modules/yargs/locales/de.json
@@ -0,0 +1,38 @@
+{
+  "Commands:": "Kommandos:",
+  "Options:": "Optionen:",
+  "Examples:": "Beispiele:",
+  "boolean": "boolean",
+  "count": "Zähler",
+  "string": "string",
+  "number": "Zahl",
+  "array": "array",
+  "required": "erforderlich",
+  "default:": "Standard:",
+  "choices:": "Möglichkeiten:",
+  "generated-value": "Generierter-Wert",
+  "Not enough non-option arguments: got %s, need at least %s": "Nicht genügend Argumente ohne Optionen: %s vorhanden, mindestens %s benötigt",
+  "Too many non-option arguments: got %s, maximum of %s": "Zu viele Argumente ohne Optionen: %s vorhanden, maximal %s erlaubt",
+  "Missing argument value: %s": {
+    "one": "Fehlender Argumentwert: %s",
+    "other": "Fehlende Argumentwerte: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "Fehlendes Argument: %s",
+    "other": "Fehlende Argumente: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "Unbekanntes Argument: %s",
+    "other": "Unbekannte Argumente: %s"
+  },
+  "Invalid values:": "Unzulässige Werte:",
+  "Argument: %s, Given: %s, Choices: %s": "Argument: %s, Gegeben: %s, Möglichkeiten: %s",
+  "Argument check failed: %s": "Argumente-Check fehlgeschlagen: %s",
+  "Implications failed:": "Implikationen fehlgeschlagen:",
+  "Not enough arguments following: %s": "Nicht genügend Argumente nach: %s",
+  "Invalid JSON config file: %s": "Fehlerhafte JSON-Config Datei: %s",
+  "Path to JSON config file": "Pfad zur JSON-Config Datei",
+  "Show help": "Hilfe anzeigen",
+  "Show version number": "Version anzeigen",
+  "Did you mean %s?": "Meintest du %s?"
+}
diff --git a/server/node_modules/yargs/locales/en.json b/server/node_modules/yargs/locales/en.json
new file mode 100644
index 0000000000000000000000000000000000000000..59d4eb08d6faf94a89cd24866201c49180a47939
--- /dev/null
+++ b/server/node_modules/yargs/locales/en.json
@@ -0,0 +1,38 @@
+{
+  "Commands:": "Commands:",
+  "Options:": "Options:",
+  "Examples:": "Examples:",
+  "boolean": "boolean",
+  "count": "count",
+  "string": "string",
+  "number": "number",
+  "array": "array",
+  "required": "required",
+  "default:": "default:",
+  "choices:": "choices:",
+  "generated-value": "generated-value",
+  "Not enough non-option arguments: got %s, need at least %s": "Not enough non-option arguments: got %s, need at least %s",
+  "Too many non-option arguments: got %s, maximum of %s": "Too many non-option arguments: got %s, maximum of %s",
+  "Missing argument value: %s": {
+    "one": "Missing argument value: %s",
+    "other": "Missing argument values: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "Missing required argument: %s",
+    "other": "Missing required arguments: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "Unknown argument: %s",
+    "other": "Unknown arguments: %s"
+  },
+  "Invalid values:": "Invalid values:",
+  "Argument: %s, Given: %s, Choices: %s": "Argument: %s, Given: %s, Choices: %s",
+  "Argument check failed: %s": "Argument check failed: %s",
+  "Implications failed:": "Implications failed:",
+  "Not enough arguments following: %s": "Not enough arguments following: %s",
+  "Invalid JSON config file: %s": "Invalid JSON config file: %s",
+  "Path to JSON config file": "Path to JSON config file",
+  "Show help": "Show help",
+  "Show version number": "Show version number",
+  "Did you mean %s?": "Did you mean %s?"
+}
diff --git a/server/node_modules/yargs/locales/es.json b/server/node_modules/yargs/locales/es.json
new file mode 100644
index 0000000000000000000000000000000000000000..39c25222e30427a837cd34c310a9d919f315ea2f
--- /dev/null
+++ b/server/node_modules/yargs/locales/es.json
@@ -0,0 +1,37 @@
+{
+  "Commands:": "Comandos:",
+  "Options:": "Opciones:",
+  "Examples:": "Ejemplos:",
+  "boolean": "boolean",
+  "count": "cuenta",
+  "string": "cadena de caracteres",
+  "number": "número",
+  "array": "tabla",
+  "required": "requisito",
+  "default:": "defecto:",
+  "choices:": "selección:",
+  "generated-value": "valor-generado",
+  "Not enough non-option arguments: got %s, need at least %s": "Hacen falta argumentos no-opcionales: Número recibido %s, necesita por lo menos %s",
+  "Too many non-option arguments: got %s, maximum of %s": "Demasiados argumentos no-opcionales: Número recibido %s, máximo es %s",
+  "Missing argument value: %s": {
+    "one": "Falta argumento: %s",
+    "other": "Faltan argumentos: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "Falta argumento requerido: %s",
+    "other": "Faltan argumentos requeridos: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "Argumento desconocido: %s",
+    "other": "Argumentos desconocidos: %s"
+  },
+  "Invalid values:": "Valores inválidos:",
+  "Argument: %s, Given: %s, Choices: %s": "Argumento: %s, Recibido: %s, Selección: %s",
+  "Argument check failed: %s": "Verificación de argumento ha fracasado: %s",
+  "Implications failed:": "Implicaciones fracasadas:",
+  "Not enough arguments following: %s": "No hay suficientes argumentos después de: %s",
+  "Invalid JSON config file: %s": "Archivo de configuración JSON inválido: %s",
+  "Path to JSON config file": "Ruta al archivo de configuración JSON",
+  "Show help": "Muestra ayuda",
+  "Show version number": "Muestra número de versión"
+}
diff --git a/server/node_modules/yargs/locales/fr.json b/server/node_modules/yargs/locales/fr.json
new file mode 100644
index 0000000000000000000000000000000000000000..481f47e37fbc9d998e2b5bd0f7386078c9842281
--- /dev/null
+++ b/server/node_modules/yargs/locales/fr.json
@@ -0,0 +1,37 @@
+{
+  "Commands:": "Commandes:",
+  "Options:": "Options:",
+  "Examples:": "Exemples:",
+  "boolean": "booléen",
+  "count": "comptage",
+  "string": "chaine de caractère",
+  "number": "nombre",
+  "array": "tableau",
+  "required": "requis",
+  "default:": "défaut:",
+  "choices:": "choix:",
+  "generated-value": "valeur générée",
+  "Not enough non-option arguments: got %s, need at least %s": "Pas assez d'arguments non-option: reçu %s, besoin d'au moins %s",
+  "Too many non-option arguments: got %s, maximum of %s": "Trop d'arguments non-option: reçu %s, maximum %s",
+  "Missing argument value: %s": {
+    "one": "Argument manquant: %s",
+    "other": "Arguments manquants: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "Argument requis manquant: %s",
+    "other": "Arguments requis manquants: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "Argument inconnu: %s",
+    "other": "Arguments inconnus: %s"
+  },
+  "Invalid values:": "Valeurs invalides:",
+  "Argument: %s, Given: %s, Choices: %s": "Argument: %s, Donné: %s, Choix: %s",
+  "Argument check failed: %s": "Echec de la vérification de l'argument: %s",
+  "Implications failed:": "Implications échouées:",
+  "Not enough arguments following: %s": "Pas assez d'arguments suivant: %s",
+  "Invalid JSON config file: %s": "Fichier de configuration JSON invalide: %s",
+  "Path to JSON config file": "Chemin du fichier de configuration JSON",
+  "Show help": "Affiche de l'aide",
+  "Show version number": "Affiche le numéro de version"
+}
diff --git a/server/node_modules/yargs/locales/id.json b/server/node_modules/yargs/locales/id.json
new file mode 100644
index 0000000000000000000000000000000000000000..ea2ce5a5b6d62bbb7c72b15359935a74d072c347
--- /dev/null
+++ b/server/node_modules/yargs/locales/id.json
@@ -0,0 +1,38 @@
+
+{
+  "Commands:": "Perintah:",
+  "Options:": "Pilihan:",
+  "Examples:": "Contoh:",
+  "boolean": "boolean",
+  "count": "jumlah",
+  "number": "nomor",
+  "string": "string",
+  "array": "larik",
+  "required": "diperlukan",
+  "default:": "bawaan:",
+  "choices:": "pilihan:",
+  "generated-value": "nilai-yang-dihasilkan",
+  "Not enough non-option arguments: got %s, need at least %s": "Argumen wajib kurang: hanya %s, minimal %s",
+  "Too many non-option arguments: got %s, maximum of %s": "Terlalu banyak argumen wajib: ada %s, maksimal %s",
+  "Missing argument value: %s": {
+    "one": "Kurang argumen: %s",
+    "other": "Kurang argumen: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "Kurang argumen wajib: %s",
+    "other": "Kurang argumen wajib: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "Argumen tak diketahui: %s",
+    "other": "Argumen tak diketahui: %s"
+  },
+  "Invalid values:": "Nilai-nilai tidak valid:",
+  "Argument: %s, Given: %s, Choices: %s": "Argumen: %s, Diberikan: %s, Pilihan: %s",
+  "Argument check failed: %s": "Pemeriksaan argument gagal: %s",
+  "Implications failed:": "Implikasi gagal:",
+  "Not enough arguments following: %s": "Kurang argumen untuk: %s",
+  "Invalid JSON config file: %s": "Berkas konfigurasi JSON tidak valid: %s",
+  "Path to JSON config file": "Alamat berkas konfigurasi JSON",
+  "Show help": "Lihat bantuan",
+  "Show version number": "Lihat nomor versi"
+}
diff --git a/server/node_modules/yargs/locales/it.json b/server/node_modules/yargs/locales/it.json
new file mode 100644
index 0000000000000000000000000000000000000000..bd9573a2210d377a2e9832362014cd4790a0d9dd
--- /dev/null
+++ b/server/node_modules/yargs/locales/it.json
@@ -0,0 +1,37 @@
+{
+  "Commands:": "Comandi:",
+  "Options:": "Opzioni:",
+  "Examples:": "Esempi:",
+  "boolean": "booleano",
+  "count": "contatore",
+  "string": "stringa",
+  "number": "numero",
+  "array": "vettore",
+  "required": "richiesto",
+  "default:": "predefinito:",
+  "choices:": "scelte:",
+  "generated-value": "valore generato",
+  "Not enough non-option arguments: got %s, need at least %s": "Numero insufficiente di argomenti non opzione: inseriti %s, richiesti almeno %s",
+  "Too many non-option arguments: got %s, maximum of %s": "Troppi argomenti non opzione: inseriti %s, massimo possibile %s",
+  "Missing argument value: %s": {
+    "one": "Argomento mancante: %s",
+    "other": "Argomenti mancanti: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "Argomento richiesto mancante: %s",
+    "other": "Argomenti richiesti mancanti: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "Argomento sconosciuto: %s",
+    "other": "Argomenti sconosciuti: %s"
+  },
+  "Invalid values:": "Valori non validi:",
+  "Argument: %s, Given: %s, Choices: %s": "Argomento: %s, Richiesto: %s, Scelte: %s",
+  "Argument check failed: %s": "Controllo dell'argomento fallito: %s",
+  "Implications failed:": "Argomenti impliciti non soddisfatti:",
+  "Not enough arguments following: %s": "Argomenti insufficienti dopo: %s",
+  "Invalid JSON config file: %s": "File di configurazione JSON non valido: %s",
+  "Path to JSON config file": "Percorso del file di configurazione JSON",
+  "Show help": "Mostra la schermata di aiuto",
+  "Show version number": "Mostra il numero di versione"
+}
diff --git a/server/node_modules/yargs/locales/ja.json b/server/node_modules/yargs/locales/ja.json
new file mode 100644
index 0000000000000000000000000000000000000000..899454c9bf6b0a118a86ad477359165b3af420cc
--- /dev/null
+++ b/server/node_modules/yargs/locales/ja.json
@@ -0,0 +1,37 @@
+{
+  "Commands:": "コマンド:",
+  "Options:": "オプション:",
+  "Examples:": "例:",
+  "boolean": "真偽",
+  "count": "カウント",
+  "string": "文字列",
+  "number": "数値",
+  "array": "配列",
+  "required": "å¿…é ˆ",
+  "default:": "デフォルト:",
+  "choices:": "選択してください:",
+  "generated-value": "生成された値",
+  "Not enough non-option arguments: got %s, need at least %s": "オプションではない引数が %s 個では不足しています。少なくとも %s 個の引数が必要です:",
+  "Too many non-option arguments: got %s, maximum of %s": "オプションではない引数が %s 個では多すぎます。最大で %s 個までです:",
+  "Missing argument value: %s": {
+    "one": "引数が見つかりません: %s",
+    "other": "引数が見つかりません: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "必須の引数が見つかりません: %s",
+    "other": "必須の引数が見つかりません: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "未知の引数です: %s",
+    "other": "未知の引数です: %s"
+  },
+  "Invalid values:": "不正な値です:",
+  "Argument: %s, Given: %s, Choices: %s": "引数は %s です。指定できるのは %s つです。選択してください: %s",
+  "Argument check failed: %s": "引数のチェックに失敗しました: %s",
+  "Implications failed:": "オプションの組み合わせで不正が生じました:",
+  "Not enough arguments following: %s": "次の引数が不足しています。: %s",
+  "Invalid JSON config file: %s": "JSONの設定ファイルが不正です: %s",
+  "Path to JSON config file": "JSONの設定ファイルまでのpath",
+  "Show help": "ヘルプを表示",
+  "Show version number": "バージョンを表示"
+}
diff --git a/server/node_modules/yargs/locales/ko.json b/server/node_modules/yargs/locales/ko.json
new file mode 100644
index 0000000000000000000000000000000000000000..a70ec24dd254ec4bbcbf8cb04a14456eb552e9a2
--- /dev/null
+++ b/server/node_modules/yargs/locales/ko.json
@@ -0,0 +1,37 @@
+{
+  "Commands:": "명령:",
+  "Options:": "옵션:",
+  "Examples:": "예시:",
+  "boolean": "여부",
+  "count": "개수",
+  "string": "문자열",
+  "number": "숫자",
+  "array": "ë°°ì—´",
+  "required": "필수",
+  "default:": "기본:",
+  "choices:": "선택:",
+  "generated-value": "생성된 값",
+  "Not enough non-option arguments: got %s, need at least %s": "옵션이 아닌 인자가 충분치 않습니다: %s개를 받았지만, 적어도 %s개는 필요합니다",
+  "Too many non-option arguments: got %s, maximum of %s": "옵션이 아닌 인자가 너무 많습니다: %s개를 받았지만, %s개 이하여야 합니다",
+  "Missing argument value: %s": {
+    "one": "인자값을 받지 못했습니다: %s",
+    "other": "인자값들을 받지 못했습니다: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "필수 인자를 받지 못했습니다: %s",
+    "other": "필수 인자들을 받지 못했습니다: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "알 수 없는 인자입니다: %s",
+    "other": "알 수 없는 인자들입니다: %s"
+  },
+  "Invalid values:": "잘못된 값입니다:",
+  "Argument: %s, Given: %s, Choices: %s": "인자: %s, 입력받은 값: %s, 선택지: %s",
+  "Argument check failed: %s": "유효하지 않은 인자입니다: %s",
+  "Implications failed:": "옵션의 조합이 잘못되었습니다:",
+  "Not enough arguments following: %s": "인자가 충분하게 주어지지 않았습니다: %s",
+  "Invalid JSON config file: %s": "유효하지 않은 JSON 설정파일입니다: %s",
+  "Path to JSON config file": "JSON 설정파일 경로",
+  "Show help": "도움말을 보여줍니다",
+  "Show version number": "버전 넘버를 보여줍니다"
+}
diff --git a/server/node_modules/yargs/locales/nb.json b/server/node_modules/yargs/locales/nb.json
new file mode 100644
index 0000000000000000000000000000000000000000..fc607fb1e19c112a019fa1dac39606fb8e11b20d
--- /dev/null
+++ b/server/node_modules/yargs/locales/nb.json
@@ -0,0 +1,37 @@
+{
+  "Commands:": "Kommandoer:",
+  "Options:": "Alternativer:",
+  "Examples:": "Eksempler:",
+  "boolean": "boolsk",
+  "count": "antall",
+  "string": "streng",
+  "number": "nummer",
+  "array": "matrise",
+  "required": "obligatorisk",
+  "default:": "standard:",
+  "choices:": "valg:",
+  "generated-value": "generert-verdi",
+  "Not enough non-option arguments: got %s, need at least %s": "Ikke nok ikke-alternativ argumenter: fikk %s, trenger minst %s",
+  "Too many non-option arguments: got %s, maximum of %s": "For mange ikke-alternativ argumenter: fikk %s, maksimum %s",
+  "Missing argument value: %s": {
+    "one": "Mangler argument verdi: %s",
+    "other": "Mangler argument verdier: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "Mangler obligatorisk argument: %s",
+    "other": "Mangler obligatoriske argumenter: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "Ukjent argument: %s",
+    "other": "Ukjente argumenter: %s"
+  },
+  "Invalid values:": "Ugyldige verdier:",
+  "Argument: %s, Given: %s, Choices: %s": "Argument: %s, Gitt: %s, Valg: %s",
+  "Argument check failed: %s": "Argument sjekk mislyktes: %s",
+  "Implications failed:": "Konsekvensene mislyktes:",
+  "Not enough arguments following: %s": "Ikke nok følgende argumenter: %s",
+  "Invalid JSON config file: %s": "Ugyldig JSON konfigurasjonsfil: %s",
+  "Path to JSON config file": "Bane til JSON konfigurasjonsfil",
+  "Show help": "Vis hjelp",
+  "Show version number": "Vis versjonsnummer"
+}
diff --git a/server/node_modules/yargs/locales/pirate.json b/server/node_modules/yargs/locales/pirate.json
new file mode 100644
index 0000000000000000000000000000000000000000..1f4e19e65de5e7922f61d3ab8e55db8fc33df275
--- /dev/null
+++ b/server/node_modules/yargs/locales/pirate.json
@@ -0,0 +1,12 @@
+{
+  "Commands:": "Choose yer command:",
+  "Options:": "Options for me hearties!",
+  "Examples:": "Ex. marks the spot:",
+  "required": "requi-yar-ed",
+  "Missing required argument: %s": {
+    "one": "Ye be havin' to set the followin' argument land lubber: %s",
+    "other": "Ye be havin' to set the followin' arguments land lubber: %s"
+  },
+  "Show help": "Parlay this here code of conduct",
+  "Show version number": "'Tis the version ye be askin' fer"
+}
diff --git a/server/node_modules/yargs/locales/pl.json b/server/node_modules/yargs/locales/pl.json
new file mode 100644
index 0000000000000000000000000000000000000000..5e48ac6770e93d32f136cc1d485cb1daf52cbde5
--- /dev/null
+++ b/server/node_modules/yargs/locales/pl.json
@@ -0,0 +1,37 @@
+{
+  "Commands:": "Polecenia:",
+  "Options:": "Opcje:",
+  "Examples:": "Przykłady:",
+  "boolean": "boolean",
+  "count": "ilość",
+  "string": "ciąg znaków",
+  "number": "liczba",
+  "array": "tablica",
+  "required": "wymagany",
+  "default:": "domyślny:",
+  "choices:": "dostępne:",
+  "generated-value": "wygenerowana-wartość",
+  "Not enough non-option arguments: got %s, need at least %s": "Niewystarczająca ilość argumentów: otrzymano %s, wymagane co najmniej %s",
+  "Too many non-option arguments: got %s, maximum of %s": "Zbyt duża ilość argumentów: otrzymano %s, wymagane co najwyżej %s",
+  "Missing argument value: %s": {
+    "one": "Brak wartości dla argumentu: %s",
+    "other": "Brak wartości dla argumentów: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "Brak wymaganego argumentu: %s",
+    "other": "Brak wymaganych argumentów: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "Nieznany argument: %s",
+    "other": "Nieznane argumenty: %s"
+  },
+  "Invalid values:": "Nieprawidłowe wartości:",
+  "Argument: %s, Given: %s, Choices: %s": "Argument: %s, Otrzymano: %s, Dostępne: %s",
+  "Argument check failed: %s": "Weryfikacja argumentów nie powiodła się: %s",
+  "Implications failed:": "Założenia nie zostały spełnione:",
+  "Not enough arguments following: %s": "Niewystarczająca ilość argumentów następujących po: %s",
+  "Invalid JSON config file: %s": "Nieprawidłowy plik konfiguracyjny JSON: %s",
+  "Path to JSON config file": "Ścieżka do pliku konfiguracyjnego JSON",
+  "Show help": "Pokaż pomoc",
+  "Show version number": "Pokaż numer wersji"
+}
diff --git a/server/node_modules/yargs/locales/pt.json b/server/node_modules/yargs/locales/pt.json
new file mode 100644
index 0000000000000000000000000000000000000000..0b9ea25f401d520fb91b9bf53ddc29772d34a94d
--- /dev/null
+++ b/server/node_modules/yargs/locales/pt.json
@@ -0,0 +1,37 @@
+{
+  "Commands:": "Comandos:",
+  "Options:": "Opções:",
+  "Examples:": "Exemplos:",
+  "boolean": "boolean",
+  "count": "contagem",
+  "string": "cadeia de caracteres",
+  "number": "número",
+  "array": "arranjo",
+  "required": "requerido",
+  "default:": "padrão:",
+  "choices:": "escolhas:",
+  "generated-value": "valor-gerado",
+  "Not enough non-option arguments: got %s, need at least %s": "Argumentos insuficientes não opcionais: Argumento %s, necessário pelo menos %s",
+  "Too many non-option arguments: got %s, maximum of %s": "Excesso de argumentos não opcionais: recebido %s, máximo de %s",
+  "Missing argument value: %s": {
+    "one": "Falta valor de argumento: %s",
+    "other": "Falta valores de argumento: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "Falta argumento obrigatório: %s",
+    "other": "Faltando argumentos obrigatórios: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "Argumento desconhecido: %s",
+    "other": "Argumentos desconhecidos: %s"
+  },
+  "Invalid values:": "Valores inválidos:",
+  "Argument: %s, Given: %s, Choices: %s": "Argumento: %s, Dado: %s, Escolhas: %s",
+  "Argument check failed: %s": "Verificação de argumento falhou: %s",
+  "Implications failed:": "Implicações falharam:",
+  "Not enough arguments following: %s": "Insuficientes argumentos a seguir: %s",
+  "Invalid JSON config file: %s": "Arquivo de configuração em JSON esta inválido: %s",
+  "Path to JSON config file": "Caminho para o arquivo de configuração em JSON",
+  "Show help": "Mostra ajuda",
+  "Show version number": "Mostra número de versão"
+}
diff --git a/server/node_modules/yargs/locales/pt_BR.json b/server/node_modules/yargs/locales/pt_BR.json
new file mode 100644
index 0000000000000000000000000000000000000000..f0aec141fa27f5eb71bff4c135f3cf8e4cf7f0a8
--- /dev/null
+++ b/server/node_modules/yargs/locales/pt_BR.json
@@ -0,0 +1,37 @@
+{
+  "Commands:": "Comandos:",
+  "Options:": "Opções:",
+  "Examples:": "Exemplos:",
+  "boolean": "boolean",
+  "count": "contagem",
+  "string": "string",
+  "number": "número",
+  "array": "array",
+  "required": "obrigatório",
+  "default:": "padrão:",
+  "choices:": "opções:",
+  "generated-value": "valor-gerado",
+  "Not enough non-option arguments: got %s, need at least %s": "Argumentos insuficientes: Argumento %s, necessário pelo menos %s",
+  "Too many non-option arguments: got %s, maximum of %s": "Excesso de argumentos: recebido %s, máximo de %s",
+  "Missing argument value: %s": {
+    "one": "Falta valor de argumento: %s",
+    "other": "Falta valores de argumento: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "Falta argumento obrigatório: %s",
+    "other": "Faltando argumentos obrigatórios: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "Argumento desconhecido: %s",
+    "other": "Argumentos desconhecidos: %s"
+  },
+  "Invalid values:": "Valores inválidos:",
+  "Argument: %s, Given: %s, Choices: %s": "Argumento: %s, Dado: %s, Opções: %s",
+  "Argument check failed: %s": "Verificação de argumento falhou: %s",
+  "Implications failed:": "Implicações falharam:",
+  "Not enough arguments following: %s": "Argumentos insuficientes a seguir: %s",
+  "Invalid JSON config file: %s": "Arquivo JSON de configuração inválido: %s",
+  "Path to JSON config file": "Caminho para o arquivo JSON de configuração",
+  "Show help": "Exibe ajuda",
+  "Show version number": "Exibe a versão"
+}
diff --git a/server/node_modules/yargs/locales/tr.json b/server/node_modules/yargs/locales/tr.json
new file mode 100644
index 0000000000000000000000000000000000000000..5b5c91bb65d6c97d99636e76c50ff016bbf07f37
--- /dev/null
+++ b/server/node_modules/yargs/locales/tr.json
@@ -0,0 +1,37 @@
+{
+  "Commands:": "Komutlar:",
+  "Options:": "Seçenekler:",
+  "Examples:": "Örnekler:",
+  "boolean": "boolean",
+  "count": "sayı",
+  "string": "string",
+  "number": "numara",
+  "array": "array",
+  "required": "zorunlu",
+  "default:": "varsayılan:",
+  "choices:": "seçimler:",
+  "generated-value": "oluÅŸturulan-deÄŸer",
+  "Not enough non-option arguments: got %s, need at least %s": "Seçenek dışı argümanlar yetersiz: %s bulundu, %s gerekli",
+  "Too many non-option arguments: got %s, maximum of %s": "Seçenek dışı argümanlar gereğinden fazla: %s bulundu, azami %s",
+  "Missing argument value: %s": {
+    "one": "Eksik argüman değeri: %s",
+    "other": "Eksik argüman değerleri: %s"
+  },
+  "Missing required argument: %s": {
+    "one": "Eksik zorunlu argüman: %s",
+    "other": "Eksik zorunlu argümanlar: %s"
+  },
+  "Unknown argument: %s": {
+    "one": "Bilinmeyen argüman: %s",
+    "other": "Bilinmeyen argümanlar: %s"
+  },
+  "Invalid values:": "Geçersiz değerler:",
+  "Argument: %s, Given: %s, Choices: %s": "Argüman: %s, Verilen: %s, Seçimler: %s",
+  "Argument check failed: %s": "Argüman kontrolü başarısız oldu: %s",
+  "Implications failed:": "Sonuçlar başarısız oldu:",
+  "Not enough arguments following: %s": "%s için yeterli argüman bulunamadı",
+  "Invalid JSON config file: %s": "Geçersiz JSON yapılandırma dosyası: %s",
+  "Path to JSON config file": "JSON yapılandırma dosya konumu",
+  "Show help": "Yardım detaylarını göster",
+  "Show version number": "Versiyon detaylarını göster"
+}
diff --git a/server/node_modules/yargs/locales/zh_CN.json b/server/node_modules/yargs/locales/zh_CN.json
new file mode 100644
index 0000000000000000000000000000000000000000..b25c7b9d2063f6e708c5d2e07b8ec8aa63043638
--- /dev/null
+++ b/server/node_modules/yargs/locales/zh_CN.json
@@ -0,0 +1,37 @@
+{
+  "Commands:": "命令:",
+  "Options:": "选项:",
+  "Examples:": "示例:",
+  "boolean": "布尔",
+  "count": "计数",
+  "string": "字符串",
+  "number": "æ•°å­—",
+  "array": "数组",
+  "required": "必需",
+  "default:": "默认值:",
+  "choices:": "可选值:",
+  "generated-value": "生成的值",
+  "Not enough non-option arguments: got %s, need at least %s": "缺少 non-option 参数:传入了 %s 个, 至少需要 %s 个",
+  "Too many non-option arguments: got %s, maximum of %s": "non-option 参数过多:传入了 %s 个, 最大允许 %s 个",
+  "Missing argument value: %s": {
+    "one": "没有给此选项指定值:%s",
+    "other": "没有给这些选项指定值:%s"
+  },
+  "Missing required argument: %s": {
+    "one": "缺少必须的选项:%s",
+    "other": "缺少这些必须的选项:%s"
+  },
+  "Unknown argument: %s": {
+    "one": "无法识别的选项:%s",
+    "other": "无法识别这些选项:%s"
+  },
+  "Invalid values:": "无效的选项值:",
+  "Argument: %s, Given: %s, Choices: %s": "选项名称: %s, 传入的值: %s, 可选的值:%s",
+  "Argument check failed: %s": "选项值验证失败:%s",
+  "Implications failed:": "缺少依赖的选项:",
+  "Not enough arguments following: %s": "没有提供足够的值给此选项:%s",
+  "Invalid JSON config file: %s": "无效的 JSON 配置文件:%s",
+  "Path to JSON config file": "JSON 配置文件的路径",
+  "Show help": "显示帮助信息",
+  "Show version number": "显示版本号"
+}
diff --git a/server/node_modules/yargs/package.json b/server/node_modules/yargs/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..d5c3e67674a251296d3e47af7596aeae68df5c09
--- /dev/null
+++ b/server/node_modules/yargs/package.json
@@ -0,0 +1,102 @@
+{
+  "_from": "yargs@^5.0.0",
+  "_id": "yargs@5.0.0",
+  "_inBundle": false,
+  "_integrity": "sha1-M1UUSXfQV1fbuG1uOOwFYSOzpm4=",
+  "_location": "/yargs",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "yargs@^5.0.0",
+    "name": "yargs",
+    "escapedName": "yargs",
+    "rawSpec": "^5.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^5.0.0"
+  },
+  "_requiredBy": [
+    "/pgtools"
+  ],
+  "_resolved": "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz",
+  "_shasum": "3355144977d05757dbb86d6e38ec056123b3a66e",
+  "_spec": "yargs@^5.0.0",
+  "_where": "/home/dante/Documents/pinsis-portal/server/node_modules/pgtools",
+  "bugs": {
+    "url": "https://github.com/yargs/yargs/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {
+    "cliui": "^3.2.0",
+    "decamelize": "^1.1.1",
+    "get-caller-file": "^1.0.1",
+    "lodash.assign": "^4.2.0",
+    "os-locale": "^1.4.0",
+    "read-pkg-up": "^1.0.1",
+    "require-directory": "^2.1.1",
+    "require-main-filename": "^1.0.1",
+    "set-blocking": "^2.0.0",
+    "string-width": "^1.0.2",
+    "which-module": "^1.0.0",
+    "window-size": "^0.2.0",
+    "y18n": "^3.2.1",
+    "yargs-parser": "^3.2.0"
+  },
+  "deprecated": false,
+  "description": "yargs the modern, pirate-themed, successor to optimist.",
+  "devDependencies": {
+    "chai": "^3.4.1",
+    "chalk": "^1.1.3",
+    "coveralls": "^2.11.11",
+    "cpr": "^1.0.0",
+    "cross-spawn": "^4.0.0",
+    "es6-promise": "^3.0.2",
+    "hashish": "0.0.4",
+    "mocha": "^3.0.1",
+    "nyc": "^8.1.0",
+    "rimraf": "^2.5.0",
+    "standard": "^7.0.0",
+    "standard-version": "^2.2.1",
+    "which": "^1.2.9"
+  },
+  "engine": {
+    "node": ">=0.10"
+  },
+  "files": [
+    "index.js",
+    "yargs.js",
+    "lib",
+    "locales",
+    "completion.sh.hbs",
+    "LICENSE"
+  ],
+  "homepage": "http://yargs.js.org/",
+  "keywords": [
+    "argument",
+    "args",
+    "option",
+    "parser",
+    "parsing",
+    "cli",
+    "command"
+  ],
+  "license": "MIT",
+  "main": "./index.js",
+  "name": "yargs",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/yargs/yargs.git"
+  },
+  "scripts": {
+    "coverage": "nyc report --reporter=text-lcov | coveralls",
+    "pretest": "standard",
+    "test": "nyc --cache mocha --require ./test/before.js --timeout=8000 --check-leaks",
+    "version": "standard-version"
+  },
+  "standard": {
+    "ignore": [
+      "**/example/**"
+    ]
+  },
+  "version": "5.0.0"
+}
diff --git a/server/node_modules/yargs/yargs.js b/server/node_modules/yargs/yargs.js
new file mode 100644
index 0000000000000000000000000000000000000000..c767c0e56cefd8cd3d88060ea0204c89c836fbf1
--- /dev/null
+++ b/server/node_modules/yargs/yargs.js
@@ -0,0 +1,852 @@
+const assert = require('assert')
+const Command = require('./lib/command')
+const Completion = require('./lib/completion')
+const Parser = require('yargs-parser')
+const path = require('path')
+const Usage = require('./lib/usage')
+const Validation = require('./lib/validation')
+const Y18n = require('y18n')
+const objFilter = require('./lib/obj-filter')
+const setBlocking = require('set-blocking')
+
+var exports = module.exports = Yargs
+function Yargs (processArgs, cwd, parentRequire) {
+  processArgs = processArgs || [] // handle calling yargs().
+
+  const self = {}
+  var command = null
+  var completion = null
+  var groups = {}
+  var preservedGroups = {}
+  var usage = null
+  var validation = null
+
+  const y18n = Y18n({
+    directory: path.resolve(__dirname, './locales'),
+    updateFiles: false
+  })
+
+  if (!cwd) cwd = process.cwd()
+
+  self.$0 = process.argv
+    .slice(0, 2)
+    .map(function (x, i) {
+      // ignore the node bin, specify this in your
+      // bin file with #!/usr/bin/env node
+      if (i === 0 && /\b(node|iojs)(\.exe)?$/.test(x)) return
+      var b = rebase(cwd, x)
+      return x.match(/^(\/|([a-zA-Z]:)?\\)/) && b.length < x.length ? b : x
+    })
+    .join(' ').trim()
+
+  if (process.env._ !== undefined && process.argv[1] === process.env._) {
+    self.$0 = process.env._.replace(
+      path.dirname(process.execPath) + '/', ''
+    )
+  }
+
+  // use context object to keep track of resets, subcommand execution, etc
+  // submodules should modify and check the state of context as necessary
+  const context = { resets: -1, commands: [], files: [] }
+  self.getContext = function () {
+    return context
+  }
+
+  // puts yargs back into an initial state. any keys
+  // that have been set to "global" will not be reset
+  // by this action.
+  var options
+  self.resetOptions = self.reset = function (aliases) {
+    context.resets++
+    aliases = aliases || {}
+    options = options || {}
+    // put yargs back into an initial state, this
+    // logic is used to build a nested command
+    // hierarchy.
+    var tmpOptions = {}
+    tmpOptions.global = options.global ? options.global : []
+
+    // if a key has been set as a global, we
+    // do not want to reset it or its aliases.
+    var globalLookup = {}
+    tmpOptions.global.forEach(function (g) {
+      globalLookup[g] = true
+      ;(aliases[g] || []).forEach(function (a) {
+        globalLookup[a] = true
+      })
+    })
+
+    // preserve groups containing global keys
+    preservedGroups = Object.keys(groups).reduce(function (acc, groupName) {
+      var keys = groups[groupName].filter(function (key) {
+        return key in globalLookup
+      })
+      if (keys.length > 0) {
+        acc[groupName] = keys
+      }
+      return acc
+    }, {})
+    // groups can now be reset
+    groups = {}
+
+    var arrayOptions = [
+      'array', 'boolean', 'string', 'requiresArg', 'skipValidation',
+      'count', 'normalize', 'number'
+    ]
+
+    var objectOptions = [
+      'narg', 'key', 'alias', 'default', 'defaultDescription',
+      'config', 'choices', 'demanded', 'coerce'
+    ]
+
+    arrayOptions.forEach(function (k) {
+      tmpOptions[k] = (options[k] || []).filter(function (k) {
+        return globalLookup[k]
+      })
+    })
+
+    objectOptions.forEach(function (k) {
+      tmpOptions[k] = objFilter(options[k], function (k, v) {
+        return globalLookup[k]
+      })
+    })
+
+    tmpOptions.envPrefix = options.envPrefix
+    options = tmpOptions
+
+    // if this is the first time being executed, create
+    // instances of all our helpers -- otherwise just reset.
+    usage = usage ? usage.reset(globalLookup) : Usage(self, y18n)
+    validation = validation ? validation.reset(globalLookup) : Validation(self, usage, y18n)
+    command = command ? command.reset() : Command(self, usage, validation)
+    if (!completion) completion = Completion(self, usage, command)
+
+    exitProcess = true
+    strict = false
+    completionCommand = null
+    self.parsed = false
+
+    return self
+  }
+  self.resetOptions()
+
+  self.boolean = function (bools) {
+    options.boolean.push.apply(options.boolean, [].concat(bools))
+    return self
+  }
+
+  self.array = function (arrays) {
+    options.array.push.apply(options.array, [].concat(arrays))
+    return self
+  }
+
+  self.nargs = function (key, n) {
+    if (typeof key === 'object') {
+      Object.keys(key).forEach(function (k) {
+        self.nargs(k, key[k])
+      })
+    } else {
+      options.narg[key] = n
+    }
+    return self
+  }
+
+  self.number = function (numbers) {
+    options.number.push.apply(options.number, [].concat(numbers))
+    return self
+  }
+
+  self.choices = function (key, values) {
+    if (typeof key === 'object') {
+      Object.keys(key).forEach(function (k) {
+        self.choices(k, key[k])
+      })
+    } else {
+      options.choices[key] = (options.choices[key] || []).concat(values)
+    }
+    return self
+  }
+
+  self.normalize = function (strings) {
+    options.normalize.push.apply(options.normalize, [].concat(strings))
+    return self
+  }
+
+  self.config = function (key, msg, parseFn) {
+    // allow to pass a configuration object
+    if (typeof key === 'object') {
+      options.configObjects = (options.configObjects || []).concat(key)
+      return self
+    }
+
+    // allow to provide a parsing function
+    if (typeof msg === 'function') {
+      parseFn = msg
+      msg = null
+    }
+
+    key = key || 'config'
+    self.describe(key, msg || usage.deferY18nLookup('Path to JSON config file'))
+    ;(Array.isArray(key) ? key : [key]).forEach(function (k) {
+      options.config[k] = parseFn || true
+    })
+    return self
+  }
+
+  self.example = function (cmd, description) {
+    usage.example(cmd, description)
+    return self
+  }
+
+  self.command = function (cmd, description, builder, handler) {
+    command.addHandler(cmd, description, builder, handler)
+    return self
+  }
+
+  self.commandDir = function (dir, opts) {
+    const req = parentRequire || require
+    command.addDirectory(dir, self.getContext(), req, require('get-caller-file')(), opts)
+    return self
+  }
+
+  self.string = function (strings) {
+    options.string.push.apply(options.string, [].concat(strings))
+    return self
+  }
+
+  // The 'defaults' alias is deprecated. It will be removed in the next major version.
+  self.default = self.defaults = function (key, value, defaultDescription) {
+    if (typeof key === 'object') {
+      Object.keys(key).forEach(function (k) {
+        self.default(k, key[k])
+      })
+    } else {
+      if (defaultDescription) options.defaultDescription[key] = defaultDescription
+      if (typeof value === 'function') {
+        if (!options.defaultDescription[key]) options.defaultDescription[key] = usage.functionDescription(value)
+        value = value.call()
+      }
+      options.default[key] = value
+    }
+    return self
+  }
+
+  self.alias = function (x, y) {
+    if (typeof x === 'object') {
+      Object.keys(x).forEach(function (key) {
+        self.alias(key, x[key])
+      })
+    } else {
+      options.alias[x] = (options.alias[x] || []).concat(y)
+    }
+    return self
+  }
+
+  self.coerce = function (key, fn) {
+    if (typeof key === 'object' && !Array.isArray(key)) {
+      Object.keys(key).forEach(function (k) {
+        self.coerce(k, key[k])
+      })
+    } else {
+      [].concat(key).forEach(function (k) {
+        options.coerce[k] = fn
+      })
+    }
+    return self
+  }
+
+  self.count = function (counts) {
+    options.count.push.apply(options.count, [].concat(counts))
+    return self
+  }
+
+  self.demand = self.required = self.require = function (keys, max, msg) {
+    // you can optionally provide a 'max' key,
+    // which will raise an exception if too many '_'
+    // options are provided.
+
+    if (Array.isArray(max)) {
+      max.forEach(function (key) {
+        self.demand(key, msg)
+      })
+      max = Infinity
+    } else if (typeof max !== 'number') {
+      msg = max
+      max = Infinity
+    }
+
+    if (typeof keys === 'number') {
+      if (!options.demanded._) options.demanded._ = { count: 0, msg: null, max: max }
+      options.demanded._.count = keys
+      options.demanded._.msg = msg
+    } else if (Array.isArray(keys)) {
+      keys.forEach(function (key) {
+        self.demand(key, msg)
+      })
+    } else {
+      if (typeof msg === 'string') {
+        options.demanded[keys] = { msg: msg }
+      } else if (msg === true || typeof msg === 'undefined') {
+        options.demanded[keys] = { msg: undefined }
+      }
+    }
+
+    return self
+  }
+
+  self.getDemanded = function () {
+    return options.demanded
+  }
+
+  self.requiresArg = function (requiresArgs) {
+    options.requiresArg.push.apply(options.requiresArg, [].concat(requiresArgs))
+    return self
+  }
+
+  self.skipValidation = function (skipValidations) {
+    options.skipValidation.push.apply(options.skipValidation, [].concat(skipValidations))
+    return self
+  }
+
+  self.implies = function (key, value) {
+    validation.implies(key, value)
+    return self
+  }
+
+  self.usage = function (msg, opts) {
+    if (!opts && typeof msg === 'object') {
+      opts = msg
+      msg = null
+    }
+
+    usage.usage(msg)
+
+    if (opts) self.options(opts)
+
+    return self
+  }
+
+  self.epilogue = self.epilog = function (msg) {
+    usage.epilog(msg)
+    return self
+  }
+
+  self.fail = function (f) {
+    usage.failFn(f)
+    return self
+  }
+
+  self.check = function (f) {
+    validation.check(f)
+    return self
+  }
+
+  self.describe = function (key, desc) {
+    options.key[key] = true
+    usage.describe(key, desc)
+    return self
+  }
+
+  self.global = function (globals) {
+    options.global.push.apply(options.global, [].concat(globals))
+    return self
+  }
+
+  self.pkgConf = function (key, path) {
+    var conf = null
+
+    var obj = pkgUp(path)
+
+    // If an object exists in the key, add it to options.configObjects
+    if (obj[key] && typeof obj[key] === 'object') {
+      conf = obj[key]
+      options.configObjects = (options.configObjects || []).concat(conf)
+    }
+
+    return self
+  }
+
+  var pkgs = {}
+  function pkgUp (path) {
+    var npath = path || '*'
+    if (pkgs[npath]) return pkgs[npath]
+    const readPkgUp = require('read-pkg-up')
+
+    var obj = {}
+    try {
+      obj = readPkgUp.sync({
+        cwd: path || require('require-main-filename')(parentRequire || require)
+      })
+    } catch (noop) {}
+
+    pkgs[npath] = obj.pkg || {}
+    return pkgs[npath]
+  }
+
+  self.parse = function (args, shortCircuit) {
+    if (!shortCircuit) processArgs = args
+    return parseArgs(args, shortCircuit)
+  }
+
+  self.option = self.options = function (key, opt) {
+    if (typeof key === 'object') {
+      Object.keys(key).forEach(function (k) {
+        self.options(k, key[k])
+      })
+    } else {
+      assert(typeof opt === 'object', 'second argument to option must be an object')
+
+      options.key[key] = true // track manually set keys.
+
+      if (opt.alias) self.alias(key, opt.alias)
+
+      var demand = opt.demand || opt.required || opt.require
+
+      if (demand) {
+        self.demand(key, demand)
+      } if ('config' in opt) {
+        self.config(key, opt.configParser)
+      } if ('default' in opt) {
+        self.default(key, opt.default)
+      } if ('nargs' in opt) {
+        self.nargs(key, opt.nargs)
+      } if ('normalize' in opt) {
+        self.normalize(key)
+      } if ('choices' in opt) {
+        self.choices(key, opt.choices)
+      } if ('coerce' in opt) {
+        self.coerce(key, opt.coerce)
+      } if ('group' in opt) {
+        self.group(key, opt.group)
+      } if (opt.global) {
+        self.global(key)
+      } if (opt.boolean || opt.type === 'boolean') {
+        self.boolean(key)
+        if (opt.alias) self.boolean(opt.alias)
+      } if (opt.array || opt.type === 'array') {
+        self.array(key)
+        if (opt.alias) self.array(opt.alias)
+      } if (opt.number || opt.type === 'number') {
+        self.number(key)
+        if (opt.alias) self.number(opt.alias)
+      } if (opt.string || opt.type === 'string') {
+        self.string(key)
+        if (opt.alias) self.string(opt.alias)
+      } if (opt.count || opt.type === 'count') {
+        self.count(key)
+      } if (opt.defaultDescription) {
+        options.defaultDescription[key] = opt.defaultDescription
+      } if (opt.skipValidation) {
+        self.skipValidation(key)
+      }
+
+      var desc = opt.describe || opt.description || opt.desc
+      if (desc) {
+        self.describe(key, desc)
+      }
+
+      if (opt.requiresArg) {
+        self.requiresArg(key)
+      }
+    }
+
+    return self
+  }
+  self.getOptions = function () {
+    return options
+  }
+
+  self.group = function (opts, groupName) {
+    var existing = preservedGroups[groupName] || groups[groupName]
+    if (preservedGroups[groupName]) {
+      // the preserved group will be moved to the set of explicitly declared
+      // groups
+      delete preservedGroups[groupName]
+    }
+
+    var seen = {}
+    groups[groupName] = (existing || []).concat(opts).filter(function (key) {
+      if (seen[key]) return false
+      return (seen[key] = true)
+    })
+    return self
+  }
+  self.getGroups = function () {
+    // combine explicit and preserved groups. explicit groups should be first
+    return require('lodash.assign')({}, groups, preservedGroups)
+  }
+
+  // as long as options.envPrefix is not undefined,
+  // parser will apply env vars matching prefix to argv
+  self.env = function (prefix) {
+    if (prefix === false) options.envPrefix = undefined
+    else options.envPrefix = prefix || ''
+    return self
+  }
+
+  self.wrap = function (cols) {
+    usage.wrap(cols)
+    return self
+  }
+
+  var strict = false
+  self.strict = function () {
+    strict = true
+    return self
+  }
+  self.getStrict = function () {
+    return strict
+  }
+
+  self.showHelp = function (level) {
+    if (!self.parsed) parseArgs(processArgs) // run parser, if it has not already been executed.
+    usage.showHelp(level)
+    return self
+  }
+
+  var versionOpt = null
+  self.version = function (opt, msg, ver) {
+    if (arguments.length === 0) {
+      ver = guessVersion()
+      opt = 'version'
+    } else if (arguments.length === 1) {
+      ver = opt
+      opt = 'version'
+    } else if (arguments.length === 2) {
+      ver = msg
+    }
+
+    versionOpt = opt
+    msg = msg || usage.deferY18nLookup('Show version number')
+
+    usage.version(ver || undefined)
+    self.boolean(versionOpt)
+    self.global(versionOpt)
+    self.describe(versionOpt, msg)
+    return self
+  }
+
+  function guessVersion () {
+    var obj = pkgUp()
+
+    return obj.version || 'unknown'
+  }
+
+  var helpOpt = null
+  var useHelpOptAsCommand = false // a call to .help() will enable this
+  self.addHelpOpt = self.help = function (opt, msg, addImplicitCmd) {
+    // argument shuffle
+    if (arguments.length === 0) {
+      useHelpOptAsCommand = true
+    } else if (arguments.length === 1) {
+      if (typeof opt === 'boolean') {
+        useHelpOptAsCommand = opt
+        opt = null
+      } else {
+        useHelpOptAsCommand = true
+      }
+    } else if (arguments.length === 2) {
+      if (typeof msg === 'boolean') {
+        useHelpOptAsCommand = msg
+        msg = null
+      } else {
+        useHelpOptAsCommand = true
+      }
+    } else {
+      useHelpOptAsCommand = Boolean(addImplicitCmd)
+    }
+    // use arguments, fallback to defaults for opt and msg
+    helpOpt = opt || 'help'
+    self.boolean(helpOpt)
+    self.global(helpOpt)
+    self.describe(helpOpt, msg || usage.deferY18nLookup('Show help'))
+    return self
+  }
+
+  self.showHelpOnFail = function (enabled, message) {
+    usage.showHelpOnFail(enabled, message)
+    return self
+  }
+
+  var exitProcess = true
+  self.exitProcess = function (enabled) {
+    if (typeof enabled !== 'boolean') {
+      enabled = true
+    }
+    exitProcess = enabled
+    return self
+  }
+  self.getExitProcess = function () {
+    return exitProcess
+  }
+
+  var completionCommand = null
+  self.completion = function (cmd, desc, fn) {
+    // a function to execute when generating
+    // completions can be provided as the second
+    // or third argument to completion.
+    if (typeof desc === 'function') {
+      fn = desc
+      desc = null
+    }
+
+    // register the completion command.
+    completionCommand = cmd || 'completion'
+    if (!desc && desc !== false) {
+      desc = 'generate bash completion script'
+    }
+    self.command(completionCommand, desc)
+
+    // a function can be provided
+    if (fn) completion.registerFunction(fn)
+
+    return self
+  }
+
+  self.showCompletionScript = function ($0) {
+    $0 = $0 || self.$0
+    console.log(completion.generateCompletionScript($0))
+    return self
+  }
+
+  self.getCompletion = function (args, done) {
+    completion.getCompletion(args, done)
+  }
+
+  self.locale = function (locale) {
+    if (arguments.length === 0) {
+      guessLocale()
+      return y18n.getLocale()
+    }
+    detectLocale = false
+    y18n.setLocale(locale)
+    return self
+  }
+
+  self.updateStrings = self.updateLocale = function (obj) {
+    detectLocale = false
+    y18n.updateLocale(obj)
+    return self
+  }
+
+  var detectLocale = true
+  self.detectLocale = function (detect) {
+    detectLocale = detect
+    return self
+  }
+  self.getDetectLocale = function () {
+    return detectLocale
+  }
+
+  var recommendCommands
+  self.recommendCommands = function () {
+    recommendCommands = true
+    return self
+  }
+
+  self.getUsageInstance = function () {
+    return usage
+  }
+
+  self.getValidationInstance = function () {
+    return validation
+  }
+
+  self.getCommandInstance = function () {
+    return command
+  }
+
+  self.terminalWidth = function () {
+    return require('window-size').width
+  }
+
+  Object.defineProperty(self, 'argv', {
+    get: function () {
+      var args = null
+
+      try {
+        args = parseArgs(processArgs)
+      } catch (err) {
+        usage.fail(err.message, err)
+      }
+
+      return args
+    },
+    enumerable: true
+  })
+
+  function parseArgs (args, shortCircuit) {
+    options.__ = y18n.__
+    options.configuration = pkgUp(cwd)['yargs'] || {}
+    const parsed = Parser.detailed(args, options)
+    const argv = parsed.argv
+    var aliases = parsed.aliases
+
+    argv.$0 = self.$0
+    self.parsed = parsed
+
+    guessLocale() // guess locale lazily, so that it can be turned off in chain.
+
+    // while building up the argv object, there
+    // are two passes through the parser. If completion
+    // is being performed short-circuit on the first pass.
+    if (shortCircuit) {
+      return argv
+    }
+
+    if (argv._.length) {
+      // check for helpOpt in argv._ before running commands
+      // assumes helpOpt must be valid if useHelpOptAsCommand is true
+      if (useHelpOptAsCommand) {
+        // consider any multi-char helpOpt alias as a valid help command
+        // unless all helpOpt aliases are single-char
+        // note that parsed.aliases is a normalized bidirectional map :)
+        var helpCmds = [helpOpt].concat(aliases[helpOpt])
+        var multiCharHelpCmds = helpCmds.filter(function (k) {
+          return k.length > 1
+        })
+        if (multiCharHelpCmds.length) helpCmds = multiCharHelpCmds
+        // look for and strip any helpCmds from argv._
+        argv._ = argv._.filter(function (cmd) {
+          if (~helpCmds.indexOf(cmd)) {
+            argv[helpOpt] = true
+            return false
+          }
+          return true
+        })
+      }
+
+      // if there's a handler associated with a
+      // command defer processing to it.
+      var handlerKeys = command.getCommands()
+      if (handlerKeys.length) {
+        var firstUnknownCommand
+        for (var i = 0, cmd; (cmd = argv._[i]) !== undefined; i++) {
+          if (~handlerKeys.indexOf(cmd) && cmd !== completionCommand) {
+            setPlaceholderKeys(argv)
+            return command.runCommand(cmd, self, parsed)
+          } else if (!firstUnknownCommand && cmd !== completionCommand) {
+            firstUnknownCommand = cmd
+          }
+        }
+
+        // recommend a command if recommendCommands() has
+        // been enabled, and no commands were found to execute
+        if (recommendCommands && firstUnknownCommand) {
+          validation.recommendCommands(firstUnknownCommand, handlerKeys)
+        }
+      }
+
+      // generate a completion script for adding to ~/.bashrc.
+      if (completionCommand && ~argv._.indexOf(completionCommand) && !argv[completion.completionKey]) {
+        if (exitProcess) setBlocking(true)
+        self.showCompletionScript()
+        if (exitProcess) {
+          process.exit(0)
+        }
+      }
+    }
+
+    // we must run completions first, a user might
+    // want to complete the --help or --version option.
+    if (completion.completionKey in argv) {
+      if (exitProcess) setBlocking(true)
+
+      // we allow for asynchronous completions,
+      // e.g., loading in a list of commands from an API.
+      var completionArgs = args.slice(args.indexOf('--' + completion.completionKey) + 1)
+      completion.getCompletion(completionArgs, function (completions) {
+        ;(completions || []).forEach(function (completion) {
+          console.log(completion)
+        })
+
+        if (exitProcess) {
+          process.exit(0)
+        }
+      })
+      return
+    }
+
+    var skipValidation = false
+
+    // Handle 'help' and 'version' options
+    Object.keys(argv).forEach(function (key) {
+      if (key === helpOpt && argv[key]) {
+        if (exitProcess) setBlocking(true)
+
+        skipValidation = true
+        self.showHelp('log')
+        if (exitProcess) {
+          process.exit(0)
+        }
+      } else if (key === versionOpt && argv[key]) {
+        if (exitProcess) setBlocking(true)
+
+        skipValidation = true
+        usage.showVersion()
+        if (exitProcess) {
+          process.exit(0)
+        }
+      }
+    })
+
+    // Check if any of the options to skip validation were provided
+    if (!skipValidation && options.skipValidation.length > 0) {
+      skipValidation = Object.keys(argv).some(function (key) {
+        return options.skipValidation.indexOf(key) >= 0
+      })
+    }
+
+    // If the help or version options where used and exitProcess is false,
+    // or if explicitly skipped, we won't run validations
+    if (!skipValidation) {
+      if (parsed.error) throw parsed.error
+
+      // if we're executed via bash completion, don't
+      // bother with validation.
+      if (!argv[completion.completionKey]) {
+        validation.nonOptionCount(argv)
+        validation.missingArgumentValue(argv)
+        validation.requiredArguments(argv)
+        if (strict) validation.unknownArguments(argv, aliases)
+        validation.customChecks(argv, aliases)
+        validation.limitedChoices(argv)
+        validation.implications(argv)
+      }
+    }
+
+    setPlaceholderKeys(argv)
+
+    return argv
+  }
+
+  function guessLocale () {
+    if (!detectLocale) return
+
+    try {
+      const osLocale = require('os-locale')
+      self.locale(osLocale.sync({ spawn: false }))
+    } catch (err) {
+      // if we explode looking up locale just noop
+      // we'll keep using the default language 'en'.
+    }
+  }
+
+  function setPlaceholderKeys (argv) {
+    Object.keys(options.key).forEach(function (key) {
+      // don't set placeholder keys for dot
+      // notation options 'foo.bar'.
+      if (~key.indexOf('.')) return
+      if (typeof argv[key] === 'undefined') argv[key] = undefined
+    })
+  }
+
+  return self
+}
+
+// rebase an absolute path to a relative one with respect to a base directory
+// exported for tests
+exports.rebase = rebase
+function rebase (base, dir) {
+  return path.relative(base, dir)
+}
diff --git a/server/package-lock.json b/server/package-lock.json
index 96dadf71286632fe23ed1f104858ded0b00c11cd..e24ac78ee5bc32fa0c07bc25893d3bc49e472aef 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -97,16 +97,36 @@
       "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
       "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
     },
+    "buffer-writer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
+      "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw=="
+    },
     "bytes": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
       "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
     },
+    "camelcase": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+      "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
+    },
     "chownr": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz",
       "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw=="
     },
+    "cliui": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+      "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+      "requires": {
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1",
+        "wrap-ansi": "^2.0.0"
+      }
+    },
     "code-point-at": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
@@ -167,6 +187,11 @@
         "ms": "2.0.0"
       }
     },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+    },
     "deep-extend": {
       "version": "0.6.0",
       "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@@ -210,6 +235,14 @@
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
       "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
     },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
     "escape-html": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -271,6 +304,15 @@
         "unpipe": "~1.0.0"
       }
     },
+    "find-up": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+      "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+      "requires": {
+        "path-exists": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      }
+    },
     "forwarded": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
@@ -309,6 +351,16 @@
         "wide-align": "^1.1.0"
       }
     },
+    "generic-pool": {
+      "version": "2.4.3",
+      "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-2.4.3.tgz",
+      "integrity": "sha1-eAw29p360FpaBF3Te+etyhGk9v8="
+    },
+    "get-caller-file": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+      "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w=="
+    },
     "glob": {
       "version": "7.1.5",
       "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz",
@@ -322,11 +374,21 @@
         "path-is-absolute": "^1.0.0"
       }
     },
+    "graceful-fs": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
+      "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
+    },
     "has-unicode": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
       "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
     },
+    "hosted-git-info": {
+      "version": "2.8.5",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
+      "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg=="
+    },
     "http-errors": {
       "version": "1.7.2",
       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
@@ -374,11 +436,21 @@
       "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
       "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
     },
+    "invert-kv": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+      "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
+    },
     "ipaddr.js": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
       "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
     },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
+    },
     "is-fullwidth-code-point": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
@@ -387,11 +459,21 @@
         "number-is-nan": "^1.0.0"
       }
     },
+    "is-utf8": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
+    },
     "isarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
       "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
     },
+    "js-string-escape": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",
+      "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8="
+    },
     "jsonwebtoken": {
       "version": "8.5.1",
       "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
@@ -440,6 +522,31 @@
       "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz",
       "integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw=="
     },
+    "lcid": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+      "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+      "requires": {
+        "invert-kv": "^1.0.0"
+      }
+    },
+    "load-json-file": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "parse-json": "^2.2.0",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0",
+        "strip-bom": "^2.0.0"
+      }
+    },
+    "lodash.assign": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
+      "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc="
+    },
     "lodash.includes": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
@@ -679,6 +786,17 @@
         "osenv": "^0.1.4"
       }
     },
+    "normalize-package-data": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "requires": {
+        "hosted-git-info": "^2.1.4",
+        "resolve": "^1.10.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      }
+    },
     "npm-bundled": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
@@ -735,6 +853,14 @@
       "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
       "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
     },
+    "os-locale": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+      "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+      "requires": {
+        "lcid": "^1.0.0"
+      }
+    },
     "os-tmpdir": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
@@ -749,21 +875,228 @@
         "os-tmpdir": "^1.0.0"
       }
     },
+    "packet-reader": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
+      "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ=="
+    },
+    "parse-json": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+      "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+      "requires": {
+        "error-ex": "^1.2.0"
+      }
+    },
     "parseurl": {
       "version": "1.3.3",
       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
       "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
     },
+    "path-exists": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+      "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+      "requires": {
+        "pinkie-promise": "^2.0.0"
+      }
+    },
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
       "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
     },
+    "path-parse": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
+    },
     "path-to-regexp": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
       "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
     },
+    "path-type": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+      "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      }
+    },
+    "pg": {
+      "version": "7.12.1",
+      "resolved": "https://registry.npmjs.org/pg/-/pg-7.12.1.tgz",
+      "integrity": "sha512-l1UuyfEvoswYfcUe6k+JaxiN+5vkOgYcVSbSuw3FvdLqDbaoa2RJo1zfJKfPsSYPFVERd4GHvX3s2PjG1asSDA==",
+      "requires": {
+        "buffer-writer": "2.0.0",
+        "packet-reader": "1.0.0",
+        "pg-connection-string": "0.1.3",
+        "pg-pool": "^2.0.4",
+        "pg-types": "^2.1.0",
+        "pgpass": "1.x",
+        "semver": "4.3.2"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "4.3.2",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz",
+          "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c="
+        }
+      }
+    },
+    "pg-connection-string": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz",
+      "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc="
+    },
+    "pg-int8": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
+      "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="
+    },
+    "pg-pool": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.7.tgz",
+      "integrity": "sha512-UiJyO5B9zZpu32GSlP0tXy8J2NsJ9EFGFfz5v6PSbdz/1hBLX1rNiiy5+mAm5iJJYwfCv4A0EBcQLGWwjbpzZw=="
+    },
+    "pg-types": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
+      "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
+      "requires": {
+        "pg-int8": "1.0.1",
+        "postgres-array": "~2.0.0",
+        "postgres-bytea": "~1.0.0",
+        "postgres-date": "~1.0.4",
+        "postgres-interval": "^1.1.0"
+      }
+    },
+    "pgpass": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz",
+      "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=",
+      "requires": {
+        "split": "^1.0.0"
+      }
+    },
+    "pgtools": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/pgtools/-/pgtools-0.3.0.tgz",
+      "integrity": "sha512-8NxDCJ8xJ6hOp9hVNZqxi+TZl7hM1Jc8pQyj8DlAbyaWnk5OsGwf3gB/UyDODdOguiim9QzbzPsslp//apO+Uw==",
+      "requires": {
+        "bluebird": "^3.3.5",
+        "pg": "^6.1.0",
+        "pg-connection-string": "^0.1.3",
+        "yargs": "^5.0.0"
+      },
+      "dependencies": {
+        "buffer-writer": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.1.tgz",
+          "integrity": "sha1-Iqk2kB4wKa/NdUfrRIfOtpejvwg="
+        },
+        "object-assign": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz",
+          "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A="
+        },
+        "packet-reader": {
+          "version": "0.3.1",
+          "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz",
+          "integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc="
+        },
+        "pg": {
+          "version": "6.4.2",
+          "resolved": "https://registry.npmjs.org/pg/-/pg-6.4.2.tgz",
+          "integrity": "sha1-w2QBEGDqx6UHoq4GPrhX7OkQ4n8=",
+          "requires": {
+            "buffer-writer": "1.0.1",
+            "js-string-escape": "1.0.1",
+            "packet-reader": "0.3.1",
+            "pg-connection-string": "0.1.3",
+            "pg-pool": "1.*",
+            "pg-types": "1.*",
+            "pgpass": "1.*",
+            "semver": "4.3.2"
+          }
+        },
+        "pg-pool": {
+          "version": "1.8.0",
+          "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-1.8.0.tgz",
+          "integrity": "sha1-9+xzgkw3oD8Hb1G/33DjQBR8Tzc=",
+          "requires": {
+            "generic-pool": "2.4.3",
+            "object-assign": "4.1.0"
+          }
+        },
+        "pg-types": {
+          "version": "1.13.0",
+          "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.13.0.tgz",
+          "integrity": "sha512-lfKli0Gkl/+za/+b6lzENajczwZHc7D5kiUCZfgm914jipD2kIOIvEkAhZ8GrW3/TUoP9w8FHjwpPObBye5KQQ==",
+          "requires": {
+            "pg-int8": "1.0.1",
+            "postgres-array": "~1.0.0",
+            "postgres-bytea": "~1.0.0",
+            "postgres-date": "~1.0.0",
+            "postgres-interval": "^1.1.0"
+          }
+        },
+        "postgres-array": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.3.tgz",
+          "integrity": "sha512-5wClXrAP0+78mcsNX3/ithQ5exKvCyK5lr5NEEEeGwwM6NJdQgzIJBVxLvRW+huFpX92F2QnZ5CcokH0VhK2qQ=="
+        },
+        "semver": {
+          "version": "4.3.2",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz",
+          "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c="
+        }
+      }
+    },
+    "pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "requires": {
+        "pinkie": "^2.0.0"
+      }
+    },
+    "postgres-array": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
+      "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="
+    },
+    "postgres-bytea": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
+      "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU="
+    },
+    "postgres-date": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.4.tgz",
+      "integrity": "sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA=="
+    },
+    "postgres-interval": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
+      "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
+      "requires": {
+        "xtend": "^4.0.0"
+      }
+    },
     "process-nextick-args": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -783,6 +1116,11 @@
       "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
       "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
     },
+    "ramda": {
+      "version": "0.26.1",
+      "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz",
+      "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ=="
+    },
     "range-parser": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -817,6 +1155,25 @@
         }
       }
     },
+    "read-pkg": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+      "requires": {
+        "load-json-file": "^1.0.0",
+        "normalize-package-data": "^2.3.2",
+        "path-type": "^1.0.0"
+      }
+    },
+    "read-pkg-up": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+      "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+      "requires": {
+        "find-up": "^1.0.0",
+        "read-pkg": "^1.0.0"
+      }
+    },
     "readable-stream": {
       "version": "2.3.6",
       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
@@ -836,6 +1193,16 @@
       "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
       "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw=="
     },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+    },
+    "require-main-filename": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+      "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
+    },
     "require_optional": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
@@ -845,6 +1212,14 @@
         "semver": "^5.1.0"
       }
     },
+    "resolve": {
+      "version": "1.12.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
+      "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
+      "requires": {
+        "path-parse": "^1.0.6"
+      }
+    },
     "resolve-from": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
@@ -941,6 +1316,42 @@
       "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
       "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
     },
+    "spdx-correct": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+      "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+      "requires": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+      "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA=="
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+      "requires": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+      "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q=="
+    },
+    "split": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
+      "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
+      "requires": {
+        "through": "2"
+      }
+    },
     "statuses": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
@@ -972,6 +1383,14 @@
         "ansi-regex": "^2.0.0"
       }
     },
+    "strip-bom": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+      "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+      "requires": {
+        "is-utf8": "^0.2.0"
+      }
+    },
     "strip-json-comments": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@@ -991,6 +1410,11 @@
         "yallist": "^3.0.3"
       }
     },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+    },
     "toidentifier": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
@@ -1020,11 +1444,25 @@
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
       "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
     },
+    "validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "requires": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
     "vary": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
       "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
     },
+    "which-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+      "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8="
+    },
     "wide-align": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
@@ -1033,15 +1471,69 @@
         "string-width": "^1.0.2 || 2"
       }
     },
+    "window-size": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz",
+      "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU="
+    },
+    "wrap-ansi": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+      "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+      "requires": {
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1"
+      }
+    },
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
       "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
     },
+    "xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
+    },
+    "y18n": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+      "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
+    },
     "yallist": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
       "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
+    },
+    "yargs": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz",
+      "integrity": "sha1-M1UUSXfQV1fbuG1uOOwFYSOzpm4=",
+      "requires": {
+        "cliui": "^3.2.0",
+        "decamelize": "^1.1.1",
+        "get-caller-file": "^1.0.1",
+        "lodash.assign": "^4.2.0",
+        "os-locale": "^1.4.0",
+        "read-pkg-up": "^1.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^1.0.1",
+        "set-blocking": "^2.0.0",
+        "string-width": "^1.0.2",
+        "which-module": "^1.0.0",
+        "window-size": "^0.2.0",
+        "y18n": "^3.2.1",
+        "yargs-parser": "^3.2.0"
+      }
+    },
+    "yargs-parser": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz",
+      "integrity": "sha1-UIE1XRnZ0MjF2BrakIy05tGGZk8=",
+      "requires": {
+        "camelcase": "^3.0.0",
+        "lodash.assign": "^4.1.0"
+      }
     }
   }
 }
diff --git a/server/package.json b/server/package.json
index bccfb538fe1f69d2d8f344804f09411fea8bb66d..892e017632ce7655f997d2ebc0923916055afa49 100644
--- a/server/package.json
+++ b/server/package.json
@@ -15,7 +15,10 @@
     "cors": "^2.8.5",
     "express": "^4.17.1",
     "jsonwebtoken": "^8.5.1",
-    "mongoose": "^5.7.4"
+    "mongoose": "^5.7.4",
+    "pg": "^7.12.1",
+    "pgtools": "^0.3.0",
+    "ramda": "^0.26.1"
   },
   "description": ""
 }
diff --git a/server/routes/api.js b/server/routes/api.js
index 5e13950140d7b676dc6b28258166db4216159319..e5b9430da4c1562343c29208a939122802d71dae 100644
--- a/server/routes/api.js
+++ b/server/routes/api.js
@@ -5,7 +5,8 @@ const User = require('../models/user');
 const jwt = require('jsonwebtoken')
 const db = "mongodb://localhost:27017/eventsdb";
 var bcrypt = require('bcrypt');
-
+const mongo = require('mongodb');
+const MongoClient = mongo.MongoClient;
 
 // mongoose.Promise = global.Promise;
 
@@ -17,6 +18,31 @@ mongoose.connect(db, function(err){
     }
 });
 
+MongoClient.connect(db, { useNewUrlParser: true }, (err, client) => {
+
+    if (err) throw err;
+
+    const db1 = client.db("eventsdb");
+
+    db1.listCollections().toArray().then((docs) => {
+
+        console.log('Available collections:');
+        docs.forEach((doc, idx, array) => { console.log(doc.name) });
+
+    }).catch((err) => {
+
+        console.log(err);
+    }).finally(() => {
+
+        client.close();
+    });
+
+});
+
+
+
+
+
 function verifyToken(req, res, next) {
   if(!req.headers.authorization) {
     return res.status(401).send('Unauthorized request')